Factor PassResourceUsageTracker to its own file
GPURenderBundleEncoder and GPUCommandEncoder will need to share code for tracking resource usages. Bug: dawn:154 Change-Id: I0286f71c4c0638f89be2754c8e9691e67e5db335 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/9700 Commit-Queue: Austin Eng <enga@chromium.org> Reviewed-by: Kai Ninomiya <kainino@chromium.org>
This commit is contained in:
parent
bb10a91876
commit
e9fabf5916
2
BUILD.gn
2
BUILD.gn
|
@ -154,6 +154,8 @@ source_set("libdawn_native_sources") {
|
|||
"src/dawn_native/ObjectBase.cpp",
|
||||
"src/dawn_native/ObjectBase.h",
|
||||
"src/dawn_native/PassResourceUsage.h",
|
||||
"src/dawn_native/PassResourceUsageTracker.cpp",
|
||||
"src/dawn_native/PassResourceUsageTracker.h",
|
||||
"src/dawn_native/PerStage.cpp",
|
||||
"src/dawn_native/PerStage.h",
|
||||
"src/dawn_native/Pipeline.cpp",
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "dawn_native/ComputePassEncoder.h"
|
||||
#include "dawn_native/Device.h"
|
||||
#include "dawn_native/ErrorData.h"
|
||||
#include "dawn_native/PassResourceUsageTracker.h"
|
||||
#include "dawn_native/RenderPassEncoder.h"
|
||||
#include "dawn_native/RenderPipeline.h"
|
||||
|
||||
|
@ -475,117 +476,6 @@ namespace dawn_native {
|
|||
return {};
|
||||
}
|
||||
|
||||
enum class PassType {
|
||||
Render,
|
||||
Compute,
|
||||
};
|
||||
|
||||
// Helper class to encapsulate the logic of tracking per-resource usage during the
|
||||
// validation of command buffer passes. It is used both to know if there are validation
|
||||
// errors, and to get a list of resources used per pass for backends that need the
|
||||
// information.
|
||||
class PassResourceUsageTracker {
|
||||
public:
|
||||
void BufferUsedAs(BufferBase* buffer, dawn::BufferUsageBit usage) {
|
||||
// std::map's operator[] will create the key and return 0 if the key didn't exist
|
||||
// before.
|
||||
dawn::BufferUsageBit& storedUsage = mBufferUsages[buffer];
|
||||
|
||||
if (usage == dawn::BufferUsageBit::Storage &&
|
||||
storedUsage & dawn::BufferUsageBit::Storage) {
|
||||
mStorageUsedMultipleTimes = true;
|
||||
}
|
||||
|
||||
storedUsage |= usage;
|
||||
}
|
||||
|
||||
void TextureUsedAs(TextureBase* texture, dawn::TextureUsageBit usage) {
|
||||
// std::map's operator[] will create the key and return 0 if the key didn't exist
|
||||
// before.
|
||||
dawn::TextureUsageBit& storedUsage = mTextureUsages[texture];
|
||||
|
||||
if (usage == dawn::TextureUsageBit::Storage &&
|
||||
storedUsage & dawn::TextureUsageBit::Storage) {
|
||||
mStorageUsedMultipleTimes = true;
|
||||
}
|
||||
|
||||
storedUsage |= usage;
|
||||
}
|
||||
|
||||
// Performs the per-pass usage validation checks
|
||||
MaybeError ValidateUsages(PassType pass) const {
|
||||
// Storage resources cannot be used twice in the same compute pass
|
||||
if (pass == PassType::Compute && mStorageUsedMultipleTimes) {
|
||||
return DAWN_VALIDATION_ERROR(
|
||||
"Storage resource used multiple times in compute pass");
|
||||
}
|
||||
|
||||
// Buffers can only be used as single-write or multiple read.
|
||||
for (auto& it : mBufferUsages) {
|
||||
BufferBase* buffer = it.first;
|
||||
dawn::BufferUsageBit usage = it.second;
|
||||
|
||||
if (usage & ~buffer->GetUsage()) {
|
||||
return DAWN_VALIDATION_ERROR("Buffer missing usage for the pass");
|
||||
}
|
||||
|
||||
bool readOnly = (usage & kReadOnlyBufferUsages) == usage;
|
||||
bool singleUse = dawn::HasZeroOrOneBits(usage);
|
||||
|
||||
if (!readOnly && !singleUse) {
|
||||
return DAWN_VALIDATION_ERROR(
|
||||
"Buffer used as writable usage and another usage in pass");
|
||||
}
|
||||
}
|
||||
|
||||
// Textures can only be used as single-write or multiple read.
|
||||
// TODO(cwallez@chromium.org): implement per-subresource tracking
|
||||
for (auto& it : mTextureUsages) {
|
||||
TextureBase* texture = it.first;
|
||||
dawn::TextureUsageBit usage = it.second;
|
||||
|
||||
if (usage & ~texture->GetUsage()) {
|
||||
return DAWN_VALIDATION_ERROR("Texture missing usage for the pass");
|
||||
}
|
||||
|
||||
// For textures the only read-only usage in a pass is Sampled, so checking the
|
||||
// usage constraint simplifies to checking a single usage bit is set.
|
||||
if (!dawn::HasZeroOrOneBits(it.second)) {
|
||||
return DAWN_VALIDATION_ERROR(
|
||||
"Texture used with more than one usage in pass");
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// Returns the per-pass usage for use by backends for APIs with explicit barriers.
|
||||
PassResourceUsage AcquireResourceUsage() {
|
||||
PassResourceUsage result;
|
||||
result.buffers.reserve(mBufferUsages.size());
|
||||
result.bufferUsages.reserve(mBufferUsages.size());
|
||||
result.textures.reserve(mTextureUsages.size());
|
||||
result.textureUsages.reserve(mTextureUsages.size());
|
||||
|
||||
for (auto& it : mBufferUsages) {
|
||||
result.buffers.push_back(it.first);
|
||||
result.bufferUsages.push_back(it.second);
|
||||
}
|
||||
|
||||
for (auto& it : mTextureUsages) {
|
||||
result.textures.push_back(it.first);
|
||||
result.textureUsages.push_back(it.second);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<BufferBase*, dawn::BufferUsageBit> mBufferUsages;
|
||||
std::map<TextureBase*, dawn::TextureUsageBit> mTextureUsages;
|
||||
bool mStorageUsedMultipleTimes = false;
|
||||
};
|
||||
|
||||
void TrackBindGroupResourceUsage(BindGroupBase* group, PassResourceUsageTracker* tracker) {
|
||||
const auto& layoutInfo = group->GetLayout()->GetBindingInfo();
|
||||
|
||||
|
@ -1003,7 +893,7 @@ namespace dawn_native {
|
|||
|
||||
DAWN_TRY(ValidateDebugGroups(mDebugGroupStackSize));
|
||||
|
||||
DAWN_TRY(usageTracker.ValidateUsages(PassType::Compute));
|
||||
DAWN_TRY(usageTracker.ValidateComputePassUsages());
|
||||
mResourceUsages.perPass.push_back(usageTracker.AcquireResourceUsage());
|
||||
return {};
|
||||
} break;
|
||||
|
@ -1092,7 +982,7 @@ namespace dawn_native {
|
|||
|
||||
DAWN_TRY(ValidateDebugGroups(mDebugGroupStackSize));
|
||||
|
||||
DAWN_TRY(usageTracker.ValidateUsages(PassType::Render));
|
||||
DAWN_TRY(usageTracker.ValidateRenderPassUsages());
|
||||
mResourceUsages.perPass.push_back(usageTracker.AcquireResourceUsage());
|
||||
return {};
|
||||
} break;
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
// Copyright 2019 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/PassResourceUsageTracker.h"
|
||||
|
||||
#include "dawn_native/Buffer.h"
|
||||
#include "dawn_native/Texture.h"
|
||||
|
||||
namespace dawn_native {
|
||||
|
||||
void PassResourceUsageTracker::BufferUsedAs(BufferBase* buffer, dawn::BufferUsageBit usage) {
|
||||
// std::map's operator[] will create the key and return 0 if the key didn't exist
|
||||
// before.
|
||||
dawn::BufferUsageBit& storedUsage = mBufferUsages[buffer];
|
||||
|
||||
if (usage == dawn::BufferUsageBit::Storage && storedUsage & dawn::BufferUsageBit::Storage) {
|
||||
mStorageUsedMultipleTimes = true;
|
||||
}
|
||||
|
||||
storedUsage |= usage;
|
||||
}
|
||||
|
||||
void PassResourceUsageTracker::TextureUsedAs(TextureBase* texture,
|
||||
dawn::TextureUsageBit usage) {
|
||||
// std::map's operator[] will create the key and return 0 if the key didn't exist
|
||||
// before.
|
||||
dawn::TextureUsageBit& storedUsage = mTextureUsages[texture];
|
||||
|
||||
if (usage == dawn::TextureUsageBit::Storage &&
|
||||
storedUsage & dawn::TextureUsageBit::Storage) {
|
||||
mStorageUsedMultipleTimes = true;
|
||||
}
|
||||
|
||||
storedUsage |= usage;
|
||||
}
|
||||
|
||||
MaybeError PassResourceUsageTracker::ValidateComputePassUsages() const {
|
||||
// Storage resources cannot be used twice in the same compute pass
|
||||
if (mStorageUsedMultipleTimes) {
|
||||
return DAWN_VALIDATION_ERROR("Storage resource used multiple times in compute pass");
|
||||
}
|
||||
return ValidateUsages();
|
||||
}
|
||||
|
||||
MaybeError PassResourceUsageTracker::ValidateRenderPassUsages() const {
|
||||
return ValidateUsages();
|
||||
}
|
||||
|
||||
// Performs the per-pass usage validation checks
|
||||
MaybeError PassResourceUsageTracker::ValidateUsages() const {
|
||||
// Buffers can only be used as single-write or multiple read.
|
||||
for (auto& it : mBufferUsages) {
|
||||
BufferBase* buffer = it.first;
|
||||
dawn::BufferUsageBit usage = it.second;
|
||||
|
||||
if (usage & ~buffer->GetUsage()) {
|
||||
return DAWN_VALIDATION_ERROR("Buffer missing usage for the pass");
|
||||
}
|
||||
|
||||
bool readOnly = (usage & kReadOnlyBufferUsages) == usage;
|
||||
bool singleUse = dawn::HasZeroOrOneBits(usage);
|
||||
|
||||
if (!readOnly && !singleUse) {
|
||||
return DAWN_VALIDATION_ERROR(
|
||||
"Buffer used as writable usage and another usage in pass");
|
||||
}
|
||||
}
|
||||
|
||||
// Textures can only be used as single-write or multiple read.
|
||||
// TODO(cwallez@chromium.org): implement per-subresource tracking
|
||||
for (auto& it : mTextureUsages) {
|
||||
TextureBase* texture = it.first;
|
||||
dawn::TextureUsageBit usage = it.second;
|
||||
|
||||
if (usage & ~texture->GetUsage()) {
|
||||
return DAWN_VALIDATION_ERROR("Texture missing usage for the pass");
|
||||
}
|
||||
|
||||
// For textures the only read-only usage in a pass is Sampled, so checking the
|
||||
// usage constraint simplifies to checking a single usage bit is set.
|
||||
if (!dawn::HasZeroOrOneBits(it.second)) {
|
||||
return DAWN_VALIDATION_ERROR("Texture used with more than one usage in pass");
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// Returns the per-pass usage for use by backends for APIs with explicit barriers.
|
||||
PassResourceUsage PassResourceUsageTracker::AcquireResourceUsage() {
|
||||
PassResourceUsage result;
|
||||
result.buffers.reserve(mBufferUsages.size());
|
||||
result.bufferUsages.reserve(mBufferUsages.size());
|
||||
result.textures.reserve(mTextureUsages.size());
|
||||
result.textureUsages.reserve(mTextureUsages.size());
|
||||
|
||||
for (auto& it : mBufferUsages) {
|
||||
result.buffers.push_back(it.first);
|
||||
result.bufferUsages.push_back(it.second);
|
||||
}
|
||||
|
||||
for (auto& it : mTextureUsages) {
|
||||
result.textures.push_back(it.first);
|
||||
result.textureUsages.push_back(it.second);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace dawn_native
|
|
@ -0,0 +1,56 @@
|
|||
// Copyright 2019 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.
|
||||
|
||||
#ifndef DAWNNATIVE_PASSRESOURCEUSAGETRACKER_H_
|
||||
#define DAWNNATIVE_PASSRESOURCEUSAGETRACKER_H_
|
||||
|
||||
#include "dawn_native/Error.h"
|
||||
#include "dawn_native/PassResourceUsage.h"
|
||||
|
||||
#include "dawn_native/dawn_platform.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace dawn_native {
|
||||
|
||||
class BufferBase;
|
||||
class TextureBase;
|
||||
|
||||
// Helper class to encapsulate the logic of tracking per-resource usage during the
|
||||
// validation of command buffer passes. It is used both to know if there are validation
|
||||
// errors, and to get a list of resources used per pass for backends that need the
|
||||
// information.
|
||||
class PassResourceUsageTracker {
|
||||
public:
|
||||
void BufferUsedAs(BufferBase* buffer, dawn::BufferUsageBit usage);
|
||||
void TextureUsedAs(TextureBase* texture, dawn::TextureUsageBit usage);
|
||||
|
||||
MaybeError ValidateComputePassUsages() const;
|
||||
MaybeError ValidateRenderPassUsages() const;
|
||||
|
||||
// Returns the per-pass usage for use by backends for APIs with explicit barriers.
|
||||
PassResourceUsage AcquireResourceUsage();
|
||||
|
||||
private:
|
||||
// Performs the per-pass usage validation checks
|
||||
MaybeError ValidateUsages() const;
|
||||
|
||||
std::map<BufferBase*, dawn::BufferUsageBit> mBufferUsages;
|
||||
std::map<TextureBase*, dawn::TextureUsageBit> mTextureUsages;
|
||||
bool mStorageUsedMultipleTimes = false;
|
||||
};
|
||||
|
||||
} // namespace dawn_native
|
||||
|
||||
#endif // DAWNNATIVE_PASSRESOURCEUSAGETRACKER_H_
|
Loading…
Reference in New Issue