Query API: WriteTimestamp

Add WriteTimestamp API on CommandEncoder, ComputePassEncoder and
RenderPassEncoder.

Bug: dawn:434
Change-Id: Ifeca4efed01d80459d6fefa22ba05bea699b541f
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/23244
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Hao Li <hao.x.li@intel.com>
This commit is contained in:
Hao Li 2020-07-01 10:48:16 +00:00 committed by Commit Bot service account
parent 2ffc55ab38
commit 5191adc58c
23 changed files with 421 additions and 41 deletions

View File

@ -391,6 +391,13 @@
"args": [
{"name": "group label", "type": "char", "annotation": "const*", "length": "strlen"}
]
},
{
"name": "write timestamp",
"args": [
{"name": "query set", "type": "query set"},
{"name": "query index", "type": "uint32_t"}
]
}
]
},
@ -456,6 +463,13 @@
{"name": "dynamic offsets", "type": "uint32_t", "annotation": "const*", "length": "dynamic offset count", "optional": true}
]
},
{
"name": "write timestamp",
"args": [
{"name": "query set", "type": "query set"},
{"name": "query index", "type": "uint32_t"}
]
},
{
"name": "dispatch",
"args": [
@ -1261,6 +1275,13 @@
{"name": "size", "type": "uint64_t", "default": "0"}
]
},
{
"name": "write timestamp",
"args": [
{"name": "query set", "type": "query set"},
{"name": "query index", "type": "uint32_t"}
]
},
{
"name": "end pass"
}

View File

@ -24,6 +24,7 @@
#include "dawn_native/ComputePassEncoder.h"
#include "dawn_native/Device.h"
#include "dawn_native/ErrorData.h"
#include "dawn_native/QuerySet.h"
#include "dawn_native/RenderPassEncoder.h"
#include "dawn_native/RenderPipeline.h"
#include "dawn_native/ValidationUtils_autogen.h"
@ -529,14 +530,18 @@ namespace dawn_native {
CommandBufferResourceUsage CommandEncoder::AcquireResourceUsages() {
return CommandBufferResourceUsage{mEncodingContext.AcquirePassUsages(),
std::move(mTopLevelBuffers),
std::move(mTopLevelTextures)};
std::move(mTopLevelBuffers), std::move(mTopLevelTextures),
std::move(mUsedQuerySets)};
}
CommandIterator CommandEncoder::AcquireCommands() {
return mEncodingContext.AcquireCommands();
}
void CommandEncoder::TrackUsedQuerySet(QuerySetBase* querySet) {
mUsedQuerySets.insert(querySet);
}
// Implementation of the API's command recording methods
ComputePassEncoder* CommandEncoder::BeginComputePass(const ComputePassDescriptor* descriptor) {
@ -893,6 +898,23 @@ namespace dawn_native {
});
}
void CommandEncoder::WriteTimestamp(QuerySetBase* querySet, uint32_t queryIndex) {
mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
if (GetDevice()->IsValidationEnabled()) {
DAWN_TRY(GetDevice()->ValidateObject(querySet));
DAWN_TRY(ValidateTimestampQuery(querySet, queryIndex));
TrackUsedQuerySet(querySet);
}
WriteTimestampCmd* cmd =
allocator->Allocate<WriteTimestampCmd>(Command::WriteTimestamp);
cmd->querySet = querySet;
cmd->queryIndex = queryIndex;
return {};
});
}
CommandBufferBase* CommandEncoder::Finish(const CommandBufferDescriptor* descriptor) {
DeviceBase* device = GetDevice();
// Even if mEncodingContext.Finish() validation fails, calling it will mutate the internal
@ -976,6 +998,11 @@ namespace dawn_native {
debugGroupStackSize++;
break;
}
case Command::WriteTimestamp: {
commands->NextCommand<WriteTimestampCmd>();
break;
}
default:
return DAWN_VALIDATION_ERROR("Command disallowed outside of a pass");
}

