Support the VK_KHR_imageless_framebuffer extension.

I'm not sure this is the elegant way but it works in my own
project:)
This commit is contained in:
UnsafeBy 2021-05-28 23:28:20 +08:00
parent 102037491a
commit a723dc1f21
12 changed files with 100 additions and 19 deletions

View File

@ -273,6 +273,7 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll
- `VK_KHR_get_memory_requirements2`
- `VK_KHR_get_physical_device_properties2`
- `VK_KHR_get_surface_capabilities2`
- `VK_KHR_imageless_framebuffer`
- `VK_KHR_image_format_list`
- `VK_KHR_maintenance1`
- `VK_KHR_maintenance2`

View File

@ -50,6 +50,7 @@ protected:
MVKFramebuffer* _framebuffer;
VkRect2D _renderArea;
VkSubpassContents _contents;
MVKSmallVector<MVKImageView*, 8> _imagelessAttachments;
};

View File

@ -36,6 +36,20 @@ VkResult MVKCmdBeginRenderPassBase::setContent(MVKCommandBuffer* cmdBuff,
_framebuffer = (MVKFramebuffer*)pRenderPassBegin->framebuffer;
_renderArea = pRenderPassBegin->renderArea;
for (auto* next = (const VkBaseInStructure*)pRenderPassBegin->pNext; next; next = next->pNext) {
switch (next->sType) {
case VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO: {
const auto* pAttachmentBegin = (VkRenderPassAttachmentBeginInfo*)next;
for(uint32_t i = 0; i < pAttachmentBegin->attachmentCount; i++) {
_imagelessAttachments.push_back((MVKImageView*)pAttachmentBegin->pAttachments[i]);
}
break;
}
default:
break;
}
}
return VK_SUCCESS;
}
@ -70,7 +84,7 @@ VkResult MVKCmdBeginRenderPass<N>::setContent(MVKCommandBuffer* cmdBuff,
template <size_t N>
void MVKCmdBeginRenderPass<N>::encode(MVKCommandEncoder* cmdEncoder) {
// MVKLogDebug("Encoding vkCmdBeginRenderPass(). Elapsed time: %.6f ms.", mvkGetElapsedMilliseconds());
cmdEncoder->beginRenderpass(this, _contents, _renderPass, _framebuffer, _renderArea, _clearValues.contents());
cmdEncoder->beginRenderpass(this, _contents, _renderPass, _framebuffer, _renderArea, _clearValues.contents(), _imagelessAttachments.contents());
}
template class MVKCmdBeginRenderPass<1>;

View File

@ -275,7 +275,8 @@ public:
MVKRenderPass* renderPass,
MVKFramebuffer* framebuffer,
VkRect2D& renderArea,
MVKArrayRef<VkClearValue> clearValues);
MVKArrayRef<VkClearValue> clearValues,
MVKArrayRef<MVKImageView*> imageless_attachments);
/** Begins the next render subpass. */
void beginNextSubpass(MVKCommand* subpassCmd, VkSubpassContents renderpassContents);
@ -494,6 +495,7 @@ protected:
VkRect2D _renderArea;
MVKActivatedQueries* _pActivatedQueries;
MVKSmallVector<VkClearValue, kMVKDefaultAttachmentCount> _clearValues;
MVKSmallVector<MVKImageView*, kMVKDefaultAttachmentCount> _imagelessAttachments;
id<MTLComputeCommandEncoder> _mtlComputeEncoder;
MVKCommandUse _mtlComputeEncoderUse;
id<MTLBlitCommandEncoder> _mtlBlitEncoder;

View File

