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