View File

@ -35,6 +35,8 @@ namespace dawn_native {
CommandIterator AcquireCommands();
CommandBufferResourceUsage AcquireResourceUsages();
void TrackUsedQuerySet(QuerySetBase* querySet);
// Dawn API
ComputePassEncoder* BeginComputePass(const ComputePassDescriptor* descriptor);
RenderPassEncoder* BeginRenderPass(const RenderPassDescriptor* descriptor);
@ -58,6 +60,8 @@ namespace dawn_native {
void PopDebugGroup();
void PushDebugGroup(const char* groupLabel);
void WriteTimestamp(QuerySetBase* querySet, uint32_t queryIndex);
CommandBufferBase* Finish(const CommandBufferDescriptor* descriptor);
private:
@ -67,6 +71,7 @@ namespace dawn_native {
EncodingContext mEncodingContext;
std::set<BufferBase*> mTopLevelBuffers;
std::set<TextureBase*> mTopLevelTextures;
std::set<QuerySetBase*> mUsedQuerySets;
};
} // namespace dawn_native

View File

@ -20,6 +20,7 @@
#include "dawn_native/CommandBufferStateTracker.h"
#include "dawn_native/Commands.h"
#include "dawn_native/PassResourceUsage.h"
#include "dawn_native/QuerySet.h"
#include "dawn_native/RenderBundle.h"
#include "dawn_native/RenderPipeline.h"
@ -202,6 +203,11 @@ namespace dawn_native {
break;
}
case Command::WriteTimestamp: {
commands->NextCommand<WriteTimestampCmd>();
break;
}
default:
DAWN_TRY(ValidateRenderBundleCommand(
commands, type, &commandBufferState, renderPass->attachmentState.Get(),
@ -274,6 +280,11 @@ namespace dawn_native {
break;
}
case Command::WriteTimestamp: {
commands->NextCommand<WriteTimestampCmd>();
break;
}
default:
return DAWN_VALIDATION_ERROR("Command disallowed inside a compute pass");
}
@ -339,6 +350,18 @@ namespace dawn_native {
return {};
}
MaybeError ValidateTimestampQuery(QuerySetBase* querySet, uint32_t queryIndex) {
if (querySet->GetQueryType() != wgpu::QueryType::Timestamp) {
return DAWN_VALIDATION_ERROR("The query type of query set must be Timestamp");
}
if (queryIndex >= querySet->GetQueryCount()) {
return DAWN_VALIDATION_ERROR("Query index exceeds the number of queries in query set");
}
return {};
}
bool IsRangeOverlapped(uint32_t startA, uint32_t startB, uint32_t length) {
uint32_t maxStart = std::max(startA, startB);
uint32_t minStart = std::min(startA, startB);

View File

@ -23,6 +23,7 @@
namespace dawn_native {
class AttachmentState;
class QuerySetBase;
struct BeginRenderPassCmd;
struct PassResourceUsage;
@ -36,6 +37,8 @@ namespace dawn_native {
MaybeError ValidatePassResourceUsage(const PassResourceUsage& usage);
MaybeError ValidateTimestampQuery(QuerySetBase* querySet, uint32_t queryIndex);
bool IsRangeOverlapped(uint32_t startA, uint32_t startB, uint32_t length);
} // namespace dawn_native

View File

@ -18,6 +18,7 @@
#include "dawn_native/Buffer.h"
#include "dawn_native/CommandAllocator.h"
#include "dawn_native/ComputePipeline.h"
#include "dawn_native/QuerySet.h"
#include "dawn_native/RenderBundle.h"
#include "dawn_native/RenderPipeline.h"
#include "dawn_native/Texture.h"
@ -175,6 +176,11 @@ namespace dawn_native {
cmd->~SetVertexBufferCmd();
break;
}
case Command::WriteTimestamp: {
WriteTimestampCmd* cmd = commands->NextCommand<WriteTimestampCmd>();
cmd->~WriteTimestampCmd();
break;
}
}
}
commands->DataWasDestroyed();
@ -300,6 +306,11 @@ namespace dawn_native {
commands->NextCommand<SetVertexBufferCmd>();
break;
}
case Command::WriteTimestamp: {
commands->NextCommand<WriteTimestampCmd>();
break;
}
}
}

