• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/u_debug.h"
37 #include "util/disk_cache.h"
38 #include "util/macros.h"
39 #include "util/mesa-sha1.h"
40 #include "util/u_dl.h"
41 
42 #include "util/driconf.h"
43 
44 #include "glsl_types.h"
45 
46 #include "dxil_validator.h"
47 
48 #include "git_sha1.h"
49 
50 #include <string.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <c99_alloca.h>
54 
55 #ifdef _WIN32
56 #include <windows.h>
57 #include <shlobj.h>
58 #include "dzn_dxgi.h"
59 #endif
60 
61 #include <directx/d3d12sdklayers.h>
62 
63 #define DZN_API_VERSION VK_MAKE_VERSION(1, 2, VK_HEADER_VERSION)
64 
65 #define MAX_TIER2_MEMORY_TYPES 4
66 
67 const VkExternalMemoryHandleTypeFlags opaque_external_flag =
68 #ifdef _WIN32
69    VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
70 #else
71    VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
72 #endif
73 
74 static const struct vk_instance_extension_table instance_extensions = {
75    .KHR_get_physical_device_properties2      = true,
76    .KHR_device_group_creation                = true,
77 #ifdef DZN_USE_WSI_PLATFORM
78    .KHR_surface                              = true,
79    .KHR_get_surface_capabilities2            = true,
80 #endif
81 #ifdef VK_USE_PLATFORM_WIN32_KHR
82    .KHR_win32_surface                        = true,
83 #endif
84 #ifdef VK_USE_PLATFORM_XCB_KHR
85    .KHR_xcb_surface                          = true,
86 #endif
87 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
88    .KHR_wayland_surface                      = true,
89 #endif
90 #ifdef VK_USE_PLATFORM_XLIB_KHR
91    .KHR_xlib_surface                         = true,
92 #endif
93 #ifndef VK_USE_PLATFORM_WIN32_KHR
94    .EXT_headless_surface                     = true,
95 #endif
96    .EXT_debug_report                         = true,
97    .EXT_debug_utils                          = true,
98 };
99 
100 static void
dzn_physical_device_get_extensions(struct dzn_physical_device * pdev)101 dzn_physical_device_get_extensions(struct dzn_physical_device *pdev)
102 {
103    pdev->vk.supported_extensions = (struct vk_device_extension_table) {
104       .KHR_16bit_storage                     = pdev->options4.Native16BitShaderOpsSupported,
105       .KHR_bind_memory2                      = true,
106       .KHR_buffer_device_address             = pdev->shader_model >= D3D_SHADER_MODEL_6_6,
107       .KHR_create_renderpass2                = true,
108       .KHR_dedicated_allocation              = true,
109       .KHR_depth_stencil_resolve             = true,
110       .KHR_descriptor_update_template        = true,
111       .KHR_device_group                      = true,
112       .KHR_draw_indirect_count               = true,
113       .KHR_driver_properties                 = true,
114       .KHR_dynamic_rendering                 = true,
115       .KHR_external_memory                   = true,
116       .KHR_external_semaphore                = true,
117 #ifdef _WIN32
118       .KHR_external_memory_win32             = true,
119       .KHR_external_semaphore_win32          = true,
120 #else
121       .KHR_external_memory_fd                = true,
122       .KHR_external_semaphore_fd             = true,
123 #endif
124       .KHR_image_format_list                 = true,
125       .KHR_imageless_framebuffer             = true,
126       .KHR_get_memory_requirements2          = true,
127       .KHR_maintenance1                      = true,
128       .KHR_maintenance2                      = true,
129       .KHR_maintenance3                      = true,
130       .KHR_multiview                         = true,
131       .KHR_relaxed_block_layout              = true,
132       .KHR_sampler_mirror_clamp_to_edge      = true,
133       .KHR_separate_depth_stencil_layouts    = true,
134       .KHR_shader_draw_parameters            = true,
135       .KHR_shader_expect_assume              = true,
136       .KHR_shader_float16_int8               = pdev->options4.Native16BitShaderOpsSupported,
137       .KHR_shader_float_controls             = true,
138       .KHR_shader_integer_dot_product        = true,
139       .KHR_spirv_1_4                         = true,
140       .KHR_storage_buffer_storage_class      = true,
141 #ifdef DZN_USE_WSI_PLATFORM
142       .KHR_swapchain                         = true,
143 #endif
144       .KHR_synchronization2                  = true,
145       .KHR_timeline_semaphore                = true,
146       .KHR_uniform_buffer_standard_layout    = true,
147       .EXT_buffer_device_address             = pdev->shader_model >= D3D_SHADER_MODEL_6_6,
148       .EXT_descriptor_indexing               = pdev->shader_model >= D3D_SHADER_MODEL_6_6,
149 #if defined(_WIN32)
150       .EXT_external_memory_host              = pdev->dev13,
151 #endif
152       .EXT_scalar_block_layout               = true,
153       .EXT_separate_stencil_usage            = true,
154       .EXT_shader_replicated_composites      = true,
155       .EXT_shader_subgroup_ballot            = true,
156       .EXT_shader_subgroup_vote              = true,
157       .EXT_subgroup_size_control             = true,
158       .EXT_vertex_attribute_divisor          = true,
159       .MSFT_layered_driver                   = true,
160    };
161 }
162 
163 VKAPI_ATTR VkResult VKAPI_CALL
dzn_EnumerateInstanceExtensionProperties(const char * pLayerName,uint32_t * pPropertyCount,VkExtensionProperties * pProperties)164 dzn_EnumerateInstanceExtensionProperties(const char *pLayerName,
165                                          uint32_t *pPropertyCount,
166                                          VkExtensionProperties *pProperties)
167 {
168    /* We don't support any layers  */
169    if (pLayerName)
170       return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);
171 
172    return vk_enumerate_instance_extension_properties(
173       &instance_extensions, pPropertyCount, pProperties);
174 }
175 
176 static const struct debug_control dzn_debug_options[] = {
177    { "sync", DZN_DEBUG_SYNC },
178    { "nir", DZN_DEBUG_NIR },
179    { "dxil", DZN_DEBUG_DXIL },
180    { "warp", DZN_DEBUG_WARP },
181    { "internal", DZN_DEBUG_INTERNAL },
182    { "signature", DZN_DEBUG_SIG },
183    { "gbv", DZN_DEBUG_GBV },
184    { "d3d12", DZN_DEBUG_D3D12 },
185    { "debugger", DZN_DEBUG_DEBUGGER },
186    { "redirects", DZN_DEBUG_REDIRECTS },
187    { "bindless", DZN_DEBUG_BINDLESS },
188    { "nobindless", DZN_DEBUG_NO_BINDLESS },
189    { "experimental", DZN_DEBUG_EXPERIMENTAL },
190    { "multiview", DZN_DEBUG_MULTIVIEW },
191    { NULL, 0 }
192 };
193 
194 static void
dzn_physical_device_destroy(struct vk_physical_device * physical)195 dzn_physical_device_destroy(struct vk_physical_device *physical)
196 {
197    struct dzn_physical_device *pdev = container_of(physical, struct dzn_physical_device, vk);
198    struct dzn_instance *instance = container_of(pdev->vk.instance, struct dzn_instance, vk);
199 
200    if (pdev->dev)
201       ID3D12Device1_Release(pdev->dev);
202 
203    if (pdev->dev10)
204       ID3D12Device1_Release(pdev->dev10);
205 
206    if (pdev->dev11)
207       ID3D12Device1_Release(pdev->dev11);
208 
209    if (pdev->dev12)
210       ID3D12Device1_Release(pdev->dev12);
211 
212    if (pdev->dev13)
213       ID3D12Device1_Release(pdev->dev13);
214 
215    if (pdev->adapter)
216       IUnknown_Release(pdev->adapter);
217 
218    dzn_wsi_finish(pdev);
219    vk_physical_device_finish(&pdev->vk);
220    vk_free(&instance->vk.alloc, pdev);
221 }
222 
223 static void
dzn_instance_destroy(struct dzn_instance * instance,const VkAllocationCallbacks * alloc)224 dzn_instance_destroy(struct dzn_instance *instance, const VkAllocationCallbacks *alloc)
225 {
226    if (!instance)
227       return;
228 
229    vk_instance_finish(&instance->vk);
230 
231 #ifdef _WIN32
232    dxil_destroy_validator(instance->dxil_validator);
233 #endif
234 
235    if (instance->factory)
236       ID3D12DeviceFactory_Release(instance->factory);
237 
238    if (instance->d3d12_mod)
239       util_dl_close(instance->d3d12_mod);
240 
241    driDestroyOptionCache(&instance->dri_options);
242    driDestroyOptionInfo(&instance->available_dri_options);
243 
244    vk_free2(vk_default_allocator(), alloc, instance);
245 }
246 
247 #ifdef _WIN32
248 extern IMAGE_DOS_HEADER __ImageBase;
249 static const char *
try_find_d3d12core_next_to_self(char * path,size_t path_arr_size)250 try_find_d3d12core_next_to_self(char *path, size_t path_arr_size)
251 {
252    uint32_t path_size = GetModuleFileNameA((HINSTANCE)&__ImageBase,
253                                            path, path_arr_size);
254    if (!path_arr_size || path_size == path_arr_size) {
255       mesa_loge("Unable to get path to self\n");
256       return NULL;
257    }
258 
259    char *last_slash = strrchr(path, '\\');
260    if (!last_slash) {
261       mesa_loge("Unable to get path to self\n");
262       return NULL;
263    }
264 
265    *(last_slash + 1) = '\0';
266    if (strcat_s(path, path_arr_size, "D3D12Core.dll") != 0) {
267       mesa_loge("Unable to get path to D3D12Core.dll next to self\n");
268       return NULL;
269    }
270 
271    if (GetFileAttributesA(path) == INVALID_FILE_ATTRIBUTES) {
272       return NULL;
273    }
274 
275    *(last_slash + 1) = '\0';
276    return path;
277 }
278 #endif
279 
280 static ID3D12DeviceFactory *
try_create_device_factory(struct util_dl_library * d3d12_mod)281 try_create_device_factory(struct util_dl_library *d3d12_mod)
282 {
283    /* A device factory allows us to isolate things like debug layer enablement from other callers,
284    * and can potentially even refer to a different D3D12 redist implementation from others.
285    */
286    ID3D12DeviceFactory *factory = NULL;
287 
288    PFN_D3D12_GET_INTERFACE D3D12GetInterface = (PFN_D3D12_GET_INTERFACE)util_dl_get_proc_address(d3d12_mod, "D3D12GetInterface");
289    if (!D3D12GetInterface) {
290       mesa_loge("Failed to retrieve D3D12GetInterface\n");
291       return NULL;
292    }
293 
294 #ifdef _WIN32
295    /* First, try to create a device factory from a DLL-parallel D3D12Core.dll */
296    ID3D12SDKConfiguration *sdk_config = NULL;
297    if (SUCCEEDED(D3D12GetInterface(&CLSID_D3D12SDKConfiguration, &IID_ID3D12SDKConfiguration, (void **)&sdk_config))) {
298       ID3D12SDKConfiguration1 *sdk_config1 = NULL;
299       if (SUCCEEDED(IUnknown_QueryInterface(sdk_config, &IID_ID3D12SDKConfiguration1, (void **)&sdk_config1))) {
300          char self_path[MAX_PATH];
301          const char *d3d12core_path = try_find_d3d12core_next_to_self(self_path, sizeof(self_path));
302          if (d3d12core_path) {
303             if (SUCCEEDED(ID3D12SDKConfiguration1_CreateDeviceFactory(sdk_config1, D3D12_PREVIEW_SDK_VERSION, d3d12core_path, &IID_ID3D12DeviceFactory, (void **)&factory)) ||
304                 SUCCEEDED(ID3D12SDKConfiguration1_CreateDeviceFactory(sdk_config1, D3D12_SDK_VERSION, d3d12core_path, &IID_ID3D12DeviceFactory, (void **)&factory))) {
305                ID3D12SDKConfiguration_Release(sdk_config);
306                ID3D12SDKConfiguration1_Release(sdk_config1);
307                return factory;
308             }
309          }
310 
311          /* Nope, seems we don't have a matching D3D12Core.dll next to ourselves */
312          ID3D12SDKConfiguration1_Release(sdk_config1);
313       }
314 
315       /* It's possible there's a D3D12Core.dll next to the .exe, for development/testing purposes. If so, we'll be notified
316       * by environment variables what the relative path is and the version to use.
317       */
318       const char *d3d12core_relative_path = getenv("DZN_AGILITY_RELATIVE_PATH");
319       const char *d3d12core_sdk_version = getenv("DZN_AGILITY_SDK_VERSION");
320       if (d3d12core_relative_path && d3d12core_sdk_version) {
321          ID3D12SDKConfiguration_SetSDKVersion(sdk_config, atoi(d3d12core_sdk_version), d3d12core_relative_path);
322       }
323       ID3D12SDKConfiguration_Release(sdk_config);
324    }
325 #endif
326 
327    (void)D3D12GetInterface(&CLSID_D3D12DeviceFactory, &IID_ID3D12DeviceFactory, (void **)&factory);
328    return factory;
329 }
330 
331 VKAPI_ATTR void VKAPI_CALL
dzn_DestroyInstance(VkInstance instance,const VkAllocationCallbacks * pAllocator)332 dzn_DestroyInstance(VkInstance instance,
333                     const VkAllocationCallbacks *pAllocator)
334 {
335    dzn_instance_destroy(dzn_instance_from_handle(instance), pAllocator);
336 }
337 
338 static void
dzn_physical_device_init_uuids(struct dzn_physical_device * pdev)339 dzn_physical_device_init_uuids(struct dzn_physical_device *pdev)
340 {
341    const char *mesa_version = "Mesa " PACKAGE_VERSION MESA_GIT_SHA1;
342 
343    struct mesa_sha1 sha1_ctx;
344    uint8_t sha1[SHA1_DIGEST_LENGTH];
345    STATIC_ASSERT(VK_UUID_SIZE <= sizeof(sha1));
346 
347    /* The pipeline cache UUID is used for determining when a pipeline cache is
348     * invalid. Our cache is device-agnostic, but it does depend on the features
349     * provided by the D3D12 driver, so let's hash the build ID plus some
350     * caps that might impact our NIR lowering passes.
351     */
352    _mesa_sha1_init(&sha1_ctx);
353    _mesa_sha1_update(&sha1_ctx,  mesa_version, strlen(mesa_version));
354    disk_cache_get_function_identifier(dzn_physical_device_init_uuids, &sha1_ctx);
355    _mesa_sha1_update(&sha1_ctx, &pdev->options,
356       offsetof(struct dzn_physical_device, options21) + sizeof(pdev->options21) -
357                      offsetof(struct dzn_physical_device, options));
358    _mesa_sha1_final(&sha1_ctx, sha1);
359    memcpy(pdev->pipeline_cache_uuid, sha1, VK_UUID_SIZE);
360 
361    /* The driver UUID is used for determining sharability of images and memory
362     * between two Vulkan instances in separate processes.  People who want to
363     * share memory need to also check the device UUID (below) so all this
364     * needs to be is the build-id.
365     */
366    _mesa_sha1_compute(mesa_version, strlen(mesa_version), sha1);
367    memcpy(pdev->driver_uuid, sha1, VK_UUID_SIZE);
368 
369    /* The device UUID uniquely identifies the given device within the machine. */
370    _mesa_sha1_init(&sha1_ctx);
371    _mesa_sha1_update(&sha1_ctx, &pdev->desc.vendor_id, sizeof(pdev->desc.vendor_id));
372    _mesa_sha1_update(&sha1_ctx, &pdev->desc.device_id, sizeof(pdev->desc.device_id));
373    _mesa_sha1_update(&sha1_ctx, &pdev->desc.subsys_id, sizeof(pdev->desc.subsys_id));
374    _mesa_sha1_update(&sha1_ctx, &pdev->desc.revision, sizeof(pdev->desc.revision));
375    _mesa_sha1_final(&sha1_ctx, sha1);
376    memcpy(pdev->device_uuid, sha1, VK_UUID_SIZE);
377 }
378 
379 const struct vk_pipeline_cache_object_ops *const dzn_pipeline_cache_import_ops[] = {
380    &dzn_cached_blob_ops,
381    NULL,
382 };
383 
384 static void
dzn_physical_device_cache_caps(struct dzn_physical_device * pdev)385 dzn_physical_device_cache_caps(struct dzn_physical_device *pdev)
386 {
387    D3D_FEATURE_LEVEL checklist[] = {
388       D3D_FEATURE_LEVEL_11_0,
389       D3D_FEATURE_LEVEL_11_1,
390       D3D_FEATURE_LEVEL_12_0,
391       D3D_FEATURE_LEVEL_12_1,
392       D3D_FEATURE_LEVEL_12_2,
393    };
394 
395    D3D12_FEATURE_DATA_FEATURE_LEVELS levels = {
396       .NumFeatureLevels = ARRAY_SIZE(checklist),
397       .pFeatureLevelsRequested = checklist,
398    };
399 
400    ID3D12Device1_CheckFeatureSupport(pdev->dev, D3D12_FEATURE_FEATURE_LEVELS, &levels, sizeof(levels));
401    pdev->feature_level = levels.MaxSupportedFeatureLevel;
402 
403    static const D3D_SHADER_MODEL valid_shader_models[] = {
404       D3D_SHADER_MODEL_6_8 ,D3D_SHADER_MODEL_6_7, D3D_SHADER_MODEL_6_6, D3D_SHADER_MODEL_6_5,
405       D3D_SHADER_MODEL_6_4, D3D_SHADER_MODEL_6_3, D3D_SHADER_MODEL_6_2, D3D_SHADER_MODEL_6_1,
406    };
407    for (UINT i = 0; i < ARRAY_SIZE(valid_shader_models); ++i) {
408       D3D12_FEATURE_DATA_SHADER_MODEL shader_model = { valid_shader_models[i] };
409       if (SUCCEEDED(ID3D12Device1_CheckFeatureSupport(pdev->dev, D3D12_FEATURE_SHADER_MODEL, &shader_model, sizeof(shader_model)))) {
410          pdev->shader_model = shader_model.HighestShaderModel;
411          break;
412       }
413    }
414 
415    D3D_ROOT_SIGNATURE_VERSION root_sig_versions[] = {
416       D3D_ROOT_SIGNATURE_VERSION_1_2,
417       D3D_ROOT_SIGNATURE_VERSION_1_1
418    };
419    for (UINT i = 0; i < ARRAY_SIZE(root_sig_versions); ++i) {
420       D3D12_FEATURE_DATA_ROOT_SIGNATURE root_sig = { root_sig_versions[i] };
421       if (SUCCEEDED(ID3D12Device1_CheckFeatureSupport(pdev->dev, D3D12_FEATURE_ROOT_SIGNATURE, &root_sig, sizeof(root_sig)))) {
422          pdev->root_sig_version = root_sig.HighestVersion;
423          break;
424       }
425    }
426 
427    ID3D12Device1_CheckFeatureSupport(pdev->dev, D3D12_FEATURE_ARCHITECTURE1, &pdev->architecture, sizeof(pdev->architecture));
428    ID3D12Device1_CheckFeatureSupport(pdev->dev, D3D12_FEATURE_D3D12_OPTIONS, &pdev->options, sizeof(pdev->options));
429    ID3D12Device1_CheckFeatureSupport(pdev->dev, D3D12_FEATURE_D3D12_OPTIONS1, &pdev->options1, sizeof(pdev->options1));
430    ID3D12Device1_CheckFeatureSupport(pdev->dev, D3D12_FEATURE_D3D12_OPTIONS2, &pdev->options2, sizeof(pdev->options2));
431    ID3D12Device1_CheckFeatureSupport(pdev->dev, D3D12_FEATURE_D3D12_OPTIONS3, &pdev->options3, sizeof(pdev->options3));
432    ID3D12Device1_CheckFeatureSupport(pdev->dev, D3D12_FEATURE_D3D12_OPTIONS4, &pdev->options4, sizeof(pdev->options4));
433    ID3D12Device1_CheckFeatureSupport(pdev->dev, D3D12_FEATURE_D3D12_OPTIONS12, &pdev->options12, sizeof(pdev->options12));
434    ID3D12Device1_CheckFeatureSupport(pdev->dev, D3D12_FEATURE_D3D12_OPTIONS13, &pdev->options13, sizeof(pdev->options13));
435    ID3D12Device1_CheckFeatureSupport(pdev->dev, D3D12_FEATURE_D3D12_OPTIONS14, &pdev->options14, sizeof(pdev->options14));
436    ID3D12Device1_CheckFeatureSupport(pdev->dev, D3D12_FEATURE_D3D12_OPTIONS15, &pdev->options15, sizeof(pdev->options15));
437    ID3D12Device1_CheckFeatureSupport(pdev->dev, D3D12_FEATURE_D3D12_OPTIONS16, &pdev->options16, sizeof(pdev->options16));
438    ID3D12Device1_CheckFeatureSupport(pdev->dev, D3D12_FEATURE_D3D12_OPTIONS17, &pdev->options17, sizeof(pdev->options17));
439    if (FAILED(ID3D12Device1_CheckFeatureSupport(pdev->dev, D3D12_FEATURE_D3D12_OPTIONS19, &pdev->options19, sizeof(pdev->options19)))) {
440       pdev->options19.MaxSamplerDescriptorHeapSize = D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE;
441       pdev->options19.MaxSamplerDescriptorHeapSizeWithStaticSamplers = pdev->options19.MaxSamplerDescriptorHeapSize;
442       pdev->options19.MaxViewDescriptorHeapSize = D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1;
443    }
444    if (FAILED(ID3D12Device1_CheckFeatureSupport(pdev->dev, D3D12_FEATURE_D3D12_OPTIONS21, &pdev->options21, sizeof(pdev->options21)))) {
445       pdev->options21.ExecuteIndirectTier = D3D12_EXECUTE_INDIRECT_TIER_1_0;
446    }
447    {
448       D3D12_FEATURE_DATA_FORMAT_SUPPORT a4b4g4r4_support = {
449          .Format = DXGI_FORMAT_A4B4G4R4_UNORM
450       };
451       pdev->support_a4b4g4r4 =
452          SUCCEEDED(ID3D12Device1_CheckFeatureSupport(pdev->dev, D3D12_FEATURE_FORMAT_SUPPORT, &a4b4g4r4_support, sizeof(a4b4g4r4_support)));
453    }
454 
455    pdev->queue_families[pdev->queue_family_count++] = (struct dzn_queue_family) {
456       .props = {
457          .queueFlags = VK_QUEUE_GRAPHICS_BIT |
458                        VK_QUEUE_COMPUTE_BIT |
459                        VK_QUEUE_TRANSFER_BIT,
460          .queueCount = 4,
461          .timestampValidBits = 64,
462          .minImageTransferGranularity = { 0, 0, 0 },
463       },
464       .desc = {
465          .Type = D3D12_COMMAND_LIST_TYPE_DIRECT,
466       },
467    };
468 
469    pdev->queue_families[pdev->queue_family_count++] = (struct dzn_queue_family) {
470       .props = {
471          .queueFlags = VK_QUEUE_COMPUTE_BIT |
472                        VK_QUEUE_TRANSFER_BIT,
473          .queueCount = 8,
474          .timestampValidBits = 64,
475          .minImageTransferGranularity = { 0, 0, 0 },
476       },
477       .desc = {
478          .Type = D3D12_COMMAND_LIST_TYPE_COMPUTE,
479       },
480    };
481 
482    assert(pdev->queue_family_count <= ARRAY_SIZE(pdev->queue_families));
483 
484    D3D12_COMMAND_QUEUE_DESC queue_desc = {
485       .Type = D3D12_COMMAND_LIST_TYPE_DIRECT,
486       .Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL,
487       .Flags = D3D12_COMMAND_QUEUE_FLAG_NONE,
488       .NodeMask = 0,
489    };
490 
491    ID3D12CommandQueue *cmdqueue;
492    ID3D12Device1_CreateCommandQueue(pdev->dev, &queue_desc,
493                                     &IID_ID3D12CommandQueue,
494                                     (void **)&cmdqueue);
495 
496    uint64_t ts_freq;
497    ID3D12CommandQueue_GetTimestampFrequency(cmdqueue, &ts_freq);
498    pdev->timestamp_period = 1000000000.0f / ts_freq;
499    ID3D12CommandQueue_Release(cmdqueue);
500 }
501 
502 static void
dzn_physical_device_init_memory(struct dzn_physical_device * pdev)503 dzn_physical_device_init_memory(struct dzn_physical_device *pdev)
504 {
505    VkPhysicalDeviceMemoryProperties *mem = &pdev->memory;
506 
507    /* For each pair of elements X and Y returned in memoryTypes, X must be placed at a lower index position than Y if:
508     * - the set of bit flags returned in the propertyFlags member of X is a strict subset of the set of bit flags
509     *   returned in the propertyFlags member of Y; or
510     * - the propertyFlags members of X and Y are equal, and X belongs to a memory heap with greater performance
511     *   (as determined in an implementation-specific manner) ; or
512     * - the propertyFlags members of Y includes VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD or
513     *   VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD and X does not
514     * See: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMemoryProperties.html
515    */
516 
517    mem->memoryHeapCount = 0;
518    mem->memoryTypeCount = 0;
519 
520    VkMemoryPropertyFlags ram_device_local_property = 0;
521    VkMemoryHeapFlags ram_device_local_heap_flag = 0;
522 
523    if (pdev->architecture.UMA) {
524       /* All memory is considered device-local for UMA even though it's just RAM */
525       ram_device_local_property = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
526       ram_device_local_heap_flag = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT;
527    }
528 
529    mem->memoryHeaps[mem->memoryHeapCount++] = (VkMemoryHeap) {
530       .size = pdev->desc.shared_system_memory,
531       .flags = ram_device_local_heap_flag,
532    };
533 
534    /* Three non-device-local memory types: host non-visible, host write-combined, and host cached */
535    mem->memoryTypes[mem->memoryTypeCount++] = (VkMemoryType){
536       .propertyFlags = ram_device_local_property,
537       .heapIndex = mem->memoryHeapCount - 1,
538    };
539    mem->memoryTypes[mem->memoryTypeCount++] = (VkMemoryType){
540       .propertyFlags = ram_device_local_property |
541                        VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
542                        VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
543       .heapIndex = mem->memoryHeapCount - 1,
544    };
545    mem->memoryTypes[mem->memoryTypeCount++] = (VkMemoryType) {
546       .propertyFlags = ram_device_local_property |
547                        VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
548                        VK_MEMORY_PROPERTY_HOST_CACHED_BIT |
549                        VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
550      .heapIndex = mem->memoryHeapCount - 1,
551    };
552 
553    if (!pdev->architecture.UMA) {
554       /* Add a device-local memory heap/type */
555       mem->memoryHeaps[mem->memoryHeapCount++] = (VkMemoryHeap){
556          .size = pdev->desc.dedicated_video_memory,
557          .flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT,
558       };
559       mem->memoryTypes[mem->memoryTypeCount++] = (VkMemoryType){
560          .propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
561          .heapIndex = mem->memoryHeapCount - 1,
562       };
563    }
564 
565    assert(mem->memoryTypeCount <= MAX_TIER2_MEMORY_TYPES);
566 
567    if (pdev->options.ResourceHeapTier == D3D12_RESOURCE_HEAP_TIER_1) {
568       unsigned oldMemoryTypeCount = mem->memoryTypeCount;
569       VkMemoryType oldMemoryTypes[MAX_TIER2_MEMORY_TYPES];
570 
571       memcpy(oldMemoryTypes, mem->memoryTypes, oldMemoryTypeCount * sizeof(VkMemoryType));
572 
573       mem->memoryTypeCount = 0;
574       for (unsigned oldMemoryTypeIdx = 0; oldMemoryTypeIdx < oldMemoryTypeCount; ++oldMemoryTypeIdx) {
575          D3D12_HEAP_FLAGS flags[] = {
576             D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS,
577             D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES,
578             /* Note: Vulkan requires *all* images to come from the same memory type as long as
579              * the tiling property (and a few other misc properties) are the same. So, this
580              * non-RT/DS texture flag will only be used for TILING_LINEAR textures, which
581              * can't be render targets.
582              */
583             D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES
584          };
585          for (int i = 0; i < ARRAY_SIZE(flags); ++i) {
586             D3D12_HEAP_FLAGS flag = flags[i];
587             pdev->heap_flags_for_mem_type[mem->memoryTypeCount] = flag;
588             mem->memoryTypes[mem->memoryTypeCount] = oldMemoryTypes[oldMemoryTypeIdx];
589             mem->memoryTypeCount++;
590          }
591       }
592    }
593 }
594 
595 static D3D12_HEAP_FLAGS
dzn_physical_device_get_heap_flags_for_mem_type(const struct dzn_physical_device * pdev,uint32_t mem_type)596 dzn_physical_device_get_heap_flags_for_mem_type(const struct dzn_physical_device *pdev,
597                                                 uint32_t mem_type)
598 {
599    return pdev->heap_flags_for_mem_type[mem_type];
600 }
601 
602 uint32_t
dzn_physical_device_get_mem_type_mask_for_resource(const struct dzn_physical_device * pdev,const D3D12_RESOURCE_DESC * desc,bool shared)603 dzn_physical_device_get_mem_type_mask_for_resource(const struct dzn_physical_device *pdev,
604                                                    const D3D12_RESOURCE_DESC *desc,
605                                                    bool shared)
606 {
607    if (pdev->options.ResourceHeapTier > D3D12_RESOURCE_HEAP_TIER_1 && !shared)
608       return (1u << pdev->memory.memoryTypeCount) - 1;
609 
610    D3D12_HEAP_FLAGS deny_flag = D3D12_HEAP_FLAG_NONE;
611    if (pdev->options.ResourceHeapTier <= D3D12_RESOURCE_HEAP_TIER_1) {
612       if (desc->Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
613          deny_flag = D3D12_HEAP_FLAG_DENY_BUFFERS;
614       else if (desc->Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL))
615          deny_flag = D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES;
616       else
617          deny_flag = D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES;
618    }
619 
620    uint32_t mask = 0;
621    for (unsigned i = 0; i < pdev->memory.memoryTypeCount; ++i) {
622       if (shared && (pdev->memory.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT))
623          continue;
624       if ((pdev->heap_flags_for_mem_type[i] & deny_flag) == D3D12_HEAP_FLAG_NONE)
625          mask |= (1 << i);
626    }
627    return mask;
628 }
629 
630 static uint32_t
dzn_physical_device_get_max_mip_level(bool is_3d)631 dzn_physical_device_get_max_mip_level(bool is_3d)
632 {
633    return is_3d ? 11 : 14;
634 }
635 
636 static uint32_t
dzn_physical_device_get_max_extent(bool is_3d)637 dzn_physical_device_get_max_extent(bool is_3d)
638 {
639    uint32_t max_mip = dzn_physical_device_get_max_mip_level(is_3d);
640 
641    return 1 << max_mip;
642 }
643 
644 static uint32_t
dzn_physical_device_get_max_array_layers()645 dzn_physical_device_get_max_array_layers()
646 {
647    return dzn_physical_device_get_max_extent(false);
648 }
649 
650 static void
dzn_physical_device_get_features(const struct dzn_physical_device * pdev,struct vk_features * features)651 dzn_physical_device_get_features(const struct dzn_physical_device *pdev,
652                                  struct vk_features *features)
653 {
654    struct dzn_instance *instance = container_of(pdev->vk.instance, struct dzn_instance, vk);
655 
656    bool support_descriptor_indexing = pdev->shader_model >= D3D_SHADER_MODEL_6_6 &&
657       !(instance->debug_flags & DZN_DEBUG_NO_BINDLESS);
658    bool support_8bit = driQueryOptionb(&instance->dri_options, "dzn_enable_8bit_loads_stores") &&
659       pdev->options4.Native16BitShaderOpsSupported;
660 
661    *features = (struct vk_features) {
662       .robustBufferAccess = true, /* This feature is mandatory */
663       .fullDrawIndexUint32 = false,
664       .imageCubeArray = true,
665       .independentBlend = true,
666       .geometryShader = true,
667       .tessellationShader = false,
668       .sampleRateShading = true,
669       .dualSrcBlend = false,
670       .logicOp = false,
671       .multiDrawIndirect = true,
672       .drawIndirectFirstInstance = true,
673       .depthClamp = true,
674       .depthBiasClamp = true,
675       .fillModeNonSolid = true,
676       .depthBounds = pdev->options2.DepthBoundsTestSupported,
677       .wideLines = driQueryOptionb(&instance->dri_options, "dzn_claim_wide_lines"),
678       .largePoints = false,
679       .alphaToOne = false,
680       .multiViewport = false,
681       .samplerAnisotropy = true,
682       .textureCompressionETC2 = false,
683       .textureCompressionASTC_LDR = false,
684       .textureCompressionBC = true,
685       .occlusionQueryPrecise = true,
686       .pipelineStatisticsQuery = true,
687       .vertexPipelineStoresAndAtomics = true,
688       .fragmentStoresAndAtomics = true,
689       .shaderTessellationAndGeometryPointSize = false,
690       .shaderImageGatherExtended = true,
691       .shaderStorageImageExtendedFormats = pdev->options.TypedUAVLoadAdditionalFormats,
692       .shaderStorageImageMultisample = false,
693       .shaderStorageImageReadWithoutFormat = true,
694       .shaderStorageImageWriteWithoutFormat = true,
695       .shaderUniformBufferArrayDynamicIndexing = true,
696       .shaderSampledImageArrayDynamicIndexing = true,
697       .shaderStorageBufferArrayDynamicIndexing = true,
698       .shaderStorageImageArrayDynamicIndexing = true,
699       .shaderClipDistance = true,
700       .shaderCullDistance = true,
701       .shaderFloat64 = pdev->options.DoublePrecisionFloatShaderOps,
702       .shaderInt64 = pdev->options1.Int64ShaderOps,
703       .shaderInt16 = pdev->options4.Native16BitShaderOpsSupported,
704       .shaderResourceResidency = false,
705       .shaderResourceMinLod = false,
706       .sparseBinding = false,
707       .sparseResidencyBuffer = false,
708       .sparseResidencyImage2D = false,
709       .sparseResidencyImage3D = false,
710       .sparseResidency2Samples = false,
711       .sparseResidency4Samples = false,
712       .sparseResidency8Samples = false,
713       .sparseResidency16Samples = false,
714       .sparseResidencyAliased = false,
715       .variableMultisampleRate = false,
716       .inheritedQueries = false,
717 
718       .storageBuffer16BitAccess           = pdev->options4.Native16BitShaderOpsSupported,
719       .uniformAndStorageBuffer16BitAccess = pdev->options4.Native16BitShaderOpsSupported,
720       .storagePushConstant16              = false,
721       .storageInputOutput16               = false,
722       .multiview                          = true,
723       .multiviewGeometryShader            = true,
724       .multiviewTessellationShader        = false,
725       .variablePointersStorageBuffer      = false,
726       .variablePointers                   = false,
727       .protectedMemory                    = false,
728       .samplerYcbcrConversion             = false,
729       .shaderDrawParameters               = true,
730 
731       .samplerMirrorClampToEdge           = true,
732       .drawIndirectCount                  = true,
733       .storageBuffer8BitAccess            = support_8bit,
734       .uniformAndStorageBuffer8BitAccess  = support_8bit,
735       .storagePushConstant8               = support_8bit,
736       .shaderBufferInt64Atomics           = false,
737       .shaderSharedInt64Atomics           = false,
738       .shaderFloat16                      = pdev->options4.Native16BitShaderOpsSupported,
739       .shaderInt8                         = support_8bit,
740 
741       .descriptorIndexing                                   = support_descriptor_indexing,
742       .shaderInputAttachmentArrayDynamicIndexing            = true,
743       .shaderUniformTexelBufferArrayDynamicIndexing         = true,
744       .shaderStorageTexelBufferArrayDynamicIndexing         = true,
745       .shaderUniformBufferArrayNonUniformIndexing           = support_descriptor_indexing,
746       .shaderSampledImageArrayNonUniformIndexing            = support_descriptor_indexing,
747       .shaderStorageBufferArrayNonUniformIndexing           = support_descriptor_indexing,
748       .shaderStorageImageArrayNonUniformIndexing            = support_descriptor_indexing,
749       .shaderInputAttachmentArrayNonUniformIndexing         = support_descriptor_indexing,
750       .shaderUniformTexelBufferArrayNonUniformIndexing      = support_descriptor_indexing,
751       .shaderStorageTexelBufferArrayNonUniformIndexing      = support_descriptor_indexing,
752       .descriptorBindingUniformBufferUpdateAfterBind        = support_descriptor_indexing,
753       .descriptorBindingSampledImageUpdateAfterBind         = support_descriptor_indexing,
754       .descriptorBindingStorageImageUpdateAfterBind         = support_descriptor_indexing,
755       .descriptorBindingStorageBufferUpdateAfterBind        = support_descriptor_indexing,
756       .descriptorBindingUniformTexelBufferUpdateAfterBind   = support_descriptor_indexing,
757       .descriptorBindingStorageTexelBufferUpdateAfterBind   = support_descriptor_indexing,
758       .descriptorBindingUpdateUnusedWhilePending            = support_descriptor_indexing,
759       .descriptorBindingPartiallyBound                      = support_descriptor_indexing,
760       .descriptorBindingVariableDescriptorCount             = support_descriptor_indexing,
761       .runtimeDescriptorArray                               = support_descriptor_indexing,
762 
763       .samplerFilterMinmax                = false,
764       .scalarBlockLayout                  = true,
765       .imagelessFramebuffer               = true,
766       .uniformBufferStandardLayout        = true,
767       .shaderSubgroupExtendedTypes        = true,
768       .separateDepthStencilLayouts        = true,
769       .hostQueryReset                     = true,
770       .timelineSemaphore                  = true,
771       .bufferDeviceAddress                = pdev->shader_model >= D3D_SHADER_MODEL_6_6,
772       .bufferDeviceAddressCaptureReplay   = false,
773       .bufferDeviceAddressMultiDevice     = false,
774       .vulkanMemoryModel                  = false,
775       .vulkanMemoryModelDeviceScope       = false,
776       .vulkanMemoryModelAvailabilityVisibilityChains = false,
777       .shaderOutputViewportIndex          = false,
778       .shaderOutputLayer                  = false,
779       .subgroupBroadcastDynamicId         = true,
780 
781       .robustImageAccess                  = false,
782       .inlineUniformBlock                 = false,
783       .descriptorBindingInlineUniformBlockUpdateAfterBind = false,
784       .pipelineCreationCacheControl       = false,
785       .privateData                        = true,
786       .shaderDemoteToHelperInvocation     = false,
787       .shaderTerminateInvocation          = false,
788       .subgroupSizeControl                = pdev->options1.WaveOps && pdev->shader_model >= D3D_SHADER_MODEL_6_6,
789       .computeFullSubgroups               = true,
790       .synchronization2                   = true,
791       .textureCompressionASTC_HDR         = false,
792       .shaderZeroInitializeWorkgroupMemory = false,
793       .dynamicRendering                   = true,
794       .shaderIntegerDotProduct            = true,
795       .maintenance4                       = false,
796       .shaderExpectAssume                 = true,
797 
798       .vertexAttributeInstanceRateDivisor = true,
799       .vertexAttributeInstanceRateZeroDivisor = true,
800       .shaderReplicatedComposites         = true,
801    };
802 }
803 
804 static void
dzn_physical_device_get_properties(const struct dzn_physical_device * pdev,struct vk_properties * properties)805 dzn_physical_device_get_properties(const struct dzn_physical_device *pdev,
806                                    struct vk_properties *properties)
807 {
808    /* minimum from the D3D and Vulkan specs */
809    const VkSampleCountFlags supported_sample_counts = VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT;
810 
811    VkPhysicalDeviceType devtype = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
812    if (pdev->desc.is_warp)
813       devtype = VK_PHYSICAL_DEVICE_TYPE_CPU;
814    else if (!pdev->architecture.UMA) {
815       devtype = VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU;
816    }
817 
818    *properties = (struct vk_properties){
819       .apiVersion = DZN_API_VERSION,
820       .driverVersion = vk_get_driver_version(),
821 
822       .vendorID = pdev->desc.vendor_id,
823       .deviceID = pdev->desc.device_id,
824       .deviceType = devtype,
825 
826       /* Limits */
827       .maxImageDimension1D = D3D12_REQ_TEXTURE1D_U_DIMENSION,
828       .maxImageDimension2D = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION,
829       .maxImageDimension3D = D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION,
830       .maxImageDimensionCube = D3D12_REQ_TEXTURECUBE_DIMENSION,
831       .maxImageArrayLayers = D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION,
832 
833       /* from here on, we simply use the minimum values from the spec for now */
834       .maxTexelBufferElements = 1 << D3D12_REQ_BUFFER_RESOURCE_TEXEL_COUNT_2_TO_EXP,
835       .maxUniformBufferRange = D3D12_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * D3D12_STANDARD_VECTOR_SIZE * sizeof(float),
836       .maxStorageBufferRange = 1 << D3D12_REQ_BUFFER_RESOURCE_TEXEL_COUNT_2_TO_EXP,
837       .maxPushConstantsSize = 128,
838       .maxMemoryAllocationCount = 4096,
839       .maxSamplerAllocationCount = 4000,
840       .bufferImageGranularity = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT,
841       .sparseAddressSpaceSize = 0,
842       .maxBoundDescriptorSets = MAX_SETS,
843       .maxPerStageDescriptorSamplers =
844          pdev->options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1 ?
845          16u : MAX_DESCS_PER_SAMPLER_HEAP,
846       .maxPerStageDescriptorUniformBuffers =
847          pdev->options.ResourceBindingTier <= D3D12_RESOURCE_BINDING_TIER_2 ?
848          14u : MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
849       .maxPerStageDescriptorStorageBuffers =
850          pdev->options.ResourceBindingTier <= D3D12_RESOURCE_BINDING_TIER_2 ?
851          64u : MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
852       .maxPerStageDescriptorSampledImages =
853          pdev->options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1 ?
854          128u : MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
855       .maxPerStageDescriptorStorageImages =
856          pdev->options.ResourceBindingTier <= D3D12_RESOURCE_BINDING_TIER_2 ?
857          64u : MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
858       .maxPerStageDescriptorInputAttachments =
859          pdev->options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1 ?
860          128u : MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
861       .maxPerStageResources = MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
862       .maxDescriptorSetSamplers = MAX_DESCS_PER_SAMPLER_HEAP,
863       .maxDescriptorSetUniformBuffers = MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
864       .maxDescriptorSetUniformBuffersDynamic = MAX_DYNAMIC_UNIFORM_BUFFERS,
865       .maxDescriptorSetStorageBuffers = MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
866       .maxDescriptorSetStorageBuffersDynamic = MAX_DYNAMIC_STORAGE_BUFFERS,
867       .maxDescriptorSetSampledImages = MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
868       .maxDescriptorSetStorageImages = MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
869       .maxDescriptorSetInputAttachments = MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
870       .maxVertexInputAttributes = MIN2(D3D12_STANDARD_VERTEX_ELEMENT_COUNT, MAX_VERTEX_GENERIC_ATTRIBS),
871       .maxVertexInputBindings = MAX_VBS,
872       .maxVertexInputAttributeOffset = D3D12_REQ_MULTI_ELEMENT_STRUCTURE_SIZE_IN_BYTES - 1,
873       .maxVertexInputBindingStride = D3D12_REQ_MULTI_ELEMENT_STRUCTURE_SIZE_IN_BYTES,
874       .maxVertexOutputComponents = D3D12_VS_OUTPUT_REGISTER_COUNT * D3D12_VS_OUTPUT_REGISTER_COMPONENTS,
875       .maxTessellationGenerationLevel = 0,
876       .maxTessellationPatchSize = 0,
877       .maxTessellationControlPerVertexInputComponents = 0,
878       .maxTessellationControlPerVertexOutputComponents = 0,
879       .maxTessellationControlPerPatchOutputComponents = 0,
880       .maxTessellationControlTotalOutputComponents = 0,
881       .maxTessellationEvaluationInputComponents = 0,
882       .maxTessellationEvaluationOutputComponents = 0,
883       .maxGeometryShaderInvocations = D3D12_GS_MAX_INSTANCE_COUNT,
884       .maxGeometryInputComponents = D3D12_GS_INPUT_REGISTER_COUNT * D3D12_GS_INPUT_REGISTER_COMPONENTS,
885       .maxGeometryOutputComponents = D3D12_GS_OUTPUT_REGISTER_COUNT * D3D12_GS_OUTPUT_REGISTER_COMPONENTS,
886       .maxGeometryOutputVertices = D3D12_GS_MAX_OUTPUT_VERTEX_COUNT_ACROSS_INSTANCES,
887       .maxGeometryTotalOutputComponents = D3D12_REQ_GS_INVOCATION_32BIT_OUTPUT_COMPONENT_LIMIT,
888       .maxFragmentInputComponents = D3D12_PS_INPUT_REGISTER_COUNT * D3D12_PS_INPUT_REGISTER_COMPONENTS,
889       .maxFragmentOutputAttachments = D3D12_PS_OUTPUT_REGISTER_COUNT,
890       .maxFragmentDualSrcAttachments = 0,
891       .maxFragmentCombinedOutputResources = D3D12_PS_OUTPUT_REGISTER_COUNT,
892       .maxComputeSharedMemorySize = D3D12_CS_TGSM_REGISTER_COUNT * sizeof(float),
893       .maxComputeWorkGroupCount = { D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION,
894                                                     D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION,
895                                                     D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION },
896       .maxComputeWorkGroupInvocations = D3D12_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP,
897       .maxComputeWorkGroupSize = { D3D12_CS_THREAD_GROUP_MAX_X, D3D12_CS_THREAD_GROUP_MAX_Y, D3D12_CS_THREAD_GROUP_MAX_Z },
898       .subPixelPrecisionBits = D3D12_SUBPIXEL_FRACTIONAL_BIT_COUNT,
899       .subTexelPrecisionBits = D3D12_SUBTEXEL_FRACTIONAL_BIT_COUNT,
900       .mipmapPrecisionBits = D3D12_MIP_LOD_FRACTIONAL_BIT_COUNT,
901       .maxDrawIndexedIndexValue = 0x00ffffff,
902       .maxDrawIndirectCount = UINT32_MAX,
903       .maxSamplerLodBias = D3D12_MIP_LOD_BIAS_MAX,
904       .maxSamplerAnisotropy = D3D12_REQ_MAXANISOTROPY,
905       .maxViewports = MAX_VP,
906       .maxViewportDimensions = { D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION, D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION },
907       .viewportBoundsRange = { D3D12_VIEWPORT_BOUNDS_MIN, D3D12_VIEWPORT_BOUNDS_MAX },
908       .viewportSubPixelBits = 0,
909       .minMemoryMapAlignment = 64,
910       .minTexelBufferOffsetAlignment = 32,
911       .minUniformBufferOffsetAlignment = D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT,
912       .minStorageBufferOffsetAlignment = D3D12_RAW_UAV_SRV_BYTE_ALIGNMENT,
913       .minTexelOffset = D3D12_COMMONSHADER_TEXEL_OFFSET_MAX_NEGATIVE,
914       .maxTexelOffset = D3D12_COMMONSHADER_TEXEL_OFFSET_MAX_POSITIVE,
915       .minTexelGatherOffset = -32,
916       .maxTexelGatherOffset = 31,
917       .minInterpolationOffset = -0.5f,
918       .maxInterpolationOffset = 0.5f,
919       .subPixelInterpolationOffsetBits = 4,
920       .maxFramebufferWidth = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION,
921       .maxFramebufferHeight = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION,
922       .maxFramebufferLayers = D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION,
923       .framebufferColorSampleCounts = supported_sample_counts,
924       .framebufferDepthSampleCounts = supported_sample_counts,
925       .framebufferStencilSampleCounts = supported_sample_counts,
926       .framebufferNoAttachmentsSampleCounts = supported_sample_counts,
927       .maxColorAttachments = MAX_RTS,
928       .sampledImageColorSampleCounts = supported_sample_counts,
929       .sampledImageIntegerSampleCounts = VK_SAMPLE_COUNT_1_BIT,
930       .sampledImageDepthSampleCounts = supported_sample_counts,
931       .sampledImageStencilSampleCounts = supported_sample_counts,
932       .storageImageSampleCounts = VK_SAMPLE_COUNT_1_BIT,
933       .maxSampleMaskWords = 1,
934       .timestampComputeAndGraphics = true,
935       .timestampPeriod = pdev->timestamp_period,
936       .maxClipDistances = D3D12_CLIP_OR_CULL_DISTANCE_COUNT,
937       .maxCullDistances = D3D12_CLIP_OR_CULL_DISTANCE_COUNT,
938       .maxCombinedClipAndCullDistances = D3D12_CLIP_OR_CULL_DISTANCE_COUNT,
939       .discreteQueuePriorities = 2,
940       .pointSizeRange = { 1.0f, 1.0f },
941       .lineWidthRange = { 1.0f, 1.0f },
942       .pointSizeGranularity = 0.0f,
943       .lineWidthGranularity = 0.0f,
944       .strictLines = 0,
945       .standardSampleLocations = true,
946       .optimalBufferCopyOffsetAlignment = D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT,
947       .optimalBufferCopyRowPitchAlignment = D3D12_TEXTURE_DATA_PITCH_ALIGNMENT,
948       .nonCoherentAtomSize = 256,
949 
950       /* Core 1.1 */
951       .deviceLUIDValid = true,
952       .pointClippingBehavior = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES,
953       .maxMultiviewViewCount = 6,
954       .maxMultiviewInstanceIndex = UINT_MAX,
955       .protectedNoFault = false,
956       /* Vulkan 1.1 wants this value to be at least 1024. Let's stick to this
957        * minimum requirement for now, and hope the total number of samplers
958        * across all descriptor sets doesn't exceed 2048, otherwise we'd exceed
959        * the maximum number of samplers per heap. For any descriptor set
960        * containing more than 1024 descriptors,
961        * vkGetDescriptorSetLayoutSupport() can be called to determine if the
962        * layout is within D3D12 descriptor heap bounds.
963        */
964       .maxPerSetDescriptors = 1024,
965       /* According to the spec, the maximum D3D12 resource size is
966        * min(max(128MB, 0.25f * (amount of dedicated VRAM)), 2GB),
967        * but the limit actually depends on the max(system_ram, VRAM) not
968        * just the VRAM.
969        */
970       .maxMemoryAllocationSize =
971          CLAMP(MAX2(pdev->desc.dedicated_video_memory,
972                     pdev->desc.dedicated_system_memory +
973                     pdev->desc.shared_system_memory) / 4,
974                128ull * 1024 * 1024, 2ull * 1024 * 1024 * 1024),
975       .subgroupSupportedOperations = VK_SUBGROUP_FEATURE_BASIC_BIT |
976                                      VK_SUBGROUP_FEATURE_BALLOT_BIT |
977                                      VK_SUBGROUP_FEATURE_VOTE_BIT |
978                                      VK_SUBGROUP_FEATURE_SHUFFLE_BIT |
979                                      VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT |
980                                      VK_SUBGROUP_FEATURE_QUAD_BIT |
981                                      VK_SUBGROUP_FEATURE_ARITHMETIC_BIT,
982       .subgroupSupportedStages = VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_COMPUTE_BIT |
983                                  VK_SHADER_STAGE_GEOMETRY_BIT | VK_SHADER_STAGE_VERTEX_BIT,
984       .subgroupQuadOperationsInAllStages = true,
985       .subgroupSize = pdev->options1.WaveOps ? pdev->options1.WaveLaneCountMin : 1,
986 
987       /* Core 1.2 */
988       .driverID = VK_DRIVER_ID_MESA_DOZEN,
989       .conformanceVersion = (VkConformanceVersion){
990          .major = 0,
991          .minor = 0,
992          .subminor = 0,
993          .patch = 0,
994       },
995       .denormBehaviorIndependence = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL,
996       .roundingModeIndependence = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL,
997       .shaderSignedZeroInfNanPreserveFloat16 = false,
998       .shaderSignedZeroInfNanPreserveFloat32 = false,
999       .shaderSignedZeroInfNanPreserveFloat64 = false,
1000       .shaderDenormPreserveFloat16 = true,
1001       .shaderDenormPreserveFloat32 = pdev->shader_model >= D3D_SHADER_MODEL_6_2,
1002       .shaderDenormPreserveFloat64 = true,
1003       .shaderDenormFlushToZeroFloat16 = false,
1004       .shaderDenormFlushToZeroFloat32 = true,
1005       .shaderDenormFlushToZeroFloat64 = false,
1006       .shaderRoundingModeRTEFloat16 = true,
1007       .shaderRoundingModeRTEFloat32 = true,
1008       .shaderRoundingModeRTEFloat64 = true,
1009       .shaderRoundingModeRTZFloat16 = false,
1010       .shaderRoundingModeRTZFloat32 = false,
1011       .shaderRoundingModeRTZFloat64 = false,
1012       .shaderUniformBufferArrayNonUniformIndexingNative = true,
1013       .shaderSampledImageArrayNonUniformIndexingNative = true,
1014       .shaderStorageBufferArrayNonUniformIndexingNative = true,
1015       .shaderStorageImageArrayNonUniformIndexingNative = true,
1016       .shaderInputAttachmentArrayNonUniformIndexingNative = true,
1017       .robustBufferAccessUpdateAfterBind = true,
1018       .quadDivergentImplicitLod = false,
1019       .maxUpdateAfterBindDescriptorsInAllPools = MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
1020       .maxPerStageDescriptorUpdateAfterBindSamplers = MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
1021       .maxPerStageDescriptorUpdateAfterBindUniformBuffers = MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
1022       .maxPerStageDescriptorUpdateAfterBindStorageBuffers = MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
1023       .maxPerStageDescriptorUpdateAfterBindSampledImages = MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
1024       .maxPerStageDescriptorUpdateAfterBindStorageImages = MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
1025       .maxPerStageDescriptorUpdateAfterBindInputAttachments = MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
1026       .maxPerStageUpdateAfterBindResources = MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
1027       .maxDescriptorSetUpdateAfterBindSamplers = MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
1028       .maxDescriptorSetUpdateAfterBindUniformBuffers = MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
1029       .maxDescriptorSetUpdateAfterBindUniformBuffersDynamic = MAX_DYNAMIC_UNIFORM_BUFFERS,
1030       .maxDescriptorSetUpdateAfterBindStorageBuffers = MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
1031       .maxDescriptorSetUpdateAfterBindStorageBuffersDynamic = MAX_DYNAMIC_STORAGE_BUFFERS,
1032       .maxDescriptorSetUpdateAfterBindSampledImages = MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
1033       .maxDescriptorSetUpdateAfterBindStorageImages = MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
1034       .maxDescriptorSetUpdateAfterBindInputAttachments = MAX_DESCS_PER_CBV_SRV_UAV_HEAP,
1035 
1036       .supportedDepthResolveModes = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT | VK_RESOLVE_MODE_AVERAGE_BIT |
1037          VK_RESOLVE_MODE_MIN_BIT | VK_RESOLVE_MODE_MAX_BIT,
1038       .supportedStencilResolveModes = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT | VK_RESOLVE_MODE_MIN_BIT | VK_RESOLVE_MODE_MAX_BIT,
1039       .independentResolveNone = true,
1040       .independentResolve = true,
1041       .filterMinmaxSingleComponentFormats = false,
1042       .filterMinmaxImageComponentMapping = false,
1043       .maxTimelineSemaphoreValueDifference = UINT64_MAX,
1044       .framebufferIntegerColorSampleCounts = VK_SAMPLE_COUNT_1_BIT,
1045 
1046       /* Core 1.3 */
1047       .minSubgroupSize = pdev->options1.WaveOps ? pdev->options1.WaveLaneCountMin : 1,
1048       .maxSubgroupSize = pdev->options1.WaveOps ? pdev->options1.WaveLaneCountMax : 1,
1049       .maxComputeWorkgroupSubgroups = D3D12_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP /
1050          (pdev->options1.WaveOps ? pdev->options1.WaveLaneCountMin : 1),
1051       .requiredSubgroupSizeStages = VK_SHADER_STAGE_COMPUTE_BIT,
1052       .integerDotProduct4x8BitPackedSignedAccelerated = pdev->shader_model >= D3D_SHADER_MODEL_6_4,
1053       .integerDotProduct4x8BitPackedUnsignedAccelerated = pdev->shader_model >= D3D_SHADER_MODEL_6_4,
1054       .integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated = pdev->shader_model >= D3D_SHADER_MODEL_6_4,
1055       .integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated = pdev->shader_model >= D3D_SHADER_MODEL_6_4,
1056 
1057       /* VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT */
1058       .maxVertexAttribDivisor = UINT32_MAX,
1059 
1060       /* VkPhysicalDeviceExternalMemoryHostPropertiesEXT */
1061       .minImportedHostPointerAlignment = 65536,
1062 
1063       /* VkPhysicalDeviceLayeredDriverPropertiesMSFT */
1064       .underlyingAPI = VK_LAYERED_DRIVER_UNDERLYING_API_D3D12_MSFT,
1065    };
1066 
1067    snprintf(properties->deviceName,
1068             sizeof(properties->deviceName),
1069             "Microsoft Direct3D12 (%s)", pdev->desc.description);
1070    memcpy(properties->pipelineCacheUUID,
1071           pdev->pipeline_cache_uuid, VK_UUID_SIZE);
1072    memcpy(properties->driverUUID, pdev->driver_uuid, VK_UUID_SIZE);
1073    memcpy(properties->deviceUUID, pdev->device_uuid, VK_UUID_SIZE);
1074    memcpy(properties->deviceLUID, &pdev->desc.adapter_luid, VK_LUID_SIZE);
1075 
1076    STATIC_ASSERT(sizeof(pdev->desc.adapter_luid) == sizeof(properties->deviceLUID));
1077 
1078    snprintf(properties->driverName, VK_MAX_DRIVER_NAME_SIZE, "Dozen");
1079    snprintf(properties->driverInfo, VK_MAX_DRIVER_INFO_SIZE, "Mesa " PACKAGE_VERSION MESA_GIT_SHA1);
1080 }
1081 
1082 static VkResult
dzn_physical_device_create(struct vk_instance * instance,IUnknown * adapter,const struct dzn_physical_device_desc * desc)1083 dzn_physical_device_create(struct vk_instance *instance,
1084                            IUnknown *adapter,
1085                            const struct dzn_physical_device_desc *desc)
1086 {
1087    struct dzn_physical_device *pdev =
1088       vk_zalloc(&instance->alloc, sizeof(*pdev), 8,
1089                 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1090 
1091    if (!pdev)
1092       return vk_error(instance, VK_ERROR_OUT_OF_HOST_MEMORY);
1093 
1094    struct vk_physical_device_dispatch_table dispatch_table;
1095    vk_physical_device_dispatch_table_from_entrypoints(&dispatch_table,
1096                                                       &dzn_physical_device_entrypoints,
1097                                                       true);
1098    vk_physical_device_dispatch_table_from_entrypoints(&dispatch_table,
1099                                                       &wsi_physical_device_entrypoints,
1100                                                       false);
1101 
1102    VkResult result =
1103       vk_physical_device_init(&pdev->vk, instance,
1104                               NULL, NULL, NULL, /* We set up extensions later */
1105                               &dispatch_table);
1106    if (result != VK_SUCCESS) {
1107       vk_free(&instance->alloc, pdev);
1108       return result;
1109    }
1110 
1111    pdev->desc = *desc;
1112    pdev->adapter = adapter;
1113    IUnknown_AddRef(adapter);
1114    list_addtail(&pdev->vk.link, &instance->physical_devices.list);
1115 
1116    vk_warn_non_conformant_implementation("dzn");
1117 
1118    struct dzn_instance *dzn_instance = container_of(instance, struct dzn_instance, vk);
1119 
1120    uint32_t num_sync_types = 0;
1121    pdev->sync_types[num_sync_types++] = &dzn_sync_type;
1122    pdev->sync_types[num_sync_types++] = &dzn_instance->sync_binary_type.sync;
1123    pdev->sync_types[num_sync_types++] = &vk_sync_dummy_type;
1124    pdev->sync_types[num_sync_types] = NULL;
1125    assert(num_sync_types <= MAX_SYNC_TYPES);
1126    pdev->vk.supported_sync_types = pdev->sync_types;
1127 
1128    pdev->vk.pipeline_cache_import_ops = dzn_pipeline_cache_import_ops;
1129 
1130    pdev->dev = d3d12_create_device(dzn_instance->d3d12_mod,
1131                                    pdev->adapter,
1132                                    dzn_instance->factory,
1133                                    !dzn_instance->dxil_validator);
1134    if (!pdev->dev) {
1135       list_del(&pdev->vk.link);
1136       dzn_physical_device_destroy(&pdev->vk);
1137       return vk_error(instance, VK_ERROR_INITIALIZATION_FAILED);
1138    }
1139 
1140    if (FAILED(ID3D12Device1_QueryInterface(pdev->dev, &IID_ID3D12Device10, (void **)&pdev->dev10)))
1141       pdev->dev10 = NULL;
1142    if (FAILED(ID3D12Device1_QueryInterface(pdev->dev, &IID_ID3D12Device11, (void **)&pdev->dev11)))
1143       pdev->dev11 = NULL;
1144    if (FAILED(ID3D12Device1_QueryInterface(pdev->dev, &IID_ID3D12Device12, (void **)&pdev->dev12)))
1145       pdev->dev12 = NULL;
1146    if (FAILED(ID3D12Device1_QueryInterface(pdev->dev, &IID_ID3D12Device13, (void **)&pdev->dev13)))
1147       pdev->dev13 = NULL;
1148    dzn_physical_device_cache_caps(pdev);
1149    dzn_physical_device_init_memory(pdev);
1150    dzn_physical_device_init_uuids(pdev);
1151 
1152    if (dzn_instance->debug_flags & DZN_DEBUG_MULTIVIEW)
1153       pdev->options3.ViewInstancingTier = D3D12_VIEW_INSTANCING_TIER_NOT_SUPPORTED;
1154 
1155    dzn_physical_device_get_extensions(pdev);
1156    if (driQueryOptionb(&dzn_instance->dri_options, "dzn_enable_8bit_loads_stores") &&
1157        pdev->options4.Native16BitShaderOpsSupported)
1158       pdev->vk.supported_extensions.KHR_8bit_storage = true;
1159    if (dzn_instance->debug_flags & DZN_DEBUG_NO_BINDLESS)
1160       pdev->vk.supported_extensions.EXT_descriptor_indexing = false;
1161    dzn_physical_device_get_features(pdev, &pdev->vk.supported_features);
1162    dzn_physical_device_get_properties(pdev, &pdev->vk.properties);
1163 
1164    result = dzn_wsi_init(pdev);
1165    if (result != VK_SUCCESS || !pdev->dev) {
1166       list_del(&pdev->vk.link);
1167       dzn_physical_device_destroy(&pdev->vk);
1168       return result;
1169    }
1170 
1171    return VK_SUCCESS;
1172 }
1173 
1174 static DXGI_FORMAT
dzn_get_most_capable_format_for_casting(VkFormat format,VkImageCreateFlags create_flags)1175 dzn_get_most_capable_format_for_casting(VkFormat format, VkImageCreateFlags create_flags)
1176 {
1177    enum pipe_format pfmt = vk_format_to_pipe_format(format);
1178    bool block_compressed = util_format_is_compressed(pfmt);
1179    if (block_compressed &&
1180        !(create_flags & VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT))
1181       return dzn_image_get_dxgi_format(NULL, format, 0, 0);
1182    unsigned blksz = util_format_get_blocksize(pfmt);
1183    switch (blksz) {
1184    case 1: return DXGI_FORMAT_R8_UNORM;
1185    case 2: return DXGI_FORMAT_R16_UNORM;
1186    case 4: return DXGI_FORMAT_R32_FLOAT;
1187    case 8: return DXGI_FORMAT_R32G32_FLOAT;
1188    case 12: return DXGI_FORMAT_R32G32B32_FLOAT;
1189    case 16: return DXGI_FORMAT_R32G32B32A32_FLOAT;
1190    default: unreachable("Unsupported format bit size");;
1191    }
1192 }
1193 
1194 D3D12_FEATURE_DATA_FORMAT_SUPPORT
dzn_physical_device_get_format_support(struct dzn_physical_device * pdev,VkFormat format,VkImageCreateFlags create_flags)1195 dzn_physical_device_get_format_support(struct dzn_physical_device *pdev,
1196                                        VkFormat format,
1197                                        VkImageCreateFlags create_flags)
1198 {
1199    VkImageUsageFlags usage =
1200       vk_format_is_depth_or_stencil(format) ?
1201       VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT : 0;
1202    VkImageAspectFlags aspects = 0;
1203 
1204    if (vk_format_has_depth(format))
1205       aspects = VK_IMAGE_ASPECT_DEPTH_BIT;
1206    if (vk_format_has_stencil(format))
1207       aspects = VK_IMAGE_ASPECT_STENCIL_BIT;
1208 
1209    D3D12_FEATURE_DATA_FORMAT_SUPPORT dfmt_info = {
1210      .Format = dzn_image_get_dxgi_format(pdev, format, usage, aspects),
1211    };
1212 
1213    /* KHR_maintenance2: If an image is created with the extended usage flag
1214     * (or if properties are queried with that flag), then if any compatible
1215     * format can support a given usage, it should be considered supported.
1216     * With the exception of depth, which are limited in their cast set,
1217     * we can do this by just picking a single most-capable format to query
1218     * the support for, instead of the originally requested format. */
1219    if (aspects == 0 && dfmt_info.Format != DXGI_FORMAT_UNKNOWN &&
1220        (create_flags & VK_IMAGE_CREATE_EXTENDED_USAGE_BIT)) {
1221       dfmt_info.Format = dzn_get_most_capable_format_for_casting(format, create_flags);
1222    }
1223 
1224    ASSERTED HRESULT hres =
1225       ID3D12Device1_CheckFeatureSupport(pdev->dev, D3D12_FEATURE_FORMAT_SUPPORT,
1226                                         &dfmt_info, sizeof(dfmt_info));
1227    assert(!FAILED(hres));
1228 
1229    if (usage != VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
1230       return dfmt_info;
1231 
1232    /* Depth/stencil resources have different format when they're accessed
1233     * as textures, query the capabilities for this format too.
1234     */
1235    dzn_foreach_aspect(aspect, aspects) {
1236       D3D12_FEATURE_DATA_FORMAT_SUPPORT dfmt_info2 = {
1237         .Format = dzn_image_get_dxgi_format(pdev, format, 0, aspect),
1238       };
1239 
1240       hres = ID3D12Device1_CheckFeatureSupport(pdev->dev, D3D12_FEATURE_FORMAT_SUPPORT,
1241                                       &dfmt_info2, sizeof(dfmt_info2));
1242       assert(!FAILED(hres));
1243 
1244 #define DS_SRV_FORMAT_SUPPORT1_MASK \
1245         (D3D12_FORMAT_SUPPORT1_SHADER_LOAD | \
1246          D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE | \
1247          D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE_COMPARISON | \
1248          D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE_MONO_TEXT | \
1249          D3D12_FORMAT_SUPPORT1_MULTISAMPLE_RESOLVE | \
1250          D3D12_FORMAT_SUPPORT1_MULTISAMPLE_LOAD | \
1251          D3D12_FORMAT_SUPPORT1_SHADER_GATHER | \
1252          D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW | \
1253          D3D12_FORMAT_SUPPORT1_SHADER_GATHER_COMPARISON)
1254 
1255       dfmt_info.Support1 |= dfmt_info2.Support1 & DS_SRV_FORMAT_SUPPORT1_MASK;
1256       dfmt_info.Support2 |= dfmt_info2.Support2;
1257    }
1258 
1259    return dfmt_info;
1260 }
1261 
1262 static void
dzn_physical_device_get_format_properties(struct dzn_physical_device * pdev,VkFormat format,VkFormatProperties2 * properties)1263 dzn_physical_device_get_format_properties(struct dzn_physical_device *pdev,
1264                                           VkFormat format,
1265                                           VkFormatProperties2 *properties)
1266 {
1267    D3D12_FEATURE_DATA_FORMAT_SUPPORT dfmt_info =
1268       dzn_physical_device_get_format_support(pdev, format, 0);
1269    VkFormatProperties *base_props = &properties->formatProperties;
1270 
1271    vk_foreach_struct(ext, properties->pNext) {
1272       vk_debug_ignored_stype(ext->sType);
1273    }
1274 
1275    if (dfmt_info.Format == DXGI_FORMAT_UNKNOWN) {
1276       if (dzn_graphics_pipeline_patch_vi_format(format) != format)
1277          *base_props = (VkFormatProperties){
1278             .bufferFeatures = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT | VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT,
1279          };
1280       else
1281          *base_props = (VkFormatProperties) { 0 };
1282       return;
1283    }
1284 
1285    *base_props = (VkFormatProperties) {
1286       .linearTilingFeatures = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT,
1287       .optimalTilingFeatures = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT,
1288       .bufferFeatures = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT,
1289    };
1290 
1291    if (dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_IA_VERTEX_BUFFER)
1292       base_props->bufferFeatures |= VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT;
1293 
1294 #define TEX_FLAGS (D3D12_FORMAT_SUPPORT1_TEXTURE1D | \
1295                    D3D12_FORMAT_SUPPORT1_TEXTURE2D | \
1296                    D3D12_FORMAT_SUPPORT1_TEXTURE3D | \
1297                    D3D12_FORMAT_SUPPORT1_TEXTURECUBE)
1298    if ((dfmt_info.Support1 & TEX_FLAGS) &&
1299        (dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_SHADER_LOAD)) {
1300       base_props->optimalTilingFeatures |=
1301          VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_BLIT_SRC_BIT;
1302    }
1303 
1304    if (dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE) {
1305       base_props->optimalTilingFeatures |=
1306          VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
1307    }
1308 
1309    if ((dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_SHADER_LOAD) &&
1310        (dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW)) {
1311       base_props->optimalTilingFeatures |= VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT;
1312       if (dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_BUFFER)
1313          base_props->bufferFeatures |= VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT;
1314    }
1315 
1316 #define ATOMIC_FLAGS (D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_ADD | \
1317                       D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_BITWISE_OPS | \
1318                       D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_COMPARE_STORE_OR_COMPARE_EXCHANGE | \
1319                       D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_EXCHANGE | \
1320                       D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_SIGNED_MIN_OR_MAX | \
1321                       D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_UNSIGNED_MIN_OR_MAX)
1322    if ((dfmt_info.Support2 & ATOMIC_FLAGS) == ATOMIC_FLAGS) {
1323       base_props->optimalTilingFeatures |= VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT;
1324       base_props->bufferFeatures |= VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT;
1325    }
1326 
1327    if (dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_BUFFER)
1328       base_props->bufferFeatures |= VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT;
1329 
1330    /* Color/depth/stencil attachment cap implies input attachement cap, and input
1331     * attachment loads are lowered to texture loads in dozen, hence the requirement
1332     * to have shader-load support.
1333     */
1334    if (dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_SHADER_LOAD) {
1335       if (dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_RENDER_TARGET) {
1336          base_props->optimalTilingFeatures |=
1337             VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT;
1338       }
1339 
1340       if (dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_BLENDABLE)
1341          base_props->optimalTilingFeatures |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT;
1342 
1343       if (dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL) {
1344          base_props->optimalTilingFeatures |=
1345             VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT;
1346       }
1347    }
1348 
1349    /* B4G4R4A4 support is required, but d3d12 doesn't support it. The needed
1350     * d3d12 format would be A4R4G4B4. We map this format to d3d12's B4G4R4A4,
1351     * which is Vulkan's A4R4G4B4, and adjust the SRV component-mapping to fake
1352     * B4G4R4A4, but that forces us to limit the usage to sampling, which,
1353     * luckily, is exactly what we need to support the required features.
1354     *
1355     * However, since this involves swizzling the alpha channel, it can cause
1356     * problems for border colors. Fortunately, d3d12 added an A4B4G4R4 format,
1357     * which still isn't quite right (it'd be Vulkan R4G4B4A4), but can be
1358     * swizzled by just swapping R and B, so no border color issues arise.
1359     */
1360    if (format == VK_FORMAT_B4G4R4A4_UNORM_PACK16) {
1361       VkFormatFeatureFlags bgra4_req_features =
1362          VK_FORMAT_FEATURE_TRANSFER_SRC_BIT |
1363          VK_FORMAT_FEATURE_TRANSFER_DST_BIT |
1364          VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
1365          VK_FORMAT_FEATURE_BLIT_SRC_BIT |
1366          VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
1367       base_props->optimalTilingFeatures &= bgra4_req_features;
1368       base_props->bufferFeatures =
1369          VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT;
1370    }
1371 
1372    /* depth/stencil format shouldn't advertise buffer features */
1373    if (vk_format_is_depth_or_stencil(format))
1374       base_props->bufferFeatures = 0;
1375 }
1376 
1377 static VkResult
dzn_physical_device_get_image_format_properties(struct dzn_physical_device * pdev,const VkPhysicalDeviceImageFormatInfo2 * info,VkImageFormatProperties2 * properties)1378 dzn_physical_device_get_image_format_properties(struct dzn_physical_device *pdev,
1379                                                 const VkPhysicalDeviceImageFormatInfo2 *info,
1380                                                 VkImageFormatProperties2 *properties)
1381 {
1382    const VkPhysicalDeviceExternalImageFormatInfo *external_info = NULL;
1383    VkExternalImageFormatProperties *external_props = NULL;
1384 
1385    properties->imageFormatProperties = (VkImageFormatProperties) { 0 };
1386 
1387    VkImageUsageFlags usage = info->usage;
1388 
1389    /* Extract input structs */
1390    vk_foreach_struct_const(s, info->pNext) {
1391       switch (s->sType) {
1392       case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO:
1393          external_info = (const VkPhysicalDeviceExternalImageFormatInfo *)s;
1394          break;
1395       case VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO:
1396          usage |= ((const VkImageStencilUsageCreateInfo *)s)->stencilUsage;
1397          break;
1398       default:
1399          vk_debug_ignored_stype(s->sType);
1400          break;
1401       }
1402    }
1403 
1404    assert(info->tiling == VK_IMAGE_TILING_OPTIMAL || info->tiling == VK_IMAGE_TILING_LINEAR);
1405 
1406    /* Extract output structs */
1407    vk_foreach_struct(s, properties->pNext) {
1408       switch (s->sType) {
1409       case VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES:
1410          external_props = (VkExternalImageFormatProperties *)s;
1411          external_props->externalMemoryProperties = (VkExternalMemoryProperties) { 0 };
1412          break;
1413       default:
1414          vk_debug_ignored_stype(s->sType);
1415          break;
1416       }
1417    }
1418 
1419    if (external_info && external_info->handleType != 0) {
1420       const VkExternalMemoryHandleTypeFlags d3d12_resource_handle_types =
1421          VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT | opaque_external_flag;
1422       const VkExternalMemoryHandleTypeFlags d3d11_texture_handle_types =
1423          VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT | d3d12_resource_handle_types;
1424       const VkExternalMemoryFeatureFlags import_export_feature_flags =
1425          VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT;
1426       const VkExternalMemoryFeatureFlags dedicated_feature_flags =
1427          VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT | import_export_feature_flags;
1428 
1429       switch (external_info->handleType) {
1430       case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT:
1431          external_props->externalMemoryProperties.compatibleHandleTypes = d3d11_texture_handle_types;
1432          external_props->externalMemoryProperties.exportFromImportedHandleTypes = d3d11_texture_handle_types;
1433          external_props->externalMemoryProperties.externalMemoryFeatures = dedicated_feature_flags;
1434          break;
1435       case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT:
1436          external_props->externalMemoryProperties.compatibleHandleTypes = d3d12_resource_handle_types;
1437          external_props->externalMemoryProperties.exportFromImportedHandleTypes = d3d12_resource_handle_types;
1438          external_props->externalMemoryProperties.externalMemoryFeatures = dedicated_feature_flags;
1439          break;
1440       case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT:
1441          external_props->externalMemoryProperties.compatibleHandleTypes =
1442             external_props->externalMemoryProperties.exportFromImportedHandleTypes =
1443             VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT | opaque_external_flag;
1444          external_props->externalMemoryProperties.externalMemoryFeatures = import_export_feature_flags;
1445          break;
1446 #ifdef _WIN32
1447       case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT:
1448 #else
1449       case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT:
1450 #endif
1451          external_props->externalMemoryProperties.compatibleHandleTypes = d3d11_texture_handle_types;
1452          external_props->externalMemoryProperties.exportFromImportedHandleTypes = d3d11_texture_handle_types;
1453          external_props->externalMemoryProperties.externalMemoryFeatures = import_export_feature_flags;
1454          break;
1455 #if defined(_WIN32)
1456       case VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT:
1457          if (pdev->dev13) {
1458             external_props->externalMemoryProperties.compatibleHandleTypes =
1459                external_props->externalMemoryProperties.exportFromImportedHandleTypes =
1460                VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT | opaque_external_flag;
1461             external_props->externalMemoryProperties.externalMemoryFeatures = import_export_feature_flags;
1462             break;
1463          }
1464          FALLTHROUGH;
1465 #endif
1466       default:
1467          return VK_ERROR_FORMAT_NOT_SUPPORTED;
1468       }
1469 
1470       /* Linear textures not supported, but there's nothing else we can deduce from just a handle type */
1471       if (info->tiling != VK_IMAGE_TILING_OPTIMAL &&
1472           external_info->handleType != VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT)
1473          return VK_ERROR_FORMAT_NOT_SUPPORTED;
1474    }
1475 
1476    if (info->tiling != VK_IMAGE_TILING_OPTIMAL &&
1477        (usage & ~(VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT)))
1478       return VK_ERROR_FORMAT_NOT_SUPPORTED;
1479 
1480    if (info->tiling != VK_IMAGE_TILING_OPTIMAL &&
1481        vk_format_is_depth_or_stencil(info->format))
1482       return VK_ERROR_FORMAT_NOT_SUPPORTED;
1483 
1484    D3D12_FEATURE_DATA_FORMAT_SUPPORT dfmt_info =
1485       dzn_physical_device_get_format_support(pdev, info->format, info->flags);
1486    if (dfmt_info.Format == DXGI_FORMAT_UNKNOWN)
1487       return VK_ERROR_FORMAT_NOT_SUPPORTED;
1488 
1489    bool is_bgra4 = info->format == VK_FORMAT_B4G4R4A4_UNORM_PACK16 &&
1490       !(info->flags & VK_IMAGE_CREATE_EXTENDED_USAGE_BIT);
1491 
1492    if ((info->type == VK_IMAGE_TYPE_1D && !(dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURE1D)) ||
1493        (info->type == VK_IMAGE_TYPE_2D && !(dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURE2D)) ||
1494        (info->type == VK_IMAGE_TYPE_3D && !(dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURE3D)) ||
1495        ((info->flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) &&
1496         !(dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURECUBE)))
1497       return VK_ERROR_FORMAT_NOT_SUPPORTED;
1498 
1499    /* Due to extended capability querying, we might see 1D support for BC, but we don't actually have it */
1500    if (vk_format_is_block_compressed(info->format) && info->type == VK_IMAGE_TYPE_1D)
1501       return VK_ERROR_FORMAT_NOT_SUPPORTED;
1502 
1503    if ((usage & VK_IMAGE_USAGE_SAMPLED_BIT) &&
1504        /* Note: format support for SAMPLED is not necessarily accurate for integer formats */
1505        !(dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_SHADER_LOAD))
1506       return VK_ERROR_FORMAT_NOT_SUPPORTED;
1507 
1508    if ((usage & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) &&
1509        (!(dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_SHADER_LOAD) || is_bgra4))
1510       return VK_ERROR_FORMAT_NOT_SUPPORTED;
1511 
1512    if ((usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) &&
1513        (!(dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_RENDER_TARGET) || is_bgra4))
1514       return VK_ERROR_FORMAT_NOT_SUPPORTED;
1515 
1516    if ((usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) &&
1517        (!(dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL) || is_bgra4))
1518       return VK_ERROR_FORMAT_NOT_SUPPORTED;
1519 
1520    if ((usage & VK_IMAGE_USAGE_STORAGE_BIT) &&
1521        (!(dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW) || is_bgra4))
1522       return VK_ERROR_FORMAT_NOT_SUPPORTED;
1523 
1524    if (info->type == VK_IMAGE_TYPE_3D && info->tiling != VK_IMAGE_TILING_OPTIMAL)
1525       return VK_ERROR_FORMAT_NOT_SUPPORTED;
1526 
1527    bool is_3d = info->type == VK_IMAGE_TYPE_3D;
1528    uint32_t max_extent = dzn_physical_device_get_max_extent(is_3d);
1529 
1530    if (info->tiling == VK_IMAGE_TILING_OPTIMAL &&
1531        dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_MIP)
1532       properties->imageFormatProperties.maxMipLevels = dzn_physical_device_get_max_mip_level(is_3d) + 1;
1533    else
1534       properties->imageFormatProperties.maxMipLevels = 1;
1535 
1536    if (info->tiling == VK_IMAGE_TILING_OPTIMAL && info->type != VK_IMAGE_TYPE_3D)
1537       properties->imageFormatProperties.maxArrayLayers = dzn_physical_device_get_max_array_layers();
1538    else
1539       properties->imageFormatProperties.maxArrayLayers = 1;
1540 
1541    switch (info->type) {
1542    case VK_IMAGE_TYPE_1D:
1543       properties->imageFormatProperties.maxExtent.width = max_extent;
1544       properties->imageFormatProperties.maxExtent.height = 1;
1545       properties->imageFormatProperties.maxExtent.depth = 1;
1546       break;
1547    case VK_IMAGE_TYPE_2D:
1548       properties->imageFormatProperties.maxExtent.width = max_extent;
1549       properties->imageFormatProperties.maxExtent.height = max_extent;
1550       properties->imageFormatProperties.maxExtent.depth = 1;
1551       break;
1552    case VK_IMAGE_TYPE_3D:
1553       properties->imageFormatProperties.maxExtent.width = max_extent;
1554       properties->imageFormatProperties.maxExtent.height = max_extent;
1555       properties->imageFormatProperties.maxExtent.depth = max_extent;
1556       break;
1557    default:
1558       unreachable("bad VkImageType");
1559    }
1560 
1561    /* From the Vulkan 1.0 spec, section 34.1.1. Supported Sample Counts:
1562     *
1563     * sampleCounts will be set to VK_SAMPLE_COUNT_1_BIT if at least one of the
1564     * following conditions is true:
1565     *
1566     *   - tiling is VK_IMAGE_TILING_LINEAR
1567     *   - type is not VK_IMAGE_TYPE_2D
1568     *   - flags contains VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT
1569     *   - neither the VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT flag nor the
1570     *     VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT flag in
1571     *     VkFormatProperties::optimalTilingFeatures returned by
1572     *     vkGetPhysicalDeviceFormatProperties is set.
1573     *
1574     * D3D12 has a few more constraints:
1575     *   - no UAVs on multisample resources
1576     */
1577    properties->imageFormatProperties.sampleCounts = VK_SAMPLE_COUNT_1_BIT;
1578    if (info->tiling != VK_IMAGE_TILING_LINEAR &&
1579        info->type == VK_IMAGE_TYPE_2D &&
1580        !(info->flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) &&
1581        (dfmt_info.Support1 & D3D12_FORMAT_SUPPORT1_MULTISAMPLE_LOAD) &&
1582        !is_bgra4 &&
1583        !(usage & VK_IMAGE_USAGE_STORAGE_BIT)) {
1584       for (uint32_t s = VK_SAMPLE_COUNT_2_BIT; s < VK_SAMPLE_COUNT_64_BIT; s <<= 1) {
1585          D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS ms_info = {
1586             .Format = dfmt_info.Format,
1587             .SampleCount = s,
1588          };
1589 
1590          HRESULT hres =
1591             ID3D12Device1_CheckFeatureSupport(pdev->dev, D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,
1592                                      &ms_info, sizeof(ms_info));
1593          if (!FAILED(hres) && ms_info.NumQualityLevels > 0)
1594             properties->imageFormatProperties.sampleCounts |= s;
1595       }
1596    }
1597 
1598    /* TODO: set correct value here */
1599    properties->imageFormatProperties.maxResourceSize = UINT32_MAX;
1600 
1601    return VK_SUCCESS;
1602 }
1603 
1604 VKAPI_ATTR void VKAPI_CALL
dzn_GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice,VkFormat format,VkFormatProperties2 * pFormatProperties)1605 dzn_GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice,
1606                                        VkFormat format,
1607                                        VkFormatProperties2 *pFormatProperties)
1608 {
1609    VK_FROM_HANDLE(dzn_physical_device, pdev, physicalDevice);
1610 
1611    dzn_physical_device_get_format_properties(pdev, format, pFormatProperties);
1612 }
1613 
1614 VKAPI_ATTR VkResult VKAPI_CALL
dzn_GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice,const VkPhysicalDeviceImageFormatInfo2 * info,VkImageFormatProperties2 * props)1615 dzn_GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice,
1616                                             const VkPhysicalDeviceImageFormatInfo2 *info,
1617                                             VkImageFormatProperties2 *props)
1618 {
1619    VK_FROM_HANDLE(dzn_physical_device, pdev, physicalDevice);
1620 
1621    return dzn_physical_device_get_image_format_properties(pdev, info, props);
1622 }
1623 
1624 VKAPI_ATTR VkResult VKAPI_CALL
dzn_GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice,VkFormat format,VkImageType type,VkImageTiling tiling,VkImageUsageFlags usage,VkImageCreateFlags createFlags,VkImageFormatProperties * pImageFormatProperties)1625 dzn_GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice,
1626                                            VkFormat format,
1627                                            VkImageType type,
1628                                            VkImageTiling tiling,
1629                                            VkImageUsageFlags usage,
1630                                            VkImageCreateFlags createFlags,
1631                                            VkImageFormatProperties *pImageFormatProperties)
1632 {
1633    const VkPhysicalDeviceImageFormatInfo2 info = {
1634       .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
1635       .format = format,
1636       .type = type,
1637       .tiling = tiling,
1638       .usage = usage,
1639       .flags = createFlags,
1640    };
1641 
1642    VkImageFormatProperties2 props = { 0 };
1643 
1644    VkResult result =
1645       dzn_GetPhysicalDeviceImageFormatProperties2(physicalDevice, &info, &props);
1646    *pImageFormatProperties = props.imageFormatProperties;
1647 
1648    return result;
1649 }
1650 
1651 VKAPI_ATTR void VKAPI_CALL
dzn_GetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice,VkFormat format,VkImageType type,VkSampleCountFlagBits samples,VkImageUsageFlags usage,VkImageTiling tiling,uint32_t * pPropertyCount,VkSparseImageFormatProperties * pProperties)1652 dzn_GetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice,
1653                                                  VkFormat format,
1654                                                  VkImageType type,
1655                                                  VkSampleCountFlagBits samples,
1656                                                  VkImageUsageFlags usage,
1657                                                  VkImageTiling tiling,
1658                                                  uint32_t *pPropertyCount,
1659                                                  VkSparseImageFormatProperties *pProperties)
1660 {
1661    *pPropertyCount = 0;
1662 }
1663 
1664 VKAPI_ATTR void VKAPI_CALL
dzn_GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice,const VkPhysicalDeviceSparseImageFormatInfo2 * pFormatInfo,uint32_t * pPropertyCount,VkSparseImageFormatProperties2 * pProperties)1665 dzn_GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice,
1666                                                   const VkPhysicalDeviceSparseImageFormatInfo2 *pFormatInfo,
1667                                                   uint32_t *pPropertyCount,
1668                                                   VkSparseImageFormatProperties2 *pProperties)
1669 {
1670    *pPropertyCount = 0;
1671 }
1672 
1673 VKAPI_ATTR void VKAPI_CALL
dzn_GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice,const VkPhysicalDeviceExternalBufferInfo * pExternalBufferInfo,VkExternalBufferProperties * pExternalBufferProperties)1674 dzn_GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice,
1675                                               const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo,
1676                                               VkExternalBufferProperties *pExternalBufferProperties)
1677 {
1678 #if defined(_WIN32)
1679    VK_FROM_HANDLE(dzn_physical_device, pdev, physicalDevice);
1680 #endif
1681 
1682    const VkExternalMemoryHandleTypeFlags d3d12_resource_handle_types =
1683       VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT | opaque_external_flag;
1684    const VkExternalMemoryFeatureFlags import_export_feature_flags =
1685       VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT;
1686    const VkExternalMemoryFeatureFlags dedicated_feature_flags =
1687       VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT | import_export_feature_flags;
1688    switch (pExternalBufferInfo->handleType) {
1689    case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT:
1690       pExternalBufferProperties->externalMemoryProperties.compatibleHandleTypes = d3d12_resource_handle_types;
1691       pExternalBufferProperties->externalMemoryProperties.exportFromImportedHandleTypes = d3d12_resource_handle_types;
1692       pExternalBufferProperties->externalMemoryProperties.externalMemoryFeatures = dedicated_feature_flags;
1693       break;
1694    case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT:
1695       pExternalBufferProperties->externalMemoryProperties.compatibleHandleTypes =
1696          pExternalBufferProperties->externalMemoryProperties.exportFromImportedHandleTypes =
1697          VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT | opaque_external_flag;
1698       pExternalBufferProperties->externalMemoryProperties.externalMemoryFeatures = import_export_feature_flags;
1699       break;
1700 #ifdef _WIN32
1701    case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT:
1702 #else
1703    case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT:
1704 #endif
1705       pExternalBufferProperties->externalMemoryProperties.compatibleHandleTypes =
1706          pExternalBufferProperties->externalMemoryProperties.exportFromImportedHandleTypes =
1707          VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT | d3d12_resource_handle_types;
1708       pExternalBufferProperties->externalMemoryProperties.externalMemoryFeatures = import_export_feature_flags;
1709       break;
1710 #if defined(_WIN32)
1711    case VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT:
1712       if (pdev->dev13) {
1713          pExternalBufferProperties->externalMemoryProperties.compatibleHandleTypes =
1714             pExternalBufferProperties->externalMemoryProperties.exportFromImportedHandleTypes =
1715             VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT | opaque_external_flag;
1716          pExternalBufferProperties->externalMemoryProperties.externalMemoryFeatures = import_export_feature_flags;
1717          break;
1718       }
1719       FALLTHROUGH;
1720 #endif
1721    default:
1722       pExternalBufferProperties->externalMemoryProperties = (VkExternalMemoryProperties){ 0 };
1723       break;
1724    }
1725 }
1726 
1727 VkResult
dzn_instance_add_physical_device(struct vk_instance * instance,IUnknown * adapter,const struct dzn_physical_device_desc * desc)1728 dzn_instance_add_physical_device(struct vk_instance *instance,
1729                                  IUnknown *adapter,
1730                                  const struct dzn_physical_device_desc *desc)
1731 {
1732    struct dzn_instance *dzn_instance = container_of(instance, struct dzn_instance, vk);
1733    if ((dzn_instance->debug_flags & DZN_DEBUG_WARP) &&
1734        !desc->is_warp)
1735       return VK_SUCCESS;
1736 
1737    return dzn_physical_device_create(instance, adapter, desc);
1738 }
1739 
1740 static VkResult
dzn_enumerate_physical_devices(struct vk_instance * instance)1741 dzn_enumerate_physical_devices(struct vk_instance *instance)
1742 {
1743    VkResult result = dzn_enumerate_physical_devices_dxcore(instance);
1744 #ifdef _WIN32
1745    if (result != VK_SUCCESS)
1746       result = dzn_enumerate_physical_devices_dxgi(instance);
1747 #endif
1748 
1749    return result;
1750 }
1751 
1752 static const driOptionDescription dzn_dri_options[] = {
1753    DRI_CONF_SECTION_DEBUG
1754       DRI_CONF_DZN_CLAIM_WIDE_LINES(false)
1755       DRI_CONF_DZN_ENABLE_8BIT_LOADS_STORES(false)
1756       DRI_CONF_DZN_DISABLE(false)
1757       DRI_CONF_VK_WSI_FORCE_SWAPCHAIN_TO_CURRENT_EXTENT(false)
1758    DRI_CONF_SECTION_END
1759 };
1760 
1761 static void
dzn_init_dri_config(struct dzn_instance * instance)1762 dzn_init_dri_config(struct dzn_instance *instance)
1763 {
1764    driParseOptionInfo(&instance->available_dri_options, dzn_dri_options,
1765                       ARRAY_SIZE(dzn_dri_options));
1766    driParseConfigFiles(&instance->dri_options, &instance->available_dri_options, 0, "dzn", NULL, NULL,
1767                        instance->vk.app_info.app_name, instance->vk.app_info.app_version,
1768                        instance->vk.app_info.engine_name, instance->vk.app_info.engine_version);
1769 }
1770 
1771 static VkResult
dzn_instance_create(const VkInstanceCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkInstance * out)1772 dzn_instance_create(const VkInstanceCreateInfo *pCreateInfo,
1773                     const VkAllocationCallbacks *pAllocator,
1774                     VkInstance *out)
1775 {
1776    struct dzn_instance *instance =
1777       vk_zalloc2(vk_default_allocator(), pAllocator, sizeof(*instance), 8,
1778                  VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
1779    if (!instance)
1780       return vk_error(NULL, VK_ERROR_OUT_OF_HOST_MEMORY);
1781 
1782    struct vk_instance_dispatch_table dispatch_table;
1783    vk_instance_dispatch_table_from_entrypoints(&dispatch_table,
1784                                                &dzn_instance_entrypoints,
1785                                                true);
1786    vk_instance_dispatch_table_from_entrypoints(&dispatch_table,
1787                                                &wsi_instance_entrypoints,
1788                                                false);
1789 
1790    VkResult result =
1791       vk_instance_init(&instance->vk, &instance_extensions,
1792                        &dispatch_table, pCreateInfo,
1793                        pAllocator ? pAllocator : vk_default_allocator());
1794    if (result != VK_SUCCESS) {
1795       vk_free2(vk_default_allocator(), pAllocator, instance);
1796       return result;
1797    }
1798 
1799    instance->vk.physical_devices.enumerate = dzn_enumerate_physical_devices;
1800    instance->vk.physical_devices.destroy = dzn_physical_device_destroy;
1801    instance->debug_flags =
1802       parse_debug_string(getenv("DZN_DEBUG"), dzn_debug_options);
1803 
1804 #ifdef _WIN32
1805    if (instance->debug_flags & DZN_DEBUG_DEBUGGER) {
1806       /* wait for debugger to attach... */
1807       while (!IsDebuggerPresent()) {
1808          Sleep(100);
1809       }
1810    }
1811 
1812    if (instance->debug_flags & DZN_DEBUG_REDIRECTS) {
1813       char home[MAX_PATH], path[MAX_PATH];
1814       if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_PROFILE, NULL, 0, home))) {
1815          snprintf(path, sizeof(path), "%s\\stderr.txt", home);
1816          freopen(path, "w", stderr);
1817          snprintf(path, sizeof(path), "%s\\stdout.txt", home);
1818          freopen(path, "w", stdout);
1819       }
1820    }
1821 #endif
1822 
1823    bool missing_validator = false;
1824 #ifdef _WIN32
1825    if ((instance->debug_flags & DZN_DEBUG_EXPERIMENTAL) == 0) {
1826       instance->dxil_validator = dxil_create_validator(NULL);
1827       missing_validator = !instance->dxil_validator;
1828    }
1829 #endif
1830 
1831    if (missing_validator) {
1832       dzn_instance_destroy(instance, pAllocator);
1833       return vk_error(NULL, VK_ERROR_INITIALIZATION_FAILED);
1834    }
1835 
1836    instance->d3d12_mod = util_dl_open(UTIL_DL_PREFIX "d3d12" UTIL_DL_EXT);
1837    if (!instance->d3d12_mod) {
1838       dzn_instance_destroy(instance, pAllocator);
1839       return vk_error(NULL, VK_ERROR_INITIALIZATION_FAILED);
1840    }
1841 
1842    instance->d3d12.serialize_root_sig = d3d12_get_serialize_root_sig(instance->d3d12_mod);
1843    if (!instance->d3d12.serialize_root_sig) {
1844       dzn_instance_destroy(instance, pAllocator);
1845       return vk_error(NULL, VK_ERROR_INITIALIZATION_FAILED);
1846    }
1847 
1848    instance->factory = try_create_device_factory(instance->d3d12_mod);
1849 
1850    if (instance->debug_flags & DZN_DEBUG_D3D12)
1851       d3d12_enable_debug_layer(instance->d3d12_mod, instance->factory);
1852    if (instance->debug_flags & DZN_DEBUG_GBV)
1853       d3d12_enable_gpu_validation(instance->d3d12_mod, instance->factory);
1854 
1855    instance->sync_binary_type = vk_sync_binary_get_type(&dzn_sync_type);
1856    dzn_init_dri_config(instance);
1857 
1858    if (driQueryOptionb(&instance->dri_options, "dzn_disable")) {
1859       dzn_instance_destroy(instance, pAllocator);
1860       return vk_errorf(NULL, VK_ERROR_INITIALIZATION_FAILED, "dzn_disable set, failing instance creation");
1861    }
1862 
1863    *out = dzn_instance_to_handle(instance);
1864    return VK_SUCCESS;
1865 }
1866 
1867 VKAPI_ATTR VkResult VKAPI_CALL
dzn_CreateInstance(const VkInstanceCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkInstance * pInstance)1868 dzn_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
1869                    const VkAllocationCallbacks *pAllocator,
1870                    VkInstance *pInstance)
1871 {
1872    return dzn_instance_create(pCreateInfo, pAllocator, pInstance);
1873 }
1874 
1875 VKAPI_ATTR VkResult VKAPI_CALL
dzn_EnumerateInstanceVersion(uint32_t * pApiVersion)1876 dzn_EnumerateInstanceVersion(uint32_t *pApiVersion)
1877 {
1878    *pApiVersion = DZN_API_VERSION;
1879    return VK_SUCCESS;
1880 }
1881 
1882 
1883 VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
dzn_GetInstanceProcAddr(VkInstance _instance,const char * pName)1884 dzn_GetInstanceProcAddr(VkInstance _instance,
1885                         const char *pName)
1886 {
1887    VK_FROM_HANDLE(dzn_instance, instance, _instance);
1888    return vk_instance_get_proc_addr(&instance->vk,
1889                                     &dzn_instance_entrypoints,
1890                                     pName);
1891 }
1892 
1893 /* Windows will use a dll definition file to avoid build errors. */
1894 #ifdef _WIN32
1895 #undef PUBLIC
1896 #define PUBLIC
1897 #endif
1898 
1899 PUBLIC VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
vk_icdGetInstanceProcAddr(VkInstance instance,const char * pName)1900 vk_icdGetInstanceProcAddr(VkInstance instance,
1901                           const char *pName)
1902 {
1903    return dzn_GetInstanceProcAddr(instance, pName);
1904 }
1905 
1906 VKAPI_ATTR void VKAPI_CALL
dzn_GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice,uint32_t * pQueueFamilyPropertyCount,VkQueueFamilyProperties2 * pQueueFamilyProperties)1907 dzn_GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice,
1908                                             uint32_t *pQueueFamilyPropertyCount,
1909                                             VkQueueFamilyProperties2 *pQueueFamilyProperties)
1910 {
1911    VK_FROM_HANDLE(dzn_physical_device, pdev, physicalDevice);
1912    VK_OUTARRAY_MAKE_TYPED(VkQueueFamilyProperties2, out,
1913                           pQueueFamilyProperties, pQueueFamilyPropertyCount);
1914 
1915    for (uint32_t i = 0; i < pdev->queue_family_count; i++) {
1916       vk_outarray_append_typed(VkQueueFamilyProperties2, &out, p) {
1917          p->queueFamilyProperties = pdev->queue_families[i].props;
1918 
1919          vk_foreach_struct(ext, pQueueFamilyProperties->pNext) {
1920             vk_debug_ignored_stype(ext->sType);
1921          }
1922       }
1923    }
1924 }
1925 
1926 VKAPI_ATTR void VKAPI_CALL
dzn_GetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice,VkPhysicalDeviceMemoryProperties * pMemoryProperties)1927 dzn_GetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice,
1928                                       VkPhysicalDeviceMemoryProperties *pMemoryProperties)
1929 {
1930    VK_FROM_HANDLE(dzn_physical_device, pdev, physicalDevice);
1931 
1932    *pMemoryProperties = pdev->memory;
1933 }
1934 
1935 VKAPI_ATTR void VKAPI_CALL
dzn_GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice,VkPhysicalDeviceMemoryProperties2 * pMemoryProperties)1936 dzn_GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice,
1937                                        VkPhysicalDeviceMemoryProperties2 *pMemoryProperties)
1938 {
1939    dzn_GetPhysicalDeviceMemoryProperties(physicalDevice,
1940                                          &pMemoryProperties->memoryProperties);
1941 
1942    vk_foreach_struct(ext, pMemoryProperties->pNext) {
1943       vk_debug_ignored_stype(ext->sType);
1944    }
1945 }
1946 
1947 VKAPI_ATTR VkResult VKAPI_CALL
dzn_EnumerateInstanceLayerProperties(uint32_t * pPropertyCount,VkLayerProperties * pProperties)1948 dzn_EnumerateInstanceLayerProperties(uint32_t *pPropertyCount,
1949                                      VkLayerProperties *pProperties)
1950 {
1951    if (pProperties == NULL) {
1952       *pPropertyCount = 0;
1953       return VK_SUCCESS;
1954    }
1955 
1956    return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);
1957 }
1958 
1959 static VkResult
dzn_queue_sync_wait(struct dzn_queue * queue,const struct vk_sync_wait * wait)1960 dzn_queue_sync_wait(struct dzn_queue *queue, const struct vk_sync_wait *wait)
1961 {
1962    if (wait->sync->type == &vk_sync_dummy_type)
1963       return VK_SUCCESS;
1964 
1965    struct dzn_device *device = container_of(queue->vk.base.device, struct dzn_device, vk);
1966    assert(wait->sync->type == &dzn_sync_type);
1967    struct dzn_sync *sync = container_of(wait->sync, struct dzn_sync, vk);
1968    uint64_t value =
1969       (sync->vk.flags & VK_SYNC_IS_TIMELINE) ? wait->wait_value : 1;
1970 
1971    assert(sync->fence != NULL);
1972 
1973    if (value > 0 && FAILED(ID3D12CommandQueue_Wait(queue->cmdqueue, sync->fence, value)))
1974       return vk_error(device, VK_ERROR_UNKNOWN);
1975 
1976    return VK_SUCCESS;
1977 }
1978 
1979 static VkResult
dzn_queue_sync_signal(struct dzn_queue * queue,const struct vk_sync_signal * signal)1980 dzn_queue_sync_signal(struct dzn_queue *queue, const struct vk_sync_signal *signal)
1981 {
1982    if (signal->sync->type == &vk_sync_dummy_type)
1983       return VK_SUCCESS;
1984 
1985    struct dzn_device *device = container_of(queue->vk.base.device, struct dzn_device, vk);
1986    assert(signal->sync->type == &dzn_sync_type);
1987    struct dzn_sync *sync = container_of(signal->sync, struct dzn_sync, vk);
1988    uint64_t value =
1989       (sync->vk.flags & VK_SYNC_IS_TIMELINE) ? signal->signal_value : 1;
1990    assert(value > 0);
1991 
1992    assert(sync->fence != NULL);
1993 
1994    if (FAILED(ID3D12CommandQueue_Signal(queue->cmdqueue, sync->fence, value)))
1995       return vk_error(device, VK_ERROR_UNKNOWN);
1996 
1997    return VK_SUCCESS;
1998 }
1999 
2000 static VkResult
dzn_queue_submit(struct vk_queue * q,struct vk_queue_submit * info)2001 dzn_queue_submit(struct vk_queue *q,
2002                  struct vk_queue_submit *info)
2003 {
2004    struct dzn_queue *queue = container_of(q, struct dzn_queue, vk);
2005    struct dzn_device *device = container_of(q->base.device, struct dzn_device, vk);
2006    VkResult result = VK_SUCCESS;
2007 
2008    for (uint32_t i = 0; i < info->wait_count; i++) {
2009       result = dzn_queue_sync_wait(queue, &info->waits[i]);
2010       if (result != VK_SUCCESS)
2011          return result;
2012    }
2013 
2014    ID3D12CommandList **cmdlists = alloca(info->command_buffer_count * sizeof(ID3D12CommandList*));
2015 
2016    for (uint32_t i = 0; i < info->command_buffer_count; i++) {
2017       struct dzn_cmd_buffer *cmd_buffer =
2018          container_of(info->command_buffers[i], struct dzn_cmd_buffer, vk);
2019 
2020       cmdlists[i] = (ID3D12CommandList *)cmd_buffer->cmdlist;
2021 
2022       util_dynarray_foreach(&cmd_buffer->queries.reset, struct dzn_cmd_buffer_query_range, range) {
2023          mtx_lock(&range->qpool->queries_lock);
2024          for (uint32_t q = range->start; q < range->start + range->count; q++) {
2025             struct dzn_query *query = &range->qpool->queries[q];
2026             if (query->fence) {
2027                ID3D12Fence_Release(query->fence);
2028                query->fence = NULL;
2029             }
2030             query->fence_value = 0;
2031          }
2032          mtx_unlock(&range->qpool->queries_lock);
2033       }
2034    }
2035 
2036    ID3D12CommandQueue_ExecuteCommandLists(queue->cmdqueue, info->command_buffer_count, cmdlists);
2037 
2038    for (uint32_t i = 0; i < info->command_buffer_count; i++) {
2039       struct dzn_cmd_buffer* cmd_buffer =
2040          container_of(info->command_buffers[i], struct dzn_cmd_buffer, vk);
2041 
2042       util_dynarray_foreach(&cmd_buffer->events.signal, struct dzn_cmd_event_signal, evt) {
2043          if (FAILED(ID3D12CommandQueue_Signal(queue->cmdqueue, evt->event->fence, evt->value ? 1 : 0)))
2044             return vk_error(device, VK_ERROR_UNKNOWN);
2045       }
2046 
2047       util_dynarray_foreach(&cmd_buffer->queries.signal, struct dzn_cmd_buffer_query_range, range) {
2048          mtx_lock(&range->qpool->queries_lock);
2049          for (uint32_t q = range->start; q < range->start + range->count; q++) {
2050             struct dzn_query *query = &range->qpool->queries[q];
2051             query->fence_value = queue->fence_point + 1;
2052             query->fence = queue->fence;
2053             ID3D12Fence_AddRef(query->fence);
2054          }
2055          mtx_unlock(&range->qpool->queries_lock);
2056       }
2057    }
2058 
2059    for (uint32_t i = 0; i < info->signal_count; i++) {
2060       result = dzn_queue_sync_signal(queue, &info->signals[i]);
2061       if (result != VK_SUCCESS)
2062          return vk_error(device, VK_ERROR_UNKNOWN);
2063    }
2064 
2065    if (FAILED(ID3D12CommandQueue_Signal(queue->cmdqueue, queue->fence, ++queue->fence_point)))
2066       return vk_error(device, VK_ERROR_UNKNOWN);
2067 
2068    return VK_SUCCESS;
2069 }
2070 
2071 static void
dzn_queue_finish(struct dzn_queue * queue)2072 dzn_queue_finish(struct dzn_queue *queue)
2073 {
2074    if (queue->cmdqueue)
2075       ID3D12CommandQueue_Release(queue->cmdqueue);
2076 
2077    if (queue->fence)
2078       ID3D12Fence_Release(queue->fence);
2079 
2080    vk_queue_finish(&queue->vk);
2081 }
2082 
2083 static VkResult
dzn_queue_init(struct dzn_queue * queue,struct dzn_device * device,const VkDeviceQueueCreateInfo * pCreateInfo,uint32_t index_in_family)2084 dzn_queue_init(struct dzn_queue *queue,
2085                struct dzn_device *device,
2086                const VkDeviceQueueCreateInfo *pCreateInfo,
2087                uint32_t index_in_family)
2088 {
2089    struct dzn_physical_device *pdev = container_of(device->vk.physical, struct dzn_physical_device, vk);
2090 
2091    VkResult result = vk_queue_init(&queue->vk, &device->vk, pCreateInfo, index_in_family);
2092    if (result != VK_SUCCESS)
2093       return result;
2094 
2095    queue->vk.driver_submit = dzn_queue_submit;
2096 
2097    assert(pCreateInfo->queueFamilyIndex < pdev->queue_family_count);
2098 
2099    D3D12_COMMAND_QUEUE_DESC queue_desc =
2100       pdev->queue_families[pCreateInfo->queueFamilyIndex].desc;
2101 
2102    float priority_in = pCreateInfo->pQueuePriorities[index_in_family];
2103    queue_desc.Priority =
2104       priority_in > 0.5f ? D3D12_COMMAND_QUEUE_PRIORITY_HIGH : D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
2105    queue_desc.NodeMask = 0;
2106 
2107    if (FAILED(ID3D12Device1_CreateCommandQueue(device->dev, &queue_desc,
2108                                                &IID_ID3D12CommandQueue,
2109                                                (void **)&queue->cmdqueue))) {
2110       dzn_queue_finish(queue);
2111       return vk_error(device->vk.physical->instance, VK_ERROR_INITIALIZATION_FAILED);
2112    }
2113 
2114    if (FAILED(ID3D12Device1_CreateFence(device->dev, 0, D3D12_FENCE_FLAG_NONE,
2115                                         &IID_ID3D12Fence,
2116                                         (void **)&queue->fence))) {
2117       dzn_queue_finish(queue);
2118       return vk_error(device->vk.physical->instance, VK_ERROR_INITIALIZATION_FAILED);
2119    }
2120 
2121    return VK_SUCCESS;
2122 }
2123 
2124 static VkResult
dzn_device_create_sync_for_memory(struct vk_device * device,VkDeviceMemory memory,bool signal_memory,struct vk_sync ** sync_out)2125 dzn_device_create_sync_for_memory(struct vk_device *device,
2126                                   VkDeviceMemory memory,
2127                                   bool signal_memory,
2128                                   struct vk_sync **sync_out)
2129 {
2130    return vk_sync_create(device, &vk_sync_dummy_type,
2131                          0, 1, sync_out);
2132 }
2133 
2134 static VkResult
dzn_device_query_init(struct dzn_device * device)2135 dzn_device_query_init(struct dzn_device *device)
2136 {
2137    /* FIXME: create the resource in the default heap */
2138    D3D12_HEAP_PROPERTIES hprops = dzn_ID3D12Device4_GetCustomHeapProperties(device->dev, 0, D3D12_HEAP_TYPE_UPLOAD);
2139    D3D12_RESOURCE_DESC rdesc = {
2140       .Dimension = D3D12_RESOURCE_DIMENSION_BUFFER,
2141       .Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT,
2142       .Width = DZN_QUERY_REFS_RES_SIZE,
2143       .Height = 1,
2144       .DepthOrArraySize = 1,
2145       .MipLevels = 1,
2146       .Format = DXGI_FORMAT_UNKNOWN,
2147       .SampleDesc = { .Count = 1, .Quality = 0 },
2148       .Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
2149       .Flags = D3D12_RESOURCE_FLAG_NONE,
2150    };
2151 
2152    if (FAILED(ID3D12Device1_CreateCommittedResource(device->dev, &hprops,
2153                                                    D3D12_HEAP_FLAG_NONE,
2154                                                    &rdesc,
2155                                                    D3D12_RESOURCE_STATE_COMMON,
2156                                                    NULL,
2157                                                    &IID_ID3D12Resource,
2158                                                    (void **)&device->queries.refs)))
2159       return vk_error(device->vk.physical, VK_ERROR_OUT_OF_DEVICE_MEMORY);
2160 
2161    uint8_t *queries_ref;
2162    if (FAILED(ID3D12Resource_Map(device->queries.refs, 0, NULL, (void **)&queries_ref)))
2163       return vk_error(device->vk.physical, VK_ERROR_OUT_OF_HOST_MEMORY);
2164 
2165    memset(queries_ref + DZN_QUERY_REFS_ALL_ONES_OFFSET, 0xff, DZN_QUERY_REFS_SECTION_SIZE);
2166    memset(queries_ref + DZN_QUERY_REFS_ALL_ZEROS_OFFSET, 0x0, DZN_QUERY_REFS_SECTION_SIZE);
2167    ID3D12Resource_Unmap(device->queries.refs, 0, NULL);
2168 
2169    return VK_SUCCESS;
2170 }
2171 
2172 static void
dzn_device_query_finish(struct dzn_device * device)2173 dzn_device_query_finish(struct dzn_device *device)
2174 {
2175    if (device->queries.refs)
2176       ID3D12Resource_Release(device->queries.refs);
2177 }
2178 
2179 static void
dzn_device_destroy(struct dzn_device * device,const VkAllocationCallbacks * pAllocator)2180 dzn_device_destroy(struct dzn_device *device, const VkAllocationCallbacks *pAllocator)
2181 {
2182    if (!device)
2183       return;
2184 
2185    struct dzn_instance *instance =
2186       container_of(device->vk.physical->instance, struct dzn_instance, vk);
2187 
2188    vk_foreach_queue_safe(q, &device->vk) {
2189       struct dzn_queue *queue = container_of(q, struct dzn_queue, vk);
2190 
2191       dzn_queue_finish(queue);
2192    }
2193 
2194    dzn_device_query_finish(device);
2195    dzn_meta_finish(device);
2196 
2197    dzn_foreach_pool_type(type) {
2198       dzn_descriptor_heap_finish(&device->device_heaps[type].heap);
2199       util_dynarray_fini(&device->device_heaps[type].slot_freelist);
2200       mtx_destroy(&device->device_heaps[type].lock);
2201    }
2202 
2203    if (device->dev_config)
2204       ID3D12DeviceConfiguration_Release(device->dev_config);
2205 
2206    if (device->dev)
2207       ID3D12Device1_Release(device->dev);
2208 
2209    if (device->dev10)
2210       ID3D12Device1_Release(device->dev10);
2211 
2212    if (device->dev11)
2213       ID3D12Device1_Release(device->dev11);
2214 
2215    if (device->dev12)
2216       ID3D12Device1_Release(device->dev12);
2217 
2218    if (device->dev13)
2219       ID3D12Device1_Release(device->dev13);
2220 
2221    vk_device_finish(&device->vk);
2222    vk_free2(&instance->vk.alloc, pAllocator, device);
2223 }
2224 
2225 static VkResult
dzn_device_check_status(struct vk_device * dev)2226 dzn_device_check_status(struct vk_device *dev)
2227 {
2228    struct dzn_device *device = container_of(dev, struct dzn_device, vk);
2229 
2230    if (FAILED(ID3D12Device_GetDeviceRemovedReason(device->dev)))
2231       return vk_device_set_lost(&device->vk, "D3D12 device removed");
2232 
2233    return VK_SUCCESS;
2234 }
2235 
2236 static VkResult
dzn_device_create(struct dzn_physical_device * pdev,const VkDeviceCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkDevice * out)2237 dzn_device_create(struct dzn_physical_device *pdev,
2238                   const VkDeviceCreateInfo *pCreateInfo,
2239                   const VkAllocationCallbacks *pAllocator,
2240                   VkDevice *out)
2241 {
2242    struct dzn_instance *instance = container_of(pdev->vk.instance, struct dzn_instance, vk);
2243 
2244    uint32_t graphics_queue_count = 0;
2245    uint32_t queue_count = 0;
2246    for (uint32_t qf = 0; qf < pCreateInfo->queueCreateInfoCount; qf++) {
2247       const VkDeviceQueueCreateInfo *qinfo = &pCreateInfo->pQueueCreateInfos[qf];
2248       queue_count += qinfo->queueCount;
2249       if (pdev->queue_families[qinfo->queueFamilyIndex].props.queueFlags & VK_QUEUE_GRAPHICS_BIT)
2250          graphics_queue_count += qinfo->queueCount;
2251    }
2252 
2253    /* Add a swapchain queue if there's no or too many graphics queues */
2254    if (graphics_queue_count != 1)
2255       queue_count++;
2256 
2257    VK_MULTIALLOC(ma);
2258    VK_MULTIALLOC_DECL(&ma, struct dzn_device, device, 1);
2259    VK_MULTIALLOC_DECL(&ma, struct dzn_queue, queues, queue_count);
2260 
2261    if (!vk_multialloc_zalloc2(&ma, &instance->vk.alloc, pAllocator,
2262                               VK_SYSTEM_ALLOCATION_SCOPE_DEVICE))
2263       return vk_error(pdev, VK_ERROR_OUT_OF_HOST_MEMORY);
2264 
2265    struct vk_device_dispatch_table dispatch_table;
2266 
2267    /* For secondary command buffer support, overwrite any command entrypoints
2268     * in the main device-level dispatch table with
2269     * vk_cmd_enqueue_unless_primary_Cmd*.
2270     */
2271    vk_device_dispatch_table_from_entrypoints(&dispatch_table,
2272       &vk_cmd_enqueue_unless_primary_device_entrypoints, true);
2273    vk_device_dispatch_table_from_entrypoints(&dispatch_table,
2274       &dzn_device_entrypoints, false);
2275    vk_device_dispatch_table_from_entrypoints(&dispatch_table,
2276       &wsi_device_entrypoints, false);
2277 
2278    /* Populate our primary cmd_dispatch table. */
2279    vk_device_dispatch_table_from_entrypoints(&device->cmd_dispatch,
2280       &dzn_device_entrypoints, true);
2281    vk_device_dispatch_table_from_entrypoints(&device->cmd_dispatch,
2282                                              &vk_common_device_entrypoints,
2283                                              false);
2284 
2285    /* Override entrypoints with alternatives based on supported features. */
2286    if (pdev->options12.EnhancedBarriersSupported) {
2287       device->cmd_dispatch.CmdPipelineBarrier2 = dzn_CmdPipelineBarrier2_enhanced;
2288    }
2289 
2290    VkResult result =
2291       vk_device_init(&device->vk, &pdev->vk, &dispatch_table, pCreateInfo, pAllocator);
2292    if (result != VK_SUCCESS) {
2293       vk_free2(&device->vk.alloc, pAllocator, device);
2294       return result;
2295    }
2296 
2297    /* Must be done after vk_device_init() because this function memset(0) the
2298     * whole struct.
2299     */
2300    device->vk.command_dispatch_table = &device->cmd_dispatch;
2301    device->vk.create_sync_for_memory = dzn_device_create_sync_for_memory;
2302    device->vk.check_status = dzn_device_check_status;
2303 
2304    device->dev = pdev->dev;
2305 
2306    ID3D12Device1_AddRef(device->dev);
2307 
2308    if (pdev->dev10) {
2309       device->dev10 = pdev->dev10;
2310       ID3D12Device1_AddRef(device->dev10);
2311    }
2312    if (pdev->dev11) {
2313       device->dev11 = pdev->dev11;
2314       ID3D12Device1_AddRef(device->dev11);
2315    }
2316 
2317    if (pdev->dev12) {
2318       device->dev12 = pdev->dev12;
2319       ID3D12Device1_AddRef(device->dev12);
2320    }
2321 
2322    if (pdev->dev13) {
2323       device->dev13 = pdev->dev13;
2324       ID3D12Device1_AddRef(device->dev13);
2325    }
2326 
2327    ID3D12InfoQueue *info_queue;
2328    if (SUCCEEDED(ID3D12Device1_QueryInterface(device->dev,
2329                                               &IID_ID3D12InfoQueue,
2330                                               (void **)&info_queue))) {
2331       D3D12_MESSAGE_SEVERITY severities[] = {
2332          D3D12_MESSAGE_SEVERITY_INFO,
2333          D3D12_MESSAGE_SEVERITY_WARNING,
2334       };
2335 
2336       D3D12_MESSAGE_ID msg_ids[] = {
2337          D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE,
2338       };
2339 
2340       D3D12_INFO_QUEUE_FILTER NewFilter = { 0 };
2341       NewFilter.DenyList.NumSeverities = ARRAY_SIZE(severities);
2342       NewFilter.DenyList.pSeverityList = severities;
2343       NewFilter.DenyList.NumIDs = ARRAY_SIZE(msg_ids);
2344       NewFilter.DenyList.pIDList = msg_ids;
2345 
2346       ID3D12InfoQueue_PushStorageFilter(info_queue, &NewFilter);
2347       ID3D12InfoQueue_Release(info_queue);
2348    }
2349 
2350    IUnknown_QueryInterface(device->dev, &IID_ID3D12DeviceConfiguration, (void **)&device->dev_config);
2351 
2352    result = dzn_meta_init(device);
2353    if (result != VK_SUCCESS) {
2354       dzn_device_destroy(device, pAllocator);
2355       return result;
2356    }
2357 
2358    result = dzn_device_query_init(device);
2359    if (result != VK_SUCCESS) {
2360       dzn_device_destroy(device, pAllocator);
2361       return result;
2362    }
2363 
2364    uint32_t qindex = 0;
2365    for (uint32_t qf = 0; qf < pCreateInfo->queueCreateInfoCount; qf++) {
2366       const VkDeviceQueueCreateInfo *qinfo = &pCreateInfo->pQueueCreateInfos[qf];
2367 
2368       for (uint32_t q = 0; q < qinfo->queueCount; q++) {
2369          result =
2370             dzn_queue_init(&queues[qindex++], device, qinfo, q);
2371          if (result != VK_SUCCESS) {
2372             dzn_device_destroy(device, pAllocator);
2373             return result;
2374          }
2375          if (graphics_queue_count == 1 &&
2376              pdev->queue_families[qinfo->queueFamilyIndex].props.queueFlags & VK_QUEUE_GRAPHICS_BIT)
2377             device->swapchain_queue = &queues[qindex - 1];
2378       }
2379    }
2380 
2381    if (!device->swapchain_queue) {
2382       const float swapchain_queue_priority = 0.0f;
2383       VkDeviceQueueCreateInfo swapchain_queue_info = {
2384          .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
2385          .flags = 0,
2386          .queueCount = 1,
2387          .pQueuePriorities = &swapchain_queue_priority,
2388       };
2389       for (uint32_t qf = 0; qf < pdev->queue_family_count; qf++) {
2390          if (pdev->queue_families[qf].props.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
2391             swapchain_queue_info.queueFamilyIndex = qf;
2392             break;
2393          }
2394       }
2395       result = dzn_queue_init(&queues[qindex], device, &swapchain_queue_info, 0);
2396       if (result != VK_SUCCESS) {
2397          dzn_device_destroy(device, pAllocator);
2398          return result;
2399       }
2400       device->swapchain_queue = &queues[qindex++];
2401       device->need_swapchain_blits = true;
2402    }
2403 
2404    device->support_static_samplers = true;
2405    device->bindless = (instance->debug_flags & DZN_DEBUG_BINDLESS) != 0 ||
2406       device->vk.enabled_features.descriptorIndexing ||
2407       device->vk.enabled_extensions.EXT_descriptor_indexing ||
2408       device->vk.enabled_features.bufferDeviceAddress ||
2409       device->vk.enabled_extensions.EXT_buffer_device_address;
2410 
2411    if (device->bindless) {
2412       uint32_t sampler_count = MIN2(pdev->options19.MaxSamplerDescriptorHeapSize, 4000);
2413       device->support_static_samplers = pdev->options19.MaxSamplerDescriptorHeapSizeWithStaticSamplers >= sampler_count;
2414       dzn_foreach_pool_type(type) {
2415          uint32_t descriptor_count = type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER ?
2416             sampler_count : D3D12_MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1;
2417          result = dzn_descriptor_heap_init(&device->device_heaps[type].heap, device, type, descriptor_count, true);
2418          if (result != VK_SUCCESS) {
2419             dzn_device_destroy(device, pAllocator);
2420             return result;
2421          }
2422 
2423          mtx_init(&device->device_heaps[type].lock, mtx_plain);
2424          util_dynarray_init(&device->device_heaps[type].slot_freelist, NULL);
2425          device->device_heaps[type].next_alloc_slot = 0;
2426       }
2427    }
2428 
2429    assert(queue_count == qindex);
2430    *out = dzn_device_to_handle(device);
2431    return VK_SUCCESS;
2432 }
2433 
2434 static ID3DBlob *
serialize_root_sig(struct dzn_device * device,const D3D12_VERSIONED_ROOT_SIGNATURE_DESC * desc)2435 serialize_root_sig(struct dzn_device *device,
2436                    const D3D12_VERSIONED_ROOT_SIGNATURE_DESC *desc)
2437 {
2438    struct dzn_instance *instance =
2439       container_of(device->vk.physical->instance, struct dzn_instance, vk);
2440    ID3DBlob *sig = NULL, *error = NULL;
2441 
2442    HRESULT hr = device->dev_config ?
2443          ID3D12DeviceConfiguration_SerializeVersionedRootSignature(device->dev_config, desc, &sig, &error) :
2444          instance->d3d12.serialize_root_sig(desc, &sig, &error);
2445 
2446    if (FAILED(hr)) {
2447       if (instance->debug_flags & DZN_DEBUG_SIG) {
2448          const char *error_msg = (const char *)ID3D10Blob_GetBufferPointer(error);
2449          fprintf(stderr,
2450                  "== SERIALIZE ROOT SIG ERROR =============================================\n"
2451                  "%s\n"
2452                  "== END ==========================================================\n",
2453                  error_msg);
2454       }
2455    }
2456 
2457    if (error)
2458       ID3D10Blob_Release(error);
2459 
2460    return sig;
2461 }
2462 
2463 ID3D12RootSignature *
dzn_device_create_root_sig(struct dzn_device * device,const D3D12_VERSIONED_ROOT_SIGNATURE_DESC * desc)2464 dzn_device_create_root_sig(struct dzn_device *device,
2465                            const D3D12_VERSIONED_ROOT_SIGNATURE_DESC *desc)
2466 {
2467    ID3DBlob *sig = serialize_root_sig(device, desc);
2468    if (!sig)
2469       return NULL;
2470 
2471    ID3D12RootSignature *root_sig = NULL;
2472    ID3D12Device1_CreateRootSignature(device->dev, 0,
2473                                      ID3D10Blob_GetBufferPointer(sig),
2474                                      ID3D10Blob_GetBufferSize(sig),
2475                                      &IID_ID3D12RootSignature,
2476                                      (void **)&root_sig);
2477    ID3D10Blob_Release(sig);
2478    return root_sig;
2479 }
2480 
2481 VKAPI_ATTR VkResult VKAPI_CALL
dzn_CreateDevice(VkPhysicalDevice physicalDevice,const VkDeviceCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkDevice * pDevice)2482 dzn_CreateDevice(VkPhysicalDevice physicalDevice,
2483                  const VkDeviceCreateInfo *pCreateInfo,
2484                  const VkAllocationCallbacks *pAllocator,
2485                  VkDevice *pDevice)
2486 {
2487    VK_FROM_HANDLE(dzn_physical_device, physical_device, physicalDevice);
2488    VkResult result;
2489 
2490    assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO);
2491 
2492    /* Check enabled features */
2493    if (pCreateInfo->pEnabledFeatures) {
2494       result = vk_physical_device_check_device_features(&physical_device->vk, pCreateInfo);
2495       if (result != VK_SUCCESS)
2496          return vk_error(physical_device, result);
2497    }
2498 
2499    /* Check requested queues and fail if we are requested to create any
2500     * queues with flags we don't support.
2501     */
2502    assert(pCreateInfo->queueCreateInfoCount > 0);
2503    for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++) {
2504       if (pCreateInfo->pQueueCreateInfos[i].flags != 0)
2505          return vk_error(physical_device, VK_ERROR_INITIALIZATION_FAILED);
2506    }
2507 
2508    return dzn_device_create(physical_device, pCreateInfo, pAllocator, pDevice);
2509 }
2510 
2511 VKAPI_ATTR void VKAPI_CALL
dzn_DestroyDevice(VkDevice dev,const VkAllocationCallbacks * pAllocator)2512 dzn_DestroyDevice(VkDevice dev,
2513                   const VkAllocationCallbacks *pAllocator)
2514 {
2515    VK_FROM_HANDLE(dzn_device, device, dev);
2516 
2517    device->vk.dispatch_table.DeviceWaitIdle(dev);
2518 
2519    dzn_device_destroy(device, pAllocator);
2520 }
2521 
2522 static void
dzn_device_memory_destroy(struct dzn_device_memory * mem,const VkAllocationCallbacks * pAllocator)2523 dzn_device_memory_destroy(struct dzn_device_memory *mem,
2524                           const VkAllocationCallbacks *pAllocator)
2525 {
2526    if (!mem)
2527       return;
2528 
2529    struct dzn_device *device = container_of(mem->base.device, struct dzn_device, vk);
2530 
2531    if (mem->map && mem->map_res)
2532       ID3D12Resource_Unmap(mem->map_res, 0, NULL);
2533 
2534    if (mem->map_res)
2535       ID3D12Resource_Release(mem->map_res);
2536 
2537    if (mem->heap)
2538       ID3D12Heap_Release(mem->heap);
2539 
2540    if (mem->dedicated_res)
2541       ID3D12Resource_Release(mem->dedicated_res);
2542 
2543 #ifdef _WIN32
2544    if (mem->export_handle)
2545       CloseHandle(mem->export_handle);
2546 #else
2547    if ((intptr_t)mem->export_handle >= 0)
2548       close((int)(intptr_t)mem->export_handle);
2549 #endif
2550 
2551    vk_object_base_finish(&mem->base);
2552    vk_free2(&device->vk.alloc, pAllocator, mem);
2553 }
2554 
2555 static D3D12_HEAP_PROPERTIES
deduce_heap_properties_from_memory(struct dzn_physical_device * pdevice,const VkMemoryType * mem_type)2556 deduce_heap_properties_from_memory(struct dzn_physical_device *pdevice,
2557                                    const VkMemoryType *mem_type)
2558 {
2559    D3D12_HEAP_PROPERTIES properties = { .Type = D3D12_HEAP_TYPE_CUSTOM };
2560    properties.MemoryPoolPreference =
2561       ((mem_type->propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) &&
2562        !pdevice->architecture.UMA) ?
2563       D3D12_MEMORY_POOL_L1 : D3D12_MEMORY_POOL_L0;
2564    if ((mem_type->propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) ||
2565        ((mem_type->propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && pdevice->architecture.CacheCoherentUMA)) {
2566       properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_WRITE_BACK;
2567    } else if (mem_type->propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
2568       properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE;
2569    } else {
2570       properties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE;
2571    }
2572    return properties;
2573 }
2574 
2575 static VkResult
dzn_device_memory_create(struct dzn_device * device,const VkMemoryAllocateInfo * pAllocateInfo,const VkAllocationCallbacks * pAllocator,VkDeviceMemory * out)2576 dzn_device_memory_create(struct dzn_device *device,
2577                          const VkMemoryAllocateInfo *pAllocateInfo,
2578                          const VkAllocationCallbacks *pAllocator,
2579                          VkDeviceMemory *out)
2580 {
2581    struct dzn_physical_device *pdevice =
2582       container_of(device->vk.physical, struct dzn_physical_device, vk);
2583 
2584    const struct dzn_buffer *buffer = NULL;
2585    const struct dzn_image *image = NULL;
2586 
2587    VkExternalMemoryHandleTypeFlags export_flags = 0;
2588    HANDLE import_handle = NULL;
2589    bool imported_from_d3d11 = false;
2590    void *host_pointer = NULL;
2591 #ifdef _WIN32
2592    const wchar_t *import_name = NULL;
2593    const VkExportMemoryWin32HandleInfoKHR *win32_export = NULL;
2594 #endif
2595    vk_foreach_struct_const(ext, pAllocateInfo->pNext) {
2596       switch (ext->sType) {
2597       case VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO: {
2598          const VkExportMemoryAllocateInfo *exp =
2599             (const VkExportMemoryAllocateInfo *)ext;
2600 
2601          export_flags = exp->handleTypes;
2602          break;
2603       }
2604 #ifdef _WIN32
2605       case VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR: {
2606          const VkImportMemoryWin32HandleInfoKHR *imp =
2607             (const VkImportMemoryWin32HandleInfoKHR *)ext;
2608          switch (imp->handleType) {
2609          case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT:
2610             imported_from_d3d11 = true;
2611             FALLTHROUGH;
2612          case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT:
2613          case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT:
2614          case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT:
2615             break;
2616          default:
2617             return vk_error(device, VK_ERROR_INVALID_EXTERNAL_HANDLE);
2618          }
2619          import_handle = imp->handle;
2620          import_name = imp->name;
2621          break;
2622       }
2623       case VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR:
2624          win32_export = (const VkExportMemoryWin32HandleInfoKHR *)ext;
2625          break;
2626       case VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT: {
2627          const VkImportMemoryHostPointerInfoEXT *imp =
2628             (const VkImportMemoryHostPointerInfoEXT *)ext;
2629          host_pointer = imp->pHostPointer;
2630          break;
2631       }
2632 #else
2633       case VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR: {
2634          const VkImportMemoryFdInfoKHR *imp =
2635             (const VkImportMemoryFdInfoKHR *)ext;
2636          switch (imp->handleType) {
2637          case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT:
2638          case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT:
2639          case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT:
2640             break;
2641          default:
2642             return vk_error(device, VK_ERROR_INVALID_EXTERNAL_HANDLE);
2643          }
2644          import_handle = (HANDLE)(intptr_t)imp->fd;
2645          break;
2646       }
2647 #endif
2648       case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO: {
2649          const VkMemoryDedicatedAllocateInfo *dedicated =
2650            (const VkMemoryDedicatedAllocateInfo *)ext;
2651 
2652          buffer = dzn_buffer_from_handle(dedicated->buffer);
2653          image = dzn_image_from_handle(dedicated->image);
2654          assert(!buffer || !image);
2655          break;
2656       }
2657       default:
2658          vk_debug_ignored_stype(ext->sType);
2659          break;
2660       }
2661    }
2662 
2663    const VkMemoryType *mem_type =
2664       &pdevice->memory.memoryTypes[pAllocateInfo->memoryTypeIndex];
2665 
2666    D3D12_HEAP_DESC heap_desc = { 0 };
2667 
2668    heap_desc.SizeInBytes = pAllocateInfo->allocationSize;
2669    if (buffer) {
2670       heap_desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
2671    } else if (image) {
2672       heap_desc.Alignment =
2673          image->vk.samples > 1 ?
2674          D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT :
2675          D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
2676    } else {
2677       heap_desc.Alignment =
2678          heap_desc.SizeInBytes >= D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT ?
2679          D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT :
2680          D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
2681    }
2682 
2683    if (mem_type->propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
2684       image = NULL;
2685 
2686    VkExternalMemoryHandleTypeFlags valid_flags =
2687       opaque_external_flag |
2688       (buffer || image ?
2689        VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT :
2690        VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT);
2691    if (image && imported_from_d3d11)
2692       valid_flags |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT;
2693 
2694    if (export_flags & ~valid_flags)
2695       return vk_error(device, VK_ERROR_INVALID_EXTERNAL_HANDLE);
2696 
2697    struct dzn_device_memory *mem =
2698       vk_zalloc2(&device->vk.alloc, pAllocator, sizeof(*mem), 8,
2699                  VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
2700    if (!mem)
2701       return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
2702 
2703    vk_object_base_init(&device->vk, &mem->base, VK_OBJECT_TYPE_DEVICE_MEMORY);
2704 #ifndef _WIN32
2705    mem->export_handle = (HANDLE)(intptr_t)-1;
2706 #endif
2707 
2708    /* The Vulkan 1.0.33 spec says "allocationSize must be greater than 0". */
2709    assert(pAllocateInfo->allocationSize > 0);
2710 
2711    mem->size = pAllocateInfo->allocationSize;
2712 
2713    heap_desc.SizeInBytes = ALIGN_POT(heap_desc.SizeInBytes, heap_desc.Alignment);
2714    if (!image && !buffer)
2715       heap_desc.Flags =
2716          dzn_physical_device_get_heap_flags_for_mem_type(pdevice, pAllocateInfo->memoryTypeIndex);
2717    heap_desc.Properties = deduce_heap_properties_from_memory(pdevice, mem_type);
2718    if (export_flags) {
2719       heap_desc.Flags |= D3D12_HEAP_FLAG_SHARED;
2720       assert(host_pointer || heap_desc.Properties.CPUPageProperty == D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE);
2721    }
2722 
2723    VkResult error = VK_ERROR_OUT_OF_DEVICE_MEMORY;
2724 
2725 #ifdef _WIN32
2726    HANDLE handle_from_name = NULL;
2727    if (import_name) {
2728       if (FAILED(ID3D12Device_OpenSharedHandleByName(device->dev, import_name, GENERIC_ALL, &handle_from_name))) {
2729          error = VK_ERROR_INVALID_EXTERNAL_HANDLE;
2730          goto cleanup;
2731       }
2732       import_handle = handle_from_name;
2733    }
2734 #endif
2735 
2736    if (host_pointer) {
2737       error = VK_ERROR_INVALID_EXTERNAL_HANDLE;
2738 
2739 #if defined(_WIN32)
2740       if (!device->dev13)
2741          goto cleanup;
2742 
2743       if (FAILED(ID3D12Device13_OpenExistingHeapFromAddress1(device->dev13, host_pointer, heap_desc.SizeInBytes, &IID_ID3D12Heap, (void**)&mem->heap)))
2744          goto cleanup;
2745 
2746       D3D12_HEAP_DESC desc = dzn_ID3D12Heap_GetDesc(mem->heap);
2747       if (desc.Properties.Type != D3D12_HEAP_TYPE_CUSTOM)
2748          desc.Properties = dzn_ID3D12Device4_GetCustomHeapProperties(device->dev, 0, desc.Properties.Type);
2749 
2750       if ((heap_desc.Flags & ~desc.Flags) ||
2751           desc.Properties.CPUPageProperty != heap_desc.Properties.CPUPageProperty ||
2752           desc.Properties.MemoryPoolPreference != heap_desc.Properties.MemoryPoolPreference)
2753          goto cleanup;
2754 
2755       mem->map = host_pointer;
2756       mem->res_flags = D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER;
2757 #else
2758       goto cleanup;
2759 #endif
2760    } else if (import_handle) {
2761       error = VK_ERROR_INVALID_EXTERNAL_HANDLE;
2762       if (image || buffer) {
2763          if (FAILED(ID3D12Device_OpenSharedHandle(device->dev, import_handle, &IID_ID3D12Resource, (void **)&mem->dedicated_res)))
2764             goto cleanup;
2765 
2766          /* Verify compatibility */
2767          D3D12_RESOURCE_DESC desc = dzn_ID3D12Resource_GetDesc(mem->dedicated_res);
2768          D3D12_HEAP_PROPERTIES opened_props = { 0 };
2769          D3D12_HEAP_FLAGS opened_flags = 0;
2770          ID3D12Resource_GetHeapProperties(mem->dedicated_res, &opened_props, &opened_flags);
2771          if (opened_props.Type != D3D12_HEAP_TYPE_CUSTOM)
2772             opened_props = dzn_ID3D12Device4_GetCustomHeapProperties(device->dev, 0, opened_props.Type);
2773 
2774          /* Don't validate format, cast lists aren't reflectable so it could be valid */
2775          if (image) {
2776             if (desc.Dimension != image->desc.Dimension ||
2777                 desc.MipLevels != image->desc.MipLevels ||
2778                 desc.Width != image->desc.Width ||
2779                 desc.Height != image->desc.Height ||
2780                 desc.DepthOrArraySize != image->desc.DepthOrArraySize ||
2781                 (image->desc.Flags & ~desc.Flags) ||
2782                 desc.SampleDesc.Count != image->desc.SampleDesc.Count)
2783                goto cleanup;
2784          } else if (desc.Dimension != D3D12_RESOURCE_DIMENSION_BUFFER ||
2785                     desc.Width != buffer->desc.Width ||
2786                     buffer->desc.Flags & ~(desc.Flags))
2787             goto cleanup;
2788          if (opened_props.CPUPageProperty != heap_desc.Properties.CPUPageProperty ||
2789              opened_props.MemoryPoolPreference != heap_desc.Properties.MemoryPoolPreference)
2790             goto cleanup;
2791          if ((heap_desc.Flags & D3D12_HEAP_FLAG_DENY_BUFFERS) && desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
2792             goto cleanup;
2793          if ((heap_desc.Flags & D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES) && (desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET))
2794             goto cleanup;
2795          else if ((heap_desc.Flags & D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES) && !(desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET))
2796             goto cleanup;
2797       } else {
2798          if (FAILED(ID3D12Device_OpenSharedHandle(device->dev, import_handle, &IID_ID3D12Heap, (void **)&mem->heap)))
2799             goto cleanup;
2800 
2801          D3D12_HEAP_DESC desc = dzn_ID3D12Heap_GetDesc(mem->heap);
2802          if (desc.Properties.Type != D3D12_HEAP_TYPE_CUSTOM)
2803             desc.Properties = dzn_ID3D12Device4_GetCustomHeapProperties(device->dev, 0, desc.Properties.Type);
2804 
2805          if (desc.Alignment < heap_desc.Alignment ||
2806              desc.SizeInBytes < heap_desc.SizeInBytes ||
2807              (heap_desc.Flags & ~desc.Flags) ||
2808              desc.Properties.CPUPageProperty != heap_desc.Properties.CPUPageProperty ||
2809              desc.Properties.MemoryPoolPreference != heap_desc.Properties.MemoryPoolPreference)
2810             goto cleanup;
2811       }
2812    } else if (image) {
2813       if (device->dev10 && image->castable_format_count > 0) {
2814          D3D12_RESOURCE_DESC1 desc = {
2815             .Dimension = image->desc.Dimension,
2816             .Alignment = image->desc.Alignment,
2817             .Width = image->desc.Width,
2818             .Height = image->desc.Height,
2819             .DepthOrArraySize = image->desc.DepthOrArraySize,
2820             .MipLevels = image->desc.MipLevels,
2821             .Format = image->desc.Format,
2822             .SampleDesc = image->desc.SampleDesc,
2823             .Layout = image->desc.Layout,
2824             .Flags = image->desc.Flags,
2825          };
2826          if (FAILED(ID3D12Device10_CreateCommittedResource3(device->dev10, &heap_desc.Properties,
2827                                                             heap_desc.Flags, &desc,
2828                                                             D3D12_BARRIER_LAYOUT_COMMON,
2829                                                             NULL, NULL,
2830                                                             image->castable_format_count,
2831                                                             image->castable_formats,
2832                                                             &IID_ID3D12Resource,
2833                                                             (void **)&mem->dedicated_res)))
2834             goto cleanup;
2835       } else if (FAILED(ID3D12Device1_CreateCommittedResource(device->dev, &heap_desc.Properties,
2836                                                               heap_desc.Flags, &image->desc,
2837                                                               D3D12_RESOURCE_STATE_COMMON,
2838                                                               NULL,
2839                                                               &IID_ID3D12Resource,
2840                                                               (void **)&mem->dedicated_res)))
2841          goto cleanup;
2842    } else if (buffer) {
2843       if (FAILED(ID3D12Device1_CreateCommittedResource(device->dev, &heap_desc.Properties,
2844                                                        heap_desc.Flags, &buffer->desc,
2845                                                        D3D12_RESOURCE_STATE_COMMON,
2846                                                        NULL,
2847                                                        &IID_ID3D12Resource,
2848                                                        (void **)&mem->dedicated_res)))
2849          goto cleanup;
2850    } else {
2851       if (FAILED(ID3D12Device1_CreateHeap(device->dev, &heap_desc,
2852                                           &IID_ID3D12Heap,
2853                                           (void **)&mem->heap)))
2854          goto cleanup;
2855    }
2856 
2857    if ((mem_type->propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) &&
2858        !(heap_desc.Flags & D3D12_HEAP_FLAG_DENY_BUFFERS) &&
2859        !mem->map){
2860       assert(!image);
2861       if (buffer) {
2862          mem->map_res = mem->dedicated_res;
2863          ID3D12Resource_AddRef(mem->map_res);
2864       } else {
2865          D3D12_RESOURCE_DESC res_desc = { 0 };
2866          res_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
2867          res_desc.Format = DXGI_FORMAT_UNKNOWN;
2868          res_desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
2869          res_desc.Width = heap_desc.SizeInBytes;
2870          res_desc.Height = 1;
2871          res_desc.DepthOrArraySize = 1;
2872          res_desc.MipLevels = 1;
2873          res_desc.SampleDesc.Count = 1;
2874          res_desc.SampleDesc.Quality = 0;
2875          res_desc.Flags = D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
2876          res_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
2877          HRESULT hr = ID3D12Device1_CreatePlacedResource(device->dev, mem->heap, 0, &res_desc,
2878                                                          D3D12_RESOURCE_STATE_COMMON,
2879                                                          NULL,
2880                                                          &IID_ID3D12Resource,
2881                                                          (void **)&mem->map_res);
2882          if (FAILED(hr))
2883             goto cleanup;
2884       }
2885    }
2886 
2887    if (export_flags) {
2888       error = VK_ERROR_INVALID_EXTERNAL_HANDLE;
2889       ID3D12DeviceChild *shareable = mem->heap ? (void *)mem->heap : (void *)mem->dedicated_res;
2890       DWORD dwAccess = GENERIC_ALL; /* Ignore any provided access, this is the only one D3D allows */
2891 #ifdef _WIN32
2892       const SECURITY_ATTRIBUTES *pAttributes = win32_export ? win32_export->pAttributes : NULL;
2893       const wchar_t *name = win32_export ? win32_export->name : NULL;
2894 #else
2895       const SECURITY_ATTRIBUTES *pAttributes = NULL;
2896       const wchar_t *name = NULL;
2897 #endif
2898       if (FAILED(ID3D12Device_CreateSharedHandle(device->dev, shareable, pAttributes,
2899                                                  dwAccess, name, &mem->export_handle)))
2900          goto cleanup;
2901    }
2902 
2903    *out = dzn_device_memory_to_handle(mem);
2904    return VK_SUCCESS;
2905 
2906 cleanup:
2907 #ifdef _WIN32
2908    if (handle_from_name)
2909       CloseHandle(handle_from_name);
2910 #endif
2911    dzn_device_memory_destroy(mem, pAllocator);
2912    return vk_error(device, error);
2913 }
2914 
2915 VKAPI_ATTR VkResult VKAPI_CALL
dzn_AllocateMemory(VkDevice device,const VkMemoryAllocateInfo * pAllocateInfo,const VkAllocationCallbacks * pAllocator,VkDeviceMemory * pMem)2916 dzn_AllocateMemory(VkDevice device,
2917                    const VkMemoryAllocateInfo *pAllocateInfo,
2918                    const VkAllocationCallbacks *pAllocator,
2919                    VkDeviceMemory *pMem)
2920 {
2921    return dzn_device_memory_create(dzn_device_from_handle(device),
2922                                    pAllocateInfo, pAllocator, pMem);
2923 }
2924 
2925 VKAPI_ATTR void VKAPI_CALL
dzn_FreeMemory(VkDevice device,VkDeviceMemory mem,const VkAllocationCallbacks * pAllocator)2926 dzn_FreeMemory(VkDevice device,
2927                VkDeviceMemory mem,
2928                const VkAllocationCallbacks *pAllocator)
2929 {
2930    dzn_device_memory_destroy(dzn_device_memory_from_handle(mem), pAllocator);
2931 }
2932 
2933 VKAPI_ATTR VkResult VKAPI_CALL
dzn_MapMemory(VkDevice _device,VkDeviceMemory _memory,VkDeviceSize offset,VkDeviceSize size,VkMemoryMapFlags flags,void ** ppData)2934 dzn_MapMemory(VkDevice _device,
2935               VkDeviceMemory _memory,
2936               VkDeviceSize offset,
2937               VkDeviceSize size,
2938               VkMemoryMapFlags flags,
2939               void **ppData)
2940 {
2941    VK_FROM_HANDLE(dzn_device, device, _device);
2942    VK_FROM_HANDLE(dzn_device_memory, mem, _memory);
2943 
2944    if (mem == NULL) {
2945       *ppData = NULL;
2946       return VK_SUCCESS;
2947    }
2948 
2949    if (mem->map && !mem->map_res) {
2950       *ppData = ((uint8_t *)mem->map) + offset;
2951       return VK_SUCCESS;
2952    }
2953 
2954    if (size == VK_WHOLE_SIZE)
2955       size = mem->size - offset;
2956 
2957    /* From the Vulkan spec version 1.0.32 docs for MapMemory:
2958     *
2959     *  * If size is not equal to VK_WHOLE_SIZE, size must be greater than 0
2960     *    assert(size != 0);
2961     *  * If size is not equal to VK_WHOLE_SIZE, size must be less than or
2962     *    equal to the size of the memory minus offset
2963     */
2964    assert(size > 0);
2965    assert(offset + size <= mem->size);
2966 
2967    assert(mem->map_res);
2968    D3D12_RANGE range = { 0 };
2969    range.Begin = offset;
2970    range.End = offset + size;
2971    void *map = NULL;
2972    if (FAILED(ID3D12Resource_Map(mem->map_res, 0, &range, &map)))
2973       return vk_error(device, VK_ERROR_MEMORY_MAP_FAILED);
2974 
2975    mem->map = map;
2976    mem->map_size = size;
2977 
2978    *ppData = ((uint8_t *) map) + offset;
2979 
2980    return VK_SUCCESS;
2981 }
2982 
2983 VKAPI_ATTR void VKAPI_CALL
dzn_UnmapMemory(VkDevice _device,VkDeviceMemory _memory)2984 dzn_UnmapMemory(VkDevice _device,
2985                 VkDeviceMemory _memory)
2986 {
2987    VK_FROM_HANDLE(dzn_device_memory, mem, _memory);
2988 
2989    if (mem == NULL)
2990       return;
2991 
2992    if (!mem->map_res)
2993       return;
2994 
2995    ID3D12Resource_Unmap(mem->map_res, 0, NULL);
2996 
2997    mem->map = NULL;
2998    mem->map_size = 0;
2999 }
3000 
3001 VKAPI_ATTR VkResult VKAPI_CALL
dzn_FlushMappedMemoryRanges(VkDevice _device,uint32_t memoryRangeCount,const VkMappedMemoryRange * pMemoryRanges)3002 dzn_FlushMappedMemoryRanges(VkDevice _device,
3003                             uint32_t memoryRangeCount,
3004                             const VkMappedMemoryRange *pMemoryRanges)
3005 {
3006    return VK_SUCCESS;
3007 }
3008 
3009 VKAPI_ATTR VkResult VKAPI_CALL
dzn_InvalidateMappedMemoryRanges(VkDevice _device,uint32_t memoryRangeCount,const VkMappedMemoryRange * pMemoryRanges)3010 dzn_InvalidateMappedMemoryRanges(VkDevice _device,
3011                                  uint32_t memoryRangeCount,
3012                                  const VkMappedMemoryRange *pMemoryRanges)
3013 {
3014    return VK_SUCCESS;
3015 }
3016 
3017 static void
dzn_buffer_destroy(struct dzn_buffer * buf,const VkAllocationCallbacks * pAllocator)3018 dzn_buffer_destroy(struct dzn_buffer *buf, const VkAllocationCallbacks *pAllocator)
3019 {
3020    if (!buf)
3021       return;
3022 
3023    struct dzn_device *device = container_of(buf->base.device, struct dzn_device, vk);
3024 
3025    if (buf->res)
3026       ID3D12Resource_Release(buf->res);
3027 
3028    dzn_device_descriptor_heap_free_slot(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, buf->cbv_bindless_slot);
3029    dzn_device_descriptor_heap_free_slot(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, buf->uav_bindless_slot);
3030    if (buf->custom_views) {
3031       hash_table_foreach(buf->custom_views, entry) {
3032          free((void *)entry->key);
3033          dzn_device_descriptor_heap_free_slot(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, (int)(intptr_t)entry->data);
3034       }
3035       _mesa_hash_table_destroy(buf->custom_views, NULL);
3036    }
3037 
3038    vk_object_base_finish(&buf->base);
3039    vk_free2(&device->vk.alloc, pAllocator, buf);
3040 }
3041 
3042 static VkResult
dzn_buffer_create(struct dzn_device * device,const VkBufferCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkBuffer * out)3043 dzn_buffer_create(struct dzn_device *device,
3044                   const VkBufferCreateInfo *pCreateInfo,
3045                   const VkAllocationCallbacks *pAllocator,
3046                   VkBuffer *out)
3047 {
3048    struct dzn_buffer *buf =
3049       vk_zalloc2(&device->vk.alloc, pAllocator, sizeof(*buf), 8,
3050                  VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
3051    if (!buf)
3052      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
3053 
3054    vk_object_base_init(&device->vk, &buf->base, VK_OBJECT_TYPE_BUFFER);
3055    buf->create_flags = pCreateInfo->flags;
3056    buf->size = pCreateInfo->size;
3057    buf->usage = pCreateInfo->usage;
3058 
3059    if (buf->usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)
3060       buf->size = MAX2(buf->size, ALIGN_POT(buf->size, 256));
3061    if (buf->usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
3062       buf->size = MAX2(buf->size, ALIGN_POT(buf->size, 4));
3063 
3064    buf->desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
3065    buf->desc.Format = DXGI_FORMAT_UNKNOWN;
3066    buf->desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
3067    buf->desc.Width = buf->size;
3068    buf->desc.Height = 1;
3069    buf->desc.DepthOrArraySize = 1;
3070    buf->desc.MipLevels = 1;
3071    buf->desc.SampleDesc.Count = 1;
3072    buf->desc.SampleDesc.Quality = 0;
3073    buf->desc.Flags = D3D12_RESOURCE_FLAG_NONE;
3074    buf->desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
3075    buf->valid_access =
3076       D3D12_BARRIER_ACCESS_VERTEX_BUFFER |
3077       D3D12_BARRIER_ACCESS_CONSTANT_BUFFER |
3078       D3D12_BARRIER_ACCESS_INDEX_BUFFER |
3079       D3D12_BARRIER_ACCESS_SHADER_RESOURCE |
3080       D3D12_BARRIER_ACCESS_STREAM_OUTPUT |
3081       D3D12_BARRIER_ACCESS_INDIRECT_ARGUMENT |
3082       D3D12_BARRIER_ACCESS_PREDICATION |
3083       D3D12_BARRIER_ACCESS_COPY_DEST |
3084       D3D12_BARRIER_ACCESS_COPY_SOURCE |
3085       D3D12_BARRIER_ACCESS_RAYTRACING_ACCELERATION_STRUCTURE_READ |
3086       D3D12_BARRIER_ACCESS_RAYTRACING_ACCELERATION_STRUCTURE_WRITE;
3087 
3088    if (buf->usage &
3089        (VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
3090         VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT |
3091         VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT)) {
3092       buf->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
3093       buf->valid_access |= D3D12_BARRIER_ACCESS_UNORDERED_ACCESS;
3094    }
3095 
3096    buf->cbv_bindless_slot = buf->uav_bindless_slot = -1;
3097    if (device->bindless) {
3098       if (buf->usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) {
3099          buf->cbv_bindless_slot = dzn_device_descriptor_heap_alloc_slot(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
3100          if (buf->cbv_bindless_slot < 0) {
3101             dzn_buffer_destroy(buf, pAllocator);
3102             return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
3103          }
3104       }
3105       if (buf->usage & (VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT)) {
3106          buf->uav_bindless_slot = dzn_device_descriptor_heap_alloc_slot(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
3107          if (buf->uav_bindless_slot < 0) {
3108             dzn_buffer_destroy(buf, pAllocator);
3109             return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
3110          }
3111       }
3112    }
3113 
3114    if (device->bindless)
3115       mtx_init(&buf->bindless_view_lock, mtx_plain);
3116 
3117    const VkExternalMemoryBufferCreateInfo *external_info =
3118       vk_find_struct_const(pCreateInfo->pNext, EXTERNAL_MEMORY_BUFFER_CREATE_INFO);
3119    if (external_info && external_info->handleTypes != 0)
3120       buf->shared = true;
3121 
3122    *out = dzn_buffer_to_handle(buf);
3123    return VK_SUCCESS;
3124 }
3125 
3126 DXGI_FORMAT
dzn_buffer_get_dxgi_format(VkFormat format)3127 dzn_buffer_get_dxgi_format(VkFormat format)
3128 {
3129    enum pipe_format pfmt = vk_format_to_pipe_format(format);
3130 
3131    return dzn_pipe_to_dxgi_format(pfmt);
3132 }
3133 
3134 D3D12_TEXTURE_COPY_LOCATION
dzn_buffer_get_copy_loc(const struct dzn_buffer * buf,VkFormat format,const VkBufferImageCopy2 * region,VkImageAspectFlagBits aspect,uint32_t layer)3135 dzn_buffer_get_copy_loc(const struct dzn_buffer *buf,
3136                         VkFormat format,
3137                         const VkBufferImageCopy2 *region,
3138                         VkImageAspectFlagBits aspect,
3139                         uint32_t layer)
3140 {
3141    struct dzn_physical_device *pdev =
3142       container_of(buf->base.device->physical, struct dzn_physical_device, vk);
3143    const uint32_t buffer_row_length =
3144       region->bufferRowLength ? region->bufferRowLength : region->imageExtent.width;
3145 
3146    VkFormat plane_format = dzn_image_get_plane_format(format, aspect);
3147 
3148    enum pipe_format pfmt = vk_format_to_pipe_format(plane_format);
3149    uint32_t blksz = util_format_get_blocksize(pfmt);
3150    uint32_t blkw = util_format_get_blockwidth(pfmt);
3151    uint32_t blkh = util_format_get_blockheight(pfmt);
3152 
3153    D3D12_TEXTURE_COPY_LOCATION loc = {
3154      .pResource = buf->res,
3155      .Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT,
3156      .PlacedFootprint = {
3157         .Footprint = {
3158            .Format =
3159               dzn_image_get_placed_footprint_format(pdev, format, aspect),
3160            .Width = region->imageExtent.width,
3161            .Height = region->imageExtent.height,
3162            .Depth = region->imageExtent.depth,
3163            .RowPitch = blksz * DIV_ROUND_UP(buffer_row_length, blkw),
3164         },
3165      },
3166    };
3167 
3168    uint32_t buffer_layer_stride =
3169       loc.PlacedFootprint.Footprint.RowPitch *
3170       DIV_ROUND_UP(loc.PlacedFootprint.Footprint.Height, blkh);
3171 
3172    loc.PlacedFootprint.Offset =
3173       region->bufferOffset + (layer * buffer_layer_stride);
3174 
3175    return loc;
3176 }
3177 
3178 D3D12_TEXTURE_COPY_LOCATION
dzn_buffer_get_line_copy_loc(const struct dzn_buffer * buf,VkFormat format,const VkBufferImageCopy2 * region,const D3D12_TEXTURE_COPY_LOCATION * loc,uint32_t y,uint32_t z,uint32_t * start_x)3179 dzn_buffer_get_line_copy_loc(const struct dzn_buffer *buf, VkFormat format,
3180                              const VkBufferImageCopy2 *region,
3181                              const D3D12_TEXTURE_COPY_LOCATION *loc,
3182                              uint32_t y, uint32_t z, uint32_t *start_x)
3183 {
3184    uint32_t buffer_row_length =
3185       region->bufferRowLength ? region->bufferRowLength : region->imageExtent.width;
3186    uint32_t buffer_image_height =
3187       region->bufferImageHeight ? region->bufferImageHeight : region->imageExtent.height;
3188 
3189    format = dzn_image_get_plane_format(format, region->imageSubresource.aspectMask);
3190 
3191    enum pipe_format pfmt = vk_format_to_pipe_format(format);
3192    uint32_t blksz = util_format_get_blocksize(pfmt);
3193    uint32_t blkw = util_format_get_blockwidth(pfmt);
3194    uint32_t blkh = util_format_get_blockheight(pfmt);
3195    uint32_t blkd = util_format_get_blockdepth(pfmt);
3196    D3D12_TEXTURE_COPY_LOCATION new_loc = *loc;
3197    uint32_t buffer_row_stride =
3198       DIV_ROUND_UP(buffer_row_length, blkw) * blksz;
3199    uint32_t buffer_layer_stride =
3200       buffer_row_stride *
3201       DIV_ROUND_UP(buffer_image_height, blkh);
3202 
3203    uint64_t tex_offset =
3204       ((y / blkh) * buffer_row_stride) +
3205       ((z / blkd) * buffer_layer_stride);
3206    uint64_t offset = loc->PlacedFootprint.Offset + tex_offset;
3207    uint32_t offset_alignment = D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT;
3208 
3209    while (offset_alignment % blksz)
3210       offset_alignment += D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT;
3211 
3212    new_loc.PlacedFootprint.Footprint.Height = blkh;
3213    new_loc.PlacedFootprint.Footprint.Depth = 1;
3214    new_loc.PlacedFootprint.Offset = (offset / offset_alignment) * offset_alignment;
3215    *start_x = ((offset % offset_alignment) / blksz) * blkw;
3216    new_loc.PlacedFootprint.Footprint.Width = *start_x + region->imageExtent.width;
3217    new_loc.PlacedFootprint.Footprint.RowPitch =
3218       ALIGN_POT(DIV_ROUND_UP(new_loc.PlacedFootprint.Footprint.Width, blkw) * blksz,
3219                 D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
3220    return new_loc;
3221 }
3222 
3223 bool
dzn_buffer_supports_region_copy(struct dzn_physical_device * pdev,const D3D12_TEXTURE_COPY_LOCATION * loc)3224 dzn_buffer_supports_region_copy(struct dzn_physical_device *pdev,
3225                                 const D3D12_TEXTURE_COPY_LOCATION *loc)
3226 {
3227    if (pdev->options13.UnrestrictedBufferTextureCopyPitchSupported)
3228       return true;
3229    return !(loc->PlacedFootprint.Offset & (D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT - 1)) &&
3230           !(loc->PlacedFootprint.Footprint.RowPitch & (D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1));
3231 }
3232 
3233 VKAPI_ATTR VkResult VKAPI_CALL
dzn_CreateBuffer(VkDevice device,const VkBufferCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkBuffer * pBuffer)3234 dzn_CreateBuffer(VkDevice device,
3235                  const VkBufferCreateInfo *pCreateInfo,
3236                  const VkAllocationCallbacks *pAllocator,
3237                  VkBuffer *pBuffer)
3238 {
3239    return dzn_buffer_create(dzn_device_from_handle(device),
3240                             pCreateInfo, pAllocator, pBuffer);
3241 }
3242 
3243 VKAPI_ATTR void VKAPI_CALL
dzn_DestroyBuffer(VkDevice device,VkBuffer buffer,const VkAllocationCallbacks * pAllocator)3244 dzn_DestroyBuffer(VkDevice device,
3245                   VkBuffer buffer,
3246                   const VkAllocationCallbacks *pAllocator)
3247 {
3248    dzn_buffer_destroy(dzn_buffer_from_handle(buffer), pAllocator);
3249 }
3250 
3251 VKAPI_ATTR void VKAPI_CALL
dzn_GetBufferMemoryRequirements2(VkDevice dev,const VkBufferMemoryRequirementsInfo2 * pInfo,VkMemoryRequirements2 * pMemoryRequirements)3252 dzn_GetBufferMemoryRequirements2(VkDevice dev,
3253                                  const VkBufferMemoryRequirementsInfo2 *pInfo,
3254                                  VkMemoryRequirements2 *pMemoryRequirements)
3255 {
3256    VK_FROM_HANDLE(dzn_device, device, dev);
3257    VK_FROM_HANDLE(dzn_buffer, buffer, pInfo->buffer);
3258    struct dzn_physical_device *pdev =
3259       container_of(device->vk.physical, struct dzn_physical_device, vk);
3260 
3261    uint32_t alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
3262    VkDeviceSize size = buffer->size;
3263 
3264    if (buffer->usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) {
3265       alignment = MAX2(alignment, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT);
3266       size = ALIGN_POT(size, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT);
3267    }
3268 
3269    pMemoryRequirements->memoryRequirements.size = size;
3270    pMemoryRequirements->memoryRequirements.alignment = alignment;
3271    pMemoryRequirements->memoryRequirements.memoryTypeBits =
3272       dzn_physical_device_get_mem_type_mask_for_resource(pdev, &buffer->desc, buffer->shared);
3273 
3274    vk_foreach_struct(ext, pMemoryRequirements->pNext) {
3275       switch (ext->sType) {
3276       case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS: {
3277          VkMemoryDedicatedRequirements *requirements =
3278             (VkMemoryDedicatedRequirements *)ext;
3279          requirements->requiresDedicatedAllocation = false;
3280          requirements->prefersDedicatedAllocation = false;
3281          break;
3282       }
3283 
3284       default:
3285          vk_debug_ignored_stype(ext->sType);
3286          break;
3287       }
3288    }
3289 }
3290 
3291 VKAPI_ATTR VkResult VKAPI_CALL
dzn_BindBufferMemory2(VkDevice _device,uint32_t bindInfoCount,const VkBindBufferMemoryInfo * pBindInfos)3292 dzn_BindBufferMemory2(VkDevice _device,
3293                       uint32_t bindInfoCount,
3294                       const VkBindBufferMemoryInfo *pBindInfos)
3295 {
3296    VK_FROM_HANDLE(dzn_device, device, _device);
3297 
3298    for (uint32_t i = 0; i < bindInfoCount; i++) {
3299       assert(pBindInfos[i].sType == VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO);
3300 
3301       VK_FROM_HANDLE(dzn_device_memory, mem, pBindInfos[i].memory);
3302       VK_FROM_HANDLE(dzn_buffer, buffer, pBindInfos[i].buffer);
3303 
3304       if (mem->dedicated_res) {
3305          assert(pBindInfos[i].memoryOffset == 0 &&
3306                 buffer->size == mem->size);
3307          buffer->res = mem->dedicated_res;
3308          ID3D12Resource_AddRef(buffer->res);
3309       } else {
3310          D3D12_RESOURCE_DESC desc = buffer->desc;
3311          desc.Flags |= mem->res_flags;
3312          if (FAILED(ID3D12Device1_CreatePlacedResource(device->dev, mem->heap,
3313                                                        pBindInfos[i].memoryOffset,
3314                                                        &buffer->desc,
3315                                                        D3D12_RESOURCE_STATE_COMMON,
3316                                                        NULL,
3317                                                        &IID_ID3D12Resource,
3318                                                        (void **)&buffer->res)))
3319             return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
3320       }
3321 
3322       buffer->gpuva = ID3D12Resource_GetGPUVirtualAddress(buffer->res);
3323 
3324       if (device->bindless) {
3325          struct dzn_buffer_desc buf_desc = {
3326             .buffer = buffer,
3327             .offset = 0,
3328             .range = VK_WHOLE_SIZE,
3329          };
3330          if (buffer->cbv_bindless_slot >= 0) {
3331             buf_desc.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
3332             dzn_descriptor_heap_write_buffer_desc(device,
3333                                                   &device->device_heaps[D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV].heap,
3334                                                   buffer->cbv_bindless_slot,
3335                                                   false,
3336                                                   &buf_desc);
3337          }
3338          if (buffer->uav_bindless_slot >= 0) {
3339             buf_desc.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
3340             dzn_descriptor_heap_write_buffer_desc(device,
3341                                                   &device->device_heaps[D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV].heap,
3342                                                   buffer->uav_bindless_slot,
3343                                                   true,
3344                                                   &buf_desc);
3345          }
3346       }
3347    }
3348 
3349    return VK_SUCCESS;
3350 }
3351 
3352 static void
dzn_event_destroy(struct dzn_event * event,const VkAllocationCallbacks * pAllocator)3353 dzn_event_destroy(struct dzn_event *event,
3354                   const VkAllocationCallbacks *pAllocator)
3355 {
3356    if (!event)
3357       return;
3358 
3359    struct dzn_device *device =
3360       container_of(event->base.device, struct dzn_device, vk);
3361 
3362    if (event->fence)
3363       ID3D12Fence_Release(event->fence);
3364 
3365    vk_object_base_finish(&event->base);
3366    vk_free2(&device->vk.alloc, pAllocator, event);
3367 }
3368 
3369 static VkResult
dzn_event_create(struct dzn_device * device,const VkEventCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkEvent * out)3370 dzn_event_create(struct dzn_device *device,
3371                  const VkEventCreateInfo *pCreateInfo,
3372                  const VkAllocationCallbacks *pAllocator,
3373                  VkEvent *out)
3374 {
3375    struct dzn_event *event =
3376       vk_zalloc2(&device->vk.alloc, pAllocator, sizeof(*event), 8,
3377                  VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
3378    if (!event)
3379       return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
3380 
3381    vk_object_base_init(&device->vk, &event->base, VK_OBJECT_TYPE_EVENT);
3382 
3383    if (FAILED(ID3D12Device1_CreateFence(device->dev, 0, D3D12_FENCE_FLAG_NONE,
3384                                         &IID_ID3D12Fence,
3385                                         (void **)&event->fence))) {
3386       dzn_event_destroy(event, pAllocator);
3387       return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
3388    }
3389 
3390    *out = dzn_event_to_handle(event);
3391    return VK_SUCCESS;
3392 }
3393 
3394 VKAPI_ATTR VkResult VKAPI_CALL
dzn_CreateEvent(VkDevice device,const VkEventCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkEvent * pEvent)3395 dzn_CreateEvent(VkDevice device,
3396                 const VkEventCreateInfo *pCreateInfo,
3397                 const VkAllocationCallbacks *pAllocator,
3398                 VkEvent *pEvent)
3399 {
3400    return dzn_event_create(dzn_device_from_handle(device),
3401                            pCreateInfo, pAllocator, pEvent);
3402 }
3403 
3404 VKAPI_ATTR void VKAPI_CALL
dzn_DestroyEvent(VkDevice device,VkEvent event,const VkAllocationCallbacks * pAllocator)3405 dzn_DestroyEvent(VkDevice device,
3406                  VkEvent event,
3407                  const VkAllocationCallbacks *pAllocator)
3408 {
3409    dzn_event_destroy(dzn_event_from_handle(event), pAllocator);
3410 }
3411 
3412 VKAPI_ATTR VkResult VKAPI_CALL
dzn_ResetEvent(VkDevice dev,VkEvent evt)3413 dzn_ResetEvent(VkDevice dev,
3414                VkEvent evt)
3415 {
3416    VK_FROM_HANDLE(dzn_device, device, dev);
3417    VK_FROM_HANDLE(dzn_event, event, evt);
3418 
3419    if (FAILED(ID3D12Fence_Signal(event->fence, 0)))
3420       return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
3421 
3422    return VK_SUCCESS;
3423 }
3424 
3425 VKAPI_ATTR VkResult VKAPI_CALL
dzn_SetEvent(VkDevice dev,VkEvent evt)3426 dzn_SetEvent(VkDevice dev,
3427              VkEvent evt)
3428 {
3429    VK_FROM_HANDLE(dzn_device, device, dev);
3430    VK_FROM_HANDLE(dzn_event, event, evt);
3431 
3432    if (FAILED(ID3D12Fence_Signal(event->fence, 1)))
3433       return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
3434 
3435    return VK_SUCCESS;
3436 }
3437 
3438 VKAPI_ATTR VkResult VKAPI_CALL
dzn_GetEventStatus(VkDevice device,VkEvent evt)3439 dzn_GetEventStatus(VkDevice device,
3440                    VkEvent evt)
3441 {
3442    VK_FROM_HANDLE(dzn_event, event, evt);
3443 
3444    return ID3D12Fence_GetCompletedValue(event->fence) == 0 ?
3445           VK_EVENT_RESET : VK_EVENT_SET;
3446 }
3447 
3448 VKAPI_ATTR void VKAPI_CALL
dzn_GetDeviceMemoryCommitment(VkDevice device,VkDeviceMemory memory,VkDeviceSize * pCommittedMemoryInBytes)3449 dzn_GetDeviceMemoryCommitment(VkDevice device,
3450                               VkDeviceMemory memory,
3451                               VkDeviceSize *pCommittedMemoryInBytes)
3452 {
3453    VK_FROM_HANDLE(dzn_device_memory, mem, memory);
3454 
3455    // TODO: find if there's a way to query/track actual heap residency
3456    *pCommittedMemoryInBytes = mem->size;
3457 }
3458 
3459 VKAPI_ATTR VkResult VKAPI_CALL
dzn_QueueBindSparse(VkQueue queue,uint32_t bindInfoCount,const VkBindSparseInfo * pBindInfo,VkFence fence)3460 dzn_QueueBindSparse(VkQueue queue,
3461                     uint32_t bindInfoCount,
3462                     const VkBindSparseInfo *pBindInfo,
3463                     VkFence fence)
3464 {
3465    // FIXME: add proper implem
3466    dzn_stub();
3467    return VK_SUCCESS;
3468 }
3469 
3470 static D3D12_TEXTURE_ADDRESS_MODE
dzn_sampler_translate_addr_mode(VkSamplerAddressMode in)3471 dzn_sampler_translate_addr_mode(VkSamplerAddressMode in)
3472 {
3473    switch (in) {
3474    case VK_SAMPLER_ADDRESS_MODE_REPEAT: return D3D12_TEXTURE_ADDRESS_MODE_WRAP;
3475    case VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: return D3D12_TEXTURE_ADDRESS_MODE_MIRROR;
3476    case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: return D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
3477    case VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: return D3D12_TEXTURE_ADDRESS_MODE_BORDER;
3478    case VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE: return D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE;
3479    default: unreachable("Invalid address mode");
3480    }
3481 }
3482 
3483 static void
dzn_sampler_destroy(struct dzn_sampler * sampler,const VkAllocationCallbacks * pAllocator)3484 dzn_sampler_destroy(struct dzn_sampler *sampler,
3485                     const VkAllocationCallbacks *pAllocator)
3486 {
3487    if (!sampler)
3488       return;
3489 
3490    struct dzn_device *device =
3491       container_of(sampler->base.device, struct dzn_device, vk);
3492 
3493    dzn_device_descriptor_heap_free_slot(device, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, sampler->bindless_slot);
3494 
3495    vk_object_base_finish(&sampler->base);
3496    vk_free2(&device->vk.alloc, pAllocator, sampler);
3497 }
3498 
3499 static VkResult
dzn_sampler_create(struct dzn_device * device,const VkSamplerCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkSampler * out)3500 dzn_sampler_create(struct dzn_device *device,
3501                    const VkSamplerCreateInfo *pCreateInfo,
3502                    const VkAllocationCallbacks *pAllocator,
3503                    VkSampler *out)
3504 {
3505    struct dzn_physical_device *pdev = container_of(device->vk.physical, struct dzn_physical_device, vk);
3506    struct dzn_sampler *sampler =
3507       vk_zalloc2(&device->vk.alloc, pAllocator, sizeof(*sampler), 8,
3508                  VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
3509    if (!sampler)
3510       return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
3511 
3512    vk_object_base_init(&device->vk, &sampler->base, VK_OBJECT_TYPE_SAMPLER);
3513 
3514    const VkSamplerCustomBorderColorCreateInfoEXT *pBorderColor = (const VkSamplerCustomBorderColorCreateInfoEXT *)
3515       vk_find_struct_const(pCreateInfo->pNext, SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT);
3516 
3517    /* TODO: have a sampler pool to allocate shader-invisible descs which we
3518     * can copy to the desc_set when UpdateDescriptorSets() is called.
3519     */
3520    sampler->desc.Filter = dzn_translate_sampler_filter(pdev, pCreateInfo);
3521    sampler->desc.AddressU = dzn_sampler_translate_addr_mode(pCreateInfo->addressModeU);
3522    sampler->desc.AddressV = dzn_sampler_translate_addr_mode(pCreateInfo->addressModeV);
3523    sampler->desc.AddressW = dzn_sampler_translate_addr_mode(pCreateInfo->addressModeW);
3524    sampler->desc.MipLODBias = pCreateInfo->mipLodBias;
3525    sampler->desc.MaxAnisotropy = pCreateInfo->maxAnisotropy;
3526    sampler->desc.MinLOD = pCreateInfo->minLod;
3527    sampler->desc.MaxLOD = pCreateInfo->maxLod;
3528 
3529    if (pCreateInfo->compareEnable)
3530       sampler->desc.ComparisonFunc = dzn_translate_compare_op(pCreateInfo->compareOp);
3531 
3532    bool reads_border_color =
3533       pCreateInfo->addressModeU == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER ||
3534       pCreateInfo->addressModeV == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER ||
3535       pCreateInfo->addressModeW == VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
3536 
3537    if (reads_border_color) {
3538       switch (pCreateInfo->borderColor) {
3539       case VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK:
3540       case VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK:
3541          sampler->desc.FloatBorderColor[0] = 0.0f;
3542          sampler->desc.FloatBorderColor[1] = 0.0f;
3543          sampler->desc.FloatBorderColor[2] = 0.0f;
3544          sampler->desc.FloatBorderColor[3] =
3545             pCreateInfo->borderColor == VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK ? 0.0f : 1.0f;
3546          sampler->static_border_color =
3547             pCreateInfo->borderColor == VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK ?
3548             D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK :
3549             D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK;
3550          break;
3551       case VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE:
3552          sampler->desc.FloatBorderColor[0] = sampler->desc.FloatBorderColor[1] = 1.0f;
3553          sampler->desc.FloatBorderColor[2] = sampler->desc.FloatBorderColor[3] = 1.0f;
3554          sampler->static_border_color = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE;
3555          break;
3556       case VK_BORDER_COLOR_FLOAT_CUSTOM_EXT:
3557          sampler->static_border_color = (D3D12_STATIC_BORDER_COLOR)-1;
3558          for (unsigned i = 0; i < ARRAY_SIZE(sampler->desc.FloatBorderColor); i++)
3559             sampler->desc.FloatBorderColor[i] = pBorderColor->customBorderColor.float32[i];
3560          break;
3561       case VK_BORDER_COLOR_INT_TRANSPARENT_BLACK:
3562       case VK_BORDER_COLOR_INT_OPAQUE_BLACK:
3563          sampler->desc.UintBorderColor[0] = 0;
3564          sampler->desc.UintBorderColor[1] = 0;
3565          sampler->desc.UintBorderColor[2] = 0;
3566          sampler->desc.UintBorderColor[3] =
3567             pCreateInfo->borderColor == VK_BORDER_COLOR_INT_TRANSPARENT_BLACK ? 0 : 1;
3568          sampler->static_border_color =
3569             pCreateInfo->borderColor == VK_BORDER_COLOR_INT_TRANSPARENT_BLACK ?
3570             D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK :
3571             D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK_UINT;
3572          sampler->desc.Flags = D3D12_SAMPLER_FLAG_UINT_BORDER_COLOR;
3573          break;
3574       case VK_BORDER_COLOR_INT_OPAQUE_WHITE:
3575          sampler->desc.UintBorderColor[0] = sampler->desc.UintBorderColor[1] = 1;
3576          sampler->desc.UintBorderColor[2] = sampler->desc.UintBorderColor[3] = 1;
3577          sampler->static_border_color = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE_UINT;
3578          sampler->desc.Flags = D3D12_SAMPLER_FLAG_UINT_BORDER_COLOR;
3579          break;
3580       case VK_BORDER_COLOR_INT_CUSTOM_EXT:
3581          sampler->static_border_color = (D3D12_STATIC_BORDER_COLOR)-1;
3582          for (unsigned i = 0; i < ARRAY_SIZE(sampler->desc.UintBorderColor); i++)
3583             sampler->desc.UintBorderColor[i] = pBorderColor->customBorderColor.uint32[i];
3584          sampler->desc.Flags = D3D12_SAMPLER_FLAG_UINT_BORDER_COLOR;
3585          break;
3586       default:
3587          unreachable("Unsupported border color");
3588       }
3589    }
3590 
3591    if (pCreateInfo->unnormalizedCoordinates && pdev->options17.NonNormalizedCoordinateSamplersSupported)
3592       sampler->desc.Flags |= D3D12_SAMPLER_FLAG_NON_NORMALIZED_COORDINATES;
3593 
3594    sampler->bindless_slot = -1;
3595    if (device->bindless) {
3596       sampler->bindless_slot = dzn_device_descriptor_heap_alloc_slot(device, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
3597       if (sampler->bindless_slot < 0) {
3598          dzn_sampler_destroy(sampler, pAllocator);
3599          return vk_error(device, VK_ERROR_OUT_OF_DEVICE_MEMORY);
3600       }
3601 
3602       dzn_descriptor_heap_write_sampler_desc(device,
3603                                              &device->device_heaps[D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER].heap,
3604                                              sampler->bindless_slot,
3605                                              sampler);
3606    }
3607 
3608    *out = dzn_sampler_to_handle(sampler);
3609    return VK_SUCCESS;
3610 }
3611 
3612 VKAPI_ATTR VkResult VKAPI_CALL
dzn_CreateSampler(VkDevice device,const VkSamplerCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkSampler * pSampler)3613 dzn_CreateSampler(VkDevice device,
3614                   const VkSamplerCreateInfo *pCreateInfo,
3615                   const VkAllocationCallbacks *pAllocator,
3616                   VkSampler *pSampler)
3617 {
3618    return dzn_sampler_create(dzn_device_from_handle(device),
3619                              pCreateInfo, pAllocator, pSampler);
3620 }
3621 
3622 VKAPI_ATTR void VKAPI_CALL
dzn_DestroySampler(VkDevice device,VkSampler sampler,const VkAllocationCallbacks * pAllocator)3623 dzn_DestroySampler(VkDevice device,
3624                    VkSampler sampler,
3625                    const VkAllocationCallbacks *pAllocator)
3626 {
3627    dzn_sampler_destroy(dzn_sampler_from_handle(sampler), pAllocator);
3628 }
3629 
3630 int
dzn_device_descriptor_heap_alloc_slot(struct dzn_device * device,D3D12_DESCRIPTOR_HEAP_TYPE type)3631 dzn_device_descriptor_heap_alloc_slot(struct dzn_device *device,
3632                                       D3D12_DESCRIPTOR_HEAP_TYPE type)
3633 {
3634    struct dzn_device_descriptor_heap *heap = &device->device_heaps[type];
3635    mtx_lock(&heap->lock);
3636 
3637    int ret = -1;
3638    if (heap->slot_freelist.size)
3639       ret = util_dynarray_pop(&heap->slot_freelist, int);
3640    else if (heap->next_alloc_slot < heap->heap.desc_count)
3641       ret = heap->next_alloc_slot++;
3642 
3643    mtx_unlock(&heap->lock);
3644    return ret;
3645 }
3646 
3647 void
dzn_device_descriptor_heap_free_slot(struct dzn_device * device,D3D12_DESCRIPTOR_HEAP_TYPE type,int slot)3648 dzn_device_descriptor_heap_free_slot(struct dzn_device *device,
3649                                      D3D12_DESCRIPTOR_HEAP_TYPE type,
3650                                      int slot)
3651 {
3652    struct dzn_device_descriptor_heap *heap = &device->device_heaps[type];
3653    assert(slot < 0 || slot < heap->heap.desc_count);
3654 
3655    if (slot < 0)
3656       return;
3657 
3658    mtx_lock(&heap->lock);
3659    util_dynarray_append(&heap->slot_freelist, int, slot);
3660    mtx_unlock(&heap->lock);
3661 }
3662 
3663 VKAPI_ATTR void VKAPI_CALL
dzn_GetDeviceGroupPeerMemoryFeatures(VkDevice device,uint32_t heapIndex,uint32_t localDeviceIndex,uint32_t remoteDeviceIndex,VkPeerMemoryFeatureFlags * pPeerMemoryFeatures)3664 dzn_GetDeviceGroupPeerMemoryFeatures(VkDevice device,
3665                                      uint32_t heapIndex,
3666                                      uint32_t localDeviceIndex,
3667                                      uint32_t remoteDeviceIndex,
3668                                      VkPeerMemoryFeatureFlags *pPeerMemoryFeatures)
3669 {
3670    *pPeerMemoryFeatures = 0;
3671 }
3672 
3673 VKAPI_ATTR void VKAPI_CALL
dzn_GetImageSparseMemoryRequirements2(VkDevice device,const VkImageSparseMemoryRequirementsInfo2 * pInfo,uint32_t * pSparseMemoryRequirementCount,VkSparseImageMemoryRequirements2 * pSparseMemoryRequirements)3674 dzn_GetImageSparseMemoryRequirements2(VkDevice device,
3675                                       const VkImageSparseMemoryRequirementsInfo2* pInfo,
3676                                       uint32_t *pSparseMemoryRequirementCount,
3677                                       VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements)
3678 {
3679    *pSparseMemoryRequirementCount = 0;
3680 }
3681 
3682 VKAPI_ATTR VkResult VKAPI_CALL
dzn_CreateSamplerYcbcrConversion(VkDevice device,const VkSamplerYcbcrConversionCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkSamplerYcbcrConversion * pYcbcrConversion)3683 dzn_CreateSamplerYcbcrConversion(VkDevice device,
3684                                  const VkSamplerYcbcrConversionCreateInfo *pCreateInfo,
3685                                  const VkAllocationCallbacks *pAllocator,
3686                                  VkSamplerYcbcrConversion *pYcbcrConversion)
3687 {
3688    unreachable("Ycbcr sampler conversion is not supported");
3689    return VK_SUCCESS;
3690 }
3691 
3692 VKAPI_ATTR void VKAPI_CALL
dzn_DestroySamplerYcbcrConversion(VkDevice device,VkSamplerYcbcrConversion YcbcrConversion,const VkAllocationCallbacks * pAllocator)3693 dzn_DestroySamplerYcbcrConversion(VkDevice device,
3694                                   VkSamplerYcbcrConversion YcbcrConversion,
3695                                   const VkAllocationCallbacks *pAllocator)
3696 {
3697    unreachable("Ycbcr sampler conversion is not supported");
3698 }
3699 
3700 VKAPI_ATTR VkDeviceAddress VKAPI_CALL
dzn_GetBufferDeviceAddress(VkDevice device,const VkBufferDeviceAddressInfo * pInfo)3701 dzn_GetBufferDeviceAddress(VkDevice device,
3702                            const VkBufferDeviceAddressInfo* pInfo)
3703 {
3704    struct dzn_buffer *buffer = dzn_buffer_from_handle(pInfo->buffer);
3705 
3706    /* Insert a pointer tag so we never return null */
3707    return ((uint64_t)buffer->uav_bindless_slot << 32ull) | (0xD3ull << 56);
3708 }
3709 
3710 VKAPI_ATTR uint64_t VKAPI_CALL
dzn_GetBufferOpaqueCaptureAddress(VkDevice device,const VkBufferDeviceAddressInfo * pInfo)3711 dzn_GetBufferOpaqueCaptureAddress(VkDevice device,
3712                                   const VkBufferDeviceAddressInfo *pInfo)
3713 {
3714    return 0;
3715 }
3716 
3717 VKAPI_ATTR uint64_t VKAPI_CALL
dzn_GetDeviceMemoryOpaqueCaptureAddress(VkDevice device,const VkDeviceMemoryOpaqueCaptureAddressInfo * pInfo)3718 dzn_GetDeviceMemoryOpaqueCaptureAddress(VkDevice device,
3719                                         const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo)
3720 {
3721    return 0;
3722 }
3723 
3724 #ifdef _WIN32
3725 VKAPI_ATTR VkResult VKAPI_CALL
dzn_GetMemoryWin32HandleKHR(VkDevice device,const VkMemoryGetWin32HandleInfoKHR * pGetWin32HandleInfo,HANDLE * pHandle)3726 dzn_GetMemoryWin32HandleKHR(VkDevice device,
3727                             const VkMemoryGetWin32HandleInfoKHR *pGetWin32HandleInfo,
3728                             HANDLE *pHandle)
3729 {
3730    VK_FROM_HANDLE(dzn_device_memory, mem, pGetWin32HandleInfo->memory);
3731    if (!mem->export_handle)
3732       return vk_error(device, VK_ERROR_INVALID_EXTERNAL_HANDLE);
3733 
3734    switch (pGetWin32HandleInfo->handleType) {
3735    case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT:
3736    case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT:
3737    case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT:
3738    case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT:
3739       if (!DuplicateHandle(GetCurrentProcess(), mem->export_handle, GetCurrentProcess(), pHandle,
3740                            0, false, DUPLICATE_SAME_ACCESS))
3741          return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
3742       return VK_SUCCESS;
3743    default:
3744       return vk_error(device, VK_ERROR_INVALID_EXTERNAL_HANDLE);
3745    }
3746 }
3747 #else
3748 VKAPI_ATTR VkResult VKAPI_CALL
dzn_GetMemoryFdKHR(VkDevice device,const VkMemoryGetFdInfoKHR * pGetFdInfo,int * pFd)3749 dzn_GetMemoryFdKHR(VkDevice device,
3750                    const VkMemoryGetFdInfoKHR *pGetFdInfo,
3751                    int *pFd)
3752 {
3753    VK_FROM_HANDLE(dzn_device_memory, mem, pGetFdInfo->memory);
3754    if (!mem->export_handle)
3755       return vk_error(device, VK_ERROR_INVALID_EXTERNAL_HANDLE);
3756 
3757    switch (pGetFdInfo->handleType) {
3758    case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT:
3759    case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT:
3760    case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT:
3761       *pFd = (int)(intptr_t)mem->export_handle;
3762       mem->export_handle = (HANDLE)(intptr_t)-1;
3763       return VK_SUCCESS;
3764    default:
3765       return vk_error(device, VK_ERROR_INVALID_EXTERNAL_HANDLE);
3766    }
3767 }
3768 #endif
3769 
3770 #ifdef _WIN32
3771 VKAPI_ATTR VkResult VKAPI_CALL
dzn_GetMemoryWin32HandlePropertiesKHR(VkDevice _device,VkExternalMemoryHandleTypeFlagBits handleType,HANDLE handle,VkMemoryWin32HandlePropertiesKHR * pProperties)3772 dzn_GetMemoryWin32HandlePropertiesKHR(VkDevice _device,
3773                                       VkExternalMemoryHandleTypeFlagBits handleType,
3774                                       HANDLE handle,
3775                                       VkMemoryWin32HandlePropertiesKHR *pProperties)
3776 {
3777 #else
3778 VKAPI_ATTR VkResult VKAPI_CALL
3779 dzn_GetMemoryFdPropertiesKHR(VkDevice _device,
3780                              VkExternalMemoryHandleTypeFlagBits handleType,
3781                              int fd,
3782                              VkMemoryFdPropertiesKHR *pProperties)
3783 {
3784    HANDLE handle = (HANDLE)(intptr_t)fd;
3785 #endif
3786    VK_FROM_HANDLE(dzn_device, device, _device);
3787    IUnknown *opened_object;
3788    if (FAILED(ID3D12Device_OpenSharedHandle(device->dev, handle, &IID_IUnknown, (void **)&opened_object)))
3789       return vk_error(device, VK_ERROR_INVALID_EXTERNAL_HANDLE);
3790 
3791    VkResult result = VK_ERROR_INVALID_EXTERNAL_HANDLE;
3792    ID3D12Resource *res = NULL;
3793    ID3D12Heap *heap = NULL;
3794    struct dzn_physical_device *pdev = container_of(device->vk.physical, struct dzn_physical_device, vk);
3795 
3796    switch (handleType) {
3797    case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT:
3798       (void)IUnknown_QueryInterface(opened_object, &IID_ID3D12Resource, (void **)&res);
3799       (void)IUnknown_QueryInterface(opened_object, &IID_ID3D12Heap, (void **)&heap);
3800       break;
3801    case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT:
3802    case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT:
3803       (void)IUnknown_QueryInterface(opened_object, &IID_ID3D12Resource, (void **)&res);
3804       break;
3805    case VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT:
3806       (void)IUnknown_QueryInterface(opened_object, &IID_ID3D12Heap, (void **)&heap);
3807       break;
3808    default:
3809       goto cleanup;
3810    }
3811    if (!res && !heap)
3812       goto cleanup;
3813 
3814    D3D12_HEAP_DESC heap_desc;
3815    if (res)
3816       ID3D12Resource_GetHeapProperties(res, &heap_desc.Properties, &heap_desc.Flags);
3817    else
3818       heap_desc = dzn_ID3D12Heap_GetDesc(heap);
3819    if (heap_desc.Properties.Type != D3D12_HEAP_TYPE_CUSTOM)
3820       heap_desc.Properties = dzn_ID3D12Device4_GetCustomHeapProperties(device->dev, 0, heap_desc.Properties.Type);
3821 
3822    pProperties->memoryTypeBits = 0;
3823    for (uint32_t i = 0; i < pdev->memory.memoryTypeCount; ++i) {
3824       const VkMemoryType *mem_type = &pdev->memory.memoryTypes[i];
3825       D3D12_HEAP_PROPERTIES required_props = deduce_heap_properties_from_memory(pdev, mem_type);
3826       if (heap_desc.Properties.CPUPageProperty != required_props.CPUPageProperty ||
3827           heap_desc.Properties.MemoryPoolPreference != required_props.MemoryPoolPreference)
3828          continue;
3829 
3830       D3D12_HEAP_FLAGS required_flags = dzn_physical_device_get_heap_flags_for_mem_type(pdev, i);
3831       if ((heap_desc.Flags & required_flags) != required_flags)
3832          continue;
3833 
3834       pProperties->memoryTypeBits |= (1 << i);
3835    }
3836    result = VK_SUCCESS;
3837 
3838 cleanup:
3839    IUnknown_Release(opened_object);
3840    if (res)
3841       ID3D12Resource_Release(res);
3842    if (heap)
3843       ID3D12Heap_Release(heap);
3844    return result;
3845 }
3846 
3847 #if defined(_WIN32)
3848 VKAPI_ATTR VkResult VKAPI_CALL
3849 dzn_GetMemoryHostPointerPropertiesEXT(VkDevice _device,
3850                                       VkExternalMemoryHandleTypeFlagBits handleType,
3851                                       const void *pHostPointer,
3852                                       VkMemoryHostPointerPropertiesEXT *pMemoryHostPointerProperties)
3853 {
3854    VK_FROM_HANDLE(dzn_device, device, _device);
3855 
3856    if (!device->dev13)
3857       return VK_ERROR_FEATURE_NOT_PRESENT;
3858 
3859    ID3D12Heap *heap;
3860    if (FAILED(ID3D12Device13_OpenExistingHeapFromAddress1(device->dev13, pHostPointer, 1, &IID_ID3D12Heap, (void **)&heap)))
3861       return VK_ERROR_INVALID_EXTERNAL_HANDLE;
3862 
3863    struct dzn_physical_device *pdev = container_of(device->vk.physical, struct dzn_physical_device, vk);
3864    D3D12_HEAP_DESC heap_desc = dzn_ID3D12Heap_GetDesc(heap);
3865    pMemoryHostPointerProperties->memoryTypeBits = 0;
3866    for (uint32_t i = 0; i < pdev->memory.memoryTypeCount; ++i) {
3867       const VkMemoryType *mem_type = &pdev->memory.memoryTypes[i];
3868       D3D12_HEAP_PROPERTIES required_props = deduce_heap_properties_from_memory(pdev, mem_type);
3869       if (heap_desc.Properties.CPUPageProperty != required_props.CPUPageProperty ||
3870           heap_desc.Properties.MemoryPoolPreference != required_props.MemoryPoolPreference)
3871          continue;
3872 
3873       pMemoryHostPointerProperties->memoryTypeBits |= (1 << i);
3874    }
3875    ID3D12Heap_Release(heap);
3876    return VK_SUCCESS;
3877 }
3878 #endif
3879