mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-06-01 04:01:26 +00:00
Add end2end test for all vertex formats
BUG=dawn:41 Change-Id: I37bde37843522a8d7c8b3bea1cb24c0971efd8e2 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/6340 Reviewed-by: Kai Ninomiya <kainino@chromium.org> Reviewed-by: Corentin Wallez <cwallez@chromium.org> Commit-Queue: Shaobo Yan <shaobo.yan@intel.com>
This commit is contained in:
parent
a32e3bd014
commit
9286adcb0f
1
BUILD.gn
1
BUILD.gn
@ -650,6 +650,7 @@ test("dawn_end2end_tests") {
|
||||
"src/tests/end2end/SamplerTests.cpp",
|
||||
"src/tests/end2end/ScissorTests.cpp",
|
||||
"src/tests/end2end/TextureViewTests.cpp",
|
||||
"src/tests/end2end/VertexFormatTests.cpp",
|
||||
"src/tests/end2end/ViewportOrientationTests.cpp",
|
||||
]
|
||||
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
#include "common/Assert.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#if defined(DAWN_COMPILER_MSVC)
|
||||
# include <intrin.h>
|
||||
#endif
|
||||
@ -77,3 +79,29 @@ uint32_t Align(uint32_t value, size_t alignment) {
|
||||
uint32_t alignment32 = static_cast<uint32_t>(alignment);
|
||||
return (value + (alignment32 - 1)) & ~(alignment32 - 1);
|
||||
}
|
||||
|
||||
uint16_t Float32ToFloat16(float fp32) {
|
||||
uint32_t fp32i = BitCast<uint32_t>(fp32);
|
||||
uint32_t sign16 = (fp32i & 0x80000000) >> 16;
|
||||
uint32_t mantissaAndExponent = fp32i & 0x7FFFFFFF;
|
||||
|
||||
if (mantissaAndExponent > 0x47FFEFFF) { // Infinity
|
||||
return static_cast<uint16_t>(sign16 | 0x7FFF);
|
||||
} else if (mantissaAndExponent < 0x38800000) { // Denormal
|
||||
uint32_t mantissa = (mantissaAndExponent & 0x007FFFFF) | 0x00800000;
|
||||
int32_t exponent = 113 - (mantissaAndExponent >> 23);
|
||||
|
||||
if (exponent < 24) {
|
||||
mantissaAndExponent = mantissa >> exponent;
|
||||
} else {
|
||||
mantissaAndExponent = 0;
|
||||
}
|
||||
|
||||
return static_cast<uint16_t>(
|
||||
sign16 | (mantissaAndExponent + 0x00000FFF + ((mantissaAndExponent >> 13) & 1)) >> 13);
|
||||
} else {
|
||||
return static_cast<uint16_t>(sign16 | (mantissaAndExponent + 0xC8000000 + 0x00000FFF +
|
||||
((mantissaAndExponent >> 13) & 1)) >>
|
||||
13);
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,10 @@
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
// The following are not valid for 0
|
||||
uint32_t ScanForward(uint32_t bits);
|
||||
@ -38,4 +42,14 @@ const T* AlignPtr(const T* ptr, size_t alignment) {
|
||||
return reinterpret_cast<const T*>(AlignVoidPtr(const_cast<T*>(ptr), alignment));
|
||||
}
|
||||
|
||||
template <typename destType, typename sourceType>
|
||||
destType BitCast(const sourceType& source) {
|
||||
static_assert(sizeof(destType) == sizeof(sourceType), "BitCast: cannot lose precision.");
|
||||
destType output;
|
||||
std::memcpy(&output, &source, sizeof(destType));
|
||||
return output;
|
||||
}
|
||||
|
||||
uint16_t Float32ToFloat16(float fp32);
|
||||
|
||||
#endif // COMMON_MATH_H_
|
||||
|
@ -105,6 +105,30 @@ namespace dawn_native { namespace opengl {
|
||||
}
|
||||
}
|
||||
|
||||
bool VertexFormatIsInt(dawn::VertexFormat format) {
|
||||
switch (format) {
|
||||
case dawn::VertexFormat::UChar2:
|
||||
case dawn::VertexFormat::UChar4:
|
||||
case dawn::VertexFormat::Char2:
|
||||
case dawn::VertexFormat::Char4:
|
||||
case dawn::VertexFormat::UShort2:
|
||||
case dawn::VertexFormat::UShort4:
|
||||
case dawn::VertexFormat::Short2:
|
||||
case dawn::VertexFormat::Short4:
|
||||
case dawn::VertexFormat::UInt:
|
||||
case dawn::VertexFormat::UInt2:
|
||||
case dawn::VertexFormat::UInt3:
|
||||
case dawn::VertexFormat::UInt4:
|
||||
case dawn::VertexFormat::Int:
|
||||
case dawn::VertexFormat::Int2:
|
||||
case dawn::VertexFormat::Int3:
|
||||
case dawn::VertexFormat::Int4:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
GLint GetStencilMaskFromStencilFormat(dawn::TextureFormat depthStencilFormat) {
|
||||
switch (depthStencilFormat) {
|
||||
case dawn::TextureFormat::D32FloatS8Uint:
|
||||
@ -242,10 +266,16 @@ namespace dawn_native { namespace opengl {
|
||||
|
||||
GLboolean normalized = VertexFormatIsNormalized(attribute.format);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, buffer);
|
||||
glVertexAttribPointer(
|
||||
location, components, formatType, normalized, input.stride,
|
||||
reinterpret_cast<void*>(
|
||||
static_cast<intptr_t>(offset + attribute.offset)));
|
||||
if (VertexFormatIsInt(attribute.format)) {
|
||||
glVertexAttribIPointer(location, components, formatType, input.stride,
|
||||
reinterpret_cast<void*>(static_cast<intptr_t>(
|
||||
offset + attribute.offset)));
|
||||
} else {
|
||||
glVertexAttribPointer(
|
||||
location, components, formatType, normalized, input.stride,
|
||||
reinterpret_cast<void*>(
|
||||
static_cast<intptr_t>(offset + attribute.offset)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
800
src/tests/end2end/VertexFormatTests.cpp
Normal file
800
src/tests/end2end/VertexFormatTests.cpp
Normal file
@ -0,0 +1,800 @@
|
||||
// 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"
|
||||
|
||||
// Vertex format tests all work the same way: the test will render a triangle.
|
||||
// Each test will set up a vertex buffer, and the vertex shader will check that
|
||||
// the vertex content is the same as what we expected. On success it outputs green,
|
||||
// otherwise red.
|
||||
|
||||
constexpr uint32_t kRTSize = 400;
|
||||
constexpr uint32_t kVertexNum = 3;
|
||||
|
||||
std::vector<uint16_t> Float32ToFloat16(std::vector<float> data) {
|
||||
std::vector<uint16_t> expectedData;
|
||||
for (auto& element : data) {
|
||||
expectedData.push_back(Float32ToFloat16(element));
|
||||
}
|
||||
return expectedData;
|
||||
}
|
||||
|
||||
template <typename destType, typename srcType>
|
||||
std::vector<destType> BitCast(std::vector<srcType> data) {
|
||||
std::vector<destType> expectedData;
|
||||
for (auto& element : data) {
|
||||
expectedData.push_back(BitCast(element));
|
||||
}
|
||||
return expectedData;
|
||||
}
|
||||
|
||||
class VertexFormatTest : public DawnTest {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
DawnTest::SetUp();
|
||||
|
||||
renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
|
||||
}
|
||||
|
||||
utils::BasicRenderPass renderPass;
|
||||
|
||||
bool IsNormalizedFormat(dawn::VertexFormat format) {
|
||||
switch (format) {
|
||||
case dawn::VertexFormat::UChar2Norm:
|
||||
case dawn::VertexFormat::UChar4Norm:
|
||||
case dawn::VertexFormat::Char2Norm:
|
||||
case dawn::VertexFormat::Char4Norm:
|
||||
case dawn::VertexFormat::UShort2Norm:
|
||||
case dawn::VertexFormat::UShort4Norm:
|
||||
case dawn::VertexFormat::Short2Norm:
|
||||
case dawn::VertexFormat::Short4Norm:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsUnsignedFormat(dawn::VertexFormat format) {
|
||||
switch (format) {
|
||||
case dawn::VertexFormat::UInt:
|
||||
case dawn::VertexFormat::UChar2:
|
||||
case dawn::VertexFormat::UChar4:
|
||||
case dawn::VertexFormat::UShort2:
|
||||
case dawn::VertexFormat::UShort4:
|
||||
case dawn::VertexFormat::UInt2:
|
||||
case dawn::VertexFormat::UInt3:
|
||||
case dawn::VertexFormat::UInt4:
|
||||
case dawn::VertexFormat::UChar2Norm:
|
||||
case dawn::VertexFormat::UChar4Norm:
|
||||
case dawn::VertexFormat::UShort2Norm:
|
||||
case dawn::VertexFormat::UShort4Norm:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsFloatFormat(dawn::VertexFormat format) {
|
||||
switch (format) {
|
||||
case dawn::VertexFormat::Half2:
|
||||
case dawn::VertexFormat::Half4:
|
||||
case dawn::VertexFormat::Float:
|
||||
case dawn::VertexFormat::Float2:
|
||||
case dawn::VertexFormat::Float3:
|
||||
case dawn::VertexFormat::Float4:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsHalfFormat(dawn::VertexFormat format) {
|
||||
switch (format) {
|
||||
case dawn::VertexFormat::Half2:
|
||||
case dawn::VertexFormat::Half4:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t BytesPerComponents(dawn::VertexFormat format) {
|
||||
switch (format) {
|
||||
case dawn::VertexFormat::Char2:
|
||||
case dawn::VertexFormat::Char4:
|
||||
case dawn::VertexFormat::UChar2:
|
||||
case dawn::VertexFormat::UChar4:
|
||||
case dawn::VertexFormat::UChar2Norm:
|
||||
case dawn::VertexFormat::UChar4Norm:
|
||||
case dawn::VertexFormat::Char2Norm:
|
||||
case dawn::VertexFormat::Char4Norm:
|
||||
return 1;
|
||||
case dawn::VertexFormat::UShort2:
|
||||
case dawn::VertexFormat::UShort4:
|
||||
case dawn::VertexFormat::Short2:
|
||||
case dawn::VertexFormat::Short4:
|
||||
case dawn::VertexFormat::UShort2Norm:
|
||||
case dawn::VertexFormat::UShort4Norm:
|
||||
case dawn::VertexFormat::Short2Norm:
|
||||
case dawn::VertexFormat::Short4Norm:
|
||||
case dawn::VertexFormat::Half2:
|
||||
case dawn::VertexFormat::Half4:
|
||||
return 2;
|
||||
case dawn::VertexFormat::UInt:
|
||||
case dawn::VertexFormat::Int:
|
||||
case dawn::VertexFormat::Float:
|
||||
case dawn::VertexFormat::UInt2:
|
||||
case dawn::VertexFormat::UInt3:
|
||||
case dawn::VertexFormat::UInt4:
|
||||
case dawn::VertexFormat::Int2:
|
||||
case dawn::VertexFormat::Int3:
|
||||
case dawn::VertexFormat::Int4:
|
||||
case dawn::VertexFormat::Float2:
|
||||
case dawn::VertexFormat::Float3:
|
||||
case dawn::VertexFormat::Float4:
|
||||
return 4;
|
||||
default:
|
||||
DAWN_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ComponentCount(dawn::VertexFormat format) {
|
||||
switch (format) {
|
||||
case dawn::VertexFormat::UInt:
|
||||
case dawn::VertexFormat::Int:
|
||||
case dawn::VertexFormat::Float:
|
||||
return 1;
|
||||
case dawn::VertexFormat::UChar2:
|
||||
case dawn::VertexFormat::UShort2:
|
||||
case dawn::VertexFormat::UInt2:
|
||||
case dawn::VertexFormat::Char2:
|
||||
case dawn::VertexFormat::Short2:
|
||||
case dawn::VertexFormat::Int2:
|
||||
case dawn::VertexFormat::UChar2Norm:
|
||||
case dawn::VertexFormat::Char2Norm:
|
||||
case dawn::VertexFormat::UShort2Norm:
|
||||
case dawn::VertexFormat::Short2Norm:
|
||||
case dawn::VertexFormat::Half2:
|
||||
case dawn::VertexFormat::Float2:
|
||||
return 2;
|
||||
case dawn::VertexFormat::Int3:
|
||||
case dawn::VertexFormat::UInt3:
|
||||
case dawn::VertexFormat::Float3:
|
||||
return 3;
|
||||
case dawn::VertexFormat::UChar4:
|
||||
case dawn::VertexFormat::UShort4:
|
||||
case dawn::VertexFormat::UInt4:
|
||||
case dawn::VertexFormat::Char4:
|
||||
case dawn::VertexFormat::Short4:
|
||||
case dawn::VertexFormat::Int4:
|
||||
case dawn::VertexFormat::UChar4Norm:
|
||||
case dawn::VertexFormat::Char4Norm:
|
||||
case dawn::VertexFormat::UShort4Norm:
|
||||
case dawn::VertexFormat::Short4Norm:
|
||||
case dawn::VertexFormat::Half4:
|
||||
case dawn::VertexFormat::Float4:
|
||||
return 4;
|
||||
default:
|
||||
DAWN_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
std::string ShaderTypeGenerator(bool isFloat,
|
||||
bool isNormalized,
|
||||
bool isUnsigned,
|
||||
uint32_t componentCount) {
|
||||
if (componentCount == 1) {
|
||||
if (isFloat || isNormalized) {
|
||||
return "float";
|
||||
} else if (isUnsigned) {
|
||||
return "uint";
|
||||
} else {
|
||||
return "int";
|
||||
}
|
||||
} else {
|
||||
if (isNormalized || isFloat) {
|
||||
return "vec" + std::to_string(componentCount);
|
||||
} else if (isUnsigned) {
|
||||
return "uvec" + std::to_string(componentCount);
|
||||
} else {
|
||||
return "ivec" + std::to_string(componentCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The length of vertexData is fixed to 3, it aligns to triangle vertex number
|
||||
template <typename T>
|
||||
dawn::RenderPipeline MakeTestPipeline(dawn::VertexFormat format, std::vector<T>& expectedData) {
|
||||
bool isFloat = IsFloatFormat(format);
|
||||
bool isNormalized = IsNormalizedFormat(format);
|
||||
bool isUnsigned = IsUnsignedFormat(format);
|
||||
bool isInputTypeFloat = isFloat || isNormalized;
|
||||
bool isHalf = IsHalfFormat(format);
|
||||
const uint16_t kNegativeZeroInHalf = 0x8000;
|
||||
|
||||
uint32_t componentCount = ComponentCount(format);
|
||||
|
||||
std::string variableType =
|
||||
ShaderTypeGenerator(isFloat, isNormalized, isUnsigned, componentCount);
|
||||
std::string expectedDataType = ShaderTypeGenerator(isFloat, isNormalized, isUnsigned, 1);
|
||||
std::ostringstream vs;
|
||||
vs << "#version 450\n";
|
||||
|
||||
// layout(location = 0) in float/uint/int/ivecn/vecn/uvecn test;
|
||||
vs << "layout(location = 0) in " << variableType << " test;\n";
|
||||
vs << "layout(location = 0) out vec4 color;\n";
|
||||
// Because x86 CPU using "extended
|
||||
// precision"(https://en.wikipedia.org/wiki/Extended_precision) during float
|
||||
// math(https://developer.nvidia.com/sites/default/files/akamai/cuda/files/NVIDIA-CUDA-Floating-Point.pdf),
|
||||
// move normalization and Float16ToFloat32 into shader to generate
|
||||
// expected value.
|
||||
vs << "float Float16ToFloat32(uint fp16) {\n";
|
||||
vs << " uint magic = (uint(254) - uint(15)) << 23;\n";
|
||||
vs << " uint was_inf_nan = (uint(127) + uint(16)) << 23;\n";
|
||||
vs << " uint fp32u;\n";
|
||||
vs << " float fp32;\n";
|
||||
vs << " fp32u = (fp16 & 0x7FFF) << 13;\n";
|
||||
vs << " fp32 = uintBitsToFloat(fp32u) * uintBitsToFloat(magic);\n";
|
||||
vs << " fp32u = floatBitsToUint(fp32);\n";
|
||||
vs << " if (fp32 >= uintBitsToFloat(was_inf_nan)) {\n";
|
||||
vs << " fp32u |= uint(255) << 23;\n";
|
||||
vs << " }\n";
|
||||
vs << " fp32u |= (fp16 & 0x8000) << 16;\n";
|
||||
vs << " fp32 = uintBitsToFloat(fp32u);\n";
|
||||
vs << " return fp32;\n";
|
||||
vs << "}\n";
|
||||
|
||||
vs << "void main() {\n";
|
||||
|
||||
// Hard code the triangle in the shader so that we don't have to add a vertex input for it.
|
||||
vs << " const vec2 pos[3] = vec2[3](vec2(-1.0f, 0.0f), vec2(-1.0f, -1.0f), vec2(0.0f, "
|
||||
"-1.0f));\n";
|
||||
vs << " gl_Position = vec4(pos[gl_VertexIndex], 0.0, 1.0);\n";
|
||||
|
||||
// Declare expected values.
|
||||
vs << " " << expectedDataType << " expected[" + std::to_string(kVertexNum) + "]";
|
||||
vs << "[" + std::to_string(componentCount) + "];\n";
|
||||
// Assign each elements in expected values
|
||||
// e.g. expected[0][0] = uint(1);
|
||||
// expected[0][1] = uint(2);
|
||||
for (uint32_t i = 0; i < kVertexNum; ++i) {
|
||||
for (uint32_t j = 0; j < componentCount; ++j) {
|
||||
vs << " expected[" + std::to_string(i) + "][" + std::to_string(j) + "] = "
|
||||
<< expectedDataType << "(";
|
||||
if (isInputTypeFloat &&
|
||||
std::isnan(static_cast<float>(expectedData[i * componentCount + j]))) {
|
||||
// Set NaN.
|
||||
vs << "0.0 / 0.0);\n";
|
||||
} else if (isNormalized) {
|
||||
// Move normalize operation into shader because of CPU and GPU precision
|
||||
// different on float math.
|
||||
vs << "max(float(" << std::to_string(expectedData[i * componentCount + j])
|
||||
<< ") / " << std::to_string(std::numeric_limits<T>::max()) << ", -1.0));\n";
|
||||
} else if (isHalf) {
|
||||
// Becasue Vulkan and D3D12 handle -0.0f through uintBitsToFloat have different
|
||||
// result (Vulkan take -0.0f as -0.0 but D3D12 take -0.0f as 0), add workaround
|
||||
// for -0.0f.
|
||||
if (static_cast<uint16_t>(expectedData[i * componentCount + j]) ==
|
||||
kNegativeZeroInHalf) {
|
||||
vs << "-0.0f);\n";
|
||||
} else {
|
||||
vs << "Float16ToFloat32("
|
||||
<< std::to_string(expectedData[i * componentCount + j]);
|
||||
vs << "));\n";
|
||||
}
|
||||
} else {
|
||||
vs << std::to_string(expectedData[i * componentCount + j]) << ");\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vs << " bool success = true;\n";
|
||||
// Perform the checks by successively ANDing a boolean
|
||||
for (uint32_t component = 0; component < componentCount; ++component) {
|
||||
std::string suffix = componentCount == 1 ? "" : "[" + std::to_string(component) + "]";
|
||||
std::string testVal = "testVal" + std::to_string(component);
|
||||
std::string expectedVal = "expectedVal" + std::to_string(component);
|
||||
vs << " " << expectedDataType << " " << testVal << ";\n";
|
||||
vs << " " << expectedDataType << " " << expectedVal << ";\n";
|
||||
vs << " " << testVal << " = test" << suffix << ";\n";
|
||||
vs << " " << expectedVal << " = expected[gl_VertexIndex]"
|
||||
<< "[" << component << "];\n";
|
||||
if (!isInputTypeFloat) { // Integer / unsigned integer need to match exactly.
|
||||
vs << " success = success && (" << testVal << " == " << expectedVal << ");\n";
|
||||
} else {
|
||||
// TODO(shaobo.yan@intel.com) : a difference of 8 ULPs is allowed in this test
|
||||
// because it is required on MacbookPro 11.5,AMD Radeon HD 8870M(on macOS 10.13.6),
|
||||
// but that it might be possible to tighten.
|
||||
vs << " if (isnan(" << expectedVal << ")) {\n";
|
||||
vs << " success = success && isnan(" << testVal << ");\n";
|
||||
vs << " } else {\n";
|
||||
vs << " uint testValFloatToUint = floatBitsToUint(" << testVal << ");\n";
|
||||
vs << " uint expectedValFloatToUint = floatBitsToUint(" << expectedVal
|
||||
<< ");\n";
|
||||
vs << " success = success && max(testValFloatToUint, "
|
||||
"expectedValFloatToUint)";
|
||||
vs << " - min(testValFloatToUint, expectedValFloatToUint) < uint(8);\n";
|
||||
vs << " }\n";
|
||||
}
|
||||
}
|
||||
vs << " if (success) {\n";
|
||||
vs << " color = vec4(0.0f, 1.0f, 0.0f, 1.0f);\n";
|
||||
vs << " } else {\n";
|
||||
vs << " color = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n";
|
||||
vs << " }\n";
|
||||
vs << "}\n";
|
||||
|
||||
dawn::ShaderModule vsModule =
|
||||
utils::CreateShaderModule(device, dawn::ShaderStage::Vertex, vs.str().c_str());
|
||||
|
||||
dawn::ShaderModule fsModule =
|
||||
utils::CreateShaderModule(device, dawn::ShaderStage::Fragment, R"(
|
||||
#version 450
|
||||
layout(location = 0) in vec4 color;
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
void main() {
|
||||
fragColor = color;
|
||||
})");
|
||||
|
||||
uint32_t bytesPerComponents = BytesPerComponents(format);
|
||||
uint32_t strideBytes = bytesPerComponents * componentCount;
|
||||
// Stride size must be multiple of 4 bytes.
|
||||
if (strideBytes % 4 != 0) {
|
||||
strideBytes += (4 - strideBytes % 4);
|
||||
}
|
||||
|
||||
utils::ComboRenderPipelineDescriptor descriptor(device);
|
||||
descriptor.cVertexStage.module = vsModule;
|
||||
descriptor.cFragmentStage.module = fsModule;
|
||||
descriptor.cInputState.numInputs = 1;
|
||||
descriptor.cInputState.cInputs[0].stride = strideBytes;
|
||||
descriptor.cInputState.numAttributes = 1;
|
||||
descriptor.cInputState.cAttributes[0].format = format;
|
||||
descriptor.cColorStates[0]->format = renderPass.colorFormat;
|
||||
|
||||
return device.CreateRenderPipeline(&descriptor);
|
||||
}
|
||||
|
||||
template <typename VertexType, typename ExpectedType>
|
||||
void DoVertexFormatTest(dawn::VertexFormat format,
|
||||
std::vector<VertexType> vertex,
|
||||
std::vector<ExpectedType> expectedData) {
|
||||
dawn::RenderPipeline pipeline = MakeTestPipeline(format, expectedData);
|
||||
dawn::Buffer vertexBuffer =
|
||||
utils::CreateBufferFromData(device, vertex.data(), vertex.size() * sizeof(VertexType),
|
||||
dawn::BufferUsageBit::Vertex);
|
||||
uint64_t zeroOffset = 0;
|
||||
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
{
|
||||
dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
|
||||
pass.SetPipeline(pipeline);
|
||||
pass.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset);
|
||||
pass.Draw(3, 1, 0, 0);
|
||||
pass.EndPass();
|
||||
}
|
||||
|
||||
dawn::CommandBuffer commands = encoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, 0, 0);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(VertexFormatTest, UChar2) {
|
||||
std::vector<uint8_t> vertexData = {
|
||||
std::numeric_limits<uint8_t>::max(),
|
||||
0,
|
||||
0, // padding two bytes for stride
|
||||
0,
|
||||
std::numeric_limits<uint8_t>::min(),
|
||||
2,
|
||||
0,
|
||||
0, // padding two bytes for stride
|
||||
200,
|
||||
201,
|
||||
0,
|
||||
0 // padding two bytes for buffer copy
|
||||
};
|
||||
|
||||
std::vector<uint8_t> expectedData = {
|
||||
std::numeric_limits<uint8_t>::max(), 0, std::numeric_limits<uint8_t>::min(), 2, 200, 201,
|
||||
};
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::UChar2, vertexData, expectedData);
|
||||
}
|
||||
|
||||
TEST_P(VertexFormatTest, UChar4) {
|
||||
std::vector<uint8_t> vertexData = {
|
||||
std::numeric_limits<uint8_t>::max(),
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
std::numeric_limits<uint8_t>::min(),
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
200,
|
||||
201,
|
||||
202,
|
||||
203,
|
||||
};
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::UChar4, vertexData, vertexData);
|
||||
}
|
||||
|
||||
TEST_P(VertexFormatTest, Char2) {
|
||||
std::vector<int8_t> vertexData = {
|
||||
std::numeric_limits<int8_t>::max(),
|
||||
0,
|
||||
0, // padding two bytes for stride
|
||||
0,
|
||||
std::numeric_limits<int8_t>::min(),
|
||||
-2,
|
||||
0, // padding two bytes for stride
|
||||
0,
|
||||
120,
|
||||
-121,
|
||||
0,
|
||||
0 // padding two bytes for buffer copy
|
||||
};
|
||||
|
||||
std::vector<int8_t> expectedData = {
|
||||
std::numeric_limits<int8_t>::max(), 0, std::numeric_limits<int8_t>::min(), -2, 120, -121,
|
||||
};
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::Char2, vertexData, expectedData);
|
||||
}
|
||||
|
||||
TEST_P(VertexFormatTest, Char4) {
|
||||
std::vector<int8_t> vertexData = {
|
||||
std::numeric_limits<int8_t>::max(),
|
||||
0,
|
||||
-1,
|
||||
2,
|
||||
std::numeric_limits<int8_t>::min(),
|
||||
-2,
|
||||
3,
|
||||
4,
|
||||
120,
|
||||
-121,
|
||||
122,
|
||||
-123,
|
||||
};
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::Char4, vertexData, vertexData);
|
||||
}
|
||||
|
||||
TEST_P(VertexFormatTest, UChar2Norm) {
|
||||
std::vector<uint8_t> vertexData = {
|
||||
std::numeric_limits<uint8_t>::max(),
|
||||
std::numeric_limits<uint8_t>::min(),
|
||||
0, // padding two bytes for stride
|
||||
0,
|
||||
std::numeric_limits<uint8_t>::max() / 2,
|
||||
std::numeric_limits<uint8_t>::min() / 2,
|
||||
0, // padding two bytes for stride
|
||||
0,
|
||||
200,
|
||||
201,
|
||||
0,
|
||||
0 // padding two bytes for buffer copy
|
||||
};
|
||||
|
||||
std::vector<uint8_t> expectedData = {std::numeric_limits<uint8_t>::max(),
|
||||
std::numeric_limits<uint8_t>::min(),
|
||||
std::numeric_limits<uint8_t>::max() / 2,
|
||||
std::numeric_limits<uint8_t>::min() / 2,
|
||||
200,
|
||||
201};
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::UChar2Norm, vertexData, expectedData);
|
||||
}
|
||||
|
||||
TEST_P(VertexFormatTest, UChar4Norm) {
|
||||
std::vector<uint8_t> vertexData = {std::numeric_limits<uint8_t>::max(),
|
||||
std::numeric_limits<uint8_t>::min(),
|
||||
0,
|
||||
0,
|
||||
std::numeric_limits<uint8_t>::max() / 2,
|
||||
std::numeric_limits<uint8_t>::min() / 2,
|
||||
0,
|
||||
0,
|
||||
200,
|
||||
201,
|
||||
202,
|
||||
203};
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::UChar4Norm, vertexData, vertexData);
|
||||
}
|
||||
|
||||
TEST_P(VertexFormatTest, Char2Norm) {
|
||||
std::vector<int8_t> vertexData = {
|
||||
std::numeric_limits<int8_t>::max(),
|
||||
std::numeric_limits<int8_t>::min(),
|
||||
0, // padding two bytes for stride
|
||||
0,
|
||||
std::numeric_limits<int8_t>::max() / 2,
|
||||
std::numeric_limits<int8_t>::min() / 2,
|
||||
0, // padding two bytes for stride
|
||||
0,
|
||||
120,
|
||||
-121,
|
||||
0,
|
||||
0 // padding two bytes for buffer copy
|
||||
};
|
||||
|
||||
std::vector<int8_t> expectedData = {
|
||||
std::numeric_limits<int8_t>::max(),
|
||||
std::numeric_limits<int8_t>::min(),
|
||||
std::numeric_limits<int8_t>::max() / 2,
|
||||
std::numeric_limits<int8_t>::min() / 2,
|
||||
120,
|
||||
-121,
|
||||
};
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::Char2Norm, vertexData, expectedData);
|
||||
}
|
||||
|
||||
TEST_P(VertexFormatTest, Char4Norm) {
|
||||
std::vector<int8_t> vertexData = {std::numeric_limits<int8_t>::max(),
|
||||
std::numeric_limits<int8_t>::min(),
|
||||
0,
|
||||
0,
|
||||
std::numeric_limits<int8_t>::max() / 2,
|
||||
std::numeric_limits<int8_t>::min() / 2,
|
||||
-2,
|
||||
2,
|
||||
120,
|
||||
-120,
|
||||
102,
|
||||
-123};
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::Char4Norm, vertexData, vertexData);
|
||||
}
|
||||
|
||||
TEST_P(VertexFormatTest, UShort2) {
|
||||
std::vector<uint16_t> vertexData = {std::numeric_limits<uint16_t>::max(),
|
||||
0,
|
||||
std::numeric_limits<uint16_t>::min(),
|
||||
2,
|
||||
65432,
|
||||
4890};
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::UShort2, vertexData, vertexData);
|
||||
}
|
||||
|
||||
TEST_P(VertexFormatTest, UShort4) {
|
||||
std::vector<uint16_t> vertexData = {
|
||||
std::numeric_limits<uint16_t>::max(),
|
||||
std::numeric_limits<uint8_t>::max(),
|
||||
1,
|
||||
2,
|
||||
std::numeric_limits<uint16_t>::min(),
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
65520,
|
||||
65521,
|
||||
3435,
|
||||
3467,
|
||||
};
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::UShort4, vertexData, vertexData);
|
||||
}
|
||||
|
||||
TEST_P(VertexFormatTest, Short2) {
|
||||
std::vector<int16_t> vertexData = {std::numeric_limits<int16_t>::max(),
|
||||
0,
|
||||
std::numeric_limits<int16_t>::min(),
|
||||
-2,
|
||||
3876,
|
||||
-3948};
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::Short2, vertexData, vertexData);
|
||||
}
|
||||
|
||||
TEST_P(VertexFormatTest, Short4) {
|
||||
std::vector<int16_t> vertexData = {
|
||||
std::numeric_limits<int16_t>::max(),
|
||||
0,
|
||||
-1,
|
||||
2,
|
||||
std::numeric_limits<int16_t>::min(),
|
||||
-2,
|
||||
3,
|
||||
4,
|
||||
24567,
|
||||
-23545,
|
||||
4350,
|
||||
-2987,
|
||||
};
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::Short4, vertexData, vertexData);
|
||||
}
|
||||
|
||||
TEST_P(VertexFormatTest, UShort2Norm) {
|
||||
std::vector<uint16_t> vertexData = {std::numeric_limits<uint16_t>::max(),
|
||||
std::numeric_limits<uint16_t>::min(),
|
||||
std::numeric_limits<uint16_t>::max() / 2,
|
||||
std::numeric_limits<uint16_t>::min() / 2,
|
||||
3456,
|
||||
6543};
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::UShort2Norm, vertexData, vertexData);
|
||||
}
|
||||
|
||||
TEST_P(VertexFormatTest, UShort4Norm) {
|
||||
std::vector<uint16_t> vertexData = {std::numeric_limits<uint16_t>::max(),
|
||||
std::numeric_limits<uint16_t>::min(),
|
||||
0,
|
||||
0,
|
||||
std::numeric_limits<uint16_t>::max() / 2,
|
||||
std::numeric_limits<uint16_t>::min() / 2,
|
||||
0,
|
||||
0,
|
||||
2987,
|
||||
3055,
|
||||
2987,
|
||||
2987};
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::UShort4Norm, vertexData, vertexData);
|
||||
}
|
||||
|
||||
TEST_P(VertexFormatTest, Short2Norm) {
|
||||
std::vector<int16_t> vertexData = {std::numeric_limits<int16_t>::max(),
|
||||
std::numeric_limits<int16_t>::min(),
|
||||
std::numeric_limits<int16_t>::max() / 2,
|
||||
std::numeric_limits<int16_t>::min() / 2,
|
||||
4987,
|
||||
-6789};
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::Short2Norm, vertexData, vertexData);
|
||||
}
|
||||
|
||||
TEST_P(VertexFormatTest, Short4Norm) {
|
||||
std::vector<int16_t> vertexData = {std::numeric_limits<int16_t>::max(),
|
||||
std::numeric_limits<int16_t>::min(),
|
||||
0,
|
||||
0,
|
||||
std::numeric_limits<int16_t>::max() / 2,
|
||||
std::numeric_limits<int16_t>::min() / 2,
|
||||
-2,
|
||||
2,
|
||||
2890,
|
||||
-29011,
|
||||
20432,
|
||||
-2083};
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::Short4Norm, vertexData, vertexData);
|
||||
}
|
||||
|
||||
TEST_P(VertexFormatTest, Half2) {
|
||||
std::vector<uint16_t> vertexData =
|
||||
Float32ToFloat16(std::vector<float>({14.8, -0.0, 22.5, 1.3, +0.0, -24.8}));
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::Half2, vertexData, vertexData);
|
||||
}
|
||||
|
||||
TEST_P(VertexFormatTest, Half4) {
|
||||
std::vector<uint16_t> vertexData = Float32ToFloat16(std::vector<float>(
|
||||
{+0.0, -16.8, 18.2, -0.0, 12.5, 1.3, 14.8, -12.4, 22.5, -48.8, 47.4, -24.8}));
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::Half4, vertexData, vertexData);
|
||||
}
|
||||
|
||||
TEST_P(VertexFormatTest, Float) {
|
||||
std::vector<float> vertexData = {1.3f, +0.0f, -0.0f};
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::Float, vertexData, vertexData);
|
||||
|
||||
vertexData = std::vector<float>{+1.0f, -1.0f, 18.23f};
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::Float, vertexData, vertexData);
|
||||
}
|
||||
|
||||
TEST_P(VertexFormatTest, Float2) {
|
||||
std::vector<float> vertexData = {18.23f, -0.0f, +0.0f, +1.0f, 1.3f, -1.0f};
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::Float2, vertexData, vertexData);
|
||||
}
|
||||
|
||||
TEST_P(VertexFormatTest, Float3) {
|
||||
std::vector<float> vertexData = {
|
||||
+0.0f, -1.0f, -0.0f, 1.0f, 1.3f, 99.45f, 23.6f, -81.2f, 55.0f,
|
||||
};
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::Float3, vertexData, vertexData);
|
||||
}
|
||||
|
||||
TEST_P(VertexFormatTest, Float4) {
|
||||
std::vector<float> vertexData = {
|
||||
19.2f, -19.3f, +0.0f, 1.0f, -0.0f, 1.0f, 1.3f, -1.0f, 13.078f, 21.1965f, -1.1f, -1.2f,
|
||||
};
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::Float4, vertexData, vertexData);
|
||||
}
|
||||
|
||||
TEST_P(VertexFormatTest, UInt) {
|
||||
std::vector<uint32_t> vertexData = {std::numeric_limits<uint32_t>::max(),
|
||||
std::numeric_limits<uint16_t>::max(),
|
||||
std::numeric_limits<uint8_t>::max()};
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::UInt, vertexData, vertexData);
|
||||
}
|
||||
|
||||
TEST_P(VertexFormatTest, UInt2) {
|
||||
std::vector<uint32_t> vertexData = {std::numeric_limits<uint32_t>::max(), 32,
|
||||
std::numeric_limits<uint16_t>::max(), 64,
|
||||
std::numeric_limits<uint8_t>::max(), 128};
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::UInt2, vertexData, vertexData);
|
||||
}
|
||||
|
||||
TEST_P(VertexFormatTest, UInt3) {
|
||||
std::vector<uint32_t> vertexData = {std::numeric_limits<uint32_t>::max(), 32, 64,
|
||||
std::numeric_limits<uint16_t>::max(), 164, 128,
|
||||
std::numeric_limits<uint8_t>::max(), 1283, 256};
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::UInt3, vertexData, vertexData);
|
||||
}
|
||||
|
||||
TEST_P(VertexFormatTest, UInt4) {
|
||||
std::vector<uint32_t> vertexData = {std::numeric_limits<uint32_t>::max(), 32, 64, 5460,
|
||||
std::numeric_limits<uint16_t>::max(), 164, 128, 0,
|
||||
std::numeric_limits<uint8_t>::max(), 1283, 256, 4567};
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::UInt4, vertexData, vertexData);
|
||||
}
|
||||
|
||||
TEST_P(VertexFormatTest, Int) {
|
||||
std::vector<int32_t> vertexData = {std::numeric_limits<int32_t>::max(),
|
||||
std::numeric_limits<int32_t>::min(),
|
||||
std::numeric_limits<int8_t>::max()};
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::Int, vertexData, vertexData);
|
||||
}
|
||||
|
||||
TEST_P(VertexFormatTest, Int2) {
|
||||
std::vector<int32_t> vertexData = {
|
||||
std::numeric_limits<int32_t>::max(), std::numeric_limits<int32_t>::min(),
|
||||
std::numeric_limits<int16_t>::max(), std::numeric_limits<int16_t>::min(),
|
||||
std::numeric_limits<int8_t>::max(), std::numeric_limits<int8_t>::min()};
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::Int2, vertexData, vertexData);
|
||||
}
|
||||
|
||||
TEST_P(VertexFormatTest, Int3) {
|
||||
std::vector<int32_t> vertexData = {
|
||||
std::numeric_limits<int32_t>::max(), std::numeric_limits<int32_t>::min(), 64,
|
||||
std::numeric_limits<int16_t>::max(), std::numeric_limits<int16_t>::min(), 128,
|
||||
std::numeric_limits<int8_t>::max(), std::numeric_limits<int8_t>::min(), 256};
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::Int3, vertexData, vertexData);
|
||||
}
|
||||
|
||||
TEST_P(VertexFormatTest, Int4) {
|
||||
std::vector<int32_t> vertexData = {
|
||||
std::numeric_limits<int32_t>::max(), std::numeric_limits<int32_t>::min(), 64, -5460,
|
||||
std::numeric_limits<int16_t>::max(), std::numeric_limits<int16_t>::min(), -128, 0,
|
||||
std::numeric_limits<int8_t>::max(), std::numeric_limits<int8_t>::min(), 256, -4567};
|
||||
|
||||
DoVertexFormatTest(dawn::VertexFormat::Int4, vertexData, vertexData);
|
||||
}
|
||||
|
||||
DAWN_INSTANTIATE_TEST(VertexFormatTest, D3D12Backend, MetalBackend, OpenGLBackend, VulkanBackend);
|
Loading…
x
Reference in New Issue
Block a user