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>
diff --git a/dawn.json b/dawn.json
index 2575d18..bd4b5b2 100644
--- a/dawn.json
+++ b/dawn.json
@@ -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"}
+ ]
}
]
},
@@ -457,6 +464,13 @@
]
},
{
+ "name": "write timestamp",
+ "args": [
+ {"name": "query set", "type": "query set"},
+ {"name": "query index", "type": "uint32_t"}
+ ]
+ },
+ {
"name": "dispatch",
"args": [
{"name": "x", "type": "uint32_t"},
@@ -1262,6 +1276,13 @@
]
},
{
+ "name": "write timestamp",
+ "args": [
+ {"name": "query set", "type": "query set"},
+ {"name": "query index", "type": "uint32_t"}
+ ]
+ },
+ {
"name": "end pass"
}
]
diff --git a/src/dawn_native/CommandEncoder.cpp b/src/dawn_native/CommandEncoder.cpp
index b282dc8..23e2403 100644
--- a/src/dawn_native/CommandEncoder.cpp
+++ b/src/dawn_native/CommandEncoder.cpp
@@ -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 @@
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 @@
});
}
+ 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 @@
debugGroupStackSize++;
break;
}
+
+ case Command::WriteTimestamp: {
+ commands->NextCommand<WriteTimestampCmd>();
+ break;
+ }
default:
return DAWN_VALIDATION_ERROR("Command disallowed outside of a pass");
}
diff --git a/src/dawn_native/CommandEncoder.h b/src/dawn_native/CommandEncoder.h
index 2c89c4b..9caa1b2 100644
--- a/src/dawn_native/CommandEncoder.h
+++ b/src/dawn_native/CommandEncoder.h
@@ -35,6 +35,8 @@
CommandIterator AcquireCommands();
CommandBufferResourceUsage AcquireResourceUsages();
+ void TrackUsedQuerySet(QuerySetBase* querySet);
+
// Dawn API
ComputePassEncoder* BeginComputePass(const ComputePassDescriptor* descriptor);
RenderPassEncoder* BeginRenderPass(const RenderPassDescriptor* descriptor);
@@ -58,6 +60,8 @@
void PopDebugGroup();
void PushDebugGroup(const char* groupLabel);
+ void WriteTimestamp(QuerySetBase* querySet, uint32_t queryIndex);
+
CommandBufferBase* Finish(const CommandBufferDescriptor* descriptor);
private:
@@ -67,6 +71,7 @@
EncodingContext mEncodingContext;
std::set<BufferBase*> mTopLevelBuffers;
std::set<TextureBase*> mTopLevelTextures;
+ std::set<QuerySetBase*> mUsedQuerySets;
};
} // namespace dawn_native
diff --git a/src/dawn_native/CommandValidation.cpp b/src/dawn_native/CommandValidation.cpp
index 7f8da9b..0a96c85 100644
--- a/src/dawn_native/CommandValidation.cpp
+++ b/src/dawn_native/CommandValidation.cpp
@@ -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 @@
break;
}
+ case Command::WriteTimestamp: {
+ commands->NextCommand<WriteTimestampCmd>();
+ break;
+ }
+
default:
DAWN_TRY(ValidateRenderBundleCommand(
commands, type, &commandBufferState, renderPass->attachmentState.Get(),
@@ -274,6 +280,11 @@
break;
}
+ case Command::WriteTimestamp: {
+ commands->NextCommand<WriteTimestampCmd>();
+ break;
+ }
+
default:
return DAWN_VALIDATION_ERROR("Command disallowed inside a compute pass");
}
@@ -339,6 +350,18 @@
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);
diff --git a/src/dawn_native/CommandValidation.h b/src/dawn_native/CommandValidation.h
index 53871cc..49da94d 100644
--- a/src/dawn_native/CommandValidation.h
+++ b/src/dawn_native/CommandValidation.h
@@ -23,6 +23,7 @@
namespace dawn_native {
class AttachmentState;
+ class QuerySetBase;
struct BeginRenderPassCmd;
struct PassResourceUsage;
@@ -36,6 +37,8 @@
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
diff --git a/src/dawn_native/Commands.cpp b/src/dawn_native/Commands.cpp
index b409810..7da04ad 100644
--- a/src/dawn_native/Commands.cpp
+++ b/src/dawn_native/Commands.cpp
@@ -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 @@
cmd->~SetVertexBufferCmd();
break;
}
+ case Command::WriteTimestamp: {
+ WriteTimestampCmd* cmd = commands->NextCommand<WriteTimestampCmd>();
+ cmd->~WriteTimestampCmd();
+ break;
+ }
}
}
commands->DataWasDestroyed();
@@ -300,6 +306,11 @@
commands->NextCommand<SetVertexBufferCmd>();
break;
}
+
+ case Command::WriteTimestamp: {
+ commands->NextCommand<WriteTimestampCmd>();
+ break;
+ }
}
}
diff --git a/src/dawn_native/Commands.h b/src/dawn_native/Commands.h
index 0c2c8f0..70214ff 100644
--- a/src/dawn_native/Commands.h
+++ b/src/dawn_native/Commands.h
@@ -60,6 +60,7 @@
SetBindGroup,
SetIndexBuffer,
SetVertexBuffer,
+ WriteTimestamp,
};
struct BeginComputePassCmd {};
@@ -228,6 +229,11 @@
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;
diff --git a/src/dawn_native/ComputePassEncoder.cpp b/src/dawn_native/ComputePassEncoder.cpp
index 5e36601..2329c00 100644
--- a/src/dawn_native/ComputePassEncoder.cpp
+++ b/src/dawn_native/ComputePassEncoder.cpp
@@ -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 @@
});
}
+ 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
diff --git a/src/dawn_native/ComputePassEncoder.h b/src/dawn_native/ComputePassEncoder.h
index f790aad..6ae796a 100644
--- a/src/dawn_native/ComputePassEncoder.h
+++ b/src/dawn_native/ComputePassEncoder.h
@@ -36,6 +36,8 @@
void DispatchIndirect(BufferBase* indirectBuffer, uint64_t indirectOffset);
void SetPipeline(ComputePipelineBase* pipeline);
+ void WriteTimestamp(QuerySetBase* querySet, uint32_t queryIndex);
+
protected:
ComputePassEncoder(DeviceBase* device,
CommandEncoder* commandEncoder,
diff --git a/src/dawn_native/PassResourceUsage.h b/src/dawn_native/PassResourceUsage.h
index e7b0c1b..60dcd21 100644
--- a/src/dawn_native/PassResourceUsage.h
+++ b/src/dawn_native/PassResourceUsage.h
@@ -23,6 +23,7 @@
namespace dawn_native {
class BufferBase;
+ class QuerySetBase;
class TextureBase;
enum class PassType { Render, Compute };
@@ -68,6 +69,7 @@
PerPassUsages perPass;
std::set<BufferBase*> topLevelBuffers;
std::set<TextureBase*> topLevelTextures;
+ std::set<QuerySetBase*> usedQuerySets;
};
} // namespace dawn_native
diff --git a/src/dawn_native/QuerySet.cpp b/src/dawn_native/QuerySet.cpp
index 513658d..3eb18ff 100644
--- a/src/dawn_native/QuerySet.cpp
+++ b/src/dawn_native/QuerySet.cpp
@@ -131,6 +131,14 @@
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;
diff --git a/src/dawn_native/QuerySet.h b/src/dawn_native/QuerySet.h
index 7883678..a069887 100644
--- a/src/dawn_native/QuerySet.h
+++ b/src/dawn_native/QuerySet.h
@@ -35,6 +35,8 @@
uint32_t GetQueryCount() const;
const std::vector<wgpu::PipelineStatisticsName>& GetPipelineStatistics() const;
+ MaybeError ValidateCanUseInSubmitNow() const;
+
void Destroy();
protected:
diff --git a/src/dawn_native/Queue.cpp b/src/dawn_native/Queue.cpp
index 3dcf2b0..19ba51e 100644
--- a/src/dawn_native/Queue.cpp
+++ b/src/dawn_native/Queue.cpp
@@ -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 @@
for (const TextureBase* texture : usages.topLevelTextures) {
DAWN_TRY(texture->ValidateCanUseInSubmitNow());
}
+ for (const QuerySetBase* querySet : usages.usedQuerySets) {
+ DAWN_TRY(querySet->ValidateCanUseInSubmitNow());
+ }
}
return {};
diff --git a/src/dawn_native/RenderPassEncoder.cpp b/src/dawn_native/RenderPassEncoder.cpp
index e2dc4db..e51b52f 100644
--- a/src/dawn_native/RenderPassEncoder.cpp
+++ b/src/dawn_native/RenderPassEncoder.cpp
@@ -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 @@
});
}
+ 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
diff --git a/src/dawn_native/RenderPassEncoder.h b/src/dawn_native/RenderPassEncoder.h
index cd9ac01..d5a2f7a 100644
--- a/src/dawn_native/RenderPassEncoder.h
+++ b/src/dawn_native/RenderPassEncoder.h
@@ -46,6 +46,8 @@
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,
diff --git a/src/dawn_native/d3d12/CommandBufferD3D12.cpp b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
index 1b4f8cc..98fca16 100644
--- a/src/dawn_native/d3d12/CommandBufferD3D12.cpp
+++ b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
@@ -754,6 +754,10 @@
break;
}
+ case Command::WriteTimestamp: {
+ return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation.");
+ }
+
default: {
UNREACHABLE();
break;
@@ -864,6 +868,10 @@
break;
}
+ case Command::WriteTimestamp: {
+ return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation.");
+ }
+
default: {
UNREACHABLE();
break;
@@ -1280,6 +1288,10 @@
break;
}
+ case Command::WriteTimestamp: {
+ return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation.");
+ }
+
default: {
DAWN_TRY(EncodeRenderBundleCommand(&mCommands, type));
break;
diff --git a/src/dawn_native/metal/CommandBufferMTL.h b/src/dawn_native/metal/CommandBufferMTL.h
index e8c81b7..cbaf037 100644
--- a/src/dawn_native/metal/CommandBufferMTL.h
+++ b/src/dawn_native/metal/CommandBufferMTL.h
@@ -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 @@
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;
};
diff --git a/src/dawn_native/metal/CommandBufferMTL.mm b/src/dawn_native/metal/CommandBufferMTL.mm
index bd2b8f3..4efc7a6 100644
--- a/src/dawn_native/metal/CommandBufferMTL.mm
+++ b/src/dawn_native/metal/CommandBufferMTL.mm
@@ -673,7 +673,7 @@
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 @@
LazyClearForPass(passResourceUsages[nextPassNumber]);
commandContext->EndBlit();
- EncodeComputePass(commandContext);
+ DAWN_TRY(EncodeComputePass(commandContext));
nextPassNumber++;
break;
@@ -712,7 +712,7 @@
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 @@
break;
}
+ case Command::WriteTimestamp: {
+ return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation.");
+ }
+
default: {
UNREACHABLE();
break;
@@ -867,9 +871,10 @@
}
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 @@
case Command::EndComputePass: {
mCommands.NextCommand<EndComputePassCmd>();
commandContext->EndCompute();
- return;
+ return {};
}
case Command::Dispatch: {
@@ -960,6 +965,10 @@
break;
}
+ case Command::WriteTimestamp: {
+ return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation.");
+ }
+
default: {
UNREACHABLE();
break;
@@ -971,10 +980,10 @@
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 @@
// 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 @@
[temporaryResolveTextures[i] release];
temporaryResolveTextures[i] = nil;
}
- return;
+ return {};
}
}
@@ -1054,19 +1063,20 @@
// 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 @@
case Command::EndRenderPass: {
mCommands.NextCommand<EndRenderPassCmd>();
commandContext->EndRender();
- return;
+ return {};
}
case Command::SetStencilReference: {
@@ -1323,6 +1333,10 @@
break;
}
+ case Command::WriteTimestamp: {
+ return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation.");
+ }
+
default: {
EncodeRenderBundleCommand(&mCommands, type);
break;
diff --git a/src/dawn_native/metal/QueueMTL.mm b/src/dawn_native/metal/QueueMTL.mm
index 7c5967a..ffe6ca1 100644
--- a/src/dawn_native/metal/QueueMTL.mm
+++ b/src/dawn_native/metal/QueueMTL.mm
@@ -31,7 +31,7 @@
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");
diff --git a/src/dawn_native/opengl/CommandBufferGL.cpp b/src/dawn_native/opengl/CommandBufferGL.cpp
index f3fcd5c..bba5da0 100644
--- a/src/dawn_native/opengl/CommandBufferGL.cpp
+++ b/src/dawn_native/opengl/CommandBufferGL.cpp
@@ -712,6 +712,12 @@
break;
}
+ case Command::WriteTimestamp: {
+ // WriteTimestamp is not supported on OpenGL
+ UNREACHABLE();
+ break;
+ }
+
default: {
UNREACHABLE();
break;
@@ -786,6 +792,12 @@
break;
}
+ case Command::WriteTimestamp: {
+ // WriteTimestamp is not supported on OpenGL
+ UNREACHABLE();
+ break;
+ }
+
default: {
UNREACHABLE();
break;
@@ -1137,6 +1149,12 @@
break;
}
+ case Command::WriteTimestamp: {
+ // WriteTimestamp is not supported on OpenGL
+ UNREACHABLE();
+ break;
+ }
+
default: {
DoRenderBundleCommand(&mCommands, type);
break;
diff --git a/src/dawn_native/vulkan/CommandBufferVk.cpp b/src/dawn_native/vulkan/CommandBufferVk.cpp
index ae0e792..3a2bec9 100644
--- a/src/dawn_native/vulkan/CommandBufferVk.cpp
+++ b/src/dawn_native/vulkan/CommandBufferVk.cpp
@@ -589,12 +589,16 @@
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 @@
return {};
}
- void CommandBuffer::RecordComputePass(CommandRecordingContext* recordingContext) {
+ MaybeError CommandBuffer::RecordComputePass(CommandRecordingContext* recordingContext) {
Device* device = ToBackend(GetDevice());
VkCommandBuffer commands = recordingContext->commandBuffer;
@@ -616,7 +620,7 @@
switch (type) {
case Command::EndComputePass: {
mCommands.NextCommand<EndComputePassCmd>();
- return;
+ return {};
}
case Command::Dispatch: {
@@ -712,6 +716,10 @@
break;
}
+ case Command::WriteTimestamp: {
+ return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation.");
+ }
+
default: {
UNREACHABLE();
break;
@@ -981,6 +989,10 @@
break;
}
+ case Command::WriteTimestamp: {
+ return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation.");
+ }
+
default: {
EncodeRenderBundleCommand(&mCommands, type);
break;
diff --git a/src/dawn_native/vulkan/CommandBufferVk.h b/src/dawn_native/vulkan/CommandBufferVk.h
index c60fa92..fa2dd4b 100644
--- a/src/dawn_native/vulkan/CommandBufferVk.h
+++ b/src/dawn_native/vulkan/CommandBufferVk.h
@@ -42,7 +42,7 @@
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,
diff --git a/src/tests/unittests/validation/QuerySetValidationTests.cpp b/src/tests/unittests/validation/QuerySetValidationTests.cpp
index 311bc66..3039718 100644
--- a/src/tests/unittests/validation/QuerySetValidationTests.cpp
+++ b/src/tests/unittests/validation/QuerySetValidationTests.cpp
@@ -27,10 +27,11 @@
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 @@
descriptor.pipelineStatisticsCount = pipelineStatistics.size();
}
- cDevice.CreateQuerySet(&descriptor);
+ return cDevice.CreateQuerySet(&descriptor);
}
wgpu::Device deviceWithPipelineStatistics;
@@ -148,3 +149,171 @@
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));
+ }
+}