mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-28 09:26:52 +00:00
Add test of GL shader debugging
This commit is contained in:
@@ -283,6 +283,7 @@
|
||||
<ClCompile Include="gl\gl_resource_lifetimes.cpp" />
|
||||
<ClCompile Include="gl\gl_runtime_bind_prog_to_pipe.cpp" />
|
||||
<ClCompile Include="gl\gl_separable_geometry_shader.cpp" />
|
||||
<ClCompile Include="gl\gl_shader_debug_zoo.cpp" />
|
||||
<ClCompile Include="gl\gl_shader_editing.cpp" />
|
||||
<ClCompile Include="gl\gl_shader_isa.cpp" />
|
||||
<ClCompile Include="gl\gl_simple_triangle.cpp" />
|
||||
|
||||
@@ -739,6 +739,9 @@
|
||||
<ClCompile Include="d3d11\d3d11_pixel_history.cpp">
|
||||
<Filter>D3D11\demos</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="gl\gl_shader_debug_zoo.cpp">
|
||||
<Filter>OpenGL\demos</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="D3D11">
|
||||
|
||||
@@ -0,0 +1,675 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019-2025 Baldur Karlsson
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include "gl_test.h"
|
||||
|
||||
RD_TEST(GL_Shader_Debug_Zoo, OpenGLGraphicsTest)
|
||||
{
|
||||
static constexpr const char *Description =
|
||||
"Tests shader debugging on GL shaders, focussing on GL-specific functionality that is not "
|
||||
"available or implemented separately from Vulkan.";
|
||||
|
||||
std::string vertex = R"EOSHADER(
|
||||
|
||||
#ifndef LOCATION
|
||||
#define LOCATION layout
|
||||
#endif
|
||||
|
||||
out gl_PerVertex
|
||||
{
|
||||
vec4 gl_Position;
|
||||
};
|
||||
|
||||
LOCATION(location = 0) in vec3 inPosition;
|
||||
LOCATION(location = 1) in vec4 inColor;
|
||||
LOCATION(location = 2) in vec2 inUV;
|
||||
|
||||
LOCATION(location = 1) out vec4 v2fColor;
|
||||
LOCATION(location = 2) out vec2 v2fUV;
|
||||
|
||||
#ifdef MIXED
|
||||
// no location interpolators
|
||||
in float a2v_a;
|
||||
out float v2f_a;
|
||||
#endif
|
||||
|
||||
#ifdef BLOCK
|
||||
LOCATION(location = 3) in float a2v_a;
|
||||
LOCATION(location = 4) in int a2v_b;
|
||||
|
||||
LOCATION(location = 3) out v2fBlock
|
||||
{
|
||||
float a;
|
||||
flat int b;
|
||||
} v2f;
|
||||
#endif
|
||||
|
||||
#ifdef WEIRD_V2F
|
||||
LOCATION(location = 3) in float a2v_a;
|
||||
LOCATION(location = 4) in int a2v_b;
|
||||
|
||||
LOCATION(location = 3) out mat3 v2fMat;
|
||||
LOCATION(location = 6) out float v2fArr[2];
|
||||
#endif
|
||||
#ifdef MULTI
|
||||
LOCATION(location = 8) flat out int v2fInstData;
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = vec4(inPosition.xyz, 1);
|
||||
v2fColor = inColor;
|
||||
v2fUV = inUV;
|
||||
|
||||
#ifdef BLOCK
|
||||
v2f.a = a2v_a;
|
||||
v2f.b = a2v_b;
|
||||
#endif
|
||||
|
||||
#ifdef MIXED
|
||||
v2f_a = a2v_a;
|
||||
#endif
|
||||
|
||||
#ifdef WEIRD_V2F
|
||||
v2fMat = mat3(a2v_a * inPosition.xyz, (a2v_a + 1) * inPosition.xyz, (a2v_a + 2) * inPosition.xyz);
|
||||
v2fArr[0] = sqrt(a2v_a);
|
||||
v2fArr[1] = cos(a2v_a);
|
||||
#endif
|
||||
|
||||
#ifdef MULTI
|
||||
v2fInstData = a2v_b + gl_VertexID/3;
|
||||
if(gl_InstanceID != 1 && a2v_a > 5.0)
|
||||
gl_Position.y += 10.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
)EOSHADER";
|
||||
|
||||
std::string pixel = R"EOSHADER(
|
||||
|
||||
#ifndef LOCATION
|
||||
#define LOCATION layout
|
||||
#endif
|
||||
|
||||
LOCATION(location = 1) in vec4 v2fColor;
|
||||
LOCATION(location = 2) in vec2 v2fUV;
|
||||
|
||||
LOCATION(location = 0) out vec4 outColor;
|
||||
|
||||
#ifdef MIXED
|
||||
// no location interpolators
|
||||
in float v2f_a;
|
||||
#endif
|
||||
|
||||
#ifdef BLOCK
|
||||
LOCATION(location = 3) in v2fBlock
|
||||
{
|
||||
float a;
|
||||
flat int b;
|
||||
} v2f;
|
||||
#endif
|
||||
|
||||
#ifdef WEIRD_V2F
|
||||
LOCATION(location = 3) in mat3 v2fMat;
|
||||
LOCATION(location = 6) in float v2fArr[2];
|
||||
#endif
|
||||
#ifdef MULTI
|
||||
LOCATION(location = 8) flat in int v2fInstData;
|
||||
#endif
|
||||
|
||||
void main()
|
||||
{
|
||||
outColor = v2fColor + v2fUV.xyxy;
|
||||
|
||||
#ifdef BLOCK
|
||||
outColor.r += v2f.a;
|
||||
outColor.g += float(v2f.b);
|
||||
#endif
|
||||
|
||||
#ifdef MIXED
|
||||
outColor.r += v2f_a;
|
||||
#endif
|
||||
|
||||
#ifdef WEIRD_V2F
|
||||
outColor.rgb += v2fMat * outColor.rgb;
|
||||
outColor.g += v2fArr[0] * v2fArr[1];
|
||||
#endif
|
||||
|
||||
#ifdef MULTI
|
||||
if(v2fInstData != 51) discard;
|
||||
#endif
|
||||
}
|
||||
|
||||
)EOSHADER";
|
||||
|
||||
std::string bindingZooVertex = R"EOSHADER(
|
||||
|
||||
#version 460 core
|
||||
|
||||
layout(location = 0) in vec3 inPosition;
|
||||
layout(location = 1) in vec4 inColor;
|
||||
layout(location = 2) in vec2 inUV;
|
||||
|
||||
layout(location = 1) out vec4 v2fColor;
|
||||
layout(location = 2) out vec2 v2fUV;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = vec4(inPosition.xyz, 1);
|
||||
v2fColor = inColor;
|
||||
v2fUV = inUV;
|
||||
}
|
||||
|
||||
)EOSHADER";
|
||||
|
||||
std::string bindingZooPixel = R"EOSHADER(
|
||||
|
||||
#version 460 core
|
||||
|
||||
// have uniforms unused - our glslang recompilation will likely assign these locations but drivers likely won't.
|
||||
uniform int unused;
|
||||
|
||||
// ensure alphabetical order does not match declaration order, also to test that we don't depend on that
|
||||
// by accident
|
||||
uniform vec4 zzzTest;
|
||||
|
||||
uniform mat4 matrix_test;
|
||||
|
||||
uniform float array_test[4];
|
||||
|
||||
struct TestStruct
|
||||
{
|
||||
float a;
|
||||
int b;
|
||||
};
|
||||
|
||||
uniform TestStruct struct_test;
|
||||
|
||||
layout(binding = 0, std140) uniform ubo_test
|
||||
{
|
||||
vec4 data;
|
||||
} ubo;
|
||||
|
||||
layout(binding = 0, std430) buffer ssbo_test
|
||||
{
|
||||
vec4 data;
|
||||
} ssbo;
|
||||
|
||||
layout(binding = 0) uniform sampler2D tex2d_test;
|
||||
layout(binding = 1) uniform samplerBuffer texBuf_test;
|
||||
|
||||
layout(location = 1) in vec4 v2fColor;
|
||||
layout(location = 2) in vec2 v2fUV;
|
||||
|
||||
layout(location = 0) out vec4 outColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 col = vec4(0, 0, 0, 0);
|
||||
col += matrix_test * zzzTest;
|
||||
col.r += array_test[0];
|
||||
col.g += array_test[1];
|
||||
col.b += array_test[2];
|
||||
col.a += array_test[3];
|
||||
col += float(struct_test.b) * struct_test.a;
|
||||
col += ubo.data;
|
||||
col += ssbo.data;
|
||||
col += dFdx(v2fUV).xyxy;
|
||||
col += texture(tex2d_test, v2fUV);
|
||||
col += texelFetch(texBuf_test, int(v2fUV.x*10));
|
||||
outColor = col;
|
||||
}
|
||||
|
||||
)EOSHADER";
|
||||
|
||||
void Prepare(int argc, char **argv)
|
||||
{
|
||||
OpenGLGraphicsTest::Prepare(argc, argv);
|
||||
|
||||
if(!Avail.empty())
|
||||
return;
|
||||
|
||||
if(!SpvCompilationSupported())
|
||||
Avail = InternalSpvCompiler() ? "Internal SPIR-V compiler did not initialise"
|
||||
: "Couldn't find 'glslc' or 'glslangValidator' in PATH - "
|
||||
"required for SPIR-V compilation";
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// initialise, create window, create context, etc
|
||||
if(!Init())
|
||||
return 3;
|
||||
|
||||
GLuint vao = MakeVAO();
|
||||
glBindVertexArray(vao);
|
||||
|
||||
const DefaultA2V tri[9] = {
|
||||
{Vec3f(-1.0f, 1.0f, 0.0f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)},
|
||||
{Vec3f(1.0f, 1.0f, 0.0f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)},
|
||||
{Vec3f(-1.0f, -1.0f, 0.0f), Vec4f(0.0f, 1.0f, 0.0f, 1.0f), Vec2f(1.0f, 0.0f)},
|
||||
|
||||
{Vec3f(-1.0f, 1.0f, 0.0f), Vec4f(0.0f, 0.0f, 1.0f, 1.0f), Vec2f(0.0f, 0.0f)},
|
||||
{Vec3f(1.0f, 1.0f, 0.0f), Vec4f(0.0f, 0.0f, 1.0f, 1.0f), Vec2f(0.0f, 1.0f)},
|
||||
{Vec3f(-1.0f, -1.0f, 0.0f), Vec4f(0.0f, 0.0f, 1.0f, 1.0f), Vec2f(1.0f, 0.0f)},
|
||||
|
||||
{Vec3f(-1.0f, 1.0f, 0.0f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 0.0f)},
|
||||
{Vec3f(1.0f, 1.0f, 0.0f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec2f(0.0f, 1.0f)},
|
||||
{Vec3f(-1.0f, -1.0f, 0.0f), Vec4f(1.0f, 0.0f, 0.0f, 1.0f), Vec2f(1.0f, 0.0f)},
|
||||
};
|
||||
|
||||
GLuint vb = MakeBuffer();
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vb);
|
||||
glBufferStorage(GL_ARRAY_BUFFER, sizeof(tri), tri, 0);
|
||||
|
||||
ConfigureDefaultVAO();
|
||||
|
||||
struct ExtraA2V
|
||||
{
|
||||
float a;
|
||||
int b;
|
||||
};
|
||||
|
||||
const ExtraA2V tri2[6] = {
|
||||
{2.5f, 50}, {3.5f, 7}, {4.5f, 8}, {5.5f, 40}, {6.5f, 50}, {7.5f, 60},
|
||||
};
|
||||
|
||||
GLuint vb2 = MakeBuffer();
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vb2);
|
||||
glBufferStorage(GL_ARRAY_BUFFER, sizeof(tri2), tri2, 0);
|
||||
|
||||
glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, sizeof(ExtraA2V), (void *)(0));
|
||||
glVertexAttribDivisor(3, 1);
|
||||
glVertexAttribIPointer(4, 1, GL_INT, sizeof(ExtraA2V), (void *)(sizeof(float)));
|
||||
glVertexAttribDivisor(4, 1);
|
||||
|
||||
glEnableVertexAttribArray(3);
|
||||
glEnableVertexAttribArray(4);
|
||||
|
||||
std::string vs = "#version 460 core\n";
|
||||
vs += vertex;
|
||||
|
||||
std::string ps = "#version 460 core\n";
|
||||
ps += pixel;
|
||||
|
||||
GLuint spirvprogram = MakeProgram();
|
||||
GLuint spirvStrippedProgram = MakeProgram();
|
||||
|
||||
{
|
||||
GLuint vsShad = glCreateShader(GL_VERTEX_SHADER);
|
||||
GLuint psShad = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
|
||||
std::vector<uint32_t> vsSPIRV =
|
||||
CompileShaderToSpv(vs, SPIRVTarget::opengl, ShaderLang::glsl, ShaderStage::vert, "main");
|
||||
std::vector<uint32_t> fsSPIRV =
|
||||
CompileShaderToSpv(ps, SPIRVTarget::opengl, ShaderLang::glsl, ShaderStage::frag, "main");
|
||||
|
||||
glShaderBinary(1, &vsShad, GL_SHADER_BINARY_FORMAT_SPIR_V, vsSPIRV.data(),
|
||||
(GLsizei)vsSPIRV.size() * 4);
|
||||
glShaderBinary(1, &psShad, GL_SHADER_BINARY_FORMAT_SPIR_V, fsSPIRV.data(),
|
||||
(GLsizei)fsSPIRV.size() * 4);
|
||||
|
||||
std::string entry_point = "main";
|
||||
glSpecializeShaderARB(vsShad, (const GLchar *)entry_point.c_str(), 0, nullptr, nullptr);
|
||||
glSpecializeShaderARB(psShad, (const GLchar *)entry_point.c_str(), 0, nullptr, nullptr);
|
||||
|
||||
glAttachShader(spirvprogram, vsShad);
|
||||
glAttachShader(spirvprogram, psShad);
|
||||
|
||||
glLinkProgram(spirvprogram);
|
||||
|
||||
glDetachShader(spirvprogram, vsShad);
|
||||
glDetachShader(spirvprogram, psShad);
|
||||
|
||||
glDeleteShader(vsShad);
|
||||
glDeleteShader(psShad);
|
||||
|
||||
// strip any OpName/OpMemberName
|
||||
|
||||
for(size_t i = 5; i < vsSPIRV.size();)
|
||||
{
|
||||
uint16_t WordCount = vsSPIRV[i] >> 16;
|
||||
uint16_t opcode = vsSPIRV[i] & 0xffff;
|
||||
|
||||
// OpName / OpMemberName
|
||||
if(opcode == 5 || opcode == 6)
|
||||
{
|
||||
vsSPIRV.erase(vsSPIRV.begin() + i, vsSPIRV.begin() + i + WordCount);
|
||||
continue;
|
||||
}
|
||||
|
||||
i += WordCount;
|
||||
}
|
||||
|
||||
for(size_t i = 5; i < fsSPIRV.size();)
|
||||
{
|
||||
uint16_t WordCount = fsSPIRV[i] >> 16;
|
||||
uint16_t opcode = fsSPIRV[i] & 0xffff;
|
||||
|
||||
// OpName / OpMemberName
|
||||
if(opcode == 5 || opcode == 6)
|
||||
{
|
||||
fsSPIRV.erase(fsSPIRV.begin() + i, fsSPIRV.begin() + i + WordCount);
|
||||
continue;
|
||||
}
|
||||
|
||||
i += WordCount;
|
||||
}
|
||||
|
||||
vsShad = glCreateShader(GL_VERTEX_SHADER);
|
||||
psShad = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
|
||||
glShaderBinary(1, &vsShad, GL_SHADER_BINARY_FORMAT_SPIR_V, vsSPIRV.data(),
|
||||
(GLsizei)vsSPIRV.size() * 4);
|
||||
glShaderBinary(1, &psShad, GL_SHADER_BINARY_FORMAT_SPIR_V, fsSPIRV.data(),
|
||||
(GLsizei)fsSPIRV.size() * 4);
|
||||
|
||||
glSpecializeShaderARB(vsShad, (const GLchar *)entry_point.c_str(), 0, nullptr, nullptr);
|
||||
glSpecializeShaderARB(psShad, (const GLchar *)entry_point.c_str(), 0, nullptr, nullptr);
|
||||
|
||||
glAttachShader(spirvStrippedProgram, vsShad);
|
||||
glAttachShader(spirvStrippedProgram, psShad);
|
||||
|
||||
glLinkProgram(spirvStrippedProgram);
|
||||
|
||||
glDetachShader(spirvStrippedProgram, vsShad);
|
||||
glDetachShader(spirvStrippedProgram, psShad);
|
||||
|
||||
glDeleteShader(vsShad);
|
||||
glDeleteShader(psShad);
|
||||
}
|
||||
|
||||
GLuint simpleModernGLSLProgram = MakeProgram(vs, ps);
|
||||
|
||||
vs = "#version 460 core\n";
|
||||
vs += "#define LOCATION(x)\n";
|
||||
vs += vertex;
|
||||
|
||||
ps = "#version 460 core\n";
|
||||
ps += "#define LOCATION(x)\n";
|
||||
ps += pixel;
|
||||
|
||||
GLuint noLocationGLSLProgram = MakeProgram(vs, ps, "", [](GLuint prog) {
|
||||
glBindAttribLocation(prog, 0, "inPosition");
|
||||
glBindAttribLocation(prog, 1, "inColor");
|
||||
glBindAttribLocation(prog, 2, "inUV");
|
||||
});
|
||||
|
||||
vs = "#version 460 core\n";
|
||||
vs += "#define BLOCK 1\n";
|
||||
vs += vertex;
|
||||
|
||||
ps = "#version 460 core\n";
|
||||
ps += "#define BLOCK 1\n";
|
||||
ps += pixel;
|
||||
|
||||
GLuint blockLocationGLSLProgram = MakeProgram(vs, ps);
|
||||
|
||||
vs = "#version 460 core\n";
|
||||
vs += "#define BLOCK 1\n";
|
||||
vs += "#define LOCATION(x)\n";
|
||||
vs += vertex;
|
||||
|
||||
ps = "#version 460 core\n";
|
||||
ps += "#define BLOCK 1\n";
|
||||
ps += "#define LOCATION(x)\n";
|
||||
ps += pixel;
|
||||
|
||||
GLuint blockNoLocationGLSLProgram = MakeProgram(vs, ps, "", [](GLuint prog) {
|
||||
glBindAttribLocation(prog, 0, "inPosition");
|
||||
glBindAttribLocation(prog, 1, "inColor");
|
||||
glBindAttribLocation(prog, 2, "inUV");
|
||||
glBindAttribLocation(prog, 3, "a2v_a");
|
||||
glBindAttribLocation(prog, 4, "a2v_b");
|
||||
});
|
||||
|
||||
vs = "#version 460 core\n";
|
||||
vs += "#define MIXED 1\n";
|
||||
vs += vertex;
|
||||
|
||||
ps = "#version 460 core\n";
|
||||
ps += "#define MIXED 1\n";
|
||||
ps += pixel;
|
||||
|
||||
GLuint mixedLocationGLSLProgram =
|
||||
MakeProgram(vs, ps, "", [](GLuint prog) { glBindAttribLocation(prog, 3, "a2v_a"); });
|
||||
|
||||
vs = "#version 460 core\n";
|
||||
vs += "#define WEIRD_V2F 1\n";
|
||||
vs += vertex;
|
||||
|
||||
ps = "#version 460 core\n";
|
||||
ps += "#define WEIRD_V2F 1\n";
|
||||
ps += pixel;
|
||||
|
||||
GLuint weirdLocationGLSLProgram = MakeProgram(vs, ps);
|
||||
|
||||
GLuint pipeline = MakePipeline();
|
||||
GLuint pipelineVert = MakePipelineProgram(GL_VERTEX_SHADER, vs);
|
||||
GLuint pipelinePix = MakePipelineProgram(GL_FRAGMENT_SHADER, ps);
|
||||
glUseProgramStages(pipeline, GL_VERTEX_SHADER_BIT, pipelineVert);
|
||||
glUseProgramStages(pipeline, GL_FRAGMENT_SHADER_BIT, pipelinePix);
|
||||
|
||||
vs = "#version 460 core\n";
|
||||
vs += "#define WEIRD_V2F 1\n";
|
||||
vs += "#define MULTI 1\n";
|
||||
vs += vertex;
|
||||
|
||||
ps = "#version 460 core\n";
|
||||
ps += "#define WEIRD_V2F 1\n";
|
||||
ps += "#define MULTI 1\n";
|
||||
ps += pixel;
|
||||
|
||||
GLuint multiGLSLProgram = MakeProgram(vs, ps);
|
||||
|
||||
vs = "#version 460 core\n";
|
||||
vs += "#define WEIRD_V2F 1\n";
|
||||
vs += "#define LOCATION(x)\n";
|
||||
vs += vertex;
|
||||
|
||||
ps = "#version 460 core\n";
|
||||
ps += "#define WEIRD_V2F 1\n";
|
||||
ps += "#define LOCATION(x)\n";
|
||||
ps += pixel;
|
||||
|
||||
GLuint weirdNoLocationGLSLProgram = MakeProgram(vs, ps, "", [](GLuint prog) {
|
||||
glBindAttribLocation(prog, 0, "inPosition");
|
||||
glBindAttribLocation(prog, 1, "inColor");
|
||||
glBindAttribLocation(prog, 2, "inUV");
|
||||
glBindAttribLocation(prog, 3, "a2v_a");
|
||||
glBindAttribLocation(prog, 4, "a2v_b");
|
||||
});
|
||||
|
||||
GLuint bindingZooProgram = MakeProgram(bindingZooVertex, bindingZooPixel);
|
||||
(void)bindingZooProgram;
|
||||
|
||||
glUseProgram(bindingZooProgram);
|
||||
|
||||
glUniform4f(glGetUniformLocation(bindingZooProgram, "zzzTest"), 0.2f, 0.3f, 0.4f, 0.5f);
|
||||
float mat[16] = {};
|
||||
for(int i = 0; i < 16; i++)
|
||||
mat[i] = 0.6f + float(i) / 10.0f;
|
||||
glUniformMatrix4fv(glGetUniformLocation(bindingZooProgram, "matrix_test"), 1, GL_FALSE, mat);
|
||||
float arr[4] = {};
|
||||
for(int i = 0; i < 4; i++)
|
||||
arr[i] = 2.1f + float(i) / 10.0f;
|
||||
glUniform1fv(glGetUniformLocation(bindingZooProgram, "array_test"), 4, arr);
|
||||
glUniform1f(glGetUniformLocation(bindingZooProgram, "struct_test.a"), 9.9f);
|
||||
glUniform1i(glGetUniformLocation(bindingZooProgram, "struct_test.b"), 99);
|
||||
|
||||
const size_t bindOffset = 16;
|
||||
|
||||
Vec4f cbufferdata[1024 + bindOffset];
|
||||
|
||||
for(int i = 0; i < bindOffset; i++)
|
||||
cbufferdata[i] = Vec4f(-99.9f, -88.8f, -77.7f, -66.6f);
|
||||
|
||||
for(int i = 0; i < 1024; i++)
|
||||
cbufferdata[bindOffset + i] =
|
||||
Vec4f(float(i * 4 + 0), float(i * 4 + 1), float(i * 4 + 2), float(i * 4 + 3));
|
||||
|
||||
GLuint cb = MakeBuffer();
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, cb);
|
||||
glBufferStorage(GL_UNIFORM_BUFFER, sizeof(cbufferdata), cbufferdata, GL_MAP_WRITE_BIT);
|
||||
|
||||
glBindBufferRange(GL_UNIFORM_BUFFER, 0, cb, bindOffset * sizeof(Vec4f), 16 * sizeof(Vec4f));
|
||||
|
||||
GLuint ssbo = MakeBuffer();
|
||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
|
||||
glBufferStorage(GL_SHADER_STORAGE_BUFFER, sizeof(cbufferdata), cbufferdata, GL_MAP_WRITE_BIT);
|
||||
|
||||
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 0, ssbo, bindOffset * sizeof(Vec4f) * 2,
|
||||
16 * sizeof(Vec4f));
|
||||
|
||||
GLuint tbuf_store = MakeBuffer();
|
||||
glBindBuffer(GL_TEXTURE_BUFFER, tbuf_store);
|
||||
glBufferStorage(GL_TEXTURE_BUFFER, sizeof(Vec4f) * 16,
|
||||
cbufferdata + bindOffset * sizeof(Vec4f) * 3, 0);
|
||||
|
||||
GLuint tbuf = MakeTexture();
|
||||
glBindTexture(GL_TEXTURE_BUFFER, tbuf);
|
||||
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGB32F, tbuf_store);
|
||||
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_BUFFER, tbuf);
|
||||
|
||||
Texture rgba8;
|
||||
LoadXPM(SmileyTexture, rgba8);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
GLuint smiley = MakeTexture();
|
||||
glBindTexture(GL_TEXTURE_2D, smiley);
|
||||
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, rgba8.width, rgba8.height);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, rgba8.width, rgba8.height, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
rgba8.data.data());
|
||||
|
||||
// render offscreen to make picked values accurate
|
||||
GLuint fbo = MakeFBO();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
|
||||
// Color render texture
|
||||
GLuint colattach = MakeTexture();
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, colattach);
|
||||
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, screenWidth, screenHeight);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colattach, 0);
|
||||
|
||||
while(Running())
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
|
||||
float col[] = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
glClearBufferfv(GL_COLOR, 0, col);
|
||||
|
||||
glBindVertexArray(vao);
|
||||
|
||||
int test = 0;
|
||||
|
||||
pushMarker("GLSL tests");
|
||||
{
|
||||
glViewport(test * 4, screenHeight - 4, 4, 4);
|
||||
test++;
|
||||
glUseProgram(simpleModernGLSLProgram);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
|
||||
glViewport(test * 4, screenHeight - 4, 4, 4);
|
||||
test++;
|
||||
glUseProgram(noLocationGLSLProgram);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
|
||||
glViewport(test * 4, screenHeight - 4, 4, 4);
|
||||
test++;
|
||||
glUseProgram(blockLocationGLSLProgram);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
|
||||
glViewport(test * 4, screenHeight - 4, 4, 4);
|
||||
test++;
|
||||
glUseProgram(blockNoLocationGLSLProgram);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
|
||||
glViewport(test * 4, screenHeight - 4, 4, 4);
|
||||
test++;
|
||||
glUseProgram(mixedLocationGLSLProgram);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
|
||||
glViewport(test * 4, screenHeight - 4, 4, 4);
|
||||
test++;
|
||||
glUseProgram(weirdLocationGLSLProgram);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
|
||||
glViewport(test * 4, screenHeight - 4, 4, 4);
|
||||
test++;
|
||||
glUseProgram(multiGLSLProgram);
|
||||
glDrawArraysInstancedBaseInstance(GL_TRIANGLES, 3, 3, 3, 3);
|
||||
|
||||
glViewport(test * 4, screenHeight - 4, 4, 4);
|
||||
test++;
|
||||
glUseProgram(multiGLSLProgram);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 9);
|
||||
|
||||
glViewport(test * 4, screenHeight - 4, 4, 4);
|
||||
test++;
|
||||
glUseProgram(weirdNoLocationGLSLProgram);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
|
||||
glViewport(test * 4, screenHeight - 4, 4, 4);
|
||||
test++;
|
||||
glUseProgram(bindingZooProgram);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
|
||||
glViewport(test * 4, screenHeight - 4, 4, 4);
|
||||
test++;
|
||||
glUseProgram(0);
|
||||
glBindProgramPipeline(pipeline);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
|
||||
glBindProgramPipeline(0);
|
||||
}
|
||||
popMarker();
|
||||
|
||||
pushMarker("SPIRV tests");
|
||||
{
|
||||
glViewport(test * 4, screenHeight - 4, 4, 4);
|
||||
test++;
|
||||
glUseProgram(spirvprogram);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
|
||||
glViewport(test * 4, screenHeight - 4, 4, 4);
|
||||
test++;
|
||||
glUseProgram(spirvStrippedProgram);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
}
|
||||
popMarker();
|
||||
|
||||
glBlitNamedFramebuffer(fbo, 0, 0, 0, screenWidth, screenHeight, 0, 0, screenWidth,
|
||||
screenHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
|
||||
Present();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST();
|
||||
@@ -143,7 +143,8 @@ void OpenGLGraphicsTest::Shutdown()
|
||||
delete mainWindow;
|
||||
}
|
||||
|
||||
GLuint OpenGLGraphicsTest::MakeProgram(std::string vertSrc, std::string fragSrc, std::string geomSrc)
|
||||
GLuint OpenGLGraphicsTest::MakeProgram(std::string vertSrc, std::string fragSrc,
|
||||
std::string geomSrc, std::function<void(GLuint)> prelink)
|
||||
{
|
||||
GLuint vs = vertSrc.empty() ? 0 : glCreateShader(GL_VERTEX_SHADER);
|
||||
GLuint fs = fragSrc.empty() ? 0 : glCreateShader(GL_FRAGMENT_SHADER);
|
||||
@@ -232,6 +233,9 @@ GLuint OpenGLGraphicsTest::MakeProgram(std::string vertSrc, std::string fragSrc,
|
||||
if(!vs || !fs)
|
||||
glProgramParameteri(program, GL_PROGRAM_SEPARABLE, GL_TRUE);
|
||||
|
||||
if(prelink)
|
||||
prelink(program);
|
||||
|
||||
glLinkProgram(program);
|
||||
|
||||
glGetProgramiv(program, GL_LINK_STATUS, &status);
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "3rdparty/glad/glad.h"
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
struct OpenGLGraphicsTest : public GraphicsTest
|
||||
@@ -44,7 +45,8 @@ struct OpenGLGraphicsTest : public GraphicsTest
|
||||
|
||||
void PostInit();
|
||||
|
||||
GLuint MakeProgram(std::string vertSrc, std::string fragSrc, std::string geomSrc = "");
|
||||
GLuint MakeProgram(std::string vertSrc, std::string fragSrc, std::string geomSrc = "",
|
||||
std::function<void(GLuint)> prelink = {});
|
||||
GLuint MakeProgram(std::string compSrc);
|
||||
GLuint MakeProgram();
|
||||
GLuint MakePipelineProgram(GLenum type, std::string src);
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
import renderdoc as rd
|
||||
from typing import List
|
||||
import rdtest
|
||||
|
||||
|
||||
class GL_Shader_Debug_Zoo(rdtest.TestCase):
|
||||
demos_test_name = 'GL_Shader_Debug_Zoo'
|
||||
|
||||
def check_capture(self):
|
||||
if not self.controller.GetAPIProperties().shaderDebugging:
|
||||
rdtest.log.success("Shader debugging not enabled, skipping test")
|
||||
return
|
||||
|
||||
failed = False
|
||||
|
||||
x = -3
|
||||
for child in ["GLSL tests", "SPIRV tests"]:
|
||||
rdtest.log.begin_section(child)
|
||||
section = self.find_action(child)
|
||||
for test in range(len(section.children)):
|
||||
action = section.children[test]
|
||||
|
||||
if not (action.flags & rd.ActionFlags.Drawcall):
|
||||
continue
|
||||
|
||||
x += 4
|
||||
|
||||
self.controller.SetFrameEvent(action.eventId, False)
|
||||
pipe: rd.PipeState = self.controller.GetPipelineState()
|
||||
|
||||
if not pipe.GetShaderReflection(rd.ShaderStage.Vertex).debugInfo.debuggable:
|
||||
rdtest.log.print("Skipping undebuggable shader at {} in {}.".format(test, child))
|
||||
return
|
||||
|
||||
if not pipe.GetShaderReflection(rd.ShaderStage.Pixel).debugInfo.debuggable:
|
||||
rdtest.log.print("Skipping undebuggable shader at {} in {}.".format(test, child))
|
||||
return
|
||||
|
||||
y = 1
|
||||
|
||||
inputs = rd.DebugPixelInputs()
|
||||
inputs.primitive = 0
|
||||
inputs.sample = 0
|
||||
|
||||
if action.numIndices > 3:
|
||||
rdtest.log.print("prim 1")
|
||||
inputs.primitive = 1
|
||||
|
||||
# Debug the shader
|
||||
trace: rd.ShaderDebugTrace = self.controller.DebugPixel(x, y, inputs)
|
||||
|
||||
rdtest.log.print(f"debugging {x},{y}")
|
||||
|
||||
if trace.debugger is None:
|
||||
failed = True
|
||||
rdtest.log.error("Test {} in sub-section {} did not debug pixel".format(test, child))
|
||||
self.controller.FreeTrace(trace)
|
||||
continue
|
||||
|
||||
_, variables = self.process_trace(trace)
|
||||
|
||||
output: rd.SourceVariableMapping = self.find_output_source_var(trace, rd.ShaderBuiltin.ColorOutput, 0)
|
||||
|
||||
debugged = self.evaluate_source_var(output, variables)
|
||||
|
||||
try:
|
||||
self.check_pixel_value(pipe.GetOutputTargets()[0].resource, x, y, debugged.value.f32v[0:4])
|
||||
except rdtest.TestFailureException as ex:
|
||||
failed = True
|
||||
rdtest.log.error("Test {} in sub-section {} did not match pixel. {}".format(test, child, str(ex)))
|
||||
continue
|
||||
finally:
|
||||
self.controller.FreeTrace(trace)
|
||||
|
||||
rdtest.log.success("Test {} pixel in sub-section {} matched as expected".format(test, child))
|
||||
|
||||
vtx = 1
|
||||
inst = 0
|
||||
idx = vtx
|
||||
|
||||
if action.flags & rd.ActionFlags.Instanced:
|
||||
inst = 1
|
||||
|
||||
if action.flags & rd.ActionFlags.Indexed:
|
||||
ib = pipe.GetIBuffer()
|
||||
|
||||
mesh = rd.MeshFormat()
|
||||
mesh.indexResourceId = ib.resourceId
|
||||
mesh.indexByteStride = ib.byteStride
|
||||
mesh.indexByteOffset = ib.byteOffset + action.indexOffset * ib.byteStride
|
||||
mesh.indexByteSize = ib.byteSize
|
||||
mesh.baseVertex = action.baseVertex
|
||||
|
||||
indices = rdtest.fetch_indices(self.controller, action, mesh, 0, vtx, 1)
|
||||
|
||||
idx = indices[1]
|
||||
|
||||
postvs = self.get_postvs(action, rd.MeshDataStage.VSOut, first_index=vtx, num_indices=1, instance=inst)
|
||||
|
||||
trace: rd.ShaderDebugTrace = self.controller.DebugVertex(vtx, inst, idx, 0)
|
||||
|
||||
if trace.debugger is None:
|
||||
failed = True
|
||||
rdtest.log.error("Test {} in sub-section {} did not debug vertex".format(test, child))
|
||||
self.controller.FreeTrace(trace)
|
||||
continue
|
||||
|
||||
_, variables = self.process_trace(trace)
|
||||
|
||||
outputs = 0
|
||||
|
||||
for var in trace.sourceVars:
|
||||
var: rd.SourceVariableMapping
|
||||
if var.variables[0].type == rd.DebugVariableType.Variable and var.signatureIndex >= 0:
|
||||
name = var.name
|
||||
|
||||
if name not in postvs[0].keys():
|
||||
name = name.replace(".", "Block.")
|
||||
if name not in postvs[0].keys():
|
||||
failed = True
|
||||
rdtest.log.error("Don't have expected output for {}".format(name))
|
||||
continue
|
||||
|
||||
expect = postvs[0][name]
|
||||
value = self.evaluate_source_var(var, variables)
|
||||
|
||||
if len(expect) != value.columns:
|
||||
failed = True
|
||||
rdtest.log.error(
|
||||
"Output {} at EID {} has different size ({} values) to expectation ({} values)"
|
||||
.format(name, action.eventId, value.columns, len(expect)))
|
||||
continue
|
||||
|
||||
compType = rd.VarTypeCompType(value.type)
|
||||
if compType == rd.CompType.UInt:
|
||||
debugged = list(value.value.u32v[0:value.columns])
|
||||
elif compType == rd.CompType.SInt:
|
||||
debugged = list(value.value.s32v[0:value.columns])
|
||||
else:
|
||||
debugged = list(value.value.f32v[0:value.columns])
|
||||
|
||||
if not rdtest.value_compare(expect, debugged):
|
||||
failed = True
|
||||
rdtest.log.error("Test {} in sub-section {} did not match vertex.\nExpected {} but got {}".format(test, child, expect, debugged))
|
||||
break
|
||||
|
||||
is_eq, diff_amt = rdtest.value_compare_diff(expect, debugged, eps=5.0E-06)
|
||||
if not is_eq:
|
||||
failed = True
|
||||
rdtest.log.error(
|
||||
"Debugged value {} at EID {} vert {} (idx {}) instance {}: {} difference. {} doesn't exactly match postvs output {}".format(
|
||||
name, action.eventId, vtx, idx, inst, diff_amt, debugged, expect))
|
||||
|
||||
outputs = outputs + 1
|
||||
|
||||
self.controller.FreeTrace(trace)
|
||||
|
||||
rdtest.log.success("Test {} vertex in sub-section {} matched as expected".format(test, child))
|
||||
|
||||
rdtest.log.end_section(child)
|
||||
|
||||
if failed:
|
||||
raise rdtest.TestFailureException("Some tests were not as expected")
|
||||
|
||||
rdtest.log.success("All tests matched")
|
||||
Reference in New Issue
Block a user