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