mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-06-13 10:03:41 +00:00
Implement timestampWrites on D3D12 and Vulkan backends
Metal implementation is more complex and has more issues, submit D3D12 and Vulkan frist and another CL for Metal. Bug: dawn:1250 Change-Id: I718d323e01bb41b0209bfd1f1026faf64b4f1076 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/97640 Reviewed-by: Austin Eng <enga@chromium.org> Commit-Queue: Hao Li <hao.x.li@intel.com>
This commit is contained in:
parent
9ec183ed9f
commit
9afd92be3f
@ -778,8 +778,6 @@ ComputePassEncoder* CommandEncoder::APIBeginComputePass(const ComputePassDescrip
|
|||||||
Ref<ComputePassEncoder> CommandEncoder::BeginComputePass(const ComputePassDescriptor* descriptor) {
|
Ref<ComputePassEncoder> CommandEncoder::BeginComputePass(const ComputePassDescriptor* descriptor) {
|
||||||
DeviceBase* device = GetDevice();
|
DeviceBase* device = GetDevice();
|
||||||
|
|
||||||
std::vector<TimestampWrite> timestampWritesAtBeginning;
|
|
||||||
std::vector<TimestampWrite> timestampWritesAtEnd;
|
|
||||||
bool success = mEncodingContext.TryEncode(
|
bool success = mEncodingContext.TryEncode(
|
||||||
this,
|
this,
|
||||||
[&](CommandAllocator* allocator) -> MaybeError {
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
@ -792,27 +790,27 @@ Ref<ComputePassEncoder> CommandEncoder::BeginComputePass(const ComputePassDescri
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Split the timestampWrites used in BeginComputePassCmd and EndComputePassCmd
|
// Record timestamp writes at the beginning and end of compute pass. The timestamp write
|
||||||
|
// at the end also be needed in BeginComputePassCmd because it's required by compute
|
||||||
|
// pass descriptor when beginning compute pass on Metal.
|
||||||
for (uint32_t i = 0; i < descriptor->timestampWriteCount; i++) {
|
for (uint32_t i = 0; i < descriptor->timestampWriteCount; i++) {
|
||||||
QuerySetBase* querySet = descriptor->timestampWrites[i].querySet;
|
QuerySetBase* querySet = descriptor->timestampWrites[i].querySet;
|
||||||
uint32_t queryIndex = descriptor->timestampWrites[i].queryIndex;
|
uint32_t queryIndex = descriptor->timestampWrites[i].queryIndex;
|
||||||
|
|
||||||
switch (descriptor->timestampWrites[i].location) {
|
switch (descriptor->timestampWrites[i].location) {
|
||||||
case wgpu::ComputePassTimestampLocation::Beginning:
|
case wgpu::ComputePassTimestampLocation::Beginning:
|
||||||
timestampWritesAtBeginning.push_back({querySet, queryIndex});
|
cmd->beginTimestamp.querySet = querySet;
|
||||||
|
cmd->beginTimestamp.queryIndex = queryIndex;
|
||||||
break;
|
break;
|
||||||
case wgpu::ComputePassTimestampLocation::End:
|
case wgpu::ComputePassTimestampLocation::End:
|
||||||
timestampWritesAtEnd.push_back({querySet, queryIndex});
|
cmd->endTimestamp.querySet = querySet;
|
||||||
break;
|
cmd->endTimestamp.queryIndex = queryIndex;
|
||||||
default:
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
TrackQueryAvailability(querySet, queryIndex);
|
TrackQueryAvailability(querySet, queryIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd->timestampWrites = std::move(timestampWritesAtBeginning);
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
},
|
},
|
||||||
"encoding %s.BeginComputePass(%s).", this, descriptor);
|
"encoding %s.BeginComputePass(%s).", this, descriptor);
|
||||||
@ -823,8 +821,8 @@ Ref<ComputePassEncoder> CommandEncoder::BeginComputePass(const ComputePassDescri
|
|||||||
descriptor = &defaultDescriptor;
|
descriptor = &defaultDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<ComputePassEncoder> passEncoder = ComputePassEncoder::Create(
|
Ref<ComputePassEncoder> passEncoder =
|
||||||
device, descriptor, this, &mEncodingContext, std::move(timestampWritesAtEnd));
|
ComputePassEncoder::Create(device, descriptor, this, &mEncodingContext);
|
||||||
mEncodingContext.EnterPass(passEncoder.Get());
|
mEncodingContext.EnterPass(passEncoder.Get());
|
||||||
return passEncoder;
|
return passEncoder;
|
||||||
}
|
}
|
||||||
@ -846,8 +844,6 @@ Ref<RenderPassEncoder> CommandEncoder::BeginRenderPass(const RenderPassDescripto
|
|||||||
bool depthReadOnly = false;
|
bool depthReadOnly = false;
|
||||||
bool stencilReadOnly = false;
|
bool stencilReadOnly = false;
|
||||||
Ref<AttachmentState> attachmentState;
|
Ref<AttachmentState> attachmentState;
|
||||||
std::vector<TimestampWrite> timestampWritesAtBeginning;
|
|
||||||
std::vector<TimestampWrite> timestampWritesAtEnd;
|
|
||||||
bool success = mEncodingContext.TryEncode(
|
bool success = mEncodingContext.TryEncode(
|
||||||
this,
|
this,
|
||||||
[&](CommandAllocator* allocator) -> MaybeError {
|
[&](CommandAllocator* allocator) -> MaybeError {
|
||||||
@ -865,28 +861,6 @@ Ref<RenderPassEncoder> CommandEncoder::BeginRenderPass(const RenderPassDescripto
|
|||||||
cmd->attachmentState = device->GetOrCreateAttachmentState(descriptor);
|
cmd->attachmentState = device->GetOrCreateAttachmentState(descriptor);
|
||||||
attachmentState = cmd->attachmentState;
|
attachmentState = cmd->attachmentState;
|
||||||
|
|
||||||
// Split the timestampWrites used in BeginRenderPassCmd and EndRenderPassCmd
|
|
||||||
for (uint32_t i = 0; i < descriptor->timestampWriteCount; i++) {
|
|
||||||
QuerySetBase* querySet = descriptor->timestampWrites[i].querySet;
|
|
||||||
uint32_t queryIndex = descriptor->timestampWrites[i].queryIndex;
|
|
||||||
|
|
||||||
switch (descriptor->timestampWrites[i].location) {
|
|
||||||
case wgpu::RenderPassTimestampLocation::Beginning:
|
|
||||||
timestampWritesAtBeginning.push_back({querySet, queryIndex});
|
|
||||||
break;
|
|
||||||
case wgpu::RenderPassTimestampLocation::End:
|
|
||||||
timestampWritesAtEnd.push_back({querySet, queryIndex});
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
TrackQueryAvailability(querySet, queryIndex);
|
|
||||||
// Track the query availability with true on render pass again for rewrite
|
|
||||||
// validation and query reset on Vulkan
|
|
||||||
usageTracker.TrackQueryAvailability(querySet, queryIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ColorAttachmentIndex index :
|
for (ColorAttachmentIndex index :
|
||||||
IterateBitSet(cmd->attachmentState->GetColorAttachmentsMask())) {
|
IterateBitSet(cmd->attachmentState->GetColorAttachmentsMask())) {
|
||||||
uint8_t i = static_cast<uint8_t>(index);
|
uint8_t i = static_cast<uint8_t>(index);
|
||||||
@ -990,7 +964,29 @@ Ref<RenderPassEncoder> CommandEncoder::BeginRenderPass(const RenderPassDescripto
|
|||||||
|
|
||||||
cmd->occlusionQuerySet = descriptor->occlusionQuerySet;
|
cmd->occlusionQuerySet = descriptor->occlusionQuerySet;
|
||||||
|
|
||||||
cmd->timestampWrites = std::move(timestampWritesAtBeginning);
|
// Record timestamp writes at the beginning and end of render pass. The timestamp write
|
||||||
|
// at the end also be needed in BeginComputePassCmd because it's required by render pass
|
||||||
|
// descriptor when beginning render pass on Metal.
|
||||||
|
for (uint32_t i = 0; i < descriptor->timestampWriteCount; i++) {
|
||||||
|
QuerySetBase* querySet = descriptor->timestampWrites[i].querySet;
|
||||||
|
uint32_t queryIndex = descriptor->timestampWrites[i].queryIndex;
|
||||||
|
|
||||||
|
switch (descriptor->timestampWrites[i].location) {
|
||||||
|
case wgpu::RenderPassTimestampLocation::Beginning:
|
||||||
|
cmd->beginTimestamp.querySet = querySet;
|
||||||
|
cmd->beginTimestamp.queryIndex = queryIndex;
|
||||||
|
break;
|
||||||
|
case wgpu::RenderPassTimestampLocation::End:
|
||||||
|
cmd->endTimestamp.querySet = querySet;
|
||||||
|
cmd->endTimestamp.queryIndex = queryIndex;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
TrackQueryAvailability(querySet, queryIndex);
|
||||||
|
// Track the query availability with true on render pass again for rewrite
|
||||||
|
// validation and query reset on Vulkan
|
||||||
|
usageTracker.TrackQueryAvailability(querySet, queryIndex);
|
||||||
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
},
|
},
|
||||||
@ -999,8 +995,7 @@ Ref<RenderPassEncoder> CommandEncoder::BeginRenderPass(const RenderPassDescripto
|
|||||||
if (success) {
|
if (success) {
|
||||||
Ref<RenderPassEncoder> passEncoder = RenderPassEncoder::Create(
|
Ref<RenderPassEncoder> passEncoder = RenderPassEncoder::Create(
|
||||||
device, descriptor, this, &mEncodingContext, std::move(usageTracker),
|
device, descriptor, this, &mEncodingContext, std::move(usageTracker),
|
||||||
std::move(attachmentState), std::move(timestampWritesAtEnd), width, height,
|
std::move(attachmentState), width, height, depthReadOnly, stencilReadOnly);
|
||||||
depthReadOnly, stencilReadOnly);
|
|
||||||
mEncodingContext.EnterPass(passEncoder.Get());
|
mEncodingContext.EnterPass(passEncoder.Get());
|
||||||
return passEncoder;
|
return passEncoder;
|
||||||
}
|
}
|
||||||
|
@ -361,9 +361,7 @@ void SkipCommand(CommandIterator* commands, Command type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TimestampWrite::TimestampWrite(const Ref<QuerySetBase>& set, uint32_t idx)
|
TimestampWrite::TimestampWrite() = default;
|
||||||
: querySet(set), queryIndex(idx) {}
|
|
||||||
TimestampWrite::TimestampWrite(TimestampWrite&&) = default;
|
|
||||||
TimestampWrite::~TimestampWrite() = default;
|
TimestampWrite::~TimestampWrite() = default;
|
||||||
|
|
||||||
BeginComputePassCmd::BeginComputePassCmd() = default;
|
BeginComputePassCmd::BeginComputePassCmd() = default;
|
||||||
|
@ -70,8 +70,7 @@ enum class Command {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct TimestampWrite {
|
struct TimestampWrite {
|
||||||
TimestampWrite(const Ref<QuerySetBase>& set, uint32_t idx);
|
TimestampWrite();
|
||||||
TimestampWrite(TimestampWrite&&);
|
|
||||||
~TimestampWrite();
|
~TimestampWrite();
|
||||||
|
|
||||||
Ref<QuerySetBase> querySet;
|
Ref<QuerySetBase> querySet;
|
||||||
@ -82,7 +81,8 @@ struct BeginComputePassCmd {
|
|||||||
BeginComputePassCmd();
|
BeginComputePassCmd();
|
||||||
~BeginComputePassCmd();
|
~BeginComputePassCmd();
|
||||||
|
|
||||||
std::vector<TimestampWrite> timestampWrites;
|
TimestampWrite beginTimestamp;
|
||||||
|
TimestampWrite endTimestamp;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BeginOcclusionQueryCmd {
|
struct BeginOcclusionQueryCmd {
|
||||||
@ -133,7 +133,8 @@ struct BeginRenderPassCmd {
|
|||||||
uint32_t height;
|
uint32_t height;
|
||||||
|
|
||||||
Ref<QuerySetBase> occlusionQuerySet;
|
Ref<QuerySetBase> occlusionQuerySet;
|
||||||
std::vector<TimestampWrite> timestampWrites;
|
TimestampWrite beginTimestamp;
|
||||||
|
TimestampWrite endTimestamp;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BufferCopy {
|
struct BufferCopy {
|
||||||
@ -228,8 +229,6 @@ struct DrawIndexedIndirectCmd : DrawIndirectCmd {};
|
|||||||
struct EndComputePassCmd {
|
struct EndComputePassCmd {
|
||||||
EndComputePassCmd();
|
EndComputePassCmd();
|
||||||
~EndComputePassCmd();
|
~EndComputePassCmd();
|
||||||
|
|
||||||
std::vector<TimestampWrite> timestampWrites;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EndOcclusionQueryCmd {
|
struct EndOcclusionQueryCmd {
|
||||||
@ -243,8 +242,6 @@ struct EndOcclusionQueryCmd {
|
|||||||
struct EndRenderPassCmd {
|
struct EndRenderPassCmd {
|
||||||
EndRenderPassCmd();
|
EndRenderPassCmd();
|
||||||
~EndRenderPassCmd();
|
~EndRenderPassCmd();
|
||||||
|
|
||||||
std::vector<TimestampWrite> timestampWrites;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ExecuteBundlesCmd {
|
struct ExecuteBundlesCmd {
|
||||||
|
@ -111,23 +111,18 @@ ResultOrError<ComputePipelineBase*> GetOrCreateIndirectDispatchValidationPipelin
|
|||||||
ComputePassEncoder::ComputePassEncoder(DeviceBase* device,
|
ComputePassEncoder::ComputePassEncoder(DeviceBase* device,
|
||||||
const ComputePassDescriptor* descriptor,
|
const ComputePassDescriptor* descriptor,
|
||||||
CommandEncoder* commandEncoder,
|
CommandEncoder* commandEncoder,
|
||||||
EncodingContext* encodingContext,
|
EncodingContext* encodingContext)
|
||||||
std::vector<TimestampWrite> timestampWritesAtEnd)
|
|
||||||
: ProgrammableEncoder(device, descriptor->label, encodingContext),
|
: ProgrammableEncoder(device, descriptor->label, encodingContext),
|
||||||
mCommandEncoder(commandEncoder),
|
mCommandEncoder(commandEncoder) {
|
||||||
mTimestampWritesAtEnd(std::move(timestampWritesAtEnd)) {
|
|
||||||
TrackInDevice();
|
TrackInDevice();
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
Ref<ComputePassEncoder> ComputePassEncoder::Create(
|
Ref<ComputePassEncoder> ComputePassEncoder::Create(DeviceBase* device,
|
||||||
DeviceBase* device,
|
const ComputePassDescriptor* descriptor,
|
||||||
const ComputePassDescriptor* descriptor,
|
CommandEncoder* commandEncoder,
|
||||||
CommandEncoder* commandEncoder,
|
EncodingContext* encodingContext) {
|
||||||
EncodingContext* encodingContext,
|
return AcquireRef(new ComputePassEncoder(device, descriptor, commandEncoder, encodingContext));
|
||||||
std::vector<TimestampWrite> timestampWritesAtEnd) {
|
|
||||||
return AcquireRef(new ComputePassEncoder(device, descriptor, commandEncoder, encodingContext,
|
|
||||||
std::move(timestampWritesAtEnd)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ComputePassEncoder::ComputePassEncoder(DeviceBase* device,
|
ComputePassEncoder::ComputePassEncoder(DeviceBase* device,
|
||||||
@ -162,11 +157,7 @@ void ComputePassEncoder::APIEnd() {
|
|||||||
DAWN_TRY(ValidateProgrammableEncoderEnd());
|
DAWN_TRY(ValidateProgrammableEncoderEnd());
|
||||||
}
|
}
|
||||||
|
|
||||||
EndComputePassCmd* cmd =
|
allocator->Allocate<EndComputePassCmd>(Command::EndComputePass);
|
||||||
allocator->Allocate<EndComputePassCmd>(Command::EndComputePass);
|
|
||||||
// The query availability has already been updated at the beginning of compute
|
|
||||||
// pass, and no need to do update here.
|
|
||||||
cmd->timestampWrites = std::move(mTimestampWritesAtEnd);
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
},
|
},
|
||||||
|
@ -33,8 +33,7 @@ class ComputePassEncoder final : public ProgrammableEncoder {
|
|||||||
static Ref<ComputePassEncoder> Create(DeviceBase* device,
|
static Ref<ComputePassEncoder> Create(DeviceBase* device,
|
||||||
const ComputePassDescriptor* descriptor,
|
const ComputePassDescriptor* descriptor,
|
||||||
CommandEncoder* commandEncoder,
|
CommandEncoder* commandEncoder,
|
||||||
EncodingContext* encodingContext,
|
EncodingContext* encodingContext);
|
||||||
std::vector<TimestampWrite> timestampWritesAtEnd);
|
|
||||||
static Ref<ComputePassEncoder> MakeError(DeviceBase* device,
|
static Ref<ComputePassEncoder> MakeError(DeviceBase* device,
|
||||||
CommandEncoder* commandEncoder,
|
CommandEncoder* commandEncoder,
|
||||||
EncodingContext* encodingContext);
|
EncodingContext* encodingContext);
|
||||||
@ -72,8 +71,7 @@ class ComputePassEncoder final : public ProgrammableEncoder {
|
|||||||
ComputePassEncoder(DeviceBase* device,
|
ComputePassEncoder(DeviceBase* device,
|
||||||
const ComputePassDescriptor* descriptor,
|
const ComputePassDescriptor* descriptor,
|
||||||
CommandEncoder* commandEncoder,
|
CommandEncoder* commandEncoder,
|
||||||
EncodingContext* encodingContext,
|
EncodingContext* encodingContext);
|
||||||
std::vector<TimestampWrite> timestampWritesAtEnd);
|
|
||||||
ComputePassEncoder(DeviceBase* device,
|
ComputePassEncoder(DeviceBase* device,
|
||||||
CommandEncoder* commandEncoder,
|
CommandEncoder* commandEncoder,
|
||||||
EncodingContext* encodingContext,
|
EncodingContext* encodingContext,
|
||||||
@ -98,8 +96,6 @@ class ComputePassEncoder final : public ProgrammableEncoder {
|
|||||||
// For render and compute passes, the encoding context is borrowed from the command encoder.
|
// For render and compute passes, the encoding context is borrowed from the command encoder.
|
||||||
// Keep a reference to the encoder to make sure the context isn't freed.
|
// Keep a reference to the encoder to make sure the context isn't freed.
|
||||||
Ref<CommandEncoder> mCommandEncoder;
|
Ref<CommandEncoder> mCommandEncoder;
|
||||||
|
|
||||||
std::vector<TimestampWrite> mTimestampWritesAtEnd;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dawn::native
|
} // namespace dawn::native
|
||||||
|
@ -56,7 +56,6 @@ RenderPassEncoder::RenderPassEncoder(DeviceBase* device,
|
|||||||
EncodingContext* encodingContext,
|
EncodingContext* encodingContext,
|
||||||
RenderPassResourceUsageTracker usageTracker,
|
RenderPassResourceUsageTracker usageTracker,
|
||||||
Ref<AttachmentState> attachmentState,
|
Ref<AttachmentState> attachmentState,
|
||||||
std::vector<TimestampWrite> timestampWritesAtEnd,
|
|
||||||
uint32_t renderTargetWidth,
|
uint32_t renderTargetWidth,
|
||||||
uint32_t renderTargetHeight,
|
uint32_t renderTargetHeight,
|
||||||
bool depthReadOnly,
|
bool depthReadOnly,
|
||||||
@ -70,8 +69,7 @@ RenderPassEncoder::RenderPassEncoder(DeviceBase* device,
|
|||||||
mCommandEncoder(commandEncoder),
|
mCommandEncoder(commandEncoder),
|
||||||
mRenderTargetWidth(renderTargetWidth),
|
mRenderTargetWidth(renderTargetWidth),
|
||||||
mRenderTargetHeight(renderTargetHeight),
|
mRenderTargetHeight(renderTargetHeight),
|
||||||
mOcclusionQuerySet(descriptor->occlusionQuerySet),
|
mOcclusionQuerySet(descriptor->occlusionQuerySet) {
|
||||||
mTimestampWritesAtEnd(std::move(timestampWritesAtEnd)) {
|
|
||||||
mUsageTracker = std::move(usageTracker);
|
mUsageTracker = std::move(usageTracker);
|
||||||
const RenderPassDescriptorMaxDrawCount* maxDrawCountInfo = nullptr;
|
const RenderPassDescriptorMaxDrawCount* maxDrawCountInfo = nullptr;
|
||||||
FindInChain(descriptor->nextInChain, &maxDrawCountInfo);
|
FindInChain(descriptor->nextInChain, &maxDrawCountInfo);
|
||||||
@ -88,15 +86,14 @@ Ref<RenderPassEncoder> RenderPassEncoder::Create(DeviceBase* device,
|
|||||||
EncodingContext* encodingContext,
|
EncodingContext* encodingContext,
|
||||||
RenderPassResourceUsageTracker usageTracker,
|
RenderPassResourceUsageTracker usageTracker,
|
||||||
Ref<AttachmentState> attachmentState,
|
Ref<AttachmentState> attachmentState,
|
||||||
std::vector<TimestampWrite> timestampWritesAtEnd,
|
|
||||||
uint32_t renderTargetWidth,
|
uint32_t renderTargetWidth,
|
||||||
uint32_t renderTargetHeight,
|
uint32_t renderTargetHeight,
|
||||||
bool depthReadOnly,
|
bool depthReadOnly,
|
||||||
bool stencilReadOnly) {
|
bool stencilReadOnly) {
|
||||||
return AcquireRef(new RenderPassEncoder(device, descriptor, commandEncoder, encodingContext,
|
return AcquireRef(new RenderPassEncoder(device, descriptor, commandEncoder, encodingContext,
|
||||||
std::move(usageTracker), std::move(attachmentState),
|
std::move(usageTracker), std::move(attachmentState),
|
||||||
std::move(timestampWritesAtEnd), renderTargetWidth,
|
renderTargetWidth, renderTargetHeight, depthReadOnly,
|
||||||
renderTargetHeight, depthReadOnly, stencilReadOnly));
|
stencilReadOnly));
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderPassEncoder::RenderPassEncoder(DeviceBase* device,
|
RenderPassEncoder::RenderPassEncoder(DeviceBase* device,
|
||||||
@ -152,10 +149,7 @@ void RenderPassEncoder::APIEnd() {
|
|||||||
mDrawCount, this, mMaxDrawCount);
|
mDrawCount, this, mMaxDrawCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
EndRenderPassCmd* cmd = allocator->Allocate<EndRenderPassCmd>(Command::EndRenderPass);
|
allocator->Allocate<EndRenderPassCmd>(Command::EndRenderPass);
|
||||||
// The query availability has already been updated at the beginning of render
|
|
||||||
// pass, and no need to do update here.
|
|
||||||
cmd->timestampWrites = std::move(mTimestampWritesAtEnd);
|
|
||||||
|
|
||||||
DAWN_TRY(mEncodingContext->ExitRenderPass(this, std::move(mUsageTracker),
|
DAWN_TRY(mEncodingContext->ExitRenderPass(this, std::move(mUsageTracker),
|
||||||
mCommandEncoder.Get(),
|
mCommandEncoder.Get(),
|
||||||
|
@ -33,7 +33,6 @@ class RenderPassEncoder final : public RenderEncoderBase {
|
|||||||
EncodingContext* encodingContext,
|
EncodingContext* encodingContext,
|
||||||
RenderPassResourceUsageTracker usageTracker,
|
RenderPassResourceUsageTracker usageTracker,
|
||||||
Ref<AttachmentState> attachmentState,
|
Ref<AttachmentState> attachmentState,
|
||||||
std::vector<TimestampWrite> timestampWritesAtEnd,
|
|
||||||
uint32_t renderTargetWidth,
|
uint32_t renderTargetWidth,
|
||||||
uint32_t renderTargetHeight,
|
uint32_t renderTargetHeight,
|
||||||
bool depthReadOnly,
|
bool depthReadOnly,
|
||||||
@ -70,7 +69,6 @@ class RenderPassEncoder final : public RenderEncoderBase {
|
|||||||
EncodingContext* encodingContext,
|
EncodingContext* encodingContext,
|
||||||
RenderPassResourceUsageTracker usageTracker,
|
RenderPassResourceUsageTracker usageTracker,
|
||||||
Ref<AttachmentState> attachmentState,
|
Ref<AttachmentState> attachmentState,
|
||||||
std::vector<TimestampWrite> timestampWritesAtEnd,
|
|
||||||
uint32_t renderTargetWidth,
|
uint32_t renderTargetWidth,
|
||||||
uint32_t renderTargetHeight,
|
uint32_t renderTargetHeight,
|
||||||
bool depthReadOnly,
|
bool depthReadOnly,
|
||||||
@ -99,8 +97,6 @@ class RenderPassEncoder final : public RenderEncoderBase {
|
|||||||
|
|
||||||
// This is the hardcoded value in the WebGPU spec.
|
// This is the hardcoded value in the WebGPU spec.
|
||||||
uint64_t mMaxDrawCount = 50000000;
|
uint64_t mMaxDrawCount = 50000000;
|
||||||
|
|
||||||
std::vector<TimestampWrite> mTimestampWritesAtEnd;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dawn::native
|
} // namespace dawn::native
|
||||||
|
@ -90,10 +90,12 @@ bool CanUseCopyResource(const TextureCopy& src, const TextureCopy& dst, const Ex
|
|||||||
copySize.depthOrArrayLayers == srcSize.depthOrArrayLayers;
|
copySize.depthOrArrayLayers == srcSize.depthOrArrayLayers;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecordWriteTimestampCmd(ID3D12GraphicsCommandList* commandList, WriteTimestampCmd* cmd) {
|
void RecordWriteTimestampCmd(ID3D12GraphicsCommandList* commandList,
|
||||||
QuerySet* querySet = ToBackend(cmd->querySet.Get());
|
QuerySetBase* querySet,
|
||||||
ASSERT(D3D12QueryType(querySet->GetQueryType()) == D3D12_QUERY_TYPE_TIMESTAMP);
|
uint32_t queryIndex) {
|
||||||
commandList->EndQuery(querySet->GetQueryHeap(), D3D12_QUERY_TYPE_TIMESTAMP, cmd->queryIndex);
|
ASSERT(D3D12QueryType(ToBackend(querySet)->GetQueryType()) == D3D12_QUERY_TYPE_TIMESTAMP);
|
||||||
|
commandList->EndQuery(ToBackend(querySet)->GetQueryHeap(), D3D12_QUERY_TYPE_TIMESTAMP,
|
||||||
|
queryIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecordResolveQuerySetCmd(ID3D12GraphicsCommandList* commandList,
|
void RecordResolveQuerySetCmd(ID3D12GraphicsCommandList* commandList,
|
||||||
@ -653,11 +655,12 @@ MaybeError CommandBuffer::RecordCommands(CommandRecordingContext* commandContext
|
|||||||
while (mCommands.NextCommandId(&type)) {
|
while (mCommands.NextCommandId(&type)) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Command::BeginComputePass: {
|
case Command::BeginComputePass: {
|
||||||
mCommands.NextCommand<BeginComputePassCmd>();
|
BeginComputePassCmd* cmd = mCommands.NextCommand<BeginComputePassCmd>();
|
||||||
|
|
||||||
bindingTracker.SetInComputePass(true);
|
bindingTracker.SetInComputePass(true);
|
||||||
|
|
||||||
DAWN_TRY(
|
DAWN_TRY(
|
||||||
RecordComputePass(commandContext, &bindingTracker,
|
RecordComputePass(commandContext, &bindingTracker, cmd,
|
||||||
GetResourceUsages().computePasses[nextComputePassNumber]));
|
GetResourceUsages().computePasses[nextComputePassNumber]));
|
||||||
|
|
||||||
nextComputePassNumber++;
|
nextComputePassNumber++;
|
||||||
@ -942,7 +945,7 @@ MaybeError CommandBuffer::RecordCommands(CommandRecordingContext* commandContext
|
|||||||
case Command::WriteTimestamp: {
|
case Command::WriteTimestamp: {
|
||||||
WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
|
WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
|
||||||
|
|
||||||
RecordWriteTimestampCmd(commandList, cmd);
|
RecordWriteTimestampCmd(commandList, cmd->querySet.Get(), cmd->queryIndex);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1023,10 +1026,17 @@ MaybeError CommandBuffer::RecordCommands(CommandRecordingContext* commandContext
|
|||||||
|
|
||||||
MaybeError CommandBuffer::RecordComputePass(CommandRecordingContext* commandContext,
|
MaybeError CommandBuffer::RecordComputePass(CommandRecordingContext* commandContext,
|
||||||
BindGroupStateTracker* bindingTracker,
|
BindGroupStateTracker* bindingTracker,
|
||||||
|
BeginComputePassCmd* computePass,
|
||||||
const ComputePassResourceUsage& resourceUsages) {
|
const ComputePassResourceUsage& resourceUsages) {
|
||||||
uint64_t currentDispatch = 0;
|
uint64_t currentDispatch = 0;
|
||||||
ID3D12GraphicsCommandList* commandList = commandContext->GetCommandList();
|
ID3D12GraphicsCommandList* commandList = commandContext->GetCommandList();
|
||||||
|
|
||||||
|
// Write timestamp at the beginning of compute pass if it's set.
|
||||||
|
if (computePass->beginTimestamp.querySet.Get() != nullptr) {
|
||||||
|
RecordWriteTimestampCmd(commandList, computePass->beginTimestamp.querySet.Get(),
|
||||||
|
computePass->beginTimestamp.queryIndex);
|
||||||
|
}
|
||||||
|
|
||||||
Command type;
|
Command type;
|
||||||
ComputePipeline* lastPipeline = nullptr;
|
ComputePipeline* lastPipeline = nullptr;
|
||||||
while (mCommands.NextCommandId(&type)) {
|
while (mCommands.NextCommandId(&type)) {
|
||||||
@ -1068,6 +1078,12 @@ MaybeError CommandBuffer::RecordComputePass(CommandRecordingContext* commandCont
|
|||||||
|
|
||||||
case Command::EndComputePass: {
|
case Command::EndComputePass: {
|
||||||
mCommands.NextCommand<EndComputePassCmd>();
|
mCommands.NextCommand<EndComputePassCmd>();
|
||||||
|
|
||||||
|
// Write timestamp at the end of compute pass if it's set.
|
||||||
|
if (computePass->endTimestamp.querySet.Get() != nullptr) {
|
||||||
|
RecordWriteTimestampCmd(commandList, computePass->endTimestamp.querySet.Get(),
|
||||||
|
computePass->endTimestamp.queryIndex);
|
||||||
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1136,7 +1152,7 @@ MaybeError CommandBuffer::RecordComputePass(CommandRecordingContext* commandCont
|
|||||||
case Command::WriteTimestamp: {
|
case Command::WriteTimestamp: {
|
||||||
WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
|
WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
|
||||||
|
|
||||||
RecordWriteTimestampCmd(commandList, cmd);
|
RecordWriteTimestampCmd(commandList, cmd->querySet.Get(), cmd->queryIndex);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1339,6 +1355,12 @@ MaybeError CommandBuffer::RecordRenderPass(CommandRecordingContext* commandConte
|
|||||||
|
|
||||||
ID3D12GraphicsCommandList* commandList = commandContext->GetCommandList();
|
ID3D12GraphicsCommandList* commandList = commandContext->GetCommandList();
|
||||||
|
|
||||||
|
// Write timestamp at the beginning of render pass if it's set.
|
||||||
|
if (renderPass->beginTimestamp.querySet.Get() != nullptr) {
|
||||||
|
RecordWriteTimestampCmd(commandList, renderPass->beginTimestamp.querySet.Get(),
|
||||||
|
renderPass->beginTimestamp.queryIndex);
|
||||||
|
}
|
||||||
|
|
||||||
// Set up default dynamic state
|
// Set up default dynamic state
|
||||||
{
|
{
|
||||||
uint32_t width = renderPass->width;
|
uint32_t width = renderPass->width;
|
||||||
@ -1511,6 +1533,13 @@ MaybeError CommandBuffer::RecordRenderPass(CommandRecordingContext* commandConte
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case Command::EndRenderPass: {
|
case Command::EndRenderPass: {
|
||||||
mCommands.NextCommand<EndRenderPassCmd>();
|
mCommands.NextCommand<EndRenderPassCmd>();
|
||||||
|
|
||||||
|
// Write timestamp at the end of render pass if it's set.
|
||||||
|
if (renderPass->endTimestamp.querySet.Get() != nullptr) {
|
||||||
|
RecordWriteTimestampCmd(commandList, renderPass->endTimestamp.querySet.Get(),
|
||||||
|
renderPass->endTimestamp.queryIndex);
|
||||||
|
}
|
||||||
|
|
||||||
if (useRenderPass) {
|
if (useRenderPass) {
|
||||||
commandContext->GetCommandList4()->EndRenderPass();
|
commandContext->GetCommandList4()->EndRenderPass();
|
||||||
} else if (renderPass->attachmentState->GetSampleCount() > 1) {
|
} else if (renderPass->attachmentState->GetSampleCount() > 1) {
|
||||||
@ -1596,7 +1625,7 @@ MaybeError CommandBuffer::RecordRenderPass(CommandRecordingContext* commandConte
|
|||||||
case Command::WriteTimestamp: {
|
case Command::WriteTimestamp: {
|
||||||
WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
|
WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
|
||||||
|
|
||||||
RecordWriteTimestampCmd(commandList, cmd);
|
RecordWriteTimestampCmd(commandList, cmd->querySet.Get(), cmd->queryIndex);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "dawn/native/Error.h"
|
#include "dawn/native/Error.h"
|
||||||
|
|
||||||
namespace dawn::native {
|
namespace dawn::native {
|
||||||
|
struct BeginComputePassCmd;
|
||||||
struct BeginRenderPassCmd;
|
struct BeginRenderPassCmd;
|
||||||
} // namespace dawn::native
|
} // namespace dawn::native
|
||||||
|
|
||||||
@ -40,6 +41,7 @@ class CommandBuffer final : public CommandBufferBase {
|
|||||||
|
|
||||||
MaybeError RecordComputePass(CommandRecordingContext* commandContext,
|
MaybeError RecordComputePass(CommandRecordingContext* commandContext,
|
||||||
BindGroupStateTracker* bindingTracker,
|
BindGroupStateTracker* bindingTracker,
|
||||||
|
BeginComputePassCmd* computePass,
|
||||||
const ComputePassResourceUsage& resourceUsages);
|
const ComputePassResourceUsage& resourceUsages);
|
||||||
MaybeError RecordRenderPass(CommandRecordingContext* commandContext,
|
MaybeError RecordRenderPass(CommandRecordingContext* commandContext,
|
||||||
BindGroupStateTracker* bindingTracker,
|
BindGroupStateTracker* bindingTracker,
|
||||||
|
@ -610,7 +610,12 @@ MaybeError CommandBuffer::FillCommands(CommandRecordingContext* commandContext)
|
|||||||
while (mCommands.NextCommandId(&type)) {
|
while (mCommands.NextCommandId(&type)) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Command::BeginComputePass: {
|
case Command::BeginComputePass: {
|
||||||
mCommands.NextCommand<BeginComputePassCmd>();
|
BeginComputePassCmd* cmd = mCommands.NextCommand<BeginComputePassCmd>();
|
||||||
|
|
||||||
|
if (cmd->beginTimestamp.querySet.Get() != nullptr ||
|
||||||
|
cmd->endTimestamp.querySet.Get() != nullptr) {
|
||||||
|
return DAWN_UNIMPLEMENTED_ERROR("timestampWrites unimplemented.");
|
||||||
|
}
|
||||||
|
|
||||||
for (const SyncScopeResourceUsage& scope :
|
for (const SyncScopeResourceUsage& scope :
|
||||||
GetResourceUsages().computePasses[nextComputePassNumber].dispatchUsages) {
|
GetResourceUsages().computePasses[nextComputePassNumber].dispatchUsages) {
|
||||||
@ -627,6 +632,11 @@ MaybeError CommandBuffer::FillCommands(CommandRecordingContext* commandContext)
|
|||||||
case Command::BeginRenderPass: {
|
case Command::BeginRenderPass: {
|
||||||
BeginRenderPassCmd* cmd = mCommands.NextCommand<BeginRenderPassCmd>();
|
BeginRenderPassCmd* cmd = mCommands.NextCommand<BeginRenderPassCmd>();
|
||||||
|
|
||||||
|
if (cmd->beginTimestamp.querySet.Get() != nullptr ||
|
||||||
|
cmd->endTimestamp.querySet.Get() != nullptr) {
|
||||||
|
return DAWN_UNIMPLEMENTED_ERROR("timestampWrites unimplemented.");
|
||||||
|
}
|
||||||
|
|
||||||
LazyClearSyncScope(GetResourceUsages().renderPasses[nextRenderPassNumber],
|
LazyClearSyncScope(GetResourceUsages().renderPasses[nextRenderPassNumber],
|
||||||
commandContext);
|
commandContext);
|
||||||
commandContext->EndBlit();
|
commandContext->EndBlit();
|
||||||
|
@ -377,12 +377,19 @@ void ResetUsedQuerySetsOnRenderPass(Device* device,
|
|||||||
|
|
||||||
void RecordWriteTimestampCmd(CommandRecordingContext* recordingContext,
|
void RecordWriteTimestampCmd(CommandRecordingContext* recordingContext,
|
||||||
Device* device,
|
Device* device,
|
||||||
WriteTimestampCmd* cmd) {
|
QuerySetBase* querySet,
|
||||||
|
uint32_t queryIndex,
|
||||||
|
bool isRenderPass) {
|
||||||
VkCommandBuffer commands = recordingContext->commandBuffer;
|
VkCommandBuffer commands = recordingContext->commandBuffer;
|
||||||
QuerySet* querySet = ToBackend(cmd->querySet.Get());
|
|
||||||
|
// The queries must be reset between uses, and the reset command cannot be called in render
|
||||||
|
// pass.
|
||||||
|
if (!isRenderPass) {
|
||||||
|
device->fn.CmdResetQueryPool(commands, ToBackend(querySet)->GetHandle(), queryIndex, 1);
|
||||||
|
}
|
||||||
|
|
||||||
device->fn.CmdWriteTimestamp(commands, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
device->fn.CmdWriteTimestamp(commands, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||||
querySet->GetHandle(), cmd->queryIndex);
|
ToBackend(querySet)->GetHandle(), queryIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecordResolveQuerySetCmd(VkCommandBuffer commands,
|
void RecordResolveQuerySetCmd(VkCommandBuffer commands,
|
||||||
@ -735,10 +742,11 @@ MaybeError CommandBuffer::RecordCommands(CommandRecordingContext* recordingConte
|
|||||||
}
|
}
|
||||||
|
|
||||||
case Command::BeginComputePass: {
|
case Command::BeginComputePass: {
|
||||||
mCommands.NextCommand<BeginComputePassCmd>();
|
BeginComputePassCmd* cmd = mCommands.NextCommand<BeginComputePassCmd>();
|
||||||
|
|
||||||
DAWN_TRY(RecordComputePass(
|
DAWN_TRY(
|
||||||
recordingContext, GetResourceUsages().computePasses[nextComputePassNumber]));
|
RecordComputePass(recordingContext, cmd,
|
||||||
|
GetResourceUsages().computePasses[nextComputePassNumber]));
|
||||||
|
|
||||||
nextComputePassNumber++;
|
nextComputePassNumber++;
|
||||||
break;
|
break;
|
||||||
@ -777,11 +785,8 @@ MaybeError CommandBuffer::RecordCommands(CommandRecordingContext* recordingConte
|
|||||||
case Command::WriteTimestamp: {
|
case Command::WriteTimestamp: {
|
||||||
WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
|
WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
|
||||||
|
|
||||||
// The query must be reset between uses.
|
RecordWriteTimestampCmd(recordingContext, device, cmd->querySet.Get(),
|
||||||
device->fn.CmdResetQueryPool(commands, ToBackend(cmd->querySet)->GetHandle(),
|
cmd->queryIndex, false);
|
||||||
cmd->queryIndex, 1);
|
|
||||||
|
|
||||||
RecordWriteTimestampCmd(recordingContext, device, cmd);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -878,8 +883,17 @@ MaybeError CommandBuffer::RecordCommands(CommandRecordingContext* recordingConte
|
|||||||
}
|
}
|
||||||
|
|
||||||
MaybeError CommandBuffer::RecordComputePass(CommandRecordingContext* recordingContext,
|
MaybeError CommandBuffer::RecordComputePass(CommandRecordingContext* recordingContext,
|
||||||
|
BeginComputePassCmd* computePassCmd,
|
||||||
const ComputePassResourceUsage& resourceUsages) {
|
const ComputePassResourceUsage& resourceUsages) {
|
||||||
Device* device = ToBackend(GetDevice());
|
Device* device = ToBackend(GetDevice());
|
||||||
|
|
||||||
|
// Write timestamp at the beginning of compute pass if it's set
|
||||||
|
if (computePassCmd->beginTimestamp.querySet.Get() != nullptr) {
|
||||||
|
RecordWriteTimestampCmd(recordingContext, device,
|
||||||
|
computePassCmd->beginTimestamp.querySet.Get(),
|
||||||
|
computePassCmd->beginTimestamp.queryIndex, false);
|
||||||
|
}
|
||||||
|
|
||||||
VkCommandBuffer commands = recordingContext->commandBuffer;
|
VkCommandBuffer commands = recordingContext->commandBuffer;
|
||||||
|
|
||||||
uint64_t currentDispatch = 0;
|
uint64_t currentDispatch = 0;
|
||||||
@ -890,6 +904,13 @@ MaybeError CommandBuffer::RecordComputePass(CommandRecordingContext* recordingCo
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case Command::EndComputePass: {
|
case Command::EndComputePass: {
|
||||||
mCommands.NextCommand<EndComputePassCmd>();
|
mCommands.NextCommand<EndComputePassCmd>();
|
||||||
|
|
||||||
|
// Write timestamp at the end of compute pass if it's set.
|
||||||
|
if (computePassCmd->endTimestamp.querySet.Get() != nullptr) {
|
||||||
|
RecordWriteTimestampCmd(recordingContext, device,
|
||||||
|
computePassCmd->endTimestamp.querySet.Get(),
|
||||||
|
computePassCmd->endTimestamp.queryIndex, false);
|
||||||
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -996,11 +1017,8 @@ MaybeError CommandBuffer::RecordComputePass(CommandRecordingContext* recordingCo
|
|||||||
case Command::WriteTimestamp: {
|
case Command::WriteTimestamp: {
|
||||||
WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
|
WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
|
||||||
|
|
||||||
// The query must be reset between uses.
|
RecordWriteTimestampCmd(recordingContext, device, cmd->querySet.Get(),
|
||||||
device->fn.CmdResetQueryPool(commands, ToBackend(cmd->querySet)->GetHandle(),
|
cmd->queryIndex, false);
|
||||||
cmd->queryIndex, 1);
|
|
||||||
|
|
||||||
RecordWriteTimestampCmd(recordingContext, device, cmd);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1020,6 +1038,13 @@ MaybeError CommandBuffer::RecordRenderPass(CommandRecordingContext* recordingCon
|
|||||||
|
|
||||||
DAWN_TRY(RecordBeginRenderPass(recordingContext, device, renderPassCmd));
|
DAWN_TRY(RecordBeginRenderPass(recordingContext, device, renderPassCmd));
|
||||||
|
|
||||||
|
// Write timestamp at the beginning of render pass if it's set.
|
||||||
|
if (renderPassCmd->beginTimestamp.querySet.Get() != nullptr) {
|
||||||
|
RecordWriteTimestampCmd(recordingContext, device,
|
||||||
|
renderPassCmd->beginTimestamp.querySet.Get(),
|
||||||
|
renderPassCmd->beginTimestamp.queryIndex, true);
|
||||||
|
}
|
||||||
|
|
||||||
// Set the default value for the dynamic state
|
// Set the default value for the dynamic state
|
||||||
{
|
{
|
||||||
device->fn.CmdSetLineWidth(commands, 1.0f);
|
device->fn.CmdSetLineWidth(commands, 1.0f);
|
||||||
@ -1203,6 +1228,14 @@ MaybeError CommandBuffer::RecordRenderPass(CommandRecordingContext* recordingCon
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case Command::EndRenderPass: {
|
case Command::EndRenderPass: {
|
||||||
mCommands.NextCommand<EndRenderPassCmd>();
|
mCommands.NextCommand<EndRenderPassCmd>();
|
||||||
|
|
||||||
|
// Write timestamp at the end of render pass if it's set.
|
||||||
|
if (renderPassCmd->endTimestamp.querySet.Get() != nullptr) {
|
||||||
|
RecordWriteTimestampCmd(recordingContext, device,
|
||||||
|
renderPassCmd->endTimestamp.querySet.Get(),
|
||||||
|
renderPassCmd->endTimestamp.queryIndex, true);
|
||||||
|
}
|
||||||
|
|
||||||
device->fn.CmdEndRenderPass(commands);
|
device->fn.CmdEndRenderPass(commands);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -1290,7 +1323,8 @@ MaybeError CommandBuffer::RecordRenderPass(CommandRecordingContext* recordingCon
|
|||||||
case Command::WriteTimestamp: {
|
case Command::WriteTimestamp: {
|
||||||
WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
|
WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
|
||||||
|
|
||||||
RecordWriteTimestampCmd(recordingContext, device, cmd);
|
RecordWriteTimestampCmd(recordingContext, device, cmd->querySet.Get(),
|
||||||
|
cmd->queryIndex, true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "dawn/common/vulkan_platform.h"
|
#include "dawn/common/vulkan_platform.h"
|
||||||
|
|
||||||
namespace dawn::native {
|
namespace dawn::native {
|
||||||
|
struct BeginComputePassCmd;
|
||||||
struct BeginRenderPassCmd;
|
struct BeginRenderPassCmd;
|
||||||
struct TextureCopy;
|
struct TextureCopy;
|
||||||
} // namespace dawn::native
|
} // namespace dawn::native
|
||||||
@ -41,6 +42,7 @@ class CommandBuffer final : public CommandBufferBase {
|
|||||||
CommandBuffer(CommandEncoder* encoder, const CommandBufferDescriptor* descriptor);
|
CommandBuffer(CommandEncoder* encoder, const CommandBufferDescriptor* descriptor);
|
||||||
|
|
||||||
MaybeError RecordComputePass(CommandRecordingContext* recordingContext,
|
MaybeError RecordComputePass(CommandRecordingContext* recordingContext,
|
||||||
|
BeginComputePassCmd* computePass,
|
||||||
const ComputePassResourceUsage& resourceUsages);
|
const ComputePassResourceUsage& resourceUsages);
|
||||||
MaybeError RecordRenderPass(CommandRecordingContext* recordingContext,
|
MaybeError RecordRenderPass(CommandRecordingContext* recordingContext,
|
||||||
BeginRenderPassCmd* renderPass);
|
BeginRenderPassCmd* renderPass);
|
||||||
|
@ -302,7 +302,7 @@ TEST_P(OcclusionQueryTests, Rewrite) {
|
|||||||
// the query resetting at the start of render passes on Vulkan backend.
|
// the query resetting at the start of render passes on Vulkan backend.
|
||||||
TEST_P(OcclusionQueryTests, ResolveSparseQueries) {
|
TEST_P(OcclusionQueryTests, ResolveSparseQueries) {
|
||||||
// TODO(hao.x.li@intel.com): Fails on Intel Windows Vulkan due to a driver issue that
|
// TODO(hao.x.li@intel.com): Fails on Intel Windows Vulkan due to a driver issue that
|
||||||
// vkCmdFillBuffer and vkCmdCopyQueryPoolResults are not executed in order, skip it util
|
// vkCmdFillBuffer and vkCmdCopyQueryPoolResults are not executed in order, skip it until
|
||||||
// the issue is fixed.
|
// the issue is fixed.
|
||||||
DAWN_SUPPRESS_TEST_IF(IsWindows() && IsVulkan() && IsIntel());
|
DAWN_SUPPRESS_TEST_IF(IsWindows() && IsVulkan() && IsIntel());
|
||||||
|
|
||||||
@ -523,6 +523,17 @@ class TimestampQueryTests : public QueryTests {
|
|||||||
|
|
||||||
// Skip all tests if timestamp feature is not supported
|
// Skip all tests if timestamp feature is not supported
|
||||||
DAWN_TEST_UNSUPPORTED_IF(!SupportsFeatures({wgpu::FeatureName::TimestampQuery}));
|
DAWN_TEST_UNSUPPORTED_IF(!SupportsFeatures({wgpu::FeatureName::TimestampQuery}));
|
||||||
|
|
||||||
|
// Create basic compute pipeline
|
||||||
|
wgpu::ShaderModule module = utils::CreateShaderModule(device, R"(
|
||||||
|
@compute @workgroup_size(1)
|
||||||
|
fn main() {
|
||||||
|
})");
|
||||||
|
|
||||||
|
wgpu::ComputePipelineDescriptor csDesc;
|
||||||
|
csDesc.compute.module = module;
|
||||||
|
csDesc.compute.entryPoint = "main";
|
||||||
|
computePipeline = device.CreateComputePipeline(&csDesc);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<wgpu::FeatureName> GetRequiredFeatures() override {
|
std::vector<wgpu::FeatureName> GetRequiredFeatures() override {
|
||||||
@ -539,6 +550,113 @@ class TimestampQueryTests : public QueryTests {
|
|||||||
descriptor.type = wgpu::QueryType::Timestamp;
|
descriptor.type = wgpu::QueryType::Timestamp;
|
||||||
return device.CreateQuerySet(&descriptor);
|
return device.CreateQuerySet(&descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestTimestampWritesOnComputePass(
|
||||||
|
const std::vector<wgpu::ComputePassTimestampWrite>& timestampWrites,
|
||||||
|
const std::vector<wgpu::ComputePassTimestampWrite>& timestampWritesOnAnotherPass = {}) {
|
||||||
|
size_t queryCount = timestampWrites.size() + timestampWritesOnAnotherPass.size();
|
||||||
|
// The destination buffer offset must be a multiple of 256.
|
||||||
|
wgpu::Buffer destination =
|
||||||
|
CreateResolveBuffer(queryCount * kMinDestinationOffset + sizeof(uint64_t));
|
||||||
|
|
||||||
|
wgpu::ComputePassDescriptor descriptor;
|
||||||
|
descriptor.timestampWriteCount = timestampWrites.size();
|
||||||
|
descriptor.timestampWrites = timestampWrites.data();
|
||||||
|
|
||||||
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||||
|
wgpu::ComputePassEncoder pass = encoder.BeginComputePass(&descriptor);
|
||||||
|
pass.SetPipeline(computePipeline);
|
||||||
|
pass.DispatchWorkgroups(1, 1, 1);
|
||||||
|
pass.End();
|
||||||
|
|
||||||
|
// Resolve queries one by one because the query set at the beginning of pass may be
|
||||||
|
// different with the one at the end of pass.
|
||||||
|
for (size_t i = 0; i < timestampWrites.size(); i++) {
|
||||||
|
encoder.ResolveQuerySet(timestampWrites[i].querySet, timestampWrites[i].queryIndex, 1,
|
||||||
|
destination, i * kMinDestinationOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Begin another compute pass if the timestampWritesOnAnotherPass is set.
|
||||||
|
if (!timestampWritesOnAnotherPass.empty()) {
|
||||||
|
wgpu::ComputePassDescriptor descriptor2;
|
||||||
|
descriptor2.timestampWriteCount = timestampWritesOnAnotherPass.size();
|
||||||
|
descriptor2.timestampWrites = timestampWritesOnAnotherPass.data();
|
||||||
|
|
||||||
|
wgpu::ComputePassEncoder pass2 = encoder.BeginComputePass(&descriptor2);
|
||||||
|
pass2.SetPipeline(computePipeline);
|
||||||
|
pass2.DispatchWorkgroups(1, 1, 1);
|
||||||
|
pass2.End();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < timestampWritesOnAnotherPass.size(); i++) {
|
||||||
|
// Resolve queries one by one because the query set at the beginning of pass may be
|
||||||
|
// different with the one at the end of pass.
|
||||||
|
encoder.ResolveQuerySet(timestampWritesOnAnotherPass[i].querySet,
|
||||||
|
timestampWritesOnAnotherPass[i].queryIndex, 1, destination,
|
||||||
|
(timestampWrites.size() + i) * kMinDestinationOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wgpu::CommandBuffer commands = encoder.Finish();
|
||||||
|
queue.Submit(1, &commands);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < queryCount; i++) {
|
||||||
|
EXPECT_BUFFER(destination, i * kMinDestinationOffset, sizeof(uint64_t),
|
||||||
|
new TimestampExpectation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestTimestampWritesOnRenderPass(
|
||||||
|
const std::vector<wgpu::RenderPassTimestampWrite>& timestampWrites,
|
||||||
|
const std::vector<wgpu::RenderPassTimestampWrite>& timestampWritesOnAnotherPass = {}) {
|
||||||
|
size_t queryCount = timestampWrites.size() + timestampWritesOnAnotherPass.size();
|
||||||
|
// The destination buffer offset must be a multiple of 256.
|
||||||
|
wgpu::Buffer destination =
|
||||||
|
CreateResolveBuffer(queryCount * kMinDestinationOffset + sizeof(uint64_t));
|
||||||
|
|
||||||
|
utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 1, 1);
|
||||||
|
renderPass.renderPassInfo.timestampWriteCount = timestampWrites.size();
|
||||||
|
renderPass.renderPassInfo.timestampWrites = timestampWrites.data();
|
||||||
|
|
||||||
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||||
|
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
|
||||||
|
pass.End();
|
||||||
|
|
||||||
|
// Resolve queries one by one because the query set at the beginning of pass may be
|
||||||
|
// different with the one at the end of pass.
|
||||||
|
for (size_t i = 0; i < timestampWrites.size(); i++) {
|
||||||
|
encoder.ResolveQuerySet(timestampWrites[i].querySet, timestampWrites[i].queryIndex, 1,
|
||||||
|
destination, i * kMinDestinationOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Begin another render pass if the timestampWritesOnAnotherPass is set.
|
||||||
|
if (!timestampWritesOnAnotherPass.empty()) {
|
||||||
|
utils::BasicRenderPass renderPass2 = utils::CreateBasicRenderPass(device, 1, 1);
|
||||||
|
renderPass2.renderPassInfo.timestampWriteCount = timestampWritesOnAnotherPass.size();
|
||||||
|
renderPass2.renderPassInfo.timestampWrites = timestampWritesOnAnotherPass.data();
|
||||||
|
|
||||||
|
wgpu::RenderPassEncoder pass2 = encoder.BeginRenderPass(&renderPass2.renderPassInfo);
|
||||||
|
pass2.End();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < timestampWritesOnAnotherPass.size(); i++) {
|
||||||
|
// Resolve queries one by one because the query set at the beginning of pass may be
|
||||||
|
// different with the one at the end of pass.
|
||||||
|
encoder.ResolveQuerySet(timestampWritesOnAnotherPass[i].querySet,
|
||||||
|
timestampWritesOnAnotherPass[i].queryIndex, 1, destination,
|
||||||
|
(timestampWrites.size() + i) * kMinDestinationOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wgpu::CommandBuffer commands = encoder.Finish();
|
||||||
|
queue.Submit(1, &commands);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < queryCount; i++) {
|
||||||
|
EXPECT_BUFFER(destination, i * kMinDestinationOffset, sizeof(uint64_t),
|
||||||
|
new TimestampExpectation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
wgpu::ComputePipeline computePipeline;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Test creating query set with the type of Timestamp
|
// Test creating query set with the type of Timestamp
|
||||||
@ -551,6 +669,9 @@ TEST_P(TimestampQueryTests, QuerySetCreation) {
|
|||||||
|
|
||||||
// Test calling timestamp query from command encoder
|
// Test calling timestamp query from command encoder
|
||||||
TEST_P(TimestampQueryTests, TimestampOnCommandEncoder) {
|
TEST_P(TimestampQueryTests, TimestampOnCommandEncoder) {
|
||||||
|
// TODO (dawn:1250): Still not implemented on Metal backend.
|
||||||
|
DAWN_TEST_UNSUPPORTED_IF(IsMetal());
|
||||||
|
|
||||||
constexpr uint32_t kQueryCount = 2;
|
constexpr uint32_t kQueryCount = 2;
|
||||||
|
|
||||||
// Write timestamp with different query indexes
|
// Write timestamp with different query indexes
|
||||||
@ -694,6 +815,124 @@ TEST_P(TimestampQueryTests, TimestampOnComputePass) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test timestampWrites setting in compute pass descriptor
|
||||||
|
TEST_P(TimestampQueryTests, TimestampWritesOnComputePass) {
|
||||||
|
// TODO(dawn:1489): Fails on Intel Windows Vulkan due to a driver issue that
|
||||||
|
// vkCmdFillBuffer and vkCmdCopyQueryPoolResults are not executed in order, skip it until
|
||||||
|
// the issue is fixed.
|
||||||
|
DAWN_SUPPRESS_TEST_IF(IsWindows() && IsVulkan() && IsIntel());
|
||||||
|
|
||||||
|
// TODO (dawn:1250): Still not implemented on Metal backend.
|
||||||
|
DAWN_TEST_UNSUPPORTED_IF(IsMetal());
|
||||||
|
|
||||||
|
constexpr uint32_t kQueryCount = 2;
|
||||||
|
|
||||||
|
// Set timestampWrites with different query indexes and locations on same compute pass
|
||||||
|
{
|
||||||
|
wgpu::QuerySet querySet = CreateQuerySetForTimestamp(kQueryCount);
|
||||||
|
|
||||||
|
TestTimestampWritesOnComputePass(
|
||||||
|
{{querySet, 0, wgpu::ComputePassTimestampLocation::Beginning},
|
||||||
|
{querySet, 1, wgpu::ComputePassTimestampLocation::End}});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set timestampWrites with different query set on same compute pass
|
||||||
|
{
|
||||||
|
wgpu::QuerySet querySet0 = CreateQuerySetForTimestamp(1);
|
||||||
|
wgpu::QuerySet querySet1 = CreateQuerySetForTimestamp(1);
|
||||||
|
|
||||||
|
TestTimestampWritesOnComputePass(
|
||||||
|
{{querySet0, 0, wgpu::ComputePassTimestampLocation::Beginning},
|
||||||
|
{querySet1, 0, wgpu::ComputePassTimestampLocation::End}});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set timestampWrites with only one value of ComputePassTimestampLocation
|
||||||
|
{
|
||||||
|
wgpu::QuerySet querySet = CreateQuerySetForTimestamp(kQueryCount);
|
||||||
|
|
||||||
|
TestTimestampWritesOnComputePass(
|
||||||
|
{{querySet, 0, wgpu::ComputePassTimestampLocation::Beginning}});
|
||||||
|
|
||||||
|
TestTimestampWritesOnComputePass({{querySet, 1, wgpu::ComputePassTimestampLocation::End}});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set timestampWrites with same query set and query index on same compute pass
|
||||||
|
{
|
||||||
|
wgpu::QuerySet querySet = CreateQuerySetForTimestamp(kQueryCount);
|
||||||
|
|
||||||
|
TestTimestampWritesOnComputePass(
|
||||||
|
{{querySet, 0, wgpu::ComputePassTimestampLocation::Beginning},
|
||||||
|
{querySet, 0, wgpu::ComputePassTimestampLocation::End}});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set timestampWrites with same query indexes and locations on different compute pass
|
||||||
|
{
|
||||||
|
wgpu::QuerySet querySet0 = CreateQuerySetForTimestamp(kQueryCount);
|
||||||
|
wgpu::QuerySet querySet1 = CreateQuerySetForTimestamp(kQueryCount);
|
||||||
|
|
||||||
|
TestTimestampWritesOnComputePass(
|
||||||
|
{{querySet0, 0, wgpu::ComputePassTimestampLocation::Beginning},
|
||||||
|
{querySet0, 1, wgpu::ComputePassTimestampLocation::End}},
|
||||||
|
{{querySet1, 0, wgpu::ComputePassTimestampLocation::Beginning},
|
||||||
|
{querySet1, 1, wgpu::ComputePassTimestampLocation::End}});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test timestampWrites setting in render pass descriptor
|
||||||
|
TEST_P(TimestampQueryTests, TimestampWritesOnRenderPass) {
|
||||||
|
// TODO(dawn:1489): Fails on Intel Windows Vulkan due to a driver issue that
|
||||||
|
// vkCmdFillBuffer and vkCmdCopyQueryPoolResults are not executed in order, skip it until
|
||||||
|
// the issue is fixed.
|
||||||
|
DAWN_SUPPRESS_TEST_IF(IsWindows() && IsVulkan() && IsIntel());
|
||||||
|
|
||||||
|
// TODO (dawn:1250): Still not implemented on Metal backend.
|
||||||
|
DAWN_TEST_UNSUPPORTED_IF(IsMetal());
|
||||||
|
|
||||||
|
constexpr uint32_t kQueryCount = 2;
|
||||||
|
|
||||||
|
// Set timestampWrites with different query indexes and locations, not need test write same
|
||||||
|
// query index due to it's not allowed on render pass.
|
||||||
|
{
|
||||||
|
wgpu::QuerySet querySet = CreateQuerySetForTimestamp(kQueryCount);
|
||||||
|
|
||||||
|
TestTimestampWritesOnRenderPass(
|
||||||
|
{{querySet, 0, wgpu::RenderPassTimestampLocation::Beginning},
|
||||||
|
{querySet, 1, wgpu::RenderPassTimestampLocation::End}});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set timestampWrites with different query set on same render pass
|
||||||
|
{
|
||||||
|
wgpu::QuerySet querySet0 = CreateQuerySetForTimestamp(1);
|
||||||
|
wgpu::QuerySet querySet1 = CreateQuerySetForTimestamp(1);
|
||||||
|
|
||||||
|
TestTimestampWritesOnRenderPass(
|
||||||
|
{{querySet0, 0, wgpu::RenderPassTimestampLocation::Beginning},
|
||||||
|
{querySet1, 0, wgpu::RenderPassTimestampLocation::End}});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set timestampWrites with only one value of RenderPassTimestampLocation
|
||||||
|
{
|
||||||
|
wgpu::QuerySet querySet = CreateQuerySetForTimestamp(kQueryCount);
|
||||||
|
|
||||||
|
TestTimestampWritesOnRenderPass(
|
||||||
|
{{querySet, 0, wgpu::RenderPassTimestampLocation::Beginning}});
|
||||||
|
|
||||||
|
TestTimestampWritesOnRenderPass({{querySet, 1, wgpu::RenderPassTimestampLocation::End}});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set timestampWrites with same query indexes and locations on different render pass
|
||||||
|
{
|
||||||
|
wgpu::QuerySet querySet0 = CreateQuerySetForTimestamp(kQueryCount);
|
||||||
|
wgpu::QuerySet querySet1 = CreateQuerySetForTimestamp(kQueryCount);
|
||||||
|
|
||||||
|
TestTimestampWritesOnRenderPass(
|
||||||
|
{{querySet0, 0, wgpu::RenderPassTimestampLocation::Beginning},
|
||||||
|
{querySet0, 1, wgpu::RenderPassTimestampLocation::End}},
|
||||||
|
{{querySet1, 0, wgpu::RenderPassTimestampLocation::Beginning},
|
||||||
|
{querySet1, 1, wgpu::RenderPassTimestampLocation::End}});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Test resolving timestamp query from another different encoder
|
// Test resolving timestamp query from another different encoder
|
||||||
TEST_P(TimestampQueryTests, ResolveFromAnotherEncoder) {
|
TEST_P(TimestampQueryTests, ResolveFromAnotherEncoder) {
|
||||||
constexpr uint32_t kQueryCount = 2;
|
constexpr uint32_t kQueryCount = 2;
|
||||||
@ -717,8 +956,8 @@ TEST_P(TimestampQueryTests, ResolveFromAnotherEncoder) {
|
|||||||
|
|
||||||
// Test resolving timestamp query correctly if the queries are written sparsely
|
// Test resolving timestamp query correctly if the queries are written sparsely
|
||||||
TEST_P(TimestampQueryTests, ResolveSparseQueries) {
|
TEST_P(TimestampQueryTests, ResolveSparseQueries) {
|
||||||
// TODO(hao.x.li@intel.com): Fails on Intel Windows Vulkan due to a driver issue that
|
// TODO(dawn:1489): Fails on Intel Windows Vulkan due to a driver issue that
|
||||||
// vkCmdFillBuffer and vkCmdCopyQueryPoolResults are not executed in order, skip it util
|
// vkCmdFillBuffer and vkCmdCopyQueryPoolResults are not executed in order, skip it until
|
||||||
// the issue is fixed.
|
// the issue is fixed.
|
||||||
DAWN_SUPPRESS_TEST_IF(IsWindows() && IsVulkan() && IsIntel());
|
DAWN_SUPPRESS_TEST_IF(IsWindows() && IsVulkan() && IsIntel());
|
||||||
|
|
||||||
@ -768,8 +1007,8 @@ TEST_P(TimestampQueryTests, ResolveWithoutWritten) {
|
|||||||
|
|
||||||
// Test resolving timestamp query to one slot in the buffer
|
// Test resolving timestamp query to one slot in the buffer
|
||||||
TEST_P(TimestampQueryTests, ResolveToBufferWithOffset) {
|
TEST_P(TimestampQueryTests, ResolveToBufferWithOffset) {
|
||||||
// TODO(hao.x.li@intel.com): Fails on Intel Windows Vulkan due to a driver issue that
|
// TODO(dawn:1489): Fails on Intel Windows Vulkan due to a driver issue that
|
||||||
// vkCmdFillBuffer and vkCmdCopyQueryPoolResults are not executed in order, skip it util
|
// vkCmdFillBuffer and vkCmdCopyQueryPoolResults are not executed in order, skip it until
|
||||||
// the issue is fixed.
|
// the issue is fixed.
|
||||||
DAWN_SUPPRESS_TEST_IF(IsWindows() && IsVulkan() && IsIntel());
|
DAWN_SUPPRESS_TEST_IF(IsWindows() && IsVulkan() && IsIntel());
|
||||||
|
|
||||||
@ -818,8 +1057,8 @@ TEST_P(TimestampQueryTests, ResolveToBufferWithOffset) {
|
|||||||
// Test resolving a query set twice into the same destination buffer with potentially overlapping
|
// Test resolving a query set twice into the same destination buffer with potentially overlapping
|
||||||
// ranges
|
// ranges
|
||||||
TEST_P(TimestampQueryTests, ResolveTwiceToSameBuffer) {
|
TEST_P(TimestampQueryTests, ResolveTwiceToSameBuffer) {
|
||||||
// TODO(hao.x.li@intel.com): Fails on Intel Windows Vulkan due to a driver issue that
|
// TODO(dawn:1489): Fails on Intel Windows Vulkan due to a driver issue that
|
||||||
// vkCmdFillBuffer and vkCmdCopyQueryPoolResults are not executed in order, skip it util
|
// vkCmdFillBuffer and vkCmdCopyQueryPoolResults are not executed in order, skip it until
|
||||||
// the issue is fixed.
|
// the issue is fixed.
|
||||||
DAWN_SUPPRESS_TEST_IF(IsWindows() && IsVulkan() && IsIntel());
|
DAWN_SUPPRESS_TEST_IF(IsWindows() && IsVulkan() && IsIntel());
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user