Factor EncodingContext out of CommandEncoderBase.
This patch factors the CommandAllocator, CommandIterator, and error handling out of CommandEncoderBase so it can later be used by the RenderBundleEncoder. Bug: dawn:154 Change-Id: Ia4f8c3ce7f432f0887b619bd8090aa9bec7330fc Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/9181 Reviewed-by: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Kai Ninomiya <kainino@chromium.org> Commit-Queue: Austin Eng <enga@chromium.org>
This commit is contained in:
parent
8944f0205b
commit
fde94905fe
2
BUILD.gn
2
BUILD.gn
|
@ -130,6 +130,8 @@ source_set("libdawn_native_sources") {
|
|||
"src/dawn_native/Device.h",
|
||||
"src/dawn_native/DynamicUploader.cpp",
|
||||
"src/dawn_native/DynamicUploader.h",
|
||||
"src/dawn_native/EncodingContext.cpp",
|
||||
"src/dawn_native/EncodingContext.h",
|
||||
"src/dawn_native/Error.cpp",
|
||||
"src/dawn_native/Error.h",
|
||||
"src/dawn_native/ErrorData.cpp",
|
||||
|
|
|
@ -621,28 +621,8 @@ namespace dawn_native {
|
|||
|
||||
} // namespace
|
||||
|
||||
enum class CommandEncoderBase::EncodingState : uint8_t {
|
||||
TopLevel,
|
||||
ComputePass,
|
||||
RenderPass,
|
||||
Finished
|
||||
};
|
||||
|
||||
CommandEncoderBase::CommandEncoderBase(DeviceBase* device, const CommandEncoderDescriptor*)
|
||||
: ObjectBase(device), mEncodingState(EncodingState::TopLevel) {
|
||||
}
|
||||
|
||||
CommandEncoderBase::~CommandEncoderBase() {
|
||||
if (!mWereCommandsAcquired) {
|
||||
MoveToIterator();
|
||||
FreeCommands(&mIterator);
|
||||
}
|
||||
}
|
||||
|
||||
CommandIterator CommandEncoderBase::AcquireCommands() {
|
||||
ASSERT(!mWereCommandsAcquired);
|
||||
mWereCommandsAcquired = true;
|
||||
return std::move(mIterator);
|
||||
: ObjectBase(device), mEncodingContext(device, this) {
|
||||
}
|
||||
|
||||
CommandBufferResourceUsage CommandEncoderBase::AcquireResourceUsages() {
|
||||
|
@ -651,11 +631,8 @@ namespace dawn_native {
|
|||
return std::move(mResourceUsages);
|
||||
}
|
||||
|
||||
void CommandEncoderBase::MoveToIterator() {
|
||||
if (!mWasMovedToIterator) {
|
||||
mIterator = std::move(mAllocator);
|
||||
mWasMovedToIterator = true;
|
||||
}
|
||||
CommandIterator CommandEncoderBase::AcquireCommands() {
|
||||
return mEncodingContext.AcquireCommands();
|
||||
}
|
||||
|
||||
// Implementation of the API's command recording methods
|
||||
|
@ -663,41 +640,43 @@ namespace dawn_native {
|
|||
ComputePassEncoderBase* CommandEncoderBase::BeginComputePass(
|
||||
const ComputePassDescriptor* descriptor) {
|
||||
DeviceBase* device = GetDevice();
|
||||
if (ConsumedError(ValidateCanRecordTopLevelCommands())) {
|
||||
return ComputePassEncoderBase::MakeError(device, this);
|
||||
|
||||
bool success =
|
||||
mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||
DAWN_TRY(ValidateComputePassDescriptor(device, descriptor));
|
||||
|
||||
allocator->Allocate<BeginComputePassCmd>(Command::BeginComputePass);
|
||||
|
||||
return {};
|
||||
});
|
||||
|
||||
if (success) {
|
||||
ComputePassEncoderBase* passEncoder =
|
||||
new ComputePassEncoderBase(device, this, &mEncodingContext);
|
||||
mEncodingContext.EnterPass(passEncoder);
|
||||
return passEncoder;
|
||||
}
|
||||
|
||||
if (ConsumedError(ValidateComputePassDescriptor(device, descriptor))) {
|
||||
return ComputePassEncoderBase::MakeError(device, this);
|
||||
}
|
||||
|
||||
mAllocator.Allocate<BeginComputePassCmd>(Command::BeginComputePass);
|
||||
|
||||
mEncodingState = EncodingState::ComputePass;
|
||||
return new ComputePassEncoderBase(device, this, &mAllocator);
|
||||
return ComputePassEncoderBase::MakeError(device, this, &mEncodingContext);
|
||||
}
|
||||
|
||||
RenderPassEncoderBase* CommandEncoderBase::BeginRenderPass(
|
||||
const RenderPassDescriptor* descriptor) {
|
||||
DeviceBase* device = GetDevice();
|
||||
|
||||
if (ConsumedError(ValidateCanRecordTopLevelCommands())) {
|
||||
return RenderPassEncoderBase::MakeError(device, this);
|
||||
}
|
||||
|
||||
bool success =
|
||||
mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
uint32_t sampleCount = 0;
|
||||
if (ConsumedError(
|
||||
ValidateRenderPassDescriptor(device, descriptor, &width, &height, &sampleCount))) {
|
||||
return RenderPassEncoderBase::MakeError(device, this);
|
||||
}
|
||||
|
||||
DAWN_TRY(ValidateRenderPassDescriptor(device, descriptor, &width, &height,
|
||||
&sampleCount));
|
||||
|
||||
ASSERT(width > 0 && height > 0 && sampleCount > 0);
|
||||
|
||||
mEncodingState = EncodingState::RenderPass;
|
||||
|
||||
BeginRenderPassCmd* cmd = mAllocator.Allocate<BeginRenderPassCmd>(Command::BeginRenderPass);
|
||||
BeginRenderPassCmd* cmd =
|
||||
allocator->Allocate<BeginRenderPassCmd>(Command::BeginRenderPass);
|
||||
|
||||
for (uint32_t i = 0; i < descriptor->colorAttachmentCount; ++i) {
|
||||
if (descriptor->colorAttachments[i] != nullptr) {
|
||||
|
@ -707,15 +686,18 @@ namespace dawn_native {
|
|||
descriptor->colorAttachments[i]->resolveTarget;
|
||||
cmd->colorAttachments[i].loadOp = descriptor->colorAttachments[i]->loadOp;
|
||||
cmd->colorAttachments[i].storeOp = descriptor->colorAttachments[i]->storeOp;
|
||||
cmd->colorAttachments[i].clearColor = descriptor->colorAttachments[i]->clearColor;
|
||||
cmd->colorAttachments[i].clearColor =
|
||||
descriptor->colorAttachments[i]->clearColor;
|
||||
}
|
||||
}
|
||||
|
||||
cmd->hasDepthStencilAttachment = descriptor->depthStencilAttachment != nullptr;
|
||||
if (cmd->hasDepthStencilAttachment) {
|
||||
cmd->hasDepthStencilAttachment = true;
|
||||
cmd->depthStencilAttachment.view = descriptor->depthStencilAttachment->attachment;
|
||||
cmd->depthStencilAttachment.clearDepth = descriptor->depthStencilAttachment->clearDepth;
|
||||
cmd->depthStencilAttachment.view =
|
||||
descriptor->depthStencilAttachment->attachment;
|
||||
cmd->depthStencilAttachment.clearDepth =
|
||||
descriptor->depthStencilAttachment->clearDepth;
|
||||
cmd->depthStencilAttachment.clearStencil =
|
||||
descriptor->depthStencilAttachment->clearStencil;
|
||||
cmd->depthStencilAttachment.depthLoadOp =
|
||||
|
@ -732,7 +714,17 @@ namespace dawn_native {
|
|||
cmd->height = height;
|
||||
cmd->sampleCount = sampleCount;
|
||||
|
||||
return new RenderPassEncoderBase(device, this, &mAllocator);
|
||||
return {};
|
||||
});
|
||||
|
||||
if (success) {
|
||||
RenderPassEncoderBase* passEncoder =
|
||||
new RenderPassEncoderBase(device, this, &mEncodingContext);
|
||||
mEncodingContext.EnterPass(passEncoder);
|
||||
return passEncoder;
|
||||
}
|
||||
|
||||
return RenderPassEncoderBase::MakeError(device, this, &mEncodingContext);
|
||||
}
|
||||
|
||||
void CommandEncoderBase::CopyBufferToBuffer(BufferBase* source,
|
||||
|
@ -740,44 +732,31 @@ namespace dawn_native {
|
|||
BufferBase* destination,
|
||||
uint64_t destinationOffset,
|
||||
uint64_t size) {
|
||||
if (ConsumedError(ValidateCanRecordTopLevelCommands())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ConsumedError(GetDevice()->ValidateObject(source))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ConsumedError(GetDevice()->ValidateObject(destination))) {
|
||||
return;
|
||||
}
|
||||
mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||
DAWN_TRY(GetDevice()->ValidateObject(source));
|
||||
DAWN_TRY(GetDevice()->ValidateObject(destination));
|
||||
|
||||
CopyBufferToBufferCmd* copy =
|
||||
mAllocator.Allocate<CopyBufferToBufferCmd>(Command::CopyBufferToBuffer);
|
||||
allocator->Allocate<CopyBufferToBufferCmd>(Command::CopyBufferToBuffer);
|
||||
copy->source = source;
|
||||
copy->sourceOffset = sourceOffset;
|
||||
copy->destination = destination;
|
||||
copy->destinationOffset = destinationOffset;
|
||||
copy->size = size;
|
||||
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
void CommandEncoderBase::CopyBufferToTexture(const BufferCopyView* source,
|
||||
const TextureCopyView* destination,
|
||||
const Extent3D* copySize) {
|
||||
if (ConsumedError(ValidateCanRecordTopLevelCommands())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ConsumedError(GetDevice()->ValidateObject(source->buffer))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ConsumedError(GetDevice()->ValidateObject(destination->texture))) {
|
||||
return;
|
||||
}
|
||||
mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||
DAWN_TRY(GetDevice()->ValidateObject(source->buffer));
|
||||
DAWN_TRY(GetDevice()->ValidateObject(destination->texture));
|
||||
|
||||
CopyBufferToTextureCmd* copy =
|
||||
mAllocator.Allocate<CopyBufferToTextureCmd>(Command::CopyBufferToTexture);
|
||||
allocator->Allocate<CopyBufferToTextureCmd>(Command::CopyBufferToTexture);
|
||||
copy->source.buffer = source->buffer;
|
||||
copy->source.offset = source->offset;
|
||||
copy->destination.texture = destination->texture;
|
||||
|
@ -796,25 +775,20 @@ namespace dawn_native {
|
|||
} else {
|
||||
copy->source.imageHeight = source->imageHeight;
|
||||
}
|
||||
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
void CommandEncoderBase::CopyTextureToBuffer(const TextureCopyView* source,
|
||||
const BufferCopyView* destination,
|
||||
const Extent3D* copySize) {
|
||||
if (ConsumedError(ValidateCanRecordTopLevelCommands())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ConsumedError(GetDevice()->ValidateObject(source->texture))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ConsumedError(GetDevice()->ValidateObject(destination->buffer))) {
|
||||
return;
|
||||
}
|
||||
mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||
DAWN_TRY(GetDevice()->ValidateObject(source->texture));
|
||||
DAWN_TRY(GetDevice()->ValidateObject(destination->buffer));
|
||||
|
||||
CopyTextureToBufferCmd* copy =
|
||||
mAllocator.Allocate<CopyTextureToBufferCmd>(Command::CopyTextureToBuffer);
|
||||
allocator->Allocate<CopyTextureToBufferCmd>(Command::CopyTextureToBuffer);
|
||||
copy->source.texture = source->texture;
|
||||
copy->source.origin = source->origin;
|
||||
copy->copySize = *copySize;
|
||||
|
@ -833,25 +807,20 @@ namespace dawn_native {
|
|||
} else {
|
||||
copy->destination.imageHeight = destination->imageHeight;
|
||||
}
|
||||
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
void CommandEncoderBase::CopyTextureToTexture(const TextureCopyView* source,
|
||||
const TextureCopyView* destination,
|
||||
const Extent3D* copySize) {
|
||||
if (ConsumedError(ValidateCanRecordTopLevelCommands())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ConsumedError(GetDevice()->ValidateObject(source->texture))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ConsumedError(GetDevice()->ValidateObject(destination->texture))) {
|
||||
return;
|
||||
}
|
||||
mEncodingContext.TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||
DAWN_TRY(GetDevice()->ValidateObject(source->texture));
|
||||
DAWN_TRY(GetDevice()->ValidateObject(destination->texture));
|
||||
|
||||
CopyTextureToTextureCmd* copy =
|
||||
mAllocator.Allocate<CopyTextureToTextureCmd>(Command::CopyTextureToTexture);
|
||||
allocator->Allocate<CopyTextureToTextureCmd>(Command::CopyTextureToTexture);
|
||||
copy->source.texture = source->texture;
|
||||
copy->source.origin = source->origin;
|
||||
copy->source.mipLevel = source->mipLevel;
|
||||
|
@ -861,87 +830,49 @@ namespace dawn_native {
|
|||
copy->destination.mipLevel = destination->mipLevel;
|
||||
copy->destination.arrayLayer = destination->arrayLayer;
|
||||
copy->copySize = *copySize;
|
||||
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
CommandBufferBase* CommandEncoderBase::Finish(const CommandBufferDescriptor* descriptor) {
|
||||
if (GetDevice()->ConsumedError(ValidateFinish(descriptor))) {
|
||||
// Even if finish validation fails, it is now invalid to call any encoding commands on
|
||||
// this object, so we set its state to finished.
|
||||
mEncodingState = EncodingState::Finished;
|
||||
return CommandBufferBase::MakeError(GetDevice());
|
||||
}
|
||||
ASSERT(!IsError());
|
||||
|
||||
mEncodingState = EncodingState::Finished;
|
||||
|
||||
MoveToIterator();
|
||||
return GetDevice()->CreateCommandBuffer(this, descriptor);
|
||||
}
|
||||
|
||||
// Implementation of functions to interact with sub-encoders
|
||||
|
||||
void CommandEncoderBase::HandleError(const char* message) {
|
||||
if (mEncodingState != EncodingState::Finished) {
|
||||
if (!mGotError) {
|
||||
mGotError = true;
|
||||
mErrorMessage = message;
|
||||
}
|
||||
} else {
|
||||
GetDevice()->HandleError(message);
|
||||
}
|
||||
}
|
||||
|
||||
void CommandEncoderBase::ConsumeError(ErrorData* error) {
|
||||
HandleError(error->GetMessage().c_str());
|
||||
delete error;
|
||||
}
|
||||
|
||||
void CommandEncoderBase::PassEnded() {
|
||||
// This function may still be called when the command encoder is finished, just do nothing.
|
||||
if (mEncodingState == EncodingState::Finished) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mEncodingState == EncodingState::ComputePass) {
|
||||
mAllocator.Allocate<EndComputePassCmd>(Command::EndComputePass);
|
||||
} else {
|
||||
ASSERT(mEncodingState == EncodingState::RenderPass);
|
||||
mAllocator.Allocate<EndRenderPassCmd>(Command::EndRenderPass);
|
||||
}
|
||||
mEncodingState = EncodingState::TopLevel;
|
||||
}
|
||||
|
||||
// Implementation of the command buffer validation that can be precomputed before submit
|
||||
|
||||
MaybeError CommandEncoderBase::ValidateFinish(const CommandBufferDescriptor*) {
|
||||
DAWN_TRY(GetDevice()->ValidateObject(this));
|
||||
|
||||
if (mGotError) {
|
||||
return DAWN_VALIDATION_ERROR(mErrorMessage);
|
||||
}
|
||||
// Even if Finish() validation fails, calling it will mutate the internal state of the
|
||||
// encoding context. Subsequent calls to encode commands will generate errors.
|
||||
DAWN_TRY(mEncodingContext.Finish());
|
||||
|
||||
if (mEncodingState != EncodingState::TopLevel) {
|
||||
return DAWN_VALIDATION_ERROR("Command buffer recording ended mid-pass");
|
||||
}
|
||||
|
||||
MoveToIterator();
|
||||
mIterator.Reset();
|
||||
CommandIterator* commands = mEncodingContext.GetIterator();
|
||||
commands->Reset();
|
||||
|
||||
Command type;
|
||||
while (mIterator.NextCommandId(&type)) {
|
||||
while (commands->NextCommandId(&type)) {
|
||||
switch (type) {
|
||||
case Command::BeginComputePass: {
|
||||
mIterator.NextCommand<BeginComputePassCmd>();
|
||||
DAWN_TRY(ValidateComputePass());
|
||||
commands->NextCommand<BeginComputePassCmd>();
|
||||
DAWN_TRY(ValidateComputePass(commands));
|
||||
} break;
|
||||
|
||||
case Command::BeginRenderPass: {
|
||||
BeginRenderPassCmd* cmd = mIterator.NextCommand<BeginRenderPassCmd>();
|
||||
DAWN_TRY(ValidateRenderPass(cmd));
|
||||
BeginRenderPassCmd* cmd = commands->NextCommand<BeginRenderPassCmd>();
|
||||
DAWN_TRY(ValidateRenderPass(commands, cmd));
|
||||
} break;
|
||||
|
||||
case Command::CopyBufferToBuffer: {
|
||||
CopyBufferToBufferCmd* copy = mIterator.NextCommand<CopyBufferToBufferCmd>();
|
||||
CopyBufferToBufferCmd* copy = commands->NextCommand<CopyBufferToBufferCmd>();
|
||||
|
||||
DAWN_TRY(
|
||||
ValidateCopySizeFitsInBuffer(copy->source, copy->sourceOffset, copy->size));
|
||||
|
@ -959,7 +890,7 @@ namespace dawn_native {
|
|||
} break;
|
||||
|
||||
case Command::CopyBufferToTexture: {
|
||||
CopyBufferToTextureCmd* copy = mIterator.NextCommand<CopyBufferToTextureCmd>();
|
||||
CopyBufferToTextureCmd* copy = commands->NextCommand<CopyBufferToTextureCmd>();
|
||||
|
||||
DAWN_TRY(
|
||||
ValidateTextureSampleCountInCopyCommands(copy->destination.texture.Get()));
|
||||
|
@ -994,7 +925,7 @@ namespace dawn_native {
|
|||
} break;
|
||||
|
||||
case Command::CopyTextureToBuffer: {
|
||||
CopyTextureToBufferCmd* copy = mIterator.NextCommand<CopyTextureToBufferCmd>();
|
||||
CopyTextureToBufferCmd* copy = commands->NextCommand<CopyTextureToBufferCmd>();
|
||||
|
||||
DAWN_TRY(ValidateTextureSampleCountInCopyCommands(copy->source.texture.Get()));
|
||||
|
||||
|
@ -1030,7 +961,7 @@ namespace dawn_native {
|
|||
|
||||
case Command::CopyTextureToTexture: {
|
||||
CopyTextureToTextureCmd* copy =
|
||||
mIterator.NextCommand<CopyTextureToTextureCmd>();
|
||||
commands->NextCommand<CopyTextureToTextureCmd>();
|
||||
|
||||
DAWN_TRY(ValidateTextureToTextureCopyRestrictions(
|
||||
copy->source, copy->destination, copy->copySize));
|
||||
|
@ -1064,15 +995,15 @@ namespace dawn_native {
|
|||
return {};
|
||||
}
|
||||
|
||||
MaybeError CommandEncoderBase::ValidateComputePass() {
|
||||
MaybeError CommandEncoderBase::ValidateComputePass(CommandIterator* commands) {
|
||||
PassResourceUsageTracker usageTracker;
|
||||
CommandBufferStateTracker persistentState;
|
||||
|
||||
Command type;
|
||||
while (mIterator.NextCommandId(&type)) {
|
||||
while (commands->NextCommandId(&type)) {
|
||||
switch (type) {
|
||||
case Command::EndComputePass: {
|
||||
mIterator.NextCommand<EndComputePassCmd>();
|
||||
commands->NextCommand<EndComputePassCmd>();
|
||||
|
||||
DAWN_TRY(ValidateDebugGroups(mDebugGroupStackSize));
|
||||
|
||||
|
@ -1082,43 +1013,43 @@ namespace dawn_native {
|
|||
} break;
|
||||
|
||||
case Command::Dispatch: {
|
||||
mIterator.NextCommand<DispatchCmd>();
|
||||
commands->NextCommand<DispatchCmd>();
|
||||
DAWN_TRY(persistentState.ValidateCanDispatch());
|
||||
} break;
|
||||
|
||||
case Command::DispatchIndirect: {
|
||||
DispatchIndirectCmd* cmd = mIterator.NextCommand<DispatchIndirectCmd>();
|
||||
DispatchIndirectCmd* cmd = commands->NextCommand<DispatchIndirectCmd>();
|
||||
DAWN_TRY(persistentState.ValidateCanDispatch());
|
||||
usageTracker.BufferUsedAs(cmd->indirectBuffer.Get(),
|
||||
dawn::BufferUsageBit::Indirect);
|
||||
} break;
|
||||
|
||||
case Command::InsertDebugMarker: {
|
||||
InsertDebugMarkerCmd* cmd = mIterator.NextCommand<InsertDebugMarkerCmd>();
|
||||
mIterator.NextData<char>(cmd->length + 1);
|
||||
InsertDebugMarkerCmd* cmd = commands->NextCommand<InsertDebugMarkerCmd>();
|
||||
commands->NextData<char>(cmd->length + 1);
|
||||
} break;
|
||||
|
||||
case Command::PopDebugGroup: {
|
||||
mIterator.NextCommand<PopDebugGroupCmd>();
|
||||
commands->NextCommand<PopDebugGroupCmd>();
|
||||
DAWN_TRY(PopDebugMarkerStack(&mDebugGroupStackSize));
|
||||
} break;
|
||||
|
||||
case Command::PushDebugGroup: {
|
||||
PushDebugGroupCmd* cmd = mIterator.NextCommand<PushDebugGroupCmd>();
|
||||
mIterator.NextData<char>(cmd->length + 1);
|
||||
PushDebugGroupCmd* cmd = commands->NextCommand<PushDebugGroupCmd>();
|
||||
commands->NextData<char>(cmd->length + 1);
|
||||
DAWN_TRY(PushDebugMarkerStack(&mDebugGroupStackSize));
|
||||
} break;
|
||||
|
||||
case Command::SetComputePipeline: {
|
||||
SetComputePipelineCmd* cmd = mIterator.NextCommand<SetComputePipelineCmd>();
|
||||
SetComputePipelineCmd* cmd = commands->NextCommand<SetComputePipelineCmd>();
|
||||
ComputePipelineBase* pipeline = cmd->pipeline.Get();
|
||||
persistentState.SetComputePipeline(pipeline);
|
||||
} break;
|
||||
|
||||
case Command::SetBindGroup: {
|
||||
SetBindGroupCmd* cmd = mIterator.NextCommand<SetBindGroupCmd>();
|
||||
SetBindGroupCmd* cmd = commands->NextCommand<SetBindGroupCmd>();
|
||||
if (cmd->dynamicOffsetCount > 0) {
|
||||
mIterator.NextData<uint64_t>(cmd->dynamicOffsetCount);
|
||||
commands->NextData<uint64_t>(cmd->dynamicOffsetCount);
|
||||
}
|
||||
|
||||
TrackBindGroupResourceUsage(cmd->group.Get(), &usageTracker);
|
||||
|
@ -1134,7 +1065,8 @@ namespace dawn_native {
|
|||
return DAWN_VALIDATION_ERROR("Unfinished compute pass");
|
||||
}
|
||||
|
||||
MaybeError CommandEncoderBase::ValidateRenderPass(BeginRenderPassCmd* renderPass) {
|
||||
MaybeError CommandEncoderBase::ValidateRenderPass(CommandIterator* commands,
|
||||
BeginRenderPassCmd* renderPass) {
|
||||
PassResourceUsageTracker usageTracker;
|
||||
CommandBufferStateTracker persistentState;
|
||||
|
||||
|
@ -1157,10 +1089,10 @@ namespace dawn_native {
|
|||
}
|
||||
|
||||
Command type;
|
||||
while (mIterator.NextCommandId(&type)) {
|
||||
while (commands->NextCommandId(&type)) {
|
||||
switch (type) {
|
||||
case Command::EndRenderPass: {
|
||||
mIterator.NextCommand<EndRenderPassCmd>();
|
||||
commands->NextCommand<EndRenderPassCmd>();
|
||||
|
||||
DAWN_TRY(ValidateDebugGroups(mDebugGroupStackSize));
|
||||
|
||||
|
@ -1170,47 +1102,47 @@ namespace dawn_native {
|
|||
} break;
|
||||
|
||||
case Command::Draw: {
|
||||
mIterator.NextCommand<DrawCmd>();
|
||||
commands->NextCommand<DrawCmd>();
|
||||
DAWN_TRY(persistentState.ValidateCanDraw());
|
||||
} break;
|
||||
|
||||
case Command::DrawIndexed: {
|
||||
mIterator.NextCommand<DrawIndexedCmd>();
|
||||
commands->NextCommand<DrawIndexedCmd>();
|
||||
DAWN_TRY(persistentState.ValidateCanDrawIndexed());
|
||||
} break;
|
||||
|
||||
case Command::DrawIndirect: {
|
||||
DrawIndirectCmd* cmd = mIterator.NextCommand<DrawIndirectCmd>();
|
||||
DrawIndirectCmd* cmd = commands->NextCommand<DrawIndirectCmd>();
|
||||
DAWN_TRY(persistentState.ValidateCanDraw());
|
||||
usageTracker.BufferUsedAs(cmd->indirectBuffer.Get(),
|
||||
dawn::BufferUsageBit::Indirect);
|
||||
} break;
|
||||
|
||||
case Command::DrawIndexedIndirect: {
|
||||
DrawIndexedIndirectCmd* cmd = mIterator.NextCommand<DrawIndexedIndirectCmd>();
|
||||
DrawIndexedIndirectCmd* cmd = commands->NextCommand<DrawIndexedIndirectCmd>();
|
||||
DAWN_TRY(persistentState.ValidateCanDrawIndexed());
|
||||
usageTracker.BufferUsedAs(cmd->indirectBuffer.Get(),
|
||||
dawn::BufferUsageBit::Indirect);
|
||||
} break;
|
||||
|
||||
case Command::InsertDebugMarker: {
|
||||
InsertDebugMarkerCmd* cmd = mIterator.NextCommand<InsertDebugMarkerCmd>();
|
||||
mIterator.NextData<char>(cmd->length + 1);
|
||||
InsertDebugMarkerCmd* cmd = commands->NextCommand<InsertDebugMarkerCmd>();
|
||||
commands->NextData<char>(cmd->length + 1);
|
||||
} break;
|
||||
|
||||
case Command::PopDebugGroup: {
|
||||
mIterator.NextCommand<PopDebugGroupCmd>();
|
||||
commands->NextCommand<PopDebugGroupCmd>();
|
||||
DAWN_TRY(PopDebugMarkerStack(&mDebugGroupStackSize));
|
||||
} break;
|
||||
|
||||
case Command::PushDebugGroup: {
|
||||
PushDebugGroupCmd* cmd = mIterator.NextCommand<PushDebugGroupCmd>();
|
||||
mIterator.NextData<char>(cmd->length + 1);
|
||||
PushDebugGroupCmd* cmd = commands->NextCommand<PushDebugGroupCmd>();
|
||||
commands->NextData<char>(cmd->length + 1);
|
||||
DAWN_TRY(PushDebugMarkerStack(&mDebugGroupStackSize));
|
||||
} break;
|
||||
|
||||
case Command::SetRenderPipeline: {
|
||||
SetRenderPipelineCmd* cmd = mIterator.NextCommand<SetRenderPipelineCmd>();
|
||||
SetRenderPipelineCmd* cmd = commands->NextCommand<SetRenderPipelineCmd>();
|
||||
RenderPipelineBase* pipeline = cmd->pipeline.Get();
|
||||
|
||||
DAWN_TRY(pipeline->ValidateCompatibleWith(renderPass));
|
||||
|
@ -1218,25 +1150,25 @@ namespace dawn_native {
|
|||
} break;
|
||||
|
||||
case Command::SetStencilReference: {
|
||||
mIterator.NextCommand<SetStencilReferenceCmd>();
|
||||
commands->NextCommand<SetStencilReferenceCmd>();
|
||||
} break;
|
||||
|
||||
case Command::SetBlendColor: {
|
||||
mIterator.NextCommand<SetBlendColorCmd>();
|
||||
commands->NextCommand<SetBlendColorCmd>();
|
||||
} break;
|
||||
|
||||
case Command::SetViewport: {
|
||||
mIterator.NextCommand<SetViewportCmd>();
|
||||
commands->NextCommand<SetViewportCmd>();
|
||||
} break;
|
||||
|
||||
case Command::SetScissorRect: {
|
||||
mIterator.NextCommand<SetScissorRectCmd>();
|
||||
commands->NextCommand<SetScissorRectCmd>();
|
||||
} break;
|
||||
|
||||
case Command::SetBindGroup: {
|
||||
SetBindGroupCmd* cmd = mIterator.NextCommand<SetBindGroupCmd>();
|
||||
SetBindGroupCmd* cmd = commands->NextCommand<SetBindGroupCmd>();
|
||||
if (cmd->dynamicOffsetCount > 0) {
|
||||
mIterator.NextData<uint64_t>(cmd->dynamicOffsetCount);
|
||||
commands->NextData<uint64_t>(cmd->dynamicOffsetCount);
|
||||
}
|
||||
|
||||
TrackBindGroupResourceUsage(cmd->group.Get(), &usageTracker);
|
||||
|
@ -1244,16 +1176,16 @@ namespace dawn_native {
|
|||
} break;
|
||||
|
||||
case Command::SetIndexBuffer: {
|
||||
SetIndexBufferCmd* cmd = mIterator.NextCommand<SetIndexBufferCmd>();
|
||||
SetIndexBufferCmd* cmd = commands->NextCommand<SetIndexBufferCmd>();
|
||||
|
||||
usageTracker.BufferUsedAs(cmd->buffer.Get(), dawn::BufferUsageBit::Index);
|
||||
persistentState.SetIndexBuffer();
|
||||
} break;
|
||||
|
||||
case Command::SetVertexBuffers: {
|
||||
SetVertexBuffersCmd* cmd = mIterator.NextCommand<SetVertexBuffersCmd>();
|
||||
auto buffers = mIterator.NextData<Ref<BufferBase>>(cmd->count);
|
||||
mIterator.NextData<uint64_t>(cmd->count);
|
||||
SetVertexBuffersCmd* cmd = commands->NextCommand<SetVertexBuffersCmd>();
|
||||
auto buffers = commands->NextData<Ref<BufferBase>>(cmd->count);
|
||||
commands->NextData<uint64_t>(cmd->count);
|
||||
|
||||
for (uint32_t i = 0; i < cmd->count; ++i) {
|
||||
usageTracker.BufferUsedAs(buffers[i].Get(), dawn::BufferUsageBit::Vertex);
|
||||
|
@ -1270,11 +1202,4 @@ namespace dawn_native {
|
|||
return DAWN_VALIDATION_ERROR("Unfinished render pass");
|
||||
}
|
||||
|
||||
MaybeError CommandEncoderBase::ValidateCanRecordTopLevelCommands() const {
|
||||
if (mEncodingState != EncodingState::TopLevel) {
|
||||
return DAWN_VALIDATION_ERROR("Command cannot be recorded inside a pass");
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace dawn_native
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
#include "dawn_native/dawn_platform.h"
|
||||
|
||||
#include "dawn_native/CommandAllocator.h"
|
||||
#include "dawn_native/EncodingContext.h"
|
||||
#include "dawn_native/Error.h"
|
||||
#include "dawn_native/ObjectBase.h"
|
||||
#include "dawn_native/PassResourceUsage.h"
|
||||
|
@ -31,7 +31,6 @@ namespace dawn_native {
|
|||
class CommandEncoderBase : public ObjectBase {
|
||||
public:
|
||||
CommandEncoderBase(DeviceBase* device, const CommandEncoderDescriptor* descriptor);
|
||||
~CommandEncoderBase();
|
||||
|
||||
CommandIterator AcquireCommands();
|
||||
CommandBufferResourceUsage AcquireResourceUsages();
|
||||
|
@ -55,41 +54,17 @@ namespace dawn_native {
|
|||
const Extent3D* copySize);
|
||||
CommandBufferBase* Finish(const CommandBufferDescriptor* descriptor);
|
||||
|
||||
// Functions to interact with the encoders
|
||||
void HandleError(const char* message);
|
||||
void ConsumeError(ErrorData* error);
|
||||
bool ConsumedError(MaybeError maybeError) {
|
||||
if (DAWN_UNLIKELY(maybeError.IsError())) {
|
||||
ConsumeError(maybeError.AcquireError());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void PassEnded();
|
||||
|
||||
private:
|
||||
MaybeError ValidateFinish(const CommandBufferDescriptor* descriptor);
|
||||
MaybeError ValidateComputePass();
|
||||
MaybeError ValidateRenderPass(BeginRenderPassCmd* renderPass);
|
||||
MaybeError ValidateCanRecordTopLevelCommands() const;
|
||||
MaybeError ValidateComputePass(CommandIterator* commands);
|
||||
MaybeError ValidateRenderPass(CommandIterator* commands, BeginRenderPassCmd* renderPass);
|
||||
|
||||
enum class EncodingState : uint8_t;
|
||||
EncodingState mEncodingState;
|
||||
|
||||
void MoveToIterator();
|
||||
CommandAllocator mAllocator;
|
||||
CommandIterator mIterator;
|
||||
bool mWasMovedToIterator = false;
|
||||
bool mWereCommandsAcquired = false;
|
||||
EncodingContext mEncodingContext;
|
||||
|
||||
bool mWereResourceUsagesAcquired = false;
|
||||
CommandBufferResourceUsage mResourceUsages;
|
||||
|
||||
unsigned int mDebugGroupStackSize = 0;
|
||||
|
||||
bool mGotError = false;
|
||||
std::string mErrorMessage;
|
||||
};
|
||||
|
||||
} // namespace dawn_native
|
||||
|
|
|
@ -23,70 +23,76 @@
|
|||
namespace dawn_native {
|
||||
|
||||
ComputePassEncoderBase::ComputePassEncoderBase(DeviceBase* device,
|
||||
CommandEncoderBase* topLevelEncoder,
|
||||
CommandAllocator* allocator)
|
||||
: ProgrammablePassEncoder(device, topLevelEncoder, allocator) {
|
||||
CommandEncoderBase* commandEncoder,
|
||||
EncodingContext* encodingContext)
|
||||
: ProgrammablePassEncoder(device, encodingContext), mCommandEncoder(commandEncoder) {
|
||||
}
|
||||
|
||||
ComputePassEncoderBase::ComputePassEncoderBase(DeviceBase* device,
|
||||
CommandEncoderBase* topLevelEncoder,
|
||||
CommandEncoderBase* commandEncoder,
|
||||
EncodingContext* encodingContext,
|
||||
ErrorTag errorTag)
|
||||
: ProgrammablePassEncoder(device, topLevelEncoder, errorTag) {
|
||||
: ProgrammablePassEncoder(device, encodingContext, errorTag),
|
||||
mCommandEncoder(commandEncoder) {
|
||||
}
|
||||
|
||||
ComputePassEncoderBase* ComputePassEncoderBase::MakeError(DeviceBase* device,
|
||||
CommandEncoderBase* topLevelEncoder) {
|
||||
return new ComputePassEncoderBase(device, topLevelEncoder, ObjectBase::kError);
|
||||
CommandEncoderBase* commandEncoder,
|
||||
EncodingContext* encodingContext) {
|
||||
return new ComputePassEncoderBase(device, commandEncoder, encodingContext,
|
||||
ObjectBase::kError);
|
||||
}
|
||||
|
||||
void ComputePassEncoderBase::EndPass() {
|
||||
if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) {
|
||||
return;
|
||||
}
|
||||
if (mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||
allocator->Allocate<EndComputePassCmd>(Command::EndComputePass);
|
||||
|
||||
mTopLevelEncoder->PassEnded();
|
||||
mAllocator = nullptr;
|
||||
return {};
|
||||
})) {
|
||||
mEncodingContext->ExitPass(this);
|
||||
}
|
||||
}
|
||||
|
||||
void ComputePassEncoderBase::Dispatch(uint32_t x, uint32_t y, uint32_t z) {
|
||||
if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) {
|
||||
return;
|
||||
}
|
||||
|
||||
DispatchCmd* dispatch = mAllocator->Allocate<DispatchCmd>(Command::Dispatch);
|
||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||
DispatchCmd* dispatch = allocator->Allocate<DispatchCmd>(Command::Dispatch);
|
||||
dispatch->x = x;
|
||||
dispatch->y = y;
|
||||
dispatch->z = z;
|
||||
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
void ComputePassEncoderBase::DispatchIndirect(BufferBase* indirectBuffer,
|
||||
uint64_t indirectOffset) {
|
||||
if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands()) ||
|
||||
mTopLevelEncoder->ConsumedError(GetDevice()->ValidateObject(indirectBuffer))) {
|
||||
return;
|
||||
}
|
||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||
DAWN_TRY(GetDevice()->ValidateObject(indirectBuffer));
|
||||
|
||||
if (indirectOffset >= indirectBuffer->GetSize() ||
|
||||
indirectOffset + kDispatchIndirectSize > indirectBuffer->GetSize()) {
|
||||
mTopLevelEncoder->HandleError("Indirect offset out of bounds");
|
||||
return;
|
||||
return DAWN_VALIDATION_ERROR("Indirect offset out of bounds");
|
||||
}
|
||||
|
||||
DispatchIndirectCmd* dispatch =
|
||||
mAllocator->Allocate<DispatchIndirectCmd>(Command::DispatchIndirect);
|
||||
allocator->Allocate<DispatchIndirectCmd>(Command::DispatchIndirect);
|
||||
dispatch->indirectBuffer = indirectBuffer;
|
||||
dispatch->indirectOffset = indirectOffset;
|
||||
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
void ComputePassEncoderBase::SetPipeline(ComputePipelineBase* pipeline) {
|
||||
if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands()) ||
|
||||
mTopLevelEncoder->ConsumedError(GetDevice()->ValidateObject(pipeline))) {
|
||||
return;
|
||||
}
|
||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||
DAWN_TRY(GetDevice()->ValidateObject(pipeline));
|
||||
|
||||
SetComputePipelineCmd* cmd =
|
||||
mAllocator->Allocate<SetComputePipelineCmd>(Command::SetComputePipeline);
|
||||
allocator->Allocate<SetComputePipelineCmd>(Command::SetComputePipeline);
|
||||
cmd->pipeline = pipeline;
|
||||
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace dawn_native
|
||||
|
|
|
@ -27,11 +27,12 @@ namespace dawn_native {
|
|||
class ComputePassEncoderBase : public ProgrammablePassEncoder {
|
||||
public:
|
||||
ComputePassEncoderBase(DeviceBase* device,
|
||||
CommandEncoderBase* topLevelEncoder,
|
||||
CommandAllocator* allocator);
|
||||
CommandEncoderBase* commandEncoder,
|
||||
EncodingContext* encodingContext);
|
||||
|
||||
static ComputePassEncoderBase* MakeError(DeviceBase* device,
|
||||
CommandEncoderBase* topLevelEncoder);
|
||||
CommandEncoderBase* commandEncoder,
|
||||
EncodingContext* encodingContext);
|
||||
|
||||
void EndPass();
|
||||
|
||||
|
@ -41,8 +42,14 @@ namespace dawn_native {
|
|||
|
||||
protected:
|
||||
ComputePassEncoderBase(DeviceBase* device,
|
||||
CommandEncoderBase* topLevelEncoder,
|
||||
CommandEncoderBase* commandEncoder,
|
||||
EncodingContext* encodingContext,
|
||||
ErrorTag errorTag);
|
||||
|
||||
private:
|
||||
// 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.
|
||||
Ref<CommandEncoderBase> mCommandEncoder;
|
||||
};
|
||||
|
||||
} // namespace dawn_native
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
// Copyright 2019 The Dawn Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "dawn_native/EncodingContext.h"
|
||||
|
||||
#include "common/Assert.h"
|
||||
#include "dawn_native/Commands.h"
|
||||
#include "dawn_native/Device.h"
|
||||
#include "dawn_native/ErrorData.h"
|
||||
|
||||
namespace dawn_native {
|
||||
|
||||
EncodingContext::EncodingContext(DeviceBase* device, const ObjectBase* initialEncoder)
|
||||
: mDevice(device), mTopLevelEncoder(initialEncoder), mCurrentEncoder(initialEncoder) {
|
||||
}
|
||||
|
||||
EncodingContext::~EncodingContext() {
|
||||
if (!mWereCommandsAcquired) {
|
||||
FreeCommands(GetIterator());
|
||||
}
|
||||
}
|
||||
|
||||
CommandIterator EncodingContext::AcquireCommands() {
|
||||
ASSERT(!mWereCommandsAcquired);
|
||||
mWereCommandsAcquired = true;
|
||||
return std::move(mIterator);
|
||||
}
|
||||
|
||||
CommandIterator* EncodingContext::GetIterator() {
|
||||
if (!mWasMovedToIterator) {
|
||||
mIterator = std::move(mAllocator);
|
||||
mWasMovedToIterator = true;
|
||||
}
|
||||
return &mIterator;
|
||||
}
|
||||
|
||||
void EncodingContext::HandleError(const char* message) {
|
||||
if (!IsFinished()) {
|
||||
// If the encoding context is not finished, errors are deferred until
|
||||
// Finish() is called.
|
||||
if (!mGotError) {
|
||||
mGotError = true;
|
||||
mErrorMessage = message;
|
||||
}
|
||||
} else {
|
||||
mDevice->HandleError(message);
|
||||
}
|
||||
}
|
||||
|
||||
void EncodingContext::EnterPass(const ObjectBase* passEncoder) {
|
||||
// Assert we're at the top level.
|
||||
ASSERT(mCurrentEncoder == mTopLevelEncoder);
|
||||
ASSERT(passEncoder != nullptr);
|
||||
|
||||
mCurrentEncoder = passEncoder;
|
||||
}
|
||||
|
||||
void EncodingContext::ExitPass(const ObjectBase* passEncoder) {
|
||||
// Assert we're not at the top level.
|
||||
ASSERT(mCurrentEncoder != mTopLevelEncoder);
|
||||
// Assert the pass encoder is current.
|
||||
ASSERT(mCurrentEncoder == passEncoder);
|
||||
|
||||
mCurrentEncoder = mTopLevelEncoder;
|
||||
}
|
||||
|
||||
MaybeError EncodingContext::Finish() {
|
||||
const void* currentEncoder = mCurrentEncoder;
|
||||
const void* topLevelEncoder = mTopLevelEncoder;
|
||||
|
||||
// Even if finish validation fails, it is now invalid to call any encoding commands,
|
||||
// so we clear the encoders. Note: mTopLevelEncoder == nullptr is used as a flag for
|
||||
// if Finish() has been called.
|
||||
mCurrentEncoder = nullptr;
|
||||
mTopLevelEncoder = nullptr;
|
||||
|
||||
if (mGotError) {
|
||||
return DAWN_VALIDATION_ERROR(mErrorMessage);
|
||||
}
|
||||
if (currentEncoder != topLevelEncoder) {
|
||||
return DAWN_VALIDATION_ERROR("Command buffer recording ended mid-pass");
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool EncodingContext::IsFinished() const {
|
||||
return mTopLevelEncoder == nullptr;
|
||||
}
|
||||
|
||||
} // namespace dawn_native
|
|
@ -0,0 +1,101 @@
|
|||
// Copyright 2019 The Dawn Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef DAWNNATIVE_ENCODINGCONTEXT_H_
|
||||
#define DAWNNATIVE_ENCODINGCONTEXT_H_
|
||||
|
||||
#include "dawn_native/CommandAllocator.h"
|
||||
#include "dawn_native/Error.h"
|
||||
#include "dawn_native/ErrorData.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace dawn_native {
|
||||
|
||||
class ObjectBase;
|
||||
class DeviceBase;
|
||||
|
||||
// Base class for allocating/iterating commands.
|
||||
// It performs error tracking as well as encoding state for render/compute passes.
|
||||
class EncodingContext {
|
||||
public:
|
||||
EncodingContext(DeviceBase* device, const ObjectBase* initialEncoder);
|
||||
~EncodingContext();
|
||||
|
||||
CommandIterator AcquireCommands();
|
||||
CommandIterator* GetIterator();
|
||||
|
||||
// Functions to handle encoder errors
|
||||
void HandleError(const char* message);
|
||||
|
||||
inline void ConsumeError(ErrorData* error) {
|
||||
HandleError(error->GetMessage().c_str());
|
||||
delete error;
|
||||
}
|
||||
|
||||
inline bool ConsumedError(MaybeError maybeError) {
|
||||
if (DAWN_UNLIKELY(maybeError.IsError())) {
|
||||
ConsumeError(maybeError.AcquireError());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename EncodeFunction>
|
||||
inline bool TryEncode(const void* encoder, EncodeFunction&& encodeFunction) {
|
||||
if (DAWN_UNLIKELY(encoder != mCurrentEncoder)) {
|
||||
if (mCurrentEncoder != mTopLevelEncoder) {
|
||||
// The top level encoder was used when a pass encoder was current.
|
||||
HandleError("Command cannot be recorded inside a pass");
|
||||
} else {
|
||||
HandleError("Recording in an error or already ended pass encoder");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
ASSERT(!mWasMovedToIterator);
|
||||
return !ConsumedError(encodeFunction(&mAllocator));
|
||||
}
|
||||
|
||||
// Functions to set current encoder state
|
||||
void EnterPass(const ObjectBase* passEncoder);
|
||||
void ExitPass(const ObjectBase* passEncoder);
|
||||
MaybeError Finish();
|
||||
|
||||
private:
|
||||
bool IsFinished() const;
|
||||
|
||||
DeviceBase* mDevice;
|
||||
|
||||
// There can only be two levels of encoders. Top-level and render/compute pass.
|
||||
// The top level encoder is the encoder the EncodingContext is created with.
|
||||
// It doubles as flag to check if encoding has been Finished.
|
||||
const ObjectBase* mTopLevelEncoder;
|
||||
// The current encoder must be the same as the encoder provided to TryEncode,
|
||||
// otherwise an error is produced. It may be nullptr if the EncodingContext is an error.
|
||||
// The current encoder changes with Enter/ExitPass which should be called by
|
||||
// CommandEncoder::Begin/EndPass.
|
||||
const ObjectBase* mCurrentEncoder;
|
||||
|
||||
CommandAllocator mAllocator;
|
||||
CommandIterator mIterator;
|
||||
bool mWasMovedToIterator = false;
|
||||
bool mWereCommandsAcquired = false;
|
||||
|
||||
bool mGotError = false;
|
||||
std::string mErrorMessage;
|
||||
};
|
||||
|
||||
} // namespace dawn_native
|
||||
|
||||
#endif // DAWNNATIVE_ENCODINGCONTEXT_H_
|
|
@ -26,109 +26,98 @@
|
|||
namespace dawn_native {
|
||||
|
||||
ProgrammablePassEncoder::ProgrammablePassEncoder(DeviceBase* device,
|
||||
CommandEncoderBase* topLevelEncoder,
|
||||
CommandAllocator* allocator)
|
||||
: ObjectBase(device), mTopLevelEncoder(topLevelEncoder), mAllocator(allocator) {
|
||||
DAWN_ASSERT(allocator != nullptr);
|
||||
EncodingContext* encodingContext)
|
||||
: ObjectBase(device), mEncodingContext(encodingContext) {
|
||||
}
|
||||
|
||||
ProgrammablePassEncoder::ProgrammablePassEncoder(DeviceBase* device,
|
||||
CommandEncoderBase* topLevelEncoder,
|
||||
EncodingContext* encodingContext,
|
||||
ErrorTag errorTag)
|
||||
: ObjectBase(device, errorTag), mTopLevelEncoder(topLevelEncoder), mAllocator(nullptr) {
|
||||
: ObjectBase(device, errorTag), mEncodingContext(encodingContext) {
|
||||
}
|
||||
|
||||
void ProgrammablePassEncoder::InsertDebugMarker(const char* groupLabel) {
|
||||
if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) {
|
||||
return;
|
||||
}
|
||||
|
||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||
InsertDebugMarkerCmd* cmd =
|
||||
mAllocator->Allocate<InsertDebugMarkerCmd>(Command::InsertDebugMarker);
|
||||
allocator->Allocate<InsertDebugMarkerCmd>(Command::InsertDebugMarker);
|
||||
cmd->length = strlen(groupLabel);
|
||||
|
||||
char* label = mAllocator->AllocateData<char>(cmd->length + 1);
|
||||
char* label = allocator->AllocateData<char>(cmd->length + 1);
|
||||
memcpy(label, groupLabel, cmd->length + 1);
|
||||
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
void ProgrammablePassEncoder::PopDebugGroup() {
|
||||
if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) {
|
||||
return;
|
||||
}
|
||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||
allocator->Allocate<PopDebugGroupCmd>(Command::PopDebugGroup);
|
||||
|
||||
mAllocator->Allocate<PopDebugGroupCmd>(Command::PopDebugGroup);
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
void ProgrammablePassEncoder::PushDebugGroup(const char* groupLabel) {
|
||||
if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) {
|
||||
return;
|
||||
}
|
||||
|
||||
PushDebugGroupCmd* cmd = mAllocator->Allocate<PushDebugGroupCmd>(Command::PushDebugGroup);
|
||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||
PushDebugGroupCmd* cmd =
|
||||
allocator->Allocate<PushDebugGroupCmd>(Command::PushDebugGroup);
|
||||
cmd->length = strlen(groupLabel);
|
||||
|
||||
char* label = mAllocator->AllocateData<char>(cmd->length + 1);
|
||||
char* label = allocator->AllocateData<char>(cmd->length + 1);
|
||||
memcpy(label, groupLabel, cmd->length + 1);
|
||||
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
void ProgrammablePassEncoder::SetBindGroup(uint32_t groupIndex,
|
||||
BindGroupBase* group,
|
||||
uint32_t dynamicOffsetCount,
|
||||
const uint64_t* dynamicOffsets) {
|
||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||
const BindGroupLayoutBase* layout = group->GetLayout();
|
||||
|
||||
if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands()) ||
|
||||
mTopLevelEncoder->ConsumedError(GetDevice()->ValidateObject(group))) {
|
||||
return;
|
||||
}
|
||||
DAWN_TRY(GetDevice()->ValidateObject(group));
|
||||
|
||||
if (groupIndex >= kMaxBindGroups) {
|
||||
mTopLevelEncoder->HandleError("Setting bind group over the max");
|
||||
return;
|
||||
return DAWN_VALIDATION_ERROR("Setting bind group over the max");
|
||||
}
|
||||
|
||||
// Dynamic offsets count must match the number required by the layout perfectly.
|
||||
if (layout->GetDynamicBufferCount() != dynamicOffsetCount) {
|
||||
mTopLevelEncoder->HandleError("dynamicOffset count mismatch");
|
||||
return DAWN_VALIDATION_ERROR("dynamicOffset count mismatch");
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < dynamicOffsetCount; ++i) {
|
||||
if (dynamicOffsets[i] % kMinDynamicBufferOffsetAlignment != 0) {
|
||||
mTopLevelEncoder->HandleError("Dynamic Buffer Offset need to be aligned");
|
||||
return;
|
||||
return DAWN_VALIDATION_ERROR("Dynamic Buffer Offset need to be aligned");
|
||||
}
|
||||
|
||||
BufferBinding bufferBinding = group->GetBindingAsBufferBinding(i);
|
||||
|
||||
// During BindGroup creation, validation ensures binding offset + binding size <= buffer
|
||||
// size.
|
||||
// During BindGroup creation, validation ensures binding offset + binding size <=
|
||||
// buffer size.
|
||||
DAWN_ASSERT(bufferBinding.buffer->GetSize() >= bufferBinding.size);
|
||||
DAWN_ASSERT(bufferBinding.buffer->GetSize() - bufferBinding.size >=
|
||||
bufferBinding.offset);
|
||||
|
||||
if (dynamicOffsets[i] >
|
||||
bufferBinding.buffer->GetSize() - bufferBinding.offset - bufferBinding.size) {
|
||||
mTopLevelEncoder->HandleError("dynamic offset out of bounds");
|
||||
return;
|
||||
if ((dynamicOffsets[i] >
|
||||
bufferBinding.buffer->GetSize() - bufferBinding.offset - bufferBinding.size)) {
|
||||
return DAWN_VALIDATION_ERROR("dynamic offset out of bounds");
|
||||
}
|
||||
}
|
||||
|
||||
SetBindGroupCmd* cmd = mAllocator->Allocate<SetBindGroupCmd>(Command::SetBindGroup);
|
||||
SetBindGroupCmd* cmd = allocator->Allocate<SetBindGroupCmd>(Command::SetBindGroup);
|
||||
cmd->index = groupIndex;
|
||||
cmd->group = group;
|
||||
cmd->dynamicOffsetCount = dynamicOffsetCount;
|
||||
if (dynamicOffsetCount > 0) {
|
||||
uint64_t* offsets = mAllocator->AllocateData<uint64_t>(cmd->dynamicOffsetCount);
|
||||
uint64_t* offsets = allocator->AllocateData<uint64_t>(cmd->dynamicOffsetCount);
|
||||
memcpy(offsets, dynamicOffsets, dynamicOffsetCount * sizeof(uint64_t));
|
||||
}
|
||||
}
|
||||
|
||||
MaybeError ProgrammablePassEncoder::ValidateCanRecordCommands() const {
|
||||
if (mAllocator == nullptr) {
|
||||
return DAWN_VALIDATION_ERROR("Recording in an error or already ended pass encoder");
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace dawn_native
|
||||
|
|
|
@ -29,9 +29,7 @@ namespace dawn_native {
|
|||
// Base class for shared functionality between ComputePassEncoder and RenderPassEncoder.
|
||||
class ProgrammablePassEncoder : public ObjectBase {
|
||||
public:
|
||||
ProgrammablePassEncoder(DeviceBase* device,
|
||||
CommandEncoderBase* topLevelEncoder,
|
||||
CommandAllocator* allocator);
|
||||
ProgrammablePassEncoder(DeviceBase* device, EncodingContext* encodingContext);
|
||||
|
||||
void InsertDebugMarker(const char* groupLabel);
|
||||
void PopDebugGroup();
|
||||
|
@ -45,16 +43,10 @@ namespace dawn_native {
|
|||
protected:
|
||||
// Construct an "error" programmable pass encoder.
|
||||
ProgrammablePassEncoder(DeviceBase* device,
|
||||
CommandEncoderBase* topLevelEncoder,
|
||||
EncodingContext* encodingContext,
|
||||
ErrorTag errorTag);
|
||||
|
||||
MaybeError ValidateCanRecordCommands() const;
|
||||
|
||||
// The allocator is borrowed from the top level encoder. Keep a reference to the encoder
|
||||
// to make sure the allocator isn't freed.
|
||||
Ref<CommandEncoderBase> mTopLevelEncoder = nullptr;
|
||||
// mAllocator is cleared at the end of the pass so it acts as a tag that EndPass was called
|
||||
CommandAllocator* mAllocator = nullptr;
|
||||
EncodingContext* mEncodingContext = nullptr;
|
||||
};
|
||||
|
||||
} // namespace dawn_native
|
||||
|
|
|
@ -26,31 +26,29 @@
|
|||
|
||||
namespace dawn_native {
|
||||
|
||||
RenderEncoderBase::RenderEncoderBase(DeviceBase* device,
|
||||
CommandEncoderBase* topLevelEncoder,
|
||||
CommandAllocator* allocator)
|
||||
: ProgrammablePassEncoder(device, topLevelEncoder, allocator) {
|
||||
RenderEncoderBase::RenderEncoderBase(DeviceBase* device, EncodingContext* encodingContext)
|
||||
: ProgrammablePassEncoder(device, encodingContext) {
|
||||
}
|
||||
|
||||
RenderEncoderBase::RenderEncoderBase(DeviceBase* device,
|
||||
CommandEncoderBase* topLevelEncoder,
|
||||
EncodingContext* encodingContext,
|
||||
ErrorTag errorTag)
|
||||
: ProgrammablePassEncoder(device, topLevelEncoder, errorTag) {
|
||||
: ProgrammablePassEncoder(device, encodingContext, errorTag) {
|
||||
}
|
||||
|
||||
void RenderEncoderBase::Draw(uint32_t vertexCount,
|
||||
uint32_t instanceCount,
|
||||
uint32_t firstVertex,
|
||||
uint32_t firstInstance) {
|
||||
if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) {
|
||||
return;
|
||||
}
|
||||
|
||||
DrawCmd* draw = mAllocator->Allocate<DrawCmd>(Command::Draw);
|
||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||
DrawCmd* draw = allocator->Allocate<DrawCmd>(Command::Draw);
|
||||
draw->vertexCount = vertexCount;
|
||||
draw->instanceCount = instanceCount;
|
||||
draw->firstVertex = firstVertex;
|
||||
draw->firstInstance = firstInstance;
|
||||
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
void RenderEncoderBase::DrawIndexed(uint32_t indexCount,
|
||||
|
@ -58,102 +56,103 @@ namespace dawn_native {
|
|||
uint32_t firstIndex,
|
||||
int32_t baseVertex,
|
||||
uint32_t firstInstance) {
|
||||
if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) {
|
||||
return;
|
||||
}
|
||||
|
||||
DrawIndexedCmd* draw = mAllocator->Allocate<DrawIndexedCmd>(Command::DrawIndexed);
|
||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||
DrawIndexedCmd* draw = allocator->Allocate<DrawIndexedCmd>(Command::DrawIndexed);
|
||||
draw->indexCount = indexCount;
|
||||
draw->instanceCount = instanceCount;
|
||||
draw->firstIndex = firstIndex;
|
||||
draw->baseVertex = baseVertex;
|
||||
draw->firstInstance = firstInstance;
|
||||
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
void RenderEncoderBase::DrawIndirect(BufferBase* indirectBuffer, uint64_t indirectOffset) {
|
||||
if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands()) ||
|
||||
mTopLevelEncoder->ConsumedError(GetDevice()->ValidateObject(indirectBuffer))) {
|
||||
return;
|
||||
}
|
||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||
DAWN_TRY(GetDevice()->ValidateObject(indirectBuffer));
|
||||
|
||||
if (indirectOffset >= indirectBuffer->GetSize() ||
|
||||
indirectOffset + kDrawIndirectSize > indirectBuffer->GetSize()) {
|
||||
mTopLevelEncoder->HandleError("Indirect offset out of bounds");
|
||||
return;
|
||||
return DAWN_VALIDATION_ERROR("Indirect offset out of bounds");
|
||||
}
|
||||
|
||||
DrawIndirectCmd* cmd = mAllocator->Allocate<DrawIndirectCmd>(Command::DrawIndirect);
|
||||
DrawIndirectCmd* cmd = allocator->Allocate<DrawIndirectCmd>(Command::DrawIndirect);
|
||||
cmd->indirectBuffer = indirectBuffer;
|
||||
cmd->indirectOffset = indirectOffset;
|
||||
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
void RenderEncoderBase::DrawIndexedIndirect(BufferBase* indirectBuffer,
|
||||
uint64_t indirectOffset) {
|
||||
if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands()) ||
|
||||
mTopLevelEncoder->ConsumedError(GetDevice()->ValidateObject(indirectBuffer))) {
|
||||
return;
|
||||
}
|
||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||
DAWN_TRY(GetDevice()->ValidateObject(indirectBuffer));
|
||||
|
||||
if (indirectOffset >= indirectBuffer->GetSize() ||
|
||||
indirectOffset + kDrawIndexedIndirectSize > indirectBuffer->GetSize()) {
|
||||
mTopLevelEncoder->HandleError("Indirect offset out of bounds");
|
||||
return;
|
||||
if ((indirectOffset >= indirectBuffer->GetSize() ||
|
||||
indirectOffset + kDrawIndexedIndirectSize > indirectBuffer->GetSize())) {
|
||||
return DAWN_VALIDATION_ERROR("Indirect offset out of bounds");
|
||||
}
|
||||
|
||||
DrawIndexedIndirectCmd* cmd =
|
||||
mAllocator->Allocate<DrawIndexedIndirectCmd>(Command::DrawIndexedIndirect);
|
||||
allocator->Allocate<DrawIndexedIndirectCmd>(Command::DrawIndexedIndirect);
|
||||
cmd->indirectBuffer = indirectBuffer;
|
||||
cmd->indirectOffset = indirectOffset;
|
||||
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
void RenderEncoderBase::SetPipeline(RenderPipelineBase* pipeline) {
|
||||
if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands()) ||
|
||||
mTopLevelEncoder->ConsumedError(GetDevice()->ValidateObject(pipeline))) {
|
||||
return;
|
||||
}
|
||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||
DAWN_TRY(GetDevice()->ValidateObject(pipeline));
|
||||
|
||||
SetRenderPipelineCmd* cmd =
|
||||
mAllocator->Allocate<SetRenderPipelineCmd>(Command::SetRenderPipeline);
|
||||
allocator->Allocate<SetRenderPipelineCmd>(Command::SetRenderPipeline);
|
||||
cmd->pipeline = pipeline;
|
||||
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
void RenderEncoderBase::SetIndexBuffer(BufferBase* buffer, uint64_t offset) {
|
||||
if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands()) ||
|
||||
mTopLevelEncoder->ConsumedError(GetDevice()->ValidateObject(buffer))) {
|
||||
return;
|
||||
}
|
||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||
DAWN_TRY(GetDevice()->ValidateObject(buffer));
|
||||
|
||||
SetIndexBufferCmd* cmd = mAllocator->Allocate<SetIndexBufferCmd>(Command::SetIndexBuffer);
|
||||
SetIndexBufferCmd* cmd =
|
||||
allocator->Allocate<SetIndexBufferCmd>(Command::SetIndexBuffer);
|
||||
cmd->buffer = buffer;
|
||||
cmd->offset = offset;
|
||||
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
void RenderEncoderBase::SetVertexBuffers(uint32_t startSlot,
|
||||
uint32_t count,
|
||||
BufferBase* const* buffers,
|
||||
uint64_t const* offsets) {
|
||||
if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) {
|
||||
return;
|
||||
}
|
||||
|
||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
if (mTopLevelEncoder->ConsumedError(GetDevice()->ValidateObject(buffers[i]))) {
|
||||
return;
|
||||
}
|
||||
DAWN_TRY(GetDevice()->ValidateObject(buffers[i]));
|
||||
}
|
||||
|
||||
SetVertexBuffersCmd* cmd =
|
||||
mAllocator->Allocate<SetVertexBuffersCmd>(Command::SetVertexBuffers);
|
||||
allocator->Allocate<SetVertexBuffersCmd>(Command::SetVertexBuffers);
|
||||
cmd->startSlot = startSlot;
|
||||
cmd->count = count;
|
||||
|
||||
Ref<BufferBase>* cmdBuffers = mAllocator->AllocateData<Ref<BufferBase>>(count);
|
||||
Ref<BufferBase>* cmdBuffers = allocator->AllocateData<Ref<BufferBase>>(count);
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
cmdBuffers[i] = buffers[i];
|
||||
}
|
||||
|
||||
uint64_t* cmdOffsets = mAllocator->AllocateData<uint64_t>(count);
|
||||
uint64_t* cmdOffsets = allocator->AllocateData<uint64_t>(count);
|
||||
memcpy(cmdOffsets, offsets, count * sizeof(uint64_t));
|
||||
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace dawn_native
|
||||
|
|
|
@ -22,9 +22,7 @@ namespace dawn_native {
|
|||
|
||||
class RenderEncoderBase : public ProgrammablePassEncoder {
|
||||
public:
|
||||
RenderEncoderBase(DeviceBase* device,
|
||||
CommandEncoderBase* topLevelEncoder,
|
||||
CommandAllocator* allocator);
|
||||
RenderEncoderBase(DeviceBase* device, EncodingContext* encodingContext);
|
||||
|
||||
void Draw(uint32_t vertexCount,
|
||||
uint32_t instanceCount,
|
||||
|
@ -57,9 +55,7 @@ namespace dawn_native {
|
|||
|
||||
protected:
|
||||
// Construct an "error" render encoder base.
|
||||
RenderEncoderBase(DeviceBase* device,
|
||||
CommandEncoderBase* topLevelEncoder,
|
||||
ErrorTag errorTag);
|
||||
RenderEncoderBase(DeviceBase* device, EncodingContext* encodingContext, ErrorTag errorTag);
|
||||
};
|
||||
|
||||
} // namespace dawn_native
|
||||
|
|
|
@ -27,48 +27,52 @@
|
|||
namespace dawn_native {
|
||||
|
||||
RenderPassEncoderBase::RenderPassEncoderBase(DeviceBase* device,
|
||||
CommandEncoderBase* topLevelEncoder,
|
||||
CommandAllocator* allocator)
|
||||
: RenderEncoderBase(device, topLevelEncoder, allocator) {
|
||||
CommandEncoderBase* commandEncoder,
|
||||
EncodingContext* encodingContext)
|
||||
: RenderEncoderBase(device, encodingContext), mCommandEncoder(commandEncoder) {
|
||||
}
|
||||
|
||||
RenderPassEncoderBase::RenderPassEncoderBase(DeviceBase* device,
|
||||
CommandEncoderBase* topLevelEncoder,
|
||||
CommandEncoderBase* commandEncoder,
|
||||
EncodingContext* encodingContext,
|
||||
ErrorTag errorTag)
|
||||
: RenderEncoderBase(device, topLevelEncoder, errorTag) {
|
||||
: RenderEncoderBase(device, encodingContext, errorTag), mCommandEncoder(commandEncoder) {
|
||||
}
|
||||
|
||||
RenderPassEncoderBase* RenderPassEncoderBase::MakeError(DeviceBase* device,
|
||||
CommandEncoderBase* topLevelEncoder) {
|
||||
return new RenderPassEncoderBase(device, topLevelEncoder, ObjectBase::kError);
|
||||
CommandEncoderBase* commandEncoder,
|
||||
EncodingContext* encodingContext) {
|
||||
return new RenderPassEncoderBase(device, commandEncoder, encodingContext,
|
||||
ObjectBase::kError);
|
||||
}
|
||||
|
||||
void RenderPassEncoderBase::EndPass() {
|
||||
if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) {
|
||||
return;
|
||||
}
|
||||
if (mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||
allocator->Allocate<EndRenderPassCmd>(Command::EndRenderPass);
|
||||
|
||||
mTopLevelEncoder->PassEnded();
|
||||
mAllocator = nullptr;
|
||||
return {};
|
||||
})) {
|
||||
mEncodingContext->ExitPass(this);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderPassEncoderBase::SetStencilReference(uint32_t reference) {
|
||||
if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) {
|
||||
return;
|
||||
}
|
||||
|
||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||
SetStencilReferenceCmd* cmd =
|
||||
mAllocator->Allocate<SetStencilReferenceCmd>(Command::SetStencilReference);
|
||||
allocator->Allocate<SetStencilReferenceCmd>(Command::SetStencilReference);
|
||||
cmd->reference = reference;
|
||||
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
void RenderPassEncoderBase::SetBlendColor(const Color* color) {
|
||||
if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) {
|
||||
return;
|
||||
}
|
||||
|
||||
SetBlendColorCmd* cmd = mAllocator->Allocate<SetBlendColorCmd>(Command::SetBlendColor);
|
||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||
SetBlendColorCmd* cmd = allocator->Allocate<SetBlendColorCmd>(Command::SetBlendColor);
|
||||
cmd->color = *color;
|
||||
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
void RenderPassEncoderBase::SetViewport(float x,
|
||||
|
@ -77,55 +81,53 @@ namespace dawn_native {
|
|||
float height,
|
||||
float minDepth,
|
||||
float maxDepth) {
|
||||
if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isnan(x) || isnan(y) || isnan(width) || isnan(height) || isnan(minDepth) ||
|
||||
isnan(maxDepth)) {
|
||||
mTopLevelEncoder->HandleError("NaN is not allowed.");
|
||||
return;
|
||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||
if ((isnan(x) || isnan(y) || isnan(width) || isnan(height) || isnan(minDepth) ||
|
||||
isnan(maxDepth))) {
|
||||
return DAWN_VALIDATION_ERROR("NaN is not allowed.");
|
||||
}
|
||||
|
||||
// TODO(yunchao.he@intel.com): there are more restrictions for x, y, width and height in
|
||||
// Vulkan, and height can be a negative value in Vulkan 1.1. Revisit this part later (say,
|
||||
// for WebGPU v1).
|
||||
// Vulkan, and height can be a negative value in Vulkan 1.1. Revisit this part later
|
||||
// (say, for WebGPU v1).
|
||||
if (width <= 0 || height <= 0) {
|
||||
mTopLevelEncoder->HandleError("Width and height must be greater than 0.");
|
||||
return;
|
||||
return DAWN_VALIDATION_ERROR("Width and height must be greater than 0.");
|
||||
}
|
||||
|
||||
if (minDepth < 0 || minDepth > 1 || maxDepth < 0 || maxDepth > 1) {
|
||||
mTopLevelEncoder->HandleError("minDepth and maxDepth must be in [0, 1].");
|
||||
return;
|
||||
return DAWN_VALIDATION_ERROR("minDepth and maxDepth must be in [0, 1].");
|
||||
}
|
||||
|
||||
SetViewportCmd* cmd = mAllocator->Allocate<SetViewportCmd>(Command::SetViewport);
|
||||
SetViewportCmd* cmd = allocator->Allocate<SetViewportCmd>(Command::SetViewport);
|
||||
cmd->x = x;
|
||||
cmd->y = y;
|
||||
cmd->width = width;
|
||||
cmd->height = height;
|
||||
cmd->minDepth = minDepth;
|
||||
cmd->maxDepth = maxDepth;
|
||||
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
void RenderPassEncoderBase::SetScissorRect(uint32_t x,
|
||||
uint32_t y,
|
||||
uint32_t width,
|
||||
uint32_t height) {
|
||||
if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) {
|
||||
return;
|
||||
}
|
||||
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
|
||||
if (width == 0 || height == 0) {
|
||||
mTopLevelEncoder->HandleError("Width and height must be greater than 0.");
|
||||
return;
|
||||
return DAWN_VALIDATION_ERROR("Width and height must be greater than 0.");
|
||||
}
|
||||
|
||||
SetScissorRectCmd* cmd = mAllocator->Allocate<SetScissorRectCmd>(Command::SetScissorRect);
|
||||
SetScissorRectCmd* cmd =
|
||||
allocator->Allocate<SetScissorRectCmd>(Command::SetScissorRect);
|
||||
cmd->x = x;
|
||||
cmd->y = y;
|
||||
cmd->width = width;
|
||||
cmd->height = height;
|
||||
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace dawn_native
|
||||
|
|
|
@ -27,11 +27,12 @@ namespace dawn_native {
|
|||
class RenderPassEncoderBase : public RenderEncoderBase {
|
||||
public:
|
||||
RenderPassEncoderBase(DeviceBase* device,
|
||||
CommandEncoderBase* topLevelEncoder,
|
||||
CommandAllocator* allocator);
|
||||
CommandEncoderBase* commandEncoder,
|
||||
EncodingContext* encodingContext);
|
||||
|
||||
static RenderPassEncoderBase* MakeError(DeviceBase* device,
|
||||
CommandEncoderBase* topLevelEncoder);
|
||||
CommandEncoderBase* commandEncoder,
|
||||
EncodingContext* encodingContext);
|
||||
|
||||
void EndPass();
|
||||
|
||||
|
@ -47,8 +48,14 @@ namespace dawn_native {
|
|||
|
||||
protected:
|
||||
RenderPassEncoderBase(DeviceBase* device,
|
||||
CommandEncoderBase* topLevelEncoder,
|
||||
CommandEncoderBase* commandEncoder,
|
||||
EncodingContext* encodingContext,
|
||||
ErrorTag errorTag);
|
||||
|
||||
private:
|
||||
// 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.
|
||||
Ref<CommandEncoderBase> mCommandEncoder;
|
||||
};
|
||||
|
||||
} // namespace dawn_native
|
||||
|
|
|
@ -49,9 +49,7 @@ TEST_F(CommandBufferValidationTest, EndedMidRenderPass) {
|
|||
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&dummyRenderPass);
|
||||
ASSERT_DEVICE_ERROR(encoder.Finish());
|
||||
// TODO(cwallez@chromium.org) this should probably be a device error, but currently it
|
||||
// produces a encoder error.
|
||||
pass.EndPass();
|
||||
ASSERT_DEVICE_ERROR(pass.EndPass());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,9 +76,7 @@ TEST_F(CommandBufferValidationTest, EndedMidComputePass) {
|
|||
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
dawn::ComputePassEncoder pass = encoder.BeginComputePass();
|
||||
ASSERT_DEVICE_ERROR(encoder.Finish());
|
||||
// TODO(cwallez@chromium.org) this should probably be a device error, but currently it
|
||||
// produces a encoder error.
|
||||
pass.EndPass();
|
||||
ASSERT_DEVICE_ERROR(pass.EndPass());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,8 +97,6 @@ TEST_F(CommandBufferValidationTest, RenderPassEndedTwice) {
|
|||
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&dummyRenderPass);
|
||||
pass.EndPass();
|
||||
// TODO(cwallez@chromium.org) this should probably be a device error, but currently it
|
||||
// produces a encoder error.
|
||||
pass.EndPass();
|
||||
ASSERT_DEVICE_ERROR(encoder.Finish());
|
||||
}
|
||||
|
@ -123,8 +117,6 @@ TEST_F(CommandBufferValidationTest, ComputePassEndedTwice) {
|
|||
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
dawn::ComputePassEncoder pass = encoder.BeginComputePass();
|
||||
pass.EndPass();
|
||||
// TODO(cwallez@chromium.org) this should probably be a device error, but currently it
|
||||
// produces a encoder error.
|
||||
pass.EndPass();
|
||||
ASSERT_DEVICE_ERROR(encoder.Finish());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue