Support sampling the stencil component
This uses an internal R8Uint texture, which holds the copy of stencil
data, for sampling the stencil component.
Bug: dawn:1827
Bug: dawn:1705
Change-Id: I0fb806e620bccab92b7c75841e7a3fc48d21b161
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/142349
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Peng Huang <penghuang@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Jie A Chen <jie.a.chen@intel.com>
diff --git a/src/dawn/native/d3d11/BindGroupTrackerD3D11.cpp b/src/dawn/native/d3d11/BindGroupTrackerD3D11.cpp
index 879e5ae..7181789 100644
--- a/src/dawn/native/d3d11/BindGroupTrackerD3D11.cpp
+++ b/src/dawn/native/d3d11/BindGroupTrackerD3D11.cpp
@@ -351,7 +351,13 @@
case BindingInfoType::Texture: {
TextureView* view = ToBackend(group->GetBindingAsTextureView(bindingIndex));
ComPtr<ID3D11ShaderResourceView> srv;
- DAWN_TRY_ASSIGN(srv, view->CreateD3D11ShaderResourceView());
+ // For sampling from stencil, we have to use an internal mirror 'R8Uint' texture.
+ if (view->GetAspects() == Aspect::Stencil) {
+ DAWN_TRY_ASSIGN(
+ srv, ToBackend(view->GetTexture())->GetStencilSRV(mCommandContext, view));
+ } else {
+ DAWN_TRY_ASSIGN(srv, view->CreateD3D11ShaderResourceView());
+ }
if (bindingVisibility & wgpu::ShaderStage::Vertex) {
deviceContext1->VSSetShaderResources(bindingSlot, 1, srv.GetAddressOf());
}
diff --git a/src/dawn/native/d3d11/TextureD3D11.cpp b/src/dawn/native/d3d11/TextureD3D11.cpp
index 72c3eff..d43b82d 100644
--- a/src/dawn/native/d3d11/TextureD3D11.cpp
+++ b/src/dawn/native/d3d11/TextureD3D11.cpp
@@ -1059,6 +1059,81 @@
return GetDevice()->GetLastSubmittedCommandSerial();
}
+ResultOrError<ComPtr<ID3D11ShaderResourceView>> Texture::GetStencilSRV(
+ CommandRecordingContext* commandContext,
+ const TextureView* view) {
+ ASSERT(GetFormat().HasStencil());
+
+ if (!mTextureForStencilSampling.Get()) {
+ // Create an interim texture of R8Uint format.
+ TextureDescriptor desc = {};
+ desc.label = "InterimStencilTexture";
+ desc.dimension = GetDimension();
+ desc.size = GetSize();
+ desc.format = wgpu::TextureFormat::R8Uint;
+ desc.mipLevelCount = GetNumMipLevels();
+ desc.sampleCount = GetSampleCount();
+ desc.usage = wgpu::TextureUsage::TextureBinding;
+
+ DAWN_TRY_ASSIGN(mTextureForStencilSampling,
+ CreateInternal(ToBackend(GetDevice()), &desc, Kind::Interim));
+ }
+
+ // Sync the stencil data of this texture to the interim stencil-view texture.
+ // TODO(dawn:1705): Improve to only sync as few as possible.
+ const auto range = view->GetSubresourceRange();
+ const TexelBlockInfo& blockInfo = GetFormat().GetAspectInfo(range.aspects).block;
+ Extent3D size = GetMipLevelSubresourceVirtualSize(range.baseMipLevel);
+ uint32_t bytesPerRow = blockInfo.byteSize * size.width;
+ uint32_t rowsPerImage = size.height;
+ uint64_t byteLength;
+ DAWN_TRY_ASSIGN(byteLength,
+ ComputeRequiredBytesInCopy(blockInfo, size, bytesPerRow, rowsPerImage));
+
+ std::vector<uint8_t> stagingData(byteLength);
+ for (uint32_t layer = range.baseArrayLayer; layer < range.baseArrayLayer + range.layerCount;
+ ++layer) {
+ for (uint32_t level = range.baseMipLevel; level < range.baseMipLevel + range.levelCount;
+ ++level) {
+ size = GetMipLevelSubresourceVirtualSize(level);
+ bytesPerRow = blockInfo.byteSize * size.width;
+ rowsPerImage = size.height;
+ auto singleRange = SubresourceRange::MakeSingle(range.aspects, layer, level);
+
+ Texture::ReadCallback callback = [&](const uint8_t* data, uint64_t offset,
+ uint64_t length) -> MaybeError {
+ std::memcpy(static_cast<uint8_t*>(stagingData.data()) + offset, data, length);
+ return {};
+ };
+
+ // TODO(dawn:1705): Work out a way of GPU-GPU copy, rather than the CPU-GPU round trip.
+ commandContext->GetDevice()->EmitWarningOnce(
+ "Sampling the stencil component is rather slow now.");
+ DAWN_TRY(Read(commandContext, singleRange, {0, 0, 0}, size, bytesPerRow, rowsPerImage,
+ callback));
+
+ DAWN_TRY(mTextureForStencilSampling->WriteInternal(commandContext, singleRange,
+ {0, 0, 0}, size, stagingData.data(),
+ bytesPerRow, rowsPerImage));
+ }
+ }
+
+ Ref<TextureViewBase> textureView;
+ TextureViewDescriptor viewDesc = {};
+ viewDesc.label = "InterimStencilTextureView";
+ viewDesc.format = wgpu::TextureFormat::R8Uint;
+ viewDesc.dimension = view->GetDimension();
+ viewDesc.baseArrayLayer = view->GetBaseArrayLayer();
+ viewDesc.arrayLayerCount = view->GetLayerCount();
+ viewDesc.baseMipLevel = view->GetBaseMipLevel();
+ viewDesc.mipLevelCount = view->GetLevelCount();
+ DAWN_TRY_ASSIGN(textureView, mTextureForStencilSampling->CreateView(&viewDesc));
+
+ ComPtr<ID3D11ShaderResourceView> srv;
+ DAWN_TRY_ASSIGN(srv, ToBackend(textureView)->CreateD3D11ShaderResourceView());
+ return srv;
+}
+
// static
Ref<TextureView> TextureView::Create(TextureBase* texture,
const TextureViewDescriptor* descriptor) {
@@ -1100,8 +1175,7 @@
break;
case Aspect::Stencil:
srvDesc.Format = DXGI_FORMAT_X24_TYPELESS_G8_UINT;
- // TODO(dawn:1827) Support sampling the stencil component.
- return DAWN_UNIMPLEMENTED_ERROR("Sampling the stencil component.");
+ break;
default:
UNREACHABLE();
break;
@@ -1124,8 +1198,7 @@
break;
case Aspect::Stencil:
srvDesc.Format = DXGI_FORMAT_X32_TYPELESS_G8X24_UINT;
- // TODO(dawn:1827) Support sampling the stencil component.
- return DAWN_UNIMPLEMENTED_ERROR("Sampling the stencil component.");
+ break;
default:
UNREACHABLE();
break;
diff --git a/src/dawn/native/d3d11/TextureD3D11.h b/src/dawn/native/d3d11/TextureD3D11.h
index 7eb2788..b72cdab 100644
--- a/src/dawn/native/d3d11/TextureD3D11.h
+++ b/src/dawn/native/d3d11/TextureD3D11.h
@@ -36,6 +36,7 @@
class CommandRecordingContext;
class Device;
+class TextureView;
MaybeError ValidateTextureCanBeWrapped(ID3D11Resource* d3d11Resource,
const TextureDescriptor* descriptor);
@@ -82,6 +83,13 @@
ResultOrError<ExecutionSerial> EndAccess() override;
+ // As D3D11 SRV doesn't support 'Shader4ComponentMapping' for depth-stencil textures, we can't
+ // sample the stencil component directly. As a workaround we create an internal R8Uint texture,
+ // holding the copy of its stencil data, and use the internal texture's SRV instead.
+ ResultOrError<ComPtr<ID3D11ShaderResourceView>> GetStencilSRV(
+ CommandRecordingContext* commandContext,
+ const TextureView* view);
+
private:
using Base = d3d::Texture;
@@ -160,6 +168,8 @@
const Kind mKind = Kind::Normal;
ComPtr<ID3D11Resource> mD3d11Resource;
+ // The internal 'R8Uint' texture for sampling stencil from depth-stencil textures.
+ Ref<Texture> mTextureForStencilSampling;
};
class TextureView final : public TextureViewBase {
diff --git a/src/dawn/tests/end2end/DepthStencilSamplingTests.cpp b/src/dawn/tests/end2end/DepthStencilSamplingTests.cpp
index e3f5c23..9816af9 100644
--- a/src/dawn/tests/end2end/DepthStencilSamplingTests.cpp
+++ b/src/dawn/tests/end2end/DepthStencilSamplingTests.cpp
@@ -313,8 +313,6 @@
inputViewDesc.aspect = wgpu::TextureAspect::DepthOnly;
break;
case TestAspectAndSamplerType::StencilAsUint:
- // TODO(dawn:1827): Suport SRV component mapping for stencil on D3D11.
- DAWN_SUPPRESS_TEST_IF(IsD3D11());
inputViewDesc.aspect = wgpu::TextureAspect::StencilOnly;
break;
}
@@ -372,8 +370,6 @@
inputViewDesc.aspect = wgpu::TextureAspect::DepthOnly;
break;
case TestAspectAndSamplerType::StencilAsUint:
- // TODO(dawn:1827): Suport SRV component mapping for stencil on D3D11.
- DAWN_SUPPRESS_TEST_IF(IsD3D11());
inputViewDesc.aspect = wgpu::TextureAspect::StencilOnly;
break;
}
@@ -749,9 +745,6 @@
// In compat, you can't have different views of the same texture in the same draw command.
DAWN_TEST_UNSUPPORTED_IF(IsCompatibilityMode());
- // TODO(dawn:1827): Suport SRV component mapping for stencil on D3D11.
- DAWN_SUPPRESS_TEST_IF(IsD3D11());
-
wgpu::TextureFormat format = GetParam().mTextureFormat;
wgpu::SamplerDescriptor samplerDesc;
diff --git a/src/dawn/tests/end2end/ReadOnlyDepthStencilAttachmentTests.cpp b/src/dawn/tests/end2end/ReadOnlyDepthStencilAttachmentTests.cpp
index 53410ae..7afde12 100644
--- a/src/dawn/tests/end2end/ReadOnlyDepthStencilAttachmentTests.cpp
+++ b/src/dawn/tests/end2end/ReadOnlyDepthStencilAttachmentTests.cpp
@@ -297,9 +297,6 @@
};
TEST_P(ReadOnlyStencilAttachmentTests, SampleFromAttachment) {
- // TODO(dawn:1827): sampling from stencil attachment fails on D3D11.
- DAWN_SUPPRESS_TEST_IF(IsD3D11());
-
wgpu::Texture colorTexture =
CreateTexture(wgpu::TextureFormat::RGBA8Unorm,
wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc);