Query API: Non Precise Occlusion Query
- Add BeginOcclusionQuery and EndOcclusionQuery in frontend - Set occlusion query as unsafe APIs - Add validation tests Bug: dawn:434 Change-Id: I3d1cefed780812dd62fb082287ff71530b76ebee Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/31321 Commit-Queue: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
parent
55f251dffe
commit
01e4450729
|
@ -1362,6 +1362,15 @@
|
||||||
{"name": "size", "type": "uint64_t", "default": "0"}
|
{"name": "size", "type": "uint64_t", "default": "0"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "begin occlusion query",
|
||||||
|
"args": [
|
||||||
|
{"name": "query index", "type": "uint32_t"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "end occlusion query"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "write timestamp",
|
"name": "write timestamp",
|
||||||
"args": [
|
"args": [
|
||||||
|
|
|
@ -324,7 +324,19 @@ namespace dawn_native {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (descriptor->occlusionQuerySet != nullptr) {
|
if (descriptor->occlusionQuerySet != nullptr) {
|
||||||
return DAWN_VALIDATION_ERROR("occlusionQuerySet not implemented");
|
DAWN_TRY(device->ValidateObject(descriptor->occlusionQuerySet));
|
||||||
|
|
||||||
|
// Occlusion query has not been implemented completely. Disallow it as unsafe until
|
||||||
|
// the implementaion is completed.
|
||||||
|
if (device->IsToggleEnabled(Toggle::DisallowUnsafeAPIs)) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"Occlusion query is disallowed because it has not been implemented "
|
||||||
|
"completely.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (descriptor->occlusionQuerySet->GetQueryType() != wgpu::QueryType::Occlusion) {
|
||||||
|
return DAWN_VALIDATION_ERROR("The type of query set must be Occlusion");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (descriptor->colorAttachmentCount == 0 &&
|
if (descriptor->colorAttachmentCount == 0 &&
|
||||||
|
@ -508,8 +520,9 @@ namespace dawn_native {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
RenderPassEncoder* passEncoder = new RenderPassEncoder(
|
RenderPassEncoder* passEncoder =
|
||||||
device, this, &mEncodingContext, std::move(usageTracker), width, height);
|
new RenderPassEncoder(device, this, &mEncodingContext, std::move(usageTracker),
|
||||||
|
descriptor->occlusionQuerySet, width, height);
|
||||||
mEncodingContext.EnterPass(passEncoder);
|
mEncodingContext.EnterPass(passEncoder);
|
||||||
return passEncoder;
|
return passEncoder;
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,6 +159,16 @@ namespace dawn_native {
|
||||||
Command type;
|
Command type;
|
||||||
while (commands->NextCommandId(&type)) {
|
while (commands->NextCommandId(&type)) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
case Command::BeginOcclusionQuery: {
|
||||||
|
commands->NextCommand<BeginOcclusionQueryCmd>();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Command::EndOcclusionQuery: {
|
||||||
|
commands->NextCommand<EndOcclusionQueryCmd>();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case Command::EndRenderPass: {
|
case Command::EndRenderPass: {
|
||||||
commands->NextCommand<EndRenderPassCmd>();
|
commands->NextCommand<EndRenderPassCmd>();
|
||||||
DAWN_TRY(ValidateFinalDebugGroupStackSize(debugGroupStackSize));
|
DAWN_TRY(ValidateFinalDebugGroupStackSize(debugGroupStackSize));
|
||||||
|
|
|
@ -36,6 +36,11 @@ namespace dawn_native {
|
||||||
begin->~BeginComputePassCmd();
|
begin->~BeginComputePassCmd();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case Command::BeginOcclusionQuery: {
|
||||||
|
BeginOcclusionQueryCmd* begin = commands->NextCommand<BeginOcclusionQueryCmd>();
|
||||||
|
begin->~BeginOcclusionQueryCmd();
|
||||||
|
break;
|
||||||
|
}
|
||||||
case Command::BeginRenderPass: {
|
case Command::BeginRenderPass: {
|
||||||
BeginRenderPassCmd* begin = commands->NextCommand<BeginRenderPassCmd>();
|
BeginRenderPassCmd* begin = commands->NextCommand<BeginRenderPassCmd>();
|
||||||
begin->~BeginRenderPassCmd();
|
begin->~BeginRenderPassCmd();
|
||||||
|
@ -97,6 +102,11 @@ namespace dawn_native {
|
||||||
cmd->~EndComputePassCmd();
|
cmd->~EndComputePassCmd();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case Command::EndOcclusionQuery: {
|
||||||
|
EndOcclusionQueryCmd* cmd = commands->NextCommand<EndOcclusionQueryCmd>();
|
||||||
|
cmd->~EndOcclusionQueryCmd();
|
||||||
|
break;
|
||||||
|
}
|
||||||
case Command::EndRenderPass: {
|
case Command::EndRenderPass: {
|
||||||
EndRenderPassCmd* cmd = commands->NextCommand<EndRenderPassCmd>();
|
EndRenderPassCmd* cmd = commands->NextCommand<EndRenderPassCmd>();
|
||||||
cmd->~EndRenderPassCmd();
|
cmd->~EndRenderPassCmd();
|
||||||
|
@ -198,6 +208,10 @@ namespace dawn_native {
|
||||||
commands->NextCommand<BeginComputePassCmd>();
|
commands->NextCommand<BeginComputePassCmd>();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Command::BeginOcclusionQuery:
|
||||||
|
commands->NextCommand<BeginOcclusionQueryCmd>();
|
||||||
|
break;
|
||||||
|
|
||||||
case Command::BeginRenderPass:
|
case Command::BeginRenderPass:
|
||||||
commands->NextCommand<BeginRenderPassCmd>();
|
commands->NextCommand<BeginRenderPassCmd>();
|
||||||
break;
|
break;
|
||||||
|
@ -246,6 +260,10 @@ namespace dawn_native {
|
||||||
commands->NextCommand<EndComputePassCmd>();
|
commands->NextCommand<EndComputePassCmd>();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Command::EndOcclusionQuery:
|
||||||
|
commands->NextCommand<EndOcclusionQueryCmd>();
|
||||||
|
break;
|
||||||
|
|
||||||
case Command::EndRenderPass:
|
case Command::EndRenderPass:
|
||||||
commands->NextCommand<EndRenderPassCmd>();
|
commands->NextCommand<EndRenderPassCmd>();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -34,6 +34,7 @@ namespace dawn_native {
|
||||||
|
|
||||||
enum class Command {
|
enum class Command {
|
||||||
BeginComputePass,
|
BeginComputePass,
|
||||||
|
BeginOcclusionQuery,
|
||||||
BeginRenderPass,
|
BeginRenderPass,
|
||||||
CopyBufferToBuffer,
|
CopyBufferToBuffer,
|
||||||
CopyBufferToTexture,
|
CopyBufferToTexture,
|
||||||
|
@ -46,6 +47,7 @@ namespace dawn_native {
|
||||||
DrawIndirect,
|
DrawIndirect,
|
||||||
DrawIndexedIndirect,
|
DrawIndexedIndirect,
|
||||||
EndComputePass,
|
EndComputePass,
|
||||||
|
EndOcclusionQuery,
|
||||||
EndRenderPass,
|
EndRenderPass,
|
||||||
ExecuteBundles,
|
ExecuteBundles,
|
||||||
InsertDebugMarker,
|
InsertDebugMarker,
|
||||||
|
@ -66,6 +68,11 @@ namespace dawn_native {
|
||||||
|
|
||||||
struct BeginComputePassCmd {};
|
struct BeginComputePassCmd {};
|
||||||
|
|
||||||
|
struct BeginOcclusionQueryCmd {
|
||||||
|
Ref<QuerySetBase> querySet;
|
||||||
|
uint32_t queryIndex;
|
||||||
|
};
|
||||||
|
|
||||||
struct RenderPassColorAttachmentInfo {
|
struct RenderPassColorAttachmentInfo {
|
||||||
Ref<TextureViewBase> view;
|
Ref<TextureViewBase> view;
|
||||||
Ref<TextureViewBase> resolveTarget;
|
Ref<TextureViewBase> resolveTarget;
|
||||||
|
@ -173,6 +180,11 @@ namespace dawn_native {
|
||||||
|
|
||||||
struct EndComputePassCmd {};
|
struct EndComputePassCmd {};
|
||||||
|
|
||||||
|
struct EndOcclusionQueryCmd {
|
||||||
|
Ref<QuerySetBase> querySet;
|
||||||
|
uint32_t queryIndex;
|
||||||
|
};
|
||||||
|
|
||||||
struct EndRenderPassCmd {};
|
struct EndRenderPassCmd {};
|
||||||
|
|
||||||
struct ExecuteBundlesCmd {
|
struct ExecuteBundlesCmd {
|
||||||
|
|
|
@ -52,12 +52,14 @@ namespace dawn_native {
|
||||||
CommandEncoder* commandEncoder,
|
CommandEncoder* commandEncoder,
|
||||||
EncodingContext* encodingContext,
|
EncodingContext* encodingContext,
|
||||||
PassResourceUsageTracker usageTracker,
|
PassResourceUsageTracker usageTracker,
|
||||||
|
QuerySetBase* occlusionQuerySet,
|
||||||
uint32_t renderTargetWidth,
|
uint32_t renderTargetWidth,
|
||||||
uint32_t renderTargetHeight)
|
uint32_t renderTargetHeight)
|
||||||
: RenderEncoderBase(device, encodingContext),
|
: RenderEncoderBase(device, encodingContext),
|
||||||
mCommandEncoder(commandEncoder),
|
mCommandEncoder(commandEncoder),
|
||||||
mRenderTargetWidth(renderTargetWidth),
|
mRenderTargetWidth(renderTargetWidth),
|
||||||
mRenderTargetHeight(renderTargetHeight) {
|
mRenderTargetHeight(renderTargetHeight),
|
||||||
|
mOcclusionQuerySet(occlusionQuerySet) {
|
||||||
mUsageTracker = std::move(usageTracker);
|
mUsageTracker = std::move(usageTracker);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,6 +96,13 @@ namespace dawn_native {
|
||||||
if (mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
if (mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||||
allocator->Allocate<EndRenderPassCmd>(Command::EndRenderPass);
|
allocator->Allocate<EndRenderPassCmd>(Command::EndRenderPass);
|
||||||
|
|
||||||
|
if (GetDevice()->IsValidationEnabled()) {
|
||||||
|
if (mOcclusionQueryActive) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"The occlusion query must be ended before endPass.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
})) {
|
})) {
|
||||||
mEncodingContext->ExitPass(this, mUsageTracker.AcquireResourceUsage());
|
mEncodingContext->ExitPass(this, mUsageTracker.AcquireResourceUsage());
|
||||||
|
@ -208,6 +217,67 @@ namespace dawn_native {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RenderPassEncoder::BeginOcclusionQuery(uint32_t queryIndex) {
|
||||||
|
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||||
|
if (GetDevice()->IsValidationEnabled()) {
|
||||||
|
if (mOcclusionQuerySet.Get() == nullptr) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"The occlusionQuerySet in RenderPassDescriptor must be set.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// The type of querySet has been validated by ValidateRenderPassDescriptor
|
||||||
|
|
||||||
|
if (queryIndex >= mOcclusionQuerySet->GetQueryCount()) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"Query index exceeds the number of queries in query set.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mOcclusionQueryActive) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"Only a single occlusion query can be begun at a time.");
|
||||||
|
}
|
||||||
|
|
||||||
|
DAWN_TRY(ValidateQueryIndexOverwrite(mOcclusionQuerySet.Get(), queryIndex,
|
||||||
|
GetQueryAvailabilityMap()));
|
||||||
|
|
||||||
|
mCommandEncoder->TrackUsedQuerySet(mOcclusionQuerySet.Get());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record the current query index for endOcclusionQuery.
|
||||||
|
mCurrentOcclusionQueryIndex = queryIndex;
|
||||||
|
mOcclusionQueryActive = true;
|
||||||
|
|
||||||
|
BeginOcclusionQueryCmd* cmd =
|
||||||
|
allocator->Allocate<BeginOcclusionQueryCmd>(Command::BeginOcclusionQuery);
|
||||||
|
cmd->querySet = mOcclusionQuerySet.Get();
|
||||||
|
cmd->queryIndex = queryIndex;
|
||||||
|
|
||||||
|
return {};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderPassEncoder::EndOcclusionQuery() {
|
||||||
|
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||||
|
if (GetDevice()->IsValidationEnabled()) {
|
||||||
|
if (!mOcclusionQueryActive) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"EndOcclusionQuery cannot be called without corresponding "
|
||||||
|
"BeginOcclusionQuery.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TrackQueryAvailability(mOcclusionQuerySet.Get(), mCurrentOcclusionQueryIndex);
|
||||||
|
mOcclusionQueryActive = false;
|
||||||
|
|
||||||
|
EndOcclusionQueryCmd* cmd =
|
||||||
|
allocator->Allocate<EndOcclusionQueryCmd>(Command::EndOcclusionQuery);
|
||||||
|
cmd->querySet = mOcclusionQuerySet.Get();
|
||||||
|
cmd->queryIndex = mCurrentOcclusionQueryIndex;
|
||||||
|
|
||||||
|
return {};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void RenderPassEncoder::WriteTimestamp(QuerySetBase* querySet, uint32_t queryIndex) {
|
void RenderPassEncoder::WriteTimestamp(QuerySetBase* querySet, uint32_t queryIndex) {
|
||||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||||
if (GetDevice()->IsValidationEnabled()) {
|
if (GetDevice()->IsValidationEnabled()) {
|
||||||
|
|
|
@ -28,6 +28,7 @@ namespace dawn_native {
|
||||||
CommandEncoder* commandEncoder,
|
CommandEncoder* commandEncoder,
|
||||||
EncodingContext* encodingContext,
|
EncodingContext* encodingContext,
|
||||||
PassResourceUsageTracker usageTracker,
|
PassResourceUsageTracker usageTracker,
|
||||||
|
QuerySetBase* occlusionQuerySet,
|
||||||
uint32_t renderTargetWidth,
|
uint32_t renderTargetWidth,
|
||||||
uint32_t renderTargetHeight);
|
uint32_t renderTargetHeight);
|
||||||
|
|
||||||
|
@ -51,6 +52,9 @@ namespace dawn_native {
|
||||||
void SetScissorRect(uint32_t x, uint32_t y, uint32_t width, uint32_t height);
|
void SetScissorRect(uint32_t x, uint32_t y, uint32_t width, uint32_t height);
|
||||||
void ExecuteBundles(uint32_t count, RenderBundleBase* const* renderBundles);
|
void ExecuteBundles(uint32_t count, RenderBundleBase* const* renderBundles);
|
||||||
|
|
||||||
|
void BeginOcclusionQuery(uint32_t queryIndex);
|
||||||
|
void EndOcclusionQuery();
|
||||||
|
|
||||||
void WriteTimestamp(QuerySetBase* querySet, uint32_t queryIndex);
|
void WriteTimestamp(QuerySetBase* querySet, uint32_t queryIndex);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -71,6 +75,11 @@ namespace dawn_native {
|
||||||
// query cannot be written twice in same render pass, so each render pass also need to have
|
// query cannot be written twice in same render pass, so each render pass also need to have
|
||||||
// its own query availability map.
|
// its own query availability map.
|
||||||
QueryAvailabilityMap mQueryAvailabilityMap;
|
QueryAvailabilityMap mQueryAvailabilityMap;
|
||||||
|
|
||||||
|
// The resources for occlusion query
|
||||||
|
Ref<QuerySetBase> mOcclusionQuerySet;
|
||||||
|
uint32_t mCurrentOcclusionQueryIndex = 0;
|
||||||
|
bool mOcclusionQueryActive = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dawn_native
|
} // namespace dawn_native
|
||||||
|
|
|
@ -1482,6 +1482,14 @@ namespace dawn_native { namespace d3d12 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Command::BeginOcclusionQuery: {
|
||||||
|
return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation.");
|
||||||
|
}
|
||||||
|
|
||||||
|
case Command::EndOcclusionQuery: {
|
||||||
|
return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation.");
|
||||||
|
}
|
||||||
|
|
||||||
case Command::WriteTimestamp: {
|
case Command::WriteTimestamp: {
|
||||||
WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
|
WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
|
||||||
|
|
||||||
|
|
|
@ -1294,6 +1294,14 @@ namespace dawn_native { namespace metal {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Command::BeginOcclusionQuery: {
|
||||||
|
return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation.");
|
||||||
|
}
|
||||||
|
|
||||||
|
case Command::EndOcclusionQuery: {
|
||||||
|
return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation.");
|
||||||
|
}
|
||||||
|
|
||||||
case Command::WriteTimestamp: {
|
case Command::WriteTimestamp: {
|
||||||
WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
|
WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
|
||||||
QuerySet* querySet = ToBackend(cmd->querySet.Get());
|
QuerySet* querySet = ToBackend(cmd->querySet.Get());
|
||||||
|
|
|
@ -1221,6 +1221,14 @@ namespace dawn_native { namespace opengl {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Command::BeginOcclusionQuery: {
|
||||||
|
return DAWN_UNIMPLEMENTED_ERROR("BeginOcclusionQuery unimplemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
case Command::EndOcclusionQuery: {
|
||||||
|
return DAWN_UNIMPLEMENTED_ERROR("EndOcclusionQuery unimplemented.");
|
||||||
|
}
|
||||||
|
|
||||||
case Command::WriteTimestamp:
|
case Command::WriteTimestamp:
|
||||||
return DAWN_UNIMPLEMENTED_ERROR("WriteTimestamp unimplemented");
|
return DAWN_UNIMPLEMENTED_ERROR("WriteTimestamp unimplemented");
|
||||||
|
|
||||||
|
|
|
@ -1222,6 +1222,14 @@ namespace dawn_native { namespace vulkan {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Command::BeginOcclusionQuery: {
|
||||||
|
return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation.");
|
||||||
|
}
|
||||||
|
|
||||||
|
case Command::EndOcclusionQuery: {
|
||||||
|
return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation.");
|
||||||
|
}
|
||||||
|
|
||||||
case Command::WriteTimestamp: {
|
case Command::WriteTimestamp: {
|
||||||
WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
|
WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,146 @@ TEST_F(QuerySetValidationTest, DestroyDestroyedQuerySet) {
|
||||||
querySet.Destroy();
|
querySet.Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class OcclusionQueryValidationTest : public QuerySetValidationTest {};
|
||||||
|
|
||||||
|
// Test the occlusionQuerySet in RenderPassDescriptor
|
||||||
|
TEST_F(OcclusionQueryValidationTest, InvalidOcclusionQuerySet) {
|
||||||
|
wgpu::QuerySet occlusionQuerySet = CreateQuerySet(device, wgpu::QueryType::Occlusion, 2);
|
||||||
|
DummyRenderPass renderPass(device);
|
||||||
|
|
||||||
|
// Success
|
||||||
|
{
|
||||||
|
renderPass.occlusionQuerySet = occlusionQuerySet;
|
||||||
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||||
|
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
|
||||||
|
pass.BeginOcclusionQuery(0);
|
||||||
|
pass.EndOcclusionQuery();
|
||||||
|
pass.BeginOcclusionQuery(1);
|
||||||
|
pass.EndOcclusionQuery();
|
||||||
|
pass.EndPass();
|
||||||
|
encoder.Finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fail to begin occlusion query if the occlusionQuerySet is not set in RenderPassDescriptor
|
||||||
|
{
|
||||||
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||||
|
DummyRenderPass renderPassWithoutOcclusion(device);
|
||||||
|
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPassWithoutOcclusion);
|
||||||
|
pass.BeginOcclusionQuery(0);
|
||||||
|
pass.EndOcclusionQuery();
|
||||||
|
pass.EndPass();
|
||||||
|
ASSERT_DEVICE_ERROR(encoder.Finish());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fail to begin render pass if the occlusionQuerySet is created from other device
|
||||||
|
{
|
||||||
|
wgpu::Device otherDevice = adapter.CreateDevice();
|
||||||
|
wgpu::QuerySet occlusionQuerySetOnOther =
|
||||||
|
CreateQuerySet(otherDevice, wgpu::QueryType::Occlusion, 2);
|
||||||
|
renderPass.occlusionQuerySet = occlusionQuerySetOnOther;
|
||||||
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||||
|
encoder.BeginRenderPass(&renderPass);
|
||||||
|
ASSERT_DEVICE_ERROR(encoder.Finish());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fail to submit occlusion query with a destroyed query set
|
||||||
|
{
|
||||||
|
renderPass.occlusionQuerySet = occlusionQuerySet;
|
||||||
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||||
|
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
|
||||||
|
pass.BeginOcclusionQuery(0);
|
||||||
|
pass.EndOcclusionQuery();
|
||||||
|
pass.EndPass();
|
||||||
|
wgpu::CommandBuffer commands = encoder.Finish();
|
||||||
|
wgpu::Queue queue = device.GetDefaultQueue();
|
||||||
|
occlusionQuerySet.Destroy();
|
||||||
|
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test query index of occlusion query
|
||||||
|
TEST_F(OcclusionQueryValidationTest, InvalidQueryIndex) {
|
||||||
|
wgpu::QuerySet occlusionQuerySet = CreateQuerySet(device, wgpu::QueryType::Occlusion, 2);
|
||||||
|
DummyRenderPass renderPass(device);
|
||||||
|
renderPass.occlusionQuerySet = occlusionQuerySet;
|
||||||
|
|
||||||
|
// Fail to begin occlusion query if the query index exceeds the number of queries in query set
|
||||||
|
{
|
||||||
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||||
|
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
|
||||||
|
pass.BeginOcclusionQuery(2);
|
||||||
|
pass.EndOcclusionQuery();
|
||||||
|
pass.EndPass();
|
||||||
|
ASSERT_DEVICE_ERROR(encoder.Finish());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success to begin occlusion query with same query index twice on different render encoder
|
||||||
|
{
|
||||||
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||||
|
wgpu::RenderPassEncoder pass0 = encoder.BeginRenderPass(&renderPass);
|
||||||
|
pass0.BeginOcclusionQuery(0);
|
||||||
|
pass0.EndOcclusionQuery();
|
||||||
|
pass0.EndPass();
|
||||||
|
|
||||||
|
wgpu::RenderPassEncoder pass1 = encoder.BeginRenderPass(&renderPass);
|
||||||
|
pass1.BeginOcclusionQuery(0);
|
||||||
|
pass1.EndOcclusionQuery();
|
||||||
|
pass1.EndPass();
|
||||||
|
encoder.Finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fail to begin occlusion query with same query index twice on a same render encoder
|
||||||
|
{
|
||||||
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||||
|
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
|
||||||
|
pass.BeginOcclusionQuery(0);
|
||||||
|
pass.EndOcclusionQuery();
|
||||||
|
pass.BeginOcclusionQuery(0);
|
||||||
|
pass.EndOcclusionQuery();
|
||||||
|
pass.EndPass();
|
||||||
|
ASSERT_DEVICE_ERROR(encoder.Finish());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test the correspondence between BeginOcclusionQuery and EndOcclusionQuery
|
||||||
|
TEST_F(OcclusionQueryValidationTest, InvalidBeginAndEnd) {
|
||||||
|
wgpu::QuerySet occlusionQuerySet = CreateQuerySet(device, wgpu::QueryType::Occlusion, 2);
|
||||||
|
DummyRenderPass renderPass(device);
|
||||||
|
renderPass.occlusionQuerySet = occlusionQuerySet;
|
||||||
|
|
||||||
|
// Fail to begin an occlusion query without corresponding end operation
|
||||||
|
{
|
||||||
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||||
|
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
|
||||||
|
pass.BeginOcclusionQuery(0);
|
||||||
|
pass.BeginOcclusionQuery(1);
|
||||||
|
pass.EndOcclusionQuery();
|
||||||
|
pass.EndPass();
|
||||||
|
ASSERT_DEVICE_ERROR(encoder.Finish());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fail to end occlusion query twice in a row even the begin occlusion query twice
|
||||||
|
{
|
||||||
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||||
|
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
|
||||||
|
pass.BeginOcclusionQuery(0);
|
||||||
|
pass.BeginOcclusionQuery(1);
|
||||||
|
pass.EndOcclusionQuery();
|
||||||
|
pass.EndOcclusionQuery();
|
||||||
|
pass.EndPass();
|
||||||
|
ASSERT_DEVICE_ERROR(encoder.Finish());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fail to end occlusion query without begin operation
|
||||||
|
{
|
||||||
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||||
|
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
|
||||||
|
pass.EndOcclusionQuery();
|
||||||
|
pass.EndPass();
|
||||||
|
ASSERT_DEVICE_ERROR(encoder.Finish());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class TimestampQueryValidationTest : public QuerySetValidationTest {
|
class TimestampQueryValidationTest : public QuerySetValidationTest {
|
||||||
protected:
|
protected:
|
||||||
wgpu::Device CreateTestDevice() override {
|
wgpu::Device CreateTestDevice() override {
|
||||||
|
@ -101,6 +241,18 @@ TEST_F(TimestampQueryValidationTest, UnnecessaryPipelineStatistics) {
|
||||||
{wgpu::PipelineStatisticName::VertexShaderInvocations}));
|
{wgpu::PipelineStatisticName::VertexShaderInvocations}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test query set with type of timestamp is set to the occlusionQuerySet of RenderPassDescriptor.
|
||||||
|
TEST_F(TimestampQueryValidationTest, BeginRenderPassWithTimestampQuerySet) {
|
||||||
|
// Fail to begin render pass if the type of occlusionQuerySet is not Occlusion
|
||||||
|
wgpu::QuerySet querySet = CreateQuerySet(device, wgpu::QueryType::Timestamp, 1);
|
||||||
|
DummyRenderPass renderPass(device);
|
||||||
|
renderPass.occlusionQuerySet = querySet;
|
||||||
|
|
||||||
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||||
|
encoder.BeginRenderPass(&renderPass);
|
||||||
|
ASSERT_DEVICE_ERROR(encoder.Finish());
|
||||||
|
}
|
||||||
|
|
||||||
// Test write timestamp on command encoder
|
// Test write timestamp on command encoder
|
||||||
TEST_F(TimestampQueryValidationTest, WriteTimestampOnCommandEncoder) {
|
TEST_F(TimestampQueryValidationTest, WriteTimestampOnCommandEncoder) {
|
||||||
wgpu::QuerySet timestampQuerySet = CreateQuerySet(device, wgpu::QueryType::Timestamp, 2);
|
wgpu::QuerySet timestampQuerySet = CreateQuerySet(device, wgpu::QueryType::Timestamp, 2);
|
||||||
|
@ -311,6 +463,21 @@ TEST_F(PipelineStatisticsQueryValidationTest, InvalidPipelineStatistics) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test query set with type of pipeline statistics is set to the occlusionQuerySet of
|
||||||
|
// RenderPassDescriptor.
|
||||||
|
TEST_F(PipelineStatisticsQueryValidationTest, BeginRenderPassWithPipelineStatisticsQuerySet) {
|
||||||
|
// Fail to begin render pass if the type of occlusionQuerySet is not Occlusion
|
||||||
|
wgpu::QuerySet querySet =
|
||||||
|
CreateQuerySet(device, wgpu::QueryType::PipelineStatistics, 1,
|
||||||
|
{wgpu::PipelineStatisticName::VertexShaderInvocations});
|
||||||
|
DummyRenderPass renderPass(device);
|
||||||
|
renderPass.occlusionQuerySet = querySet;
|
||||||
|
|
||||||
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||||
|
encoder.BeginRenderPass(&renderPass);
|
||||||
|
ASSERT_DEVICE_ERROR(encoder.Finish());
|
||||||
|
}
|
||||||
|
|
||||||
class ResolveQuerySetValidationTest : public QuerySetValidationTest {
|
class ResolveQuerySetValidationTest : public QuerySetValidationTest {
|
||||||
protected:
|
protected:
|
||||||
wgpu::Buffer CreateBuffer(wgpu::Device cDevice, uint64_t size, wgpu::BufferUsage usage) {
|
wgpu::Buffer CreateBuffer(wgpu::Device cDevice, uint64_t size, wgpu::BufferUsage usage) {
|
||||||
|
|
|
@ -167,3 +167,32 @@ TEST_F(UnsafeAPIValidationTest, DynamicStorageBuffer) {
|
||||||
ASSERT_DEVICE_ERROR(device.CreateBindGroupLayout(&desc));
|
ASSERT_DEVICE_ERROR(device.CreateBindGroupLayout(&desc));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check that occlusion query is disallowed as part of unsafe APIs.
|
||||||
|
TEST_F(UnsafeAPIValidationTest, OcclusionQueryDisallowed) {
|
||||||
|
DummyRenderPass renderPass(device);
|
||||||
|
|
||||||
|
// Control case: BeginRenderPass without occlusionQuerySet is allowed.
|
||||||
|
{
|
||||||
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||||
|
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
|
||||||
|
|
||||||
|
pass.EndPass();
|
||||||
|
encoder.Finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error case: BeginRenderPass with occlusionQuerySet is disallowed.
|
||||||
|
{
|
||||||
|
wgpu::QuerySetDescriptor descriptor;
|
||||||
|
descriptor.type = wgpu::QueryType::Occlusion;
|
||||||
|
descriptor.count = 1;
|
||||||
|
wgpu::QuerySet querySet = device.CreateQuerySet(&descriptor);
|
||||||
|
renderPass.occlusionQuerySet = querySet;
|
||||||
|
|
||||||
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||||
|
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
|
||||||
|
|
||||||
|
pass.EndPass();
|
||||||
|
ASSERT_DEVICE_ERROR(encoder.Finish());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue