1 /* RetroArch - A frontend for libretro.
2 * Copyright (C) 2014-2018 - Ali Bouhlel
3 * Copyright (C) 2016-2019 - Brad Parker
4 *
5 * RetroArch is free software: you can redistribute it and/or modify it under the terms
6 * of the GNU General Public License as published by the Free Software Found-
7 * ation, either version 3 of the License, or (at your option) any later version.
8 *
9 * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
10 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along with RetroArch.
14 * If not, see <http://www.gnu.org/licenses/>.
15 */
16
17 #define CINTERFACE
18
19 #include <assert.h>
20 #include <boolean.h>
21 #include <string/stdstring.h>
22 #include <file/file_path.h>
23 #include <formats/image.h>
24
25 #include "../font_driver.h"
26 #include "../common/d3d_common.h"
27 #include "../common/win32_common.h"
28 #include "../common/dxgi_common.h"
29 #include "../common/d3d12_common.h"
30 #include "../common/d3dcompiler_common.h"
31
32 #include "../../driver.h"
33 #include "../../verbosity.h"
34 #include "../../configuration.h"
35 #include "../../retroarch.h"
36 #ifdef HAVE_REWIND
37 #include "../../state_manager.h"
38 #endif
39
40 #ifdef HAVE_MENU
41 #include "../../menu/menu_driver.h"
42 #endif
43 #ifdef HAVE_GFX_WIDGETS
44 #include "../gfx_widgets.h"
45 #endif
46
47 #include "wiiu/wiiu_dbg.h"
48
49 /* Temporary workaround for d3d12 not being able to poll flags during init */
50 static gfx_ctx_driver_t d3d12_fake_context;
51 static uint32_t d3d12_get_flags(void *data);
52
d3d12_gfx_sync(d3d12_video_t * d3d12)53 static void d3d12_gfx_sync(d3d12_video_t* d3d12)
54 {
55 D3D12SignalCommandQueue(d3d12->queue.handle, d3d12->queue.fence, ++d3d12->queue.fenceValue);
56 if (D3D12GetCompletedValue(d3d12->queue.fence) < d3d12->queue.fenceValue)
57 {
58 D3D12SetEventOnCompletion(
59 d3d12->queue.fence, d3d12->queue.fenceValue, d3d12->queue.fenceEvent);
60 WaitForSingleObject(d3d12->queue.fenceEvent, INFINITE);
61 }
62 }
63
64 #ifdef HAVE_OVERLAY
d3d12_free_overlays(d3d12_video_t * d3d12)65 static void d3d12_free_overlays(d3d12_video_t* d3d12)
66 {
67 unsigned i;
68 for (i = 0; i < (unsigned)d3d12->overlays.count; i++)
69 d3d12_release_texture(&d3d12->overlays.textures[i]);
70
71 Release(d3d12->overlays.vbo);
72 }
73
74 static void
d3d12_overlay_vertex_geom(void * data,unsigned index,float x,float y,float w,float h)75 d3d12_overlay_vertex_geom(void* data, unsigned index, float x, float y, float w, float h)
76 {
77 d3d12_sprite_t* sprites = NULL;
78 D3D12_RANGE range = { 0, 0 };
79 d3d12_video_t* d3d12 = (d3d12_video_t*)data;
80
81 if (!d3d12)
82 return;
83
84 D3D12Map(d3d12->overlays.vbo, 0, &range, (void**)&sprites);
85
86 sprites[index].pos.x = x;
87 sprites[index].pos.y = y;
88 sprites[index].pos.w = w;
89 sprites[index].pos.h = h;
90
91 range.Begin = index * sizeof(*sprites);
92 range.End = range.Begin + sizeof(*sprites);
93 D3D12Unmap(d3d12->overlays.vbo, 0, &range);
94 }
95
d3d12_overlay_tex_geom(void * data,unsigned index,float u,float v,float w,float h)96 static void d3d12_overlay_tex_geom(void* data, unsigned index, float u, float v, float w, float h)
97 {
98 d3d12_sprite_t* sprites = NULL;
99 D3D12_RANGE range = { 0, 0 };
100 d3d12_video_t* d3d12 = (d3d12_video_t*)data;
101
102 if (!d3d12)
103 return;
104
105 D3D12Map(d3d12->overlays.vbo, 0, &range, (void**)&sprites);
106
107 sprites[index].coords.u = u;
108 sprites[index].coords.v = v;
109 sprites[index].coords.w = w;
110 sprites[index].coords.h = h;
111
112 range.Begin = index * sizeof(*sprites);
113 range.End = range.Begin + sizeof(*sprites);
114 D3D12Unmap(d3d12->overlays.vbo, 0, &range);
115 }
116
d3d12_overlay_set_alpha(void * data,unsigned index,float mod)117 static void d3d12_overlay_set_alpha(void* data, unsigned index, float mod)
118 {
119 d3d12_sprite_t* sprites = NULL;
120 D3D12_RANGE range = { 0, 0 };
121 d3d12_video_t* d3d12 = (d3d12_video_t*)data;
122
123 if (!d3d12)
124 return;
125
126 D3D12Map(d3d12->overlays.vbo, 0, &range, (void**)&sprites);
127
128 sprites[index].colors[0] = DXGI_COLOR_RGBA(0xFF, 0xFF, 0xFF, mod * 0xFF);
129 sprites[index].colors[1] = sprites[index].colors[0];
130 sprites[index].colors[2] = sprites[index].colors[0];
131 sprites[index].colors[3] = sprites[index].colors[0];
132
133 range.Begin = index * sizeof(*sprites);
134 range.End = range.Begin + sizeof(*sprites);
135 D3D12Unmap(d3d12->overlays.vbo, 0, &range);
136 }
137
d3d12_overlay_load(void * data,const void * image_data,unsigned num_images)138 static bool d3d12_overlay_load(void* data, const void* image_data, unsigned num_images)
139 {
140 unsigned i;
141 d3d12_sprite_t* sprites = NULL;
142 D3D12_RANGE range = { 0, 0 };
143 d3d12_video_t* d3d12 = (d3d12_video_t*)data;
144 const struct texture_image* images = (const struct texture_image*)image_data;
145
146 if (!d3d12)
147 return false;
148
149 d3d12_gfx_sync(d3d12);
150 d3d12_free_overlays(d3d12);
151 d3d12->overlays.count = num_images;
152 d3d12->overlays.textures = (d3d12_texture_t*)calloc(num_images, sizeof(d3d12_texture_t));
153
154 d3d12->overlays.count = num_images;
155 d3d12->overlays.vbo_view.SizeInBytes = sizeof(d3d12_sprite_t) * d3d12->overlays.count;
156 d3d12->overlays.vbo_view.StrideInBytes = sizeof(d3d12_sprite_t);
157 d3d12->overlays.vbo_view.BufferLocation = d3d12_create_buffer(
158 d3d12->device, d3d12->overlays.vbo_view.SizeInBytes, &d3d12->overlays.vbo);
159
160 D3D12Map(d3d12->overlays.vbo, 0, &range, (void**)&sprites);
161
162 for (i = 0; i < num_images; i++)
163 {
164
165 d3d12->overlays.textures[i].desc.Width = images[i].width;
166 d3d12->overlays.textures[i].desc.Height = images[i].height;
167 d3d12->overlays.textures[i].desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
168 d3d12->overlays.textures[i].srv_heap = &d3d12->desc.srv_heap;
169 d3d12_init_texture(d3d12->device, &d3d12->overlays.textures[i]);
170
171 d3d12_update_texture(
172 images[i].width, images[i].height, 0, DXGI_FORMAT_B8G8R8A8_UNORM, images[i].pixels,
173 &d3d12->overlays.textures[i]);
174
175 sprites[i].pos.x = 0.0f;
176 sprites[i].pos.y = 0.0f;
177 sprites[i].pos.w = 1.0f;
178 sprites[i].pos.h = 1.0f;
179
180 sprites[i].coords.u = 0.0f;
181 sprites[i].coords.v = 0.0f;
182 sprites[i].coords.w = 1.0f;
183 sprites[i].coords.h = 1.0f;
184
185 sprites[i].params.scaling = 1;
186 sprites[i].params.rotation = 0;
187
188 sprites[i].colors[0] = 0xFFFFFFFF;
189 sprites[i].colors[1] = sprites[i].colors[0];
190 sprites[i].colors[2] = sprites[i].colors[0];
191 sprites[i].colors[3] = sprites[i].colors[0];
192 }
193 D3D12Unmap(d3d12->overlays.vbo, 0, NULL);
194
195 return true;
196 }
197
d3d12_overlay_enable(void * data,bool state)198 static void d3d12_overlay_enable(void* data, bool state)
199 {
200 d3d12_video_t* d3d12 = (d3d12_video_t*)data;
201
202 if (!d3d12)
203 return;
204
205 d3d12->overlays.enabled = state;
206 win32_show_cursor(d3d12, state);
207 }
208
d3d12_overlay_full_screen(void * data,bool enable)209 static void d3d12_overlay_full_screen(void* data, bool enable)
210 {
211 d3d12_video_t* d3d12 = (d3d12_video_t*)data;
212
213 if (!d3d12)
214 return;
215
216 d3d12->overlays.fullscreen = enable;
217 }
218
d3d12_get_overlay_interface(void * data,const video_overlay_interface_t ** iface)219 static void d3d12_get_overlay_interface(void* data, const video_overlay_interface_t** iface)
220 {
221 static const video_overlay_interface_t overlay_interface = {
222 d3d12_overlay_enable, d3d12_overlay_load, d3d12_overlay_tex_geom,
223 d3d12_overlay_vertex_geom, d3d12_overlay_full_screen, d3d12_overlay_set_alpha,
224 };
225
226 *iface = &overlay_interface;
227 }
228 #endif
229
d3d12_set_filtering(void * data,unsigned index,bool smooth,bool ctx_scaling)230 static void d3d12_set_filtering(void* data, unsigned index, bool smooth, bool ctx_scaling)
231 {
232 int i;
233 d3d12_video_t* d3d12 = (d3d12_video_t*)data;
234
235 for (i = 0; i < RARCH_WRAP_MAX; i++)
236 {
237 if (smooth)
238 d3d12->samplers[RARCH_FILTER_UNSPEC][i] = d3d12->samplers[RARCH_FILTER_LINEAR][i];
239 else
240 d3d12->samplers[RARCH_FILTER_UNSPEC][i] = d3d12->samplers[RARCH_FILTER_NEAREST][i];
241 }
242 }
243
d3d12_gfx_set_rotation(void * data,unsigned rotation)244 static void d3d12_gfx_set_rotation(void* data, unsigned rotation)
245 {
246 math_matrix_4x4 rot;
247 math_matrix_4x4* mvp;
248 D3D12_RANGE read_range = { 0, 0 };
249 d3d12_video_t* d3d12 = (d3d12_video_t*)data;
250
251 if (!d3d12)
252 return;
253
254 d3d12_gfx_sync(d3d12);
255 d3d12->frame.rotation = rotation;
256
257 matrix_4x4_rotate_z(rot, d3d12->frame.rotation * (M_PI / 2.0f));
258 matrix_4x4_multiply(d3d12->mvp, rot, d3d12->mvp_no_rot);
259
260 D3D12Map(d3d12->frame.ubo, 0, &read_range, (void**)&mvp);
261 *mvp = d3d12->mvp;
262 D3D12Unmap(d3d12->frame.ubo, 0, NULL);
263 }
264
d3d12_update_viewport(void * data,bool force_full)265 static void d3d12_update_viewport(void* data, bool force_full)
266 {
267 d3d12_video_t* d3d12 = (d3d12_video_t*)data;
268
269 video_driver_update_viewport(&d3d12->vp, force_full, d3d12->keep_aspect);
270
271 d3d12->frame.viewport.TopLeftX = d3d12->vp.x;
272 d3d12->frame.viewport.TopLeftY = d3d12->vp.y;
273 d3d12->frame.viewport.Width = d3d12->vp.width;
274 d3d12->frame.viewport.Height = d3d12->vp.height;
275 d3d12->frame.viewport.MaxDepth = 0.0f;
276 d3d12->frame.viewport.MaxDepth = 1.0f;
277
278 /* having to add vp.x and vp.y here doesn't make any sense */
279 d3d12->frame.scissorRect.top = 0;
280 d3d12->frame.scissorRect.left = 0;
281 d3d12->frame.scissorRect.right = d3d12->vp.x + d3d12->vp.width;
282 d3d12->frame.scissorRect.bottom = d3d12->vp.y + d3d12->vp.height;
283
284 if (d3d12->shader_preset && (d3d12->frame.output_size.x != d3d12->vp.width ||
285 d3d12->frame.output_size.y != d3d12->vp.height))
286 d3d12->resize_render_targets = true;
287
288 d3d12->frame.output_size.x = d3d12->vp.width;
289 d3d12->frame.output_size.y = d3d12->vp.height;
290 d3d12->frame.output_size.z = 1.0f / d3d12->vp.width;
291 d3d12->frame.output_size.w = 1.0f / d3d12->vp.height;
292
293 d3d12->resize_viewport = false;
294 }
295
d3d12_free_shader_preset(d3d12_video_t * d3d12)296 static void d3d12_free_shader_preset(d3d12_video_t* d3d12)
297 {
298 unsigned i;
299 if (!d3d12->shader_preset)
300 return;
301
302 for (i = 0; i < d3d12->shader_preset->passes; i++)
303 {
304 unsigned j;
305
306 free(d3d12->shader_preset->pass[i].source.string.vertex);
307 free(d3d12->shader_preset->pass[i].source.string.fragment);
308 free(d3d12->pass[i].semantics.textures);
309 d3d12_release_texture(&d3d12->pass[i].rt);
310 d3d12_release_texture(&d3d12->pass[i].feedback);
311
312 for (j = 0; j < SLANG_CBUFFER_MAX; j++)
313 {
314 free(d3d12->pass[i].semantics.cbuffers[j].uniforms);
315 Release(d3d12->pass[i].buffers[j]);
316 }
317
318 Release(d3d12->pass[i].pipe);
319 }
320
321 memset(d3d12->pass, 0, sizeof(d3d12->pass));
322
323 /* only free the history textures here */
324 for (i = 1; i <= (unsigned)d3d12->shader_preset->history_size; i++)
325 d3d12_release_texture(&d3d12->frame.texture[i]);
326
327 memset(
328 &d3d12->frame.texture[1], 0,
329 sizeof(d3d12->frame.texture[1]) * d3d12->shader_preset->history_size);
330
331 for (i = 0; i < d3d12->shader_preset->luts; i++)
332 d3d12_release_texture(&d3d12->luts[i]);
333
334 memset(d3d12->luts, 0, sizeof(d3d12->luts));
335
336 free(d3d12->shader_preset);
337 d3d12->shader_preset = NULL;
338 d3d12->init_history = false;
339 d3d12->resize_render_targets = false;
340 }
341
d3d12_gfx_set_shader(void * data,enum rarch_shader_type type,const char * path)342 static bool d3d12_gfx_set_shader(void* data, enum rarch_shader_type type, const char* path)
343 {
344 #if defined(HAVE_SLANG) && defined(HAVE_SPIRV_CROSS)
345 unsigned i;
346 d3d12_texture_t* source = NULL;
347 d3d12_video_t* d3d12 = (d3d12_video_t*)data;
348
349 if (!d3d12)
350 return false;
351
352 d3d12_gfx_sync(d3d12);
353 d3d12_free_shader_preset(d3d12);
354
355 if (string_is_empty(path))
356 return true;
357
358 if (type != RARCH_SHADER_SLANG)
359 {
360 RARCH_WARN("[D3D12]: Only Slang shaders are supported. Falling back to stock.\n");
361 return false;
362 }
363
364 d3d12->shader_preset = (struct video_shader*)calloc(1, sizeof(*d3d12->shader_preset));
365
366 if (!video_shader_load_preset_into_shader(path, d3d12->shader_preset))
367 goto error;
368
369 source = &d3d12->frame.texture[0];
370 for (i = 0; i < d3d12->shader_preset->passes; source = &d3d12->pass[i++].rt)
371 {
372 unsigned j;
373 /* clang-format off */
374 semantics_map_t semantics_map = {
375 {
376 /* Original */
377 { &d3d12->frame.texture[0], 0,
378 &d3d12->frame.texture[0].size_data, 0},
379
380 /* Source */
381 { source, 0,
382 &source->size_data, 0},
383
384 /* OriginalHistory */
385 { &d3d12->frame.texture[0], sizeof(*d3d12->frame.texture),
386 &d3d12->frame.texture[0].size_data, sizeof(*d3d12->frame.texture)},
387
388 /* PassOutput */
389 { &d3d12->pass[0].rt, sizeof(*d3d12->pass),
390 &d3d12->pass[0].rt.size_data, sizeof(*d3d12->pass)},
391
392 /* PassFeedback */
393 { &d3d12->pass[0].feedback, sizeof(*d3d12->pass),
394 &d3d12->pass[0].feedback.size_data, sizeof(*d3d12->pass)},
395
396 /* User */
397 { &d3d12->luts[0], sizeof(*d3d12->luts),
398 &d3d12->luts[0].size_data, sizeof(*d3d12->luts)},
399 },
400 {
401 &d3d12->mvp, /* MVP */
402 &d3d12->pass[i].rt.size_data, /* OutputSize */
403 &d3d12->frame.output_size, /* FinalViewportSize */
404 &d3d12->pass[i].frame_count, /* FrameCount */
405 &d3d12->pass[i].frame_direction, /* FrameDirection */
406 }
407 };
408 /* clang-format on */
409
410 if (!slang_process(
411 d3d12->shader_preset, i, RARCH_SHADER_HLSL, 50, &semantics_map,
412 &d3d12->pass[i].semantics))
413 goto error;
414
415 {
416 D3DBlob vs_code = NULL;
417 D3DBlob ps_code = NULL;
418 D3D12_GRAPHICS_PIPELINE_STATE_DESC desc = { d3d12->desc.sl_rootSignature };
419
420 static const D3D12_INPUT_ELEMENT_DESC inputElementDesc[] = {
421 { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(d3d12_vertex_t, position),
422 D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
423 { "TEXCOORD", 1, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(d3d12_vertex_t, texcoord),
424 D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
425 };
426 #ifdef DEBUG
427 bool save_hlsl = true;
428 #else
429 bool save_hlsl = false;
430 #endif
431 static const char vs_ext[] = ".vs.hlsl";
432 static const char ps_ext[] = ".ps.hlsl";
433 char vs_path[PATH_MAX_LENGTH] = {0};
434 char ps_path[PATH_MAX_LENGTH] = {0};
435 const char* slang_path = d3d12->shader_preset->pass[i].source.path;
436 const char* vs_src = d3d12->shader_preset->pass[i].source.string.vertex;
437 const char* ps_src = d3d12->shader_preset->pass[i].source.string.fragment;
438
439 strlcpy(vs_path, slang_path, sizeof(vs_path));
440 strlcpy(ps_path, slang_path, sizeof(ps_path));
441 strlcat(vs_path, vs_ext, sizeof(vs_path));
442 strlcat(ps_path, ps_ext, sizeof(ps_path));
443
444 if (!d3d_compile(vs_src, 0, vs_path, "main", "vs_5_0", &vs_code))
445 save_hlsl = true;
446 if (!d3d_compile(ps_src, 0, ps_path, "main", "ps_5_0", &ps_code))
447 save_hlsl = true;
448
449 desc.BlendState.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
450 if (i == d3d12->shader_preset->passes - 1)
451 desc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
452 else
453 desc.RTVFormats[0] = glslang_format_to_dxgi(d3d12->pass[i].semantics.format);
454
455 desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
456 desc.InputLayout.pInputElementDescs = inputElementDesc;
457 desc.InputLayout.NumElements = countof(inputElementDesc);
458
459 if (!d3d12_init_pipeline(
460 d3d12->device, vs_code, ps_code, NULL, &desc, &d3d12->pass[i].pipe))
461 save_hlsl = true;
462
463 if (save_hlsl)
464 {
465 FILE* fp = fopen(vs_path, "w");
466 fwrite(vs_src, 1, strlen(vs_src), fp);
467 fclose(fp);
468
469 fp = fopen(ps_path, "w");
470 fwrite(ps_src, 1, strlen(ps_src), fp);
471 fclose(fp);
472 }
473
474 free(d3d12->shader_preset->pass[i].source.string.vertex);
475 free(d3d12->shader_preset->pass[i].source.string.fragment);
476
477 d3d12->shader_preset->pass[i].source.string.vertex = NULL;
478 d3d12->shader_preset->pass[i].source.string.fragment = NULL;
479
480 Release(vs_code);
481 Release(ps_code);
482
483 if (!d3d12->pass[i].pipe)
484 goto error;
485
486 d3d12->pass[i].rt.rt_view.ptr =
487 d3d12->desc.rtv_heap.cpu.ptr +
488 (countof(d3d12->chain.renderTargets) + (2 * i)) * d3d12->desc.rtv_heap.stride;
489 d3d12->pass[i].feedback.rt_view.ptr = d3d12->pass[i].rt.rt_view.ptr + d3d12->desc.rtv_heap.stride;
490
491 d3d12->pass[i].textures.ptr =
492 d3d12->desc.srv_heap.gpu.ptr + i * SLANG_NUM_SEMANTICS * d3d12->desc.srv_heap.stride;
493 d3d12->pass[i].samplers.ptr = d3d12->desc.sampler_heap.gpu.ptr +
494 i * SLANG_NUM_SEMANTICS * d3d12->desc.sampler_heap.stride;
495 }
496
497 for (j = 0; j < SLANG_CBUFFER_MAX; j++)
498 {
499 if (!d3d12->pass[i].semantics.cbuffers[j].size)
500 continue;
501
502 d3d12->pass[i].buffer_view[j].SizeInBytes = d3d12->pass[i].semantics.cbuffers[j].size;
503 d3d12->pass[i].buffer_view[j].BufferLocation = d3d12_create_buffer(
504 d3d12->device, d3d12->pass[i].buffer_view[j].SizeInBytes,
505 &d3d12->pass[i].buffers[j]);
506 }
507 }
508
509 for (i = 0; i < d3d12->shader_preset->luts; i++)
510 {
511 struct texture_image image = { 0 };
512 image.supports_rgba = true;
513
514 if (!image_texture_load(&image, d3d12->shader_preset->lut[i].path))
515 goto error;
516
517 d3d12->luts[i].desc.Width = image.width;
518 d3d12->luts[i].desc.Height = image.height;
519 d3d12->luts[i].desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
520 d3d12->luts[i].srv_heap = &d3d12->desc.srv_heap;
521
522 if (d3d12->shader_preset->lut[i].mipmap)
523 d3d12->luts[i].desc.MipLevels = UINT16_MAX;
524
525 d3d12_init_texture(d3d12->device, &d3d12->luts[i]);
526
527 d3d12_update_texture(
528 image.width, image.height, 0, DXGI_FORMAT_R8G8B8A8_UNORM, image.pixels,
529 &d3d12->luts[i]);
530
531 image_texture_free(&image);
532 }
533
534 d3d12->resize_render_targets = true;
535 d3d12->init_history = true;
536
537 return true;
538
539 error:
540 d3d12_free_shader_preset(d3d12);
541 #endif
542 return false;
543 }
544
d3d12_gfx_init_pipelines(d3d12_video_t * d3d12)545 static bool d3d12_gfx_init_pipelines(d3d12_video_t* d3d12)
546 {
547 D3DBlob vs_code = NULL;
548 D3DBlob ps_code = NULL;
549 D3DBlob gs_code = NULL;
550 D3DBlob cs_code = NULL;
551 settings_t * settings = config_get_ptr();
552 D3D12_GRAPHICS_PIPELINE_STATE_DESC desc = { d3d12->desc.rootSignature };
553
554 desc.BlendState.RenderTarget[0] = d3d12_blend_enable_desc;
555 desc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
556
557 {
558 static const char shader[] =
559 #include "../drivers/d3d_shaders/opaque_sm5.hlsl.h"
560 ;
561
562 static const D3D12_INPUT_ELEMENT_DESC inputElementDesc[] = {
563 { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(d3d12_vertex_t, position),
564 D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
565 { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(d3d12_vertex_t, texcoord),
566 D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
567 { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(d3d12_vertex_t, color),
568 D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
569 };
570
571 if (!d3d_compile(shader, sizeof(shader), NULL, "VSMain", "vs_5_0", &vs_code))
572 goto error;
573 if (!d3d_compile(shader, sizeof(shader), NULL, "PSMain", "ps_5_0", &ps_code))
574 goto error;
575
576 desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
577 desc.InputLayout.pInputElementDescs = inputElementDesc;
578 desc.InputLayout.NumElements = countof(inputElementDesc);
579
580 if (!d3d12_init_pipeline(
581 d3d12->device, vs_code, ps_code, NULL, &desc,
582 &d3d12->pipes[VIDEO_SHADER_STOCK_BLEND]))
583 goto error;
584
585 Release(vs_code);
586 Release(ps_code);
587 vs_code = NULL;
588 ps_code = NULL;
589 }
590 {
591 static const char shader[] =
592 #include "d3d_shaders/sprite_sm4.hlsl.h"
593 ;
594
595 D3D12_INPUT_ELEMENT_DESC inputElementDesc[] = {
596 { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(d3d12_sprite_t, pos),
597 D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
598 { "TEXCOORD", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(d3d12_sprite_t, coords),
599 D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
600 { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(d3d12_sprite_t, colors[0]),
601 D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
602 { "COLOR", 1, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(d3d12_sprite_t, colors[1]),
603 D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
604 { "COLOR", 2, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(d3d12_sprite_t, colors[2]),
605 D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
606 { "COLOR", 3, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(d3d12_sprite_t, colors[3]),
607 D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
608 { "PARAMS", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(d3d12_sprite_t, params),
609 D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
610 };
611
612 if (!d3d_compile(shader, sizeof(shader), NULL, "VSMain", "vs_5_0", &vs_code))
613 goto error;
614 if (!d3d_compile(shader, sizeof(shader), NULL, "PSMain", "ps_5_0", &ps_code))
615 goto error;
616 if (!d3d_compile(shader, sizeof(shader), NULL, "GSMain", "gs_5_0", &gs_code))
617 goto error;
618
619 desc.BlendState.RenderTarget[0].BlendEnable = false;
620 desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
621 desc.InputLayout.pInputElementDescs = inputElementDesc;
622 desc.InputLayout.NumElements = countof(inputElementDesc);
623
624 if (!d3d12_init_pipeline(
625 d3d12->device, vs_code, ps_code, gs_code, &desc, &d3d12->sprites.pipe_noblend))
626 goto error;
627
628 desc.BlendState.RenderTarget[0].BlendEnable = true;
629 if (!d3d12_init_pipeline(
630 d3d12->device, vs_code, ps_code, gs_code, &desc, &d3d12->sprites.pipe_blend))
631 goto error;
632
633 Release(ps_code);
634 ps_code = NULL;
635
636 if (!d3d_compile(shader, sizeof(shader), NULL, "PSMainA8", "ps_5_0", &ps_code))
637 goto error;
638
639 if (!d3d12_init_pipeline(
640 d3d12->device, vs_code, ps_code, gs_code, &desc, &d3d12->sprites.pipe_font))
641 goto error;
642
643 Release(vs_code);
644 Release(ps_code);
645 Release(gs_code);
646 vs_code = NULL;
647 ps_code = NULL;
648 gs_code = NULL;
649 }
650
651 if (string_is_equal(settings->arrays.menu_driver, "xmb"))
652 {
653 {
654 static const char ribbon[] =
655 #include "d3d_shaders/ribbon_sm4.hlsl.h"
656 ;
657 static const char ribbon_simple[] =
658 #include "d3d_shaders/ribbon_simple_sm4.hlsl.h"
659 ;
660
661 D3D12_INPUT_ELEMENT_DESC inputElementDesc[] = {
662 { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0,
663 D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
664 };
665
666 desc.BlendState.RenderTarget[0].SrcBlend = D3D12_BLEND_ONE;
667 desc.BlendState.RenderTarget[0].DestBlend = D3D12_BLEND_ONE;
668 desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
669 desc.InputLayout.pInputElementDescs = inputElementDesc;
670 desc.InputLayout.NumElements = countof(inputElementDesc);
671
672 if (!d3d_compile(ribbon, sizeof(ribbon), NULL, "VSMain", "vs_5_0", &vs_code))
673 goto error;
674 if (!d3d_compile(ribbon, sizeof(ribbon), NULL, "PSMain", "ps_5_0", &ps_code))
675 goto error;
676
677 if (!d3d12_init_pipeline(
678 d3d12->device, vs_code, ps_code, NULL, &desc, &d3d12->pipes[VIDEO_SHADER_MENU]))
679 goto error;
680
681 Release(vs_code);
682 Release(ps_code);
683 vs_code = NULL;
684 ps_code = NULL;
685
686 if (!d3d_compile(ribbon_simple, sizeof(ribbon_simple), NULL, "VSMain", "vs_5_0", &vs_code))
687 goto error;
688 if (!d3d_compile(ribbon_simple, sizeof(ribbon_simple), NULL, "PSMain", "ps_5_0", &ps_code))
689 goto error;
690
691 if (!d3d12_init_pipeline(
692 d3d12->device, vs_code, ps_code, NULL, &desc, &d3d12->pipes[VIDEO_SHADER_MENU_2]))
693 goto error;
694
695 Release(vs_code);
696 Release(ps_code);
697 vs_code = NULL;
698 ps_code = NULL;
699 }
700
701 {
702 static const char simple_snow[] =
703 #include "d3d_shaders/simple_snow_sm4.hlsl.h"
704 ;
705 static const char snow[] =
706 #include "d3d_shaders/snow_sm4.hlsl.h"
707 ;
708 static const char bokeh[] =
709 #include "d3d_shaders/bokeh_sm4.hlsl.h"
710 ;
711 static const char snowflake[] =
712 #include "d3d_shaders/snowflake_sm4.hlsl.h"
713 ;
714
715 D3D12_INPUT_ELEMENT_DESC inputElementDesc[] = {
716 { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(d3d12_vertex_t, position),
717 D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
718 { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(d3d12_vertex_t, texcoord),
719 D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
720 };
721
722 desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
723 desc.InputLayout.pInputElementDescs = inputElementDesc;
724 desc.InputLayout.NumElements = countof(inputElementDesc);
725
726 if (!d3d_compile(simple_snow, sizeof(simple_snow), NULL, "VSMain", "vs_5_0", &vs_code))
727 goto error;
728 if (!d3d_compile(simple_snow, sizeof(simple_snow), NULL, "PSMain", "ps_5_0", &ps_code))
729 goto error;
730
731 if (!d3d12_init_pipeline(
732 d3d12->device, vs_code, ps_code, NULL, &desc, &d3d12->pipes[VIDEO_SHADER_MENU_3]))
733 goto error;
734
735 Release(vs_code);
736 Release(ps_code);
737 vs_code = NULL;
738 ps_code = NULL;
739
740 if (!d3d_compile(snow, sizeof(snow), NULL, "VSMain", "vs_5_0", &vs_code))
741 goto error;
742 if (!d3d_compile(snow, sizeof(snow), NULL, "PSMain", "ps_5_0", &ps_code))
743 goto error;
744
745 if (!d3d12_init_pipeline(
746 d3d12->device, vs_code, ps_code, NULL, &desc, &d3d12->pipes[VIDEO_SHADER_MENU_4]))
747 goto error;
748
749 Release(vs_code);
750 Release(ps_code);
751 vs_code = NULL;
752 ps_code = NULL;
753
754 if (!d3d_compile(bokeh, sizeof(bokeh), NULL, "VSMain", "vs_5_0", &vs_code))
755 goto error;
756 if (!d3d_compile(bokeh, sizeof(bokeh), NULL, "PSMain", "ps_5_0", &ps_code))
757 goto error;
758
759 if (!d3d12_init_pipeline(
760 d3d12->device, vs_code, ps_code, NULL, &desc, &d3d12->pipes[VIDEO_SHADER_MENU_5]))
761 goto error;
762
763 Release(vs_code);
764 Release(ps_code);
765 vs_code = NULL;
766 ps_code = NULL;
767
768 if (!d3d_compile(snowflake, sizeof(snowflake), NULL, "VSMain", "vs_5_0", &vs_code))
769 goto error;
770 if (!d3d_compile(snowflake, sizeof(snowflake), NULL, "PSMain", "ps_5_0", &ps_code))
771 goto error;
772
773 if (!d3d12_init_pipeline(
774 d3d12->device, vs_code, ps_code, NULL, &desc, &d3d12->pipes[VIDEO_SHADER_MENU_6]))
775 goto error;
776
777 Release(vs_code);
778 Release(ps_code);
779 vs_code = NULL;
780 ps_code = NULL;
781 }
782 }
783
784 {
785 static const char shader[] =
786 #include "d3d_shaders/mimpapgen_sm5.h"
787 ;
788 D3D12_COMPUTE_PIPELINE_STATE_DESC desc = { d3d12->desc.cs_rootSignature };
789 if (!d3d_compile(shader, sizeof(shader), NULL, "CSMain", "cs_5_0", &cs_code))
790 goto error;
791
792 desc.CS.pShaderBytecode = D3DGetBufferPointer(cs_code);
793 desc.CS.BytecodeLength = D3DGetBufferSize(cs_code);
794 if (!D3D12CreateComputePipelineState(d3d12->device, &desc, &d3d12->mipmapgen_pipe))
795
796 Release(cs_code);
797 cs_code = NULL;
798 }
799
800 return true;
801
802 error:
803 Release(vs_code);
804 Release(ps_code);
805 Release(gs_code);
806 Release(cs_code);
807 return false;
808 }
809
d3d12_gfx_free(void * data)810 static void d3d12_gfx_free(void* data)
811 {
812 unsigned i;
813 d3d12_video_t* d3d12 = (d3d12_video_t*)data;
814
815 if (!d3d12)
816 return;
817
818 d3d12_gfx_sync(d3d12);
819
820 #ifdef HAVE_OVERLAY
821 d3d12_free_overlays(d3d12);
822 #endif
823
824 d3d12_free_shader_preset(d3d12);
825
826 font_driver_free_osd();
827
828 Release(d3d12->sprites.vbo);
829 Release(d3d12->menu_pipeline_vbo);
830
831 Release(d3d12->frame.ubo);
832 Release(d3d12->frame.vbo);
833 Release(d3d12->frame.texture[0].handle);
834 Release(d3d12->frame.texture[0].upload_buffer);
835 Release(d3d12->menu.vbo);
836 Release(d3d12->menu.texture.handle);
837 Release(d3d12->menu.texture.upload_buffer);
838
839 free(d3d12->desc.sampler_heap.map);
840 free(d3d12->desc.srv_heap.map);
841 free(d3d12->desc.rtv_heap.map);
842 Release(d3d12->desc.sampler_heap.handle);
843 Release(d3d12->desc.srv_heap.handle);
844 Release(d3d12->desc.rtv_heap.handle);
845
846 Release(d3d12->desc.cs_rootSignature);
847 Release(d3d12->desc.sl_rootSignature);
848 Release(d3d12->desc.rootSignature);
849
850 Release(d3d12->ubo);
851
852 for (i = 0; i < GFX_MAX_SHADERS; i++)
853 Release(d3d12->pipes[i]);
854
855 Release(d3d12->mipmapgen_pipe);
856 Release(d3d12->sprites.pipe_blend);
857 Release(d3d12->sprites.pipe_noblend);
858 Release(d3d12->sprites.pipe_font);
859
860 Release(d3d12->queue.fence);
861 Release(d3d12->chain.renderTargets[0]);
862 Release(d3d12->chain.renderTargets[1]);
863 Release(d3d12->chain.handle);
864
865 Release(d3d12->queue.cmd);
866 Release(d3d12->queue.allocator);
867 Release(d3d12->queue.handle);
868
869 Release(d3d12->factory);
870 Release(d3d12->device);
871 Release(d3d12->adapter);
872
873 for (i = 0; i < D3D12_MAX_GPU_COUNT; i++)
874 {
875 if (d3d12->adapters[i])
876 {
877 Release(d3d12->adapters[i]);
878 d3d12->adapters[i] = NULL;
879 }
880 }
881
882 #ifdef HAVE_MONITOR
883 win32_monitor_from_window();
884 #endif
885 #ifdef HAVE_WINDOW
886 win32_destroy_window();
887 #endif
888
889 free(d3d12);
890 }
891
d3d12_gfx_init(const video_info_t * video,input_driver_t ** input,void ** input_data)892 static void *d3d12_gfx_init(const video_info_t* video,
893 input_driver_t** input, void** input_data)
894 {
895 #ifdef HAVE_MONITOR
896 MONITORINFOEX current_mon;
897 HMONITOR hm_to_use;
898 WNDCLASSEX wndclass = { 0 };
899 #endif
900 settings_t* settings = config_get_ptr();
901 d3d12_video_t* d3d12 = (d3d12_video_t*)calloc(1, sizeof(*d3d12));
902
903 if (!d3d12)
904 return NULL;
905
906 #ifdef HAVE_WINDOW
907 win32_window_reset();
908 #endif
909 #ifdef HAVE_MONITOR
910 win32_monitor_init();
911 wndclass.lpfnWndProc = wnd_proc_d3d_common;
912 #ifdef HAVE_DINPUT
913 if (string_is_equal(settings->arrays.input_driver, "dinput"))
914 wndclass.lpfnWndProc = wnd_proc_d3d_dinput;
915 #endif
916 #ifdef HAVE_WINDOW
917 win32_window_init(&wndclass, true, NULL);
918 #endif
919
920 win32_monitor_info(¤t_mon, &hm_to_use, &d3d12->cur_mon_id);
921 #endif
922
923 d3d12->vp.full_width = video->width;
924 d3d12->vp.full_height = video->height;
925
926 #ifdef HAVE_MONITOR
927 if (!d3d12->vp.full_width)
928 d3d12->vp.full_width = current_mon.rcMonitor.right - current_mon.rcMonitor.left;
929 if (!d3d12->vp.full_height)
930 d3d12->vp.full_height = current_mon.rcMonitor.bottom - current_mon.rcMonitor.top;
931 #endif
932
933 if (!win32_set_video_mode(d3d12, d3d12->vp.full_width, d3d12->vp.full_height, video->fullscreen))
934 {
935 RARCH_ERR("[D3D12]: win32_set_video_mode failed.\n");
936 goto error;
937 }
938
939 d3d_input_driver(settings->arrays.input_driver, settings->arrays.input_joypad_driver, input, input_data);
940
941 if (!d3d12_init_base(d3d12))
942 goto error;
943
944 if (!d3d12_init_descriptors(d3d12))
945 goto error;
946
947 if (!d3d12_gfx_init_pipelines(d3d12))
948 goto error;
949
950 if (!d3d12_init_queue(d3d12))
951 goto error;
952
953 #ifdef __WINRT__
954 if (!d3d12_init_swapchain(d3d12, d3d12->vp.full_width, d3d12->vp.full_height, uwp_get_corewindow()))
955 goto error;
956 #else
957 if (!d3d12_init_swapchain(d3d12, d3d12->vp.full_width, d3d12->vp.full_height, main_window.hwnd))
958 goto error;
959 #endif
960
961 d3d12_init_samplers(d3d12);
962 d3d12_set_filtering(d3d12, 0, video->smooth, video->ctx_scaling);
963
964 d3d12_create_fullscreen_quad_vbo(d3d12->device, &d3d12->frame.vbo_view, &d3d12->frame.vbo);
965 d3d12_create_fullscreen_quad_vbo(d3d12->device, &d3d12->menu.vbo_view, &d3d12->menu.vbo);
966
967 d3d12->sprites.capacity = 16 * 1024;
968 d3d12->sprites.vbo_view.SizeInBytes = sizeof(d3d12_sprite_t) * d3d12->sprites.capacity;
969 d3d12->sprites.vbo_view.StrideInBytes = sizeof(d3d12_sprite_t);
970 d3d12->sprites.vbo_view.BufferLocation = d3d12_create_buffer(
971 d3d12->device, d3d12->sprites.vbo_view.SizeInBytes, &d3d12->sprites.vbo);
972
973 d3d12->ubo_view.SizeInBytes = sizeof(d3d12_uniform_t);
974 d3d12->ubo_view.BufferLocation =
975 d3d12_create_buffer(d3d12->device, d3d12->ubo_view.SizeInBytes, &d3d12->ubo);
976
977 d3d12->frame.ubo_view.SizeInBytes = sizeof(d3d12_uniform_t);
978 d3d12->frame.ubo_view.BufferLocation =
979 d3d12_create_buffer(d3d12->device, d3d12->frame.ubo_view.SizeInBytes, &d3d12->frame.ubo);
980
981 matrix_4x4_ortho(d3d12->mvp_no_rot, 0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f);
982
983 d3d12->ubo_values.mvp = d3d12->mvp_no_rot;
984 d3d12->ubo_values.OutputSize.width = d3d12->chain.viewport.Width;
985 d3d12->ubo_values.OutputSize.height = d3d12->chain.viewport.Height;
986
987 {
988 math_matrix_4x4* mvp;
989 D3D12_RANGE read_range = { 0, 0 };
990 D3D12Map(d3d12->ubo, 0, &read_range, (void**)&mvp);
991 *mvp = d3d12->mvp_no_rot;
992 D3D12Unmap(d3d12->ubo, 0, NULL);
993 }
994
995 d3d12_gfx_set_rotation(d3d12, 0);
996 video_driver_set_size(d3d12->vp.full_width, d3d12->vp.full_height);
997 d3d12->chain.viewport.Width = d3d12->vp.full_width;
998 d3d12->chain.viewport.Height = d3d12->vp.full_height;
999 d3d12->resize_viewport = true;
1000 d3d12->keep_aspect = video->force_aspect;
1001 d3d12->chain.vsync = video->vsync;
1002 d3d12->format = video->rgb32 ? DXGI_FORMAT_B8G8R8X8_UNORM : DXGI_FORMAT_B5G6R5_UNORM;
1003 d3d12->frame.texture[0].desc.Format = d3d12->format;
1004 d3d12->frame.texture[0].desc.Width = 4;
1005 d3d12->frame.texture[0].desc.Height = 4;
1006 d3d12->frame.texture[0].srv_heap = &d3d12->desc.srv_heap;
1007 d3d12_init_texture(d3d12->device, &d3d12->frame.texture[0]);
1008
1009 font_driver_init_osd(d3d12,
1010 video,
1011 false,
1012 video->is_threaded,
1013 FONT_DRIVER_RENDER_D3D12_API);
1014
1015 {
1016 d3d12_fake_context.get_flags = d3d12_get_flags;
1017 d3d12_fake_context.get_metrics = win32_get_metrics;
1018 video_context_driver_set(&d3d12_fake_context);
1019 const char *shader_preset = retroarch_get_shader_preset();
1020 enum rarch_shader_type type = video_shader_parse_type(shader_preset);
1021 d3d12_gfx_set_shader(d3d12, type, shader_preset);
1022 }
1023
1024 return d3d12;
1025
1026 error:
1027 RARCH_ERR("[D3D12]: Failed to init video driver.\n");
1028 d3d12_gfx_free(d3d12);
1029 return NULL;
1030 }
1031
d3d12_init_history(d3d12_video_t * d3d12,unsigned width,unsigned height)1032 static void d3d12_init_history(d3d12_video_t* d3d12, unsigned width, unsigned height)
1033 {
1034 unsigned i;
1035
1036 /* todo: should we init history to max_width/max_height instead ?
1037 * to prevent out of memory errors happening several frames later
1038 * and to reduce memory fragmentation */
1039
1040 assert(d3d12->shader_preset);
1041 for (i = 0; i < (unsigned)d3d12->shader_preset->history_size + 1; i++)
1042 {
1043 d3d12->frame.texture[i].desc.Width = width;
1044 d3d12->frame.texture[i].desc.Height = height;
1045 d3d12->frame.texture[i].desc.Format = d3d12->frame.texture[0].desc.Format;
1046 d3d12->frame.texture[i].desc.MipLevels = d3d12->frame.texture[0].desc.MipLevels;
1047 d3d12->frame.texture[i].srv_heap = &d3d12->desc.srv_heap;
1048 d3d12_init_texture(d3d12->device, &d3d12->frame.texture[i]);
1049 /* todo: clear texture ? */
1050 }
1051 d3d12->init_history = false;
1052 }
d3d12_init_render_targets(d3d12_video_t * d3d12,unsigned width,unsigned height)1053 static void d3d12_init_render_targets(d3d12_video_t* d3d12, unsigned width, unsigned height)
1054 {
1055 unsigned i;
1056
1057 assert(d3d12->shader_preset);
1058
1059 for (i = 0; i < d3d12->shader_preset->passes; i++)
1060 {
1061 struct video_shader_pass* pass = &d3d12->shader_preset->pass[i];
1062
1063 if (pass->fbo.valid)
1064 {
1065
1066 switch (pass->fbo.type_x)
1067 {
1068 case RARCH_SCALE_INPUT:
1069 width *= pass->fbo.scale_x;
1070 break;
1071
1072 case RARCH_SCALE_VIEWPORT:
1073 width = d3d12->vp.width * pass->fbo.scale_x;
1074 break;
1075
1076 case RARCH_SCALE_ABSOLUTE:
1077 width = pass->fbo.abs_x;
1078 break;
1079
1080 default:
1081 break;
1082 }
1083
1084 if (!width)
1085 width = d3d12->vp.width;
1086
1087 switch (pass->fbo.type_y)
1088 {
1089 case RARCH_SCALE_INPUT:
1090 height *= pass->fbo.scale_y;
1091 break;
1092
1093 case RARCH_SCALE_VIEWPORT:
1094 height = d3d12->vp.height * pass->fbo.scale_y;
1095 break;
1096
1097 case RARCH_SCALE_ABSOLUTE:
1098 height = pass->fbo.abs_y;
1099 break;
1100
1101 default:
1102 break;
1103 }
1104
1105 if (!height)
1106 height = d3d12->vp.height;
1107 }
1108 else if (i == (d3d12->shader_preset->passes - 1))
1109 {
1110 width = d3d12->vp.width;
1111 height = d3d12->vp.height;
1112 }
1113
1114 RARCH_LOG("[D3D12]: Updating framebuffer size %u x %u.\n", width, height);
1115
1116 if ((i != (d3d12->shader_preset->passes - 1)) || (width != d3d12->vp.width) ||
1117 (height != d3d12->vp.height))
1118 {
1119 d3d12->pass[i].viewport.Width = width;
1120 d3d12->pass[i].viewport.Height = height;
1121 d3d12->pass[i].viewport.MaxDepth = 1.0;
1122 d3d12->pass[i].scissorRect.right = width;
1123 d3d12->pass[i].scissorRect.bottom = height;
1124 d3d12->pass[i].rt.desc.Width = width;
1125 d3d12->pass[i].rt.desc.Height = height;
1126 d3d12->pass[i].rt.desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
1127 d3d12->pass[i].rt.srv_heap = &d3d12->desc.srv_heap;
1128 d3d12->pass[i].rt.desc.Format = glslang_format_to_dxgi(d3d12->pass[i].semantics.format);
1129 d3d12_init_texture(d3d12->device, &d3d12->pass[i].rt);
1130
1131 if (pass->feedback)
1132 {
1133 d3d12->pass[i].feedback.desc = d3d12->pass[i].rt.desc;
1134 d3d12->pass[i].feedback.srv_heap = &d3d12->desc.srv_heap;
1135 d3d12_init_texture(d3d12->device, &d3d12->pass[i].feedback);
1136 /* todo: do we need to clear it to black here ? */
1137 }
1138 }
1139 else
1140 {
1141 d3d12->pass[i].rt.size_data.x = width;
1142 d3d12->pass[i].rt.size_data.y = height;
1143 d3d12->pass[i].rt.size_data.z = 1.0f / width;
1144 d3d12->pass[i].rt.size_data.w = 1.0f / height;
1145 }
1146
1147 d3d12->pass[i].sampler = d3d12->samplers[pass->filter][pass->wrap];
1148 }
1149
1150 d3d12->resize_render_targets = false;
1151
1152 #if 0
1153 error:
1154 d3d12_free_shader_preset(d3d12);
1155 return false;
1156 #endif
1157 }
1158
d3d12_gfx_frame(void * data,const void * frame,unsigned width,unsigned height,uint64_t frame_count,unsigned pitch,const char * msg,video_frame_info_t * video_info)1159 static bool d3d12_gfx_frame(
1160 void* data,
1161 const void* frame,
1162 unsigned width,
1163 unsigned height,
1164 uint64_t frame_count,
1165 unsigned pitch,
1166 const char* msg,
1167 video_frame_info_t* video_info)
1168 {
1169 unsigned i;
1170 d3d12_texture_t* texture = NULL;
1171 d3d12_video_t* d3d12 = (d3d12_video_t*)data;
1172 bool vsync = d3d12->chain.vsync;
1173 unsigned sync_interval = (vsync) ? d3d12->chain.swap_interval : 0;
1174 unsigned present_flags = (vsync) ? 0 : DXGI_PRESENT_ALLOW_TEARING;
1175 const char *stat_text = video_info->stat_text;
1176 bool statistics_show = video_info->statistics_show;
1177 unsigned video_width = video_info->width;
1178 unsigned video_height = video_info->height;
1179 struct font_params *osd_params = (struct font_params*)
1180 &video_info->osd_stat_params;
1181 bool menu_is_alive = video_info->menu_is_alive;
1182 #ifdef HAVE_GFX_WIDGETS
1183 bool widgets_active = video_info->widgets_active;
1184 #endif
1185
1186 if (d3d12->resize_chain)
1187 {
1188 unsigned i;
1189
1190 for (i = 0; i < countof(d3d12->chain.renderTargets); i++)
1191 Release(d3d12->chain.renderTargets[i]);
1192
1193 DXGIResizeBuffers(d3d12->chain.handle, 0, 0, 0, DXGI_FORMAT_UNKNOWN, DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING);
1194
1195 for (i = 0; i < countof(d3d12->chain.renderTargets); i++)
1196 {
1197 DXGIGetSwapChainBuffer(d3d12->chain.handle, i, &d3d12->chain.renderTargets[i]);
1198 D3D12CreateRenderTargetView(
1199 d3d12->device, d3d12->chain.renderTargets[i], NULL, d3d12->chain.desc_handles[i]);
1200 }
1201
1202 d3d12->chain.viewport.Width = video_width;
1203 d3d12->chain.viewport.Height = video_height;
1204 d3d12->chain.scissorRect.right = video_width;
1205 d3d12->chain.scissorRect.bottom = video_height;
1206 d3d12->resize_chain = false;
1207 d3d12->resize_viewport = true;
1208
1209 d3d12->ubo_values.OutputSize.width = d3d12->chain.viewport.Width;
1210 d3d12->ubo_values.OutputSize.height = d3d12->chain.viewport.Height;
1211
1212 video_driver_set_size(video_width, video_height);
1213 }
1214
1215 D3D12ResetCommandAllocator(d3d12->queue.allocator);
1216
1217 D3D12ResetGraphicsCommandList(
1218 d3d12->queue.cmd, d3d12->queue.allocator, d3d12->pipes[VIDEO_SHADER_STOCK_BLEND]);
1219
1220 {
1221 D3D12DescriptorHeap desc_heaps[] = { d3d12->desc.srv_heap.handle,
1222 d3d12->desc.sampler_heap.handle };
1223 D3D12SetDescriptorHeaps(d3d12->queue.cmd, countof(desc_heaps), desc_heaps);
1224 }
1225
1226 #if 0 /* custom viewport doesn't call apply_state_changes, so we can't rely on this for now */
1227 if (d3d12->resize_viewport)
1228 #endif
1229 d3d12_update_viewport(d3d12, false);
1230
1231 D3D12IASetPrimitiveTopology(d3d12->queue.cmd, D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
1232
1233 if (frame && width && height)
1234 {
1235 if (d3d12->shader_preset)
1236 {
1237 if (d3d12->shader_preset->luts && d3d12->luts[0].dirty)
1238 for (i = 0; i < d3d12->shader_preset->luts; i++)
1239 d3d12_upload_texture(d3d12->queue.cmd, &d3d12->luts[i],
1240 d3d12);
1241
1242 if (d3d12->frame.texture[0].desc.Width != width ||
1243 d3d12->frame.texture[0].desc.Height != height)
1244 d3d12->resize_render_targets = true;
1245
1246 if (d3d12->resize_render_targets)
1247 {
1248 /* release all render targets first to avoid memory fragmentation */
1249 for (i = 0; i < d3d12->shader_preset->passes; i++)
1250 {
1251 d3d12_release_texture(&d3d12->pass[i].rt);
1252 d3d12->pass[i].rt.handle = NULL;
1253 d3d12_release_texture(&d3d12->pass[i].feedback);
1254 d3d12->pass[i].feedback.handle = NULL;
1255 }
1256 }
1257
1258 if (d3d12->shader_preset->history_size)
1259 {
1260 if (d3d12->init_history)
1261 d3d12_init_history(d3d12, width, height);
1262 else
1263 {
1264 int k;
1265 /* todo: what about frame-duping ?
1266 * maybe clone d3d12_texture_t with AddRef */
1267 d3d12_texture_t tmp = d3d12->frame.texture[d3d12->shader_preset->history_size];
1268 for (k = d3d12->shader_preset->history_size; k > 0; k--)
1269 d3d12->frame.texture[k] = d3d12->frame.texture[k - 1];
1270 d3d12->frame.texture[0] = tmp;
1271 }
1272 }
1273 }
1274
1275 /* either no history, or we moved a texture of a different size in the front slot */
1276 if (d3d12->frame.texture[0].desc.Width != width ||
1277 d3d12->frame.texture[0].desc.Height != height)
1278 {
1279 d3d12->frame.texture[0].desc.Width = width;
1280 d3d12->frame.texture[0].desc.Height = height;
1281 d3d12->frame.texture[0].srv_heap = &d3d12->desc.srv_heap;
1282 d3d12_init_texture(d3d12->device, &d3d12->frame.texture[0]);
1283 }
1284
1285 if (d3d12->resize_render_targets)
1286 d3d12_init_render_targets(d3d12, width, height);
1287
1288 d3d12_update_texture(width, height, pitch, d3d12->format, frame, &d3d12->frame.texture[0]);
1289
1290 d3d12_upload_texture(d3d12->queue.cmd, &d3d12->frame.texture[0],
1291 d3d12);
1292 }
1293 D3D12IASetVertexBuffers(d3d12->queue.cmd, 0, 1, &d3d12->frame.vbo_view);
1294
1295 texture = d3d12->frame.texture;
1296
1297 if (d3d12->shader_preset)
1298 {
1299 D3D12SetGraphicsRootSignature(d3d12->queue.cmd, d3d12->desc.sl_rootSignature);
1300
1301 for (i = 0; i < d3d12->shader_preset->passes; i++)
1302 {
1303 if (d3d12->shader_preset->pass[i].feedback)
1304 {
1305 d3d12_texture_t tmp = d3d12->pass[i].feedback;
1306 d3d12->pass[i].feedback = d3d12->pass[i].rt;
1307 d3d12->pass[i].rt = tmp;
1308 }
1309 }
1310
1311 for (i = 0; i < d3d12->shader_preset->passes; i++)
1312 {
1313 unsigned j;
1314
1315 D3D12SetPipelineState(d3d12->queue.cmd, d3d12->pass[i].pipe);
1316
1317 if (d3d12->shader_preset->pass[i].frame_count_mod)
1318 d3d12->pass[i].frame_count =
1319 frame_count % d3d12->shader_preset->pass[i].frame_count_mod;
1320 else
1321 d3d12->pass[i].frame_count = frame_count;
1322
1323 #ifdef HAVE_REWIND
1324 d3d12->pass[i].frame_direction = state_manager_frame_is_reversed() ? -1 : 1;
1325 #else
1326 d3d12->pass[i].frame_direction = 1;
1327 #endif
1328
1329 for (j = 0; j < SLANG_CBUFFER_MAX; j++)
1330 {
1331 cbuffer_sem_t* buffer_sem = &d3d12->pass[i].semantics.cbuffers[j];
1332
1333 if (buffer_sem->stage_mask && buffer_sem->uniforms)
1334 {
1335 D3D12_RANGE range = { 0, 0 };
1336 uint8_t* mapped_data = NULL;
1337 uniform_sem_t* uniform = buffer_sem->uniforms;
1338
1339 D3D12Map(d3d12->pass[i].buffers[j], 0, &range, (void**)&mapped_data);
1340 while (uniform->size)
1341 {
1342 if (uniform->data)
1343 memcpy(mapped_data + uniform->offset, uniform->data, uniform->size);
1344 uniform++;
1345 }
1346 D3D12Unmap(d3d12->pass[i].buffers[j], 0, NULL);
1347
1348 D3D12SetGraphicsRootConstantBufferView(
1349 d3d12->queue.cmd, j == SLANG_CBUFFER_UBO ? ROOT_ID_UBO : ROOT_ID_PC,
1350 d3d12->pass[i].buffer_view[j].BufferLocation);
1351 }
1352 }
1353 #if 0
1354 D3D12OMSetRenderTargets(d3d12->queue.cmd, 1, NULL, FALSE, NULL);
1355 #endif
1356
1357 {
1358 texture_sem_t* texture_sem = d3d12->pass[i].semantics.textures;
1359 while (texture_sem->stage_mask)
1360 {
1361 {
1362 D3D12_CPU_DESCRIPTOR_HANDLE handle = {
1363 d3d12->pass[i].textures.ptr - d3d12->desc.srv_heap.gpu.ptr +
1364 d3d12->desc.srv_heap.cpu.ptr +
1365 texture_sem->binding * d3d12->desc.srv_heap.stride
1366 };
1367 d3d12_texture_t* tex = (d3d12_texture_t*)texture_sem->texture_data;
1368 D3D12_SHADER_RESOURCE_VIEW_DESC desc = { tex->desc.Format };
1369
1370 desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
1371 desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
1372 desc.Texture2D.MipLevels = tex->desc.MipLevels;
1373
1374 D3D12CreateShaderResourceView(d3d12->device,
1375 tex->handle, &desc, handle);
1376 }
1377
1378 {
1379 D3D12_CPU_DESCRIPTOR_HANDLE handle = {
1380 d3d12->pass[i].samplers.ptr - d3d12->desc.sampler_heap.gpu.ptr +
1381 d3d12->desc.sampler_heap.cpu.ptr +
1382 texture_sem->binding * d3d12->desc.sampler_heap.stride
1383 };
1384 D3D12_SAMPLER_DESC desc = { D3D12_FILTER_MIN_MAG_MIP_LINEAR };
1385
1386 if (texture_sem->filter == RARCH_FILTER_NEAREST)
1387 desc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
1388
1389 switch (texture_sem->wrap)
1390 {
1391 default:
1392 case RARCH_WRAP_BORDER:
1393 desc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
1394 break;
1395
1396 case RARCH_WRAP_EDGE:
1397 desc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
1398 break;
1399
1400 case RARCH_WRAP_REPEAT:
1401 desc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
1402 break;
1403
1404 case RARCH_WRAP_MIRRORED_REPEAT:
1405 desc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_MIRROR;
1406 break;
1407 }
1408
1409 desc.AddressV = desc.AddressU;
1410 desc.AddressW = desc.AddressU;
1411 desc.MaxAnisotropy = 1;
1412 desc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
1413 desc.MinLOD = -D3D12_FLOAT32_MAX;
1414 desc.MaxLOD = D3D12_FLOAT32_MAX;
1415
1416 D3D12CreateSampler(d3d12->device, &desc, handle);
1417 }
1418
1419 texture_sem++;
1420 }
1421
1422 D3D12SetGraphicsRootDescriptorTable(
1423 d3d12->queue.cmd, ROOT_ID_TEXTURE_T, d3d12->pass[i].textures);
1424 D3D12SetGraphicsRootDescriptorTable(
1425 d3d12->queue.cmd, ROOT_ID_SAMPLER_T, d3d12->pass[i].samplers);
1426 }
1427
1428 if (d3d12->pass[i].rt.handle)
1429 {
1430 d3d12_resource_transition(
1431 d3d12->queue.cmd, d3d12->pass[i].rt.handle,
1432 D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET);
1433
1434 D3D12OMSetRenderTargets(d3d12->queue.cmd, 1, &d3d12->pass[i].rt.rt_view, FALSE, NULL);
1435 #if 0
1436 D3D12ClearRenderTargetView(
1437 d3d12->queue.cmd, d3d12->pass[i].rt.rt_view, d3d12->chain.clearcolor, 0, NULL);
1438 #endif
1439 D3D12RSSetViewports(d3d12->queue.cmd, 1, &d3d12->pass[i].viewport);
1440 D3D12RSSetScissorRects(d3d12->queue.cmd, 1, &d3d12->pass[i].scissorRect);
1441
1442 D3D12DrawInstanced(d3d12->queue.cmd, 4, 1, 0, 0);
1443
1444 d3d12_resource_transition(
1445 d3d12->queue.cmd, d3d12->pass[i].rt.handle, D3D12_RESOURCE_STATE_RENDER_TARGET,
1446 D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
1447 texture = &d3d12->pass[i].rt;
1448 }
1449 else
1450 {
1451 texture = NULL;
1452 break;
1453 }
1454 }
1455 }
1456
1457 if (texture)
1458 {
1459 D3D12SetPipelineState(d3d12->queue.cmd, d3d12->pipes[VIDEO_SHADER_STOCK_BLEND]);
1460 D3D12SetGraphicsRootSignature(d3d12->queue.cmd, d3d12->desc.rootSignature);
1461 d3d12_set_texture(d3d12->queue.cmd, &d3d12->frame.texture[0]);
1462 d3d12_set_sampler(d3d12->queue.cmd, d3d12->samplers[RARCH_FILTER_UNSPEC][RARCH_WRAP_DEFAULT]);
1463 D3D12SetGraphicsRootConstantBufferView(
1464 d3d12->queue.cmd, ROOT_ID_UBO, d3d12->frame.ubo_view.BufferLocation);
1465 }
1466
1467 d3d12->chain.frame_index = DXGIGetCurrentBackBufferIndex(d3d12->chain.handle);
1468 d3d12_resource_transition(
1469 d3d12->queue.cmd, d3d12->chain.renderTargets[d3d12->chain.frame_index],
1470 D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET);
1471
1472 D3D12OMSetRenderTargets(
1473 d3d12->queue.cmd, 1, &d3d12->chain.desc_handles[d3d12->chain.frame_index], FALSE, NULL);
1474 D3D12ClearRenderTargetView(
1475 d3d12->queue.cmd, d3d12->chain.desc_handles[d3d12->chain.frame_index],
1476 d3d12->chain.clearcolor, 0, NULL);
1477
1478 D3D12RSSetViewports(d3d12->queue.cmd, 1, &d3d12->frame.viewport);
1479 D3D12RSSetScissorRects(d3d12->queue.cmd, 1, &d3d12->frame.scissorRect);
1480
1481 D3D12DrawInstanced(d3d12->queue.cmd, 4, 1, 0, 0);
1482
1483 D3D12SetPipelineState(d3d12->queue.cmd, d3d12->pipes[VIDEO_SHADER_STOCK_BLEND]);
1484 D3D12SetGraphicsRootSignature(d3d12->queue.cmd, d3d12->desc.rootSignature);
1485
1486 if (d3d12->menu.enabled && d3d12->menu.texture.handle)
1487 {
1488 if (d3d12->menu.texture.dirty)
1489 d3d12_upload_texture(d3d12->queue.cmd, &d3d12->menu.texture,
1490 d3d12);
1491
1492 D3D12SetGraphicsRootConstantBufferView(
1493 d3d12->queue.cmd, ROOT_ID_UBO, d3d12->ubo_view.BufferLocation);
1494
1495 if (d3d12->menu.fullscreen)
1496 {
1497 D3D12RSSetViewports(d3d12->queue.cmd, 1, &d3d12->chain.viewport);
1498 D3D12RSSetScissorRects(d3d12->queue.cmd, 1, &d3d12->chain.scissorRect);
1499 }
1500
1501 d3d12_set_texture_and_sampler(d3d12->queue.cmd, &d3d12->menu.texture);
1502 D3D12IASetVertexBuffers(d3d12->queue.cmd, 0, 1, &d3d12->menu.vbo_view);
1503 D3D12DrawInstanced(d3d12->queue.cmd, 4, 1, 0, 0);
1504 }
1505
1506 d3d12->sprites.pipe = d3d12->sprites.pipe_noblend;
1507 D3D12SetPipelineState(d3d12->queue.cmd, d3d12->sprites.pipe);
1508 D3D12IASetPrimitiveTopology(d3d12->queue.cmd, D3D_PRIMITIVE_TOPOLOGY_POINTLIST);
1509
1510 d3d12->sprites.enabled = true;
1511
1512 #ifdef HAVE_MENU
1513 #ifndef HAVE_GFX_WIDGETS
1514 if (d3d12->menu.enabled)
1515 #endif
1516 {
1517 D3D12RSSetViewports(d3d12->queue.cmd, 1, &d3d12->chain.viewport);
1518 D3D12RSSetScissorRects(d3d12->queue.cmd, 1, &d3d12->chain.scissorRect);
1519 D3D12IASetVertexBuffers(d3d12->queue.cmd, 0, 1, &d3d12->sprites.vbo_view);
1520 }
1521 #endif
1522
1523 #ifdef HAVE_MENU
1524 if (d3d12->menu.enabled)
1525 menu_driver_frame(menu_is_alive, video_info);
1526 else
1527 #endif
1528 if (statistics_show)
1529 {
1530 if (osd_params)
1531 {
1532 D3D12SetPipelineState(d3d12->queue.cmd, d3d12->sprites.pipe_blend);
1533 D3D12RSSetViewports(d3d12->queue.cmd, 1, &d3d12->chain.viewport);
1534 D3D12RSSetScissorRects(d3d12->queue.cmd, 1, &d3d12->chain.scissorRect);
1535 D3D12IASetVertexBuffers(d3d12->queue.cmd, 0, 1, &d3d12->sprites.vbo_view);
1536 font_driver_render_msg(d3d12, stat_text,
1537 (const struct font_params*)osd_params, NULL);
1538 }
1539 }
1540 #ifdef HAVE_OVERLAY
1541 if (d3d12->overlays.enabled)
1542 {
1543 if (d3d12->overlays.fullscreen)
1544 {
1545 D3D12RSSetViewports(d3d12->queue.cmd, 1, &d3d12->chain.viewport);
1546 D3D12RSSetScissorRects(d3d12->queue.cmd, 1, &d3d12->chain.scissorRect);
1547 }
1548 else
1549 {
1550 D3D12RSSetViewports(d3d12->queue.cmd, 1, &d3d12->frame.viewport);
1551 D3D12RSSetScissorRects(d3d12->queue.cmd, 1, &d3d12->frame.scissorRect);
1552 }
1553
1554 D3D12IASetVertexBuffers(d3d12->queue.cmd, 0, 1, &d3d12->overlays.vbo_view);
1555
1556 D3D12SetPipelineState(d3d12->queue.cmd, d3d12->sprites.pipe_blend);
1557
1558 D3D12SetGraphicsRootDescriptorTable(
1559 d3d12->queue.cmd, ROOT_ID_SAMPLER_T,
1560 d3d12->samplers[RARCH_FILTER_UNSPEC][RARCH_WRAP_DEFAULT]);
1561
1562 for (i = 0; i < (unsigned)d3d12->overlays.count; i++)
1563 {
1564 if (d3d12->overlays.textures[i].dirty)
1565 d3d12_upload_texture(d3d12->queue.cmd,
1566 &d3d12->overlays.textures[i],
1567 d3d12);
1568
1569 D3D12SetGraphicsRootDescriptorTable(
1570 d3d12->queue.cmd, ROOT_ID_TEXTURE_T, d3d12->overlays.textures[i].gpu_descriptor[0]);
1571 D3D12DrawInstanced(d3d12->queue.cmd, 1, 1, i, 0);
1572 }
1573 }
1574 #endif
1575
1576 #ifdef HAVE_GFX_WIDGETS
1577 if (widgets_active)
1578 gfx_widgets_frame(video_info);
1579 #endif
1580
1581 if (msg && *msg)
1582 {
1583 D3D12SetPipelineState(d3d12->queue.cmd, d3d12->sprites.pipe_blend);
1584 D3D12RSSetViewports(d3d12->queue.cmd, 1, &d3d12->chain.viewport);
1585 D3D12RSSetScissorRects(d3d12->queue.cmd, 1, &d3d12->chain.scissorRect);
1586 D3D12IASetVertexBuffers(d3d12->queue.cmd, 0, 1, &d3d12->sprites.vbo_view);
1587
1588 font_driver_render_msg(d3d12, msg, NULL, NULL);
1589 }
1590 d3d12->sprites.enabled = false;
1591
1592 d3d12_resource_transition(
1593 d3d12->queue.cmd, d3d12->chain.renderTargets[d3d12->chain.frame_index],
1594 D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT);
1595 D3D12CloseGraphicsCommandList(d3d12->queue.cmd);
1596
1597 D3D12ExecuteGraphicsCommandLists(d3d12->queue.handle, 1, &d3d12->queue.cmd);
1598
1599 #if defined(_WIN32) && !defined(__WINRT__)
1600 win32_update_title();
1601 #endif
1602 #if 1
1603 DXGIPresent(d3d12->chain.handle, sync_interval, present_flags);
1604 #else
1605 DXGI_PRESENT_PARAMETERS pp = { 0 };
1606 DXGIPresent1(d3d12->swapchain, 0, 0, &pp);
1607 #endif
1608
1609 /* Sync after Present for minimal delay */
1610 d3d12_gfx_sync(d3d12);
1611
1612 return true;
1613 }
1614
d3d12_gfx_set_nonblock_state(void * data,bool toggle,bool adaptive_vsync_enabled,unsigned swap_interval)1615 static void d3d12_gfx_set_nonblock_state(void* data, bool toggle,
1616 bool adaptive_vsync_enabled,
1617 unsigned swap_interval)
1618 {
1619 d3d12_video_t* d3d12 = (d3d12_video_t*)data;
1620 d3d12->chain.vsync = !toggle;
1621 d3d12->chain.swap_interval = swap_interval;
1622 }
1623
d3d12_gfx_alive(void * data)1624 static bool d3d12_gfx_alive(void* data)
1625 {
1626 bool quit;
1627 d3d12_video_t* d3d12 = (d3d12_video_t*)data;
1628
1629 win32_check_window(NULL,
1630 &quit,
1631 &d3d12->resize_chain,
1632 &d3d12->vp.full_width,
1633 &d3d12->vp.full_height);
1634
1635 if ( d3d12->resize_chain
1636 && d3d12->vp.full_width != 0
1637 && d3d12->vp.full_height != 0)
1638 video_driver_set_size(d3d12->vp.full_width, d3d12->vp.full_height);
1639
1640 return !quit;
1641 }
1642
d3d12_gfx_suppress_screensaver(void * data,bool enable)1643 static bool d3d12_gfx_suppress_screensaver(void* data, bool enable) { return false; }
d3d12_gfx_has_windowed(void * data)1644 static bool d3d12_gfx_has_windowed(void* data) { return true; }
1645
d3d12_gfx_get_current_shader(void * data)1646 static struct video_shader* d3d12_gfx_get_current_shader(void* data)
1647 {
1648 d3d12_video_t* d3d12 = (d3d12_video_t*)data;
1649
1650 if (!d3d12)
1651 return NULL;
1652
1653 return d3d12->shader_preset;
1654 }
1655
d3d12_gfx_viewport_info(void * data,struct video_viewport * vp)1656 static void d3d12_gfx_viewport_info(void* data, struct video_viewport* vp)
1657 {
1658 d3d12_video_t* d3d12 = (d3d12_video_t*)data;
1659
1660 *vp = d3d12->vp;
1661 }
1662
d3d12_set_menu_texture_frame(void * data,const void * frame,bool rgb32,unsigned width,unsigned height,float alpha)1663 static void d3d12_set_menu_texture_frame(
1664 void* data, const void* frame, bool rgb32,
1665 unsigned width, unsigned height, float alpha)
1666 {
1667 d3d12_video_t* d3d12 = (d3d12_video_t*)data;
1668 settings_t* settings = config_get_ptr();
1669 int pitch = width *
1670 (rgb32 ? sizeof(uint32_t) : sizeof(uint16_t));
1671 DXGI_FORMAT format = rgb32 ? DXGI_FORMAT_B8G8R8A8_UNORM
1672 : (DXGI_FORMAT)DXGI_FORMAT_EX_A4R4G4B4_UNORM;
1673
1674 if (
1675 d3d12->menu.texture.desc.Width != width ||
1676 d3d12->menu.texture.desc.Height != height)
1677 {
1678 d3d12->menu.texture.desc.Width = width;
1679 d3d12->menu.texture.desc.Height = height;
1680 d3d12->menu.texture.desc.Format = format;
1681 d3d12->menu.texture.srv_heap = &d3d12->desc.srv_heap;
1682 d3d12_init_texture(d3d12->device, &d3d12->menu.texture);
1683 }
1684
1685 d3d12_update_texture(width, height, pitch,
1686 format, frame, &d3d12->menu.texture);
1687
1688 d3d12->menu.alpha = alpha;
1689
1690 {
1691 D3D12_RANGE read_range = { 0, 0 };
1692 d3d12_vertex_t* v = NULL;
1693
1694 D3D12Map(d3d12->menu.vbo, 0, &read_range, (void**)&v);
1695 v[0].color[3] = alpha;
1696 v[1].color[3] = alpha;
1697 v[2].color[3] = alpha;
1698 v[3].color[3] = alpha;
1699 D3D12Unmap(d3d12->menu.vbo, 0, NULL);
1700 }
1701
1702 d3d12->menu.texture.sampler = settings->bools.menu_linear_filter
1703 ? d3d12->samplers[RARCH_FILTER_LINEAR][RARCH_WRAP_DEFAULT]
1704 : d3d12->samplers[RARCH_FILTER_NEAREST][RARCH_WRAP_DEFAULT];
1705 }
1706
d3d12_set_menu_texture_enable(void * data,bool state,bool full_screen)1707 static void d3d12_set_menu_texture_enable(void* data,
1708 bool state, bool full_screen)
1709 {
1710 d3d12_video_t* d3d12 = (d3d12_video_t*)data;
1711
1712 if (!d3d12)
1713 return;
1714
1715 d3d12->menu.enabled = state;
1716 d3d12->menu.fullscreen = full_screen;
1717 }
1718
d3d12_gfx_set_aspect_ratio(void * data,unsigned aspect_ratio_idx)1719 static void d3d12_gfx_set_aspect_ratio(void* data, unsigned aspect_ratio_idx)
1720 {
1721 d3d12_video_t* d3d12 = (d3d12_video_t*)data;
1722
1723 if (!d3d12)
1724 return;
1725
1726 d3d12->keep_aspect = true;
1727 d3d12->resize_viewport = true;
1728 }
1729
d3d12_gfx_apply_state_changes(void * data)1730 static void d3d12_gfx_apply_state_changes(void* data)
1731 {
1732 d3d12_video_t* d3d12 = (d3d12_video_t*)data;
1733
1734 if (d3d12)
1735 d3d12->resize_viewport = true;
1736 }
1737
d3d12_gfx_set_osd_msg(void * data,const char * msg,const void * params,void * font)1738 static void d3d12_gfx_set_osd_msg(
1739 void* data,
1740 const char* msg,
1741 const void* params,
1742 void* font)
1743 {
1744 d3d12_video_t* d3d12 = (d3d12_video_t*)data;
1745
1746 if (!d3d12 || !d3d12->sprites.enabled)
1747 return;
1748
1749 font_driver_render_msg(d3d12, msg,
1750 (const struct font_params*)params, font);
1751 }
1752
d3d12_gfx_load_texture(void * video_data,void * data,bool threaded,enum texture_filter_type filter_type)1753 static uintptr_t d3d12_gfx_load_texture(
1754 void* video_data, void* data, bool threaded,
1755 enum texture_filter_type filter_type)
1756 {
1757 d3d12_texture_t* texture = NULL;
1758 d3d12_video_t* d3d12 = (d3d12_video_t*)video_data;
1759 struct texture_image* image = (struct texture_image*)data;
1760
1761 if (!d3d12)
1762 return 0;
1763
1764 texture = (d3d12_texture_t*)calloc(1, sizeof(*texture));
1765
1766 if (!texture)
1767 return 0;
1768
1769 switch (filter_type)
1770 {
1771 case TEXTURE_FILTER_MIPMAP_LINEAR:
1772 texture->desc.MipLevels = UINT16_MAX;
1773 case TEXTURE_FILTER_LINEAR:
1774 texture->sampler = d3d12->samplers[
1775 RARCH_FILTER_LINEAR][RARCH_WRAP_EDGE];
1776 break;
1777 case TEXTURE_FILTER_MIPMAP_NEAREST:
1778 texture->desc.MipLevels = UINT16_MAX;
1779 case TEXTURE_FILTER_NEAREST:
1780 texture->sampler = d3d12->samplers[
1781 RARCH_FILTER_NEAREST][RARCH_WRAP_EDGE];
1782 break;
1783 }
1784
1785 texture->desc.Width = image->width;
1786 texture->desc.Height = image->height;
1787 texture->desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
1788 texture->srv_heap = &d3d12->desc.srv_heap;
1789
1790 d3d12_init_texture(d3d12->device, texture);
1791
1792 d3d12_update_texture(
1793 image->width, image->height, 0,
1794 DXGI_FORMAT_B8G8R8A8_UNORM, image->pixels, texture);
1795
1796 return (uintptr_t)texture;
1797 }
d3d12_gfx_unload_texture(void * data,bool threaded,uintptr_t handle)1798 static void d3d12_gfx_unload_texture(void* data,
1799 bool threaded, uintptr_t handle)
1800 {
1801 d3d12_texture_t* texture = (d3d12_texture_t*)handle;
1802
1803 if (!texture)
1804 return;
1805
1806 d3d12_gfx_sync((d3d12_video_t*)data);
1807 d3d12_release_texture(texture);
1808 free(texture);
1809 }
1810
d3d12_get_flags(void * data)1811 static uint32_t d3d12_get_flags(void *data)
1812 {
1813 uint32_t flags = 0;
1814
1815 BIT32_SET(flags, GFX_CTX_FLAGS_MENU_FRAME_FILTERING);
1816 #if defined(HAVE_SLANG) && defined(HAVE_SPIRV_CROSS)
1817 BIT32_SET(flags, GFX_CTX_FLAGS_SHADERS_SLANG);
1818 #endif
1819
1820 return flags;
1821 }
1822
1823 #ifndef __WINRT__
d3d12_get_video_output_size(void * data,unsigned * width,unsigned * height)1824 static void d3d12_get_video_output_size(void *data,
1825 unsigned *width, unsigned *height)
1826 {
1827 win32_get_video_output_size(width, height);
1828 }
1829
d3d12_get_video_output_prev(void * data)1830 static void d3d12_get_video_output_prev(void *data)
1831 {
1832 unsigned width = 0;
1833 unsigned height = 0;
1834 win32_get_video_output_prev(&width, &height);
1835 }
1836
d3d12_get_video_output_next(void * data)1837 static void d3d12_get_video_output_next(void *data)
1838 {
1839 unsigned width = 0;
1840 unsigned height = 0;
1841 win32_get_video_output_next(&width, &height);
1842 }
1843 #endif
1844
1845 static const video_poke_interface_t d3d12_poke_interface = {
1846 d3d12_get_flags,
1847 d3d12_gfx_load_texture,
1848 d3d12_gfx_unload_texture,
1849 NULL, /* set_video_mode */
1850 #ifndef __WINRT__
1851 win32_get_refresh_rate,
1852 #else
1853 /* UWP does not expose this information easily */
1854 NULL,
1855 #endif
1856 d3d12_set_filtering,
1857 #ifdef __WINRT__
1858 NULL, /* get_video_output_size */
1859 NULL, /* get_video_output_prev */
1860 NULL, /* get_video_output_next */
1861 #else
1862 d3d12_get_video_output_size,
1863 d3d12_get_video_output_prev,
1864 d3d12_get_video_output_next,
1865 #endif
1866 NULL, /* get_current_framebuffer */
1867 NULL, /* get_proc_address */
1868 d3d12_gfx_set_aspect_ratio,
1869 d3d12_gfx_apply_state_changes,
1870 d3d12_set_menu_texture_frame,
1871 d3d12_set_menu_texture_enable,
1872 d3d12_gfx_set_osd_msg,
1873 win32_show_cursor,
1874 NULL, /* grab_mouse_toggle */
1875 d3d12_gfx_get_current_shader,
1876 NULL, /* get_current_software_framebuffer */
1877 NULL, /* get_hw_render_interface */
1878 };
1879
d3d12_gfx_get_poke_interface(void * data,const video_poke_interface_t ** iface)1880 static void d3d12_gfx_get_poke_interface(void* data, const video_poke_interface_t** iface)
1881 {
1882 *iface = &d3d12_poke_interface;
1883 }
1884
1885 #ifdef HAVE_GFX_WIDGETS
d3d12_gfx_widgets_enabled(void * data)1886 static bool d3d12_gfx_widgets_enabled(void *data) { return true; }
1887 #endif
1888
1889 video_driver_t video_d3d12 = {
1890 d3d12_gfx_init,
1891 d3d12_gfx_frame,
1892 d3d12_gfx_set_nonblock_state,
1893 d3d12_gfx_alive,
1894 win32_has_focus,
1895 d3d12_gfx_suppress_screensaver,
1896 d3d12_gfx_has_windowed,
1897 d3d12_gfx_set_shader,
1898 d3d12_gfx_free,
1899 "d3d12",
1900 NULL, /* set_viewport */
1901 d3d12_gfx_set_rotation,
1902 d3d12_gfx_viewport_info,
1903 NULL, /* read_viewport */
1904 NULL, /* read_frame_raw */
1905
1906 #ifdef HAVE_OVERLAY
1907 d3d12_get_overlay_interface,
1908 #endif
1909 #ifdef HAVE_VIDEO_LAYOUT
1910 NULL,
1911 #endif
1912 d3d12_gfx_get_poke_interface,
1913 NULL, /* d3d12_wrap_type_to_enum */
1914 #ifdef HAVE_GFX_WIDGETS
1915 d3d12_gfx_widgets_enabled
1916 #endif
1917 };
1918