Commit 02d4c0d3 by Chris Forbes

Add support for multiview rendering

This is a mandatory feature for 1.1, but Vulkan CTS 1.1.3 doesn't enforce that -- it only tests the feature if it is present. Highlights: - Multiple views implemented by running each draw multiple times. We could do something more efficient, but this is a fringe feature so far. - Render targets and input attachments are adjusted to use the layer corresponding to the current view. - Explicit attachment clears and end-of-subpass resolves are broadcast to the layers corresponding to the current subpass's view mask. - Renderpass attachment load ops are executed for the layers corresponding to the union of the subpass view masks for all subpasses which use the attachment. The actual load ops are still performed together at the beginning of the renderpass. - ViewIndex builtin variable is exposed to the shaders. In a non-multiview draw call, ViewIndex is still available, but is always zero. Bug: b/139862810 Test: dEQP-VK.*multiview* Change-Id: Iaf40cfdb2f5afa61253cc756f97c0db30fb4d813 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/35408 Kokoro-Presubmit: kokoro <noreply+kokoro@google.com> Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com> Tested-by: 's avatarChris Forbes <chrisforbes@google.com>
parent 23742c09
......@@ -96,6 +96,7 @@ namespace sw
// Instancing
int instanceID;
int viewID;
bool occlusionEnabled;
......
......@@ -348,11 +348,8 @@ namespace sw
}
data->indices = context->indexBuffer;
if(context->vertexShader->hasBuiltinInput(spv::BuiltInInstanceIndex))
{
data->instanceID = context->instanceID;
}
data->viewID = context->viewID;
data->instanceID = context->instanceID;
data->baseVertex = baseVertex;
......@@ -426,7 +423,7 @@ namespace sw
if(draw->renderTarget[index])
{
data->colorBuffer[index] = (unsigned int*)context->renderTarget[index]->getOffsetPointer({0, 0, 0}, VK_IMAGE_ASPECT_COLOR_BIT, 0, 0);
data->colorBuffer[index] = (unsigned int*)context->renderTarget[index]->getOffsetPointer({0, 0, 0}, VK_IMAGE_ASPECT_COLOR_BIT, 0, data->viewID);
data->colorPitchB[index] = context->renderTarget[index]->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0);
data->colorSliceB[index] = context->renderTarget[index]->slicePitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0);
}
......@@ -437,14 +434,14 @@ namespace sw
if(draw->depthBuffer)
{
data->depthBuffer = (float*)context->depthBuffer->getOffsetPointer({0, 0, 0}, VK_IMAGE_ASPECT_DEPTH_BIT, 0, 0);
data->depthBuffer = (float*)context->depthBuffer->getOffsetPointer({0, 0, 0}, VK_IMAGE_ASPECT_DEPTH_BIT, 0, data->viewID);
data->depthPitchB = context->depthBuffer->rowPitchBytes(VK_IMAGE_ASPECT_DEPTH_BIT, 0);
data->depthSliceB = context->depthBuffer->slicePitchBytes(VK_IMAGE_ASPECT_DEPTH_BIT, 0);
}
if(draw->stencilBuffer)
{
data->stencilBuffer = (unsigned char*)context->stencilBuffer->getOffsetPointer({0, 0, 0}, VK_IMAGE_ASPECT_STENCIL_BIT, 0, 0);
data->stencilBuffer = (unsigned char*)context->stencilBuffer->getOffsetPointer({0, 0, 0}, VK_IMAGE_ASPECT_STENCIL_BIT, 0, data->viewID);
data->stencilPitchB = context->stencilBuffer->rowPitchBytes(VK_IMAGE_ASPECT_STENCIL_BIT, 0);
data->stencilSliceB = context->stencilBuffer->slicePitchBytes(VK_IMAGE_ASPECT_STENCIL_BIT, 0);
}
......
......@@ -60,6 +60,7 @@ namespace sw
int instanceID;
int baseVertex;
float lineWidth;
int viewID;
PixelProcessor::Stencil stencil[2]; // clockwise, counterclockwise
PixelProcessor::Factor factor;
......
......@@ -24,6 +24,12 @@ namespace sw
{
routine.setImmutableInputBuiltins(spirvShader);
routine.setInputBuiltin(spirvShader, spv::BuiltInViewIndex, [&](const SpirvShader::BuiltinMapping& builtin, Array<SIMD::Float>& value)
{
assert(builtin.SizeInComponents == 1);
value[builtin.FirstComponent] = As<Float4>(Int4((*Pointer<Int>(data + OFFSET(DrawData, viewID)))));
});
routine.setInputBuiltin(spirvShader, spv::BuiltInFragCoord, [&](const SpirvShader::BuiltinMapping& builtin, Array<SIMD::Float>& value)
{
assert(builtin.SizeInComponents == 4);
......@@ -50,6 +56,7 @@ namespace sw
routine.windowSpacePosition[0] = x + SIMD::Int(0,1,0,1);
routine.windowSpacePosition[1] = y + SIMD::Int(0,0,1,1);
routine.viewID = *Pointer<Int>(data + OFFSET(DrawData, viewID));
}
void PixelProgram::applyShader(Int cMask[4])
......
......@@ -1131,6 +1131,7 @@ namespace sw
if (!strcmp(ext, "SPV_KHR_16bit_storage")) break;
if (!strcmp(ext, "SPV_KHR_variable_pointers")) break;
if (!strcmp(ext, "SPV_KHR_device_group")) break;
if (!strcmp(ext, "SPV_KHR_multiview")) break;
UNSUPPORTED("SPIR-V Extension: %s", ext);
break;
}
......@@ -5325,6 +5326,12 @@ namespace sw
ptr += coordinate.Int(dims) * slicePitch;
}
if (dim == spv::DimSubpassData)
{
// Multiview input attachment access is to the layer corresponding to the current view
ptr += SIMD::Int(routine->viewID) * slicePitch;
}
if (sampleId.value())
{
GenericValue sample(this, state, sampleId);
......
......@@ -1299,6 +1299,7 @@ namespace sw
Pointer<Byte> constants;
Int killMask = Int{0};
SIMD::Int windowSpacePosition[2];
Int viewID; // slice offset into input attachments for multiview, even if the shader doesn't use ViewIndex
void createVariable(SpirvShader::Object::ID id, uint32_t size)
{
......
......@@ -34,6 +34,12 @@ namespace sw
{
routine.setImmutableInputBuiltins(spirvShader);
routine.setInputBuiltin(spirvShader, spv::BuiltInViewIndex, [&](const SpirvShader::BuiltinMapping& builtin, Array<SIMD::Float>& value)
{
assert(builtin.SizeInComponents == 1);
value[builtin.FirstComponent] = As<Float4>(Int4((*Pointer<Int>(data + OFFSET(DrawData, viewID)))));
});
routine.setInputBuiltin(spirvShader, spv::BuiltInInstanceIndex, [&](const SpirvShader::BuiltinMapping& builtin, Array<SIMD::Float>& value)
{
// TODO: we could do better here; we know InstanceIndex is uniform across all lanes
......
......@@ -515,7 +515,7 @@ struct DrawBase : public CommandBuffer::Command
{
auto const &pipelineState = executionState.pipelineState[VK_PIPELINE_BIND_POINT_GRAPHICS];
GraphicsPipeline* pipeline = static_cast<GraphicsPipeline*>(pipelineState.pipeline);
GraphicsPipeline *pipeline = static_cast<GraphicsPipeline *>(pipelineState.pipeline);
sw::Context context = pipeline->getContext();
......@@ -527,12 +527,13 @@ struct DrawBase : public CommandBuffer::Command
// Apply either pipeline state or dynamic state
executionState.renderer->setScissor(pipeline->hasDynamicState(VK_DYNAMIC_STATE_SCISSOR) ?
executionState.dynamicState.scissor : pipeline->getScissor());
executionState.dynamicState.scissor : pipeline->getScissor());
executionState.renderer->setViewport(pipeline->hasDynamicState(VK_DYNAMIC_STATE_VIEWPORT) ?
executionState.dynamicState.viewport : pipeline->getViewport());
executionState.dynamicState.viewport : pipeline->getViewport());
executionState.renderer->setBlendConstant(pipeline->hasDynamicState(VK_DYNAMIC_STATE_BLEND_CONSTANTS) ?
executionState.dynamicState.blendConstants : pipeline->getBlendConstants());
if(pipeline->hasDynamicState(VK_DYNAMIC_STATE_DEPTH_BIAS))
executionState.dynamicState.blendConstants
: pipeline->getBlendConstants());
if (pipeline->hasDynamicState(VK_DYNAMIC_STATE_DEPTH_BIAS))
{
// If the depth bias clamping feature is not enabled, depthBiasClamp must be 0.0
ASSERT(executionState.dynamicState.depthBiasClamp == 0.0f);
......@@ -540,25 +541,27 @@ struct DrawBase : public CommandBuffer::Command
context.depthBias = executionState.dynamicState.depthBiasConstantFactor;
context.slopeDepthBias = executionState.dynamicState.depthBiasSlopeFactor;
}
if(pipeline->hasDynamicState(VK_DYNAMIC_STATE_DEPTH_BOUNDS) && context.depthBoundsTestEnable)
if (pipeline->hasDynamicState(VK_DYNAMIC_STATE_DEPTH_BOUNDS) && context.depthBoundsTestEnable)
{
// Unless the VK_EXT_depth_range_unrestricted extension is enabled minDepthBounds and maxDepthBounds must be between 0.0 and 1.0, inclusive
ASSERT(executionState.dynamicState.minDepthBounds >= 0.0f && executionState.dynamicState.minDepthBounds <= 1.0f);
ASSERT(executionState.dynamicState.maxDepthBounds >= 0.0f && executionState.dynamicState.maxDepthBounds <= 1.0f);
ASSERT(executionState.dynamicState.minDepthBounds >= 0.0f &&
executionState.dynamicState.minDepthBounds <= 1.0f);
ASSERT(executionState.dynamicState.maxDepthBounds >= 0.0f &&
executionState.dynamicState.maxDepthBounds <= 1.0f);
UNIMPLEMENTED("depthBoundsTestEnable");
}
if(pipeline->hasDynamicState(VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK) && context.stencilEnable)
if (pipeline->hasDynamicState(VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK) && context.stencilEnable)
{
context.frontStencil.compareMask = executionState.dynamicState.compareMask[0];
context.backStencil.compareMask = executionState.dynamicState.compareMask[1];
}
if(pipeline->hasDynamicState(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK) && context.stencilEnable)
if (pipeline->hasDynamicState(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK) && context.stencilEnable)
{
context.frontStencil.writeMask = executionState.dynamicState.writeMask[0];
context.backStencil.writeMask = executionState.dynamicState.writeMask[1];
}
if(pipeline->hasDynamicState(VK_DYNAMIC_STATE_STENCIL_REFERENCE) && context.stencilEnable)
if (pipeline->hasDynamicState(VK_DYNAMIC_STATE_STENCIL_REFERENCE) && context.stencilEnable)
{
context.frontStencil.reference = executionState.dynamicState.reference[0];
context.backStencil.reference = executionState.dynamicState.reference[1];
......@@ -566,23 +569,23 @@ struct DrawBase : public CommandBuffer::Command
executionState.bindAttachments(context);
context.multiSampleMask = context.sampleMask & ((unsigned)0xFFFFFFFF >> (32 - context.sampleCount));
context.multiSampleMask = context.sampleMask & ((unsigned) 0xFFFFFFFF >> (32 - context.sampleCount));
context.occlusionEnabled = executionState.renderer->hasOcclusionQuery();
std::vector<std::pair<uint32_t, void*>> indexBuffers;
if(indexed)
std::vector<std::pair<uint32_t, void *>> indexBuffers;
if (indexed)
{
void* indexBuffer = executionState.indexBufferBinding.buffer->getOffsetPointer(
executionState.indexBufferBinding.offset + first * bytesPerIndex(executionState));
if(pipeline->hasPrimitiveRestartEnable())
void *indexBuffer = executionState.indexBufferBinding.buffer->getOffsetPointer(
executionState.indexBufferBinding.offset + first * bytesPerIndex(executionState));
if (pipeline->hasPrimitiveRestartEnable())
{
switch(executionState.indexType)
switch (executionState.indexType)
{
case VK_INDEX_TYPE_UINT16:
processPrimitiveRestart(static_cast<uint16_t*>(indexBuffer), count, pipeline, indexBuffers);
processPrimitiveRestart(static_cast<uint16_t *>(indexBuffer), count, pipeline, indexBuffers);
break;
case VK_INDEX_TYPE_UINT32:
processPrimitiveRestart(static_cast<uint32_t*>(indexBuffer), count, pipeline, indexBuffers);
processPrimitiveRestart(static_cast<uint32_t *>(indexBuffer), count, pipeline, indexBuffers);
break;
default:
UNIMPLEMENTED("executionState.indexType %d", int(executionState.indexType));
......@@ -590,23 +593,32 @@ struct DrawBase : public CommandBuffer::Command
}
else
{
indexBuffers.push_back({ pipeline->computePrimitiveCount(count), indexBuffer });
indexBuffers.push_back({pipeline->computePrimitiveCount(count), indexBuffer});
}
}
else
{
indexBuffers.push_back({ pipeline->computePrimitiveCount(count), nullptr });
indexBuffers.push_back({pipeline->computePrimitiveCount(count), nullptr});
}
for(uint32_t instance = firstInstance; instance != firstInstance + instanceCount; instance++)
for (uint32_t instance = firstInstance; instance != firstInstance + instanceCount; instance++)
{
context.instanceID = instance;
for(auto indexBuffer : indexBuffers)
// FIXME: reconsider instances/views nesting.
auto viewMask = executionState.renderPass->getViewMask();
while (viewMask)
{
const uint32_t primitiveCount = indexBuffer.first;
context.indexBuffer = indexBuffer.second;
executionState.renderer->draw(&context, executionState.indexType, primitiveCount, vertexOffset, executionState.events);
context.viewID = sw::log2i(viewMask);
viewMask &= ~(1 << context.viewID);
for (auto indexBuffer : indexBuffers)
{
const uint32_t primitiveCount = indexBuffer.first;
context.indexBuffer = indexBuffer.second;
executionState.renderer->draw(&context, executionState.indexType, primitiveCount, vertexOffset,
executionState.events);
}
}
executionState.renderer->advanceInstanceAttributes(context.input);
......
......@@ -17,6 +17,7 @@
#include "VkRenderPass.hpp"
#include <algorithm>
#include <memory.h>
#include <System/Math.hpp>
namespace vk
{
......@@ -60,15 +61,38 @@ void Framebuffer::clear(const RenderPass* renderPass, uint32_t clearValueCount,
if(clearDepth || clearStencil)
{
attachments[i]->clear(pClearValues[i],
(clearDepth ? VK_IMAGE_ASPECT_DEPTH_BIT : 0) |
(clearStencil ? VK_IMAGE_ASPECT_STENCIL_BIT : 0),
renderArea);
auto aspectMask = (clearDepth ? VK_IMAGE_ASPECT_DEPTH_BIT : 0) |
(clearStencil ? VK_IMAGE_ASPECT_STENCIL_BIT : 0);
if (renderPass->isMultiView())
{
auto viewMask = renderPass->getAttachmentViewMask(i);
while (viewMask)
{
uint32_t view = sw::log2i(viewMask);
viewMask &= ~(1 << view);
VkClearRect r{renderArea, view, 1};
attachments[i]->clear(pClearValues[i], aspectMask, r);
}
}
else
attachments[i]->clear(pClearValues[i], aspectMask, renderArea);
}
}
else if(attachment.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR)
{
attachments[i]->clear(pClearValues[i], VK_IMAGE_ASPECT_COLOR_BIT, renderArea);
if (renderPass->isMultiView())
{
auto viewMask = renderPass->getAttachmentViewMask(i);
while (viewMask)
{
uint32_t view = sw::log2i(viewMask);
viewMask &= ~(1 << view);
VkClearRect r{renderArea, view, 1};
attachments[i]->clear(pClearValues[i], VK_IMAGE_ASPECT_COLOR_BIT, r);
}
}
else
attachments[i]->clear(pClearValues[i], VK_IMAGE_ASPECT_COLOR_BIT, renderArea);
}
}
}
......@@ -84,8 +108,21 @@ void Framebuffer::clear(const RenderPass* renderPass, const VkClearAttachment& a
ASSERT(attachment.colorAttachment < subpass.colorAttachmentCount);
ASSERT(subpass.pColorAttachments[attachment.colorAttachment].attachment < attachmentCount);
attachments[subpass.pColorAttachments[attachment.colorAttachment].attachment]->clear(
attachment.clearValue, attachment.aspectMask, rect);
if (renderPass->isMultiView())
{
auto viewMask = renderPass->getViewMask();
while (viewMask)
{
int view = sw::log2i(viewMask);
viewMask &= ~(1 << view);
VkClearRect r = rect;
r.baseArrayLayer = view;
attachments[subpass.pColorAttachments[attachment.colorAttachment].attachment]->clear(attachment.clearValue, attachment.aspectMask, r);
}
}
else
attachments[subpass.pColorAttachments[attachment.colorAttachment].attachment]->clear(
attachment.clearValue, attachment.aspectMask, rect);
}
}
else if(attachment.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT))
......@@ -94,7 +131,20 @@ void Framebuffer::clear(const RenderPass* renderPass, const VkClearAttachment& a
ASSERT(subpass.pDepthStencilAttachment->attachment < attachmentCount);
attachments[subpass.pDepthStencilAttachment->attachment]->clear(attachment.clearValue, attachment.aspectMask, rect);
if (renderPass->isMultiView())
{
auto viewMask = renderPass->getViewMask();
while (viewMask)
{
int view = sw::log2i(viewMask);
viewMask &= ~(1 << view);
VkClearRect r = rect;
r.baseArrayLayer = view;
attachments[subpass.pDepthStencilAttachment->attachment]->clear(attachment.clearValue, attachment.aspectMask, r);
}
}
else
attachments[subpass.pDepthStencilAttachment->attachment]->clear(attachment.clearValue, attachment.aspectMask, rect);
}
}
......@@ -113,7 +163,20 @@ void Framebuffer::resolve(const RenderPass* renderPass)
uint32_t resolveAttachment = subpass.pResolveAttachments[i].attachment;
if(resolveAttachment != VK_ATTACHMENT_UNUSED)
{
attachments[subpass.pColorAttachments[i].attachment]->resolve(attachments[resolveAttachment]);
if (renderPass->isMultiView())
{
auto viewMask = renderPass->getViewMask();
while (viewMask)
{
int view = sw::log2i(viewMask);
viewMask &= ~(1 << view);
attachments[subpass.pColorAttachments[i].attachment]->resolve(attachments[resolveAttachment], view);
}
}
else
{
attachments[subpass.pColorAttachments[i].attachment]->resolve(attachments[resolveAttachment]);
}
}
}
}
......
......@@ -154,6 +154,36 @@ void ImageView::clear(const VkClearValue& clearValue, const VkImageAspectFlags a
image->clear(clearValue, format, renderArea.rect, sr);
}
void ImageView::resolve(ImageView* resolveAttachment, int layer)
{
if((subresourceRange.levelCount != 1) || (resolveAttachment->subresourceRange.levelCount != 1))
{
UNIMPLEMENTED("levelCount");
}
VkImageCopy region;
region.srcSubresource =
{
subresourceRange.aspectMask,
subresourceRange.baseMipLevel,
subresourceRange.baseArrayLayer + layer,
1
};
region.srcOffset = { 0, 0, 0 };
region.dstSubresource =
{
resolveAttachment->subresourceRange.aspectMask,
resolveAttachment->subresourceRange.baseMipLevel,
resolveAttachment->subresourceRange.baseArrayLayer + layer,
1
};
region.dstOffset = { 0, 0, 0 };
region.extent = image->getMipLevelExtent(static_cast<VkImageAspectFlagBits>(subresourceRange.aspectMask),
subresourceRange.baseMipLevel);
image->copyTo(resolveAttachment->image, region);
}
void ImageView::resolve(ImageView* resolveAttachment)
{
if((subresourceRange.levelCount != 1) || (resolveAttachment->subresourceRange.levelCount != 1))
......
......@@ -42,6 +42,7 @@ public:
void clear(const VkClearValue& clearValues, VkImageAspectFlags aspectMask, const VkRect2D& renderArea);
void clear(const VkClearValue& clearValue, VkImageAspectFlags aspectMask, const VkClearRect& renderArea);
void resolve(ImageView* resolveAttachment);
void resolve(ImageView* resolveAttachment, int layer);
VkImageViewType getType() const { return viewType; }
Format getFormat(Usage usage = RAW) const;
......
......@@ -119,7 +119,7 @@ void PhysicalDevice::getFeatures(VkPhysicalDevice8BitStorageFeaturesKHR* feature
void PhysicalDevice::getFeatures(VkPhysicalDeviceMultiviewFeatures* features) const
{
features->multiview = VK_FALSE;
features->multiview = VK_TRUE;
features->multiviewGeometryShader = VK_FALSE;
features->multiviewTessellationShader = VK_FALSE;
}
......@@ -295,8 +295,8 @@ void PhysicalDevice::getProperties(VkPhysicalDeviceMaintenance3Properties* prope
void PhysicalDevice::getProperties(VkPhysicalDeviceMultiviewProperties* properties) const
{
properties->maxMultiviewViewCount = 0;
properties->maxMultiviewInstanceIndex = 0;
properties->maxMultiviewViewCount = 6;
properties->maxMultiviewInstanceIndex = 1u<<27;
}
void PhysicalDevice::getProperties(VkPhysicalDevicePointClippingProperties* properties) const
......
......@@ -15,15 +15,6 @@
#include "VkRenderPass.hpp"
#include <cstring>
namespace
{
void MarkFirstUse(int& attachment, int subpass)
{
if (attachment == -1)
attachment = subpass;
}
}
namespace vk
{
......@@ -41,6 +32,8 @@ RenderPass::RenderPass(const VkRenderPassCreateInfo* pCreateInfo, void* mem) :
subpasses = reinterpret_cast<VkSubpassDescription*>(hostMemory);
memcpy(subpasses, pCreateInfo->pSubpasses, subpassesSize);
hostMemory += subpassesSize;
uint32_t *masks = reinterpret_cast<uint32_t *>(hostMemory);
hostMemory += pCreateInfo->subpassCount * sizeof(uint32_t);
if(pCreateInfo->attachmentCount > 0)
{
......@@ -51,9 +44,43 @@ RenderPass::RenderPass(const VkRenderPassCreateInfo* pCreateInfo, void* mem) :
size_t firstUseSize = pCreateInfo->attachmentCount * sizeof(int);
attachmentFirstUse = reinterpret_cast<int*>(hostMemory);
hostMemory += firstUseSize;
attachmentViewMasks = reinterpret_cast<uint32_t *>(hostMemory);
hostMemory += pCreateInfo->attachmentCount * sizeof(uint32_t);
for (auto i = 0u; i < pCreateInfo->attachmentCount; i++)
{
attachmentFirstUse[i] = -1;
hostMemory += firstUseSize;
attachmentViewMasks[i] = 0;
}
}
const VkBaseInStructure* extensionCreateInfo = reinterpret_cast<const VkBaseInStructure*>(pCreateInfo->pNext);
while (extensionCreateInfo)
{
switch (extensionCreateInfo->sType)
{
case VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO:
{
// Renderpass uses multiview if this structure is present AND some subpass specifies
// a nonzero view mask
auto const *multiviewCreateInfo = reinterpret_cast<VkRenderPassMultiviewCreateInfo const *>(extensionCreateInfo);
for (auto i = 0u; i < pCreateInfo->subpassCount; i++)
{
masks[i] = multiviewCreateInfo->pViewMasks[i];
// This is now a multiview renderpass, so make the masks available
if (masks[i])
viewMasks = masks;
}
break;
}
default:
/* Unknown structure in pNext chain must be ignored */
break;
}
extensionCreateInfo = extensionCreateInfo->pNext;
}
// Deep copy subpasses
......@@ -77,7 +104,7 @@ RenderPass::RenderPass(const VkRenderPassCreateInfo* pCreateInfo, void* mem) :
for (auto j = 0u; j < subpasses[i].inputAttachmentCount; j++)
{
if (subpass.pInputAttachments[j].attachment != VK_ATTACHMENT_UNUSED)
MarkFirstUse(attachmentFirstUse[subpass.pInputAttachments[j].attachment], i);
MarkFirstUse(subpass.pInputAttachments[j].attachment, i);
}
}
......@@ -100,10 +127,10 @@ RenderPass::RenderPass(const VkRenderPassCreateInfo* pCreateInfo, void* mem) :
for (auto j = 0u; j < subpasses[i].colorAttachmentCount; j++)
{
if (subpass.pColorAttachments[j].attachment != VK_ATTACHMENT_UNUSED)
MarkFirstUse(attachmentFirstUse[subpass.pColorAttachments[j].attachment], i);
MarkFirstUse(subpass.pColorAttachments[j].attachment, i);
if (subpass.pResolveAttachments &&
subpass.pResolveAttachments[j].attachment != VK_ATTACHMENT_UNUSED)
MarkFirstUse(attachmentFirstUse[subpass.pResolveAttachments[j].attachment], i);
MarkFirstUse(subpass.pResolveAttachments[j].attachment, i);
}
}
......@@ -115,7 +142,7 @@ RenderPass::RenderPass(const VkRenderPassCreateInfo* pCreateInfo, void* mem) :
hostMemory += sizeof(VkAttachmentReference);
if (subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED)
MarkFirstUse(attachmentFirstUse[subpass.pDepthStencilAttachment->attachment], i);
MarkFirstUse(subpass.pDepthStencilAttachment->attachment, i);
}
if(subpass.preserveAttachmentCount > 0)
......@@ -129,7 +156,7 @@ RenderPass::RenderPass(const VkRenderPassCreateInfo* pCreateInfo, void* mem) :
for (auto j = 0u; j < subpasses[i].preserveAttachmentCount; j++)
{
if (subpass.pPreserveAttachments[j] != VK_ATTACHMENT_UNUSED)
MarkFirstUse(attachmentFirstUse[subpass.pPreserveAttachments[j]], i);
MarkFirstUse(subpass.pPreserveAttachments[j], i);
}
}
}
......@@ -150,7 +177,8 @@ void RenderPass::destroy(const VkAllocationCallbacks* pAllocator)
size_t RenderPass::ComputeRequiredAllocationSize(const VkRenderPassCreateInfo* pCreateInfo)
{
size_t attachmentSize = pCreateInfo->attachmentCount * sizeof(VkAttachmentDescription)
+ pCreateInfo->attachmentCount * sizeof(int);
+ pCreateInfo->attachmentCount * sizeof(int) // first use
+ pCreateInfo->attachmentCount * sizeof(uint32_t); // union of subpass view masks, per attachment
size_t subpassesSize = 0;
for(uint32_t i = 0; i < pCreateInfo->subpassCount; ++i)
{
......@@ -166,7 +194,8 @@ size_t RenderPass::ComputeRequiredAllocationSize(const VkRenderPassCreateInfo* p
}
subpassesSize += sizeof(VkSubpassDescription) +
sizeof(VkAttachmentReference) * nbAttachments +
sizeof(uint32_t) * subpass.preserveAttachmentCount;
sizeof(uint32_t) * subpass.preserveAttachmentCount +
sizeof(uint32_t); // view mask
}
size_t dependenciesSize = pCreateInfo->dependencyCount * sizeof(VkSubpassDependency);
......@@ -195,4 +224,16 @@ void RenderPass::end()
currentSubpass = 0;
}
void RenderPass::MarkFirstUse(int attachment, int subpass)
{
// FIXME: we may not actually need to track attachmentFirstUse if we're going to eagerly
// clear attachments at the start of the renderpass; can use attachmentViewMasks always instead.
if (attachmentFirstUse[attachment] == -1)
attachmentFirstUse[attachment] = subpass;
if (isMultiView())
attachmentViewMasks[attachment] |= viewMasks[subpass];
}
} // namespace vk
\ No newline at end of file
......@@ -76,6 +76,21 @@ public:
return attachmentFirstUse[i] >= 0;
}
uint32_t getViewMask() const
{
return viewMasks ? viewMasks[currentSubpass] : 1;
}
bool isMultiView() const
{
return viewMasks != nullptr;
}
uint32_t getAttachmentViewMask(uint32_t i) const
{
return attachmentViewMasks[i];
}
private:
uint32_t attachmentCount = 0;
VkAttachmentDescription* attachments = nullptr;
......@@ -85,6 +100,10 @@ private:
VkSubpassDependency* dependencies = nullptr;
uint32_t currentSubpass = 0;
int* attachmentFirstUse = nullptr;
uint32_t* viewMasks = nullptr;
uint32_t* attachmentViewMasks = nullptr;
void MarkFirstUse(int attachment, int subpass);
};
static inline RenderPass* Cast(VkRenderPass object)
......
......@@ -511,8 +511,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice(VkPhysicalDevice physicalDevice, c
{
const VkPhysicalDeviceMultiviewFeatures* multiviewFeatures = reinterpret_cast<const VkPhysicalDeviceMultiviewFeatures*>(extensionCreateInfo);
if (multiviewFeatures->multiview ||
multiviewFeatures->multiviewGeometryShader ||
if (multiviewFeatures->multiviewGeometryShader ||
multiviewFeatures->multiviewTessellationShader)
{
return VK_ERROR_FEATURE_NOT_PRESENT;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment