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 #define COBJMACROS
19 
20 #include <boolean.h>
21 
22 #include "d3d_common.h"
23 #include "d3d12_common.h"
24 #include "dxgi_common.h"
25 #include "d3dcompiler_common.h"
26 
27 #include "../verbosity.h"
28 #include "../../configuration.h"
29 
30 #ifdef HAVE_DYNAMIC
31 #include <dynamic/dylib.h>
32 #endif
33 
34 #include <encodings/utf.h>
35 #include <lists/string_list.h>
36 #include <dxgi.h>
37 
38 #ifdef __MINGW32__
39 /* clang-format off */
40 #ifdef __cplusplus
41 #define DEFINE_GUIDW(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) EXTERN_C const GUID DECLSPEC_SELECTANY name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
42 #else
43 #define DEFINE_GUIDW(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) const GUID DECLSPEC_SELECTANY name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
44 #endif
45 
46 DEFINE_GUIDW(IID_ID3D12PipelineState, 0x765a30f3, 0xf624, 0x4c6f, 0xa8, 0x28, 0xac, 0xe9, 0x48, 0x62, 0x24, 0x45);
47 DEFINE_GUIDW(IID_ID3D12RootSignature, 0xc54a6b66, 0x72df, 0x4ee8, 0x8b, 0xe5, 0xa9, 0x46, 0xa1, 0x42, 0x92, 0x14);
48 DEFINE_GUIDW(IID_ID3D12Resource, 0x696442be, 0xa72e, 0x4059, 0xbc, 0x79, 0x5b, 0x5c, 0x98, 0x04, 0x0f, 0xad);
49 DEFINE_GUIDW(IID_ID3D12CommandAllocator, 0x6102dee4, 0xaf59, 0x4b09, 0xb9, 0x99, 0xb4, 0x4d, 0x73, 0xf0, 0x9b, 0x24);
50 DEFINE_GUIDW(IID_ID3D12Fence, 0x0a753dcf, 0xc4d8, 0x4b91, 0xad, 0xf6, 0xbe, 0x5a, 0x60, 0xd9, 0x5a, 0x76);
51 DEFINE_GUIDW(IID_ID3D12DescriptorHeap, 0x8efb471d, 0x616c, 0x4f49, 0x90, 0xf7, 0x12, 0x7b, 0xb7, 0x63, 0xfa, 0x51);
52 DEFINE_GUIDW(IID_ID3D12GraphicsCommandList, 0x5b160d0f, 0xac1b, 0x4185, 0x8b, 0xa8, 0xb3, 0xae, 0x42, 0xa5, 0xa4, 0x55);
53 DEFINE_GUIDW(IID_ID3D12CommandQueue, 0x0ec870a6, 0x5d7e, 0x4c22, 0x8c, 0xfc, 0x5b, 0xaa, 0xe0, 0x76, 0x16, 0xed);
54 DEFINE_GUIDW(IID_ID3D12Device, 0x189819f1, 0x1db6, 0x4b57, 0xbe, 0x54, 0x18, 0x21, 0x33, 0x9b, 0x85, 0xf7);
55 DEFINE_GUIDW(IID_ID3D12Object, 0xc4fec28f, 0x7966, 0x4e95, 0x9f, 0x94, 0xf4, 0x31, 0xcb, 0x56, 0xc3, 0xb8);
56 DEFINE_GUIDW(IID_ID3D12DeviceChild, 0x905db94b, 0xa00c, 0x4140, 0x9d, 0xf5, 0x2b, 0x64, 0xca, 0x9e, 0xa3, 0x57);
57 DEFINE_GUIDW(IID_ID3D12RootSignatureDeserializer, 0x34AB647B, 0x3CC8, 0x46AC, 0x84, 0x1B, 0xC0, 0x96, 0x56, 0x45, 0xC0, 0x46);
58 DEFINE_GUIDW(IID_ID3D12VersionedRootSignatureDeserializer, 0x7F91CE67, 0x090C, 0x4BB7, 0xB7, 0x8E, 0xED, 0x8F, 0xF2, 0xE3, 0x1D, 0xA0);
59 DEFINE_GUIDW(IID_ID3D12Pageable, 0x63ee58fb, 0x1268, 0x4835, 0x86, 0xda, 0xf0, 0x08, 0xce, 0x62, 0xf0, 0xd6);
60 DEFINE_GUIDW(IID_ID3D12Heap, 0x6b3b2502, 0x6e51, 0x45b3, 0x90, 0xee, 0x98, 0x84, 0x26, 0x5e, 0x8d, 0xf3);
61 DEFINE_GUIDW(IID_ID3D12QueryHeap, 0x0d9658ae, 0xed45, 0x469e, 0xa6, 0x1d, 0x97, 0x0e, 0xc5, 0x83, 0xca, 0xb4);
62 DEFINE_GUIDW(IID_ID3D12CommandSignature, 0xc36a797c, 0xec80, 0x4f0a, 0x89, 0x85, 0xa7, 0xb2, 0x47, 0x50, 0x82, 0xd1);
63 DEFINE_GUIDW(IID_ID3D12CommandList, 0x7116d91c, 0xe7e4, 0x47ce, 0xb8, 0xc6, 0xec, 0x81, 0x68, 0xf4, 0x37, 0xe5);
64 DEFINE_GUIDW(IID_ID3D12PipelineLibrary, 0xc64226a8, 0x9201, 0x46af, 0xb4, 0xcc, 0x53, 0xfb, 0x9f, 0xf7, 0x41, 0x4f);
65 DEFINE_GUIDW(IID_ID3D12Device1, 0x77acce80, 0x638e, 0x4e65, 0x88, 0x95, 0xc1, 0xf2, 0x33, 0x86, 0x86, 0x3e);
66 #ifdef DEBUG
67 DEFINE_GUIDW(IID_ID3D12Debug, 0x344488b7, 0x6846, 0x474b, 0xb9, 0x89, 0xf0, 0x27, 0x44, 0x82, 0x45, 0xe0);
68 DEFINE_GUIDW(IID_ID3D12Debug1, 0xaffaa4ca, 0x63fe, 0x4d8e, 0xb8, 0xad, 0x15, 0x90, 0x00, 0xaf, 0x43, 0x04);
69 DEFINE_GUIDW(IID_ID3D12DebugDevice1, 0xa9b71770, 0xd099, 0x4a65, 0xa6, 0x98, 0x3d, 0xee, 0x10, 0x02, 0x0f, 0x88);
70 DEFINE_GUIDW(IID_ID3D12DebugDevice, 0x3febd6dd, 0x4973, 0x4787, 0x81, 0x94, 0xe4, 0x5f, 0x9e, 0x28, 0x92, 0x3e);
71 DEFINE_GUIDW(IID_ID3D12DebugCommandQueue, 0x09e0bf36, 0x54ac, 0x484f, 0x88, 0x47, 0x4b, 0xae, 0xea, 0xb6, 0x05, 0x3a);
72 DEFINE_GUIDW(IID_ID3D12DebugCommandList1, 0x102ca951, 0x311b, 0x4b01, 0xb1, 0x1f, 0xec, 0xb8, 0x3e, 0x06, 0x1b, 0x37);
73 DEFINE_GUIDW(IID_ID3D12DebugCommandList, 0x09e0bf36, 0x54ac, 0x484f, 0x88, 0x47, 0x4b, 0xae, 0xea, 0xb6, 0x05, 0x3f);
74 #endif
75 /* clang-format on */
76 #endif
77 
78 #if defined(HAVE_DYNAMIC) && !defined(__WINRT__)
79 static dylib_t     d3d12_dll;
80 static const char* d3d12_dll_name = "d3d12.dll";
81 
D3D12CreateDevice(IUnknown * pAdapter,D3D_FEATURE_LEVEL MinimumFeatureLevel,REFIID riid,void ** ppDevice)82 HRESULT WINAPI D3D12CreateDevice(
83       IUnknown* pAdapter, D3D_FEATURE_LEVEL MinimumFeatureLevel, REFIID riid, void** ppDevice)
84 {
85    static PFN_D3D12_CREATE_DEVICE fp;
86    if (!d3d12_dll)
87       d3d12_dll = dylib_load(d3d12_dll_name);
88 
89    if (!d3d12_dll)
90       return TYPE_E_CANTLOADLIBRARY;
91 
92    if (!fp)
93       fp = (PFN_D3D12_CREATE_DEVICE)dylib_proc(d3d12_dll, "D3D12CreateDevice");
94 
95    if (!fp)
96       return TYPE_E_DLLFUNCTIONNOTFOUND;
97 
98    return fp(pAdapter, MinimumFeatureLevel, riid, ppDevice);
99 }
100 
D3D12GetDebugInterface(REFIID riid,void ** ppvDebug)101 HRESULT WINAPI D3D12GetDebugInterface(REFIID riid, void** ppvDebug)
102 {
103    static PFN_D3D12_GET_DEBUG_INTERFACE fp;
104    if (!d3d12_dll)
105       d3d12_dll = dylib_load(d3d12_dll_name);
106 
107    if (!d3d12_dll)
108       return TYPE_E_CANTLOADLIBRARY;
109 
110    if (!fp)
111       fp = (PFN_D3D12_GET_DEBUG_INTERFACE)dylib_proc(d3d12_dll, "D3D12GetDebugInterface");
112 
113    if (!fp)
114       return TYPE_E_DLLFUNCTIONNOTFOUND;
115 
116    return fp(riid, ppvDebug);
117 }
118 
D3D12SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC * pRootSignature,D3D_ROOT_SIGNATURE_VERSION Version,ID3DBlob ** ppBlob,ID3DBlob ** ppErrorBlob)119 HRESULT WINAPI D3D12SerializeRootSignature(
120       const D3D12_ROOT_SIGNATURE_DESC* pRootSignature,
121       D3D_ROOT_SIGNATURE_VERSION       Version,
122       ID3DBlob**                       ppBlob,
123       ID3DBlob**                       ppErrorBlob)
124 {
125    static PFN_D3D12_SERIALIZE_ROOT_SIGNATURE fp;
126    if (!d3d12_dll)
127       d3d12_dll = dylib_load(d3d12_dll_name);
128 
129    if (!d3d12_dll)
130       return TYPE_E_CANTLOADLIBRARY;
131 
132    if (!fp)
133       fp = (PFN_D3D12_SERIALIZE_ROOT_SIGNATURE)dylib_proc(d3d12_dll, "D3D12SerializeRootSignature");
134 
135    if (!fp)
136       return TYPE_E_DLLFUNCTIONNOTFOUND;
137 
138    return fp(pRootSignature, Version, ppBlob, ppErrorBlob);
139 }
140 
D3D12SerializeVersionedRootSignature(const D3D12_VERSIONED_ROOT_SIGNATURE_DESC * pRootSignature,ID3DBlob ** ppBlob,ID3DBlob ** ppErrorBlob)141 HRESULT WINAPI D3D12SerializeVersionedRootSignature(
142       const D3D12_VERSIONED_ROOT_SIGNATURE_DESC* pRootSignature,
143       ID3DBlob**                                 ppBlob,
144       ID3DBlob**                                 ppErrorBlob)
145 {
146    static PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE fp;
147    if (!d3d12_dll)
148       d3d12_dll = dylib_load(d3d12_dll_name);
149 
150    if (!d3d12_dll)
151       return TYPE_E_CANTLOADLIBRARY;
152 
153    if (!fp)
154       fp = (PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE)dylib_proc(
155             d3d12_dll, "D3D12SerializeRootSignature");
156 
157    if (!fp)
158       return TYPE_E_DLLFUNCTIONNOTFOUND;
159 
160    return fp(pRootSignature, ppBlob, ppErrorBlob);
161 }
162 #endif
163 
d3d12_init_base(d3d12_video_t * d3d12)164 bool d3d12_init_base(d3d12_video_t* d3d12)
165 {
166    DXGIAdapter adapter = NULL;
167 #ifdef DEBUG
168    D3D12GetDebugInterface_(&d3d12->debugController);
169    D3D12EnableDebugLayer(d3d12->debugController);
170 #endif
171 
172 #ifdef __WINRT__
173    DXGICreateFactory2(&d3d12->factory);
174 #else
175    DXGICreateFactory(&d3d12->factory);
176 #endif
177 
178    {
179       int i = 0;
180       settings_t *settings = config_get_ptr();
181       int gpu_index        = settings->ints.d3d12_gpu_index;
182 
183       if (d3d12->gpu_list)
184          string_list_free(d3d12->gpu_list);
185 
186       d3d12->gpu_list = string_list_new();
187 
188       for (;;)
189       {
190          char str[128];
191          union string_list_elem_attr attr = {0};
192          DXGI_ADAPTER_DESC desc           = {0};
193 
194          str[0] = '\0';
195 
196 #ifdef __WINRT__
197          if (FAILED(DXGIEnumAdapters2(d3d12->factory, i, &adapter)))
198             break;
199 #else
200          if (FAILED(DXGIEnumAdapters(d3d12->factory, i, &adapter)))
201             break;
202 #endif
203 
204          IDXGIAdapter_GetDesc(adapter, &desc);
205 
206          utf16_to_char_string((const uint16_t*)desc.Description, str, sizeof(str));
207 
208          RARCH_LOG("[D3D12]: Found GPU at index %d: %s\n", i, str);
209 
210          string_list_append(d3d12->gpu_list, str, attr);
211 
212          if (i < D3D12_MAX_GPU_COUNT)
213          {
214             AddRef(adapter);
215             d3d12->adapters[i] = adapter;
216          }
217          Release(adapter);
218          adapter = NULL;
219 
220          i++;
221          if (i >= D3D12_MAX_GPU_COUNT)
222             break;
223       }
224 
225       video_driver_set_gpu_api_devices(GFX_CTX_DIRECT3D12_API, d3d12->gpu_list);
226 
227       if (0 <= gpu_index && gpu_index <= i && gpu_index < D3D12_MAX_GPU_COUNT)
228       {
229          d3d12->adapter = d3d12->adapters[gpu_index];
230          AddRef(d3d12->adapter);
231          RARCH_LOG("[D3D12]: Using GPU index %d.\n", gpu_index);
232          video_driver_set_gpu_device_string(
233                d3d12->gpu_list->elems[gpu_index].data);
234       }
235       else
236       {
237          RARCH_WARN("[D3D12]: Invalid GPU index %d, using first device found.\n", gpu_index);
238          d3d12->adapter = d3d12->adapters[0];
239          AddRef(d3d12->adapter);
240       }
241 
242       if (!SUCCEEDED(D3D12CreateDevice_(d3d12->adapter, D3D_FEATURE_LEVEL_11_0, &d3d12->device)))
243          RARCH_WARN("[D3D12]: Could not create D3D12 device.\n");
244    }
245 
246    return true;
247 }
248 
d3d12_init_queue(d3d12_video_t * d3d12)249 bool d3d12_init_queue(d3d12_video_t* d3d12)
250 {
251    {
252       static const D3D12_COMMAND_QUEUE_DESC desc = {
253          D3D12_COMMAND_LIST_TYPE_DIRECT,
254          0,
255          D3D12_COMMAND_QUEUE_FLAG_NONE,
256          0
257       };
258       D3D12CreateCommandQueue(
259             d3d12->device,
260             (D3D12_COMMAND_QUEUE_DESC*)&desc,
261             &d3d12->queue.handle);
262    }
263 
264    D3D12CreateCommandAllocator(
265          d3d12->device,
266          D3D12_COMMAND_LIST_TYPE_DIRECT,
267          &d3d12->queue.allocator);
268 
269    D3D12CreateGraphicsCommandList(
270          d3d12->device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT, d3d12->queue.allocator,
271          d3d12->pipes[VIDEO_SHADER_STOCK_BLEND], &d3d12->queue.cmd);
272 
273    D3D12CloseGraphicsCommandList(d3d12->queue.cmd);
274 
275    D3D12CreateFence(d3d12->device, 0, D3D12_FENCE_FLAG_NONE, &d3d12->queue.fence);
276    d3d12->queue.fenceValue = 0;
277    d3d12->queue.fenceEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
278 
279    return true;
280 }
281 
d3d12_init_swapchain(d3d12_video_t * d3d12,int width,int height,void * corewindow)282 bool d3d12_init_swapchain(d3d12_video_t* d3d12,
283       int width, int height, void* corewindow)
284 {
285    unsigned i;
286    HRESULT hr;
287 #ifdef __WINRT__
288    DXGI_SWAP_CHAIN_DESC1 desc;
289    memset(&desc, 0, sizeof(DXGI_SWAP_CHAIN_DESC1));
290 #else
291    DXGI_SWAP_CHAIN_DESC desc;
292    HWND hwnd                 = (HWND)corewindow;
293    memset(&desc, 0, sizeof(DXGI_SWAP_CHAIN_DESC));
294 #endif
295 
296    desc.BufferCount          = countof(d3d12->chain.renderTargets);
297    desc.BufferUsage          = DXGI_USAGE_RENDER_TARGET_OUTPUT;
298 #ifdef __WINRT__
299    desc.Width                = width;
300    desc.Height               = height;
301    desc.Format               = DXGI_FORMAT_R8G8B8A8_UNORM;
302 #else
303    desc.BufferDesc.Width     = width;
304    desc.BufferDesc.Height    = height;
305    desc.BufferDesc.Format    = DXGI_FORMAT_R8G8B8A8_UNORM;
306    desc.BufferDesc.RefreshRate.Numerator   = 0;
307    desc.BufferDesc.RefreshRate.Denominator = 1;
308 #endif
309    desc.SampleDesc.Count     = 1;
310    desc.SampleDesc.Quality   = 0;
311 #ifdef HAVE_WINDOW
312    desc.OutputWindow = hwnd;
313    desc.Windowed     = TRUE;
314 #endif
315 #if 0
316    desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
317 #else
318    desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
319 #endif
320    desc.Flags      = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
321 
322 #ifdef __WINRT__
323    hr = DXGICreateSwapChainForCoreWindow(d3d12->factory, d3d12->queue.handle, corewindow, &desc, NULL, &d3d12->chain.handle);
324 #else
325    hr = DXGICreateSwapChain(d3d12->factory, d3d12->queue.handle, &desc, &d3d12->chain.handle);
326 #endif
327    if (FAILED(hr))
328    {
329       RARCH_ERR("[D3D12]: Failed to create the swap chain (0x%08X)\n", hr);
330       return false;
331    }
332 
333 #ifdef HAVE_WINDOW
334    DXGIMakeWindowAssociation(d3d12->factory, hwnd, DXGI_MWA_NO_ALT_ENTER);
335 #endif
336 
337    d3d12->chain.frame_index = DXGIGetCurrentBackBufferIndex(d3d12->chain.handle);
338 
339    for (i = 0; i < countof(d3d12->chain.renderTargets); i++)
340    {
341       DXGIGetSwapChainBuffer(d3d12->chain.handle, i, &d3d12->chain.renderTargets[i]);
342       D3D12CreateRenderTargetView(
343             d3d12->device, d3d12->chain.renderTargets[i], NULL, d3d12->chain.desc_handles[i]);
344    }
345 
346    d3d12->chain.viewport.Width     = width;
347    d3d12->chain.viewport.Height    = height;
348    d3d12->chain.scissorRect.right  = width;
349    d3d12->chain.scissorRect.bottom = height;
350 
351    return true;
352 }
353 
d3d12_init_descriptor_heap(D3D12Device device,d3d12_descriptor_heap_t * out)354 static void d3d12_init_descriptor_heap(D3D12Device device, d3d12_descriptor_heap_t* out)
355 {
356    D3D12CreateDescriptorHeap(device, &out->desc, &out->handle);
357    out->cpu    = D3D12GetCPUDescriptorHandleForHeapStart(out->handle);
358    out->gpu    = D3D12GetGPUDescriptorHandleForHeapStart(out->handle);
359    out->stride = D3D12GetDescriptorHandleIncrementSize(device, out->desc.Type);
360    out->map    = (bool*)calloc(out->desc.NumDescriptors, sizeof(bool));
361 }
362 
d3d12_release_descriptor_heap(d3d12_descriptor_heap_t * heap)363 static inline void d3d12_release_descriptor_heap(d3d12_descriptor_heap_t* heap)
364 {
365    free(heap->map);
366    Release(heap->handle);
367 }
368 
d3d12_descriptor_heap_slot_alloc(d3d12_descriptor_heap_t * heap)369 static D3D12_CPU_DESCRIPTOR_HANDLE d3d12_descriptor_heap_slot_alloc(d3d12_descriptor_heap_t* heap)
370 {
371    int                         i;
372    D3D12_CPU_DESCRIPTOR_HANDLE handle = { 0 };
373 
374    for (i = heap->start; i < (int)heap->desc.NumDescriptors; i++)
375    {
376       if (!heap->map[i])
377       {
378          heap->map[i] = true;
379          handle.ptr   = heap->cpu.ptr + i * heap->stride;
380          heap->start  = i + 1;
381          return handle;
382       }
383    }
384    /* if you get here try increasing NumDescriptors for this heap */
385    assert(0);
386    return handle;
387 }
388 
389 static void
d3d12_descriptor_heap_slot_free(d3d12_descriptor_heap_t * heap,D3D12_CPU_DESCRIPTOR_HANDLE handle)390 d3d12_descriptor_heap_slot_free(d3d12_descriptor_heap_t* heap, D3D12_CPU_DESCRIPTOR_HANDLE handle)
391 {
392    unsigned i;
393 
394    if (!handle.ptr)
395       return;
396 
397    assert(((handle.ptr - heap->cpu.ptr) % heap->stride) == 0);
398 
399    i = (handle.ptr - heap->cpu.ptr) / heap->stride;
400    assert(i >= 0 && i < heap->desc.NumDescriptors);
401    assert(heap->map[i]);
402 
403    heap->map[i] = false;
404    if (heap->start > (int)i)
405       heap->start = i;
406 }
407 
d3d12_create_root_signature(D3D12Device device,D3D12_ROOT_SIGNATURE_DESC * desc,D3D12RootSignature * out)408 bool d3d12_create_root_signature(
409       D3D12Device device, D3D12_ROOT_SIGNATURE_DESC* desc, D3D12RootSignature* out)
410 {
411    D3DBlob signature;
412    D3DBlob error;
413    D3D12SerializeRootSignature(desc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error);
414 
415    if (error)
416    {
417       RARCH_ERR(
418             "[D3D12]: CreateRootSignature failed : %s", (const char*)D3DGetBufferPointer(error));
419       Release(error);
420       return false;
421    }
422 
423    D3D12CreateRootSignature(
424          device, 0, D3DGetBufferPointer(signature), D3DGetBufferSize(signature), out);
425    Release(signature);
426 
427    return true;
428 }
429 
d3d12_init_descriptors(d3d12_video_t * d3d12)430 bool d3d12_init_descriptors(d3d12_video_t* d3d12)
431 {
432    int                       i, j;
433    D3D12_ROOT_SIGNATURE_DESC desc;
434    D3D12_DESCRIPTOR_RANGE    srv_tbl[1]     = { { D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1 } };
435    D3D12_DESCRIPTOR_RANGE    uav_tbl[1]     = { { D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1 } };
436    D3D12_DESCRIPTOR_RANGE    sampler_tbl[1] = { { D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1 } };
437    D3D12_STATIC_SAMPLER_DESC static_sampler = { D3D12_FILTER_MIN_MAG_MIP_POINT };
438    D3D12_ROOT_PARAMETER      root_params[ROOT_ID_MAX];
439    D3D12_ROOT_PARAMETER      cs_root_params[CS_ROOT_ID_MAX];
440 
441    root_params[ROOT_ID_TEXTURE_T].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
442    root_params[ROOT_ID_TEXTURE_T].DescriptorTable.NumDescriptorRanges = countof(srv_tbl);
443    root_params[ROOT_ID_TEXTURE_T].DescriptorTable.pDescriptorRanges   = srv_tbl;
444    root_params[ROOT_ID_TEXTURE_T].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
445 
446    root_params[ROOT_ID_SAMPLER_T].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
447    root_params[ROOT_ID_SAMPLER_T].DescriptorTable.NumDescriptorRanges = countof(sampler_tbl);
448    root_params[ROOT_ID_SAMPLER_T].DescriptorTable.pDescriptorRanges   = sampler_tbl;
449    root_params[ROOT_ID_SAMPLER_T].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
450 
451    root_params[ROOT_ID_UBO].ParameterType             = D3D12_ROOT_PARAMETER_TYPE_CBV;
452    root_params[ROOT_ID_UBO].Descriptor.RegisterSpace  = 0;
453    root_params[ROOT_ID_UBO].Descriptor.ShaderRegister = 0;
454    root_params[ROOT_ID_UBO].ShaderVisibility          = D3D12_SHADER_VISIBILITY_ALL;
455 
456    root_params[ROOT_ID_PC].ParameterType             = D3D12_ROOT_PARAMETER_TYPE_CBV;
457    root_params[ROOT_ID_PC].Descriptor.RegisterSpace  = 0;
458    root_params[ROOT_ID_PC].Descriptor.ShaderRegister = 1;
459    root_params[ROOT_ID_PC].ShaderVisibility          = D3D12_SHADER_VISIBILITY_ALL;
460 
461    desc.NumParameters     = countof(root_params);
462    desc.pParameters       = root_params;
463    desc.NumStaticSamplers = 0;
464    desc.pStaticSamplers   = NULL;
465    desc.Flags             = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
466 
467    d3d12_create_root_signature(d3d12->device, &desc, &d3d12->desc.rootSignature);
468 
469    srv_tbl[0].NumDescriptors     = SLANG_NUM_BINDINGS;
470    sampler_tbl[0].NumDescriptors = SLANG_NUM_BINDINGS;
471    d3d12_create_root_signature(d3d12->device, &desc, &d3d12->desc.sl_rootSignature);
472 
473    cs_root_params[CS_ROOT_ID_TEXTURE_T].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
474    cs_root_params[CS_ROOT_ID_TEXTURE_T].DescriptorTable.NumDescriptorRanges = countof(srv_tbl);
475    cs_root_params[CS_ROOT_ID_TEXTURE_T].DescriptorTable.pDescriptorRanges   = srv_tbl;
476    cs_root_params[CS_ROOT_ID_TEXTURE_T].ShaderVisibility                    = D3D12_SHADER_VISIBILITY_ALL;
477 
478    cs_root_params[CS_ROOT_ID_UAV_T].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
479    cs_root_params[CS_ROOT_ID_UAV_T].DescriptorTable.NumDescriptorRanges = countof(uav_tbl);
480    cs_root_params[CS_ROOT_ID_UAV_T].DescriptorTable.pDescriptorRanges   = uav_tbl;
481    cs_root_params[CS_ROOT_ID_UAV_T].ShaderVisibility                    = D3D12_SHADER_VISIBILITY_ALL;
482 
483    cs_root_params[CS_ROOT_ID_CONSTANTS].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
484    cs_root_params[CS_ROOT_ID_CONSTANTS].Constants.Num32BitValues = 3;
485    cs_root_params[CS_ROOT_ID_CONSTANTS].Constants.RegisterSpace  = 0;
486    cs_root_params[CS_ROOT_ID_CONSTANTS].Constants.ShaderRegister = 0;
487    cs_root_params[CS_ROOT_ID_CONSTANTS].ShaderVisibility         = D3D12_SHADER_VISIBILITY_ALL;
488 
489    static_sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
490    static_sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
491    static_sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
492 #if 0
493    static_sampler.MaxAnisotropy             = 1;
494    static_sampler.ComparisonFunc            = D3D12_COMPARISON_FUNC_NEVER;
495    static_sampler.MinLOD                    = -D3D12_FLOAT32_MAX;
496    static_sampler.MaxLOD                    = D3D12_FLOAT32_MAX;
497 #endif
498 
499    desc.NumParameters     = countof(cs_root_params);
500    desc.pParameters       = cs_root_params;
501    desc.NumStaticSamplers = 1;
502    desc.pStaticSamplers   = &static_sampler;
503    desc.Flags             = D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS |
504                 D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS |
505                 D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
506                 D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS |
507                 D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS;
508 
509    d3d12_create_root_signature(d3d12->device, &desc, &d3d12->desc.cs_rootSignature);
510 
511    d3d12->desc.rtv_heap.desc.Type           = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
512    d3d12->desc.rtv_heap.desc.NumDescriptors = countof(d3d12->chain.renderTargets) + GFX_MAX_SHADERS * 2;
513    d3d12->desc.rtv_heap.desc.Flags          = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
514    d3d12_init_descriptor_heap(d3d12->device, &d3d12->desc.rtv_heap);
515 
516    d3d12->desc.srv_heap.desc.Type           = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
517    d3d12->desc.srv_heap.desc.NumDescriptors = SLANG_NUM_BINDINGS * GFX_MAX_SHADERS + 2048;
518    d3d12->desc.srv_heap.desc.Flags          = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
519    d3d12_init_descriptor_heap(d3d12->device, &d3d12->desc.srv_heap);
520 
521    d3d12->desc.sampler_heap.desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER;
522    d3d12->desc.sampler_heap.desc.NumDescriptors =
523          SLANG_NUM_BINDINGS * GFX_MAX_SHADERS + 2 * RARCH_WRAP_MAX;
524    d3d12->desc.sampler_heap.desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
525    d3d12_init_descriptor_heap(d3d12->device, &d3d12->desc.sampler_heap);
526 
527    for (i = 0; i < countof(d3d12->chain.renderTargets); i++)
528    {
529       d3d12->chain.desc_handles[i].ptr =
530             d3d12->desc.rtv_heap.cpu.ptr + i * d3d12->desc.rtv_heap.stride;
531    }
532 
533    for (i = 0; i < GFX_MAX_SHADERS; i++)
534    {
535       d3d12->pass[i].rt.rt_view.ptr =
536             d3d12->desc.rtv_heap.cpu.ptr +
537             (countof(d3d12->chain.renderTargets) + (2 * i)) * d3d12->desc.rtv_heap.stride;
538       d3d12->pass[i].feedback.rt_view.ptr = d3d12->pass[i].rt.rt_view.ptr + d3d12->desc.rtv_heap.stride;
539 
540       d3d12->pass[i].textures.ptr = d3d12_descriptor_heap_slot_alloc(&d3d12->desc.srv_heap).ptr -
541                                     d3d12->desc.srv_heap.cpu.ptr + d3d12->desc.srv_heap.gpu.ptr;
542       d3d12->pass[i].samplers.ptr =
543             d3d12_descriptor_heap_slot_alloc(&d3d12->desc.sampler_heap).ptr -
544             d3d12->desc.sampler_heap.cpu.ptr + d3d12->desc.sampler_heap.gpu.ptr;
545 
546       for (j = 1; j < SLANG_NUM_BINDINGS; j++)
547       {
548          d3d12_descriptor_heap_slot_alloc(&d3d12->desc.srv_heap);
549          d3d12_descriptor_heap_slot_alloc(&d3d12->desc.sampler_heap);
550       }
551    }
552 
553    return true;
554 }
555 
556 static INLINE D3D12_GPU_DESCRIPTOR_HANDLE
d3d12_create_sampler(D3D12Device device,D3D12_SAMPLER_DESC * desc,d3d12_descriptor_heap_t * heap)557               d3d12_create_sampler(D3D12Device device, D3D12_SAMPLER_DESC* desc, d3d12_descriptor_heap_t* heap)
558 {
559    D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle = d3d12_descriptor_heap_slot_alloc(heap);
560    D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle = { cpu_handle.ptr - heap->cpu.ptr + heap->gpu.ptr };
561 
562    D3D12CreateSampler(device, desc, cpu_handle);
563    return gpu_handle;
564 }
565 
d3d12_init_samplers(d3d12_video_t * d3d12)566 void d3d12_init_samplers(d3d12_video_t* d3d12)
567 {
568    int                i;
569    D3D12_SAMPLER_DESC desc = { D3D12_FILTER_MIN_MAG_MIP_POINT };
570    desc.MaxAnisotropy      = 1;
571    desc.ComparisonFunc     = D3D12_COMPARISON_FUNC_NEVER;
572    desc.MinLOD             = -D3D12_FLOAT32_MAX;
573    desc.MaxLOD             = D3D12_FLOAT32_MAX;
574 
575    for (i = 0; i < RARCH_WRAP_MAX; i++)
576    {
577       switch (i)
578       {
579          default:
580          case RARCH_WRAP_BORDER:
581             desc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
582             break;
583 
584          case RARCH_WRAP_EDGE:
585             desc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
586             break;
587 
588          case RARCH_WRAP_REPEAT:
589             desc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
590             break;
591 
592          case RARCH_WRAP_MIRRORED_REPEAT:
593             desc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_MIRROR;
594             break;
595       }
596       desc.AddressV = desc.AddressU;
597       desc.AddressW = desc.AddressU;
598 
599       desc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
600       d3d12->samplers[RARCH_FILTER_LINEAR][i] =
601             d3d12_create_sampler(d3d12->device, &desc, &d3d12->desc.sampler_heap);
602 
603       desc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
604       d3d12->samplers[RARCH_FILTER_NEAREST][i] =
605             d3d12_create_sampler(d3d12->device, &desc, &d3d12->desc.sampler_heap);
606    }
607 }
608 
609 D3D12_RENDER_TARGET_BLEND_DESC d3d12_blend_enable_desc = {
610    TRUE,
611    FALSE,
612    D3D12_BLEND_SRC_ALPHA,
613    D3D12_BLEND_INV_SRC_ALPHA,
614    D3D12_BLEND_OP_ADD,
615    D3D12_BLEND_SRC_ALPHA,
616    D3D12_BLEND_INV_SRC_ALPHA,
617    D3D12_BLEND_OP_ADD,
618    D3D12_LOGIC_OP_NOOP,
619    D3D12_COLOR_WRITE_ENABLE_ALL,
620 };
621 
d3d12_init_pipeline(D3D12Device device,D3DBlob vs_code,D3DBlob ps_code,D3DBlob gs_code,D3D12_GRAPHICS_PIPELINE_STATE_DESC * desc,D3D12PipelineState * out)622 bool d3d12_init_pipeline(
623       D3D12Device                         device,
624       D3DBlob                             vs_code,
625       D3DBlob                             ps_code,
626       D3DBlob                             gs_code,
627       D3D12_GRAPHICS_PIPELINE_STATE_DESC* desc,
628       D3D12PipelineState*                 out)
629 {
630    if (vs_code)
631    {
632       desc->VS.pShaderBytecode = D3DGetBufferPointer(vs_code);
633       desc->VS.BytecodeLength  = D3DGetBufferSize(vs_code);
634    }
635    else
636    {
637       desc->VS.pShaderBytecode = NULL;
638       desc->VS.BytecodeLength  = 0;
639    }
640 
641    if (ps_code)
642    {
643       desc->PS.pShaderBytecode = D3DGetBufferPointer(ps_code);
644       desc->PS.BytecodeLength  = D3DGetBufferSize(ps_code);
645    }
646    else
647    {
648       desc->PS.pShaderBytecode = NULL;
649       desc->PS.BytecodeLength  = 0;
650    }
651 
652    if (gs_code)
653    {
654       desc->GS.pShaderBytecode = D3DGetBufferPointer(gs_code);
655       desc->GS.BytecodeLength  = D3DGetBufferSize(gs_code);
656    }
657    else
658    {
659       desc->GS.pShaderBytecode = NULL;
660       desc->GS.BytecodeLength  = 0;
661    }
662 
663    desc->SampleMask               = UINT_MAX;
664    desc->RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
665    desc->RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
666    desc->NumRenderTargets         = 1;
667    desc->SampleDesc.Count         = 1;
668 
669    D3D12CreateGraphicsPipelineState(device, desc, out);
670 
671    return true;
672 }
673 
674 D3D12_GPU_VIRTUAL_ADDRESS
d3d12_create_buffer(D3D12Device device,UINT size_in_bytes,D3D12Resource * buffer)675 d3d12_create_buffer(D3D12Device device, UINT size_in_bytes, D3D12Resource* buffer)
676 {
677    D3D12_HEAP_PROPERTIES heap_props    = { D3D12_HEAP_TYPE_UPLOAD, D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
678                                         D3D12_MEMORY_POOL_UNKNOWN, 1, 1 };
679    D3D12_RESOURCE_DESC   resource_desc = { D3D12_RESOURCE_DIMENSION_BUFFER };
680 
681    resource_desc.Width            = size_in_bytes;
682    resource_desc.Height           = 1;
683    resource_desc.DepthOrArraySize = 1;
684    resource_desc.MipLevels        = 1;
685    resource_desc.SampleDesc.Count = 1;
686    resource_desc.Layout           = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
687 
688    D3D12CreateCommittedResource(
689          device, (D3D12_HEAP_PROPERTIES*)&heap_props, D3D12_HEAP_FLAG_NONE, &resource_desc,
690          D3D12_RESOURCE_STATE_GENERIC_READ, NULL, buffer);
691 
692    return D3D12GetGPUVirtualAddress(*buffer);
693 }
694 
d3d12_release_texture(d3d12_texture_t * texture)695 void d3d12_release_texture(d3d12_texture_t* texture)
696 {
697    if (!texture->handle)
698       return;
699 
700    if (texture->srv_heap && texture->desc.MipLevels <= countof(texture->cpu_descriptor))
701    {
702       int i;
703       for (i = 0; i < texture->desc.MipLevels; i++)
704       {
705          d3d12_descriptor_heap_slot_free(texture->srv_heap, texture->cpu_descriptor[i]);
706          texture->cpu_descriptor[i].ptr = 0;
707       }
708    }
709 
710    Release(texture->handle);
711    Release(texture->upload_buffer);
712 }
d3d12_init_texture(D3D12Device device,d3d12_texture_t * texture)713 void d3d12_init_texture(D3D12Device device, d3d12_texture_t* texture)
714 {
715    int i;
716    d3d12_release_texture(texture);
717 
718    if (!texture->desc.MipLevels)
719       texture->desc.MipLevels = 1;
720 
721    if (!(texture->desc.Width >> (texture->desc.MipLevels - 1)) &&
722        !(texture->desc.Height >> (texture->desc.MipLevels - 1)))
723    {
724       unsigned width          = texture->desc.Width >> 5;
725       unsigned height         = texture->desc.Height >> 5;
726       texture->desc.MipLevels = 1;
727       while (width && height)
728       {
729          width >>= 1;
730          height >>= 1;
731          texture->desc.MipLevels++;
732       }
733    }
734 
735    {
736       D3D12_FEATURE_DATA_FORMAT_SUPPORT format_support = {
737          texture->desc.Format, D3D12_FORMAT_SUPPORT1_TEXTURE2D | D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE
738       };
739       D3D12_HEAP_PROPERTIES heap_props = { D3D12_HEAP_TYPE_DEFAULT, D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
740                                            D3D12_MEMORY_POOL_UNKNOWN, 1, 1 };
741 
742       if (texture->desc.MipLevels > 1)
743       {
744          texture->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
745          format_support.Support1 |= D3D12_FORMAT_SUPPORT1_MIP;
746          format_support.Support2 |= D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE;
747       }
748 
749       if (texture->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)
750          format_support.Support1 |= D3D12_FORMAT_SUPPORT1_RENDER_TARGET;
751 
752       texture->desc.Dimension        = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
753       texture->desc.DepthOrArraySize = 1;
754       texture->desc.SampleDesc.Count = 1;
755       texture->desc.Format           = d3d12_get_closest_match(device, &format_support);
756 
757       D3D12CreateCommittedResource(
758             device, &heap_props, D3D12_HEAP_FLAG_NONE, &texture->desc,
759             D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, NULL, &texture->handle);
760    }
761 
762    assert(texture->srv_heap);
763 
764    {
765       D3D12_SHADER_RESOURCE_VIEW_DESC desc = { texture->desc.Format };
766 
767       desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
768       desc.ViewDimension           = D3D12_SRV_DIMENSION_TEXTURE2D;
769       desc.Texture2D.MipLevels     = texture->desc.MipLevels;
770 
771       texture->cpu_descriptor[0] = d3d12_descriptor_heap_slot_alloc(texture->srv_heap);
772       D3D12CreateShaderResourceView(device, texture->handle, &desc, texture->cpu_descriptor[0]);
773       texture->gpu_descriptor[0].ptr = texture->cpu_descriptor[0].ptr - texture->srv_heap->cpu.ptr +
774                                        texture->srv_heap->gpu.ptr;
775    }
776 
777    for (i = 1; i < texture->desc.MipLevels; i++)
778    {
779       D3D12_UNORDERED_ACCESS_VIEW_DESC desc = { texture->desc.Format };
780 
781       desc.ViewDimension      = D3D12_UAV_DIMENSION_TEXTURE2D;
782       desc.Texture2D.MipSlice = i;
783 
784       texture->cpu_descriptor[i] = d3d12_descriptor_heap_slot_alloc(texture->srv_heap);
785       D3D12CreateUnorderedAccessView(
786             device, texture->handle, NULL, &desc, texture->cpu_descriptor[i]);
787       texture->gpu_descriptor[i].ptr = texture->cpu_descriptor[i].ptr - texture->srv_heap->cpu.ptr +
788                                        texture->srv_heap->gpu.ptr;
789    }
790 
791    if (texture->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)
792    {
793       assert(texture->rt_view.ptr);
794       D3D12CreateRenderTargetView(device, texture->handle, NULL, texture->rt_view);
795    }
796    else
797    {
798       D3D12_HEAP_PROPERTIES heap_props  = { D3D12_HEAP_TYPE_UPLOAD, D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
799                                            D3D12_MEMORY_POOL_UNKNOWN, 1, 1 };
800       D3D12_RESOURCE_DESC   buffer_desc = { D3D12_RESOURCE_DIMENSION_BUFFER };
801 
802       D3D12GetCopyableFootprints(
803             device, &texture->desc, 0, 1, 0, &texture->layout, &texture->num_rows,
804             &texture->row_size_in_bytes, &texture->total_bytes);
805 
806       buffer_desc.Width            = texture->total_bytes;
807       buffer_desc.Height           = 1;
808       buffer_desc.DepthOrArraySize = 1;
809       buffer_desc.MipLevels        = 1;
810       buffer_desc.SampleDesc.Count = 1;
811       buffer_desc.Layout           = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
812 #if 0
813       buffer_desc.Flags            = D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
814 #endif
815 
816       D3D12CreateCommittedResource(
817             device, &heap_props, D3D12_HEAP_FLAG_NONE, &buffer_desc,
818             D3D12_RESOURCE_STATE_GENERIC_READ, NULL, &texture->upload_buffer);
819    }
820 
821    texture->size_data.x = texture->desc.Width;
822    texture->size_data.y = texture->desc.Height;
823    texture->size_data.z = 1.0f / texture->desc.Width;
824    texture->size_data.w = 1.0f / texture->desc.Height;
825 }
826 
d3d12_update_texture(int width,int height,int pitch,DXGI_FORMAT format,const void * data,d3d12_texture_t * texture)827 void d3d12_update_texture(
828       int              width,
829       int              height,
830       int              pitch,
831       DXGI_FORMAT      format,
832       const void*      data,
833       d3d12_texture_t* texture)
834 {
835    uint8_t*    dst;
836    D3D12_RANGE read_range = { 0, 0 };
837 
838    if (!texture || !texture->upload_buffer)
839       return;
840 
841    D3D12Map(texture->upload_buffer, 0, &read_range, (void**)&dst);
842 
843    dxgi_copy(
844          width, height, format, pitch, data, texture->desc.Format,
845          texture->layout.Footprint.RowPitch, dst + texture->layout.Offset);
846 
847    D3D12Unmap(texture->upload_buffer, 0, NULL);
848 
849    texture->dirty = true;
850 }
d3d12_upload_texture(D3D12GraphicsCommandList cmd,d3d12_texture_t * texture,void * userdata)851 void d3d12_upload_texture(D3D12GraphicsCommandList cmd,
852       d3d12_texture_t* texture, void *userdata)
853 {
854    D3D12_TEXTURE_COPY_LOCATION src = { 0 };
855    D3D12_TEXTURE_COPY_LOCATION dst = { 0 };
856 
857    src.pResource       = texture->upload_buffer;
858    src.Type            = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
859    src.PlacedFootprint = texture->layout;
860 
861    dst.pResource        = texture->handle;
862    dst.Type             = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
863    dst.SubresourceIndex = 0;
864 
865    d3d12_resource_transition(
866          cmd, texture->handle, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
867          D3D12_RESOURCE_STATE_COPY_DEST);
868 
869    D3D12CopyTextureRegion(cmd, &dst, 0, 0, 0, &src, NULL);
870 
871    d3d12_resource_transition(
872          cmd, texture->handle, D3D12_RESOURCE_STATE_COPY_DEST,
873          D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
874 
875    if (texture->desc.MipLevels > 1)
876    {
877       unsigned       i;
878       d3d12_video_t* d3d12 = (d3d12_video_t*)userdata;
879 
880       D3D12SetComputeRootSignature(cmd, d3d12->desc.cs_rootSignature);
881       D3D12SetPipelineState(cmd, d3d12->mipmapgen_pipe);
882       D3D12SetComputeRootDescriptorTable(cmd, CS_ROOT_ID_TEXTURE_T, texture->gpu_descriptor[0]);
883 
884       for (i = 1; i < texture->desc.MipLevels; i++)
885       {
886          unsigned width  = texture->desc.Width >> i;
887          unsigned height = texture->desc.Height >> i;
888          struct
889          {
890             uint32_t src_level;
891             float    texel_size[2];
892          } cbuffer = { i - 1, { 1.0f / width, 1.0f / height } };
893 
894          {
895             D3D12_RESOURCE_BARRIER barrier = { D3D12_RESOURCE_BARRIER_TYPE_TRANSITION };
896             barrier.Transition.pResource   = texture->handle;
897             barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
898             barrier.Transition.StateAfter  = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
899             barrier.Transition.Subresource = i;
900             D3D12ResourceBarrier(cmd, 1, &barrier);
901          }
902 
903          D3D12SetComputeRootDescriptorTable(cmd, CS_ROOT_ID_UAV_T, texture->gpu_descriptor[i]);
904          D3D12SetComputeRoot32BitConstants(
905                cmd, CS_ROOT_ID_CONSTANTS, sizeof(cbuffer) / sizeof(uint32_t), &cbuffer, 0);
906          D3D12Dispatch(cmd, (width + 0x7) >> 3, (height + 0x7) >> 3, 1);
907 
908          {
909             D3D12_RESOURCE_BARRIER barrier = { D3D12_RESOURCE_BARRIER_TYPE_UAV };
910             barrier.UAV.pResource          = texture->handle;
911             D3D12ResourceBarrier(cmd, 1, &barrier);
912          }
913 
914          {
915             D3D12_RESOURCE_BARRIER barrier = { D3D12_RESOURCE_BARRIER_TYPE_TRANSITION };
916             barrier.Transition.pResource   = texture->handle;
917             barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
918             barrier.Transition.StateAfter  = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
919             barrier.Transition.Subresource = i;
920             D3D12ResourceBarrier(cmd, 1, &barrier);
921          }
922       }
923    }
924 
925    texture->dirty = false;
926 }
927 
d3d12_create_fullscreen_quad_vbo(D3D12Device device,D3D12_VERTEX_BUFFER_VIEW * view,D3D12Resource * vbo)928 void d3d12_create_fullscreen_quad_vbo(
929       D3D12Device device, D3D12_VERTEX_BUFFER_VIEW* view, D3D12Resource* vbo)
930 {
931    static const d3d12_vertex_t vertices[] = {
932       { { 0.0f, 0.0f }, { 0.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
933       { { 0.0f, 1.0f }, { 0.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
934       { { 1.0f, 0.0f }, { 1.0f, 1.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
935       { { 1.0f, 1.0f }, { 1.0f, 0.0f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
936    };
937 
938    view->SizeInBytes    = sizeof(vertices);
939    view->StrideInBytes  = sizeof(*vertices);
940    view->BufferLocation = d3d12_create_buffer(device, view->SizeInBytes, vbo);
941 
942    {
943       void*       vertex_data_begin;
944       D3D12_RANGE read_range = { 0, 0 };
945 
946       D3D12Map(*vbo, 0, &read_range, &vertex_data_begin);
947       memcpy(vertex_data_begin, vertices, sizeof(vertices));
948       D3D12Unmap(*vbo, 0, NULL);
949    }
950 }
951 
d3d12_get_closest_match(D3D12Device device,D3D12_FEATURE_DATA_FORMAT_SUPPORT * desired)952 DXGI_FORMAT d3d12_get_closest_match(D3D12Device device, D3D12_FEATURE_DATA_FORMAT_SUPPORT* desired)
953 {
954    DXGI_FORMAT  default_list[] = { desired->Format, DXGI_FORMAT_UNKNOWN };
955    DXGI_FORMAT* format         = dxgi_get_format_fallback_list(desired->Format);
956 
957    if (!format)
958       format = default_list;
959 
960    while (*format != DXGI_FORMAT_UNKNOWN)
961    {
962       D3D12_FEATURE_DATA_FORMAT_SUPPORT format_support = { *format };
963       if (SUCCEEDED(D3D12CheckFeatureSupport(
964                 device, D3D12_FEATURE_FORMAT_SUPPORT, &format_support, sizeof(format_support))) &&
965           ((format_support.Support1 & desired->Support1) == desired->Support1) &&
966           ((format_support.Support2 & desired->Support2) == desired->Support2))
967          break;
968       format++;
969    }
970    assert(*format);
971    return *format;
972 }
973