Add most WebGPU texture formats on Vulkan
This adds the formats to dawn.json, implements support in the Vulkan backend and adds tests performing basic sampling checks for all formats. The R8UnormSrgb and RG8UnormSrgb formats skipped because they are not required in Vulkan (and RG8UnormSrgb is in fact not supported on the machine used for developing this CL). A PR will be sent to the WebGPU repo to remove the from the initial list of formats. The RG11B10Float and RGB10A2Unorm formats of WebGPU are replaced with B10GR11Float and A2RGB10Unorm that are the formats exposed by Vulkan. It is likely that all APIs implement them with components stored in that order. Each format except depth-stencil ones is tested by uploading some interesting texel data and checking that sampling from the texture produces correct results. The goal is to make sure that backends don't make a mistake in the giant switch statements. There was no effort made to check the hardware implementation of the formats. Tests will later be extended to cover rendering and clearing operations as well as multisample resolve. It isn't clear if depth-stencil format will support TRANSFER operations in WebGPU so these are left untested for now. BUG=dawn:128 Change-Id: I78ac5bf77b57398155551e6db3de50b478d69452 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/8363 Reviewed-by: Austin Eng <enga@chromium.org> Reviewed-by: Jiawei Shao <jiawei.shao@intel.com> Commit-Queue: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
parent
b6096db4ab
commit
431d618961
1
BUILD.gn
1
BUILD.gn
|
@ -679,6 +679,7 @@ test("dawn_end2end_tests") {
|
|||
"src/tests/end2end/RenderPassTests.cpp",
|
||||
"src/tests/end2end/SamplerTests.cpp",
|
||||
"src/tests/end2end/ScissorTests.cpp",
|
||||
"src/tests/end2end/TextureFormatTests.cpp",
|
||||
"src/tests/end2end/TextureViewTests.cpp",
|
||||
"src/tests/end2end/TextureZeroInitTests.cpp",
|
||||
"src/tests/end2end/VertexFormatTests.cpp",
|
||||
|
|
87
dawn.json
87
dawn.json
|
@ -1034,28 +1034,71 @@
|
|||
"texture format": {
|
||||
"category": "enum",
|
||||
"values": [
|
||||
{"value": 0, "name": "RGBA8 unorm"},
|
||||
{"value": 1, "name": "RG8 unorm"},
|
||||
{"value": 2, "name": "R8 unorm"},
|
||||
{"value": 3, "name": "RGBA8 uint"},
|
||||
{"value": 4, "name": "RG8 uint"},
|
||||
{"value": 5, "name": "R8 uint"},
|
||||
{"value": 6, "name": "BGRA8 unorm"},
|
||||
{"value": 7, "name": "depth24 plus stencil8"},
|
||||
{"value": 8, "name": "BC1 RGBA unorm"},
|
||||
{"value": 9, "name": "BC1 RGBA unorm srgb"},
|
||||
{"value": 10, "name": "BC2 RGBA unorm"},
|
||||
{"value": 11, "name": "BC2 RGBA unorm srgb"},
|
||||
{"value": 12, "name": "BC3 RGBA unorm"},
|
||||
{"value": 13, "name": "BC3 RGBA unorm srgb"},
|
||||
{"value": 14, "name": "BC4 R unorm"},
|
||||
{"value": 15, "name": "BC4 R snorm"},
|
||||
{"value": 16, "name": "BC5 RG unorm"},
|
||||
{"value": 17, "name": "BC5 RG snorm"},
|
||||
{"value": 18, "name": "BC6H RGB ufloat"},
|
||||
{"value": 19, "name": "BC6H RGB sfloat"},
|
||||
{"value": 20, "name": "BC7 RGBA unorm"},
|
||||
{"value": 21, "name": "BC7 RGBA unorm srgb"}
|
||||
{"value": 0, "name": "R8 unorm"},
|
||||
{"value": 1, "name": "R8 snorm"},
|
||||
{"value": 2, "name": "R8 uint"},
|
||||
{"value": 3, "name": "R8 sint"},
|
||||
|
||||
{"value": 4, "name": "R16 unorm"},
|
||||
{"value": 5, "name": "R16 snorm"},
|
||||
{"value": 6, "name": "R16 uint"},
|
||||
{"value": 7, "name": "R16 sint"},
|
||||
{"value": 8, "name": "R16 float"},
|
||||
{"value": 9, "name": "RG8 unorm"},
|
||||
{"value": 10, "name": "RG8 snorm"},
|
||||
{"value": 11, "name": "RG8 uint"},
|
||||
{"value": 12, "name": "RG8 sint"},
|
||||
{"value": 13, "name": "B5 G6 R5 unorm"},
|
||||
|
||||
{"value": 14, "name": "R32 float"},
|
||||
{"value": 15, "name": "R32 uint"},
|
||||
{"value": 16, "name": "R32 sint"},
|
||||
{"value": 17, "name": "RG16 unorm"},
|
||||
{"value": 18, "name": "RG16 snorm"},
|
||||
{"value": 19, "name": "RG16 uint"},
|
||||
{"value": 20, "name": "RG16 sint"},
|
||||
{"value": 21, "name": "RG16 float"},
|
||||
{"value": 22, "name": "RGBA8 unorm"},
|
||||
{"value": 23, "name": "RGBA8 unorm srgb"},
|
||||
{"value": 24, "name": "RGBA8 snorm"},
|
||||
{"value": 25, "name": "RGBA8 uint"},
|
||||
{"value": 26, "name": "RGBA8 sint"},
|
||||
{"value": 27, "name": "BGRA8 unorm"},
|
||||
{"value": 28, "name": "BGRA8 unorm srgb"},
|
||||
{"value": 29, "name": "A2 RGB10 unorm"},
|
||||
{"value": 30, "name": "B10 GR11 float"},
|
||||
|
||||
{"value": 31, "name": "RG32 float"},
|
||||
{"value": 32, "name": "RG32 uint"},
|
||||
{"value": 33, "name": "RG32 sint"},
|
||||
{"value": 34, "name": "RGBA16 unorm"},
|
||||
{"value": 35, "name": "RGBA16 snorm"},
|
||||
{"value": 36, "name": "RGBA16 uint"},
|
||||
{"value": 37, "name": "RGBA16 sint"},
|
||||
{"value": 38, "name": "RGBA16 float"},
|
||||
|
||||
{"value": 39, "name": "RGBA32 float"},
|
||||
{"value": 40, "name": "RGBA32 uint"},
|
||||
{"value": 41, "name": "RGBA32 sint"},
|
||||
|
||||
{"value": 42, "name": "depth32 float"},
|
||||
{"value": 43, "name": "depth24 plus"},
|
||||
{"value": 44, "name": "depth24 plus stencil8"},
|
||||
|
||||
{"value": 45, "name": "BC1 RGBA unorm"},
|
||||
{"value": 46, "name": "BC1 RGBA unorm srgb"},
|
||||
{"value": 47, "name": "BC2 RGBA unorm"},
|
||||
{"value": 48, "name": "BC2 RGBA unorm srgb"},
|
||||
{"value": 49, "name": "BC3 RGBA unorm"},
|
||||
{"value": 50, "name": "BC3 RGBA unorm srgb"},
|
||||
{"value": 51, "name": "BC4 R unorm"},
|
||||
{"value": 52, "name": "BC4 R snorm"},
|
||||
{"value": 53, "name": "BC5 RG unorm"},
|
||||
{"value": 54, "name": "BC5 RG snorm"},
|
||||
{"value": 55, "name": "BC6H RGB ufloat"},
|
||||
{"value": 56, "name": "BC6H RGB sfloat"},
|
||||
{"value": 57, "name": "BC7 RGBA unorm"},
|
||||
{"value": 58, "name": "BC7 RGBA unorm srgb"}
|
||||
],
|
||||
"TODO": [
|
||||
"jiawei.shao@intel.com: support BC formats as extension"
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "common/Assert.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
#if defined(DAWN_COMPILER_MSVC)
|
||||
# include <intrin.h>
|
||||
|
@ -107,3 +108,19 @@ uint16_t Float32ToFloat16(float fp32) {
|
|||
13);
|
||||
}
|
||||
}
|
||||
|
||||
// Based on the Khronos Data Format Specification 1.2 Section 13.3 sRGB transfer functions
|
||||
float SRGBToLinear(float srgb) {
|
||||
// sRGB is always used in unsigned normalized formats so clamp to [0.0, 1.0]
|
||||
if (srgb <= 0.0f) {
|
||||
return 0.0f;
|
||||
} else if (srgb > 1.0f) {
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
if (srgb < 0.04045f) {
|
||||
return srgb / 12.92f;
|
||||
} else {
|
||||
return std::pow((srgb + 0.055f) / 1.055f, 2.4f);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,4 +52,6 @@ destType BitCast(const sourceType& source) {
|
|||
|
||||
uint16_t Float32ToFloat16(float fp32);
|
||||
|
||||
float SRGBToLinear(float srgb);
|
||||
|
||||
#endif // COMMON_MATH_H_
|
||||
|
|
|
@ -129,19 +129,65 @@ namespace dawn_native {
|
|||
|
||||
switch (format) {
|
||||
case dawn::TextureFormat::R8Unorm:
|
||||
case dawn::TextureFormat::R8Snorm:
|
||||
case dawn::TextureFormat::R8Uint:
|
||||
case dawn::TextureFormat::R8Sint:
|
||||
return MakeColorFormat(format, true, 1);
|
||||
|
||||
case dawn::TextureFormat::R16Unorm:
|
||||
case dawn::TextureFormat::R16Snorm:
|
||||
case dawn::TextureFormat::R16Uint:
|
||||
case dawn::TextureFormat::R16Sint:
|
||||
case dawn::TextureFormat::R16Float:
|
||||
case dawn::TextureFormat::RG8Unorm:
|
||||
case dawn::TextureFormat::RG8Snorm:
|
||||
case dawn::TextureFormat::RG8Uint:
|
||||
case dawn::TextureFormat::RG8Sint:
|
||||
case dawn::TextureFormat::B5G6R5Unorm:
|
||||
return MakeColorFormat(format, true, 2);
|
||||
|
||||
case dawn::TextureFormat::R32Uint:
|
||||
case dawn::TextureFormat::R32Sint:
|
||||
case dawn::TextureFormat::R32Float:
|
||||
case dawn::TextureFormat::RG16Unorm:
|
||||
case dawn::TextureFormat::RG16Snorm:
|
||||
case dawn::TextureFormat::RG16Uint:
|
||||
case dawn::TextureFormat::RG16Sint:
|
||||
case dawn::TextureFormat::RG16Float:
|
||||
case dawn::TextureFormat::RGBA8Unorm:
|
||||
case dawn::TextureFormat::RGBA8UnormSrgb:
|
||||
case dawn::TextureFormat::RGBA8Snorm:
|
||||
case dawn::TextureFormat::RGBA8Uint:
|
||||
case dawn::TextureFormat::RGBA8Sint:
|
||||
case dawn::TextureFormat::BGRA8Unorm:
|
||||
case dawn::TextureFormat::BGRA8UnormSrgb:
|
||||
case dawn::TextureFormat::A2RGB10Unorm:
|
||||
case dawn::TextureFormat::B10GR11Float:
|
||||
return MakeColorFormat(format, true, 4);
|
||||
|
||||
case dawn::TextureFormat::RG32Uint:
|
||||
case dawn::TextureFormat::RG32Sint:
|
||||
case dawn::TextureFormat::RG32Float:
|
||||
case dawn::TextureFormat::RGBA16Unorm:
|
||||
case dawn::TextureFormat::RGBA16Snorm:
|
||||
case dawn::TextureFormat::RGBA16Uint:
|
||||
case dawn::TextureFormat::RGBA16Sint:
|
||||
case dawn::TextureFormat::RGBA16Float:
|
||||
return MakeColorFormat(format, true, 8);
|
||||
|
||||
case dawn::TextureFormat::RGBA32Uint:
|
||||
case dawn::TextureFormat::RGBA32Sint:
|
||||
case dawn::TextureFormat::RGBA32Float:
|
||||
return MakeColorFormat(format, true, 16);
|
||||
|
||||
case dawn::TextureFormat::Depth32Float:
|
||||
case dawn::TextureFormat::Depth24Plus:
|
||||
return MakeDepthStencilFormat(format, Format::Aspect::Depth, 4);
|
||||
case dawn::TextureFormat::Depth24PlusStencil8:
|
||||
// TODO(cwallez@chromium.org): It isn't clear if this format should be copyable
|
||||
// because its size isn't well defined, is it 4, 5 or 8?
|
||||
return MakeDepthStencilFormat(format, Format::Aspect::DepthStencil, 4);
|
||||
|
||||
case dawn::TextureFormat::BC1RGBAUnorm:
|
||||
case dawn::TextureFormat::BC1RGBAUnormSrgb:
|
||||
case dawn::TextureFormat::BC4RSnorm:
|
||||
|
|
|
@ -211,22 +211,131 @@ namespace dawn_native { namespace vulkan {
|
|||
// Converts Dawn texture format to Vulkan formats.
|
||||
VkFormat VulkanImageFormat(dawn::TextureFormat format) {
|
||||
switch (format) {
|
||||
case dawn::TextureFormat::RGBA8Unorm:
|
||||
return VK_FORMAT_R8G8B8A8_UNORM;
|
||||
case dawn::TextureFormat::RG8Unorm:
|
||||
return VK_FORMAT_R8G8_UNORM;
|
||||
case dawn::TextureFormat::R8Unorm:
|
||||
return VK_FORMAT_R8_UNORM;
|
||||
case dawn::TextureFormat::RGBA8Uint:
|
||||
return VK_FORMAT_R8G8B8A8_UINT;
|
||||
case dawn::TextureFormat::RG8Uint:
|
||||
return VK_FORMAT_R8G8_UINT;
|
||||
case dawn::TextureFormat::R8Snorm:
|
||||
return VK_FORMAT_R8_SNORM;
|
||||
case dawn::TextureFormat::R8Uint:
|
||||
return VK_FORMAT_R8_UINT;
|
||||
case dawn::TextureFormat::R8Sint:
|
||||
return VK_FORMAT_R8_SINT;
|
||||
|
||||
case dawn::TextureFormat::R16Unorm:
|
||||
return VK_FORMAT_R16_UNORM;
|
||||
case dawn::TextureFormat::R16Snorm:
|
||||
return VK_FORMAT_R16_SNORM;
|
||||
case dawn::TextureFormat::R16Uint:
|
||||
return VK_FORMAT_R16_UINT;
|
||||
case dawn::TextureFormat::R16Sint:
|
||||
return VK_FORMAT_R16_SINT;
|
||||
case dawn::TextureFormat::R16Float:
|
||||
return VK_FORMAT_R16_SFLOAT;
|
||||
case dawn::TextureFormat::RG8Unorm:
|
||||
return VK_FORMAT_R8G8_UNORM;
|
||||
case dawn::TextureFormat::RG8Snorm:
|
||||
return VK_FORMAT_R8G8_SNORM;
|
||||
case dawn::TextureFormat::RG8Uint:
|
||||
return VK_FORMAT_R8G8_UINT;
|
||||
case dawn::TextureFormat::RG8Sint:
|
||||
return VK_FORMAT_R8G8_SINT;
|
||||
case dawn::TextureFormat::B5G6R5Unorm:
|
||||
return VK_FORMAT_B5G6R5_UNORM_PACK16;
|
||||
|
||||
case dawn::TextureFormat::R32Uint:
|
||||
return VK_FORMAT_R32_UINT;
|
||||
case dawn::TextureFormat::R32Sint:
|
||||
return VK_FORMAT_R32_SINT;
|
||||
case dawn::TextureFormat::R32Float:
|
||||
return VK_FORMAT_R32_SFLOAT;
|
||||
case dawn::TextureFormat::RG16Unorm:
|
||||
return VK_FORMAT_R16G16_UNORM;
|
||||
case dawn::TextureFormat::RG16Snorm:
|
||||
return VK_FORMAT_R16G16_SNORM;
|
||||
case dawn::TextureFormat::RG16Uint:
|
||||
return VK_FORMAT_R16G16_UINT;
|
||||
case dawn::TextureFormat::RG16Sint:
|
||||
return VK_FORMAT_R16G16_SINT;
|
||||
case dawn::TextureFormat::RG16Float:
|
||||
return VK_FORMAT_R16G16_SFLOAT;
|
||||
case dawn::TextureFormat::RGBA8Unorm:
|
||||
return VK_FORMAT_R8G8B8A8_UNORM;
|
||||
case dawn::TextureFormat::RGBA8UnormSrgb:
|
||||
return VK_FORMAT_R8G8B8A8_SRGB;
|
||||
case dawn::TextureFormat::RGBA8Snorm:
|
||||
return VK_FORMAT_R8G8B8A8_SNORM;
|
||||
case dawn::TextureFormat::RGBA8Uint:
|
||||
return VK_FORMAT_R8G8B8A8_UINT;
|
||||
case dawn::TextureFormat::RGBA8Sint:
|
||||
return VK_FORMAT_R8G8B8A8_SINT;
|
||||
case dawn::TextureFormat::BGRA8Unorm:
|
||||
return VK_FORMAT_B8G8R8A8_UNORM;
|
||||
case dawn::TextureFormat::BGRA8UnormSrgb:
|
||||
return VK_FORMAT_B8G8R8A8_SRGB;
|
||||
case dawn::TextureFormat::A2RGB10Unorm:
|
||||
return VK_FORMAT_A2R10G10B10_UNORM_PACK32;
|
||||
case dawn::TextureFormat::B10GR11Float:
|
||||
return VK_FORMAT_B10G11R11_UFLOAT_PACK32;
|
||||
|
||||
case dawn::TextureFormat::RG32Uint:
|
||||
return VK_FORMAT_R32G32_UINT;
|
||||
case dawn::TextureFormat::RG32Sint:
|
||||
return VK_FORMAT_R32G32_SINT;
|
||||
case dawn::TextureFormat::RG32Float:
|
||||
return VK_FORMAT_R32G32_SFLOAT;
|
||||
case dawn::TextureFormat::RGBA16Unorm:
|
||||
return VK_FORMAT_R16G16B16A16_UNORM;
|
||||
case dawn::TextureFormat::RGBA16Snorm:
|
||||
return VK_FORMAT_R16G16B16A16_SNORM;
|
||||
case dawn::TextureFormat::RGBA16Uint:
|
||||
return VK_FORMAT_R16G16B16A16_UINT;
|
||||
case dawn::TextureFormat::RGBA16Sint:
|
||||
return VK_FORMAT_R16G16B16A16_SINT;
|
||||
case dawn::TextureFormat::RGBA16Float:
|
||||
return VK_FORMAT_R16G16B16A16_SFLOAT;
|
||||
|
||||
case dawn::TextureFormat::RGBA32Uint:
|
||||
return VK_FORMAT_R32G32B32A32_UINT;
|
||||
case dawn::TextureFormat::RGBA32Sint:
|
||||
return VK_FORMAT_R32G32B32A32_SINT;
|
||||
case dawn::TextureFormat::RGBA32Float:
|
||||
return VK_FORMAT_R32G32B32A32_SFLOAT;
|
||||
|
||||
case dawn::TextureFormat::Depth32Float:
|
||||
return VK_FORMAT_D32_SFLOAT;
|
||||
case dawn::TextureFormat::Depth24Plus:
|
||||
return VK_FORMAT_D32_SFLOAT;
|
||||
case dawn::TextureFormat::Depth24PlusStencil8:
|
||||
return VK_FORMAT_D32_SFLOAT_S8_UINT;
|
||||
|
||||
case dawn::TextureFormat::BC1RGBAUnorm:
|
||||
return VK_FORMAT_BC1_RGBA_UNORM_BLOCK;
|
||||
case dawn::TextureFormat::BC1RGBAUnormSrgb:
|
||||
return VK_FORMAT_BC1_RGBA_SRGB_BLOCK;
|
||||
case dawn::TextureFormat::BC2RGBAUnorm:
|
||||
return VK_FORMAT_BC2_UNORM_BLOCK;
|
||||
case dawn::TextureFormat::BC2RGBAUnormSrgb:
|
||||
return VK_FORMAT_BC2_SRGB_BLOCK;
|
||||
case dawn::TextureFormat::BC3RGBAUnorm:
|
||||
return VK_FORMAT_BC3_UNORM_BLOCK;
|
||||
case dawn::TextureFormat::BC3RGBAUnormSrgb:
|
||||
return VK_FORMAT_BC3_SRGB_BLOCK;
|
||||
case dawn::TextureFormat::BC4RSnorm:
|
||||
return VK_FORMAT_BC4_SNORM_BLOCK;
|
||||
case dawn::TextureFormat::BC4RUnorm:
|
||||
return VK_FORMAT_BC4_UNORM_BLOCK;
|
||||
case dawn::TextureFormat::BC5RGSnorm:
|
||||
return VK_FORMAT_BC5_SNORM_BLOCK;
|
||||
case dawn::TextureFormat::BC5RGUnorm:
|
||||
return VK_FORMAT_BC5_UNORM_BLOCK;
|
||||
case dawn::TextureFormat::BC6HRGBSfloat:
|
||||
return VK_FORMAT_BC6H_SFLOAT_BLOCK;
|
||||
case dawn::TextureFormat::BC6HRGBUfloat:
|
||||
return VK_FORMAT_BC6H_UFLOAT_BLOCK;
|
||||
case dawn::TextureFormat::BC7RGBAUnorm:
|
||||
return VK_FORMAT_BC7_UNORM_BLOCK;
|
||||
case dawn::TextureFormat::BC7RGBAUnormSrgb:
|
||||
return VK_FORMAT_BC7_SRGB_BLOCK;
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
|
|
@ -688,7 +688,6 @@ namespace detail {
|
|||
|
||||
const T* actual = static_cast<const T*>(data);
|
||||
|
||||
testing::AssertionResult failure = testing::AssertionFailure();
|
||||
for (size_t i = 0; i < mExpected.size(); ++i) {
|
||||
if (actual[i] != mExpected[i]) {
|
||||
testing::AssertionResult result = testing::AssertionFailure()
|
||||
|
|
|
@ -0,0 +1,719 @@
|
|||
// 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/Math.h"
|
||||
#include "utils/ComboRenderPipelineDescriptor.h"
|
||||
#include "utils/DawnHelpers.h"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
// An expectation for float buffer content that can correctly compare different NaN values and
|
||||
// supports a basic tolerance for comparison of finite values.
|
||||
class ExpectFloatWithTolerance : public detail::Expectation {
|
||||
public:
|
||||
ExpectFloatWithTolerance(std::vector<float> expected, float tolerance)
|
||||
: mExpected(std::move(expected)), mTolerance(tolerance) {
|
||||
}
|
||||
|
||||
testing::AssertionResult Check(const void* data, size_t size) override {
|
||||
ASSERT(size == sizeof(float) * mExpected.size());
|
||||
|
||||
const float* actual = static_cast<const float*>(data);
|
||||
|
||||
for (size_t i = 0; i < mExpected.size(); ++i) {
|
||||
float expectedValue = mExpected[i];
|
||||
float actualValue = actual[i];
|
||||
|
||||
if (!FloatsMatch(expectedValue, actualValue)) {
|
||||
testing::AssertionResult result = testing::AssertionFailure()
|
||||
<< "Expected data[" << i << "] to be close to "
|
||||
<< expectedValue << ", actual " << actualValue
|
||||
<< std::endl;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return testing::AssertionSuccess();
|
||||
}
|
||||
|
||||
private:
|
||||
bool FloatsMatch(float expected, float actual) {
|
||||
if (std::isnan(expected)) {
|
||||
return std::isnan(actual);
|
||||
}
|
||||
|
||||
if (std::isinf(expected)) {
|
||||
return std::isinf(actual) && std::signbit(expected) == std::signbit(actual);
|
||||
}
|
||||
|
||||
if (mTolerance == 0.0f) {
|
||||
return expected == actual;
|
||||
}
|
||||
|
||||
float error = std::abs(expected - actual);
|
||||
return error < mTolerance;
|
||||
}
|
||||
|
||||
std::vector<float> mExpected;
|
||||
float mTolerance;
|
||||
};
|
||||
|
||||
class TextureFormatTest : public DawnTest {
|
||||
protected:
|
||||
void SetUp() {
|
||||
DawnTest::SetUp();
|
||||
|
||||
mSampleBGL = utils::MakeBindGroupLayout(
|
||||
device, {{0, dawn::ShaderStageBit::Fragment, dawn::BindingType::Sampler},
|
||||
{1, dawn::ShaderStageBit::Fragment, dawn::BindingType::SampledTexture}});
|
||||
}
|
||||
|
||||
// Describes what the "decompressed" data type for a texture format is. For example normalized
|
||||
// formats are stored as integers but interpreted to produce floating point values.
|
||||
enum ComponentType {
|
||||
Uint,
|
||||
Sint,
|
||||
Float,
|
||||
};
|
||||
|
||||
// Structure containing all the information that tests need to know about the format.
|
||||
struct FormatTestInfo {
|
||||
dawn::TextureFormat format;
|
||||
uint32_t texelByteSize;
|
||||
ComponentType type;
|
||||
uint32_t componentCount;
|
||||
};
|
||||
|
||||
// Returns a texture format that can be used to contain the interpreted value of the format in
|
||||
// formatInfo.
|
||||
dawn::TextureFormat GetComponentFormat(FormatTestInfo formatInfo) {
|
||||
std::array<dawn::TextureFormat, 4> floatFormats = {
|
||||
dawn::TextureFormat::R32Float,
|
||||
dawn::TextureFormat::RG32Float,
|
||||
dawn::TextureFormat::RGBA32Float,
|
||||
dawn::TextureFormat::RGBA32Float,
|
||||
};
|
||||
std::array<dawn::TextureFormat, 4> sintFormats = {
|
||||
dawn::TextureFormat::R32Sint,
|
||||
dawn::TextureFormat::RG32Sint,
|
||||
dawn::TextureFormat::RGBA32Sint,
|
||||
dawn::TextureFormat::RGBA32Sint,
|
||||
};
|
||||
std::array<dawn::TextureFormat, 4> uintFormats = {
|
||||
dawn::TextureFormat::R32Uint,
|
||||
dawn::TextureFormat::RG32Uint,
|
||||
dawn::TextureFormat::RGBA32Uint,
|
||||
dawn::TextureFormat::RGBA32Uint,
|
||||
};
|
||||
|
||||
ASSERT(formatInfo.componentCount > 0 && formatInfo.componentCount <= 4);
|
||||
switch (formatInfo.type) {
|
||||
case Float:
|
||||
return floatFormats[formatInfo.componentCount - 1];
|
||||
case Sint:
|
||||
return sintFormats[formatInfo.componentCount - 1];
|
||||
case Uint:
|
||||
return uintFormats[formatInfo.componentCount - 1];
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return dawn::TextureFormat::R32Float;
|
||||
}
|
||||
}
|
||||
|
||||
// Return a pipeline that can be used in a full-texture draw to sample from the texture in the
|
||||
// bindgroup and output its decompressed values to the render target.
|
||||
dawn::RenderPipeline CreateSamplePipeline(FormatTestInfo formatInfo) {
|
||||
utils::ComboRenderPipelineDescriptor desc(device);
|
||||
|
||||
dawn::ShaderModule vsModule =
|
||||
utils::CreateShaderModule(device, dawn::ShaderStage::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 = gl_Position.xy / 2.0f + vec2(0.5f);
|
||||
})");
|
||||
|
||||
// Compute the prefix needed for GLSL types that handle our texture's data.
|
||||
const char* prefix = nullptr;
|
||||
switch (formatInfo.type) {
|
||||
case Float:
|
||||
prefix = "";
|
||||
break;
|
||||
case Sint:
|
||||
prefix = "i";
|
||||
break;
|
||||
case Uint:
|
||||
prefix = "u";
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
|
||||
std::ostringstream fsSource;
|
||||
fsSource << "#version 450\n";
|
||||
fsSource << "layout(set=0, binding=0) uniform sampler mySampler;\n";
|
||||
fsSource << "layout(set=0, binding=1) uniform " << prefix << "texture2D myTexture;\n";
|
||||
|
||||
fsSource << "layout(location=0) in vec2 texCoord;\n";
|
||||
fsSource << "layout(location=0) out " << prefix << "vec4 fragColor;\n";
|
||||
|
||||
fsSource << "void main() {\n";
|
||||
fsSource << " fragColor = texture(" << prefix
|
||||
<< "sampler2D(myTexture, mySampler), texCoord);\n";
|
||||
fsSource << "}";
|
||||
|
||||
dawn::ShaderModule fsModule =
|
||||
utils::CreateShaderModule(device, dawn::ShaderStage::Fragment, fsSource.str().c_str());
|
||||
|
||||
desc.cVertexStage.module = vsModule;
|
||||
desc.cFragmentStage.module = fsModule;
|
||||
desc.layout = utils::MakeBasicPipelineLayout(device, &mSampleBGL);
|
||||
desc.cColorStates[0]->format = GetComponentFormat(formatInfo);
|
||||
|
||||
return device.CreateRenderPipeline(&desc);
|
||||
}
|
||||
|
||||
// The sampling test uploads the textureData in a texture with the formatInfo.format format and
|
||||
// the samples from it, then checks that the sampled values correspond to expectedRenderData.
|
||||
void DoSampleTest(FormatTestInfo formatInfo,
|
||||
const void* textureData,
|
||||
size_t textureDataSize,
|
||||
const void* expectedRenderData,
|
||||
size_t expectedRenderDataSize,
|
||||
float floatTolerance) {
|
||||
// The input data should contain an exact number of texels
|
||||
ASSERT(textureDataSize % formatInfo.texelByteSize == 0);
|
||||
uint32_t width = textureDataSize / formatInfo.texelByteSize;
|
||||
|
||||
// The input data must be a multiple of 4 byte in length for setSubData
|
||||
ASSERT(textureDataSize % 4 == 0);
|
||||
|
||||
// Create the texture we will sample from
|
||||
dawn::TextureDescriptor textureDesc;
|
||||
textureDesc.usage = dawn::TextureUsageBit::TransferDst | dawn::TextureUsageBit::Sampled;
|
||||
textureDesc.dimension = dawn::TextureDimension::e2D;
|
||||
textureDesc.size = {width, 1, 1};
|
||||
textureDesc.arrayLayerCount = 1;
|
||||
textureDesc.format = formatInfo.format;
|
||||
textureDesc.mipLevelCount = 1;
|
||||
textureDesc.sampleCount = 1;
|
||||
|
||||
dawn::Texture texture = device.CreateTexture(&textureDesc);
|
||||
|
||||
dawn::Buffer uploadBuffer = utils::CreateBufferFromData(
|
||||
device, textureData, textureDataSize, dawn::BufferUsageBit::TransferSrc);
|
||||
|
||||
// Create the texture that we will render results to
|
||||
dawn::TextureDescriptor renderTargetDesc;
|
||||
renderTargetDesc.usage =
|
||||
dawn::TextureUsageBit::TransferSrc | dawn::TextureUsageBit::OutputAttachment;
|
||||
renderTargetDesc.dimension = dawn::TextureDimension::e2D;
|
||||
renderTargetDesc.size = {width, 1, 1};
|
||||
renderTargetDesc.arrayLayerCount = 1;
|
||||
renderTargetDesc.format = GetComponentFormat(formatInfo);
|
||||
renderTargetDesc.mipLevelCount = 1;
|
||||
renderTargetDesc.sampleCount = 1;
|
||||
|
||||
dawn::Texture renderTarget = device.CreateTexture(&renderTargetDesc);
|
||||
|
||||
// Create the readback buffer for the data in renderTarget
|
||||
dawn::BufferDescriptor readbackBufferDesc;
|
||||
readbackBufferDesc.usage =
|
||||
dawn::BufferUsageBit::TransferDst | dawn::BufferUsageBit::TransferSrc;
|
||||
readbackBufferDesc.size = 4 * width * formatInfo.componentCount;
|
||||
dawn::Buffer readbackBuffer = device.CreateBuffer(&readbackBufferDesc);
|
||||
|
||||
// Prepare objects needed to sample from texture in the renderpass
|
||||
dawn::RenderPipeline pipeline = CreateSamplePipeline(formatInfo);
|
||||
dawn::SamplerDescriptor samplerDesc = utils::GetDefaultSamplerDescriptor();
|
||||
dawn::Sampler sampler = device.CreateSampler(&samplerDesc);
|
||||
dawn::BindGroup bindGroup = utils::MakeBindGroup(
|
||||
device, mSampleBGL, {{0, sampler}, {1, texture.CreateDefaultView()}});
|
||||
|
||||
// Encode commands for the test that fill texture, sample it to render to renderTarget then
|
||||
// copy renderTarget in a buffer so we can read it easily.
|
||||
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
|
||||
{
|
||||
dawn::BufferCopyView bufferView = utils::CreateBufferCopyView(uploadBuffer, 0, 256, 0);
|
||||
dawn::TextureCopyView textureView =
|
||||
utils::CreateTextureCopyView(texture, 0, 0, {0, 0, 0});
|
||||
dawn::Extent3D extent{width, 1, 1};
|
||||
encoder.CopyBufferToTexture(&bufferView, &textureView, &extent);
|
||||
}
|
||||
|
||||
utils::ComboRenderPassDescriptor renderPassDesc({renderTarget.CreateDefaultView()});
|
||||
dawn::RenderPassEncoder renderPass = encoder.BeginRenderPass(&renderPassDesc);
|
||||
renderPass.SetPipeline(pipeline);
|
||||
renderPass.SetBindGroup(0, bindGroup, 0, nullptr);
|
||||
renderPass.Draw(3, 1, 0, 0);
|
||||
renderPass.EndPass();
|
||||
|
||||
{
|
||||
dawn::BufferCopyView bufferView =
|
||||
utils::CreateBufferCopyView(readbackBuffer, 0, 256, 0);
|
||||
dawn::TextureCopyView textureView =
|
||||
utils::CreateTextureCopyView(renderTarget, 0, 0, {0, 0, 0});
|
||||
dawn::Extent3D extent{width, 1, 1};
|
||||
encoder.CopyTextureToBuffer(&textureView, &bufferView, &extent);
|
||||
}
|
||||
|
||||
dawn::CommandBuffer commands = encoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
// For floats use a special expectation that understands how to compare NaNs and support a
|
||||
// tolerance.
|
||||
if (formatInfo.type == Float) {
|
||||
const float* expectedFloats = static_cast<const float*>(expectedRenderData);
|
||||
std::vector<float> expectedVector(
|
||||
expectedFloats, expectedFloats + expectedRenderDataSize / sizeof(float));
|
||||
AddBufferExpectation(__FILE__, __LINE__, readbackBuffer, 0, expectedRenderDataSize,
|
||||
new ExpectFloatWithTolerance(expectedVector, floatTolerance));
|
||||
} else {
|
||||
EXPECT_BUFFER_U32_RANGE_EQ(static_cast<const uint32_t*>(expectedRenderData),
|
||||
readbackBuffer, 0,
|
||||
expectedRenderDataSize / sizeof(uint32_t));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TextureData, typename RenderData>
|
||||
void DoSampleTest(FormatTestInfo formatInfo,
|
||||
const std::vector<TextureData>& textureData,
|
||||
const std::vector<RenderData>& expectedRenderData,
|
||||
float floatTolerance = 0.0f) {
|
||||
DoSampleTest(formatInfo, textureData.data(), textureData.size() * sizeof(TextureData),
|
||||
expectedRenderData.data(), expectedRenderData.size() * sizeof(RenderData),
|
||||
floatTolerance);
|
||||
}
|
||||
|
||||
// Below are helper functions for types that are very similar to one another so the logic is
|
||||
// shared.
|
||||
|
||||
template <typename T>
|
||||
void DoUnormTest(FormatTestInfo formatInfo) {
|
||||
static_assert(!std::is_signed<T>::value && std::is_integral<T>::value, "");
|
||||
ASSERT(sizeof(T) * formatInfo.componentCount == formatInfo.texelByteSize);
|
||||
ASSERT(formatInfo.type == Float);
|
||||
|
||||
T maxValue = std::numeric_limits<T>::max();
|
||||
std::vector<T> textureData = {0, 1, maxValue, maxValue};
|
||||
std::vector<float> expectedData = {0.0f, 1.0f / maxValue, 1.0f, 1.0f};
|
||||
|
||||
DoSampleTest(formatInfo, textureData, expectedData);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void DoSnormTest(FormatTestInfo formatInfo) {
|
||||
static_assert(std::is_signed<T>::value && std::is_integral<T>::value, "");
|
||||
ASSERT(sizeof(T) * formatInfo.componentCount == formatInfo.texelByteSize);
|
||||
ASSERT(formatInfo.type == Float);
|
||||
|
||||
T maxValue = std::numeric_limits<T>::max();
|
||||
T minValue = std::numeric_limits<T>::min();
|
||||
std::vector<T> textureData = {0, 1, maxValue, minValue};
|
||||
std::vector<float> expectedData = {0.0f, 1.0f / maxValue, 1.0f, -1.0f};
|
||||
|
||||
DoSampleTest(formatInfo, textureData, expectedData, 0.0001f / maxValue);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void DoUintTest(FormatTestInfo formatInfo) {
|
||||
static_assert(!std::is_signed<T>::value && std::is_integral<T>::value, "");
|
||||
ASSERT(sizeof(T) * formatInfo.componentCount == formatInfo.texelByteSize);
|
||||
ASSERT(formatInfo.type == Uint);
|
||||
|
||||
T maxValue = std::numeric_limits<T>::max();
|
||||
std::vector<T> textureData = {0, 1, maxValue, maxValue};
|
||||
std::vector<uint32_t> expectedData = {0, 1, maxValue, maxValue};
|
||||
|
||||
DoSampleTest(formatInfo, textureData, expectedData);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void DoSintTest(FormatTestInfo formatInfo) {
|
||||
static_assert(std::is_signed<T>::value && std::is_integral<T>::value, "");
|
||||
ASSERT(sizeof(T) * formatInfo.componentCount == formatInfo.texelByteSize);
|
||||
ASSERT(formatInfo.type == Sint);
|
||||
|
||||
T maxValue = std::numeric_limits<T>::max();
|
||||
T minValue = std::numeric_limits<T>::min();
|
||||
std::vector<T> textureData = {0, 1, maxValue, minValue};
|
||||
std::vector<int32_t> expectedData = {0, 1, maxValue, minValue};
|
||||
|
||||
DoSampleTest(formatInfo, textureData, expectedData);
|
||||
}
|
||||
|
||||
void DoFloat32Test(FormatTestInfo formatInfo) {
|
||||
ASSERT(sizeof(float) * formatInfo.componentCount == formatInfo.texelByteSize);
|
||||
ASSERT(formatInfo.type == Float);
|
||||
|
||||
std::vector<float> textureData = {+0.0f, -0.0f, 1.0f, 1.0e-29,
|
||||
1.0e29, NAN, INFINITY, -INFINITY};
|
||||
|
||||
DoSampleTest(formatInfo, textureData, textureData);
|
||||
}
|
||||
|
||||
void DoFloat16Test(FormatTestInfo formatInfo) {
|
||||
ASSERT(sizeof(int16_t) * formatInfo.componentCount == formatInfo.texelByteSize);
|
||||
ASSERT(formatInfo.type == Float);
|
||||
|
||||
std::vector<float> expectedData = {+0.0f, -0.0f, 1.0f, 1.0e-4,
|
||||
1.0e4, NAN, INFINITY, -INFINITY};
|
||||
std::vector<uint16_t> textureData;
|
||||
for (float value : expectedData) {
|
||||
textureData.push_back(Float32ToFloat16(value));
|
||||
}
|
||||
|
||||
DoSampleTest(formatInfo, textureData, expectedData, 1.0e-5);
|
||||
}
|
||||
|
||||
private:
|
||||
dawn::BindGroupLayout mSampleBGL;
|
||||
};
|
||||
|
||||
// Test the R8Unorm format
|
||||
TEST_P(TextureFormatTest, R8Unorm) {
|
||||
DoUnormTest<uint8_t>({dawn::TextureFormat::R8Unorm, 1, Float, 1});
|
||||
}
|
||||
|
||||
// Test the RG8Unorm format
|
||||
TEST_P(TextureFormatTest, RG8Unorm) {
|
||||
DoUnormTest<uint8_t>({dawn::TextureFormat::RG8Unorm, 2, Float, 2});
|
||||
}
|
||||
|
||||
// Test the RGBA8Unorm format
|
||||
TEST_P(TextureFormatTest, RGBA8Unorm) {
|
||||
DoUnormTest<uint8_t>({dawn::TextureFormat::RGBA8Unorm, 4, Float, 4});
|
||||
}
|
||||
|
||||
// Test the R16Unorm format
|
||||
TEST_P(TextureFormatTest, R16Unorm) {
|
||||
DoUnormTest<uint16_t>({dawn::TextureFormat::R16Unorm, 2, Float, 1});
|
||||
}
|
||||
|
||||
// Test the RG16Unorm format
|
||||
TEST_P(TextureFormatTest, RG16Unorm) {
|
||||
DoUnormTest<uint16_t>({dawn::TextureFormat::RG16Unorm, 4, Float, 2});
|
||||
}
|
||||
|
||||
// Test the RGBA16Unorm format
|
||||
TEST_P(TextureFormatTest, RGBA16Unorm) {
|
||||
DoUnormTest<uint16_t>({dawn::TextureFormat::RGBA16Unorm, 8, Float, 4});
|
||||
}
|
||||
|
||||
// Test the BGRA8Unorm format
|
||||
TEST_P(TextureFormatTest, BGRA8Unorm) {
|
||||
uint8_t maxValue = std::numeric_limits<uint8_t>::max();
|
||||
std::vector<uint8_t> textureData = {maxValue, 1, 0, maxValue};
|
||||
std::vector<float> expectedData = {0.0f, 1.0f / maxValue, 1.0f, 1.0f};
|
||||
DoSampleTest({dawn::TextureFormat::BGRA8Unorm, 4, Float, 4}, textureData, expectedData);
|
||||
}
|
||||
|
||||
// Test the R8Snorm format
|
||||
TEST_P(TextureFormatTest, R8Snorm) {
|
||||
DoSnormTest<int8_t>({dawn::TextureFormat::R8Snorm, 1, Float, 1});
|
||||
}
|
||||
|
||||
// Test the RG8Snorm format
|
||||
TEST_P(TextureFormatTest, RG8Snorm) {
|
||||
DoSnormTest<int8_t>({dawn::TextureFormat::RG8Snorm, 2, Float, 2});
|
||||
}
|
||||
|
||||
// Test the RGBA8Snorm format
|
||||
TEST_P(TextureFormatTest, RGBA8Snorm) {
|
||||
DoSnormTest<int8_t>({dawn::TextureFormat::RGBA8Snorm, 4, Float, 4});
|
||||
}
|
||||
|
||||
// Test the R16Snorm format
|
||||
TEST_P(TextureFormatTest, R16Snorm) {
|
||||
DoSnormTest<int16_t>({dawn::TextureFormat::R16Snorm, 2, Float, 1});
|
||||
}
|
||||
|
||||
// Test the RG16Snorm format
|
||||
TEST_P(TextureFormatTest, RG16Snorm) {
|
||||
DoSnormTest<int16_t>({dawn::TextureFormat::RG16Snorm, 4, Float, 2});
|
||||
}
|
||||
|
||||
// Test the RGBA16Snorm format
|
||||
TEST_P(TextureFormatTest, RGBA16Snorm) {
|
||||
DoSnormTest<int16_t>({dawn::TextureFormat::RGBA16Snorm, 8, Float, 4});
|
||||
}
|
||||
|
||||
// Test the R8Uint format
|
||||
TEST_P(TextureFormatTest, R8Uint) {
|
||||
DoUintTest<uint8_t>({dawn::TextureFormat::R8Uint, 1, Uint, 1});
|
||||
}
|
||||
|
||||
// Test the RG8Uint format
|
||||
TEST_P(TextureFormatTest, RG8Uint) {
|
||||
DoUintTest<uint8_t>({dawn::TextureFormat::RG8Uint, 2, Uint, 2});
|
||||
}
|
||||
|
||||
// Test the RGBA8Uint format
|
||||
TEST_P(TextureFormatTest, RGBA8Uint) {
|
||||
DoUintTest<uint8_t>({dawn::TextureFormat::RGBA8Uint, 4, Uint, 4});
|
||||
}
|
||||
|
||||
// Test the R16Uint format
|
||||
TEST_P(TextureFormatTest, R16Uint) {
|
||||
DoUintTest<uint16_t>({dawn::TextureFormat::R16Uint, 2, Uint, 1});
|
||||
}
|
||||
|
||||
// Test the RG16Uint format
|
||||
TEST_P(TextureFormatTest, RG16Uint) {
|
||||
DoUintTest<uint16_t>({dawn::TextureFormat::RG16Uint, 4, Uint, 2});
|
||||
}
|
||||
|
||||
// Test the RGBA16Uint format
|
||||
TEST_P(TextureFormatTest, RGBA16Uint) {
|
||||
DoUintTest<uint16_t>({dawn::TextureFormat::RGBA16Uint, 8, Uint, 4});
|
||||
}
|
||||
|
||||
// Test the R32Uint format
|
||||
TEST_P(TextureFormatTest, R32Uint) {
|
||||
DoUintTest<uint32_t>({dawn::TextureFormat::R32Uint, 4, Uint, 1});
|
||||
}
|
||||
|
||||
// Test the RG32Uint format
|
||||
TEST_P(TextureFormatTest, RG32Uint) {
|
||||
DoUintTest<uint32_t>({dawn::TextureFormat::RG32Uint, 8, Uint, 2});
|
||||
}
|
||||
|
||||
// Test the RGBA32Uint format
|
||||
TEST_P(TextureFormatTest, RGBA32Uint) {
|
||||
DoUintTest<uint32_t>({dawn::TextureFormat::RGBA32Uint, 16, Uint, 4});
|
||||
}
|
||||
|
||||
// Test the R8Sint format
|
||||
TEST_P(TextureFormatTest, R8Sint) {
|
||||
DoSintTest<int8_t>({dawn::TextureFormat::R8Sint, 1, Sint, 1});
|
||||
}
|
||||
|
||||
// Test the RG8Sint format
|
||||
TEST_P(TextureFormatTest, RG8Sint) {
|
||||
DoSintTest<int8_t>({dawn::TextureFormat::RG8Sint, 2, Sint, 2});
|
||||
}
|
||||
|
||||
// Test the RGBA8Sint format
|
||||
TEST_P(TextureFormatTest, RGBA8Sint) {
|
||||
DoSintTest<int8_t>({dawn::TextureFormat::RGBA8Sint, 4, Sint, 4});
|
||||
}
|
||||
|
||||
// Test the R16Sint format
|
||||
TEST_P(TextureFormatTest, R16Sint) {
|
||||
DoSintTest<int16_t>({dawn::TextureFormat::R16Sint, 2, Sint, 1});
|
||||
}
|
||||
|
||||
// Test the RG16Sint format
|
||||
TEST_P(TextureFormatTest, RG16Sint) {
|
||||
DoSintTest<int16_t>({dawn::TextureFormat::RG16Sint, 4, Sint, 2});
|
||||
}
|
||||
|
||||
// Test the RGBA16Sint format
|
||||
TEST_P(TextureFormatTest, RGBA16Sint) {
|
||||
DoSintTest<int16_t>({dawn::TextureFormat::RGBA16Sint, 8, Sint, 4});
|
||||
}
|
||||
|
||||
// Test the R32Sint format
|
||||
TEST_P(TextureFormatTest, R32Sint) {
|
||||
DoSintTest<int32_t>({dawn::TextureFormat::R32Sint, 4, Sint, 1});
|
||||
}
|
||||
|
||||
// Test the RG32Sint format
|
||||
TEST_P(TextureFormatTest, RG32Sint) {
|
||||
DoSintTest<int32_t>({dawn::TextureFormat::RG32Sint, 8, Sint, 2});
|
||||
}
|
||||
|
||||
// Test the RGBA32Sint format
|
||||
TEST_P(TextureFormatTest, RGBA32Sint) {
|
||||
DoSintTest<int32_t>({dawn::TextureFormat::RGBA32Sint, 16, Sint, 4});
|
||||
}
|
||||
|
||||
// Test the R32Float format
|
||||
TEST_P(TextureFormatTest, R32Float) {
|
||||
DoFloat32Test({dawn::TextureFormat::R32Float, 4, Float, 1});
|
||||
}
|
||||
|
||||
// Test the RG32Float format
|
||||
TEST_P(TextureFormatTest, RG32Float) {
|
||||
DoFloat32Test({dawn::TextureFormat::RG32Float, 8, Float, 2});
|
||||
}
|
||||
|
||||
// Test the RGBA32Float format
|
||||
TEST_P(TextureFormatTest, RGBA32Float) {
|
||||
DoFloat32Test({dawn::TextureFormat::RGBA32Float, 16, Float, 4});
|
||||
}
|
||||
|
||||
// Test the R16Float format
|
||||
TEST_P(TextureFormatTest, R16Float) {
|
||||
DoFloat16Test({dawn::TextureFormat::R16Float, 2, Float, 1});
|
||||
}
|
||||
|
||||
// Test the RG16Float format
|
||||
TEST_P(TextureFormatTest, RG16Float) {
|
||||
DoFloat16Test({dawn::TextureFormat::RG16Float, 4, Float, 2});
|
||||
}
|
||||
|
||||
// Test the RGBA16Float format
|
||||
TEST_P(TextureFormatTest, RGBA16Float) {
|
||||
DoFloat16Test({dawn::TextureFormat::RGBA16Float, 8, Float, 4});
|
||||
}
|
||||
|
||||
// Test the RGBA8Unorm format
|
||||
TEST_P(TextureFormatTest, RGBA8UnormSrgb) {
|
||||
uint8_t maxValue = std::numeric_limits<uint8_t>::max();
|
||||
std::vector<uint8_t> textureData = {0, 1, maxValue, 64, 35, 68, 152, 168};
|
||||
|
||||
std::vector<float> expectedData;
|
||||
for (size_t i = 0; i < textureData.size(); i += 4) {
|
||||
expectedData.push_back(SRGBToLinear(textureData[i + 0] / float(maxValue)));
|
||||
expectedData.push_back(SRGBToLinear(textureData[i + 1] / float(maxValue)));
|
||||
expectedData.push_back(SRGBToLinear(textureData[i + 2] / float(maxValue)));
|
||||
// Alpha is linear for sRGB formats
|
||||
expectedData.push_back(textureData[i + 3] / float(maxValue));
|
||||
}
|
||||
|
||||
DoSampleTest({dawn::TextureFormat::RGBA8UnormSrgb, 4, Float, 4}, textureData, expectedData,
|
||||
1.0e-3);
|
||||
}
|
||||
|
||||
// Test the BGRA8Unorm format
|
||||
TEST_P(TextureFormatTest, BGRA8UnormSrgb) {
|
||||
uint8_t maxValue = std::numeric_limits<uint8_t>::max();
|
||||
std::vector<uint8_t> textureData = {0, 1, maxValue, 64, 35, 68, 152, 168};
|
||||
|
||||
std::vector<float> expectedData;
|
||||
for (size_t i = 0; i < textureData.size(); i += 4) {
|
||||
// Note that R and B are swapped
|
||||
expectedData.push_back(SRGBToLinear(textureData[i + 2] / float(maxValue)));
|
||||
expectedData.push_back(SRGBToLinear(textureData[i + 1] / float(maxValue)));
|
||||
expectedData.push_back(SRGBToLinear(textureData[i + 0] / float(maxValue)));
|
||||
// Alpha is linear for sRGB formats
|
||||
expectedData.push_back(textureData[i + 3] / float(maxValue));
|
||||
}
|
||||
|
||||
DoSampleTest({dawn::TextureFormat::BGRA8UnormSrgb, 4, Float, 4}, textureData, expectedData,
|
||||
1.0e-3);
|
||||
}
|
||||
|
||||
// Test the B5G6R5Unorm format
|
||||
TEST_P(TextureFormatTest, B5G6R5Unorm) {
|
||||
auto MakeBGR565 = [](uint32_t r, uint32_t g, uint32_t b) -> uint16_t {
|
||||
ASSERT((r & 0x1F) == r);
|
||||
ASSERT((g & 0x3F) == g);
|
||||
ASSERT((b & 0x1F) == b);
|
||||
return b << 11 | g << 5 | r;
|
||||
};
|
||||
|
||||
std::vector<uint16_t> textureData = {MakeBGR565(0, 0, 0), MakeBGR565(31, 63, 31),
|
||||
MakeBGR565(9, 18, 27), MakeBGR565(0, 0, 0)};
|
||||
// This is one of the only 3-channel formats, so we don't have specific testing for them. Alpha
|
||||
// should slways be sampled as 1
|
||||
// clang-format off
|
||||
std::vector<float> expectedData = {
|
||||
0.0f, 0.0f, 0.0f, 1.0f,
|
||||
1.0f, 1.0f, 1.0f, 1.0f,
|
||||
9 / 31.0f, 18 / 63.0f, 27 / 31.0f, 1.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
DoSampleTest({dawn::TextureFormat::B5G6R5Unorm, 2, Float, 4}, textureData, expectedData,
|
||||
1.0e-3);
|
||||
}
|
||||
|
||||
// Test the A2RGB10Unorm format
|
||||
// TODO(cwallez@chromium.org): This is actually RGB10A2 in WebGPU but Vulkan doesn't support that
|
||||
// format. Do all platforms have A in the high bits?
|
||||
TEST_P(TextureFormatTest, A2RGB10Unorm) {
|
||||
auto MakeA2RGB10 = [](uint32_t r, uint32_t g, uint32_t b, uint32_t a) -> uint32_t {
|
||||
ASSERT((r & 0x3FF) == r);
|
||||
ASSERT((g & 0x3FF) == g);
|
||||
ASSERT((b & 0x3FF) == b);
|
||||
ASSERT((a & 0x3) == a);
|
||||
return a << 30 | r << 20 | g << 10 | b;
|
||||
};
|
||||
|
||||
std::vector<uint32_t> textureData = {MakeA2RGB10(0, 0, 0, 0), MakeA2RGB10(1023, 1023, 1023, 1),
|
||||
MakeA2RGB10(243, 578, 765, 2), MakeA2RGB10(0, 0, 0, 3)};
|
||||
// clang-format off
|
||||
std::vector<float> expectedData = {
|
||||
0.0f, 0.0f, 0.0f, 0.0f,
|
||||
1.0f, 1.0f, 1.0f, 1 / 3.0f,
|
||||
243 / 1023.0f, 576 / 1023.0f, 765 / 1023.0f, 2 / 3.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
DoSampleTest({dawn::TextureFormat::A2RGB10Unorm, 4, Float, 4}, textureData, expectedData,
|
||||
2.0e-3);
|
||||
}
|
||||
|
||||
// Test the B10GR11Float format
|
||||
// TODO(cwallez@chromium.org): This is actually GR11B10 in WebGPU but Vulkan doesn't support that
|
||||
// format. Do all platforms have it reversed?
|
||||
TEST_P(TextureFormatTest, B10GR11Float) {
|
||||
constexpr uint32_t kFloat11Zero = 0;
|
||||
constexpr uint32_t kFloat11Infinity = 0x7C0;
|
||||
constexpr uint32_t kFloat11Nan = 0x7C1;
|
||||
constexpr uint32_t kFloat11One = 0x3C0;
|
||||
|
||||
constexpr uint32_t kFloat10Zero = 0;
|
||||
constexpr uint32_t kFloat10Infinity = 0x3E0;
|
||||
constexpr uint32_t kFloat10Nan = 0x3E1;
|
||||
constexpr uint32_t kFloat10One = 0x1E0;
|
||||
|
||||
auto MakeB10GR11 = [](uint32_t r, uint32_t g, uint32_t b) {
|
||||
ASSERT((r & 0x7FF) == r);
|
||||
ASSERT((g & 0x7FF) == g);
|
||||
ASSERT((b & 0x3FF) == b);
|
||||
return b << 22 | g << 11 | r;
|
||||
};
|
||||
|
||||
// Test each of (0, 1, INFINITY, NaN) for each component but never two with the same value at a
|
||||
// time.
|
||||
std::vector<uint32_t> textureData = {
|
||||
MakeB10GR11(kFloat11Zero, kFloat11Infinity, kFloat10Nan),
|
||||
MakeB10GR11(kFloat11Infinity, kFloat11Nan, kFloat10One),
|
||||
MakeB10GR11(kFloat11Nan, kFloat11One, kFloat10Zero),
|
||||
MakeB10GR11(kFloat11One, kFloat11Zero, kFloat10Infinity),
|
||||
};
|
||||
|
||||
// This is one of the only 3-channel formats, so we don't have specific testing for them. Alpha
|
||||
// should slways be sampled as 1
|
||||
// clang-format off
|
||||
std::vector<float> expectedData = {
|
||||
0.0f, INFINITY, NAN, 1.0f,
|
||||
INFINITY, NAN, 1.0f, 1.0f,
|
||||
NAN, 1.0f, 0.0f, 1.0f,
|
||||
1.0f, 0.0f, INFINITY, 1.0f
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
DoSampleTest({dawn::TextureFormat::B10GR11Float, 4, Float, 4}, textureData, expectedData);
|
||||
}
|
||||
|
||||
// TODO(cwallez@chromium.org): Add tests for depth-stencil formats when we know if they are copyable
|
||||
// in WebGPU.
|
||||
|
||||
DAWN_INSTANTIATE_TEST(TextureFormatTest, VulkanBackend);
|
|
@ -150,3 +150,14 @@ TEST(Math, Float32ToFloat16) {
|
|||
|
||||
ASSERT_EQ(Float32ToFloat16(1.0f), 0x3C00);
|
||||
}
|
||||
|
||||
// Tests for SRGBToLinear
|
||||
TEST(Math, SRGBToLinear) {
|
||||
ASSERT_EQ(SRGBToLinear(0.0f), 0.0f);
|
||||
ASSERT_EQ(SRGBToLinear(1.0f), 1.0f);
|
||||
|
||||
ASSERT_EQ(SRGBToLinear(-1.0f), 0.0f);
|
||||
ASSERT_EQ(SRGBToLinear(2.0f), 1.0f);
|
||||
|
||||
ASSERT_FLOAT_EQ(SRGBToLinear(0.5f), 0.21404114f);
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ namespace utils {
|
|||
// utils::MakeBindGroup(device, layout, {
|
||||
// {0, mySampler},
|
||||
// {1, myBuffer, offset, size},
|
||||
// {3, myTexture}
|
||||
// {3, myTextureView}
|
||||
// });
|
||||
|
||||
// Structure with one constructor per-type of bindings, so that the initializer_list accepts
|
||||
|
|
Loading…
Reference in New Issue