blob: 32084817b91a784a8750f63953217cd7d6873abf [file] [log] [blame]
// Copyright 2019 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 "tests/DawnTest.h"
#include "common/Assert.h"
#include "common/Constants.h"
#include "common/Math.h"
#include "utils/ComboRenderPipelineDescriptor.h"
#include "utils/DawnHelpers.h"
// The helper struct to configure the copies between buffers and textures.
struct CopyConfig {
dawn::TextureDescriptor textureDescriptor;
dawn::Extent3D copyExtent3D;
dawn::Origin3D copyOrigin3D = {0, 0, 0};
uint32_t viewMipmapLevel = 0;
uint32_t viewArrayLayer = 0;
uint32_t bufferOffset = 0;
uint32_t rowPitchAlignment = kTextureRowPitchAlignment;
uint32_t imageHeight = 0;
};
class CompressedTextureBCFormatTest : public DawnTest {
protected:
void SetUp() override {
DawnTest::SetUp();
mBindGroupLayout = utils::MakeBindGroupLayout(
device, {{0, dawn::ShaderStage::Fragment, dawn::BindingType::Sampler},
{1, dawn::ShaderStage::Fragment, dawn::BindingType::SampledTexture}});
}
std::vector<const char*> GetRequiredExtensions() override {
mIsBCFormatSupported = SupportsExtensions({"texture_compression_bc"});
if (!mIsBCFormatSupported) {
return {};
}
return {"texture_compression_bc"};
}
bool IsBCFormatSupported() const {
return mIsBCFormatSupported;
}
// Copy the compressed texture data into the destination texture as is specified in copyConfig.
void InitializeDataInCompressedTexture(dawn::Texture bcCompressedTexture,
const CopyConfig& copyConfig) {
ASSERT(IsBCFormatSupported());
// Compute the upload buffer size with rowPitchAlignment and the copy region.
const dawn::Extent3D textureSize = copyConfig.textureDescriptor.size;
uint32_t actualWidthAtLevel = textureSize.width >> copyConfig.viewMipmapLevel;
uint32_t actualHeightAtLevel = textureSize.height >> copyConfig.viewMipmapLevel;
uint32_t copyWidthInBlockAtLevel =
(actualWidthAtLevel + kBCBlockWidthInTexels - 1) / kBCBlockWidthInTexels;
uint32_t copyHeightInBlockAtLevel =
(actualHeightAtLevel + kBCBlockHeightInTexels - 1) / kBCBlockHeightInTexels;
uint32_t bufferRowPitchInBytes = 0;
if (copyConfig.rowPitchAlignment != 0) {
bufferRowPitchInBytes = copyConfig.rowPitchAlignment;
} else {
bufferRowPitchInBytes =
copyWidthInBlockAtLevel *
CompressedFormatBlockSizeInBytes(copyConfig.textureDescriptor.format);
}
uint32_t uploadBufferSize =
copyConfig.bufferOffset + bufferRowPitchInBytes * copyHeightInBlockAtLevel;
// Fill uploadData with the pre-prepared one-block compressed texture data.
std::vector<uint8_t> uploadData(uploadBufferSize, 0);
std::vector<uint8_t> oneBlockCompressedTextureData =
GetOneBlockBCFormatTextureData(copyConfig.textureDescriptor.format);
for (uint32_t h = 0; h < copyHeightInBlockAtLevel; ++h) {
for (uint32_t w = 0; w < copyWidthInBlockAtLevel; ++w) {
uint32_t uploadBufferOffset = copyConfig.bufferOffset + bufferRowPitchInBytes * h +
oneBlockCompressedTextureData.size() * w;
std::memcpy(&uploadData[uploadBufferOffset], oneBlockCompressedTextureData.data(),
oneBlockCompressedTextureData.size() * sizeof(uint8_t));
}
}
// Copy texture data from a staging buffer to the destination texture.
dawn::Buffer stagingBuffer = utils::CreateBufferFromData(
device, uploadData.data(), uploadBufferSize, dawn::BufferUsage::CopySrc);
dawn::BufferCopyView bufferCopyView =
utils::CreateBufferCopyView(stagingBuffer, copyConfig.bufferOffset,
copyConfig.rowPitchAlignment, copyConfig.imageHeight);
dawn::TextureCopyView textureCopyView =
utils::CreateTextureCopyView(bcCompressedTexture, copyConfig.viewMipmapLevel,
copyConfig.viewArrayLayer, copyConfig.copyOrigin3D);
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, &copyConfig.copyExtent3D);
dawn::CommandBuffer copy = encoder.Finish();
queue.Submit(1, &copy);
}
// Create the bind group that includes a BC texture and a sampler.
dawn::BindGroup CreateBindGroupForTest(dawn::Texture bcCompressedTexture,
dawn::TextureFormat bcFormat,
uint32_t baseArrayLayer = 0,
uint32_t baseMipLevel = 0) {
ASSERT(IsBCFormatSupported());
dawn::SamplerDescriptor samplerDesc = utils::GetDefaultSamplerDescriptor();
samplerDesc.minFilter = dawn::FilterMode::Nearest;
samplerDesc.magFilter = dawn::FilterMode::Nearest;
dawn::Sampler sampler = device.CreateSampler(&samplerDesc);
dawn::TextureViewDescriptor textureViewDescriptor;
textureViewDescriptor.format = bcFormat;
textureViewDescriptor.dimension = dawn::TextureViewDimension::e2D;
textureViewDescriptor.baseMipLevel = baseMipLevel;
textureViewDescriptor.baseArrayLayer = baseArrayLayer;
textureViewDescriptor.arrayLayerCount = 1;
textureViewDescriptor.mipLevelCount = 1;
dawn::TextureView bcTextureView = bcCompressedTexture.CreateView(&textureViewDescriptor);
return utils::MakeBindGroup(device, mBindGroupLayout, {{0, sampler}, {1, bcTextureView}});
}
// Create a render pipeline for sampling from a BC texture and rendering into the render target.
dawn::RenderPipeline CreateRenderPipelineForTest() {
ASSERT(IsBCFormatSupported());
dawn::PipelineLayout pipelineLayout =
utils::MakeBasicPipelineLayout(device, &mBindGroupLayout);
utils::ComboRenderPipelineDescriptor renderPipelineDescriptor(device);
dawn::ShaderModule vsModule =
utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"(
#version 450
layout(location=0) out vec2 texCoord;
void main() {
const vec2 pos[3] = vec2[3](
vec2(-3.0f, 1.0f),
vec2( 3.0f, 1.0f),
vec2( 0.0f, -2.0f)
);
gl_Position = vec4(pos[gl_VertexIndex], 0.0f, 1.0f);
texCoord = vec2(gl_Position.x / 2.0f, -gl_Position.y / 2.0f) + vec2(0.5f);
})");
dawn::ShaderModule fsModule =
utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"(
#version 450
layout(set = 0, binding = 0) uniform sampler sampler0;
layout(set = 0, binding = 1) uniform texture2D texture0;
layout(location = 0) in vec2 texCoord;
layout(location = 0) out vec4 fragColor;
void main() {
fragColor = texture(sampler2D(texture0, sampler0), texCoord);
})");
renderPipelineDescriptor.vertexStage.module = vsModule;
renderPipelineDescriptor.cFragmentStage.module = fsModule;
renderPipelineDescriptor.layout = pipelineLayout;
renderPipelineDescriptor.cColorStates[0].format =
utils::BasicRenderPass::kDefaultColorFormat;
return device.CreateRenderPipeline(&renderPipelineDescriptor);
}
// Run the given render pipeline and bind group and verify the pixels in the render target.
void VerifyCompressedTexturePixelValues(dawn::RenderPipeline renderPipeline,
dawn::BindGroup bindGroup,
const dawn::Extent3D& renderTargetSize,
const dawn::Origin3D& expectedOrigin,
const dawn::Extent3D& expectedExtent,
const std::vector<RGBA8>& expected) {
ASSERT(IsBCFormatSupported());
ASSERT(expected.size() == renderTargetSize.width * renderTargetSize.height);
utils::BasicRenderPass renderPass =
utils::CreateBasicRenderPass(device, renderTargetSize.width, renderTargetSize.height);
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
{
dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
pass.SetPipeline(renderPipeline);
pass.SetBindGroup(0, bindGroup);
pass.Draw(6, 1, 0, 0);
pass.EndPass();
}
dawn::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
EXPECT_TEXTURE_RGBA8_EQ(expected.data(), renderPass.color, expectedOrigin.x,
expectedOrigin.y, expectedExtent.width, expectedExtent.height, 0,
0);
}
// Run the tests that copies pre-prepared BC format data into a BC texture and verifies if we
// can render correctly with the pixel values sampled from the BC texture.
void TestCopyRegionIntoBCFormatTextures(const CopyConfig& config) {
ASSERT(IsBCFormatSupported());
dawn::Texture bcTexture = CreateTextureWithCompressedData(config);
dawn::BindGroup bindGroup =
CreateBindGroupForTest(bcTexture, config.textureDescriptor.format,
config.viewArrayLayer, config.viewMipmapLevel);
dawn::RenderPipeline renderPipeline = CreateRenderPipelineForTest();
dawn::Extent3D virtualSizeAtLevel = GetVirtualSizeAtLevel(config);
// The copy region may exceed the subresource size because of the required paddings for BC
// blocks, so we should limit the size of the expectedData to make it match the real size
// of the render target.
dawn::Extent3D noPaddingExtent3D = config.copyExtent3D;
if (config.copyOrigin3D.x + config.copyExtent3D.width > virtualSizeAtLevel.width) {
noPaddingExtent3D.width = virtualSizeAtLevel.width - config.copyOrigin3D.x;
}
if (config.copyOrigin3D.y + config.copyExtent3D.height > virtualSizeAtLevel.height) {
noPaddingExtent3D.height = virtualSizeAtLevel.height - config.copyOrigin3D.y;
}
std::vector<RGBA8> expectedData =
GetExpectedData(config.textureDescriptor.format, virtualSizeAtLevel);
VerifyCompressedTexturePixelValues(renderPipeline, bindGroup, virtualSizeAtLevel,
config.copyOrigin3D, noPaddingExtent3D, expectedData);
}
// Create a texture and initialize it with the pre-prepared compressed texture data.
dawn::Texture CreateTextureWithCompressedData(CopyConfig config) {
dawn::Texture bcTexture = device.CreateTexture(&config.textureDescriptor);
InitializeDataInCompressedTexture(bcTexture, config);
return bcTexture;
}
// Record a texture-to-texture copy command into command encoder without finishing the encoding.
void RecordTextureToTextureCopy(dawn::CommandEncoder encoder,
dawn::Texture srcTexture,
dawn::Texture dstTexture,
CopyConfig srcConfig,
CopyConfig dstConfig) {
dawn::TextureCopyView textureCopyViewSrc =
utils::CreateTextureCopyView(srcTexture, srcConfig.viewMipmapLevel,
srcConfig.viewArrayLayer, srcConfig.copyOrigin3D);
dawn::TextureCopyView textureCopyViewDst =
utils::CreateTextureCopyView(dstTexture, dstConfig.viewMipmapLevel,
dstConfig.viewArrayLayer, dstConfig.copyOrigin3D);
encoder.CopyTextureToTexture(&textureCopyViewSrc, &textureCopyViewDst,
&dstConfig.copyExtent3D);
}
dawn::Texture CreateTextureFromTexture(dawn::Texture srcTexture,
CopyConfig srcConfig,
CopyConfig dstConfig) {
dawn::Texture dstTexture = device.CreateTexture(&dstConfig.textureDescriptor);
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
RecordTextureToTextureCopy(encoder, srcTexture, dstTexture, srcConfig, dstConfig);
dawn::CommandBuffer copy = encoder.Finish();
queue.Submit(1, &copy);
return dstTexture;
}
// Return the BC block size in bytes.
static uint32_t CompressedFormatBlockSizeInBytes(dawn::TextureFormat format) {
switch (format) {
case dawn::TextureFormat::BC1RGBAUnorm:
case dawn::TextureFormat::BC1RGBAUnormSrgb:
case dawn::TextureFormat::BC4RSnorm:
case dawn::TextureFormat::BC4RUnorm:
return 8;
case dawn::TextureFormat::BC2RGBAUnorm:
case dawn::TextureFormat::BC2RGBAUnormSrgb:
case dawn::TextureFormat::BC3RGBAUnorm:
case dawn::TextureFormat::BC3RGBAUnormSrgb:
case dawn::TextureFormat::BC5RGSnorm:
case dawn::TextureFormat::BC5RGUnorm:
case dawn::TextureFormat::BC6HRGBSfloat:
case dawn::TextureFormat::BC6HRGBUfloat:
case dawn::TextureFormat::BC7RGBAUnorm:
case dawn::TextureFormat::BC7RGBAUnormSrgb:
return 16;
default:
UNREACHABLE();
return 0;
}
}
// Return the pre-prepared one-block BC texture data.
static std::vector<uint8_t> GetOneBlockBCFormatTextureData(dawn::TextureFormat bcFormat) {
switch (bcFormat) {
// The expected data represents 4x4 pixel images with the left side dark red and the
// right side dark green. We specify the same compressed data in both sRGB and non-sRGB
// tests, but the rendering result should be different because for sRGB formats, the
// red, green, and blue components are converted from an sRGB color space to a linear
// color space as part of filtering.
case dawn::TextureFormat::BC1RGBAUnorm:
case dawn::TextureFormat::BC1RGBAUnormSrgb:
return {0x0, 0xC0, 0x60, 0x6, 0x50, 0x50, 0x50, 0x50};
case dawn::TextureFormat::BC7RGBAUnorm:
case dawn::TextureFormat::BC7RGBAUnormSrgb:
return {0x50, 0x18, 0xfc, 0xf, 0x0, 0x30, 0xe3, 0xe1,
0xe1, 0xe1, 0xc1, 0xf, 0xfc, 0xc0, 0xf, 0xfc};
// The expected data represents 4x4 pixel images with the left side dark red and the
// right side dark green. The pixels in the left side of the block all have an alpha
// value equal to 0x88. We specify the same compressed data in both sRGB and non-sRGB
// tests, but the rendering result should be different because for sRGB formats, the
// red, green, and blue components are converted from an sRGB color space to a linear
// color space as part of filtering, and any alpha component is left unchanged.
case dawn::TextureFormat::BC2RGBAUnorm:
case dawn::TextureFormat::BC2RGBAUnormSrgb:
return {0x88, 0xFF, 0x88, 0xFF, 0x88, 0xFF, 0x88, 0xFF,
0x0, 0xC0, 0x60, 0x6, 0x50, 0x50, 0x50, 0x50};
case dawn::TextureFormat::BC3RGBAUnorm:
case dawn::TextureFormat::BC3RGBAUnormSrgb:
return {0x88, 0xFF, 0x40, 0x2, 0x24, 0x40, 0x2, 0x24,
0x0, 0xC0, 0x60, 0x6, 0x50, 0x50, 0x50, 0x50};
// The expected data represents 4x4 pixel images with the left side red and the
// right side black.
case dawn::TextureFormat::BC4RSnorm:
return {0x7F, 0x0, 0x40, 0x2, 0x24, 0x40, 0x2, 0x24};
case dawn::TextureFormat::BC4RUnorm:
return {0xFF, 0x0, 0x40, 0x2, 0x24, 0x40, 0x2, 0x24};
// The expected data represents 4x4 pixel images with the left side red and the right
// side green and was encoded with DirectXTex from Microsoft.
case dawn::TextureFormat::BC5RGSnorm:
return {0x7f, 0x81, 0x40, 0x2, 0x24, 0x40, 0x2, 0x24,
0x7f, 0x81, 0x9, 0x90, 0x0, 0x9, 0x90, 0x0};
case dawn::TextureFormat::BC5RGUnorm:
return {0xff, 0x0, 0x40, 0x2, 0x24, 0x40, 0x2, 0x24,
0xff, 0x0, 0x9, 0x90, 0x0, 0x9, 0x90, 0x0};
case dawn::TextureFormat::BC6HRGBSfloat:
return {0xe3, 0x1f, 0x0, 0x0, 0x0, 0xe0, 0x1f, 0x0,
0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff};
case dawn::TextureFormat::BC6HRGBUfloat:
return {0xe3, 0x3d, 0x0, 0x0, 0x0, 0xe0, 0x3d, 0x0,
0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff};
default:
UNREACHABLE();
return {};
}
}
// Return the texture data that is decoded from the result of GetOneBlockBCFormatTextureData in
// RGBA8 formats.
static std::vector<RGBA8> GetExpectedData(dawn::TextureFormat bcFormat,
const dawn::Extent3D& testRegion) {
constexpr RGBA8 kRed(255, 0, 0, 255);
constexpr RGBA8 kGreen(0, 255, 0, 255);
constexpr RGBA8 kBlack(0, 0, 0, 255);
constexpr RGBA8 kDarkRed(198, 0, 0, 255);
constexpr RGBA8 kDarkGreen(0, 207, 0, 255);
constexpr RGBA8 kDarkRedSRGB(144, 0, 0, 255);
constexpr RGBA8 kDarkGreenSRGB(0, 159, 0, 255);
constexpr uint8_t kLeftAlpha = 0x88;
constexpr uint8_t kRightAlpha = 0xFF;
switch (bcFormat) {
case dawn::TextureFormat::BC1RGBAUnorm:
case dawn::TextureFormat::BC7RGBAUnorm:
return FillExpectedData(testRegion, kDarkRed, kDarkGreen);
case dawn::TextureFormat::BC2RGBAUnorm:
case dawn::TextureFormat::BC3RGBAUnorm: {
constexpr RGBA8 kLeftColor = RGBA8(kDarkRed.r, 0, 0, kLeftAlpha);
constexpr RGBA8 kRightColor = RGBA8(0, kDarkGreen.g, 0, kRightAlpha);
return FillExpectedData(testRegion, kLeftColor, kRightColor);
}
case dawn::TextureFormat::BC1RGBAUnormSrgb:
case dawn::TextureFormat::BC7RGBAUnormSrgb:
return FillExpectedData(testRegion, kDarkRedSRGB, kDarkGreenSRGB);
case dawn::TextureFormat::BC2RGBAUnormSrgb:
case dawn::TextureFormat::BC3RGBAUnormSrgb: {
constexpr RGBA8 kLeftColor = RGBA8(kDarkRedSRGB.r, 0, 0, kLeftAlpha);
constexpr RGBA8 kRightColor = RGBA8(0, kDarkGreenSRGB.g, 0, kRightAlpha);
return FillExpectedData(testRegion, kLeftColor, kRightColor);
}
case dawn::TextureFormat::BC4RSnorm:
case dawn::TextureFormat::BC4RUnorm:
return FillExpectedData(testRegion, kRed, kBlack);
case dawn::TextureFormat::BC5RGSnorm:
case dawn::TextureFormat::BC5RGUnorm:
case dawn::TextureFormat::BC6HRGBSfloat:
case dawn::TextureFormat::BC6HRGBUfloat:
return FillExpectedData(testRegion, kRed, kGreen);
default:
UNREACHABLE();
return {};
}
}
static std::vector<RGBA8> FillExpectedData(const dawn::Extent3D& testRegion,
RGBA8 leftColorInBlock,
RGBA8 rightColorInBlock) {
ASSERT(testRegion.depth == 1);
std::vector<RGBA8> expectedData(testRegion.width * testRegion.height, leftColorInBlock);
for (uint32_t y = 0; y < testRegion.height; ++y) {
for (uint32_t x = 0; x < testRegion.width; ++x) {
if (x % kBCBlockWidthInTexels >= kBCBlockWidthInTexels / 2) {
expectedData[testRegion.width * y + x] = rightColorInBlock;
}
}
}
return expectedData;
}
static dawn::Extent3D GetVirtualSizeAtLevel(const CopyConfig& config) {
return {config.textureDescriptor.size.width >> config.viewMipmapLevel,
config.textureDescriptor.size.height >> config.viewMipmapLevel, 1};
}
static dawn::Extent3D GetPhysicalSizeAtLevel(const CopyConfig& config) {
dawn::Extent3D sizeAtLevel = GetVirtualSizeAtLevel(config);
sizeAtLevel.width = (sizeAtLevel.width + kBCBlockWidthInTexels - 1) /
kBCBlockWidthInTexels * kBCBlockWidthInTexels;
sizeAtLevel.height = (sizeAtLevel.height + kBCBlockHeightInTexels - 1) /
kBCBlockHeightInTexels * kBCBlockHeightInTexels;
return sizeAtLevel;
}
const std::array<dawn::TextureFormat, 14> kBCFormats = {
dawn::TextureFormat::BC1RGBAUnorm, dawn::TextureFormat::BC1RGBAUnormSrgb,
dawn::TextureFormat::BC2RGBAUnorm, dawn::TextureFormat::BC2RGBAUnormSrgb,
dawn::TextureFormat::BC3RGBAUnorm, dawn::TextureFormat::BC3RGBAUnormSrgb,
dawn::TextureFormat::BC4RSnorm, dawn::TextureFormat::BC4RUnorm,
dawn::TextureFormat::BC5RGSnorm, dawn::TextureFormat::BC5RGUnorm,
dawn::TextureFormat::BC6HRGBSfloat, dawn::TextureFormat::BC6HRGBUfloat,
dawn::TextureFormat::BC7RGBAUnorm, dawn::TextureFormat::BC7RGBAUnormSrgb};
// Tthe block width and height in texels are 4 for all BC formats.
static constexpr uint32_t kBCBlockWidthInTexels = 4;
static constexpr uint32_t kBCBlockHeightInTexels = 4;
static constexpr dawn::TextureUsage kDefaultBCFormatTextureUsage =
dawn::TextureUsage::Sampled | dawn::TextureUsage::CopyDst;
dawn::BindGroupLayout mBindGroupLayout;
bool mIsBCFormatSupported = false;
};
// Test copying into the whole BC texture with 2x2 blocks and sampling from it.
TEST_P(CompressedTextureBCFormatTest, Basic) {
// TODO(jiawei.shao@intel.com): find out why this test is flaky on Windows Intel Vulkan
// bots.
DAWN_SKIP_TEST_IF(IsIntel() && IsVulkan() && IsWindows());
// TODO(jiawei.shao@intel.com): find out why this test fails on Windows Intel OpenGL drivers.
DAWN_SKIP_TEST_IF(IsIntel() && IsOpenGL() && IsWindows());
DAWN_SKIP_TEST_IF(!IsBCFormatSupported());
CopyConfig config;
config.textureDescriptor.usage = kDefaultBCFormatTextureUsage;
config.textureDescriptor.size = {8, 8, 1};
config.copyExtent3D = config.textureDescriptor.size;
for (dawn::TextureFormat format : kBCFormats) {
config.textureDescriptor.format = format;
TestCopyRegionIntoBCFormatTextures(config);
}
}
// Test copying into a sub-region of a texture with BC formats works correctly.
TEST_P(CompressedTextureBCFormatTest, CopyIntoSubRegion) {
// TODO(jiawei.shao@intel.com): find out why this test is flaky on Windows Intel Vulkan
// bots.
DAWN_SKIP_TEST_IF(IsIntel() && IsVulkan() && IsWindows());
DAWN_SKIP_TEST_IF(!IsBCFormatSupported());
CopyConfig config;
config.textureDescriptor.usage = kDefaultBCFormatTextureUsage;
config.textureDescriptor.size = {8, 8, 1};
const dawn::Origin3D kOrigin = {4, 4, 0};
const dawn::Extent3D kExtent3D = {4, 4, 1};
config.copyOrigin3D = kOrigin;
config.copyExtent3D = kExtent3D;
for (dawn::TextureFormat format : kBCFormats) {
config.textureDescriptor.format = format;
TestCopyRegionIntoBCFormatTextures(config);
}
}
// Test using rowPitch == 0 in the copies with BC formats works correctly.
TEST_P(CompressedTextureBCFormatTest, CopyWithZeroRowPitch) {
// TODO(jiawei.shao@intel.com): find out why this test is flaky on Windows Intel Vulkan
// bots.
DAWN_SKIP_TEST_IF(IsIntel() && IsVulkan() && IsWindows());
// TODO(jiawei.shao@intel.com): find out why this test fails on Windows Intel OpenGL drivers.
DAWN_SKIP_TEST_IF(IsIntel() && IsOpenGL() && IsWindows());
DAWN_SKIP_TEST_IF(!IsBCFormatSupported());
CopyConfig config;
config.textureDescriptor.usage = kDefaultBCFormatTextureUsage;
config.textureDescriptor.size.height = 8;
config.textureDescriptor.size.depth = 1;
config.rowPitchAlignment = 0;
for (dawn::TextureFormat format : kBCFormats) {
config.textureDescriptor.format = format;
config.textureDescriptor.size.width = kTextureRowPitchAlignment /
CompressedFormatBlockSizeInBytes(format) *
kBCBlockWidthInTexels;
config.copyExtent3D = config.textureDescriptor.size;
TestCopyRegionIntoBCFormatTextures(config);
}
}
// Test copying into the non-zero layer of a 2D array texture with BC formats works correctly.
TEST_P(CompressedTextureBCFormatTest, CopyIntoNonZeroArrayLayer) {
// TODO(jiawei.shao@intel.com): find out why this test is flaky on Windows Intel Vulkan
// bots.
DAWN_SKIP_TEST_IF(IsIntel() && IsVulkan() && IsWindows());
// TODO(jiawei.shao@intel.com): find out why this test fails on Windows Intel OpenGL drivers.
DAWN_SKIP_TEST_IF(IsIntel() && IsOpenGL() && IsWindows());
DAWN_SKIP_TEST_IF(!IsBCFormatSupported());
CopyConfig config;
config.textureDescriptor.usage = kDefaultBCFormatTextureUsage;
config.textureDescriptor.size = {8, 8, 1};
config.copyExtent3D = config.textureDescriptor.size;
constexpr uint32_t kArrayLayerCount = 3;
config.textureDescriptor.arrayLayerCount = kArrayLayerCount;
config.viewArrayLayer = kArrayLayerCount - 1;
for (dawn::TextureFormat format : kBCFormats) {
config.textureDescriptor.format = format;
TestCopyRegionIntoBCFormatTextures(config);
}
}
// Test copying into a non-zero mipmap level of a texture with BC texture formats.
TEST_P(CompressedTextureBCFormatTest, CopyBufferIntoNonZeroMipmapLevel) {
// TODO(jiawei.shao@intel.com): find out why this test is flaky on Windows Intel Vulkan
// bots.
DAWN_SKIP_TEST_IF(IsIntel() && IsVulkan() && IsWindows());
// TODO(jiawei.shao@intel.com): find out why this test fails on Windows Intel OpenGL drivers.
DAWN_SKIP_TEST_IF(IsIntel() && IsOpenGL() && IsWindows());
DAWN_SKIP_TEST_IF(!IsBCFormatSupported());
CopyConfig config;
config.textureDescriptor.usage = kDefaultBCFormatTextureUsage;
config.textureDescriptor.size = {60, 60, 1};
constexpr uint32_t kMipmapLevelCount = 3;
config.textureDescriptor.mipLevelCount = kMipmapLevelCount;
config.viewMipmapLevel = kMipmapLevelCount - 1;
// The actual size of the texture at mipmap level == 2 is not a multiple of 4, paddings are
// required in the copies.
const dawn::Extent3D textureSizeLevel0 = config.textureDescriptor.size;
const uint32_t kActualWidthAtLevel = textureSizeLevel0.width >> config.viewMipmapLevel;
const uint32_t kActualHeightAtLevel = textureSizeLevel0.height >> config.viewMipmapLevel;
ASSERT(kActualWidthAtLevel % kBCBlockWidthInTexels != 0);
ASSERT(kActualHeightAtLevel % kBCBlockHeightInTexels != 0);
const uint32_t kCopyWidthAtLevel = (kActualWidthAtLevel + kBCBlockWidthInTexels - 1) /
kBCBlockWidthInTexels * kBCBlockWidthInTexels;
const uint32_t kCopyHeightAtLevel = (kActualHeightAtLevel + kBCBlockHeightInTexels - 1) /
kBCBlockHeightInTexels * kBCBlockHeightInTexels;
config.copyExtent3D = {kCopyWidthAtLevel, kCopyHeightAtLevel, 1};
for (dawn::TextureFormat format : kBCFormats) {
config.textureDescriptor.format = format;
TestCopyRegionIntoBCFormatTextures(config);
}
}
// Test texture-to-texture whole-size copies with BC formats.
TEST_P(CompressedTextureBCFormatTest, CopyWholeTextureSubResourceIntoNonZeroMipmapLevel) {
// TODO(jiawei.shao@intel.com): find out why this test is flaky on Windows Intel Vulkan
// bots.
DAWN_SKIP_TEST_IF(IsIntel() && IsVulkan() && IsWindows());
// TODO(jiawei.shao@intel.com): find out why this test fails on Windows Intel OpenGL drivers.
DAWN_SKIP_TEST_IF(IsIntel() && IsOpenGL() && IsWindows());
DAWN_SKIP_TEST_IF(!IsBCFormatSupported());
// TODO(cwallez@chromium.org): This consistently fails on with the 12th pixel being opaque black
// instead of opaque red on Win10 FYI Release (NVIDIA GeForce GTX 1660). See
// https://bugs.chromium.org/p/chromium/issues/detail?id=981393
DAWN_SKIP_TEST_IF(IsWindows() && IsVulkan() && IsNvidia());
CopyConfig config;
config.textureDescriptor.size = {60, 60, 1};
constexpr uint32_t kMipmapLevelCount = 3;
config.textureDescriptor.mipLevelCount = kMipmapLevelCount;
config.viewMipmapLevel = kMipmapLevelCount - 1;
// The actual size of the texture at mipmap level == 2 is not a multiple of 4, paddings are
// required in the copies.
const dawn::Extent3D kVirtualSize = GetVirtualSizeAtLevel(config);
const dawn::Extent3D kPhysicalSize = GetPhysicalSizeAtLevel(config);
ASSERT_NE(0u, kVirtualSize.width % kBCBlockWidthInTexels);
ASSERT_NE(0u, kVirtualSize.height % kBCBlockHeightInTexels);
config.copyExtent3D = kPhysicalSize;
for (dawn::TextureFormat format : kBCFormats) {
// Create bcTextureSrc as the source texture and initialize it with pre-prepared BC
// compressed data.
config.textureDescriptor.format = format;
// Add the usage bit for both source and destination textures so that we don't need to
// create two copy configs.
config.textureDescriptor.usage =
dawn::TextureUsage::CopySrc | dawn::TextureUsage::CopyDst | dawn::TextureUsage::Sampled;
dawn::Texture bcTextureSrc = CreateTextureWithCompressedData(config);
// Create bcTexture and copy from the content in bcTextureSrc into it.
dawn::Texture bcTextureDst = CreateTextureFromTexture(bcTextureSrc, config, config);
// Verify if we can use bcTexture as sampled textures correctly.
dawn::BindGroup bindGroup = CreateBindGroupForTest(
bcTextureDst, format, config.viewArrayLayer, config.viewMipmapLevel);
dawn::RenderPipeline renderPipeline = CreateRenderPipelineForTest();
std::vector<RGBA8> expectedData = GetExpectedData(format, kVirtualSize);
VerifyCompressedTexturePixelValues(renderPipeline, bindGroup, kVirtualSize,
config.copyOrigin3D, kVirtualSize, expectedData);
}
}
// Test BC format texture-to-texture partial copies where the physical size of the destination
// subresource is different from its virtual size.
TEST_P(CompressedTextureBCFormatTest, CopyIntoSubresourceWithPhysicalSizeNotEqualToVirtualSize) {
DAWN_SKIP_TEST_IF(!IsBCFormatSupported());
// TODO(jiawei.shao@intel.com): add workaround on the T2T copies where Extent3D fits in one
// subresource and does not fit in another one on OpenGL.
DAWN_SKIP_TEST_IF(IsOpenGL());
// TODO(jiawei.shao@intel.com): find out why this test is flaky on Windows Intel Vulkan
// bots.
DAWN_SKIP_TEST_IF(IsIntel() && IsVulkan() && IsWindows());
CopyConfig srcConfig;
srcConfig.textureDescriptor.size = {60, 60, 1};
srcConfig.viewMipmapLevel = srcConfig.textureDescriptor.mipLevelCount - 1;
const dawn::Extent3D kSrcVirtualSize = GetVirtualSizeAtLevel(srcConfig);
CopyConfig dstConfig;
dstConfig.textureDescriptor.size = {60, 60, 1};
constexpr uint32_t kMipmapLevelCount = 3;
dstConfig.textureDescriptor.mipLevelCount = kMipmapLevelCount;
dstConfig.viewMipmapLevel = kMipmapLevelCount - 1;
// The actual size of the texture at mipmap level == 2 is not a multiple of 4, paddings are
// required in the copies.
const dawn::Extent3D kDstVirtualSize = GetVirtualSizeAtLevel(dstConfig);
ASSERT_NE(0u, kDstVirtualSize.width % kBCBlockWidthInTexels);
ASSERT_NE(0u, kDstVirtualSize.height % kBCBlockHeightInTexels);
const dawn::Extent3D kDstPhysicalSize = GetPhysicalSizeAtLevel(dstConfig);
srcConfig.copyExtent3D = dstConfig.copyExtent3D = kDstPhysicalSize;
ASSERT_LT(srcConfig.copyOrigin3D.x + srcConfig.copyExtent3D.width, kSrcVirtualSize.width);
ASSERT_LT(srcConfig.copyOrigin3D.y + srcConfig.copyExtent3D.height, kSrcVirtualSize.height);
for (dawn::TextureFormat format : kBCFormats) {
// Create bcTextureSrc as the source texture and initialize it with pre-prepared BC
// compressed data.
srcConfig.textureDescriptor.format = format;
srcConfig.textureDescriptor.usage =
dawn::TextureUsage::CopySrc | dawn::TextureUsage::CopyDst;
dawn::Texture bcTextureSrc = CreateTextureWithCompressedData(srcConfig);
dawn::TextureCopyView textureCopyViewSrc =
utils::CreateTextureCopyView(bcTextureSrc, srcConfig.viewMipmapLevel,
srcConfig.viewArrayLayer, srcConfig.copyOrigin3D);
// Create bcTexture and copy from the content in bcTextureSrc into it.
dstConfig.textureDescriptor.format = format;
dstConfig.textureDescriptor.usage = kDefaultBCFormatTextureUsage;
dawn::Texture bcTextureDst = CreateTextureFromTexture(bcTextureSrc, srcConfig, dstConfig);
// Verify if we can use bcTexture as sampled textures correctly.
dawn::BindGroup bindGroup = CreateBindGroupForTest(
bcTextureDst, format, dstConfig.viewArrayLayer, dstConfig.viewMipmapLevel);
dawn::RenderPipeline renderPipeline = CreateRenderPipelineForTest();
std::vector<RGBA8> expectedData = GetExpectedData(format, kDstVirtualSize);
VerifyCompressedTexturePixelValues(renderPipeline, bindGroup, kDstVirtualSize,
dstConfig.copyOrigin3D, kDstVirtualSize, expectedData);
}
}
// Test BC format texture-to-texture partial copies where the physical size of the source
// subresource is different from its virtual size.
TEST_P(CompressedTextureBCFormatTest, CopyFromSubresourceWithPhysicalSizeNotEqualToVirtualSize) {
DAWN_SKIP_TEST_IF(!IsBCFormatSupported());
// TODO(jiawei.shao@intel.com): add workaround on the T2T copies where Extent3D fits in one
// subresource and does not fit in another one on OpenGL.
DAWN_SKIP_TEST_IF(IsOpenGL());
// TODO(jiawei.shao@intel.com): find out why this test is flaky on Windows Intel Vulkan
// bots.
DAWN_SKIP_TEST_IF(IsIntel() && IsVulkan() && IsWindows());
CopyConfig srcConfig;
srcConfig.textureDescriptor.size = {60, 60, 1};
constexpr uint32_t kMipmapLevelCount = 3;
srcConfig.textureDescriptor.mipLevelCount = kMipmapLevelCount;
srcConfig.viewMipmapLevel = srcConfig.textureDescriptor.mipLevelCount - 1;
// The actual size of the texture at mipmap level == 2 is not a multiple of 4, paddings are
// required in the copies.
const dawn::Extent3D kSrcVirtualSize = GetVirtualSizeAtLevel(srcConfig);
ASSERT_NE(0u, kSrcVirtualSize.width % kBCBlockWidthInTexels);
ASSERT_NE(0u, kSrcVirtualSize.height % kBCBlockHeightInTexels);
CopyConfig dstConfig;
dstConfig.textureDescriptor.size = {16, 16, 1};
dstConfig.viewMipmapLevel = dstConfig.textureDescriptor.mipLevelCount - 1;
const dawn::Extent3D kDstVirtualSize = GetVirtualSizeAtLevel(dstConfig);
srcConfig.copyExtent3D = dstConfig.copyExtent3D = kDstVirtualSize;
ASSERT_GT(srcConfig.copyOrigin3D.x + srcConfig.copyExtent3D.width, kSrcVirtualSize.width);
ASSERT_GT(srcConfig.copyOrigin3D.y + srcConfig.copyExtent3D.height, kSrcVirtualSize.height);
for (dawn::TextureFormat format : kBCFormats) {
srcConfig.textureDescriptor.format = dstConfig.textureDescriptor.format = format;
srcConfig.textureDescriptor.usage =
dawn::TextureUsage::CopySrc | dawn::TextureUsage::CopyDst;
dstConfig.textureDescriptor.usage = kDefaultBCFormatTextureUsage;
// Create bcTextureSrc as the source texture and initialize it with pre-prepared BC
// compressed data.
dawn::Texture bcTextureSrc = CreateTextureWithCompressedData(srcConfig);
// Create bcTexture and copy from the content in bcTextureSrc into it.
dawn::Texture bcTextureDst = CreateTextureFromTexture(bcTextureSrc, srcConfig, dstConfig);
// Verify if we can use bcTexture as sampled textures correctly.
dawn::BindGroup bindGroup = CreateBindGroupForTest(
bcTextureDst, format, dstConfig.viewArrayLayer, dstConfig.viewMipmapLevel);
dawn::RenderPipeline renderPipeline = CreateRenderPipelineForTest();
std::vector<RGBA8> expectedData = GetExpectedData(format, kDstVirtualSize);
VerifyCompressedTexturePixelValues(renderPipeline, bindGroup, kDstVirtualSize,
dstConfig.copyOrigin3D, kDstVirtualSize, expectedData);
}
}
// Test recording two BC format texture-to-texture partial copies where the physical size of the
// source subresource is different from its virtual size into one command buffer.
TEST_P(CompressedTextureBCFormatTest, MultipleCopiesWithPhysicalSizeNotEqualToVirtualSize) {
DAWN_SKIP_TEST_IF(!IsBCFormatSupported());
// TODO(jiawei.shao@intel.com): add workaround on the T2T copies where Extent3D fits in one
// subresource and does not fit in another one on OpenGL.
DAWN_SKIP_TEST_IF(IsOpenGL());
// TODO(jiawei.shao@intel.com): find out why this test is flaky on Windows Intel Vulkan
// bots.
DAWN_SKIP_TEST_IF(IsIntel() && IsVulkan() && IsWindows());
constexpr uint32_t kTotalCopyCount = 2;
std::array<CopyConfig, kTotalCopyCount> srcConfigs;
std::array<CopyConfig, kTotalCopyCount> dstConfigs;
constexpr uint32_t kSrcMipmapLevelCount0 = 3;
srcConfigs[0].textureDescriptor.size = {60, 60, 1};
srcConfigs[0].textureDescriptor.mipLevelCount = kSrcMipmapLevelCount0;
srcConfigs[0].viewMipmapLevel = srcConfigs[0].textureDescriptor.mipLevelCount - 1;
dstConfigs[0].textureDescriptor.size = {16, 16, 1};
dstConfigs[0].viewMipmapLevel = dstConfigs[0].textureDescriptor.mipLevelCount - 1;
srcConfigs[0].copyExtent3D = dstConfigs[0].copyExtent3D = GetVirtualSizeAtLevel(dstConfigs[0]);
const dawn::Extent3D kSrcVirtualSize0 = GetVirtualSizeAtLevel(srcConfigs[0]);
ASSERT_NE(0u, kSrcVirtualSize0.width % kBCBlockWidthInTexels);
ASSERT_NE(0u, kSrcVirtualSize0.height % kBCBlockHeightInTexels);
constexpr uint32_t kDstMipmapLevelCount1 = 4;
srcConfigs[1].textureDescriptor.size = {8, 8, 1};
srcConfigs[1].viewMipmapLevel = srcConfigs[1].textureDescriptor.mipLevelCount - 1;
dstConfigs[1].textureDescriptor.size = {56, 56, 1};
dstConfigs[1].textureDescriptor.mipLevelCount = kDstMipmapLevelCount1;
dstConfigs[1].viewMipmapLevel = dstConfigs[1].textureDescriptor.mipLevelCount - 1;
srcConfigs[1].copyExtent3D = dstConfigs[1].copyExtent3D = GetVirtualSizeAtLevel(srcConfigs[1]);
std::array<dawn::Extent3D, kTotalCopyCount> dstVirtualSizes;
for (uint32_t i = 0; i < kTotalCopyCount; ++i) {
dstVirtualSizes[i] = GetVirtualSizeAtLevel(dstConfigs[i]);
}
ASSERT_NE(0u, dstVirtualSizes[1].width % kBCBlockWidthInTexels);
ASSERT_NE(0u, dstVirtualSizes[1].height % kBCBlockHeightInTexels);
for (dawn::TextureFormat format : kBCFormats) {
std::array<dawn::Texture, kTotalCopyCount> bcSrcTextures;
std::array<dawn::Texture, kTotalCopyCount> bcDstTextures;
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
for (uint32_t i = 0; i < kTotalCopyCount; ++i) {
srcConfigs[i].textureDescriptor.format = dstConfigs[i].textureDescriptor.format =
format;
srcConfigs[i].textureDescriptor.usage =
dawn::TextureUsage::CopySrc | dawn::TextureUsage::CopyDst;
dstConfigs[i].textureDescriptor.usage = kDefaultBCFormatTextureUsage;
// Create bcSrcTextures as the source textures and initialize them with pre-prepared BC
// compressed data.
bcSrcTextures[i] = CreateTextureWithCompressedData(srcConfigs[i]);
bcDstTextures[i] = device.CreateTexture(&dstConfigs[i].textureDescriptor);
RecordTextureToTextureCopy(encoder, bcSrcTextures[i], bcDstTextures[i], srcConfigs[i],
dstConfigs[i]);
}
dawn::CommandBuffer commandBuffer = encoder.Finish();
queue.Submit(1, &commandBuffer);
dawn::RenderPipeline renderPipeline = CreateRenderPipelineForTest();
for (uint32_t i = 0; i < kTotalCopyCount; ++i) {
// Verify if we can use bcDstTextures as sampled textures correctly.
dawn::BindGroup bindGroup0 =
CreateBindGroupForTest(bcDstTextures[i], format, dstConfigs[i].viewArrayLayer,
dstConfigs[i].viewMipmapLevel);
std::vector<RGBA8> expectedData = GetExpectedData(format, dstVirtualSizes[i]);
VerifyCompressedTexturePixelValues(renderPipeline, bindGroup0, dstVirtualSizes[i],
dstConfigs[i].copyOrigin3D, dstVirtualSizes[i],
expectedData);
}
}
}
// Test the special case of the B2T copies on the D3D12 backend that the buffer offset and texture
// extent exactly fit the RowPitch.
TEST_P(CompressedTextureBCFormatTest, BufferOffsetAndExtentFitRowPitch) {
// TODO(jiawei.shao@intel.com): find out why this test is flaky on Windows Intel Vulkan
// bots.
DAWN_SKIP_TEST_IF(IsIntel() && IsVulkan() && IsWindows());
// TODO(jiawei.shao@intel.com): find out why this test fails on Windows Intel OpenGL drivers.
DAWN_SKIP_TEST_IF(IsIntel() && IsOpenGL() && IsWindows());
DAWN_SKIP_TEST_IF(!IsBCFormatSupported());
CopyConfig config;
config.textureDescriptor.usage = kDefaultBCFormatTextureUsage;
config.textureDescriptor.size = {8, 8, 1};
config.copyExtent3D = config.textureDescriptor.size;
const uint32_t blockCountPerRow = config.textureDescriptor.size.width / kBCBlockWidthInTexels;
for (dawn::TextureFormat format : kBCFormats) {
config.textureDescriptor.format = format;
const uint32_t blockSizeInBytes = CompressedFormatBlockSizeInBytes(format);
const uint32_t blockCountPerRowPitch = config.rowPitchAlignment / blockSizeInBytes;
config.bufferOffset = (blockCountPerRowPitch - blockCountPerRow) * blockSizeInBytes;
TestCopyRegionIntoBCFormatTextures(config);
}
}
// Test the special case of the B2T copies on the D3D12 backend that the buffer offset exceeds the
// slice pitch (slicePitch = rowPitch * (imageHeightInTexels / blockHeightInTexels)). On D3D12
// backend the texelOffset.y will be greater than 0 after calcuting the texelOffset in the function
// ComputeTexelOffsets().
TEST_P(CompressedTextureBCFormatTest, BufferOffsetExceedsSlicePitch) {
// TODO(jiawei.shao@intel.com): find out why this test is flaky on Windows Intel Vulkan
// bots.
DAWN_SKIP_TEST_IF(IsIntel() && IsVulkan() && IsWindows());
// TODO(jiawei.shao@intel.com): find out why this test fails on Windows Intel OpenGL drivers.
DAWN_SKIP_TEST_IF(IsIntel() && IsOpenGL() && IsWindows());
DAWN_SKIP_TEST_IF(!IsBCFormatSupported());
CopyConfig config;
config.textureDescriptor.usage = kDefaultBCFormatTextureUsage;
config.textureDescriptor.size = {8, 8, 1};
config.copyExtent3D = config.textureDescriptor.size;
const dawn::Extent3D textureSizeLevel0 = config.textureDescriptor.size;
const uint32_t blockCountPerRow = textureSizeLevel0.width / kBCBlockWidthInTexels;
const uint32_t slicePitchInBytes =
config.rowPitchAlignment * (textureSizeLevel0.height / kBCBlockHeightInTexels);
for (dawn::TextureFormat format : kBCFormats) {
config.textureDescriptor.format = format;
const uint32_t blockSizeInBytes = CompressedFormatBlockSizeInBytes(format);
const uint32_t blockCountPerRowPitch = config.rowPitchAlignment / blockSizeInBytes;
config.bufferOffset = (blockCountPerRowPitch - blockCountPerRow) * blockSizeInBytes +
config.rowPitchAlignment + slicePitchInBytes;
TestCopyRegionIntoBCFormatTextures(config);
}
}
// Test the special case of the B2T copies on the D3D12 backend that the buffer offset and texture
// extent exceed the RowPitch. On D3D12 backend two copies are required for this case.
TEST_P(CompressedTextureBCFormatTest, CopyWithBufferOffsetAndExtentExceedRowPitch) {
// TODO(jiawei.shao@intel.com): find out why this test is flaky on Windows Intel Vulkan
// bots.
DAWN_SKIP_TEST_IF(IsIntel() && IsVulkan() && IsWindows());
// TODO(jiawei.shao@intel.com): find out why this test fails on Windows Intel OpenGL drivers.
DAWN_SKIP_TEST_IF(IsIntel() && IsOpenGL() && IsWindows());
DAWN_SKIP_TEST_IF(!IsBCFormatSupported());
CopyConfig config;
config.textureDescriptor.usage = kDefaultBCFormatTextureUsage;
config.textureDescriptor.size = {8, 8, 1};
config.copyExtent3D = config.textureDescriptor.size;
const uint32_t blockCountPerRow = config.textureDescriptor.size.width / kBCBlockWidthInTexels;
constexpr uint32_t kExceedRowBlockCount = 1;
for (dawn::TextureFormat format : kBCFormats) {
config.textureDescriptor.format = format;
const uint32_t blockSizeInBytes = CompressedFormatBlockSizeInBytes(format);
const uint32_t blockCountPerRowPitch = config.rowPitchAlignment / blockSizeInBytes;
config.bufferOffset =
(blockCountPerRowPitch - blockCountPerRow + kExceedRowBlockCount) * blockSizeInBytes;
TestCopyRegionIntoBCFormatTextures(config);
}
}
// Test the special case of the B2T copies on the D3D12 backend that the slicePitch is equal to the
// rowPitch. On D3D12 backend the texelOffset.z will be greater than 0 after calcuting the
// texelOffset in the function ComputeTexelOffsets().
TEST_P(CompressedTextureBCFormatTest, RowPitchEqualToSlicePitch) {
// TODO(jiawei.shao@intel.com): find out why this test is flaky on Windows Intel Vulkan
// bots.
DAWN_SKIP_TEST_IF(IsIntel() && IsVulkan() && IsWindows());
DAWN_SKIP_TEST_IF(!IsBCFormatSupported());
CopyConfig config;
config.textureDescriptor.usage = kDefaultBCFormatTextureUsage;
config.textureDescriptor.size = {8, kBCBlockHeightInTexels, 1};
config.copyExtent3D = config.textureDescriptor.size;
const uint32_t blockCountPerRow = config.textureDescriptor.size.width / kBCBlockWidthInTexels;
const uint32_t slicePitchInBytes = config.rowPitchAlignment;
for (dawn::TextureFormat format : kBCFormats) {
config.textureDescriptor.format = format;
const uint32_t blockSizeInBytes = CompressedFormatBlockSizeInBytes(format);
const uint32_t blockCountPerRowPitch = config.rowPitchAlignment / blockSizeInBytes;
config.bufferOffset =
(blockCountPerRowPitch - blockCountPerRow) * blockSizeInBytes + slicePitchInBytes;
TestCopyRegionIntoBCFormatTextures(config);
}
}
// Test the workaround in the B2T copies when (bufferSize - bufferOffset < bytesPerImage *
// copyExtent.depth) on Metal backends. As copyExtent.depth can only be 1 for BC formats, on Metal
// backend we will use two copies to implement such copy.
TEST_P(CompressedTextureBCFormatTest, LargeImageHeight) {
// TODO(jiawei.shao@intel.com): find out why this test is flaky on Windows Intel Vulkan
// bots.
DAWN_SKIP_TEST_IF(IsIntel() && IsVulkan() && IsWindows());
// TODO(jiawei.shao@intel.com): find out why this test fails on Windows Intel OpenGL drivers.
DAWN_SKIP_TEST_IF(IsIntel() && IsOpenGL() && IsWindows());
DAWN_SKIP_TEST_IF(!IsBCFormatSupported());
CopyConfig config;
config.textureDescriptor.usage = kDefaultBCFormatTextureUsage;
config.textureDescriptor.size = {8, 8, 1};
config.copyExtent3D = config.textureDescriptor.size;
config.imageHeight = config.textureDescriptor.size.height * 2;
for (dawn::TextureFormat format : kBCFormats) {
config.textureDescriptor.format = format;
TestCopyRegionIntoBCFormatTextures(config);
}
}
// Test the workaround in the B2T copies when (bufferSize - bufferOffset < bytesPerImage *
// copyExtent.depth) and copyExtent needs to be clamped.
TEST_P(CompressedTextureBCFormatTest, LargeImageHeightAndClampedCopyExtent) {
// TODO(jiawei.shao@intel.com): find out why this test is flaky on Windows Intel Vulkan
// bots.
DAWN_SKIP_TEST_IF(IsIntel() && IsVulkan() && IsWindows());
// TODO(jiawei.shao@intel.com): find out why this test fails on Windows Intel OpenGL drivers.
DAWN_SKIP_TEST_IF(IsIntel() && IsOpenGL() && IsWindows());
DAWN_SKIP_TEST_IF(!IsBCFormatSupported());
CopyConfig config;
config.textureDescriptor.usage = kDefaultBCFormatTextureUsage;
config.textureDescriptor.size = {56, 56, 1};
constexpr uint32_t kMipmapLevelCount = 3;
config.textureDescriptor.mipLevelCount = kMipmapLevelCount;
config.viewMipmapLevel = kMipmapLevelCount - 1;
// The actual size of the texture at mipmap level == 2 is not a multiple of 4, paddings are
// required in the copies.
const dawn::Extent3D textureSizeLevel0 = config.textureDescriptor.size;
const uint32_t kActualWidthAtLevel = textureSizeLevel0.width >> config.viewMipmapLevel;
const uint32_t kActualHeightAtLevel = textureSizeLevel0.height >> config.viewMipmapLevel;
ASSERT(kActualWidthAtLevel % kBCBlockWidthInTexels != 0);
ASSERT(kActualHeightAtLevel % kBCBlockHeightInTexels != 0);
const uint32_t kCopyWidthAtLevel = (kActualWidthAtLevel + kBCBlockWidthInTexels - 1) /
kBCBlockWidthInTexels * kBCBlockWidthInTexels;
const uint32_t kCopyHeightAtLevel = (kActualHeightAtLevel + kBCBlockHeightInTexels - 1) /
kBCBlockHeightInTexels * kBCBlockHeightInTexels;
config.copyExtent3D = {kCopyWidthAtLevel, kCopyHeightAtLevel, 1};
config.imageHeight = kCopyHeightAtLevel * 2;
for (dawn::TextureFormat format : kBCFormats) {
config.textureDescriptor.format = format;
TestCopyRegionIntoBCFormatTextures(config);
}
}
// TODO(jiawei.shao@intel.com): support BC formats on OpenGL backend
DAWN_INSTANTIATE_TEST(CompressedTextureBCFormatTest,
D3D12Backend,
MetalBackend,
OpenGLBackend,
VulkanBackend,
ForceWorkarounds(VulkanBackend,
{"use_temporary_buffer_in_texture_to_texture_copy"}));