mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-12-20 18:29:23 +00:00
Properly implement per-dispatch synchronization scopes.
Below are the list of all the individual changes, which are a good order in which to review this CL. Core changes: - Change the tracking in the frontend to produce a synchronization scope per dispatch instead of per compute pass. Some bindgroups might not be part of any synchronization scopes so we also track all the referenced resources on the side so they can be checked during Queue::Submit validation. - Fix clearing in the GL and Metal backends to use the per-dispatch synchronization scopes. - Fix the Vulkan backend to use the per dispatch synchronization scopes to produce the correct pipeline barriers. This allows the removal of previous logic that was subtly incorrect for Indirect buffer. This allows the merging of the Compute and Render DescriptorSetTracker into a single small helper class. - D3D12 changes are similar to Vulkan, but the simplification is just a the suppression of a branch with a lot of code in BindGroupStateTracker. Test changes: - Fixup all the ResourceUsageTracking tests to follow the WebGPU spec for synchronization scopes (fixing a lot of TODOs). - Add additional tests checking that Indirect buffers are not allowed to be used as a writeable storage in the same synchronization scope. - Add tests for Queue::Submit validation correctly taking into account resources that are bound but unused in compute passes. - Add an end2end test for using a buffer as Indirect and Storage at the same time in a DispatchIndirect, which would previously produce incorrect barriers in the Vulkan and D3D12 backends. Other small changes (that I was to lazy to put in a different CL): - Add the utils::MakePipelineLayout helper function. - Fix Indirect not being in the list of readonly buffer usages (caught by a test added in this CL). Bug: dawn:632 Change-Id: I77263c3535a4ba995faccbf26255da9a2f6ed3b5 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/49887 Commit-Queue: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Stephen White <senorblanco@chromium.org>
This commit is contained in:
committed by
Commit Bot service account
parent
d0ebcbac7a
commit
76732abfe5
@@ -34,7 +34,8 @@ namespace dawn_native {
|
||||
|
||||
static constexpr wgpu::BufferUsage kReadOnlyBufferUsages =
|
||||
wgpu::BufferUsage::MapRead | wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::Index |
|
||||
wgpu::BufferUsage::Vertex | wgpu::BufferUsage::Uniform | kReadOnlyStorageBuffer;
|
||||
wgpu::BufferUsage::Vertex | wgpu::BufferUsage::Uniform | kReadOnlyStorageBuffer |
|
||||
wgpu::BufferUsage::Indirect;
|
||||
|
||||
class BufferBase : public ObjectBase {
|
||||
enum class BufferState {
|
||||
|
||||
@@ -227,4 +227,12 @@ namespace dawn_native {
|
||||
mAspects &= ~kLazyAspects;
|
||||
}
|
||||
|
||||
BindGroupBase* CommandBufferStateTracker::GetBindGroup(BindGroupIndex index) const {
|
||||
return mBindgroups[index];
|
||||
}
|
||||
|
||||
PipelineLayoutBase* CommandBufferStateTracker::GetPipelineLayout() const {
|
||||
return mLastPipelineLayout;
|
||||
}
|
||||
|
||||
} // namespace dawn_native
|
||||
|
||||
@@ -50,6 +50,8 @@ namespace dawn_native {
|
||||
wgpu::IndexFormat GetIndexFormat() {
|
||||
return mIndexFormat;
|
||||
}
|
||||
BindGroupBase* GetBindGroup(BindGroupIndex index) const;
|
||||
PipelineLayoutBase* GetPipelineLayout() const;
|
||||
|
||||
private:
|
||||
MaybeError ValidateOperation(ValidationAspects requiredAspects);
|
||||
|
||||
@@ -949,8 +949,12 @@ namespace dawn_native {
|
||||
for (const RenderPassResourceUsage& passUsage : mEncodingContext.GetRenderPassUsages()) {
|
||||
DAWN_TRY(ValidateSyncScopeResourceUsage(passUsage));
|
||||
}
|
||||
// TODO(dawn:632): The synchronization scopes of compute passes should be validated here
|
||||
// once they are tracked per-dispatch.
|
||||
|
||||
for (const ComputePassResourceUsage& passUsage : mEncodingContext.GetComputePassUsages()) {
|
||||
for (const SyncScopeResourceUsage& scope : passUsage.dispatchUsages) {
|
||||
DAWN_TRY(ValidateSyncScopeResourceUsage(scope));
|
||||
}
|
||||
}
|
||||
|
||||
if (mDebugGroupStackSize != 0) {
|
||||
return DAWN_VALIDATION_ERROR("Each Push must be balanced by a corresponding Pop.");
|
||||
|
||||
@@ -37,7 +37,8 @@ namespace dawn_native {
|
||||
|
||||
if (!readOnly && !singleUse) {
|
||||
return DAWN_VALIDATION_ERROR(
|
||||
"Buffer used as writable usage and another usage in pass");
|
||||
"Buffer used as writable usage and another usage in the same synchronization "
|
||||
"scope");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +51,8 @@ namespace dawn_native {
|
||||
bool singleUse = wgpu::HasZeroOrOneBits(usage);
|
||||
if (!readOnly && !singleUse && !error.IsError()) {
|
||||
error = DAWN_VALIDATION_ERROR(
|
||||
"Texture used as writable usage and another usage in render pass");
|
||||
"Texture used as writable usage and another usage in the same "
|
||||
"synchronization scope");
|
||||
}
|
||||
});
|
||||
DAWN_TRY(std::move(error));
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "dawn_native/Commands.h"
|
||||
#include "dawn_native/ComputePipeline.h"
|
||||
#include "dawn_native/Device.h"
|
||||
#include "dawn_native/PassResourceUsageTracker.h"
|
||||
#include "dawn_native/QuerySet.h"
|
||||
|
||||
namespace dawn_native {
|
||||
@@ -64,6 +65,9 @@ namespace dawn_native {
|
||||
DAWN_TRY(mCommandBufferState.ValidateCanDispatch());
|
||||
}
|
||||
|
||||
// Record the synchronization scope for Dispatch, which is just the current bindgroups.
|
||||
AddDispatchSyncScope();
|
||||
|
||||
DispatchCmd* dispatch = allocator->Allocate<DispatchCmd>(Command::Dispatch);
|
||||
dispatch->x = x;
|
||||
dispatch->y = y;
|
||||
@@ -101,13 +105,18 @@ namespace dawn_native {
|
||||
}
|
||||
}
|
||||
|
||||
// Record the synchronization scope for Dispatch, both the bindgroups and the indirect
|
||||
// buffer.
|
||||
SyncScopeUsageTracker scope;
|
||||
scope.BufferUsedAs(indirectBuffer, wgpu::BufferUsage::Indirect);
|
||||
mUsageTracker.AddReferencedBuffer(indirectBuffer);
|
||||
AddDispatchSyncScope(std::move(scope));
|
||||
|
||||
DispatchIndirectCmd* dispatch =
|
||||
allocator->Allocate<DispatchIndirectCmd>(Command::DispatchIndirect);
|
||||
dispatch->indirectBuffer = indirectBuffer;
|
||||
dispatch->indirectOffset = indirectOffset;
|
||||
|
||||
mUsageTracker.BufferUsedAs(indirectBuffer, wgpu::BufferUsage::Indirect);
|
||||
|
||||
return {};
|
||||
});
|
||||
}
|
||||
@@ -140,13 +149,11 @@ namespace dawn_native {
|
||||
ValidateSetBindGroup(groupIndex, group, dynamicOffsetCount, dynamicOffsets));
|
||||
}
|
||||
|
||||
mUsageTracker.AddResourcesReferencedByBindGroup(group);
|
||||
|
||||
RecordSetBindGroup(allocator, groupIndex, group, dynamicOffsetCount, dynamicOffsets);
|
||||
mCommandBufferState.SetBindGroup(groupIndex, group);
|
||||
|
||||
// TODO(dawn:632): This doesn't match the WebGPU specification. Instead the
|
||||
// synchronization scopes should be created on Dispatch().
|
||||
mUsageTracker.AddBindGroup(group);
|
||||
|
||||
return {};
|
||||
});
|
||||
}
|
||||
@@ -169,4 +176,12 @@ namespace dawn_native {
|
||||
});
|
||||
}
|
||||
|
||||
void ComputePassEncoder::AddDispatchSyncScope(SyncScopeUsageTracker scope) {
|
||||
PipelineLayoutBase* layout = mCommandBufferState.GetPipelineLayout();
|
||||
for (BindGroupIndex i : IterateBitSet(layout->GetBindGroupLayoutsMask())) {
|
||||
scope.AddBindGroup(mCommandBufferState.GetBindGroup(i));
|
||||
}
|
||||
mUsageTracker.AddDispatch(scope.AcquireSyncScopeUsage());
|
||||
}
|
||||
|
||||
} // namespace dawn_native
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
namespace dawn_native {
|
||||
|
||||
class SyncScopeUsageTracker;
|
||||
|
||||
class ComputePassEncoder final : public ProgrammablePassEncoder {
|
||||
public:
|
||||
ComputePassEncoder(DeviceBase* device,
|
||||
@@ -53,6 +55,10 @@ namespace dawn_native {
|
||||
|
||||
private:
|
||||
CommandBufferStateTracker mCommandBufferState;
|
||||
|
||||
// Adds the bindgroups used for the current dispatch to the SyncScopeResourceUsage and
|
||||
// records it in mUsageTracker.
|
||||
void AddDispatchSyncScope(SyncScopeUsageTracker scope = {});
|
||||
ComputePassResourceUsageTracker mUsageTracker;
|
||||
|
||||
// For render and compute passes, the encoding context is borrowed from the command encoder.
|
||||
|
||||
@@ -48,12 +48,23 @@ namespace dawn_native {
|
||||
|
||||
// Contains all the resource usage data for a compute pass.
|
||||
//
|
||||
// TODO(dawn:632) Not now, but in the future, compute passes will contain a list of
|
||||
// SyncScopeResourceUsage, one per Dispatch as required by the WebGPU specification. They will
|
||||
// also store inline the set of all buffers and textures used, because some unused BindGroups
|
||||
// may not be used at all in synchronization scope but their resources still need to be
|
||||
// validated on Queue::Submit.
|
||||
struct ComputePassResourceUsage : public SyncScopeResourceUsage {};
|
||||
// Essentially a list of SyncScopeResourceUsage, one per Dispatch as required by the WebGPU
|
||||
// specification. ComputePassResourceUsage also stores nline the set of all buffers and
|
||||
// textures used, because some unused BindGroups may not be used at all in synchronization
|
||||
// scope but their resources still need to be validated on Queue::Submit.
|
||||
struct ComputePassResourceUsage {
|
||||
// Somehow without this defaulted constructor, MSVC or its STDlib have an issue where they
|
||||
// use the copy constructor (that's deleted) when doing operations on a
|
||||
// vector<ComputePassResourceUsage>
|
||||
ComputePassResourceUsage(ComputePassResourceUsage&&) = default;
|
||||
ComputePassResourceUsage() = default;
|
||||
|
||||
std::vector<SyncScopeResourceUsage> dispatchUsages;
|
||||
|
||||
// All the resources referenced by this compute pass for validation in Queue::Submit.
|
||||
std::set<BufferBase*> referencedBuffers;
|
||||
std::set<TextureBase*> referencedTextures;
|
||||
};
|
||||
|
||||
// Contains all the resource usage data for a render pass.
|
||||
//
|
||||
|
||||
@@ -138,10 +138,39 @@ namespace dawn_native {
|
||||
return result;
|
||||
}
|
||||
|
||||
void ComputePassResourceUsageTracker::AddDispatch(SyncScopeResourceUsage scope) {
|
||||
mUsage.dispatchUsages.push_back(std::move(scope));
|
||||
}
|
||||
|
||||
void ComputePassResourceUsageTracker::AddReferencedBuffer(BufferBase* buffer) {
|
||||
mUsage.referencedBuffers.insert(buffer);
|
||||
}
|
||||
|
||||
void ComputePassResourceUsageTracker::AddResourcesReferencedByBindGroup(BindGroupBase* group) {
|
||||
for (BindingIndex index{0}; index < group->GetLayout()->GetBindingCount(); ++index) {
|
||||
const BindingInfo& bindingInfo = group->GetLayout()->GetBindingInfo(index);
|
||||
|
||||
switch (bindingInfo.bindingType) {
|
||||
case BindingInfoType::Buffer: {
|
||||
mUsage.referencedBuffers.insert(group->GetBindingAsBufferBinding(index).buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
case BindingInfoType::Texture: {
|
||||
mUsage.referencedTextures.insert(
|
||||
group->GetBindingAsTextureView(index)->GetTexture());
|
||||
break;
|
||||
}
|
||||
|
||||
case BindingInfoType::StorageTexture:
|
||||
case BindingInfoType::Sampler:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ComputePassResourceUsage ComputePassResourceUsageTracker::AcquireResourceUsage() {
|
||||
ComputePassResourceUsage result;
|
||||
*static_cast<SyncScopeResourceUsage*>(&result) = AcquireSyncScopeUsage();
|
||||
return result;
|
||||
return std::move(mUsage);
|
||||
}
|
||||
|
||||
RenderPassResourceUsage RenderPassResourceUsageTracker::AcquireResourceUsage() {
|
||||
|
||||
@@ -49,14 +49,16 @@ namespace dawn_native {
|
||||
};
|
||||
|
||||
// Helper class to build ComputePassResourceUsages
|
||||
class ComputePassResourceUsageTracker : public SyncScopeUsageTracker {
|
||||
class ComputePassResourceUsageTracker {
|
||||
public:
|
||||
void AddDispatch(SyncScopeResourceUsage scope);
|
||||
void AddReferencedBuffer(BufferBase* buffer);
|
||||
void AddResourcesReferencedByBindGroup(BindGroupBase* group);
|
||||
|
||||
ComputePassResourceUsage AcquireResourceUsage();
|
||||
|
||||
private:
|
||||
// Hide AcquireSyncScopeUsage since users of this class should use AcquireResourceUsage
|
||||
// instead.
|
||||
using SyncScopeUsageTracker::AcquireSyncScopeUsage;
|
||||
ComputePassResourceUsage mUsage;
|
||||
};
|
||||
|
||||
// Helper class to build RenderPassResourceUsages
|
||||
|
||||
@@ -37,18 +37,6 @@ namespace dawn_native {
|
||||
|
||||
namespace {
|
||||
|
||||
MaybeError ValidateSyncScopeUsedInSubmit(const SyncScopeResourceUsage& scope) {
|
||||
for (const BufferBase* buffer : scope.buffers) {
|
||||
DAWN_TRY(buffer->ValidateCanUseOnQueueNow());
|
||||
}
|
||||
|
||||
for (const TextureBase* texture : scope.textures) {
|
||||
DAWN_TRY(texture->ValidateCanUseInSubmitNow());
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void CopyTextureData(uint8_t* dstPointer,
|
||||
const uint8_t* srcPointer,
|
||||
uint32_t depth,
|
||||
@@ -423,10 +411,22 @@ namespace dawn_native {
|
||||
const CommandBufferResourceUsage& usages = commands[i]->GetResourceUsages();
|
||||
|
||||
for (const SyncScopeResourceUsage& scope : usages.renderPasses) {
|
||||
DAWN_TRY(ValidateSyncScopeUsedInSubmit(scope));
|
||||
for (const BufferBase* buffer : scope.buffers) {
|
||||
DAWN_TRY(buffer->ValidateCanUseOnQueueNow());
|
||||
}
|
||||
|
||||
for (const TextureBase* texture : scope.textures) {
|
||||
DAWN_TRY(texture->ValidateCanUseInSubmitNow());
|
||||
}
|
||||
}
|
||||
for (const SyncScopeResourceUsage& scope : usages.computePasses) {
|
||||
DAWN_TRY(ValidateSyncScopeUsedInSubmit(scope));
|
||||
|
||||
for (const ComputePassResourceUsage& pass : usages.computePasses) {
|
||||
for (const BufferBase* buffer : pass.referencedBuffers) {
|
||||
DAWN_TRY(buffer->ValidateCanUseOnQueueNow());
|
||||
}
|
||||
for (const TextureBase* texture : pass.referencedTextures) {
|
||||
DAWN_TRY(texture->ValidateCanUseInSubmitNow());
|
||||
}
|
||||
}
|
||||
|
||||
for (const BufferBase* buffer : usages.topLevelBuffers) {
|
||||
|
||||
@@ -193,6 +193,62 @@ namespace dawn_native { namespace d3d12 {
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// Records the necessary barriers for a synchronization scope using the resource usage
|
||||
// data pre-computed in the frontend. Also performs lazy initialization if required.
|
||||
// Returns whether any UAV are used in the synchronization scope.
|
||||
bool TransitionAndClearForSyncScope(CommandRecordingContext* commandContext,
|
||||
const SyncScopeResourceUsage& usages) {
|
||||
std::vector<D3D12_RESOURCE_BARRIER> barriers;
|
||||
|
||||
ID3D12GraphicsCommandList* commandList = commandContext->GetCommandList();
|
||||
|
||||
wgpu::BufferUsage bufferUsages = wgpu::BufferUsage::None;
|
||||
|
||||
for (size_t i = 0; i < usages.buffers.size(); ++i) {
|
||||
Buffer* buffer = ToBackend(usages.buffers[i]);
|
||||
|
||||
// TODO(jiawei.shao@intel.com): clear storage buffers with
|
||||
// ClearUnorderedAccessView*().
|
||||
buffer->GetDevice()->ConsumedError(buffer->EnsureDataInitialized(commandContext));
|
||||
|
||||
D3D12_RESOURCE_BARRIER barrier;
|
||||
if (buffer->TrackUsageAndGetResourceBarrier(commandContext, &barrier,
|
||||
usages.bufferUsages[i])) {
|
||||
barriers.push_back(barrier);
|
||||
}
|
||||
bufferUsages |= usages.bufferUsages[i];
|
||||
}
|
||||
|
||||
wgpu::TextureUsage textureUsages = wgpu::TextureUsage::None;
|
||||
|
||||
for (size_t i = 0; i < usages.textures.size(); ++i) {
|
||||
Texture* texture = ToBackend(usages.textures[i]);
|
||||
|
||||
// Clear subresources that are not render attachments. Render attachments will be
|
||||
// cleared in RecordBeginRenderPass by setting the loadop to clear when the texture
|
||||
// subresource has not been initialized before the render pass.
|
||||
usages.textureUsages[i].Iterate(
|
||||
[&](const SubresourceRange& range, wgpu::TextureUsage usage) {
|
||||
if (usage & ~wgpu::TextureUsage::RenderAttachment) {
|
||||
texture->EnsureSubresourceContentInitialized(commandContext, range);
|
||||
}
|
||||
textureUsages |= usage;
|
||||
});
|
||||
|
||||
ToBackend(usages.textures[i])
|
||||
->TrackUsageAndGetResourceBarrierForPass(commandContext, &barriers,
|
||||
usages.textureUsages[i]);
|
||||
}
|
||||
|
||||
if (barriers.size()) {
|
||||
commandList->ResourceBarrier(barriers.size(), barriers.data());
|
||||
}
|
||||
|
||||
return (bufferUsages & wgpu::BufferUsage::Storage ||
|
||||
textureUsages & wgpu::TextureUsage::Storage);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
class BindGroupStateTracker : public BindGroupTrackerBase<false, uint64_t> {
|
||||
@@ -274,81 +330,6 @@ namespace dawn_native { namespace d3d12 {
|
||||
mDynamicOffsetCounts[index], mDynamicOffsets[index].data());
|
||||
}
|
||||
|
||||
if (mInCompute) {
|
||||
std::vector<D3D12_RESOURCE_BARRIER> barriers;
|
||||
for (BindGroupIndex index : IterateBitSet(mBindGroupLayoutsMask)) {
|
||||
BindGroupLayoutBase* layout = mBindGroups[index]->GetLayout();
|
||||
for (BindingIndex binding{0}; binding < layout->GetBindingCount(); ++binding) {
|
||||
const BindingInfo& bindingInfo = layout->GetBindingInfo(binding);
|
||||
switch (bindingInfo.bindingType) {
|
||||
case BindingInfoType::Buffer: {
|
||||
D3D12_RESOURCE_BARRIER barrier;
|
||||
wgpu::BufferUsage usage;
|
||||
switch (bindingInfo.buffer.type) {
|
||||
case wgpu::BufferBindingType::Uniform:
|
||||
usage = wgpu::BufferUsage::Uniform;
|
||||
break;
|
||||
case wgpu::BufferBindingType::Storage:
|
||||
usage = wgpu::BufferUsage::Storage;
|
||||
break;
|
||||
case wgpu::BufferBindingType::ReadOnlyStorage:
|
||||
usage = kReadOnlyStorageBuffer;
|
||||
break;
|
||||
case wgpu::BufferBindingType::Undefined:
|
||||
UNREACHABLE();
|
||||
}
|
||||
if (ToBackend(mBindGroups[index]
|
||||
->GetBindingAsBufferBinding(binding)
|
||||
.buffer)
|
||||
->TrackUsageAndGetResourceBarrier(commandContext, &barrier,
|
||||
usage)) {
|
||||
barriers.push_back(barrier);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BindingInfoType::StorageTexture: {
|
||||
TextureViewBase* view =
|
||||
mBindGroups[index]->GetBindingAsTextureView(binding);
|
||||
wgpu::TextureUsage usage;
|
||||
switch (bindingInfo.storageTexture.access) {
|
||||
case wgpu::StorageTextureAccess::ReadOnly:
|
||||
usage = kReadOnlyStorageTexture;
|
||||
break;
|
||||
case wgpu::StorageTextureAccess::WriteOnly:
|
||||
usage = wgpu::TextureUsage::Storage;
|
||||
break;
|
||||
case wgpu::StorageTextureAccess::Undefined:
|
||||
UNREACHABLE();
|
||||
}
|
||||
ToBackend(view->GetTexture())
|
||||
->TransitionUsageAndGetResourceBarrier(
|
||||
commandContext, &barriers, usage,
|
||||
view->GetSubresourceRange());
|
||||
break;
|
||||
}
|
||||
|
||||
case BindingInfoType::Texture: {
|
||||
TextureViewBase* view =
|
||||
mBindGroups[index]->GetBindingAsTextureView(binding);
|
||||
ToBackend(view->GetTexture())
|
||||
->TransitionUsageAndGetResourceBarrier(
|
||||
commandContext, &barriers, wgpu::TextureUsage::Sampled,
|
||||
view->GetSubresourceRange());
|
||||
break;
|
||||
}
|
||||
|
||||
case BindingInfoType::Sampler:
|
||||
// Don't require barriers.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!barriers.empty()) {
|
||||
commandList->ResourceBarrier(barriers.size(), barriers.data());
|
||||
}
|
||||
}
|
||||
DidApply();
|
||||
|
||||
return {};
|
||||
@@ -610,78 +591,6 @@ namespace dawn_native { namespace d3d12 {
|
||||
// actual command list but here is ok because there should be few command buffers.
|
||||
bindingTracker.SetID3D12DescriptorHeaps(commandList);
|
||||
|
||||
// Records the necessary barriers for the resource usage pre-computed by the frontend
|
||||
auto PrepareResourcesForRenderPass = [](CommandRecordingContext* commandContext,
|
||||
const RenderPassResourceUsage& usages) -> bool {
|
||||
std::vector<D3D12_RESOURCE_BARRIER> barriers;
|
||||
|
||||
ID3D12GraphicsCommandList* commandList = commandContext->GetCommandList();
|
||||
|
||||
wgpu::BufferUsage bufferUsages = wgpu::BufferUsage::None;
|
||||
|
||||
for (size_t i = 0; i < usages.buffers.size(); ++i) {
|
||||
Buffer* buffer = ToBackend(usages.buffers[i]);
|
||||
|
||||
// TODO(jiawei.shao@intel.com): clear storage buffers with
|
||||
// ClearUnorderedAccessView*().
|
||||
buffer->GetDevice()->ConsumedError(buffer->EnsureDataInitialized(commandContext));
|
||||
|
||||
D3D12_RESOURCE_BARRIER barrier;
|
||||
if (buffer->TrackUsageAndGetResourceBarrier(commandContext, &barrier,
|
||||
usages.bufferUsages[i])) {
|
||||
barriers.push_back(barrier);
|
||||
}
|
||||
bufferUsages |= usages.bufferUsages[i];
|
||||
}
|
||||
|
||||
wgpu::TextureUsage textureUsages = wgpu::TextureUsage::None;
|
||||
|
||||
for (size_t i = 0; i < usages.textures.size(); ++i) {
|
||||
Texture* texture = ToBackend(usages.textures[i]);
|
||||
|
||||
// Clear subresources that are not render attachments. Render attachments will be
|
||||
// cleared in RecordBeginRenderPass by setting the loadop to clear when the texture
|
||||
// subresource has not been initialized before the render pass.
|
||||
usages.textureUsages[i].Iterate(
|
||||
[&](const SubresourceRange& range, wgpu::TextureUsage usage) {
|
||||
if (usage & ~wgpu::TextureUsage::RenderAttachment) {
|
||||
texture->EnsureSubresourceContentInitialized(commandContext, range);
|
||||
}
|
||||
textureUsages |= usage;
|
||||
});
|
||||
|
||||
ToBackend(usages.textures[i])
|
||||
->TrackUsageAndGetResourceBarrierForPass(commandContext, &barriers,
|
||||
usages.textureUsages[i]);
|
||||
}
|
||||
|
||||
if (barriers.size()) {
|
||||
commandList->ResourceBarrier(barriers.size(), barriers.data());
|
||||
}
|
||||
|
||||
return (bufferUsages & wgpu::BufferUsage::Storage ||
|
||||
textureUsages & wgpu::TextureUsage::Storage);
|
||||
};
|
||||
|
||||
// TODO(jiawei.shao@intel.com): move the resource lazy clearing inside the barrier tracking
|
||||
// for compute passes.
|
||||
auto PrepareResourcesForComputePass = [](CommandRecordingContext* commandContext,
|
||||
const ComputePassResourceUsage& usages) {
|
||||
for (size_t i = 0; i < usages.buffers.size(); ++i) {
|
||||
Buffer* buffer = ToBackend(usages.buffers[i]);
|
||||
|
||||
// TODO(jiawei.shao@intel.com): clear storage buffers with
|
||||
// ClearUnorderedAccessView*().
|
||||
buffer->GetDevice()->ConsumedError(buffer->EnsureDataInitialized(commandContext));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < usages.textures.size(); ++i) {
|
||||
Texture* texture = ToBackend(usages.textures[i]);
|
||||
texture->EnsureSubresourceContentInitialized(commandContext,
|
||||
texture->GetAllSubresources());
|
||||
}
|
||||
};
|
||||
|
||||
size_t nextComputePassNumber = 0;
|
||||
size_t nextRenderPassNumber = 0;
|
||||
|
||||
@@ -691,10 +600,10 @@ namespace dawn_native { namespace d3d12 {
|
||||
case Command::BeginComputePass: {
|
||||
mCommands.NextCommand<BeginComputePassCmd>();
|
||||
|
||||
PrepareResourcesForComputePass(
|
||||
commandContext, GetResourceUsages().computePasses[nextComputePassNumber]);
|
||||
bindingTracker.SetInComputePass(true);
|
||||
DAWN_TRY(RecordComputePass(commandContext, &bindingTracker));
|
||||
DAWN_TRY(RecordComputePass(
|
||||
commandContext, &bindingTracker,
|
||||
GetResourceUsages().computePasses[nextComputePassNumber]));
|
||||
|
||||
nextComputePassNumber++;
|
||||
break;
|
||||
@@ -704,7 +613,7 @@ namespace dawn_native { namespace d3d12 {
|
||||
BeginRenderPassCmd* beginRenderPassCmd =
|
||||
mCommands.NextCommand<BeginRenderPassCmd>();
|
||||
|
||||
const bool passHasUAV = PrepareResourcesForRenderPass(
|
||||
const bool passHasUAV = TransitionAndClearForSyncScope(
|
||||
commandContext, GetResourceUsages().renderPasses[nextRenderPassNumber]);
|
||||
bindingTracker.SetInComputePass(false);
|
||||
|
||||
@@ -945,7 +854,9 @@ namespace dawn_native { namespace d3d12 {
|
||||
}
|
||||
|
||||
MaybeError CommandBuffer::RecordComputePass(CommandRecordingContext* commandContext,
|
||||
BindGroupStateTracker* bindingTracker) {
|
||||
BindGroupStateTracker* bindingTracker,
|
||||
const ComputePassResourceUsage& resourceUsages) {
|
||||
uint64_t currentDispatch = 0;
|
||||
PipelineLayout* lastLayout = nullptr;
|
||||
ID3D12GraphicsCommandList* commandList = commandContext->GetCommandList();
|
||||
|
||||
@@ -955,21 +866,28 @@ namespace dawn_native { namespace d3d12 {
|
||||
case Command::Dispatch: {
|
||||
DispatchCmd* dispatch = mCommands.NextCommand<DispatchCmd>();
|
||||
|
||||
TransitionAndClearForSyncScope(commandContext,
|
||||
resourceUsages.dispatchUsages[currentDispatch]);
|
||||
DAWN_TRY(bindingTracker->Apply(commandContext));
|
||||
|
||||
commandList->Dispatch(dispatch->x, dispatch->y, dispatch->z);
|
||||
currentDispatch++;
|
||||
break;
|
||||
}
|
||||
|
||||
case Command::DispatchIndirect: {
|
||||
DispatchIndirectCmd* dispatch = mCommands.NextCommand<DispatchIndirectCmd>();
|
||||
|
||||
DAWN_TRY(bindingTracker->Apply(commandContext));
|
||||
Buffer* buffer = ToBackend(dispatch->indirectBuffer.Get());
|
||||
buffer->TrackUsageAndTransitionNow(commandContext, wgpu::BufferUsage::Indirect);
|
||||
|
||||
TransitionAndClearForSyncScope(commandContext,
|
||||
resourceUsages.dispatchUsages[currentDispatch]);
|
||||
DAWN_TRY(bindingTracker->Apply(commandContext));
|
||||
|
||||
ComPtr<ID3D12CommandSignature> signature =
|
||||
ToBackend(GetDevice())->GetDispatchIndirectSignature();
|
||||
commandList->ExecuteIndirect(signature.Get(), 1, buffer->GetD3D12Resource(),
|
||||
dispatch->indirectOffset, nullptr, 0);
|
||||
currentDispatch++;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,8 @@ namespace dawn_native { namespace d3d12 {
|
||||
CommandBuffer(CommandEncoder* encoder, const CommandBufferDescriptor* descriptor);
|
||||
|
||||
MaybeError RecordComputePass(CommandRecordingContext* commandContext,
|
||||
BindGroupStateTracker* bindingTracker);
|
||||
BindGroupStateTracker* bindingTracker,
|
||||
const ComputePassResourceUsage& resourceUsages);
|
||||
MaybeError RecordRenderPass(CommandRecordingContext* commandContext,
|
||||
BindGroupStateTracker* bindingTracker,
|
||||
BeginRenderPassCmd* renderPass,
|
||||
|
||||
@@ -554,8 +554,8 @@ namespace dawn_native { namespace metal {
|
||||
size_t nextComputePassNumber = 0;
|
||||
size_t nextRenderPassNumber = 0;
|
||||
|
||||
auto LazyClearForPass = [](const SyncScopeResourceUsage& scope,
|
||||
CommandRecordingContext* commandContext) {
|
||||
auto LazyClearSyncScope = [](const SyncScopeResourceUsage& scope,
|
||||
CommandRecordingContext* commandContext) {
|
||||
for (size_t i = 0; i < scope.textures.size(); ++i) {
|
||||
Texture* texture = ToBackend(scope.textures[i]);
|
||||
|
||||
@@ -580,8 +580,10 @@ namespace dawn_native { namespace metal {
|
||||
case Command::BeginComputePass: {
|
||||
mCommands.NextCommand<BeginComputePassCmd>();
|
||||
|
||||
LazyClearForPass(GetResourceUsages().computePasses[nextComputePassNumber],
|
||||
commandContext);
|
||||
for (const SyncScopeResourceUsage& scope :
|
||||
GetResourceUsages().computePasses[nextComputePassNumber].dispatchUsages) {
|
||||
LazyClearSyncScope(scope, commandContext);
|
||||
}
|
||||
commandContext->EndBlit();
|
||||
|
||||
DAWN_TRY(EncodeComputePass(commandContext));
|
||||
@@ -593,8 +595,8 @@ namespace dawn_native { namespace metal {
|
||||
case Command::BeginRenderPass: {
|
||||
BeginRenderPassCmd* cmd = mCommands.NextCommand<BeginRenderPassCmd>();
|
||||
|
||||
LazyClearForPass(GetResourceUsages().renderPasses[nextRenderPassNumber],
|
||||
commandContext);
|
||||
LazyClearSyncScope(GetResourceUsages().renderPasses[nextRenderPassNumber],
|
||||
commandContext);
|
||||
commandContext->EndBlit();
|
||||
|
||||
LazyClearRenderPassAttachments(cmd);
|
||||
|
||||
@@ -536,7 +536,7 @@ namespace dawn_native { namespace opengl {
|
||||
MaybeError CommandBuffer::Execute() {
|
||||
const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
|
||||
|
||||
auto LazyClearForPass = [](const SyncScopeResourceUsage& scope) {
|
||||
auto LazyClearSyncScope = [](const SyncScopeResourceUsage& scope) {
|
||||
for (size_t i = 0; i < scope.textures.size(); i++) {
|
||||
Texture* texture = ToBackend(scope.textures[i]);
|
||||
|
||||
@@ -564,7 +564,10 @@ namespace dawn_native { namespace opengl {
|
||||
switch (type) {
|
||||
case Command::BeginComputePass: {
|
||||
mCommands.NextCommand<BeginComputePassCmd>();
|
||||
LazyClearForPass(GetResourceUsages().computePasses[nextComputePassNumber]);
|
||||
for (const SyncScopeResourceUsage& scope :
|
||||
GetResourceUsages().computePasses[nextComputePassNumber].dispatchUsages) {
|
||||
LazyClearSyncScope(scope);
|
||||
}
|
||||
DAWN_TRY(ExecuteComputePass());
|
||||
|
||||
nextComputePassNumber++;
|
||||
@@ -573,7 +576,7 @@ namespace dawn_native { namespace opengl {
|
||||
|
||||
case Command::BeginRenderPass: {
|
||||
auto* cmd = mCommands.NextCommand<BeginRenderPassCmd>();
|
||||
LazyClearForPass(GetResourceUsages().renderPasses[nextRenderPassNumber]);
|
||||
LazyClearSyncScope(GetResourceUsages().renderPasses[nextRenderPassNumber]);
|
||||
LazyClearRenderPassAttachments(cmd);
|
||||
DAWN_TRY(ExecuteRenderPass(cmd));
|
||||
|
||||
|
||||
@@ -100,130 +100,73 @@ namespace dawn_native { namespace vulkan {
|
||||
return region;
|
||||
}
|
||||
|
||||
void ApplyDescriptorSets(
|
||||
Device* device,
|
||||
VkCommandBuffer commands,
|
||||
VkPipelineBindPoint bindPoint,
|
||||
VkPipelineLayout pipelineLayout,
|
||||
const BindGroupLayoutMask& bindGroupsToApply,
|
||||
const ityp::array<BindGroupIndex, BindGroupBase*, kMaxBindGroups>& bindGroups,
|
||||
const ityp::array<BindGroupIndex, uint32_t, kMaxBindGroups>& dynamicOffsetCounts,
|
||||
const ityp::array<BindGroupIndex,
|
||||
std::array<uint32_t, kMaxDynamicBuffersPerPipelineLayout>,
|
||||
kMaxBindGroups>& dynamicOffsets) {
|
||||
for (BindGroupIndex dirtyIndex : IterateBitSet(bindGroupsToApply)) {
|
||||
VkDescriptorSet set = ToBackend(bindGroups[dirtyIndex])->GetHandle();
|
||||
const uint32_t* dynamicOffset = dynamicOffsetCounts[dirtyIndex] > 0
|
||||
? dynamicOffsets[dirtyIndex].data()
|
||||
: nullptr;
|
||||
device->fn.CmdBindDescriptorSets(commands, bindPoint, pipelineLayout,
|
||||
static_cast<uint32_t>(dirtyIndex), 1, &*set,
|
||||
dynamicOffsetCounts[dirtyIndex], dynamicOffset);
|
||||
class DescriptorSetTracker : public BindGroupTrackerBase<true, uint32_t> {
|
||||
public:
|
||||
DescriptorSetTracker() = default;
|
||||
|
||||
void Apply(Device* device,
|
||||
CommandRecordingContext* recordingContext,
|
||||
VkPipelineBindPoint bindPoint) {
|
||||
for (BindGroupIndex dirtyIndex :
|
||||
IterateBitSet(mDirtyBindGroupsObjectChangedOrIsDynamic)) {
|
||||
VkDescriptorSet set = ToBackend(mBindGroups[dirtyIndex])->GetHandle();
|
||||
const uint32_t* dynamicOffset = mDynamicOffsetCounts[dirtyIndex] > 0
|
||||
? mDynamicOffsets[dirtyIndex].data()
|
||||
: nullptr;
|
||||
device->fn.CmdBindDescriptorSets(
|
||||
recordingContext->commandBuffer, bindPoint,
|
||||
ToBackend(mPipelineLayout)->GetHandle(), static_cast<uint32_t>(dirtyIndex),
|
||||
1, &*set, mDynamicOffsetCounts[dirtyIndex], dynamicOffset);
|
||||
}
|
||||
DidApply();
|
||||
}
|
||||
};
|
||||
|
||||
// Records the necessary barriers for a synchronization scope using the resource usage
|
||||
// data pre-computed in the frontend. Also performs lazy initialization if required.
|
||||
void TransitionAndClearForSyncScope(Device* device,
|
||||
CommandRecordingContext* recordingContext,
|
||||
const SyncScopeResourceUsage& scope) {
|
||||
std::vector<VkBufferMemoryBarrier> bufferBarriers;
|
||||
std::vector<VkImageMemoryBarrier> imageBarriers;
|
||||
VkPipelineStageFlags srcStages = 0;
|
||||
VkPipelineStageFlags dstStages = 0;
|
||||
|
||||
for (size_t i = 0; i < scope.buffers.size(); ++i) {
|
||||
Buffer* buffer = ToBackend(scope.buffers[i]);
|
||||
buffer->EnsureDataInitialized(recordingContext);
|
||||
|
||||
VkBufferMemoryBarrier bufferBarrier;
|
||||
if (buffer->TransitionUsageAndGetResourceBarrier(
|
||||
scope.bufferUsages[i], &bufferBarrier, &srcStages, &dstStages)) {
|
||||
bufferBarriers.push_back(bufferBarrier);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < scope.textures.size(); ++i) {
|
||||
Texture* texture = ToBackend(scope.textures[i]);
|
||||
|
||||
// Clear subresources that are not render attachments. Render attachments will be
|
||||
// cleared in RecordBeginRenderPass by setting the loadop to clear when the texture
|
||||
// subresource has not been initialized before the render pass.
|
||||
scope.textureUsages[i].Iterate(
|
||||
[&](const SubresourceRange& range, wgpu::TextureUsage usage) {
|
||||
if (usage & ~wgpu::TextureUsage::RenderAttachment) {
|
||||
texture->EnsureSubresourceContentInitialized(recordingContext, range);
|
||||
}
|
||||
});
|
||||
texture->TransitionUsageForPass(recordingContext, scope.textureUsages[i],
|
||||
&imageBarriers, &srcStages, &dstStages);
|
||||
}
|
||||
|
||||
if (bufferBarriers.size() || imageBarriers.size()) {
|
||||
device->fn.CmdPipelineBarrier(recordingContext->commandBuffer, srcStages, dstStages,
|
||||
0, 0, nullptr, bufferBarriers.size(),
|
||||
bufferBarriers.data(), imageBarriers.size(),
|
||||
imageBarriers.data());
|
||||
}
|
||||
}
|
||||
|
||||
class RenderDescriptorSetTracker : public BindGroupTrackerBase<true, uint32_t> {
|
||||
public:
|
||||
RenderDescriptorSetTracker() = default;
|
||||
|
||||
void Apply(Device* device,
|
||||
CommandRecordingContext* recordingContext,
|
||||
VkPipelineBindPoint bindPoint) {
|
||||
ApplyDescriptorSets(device, recordingContext->commandBuffer, bindPoint,
|
||||
ToBackend(mPipelineLayout)->GetHandle(),
|
||||
mDirtyBindGroupsObjectChangedOrIsDynamic, mBindGroups,
|
||||
mDynamicOffsetCounts, mDynamicOffsets);
|
||||
DidApply();
|
||||
}
|
||||
};
|
||||
|
||||
class ComputeDescriptorSetTracker : public BindGroupTrackerBase<true, uint32_t> {
|
||||
public:
|
||||
ComputeDescriptorSetTracker() = default;
|
||||
|
||||
void Apply(Device* device,
|
||||
CommandRecordingContext* recordingContext,
|
||||
VkPipelineBindPoint bindPoint) {
|
||||
ApplyDescriptorSets(device, recordingContext->commandBuffer, bindPoint,
|
||||
ToBackend(mPipelineLayout)->GetHandle(),
|
||||
mDirtyBindGroupsObjectChangedOrIsDynamic, mBindGroups,
|
||||
mDynamicOffsetCounts, mDynamicOffsets);
|
||||
|
||||
std::vector<VkBufferMemoryBarrier> bufferBarriers;
|
||||
std::vector<VkImageMemoryBarrier> imageBarriers;
|
||||
VkPipelineStageFlags srcStages = 0;
|
||||
VkPipelineStageFlags dstStages = 0;
|
||||
|
||||
for (BindGroupIndex index : IterateBitSet(mBindGroupLayoutsMask)) {
|
||||
BindGroupLayoutBase* layout = mBindGroups[index]->GetLayout();
|
||||
for (BindingIndex binding{0}; binding < layout->GetBindingCount(); ++binding) {
|
||||
const BindingInfo& bindingInfo = layout->GetBindingInfo(binding);
|
||||
|
||||
switch (bindingInfo.bindingType) {
|
||||
case BindingInfoType::Buffer: {
|
||||
wgpu::BufferUsage usage;
|
||||
switch (bindingInfo.buffer.type) {
|
||||
case wgpu::BufferBindingType::Uniform:
|
||||
usage = wgpu::BufferUsage::Uniform;
|
||||
break;
|
||||
case wgpu::BufferBindingType::Storage:
|
||||
case wgpu::BufferBindingType::ReadOnlyStorage:
|
||||
usage = wgpu::BufferUsage::Storage;
|
||||
break;
|
||||
case wgpu::BufferBindingType::Undefined:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
VkBufferMemoryBarrier bufferBarrier;
|
||||
if (ToBackend(mBindGroups[index]
|
||||
->GetBindingAsBufferBinding(binding)
|
||||
.buffer)
|
||||
->TransitionUsageAndGetResourceBarrier(
|
||||
usage, &bufferBarrier, &srcStages, &dstStages)) {
|
||||
bufferBarriers.push_back(bufferBarrier);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BindingInfoType::StorageTexture: {
|
||||
TextureViewBase* view =
|
||||
mBindGroups[index]->GetBindingAsTextureView(binding);
|
||||
ToBackend(view->GetTexture())
|
||||
->TransitionUsageAndGetResourceBarrier(
|
||||
wgpu::TextureUsage::Storage, view->GetSubresourceRange(),
|
||||
&imageBarriers, &srcStages, &dstStages);
|
||||
break;
|
||||
}
|
||||
|
||||
case BindingInfoType::Texture: {
|
||||
TextureViewBase* view =
|
||||
mBindGroups[index]->GetBindingAsTextureView(binding);
|
||||
ToBackend(view->GetTexture())
|
||||
->TransitionUsageAndGetResourceBarrier(
|
||||
wgpu::TextureUsage::Sampled, view->GetSubresourceRange(),
|
||||
&imageBarriers, &srcStages, &dstStages);
|
||||
break;
|
||||
}
|
||||
|
||||
case BindingInfoType::Sampler:
|
||||
// Don't require barriers.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!bufferBarriers.empty() || !imageBarriers.empty()) {
|
||||
ASSERT(srcStages != 0 && dstStages != 0);
|
||||
device->fn.CmdPipelineBarrier(recordingContext->commandBuffer, srcStages,
|
||||
dstStages, 0, 0, nullptr, bufferBarriers.size(),
|
||||
bufferBarriers.data(), imageBarriers.size(),
|
||||
imageBarriers.data());
|
||||
}
|
||||
|
||||
DidApply();
|
||||
}
|
||||
};
|
||||
|
||||
MaybeError RecordBeginRenderPass(CommandRecordingContext* recordingContext,
|
||||
Device* device,
|
||||
BeginRenderPassCmd* renderPass) {
|
||||
@@ -532,44 +475,7 @@ namespace dawn_native { namespace vulkan {
|
||||
auto PrepareResourcesForRenderPass = [](Device* device,
|
||||
CommandRecordingContext* recordingContext,
|
||||
const RenderPassResourceUsage& usages) {
|
||||
std::vector<VkBufferMemoryBarrier> bufferBarriers;
|
||||
std::vector<VkImageMemoryBarrier> imageBarriers;
|
||||
VkPipelineStageFlags srcStages = 0;
|
||||
VkPipelineStageFlags dstStages = 0;
|
||||
|
||||
for (size_t i = 0; i < usages.buffers.size(); ++i) {
|
||||
Buffer* buffer = ToBackend(usages.buffers[i]);
|
||||
buffer->EnsureDataInitialized(recordingContext);
|
||||
|
||||
VkBufferMemoryBarrier bufferBarrier;
|
||||
if (buffer->TransitionUsageAndGetResourceBarrier(
|
||||
usages.bufferUsages[i], &bufferBarrier, &srcStages, &dstStages)) {
|
||||
bufferBarriers.push_back(bufferBarrier);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < usages.textures.size(); ++i) {
|
||||
Texture* texture = ToBackend(usages.textures[i]);
|
||||
|
||||
// Clear subresources that are not render attachments. Render attachments will be
|
||||
// cleared in RecordBeginRenderPass by setting the loadop to clear when the texture
|
||||
// subresource has not been initialized before the render pass.
|
||||
usages.textureUsages[i].Iterate(
|
||||
[&](const SubresourceRange& range, wgpu::TextureUsage usage) {
|
||||
if (usage & ~wgpu::TextureUsage::RenderAttachment) {
|
||||
texture->EnsureSubresourceContentInitialized(recordingContext, range);
|
||||
}
|
||||
});
|
||||
texture->TransitionUsageForPass(recordingContext, usages.textureUsages[i],
|
||||
&imageBarriers, &srcStages, &dstStages);
|
||||
}
|
||||
|
||||
if (bufferBarriers.size() || imageBarriers.size()) {
|
||||
device->fn.CmdPipelineBarrier(recordingContext->commandBuffer, srcStages, dstStages,
|
||||
0, 0, nullptr, bufferBarriers.size(),
|
||||
bufferBarriers.data(), imageBarriers.size(),
|
||||
imageBarriers.data());
|
||||
}
|
||||
TransitionAndClearForSyncScope(device, recordingContext, usages);
|
||||
|
||||
// Reset all query set used on current render pass together before beginning render pass
|
||||
// because the reset command must be called outside render pass
|
||||
@@ -579,23 +485,6 @@ namespace dawn_native { namespace vulkan {
|
||||
}
|
||||
};
|
||||
|
||||
// TODO(jiawei.shao@intel.com): move the resource lazy clearing inside the barrier tracking
|
||||
// for compute passes.
|
||||
auto PrepareResourcesForComputePass = [](Device* device,
|
||||
CommandRecordingContext* recordingContext,
|
||||
const ComputePassResourceUsage& usages) {
|
||||
for (size_t i = 0; i < usages.buffers.size(); ++i) {
|
||||
Buffer* buffer = ToBackend(usages.buffers[i]);
|
||||
buffer->EnsureDataInitialized(recordingContext);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < usages.textures.size(); ++i) {
|
||||
Texture* texture = ToBackend(usages.textures[i]);
|
||||
texture->EnsureSubresourceContentInitialized(recordingContext,
|
||||
texture->GetAllSubresources());
|
||||
}
|
||||
};
|
||||
|
||||
size_t nextComputePassNumber = 0;
|
||||
size_t nextRenderPassNumber = 0;
|
||||
|
||||
@@ -788,10 +677,9 @@ namespace dawn_native { namespace vulkan {
|
||||
case Command::BeginComputePass: {
|
||||
mCommands.NextCommand<BeginComputePassCmd>();
|
||||
|
||||
PrepareResourcesForComputePass(
|
||||
device, recordingContext,
|
||||
GetResourceUsages().computePasses[nextComputePassNumber]);
|
||||
DAWN_TRY(RecordComputePass(recordingContext));
|
||||
DAWN_TRY(RecordComputePass(
|
||||
recordingContext,
|
||||
GetResourceUsages().computePasses[nextComputePassNumber]));
|
||||
|
||||
nextComputePassNumber++;
|
||||
break;
|
||||
@@ -903,11 +791,13 @@ namespace dawn_native { namespace vulkan {
|
||||
return {};
|
||||
}
|
||||
|
||||
MaybeError CommandBuffer::RecordComputePass(CommandRecordingContext* recordingContext) {
|
||||
MaybeError CommandBuffer::RecordComputePass(CommandRecordingContext* recordingContext,
|
||||
const ComputePassResourceUsage& resourceUsages) {
|
||||
Device* device = ToBackend(GetDevice());
|
||||
VkCommandBuffer commands = recordingContext->commandBuffer;
|
||||
|
||||
ComputeDescriptorSetTracker descriptorSets = {};
|
||||
uint64_t currentDispatch = 0;
|
||||
DescriptorSetTracker descriptorSets = {};
|
||||
|
||||
Command type;
|
||||
while (mCommands.NextCommandId(&type)) {
|
||||
@@ -920,21 +810,27 @@ namespace dawn_native { namespace vulkan {
|
||||
case Command::Dispatch: {
|
||||
DispatchCmd* dispatch = mCommands.NextCommand<DispatchCmd>();
|
||||
|
||||
TransitionAndClearForSyncScope(device, recordingContext,
|
||||
resourceUsages.dispatchUsages[currentDispatch]);
|
||||
descriptorSets.Apply(device, recordingContext, VK_PIPELINE_BIND_POINT_COMPUTE);
|
||||
|
||||
device->fn.CmdDispatch(commands, dispatch->x, dispatch->y, dispatch->z);
|
||||
currentDispatch++;
|
||||
break;
|
||||
}
|
||||
|
||||
case Command::DispatchIndirect: {
|
||||
DispatchIndirectCmd* dispatch = mCommands.NextCommand<DispatchIndirectCmd>();
|
||||
ToBackend(dispatch->indirectBuffer)
|
||||
->TransitionUsageNow(recordingContext, wgpu::BufferUsage::Indirect);
|
||||
VkBuffer indirectBuffer = ToBackend(dispatch->indirectBuffer)->GetHandle();
|
||||
|
||||
TransitionAndClearForSyncScope(device, recordingContext,
|
||||
resourceUsages.dispatchUsages[currentDispatch]);
|
||||
descriptorSets.Apply(device, recordingContext, VK_PIPELINE_BIND_POINT_COMPUTE);
|
||||
|
||||
device->fn.CmdDispatchIndirect(
|
||||
commands, indirectBuffer,
|
||||
static_cast<VkDeviceSize>(dispatch->indirectOffset));
|
||||
currentDispatch++;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1072,7 +968,7 @@ namespace dawn_native { namespace vulkan {
|
||||
device->fn.CmdSetScissor(commands, 0, 1, &scissorRect);
|
||||
}
|
||||
|
||||
RenderDescriptorSetTracker descriptorSets = {};
|
||||
DescriptorSetTracker descriptorSets = {};
|
||||
RenderPipeline* lastPipeline = nullptr;
|
||||
|
||||
auto EncodeRenderBundleCommand = [&](CommandIterator* iter, Command type) {
|
||||
|
||||
@@ -40,7 +40,8 @@ namespace dawn_native { namespace vulkan {
|
||||
private:
|
||||
CommandBuffer(CommandEncoder* encoder, const CommandBufferDescriptor* descriptor);
|
||||
|
||||
MaybeError RecordComputePass(CommandRecordingContext* recordingContext);
|
||||
MaybeError RecordComputePass(CommandRecordingContext* recordingContext,
|
||||
const ComputePassResourceUsage& resourceUsages);
|
||||
MaybeError RecordRenderPass(CommandRecordingContext* recordingContext,
|
||||
BeginRenderPassCmd* renderPass);
|
||||
void RecordCopyImageWithTemporaryBuffer(CommandRecordingContext* recordingContext,
|
||||
|
||||
Reference in New Issue
Block a user