Implement RenderBundle in the frontend
This CL implements RenderBundle and RenderBundleEncoder in the frontend
and adds unittests for validation.
Bug: dawn:154
Change-Id: Ice5ecd384cd627ad270b73052408f8139d1ea5f4
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/9221
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
diff --git a/src/dawn_native/AttachmentState.cpp b/src/dawn_native/AttachmentState.cpp
index 39ddb4b..00bd10b 100644
--- a/src/dawn_native/AttachmentState.cpp
+++ b/src/dawn_native/AttachmentState.cpp
@@ -21,6 +21,19 @@
namespace dawn_native {
+ AttachmentStateBlueprint::AttachmentStateBlueprint(
+ const RenderBundleEncoderDescriptor* descriptor)
+ : mHasDepthStencilAttachment(descriptor->depthStencilFormat != nullptr),
+ mSampleCount(descriptor->sampleCount) {
+ for (uint32_t i = 0; i < descriptor->colorFormatsCount; ++i) {
+ mColorAttachmentsSet.set(i);
+ mColorFormats[i] = descriptor->colorFormats[i];
+ }
+ if (mHasDepthStencilAttachment) {
+ mDepthStencilFormat = *descriptor->depthStencilFormat;
+ }
+ }
+
AttachmentStateBlueprint::AttachmentStateBlueprint(const RenderPipelineDescriptor* descriptor)
: mHasDepthStencilAttachment(descriptor->depthStencilState != nullptr),
mSampleCount(descriptor->sampleCount) {
diff --git a/src/dawn_native/AttachmentState.h b/src/dawn_native/AttachmentState.h
index 34f2c1a..a7202fd 100644
--- a/src/dawn_native/AttachmentState.h
+++ b/src/dawn_native/AttachmentState.h
@@ -33,8 +33,9 @@
class AttachmentStateBlueprint {
public:
// Note: Descriptors must be validated before the AttachmentState is constructed.
- AttachmentStateBlueprint(const RenderPipelineDescriptor* descriptor);
- AttachmentStateBlueprint(const RenderPassDescriptor* descriptor);
+ explicit AttachmentStateBlueprint(const RenderBundleEncoderDescriptor* descriptor);
+ explicit AttachmentStateBlueprint(const RenderPipelineDescriptor* descriptor);
+ explicit AttachmentStateBlueprint(const RenderPassDescriptor* descriptor);
AttachmentStateBlueprint(const AttachmentStateBlueprint& rhs);
diff --git a/src/dawn_native/CommandValidation.cpp b/src/dawn_native/CommandValidation.cpp
index 9099a9e..78f8949 100644
--- a/src/dawn_native/CommandValidation.cpp
+++ b/src/dawn_native/CommandValidation.cpp
@@ -19,6 +19,7 @@
#include "dawn_native/CommandBufferStateTracker.h"
#include "dawn_native/Commands.h"
#include "dawn_native/PassResourceUsageTracker.h"
+#include "dawn_native/RenderBundle.h"
#include "dawn_native/RenderPipeline.h"
namespace dawn_native {
@@ -177,6 +178,27 @@
} // namespace
+ MaybeError ValidateRenderBundle(CommandIterator* commands,
+ const AttachmentState* attachmentState,
+ PassResourceUsage* resourceUsage) {
+ PassResourceUsageTracker usageTracker;
+ CommandBufferStateTracker commandBufferState;
+ unsigned int debugGroupStackSize = 0;
+
+ Command type;
+ while (commands->NextCommandId(&type)) {
+ DAWN_TRY(ValidateRenderBundleCommand(commands, type, &usageTracker, &commandBufferState,
+ attachmentState, &debugGroupStackSize,
+ "Command disallowed inside a render bundle"));
+ }
+
+ DAWN_TRY(usageTracker.ValidateRenderPassUsages());
+ ASSERT(resourceUsage != nullptr);
+ *resourceUsage = usageTracker.AcquireResourceUsage();
+
+ return {};
+ }
+
MaybeError ValidateRenderPass(CommandIterator* commands,
BeginRenderPassCmd* renderPass,
std::vector<PassResourceUsage>* perPassResourceUsages) {
@@ -217,6 +239,33 @@
return {};
} break;
+ case Command::ExecuteBundles: {
+ ExecuteBundlesCmd* cmd = commands->NextCommand<ExecuteBundlesCmd>();
+ auto bundles = commands->NextData<Ref<RenderBundleBase>>(cmd->count);
+ for (uint32_t i = 0; i < cmd->count; ++i) {
+ if (DAWN_UNLIKELY(renderPass->attachmentState.Get() !=
+ bundles[i]->GetAttachmentState())) {
+ return DAWN_VALIDATION_ERROR(
+ "Render bundle is not compatible with render pass");
+ }
+
+ const PassResourceUsage& usages = bundles[i]->GetResourceUsage();
+ for (uint32_t i = 0; i < usages.buffers.size(); ++i) {
+ usageTracker.BufferUsedAs(usages.buffers[i], usages.bufferUsages[i]);
+ }
+
+ for (uint32_t i = 0; i < usages.textures.size(); ++i) {
+ usageTracker.TextureUsedAs(usages.textures[i], usages.textureUsages[i]);
+ }
+ }
+
+ if (cmd->count > 0) {
+ // Reset state. It is invalidated after render bundle execution.
+ commandBufferState = CommandBufferStateTracker{};
+ }
+
+ } break;
+
case Command::SetStencilReference: {
commands->NextCommand<SetStencilReferenceCmd>();
} break;
diff --git a/src/dawn_native/CommandValidation.h b/src/dawn_native/CommandValidation.h
index 2d29cb3..c90343c 100644
--- a/src/dawn_native/CommandValidation.h
+++ b/src/dawn_native/CommandValidation.h
@@ -22,9 +22,13 @@
namespace dawn_native {
+ class AttachmentState;
struct BeginRenderPassCmd;
struct PassResourceUsage;
+ MaybeError ValidateRenderBundle(CommandIterator* commands,
+ const AttachmentState* attachmentState,
+ PassResourceUsage* resourceUsage);
MaybeError ValidateRenderPass(CommandIterator* commands,
BeginRenderPassCmd* renderPass,
std::vector<PassResourceUsage>* perPassResourceUsages);
diff --git a/src/dawn_native/Commands.cpp b/src/dawn_native/Commands.cpp
index fbc9172..eb11791 100644
--- a/src/dawn_native/Commands.cpp
+++ b/src/dawn_native/Commands.cpp
@@ -18,6 +18,7 @@
#include "dawn_native/Buffer.h"
#include "dawn_native/CommandAllocator.h"
#include "dawn_native/ComputePipeline.h"
+#include "dawn_native/RenderBundle.h"
#include "dawn_native/RenderPipeline.h"
#include "dawn_native/Texture.h"
@@ -86,6 +87,14 @@
EndRenderPassCmd* cmd = commands->NextCommand<EndRenderPassCmd>();
cmd->~EndRenderPassCmd();
} break;
+ case Command::ExecuteBundles: {
+ ExecuteBundlesCmd* cmd = commands->NextCommand<ExecuteBundlesCmd>();
+ auto bundles = commands->NextData<Ref<RenderBundleBase>>(cmd->count);
+ for (size_t i = 0; i < cmd->count; ++i) {
+ (&bundles[i])->~Ref<RenderBundleBase>();
+ }
+ cmd->~ExecuteBundlesCmd();
+ } break;
case Command::InsertDebugMarker: {
InsertDebugMarkerCmd* cmd = commands->NextCommand<InsertDebugMarkerCmd>();
commands->NextData<char>(cmd->length + 1);
@@ -207,6 +216,11 @@
commands->NextCommand<EndRenderPassCmd>();
break;
+ case Command::ExecuteBundles: {
+ auto* cmd = commands->NextCommand<ExecuteBundlesCmd>();
+ commands->NextData<Ref<RenderBundleBase>>(cmd->count);
+ } break;
+
case Command::InsertDebugMarker: {
InsertDebugMarkerCmd* cmd = commands->NextCommand<InsertDebugMarkerCmd>();
commands->NextData<char>(cmd->length + 1);
diff --git a/src/dawn_native/Commands.h b/src/dawn_native/Commands.h
index 442cc95..18d834d 100644
--- a/src/dawn_native/Commands.h
+++ b/src/dawn_native/Commands.h
@@ -46,6 +46,7 @@
DrawIndexedIndirect,
EndComputePass,
EndRenderPass,
+ ExecuteBundles,
InsertDebugMarker,
PopDebugGroup,
PushDebugGroup,
@@ -170,6 +171,10 @@
struct EndRenderPassCmd {};
+ struct ExecuteBundlesCmd {
+ uint32_t count;
+ };
+
struct InsertDebugMarkerCmd {
uint32_t length;
};
diff --git a/src/dawn_native/Device.cpp b/src/dawn_native/Device.cpp
index 3eef7e3..b02bda1e 100644
--- a/src/dawn_native/Device.cpp
+++ b/src/dawn_native/Device.cpp
@@ -29,6 +29,7 @@
#include "dawn_native/Instance.h"
#include "dawn_native/PipelineLayout.h"
#include "dawn_native/Queue.h"
+#include "dawn_native/RenderBundleEncoder.h"
#include "dawn_native/RenderPipeline.h"
#include "dawn_native/Sampler.h"
#include "dawn_native/ShaderModule.h"
@@ -268,33 +269,34 @@
}
Ref<AttachmentState> DeviceBase::GetOrCreateAttachmentState(
- const RenderPipelineDescriptor* descriptor) {
- AttachmentStateBlueprint blueprint(descriptor);
-
- auto iter = mCaches->attachmentStates.find(&blueprint);
+ AttachmentStateBlueprint* blueprint) {
+ auto iter = mCaches->attachmentStates.find(blueprint);
if (iter != mCaches->attachmentStates.end()) {
return static_cast<AttachmentState*>(*iter);
}
- Ref<AttachmentState> attachmentState = new AttachmentState(this, blueprint);
+ Ref<AttachmentState> attachmentState = new AttachmentState(this, *blueprint);
attachmentState->Release();
mCaches->attachmentStates.insert(attachmentState.Get());
return attachmentState;
}
Ref<AttachmentState> DeviceBase::GetOrCreateAttachmentState(
+ const RenderBundleEncoderDescriptor* descriptor) {
+ AttachmentStateBlueprint blueprint(descriptor);
+ return GetOrCreateAttachmentState(&blueprint);
+ }
+
+ Ref<AttachmentState> DeviceBase::GetOrCreateAttachmentState(
+ const RenderPipelineDescriptor* descriptor) {
+ AttachmentStateBlueprint blueprint(descriptor);
+ return GetOrCreateAttachmentState(&blueprint);
+ }
+
+ Ref<AttachmentState> DeviceBase::GetOrCreateAttachmentState(
const RenderPassDescriptor* descriptor) {
AttachmentStateBlueprint blueprint(descriptor);
-
- auto iter = mCaches->attachmentStates.find(&blueprint);
- if (iter != mCaches->attachmentStates.end()) {
- return static_cast<AttachmentState*>(*iter);
- }
-
- Ref<AttachmentState> attachmentState = new AttachmentState(this, blueprint);
- attachmentState->Release();
- mCaches->attachmentStates.insert(attachmentState.Get());
- return attachmentState;
+ return GetOrCreateAttachmentState(&blueprint);
}
void DeviceBase::UncacheAttachmentState(AttachmentState* obj) {
@@ -428,6 +430,16 @@
return result;
}
+ RenderBundleEncoderBase* DeviceBase::CreateRenderBundleEncoder(
+ const RenderBundleEncoderDescriptor* descriptor) {
+ RenderBundleEncoderBase* result = nullptr;
+
+ if (ConsumedError(CreateRenderBundleEncoderInternal(&result, descriptor))) {
+ return RenderBundleEncoderBase::MakeError(this);
+ }
+
+ return result;
+ }
RenderPipelineBase* DeviceBase::CreateRenderPipeline(
const RenderPipelineDescriptor* descriptor) {
RenderPipelineBase* result = nullptr;
@@ -601,6 +613,14 @@
return {};
}
+ MaybeError DeviceBase::CreateRenderBundleEncoderInternal(
+ RenderBundleEncoderBase** result,
+ const RenderBundleEncoderDescriptor* descriptor) {
+ DAWN_TRY(ValidateRenderBundleEncoderDescriptor(this, descriptor));
+ *result = new RenderBundleEncoderBase(this, descriptor);
+ return {};
+ }
+
MaybeError DeviceBase::CreateRenderPipelineInternal(
RenderPipelineBase** result,
const RenderPipelineDescriptor* descriptor) {
diff --git a/src/dawn_native/Device.h b/src/dawn_native/Device.h
index 8a2b1c8..3ccde37 100644
--- a/src/dawn_native/Device.h
+++ b/src/dawn_native/Device.h
@@ -34,6 +34,7 @@
class AdapterBase;
class AttachmentState;
+ class AttachmentStateBlueprint;
class FenceSignalTracker;
class DynamicUploader;
class StagingBufferBase;
@@ -116,6 +117,9 @@
const ShaderModuleDescriptor* descriptor);
void UncacheShaderModule(ShaderModuleBase* obj);
+ Ref<AttachmentState> GetOrCreateAttachmentState(AttachmentStateBlueprint* blueprint);
+ Ref<AttachmentState> GetOrCreateAttachmentState(
+ const RenderBundleEncoderDescriptor* descriptor);
Ref<AttachmentState> GetOrCreateAttachmentState(const RenderPipelineDescriptor* descriptor);
Ref<AttachmentState> GetOrCreateAttachmentState(const RenderPassDescriptor* descriptor);
void UncacheAttachmentState(AttachmentState* obj);
@@ -132,6 +136,8 @@
ComputePipelineBase* CreateComputePipeline(const ComputePipelineDescriptor* descriptor);
PipelineLayoutBase* CreatePipelineLayout(const PipelineLayoutDescriptor* descriptor);
QueueBase* CreateQueue();
+ RenderBundleEncoderBase* CreateRenderBundleEncoder(
+ const RenderBundleEncoderDescriptor* descriptor);
RenderPipelineBase* CreateRenderPipeline(const RenderPipelineDescriptor* descriptor);
SamplerBase* CreateSampler(const SamplerDescriptor* descriptor);
ShaderModuleBase* CreateShaderModule(const ShaderModuleDescriptor* descriptor);
@@ -204,6 +210,9 @@
MaybeError CreatePipelineLayoutInternal(PipelineLayoutBase** result,
const PipelineLayoutDescriptor* descriptor);
MaybeError CreateQueueInternal(QueueBase** result);
+ MaybeError CreateRenderBundleEncoderInternal(
+ RenderBundleEncoderBase** result,
+ const RenderBundleEncoderDescriptor* descriptor);
MaybeError CreateRenderPipelineInternal(RenderPipelineBase** result,
const RenderPipelineDescriptor* descriptor);
MaybeError CreateSamplerInternal(SamplerBase** result, const SamplerDescriptor* descriptor);
diff --git a/src/dawn_native/EncodingContext.cpp b/src/dawn_native/EncodingContext.cpp
index d2c8a75..d36ccef 100644
--- a/src/dawn_native/EncodingContext.cpp
+++ b/src/dawn_native/EncodingContext.cpp
@@ -76,6 +76,10 @@
}
MaybeError EncodingContext::Finish() {
+ if (IsFinished()) {
+ return DAWN_VALIDATION_ERROR("Command encoding already finished");
+ }
+
const void* currentEncoder = mCurrentEncoder;
const void* topLevelEncoder = mTopLevelEncoder;
diff --git a/src/dawn_native/Forward.h b/src/dawn_native/Forward.h
index b4c3e83..1ba29da 100644
--- a/src/dawn_native/Forward.h
+++ b/src/dawn_native/Forward.h
@@ -32,6 +32,8 @@
class PipelineBase;
class PipelineLayoutBase;
class QueueBase;
+ class RenderBundleBase;
+ class RenderBundleEncoderBase;
class RenderPassEncoderBase;
class RenderPipelineBase;
class SamplerBase;
diff --git a/src/dawn_native/RenderBundle.cpp b/src/dawn_native/RenderBundle.cpp
new file mode 100644
index 0000000..9cd08ea
--- /dev/null
+++ b/src/dawn_native/RenderBundle.cpp
@@ -0,0 +1,61 @@
+// 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/RenderBundle.h"
+
+#include "common/BitSetIterator.h"
+#include "dawn_native/Commands.h"
+#include "dawn_native/Device.h"
+#include "dawn_native/RenderBundleEncoder.h"
+
+namespace dawn_native {
+
+ RenderBundleBase::RenderBundleBase(RenderBundleEncoderBase* encoder,
+ const RenderBundleDescriptor* descriptor,
+ AttachmentState* attachmentState,
+ PassResourceUsage resourceUsage)
+ : ObjectBase(encoder->GetDevice()),
+ mCommands(encoder->AcquireCommands()),
+ mAttachmentState(attachmentState),
+ mResourceUsage(std::move(resourceUsage)) {
+ }
+
+ RenderBundleBase::~RenderBundleBase() {
+ FreeCommands(&mCommands);
+ }
+
+ // static
+ RenderBundleBase* RenderBundleBase::MakeError(DeviceBase* device) {
+ return new RenderBundleBase(device, ObjectBase::kError);
+ }
+
+ RenderBundleBase::RenderBundleBase(DeviceBase* device, ErrorTag errorTag)
+ : ObjectBase(device, errorTag) {
+ }
+
+ CommandIterator* RenderBundleBase::GetCommands() {
+ return &mCommands;
+ }
+
+ const AttachmentState* RenderBundleBase::GetAttachmentState() const {
+ ASSERT(!IsError());
+ return mAttachmentState.Get();
+ }
+
+ const PassResourceUsage& RenderBundleBase::GetResourceUsage() const {
+ ASSERT(!IsError());
+ return mResourceUsage;
+ }
+
+} // namespace dawn_native
diff --git a/src/dawn_native/RenderBundle.h b/src/dawn_native/RenderBundle.h
new file mode 100644
index 0000000..26db850
--- /dev/null
+++ b/src/dawn_native/RenderBundle.h
@@ -0,0 +1,60 @@
+// 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_RENDERBUNDLE_H_
+#define DAWNNATIVE_RENDERBUNDLE_H_
+
+#include "common/Constants.h"
+#include "dawn_native/AttachmentState.h"
+#include "dawn_native/CommandAllocator.h"
+#include "dawn_native/Error.h"
+#include "dawn_native/ObjectBase.h"
+#include "dawn_native/PassResourceUsage.h"
+
+#include "dawn_native/dawn_platform.h"
+
+#include <bitset>
+
+namespace dawn_native {
+
+ struct BeginRenderPassCmd;
+ struct RenderBundleDescriptor;
+ class RenderBundleEncoderBase;
+
+ class RenderBundleBase : public ObjectBase {
+ public:
+ RenderBundleBase(RenderBundleEncoderBase* encoder,
+ const RenderBundleDescriptor* descriptor,
+ AttachmentState* attachmentState,
+ PassResourceUsage resourceUsage);
+ ~RenderBundleBase() override;
+
+ static RenderBundleBase* MakeError(DeviceBase* device);
+
+ CommandIterator* GetCommands();
+
+ const AttachmentState* GetAttachmentState() const;
+ const PassResourceUsage& GetResourceUsage() const;
+
+ private:
+ RenderBundleBase(DeviceBase* device, ErrorTag errorTag);
+
+ CommandIterator mCommands;
+ Ref<AttachmentState> mAttachmentState;
+ PassResourceUsage mResourceUsage;
+ };
+
+} // namespace dawn_native
+
+#endif // DAWNNATIVE_RENDERBUNDLE_H_
diff --git a/src/dawn_native/RenderBundleEncoder.cpp b/src/dawn_native/RenderBundleEncoder.cpp
new file mode 100644
index 0000000..b4febef
--- /dev/null
+++ b/src/dawn_native/RenderBundleEncoder.cpp
@@ -0,0 +1,99 @@
+// 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/RenderBundleEncoder.h"
+
+#include "dawn_native/CommandValidation.h"
+#include "dawn_native/Commands.h"
+#include "dawn_native/Device.h"
+#include "dawn_native/RenderPipeline.h"
+#include "dawn_native/ValidationUtils_autogen.h"
+
+namespace dawn_native {
+
+ MaybeError ValidateRenderBundleEncoderDescriptor(
+ const DeviceBase* device,
+ const RenderBundleEncoderDescriptor* descriptor) {
+ if (!IsValidSampleCount(descriptor->sampleCount)) {
+ return DAWN_VALIDATION_ERROR("Sample count is not supported");
+ }
+
+ if (descriptor->colorFormatsCount > kMaxColorAttachments) {
+ return DAWN_VALIDATION_ERROR("Color formats count exceeds maximum");
+ }
+
+ if (descriptor->colorFormatsCount == 0 && !descriptor->depthStencilFormat) {
+ return DAWN_VALIDATION_ERROR("Should have at least one attachment format");
+ }
+
+ for (uint32_t i = 0; i < descriptor->colorFormatsCount; ++i) {
+ DAWN_TRY(ValidateTextureFormat(descriptor->colorFormats[i]));
+ }
+
+ if (descriptor->depthStencilFormat != nullptr) {
+ DAWN_TRY(ValidateTextureFormat(*descriptor->depthStencilFormat));
+ }
+
+ return {};
+ }
+
+ RenderBundleEncoderBase::RenderBundleEncoderBase(
+ DeviceBase* device,
+ const RenderBundleEncoderDescriptor* descriptor)
+ : RenderEncoderBase(device, &mEncodingContext),
+ mEncodingContext(device, this),
+ mAttachmentState(device->GetOrCreateAttachmentState(descriptor)) {
+ }
+
+ RenderBundleEncoderBase::RenderBundleEncoderBase(DeviceBase* device, ErrorTag errorTag)
+ : RenderEncoderBase(device, &mEncodingContext, errorTag), mEncodingContext(device, this) {
+ }
+
+ // static
+ RenderBundleEncoderBase* RenderBundleEncoderBase::MakeError(DeviceBase* device) {
+ return new RenderBundleEncoderBase(device, ObjectBase::kError);
+ }
+
+ const AttachmentState* RenderBundleEncoderBase::GetAttachmentState() const {
+ return mAttachmentState.Get();
+ }
+
+ CommandIterator RenderBundleEncoderBase::AcquireCommands() {
+ return mEncodingContext.AcquireCommands();
+ }
+
+ RenderBundleBase* RenderBundleEncoderBase::Finish(const RenderBundleDescriptor* descriptor) {
+ if (GetDevice()->ConsumedError(ValidateFinish(descriptor))) {
+ return RenderBundleBase::MakeError(GetDevice());
+ }
+ ASSERT(!IsError());
+
+ return new RenderBundleBase(this, descriptor, mAttachmentState.Get(),
+ std::move(mResourceUsage));
+ }
+
+ MaybeError RenderBundleEncoderBase::ValidateFinish(const RenderBundleDescriptor* descriptor) {
+ DAWN_TRY(GetDevice()->ValidateObject(this));
+
+ // 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());
+
+ CommandIterator* commands = mEncodingContext.GetIterator();
+
+ DAWN_TRY(ValidateRenderBundle(commands, mAttachmentState.Get(), &mResourceUsage));
+ return {};
+ }
+
+} // namespace dawn_native
diff --git a/src/dawn_native/RenderBundleEncoder.h b/src/dawn_native/RenderBundleEncoder.h
new file mode 100644
index 0000000..aa32201
--- /dev/null
+++ b/src/dawn_native/RenderBundleEncoder.h
@@ -0,0 +1,53 @@
+// 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_RENDERBUNDLEENCODER_H_
+#define DAWNNATIVE_RENDERBUNDLEENCODER_H_
+
+#include "dawn_native/AttachmentState.h"
+#include "dawn_native/EncodingContext.h"
+#include "dawn_native/Error.h"
+#include "dawn_native/RenderBundle.h"
+#include "dawn_native/RenderEncoderBase.h"
+
+namespace dawn_native {
+
+ MaybeError ValidateRenderBundleEncoderDescriptor(
+ const DeviceBase* device,
+ const RenderBundleEncoderDescriptor* descriptor);
+ class RenderBundleEncoderBase : public RenderEncoderBase {
+ public:
+ RenderBundleEncoderBase(DeviceBase* device,
+ const RenderBundleEncoderDescriptor* descriptor);
+
+ static RenderBundleEncoderBase* MakeError(DeviceBase* device);
+
+ const AttachmentState* GetAttachmentState() const;
+
+ RenderBundleBase* Finish(const RenderBundleDescriptor* descriptor);
+
+ CommandIterator AcquireCommands();
+
+ private:
+ RenderBundleEncoderBase(DeviceBase* device, ErrorTag errorTag);
+
+ MaybeError ValidateFinish(const RenderBundleDescriptor* descriptor);
+
+ EncodingContext mEncodingContext;
+ Ref<AttachmentState> mAttachmentState;
+ PassResourceUsage mResourceUsage;
+ };
+} // namespace dawn_native
+
+#endif // DAWNNATIVE_RENDERBUNDLEENCODER_H_
diff --git a/src/dawn_native/RenderPassEncoder.cpp b/src/dawn_native/RenderPassEncoder.cpp
index 54d5db5..27f5df3 100644
--- a/src/dawn_native/RenderPassEncoder.cpp
+++ b/src/dawn_native/RenderPassEncoder.cpp
@@ -19,6 +19,7 @@
#include "dawn_native/CommandEncoder.h"
#include "dawn_native/Commands.h"
#include "dawn_native/Device.h"
+#include "dawn_native/RenderBundle.h"
#include "dawn_native/RenderPipeline.h"
#include <math.h>
@@ -130,4 +131,24 @@
});
}
+ void RenderPassEncoderBase::ExecuteBundles(uint32_t count,
+ RenderBundleBase* const* renderBundles) {
+ mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
+ for (uint32_t i = 0; i < count; ++i) {
+ DAWN_TRY(GetDevice()->ValidateObject(renderBundles[i]));
+ }
+
+ ExecuteBundlesCmd* cmd =
+ allocator->Allocate<ExecuteBundlesCmd>(Command::ExecuteBundles);
+ cmd->count = count;
+
+ Ref<RenderBundleBase>* bundles = allocator->AllocateData<Ref<RenderBundleBase>>(count);
+ for (uint32_t i = 0; i < count; ++i) {
+ bundles[i] = renderBundles[i];
+ }
+
+ return {};
+ });
+ }
+
} // namespace dawn_native
diff --git a/src/dawn_native/RenderPassEncoder.h b/src/dawn_native/RenderPassEncoder.h
index b961079..4b7c06d 100644
--- a/src/dawn_native/RenderPassEncoder.h
+++ b/src/dawn_native/RenderPassEncoder.h
@@ -20,10 +20,12 @@
namespace dawn_native {
+ class RenderBundleBase;
+
// This is called RenderPassEncoderBase to match the code generator expectations. Note that it
// is a pure frontend type to record in its parent CommandEncoder and never has a backend
// implementation.
- // TODO(cwallez@chromium.org): Remove that generator limitation and rename to ComputePassEncoder
+ // TODO(cwallez@chromium.org): Remove that generator limitation and rename to RenderPassEncoder
class RenderPassEncoderBase : public RenderEncoderBase {
public:
RenderPassEncoderBase(DeviceBase* device,
@@ -45,6 +47,7 @@
float minDepth,
float maxDepth);
void SetScissorRect(uint32_t x, uint32_t y, uint32_t width, uint32_t height);
+ void ExecuteBundles(uint32_t count, RenderBundleBase* const* renderBundles);
protected:
RenderPassEncoderBase(DeviceBase* device,
diff --git a/src/dawn_native/RenderPipeline.h b/src/dawn_native/RenderPipeline.h
index 7a00e3a..490d178 100644
--- a/src/dawn_native/RenderPipeline.h
+++ b/src/dawn_native/RenderPipeline.h
@@ -28,6 +28,7 @@
struct BeginRenderPassCmd;
class DeviceBase;
+ class RenderBundleEncoderBase;
MaybeError ValidateRenderPipelineDescriptor(const DeviceBase* device,
const RenderPipelineDescriptor* descriptor);