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