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/Commands.h" 21 #include "dawn_native/Device.h" 22 #include "dawn_native/RenderPipeline.h" 23 24 #include <math.h> 25 #include <string.h> 26 27 namespace dawn_native { 28 RenderPassEncoderBase(DeviceBase * device,CommandEncoderBase * topLevelEncoder,CommandAllocator * allocator)29 RenderPassEncoderBase::RenderPassEncoderBase(DeviceBase* device, 30 CommandEncoderBase* topLevelEncoder, 31 CommandAllocator* allocator) 32 : ProgrammablePassEncoder(device, topLevelEncoder, allocator) { 33 } 34 RenderPassEncoderBase(DeviceBase * device,CommandEncoderBase * topLevelEncoder,ErrorTag errorTag)35 RenderPassEncoderBase::RenderPassEncoderBase(DeviceBase* device, 36 CommandEncoderBase* topLevelEncoder, 37 ErrorTag errorTag) 38 : ProgrammablePassEncoder(device, topLevelEncoder, errorTag) { 39 } 40 MakeError(DeviceBase * device,CommandEncoderBase * topLevelEncoder)41 RenderPassEncoderBase* RenderPassEncoderBase::MakeError(DeviceBase* device, 42 CommandEncoderBase* topLevelEncoder) { 43 return new RenderPassEncoderBase(device, topLevelEncoder, ObjectBase::kError); 44 } 45 Draw(uint32_t vertexCount,uint32_t instanceCount,uint32_t firstVertex,uint32_t firstInstance)46 void RenderPassEncoderBase::Draw(uint32_t vertexCount, 47 uint32_t instanceCount, 48 uint32_t firstVertex, 49 uint32_t firstInstance) { 50 if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) { 51 return; 52 } 53 54 DrawCmd* draw = mAllocator->Allocate<DrawCmd>(Command::Draw); 55 draw->vertexCount = vertexCount; 56 draw->instanceCount = instanceCount; 57 draw->firstVertex = firstVertex; 58 draw->firstInstance = firstInstance; 59 } 60 DrawIndexed(uint32_t indexCount,uint32_t instanceCount,uint32_t firstIndex,int32_t baseVertex,uint32_t firstInstance)61 void RenderPassEncoderBase::DrawIndexed(uint32_t indexCount, 62 uint32_t instanceCount, 63 uint32_t firstIndex, 64 int32_t baseVertex, 65 uint32_t firstInstance) { 66 if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) { 67 return; 68 } 69 70 DrawIndexedCmd* draw = mAllocator->Allocate<DrawIndexedCmd>(Command::DrawIndexed); 71 draw->indexCount = indexCount; 72 draw->instanceCount = instanceCount; 73 draw->firstIndex = firstIndex; 74 draw->baseVertex = baseVertex; 75 draw->firstInstance = firstInstance; 76 } 77 DrawIndirect(BufferBase * indirectBuffer,uint64_t indirectOffset)78 void RenderPassEncoderBase::DrawIndirect(BufferBase* indirectBuffer, uint64_t indirectOffset) { 79 if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands()) || 80 mTopLevelEncoder->ConsumedError(GetDevice()->ValidateObject(indirectBuffer))) { 81 return; 82 } 83 84 if (indirectOffset >= indirectBuffer->GetSize() || 85 indirectOffset + kDrawIndirectSize > indirectBuffer->GetSize()) { 86 mTopLevelEncoder->HandleError("Indirect offset out of bounds"); 87 return; 88 } 89 90 DrawIndirectCmd* cmd = mAllocator->Allocate<DrawIndirectCmd>(Command::DrawIndirect); 91 cmd->indirectBuffer = indirectBuffer; 92 cmd->indirectOffset = indirectOffset; 93 } 94 DrawIndexedIndirect(BufferBase * indirectBuffer,uint64_t indirectOffset)95 void RenderPassEncoderBase::DrawIndexedIndirect(BufferBase* indirectBuffer, 96 uint64_t indirectOffset) { 97 if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands()) || 98 mTopLevelEncoder->ConsumedError(GetDevice()->ValidateObject(indirectBuffer))) { 99 return; 100 } 101 102 if (indirectOffset >= indirectBuffer->GetSize() || 103 indirectOffset + kDrawIndexedIndirectSize > indirectBuffer->GetSize()) { 104 mTopLevelEncoder->HandleError("Indirect offset out of bounds"); 105 return; 106 } 107 108 DrawIndexedIndirectCmd* cmd = 109 mAllocator->Allocate<DrawIndexedIndirectCmd>(Command::DrawIndexedIndirect); 110 cmd->indirectBuffer = indirectBuffer; 111 cmd->indirectOffset = indirectOffset; 112 } 113 SetPipeline(RenderPipelineBase * pipeline)114 void RenderPassEncoderBase::SetPipeline(RenderPipelineBase* pipeline) { 115 if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands()) || 116 mTopLevelEncoder->ConsumedError(GetDevice()->ValidateObject(pipeline))) { 117 return; 118 } 119 120 SetRenderPipelineCmd* cmd = 121 mAllocator->Allocate<SetRenderPipelineCmd>(Command::SetRenderPipeline); 122 cmd->pipeline = pipeline; 123 } 124 SetStencilReference(uint32_t reference)125 void RenderPassEncoderBase::SetStencilReference(uint32_t reference) { 126 if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) { 127 return; 128 } 129 130 SetStencilReferenceCmd* cmd = 131 mAllocator->Allocate<SetStencilReferenceCmd>(Command::SetStencilReference); 132 cmd->reference = reference; 133 } 134 SetBlendColor(const Color * color)135 void RenderPassEncoderBase::SetBlendColor(const Color* color) { 136 if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) { 137 return; 138 } 139 140 SetBlendColorCmd* cmd = mAllocator->Allocate<SetBlendColorCmd>(Command::SetBlendColor); 141 cmd->color = *color; 142 } 143 SetViewport(float x,float y,float width,float height,float minDepth,float maxDepth)144 void RenderPassEncoderBase::SetViewport(float x, 145 float y, 146 float width, 147 float height, 148 float minDepth, 149 float maxDepth) { 150 if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) { 151 return; 152 } 153 154 if (isnan(x) || isnan(y) || isnan(width) || isnan(height) || isnan(minDepth) || 155 isnan(maxDepth)) { 156 mTopLevelEncoder->HandleError("NaN is not allowed."); 157 return; 158 } 159 160 // TODO(yunchao.he@intel.com): there are more restrictions for x, y, width and height in 161 // Vulkan, and height can be a negative value in Vulkan 1.1. Revisit this part later (say, 162 // for WebGPU v1). 163 if (width <= 0 || height <= 0) { 164 mTopLevelEncoder->HandleError("Width and height must be greater than 0."); 165 return; 166 } 167 168 if (minDepth < 0 || minDepth > 1 || maxDepth < 0 || maxDepth > 1) { 169 mTopLevelEncoder->HandleError("minDepth and maxDepth must be in [0, 1]."); 170 return; 171 } 172 173 SetViewportCmd* cmd = mAllocator->Allocate<SetViewportCmd>(Command::SetViewport); 174 cmd->x = x; 175 cmd->y = y; 176 cmd->width = width; 177 cmd->height = height; 178 cmd->minDepth = minDepth; 179 cmd->maxDepth = maxDepth; 180 } 181 SetScissorRect(uint32_t x,uint32_t y,uint32_t width,uint32_t height)182 void RenderPassEncoderBase::SetScissorRect(uint32_t x, 183 uint32_t y, 184 uint32_t width, 185 uint32_t height) { 186 if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) { 187 return; 188 } 189 if (width == 0 || height == 0) { 190 mTopLevelEncoder->HandleError("Width and height must be greater than 0."); 191 return; 192 } 193 194 SetScissorRectCmd* cmd = mAllocator->Allocate<SetScissorRectCmd>(Command::SetScissorRect); 195 cmd->x = x; 196 cmd->y = y; 197 cmd->width = width; 198 cmd->height = height; 199 } 200 SetIndexBuffer(BufferBase * buffer,uint64_t offset)201 void RenderPassEncoderBase::SetIndexBuffer(BufferBase* buffer, uint64_t offset) { 202 if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands()) || 203 mTopLevelEncoder->ConsumedError(GetDevice()->ValidateObject(buffer))) { 204 return; 205 } 206 207 SetIndexBufferCmd* cmd = mAllocator->Allocate<SetIndexBufferCmd>(Command::SetIndexBuffer); 208 cmd->buffer = buffer; 209 cmd->offset = offset; 210 } 211 SetVertexBuffers(uint32_t startSlot,uint32_t count,BufferBase * const * buffers,uint64_t const * offsets)212 void RenderPassEncoderBase::SetVertexBuffers(uint32_t startSlot, 213 uint32_t count, 214 BufferBase* const* buffers, 215 uint64_t const* offsets) { 216 if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) { 217 return; 218 } 219 220 for (size_t i = 0; i < count; ++i) { 221 if (mTopLevelEncoder->ConsumedError(GetDevice()->ValidateObject(buffers[i]))) { 222 return; 223 } 224 } 225 226 SetVertexBuffersCmd* cmd = 227 mAllocator->Allocate<SetVertexBuffersCmd>(Command::SetVertexBuffers); 228 cmd->startSlot = startSlot; 229 cmd->count = count; 230 231 Ref<BufferBase>* cmdBuffers = mAllocator->AllocateData<Ref<BufferBase>>(count); 232 for (size_t i = 0; i < count; ++i) { 233 cmdBuffers[i] = buffers[i]; 234 } 235 236 uint64_t* cmdOffsets = mAllocator->AllocateData<uint64_t>(count); 237 memcpy(cmdOffsets, offsets, count * sizeof(uint64_t)); 238 } 239 240 } // namespace dawn_native 241