Add support for VK_EXT_private_data extension.
Moved to a new model for creation: create and potentially destroy the object
within MVKDevice::create..., to hide it from vulkan.mm where all other object
creation errors are handled. We could move to this slowly over time.
Passes all 49 private data CTS tests.
diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md
index f1fc211..7c83f6b 100644
--- a/Docs/MoltenVK_Runtime_UserGuide.md
+++ b/Docs/MoltenVK_Runtime_UserGuide.md
@@ -310,6 +310,7 @@
- `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 36fe387..e404d3a 100644
--- a/Docs/Whats_New.md
+++ b/Docs/Whats_New.md
@@ -18,6 +18,8 @@
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 3fd9fbd..1af11db 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
@@ -66,6 +66,7 @@
class MVKCommandPool;
class MVKCommandEncoder;
class MVKCommandResourceFactory;
+class MVKPrivateDataSlot;
/** The buffer index to use for vertex content. */
@@ -578,6 +579,13 @@
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 @@
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 @@
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 @@
MTLCompileOptions* _mtlCompileOptions;
MVKSmallVector<MVKSmallVector<MVKQueue*, kMVKQueueCountPerQueueFamily>, kMVKQueueFamilyCount> _queuesByQueueFamilyIndex;
MVKSmallVector<MVKResource*, 256> _resources;
+ MVKSmallVector<MVKPrivateDataSlot*> _privateDataSlots;
+ MVKSmallVector<bool> _privateDataSlotsAvailability;
std::mutex _rezLock;
std::mutex _perfLock;
id<MTLBuffer> _globalVisibilityResultMTLBuffer;
@@ -820,6 +832,35 @@
#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<uint64_t, uint64_t> _privateData;
+};
+
+
+#pragma mark -
#pragma mark MVKDeviceObjectPool
/** Manages a pool of instances of a particular object type that requires an MVKDevice during construction. */
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
index ba3d9cb..8f9bf48 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
@@ -169,6 +169,11 @@
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 @@
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 @@
_enabledScalarLayoutFeatures(),
_enabledTexelBuffAlignFeatures(),
_enabledVtxAttrDivFeatures(),
+ _enabledPrivateDataFeatures(),
_enabledPortabilityFeatures(),
_enabledExtensions(this)
{
@@ -3085,6 +3132,8 @@
initPhysicalDevice(physicalDevice, pCreateInfo);
enableFeatures(pCreateInfo);
enableExtensions(pCreateInfo);
+ initQueues(pCreateInfo);
+ reservePrivateData(pCreateInfo);
_globalVisibilityResultMTLBuffer = nil;
_globalVisibilityQueryCount = 0;
@@ -3093,8 +3142,6 @@
_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 @@
mvkClear(&_enabledScalarLayoutFeatures);
mvkClear(&_enabledTexelBuffAlignFeatures);
mvkClear(&_enabledVtxAttrDivFeatures);
+ mvkClear(&_enabledPrivateDataFeatures);
mvkClear(&_enabledPortabilityFeatures);
// Fetch the available physical device features.
@@ -3232,9 +3280,13 @@
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 @@
&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::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 @@
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 e8d42d6..9fa432c 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm
@@ -669,6 +669,10 @@
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 c770885..2f81276 100644
--- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def
+++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def
@@ -88,6 +88,7 @@
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 1fecb88..16b3a11 100644
--- a/MoltenVK/MoltenVK/Vulkan/vulkan.mm
+++ b/MoltenVK/MoltenVK/Vulkan/vulkan.mm
@@ -2934,6 +2934,7 @@
VkDevice device,
VkSwapchainKHR swapchain,
VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties) {
+
MVKTraceVulkanCallStart();
MVKSwapchain* mvkSwapchain = (MVKSwapchain*)swapchain;
VkResult rslt = mvkSwapchain->getRefreshCycleDuration(pDisplayTimingProperties);
@@ -2946,6 +2947,7 @@
VkSwapchainKHR swapchain,
uint32_t* pPresentationTimingCount,
VkPastPresentationTimingGOOGLE* pPresentationTimings) {
+
MVKTraceVulkanCallStart();
MVKSwapchain* mvkSwapchain = (MVKSwapchain*)swapchain;
VkResult rslt = mvkSwapchain->getPastPresentationTiming(pPresentationTimingCount, pPresentationTimings);
@@ -2954,6 +2956,60 @@
}
#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
MVK_PUBLIC_SYMBOL VkResult vkCreate_PLATFORM_SurfaceMVK(