diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md index f1fc2116..7c83f6bd 100644 --- a/Docs/MoltenVK_Runtime_UserGuide.md +++ b/Docs/MoltenVK_Runtime_UserGuide.md @@ -310,6 +310,7 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll - `VK_EXT_memory_budget` *(requires Metal 2.0)* - `VK_EXT_metal_surface` - `VK_EXT_post_depth_coverage` *(iOS, requires GPU family 4)* +- `VK_EXT_private_data ` - `VK_EXT_robustness2` - `VK_EXT_scalar_block_layout` - `VK_EXT_shader_stencil_export` *(requires Mac GPU family 2 or iOS GPU family 5)* diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 36fe3877..e404d3a3 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -18,6 +18,8 @@ MoltenVK 1.1.1 Released TBD +- Add support for extensions: + - `VK_EXT_private_data` - Use `VK_KHR_image_format_list` to disable `MTLTextureUsagePixelFormatView` if only swizzles or `sRGB` conversion will be used for image views, improving performance on *iOS* by allowing Metal to use lossless texture compression. diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h index 3fd9fbd9..1af11db1 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h @@ -66,6 +66,7 @@ class MVKRenderPass; class MVKCommandPool; class MVKCommandEncoder; class MVKCommandResourceFactory; +class MVKPrivateDataSlot; /** The buffer index to use for vertex content. */ @@ -578,6 +579,13 @@ public: void freeMemory(MVKDeviceMemory* mvkDevMem, const VkAllocationCallbacks* pAllocator); + VkResult createPrivateDataSlot(const VkPrivateDataSlotCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkPrivateDataSlotEXT* pPrivateDataSlot); + + void destroyPrivateDataSlot(VkPrivateDataSlotEXT privateDataSlot, + const VkAllocationCallbacks* pAllocator); + #pragma mark Operations @@ -678,6 +686,7 @@ public: const VkPhysicalDeviceScalarBlockLayoutFeaturesEXT _enabledScalarLayoutFeatures; const VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT _enabledTexelBuffAlignFeatures; const VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT _enabledVtxAttrDivFeatures; + const VkPhysicalDevicePrivateDataFeaturesEXT _enabledPrivateDataFeatures; const VkPhysicalDevicePortabilitySubsetFeaturesKHR _enabledPortabilityFeatures; /** The list of Vulkan extensions, indicating whether each has been enabled by the app for this device. */ @@ -724,6 +733,7 @@ protected: void initPerformanceTracking(); void initPhysicalDevice(MVKPhysicalDevice* physicalDevice, const VkDeviceCreateInfo* pCreateInfo); void initQueues(const VkDeviceCreateInfo* pCreateInfo); + void reservePrivateData(const VkDeviceCreateInfo* pCreateInfo); void initMTLCompileOptions(); void enableFeatures(const VkDeviceCreateInfo* pCreateInfo); void enableFeatures(const VkBool32* pEnable, const VkBool32* pRequested, const VkBool32* pAvailable, uint32_t count); @@ -737,6 +747,8 @@ protected: MTLCompileOptions* _mtlCompileOptions; MVKSmallVector, kMVKQueueFamilyCount> _queuesByQueueFamilyIndex; MVKSmallVector _resources; + MVKSmallVector _privateDataSlots; + MVKSmallVector _privateDataSlotsAvailability; std::mutex _rezLock; std::mutex _perfLock; id _globalVisibilityResultMTLBuffer; @@ -819,6 +831,35 @@ protected: }; +#pragma mark - +#pragma mark MVKPrivateDataSlot + +/** Private data slot. */ +class MVKPrivateDataSlot : public MVKVulkanAPIDeviceObject { + +public: + + /** Returns the Vulkan type of this object. */ + VkObjectType getVkObjectType() override { return VK_OBJECT_TYPE_PRIVATE_DATA_SLOT_EXT; } + + /** Returns the debug report object type of this object. */ + VkDebugReportObjectTypeEXT getVkDebugReportObjectType() override { return VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT; } + + void setData(VkObjectType objectType, uint64_t objectHandle, uint64_t data) { _privateData[objectHandle] = data; } + + uint64_t getData(VkObjectType objectType, uint64_t objectHandle) { return _privateData[objectHandle]; } + + void clearData() { _privateData.clear(); } + + MVKPrivateDataSlot(MVKDevice* device) : MVKVulkanAPIDeviceObject(device) {} + +protected: + void propagateDebugName() override {} + + std::unordered_map _privateData; +}; + + #pragma mark - #pragma mark MVKDeviceObjectPool diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index ba3d9cb0..8f9bf488 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -169,6 +169,11 @@ void MVKPhysicalDevice::getFeatures(VkPhysicalDeviceFeatures2* features) { divisorFeatures->vertexAttributeInstanceRateZeroDivisor = true; break; } + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES_EXT: { + auto* privateDataFeatures = (VkPhysicalDevicePrivateDataFeaturesEXT*)next; + privateDataFeatures->privateData = true; + break; + } case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR: { auto* portabilityFeatures = (VkPhysicalDevicePortabilitySubsetFeaturesKHR*)next; portabilityFeatures->constantAlphaColorBlendFactors = true; @@ -2886,6 +2891,47 @@ void MVKDevice::freeMemory(MVKDeviceMemory* mvkDevMem, if (mvkDevMem) { mvkDevMem->destroy(); } } +// Look for an available pre-reserved private data slot and return it's address if found. +// Otherwise create a new instance and return it. +VkResult MVKDevice::createPrivateDataSlot(const VkPrivateDataSlotCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkPrivateDataSlotEXT* pPrivateDataSlot) { + MVKPrivateDataSlot* mvkPDS = nullptr; + + size_t slotCnt = _privateDataSlots.size(); + for (size_t slotIdx = 0; slotIdx < slotCnt; slotIdx++) { + if ( _privateDataSlotsAvailability[slotIdx] ) { + _privateDataSlotsAvailability[slotIdx] = false; + mvkPDS = _privateDataSlots[slotIdx]; + break; + } + } + + if ( !mvkPDS ) { mvkPDS = new MVKPrivateDataSlot(this); } + + *pPrivateDataSlot = (VkPrivateDataSlotEXT)mvkPDS; + return VK_SUCCESS; +} + +// If the private data slot is one of the pre-reserved slots, clear it and mark it as available. +// Otherwise destroy it. +void MVKDevice::destroyPrivateDataSlot(VkPrivateDataSlotEXT privateDataSlot, + const VkAllocationCallbacks* pAllocator) { + + MVKPrivateDataSlot* mvkPDS = (MVKPrivateDataSlot*)privateDataSlot; + + size_t slotCnt = _privateDataSlots.size(); + for (size_t slotIdx = 0; slotIdx < slotCnt; slotIdx++) { + if (mvkPDS == _privateDataSlots[slotIdx]) { + mvkPDS->clearData(); + _privateDataSlotsAvailability[slotIdx] = true; + return; + } + } + + mvkPDS->destroy(); +} + #pragma mark Operations @@ -3077,6 +3123,7 @@ MVKDevice::MVKDevice(MVKPhysicalDevice* physicalDevice, const VkDeviceCreateInfo _enabledScalarLayoutFeatures(), _enabledTexelBuffAlignFeatures(), _enabledVtxAttrDivFeatures(), + _enabledPrivateDataFeatures(), _enabledPortabilityFeatures(), _enabledExtensions(this) { @@ -3085,6 +3132,8 @@ MVKDevice::MVKDevice(MVKPhysicalDevice* physicalDevice, const VkDeviceCreateInfo initPhysicalDevice(physicalDevice, pCreateInfo); enableFeatures(pCreateInfo); enableExtensions(pCreateInfo); + initQueues(pCreateInfo); + reservePrivateData(pCreateInfo); _globalVisibilityResultMTLBuffer = nil; _globalVisibilityQueryCount = 0; @@ -3093,8 +3142,6 @@ MVKDevice::MVKDevice(MVKPhysicalDevice* physicalDevice, const VkDeviceCreateInfo _commandResourceFactory = new MVKCommandResourceFactory(this); - initQueues(pCreateInfo); - if (getInstance()->_autoGPUCaptureScope == MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_DEVICE) { MTLCaptureManager *captureMgr = [MTLCaptureManager sharedCaptureManager]; if (!getInstance()->_autoGPUCaptureOutputFile.empty()) { @@ -3225,6 +3272,7 @@ void MVKDevice::enableFeatures(const VkDeviceCreateInfo* pCreateInfo) { mvkClear(&_enabledScalarLayoutFeatures); mvkClear(&_enabledTexelBuffAlignFeatures); mvkClear(&_enabledVtxAttrDivFeatures); + mvkClear(&_enabledPrivateDataFeatures); mvkClear(&_enabledPortabilityFeatures); // Fetch the available physical device features. @@ -3232,9 +3280,13 @@ void MVKDevice::enableFeatures(const VkDeviceCreateInfo* pCreateInfo) { pdPortabilityFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR; pdPortabilityFeatures.pNext = NULL; + VkPhysicalDevicePrivateDataFeaturesEXT pdPrivateDataFeatures; + pdPrivateDataFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES_EXT; + pdPrivateDataFeatures.pNext = &pdPortabilityFeatures; + VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT pdVtxAttrDivFeatures; pdVtxAttrDivFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT; - pdVtxAttrDivFeatures.pNext = &pdPortabilityFeatures; + pdVtxAttrDivFeatures.pNext = &pdPrivateDataFeatures; VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT pdTexelBuffAlignFeatures; pdTexelBuffAlignFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT; @@ -3375,6 +3427,13 @@ void MVKDevice::enableFeatures(const VkDeviceCreateInfo* pCreateInfo) { &pdVtxAttrDivFeatures.vertexAttributeInstanceRateDivisor, 2); break; } + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES_EXT: { + auto* requestedFeatures = (VkPhysicalDevicePrivateDataFeaturesEXT*)next; + enableFeatures(&_enabledPrivateDataFeatures.privateData, + &requestedFeatures->privateData, + &pdPrivateDataFeatures.privateData, 1); + break; + } case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR: { auto* requestedFeatures = (VkPhysicalDevicePortabilitySubsetFeaturesKHR*)next; enableFeatures(&_enabledPortabilityFeatures.constantAlphaColorBlendFactors, @@ -3428,6 +3487,28 @@ void MVKDevice::initQueues(const VkDeviceCreateInfo* pCreateInfo) { } } +void MVKDevice::reservePrivateData(const VkDeviceCreateInfo* pCreateInfo) { + size_t slotCnt = 0; + for (const auto* next = (const VkBaseInStructure*)pCreateInfo->pNext; next; next = next->pNext) { + switch (next->sType) { + case VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO_EXT: { + auto* pPDCreateInfo = (const VkDevicePrivateDataCreateInfoEXT*)next; + slotCnt += pPDCreateInfo->privateDataSlotRequestCount; + break; + } + default: + break; + } + } + + _privateDataSlots.reserve(slotCnt); + _privateDataSlotsAvailability.reserve(slotCnt); + for (uint32_t slotIdx = 0; slotIdx < slotCnt; slotIdx++) { + _privateDataSlots.push_back(new MVKPrivateDataSlot(this)); + _privateDataSlotsAvailability.push_back(true); + } +} + void MVKDevice::initMTLCompileOptions() { _mtlCompileOptions = [MTLCompileOptions new]; // retained _mtlCompileOptions.languageVersion = _pMetalFeatures->mslVersionEnum; @@ -3445,6 +3526,8 @@ MVKDevice::~MVKDevice() { if (getInstance()->_autoGPUCaptureScope == MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_DEVICE) { [[MTLCaptureManager sharedCaptureManager] stopCapture]; } + + mvkDestroyContainerContents(_privateDataSlots); } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm index e8d42d6a..9fa432cb 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm @@ -669,6 +669,10 @@ void MVKInstance::initProcAddrs() { ADD_DVC_EXT_ENTRY_POINT(vkCmdDebugMarkerInsertEXT, EXT_DEBUG_MARKER); ADD_DVC_EXT_ENTRY_POINT(vkGetRefreshCycleDurationGOOGLE, GOOGLE_DISPLAY_TIMING); ADD_DVC_EXT_ENTRY_POINT(vkGetPastPresentationTimingGOOGLE, GOOGLE_DISPLAY_TIMING); + ADD_DVC_EXT_ENTRY_POINT(vkCreatePrivateDataSlotEXT, EXT_PRIVATE_DATA); + ADD_DVC_EXT_ENTRY_POINT(vkDestroyPrivateDataSlotEXT, EXT_PRIVATE_DATA); + ADD_DVC_EXT_ENTRY_POINT(vkGetPrivateDataEXT, EXT_PRIVATE_DATA); + ADD_DVC_EXT_ENTRY_POINT(vkSetPrivateDataEXT, EXT_PRIVATE_DATA); } void MVKInstance::logVersions() { diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def index c770885b..2f812763 100644 --- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def +++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def @@ -88,6 +88,7 @@ MVK_EXTENSION(EXT_inline_uniform_block, EXT_INLINE_UNIFORM_BLOCK, DEVICE) MVK_EXTENSION(EXT_memory_budget, EXT_MEMORY_BUDGET, DEVICE) MVK_EXTENSION(EXT_metal_surface, EXT_METAL_SURFACE, INSTANCE) MVK_EXTENSION(EXT_post_depth_coverage, EXT_POST_DEPTH_COVERAGE, DEVICE) +MVK_EXTENSION(EXT_private_data, EXT_PRIVATE_DATA, DEVICE) MVK_EXTENSION(EXT_robustness2, EXT_ROBUSTNESS_2, DEVICE) MVK_EXTENSION(EXT_scalar_block_layout, EXT_SCALAR_BLOCK_LAYOUT, DEVICE) MVK_EXTENSION(EXT_shader_stencil_export, EXT_SHADER_STENCIL_EXPORT, DEVICE) diff --git a/MoltenVK/MoltenVK/Vulkan/vulkan.mm b/MoltenVK/MoltenVK/Vulkan/vulkan.mm index 1fecb88e..16b3a119 100644 --- a/MoltenVK/MoltenVK/Vulkan/vulkan.mm +++ b/MoltenVK/MoltenVK/Vulkan/vulkan.mm @@ -2934,6 +2934,7 @@ MVK_PUBLIC_SYMBOL VkResult vkGetRefreshCycleDurationGOOGLE( VkDevice device, VkSwapchainKHR swapchain, VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties) { + MVKTraceVulkanCallStart(); MVKSwapchain* mvkSwapchain = (MVKSwapchain*)swapchain; VkResult rslt = mvkSwapchain->getRefreshCycleDuration(pDisplayTimingProperties); @@ -2946,6 +2947,7 @@ MVK_PUBLIC_SYMBOL VkResult vkGetPastPresentationTimingGOOGLE( VkSwapchainKHR swapchain, uint32_t* pPresentationTimingCount, VkPastPresentationTimingGOOGLE* pPresentationTimings) { + MVKTraceVulkanCallStart(); MVKSwapchain* mvkSwapchain = (MVKSwapchain*)swapchain; VkResult rslt = mvkSwapchain->getPastPresentationTiming(pPresentationTimingCount, pPresentationTimings); @@ -2953,6 +2955,60 @@ MVK_PUBLIC_SYMBOL VkResult vkGetPastPresentationTimingGOOGLE( return rslt; } +#pragma mark - +#pragma mark VK_EXT_private_data extension + +MVK_PUBLIC_SYMBOL VkResult vkCreatePrivateDataSlotEXT( + VkDevice device, + const VkPrivateDataSlotCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkPrivateDataSlotEXT* pPrivateDataSlot) { + + MVKTraceVulkanCallStart(); + MVKDevice* mvkDev = MVKDevice::getMVKDevice(device); + VkResult rslt = mvkDev->createPrivateDataSlot(pCreateInfo, pAllocator, pPrivateDataSlot); + MVKTraceVulkanCallEnd(); + return rslt; +} + +MVK_PUBLIC_SYMBOL void vkDestroyPrivateDataSlotEXT( + VkDevice device, + VkPrivateDataSlotEXT privateDataSlot, + const VkAllocationCallbacks* pAllocator) { + + MVKTraceVulkanCallStart(); + MVKDevice* mvkDev = MVKDevice::getMVKDevice(device); + mvkDev->destroyPrivateDataSlot(privateDataSlot, pAllocator); + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_SYMBOL VkResult vkSetPrivateDataEXT( + VkDevice device, + VkObjectType objectType, + uint64_t objectHandle, + VkPrivateDataSlotEXT privateDataSlot, + uint64_t data) { + + MVKTraceVulkanCallStart(); + MVKPrivateDataSlot* mvkPDS = (MVKPrivateDataSlot*)privateDataSlot; + mvkPDS->setData(objectType, objectHandle, data); + MVKTraceVulkanCallEnd(); + return VK_SUCCESS; +} + +MVK_PUBLIC_SYMBOL void vkGetPrivateDataEXT( + VkDevice device, + VkObjectType objectType, + uint64_t objectHandle, + VkPrivateDataSlotEXT privateDataSlot, + uint64_t* pData) { + + MVKTraceVulkanCallStart(); + MVKPrivateDataSlot* mvkPDS = (MVKPrivateDataSlot*)privateDataSlot; + *pData = mvkPDS->getData(objectType, objectHandle); + MVKTraceVulkanCallEnd(); +} + #pragma mark - #pragma mark iOS & macOS surface extensions