diff --git a/Source/Engine/Graphics/Enums.h b/Source/Engine/Graphics/Enums.h
index 639899d9a..28200a895 100644
--- a/Source/Engine/Graphics/Enums.h
+++ b/Source/Engine/Graphics/Enums.h
@@ -410,6 +410,11 @@ enum class GPUQueryType
///
Occlusion = 1,
+ ///
+ /// Tests object visibility by checking depth and stencil tests. Works like Occlusion query, except returns simply a binary 0/1 result: 0 indicates that no samples passed depth and stencil testing; 1 indicates that at least one sample passed.
+ ///
+ BinaryOcclusion = 2,
+
MAX
};
diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.cpp
index 4de8b8ea5..067adab65 100644
--- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.cpp
+++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.cpp
@@ -303,7 +303,7 @@ void GPUContextDX11::SetRenderTarget(GPUTextureView* depthBuffer, GPUTextureView
void GPUContextDX11::SetRenderTarget(GPUTextureView* depthBuffer, const Span& rts)
{
- ASSERT(Math::IsInRange(rts.Length(), 1, GPU_MAX_RT_BINDED));
+ ASSERT(Math::IsInRange(rts.Length(), 0, GPU_MAX_RT_BINDED));
auto depthBufferDX11 = static_cast(depthBuffer);
ID3D11DepthStencilView* dsv = depthBufferDX11 ? depthBufferDX11->DSV() : nullptr;
@@ -590,7 +590,18 @@ uint64 GPUContextDX11::BeginQuery(GPUQueryType type)
auto& query = _device->_queries.AddOne();
query.Type = type;
D3D11_QUERY_DESC queryDesc;
- queryDesc.Query = type == GPUQueryType::Occlusion ? D3D11_QUERY_OCCLUSION : D3D11_QUERY_TIMESTAMP;
+ switch (type)
+ {
+ case GPUQueryType::Timer:
+ queryDesc.Query = D3D11_QUERY_TIMESTAMP;
+ break;
+ case GPUQueryType::Occlusion:
+ queryDesc.Query = D3D11_QUERY_OCCLUSION;
+ break;
+ case GPUQueryType::BinaryOcclusion:
+ queryDesc.Query = D3D11_QUERY_OCCLUSION_PREDICATE;
+ break;
+ }
queryDesc.MiscFlags = 0;
HRESULT hr = _device->GetDevice()->CreateQuery(&queryDesc, &query.Query);
LOG_DIRECTX_RESULT_WITH_RETURN(hr, 0);
diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp
index aa23c3a0f..b19961ed8 100644
--- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp
+++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp
@@ -1060,9 +1060,15 @@ RETRY:
}
}
}
+ else if (q.Type == (uint16)GPUQueryType::Occlusion)
+ {
+ hasData = context->GetData(query.Query, &result, sizeof(UINT64), 0) == S_OK;
+ }
else
{
- hasData = context->GetData(query.Query, &result, sizeof(uint64), 0) == S_OK;
+ BOOL resultBool;
+ hasData = context->GetData(query.Query, &resultBool, sizeof(BOOL), 0) == S_OK;
+ result = resultBool ? 1 : 0;
}
if (!hasData && wait)
diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.h b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.h
index 08007a0e3..a298d3b61 100644
--- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.h
+++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.h
@@ -93,7 +93,7 @@ private:
bool _allowTearing = false;
GPUBuffer* _dummyVB = nullptr;
Array _queries;
- Array _readyQueries[2]; // Timer and Occlusion
+ Array _readyQueries[3]; // Timer and Occlusion and BinaryOcclusion
// Static Samplers
ID3D11SamplerState* _samplerLinearClamp = nullptr;
diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.cpp
index 44e5cb400..bb1cbbb27 100644
--- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.cpp
+++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.cpp
@@ -948,7 +948,7 @@ void GPUContextDX12::SetRenderTarget(GPUTextureView* depthBuffer, GPUTextureView
void GPUContextDX12::SetRenderTarget(GPUTextureView* depthBuffer, const Span& rts)
{
- ASSERT(Math::IsInRange(rts.Length(), 1, GPU_MAX_RT_BINDED));
+ ASSERT(Math::IsInRange(rts.Length(), 0, GPU_MAX_RT_BINDED));
const auto depthBufferDX12 = static_cast(depthBuffer);
diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp
index 1c3f01899..1d65e7bce 100644
--- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp
+++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp
@@ -1061,7 +1061,7 @@ GPUQueryDX12 GPUDeviceDX12::AllocQuery(GPUQueryType type)
// Allocate a new query heap
PROFILE_MEM(GraphicsCommands);
auto heap = New();
- int32 size = type == GPUQueryType::Occlusion ? 4096 : 1024;
+ int32 size = type == GPUQueryType::Timer ? 1024 : 4096;
if (heap->Init(this, type, size))
{
Delete(heap);
diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/QueryHeapDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/QueryHeapDX12.cpp
index 5a24c5b4c..5d818c070 100644
--- a/Source/Engine/GraphicsDevice/DirectX/DX12/QueryHeapDX12.cpp
+++ b/Source/Engine/GraphicsDevice/DirectX/DX12/QueryHeapDX12.cpp
@@ -28,6 +28,11 @@ bool QueryHeapDX12::Init(GPUDeviceDX12* device, GPUQueryType type, uint32 size)
QueryType = D3D12_QUERY_TYPE_OCCLUSION;
heapDesc.Type = D3D12_QUERY_HEAP_TYPE_OCCLUSION;
break;
+ case GPUQueryType::BinaryOcclusion:
+ _resultSize = sizeof(uint64);
+ QueryType = D3D12_QUERY_TYPE_BINARY_OCCLUSION;
+ heapDesc.Type = D3D12_QUERY_HEAP_TYPE_OCCLUSION;
+ break;
case GPUQueryType::MAX:
return true;
}
@@ -100,11 +105,6 @@ void QueryHeapDX12::EndQueryBatchAndResolveQueryData(GPUContextDX12* context)
StartQueryBatch();
}
-bool QueryHeapDX12::CanAlloc(int32 count) const
-{
- return _currentBatch.Open && _currentIndex + count <= GetQueryHeapCount();
-}
-
void QueryHeapDX12::Alloc(ElementHandle& handle)
{
ASSERT(_currentBatch.Open);
diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/QueryHeapDX12.h b/Source/Engine/GraphicsDevice/DirectX/DX12/QueryHeapDX12.h
index e8ab92a73..629c8cb51 100644
--- a/Source/Engine/GraphicsDevice/DirectX/DX12/QueryHeapDX12.h
+++ b/Source/Engine/GraphicsDevice/DirectX/DX12/QueryHeapDX12.h
@@ -153,7 +153,10 @@ public:
///
/// How many elements to allocate?
/// True if can alloc new query within the same batch.
- bool CanAlloc(int32 count = 1) const;
+ bool CanAlloc(int32 count = 1) const
+ {
+ return _currentBatch.Open && _currentIndex + count <= _queryHeapCount;
+ }
///
/// Allocates the query heap element.
diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp
index e835b2f80..5fc45fd22 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp
+++ b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp
@@ -1466,6 +1466,9 @@ uint64 GPUContextVulkan::BeginQuery(GPUQueryType type)
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);
+ break;
}
pool->MarkQueryAsStarted(query.QueryIndex);
@@ -1492,6 +1495,7 @@ void GPUContextVulkan::EndQuery(uint64 queryID)
#endif
break;
case GPUQueryType::Occlusion:
+ case GPUQueryType::BinaryOcclusion:
vkCmdEndQuery(cmdBuffer->GetHandle(), pool->GetHandle(), query.QueryIndex);
break;
}
diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp
index 084122d77..ac58b3a22 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp
+++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp
@@ -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::Occlusion ? VK_QUERY_TYPE_OCCLUSION : VK_QUERY_TYPE_TIMESTAMP;
+ 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));
@@ -1282,7 +1282,7 @@ int32 GPUDeviceVulkan::GetOrCreateQueryPool(GPUQueryType type)
PROFILE_CPU_NAMED("Create Create Pool");
PROFILE_MEM(GraphicsCommands);
- auto pool = New(this, type == GPUQueryType::Occlusion ? 4096 : 1024, type);
+ auto pool = New(this, type == GPUQueryType::Timer ? 1024 : 4096, type);
QueryPools.Add(pool);
return QueryPools.Count() - 1;
}
@@ -2217,13 +2217,17 @@ RETRY:
}
break;
case GPUQueryType::Occlusion:
+ case GPUQueryType::BinaryOcclusion:
hasData = pool->GetResults(query.QueryIndex, result);
+ if (hasData && pool->Type == GPUQueryType::BinaryOcclusion && result > 1)
+ result = 1; // Clamp binary result
break;
}
if (!hasData && wait)
{
// Wait until data is ready
+ // TODO: use VK_QUERY_RESULT_WAIT_BIT maybe?
Platform::Yield();
goto RETRY;
}
diff --git a/Source/Engine/GraphicsDevice/WebGPU/GPUContextWebGPU.cpp b/Source/Engine/GraphicsDevice/WebGPU/GPUContextWebGPU.cpp
index 8b132dde2..839169f81 100644
--- a/Source/Engine/GraphicsDevice/WebGPU/GPUContextWebGPU.cpp
+++ b/Source/Engine/GraphicsDevice/WebGPU/GPUContextWebGPU.cpp
@@ -229,7 +229,7 @@ void GPUContextWebGPU::SetRenderTarget(GPUTextureView* depthBuffer, GPUTextureVi
void GPUContextWebGPU::SetRenderTarget(GPUTextureView* depthBuffer, const Span& rts)
{
- ASSERT(Math::IsInRange(rts.Length(), 1, GPU_MAX_RT_BINDED));
+ ASSERT(Math::IsInRange(rts.Length(), 0, GPU_MAX_RT_BINDED));
auto depthBufferGPU = (GPUTextureViewWebGPU*)depthBuffer;
if (_renderTargetCount != rts.Length() || _depthStencil != depthBufferGPU || Platform::MemoryCompare(_renderTargets, rts.Get(), rts.Length() * sizeof(void*)) != 0)
{
diff --git a/Source/Engine/GraphicsDevice/WebGPU/GPUDeviceWebGPU.cpp b/Source/Engine/GraphicsDevice/WebGPU/GPUDeviceWebGPU.cpp
index 85ff85616..8bb29c825 100644
--- a/Source/Engine/GraphicsDevice/WebGPU/GPUDeviceWebGPU.cpp
+++ b/Source/Engine/GraphicsDevice/WebGPU/GPUDeviceWebGPU.cpp
@@ -860,7 +860,7 @@ GPUQueryWebGPU GPUDeviceWebGPU::AllocateQuery(GPUQueryType type)
// Allocate a new query heap
PROFILE_MEM(GraphicsCommands);
- uint32 size = type == GPUQueryType::Occlusion ? 4096 : 1024;
+ uint32 size = type == GPUQueryType::Timer ? 1024 : 4096;
auto set = New(Device, type, size);
QuerySets[QuerySetsCount++] = set;
}