Fix occlusion queries on Vulkan
This commit is contained in:
@@ -289,7 +289,7 @@ void CmdBufferManagerVulkan::SubmitActiveCmdBuffer(SemaphoreVulkan* signalSemaph
|
||||
}
|
||||
#else
|
||||
for (int32 i = 0; i < _activeTimerQueries.Count(); i++)
|
||||
queries->Interrupt(_activeCmdBuffer);
|
||||
queries[i]->Interrupt(_context);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -347,7 +347,7 @@ void CmdBufferManagerVulkan::GetNewActiveCommandBuffer()
|
||||
#else
|
||||
for (int32 i = 0; i < _activeTimerQueries.Count(); i++)
|
||||
{
|
||||
queries->Resume(_activeCmdBuffer);
|
||||
queries[i]->Resume(_context);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -437,6 +437,7 @@ void GPUContextVulkan::BeginRenderPass()
|
||||
|
||||
// Build render targets layout descriptor and framebuffer key
|
||||
FramebufferVulkan::Key framebufferKey;
|
||||
Platform::MemoryClear(&framebufferKey, sizeof(framebufferKey));
|
||||
framebufferKey.AttachmentCount = _rtCount;
|
||||
RenderTargetLayoutVulkan layout;
|
||||
Platform::MemoryClear(&layout, sizeof(layout));
|
||||
@@ -445,7 +446,7 @@ void GPUContextVulkan::BeginRenderPass()
|
||||
layout.DepthFormat = _rtDepth ? _rtDepth->GetFormat() : PixelFormat::Unknown;
|
||||
VkClearValue clearValues[GPU_MAX_RT_BINDED + 1];
|
||||
PendingClear clear;
|
||||
for (int32 i = 0; i < GPU_MAX_RT_BINDED; i++)
|
||||
for (int32 i = 0; i < _rtCount; i++)
|
||||
{
|
||||
auto handle = _rtTargets[i];
|
||||
if (handle)
|
||||
@@ -470,11 +471,6 @@ void GPUContextVulkan::BeginRenderPass()
|
||||
layout.StoreDontCare |= mask;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
layout.RTVsFormats[i] = PixelFormat::Unknown;
|
||||
framebufferKey.Attachments[i] = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
GPUTextureViewVulkan* handle;
|
||||
if (_rtDepth)
|
||||
@@ -536,6 +532,7 @@ void GPUContextVulkan::BeginRenderPass()
|
||||
FlushBarriers();
|
||||
|
||||
cmdBuffer->BeginRenderPass(renderPass, framebuffer, ARRAY_COUNT(clearValues), clearValues);
|
||||
_rtDirtyFlag = false;
|
||||
}
|
||||
|
||||
void GPUContextVulkan::EndRenderPass()
|
||||
@@ -802,7 +799,7 @@ void GPUContextVulkan::OnDrawCall()
|
||||
}
|
||||
|
||||
// Allocate sets if need to
|
||||
//if (needsWrite) // TODO: write on change only?
|
||||
if (needsWrite)
|
||||
{
|
||||
if (!pipelineState->CurrentTypedDescriptorPoolSet->AllocateDescriptorSets(*pipelineState->DescriptorSetsLayout, pipelineState->DescriptorSetHandles.Get()))
|
||||
return;
|
||||
@@ -862,7 +859,6 @@ void GPUContextVulkan::OnDrawCall()
|
||||
vkCmdBindDescriptorSets(cmdBuffer->GetHandle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineState->GetLayout()->Handle, 0, descriptorSets.Count(), descriptorSets.Get(), dynamicOffsets.Count(), dynamicOffsets.Get());
|
||||
}
|
||||
|
||||
_rtDirtyFlag = false;
|
||||
#if VK_ENABLE_BARRIERS_DEBUG
|
||||
LOG(Warning, "Draw");
|
||||
#endif
|
||||
@@ -904,7 +900,7 @@ void GPUContextVulkan::FrameBegin()
|
||||
if (_device->QueriesToReset.HasItems())
|
||||
{
|
||||
for (auto query : _device->QueriesToReset)
|
||||
query->Reset(cmdBuffer);
|
||||
query->Reset(this);
|
||||
_device->QueriesToReset.Clear();
|
||||
}
|
||||
#endif
|
||||
@@ -1442,7 +1438,7 @@ uint64 GPUContextVulkan::BeginQuery(GPUQueryType type)
|
||||
auto pool = _device->QueryPools[poolIndex];
|
||||
uint32 index = 0;
|
||||
const auto cmdBuffer = _cmdBufferManager->GetCmdBuffer();
|
||||
if (!pool->AcquireQuery(cmdBuffer, index))
|
||||
if (!pool->AcquireQuery(this, index))
|
||||
return 0;
|
||||
GPUQueryVulkan query;
|
||||
query.PoolIndex = (uint16)poolIndex;
|
||||
@@ -1455,19 +1451,21 @@ uint64 GPUContextVulkan::BeginQuery(GPUQueryType type)
|
||||
{
|
||||
case GPUQueryType::Timer:
|
||||
// Timer queries need 2 slots (begin + end)
|
||||
pool->AcquireQuery(cmdBuffer, index);
|
||||
pool->AcquireQuery(this, index);
|
||||
query.SecondQueryIndex = (uint16)index;
|
||||
|
||||
vkCmdWriteTimestamp(cmdBuffer->GetHandle(), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, pool->GetHandle(), query.QueryIndex);
|
||||
#if GPU_VULKAN_PAUSE_QUERIES
|
||||
_cmdBufferManager->OnTimerQueryBegin(query.Raw);
|
||||
#endif
|
||||
break;
|
||||
case GPUQueryType::Occlusion:
|
||||
vkCmdBeginQuery(cmdBuffer->GetHandle(), pool->GetHandle(), query.QueryIndex, 0);
|
||||
break;
|
||||
case GPUQueryType::BinaryOcclusion:
|
||||
vkCmdBeginQuery(cmdBuffer->GetHandle(), pool->GetHandle(), query.QueryIndex, VK_QUERY_CONTROL_PRECISE_BIT);
|
||||
// Flush render pass when starting occlusion query
|
||||
if (_rtDirtyFlag && cmdBuffer->IsInsideRenderPass())
|
||||
EndRenderPass();
|
||||
if (cmdBuffer->IsOutsideRenderPass())
|
||||
BeginRenderPass();
|
||||
vkCmdBeginQuery(cmdBuffer->GetHandle(), pool->GetHandle(), query.QueryIndex, type == GPUQueryType::Occlusion ? VK_QUERY_CONTROL_PRECISE_BIT : 0);
|
||||
break;
|
||||
}
|
||||
pool->MarkQueryAsStarted(query.QueryIndex);
|
||||
|
||||
@@ -527,7 +527,7 @@ RenderPassVulkan::RenderPassVulkan(GPUDeviceVulkan* device, const RenderTargetLa
|
||||
: Device(device)
|
||||
, Handle(VK_NULL_HANDLE)
|
||||
, Layout(layout)
|
||||
, CanDepthWrite(true)
|
||||
, CanDepthStencilWrite(true)
|
||||
{
|
||||
const int32 colorAttachmentsCount = layout.RTsCount;
|
||||
const bool hasDepthStencilAttachment = layout.DepthFormat != PixelFormat::Unknown;
|
||||
@@ -615,7 +615,7 @@ RenderPassVulkan::RenderPassVulkan(GPUDeviceVulkan* device, const RenderTargetLa
|
||||
depthStencilReference.layout = depthStencilLayout;
|
||||
subpassDesc.pDepthStencilAttachment = &depthStencilReference;
|
||||
if (!layout.WriteDepth && !layout.WriteStencil)
|
||||
CanDepthWrite = false;
|
||||
CanDepthStencilWrite = false;
|
||||
}
|
||||
|
||||
VkRenderPassCreateInfo createInfo;
|
||||
@@ -642,7 +642,7 @@ QueryPoolVulkan::QueryPoolVulkan(GPUDeviceVulkan* device, int32 capacity, GPUQue
|
||||
{
|
||||
VkQueryPoolCreateInfo createInfo;
|
||||
RenderToolsVulkan::ZeroStruct(createInfo, VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO);
|
||||
createInfo.queryType = type != GPUQueryType::Timer ? VK_QUERY_TYPE_TIMESTAMP : VK_QUERY_TYPE_OCCLUSION;
|
||||
createInfo.queryType = type == GPUQueryType::Timer ? VK_QUERY_TYPE_TIMESTAMP : VK_QUERY_TYPE_OCCLUSION;
|
||||
createInfo.queryCount = capacity;
|
||||
VALIDATE_VULKAN_RESULT(vkCreateQueryPool(device->Device, &createInfo, nullptr, &_handle));
|
||||
|
||||
@@ -663,11 +663,18 @@ QueryPoolVulkan::~QueryPoolVulkan()
|
||||
|
||||
#if VULKAN_RESET_QUERY_POOLS
|
||||
|
||||
void QueryPoolVulkan::Reset(CmdBufferVulkan* cmdBuffer)
|
||||
void QueryPoolVulkan::Reset(GPUContextVulkan* context)
|
||||
{
|
||||
if (_resetRanges.IsEmpty())
|
||||
return;
|
||||
const auto cmdBuffer = context->GetCmdBufferManager()->GetCmdBuffer();
|
||||
if (cmdBuffer->IsInsideRenderPass())
|
||||
context->EndRenderPass(); // vkCmdResetQueryPool can be called only outside the render pass
|
||||
// TODO: batch sequential reset operations
|
||||
auto commandBuffer = cmdBuffer->GetHandle();
|
||||
for (auto& range : _resetRanges)
|
||||
{
|
||||
vkCmdResetQueryPool(cmdBuffer->GetHandle(), _handle, range.Start, range.Count);
|
||||
vkCmdResetQueryPool(commandBuffer, _handle, range.Start, range.Count);
|
||||
}
|
||||
_resetRanges.Clear();
|
||||
ResetBeforeUse = false;
|
||||
@@ -684,7 +691,7 @@ BufferedQueryPoolVulkan::BufferedQueryPoolVulkan(GPUDeviceVulkan* device, int32
|
||||
_readResultsBits.AddZeroed((capacity + 63) / 64);
|
||||
}
|
||||
|
||||
bool BufferedQueryPoolVulkan::AcquireQuery(CmdBufferVulkan* cmdBuffer, uint32& resultIndex)
|
||||
bool BufferedQueryPoolVulkan::AcquireQuery(GPUContextVulkan* context, uint32& resultIndex)
|
||||
{
|
||||
const uint64 allUsedMask = MAX_uint64;
|
||||
for (int32 wordIndex = _lastBeginIndex / 64; wordIndex < _usedQueryBits.Count(); wordIndex++)
|
||||
@@ -705,7 +712,7 @@ bool BufferedQueryPoolVulkan::AcquireQuery(CmdBufferVulkan* cmdBuffer, uint32& r
|
||||
_readResultsBits[wordIndex] &= ~bit;
|
||||
_lastBeginIndex = resultIndex + 1;
|
||||
if (ResetBeforeUse)
|
||||
Reset(cmdBuffer);
|
||||
Reset(context);
|
||||
_lastUsedFrame = Engine::FrameCount;
|
||||
return true;
|
||||
}
|
||||
@@ -757,6 +764,7 @@ bool BufferedQueryPoolVulkan::GetResults(uint32 index, uint64& result)
|
||||
if ((_startedQueryBits[word] & bit) == 0)
|
||||
{
|
||||
// Query never started/ended
|
||||
result = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -809,27 +817,23 @@ bool BufferedQueryPoolVulkan::TryExpire()
|
||||
return false;
|
||||
|
||||
// Reset back to clean state all unfinished queries
|
||||
for (uint32 index = 0; index < _queryOutput.Count(); index++)
|
||||
bool canUseNow = true;
|
||||
for (uint32 index = 0; index < (uint32)_queryOutput.Count(); index++)
|
||||
{
|
||||
const uint64 bit = (uint64)1 << (index % 64);
|
||||
const uint32 word = index / 64;
|
||||
if ((_usedQueryBits[word] & bit) == 0)
|
||||
continue;
|
||||
#if VULKAN_RESET_QUERY_POOLS
|
||||
if ((_readResultsBits[word] & bit) == 0)
|
||||
{
|
||||
const VkResult vkResult = vkGetQueryPoolResults(_device->Device, _handle, index, 1, sizeof(uint64), &_queryOutput[index], sizeof(uint64), VK_QUERY_RESULT_64_BIT);
|
||||
if (vkResult == VK_SUCCESS)
|
||||
{
|
||||
_readResultsBits[word] = _readResultsBits[word] | bit;
|
||||
|
||||
#if VULKAN_RESET_QUERY_POOLS
|
||||
// Add to reset
|
||||
if (!_device->QueriesToReset.Contains(this))
|
||||
_device->QueriesToReset.Add(this);
|
||||
_resetRanges.Add(Range{ index, 1 });
|
||||
#endif
|
||||
}
|
||||
// Add to reset
|
||||
if (!_device->QueriesToReset.Contains(this))
|
||||
_device->QueriesToReset.Add(this);
|
||||
_resetRanges.Add(Range{ index, 1 });
|
||||
canUseNow = false;
|
||||
}
|
||||
#endif
|
||||
_usedQueryBits[word] = _usedQueryBits[word] & ~bit;
|
||||
}
|
||||
constexpr uint64 allUsedMask = MAX_uint64;
|
||||
@@ -842,7 +846,7 @@ bool BufferedQueryPoolVulkan::TryExpire()
|
||||
}
|
||||
}
|
||||
|
||||
return HasRoom();
|
||||
return canUseNow && HasRoom();
|
||||
}
|
||||
|
||||
HelperResourcesVulkan::HelperResourcesVulkan(GPUDeviceVulkan* device)
|
||||
|
||||
@@ -260,7 +260,7 @@ public:
|
||||
GPUDeviceVulkan* Device;
|
||||
VkRenderPass Handle;
|
||||
RenderTargetLayoutVulkan Layout;
|
||||
bool CanDepthWrite;
|
||||
bool CanDepthStencilWrite;
|
||||
#if VULKAN_USE_DEBUG_DATA
|
||||
VkRenderPassCreateInfo DebugCreateInfo;
|
||||
#endif
|
||||
@@ -299,7 +299,7 @@ public:
|
||||
|
||||
#if VULKAN_RESET_QUERY_POOLS
|
||||
bool ResetBeforeUse;
|
||||
void Reset(CmdBufferVulkan* cmdBuffer);
|
||||
void Reset(GPUContextVulkan* context);
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -318,7 +318,7 @@ private:
|
||||
|
||||
public:
|
||||
BufferedQueryPoolVulkan(GPUDeviceVulkan* device, int32 capacity, GPUQueryType type);
|
||||
bool AcquireQuery(CmdBufferVulkan* cmdBuffer, uint32& resultIndex);
|
||||
bool AcquireQuery(GPUContextVulkan* context, uint32& resultIndex);
|
||||
void ReleaseQuery(uint32 queryIndex);
|
||||
void MarkQueryAsStarted(uint32 queryIndex);
|
||||
bool GetResults(uint32 index, uint64& result);
|
||||
|
||||
@@ -315,10 +315,13 @@ VkPipeline GPUPipelineStateVulkan::GetState(RenderPassVulkan* renderPass, GPUVer
|
||||
|
||||
// Create object
|
||||
auto depthWrite = _descDepthStencil.depthWriteEnable;
|
||||
_descDepthStencil.depthWriteEnable &= renderPass->CanDepthWrite ? 1 : 0;
|
||||
auto stencilWriteMask = _descDepthStencil.front.writeMask;
|
||||
_descDepthStencil.depthWriteEnable &= renderPass->CanDepthStencilWrite ? 1 : 0;
|
||||
_descDepthStencil.front.writeMask &= renderPass->CanDepthStencilWrite ? MAX_uint32 : 0;
|
||||
const VkResult result = vkCreateGraphicsPipelines(_device->Device, _device->PipelineCache, 1, &_desc, nullptr, &pipeline);
|
||||
_device->PipelineCacheUsage++;
|
||||
_descDepthStencil.depthWriteEnable = depthWrite;
|
||||
_descDepthStencil.front.writeMask = _descDepthStencil.back.writeMask = stencilWriteMask;
|
||||
LOG_VULKAN_RESULT(result);
|
||||
if (result != VK_SUCCESS)
|
||||
{
|
||||
|
||||
@@ -642,7 +642,7 @@ void GPUSwapChainVulkan::Present(bool vsync)
|
||||
|
||||
// Cache a command buffer to wait on its fence before drawing to this backbuffer again
|
||||
auto& acquiredBackBuffer = _backBuffers[_acquiredImageIndex];
|
||||
ASSERT(acquiredBackBuffer.SubmitCmdBuffer == nullptr || !acquiredBackBuffer.SubmitCmdBuffer->IsSubmitted());
|
||||
ASSERT(acquiredBackBuffer.SubmitCmdBuffer == nullptr || acquiredBackBuffer.SubmitCmdBuffer->IsSubmitted());
|
||||
acquiredBackBuffer.SubmitCmdBuffer = context->GetCmdBufferManager()->GetActiveCmdBuffer();
|
||||
|
||||
context->GetCmdBufferManager()->SubmitActiveCmdBuffer(_backBuffers[_acquiredImageIndex].RenderingDoneSemaphore);
|
||||
|
||||
@@ -83,16 +83,16 @@ float GPUTimerQueryVulkan::GetResult()
|
||||
|
||||
#else
|
||||
|
||||
void GPUTimerQueryVulkan::Interrupt(CmdBufferVulkan* cmdBuffer)
|
||||
void GPUTimerQueryVulkan::Interrupt(GPUContextVulkan* context)
|
||||
{
|
||||
if (!_interrupted)
|
||||
{
|
||||
_interrupted = true;
|
||||
WriteTimestamp(cmdBuffer, _queries[_queryIndex].End, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
|
||||
WriteTimestamp(context, _queries[_queryIndex].End, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
void GPUTimerQueryVulkan::Resume(CmdBufferVulkan* cmdBuffer)
|
||||
void GPUTimerQueryVulkan::Resume(GPUContextVulkan* context)
|
||||
{
|
||||
ASSERT(_interrupted);
|
||||
|
||||
@@ -100,7 +100,7 @@ void GPUTimerQueryVulkan::Resume(CmdBufferVulkan* cmdBuffer)
|
||||
e.End.Pool = nullptr;
|
||||
|
||||
_interrupted = false;
|
||||
WriteTimestamp(cmdBuffer, e.Begin, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
|
||||
WriteTimestamp(context, e.Begin, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
|
||||
|
||||
_queries.Add(e);
|
||||
_queryIndex++;
|
||||
@@ -127,13 +127,13 @@ bool GPUTimerQueryVulkan::GetResult(Query& query)
|
||||
return false;
|
||||
}
|
||||
|
||||
void GPUTimerQueryVulkan::WriteTimestamp(CmdBufferVulkan* cmdBuffer, Query& query, VkPipelineStageFlagBits stage) const
|
||||
void GPUTimerQueryVulkan::WriteTimestamp(GPUContextVulkan* context, Query& query, VkPipelineStageFlagBits stage) const
|
||||
{
|
||||
auto pool = _device->QueryPools[_device->GetOrCreateQueryPool(GPUQueryType::Timer)];
|
||||
uint32 index;
|
||||
if (pool->AcquireQuery(cmdBuffer, index))
|
||||
if (pool->AcquireQuery(context, index))
|
||||
{
|
||||
vkCmdWriteTimestamp(cmdBuffer->GetHandle(), stage, pool->GetHandle(), index);
|
||||
vkCmdWriteTimestamp(context->GetCmdBufferManager()->GetCmdBuffer()->GetHandle(), stage, pool->GetHandle(), index);
|
||||
pool->MarkQueryAsStarted(index);
|
||||
query.Pool = pool;
|
||||
query.Index = index;
|
||||
@@ -215,14 +215,13 @@ void GPUTimerQueryVulkan::Begin()
|
||||
if (UseQueries())
|
||||
{
|
||||
const auto context = (GPUContextVulkan*)_device->GetMainContext();
|
||||
const auto cmdBuffer = context->GetCmdBufferManager()->GetCmdBuffer();
|
||||
|
||||
QueryPair e;
|
||||
e.End.Pool = nullptr;
|
||||
|
||||
_queryIndex = 0;
|
||||
_interrupted = false;
|
||||
WriteTimestamp(cmdBuffer, e.Begin, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
|
||||
WriteTimestamp(context, e.Begin, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
|
||||
context->GetCmdBufferManager()->OnTimerQueryBegin(this);
|
||||
|
||||
ASSERT(_queries.IsEmpty());
|
||||
@@ -241,11 +240,10 @@ void GPUTimerQueryVulkan::End()
|
||||
if (UseQueries())
|
||||
{
|
||||
const auto context = (GPUContextVulkan*)_device->GetMainContext();
|
||||
const auto cmdBuffer = context->GetCmdBufferManager()->GetCmdBuffer();
|
||||
|
||||
if (!_interrupted)
|
||||
{
|
||||
WriteTimestamp(cmdBuffer, _queries[_queryIndex].End, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
|
||||
WriteTimestamp(context, _queries[_queryIndex].End, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
|
||||
}
|
||||
context->GetCmdBufferManager()->OnTimerQueryEnd(this);
|
||||
}
|
||||
|
||||
@@ -51,20 +51,20 @@ public:
|
||||
#if !GPU_VULKAN_QUERY_NEW
|
||||
public:
|
||||
/// <summary>
|
||||
/// Interrupts an in-progress query, allowing the command buffer to submitted. Interrupted queries must be resumed using Resume().
|
||||
/// Interrupts an in-progress query, allowing the command buffer to submit. Interrupted queries must be resumed using Resume().
|
||||
/// </summary>
|
||||
/// <param name="cmdBuffer">The GPU commands buffer.</param>
|
||||
void Interrupt(CmdBufferVulkan* cmdBuffer);
|
||||
/// <param name="context">The GPU context.</param>
|
||||
void Interrupt(GPUContextVulkan* context);
|
||||
|
||||
/// <summary>
|
||||
/// Resumes an interrupted query, restoring it back to its original in-progress state.
|
||||
/// </summary>
|
||||
/// <param name="cmdBuffer">The GPU commands buffer.</param>
|
||||
void Resume(CmdBufferVulkan* cmdBuffer);
|
||||
/// <param name="context">The GPU context.</param>
|
||||
void Resume(GPUContextVulkan* context);
|
||||
|
||||
private:
|
||||
bool GetResult(Query& query);
|
||||
void WriteTimestamp(CmdBufferVulkan* cmdBuffer, Query& query, VkPipelineStageFlagBits stage) const;
|
||||
void WriteTimestamp(GPUContextVulkan* context, Query& query, VkPipelineStageFlagBits stage) const;
|
||||
bool TryGetResult();
|
||||
bool UseQueries();
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user