1 /*
2 * Copyright © Microsoft Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include "d3d12_wgl_public.h"
25
26 #include <Windows.h>
27 #include <dxgi1_4.h>
28 #include <directx/d3d12.h>
29 #include <wrl.h>
30
31 #include "util/u_memory.h"
32 #include "util/u_inlines.h"
33 #include "frontend/api.h"
34 #include "frontend/winsys_handle.h"
35
36 #include "stw_device.h"
37 #include "stw_pixelformat.h"
38 #include "stw_winsys.h"
39
40 #include "d3d12/d3d12_format.h"
41 #include "d3d12/d3d12_resource.h"
42 #include "d3d12/d3d12_screen.h"
43
44 using Microsoft::WRL::ComPtr;
45 constexpr uint32_t num_buffers = 2;
46
47 struct d3d12_wgl_framebuffer {
48 struct stw_winsys_framebuffer base;
49
50 struct d3d12_screen *screen;
51 enum pipe_format pformat;
52 HWND window;
53 ComPtr<IDXGISwapChain3> swapchain;
54 struct pipe_resource *buffers[num_buffers];
55 };
56
57 static struct d3d12_wgl_framebuffer *
d3d12_wgl_framebuffer(struct stw_winsys_framebuffer * fb)58 d3d12_wgl_framebuffer(struct stw_winsys_framebuffer *fb)
59 {
60 return (struct d3d12_wgl_framebuffer *)fb;
61 }
62
63 static void
d3d12_wgl_framebuffer_destroy(struct stw_winsys_framebuffer * fb,pipe_context * ctx)64 d3d12_wgl_framebuffer_destroy(struct stw_winsys_framebuffer *fb,
65 pipe_context *ctx)
66 {
67 struct d3d12_wgl_framebuffer *framebuffer = d3d12_wgl_framebuffer(fb);
68 struct pipe_fence_handle *fence = NULL;
69
70 if (ctx) {
71 /* Ensure all resources are flushed */
72 ctx->flush(ctx, &fence, PIPE_FLUSH_HINT_FINISH);
73 if (fence) {
74 ctx->screen->fence_finish(ctx->screen, ctx, fence, PIPE_TIMEOUT_INFINITE);
75 ctx->screen->fence_reference(ctx->screen, &fence, NULL);
76 }
77 }
78
79 for (int i = 0; i < num_buffers; ++i) {
80 if (framebuffer->buffers[i]) {
81 d3d12_resource_release(d3d12_resource(framebuffer->buffers[i]));
82 pipe_resource_reference(&framebuffer->buffers[i], NULL);
83 }
84 }
85
86 delete framebuffer;
87 }
88
89 static void
d3d12_wgl_framebuffer_resize(stw_winsys_framebuffer * fb,pipe_context * ctx,pipe_resource * templ)90 d3d12_wgl_framebuffer_resize(stw_winsys_framebuffer *fb,
91 pipe_context *ctx,
92 pipe_resource *templ)
93 {
94 struct d3d12_wgl_framebuffer *framebuffer = d3d12_wgl_framebuffer(fb);
95 struct d3d12_dxgi_screen *screen = d3d12_dxgi_screen(framebuffer->screen);
96
97 DXGI_SWAP_CHAIN_DESC1 desc = {};
98 desc.BufferCount = num_buffers;
99 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT;
100 desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
101 desc.Format = d3d12_get_format(templ->format);
102 desc.Width = templ->width0;
103 desc.Height = templ->height0;
104 desc.SampleDesc.Count = 1;
105 desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
106
107 framebuffer->pformat = templ->format;
108
109 if (!framebuffer->swapchain) {
110 ComPtr<IDXGISwapChain1> swapchain1;
111 if (FAILED(screen->factory->CreateSwapChainForHwnd(
112 screen->base.cmdqueue,
113 framebuffer->window,
114 &desc,
115 nullptr,
116 nullptr,
117 &swapchain1))) {
118 debug_printf("D3D12: failed to create swapchain");
119 return;
120 }
121
122 swapchain1.As(&framebuffer->swapchain);
123
124 screen->factory->MakeWindowAssociation(framebuffer->window,
125 DXGI_MWA_NO_WINDOW_CHANGES | DXGI_MWA_NO_ALT_ENTER | DXGI_MWA_NO_PRINT_SCREEN);
126 }
127 else {
128 struct pipe_fence_handle *fence = NULL;
129
130 /* Ensure all resources are flushed */
131 ctx->flush(ctx, &fence, PIPE_FLUSH_HINT_FINISH);
132 if (fence) {
133 ctx->screen->fence_finish(ctx->screen, ctx, fence, PIPE_TIMEOUT_INFINITE);
134 ctx->screen->fence_reference(ctx->screen, &fence, NULL);
135 }
136
137 for (int i = 0; i < num_buffers; ++i) {
138 if (framebuffer->buffers[i]) {
139 d3d12_resource_release(d3d12_resource(framebuffer->buffers[i]));
140 pipe_resource_reference(&framebuffer->buffers[i], NULL);
141 }
142 }
143 if (FAILED(framebuffer->swapchain->ResizeBuffers(num_buffers, desc.Width, desc.Height, desc.Format, desc.Flags))) {
144 debug_printf("D3D12: failed to resize swapchain");
145 }
146 }
147 }
148
149 static boolean
d3d12_wgl_framebuffer_present(stw_winsys_framebuffer * fb)150 d3d12_wgl_framebuffer_present(stw_winsys_framebuffer *fb)
151 {
152 auto framebuffer = d3d12_wgl_framebuffer(fb);
153 if (!framebuffer->swapchain) {
154 debug_printf("D3D12: Cannot present; no swapchain");
155 return false;
156 }
157
158 if (stw_dev->swap_interval < 1)
159 return S_OK == framebuffer->swapchain->Present(0, DXGI_PRESENT_ALLOW_TEARING);
160 else
161 return S_OK == framebuffer->swapchain->Present(stw_dev->swap_interval, 0);
162 }
163
164 static struct pipe_resource *
d3d12_wgl_framebuffer_get_resource(struct stw_winsys_framebuffer * pframebuffer,st_attachment_type statt)165 d3d12_wgl_framebuffer_get_resource(struct stw_winsys_framebuffer *pframebuffer,
166 st_attachment_type statt)
167 {
168 auto framebuffer = d3d12_wgl_framebuffer(pframebuffer);
169 auto pscreen = &framebuffer->screen->base;
170
171 if (!framebuffer->swapchain)
172 return nullptr;
173
174 UINT index = framebuffer->swapchain->GetCurrentBackBufferIndex();
175 if (statt == ST_ATTACHMENT_FRONT_LEFT)
176 index = !index;
177
178 if (framebuffer->buffers[index]) {
179 pipe_reference(NULL, &framebuffer->buffers[index]->reference);
180 return framebuffer->buffers[index];
181 }
182
183 ID3D12Resource *res;
184 framebuffer->swapchain->GetBuffer(index, IID_PPV_ARGS(&res));
185 if (!res)
186 return nullptr;
187
188 struct winsys_handle handle;
189 memset(&handle, 0, sizeof(handle));
190 handle.type = WINSYS_HANDLE_TYPE_D3D12_RES;
191 handle.com_obj = res;
192
193 D3D12_RESOURCE_DESC res_desc = res->GetDesc();
194
195 struct pipe_resource templ;
196 memset(&templ, 0, sizeof(templ));
197 templ.target = PIPE_TEXTURE_2D;
198 templ.format = framebuffer->pformat;
199 templ.width0 = res_desc.Width;
200 templ.height0 = res_desc.Height;
201 templ.depth0 = 1;
202 templ.array_size = res_desc.DepthOrArraySize;
203 templ.nr_samples = res_desc.SampleDesc.Count;
204 templ.last_level = res_desc.MipLevels - 1;
205 templ.bind = PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_RENDER_TARGET;
206 templ.usage = PIPE_USAGE_DEFAULT;
207 templ.flags = 0;
208
209 pipe_resource_reference(&framebuffer->buffers[index],
210 pscreen->resource_from_handle(pscreen, &templ, &handle,
211 PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE));
212 return framebuffer->buffers[index];
213 }
214
215 struct stw_winsys_framebuffer *
d3d12_wgl_create_framebuffer(struct pipe_screen * screen,HWND hWnd,int iPixelFormat)216 d3d12_wgl_create_framebuffer(struct pipe_screen *screen,
217 HWND hWnd,
218 int iPixelFormat)
219 {
220 const struct stw_pixelformat_info *pfi =
221 stw_pixelformat_get_info(iPixelFormat);
222 if (!(pfi->pfd.dwFlags & PFD_DOUBLEBUFFER) ||
223 (pfi->pfd.dwFlags & PFD_SUPPORT_GDI))
224 return NULL;
225
226 struct d3d12_wgl_framebuffer *fb = CALLOC_STRUCT(d3d12_wgl_framebuffer);
227 if (!fb)
228 return NULL;
229
230 new (fb) struct d3d12_wgl_framebuffer();
231
232 fb->window = hWnd;
233 fb->screen = d3d12_screen(screen);
234 fb->base.destroy = d3d12_wgl_framebuffer_destroy;
235 fb->base.resize = d3d12_wgl_framebuffer_resize;
236 fb->base.present = d3d12_wgl_framebuffer_present;
237 fb->base.get_resource = d3d12_wgl_framebuffer_get_resource;
238
239 return &fb->base;
240 }
241