Add support for stencil buffer on Vulkan and D3D11/D3D12
This commit is contained in:
@@ -72,55 +72,19 @@ const Char* ToString(VkImageLayout layout)
|
||||
|
||||
#endif
|
||||
|
||||
void PipelineBarrierVulkan::AddImageBarrier(VkImage image, const VkImageSubresourceRange& range, VkImageLayout srcLayout, VkImageLayout dstLayout, GPUTextureViewVulkan* handle)
|
||||
{
|
||||
#if VK_ENABLE_BARRIERS_DEBUG
|
||||
ImageBarriersDebug.Add(handle);
|
||||
#endif
|
||||
VkImageMemoryBarrier& imageBarrier = ImageBarriers.AddOne();
|
||||
RenderToolsVulkan::ZeroStruct(imageBarrier, VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER);
|
||||
imageBarrier.image = image;
|
||||
imageBarrier.subresourceRange = range;
|
||||
imageBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
imageBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
imageBarrier.oldLayout = srcLayout;
|
||||
imageBarrier.newLayout = dstLayout;
|
||||
SourceStage |= RenderToolsVulkan::GetImageBarrierFlags(srcLayout, imageBarrier.srcAccessMask);
|
||||
DestStage |= RenderToolsVulkan::GetImageBarrierFlags(dstLayout, imageBarrier.dstAccessMask);
|
||||
#if VK_ENABLE_BARRIERS_DEBUG
|
||||
LOG(Warning, "Image Barrier: 0x{0:x}, {1} -> {2} for baseMipLevel: {3}, baseArrayLayer: {4}, levelCount: {5}, layerCount: {6} ({7})",
|
||||
(uintptr)image,
|
||||
ToString(srcLayout),
|
||||
ToString(dstLayout),
|
||||
range.baseMipLevel,
|
||||
range.baseArrayLayer,
|
||||
range.levelCount,
|
||||
range.layerCount,
|
||||
handle && handle->Owner->AsGPUResource() ? handle->Owner->AsGPUResource()->ToString() : String::Empty
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
void PipelineBarrierVulkan::AddBufferBarrier(VkBuffer buffer, VkDeviceSize offset, VkDeviceSize size, VkAccessFlags srcAccess, VkAccessFlags dstAccess)
|
||||
{
|
||||
VkBufferMemoryBarrier& bufferBarrier = BufferBarriers.AddOne();
|
||||
RenderToolsVulkan::ZeroStruct(bufferBarrier, VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER);
|
||||
bufferBarrier.buffer = buffer;
|
||||
bufferBarrier.offset = offset;
|
||||
bufferBarrier.size = size;
|
||||
bufferBarrier.srcAccessMask = srcAccess;
|
||||
bufferBarrier.dstAccessMask = dstAccess;
|
||||
bufferBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
bufferBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
SourceStage |= RenderToolsVulkan::GetBufferBarrierFlags(srcAccess);
|
||||
DestStage |= RenderToolsVulkan::GetBufferBarrierFlags(dstAccess);
|
||||
}
|
||||
|
||||
void PipelineBarrierVulkan::Execute(CmdBufferVulkan* cmdBuffer)
|
||||
void PipelineBarrierVulkan::Execute(const CmdBufferVulkan* cmdBuffer)
|
||||
{
|
||||
ASSERT(cmdBuffer->IsOutsideRenderPass());
|
||||
vkCmdPipelineBarrier(cmdBuffer->GetHandle(), SourceStage, DestStage, 0, 0, nullptr, BufferBarriers.Count(), BufferBarriers.Get(), ImageBarriers.Count(), ImageBarriers.Get());
|
||||
Reset();
|
||||
|
||||
// Reset
|
||||
SourceStage = 0;
|
||||
DestStage = 0;
|
||||
ImageBarriers.Clear();
|
||||
BufferBarriers.Clear();
|
||||
#if VK_ENABLE_BARRIERS_DEBUG
|
||||
ImageBarriersDebug.Clear();
|
||||
#endif
|
||||
}
|
||||
|
||||
GPUContextVulkan::GPUContextVulkan(GPUDeviceVulkan* device, QueueVulkan* queue)
|
||||
@@ -154,7 +118,7 @@ GPUContextVulkan::~GPUContextVulkan()
|
||||
Delete(_cmdBufferManager);
|
||||
}
|
||||
|
||||
void GPUContextVulkan::AddImageBarrier(VkImage image, VkImageLayout srcLayout, VkImageLayout dstLayout, VkImageSubresourceRange& subresourceRange, GPUTextureViewVulkan* handle)
|
||||
void GPUContextVulkan::AddImageBarrier(VkImage image, VkImageLayout srcLayout, VkImageLayout dstLayout, const VkImageSubresourceRange& subresourceRange, GPUTextureViewVulkan* handle)
|
||||
{
|
||||
#if VK_ENABLE_BARRIERS_BATCHING
|
||||
// Auto-flush on overflow
|
||||
@@ -168,7 +132,31 @@ void GPUContextVulkan::AddImageBarrier(VkImage image, VkImageLayout srcLayout, V
|
||||
#endif
|
||||
|
||||
// Insert barrier
|
||||
_barriers.AddImageBarrier(image, subresourceRange, srcLayout, dstLayout, handle);
|
||||
#if VK_ENABLE_BARRIERS_DEBUG
|
||||
_barriers.ImageBarriersDebug.Add(handle);
|
||||
#endif
|
||||
VkImageMemoryBarrier& imageBarrier = _barriers.ImageBarriers.AddOne();
|
||||
RenderToolsVulkan::ZeroStruct(imageBarrier, VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER);
|
||||
imageBarrier.image = image;
|
||||
imageBarrier.subresourceRange = subresourceRange;
|
||||
imageBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
imageBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
imageBarrier.oldLayout = srcLayout;
|
||||
imageBarrier.newLayout = dstLayout;
|
||||
_barriers.SourceStage |= RenderToolsVulkan::GetImageBarrierFlags(srcLayout, imageBarrier.srcAccessMask);
|
||||
_barriers.DestStage |= RenderToolsVulkan::GetImageBarrierFlags(dstLayout, imageBarrier.dstAccessMask);
|
||||
#if VK_ENABLE_BARRIERS_DEBUG
|
||||
LOG(Warning, "Image Barrier: 0x{0:x}, {1} -> {2} for baseMipLevel: {3}, baseArrayLayer: {4}, levelCount: {5}, layerCount: {6} ({7})",
|
||||
(uintptr)image,
|
||||
::ToString(srcLayout),
|
||||
::ToString(dstLayout),
|
||||
subresourceRange.baseMipLevel,
|
||||
subresourceRange.baseArrayLayer,
|
||||
subresourceRange.levelCount,
|
||||
subresourceRange.layerCount,
|
||||
handle && handle->Owner->AsGPUResource() ? handle->Owner->AsGPUResource()->ToString() : String::Empty
|
||||
);
|
||||
#endif
|
||||
|
||||
#if !VK_ENABLE_BARRIERS_BATCHING
|
||||
// Auto-flush without batching
|
||||
@@ -306,7 +294,17 @@ void GPUContextVulkan::AddBufferBarrier(GPUBufferVulkan* buffer, VkAccessFlags d
|
||||
#endif
|
||||
|
||||
// Insert barrier
|
||||
_barriers.AddBufferBarrier(buffer->GetHandle(), 0, buffer->GetSize(), buffer->Access, dstAccess);
|
||||
VkBufferMemoryBarrier& bufferBarrier = _barriers.BufferBarriers.AddOne();
|
||||
RenderToolsVulkan::ZeroStruct(bufferBarrier, VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER);
|
||||
bufferBarrier.buffer = buffer->GetHandle();
|
||||
bufferBarrier.offset = 0;
|
||||
bufferBarrier.size = buffer->GetSize();
|
||||
bufferBarrier.srcAccessMask = buffer->Access;
|
||||
bufferBarrier.dstAccessMask = dstAccess;
|
||||
bufferBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
bufferBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
_barriers.SourceStage |= RenderToolsVulkan::GetBufferBarrierFlags(buffer->Access);
|
||||
_barriers.DestStage |= RenderToolsVulkan::GetBufferBarrierFlags(dstAccess);
|
||||
buffer->Access = dstAccess;
|
||||
|
||||
#if !VK_ENABLE_BARRIERS_BATCHING
|
||||
@@ -404,8 +402,18 @@ void GPUContextVulkan::BeginRenderPass()
|
||||
if (_rtDepth)
|
||||
{
|
||||
handle = _rtDepth;
|
||||
layout.ReadDepth = true; // TODO: use proper depthStencilAccess flags
|
||||
layout.WriteDepth = handle->LayoutRTV == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; // TODO: do it in a proper way
|
||||
layout.ReadDepth = true;
|
||||
layout.ReadStencil = PixelFormatExtensions::HasStencil(handle->GetFormat());
|
||||
layout.WriteDepth = handle->LayoutRTV == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL || handle->LayoutRTV == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL || handle->LayoutRTV == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL;
|
||||
layout.WriteStencil = handle->LayoutRTV == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL || handle->LayoutRTV == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL || handle->LayoutRTV == VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
if (_currentState && 0)
|
||||
{
|
||||
// TODO: use this but only if state doesn't change during whole render pass (eg. 1st draw call might not draw depth but 2nd might)
|
||||
layout.ReadDepth &= _currentState->DepthReadEnable;
|
||||
layout.ReadStencil &= _currentState->StencilReadEnable;
|
||||
layout.WriteDepth &= _currentState->DepthWriteEnable;
|
||||
layout.WriteStencil &= _currentState->StencilWriteEnable;
|
||||
}
|
||||
framebufferKey.AttachmentCount++;
|
||||
framebufferKey.Attachments[_rtCount] = handle->GetFramebufferView();
|
||||
AddImageBarrier(handle, handle->LayoutRTV);
|
||||
@@ -571,55 +579,6 @@ void GPUContextVulkan::UpdateDescriptorSets(const SpirvShaderDescriptorInfo& des
|
||||
}
|
||||
}
|
||||
|
||||
void GPUContextVulkan::UpdateDescriptorSets(GPUPipelineStateVulkan* pipelineState)
|
||||
{
|
||||
const auto cmdBuffer = _cmdBufferManager->GetCmdBuffer();
|
||||
const auto pipelineLayout = pipelineState->GetLayout();
|
||||
ASSERT(pipelineLayout);
|
||||
bool needsWrite = false;
|
||||
|
||||
// No current descriptor pools set - acquire one and reset
|
||||
const bool newDescriptorPool = pipelineState->AcquirePoolSet(cmdBuffer);
|
||||
needsWrite |= newDescriptorPool;
|
||||
|
||||
// Update descriptors for every used shader stage
|
||||
uint32 remainingHasDescriptorsPerStageMask = pipelineState->HasDescriptorsPerStageMask;
|
||||
for (int32 stage = 0; stage < DescriptorSet::GraphicsStagesCount && remainingHasDescriptorsPerStageMask; stage++)
|
||||
{
|
||||
// Only process stages that exist in this pipeline and use descriptors
|
||||
if (remainingHasDescriptorsPerStageMask & 1)
|
||||
{
|
||||
UpdateDescriptorSets(*pipelineState->DescriptorInfoPerStage[stage], pipelineState->DSWriter[stage], needsWrite);
|
||||
}
|
||||
|
||||
remainingHasDescriptorsPerStageMask >>= 1;
|
||||
}
|
||||
|
||||
// Allocate sets if need to
|
||||
//if (needsWrite) // TODO: write on change only?
|
||||
{
|
||||
if (!pipelineState->AllocateDescriptorSets())
|
||||
{
|
||||
return;
|
||||
}
|
||||
uint32 remainingStagesMask = pipelineState->HasDescriptorsPerStageMask;
|
||||
uint32 stage = 0;
|
||||
while (remainingStagesMask)
|
||||
{
|
||||
if (remainingStagesMask & 1)
|
||||
{
|
||||
const VkDescriptorSet descriptorSet = pipelineState->DescriptorSetHandles[stage];
|
||||
pipelineState->DSWriter[stage].SetDescriptorSet(descriptorSet);
|
||||
}
|
||||
|
||||
stage++;
|
||||
remainingStagesMask >>= 1;
|
||||
}
|
||||
|
||||
vkUpdateDescriptorSets(_device->Device, pipelineState->DSWriteContainer.DescriptorWrites.Count(), pipelineState->DSWriteContainer.DescriptorWrites.Get(), 0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void GPUContextVulkan::UpdateDescriptorSets(ComputePipelineStateVulkan* pipelineState)
|
||||
{
|
||||
const auto cmdBuffer = _cmdBufferManager->GetCmdBuffer();
|
||||
@@ -654,8 +613,6 @@ void GPUContextVulkan::OnDrawCall()
|
||||
GPUPipelineStateVulkan* pipelineState = _currentState;
|
||||
ASSERT(pipelineState && pipelineState->IsValid());
|
||||
const auto cmdBuffer = _cmdBufferManager->GetCmdBuffer();
|
||||
const auto pipelineLayout = pipelineState->GetLayout();
|
||||
ASSERT(pipelineLayout);
|
||||
|
||||
// End previous render pass if render targets layout was modified
|
||||
if (_rtDirtyFlag && cmdBuffer->IsInsideRenderPass())
|
||||
@@ -663,7 +620,35 @@ void GPUContextVulkan::OnDrawCall()
|
||||
|
||||
if (pipelineState->HasDescriptorsPerStageMask)
|
||||
{
|
||||
UpdateDescriptorSets(pipelineState);
|
||||
// Get descriptor pools set
|
||||
bool needsWrite = pipelineState->AcquirePoolSet(cmdBuffer);
|
||||
|
||||
// Update descriptors for every used shader stage
|
||||
uint32 remainingHasDescriptorsPerStageMask = pipelineState->HasDescriptorsPerStageMask;
|
||||
for (int32 stage = 0; stage < DescriptorSet::GraphicsStagesCount && remainingHasDescriptorsPerStageMask; stage++)
|
||||
{
|
||||
if (remainingHasDescriptorsPerStageMask & 1)
|
||||
UpdateDescriptorSets(*pipelineState->DescriptorInfoPerStage[stage], pipelineState->DSWriter[stage], needsWrite);
|
||||
remainingHasDescriptorsPerStageMask >>= 1;
|
||||
}
|
||||
|
||||
// Allocate sets if need to
|
||||
//if (needsWrite) // TODO: write on change only?
|
||||
{
|
||||
if (!pipelineState->CurrentTypedDescriptorPoolSet->AllocateDescriptorSets(*pipelineState->DescriptorSetsLayout, pipelineState->DescriptorSetHandles.Get()))
|
||||
return;
|
||||
uint32 remainingStagesMask = pipelineState->HasDescriptorsPerStageMask;
|
||||
uint32 stage = 0;
|
||||
while (remainingStagesMask)
|
||||
{
|
||||
if (remainingStagesMask & 1)
|
||||
pipelineState->DSWriter[stage].SetDescriptorSet(pipelineState->DescriptorSetHandles[stage]);
|
||||
remainingStagesMask >>= 1;
|
||||
stage++;
|
||||
}
|
||||
|
||||
vkUpdateDescriptorSets(_device->Device, pipelineState->DSWriteContainer.DescriptorWrites.Count(), pipelineState->DSWriteContainer.DescriptorWrites.Get(), 0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
// Bind any missing vertex buffers to null if required by the current state
|
||||
@@ -689,26 +674,30 @@ void GPUContextVulkan::OnDrawCall()
|
||||
}
|
||||
|
||||
// Bind pipeline
|
||||
if (_psDirtyFlag && _currentState && (_rtDepth || _rtCount))
|
||||
if (_psDirtyFlag && pipelineState && (_rtDepth || _rtCount))
|
||||
{
|
||||
_psDirtyFlag = false;
|
||||
const auto cmdBuffer = _cmdBufferManager->GetCmdBuffer();
|
||||
const auto pipeline = _currentState->GetState(_renderPass);
|
||||
const auto pipeline = pipelineState->GetState(_renderPass);
|
||||
vkCmdBindPipeline(cmdBuffer->GetHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||
RENDER_STAT_PS_STATE_CHANGE();
|
||||
}
|
||||
|
||||
//UpdateDynamicStates();
|
||||
|
||||
// Bind descriptors sets to the graphics pipeline
|
||||
if (pipelineState->HasDescriptorsPerStageMask)
|
||||
{
|
||||
pipelineState->Bind(cmdBuffer);
|
||||
vkCmdBindDescriptorSets(
|
||||
cmdBuffer->GetHandle(),
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
pipelineState->GetLayout()->GetHandle(),
|
||||
0,
|
||||
pipelineState->DescriptorSetHandles.Count(),
|
||||
pipelineState->DescriptorSetHandles.Get(),
|
||||
pipelineState->DynamicOffsets.Count(),
|
||||
pipelineState->DynamicOffsets.Get());
|
||||
}
|
||||
|
||||
// Clear flag
|
||||
_rtDirtyFlag = false;
|
||||
|
||||
#if VK_ENABLE_BARRIERS_DEBUG
|
||||
LOG(Warning, "Draw");
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user