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/ProgrammablePassEncoder.h" 16 17 #include "dawn_native/BindGroup.h" 18 #include "dawn_native/Buffer.h" 19 #include "dawn_native/CommandBuffer.h" 20 #include "dawn_native/Commands.h" 21 #include "dawn_native/Device.h" 22 #include "dawn_native/ValidationUtils_autogen.h" 23 24 #include <string.h> 25 26 namespace dawn_native { 27 ProgrammablePassEncoder(DeviceBase * device,CommandEncoderBase * topLevelEncoder,CommandAllocator * allocator)28 ProgrammablePassEncoder::ProgrammablePassEncoder(DeviceBase* device, 29 CommandEncoderBase* topLevelEncoder, 30 CommandAllocator* allocator) 31 : ObjectBase(device), mTopLevelEncoder(topLevelEncoder), mAllocator(allocator) { 32 DAWN_ASSERT(allocator != nullptr); 33 } 34 ProgrammablePassEncoder(DeviceBase * device,CommandEncoderBase * topLevelEncoder,ErrorTag errorTag)35 ProgrammablePassEncoder::ProgrammablePassEncoder(DeviceBase* device, 36 CommandEncoderBase* topLevelEncoder, 37 ErrorTag errorTag) 38 : ObjectBase(device, errorTag), mTopLevelEncoder(topLevelEncoder), mAllocator(nullptr) { 39 } 40 EndPass()41 void ProgrammablePassEncoder::EndPass() { 42 if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) { 43 return; 44 } 45 46 mTopLevelEncoder->PassEnded(); 47 mAllocator = nullptr; 48 } 49 InsertDebugMarker(const char * groupLabel)50 void ProgrammablePassEncoder::InsertDebugMarker(const char* groupLabel) { 51 if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) { 52 return; 53 } 54 55 InsertDebugMarkerCmd* cmd = 56 mAllocator->Allocate<InsertDebugMarkerCmd>(Command::InsertDebugMarker); 57 cmd->length = strlen(groupLabel); 58 59 char* label = mAllocator->AllocateData<char>(cmd->length + 1); 60 memcpy(label, groupLabel, cmd->length + 1); 61 } 62 PopDebugGroup()63 void ProgrammablePassEncoder::PopDebugGroup() { 64 if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) { 65 return; 66 } 67 68 mAllocator->Allocate<PopDebugGroupCmd>(Command::PopDebugGroup); 69 } 70 PushDebugGroup(const char * groupLabel)71 void ProgrammablePassEncoder::PushDebugGroup(const char* groupLabel) { 72 if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) { 73 return; 74 } 75 76 PushDebugGroupCmd* cmd = mAllocator->Allocate<PushDebugGroupCmd>(Command::PushDebugGroup); 77 cmd->length = strlen(groupLabel); 78 79 char* label = mAllocator->AllocateData<char>(cmd->length + 1); 80 memcpy(label, groupLabel, cmd->length + 1); 81 } 82 SetBindGroup(uint32_t groupIndex,BindGroupBase * group,uint32_t dynamicOffsetCount,const uint64_t * dynamicOffsets)83 void ProgrammablePassEncoder::SetBindGroup(uint32_t groupIndex, 84 BindGroupBase* group, 85 uint32_t dynamicOffsetCount, 86 const uint64_t* dynamicOffsets) { 87 const BindGroupLayoutBase* layout = group->GetLayout(); 88 89 if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands()) || 90 mTopLevelEncoder->ConsumedError(GetDevice()->ValidateObject(group))) { 91 return; 92 } 93 94 if (groupIndex >= kMaxBindGroups) { 95 mTopLevelEncoder->HandleError("Setting bind group over the max"); 96 return; 97 } 98 99 // Dynamic offsets count must match the number required by the layout perfectly. 100 if (layout->GetDynamicBufferCount() != dynamicOffsetCount) { 101 mTopLevelEncoder->HandleError("dynamicOffset count mismatch"); 102 } 103 104 for (uint32_t i = 0; i < dynamicOffsetCount; ++i) { 105 if (dynamicOffsets[i] % kMinDynamicBufferOffsetAlignment != 0) { 106 mTopLevelEncoder->HandleError("Dynamic Buffer Offset need to be aligned"); 107 return; 108 } 109 110 BufferBinding bufferBinding = group->GetBindingAsBufferBinding(i); 111 112 // During BindGroup creation, validation ensures binding offset + binding size <= buffer 113 // size. 114 DAWN_ASSERT(bufferBinding.buffer->GetSize() >= bufferBinding.size); 115 DAWN_ASSERT(bufferBinding.buffer->GetSize() - bufferBinding.size >= 116 bufferBinding.offset); 117 118 if (dynamicOffsets[i] > 119 bufferBinding.buffer->GetSize() - bufferBinding.offset - bufferBinding.size) { 120 mTopLevelEncoder->HandleError("dynamic offset out of bounds"); 121 return; 122 } 123 } 124 125 SetBindGroupCmd* cmd = mAllocator->Allocate<SetBindGroupCmd>(Command::SetBindGroup); 126 cmd->index = groupIndex; 127 cmd->group = group; 128 cmd->dynamicOffsetCount = dynamicOffsetCount; 129 if (dynamicOffsetCount > 0) { 130 uint64_t* offsets = mAllocator->AllocateData<uint64_t>(cmd->dynamicOffsetCount); 131 memcpy(offsets, dynamicOffsets, dynamicOffsetCount * sizeof(uint64_t)); 132 } 133 } 134 ValidateCanRecordCommands() const135 MaybeError ProgrammablePassEncoder::ValidateCanRecordCommands() const { 136 if (mAllocator == nullptr) { 137 return DAWN_VALIDATION_ERROR("Recording in an error or already ended pass encoder"); 138 } 139 140 return nullptr; 141 } 142 143 } // namespace dawn_native 144