mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-06 01:50:38 +00:00
Move GLSL reflection tests to common place for SPIR-V to use
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -30,8 +30,18 @@ enum ShaderType
|
||||
eShaderGLSPIRV,
|
||||
};
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
std::string GenerateGLSLShader(const std::string &shader, ShaderType type, int version,
|
||||
const std::string &defines = "");
|
||||
|
||||
// for unit tests
|
||||
struct ShaderReflection;
|
||||
struct ShaderBindpointMapping;
|
||||
enum class ShaderStage : uint32_t;
|
||||
using ReflectionMaker =
|
||||
std::function<void(ShaderStage stage, const std::string &source, const std::string &entryPoint,
|
||||
ShaderReflection &refl, ShaderBindpointMapping &mapping)>;
|
||||
void TestGLSLReflection(ShaderType testType, ReflectionMaker compile);
|
||||
@@ -3317,6 +3317,7 @@ void GLDispatchTable::DriverForEmulation(WrappedOpenGL *driver)
|
||||
|
||||
#include "../gl_shader_refl.h"
|
||||
#include "3rdparty/catch/catch.hpp"
|
||||
#include "data/glsl_shaders.h"
|
||||
#include "strings/string_utils.h"
|
||||
|
||||
GLint APIENTRY _testStub_GetUniformLocation(GLuint program, const GLchar *name)
|
||||
@@ -3430,11 +3431,14 @@ GLint APIENTRY _testStub_AttribLocation(GLuint program, const GLchar *name)
|
||||
}
|
||||
|
||||
void MakeOfflineShaderReflection(ShaderStage stage, const std::string &source,
|
||||
ShaderReflection &refl, ShaderBindpointMapping &mapping)
|
||||
const std::string &entryPoint, ShaderReflection &refl,
|
||||
ShaderBindpointMapping &mapping)
|
||||
{
|
||||
InitSPIRVCompiler();
|
||||
RenderDoc::Inst().RegisterShutdownFunction(&ShutdownSPIRVCompiler);
|
||||
|
||||
RDCASSERT(entryPoint == "main");
|
||||
|
||||
// as a hack, create a local 'driver' and just populate m_Programs with what we want.
|
||||
GLDummyPlatform dummy;
|
||||
WrappedOpenGL driver(dummy);
|
||||
@@ -3487,11 +3491,14 @@ void MakeOfflineShaderReflection(ShaderStage stage, const std::string &source,
|
||||
//
|
||||
// Note that we can't fill out ShaderBindpointMapping easily on the actual driver
|
||||
void MakeOnlineShaderReflection(ShaderStage stage, const std::string &source,
|
||||
ShaderReflection &refl, ShaderBindpointMapping &mapping)
|
||||
const std::string &entryPoint, ShaderReflection &refl,
|
||||
ShaderBindpointMapping &mapping)
|
||||
{
|
||||
ReplayStatus status = ReplayStatus::UnknownError;
|
||||
IReplayDriver *driver = NULL;
|
||||
|
||||
RDCASSERT(entryPoint == "main");
|
||||
|
||||
std::map<RDCDriver, std::string> replays = RenderDoc::Inst().GetReplayDrivers();
|
||||
|
||||
if(replays.find(RDCDriver::OpenGL) != replays.end())
|
||||
@@ -3524,859 +3531,9 @@ void MakeOnlineShaderReflection(ShaderStage stage, const std::string &source,
|
||||
driver->Shutdown();
|
||||
}
|
||||
|
||||
TEST_CASE("Validate ARB_program_interface_query emulation", "[opengl][glslang]")
|
||||
TEST_CASE("Validate ARB_program_interface_query emulation", "[opengl][glslang][reflection]")
|
||||
{
|
||||
SECTION("Single shader deep dive")
|
||||
{
|
||||
std::string source = R"(
|
||||
#version 450 core
|
||||
|
||||
struct glstruct
|
||||
{
|
||||
float a;
|
||||
int b;
|
||||
mat2x2 c;
|
||||
};
|
||||
|
||||
layout(binding = 8, std140) uniform ubo_block {
|
||||
float ubo_a;
|
||||
layout(column_major) mat4x3 ubo_b;
|
||||
layout(row_major) mat4x3 ubo_c;
|
||||
ivec2 ubo_d;
|
||||
vec2 ubo_e[3];
|
||||
glstruct ubo_f;
|
||||
layout(offset = 256) vec4 ubo_z;
|
||||
} ubo_root;
|
||||
|
||||
layout(binding = 2, std430) buffer ssbo
|
||||
{
|
||||
uint ssbo_a[10];
|
||||
glstruct ssbo_b[3];
|
||||
float ssbo_c;
|
||||
} ssbo_root;
|
||||
|
||||
layout(binding = 0) uniform atomic_uint atom;
|
||||
|
||||
layout(location = 3) in vec2 a_input;
|
||||
layout(location = 6) flat in uvec3 z_input;
|
||||
|
||||
uniform vec3 global_var[5];
|
||||
uniform mat3x2 global_var2[3];
|
||||
|
||||
layout(binding = 3) uniform sampler2D tex2D;
|
||||
layout(binding = 5) uniform isampler3D tex3D;
|
||||
|
||||
layout(location = 0) out vec4 a_output;
|
||||
layout(location = 1) out vec3 z_output;
|
||||
layout(location = 2) out int b_output;
|
||||
|
||||
void main() {
|
||||
float a = ubo_root.ubo_a + global_var2[2][0][1];
|
||||
a_output = vec4(sin(float(a) + gl_FragCoord.x), 0, 0, 1);
|
||||
z_output = textureLod(tex2D, a_output.xy, a_output.z).xyz + a_input.xyx + global_var[4];
|
||||
ssbo_root.ssbo_a[5] = 4 + atomicCounter(atom) + z_input.y;
|
||||
b_output = ssbo_root.ssbo_b[2].b + texelFetch(tex3D, ivec3(z_input), 0).x;
|
||||
gl_FragDepth = z_output.y;
|
||||
}
|
||||
|
||||
)";
|
||||
|
||||
#define REQUIRE_ARRAY_SIZE(size, min) \
|
||||
REQUIRE(size >= min); \
|
||||
CHECK(size == min);
|
||||
|
||||
ShaderReflection refl;
|
||||
ShaderBindpointMapping mapping;
|
||||
MakeOfflineShaderReflection(ShaderStage::Fragment, source, refl, mapping);
|
||||
|
||||
REQUIRE_ARRAY_SIZE(refl.inputSignature.size(), 3);
|
||||
{
|
||||
CHECK(refl.inputSignature[0].varName == "gl_FragCoord");
|
||||
{
|
||||
const SigParameter &sig = refl.inputSignature[0];
|
||||
INFO("signature element: " << sig.varName.c_str());
|
||||
|
||||
CHECK(sig.regIndex == 0);
|
||||
CHECK(sig.systemValue == ShaderBuiltin::Position);
|
||||
CHECK(sig.compType == CompType::Float);
|
||||
CHECK(sig.compCount == 4);
|
||||
CHECK(sig.regChannelMask == 0xf);
|
||||
CHECK(sig.channelUsedMask == 0xf);
|
||||
}
|
||||
|
||||
CHECK(refl.inputSignature[1].varName == "a_input");
|
||||
{
|
||||
const SigParameter &sig = refl.inputSignature[1];
|
||||
INFO("signature element: " << sig.varName.c_str());
|
||||
|
||||
CHECK(sig.regIndex == 3);
|
||||
CHECK(sig.systemValue == ShaderBuiltin::Undefined);
|
||||
CHECK(sig.compType == CompType::Float);
|
||||
CHECK(sig.compCount == 2);
|
||||
CHECK(sig.regChannelMask == 0x3);
|
||||
CHECK(sig.channelUsedMask == 0x3);
|
||||
}
|
||||
|
||||
CHECK(refl.inputSignature[2].varName == "z_input");
|
||||
{
|
||||
const SigParameter &sig = refl.inputSignature[2];
|
||||
INFO("signature element: " << sig.varName.c_str());
|
||||
|
||||
CHECK(sig.regIndex == 6);
|
||||
CHECK(sig.systemValue == ShaderBuiltin::Undefined);
|
||||
CHECK(sig.compType == CompType::UInt);
|
||||
CHECK(sig.compCount == 3);
|
||||
CHECK(sig.regChannelMask == 0x7);
|
||||
CHECK(sig.channelUsedMask == 0x7);
|
||||
}
|
||||
}
|
||||
|
||||
REQUIRE_ARRAY_SIZE(refl.outputSignature.size(), 4);
|
||||
{
|
||||
CHECK(refl.outputSignature[0].varName == "a_output");
|
||||
{
|
||||
const SigParameter &sig = refl.outputSignature[0];
|
||||
INFO("signature element: " << sig.varName.c_str());
|
||||
|
||||
CHECK(sig.regIndex == 0);
|
||||
CHECK(sig.systemValue == ShaderBuiltin::ColorOutput);
|
||||
CHECK(sig.compType == CompType::Float);
|
||||
CHECK(sig.compCount == 4);
|
||||
CHECK(sig.regChannelMask == 0xf);
|
||||
CHECK(sig.channelUsedMask == 0xf);
|
||||
}
|
||||
|
||||
CHECK(refl.outputSignature[1].varName == "z_output");
|
||||
{
|
||||
const SigParameter &sig = refl.outputSignature[1];
|
||||
INFO("signature element: " << sig.varName.c_str());
|
||||
|
||||
CHECK(sig.regIndex == 1);
|
||||
CHECK(sig.systemValue == ShaderBuiltin::ColorOutput);
|
||||
CHECK(sig.compType == CompType::Float);
|
||||
CHECK(sig.compCount == 3);
|
||||
CHECK(sig.regChannelMask == 0x7);
|
||||
CHECK(sig.channelUsedMask == 0x7);
|
||||
}
|
||||
|
||||
CHECK(refl.outputSignature[2].varName == "b_output");
|
||||
{
|
||||
const SigParameter &sig = refl.outputSignature[2];
|
||||
INFO("signature element: " << sig.varName.c_str());
|
||||
|
||||
CHECK(sig.regIndex == 2);
|
||||
CHECK(sig.systemValue == ShaderBuiltin::ColorOutput);
|
||||
CHECK(sig.compType == CompType::SInt);
|
||||
CHECK(sig.compCount == 1);
|
||||
CHECK(sig.regChannelMask == 0x1);
|
||||
CHECK(sig.channelUsedMask == 0x1);
|
||||
}
|
||||
|
||||
CHECK(refl.outputSignature[3].varName == "gl_FragDepth");
|
||||
{
|
||||
const SigParameter &sig = refl.outputSignature[3];
|
||||
INFO("signature element: " << sig.varName.c_str());
|
||||
|
||||
// when not running with a driver we default to just using the index instead of looking up
|
||||
// the location of outputs, so this will be wrong
|
||||
// CHECK(sig.regIndex == 0);
|
||||
CHECK(sig.systemValue == ShaderBuiltin::DepthOutput);
|
||||
CHECK(sig.compType == CompType::Float);
|
||||
CHECK(sig.compCount == 1);
|
||||
CHECK(sig.regChannelMask == 0x1);
|
||||
CHECK(sig.channelUsedMask == 0x1);
|
||||
}
|
||||
}
|
||||
|
||||
REQUIRE_ARRAY_SIZE(refl.readOnlyResources.size(), 2);
|
||||
{
|
||||
CHECK(refl.readOnlyResources[0].name == "tex2D");
|
||||
{
|
||||
const ShaderResource &res = refl.readOnlyResources[0];
|
||||
INFO("read-only resource: " << res.name.c_str());
|
||||
|
||||
CHECK(res.bindPoint == 0);
|
||||
CHECK(res.resType == TextureType::Texture2D);
|
||||
CHECK(res.variableType.members.empty());
|
||||
CHECK(res.variableType.descriptor.type == VarType::Float);
|
||||
CHECK(res.variableType.descriptor.rows == 1);
|
||||
CHECK(res.variableType.descriptor.columns == 4);
|
||||
CHECK(res.variableType.descriptor.name == "sampler2D");
|
||||
}
|
||||
|
||||
CHECK(refl.readOnlyResources[1].name == "tex3D");
|
||||
{
|
||||
const ShaderResource &res = refl.readOnlyResources[1];
|
||||
INFO("read-only resource: " << res.name.c_str());
|
||||
|
||||
CHECK(res.bindPoint == 1);
|
||||
CHECK(res.resType == TextureType::Texture3D);
|
||||
CHECK(res.variableType.members.empty());
|
||||
CHECK(res.variableType.descriptor.type == VarType::SInt);
|
||||
CHECK(res.variableType.descriptor.rows == 1);
|
||||
CHECK(res.variableType.descriptor.columns == 4);
|
||||
CHECK(res.variableType.descriptor.name == "isampler3D");
|
||||
}
|
||||
}
|
||||
|
||||
REQUIRE_ARRAY_SIZE(refl.readWriteResources.size(), 2);
|
||||
{
|
||||
CHECK(refl.readWriteResources[0].name == "atom");
|
||||
{
|
||||
const ShaderResource &res = refl.readWriteResources[0];
|
||||
INFO("read-write resource: " << res.name.c_str());
|
||||
|
||||
CHECK(res.bindPoint == 0);
|
||||
CHECK(res.resType == TextureType::Buffer);
|
||||
CHECK(res.variableType.members.empty());
|
||||
CHECK(res.variableType.descriptor.type == VarType::UInt);
|
||||
CHECK(res.variableType.descriptor.rows == 1);
|
||||
CHECK(res.variableType.descriptor.columns == 1);
|
||||
CHECK(res.variableType.descriptor.name == "atomic_uint");
|
||||
}
|
||||
|
||||
CHECK(refl.readWriteResources[1].name == "ssbo");
|
||||
{
|
||||
const ShaderResource &res = refl.readWriteResources[1];
|
||||
INFO("read-write resource: " << res.name.c_str());
|
||||
|
||||
CHECK(res.bindPoint == 1);
|
||||
CHECK(res.resType == TextureType::Buffer);
|
||||
CHECK(res.variableType.descriptor.type == VarType::UInt);
|
||||
CHECK(res.variableType.descriptor.rows == 0);
|
||||
CHECK(res.variableType.descriptor.columns == 0);
|
||||
CHECK(res.variableType.descriptor.name == "buffer");
|
||||
|
||||
REQUIRE_ARRAY_SIZE(res.variableType.members.size(), 3);
|
||||
{
|
||||
CHECK(res.variableType.members[0].name == "ssbo_a");
|
||||
{
|
||||
const ShaderConstant &member = res.variableType.members[0];
|
||||
INFO("SSBO member: " << member.name.c_str());
|
||||
|
||||
CHECK(member.byteOffset == 0);
|
||||
CHECK(member.type.members.empty());
|
||||
CHECK(member.type.descriptor.type == VarType::UInt);
|
||||
CHECK(member.type.descriptor.rows == 1);
|
||||
CHECK(member.type.descriptor.columns == 1);
|
||||
CHECK(member.type.descriptor.elements == 10);
|
||||
CHECK(member.type.descriptor.arrayByteStride == 4);
|
||||
CHECK(member.type.descriptor.name == "uint");
|
||||
}
|
||||
|
||||
CHECK(res.variableType.members[1].name == "ssbo_b");
|
||||
{
|
||||
const ShaderConstant &member = res.variableType.members[1];
|
||||
INFO("SSBO member: " << member.name.c_str());
|
||||
|
||||
CHECK(member.byteOffset == 40);
|
||||
// this doesn't reflect in native introspection, so we skip it
|
||||
// CHECK(member.type.descriptor.elements == 3);
|
||||
CHECK(member.type.descriptor.name == "struct");
|
||||
CHECK(member.type.descriptor.arrayByteStride == 24);
|
||||
|
||||
REQUIRE_ARRAY_SIZE(member.type.members.size(), 3);
|
||||
{
|
||||
CHECK(member.type.members[0].name == "a");
|
||||
{
|
||||
const ShaderConstant &submember = member.type.members[0];
|
||||
INFO("SSBO submember: " << submember.name.c_str());
|
||||
|
||||
CHECK(submember.byteOffset == 0);
|
||||
CHECK(submember.type.members.empty());
|
||||
CHECK(submember.type.descriptor.type == VarType::Float);
|
||||
CHECK(submember.type.descriptor.rows == 1);
|
||||
CHECK(submember.type.descriptor.columns == 1);
|
||||
CHECK(submember.type.descriptor.name == "float");
|
||||
}
|
||||
|
||||
CHECK(member.type.members[1].name == "b");
|
||||
{
|
||||
const ShaderConstant &submember = member.type.members[1];
|
||||
INFO("SSBO submember: " << submember.name.c_str());
|
||||
|
||||
CHECK(submember.byteOffset == 4);
|
||||
CHECK(submember.type.members.empty());
|
||||
CHECK(submember.type.descriptor.type == VarType::SInt);
|
||||
CHECK(submember.type.descriptor.rows == 1);
|
||||
CHECK(submember.type.descriptor.columns == 1);
|
||||
CHECK(submember.type.descriptor.name == "int");
|
||||
}
|
||||
|
||||
CHECK(member.type.members[2].name == "c");
|
||||
{
|
||||
const ShaderConstant &submember = member.type.members[2];
|
||||
INFO("SSBO submember: " << submember.name.c_str());
|
||||
|
||||
CHECK(submember.byteOffset == 8);
|
||||
CHECK(submember.type.members.empty());
|
||||
CHECK(submember.type.descriptor.type == VarType::Float);
|
||||
CHECK(submember.type.descriptor.rows == 2);
|
||||
CHECK(submember.type.descriptor.columns == 2);
|
||||
CHECK(submember.type.descriptor.rowMajorStorage == false);
|
||||
CHECK(submember.type.descriptor.name == "mat2");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CHECK(res.variableType.members[2].name == "ssbo_c");
|
||||
{
|
||||
const ShaderConstant &member = res.variableType.members[2];
|
||||
INFO("SSBO member: " << member.name.c_str());
|
||||
|
||||
CHECK(member.byteOffset == 112);
|
||||
CHECK(member.type.members.empty());
|
||||
CHECK(member.type.descriptor.type == VarType::Float);
|
||||
CHECK(member.type.descriptor.rows == 1);
|
||||
CHECK(member.type.descriptor.columns == 1);
|
||||
CHECK(member.type.descriptor.name == "float");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
REQUIRE_ARRAY_SIZE(refl.constantBlocks.size(), 2);
|
||||
{
|
||||
CHECK(refl.constantBlocks[0].name == "ubo_block");
|
||||
{
|
||||
const ConstantBlock &cblock = refl.constantBlocks[0];
|
||||
INFO("UBO: " << cblock.name.c_str());
|
||||
|
||||
CHECK(cblock.bindPoint == 0);
|
||||
CHECK(cblock.bufferBacked);
|
||||
CHECK(cblock.byteSize == 272);
|
||||
|
||||
REQUIRE_ARRAY_SIZE(cblock.variables.size(), 1);
|
||||
|
||||
CHECK(cblock.variables[0].name == "ubo_block");
|
||||
const ShaderConstant &ubo_root = cblock.variables[0];
|
||||
|
||||
CHECK(ubo_root.byteOffset == 0);
|
||||
CHECK(ubo_root.type.descriptor.name == "struct");
|
||||
|
||||
REQUIRE_ARRAY_SIZE(ubo_root.type.members.size(), 7);
|
||||
{
|
||||
CHECK(ubo_root.type.members[0].name == "ubo_a");
|
||||
{
|
||||
const ShaderConstant &member = ubo_root.type.members[0];
|
||||
INFO("UBO member: " << member.name.c_str());
|
||||
|
||||
CHECK(member.byteOffset == 0);
|
||||
CHECK(member.type.members.empty());
|
||||
CHECK(member.type.descriptor.type == VarType::Float);
|
||||
CHECK(member.type.descriptor.rows == 1);
|
||||
CHECK(member.type.descriptor.columns == 1);
|
||||
CHECK(member.type.descriptor.name == "float");
|
||||
}
|
||||
|
||||
CHECK(ubo_root.type.members[1].name == "ubo_b");
|
||||
{
|
||||
const ShaderConstant &member = ubo_root.type.members[1];
|
||||
INFO("UBO member: " << member.name.c_str());
|
||||
|
||||
CHECK(member.byteOffset == 16);
|
||||
CHECK(member.type.members.empty());
|
||||
CHECK(member.type.descriptor.type == VarType::Float);
|
||||
CHECK(member.type.descriptor.rows == 3);
|
||||
CHECK(member.type.descriptor.columns == 4);
|
||||
CHECK(member.type.descriptor.rowMajorStorage == false);
|
||||
CHECK(member.type.descriptor.name == "mat4x3");
|
||||
}
|
||||
|
||||
CHECK(ubo_root.type.members[2].name == "ubo_c");
|
||||
{
|
||||
const ShaderConstant &member = ubo_root.type.members[2];
|
||||
INFO("UBO member: " << member.name.c_str());
|
||||
|
||||
CHECK(member.byteOffset == 80);
|
||||
CHECK(member.type.members.empty());
|
||||
CHECK(member.type.descriptor.type == VarType::Float);
|
||||
CHECK(member.type.descriptor.rows == 3);
|
||||
CHECK(member.type.descriptor.columns == 4);
|
||||
CHECK(member.type.descriptor.rowMajorStorage == true);
|
||||
CHECK(member.type.descriptor.name == "mat4x3");
|
||||
}
|
||||
|
||||
CHECK(ubo_root.type.members[3].name == "ubo_d");
|
||||
{
|
||||
const ShaderConstant &member = ubo_root.type.members[3];
|
||||
INFO("UBO member: " << member.name.c_str());
|
||||
|
||||
CHECK(member.byteOffset == 128);
|
||||
CHECK(member.type.members.empty());
|
||||
CHECK(member.type.descriptor.type == VarType::SInt);
|
||||
CHECK(member.type.descriptor.rows == 1);
|
||||
CHECK(member.type.descriptor.columns == 2);
|
||||
CHECK(member.type.descriptor.name == "ivec2");
|
||||
}
|
||||
|
||||
CHECK(ubo_root.type.members[4].name == "ubo_e");
|
||||
{
|
||||
const ShaderConstant &member = ubo_root.type.members[4];
|
||||
INFO("UBO member: " << member.name.c_str());
|
||||
|
||||
CHECK(member.byteOffset == 144);
|
||||
CHECK(member.type.members.empty());
|
||||
CHECK(member.type.descriptor.type == VarType::Float);
|
||||
CHECK(member.type.descriptor.rows == 1);
|
||||
CHECK(member.type.descriptor.columns == 2);
|
||||
CHECK(member.type.descriptor.elements == 3);
|
||||
CHECK(member.type.descriptor.arrayByteStride == 16);
|
||||
CHECK(member.type.descriptor.name == "vec2");
|
||||
}
|
||||
|
||||
CHECK(ubo_root.type.members[5].name == "ubo_f");
|
||||
{
|
||||
const ShaderConstant &member = ubo_root.type.members[5];
|
||||
INFO("UBO member: " << member.name.c_str());
|
||||
|
||||
CHECK(member.byteOffset == 192);
|
||||
// this doesn't reflect in native introspection, so we skip it
|
||||
// CHECK(member.type.descriptor.elements == 3);
|
||||
CHECK(member.type.descriptor.name == "struct");
|
||||
|
||||
REQUIRE_ARRAY_SIZE(member.type.members.size(), 3);
|
||||
{
|
||||
CHECK(member.type.members[0].name == "a");
|
||||
{
|
||||
const ShaderConstant &submember = member.type.members[0];
|
||||
INFO("UBO submember: " << submember.name.c_str());
|
||||
|
||||
CHECK(submember.byteOffset == 0);
|
||||
CHECK(submember.type.members.empty());
|
||||
CHECK(submember.type.descriptor.type == VarType::Float);
|
||||
CHECK(submember.type.descriptor.rows == 1);
|
||||
CHECK(submember.type.descriptor.columns == 1);
|
||||
CHECK(submember.type.descriptor.name == "float");
|
||||
}
|
||||
|
||||
CHECK(member.type.members[1].name == "b");
|
||||
{
|
||||
const ShaderConstant &submember = member.type.members[1];
|
||||
INFO("UBO submember: " << submember.name.c_str());
|
||||
|
||||
CHECK(submember.byteOffset == 4);
|
||||
CHECK(submember.type.members.empty());
|
||||
CHECK(submember.type.descriptor.type == VarType::SInt);
|
||||
CHECK(submember.type.descriptor.rows == 1);
|
||||
CHECK(submember.type.descriptor.columns == 1);
|
||||
CHECK(submember.type.descriptor.name == "int");
|
||||
}
|
||||
|
||||
CHECK(member.type.members[2].name == "c");
|
||||
{
|
||||
const ShaderConstant &submember = member.type.members[2];
|
||||
INFO("UBO submember: " << submember.name.c_str());
|
||||
|
||||
CHECK(submember.byteOffset == 16);
|
||||
CHECK(submember.type.members.empty());
|
||||
CHECK(submember.type.descriptor.type == VarType::Float);
|
||||
CHECK(submember.type.descriptor.rows == 2);
|
||||
CHECK(submember.type.descriptor.columns == 2);
|
||||
CHECK(submember.type.descriptor.rowMajorStorage == false);
|
||||
CHECK(submember.type.descriptor.name == "mat2");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CHECK(ubo_root.type.members[6].name == "ubo_z");
|
||||
{
|
||||
const ShaderConstant &member = ubo_root.type.members[6];
|
||||
INFO("UBO member: " << member.name.c_str());
|
||||
|
||||
CHECK(member.byteOffset == 256);
|
||||
CHECK(member.type.members.empty());
|
||||
CHECK(member.type.descriptor.type == VarType::Float);
|
||||
CHECK(member.type.descriptor.rows == 1);
|
||||
CHECK(member.type.descriptor.columns == 4);
|
||||
CHECK(member.type.descriptor.name == "vec4");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CHECK(refl.constantBlocks[1].name == "$Globals");
|
||||
{
|
||||
const ConstantBlock &cblock = refl.constantBlocks[1];
|
||||
INFO("UBO: " << cblock.name.c_str());
|
||||
|
||||
CHECK(cblock.bindPoint == 1);
|
||||
CHECK(!cblock.bufferBacked);
|
||||
|
||||
REQUIRE_ARRAY_SIZE(cblock.variables.size(), 2);
|
||||
{
|
||||
CHECK(cblock.variables[0].name == "global_var");
|
||||
{
|
||||
const ShaderConstant &member = cblock.variables[0];
|
||||
INFO("UBO member: " << member.name.c_str());
|
||||
|
||||
CHECK(member.type.members.empty());
|
||||
CHECK(member.type.descriptor.type == VarType::Float);
|
||||
CHECK(member.type.descriptor.rows == 1);
|
||||
CHECK(member.type.descriptor.columns == 3);
|
||||
CHECK(member.type.descriptor.elements == 5);
|
||||
CHECK(member.type.descriptor.name == "vec3");
|
||||
}
|
||||
|
||||
CHECK(cblock.variables[1].name == "global_var2");
|
||||
{
|
||||
const ShaderConstant &member = cblock.variables[1];
|
||||
INFO("UBO member: " << member.name.c_str());
|
||||
|
||||
CHECK(member.type.members.empty());
|
||||
CHECK(member.type.descriptor.type == VarType::Float);
|
||||
CHECK(member.type.descriptor.rows == 2);
|
||||
CHECK(member.type.descriptor.columns == 3);
|
||||
CHECK(member.type.descriptor.elements == 3);
|
||||
CHECK(member.type.descriptor.rowMajorStorage == false);
|
||||
CHECK(member.type.descriptor.name == "mat3x2");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
REQUIRE(refl.samplers.empty());
|
||||
REQUIRE(refl.interfaces.empty());
|
||||
|
||||
REQUIRE_ARRAY_SIZE(mapping.inputAttributes.size(), 16);
|
||||
for(size_t i = 0; i < mapping.inputAttributes.size(); i++)
|
||||
{
|
||||
CHECK(mapping.inputAttributes[i] == -1);
|
||||
}
|
||||
|
||||
REQUIRE_ARRAY_SIZE(mapping.readOnlyResources.size(), 2);
|
||||
{
|
||||
// tex2d
|
||||
CHECK(mapping.readOnlyResources[0].bindset == 0);
|
||||
CHECK(mapping.readOnlyResources[0].bind == 3);
|
||||
CHECK(mapping.readOnlyResources[0].arraySize == 1);
|
||||
CHECK(mapping.readOnlyResources[0].used);
|
||||
|
||||
// tex3d
|
||||
CHECK(mapping.readOnlyResources[1].bindset == 0);
|
||||
CHECK(mapping.readOnlyResources[1].bind == 5);
|
||||
CHECK(mapping.readOnlyResources[1].arraySize == 1);
|
||||
CHECK(mapping.readOnlyResources[1].used);
|
||||
}
|
||||
|
||||
REQUIRE_ARRAY_SIZE(mapping.readWriteResources.size(), 2);
|
||||
{
|
||||
// atom
|
||||
CHECK(mapping.readWriteResources[0].bindset == 0);
|
||||
CHECK(mapping.readWriteResources[0].bind == 0);
|
||||
CHECK(mapping.readWriteResources[0].arraySize == 1);
|
||||
CHECK(mapping.readWriteResources[0].used);
|
||||
|
||||
// ssbo
|
||||
CHECK(mapping.readWriteResources[1].bindset == 0);
|
||||
CHECK(mapping.readWriteResources[1].bind == 2);
|
||||
CHECK(mapping.readWriteResources[1].arraySize == 1);
|
||||
CHECK(mapping.readWriteResources[1].used);
|
||||
}
|
||||
|
||||
REQUIRE_ARRAY_SIZE(mapping.constantBlocks.size(), 2);
|
||||
{
|
||||
// ubo
|
||||
CHECK(mapping.constantBlocks[0].bindset == 0);
|
||||
CHECK(mapping.constantBlocks[0].bind == 8);
|
||||
CHECK(mapping.constantBlocks[0].arraySize == 1);
|
||||
CHECK(mapping.constantBlocks[0].used);
|
||||
|
||||
// $Globals
|
||||
CHECK(mapping.constantBlocks[1].bindset == -1);
|
||||
CHECK(mapping.constantBlocks[1].bind == -1);
|
||||
CHECK(mapping.constantBlocks[1].arraySize == 1);
|
||||
CHECK(mapping.constantBlocks[1].used);
|
||||
}
|
||||
|
||||
REQUIRE(mapping.samplers.empty());
|
||||
};
|
||||
|
||||
SECTION("vertex shader fixed function outputs")
|
||||
{
|
||||
std::string source = R"(
|
||||
#version 150 core
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(0, 1, 0, 1);
|
||||
}
|
||||
|
||||
)";
|
||||
|
||||
ShaderReflection refl;
|
||||
ShaderBindpointMapping mapping;
|
||||
MakeOfflineShaderReflection(ShaderStage::Vertex, source, refl, mapping);
|
||||
|
||||
REQUIRE_ARRAY_SIZE(refl.outputSignature.size(), 1);
|
||||
{
|
||||
CHECK(refl.outputSignature[0].varName == "gl_Position");
|
||||
{
|
||||
const SigParameter &sig = refl.outputSignature[0];
|
||||
INFO("signature element: " << sig.varName.c_str());
|
||||
|
||||
CHECK(sig.regIndex == 0);
|
||||
CHECK(sig.systemValue == ShaderBuiltin::Position);
|
||||
CHECK(sig.compType == CompType::Float);
|
||||
CHECK(sig.compCount == 4);
|
||||
CHECK(sig.regChannelMask == 0xf);
|
||||
CHECK(sig.channelUsedMask == 0xf);
|
||||
}
|
||||
}
|
||||
|
||||
std::string source2 = R"(
|
||||
#version 150 core
|
||||
|
||||
void main() {
|
||||
gl_Position = vec4(0, 1, 0, 1);
|
||||
gl_PointSize = 1.5f;
|
||||
}
|
||||
|
||||
)";
|
||||
|
||||
refl = ShaderReflection();
|
||||
mapping = ShaderBindpointMapping();
|
||||
MakeOfflineShaderReflection(ShaderStage::Vertex, source2, refl, mapping);
|
||||
|
||||
REQUIRE_ARRAY_SIZE(refl.outputSignature.size(), 2);
|
||||
{
|
||||
CHECK(refl.outputSignature[0].varName == "gl_Position");
|
||||
{
|
||||
const SigParameter &sig = refl.outputSignature[0];
|
||||
INFO("signature element: " << sig.varName.c_str());
|
||||
|
||||
CHECK(sig.regIndex == 0);
|
||||
CHECK(sig.systemValue == ShaderBuiltin::Position);
|
||||
CHECK(sig.compType == CompType::Float);
|
||||
CHECK(sig.compCount == 4);
|
||||
CHECK(sig.regChannelMask == 0xf);
|
||||
CHECK(sig.channelUsedMask == 0xf);
|
||||
}
|
||||
|
||||
CHECK(refl.outputSignature[1].varName == "gl_PointSize");
|
||||
{
|
||||
const SigParameter &sig = refl.outputSignature[1];
|
||||
INFO("signature element: " << sig.varName.c_str());
|
||||
|
||||
CHECK(sig.regIndex == 0);
|
||||
CHECK(sig.systemValue == ShaderBuiltin::PointSize);
|
||||
CHECK(sig.compType == CompType::Float);
|
||||
CHECK(sig.compCount == 1);
|
||||
CHECK(sig.regChannelMask == 0x1);
|
||||
CHECK(sig.channelUsedMask == 0x1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SECTION("shader input/output blocks")
|
||||
{
|
||||
std::string source = R"(
|
||||
#version 420 core
|
||||
|
||||
layout(triangles) in;
|
||||
layout(triangle_strip, max_vertices = 4) out;
|
||||
|
||||
in gl_PerVertex
|
||||
{
|
||||
vec4 gl_Position;
|
||||
} gl_in[];
|
||||
|
||||
in block
|
||||
{
|
||||
vec2 Texcoord;
|
||||
} In[];
|
||||
|
||||
out gl_PerVertex
|
||||
{
|
||||
vec4 gl_Position;
|
||||
};
|
||||
|
||||
out block
|
||||
{
|
||||
vec2 Texcoord;
|
||||
} Out;
|
||||
|
||||
void main()
|
||||
{
|
||||
for(int i = 0; i < gl_in.length(); ++i)
|
||||
{
|
||||
gl_Position = gl_in[i].gl_Position;
|
||||
Out.Texcoord = In[i].Texcoord;
|
||||
EmitVertex();
|
||||
}
|
||||
EndPrimitive();
|
||||
}
|
||||
|
||||
)";
|
||||
|
||||
ShaderReflection refl;
|
||||
ShaderBindpointMapping mapping;
|
||||
MakeOfflineShaderReflection(ShaderStage::Geometry, source, refl, mapping);
|
||||
|
||||
REQUIRE_ARRAY_SIZE(refl.inputSignature.size(), 2);
|
||||
{
|
||||
CHECK(refl.inputSignature[0].varName == "gl_PerVertex.gl_Position");
|
||||
{
|
||||
const SigParameter &sig = refl.inputSignature[0];
|
||||
INFO("signature element: " << sig.varName.c_str());
|
||||
|
||||
CHECK(sig.regIndex == 0);
|
||||
CHECK(sig.systemValue == ShaderBuiltin::Position);
|
||||
CHECK(sig.compType == CompType::Float);
|
||||
CHECK(sig.compCount == 4);
|
||||
CHECK(sig.regChannelMask == 0xf);
|
||||
CHECK(sig.channelUsedMask == 0xf);
|
||||
}
|
||||
|
||||
CHECK(refl.inputSignature[1].varName == "block.Texcoord");
|
||||
{
|
||||
const SigParameter &sig = refl.inputSignature[1];
|
||||
INFO("signature element: " << sig.varName.c_str());
|
||||
|
||||
CHECK(sig.regIndex == 0);
|
||||
CHECK(sig.systemValue == ShaderBuiltin::Undefined);
|
||||
CHECK(sig.compType == CompType::Float);
|
||||
CHECK(sig.compCount == 2);
|
||||
CHECK(sig.regChannelMask == 0x3);
|
||||
CHECK(sig.channelUsedMask == 0x3);
|
||||
}
|
||||
}
|
||||
|
||||
REQUIRE_ARRAY_SIZE(refl.outputSignature.size(), 2);
|
||||
{
|
||||
CHECK(refl.outputSignature[0].varName == "gl_Position");
|
||||
{
|
||||
const SigParameter &sig = refl.outputSignature[0];
|
||||
INFO("signature element: " << sig.varName.c_str());
|
||||
|
||||
CHECK(sig.regIndex == 0);
|
||||
CHECK(sig.systemValue == ShaderBuiltin::Position);
|
||||
CHECK(sig.compType == CompType::Float);
|
||||
CHECK(sig.compCount == 4);
|
||||
CHECK(sig.regChannelMask == 0xf);
|
||||
CHECK(sig.channelUsedMask == 0xf);
|
||||
}
|
||||
|
||||
CHECK(refl.outputSignature[1].varName == "block.Texcoord");
|
||||
{
|
||||
const SigParameter &sig = refl.outputSignature[1];
|
||||
INFO("signature element: " << sig.varName.c_str());
|
||||
|
||||
CHECK(sig.regIndex == 0);
|
||||
CHECK(sig.systemValue == ShaderBuiltin::Undefined);
|
||||
CHECK(sig.compType == CompType::Float);
|
||||
CHECK(sig.compCount == 2);
|
||||
CHECK(sig.regChannelMask == 0x3);
|
||||
CHECK(sig.channelUsedMask == 0x3);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SECTION("matrix and array outputs")
|
||||
{
|
||||
std::string source = R"(
|
||||
#version 150 core
|
||||
|
||||
out vec3 outarr[3];
|
||||
out mat2 outmat;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = vec4(0, 0, 0, 1);
|
||||
outarr[0] = gl_Position.xyz;
|
||||
outarr[1] = gl_Position.xyz;
|
||||
outarr[2] = gl_Position.xyz;
|
||||
outmat = mat2(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
)";
|
||||
|
||||
ShaderReflection refl;
|
||||
ShaderBindpointMapping mapping;
|
||||
MakeOfflineShaderReflection(ShaderStage::Vertex, source, refl, mapping);
|
||||
|
||||
REQUIRE_ARRAY_SIZE(refl.outputSignature.size(), 6);
|
||||
{
|
||||
CHECK(refl.outputSignature[0].varName == "gl_Position");
|
||||
{
|
||||
const SigParameter &sig = refl.outputSignature[0];
|
||||
INFO("signature element: " << sig.varName.c_str());
|
||||
|
||||
CHECK(sig.regIndex == 0);
|
||||
CHECK(sig.systemValue == ShaderBuiltin::Position);
|
||||
CHECK(sig.compType == CompType::Float);
|
||||
CHECK(sig.compCount == 4);
|
||||
CHECK(sig.regChannelMask == 0xf);
|
||||
CHECK(sig.channelUsedMask == 0xf);
|
||||
}
|
||||
|
||||
CHECK(refl.outputSignature[1].varName == "outarr[0]");
|
||||
{
|
||||
const SigParameter &sig = refl.outputSignature[1];
|
||||
INFO("signature element: " << sig.varName.c_str());
|
||||
|
||||
CHECK(sig.regIndex == 0);
|
||||
CHECK(sig.arrayIndex == 0);
|
||||
CHECK(sig.systemValue == ShaderBuiltin::Undefined);
|
||||
CHECK(sig.compType == CompType::Float);
|
||||
CHECK(sig.compCount == 3);
|
||||
CHECK(sig.regChannelMask == 0x7);
|
||||
CHECK(sig.channelUsedMask == 0x7);
|
||||
}
|
||||
|
||||
CHECK(refl.outputSignature[2].varName == "outarr[1]");
|
||||
{
|
||||
const SigParameter &sig = refl.outputSignature[2];
|
||||
INFO("signature element: " << sig.varName.c_str());
|
||||
|
||||
CHECK(sig.regIndex == 1);
|
||||
CHECK(sig.arrayIndex == 1);
|
||||
CHECK(sig.systemValue == ShaderBuiltin::Undefined);
|
||||
CHECK(sig.compType == CompType::Float);
|
||||
CHECK(sig.compCount == 3);
|
||||
CHECK(sig.regChannelMask == 0x7);
|
||||
CHECK(sig.channelUsedMask == 0x7);
|
||||
}
|
||||
|
||||
CHECK(refl.outputSignature[3].varName == "outarr[2]");
|
||||
{
|
||||
const SigParameter &sig = refl.outputSignature[3];
|
||||
INFO("signature element: " << sig.varName.c_str());
|
||||
|
||||
CHECK(sig.regIndex == 2);
|
||||
CHECK(sig.arrayIndex == 2);
|
||||
CHECK(sig.systemValue == ShaderBuiltin::Undefined);
|
||||
CHECK(sig.compType == CompType::Float);
|
||||
CHECK(sig.compCount == 3);
|
||||
CHECK(sig.regChannelMask == 0x7);
|
||||
CHECK(sig.channelUsedMask == 0x7);
|
||||
}
|
||||
|
||||
CHECK(refl.outputSignature[4].varName == "outmat:row0");
|
||||
{
|
||||
const SigParameter &sig = refl.outputSignature[4];
|
||||
INFO("signature element: " << sig.varName.c_str());
|
||||
|
||||
CHECK(sig.regIndex == 3);
|
||||
CHECK(sig.systemValue == ShaderBuiltin::Undefined);
|
||||
CHECK(sig.compType == CompType::Float);
|
||||
CHECK(sig.compCount == 2);
|
||||
CHECK(sig.regChannelMask == 0x3);
|
||||
CHECK(sig.channelUsedMask == 0x3);
|
||||
}
|
||||
|
||||
CHECK(refl.outputSignature[5].varName == "outmat:row1");
|
||||
{
|
||||
const SigParameter &sig = refl.outputSignature[5];
|
||||
INFO("signature element: " << sig.varName.c_str());
|
||||
|
||||
CHECK(sig.regIndex == 4);
|
||||
CHECK(sig.systemValue == ShaderBuiltin::Undefined);
|
||||
CHECK(sig.compType == CompType::Float);
|
||||
CHECK(sig.compCount == 2);
|
||||
CHECK(sig.regChannelMask == 0x3);
|
||||
CHECK(sig.channelUsedMask == 0x3);
|
||||
}
|
||||
}
|
||||
};
|
||||
TestGLSLReflection(ShaderType::eShaderGLSL, MakeOfflineShaderReflection);
|
||||
|
||||
SECTION("shader stage references")
|
||||
{
|
||||
|
||||
@@ -184,3 +184,53 @@ void AddXFBAnnotations(const ShaderReflection &refl, const SPIRVPatchData &patch
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLED(ENABLE_UNIT_TESTS)
|
||||
|
||||
#include "3rdparty/catch/catch.hpp"
|
||||
#include "data/glsl_shaders.h"
|
||||
#include "glslang_compile.h"
|
||||
|
||||
TEST_CASE("Validate SPIR-V reflection", "[spirv][reflection]")
|
||||
{
|
||||
ShaderType type = ShaderType::eShaderVulkan;
|
||||
auto compiler = [&type](ShaderStage stage, const std::string &source, const std::string &entryPoint,
|
||||
ShaderReflection &refl, ShaderBindpointMapping &mapping) {
|
||||
|
||||
InitSPIRVCompiler();
|
||||
RenderDoc::Inst().RegisterShutdownFunction(&ShutdownSPIRVCompiler);
|
||||
|
||||
std::vector<uint32_t> spirv;
|
||||
SPIRVCompilationSettings settings(type == ShaderType::eShaderVulkan
|
||||
? SPIRVSourceLanguage::VulkanGLSL
|
||||
: SPIRVSourceLanguage::OpenGLGLSL,
|
||||
SPIRVShaderStage(stage));
|
||||
std::string errors = CompileSPIRV(settings, {source}, spirv);
|
||||
|
||||
INFO("SPIR-V compile output: " << errors);
|
||||
|
||||
REQUIRE(!spirv.empty());
|
||||
|
||||
SPVModule spv;
|
||||
ParseSPIRV(spirv.data(), spirv.size(), spv);
|
||||
|
||||
SPIRVPatchData patchData;
|
||||
spv.MakeReflection(type == ShaderType::eShaderVulkan ? GraphicsAPI::Vulkan : GraphicsAPI::OpenGL,
|
||||
stage, entryPoint, refl, mapping, patchData);
|
||||
};
|
||||
|
||||
// test both Vulkan and GL SPIR-V reflection
|
||||
SECTION("Vulkan GLSL reflection")
|
||||
{
|
||||
type = ShaderType::eShaderVulkan;
|
||||
TestGLSLReflection(type, compiler);
|
||||
};
|
||||
|
||||
SECTION("OpenGL GLSL reflection")
|
||||
{
|
||||
type = ShaderType::eShaderGLSPIRV;
|
||||
TestGLSLReflection(type, compiler);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user