d3d11: fix and enable ComputeStorageBufferBarrierTests
The problem is becasue a resource can not be set as input and output at same time on device context. So we have to track used slots and unset related slots before binding a group. This CL also unset all affect slots when a render pass or compute pass is end, so all related resources could be unref from the device context. Bug: dawn:1705 Change-Id: I597762ad8afa3b8df7139b0070f0b457d7319836 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/131380 Commit-Queue: Peng Huang <penghuang@chromium.org> Reviewed-by: Austin Eng <enga@chromium.org> Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
parent
b703afc061
commit
283b3a042f
|
@ -434,6 +434,8 @@ source_set("sources") {
|
|||
"d3d11/BindGroupD3D11.h",
|
||||
"d3d11/BindGroupLayoutD3D11.cpp",
|
||||
"d3d11/BindGroupLayoutD3D11.h",
|
||||
"d3d11/BindGroupTrackerD3D11.cpp",
|
||||
"d3d11/BindGroupTrackerD3D11.h",
|
||||
"d3d11/BufferD3D11.cpp",
|
||||
"d3d11/BufferD3D11.h",
|
||||
"d3d11/CommandBufferD3D11.cpp",
|
||||
|
|
|
@ -291,6 +291,8 @@ if (DAWN_ENABLE_D3D11)
|
|||
"d3d11/BindGroupD3D11.h"
|
||||
"d3d11/BindGroupLayoutD3D11.cpp"
|
||||
"d3d11/BindGroupLayoutD3D11.h"
|
||||
"d3d11/BindGroupTrackerD3D11.cpp"
|
||||
"d3d11/BindGroupTrackerD3D11.h"
|
||||
"d3d11/BufferD3D11.cpp"
|
||||
"d3d11/BufferD3D11.h"
|
||||
"d3d11/CommandBufferD3D11.cpp"
|
||||
|
|
|
@ -0,0 +1,351 @@
|
|||
// Copyright 2023 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/d3d11/BindGroupTrackerD3D11.h"
|
||||
|
||||
#include "dawn/common/Assert.h"
|
||||
#include "dawn/native/Format.h"
|
||||
#include "dawn/native/d3d/D3DError.h"
|
||||
#include "dawn/native/d3d11/BindGroupD3D11.h"
|
||||
#include "dawn/native/d3d11/BufferD3D11.h"
|
||||
#include "dawn/native/d3d11/CommandRecordingContextD3D11.h"
|
||||
#include "dawn/native/d3d11/DeviceD3D11.h"
|
||||
#include "dawn/native/d3d11/PipelineLayoutD3D11.h"
|
||||
#include "dawn/native/d3d11/SamplerD3D11.h"
|
||||
#include "dawn/native/d3d11/TextureD3D11.h"
|
||||
|
||||
namespace dawn::native::d3d11 {
|
||||
namespace {
|
||||
|
||||
bool CheckAllSlotsAreEmpty(CommandRecordingContext* commandContext) {
|
||||
ID3D11DeviceContext1* deviceContext1 = commandContext->GetD3D11DeviceContext1();
|
||||
|
||||
// Reserve one slot for builtin constants.
|
||||
constexpr uint32_t kReservedCBVSlots = 1;
|
||||
|
||||
// Check constant buffer slots
|
||||
for (UINT slot = 0;
|
||||
slot < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - kReservedCBVSlots; ++slot) {
|
||||
ID3D11Buffer* buffer = nullptr;
|
||||
deviceContext1->VSGetConstantBuffers1(slot, 1, &buffer, nullptr, nullptr);
|
||||
ASSERT(buffer == nullptr);
|
||||
deviceContext1->PSGetConstantBuffers1(slot, 1, &buffer, nullptr, nullptr);
|
||||
ASSERT(buffer == nullptr);
|
||||
deviceContext1->CSGetConstantBuffers1(slot, 1, &buffer, nullptr, nullptr);
|
||||
ASSERT(buffer == nullptr);
|
||||
}
|
||||
|
||||
// Check resource slots
|
||||
for (UINT slot = 0; slot < D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT; ++slot) {
|
||||
ID3D11ShaderResourceView* srv = nullptr;
|
||||
deviceContext1->VSGetShaderResources(slot, 1, &srv);
|
||||
ASSERT(srv == nullptr);
|
||||
deviceContext1->PSGetShaderResources(slot, 1, &srv);
|
||||
ASSERT(srv == nullptr);
|
||||
deviceContext1->CSGetShaderResources(slot, 1, &srv);
|
||||
ASSERT(srv == nullptr);
|
||||
}
|
||||
|
||||
// Check sampler slots
|
||||
for (UINT slot = 0; slot < D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT; ++slot) {
|
||||
ID3D11SamplerState* sampler = nullptr;
|
||||
deviceContext1->VSGetSamplers(slot, 1, &sampler);
|
||||
ASSERT(sampler == nullptr);
|
||||
deviceContext1->PSGetSamplers(slot, 1, &sampler);
|
||||
ASSERT(sampler == nullptr);
|
||||
deviceContext1->CSGetSamplers(slot, 1, &sampler);
|
||||
ASSERT(sampler == nullptr);
|
||||
}
|
||||
|
||||
// Check UAV slots
|
||||
for (UINT slot = 0; slot < D3D11_1_UAV_SLOT_COUNT; ++slot) {
|
||||
ID3D11UnorderedAccessView* uav = nullptr;
|
||||
deviceContext1->CSGetUnorderedAccessViews(slot, 1, &uav);
|
||||
ASSERT(uav == nullptr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
BindGroupTracker::BindGroupTracker(CommandRecordingContext* commandContext)
|
||||
: mCommandContext(commandContext) {}
|
||||
|
||||
BindGroupTracker::~BindGroupTracker() {
|
||||
if (mLastAppliedPipelineLayout) {
|
||||
for (BindGroupIndex index :
|
||||
IterateBitSet(mLastAppliedPipelineLayout->GetBindGroupLayoutsMask())) {
|
||||
UnApplyBindGroup(index);
|
||||
}
|
||||
}
|
||||
// All slots should be unbound here.
|
||||
ASSERT(CheckAllSlotsAreEmpty(mCommandContext));
|
||||
}
|
||||
|
||||
MaybeError BindGroupTracker::Apply() {
|
||||
BeforeApply();
|
||||
|
||||
// A resource cannot be bound as both input resource and UAV at the same time, so to avoid this
|
||||
// conflict, we need to unbind groups which are not used by the new pipeline. and unbind groups
|
||||
// which are not inherited by the new pipeline.
|
||||
if (mLastAppliedPipelineLayout) {
|
||||
BindGroupLayoutMask unusedGroups = mLastAppliedPipelineLayout->GetBindGroupLayoutsMask() &
|
||||
~mPipelineLayout->GetBindGroupLayoutsMask();
|
||||
// Unset bind groups which are not used by the new pipeline and are not inherited.
|
||||
for (BindGroupIndex index : IterateBitSet(mDirtyBindGroups | unusedGroups)) {
|
||||
UnApplyBindGroup(index);
|
||||
}
|
||||
}
|
||||
|
||||
for (BindGroupIndex index : IterateBitSet(mDirtyBindGroupsObjectChangedOrIsDynamic)) {
|
||||
DAWN_TRY(ApplyBindGroup(index));
|
||||
}
|
||||
|
||||
AfterApply();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
MaybeError BindGroupTracker::ApplyBindGroup(BindGroupIndex index) {
|
||||
ID3D11DeviceContext1* deviceContext1 = mCommandContext->GetD3D11DeviceContext1();
|
||||
BindGroupBase* group = mBindGroups[index];
|
||||
const ityp::vector<BindingIndex, uint64_t>& dynamicOffsets = mDynamicOffsets[index];
|
||||
const auto& indices = ToBackend(mPipelineLayout)->GetBindingIndexInfo()[index];
|
||||
|
||||
for (BindingIndex bindingIndex{0}; bindingIndex < group->GetLayout()->GetBindingCount();
|
||||
++bindingIndex) {
|
||||
const BindingInfo& bindingInfo = group->GetLayout()->GetBindingInfo(bindingIndex);
|
||||
const uint32_t bindingSlot = indices[bindingIndex];
|
||||
|
||||
switch (bindingInfo.bindingType) {
|
||||
case BindingInfoType::Buffer: {
|
||||
BufferBinding binding = group->GetBindingAsBufferBinding(bindingIndex);
|
||||
ID3D11Buffer* d3d11Buffer = ToBackend(binding.buffer)->GetD3D11Buffer();
|
||||
auto offset = binding.offset;
|
||||
if (bindingInfo.buffer.hasDynamicOffset) {
|
||||
// Dynamic buffers are packed at the front of BindingIndices.
|
||||
offset += dynamicOffsets[bindingIndex];
|
||||
}
|
||||
|
||||
switch (bindingInfo.buffer.type) {
|
||||
case wgpu::BufferBindingType::Uniform: {
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/d3d11_1/nf-d3d11_1-id3d11devicecontext1-vssetconstantbuffers1
|
||||
// Offset and size are measured in shader constants, which are 16 bytes
|
||||
// (4*32-bit components). And the offsets and counts must be multiples
|
||||
// of 16.
|
||||
// WebGPU's minUniformBufferOffsetAlignment is 256.
|
||||
DAWN_ASSERT(IsAligned(offset, 256));
|
||||
uint32_t firstConstant = static_cast<uint32_t>(offset / 16);
|
||||
uint32_t size = static_cast<uint32_t>(Align(binding.size, 16) / 16);
|
||||
uint32_t numConstants = Align(size, 16);
|
||||
DAWN_ASSERT(offset + numConstants * 16 <=
|
||||
binding.buffer->GetAllocatedSize());
|
||||
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) {
|
||||
deviceContext1->VSSetConstantBuffers1(bindingSlot, 1, &d3d11Buffer,
|
||||
&firstConstant, &numConstants);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) {
|
||||
deviceContext1->PSSetConstantBuffers1(bindingSlot, 1, &d3d11Buffer,
|
||||
&firstConstant, &numConstants);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) {
|
||||
deviceContext1->CSSetConstantBuffers1(bindingSlot, 1, &d3d11Buffer,
|
||||
&firstConstant, &numConstants);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case wgpu::BufferBindingType::Storage:
|
||||
case kInternalStorageBufferBinding: {
|
||||
ASSERT(IsSubset(bindingInfo.visibility, wgpu::ShaderStage::Compute));
|
||||
ComPtr<ID3D11UnorderedAccessView> d3d11UAV;
|
||||
DAWN_TRY_ASSIGN(d3d11UAV, ToBackend(binding.buffer)
|
||||
->CreateD3D11UnorderedAccessView1(
|
||||
0, binding.buffer->GetSize()));
|
||||
UINT firstElement = offset / 4;
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) {
|
||||
deviceContext1->CSSetUnorderedAccessViews(
|
||||
bindingSlot, 1, d3d11UAV.GetAddressOf(), &firstElement);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case wgpu::BufferBindingType::ReadOnlyStorage: {
|
||||
ComPtr<ID3D11ShaderResourceView> d3d11SRV;
|
||||
DAWN_TRY_ASSIGN(d3d11SRV,
|
||||
ToBackend(binding.buffer)
|
||||
->CreateD3D11ShaderResourceView(offset, binding.size));
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) {
|
||||
deviceContext1->VSSetShaderResources(bindingSlot, 1,
|
||||
d3d11SRV.GetAddressOf());
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) {
|
||||
deviceContext1->PSSetShaderResources(bindingSlot, 1,
|
||||
d3d11SRV.GetAddressOf());
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) {
|
||||
deviceContext1->CSSetShaderResources(bindingSlot, 1,
|
||||
d3d11SRV.GetAddressOf());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case wgpu::BufferBindingType::Undefined:
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BindingInfoType::Sampler: {
|
||||
Sampler* sampler = ToBackend(group->GetBindingAsSampler(bindingIndex));
|
||||
ID3D11SamplerState* d3d11SamplerState = sampler->GetD3D11SamplerState();
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) {
|
||||
deviceContext1->VSSetSamplers(bindingSlot, 1, &d3d11SamplerState);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) {
|
||||
deviceContext1->PSSetSamplers(bindingSlot, 1, &d3d11SamplerState);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) {
|
||||
deviceContext1->CSSetSamplers(bindingSlot, 1, &d3d11SamplerState);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BindingInfoType::Texture: {
|
||||
TextureView* view = ToBackend(group->GetBindingAsTextureView(bindingIndex));
|
||||
ComPtr<ID3D11ShaderResourceView> srv;
|
||||
DAWN_TRY_ASSIGN(srv, view->CreateD3D11ShaderResourceView());
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) {
|
||||
deviceContext1->VSSetShaderResources(bindingSlot, 1, srv.GetAddressOf());
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) {
|
||||
deviceContext1->PSSetShaderResources(bindingSlot, 1, srv.GetAddressOf());
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) {
|
||||
deviceContext1->CSSetShaderResources(bindingSlot, 1, srv.GetAddressOf());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BindingInfoType::StorageTexture: {
|
||||
return DAWN_UNIMPLEMENTED_ERROR("Storage textures are not supported");
|
||||
}
|
||||
|
||||
case BindingInfoType::ExternalTexture: {
|
||||
return DAWN_UNIMPLEMENTED_ERROR("External textures are not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void BindGroupTracker::UnApplyBindGroup(BindGroupIndex index) {
|
||||
ID3D11DeviceContext1* deviceContext1 = mCommandContext->GetD3D11DeviceContext1();
|
||||
BindGroupLayoutBase* groupLayout = mLastAppliedPipelineLayout->GetBindGroupLayout(index);
|
||||
const auto& indices = ToBackend(mLastAppliedPipelineLayout)->GetBindingIndexInfo()[index];
|
||||
|
||||
for (BindingIndex bindingIndex{0}; bindingIndex < groupLayout->GetBindingCount();
|
||||
++bindingIndex) {
|
||||
const BindingInfo& bindingInfo = groupLayout->GetBindingInfo(bindingIndex);
|
||||
const uint32_t bindingSlot = indices[bindingIndex];
|
||||
|
||||
switch (bindingInfo.bindingType) {
|
||||
case BindingInfoType::Buffer: {
|
||||
switch (bindingInfo.buffer.type) {
|
||||
case wgpu::BufferBindingType::Uniform: {
|
||||
ID3D11Buffer* nullBuffer = nullptr;
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) {
|
||||
deviceContext1->VSSetConstantBuffers1(bindingSlot, 1, &nullBuffer,
|
||||
nullptr, nullptr);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) {
|
||||
deviceContext1->PSSetConstantBuffers1(bindingSlot, 1, &nullBuffer,
|
||||
nullptr, nullptr);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) {
|
||||
deviceContext1->CSSetConstantBuffers1(bindingSlot, 1, &nullBuffer,
|
||||
nullptr, nullptr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case wgpu::BufferBindingType::Storage:
|
||||
case kInternalStorageBufferBinding: {
|
||||
ASSERT(IsSubset(bindingInfo.visibility, wgpu::ShaderStage::Compute));
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) {
|
||||
ID3D11UnorderedAccessView* nullUAV = nullptr;
|
||||
deviceContext1->CSSetUnorderedAccessViews(bindingSlot, 1, &nullUAV,
|
||||
nullptr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case wgpu::BufferBindingType::ReadOnlyStorage: {
|
||||
ID3D11ShaderResourceView* nullSRV = nullptr;
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) {
|
||||
deviceContext1->VSSetShaderResources(bindingSlot, 1, &nullSRV);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) {
|
||||
deviceContext1->PSSetShaderResources(bindingSlot, 1, &nullSRV);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) {
|
||||
deviceContext1->CSSetShaderResources(bindingSlot, 1, &nullSRV);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case wgpu::BufferBindingType::Undefined:
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BindingInfoType::Sampler: {
|
||||
ID3D11SamplerState* nullSampler = nullptr;
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) {
|
||||
deviceContext1->VSSetSamplers(bindingSlot, 1, &nullSampler);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) {
|
||||
deviceContext1->PSSetSamplers(bindingSlot, 1, &nullSampler);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) {
|
||||
deviceContext1->CSSetSamplers(bindingSlot, 1, &nullSampler);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BindingInfoType::Texture: {
|
||||
ID3D11ShaderResourceView* nullSRV = nullptr;
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) {
|
||||
deviceContext1->VSSetShaderResources(bindingSlot, 1, &nullSRV);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) {
|
||||
deviceContext1->PSSetShaderResources(bindingSlot, 1, &nullSRV);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) {
|
||||
deviceContext1->CSSetShaderResources(bindingSlot, 1, &nullSRV);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BindingInfoType::StorageTexture: {
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
|
||||
case BindingInfoType::ExternalTexture: {
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dawn::native::d3d11
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright 2023 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 SRC_DAWN_NATIVE_D3D11_BINDGROUPTRACKERD3D11_H_
|
||||
#define SRC_DAWN_NATIVE_D3D11_BINDGROUPTRACKERD3D11_H_
|
||||
|
||||
#include "dawn/native/BindGroupTracker.h"
|
||||
#include "dawn/native/d3d/d3d_platform.h"
|
||||
|
||||
namespace dawn::native::d3d11 {
|
||||
|
||||
class CommandRecordingContext;
|
||||
|
||||
// We need convert WebGPU bind slot to d3d11 bind slot according a map in PipelineLayout, so we
|
||||
// cannot inherit BindGroupTrackerGroups.
|
||||
class BindGroupTracker : public BindGroupTrackerBase</*CanInheritBindGroups=*/false, uint64_t> {
|
||||
public:
|
||||
explicit BindGroupTracker(CommandRecordingContext* commandContext);
|
||||
~BindGroupTracker();
|
||||
MaybeError Apply();
|
||||
|
||||
private:
|
||||
MaybeError ApplyBindGroup(BindGroupIndex index);
|
||||
void UnApplyBindGroup(BindGroupIndex index);
|
||||
|
||||
CommandRecordingContext* const mCommandContext;
|
||||
};
|
||||
|
||||
} // namespace dawn::native::d3d11
|
||||
|
||||
#endif // SRC_DAWN_NATIVE_D3D11_BINDGROUPTRACKERD3D11_H_
|
|
@ -20,8 +20,6 @@
|
|||
#include <vector>
|
||||
|
||||
#include "dawn/common/WindowsUtils.h"
|
||||
#include "dawn/native/BindGroup.h"
|
||||
#include "dawn/native/BindGroupTracker.h"
|
||||
#include "dawn/native/CommandEncoder.h"
|
||||
#include "dawn/native/CommandValidation.h"
|
||||
#include "dawn/native/Commands.h"
|
||||
|
@ -29,13 +27,12 @@
|
|||
#include "dawn/native/RenderBundle.h"
|
||||
#include "dawn/native/VertexFormat.h"
|
||||
#include "dawn/native/d3d/D3DError.h"
|
||||
#include "dawn/native/d3d11/BindGroupTrackerD3D11.h"
|
||||
#include "dawn/native/d3d11/BufferD3D11.h"
|
||||
#include "dawn/native/d3d11/ComputePipelineD3D11.h"
|
||||
#include "dawn/native/d3d11/DeviceD3D11.h"
|
||||
#include "dawn/native/d3d11/Forward.h"
|
||||
#include "dawn/native/d3d11/PipelineLayoutD3D11.h"
|
||||
#include "dawn/native/d3d11/RenderPipelineD3D11.h"
|
||||
#include "dawn/native/d3d11/SamplerD3D11.h"
|
||||
#include "dawn/native/d3d11/TextureD3D11.h"
|
||||
#include "dawn/native/d3d11/UtilsD3D11.h"
|
||||
|
||||
|
@ -53,174 +50,6 @@ DXGI_FORMAT DXGIIndexFormat(wgpu::IndexFormat format) {
|
|||
}
|
||||
}
|
||||
|
||||
class BindGroupTracker : public BindGroupTrackerBase<false, uint64_t> {
|
||||
public:
|
||||
MaybeError Apply(CommandRecordingContext* commandContext) {
|
||||
BeforeApply();
|
||||
for (BindGroupIndex index : IterateBitSet(mDirtyBindGroupsObjectChangedOrIsDynamic)) {
|
||||
DAWN_TRY(
|
||||
ApplyBindGroup(commandContext, index, mBindGroups[index], mDynamicOffsets[index]));
|
||||
}
|
||||
AfterApply();
|
||||
return {};
|
||||
}
|
||||
|
||||
void AfterDispatch(CommandRecordingContext* commandContext) {
|
||||
// Clear the UAVs after the dispatch, otherwise the buffer cannot be used as input in vertex
|
||||
// or pixel stage.
|
||||
for (UINT uav : mUnorderedAccessViews) {
|
||||
ID3D11UnorderedAccessView* nullUAV = nullptr;
|
||||
commandContext->GetD3D11DeviceContext1()->CSSetUnorderedAccessViews(uav, 1, &nullUAV,
|
||||
nullptr);
|
||||
}
|
||||
mUnorderedAccessViews.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
MaybeError ApplyBindGroup(CommandRecordingContext* commandContext,
|
||||
BindGroupIndex index,
|
||||
BindGroupBase* group,
|
||||
const ityp::vector<BindingIndex, uint64_t>& dynamicOffsets) {
|
||||
const auto& indices = ToBackend(mPipelineLayout)->GetBindingIndexInfo()[index];
|
||||
for (BindingIndex bindingIndex{0}; bindingIndex < group->GetLayout()->GetBindingCount();
|
||||
++bindingIndex) {
|
||||
const BindingInfo& bindingInfo = group->GetLayout()->GetBindingInfo(bindingIndex);
|
||||
const uint32_t bindingSlot = indices[bindingIndex];
|
||||
|
||||
switch (bindingInfo.bindingType) {
|
||||
case BindingInfoType::Buffer: {
|
||||
BufferBinding binding = group->GetBindingAsBufferBinding(bindingIndex);
|
||||
ID3D11Buffer* d3d11Buffer = ToBackend(binding.buffer)->GetD3D11Buffer();
|
||||
auto offset = binding.offset;
|
||||
if (bindingInfo.buffer.hasDynamicOffset) {
|
||||
// Dynamic buffers are packed at the front of BindingIndices.
|
||||
offset += dynamicOffsets[bindingIndex];
|
||||
}
|
||||
|
||||
auto* deviceContext = commandContext->GetD3D11DeviceContext1();
|
||||
|
||||
switch (bindingInfo.buffer.type) {
|
||||
case wgpu::BufferBindingType::Uniform: {
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/d3d11_1/nf-d3d11_1-id3d11devicecontext1-vssetconstantbuffers1
|
||||
// Offset and size are measured in shader constants, which are 16 bytes
|
||||
// (4*32-bit components). And the offsets and counts must be multiples
|
||||
// of 16.
|
||||
DAWN_ASSERT(IsAligned(offset, 256));
|
||||
uint32_t firstConstant = static_cast<uint32_t>(offset / 16);
|
||||
uint32_t size = static_cast<uint32_t>(Align(binding.size, 16) / 16);
|
||||
uint32_t numConstants = Align(size, 16);
|
||||
DAWN_ASSERT(offset + numConstants * 16 <=
|
||||
binding.buffer->GetAllocatedSize());
|
||||
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) {
|
||||
deviceContext->VSSetConstantBuffers1(bindingSlot, 1, &d3d11Buffer,
|
||||
&firstConstant, &numConstants);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) {
|
||||
deviceContext->PSSetConstantBuffers1(bindingSlot, 1, &d3d11Buffer,
|
||||
&firstConstant, &numConstants);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) {
|
||||
deviceContext->CSSetConstantBuffers1(bindingSlot, 1, &d3d11Buffer,
|
||||
&firstConstant, &numConstants);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case wgpu::BufferBindingType::Storage: {
|
||||
ComPtr<ID3D11UnorderedAccessView> d3d11UAV;
|
||||
DAWN_TRY_ASSIGN(d3d11UAV, ToBackend(binding.buffer)
|
||||
->CreateD3D11UnorderedAccessView1(
|
||||
0, binding.buffer->GetSize()));
|
||||
UINT firstElement = offset / 4;
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) {
|
||||
deviceContext->CSSetUnorderedAccessViews(
|
||||
bindingSlot, 1, d3d11UAV.GetAddressOf(), &firstElement);
|
||||
// Record the bounded UAVs so that we can clear them after the
|
||||
// dispatch.
|
||||
mUnorderedAccessViews.emplace_back(bindingSlot);
|
||||
} else {
|
||||
return DAWN_INTERNAL_ERROR(
|
||||
"Storage buffers are only supported in compute shaders");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case wgpu::BufferBindingType::ReadOnlyStorage: {
|
||||
ComPtr<ID3D11ShaderResourceView> d3d11SRV;
|
||||
DAWN_TRY_ASSIGN(d3d11SRV, ToBackend(binding.buffer)
|
||||
->CreateD3D11ShaderResourceView(
|
||||
offset, binding.size));
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) {
|
||||
deviceContext->VSSetShaderResources(bindingSlot, 1,
|
||||
d3d11SRV.GetAddressOf());
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) {
|
||||
deviceContext->PSSetShaderResources(bindingSlot, 1,
|
||||
d3d11SRV.GetAddressOf());
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) {
|
||||
deviceContext->CSSetShaderResources(bindingSlot, 1,
|
||||
d3d11SRV.GetAddressOf());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case wgpu::BufferBindingType::Undefined:
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BindingInfoType::Sampler: {
|
||||
Sampler* sampler = ToBackend(group->GetBindingAsSampler(bindingIndex));
|
||||
ID3D11SamplerState* d3d11SamplerState = sampler->GetD3D11SamplerState();
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) {
|
||||
commandContext->GetD3D11DeviceContext1()->VSSetSamplers(bindingSlot, 1,
|
||||
&d3d11SamplerState);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) {
|
||||
commandContext->GetD3D11DeviceContext1()->PSSetSamplers(bindingSlot, 1,
|
||||
&d3d11SamplerState);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) {
|
||||
commandContext->GetD3D11DeviceContext1()->CSSetSamplers(bindingSlot, 1,
|
||||
&d3d11SamplerState);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BindingInfoType::Texture: {
|
||||
TextureView* view = ToBackend(group->GetBindingAsTextureView(bindingIndex));
|
||||
ComPtr<ID3D11ShaderResourceView> srv;
|
||||
DAWN_TRY_ASSIGN(srv, view->CreateD3D11ShaderResourceView());
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) {
|
||||
commandContext->GetD3D11DeviceContext1()->VSSetShaderResources(
|
||||
bindingSlot, 1, srv.GetAddressOf());
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) {
|
||||
commandContext->GetD3D11DeviceContext1()->PSSetShaderResources(
|
||||
bindingSlot, 1, srv.GetAddressOf());
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) {
|
||||
commandContext->GetD3D11DeviceContext1()->CSSetShaderResources(
|
||||
bindingSlot, 1, srv.GetAddressOf());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BindingInfoType::StorageTexture: {
|
||||
return DAWN_UNIMPLEMENTED_ERROR("Storage textures are not supported");
|
||||
}
|
||||
|
||||
case BindingInfoType::ExternalTexture: {
|
||||
return DAWN_UNIMPLEMENTED_ERROR("External textures are not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<UINT> mUnorderedAccessViews;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// Create CommandBuffer
|
||||
|
@ -457,7 +286,7 @@ MaybeError CommandBuffer::Execute() {
|
|||
|
||||
MaybeError CommandBuffer::ExecuteComputePass(CommandRecordingContext* commandContext) {
|
||||
ComputePipeline* lastPipeline = nullptr;
|
||||
BindGroupTracker bindGroupTracker = {};
|
||||
BindGroupTracker bindGroupTracker(commandContext);
|
||||
|
||||
Command type;
|
||||
while (mCommands.NextCommandId(&type)) {
|
||||
|
@ -470,12 +299,11 @@ MaybeError CommandBuffer::ExecuteComputePass(CommandRecordingContext* commandCon
|
|||
case Command::Dispatch: {
|
||||
DispatchCmd* dispatch = mCommands.NextCommand<DispatchCmd>();
|
||||
|
||||
DAWN_TRY(bindGroupTracker.Apply(commandContext));
|
||||
DAWN_TRY(bindGroupTracker.Apply());
|
||||
|
||||
DAWN_TRY(RecordNumWorkgroupsForDispatch(lastPipeline, commandContext, dispatch));
|
||||
commandContext->GetD3D11DeviceContext()->Dispatch(dispatch->x, dispatch->y,
|
||||
dispatch->z);
|
||||
bindGroupTracker.AfterDispatch(commandContext);
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -484,7 +312,7 @@ MaybeError CommandBuffer::ExecuteComputePass(CommandRecordingContext* commandCon
|
|||
// TODO(1716): figure how to update num workgroups builtins
|
||||
DispatchIndirectCmd* dispatch = mCommands.NextCommand<DispatchIndirectCmd>();
|
||||
|
||||
DAWN_TRY(bindGroupTracker.Apply(commandContext));
|
||||
DAWN_TRY(bindGroupTracker.Apply());
|
||||
|
||||
uint64_t indirectBufferOffset = dispatch->indirectOffset;
|
||||
Buffer* indirectBuffer = ToBackend(dispatch->indirectBuffer.Get());
|
||||
|
@ -492,8 +320,6 @@ MaybeError CommandBuffer::ExecuteComputePass(CommandRecordingContext* commandCon
|
|||
commandContext->GetD3D11DeviceContext()->DispatchIndirect(
|
||||
indirectBuffer->GetD3D11Buffer(), indirectBufferOffset);
|
||||
|
||||
bindGroupTracker.AfterDispatch(commandContext);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -612,7 +438,7 @@ MaybeError CommandBuffer::ExecuteRenderPass(BeginRenderPassCmd* renderPass,
|
|||
d3d11DeviceContext1->RSSetScissorRects(1, &scissor);
|
||||
|
||||
RenderPipeline* lastPipeline = nullptr;
|
||||
BindGroupTracker bindGroupTracker = {};
|
||||
BindGroupTracker bindGroupTracker(commandContext);
|
||||
std::array<float, 4> blendColor = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
uint32_t stencilReference = 0;
|
||||
|
||||
|
@ -621,7 +447,7 @@ MaybeError CommandBuffer::ExecuteRenderPass(BeginRenderPassCmd* renderPass,
|
|||
case Command::Draw: {
|
||||
DrawCmd* draw = iter->NextCommand<DrawCmd>();
|
||||
|
||||
DAWN_TRY(bindGroupTracker.Apply(commandContext));
|
||||
DAWN_TRY(bindGroupTracker.Apply());
|
||||
DAWN_TRY(RecordFirstIndexOffset(lastPipeline, commandContext, draw->firstVertex,
|
||||
draw->firstInstance));
|
||||
commandContext->GetD3D11DeviceContext()->DrawInstanced(
|
||||
|
@ -633,7 +459,7 @@ MaybeError CommandBuffer::ExecuteRenderPass(BeginRenderPassCmd* renderPass,
|
|||
case Command::DrawIndexed: {
|
||||
DrawIndexedCmd* draw = iter->NextCommand<DrawIndexedCmd>();
|
||||
|
||||
DAWN_TRY(bindGroupTracker.Apply(commandContext));
|
||||
DAWN_TRY(bindGroupTracker.Apply());
|
||||
DAWN_TRY(RecordFirstIndexOffset(lastPipeline, commandContext, draw->baseVertex,
|
||||
draw->firstInstance));
|
||||
commandContext->GetD3D11DeviceContext()->DrawIndexedInstanced(
|
||||
|
@ -647,7 +473,7 @@ MaybeError CommandBuffer::ExecuteRenderPass(BeginRenderPassCmd* renderPass,
|
|||
// TODO(dawn:1716): figure how to setup built-in variables for indirect draw.
|
||||
DrawIndirectCmd* draw = iter->NextCommand<DrawIndirectCmd>();
|
||||
|
||||
DAWN_TRY(bindGroupTracker.Apply(commandContext));
|
||||
DAWN_TRY(bindGroupTracker.Apply());
|
||||
uint64_t indirectBufferOffset = draw->indirectOffset;
|
||||
Buffer* indirectBuffer = ToBackend(draw->indirectBuffer.Get());
|
||||
ASSERT(indirectBuffer != nullptr);
|
||||
|
@ -662,7 +488,7 @@ MaybeError CommandBuffer::ExecuteRenderPass(BeginRenderPassCmd* renderPass,
|
|||
// TODO(dawn:1716): figure how to setup built-in variables for indirect draw.
|
||||
DrawIndexedIndirectCmd* draw = iter->NextCommand<DrawIndexedIndirectCmd>();
|
||||
|
||||
DAWN_TRY(bindGroupTracker.Apply(commandContext));
|
||||
DAWN_TRY(bindGroupTracker.Apply());
|
||||
|
||||
Buffer* indirectBuffer = ToBackend(draw->indirectBuffer.Get());
|
||||
ASSERT(indirectBuffer != nullptr);
|
||||
|
@ -755,7 +581,7 @@ MaybeError CommandBuffer::ExecuteRenderPass(BeginRenderPassCmd* renderPass,
|
|||
if (lastPipeline) {
|
||||
lastPipeline->ApplyDepthStencilState(commandContext, stencilReference);
|
||||
}
|
||||
return {};
|
||||
break;
|
||||
}
|
||||
|
||||
case Command::SetViewport: {
|
||||
|
|
|
@ -156,7 +156,7 @@ MaybeError PhysicalDevice::InitializeSupportedLimitsImpl(CombinedLimits* limits)
|
|||
// Allocate half of the UAVs to storage buffers, and half to storage textures.
|
||||
limits->v1.maxStorageTexturesPerShaderStage = maxUAVsPerStage / 2;
|
||||
limits->v1.maxStorageBuffersPerShaderStage = maxUAVsPerStage - maxUAVsPerStage / 2;
|
||||
limits->v1.maxSampledTexturesPerShaderStage = D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT;
|
||||
limits->v1.maxSampledTexturesPerShaderStage = D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT;
|
||||
limits->v1.maxSamplersPerShaderStage = D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT;
|
||||
limits->v1.maxColorAttachments = D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT;
|
||||
|
||||
|
|
|
@ -50,9 +50,11 @@ MaybeError PipelineLayout::Initialize() {
|
|||
break;
|
||||
case wgpu::BufferBindingType::Storage:
|
||||
case kInternalStorageBufferBinding:
|
||||
case wgpu::BufferBindingType::ReadOnlyStorage:
|
||||
mIndexInfo[group][bindingIndex] = unorderedAccessViewIndex++;
|
||||
break;
|
||||
case wgpu::BufferBindingType::ReadOnlyStorage:
|
||||
mIndexInfo[group][bindingIndex] = shaderResourceViewIndex++;
|
||||
break;
|
||||
case wgpu::BufferBindingType::Undefined:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
|
|
@ -202,6 +202,9 @@ TEST_P(ComputeStorageBufferBarrierTests, StorageAndReadonlyStoragePingPongInOneP
|
|||
// Test that Storage to Uniform buffer transitions work and synchronize correctly
|
||||
// by ping-ponging between Storage/Uniform usage in sequential compute passes.
|
||||
TEST_P(ComputeStorageBufferBarrierTests, UniformToStorageAddPingPong) {
|
||||
// TODO(dawn:1721): D3D11 buffer cannot be uniform and storage at the same time.
|
||||
DAWN_SUPPRESS_TEST_IF(IsD3D11());
|
||||
|
||||
std::vector<uint32_t> data(kNumValues, 0);
|
||||
std::vector<uint32_t> expectedA(kNumValues, 0x1234 * kIterations);
|
||||
std::vector<uint32_t> expectedB(kNumValues, 0x1234 * (kIterations - 1));
|
||||
|
@ -270,6 +273,9 @@ TEST_P(ComputeStorageBufferBarrierTests, UniformToStorageAddPingPong) {
|
|||
// Test that Storage to Uniform buffer transitions work and synchronize correctly
|
||||
// by ping-ponging between Storage/Uniform usage in one compute pass.
|
||||
TEST_P(ComputeStorageBufferBarrierTests, UniformToStorageAddPingPongInOnePass) {
|
||||
// TODO(dawn:1721): D3D11 buffer cannot be uniform and storage at the same time.
|
||||
DAWN_SUPPRESS_TEST_IF(IsD3D11());
|
||||
|
||||
std::vector<uint32_t> data(kNumValues, 0);
|
||||
std::vector<uint32_t> expectedA(kNumValues, 0x1234 * kIterations);
|
||||
std::vector<uint32_t> expectedB(kNumValues, 0x1234 * (kIterations - 1));
|
||||
|
@ -409,6 +415,7 @@ TEST_P(ComputeStorageBufferBarrierTests, IndirectBufferCorrectBarrier) {
|
|||
}
|
||||
|
||||
DAWN_INSTANTIATE_TEST(ComputeStorageBufferBarrierTests,
|
||||
D3D11Backend(),
|
||||
D3D12Backend(),
|
||||
MetalBackend(),
|
||||
OpenGLBackend(),
|
||||
|
|
|
@ -129,6 +129,7 @@ TEST_P(DrawIndirectTest, IndirectOffset) {
|
|||
}
|
||||
|
||||
DAWN_INSTANTIATE_TEST(DrawIndirectTest,
|
||||
D3D11Backend(),
|
||||
D3D12Backend(),
|
||||
MetalBackend(),
|
||||
OpenGLBackend(),
|
||||
|
|
Loading…
Reference in New Issue