1 // Copyright 2018 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/RenderPassEncoder.h"
16 
17 #include "common/Constants.h"
18 #include "dawn_native/Buffer.h"
19 #include "dawn_native/CommandEncoder.h"
20 #include "dawn_native/CommandValidation.h"
21 #include "dawn_native/Commands.h"
22 #include "dawn_native/Device.h"
23 #include "dawn_native/QuerySet.h"
24 #include "dawn_native/RenderBundle.h"
25 #include "dawn_native/RenderPipeline.h"
26 
27 #include <math.h>
28 #include <cstring>
29 
30 namespace dawn_native {
31 
32     // The usage tracker is passed in here, because it is prepopulated with usages from the
33     // BeginRenderPassCmd. If we had RenderPassEncoder responsible for recording the
34     // command, then this wouldn't be necessary.
RenderPassEncoder(DeviceBase * device,CommandEncoder * commandEncoder,EncodingContext * encodingContext,PassResourceUsageTracker usageTracker,uint32_t renderTargetWidth,uint32_t renderTargetHeight)35     RenderPassEncoder::RenderPassEncoder(DeviceBase* device,
36                                          CommandEncoder* commandEncoder,
37                                          EncodingContext* encodingContext,
38                                          PassResourceUsageTracker usageTracker,
39                                          uint32_t renderTargetWidth,
40                                          uint32_t renderTargetHeight)
41         : RenderEncoderBase(device, encodingContext),
42           mCommandEncoder(commandEncoder),
43           mRenderTargetWidth(renderTargetWidth),
44           mRenderTargetHeight(renderTargetHeight) {
45         mUsageTracker = std::move(usageTracker);
46     }
47 
RenderPassEncoder(DeviceBase * device,CommandEncoder * commandEncoder,EncodingContext * encodingContext,ErrorTag errorTag)48     RenderPassEncoder::RenderPassEncoder(DeviceBase* device,
49                                          CommandEncoder* commandEncoder,
50                                          EncodingContext* encodingContext,
51                                          ErrorTag errorTag)
52         : RenderEncoderBase(device, encodingContext, errorTag), mCommandEncoder(commandEncoder) {
53     }
54 
MakeError(DeviceBase * device,CommandEncoder * commandEncoder,EncodingContext * encodingContext)55     RenderPassEncoder* RenderPassEncoder::MakeError(DeviceBase* device,
56                                                     CommandEncoder* commandEncoder,
57                                                     EncodingContext* encodingContext) {
58         return new RenderPassEncoder(device, commandEncoder, encodingContext, ObjectBase::kError);
59     }
60 
EndPass()61     void RenderPassEncoder::EndPass() {
62         if (mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
63                 allocator->Allocate<EndRenderPassCmd>(Command::EndRenderPass);
64 
65                 return {};
66             })) {
67             mEncodingContext->ExitPass(this, mUsageTracker.AcquireResourceUsage());
68         }
69     }
70 
SetStencilReference(uint32_t reference)71     void RenderPassEncoder::SetStencilReference(uint32_t reference) {
72         mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
73             SetStencilReferenceCmd* cmd =
74                 allocator->Allocate<SetStencilReferenceCmd>(Command::SetStencilReference);
75             cmd->reference = reference;
76 
77             return {};
78         });
79     }
80 
SetBlendColor(const Color * color)81     void RenderPassEncoder::SetBlendColor(const Color* color) {
82         mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
83             SetBlendColorCmd* cmd = allocator->Allocate<SetBlendColorCmd>(Command::SetBlendColor);
84             cmd->color = *color;
85 
86             return {};
87         });
88     }
89 
SetViewport(float x,float y,float width,float height,float minDepth,float maxDepth)90     void RenderPassEncoder::SetViewport(float x,
91                                         float y,
92                                         float width,
93                                         float height,
94                                         float minDepth,
95                                         float maxDepth) {
96         mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
97             if ((isnan(x) || isnan(y) || isnan(width) || isnan(height) || isnan(minDepth) ||
98                  isnan(maxDepth))) {
99                 return DAWN_VALIDATION_ERROR("NaN is not allowed.");
100             }
101 
102             if (x < 0 || y < 0 || width < 0 || height < 0) {
103                 return DAWN_VALIDATION_ERROR("X, Y, width and height must be non-negative.");
104             }
105 
106             if (x + width > mRenderTargetWidth || y + height > mRenderTargetHeight) {
107                 return DAWN_VALIDATION_ERROR(
108                     "The viewport must be contained in the render targets");
109             }
110 
111             // Check for depths being in [0, 1] and min <= max in 3 checks instead of 5.
112             if (minDepth < 0 || minDepth > maxDepth || maxDepth > 1) {
113                 return DAWN_VALIDATION_ERROR(
114                     "minDepth and maxDepth must be in [0, 1] and minDepth <= maxDepth.");
115             }
116 
117             SetViewportCmd* cmd = allocator->Allocate<SetViewportCmd>(Command::SetViewport);
118             cmd->x = x;
119             cmd->y = y;
120             cmd->width = width;
121             cmd->height = height;
122             cmd->minDepth = minDepth;
123             cmd->maxDepth = maxDepth;
124 
125             return {};
126         });
127     }
128 
SetScissorRect(uint32_t x,uint32_t y,uint32_t width,uint32_t height)129     void RenderPassEncoder::SetScissorRect(uint32_t x,
130                                            uint32_t y,
131                                            uint32_t width,
132                                            uint32_t height) {
133         mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
134             if (width > mRenderTargetWidth || height > mRenderTargetHeight ||
135                 x > mRenderTargetWidth - width || y > mRenderTargetHeight - height) {
136                 return DAWN_VALIDATION_ERROR(
137                     "The scissor rect must be contained in the render targets");
138             }
139 
140             SetScissorRectCmd* cmd =
141                 allocator->Allocate<SetScissorRectCmd>(Command::SetScissorRect);
142             cmd->x = x;
143             cmd->y = y;
144             cmd->width = width;
145             cmd->height = height;
146 
147             return {};
148         });
149     }
150 
ExecuteBundles(uint32_t count,RenderBundleBase * const * renderBundles)151     void RenderPassEncoder::ExecuteBundles(uint32_t count, RenderBundleBase* const* renderBundles) {
152         mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
153             for (uint32_t i = 0; i < count; ++i) {
154                 DAWN_TRY(GetDevice()->ValidateObject(renderBundles[i]));
155             }
156 
157             ExecuteBundlesCmd* cmd =
158                 allocator->Allocate<ExecuteBundlesCmd>(Command::ExecuteBundles);
159             cmd->count = count;
160 
161             Ref<RenderBundleBase>* bundles = allocator->AllocateData<Ref<RenderBundleBase>>(count);
162             for (uint32_t i = 0; i < count; ++i) {
163                 bundles[i] = renderBundles[i];
164 
165                 const PassResourceUsage& usages = bundles[i]->GetResourceUsage();
166                 for (uint32_t i = 0; i < usages.buffers.size(); ++i) {
167                     mUsageTracker.BufferUsedAs(usages.buffers[i], usages.bufferUsages[i]);
168                 }
169 
170                 for (uint32_t i = 0; i < usages.textures.size(); ++i) {
171                     mUsageTracker.AddTextureUsage(usages.textures[i], usages.textureUsages[i]);
172                 }
173             }
174 
175             return {};
176         });
177     }
178 
WriteTimestamp(QuerySetBase * querySet,uint32_t queryIndex)179     void RenderPassEncoder::WriteTimestamp(QuerySetBase* querySet, uint32_t queryIndex) {
180         mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
181             if (GetDevice()->IsValidationEnabled()) {
182                 DAWN_TRY(GetDevice()->ValidateObject(querySet));
183                 DAWN_TRY(ValidateTimestampQuery(querySet, queryIndex,
184                                                 mCommandEncoder->GetUsedQueryIndices()));
185                 mCommandEncoder->TrackUsedQuerySet(querySet);
186             }
187 
188             mCommandEncoder->TrackUsedQueryIndex(querySet, queryIndex);
189 
190             WriteTimestampCmd* cmd =
191                 allocator->Allocate<WriteTimestampCmd>(Command::WriteTimestamp);
192             cmd->querySet = querySet;
193             cmd->queryIndex = queryIndex;
194 
195             return {};
196         });
197     }
198 
199 }  // namespace dawn_native
200