1/*
2 * Copyright © Microsoft Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24#include "dzn_private.h"
25
26#define D3D12_IGNORE_SDK_LAYERS
27#define COBJMACROS
28#include <directx/d3d12.h>
29
30#include <vulkan/vulkan.h>
31
32#include "util/format/u_format.h"
33#include "util/log.h"
34
35#include <directx/d3d12sdklayers.h>
36#include <util/u_dl.h>
37
38static const DXGI_FORMAT formats[PIPE_FORMAT_COUNT] = {
39#define MAP_FORMAT_NORM(FMT) \
40   [PIPE_FORMAT_ ## FMT ## _UNORM] = DXGI_FORMAT_ ## FMT ## _UNORM, \
41   [PIPE_FORMAT_ ## FMT ## _SNORM] = DXGI_FORMAT_ ## FMT ## _SNORM,
42
43#define MAP_FORMAT_INT(FMT) \
44   [PIPE_FORMAT_ ## FMT ## _UINT] = DXGI_FORMAT_ ## FMT ## _UINT, \
45   [PIPE_FORMAT_ ## FMT ## _SINT] = DXGI_FORMAT_ ## FMT ## _SINT,
46
47#define MAP_FORMAT_SRGB(FMT) \
48   [PIPE_FORMAT_ ## FMT ## _SRGB] = DXGI_FORMAT_ ## FMT ## _UNORM_SRGB,
49
50#define MAP_FORMAT_FLOAT(FMT) \
51   [PIPE_FORMAT_ ## FMT ## _FLOAT] = DXGI_FORMAT_ ## FMT ## _FLOAT,
52
53#define MAP_EMU_FORMAT_NO_ALPHA(BITS, TYPE) \
54   [PIPE_FORMAT_L ## BITS ## _ ## TYPE] = DXGI_FORMAT_R ## BITS ## _ ## TYPE, \
55   [PIPE_FORMAT_I ## BITS ## _ ## TYPE] = DXGI_FORMAT_R ## BITS ## _ ## TYPE, \
56   [PIPE_FORMAT_L ## BITS ## A ## BITS ## _ ## TYPE] = \
57          DXGI_FORMAT_R ## BITS ## G ## BITS ## _ ## TYPE,
58
59#define MAP_EMU_FORMAT(BITS, TYPE) \
60   [PIPE_FORMAT_A ## BITS ## _ ## TYPE] = DXGI_FORMAT_R ## BITS ## _ ## TYPE, \
61   MAP_EMU_FORMAT_NO_ALPHA(BITS, TYPE)
62
63   MAP_FORMAT_NORM(R8)
64   MAP_FORMAT_INT(R8)
65
66   MAP_FORMAT_NORM(R8G8)
67   MAP_FORMAT_INT(R8G8)
68
69   MAP_FORMAT_NORM(R8G8B8A8)
70   MAP_FORMAT_INT(R8G8B8A8)
71   MAP_FORMAT_SRGB(R8G8B8A8)
72
73   [PIPE_FORMAT_B8G8R8X8_UNORM] = DXGI_FORMAT_B8G8R8X8_UNORM,
74   [PIPE_FORMAT_B8G8R8A8_UNORM] = DXGI_FORMAT_B8G8R8A8_UNORM,
75   [PIPE_FORMAT_B4G4R4A4_UNORM] = DXGI_FORMAT_B4G4R4A4_UNORM,
76   [PIPE_FORMAT_A4R4G4B4_UNORM] = DXGI_FORMAT_B4G4R4A4_UNORM,
77   [PIPE_FORMAT_B5G6R5_UNORM] = DXGI_FORMAT_B5G6R5_UNORM,
78   [PIPE_FORMAT_B5G5R5A1_UNORM] = DXGI_FORMAT_B5G5R5A1_UNORM,
79
80   MAP_FORMAT_SRGB(B8G8R8A8)
81
82   MAP_FORMAT_INT(R32)
83   MAP_FORMAT_FLOAT(R32)
84   MAP_FORMAT_INT(R32G32)
85   MAP_FORMAT_FLOAT(R32G32)
86   MAP_FORMAT_INT(R32G32B32)
87   MAP_FORMAT_FLOAT(R32G32B32)
88   MAP_FORMAT_INT(R32G32B32A32)
89   MAP_FORMAT_FLOAT(R32G32B32A32)
90
91   MAP_FORMAT_NORM(R16)
92   MAP_FORMAT_INT(R16)
93   MAP_FORMAT_FLOAT(R16)
94
95   MAP_FORMAT_NORM(R16G16)
96   MAP_FORMAT_INT(R16G16)
97   MAP_FORMAT_FLOAT(R16G16)
98
99   MAP_FORMAT_NORM(R16G16B16A16)
100   MAP_FORMAT_INT(R16G16B16A16)
101   MAP_FORMAT_FLOAT(R16G16B16A16)
102
103   [PIPE_FORMAT_A8_UNORM] = DXGI_FORMAT_A8_UNORM,
104   MAP_EMU_FORMAT_NO_ALPHA(8, UNORM)
105   MAP_EMU_FORMAT(8, SNORM)
106   MAP_EMU_FORMAT(8, SINT)
107   MAP_EMU_FORMAT(8, UINT)
108   MAP_EMU_FORMAT(16, UNORM)
109   MAP_EMU_FORMAT(16, SNORM)
110   MAP_EMU_FORMAT(16, SINT)
111   MAP_EMU_FORMAT(16, UINT)
112   MAP_EMU_FORMAT(16, FLOAT)
113   MAP_EMU_FORMAT(32, SINT)
114   MAP_EMU_FORMAT(32, UINT)
115   MAP_EMU_FORMAT(32, FLOAT)
116
117   [PIPE_FORMAT_R9G9B9E5_FLOAT] = DXGI_FORMAT_R9G9B9E5_SHAREDEXP,
118   [PIPE_FORMAT_R11G11B10_FLOAT] = DXGI_FORMAT_R11G11B10_FLOAT,
119   [PIPE_FORMAT_R10G10B10A2_UINT] = DXGI_FORMAT_R10G10B10A2_UINT,
120   [PIPE_FORMAT_R10G10B10A2_UNORM] = DXGI_FORMAT_R10G10B10A2_UNORM,
121
122   [PIPE_FORMAT_DXT1_RGB] = DXGI_FORMAT_BC1_UNORM,
123   [PIPE_FORMAT_DXT1_RGBA] = DXGI_FORMAT_BC1_UNORM,
124   [PIPE_FORMAT_DXT3_RGBA] = DXGI_FORMAT_BC2_UNORM,
125   [PIPE_FORMAT_DXT5_RGBA] = DXGI_FORMAT_BC3_UNORM,
126
127   [PIPE_FORMAT_DXT1_SRGB] = DXGI_FORMAT_BC1_UNORM_SRGB,
128   [PIPE_FORMAT_DXT1_SRGBA] = DXGI_FORMAT_BC1_UNORM_SRGB,
129   [PIPE_FORMAT_DXT3_SRGBA] = DXGI_FORMAT_BC2_UNORM_SRGB,
130   [PIPE_FORMAT_DXT5_SRGBA] = DXGI_FORMAT_BC3_UNORM_SRGB,
131
132   [PIPE_FORMAT_RGTC1_UNORM] = DXGI_FORMAT_BC4_UNORM,
133   [PIPE_FORMAT_RGTC1_SNORM] = DXGI_FORMAT_BC4_SNORM,
134   [PIPE_FORMAT_RGTC2_UNORM] = DXGI_FORMAT_BC5_UNORM,
135   [PIPE_FORMAT_RGTC2_SNORM] = DXGI_FORMAT_BC5_SNORM,
136
137   [PIPE_FORMAT_BPTC_RGB_UFLOAT] = DXGI_FORMAT_BC6H_UF16,
138   [PIPE_FORMAT_BPTC_RGB_FLOAT] = DXGI_FORMAT_BC6H_SF16,
139   [PIPE_FORMAT_BPTC_RGBA_UNORM] = DXGI_FORMAT_BC7_UNORM,
140   [PIPE_FORMAT_BPTC_SRGBA] = DXGI_FORMAT_BC7_UNORM_SRGB,
141
142   [PIPE_FORMAT_Z32_FLOAT] = DXGI_FORMAT_R32_TYPELESS,
143   [PIPE_FORMAT_Z16_UNORM] = DXGI_FORMAT_R16_TYPELESS,
144   [PIPE_FORMAT_Z24X8_UNORM] = DXGI_FORMAT_R24G8_TYPELESS,
145   [PIPE_FORMAT_X24S8_UINT] = DXGI_FORMAT_R24G8_TYPELESS,
146
147   [PIPE_FORMAT_Z24_UNORM_S8_UINT] = DXGI_FORMAT_R24G8_TYPELESS,
148   [PIPE_FORMAT_Z32_FLOAT_S8X24_UINT] = DXGI_FORMAT_R32G8X24_TYPELESS,
149   [PIPE_FORMAT_X32_S8X24_UINT] = DXGI_FORMAT_R32G8X24_TYPELESS,
150};
151
152DXGI_FORMAT
153dzn_pipe_to_dxgi_format(enum pipe_format in)
154{
155   return formats[in];
156}
157
158DXGI_FORMAT
159dzn_get_typeless_dxgi_format(DXGI_FORMAT in)
160{
161   if (in >= DXGI_FORMAT_R32G32B32A32_TYPELESS && in <= DXGI_FORMAT_R32G32B32A32_SINT)
162      return DXGI_FORMAT_R32G32B32A32_TYPELESS;
163   if (in >= DXGI_FORMAT_R32G32B32_TYPELESS && in <= DXGI_FORMAT_R32G32B32_SINT)
164      return DXGI_FORMAT_R32G32B32_TYPELESS;
165   if (in >= DXGI_FORMAT_R16G16B16A16_TYPELESS && in <= DXGI_FORMAT_R16G16B16A16_SINT)
166      return DXGI_FORMAT_R16G16B16A16_TYPELESS;
167   if (in >= DXGI_FORMAT_R32G32_TYPELESS && in <= DXGI_FORMAT_R32G32_SINT)
168      return DXGI_FORMAT_R32G32_TYPELESS;
169   if (in >= DXGI_FORMAT_R32G8X24_TYPELESS && in <= DXGI_FORMAT_X32_TYPELESS_G8X24_UINT)
170      return DXGI_FORMAT_R32G8X24_TYPELESS;
171   if (in >= DXGI_FORMAT_R10G10B10A2_TYPELESS && in <= DXGI_FORMAT_R10G10B10A2_UINT)
172      return DXGI_FORMAT_R10G10B10A2_TYPELESS;
173   if (in >= DXGI_FORMAT_R8G8B8A8_TYPELESS && in <= DXGI_FORMAT_R8G8B8A8_SINT)
174      return DXGI_FORMAT_R8G8B8A8_TYPELESS;
175   if (in >= DXGI_FORMAT_R16G16_TYPELESS && in <= DXGI_FORMAT_R16G16_SINT)
176      return DXGI_FORMAT_R16G16_TYPELESS;
177   if (in >= DXGI_FORMAT_R32_TYPELESS && in <= DXGI_FORMAT_R32_SINT)
178      return DXGI_FORMAT_R32_TYPELESS;
179   if (in >= DXGI_FORMAT_R24G8_TYPELESS && in <= DXGI_FORMAT_X24_TYPELESS_G8_UINT)
180      return DXGI_FORMAT_R24G8_TYPELESS;
181   if (in >= DXGI_FORMAT_R8G8_TYPELESS && in <= DXGI_FORMAT_R8G8_SINT)
182      return DXGI_FORMAT_R8G8_TYPELESS;
183   if (in >= DXGI_FORMAT_R16_TYPELESS && in <= DXGI_FORMAT_R16_SINT)
184      return DXGI_FORMAT_R16_TYPELESS;
185   if (in >= DXGI_FORMAT_R8_TYPELESS && in <= DXGI_FORMAT_R8_SINT)
186      return DXGI_FORMAT_R8_TYPELESS;
187   if (in >= DXGI_FORMAT_BC1_TYPELESS && in <= DXGI_FORMAT_BC1_UNORM_SRGB)
188      return DXGI_FORMAT_BC1_TYPELESS;
189   if (in >= DXGI_FORMAT_BC2_TYPELESS && in <= DXGI_FORMAT_BC2_UNORM_SRGB)
190      return DXGI_FORMAT_BC2_TYPELESS;
191   if (in >= DXGI_FORMAT_BC3_TYPELESS && in <= DXGI_FORMAT_BC3_UNORM_SRGB)
192      return DXGI_FORMAT_BC3_TYPELESS;
193   if (in >= DXGI_FORMAT_BC4_TYPELESS && in <= DXGI_FORMAT_BC4_SNORM)
194      return DXGI_FORMAT_BC4_TYPELESS;
195   if (in >= DXGI_FORMAT_BC5_TYPELESS && in <= DXGI_FORMAT_BC5_SNORM)
196      return DXGI_FORMAT_BC5_TYPELESS;
197   if (in == DXGI_FORMAT_B8G8R8A8_UNORM ||
198       (in >= DXGI_FORMAT_B8G8R8A8_TYPELESS && in <= DXGI_FORMAT_B8G8R8A8_UNORM_SRGB))
199      return DXGI_FORMAT_B8G8R8A8_TYPELESS;
200   if (in == DXGI_FORMAT_B8G8R8X8_UNORM ||
201       (in >= DXGI_FORMAT_B8G8R8X8_TYPELESS && in <= DXGI_FORMAT_B8G8R8X8_UNORM_SRGB))
202      return DXGI_FORMAT_B8G8R8X8_TYPELESS;
203   if (in >= DXGI_FORMAT_BC6H_TYPELESS && in <= DXGI_FORMAT_BC6H_SF16)
204      return DXGI_FORMAT_BC6H_TYPELESS;
205   if (in >= DXGI_FORMAT_BC7_TYPELESS && in <= DXGI_FORMAT_BC7_UNORM_SRGB)
206      return DXGI_FORMAT_BC7_TYPELESS;
207
208   return in;
209}
210
211struct dzn_sampler_filter_info {
212   VkFilter min, mag;
213   VkSamplerMipmapMode mipmap;
214};
215
216#define FILTER(__min, __mag, __mipmap) \
217{ \
218   .min = VK_FILTER_ ## __min, \
219   .mag = VK_FILTER_ ## __mag, \
220   .mipmap = VK_SAMPLER_MIPMAP_MODE_ ## __mipmap, \
221}
222
223static const struct dzn_sampler_filter_info filter_table[] = {
224   [D3D12_FILTER_MIN_MAG_MIP_POINT] = FILTER(NEAREST, NEAREST, NEAREST),
225   [D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR] = FILTER(NEAREST, NEAREST, LINEAR),
226   [D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT] = FILTER(NEAREST, LINEAR, NEAREST),
227   [D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR] = FILTER(NEAREST, LINEAR, LINEAR),
228   [D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT] = FILTER(LINEAR, NEAREST, NEAREST),
229   [D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR] = FILTER(LINEAR, NEAREST, LINEAR),
230   [D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT] = FILTER(LINEAR, LINEAR, NEAREST),
231   [D3D12_FILTER_MIN_MAG_MIP_LINEAR] = FILTER(LINEAR, LINEAR, LINEAR),
232};
233
234D3D12_FILTER
235dzn_translate_sampler_filter(const VkSamplerCreateInfo *create_info)
236{
237   D3D12_FILTER filter = (D3D12_FILTER)0;
238
239   if (!create_info->anisotropyEnable) {
240      unsigned i;
241      for (i = 0; i < ARRAY_SIZE(filter_table); i++) {
242         if (create_info->minFilter == filter_table[i].min &&
243             create_info->magFilter == filter_table[i].mag &&
244             create_info->mipmapMode == filter_table[i].mipmap) {
245            filter = (D3D12_FILTER)i;
246            break;
247         }
248      }
249
250      assert(i < ARRAY_SIZE(filter_table));
251   } else {
252      filter = D3D12_FILTER_ANISOTROPIC;
253   }
254
255   if (create_info->compareEnable)
256      filter = (D3D12_FILTER)(filter + D3D12_FILTER_COMPARISON_MIN_MAG_MIP_POINT);
257
258   return filter;
259}
260
261D3D12_COMPARISON_FUNC
262dzn_translate_compare_op(VkCompareOp in)
263{
264   switch (in) {
265   case VK_COMPARE_OP_NEVER: return D3D12_COMPARISON_FUNC_NEVER;
266   case VK_COMPARE_OP_LESS: return D3D12_COMPARISON_FUNC_LESS;
267   case VK_COMPARE_OP_EQUAL: return D3D12_COMPARISON_FUNC_EQUAL;
268   case VK_COMPARE_OP_LESS_OR_EQUAL: return D3D12_COMPARISON_FUNC_LESS_EQUAL;
269   case VK_COMPARE_OP_GREATER: return D3D12_COMPARISON_FUNC_GREATER;
270   case VK_COMPARE_OP_NOT_EQUAL: return D3D12_COMPARISON_FUNC_NOT_EQUAL;
271   case VK_COMPARE_OP_GREATER_OR_EQUAL: return D3D12_COMPARISON_FUNC_GREATER_EQUAL;
272   case VK_COMPARE_OP_ALWAYS: return D3D12_COMPARISON_FUNC_ALWAYS;
273   default: unreachable("Invalid compare op");
274   }
275}
276
277void
278dzn_translate_viewport(D3D12_VIEWPORT *out,
279                       const VkViewport *in)
280{
281   out->TopLeftX = in->x;
282   out->TopLeftY = in->height < 0 ? in->height + in->y : in->y;
283   out->Width = in->width;
284   out->Height = fabs(in->height);
285   out->MinDepth = MIN2(in->minDepth, in->maxDepth);
286   out->MaxDepth = MAX2(in->maxDepth, in->minDepth);
287}
288
289void
290dzn_translate_rect(D3D12_RECT *out,
291                   const VkRect2D *in)
292{
293   out->left = in->offset.x;
294   out->top = in->offset.y;
295   out->right = in->offset.x + in->extent.width;
296   out->bottom = in->offset.y + in->extent.height;
297}
298
299static ID3D12Debug *
300get_debug_interface()
301{
302   typedef HRESULT(WINAPI *PFN_D3D12_GET_DEBUG_INTERFACE)(REFIID riid, void **ppFactory);
303   PFN_D3D12_GET_DEBUG_INTERFACE D3D12GetDebugInterface;
304
305   struct util_dl_library *d3d12_mod = util_dl_open(UTIL_DL_PREFIX "d3d12" UTIL_DL_EXT);
306   if (!d3d12_mod) {
307      mesa_loge("failed to load D3D12\n");
308      return NULL;
309   }
310
311   D3D12GetDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)util_dl_get_proc_address(d3d12_mod, "D3D12GetDebugInterface");
312   if (!D3D12GetDebugInterface) {
313      mesa_loge("failed to load D3D12GetDebugInterface from D3D12.DLL\n");
314      return NULL;
315   }
316
317   ID3D12Debug *debug;
318   if (FAILED(D3D12GetDebugInterface(&IID_ID3D12Debug, (void **)&debug))) {
319      mesa_loge("D3D12GetDebugInterface failed\n");
320      return NULL;
321   }
322
323   return debug;
324}
325
326void
327d3d12_enable_debug_layer(void)
328{
329   ID3D12Debug *debug = get_debug_interface();
330   if (debug) {
331      ID3D12Debug_EnableDebugLayer(debug);
332      ID3D12Debug_Release(debug);
333   }
334}
335
336void
337d3d12_enable_gpu_validation(void)
338{
339   ID3D12Debug *debug = get_debug_interface();
340   if (debug) {
341      ID3D12Debug3 *debug3;
342      if (SUCCEEDED(ID3D12Debug_QueryInterface(debug,
343                                               &IID_ID3D12Debug3,
344                                               (void **)&debug3))) {
345         ID3D12Debug3_SetEnableGPUBasedValidation(debug3, true);
346         ID3D12Debug3_Release(debug3);
347      }
348      ID3D12Debug_Release(debug);
349   }
350}
351
352ID3D12Device2 *
353d3d12_create_device(IUnknown *adapter, bool experimental_features)
354{
355   typedef HRESULT(WINAPI *PFN_D3D12CREATEDEVICE)(IUnknown *, D3D_FEATURE_LEVEL, REFIID, void **);
356   PFN_D3D12CREATEDEVICE D3D12CreateDevice;
357
358   struct util_dl_library *d3d12_mod = util_dl_open(UTIL_DL_PREFIX "d3d12" UTIL_DL_EXT);
359   if (!d3d12_mod) {
360      mesa_loge("failed to load D3D12\n");
361      return NULL;
362   }
363
364#ifdef _WIN32
365   if (experimental_features)
366#endif
367   {
368      typedef HRESULT(WINAPI *PFN_D3D12ENABLEEXPERIMENTALFEATURES)(UINT, const IID *, void *, UINT *);
369      PFN_D3D12ENABLEEXPERIMENTALFEATURES D3D12EnableExperimentalFeatures =
370         (PFN_D3D12ENABLEEXPERIMENTALFEATURES)util_dl_get_proc_address(d3d12_mod, "D3D12EnableExperimentalFeatures");
371      if (FAILED(D3D12EnableExperimentalFeatures(1, &D3D12ExperimentalShaderModels, NULL, NULL))) {
372         mesa_loge("failed to enable experimental shader models\n");
373         return NULL;
374      }
375   }
376
377   D3D12CreateDevice = (PFN_D3D12CREATEDEVICE)util_dl_get_proc_address(d3d12_mod, "D3D12CreateDevice");
378   if (!D3D12CreateDevice) {
379      mesa_loge("failed to load D3D12CreateDevice from D3D12\n");
380      return NULL;
381   }
382
383   ID3D12Device2 *dev;
384   if (SUCCEEDED(D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0,
385                 &IID_ID3D12Device2,
386                 (void **)&dev)))
387      return dev;
388
389   mesa_loge("D3D12CreateDevice failed\n");
390   return NULL;
391}
392
393PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE
394d3d12_get_serialize_root_sig(void)
395{
396   struct util_dl_library *d3d12_mod = util_dl_open(UTIL_DL_PREFIX "d3d12" UTIL_DL_EXT);
397   if (!d3d12_mod) {
398      mesa_loge("failed to load D3D12\n");
399      return NULL;
400   }
401
402   return (PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE)
403      util_dl_get_proc_address(d3d12_mod, "D3D12SerializeVersionedRootSignature");
404}
405