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:
parent
102037491a
commit
a723dc1f21
@ -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`
|
||||
|
@ -50,6 +50,7 @@ protected:
|
||||
MVKFramebuffer* _framebuffer;
|
||||
VkRect2D _renderArea;
|
||||
VkSubpassContents _contents;
|
||||
MVKSmallVector<MVKImageView*, 8> _imagelessAttachments;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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>;
|
||||
|
@ -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;
|
||||
|
@ -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); }
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user