VideoViewsTests: add test which uses a sampler per plane
This test sees flaky failures.
- Check the entire checkerboard texture contents to get more
information.
- Add a test which uses seperate sampling states to see if DX12
driver has difficulty sampling multi-planar formats using a
single sampler.
- Also, double check support for the NV12 format in case
something in the driver flakily exposes support.
From https://dawn-review.googlesource.com/c/dawn/+/47660
Bug: dawn:733
Change-Id: I766907ff648f1dc35387902a70c3fb65debcaecd
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/119343
Commit-Queue: Austin Eng <enga@chromium.org>
Kokoro: Austin Eng <enga@chromium.org>
Reviewed-by: Shrek Shao <shrekshao@google.com>
diff --git a/src/dawn/tests/end2end/VideoViewsTests.cpp b/src/dawn/tests/end2end/VideoViewsTests.cpp
index bbc04a2..eee92bd 100644
--- a/src/dawn/tests/end2end/VideoViewsTests.cpp
+++ b/src/dawn/tests/end2end/VideoViewsTests.cpp
@@ -71,45 +71,58 @@
constexpr uint8_t Yu = kYellowYUVColor[kYUVChromaPlaneIndex].r;
constexpr uint8_t Yv = kYellowYUVColor[kYUVChromaPlaneIndex].g;
+ constexpr uint8_t Wy = kWhiteYUVColor[kYUVLumaPlaneIndex].r;
+ constexpr uint8_t Wu = kWhiteYUVColor[kYUVChromaPlaneIndex].r;
+ constexpr uint8_t Wv = kWhiteYUVColor[kYUVChromaPlaneIndex].g;
+
+ constexpr uint8_t Ry = kRedYUVColor[kYUVLumaPlaneIndex].r;
+ constexpr uint8_t Ru = kRedYUVColor[kYUVChromaPlaneIndex].r;
+ constexpr uint8_t Rv = kRedYUVColor[kYUVChromaPlaneIndex].g;
+
+ constexpr uint8_t By = kBlueYUVColor[kYUVLumaPlaneIndex].r;
+ constexpr uint8_t Bu = kBlueYUVColor[kYUVChromaPlaneIndex].r;
+ constexpr uint8_t Bv = kBlueYUVColor[kYUVChromaPlaneIndex].g;
+
switch (format) {
// The first 16 bytes is the luma plane (Y), followed by the chroma plane (UV) which
// is half the number of bytes (subsampled by 2) but same bytes per line as luma
// plane.
case wgpu::TextureFormat::R8BG8Biplanar420Unorm:
if (isCheckerboard) {
- constexpr uint8_t Wy = kWhiteYUVColor[kYUVLumaPlaneIndex].r;
- constexpr uint8_t Wu = kWhiteYUVColor[kYUVChromaPlaneIndex].r;
- constexpr uint8_t Wv = kWhiteYUVColor[kYUVChromaPlaneIndex].g;
-
- constexpr uint8_t Ry = kRedYUVColor[kYUVLumaPlaneIndex].r;
- constexpr uint8_t Ru = kRedYUVColor[kYUVChromaPlaneIndex].r;
- constexpr uint8_t Rv = kRedYUVColor[kYUVChromaPlaneIndex].g;
-
- constexpr uint8_t By = kBlueYUVColor[kYUVLumaPlaneIndex].r;
- constexpr uint8_t Bu = kBlueYUVColor[kYUVChromaPlaneIndex].r;
- constexpr uint8_t Bv = kBlueYUVColor[kYUVChromaPlaneIndex].g;
-
- // clang-format off
- return {
- Wy, Wy, Ry, Ry, // plane 0, start + 0
- Wy, Wy, Ry, Ry,
- Yy, Yy, By, By,
- Yy, Yy, By, By,
- Wu, Wv, Ru, Rv, // plane 1, start + 16
- Yu, Yv, Bu, Bv,
- };
- // clang-format on
+ return {
+ Wy, Wy, Ry, Ry, // plane 0, start + 0
+ Wy, Wy, Ry, Ry, //
+ Yy, Yy, By, By, //
+ Yy, Yy, By, By, //
+ Wu, Wv, Ru, Rv, // plane 1, start + 16
+ Yu, Yv, Bu, Bv, //
+ };
} else {
- // clang-format off
- return {
- Yy, Yy, Yy, Yy, // plane 0, start + 0
- Yy, Yy, Yy, Yy,
- Yy, Yy, Yy, Yy,
- Yy, Yy, Yy, Yy,
- Yu, Yv, Yu, Yv, // plane 1, start + 16
- Yu, Yv, Yu, Yv,
- };
- // clang-format on
+ return {
+ Yy, Yy, Yy, Yy, // plane 0, start + 0
+ Yy, Yy, Yy, Yy, //
+ Yy, Yy, Yy, Yy, //
+ Yy, Yy, Yy, Yy, //
+ Yu, Yv, Yu, Yv, // plane 1, start + 16
+ Yu, Yv, Yu, Yv, //
+ };
+ }
+ case wgpu::TextureFormat::RGBA8Unorm:
+ // Combines both NV12 planes by directly mapping back to RGB: R=Y, G=U, B=V.
+ if (isCheckerboard) {
+ return {
+ Yy, Yu, Yv, Yy, Yu, Yv, By, Bu, Bv, By, Bu, Bv, //
+ Yy, Yu, Yv, Yy, Yu, Yv, By, Bu, Bv, By, Bu, Bv, //
+ Wy, Wu, Wv, Wy, Wu, Wv, Ry, Ru, Rv, Ry, Ru, Rv, //
+ Wy, Wu, Wv, Wy, Wu, Wv, Ry, Ru, Rv, Ry, Ru, Rv, //
+ };
+ } else {
+ return {
+ Yy, Yu, Yv, Yy, Yu, Yv, Yy, Yu, Yv, Yy, Yu, Yv, //
+ Yy, Yu, Yv, Yy, Yu, Yv, Yy, Yu, Yv, Yy, Yu, Yv, //
+ Yy, Yu, Yv, Yy, Yu, Yv, Yy, Yu, Yv, Yy, Yu, Yv, //
+ Yy, Yu, Yv, Yy, Yu, Yv, Yy, Yu, Yv, Yy, Yu, Yv, //
+ };
}
default:
UNREACHABLE();
@@ -323,8 +336,8 @@
mBackend->DestroyVideoTextureForTest(std::move(platformTexture));
}
-// Renders a NV12 "checkerboard" texture into a RGB quad then checks the color at specific
-// points to ensure the image has not been flipped.
+// Renders a NV12 "checkerboard" texture into a RGB quad, then checks the the entire
+// contents to ensure the image has not been flipped.
TEST_P(VideoViewsTests, NV12SampleYUVtoRGB) {
std::unique_ptr<VideoViewsTestBackend::PlatformTexture> platformTexture =
mBackend->CreateVideoTextureForTest(wgpu::TextureFormat::R8BG8Biplanar420Unorm,
@@ -385,27 +398,90 @@
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
- // Test four corners of the checkerboard image (YUV color space).
- utils::RGBA8 yellowYUV(kYellowYUVColor[kYUVLumaPlaneIndex].r,
- kYellowYUVColor[kYUVChromaPlaneIndex].r,
- kYellowYUVColor[kYUVChromaPlaneIndex].g, 0xFF);
- EXPECT_PIXEL_RGBA8_EQ(yellowYUV, renderPass.color, 0, 0); // top left
+ std::vector<uint8_t> expectedData = GetTestTextureData(wgpu::TextureFormat::RGBA8Unorm, true);
+ std::vector<utils::RGBA8> expectedRGBA;
+ for (uint8_t i = 0; i < expectedData.size(); i += 3) {
+ expectedRGBA.push_back({expectedData[i], expectedData[i + 1], expectedData[i + 2], 0xFF});
+ }
- utils::RGBA8 redYUV(kRedYUVColor[kYUVLumaPlaneIndex].r, kRedYUVColor[kYUVChromaPlaneIndex].r,
- kRedYUVColor[kYUVChromaPlaneIndex].g, 0xFF);
- EXPECT_PIXEL_RGBA8_EQ(redYUV, renderPass.color, kYUVImageDataWidthInTexels - 1,
- kYUVImageDataHeightInTexels - 1); // bottom right
+ EXPECT_TEXTURE_EQ(expectedRGBA.data(), renderPass.color, {0, 0},
+ {kYUVImageDataWidthInTexels, kYUVImageDataHeightInTexels});
+ mBackend->DestroyVideoTextureForTest(std::move(platformTexture));
+}
- utils::RGBA8 blueYUV(kBlueYUVColor[kYUVLumaPlaneIndex].r, kBlueYUVColor[kYUVChromaPlaneIndex].r,
- kBlueYUVColor[kYUVChromaPlaneIndex].g, 0xFF);
- EXPECT_PIXEL_RGBA8_EQ(blueYUV, renderPass.color, kYUVImageDataWidthInTexels - 1,
- 0); // top right
+// Renders a NV12 "checkerboard" texture into a RGB quad with two samplers, then checks the the
+// entire contents to ensure the image has not been flipped.
+TEST_P(VideoViewsTests, NV12SampleYUVtoRGBMultipleSamplers) {
+ std::unique_ptr<VideoViewsTestBackend::PlatformTexture> platformTexture =
+ mBackend->CreateVideoTextureForTest(wgpu::TextureFormat::R8BG8Biplanar420Unorm,
+ wgpu::TextureUsage::TextureBinding,
+ /*isCheckerboard*/ true,
+ /*initialized*/ true);
+ ASSERT_NE(platformTexture.get(), nullptr);
+ if (!platformTexture->CanWrapAsWGPUTexture()) {
+ mBackend->DestroyVideoTextureForTest(std::move(platformTexture));
+ GTEST_SKIP() << "Skipped because not supported.";
+ }
- utils::RGBA8 whiteYUV(kWhiteYUVColor[kYUVLumaPlaneIndex].r,
- kWhiteYUVColor[kYUVChromaPlaneIndex].r,
- kWhiteYUVColor[kYUVChromaPlaneIndex].g, 0xFF);
- EXPECT_PIXEL_RGBA8_EQ(whiteYUV, renderPass.color, 0,
- kYUVImageDataHeightInTexels - 1); // bottom left
+ wgpu::TextureViewDescriptor lumaViewDesc;
+ lumaViewDesc.format = wgpu::TextureFormat::R8Unorm;
+ lumaViewDesc.aspect = wgpu::TextureAspect::Plane0Only;
+ wgpu::TextureView lumaTextureView = platformTexture->wgpuTexture.CreateView(&lumaViewDesc);
+
+ wgpu::TextureViewDescriptor chromaViewDesc;
+ chromaViewDesc.format = wgpu::TextureFormat::RG8Unorm;
+ chromaViewDesc.aspect = wgpu::TextureAspect::Plane1Only;
+ wgpu::TextureView chromaTextureView = platformTexture->wgpuTexture.CreateView(&chromaViewDesc);
+
+ 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 sampler1 : sampler;
+ @group(0) @binding(2) var lumaTexture : texture_2d<f32>;
+ @group(0) @binding(3) var chromaTexture : texture_2d<f32>;
+
+ @fragment
+ fn main(@location(0) texCoord : vec2f) -> @location(0) vec4f {
+ let y : f32 = textureSample(lumaTexture, sampler0, texCoord).r;
+ let u : f32 = textureSample(chromaTexture, sampler1, texCoord).r;
+ let v : f32 = textureSample(chromaTexture, sampler1, texCoord).g;
+ return vec4f(y, u, v, 1.0);
+ })");
+
+ utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(
+ device, kYUVImageDataWidthInTexels, kYUVImageDataHeightInTexels);
+ renderPipelineDescriptor.cTargets[0].format = renderPass.colorFormat;
+
+ wgpu::RenderPipeline renderPipeline = device.CreateRenderPipeline(&renderPipelineDescriptor);
+
+ wgpu::Sampler sampler0 = device.CreateSampler();
+ wgpu::Sampler sampler1 = device.CreateSampler();
+
+ wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+ {
+ wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
+ pass.SetPipeline(renderPipeline);
+ pass.SetBindGroup(
+ 0, utils::MakeBindGroup(
+ device, renderPipeline.GetBindGroupLayout(0),
+ {{0, sampler0}, {1, sampler1}, {2, lumaTextureView}, {3, chromaTextureView}}));
+ pass.Draw(6);
+ pass.End();
+ }
+
+ wgpu::CommandBuffer commands = encoder.Finish();
+ queue.Submit(1, &commands);
+
+ std::vector<uint8_t> expectedData = GetTestTextureData(wgpu::TextureFormat::RGBA8Unorm, true);
+ std::vector<utils::RGBA8> expectedRGBA;
+ for (uint8_t i = 0; i < expectedData.size(); i += 3) {
+ expectedRGBA.push_back({expectedData[i], expectedData[i + 1], expectedData[i + 2], 0xFF});
+ }
+
+ EXPECT_TEXTURE_EQ(expectedRGBA.data(), renderPass.color, {0, 0},
+ {kYUVImageDataWidthInTexels, kYUVImageDataHeightInTexels});
mBackend->DestroyVideoTextureForTest(std::move(platformTexture));
}
diff --git a/src/dawn/tests/end2end/VideoViewsTests_win.cpp b/src/dawn/tests/end2end/VideoViewsTests_win.cpp
index 45991dd..d8f4c254 100644
--- a/src/dawn/tests/end2end/VideoViewsTests_win.cpp
+++ b/src/dawn/tests/end2end/VideoViewsTests_win.cpp
@@ -74,6 +74,13 @@
ASSERT_GE(featureOptions5.SharedResourceTier, D3D11_SHARED_RESOURCE_TIER_2);
+ // Not all D3D11 devices support NV12 textures.
+ UINT formatSupport;
+ hr = d3d11Device->CheckFormatSupport(DXGI_FORMAT_NV12, &formatSupport);
+ ASSERT_EQ(hr, S_OK);
+
+ ASSERT_TRUE(formatSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D);
+
mD3d11Device = std::move(d3d11Device);
}