• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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 #ifndef DAWNNATIVE_ENCODINGCONTEXT_H_
16 #define DAWNNATIVE_ENCODINGCONTEXT_H_
17 
18 #include "dawn_native/CommandAllocator.h"
19 #include "dawn_native/Error.h"
20 #include "dawn_native/ErrorData.h"
21 #include "dawn_native/IndirectDrawMetadata.h"
22 #include "dawn_native/PassResourceUsageTracker.h"
23 #include "dawn_native/dawn_platform.h"
24 
25 #include <string>
26 
27 namespace dawn_native {
28 
29     class CommandEncoder;
30     class DeviceBase;
31     class ApiObjectBase;
32 
33     // Base class for allocating/iterating commands.
34     // It performs error tracking as well as encoding state for render/compute passes.
35     class EncodingContext {
36       public:
37         EncodingContext(DeviceBase* device, const ApiObjectBase* initialEncoder);
38         ~EncodingContext();
39 
40         // Marks the encoding context as destroyed so that any future encodes will fail, and all
41         // encoded commands are released.
42         void Destroy();
43 
44         CommandIterator AcquireCommands();
45         CommandIterator* GetIterator();
46 
47         // Functions to handle encoder errors
48         void HandleError(std::unique_ptr<ErrorData> error);
49 
ConsumedError(MaybeError maybeError)50         inline bool ConsumedError(MaybeError maybeError) {
51             if (DAWN_UNLIKELY(maybeError.IsError())) {
52                 HandleError(maybeError.AcquireError());
53                 return true;
54             }
55             return false;
56         }
57 
58         template <typename... Args>
ConsumedError(MaybeError maybeError,const char * formatStr,const Args &...args)59         inline bool ConsumedError(MaybeError maybeError,
60                                   const char* formatStr,
61                                   const Args&... args) {
62             if (DAWN_UNLIKELY(maybeError.IsError())) {
63                 std::unique_ptr<ErrorData> error = maybeError.AcquireError();
64                 if (error->GetType() == InternalErrorType::Validation) {
65                     std::string out;
66                     absl::UntypedFormatSpec format(formatStr);
67                     if (absl::FormatUntyped(&out, format, {absl::FormatArg(args)...})) {
68                         error->AppendContext(std::move(out));
69                     } else {
70                         error->AppendContext(absl::StrFormat(
71                             "[Failed to format error message: \"%s\"].", formatStr));
72                     }
73                 }
74                 HandleError(std::move(error));
75                 return true;
76             }
77             return false;
78         }
79 
CheckCurrentEncoder(const ApiObjectBase * encoder)80         inline bool CheckCurrentEncoder(const ApiObjectBase* encoder) {
81             if (DAWN_UNLIKELY(encoder != mCurrentEncoder)) {
82                 if (mDestroyed) {
83                     HandleError(
84                         DAWN_FORMAT_VALIDATION_ERROR("Recording in a destroyed %s.", encoder));
85                 } else if (mCurrentEncoder != mTopLevelEncoder) {
86                     // The top level encoder was used when a pass encoder was current.
87                     HandleError(DAWN_FORMAT_VALIDATION_ERROR(
88                         "Command cannot be recorded while %s is active.", mCurrentEncoder));
89                 } else {
90                     HandleError(DAWN_FORMAT_VALIDATION_ERROR(
91                         "Recording in an error or already ended %s.", encoder));
92                 }
93                 return false;
94             }
95             return true;
96         }
97 
98         template <typename EncodeFunction>
TryEncode(const ApiObjectBase * encoder,EncodeFunction && encodeFunction)99         inline bool TryEncode(const ApiObjectBase* encoder, EncodeFunction&& encodeFunction) {
100             if (!CheckCurrentEncoder(encoder)) {
101                 return false;
102             }
103             ASSERT(!mWasMovedToIterator);
104             return !ConsumedError(encodeFunction(&mPendingCommands));
105         }
106 
107         template <typename EncodeFunction, typename... Args>
TryEncode(const ApiObjectBase * encoder,EncodeFunction && encodeFunction,const char * formatStr,const Args &...args)108         inline bool TryEncode(const ApiObjectBase* encoder,
109                               EncodeFunction&& encodeFunction,
110                               const char* formatStr,
111                               const Args&... args) {
112             if (!CheckCurrentEncoder(encoder)) {
113                 return false;
114             }
115             ASSERT(!mWasMovedToIterator);
116             return !ConsumedError(encodeFunction(&mPendingCommands), formatStr, args...);
117         }
118 
119         // Must be called prior to encoding a BeginRenderPassCmd. Note that it's OK to call this
120         // and then not actually call EnterPass+ExitRenderPass, for example if some other pass setup
121         // failed validation before the BeginRenderPassCmd could be encoded.
122         void WillBeginRenderPass();
123 
124         // Functions to set current encoder state
125         void EnterPass(const ApiObjectBase* passEncoder);
126         MaybeError ExitRenderPass(const ApiObjectBase* passEncoder,
127                                   RenderPassResourceUsageTracker usageTracker,
128                                   CommandEncoder* commandEncoder,
129                                   IndirectDrawMetadata indirectDrawMetadata);
130         void ExitComputePass(const ApiObjectBase* passEncoder, ComputePassResourceUsage usages);
131         MaybeError Finish();
132 
133         // Called when a pass encoder is deleted. Provides an opportunity to clean up if it's the
134         // mCurrentEncoder.
135         void EnsurePassExited(const ApiObjectBase* passEncoder);
136 
137         const RenderPassUsages& GetRenderPassUsages() const;
138         const ComputePassUsages& GetComputePassUsages() const;
139         RenderPassUsages AcquireRenderPassUsages();
140         ComputePassUsages AcquireComputePassUsages();
141 
142         void PushDebugGroupLabel(const char* groupLabel);
143         void PopDebugGroupLabel();
144 
145       private:
146         void CommitCommands(CommandAllocator allocator);
147 
148         bool IsFinished() const;
149         void MoveToIterator();
150 
151         DeviceBase* mDevice;
152 
153         // There can only be two levels of encoders. Top-level and render/compute pass.
154         // The top level encoder is the encoder the EncodingContext is created with.
155         // It doubles as flag to check if encoding has been Finished.
156         const ApiObjectBase* mTopLevelEncoder;
157         // The current encoder must be the same as the encoder provided to TryEncode,
158         // otherwise an error is produced. It may be nullptr if the EncodingContext is an error.
159         // The current encoder changes with Enter/ExitPass which should be called by
160         // CommandEncoder::Begin/EndPass.
161         const ApiObjectBase* mCurrentEncoder;
162 
163         RenderPassUsages mRenderPassUsages;
164         bool mWereRenderPassUsagesAcquired = false;
165         ComputePassUsages mComputePassUsages;
166         bool mWereComputePassUsagesAcquired = false;
167 
168         CommandAllocator mPendingCommands;
169 
170         std::vector<CommandAllocator> mAllocators;
171         CommandIterator mIterator;
172         bool mWasMovedToIterator = false;
173         bool mWereCommandsAcquired = false;
174         bool mDestroyed = false;
175 
176         std::unique_ptr<ErrorData> mError;
177         std::vector<std::string> mDebugGroupLabels;
178     };
179 
180 }  // namespace dawn_native
181 
182 #endif  // DAWNNATIVE_ENCODINGCONTEXT_H_
183