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": [ "args": [
{"name": "group label", "type": "char", "annotation": "const*", "length": "strlen"} {"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": "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", "name": "dispatch",
"args": [ "args": [
@ -1261,6 +1275,13 @@
{"name": "size", "type": "uint64_t", "default": "0"} {"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" "name": "end pass"
} }

View File

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

View File

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

View File

@ -20,6 +20,7 @@
#include "dawn_native/CommandBufferStateTracker.h" #include "dawn_native/CommandBufferStateTracker.h"
#include "dawn_native/Commands.h" #include "dawn_native/Commands.h"
#include "dawn_native/PassResourceUsage.h" #include "dawn_native/PassResourceUsage.h"
#include "dawn_native/QuerySet.h"
#include "dawn_native/RenderBundle.h" #include "dawn_native/RenderBundle.h"
#include "dawn_native/RenderPipeline.h" #include "dawn_native/RenderPipeline.h"
@ -202,6 +203,11 @@ namespace dawn_native {
break; break;
} }
case Command::WriteTimestamp: {
commands->NextCommand<WriteTimestampCmd>();
break;
}
default: default:
DAWN_TRY(ValidateRenderBundleCommand( DAWN_TRY(ValidateRenderBundleCommand(
commands, type, &commandBufferState, renderPass->attachmentState.Get(), commands, type, &commandBufferState, renderPass->attachmentState.Get(),
@ -274,6 +280,11 @@ namespace dawn_native {
break; break;
} }
case Command::WriteTimestamp: {
commands->NextCommand<WriteTimestampCmd>();
break;
}
default: default:
return DAWN_VALIDATION_ERROR("Command disallowed inside a compute pass"); return DAWN_VALIDATION_ERROR("Command disallowed inside a compute pass");
} }
@ -339,6 +350,18 @@ namespace dawn_native {
return {}; 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) { bool IsRangeOverlapped(uint32_t startA, uint32_t startB, uint32_t length) {
uint32_t maxStart = std::max(startA, startB); uint32_t maxStart = std::max(startA, startB);
uint32_t minStart = std::min(startA, startB); uint32_t minStart = std::min(startA, startB);

View File

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

View File

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

View File

@ -60,6 +60,7 @@ namespace dawn_native {
SetBindGroup, SetBindGroup,
SetIndexBuffer, SetIndexBuffer,
SetVertexBuffer, SetVertexBuffer,
WriteTimestamp,
}; };
struct BeginComputePassCmd {}; struct BeginComputePassCmd {};
@ -228,6 +229,11 @@ namespace dawn_native {
uint64_t size; 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 // 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. // the commands have a chance to run their destructor and remove internal references.
class CommandIterator; class CommandIterator;

View File

@ -16,9 +16,11 @@
#include "dawn_native/Buffer.h" #include "dawn_native/Buffer.h"
#include "dawn_native/CommandEncoder.h" #include "dawn_native/CommandEncoder.h"
#include "dawn_native/CommandValidation.h"
#include "dawn_native/Commands.h" #include "dawn_native/Commands.h"
#include "dawn_native/ComputePipeline.h" #include "dawn_native/ComputePipeline.h"
#include "dawn_native/Device.h" #include "dawn_native/Device.h"
#include "dawn_native/QuerySet.h"
namespace dawn_native { 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 } // namespace dawn_native

View File

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

View File

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

View File

@ -131,6 +131,14 @@ namespace dawn_native {
return mPipelineStatistics; 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() { void QuerySetBase::Destroy() {
if (GetDevice()->ConsumedError(ValidateDestroy())) { if (GetDevice()->ConsumedError(ValidateDestroy())) {
return; return;

View File

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

View File

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

View File

@ -17,8 +17,10 @@
#include "common/Constants.h" #include "common/Constants.h"
#include "dawn_native/Buffer.h" #include "dawn_native/Buffer.h"
#include "dawn_native/CommandEncoder.h" #include "dawn_native/CommandEncoder.h"
#include "dawn_native/CommandValidation.h"
#include "dawn_native/Commands.h" #include "dawn_native/Commands.h"
#include "dawn_native/Device.h" #include "dawn_native/Device.h"
#include "dawn_native/QuerySet.h"
#include "dawn_native/RenderBundle.h" #include "dawn_native/RenderBundle.h"
#include "dawn_native/RenderPipeline.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 } // 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 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 WriteTimestamp(QuerySetBase* querySet, uint32_t queryIndex);
protected: protected:
RenderPassEncoder(DeviceBase* device, RenderPassEncoder(DeviceBase* device,
CommandEncoder* commandEncoder, CommandEncoder* commandEncoder,

View File

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

View File

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

View File

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

View File

@ -31,7 +31,7 @@ namespace dawn_native { namespace metal {
TRACE_EVENT_BEGIN0(GetDevice()->GetPlatform(), Recording, "CommandBufferMTL::FillCommands"); TRACE_EVENT_BEGIN0(GetDevice()->GetPlatform(), Recording, "CommandBufferMTL::FillCommands");
for (uint32_t i = 0; i < commandCount; ++i) { 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"); TRACE_EVENT_END0(GetDevice()->GetPlatform(), Recording, "CommandBufferMTL::FillCommands");

View File

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

View File

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

View File

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

View File

@ -27,7 +27,8 @@ class QuerySetValidationTest : public ValidationTest {
deviceWithTimestamp = CreateDeviceFromAdapter(adapter, {"timestamp_query"}); deviceWithTimestamp = CreateDeviceFromAdapter(adapter, {"timestamp_query"});
} }
void CreateQuerySet(wgpu::Device cDevice, wgpu::QuerySet CreateQuerySet(
wgpu::Device cDevice,
wgpu::QueryType queryType, wgpu::QueryType queryType,
uint32_t queryCount, uint32_t queryCount,
std::vector<wgpu::PipelineStatisticsName> pipelineStatistics = {}) { std::vector<wgpu::PipelineStatisticsName> pipelineStatistics = {}) {
@ -40,7 +41,7 @@ class QuerySetValidationTest : public ValidationTest {
descriptor.pipelineStatisticsCount = pipelineStatistics.size(); descriptor.pipelineStatisticsCount = pipelineStatistics.size();
} }
cDevice.CreateQuerySet(&descriptor); return cDevice.CreateQuerySet(&descriptor);
} }
wgpu::Device deviceWithPipelineStatistics; wgpu::Device deviceWithPipelineStatistics;
@ -148,3 +149,171 @@ TEST_F(QuerySetValidationTest, DestroyDestroyedQuerySet) {
querySet.Destroy(); querySet.Destroy();
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));
}
}