• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/ProgrammableEncoder.h"
16 
17 #include "common/BitSetIterator.h"
18 #include "common/ityp_array.h"
19 #include "dawn_native/BindGroup.h"
20 #include "dawn_native/Buffer.h"
21 #include "dawn_native/CommandBuffer.h"
22 #include "dawn_native/Commands.h"
23 #include "dawn_native/Device.h"
24 #include "dawn_native/ObjectType_autogen.h"
25 #include "dawn_native/ValidationUtils_autogen.h"
26 
27 #include <cstring>
28 
29 namespace dawn_native {
30 
ProgrammableEncoder(DeviceBase * device,const char * label,EncodingContext * encodingContext)31     ProgrammableEncoder::ProgrammableEncoder(DeviceBase* device,
32                                              const char* label,
33                                              EncodingContext* encodingContext)
34         : ApiObjectBase(device, label),
35           mEncodingContext(encodingContext),
36           mValidationEnabled(device->IsValidationEnabled()) {
37     }
38 
ProgrammableEncoder(DeviceBase * device,EncodingContext * encodingContext,ErrorTag errorTag)39     ProgrammableEncoder::ProgrammableEncoder(DeviceBase* device,
40                                              EncodingContext* encodingContext,
41                                              ErrorTag errorTag)
42         : ApiObjectBase(device, errorTag),
43           mEncodingContext(encodingContext),
44           mValidationEnabled(device->IsValidationEnabled()) {
45     }
46 
IsValidationEnabled() const47     bool ProgrammableEncoder::IsValidationEnabled() const {
48         return mValidationEnabled;
49     }
50 
ValidateProgrammableEncoderEnd() const51     MaybeError ProgrammableEncoder::ValidateProgrammableEncoderEnd() const {
52         DAWN_INVALID_IF(mDebugGroupStackSize != 0,
53                         "PushDebugGroup called %u time(s) without a corresponding PopDebugGroup.",
54                         mDebugGroupStackSize);
55         return {};
56     }
57 
APIInsertDebugMarker(const char * groupLabel)58     void ProgrammableEncoder::APIInsertDebugMarker(const char* groupLabel) {
59         mEncodingContext->TryEncode(
60             this,
61             [&](CommandAllocator* allocator) -> MaybeError {
62                 InsertDebugMarkerCmd* cmd =
63                     allocator->Allocate<InsertDebugMarkerCmd>(Command::InsertDebugMarker);
64                 cmd->length = strlen(groupLabel);
65 
66                 char* label = allocator->AllocateData<char>(cmd->length + 1);
67                 memcpy(label, groupLabel, cmd->length + 1);
68 
69                 return {};
70             },
71             "encoding %s.InsertDebugMarker(\"%s\").", this, groupLabel);
72     }
73 
APIPopDebugGroup()74     void ProgrammableEncoder::APIPopDebugGroup() {
75         mEncodingContext->TryEncode(
76             this,
77             [&](CommandAllocator* allocator) -> MaybeError {
78                 if (IsValidationEnabled()) {
79                     DAWN_INVALID_IF(
80                         mDebugGroupStackSize == 0,
81                         "PopDebugGroup called when no debug groups are currently pushed.");
82                 }
83                 allocator->Allocate<PopDebugGroupCmd>(Command::PopDebugGroup);
84                 mDebugGroupStackSize--;
85                 mEncodingContext->PopDebugGroupLabel();
86 
87                 return {};
88             },
89             "encoding %s.PopDebugGroup().", this);
90     }
91 
APIPushDebugGroup(const char * groupLabel)92     void ProgrammableEncoder::APIPushDebugGroup(const char* groupLabel) {
93         mEncodingContext->TryEncode(
94             this,
95             [&](CommandAllocator* allocator) -> MaybeError {
96                 PushDebugGroupCmd* cmd =
97                     allocator->Allocate<PushDebugGroupCmd>(Command::PushDebugGroup);
98                 cmd->length = strlen(groupLabel);
99 
100                 char* label = allocator->AllocateData<char>(cmd->length + 1);
101                 memcpy(label, groupLabel, cmd->length + 1);
102 
103                 mDebugGroupStackSize++;
104                 mEncodingContext->PushDebugGroupLabel(groupLabel);
105 
106                 return {};
107             },
108             "encoding %s.PushDebugGroup(\"%s\").", this, groupLabel);
109     }
110 
ValidateSetBindGroup(BindGroupIndex index,BindGroupBase * group,uint32_t dynamicOffsetCountIn,const uint32_t * dynamicOffsetsIn) const111     MaybeError ProgrammableEncoder::ValidateSetBindGroup(BindGroupIndex index,
112                                                          BindGroupBase* group,
113                                                          uint32_t dynamicOffsetCountIn,
114                                                          const uint32_t* dynamicOffsetsIn) const {
115         DAWN_TRY(GetDevice()->ValidateObject(group));
116 
117         DAWN_INVALID_IF(index >= kMaxBindGroupsTyped,
118                         "Bind group index (%u) exceeds the maximum (%u).",
119                         static_cast<uint32_t>(index), kMaxBindGroups);
120 
121         ityp::span<BindingIndex, const uint32_t> dynamicOffsets(dynamicOffsetsIn,
122                                                                 BindingIndex(dynamicOffsetCountIn));
123 
124         // Dynamic offsets count must match the number required by the layout perfectly.
125         const BindGroupLayoutBase* layout = group->GetLayout();
126         DAWN_INVALID_IF(
127             layout->GetDynamicBufferCount() != dynamicOffsets.size(),
128             "The number of dynamic offsets (%u) does not match the number of dynamic buffers (%u) "
129             "in %s.",
130             static_cast<uint32_t>(dynamicOffsets.size()),
131             static_cast<uint32_t>(layout->GetDynamicBufferCount()), layout);
132 
133         for (BindingIndex i{0}; i < dynamicOffsets.size(); ++i) {
134             const BindingInfo& bindingInfo = layout->GetBindingInfo(i);
135 
136             // BGL creation sorts bindings such that the dynamic buffer bindings are first.
137             // ASSERT that this true.
138             ASSERT(bindingInfo.bindingType == BindingInfoType::Buffer);
139             ASSERT(bindingInfo.buffer.hasDynamicOffset);
140 
141             uint64_t requiredAlignment;
142             switch (bindingInfo.buffer.type) {
143                 case wgpu::BufferBindingType::Uniform:
144                     requiredAlignment = GetDevice()->GetLimits().v1.minUniformBufferOffsetAlignment;
145                     break;
146                 case wgpu::BufferBindingType::Storage:
147                 case wgpu::BufferBindingType::ReadOnlyStorage:
148                 case kInternalStorageBufferBinding:
149                     requiredAlignment = GetDevice()->GetLimits().v1.minStorageBufferOffsetAlignment;
150                     break;
151                 case wgpu::BufferBindingType::Undefined:
152                     UNREACHABLE();
153             }
154 
155             DAWN_INVALID_IF(!IsAligned(dynamicOffsets[i], requiredAlignment),
156                             "Dynamic Offset[%u] (%u) is not %u byte aligned.",
157                             static_cast<uint32_t>(i), dynamicOffsets[i], requiredAlignment);
158 
159             BufferBinding bufferBinding = group->GetBindingAsBufferBinding(i);
160 
161             // During BindGroup creation, validation ensures binding offset + binding size
162             // <= buffer size.
163             ASSERT(bufferBinding.buffer->GetSize() >= bufferBinding.size);
164             ASSERT(bufferBinding.buffer->GetSize() - bufferBinding.size >= bufferBinding.offset);
165 
166             if ((dynamicOffsets[i] >
167                  bufferBinding.buffer->GetSize() - bufferBinding.offset - bufferBinding.size)) {
168                 DAWN_INVALID_IF(
169                     (bufferBinding.buffer->GetSize() - bufferBinding.offset) == bufferBinding.size,
170                     "Dynamic Offset[%u] (%u) is out of bounds of %s with a size of %u and a bound "
171                     "range of (offset: %u, size: %u). The binding goes to the end of the buffer "
172                     "even with a dynamic offset of 0. Did you forget to specify "
173                     "the binding's size?",
174                     static_cast<uint32_t>(i), dynamicOffsets[i], bufferBinding.buffer,
175                     bufferBinding.buffer->GetSize(), bufferBinding.offset, bufferBinding.size);
176 
177                 return DAWN_FORMAT_VALIDATION_ERROR(
178                     "Dynamic Offset[%u] (%u) is out of bounds of "
179                     "%s with a size of %u and a bound range of (offset: %u, size: %u).",
180                     static_cast<uint32_t>(i), dynamicOffsets[i], bufferBinding.buffer,
181                     bufferBinding.buffer->GetSize(), bufferBinding.offset, bufferBinding.size);
182             }
183         }
184 
185         return {};
186     }
187 
RecordSetBindGroup(CommandAllocator * allocator,BindGroupIndex index,BindGroupBase * group,uint32_t dynamicOffsetCount,const uint32_t * dynamicOffsets) const188     void ProgrammableEncoder::RecordSetBindGroup(CommandAllocator* allocator,
189                                                  BindGroupIndex index,
190                                                  BindGroupBase* group,
191                                                  uint32_t dynamicOffsetCount,
192                                                  const uint32_t* dynamicOffsets) const {
193         SetBindGroupCmd* cmd = allocator->Allocate<SetBindGroupCmd>(Command::SetBindGroup);
194         cmd->index = index;
195         cmd->group = group;
196         cmd->dynamicOffsetCount = dynamicOffsetCount;
197         if (dynamicOffsetCount > 0) {
198             uint32_t* offsets = allocator->AllocateData<uint32_t>(cmd->dynamicOffsetCount);
199             memcpy(offsets, dynamicOffsets, dynamicOffsetCount * sizeof(uint32_t));
200         }
201     }
202 
203 }  // namespace dawn_native
204