diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 3d0b6293..e51ec249 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -22,6 +22,7 @@ Released TBD - Add correct function entry point handling. - Add support for `VK_KHR_get_surface_capabilities2` extension. - Implement newer `VK_KHR_swapchain` extension functions. +- Add support for tracking device features enabled during `vkCreateDevice()`. - Allow zero offset and stride combo in `VkVertexInputBindingDescription`. - Fix conditions when multiple functions return VK_INCOMPLETE. - Fix potential memory leak on synchronous command buffer submission. diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm index f0802737..2b798977 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm @@ -148,7 +148,7 @@ void MVKCmdSetLineWidth::setContent(float lineWidth) { // Validate clearConfigurationResult(); - if (_lineWidth != 1.0 || getDevice()->_pFeatures->wideLines) { + if (_lineWidth != 1.0 || getDevice()->_enabledFeatures.wideLines) { setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdSetLineWidth(): The current device does not support wide lines.")); } } @@ -207,7 +207,7 @@ void MVKCmdSetDepthBounds::setContent(float minDepthBounds, float maxDepthBounds // Validate clearConfigurationResult(); - if (getDevice()->_pFeatures->depthBounds) { + if (getDevice()->_enabledFeatures.depthBounds) { setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdSetDepthBounds(): The current device does not support setting depth bounds.")); } } diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm index 38277446..600f8927 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm @@ -532,7 +532,7 @@ MVKCommandEncoder::MVKCommandEncoder(MVKCommandBuffer* cmdBuffer) : MVKBaseDevic _computeResourcesState(this), _occlusionQueryState(this) { - _pDeviceFeatures = _device->_pFeatures; + _pDeviceFeatures = &_device->_enabledFeatures; _pDeviceMetalFeatures = _device->_pMetalFeatures; _pDeviceProperties = _device->_pProperties; _pDeviceMemoryProperties = _device->_pMemoryProperties; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm index f62ffd5b..4b8eaec4 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm @@ -73,7 +73,7 @@ void MVKViewportCommandEncoderState::setViewports(const MVKVector & void MVKViewportCommandEncoderState::encodeImpl(uint32_t stage) { if (stage != kMVKGraphicsStageRasterization) { return; } MVKAssert(!_mtlViewports.empty(), "Must specify at least one viewport"); - if (_cmdEncoder->getDevice()->_pFeatures->multiViewport) { + if (_cmdEncoder->_pDeviceFeatures->multiViewport) { [_cmdEncoder->_mtlRenderEncoder setViewports: &_mtlViewports[0] count: _mtlViewports.size()]; } else { [_cmdEncoder->_mtlRenderEncoder setViewport: _mtlViewports[0]]; @@ -115,7 +115,7 @@ void MVKScissorCommandEncoderState::encodeImpl(uint32_t stage) { std::for_each(clippedScissors.begin(), clippedScissors.end(), [this](MTLScissorRect& scissor) { scissor = _cmdEncoder->clipToRenderArea(scissor); }); - if (_cmdEncoder->getDevice()->_pFeatures->multiViewport) { + if (_cmdEncoder->_pDeviceFeatures->multiViewport) { [_cmdEncoder->_mtlRenderEncoder setScissorRects: &clippedScissors[0] count: clippedScissors.size()]; } else { [_cmdEncoder->_mtlRenderEncoder setScissorRect: clippedScissors[0]]; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h index 5aa11f7a..7712bce5 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h @@ -583,8 +583,18 @@ public: /** Pointer to the MoltenVK configuration settings. */ const MVKConfiguration* _pMVKConfig; - /** Pointer to the feature set of the underlying physical device. */ - const VkPhysicalDeviceFeatures* _pFeatures; + /** Device features available and enabled. */ + const VkPhysicalDeviceFeatures _enabledFeatures; + const VkPhysicalDevice16BitStorageFeatures _enabledStorage16Features; + const VkPhysicalDevice8BitStorageFeaturesKHR _enabledStorage8Features; + const VkPhysicalDeviceFloat16Int8FeaturesKHR _enabledF16I8Features; + const VkPhysicalDeviceVariablePointerFeatures _enabledVarPtrFeatures; + const VkPhysicalDeviceHostQueryResetFeaturesEXT _enabledHostQryResetFeatures; + const VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT _enabledVtxAttrDivFeatures; + const VkPhysicalDevicePortabilitySubsetFeaturesEXTX _enabledPortabilityFeatures; + + /** The list of Vulkan extensions, indicating whether each has been enabled by the app for this device. */ + const MVKExtensionList _enabledExtensions; /** Pointer to the Metal-specific features of the underlying physical device. */ const MVKPhysicalDeviceMetalFeatures* _pMetalFeatures; @@ -595,9 +605,6 @@ public: /** Pointer to the memory properties of the underlying physical device. */ const VkPhysicalDeviceMemoryProperties* _pMemoryProperties; - /** The list of Vulkan extensions, indicating whether each has been enabled by the app for this device. */ - const MVKExtensionList _enabledExtensions; - /** Performance statistics. */ MVKPerformanceStatistics _performanceStatistics; @@ -629,6 +636,9 @@ protected: void initPerformanceTracking(); void initPhysicalDevice(MVKPhysicalDevice* physicalDevice); void initQueues(const VkDeviceCreateInfo* pCreateInfo); + void enableFeatures(const VkDeviceCreateInfo* pCreateInfo); + void enableFeatures(const VkBool32* pEnable, const VkBool32* pRequested, const VkBool32* pAvailable, uint32_t count); + void enableExtensions(const VkDeviceCreateInfo* pCreateInfo); const char* getActivityPerformanceDescription(MVKPerformanceTracker& shaderCompilationEvent); uint64_t getPerformanceTimestampImpl(); void addActivityPerformanceImpl(MVKPerformanceTracker& shaderCompilationEvent, diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 28c47980..d8d9d5f6 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -2036,21 +2036,27 @@ uint32_t MVKDevice::expandVisibilityResultMTLBuffer(uint32_t queryCount) { #pragma mark Construction -MVKDevice::MVKDevice(MVKPhysicalDevice* physicalDevice, const VkDeviceCreateInfo* pCreateInfo) { +MVKDevice::MVKDevice(MVKPhysicalDevice* physicalDevice, const VkDeviceCreateInfo* pCreateInfo) : + _enabledFeatures(), + _enabledStorage16Features(), + _enabledStorage8Features(), + _enabledF16I8Features(), + _enabledVarPtrFeatures(), + _enabledHostQryResetFeatures(), + _enabledVtxAttrDivFeatures(), + _enabledPortabilityFeatures() +{ initPerformanceTracking(); initPhysicalDevice(physicalDevice); + enableFeatures(pCreateInfo); + enableExtensions(pCreateInfo); _globalVisibilityResultMTLBuffer = nil; _globalVisibilityQueryCount = 0; _commandResourceFactory = new MVKCommandResourceFactory(this); - MVKExtensionList* pWritableExtns = (MVKExtensionList*)&_enabledExtensions; - setConfigurationResult(pWritableExtns->enable(pCreateInfo->enabledExtensionCount, - pCreateInfo->ppEnabledExtensionNames, - getInstance()->getDriverLayer()->getSupportedExtensions())); - initQueues(pCreateInfo); string logMsg = "Created VkDevice to run on GPU %s with the following Vulkan extensions enabled:"; @@ -2083,7 +2089,6 @@ void MVKDevice::initPhysicalDevice(MVKPhysicalDevice* physicalDevice) { _physicalDevice = physicalDevice; _pMVKConfig = _physicalDevice->_mvkInstance->getMoltenVKConfiguration(); - _pFeatures = &_physicalDevice->_features; _pMetalFeatures = _physicalDevice->getMetalFeatures(); _pProperties = &_physicalDevice->_properties; _pMemoryProperties = &_physicalDevice->_memoryProperties; @@ -2103,6 +2108,142 @@ void MVKDevice::initPhysicalDevice(MVKPhysicalDevice* physicalDevice) { #endif } +void MVKDevice::enableFeatures(const VkDeviceCreateInfo* pCreateInfo) { + + // Start with all features disabled + memset((void*)&_enabledFeatures, 0, sizeof(_enabledFeatures)); + memset((void*)&_enabledStorage16Features, 0, sizeof(_enabledStorage16Features)); + memset((void*)&_enabledStorage8Features, 0, sizeof(_enabledStorage8Features)); + memset((void*)&_enabledF16I8Features, 0, sizeof(_enabledF16I8Features)); + memset((void*)&_enabledVarPtrFeatures, 0, sizeof(_enabledVarPtrFeatures)); + memset((void*)&_enabledHostQryResetFeatures, 0, sizeof(_enabledHostQryResetFeatures)); + memset((void*)&_enabledVtxAttrDivFeatures, 0, sizeof(_enabledVtxAttrDivFeatures)); + memset((void*)&_enabledPortabilityFeatures, 0, sizeof(_enabledPortabilityFeatures)); + + // Fetch the available physical device features. + VkPhysicalDevicePortabilitySubsetFeaturesEXTX pdPortabilityFeatures; + pdPortabilityFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_EXTX; + pdPortabilityFeatures.pNext = NULL; + + VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT pdVtxAttrDivFeatures; + pdVtxAttrDivFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT; + pdVtxAttrDivFeatures.pNext = &pdPortabilityFeatures; + + VkPhysicalDeviceHostQueryResetFeaturesEXT pdHostQryResetFeatures; + pdHostQryResetFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT; + pdHostQryResetFeatures.pNext = &pdVtxAttrDivFeatures; + + VkPhysicalDeviceVariablePointerFeatures pdVarPtrFeatures; + pdVarPtrFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES; + pdVarPtrFeatures.pNext = &pdHostQryResetFeatures; + + VkPhysicalDeviceFloat16Int8FeaturesKHR pdF16I8Features; + pdF16I8Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR; + pdF16I8Features.pNext = &pdVarPtrFeatures; + + VkPhysicalDevice8BitStorageFeaturesKHR pdStorage8Features; + pdStorage8Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR; + pdStorage8Features.pNext = &pdF16I8Features; + + VkPhysicalDevice16BitStorageFeatures pdStorage16Features; + pdStorage16Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES; + pdStorage16Features.pNext = &pdStorage8Features; + + VkPhysicalDeviceFeatures2 pdFeats2; + pdFeats2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + pdFeats2.pNext = &pdStorage16Features; + + _physicalDevice->getFeatures(&pdFeats2); + + //Enable device features based on requested and available features + if (pCreateInfo->pEnabledFeatures) { + enableFeatures(&_enabledFeatures.robustBufferAccess, + &pCreateInfo->pEnabledFeatures->robustBufferAccess, + &pdFeats2.features.robustBufferAccess, 55); + } + + auto* next = (MVKVkAPIStructHeader*)pCreateInfo->pNext; + while (next) { + switch ((uint32_t)next->sType) { + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2: { + auto* requestedFeatures = (VkPhysicalDeviceFeatures2*)next; + enableFeatures(&_enabledFeatures.robustBufferAccess, + &requestedFeatures->features.robustBufferAccess, + &pdFeats2.features.robustBufferAccess, 55); + break; + } + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES: { + auto* requestedFeatures = (VkPhysicalDevice16BitStorageFeatures*)next; + enableFeatures(&_enabledStorage16Features.storageBuffer16BitAccess, + &requestedFeatures->storageBuffer16BitAccess, + &pdStorage16Features.storageBuffer16BitAccess, 4); + break; + } + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR: { + auto* requestedFeatures = (VkPhysicalDevice8BitStorageFeaturesKHR*)next; + enableFeatures(&_enabledStorage8Features.storageBuffer8BitAccess, + &requestedFeatures->storageBuffer8BitAccess, + &pdStorage8Features.storageBuffer8BitAccess, 3); + break; + } + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR: { + auto* requestedFeatures = (VkPhysicalDeviceFloat16Int8FeaturesKHR*)next; + enableFeatures(&_enabledF16I8Features.shaderFloat16, + &requestedFeatures->shaderFloat16, + &pdF16I8Features.shaderFloat16, 2); + break; + } + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES: { + auto* requestedFeatures = (VkPhysicalDeviceVariablePointerFeatures*)next; + enableFeatures(&_enabledVarPtrFeatures.variablePointersStorageBuffer, + &requestedFeatures->variablePointersStorageBuffer, + &pdVarPtrFeatures.variablePointersStorageBuffer, 2); + break; + } + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT: { + auto* requestedFeatures = (VkPhysicalDeviceHostQueryResetFeaturesEXT*)next; + enableFeatures(&_enabledHostQryResetFeatures.hostQueryReset, + &requestedFeatures->hostQueryReset, + &pdHostQryResetFeatures.hostQueryReset, 1); + break; + } + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT: { + auto* requestedFeatures = (VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT*)next; + enableFeatures(&_enabledVtxAttrDivFeatures.vertexAttributeInstanceRateDivisor, + &requestedFeatures->vertexAttributeInstanceRateDivisor, + &pdVtxAttrDivFeatures.vertexAttributeInstanceRateDivisor, 2); + break; + } + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_EXTX: { + auto* requestedFeatures = (VkPhysicalDevicePortabilitySubsetFeaturesEXTX*)next; + enableFeatures(&_enabledPortabilityFeatures.triangleFans, + &requestedFeatures->triangleFans, + &pdPortabilityFeatures.triangleFans, 5); + break; + } + default: + break; + } + next = (MVKVkAPIStructHeader*)next->pNext; + } +} + +void MVKDevice::enableFeatures(const VkBool32* pEnable, const VkBool32* pRequested, const VkBool32* pAvailable, uint32_t count) { + for (uint32_t i = 0; i < count; i++) { + ((VkBool32*)pEnable)[i] = pRequested[i] && pAvailable[i]; + if (pRequested[i] && !pAvailable[i]) { + setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateDevice(): Requested feature is not available on this device.")); + } + } +} + +void MVKDevice::enableExtensions(const VkDeviceCreateInfo* pCreateInfo) { + MVKExtensionList* pWritableExtns = (MVKExtensionList*)&_enabledExtensions; + setConfigurationResult(pWritableExtns->enable(pCreateInfo->enabledExtensionCount, + pCreateInfo->ppEnabledExtensionNames, + getInstance()->getDriverLayer()->getSupportedExtensions())); +} + // Create the command queues void MVKDevice::initQueues(const VkDeviceCreateInfo* pCreateInfo) { vector qFams = _physicalDevice->getQueueFamilies(); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm index 84063271..9fdec174 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm @@ -226,7 +226,7 @@ void MVKGraphicsPipeline::encode(MVKCommandEncoder* cmdEncoder, uint32_t stage) [mtlCmdEnc setFrontFacingWinding: _mtlFrontWinding]; [mtlCmdEnc setTriangleFillMode: _mtlFillMode]; - if (_device->_pFeatures->depthClamp) { + if (_device->_enabledFeatures.depthClamp) { [mtlCmdEnc setDepthClipMode: _mtlDepthClipMode]; } @@ -323,7 +323,7 @@ MVKGraphicsPipeline::MVKGraphicsPipeline(MVKDevice* device, _mtlFrontWinding = mvkMTLWindingFromVkFrontFace(_rasterInfo.frontFace); _mtlFillMode = mvkMTLTriangleFillModeFromVkPolygonMode(_rasterInfo.polygonMode); if (_rasterInfo.depthClampEnable) { - if (_device->_pFeatures->depthClamp) { + if (_device->_enabledFeatures.depthClamp) { _mtlDepthClipMode = MTLDepthClipModeClamp; } else { setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_FEATURE_NOT_PRESENT, "This device does not support depth clamping.")); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm b/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm index d81e7efe..ad052c08 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm @@ -244,7 +244,7 @@ MVKOcclusionQueryPool::~MVKOcclusionQueryPool() { MVKPipelineStatisticsQueryPool::MVKPipelineStatisticsQueryPool(MVKDevice* device, const VkQueryPoolCreateInfo* pCreateInfo) : MVKQueryPool(device, pCreateInfo, 1) { - if ( !_device->_pFeatures->pipelineStatisticsQuery ) { + if ( !_device->_enabledFeatures.pipelineStatisticsQuery ) { setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateQueryPool: VK_QUERY_TYPE_PIPELINE_STATISTICS is not supported.")); } } diff --git a/MoltenVK/MoltenVK/Vulkan/vulkan.mm b/MoltenVK/MoltenVK/Vulkan/vulkan.mm index 71a9fd61..2eeb83eb 100644 --- a/MoltenVK/MoltenVK/Vulkan/vulkan.mm +++ b/MoltenVK/MoltenVK/Vulkan/vulkan.mm @@ -159,7 +159,7 @@ MVK_PUBLIC_SYMBOL VkResult vkCreateDevice( MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice); MVKDevice* mvkDev = new MVKDevice(mvkPD, pCreateInfo); *pDevice = mvkDev->getVkDevice(); - return VK_SUCCESS; + return mvkDev->getConfigurationResult(); } MVK_PUBLIC_SYMBOL void vkDestroyDevice( @@ -288,12 +288,14 @@ MVK_PUBLIC_SYMBOL VkResult vkFlushMappedMemoryRanges( uint32_t memRangeCount, const VkMappedMemoryRange* pMemRanges) { + VkResult rslt = VK_SUCCESS; for (uint32_t i = 0; i < memRangeCount; i++) { const VkMappedMemoryRange* pMem = &pMemRanges[i]; MVKDeviceMemory* mvkMem = (MVKDeviceMemory*)pMem->memory; - mvkMem->flushToDevice(pMem->offset, pMem->size); + VkResult r = mvkMem->flushToDevice(pMem->offset, pMem->size); + if (rslt == VK_SUCCESS) { rslt = r; } } - return VK_SUCCESS; + return rslt; } MVK_PUBLIC_SYMBOL VkResult vkInvalidateMappedMemoryRanges( @@ -301,12 +303,14 @@ MVK_PUBLIC_SYMBOL VkResult vkInvalidateMappedMemoryRanges( uint32_t memRangeCount, const VkMappedMemoryRange* pMemRanges) { + VkResult rslt = VK_SUCCESS; for (uint32_t i = 0; i < memRangeCount; i++) { const VkMappedMemoryRange* pMem = &pMemRanges[i]; MVKDeviceMemory* mvkMem = (MVKDeviceMemory*)pMem->memory; - mvkMem->pullFromDevice(pMem->offset, pMem->size); + VkResult r = mvkMem->pullFromDevice(pMem->offset, pMem->size); + if (rslt == VK_SUCCESS) { rslt = r; } } - return VK_SUCCESS; + return rslt; } MVK_PUBLIC_SYMBOL void vkGetDeviceMemoryCommitment( @@ -366,7 +370,10 @@ MVK_PUBLIC_SYMBOL void vkGetImageSparseMemoryRequirements( uint32_t* pNumRequirements, VkSparseImageMemoryRequirements* pSparseMemoryRequirements) { - MVKLogUnimplemented("vkGetImageSparseMemoryRequirements"); + // Metal does not support sparse images. + // Vulkan spec: "If the image was not created with VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT then + // pSparseMemoryRequirementCount will be set to zero and pSparseMemoryRequirements will not be written to.". + *pNumRequirements = 0; } @@ -380,7 +387,10 @@ MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceSparseImageFormatProperties( uint32_t* pPropertyCount, VkSparseImageFormatProperties* pProperties) { - MVKLogUnimplemented("vkGetPhysicalDeviceSparseImageFormatProperties"); + // Metal does not support sparse images. + // Vulkan spec: "If VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT is not supported for the given arguments, + // pPropertyCount will be set to zero upon return, and no data will be written to pProperties.". + *pPropertyCount = 0; } @@ -390,7 +400,7 @@ MVK_PUBLIC_SYMBOL VkResult vkQueueBindSparse( const VkBindSparseInfo* pBindInfo, VkFence fence) { - return MVKLogUnimplemented("vkQueueBindSparse"); + return mvkNotifyErrorWithText(VK_ERROR_FEATURE_NOT_PRESENT, "vkQueueBindSparse(): Sparse binding is not supported."); } MVK_PUBLIC_SYMBOL VkResult vkCreateFence( @@ -1569,7 +1579,10 @@ MVK_PUBLIC_SYMBOL void vkGetImageSparseMemoryRequirements2KHR( uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2KHR* pSparseMemoryRequirements) { - MVKLogUnimplemented("vkGetImageSparseMemoryRequirements2KHR"); + // Metal does not support sparse images. + // Vulkan spec: "If the image was not created with VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT then + // pSparseMemoryRequirementCount will be set to zero and pSparseMemoryRequirements will not be written to.". + *pSparseMemoryRequirementCount = 0; } @@ -1634,7 +1647,10 @@ MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceSparseImageFormatProperties2KHR( uint32_t* pPropertyCount, VkSparseImageFormatProperties2KHR* pProperties) { - MVKLogUnimplemented("vkGetPhysicalDeviceSparseImageFormatProperties"); + // Metal does not support sparse images. + // Vulkan spec: "If VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT is not supported for the given arguments, + // pPropertyCount will be set to zero upon return, and no data will be written to pProperties.". + *pPropertyCount = 0; }