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(&current_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