d2d_window.cpp
1 #include "pch.h" 2 #include "d2d_window.h" 3 4 #include <common/utils/resources.h> 5 6 D2DWindow::D2DWindow() 7 { 8 static const WCHAR* class_name = L"PToyD2DPopup"; 9 WNDCLASS wc = {}; 10 wc.hCursor = LoadCursor(nullptr, IDC_ARROW); 11 wc.hInstance = reinterpret_cast<HINSTANCE>(&__ImageBase); 12 wc.lpszClassName = class_name; 13 wc.style = CS_HREDRAW | CS_VREDRAW; 14 wc.lpfnWndProc = d2d_window_proc; 15 RegisterClass(&wc); 16 hwnd = CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_NOREDIRECTIONBITMAP | WS_EX_LAYERED, 17 wc.lpszClassName, 18 L"PToyD2DPopup", 19 WS_POPUP | WS_VISIBLE, 20 CW_USEDEFAULT, 21 CW_USEDEFAULT, 22 CW_USEDEFAULT, 23 CW_USEDEFAULT, 24 nullptr, 25 nullptr, 26 wc.hInstance, 27 this); 28 WINRT_VERIFY(hwnd); 29 } 30 31 void D2DWindow::show(UINT x, UINT y, UINT width, UINT height) 32 { 33 if (!initialized) 34 { 35 base_init(); 36 } 37 base_resize(width, height); 38 render_empty(); 39 hidden = false; 40 on_show(); 41 SetWindowPos(hwnd, HWND_TOPMOST, x, y, width, height, 0); 42 ShowWindow(hwnd, SW_SHOWNORMAL); 43 SetForegroundWindow(hwnd); 44 UpdateWindow(hwnd); 45 } 46 47 void D2DWindow::hide() 48 { 49 hidden = true; 50 ShowWindow(hwnd, SW_HIDE); 51 on_hide(); 52 } 53 54 void D2DWindow::initialize() 55 { 56 base_init(); 57 } 58 59 void D2DWindow::base_init() 60 { 61 std::unique_lock lock(mutex); 62 // D2D1Factory is independent from the device, no need to recreate it if we need to recreate the device. 63 if (!d2d_factory) 64 { 65 #ifdef _DEBUG 66 D2D1_FACTORY_OPTIONS options = { D2D1_DEBUG_LEVEL_INFORMATION }; 67 #else 68 D2D1_FACTORY_OPTIONS options = {}; 69 #endif 70 winrt::check_hresult(D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, 71 __uuidof(d2d_factory), 72 &options, 73 d2d_factory.put_void())); 74 } 75 // For all other stuff - assign nullptr first to release the object, to reset the com_ptr. 76 d2d_dc = nullptr; 77 d2d_device = nullptr; 78 dxgi_factory = nullptr; 79 dxgi_device = nullptr; 80 d3d_device = nullptr; 81 winrt::check_hresult(D3D11CreateDevice(nullptr, 82 D3D_DRIVER_TYPE_HARDWARE, 83 nullptr, 84 D3D11_CREATE_DEVICE_BGRA_SUPPORT, 85 nullptr, 86 0, 87 D3D11_SDK_VERSION, 88 d3d_device.put(), 89 nullptr, 90 nullptr)); 91 winrt::check_hresult(d3d_device->QueryInterface(__uuidof(dxgi_device), dxgi_device.put_void())); 92 winrt::check_hresult(CreateDXGIFactory2(0, __uuidof(dxgi_factory), dxgi_factory.put_void())); 93 winrt::check_hresult(d2d_factory->CreateDevice(dxgi_device.get(), d2d_device.put())); 94 winrt::check_hresult(d2d_device->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, d2d_dc.put())); 95 init(); 96 initialized = true; 97 } 98 99 void D2DWindow::base_resize(UINT width, UINT height) 100 { 101 std::unique_lock lock(mutex); 102 if (!initialized) 103 { 104 return; 105 } 106 window_width = width; 107 window_height = height; 108 if (window_width == 0 || window_height == 0) 109 { 110 return; 111 } 112 DXGI_SWAP_CHAIN_DESC1 sc_description = {}; 113 sc_description.Format = DXGI_FORMAT_B8G8R8A8_UNORM; 114 sc_description.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 115 sc_description.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; 116 sc_description.BufferCount = 2; 117 sc_description.SampleDesc.Count = 1; 118 sc_description.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED; 119 sc_description.Width = window_width; 120 sc_description.Height = window_height; 121 dxgi_swap_chain = nullptr; 122 winrt::check_hresult(dxgi_factory->CreateSwapChainForComposition(dxgi_device.get(), 123 &sc_description, 124 nullptr, 125 dxgi_swap_chain.put())); 126 composition_device = nullptr; 127 winrt::check_hresult(DCompositionCreateDevice(dxgi_device.get(), 128 __uuidof(composition_device), 129 composition_device.put_void())); 130 131 composition_target = nullptr; 132 winrt::check_hresult(composition_device->CreateTargetForHwnd(hwnd, true, composition_target.put())); 133 134 composition_visual = nullptr; 135 winrt::check_hresult(composition_device->CreateVisual(composition_visual.put())); 136 winrt::check_hresult(composition_visual->SetContent(dxgi_swap_chain.get())); 137 winrt::check_hresult(composition_target->SetRoot(composition_visual.get())); 138 139 dxgi_surface = nullptr; 140 winrt::check_hresult(dxgi_swap_chain->GetBuffer(0, __uuidof(dxgi_surface), dxgi_surface.put_void())); 141 D2D1_BITMAP_PROPERTIES1 properties = {}; 142 properties.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED; 143 properties.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM; 144 properties.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW; 145 146 d2d_bitmap = nullptr; 147 winrt::check_hresult(d2d_dc->CreateBitmapFromDxgiSurface(dxgi_surface.get(), 148 properties, 149 d2d_bitmap.put())); 150 d2d_dc->SetTarget(d2d_bitmap.get()); 151 resize(); 152 } 153 154 void D2DWindow::base_render() 155 { 156 std::unique_lock lock(mutex); 157 if (!initialized || !d2d_dc || !d2d_bitmap) 158 return; 159 d2d_dc->BeginDraw(); 160 render(d2d_dc.get()); 161 winrt::check_hresult(d2d_dc->EndDraw()); 162 winrt::check_hresult(dxgi_swap_chain->Present(1, 0)); 163 winrt::check_hresult(composition_device->Commit()); 164 } 165 166 void D2DWindow::render_empty() 167 { 168 std::unique_lock lock(mutex); 169 if (!initialized || !d2d_dc || !d2d_bitmap) 170 return; 171 d2d_dc->BeginDraw(); 172 d2d_dc->Clear(); 173 winrt::check_hresult(d2d_dc->EndDraw()); 174 winrt::check_hresult(dxgi_swap_chain->Present(1, 0)); 175 winrt::check_hresult(composition_device->Commit()); 176 } 177 178 D2DWindow::~D2DWindow() 179 { 180 ShowWindow(hwnd, SW_HIDE); 181 DestroyWindow(hwnd); 182 } 183 184 D2DWindow* D2DWindow::this_from_hwnd(HWND window) 185 { 186 return reinterpret_cast<D2DWindow*>(GetWindowLongPtr(window, GWLP_USERDATA)); 187 } 188 189 LRESULT __stdcall D2DWindow::d2d_window_proc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) 190 { 191 auto self = this_from_hwnd(window); 192 switch (message) 193 { 194 case WM_NCCREATE: 195 { 196 auto create_struct = reinterpret_cast<CREATESTRUCT*>(lparam); 197 SetWindowLongPtr(window, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(create_struct->lpCreateParams)); 198 return TRUE; 199 } 200 case WM_MOVE: 201 case WM_SIZE: 202 self->base_resize(static_cast<unsigned>(lparam) & 0xFFFF, static_cast<unsigned>(lparam) >> 16); 203 [[fallthrough]]; 204 case WM_PAINT: 205 self->base_render(); 206 return 0; 207 208 default: 209 return DefWindowProc(window, message, wparam, lparam); 210 } 211 }