View File

@ -60,6 +60,7 @@ namespace dawn_native {
SetBindGroup,
SetIndexBuffer,
SetVertexBuffer,
WriteTimestamp,
};
struct BeginComputePassCmd {};
@ -228,6 +229,11 @@ namespace dawn_native {
uint64_t size;
};
struct WriteTimestampCmd {
Ref<QuerySetBase> querySet;
uint32_t queryIndex;
};
// This needs to be called before the CommandIterator is freed so that the Ref<> present in
// the commands have a chance to run their destructor and remove internal references.
class CommandIterator;

View File

@ -16,9 +16,11 @@
#include "dawn_native/Buffer.h"
#include "dawn_native/CommandEncoder.h"
#include "dawn_native/CommandValidation.h"
#include "dawn_native/Commands.h"
#include "dawn_native/ComputePipeline.h"
#include "dawn_native/Device.h"
#include "dawn_native/QuerySet.h"
namespace dawn_native {
@ -96,4 +98,21 @@ namespace dawn_native {
});
}
void ComputePassEncoder::WriteTimestamp(QuerySetBase* querySet, uint32_t queryIndex) {
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
if (GetDevice()->IsValidationEnabled()) {
DAWN_TRY(GetDevice()->ValidateObject(querySet));
DAWN_TRY(ValidateTimestampQuery(querySet, queryIndex));
mCommandEncoder->TrackUsedQuerySet(querySet);
}
WriteTimestampCmd* cmd =
allocator->Allocate<WriteTimestampCmd>(Command::WriteTimestamp);
cmd->querySet = querySet;
cmd->queryIndex = queryIndex;
return {};
});
}
} // namespace dawn_native

View File

@ -36,6 +36,8 @@ namespace dawn_native {
void DispatchIndirect(BufferBase* indirectBuffer, uint64_t indirectOffset);
void SetPipeline(ComputePipelineBase* pipeline);
void WriteTimestamp(QuerySetBase* querySet, uint32_t queryIndex);
protected:
ComputePassEncoder(DeviceBase* device,
CommandEncoder* commandEncoder,

View File

@ -23,6 +23,7 @@
namespace dawn_native {
class BufferBase;
class QuerySetBase;
class TextureBase;
enum class PassType { Render, Compute };
@ -68,6 +69,7 @@ namespace dawn_native {
PerPassUsages perPass;
std::set<BufferBase*> topLevelBuffers;
std::set<TextureBase*> topLevelTextures;
std::set<QuerySetBase*> usedQuerySets;
};
} // namespace dawn_native

View File

@ -131,6 +131,14 @@ namespace dawn_native {
return mPipelineStatistics;
}
MaybeError QuerySetBase::ValidateCanUseInSubmitNow() const {
ASSERT(!IsError());
if (mState == QuerySetState::Destroyed) {
return DAWN_VALIDATION_ERROR("Destroyed query set used in a submit");
}
return {};
}
void QuerySetBase::Destroy() {
if (GetDevice()->ConsumedError(ValidateDestroy())) {
return;

View File

@ -35,6 +35,8 @@ namespace dawn_native {
uint32_t GetQueryCount() const;
const std::vector<wgpu::PipelineStatisticsName>& GetPipelineStatistics() const;
MaybeError ValidateCanUseInSubmitNow() const;
void Destroy();
protected:

View File

@ -22,6 +22,7 @@
#include "dawn_native/ErrorScopeTracker.h"
#include "dawn_native/Fence.h"
#include "dawn_native/FenceSignalTracker.h"
#include "dawn_native/QuerySet.h"
#include "dawn_native/Texture.h"
#include "dawn_platform/DawnPlatform.h"
#include "dawn_platform/tracing/TraceEvent.h"
@ -155,6 +156,9 @@ namespace dawn_native {
for (const TextureBase* texture : usages.topLevelTextures) {
DAWN_TRY(texture->ValidateCanUseInSubmitNow());
}
for (const QuerySetBase* querySet : usages.usedQuerySets) {
DAWN_TRY(querySet->ValidateCanUseInSubmitNow());
}
}
return {};

View File

@ -17,8 +17,10 @@
#include "common/Constants.h"
#include "dawn_native/Buffer.h"
#include "dawn_native/CommandEncoder.h"
#include "dawn_native/CommandValidation.h"
#include "dawn_native/Commands.h"
#include "dawn_native/Device.h"
#include "dawn_native/QuerySet.h"
#include "dawn_native/RenderBundle.h"
#include "dawn_native/RenderPipeline.h"
@ -163,4 +165,21 @@ namespace dawn_native {
});
}
void RenderPassEncoder::WriteTimestamp(QuerySetBase* querySet, uint32_t queryIndex) {
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
if (GetDevice()->IsValidationEnabled()) {
DAWN_TRY(GetDevice()->ValidateObject(querySet));
DAWN_TRY(ValidateTimestampQuery(querySet, queryIndex));
mCommandEncoder->TrackUsedQuerySet(querySet);
}
WriteTimestampCmd* cmd =
allocator->Allocate<WriteTimestampCmd>(Command::WriteTimestamp);
cmd->querySet = querySet;
cmd->queryIndex = queryIndex;
return {};
});
}
} // namespace dawn_native

