dawn-cmake/src/dawn_native/CommandBuffer.cpp
Austin Eng 6abf1a1adb Remove deferred BufferLocation updates for drawIndexedIndirect
Instead of using BufferLocation as another layer of indirection,
the indirectBuffer can be set directly on the indirect command.
This makes the indirect validation a bit simpler, but introduces
additional lifetime dependencies in that the indirect draw validation
MUST be encoded while the DrawIndexedIndirectCmds it references
are still valid.

Bug: dawn:809
Change-Id: I1ef084622d8737ad5ec1b0247bf9062712e35008
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/67241
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
2021-11-02 18:23:49 +00:00

239 lines
9.8 KiB
C++

// Copyright 2017 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/CommandBuffer.h"
#include "common/BitSetIterator.h"
#include "dawn_native/Buffer.h"
#include "dawn_native/CommandEncoder.h"
#include "dawn_native/CommandValidation.h"
#include "dawn_native/Commands.h"
#include "dawn_native/Format.h"
#include "dawn_native/ObjectType_autogen.h"
#include "dawn_native/Texture.h"
namespace dawn_native {
CommandBufferBase::CommandBufferBase(CommandEncoder* encoder, const CommandBufferDescriptor*)
: ApiObjectBase(encoder->GetDevice(), kLabelNotImplemented),
mCommands(encoder->AcquireCommands()),
mResourceUsages(encoder->AcquireResourceUsages()) {
}
CommandBufferBase::CommandBufferBase(DeviceBase* device, ObjectBase::ErrorTag tag)
: ApiObjectBase(device, tag) {
}
CommandBufferBase::~CommandBufferBase() {
Destroy();
}
// static
CommandBufferBase* CommandBufferBase::MakeError(DeviceBase* device) {
return new CommandBufferBase(device, ObjectBase::kError);
}
ObjectType CommandBufferBase::GetType() const {
return ObjectType::CommandBuffer;
}
MaybeError CommandBufferBase::ValidateCanUseInSubmitNow() const {
ASSERT(!IsError());
DAWN_INVALID_IF(mDestroyed, "%s cannot be submitted more than once.", this);
return {};
}
void CommandBufferBase::Destroy() {
FreeCommands(&mCommands);
mResourceUsages = {};
mDestroyed = true;
}
const CommandBufferResourceUsage& CommandBufferBase::GetResourceUsages() const {
return mResourceUsages;
}
CommandIterator* CommandBufferBase::GetCommandIteratorForTesting() {
return &mCommands;
}
bool IsCompleteSubresourceCopiedTo(const TextureBase* texture,
const Extent3D copySize,
const uint32_t mipLevel) {
Extent3D extent = texture->GetMipLevelPhysicalSize(mipLevel);
ASSERT(texture->GetDimension() != wgpu::TextureDimension::e1D);
switch (texture->GetDimension()) {
case wgpu::TextureDimension::e2D:
return extent.width == copySize.width && extent.height == copySize.height;
case wgpu::TextureDimension::e3D:
return extent.width == copySize.width && extent.height == copySize.height &&
extent.depthOrArrayLayers == copySize.depthOrArrayLayers;
default:
UNREACHABLE();
}
}
SubresourceRange GetSubresourcesAffectedByCopy(const TextureCopy& copy,
const Extent3D& copySize) {
switch (copy.texture->GetDimension()) {
case wgpu::TextureDimension::e2D:
return {
copy.aspect, {copy.origin.z, copySize.depthOrArrayLayers}, {copy.mipLevel, 1}};
case wgpu::TextureDimension::e3D:
return {copy.aspect, {0, 1}, {copy.mipLevel, 1}};
default:
UNREACHABLE();
}
}
void LazyClearRenderPassAttachments(BeginRenderPassCmd* renderPass) {
for (ColorAttachmentIndex i :
IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) {
auto& attachmentInfo = renderPass->colorAttachments[i];
TextureViewBase* view = attachmentInfo.view.Get();
bool hasResolveTarget = attachmentInfo.resolveTarget != nullptr;
ASSERT(view->GetLayerCount() == 1);
ASSERT(view->GetLevelCount() == 1);
SubresourceRange range = view->GetSubresourceRange();
// If the loadOp is Load, but the subresource is not initialized, use Clear instead.
if (attachmentInfo.loadOp == wgpu::LoadOp::Load &&
!view->GetTexture()->IsSubresourceContentInitialized(range)) {
attachmentInfo.loadOp = wgpu::LoadOp::Clear;
attachmentInfo.clearColor = {0.f, 0.f, 0.f, 0.f};
}
if (hasResolveTarget) {
// We need to set the resolve target to initialized so that it does not get
// cleared later in the pipeline. The texture will be resolved from the
// source color attachment, which will be correctly initialized.
TextureViewBase* resolveView = attachmentInfo.resolveTarget.Get();
ASSERT(resolveView->GetLayerCount() == 1);
ASSERT(resolveView->GetLevelCount() == 1);
resolveView->GetTexture()->SetIsSubresourceContentInitialized(
true, resolveView->GetSubresourceRange());
}
switch (attachmentInfo.storeOp) {
case wgpu::StoreOp::Store:
view->GetTexture()->SetIsSubresourceContentInitialized(true, range);
break;
case wgpu::StoreOp::Discard:
view->GetTexture()->SetIsSubresourceContentInitialized(false, range);
break;
}
}
if (renderPass->attachmentState->HasDepthStencilAttachment()) {
auto& attachmentInfo = renderPass->depthStencilAttachment;
TextureViewBase* view = attachmentInfo.view.Get();
ASSERT(view->GetLayerCount() == 1);
ASSERT(view->GetLevelCount() == 1);
SubresourceRange range = view->GetSubresourceRange();
SubresourceRange depthRange = range;
depthRange.aspects = range.aspects & Aspect::Depth;
SubresourceRange stencilRange = range;
stencilRange.aspects = range.aspects & Aspect::Stencil;
// If the depth stencil texture has not been initialized, we want to use loadop
// clear to init the contents to 0's
if (!view->GetTexture()->IsSubresourceContentInitialized(depthRange) &&
attachmentInfo.depthLoadOp == wgpu::LoadOp::Load) {
attachmentInfo.clearDepth = 0.0f;
attachmentInfo.depthLoadOp = wgpu::LoadOp::Clear;
}
if (!view->GetTexture()->IsSubresourceContentInitialized(stencilRange) &&
attachmentInfo.stencilLoadOp == wgpu::LoadOp::Load) {
attachmentInfo.clearStencil = 0u;
attachmentInfo.stencilLoadOp = wgpu::LoadOp::Clear;
}
view->GetTexture()->SetIsSubresourceContentInitialized(
attachmentInfo.depthStoreOp == wgpu::StoreOp::Store, depthRange);
view->GetTexture()->SetIsSubresourceContentInitialized(
attachmentInfo.stencilStoreOp == wgpu::StoreOp::Store, stencilRange);
}
}
bool IsFullBufferOverwrittenInTextureToBufferCopy(const CopyTextureToBufferCmd* copy) {
ASSERT(copy != nullptr);
if (copy->destination.offset > 0) {
// The copy doesn't touch the start of the buffer.
return false;
}
const TextureBase* texture = copy->source.texture.Get();
const TexelBlockInfo& blockInfo =
texture->GetFormat().GetAspectInfo(copy->source.aspect).block;
const uint64_t widthInBlocks = copy->copySize.width / blockInfo.width;
const uint64_t heightInBlocks = copy->copySize.height / blockInfo.height;
const bool multiSlice = copy->copySize.depthOrArrayLayers > 1;
const bool multiRow = multiSlice || heightInBlocks > 1;
if (multiSlice && copy->destination.rowsPerImage > heightInBlocks) {
// There are gaps between slices that aren't overwritten
return false;
}
const uint64_t copyTextureDataSizePerRow = widthInBlocks * blockInfo.byteSize;
if (multiRow && copy->destination.bytesPerRow > copyTextureDataSizePerRow) {
// There are gaps between rows that aren't overwritten
return false;
}
// After the above checks, we're sure the copy has no gaps.
// Now, compute the total number of bytes written.
const uint64_t writtenBytes =
ComputeRequiredBytesInCopy(blockInfo, copy->copySize, copy->destination.bytesPerRow,
copy->destination.rowsPerImage)
.AcquireSuccess();
if (!copy->destination.buffer->IsFullBufferRange(copy->destination.offset, writtenBytes)) {
// The written bytes don't cover the whole buffer.
return false;
}
return true;
}
std::array<float, 4> ConvertToFloatColor(dawn_native::Color color) {
const std::array<float, 4> outputValue = {
static_cast<float>(color.r), static_cast<float>(color.g), static_cast<float>(color.b),
static_cast<float>(color.a)};
return outputValue;
}
std::array<int32_t, 4> ConvertToSignedIntegerColor(dawn_native::Color color) {
const std::array<int32_t, 4> outputValue = {
static_cast<int32_t>(color.r), static_cast<int32_t>(color.g),
static_cast<int32_t>(color.b), static_cast<int32_t>(color.a)};
return outputValue;
}
std::array<uint32_t, 4> ConvertToUnsignedIntegerColor(dawn_native::Color color) {
const std::array<uint32_t, 4> outputValue = {
static_cast<uint32_t>(color.r), static_cast<uint32_t>(color.g),
static_cast<uint32_t>(color.b), static_cast<uint32_t>(color.a)};
return outputValue;
}
} // namespace dawn_native