shobomaru

D3DD2DInteropMutex

Nov 16th, 2012
859
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ■D3DD2DInteropMutex.cpp
  2. // Direct3D 11.0とDirect2Dを連携するサンプル(IDXGIKeyedMutexを使う方法)
  3. // ver 1.0 2012/11/16
  4. //
  5. // ■必須環境
  6. // Windows 7+ or ( Windows Vista SP2 + KB 971644 )
  7. // 注意 : Direct2Dが必要になるため、Windows VistaではWindows Updateを行う必要あり。
  8. // VisualStudio 2012+ or ( VisualStudio 2008 Express以降 + DirectX SDK )
  9.  
  10.  
  11. #define _WIN32_WINNT 0x0601
  12.  
  13. #include <Windows.h>
  14. #include <tchar.h>
  15. #include <d3d11.h>
  16. #include <d3d10_1.h>
  17. #include <d2d1.h>
  18. #include <dwrite.h>
  19. #include <exception>
  20. #include <cstring>
  21.  
  22. #pragma comment( lib, "d3d11.lib" )
  23. #pragma comment( lib, "d3d10_1.lib" )
  24. #pragma comment( lib, "d2d1.lib" )
  25. #pragma comment( lib, "dwrite.lib" )
  26.  
  27.  
  28. // ウィンドウのサイズ
  29. static const int WINDOW_WIDTH  = 800;
  30. static const int WINDOW_HEIGHT = 600;
  31.  
  32. // ウィンドウのハンドル
  33. static HWND g_mainWindowHandle = 0;
  34.  
  35. // フォントの基本サイズ
  36. static const float FONT_DEFAULT_SIZE = 48.0f;
  37.  
  38.  
  39.  
  40. // Win32APIに関する問題が発生したときに投げる例外
  41. class win32_exception : public std::exception
  42. {
  43. public:
  44.     win32_exception( const char *const msg ) : std::exception( msg ) {}
  45. };
  46.  
  47. // Direct3D/2Dに関する問題が発生したときに投げる例外
  48. class d3d_exception : public std::exception
  49. {
  50. public:
  51.     d3d_exception( const char *const msg ) : std::exception( msg ) {}
  52. };
  53.  
  54.  
  55.  
  56. class MyD3D
  57. {
  58. public:
  59.     IDXGISwapChain         *swapChain_;
  60.     IDXGIDevice1           *dxgiDev_;
  61.     ID3D11Device           *dev_;
  62.     ID3D11DeviceContext    *cont_;
  63.     ID3D10Device1          *dev101_;
  64.     D3D_FEATURE_LEVEL      featureLevel_;
  65.     ID3D11Texture2D        *backBufferTex_;
  66.     ID3D11RenderTargetView *backBufferRTV_;
  67.     ID2D1RenderTarget      *d2dRenderTarget_;
  68.     IDWriteTextFormat      *dwriteTextFormat_;
  69.     ID3D11Texture2D        *sharedSurfTex_;
  70.     ID3D11ShaderResourceView *sharedSurfSRV_;
  71.     IDXGIKeyedMutex        *mutex11_, *mutex101_;
  72.     IDXGISurface1          *dxgiBackBuffer_;
  73.  
  74. public:
  75.     void Release()
  76.     {
  77. #define SAFE_RELEASE( i ) if( (i) ) { (i)->Release(); (i) = nullptr; }
  78.  
  79.         SAFE_RELEASE( swapChain_ );
  80.         SAFE_RELEASE( dxgiDev_ );
  81.         SAFE_RELEASE( dev_ );
  82.         SAFE_RELEASE( cont_ );
  83.         SAFE_RELEASE( dev101_ );
  84.         SAFE_RELEASE( backBufferTex_ );
  85.         SAFE_RELEASE( backBufferRTV_ );
  86.         SAFE_RELEASE( d2dRenderTarget_ );
  87.         SAFE_RELEASE( dwriteTextFormat_ );
  88.         SAFE_RELEASE( sharedSurfTex_ );
  89.         SAFE_RELEASE( sharedSurfSRV_ );
  90.         SAFE_RELEASE( mutex11_ );
  91.         SAFE_RELEASE( mutex101_ );
  92.         SAFE_RELEASE( dxgiBackBuffer_ );
  93.  
  94. #undef SAFE_RELEASE
  95.     }
  96.  
  97.     void Init()
  98.     {
  99.         HRESULT hr;
  100.         float dpiX, dpiY;
  101.  
  102.         // スワップチェインの記述
  103.         DXGI_SWAP_CHAIN_DESC sc;
  104.  
  105.         // 解像度
  106.         sc.BufferDesc.Width = WINDOW_WIDTH;
  107.         sc.BufferDesc.Height = WINDOW_HEIGHT;
  108.         // バックバッファのテクスチャフォーマット
  109.         sc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
  110.         // フレームレート
  111.         sc.BufferDesc.RefreshRate.Denominator = 1;
  112.         sc.BufferDesc.RefreshRate.Numerator   = 60;
  113.         // スケール方法
  114.         sc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
  115.         // インタレース方法
  116.         sc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
  117.         // ウィンドウハンドル
  118.         sc.OutputWindow = g_mainWindowHandle;
  119.         // 全画面表示か否か
  120.         sc.Windowed = TRUE;
  121.  
  122.         // 使用方法
  123.         sc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
  124.         // バックバッファの数
  125.         sc.BufferCount = 2;
  126.         // 描画後のバッファの扱い
  127.         sc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL;
  128.         // MSAA
  129.         sc.SampleDesc.Count = 1;
  130.         sc.SampleDesc.Quality = 0;
  131.         // フラグ
  132.         sc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; // 解像度変更が有効
  133.  
  134.         // 下位互換API
  135.         D3D_FEATURE_LEVEL features[] = {
  136.             D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0
  137.         };
  138.  
  139.         // フラグ
  140.         UINT d3dFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; // BGRA テクスチャ有効
  141. #ifndef NDEBUG
  142.         d3dFlags |= D3D11_CREATE_DEVICE_DEBUG; // Debug ビルドならエラー報告を有効
  143. #endif
  144.        
  145.         // Direct3Dの作成
  146.         hr = D3D11CreateDeviceAndSwapChain(
  147.             nullptr, D3D_DRIVER_TYPE_HARDWARE, 0, d3dFlags,
  148.             features, ARRAYSIZE( features ), D3D11_SDK_VERSION,
  149.             &sc, &swapChain_,
  150.             &dev_, &featureLevel_, &cont_ );
  151.         if( FAILED( hr ) )
  152.             throw d3d_exception( "D3D11CreateDevice()" );
  153.  
  154.         // DXGIデバイスの作成
  155.         hr = dev_->QueryInterface<IDXGIDevice1>( &dxgiDev_ );
  156.         if( FAILED( hr ) )
  157.             throw d3d_exception( "ID3D11Device#QueryInterface()" );
  158.  
  159.         // キューに格納されていく描画コマンドをスワップ時に全てフラッシュする
  160.         dxgiDev_->SetMaximumFrameLatency( 1 );
  161.  
  162.         // DXGIアダプタ(GPU)の取得
  163.         IDXGIAdapter *adapter;
  164.         hr = dxgiDev_->GetAdapter( &adapter );
  165.         if( FAILED( hr ) )
  166.             throw d3d_exception( "IDXGIDevice#GetAdapter()" );
  167.  
  168.         // Direct3D 10.1に関連するパラメータ
  169.         UINT d3d101Flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; // BGRA テクスチャ有効
  170. #ifndef NDEBUG
  171.         d3d101Flags |= D3D11_CREATE_DEVICE_DEBUG; // Debug ビルドならエラー報告を有効
  172. #endif
  173.         D3D10_FEATURE_LEVEL1 feature101;
  174.         switch( featureLevel_ ) {
  175.         case D3D_FEATURE_LEVEL_9_1: feature101 = D3D10_FEATURE_LEVEL_9_1; break;
  176.         case D3D_FEATURE_LEVEL_9_2: feature101 = D3D10_FEATURE_LEVEL_9_2; break;
  177.         case D3D_FEATURE_LEVEL_9_3: feature101 = D3D10_FEATURE_LEVEL_9_3; break;
  178.         case D3D_FEATURE_LEVEL_10_0: feature101 = D3D10_FEATURE_LEVEL_10_0; break;
  179.         default: feature101 = D3D10_FEATURE_LEVEL_10_1; break;
  180.         }
  181.  
  182.         // Direct3D 10.1の作成
  183.         hr = D3D10CreateDevice1(
  184.             adapter, D3D10_DRIVER_TYPE_HARDWARE, 0, d3d101Flags,
  185.             feature101, D3D10_1_SDK_VERSION, &dev101_ );
  186.         if( FAILED( hr ) )
  187.             throw d3d_exception( "D3D10CreateDevice1()" );
  188.  
  189.         // バックバッファの取得
  190.         hr = swapChain_->GetBuffer( 0, IID_PPV_ARGS( &backBufferTex_ ) );
  191.         if( FAILED( hr ) )
  192.             throw d3d_exception( "IDXGISwapChain#GetBuffer()" );
  193.  
  194.         // バックバッファのレンダーターゲットビューの作成
  195.         hr = dev_->CreateRenderTargetView( backBufferTex_, nullptr, &backBufferRTV_ );
  196.         if( FAILED( hr ) )
  197.             throw d3d_exception( "ID3D11Device#CreateRenderTargetView()" );
  198.  
  199.         // 共有するテクスチャの作成
  200.         D3D11_TEXTURE2D_DESC texDesc;
  201.         ZeroMemory( &texDesc, sizeof( texDesc ) );
  202.         texDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
  203.         texDesc.Width = sc.BufferDesc.Width;
  204.         texDesc.Height = sc.BufferDesc.Height;
  205.         texDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
  206.         texDesc.Usage = D3D11_USAGE_DEFAULT;
  207.         texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
  208.         texDesc.SampleDesc.Count = 1;
  209.         texDesc.ArraySize = 1;
  210.         texDesc.MipLevels = 1;
  211.         hr = dev_->CreateTexture2D( &texDesc, nullptr, &sharedSurfTex_ );
  212.         if( FAILED( hr ) )
  213.             throw d3d_exception( "ID3D11Device#CreateTexture2D()" );
  214.  
  215.         hr = dev_->CreateShaderResourceView(
  216.             sharedSurfTex_, nullptr, &sharedSurfSRV_ );
  217.         if( FAILED( hr ) )
  218.             throw d3d_exception( "ID3D11Device#CreateShaderResourceView()" );
  219.  
  220.         //
  221.         hr = sharedSurfTex_->QueryInterface( IID_PPV_ARGS( &mutex11_ ) );
  222.         if( FAILED( hr ) )
  223.             throw d3d_exception( "ID3D11Texture2D#QueryInterface()" );
  224.  
  225.         IDXGIResource *dxgiRes;
  226.         hr = sharedSurfTex_->QueryInterface( IID_PPV_ARGS( &dxgiRes ) );
  227.         if( FAILED( hr ) )
  228.             throw d3d_exception( "ID3D11Texture2D#QueryInterface()" );
  229.  
  230.         HANDLE hShared;
  231.         hr = dxgiRes->GetSharedHandle( &hShared );
  232.         dxgiRes->Release();
  233.         if( FAILED( hr ) )
  234.             throw d3d_exception( "IDXGIResource#GetSharedHandle()" );
  235.  
  236.         hr = dev101_->OpenSharedResource( hShared, IID_PPV_ARGS( &dxgiBackBuffer_ ) );
  237.         if( FAILED( hr ) )
  238.             throw d3d_exception( "ID3D10Device1#OpenSharedResource()" );
  239.  
  240.         hr = dxgiBackBuffer_->QueryInterface( IID_PPV_ARGS( &mutex101_ ) );
  241.         if( FAILED( hr ) )
  242.             throw d3d_exception( "IDXGISurface1#QueryInterface()" );
  243.  
  244.  
  245.         // Direct2Dのファクトリーの作成
  246.         D2D1_FACTORY_OPTIONS d2dOpt;
  247.         ZeroMemory( &d2dOpt, sizeof d2dOpt );
  248.         ID2D1Factory *d2dFactory;
  249.         hr = D2D1CreateFactory(
  250.             D2D1_FACTORY_TYPE_SINGLE_THREADED,
  251.             __uuidof( ID2D1Factory ),
  252.             &d2dOpt,
  253.             reinterpret_cast<void**>( &d2dFactory ) );
  254.         if( FAILED( hr ) )
  255.             throw d3d_exception( "D2D1CreateFactory()" );
  256.  
  257.         // DPIの取得
  258.         d2dFactory->GetDesktopDpi( &dpiX, &dpiY );
  259.  
  260.         // Direct2Dの描画先となるレンダーターゲットを作成
  261.         D2D1_RENDER_TARGET_PROPERTIES d2dProp =
  262.             D2D1::RenderTargetProperties(
  263.             D2D1_RENDER_TARGET_TYPE_HARDWARE,
  264.             D2D1::PixelFormat( DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED ),
  265.             dpiX,
  266.             dpiY );
  267.  
  268.         hr = d2dFactory->CreateDxgiSurfaceRenderTarget(
  269.             dxgiBackBuffer_, &d2dProp, &d2dRenderTarget_ );
  270.         if( FAILED( hr ) )
  271.             throw d3d_exception( "ID2D1Factory#CreateDxgiSurfaceRenderTarget()" );
  272.  
  273.         // DirectWriteのファクトリの作成
  274.         IDWriteFactory *dwriteFactory;
  275.         hr = DWriteCreateFactory(
  276.             DWRITE_FACTORY_TYPE_SHARED,
  277.             __uuidof( dwriteFactory ),
  278.             reinterpret_cast<IUnknown**>( &dwriteFactory ) );
  279.         if( FAILED( hr ) )
  280.             throw d3d_exception( "DWriteCreateFactory()" );
  281.  
  282.         // テキストフォーマットの作成
  283.         hr = dwriteFactory->CreateTextFormat(
  284.             L"Meiryo UI", nullptr,
  285.             DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
  286.             FONT_DEFAULT_SIZE, L"", &dwriteTextFormat_ );
  287.         dwriteFactory->Release();
  288.         if( FAILED( hr ) )
  289.             throw d3d_exception( "IDWriteFactory#CreateTextFormat()" );
  290.  
  291.         // 文字の位置の設定
  292.         hr = dwriteTextFormat_->SetTextAlignment( DWRITE_TEXT_ALIGNMENT_CENTER );
  293.         if( FAILED( hr ) )
  294.             throw d3d_exception( "IDWriteTextFormat#SetTextAlignment()" );
  295.  
  296.         // パラグラフの指定
  297.         hr = dwriteTextFormat_->SetParagraphAlignment( DWRITE_PARAGRAPH_ALIGNMENT_NEAR );
  298.         if( FAILED( hr ) )
  299.             throw d3d_exception( "IDWriteTextFormat#SetParagraphAlignment()" );
  300.     }
  301.  
  302. };
  303. static MyD3D g_d3d;
  304.  
  305.  
  306.  
  307. // 描画
  308. void draw()
  309. {
  310.     HRESULT hr;
  311.     static float el = 0.0f;
  312.     el += 1.0f;
  313.     if( el > 360.0f ) el = 0.0f;
  314.  
  315.     // Direct3D
  316.    
  317.     hr = g_d3d.mutex11_->AcquireSync( 0, INFINITE );
  318.     if( FAILED( hr ) )
  319.         throw d3d_exception( "IDXGIKeyedMutex#AcquireSync()" );
  320.  
  321.     float clearColor[] = { 0.1f, 0.2f, 0.4f, 1.0f };
  322.     g_d3d.cont_->ClearRenderTargetView( g_d3d.backBufferRTV_, clearColor );
  323.  
  324.     hr = g_d3d.mutex11_->ReleaseSync( 1 );
  325.     if( FAILED( hr ) )
  326.         throw d3d_exception( "IDXGIKeyedMutex#ReleaseSync()" );
  327.  
  328.     // Direct2D
  329.  
  330.     hr = g_d3d.mutex101_->AcquireSync( 1, INFINITE );
  331.     if( FAILED( hr ) )
  332.         throw d3d_exception( "IDXGIKeyedMutex#AcquireSync()" );
  333.  
  334.     D2D1_COLOR_F color;
  335.     color =  D2D1::ColorF(
  336.         min( 120.0f, max( 0, 120.0f - el ) ) / 120.0f,
  337.         min( 120.0f, max( 0, el - 120.0f ) ) / 120.0f,
  338.         min( 120.0f, max( 0, 240.0f - el ) ) / 120.0f,
  339.         1.0f );
  340.  
  341.     ID2D1SolidColorBrush *brush;
  342.     hr = g_d3d.d2dRenderTarget_->CreateSolidColorBrush( color, &brush );
  343.     if( FAILED( hr ) )
  344.         throw d3d_exception( "ID2D1DeviceContext#CreateSolidColorBrush()" );
  345.  
  346.     D2D1_RECT_F rect;
  347.     rect = D2D1::RectF( 0 + el, 500, 440 + el, 550 );
  348.  
  349.     g_d3d.d2dRenderTarget_->BeginDraw();
  350.     g_d3d.d2dRenderTarget_->Clear( D2D1::ColorF( 0.0f, 0.5f, 0.0f, 0.0f ) );
  351.     g_d3d.d2dRenderTarget_->FillRectangle( &rect, brush );
  352.  
  353.     // DirectWrite
  354.  
  355.     rect = D2D1::RectF( 0 + el, 200, 450 + el, 201 );
  356.     TCHAR *drawText = _T( "Hello HELL World!!!\n地球の未来にご奉仕するにゃん!" );
  357.     g_d3d.d2dRenderTarget_->DrawText(
  358.         drawText, _tcslen( drawText ), g_d3d.dwriteTextFormat_, &rect, brush );
  359.    
  360.     g_d3d.d2dRenderTarget_->EndDraw();
  361.     brush->Release();
  362.  
  363.     hr = g_d3d.mutex101_->ReleaseSync( 2 );
  364.     if( FAILED( hr ) )
  365.         throw d3d_exception( "IDXGIKeyedMutex#ReleaseSync()" );
  366.  
  367.     // Direct3D
  368.  
  369.     hr = g_d3d.mutex11_->AcquireSync( 2, INFINITE );
  370.     if( FAILED( hr ) )
  371.         throw d3d_exception( "IDXGIKeyedMutex#AcquireSync()" );
  372.  
  373.     g_d3d.cont_->CopyResource( g_d3d.backBufferTex_, g_d3d.sharedSurfTex_ );
  374.  
  375.     hr = g_d3d.mutex11_->ReleaseSync( 0 );
  376.     if( FAILED( hr ) )
  377.         throw d3d_exception( "IDXGIKeyedMutex#ReleaseSync()" );
  378.  
  379.     // DXGI
  380.  
  381.     g_d3d.swapChain_->Present( 1, 0 );
  382. }
  383.  
  384.  
  385.  
  386. // ウィンドウプロシージャ
  387. LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
  388. {
  389.     PAINTSTRUCT ps;
  390.     HDC hdc;
  391.  
  392.     switch( message ) {
  393.     case WM_KEYDOWN:
  394.         if( wParam == VK_ESCAPE ) {
  395.             PostMessage( hWnd, WM_DESTROY, 0, 0 );
  396.             return 0;
  397.         }
  398.         break;
  399.  
  400.     case WM_PAINT:
  401.         hdc = BeginPaint( hWnd, &ps );
  402.         EndPaint( hWnd, &ps );
  403.         break;
  404.  
  405.     case WM_DESTROY:
  406.         PostQuitMessage( 0 );
  407.         break;
  408.  
  409.     default:
  410.         return DefWindowProc( hWnd, message, wParam, lParam );
  411.     }
  412.     return 0;
  413. }
  414.  
  415. // ウィンドウを作成する
  416. static HWND setupWindow( int width, int height )
  417. {
  418.     WNDCLASSEX wcex;
  419.     wcex.cbSize         = sizeof( WNDCLASSEX );
  420.     wcex.style          = CS_HREDRAW | CS_VREDRAW;
  421.     wcex.lpfnWndProc    = WndProc;
  422.     wcex.cbClsExtra     = 0;
  423.     wcex.cbWndExtra     = 0;
  424.     wcex.hInstance      = (HMODULE)GetModuleHandle( 0 );
  425.     wcex.hIcon          = nullptr;
  426.     wcex.hCursor        = LoadCursor( nullptr, IDC_ARROW );
  427.     wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW + 1);
  428.     wcex.lpszMenuName   = nullptr;
  429.     wcex.lpszClassName  = _T( "WindowClass" );
  430.     wcex.hIconSm        = nullptr;
  431.     if( !RegisterClassEx( &wcex ) ) {
  432.         throw win32_exception( "RegisterClassEx()" );
  433.     }
  434.  
  435.     RECT rect = { 0, 0, width, height };
  436.     AdjustWindowRect( &rect, WS_OVERLAPPEDWINDOW, FALSE );
  437.     const int windowWidth  = ( rect.right  - rect.left );
  438.     const int windowHeight = ( rect.bottom - rect.top );
  439.  
  440.     HWND hWnd = CreateWindow( _T("WindowClass"), _T("D3DD2DInterop"),
  441.         WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, windowWidth, windowHeight,
  442.         nullptr, nullptr, nullptr, nullptr );
  443.     if( !hWnd ) {
  444.         throw win32_exception( "CreateWindow()" );
  445.     }
  446.  
  447.     return hWnd;
  448. }
  449.  
  450. // エントリーポイント
  451. int WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
  452. {
  453.     MSG msg;
  454.     ZeroMemory( &msg, sizeof msg );
  455.  
  456.     // Debugでは例外を開発環境が受け取り,Releaseではメッセージを表示して強制的に終了する
  457. #ifdef NDEBUG
  458.     try {
  459. #endif
  460.    
  461.     g_mainWindowHandle = setupWindow( WINDOW_WIDTH, WINDOW_HEIGHT );
  462.     ShowWindow( g_mainWindowHandle, SW_SHOW );
  463.     UpdateWindow( g_mainWindowHandle );
  464.  
  465.     g_d3d.Init();
  466.  
  467.     while( msg.message != WM_QUIT ) {
  468.         BOOL r = PeekMessage( &msg, nullptr, 0, 0, PM_REMOVE );
  469.         if( r == 0 ) {
  470.             draw();
  471.         }
  472.         else {
  473.             DispatchMessage( &msg );
  474.         }
  475.     }
  476.  
  477. #ifdef NDEBUG
  478.     } catch( std::exception &e ) {
  479.         MessageBoxA( g_mainWindowHandle, e.what(), "D3DD2DInterop - 問題が発生しました", MB_ICONSTOP ); }
  480. #endif
  481.  
  482.     g_d3d.Release();
  483.  
  484.     return static_cast<int>( msg.wParam );
  485. }
RAW Paste Data