View File

@ -46,6 +46,8 @@ namespace dawn_native {
void SetScissorRect(uint32_t x, uint32_t y, uint32_t width, uint32_t height);
void ExecuteBundles(uint32_t count, RenderBundleBase* const* renderBundles);
void WriteTimestamp(QuerySetBase* querySet, uint32_t queryIndex);
protected:
RenderPassEncoder(DeviceBase* device,
CommandEncoder* commandEncoder,

View File

@ -754,6 +754,10 @@ namespace dawn_native { namespace d3d12 {
break;
}
case Command::WriteTimestamp: {
return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation.");
}
default: {
UNREACHABLE();
break;
@ -864,6 +868,10 @@ namespace dawn_native { namespace d3d12 {
break;
}
case Command::WriteTimestamp: {
return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation.");
}
default: {
UNREACHABLE();
break;
@ -1280,6 +1288,10 @@ namespace dawn_native { namespace d3d12 {
break;
}
case Command::WriteTimestamp: {
return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation.");
}
default: {
DAWN_TRY(EncodeRenderBundleCommand(&mCommands, type));
break;

View File

@ -17,6 +17,7 @@
#include "dawn_native/CommandAllocator.h"
#include "dawn_native/CommandBuffer.h"
#include "dawn_native/Error.h"
#import <Metal/Metal.h>
@ -33,20 +34,20 @@ namespace dawn_native { namespace metal {
public:
CommandBuffer(CommandEncoder* encoder, const CommandBufferDescriptor* descriptor);
void FillCommands(CommandRecordingContext* commandContext);
MaybeError FillCommands(CommandRecordingContext* commandContext);
private:
~CommandBuffer() override;
void EncodeComputePass(CommandRecordingContext* commandContext);
void EncodeRenderPass(CommandRecordingContext* commandContext,
MTLRenderPassDescriptor* mtlRenderPass,
uint32_t width,
uint32_t height);
MaybeError EncodeComputePass(CommandRecordingContext* commandContext);
MaybeError EncodeRenderPass(CommandRecordingContext* commandContext,
MTLRenderPassDescriptor* mtlRenderPass,
uint32_t width,
uint32_t height);
void EncodeRenderPassInternal(CommandRecordingContext* commandContext,
MTLRenderPassDescriptor* mtlRenderPass,
uint32_t width,
uint32_t height);
MaybeError EncodeRenderPassInternal(CommandRecordingContext* commandContext,
MTLRenderPassDescriptor* mtlRenderPass,
uint32_t width,
uint32_t height);
CommandIterator mCommands;
};

View File

@ -673,7 +673,7 @@ namespace dawn_native { namespace metal {
FreeCommands(&mCommands);
}
void CommandBuffer::FillCommands(CommandRecordingContext* commandContext) {
MaybeError CommandBuffer::FillCommands(CommandRecordingContext* commandContext) {
const std::vector<PassResourceUsage>& passResourceUsages = GetResourceUsages().perPass;
size_t nextPassNumber = 0;
@ -698,7 +698,7 @@ namespace dawn_native { namespace metal {
LazyClearForPass(passResourceUsages[nextPassNumber]);
commandContext->EndBlit();
EncodeComputePass(commandContext);
DAWN_TRY(EncodeComputePass(commandContext));
nextPassNumber++;
break;
@ -712,7 +712,7 @@ namespace dawn_native { namespace metal {
LazyClearRenderPassAttachments(cmd);
MTLRenderPassDescriptor* descriptor = CreateMTLRenderPassDescriptor(cmd);
EncodeRenderPass(commandContext, descriptor, cmd->width, cmd->height);
DAWN_TRY(EncodeRenderPass(commandContext, descriptor, cmd->width, cmd->height));
nextPassNumber++;
break;
@ -859,6 +859,10 @@ namespace dawn_native { namespace metal {
break;
}
case Command::WriteTimestamp: {
return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation.");
}
default: {
UNREACHABLE();
break;
@ -867,9 +871,10 @@ namespace dawn_native { namespace metal {
}
commandContext->EndBlit();
return {};
}
void CommandBuffer::EncodeComputePass(CommandRecordingContext* commandContext) {
MaybeError CommandBuffer::EncodeComputePass(CommandRecordingContext* commandContext) {
ComputePipeline* lastPipeline = nullptr;
StorageBufferLengthTracker storageBufferLengths = {};
BindGroupTracker bindGroups(&storageBufferLengths);
@ -882,7 +887,7 @@ namespace dawn_native { namespace metal {
case Command::EndComputePass: {
mCommands.NextCommand<EndComputePassCmd>();
commandContext->EndCompute();
return;
return {};
}
case Command::Dispatch: {
@ -960,6 +965,10 @@ namespace dawn_native { namespace metal {
break;
}
case Command::WriteTimestamp: {
return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation.");
}
default: {
UNREACHABLE();
break;
@ -971,10 +980,10 @@ namespace dawn_native { namespace metal {
UNREACHABLE();
}
void CommandBuffer::EncodeRenderPass(CommandRecordingContext* commandContext,
MTLRenderPassDescriptor* mtlRenderPass,
uint32_t width,
uint32_t height) {
MaybeError CommandBuffer::EncodeRenderPass(CommandRecordingContext* commandContext,
MTLRenderPassDescriptor* mtlRenderPass,
uint32_t width,
uint32_t height) {
ASSERT(mtlRenderPass);
Device* device = ToBackend(GetDevice());
@ -1018,7 +1027,7 @@ namespace dawn_native { namespace metal {
// If we need to use a temporary resolve texture we need to copy the result of MSAA
// resolve back to the true resolve targets.
if (useTemporaryResolveTexture) {
EncodeRenderPass(commandContext, mtlRenderPass, width, height);
DAWN_TRY(EncodeRenderPass(commandContext, mtlRenderPass, width, height));
for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
if (trueResolveTextures[i] == nil) {
continue;
@ -1031,7 +1040,7 @@ namespace dawn_native { namespace metal {
[temporaryResolveTextures[i] release];
temporaryResolveTextures[i] = nil;
}
return;
return {};
}
}
@ -1054,19 +1063,20 @@ namespace dawn_native { namespace metal {
// If we found a store + MSAA resolve we need to resolve in a different render pass.
if (hasStoreAndMSAAResolve) {
EncodeRenderPass(commandContext, mtlRenderPass, width, height);
DAWN_TRY(EncodeRenderPass(commandContext, mtlRenderPass, width, height));
ResolveInAnotherRenderPass(commandContext, mtlRenderPass, resolveTextures);
return;
return {};
}
}
EncodeRenderPassInternal(commandContext, mtlRenderPass, width, height);
DAWN_TRY(EncodeRenderPassInternal(commandContext, mtlRenderPass, width, height));
return {};
}
void CommandBuffer::EncodeRenderPassInternal(CommandRecordingContext* commandContext,
MTLRenderPassDescriptor* mtlRenderPass,
uint32_t width,
uint32_t height) {
MaybeError CommandBuffer::EncodeRenderPassInternal(CommandRecordingContext* commandContext,
MTLRenderPassDescriptor* mtlRenderPass,
uint32_t width,
uint32_t height) {
RenderPipeline* lastPipeline = nullptr;
id<MTLBuffer> indexBuffer = nil;
uint32_t indexBufferBaseOffset = 0;
@ -1256,7 +1266,7 @@ namespace dawn_native { namespace metal {
case Command::EndRenderPass: {
mCommands.NextCommand<EndRenderPassCmd>();
commandContext->EndRender();
return;
return {};
}
case Command::SetStencilReference: {
@ -1323,6 +1333,10 @@ namespace dawn_native { namespace metal {
break;
}
case Command::WriteTimestamp: {
return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation.");
}
default: {
EncodeRenderBundleCommand(&mCommands, type);
break;

View File

@ -31,7 +31,7 @@ namespace dawn_native { namespace metal {
TRACE_EVENT_BEGIN0(GetDevice()->GetPlatform(), Recording, "CommandBufferMTL::FillCommands");
for (uint32_t i = 0; i < commandCount; ++i) {
ToBackend(commands[i])->FillCommands(commandContext);
DAWN_TRY(ToBackend(commands[i])->FillCommands(commandContext));
}
TRACE_EVENT_END0(GetDevice()->GetPlatform(), Recording, "CommandBufferMTL::FillCommands");

View File

@ -712,6 +712,12 @@ namespace dawn_native { namespace opengl {
break;
}
case Command::WriteTimestamp: {
// WriteTimestamp is not supported on OpenGL
UNREACHABLE();
break;
}
default: {
UNREACHABLE();
break;
@ -786,6 +792,12 @@ namespace dawn_native { namespace opengl {
break;
}
case Command::WriteTimestamp: {
// WriteTimestamp is not supported on OpenGL
UNREACHABLE();
break;
}
default: {
UNREACHABLE();
break;
@ -1137,6 +1149,12 @@ namespace dawn_native { namespace opengl {
break;
}
case Command::WriteTimestamp: {
// WriteTimestamp is not supported on OpenGL
UNREACHABLE();
break;
}
default: {
DoRenderBundleCommand(&mCommands, type);
break;

View File

@ -589,12 +589,16 @@ namespace dawn_native { namespace vulkan {
mCommands.NextCommand<BeginComputePassCmd>();
TransitionForPass(device, recordingContext, passResourceUsages[nextPassNumber]);
RecordComputePass(recordingContext);
DAWN_TRY(RecordComputePass(recordingContext));
nextPassNumber++;
break;
}
case Command::WriteTimestamp: {
return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation.");
}
default: {
UNREACHABLE();
break;
@ -605,7 +609,7 @@ namespace dawn_native { namespace vulkan {
return {};
}
void CommandBuffer::RecordComputePass(CommandRecordingContext* recordingContext) {
MaybeError CommandBuffer::RecordComputePass(CommandRecordingContext* recordingContext) {
Device* device = ToBackend(GetDevice());
VkCommandBuffer commands = recordingContext->commandBuffer;
@ -616,7 +620,7 @@ namespace dawn_native { namespace vulkan {
switch (type) {
case Command::EndComputePass: {
mCommands.NextCommand<EndComputePassCmd>();
return;
return {};
}
case Command::Dispatch: {
@ -712,6 +716,10 @@ namespace dawn_native { namespace vulkan {
break;
}
case Command::WriteTimestamp: {
return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation.");
}
default: {
UNREACHABLE();
break;
@ -981,6 +989,10 @@ namespace dawn_native { namespace vulkan {
break;
}
case Command::WriteTimestamp: {
return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation.");
}
default: {
EncodeRenderBundleCommand(&mCommands, type);
break;

View File

@ -42,7 +42,7 @@ namespace dawn_native { namespace vulkan {
CommandBuffer(CommandEncoder* encoder, const CommandBufferDescriptor* descriptor);
~CommandBuffer() override;
void RecordComputePass(CommandRecordingContext* recordingContext);
MaybeError RecordComputePass(CommandRecordingContext* recordingContext);
MaybeError RecordRenderPass(CommandRecordingContext* recordingContext,
BeginRenderPassCmd* renderPass);
void RecordCopyImageWithTemporaryBuffer(CommandRecordingContext* recordingContext,

View File

@ -27,10 +27,11 @@ class QuerySetValidationTest : public ValidationTest {
deviceWithTimestamp = CreateDeviceFromAdapter(adapter, {"timestamp_query"});
}
void CreateQuerySet(wgpu::Device cDevice,
wgpu::QueryType queryType,
uint32_t queryCount,
std::vector<wgpu::PipelineStatisticsName> pipelineStatistics = {}) {
wgpu::QuerySet CreateQuerySet(
wgpu::Device cDevice,
wgpu::QueryType queryType,
uint32_t queryCount,
std::vector<wgpu::PipelineStatisticsName> pipelineStatistics = {}) {
wgpu::QuerySetDescriptor descriptor;
descriptor.type = queryType;
descriptor.count = queryCount;
@ -40,7 +41,7 @@ class QuerySetValidationTest : public ValidationTest {
descriptor.pipelineStatisticsCount = pipelineStatistics.size();
}
cDevice.CreateQuerySet(&descriptor);
return cDevice.CreateQuerySet(&descriptor);
}
wgpu::Device deviceWithPipelineStatistics;
@ -148,3 +149,171 @@ TEST_F(QuerySetValidationTest, DestroyDestroyedQuerySet) {
querySet.Destroy();
querySet.Destroy();
}
class TimestampQueryValidationTest : public QuerySetValidationTest {};
// Test write timestamp on command encoder
TEST_F(TimestampQueryValidationTest, WriteTimestampOnCommandEncoder) {
wgpu::QuerySet timestampQuerySet =
CreateQuerySet(deviceWithTimestamp, wgpu::QueryType::Timestamp, 2);
wgpu::QuerySet occlusionQuerySet =
CreateQuerySet(deviceWithTimestamp, wgpu::QueryType::Occlusion, 2);
// Success on command encoder
{
wgpu::CommandEncoder encoder = deviceWithTimestamp.CreateCommandEncoder();
encoder.WriteTimestamp(timestampQuerySet, 0);
encoder.Finish();
}
// Not allow to write timestamp from another device
{
// Write timestamp from default device
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
encoder.WriteTimestamp(timestampQuerySet, 0);
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Not allow to write timestamp to the query set with other query type
{
wgpu::CommandEncoder encoder = deviceWithTimestamp.CreateCommandEncoder();
encoder.WriteTimestamp(occlusionQuerySet, 0);
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Fail to write timestamp to the index which exceeds the number of queries in query set
{
wgpu::CommandEncoder encoder = deviceWithTimestamp.CreateCommandEncoder();
encoder.WriteTimestamp(timestampQuerySet, 2);
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Fail to submit timestamp query with a destroyed query set
{
wgpu::CommandEncoder encoder = deviceWithTimestamp.CreateCommandEncoder();
encoder.WriteTimestamp(timestampQuerySet, 0);
wgpu::CommandBuffer commands = encoder.Finish();
wgpu::Queue queue = deviceWithTimestamp.GetDefaultQueue();
timestampQuerySet.Destroy();
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
}
}
// Test write timestamp on compute pass encoder
TEST_F(TimestampQueryValidationTest, WriteTimestampOnComputePassEncoder) {
wgpu::QuerySet timestampQuerySet =
CreateQuerySet(deviceWithTimestamp, wgpu::QueryType::Timestamp, 2);
wgpu::QuerySet occlusionQuerySet =
CreateQuerySet(deviceWithTimestamp, wgpu::QueryType::Occlusion, 2);
// Success on compute pass encoder
{
wgpu::CommandEncoder encoder = deviceWithTimestamp.CreateCommandEncoder();
wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
pass.WriteTimestamp(timestampQuerySet, 0);
pass.EndPass();
encoder.Finish();
}
// Not allow to write timestamp from another device
{
// Write timestamp from default device
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
pass.WriteTimestamp(timestampQuerySet, 0);
pass.EndPass();
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Not allow to write timestamp to the query set with other query type
{
wgpu::CommandEncoder encoder = deviceWithTimestamp.CreateCommandEncoder();
wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
pass.WriteTimestamp(occlusionQuerySet, 0);
pass.EndPass();
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Fail to write timestamp to the index which exceeds the number of queries in query set
{
wgpu::CommandEncoder encoder = deviceWithTimestamp.CreateCommandEncoder();
wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
pass.WriteTimestamp(timestampQuerySet, 2);
pass.EndPass();
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Fail to submit timestamp query with a destroyed query set
{
wgpu::CommandEncoder encoder = deviceWithTimestamp.CreateCommandEncoder();
wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
pass.WriteTimestamp(timestampQuerySet, 0);
pass.EndPass();
wgpu::CommandBuffer commands = encoder.Finish();
wgpu::Queue queue = deviceWithTimestamp.GetDefaultQueue();
timestampQuerySet.Destroy();
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
}
}
// Test write timestamp on render pass encoder
TEST_F(TimestampQueryValidationTest, WriteTimestampOnRenderPassEncoder) {
DummyRenderPass renderPass(deviceWithTimestamp);
wgpu::QuerySet timestampQuerySet =
CreateQuerySet(deviceWithTimestamp, wgpu::QueryType::Timestamp, 2);
wgpu::QuerySet occlusionQuerySet =
CreateQuerySet(deviceWithTimestamp, wgpu::QueryType::Occlusion, 2);
// Success on render pass encoder
{
wgpu::CommandEncoder encoder = deviceWithTimestamp.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
pass.WriteTimestamp(timestampQuerySet, 0);
pass.EndPass();
encoder.Finish();
}
// Not allow to write timestamp from another device
{
// Write timestamp from default device
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
pass.WriteTimestamp(timestampQuerySet, 0);
pass.EndPass();
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Not allow to write timestamp to the query set with other query type
{
wgpu::CommandEncoder encoder = deviceWithTimestamp.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
pass.WriteTimestamp(occlusionQuerySet, 0);
pass.EndPass();
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Fail to write timestamp to the index which exceeds the number of queries in query set
{
wgpu::CommandEncoder encoder = deviceWithTimestamp.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
pass.WriteTimestamp(timestampQuerySet, 2);
pass.EndPass();
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Fail to submit timestamp query with a destroyed query set
{
wgpu::CommandEncoder encoder = deviceWithTimestamp.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
pass.WriteTimestamp(timestampQuerySet, 0);
pass.EndPass();
wgpu::CommandBuffer commands = encoder.Finish();
wgpu::Queue queue = deviceWithTimestamp.GetDefaultQueue();
timestampQuerySet.Destroy();
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
}
}