yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Gangzheng TongFix additional VVL violations (#7377)3822f9243

master
97.0 KiB2684 linesraw
1// vk-device.cpp
2#include "vk-device.h"
3
4#include "core/slang-platform.h"
5#include "vk-buffer.h"
6#include "vk-command-queue.h"
7#include "vk-fence.h"
8#include "vk-helper-functions.h"
9#include "vk-pipeline-dump-layer.h"
10#include "vk-query.h"
11#include "vk-render-pass.h"
12#include "vk-resource-views.h"
13#include "vk-sampler.h"
14#include "vk-shader-object-layout.h"
15#include "vk-shader-object.h"
16#include "vk-shader-program.h"
17#include "vk-shader-table.h"
18#include "vk-swap-chain.h"
19#include "vk-transient-heap.h"
20#include "vk-vertex-layout.h"
21
22#ifdef GFX_NV_AFTERMATH
23#include "GFSDK_Aftermath.h"
24#include "GFSDK_Aftermath_Defines.h"
25#include "GFSDK_Aftermath_GpuCrashDump.h"
26#endif
27
28namespace gfx
29{
30
31using namespace Slang;
32
33namespace vk
34{
35
36static bool shouldDumpPipeline()
37{
38    StringBuilder dumpPipelineSettings;
39    PlatformUtil::getEnvironmentVariable(toSlice("SLANG_GFX_DUMP_PIPELINE"), dumpPipelineSettings);
40    return dumpPipelineSettings.produceString() == "1";
41}
42
43DeviceImpl::~DeviceImpl()
44{
45    if (shouldDumpPipeline())
46    {
47        writePipelineDump(toSlice("gfx-vk-pipeline-dump.bin"));
48    }
49
50    // Check the device queue is valid else, we can't wait on it..
51    if (m_deviceQueue.isValid())
52    {
53        waitForGpu();
54    }
55
56    m_shaderObjectLayoutCache = decltype(m_shaderObjectLayoutCache)();
57    shaderCache.free();
58    m_deviceObjectsWithPotentialBackReferences.clearAndDeallocate();
59
60    if (m_api.vkDestroySampler)
61    {
62        m_api.vkDestroySampler(m_device, m_defaultSampler, nullptr);
63    }
64
65    m_deviceQueue.destroy();
66
67    descriptorSetAllocator.close();
68
69    m_emptyFramebuffer = nullptr;
70
71    if (m_device != VK_NULL_HANDLE)
72    {
73        if (m_desc.existingDeviceHandles.handles[2].handleValue == 0)
74            m_api.vkDestroyDevice(m_device, nullptr);
75        m_device = VK_NULL_HANDLE;
76        if (m_debugReportCallback != VK_NULL_HANDLE)
77            m_api.vkDestroyDebugReportCallbackEXT(m_api.m_instance, m_debugReportCallback, nullptr);
78        if (m_api.m_instance != VK_NULL_HANDLE &&
79            m_desc.existingDeviceHandles.handles[0].handleValue == 0)
80            m_api.vkDestroyInstance(m_api.m_instance, nullptr);
81    }
82}
83
84// TODO: Is "location" still needed for this function?
85VkBool32 DeviceImpl::handleDebugMessage(
86    VkDebugReportFlagsEXT flags,
87    VkDebugReportObjectTypeEXT objType,
88    uint64_t srcObject,
89    Size location,
90    int32_t msgCode,
91    const char* pLayerPrefix,
92    const char* pMsg)
93{
94    DebugMessageType msgType = DebugMessageType::Info;
95
96    char const* severity = "message";
97    if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT)
98    {
99        severity = "warning";
100        msgType = DebugMessageType::Warning;
101    }
102    if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT)
103    {
104        severity = "error";
105        msgType = DebugMessageType::Error;
106    }
107
108    // pMsg can be really big (it can be assembler dump for example)
109    // Use a dynamic buffer to store
110    Size bufferSize = strlen(pMsg) + 1 + 1024;
111    List<char> bufferArray;
112    bufferArray.setCount(bufferSize);
113    char* buffer = bufferArray.getBuffer();
114
115    sprintf_s(buffer, bufferSize, "%s: %s %d: %s\n", pLayerPrefix, severity, msgCode, pMsg);
116
117    getDebugCallback()->handleMessage(msgType, DebugMessageSource::Driver, buffer);
118    return VK_FALSE;
119}
120
121VKAPI_ATTR VkBool32 VKAPI_CALL DeviceImpl::debugMessageCallback(
122    VkDebugReportFlagsEXT flags,
123    VkDebugReportObjectTypeEXT objType,
124    uint64_t srcObject,
125    Size location,
126    int32_t msgCode,
127    const char* pLayerPrefix,
128    const char* pMsg,
129    void* pUserData)
130{
131    return ((DeviceImpl*)pUserData)
132        ->handleDebugMessage(flags, objType, srcObject, location, msgCode, pLayerPrefix, pMsg);
133}
134
135Result DeviceImpl::getNativeDeviceHandles(InteropHandles* outHandles)
136{
137    outHandles->handles[0].handleValue = (uint64_t)m_api.m_instance;
138    outHandles->handles[0].api = InteropHandleAPI::Vulkan;
139    outHandles->handles[1].handleValue = (uint64_t)m_api.m_physicalDevice;
140    outHandles->handles[1].api = InteropHandleAPI::Vulkan;
141    outHandles->handles[2].handleValue = (uint64_t)m_api.m_device;
142    outHandles->handles[2].api = InteropHandleAPI::Vulkan;
143    return SLANG_OK;
144}
145
146template<typename T>
147static bool _hasAnySetBits(const T& val, size_t offset)
148{
149    const uint8_t* ptr = reinterpret_cast<const uint8_t*>(&val);
150    for (size_t i = offset; i < sizeof(val); i++)
151        if (ptr[i])
152            return true;
153    return false;
154}
155
156Result DeviceImpl::initVulkanInstanceAndDevice(
157    const InteropHandle* handles,
158    bool useValidationLayer)
159{
160    m_features.clear();
161
162    m_queueAllocCount = 0;
163
164    bool enableRayTracingValidation = false;
165
166    // Read properties from extended device descriptions
167    for (GfxIndex i = 0; i < m_desc.extendedDescCount; i++)
168    {
169        StructType stype;
170        memcpy(&stype, m_desc.extendedDescs[i], sizeof(stype));
171        switch (stype)
172        {
173        case StructType::RayTracingValidationDesc:
174            enableRayTracingValidation =
175                static_cast<RayTracingValidationDesc*>(m_desc.extendedDescs[i])
176                    ->enableRaytracingValidation;
177            break;
178        }
179    }
180
181
182    VkInstance instance = VK_NULL_HANDLE;
183    if (handles[0].handleValue == 0)
184    {
185        VkApplicationInfo applicationInfo = {VK_STRUCTURE_TYPE_APPLICATION_INFO};
186        applicationInfo.pApplicationName = "slang-gfx";
187        applicationInfo.pEngineName = "slang-gfx";
188        applicationInfo.apiVersion = VK_API_VERSION_1_1;
189        applicationInfo.engineVersion = 1;
190        applicationInfo.applicationVersion = 1;
191
192        Array<const char*, 7> instanceExtensions;
193
194#if SLANG_APPLE_FAMILY
195        instanceExtensions.add(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
196#endif
197        instanceExtensions.add(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
198        instanceExtensions.add(VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME);
199
200        // Software (swiftshader) implementation currently does not support surface extension,
201        // so only use it with a hardware implementation.
202        if (!m_api.m_module->isSoftware())
203        {
204            instanceExtensions.add(VK_KHR_SURFACE_EXTENSION_NAME);
205            // Note: this extension is not yet supported by nvidia drivers, disable for now.
206            // instanceExtensions.add("VK_GOOGLE_surfaceless_query");
207#if SLANG_WINDOWS_FAMILY
208            instanceExtensions.add(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
209#elif SLANG_APPLE_FAMILY
210            instanceExtensions.add(VK_EXT_METAL_SURFACE_EXTENSION_NAME);
211#elif defined(SLANG_ENABLE_XLIB)
212
213            instanceExtensions.add(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
214#endif
215        }
216
217        gfxEnableDebugLayer(useValidationLayer);
218        if (isGfxDebugLayerEnabled())
219            instanceExtensions.add(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
220
221        VkInstanceCreateInfo instanceCreateInfo = {VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO};
222#if SLANG_APPLE_FAMILY
223        instanceCreateInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
224#endif
225        instanceCreateInfo.pApplicationInfo = &applicationInfo;
226        instanceCreateInfo.enabledExtensionCount = (uint32_t)instanceExtensions.getCount();
227        instanceCreateInfo.ppEnabledExtensionNames = &instanceExtensions[0];
228
229        const char* layerNames[] = {nullptr};
230
231        VkValidationFeaturesEXT validationFeatures = {};
232        VkValidationFeatureEnableEXT enabledValidationFeatures[1] = {
233            VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT};
234        if (useValidationLayer)
235        {
236            // Depending on driver version, validation layer may or may not exist.
237            // Newer drivers comes with "VK_LAYER_KHRONOS_validation", while older
238            // drivers provide only the deprecated
239            // "VK_LAYER_LUNARG_standard_validation" layer.
240            // We will check what layers are available, and use the newer
241            // "VK_LAYER_KHRONOS_validation" layer when possible.
242            uint32_t layerCount;
243            m_api.vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
244
245            List<VkLayerProperties> availableLayers;
246            availableLayers.setCount(layerCount);
247            m_api.vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.getBuffer());
248
249            for (auto& layer : availableLayers)
250            {
251                if (strncmp(
252                        layer.layerName,
253                        "VK_LAYER_KHRONOS_validation",
254                        sizeof("VK_LAYER_KHRONOS_validation")) == 0)
255                {
256                    layerNames[0] = "VK_LAYER_KHRONOS_validation";
257                    break;
258                }
259            }
260            // On older drivers, only "VK_LAYER_LUNARG_standard_validation" exists,
261            // so we try to use it if we can't find "VK_LAYER_KHRONOS_validation".
262            if (!layerNames[0])
263            {
264                for (auto& layer : availableLayers)
265                {
266                    if (strncmp(
267                            layer.layerName,
268                            "VK_LAYER_LUNARG_standard_validation",
269                            sizeof("VK_LAYER_LUNARG_standard_validation")) == 0)
270                    {
271                        layerNames[0] = "VK_LAYER_LUNARG_standard_validation";
272                        break;
273                    }
274                }
275            }
276            if (layerNames[0])
277            {
278                instanceCreateInfo.enabledLayerCount = SLANG_COUNT_OF(layerNames);
279                instanceCreateInfo.ppEnabledLayerNames = layerNames;
280
281                // Include support for printf
282                validationFeatures.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT;
283                validationFeatures.enabledValidationFeatureCount = 1;
284                validationFeatures.pEnabledValidationFeatures = enabledValidationFeatures;
285                instanceCreateInfo.pNext = &validationFeatures;
286            }
287        }
288        uint32_t apiVersionsToTry[] = {VK_API_VERSION_1_2, VK_API_VERSION_1_1, VK_API_VERSION_1_0};
289        for (auto apiVersion : apiVersionsToTry)
290        {
291            applicationInfo.apiVersion = apiVersion;
292            // If r is VK_ERROR_LAYER_NOT_PRESENT, it's almost certainly
293            // because the layer shared library failed to load (we check that
294            // the layer is known earlier). It might, for example, be absent
295            // from the system library search path, and not referenced with an
296            // absolute path in VkLayer_khronos_validation.json.
297            const auto r = m_api.vkCreateInstance(&instanceCreateInfo, nullptr, &instance);
298            if (r == VK_SUCCESS)
299            {
300                break;
301            }
302        }
303    }
304    else
305    {
306        instance = (VkInstance)handles[0].handleValue;
307    }
308    if (!instance)
309        return SLANG_FAIL;
310    SLANG_RETURN_ON_FAIL(m_api.initInstanceProcs(instance));
311
312    if ((enableRayTracingValidation || useValidationLayer) && m_api.vkCreateDebugReportCallbackEXT)
313    {
314        VkDebugReportFlagsEXT debugFlags =
315            VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
316
317        VkDebugReportCallbackCreateInfoEXT debugCreateInfo = {
318            VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT};
319        debugCreateInfo.pfnCallback = &debugMessageCallback;
320        debugCreateInfo.pUserData = this;
321        debugCreateInfo.flags = debugFlags;
322
323        SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateDebugReportCallbackEXT(
324            instance,
325            &debugCreateInfo,
326            nullptr,
327            &m_debugReportCallback));
328    }
329
330    VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
331    if (handles[1].handleValue == 0)
332    {
333        uint32_t numPhysicalDevices = 0;
334        SLANG_VK_RETURN_ON_FAIL(
335            m_api.vkEnumeratePhysicalDevices(instance, &numPhysicalDevices, nullptr));
336
337        List<VkPhysicalDevice> physicalDevices;
338        physicalDevices.setCount(numPhysicalDevices);
339        SLANG_VK_RETURN_ON_FAIL(m_api.vkEnumeratePhysicalDevices(
340            instance,
341            &numPhysicalDevices,
342            physicalDevices.getBuffer()));
343
344        // Use first physical device by default.
345        Index selectedDeviceIndex = 0;
346
347        // Search for requested adapter.
348        if (m_desc.adapterLUID)
349        {
350            selectedDeviceIndex = -1;
351            for (Index i = 0; i < physicalDevices.getCount(); ++i)
352            {
353                if (vk::getAdapterLUID(m_api, physicalDevices[i]) == *m_desc.adapterLUID)
354                {
355                    selectedDeviceIndex = i;
356                    break;
357                }
358            }
359            if (selectedDeviceIndex < 0)
360                return SLANG_E_NOT_FOUND;
361        }
362
363        if (selectedDeviceIndex >= physicalDevices.getCount())
364            return SLANG_FAIL;
365
366        physicalDevice = physicalDevices[selectedDeviceIndex];
367    }
368    else
369    {
370        physicalDevice = (VkPhysicalDevice)handles[1].handleValue;
371    }
372
373    SLANG_RETURN_ON_FAIL(m_api.initPhysicalDevice(physicalDevice));
374
375    // Obtain the name of the selected adapter.
376    {
377        VkPhysicalDeviceProperties basicProps = {};
378        m_api.vkGetPhysicalDeviceProperties(physicalDevice, &basicProps);
379        m_adapterName = basicProps.deviceName;
380        m_info.adapterName = m_adapterName.begin();
381    }
382
383    // Query the available extensions
384    uint32_t extensionCount = 0;
385    m_api.vkEnumerateDeviceExtensionProperties(m_api.m_physicalDevice, NULL, &extensionCount, NULL);
386    Slang::List<VkExtensionProperties> extensions;
387    extensions.setCount(extensionCount);
388    m_api.vkEnumerateDeviceExtensionProperties(
389        m_api.m_physicalDevice,
390        NULL,
391        &extensionCount,
392        extensions.getBuffer());
393    HashSet<String> extensionNames;
394    for (const auto& e : extensions)
395        extensionNames.add(e.extensionName);
396
397    List<const char*> deviceExtensions;
398    deviceExtensions.add(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
399    deviceExtensions.add(VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME);
400#if SLANG_APPLE_FAMILY
401    deviceExtensions.add("VK_KHR_portability_subset");
402#endif
403
404    VkDeviceCreateInfo deviceCreateInfo = {VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO};
405    deviceCreateInfo.queueCreateInfoCount = 1;
406    deviceCreateInfo.pEnabledFeatures = &m_api.m_deviceFeatures;
407
408    // Get the device features (doesn't use, but useful when debugging)
409    if (m_api.vkGetPhysicalDeviceFeatures2)
410    {
411        VkPhysicalDeviceFeatures2 deviceFeatures2 = {};
412        deviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
413        m_api.vkGetPhysicalDeviceFeatures2(m_api.m_physicalDevice, &deviceFeatures2);
414    }
415
416    VkPhysicalDeviceProperties basicProps = {};
417    m_api.vkGetPhysicalDeviceProperties(m_api.m_physicalDevice, &basicProps);
418
419    // Compute timestamp frequency.
420    m_info.timestampFrequency = uint64_t(1e9 / basicProps.limits.timestampPeriod);
421
422    // Get device limits.
423    {
424        DeviceLimits limits = {};
425        limits.maxTextureDimension1D = basicProps.limits.maxImageDimension1D;
426        limits.maxTextureDimension2D = basicProps.limits.maxImageDimension2D;
427        limits.maxTextureDimension3D = basicProps.limits.maxImageDimension3D;
428        limits.maxTextureDimensionCube = basicProps.limits.maxImageDimensionCube;
429        limits.maxTextureArrayLayers = basicProps.limits.maxImageArrayLayers;
430
431        limits.maxVertexInputElements = basicProps.limits.maxVertexInputAttributes;
432        limits.maxVertexInputElementOffset = basicProps.limits.maxVertexInputAttributeOffset;
433        limits.maxVertexStreams = basicProps.limits.maxVertexInputBindings;
434        limits.maxVertexStreamStride = basicProps.limits.maxVertexInputBindingStride;
435
436        limits.maxComputeThreadsPerGroup = basicProps.limits.maxComputeWorkGroupInvocations;
437        limits.maxComputeThreadGroupSize[0] = basicProps.limits.maxComputeWorkGroupSize[0];
438        limits.maxComputeThreadGroupSize[1] = basicProps.limits.maxComputeWorkGroupSize[1];
439        limits.maxComputeThreadGroupSize[2] = basicProps.limits.maxComputeWorkGroupSize[2];
440        limits.maxComputeDispatchThreadGroups[0] = basicProps.limits.maxComputeWorkGroupCount[0];
441        limits.maxComputeDispatchThreadGroups[1] = basicProps.limits.maxComputeWorkGroupCount[1];
442        limits.maxComputeDispatchThreadGroups[2] = basicProps.limits.maxComputeWorkGroupCount[2];
443
444        limits.maxViewports = basicProps.limits.maxViewports;
445        limits.maxViewportDimensions[0] = basicProps.limits.maxViewportDimensions[0];
446        limits.maxViewportDimensions[1] = basicProps.limits.maxViewportDimensions[1];
447        limits.maxFramebufferDimensions[0] = basicProps.limits.maxFramebufferWidth;
448        limits.maxFramebufferDimensions[1] = basicProps.limits.maxFramebufferHeight;
449        limits.maxFramebufferDimensions[2] = basicProps.limits.maxFramebufferLayers;
450
451        limits.maxShaderVisibleSamplers = basicProps.limits.maxPerStageDescriptorSamplers;
452
453        m_info.limits = limits;
454    }
455
456    // Get the API version
457    const uint32_t majorVersion = VK_VERSION_MAJOR(basicProps.apiVersion);
458    const uint32_t minorVersion = VK_VERSION_MINOR(basicProps.apiVersion);
459
460    auto& extendedFeatures = m_api.m_extendedFeatures;
461
462    // API version check, can't use vkGetPhysicalDeviceProperties2 yet since this device might not
463    // support it
464    if (VK_MAKE_VERSION(majorVersion, minorVersion, 0) >= VK_API_VERSION_1_1 &&
465        m_api.vkGetPhysicalDeviceProperties2 && m_api.vkGetPhysicalDeviceFeatures2)
466    {
467        // Get device features
468        VkPhysicalDeviceFeatures2 deviceFeatures2 = {};
469        deviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
470
471        // Inline uniform block
472        extendedFeatures.inlineUniformBlockFeatures.pNext = deviceFeatures2.pNext;
473        deviceFeatures2.pNext = &extendedFeatures.inlineUniformBlockFeatures;
474
475        // Ray query features
476        extendedFeatures.rayQueryFeatures.pNext = deviceFeatures2.pNext;
477        deviceFeatures2.pNext = &extendedFeatures.rayQueryFeatures;
478
479        // Ray tracing pipeline features
480        extendedFeatures.rayTracingPipelineFeatures.pNext = deviceFeatures2.pNext;
481        deviceFeatures2.pNext = &extendedFeatures.rayTracingPipelineFeatures;
482
483        // SER features.
484        extendedFeatures.rayTracingInvocationReorderFeatures.pNext = deviceFeatures2.pNext;
485        deviceFeatures2.pNext = &extendedFeatures.rayTracingInvocationReorderFeatures;
486
487        // Acceleration structure features
488        extendedFeatures.accelerationStructureFeatures.pNext = deviceFeatures2.pNext;
489        deviceFeatures2.pNext = &extendedFeatures.accelerationStructureFeatures;
490
491        // Variable pointer features.
492        extendedFeatures.variablePointersFeatures.pNext = deviceFeatures2.pNext;
493        deviceFeatures2.pNext = &extendedFeatures.variablePointersFeatures;
494
495        // Compute shader derivative features.
496        extendedFeatures.computeShaderDerivativeFeatures.pNext = deviceFeatures2.pNext;
497        deviceFeatures2.pNext = &extendedFeatures.computeShaderDerivativeFeatures;
498
499        // Extended dynamic states
500        extendedFeatures.extendedDynamicStateFeatures.pNext = deviceFeatures2.pNext;
501        deviceFeatures2.pNext = &extendedFeatures.extendedDynamicStateFeatures;
502
503        // 16-bit storage
504        extendedFeatures.storage16BitFeatures.pNext = deviceFeatures2.pNext;
505        deviceFeatures2.pNext = &extendedFeatures.storage16BitFeatures;
506
507        // robustness2 features
508        extendedFeatures.robustness2Features.pNext = deviceFeatures2.pNext;
509        deviceFeatures2.pNext = &extendedFeatures.robustness2Features;
510
511        // clock features
512        extendedFeatures.clockFeatures.pNext = deviceFeatures2.pNext;
513        deviceFeatures2.pNext = &extendedFeatures.clockFeatures;
514
515        // cooperative vector features
516        extendedFeatures.cooperativeVectorFeatures.pNext = deviceFeatures2.pNext;
517        deviceFeatures2.pNext = &extendedFeatures.cooperativeVectorFeatures;
518
519        // Atomic Float
520        // To detect atomic float we need
521        // https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderAtomicFloatFeaturesEXT.html
522
523        extendedFeatures.atomicFloatFeatures.pNext = deviceFeatures2.pNext;
524        deviceFeatures2.pNext = &extendedFeatures.atomicFloatFeatures;
525
526        // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT.html
527        extendedFeatures.atomicFloat2Features.pNext = deviceFeatures2.pNext;
528        deviceFeatures2.pNext = &extendedFeatures.atomicFloat2Features;
529
530        // Image Int64 Atomic
531        // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT.html
532        extendedFeatures.imageInt64AtomicFeatures.pNext = deviceFeatures2.pNext;
533        deviceFeatures2.pNext = &extendedFeatures.imageInt64AtomicFeatures;
534
535        // mesh shader features
536        extendedFeatures.meshShaderFeatures.pNext = deviceFeatures2.pNext;
537        deviceFeatures2.pNext = &extendedFeatures.meshShaderFeatures;
538
539        // multiview features
540        extendedFeatures.multiviewFeatures.pNext = deviceFeatures2.pNext;
541        deviceFeatures2.pNext = &extendedFeatures.multiviewFeatures;
542
543        // fragment shading rate features
544        extendedFeatures.fragmentShadingRateFeatures.pNext = deviceFeatures2.pNext;
545        deviceFeatures2.pNext = &extendedFeatures.fragmentShadingRateFeatures;
546
547        // raytracing validation features
548        extendedFeatures.rayTracingValidationFeatures.pNext = deviceFeatures2.pNext;
549        deviceFeatures2.pNext = &extendedFeatures.rayTracingValidationFeatures;
550
551        if (VK_MAKE_VERSION(majorVersion, minorVersion, 0) >= VK_API_VERSION_1_2)
552        {
553            extendedFeatures.vulkan12Features.pNext = deviceFeatures2.pNext;
554            deviceFeatures2.pNext = &extendedFeatures.vulkan12Features;
555        }
556
557        m_api.vkGetPhysicalDeviceFeatures2(m_api.m_physicalDevice, &deviceFeatures2);
558
559        if (deviceFeatures2.features.shaderResourceMinLod)
560        {
561            m_features.add("shader-resource-min-lod");
562        }
563        if (deviceFeatures2.features.shaderFloat64)
564        {
565            m_features.add("double");
566        }
567        if (deviceFeatures2.features.shaderInt64)
568        {
569            m_features.add("int64");
570        }
571        if (deviceFeatures2.features.shaderInt16)
572        {
573            m_features.add("int16");
574        }
575        // If we have float16 features then enable
576        if (extendedFeatures.vulkan12Features.shaderFloat16)
577        {
578            // We have half support
579            m_features.add("half");
580        }
581
582        const auto addFeatureExtension =
583            [&](const bool feature, auto& featureStruct, const char* extension = nullptr)
584        {
585            if (!feature)
586                return false;
587            if (extension)
588            {
589                if (!extensionNames.contains(extension))
590                    return false;
591                deviceExtensions.add(extension);
592            }
593            featureStruct.pNext = (void*)deviceCreateInfo.pNext;
594            deviceCreateInfo.pNext = &featureStruct;
595            return true;
596        };
597
598        // SIMPLE_EXTENSION_FEATURE(struct, feature member name, extension
599        // name, features...) will check for the presence of the boolean
600        // feature member in struct and the availability of the extensions. If
601        // they are both present then the extensions are added, the struct
602        // linked into the deviceCreateInfo chain and the features added to the
603        // supported features list.
604#define SIMPLE_EXTENSION_FEATURE(s, m, e, ...) \
605    do                                         \
606    {                                          \
607        const static auto fs = {__VA_ARGS__};  \
608        if (addFeatureExtension(s.m, s, e))    \
609            for (const auto& p : fs)           \
610                m_features.add(p);             \
611    } while (0)
612
613        SIMPLE_EXTENSION_FEATURE(
614            extendedFeatures.storage16BitFeatures,
615            storageBuffer16BitAccess,
616            VK_KHR_16BIT_STORAGE_EXTENSION_NAME,
617            "16-bit-storage");
618
619        SIMPLE_EXTENSION_FEATURE(
620            extendedFeatures.atomicFloatFeatures,
621            shaderBufferFloat32Atomics,
622            VK_EXT_SHADER_ATOMIC_FLOAT_EXTENSION_NAME,
623            "atomic-float");
624
625        SIMPLE_EXTENSION_FEATURE(
626            extendedFeatures.atomicFloat2Features,
627            shaderBufferFloat16Atomics,
628            VK_EXT_SHADER_ATOMIC_FLOAT_2_EXTENSION_NAME,
629            "atomic-float-2");
630
631        SIMPLE_EXTENSION_FEATURE(
632            extendedFeatures.imageInt64AtomicFeatures,
633            shaderImageInt64Atomics,
634            VK_EXT_SHADER_IMAGE_ATOMIC_INT64_EXTENSION_NAME,
635            "image-atomic-int64");
636
637        SIMPLE_EXTENSION_FEATURE(
638            extendedFeatures.extendedDynamicStateFeatures,
639            extendedDynamicState,
640            VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME,
641            "extended-dynamic-states");
642
643        if (extendedFeatures.accelerationStructureFeatures.accelerationStructure &&
644            extensionNames.contains(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME) &&
645            extensionNames.contains(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME))
646        {
647            extendedFeatures.accelerationStructureFeatures.pNext = (void*)deviceCreateInfo.pNext;
648            deviceCreateInfo.pNext = &extendedFeatures.accelerationStructureFeatures;
649            deviceExtensions.add(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
650            deviceExtensions.add(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
651            m_features.add("acceleration-structure");
652
653            // These both depend on VK_KHR_acceleration_structure
654
655            SIMPLE_EXTENSION_FEATURE(
656                extendedFeatures.rayQueryFeatures,
657                rayQuery,
658                VK_KHR_RAY_QUERY_EXTENSION_NAME,
659                "ray-query",
660                "ray-tracing");
661
662            SIMPLE_EXTENSION_FEATURE(
663                extendedFeatures.rayTracingPipelineFeatures,
664                rayTracingPipeline,
665                VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME,
666                "ray-tracing-pipeline");
667        }
668
669        SIMPLE_EXTENSION_FEATURE(
670            extendedFeatures.inlineUniformBlockFeatures,
671            inlineUniformBlock,
672            VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME,
673            "inline-uniform-block", );
674
675        SIMPLE_EXTENSION_FEATURE(
676            extendedFeatures.robustness2Features,
677            nullDescriptor,
678            VK_EXT_ROBUSTNESS_2_EXTENSION_NAME,
679            "robustness2", );
680
681        SIMPLE_EXTENSION_FEATURE(
682            extendedFeatures.clockFeatures,
683            shaderDeviceClock,
684            VK_KHR_SHADER_CLOCK_EXTENSION_NAME,
685            "realtime-clock");
686
687        SIMPLE_EXTENSION_FEATURE(
688            extendedFeatures.meshShaderFeatures,
689            meshShader,
690            VK_EXT_MESH_SHADER_EXTENSION_NAME,
691            "mesh-shader");
692
693        SIMPLE_EXTENSION_FEATURE(
694            extendedFeatures.multiviewFeatures,
695            multiview,
696            VK_KHR_MULTIVIEW_EXTENSION_NAME,
697            "multiview");
698
699        SIMPLE_EXTENSION_FEATURE(
700            extendedFeatures.fragmentShadingRateFeatures,
701            primitiveFragmentShadingRate,
702            VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME,
703            "fragment-shading-rate");
704
705        SIMPLE_EXTENSION_FEATURE(
706            extendedFeatures.rayTracingInvocationReorderFeatures,
707            rayTracingInvocationReorder,
708            VK_NV_RAY_TRACING_INVOCATION_REORDER_EXTENSION_NAME,
709            "shader-execution-reorder");
710
711        SIMPLE_EXTENSION_FEATURE(
712            extendedFeatures.variablePointersFeatures,
713            variablePointers,
714            VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME,
715            "variable-pointer");
716
717        SIMPLE_EXTENSION_FEATURE(
718            extendedFeatures.computeShaderDerivativeFeatures,
719            computeDerivativeGroupLinear,
720            VK_KHR_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME,
721            "computeDerivativeGroupLinear");
722
723        // Only enable raytracing validation if both requested and supported
724        if (enableRayTracingValidation &&
725            extendedFeatures.rayTracingValidationFeatures.rayTracingValidation)
726        {
727            SIMPLE_EXTENSION_FEATURE(
728                extendedFeatures.rayTracingValidationFeatures,
729                rayTracingValidation,
730                VK_NV_RAY_TRACING_VALIDATION_EXTENSION_NAME,
731                "ray-tracing-validation");
732        }
733
734        SIMPLE_EXTENSION_FEATURE(
735            extendedFeatures.cooperativeVectorFeatures,
736            cooperativeVector,
737            VK_NV_COOPERATIVE_VECTOR_EXTENSION_NAME,
738            "cooperative-vector");
739
740#undef SIMPLE_EXTENSION_FEATURE
741
742        if (extendedFeatures.vulkan12Features.shaderBufferInt64Atomics)
743            m_features.add("atomic-int64");
744
745        if (extendedFeatures.vulkan12Features.timelineSemaphore)
746            m_features.add("timeline-semaphore");
747
748        if (extendedFeatures.vulkan12Features.shaderSubgroupExtendedTypes)
749            m_features.add("shader-subgroup-extended-types");
750
751        if (extendedFeatures.vulkan12Features.bufferDeviceAddress)
752            m_features.add("buffer-device-address");
753
754        if (_hasAnySetBits(
755                extendedFeatures.vulkan12Features,
756                offsetof(VkPhysicalDeviceVulkan12Features, pNext) + sizeof(void*)))
757        {
758            extendedFeatures.vulkan12Features.pNext = (void*)deviceCreateInfo.pNext;
759            deviceCreateInfo.pNext = &extendedFeatures.vulkan12Features;
760        }
761
762        VkPhysicalDeviceProperties2 extendedProps = {
763            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
764        VkPhysicalDeviceRayTracingPipelinePropertiesKHR rtProps = {
765            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR};
766        VkPhysicalDeviceSubgroupProperties subgroupProps = {
767            VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES};
768
769        rtProps.pNext = extendedProps.pNext;
770        extendedProps.pNext = &rtProps;
771        subgroupProps.pNext = extendedProps.pNext;
772        extendedProps.pNext = &subgroupProps;
773
774        m_api.vkGetPhysicalDeviceProperties2(m_api.m_physicalDevice, &extendedProps);
775        m_api.m_rtProperties = rtProps;
776
777        // Approximate DX12's WaveOps boolean
778        if (subgroupProps.supportedOperations &
779            (VK_SUBGROUP_FEATURE_BASIC_BIT | VK_SUBGROUP_FEATURE_VOTE_BIT |
780             VK_SUBGROUP_FEATURE_ARITHMETIC_BIT | VK_SUBGROUP_FEATURE_BALLOT_BIT |
781             VK_SUBGROUP_FEATURE_SHUFFLE_BIT | VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT |
782             VK_SUBGROUP_FEATURE_CLUSTERED_BIT | VK_SUBGROUP_FEATURE_QUAD_BIT |
783             VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV))
784        {
785            m_features.add("wave-ops");
786        }
787
788        if (extensionNames.contains("VK_KHR_external_memory"))
789        {
790            deviceExtensions.add(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME);
791#if SLANG_WINDOWS_FAMILY
792            if (extensionNames.contains("VK_KHR_external_memory_win32"))
793            {
794                deviceExtensions.add(VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME);
795            }
796#else
797            if (extensionNames.contains("VK_KHR_external_memory_fd"))
798            {
799                deviceExtensions.add(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME);
800            }
801#endif
802            m_features.add("external-memory");
803        }
804        if (extensionNames.contains(VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME))
805        {
806            deviceExtensions.add(VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME);
807#if SLANG_WINDOWS_FAMILY
808            if (extensionNames.contains(VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME))
809            {
810                deviceExtensions.add(VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME);
811            }
812#else
813            if (extensionNames.contains(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME))
814            {
815                deviceExtensions.add(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME);
816            }
817#endif
818            m_features.add("external-semaphore");
819        }
820        if (extensionNames.contains(VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME))
821        {
822            deviceExtensions.add(VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME);
823            m_features.add("conservative-rasterization-3");
824            m_features.add("conservative-rasterization-2");
825            m_features.add("conservative-rasterization-1");
826        }
827        if (extensionNames.contains(VK_EXT_DEBUG_REPORT_EXTENSION_NAME))
828        {
829            deviceExtensions.add(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
830            if (extensionNames.contains(VK_EXT_DEBUG_MARKER_EXTENSION_NAME))
831            {
832                deviceExtensions.add(VK_EXT_DEBUG_MARKER_EXTENSION_NAME);
833            }
834        }
835        if (extensionNames.contains(VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME))
836        {
837            deviceExtensions.add(VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME);
838        }
839        if (extensionNames.contains(VK_NVX_BINARY_IMPORT_EXTENSION_NAME))
840        {
841            deviceExtensions.add(VK_NVX_BINARY_IMPORT_EXTENSION_NAME);
842            m_features.add("nvx-binary-import");
843        }
844        if (extensionNames.contains(VK_NVX_IMAGE_VIEW_HANDLE_EXTENSION_NAME))
845        {
846            deviceExtensions.add(VK_NVX_IMAGE_VIEW_HANDLE_EXTENSION_NAME);
847            m_features.add("nvx-image-view-handle");
848        }
849        if (extensionNames.contains(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME))
850        {
851            deviceExtensions.add(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
852            m_features.add("push-descriptor");
853        }
854        if (extensionNames.contains(VK_NV_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME))
855        {
856            deviceExtensions.add(VK_NV_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME);
857            m_features.add("barycentrics");
858        }
859        if (extensionNames.contains(VK_NV_SHADER_SUBGROUP_PARTITIONED_EXTENSION_NAME))
860        {
861            deviceExtensions.add(VK_NV_SHADER_SUBGROUP_PARTITIONED_EXTENSION_NAME);
862            m_features.add("shader-subgroup-partitioned");
863        }
864
865        // Derive approximate DX12 shader model.
866        const char* featureTable[] = {
867            "sm_6_0",
868            "wave-ops",
869            "atomic-int64",
870            nullptr,
871            "sm_6_1",
872            "barycentrics",
873            "multiview",
874            nullptr,
875            "sm_6_2",
876            "half",
877            nullptr,
878            "sm_6_3",
879            "ray-tracing-pipeline",
880            nullptr,
881            "sm_6_4",
882            "fragment-shading-rate",
883            nullptr,
884            "sm_6_5",
885            "ray-query",
886            "mesh-shader",
887            nullptr,
888            "sm_6_6",
889            "wave-ops",
890            "atomic-float",
891            "atomic-int64",
892            nullptr,
893            nullptr,
894        };
895
896        int i = 0;
897        while (i < SLANG_COUNT_OF(featureTable))
898        {
899            const char* sm = featureTable[i++];
900            if (sm == nullptr)
901            {
902                break;
903            }
904            bool hasAll = true;
905            while (i < SLANG_COUNT_OF(featureTable))
906            {
907                const char* feature = featureTable[i++];
908                if (feature == nullptr)
909                {
910                    break;
911                }
912                hasAll &= m_features.contains(feature);
913            }
914            if (hasAll)
915            {
916                m_features.add(sm);
917            }
918            else
919            {
920                break;
921            }
922        }
923    }
924    if (m_api.m_module->isSoftware())
925    {
926        m_features.add("software-device");
927    }
928    else
929    {
930        m_features.add("hardware-device");
931    }
932
933    m_queueFamilyIndex = m_api.findQueue(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT);
934    assert(m_queueFamilyIndex >= 0);
935
936#if defined(GFX_NV_AFTERMATH)
937    VkDeviceDiagnosticsConfigCreateInfoNV aftermathInfo = {};
938
939    {
940        // Enable NV_device_diagnostic_checkpoints extension to be able to
941        // use Aftermath event markers.
942        deviceExtensions.add(VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_EXTENSION_NAME);
943
944        // Enable NV_device_diagnostics_config extension to configure Aftermath
945        // features.
946        deviceExtensions.add(VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME);
947
948        // Set up device creation info for Aftermath feature flag configuration.
949        VkDeviceDiagnosticsConfigFlagsNV aftermathFlags =
950            VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_AUTOMATIC_CHECKPOINTS_BIT_NV | // Enable automatic
951                                                                               // call stack
952                                                                               // checkpoints.
953            VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_RESOURCE_TRACKING_BIT_NV |     // Enable tracking of
954                                                                               // resources.
955            VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_DEBUG_INFO_BIT_NV;      // Generate debug
956                                                                               // information for
957                                                                               // shaders.
958        // Not available on the version of Vulkan currently building with.
959        // VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_ERROR_REPORTING_BIT_NV;  // Enable additional
960        // runtime shader error reporting.
961
962        aftermathInfo.sType = VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV;
963        aftermathInfo.flags = aftermathFlags;
964
965        aftermathInfo.pNext = deviceCreateInfo.pNext;
966        deviceCreateInfo.pNext = &aftermathInfo;
967    }
968#endif
969
970    if (handles[2].handleValue == 0)
971    {
972        float queuePriority = 0.0f;
973        VkDeviceQueueCreateInfo queueCreateInfo = {VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO};
974        queueCreateInfo.queueFamilyIndex = m_queueFamilyIndex;
975        queueCreateInfo.queueCount = 1;
976        queueCreateInfo.pQueuePriorities = &queuePriority;
977
978        deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo;
979
980        deviceCreateInfo.enabledExtensionCount = uint32_t(deviceExtensions.getCount());
981        deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions.getBuffer();
982
983        if (m_api.vkCreateDevice(m_api.m_physicalDevice, &deviceCreateInfo, nullptr, &m_device) !=
984            VK_SUCCESS)
985            return SLANG_FAIL;
986    }
987    else
988    {
989        m_device = (VkDevice)handles[2].handleValue;
990    }
991
992    SLANG_RETURN_ON_FAIL(m_api.initDeviceProcs(m_device));
993
994    if (shouldDumpPipeline())
995    {
996        installPipelineDumpLayer(m_api);
997    }
998
999    return SLANG_OK;
1000}
1001
1002SlangResult DeviceImpl::initialize(const Desc& desc)
1003{
1004    // Initialize device info.
1005    {
1006        m_info.apiName = "Vulkan";
1007        m_info.bindingStyle = BindingStyle::Vulkan;
1008        m_info.projectionStyle = ProjectionStyle::Vulkan;
1009        m_info.deviceType = DeviceType::Vulkan;
1010        static const float kIdentity[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
1011        ::memcpy(m_info.identityProjectionMatrix, kIdentity, sizeof(kIdentity));
1012    }
1013
1014    m_desc = desc;
1015
1016    SLANG_RETURN_ON_FAIL(RendererBase::initialize(desc));
1017    SlangResult initDeviceResult = SLANG_OK;
1018
1019    m_glslang.init();
1020    for (int forceSoftware = 0; forceSoftware <= 1; forceSoftware++)
1021    {
1022        initDeviceResult = m_module.init(forceSoftware != 0);
1023        if (initDeviceResult != SLANG_OK)
1024            continue;
1025        initDeviceResult = m_api.initGlobalProcs(m_module);
1026        if (initDeviceResult != SLANG_OK)
1027            continue;
1028        descriptorSetAllocator.m_api = &m_api;
1029        initDeviceResult = initVulkanInstanceAndDevice(
1030            desc.existingDeviceHandles.handles,
1031            isGfxDebugLayerEnabled());
1032        if (initDeviceResult == SLANG_OK)
1033            break;
1034    }
1035    SLANG_RETURN_ON_FAIL(initDeviceResult);
1036
1037    {
1038        VkQueue queue;
1039        m_api.vkGetDeviceQueue(m_device, m_queueFamilyIndex, 0, &queue);
1040        SLANG_RETURN_ON_FAIL(m_deviceQueue.init(m_api, queue, m_queueFamilyIndex));
1041    }
1042
1043    SLANG_RETURN_ON_FAIL(slangContext.initialize(
1044        desc.slang,
1045        desc.extendedDescCount,
1046        desc.extendedDescs,
1047        SLANG_SPIRV,
1048        "sm_5_1",
1049        makeArray(slang::PreprocessorMacroDesc{"__VK__", "1"}).getView()));
1050
1051    // Create default sampler.
1052    {
1053        VkSamplerCreateInfo samplerInfo = {VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
1054        samplerInfo.magFilter = VK_FILTER_NEAREST;
1055        samplerInfo.minFilter = VK_FILTER_NEAREST;
1056        samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
1057        samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
1058        samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
1059        samplerInfo.anisotropyEnable = VK_FALSE;
1060        samplerInfo.maxAnisotropy = 1;
1061        samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
1062        samplerInfo.unnormalizedCoordinates = VK_FALSE;
1063        samplerInfo.compareEnable = VK_FALSE;
1064        samplerInfo.compareOp = VK_COMPARE_OP_NEVER;
1065        samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
1066        samplerInfo.minLod = 0.0f;
1067        samplerInfo.maxLod = 0.0f;
1068        SLANG_VK_RETURN_ON_FAIL(
1069            m_api.vkCreateSampler(m_device, &samplerInfo, nullptr, &m_defaultSampler));
1070    }
1071
1072    // Create empty frame buffer.
1073    {
1074        IFramebufferLayout::Desc layoutDesc = {};
1075        layoutDesc.renderTargetCount = 0;
1076        layoutDesc.depthStencil = nullptr;
1077        ComPtr<IFramebufferLayout> layout;
1078        SLANG_RETURN_ON_FAIL(createFramebufferLayout(layoutDesc, layout.writeRef()));
1079        IFramebuffer::Desc desc = {};
1080        desc.layout = layout;
1081        ComPtr<IFramebuffer> framebuffer;
1082        SLANG_RETURN_ON_FAIL(createFramebuffer(desc, framebuffer.writeRef()));
1083        m_emptyFramebuffer = static_cast<FramebufferImpl*>(framebuffer.get());
1084        m_emptyFramebuffer->m_renderer.breakStrongReference();
1085    }
1086
1087    return SLANG_OK;
1088}
1089
1090void DeviceImpl::waitForGpu()
1091{
1092    m_deviceQueue.flushAndWait();
1093}
1094
1095SLANG_NO_THROW const DeviceInfo& SLANG_MCALL DeviceImpl::getDeviceInfo() const
1096{
1097    return m_info;
1098}
1099
1100Result DeviceImpl::createTransientResourceHeap(
1101    const ITransientResourceHeap::Desc& desc,
1102    ITransientResourceHeap** outHeap)
1103{
1104    RefPtr<TransientResourceHeapImpl> result = new TransientResourceHeapImpl();
1105    SLANG_RETURN_ON_FAIL(result->init(desc, this));
1106    returnComPtr(outHeap, result);
1107    return SLANG_OK;
1108}
1109
1110Result DeviceImpl::createCommandQueue(const ICommandQueue::Desc& desc, ICommandQueue** outQueue)
1111{
1112    // Only support one queue for now.
1113    if (m_queueAllocCount != 0)
1114        return SLANG_FAIL;
1115    auto queueFamilyIndex = m_api.findQueue(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT);
1116    VkQueue vkQueue;
1117    m_api.vkGetDeviceQueue(m_api.m_device, queueFamilyIndex, 0, &vkQueue);
1118    RefPtr<CommandQueueImpl> result = new CommandQueueImpl();
1119    result->init(this, vkQueue, queueFamilyIndex);
1120    returnComPtr(outQueue, result);
1121    m_queueAllocCount++;
1122    return SLANG_OK;
1123}
1124
1125Result DeviceImpl::createSwapchain(
1126    const ISwapchain::Desc& desc,
1127    WindowHandle window,
1128    ISwapchain** outSwapchain)
1129{
1130#if !defined(SLANG_ENABLE_XLIB)
1131    if (window.type == WindowHandle::Type::XLibHandle)
1132    {
1133        return SLANG_FAIL;
1134    }
1135#endif
1136
1137    RefPtr<SwapchainImpl> sc = new SwapchainImpl();
1138    SLANG_RETURN_ON_FAIL(sc->init(this, desc, window));
1139    returnComPtr(outSwapchain, sc);
1140    return SLANG_OK;
1141}
1142
1143Result DeviceImpl::createFramebufferLayout(
1144    const IFramebufferLayout::Desc& desc,
1145    IFramebufferLayout** outLayout)
1146{
1147    RefPtr<FramebufferLayoutImpl> layout = new FramebufferLayoutImpl();
1148    SLANG_RETURN_ON_FAIL(layout->init(this, desc));
1149    returnComPtr(outLayout, layout);
1150    return SLANG_OK;
1151}
1152
1153Result DeviceImpl::createRenderPassLayout(
1154    const IRenderPassLayout::Desc& desc,
1155    IRenderPassLayout** outRenderPassLayout)
1156{
1157    RefPtr<RenderPassLayoutImpl> result = new RenderPassLayoutImpl();
1158    SLANG_RETURN_ON_FAIL(result->init(this, desc));
1159    returnComPtr(outRenderPassLayout, result);
1160    return SLANG_OK;
1161}
1162
1163Result DeviceImpl::createFramebuffer(const IFramebuffer::Desc& desc, IFramebuffer** outFramebuffer)
1164{
1165    RefPtr<FramebufferImpl> fb = new FramebufferImpl();
1166    SLANG_RETURN_ON_FAIL(fb->init(this, desc));
1167    returnComPtr(outFramebuffer, fb);
1168    return SLANG_OK;
1169}
1170
1171SlangResult DeviceImpl::readTextureResource(
1172    ITextureResource* texture,
1173    ResourceState state,
1174    ISlangBlob** outBlob,
1175    Size* outRowPitch,
1176    Size* outPixelSize)
1177{
1178    auto textureImpl = static_cast<TextureResourceImpl*>(texture);
1179
1180    List<uint8_t> blobData;
1181
1182    auto desc = textureImpl->getDesc();
1183    auto width = desc->size.width;
1184    auto height = desc->size.height;
1185    FormatInfo sizeInfo;
1186    SLANG_RETURN_ON_FAIL(gfxGetFormatInfo(desc->format, &sizeInfo));
1187    Size pixelSize = sizeInfo.blockSizeInBytes / sizeInfo.pixelsPerBlock;
1188    Size rowPitch = width * pixelSize;
1189
1190    List<TextureResource::Extents> mipSizes;
1191
1192    const int numMipMaps = desc->numMipLevels;
1193    auto arraySize = calcEffectiveArraySize(*desc);
1194
1195    // Calculate how large the buffer has to be
1196    Size bufferSize = 0;
1197    // Calculate how large an array entry is
1198    for (int j = 0; j < numMipMaps; ++j)
1199    {
1200        const TextureResource::Extents mipSize = calcMipSize(desc->size, j);
1201
1202        auto rowSizeInBytes = calcRowSize(desc->format, mipSize.width);
1203        auto numRows = calcNumRows(desc->format, mipSize.height);
1204
1205        mipSizes.add(mipSize);
1206
1207        bufferSize += (rowSizeInBytes * numRows) * mipSize.depth;
1208    }
1209    // Calculate the total size taking into account the array
1210    bufferSize *= arraySize;
1211
1212    blobData.setCount(Count(bufferSize));
1213
1214    VKBufferHandleRAII staging;
1215    SLANG_RETURN_ON_FAIL(staging.init(
1216        m_api,
1217        bufferSize,
1218        VK_BUFFER_USAGE_TRANSFER_DST_BIT,
1219        VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT));
1220
1221    VkCommandBuffer commandBuffer = m_deviceQueue.getCommandBuffer();
1222    VkImage srcImage = textureImpl->m_image;
1223    VkImageLayout srcImageLayout = VulkanUtil::getImageLayoutFromState(state);
1224
1225    Offset dstOffset = 0;
1226    for (int i = 0; i < arraySize; ++i)
1227    {
1228        for (Index j = 0; j < mipSizes.getCount(); ++j)
1229        {
1230            const auto& mipSize = mipSizes[j];
1231
1232            auto rowSizeInBytes = calcRowSize(desc->format, mipSize.width);
1233            auto numRows = calcNumRows(desc->format, mipSize.height);
1234
1235            VkBufferImageCopy region = {};
1236
1237            region.bufferOffset = dstOffset;
1238            region.bufferRowLength = 0;
1239            region.bufferImageHeight = 0;
1240
1241            region.imageSubresource.aspectMask =
1242                getAspectMaskFromFormat(VulkanUtil::getVkFormat(desc->format));
1243            region.imageSubresource.mipLevel = uint32_t(j);
1244            region.imageSubresource.baseArrayLayer = i;
1245            region.imageSubresource.layerCount = 1;
1246            region.imageOffset = {0, 0, 0};
1247            region.imageExtent = {
1248                uint32_t(mipSize.width),
1249                uint32_t(mipSize.height),
1250                uint32_t(mipSize.depth)};
1251
1252            m_api.vkCmdCopyImageToBuffer(
1253                commandBuffer,
1254                srcImage,
1255                srcImageLayout,
1256                staging.m_buffer,
1257                1,
1258                &region);
1259
1260            dstOffset += rowSizeInBytes * numRows * mipSize.depth;
1261        }
1262    }
1263
1264    m_deviceQueue.flushAndWait();
1265
1266    // Write out the data from the buffer
1267    void* mappedData = nullptr;
1268    SLANG_RETURN_ON_FAIL(
1269        m_api.vkMapMemory(m_device, staging.m_memory, 0, bufferSize, 0, &mappedData));
1270
1271    ::memcpy(blobData.getBuffer(), mappedData, bufferSize);
1272    m_api.vkUnmapMemory(m_device, staging.m_memory);
1273
1274    *outPixelSize = pixelSize;
1275    *outRowPitch = rowPitch;
1276
1277    auto blob = ListBlob::moveCreate(blobData);
1278
1279    returnComPtr(outBlob, blob);
1280    return SLANG_OK;
1281}
1282
1283SlangResult DeviceImpl::readBufferResource(
1284    IBufferResource* inBuffer,
1285    Offset offset,
1286    Size size,
1287    ISlangBlob** outBlob)
1288{
1289    BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(inBuffer);
1290
1291    List<uint8_t> blobData;
1292
1293    blobData.setCount(size);
1294
1295    // create staging buffer
1296    VKBufferHandleRAII staging;
1297
1298    SLANG_RETURN_ON_FAIL(staging.init(
1299        m_api,
1300        size,
1301        VK_BUFFER_USAGE_TRANSFER_DST_BIT,
1302        VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT));
1303
1304    // Copy from real buffer to staging buffer
1305    VkCommandBuffer commandBuffer = m_deviceQueue.getCommandBuffer();
1306
1307    VkBufferCopy copyInfo = {};
1308    copyInfo.size = size;
1309    copyInfo.srcOffset = offset;
1310    m_api.vkCmdCopyBuffer(commandBuffer, buffer->m_buffer.m_buffer, staging.m_buffer, 1, &copyInfo);
1311
1312    m_deviceQueue.flushAndWait();
1313
1314    // Write out the data from the buffer
1315    void* mappedData = nullptr;
1316    SLANG_RETURN_ON_FAIL(m_api.vkMapMemory(m_device, staging.m_memory, 0, size, 0, &mappedData));
1317
1318    ::memcpy(blobData.getBuffer(), mappedData, size);
1319    m_api.vkUnmapMemory(m_device, staging.m_memory);
1320
1321    auto blob = ListBlob::moveCreate(blobData);
1322
1323    returnComPtr(outBlob, blob);
1324    return SLANG_OK;
1325}
1326
1327Result DeviceImpl::getAccelerationStructurePrebuildInfo(
1328    const IAccelerationStructure::BuildInputs& buildInputs,
1329    IAccelerationStructure::PrebuildInfo* outPrebuildInfo)
1330{
1331    if (!m_api.vkGetAccelerationStructureBuildSizesKHR)
1332    {
1333        return SLANG_E_NOT_AVAILABLE;
1334    }
1335    VkAccelerationStructureBuildSizesInfoKHR sizeInfo = {
1336        VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR};
1337    AccelerationStructureBuildGeometryInfoBuilder geomInfoBuilder;
1338    SLANG_RETURN_ON_FAIL(geomInfoBuilder.build(buildInputs, getDebugCallback()));
1339    m_api.vkGetAccelerationStructureBuildSizesKHR(
1340        m_api.m_device,
1341        VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR,
1342        &geomInfoBuilder.buildInfo,
1343        geomInfoBuilder.primitiveCounts.getBuffer(),
1344        &sizeInfo);
1345    outPrebuildInfo->resultDataMaxSize = (Size)sizeInfo.accelerationStructureSize;
1346    outPrebuildInfo->scratchDataSize = (Size)sizeInfo.buildScratchSize;
1347    outPrebuildInfo->updateScratchDataSize = (Size)sizeInfo.updateScratchSize;
1348    return SLANG_OK;
1349}
1350
1351Result DeviceImpl::createAccelerationStructure(
1352    const IAccelerationStructure::CreateDesc& desc,
1353    IAccelerationStructure** outAS)
1354{
1355    if (!m_api.vkCreateAccelerationStructureKHR)
1356    {
1357        return SLANG_E_NOT_AVAILABLE;
1358    }
1359    RefPtr<AccelerationStructureImpl> resultAS = new AccelerationStructureImpl();
1360    resultAS->m_offset = desc.offset;
1361    resultAS->m_size = desc.size;
1362    resultAS->m_buffer = static_cast<BufferResourceImpl*>(desc.buffer);
1363    resultAS->m_device = this;
1364    resultAS->m_desc.type = IResourceView::Type::AccelerationStructure;
1365    VkAccelerationStructureCreateInfoKHR createInfo = {
1366        VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR};
1367    createInfo.buffer = resultAS->m_buffer->m_buffer.m_buffer;
1368    createInfo.offset = desc.offset;
1369    createInfo.size = desc.size;
1370    switch (desc.kind)
1371    {
1372    case IAccelerationStructure::Kind::BottomLevel:
1373        createInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
1374        break;
1375    case IAccelerationStructure::Kind::TopLevel:
1376        createInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR;
1377        break;
1378    default:
1379        getDebugCallback()->handleMessage(
1380            DebugMessageType::Error,
1381            DebugMessageSource::Layer,
1382            "invalid value of IAccelerationStructure::Kind encountered in desc.kind");
1383        return SLANG_E_INVALID_ARG;
1384    }
1385
1386    SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateAccelerationStructureKHR(
1387        m_api.m_device,
1388        &createInfo,
1389        nullptr,
1390        &resultAS->m_vkHandle));
1391    returnComPtr(outAS, resultAS);
1392    return SLANG_OK;
1393}
1394
1395void DeviceImpl::_transitionImageLayout(
1396    VkCommandBuffer commandBuffer,
1397    VkImage image,
1398    VkFormat format,
1399    const TextureResource::Desc& desc,
1400    VkImageLayout oldLayout,
1401    VkImageLayout newLayout)
1402{
1403    if (oldLayout == newLayout)
1404        return;
1405
1406    VkImageMemoryBarrier barrier = {};
1407    barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1408    barrier.oldLayout = oldLayout;
1409    barrier.newLayout = newLayout;
1410    barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1411    barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1412    barrier.image = image;
1413
1414    barrier.subresourceRange.aspectMask = getAspectMaskFromFormat(format);
1415
1416    barrier.subresourceRange.baseMipLevel = 0;
1417    barrier.subresourceRange.levelCount = desc.numMipLevels;
1418    barrier.subresourceRange.baseArrayLayer = 0;
1419    barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
1420    barrier.srcAccessMask = calcAccessFlagsFromImageLayout(oldLayout);
1421    barrier.dstAccessMask = calcAccessFlagsFromImageLayout(newLayout);
1422
1423    VkPipelineStageFlags sourceStage = calcPipelineStageFlagsFromImageLayout(oldLayout);
1424    VkPipelineStageFlags destinationStage = calcPipelineStageFlagsFromImageLayout(newLayout);
1425
1426    m_api.vkCmdPipelineBarrier(
1427        commandBuffer,
1428        sourceStage,
1429        destinationStage,
1430        0,
1431        0,
1432        nullptr,
1433        0,
1434        nullptr,
1435        1,
1436        &barrier);
1437}
1438
1439uint32_t DeviceImpl::getQueueFamilyIndex(ICommandQueue::QueueType queueType)
1440{
1441    switch (queueType)
1442    {
1443    case ICommandQueue::QueueType::Graphics:
1444    default:
1445        return m_queueFamilyIndex;
1446    }
1447}
1448
1449void DeviceImpl::_transitionImageLayout(
1450    VkImage image,
1451    VkFormat format,
1452    const TextureResource::Desc& desc,
1453    VkImageLayout oldLayout,
1454    VkImageLayout newLayout)
1455{
1456    VkCommandBuffer commandBuffer = m_deviceQueue.getCommandBuffer();
1457    _transitionImageLayout(commandBuffer, image, format, desc, oldLayout, newLayout);
1458}
1459
1460Result DeviceImpl::getTextureAllocationInfo(
1461    const ITextureResource::Desc& descIn,
1462    Size* outSize,
1463    Size* outAlignment)
1464{
1465    TextureResource::Desc desc = fixupTextureDesc(descIn);
1466
1467    const VkFormat format = VulkanUtil::getVkFormat(desc.format);
1468    if (format == VK_FORMAT_UNDEFINED)
1469    {
1470        assert(!"Unhandled image format");
1471        return SLANG_FAIL;
1472    }
1473    const int arraySize = calcEffectiveArraySize(desc);
1474
1475    VkImageCreateInfo imageInfo = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO};
1476    switch (desc.type)
1477    {
1478    case IResource::Type::Texture1D:
1479        {
1480            imageInfo.imageType = VK_IMAGE_TYPE_1D;
1481            imageInfo.extent = VkExtent3D{uint32_t(descIn.size.width), 1, 1};
1482            break;
1483        }
1484    case IResource::Type::Texture2D:
1485        {
1486            imageInfo.imageType = VK_IMAGE_TYPE_2D;
1487            imageInfo.extent =
1488                VkExtent3D{uint32_t(descIn.size.width), uint32_t(descIn.size.height), 1};
1489            break;
1490        }
1491    case IResource::Type::TextureCube:
1492        {
1493            imageInfo.imageType = VK_IMAGE_TYPE_2D;
1494            imageInfo.extent =
1495                VkExtent3D{uint32_t(descIn.size.width), uint32_t(descIn.size.height), 1};
1496            imageInfo.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
1497            break;
1498        }
1499    case IResource::Type::Texture3D:
1500        {
1501            // Can't have an array and 3d texture
1502            assert(desc.arraySize <= 1);
1503
1504            imageInfo.imageType = VK_IMAGE_TYPE_3D;
1505            imageInfo.extent = VkExtent3D{
1506                uint32_t(descIn.size.width),
1507                uint32_t(descIn.size.height),
1508                uint32_t(descIn.size.depth)};
1509            break;
1510        }
1511    default:
1512        {
1513            assert(!"Unhandled type");
1514            return SLANG_FAIL;
1515        }
1516    }
1517
1518    imageInfo.mipLevels = desc.numMipLevels;
1519    imageInfo.arrayLayers = arraySize;
1520
1521    imageInfo.format = format;
1522
1523    imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
1524    imageInfo.usage = _calcImageUsageFlags(desc.allowedStates, desc.memoryType, nullptr);
1525    imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1526
1527    imageInfo.samples = (VkSampleCountFlagBits)desc.sampleDesc.numSamples;
1528
1529    VkImage image;
1530    SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateImage(m_device, &imageInfo, nullptr, &image));
1531
1532    VkMemoryRequirements memRequirements;
1533    m_api.vkGetImageMemoryRequirements(m_device, image, &memRequirements);
1534
1535    *outSize = (Size)memRequirements.size;
1536    *outAlignment = (Size)memRequirements.alignment;
1537
1538    m_api.vkDestroyImage(m_device, image, nullptr);
1539    return SLANG_OK;
1540}
1541
1542Result DeviceImpl::getTextureRowAlignment(Size* outAlignment)
1543{
1544    *outAlignment = 1;
1545    return SLANG_OK;
1546}
1547
1548Result DeviceImpl::getCooperativeVectorProperties(
1549    CooperativeVectorProperties* properties,
1550    uint32_t* propertyCount)
1551{
1552    if (!m_api.m_extendedFeatures.cooperativeVectorFeatures.cooperativeVector ||
1553        !m_api.vkGetPhysicalDeviceCooperativeVectorPropertiesNV)
1554        return SLANG_E_NOT_AVAILABLE;
1555
1556    if (m_cooperativeVectorProperties.empty())
1557    {
1558        uint32_t vkPropertyCount = 0;
1559        m_api.vkGetPhysicalDeviceCooperativeVectorPropertiesNV(
1560            m_api.m_physicalDevice,
1561            &vkPropertyCount,
1562            nullptr);
1563        std::vector<VkCooperativeVectorPropertiesNV> vkProperties(vkPropertyCount);
1564        SLANG_VK_RETURN_ON_FAIL(m_api.vkGetPhysicalDeviceCooperativeVectorPropertiesNV(
1565            m_api.m_physicalDevice,
1566            &vkPropertyCount,
1567            vkProperties.data()));
1568        for (const auto& vkProps : vkProperties)
1569        {
1570            CooperativeVectorProperties props;
1571            props.inputType =
1572                VulkanUtil::translateCooperativeVectorComponentType(vkProps.inputType);
1573            props.inputInterpretation =
1574                VulkanUtil::translateCooperativeVectorComponentType(vkProps.inputInterpretation);
1575            props.matrixInterpretation =
1576                VulkanUtil::translateCooperativeVectorComponentType(vkProps.matrixInterpretation);
1577            props.biasInterpretation =
1578                VulkanUtil::translateCooperativeVectorComponentType(vkProps.biasInterpretation);
1579            props.resultType =
1580                VulkanUtil::translateCooperativeVectorComponentType(vkProps.resultType);
1581            props.transpose = vkProps.transpose;
1582            m_cooperativeVectorProperties.push_back(props);
1583        }
1584    }
1585
1586    return RendererBase::getCooperativeVectorProperties(properties, propertyCount);
1587}
1588
1589Result DeviceImpl::createTextureResource(
1590    const ITextureResource::Desc& descIn,
1591    const ITextureResource::SubresourceData* initData,
1592    ITextureResource** outResource)
1593{
1594    TextureResource::Desc desc = fixupTextureDesc(descIn);
1595
1596    const VkFormat format = VulkanUtil::getVkFormat(desc.format);
1597    if (format == VK_FORMAT_UNDEFINED)
1598    {
1599        assert(!"Unhandled image format");
1600        return SLANG_FAIL;
1601    }
1602
1603    const int arraySize = calcEffectiveArraySize(desc);
1604
1605    RefPtr<TextureResourceImpl> texture(new TextureResourceImpl(desc, this));
1606    texture->m_vkformat = format;
1607    // Create the image
1608
1609    VkImageCreateInfo imageInfo = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO};
1610    switch (desc.type)
1611    {
1612    case IResource::Type::Texture1D:
1613        {
1614            imageInfo.imageType = VK_IMAGE_TYPE_1D;
1615            imageInfo.extent = VkExtent3D{uint32_t(descIn.size.width), 1, 1};
1616            break;
1617        }
1618    case IResource::Type::Texture2D:
1619        {
1620            imageInfo.imageType = VK_IMAGE_TYPE_2D;
1621            imageInfo.extent =
1622                VkExtent3D{uint32_t(descIn.size.width), uint32_t(descIn.size.height), 1};
1623            break;
1624        }
1625    case IResource::Type::TextureCube:
1626        {
1627            imageInfo.imageType = VK_IMAGE_TYPE_2D;
1628            imageInfo.extent =
1629                VkExtent3D{uint32_t(descIn.size.width), uint32_t(descIn.size.height), 1};
1630            imageInfo.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
1631            break;
1632        }
1633    case IResource::Type::Texture3D:
1634        {
1635            // Can't have an array and 3d texture
1636            assert(desc.arraySize <= 1);
1637
1638            imageInfo.imageType = VK_IMAGE_TYPE_3D;
1639            imageInfo.extent = VkExtent3D{
1640                uint32_t(descIn.size.width),
1641                uint32_t(descIn.size.height),
1642                uint32_t(descIn.size.depth)};
1643            break;
1644        }
1645    default:
1646        {
1647            assert(!"Unhandled type");
1648            return SLANG_FAIL;
1649        }
1650    }
1651
1652    imageInfo.mipLevels = desc.numMipLevels;
1653    imageInfo.arrayLayers = arraySize;
1654
1655    imageInfo.format = format;
1656
1657    imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
1658    imageInfo.usage = _calcImageUsageFlags(desc.allowedStates, desc.memoryType, initData);
1659    imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1660
1661    imageInfo.samples = (VkSampleCountFlagBits)desc.sampleDesc.numSamples;
1662
1663    VkExternalMemoryImageCreateInfo externalMemoryImageCreateInfo = {
1664        VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO};
1665    VkExternalMemoryHandleTypeFlags extMemoryHandleType =
1666#if SLANG_WINDOWS_FAMILY
1667        VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
1668#else
1669        VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
1670#endif
1671    if (descIn.isShared)
1672    {
1673        externalMemoryImageCreateInfo.pNext = nullptr;
1674        externalMemoryImageCreateInfo.handleTypes = extMemoryHandleType;
1675        imageInfo.pNext = &externalMemoryImageCreateInfo;
1676    }
1677    SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateImage(m_device, &imageInfo, nullptr, &texture->m_image));
1678
1679    VkMemoryRequirements memRequirements;
1680    m_api.vkGetImageMemoryRequirements(m_device, texture->m_image, &memRequirements);
1681
1682    // Allocate the memory
1683    VkMemoryPropertyFlags reqMemoryProperties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
1684    int memoryTypeIndex =
1685        m_api.findMemoryTypeIndex(memRequirements.memoryTypeBits, reqMemoryProperties);
1686    assert(memoryTypeIndex >= 0);
1687
1688    VkMemoryPropertyFlags actualMemoryProperites =
1689        m_api.m_deviceMemoryProperties.memoryTypes[memoryTypeIndex].propertyFlags;
1690    VkMemoryAllocateInfo allocInfo = {VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO};
1691    allocInfo.allocationSize = memRequirements.size;
1692    allocInfo.memoryTypeIndex = memoryTypeIndex;
1693#if SLANG_WINDOWS_FAMILY
1694    VkExportMemoryWin32HandleInfoKHR exportMemoryWin32HandleInfo = {
1695        VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR};
1696#endif
1697    VkExportMemoryAllocateInfoKHR exportMemoryAllocateInfo = {
1698        VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR};
1699    if (descIn.isShared)
1700    {
1701#if SLANG_WINDOWS_FAMILY
1702        exportMemoryWin32HandleInfo.pNext = nullptr;
1703        exportMemoryWin32HandleInfo.pAttributes = nullptr;
1704        exportMemoryWin32HandleInfo.dwAccess =
1705            DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE;
1706        exportMemoryWin32HandleInfo.name = NULL;
1707
1708        exportMemoryAllocateInfo.pNext =
1709            extMemoryHandleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR
1710                ? &exportMemoryWin32HandleInfo
1711                : nullptr;
1712#endif
1713        exportMemoryAllocateInfo.handleTypes = extMemoryHandleType;
1714        allocInfo.pNext = &exportMemoryAllocateInfo;
1715    }
1716    SLANG_VK_RETURN_ON_FAIL(
1717        m_api.vkAllocateMemory(m_device, &allocInfo, nullptr, &texture->m_imageMemory));
1718
1719    // Bind the memory to the image
1720    m_api.vkBindImageMemory(m_device, texture->m_image, texture->m_imageMemory, 0);
1721
1722    VKBufferHandleRAII uploadBuffer;
1723    if (initData)
1724    {
1725        List<TextureResource::Extents> mipSizes;
1726
1727        VkCommandBuffer commandBuffer = m_deviceQueue.getCommandBuffer();
1728
1729        const int numMipMaps = desc.numMipLevels;
1730
1731        // Calculate how large the buffer has to be
1732        Size bufferSize = 0;
1733        // Calculate how large an array entry is
1734        for (int j = 0; j < numMipMaps; ++j)
1735        {
1736            const TextureResource::Extents mipSize = calcMipSize(desc.size, j);
1737
1738            auto rowSizeInBytes = calcRowSize(desc.format, mipSize.width);
1739            auto numRows = calcNumRows(desc.format, mipSize.height);
1740
1741            mipSizes.add(mipSize);
1742
1743            bufferSize += (rowSizeInBytes * numRows) * mipSize.depth;
1744        }
1745
1746        // Calculate the total size taking into account the array
1747        bufferSize *= arraySize;
1748
1749        SLANG_RETURN_ON_FAIL(uploadBuffer.init(
1750            m_api,
1751            bufferSize,
1752            VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
1753            VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT));
1754
1755        assert(mipSizes.getCount() == numMipMaps);
1756
1757        // Copy into upload buffer
1758        {
1759            int subResourceCounter = 0;
1760
1761            uint8_t* dstData;
1762            m_api.vkMapMemory(m_device, uploadBuffer.m_memory, 0, bufferSize, 0, (void**)&dstData);
1763            uint8_t* dstDataStart;
1764            dstDataStart = dstData;
1765
1766            Offset dstSubresourceOffset = 0;
1767            for (int i = 0; i < arraySize; ++i)
1768            {
1769                for (Index j = 0; j < mipSizes.getCount(); ++j)
1770                {
1771                    const auto& mipSize = mipSizes[j];
1772
1773                    int subResourceIndex = subResourceCounter++;
1774                    auto initSubresource = initData[subResourceIndex];
1775
1776                    const ptrdiff_t srcRowStride = (ptrdiff_t)initSubresource.strideY;
1777                    const ptrdiff_t srcLayerStride = (ptrdiff_t)initSubresource.strideZ;
1778
1779                    auto dstRowSizeInBytes = calcRowSize(desc.format, mipSize.width);
1780                    auto numRows = calcNumRows(desc.format, mipSize.height);
1781                    auto dstLayerSizeInBytes = dstRowSizeInBytes * numRows;
1782
1783                    const uint8_t* srcLayer = (const uint8_t*)initSubresource.data;
1784                    uint8_t* dstLayer = dstData + dstSubresourceOffset;
1785
1786                    for (int k = 0; k < mipSize.depth; k++)
1787                    {
1788                        const uint8_t* srcRow = srcLayer;
1789                        uint8_t* dstRow = dstLayer;
1790
1791                        for (GfxCount l = 0; l < numRows; l++)
1792                        {
1793                            ::memcpy(dstRow, srcRow, dstRowSizeInBytes);
1794
1795                            dstRow += dstRowSizeInBytes;
1796                            srcRow += srcRowStride;
1797                        }
1798
1799                        dstLayer += dstLayerSizeInBytes;
1800                        srcLayer += srcLayerStride;
1801                    }
1802
1803                    dstSubresourceOffset += dstLayerSizeInBytes * mipSize.depth;
1804                }
1805            }
1806
1807            m_api.vkUnmapMemory(m_device, uploadBuffer.m_memory);
1808        }
1809
1810        _transitionImageLayout(
1811            texture->m_image,
1812            format,
1813            *texture->getDesc(),
1814            VK_IMAGE_LAYOUT_UNDEFINED,
1815            VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
1816
1817        if (desc.sampleDesc.numSamples != 1)
1818        {
1819            // Handle senario where texture is sampled. We cannot use
1820            // a simple buffer copy for sampled textures. ClearColorImage
1821            // is not data accurate but it is fine for testing & works.
1822            FormatInfo formatInfo;
1823            gfxGetFormatInfo(desc.format, &formatInfo);
1824            uint32_t data = 0;
1825            VkClearColorValue clearColor;
1826            switch (formatInfo.channelType)
1827            {
1828            case SLANG_SCALAR_TYPE_INT32:
1829                for (int i = 0; i < 4; i++)
1830                    clearColor.int32[i] =
1831                        *reinterpret_cast<int32_t*>(const_cast<void*>(initData->data));
1832                break;
1833            case SLANG_SCALAR_TYPE_UINT32:
1834                for (int i = 0; i < 4; i++)
1835                    clearColor.uint32[i] =
1836                        *reinterpret_cast<uint32_t*>(const_cast<void*>(initData->data));
1837                break;
1838            case SLANG_SCALAR_TYPE_INT64:
1839                {
1840                    for (int i = 0; i < 4; i++)
1841                        clearColor.int32[i] =
1842                            int32_t(*reinterpret_cast<int64_t*>(const_cast<void*>(initData->data)));
1843                    break;
1844                }
1845            case SLANG_SCALAR_TYPE_UINT64:
1846                {
1847                    for (int i = 0; i < 4; i++)
1848                        clearColor.uint32[i] = uint32_t(
1849                            *reinterpret_cast<uint64_t*>(const_cast<void*>(initData->data)));
1850                    break;
1851                }
1852            case SLANG_SCALAR_TYPE_FLOAT16:
1853                {
1854                    for (int i = 0; i < 4; i++)
1855                        clearColor.float32[i] = HalfToFloat(
1856                            *reinterpret_cast<uint16_t*>(const_cast<void*>(initData->data)));
1857                    break;
1858                }
1859            case SLANG_SCALAR_TYPE_FLOAT32:
1860                {
1861                    for (int i = 0; i < 4; i++)
1862                        clearColor.float32[i] =
1863                            (*reinterpret_cast<float*>(const_cast<void*>(initData->data)));
1864                    break;
1865                }
1866            case SLANG_SCALAR_TYPE_FLOAT64:
1867                {
1868                    for (int i = 0; i < 4; i++)
1869                        clearColor.float32[i] =
1870                            float(*reinterpret_cast<double*>(const_cast<void*>(initData->data)));
1871                    break;
1872                }
1873            case SLANG_SCALAR_TYPE_INT8:
1874                {
1875                    for (int i = 0; i < 4; i++)
1876                        clearColor.int32[i] =
1877                            int32_t(*reinterpret_cast<int8_t*>(const_cast<void*>(initData->data)));
1878                    break;
1879                }
1880            case SLANG_SCALAR_TYPE_UINT8:
1881                {
1882                    for (int i = 0; i < 4; i++)
1883                        clearColor.uint32[i] = uint32_t(
1884                            *reinterpret_cast<uint8_t*>(const_cast<void*>(initData->data)));
1885                    break;
1886                }
1887            case SLANG_SCALAR_TYPE_INT16:
1888                {
1889                    for (int i = 0; i < 4; i++)
1890                        clearColor.int32[i] =
1891                            int32_t(*reinterpret_cast<int16_t*>(const_cast<void*>(initData->data)));
1892                    break;
1893                }
1894            case SLANG_SCALAR_TYPE_UINT16:
1895                {
1896                    for (int i = 0; i < 4; i++)
1897                        clearColor.uint32[i] = uint32_t(
1898                            *reinterpret_cast<uint16_t*>(const_cast<void*>(initData->data)));
1899                    break;
1900                }
1901            };
1902
1903            VkImageSubresourceRange range{};
1904            range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1905            range.baseMipLevel = 0;
1906            range.levelCount = VK_REMAINING_MIP_LEVELS;
1907            range.baseArrayLayer = 0;
1908            range.layerCount = VK_REMAINING_ARRAY_LAYERS;
1909
1910            m_api.vkCmdClearColorImage(
1911                commandBuffer,
1912                texture->m_image,
1913                VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1914                &clearColor,
1915                1,
1916                &range);
1917        }
1918        else
1919        {
1920            Offset srcOffset = 0;
1921            for (int i = 0; i < arraySize; ++i)
1922            {
1923                for (Index j = 0; j < mipSizes.getCount(); ++j)
1924                {
1925                    const auto& mipSize = mipSizes[j];
1926
1927                    auto rowSizeInBytes = calcRowSize(desc.format, mipSize.width);
1928                    auto numRows = calcNumRows(desc.format, mipSize.height);
1929
1930                    // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkBufferImageCopy.html
1931                    // bufferRowLength and bufferImageHeight specify the data in buffer memory as a
1932                    // subregion of a larger two- or three-dimensional image, and control the
1933                    // addressing calculations of data in buffer memory. If either of these values
1934                    // is zero, that aspect of the buffer memory is considered to be tightly packed
1935                    // according to the imageExtent.
1936
1937                    VkBufferImageCopy region = {};
1938
1939                    region.bufferOffset = srcOffset;
1940                    region.bufferRowLength = 0; // rowSizeInBytes;
1941                    region.bufferImageHeight = 0;
1942
1943                    region.imageSubresource.aspectMask = getAspectMaskFromFormat(format);
1944                    region.imageSubresource.mipLevel = uint32_t(j);
1945                    region.imageSubresource.baseArrayLayer = i;
1946                    region.imageSubresource.layerCount = 1;
1947                    region.imageOffset = {0, 0, 0};
1948                    region.imageExtent = {
1949                        uint32_t(mipSize.width),
1950                        uint32_t(mipSize.height),
1951                        uint32_t(mipSize.depth)};
1952
1953                    // Do the copy (do all depths in a single go)
1954                    m_api.vkCmdCopyBufferToImage(
1955                        commandBuffer,
1956                        uploadBuffer.m_buffer,
1957                        texture->m_image,
1958                        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1959                        1,
1960                        &region);
1961
1962                    // Next
1963                    srcOffset += rowSizeInBytes * numRows * mipSize.depth;
1964                }
1965            }
1966        }
1967        auto defaultLayout = VulkanUtil::getImageLayoutFromState(desc.defaultState);
1968        _transitionImageLayout(
1969            texture->m_image,
1970            format,
1971            *texture->getDesc(),
1972            VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1973            defaultLayout);
1974    }
1975    else
1976    {
1977        auto defaultLayout = VulkanUtil::getImageLayoutFromState(desc.defaultState);
1978        if (defaultLayout != VK_IMAGE_LAYOUT_UNDEFINED)
1979        {
1980            _transitionImageLayout(
1981                texture->m_image,
1982                format,
1983                *texture->getDesc(),
1984                VK_IMAGE_LAYOUT_UNDEFINED,
1985                defaultLayout);
1986        }
1987    }
1988    m_deviceQueue.flushAndWait();
1989    returnComPtr(outResource, texture);
1990    return SLANG_OK;
1991}
1992
1993Result DeviceImpl::createBufferResource(
1994    const IBufferResource::Desc& descIn,
1995    const void* initData,
1996    IBufferResource** outResource)
1997{
1998    return createBufferResourceImpl(descIn, 0, initData, outResource);
1999}
2000
2001Result DeviceImpl::createBufferResourceImpl(
2002    const IBufferResource::Desc& descIn,
2003    VkBufferUsageFlags additionalUsageFlag,
2004    const void* initData,
2005    IBufferResource** outResource)
2006{
2007    BufferResource::Desc desc = fixupBufferDesc(descIn);
2008
2009    const Size bufferSize = desc.sizeInBytes;
2010
2011    VkMemoryPropertyFlags reqMemoryProperties = 0;
2012
2013    VkBufferUsageFlags usage = _calcBufferUsageFlags(desc.allowedStates) | additionalUsageFlag;
2014    if (m_api.m_extendedFeatures.vulkan12Features.bufferDeviceAddress)
2015    {
2016        usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
2017    }
2018    if (desc.allowedStates.contains(ResourceState::ShaderResource) &&
2019        m_api.m_extendedFeatures.accelerationStructureFeatures.accelerationStructure)
2020    {
2021        usage |= VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR;
2022    }
2023    if (initData)
2024    {
2025        usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT;
2026    }
2027
2028    if (desc.allowedStates.contains(ResourceState::ConstantBuffer) ||
2029        desc.memoryType == MemoryType::Upload || desc.memoryType == MemoryType::ReadBack)
2030    {
2031        reqMemoryProperties =
2032            VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
2033    }
2034    else
2035    {
2036        reqMemoryProperties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
2037    }
2038
2039    RefPtr<BufferResourceImpl> buffer(new BufferResourceImpl(desc, this));
2040    if (desc.isShared)
2041    {
2042        VkExternalMemoryHandleTypeFlagsKHR extMemHandleType
2043#if SLANG_WINDOWS_FAMILY
2044            = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
2045#else
2046            = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
2047#endif
2048        SLANG_RETURN_ON_FAIL(buffer->m_buffer.init(
2049            m_api,
2050            desc.sizeInBytes,
2051            usage,
2052            reqMemoryProperties,
2053            desc.isShared,
2054            extMemHandleType));
2055    }
2056    else
2057    {
2058        SLANG_RETURN_ON_FAIL(
2059            buffer->m_buffer.init(m_api, desc.sizeInBytes, usage, reqMemoryProperties));
2060    }
2061
2062    if (initData)
2063    {
2064        if (desc.memoryType == MemoryType::DeviceLocal)
2065        {
2066            SLANG_RETURN_ON_FAIL(buffer->m_uploadBuffer.init(
2067                m_api,
2068                bufferSize,
2069                VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
2070                VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT));
2071            // Copy into staging buffer
2072            void* mappedData = nullptr;
2073            SLANG_VK_CHECK(m_api.vkMapMemory(
2074                m_device,
2075                buffer->m_uploadBuffer.m_memory,
2076                0,
2077                bufferSize,
2078                0,
2079                &mappedData));
2080            ::memcpy(mappedData, initData, bufferSize);
2081            m_api.vkUnmapMemory(m_device, buffer->m_uploadBuffer.m_memory);
2082
2083            // Copy from staging buffer to real buffer
2084            VkCommandBuffer commandBuffer = m_deviceQueue.getCommandBuffer();
2085
2086            VkBufferCopy copyInfo = {};
2087            copyInfo.size = bufferSize;
2088            m_api.vkCmdCopyBuffer(
2089                commandBuffer,
2090                buffer->m_uploadBuffer.m_buffer,
2091                buffer->m_buffer.m_buffer,
2092                1,
2093                &copyInfo);
2094            m_deviceQueue.flush();
2095        }
2096        else
2097        {
2098            // Copy into mapped buffer directly
2099            void* mappedData = nullptr;
2100            SLANG_VK_CHECK(m_api.vkMapMemory(
2101                m_device,
2102                buffer->m_buffer.m_memory,
2103                0,
2104                bufferSize,
2105                0,
2106                &mappedData));
2107            ::memcpy(mappedData, initData, bufferSize);
2108            m_api.vkUnmapMemory(m_device, buffer->m_buffer.m_memory);
2109        }
2110    }
2111
2112    returnComPtr(outResource, buffer);
2113    return SLANG_OK;
2114}
2115
2116Result DeviceImpl::createBufferFromNativeHandle(
2117    InteropHandle handle,
2118    const IBufferResource::Desc& srcDesc,
2119    IBufferResource** outResource)
2120{
2121    RefPtr<BufferResourceImpl> buffer(new BufferResourceImpl(srcDesc, this));
2122
2123    if (handle.api == InteropHandleAPI::Vulkan)
2124    {
2125        buffer->m_buffer.m_buffer = (VkBuffer)handle.handleValue;
2126    }
2127    else
2128    {
2129        return SLANG_FAIL;
2130    }
2131
2132    returnComPtr(outResource, buffer);
2133    return SLANG_OK;
2134}
2135
2136Result DeviceImpl::createSamplerState(ISamplerState::Desc const& desc, ISamplerState** outSampler)
2137{
2138    VkSamplerCreateInfo samplerInfo = {VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO};
2139
2140    samplerInfo.magFilter = VulkanUtil::translateFilterMode(desc.magFilter);
2141    samplerInfo.minFilter = VulkanUtil::translateFilterMode(desc.minFilter);
2142
2143    samplerInfo.addressModeU = VulkanUtil::translateAddressingMode(desc.addressU);
2144    samplerInfo.addressModeV = VulkanUtil::translateAddressingMode(desc.addressV);
2145    samplerInfo.addressModeW = VulkanUtil::translateAddressingMode(desc.addressW);
2146
2147    samplerInfo.anisotropyEnable = desc.maxAnisotropy > 1;
2148    samplerInfo.maxAnisotropy = (float)desc.maxAnisotropy;
2149
2150    // TODO: support translation of border color...
2151    samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
2152
2153    samplerInfo.unnormalizedCoordinates = VK_FALSE;
2154    samplerInfo.compareEnable = desc.reductionOp == TextureReductionOp::Comparison;
2155    samplerInfo.compareOp = VulkanUtil::translateComparisonFunc(desc.comparisonFunc);
2156    samplerInfo.mipmapMode = VulkanUtil::translateMipFilterMode(desc.mipFilter);
2157    samplerInfo.minLod = Math::Max(0.0f, desc.minLOD);
2158    samplerInfo.maxLod = Math::Clamp(desc.maxLOD, samplerInfo.minLod, VK_LOD_CLAMP_NONE);
2159
2160    VkSamplerReductionModeCreateInfo reductionInfo = {
2161        VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO};
2162    reductionInfo.reductionMode = VulkanUtil::translateReductionOp(desc.reductionOp);
2163    samplerInfo.pNext = &reductionInfo;
2164
2165    VkSampler sampler;
2166    SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateSampler(m_device, &samplerInfo, nullptr, &sampler));
2167
2168    RefPtr<SamplerStateImpl> samplerImpl = new SamplerStateImpl(this);
2169    samplerImpl->m_sampler = sampler;
2170    returnComPtr(outSampler, samplerImpl);
2171    return SLANG_OK;
2172}
2173
2174Result DeviceImpl::createTextureView(
2175    ITextureResource* texture,
2176    IResourceView::Desc const& desc,
2177    IResourceView** outView)
2178{
2179    auto resourceImpl = static_cast<TextureResourceImpl*>(texture);
2180    RefPtr<TextureResourceViewImpl> view = new TextureResourceViewImpl(this);
2181    view->m_texture = resourceImpl;
2182    view->m_desc = desc;
2183    if (!texture)
2184    {
2185        view->m_view = VK_NULL_HANDLE;
2186        returnComPtr(outView, view);
2187        return SLANG_OK;
2188    }
2189
2190    bool isArray = resourceImpl->getDesc()->arraySize > 1;
2191    VkImageViewCreateInfo createInfo = {};
2192    createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2193    createInfo.flags = 0;
2194    createInfo.format = gfxIsTypelessFormat(texture->getDesc()->format)
2195                            ? VulkanUtil::getVkFormat(desc.format)
2196                            : resourceImpl->m_vkformat;
2197    createInfo.image = resourceImpl->m_image;
2198    createInfo.components = VkComponentMapping{
2199        VK_COMPONENT_SWIZZLE_R,
2200        VK_COMPONENT_SWIZZLE_G,
2201        VK_COMPONENT_SWIZZLE_B,
2202        VK_COMPONENT_SWIZZLE_A};
2203    switch (resourceImpl->getType())
2204    {
2205    case IResource::Type::Texture1D:
2206        createInfo.viewType = isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D;
2207        break;
2208    case IResource::Type::Texture2D:
2209        createInfo.viewType = isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
2210        break;
2211    case IResource::Type::Texture3D:
2212        createInfo.viewType = VK_IMAGE_VIEW_TYPE_3D;
2213        break;
2214    case IResource::Type::TextureCube:
2215        createInfo.viewType = isArray ? VK_IMAGE_VIEW_TYPE_CUBE_ARRAY : VK_IMAGE_VIEW_TYPE_CUBE;
2216        break;
2217    default:
2218        SLANG_UNIMPLEMENTED_X("Unknown Texture type.");
2219        break;
2220    }
2221
2222    createInfo.subresourceRange.aspectMask = getAspectMaskFromFormat(resourceImpl->m_vkformat);
2223
2224    createInfo.subresourceRange.baseArrayLayer = desc.subresourceRange.baseArrayLayer;
2225    createInfo.subresourceRange.baseMipLevel = desc.subresourceRange.mipLevel;
2226    createInfo.subresourceRange.layerCount = desc.subresourceRange.layerCount;
2227    if (createInfo.subresourceRange.layerCount == 0)
2228    {
2229        createInfo.subresourceRange.layerCount = isArray ? VK_REMAINING_ARRAY_LAYERS : 1;
2230        if (createInfo.viewType == VK_IMAGE_VIEW_TYPE_CUBE)
2231        {
2232            createInfo.subresourceRange.layerCount = 6;
2233        }
2234    }
2235    createInfo.subresourceRange.levelCount = desc.subresourceRange.mipLevelCount == 0
2236                                                 ? VK_REMAINING_MIP_LEVELS
2237                                                 : desc.subresourceRange.mipLevelCount;
2238    switch (desc.type)
2239    {
2240    case IResourceView::Type::DepthStencil:
2241        view->m_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
2242        createInfo.subresourceRange.levelCount = 1;
2243        break;
2244    case IResourceView::Type::RenderTarget:
2245        view->m_layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
2246        createInfo.subresourceRange.levelCount = 1;
2247        break;
2248    case IResourceView::Type::ShaderResource:
2249        view->m_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
2250        break;
2251    case IResourceView::Type::UnorderedAccess:
2252        view->m_layout = VK_IMAGE_LAYOUT_GENERAL;
2253        break;
2254    default:
2255        SLANG_UNIMPLEMENTED_X("Unknown TextureViewDesc type.");
2256        break;
2257    }
2258    m_api.vkCreateImageView(m_device, &createInfo, nullptr, &view->m_view);
2259    returnComPtr(outView, view);
2260    return SLANG_OK;
2261}
2262
2263Result DeviceImpl::getFormatSupportedResourceStates(Format format, ResourceStateSet* outStates)
2264{
2265    // TODO: Add variables to VkDevice to track supported surface presentable formats
2266
2267    VkFormat vkFormat = VulkanUtil::getVkFormat(format);
2268
2269    VkFormatProperties supportedProperties = {};
2270    m_api.vkGetPhysicalDeviceFormatProperties(
2271        m_api.m_physicalDevice,
2272        vkFormat,
2273        &supportedProperties);
2274
2275    HashSet<VkFormat> presentableFormats;
2276    // TODO: enable this once we have VK_GOOGLE_surfaceless_query.
2277#if 0
2278    List<VkSurfaceFormatKHR> surfaceFormats;
2279
2280    uint32_t surfaceFormatCount = 0;
2281    m_api.vkGetPhysicalDeviceSurfaceFormatsKHR(
2282        m_api.m_physicalDevice, VK_NULL_HANDLE, &surfaceFormatCount, nullptr);
2283
2284    surfaceFormats.setCount(surfaceFormatCount);
2285    m_api.vkGetPhysicalDeviceSurfaceFormatsKHR(m_api.m_physicalDevice, VK_NULL_HANDLE, &surfaceFormatCount, surfaceFormats.getBuffer());
2286    for (auto surfaceFormat : surfaceFormats)
2287    {
2288        presentableFormats.add(surfaceFormat.format);
2289    }
2290#else
2291    // Until we have a solution to query presentable formats without needing a surface,
2292    // hard code presentable formats that is supported by most drivers.
2293    presentableFormats.add(VK_FORMAT_R8G8B8A8_UNORM);
2294    presentableFormats.add(VK_FORMAT_B8G8R8A8_UNORM);
2295    presentableFormats.add(VK_FORMAT_R8G8B8A8_SRGB);
2296    presentableFormats.add(VK_FORMAT_B8G8R8A8_SRGB);
2297#endif
2298
2299    ResourceStateSet allowedStates;
2300    // TODO: Currently only supports VK_IMAGE_TILING_OPTIMAL
2301    auto imageFeatures = supportedProperties.optimalTilingFeatures;
2302    auto bufferFeatures = supportedProperties.bufferFeatures;
2303    // PreInitialized - Only supported for VK_IMAGE_TILING_LINEAR
2304    // VertexBuffer
2305    if (bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT)
2306        allowedStates.add(ResourceState::VertexBuffer);
2307    // IndexBuffer - Without extensions, Vulkan only supports two formats for index buffers.
2308    switch (format)
2309    {
2310    case Format::R32_UINT:
2311    case Format::R16_UINT:
2312        allowedStates.add(ResourceState::IndexBuffer);
2313        break;
2314    default:
2315        break;
2316    }
2317    // ConstantBuffer
2318    allowedStates.add(ResourceState::ConstantBuffer);
2319    // StreamOutput - TODO: Requires VK_EXT_transform_feedback
2320    // ShaderResource
2321    if (imageFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)
2322        allowedStates.add(ResourceState::ShaderResource);
2323    if (bufferFeatures & VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT)
2324        allowedStates.add(ResourceState::ShaderResource);
2325    // UnorderedAccess
2326    if (imageFeatures &
2327        (VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT | VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT))
2328        allowedStates.add(ResourceState::UnorderedAccess);
2329    if (bufferFeatures & (VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT |
2330                          VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT))
2331        allowedStates.add(ResourceState::UnorderedAccess);
2332    // RenderTarget
2333    if (imageFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)
2334        allowedStates.add(ResourceState::RenderTarget);
2335    // DepthRead, DepthWrite
2336    if (imageFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
2337    {
2338        allowedStates.add(ResourceState::DepthRead);
2339        allowedStates.add(ResourceState::DepthWrite);
2340    }
2341    // Present
2342    if (presentableFormats.contains(vkFormat))
2343        allowedStates.add(ResourceState::Present);
2344    // IndirectArgument
2345    allowedStates.add(ResourceState::IndirectArgument);
2346    // CopySource, ResolveSource
2347    if (imageFeatures & VK_FORMAT_FEATURE_TRANSFER_SRC_BIT)
2348    {
2349        allowedStates.add(ResourceState::CopySource);
2350        allowedStates.add(ResourceState::ResolveSource);
2351    }
2352    // CopyDestination, ResolveDestination
2353    if (imageFeatures & VK_FORMAT_FEATURE_TRANSFER_DST_BIT)
2354    {
2355        allowedStates.add(ResourceState::CopyDestination);
2356        allowedStates.add(ResourceState::ResolveDestination);
2357    }
2358    // AccelerationStructure
2359    if (bufferFeatures & VK_FORMAT_FEATURE_ACCELERATION_STRUCTURE_VERTEX_BUFFER_BIT_KHR)
2360    {
2361        allowedStates.add(ResourceState::AccelerationStructure);
2362        allowedStates.add(ResourceState::AccelerationStructureBuildInput);
2363    }
2364
2365    *outStates = allowedStates;
2366    return SLANG_OK;
2367}
2368
2369Result DeviceImpl::createBufferView(
2370    IBufferResource* buffer,
2371    IBufferResource* counterBuffer,
2372    IResourceView::Desc const& desc,
2373    IResourceView** outView)
2374{
2375    auto resourceImpl = (BufferResourceImpl*)buffer;
2376
2377    VkDeviceSize offset = (VkDeviceSize)desc.bufferRange.offset;
2378    VkDeviceSize size = desc.bufferRange.size == 0
2379                            ? (buffer ? resourceImpl->getDesc()->sizeInBytes : 0)
2380                            : (VkDeviceSize)desc.bufferRange.size;
2381
2382    // There are two different cases we need to think about for buffers.
2383    //
2384    // One is when we have a "uniform texel buffer" or "storage texel buffer,"
2385    // in which case we need to construct a `VkBufferView` to represent the
2386    // formatting that is applied to the buffer. This case would correspond
2387    // to a `textureBuffer` or `imageBuffer` in GLSL, and more or less to
2388    // `Buffer<..>` or `RWBuffer<...>` in HLSL.
2389    //
2390    // The other case is a `storage buffer` which is the catch-all for any
2391    // non-formatted R/W access to a buffer. In GLSL this is a `buffer { ... }`
2392    // declaration, while in HLSL it covers a bunch of different `RW*Buffer`
2393    // cases. In these cases we do *not* need a `VkBufferView`, but in
2394    // order to be compatible with other APIs that require views for any
2395    // potentially writable access, we will have to create one anyway.
2396    //
2397    // We will distinguish the two cases by looking at whether the view
2398    // is being requested with a format or not.
2399    //
2400
2401    switch (desc.type)
2402    {
2403    default:
2404        assert(!"unhandled");
2405        return SLANG_FAIL;
2406
2407    case IResourceView::Type::UnorderedAccess:
2408    case IResourceView::Type::ShaderResource:
2409        // Is this a formatted view?
2410        //
2411        if (desc.format == Format::Unknown)
2412        {
2413            // Buffer usage that doesn't involve formatting doesn't
2414            // require a view in Vulkan.
2415            RefPtr<PlainBufferResourceViewImpl> viewImpl = new PlainBufferResourceViewImpl(this);
2416            viewImpl->m_buffer = resourceImpl;
2417            viewImpl->offset = offset;
2418            viewImpl->size = size;
2419            viewImpl->m_desc = desc;
2420
2421            returnComPtr(outView, viewImpl);
2422            return SLANG_OK;
2423        }
2424        //
2425        // If the view is formatted, then we need to handle
2426        // it just like we would for a "sampled" buffer:
2427        //
2428        // FALLTHROUGH
2429        {
2430            VkBufferViewCreateInfo info = {VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO};
2431
2432            VkBufferView view = VK_NULL_HANDLE;
2433
2434            if (buffer)
2435            {
2436                info.format = VulkanUtil::getVkFormat(desc.format);
2437                info.buffer = resourceImpl->m_buffer.m_buffer;
2438                info.offset = offset;
2439                info.range = size;
2440                VkBufferUsageFlags2CreateInfoKHR bufferViewUsage{};
2441                bufferViewUsage.sType = VK_STRUCTURE_TYPE_BUFFER_USAGE_FLAGS_2_CREATE_INFO_KHR;
2442
2443                if (desc.type == IResourceView::Type::UnorderedAccess)
2444                {
2445                    info.pNext = &bufferViewUsage;
2446                    bufferViewUsage.usage = VK_BUFFER_USAGE_2_STORAGE_TEXEL_BUFFER_BIT_KHR;
2447                }
2448                else if (desc.type == IResourceView::Type::ShaderResource)
2449                {
2450                    info.pNext = &bufferViewUsage;
2451                    bufferViewUsage.usage = VK_BUFFER_USAGE_2_UNIFORM_TEXEL_BUFFER_BIT_KHR;
2452                }
2453                else
2454                {
2455                    assert(!"unhandled");
2456                }
2457
2458                SLANG_VK_RETURN_ON_FAIL(m_api.vkCreateBufferView(m_device, &info, nullptr, &view));
2459            }
2460
2461            RefPtr<TexelBufferResourceViewImpl> viewImpl = new TexelBufferResourceViewImpl(this);
2462            viewImpl->m_buffer = resourceImpl;
2463            viewImpl->m_view = view;
2464            viewImpl->m_desc = desc;
2465
2466            returnComPtr(outView, viewImpl);
2467            return SLANG_OK;
2468        }
2469        break;
2470    }
2471}
2472
2473Result DeviceImpl::createInputLayout(IInputLayout::Desc const& desc, IInputLayout** outLayout)
2474{
2475    RefPtr<InputLayoutImpl> layout(new InputLayoutImpl);
2476
2477    List<VkVertexInputAttributeDescription>& dstAttributes = layout->m_attributeDescs;
2478    List<VkVertexInputBindingDescription>& dstStreams = layout->m_streamDescs;
2479
2480    auto elements = desc.inputElements;
2481    Int numElements = desc.inputElementCount;
2482
2483    auto srcVertexStreams = desc.vertexStreams;
2484    Int vertexStreamCount = desc.vertexStreamCount;
2485
2486    dstAttributes.setCount(numElements);
2487    dstStreams.setCount(vertexStreamCount);
2488
2489    for (Int i = 0; i < vertexStreamCount; i++)
2490    {
2491        auto& dstStream = dstStreams[i];
2492        auto& srcStream = srcVertexStreams[i];
2493        dstStream.stride = (uint32_t)srcStream.stride;
2494        dstStream.binding = (uint32_t)i;
2495        dstStream.inputRate = (srcStream.slotClass == InputSlotClass::PerInstance)
2496                                  ? VK_VERTEX_INPUT_RATE_INSTANCE
2497                                  : VK_VERTEX_INPUT_RATE_VERTEX;
2498    }
2499
2500    for (Int i = 0; i < numElements; ++i)
2501    {
2502        const InputElementDesc& srcDesc = elements[i];
2503        auto streamIndex = srcDesc.bufferSlotIndex;
2504
2505        VkVertexInputAttributeDescription& dstDesc = dstAttributes[i];
2506
2507        dstDesc.location = uint32_t(i);
2508        dstDesc.binding = (uint32_t)streamIndex;
2509        dstDesc.format = VulkanUtil::getVkFormat(srcDesc.format);
2510        if (dstDesc.format == VK_FORMAT_UNDEFINED)
2511        {
2512            return SLANG_FAIL;
2513        }
2514
2515        dstDesc.offset = uint32_t(srcDesc.offset);
2516    }
2517
2518    // Work out the overall size
2519    returnComPtr(outLayout, layout);
2520    return SLANG_OK;
2521}
2522
2523Result DeviceImpl::createProgram(
2524    const IShaderProgram::Desc& desc,
2525    IShaderProgram** outProgram,
2526    ISlangBlob** outDiagnosticBlob)
2527{
2528    RefPtr<ShaderProgramImpl> shaderProgram = new ShaderProgramImpl(this);
2529    shaderProgram->init(desc);
2530
2531    m_deviceObjectsWithPotentialBackReferences.add(shaderProgram);
2532
2533    RootShaderObjectLayout::create(
2534        this,
2535        shaderProgram->linkedProgram,
2536        shaderProgram->linkedProgram->getLayout(),
2537        shaderProgram->m_rootObjectLayout.writeRef());
2538
2539    if (!shaderProgram->isSpecializable())
2540    {
2541        SLANG_RETURN_ON_FAIL(shaderProgram->compileShaders(this));
2542    }
2543
2544    returnComPtr(outProgram, shaderProgram);
2545    return SLANG_OK;
2546}
2547
2548Result DeviceImpl::createShaderObjectLayout(
2549    slang::ISession* session,
2550    slang::TypeLayoutReflection* typeLayout,
2551    ShaderObjectLayoutBase** outLayout)
2552{
2553    RefPtr<ShaderObjectLayoutImpl> layout;
2554    SLANG_RETURN_ON_FAIL(
2555        ShaderObjectLayoutImpl::createForElementType(this, session, typeLayout, layout.writeRef()));
2556    returnRefPtrMove(outLayout, layout);
2557    return SLANG_OK;
2558}
2559
2560Result DeviceImpl::createShaderObject(ShaderObjectLayoutBase* layout, IShaderObject** outObject)
2561{
2562    RefPtr<ShaderObjectImpl> shaderObject;
2563    SLANG_RETURN_ON_FAIL(ShaderObjectImpl::create(
2564        this,
2565        static_cast<ShaderObjectLayoutImpl*>(layout),
2566        shaderObject.writeRef()));
2567    returnComPtr(outObject, shaderObject);
2568    return SLANG_OK;
2569}
2570
2571Result DeviceImpl::createMutableShaderObject(
2572    ShaderObjectLayoutBase* layout,
2573    IShaderObject** outObject)
2574{
2575    auto layoutImpl = static_cast<ShaderObjectLayoutImpl*>(layout);
2576
2577    RefPtr<ShaderObjectImpl> result;
2578    SLANG_RETURN_ON_FAIL(ShaderObjectImpl::create(this, layoutImpl, result.writeRef()));
2579    returnComPtr(outObject, result);
2580
2581    return SLANG_OK;
2582}
2583
2584Result DeviceImpl::createMutableRootShaderObject(IShaderProgram* program, IShaderObject** outObject)
2585{
2586    RefPtr<MutableRootShaderObjectImpl> result = new MutableRootShaderObjectImpl();
2587    auto programImpl = static_cast<ShaderProgramImpl*>(program);
2588    SLANG_RETURN_ON_FAIL(result->init(this, programImpl->m_rootObjectLayout));
2589    returnComPtr(outObject, result);
2590    return SLANG_OK;
2591}
2592
2593Result DeviceImpl::createShaderTable(const IShaderTable::Desc& desc, IShaderTable** outShaderTable)
2594{
2595    RefPtr<ShaderTableImpl> result = new ShaderTableImpl();
2596    result->m_device = this;
2597    result->init(desc);
2598    returnComPtr(outShaderTable, result);
2599    return SLANG_OK;
2600}
2601
2602Result DeviceImpl::createGraphicsPipelineState(
2603    const GraphicsPipelineStateDesc& inDesc,
2604    IPipelineState** outState)
2605{
2606    GraphicsPipelineStateDesc desc = inDesc;
2607    RefPtr<PipelineStateImpl> pipelineStateImpl = new PipelineStateImpl(this);
2608    pipelineStateImpl->init(desc);
2609    pipelineStateImpl->establishStrongDeviceReference();
2610    m_deviceObjectsWithPotentialBackReferences.add(pipelineStateImpl);
2611    returnComPtr(outState, pipelineStateImpl);
2612
2613    return SLANG_OK;
2614}
2615
2616Result DeviceImpl::createComputePipelineState(
2617    const ComputePipelineStateDesc& inDesc,
2618    IPipelineState** outState)
2619{
2620    ComputePipelineStateDesc desc = inDesc;
2621    RefPtr<PipelineStateImpl> pipelineStateImpl = new PipelineStateImpl(this);
2622    pipelineStateImpl->init(desc);
2623    m_deviceObjectsWithPotentialBackReferences.add(pipelineStateImpl);
2624    pipelineStateImpl->establishStrongDeviceReference();
2625    returnComPtr(outState, pipelineStateImpl);
2626    return SLANG_OK;
2627}
2628
2629Result DeviceImpl::createRayTracingPipelineState(
2630    const RayTracingPipelineStateDesc& desc,
2631    IPipelineState** outState)
2632{
2633    RefPtr<RayTracingPipelineStateImpl> pipelineStateImpl = new RayTracingPipelineStateImpl(this);
2634    pipelineStateImpl->init(desc);
2635    m_deviceObjectsWithPotentialBackReferences.add(pipelineStateImpl);
2636    pipelineStateImpl->establishStrongDeviceReference();
2637    returnComPtr(outState, pipelineStateImpl);
2638    return SLANG_OK;
2639}
2640
2641Result DeviceImpl::createQueryPool(const IQueryPool::Desc& desc, IQueryPool** outPool)
2642{
2643    RefPtr<QueryPoolImpl> result = new QueryPoolImpl();
2644    SLANG_RETURN_ON_FAIL(result->init(desc, this));
2645    returnComPtr(outPool, result);
2646    return SLANG_OK;
2647}
2648
2649Result DeviceImpl::createFence(const IFence::Desc& desc, IFence** outFence)
2650{
2651    RefPtr<FenceImpl> fence = new FenceImpl(this);
2652    SLANG_RETURN_ON_FAIL(fence->init(desc));
2653    returnComPtr(outFence, fence);
2654    return SLANG_OK;
2655}
2656
2657Result DeviceImpl::waitForFences(
2658    GfxCount fenceCount,
2659    IFence** fences,
2660    uint64_t* fenceValues,
2661    bool waitForAll,
2662    uint64_t timeout)
2663{
2664    ShortList<VkSemaphore> semaphores;
2665    for (GfxIndex i = 0; i < fenceCount; ++i)
2666    {
2667        auto fenceImpl = static_cast<FenceImpl*>(fences[i]);
2668        semaphores.add(fenceImpl->m_semaphore);
2669    }
2670    VkSemaphoreWaitInfo waitInfo;
2671    waitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO;
2672    waitInfo.pNext = NULL;
2673    waitInfo.flags = 0;
2674    waitInfo.semaphoreCount = 1;
2675    waitInfo.pSemaphores = semaphores.getArrayView().getBuffer();
2676    waitInfo.pValues = fenceValues;
2677    auto result = m_api.vkWaitSemaphores(m_api.m_device, &waitInfo, timeout);
2678    if (result == VK_TIMEOUT)
2679        return SLANG_E_TIME_OUT;
2680    return result == VK_SUCCESS ? SLANG_OK : SLANG_FAIL;
2681}
2682
2683} // namespace vk
2684} // namespace gfx