Graphite: Enable MultiPlanarRenderTargets feature for D3D11/12
Enable MultiPlanarRenderTargets feature for D3D11/12. As part of that
pass the correct planeSlice to D3D12_RENDER_TARGET_VIEW_DESC and
binding for the VideoViewsTests.
Bug: dawn:1337
Change-Id: I3ab3f4432a9670f162154a967345c52d31e72373
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/154820
Reviewed-by: Austin Eng <enga@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Saifuddin Hitawala <hitawala@chromium.org>
diff --git a/src/dawn/native/d3d11/PhysicalDeviceD3D11.cpp b/src/dawn/native/d3d11/PhysicalDeviceD3D11.cpp
index d1efb23..337f5ae 100644
--- a/src/dawn/native/d3d11/PhysicalDeviceD3D11.cpp
+++ b/src/dawn/native/d3d11/PhysicalDeviceD3D11.cpp
@@ -196,6 +196,7 @@
if (mDeviceInfo.supportsSharedResourceCapabilityTier2) {
EnableFeature(Feature::DawnMultiPlanarFormats);
EnableFeature(Feature::MultiPlanarFormatP010);
+ EnableFeature(Feature::MultiPlanarRenderTargets);
}
if (mDeviceInfo.supportsROV) {
EnableFeature(Feature::PixelLocalStorageCoherent);
diff --git a/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp b/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp
index 204f704..34c0bcc 100644
--- a/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp
+++ b/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp
@@ -145,6 +145,7 @@
EnableFeature(Feature::Norm16TextureFormats);
EnableFeature(Feature::AdapterPropertiesMemoryHeaps);
EnableFeature(Feature::AdapterPropertiesD3D);
+ EnableFeature(Feature::MultiPlanarRenderTargets);
if (AreTimestampQueriesSupported()) {
EnableFeature(Feature::TimestampQuery);
diff --git a/src/dawn/native/d3d12/TextureD3D12.cpp b/src/dawn/native/d3d12/TextureD3D12.cpp
index 921c0fa..1847a02 100644
--- a/src/dawn/native/d3d12/TextureD3D12.cpp
+++ b/src/dawn/native/d3d12/TextureD3D12.cpp
@@ -689,7 +689,8 @@
D3D12_RENDER_TARGET_VIEW_DESC Texture::GetRTVDescriptor(const Format& format,
uint32_t mipLevel,
uint32_t baseSlice,
- uint32_t sliceCount) const {
+ uint32_t sliceCount,
+ uint32_t planeSlice) const {
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc;
rtvDesc.Format = d3d::DXGITextureFormat(format.format);
if (IsMultisampledTexture()) {
@@ -713,7 +714,7 @@
rtvDesc.Texture2DArray.FirstArraySlice = baseSlice;
rtvDesc.Texture2DArray.ArraySize = sliceCount;
rtvDesc.Texture2DArray.MipSlice = mipLevel;
- rtvDesc.Texture2DArray.PlaneSlice = 0;
+ rtvDesc.Texture2DArray.PlaneSlice = planeSlice;
break;
case wgpu::TextureDimension::e3D:
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D;
@@ -849,7 +850,8 @@
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc =
GetRTVDescriptor(GetFormat(), level, layer,
GetMipLevelSingleSubresourceVirtualSize(level, Aspect::Color)
- .depthOrArrayLayers);
+ .depthOrArrayLayers,
+ GetAspectIndex(range.aspects));
device->GetD3D12Device()->CreateRenderTargetView(GetD3D12Resource(), &rtvDesc,
rtvHandle);
commandList->ClearRenderTargetView(rtvHandle, clearColorRGBA, 0, nullptr);
@@ -1126,7 +1128,7 @@
// view's dimension.
return ToBackend(GetTexture())
->GetRTVDescriptor(GetFormat(), GetBaseMipLevel(), GetBaseArrayLayer() + depthSlice,
- GetLayerCount());
+ GetLayerCount(), GetAspectIndex(GetAspects()));
}
D3D12_DEPTH_STENCIL_VIEW_DESC TextureView::GetDSVDescriptor(bool depthReadOnly,
diff --git a/src/dawn/native/d3d12/TextureD3D12.h b/src/dawn/native/d3d12/TextureD3D12.h
index fe3cc45..6274a30 100644
--- a/src/dawn/native/d3d12/TextureD3D12.h
+++ b/src/dawn/native/d3d12/TextureD3D12.h
@@ -81,7 +81,8 @@
D3D12_RENDER_TARGET_VIEW_DESC GetRTVDescriptor(const Format& format,
uint32_t mipLevel,
uint32_t baseSlice,
- uint32_t sliceCount) const;
+ uint32_t sliceCount,
+ uint32_t planeSlice) const;
D3D12_DEPTH_STENCIL_VIEW_DESC GetDSVDescriptor(uint32_t mipLevel,
uint32_t baseArrayLayer,
uint32_t layerCount,
diff --git a/src/dawn/tests/end2end/VideoViewsTests.cpp b/src/dawn/tests/end2end/VideoViewsTests.cpp
index f2acfd6..8f3932a 100644
--- a/src/dawn/tests/end2end/VideoViewsTests.cpp
+++ b/src/dawn/tests/end2end/VideoViewsTests.cpp
@@ -1552,6 +1552,142 @@
mBackend->DestroyVideoTextureForTest(std::move(destVideoTexture));
}
+
+ // Tests for rendering to a chroma texture view from a luma texture view, both of which created
+ // from a multiplanar video texture. The test then copies back from chroma view to plane 0
+ // texture view and compares the result same as expected texture data from first plane.
+ template <typename T>
+ void RenderFromLumaToChromaPlane() {
+ // Create plane texture initialized with data.
+ auto CreatePlaneTexWithData = [this](int planeIndex, bool hasAlpha) -> wgpu::Texture {
+ auto kSubsampleFactor = planeIndex == kYUVAChromaPlaneIndex ? 2 : 1;
+ wgpu::Extent3D size = {kYUVAImageDataWidthInTexels / kSubsampleFactor,
+ kYUVAImageDataHeightInTexels / kSubsampleFactor, 1};
+
+ // Create source texture with plane format
+ wgpu::TextureDescriptor planeTextureDesc;
+ planeTextureDesc.size = size;
+ planeTextureDesc.format = GetPlaneFormat(planeIndex);
+ planeTextureDesc.usage = wgpu::TextureUsage::CopyDst |
+ wgpu::TextureUsage::TextureBinding |
+ wgpu::TextureUsage::RenderAttachment;
+ wgpu::Texture planeTexture = device.CreateTexture(&planeTextureDesc);
+
+ // Copy plane (Y/UV/A) data to the plane source texture.
+ size_t bytesPerRow = kYUVAImageDataWidthInTexels * sizeof(T);
+ std::vector<T> planeSrcData = VideoViewsTestsBase::GetTestTextureDataWithPlaneIndex<T>(
+ planeIndex, bytesPerRow, kYUVAImageDataHeightInTexels / kSubsampleFactor, false,
+ hasAlpha);
+ wgpu::ImageCopyTexture imageCopyTexture = utils::CreateImageCopyTexture(planeTexture);
+ wgpu::TextureDataLayout textureDataLayout =
+ utils::CreateTextureDataLayout(0, bytesPerRow);
+ wgpu::Queue queue = device.GetQueue();
+ queue.WriteTexture(&imageCopyTexture, planeSrcData.data(),
+ planeSrcData.size() * sizeof(T), &textureDataLayout, &size);
+
+ return planeTexture;
+ };
+
+ const bool hasAlpha = NumPlanes(GetFormat()) > 2;
+ // Create source texture with plane 0 format i.e. R8/R16Unorm.
+ wgpu::Texture plane0Texture = CreatePlaneTexWithData(kYUVALumaPlaneIndex, hasAlpha);
+ ASSERT_NE(plane0Texture.Get(), nullptr);
+
+ // Create a video texture to be rendered into with multiplanar format.
+ auto destVideoTexture = mBackend->CreateVideoTextureForTest(
+ GetFormat(), wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment,
+ /*isCheckerboard*/ false,
+ /*initialized*/ true);
+ ASSERT_NE(destVideoTexture.get(), nullptr);
+ if (!destVideoTexture->CanWrapAsWGPUTexture()) {
+ mBackend->DestroyVideoTextureForTest(std::move(destVideoTexture));
+ GTEST_SKIP() << "Skipped because not supported.";
+ }
+ auto destVideoWGPUTexture = destVideoTexture->wgpuTexture;
+
+ // Create luma plane texture view from multiplanar video texture.
+ wgpu::TextureViewDescriptor lumaViewDesc;
+ lumaViewDesc.format = GetPlaneFormat(kYUVALumaPlaneIndex);
+ lumaViewDesc.aspect = GetPlaneAspect(kYUVALumaPlaneIndex);
+ wgpu::TextureView lumaTextureView = destVideoWGPUTexture.CreateView(&lumaViewDesc);
+
+ // Create chroma plane texture view from multiplanar video texture.
+ wgpu::TextureViewDescriptor chromaViewDesc;
+ chromaViewDesc.format = GetPlaneFormat(kYUVAChromaPlaneIndex);
+ chromaViewDesc.aspect = GetPlaneAspect(kYUVAChromaPlaneIndex);
+ wgpu::TextureView chromaTextureView = destVideoWGPUTexture.CreateView(&chromaViewDesc);
+
+ wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+ wgpu::Sampler sampler = device.CreateSampler();
+
+ auto CreateRenderPipeline = [this](int planeIndex, wgpu::TextureView srcTextureView,
+ wgpu::TextureView destTextureView,
+ wgpu::CommandEncoder encoder,
+ wgpu::Sampler sampler) -> wgpu::RenderPipeline {
+ utils::ComboRenderPipelineDescriptor renderPipelineDescriptor;
+ renderPipelineDescriptor.vertex.module = GetTestVertexShaderModule();
+ renderPipelineDescriptor.cFragment.module = utils::CreateShaderModule(device, R"(
+ @group(0) @binding(0) var sampler0 : sampler;
+ @group(0) @binding(1) var texture : texture_2d<f32>;
+
+ @fragment
+ fn main(@location(0) texCoord : vec2f) -> @location(0) vec4f {
+ return textureSample(texture, sampler0, texCoord);
+ })");
+ renderPipelineDescriptor.primitive.topology = wgpu::PrimitiveTopology::TriangleList;
+ renderPipelineDescriptor.cTargets[0].format = GetPlaneFormat(planeIndex);
+ wgpu::RenderPipeline renderPipeline =
+ device.CreateRenderPipeline(&renderPipelineDescriptor);
+
+ utils::ComboRenderPassDescriptor renderPass({destTextureView});
+ wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
+ pass.SetPipeline(renderPipeline);
+ pass.SetBindGroup(0, utils::MakeBindGroup(device, renderPipeline.GetBindGroupLayout(0),
+ {{0, sampler}, {1, srcTextureView}}));
+ pass.Draw(6);
+ pass.End();
+
+ return renderPipeline;
+ };
+
+ // Render pass operations for reading plane0Texture with data into lumaTextureView created
+ // from the multiplanar video texture.
+ wgpu::RenderPipeline renderPipeline1 = CreateRenderPipeline(
+ kYUVALumaPlaneIndex, plane0Texture.CreateView(), lumaTextureView, encoder, sampler);
+
+ // Render pass operations for reading lumaTextureView into chromaTextureView created from
+ // the multiplanar video texture.
+ wgpu::RenderPipeline renderPipeline2 = CreateRenderPipeline(
+ kYUVAChromaPlaneIndex, lumaTextureView, chromaTextureView, encoder, sampler);
+
+ // Another render pass for reading the chromaTextureView into a texture of the luma plane's
+ // format (i.e. R8/R16Unorm).
+ utils::BasicRenderPass basicRenderPass = utils::CreateBasicRenderPass(
+ device, kYUVAImageDataWidthInTexels, kYUVAImageDataHeightInTexels,
+ GetPlaneFormat(kYUVALumaPlaneIndex));
+ wgpu::RenderPassEncoder secondPass =
+ encoder.BeginRenderPass(&basicRenderPass.renderPassInfo);
+ secondPass.SetPipeline(renderPipeline1);
+ secondPass.SetBindGroup(0,
+ utils::MakeBindGroup(device, renderPipeline1.GetBindGroupLayout(0),
+ {{0, sampler}, {1, chromaTextureView}}));
+ secondPass.Draw(6);
+ secondPass.End();
+
+ // Submit all commands for the encoder.
+ wgpu::CommandBuffer commands = encoder.Finish();
+ queue.Submit(1, &commands);
+
+ // Compare expected data from luma values to that from basicRenderPass.
+ std::vector<T> expectedData = VideoViewsTestsBase::GetTestTextureDataWithPlaneIndex<T>(
+ kYUVALumaPlaneIndex, kYUVAImageDataWidthInTexels * sizeof(T),
+ kYUVAImageDataHeightInTexels, false, hasAlpha);
+ EXPECT_TEXTURE_EQ(expectedData.data(), basicRenderPass.color, {0, 0},
+ {kYUVAImageDataWidthInTexels, kYUVAImageDataHeightInTexels},
+ GetPlaneFormat(kYUVALumaPlaneIndex));
+
+ mBackend->DestroyVideoTextureForTest(std::move(destVideoTexture));
+ }
};
// Tests creating a texture with a multi-plane format.
@@ -1638,6 +1774,18 @@
}
}
+// Tests for rendering to one plane while reading from another plane.
+TEST_P(VideoViewsRenderTargetTests, RenderFromLumaToChromaPlane) {
+ if (GetFormat() == wgpu::TextureFormat::R8BG8Biplanar420Unorm ||
+ GetFormat() == wgpu::TextureFormat::R8BG8A8Triplanar420Unorm) {
+ RenderFromLumaToChromaPlane<uint8_t>();
+ } else if (GetFormat() == wgpu::TextureFormat::R10X6BG10X6Biplanar420Unorm) {
+ RenderFromLumaToChromaPlane<uint16_t>();
+ } else {
+ DAWN_UNREACHABLE();
+ }
+}
+
class VideoViewsExtendedUsagesTests : public VideoViewsTestsBase {
protected:
void SetUp() override {
diff --git a/src/dawn/tests/end2end/VideoViewsTests_win.cpp b/src/dawn/tests/end2end/VideoViewsTests_win.cpp
index fb7c493..7705644 100644
--- a/src/dawn/tests/end2end/VideoViewsTests_win.cpp
+++ b/src/dawn/tests/end2end/VideoViewsTests_win.cpp
@@ -106,6 +106,20 @@
}
}
+ static UINT GetD3D11TextureBindFlags(wgpu::TextureUsage usage) {
+ UINT bindFlags = 0;
+ if (usage & wgpu::TextureUsage::TextureBinding) {
+ bindFlags |= D3D11_BIND_SHADER_RESOURCE;
+ }
+ if (usage & wgpu::TextureUsage::StorageBinding) {
+ bindFlags |= D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;
+ }
+ if (usage & wgpu::TextureUsage::RenderAttachment) {
+ bindFlags |= D3D11_BIND_RENDER_TARGET;
+ }
+ return bindFlags;
+ }
+
std::unique_ptr<VideoViewsTestBackend::PlatformTexture> CreateVideoTextureForTest(
wgpu::TextureFormat format,
wgpu::TextureUsage usage,
@@ -128,7 +142,7 @@
d3dDescriptor.SampleDesc.Count = 1;
d3dDescriptor.SampleDesc.Quality = 0;
d3dDescriptor.Usage = D3D11_USAGE_DEFAULT;
- d3dDescriptor.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+ d3dDescriptor.BindFlags = GetD3D11TextureBindFlags(usage);
d3dDescriptor.CPUAccessFlags = 0;
d3dDescriptor.MiscFlags = D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED;