composite.cpp (5736B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #ifdef _WIN32 6 7 # include <d3d11.h> 8 # include <wrl/client.h> 9 # include <dcomp.h> 10 # include <assert.h> 11 # include <dxgi.h> 12 13 # include <stdio.h> 14 15 using namespace Microsoft::WRL; 16 17 // A basic composition layer backed by a swap-chain for DirectComposition 18 class Layer { 19 public: 20 Layer(int width, int height, bool is_opaque, 21 const ComPtr<IDXGIFactory2>& dxgiFactory, 22 const ComPtr<ID3D11Device>& d3dDevice, 23 const ComPtr<IDCompositionDesktopDevice>& dCompDevice) { 24 HRESULT hr; 25 26 DXGI_SWAP_CHAIN_DESC1 desc{}; 27 desc.Width = width; 28 desc.Height = height; 29 desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; 30 desc.SampleDesc.Count = 1; 31 desc.SampleDesc.Quality = 0; 32 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 33 desc.BufferCount = 2; 34 // DXGI_SCALING_NONE caused swap chain creation failure. 35 desc.Scaling = DXGI_SCALING_STRETCH; 36 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; 37 desc.AlphaMode = 38 is_opaque ? DXGI_ALPHA_MODE_IGNORE : DXGI_ALPHA_MODE_PREMULTIPLIED; 39 desc.Flags = 0; 40 41 // Create a swap-chain, visual, attach them and get the backbuffer texture 42 // to draw to 43 44 hr = dxgiFactory->CreateSwapChainForComposition( 45 d3dDevice.Get(), &desc, nullptr, mSwapChain.GetAddressOf()); 46 assert(SUCCEEDED(hr)); 47 48 hr = dCompDevice->CreateVisual(mVisual.GetAddressOf()); 49 assert(SUCCEEDED(hr)); 50 51 mVisual->SetContent(mSwapChain.Get()); 52 53 hr = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), 54 (void**)mBackBuffer.GetAddressOf()); 55 assert(SUCCEEDED(hr)); 56 } 57 58 ComPtr<IDXGISwapChain1> mSwapChain; 59 ComPtr<IDCompositionVisual2> mVisual; 60 ComPtr<ID3D11Texture2D> mBackBuffer; 61 }; 62 63 // A basic DirectComposition compositor implementation 64 class Compositor { 65 public: 66 Compositor(ID3D11Device* aDevice, HWND hWnd) : pD3DDevice(aDevice) { 67 HRESULT hr; 68 69 // Get DXGI device from D3D (which was created by ANGLE) 70 hr = pD3DDevice.As(&pDXGIDevice); 71 assert(SUCCEEDED(hr)); 72 73 // Create DirectComposition 74 hr = DCompositionCreateDevice2(pDXGIDevice.Get(), 75 __uuidof(IDCompositionDesktopDevice), 76 (void**)pDCompDevice.GetAddressOf()); 77 assert(SUCCEEDED(hr)); 78 79 // Bind DC to the hWnd that was created by winit 80 hr = pDCompDevice->CreateTargetForHwnd(hWnd, TRUE, 81 pCompositionTarget.GetAddressOf()); 82 assert(SUCCEEDED(hr)); 83 84 // Create and set root of the visual tree 85 hr = pDCompDevice->CreateVisual(pRootVisual.GetAddressOf()); 86 assert(SUCCEEDED(hr)); 87 hr = pCompositionTarget->SetRoot(pRootVisual.Get()); 88 assert(SUCCEEDED(hr)); 89 pRootVisual->SetBitmapInterpolationMode( 90 DCOMPOSITION_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR); 91 92 // Enable DC debug counter overlay (helpful for seeing if DC composition is 93 // active during development) 94 hr = pDCompDevice.As(&pDCompDebug); 95 assert(SUCCEEDED(hr)); 96 pDCompDebug->EnableDebugCounters(); 97 98 // Get a DXGI factory interface for creating swap-chains 99 hr = pDXGIDevice->GetAdapter(&pDXGIAdapter); 100 assert(SUCCEEDED(hr)); 101 hr = pDXGIAdapter->GetParent(__uuidof(IDXGIFactory2), 102 (void**)pIDXGIFactory.GetAddressOf()); 103 assert(SUCCEEDED(hr)); 104 } 105 106 ~Compositor() {} 107 108 // Construct a layer of given dimensions. 109 Layer* create_layer(int width, int height, bool is_opaque) { 110 Layer* layer = new Layer(width, height, is_opaque, pIDXGIFactory, 111 pD3DDevice, pDCompDevice); 112 113 return layer; 114 } 115 116 void begin_frame() { pRootVisual->RemoveAllVisuals(); } 117 118 void add_layer(Layer* layer) { 119 // TODO(gwc): Don't add the visual during creation. Once we support multiple 120 // swap-chain layers, we'll need to support rebuilding the visual tree for 121 // DC as needed. 122 HRESULT hr = pRootVisual->AddVisual(layer->mVisual.Get(), FALSE, nullptr); 123 assert(SUCCEEDED(hr)); 124 } 125 126 void end_frame() { 127 // TODO(gwc): Only commit if the visual tree was rebuilt 128 pDCompDevice->Commit(); 129 } 130 131 private: 132 ComPtr<ID3D11Device> pD3DDevice; 133 ComPtr<IDXGIDevice> pDXGIDevice; 134 ComPtr<IDCompositionDesktopDevice> pDCompDevice; 135 ComPtr<IDCompositionTarget> pCompositionTarget; 136 ComPtr<IDCompositionVisual2> pRootVisual; 137 ComPtr<IDCompositionDeviceDebug> pDCompDebug; 138 ComPtr<IDXGIAdapter> pDXGIAdapter; 139 ComPtr<IDXGIFactory2> pIDXGIFactory; 140 }; 141 142 // Bindings called by wrench rust impl of the LayerCompositor trait 143 extern "C" { 144 Compositor* wrc_new(void* d3d11_device, void* hwnd) { 145 return new Compositor(static_cast<ID3D11Device*>(d3d11_device), 146 static_cast<HWND>(hwnd)); 147 } 148 149 void wrc_delete(Compositor* compositor) { delete compositor; } 150 151 Layer* wrc_create_layer(Compositor* compositor, int width, int height, 152 bool is_opaque) { 153 return compositor->create_layer(width, height, is_opaque); 154 } 155 156 void* wrc_get_layer_backbuffer(Layer* layer) { 157 void* p = layer->mBackBuffer.Get(); 158 return p; 159 } 160 161 void wrc_present_layer(Layer* layer) { layer->mSwapChain->Present(0, 0); } 162 163 void wrc_begin_frame(Compositor* compositor) { compositor->begin_frame(); } 164 165 void wrc_end_frame(Compositor* compositor) { compositor->end_frame(); } 166 167 void wrc_add_layer(Compositor* compositor, Layer* layer) { 168 compositor->add_layer(layer); 169 } 170 171 void wrc_set_layer_position(Layer* layer, float x, float y) { 172 layer->mVisual->SetOffsetX(x); 173 layer->mVisual->SetOffsetY(y); 174 } 175 } 176 177 #endif