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#include "vk_alloc.h"
27#include "vk_common_entrypoints.h"
28#include "vk_cmd_enqueue_entrypoints.h"
29#include "vk_debug_report.h"
30#include "vk_format.h"
31#include "vk_sync_dummy.h"
32#include "vk_util.h"
33
34#include "git_sha1.h"
35
36#include "util/debug.h"
37#include "util/disk_cache.h"
38#include "util/macros.h"
39#include "util/mesa-sha1.h"
40
41#include "glsl_types.h"
42
43#include "dxil_validator.h"
44
45#include "git_sha1.h"
46
47#include <string.h>
48#include <stdio.h>
49#include <stdlib.h>
50
51#ifdef _WIN32
52#include <windows.h>
53#include <shlobj.h>
54#include "dzn_dxgi.h"
55#endif
56
57#include <directx/d3d12sdklayers.h>
58
59#if defined(VK_USE_PLATFORM_WIN32_KHR) || \
60    defined(VK_USE_PLATFORM_WAYLAND_KHR) || \
61    defined(VK_USE_PLATFORM_XCB_KHR) || \
62    defined(VK_USE_PLATFORM_XLIB_KHR)
63#define DZN_USE_WSI_PLATFORM
64#endif
65
66#define DZN_API_VERSION VK_MAKE_VERSION(1, 0, VK_HEADER_VERSION)
67
68#define MAX_TIER2_MEMORY_TYPES 3
69
70static const struct vk_instance_extension_table instance_extensions = {
71   .KHR_get_physical_device_properties2      = true,
72#ifdef DZN_USE_WSI_PLATFORM
73   .KHR_surface                              = true,
74#endif
75#ifdef VK_USE_PLATFORM_WIN32_KHR
76   .KHR_win32_surface                        = true,
77#endif
78#ifdef VK_USE_PLATFORM_XCB_KHR
79   .KHR_xcb_surface                          = true,
80#endif
81#ifdef VK_USE_PLATFORM_WAYLAND_KHR
82   .KHR_wayland_surface                      = true,
83#endif
84#ifdef VK_USE_PLATFORM_XLIB_KHR
85   .KHR_xlib_surface                         = true,
86#endif
87   .EXT_debug_report                         = true,
88   .EXT_debug_utils                          = true,
89};
90
91static void
92dzn_physical_device_get_extensions(struct dzn_physical_device *pdev)
93{
94   pdev->vk.supported_extensions = (struct vk_device_extension_table) {
95      .KHR_create_renderpass2                = true,
96      .KHR_depth_stencil_resolve             = true,
97      .KHR_descriptor_update_template        = true,
98      .KHR_draw_indirect_count               = true,
99      .KHR_driver_properties                 = true,
100      .KHR_dynamic_rendering                 = true,
101      .KHR_shader_draw_parameters            = true,
102#ifdef DZN_USE_WSI_PLATFORM
103      .KHR_swapchain                         = true,
104#endif
105      .EXT_vertex_attribute_divisor          = true,
106   };
107}
108
109VKAPI_ATTR VkResult VKAPI_CALL
110dzn_EnumerateInstanceExtensionProperties(const char *pLayerName,
111                                         uint32_t *pPropertyCount,
112                                         VkExtensionProperties *pProperties)
113{
114   /* We don't support any layers  */
115   if (pLayerName)
116      return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);
117
118   return vk_enumerate_instance_extension_properties(
119      &instance_extensions, pPropertyCount, pProperties);
120}
121
122static const struct debug_control dzn_debug_options[] = {
123   { "sync", DZN_DEBUG_SYNC },
124   { "nir", DZN_DEBUG_NIR },
125   { "dxil", DZN_DEBUG_DXIL },
126   { "warp", DZN_DEBUG_WARP },
127   { "internal", DZN_DEBUG_INTERNAL },
128   { "signature", DZN_DEBUG_SIG },
129   { "gbv", DZN_DEBUG_GBV },
130   { "d3d12", DZN_DEBUG_D3D12 },
131   { "debugger", DZN_DEBUG_DEBUGGER },
132   { "redirects", DZN_DEBUG_REDIRECTS },
133   { NULL, 0 }
134};
135
136static void
137dzn_physical_device_destroy(struct dzn_physical_device *pdev)
138{
139   struct dzn_instance *instance = container_of(pdev->vk.instance, struct dzn_instance, vk);
140
141   list_del(&pdev->link);
142
143   if (pdev->dev)
144      ID3D12Device1_Release(pdev->dev);
145
146   if (pdev->adapter)
147      IUnknown_Release(pdev->adapter);
148
149   dzn_wsi_finish(pdev);
150   vk_physical_device_finish(&pdev->vk);
151   vk_free(&instance->vk.alloc, pdev);
152}
153
154static void
155dzn_instance_destroy(struct dzn_instance *instance, const VkAllocationCallbacks *alloc)
156{
157   if (!instance)
158      return;
159
160#ifdef _WIN32
161   if (instance->dxil_validator)
162      dxil_destroy_validator(instance->dxil_validator);
163#endif
164
165   list_for_each_entry_safe(struct dzn_physical_device, pdev,
166                            &instance->physical_devices, link) {
167      dzn_physical_device_destroy(pdev);
168   }
169
170   vk_instance_finish(&instance->vk);
171   vk_free2(vk_default_allocator(), alloc, instance);
172}
173
174static VkResult
175dzn_instance_create(const VkInstanceCreateInfo *pCreateInfo,
176                    const VkAllocationCallbacks *pAllocator,
177                    VkInstance *out)
178{
179   struct dzn_instance *instance =
180      vk_zalloc2(vk_default_allocator(), pAllocator, sizeof(*instance), 8,
181                 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
182   if (!instance)
183      return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
184
185   struct vk_instance_dispatch_table dispatch_table;
186   vk_instance_dispatch_table_from_entrypoints(&dispatch_table,
187                                               &dzn_instance_entrypoints,
188                                               true);
189
190   VkResult result =
191      vk_instance_init(&instance->vk, &instance_extensions,
192                       &dispatch_table, pCreateInfo,
193                       pAllocator ? pAllocator : vk_default_allocator());
194   if (result != VK_SUCCESS) {
195      vk_free2(vk_default_allocator(), pAllocator, instance);
196      return result;
197   }
198
199   list_inithead(&instance->physical_devices);
200   instance->physical_devices_enumerated = false;
201   instance->debug_flags =
202      parse_debug_string(getenv("DZN_DEBUG"), dzn_debug_options);
203
204#ifdef _WIN32
205   if (instance->debug_flags & DZN_DEBUG_DEBUGGER) {
206      /* wait for debugger to attach... */
207      while (!IsDebuggerPresent()) {
208         Sleep(100);
209      }
210   }
211
212   if (instance->debug_flags & DZN_DEBUG_REDIRECTS) {
213      char home[MAX_PATH], path[MAX_PATH];
214      if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_PROFILE, NULL, 0, home))) {
215         snprintf(path, sizeof(path), "%s\\stderr.txt", home);
216         freopen(path, "w", stderr);
217         snprintf(path, sizeof(path), "%s\\stdout.txt", home);
218         freopen(path, "w", stdout);
219      }
220   }
221#endif
222
223   bool missing_validator = false;
224#ifdef _WIN32
225   instance->dxil_validator = dxil_create_validator(NULL);
226   missing_validator = !instance->dxil_validator;
227#endif
228
229   instance->d3d12.serialize_root_sig = d3d12_get_serialize_root_sig();
230
231   if (missing_validator ||
232       !instance->d3d12.serialize_root_sig) {
233      dzn_instance_destroy(instance, pAllocator);
234      return vk_error(NULL, VK_ERROR_INITIALIZATION_FAILED);
235   }
236
237   if (instance->debug_flags & DZN_DEBUG_D3D12)
238      d3d12_enable_debug_layer();
239   if (instance->debug_flags & DZN_DEBUG_GBV)
240      d3d12_enable_gpu_validation();
241
242   instance->sync_binary_type = vk_sync_binary_get_type(&dzn_sync_type);
243
244   *out = dzn_instance_to_handle(instance);
245   return VK_SUCCESS;
246}
247
248VKAPI_ATTR VkResult VKAPI_CALL
249dzn_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
250                   const VkAllocationCallbacks *pAllocator,
251                   VkInstance *pInstance)
252{
253   return dzn_instance_create(pCreateInfo, pAllocator, pInstance);
254}
255
256VKAPI_ATTR void VKAPI_CALL
257dzn_DestroyInstance(VkInstance instance,
258                    const VkAllocationCallbacks *pAllocator)
259{
260   dzn_instance_destroy(dzn_instance_from_handle(instance), pAllocator);
261}
262
263static void
264dzn_physical_device_init_uuids(struct dzn_physical_device *pdev)
265{
266   const char *mesa_version = "Mesa " PACKAGE_VERSION MESA_GIT_SHA1;
267
268   struct mesa_sha1 sha1_ctx;
269   uint8_t sha1[SHA1_DIGEST_LENGTH];
270   STATIC_ASSERT(VK_UUID_SIZE <= sizeof(sha1));
271
272   /* The pipeline cache UUID is used for determining when a pipeline cache is
273    * invalid. Our cache is device-agnostic, but it does depend on the features
274    * provided by the D3D12 driver, so let's hash the build ID plus some
275    * caps that might impact our NIR lowering passes.
276    */
277   _mesa_sha1_init(&sha1_ctx);
278   _mesa_sha1_update(&sha1_ctx,  mesa_version, strlen(mesa_version));
279   disk_cache_get_function_identifier(dzn_physical_device_init_uuids, &sha1_ctx);
280   _mesa_sha1_update(&sha1_ctx,  &pdev->options, sizeof(pdev->options));
281   _mesa_sha1_update(&sha1_ctx,  &pdev->options2, sizeof(pdev->options2));
282   _mesa_sha1_final(&sha1_ctx, sha1);
283   memcpy(pdev->pipeline_cache_uuid, sha1, VK_UUID_SIZE);
284
285   /* The driver UUID is used for determining sharability of images and memory
286    * between two Vulkan instances in separate processes.  People who want to
287    * share memory need to also check the device UUID (below) so all this
288    * needs to be is the build-id.
289    */
290   _mesa_sha1_compute(mesa_version, strlen(mesa_version), sha1);
291   memcpy(pdev->driver_uuid, sha1, VK_UUID_SIZE);
292
293   /* The device UUID uniquely identifies the given device within the machine. */
294   _mesa_sha1_init(&sha1_ctx);
295   _mesa_sha1_update(&sha1_ctx, &pdev->desc.vendor_id, sizeof(pdev->desc.vendor_id));
296   _mesa_sha1_update(&sha1_ctx, &pdev->desc.device_id, sizeof(pdev->desc.device_id));
297   _mesa_sha1_update(&sha1_ctx, &pdev->desc.subsys_id, sizeof(pdev->desc.subsys_id));
298   _mesa_sha1_update(&sha1_ctx, &pdev->desc.revision, sizeof(pdev->desc.revision));
299   _mesa_sha1_final(&sha1_ctx, sha1);
300   memcpy(pdev->device_uuid, sha1, VK_UUID_SIZE);
301}
302
303const struct vk_pipeline_cache_object_ops *const dzn_pipeline_cache_import_ops[] = {
304   &dzn_cached_blob_ops,
305   NULL,
306};
307
308static VkResult
309dzn_physical_device_create(struct dzn_instance *instance,
310                           IUnknown *adapter,
311                           const struct dzn_physical_device_desc *desc)
312{
313   struct dzn_physical_device *pdev =
314      vk_zalloc(&instance->vk.alloc, sizeof(*pdev), 8,
315                VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
316
317   if (!pdev)
318      return vk_error(instance, VK_ERROR_OUT_OF_HOST_MEMORY);
319
320   struct vk_physical_device_dispatch_table dispatch_table;
321   vk_physical_device_dispatch_table_from_entrypoints(&dispatch_table,
322                                                      &dzn_physical_device_entrypoints,
323                                                      true);
324   vk_physical_device_dispatch_table_from_entrypoints(&dispatch_table,
325                                                      &wsi_physical_device_entrypoints,
326                                                      false);
327
328   VkResult result =
329      vk_physical_device_init(&pdev->vk, &instance->vk,
330                              NULL, /* We set up extensions later */
331                              &dispatch_table);
332   if (result != VK_SUCCESS) {
333      vk_free(&instance->vk.alloc, pdev);
334      return result;
335   }
336
337   mtx_init(&pdev->dev_lock, mtx_plain);
338   pdev->desc = *desc;
339   pdev->adapter = adapter;
340   IUnknown_AddRef(adapter);
341   list_addtail(&pdev->link, &instance->physical_devices);
342
343   vk_warn_non_conformant_implementation("dzn");
344
345   uint32_t num_sync_types = 0;
346   pdev->sync_types[num_sync_types++] = &dzn_sync_type;
347   pdev->sync_types[num_sync_types++] = &instance->sync_binary_type.sync;
348   pdev->sync_types[num_sync_types++] = &vk_sync_dummy_type;
349   pdev->sync_types[num_sync_types] = NULL;
350   assert(num_sync_types <= MAX_SYNC_TYPES);
351   pdev->vk.supported_sync_types = pdev->sync_types;
352
353   pdev->vk.pipeline_cache_import_ops = dzn_pipeline_cache_import_ops;
354
355   /* TODO: something something queue families */
356
357   result = dzn_wsi_init(pdev);
358   if (result != VK_SUCCESS) {
359      dzn_physical_device_destroy(pdev);
360      return result;
361   }
362
363   dzn_physical_device_get_extensions(pdev);
364
365   return VK_SUCCESS;
366}
367
368static void
369dzn_physical_device_cache_caps(struct dzn_physical_device *pdev)
370{
371   D3D_FEATURE_LEVEL checklist[] = {
372      D3D_FEATURE_LEVEL_11_0,
373      D3D_FEATURE_LEVEL_11_1,
374      D3D_FEATURE_LEVEL_12_0,
375      D3D_FEATURE_LEVEL_12_1,
376      D3D_FEATURE_LEVEL_12_2,
377   };
378
379   D3D12_FEATURE_DATA_FEATURE_LEVELS levels = {
380      .NumFeatureLevels = ARRAY_SIZE(checklist),
381      .pFeatureLevelsRequested = checklist,
382   };
383
384   ID3D12Device1_CheckFeatureSupport(pdev->dev, D3D12_FEATURE_FEATURE_LEVELS, &levels, sizeof(levels));
385   pdev->feature_level = levels.MaxSupportedFeatureLevel;
386
387   ID3D12Device1_CheckFeatureSupport(pdev->dev, D3D12_FEATURE_ARCHITECTURE1, &pdev->architecture, sizeof(pdev->architecture));
388   ID3D12Device1_CheckFeatureSupport(pdev->dev, D3D12_FEATURE_D3D12_OPTIONS, &pdev->options, sizeof(pdev->options));
389   ID3D12Device1_CheckFeatureSupport(pdev->dev, D3D12_FEATURE_D3D12_OPTIONS2, &pdev->options2, sizeof(pdev->options2));
390   ID3D12Device1_CheckFeatureSupport(pdev->dev, D3D12_FEATURE_D3D12_OPTIONS3, &pdev->options3, sizeof(pdev->options3));
391
392   pdev->queue_families[pdev->queue_family_count++] = (struct dzn_queue_family) {
393      .props = {
394         .queueFlags = VK_QUEUE_GRAPHICS_BIT |
395                       VK_QUEUE_COMPUTE_BIT |
396                       VK_QUEUE_TRANSFER_BIT,
397         .queueCount = 1,
398         .timestampValidBits = 64,
399         .minImageTransferGranularity = { 0, 0, 0 },
400      },
401      .desc = {
402         .Type = D3D12_COMMAND_LIST_TYPE_DIRECT,
403      },
404   };
405
406   pdev->queue_families[pdev->queue_family_count++] = (struct dzn_queue_family) {
407      .props = {
408         .queueFlags = VK_QUEUE_COMPUTE_BIT |
409                       VK_QUEUE_TRANSFER_BIT,
410         .queueCount = 8,
411         .timestampValidBits = 64,
412         .minImageTransferGranularity = { 0, 0, 0 },
413      },
414      .desc = {
415         .Type = D3D12_COMMAND_LIST_TYPE_COMPUTE,
416      },
417   };
418
419   pdev->queue_families[pdev->queue_family_count++] = (struct dzn_queue_family) {
420      .props = {
421         .queueFlags = VK_QUEUE_TRANSFER_BIT,
422         .queueCount = 1,
423         .timestampValidBits = 0,
424         .minImageTransferGranularity = { 0, 0, 0 },
425      },
426      .desc = {
427         .Type = D3D12_COMMAND_LIST_TYPE_COPY,
428      },
429   };
430
431   assert(pdev->queue_family_count <= ARRAY_SIZE(pdev->queue_families));
432
433   D3D12_COMMAND_QUEUE_DESC queue_desc = {
434      .Type = D3D12_COMMAND_LIST_TYPE_DIRECT,
435      .Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL,
436      .Flags = D3D12_COMMAND_QUEUE_FLAG_NONE,
437      .NodeMask = 0,
438   };
439
440   ID3D12CommandQueue *cmdqueue;
441   ID3D12Device1_CreateCommandQueue(pdev->dev, &queue_desc,
442                                    &IID_ID3D12CommandQueue,
443                                    (void **)&cmdqueue);
444
445   uint64_t ts_freq;
446   ID3D12CommandQueue_GetTimestampFrequency(cmdqueue, &ts_freq);
447   pdev->timestamp_period = 1000000000.0f / ts_freq;
448   ID3D12CommandQueue_Release(cmdqueue);
449}
450
451static void
452dzn_physical_device_init_memory(struct dzn_physical_device *pdev)
453{
454   VkPhysicalDeviceMemoryProperties *mem = &pdev->memory;
455
456   mem->memoryHeapCount = 1;
457   mem->memoryHeaps[0] = (VkMemoryHeap) {
458      .size = pdev->desc.shared_system_memory,
459      .flags = 0,
460   };
461
462   mem->memoryTypes[mem->memoryTypeCount++] = (VkMemoryType) {
463      .propertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
464                       VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
465      .heapIndex = 0,
466   };
467   mem->memoryTypes[mem->memoryTypeCount++] = (VkMemoryType) {
468      .propertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
469                       VK_MEMORY_PROPERTY_HOST_CACHED_BIT |
470                       VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
471     .heapIndex = 0,
472   };
473
474   if (!pdev->architecture.UMA) {
475      mem->memoryHeaps[mem->memoryHeapCount++] = (VkMemoryHeap) {
476         .size = pdev->desc.dedicated_video_memory,
477         .flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT,
478      };
479      mem->memoryTypes[mem->memoryTypeCount++] = (VkMemoryType) {
480         .propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
481         .heapIndex = mem->memoryHeapCount - 1,
482      };
483   } else {
484      mem->memoryHeaps[0].flags |= VK_MEMORY_HEAP_DEVICE_LOCAL_BIT;
485      mem->memoryTypes[0].propertyFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
486      mem->memoryTypes[1].propertyFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
487   }
488
489   assert(mem->memoryTypeCount <= MAX_TIER2_MEMORY_TYPES);
490
491   if (pdev->options.ResourceHeapTier == D3D12_RESOURCE_HEAP_TIER_1) {
492      unsigned oldMemoryTypeCount = mem->memoryTypeCount;
493      VkMemoryType oldMemoryTypes[MAX_TIER2_MEMORY_TYPES];
494
495      memcpy(oldMemoryTypes, mem->memoryTypes, oldMemoryTypeCount * sizeof(VkMemoryType));
496
497      mem->memoryTypeCount = 0;
498      for (unsigned oldMemoryTypeIdx = 0; oldMemoryTypeIdx < oldMemoryTypeCount; ++oldMemoryTypeIdx) {
499         D3D12_HEAP_FLAGS flags[] = {
500            D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS,
501            D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES,
502            /* Note: Vulkan requires *all* images to come from the same memory type as long as
503             * the tiling property (and a few other misc properties) are the same. So, this
504             * non-RT/DS texture flag will only be used for TILING_LINEAR textures, which
505             * can't be render targets.
506             */
507            D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES
508         };
509         for (int i = 0; i < ARRAY_SIZE(flags); ++i) {
510            D3D12_HEAP_FLAGS flag = flags[i];
511            pdev->heap_flags_for_mem_type[mem->memoryTypeCount] = flag;
512            mem->memoryTypes[mem->memoryTypeCount] = oldMemoryTypes[oldMemoryTypeIdx];
513            mem->memoryTypeCount++;
514         }
515      }
516   }
517}
518
519static D3D12_HEAP_FLAGS
520dzn_physical_device_get_heap_flags_for_mem_type(const struct dzn_physical_device *pdev,
521                                                uint32_t mem_type)
522{
523   return pdev->heap_flags_for_mem_type[mem_type];
524}
525
526uint32_t
527dzn_physical_device_get_mem_type_mask_for_resource(const struct dzn_physical_device *pdev,
528                                                   const D3D12_RESOURCE_DESC *desc)
529{
530   if (pdev->options.ResourceHeapTier > D3D12_RESOURCE_HEAP_TIER_1)
531      return (1u << pdev->memory.memoryTypeCount) - 1;
532
533   D3D12_HEAP_FLAGS deny_flag;
534   if (desc->Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
535      deny_flag = D3D12_HEAP_FLAG_DENY_BUFFERS;
536   else if (desc->Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL))
537      deny_flag = D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES;
538   else
539      deny_flag = D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES;
540
541   uint32_t mask = 0;
542   for (unsigned i = 0; i < pdev->memory.memoryTypeCount; ++i) {
543      if ((pdev->heap_flags_for_mem_type[i] & deny_flag) == D3D12_HEAP_FLAG_NONE)
544         mask |= (1 << i);
545   }
546   return mask;
547}
548
549static uint32_t
550dzn_physical_device_get_max_mip_level(bool is_3d)
551{
552   return is_3d ? 11 : 14;
553}
554
555static uint32_t
556dzn_physical_device_get_max_extent(bool is_3d)
557{
558   uint32_t max_mip = dzn_physical_device_get_max_mip_level(is_3d);
559
560   return 1 << max_mip;
561}
562
563static uint32_t
564dzn_physical_device_get_max_array_layers()
565{
566   return dzn_physical_device_get_max_extent(false);
567}
568
569static ID3D12Device2 *
570dzn_physical_device_get_d3d12_dev(struct dzn_physical_device *pdev)
571{
572   struct dzn_instance *instance = container_of(pdev->vk.instance, struct dzn_instance, vk);
573
574   mtx_lock(&pdev->dev_lock);
575   if (!pdev->dev) {
576      pdev->dev = d3d12_create_device(pdev->adapter, !instance->dxil_validator);
577
578      dzn_physical_device_cache_caps(pdev);
579      dzn_physical_device_init_memory(pdev);
580      dzn_physical_device_init_uuids(pdev);
581   }
582   mtx_unlock(&pdev->dev_lock);
583
584   return pdev->dev;
585}
586
587D3D12_FEATURE_DATA_FORMAT_SUPPORT
588dzn_physical_device_get_format_support(struct dzn_physical_device *pdev,
589                                       VkFormat format)
590{
591   VkImageUsageFlags usage =
592      vk_format_is_depth_or_stencil(format) ?
593      VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT : 0;
594   VkImageAspectFlags aspects = 0;
595   VkFormat patched_format =
596      dzn_graphics_pipeline_patch_vi_format(format);
597
598   if (patched_format != format) {
599      D3D12_FEATURE_DATA_FORMAT_SUPPORT dfmt_info = {
600         .Format = dzn_buffer_get_dxgi_format(patched_format),
601         .Support1 = D3D12_FORMAT_SUPPORT1_IA_VERTEX_BUFFER,
602      };
603
604      return dfmt_info;
605   }
606
607   if (vk_format_has_depth(format))
608      aspects = VK_IMAGE_ASPECT_DEPTH_BIT;
609   if (vk_format_has_stencil(format))
610      aspects = VK_IMAGE_ASPECT_STENCIL_BIT;
611
612   D3D12_FEATURE_DATA_FORMAT_SUPPORT dfmt_info = {
613     .Format = dzn_image_get_dxgi_format(format, usage, aspects),
614   };
615
616   ID3D12Device2 *dev = dzn_physical_device_get_d3d12_dev(pdev);
617   ASSERTED HRESULT hres =
618      ID3D12Device1_CheckFeatureSupport(dev, D3D12_FEATURE_FORMAT_SUPPORT,
619                                        &dfmt_info, sizeof(dfmt_info));
620   assert(!FAILED(hres));
621
622   if (usage != VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
623      return dfmt_info;
624
625   /* Depth/stencil resources have different format when they're accessed
626    * as textures, query the capabilities for this format too.
627    */
628   dzn_foreach_aspect(aspect, aspects) {
629      D3D12_FEATURE_DATA_FORMAT_SUPPORT dfmt_info2 = {
630        .Format = dzn_image_get_dxgi_format(format, 0, aspect),
631      };
632
633      hres = ID3D12Device1_CheckFeatureSupport(dev, D3D12_FEATURE_FORMAT_SUPPORT,
634                                      &dfmt_info2, sizeof(dfmt_info2));
635      assert(!FAILED(hres));
636
637#define DS_SRV_FORMAT_SUPPORT1_MASK \
638        (D3D12_FORMAT_SUPPORT1_SHADER_LOAD | \
639         D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE | \
640         D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE_COMPARISON | \
641         D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE_MONO_TEXT | \
642         D3D12_FORMAT_SUPPORT1_MULTISAMPLE_RESOLVE | \
643         D3D12_FORMAT_SUPPORT1_MULTISAMPLE_LOAD | \
644         D3D12_FORMAT_SUPPORT1_SHADER_GATHER | \
645         D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW | \
646         D3D12_FORMAT_SUPPORT1_SHADER_GATHER_COMPARISON)
647
648      dfmt_info.Support1 |= dfmt_info2.Support1 & DS_SRV_FORMAT_SUPPORT1_MASK;
649      dfmt_info.Support2 |= dfmt_info2.Support2;
650   }
651
652   return dfmt_info;
653}
654
655static void
656dzn_physical_device_get_format_properties(struct dzn_physical_device *pdev,
657                                          VkFormat format,
658                                          VkFormatProperties2 *properties)
659{
660   D3D12_FEATURE_DATA_FORMAT_SUPPORT dfmt_info =
661      dzn_physical_device_get_format_support(pdev, format);
662   VkFormatProperties *base_props = &properties->formatProperties;
663
664   vk_foreach_struct(ext, properties->pNext) {
665      dzn_debug_ignored_stype(ext->sType);
666   }
667
668   if (dfmt_info.Format == DXGI_FORMAT_UNKNOWN) {
669      *base_props = (VkFormatProperties) { 0 };
670      return;
671   }
672
673   *base_props = (VkFormatProperties) {
674      .linearTilingFeatures = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT,
675      .optimalTilingFeatures = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT,
676      .bufferFeatures = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT,
677   };
678
679   if (dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_IA_VERTEX_BUFFER)
680      base_props->bufferFeatures |= VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT;
681
682#define TEX_FLAGS (D3D12_FORMAT_SUPPORT1_TEXTURE1D | \
683                   D3D12_FORMAT_SUPPORT1_TEXTURE2D | \
684                   D3D12_FORMAT_SUPPORT1_TEXTURE3D | \
685                   D3D12_FORMAT_SUPPORT1_TEXTURECUBE)
686   if (dfmt_info.Support1 & TEX_FLAGS) {
687      base_props->optimalTilingFeatures |=
688         VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_BLIT_SRC_BIT;
689   }
690
691   if (dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE) {
692      base_props->optimalTilingFeatures |=
693         VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
694   }
695
696   if ((dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_SHADER_LOAD) &&
697       (dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW)) {
698      base_props->optimalTilingFeatures |= VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT;
699      base_props->bufferFeatures |= VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT;
700   }
701
702#define ATOMIC_FLAGS (D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_ADD | \
703                      D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_BITWISE_OPS | \
704                      D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_COMPARE_STORE_OR_COMPARE_EXCHANGE | \
705                      D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_EXCHANGE | \
706                      D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_SIGNED_MIN_OR_MAX | \
707                      D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_UNSIGNED_MIN_OR_MAX)
708   if ((dfmt_info.Support2 & ATOMIC_FLAGS) == ATOMIC_FLAGS) {
709      base_props->optimalTilingFeatures |= VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT;
710      base_props->bufferFeatures |= VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT;
711   }
712
713   if (dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_SHADER_LOAD)
714      base_props->bufferFeatures |= VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT;
715
716   /* Color/depth/stencil attachment cap implies input attachement cap, and input
717    * attachment loads are lowered to texture loads in dozen, hence the requirement
718    * to have shader-load support.
719    */
720   if (dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_SHADER_LOAD) {
721      if (dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_RENDER_TARGET) {
722         base_props->optimalTilingFeatures |=
723            VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT;
724      }
725
726      if (dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_BLENDABLE)
727         base_props->optimalTilingFeatures |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT;
728
729      if (dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL) {
730         base_props->optimalTilingFeatures |=
731            VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT;
732      }
733   }
734
735   /* B4G4R4A4 support is required, but d3d12 doesn't support it. We map this
736    * format to R4G4B4A4 and adjust the SRV component-mapping to fake
737    * B4G4R4A4, but that forces us to limit the usage to sampling, which,
738    * luckily, is exactly what we need to support the required features.
739    */
740   if (format == VK_FORMAT_B4G4R4A4_UNORM_PACK16) {
741      VkFormatFeatureFlags bgra4_req_features =
742         VK_FORMAT_FEATURE_TRANSFER_SRC_BIT |
743         VK_FORMAT_FEATURE_TRANSFER_DST_BIT |
744         VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
745         VK_FORMAT_FEATURE_BLIT_SRC_BIT |
746         VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
747      base_props->optimalTilingFeatures &= bgra4_req_features;
748      base_props->bufferFeatures =
749         VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT;
750   }
751
752   /* depth/stencil format shouldn't advertise buffer features */
753   if (vk_format_is_depth_or_stencil(format))
754      base_props->bufferFeatures = 0;
755}
756
757static VkResult
758dzn_physical_device_get_image_format_properties(struct dzn_physical_device *pdev,
759                                                const VkPhysicalDeviceImageFormatInfo2 *info,
760                                                VkImageFormatProperties2 *properties)
761{
762   const VkPhysicalDeviceExternalImageFormatInfo *external_info = NULL;
763   VkExternalImageFormatProperties *external_props = NULL;
764
765   *properties = (VkImageFormatProperties2) {
766      .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
767   };
768
769   /* Extract input structs */
770   vk_foreach_struct_const(s, info->pNext) {
771      switch (s->sType) {
772      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO:
773         external_info = (const VkPhysicalDeviceExternalImageFormatInfo *)s;
774         break;
775      default:
776         dzn_debug_ignored_stype(s->sType);
777         break;
778      }
779   }
780
781   assert(info->tiling == VK_IMAGE_TILING_OPTIMAL || info->tiling == VK_IMAGE_TILING_LINEAR);
782
783   /* Extract output structs */
784   vk_foreach_struct(s, properties->pNext) {
785      switch (s->sType) {
786      case VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES:
787         external_props = (VkExternalImageFormatProperties *)s;
788         external_props->externalMemoryProperties = (VkExternalMemoryProperties) { 0 };
789         break;
790      default:
791         dzn_debug_ignored_stype(s->sType);
792         break;
793      }
794   }
795
796   /* TODO: support image import */
797   if (external_info && external_info->handleType != 0)
798      return VK_ERROR_FORMAT_NOT_SUPPORTED;
799
800   if (info->tiling != VK_IMAGE_TILING_OPTIMAL &&
801       (info->usage & ~(VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT)))
802      return VK_ERROR_FORMAT_NOT_SUPPORTED;
803
804   if (info->tiling != VK_IMAGE_TILING_OPTIMAL &&
805       vk_format_is_depth_or_stencil(info->format))
806      return VK_ERROR_FORMAT_NOT_SUPPORTED;
807
808   D3D12_FEATURE_DATA_FORMAT_SUPPORT dfmt_info =
809      dzn_physical_device_get_format_support(pdev, info->format);
810   if (dfmt_info.Format == DXGI_FORMAT_UNKNOWN)
811      return VK_ERROR_FORMAT_NOT_SUPPORTED;
812
813   bool is_bgra4 = info->format == VK_FORMAT_B4G4R4A4_UNORM_PACK16;
814   ID3D12Device2 *dev = dzn_physical_device_get_d3d12_dev(pdev);
815
816   if ((info->type == VK_IMAGE_TYPE_1D && !(dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURE1D)) ||
817       (info->type == VK_IMAGE_TYPE_2D && !(dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURE2D)) ||
818       (info->type == VK_IMAGE_TYPE_3D && !(dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURE3D)) ||
819       ((info->flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) &&
820        !(dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURECUBE)))
821      return VK_ERROR_FORMAT_NOT_SUPPORTED;
822
823   if ((info->usage & VK_IMAGE_USAGE_SAMPLED_BIT) &&
824       !(dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE))
825      return VK_ERROR_FORMAT_NOT_SUPPORTED;
826
827   if ((info->usage & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) &&
828       (!(dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_SHADER_LOAD) || is_bgra4))
829      return VK_ERROR_FORMAT_NOT_SUPPORTED;
830
831   if ((info->usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) &&
832       (!(dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_RENDER_TARGET) || is_bgra4))
833      return VK_ERROR_FORMAT_NOT_SUPPORTED;
834
835   if ((info->usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) &&
836       (!(dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL) || is_bgra4))
837      return VK_ERROR_FORMAT_NOT_SUPPORTED;
838
839   if ((info->usage & VK_IMAGE_USAGE_STORAGE_BIT) &&
840       (!(dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW) || is_bgra4))
841      return VK_ERROR_FORMAT_NOT_SUPPORTED;
842
843   if (info->type == VK_IMAGE_TYPE_3D && info->tiling != VK_IMAGE_TILING_OPTIMAL)
844      return VK_ERROR_FORMAT_NOT_SUPPORTED;
845
846   bool is_3d = info->type == VK_IMAGE_TYPE_3D;
847   uint32_t max_extent = dzn_physical_device_get_max_extent(is_3d);
848
849   if (info->tiling == VK_IMAGE_TILING_OPTIMAL &&
850       dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_MIP)
851      properties->imageFormatProperties.maxMipLevels = dzn_physical_device_get_max_mip_level(is_3d) + 1;
852   else
853      properties->imageFormatProperties.maxMipLevels = 1;
854
855   if (info->tiling == VK_IMAGE_TILING_OPTIMAL && info->type != VK_IMAGE_TYPE_3D)
856      properties->imageFormatProperties.maxArrayLayers = dzn_physical_device_get_max_array_layers();
857   else
858      properties->imageFormatProperties.maxArrayLayers = 1;
859
860   switch (info->type) {
861   case VK_IMAGE_TYPE_1D:
862      properties->imageFormatProperties.maxExtent.width = max_extent;
863      properties->imageFormatProperties.maxExtent.height = 1;
864      properties->imageFormatProperties.maxExtent.depth = 1;
865      break;
866   case VK_IMAGE_TYPE_2D:
867      properties->imageFormatProperties.maxExtent.width = max_extent;
868      properties->imageFormatProperties.maxExtent.height = max_extent;
869      properties->imageFormatProperties.maxExtent.depth = 1;
870      break;
871   case VK_IMAGE_TYPE_3D:
872      properties->imageFormatProperties.maxExtent.width = max_extent;
873      properties->imageFormatProperties.maxExtent.height = max_extent;
874      properties->imageFormatProperties.maxExtent.depth = max_extent;
875      break;
876   default:
877      unreachable("bad VkImageType");
878   }
879
880   /* From the Vulkan 1.0 spec, section 34.1.1. Supported Sample Counts:
881    *
882    * sampleCounts will be set to VK_SAMPLE_COUNT_1_BIT if at least one of the
883    * following conditions is true:
884    *
885    *   - tiling is VK_IMAGE_TILING_LINEAR
886    *   - type is not VK_IMAGE_TYPE_2D
887    *   - flags contains VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT
888    *   - neither the VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT flag nor the
889    *     VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT flag in
890    *     VkFormatProperties::optimalTilingFeatures returned by
891    *     vkGetPhysicalDeviceFormatProperties is set.
892    *
893    * D3D12 has a few more constraints:
894    *   - no UAVs on multisample resources
895    */
896   bool rt_or_ds_cap =
897      dfmt_info.Support1 &
898      (D3D12_FORMAT_SUPPORT1_RENDER_TARGET | D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL);
899
900   properties->imageFormatProperties.sampleCounts = VK_SAMPLE_COUNT_1_BIT;
901   if (info->tiling != VK_IMAGE_TILING_LINEAR &&
902       info->type == VK_IMAGE_TYPE_2D &&
903       !(info->flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) &&
904       rt_or_ds_cap && !is_bgra4 &&
905       !(info->usage & VK_IMAGE_USAGE_STORAGE_BIT)) {
906      for (uint32_t s = VK_SAMPLE_COUNT_2_BIT; s < VK_SAMPLE_COUNT_64_BIT; s <<= 1) {
907         D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS ms_info = {
908            .Format = dfmt_info.Format,
909            .SampleCount = s,
910         };
911
912         HRESULT hres =
913            ID3D12Device1_CheckFeatureSupport(dev, D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,
914                                     &ms_info, sizeof(ms_info));
915         if (!FAILED(hres) && ms_info.NumQualityLevels > 0)
916            properties->imageFormatProperties.sampleCounts |= s;
917      }
918   }
919
920   /* TODO: set correct value here */
921   properties->imageFormatProperties.maxResourceSize = UINT32_MAX;
922
923   return VK_SUCCESS;
924}
925
926VKAPI_ATTR void VKAPI_CALL
927dzn_GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice,
928                                       VkFormat format,
929                                       VkFormatProperties2 *pFormatProperties)
930{
931   VK_FROM_HANDLE(dzn_physical_device, pdev, physicalDevice);
932
933   dzn_physical_device_get_format_properties(pdev, format, pFormatProperties);
934}
935
936VKAPI_ATTR VkResult VKAPI_CALL
937dzn_GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice,
938                                            const VkPhysicalDeviceImageFormatInfo2 *info,
939                                            VkImageFormatProperties2 *props)
940{
941   VK_FROM_HANDLE(dzn_physical_device, pdev, physicalDevice);
942
943   return dzn_physical_device_get_image_format_properties(pdev, info, props);
944}
945
946VKAPI_ATTR VkResult VKAPI_CALL
947dzn_GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice,
948                                           VkFormat format,
949                                           VkImageType type,
950                                           VkImageTiling tiling,
951                                           VkImageUsageFlags usage,
952                                           VkImageCreateFlags createFlags,
953                                           VkImageFormatProperties *pImageFormatProperties)
954{
955   const VkPhysicalDeviceImageFormatInfo2 info = {
956      .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
957      .format = format,
958      .type = type,
959      .tiling = tiling,
960      .usage = usage,
961      .flags = createFlags,
962   };
963
964   VkImageFormatProperties2 props = { 0 };
965
966   VkResult result =
967      dzn_GetPhysicalDeviceImageFormatProperties2(physicalDevice, &info, &props);
968   *pImageFormatProperties = props.imageFormatProperties;
969
970   return result;
971}
972
973VKAPI_ATTR void VKAPI_CALL
974dzn_GetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice,
975                                                 VkFormat format,
976                                                 VkImageType type,
977                                                 VkSampleCountFlagBits samples,
978                                                 VkImageUsageFlags usage,
979                                                 VkImageTiling tiling,
980                                                 uint32_t *pPropertyCount,
981                                                 VkSparseImageFormatProperties *pProperties)
982{
983   *pPropertyCount = 0;
984}
985
986VKAPI_ATTR void VKAPI_CALL
987dzn_GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice,
988                                                  const VkPhysicalDeviceSparseImageFormatInfo2 *pFormatInfo,
989                                                  uint32_t *pPropertyCount,
990                                                  VkSparseImageFormatProperties2 *pProperties)
991{
992   *pPropertyCount = 0;
993}
994
995VKAPI_ATTR void VKAPI_CALL
996dzn_GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice,
997                                              const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo,
998                                              VkExternalBufferProperties *pExternalBufferProperties)
999{
1000   pExternalBufferProperties->externalMemoryProperties =
1001      (VkExternalMemoryProperties) {
1002         .compatibleHandleTypes = (VkExternalMemoryHandleTypeFlags)pExternalBufferInfo->handleType,
1003      };
1004}
1005
1006VkResult
1007dzn_instance_add_physical_device(struct dzn_instance *instance,
1008                                 IUnknown *adapter,
1009                                 const struct dzn_physical_device_desc *desc)
1010{
1011   if ((instance->debug_flags & DZN_DEBUG_WARP) &&
1012       !desc->is_warp)
1013      return VK_SUCCESS;
1014
1015   return dzn_physical_device_create(instance, adapter, desc);
1016}
1017
1018VKAPI_ATTR VkResult VKAPI_CALL
1019dzn_EnumeratePhysicalDevices(VkInstance inst,
1020                             uint32_t *pPhysicalDeviceCount,
1021                             VkPhysicalDevice *pPhysicalDevices)
1022{
1023   VK_FROM_HANDLE(dzn_instance, instance, inst);
1024
1025   if (!instance->physical_devices_enumerated) {
1026      VkResult result = dzn_enumerate_physical_devices_dxcore(instance);
1027#ifdef _WIN32
1028      if (result != VK_SUCCESS)
1029         result = dzn_enumerate_physical_devices_dxgi(instance);
1030#endif
1031      if (result != VK_SUCCESS)
1032         return result;
1033   }
1034
1035   VK_OUTARRAY_MAKE_TYPED(VkPhysicalDevice, out, pPhysicalDevices,
1036                          pPhysicalDeviceCount);
1037
1038   list_for_each_entry(struct dzn_physical_device, pdev, &instance->physical_devices, link) {
1039      vk_outarray_append_typed(VkPhysicalDevice, &out, i)
1040         *i = dzn_physical_device_to_handle(pdev);
1041   }
1042
1043   instance->physical_devices_enumerated = true;
1044   return vk_outarray_status(&out);
1045}
1046
1047VKAPI_ATTR VkResult VKAPI_CALL
1048dzn_EnumerateInstanceVersion(uint32_t *pApiVersion)
1049{
1050   *pApiVersion = DZN_API_VERSION;
1051   return VK_SUCCESS;
1052}
1053
1054static bool
1055dzn_physical_device_supports_compressed_format(struct dzn_physical_device *pdev,
1056                                               const VkFormat *formats,
1057                                               uint32_t format_count)
1058{
1059#define REQUIRED_COMPRESSED_CAPS \
1060        (VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | \
1061         VK_FORMAT_FEATURE_BLIT_SRC_BIT | \
1062         VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)
1063   for (uint32_t i = 0; i < format_count; i++) {
1064      VkFormatProperties2 props = { 0 };
1065      dzn_physical_device_get_format_properties(pdev, formats[i], &props);
1066      if ((props.formatProperties.optimalTilingFeatures & REQUIRED_COMPRESSED_CAPS) != REQUIRED_COMPRESSED_CAPS)
1067         return false;
1068   }
1069
1070   return true;
1071}
1072
1073static bool
1074dzn_physical_device_supports_bc(struct dzn_physical_device *pdev)
1075{
1076   static const VkFormat formats[] = {
1077      VK_FORMAT_BC1_RGB_UNORM_BLOCK,
1078      VK_FORMAT_BC1_RGB_SRGB_BLOCK,
1079      VK_FORMAT_BC1_RGBA_UNORM_BLOCK,
1080      VK_FORMAT_BC1_RGBA_SRGB_BLOCK,
1081      VK_FORMAT_BC2_UNORM_BLOCK,
1082      VK_FORMAT_BC2_SRGB_BLOCK,
1083      VK_FORMAT_BC3_UNORM_BLOCK,
1084      VK_FORMAT_BC3_SRGB_BLOCK,
1085      VK_FORMAT_BC4_UNORM_BLOCK,
1086      VK_FORMAT_BC4_SNORM_BLOCK,
1087      VK_FORMAT_BC5_UNORM_BLOCK,
1088      VK_FORMAT_BC5_SNORM_BLOCK,
1089      VK_FORMAT_BC6H_UFLOAT_BLOCK,
1090      VK_FORMAT_BC6H_SFLOAT_BLOCK,
1091      VK_FORMAT_BC7_UNORM_BLOCK,
1092      VK_FORMAT_BC7_SRGB_BLOCK,
1093   };
1094
1095   return dzn_physical_device_supports_compressed_format(pdev, formats, ARRAY_SIZE(formats));
1096}
1097
1098static bool
1099dzn_physical_device_supports_depth_bounds(struct dzn_physical_device *pdev)
1100{
1101   dzn_physical_device_get_d3d12_dev(pdev);
1102
1103   return pdev->options2.DepthBoundsTestSupported;
1104}
1105
1106VKAPI_ATTR void VKAPI_CALL
1107dzn_GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice,
1108                               VkPhysicalDeviceFeatures2 *pFeatures)
1109{
1110   VK_FROM_HANDLE(dzn_physical_device, pdev, physicalDevice);
1111
1112   pFeatures->features = (VkPhysicalDeviceFeatures) {
1113      .robustBufferAccess = true, /* This feature is mandatory */
1114      .fullDrawIndexUint32 = false,
1115      .imageCubeArray = true,
1116      .independentBlend = false,
1117      .geometryShader = true,
1118      .tessellationShader = false,
1119      .sampleRateShading = true,
1120      .dualSrcBlend = false,
1121      .logicOp = false,
1122      .multiDrawIndirect = true,
1123      .drawIndirectFirstInstance = true,
1124      .depthClamp = true,
1125      .depthBiasClamp = true,
1126      .fillModeNonSolid = false,
1127      .depthBounds = dzn_physical_device_supports_depth_bounds(pdev),
1128      .wideLines = false,
1129      .largePoints = false,
1130      .alphaToOne = false,
1131      .multiViewport = false,
1132      .samplerAnisotropy = true,
1133      .textureCompressionETC2 = false,
1134      .textureCompressionASTC_LDR = false,
1135      .textureCompressionBC = dzn_physical_device_supports_bc(pdev),
1136      .occlusionQueryPrecise = true,
1137      .pipelineStatisticsQuery = true,
1138      .vertexPipelineStoresAndAtomics = true,
1139      .fragmentStoresAndAtomics = true,
1140      .shaderTessellationAndGeometryPointSize = false,
1141      .shaderImageGatherExtended = true,
1142      .shaderStorageImageExtendedFormats = false,
1143      .shaderStorageImageMultisample = false,
1144      .shaderStorageImageReadWithoutFormat = false,
1145      .shaderStorageImageWriteWithoutFormat = false,
1146      .shaderUniformBufferArrayDynamicIndexing = true,
1147      .shaderSampledImageArrayDynamicIndexing = true,
1148      .shaderStorageBufferArrayDynamicIndexing = true,
1149      .shaderStorageImageArrayDynamicIndexing = true,
1150      .shaderClipDistance = true,
1151      .shaderCullDistance = true,
1152      .shaderFloat64 = false,
1153      .shaderInt64 = false,
1154      .shaderInt16 = false,
1155      .shaderResourceResidency = false,
1156      .shaderResourceMinLod = false,
1157      .sparseBinding = false,
1158      .sparseResidencyBuffer = false,
1159      .sparseResidencyImage2D = false,
1160      .sparseResidencyImage3D = false,
1161      .sparseResidency2Samples = false,
1162      .sparseResidency4Samples = false,
1163      .sparseResidency8Samples = false,
1164      .sparseResidency16Samples = false,
1165      .sparseResidencyAliased = false,
1166      .variableMultisampleRate = false,
1167      .inheritedQueries = false,
1168   };
1169
1170   VkPhysicalDeviceVulkan11Features core_1_1 = {
1171      .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES,
1172      .storageBuffer16BitAccess           = false,
1173      .uniformAndStorageBuffer16BitAccess = false,
1174      .storagePushConstant16              = false,
1175      .storageInputOutput16               = false,
1176      .multiview                          = false,
1177      .multiviewGeometryShader            = false,
1178      .multiviewTessellationShader        = false,
1179      .variablePointersStorageBuffer      = true,
1180      .variablePointers                   = true,
1181      .protectedMemory                    = false,
1182      .samplerYcbcrConversion             = false,
1183      .shaderDrawParameters               = true,
1184   };
1185
1186   const VkPhysicalDeviceVulkan12Features core_1_2 = {
1187      .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
1188      .samplerMirrorClampToEdge           = false,
1189      .drawIndirectCount                  = false,
1190      .storageBuffer8BitAccess            = false,
1191      .uniformAndStorageBuffer8BitAccess  = false,
1192      .storagePushConstant8               = false,
1193      .shaderBufferInt64Atomics           = false,
1194      .shaderSharedInt64Atomics           = false,
1195      .shaderFloat16                      = false,
1196      .shaderInt8                         = false,
1197
1198      .descriptorIndexing                                   = false,
1199      .shaderInputAttachmentArrayDynamicIndexing            = true,
1200      .shaderUniformTexelBufferArrayDynamicIndexing         = true,
1201      .shaderStorageTexelBufferArrayDynamicIndexing         = true,
1202      .shaderUniformBufferArrayNonUniformIndexing           = false,
1203      .shaderSampledImageArrayNonUniformIndexing            = false,
1204      .shaderStorageBufferArrayNonUniformIndexing           = false,
1205      .shaderStorageImageArrayNonUniformIndexing            = false,
1206      .shaderInputAttachmentArrayNonUniformIndexing         = false,
1207      .shaderUniformTexelBufferArrayNonUniformIndexing      = false,
1208      .shaderStorageTexelBufferArrayNonUniformIndexing      = false,
1209      .descriptorBindingUniformBufferUpdateAfterBind        = false,
1210      .descriptorBindingSampledImageUpdateAfterBind         = false,
1211      .descriptorBindingStorageImageUpdateAfterBind         = false,
1212      .descriptorBindingStorageBufferUpdateAfterBind        = false,
1213      .descriptorBindingUniformTexelBufferUpdateAfterBind   = false,
1214      .descriptorBindingStorageTexelBufferUpdateAfterBind   = false,
1215      .descriptorBindingUpdateUnusedWhilePending            = false,
1216      .descriptorBindingPartiallyBound                      = false,
1217      .descriptorBindingVariableDescriptorCount             = false,
1218      .runtimeDescriptorArray                               = false,
1219
1220      .samplerFilterMinmax                = false,
1221      .scalarBlockLayout                  = false,
1222      .imagelessFramebuffer               = false,
1223      .uniformBufferStandardLayout        = false,
1224      .shaderSubgroupExtendedTypes        = false,
1225      .separateDepthStencilLayouts        = false,
1226      .hostQueryReset                     = false,
1227      .timelineSemaphore                  = false,
1228      .bufferDeviceAddress                = false,
1229      .bufferDeviceAddressCaptureReplay   = false,
1230      .bufferDeviceAddressMultiDevice     = false,
1231      .vulkanMemoryModel                  = false,
1232      .vulkanMemoryModelDeviceScope       = false,
1233      .vulkanMemoryModelAvailabilityVisibilityChains = false,
1234      .shaderOutputViewportIndex          = false,
1235      .shaderOutputLayer                  = false,
1236      .subgroupBroadcastDynamicId         = false,
1237   };
1238
1239   const VkPhysicalDeviceVulkan13Features core_1_3 = {
1240      .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES,
1241      .robustImageAccess                  = false,
1242      .inlineUniformBlock                 = false,
1243      .descriptorBindingInlineUniformBlockUpdateAfterBind = false,
1244      .pipelineCreationCacheControl       = false,
1245      .privateData                        = true,
1246      .shaderDemoteToHelperInvocation     = false,
1247      .shaderTerminateInvocation          = false,
1248      .subgroupSizeControl                = false,
1249      .computeFullSubgroups               = false,
1250      .synchronization2                   = true,
1251      .textureCompressionASTC_HDR         = false,
1252      .shaderZeroInitializeWorkgroupMemory = false,
1253      .dynamicRendering                   = false,
1254      .shaderIntegerDotProduct            = false,
1255      .maintenance4                       = false,
1256   };
1257
1258   vk_foreach_struct(ext, pFeatures->pNext) {
1259      if (vk_get_physical_device_core_1_1_feature_ext(ext, &core_1_1) ||
1260          vk_get_physical_device_core_1_2_feature_ext(ext, &core_1_2) ||
1261          vk_get_physical_device_core_1_3_feature_ext(ext, &core_1_3))
1262         continue;
1263
1264      switch (ext->sType) {
1265      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT: {
1266         VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT *features =
1267            (VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT *)ext;
1268         features->vertexAttributeInstanceRateDivisor = true;
1269         features->vertexAttributeInstanceRateZeroDivisor = true;
1270         break;
1271      }
1272      default:
1273         dzn_debug_ignored_stype(ext->sType);
1274         break;
1275      }
1276   }
1277}
1278
1279
1280VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
1281dzn_GetInstanceProcAddr(VkInstance _instance,
1282                        const char *pName)
1283{
1284   VK_FROM_HANDLE(dzn_instance, instance, _instance);
1285   return vk_instance_get_proc_addr(&instance->vk,
1286                                    &dzn_instance_entrypoints,
1287                                    pName);
1288}
1289
1290/* Windows will use a dll definition file to avoid build errors. */
1291#ifdef _WIN32
1292#undef PUBLIC
1293#define PUBLIC
1294#endif
1295
1296/* With version 1+ of the loader interface the ICD should expose
1297 * vk_icdGetInstanceProcAddr to work around certain LD_PRELOAD issues seen in apps.
1298 */
1299PUBLIC VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
1300vk_icdGetInstanceProcAddr(VkInstance instance,
1301                          const char *pName);
1302
1303PUBLIC VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
1304vk_icdGetInstanceProcAddr(VkInstance instance,
1305                          const char *pName)
1306{
1307   return dzn_GetInstanceProcAddr(instance, pName);
1308}
1309
1310/* With version 4+ of the loader interface the ICD should expose
1311 * vk_icdGetPhysicalDeviceProcAddr()
1312 */
1313PUBLIC VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
1314vk_icdGetPhysicalDeviceProcAddr(VkInstance  _instance,
1315                                const char *pName);
1316
1317VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
1318vk_icdGetPhysicalDeviceProcAddr(VkInstance  _instance,
1319                                const char *pName)
1320{
1321   VK_FROM_HANDLE(dzn_instance, instance, _instance);
1322   return vk_instance_get_physical_device_proc_addr(&instance->vk, pName);
1323}
1324
1325/* vk_icd.h does not declare this function, so we declare it here to
1326 * suppress Wmissing-prototypes.
1327 */
1328PUBLIC VKAPI_ATTR VkResult VKAPI_CALL
1329vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t *pSupportedVersion);
1330
1331PUBLIC VKAPI_ATTR VkResult VKAPI_CALL
1332vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t *pSupportedVersion)
1333{
1334   /* For the full details on loader interface versioning, see
1335    * <https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/blob/master/loader/LoaderAndLayerInterface.md>.
1336    * What follows is a condensed summary, to help you navigate the large and
1337    * confusing official doc.
1338    *
1339    *   - Loader interface v0 is incompatible with later versions. We don't
1340    *     support it.
1341    *
1342    *   - In loader interface v1:
1343    *       - The first ICD entrypoint called by the loader is
1344    *         vk_icdGetInstanceProcAddr(). The ICD must statically expose this
1345    *         entrypoint.
1346    *       - The ICD must statically expose no other Vulkan symbol unless it is
1347    *         linked with -Bsymbolic.
1348    *       - Each dispatchable Vulkan handle created by the ICD must be
1349    *         a pointer to a struct whose first member is VK_LOADER_DATA. The
1350    *         ICD must initialize VK_LOADER_DATA.loadMagic to ICD_LOADER_MAGIC.
1351    *       - The loader implements vkCreate{PLATFORM}SurfaceKHR() and
1352    *         vkDestroySurfaceKHR(). The ICD must be capable of working with
1353    *         such loader-managed surfaces.
1354    *
1355    *    - Loader interface v2 differs from v1 in:
1356    *       - The first ICD entrypoint called by the loader is
1357    *         vk_icdNegotiateLoaderICDInterfaceVersion(). The ICD must
1358    *         statically expose this entrypoint.
1359    *
1360    *    - Loader interface v3 differs from v2 in:
1361    *        - The ICD must implement vkCreate{PLATFORM}SurfaceKHR(),
1362    *          vkDestroySurfaceKHR(), and other API which uses VKSurfaceKHR,
1363    *          because the loader no longer does so.
1364    *
1365    *    - Loader interface v4 differs from v3 in:
1366    *        - The ICD must implement vk_icdGetPhysicalDeviceProcAddr().
1367    *
1368    *    - Loader interface v5 differs from v4 in:
1369    *        - The ICD must support Vulkan API version 1.1 and must not return
1370    *          VK_ERROR_INCOMPATIBLE_DRIVER from vkCreateInstance() unless a
1371    *          Vulkan Loader with interface v4 or smaller is being used and the
1372    *          application provides an API version that is greater than 1.0.
1373    */
1374   *pSupportedVersion = MIN2(*pSupportedVersion, 5u);
1375   return VK_SUCCESS;
1376}
1377
1378VKAPI_ATTR void VKAPI_CALL
1379dzn_GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice,
1380                                 VkPhysicalDeviceProperties2 *pProperties)
1381{
1382   VK_FROM_HANDLE(dzn_physical_device, pdevice, physicalDevice);
1383
1384   (void)dzn_physical_device_get_d3d12_dev(pdevice);
1385
1386   /* minimum from the spec */
1387   const VkSampleCountFlags supported_sample_counts =
1388      VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_2_BIT | VK_SAMPLE_COUNT_4_BIT |
1389      VK_SAMPLE_COUNT_8_BIT | VK_SAMPLE_COUNT_16_BIT;
1390
1391   /* FIXME: this is mostly bunk for now */
1392   VkPhysicalDeviceLimits limits = {
1393
1394      /* TODO: support older feature levels */
1395      .maxImageDimension1D                      = (1 << 14),
1396      .maxImageDimension2D                      = (1 << 14),
1397      .maxImageDimension3D                      = (1 << 11),
1398      .maxImageDimensionCube                    = (1 << 14),
1399      .maxImageArrayLayers                      = (1 << 11),
1400
1401      /* from here on, we simply use the minimum values from the spec for now */
1402      .maxTexelBufferElements                   = 65536,
1403      .maxUniformBufferRange                    = 16384,
1404      .maxStorageBufferRange                    = (1ul << 27),
1405      .maxPushConstantsSize                     = 128,
1406      .maxMemoryAllocationCount                 = 4096,
1407      .maxSamplerAllocationCount                = 4000,
1408      .bufferImageGranularity                   = 131072,
1409      .sparseAddressSpaceSize                   = 0,
1410      .maxBoundDescriptorSets                   = MAX_SETS,
1411      .maxPerStageDescriptorSamplers            =
1412         pdevice->options.ResourceHeapTier == D3D12_RESOURCE_HEAP_TIER_1 ?
1413         16u : MAX_DESCS_PER_SAMPLER_HEAP,
1414      .maxPerStageDescriptorUniformBuffers      =
1415         pdevice->options.ResourceHeapTier <= D3D12_RESOURCE_HEAP_TIER_2 ?
1416         14u : MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
1417      .maxPerStageDescriptorStorageBuffers      =
1418         pdevice->options.ResourceHeapTier <= D3D12_RESOURCE_HEAP_TIER_2 ?
1419         64u : MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
1420      .maxPerStageDescriptorSampledImages       =
1421         pdevice->options.ResourceHeapTier == D3D12_RESOURCE_HEAP_TIER_1 ?
1422         128u : MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
1423      .maxPerStageDescriptorStorageImages       =
1424         pdevice->options.ResourceHeapTier <= D3D12_RESOURCE_HEAP_TIER_2 ?
1425         64u : MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
1426      .maxPerStageDescriptorInputAttachments    =
1427         pdevice->options.ResourceHeapTier == D3D12_RESOURCE_HEAP_TIER_1 ?
1428         128u : MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
1429      .maxPerStageResources                     = MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
1430      .maxDescriptorSetSamplers                 = MAX_DESCS_PER_SAMPLER_HEAP,
1431      .maxDescriptorSetUniformBuffers           = MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
1432      .maxDescriptorSetUniformBuffersDynamic    = MAX_DYNAMIC_UNIFORM_BUFFERS,
1433      .maxDescriptorSetStorageBuffers           = MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
1434      .maxDescriptorSetStorageBuffersDynamic    = MAX_DYNAMIC_STORAGE_BUFFERS,
1435      .maxDescriptorSetSampledImages            = MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
1436      .maxDescriptorSetStorageImages            = MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
1437      .maxDescriptorSetInputAttachments         = MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
1438      .maxVertexInputAttributes                 = MIN2(D3D12_STANDARD_VERTEX_ELEMENT_COUNT, MAX_VERTEX_GENERIC_ATTRIBS),
1439      .maxVertexInputBindings                   = MAX_VBS,
1440      .maxVertexInputAttributeOffset            = 2047,
1441      .maxVertexInputBindingStride              = 2048,
1442      .maxVertexOutputComponents                = 64,
1443      .maxTessellationGenerationLevel           = 0,
1444      .maxTessellationPatchSize                 = 0,
1445      .maxTessellationControlPerVertexInputComponents = 0,
1446      .maxTessellationControlPerVertexOutputComponents = 0,
1447      .maxTessellationControlPerPatchOutputComponents = 0,
1448      .maxTessellationControlTotalOutputComponents = 0,
1449      .maxTessellationEvaluationInputComponents = 0,
1450      .maxTessellationEvaluationOutputComponents = 0,
1451      .maxGeometryShaderInvocations             = 0,
1452      .maxGeometryInputComponents               = 0,
1453      .maxGeometryOutputComponents              = 0,
1454      .maxGeometryOutputVertices                = 0,
1455      .maxGeometryTotalOutputComponents         = 0,
1456      .maxFragmentInputComponents               = 64,
1457      .maxFragmentOutputAttachments             = 4,
1458      .maxFragmentDualSrcAttachments            = 0,
1459      .maxFragmentCombinedOutputResources       = 4,
1460      .maxComputeSharedMemorySize               = 16384,
1461      .maxComputeWorkGroupCount                 = { 65535, 65535, 65535 },
1462      .maxComputeWorkGroupInvocations           = 128,
1463      .maxComputeWorkGroupSize                  = { 128, 128, 64 },
1464      .subPixelPrecisionBits                    = 4,
1465      .subTexelPrecisionBits                    = 4,
1466      .mipmapPrecisionBits                      = 4,
1467      .maxDrawIndexedIndexValue                 = 0x00ffffff,
1468      .maxDrawIndirectCount                     = UINT32_MAX,
1469      .maxSamplerLodBias                        = 2.0f,
1470      .maxSamplerAnisotropy                     = 1.0f,
1471      .maxViewports                             = 1,
1472      .maxViewportDimensions                    = { 4096, 4096 },
1473      .viewportBoundsRange                      = { -8192, 8191 },
1474      .viewportSubPixelBits                     = 0,
1475      .minMemoryMapAlignment                    = 64,
1476      .minTexelBufferOffsetAlignment            = 256,
1477      .minUniformBufferOffsetAlignment          = 256,
1478      .minStorageBufferOffsetAlignment          = 256,
1479      .minTexelOffset                           = -8,
1480      .maxTexelOffset                           = 7,
1481      .minTexelGatherOffset                     = 0,
1482      .maxTexelGatherOffset                     = 0,
1483      .minInterpolationOffset                   = -0.5f,
1484      .maxInterpolationOffset                   = 0.5f,
1485      .subPixelInterpolationOffsetBits          = 4,
1486      .maxFramebufferWidth                      = 4096,
1487      .maxFramebufferHeight                     = 4096,
1488      .maxFramebufferLayers                     = 256,
1489      .framebufferColorSampleCounts             = supported_sample_counts,
1490      .framebufferDepthSampleCounts             = supported_sample_counts,
1491      .framebufferStencilSampleCounts           = supported_sample_counts,
1492      .framebufferNoAttachmentsSampleCounts     = supported_sample_counts,
1493      .maxColorAttachments                      = MAX_RTS,
1494      .sampledImageColorSampleCounts            = supported_sample_counts,
1495      .sampledImageIntegerSampleCounts          = VK_SAMPLE_COUNT_1_BIT,
1496      .sampledImageDepthSampleCounts            = supported_sample_counts,
1497      .sampledImageStencilSampleCounts          = supported_sample_counts,
1498      .storageImageSampleCounts                 = VK_SAMPLE_COUNT_1_BIT,
1499      .maxSampleMaskWords                       = 1,
1500      .timestampComputeAndGraphics              = true,
1501      .timestampPeriod                          = pdevice->timestamp_period,
1502      .maxClipDistances                         = 8,
1503      .maxCullDistances                         = 8,
1504      .maxCombinedClipAndCullDistances          = 8,
1505      .discreteQueuePriorities                  = 2,
1506      .pointSizeRange                           = { 1.0f, 1.0f },
1507      .lineWidthRange                           = { 1.0f, 1.0f },
1508      .pointSizeGranularity                     = 0.0f,
1509      .lineWidthGranularity                     = 0.0f,
1510      .strictLines                              = 0,
1511      .standardSampleLocations                  = false,
1512      .optimalBufferCopyOffsetAlignment         = D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT,
1513      .optimalBufferCopyRowPitchAlignment       = D3D12_TEXTURE_DATA_PITCH_ALIGNMENT,
1514      .nonCoherentAtomSize                      = 256,
1515   };
1516
1517   VkPhysicalDeviceType devtype = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
1518   if (pdevice->desc.is_warp)
1519      devtype = VK_PHYSICAL_DEVICE_TYPE_CPU;
1520   else if (false) { // TODO: detect discreete GPUs
1521      /* This is a tad tricky to get right, because we need to have the
1522       * actual ID3D12Device before we can query the
1523       * D3D12_FEATURE_DATA_ARCHITECTURE structure... So for now, let's
1524       * just pretend everything is integrated, because... well, that's
1525       * what I have at hand right now ;)
1526       */
1527      devtype = VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU;
1528   }
1529
1530   pProperties->properties = (VkPhysicalDeviceProperties) {
1531      .apiVersion = DZN_API_VERSION,
1532      .driverVersion = vk_get_driver_version(),
1533
1534      .vendorID = pdevice->desc.vendor_id,
1535      .deviceID = pdevice->desc.device_id,
1536      .deviceType = devtype,
1537
1538      .limits = limits,
1539      .sparseProperties = { 0 },
1540   };
1541
1542   snprintf(pProperties->properties.deviceName,
1543            sizeof(pProperties->properties.deviceName),
1544            "Microsoft Direct3D12 (%s)", pdevice->desc.description);
1545   memcpy(pProperties->properties.pipelineCacheUUID,
1546          pdevice->pipeline_cache_uuid, VK_UUID_SIZE);
1547
1548   VkPhysicalDeviceVulkan11Properties core_1_1 = {
1549      .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES,
1550      .deviceLUIDValid                       = true,
1551      .pointClippingBehavior                 = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES,
1552      .maxMultiviewViewCount                 = 0,
1553      .maxMultiviewInstanceIndex             = 0,
1554      .protectedNoFault                      = false,
1555      /* Vulkan 1.1 wants this value to be at least 1024. Let's stick to this
1556       * minimum requirement for now, and hope the total number of samplers
1557       * across all descriptor sets doesn't exceed 2048, otherwise we'd exceed
1558       * the maximum number of samplers per heap. For any descriptor set
1559       * containing more than 1024 descriptors,
1560       * vkGetDescriptorSetLayoutSupport() can be called to determine if the
1561       * layout is within D3D12 descriptor heap bounds.
1562       */
1563      .maxPerSetDescriptors                  = 1024,
1564      /* According to the spec, the maximum D3D12 resource size is
1565       * min(max(128MB, 0.25f * (amount of dedicated VRAM)), 2GB),
1566       * but the limit actually depends on the max(system_ram, VRAM) not
1567       * just the VRAM.
1568       */
1569      .maxMemoryAllocationSize               =
1570         CLAMP(MAX2(pdevice->desc.dedicated_video_memory,
1571                    pdevice->desc.dedicated_system_memory +
1572                    pdevice->desc.shared_system_memory) / 4,
1573               128ull * 1024 * 1024, 2ull * 1024 * 1024 * 1024),
1574   };
1575   memcpy(core_1_1.driverUUID, pdevice->driver_uuid, VK_UUID_SIZE);
1576   memcpy(core_1_1.deviceUUID, pdevice->device_uuid, VK_UUID_SIZE);
1577   memcpy(core_1_1.deviceLUID, &pdevice->desc.adapter_luid, VK_LUID_SIZE);
1578
1579   STATIC_ASSERT(sizeof(pdevice->desc.adapter_luid) == sizeof(core_1_1.deviceLUID));
1580
1581   VkPhysicalDeviceVulkan12Properties core_1_2 = {
1582      .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES,
1583      .driverID = VK_DRIVER_ID_MESA_DOZEN,
1584      .conformanceVersion = (VkConformanceVersion){
1585         .major = 0,
1586         .minor = 0,
1587         .subminor = 0,
1588         .patch = 0,
1589      },
1590      .denormBehaviorIndependence = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL,
1591      .roundingModeIndependence = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL,
1592      .shaderSignedZeroInfNanPreserveFloat16 = false,
1593      .shaderSignedZeroInfNanPreserveFloat32 = false,
1594      .shaderSignedZeroInfNanPreserveFloat64 = false,
1595      .shaderDenormPreserveFloat16 = true,
1596      .shaderDenormPreserveFloat32 = false,
1597      .shaderDenormPreserveFloat64 = true,
1598      .shaderDenormFlushToZeroFloat16 = false,
1599      .shaderDenormFlushToZeroFloat32 = true,
1600      .shaderDenormFlushToZeroFloat64 = false,
1601      .shaderRoundingModeRTEFloat16 = true,
1602      .shaderRoundingModeRTEFloat32 = true,
1603      .shaderRoundingModeRTEFloat64 = true,
1604      .shaderRoundingModeRTZFloat16 = false,
1605      .shaderRoundingModeRTZFloat32 = false,
1606      .shaderRoundingModeRTZFloat64 = false,
1607      .shaderUniformBufferArrayNonUniformIndexingNative = true,
1608      .shaderSampledImageArrayNonUniformIndexingNative = true,
1609      .shaderStorageBufferArrayNonUniformIndexingNative = true,
1610      .shaderStorageImageArrayNonUniformIndexingNative = true,
1611      .shaderInputAttachmentArrayNonUniformIndexingNative = true,
1612      .robustBufferAccessUpdateAfterBind = true,
1613      .quadDivergentImplicitLod = false,
1614      .maxPerStageDescriptorUpdateAfterBindSamplers = 0,
1615      .maxPerStageDescriptorUpdateAfterBindUniformBuffers = 0,
1616      .maxPerStageDescriptorUpdateAfterBindStorageBuffers = 0,
1617      .maxPerStageDescriptorUpdateAfterBindSampledImages = 0,
1618      .maxPerStageDescriptorUpdateAfterBindStorageImages = 0,
1619      .maxPerStageDescriptorUpdateAfterBindInputAttachments = 0,
1620      .maxPerStageUpdateAfterBindResources = 0,
1621      .maxDescriptorSetUpdateAfterBindSamplers = 0,
1622      .maxDescriptorSetUpdateAfterBindUniformBuffers = 0,
1623      .maxDescriptorSetUpdateAfterBindUniformBuffersDynamic = 0,
1624      .maxDescriptorSetUpdateAfterBindStorageBuffers = 0,
1625      .maxDescriptorSetUpdateAfterBindStorageBuffersDynamic = 0,
1626      .maxDescriptorSetUpdateAfterBindSampledImages = 0,
1627      .maxDescriptorSetUpdateAfterBindStorageImages = 0,
1628      .maxDescriptorSetUpdateAfterBindInputAttachments = 0,
1629
1630      /* FIXME: add support for VK_RESOLVE_MODE_SAMPLE_ZERO_BIT,
1631       * which is required by the VK 1.2 spec.
1632       */
1633      .supportedDepthResolveModes = VK_RESOLVE_MODE_AVERAGE_BIT,
1634
1635      .supportedStencilResolveModes = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT,
1636      .independentResolveNone = false,
1637      .independentResolve = false,
1638      .filterMinmaxSingleComponentFormats = false,
1639      .filterMinmaxImageComponentMapping = false,
1640      .maxTimelineSemaphoreValueDifference = UINT64_MAX,
1641      .framebufferIntegerColorSampleCounts = VK_SAMPLE_COUNT_1_BIT,
1642   };
1643
1644   snprintf(core_1_2.driverName, VK_MAX_DRIVER_NAME_SIZE, "Dozen");
1645   snprintf(core_1_2.driverInfo, VK_MAX_DRIVER_INFO_SIZE, "Mesa " PACKAGE_VERSION MESA_GIT_SHA1);
1646
1647   const VkPhysicalDeviceVulkan13Properties core_1_3 = {
1648      .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES,
1649   };
1650
1651   vk_foreach_struct(ext, pProperties->pNext) {
1652      if (vk_get_physical_device_core_1_1_property_ext(ext, &core_1_1) ||
1653          vk_get_physical_device_core_1_2_property_ext(ext, &core_1_2) ||
1654          vk_get_physical_device_core_1_3_property_ext(ext, &core_1_3))
1655         continue;
1656
1657      switch (ext->sType) {
1658      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: {
1659         VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *attr_div =
1660            (VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *)ext;
1661         attr_div->maxVertexAttribDivisor = UINT32_MAX;
1662         break;
1663      }
1664      default:
1665         dzn_debug_ignored_stype(ext->sType);
1666         break;
1667      }
1668   }
1669}
1670
1671VKAPI_ATTR void VKAPI_CALL
1672dzn_GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice,
1673                                            uint32_t *pQueueFamilyPropertyCount,
1674                                            VkQueueFamilyProperties2 *pQueueFamilyProperties)
1675{
1676   VK_FROM_HANDLE(dzn_physical_device, pdev, physicalDevice);
1677   VK_OUTARRAY_MAKE_TYPED(VkQueueFamilyProperties2, out,
1678                          pQueueFamilyProperties, pQueueFamilyPropertyCount);
1679
1680   (void)dzn_physical_device_get_d3d12_dev(pdev);
1681
1682   for (uint32_t i = 0; i < pdev->queue_family_count; i++) {
1683      vk_outarray_append_typed(VkQueueFamilyProperties2, &out, p) {
1684         p->queueFamilyProperties = pdev->queue_families[i].props;
1685
1686         vk_foreach_struct(ext, pQueueFamilyProperties->pNext) {
1687            dzn_debug_ignored_stype(ext->sType);
1688         }
1689      }
1690   }
1691}
1692
1693VKAPI_ATTR void VKAPI_CALL
1694dzn_GetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice,
1695                                      VkPhysicalDeviceMemoryProperties *pMemoryProperties)
1696{
1697   VK_FROM_HANDLE(dzn_physical_device, pdev, physicalDevice);
1698
1699   // Ensure memory caps are up-to-date
1700   (void)dzn_physical_device_get_d3d12_dev(pdev);
1701   *pMemoryProperties = pdev->memory;
1702}
1703
1704VKAPI_ATTR void VKAPI_CALL
1705dzn_GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice,
1706                                       VkPhysicalDeviceMemoryProperties2 *pMemoryProperties)
1707{
1708   dzn_GetPhysicalDeviceMemoryProperties(physicalDevice,
1709                                         &pMemoryProperties->memoryProperties);
1710
1711   vk_foreach_struct(ext, pMemoryProperties->pNext) {
1712      dzn_debug_ignored_stype(ext->sType);
1713   }
1714}
1715
1716VKAPI_ATTR VkResult VKAPI_CALL
1717dzn_EnumerateInstanceLayerProperties(uint32_t *pPropertyCount,
1718                                     VkLayerProperties *pProperties)
1719{
1720   if (pProperties == NULL) {
1721      *pPropertyCount = 0;
1722      return VK_SUCCESS;
1723   }
1724
1725   return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);
1726}
1727
1728static VkResult
1729dzn_queue_sync_wait(struct dzn_queue *queue, const struct vk_sync_wait *wait)
1730{
1731   if (wait->sync->type == &vk_sync_dummy_type)
1732      return VK_SUCCESS;
1733
1734   struct dzn_device *device = container_of(queue->vk.base.device, struct dzn_device, vk);
1735   assert(wait->sync->type == &dzn_sync_type);
1736   struct dzn_sync *sync = container_of(wait->sync, struct dzn_sync, vk);
1737   uint64_t value =
1738      (sync->vk.flags & VK_SYNC_IS_TIMELINE) ? wait->wait_value : 1;
1739
1740   assert(sync->fence != NULL);
1741
1742   if (value > 0 && FAILED(ID3D12CommandQueue_Wait(queue->cmdqueue, sync->fence, value)))
1743      return vk_error(device, VK_ERROR_UNKNOWN);
1744
1745   return VK_SUCCESS;
1746}
1747
1748static VkResult
1749dzn_queue_sync_signal(struct dzn_queue *queue, const struct vk_sync_signal *signal)
1750{
1751   if (signal->sync->type == &vk_sync_dummy_type)
1752      return VK_SUCCESS;
1753
1754   struct dzn_device *device = container_of(queue->vk.base.device, struct dzn_device, vk);
1755   assert(signal->sync->type == &dzn_sync_type);
1756   struct dzn_sync *sync = container_of(signal->sync, struct dzn_sync, vk);
1757   uint64_t value =
1758      (sync->vk.flags & VK_SYNC_IS_TIMELINE) ? signal->signal_value : 1;
1759   assert(value > 0);
1760
1761   assert(sync->fence != NULL);
1762
1763   if (FAILED(ID3D12CommandQueue_Signal(queue->cmdqueue, sync->fence, value)))
1764      return vk_error(device, VK_ERROR_UNKNOWN);
1765
1766   return VK_SUCCESS;
1767}
1768
1769static VkResult
1770dzn_queue_submit(struct vk_queue *q,
1771                 struct vk_queue_submit *info)
1772{
1773   struct dzn_queue *queue = container_of(q, struct dzn_queue, vk);
1774   struct dzn_device *device = container_of(q->base.device, struct dzn_device, vk);
1775   VkResult result = VK_SUCCESS;
1776
1777   for (uint32_t i = 0; i < info->wait_count; i++) {
1778      result = dzn_queue_sync_wait(queue, &info->waits[i]);
1779      if (result != VK_SUCCESS)
1780         return result;
1781   }
1782
1783   for (uint32_t i = 0; i < info->command_buffer_count; i++) {
1784      struct dzn_cmd_buffer *cmd_buffer =
1785         container_of(info->command_buffers[i], struct dzn_cmd_buffer, vk);
1786
1787      ID3D12CommandList *cmdlists[] = { (ID3D12CommandList *)cmd_buffer->cmdlist };
1788
1789      util_dynarray_foreach(&cmd_buffer->events.wait, struct dzn_event *, evt) {
1790         if (FAILED(ID3D12CommandQueue_Wait(queue->cmdqueue, (*evt)->fence, 1)))
1791            return vk_error(device, VK_ERROR_UNKNOWN);
1792      }
1793
1794      util_dynarray_foreach(&cmd_buffer->queries.wait, struct dzn_cmd_buffer_query_range, range) {
1795         mtx_lock(&range->qpool->queries_lock);
1796         for (uint32_t q = range->start; q < range->start + range->count; q++) {
1797            struct dzn_query *query = &range->qpool->queries[q];
1798
1799            if (query->fence &&
1800                FAILED(ID3D12CommandQueue_Wait(queue->cmdqueue, query->fence, query->fence_value)))
1801               return vk_error(device, VK_ERROR_UNKNOWN);
1802         }
1803         mtx_unlock(&range->qpool->queries_lock);
1804      }
1805
1806      util_dynarray_foreach(&cmd_buffer->queries.reset, struct dzn_cmd_buffer_query_range, range) {
1807         mtx_lock(&range->qpool->queries_lock);
1808         for (uint32_t q = range->start; q < range->start + range->count; q++) {
1809            struct dzn_query *query = &range->qpool->queries[q];
1810            if (query->fence) {
1811               ID3D12Fence_Release(query->fence);
1812               query->fence = NULL;
1813            }
1814            query->fence_value = 0;
1815         }
1816         mtx_unlock(&range->qpool->queries_lock);
1817      }
1818
1819      ID3D12CommandQueue_ExecuteCommandLists(queue->cmdqueue, 1, cmdlists);
1820
1821      util_dynarray_foreach(&cmd_buffer->events.signal, struct dzn_cmd_event_signal, evt) {
1822         if (FAILED(ID3D12CommandQueue_Signal(queue->cmdqueue, evt->event->fence, evt->value ? 1 : 0)))
1823            return vk_error(device, VK_ERROR_UNKNOWN);
1824      }
1825
1826      util_dynarray_foreach(&cmd_buffer->queries.signal, struct dzn_cmd_buffer_query_range, range) {
1827         mtx_lock(&range->qpool->queries_lock);
1828         for (uint32_t q = range->start; q < range->start + range->count; q++) {
1829            struct dzn_query *query = &range->qpool->queries[q];
1830            query->fence_value = queue->fence_point + 1;
1831            query->fence = queue->fence;
1832            ID3D12Fence_AddRef(query->fence);
1833         }
1834         mtx_unlock(&range->qpool->queries_lock);
1835      }
1836   }
1837
1838   for (uint32_t i = 0; i < info->signal_count; i++) {
1839      result = dzn_queue_sync_signal(queue, &info->signals[i]);
1840      if (result != VK_SUCCESS)
1841         return vk_error(device, VK_ERROR_UNKNOWN);
1842   }
1843
1844   if (FAILED(ID3D12CommandQueue_Signal(queue->cmdqueue, queue->fence, ++queue->fence_point)))
1845      return vk_error(device, VK_ERROR_UNKNOWN);
1846
1847   return VK_SUCCESS;
1848}
1849
1850static void
1851dzn_queue_finish(struct dzn_queue *queue)
1852{
1853   if (queue->cmdqueue)
1854      ID3D12CommandQueue_Release(queue->cmdqueue);
1855
1856   if (queue->fence)
1857      ID3D12Fence_Release(queue->fence);
1858
1859   vk_queue_finish(&queue->vk);
1860}
1861
1862static VkResult
1863dzn_queue_init(struct dzn_queue *queue,
1864               struct dzn_device *device,
1865               const VkDeviceQueueCreateInfo *pCreateInfo,
1866               uint32_t index_in_family)
1867{
1868   struct dzn_physical_device *pdev = container_of(device->vk.physical, struct dzn_physical_device, vk);
1869
1870   VkResult result = vk_queue_init(&queue->vk, &device->vk, pCreateInfo, index_in_family);
1871   if (result != VK_SUCCESS)
1872      return result;
1873
1874   queue->vk.driver_submit = dzn_queue_submit;
1875
1876   assert(pCreateInfo->queueFamilyIndex < pdev->queue_family_count);
1877
1878   D3D12_COMMAND_QUEUE_DESC queue_desc =
1879      pdev->queue_families[pCreateInfo->queueFamilyIndex].desc;
1880
1881   float priority_in = pCreateInfo->pQueuePriorities[index_in_family];
1882   queue_desc.Priority =
1883      priority_in > 0.5f ? D3D12_COMMAND_QUEUE_PRIORITY_HIGH : D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
1884   queue_desc.NodeMask = 0;
1885
1886   if (FAILED(ID3D12Device1_CreateCommandQueue(device->dev, &queue_desc,
1887                                               &IID_ID3D12CommandQueue,
1888                                               (void **)&queue->cmdqueue))) {
1889      dzn_queue_finish(queue);
1890      return vk_error(device->vk.physical->instance, VK_ERROR_INITIALIZATION_FAILED);
1891   }
1892
1893   if (FAILED(ID3D12Device1_CreateFence(device->dev, 0, D3D12_FENCE_FLAG_NONE,
1894                                        &IID_ID3D12Fence,
1895                                        (void **)&queue->fence))) {
1896      dzn_queue_finish(queue);
1897      return vk_error(device->vk.physical->instance, VK_ERROR_INITIALIZATION_FAILED);
1898   }
1899
1900   return VK_SUCCESS;
1901}
1902
1903static VkResult
1904check_physical_device_features(VkPhysicalDevice physicalDevice,
1905                               const VkPhysicalDeviceFeatures *features)
1906{
1907   VK_FROM_HANDLE(dzn_physical_device, pdev, physicalDevice);
1908
1909   VkPhysicalDeviceFeatures supported_features;
1910
1911   pdev->vk.dispatch_table.GetPhysicalDeviceFeatures(physicalDevice, &supported_features);
1912
1913   VkBool32 *supported_feature = (VkBool32 *)&supported_features;
1914   VkBool32 *enabled_feature = (VkBool32 *)features;
1915   unsigned num_features = sizeof(VkPhysicalDeviceFeatures) / sizeof(VkBool32);
1916   for (uint32_t i = 0; i < num_features; i++) {
1917      if (enabled_feature[i] && !supported_feature[i])
1918         return VK_ERROR_FEATURE_NOT_PRESENT;
1919   }
1920
1921   return VK_SUCCESS;
1922}
1923
1924static VkResult
1925dzn_device_create_sync_for_memory(struct vk_device *device,
1926                                  VkDeviceMemory memory,
1927                                  bool signal_memory,
1928                                  struct vk_sync **sync_out)
1929{
1930   return vk_sync_create(device, &vk_sync_dummy_type,
1931                         0, 1, sync_out);
1932}
1933
1934static VkResult
1935dzn_device_query_init(struct dzn_device *device)
1936{
1937   /* FIXME: create the resource in the default heap */
1938   D3D12_HEAP_PROPERTIES hprops = dzn_ID3D12Device2_GetCustomHeapProperties(device->dev, 0, D3D12_HEAP_TYPE_UPLOAD);
1939   D3D12_RESOURCE_DESC rdesc = {
1940      .Dimension = D3D12_RESOURCE_DIMENSION_BUFFER,
1941      .Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT,
1942      .Width = DZN_QUERY_REFS_RES_SIZE,
1943      .Height = 1,
1944      .DepthOrArraySize = 1,
1945      .MipLevels = 1,
1946      .Format = DXGI_FORMAT_UNKNOWN,
1947      .SampleDesc = { .Count = 1, .Quality = 0 },
1948      .Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
1949      .Flags = D3D12_RESOURCE_FLAG_NONE,
1950   };
1951
1952   if (FAILED(ID3D12Device1_CreateCommittedResource(device->dev, &hprops,
1953                                                   D3D12_HEAP_FLAG_NONE,
1954                                                   &rdesc,
1955                                                   D3D12_RESOURCE_STATE_GENERIC_READ,
1956                                                   NULL,
1957                                                   &IID_ID3D12Resource,
1958                                                   (void **)&device->queries.refs)))
1959      return vk_error(device->vk.physical, VK_ERROR_OUT_OF_DEVICE_MEMORY);
1960
1961   uint8_t *queries_ref;
1962   if (FAILED(ID3D12Resource_Map(device->queries.refs, 0, NULL, (void **)&queries_ref)))
1963      return vk_error(device->vk.physical, VK_ERROR_OUT_OF_HOST_MEMORY);
1964
1965   memset(queries_ref + DZN_QUERY_REFS_ALL_ONES_OFFSET, 0xff, DZN_QUERY_REFS_SECTION_SIZE);
1966   memset(queries_ref + DZN_QUERY_REFS_ALL_ZEROS_OFFSET, 0x0, DZN_QUERY_REFS_SECTION_SIZE);
1967   ID3D12Resource_Unmap(device->queries.refs, 0, NULL);
1968
1969   return VK_SUCCESS;
1970}
1971
1972static void
1973dzn_device_query_finish(struct dzn_device *device)
1974{
1975   if (device->queries.refs)
1976      ID3D12Resource_Release(device->queries.refs);
1977}
1978
1979static void
1980dzn_device_destroy(struct dzn_device *device, const VkAllocationCallbacks *pAllocator)
1981{
1982   if (!device)
1983      return;
1984
1985   struct dzn_instance *instance =
1986      container_of(device->vk.physical->instance, struct dzn_instance, vk);
1987
1988   vk_foreach_queue_safe(q, &device->vk) {
1989      struct dzn_queue *queue = container_of(q, struct dzn_queue, vk);
1990
1991      dzn_queue_finish(queue);
1992   }
1993
1994   dzn_device_query_finish(device);
1995   dzn_meta_finish(device);
1996
1997   if (device->dev)
1998      ID3D12Device1_Release(device->dev);
1999
2000   vk_device_finish(&device->vk);
2001   vk_free2(&instance->vk.alloc, pAllocator, device);
2002}
2003
2004static VkResult
2005dzn_device_check_status(struct vk_device *dev)
2006{
2007   struct dzn_device *device = container_of(dev, struct dzn_device, vk);
2008
2009   if (FAILED(ID3D12Device_GetDeviceRemovedReason(device->dev)))
2010      return vk_device_set_lost(&device->vk, "D3D12 device removed");
2011
2012   return VK_SUCCESS;
2013}
2014
2015static VkResult
2016dzn_device_create(struct dzn_physical_device *pdev,
2017                  const VkDeviceCreateInfo *pCreateInfo,
2018                  const VkAllocationCallbacks *pAllocator,
2019                  VkDevice *out)
2020{
2021   struct dzn_instance *instance = container_of(pdev->vk.instance, struct dzn_instance, vk);
2022
2023   uint32_t queue_count = 0;
2024   for (uint32_t qf = 0; qf < pCreateInfo->queueCreateInfoCount; qf++) {
2025      const VkDeviceQueueCreateInfo *qinfo = &pCreateInfo->pQueueCreateInfos[qf];
2026      queue_count += qinfo->queueCount;
2027   }
2028
2029   VK_MULTIALLOC(ma);
2030   VK_MULTIALLOC_DECL(&ma, struct dzn_device, device, 1);
2031   VK_MULTIALLOC_DECL(&ma, struct dzn_queue, queues, queue_count);
2032
2033   if (!vk_multialloc_zalloc2(&ma, &instance->vk.alloc, pAllocator,
2034                              VK_SYSTEM_ALLOCATION_SCOPE_DEVICE))
2035      return vk_error(pdev, VK_ERROR_OUT_OF_HOST_MEMORY);
2036
2037   struct vk_device_dispatch_table dispatch_table;
2038
2039   /* For secondary command buffer support, overwrite any command entrypoints
2040    * in the main device-level dispatch table with
2041    * vk_cmd_enqueue_unless_primary_Cmd*.
2042    */
2043   vk_device_dispatch_table_from_entrypoints(&dispatch_table,
2044      &vk_cmd_enqueue_unless_primary_device_entrypoints, true);
2045   vk_device_dispatch_table_from_entrypoints(&dispatch_table,
2046      &dzn_device_entrypoints, false);
2047   vk_device_dispatch_table_from_entrypoints(&dispatch_table,
2048      &wsi_device_entrypoints, false);
2049
2050   /* Populate our primary cmd_dispatch table. */
2051   vk_device_dispatch_table_from_entrypoints(&device->cmd_dispatch,
2052      &dzn_device_entrypoints, true);
2053   vk_device_dispatch_table_from_entrypoints(&device->cmd_dispatch,
2054                                             &vk_common_device_entrypoints,
2055                                             false);
2056
2057   VkResult result =
2058      vk_device_init(&device->vk, &pdev->vk, &dispatch_table, pCreateInfo, pAllocator);
2059   if (result != VK_SUCCESS) {
2060      vk_free2(&device->vk.alloc, pAllocator, device);
2061      return result;
2062   }
2063
2064   /* Must be done after vk_device_init() because this function memset(0) the
2065    * whole struct.
2066    */
2067   device->vk.command_dispatch_table = &device->cmd_dispatch;
2068   device->vk.create_sync_for_memory = dzn_device_create_sync_for_memory;
2069   device->vk.check_status = dzn_device_check_status;
2070
2071   device->dev = dzn_physical_device_get_d3d12_dev(pdev);
2072   if (!device->dev) {
2073      dzn_device_destroy(device, pAllocator);
2074      return vk_error(pdev, VK_ERROR_INITIALIZATION_FAILED);
2075   }
2076
2077   ID3D12Device1_AddRef(device->dev);
2078
2079   ID3D12InfoQueue *info_queue;
2080   if (SUCCEEDED(ID3D12Device1_QueryInterface(device->dev,
2081                                              &IID_ID3D12InfoQueue,
2082                                              (void **)&info_queue))) {
2083      D3D12_MESSAGE_SEVERITY severities[] = {
2084         D3D12_MESSAGE_SEVERITY_INFO,
2085         D3D12_MESSAGE_SEVERITY_WARNING,
2086      };
2087
2088      D3D12_MESSAGE_ID msg_ids[] = {
2089         D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE,
2090      };
2091
2092      D3D12_INFO_QUEUE_FILTER NewFilter = { 0 };
2093      NewFilter.DenyList.NumSeverities = ARRAY_SIZE(severities);
2094      NewFilter.DenyList.pSeverityList = severities;
2095      NewFilter.DenyList.NumIDs = ARRAY_SIZE(msg_ids);
2096      NewFilter.DenyList.pIDList = msg_ids;
2097
2098      ID3D12InfoQueue_PushStorageFilter(info_queue, &NewFilter);
2099   }
2100
2101   result = dzn_meta_init(device);
2102   if (result != VK_SUCCESS) {
2103      dzn_device_destroy(device, pAllocator);
2104      return result;
2105   }
2106
2107   result = dzn_device_query_init(device);
2108   if (result != VK_SUCCESS) {
2109      dzn_device_destroy(device, pAllocator);
2110      return result;
2111   }
2112
2113   uint32_t qindex = 0;
2114   for (uint32_t qf = 0; qf < pCreateInfo->queueCreateInfoCount; qf++) {
2115      const VkDeviceQueueCreateInfo *qinfo = &pCreateInfo->pQueueCreateInfos[qf];
2116
2117      for (uint32_t q = 0; q < qinfo->queueCount; q++) {
2118         result =
2119            dzn_queue_init(&queues[qindex++], device, qinfo, q);
2120         if (result != VK_SUCCESS) {
2121            dzn_device_destroy(device, pAllocator);
2122            return result;
2123         }
2124      }
2125   }
2126
2127   assert(queue_count == qindex);
2128   *out = dzn_device_to_handle(device);
2129   return VK_SUCCESS;
2130}
2131
2132ID3D12RootSignature *
2133dzn_device_create_root_sig(struct dzn_device *device,
2134                           const D3D12_VERSIONED_ROOT_SIGNATURE_DESC *desc)
2135{
2136   struct dzn_instance *instance =
2137      container_of(device->vk.physical->instance, struct dzn_instance, vk);
2138   ID3D12RootSignature *root_sig = NULL;
2139   ID3DBlob *sig = NULL, *error = NULL;
2140
2141   if (FAILED(instance->d3d12.serialize_root_sig(desc,
2142                                                 &sig, &error))) {
2143      if (instance->debug_flags & DZN_DEBUG_SIG) {
2144         const char *error_msg = (const char *)ID3D10Blob_GetBufferPointer(error);
2145         fprintf(stderr,
2146                 "== SERIALIZE ROOT SIG ERROR =============================================\n"
2147                 "%s\n"
2148                 "== END ==========================================================\n",
2149                 error_msg);
2150      }
2151
2152      goto out;
2153   }
2154
2155   ID3D12Device1_CreateRootSignature(device->dev, 0,
2156                                     ID3D10Blob_GetBufferPointer(sig),
2157                                     ID3D10Blob_GetBufferSize(sig),
2158                                     &IID_ID3D12RootSignature,
2159                                     (void **)&root_sig);
2160
2161out:
2162   if (error)
2163      ID3D10Blob_Release(error);
2164
2165   if (sig)
2166      ID3D10Blob_Release(sig);
2167
2168   return root_sig;
2169}
2170
2171VKAPI_ATTR VkResult VKAPI_CALL
2172dzn_CreateDevice(VkPhysicalDevice physicalDevice,
2173                 const VkDeviceCreateInfo *pCreateInfo,
2174                 const VkAllocationCallbacks *pAllocator,
2175                 VkDevice *pDevice)
2176{
2177   VK_FROM_HANDLE(dzn_physical_device, physical_device, physicalDevice);
2178   VkResult result;
2179
2180   assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO);
2181
2182   /* Check enabled features */
2183   if (pCreateInfo->pEnabledFeatures) {
2184      result = check_physical_device_features(physicalDevice,
2185                                              pCreateInfo->pEnabledFeatures);
2186      if (result != VK_SUCCESS)
2187         return vk_error(physical_device, result);
2188   }
2189
2190   /* Check requested queues and fail if we are requested to create any
2191    * queues with flags we don't support.
2192    */
2193   assert(pCreateInfo->queueCreateInfoCount > 0);
2194   for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++) {
2195      if (pCreateInfo->pQueueCreateInfos[i].flags != 0)
2196         return vk_error(physical_device, VK_ERROR_INITIALIZATION_FAILED);
2197   }
2198
2199   return dzn_device_create(physical_device, pCreateInfo, pAllocator, pDevice);
2200}
2201
2202VKAPI_ATTR void VKAPI_CALL
2203dzn_DestroyDevice(VkDevice dev,
2204                  const VkAllocationCallbacks *pAllocator)
2205{
2206   VK_FROM_HANDLE(dzn_device, device, dev);
2207
2208   device->vk.dispatch_table.DeviceWaitIdle(dev);
2209
2210   dzn_device_destroy(device, pAllocator);
2211}
2212
2213static void
2214dzn_device_memory_destroy(struct dzn_device_memory *mem,
2215                          const VkAllocationCallbacks *pAllocator)
2216{
2217   if (!mem)
2218      return;
2219
2220   struct dzn_device *device = container_of(mem->base.device, struct dzn_device, vk);
2221
2222   if (mem->map)
2223      ID3D12Resource_Unmap(mem->map_res, 0, NULL);
2224
2225   if (mem->map_res)
2226      ID3D12Resource_Release(mem->map_res);
2227
2228   if (mem->heap)
2229      ID3D12Heap_Release(mem->heap);
2230
2231   vk_object_base_finish(&mem->base);
2232   vk_free2(&device->vk.alloc, pAllocator, mem);
2233}
2234
2235static VkResult
2236dzn_device_memory_create(struct dzn_device *device,
2237                         const VkMemoryAllocateInfo *pAllocateInfo,
2238                         const VkAllocationCallbacks *pAllocator,
2239                         VkDeviceMemory *out)
2240{
2241   struct dzn_physical_device *pdevice =
2242      container_of(device->vk.physical, struct dzn_physical_device, vk);
2243
2244   struct dzn_device_memory *mem =
2245      vk_zalloc2(&device->vk.alloc, pAllocator, sizeof(*mem), 8,
2246                 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
2247   if (!mem)
2248      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
2249
2250   vk_object_base_init(&device->vk, &mem->base, VK_OBJECT_TYPE_DEVICE_MEMORY);
2251
2252   /* The Vulkan 1.0.33 spec says "allocationSize must be greater than 0". */
2253   assert(pAllocateInfo->allocationSize > 0);
2254
2255   mem->size = pAllocateInfo->allocationSize;
2256
2257   const struct dzn_buffer *buffer = NULL;
2258   const struct dzn_image *image = NULL;
2259
2260   vk_foreach_struct_const(ext, pAllocateInfo->pNext) {
2261      switch (ext->sType) {
2262      case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO: {
2263         UNUSED const VkExportMemoryAllocateInfo *exp =
2264            (const VkExportMemoryAllocateInfo *)ext;
2265
2266         // TODO: support export
2267         assert(exp->handleTypes == 0);
2268         break;
2269      }
2270      case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO: {
2271         const VkMemoryDedicatedAllocateInfo *dedicated =
2272           (const VkMemoryDedicatedAllocateInfo *)ext;
2273
2274         buffer = dzn_buffer_from_handle(dedicated->buffer);
2275         image = dzn_image_from_handle(dedicated->image);
2276         assert(!buffer || !image);
2277         break;
2278      }
2279      default:
2280         dzn_debug_ignored_stype(ext->sType);
2281         break;
2282      }
2283   }
2284
2285   const VkMemoryType *mem_type =
2286      &pdevice->memory.memoryTypes[pAllocateInfo->memoryTypeIndex];
2287
2288   D3D12_HEAP_DESC heap_desc = { 0 };
2289
2290   heap_desc.SizeInBytes = pAllocateInfo->allocationSize;
2291   if (buffer) {
2292      heap_desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
2293   } else if (image) {
2294      heap_desc.Alignment =
2295         image->vk.samples > 1 ?
2296         D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT :
2297         D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
2298   } else {
2299      heap_desc.Alignment =
2300         heap_desc.SizeInBytes >= D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT ?
2301         D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT :
2302         D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
2303   }
2304
2305   heap_desc.Flags =
2306      dzn_physical_device_get_heap_flags_for_mem_type(pdevice,
2307                                                      pAllocateInfo->memoryTypeIndex);
2308
2309   /* TODO: Unsure about this logic??? */
2310   mem->initial_state = D3D12_RESOURCE_STATE_COMMON;
2311   heap_desc.Properties.Type = D3D12_HEAP_TYPE_CUSTOM;
2312   heap_desc.Properties.MemoryPoolPreference =
2313      ((mem_type->propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) &&
2314       !pdevice->architecture.UMA) ?
2315      D3D12_MEMORY_POOL_L1 : D3D12_MEMORY_POOL_L0;
2316   if (mem_type->propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) {
2317      heap_desc.Properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_WRITE_BACK;
2318   } else if (mem_type->propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
2319      heap_desc.Properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE;
2320   } else {
2321      heap_desc.Properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE;
2322   }
2323
2324   if (FAILED(ID3D12Device1_CreateHeap(device->dev, &heap_desc,
2325                                       &IID_ID3D12Heap,
2326                                       (void **)&mem->heap))) {
2327      dzn_device_memory_destroy(mem, pAllocator);
2328      return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
2329   }
2330
2331   if ((mem_type->propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) &&
2332       !(heap_desc.Flags & D3D12_HEAP_FLAG_DENY_BUFFERS)){
2333      D3D12_RESOURCE_DESC res_desc = { 0 };
2334      res_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
2335      res_desc.Format = DXGI_FORMAT_UNKNOWN;
2336      res_desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
2337      res_desc.Width = heap_desc.SizeInBytes;
2338      res_desc.Height = 1;
2339      res_desc.DepthOrArraySize = 1;
2340      res_desc.MipLevels = 1;
2341      res_desc.SampleDesc.Count = 1;
2342      res_desc.SampleDesc.Quality = 0;
2343      res_desc.Flags = D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
2344      res_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
2345      HRESULT hr = ID3D12Device1_CreatePlacedResource(device->dev, mem->heap, 0, &res_desc,
2346                                                      mem->initial_state,
2347                                                      NULL,
2348                                                      &IID_ID3D12Resource,
2349                                                      (void **)&mem->map_res);
2350      if (FAILED(hr)) {
2351         dzn_device_memory_destroy(mem, pAllocator);
2352         return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
2353      }
2354   }
2355
2356   *out = dzn_device_memory_to_handle(mem);
2357   return VK_SUCCESS;
2358}
2359
2360VKAPI_ATTR VkResult VKAPI_CALL
2361dzn_AllocateMemory(VkDevice device,
2362                   const VkMemoryAllocateInfo *pAllocateInfo,
2363                   const VkAllocationCallbacks *pAllocator,
2364                   VkDeviceMemory *pMem)
2365{
2366   return dzn_device_memory_create(dzn_device_from_handle(device),
2367                                   pAllocateInfo, pAllocator, pMem);
2368}
2369
2370VKAPI_ATTR void VKAPI_CALL
2371dzn_FreeMemory(VkDevice device,
2372               VkDeviceMemory mem,
2373               const VkAllocationCallbacks *pAllocator)
2374{
2375   dzn_device_memory_destroy(dzn_device_memory_from_handle(mem), pAllocator);
2376}
2377
2378VKAPI_ATTR VkResult VKAPI_CALL
2379dzn_MapMemory(VkDevice _device,
2380              VkDeviceMemory _memory,
2381              VkDeviceSize offset,
2382              VkDeviceSize size,
2383              VkMemoryMapFlags flags,
2384              void **ppData)
2385{
2386   VK_FROM_HANDLE(dzn_device, device, _device);
2387   VK_FROM_HANDLE(dzn_device_memory, mem, _memory);
2388
2389   if (mem == NULL) {
2390      *ppData = NULL;
2391      return VK_SUCCESS;
2392   }
2393
2394   if (size == VK_WHOLE_SIZE)
2395      size = mem->size - offset;
2396
2397   /* From the Vulkan spec version 1.0.32 docs for MapMemory:
2398    *
2399    *  * If size is not equal to VK_WHOLE_SIZE, size must be greater than 0
2400    *    assert(size != 0);
2401    *  * If size is not equal to VK_WHOLE_SIZE, size must be less than or
2402    *    equal to the size of the memory minus offset
2403    */
2404   assert(size > 0);
2405   assert(offset + size <= mem->size);
2406
2407   assert(mem->map_res);
2408   D3D12_RANGE range = { 0 };
2409   range.Begin = offset;
2410   range.End = offset + size;
2411   void *map = NULL;
2412   if (FAILED(ID3D12Resource_Map(mem->map_res, 0, &range, &map)))
2413      return vk_error(device, VK_ERROR_MEMORY_MAP_FAILED);
2414
2415   mem->map = map;
2416   mem->map_size = size;
2417
2418   *ppData = ((uint8_t *) map) + offset;
2419
2420   return VK_SUCCESS;
2421}
2422
2423VKAPI_ATTR void VKAPI_CALL
2424dzn_UnmapMemory(VkDevice _device,
2425                VkDeviceMemory _memory)
2426{
2427   VK_FROM_HANDLE(dzn_device_memory, mem, _memory);
2428
2429   if (mem == NULL)
2430      return;
2431
2432   assert(mem->map_res);
2433   ID3D12Resource_Unmap(mem->map_res, 0, NULL);
2434
2435   mem->map = NULL;
2436   mem->map_size = 0;
2437}
2438
2439VKAPI_ATTR VkResult VKAPI_CALL
2440dzn_FlushMappedMemoryRanges(VkDevice _device,
2441                            uint32_t memoryRangeCount,
2442                            const VkMappedMemoryRange *pMemoryRanges)
2443{
2444   return VK_SUCCESS;
2445}
2446
2447VKAPI_ATTR VkResult VKAPI_CALL
2448dzn_InvalidateMappedMemoryRanges(VkDevice _device,
2449                                 uint32_t memoryRangeCount,
2450                                 const VkMappedMemoryRange *pMemoryRanges)
2451{
2452   return VK_SUCCESS;
2453}
2454
2455static void
2456dzn_buffer_destroy(struct dzn_buffer *buf, const VkAllocationCallbacks *pAllocator)
2457{
2458   if (!buf)
2459      return;
2460
2461   struct dzn_device *device = container_of(buf->base.device, struct dzn_device, vk);
2462
2463   if (buf->res)
2464      ID3D12Resource_Release(buf->res);
2465
2466   vk_object_base_finish(&buf->base);
2467   vk_free2(&device->vk.alloc, pAllocator, buf);
2468}
2469
2470static VkResult
2471dzn_buffer_create(struct dzn_device *device,
2472                  const VkBufferCreateInfo *pCreateInfo,
2473                  const VkAllocationCallbacks *pAllocator,
2474                  VkBuffer *out)
2475{
2476   struct dzn_buffer *buf =
2477      vk_zalloc2(&device->vk.alloc, pAllocator, sizeof(*buf), 8,
2478                 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
2479   if (!buf)
2480     return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
2481
2482   vk_object_base_init(&device->vk, &buf->base, VK_OBJECT_TYPE_BUFFER);
2483   buf->create_flags = pCreateInfo->flags;
2484   buf->size = pCreateInfo->size;
2485   buf->usage = pCreateInfo->usage;
2486
2487   if (buf->usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)
2488      buf->size = ALIGN_POT(buf->size, 256);
2489
2490   buf->desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
2491   buf->desc.Format = DXGI_FORMAT_UNKNOWN;
2492   buf->desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
2493   buf->desc.Width = buf->size;
2494   buf->desc.Height = 1;
2495   buf->desc.DepthOrArraySize = 1;
2496   buf->desc.MipLevels = 1;
2497   buf->desc.SampleDesc.Count = 1;
2498   buf->desc.SampleDesc.Quality = 0;
2499   buf->desc.Flags = D3D12_RESOURCE_FLAG_NONE;
2500   buf->desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
2501
2502   if (buf->usage &
2503       (VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
2504        VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT))
2505      buf->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
2506
2507   *out = dzn_buffer_to_handle(buf);
2508   return VK_SUCCESS;
2509}
2510
2511DXGI_FORMAT
2512dzn_buffer_get_dxgi_format(VkFormat format)
2513{
2514   enum pipe_format pfmt = vk_format_to_pipe_format(format);
2515
2516   return dzn_pipe_to_dxgi_format(pfmt);
2517}
2518
2519D3D12_TEXTURE_COPY_LOCATION
2520dzn_buffer_get_copy_loc(const struct dzn_buffer *buf,
2521                        VkFormat format,
2522                        const VkBufferImageCopy2 *region,
2523                        VkImageAspectFlagBits aspect,
2524                        uint32_t layer)
2525{
2526   const uint32_t buffer_row_length =
2527      region->bufferRowLength ? region->bufferRowLength : region->imageExtent.width;
2528
2529   VkFormat plane_format = dzn_image_get_plane_format(format, aspect);
2530
2531   enum pipe_format pfmt = vk_format_to_pipe_format(plane_format);
2532   uint32_t blksz = util_format_get_blocksize(pfmt);
2533   uint32_t blkw = util_format_get_blockwidth(pfmt);
2534   uint32_t blkh = util_format_get_blockheight(pfmt);
2535
2536   D3D12_TEXTURE_COPY_LOCATION loc = {
2537     .pResource = buf->res,
2538     .Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT,
2539     .PlacedFootprint = {
2540        .Footprint = {
2541           .Format =
2542              dzn_image_get_placed_footprint_format(format, aspect),
2543           .Width = region->imageExtent.width,
2544           .Height = region->imageExtent.height,
2545           .Depth = region->imageExtent.depth,
2546           .RowPitch = blksz * DIV_ROUND_UP(buffer_row_length, blkw),
2547        },
2548     },
2549   };
2550
2551   uint32_t buffer_layer_stride =
2552      loc.PlacedFootprint.Footprint.RowPitch *
2553      DIV_ROUND_UP(loc.PlacedFootprint.Footprint.Height, blkh);
2554
2555   loc.PlacedFootprint.Offset =
2556      region->bufferOffset + (layer * buffer_layer_stride);
2557
2558   return loc;
2559}
2560
2561D3D12_TEXTURE_COPY_LOCATION
2562dzn_buffer_get_line_copy_loc(const struct dzn_buffer *buf, VkFormat format,
2563                             const VkBufferImageCopy2 *region,
2564                             const D3D12_TEXTURE_COPY_LOCATION *loc,
2565                             uint32_t y, uint32_t z, uint32_t *start_x)
2566{
2567   uint32_t buffer_row_length =
2568      region->bufferRowLength ? region->bufferRowLength : region->imageExtent.width;
2569   uint32_t buffer_image_height =
2570      region->bufferImageHeight ? region->bufferImageHeight : region->imageExtent.height;
2571
2572   format = dzn_image_get_plane_format(format, region->imageSubresource.aspectMask);
2573
2574   enum pipe_format pfmt = vk_format_to_pipe_format(format);
2575   uint32_t blksz = util_format_get_blocksize(pfmt);
2576   uint32_t blkw = util_format_get_blockwidth(pfmt);
2577   uint32_t blkh = util_format_get_blockheight(pfmt);
2578   uint32_t blkd = util_format_get_blockdepth(pfmt);
2579   D3D12_TEXTURE_COPY_LOCATION new_loc = *loc;
2580   uint32_t buffer_row_stride =
2581      DIV_ROUND_UP(buffer_row_length, blkw) * blksz;
2582   uint32_t buffer_layer_stride =
2583      buffer_row_stride *
2584      DIV_ROUND_UP(buffer_image_height, blkh);
2585
2586   uint64_t tex_offset =
2587      ((y / blkh) * buffer_row_stride) +
2588      ((z / blkd) * buffer_layer_stride);
2589   uint64_t offset = loc->PlacedFootprint.Offset + tex_offset;
2590   uint32_t offset_alignment = D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT;
2591
2592   while (offset_alignment % blksz)
2593      offset_alignment += D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT;
2594
2595   new_loc.PlacedFootprint.Footprint.Height = blkh;
2596   new_loc.PlacedFootprint.Footprint.Depth = 1;
2597   new_loc.PlacedFootprint.Offset = (offset / offset_alignment) * offset_alignment;
2598   *start_x = ((offset % offset_alignment) / blksz) * blkw;
2599   new_loc.PlacedFootprint.Footprint.Width = *start_x + region->imageExtent.width;
2600   new_loc.PlacedFootprint.Footprint.RowPitch =
2601      ALIGN_POT(DIV_ROUND_UP(new_loc.PlacedFootprint.Footprint.Width, blkw) * blksz,
2602                D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
2603   return new_loc;
2604}
2605
2606bool
2607dzn_buffer_supports_region_copy(const D3D12_TEXTURE_COPY_LOCATION *loc)
2608{
2609   return !(loc->PlacedFootprint.Offset & (D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT - 1)) &&
2610          !(loc->PlacedFootprint.Footprint.RowPitch & (D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1));
2611}
2612
2613VKAPI_ATTR VkResult VKAPI_CALL
2614dzn_CreateBuffer(VkDevice device,
2615                 const VkBufferCreateInfo *pCreateInfo,
2616                 const VkAllocationCallbacks *pAllocator,
2617                 VkBuffer *pBuffer)
2618{
2619   return dzn_buffer_create(dzn_device_from_handle(device),
2620                            pCreateInfo, pAllocator, pBuffer);
2621}
2622
2623VKAPI_ATTR void VKAPI_CALL
2624dzn_DestroyBuffer(VkDevice device,
2625                  VkBuffer buffer,
2626                  const VkAllocationCallbacks *pAllocator)
2627{
2628   dzn_buffer_destroy(dzn_buffer_from_handle(buffer), pAllocator);
2629}
2630
2631VKAPI_ATTR void VKAPI_CALL
2632dzn_GetBufferMemoryRequirements2(VkDevice dev,
2633                                 const VkBufferMemoryRequirementsInfo2 *pInfo,
2634                                 VkMemoryRequirements2 *pMemoryRequirements)
2635{
2636   VK_FROM_HANDLE(dzn_device, device, dev);
2637   VK_FROM_HANDLE(dzn_buffer, buffer, pInfo->buffer);
2638   struct dzn_physical_device *pdev =
2639      container_of(device->vk.physical, struct dzn_physical_device, vk);
2640
2641   /* uh, this is grossly over-estimating things */
2642   uint32_t alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
2643   VkDeviceSize size = buffer->size;
2644
2645   if (buffer->usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) {
2646      alignment = MAX2(alignment, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT);
2647      size = ALIGN_POT(size, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT);
2648   }
2649
2650   pMemoryRequirements->memoryRequirements.size = size;
2651   pMemoryRequirements->memoryRequirements.alignment = alignment;
2652   pMemoryRequirements->memoryRequirements.memoryTypeBits =
2653      dzn_physical_device_get_mem_type_mask_for_resource(pdev, &buffer->desc);
2654
2655   vk_foreach_struct(ext, pMemoryRequirements->pNext) {
2656      switch (ext->sType) {
2657      case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS: {
2658         VkMemoryDedicatedRequirements *requirements =
2659            (VkMemoryDedicatedRequirements *)ext;
2660         /* TODO: figure out dedicated allocations */
2661         requirements->prefersDedicatedAllocation = false;
2662         requirements->requiresDedicatedAllocation = false;
2663         break;
2664      }
2665
2666      default:
2667         dzn_debug_ignored_stype(ext->sType);
2668         break;
2669      }
2670   }
2671
2672#if 0
2673   D3D12_RESOURCE_ALLOCATION_INFO GetResourceAllocationInfo(
2674      UINT                      visibleMask,
2675      UINT                      numResourceDescs,
2676      const D3D12_RESOURCE_DESC *pResourceDescs);
2677#endif
2678}
2679
2680VKAPI_ATTR VkResult VKAPI_CALL
2681dzn_BindBufferMemory2(VkDevice _device,
2682                      uint32_t bindInfoCount,
2683                      const VkBindBufferMemoryInfo *pBindInfos)
2684{
2685   VK_FROM_HANDLE(dzn_device, device, _device);
2686
2687   for (uint32_t i = 0; i < bindInfoCount; i++) {
2688      assert(pBindInfos[i].sType == VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO);
2689
2690      VK_FROM_HANDLE(dzn_device_memory, mem, pBindInfos[i].memory);
2691      VK_FROM_HANDLE(dzn_buffer, buffer, pBindInfos[i].buffer);
2692
2693      if (FAILED(ID3D12Device1_CreatePlacedResource(device->dev, mem->heap,
2694                                                   pBindInfos[i].memoryOffset,
2695                                                   &buffer->desc,
2696                                                   mem->initial_state,
2697                                                   NULL,
2698                                                   &IID_ID3D12Resource,
2699                                                   (void **)&buffer->res)))
2700         return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
2701   }
2702
2703   return VK_SUCCESS;
2704}
2705
2706static void
2707dzn_event_destroy(struct dzn_event *event,
2708                  const VkAllocationCallbacks *pAllocator)
2709{
2710   if (!event)
2711      return;
2712
2713   struct dzn_device *device =
2714      container_of(event->base.device, struct dzn_device, vk);
2715
2716   if (event->fence)
2717      ID3D12Fence_Release(event->fence);
2718
2719   vk_object_base_finish(&event->base);
2720   vk_free2(&device->vk.alloc, pAllocator, event);
2721}
2722
2723static VkResult
2724dzn_event_create(struct dzn_device *device,
2725                 const VkEventCreateInfo *pCreateInfo,
2726                 const VkAllocationCallbacks *pAllocator,
2727                 VkEvent *out)
2728{
2729   struct dzn_event *event =
2730      vk_zalloc2(&device->vk.alloc, pAllocator, sizeof(*event), 8,
2731                 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
2732   if (!event)
2733      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
2734
2735   vk_object_base_init(&device->vk, &event->base, VK_OBJECT_TYPE_EVENT);
2736
2737   if (FAILED(ID3D12Device1_CreateFence(device->dev, 0, D3D12_FENCE_FLAG_NONE,
2738                                        &IID_ID3D12Fence,
2739                                        (void **)&event->fence))) {
2740      dzn_event_destroy(event, pAllocator);
2741      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
2742   }
2743
2744   *out = dzn_event_to_handle(event);
2745   return VK_SUCCESS;
2746}
2747
2748VKAPI_ATTR VkResult VKAPI_CALL
2749dzn_CreateEvent(VkDevice device,
2750                const VkEventCreateInfo *pCreateInfo,
2751                const VkAllocationCallbacks *pAllocator,
2752                VkEvent *pEvent)
2753{
2754   return dzn_event_create(dzn_device_from_handle(device),
2755                           pCreateInfo, pAllocator, pEvent);
2756}
2757
2758VKAPI_ATTR void VKAPI_CALL
2759dzn_DestroyEvent(VkDevice device,
2760                 VkEvent event,
2761                 const VkAllocationCallbacks *pAllocator)
2762{
2763   dzn_event_destroy(dzn_event_from_handle(event), pAllocator);
2764}
2765
2766VKAPI_ATTR VkResult VKAPI_CALL
2767dzn_ResetEvent(VkDevice dev,
2768               VkEvent evt)
2769{
2770   VK_FROM_HANDLE(dzn_device, device, dev);
2771   VK_FROM_HANDLE(dzn_event, event, evt);
2772
2773   if (FAILED(ID3D12Fence_Signal(event->fence, 0)))
2774      return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
2775
2776   return VK_SUCCESS;
2777}
2778
2779VKAPI_ATTR VkResult VKAPI_CALL
2780dzn_SetEvent(VkDevice dev,
2781             VkEvent evt)
2782{
2783   VK_FROM_HANDLE(dzn_device, device, dev);
2784   VK_FROM_HANDLE(dzn_event, event, evt);
2785
2786   if (FAILED(ID3D12Fence_Signal(event->fence, 1)))
2787      return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
2788
2789   return VK_SUCCESS;
2790}
2791
2792VKAPI_ATTR VkResult VKAPI_CALL
2793dzn_GetEventStatus(VkDevice device,
2794                   VkEvent evt)
2795{
2796   VK_FROM_HANDLE(dzn_event, event, evt);
2797
2798   return ID3D12Fence_GetCompletedValue(event->fence) == 0 ?
2799          VK_EVENT_RESET : VK_EVENT_SET;
2800}
2801
2802VKAPI_ATTR void VKAPI_CALL
2803dzn_GetDeviceMemoryCommitment(VkDevice device,
2804                              VkDeviceMemory memory,
2805                              VkDeviceSize *pCommittedMemoryInBytes)
2806{
2807   VK_FROM_HANDLE(dzn_device_memory, mem, memory);
2808
2809   // TODO: find if there's a way to query/track actual heap residency
2810   *pCommittedMemoryInBytes = mem->size;
2811}
2812
2813VKAPI_ATTR VkResult VKAPI_CALL
2814dzn_QueueBindSparse(VkQueue queue,
2815                    uint32_t bindInfoCount,
2816                    const VkBindSparseInfo *pBindInfo,
2817                    VkFence fence)
2818{
2819   // FIXME: add proper implem
2820   dzn_stub();
2821   return VK_SUCCESS;
2822}
2823
2824static D3D12_TEXTURE_ADDRESS_MODE
2825dzn_sampler_translate_addr_mode(VkSamplerAddressMode in)
2826{
2827   switch (in) {
2828   case VK_SAMPLER_ADDRESS_MODE_REPEAT: return D3D12_TEXTURE_ADDRESS_MODE_WRAP;
2829   case VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: return D3D12_TEXTURE_ADDRESS_MODE_MIRROR;
2830   case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: return D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
2831   case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: return D3D12_TEXTURE_ADDRESS_MODE_BORDER;
2832   default: unreachable("Invalid address mode");
2833   }
2834}
2835
2836static void
2837dzn_sampler_destroy(struct dzn_sampler *sampler,
2838                    const VkAllocationCallbacks *pAllocator)
2839{
2840   if (!sampler)
2841      return;
2842
2843   struct dzn_device *device =
2844      container_of(sampler->base.device, struct dzn_device, vk);
2845
2846   vk_object_base_finish(&sampler->base);
2847   vk_free2(&device->vk.alloc, pAllocator, sampler);
2848}
2849
2850static VkResult
2851dzn_sampler_create(struct dzn_device *device,
2852                   const VkSamplerCreateInfo *pCreateInfo,
2853                   const VkAllocationCallbacks *pAllocator,
2854                   VkSampler *out)
2855{
2856   struct dzn_sampler *sampler =
2857      vk_zalloc2(&device->vk.alloc, pAllocator, sizeof(*sampler), 8,
2858                 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
2859   if (!sampler)
2860      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
2861
2862   vk_object_base_init(&device->vk, &sampler->base, VK_OBJECT_TYPE_SAMPLER);
2863
2864   const VkSamplerCustomBorderColorCreateInfoEXT *pBorderColor = (const VkSamplerCustomBorderColorCreateInfoEXT *)
2865      vk_find_struct_const(pCreateInfo->pNext, SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT);
2866
2867   /* TODO: have a sampler pool to allocate shader-invisible descs which we
2868    * can copy to the desc_set when UpdateDescriptorSets() is called.
2869    */
2870   sampler->desc.Filter = dzn_translate_sampler_filter(pCreateInfo);
2871   sampler->desc.AddressU = dzn_sampler_translate_addr_mode(pCreateInfo->addressModeU);
2872   sampler->desc.AddressV = dzn_sampler_translate_addr_mode(pCreateInfo->addressModeV);
2873   sampler->desc.AddressW = dzn_sampler_translate_addr_mode(pCreateInfo->addressModeW);
2874   sampler->desc.MipLODBias = pCreateInfo->mipLodBias;
2875   sampler->desc.MaxAnisotropy = pCreateInfo->maxAnisotropy;
2876   sampler->desc.MinLOD = pCreateInfo->minLod;
2877   sampler->desc.MaxLOD = pCreateInfo->maxLod;
2878
2879   if (pCreateInfo->compareEnable)
2880      sampler->desc.ComparisonFunc = dzn_translate_compare_op(pCreateInfo->compareOp);
2881
2882   bool reads_border_color =
2883      pCreateInfo->addressModeU == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER ||
2884      pCreateInfo->addressModeV == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER ||
2885      pCreateInfo->addressModeW == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
2886
2887   if (reads_border_color) {
2888      switch (pCreateInfo->borderColor) {
2889      case VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK:
2890      case VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK:
2891         sampler->desc.BorderColor[0] = 0.0f;
2892         sampler->desc.BorderColor[1] = 0.0f;
2893         sampler->desc.BorderColor[2] = 0.0f;
2894         sampler->desc.BorderColor[3] =
2895            pCreateInfo->borderColor == VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK ? 0.0f : 1.0f;
2896         sampler->static_border_color =
2897            pCreateInfo->borderColor == VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK ?
2898            D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK :
2899            D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK;
2900         break;
2901      case VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE:
2902         sampler->desc.BorderColor[0] = sampler->desc.BorderColor[1] = 1.0f;
2903         sampler->desc.BorderColor[2] = sampler->desc.BorderColor[3] = 1.0f;
2904         sampler->static_border_color = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE;
2905         break;
2906      case VK_BORDER_COLOR_FLOAT_CUSTOM_EXT:
2907         sampler->static_border_color = (D3D12_STATIC_BORDER_COLOR)-1;
2908         for (unsigned i = 0; i < ARRAY_SIZE(sampler->desc.BorderColor); i++)
2909            sampler->desc.BorderColor[i] = pBorderColor->customBorderColor.float32[i];
2910         break;
2911      case VK_BORDER_COLOR_INT_TRANSPARENT_BLACK:
2912      case VK_BORDER_COLOR_INT_OPAQUE_BLACK:
2913      case VK_BORDER_COLOR_INT_OPAQUE_WHITE:
2914      case VK_BORDER_COLOR_INT_CUSTOM_EXT:
2915         /* FIXME: sampling from integer textures is not supported yet. */
2916         sampler->static_border_color = (D3D12_STATIC_BORDER_COLOR)-1;
2917         break;
2918      default:
2919         unreachable("Unsupported border color");
2920      }
2921   }
2922
2923   *out = dzn_sampler_to_handle(sampler);
2924   return VK_SUCCESS;
2925}
2926
2927VKAPI_ATTR VkResult VKAPI_CALL
2928dzn_CreateSampler(VkDevice device,
2929                  const VkSamplerCreateInfo *pCreateInfo,
2930                  const VkAllocationCallbacks *pAllocator,
2931                  VkSampler *pSampler)
2932{
2933   return dzn_sampler_create(dzn_device_from_handle(device),
2934                             pCreateInfo, pAllocator, pSampler);
2935}
2936
2937VKAPI_ATTR void VKAPI_CALL
2938dzn_DestroySampler(VkDevice device,
2939                   VkSampler sampler,
2940                   const VkAllocationCallbacks *pAllocator)
2941{
2942   dzn_sampler_destroy(dzn_sampler_from_handle(sampler), pAllocator);
2943}
2944
2945VKAPI_ATTR void VKAPI_CALL
2946dzn_GetDeviceGroupPeerMemoryFeatures(VkDevice device,
2947                                     uint32_t heapIndex,
2948                                     uint32_t localDeviceIndex,
2949                                     uint32_t remoteDeviceIndex,
2950                                     VkPeerMemoryFeatureFlags *pPeerMemoryFeatures)
2951{
2952   *pPeerMemoryFeatures = 0;
2953}
2954
2955VKAPI_ATTR void VKAPI_CALL
2956dzn_GetImageSparseMemoryRequirements2(VkDevice device,
2957                                      const VkImageSparseMemoryRequirementsInfo2* pInfo,
2958                                      uint32_t *pSparseMemoryRequirementCount,
2959                                      VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements)
2960{
2961   *pSparseMemoryRequirementCount = 0;
2962}
2963
2964VKAPI_ATTR VkResult VKAPI_CALL
2965dzn_CreateSamplerYcbcrConversion(VkDevice device,
2966                                 const VkSamplerYcbcrConversionCreateInfo *pCreateInfo,
2967                                 const VkAllocationCallbacks *pAllocator,
2968                                 VkSamplerYcbcrConversion *pYcbcrConversion)
2969{
2970   unreachable("Ycbcr sampler conversion is not supported");
2971   return VK_SUCCESS;
2972}
2973
2974VKAPI_ATTR void VKAPI_CALL
2975dzn_DestroySamplerYcbcrConversion(VkDevice device,
2976                                  VkSamplerYcbcrConversion YcbcrConversion,
2977                                  const VkAllocationCallbacks *pAllocator)
2978{
2979   unreachable("Ycbcr sampler conversion is not supported");
2980}
2981