dawn-cmake/src/dawn/native/ProgrammableEncoder.cpp
Brandon Jones 6cb055b6aa Retain descriptor labels for error objects
Since these objects are more likely to be included in error messages
it's important that we keep the labels that the developer has given
them.

Bug: dawn:1771
Change-Id: I78f4ccc23ce40d8eeceed8ca7dd563dff949b4fb
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/128420
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Brandon Jones <bajones@chromium.org>
2023-04-20 23:35:14 +00:00

201 lines
8.5 KiB
C++

// Copyright 2018 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn/native/ProgrammableEncoder.h"
#include <cstring>
#include "dawn/common/BitSetIterator.h"
#include "dawn/common/ityp_array.h"
#include "dawn/native/BindGroup.h"
#include "dawn/native/Buffer.h"
#include "dawn/native/CommandBuffer.h"
#include "dawn/native/Commands.h"
#include "dawn/native/Device.h"
#include "dawn/native/ObjectType_autogen.h"
#include "dawn/native/ValidationUtils_autogen.h"
namespace dawn::native {
ProgrammableEncoder::ProgrammableEncoder(DeviceBase* device,
const char* label,
EncodingContext* encodingContext)
: ApiObjectBase(device, label),
mEncodingContext(encodingContext),
mValidationEnabled(device->IsValidationEnabled()) {}
ProgrammableEncoder::ProgrammableEncoder(DeviceBase* device,
EncodingContext* encodingContext,
ErrorTag errorTag,
const char* label)
: ApiObjectBase(device, errorTag, label),
mEncodingContext(encodingContext),
mValidationEnabled(device->IsValidationEnabled()) {}
bool ProgrammableEncoder::IsValidationEnabled() const {
return mValidationEnabled;
}
MaybeError ProgrammableEncoder::ValidateProgrammableEncoderEnd() const {
DAWN_INVALID_IF(mDebugGroupStackSize != 0,
"PushDebugGroup called %u time(s) without a corresponding PopDebugGroup.",
mDebugGroupStackSize);
return {};
}
void ProgrammableEncoder::APIInsertDebugMarker(const char* groupLabel) {
mEncodingContext->TryEncode(
this,
[&](CommandAllocator* allocator) -> MaybeError {
InsertDebugMarkerCmd* cmd =
allocator->Allocate<InsertDebugMarkerCmd>(Command::InsertDebugMarker);
cmd->length = strlen(groupLabel);
char* label = allocator->AllocateData<char>(cmd->length + 1);
memcpy(label, groupLabel, cmd->length + 1);
return {};
},
"encoding %s.InsertDebugMarker(\"%s\").", this, groupLabel);
}
void ProgrammableEncoder::APIPopDebugGroup() {
mEncodingContext->TryEncode(
this,
[&](CommandAllocator* allocator) -> MaybeError {
if (IsValidationEnabled()) {
DAWN_INVALID_IF(mDebugGroupStackSize == 0,
"PopDebugGroup called when no debug groups are currently pushed.");
}
allocator->Allocate<PopDebugGroupCmd>(Command::PopDebugGroup);
mDebugGroupStackSize--;
mEncodingContext->PopDebugGroupLabel();
return {};
},
"encoding %s.PopDebugGroup().", this);
}
void ProgrammableEncoder::APIPushDebugGroup(const char* groupLabel) {
mEncodingContext->TryEncode(
this,
[&](CommandAllocator* allocator) -> MaybeError {
PushDebugGroupCmd* cmd =
allocator->Allocate<PushDebugGroupCmd>(Command::PushDebugGroup);
cmd->length = strlen(groupLabel);
char* label = allocator->AllocateData<char>(cmd->length + 1);
memcpy(label, groupLabel, cmd->length + 1);
mDebugGroupStackSize++;
mEncodingContext->PushDebugGroupLabel(groupLabel);
return {};
},
"encoding %s.PushDebugGroup(\"%s\").", this, groupLabel);
}
MaybeError ProgrammableEncoder::ValidateSetBindGroup(BindGroupIndex index,
BindGroupBase* group,
uint32_t dynamicOffsetCountIn,
const uint32_t* dynamicOffsetsIn) const {
DAWN_TRY(GetDevice()->ValidateObject(group));
DAWN_INVALID_IF(index >= kMaxBindGroupsTyped, "Bind group index (%u) exceeds the maximum (%u).",
static_cast<uint32_t>(index), kMaxBindGroups);
ityp::span<BindingIndex, const uint32_t> dynamicOffsets(dynamicOffsetsIn,
BindingIndex(dynamicOffsetCountIn));
// Dynamic offsets count must match the number required by the layout perfectly.
const BindGroupLayoutBase* layout = group->GetLayout();
DAWN_INVALID_IF(
layout->GetDynamicBufferCount() != dynamicOffsets.size(),
"The number of dynamic offsets (%u) does not match the number of dynamic buffers (%u) "
"in %s.",
static_cast<uint32_t>(dynamicOffsets.size()),
static_cast<uint32_t>(layout->GetDynamicBufferCount()), layout);
for (BindingIndex i{0}; i < dynamicOffsets.size(); ++i) {
const BindingInfo& bindingInfo = layout->GetBindingInfo(i);
// BGL creation sorts bindings such that the dynamic buffer bindings are first.
// ASSERT that this true.
ASSERT(bindingInfo.bindingType == BindingInfoType::Buffer);
ASSERT(bindingInfo.buffer.hasDynamicOffset);
uint64_t requiredAlignment;
switch (bindingInfo.buffer.type) {
case wgpu::BufferBindingType::Uniform:
requiredAlignment = GetDevice()->GetLimits().v1.minUniformBufferOffsetAlignment;
break;
case wgpu::BufferBindingType::Storage:
case wgpu::BufferBindingType::ReadOnlyStorage:
case kInternalStorageBufferBinding:
requiredAlignment = GetDevice()->GetLimits().v1.minStorageBufferOffsetAlignment;
break;
case wgpu::BufferBindingType::Undefined:
UNREACHABLE();
}
DAWN_INVALID_IF(!IsAligned(dynamicOffsets[i], requiredAlignment),
"Dynamic Offset[%u] (%u) is not %u byte aligned.", static_cast<uint32_t>(i),
dynamicOffsets[i], requiredAlignment);
BufferBinding bufferBinding = group->GetBindingAsBufferBinding(i);
// During BindGroup creation, validation ensures binding offset + binding size
// <= buffer size.
ASSERT(bufferBinding.buffer->GetSize() >= bufferBinding.size);
ASSERT(bufferBinding.buffer->GetSize() - bufferBinding.size >= bufferBinding.offset);
if ((dynamicOffsets[i] >
bufferBinding.buffer->GetSize() - bufferBinding.offset - bufferBinding.size)) {
DAWN_INVALID_IF(
(bufferBinding.buffer->GetSize() - bufferBinding.offset) == bufferBinding.size,
"Dynamic Offset[%u] (%u) is out of bounds of %s with a size of %u and a bound "
"range of (offset: %u, size: %u). The binding goes to the end of the buffer "
"even with a dynamic offset of 0. Did you forget to specify "
"the binding's size?",
static_cast<uint32_t>(i), dynamicOffsets[i], bufferBinding.buffer,
bufferBinding.buffer->GetSize(), bufferBinding.offset, bufferBinding.size);
return DAWN_VALIDATION_ERROR(
"Dynamic Offset[%u] (%u) is out of bounds of "
"%s with a size of %u and a bound range of (offset: %u, size: %u).",
static_cast<uint32_t>(i), dynamicOffsets[i], bufferBinding.buffer,
bufferBinding.buffer->GetSize(), bufferBinding.offset, bufferBinding.size);
}
}
return {};
}
void ProgrammableEncoder::RecordSetBindGroup(CommandAllocator* allocator,
BindGroupIndex index,
BindGroupBase* group,
uint32_t dynamicOffsetCount,
const uint32_t* dynamicOffsets) const {
SetBindGroupCmd* cmd = allocator->Allocate<SetBindGroupCmd>(Command::SetBindGroup);
cmd->index = index;
cmd->group = group;
cmd->dynamicOffsetCount = dynamicOffsetCount;
if (dynamicOffsetCount > 0) {
uint32_t* offsets = allocator->AllocateData<uint32_t>(cmd->dynamicOffsetCount);
memcpy(offsets, dynamicOffsets, dynamicOffsetCount * sizeof(uint32_t));
}
}
} // namespace dawn::native