Fix issues for Android debugging

This commit is contained in:
baldurk
2025-12-02 12:37:19 +00:00
parent ac8b786476
commit d89b763e49
6 changed files with 201 additions and 82 deletions
+2
View File
@@ -49,6 +49,8 @@ Android
OpenGL ES capture and replay on Android is natively supported. For more information on how to capture with Android see :doc:`../how/how_android_capture`.
On many drivers debugging vertex shaders will not be possible due to lack of driver feature support.
OS X
----
+3 -1
View File
@@ -22,18 +22,20 @@
* THE SOFTWARE.
******************************************************************************/
#if defined(OPENGL_CORE)
#extension GL_ARB_compute_shader : require
#extension GL_ARB_shader_storage_buffer_object : require
// safe to assume this extension in compute shaders as it pre-dates compute shaders
#extension GL_ARB_shading_language_420pack : require
#endif
#include "glsl_ubos.h"
uniform vec4 a;
uniform vec4 b;
uniform vec4 c;
uniform uint op;
uniform int op;
layout(binding = 0, std430) buffer Output
{
+87 -43
View File
@@ -24,6 +24,10 @@
#define DEBUGSAMPLE_UBO
#ifdef OPENGL_ES
precision highp float;
#endif
#include "glsl_ubos.h"
#if UINT_TEX
@@ -31,16 +35,18 @@
#define RESULT uvec4
#define FLOAT_CONV(x) floatBitsToUint(x)
uniform usampler1D tex1D;
uniform usampler2D tex2D;
uniform usampler3D tex3D;
uniform usampler1DArray tex1DArray;
uniform usampler2DArray tex2DArray;
uniform usampler2DRect tex2DRect;
uniform usamplerBuffer texBuffer;
uniform PRECISION usampler2D tex2D;
uniform PRECISION usampler3D tex3D;
uniform PRECISION usampler2DArray tex2DArray;
uniform PRECISION usamplerBuffer texBuffer;
#ifdef TEXSAMPLE_MULTISAMPLE
uniform usampler2DMS tex2DMS;
uniform usampler2DMSArray tex2DMSArray;
uniform PRECISION usampler2DMS tex2DMS;
uniform PRECISION usampler2DMSArray tex2DMSArray;
#endif
#ifdef OPENGL_CORE
uniform PRECISION usampler1D tex1D;
uniform PRECISION usampler1DArray tex1DArray;
uniform PRECISION usampler2DRect tex2DRect;
#endif
#elif SINT_TEX
@@ -48,16 +54,18 @@ uniform usampler2DMSArray tex2DMSArray;
#define RESULT ivec4
#define FLOAT_CONV(x) floatBitsToInt(x)
uniform isampler1D tex1D;
uniform isampler2D tex2D;
uniform isampler3D tex3D;
uniform isampler1DArray tex1DArray;
uniform isampler2DArray tex2DArray;
uniform isampler2DRect tex2DRect;
uniform isamplerBuffer texBuffer;
uniform PRECISION isampler2D tex2D;
uniform PRECISION isampler3D tex3D;
uniform PRECISION isampler2DArray tex2DArray;
uniform PRECISION isamplerBuffer texBuffer;
#ifdef TEXSAMPLE_MULTISAMPLE
uniform isampler2DMS tex2DMS;
uniform isampler2DMSArray tex2DMSArray;
uniform PRECISION isampler2DMS tex2DMS;
uniform PRECISION isampler2DMSArray tex2DMSArray;
#endif
#ifdef OPENGL_CORE
uniform PRECISION isampler1D tex1D;
uniform PRECISION isampler1DArray tex1DArray;
uniform PRECISION isampler2DRect tex2DRect;
#endif
#else
@@ -65,31 +73,35 @@ uniform isampler2DMSArray tex2DMSArray;
#define RESULT vec4
#define FLOAT_CONV(x) x
uniform sampler1D tex1D;
uniform sampler2D tex2D;
uniform sampler3D tex3D;
uniform samplerCube texCube;
uniform sampler1DArray tex1DArray;
uniform sampler2DArray tex2DArray;
uniform PRECISION sampler2D tex2D;
uniform PRECISION sampler3D tex3D;
uniform PRECISION samplerCube texCube;
uniform PRECISION sampler2DArray tex2DArray;
#ifdef TEXSAMPLE_CUBE_ARRAY
uniform samplerCubeArray texCubeArray;
uniform PRECISION samplerCubeArray texCubeArray;
#endif
uniform sampler2DRect tex2DRect;
uniform samplerBuffer texBuffer;
uniform PRECISION samplerBuffer texBuffer;
#ifdef TEXSAMPLE_MULTISAMPLE
uniform sampler2DMS tex2DMS;
uniform sampler2DMSArray tex2DMSArray;
uniform PRECISION sampler2DMS tex2DMS;
uniform PRECISION sampler2DMSArray tex2DMSArray;
#endif
#ifdef OPENGL_CORE
uniform PRECISION sampler1D tex1D;
uniform PRECISION sampler1DArray tex1DArray;
uniform PRECISION sampler2DRect tex2DRect;
#endif
uniform sampler1DShadow tex1DShadow;
uniform sampler2DShadow tex2DShadow;
uniform samplerCubeShadow texCubeShadow;
uniform sampler1DArrayShadow tex1DArrayShadow;
uniform sampler2DArrayShadow tex2DArrayShadow;
uniform PRECISION sampler2DShadow tex2DShadow;
uniform PRECISION samplerCubeShadow texCubeShadow;
uniform PRECISION sampler2DArrayShadow tex2DArrayShadow;
#ifdef TEXSAMPLE_CUBE_ARRAY
uniform samplerCubeArrayShadow texCubeArrayShadow;
uniform PRECISION samplerCubeArrayShadow texCubeArrayShadow;
#endif
#ifdef OPENGL_CORE
uniform PRECISION sampler1DShadow tex1DShadow;
uniform PRECISION sampler1DArrayShadow tex1DArrayShadow;
uniform PRECISION sampler2DRectShadow tex2DRectShadow;
#endif
uniform sampler2DRectShadow tex2DRectShadow;
#endif
@@ -113,7 +125,11 @@ const ivec3 fetch_offset = ivec3(0, 0, 0);
RESULT DoFetch1D()
{
#ifdef OPENGL_CORE
return texelFetchOffset(tex1D, debugsample.texel_uvw.x, debugsample.texel_lod, fetch_offset.x);
#else
return RESULT(0, 0, 0, 0);
#endif
}
RESULT DoFetch2D()
@@ -134,8 +150,12 @@ RESULT DoFetchCube()
RESULT DoFetch1DArray()
{
#ifdef OPENGL_CORE
return texelFetchOffset(tex1DArray, debugsample.texel_uvw.xy, debugsample.texel_lod,
fetch_offset.x);
#else
return RESULT(0, 0, 0, 0);
#endif
}
RESULT DoFetch2DArray()
@@ -152,7 +172,11 @@ RESULT DoFetchCubeArray()
RESULT DoFetch2DRect()
{
#ifdef OPENGL_CORE
return texelFetchOffset(tex2DRect, debugsample.texel_uvw.xy, fetch_offset.xy);
#else
return RESULT(0, 0, 0, 0);
#endif
}
RESULT DoFetchBuffer()
@@ -178,6 +202,7 @@ RESULT DoFetch2DMSArray()
///////////////////////////////////
// OpImageQueryLod
#ifdef OPENGL_CORE
RESULT DoQueryLod1D()
{
return RESULT(FLOAT_CONV(textureQueryLod(tex1D, input_uvwa.x)), 0, 0);
@@ -224,13 +249,16 @@ RESULT DoQueryLodCubeArray()
#endif
}
#endif
#endif
///////////////////////////////////
// OpImageSampleExplicitLod (ImplicitLod is upgraded to this)
RESULT DoSample1D()
{
#if ENABLE_MINLOD && USE_GRAD
#ifdef OPENGL_ES
return RESULT(0, 0, 0, 0);
#elif ENABLE_MINLOD && USE_GRAD
return textureGradOffsetClampARB(tex1D, debugsample.uvwa.x, debugsample.ddx_uvw.x,
debugsample.ddy_uvw.x, fetch_offset.x, debugsample.minlod);
#elif USE_GRAD
@@ -290,7 +318,9 @@ RESULT DoSampleCube()
RESULT DoSample1DArray()
{
#if ENABLE_MINLOD && USE_GRAD
#ifdef OPENGL_ES
return RESULT(0, 0, 0, 0);
#elif ENABLE_MINLOD && USE_GRAD
return textureGradOffsetClampARB(tex1DArray, debugsample.uvwa.xy, debugsample.ddx_uvw.x,
debugsample.ddy_uvw.x, fetch_offset.x, debugsample.minlod);
#elif USE_GRAD
@@ -340,8 +370,12 @@ RESULT DoSampleCubeArray()
RESULT DoSample2DRect()
{
#ifdef OPENGL_ES
return RESULT(0, 0, 0, 0);
#else
// fairly degenerate, no lod or grad in use. minlod is illegal
return textureOffset(tex2DRect, debugsample.uvwa.xy, fetch_offset.xy);
#endif
}
///////////////////////////////////
@@ -351,7 +385,9 @@ RESULT DoSampleDref1D()
{
#if FLOAT_TEX
#if ENABLE_MINLOD && USE_GRAD
#ifdef OPENGL_ES
return RESULT(0, 0, 0, 0);
#elif ENABLE_MINLOD && USE_GRAD
return vec4(textureGradOffsetClampARB(
tex1DShadow, vec3(debugsample.uvwa.x, 0, debugsample.compare),
debugsample.ddx_uvw.x, debugsample.ddy_uvw.x, fetch_offset.x, debugsample.minlod),
@@ -429,7 +465,9 @@ RESULT DoSampleDref1DArray()
{
#if FLOAT_TEX
#if ENABLE_MINLOD && USE_GRAD
#ifdef OPENGL_ES
return RESULT(0, 0, 0, 0);
#elif ENABLE_MINLOD && USE_GRAD
return vec4(textureGradOffsetClampARB(
tex1DArrayShadow, vec3(debugsample.uvwa.xy, debugsample.compare),
debugsample.ddx_uvw.x, debugsample.ddy_uvw.x, fetch_offset.x, debugsample.minlod),
@@ -503,7 +541,9 @@ RESULT DoSampleDrefCubeArray()
RESULT DoSampleDref2DRect()
{
#if FLOAT_TEX
#ifdef OPENGL_ES
return RESULT(0, 0, 0, 0);
#elif FLOAT_TEX
// fairly degenerate, no lod or grad in use. minlod is illegal
return vec4(textureOffset(tex2DRectShadow, vec3(debugsample.uvwa.xy, debugsample.compare),
fetch_offset.xy),
@@ -590,7 +630,9 @@ RESULT DoGatherCubeArray()
RESULT DoGather2DRect()
{
#if GATHER_SUPPORT == 0
#ifdef OPENGL_ES
return RESULT(0, 0, 0, 0);
#elif GATHER_SUPPORT == 0
// no gather support at all
return RESULT(0, 0, 0, 0);
#elif GATHER_SUPPORT == 1
@@ -692,7 +734,9 @@ RESULT DoGatherDrefCubeArray()
RESULT DoGatherDref2DRect()
{
#if !FLOAT_TEX
#ifdef OPENGL_ES
return RESULT(0, 0, 0, 0);
#elif !FLOAT_TEX
// shadow samplers only for FLOAT_TEX
return RESULT(0, 0, 0, 0);
#elif GATHER_SUPPORT == 0
+17 -1
View File
@@ -1416,7 +1416,7 @@ GLuint GLReplay::MakeShaderDebugSampleProg(const SamplingProgramConfig &config)
{
glslVersion = 450;
defines += "#extension GL_ARB_sparse_texture_clamp : require\n";
defines += "#define USE_MINLOD 1\n";
defines += "#define ENABLE_MINLOD 1\n";
}
if(HasExt[ARB_gpu_shader5] && HasExt[ARB_texture_gather])
@@ -1435,6 +1435,22 @@ GLuint GLReplay::MakeShaderDebugSampleProg(const SamplingProgramConfig &config)
defines += "#define GATHER_SUPPORT 0\n";
}
}
else
{
defines += "#define ENABLE_MINLOD 0\n";
if(HasExt[ARB_gpu_shader5] && HasExt[ARB_texture_gather])
{
defines += "#define GATHER_SUPPORT 2\n";
}
else if(HasExt[ARB_texture_gather])
{
defines += "#define GATHER_SUPPORT 1\n";
}
else
{
defines += "#define GATHER_SUPPORT 0\n";
}
}
rdcstr vs =
GenerateGLSLShader(GetEmbeddedResource(glsl_shaderdebug_sample_vert), shaderType, glslCSVer);
+64 -37
View File
@@ -1336,7 +1336,7 @@ public:
}
// push the operation afterwards
GL.glUniform1ui(GL.glGetUniformLocation(mathProg, "op"), (uint32_t)op);
GL.glUniform1i(GL.glGetUniformLocation(mathProg, "op"), (int32_t)op);
GL.glDispatchCompute(1, 1, 1);
@@ -2005,12 +2005,12 @@ static GLuint CreateInputFetcher(const WrappedOpenGL::ShaderData &shadDetails,
source += "#define USE_SPIRV 1\n";
source += StringFormat::Fmt(
"#define VALID_MAGIC %u\n"
"#define VALID_MAGIC %uu\n"
"#define STAGE_VS %u\n"
"#define STAGE_PS %u\n"
"#define STAGE_CS %u\n"
"#define STAGE %u\n"
"#define MAXHIT %u\n"
"#define MAXHIT %uu\n"
"#define STORAGE_BINDING %u\n"
"#define NUMLANES %u\n"
"#define USEPRIM %u\n"
@@ -2069,17 +2069,26 @@ static GLuint CreateInputFetcher(const WrappedOpenGL::ShaderData &shadDetails,
}
source += R"EOSHADER(
#extension GL_ARB_shader_storage_buffer_object : require
#ifdef OPENGL_ES
precision highp float;
#endif
#ifdef OPENGL_CORE
#extension GL_ARB_shader_storage_buffer_object : require
#endif
#if PROPER_DERIVS
#extension GL_ARB_derivative_control : require
#endif
#ifdef OPENGL_CORE
#if HELPER && !USE_SPIRV
// required for gl_HelperInvocation, but don't enable with glslang due to a bug -
// we compile at a high enough core version to satisfy the requirement that way
#extension GL_ARB_ES3_1_compatibility : require
#endif
#endif
#if SUBGROUP_BASIC
#extension GL_KHR_shader_subgroup_basic : require
@@ -2098,8 +2107,8 @@ static GLuint CreateInputFetcher(const WrappedOpenGL::ShaderData &shadDetails,
#endif
// bool signature elements get reflected as ints, make macros for their access to cast to int
#define gl_FrontFacing (gl_FrontFacing ? 1 : 0)
#define gl_HelperInvocation (gl_HelperInvocation ? 1 : 0)
#define gl_FrontFacing (gl_FrontFacing ? 1u : 0u)
#define gl_HelperInvocation (gl_HelperInvocation ? 1u : 0u)
)EOSHADER";
@@ -2303,8 +2312,8 @@ void SetInputs(out Inputs inputs) {}
#if STAGE == STAGE_VS
struct VSLaneData
{
uint inst;
uint vert;
int inst;
int vert;
uint view;
uint pad;
};
@@ -2359,8 +2368,8 @@ struct ResultData
{
vec4 pos;
uint prim;
uint rd_sample;
int prim;
int rd_sample;
uint view;
uint valid;
@@ -2382,7 +2391,7 @@ struct ResultData
LaneData laneData[NUMLANES];
};
#if USE_SPIRV
#if USE_SPIRV || defined(OPENGL_ES)
layout(binding = STORAGE_BINDING)
#endif
layout(std140) buffer Output
@@ -2430,13 +2439,13 @@ layout(std140) buffer Output
void main()
{
vec4 debug_pixelPos = vec4(0,0,0,0);
uint primitive = 0;
uint rd_sample = 0;
uint isFrontFace = 0;
int primitive = 0;
int rd_sample = 0;
uint isFrontFace = 0u;
#if STAGE == STAGE_VS
uint vert = gl_VertexID;
uint inst = gl_InstanceID;
int vert = gl_VertexID;
int inst = gl_InstanceID;
#elif STAGE == STAGE_PS
debug_pixelPos = gl_FragCoord;
@@ -2454,27 +2463,27 @@ void main()
#if STAGE == STAGE_VS
VSLaneData vs;
vs.pad = 0;
vs.pad = 0u;
#elif STAGE == STAGE_PS
PSLaneData ps;
ps.pad = 0;
ps.pad = 0u;
#else
CSLaneData cs;
#endif
#if SUBGROUP_BASIC
SubgroupLaneData sub;
sub.elect = subgroupElect() ? 1 : 0;
sub.rd_active = 1;
sub.elect = subgroupElect() ? 1u : 0u;
sub.rd_active = 1u;
#endif
uint isHelper = 0;
uint quadLaneIndex = 0;
uint quadId = 0;
uint laneIndex = 0;
uvec4 globalBallot = uvec4(0,0,0,0);
uvec4 electBallot = uvec4(0,0,0,0);
uvec4 helperBallot = uvec4(0,0,0,0);
uint isHelper = 0u;
uint quadLaneIndex = 0u;
uint quadId = 0u;
uint laneIndex = 0u;
uvec4 globalBallot = uvec4(0u,0u,0u,0u);
uvec4 electBallot = uvec4(0u,0u,0u,0u);
uvec4 helperBallot = uvec4(0u,0u,0u,0u);
float derivValid = 1.0f;
quadLaneIndex = (2u * (uint(debug_pixelPos.y) & 1u)) + (uint(debug_pixelPos.x) & 1u);
@@ -2515,7 +2524,7 @@ void main()
// quadId is a single value that's unique for this quad and uniform across the quad. Degenerate
// for the simple quad case
quadId = 1000+quadSwizzleHelper(laneIndex, quadLaneIndex, 0u);
quadId = 1000u+quadSwizzleHelper(laneIndex, quadLaneIndex, 0u);
LaneData helper0data;
LaneData helper1data;
@@ -2545,7 +2554,7 @@ void main()
for(size_t i = 0; i < floatInputs.size(); i++)
{
source += StringFormat::Fmt(
" helper%udata.inputs.%s = quadSwizzleHelper(%s, quadLaneIndex, %u);\n", q,
" helper%udata.inputs.%s = quadSwizzleHelper(%s, quadLaneIndex, %uu);\n", q,
floatInputs[i].first.c_str(), floatInputs[i].second.c_str(), q);
}
if(!nonfloatInputs.empty())
@@ -2554,7 +2563,7 @@ void main()
for(size_t i = 0; i < nonfloatInputs.size(); i++)
{
source += StringFormat::Fmt(
" helper%udata.inputs.%s = quadSwizzleHelper(%s, quadLaneIndex, %u);\n", q,
" helper%udata.inputs.%s = quadSwizzleHelper(%s, quadLaneIndex, %uu);\n", q,
nonfloatInputs[i].first.c_str(), nonfloatInputs[i].second.c_str(), q);
}
source += "#else\n";
@@ -2595,7 +2604,7 @@ void main()
if(activeSubgroup)
{
if(isHelper == 0)
if(isHelper == 0u)
{
uint idx = MAXHIT;
#if SUBGROUP_BALLOT
@@ -2624,8 +2633,8 @@ void main()
outbuffer.hits[idx].subgroupSize = gl_SubgroupSize;
outbuffer.hits[idx].numSubgroups = gl_NumSubgroups;
#else
outbuffer.hits[idx].subgroupSize = 0;
outbuffer.hits[idx].numSubgroups = 0;
outbuffer.hits[idx].subgroupSize = 0u;
outbuffer.hits[idx].numSubgroups = 0u;
#endif
outbuffer.hits[idx].globalBallot = globalBallot;
outbuffer.hits[idx].electBallot = electBallot;
@@ -2969,7 +2978,23 @@ ShaderDebugTrace *GLReplay::DebugVertex(uint32_t eventId, uint32_t vertid, uint3
GLuint replacementProgram = GL.glCreateProgram();
// don't attach any other shaders since we don't declare outputs anyway and we don't need them
GLuint fragShader = 0;
// on GLES we must have a pixel shader, it's not optional.
if(IsGLES)
{
ShaderType shaderType;
int glslVersion;
int glslBaseVer;
int glslCSVer;
GetGLSLVersions(shaderType, glslVersion, glslBaseVer, glslCSVer);
rdcstr source =
GenerateGLSLShader(GetEmbeddedResource(glsl_fixedcol_frag), shaderType, glslVersion);
fragShader = CreateShader(eGL_FRAGMENT_SHADER, source);
GL.glAttachShader(replacementProgram, fragShader);
}
{
GL.glAttachShader(replacementProgram, inputFetcher);
@@ -2994,7 +3019,7 @@ ShaderDebugTrace *GLReplay::DebugVertex(uint32_t eventId, uint32_t vertid, uint3
GL.glUseProgram(replacementProgram);
if(shadDetails.spirvWords.empty())
if(shadDetails.spirvWords.empty() && !IsGLES)
{
GLuint ssboIdx =
GL.glGetProgramResourceIndex(replacementProgram, eGL_SHADER_STORAGE_BLOCK, "Output");
@@ -3006,6 +3031,8 @@ ShaderDebugTrace *GLReplay::DebugVertex(uint32_t eventId, uint32_t vertid, uint3
GL.glDeleteProgram(replacementProgram);
GL.glDeleteShader(inputFetcher);
if(fragShader)
GL.glDeleteShader(fragShader);
data.resize(feedbackStorageSize);
GL.glGetBufferSubData(eGL_SHADER_STORAGE_BUFFER, 0, feedbackStorageSize, data.data());
@@ -3406,7 +3433,7 @@ ShaderDebugTrace *GLReplay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t y,
GL.glUseProgram(replacementProgram);
if(inputShader)
if(inputShader && !IsGLES)
{
GLuint ssboIdx =
GL.glGetProgramResourceIndex(replacementProgram, eGL_SHADER_STORAGE_BLOCK, "Output");
@@ -3862,7 +3889,7 @@ ShaderDebugTrace *GLReplay::DebugThread(uint32_t eventId, const rdcfixedarray<ui
GL.glUseProgram(replacementProgram);
if(shadDetails.spirvWords.empty())
if(shadDetails.spirvWords.empty() && !IsGLES)
{
GLuint ssboIdx =
GL.glGetProgramResourceIndex(replacementProgram, eGL_SHADER_STORAGE_BLOCK, "Output");
@@ -332,6 +332,34 @@ void WrappedOpenGL::ShaderData::ProcessCompilation(WrappedOpenGL &drv, ResourceI
if(reflection->debugInfo.sourceDebugInformation)
reflection->debugInfo.compileFlags.flags.push_back({"preferSourceDebug", "1"});
if(HasExt[ARB_shader_storage_buffer_object])
{
if(type == eGL_VERTEX_SHADER)
{
GLint numSSBOs = 0;
GL.glGetIntegerv(eGL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &numSSBOs);
if(numSSBOs == 0)
{
reflection->debugInfo.debuggable = false;
reflection->debugInfo.debugStatus =
"Vertex shader debugging not supported on this driver.";
}
}
else if(type == eGL_FRAGMENT_SHADER)
{
GLint numSSBOs = 0;
GL.glGetIntegerv(eGL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &numSSBOs);
if(numSSBOs == 0)
{
reflection->debugInfo.debuggable = false;
reflection->debugInfo.debugStatus =
"Fragment shader debugging not supported on this driver.";
}
}
}
// we must ensure the converted reflection & patch data matches the real reflection so
// that ShaderBindIndex references are consistent. We could do a manual remapping during
// debug to the right index, but ShaderBindIndex's are also baked into variable results.