@ -288,13 +288,17 @@ void MVKCommandEncoder::beginRenderpass(MVKCommand* passCmd,
MVKRenderPass* renderPass,
MVKFramebuffer* framebuffer,
VkRect2D& renderArea,
MVKArrayRef<VkClearValue> clearValues) {
MVKArrayRef<VkClearValue> clearValues,
MVKArrayRef<MVKImageView*> imagelessAttachments) {
_renderPass = renderPass;
_framebuffer = framebuffer;
_renderArea = renderArea;
_isRenderingEntireAttachment = (mvkVkOffset2DsAreEqual(_renderArea.offset, {0,0}) &&
mvkVkExtent2DsAreEqual(_renderArea.extent, _framebuffer->getExtent2D()));
_clearValues.assign(clearValues.begin(), clearValues.end());
for(auto* v : imagelessAttachments) {
_imagelessAttachments.push_back(v);
}
setSubpass(passCmd, subpassContents, 0);
}
@ -334,7 +338,7 @@ void MVKCommandEncoder::beginMetalRenderPass(bool loadOverride) {
endCurrentMetalEncoding();
MTLRenderPassDescriptor* mtlRPDesc = [MTLRenderPassDescriptor renderPassDescriptor];
getSubpass()->populateMTLRenderPassDescriptor(mtlRPDesc, _multiviewPassIndex, _framebuffer, _clearValues.contents(), _isRenderingEntireAttachment, loadOverride);
getSubpass()->populateMTLRenderPassDescriptor(mtlRPDesc, _multiviewPassIndex, _framebuffer, _imagelessAttachments.contents(), _clearValues.contents(), _isRenderingEntireAttachment, loadOverride);
if (_cmdBuffer->_needsVisibilityResultMTLBuffer) {
if (!_visibilityResultMTLBuffer) {
_visibilityResultMTLBuffer = getTempMTLBuffer(_pDeviceMetalFeatures->maxQueryBufferSize, true, true);
@ -393,7 +397,10 @@ void MVKCommandEncoder::beginMetalRenderPass(bool loadOverride) {
}
void MVKCommandEncoder::encodeStoreActions(bool storeOverride) {
getSubpass()->encodeStoreActions(this, _isRenderingEntireAttachment, storeOverride);
getSubpass()->encodeStoreActions(this,
_isRenderingEntireAttachment,
_imagelessAttachments.contents(),
storeOverride);
}
MVKRenderSubpass* MVKCommandEncoder::getSubpass() { return _renderPass->getSubpass(_renderSubpassIndex); }

View File

@ -738,6 +738,7 @@ public:
const VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT _enabledTexelBuffAlignFeatures;
const VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT _enabledVtxAttrDivFeatures;
const VkPhysicalDevicePortabilitySubsetFeaturesKHR _enabledPortabilityFeatures;
const VkPhysicalDeviceImagelessFramebufferFeaturesKHR _enabledImagelessFramebufferFeatures;
/** The list of Vulkan extensions, indicating whether each has been enabled by the app for this device. */
const MVKExtensionList _enabledExtensions;

View File

@ -267,6 +267,11 @@ void MVKPhysicalDevice::getFeatures(VkPhysicalDeviceFeatures2* features) {
inlineUniformBlockFeatures->descriptorBindingInlineUniformBlockUpdateAfterBind = true;
break;
}
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES: {
auto* imagelessFramebufferFeatures = (VkPhysicalDeviceImagelessFramebufferFeaturesKHR*)next;
imagelessFramebufferFeatures->imagelessFramebuffer = true;
break;
}
default:
break;
}
@ -3789,6 +3794,7 @@ MVKDevice::MVKDevice(MVKPhysicalDevice* physicalDevice, const VkDeviceCreateInfo
_enabledVtxAttrDivFeatures(),
_enabledPrivateDataFeatures(),
_enabledPortabilityFeatures(),
_enabledImagelessFramebufferFeatures(),
_enabledExtensions(this),
_isCurrentlyAutoGPUCapturing(false)
{
@ -3899,11 +3905,16 @@ void MVKDevice::enableFeatures(const VkDeviceCreateInfo* pCreateInfo) {
mvkClear(&_enabledTexelBuffAlignFeatures);
mvkClear(&_enabledVtxAttrDivFeatures);
mvkClear(&_enabledPortabilityFeatures);
mvkClear(&_enabledImagelessFramebufferFeatures);
VkPhysicalDeviceImagelessFramebufferFeaturesKHR pdImagelessFramebufferFeatures;
pdImagelessFramebufferFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES;
pdImagelessFramebufferFeatures.pNext = NULL;
// Fetch the available physical device features.
VkPhysicalDevicePortabilitySubsetFeaturesKHR pdPortabilityFeatures;
pdPortabilityFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR;
pdPortabilityFeatures.pNext = NULL;
pdPortabilityFeatures.pNext = &pdImagelessFramebufferFeatures;
VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT pdVtxAttrDivFeatures;
pdVtxAttrDivFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT;
@ -4088,6 +4099,13 @@ void MVKDevice::enableFeatures(const VkDeviceCreateInfo* pCreateInfo) {
&pdPortabilityFeatures.constantAlphaColorBlendFactors, 15);
break;
}
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES: {
auto* requestedFeatures = (VkPhysicalDeviceImagelessFramebufferFeaturesKHR*)next;
enableFeatures(&_enabledImagelessFramebufferFeatures.imagelessFramebuffer,
&requestedFeatures->imagelessFramebuffer,
&pdImagelessFramebufferFeatures.imagelessFramebuffer, 1);
break;
}
default:
break;
}

View File

@ -45,6 +45,7 @@ public:
/** Returns the attachment at the specified index. */
inline MVKImageView* getAttachment(uint32_t index) { return _attachments[index]; }
inline bool getImageless() { return _imageless; }
#pragma mark Construction
@ -57,5 +58,7 @@ protected:
VkExtent2D _extent;
uint32_t _layerCount;
MVKSmallVector<MVKImageView*, 4> _attachments;
bool _imageless;
MVKSmallVector<MVKImageView*, 4> _imagelessAttachments;
};

View File

@ -28,10 +28,15 @@ MVKFramebuffer::MVKFramebuffer(MVKDevice* device,
_extent = { .width = pCreateInfo->width, .height = pCreateInfo->height };
_layerCount = pCreateInfo->layers;
// Add attachments
_attachments.reserve(pCreateInfo->attachmentCount);
for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) {
_attachments.push_back((MVKImageView*)pCreateInfo->pAttachments[i]);
if (pCreateInfo->flags & VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT_KHR) {
_imageless = true;
}
else {
_imageless = false;
// Add attachments
_attachments.reserve(pCreateInfo->attachmentCount);
for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) {
_attachments.push_back((MVKImageView*)pCreateInfo->pAttachments[i]);
}
}
}

View File

@ -96,6 +96,7 @@ public:
void populateMTLRenderPassDescriptor(MTLRenderPassDescriptor* mtlRPDesc,
uint32_t passIdx,
MVKFramebuffer* framebuffer,
const MVKArrayRef<MVKImageView*>& imagelessAttachments,
const MVKArrayRef<VkClearValue>& clearValues,
bool isRenderingEntireAttachment,
bool loadOverride = false);
@ -117,7 +118,10 @@ public:
uint32_t caIdx, VkImageAspectFlags aspectMask);
/** If a render encoder is active, sets the store actions for all attachments to it. */
void encodeStoreActions(MVKCommandEncoder* cmdEncoder, bool isRenderingEntireAttachment, bool storeOverride = false);
void encodeStoreActions(MVKCommandEncoder* cmdEncoder,
bool isRenderingEntireAttachment,
const MVKArrayRef<MVKImageView*>& imagelessAttachments,
bool storeOverride = false);
/** Constructs an instance for the specified parent renderpass. */
MVKRenderSubpass(MVKRenderPass* renderPass, const VkSubpassDescription* pCreateInfo,

View File

@ -176,10 +176,12 @@ uint32_t MVKRenderSubpass::getViewCountUpToMetalPass(uint32_t passIdx) const {
void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor* mtlRPDesc,
uint32_t passIdx,
MVKFramebuffer* framebuffer,
const MVKArrayRef<MVKImageView*>& imagelessAttachments,
const MVKArrayRef<VkClearValue>& clearValues,
bool isRenderingEntireAttachment,
bool loadOverride) {
MVKPixelFormats* pixFmts = _renderPass->getPixelFormats();
bool imageless = framebuffer->getImageless();
// Populate the Metal color attachments
uint32_t caCnt = getColorAttachmentCount();
@ -195,7 +197,13 @@ void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor*
uint32_t rslvRPAttIdx = _resolveAttachments.empty() ? VK_ATTACHMENT_UNUSED : _resolveAttachments[caIdx].attachment;
bool hasResolveAttachment = (rslvRPAttIdx != VK_ATTACHMENT_UNUSED);
if (hasResolveAttachment) {
framebuffer->getAttachment(rslvRPAttIdx)->populateMTLRenderPassAttachmentDescriptorResolve(mtlColorAttDesc);
if (imageless) {
imagelessAttachments[rslvRPAttIdx]->populateMTLRenderPassAttachmentDescriptorResolve(mtlColorAttDesc);
}
else {
framebuffer->getAttachment(rslvRPAttIdx)->populateMTLRenderPassAttachmentDescriptorResolve(mtlColorAttDesc);
}
// In a multiview render pass, we need to override the starting layer to ensure
// only the enabled views are loaded.
if (isMultiview()) {
@ -209,10 +217,17 @@ void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor*
// Configure the color attachment
MVKRenderPassAttachment* clrMVKRPAtt = &_renderPass->_attachments[clrRPAttIdx];
framebuffer->getAttachment(clrRPAttIdx)->populateMTLRenderPassAttachmentDescriptor(mtlColorAttDesc);
if (imageless) {
imagelessAttachments[clrRPAttIdx]->populateMTLRenderPassAttachmentDescriptor(mtlColorAttDesc);
}
else {
framebuffer->getAttachment(clrRPAttIdx)->populateMTLRenderPassAttachmentDescriptor(mtlColorAttDesc);
}
bool isMemorylessAttachment = false;
#if MVK_APPLE_SILICON
isMemorylessAttachment = framebuffer->getAttachment(clrRPAttIdx)->getMTLTexture(0).storageMode == MTLStorageModeMemoryless;
isMemorylessAttachment = imageless
? imagelessAttachments[clrRPAttIdx]->getMTLTexture(0).storageMode == MTLStorageModeMemoryless
: framebuffer->getAttachment(clrRPAttIdx)->getMTLTexture(0).storageMode == MTLStorageModeMemoryless;
#endif
if (clrMVKRPAtt->populateMTLRenderPassAttachmentDescriptor(mtlColorAttDesc, this,
isRenderingEntireAttachment,
@ -236,12 +251,16 @@ void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor*
uint32_t dsRslvRPAttIdx = _depthStencilResolveAttachment.attachment;
if (dsRPAttIdx != VK_ATTACHMENT_UNUSED) {
MVKRenderPassAttachment* dsMVKRPAtt = &_renderPass->_attachments[dsRPAttIdx];
MVKImageView* dsImage = framebuffer->getAttachment(dsRPAttIdx);
MVKImageView* dsImage = imageless
? imagelessAttachments[dsRPAttIdx]
: framebuffer->getAttachment(dsRPAttIdx);
MVKImageView* dsRslvImage = nullptr;
MTLPixelFormat mtlDSFormat = dsImage->getMTLPixelFormat(0);
if (dsRslvRPAttIdx != VK_ATTACHMENT_UNUSED) {
dsRslvImage = framebuffer->getAttachment(dsRslvRPAttIdx);
dsRslvImage = imageless
? imagelessAttachments[dsRslvRPAttIdx]
: framebuffer->getAttachment(dsRslvRPAttIdx);
}
if (pixFmts->isDepthFormat(mtlDSFormat)) {
@ -366,6 +385,7 @@ void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor*
void MVKRenderSubpass::encodeStoreActions(MVKCommandEncoder* cmdEncoder,
bool isRenderingEntireAttachment,
const MVKArrayRef<MVKImageView*>& imagelessAttachments,
bool storeOverride) {
if (!cmdEncoder->_mtlRenderEncoder) { return; }
if (!_renderPass->getDevice()->_pMetalFeatures->deferredStoreActions) { return; }
@ -377,7 +397,9 @@ void MVKRenderSubpass::encodeStoreActions(MVKCommandEncoder* cmdEncoder,
bool hasResolveAttachment = _resolveAttachments.empty() ? false : _resolveAttachments[caIdx].attachment != VK_ATTACHMENT_UNUSED;
bool isMemorylessAttachment = false;
#if MVK_APPLE_SILICON
isMemorylessAttachment = cmdEncoder->_framebuffer->getAttachment(clrRPAttIdx)->getMTLTexture(0).storageMode == MTLStorageModeMemoryless;
isMemorylessAttachment = cmdEncoder->_framebuffer->getImageless()
? imagelessAttachments[clrRPAttIdx]->getMTLTexture(0).storageMode == MTLStorageModeMemoryless
: cmdEncoder->_framebuffer->getAttachment(clrRPAttIdx)->getMTLTexture(0).storageMode == MTLStorageModeMemoryless;
#endif
_renderPass->_attachments[clrRPAttIdx].encodeStoreAction(cmdEncoder, this, isRenderingEntireAttachment, isMemorylessAttachment, hasResolveAttachment, caIdx, false, storeOverride);
}
@ -389,7 +411,9 @@ void MVKRenderSubpass::encodeStoreActions(MVKCommandEncoder* cmdEncoder,
bool hasStencilResolveAttachment = hasResolveAttachment && _stencilResolveMode != VK_RESOLVE_MODE_NONE;
bool isMemorylessAttachment = false;
#if MVK_APPLE_SILICON
isMemorylessAttachment = cmdEncoder->_framebuffer->getAttachment(dsRPAttIdx)->getMTLTexture(0).storageMode == MTLStorageModeMemoryless;
isMemorylessAttachment = cmdEncoder->_framebuffer->getImageless()
? imagelessAttachments[dsRPAttIdx]->getMTLTexture(0).storageMode == MTLStorageModeMemoryless
: cmdEncoder->_framebuffer->getAttachment(dsRPAttIdx)->getMTLTexture(0).storageMode == MTLStorageModeMemoryless;
#endif
_renderPass->_attachments[dsRPAttIdx].encodeStoreAction(cmdEncoder, this, isRenderingEntireAttachment, isMemorylessAttachment, hasDepthResolveAttachment, 0, false, storeOverride);
_renderPass->_attachments[dsRPAttIdx].encodeStoreAction(cmdEncoder, this, isRenderingEntireAttachment, isMemorylessAttachment, hasStencilResolveAttachment, 0, true, storeOverride);

View File

@ -58,6 +58,7 @@ MVK_EXTENSION(KHR_external_semaphore_capabilities, KHR_EXTERNAL_SEMAPHORE_CAPABI
MVK_EXTENSION(KHR_get_memory_requirements2, KHR_GET_MEMORY_REQUIREMENTS_2, DEVICE)
MVK_EXTENSION(KHR_get_physical_device_properties2, KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2, INSTANCE)
MVK_EXTENSION(KHR_get_surface_capabilities2, KHR_GET_SURFACE_CAPABILITIES_2, INSTANCE)
MVK_EXTENSION(KHR_imageless_framebuffer, KHR_IMAGELESS_FRAMEBUFFER, DEVICE)
MVK_EXTENSION(KHR_image_format_list, KHR_IMAGE_FORMAT_LIST, DEVICE)
MVK_EXTENSION(KHR_maintenance1, KHR_MAINTENANCE1, DEVICE)
MVK_EXTENSION(KHR_maintenance2, KHR_MAINTENANCE2, DEVICE)