Merge branch 'master' of https://github.com/KhronosGroup/MoltenVK
diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md
index d763dc3..3aabc51 100644
--- a/Docs/Whats_New.md
+++ b/Docs/Whats_New.md
@@ -19,7 +19,17 @@
Released TBD
- Add support for extensions:
+ - `VK_KHR_swapchain_mutable_format`
+ - `VK_KHR_uniform_buffer_standard_layout`
- `VK_EXT_metal_surface`
+ - `VK_EXT_post_depth_coverage`
+ - `VK_EXT_scalar_block_layout`
+ - `VK_EXT_shader_stencil_export`
+ - `VK_EXT_swapchain_colorspace`
+ - `VK_EXT_texel_buffer_alignment`
+ - `VK_AMD_shader_image_load_store_lod`
+ - `VK_AMD_shader_trinary_minmax`
+ - `VK_INTEL_shader_integer_functions2`
- For shaders created directly from MSL, set function name from
`VkPipelineShaderStageCreateInfo::pName`.
- On iOS GPU family 2 and earlier, support immutable depth-compare samplers
@@ -32,6 +42,9 @@
- Fix race condition between swapchain image destruction and presentation completion callback.
- Set Metal texture usage to allow texture copy via view.
- Fix memory leak in debug marker and debug utils labelling.
+- Fix issue with push constants used across multiple draw calls not being applied.
+- Fix crash when binding descriptor set to layout that has been destroyed and recreated.
+- Return error when `MVKImage` created as 1D attachment.
- Reduce use of autoreleased Obj-C objects, and ensure those remaining are
covered by deliberate autorelease pools.
- `vkCmdCopyImage()` support copying between compressed and uncompressed formats
@@ -75,7 +88,7 @@
- Fix tessellated indirect draws using wrong kernels to map parameters.
- Work around potential Metal bug with stage-in indirect buffers.
- Fix zero local threadgroup size in indirect tessellated rendering.
- - Fix [[attribute]] assignment for tessellation evaluation shaders.
+ - Fix `[[attribute]]` assignment for tessellation evaluation shaders.
- `VkSemaphore` optionally uses `MTLEvent`, if available and
`MVK_ALLOW_METAL_EVENTS` environment variable is enabled.
- Add `vkSetWorkgroupSizeMVK()` to set compute kernel workgroup size
@@ -100,7 +113,7 @@
- Fix unused attachments terminating loop early.
- Fix offset of buffer view relative to buffer offset within device memory.
- Guard against missing Metal pipeline states when pipeline compilation fails.
-- MVKBuffer: Force managed storage for linear textures on shared buffers.
+- `MVKBuffer`: Force managed storage for linear textures on shared buffers.
- Use device address space when decompressing DXT image data.
- Added missing `texelBufferTextureWidth` setting in `MVKComputePipeline::getMTLFunction()`.
- Fixes and consolidation of external library header references.
@@ -128,7 +141,7 @@
- MSL: Support Invariant qualifier on position.
- MSL: Support stencil export.
- Deal with case where a block is somehow emitted in a duplicated fashion.
- - Fix infinite loop when OpAtomic* temporaries are used in other blocks.
+ - Fix infinite loop when `OpAtomic*` temporaries are used in other blocks.
- Fix tests for device->constant address space change in MSL tessellation control shader generation.
- Accept SPIR-V 1.4 version.
@@ -272,7 +285,7 @@
- Allow default GPU Capture scope to be assigned to any queue in any queue family.
- VkPhysicalDevice: Correct some features and limits.
- Stop advertising atomic image support.
-- vkSetMTLTextureMVK() function retains texture object.
+- `vkSetMTLTextureMVK()` function retains texture object.
- Log to stderr instead of stdout.
- `fetchDependencies`: build `spirv-tools` when attached via symlink.
- Enhancements to `MVKVector`, and set appropriate inline sizing usages.
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm
index b8e106b..18fe127 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm
@@ -197,7 +197,7 @@
_offset = offset;
_pushConstants.resize(size);
- std::copy_n((char*)pValues, size, _pushConstants.begin());
+ std::copy_n((char*)pValues, size, _pushConstants.begin());
}
void MVKCmdPushConstants::encode(MVKCommandEncoder* cmdEncoder) {
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
index 35d6a02..641832e 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
@@ -170,9 +170,14 @@
}
}
+// At this point, I have been marked not-dirty, under the assumption that I will make changes to the encoder.
+// However, some of the paths below decide not to actually make any changes to the encoder. In that case,
+// I should remain dirty until I actually do make encoder changes.
void MVKPushConstantsCommandEncoderState::encodeImpl(uint32_t stage) {
if (_pushConstants.empty() ) { return; }
+ _isDirty = true; // Stay dirty until I actually decide to make a change to the encoder
+
switch (_shaderStage) {
case VK_SHADER_STAGE_VERTEX_BIT:
if (stage == (isTessellating() ? kMVKGraphicsStageVertex : kMVKGraphicsStageRasterization)) {
@@ -180,6 +185,7 @@
_pushConstants.data(),
_pushConstants.size(),
_mtlBufferIndex);
+ _isDirty = false; // Okay, I changed the encoder
}
break;
case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
@@ -188,6 +194,7 @@
_pushConstants.data(),
_pushConstants.size(),
_mtlBufferIndex);
+ _isDirty = false; // Okay, I changed the encoder
}
break;
case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
@@ -196,6 +203,7 @@
_pushConstants.data(),
_pushConstants.size(),
_mtlBufferIndex);
+ _isDirty = false; // Okay, I changed the encoder
}
break;
case VK_SHADER_STAGE_FRAGMENT_BIT:
@@ -204,6 +212,7 @@
_pushConstants.data(),
_pushConstants.size(),
_mtlBufferIndex);
+ _isDirty = false; // Okay, I changed the encoder
}
break;
case VK_SHADER_STAGE_COMPUTE_BIT:
@@ -211,6 +220,7 @@
_pushConstants.data(),
_pushConstants.size(),
_mtlBufferIndex);
+ _isDirty = false; // Okay, I changed the encoder
break;
default:
MVKAssert(false, "Unsupported shader stage: %d", _shaderStage);
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
index 90cf292..6bd5ae8 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
@@ -167,20 +167,25 @@
/** Returns true if this layout is for push descriptors only. */
bool isPushDescriptorLayout() const { return _isPushDescriptorLayout; }
- /** Constructs an instance for the specified device. */
MVKDescriptorSetLayout(MVKDevice* device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo);
+ ~MVKDescriptorSetLayout();
+
protected:
friend class MVKDescriptorSetLayoutBinding;
friend class MVKPipelineLayout;
friend class MVKDescriptorSet;
+ friend class MVKDescriptorPool;
void propogateDebugName() override {}
-
+ void addDescriptorPool(MVKDescriptorPool* mvkDescPool) { _descriptorPools.insert(mvkDescPool); }
+ void removeDescriptorPool(MVKDescriptorPool* mvkDescPool) { _descriptorPools.erase(mvkDescPool); }
+
MVKVectorInline<MVKDescriptorSetLayoutBinding, 8> _bindings;
std::unordered_map<uint32_t, uint32_t> _bindingToIndex;
MVKShaderResourceBinding _mtlResourceCounts;
+ std::unordered_set<MVKDescriptorPool*> _descriptorPools;
bool _isPushDescriptorLayout : 1;
};
@@ -357,6 +362,9 @@
/** Destoys all currently allocated descriptor sets. */
VkResult reset(VkDescriptorPoolResetFlags flags);
+ /** Removes the pool associated with a descriptor set layout. */
+ void removeDescriptorSetPool(MVKDescriptorSetLayout* mvkDescSetLayout);
+
/** Constructs an instance for the specified device. */
MVKDescriptorPool(MVKDevice* device, const VkDescriptorPoolCreateInfo* pCreateInfo);
@@ -366,6 +374,7 @@
protected:
void propogateDebugName() override {}
MVKDescriptorSetPool* getDescriptorSetPool(MVKDescriptorSetLayout* mvkDescSetLayout);
+ void returnDescriptorSet(MVKDescriptorSet* mvkDescSet);
uint32_t _maxSets;
std::unordered_set<MVKDescriptorSet*> _allocatedSets;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
index 1396bac..1f97ac0 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
@@ -652,6 +652,10 @@
}
}
+MVKDescriptorSetLayout::~MVKDescriptorSetLayout() {
+ for (auto& dsPool : _descriptorPools) { dsPool->removeDescriptorSetPool(this); }
+}
+
#pragma mark -
#pragma mark MVKDescriptorBinding
@@ -1021,41 +1025,66 @@
VkResult MVKDescriptorPool::freeDescriptorSets(uint32_t count, const VkDescriptorSet* pDescriptorSets) {
for (uint32_t dsIdx = 0; dsIdx < count; dsIdx++) {
MVKDescriptorSet* mvkDS = (MVKDescriptorSet*)pDescriptorSets[dsIdx];
- if (_allocatedSets.erase(mvkDS)) {
- getDescriptorSetPool(mvkDS->_pLayout)->returnObject(mvkDS);
- }
+ if (_allocatedSets.erase(mvkDS)) { returnDescriptorSet(mvkDS); }
}
return VK_SUCCESS;
}
// Return any allocated descriptor sets to their pools
VkResult MVKDescriptorPool::reset(VkDescriptorPoolResetFlags flags) {
- for (auto& mvkDS : _allocatedSets) {
- getDescriptorSetPool(mvkDS->_pLayout)->returnObject(mvkDS);
- }
+ for (auto& mvkDS : _allocatedSets) { returnDescriptorSet(mvkDS); }
_allocatedSets.clear();
return VK_SUCCESS;
}
+// Returns the descriptor set to its pool, or if that pool doesn't exist, the descriptor set is destroyed
+void MVKDescriptorPool::returnDescriptorSet(MVKDescriptorSet* mvkDescSet) {
+ MVKDescriptorSetLayout* dsLayout = mvkDescSet->_pLayout;
+ MVKDescriptorSetPool* dsPool = dsLayout ? _descriptorSetPools[dsLayout] : nullptr;
+ if (dsPool) {
+ dsPool->returnObject(mvkDescSet);
+ } else {
+ mvkDescSet->destroy();
+ _descriptorSetPools.erase(dsLayout);
+ }
+}
+
// Returns the pool of descriptor sets that use a specific layout, lazily creating it if necessary
MVKDescriptorSetPool* MVKDescriptorPool::getDescriptorSetPool(MVKDescriptorSetLayout* mvkDescSetLayout) {
MVKDescriptorSetPool* dsp = _descriptorSetPools[mvkDescSetLayout];
if ( !dsp ) {
dsp = new MVKDescriptorSetPool(_device);
_descriptorSetPools[mvkDescSetLayout] = dsp;
+ mvkDescSetLayout->addDescriptorPool(this); // tell layout to track me
}
return dsp;
}
+// Remove the descriptor set pool associated with the descriptor set layout,
+// and make sure any allocated sets don't try to return back to their pools.
+void MVKDescriptorPool::removeDescriptorSetPool(MVKDescriptorSetLayout* mvkDescSetLayout) {
+ MVKDescriptorSetPool* dsp = _descriptorSetPools[mvkDescSetLayout];
+ if (dsp) { dsp->destroy(); }
+ _descriptorSetPools.erase(mvkDescSetLayout);
+
+ for (auto& mvkDS : _allocatedSets) {
+ if (mvkDS->_pLayout == mvkDescSetLayout) { mvkDS->_pLayout = nullptr; }
+ }
+}
+
MVKDescriptorPool::MVKDescriptorPool(MVKDevice* device,
const VkDescriptorPoolCreateInfo* pCreateInfo) : MVKVulkanAPIDeviceObject(device) {
_maxSets = pCreateInfo->maxSets;
}
-// Return any allocated sets to their pools and then destroy all the pools.
+// Return any allocated sets to their pools and then destroy all the pools,
+// and ensure any descriptor set layouts used as keys are notified.
MVKDescriptorPool::~MVKDescriptorPool() {
reset(0);
- for (auto& pair : _descriptorSetPools) { pair.second->destroy(); }
+ for (auto& pair : _descriptorSetPools) {
+ pair.first->removeDescriptorPool(this);
+ if (pair.second) { pair.second->destroy(); }
+ }
}
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h
index 2c03080..0cbf0d0 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h
@@ -237,10 +237,10 @@
void propogateDebugName() override;
MVKImageSubresource* getSubresource(uint32_t mipLevel, uint32_t arrayLayer);
- void validateConfig(const VkImageCreateInfo* pCreateInfo);
- VkSampleCountFlagBits validateSamples(const VkImageCreateInfo* pCreateInfo);
- uint32_t validateMipLevels(const VkImageCreateInfo* pCreateInfo);
- bool validateLinear(const VkImageCreateInfo* pCreateInfo);
+ void validateConfig(const VkImageCreateInfo* pCreateInfo, bool isAttachment);
+ VkSampleCountFlagBits validateSamples(const VkImageCreateInfo* pCreateInfo, bool isAttachment);
+ uint32_t validateMipLevels(const VkImageCreateInfo* pCreateInfo, bool isAttachment);
+ bool validateLinear(const VkImageCreateInfo* pCreateInfo, bool isAttachment);
bool validateUseTexelBuffer();
void initSubresources(const VkImageCreateInfo* pCreateInfo);
void initSubresourceLayout(MVKImageSubresource& imgSubRez);
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
index 9204962..be2240a 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
@@ -607,10 +607,14 @@
_arrayLayers = max(pCreateInfo->arrayLayers, minDim);
// Perform validation and adjustments before configuring other settings
- validateConfig(pCreateInfo);
- _samples = validateSamples(pCreateInfo);
- _mipLevels = validateMipLevels(pCreateInfo);
- _isLinear = validateLinear(pCreateInfo);
+ bool isAttachment = mvkIsAnyFlagEnabled(pCreateInfo->usage, (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
+ VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
+ VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT |
+ VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT));
+ validateConfig(pCreateInfo, isAttachment);
+ _samples = validateSamples(pCreateInfo, isAttachment);
+ _mipLevels = validateMipLevels(pCreateInfo, isAttachment);
+ _isLinear = validateLinear(pCreateInfo, isAttachment);
_mtlPixelFormat = getMTLPixelFormatFromVkFormat(pCreateInfo->format);
_mtlTextureType = mvkMTLTextureTypeFromVkImageType(pCreateInfo->imageType, _arrayLayers, _samples > VK_SAMPLE_COUNT_1_BIT);
@@ -631,7 +635,7 @@
initSubresources(pCreateInfo);
}
-void MVKImage::validateConfig(const VkImageCreateInfo* pCreateInfo) {
+void MVKImage::validateConfig(const VkImageCreateInfo* pCreateInfo, bool isAttachment) {
bool is2D = pCreateInfo->imageType == VK_IMAGE_TYPE_2D;
bool isCompressed = mvkFormatTypeFromVkFormat(pCreateInfo->format) == kMVKFormatCompressed;
@@ -650,18 +654,18 @@
if ((mvkFormatTypeFromVkFormat(pCreateInfo->format) == kMVKFormatDepthStencil) && !is2D ) {
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : Under Metal, depth/stencil formats may only be used with 2D images."));
}
-
- bool isAttachment = mvkIsAnyFlagEnabled(pCreateInfo->usage, (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT));
if (isAttachment && (pCreateInfo->arrayLayers > 1) && !_device->_pMetalFeatures->layeredRendering) {
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : This device does not support rendering to array (layered) attachments."));
}
-
+ if (isAttachment && (pCreateInfo->imageType == VK_IMAGE_TYPE_1D)) {
+ setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : This device does not support rendering to 1D attachments."));
+ }
if (mvkIsAnyFlagEnabled(pCreateInfo->flags, VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT)) {
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : Metal does not allow uncompressed views of compressed images."));
}
}
-VkSampleCountFlagBits MVKImage::validateSamples(const VkImageCreateInfo* pCreateInfo) {
+VkSampleCountFlagBits MVKImage::validateSamples(const VkImageCreateInfo* pCreateInfo, bool isAttachment) {
VkSampleCountFlagBits validSamples = pCreateInfo->samples;
@@ -682,8 +686,6 @@
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : This device does not support multisampled array textures. Setting sample count to 1."));
validSamples = VK_SAMPLE_COUNT_1_BIT;
}
-
- bool isAttachment = mvkIsAnyFlagEnabled(pCreateInfo->usage, (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT));
if (isAttachment && !_device->_pMetalFeatures->multisampleLayeredRendering) {
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : This device does not support rendering to multisampled array (layered) attachments. Setting sample count to 1."));
validSamples = VK_SAMPLE_COUNT_1_BIT;
@@ -693,7 +695,7 @@
return validSamples;
}
-uint32_t MVKImage::validateMipLevels(const VkImageCreateInfo* pCreateInfo) {
+uint32_t MVKImage::validateMipLevels(const VkImageCreateInfo* pCreateInfo, bool isAttachment) {
uint32_t minDim = 1;
uint32_t validMipLevels = max(pCreateInfo->mipLevels, minDim);
@@ -707,7 +709,7 @@
return validMipLevels;
}
-bool MVKImage::validateLinear(const VkImageCreateInfo* pCreateInfo) {
+bool MVKImage::validateLinear(const VkImageCreateInfo* pCreateInfo, bool isAttachment) {
if (pCreateInfo->tiling != VK_IMAGE_TILING_LINEAR ) { return false; }
@@ -739,8 +741,8 @@
}
#if MVK_MACOS
- if ( mvkIsAnyFlagEnabled(pCreateInfo->usage, (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)) ) {
- setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : If tiling is VK_IMAGE_TILING_LINEAR, usage must not include VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, or VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT."));
+ if (isAttachment) {
+ setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : This device does not support rendering to linear (VK_IMAGE_TILING_LINEAR) images."));
isLin = false;
}
#endif
@@ -929,10 +931,10 @@
if (pCreateInfo->subresourceRange.layerCount != image->_extent.depth) {
reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImageView(): Metal does not fully support views on a subset of a 3D texture.");
}
- if (!mvkAreAllFlagsEnabled(_usage, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)) {
- setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImageView(): 2D views on 3D images are only supported for color attachments."));
- } else if (mvkIsAnyFlagEnabled(_usage, ~VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)) {
- reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImageView(): 2D views on 3D images are only supported for color attachments.");
+ if ( !mvkIsAnyFlagEnabled(_usage, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) ) {
+ setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImageView(): 2D views on 3D images can only be used as color attachments."));
+ } else if (mvkIsOnlyAnyFlagEnabled(_usage, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)) {
+ reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImageView(): 2D views on 3D images can only be used as color attachments.");
}
}
}