mirror of https://github.com/xemu-project/xemu.git
1293 lines
56 KiB
C++
1293 lines
56 KiB
C++
#include <cstdint>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <regex>
|
|
#include <sstream>
|
|
#include <string>
|
|
|
|
#include "../common/output_stream.h"
|
|
#include "gtest/gtest.h"
|
|
#include "spirv_reflect.h"
|
|
|
|
#if defined(_MSC_VER)
|
|
#include <direct.h>
|
|
#define posix_chdir(d) _chdir(d)
|
|
#else
|
|
#include <unistd.h>
|
|
#define posix_chdir(d) chdir(d)
|
|
#endif
|
|
|
|
#if defined(SPIRV_REFLECT_HAS_VULKAN_H)
|
|
// clang-format off
|
|
// Verify that SpvReflect enums match their Vk equivalents where appropriate
|
|
#include <vulkan/vulkan.h>
|
|
// SpvReflectFormat == VkFormat
|
|
static_assert((uint32_t)SPV_REFLECT_FORMAT_UNDEFINED == (uint32_t)VK_FORMAT_UNDEFINED, "SpvReflect/Vk enum mismatch");
|
|
static_assert((uint32_t)SPV_REFLECT_FORMAT_R32_UINT == (uint32_t)VK_FORMAT_R32_UINT, "SpvReflect/Vk enum mismatch");
|
|
static_assert((uint32_t)SPV_REFLECT_FORMAT_R32_SINT == (uint32_t)VK_FORMAT_R32_SINT, "SpvReflect/Vk enum mismatch");
|
|
static_assert((uint32_t)SPV_REFLECT_FORMAT_R32_SFLOAT == (uint32_t)VK_FORMAT_R32_SFLOAT, "SpvReflect/Vk enum mismatch");
|
|
static_assert((uint32_t)SPV_REFLECT_FORMAT_R32G32_UINT == (uint32_t)VK_FORMAT_R32G32_UINT, "SpvReflect/Vk enum mismatch");
|
|
static_assert((uint32_t)SPV_REFLECT_FORMAT_R32G32_SINT == (uint32_t)VK_FORMAT_R32G32_SINT, "SpvReflect/Vk enum mismatch");
|
|
static_assert((uint32_t)SPV_REFLECT_FORMAT_R32G32_SFLOAT == (uint32_t)VK_FORMAT_R32G32_SFLOAT, "SpvReflect/Vk enum mismatch");
|
|
static_assert((uint32_t)SPV_REFLECT_FORMAT_R32G32B32_UINT == (uint32_t)VK_FORMAT_R32G32B32_UINT, "SpvReflect/Vk enum mismatch");
|
|
static_assert((uint32_t)SPV_REFLECT_FORMAT_R32G32B32_SINT == (uint32_t)VK_FORMAT_R32G32B32_SINT, "SpvReflect/Vk enum mismatch");
|
|
static_assert((uint32_t)SPV_REFLECT_FORMAT_R32G32B32_SFLOAT == (uint32_t)VK_FORMAT_R32G32B32_SFLOAT, "SpvReflect/Vk enum mismatch");
|
|
static_assert((uint32_t)SPV_REFLECT_FORMAT_R32G32B32A32_UINT == (uint32_t)VK_FORMAT_R32G32B32A32_UINT, "SpvReflect/Vk enum mismatch");
|
|
static_assert((uint32_t)SPV_REFLECT_FORMAT_R32G32B32A32_SINT == (uint32_t)VK_FORMAT_R32G32B32A32_SINT, "SpvReflect/Vk enum mismatch");
|
|
static_assert((uint32_t)SPV_REFLECT_FORMAT_R32G32B32A32_SFLOAT == (uint32_t)VK_FORMAT_R32G32B32A32_SFLOAT, "SpvReflect/Vk enum mismatch");
|
|
// SpvReflectDescriptorType == VkDescriptorType
|
|
static_assert((uint32_t)SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLER == (uint32_t)VK_DESCRIPTOR_TYPE_SAMPLER, "SpvReflect/Vk enum mismatch");
|
|
static_assert((uint32_t)SPV_REFLECT_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER == (uint32_t)VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, "SpvReflect/Vk enum mismatch");
|
|
static_assert((uint32_t)SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLED_IMAGE == (uint32_t)VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, "SpvReflect/Vk enum mismatch");
|
|
static_assert((uint32_t)SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE == (uint32_t)VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, "SpvReflect/Vk enum mismatch");
|
|
static_assert((uint32_t)SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER == (uint32_t)VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, "SpvReflect/Vk enum mismatch");
|
|
static_assert((uint32_t)SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER == (uint32_t)VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, "SpvReflect/Vk enum mismatch");
|
|
static_assert((uint32_t)SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER == (uint32_t)VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, "SpvReflect/Vk enum mismatch");
|
|
static_assert((uint32_t)SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER == (uint32_t)VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, "SpvReflect/Vk enum mismatch");
|
|
static_assert((uint32_t)SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC == (uint32_t)VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, "SpvReflect/Vk enum mismatch");
|
|
static_assert((uint32_t)SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC == (uint32_t)VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, "SpvReflect/Vk enum mismatch");
|
|
static_assert((uint32_t)SPV_REFLECT_DESCRIPTOR_TYPE_INPUT_ATTACHMENT == (uint32_t)VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, "SpvReflect/Vk enum mismatch");
|
|
// SpvReflectShaderStageFlagBits == VkShaderStageFlagBits
|
|
static_assert((uint32_t)SPV_REFLECT_SHADER_STAGE_VERTEX_BIT == (uint32_t)VK_SHADER_STAGE_VERTEX_BIT, "SpvReflect/Vk enum mismatch");
|
|
static_assert((uint32_t)SPV_REFLECT_SHADER_STAGE_TESSELLATION_CONTROL_BIT == (uint32_t)VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, "SpvReflect/Vk enum mismatch");
|
|
static_assert((uint32_t)SPV_REFLECT_SHADER_STAGE_TESSELLATION_EVALUATION_BIT == (uint32_t)VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, "SpvReflect/Vk enum mismatch");
|
|
static_assert((uint32_t)SPV_REFLECT_SHADER_STAGE_GEOMETRY_BIT == (uint32_t)VK_SHADER_STAGE_GEOMETRY_BIT, "SpvReflect/Vk enum mismatch");
|
|
static_assert((uint32_t)SPV_REFLECT_SHADER_STAGE_FRAGMENT_BIT == (uint32_t)VK_SHADER_STAGE_FRAGMENT_BIT, "SpvReflect/Vk enum mismatch");
|
|
static_assert((uint32_t)SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT == (uint32_t)VK_SHADER_STAGE_COMPUTE_BIT, "SpvReflect/Vk enum mismatch");
|
|
#endif // defined(SPIRV_REFLECT_HAS_VULKAN_H)
|
|
// clang-format on
|
|
|
|
TEST(SpirvReflectTestCase, SourceLanguage) {
|
|
EXPECT_STREQ(spvReflectSourceLanguage(SpvSourceLanguageESSL), "ESSL");
|
|
EXPECT_STREQ(spvReflectSourceLanguage(SpvSourceLanguageGLSL), "GLSL");
|
|
EXPECT_STREQ(spvReflectSourceLanguage(SpvSourceLanguageOpenCL_C), "OpenCL_C");
|
|
EXPECT_STREQ(spvReflectSourceLanguage(SpvSourceLanguageOpenCL_CPP),
|
|
"OpenCL_CPP");
|
|
EXPECT_STREQ(spvReflectSourceLanguage(SpvSourceLanguageHLSL), "HLSL");
|
|
|
|
EXPECT_STREQ(spvReflectSourceLanguage(SpvSourceLanguageUnknown), "Unknown");
|
|
// Invalid inputs
|
|
EXPECT_STREQ(spvReflectSourceLanguage(SpvSourceLanguageMax), "Unknown");
|
|
EXPECT_STREQ(spvReflectSourceLanguage(
|
|
static_cast<SpvSourceLanguage>(SpvSourceLanguageMax - 1)),
|
|
"Unknown");
|
|
}
|
|
|
|
class SpirvReflectTest : public ::testing::TestWithParam<const char*> {
|
|
public:
|
|
// optional: initialize static data to be shared by all tests in this test
|
|
// case. Note that for parameterized tests, the specific parameter value is a
|
|
// non-static member data
|
|
static void SetUpTestCase() {
|
|
FILE* f = fopen("tests/glsl/built_in_format.spv", "r");
|
|
if (!f) {
|
|
posix_chdir("..");
|
|
f = fopen("tests/glsl/built_in_format.spv", "r");
|
|
}
|
|
EXPECT_NE(f, nullptr) << "Couldn't find test shaders!";
|
|
if (f) {
|
|
fclose(f);
|
|
}
|
|
}
|
|
static void TearDownTestCase() {}
|
|
|
|
protected:
|
|
SpirvReflectTest() {
|
|
// set-up work for each test
|
|
}
|
|
|
|
~SpirvReflectTest() override {
|
|
// clean-up work that doesn't throw exceptions
|
|
}
|
|
|
|
// optional: called after constructor & before destructor, respectively.
|
|
// Used if you have initialization steps that can throw exceptions or must
|
|
// otherwise be deferred.
|
|
void SetUp() override {
|
|
// called after constructor before each test
|
|
spirv_path_ = GetParam();
|
|
std::ifstream spirv_file(spirv_path_, std::ios::binary | std::ios::ate);
|
|
std::streampos spirv_file_nbytes = spirv_file.tellg();
|
|
spirv_file.seekg(0);
|
|
spirv_.resize(spirv_file_nbytes);
|
|
spirv_file.read(reinterpret_cast<char*>(spirv_.data()), spirv_.size());
|
|
|
|
SpvReflectResult result =
|
|
spvReflectCreateShaderModule(spirv_.size(), spirv_.data(), &module_);
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS, result)
|
|
<< "spvReflectCreateShaderModule() failed";
|
|
}
|
|
|
|
// optional:
|
|
void TearDown() override {
|
|
// called before destructor after all tests
|
|
spvReflectDestroyShaderModule(&module_);
|
|
}
|
|
|
|
// members here will be accessible in all tests in this test case
|
|
std::string spirv_path_;
|
|
std::vector<uint8_t> spirv_;
|
|
SpvReflectShaderModule module_;
|
|
|
|
// static members will be accessible to all tests in this test case
|
|
static std::string test_shaders_dir;
|
|
};
|
|
|
|
TEST_P(SpirvReflectTest, GetCodeSize) {
|
|
EXPECT_EQ(spvReflectGetCodeSize(&module_), spirv_.size());
|
|
}
|
|
TEST(SpirvReflectTestCase, GetCodeSize_Errors) {
|
|
// NULL module
|
|
EXPECT_EQ(spvReflectGetCodeSize(nullptr), 0);
|
|
}
|
|
|
|
TEST_P(SpirvReflectTest, GetCode) {
|
|
int code_compare =
|
|
memcmp(spvReflectGetCode(&module_), spirv_.data(), spirv_.size());
|
|
EXPECT_EQ(code_compare, 0);
|
|
}
|
|
TEST(SpirvReflectTestCase, GetCode_Errors) {
|
|
// NULL module
|
|
EXPECT_EQ(spvReflectGetCode(nullptr), nullptr);
|
|
}
|
|
|
|
TEST_P(SpirvReflectTest, GetDescriptorBinding) {
|
|
uint32_t binding_count = 0;
|
|
SpvReflectResult result;
|
|
result =
|
|
spvReflectEnumerateDescriptorBindings(&module_, &binding_count, nullptr);
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
std::vector<SpvReflectDescriptorBinding*> bindings(binding_count);
|
|
result = spvReflectEnumerateDescriptorBindings(&module_, &binding_count,
|
|
bindings.data());
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
|
|
for (const auto* db : bindings) {
|
|
const SpvReflectDescriptorBinding* also_db =
|
|
spvReflectGetDescriptorBinding(&module_, db->binding, db->set, &result);
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
EXPECT_EQ(db, also_db);
|
|
}
|
|
}
|
|
TEST_P(SpirvReflectTest, EnumerateDescriptorBindings_Errors) {
|
|
uint32_t binding_count = 0;
|
|
// NULL module
|
|
EXPECT_EQ(
|
|
spvReflectEnumerateDescriptorBindings(nullptr, &binding_count, nullptr),
|
|
SPV_REFLECT_RESULT_ERROR_NULL_POINTER);
|
|
// NULL binding count
|
|
EXPECT_EQ(spvReflectEnumerateDescriptorBindings(&module_, nullptr, nullptr),
|
|
SPV_REFLECT_RESULT_ERROR_NULL_POINTER);
|
|
// binding count / module binding count mismatch
|
|
EXPECT_EQ(
|
|
spvReflectEnumerateDescriptorBindings(&module_, &binding_count, nullptr),
|
|
SPV_REFLECT_RESULT_SUCCESS);
|
|
uint32_t bad_binding_count = binding_count + 1;
|
|
std::vector<SpvReflectDescriptorBinding*> bindings(bad_binding_count);
|
|
EXPECT_EQ(spvReflectEnumerateDescriptorBindings(&module_, &bad_binding_count,
|
|
bindings.data()),
|
|
SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH);
|
|
}
|
|
TEST_P(SpirvReflectTest, GetDescriptorBinding_Errors) {
|
|
SpvReflectResult result;
|
|
// NULL module
|
|
EXPECT_EQ(spvReflectGetDescriptorBinding(nullptr, 0, 0, nullptr), nullptr);
|
|
EXPECT_EQ(spvReflectGetDescriptorBinding(nullptr, 0, 0, &result), nullptr);
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_NULL_POINTER);
|
|
// Invalid binding number
|
|
EXPECT_EQ(spvReflectGetDescriptorBinding(&module_, 0xdeadbeef, 0, nullptr),
|
|
nullptr);
|
|
EXPECT_EQ(spvReflectGetDescriptorBinding(&module_, 0xdeadbeef, 0, &result),
|
|
nullptr);
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
|
|
// Invalid set number
|
|
EXPECT_EQ(spvReflectGetDescriptorBinding(&module_, 0, 0xdeadbeef, nullptr),
|
|
nullptr);
|
|
EXPECT_EQ(spvReflectGetDescriptorBinding(&module_, 0, 0xdeadbeef, &result),
|
|
nullptr);
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
|
|
}
|
|
|
|
TEST_P(SpirvReflectTest, GetDescriptorSet) {
|
|
uint32_t set_count = 0;
|
|
SpvReflectResult result;
|
|
result = spvReflectEnumerateDescriptorSets(&module_, &set_count, nullptr);
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
std::vector<SpvReflectDescriptorSet*> sets(set_count);
|
|
result = spvReflectEnumerateDescriptorSets(&module_, &set_count, sets.data());
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
|
|
for (const auto* ds : sets) {
|
|
const SpvReflectDescriptorSet* also_ds =
|
|
spvReflectGetDescriptorSet(&module_, ds->set, &result);
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
EXPECT_EQ(ds, also_ds);
|
|
}
|
|
}
|
|
TEST_P(SpirvReflectTest, EnumerateDescriptorSets_Errors) {
|
|
uint32_t set_count = 0;
|
|
// NULL module
|
|
EXPECT_EQ(spvReflectEnumerateDescriptorSets(nullptr, &set_count, nullptr),
|
|
SPV_REFLECT_RESULT_ERROR_NULL_POINTER);
|
|
// NULL set count
|
|
EXPECT_EQ(spvReflectEnumerateDescriptorSets(&module_, nullptr, nullptr),
|
|
SPV_REFLECT_RESULT_ERROR_NULL_POINTER);
|
|
// set count / module set count mismatch
|
|
EXPECT_EQ(spvReflectEnumerateDescriptorSets(&module_, &set_count, nullptr),
|
|
SPV_REFLECT_RESULT_SUCCESS);
|
|
uint32_t bad_set_count = set_count + 1;
|
|
std::vector<SpvReflectDescriptorSet*> sets(bad_set_count);
|
|
EXPECT_EQ(
|
|
spvReflectEnumerateDescriptorSets(&module_, &bad_set_count, sets.data()),
|
|
SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH);
|
|
}
|
|
TEST_P(SpirvReflectTest, GetDescriptorSet_Errors) {
|
|
SpvReflectResult result;
|
|
// NULL module
|
|
EXPECT_EQ(spvReflectGetDescriptorSet(nullptr, 0, nullptr), nullptr);
|
|
EXPECT_EQ(spvReflectGetDescriptorSet(nullptr, 0, &result), nullptr);
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_NULL_POINTER);
|
|
// Invalid set number
|
|
EXPECT_EQ(spvReflectGetDescriptorSet(&module_, 0xdeadbeef, nullptr), nullptr);
|
|
EXPECT_EQ(spvReflectGetDescriptorSet(&module_, 0xdeadbeef, &result), nullptr);
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
|
|
}
|
|
|
|
TEST_P(SpirvReflectTest, GetInputVariableByLocation) {
|
|
uint32_t iv_count = 0;
|
|
SpvReflectResult result;
|
|
result = spvReflectEnumerateInputVariables(&module_, &iv_count, nullptr);
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
std::vector<SpvReflectInterfaceVariable*> ivars(iv_count);
|
|
result = spvReflectEnumerateInputVariables(&module_, &iv_count, ivars.data());
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
|
|
for (const auto* iv : ivars) {
|
|
const SpvReflectInterfaceVariable* also_iv =
|
|
spvReflectGetInputVariableByLocation(&module_, iv->location, &result);
|
|
if (iv->location == UINT32_MAX) {
|
|
// Not all elements have valid locations.
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
|
|
EXPECT_EQ(also_iv, nullptr);
|
|
} else {
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
EXPECT_EQ(iv, also_iv);
|
|
}
|
|
}
|
|
}
|
|
TEST_P(SpirvReflectTest, EnumerateInputVariables_Errors) {
|
|
uint32_t var_count = 0;
|
|
// NULL module
|
|
EXPECT_EQ(spvReflectEnumerateInputVariables(nullptr, &var_count, nullptr),
|
|
SPV_REFLECT_RESULT_ERROR_NULL_POINTER);
|
|
// NULL var count
|
|
EXPECT_EQ(spvReflectEnumerateInputVariables(&module_, nullptr, nullptr),
|
|
SPV_REFLECT_RESULT_ERROR_NULL_POINTER);
|
|
// var count / module var count mismatch
|
|
EXPECT_EQ(spvReflectEnumerateInputVariables(&module_, &var_count, nullptr),
|
|
SPV_REFLECT_RESULT_SUCCESS);
|
|
uint32_t bad_var_count = var_count + 1;
|
|
std::vector<SpvReflectInterfaceVariable*> vars(bad_var_count);
|
|
EXPECT_EQ(
|
|
spvReflectEnumerateInputVariables(&module_, &bad_var_count, vars.data()),
|
|
SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH);
|
|
}
|
|
TEST_P(SpirvReflectTest, GetInputVariableByLocation_Errors) {
|
|
SpvReflectResult result;
|
|
// NULL module
|
|
EXPECT_EQ(spvReflectGetInputVariableByLocation(nullptr, 0, nullptr), nullptr);
|
|
EXPECT_EQ(spvReflectGetInputVariableByLocation(nullptr, 0, &result), nullptr);
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_NULL_POINTER);
|
|
// explicitly invalid location (UINT32_MAX is *always* not found)
|
|
EXPECT_EQ(spvReflectGetInputVariableByLocation(&module_, UINT32_MAX, nullptr),
|
|
nullptr);
|
|
EXPECT_EQ(spvReflectGetInputVariableByLocation(&module_, UINT32_MAX, &result),
|
|
nullptr);
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
|
|
// implicitly invalid location (0xdeadbeef is potentially valid)
|
|
EXPECT_EQ(spvReflectGetInputVariableByLocation(&module_, 0xdeadbeef, nullptr),
|
|
nullptr);
|
|
EXPECT_EQ(spvReflectGetInputVariableByLocation(&module_, 0xdeadbeef, &result),
|
|
nullptr);
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
|
|
}
|
|
|
|
TEST_P(SpirvReflectTest, GetInputVariableBySemantic) {
|
|
uint32_t iv_count = 0;
|
|
SpvReflectResult result;
|
|
result = spvReflectEnumerateInputVariables(&module_, &iv_count, nullptr);
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
std::vector<SpvReflectInterfaceVariable*> ivars(iv_count);
|
|
result = spvReflectEnumerateInputVariables(&module_, &iv_count, ivars.data());
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
|
|
for (const auto* iv : ivars) {
|
|
const SpvReflectInterfaceVariable* also_iv =
|
|
spvReflectGetInputVariableBySemantic(&module_, iv->semantic, &result);
|
|
if (iv->semantic == nullptr) {
|
|
// Not all elements have valid semantics
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_NULL_POINTER);
|
|
EXPECT_EQ(also_iv, nullptr);
|
|
} else if (iv->semantic[0] == '\0') {
|
|
// Not all elements have valid semantics
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
|
|
EXPECT_EQ(also_iv, nullptr);
|
|
} else {
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
EXPECT_EQ(iv, also_iv);
|
|
}
|
|
}
|
|
}
|
|
TEST_P(SpirvReflectTest, GetInputVariableBySemantic_Errors) {
|
|
SpvReflectResult result;
|
|
// NULL module
|
|
EXPECT_EQ(spvReflectGetInputVariableBySemantic(nullptr, nullptr, nullptr),
|
|
nullptr);
|
|
EXPECT_EQ(spvReflectGetInputVariableBySemantic(nullptr, nullptr, &result),
|
|
nullptr);
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_NULL_POINTER);
|
|
// NULL semantic
|
|
EXPECT_EQ(spvReflectGetInputVariableBySemantic(&module_, nullptr, nullptr),
|
|
nullptr);
|
|
EXPECT_EQ(spvReflectGetInputVariableBySemantic(&module_, nullptr, &result),
|
|
nullptr);
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_NULL_POINTER);
|
|
// empty semantic ("" is explicitly not found)
|
|
EXPECT_EQ(spvReflectGetInputVariableBySemantic(&module_, "", nullptr),
|
|
nullptr);
|
|
EXPECT_EQ(spvReflectGetInputVariableBySemantic(&module_, "", &result),
|
|
nullptr);
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
|
|
// implicitly invalid semantic
|
|
EXPECT_EQ(spvReflectGetInputVariableBySemantic(
|
|
&module_, "SV_PLAUSIBLE_BUT_INVALID", nullptr),
|
|
nullptr);
|
|
EXPECT_EQ(spvReflectGetInputVariableBySemantic(
|
|
&module_, "SV_PLAUSIBLE_BUT_INVALID", &result),
|
|
nullptr);
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
|
|
}
|
|
|
|
TEST_P(SpirvReflectTest, GetOutputVariableByLocation) {
|
|
uint32_t ov_count = 0;
|
|
SpvReflectResult result;
|
|
result = spvReflectEnumerateOutputVariables(&module_, &ov_count, nullptr);
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
std::vector<SpvReflectInterfaceVariable*> ovars(ov_count);
|
|
result =
|
|
spvReflectEnumerateOutputVariables(&module_, &ov_count, ovars.data());
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
|
|
for (const auto* ov : ovars) {
|
|
const SpvReflectInterfaceVariable* also_ov =
|
|
spvReflectGetOutputVariableByLocation(&module_, ov->location, &result);
|
|
if (ov->location == UINT32_MAX) {
|
|
// Not all elements have valid locations.
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
|
|
EXPECT_EQ(also_ov, nullptr);
|
|
} else {
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
EXPECT_EQ(ov, also_ov);
|
|
}
|
|
}
|
|
}
|
|
TEST_P(SpirvReflectTest, EnumerateOutputVariables_Errors) {
|
|
uint32_t var_count = 0;
|
|
// NULL module
|
|
EXPECT_EQ(spvReflectEnumerateOutputVariables(nullptr, &var_count, nullptr),
|
|
SPV_REFLECT_RESULT_ERROR_NULL_POINTER);
|
|
// NULL var count
|
|
EXPECT_EQ(spvReflectEnumerateOutputVariables(&module_, nullptr, nullptr),
|
|
SPV_REFLECT_RESULT_ERROR_NULL_POINTER);
|
|
// var count / module var count mismatch
|
|
EXPECT_EQ(spvReflectEnumerateOutputVariables(&module_, &var_count, nullptr),
|
|
SPV_REFLECT_RESULT_SUCCESS);
|
|
uint32_t bad_var_count = var_count + 1;
|
|
std::vector<SpvReflectInterfaceVariable*> vars(bad_var_count);
|
|
EXPECT_EQ(
|
|
spvReflectEnumerateOutputVariables(&module_, &bad_var_count, vars.data()),
|
|
SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH);
|
|
}
|
|
TEST_P(SpirvReflectTest, GetOutputVariableByLocation_Errors) {
|
|
SpvReflectResult result;
|
|
// NULL module
|
|
EXPECT_EQ(spvReflectGetOutputVariableByLocation(nullptr, 0, nullptr),
|
|
nullptr);
|
|
EXPECT_EQ(spvReflectGetOutputVariableByLocation(nullptr, 0, &result),
|
|
nullptr);
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_NULL_POINTER);
|
|
// explicitly invalid location (UINT32_MAX is *always* not found)
|
|
EXPECT_EQ(
|
|
spvReflectGetOutputVariableByLocation(&module_, UINT32_MAX, nullptr),
|
|
nullptr);
|
|
EXPECT_EQ(
|
|
spvReflectGetOutputVariableByLocation(&module_, UINT32_MAX, &result),
|
|
nullptr);
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
|
|
// implicitly invalid location (0xdeadbeef is potentially valid)
|
|
EXPECT_EQ(
|
|
spvReflectGetOutputVariableByLocation(&module_, 0xdeadbeef, nullptr),
|
|
nullptr);
|
|
EXPECT_EQ(
|
|
spvReflectGetOutputVariableByLocation(&module_, 0xdeadbeef, &result),
|
|
nullptr);
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
|
|
}
|
|
|
|
TEST_P(SpirvReflectTest, GetOutputVariableBySemantic) {
|
|
uint32_t ov_count = 0;
|
|
SpvReflectResult result;
|
|
result = spvReflectEnumerateOutputVariables(&module_, &ov_count, nullptr);
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
std::vector<SpvReflectInterfaceVariable*> ovars(ov_count);
|
|
result =
|
|
spvReflectEnumerateOutputVariables(&module_, &ov_count, ovars.data());
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
|
|
for (const auto* ov : ovars) {
|
|
const SpvReflectInterfaceVariable* also_ov =
|
|
spvReflectGetOutputVariableBySemantic(&module_, ov->semantic, &result);
|
|
if (ov->semantic == nullptr) {
|
|
// Not all elements have valid semantics
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_NULL_POINTER);
|
|
EXPECT_EQ(also_ov, nullptr);
|
|
} else if (ov->semantic[0] == '\0') {
|
|
// Not all elements have valid semantics
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
|
|
EXPECT_EQ(also_ov, nullptr);
|
|
} else {
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
EXPECT_EQ(ov, also_ov);
|
|
}
|
|
}
|
|
}
|
|
TEST_P(SpirvReflectTest, GetOutputVariableBySemantic_Errors) {
|
|
SpvReflectResult result;
|
|
// NULL module
|
|
EXPECT_EQ(spvReflectGetOutputVariableBySemantic(nullptr, nullptr, nullptr),
|
|
nullptr);
|
|
EXPECT_EQ(spvReflectGetOutputVariableBySemantic(nullptr, nullptr, &result),
|
|
nullptr);
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_NULL_POINTER);
|
|
// NULL semantic
|
|
EXPECT_EQ(spvReflectGetOutputVariableBySemantic(&module_, nullptr, nullptr),
|
|
nullptr);
|
|
EXPECT_EQ(spvReflectGetOutputVariableBySemantic(&module_, nullptr, &result),
|
|
nullptr);
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_NULL_POINTER);
|
|
// empty semantic ("" is explicitly not found)
|
|
EXPECT_EQ(spvReflectGetOutputVariableBySemantic(&module_, "", nullptr),
|
|
nullptr);
|
|
EXPECT_EQ(spvReflectGetOutputVariableBySemantic(&module_, "", &result),
|
|
nullptr);
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
|
|
// implicitly invalid semantic
|
|
EXPECT_EQ(spvReflectGetOutputVariableBySemantic(
|
|
&module_, "SV_PLAUSIBLE_BUT_INVALID", nullptr),
|
|
nullptr);
|
|
EXPECT_EQ(spvReflectGetOutputVariableBySemantic(
|
|
&module_, "SV_PLAUSIBLE_BUT_INVALID", &result),
|
|
nullptr);
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
|
|
}
|
|
|
|
TEST_P(SpirvReflectTest, GetPushConstantBlock) {
|
|
uint32_t block_count = 0;
|
|
SpvReflectResult result;
|
|
result =
|
|
spvReflectEnumeratePushConstantBlocks(&module_, &block_count, nullptr);
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
std::vector<SpvReflectBlockVariable*> blocks(block_count);
|
|
result = spvReflectEnumeratePushConstantBlocks(&module_, &block_count,
|
|
blocks.data());
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
|
|
for (uint32_t i = 0; i < block_count; ++i) {
|
|
const SpvReflectBlockVariable* b = blocks[i];
|
|
const SpvReflectBlockVariable* also_b =
|
|
spvReflectGetPushConstantBlock(&module_, i, &result);
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
EXPECT_EQ(b, also_b);
|
|
}
|
|
}
|
|
TEST_P(SpirvReflectTest, EnumeratePushConstantBlocks_Errors) {
|
|
uint32_t block_count = 0;
|
|
// NULL module
|
|
EXPECT_EQ(
|
|
spvReflectEnumeratePushConstantBlocks(nullptr, &block_count, nullptr),
|
|
SPV_REFLECT_RESULT_ERROR_NULL_POINTER);
|
|
// NULL var count
|
|
EXPECT_EQ(spvReflectEnumeratePushConstantBlocks(&module_, nullptr, nullptr),
|
|
SPV_REFLECT_RESULT_ERROR_NULL_POINTER);
|
|
// var count / module var count mismatch
|
|
EXPECT_EQ(
|
|
spvReflectEnumeratePushConstantBlocks(&module_, &block_count, nullptr),
|
|
SPV_REFLECT_RESULT_SUCCESS);
|
|
uint32_t bad_block_count = block_count + 1;
|
|
std::vector<SpvReflectBlockVariable*> blocks(bad_block_count);
|
|
EXPECT_EQ(spvReflectEnumeratePushConstantBlocks(&module_, &bad_block_count,
|
|
blocks.data()),
|
|
SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH);
|
|
}
|
|
TEST_P(SpirvReflectTest, GetPushConstantBlock_Errors) {
|
|
uint32_t block_count = 0;
|
|
SpvReflectResult result;
|
|
result =
|
|
spvReflectEnumeratePushConstantBlocks(&module_, &block_count, nullptr);
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
// NULL module
|
|
EXPECT_EQ(spvReflectGetPushConstantBlock(nullptr, 0, nullptr), nullptr);
|
|
EXPECT_EQ(spvReflectGetPushConstantBlock(nullptr, 0, &result), nullptr);
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_NULL_POINTER);
|
|
// invalid block index
|
|
EXPECT_EQ(spvReflectGetPushConstantBlock(&module_, block_count, nullptr),
|
|
nullptr);
|
|
EXPECT_EQ(spvReflectGetPushConstantBlock(&module_, block_count, &result),
|
|
nullptr);
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
|
|
}
|
|
|
|
TEST_P(SpirvReflectTest, ChangeDescriptorBindingNumber) {
|
|
uint32_t binding_count = 0;
|
|
SpvReflectResult result;
|
|
result =
|
|
spvReflectEnumerateDescriptorBindings(&module_, &binding_count, nullptr);
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
if (binding_count == 0) {
|
|
return; // can't change binding numbers if there are no bindings!
|
|
}
|
|
std::vector<SpvReflectDescriptorBinding*> bindings(binding_count);
|
|
result = spvReflectEnumerateDescriptorBindings(&module_, &binding_count,
|
|
bindings.data());
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
|
|
uint32_t set_count = 0;
|
|
result = spvReflectEnumerateDescriptorSets(&module_, &set_count, nullptr);
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
EXPECT_GT(set_count, 0U);
|
|
std::vector<SpvReflectDescriptorSet*> sets(set_count);
|
|
result = spvReflectEnumerateDescriptorSets(&module_, &set_count, sets.data());
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
|
|
SpvReflectDescriptorBinding* b = bindings[0];
|
|
const uint32_t new_binding_number = 1000;
|
|
const uint32_t set_number = b->set;
|
|
// Make sure no binding exists at the binding number we're about to change to.
|
|
ASSERT_EQ(spvReflectGetDescriptorBinding(&module_, new_binding_number,
|
|
set_number, &result),
|
|
nullptr);
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
|
|
// Modify the binding number (leaving the set number unchanged)
|
|
result = spvReflectChangeDescriptorBindingNumbers(
|
|
&module_, b, new_binding_number, SPV_REFLECT_SET_NUMBER_DONT_CHANGE);
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
// We should now be able to retrieve the binding at the new number
|
|
const SpvReflectDescriptorBinding* new_binding =
|
|
spvReflectGetDescriptorBinding(&module_, new_binding_number, set_number,
|
|
&result);
|
|
ASSERT_NE(new_binding, nullptr);
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
EXPECT_EQ(new_binding->binding, new_binding_number);
|
|
EXPECT_EQ(new_binding->set, set_number);
|
|
// The set count & sets contents should not have changed, since we didn't
|
|
// change the set number.
|
|
result = spvReflectEnumerateDescriptorSets(&module_, &set_count, nullptr);
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
EXPECT_EQ(set_count, sets.size());
|
|
std::vector<SpvReflectDescriptorSet*> new_sets(set_count);
|
|
result =
|
|
spvReflectEnumerateDescriptorSets(&module_, &set_count, new_sets.data());
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
EXPECT_EQ(sets, new_sets);
|
|
|
|
// TODO: confirm that the modified SPIR-V code is still valid, either by
|
|
// running spirv-val or calling vkCreateShaderModule().
|
|
}
|
|
TEST_P(SpirvReflectTest, ChangeDescriptorBindingNumbers_Errors) {
|
|
// NULL module
|
|
EXPECT_EQ(spvReflectChangeDescriptorBindingNumbers(nullptr, nullptr, 0, 0),
|
|
SPV_REFLECT_RESULT_ERROR_NULL_POINTER);
|
|
// NULL descriptor binding
|
|
EXPECT_EQ(spvReflectChangeDescriptorBindingNumbers(&module_, nullptr, 0, 0),
|
|
SPV_REFLECT_RESULT_ERROR_NULL_POINTER);
|
|
}
|
|
|
|
TEST_P(SpirvReflectTest, ChangeDescriptorSetNumber) {
|
|
uint32_t binding_count = 0;
|
|
SpvReflectResult result;
|
|
result =
|
|
spvReflectEnumerateDescriptorBindings(&module_, &binding_count, nullptr);
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
if (binding_count == 0) {
|
|
return; // can't change set numbers if there are no bindings!
|
|
}
|
|
std::vector<SpvReflectDescriptorBinding*> bindings(binding_count);
|
|
result = spvReflectEnumerateDescriptorBindings(&module_, &binding_count,
|
|
bindings.data());
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
|
|
uint32_t set_count = 0;
|
|
result = spvReflectEnumerateDescriptorSets(&module_, &set_count, nullptr);
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
EXPECT_GT(set_count, 0U);
|
|
std::vector<SpvReflectDescriptorSet*> sets(set_count);
|
|
result = spvReflectEnumerateDescriptorSets(&module_, &set_count, sets.data());
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
|
|
SpvReflectDescriptorSet* s = sets[0];
|
|
|
|
const uint32_t new_set_number = 13;
|
|
const uint32_t set_binding_count = s->binding_count;
|
|
// Make sure no set exists at the binding number we're about to change to.
|
|
ASSERT_EQ(spvReflectGetDescriptorSet(&module_, new_set_number, &result),
|
|
nullptr);
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
|
|
// Modify the set number
|
|
result = spvReflectChangeDescriptorSetNumber(&module_, s, new_set_number);
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
// We should now be able to retrieve the set at the new number
|
|
const SpvReflectDescriptorSet* new_set =
|
|
spvReflectGetDescriptorSet(&module_, new_set_number, &result);
|
|
ASSERT_NE(new_set, nullptr);
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
EXPECT_EQ(new_set->set, new_set_number);
|
|
EXPECT_EQ(new_set->binding_count, set_binding_count);
|
|
// The set count should not have changed, since we didn't
|
|
// change the set number.
|
|
result = spvReflectEnumerateDescriptorSets(&module_, &set_count, nullptr);
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
EXPECT_EQ(set_count, sets.size());
|
|
|
|
// TODO: confirm that the modified SPIR-V code is still valid, either by
|
|
// running spirv-val or calling vkCreateShaderModule().
|
|
}
|
|
TEST_P(SpirvReflectTest, ChangeDescriptorSetNumber_Errors) {
|
|
// NULL module
|
|
EXPECT_EQ(spvReflectChangeDescriptorSetNumber(nullptr, nullptr, 0),
|
|
SPV_REFLECT_RESULT_ERROR_NULL_POINTER);
|
|
// NULL descriptor set
|
|
EXPECT_EQ(spvReflectChangeDescriptorSetNumber(&module_, nullptr, 0),
|
|
SPV_REFLECT_RESULT_ERROR_NULL_POINTER);
|
|
}
|
|
|
|
TEST_P(SpirvReflectTest, ChangeInputVariableLocation) {
|
|
uint32_t iv_count = 0;
|
|
SpvReflectResult result;
|
|
result = spvReflectEnumerateInputVariables(&module_, &iv_count, nullptr);
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
if (iv_count == 0) {
|
|
return; // can't change variable locations if there are no variables!
|
|
}
|
|
std::vector<SpvReflectInterfaceVariable*> ivars(iv_count);
|
|
result = spvReflectEnumerateInputVariables(&module_, &iv_count, ivars.data());
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
|
|
SpvReflectInterfaceVariable* iv = ivars[0];
|
|
|
|
const uint32_t new_location = 37;
|
|
// Make sure no var exists at the location we're about to change to.
|
|
ASSERT_EQ(
|
|
spvReflectGetInputVariableByLocation(&module_, new_location, &result),
|
|
nullptr);
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
|
|
// Modify the location
|
|
result = spvReflectChangeInputVariableLocation(&module_, iv, new_location);
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
// We should now be able to retrieve the variable at its new location
|
|
const SpvReflectInterfaceVariable* new_iv =
|
|
spvReflectGetInputVariableByLocation(&module_, new_location, &result);
|
|
ASSERT_NE(new_iv, nullptr);
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
EXPECT_EQ(new_iv->location, new_location);
|
|
// The variable count should not have changed
|
|
result = spvReflectEnumerateInputVariables(&module_, &iv_count, nullptr);
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
EXPECT_EQ(iv_count, ivars.size());
|
|
|
|
// TODO: confirm that the modified SPIR-V code is still valid, either by
|
|
// running spirv-val or calling vkCreateShaderModule().
|
|
}
|
|
TEST_P(SpirvReflectTest, ChangeInputVariableLocation_Errors) {
|
|
// NULL module
|
|
EXPECT_EQ(spvReflectChangeInputVariableLocation(nullptr, nullptr, 0),
|
|
SPV_REFLECT_RESULT_ERROR_NULL_POINTER);
|
|
// NULL variable
|
|
EXPECT_EQ(spvReflectChangeInputVariableLocation(&module_, nullptr, 0),
|
|
SPV_REFLECT_RESULT_ERROR_NULL_POINTER);
|
|
}
|
|
|
|
TEST_P(SpirvReflectTest, ChangeOutputVariableLocation) {
|
|
uint32_t ov_count = 0;
|
|
SpvReflectResult result;
|
|
result = spvReflectEnumerateOutputVariables(&module_, &ov_count, nullptr);
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
if (ov_count == 0) {
|
|
return; // can't change variable locations if there are no variables!
|
|
}
|
|
std::vector<SpvReflectInterfaceVariable*> ovars(ov_count);
|
|
result =
|
|
spvReflectEnumerateOutputVariables(&module_, &ov_count, ovars.data());
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
|
|
SpvReflectInterfaceVariable* ov = ovars[0];
|
|
|
|
const uint32_t new_location = 37;
|
|
// Make sure no var exists at the location we're about to change to.
|
|
ASSERT_EQ(
|
|
spvReflectGetOutputVariableByLocation(&module_, new_location, &result),
|
|
nullptr);
|
|
EXPECT_EQ(result, SPV_REFLECT_RESULT_ERROR_ELEMENT_NOT_FOUND);
|
|
// Modify the location
|
|
result = spvReflectChangeOutputVariableLocation(&module_, ov, new_location);
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
// We should now be able to retrieve the variable at its new location
|
|
const SpvReflectInterfaceVariable* new_ov =
|
|
spvReflectGetOutputVariableByLocation(&module_, new_location, &result);
|
|
ASSERT_NE(new_ov, nullptr);
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
EXPECT_EQ(new_ov->location, new_location);
|
|
// The variable count should not have changed
|
|
result = spvReflectEnumerateOutputVariables(&module_, &ov_count, nullptr);
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
EXPECT_EQ(ov_count, ovars.size());
|
|
|
|
// TODO: confirm that the modified SPIR-V code is still valid, either by
|
|
// running spirv-val or calling vkCreateShaderModule().
|
|
}
|
|
TEST_P(SpirvReflectTest, ChangeOutputVariableLocation_Errors) {
|
|
// NULL module
|
|
EXPECT_EQ(spvReflectChangeOutputVariableLocation(nullptr, nullptr, 0),
|
|
SPV_REFLECT_RESULT_ERROR_NULL_POINTER);
|
|
// NULL variable
|
|
EXPECT_EQ(spvReflectChangeOutputVariableLocation(&module_, nullptr, 0),
|
|
SPV_REFLECT_RESULT_ERROR_NULL_POINTER);
|
|
}
|
|
|
|
TEST_P(SpirvReflectTest, CheckYamlOutput) {
|
|
const uint32_t yaml_verbosity = 1;
|
|
SpvReflectToYaml yamlizer(module_, yaml_verbosity);
|
|
std::stringstream test_yaml;
|
|
test_yaml << yamlizer;
|
|
std::string test_yaml_str = test_yaml.str();
|
|
|
|
std::string golden_yaml_path = spirv_path_ + ".yaml";
|
|
std::ifstream golden_yaml_file(golden_yaml_path);
|
|
ASSERT_TRUE(golden_yaml_file.good());
|
|
std::stringstream golden_yaml;
|
|
golden_yaml << golden_yaml_file.rdbuf();
|
|
golden_yaml_file.close();
|
|
std::string golden_yaml_str = golden_yaml.str();
|
|
|
|
// Quick workaround for potential line ending differences, perf be damned!
|
|
test_yaml_str = std::regex_replace(test_yaml_str, std::regex("\r"), "");
|
|
golden_yaml_str = std::regex_replace(golden_yaml_str, std::regex("\r"), "");
|
|
|
|
ASSERT_EQ(test_yaml_str.size(), golden_yaml_str.size());
|
|
// TODO: I wish there were a better way to show what changed, but the
|
|
// differences (if any) tend to be pretty large, even for small changes.
|
|
bool yaml_contents_match = (test_yaml_str == golden_yaml_str);
|
|
EXPECT_TRUE(yaml_contents_match)
|
|
<< "YAML output mismatch; try regenerating the golden YAML with "
|
|
"\"tests/build_golden_yaml.py\" and see what changed.";
|
|
}
|
|
|
|
namespace {
|
|
// TODO - have this glob search all .spv files
|
|
const std::vector<const char*> all_spirv_paths = {
|
|
// clang-format off
|
|
"../tests/16bit/vert_in_out_16.spv",
|
|
"../tests/access_chains/array_length_from_access_chain.spv",
|
|
"../tests/access_chains/pointer_access_chain_phy_storage_buffer.spv",
|
|
"../tests/cbuffer_unused/cbuffer_unused_001.spv",
|
|
"../tests/glsl/built_in_format.spv",
|
|
"../tests/entry_exec_mode/comp_local_size.spv",
|
|
"../tests/entry_exec_mode/geom_inv_out_vert.spv",
|
|
"../tests/execution_mode/local_size_id_spec.spv",
|
|
"../tests/execution_mode/local_size_id.spv",
|
|
"../tests/glsl/buffer_handle_0.spv",
|
|
"../tests/glsl/buffer_handle_1.spv",
|
|
"../tests/glsl/buffer_handle_2.spv",
|
|
"../tests/glsl/buffer_handle_3.spv",
|
|
"../tests/glsl/buffer_handle_4.spv",
|
|
"../tests/glsl/buffer_handle_5.spv",
|
|
"../tests/glsl/buffer_handle_6.spv",
|
|
"../tests/glsl/buffer_handle_7.spv",
|
|
"../tests/glsl/buffer_handle_8.spv",
|
|
"../tests/glsl/buffer_handle_9.spv",
|
|
"../tests/glsl/buffer_handle_uvec2_pc.spv",
|
|
"../tests/glsl/buffer_handle_uvec2_ssbo.spv",
|
|
"../tests/glsl/buffer_pointer.spv",
|
|
"../tests/glsl/built_in_format.spv",
|
|
"../tests/glsl/fn_struct_param.spv",
|
|
"../tests/glsl/frag_array_input.spv",
|
|
"../tests/glsl/frag_barycentric.spv",
|
|
"../tests/glsl/input_attachment.spv",
|
|
"../tests/glsl/io_vars_vs.spv",
|
|
"../tests/glsl/matrix_major_order_glsl.spv",
|
|
"../tests/glsl/non_writable_image.spv",
|
|
"../tests/glsl/readonly_writeonly.spv",
|
|
"../tests/glsl/runtime_array_of_array_of_struct.spv",
|
|
"../tests/glsl/storage_buffer.spv",
|
|
"../tests/glsl/texel_buffer.spv",
|
|
"../tests/hlsl/append_consume.spv",
|
|
"../tests/hlsl/array_of_structured_buffer.spv",
|
|
"../tests/hlsl/binding_array.spv",
|
|
"../tests/hlsl/binding_types.spv",
|
|
"../tests/hlsl/cbuffer.spv",
|
|
"../tests/hlsl/constantbuffer.spv",
|
|
"../tests/hlsl/constantbuffer_nested_structs.spv",
|
|
"../tests/hlsl/counter_buffers.spv",
|
|
"../tests/hlsl/localsize.spv",
|
|
"../tests/hlsl/matrix_major_order_hlsl.spv",
|
|
"../tests/hlsl/pushconstant.spv",
|
|
"../tests/hlsl/semantics.spv",
|
|
"../tests/hlsl/structuredbuffer.spv",
|
|
"../tests/hlsl/user_type.spv",
|
|
"../tests/interface/geom_input_builtin_array.spv",
|
|
"../tests/interface/vertex_input_builtin_block.spv",
|
|
"../tests/interface/vertex_input_builtin_non_block.spv",
|
|
"../tests/issues/77/hlsl/array_from_ubo.spv",
|
|
"../tests/issues/77/hlsl/array_from_ubo_with_O0.spv",
|
|
"../tests/issues/77/hlsl/rocketz.spv",
|
|
"../tests/issues/102/function_parameter_access.spv",
|
|
"../tests/issues/178/vertex_input_struct.spv",
|
|
"../tests/issues/178/vertex_input_struct2.spv",
|
|
"../tests/issues/227/null_node.spv",
|
|
"../tests/mesh_shader_ext/mesh_shader_ext.task.hlsl.spv",
|
|
"../tests/mesh_shader_ext/mesh_shader_ext.mesh.hlsl.spv",
|
|
"../tests/multi_entrypoint/multi_entrypoint.spv",
|
|
"../tests/push_constants/non_zero_block_offset.spv",
|
|
"../tests/push_constants/pointer_in_struct.spv",
|
|
"../tests/push_constants/pointer_in_struct_2.spv",
|
|
"../tests/push_constants/push_constant_basic_0.spv",
|
|
"../tests/push_constants/push_constant_basic_1.spv",
|
|
"../tests/push_constants/push_constant_basic_2.spv",
|
|
"../tests/push_constants/push_constant_basic_3.spv",
|
|
"../tests/raytrace/rayquery_equal.cs.spv",
|
|
"../tests/raytrace/rayquery_init_ds.spv",
|
|
"../tests/raytrace/rayquery_init_gs.spv",
|
|
"../tests/raytrace/rayquery_init_hs.spv",
|
|
"../tests/raytrace/rayquery_init_ps.spv",
|
|
"../tests/raytrace/rayquery_init_rahit.spv",
|
|
"../tests/raytrace/rayquery_init_rcall.spv",
|
|
"../tests/raytrace/rayquery_init_rchit.spv",
|
|
"../tests/raytrace/rayquery_init_rgen.spv",
|
|
"../tests/raytrace/rayquery_init_rmiss.spv",
|
|
"../tests/raytrace/raytracing.acceleration-structure.spv",
|
|
"../tests/raytrace/raytracing.khr.closesthit.spv",
|
|
"../tests/raytrace/raytracing.nv.acceleration-structure.spv",
|
|
"../tests/raytrace/raytracing.nv.anyhit.spv",
|
|
"../tests/raytrace/raytracing.nv.callable.spv",
|
|
"../tests/raytrace/raytracing.nv.closesthit.spv",
|
|
"../tests/raytrace/raytracing.nv.enum.spv",
|
|
"../tests/raytrace/raytracing.nv.intersection.spv",
|
|
"../tests/raytrace/raytracing.nv.library.spv",
|
|
"../tests/raytrace/raytracing.nv.miss.spv",
|
|
"../tests/raytrace/raytracing.nv.raygen.spv",
|
|
"../tests/spec_constants/basic.spv",
|
|
"../tests/spec_constants/convert.spv",
|
|
"../tests/spec_constants/local_size_id_10.spv",
|
|
"../tests/spec_constants/local_size_id_13.spv",
|
|
"../tests/spec_constants/ssbo_array.spv",
|
|
"../tests/spec_constants/test_32bit.spv",
|
|
"../tests/spec_constants/test_64bit.spv",
|
|
"../tests/spirv15/VertexShader.spv",
|
|
"../tests/user_type/byte_address_buffer_0.spv",
|
|
"../tests/user_type/byte_address_buffer_1.spv",
|
|
"../tests/user_type/byte_address_buffer_2.spv",
|
|
"../tests/user_type/byte_address_buffer_3.spv",
|
|
"../tests/user_type/rw_byte_address_buffer.spv",
|
|
"../tests/variable_access/atomics_0.spv",
|
|
"../tests/variable_access/atomics_1.spv",
|
|
"../tests/variable_access/copy_array_0.spv",
|
|
"../tests/variable_access/copy_array_1.spv",
|
|
"../tests/variable_access/copy_array_2.spv",
|
|
"../tests/variable_access/copy_array_3.spv",
|
|
"../tests/variable_access/copy_memory.spv",
|
|
"../tests/variable_access/copy_struct_0.spv",
|
|
"../tests/variable_access/copy_struct_1.spv",
|
|
"../tests/variable_access/descriptor_indexing_0.spv",
|
|
"../tests/variable_access/descriptor_indexing_1.spv",
|
|
"../tests/variable_access/phy_storage_buffer_used_0.spv",
|
|
"../tests/variable_access/phy_storage_buffer_used_1.spv",
|
|
"../tests/variable_access/phy_storage_buffer_used_2.spv",
|
|
"../tests/variable_access/phy_storage_buffer_used_3.spv",
|
|
// clang-format on
|
|
};
|
|
} // namespace
|
|
INSTANTIATE_TEST_CASE_P(ForAllShaders, SpirvReflectTest,
|
|
::testing::ValuesIn(all_spirv_paths));
|
|
|
|
TEST(SpirvReflectTestCase, TestComputeLocalSize) {
|
|
std::vector<uint8_t> spirv_;
|
|
SpvReflectShaderModule module_;
|
|
const std::string spirv_path = "../tests/entry_exec_mode/comp_local_size.spv";
|
|
std::ifstream spirv_file(spirv_path, std::ios::binary | std::ios::ate);
|
|
std::streampos spirv_file_nbytes = spirv_file.tellg();
|
|
spirv_file.seekg(0);
|
|
spirv_.resize(spirv_file_nbytes);
|
|
spirv_file.read(reinterpret_cast<char*>(spirv_.data()), spirv_.size());
|
|
|
|
SpvReflectResult result =
|
|
spvReflectCreateShaderModule(spirv_.size(), spirv_.data(), &module_);
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS, result)
|
|
<< "spvReflectCreateShaderModule() failed";
|
|
|
|
ASSERT_EQ(module_.entry_point_count, 1);
|
|
ASSERT_EQ(module_.entry_points[0].shader_stage,
|
|
SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT);
|
|
ASSERT_EQ(module_.entry_points[0].local_size.x, 1);
|
|
ASSERT_EQ(module_.entry_points[0].local_size.y, 1);
|
|
ASSERT_EQ(module_.entry_points[0].local_size.z, 1);
|
|
|
|
spvReflectDestroyShaderModule(&module_);
|
|
}
|
|
|
|
TEST(SpirvReflectTestCase, TestTaskShaderEXT) {
|
|
std::vector<uint8_t> spirv_;
|
|
SpvReflectShaderModule module_;
|
|
const std::string spirv_path =
|
|
"../tests/mesh_shader_ext/mesh_shader_ext.task.hlsl.spv";
|
|
std::ifstream spirv_file(spirv_path, std::ios::binary | std::ios::ate);
|
|
std::streampos spirv_file_nbytes = spirv_file.tellg();
|
|
spirv_file.seekg(0);
|
|
spirv_.resize(spirv_file_nbytes);
|
|
spirv_file.read(reinterpret_cast<char*>(spirv_.data()), spirv_.size());
|
|
|
|
SpvReflectResult result =
|
|
spvReflectCreateShaderModule(spirv_.size(), spirv_.data(), &module_);
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS, result)
|
|
<< "spvReflectCreateShaderModule() failed";
|
|
|
|
ASSERT_EQ(module_.entry_point_count, 1);
|
|
ASSERT_EQ(module_.entry_points[0].shader_stage,
|
|
SPV_REFLECT_SHADER_STAGE_TASK_BIT_EXT);
|
|
|
|
spvReflectDestroyShaderModule(&module_);
|
|
}
|
|
|
|
TEST(SpirvReflectTestCase, TestMeshShaderEXT) {
|
|
std::vector<uint8_t> spirv_;
|
|
SpvReflectShaderModule module_;
|
|
const std::string spirv_path =
|
|
"../tests/mesh_shader_ext/mesh_shader_ext.mesh.hlsl.spv";
|
|
std::ifstream spirv_file(spirv_path, std::ios::binary | std::ios::ate);
|
|
std::streampos spirv_file_nbytes = spirv_file.tellg();
|
|
spirv_file.seekg(0);
|
|
spirv_.resize(spirv_file_nbytes);
|
|
spirv_file.read(reinterpret_cast<char*>(spirv_.data()), spirv_.size());
|
|
|
|
SpvReflectResult result =
|
|
spvReflectCreateShaderModule(spirv_.size(), spirv_.data(), &module_);
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS, result)
|
|
<< "spvReflectCreateShaderModule() failed";
|
|
|
|
ASSERT_EQ(module_.entry_point_count, 1);
|
|
ASSERT_EQ(module_.entry_points[0].shader_stage,
|
|
SPV_REFLECT_SHADER_STAGE_MESH_BIT_EXT);
|
|
|
|
spvReflectDestroyShaderModule(&module_);
|
|
}
|
|
|
|
TEST(SpirvReflectTestCase, TestGeometryInvocationsOutputVertices) {
|
|
std::vector<uint8_t> spirv_;
|
|
SpvReflectShaderModule module_;
|
|
const std::string spirv_path =
|
|
"../tests/entry_exec_mode/geom_inv_out_vert.spv";
|
|
std::ifstream spirv_file(spirv_path, std::ios::binary | std::ios::ate);
|
|
std::streampos spirv_file_nbytes = spirv_file.tellg();
|
|
spirv_file.seekg(0);
|
|
spirv_.resize(spirv_file_nbytes);
|
|
spirv_file.read(reinterpret_cast<char*>(spirv_.data()), spirv_.size());
|
|
|
|
SpvReflectResult result =
|
|
spvReflectCreateShaderModule(spirv_.size(), spirv_.data(), &module_);
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS, result)
|
|
<< "spvReflectCreateShaderModule() failed";
|
|
|
|
ASSERT_EQ(module_.entry_point_count, 1);
|
|
ASSERT_EQ(module_.entry_points[0].shader_stage,
|
|
SPV_REFLECT_SHADER_STAGE_GEOMETRY_BIT);
|
|
ASSERT_EQ(module_.entry_points[0].invocations, 2);
|
|
ASSERT_EQ(module_.entry_points[0].output_vertices, 2);
|
|
|
|
spvReflectDestroyShaderModule(&module_);
|
|
}
|
|
|
|
class SpirvReflectMultiEntryPointTest : public ::testing::TestWithParam<int> {
|
|
protected:
|
|
void SetUp() override {
|
|
// called after constructor before each test
|
|
const std::string spirv_path =
|
|
"../tests/multi_entrypoint/multi_entrypoint.spv";
|
|
std::ifstream spirv_file(spirv_path, std::ios::binary | std::ios::ate);
|
|
std::streampos spirv_file_nbytes = spirv_file.tellg();
|
|
spirv_file.seekg(0);
|
|
spirv_.resize(spirv_file_nbytes);
|
|
spirv_file.read(reinterpret_cast<char*>(spirv_.data()), spirv_.size());
|
|
|
|
SpvReflectResult result =
|
|
spvReflectCreateShaderModule(spirv_.size(), spirv_.data(), &module_);
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS, result)
|
|
<< "spvReflectCreateShaderModule() failed";
|
|
}
|
|
|
|
// optional:
|
|
void TearDown() override {
|
|
// called before destructor after all tests
|
|
spvReflectDestroyShaderModule(&module_);
|
|
}
|
|
|
|
const char* eps_[2] = {"entry_vert", "entry_frag"};
|
|
std::vector<uint8_t> spirv_;
|
|
SpvReflectShaderModule module_;
|
|
};
|
|
|
|
TEST_F(SpirvReflectMultiEntryPointTest, GetEntryPoint) {
|
|
ASSERT_EQ(&module_.entry_points[0],
|
|
spvReflectGetEntryPoint(&module_, eps_[0]));
|
|
ASSERT_EQ(&module_.entry_points[1],
|
|
spvReflectGetEntryPoint(&module_, eps_[1]));
|
|
ASSERT_EQ(NULL, spvReflectGetEntryPoint(&module_, "entry_tess"));
|
|
}
|
|
|
|
TEST_F(SpirvReflectMultiEntryPointTest, GetDescriptorBindings0) {
|
|
uint32_t binding_count = 0;
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS,
|
|
spvReflectEnumerateEntryPointDescriptorBindings(
|
|
&module_, eps_[0], &binding_count, NULL));
|
|
ASSERT_EQ(binding_count, 1);
|
|
SpvReflectDescriptorBinding* binding;
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS,
|
|
spvReflectEnumerateEntryPointDescriptorBindings(
|
|
&module_, eps_[0], &binding_count, &binding));
|
|
ASSERT_EQ(binding->set, 0);
|
|
ASSERT_EQ(binding->binding, 1);
|
|
ASSERT_EQ(strcmp(binding->name, "ubo"), 0);
|
|
ASSERT_EQ(binding->descriptor_type,
|
|
SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
|
|
|
|
SpvReflectResult result;
|
|
ASSERT_EQ(binding,
|
|
spvReflectGetEntryPointDescriptorBinding(
|
|
&module_, eps_[0], binding->binding, binding->set, &result));
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS, result);
|
|
}
|
|
|
|
TEST_F(SpirvReflectMultiEntryPointTest, GetDescriptorBindings1) {
|
|
uint32_t binding_count = 0;
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS,
|
|
spvReflectEnumerateEntryPointDescriptorBindings(
|
|
&module_, eps_[1], &binding_count, NULL));
|
|
ASSERT_EQ(binding_count, 2);
|
|
SpvReflectDescriptorBinding* bindings[2];
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS,
|
|
spvReflectEnumerateEntryPointDescriptorBindings(
|
|
&module_, eps_[1], &binding_count, bindings));
|
|
ASSERT_EQ(bindings[0]->set, 0);
|
|
ASSERT_EQ(bindings[0]->binding, 0);
|
|
ASSERT_EQ(strcmp(bindings[0]->name, "tex"), 0);
|
|
ASSERT_EQ(bindings[0]->descriptor_type,
|
|
SPV_REFLECT_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
|
|
|
|
ASSERT_EQ(bindings[1]->set, 0);
|
|
ASSERT_EQ(bindings[1]->binding, 1);
|
|
ASSERT_EQ(strcmp(bindings[1]->name, "ubo"), 0);
|
|
ASSERT_EQ(bindings[1]->descriptor_type,
|
|
SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
|
|
|
|
for (size_t i = 0; i < 2; ++i) {
|
|
SpvReflectResult result;
|
|
ASSERT_EQ(bindings[i], spvReflectGetEntryPointDescriptorBinding(
|
|
&module_, eps_[1], bindings[i]->binding,
|
|
bindings[i]->set, &result));
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS, result);
|
|
}
|
|
}
|
|
|
|
TEST_F(SpirvReflectMultiEntryPointTest, GetDescriptorBindingsShared) {
|
|
uint32_t vert_count = 1;
|
|
SpvReflectDescriptorBinding* vert_binding;
|
|
|
|
uint32_t frag_count = 2;
|
|
SpvReflectDescriptorBinding* frag_binding[2];
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS,
|
|
spvReflectEnumerateEntryPointDescriptorBindings(
|
|
&module_, eps_[0], &vert_count, &vert_binding));
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS,
|
|
spvReflectEnumerateEntryPointDescriptorBindings(
|
|
&module_, eps_[1], &frag_count, frag_binding));
|
|
ASSERT_EQ(vert_binding, frag_binding[1]);
|
|
}
|
|
|
|
TEST_F(SpirvReflectMultiEntryPointTest, GetDescriptorSets0) {
|
|
uint32_t set_count;
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS,
|
|
spvReflectEnumerateEntryPointDescriptorSets(&module_, eps_[0],
|
|
&set_count, NULL));
|
|
ASSERT_EQ(set_count, 1);
|
|
SpvReflectDescriptorSet* set;
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS,
|
|
spvReflectEnumerateEntryPointDescriptorSets(&module_, eps_[0],
|
|
&set_count, &set));
|
|
ASSERT_EQ(set->set, 0);
|
|
ASSERT_EQ(set->binding_count, 1);
|
|
ASSERT_EQ(set, &module_.entry_points[0].descriptor_sets[0]);
|
|
|
|
SpvReflectResult result;
|
|
ASSERT_EQ(set, spvReflectGetEntryPointDescriptorSet(&module_, eps_[0],
|
|
set->set, &result));
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS, result);
|
|
}
|
|
|
|
TEST_F(SpirvReflectMultiEntryPointTest, GetDescriptorSets1) {
|
|
uint32_t set_count;
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS,
|
|
spvReflectEnumerateEntryPointDescriptorSets(&module_, eps_[1],
|
|
&set_count, NULL));
|
|
ASSERT_EQ(set_count, 1);
|
|
SpvReflectDescriptorSet* set;
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS,
|
|
spvReflectEnumerateEntryPointDescriptorSets(&module_, eps_[1],
|
|
&set_count, &set));
|
|
ASSERT_EQ(set->set, 0);
|
|
ASSERT_EQ(set->binding_count, 2);
|
|
ASSERT_EQ(set, &module_.entry_points[1].descriptor_sets[0]);
|
|
|
|
SpvReflectResult result;
|
|
ASSERT_EQ(set, spvReflectGetEntryPointDescriptorSet(&module_, eps_[1],
|
|
set->set, &result));
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS, result);
|
|
}
|
|
|
|
TEST_F(SpirvReflectMultiEntryPointTest, GetInputVariables) {
|
|
const uint32_t counts[2] = {2, 1};
|
|
const char* names[2][2] = {{"iUV", "pos"}, {"iUV", NULL}};
|
|
for (size_t i = 0; i < 2; ++i) {
|
|
uint32_t count = 0;
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS,
|
|
spvReflectEnumerateEntryPointInputVariables(&module_, eps_[i],
|
|
&count, NULL));
|
|
ASSERT_EQ(count, counts[i]);
|
|
|
|
// 2 is the max count
|
|
SpvReflectInterfaceVariable* vars[2];
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS,
|
|
spvReflectEnumerateEntryPointInputVariables(&module_, eps_[i],
|
|
&count, vars));
|
|
for (size_t j = 0; j < counts[i]; ++j) {
|
|
if (vars[j]->decoration_flags & SPV_REFLECT_DECORATION_BUILT_IN) {
|
|
// built-ins don't have reasonable locations
|
|
continue;
|
|
}
|
|
SpvReflectResult result;
|
|
const SpvReflectInterfaceVariable* var =
|
|
spvReflectGetEntryPointInputVariableByLocation(
|
|
&module_, eps_[i], vars[j]->location, &result);
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
ASSERT_EQ(var, vars[j]);
|
|
ASSERT_EQ(strcmp(var->name, names[i][var->location]), 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_F(SpirvReflectMultiEntryPointTest, GetOutputVariables) {
|
|
const uint32_t counts[2] = {2, 1};
|
|
// One of the outputs from the first entry point is a builtin so it has no
|
|
// position.
|
|
const char* names[2][1] = {{"oUV"}, {"colour"}};
|
|
for (size_t i = 0; i < 2; ++i) {
|
|
uint32_t count = 0;
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS,
|
|
spvReflectEnumerateEntryPointOutputVariables(&module_, eps_[i],
|
|
&count, NULL));
|
|
ASSERT_EQ(count, counts[i]);
|
|
|
|
// 2 is the max count
|
|
SpvReflectInterfaceVariable* vars[2];
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS,
|
|
spvReflectEnumerateEntryPointOutputVariables(&module_, eps_[i],
|
|
&count, vars));
|
|
for (size_t j = 0; j < counts[i]; ++j) {
|
|
if (vars[j]->decoration_flags & SPV_REFLECT_DECORATION_BUILT_IN) {
|
|
// built-ins don't have reasonable locations
|
|
continue;
|
|
}
|
|
SpvReflectResult result;
|
|
const SpvReflectInterfaceVariable* var =
|
|
spvReflectGetEntryPointOutputVariableByLocation(
|
|
&module_, eps_[i], vars[j]->location, &result);
|
|
ASSERT_EQ(result, SPV_REFLECT_RESULT_SUCCESS);
|
|
ASSERT_EQ(var, vars[j]);
|
|
ASSERT_EQ(strcmp(var->name, names[i][var->location]), 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_F(SpirvReflectMultiEntryPointTest, GetPushConstants) {
|
|
for (size_t i = 0; i < 2; ++i) {
|
|
SpvReflectBlockVariable* var;
|
|
uint32_t count = 0;
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH,
|
|
spvReflectEnumerateEntryPointPushConstantBlocks(&module_, eps_[i],
|
|
&count, &var));
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS,
|
|
spvReflectEnumerateEntryPointPushConstantBlocks(&module_, eps_[i],
|
|
&count, NULL));
|
|
ASSERT_EQ(count, 1);
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS,
|
|
spvReflectEnumerateEntryPointPushConstantBlocks(&module_, eps_[i],
|
|
&count, &var));
|
|
SpvReflectResult result;
|
|
ASSERT_EQ(var, spvReflectGetEntryPointPushConstantBlock(&module_, eps_[i],
|
|
&result));
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS, result);
|
|
}
|
|
}
|
|
|
|
TEST_F(SpirvReflectMultiEntryPointTest, ChangeDescriptorBindingNumber) {
|
|
const SpvReflectDescriptorBinding* binding =
|
|
spvReflectGetEntryPointDescriptorBinding(&module_, eps_[0], 1, 0, NULL);
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS,
|
|
spvReflectChangeDescriptorBindingNumbers(&module_, binding, 2, 1));
|
|
// Change descriptor binding numbers doesn't currently resort so it won't
|
|
// invalidate binding, but if that changes this test will need to be fixed.
|
|
ASSERT_EQ(binding->set, 1);
|
|
ASSERT_EQ(binding->binding, 2);
|
|
|
|
SpvReflectResult result;
|
|
const SpvReflectDescriptorSet* set0 =
|
|
spvReflectGetEntryPointDescriptorSet(&module_, eps_[0], 1, &result);
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS, result);
|
|
ASSERT_EQ(set0->binding_count, 1);
|
|
const SpvReflectDescriptorSet* set1 =
|
|
spvReflectGetEntryPointDescriptorSet(&module_, eps_[1], 1, &result);
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS, result);
|
|
ASSERT_EQ(set1->binding_count, 1);
|
|
|
|
ASSERT_EQ(set0->bindings[0], set1->bindings[0]);
|
|
}
|
|
|
|
TEST_F(SpirvReflectMultiEntryPointTest, ChangeDescriptorSetNumber) {
|
|
const SpvReflectDescriptorSet* set =
|
|
spvReflectGetDescriptorSet(&module_, 0, NULL);
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS,
|
|
spvReflectChangeDescriptorSetNumber(&module_, set, 1));
|
|
// Change descriptor binding numbers doesn't currently resort so it won't
|
|
// invalidate binding, but if that changes this test will need to be fixed.
|
|
ASSERT_EQ(set->set, 1);
|
|
|
|
SpvReflectResult result;
|
|
const SpvReflectDescriptorSet* set0 =
|
|
spvReflectGetEntryPointDescriptorSet(&module_, eps_[0], 1, &result);
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS, result);
|
|
ASSERT_EQ(set0->binding_count, 1);
|
|
const SpvReflectDescriptorSet* set1 =
|
|
spvReflectGetEntryPointDescriptorSet(&module_, eps_[1], 1, &result);
|
|
ASSERT_EQ(SPV_REFLECT_RESULT_SUCCESS, result);
|
|
ASSERT_EQ(set1->binding_count, 2);
|
|
|
|
ASSERT_EQ(set0->bindings[0], set1->bindings[1]);
|
|
ASSERT_EQ(set0->bindings[0]->set, 1);
|
|
}
|