// 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/ProgrammablePassEncoder.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/ValidationUtils_autogen.h" #include namespace dawn_native { ProgrammablePassEncoder::ProgrammablePassEncoder(DeviceBase* device, CommandEncoderBase* topLevelEncoder, CommandAllocator* allocator) : ObjectBase(device), mTopLevelEncoder(topLevelEncoder), mAllocator(allocator) { DAWN_ASSERT(allocator != nullptr); } ProgrammablePassEncoder::ProgrammablePassEncoder(DeviceBase* device, CommandEncoderBase* topLevelEncoder, ErrorTag errorTag) : ObjectBase(device, errorTag), mTopLevelEncoder(topLevelEncoder), mAllocator(nullptr) { } void ProgrammablePassEncoder::EndPass() { if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) { return; } mTopLevelEncoder->PassEnded(); mAllocator = nullptr; } void ProgrammablePassEncoder::InsertDebugMarker(const char* groupLabel) { if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) { return; } InsertDebugMarkerCmd* cmd = mAllocator->Allocate(Command::InsertDebugMarker); cmd->length = strlen(groupLabel); char* label = mAllocator->AllocateData(cmd->length + 1); memcpy(label, groupLabel, cmd->length + 1); } void ProgrammablePassEncoder::PopDebugGroup() { if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) { return; } mAllocator->Allocate(Command::PopDebugGroup); } void ProgrammablePassEncoder::PushDebugGroup(const char* groupLabel) { if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) { return; } PushDebugGroupCmd* cmd = mAllocator->Allocate(Command::PushDebugGroup); cmd->length = strlen(groupLabel); char* label = mAllocator->AllocateData(cmd->length + 1); memcpy(label, groupLabel, cmd->length + 1); } void ProgrammablePassEncoder::SetBindGroup(uint32_t groupIndex, BindGroupBase* group, uint32_t dynamicOffsetCount, const uint64_t* dynamicOffsets) { const BindGroupLayoutBase* layout = group->GetLayout(); if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands()) || mTopLevelEncoder->ConsumedError(GetDevice()->ValidateObject(group))) { return; } if (groupIndex >= kMaxBindGroups) { mTopLevelEncoder->HandleError("Setting bind group over the max"); return; } // Dynamic offsets count must match the number required by the layout perfectly. if (layout->GetDynamicBufferCount() != dynamicOffsetCount) { mTopLevelEncoder->HandleError("dynamicOffset count mismatch"); } for (uint32_t i = 0; i < dynamicOffsetCount; ++i) { if (dynamicOffsets[i] % kMinDynamicBufferOffsetAlignment != 0) { mTopLevelEncoder->HandleError("Dynamic Buffer Offset need to be aligned"); return; } BufferBinding bufferBinding = group->GetBindingAsBufferBinding(i); // During BindGroup creation, validation ensures binding offset + binding size <= buffer // size. DAWN_ASSERT(bufferBinding.buffer->GetSize() >= bufferBinding.size); DAWN_ASSERT(bufferBinding.buffer->GetSize() - bufferBinding.size >= bufferBinding.offset); if (dynamicOffsets[i] > bufferBinding.buffer->GetSize() - bufferBinding.offset - bufferBinding.size) { mTopLevelEncoder->HandleError("dynamic offset out of bounds"); return; } } SetBindGroupCmd* cmd = mAllocator->Allocate(Command::SetBindGroup); cmd->index = groupIndex; cmd->group = group; cmd->dynamicOffsetCount = dynamicOffsetCount; if (dynamicOffsetCount > 0) { uint64_t* offsets = mAllocator->AllocateData(cmd->dynamicOffsetCount); memcpy(offsets, dynamicOffsets, dynamicOffsetCount * sizeof(uint64_t)); } } MaybeError ProgrammablePassEncoder::ValidateCanRecordCommands() const { if (mAllocator == nullptr) { return DAWN_VALIDATION_ERROR("Recording in an error or already ended pass encoder"); } return nullptr; } } // namespace dawn_native