mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-06-03 21:21:23 +00:00
Works around issues on Metal Intel where CopyB2T and WriteTexture with depth/stencil textures do not work correctly. Fixes test failures with depth16unorm in the CTS. Deletes UseTempTextureInStencilTextureToBufferCopy in favor of the stencil blit. The former supposedly fixes a problem where the stencil data is not flushed into the real stencil texture by performing another T2T copy. This only works because the Metal Intel backend also happens to allocate s8 as d32s8. Copying the depth aspect as well seems to make the driver remember to flush the data. The stencil blit is a better fix for the problem since entirely avoids getting the driver into a bad state where the stencil data is not in sync. Fixed: dawn:1389 Change-Id: If34b1d58996157036c164a5bc329e38b5e53f67a Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/117910 Reviewed-by: Loko Kung <lokokung@google.com> Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: Austin Eng <enga@chromium.org>
961 lines
43 KiB
C++
961 lines
43 KiB
C++
// Copyright 2020 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 <array>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "dawn/common/Constants.h"
|
|
#include "dawn/common/Math.h"
|
|
#include "dawn/tests/DawnTest.h"
|
|
#include "dawn/utils/ComboRenderPipelineDescriptor.h"
|
|
#include "dawn/utils/TestUtils.h"
|
|
#include "dawn/utils/TextureUtils.h"
|
|
#include "dawn/utils/WGPUHelpers.h"
|
|
|
|
namespace {
|
|
using TextureFormat = wgpu::TextureFormat;
|
|
DAWN_TEST_PARAM_STRUCT(DepthStencilCopyTestParams, TextureFormat);
|
|
|
|
constexpr std::array<wgpu::TextureFormat, 3> kValidDepthCopyTextureFormats = {
|
|
wgpu::TextureFormat::Depth16Unorm,
|
|
wgpu::TextureFormat::Depth32Float,
|
|
wgpu::TextureFormat::Depth32FloatStencil8,
|
|
};
|
|
|
|
constexpr std::array<wgpu::TextureFormat, 1> kValidDepthCopyFromBufferFormats = {
|
|
wgpu::TextureFormat::Depth16Unorm,
|
|
};
|
|
} // namespace
|
|
|
|
class DepthStencilCopyTests : public DawnTestWithParams<DepthStencilCopyTestParams> {
|
|
protected:
|
|
void SetUp() override {
|
|
DawnTestWithParams<DepthStencilCopyTestParams>::SetUp();
|
|
|
|
DAWN_TEST_UNSUPPORTED_IF(!mIsFormatSupported);
|
|
|
|
// Draw a square in the bottom left quarter of the screen.
|
|
mVertexModule = utils::CreateShaderModule(device, R"(
|
|
@vertex
|
|
fn main(@builtin(vertex_index) VertexIndex : u32) -> @builtin(position) vec4<f32> {
|
|
var pos = array<vec2<f32>, 6>(
|
|
vec2<f32>(-1.0, -1.0),
|
|
vec2<f32>( 0.0, -1.0),
|
|
vec2<f32>(-1.0, 0.0),
|
|
vec2<f32>(-1.0, 0.0),
|
|
vec2<f32>( 0.0, -1.0),
|
|
vec2<f32>( 0.0, 0.0));
|
|
return vec4<f32>(pos[VertexIndex], 0.0, 1.0);
|
|
})");
|
|
}
|
|
|
|
std::vector<wgpu::FeatureName> GetRequiredFeatures() override {
|
|
switch (GetParam().mTextureFormat) {
|
|
case wgpu::TextureFormat::Depth32FloatStencil8:
|
|
if (SupportsFeatures({wgpu::FeatureName::Depth32FloatStencil8})) {
|
|
mIsFormatSupported = true;
|
|
return {wgpu::FeatureName::Depth32FloatStencil8};
|
|
}
|
|
return {};
|
|
default:
|
|
mIsFormatSupported = true;
|
|
return {};
|
|
}
|
|
}
|
|
|
|
bool IsValidDepthCopyTextureFormat() {
|
|
switch (GetParam().mTextureFormat) {
|
|
case wgpu::TextureFormat::Depth16Unorm:
|
|
case wgpu::TextureFormat::Depth32Float:
|
|
case wgpu::TextureFormat::Depth32FloatStencil8:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
wgpu::Texture CreateTexture(uint32_t width,
|
|
uint32_t height,
|
|
wgpu::TextureUsage usage,
|
|
uint32_t mipLevelCount = 1) {
|
|
wgpu::TextureDescriptor texDescriptor = {};
|
|
texDescriptor.size = {width, height, 1};
|
|
texDescriptor.format = GetParam().mTextureFormat;
|
|
texDescriptor.usage = usage;
|
|
texDescriptor.mipLevelCount = mipLevelCount;
|
|
return device.CreateTexture(&texDescriptor);
|
|
}
|
|
|
|
wgpu::Texture CreateDepthStencilTexture(uint32_t width,
|
|
uint32_t height,
|
|
wgpu::TextureUsage usage,
|
|
uint32_t mipLevelCount = 1) {
|
|
wgpu::TextureDescriptor texDescriptor = {};
|
|
texDescriptor.size = {width, height, 1};
|
|
texDescriptor.format = GetParam().mTextureFormat;
|
|
texDescriptor.usage = usage;
|
|
texDescriptor.mipLevelCount = mipLevelCount;
|
|
return device.CreateTexture(&texDescriptor);
|
|
}
|
|
|
|
wgpu::Texture CreateDepthTexture(uint32_t width,
|
|
uint32_t height,
|
|
wgpu::TextureUsage usage,
|
|
uint32_t mipLevelCount = 1) {
|
|
wgpu::TextureDescriptor texDescriptor = {};
|
|
texDescriptor.size = {width, height, 1};
|
|
texDescriptor.format = GetParam().mTextureFormat;
|
|
texDescriptor.usage = usage;
|
|
texDescriptor.mipLevelCount = mipLevelCount;
|
|
return device.CreateTexture(&texDescriptor);
|
|
}
|
|
|
|
// Initialize the depth/stencil values for the texture using a render pass.
|
|
// The texture will be cleared to the "clear" values, and then bottom left corner will
|
|
// be written with the "region" values.
|
|
void InitializeDepthStencilTextureRegion(wgpu::Texture texture,
|
|
float clearDepth,
|
|
float regionDepth,
|
|
uint8_t clearStencil,
|
|
uint8_t regionStencil,
|
|
uint32_t mipLevel = 0) {
|
|
wgpu::TextureFormat format = GetParam().mTextureFormat;
|
|
// Create the render pass used for the initialization.
|
|
utils::ComboRenderPipelineDescriptor renderPipelineDesc;
|
|
renderPipelineDesc.vertex.module = mVertexModule;
|
|
renderPipelineDesc.cFragment.targetCount = 0;
|
|
|
|
wgpu::DepthStencilState* depthStencil = renderPipelineDesc.EnableDepthStencil(format);
|
|
|
|
if (utils::IsStencilOnlyFormat(format)) {
|
|
depthStencil->depthCompare = wgpu::CompareFunction::Always;
|
|
renderPipelineDesc.cFragment.module = utils::CreateShaderModule(device, R"(
|
|
@fragment fn main() {}
|
|
)");
|
|
} else {
|
|
depthStencil->depthWriteEnabled = true;
|
|
renderPipelineDesc.cFragment.module = utils::CreateShaderModule(device, std::string(R"(
|
|
@fragment fn main() -> @builtin(frag_depth) f32 {
|
|
return )" + std::to_string(regionDepth) + R"(;
|
|
})")
|
|
.c_str());
|
|
}
|
|
if (!utils::IsDepthOnlyFormat(format)) {
|
|
depthStencil->stencilFront.passOp = wgpu::StencilOperation::Replace;
|
|
}
|
|
|
|
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&renderPipelineDesc);
|
|
|
|
// Build the render pass used for initialization.
|
|
wgpu::TextureViewDescriptor viewDesc = {};
|
|
viewDesc.baseMipLevel = mipLevel;
|
|
viewDesc.mipLevelCount = 1;
|
|
|
|
utils::ComboRenderPassDescriptor renderPassDesc({}, texture.CreateView(&viewDesc));
|
|
renderPassDesc.UnsetDepthStencilLoadStoreOpsForFormat(format);
|
|
renderPassDesc.cDepthStencilAttachmentInfo.depthClearValue = clearDepth;
|
|
renderPassDesc.cDepthStencilAttachmentInfo.stencilClearValue = clearStencil;
|
|
|
|
// Draw the quad (two triangles)
|
|
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
|
|
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&renderPassDesc);
|
|
pass.SetPipeline(pipeline);
|
|
pass.SetStencilReference(regionStencil);
|
|
pass.Draw(6);
|
|
pass.End();
|
|
|
|
wgpu::CommandBuffer commands = commandEncoder.Finish();
|
|
queue.Submit(1, &commands);
|
|
}
|
|
|
|
wgpu::Texture CreateInitializeDepthStencilTextureAndCopyT2T(float clearDepth,
|
|
float regionDepth,
|
|
uint8_t clearStencil,
|
|
uint8_t regionStencil,
|
|
uint32_t width,
|
|
uint32_t height,
|
|
wgpu::TextureUsage usage,
|
|
uint32_t mipLevel = 0) {
|
|
wgpu::Texture src = CreateDepthStencilTexture(
|
|
width, height, wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc,
|
|
mipLevel + 1);
|
|
|
|
wgpu::Texture dst = CreateDepthStencilTexture(
|
|
width, height, usage | wgpu::TextureUsage::CopyDst, mipLevel + 1);
|
|
|
|
InitializeDepthStencilTextureRegion(src, clearDepth, regionDepth, clearStencil,
|
|
regionStencil, mipLevel);
|
|
|
|
// Perform a T2T copy of all aspects
|
|
{
|
|
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
|
|
wgpu::ImageCopyTexture srcView =
|
|
utils::CreateImageCopyTexture(src, mipLevel, {0, 0, 0});
|
|
wgpu::ImageCopyTexture dstView =
|
|
utils::CreateImageCopyTexture(dst, mipLevel, {0, 0, 0});
|
|
wgpu::Extent3D copySize = {width >> mipLevel, height >> mipLevel, 1};
|
|
commandEncoder.CopyTextureToTexture(&srcView, &dstView, ©Size);
|
|
|
|
wgpu::CommandBuffer commands = commandEncoder.Finish();
|
|
queue.Submit(1, &commands);
|
|
}
|
|
|
|
return dst;
|
|
}
|
|
|
|
uint32_t BufferSizeForTextureCopy(uint32_t width,
|
|
uint32_t height,
|
|
uint32_t depth,
|
|
wgpu::TextureFormat format = wgpu::TextureFormat::RGBA8Unorm,
|
|
wgpu::TextureAspect aspect = wgpu::TextureAspect::All) {
|
|
uint32_t bytesPerPixel = 0;
|
|
switch (format) {
|
|
case wgpu::TextureFormat::Depth24PlusStencil8: {
|
|
ASSERT(aspect == wgpu::TextureAspect::StencilOnly);
|
|
bytesPerPixel = 1;
|
|
break;
|
|
}
|
|
case wgpu::TextureFormat::Depth32FloatStencil8: {
|
|
switch (aspect) {
|
|
case wgpu::TextureAspect::DepthOnly:
|
|
bytesPerPixel = 4;
|
|
break;
|
|
case wgpu::TextureAspect::StencilOnly:
|
|
bytesPerPixel = 1;
|
|
break;
|
|
default:
|
|
UNREACHABLE();
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
bytesPerPixel = utils::GetTexelBlockSizeInBytes(format);
|
|
break;
|
|
}
|
|
|
|
uint32_t bytesPerRow = Align(width * bytesPerPixel, kTextureBytesPerRowAlignment);
|
|
return (bytesPerRow * (height - 1) + width * bytesPerPixel) * depth;
|
|
}
|
|
|
|
wgpu::ShaderModule mVertexModule;
|
|
|
|
private:
|
|
bool mIsFormatSupported = false;
|
|
};
|
|
|
|
// Test copying both aspects in a T2T copy, then copying only stencil.
|
|
TEST_P(DepthStencilCopyTests, T2TBothAspectsThenCopyStencil) {
|
|
// TODO(crbug.com/dawn/1497): glReadPixels: GL error: HIGH: Invalid format and type combination.
|
|
DAWN_SUPPRESS_TEST_IF(IsANGLE());
|
|
|
|
// TODO(crbug.com/dawn/667): Work around some platforms' inability to read back stencil.
|
|
DAWN_TEST_UNSUPPORTED_IF(HasToggleEnabled("disable_depth_stencil_read"));
|
|
|
|
constexpr uint32_t kWidth = 4;
|
|
constexpr uint32_t kHeight = 4;
|
|
|
|
wgpu::Texture texture = CreateInitializeDepthStencilTextureAndCopyT2T(
|
|
0.1f, 0.3f, 1u, 3u, kWidth, kHeight,
|
|
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::RenderAttachment);
|
|
|
|
// Check the stencil
|
|
std::vector<uint8_t> expectedData = {
|
|
1u, 1u, 1u, 1u, //
|
|
1u, 1u, 1u, 1u, //
|
|
3u, 3u, 1u, 1u, //
|
|
3u, 3u, 1u, 1u, //
|
|
};
|
|
EXPECT_TEXTURE_EQ(expectedData.data(), texture, {0, 0}, {kWidth, kHeight}, 0,
|
|
wgpu::TextureAspect::StencilOnly);
|
|
}
|
|
|
|
// Test that part of a non-renderable stencil aspect can be copied. Notably,
|
|
// this test has different behavior on some platforms than T2TBothAspectsThenCopyStencil.
|
|
TEST_P(DepthStencilCopyTests, T2TBothAspectsThenCopyNonRenderableStencil) {
|
|
// TODO(crbug.com/dawn/1497): glReadPixels: GL error: HIGH: Invalid format and type combination.
|
|
DAWN_SUPPRESS_TEST_IF(IsANGLE());
|
|
|
|
// TODO(crbug.com/dawn/667): Work around some platforms' inability to read back stencil.
|
|
DAWN_TEST_UNSUPPORTED_IF(HasToggleEnabled("disable_depth_stencil_read"));
|
|
|
|
constexpr uint32_t kWidth = 4;
|
|
constexpr uint32_t kHeight = 4;
|
|
|
|
wgpu::Texture texture = CreateInitializeDepthStencilTextureAndCopyT2T(
|
|
0.1f, 0.3f, 1u, 3u, kWidth, kHeight, wgpu::TextureUsage::CopySrc);
|
|
|
|
// Check the stencil
|
|
std::vector<uint8_t> expectedData = {
|
|
1u, 1u, 1u, 1u, //
|
|
1u, 1u, 1u, 1u, //
|
|
3u, 3u, 1u, 1u, //
|
|
3u, 3u, 1u, 1u, //
|
|
};
|
|
EXPECT_TEXTURE_EQ(expectedData.data(), texture, {0, 0}, {kWidth, kHeight}, 0,
|
|
wgpu::TextureAspect::StencilOnly);
|
|
}
|
|
|
|
// Test that part of a non-renderable, non-zero mip stencil aspect can be copied. Notably,
|
|
// this test has different behavior on some platforms than T2TBothAspectsThenCopyStencil.
|
|
TEST_P(DepthStencilCopyTests, T2TBothAspectsThenCopyNonRenderableNonZeroMipStencil) {
|
|
// TODO(crbug.com/dawn/1497): glReadPixels: GL error: HIGH: Invalid format and type combination.
|
|
DAWN_SUPPRESS_TEST_IF(IsANGLE());
|
|
|
|
// TODO(crbug.com/dawn/667): Work around some platforms' inability to read back stencil.
|
|
DAWN_TEST_UNSUPPORTED_IF(HasToggleEnabled("disable_depth_stencil_read"));
|
|
|
|
wgpu::Texture texture = CreateInitializeDepthStencilTextureAndCopyT2T(
|
|
0.1f, 0.3f, 1u, 3u, 9, 9, wgpu::TextureUsage::CopySrc, 1);
|
|
|
|
// Check the stencil
|
|
std::vector<uint8_t> expectedData = {
|
|
1u, 1u, 1u, 1u, //
|
|
1u, 1u, 1u, 1u, //
|
|
3u, 3u, 1u, 1u, //
|
|
3u, 3u, 1u, 1u, //
|
|
};
|
|
EXPECT_TEXTURE_EQ(expectedData.data(), texture, {0, 0}, {4, 4}, 1,
|
|
wgpu::TextureAspect::StencilOnly);
|
|
}
|
|
|
|
// Test copying both aspects in a T2T copy, then copying only depth.
|
|
TEST_P(DepthStencilCopyTests, T2TBothAspectsThenCopyDepth) {
|
|
DAWN_TEST_UNSUPPORTED_IF(!IsValidDepthCopyTextureFormat());
|
|
|
|
constexpr uint32_t kWidth = 4;
|
|
constexpr uint32_t kHeight = 4;
|
|
|
|
wgpu::Texture texture = CreateInitializeDepthStencilTextureAndCopyT2T(
|
|
0.1f, 0.3f, 1u, 3u, kWidth, kHeight, wgpu::TextureUsage::RenderAttachment);
|
|
|
|
// Check the depth
|
|
ExpectAttachmentDepthTestData(texture, GetParam().mTextureFormat, kWidth, kHeight, 0, 0,
|
|
{
|
|
0.1, 0.1, 0.1, 0.1, //
|
|
0.1, 0.1, 0.1, 0.1, //
|
|
0.3, 0.3, 0.1, 0.1, //
|
|
0.3, 0.3, 0.1, 0.1, //
|
|
});
|
|
}
|
|
|
|
// Test copying both aspects in a T2T copy, then copying only depth at a nonzero mip.
|
|
TEST_P(DepthStencilCopyTests, T2TBothAspectsThenCopyNonZeroMipDepth) {
|
|
DAWN_TEST_UNSUPPORTED_IF(!IsValidDepthCopyTextureFormat());
|
|
|
|
wgpu::Texture texture = CreateInitializeDepthStencilTextureAndCopyT2T(
|
|
0.1f, 0.3f, 1u, 3u, 8, 8, wgpu::TextureUsage::RenderAttachment, 1);
|
|
|
|
// Check the depth
|
|
ExpectAttachmentDepthTestData(texture, GetParam().mTextureFormat, 4, 4, 0, 1,
|
|
{
|
|
0.1, 0.1, 0.1, 0.1, //
|
|
0.1, 0.1, 0.1, 0.1, //
|
|
0.3, 0.3, 0.1, 0.1, //
|
|
0.3, 0.3, 0.1, 0.1, //
|
|
});
|
|
}
|
|
|
|
// Test copying both aspects in a T2T copy, then copying stencil, then copying depth
|
|
TEST_P(DepthStencilCopyTests, T2TBothAspectsThenCopyStencilThenDepth) {
|
|
DAWN_TEST_UNSUPPORTED_IF(!IsValidDepthCopyTextureFormat());
|
|
|
|
// TODO(crbug.com/dawn/667): Work around some platforms' inability to read back stencil.
|
|
DAWN_TEST_UNSUPPORTED_IF(HasToggleEnabled("disable_depth_stencil_read"));
|
|
|
|
constexpr uint32_t kWidth = 4;
|
|
constexpr uint32_t kHeight = 4;
|
|
|
|
wgpu::Texture texture = CreateInitializeDepthStencilTextureAndCopyT2T(
|
|
0.1f, 0.3f, 1u, 3u, kWidth, kHeight,
|
|
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::RenderAttachment);
|
|
|
|
// Check the stencil
|
|
std::vector<uint8_t> expectedData = {
|
|
1u, 1u, 1u, 1u, //
|
|
1u, 1u, 1u, 1u, //
|
|
3u, 3u, 1u, 1u, //
|
|
3u, 3u, 1u, 1u, //
|
|
};
|
|
EXPECT_TEXTURE_EQ(expectedData.data(), texture, {0, 0}, {kWidth, kHeight}, 0,
|
|
wgpu::TextureAspect::StencilOnly);
|
|
|
|
// Check the depth
|
|
ExpectAttachmentDepthTestData(texture, GetParam().mTextureFormat, kWidth, kHeight, 0, 0,
|
|
{
|
|
0.1, 0.1, 0.1, 0.1, //
|
|
0.1, 0.1, 0.1, 0.1, //
|
|
0.3, 0.3, 0.1, 0.1, //
|
|
0.3, 0.3, 0.1, 0.1, //
|
|
});
|
|
}
|
|
|
|
// Test copying both aspects in a T2T copy, then copying depth, then copying stencil
|
|
TEST_P(DepthStencilCopyTests, T2TBothAspectsThenCopyDepthThenStencil) {
|
|
DAWN_TEST_UNSUPPORTED_IF(!IsValidDepthCopyTextureFormat());
|
|
// TODO(crbug.com/dawn/667): Work around the fact that some platforms are unable to read
|
|
// stencil.
|
|
DAWN_TEST_UNSUPPORTED_IF(HasToggleEnabled("disable_depth_stencil_read"));
|
|
|
|
constexpr uint32_t kWidth = 4;
|
|
constexpr uint32_t kHeight = 4;
|
|
|
|
wgpu::Texture texture = CreateInitializeDepthStencilTextureAndCopyT2T(
|
|
0.1f, 0.3f, 1u, 3u, kWidth, kHeight,
|
|
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::RenderAttachment);
|
|
|
|
// Check the depth
|
|
ExpectAttachmentDepthTestData(texture, GetParam().mTextureFormat, kWidth, kHeight, 0, 0,
|
|
{
|
|
0.1, 0.1, 0.1, 0.1, //
|
|
0.1, 0.1, 0.1, 0.1, //
|
|
0.3, 0.3, 0.1, 0.1, //
|
|
0.3, 0.3, 0.1, 0.1, //
|
|
});
|
|
|
|
// Check the stencil
|
|
std::vector<uint8_t> expectedData = {
|
|
1u, 1u, 1u, 1u, //
|
|
1u, 1u, 1u, 1u, //
|
|
3u, 3u, 1u, 1u, //
|
|
3u, 3u, 1u, 1u, //
|
|
};
|
|
EXPECT_TEXTURE_EQ(expectedData.data(), texture, {0, 0}, {kWidth, kHeight}, 0,
|
|
wgpu::TextureAspect::StencilOnly);
|
|
}
|
|
|
|
class DepthCopyTests : public DepthStencilCopyTests {
|
|
public:
|
|
void DoCopyFromDepthTest(uint32_t bufferCopyOffset,
|
|
float initDepth,
|
|
uint32_t textureWidth,
|
|
uint32_t textureHeight,
|
|
uint32_t testLevel) {
|
|
// TODO(crbug.com/dawn/1237): Depth16Unorm test failed on OpenGL and OpenGLES which says
|
|
// Invalid format and type combination in glReadPixels
|
|
DAWN_TEST_UNSUPPORTED_IF(GetParam().mTextureFormat == wgpu::TextureFormat::Depth16Unorm &&
|
|
(IsOpenGL() || IsOpenGLES()));
|
|
|
|
// TODO(crbug.com/dawn/1291): These tests are failing on GLES (both native and ANGLE)
|
|
// when using Tint/GLSL.
|
|
DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
|
|
|
|
uint32_t mipLevelCount = testLevel + 1;
|
|
wgpu::Texture texture = CreateTexture(
|
|
textureWidth, textureHeight,
|
|
wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc, mipLevelCount);
|
|
|
|
InitializeDepthStencilTextureRegion(texture, 0.f, initDepth, 0, 0, testLevel);
|
|
|
|
uint32_t copyWidth = textureWidth >> testLevel;
|
|
uint32_t copyHeight = textureHeight >> testLevel;
|
|
wgpu::Extent3D copySize = {copyWidth, copyHeight, 1};
|
|
|
|
constexpr uint32_t kBytesPerRow = kTextureBytesPerRowAlignment;
|
|
wgpu::BufferDescriptor bufferDescriptor = {};
|
|
bufferDescriptor.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
|
|
bufferDescriptor.size =
|
|
bufferCopyOffset + BufferSizeForTextureCopy(copyWidth, copyHeight, 1,
|
|
GetParam().mTextureFormat,
|
|
wgpu::TextureAspect::DepthOnly);
|
|
wgpu::Buffer destinationBuffer = device.CreateBuffer(&bufferDescriptor);
|
|
|
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
|
wgpu::ImageCopyTexture imageCopyTexture = utils::CreateImageCopyTexture(
|
|
texture, testLevel, {0, 0, 0}, wgpu::TextureAspect::DepthOnly);
|
|
wgpu::ImageCopyBuffer imageCopyBuffer = utils::CreateImageCopyBuffer(
|
|
destinationBuffer, bufferCopyOffset, kBytesPerRow, copyHeight);
|
|
encoder.CopyTextureToBuffer(&imageCopyTexture, &imageCopyBuffer, ©Size);
|
|
wgpu::CommandBuffer commandBuffer = encoder.Finish();
|
|
queue.Submit(1, &commandBuffer);
|
|
|
|
if (GetParam().mTextureFormat == wgpu::TextureFormat::Depth16Unorm) {
|
|
uint16_t expected = FloatToUnorm<uint16_t>(initDepth);
|
|
std::vector<uint16_t> expectedData = {
|
|
0, 0, 0, 0, //
|
|
0, 0, 0, 0, //
|
|
expected, expected, 0, 0, //
|
|
expected, expected, 0, 0, //
|
|
};
|
|
|
|
for (uint32_t y = 0; y < copyHeight; ++y) {
|
|
EXPECT_BUFFER_U16_RANGE_EQ(expectedData.data() + copyWidth * y, destinationBuffer,
|
|
bufferCopyOffset + y * kBytesPerRow, copyWidth);
|
|
}
|
|
|
|
} else {
|
|
std::vector<float> expectedData = {
|
|
0.0, 0.0, 0.0, 0.0, //
|
|
0.0, 0.0, 0.0, 0.0, //
|
|
initDepth, initDepth, 0.0, 0.0, //
|
|
initDepth, initDepth, 0.0, 0.0, //
|
|
};
|
|
|
|
for (uint32_t y = 0; y < copyHeight; ++y) {
|
|
EXPECT_BUFFER_FLOAT_RANGE_EQ(expectedData.data() + copyWidth * y, destinationBuffer,
|
|
bufferCopyOffset + y * kBytesPerRow, copyWidth);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// Test copying the depth-only aspect into a buffer.
|
|
TEST_P(DepthCopyTests, FromDepthAspect) {
|
|
constexpr float kInitDepth = 0.2f;
|
|
constexpr uint32_t kBufferCopyOffset = 0;
|
|
constexpr uint32_t kWidth = 4;
|
|
constexpr uint32_t kHeight = 4;
|
|
constexpr uint32_t kTestLevel = 0;
|
|
DoCopyFromDepthTest(kBufferCopyOffset, kInitDepth, kWidth, kHeight, kTestLevel);
|
|
}
|
|
|
|
// Test copying the depth-only aspect into a buffer at a non-zero offset.
|
|
TEST_P(DepthCopyTests, FromDepthAspectToBufferAtNonZeroOffset) {
|
|
constexpr float kInitDepth = 0.2f;
|
|
constexpr uint32_t kWidth = 4;
|
|
constexpr uint32_t kHeight = 4;
|
|
constexpr uint32_t kTestLevel = 0;
|
|
constexpr std::array<uint32_t, 2> kBufferCopyOffsets = {4u, 512u};
|
|
for (uint32_t offset : kBufferCopyOffsets) {
|
|
DoCopyFromDepthTest(offset, kInitDepth, kWidth, kHeight, kTestLevel);
|
|
}
|
|
}
|
|
|
|
// Test copying the non-zero mip, depth-only aspect into a buffer.
|
|
TEST_P(DepthCopyTests, FromNonZeroMipDepthAspect) {
|
|
constexpr float kInitDepth = 0.2f;
|
|
constexpr uint32_t kBufferCopyOffset = 0;
|
|
constexpr uint32_t kWidth = 9;
|
|
constexpr uint32_t kHeight = 9;
|
|
constexpr uint32_t kTestLevel = 1;
|
|
DoCopyFromDepthTest(kBufferCopyOffset, kInitDepth, kWidth, kHeight, kTestLevel);
|
|
}
|
|
|
|
class DepthCopyFromBufferTests : public DepthStencilCopyTests {
|
|
public:
|
|
void DoTest(uint32_t bufferCopyOffset, bool hasRenderAttachmentUsage) {
|
|
// TODO(crbug.com/dawn/1237): Depth16Unorm test failed on OpenGL and OpenGLES which says
|
|
// Invalid format and type combination in glReadPixels
|
|
DAWN_TEST_UNSUPPORTED_IF(GetParam().mTextureFormat == wgpu::TextureFormat::Depth16Unorm &&
|
|
(IsOpenGL() || IsOpenGLES()));
|
|
|
|
constexpr uint32_t kWidth = 8;
|
|
constexpr uint32_t kHeight = 1;
|
|
|
|
wgpu::TextureUsage textureUsage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc;
|
|
// On D3D12 backend the resource flag D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL is set only
|
|
// when wgpu::TextureUsage::RenderAttachment is set on the creation of a depth stencil
|
|
// texture.
|
|
if (hasRenderAttachmentUsage) {
|
|
textureUsage |= wgpu::TextureUsage::RenderAttachment;
|
|
}
|
|
wgpu::Texture destTexture = CreateTexture(kWidth, kHeight, textureUsage);
|
|
|
|
wgpu::BufferDescriptor descriptor;
|
|
descriptor.size = bufferCopyOffset +
|
|
BufferSizeForTextureCopy(kWidth, kHeight, 1, GetParam().mTextureFormat);
|
|
descriptor.usage = wgpu::BufferUsage::CopySrc;
|
|
descriptor.mappedAtCreation = true;
|
|
wgpu::Buffer srcBuffer = device.CreateBuffer(&descriptor);
|
|
|
|
constexpr uint32_t kBytesPerRow = kTextureBytesPerRowAlignment;
|
|
wgpu::ImageCopyBuffer imageCopyBuffer =
|
|
utils::CreateImageCopyBuffer(srcBuffer, bufferCopyOffset, kBytesPerRow, kHeight);
|
|
wgpu::ImageCopyTexture imageCopyTexture = utils::CreateImageCopyTexture(
|
|
destTexture, 0, {0, 0, 0}, wgpu::TextureAspect::DepthOnly);
|
|
wgpu::Extent3D extent = {kWidth, kHeight, 1};
|
|
|
|
constexpr float kInitDepth = 0.2f;
|
|
|
|
// This expectation is the test as it performs the CopyTextureToBuffer.
|
|
if (GetParam().mTextureFormat == wgpu::TextureFormat::Depth16Unorm) {
|
|
uint16_t expected = FloatToUnorm<uint16_t>(kInitDepth);
|
|
std::vector<uint16_t> expectedData = {
|
|
0, 0, expected, expected, 0, 0, expected, expected,
|
|
};
|
|
size_t expectedSize = expectedData.size() * sizeof(uint16_t);
|
|
memcpy(srcBuffer.GetMappedRange(bufferCopyOffset, expectedSize), expectedData.data(),
|
|
expectedSize);
|
|
srcBuffer.Unmap();
|
|
|
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
|
encoder.CopyBufferToTexture(&imageCopyBuffer, &imageCopyTexture, &extent);
|
|
wgpu::CommandBuffer commands = encoder.Finish();
|
|
queue.Submit(1, &commands);
|
|
|
|
EXPECT_TEXTURE_EQ(expectedData.data(), destTexture, {0, 0}, {kWidth, kHeight}, 0,
|
|
wgpu::TextureAspect::DepthOnly);
|
|
} else {
|
|
std::vector<float> expectedData = {
|
|
0.0, 0.0, kInitDepth, kInitDepth, 0.0, 0.0, kInitDepth, kInitDepth,
|
|
};
|
|
size_t expectedSize = expectedData.size() * sizeof(float);
|
|
|
|
memcpy(srcBuffer.GetMappedRange(bufferCopyOffset, expectedSize), expectedData.data(),
|
|
expectedSize);
|
|
srcBuffer.Unmap();
|
|
|
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
|
encoder.CopyBufferToTexture(&imageCopyBuffer, &imageCopyTexture, &extent);
|
|
wgpu::CommandBuffer commands = encoder.Finish();
|
|
queue.Submit(1, &commands);
|
|
|
|
EXPECT_TEXTURE_EQ(expectedData.data(), destTexture, {0, 0}, {kWidth, kHeight}, 0,
|
|
wgpu::TextureAspect::DepthOnly);
|
|
}
|
|
}
|
|
};
|
|
|
|
// Test copying the depth-only aspect from a buffer.
|
|
TEST_P(DepthCopyFromBufferTests, BufferToDepthAspect) {
|
|
constexpr uint32_t kBufferCopyOffset = 0;
|
|
constexpr bool kIsRenderable = false;
|
|
DoTest(kBufferCopyOffset, kIsRenderable);
|
|
}
|
|
|
|
// Test copying the depth-only aspect from a buffer at a non-zero offset.
|
|
TEST_P(DepthCopyFromBufferTests, BufferToNonRenderableDepthAspectAtNonZeroOffset) {
|
|
constexpr std::array<uint32_t, 2> kBufferCopyOffsets = {8, 512};
|
|
constexpr bool kIsRenderable = false;
|
|
for (uint32_t offset : kBufferCopyOffsets) {
|
|
DoTest(offset, kIsRenderable);
|
|
}
|
|
}
|
|
|
|
// Test copying the depth-only aspect from a buffer at a non-zero offset.
|
|
TEST_P(DepthCopyFromBufferTests, BufferToRenderableDepthAspectAtNonZeroOffset) {
|
|
constexpr std::array<uint32_t, 2> kBufferCopyOffsets = {8, 512};
|
|
constexpr bool kIsRenderable = true;
|
|
for (uint32_t offset : kBufferCopyOffsets) {
|
|
DoTest(offset, kIsRenderable);
|
|
}
|
|
}
|
|
|
|
class StencilCopyTests : public DepthStencilCopyTests {
|
|
public:
|
|
void DoCopyFromStencilTest(uint32_t bufferCopyOffset,
|
|
uint32_t textureWidth,
|
|
uint32_t textureHeight,
|
|
uint32_t testLevel) {
|
|
// TODO(crbug.com/dawn/1497): glReadPixels: GL error: HIGH: Invalid format and type
|
|
// combination.
|
|
DAWN_SUPPRESS_TEST_IF(IsANGLE());
|
|
|
|
// TODO(crbug.com/dawn/667): Work around the fact that some platforms are unable to read
|
|
// stencil.
|
|
DAWN_TEST_UNSUPPORTED_IF(HasToggleEnabled("disable_depth_stencil_read"));
|
|
|
|
uint32_t mipLevelCount = testLevel + 1;
|
|
wgpu::Texture depthStencilTexture = CreateDepthStencilTexture(
|
|
textureWidth, textureHeight,
|
|
wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc, mipLevelCount);
|
|
|
|
InitializeDepthStencilTextureRegion(depthStencilTexture, 0.f, 0.3f, 0u, 1u, testLevel);
|
|
|
|
std::vector<uint8_t> expectedData = {
|
|
0u, 0u, 0u, 0u, //
|
|
0u, 0u, 0u, 0u, //
|
|
1u, 1u, 0u, 0u, //
|
|
1u, 1u, 0u, 0u, //
|
|
};
|
|
|
|
uint32_t copyWidth = textureWidth >> testLevel;
|
|
uint32_t copyHeight = textureHeight >> testLevel;
|
|
ASSERT_EQ(expectedData.size(), copyWidth * copyHeight);
|
|
wgpu::Extent3D copySize = {copyWidth, copyHeight, 1};
|
|
|
|
constexpr uint32_t kBytesPerRow = kTextureBytesPerRowAlignment;
|
|
wgpu::BufferDescriptor bufferDescriptor = {};
|
|
bufferDescriptor.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
|
|
bufferDescriptor.size =
|
|
bufferCopyOffset + BufferSizeForTextureCopy(copyWidth, copyHeight, 1,
|
|
GetParam().mTextureFormat,
|
|
wgpu::TextureAspect::StencilOnly);
|
|
wgpu::Buffer destinationBuffer = device.CreateBuffer(&bufferDescriptor);
|
|
|
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
|
wgpu::ImageCopyTexture imageCopyTexture = utils::CreateImageCopyTexture(
|
|
depthStencilTexture, testLevel, {0, 0, 0}, wgpu::TextureAspect::StencilOnly);
|
|
wgpu::ImageCopyBuffer imageCopyBuffer = utils::CreateImageCopyBuffer(
|
|
destinationBuffer, bufferCopyOffset, kBytesPerRow, copyHeight);
|
|
encoder.CopyTextureToBuffer(&imageCopyTexture, &imageCopyBuffer, ©Size);
|
|
wgpu::CommandBuffer commandBuffer = encoder.Finish();
|
|
queue.Submit(1, &commandBuffer);
|
|
|
|
for (uint32_t y = 0; y < copyHeight; ++y) {
|
|
EXPECT_BUFFER_U8_RANGE_EQ(expectedData.data() + copyWidth * y, destinationBuffer,
|
|
bufferCopyOffset + y * kBytesPerRow, copyWidth);
|
|
}
|
|
}
|
|
|
|
void DoCopyToStencilTest(uint32_t bufferCopyOffset) {
|
|
// Copies to a single aspect are unsupported on OpenGL.
|
|
DAWN_TEST_UNSUPPORTED_IF(IsOpenGL());
|
|
DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
|
|
|
|
// TODO(crbug.com/dawn/1273): Fails on Win11 with D3D12 debug layer and full validation
|
|
DAWN_SUPPRESS_TEST_IF(IsD3D12() && IsBackendValidationEnabled());
|
|
|
|
// Create a stencil texture
|
|
constexpr uint32_t kWidth = 4;
|
|
constexpr uint32_t kHeight = 4;
|
|
const bool hasDepth = !utils::IsStencilOnlyFormat(GetParam().mTextureFormat);
|
|
|
|
wgpu::Texture depthStencilTexture = CreateDepthStencilTexture(
|
|
kWidth, kHeight,
|
|
wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc |
|
|
wgpu::TextureUsage::CopyDst);
|
|
|
|
if (hasDepth) {
|
|
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
|
|
|
|
// Clear depth to 0.7, so we can check that the stencil copy doesn't mutate the depth.
|
|
utils::ComboRenderPassDescriptor passDescriptor({}, depthStencilTexture.CreateView());
|
|
passDescriptor.UnsetDepthStencilLoadStoreOpsForFormat(GetParam().mTextureFormat);
|
|
passDescriptor.cDepthStencilAttachmentInfo.depthClearValue = 0.7;
|
|
|
|
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
|
|
pass.End();
|
|
|
|
wgpu::CommandBuffer commands = commandEncoder.Finish();
|
|
queue.Submit(1, &commands);
|
|
}
|
|
|
|
std::vector<uint8_t> stencilData = {
|
|
1u, 2u, 3u, 4u, //
|
|
5u, 6u, 7u, 8u, //
|
|
9u, 10u, 11u, 12u, //
|
|
13u, 14u, 15u, 16u, //
|
|
};
|
|
|
|
// After copying stencil data in, we will decrement stencil values in the bottom left
|
|
// of the screen. This is the expected result.
|
|
std::vector<uint8_t> expectedStencilData = {
|
|
1u, 2u, 3u, 4u, //
|
|
5u, 6u, 7u, 8u, //
|
|
8u, 9u, 11u, 12u, //
|
|
12u, 13u, 15u, 16u, //
|
|
};
|
|
|
|
// Upload the stencil data.
|
|
{
|
|
wgpu::BufferDescriptor descriptor;
|
|
descriptor.size = bufferCopyOffset + BufferSizeForTextureCopy(
|
|
kWidth, kHeight, 1, GetParam().mTextureFormat,
|
|
wgpu::TextureAspect::StencilOnly);
|
|
descriptor.usage = wgpu::BufferUsage::CopySrc;
|
|
descriptor.mappedAtCreation = true;
|
|
wgpu::Buffer srcBuffer = device.CreateBuffer(&descriptor);
|
|
uint8_t* mappedPtr = static_cast<uint8_t*>(srcBuffer.GetMappedRange(bufferCopyOffset));
|
|
constexpr uint32_t kBytesPerRow = kTextureBytesPerRowAlignment;
|
|
for (uint32_t y = 0; y < kHeight; ++y) {
|
|
memcpy(mappedPtr + y * kBytesPerRow, stencilData.data() + y * kWidth, kWidth);
|
|
}
|
|
srcBuffer.Unmap();
|
|
|
|
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
|
|
wgpu::ImageCopyBuffer imageCopyBuffer =
|
|
utils::CreateImageCopyBuffer(srcBuffer, bufferCopyOffset, kBytesPerRow, kHeight);
|
|
wgpu::ImageCopyTexture imageCopyTexture = utils::CreateImageCopyTexture(
|
|
depthStencilTexture, 0, {0, 0, 0}, wgpu::TextureAspect::StencilOnly);
|
|
wgpu::Extent3D copySize = {kWidth, kHeight, 1};
|
|
commandEncoder.CopyBufferToTexture(&imageCopyBuffer, &imageCopyTexture, ©Size);
|
|
wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
|
|
queue.Submit(1, &commandBuffer);
|
|
}
|
|
|
|
// Decrement the stencil value in a render pass to ensure the data is visible to the
|
|
// pipeline.
|
|
{
|
|
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
|
|
// Create a render pipline which decrements the stencil value for passing fragments.
|
|
// A quad is drawn in the bottom left.
|
|
utils::ComboRenderPipelineDescriptor renderPipelineDesc;
|
|
renderPipelineDesc.vertex.module = mVertexModule;
|
|
renderPipelineDesc.cFragment.module = utils::CreateShaderModule(device, R"(
|
|
@fragment fn main() {
|
|
})");
|
|
renderPipelineDesc.cFragment.targetCount = 0;
|
|
wgpu::DepthStencilState* depthStencil =
|
|
renderPipelineDesc.EnableDepthStencil(GetParam().mTextureFormat);
|
|
depthStencil->stencilFront.passOp = wgpu::StencilOperation::DecrementClamp;
|
|
if (!hasDepth) {
|
|
depthStencil->depthWriteEnabled = false;
|
|
depthStencil->depthCompare = wgpu::CompareFunction::Always;
|
|
}
|
|
|
|
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&renderPipelineDesc);
|
|
|
|
// Create a render pass which loads the stencil. We want to load the values we
|
|
// copied in. Also load the canary depth values so they're not lost.
|
|
utils::ComboRenderPassDescriptor passDescriptor({}, depthStencilTexture.CreateView());
|
|
passDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = wgpu::LoadOp::Load;
|
|
passDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Load;
|
|
passDescriptor.UnsetDepthStencilLoadStoreOpsForFormat(GetParam().mTextureFormat);
|
|
|
|
// Draw the quad in the bottom left (two triangles).
|
|
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
|
|
pass.SetPipeline(pipeline);
|
|
pass.Draw(6);
|
|
pass.End();
|
|
|
|
wgpu::CommandBuffer commands = commandEncoder.Finish();
|
|
queue.Submit(1, &commands);
|
|
}
|
|
|
|
// Copy back the stencil data and check it is correct.
|
|
EXPECT_TEXTURE_EQ(expectedStencilData.data(), depthStencilTexture, {0, 0},
|
|
{kWidth, kHeight}, 0, wgpu::TextureAspect::StencilOnly);
|
|
|
|
if (hasDepth) {
|
|
ExpectAttachmentDepthTestData(depthStencilTexture, GetParam().mTextureFormat, kWidth,
|
|
kHeight, 0, 0,
|
|
{
|
|
0.7, 0.7, 0.7, 0.7, //
|
|
0.7, 0.7, 0.7, 0.7, //
|
|
0.7, 0.7, 0.7, 0.7, //
|
|
0.7, 0.7, 0.7, 0.7, //
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
// Test copying the stencil-only aspect into a buffer.
|
|
TEST_P(StencilCopyTests, FromStencilAspect) {
|
|
constexpr uint32_t kWidth = 4;
|
|
constexpr uint32_t kHeight = 4;
|
|
constexpr uint32_t kTestLevel = 0;
|
|
constexpr uint32_t kBufferCopyOffset = 0;
|
|
DoCopyFromStencilTest(kBufferCopyOffset, kWidth, kHeight, kTestLevel);
|
|
}
|
|
|
|
// Test copying the stencil-only aspect into a buffer at a non-zero offset
|
|
TEST_P(StencilCopyTests, FromStencilAspectAtNonZeroOffset) {
|
|
constexpr uint32_t kWidth = 4;
|
|
constexpr uint32_t kHeight = 4;
|
|
constexpr uint32_t kTestLevel = 0;
|
|
constexpr std::array<uint32_t, 2> kBufferCopyOffsets = {4u, 512u};
|
|
for (uint32_t offset : kBufferCopyOffsets) {
|
|
DoCopyFromStencilTest(offset, kWidth, kHeight, kTestLevel);
|
|
}
|
|
}
|
|
|
|
// Test copying the non-zero mip, stencil-only aspect into a buffer.
|
|
TEST_P(StencilCopyTests, FromNonZeroMipStencilAspect) {
|
|
constexpr uint32_t kWidth = 9;
|
|
constexpr uint32_t kHeight = 9;
|
|
constexpr uint32_t kTestLevel = 1;
|
|
constexpr uint32_t kBufferCopyOffset = 0;
|
|
DoCopyFromStencilTest(kBufferCopyOffset, kWidth, kHeight, kTestLevel);
|
|
}
|
|
|
|
// Test copying to the stencil-aspect of a texture
|
|
TEST_P(StencilCopyTests, ToStencilAspect) {
|
|
constexpr uint32_t kBufferCopyOffset = 0;
|
|
DoCopyToStencilTest(kBufferCopyOffset);
|
|
}
|
|
|
|
// Test copying to the stencil-aspect of a texture at non-zero offset
|
|
TEST_P(StencilCopyTests, ToStencilAspectAtNonZeroOffset) {
|
|
constexpr std::array<uint32_t, 2> kBufferCopyOffsets = {8, 512};
|
|
for (uint32_t offset : kBufferCopyOffsets) {
|
|
DoCopyToStencilTest(offset);
|
|
}
|
|
}
|
|
|
|
// Test uploading to the non-zero mip, stencil-only aspect of a texture,
|
|
// and then checking the contents with a stencil test.
|
|
TEST_P(StencilCopyTests, CopyNonzeroMipThenReadWithStencilTest) {
|
|
// Copies to a single aspect are unsupported on OpenGL.
|
|
DAWN_TEST_UNSUPPORTED_IF(IsOpenGL());
|
|
DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
|
|
|
|
// Create a stencil texture
|
|
constexpr uint32_t kWidth = 4;
|
|
constexpr uint32_t kHeight = 4;
|
|
constexpr uint32_t kMipLevel = 1;
|
|
|
|
wgpu::Texture depthStencilTexture =
|
|
CreateDepthStencilTexture(kWidth, kHeight,
|
|
wgpu::TextureUsage::RenderAttachment |
|
|
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst,
|
|
kMipLevel + 1);
|
|
|
|
std::vector<uint8_t> stencilData = {
|
|
7u, 7u, //
|
|
7u, 7u, //
|
|
};
|
|
|
|
// Upload the stencil data.
|
|
{
|
|
wgpu::TextureDataLayout dataLayout = {};
|
|
dataLayout.bytesPerRow = kWidth >> kMipLevel;
|
|
|
|
wgpu::ImageCopyTexture imageCopyTexture = utils::CreateImageCopyTexture(
|
|
depthStencilTexture, 1, {0, 0, 0}, wgpu::TextureAspect::StencilOnly);
|
|
wgpu::Extent3D copySize = {kWidth >> kMipLevel, kHeight >> kMipLevel, 1};
|
|
|
|
queue.WriteTexture(&imageCopyTexture, stencilData.data(), stencilData.size(), &dataLayout,
|
|
©Size);
|
|
}
|
|
|
|
// Check the stencil contents.
|
|
ExpectAttachmentStencilTestData(depthStencilTexture, GetParam().mTextureFormat,
|
|
kWidth >> kMipLevel, kWidth >> kMipLevel, 0u, kMipLevel, 7u);
|
|
}
|
|
|
|
DAWN_INSTANTIATE_TEST_P(DepthStencilCopyTests,
|
|
{D3D12Backend(), MetalBackend(),
|
|
MetalBackend({"use_blit_for_buffer_to_depth_texture_copy",
|
|
"use_blit_for_buffer_to_stencil_texture_copy"}),
|
|
OpenGLBackend(), OpenGLESBackend(),
|
|
// Test with the vulkan_use_s8 toggle forced on and off.
|
|
VulkanBackend({"vulkan_use_s8"}, {}),
|
|
VulkanBackend({}, {"vulkan_use_s8"})},
|
|
std::vector<wgpu::TextureFormat>(utils::kDepthAndStencilFormats.begin(),
|
|
utils::kDepthAndStencilFormats.end()));
|
|
|
|
DAWN_INSTANTIATE_TEST_P(DepthCopyTests,
|
|
{D3D12Backend(),
|
|
D3D12Backend({"d3d12_use_temp_buffer_in_depth_stencil_texture_and_buffer_"
|
|
"copy_with_non_zero_buffer_offset"}),
|
|
MetalBackend(), OpenGLBackend(), OpenGLESBackend(), VulkanBackend()},
|
|
std::vector<wgpu::TextureFormat>(kValidDepthCopyTextureFormats.begin(),
|
|
kValidDepthCopyTextureFormats.end()));
|
|
|
|
DAWN_INSTANTIATE_TEST_P(DepthCopyFromBufferTests,
|
|
{D3D12Backend(),
|
|
D3D12Backend({"d3d12_use_temp_buffer_in_depth_stencil_texture_and_buffer_"
|
|
"copy_with_non_zero_buffer_offset"}),
|
|
MetalBackend(),
|
|
MetalBackend({"use_blit_for_buffer_to_depth_texture_copy"}),
|
|
OpenGLBackend(), OpenGLESBackend(), VulkanBackend()},
|
|
std::vector<wgpu::TextureFormat>(kValidDepthCopyFromBufferFormats.begin(),
|
|
kValidDepthCopyFromBufferFormats.end()));
|
|
|
|
DAWN_INSTANTIATE_TEST_P(
|
|
StencilCopyTests,
|
|
{D3D12Backend(),
|
|
D3D12Backend({"d3d12_use_temp_buffer_in_depth_stencil_texture_and_buffer_"
|
|
"copy_with_non_zero_buffer_offset"}),
|
|
MetalBackend(), MetalBackend({"metal_use_combined_depth_stencil_format_for_stencil8"}),
|
|
MetalBackend(
|
|
{"metal_use_both_depth_and_stencil_attachments_for_combined_depth_stencil_formats"}),
|
|
MetalBackend({"use_blit_for_buffer_to_stencil_texture_copy"}), OpenGLBackend(),
|
|
OpenGLESBackend(),
|
|
// Test with the vulkan_use_s8 toggle forced on and off.
|
|
VulkanBackend({"vulkan_use_s8"}, {}), VulkanBackend({}, {"vulkan_use_s8"})},
|
|
std::vector<wgpu::TextureFormat>(utils::kStencilFormats.begin(), utils::kStencilFormats.end()));
|