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