blob: b218c51c207c4f6f38b3edbf115800714fcbea0d [file] [log] [blame]
Austin Engfde94902019-07-24 18:15:24 +00001// Copyright 2019 The Dawn Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "dawn_native/EncodingContext.h"
16
17#include "common/Assert.h"
Austin Eng4b0b7a52019-11-21 22:09:41 +000018#include "dawn_native/CommandEncoder.h"
Austin Engfde94902019-07-24 18:15:24 +000019#include "dawn_native/Commands.h"
20#include "dawn_native/Device.h"
21#include "dawn_native/ErrorData.h"
Ken Rockotebf183b2021-09-23 00:15:19 +000022#include "dawn_native/IndirectDrawValidationEncoder.h"
Austin Eng4b0b7a52019-11-21 22:09:41 +000023#include "dawn_native/RenderBundleEncoder.h"
Austin Engfde94902019-07-24 18:15:24 +000024
25namespace dawn_native {
26
Brandon Jonesf33afcd2021-10-28 00:13:17 +000027 EncodingContext::EncodingContext(DeviceBase* device, const ApiObjectBase* initialEncoder)
Austin Engfde94902019-07-24 18:15:24 +000028 : mDevice(device), mTopLevelEncoder(initialEncoder), mCurrentEncoder(initialEncoder) {
29 }
30
31 EncodingContext::~EncodingContext() {
Loko Kung970739e2021-11-16 22:46:34 +000032 Destroy();
33 }
34
35 void EncodingContext::Destroy() {
36 if (mDestroyed) {
37 return;
38 }
Austin Engfde94902019-07-24 18:15:24 +000039 if (!mWereCommandsAcquired) {
40 FreeCommands(GetIterator());
41 }
Loko Kung970739e2021-11-16 22:46:34 +000042 // If we weren't already finished, then we want to handle an error here so that any calls
43 // to Finish after Destroy will return a meaningful error.
44 if (!IsFinished()) {
45 HandleError(DAWN_FORMAT_VALIDATION_ERROR("Destroyed encoder cannot be finished."));
46 }
47 mDestroyed = true;
48 mCurrentEncoder = nullptr;
Austin Engfde94902019-07-24 18:15:24 +000049 }
50
51 CommandIterator EncodingContext::AcquireCommands() {
Austin Eng4b0b7a52019-11-21 22:09:41 +000052 MoveToIterator();
Austin Engfde94902019-07-24 18:15:24 +000053 ASSERT(!mWereCommandsAcquired);
54 mWereCommandsAcquired = true;
55 return std::move(mIterator);
56 }
57
58 CommandIterator* EncodingContext::GetIterator() {
Austin Eng4b0b7a52019-11-21 22:09:41 +000059 MoveToIterator();
60 ASSERT(!mWereCommandsAcquired);
61 return &mIterator;
62 }
63
64 void EncodingContext::MoveToIterator() {
Ken Rockotebf183b2021-09-23 00:15:19 +000065 CommitCommands(std::move(mPendingCommands));
Austin Engfde94902019-07-24 18:15:24 +000066 if (!mWasMovedToIterator) {
Ken Rockotebf183b2021-09-23 00:15:19 +000067 mIterator.AcquireCommandBlocks(std::move(mAllocators));
Austin Engfde94902019-07-24 18:15:24 +000068 mWasMovedToIterator = true;
69 }
Austin Engfde94902019-07-24 18:15:24 +000070 }
71
Corentin Wallezd98b3072021-05-05 17:37:43 +000072 void EncodingContext::HandleError(std::unique_ptr<ErrorData> error) {
Brandon Jonesd6d25842021-09-29 19:39:02 +000073 // Append in reverse so that the most recently set debug group is printed first, like a
74 // call stack.
75 for (auto iter = mDebugGroupLabels.rbegin(); iter != mDebugGroupLabels.rend(); ++iter) {
76 error->AppendDebugGroup(*iter);
77 }
78
Austin Engfde94902019-07-24 18:15:24 +000079 if (!IsFinished()) {
Austin Eng464aaeb2020-11-14 01:24:03 +000080 // Encoding should only generate validation errors.
Corentin Wallezd98b3072021-05-05 17:37:43 +000081 ASSERT(error->GetType() == InternalErrorType::Validation);
Austin Engfde94902019-07-24 18:15:24 +000082 // If the encoding context is not finished, errors are deferred until
83 // Finish() is called.
Corentin Wallezd98b3072021-05-05 17:37:43 +000084 if (mError == nullptr) {
85 mError = std::move(error);
Austin Engfde94902019-07-24 18:15:24 +000086 }
87 } else {
Brandon Jonesd6d25842021-09-29 19:39:02 +000088 mDevice->HandleError(error->GetType(), error->GetFormattedMessage().c_str());
Austin Engfde94902019-07-24 18:15:24 +000089 }
90 }
91
Ken Rockotebf183b2021-09-23 00:15:19 +000092 void EncodingContext::WillBeginRenderPass() {
93 ASSERT(mCurrentEncoder == mTopLevelEncoder);
94 if (mDevice->IsValidationEnabled()) {
95 // When validation is enabled, we are going to want to capture all commands encoded
96 // between and including BeginRenderPassCmd and EndRenderPassCmd, and defer their
97 // sequencing util after we have a chance to insert any necessary validation
98 // commands. To support this we commit any current commands now, so that the
99 // impending BeginRenderPassCmd starts in a fresh CommandAllocator.
100 CommitCommands(std::move(mPendingCommands));
101 }
102 }
103
Brandon Jonesf33afcd2021-10-28 00:13:17 +0000104 void EncodingContext::EnterPass(const ApiObjectBase* passEncoder) {
Austin Engfde94902019-07-24 18:15:24 +0000105 // Assert we're at the top level.
106 ASSERT(mCurrentEncoder == mTopLevelEncoder);
107 ASSERT(passEncoder != nullptr);
108
109 mCurrentEncoder = passEncoder;
110 }
111
Brandon Jonesf33afcd2021-10-28 00:13:17 +0000112 MaybeError EncodingContext::ExitRenderPass(const ApiObjectBase* passEncoder,
Ken Rockotebf183b2021-09-23 00:15:19 +0000113 RenderPassResourceUsageTracker usageTracker,
114 CommandEncoder* commandEncoder,
115 IndirectDrawMetadata indirectDrawMetadata) {
Austin Engfde94902019-07-24 18:15:24 +0000116 ASSERT(mCurrentEncoder != mTopLevelEncoder);
Austin Engfde94902019-07-24 18:15:24 +0000117 ASSERT(mCurrentEncoder == passEncoder);
118
119 mCurrentEncoder = mTopLevelEncoder;
Ken Rockotebf183b2021-09-23 00:15:19 +0000120
121 if (mDevice->IsValidationEnabled()) {
122 // With validation enabled, commands were committed just before BeginRenderPassCmd was
123 // encoded by our RenderPassEncoder (see WillBeginRenderPass above). This means
124 // mPendingCommands contains only the commands from BeginRenderPassCmd to
125 // EndRenderPassCmd, inclusive. Now we swap out this allocator with a fresh one to give
126 // the validation encoder a chance to insert its commands first.
127 CommandAllocator renderCommands = std::move(mPendingCommands);
128 DAWN_TRY(EncodeIndirectDrawValidationCommands(mDevice, commandEncoder, &usageTracker,
129 &indirectDrawMetadata));
130 CommitCommands(std::move(mPendingCommands));
131 CommitCommands(std::move(renderCommands));
132 }
133
134 mRenderPassUsages.push_back(usageTracker.AcquireResourceUsage());
135 return {};
Corentin Wallezec7ea6a2021-05-05 19:55:23 +0000136 }
Corentin Wallez2dd2d672021-05-05 15:41:13 +0000137
Brandon Jonesf33afcd2021-10-28 00:13:17 +0000138 void EncodingContext::ExitComputePass(const ApiObjectBase* passEncoder,
Ken Rockotebf183b2021-09-23 00:15:19 +0000139 ComputePassResourceUsage usages) {
Corentin Wallezec7ea6a2021-05-05 19:55:23 +0000140 ASSERT(mCurrentEncoder != mTopLevelEncoder);
141 ASSERT(mCurrentEncoder == passEncoder);
142
143 mCurrentEncoder = mTopLevelEncoder;
144 mComputePassUsages.push_back(std::move(usages));
Austin Eng4b0b7a52019-11-21 22:09:41 +0000145 }
146
Brandon Jonesf33afcd2021-10-28 00:13:17 +0000147 void EncodingContext::EnsurePassExited(const ApiObjectBase* passEncoder) {
148 if (mCurrentEncoder != mTopLevelEncoder && mCurrentEncoder == passEncoder) {
149 // The current pass encoder is being deleted. Implicitly end the pass with an error.
150 mCurrentEncoder = mTopLevelEncoder;
151 HandleError(DAWN_FORMAT_VALIDATION_ERROR(
152 "Command buffer recording ended before %s was ended.", passEncoder));
153 }
154 }
155
Corentin Wallez2dd2d672021-05-05 15:41:13 +0000156 const RenderPassUsages& EncodingContext::GetRenderPassUsages() const {
157 ASSERT(!mWereRenderPassUsagesAcquired);
158 return mRenderPassUsages;
Austin Eng4b0b7a52019-11-21 22:09:41 +0000159 }
160
Corentin Wallez2dd2d672021-05-05 15:41:13 +0000161 RenderPassUsages EncodingContext::AcquireRenderPassUsages() {
162 ASSERT(!mWereRenderPassUsagesAcquired);
163 mWereRenderPassUsagesAcquired = true;
164 return std::move(mRenderPassUsages);
165 }
166
167 const ComputePassUsages& EncodingContext::GetComputePassUsages() const {
168 ASSERT(!mWereComputePassUsagesAcquired);
169 return mComputePassUsages;
170 }
171
172 ComputePassUsages EncodingContext::AcquireComputePassUsages() {
173 ASSERT(!mWereComputePassUsagesAcquired);
174 mWereComputePassUsagesAcquired = true;
175 return std::move(mComputePassUsages);
Austin Engfde94902019-07-24 18:15:24 +0000176 }
177
Brandon Jonesd6d25842021-09-29 19:39:02 +0000178 void EncodingContext::PushDebugGroupLabel(const char* groupLabel) {
179 mDebugGroupLabels.emplace_back(groupLabel);
180 }
181
182 void EncodingContext::PopDebugGroupLabel() {
183 mDebugGroupLabels.pop_back();
184 }
185
Austin Engfde94902019-07-24 18:15:24 +0000186 MaybeError EncodingContext::Finish() {
Brandon Jonesf33afcd2021-10-28 00:13:17 +0000187 DAWN_INVALID_IF(IsFinished(), "Command encoding already finished.");
Austin Eng8a488c12019-08-13 22:12:54 +0000188
Brandon Jonesf33afcd2021-10-28 00:13:17 +0000189 const ApiObjectBase* currentEncoder = mCurrentEncoder;
190 const ApiObjectBase* topLevelEncoder = mTopLevelEncoder;
Austin Engfde94902019-07-24 18:15:24 +0000191
192 // Even if finish validation fails, it is now invalid to call any encoding commands,
193 // so we clear the encoders. Note: mTopLevelEncoder == nullptr is used as a flag for
194 // if Finish() has been called.
195 mCurrentEncoder = nullptr;
196 mTopLevelEncoder = nullptr;
Ken Rockotebf183b2021-09-23 00:15:19 +0000197 CommitCommands(std::move(mPendingCommands));
Austin Engfde94902019-07-24 18:15:24 +0000198
Corentin Wallezd98b3072021-05-05 17:37:43 +0000199 if (mError != nullptr) {
200 return std::move(mError);
Austin Engfde94902019-07-24 18:15:24 +0000201 }
Brandon Jonesf33afcd2021-10-28 00:13:17 +0000202 DAWN_INVALID_IF(currentEncoder != topLevelEncoder,
203 "Command buffer recording ended before %s was ended.", currentEncoder);
Austin Engfde94902019-07-24 18:15:24 +0000204 return {};
205 }
206
Ken Rockotebf183b2021-09-23 00:15:19 +0000207 void EncodingContext::CommitCommands(CommandAllocator allocator) {
208 if (!allocator.IsEmpty()) {
209 mAllocators.push_back(std::move(allocator));
210 }
211 }
212
Austin Engfde94902019-07-24 18:15:24 +0000213 bool EncodingContext::IsFinished() const {
214 return mTopLevelEncoder == nullptr;
215 }
216
217} // namespace dawn_native