d3d11: enable DynamicBufferOffsetTests
This binds UAV slots all together at the same time. Bug: dawn:1816 Bug: dawn:1705 Change-Id: Iea7af9cf00caf126a3964cc43bbf2162b35f80e0 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/132600 Reviewed-by: Austin Eng <enga@chromium.org> Commit-Queue: Jie A Chen <jie.a.chen@intel.com> Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
parent
bfa1d3a870
commit
cd1fb68767
|
@ -266,6 +266,7 @@ MaybeError DeviceBase::Initialize(Ref<QueueBase> defaultQueue) {
|
|||
mState = State::Alive;
|
||||
|
||||
DAWN_TRY_ASSIGN(mEmptyBindGroupLayout, CreateEmptyBindGroupLayout());
|
||||
DAWN_TRY_ASSIGN(mEmptyPipelineLayout, CreateEmptyPipelineLayout());
|
||||
|
||||
// If placeholder fragment shader module is needed, initialize it
|
||||
if (IsToggleEnabled(Toggle::UsePlaceholderFragmentInVertexOnlyPipeline)) {
|
||||
|
@ -481,6 +482,7 @@ void DeviceBase::Destroy() {
|
|||
// Destroy() via APIGetQueue.
|
||||
mDynamicUploader = nullptr;
|
||||
mEmptyBindGroupLayout = nullptr;
|
||||
mEmptyPipelineLayout = nullptr;
|
||||
mInternalPipelineStore = nullptr;
|
||||
mExternalTexturePlaceholderView = nullptr;
|
||||
|
||||
|
@ -850,11 +852,24 @@ ResultOrError<Ref<BindGroupLayoutBase>> DeviceBase::CreateEmptyBindGroupLayout()
|
|||
return GetOrCreateBindGroupLayout(&desc);
|
||||
}
|
||||
|
||||
ResultOrError<Ref<PipelineLayoutBase>> DeviceBase::CreateEmptyPipelineLayout() {
|
||||
PipelineLayoutDescriptor desc = {};
|
||||
desc.bindGroupLayoutCount = 0;
|
||||
desc.bindGroupLayouts = nullptr;
|
||||
|
||||
return GetOrCreatePipelineLayout(&desc);
|
||||
}
|
||||
|
||||
BindGroupLayoutBase* DeviceBase::GetEmptyBindGroupLayout() {
|
||||
ASSERT(mEmptyBindGroupLayout != nullptr);
|
||||
return mEmptyBindGroupLayout.Get();
|
||||
}
|
||||
|
||||
PipelineLayoutBase* DeviceBase::GetEmptyPipelineLayout() {
|
||||
ASSERT(mEmptyPipelineLayout != nullptr);
|
||||
return mEmptyPipelineLayout.Get();
|
||||
}
|
||||
|
||||
Ref<ComputePipelineBase> DeviceBase::GetCachedComputePipeline(
|
||||
ComputePipelineBase* uninitializedComputePipeline) {
|
||||
Ref<ComputePipelineBase> cachedPipeline;
|
||||
|
|
|
@ -197,6 +197,7 @@ class DeviceBase : public RefCountedWithExternalCount {
|
|||
void UncacheBindGroupLayout(BindGroupLayoutBase* obj);
|
||||
|
||||
BindGroupLayoutBase* GetEmptyBindGroupLayout();
|
||||
PipelineLayoutBase* GetEmptyPipelineLayout();
|
||||
|
||||
void UncacheComputePipeline(ComputePipelineBase* obj);
|
||||
|
||||
|
@ -506,6 +507,7 @@ class DeviceBase : public RefCountedWithExternalCount {
|
|||
void FlushCallbackTaskQueue();
|
||||
|
||||
ResultOrError<Ref<BindGroupLayoutBase>> CreateEmptyBindGroupLayout();
|
||||
ResultOrError<Ref<PipelineLayoutBase>> CreateEmptyPipelineLayout();
|
||||
|
||||
Ref<ComputePipelineBase> GetCachedComputePipeline(
|
||||
ComputePipelineBase* uninitializedComputePipeline);
|
||||
|
@ -588,6 +590,7 @@ class DeviceBase : public RefCountedWithExternalCount {
|
|||
std::unique_ptr<Caches> mCaches;
|
||||
|
||||
Ref<BindGroupLayoutBase> mEmptyBindGroupLayout;
|
||||
Ref<PipelineLayoutBase> mEmptyPipelineLayout;
|
||||
|
||||
Ref<TextureViewBase> mExternalTexturePlaceholderView;
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "dawn/native/d3d11/BindGroupTrackerD3D11.h"
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "dawn/common/Assert.h"
|
||||
#include "dawn/native/Format.h"
|
||||
#include "dawn/native/d3d/D3DError.h"
|
||||
|
@ -68,23 +71,64 @@ bool CheckAllSlotsAreEmpty(CommandRecordingContext* commandContext) {
|
|||
ASSERT(sampler == nullptr);
|
||||
}
|
||||
|
||||
// Check UAV slots
|
||||
// Check UAV slots for compute
|
||||
for (UINT slot = 0; slot < D3D11_1_UAV_SLOT_COUNT; ++slot) {
|
||||
ID3D11UnorderedAccessView* uav = nullptr;
|
||||
deviceContext1->CSGetUnorderedAccessViews(slot, 1, &uav);
|
||||
ASSERT(uav == nullptr);
|
||||
}
|
||||
// Check UAV slots for render
|
||||
for (UINT slot = 0; slot < commandContext->GetDevice()->GetUAVSlotCount(); ++slot) {
|
||||
ID3D11UnorderedAccessView* uav = nullptr;
|
||||
deviceContext1->OMGetRenderTargetsAndUnorderedAccessViews(0, nullptr, nullptr, slot, 1,
|
||||
&uav);
|
||||
ASSERT(uav == nullptr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ResetAllRenderSlots(CommandRecordingContext* commandContext) {
|
||||
ID3D11DeviceContext1* deviceContext1 = commandContext->GetD3D11DeviceContext1();
|
||||
|
||||
// Reserve one slot for builtin constants.
|
||||
constexpr uint32_t kReservedCBVSlots = 1;
|
||||
|
||||
ID3D11Buffer* d3d11Buffers[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {};
|
||||
uint32_t num = D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT - kReservedCBVSlots;
|
||||
deviceContext1->VSSetConstantBuffers1(0, num, d3d11Buffers, nullptr, nullptr);
|
||||
deviceContext1->PSSetConstantBuffers1(0, num, d3d11Buffers, nullptr, nullptr);
|
||||
|
||||
ID3D11ShaderResourceView* d3d11SRVs[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT] = {};
|
||||
num = D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT;
|
||||
deviceContext1->VSSetShaderResources(0, num, d3d11SRVs);
|
||||
deviceContext1->PSSetShaderResources(0, num, d3d11SRVs);
|
||||
|
||||
ID3D11SamplerState* d3d11Samplers[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT] = {};
|
||||
num = D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT;
|
||||
deviceContext1->VSSetSamplers(0, num, d3d11Samplers);
|
||||
deviceContext1->PSSetSamplers(0, num, d3d11Samplers);
|
||||
|
||||
ID3D11UnorderedAccessView* d3d11UAVs[D3D11_1_UAV_SLOT_COUNT] = {};
|
||||
num = commandContext->GetDevice()->GetUAVSlotCount();
|
||||
deviceContext1->OMSetRenderTargetsAndUnorderedAccessViews(
|
||||
D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, nullptr, nullptr, 0, num, d3d11UAVs, nullptr);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
BindGroupTracker::BindGroupTracker(CommandRecordingContext* commandContext)
|
||||
: mCommandContext(commandContext) {}
|
||||
BindGroupTracker::BindGroupTracker(CommandRecordingContext* commandContext, bool isRenderPass)
|
||||
: mCommandContext(commandContext),
|
||||
mIsRenderPass(isRenderPass),
|
||||
mVisibleStages(isRenderPass ? wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment
|
||||
: wgpu::ShaderStage::Compute) {
|
||||
mLastAppliedPipelineLayout = commandContext->GetDevice()->GetEmptyPipelineLayout();
|
||||
}
|
||||
|
||||
BindGroupTracker::~BindGroupTracker() {
|
||||
if (mLastAppliedPipelineLayout) {
|
||||
if (mIsRenderPass) {
|
||||
ResetAllRenderSlots(mCommandContext);
|
||||
} else {
|
||||
for (BindGroupIndex index :
|
||||
IterateBitSet(mLastAppliedPipelineLayout->GetBindGroupLayoutsMask())) {
|
||||
UnApplyBindGroup(index);
|
||||
|
@ -97,15 +141,93 @@ BindGroupTracker::~BindGroupTracker() {
|
|||
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 lastGroups = mLastAppliedPipelineLayout->GetBindGroupLayoutsMask();
|
||||
BindGroupLayoutMask currentGroups = mPipelineLayout->GetBindGroupLayoutsMask();
|
||||
BindGroupLayoutMask unApplyGroups = (mDirtyBindGroups | ~currentGroups) & lastGroups;
|
||||
// Unset bind groups which are not used by the new pipeline and are not inherited.
|
||||
for (BindGroupIndex index : IterateBitSet(unApplyGroups)) {
|
||||
if (mIsRenderPass) {
|
||||
// As D3d11 requires to bind all UAVs slots at the same time for pixel shaders, we record
|
||||
// all UAV slot assignments in the bind groups, and then bind them all together.
|
||||
const BindGroupLayoutMask uavBindGroups =
|
||||
ToBackend(mPipelineLayout)->GetUAVBindGroupLayoutsMask();
|
||||
std::vector<ComPtr<ID3D11UnorderedAccessView>> d3d11UAVs;
|
||||
for (BindGroupIndex index : IterateBitSet(uavBindGroups)) {
|
||||
BindGroupBase* group = mBindGroups[index];
|
||||
const ityp::vector<BindingIndex, uint64_t>& dynamicOffsets = mDynamicOffsets[index];
|
||||
|
||||
for (BindingIndex bindingIndex{0}; bindingIndex < group->GetLayout()->GetBindingCount();
|
||||
++bindingIndex) {
|
||||
const BindingInfo& bindingInfo = group->GetLayout()->GetBindingInfo(bindingIndex);
|
||||
|
||||
switch (bindingInfo.bindingType) {
|
||||
case BindingInfoType::Buffer: {
|
||||
BufferBinding binding = group->GetBindingAsBufferBinding(bindingIndex);
|
||||
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::Storage:
|
||||
case kInternalStorageBufferBinding: {
|
||||
ASSERT(IsSubset(
|
||||
bindingInfo.visibility,
|
||||
wgpu::ShaderStage::Fragment | wgpu::ShaderStage::Compute));
|
||||
ComPtr<ID3D11UnorderedAccessView> d3d11UAV;
|
||||
DAWN_TRY_ASSIGN(d3d11UAV, ToBackend(binding.buffer)
|
||||
->CreateD3D11UnorderedAccessView1(
|
||||
offset, binding.size));
|
||||
ToBackend(binding.buffer)->MarkMutated();
|
||||
d3d11UAVs.insert(d3d11UAVs.begin(), std::move(d3d11UAV));
|
||||
break;
|
||||
}
|
||||
case wgpu::BufferBindingType::Uniform:
|
||||
case wgpu::BufferBindingType::ReadOnlyStorage:
|
||||
case wgpu::BufferBindingType::Undefined: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case BindingInfoType::StorageTexture: {
|
||||
ASSERT(bindingInfo.storageTexture.access ==
|
||||
wgpu::StorageTextureAccess::WriteOnly);
|
||||
ComPtr<ID3D11UnorderedAccessView> d3d11UAV;
|
||||
TextureView* view = ToBackend(group->GetBindingAsTextureView(bindingIndex));
|
||||
DAWN_TRY_ASSIGN(d3d11UAV, view->CreateD3D11UnorderedAccessView());
|
||||
d3d11UAVs.insert(d3d11UAVs.begin(), std::move(d3d11UAV));
|
||||
break;
|
||||
}
|
||||
case BindingInfoType::Texture:
|
||||
case BindingInfoType::ExternalTexture:
|
||||
case BindingInfoType::Sampler: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
uint32_t uavSlotCount = ToBackend(mPipelineLayout->GetDevice())->GetUAVSlotCount();
|
||||
std::vector<ID3D11UnorderedAccessView*> views;
|
||||
for (auto& uav : d3d11UAVs) {
|
||||
views.push_back(uav.Get());
|
||||
}
|
||||
mCommandContext->GetD3D11DeviceContext1()->OMSetRenderTargetsAndUnorderedAccessViews(
|
||||
D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, nullptr, nullptr,
|
||||
uavSlotCount - d3d11UAVs.size(), d3d11UAVs.size(), views.data(), nullptr);
|
||||
d3d11UAVs.clear();
|
||||
} else {
|
||||
BindGroupLayoutMask inheritedGroups =
|
||||
mPipelineLayout->InheritedGroupsMask(mLastAppliedPipelineLayout);
|
||||
BindGroupLayoutMask previousGroups = mLastAppliedPipelineLayout->GetBindGroupLayoutsMask();
|
||||
|
||||
// To avoid UAV / SRV conflicts with bindings in previously bind groups, we unset the bind
|
||||
// groups that aren't reused by the current pipeline.
|
||||
// We also need to unset the inherited bind groups which are dirty as the group may have
|
||||
// both SRV and UAV, and the same resource may change its binding from UAV to SRV next
|
||||
// dispatch in the same group.
|
||||
//
|
||||
// Note: WebGPU API guarantees that resources are not used both as UAV and SRV in the same
|
||||
// render pass. So we don't need to do this inside render passes.
|
||||
BindGroupLayoutMask groupsToUnset = previousGroups & (~inheritedGroups | mDirtyBindGroups);
|
||||
for (BindGroupIndex index : IterateBitSet(groupsToUnset)) {
|
||||
UnApplyBindGroup(index);
|
||||
}
|
||||
}
|
||||
|
@ -129,6 +251,7 @@ MaybeError BindGroupTracker::ApplyBindGroup(BindGroupIndex index) {
|
|||
++bindingIndex) {
|
||||
const BindingInfo& bindingInfo = group->GetLayout()->GetBindingInfo(bindingIndex);
|
||||
const uint32_t bindingSlot = indices[bindingIndex];
|
||||
const auto bindingVisibility = bindingInfo.visibility & mVisibleStages;
|
||||
|
||||
switch (bindingInfo.bindingType) {
|
||||
case BindingInfoType::Buffer: {
|
||||
|
@ -156,15 +279,15 @@ MaybeError BindGroupTracker::ApplyBindGroup(BindGroupIndex index) {
|
|||
DAWN_ASSERT(offset + numConstants * 16 <=
|
||||
binding.buffer->GetAllocatedSize());
|
||||
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Vertex) {
|
||||
deviceContext1->VSSetConstantBuffers1(bindingSlot, 1, &d3d11Buffer,
|
||||
&firstConstant, &numConstants);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Fragment) {
|
||||
deviceContext1->PSSetConstantBuffers1(bindingSlot, 1, &d3d11Buffer,
|
||||
&firstConstant, &numConstants);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Compute) {
|
||||
deviceContext1->CSSetConstantBuffers1(bindingSlot, 1, &d3d11Buffer,
|
||||
&firstConstant, &numConstants);
|
||||
}
|
||||
|
@ -174,17 +297,12 @@ MaybeError BindGroupTracker::ApplyBindGroup(BindGroupIndex index) {
|
|||
case kInternalStorageBufferBinding: {
|
||||
ASSERT(IsSubset(bindingInfo.visibility,
|
||||
wgpu::ShaderStage::Fragment | wgpu::ShaderStage::Compute));
|
||||
ComPtr<ID3D11UnorderedAccessView> d3d11UAV;
|
||||
DAWN_TRY_ASSIGN(
|
||||
d3d11UAV, ToBackend(binding.buffer)
|
||||
->CreateD3D11UnorderedAccessView1(offset, binding.size));
|
||||
ToBackend(binding.buffer)->MarkMutated();
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) {
|
||||
deviceContext1->OMSetRenderTargetsAndUnorderedAccessViews(
|
||||
D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, nullptr, nullptr,
|
||||
bindingSlot, 1, d3d11UAV.GetAddressOf(), nullptr);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Compute) {
|
||||
ComPtr<ID3D11UnorderedAccessView> d3d11UAV;
|
||||
DAWN_TRY_ASSIGN(d3d11UAV, ToBackend(binding.buffer)
|
||||
->CreateD3D11UnorderedAccessView1(
|
||||
offset, binding.size));
|
||||
ToBackend(binding.buffer)->MarkMutated();
|
||||
deviceContext1->CSSetUnorderedAccessViews(
|
||||
bindingSlot, 1, d3d11UAV.GetAddressOf(), nullptr);
|
||||
}
|
||||
|
@ -195,15 +313,15 @@ MaybeError BindGroupTracker::ApplyBindGroup(BindGroupIndex index) {
|
|||
DAWN_TRY_ASSIGN(d3d11SRV,
|
||||
ToBackend(binding.buffer)
|
||||
->CreateD3D11ShaderResourceView(offset, binding.size));
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Vertex) {
|
||||
deviceContext1->VSSetShaderResources(bindingSlot, 1,
|
||||
d3d11SRV.GetAddressOf());
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Fragment) {
|
||||
deviceContext1->PSSetShaderResources(bindingSlot, 1,
|
||||
d3d11SRV.GetAddressOf());
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Compute) {
|
||||
deviceContext1->CSSetShaderResources(bindingSlot, 1,
|
||||
d3d11SRV.GetAddressOf());
|
||||
}
|
||||
|
@ -218,13 +336,13 @@ MaybeError BindGroupTracker::ApplyBindGroup(BindGroupIndex index) {
|
|||
case BindingInfoType::Sampler: {
|
||||
Sampler* sampler = ToBackend(group->GetBindingAsSampler(bindingIndex));
|
||||
ID3D11SamplerState* d3d11SamplerState = sampler->GetD3D11SamplerState();
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Vertex) {
|
||||
deviceContext1->VSSetSamplers(bindingSlot, 1, &d3d11SamplerState);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Fragment) {
|
||||
deviceContext1->PSSetSamplers(bindingSlot, 1, &d3d11SamplerState);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Compute) {
|
||||
deviceContext1->CSSetSamplers(bindingSlot, 1, &d3d11SamplerState);
|
||||
}
|
||||
break;
|
||||
|
@ -234,13 +352,13 @@ MaybeError BindGroupTracker::ApplyBindGroup(BindGroupIndex index) {
|
|||
TextureView* view = ToBackend(group->GetBindingAsTextureView(bindingIndex));
|
||||
ComPtr<ID3D11ShaderResourceView> srv;
|
||||
DAWN_TRY_ASSIGN(srv, view->CreateD3D11ShaderResourceView());
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Vertex) {
|
||||
deviceContext1->VSSetShaderResources(bindingSlot, 1, srv.GetAddressOf());
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Fragment) {
|
||||
deviceContext1->PSSetShaderResources(bindingSlot, 1, srv.GetAddressOf());
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Compute) {
|
||||
deviceContext1->CSSetShaderResources(bindingSlot, 1, srv.GetAddressOf());
|
||||
}
|
||||
break;
|
||||
|
@ -248,15 +366,10 @@ MaybeError BindGroupTracker::ApplyBindGroup(BindGroupIndex index) {
|
|||
|
||||
case BindingInfoType::StorageTexture: {
|
||||
ASSERT(bindingInfo.storageTexture.access == wgpu::StorageTextureAccess::WriteOnly);
|
||||
ComPtr<ID3D11UnorderedAccessView> d3d11UAV;
|
||||
TextureView* view = ToBackend(group->GetBindingAsTextureView(bindingIndex));
|
||||
DAWN_TRY_ASSIGN(d3d11UAV, view->CreateD3D11UnorderedAccessView());
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) {
|
||||
deviceContext1->OMSetRenderTargetsAndUnorderedAccessViews(
|
||||
D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, nullptr, nullptr, bindingSlot,
|
||||
1, d3d11UAV.GetAddressOf(), nullptr);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Compute) {
|
||||
ComPtr<ID3D11UnorderedAccessView> d3d11UAV;
|
||||
TextureView* view = ToBackend(group->GetBindingAsTextureView(bindingIndex));
|
||||
DAWN_TRY_ASSIGN(d3d11UAV, view->CreateD3D11UnorderedAccessView());
|
||||
deviceContext1->CSSetUnorderedAccessViews(bindingSlot, 1,
|
||||
d3d11UAV.GetAddressOf(), nullptr);
|
||||
}
|
||||
|
@ -280,21 +393,22 @@ void BindGroupTracker::UnApplyBindGroup(BindGroupIndex index) {
|
|||
++bindingIndex) {
|
||||
const BindingInfo& bindingInfo = groupLayout->GetBindingInfo(bindingIndex);
|
||||
const uint32_t bindingSlot = indices[bindingIndex];
|
||||
const auto bindingVisibility = bindingInfo.visibility & mVisibleStages;
|
||||
|
||||
switch (bindingInfo.bindingType) {
|
||||
case BindingInfoType::Buffer: {
|
||||
switch (bindingInfo.buffer.type) {
|
||||
case wgpu::BufferBindingType::Uniform: {
|
||||
ID3D11Buffer* nullBuffer = nullptr;
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Vertex) {
|
||||
deviceContext1->VSSetConstantBuffers1(bindingSlot, 1, &nullBuffer,
|
||||
nullptr, nullptr);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Fragment) {
|
||||
deviceContext1->PSSetConstantBuffers1(bindingSlot, 1, &nullBuffer,
|
||||
nullptr, nullptr);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Compute) {
|
||||
deviceContext1->CSSetConstantBuffers1(bindingSlot, 1, &nullBuffer,
|
||||
nullptr, nullptr);
|
||||
}
|
||||
|
@ -305,12 +419,12 @@ void BindGroupTracker::UnApplyBindGroup(BindGroupIndex index) {
|
|||
ASSERT(IsSubset(bindingInfo.visibility,
|
||||
wgpu::ShaderStage::Fragment | wgpu::ShaderStage::Compute));
|
||||
ID3D11UnorderedAccessView* nullUAV = nullptr;
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Fragment) {
|
||||
deviceContext1->OMSetRenderTargetsAndUnorderedAccessViews(
|
||||
D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, nullptr, nullptr,
|
||||
bindingSlot, 1, &nullUAV, nullptr);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Compute) {
|
||||
deviceContext1->CSSetUnorderedAccessViews(bindingSlot, 1, &nullUAV,
|
||||
nullptr);
|
||||
}
|
||||
|
@ -318,13 +432,13 @@ void BindGroupTracker::UnApplyBindGroup(BindGroupIndex index) {
|
|||
}
|
||||
case wgpu::BufferBindingType::ReadOnlyStorage: {
|
||||
ID3D11ShaderResourceView* nullSRV = nullptr;
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Vertex) {
|
||||
deviceContext1->VSSetShaderResources(bindingSlot, 1, &nullSRV);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Fragment) {
|
||||
deviceContext1->PSSetShaderResources(bindingSlot, 1, &nullSRV);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Compute) {
|
||||
deviceContext1->CSSetShaderResources(bindingSlot, 1, &nullSRV);
|
||||
}
|
||||
break;
|
||||
|
@ -337,13 +451,13 @@ void BindGroupTracker::UnApplyBindGroup(BindGroupIndex index) {
|
|||
|
||||
case BindingInfoType::Sampler: {
|
||||
ID3D11SamplerState* nullSampler = nullptr;
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Vertex) {
|
||||
deviceContext1->VSSetSamplers(bindingSlot, 1, &nullSampler);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Fragment) {
|
||||
deviceContext1->PSSetSamplers(bindingSlot, 1, &nullSampler);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Compute) {
|
||||
deviceContext1->CSSetSamplers(bindingSlot, 1, &nullSampler);
|
||||
}
|
||||
break;
|
||||
|
@ -351,13 +465,13 @@ void BindGroupTracker::UnApplyBindGroup(BindGroupIndex index) {
|
|||
|
||||
case BindingInfoType::Texture: {
|
||||
ID3D11ShaderResourceView* nullSRV = nullptr;
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Vertex) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Vertex) {
|
||||
deviceContext1->VSSetShaderResources(bindingSlot, 1, &nullSRV);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Fragment) {
|
||||
deviceContext1->PSSetShaderResources(bindingSlot, 1, &nullSRV);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Compute) {
|
||||
deviceContext1->CSSetShaderResources(bindingSlot, 1, &nullSRV);
|
||||
}
|
||||
break;
|
||||
|
@ -366,12 +480,12 @@ void BindGroupTracker::UnApplyBindGroup(BindGroupIndex index) {
|
|||
case BindingInfoType::StorageTexture: {
|
||||
ASSERT(bindingInfo.storageTexture.access == wgpu::StorageTextureAccess::WriteOnly);
|
||||
ID3D11UnorderedAccessView* nullUAV = nullptr;
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Fragment) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Fragment) {
|
||||
deviceContext1->OMSetRenderTargetsAndUnorderedAccessViews(
|
||||
D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, nullptr, nullptr, bindingSlot,
|
||||
1, &nullUAV, nullptr);
|
||||
}
|
||||
if (bindingInfo.visibility & wgpu::ShaderStage::Compute) {
|
||||
if (bindingVisibility & wgpu::ShaderStage::Compute) {
|
||||
deviceContext1->CSSetUnorderedAccessViews(bindingSlot, 1, &nullUAV, nullptr);
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -24,9 +24,9 @@ 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> {
|
||||
class BindGroupTracker : public BindGroupTrackerBase</*CanInheritBindGroups=*/true, uint64_t> {
|
||||
public:
|
||||
explicit BindGroupTracker(CommandRecordingContext* commandContext);
|
||||
BindGroupTracker(CommandRecordingContext* commandContext, bool isRenderPass);
|
||||
~BindGroupTracker();
|
||||
MaybeError Apply();
|
||||
|
||||
|
@ -35,6 +35,8 @@ class BindGroupTracker : public BindGroupTrackerBase</*CanInheritBindGroups=*/fa
|
|||
void UnApplyBindGroup(BindGroupIndex index);
|
||||
|
||||
CommandRecordingContext* const mCommandContext;
|
||||
const bool mIsRenderPass;
|
||||
const wgpu::ShaderStage mVisibleStages;
|
||||
};
|
||||
|
||||
} // namespace dawn::native::d3d11
|
||||
|
|
|
@ -322,7 +322,7 @@ MaybeError CommandBuffer::Execute() {
|
|||
|
||||
MaybeError CommandBuffer::ExecuteComputePass(CommandRecordingContext* commandContext) {
|
||||
ComputePipeline* lastPipeline = nullptr;
|
||||
BindGroupTracker bindGroupTracker(commandContext);
|
||||
BindGroupTracker bindGroupTracker(commandContext, /*isRenderPass=*/false);
|
||||
|
||||
Command type;
|
||||
while (mCommands.NextCommandId(&type)) {
|
||||
|
@ -481,7 +481,7 @@ MaybeError CommandBuffer::ExecuteRenderPass(BeginRenderPassCmd* renderPass,
|
|||
d3d11DeviceContext1->RSSetScissorRects(1, &scissor);
|
||||
|
||||
RenderPipeline* lastPipeline = nullptr;
|
||||
BindGroupTracker bindGroupTracker(commandContext);
|
||||
BindGroupTracker bindGroupTracker(commandContext, /*isRenderPass=*/true);
|
||||
VertexBufferTracker vertexBufferTracker(commandContext);
|
||||
std::array<float, 4> blendColor = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
uint32_t stencilReference = 0;
|
||||
|
|
|
@ -30,6 +30,7 @@ namespace dawn::native::d3d11 {
|
|||
MaybeError CommandRecordingContext::Open(Device* device) {
|
||||
ASSERT(!IsOpen());
|
||||
ASSERT(device);
|
||||
mDevice = device;
|
||||
|
||||
if (!mD3D11DeviceContext4) {
|
||||
ID3D11Device* d3d11Device = device->GetD3D11Device();
|
||||
|
@ -106,11 +107,17 @@ Buffer* CommandRecordingContext::GetUniformBuffer() const {
|
|||
return mUniformBuffer.Get();
|
||||
}
|
||||
|
||||
Device* CommandRecordingContext::GetDevice() const {
|
||||
ASSERT(mDevice.Get());
|
||||
return mDevice.Get();
|
||||
}
|
||||
|
||||
void CommandRecordingContext::Release() {
|
||||
if (mIsOpen) {
|
||||
mIsOpen = false;
|
||||
mNeedsSubmit = false;
|
||||
mUniformBuffer = nullptr;
|
||||
mDevice = nullptr;
|
||||
ID3D11Buffer* nullBuffer = nullptr;
|
||||
mD3D11DeviceContext4->VSSetConstantBuffers(PipelineLayout::kReservedConstantBufferSlot, 1,
|
||||
&nullBuffer);
|
||||
|
|
|
@ -41,6 +41,7 @@ class CommandRecordingContext {
|
|||
ID3D11DeviceContext4* GetD3D11DeviceContext4() const;
|
||||
ID3DUserDefinedAnnotation* GetD3DUserDefinedAnnotation() const;
|
||||
Buffer* GetUniformBuffer() const;
|
||||
Device* GetDevice() const;
|
||||
|
||||
private:
|
||||
bool mIsOpen = false;
|
||||
|
@ -50,6 +51,7 @@ class CommandRecordingContext {
|
|||
ComPtr<ID3DUserDefinedAnnotation> mD3D11UserDefinedAnnotation;
|
||||
// The uniform buffer for built in variables.
|
||||
Ref<Buffer> mUniformBuffer;
|
||||
Ref<Device> mDevice;
|
||||
};
|
||||
|
||||
} // namespace dawn::native::d3d11
|
||||
|
|
|
@ -468,4 +468,8 @@ Ref<TextureBase> Device::CreateD3DExternalTexture(const TextureDescriptor* descr
|
|||
return {dawnTexture};
|
||||
}
|
||||
|
||||
uint32_t Device::GetUAVSlotCount() const {
|
||||
return ToBackend(GetPhysicalDevice())->GetUAVSlotCount();
|
||||
}
|
||||
|
||||
} // namespace dawn::native::d3d11
|
||||
|
|
|
@ -83,6 +83,8 @@ class Device final : public d3d::Device {
|
|||
ResultOrError<std::unique_ptr<d3d::ExternalImageDXGIImpl>> CreateExternalImageDXGIImplImpl(
|
||||
const d3d::ExternalImageDescriptorDXGISharedHandle* descriptor) override;
|
||||
|
||||
uint32_t GetUAVSlotCount() const;
|
||||
|
||||
private:
|
||||
using Base = d3d::Device;
|
||||
using Base::Base;
|
||||
|
|
|
@ -147,6 +147,7 @@ MaybeError PhysicalDevice::InitializeSupportedLimitsImpl(CombinedLimits* limits)
|
|||
uint32_t maxUAVsAllStages = mFeatureLevel == D3D_FEATURE_LEVEL_11_1
|
||||
? D3D11_1_UAV_SLOT_COUNT
|
||||
: D3D11_PS_CS_UAV_REGISTER_COUNT;
|
||||
mUAVSlotCount = maxUAVsAllStages;
|
||||
ASSERT(maxUAVsAllStages / 4 > limits->v1.maxStorageTexturesPerShaderStage);
|
||||
ASSERT(maxUAVsAllStages / 4 > limits->v1.maxStorageBuffersPerShaderStage);
|
||||
uint32_t maxUAVsPerStage = maxUAVsAllStages / 2;
|
||||
|
|
|
@ -37,6 +37,8 @@ class PhysicalDevice : public d3d::PhysicalDevice {
|
|||
const DeviceInfo& GetDeviceInfo() const;
|
||||
ResultOrError<ComPtr<ID3D11Device>> CreateD3D11Device();
|
||||
|
||||
uint32_t GetUAVSlotCount() const { return mUAVSlotCount; }
|
||||
|
||||
private:
|
||||
using Base = d3d::PhysicalDevice;
|
||||
|
||||
|
@ -57,6 +59,7 @@ class PhysicalDevice : public d3d::PhysicalDevice {
|
|||
ComPtr<ID3D11Device> mD3d11Device;
|
||||
D3D_FEATURE_LEVEL mFeatureLevel;
|
||||
DeviceInfo mDeviceInfo = {};
|
||||
uint32_t mUAVSlotCount;
|
||||
};
|
||||
|
||||
} // namespace dawn::native::d3d11
|
||||
|
|
|
@ -37,10 +37,7 @@ MaybeError PipelineLayout::Initialize(Device* device) {
|
|||
// resource slots when being written out. So we assign UAV binding index decreasingly here.
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/d3d11/nf-d3d11-id3d11devicecontext-omsetrendertargetsandunorderedaccessviews
|
||||
// TODO(dawn:1818): Support testing on both FL11_0 and FL11_1.
|
||||
uint32_t unorderedAccessViewIndex =
|
||||
device->GetD3D11Device()->GetFeatureLevel() == D3D_FEATURE_LEVEL_11_1
|
||||
? D3D11_1_UAV_SLOT_COUNT
|
||||
: D3D11_PS_CS_UAV_REGISTER_COUNT;
|
||||
uint32_t unorderedAccessViewIndex = device->GetUAVSlotCount();
|
||||
mTotalUAVBindingCount = unorderedAccessViewIndex;
|
||||
|
||||
for (BindGroupIndex group : IterateBitSet(GetBindGroupLayoutsMask())) {
|
||||
|
@ -58,6 +55,7 @@ MaybeError PipelineLayout::Initialize(Device* device) {
|
|||
case wgpu::BufferBindingType::Storage:
|
||||
case kInternalStorageBufferBinding:
|
||||
mIndexInfo[group][bindingIndex] = --unorderedAccessViewIndex;
|
||||
mUAVBindGroups.set(group);
|
||||
break;
|
||||
case wgpu::BufferBindingType::ReadOnlyStorage:
|
||||
mIndexInfo[group][bindingIndex] = shaderResourceViewIndex++;
|
||||
|
@ -78,6 +76,7 @@ MaybeError PipelineLayout::Initialize(Device* device) {
|
|||
|
||||
case BindingInfoType::StorageTexture:
|
||||
mIndexInfo[group][bindingIndex] = --unorderedAccessViewIndex;
|
||||
mUAVBindGroups.set(group);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -91,4 +90,8 @@ const PipelineLayout::BindingIndexInfo& PipelineLayout::GetBindingIndexInfo() co
|
|||
return mIndexInfo;
|
||||
}
|
||||
|
||||
const BindGroupLayoutMask& PipelineLayout::GetUAVBindGroupLayoutsMask() const {
|
||||
return mUAVBindGroups;
|
||||
}
|
||||
|
||||
} // namespace dawn::native::d3d11
|
||||
|
|
|
@ -51,6 +51,9 @@ class PipelineLayout final : public PipelineLayoutBase {
|
|||
uint32_t GetUnusedUAVBindingCount() const { return mUnusedUAVBindingCount; }
|
||||
uint32_t GetTotalUAVBindingCount() const { return mTotalUAVBindingCount; }
|
||||
|
||||
// Get the bind groups that use one or more UAV slots.
|
||||
const BindGroupLayoutMask& GetUAVBindGroupLayoutsMask() const;
|
||||
|
||||
private:
|
||||
using PipelineLayoutBase::PipelineLayoutBase;
|
||||
|
||||
|
@ -62,6 +65,7 @@ class PipelineLayout final : public PipelineLayoutBase {
|
|||
|
||||
uint32_t mUnusedUAVBindingCount = 0u;
|
||||
uint32_t mTotalUAVBindingCount = 0u;
|
||||
BindGroupLayoutMask mUAVBindGroups = 0;
|
||||
};
|
||||
|
||||
} // namespace dawn::native::d3d11
|
||||
|
|
|
@ -705,6 +705,91 @@ TEST_P(BindGroupTests, SetDynamicBindGroupBeforePipeline) {
|
|||
EXPECT_PIXEL_RGBA8_EQ(notFilled, renderPass.color, max, max);
|
||||
}
|
||||
|
||||
// Test that the same renderpass can use 3 more pipelines
|
||||
TEST_P(BindGroupTests, ThreePipelinesInSameRenderpass) {
|
||||
utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
|
||||
|
||||
// Create a bind group layout which uses a single dynamic uniform buffer.
|
||||
wgpu::BindGroupLayout uniformLayout = utils::MakeBindGroupLayout(
|
||||
device, {{0, wgpu::ShaderStage::Fragment, wgpu::BufferBindingType::Uniform, true}});
|
||||
|
||||
// Pipeline0 uses 2 bind groups, 'bindGroup00' and 'bindGroup01', respectively accommodated with
|
||||
// 'color00' and 'color01'.
|
||||
wgpu::RenderPipeline pipeline0 = MakeTestPipeline(
|
||||
renderPass, {wgpu::BufferBindingType::Uniform, wgpu::BufferBindingType::Uniform},
|
||||
{uniformLayout, uniformLayout});
|
||||
|
||||
// Pipeline1 uses 'bindGroup1', accommodated with 'color1'.
|
||||
wgpu::RenderPipeline pipeline1 =
|
||||
MakeTestPipeline(renderPass, {wgpu::BufferBindingType::Uniform}, {uniformLayout});
|
||||
|
||||
// Pipeline2 uses 'bindGroup2', accommodated with 'color2'.
|
||||
wgpu::RenderPipeline pipeline2 =
|
||||
MakeTestPipeline(renderPass, {wgpu::BufferBindingType::Uniform}, {uniformLayout});
|
||||
|
||||
// Sum up to (1, 1, 1, 1)
|
||||
std::array<float, 4> color00 = {1, 0, 0, 0.5};
|
||||
std::array<float, 4> color01 = {0, 1, 0, 0.5};
|
||||
std::array<float, 4> color1 = {0, 0, 0.2, 0};
|
||||
std::array<float, 4> color2 = {0, 0, 0.8, 0};
|
||||
|
||||
std::vector<uint8_t> data(sizeof(color00));
|
||||
memcpy(data.data(), color00.data(), sizeof(color00));
|
||||
wgpu::Buffer uniformBuffer00 =
|
||||
utils::CreateBufferFromData(device, data.data(), data.size(), wgpu::BufferUsage::Uniform);
|
||||
wgpu::BindGroup bindGroup00 =
|
||||
utils::MakeBindGroup(device, uniformLayout, {{0, uniformBuffer00, 0, 4 * sizeof(float)}});
|
||||
|
||||
memcpy(data.data(), color01.data(), sizeof(color01));
|
||||
wgpu::Buffer uniformBuffer01 =
|
||||
utils::CreateBufferFromData(device, data.data(), data.size(), wgpu::BufferUsage::Uniform);
|
||||
wgpu::BindGroup bindGroup01 =
|
||||
utils::MakeBindGroup(device, uniformLayout, {{0, uniformBuffer01, 0, 4 * sizeof(float)}});
|
||||
|
||||
memcpy(data.data(), color1.data(), sizeof(color1));
|
||||
wgpu::Buffer uniformBuffer1 =
|
||||
utils::CreateBufferFromData(device, data.data(), data.size(), wgpu::BufferUsage::Uniform);
|
||||
wgpu::BindGroup bindGroup1 =
|
||||
utils::MakeBindGroup(device, uniformLayout, {{0, uniformBuffer1, 0, 4 * sizeof(float)}});
|
||||
|
||||
memcpy(data.data(), color2.data(), sizeof(color2));
|
||||
wgpu::Buffer uniformBuffer2 =
|
||||
utils::CreateBufferFromData(device, data.data(), data.size(), wgpu::BufferUsage::Uniform);
|
||||
wgpu::BindGroup bindGroup2 =
|
||||
utils::MakeBindGroup(device, uniformLayout, {{0, uniformBuffer2, 0, 4 * sizeof(float)}});
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
|
||||
|
||||
uint32_t dynamicOffset = 0;
|
||||
|
||||
pass.SetPipeline(pipeline0);
|
||||
pass.SetBindGroup(0, bindGroup00, 1, &dynamicOffset);
|
||||
pass.SetBindGroup(1, bindGroup01, 1, &dynamicOffset);
|
||||
pass.Draw(3);
|
||||
|
||||
pass.SetBindGroup(0, bindGroup1, 1, &dynamicOffset);
|
||||
pass.SetPipeline(pipeline1);
|
||||
pass.Draw(3);
|
||||
|
||||
pass.SetBindGroup(0, bindGroup2, 1, &dynamicOffset);
|
||||
pass.SetPipeline(pipeline2);
|
||||
pass.Draw(3);
|
||||
|
||||
pass.End();
|
||||
|
||||
wgpu::CommandBuffer commands = encoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
utils::RGBA8 filled(255, 255, 255, 255);
|
||||
utils::RGBA8 notFilled(0, 0, 0, 0);
|
||||
uint32_t min = 1, max = kRTSize - 3;
|
||||
EXPECT_PIXEL_RGBA8_EQ(filled, renderPass.color, min, min);
|
||||
EXPECT_PIXEL_RGBA8_EQ(filled, renderPass.color, max, min);
|
||||
EXPECT_PIXEL_RGBA8_EQ(filled, renderPass.color, min, max);
|
||||
EXPECT_PIXEL_RGBA8_EQ(notFilled, renderPass.color, max, max);
|
||||
}
|
||||
|
||||
// Test that bind groups set for one pipeline are still set when the pipeline changes.
|
||||
TEST_P(BindGroupTests, BindGroupsPersistAfterPipelineChange) {
|
||||
utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
|
||||
|
|
|
@ -297,6 +297,101 @@ TEST_P(DynamicBufferOffsetTests, SetDynamicOffsetsComputePipeline) {
|
|||
mMinUniformBufferOffsetAlignment, expectedData.size());
|
||||
}
|
||||
|
||||
// Test basic inherit on render pipeline
|
||||
TEST_P(DynamicBufferOffsetTests, BasicInheritRenderPipeline) {
|
||||
wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"(
|
||||
@vertex
|
||||
fn main(@builtin(vertex_index) VertexIndex : u32) -> @builtin(position) vec4f {
|
||||
var pos = array(
|
||||
vec2f(-1.0, 0.0),
|
||||
vec2f(-1.0, 1.0),
|
||||
vec2f( 0.0, 1.0));
|
||||
return vec4f(pos[VertexIndex], 0.0, 1.0);
|
||||
})");
|
||||
|
||||
// Construct fragment shader source
|
||||
std::ostringstream fs;
|
||||
fs << R"(
|
||||
struct Buf {
|
||||
value : vec2u
|
||||
}
|
||||
|
||||
@group(0) @binding(0) var<uniform> uBufferNotDynamic : Buf;
|
||||
@group(0) @binding(1) var<storage, read_write> sBufferNotDynamic : Buf;
|
||||
@group(1) @binding(3) var<uniform> uBuffer : Buf;
|
||||
@group(1) @binding(4) var<storage, read_write> sBuffer : Buf;
|
||||
|
||||
@fragment fn main() -> @location(0) vec4f {
|
||||
sBufferNotDynamic.value = uBufferNotDynamic.value.xy;
|
||||
sBuffer.value = uBuffer.value.xy + uBufferNotDynamic.value.xy;
|
||||
return vec4f(f32(uBuffer.value.x) / 255.0, f32(uBuffer.value.y) / 255.0,
|
||||
1.0, 1.0);
|
||||
}
|
||||
)";
|
||||
|
||||
wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, fs.str().c_str());
|
||||
|
||||
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
|
||||
pipelineDescriptor.vertex.module = vsModule;
|
||||
pipelineDescriptor.cFragment.module = fsModule;
|
||||
pipelineDescriptor.cTargets[0].format = wgpu::TextureFormat::RGBA8Unorm;
|
||||
|
||||
wgpu::BindGroupLayout bindGroupLayouts[2];
|
||||
bindGroupLayouts[0] = utils::MakeBindGroupLayout(
|
||||
device, {{0, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
|
||||
wgpu::BufferBindingType::Uniform},
|
||||
{1, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
|
||||
wgpu::BufferBindingType::Storage}});
|
||||
bindGroupLayouts[1] = utils::MakeBindGroupLayout(
|
||||
device, {{3, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
|
||||
wgpu::BufferBindingType::Uniform, true},
|
||||
{4, wgpu::ShaderStage::Compute | wgpu::ShaderStage::Fragment,
|
||||
wgpu::BufferBindingType::Storage, true}});
|
||||
|
||||
wgpu::BindGroup bindGroups[2];
|
||||
bindGroups[0] = utils::MakeBindGroup(device, bindGroupLayouts[0],
|
||||
{
|
||||
{0, mUniformBuffers[0], 0, kBindingSize},
|
||||
{1, mStorageBuffers[0], 0, kBindingSize},
|
||||
});
|
||||
bindGroups[1] = utils::MakeBindGroup(
|
||||
device, bindGroupLayouts[1],
|
||||
{{3, mUniformBuffers[1], 0, kBindingSize}, {4, mStorageBuffers[1], 0, kBindingSize}});
|
||||
|
||||
wgpu::PipelineLayoutDescriptor pipelineLayoutDescriptor;
|
||||
pipelineLayoutDescriptor.bindGroupLayoutCount = 2;
|
||||
pipelineLayoutDescriptor.bindGroupLayouts = bindGroupLayouts;
|
||||
pipelineDescriptor.layout = device.CreatePipelineLayout(&pipelineLayoutDescriptor);
|
||||
|
||||
wgpu::RenderPipeline pipeline0 = device.CreateRenderPipeline(&pipelineDescriptor);
|
||||
wgpu::RenderPipeline pipeline1 = device.CreateRenderPipeline(&pipelineDescriptor);
|
||||
|
||||
utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
|
||||
|
||||
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
|
||||
std::array<uint32_t, 2> offsets0 = {0, 0};
|
||||
std::array<uint32_t, 2> offsets1 = {mMinUniformBufferOffsetAlignment,
|
||||
mMinUniformBufferOffsetAlignment};
|
||||
wgpu::RenderPassEncoder renderPassEncoder =
|
||||
commandEncoder.BeginRenderPass(&renderPass.renderPassInfo);
|
||||
renderPassEncoder.SetPipeline(pipeline0);
|
||||
renderPassEncoder.SetBindGroup(0, bindGroups[0]);
|
||||
renderPassEncoder.SetBindGroup(1, bindGroups[1], offsets0.size(), offsets0.data());
|
||||
renderPassEncoder.Draw(3);
|
||||
renderPassEncoder.SetPipeline(pipeline1);
|
||||
// bind group 0 should be inherited and still available.
|
||||
renderPassEncoder.SetBindGroup(1, bindGroups[1], offsets1.size(), offsets1.data());
|
||||
renderPassEncoder.Draw(3);
|
||||
renderPassEncoder.End();
|
||||
wgpu::CommandBuffer commands = commandEncoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
std::vector<uint32_t> expectedData = {6, 8};
|
||||
EXPECT_PIXEL_RGBA8_EQ(utils::RGBA8(5, 6, 255, 255), renderPass.color, 0, 0);
|
||||
EXPECT_BUFFER_U32_RANGE_EQ(expectedData.data(), mStorageBuffers[1],
|
||||
mMinUniformBufferOffsetAlignment, expectedData.size());
|
||||
}
|
||||
|
||||
// Test inherit dynamic offsets on render pipeline
|
||||
TEST_P(DynamicBufferOffsetTests, InheritDynamicOffsetsRenderPipeline) {
|
||||
// Using default pipeline and setting dynamic offsets
|
||||
|
@ -576,6 +671,7 @@ TEST_P(ClampedOOBDynamicBufferOffsetTests, CheckOOBAccess) {
|
|||
}
|
||||
|
||||
DAWN_INSTANTIATE_TEST(DynamicBufferOffsetTests,
|
||||
D3D11Backend(),
|
||||
D3D12Backend(),
|
||||
MetalBackend(),
|
||||
OpenGLBackend(),
|
||||
|
|
Loading…
Reference in New Issue