mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-06 14:51:04 +00:00
Try to compile GLSL shaders to SPIR-V to enable debugging
This commit is contained in:
@@ -732,6 +732,13 @@ public:
|
||||
rdcarray<uint32_t> spirvWords;
|
||||
SPIRVPatchData patchData;
|
||||
|
||||
// used if the application uploaded GLSL but we were able to compile to SPIR-V
|
||||
bool convertedSPIRV = false;
|
||||
bool convertedAutomapped = false;
|
||||
rdcarray<uint32_t> convertedSpirvWords;
|
||||
SPIRVPatchData convertedPatchData;
|
||||
ShaderReflection convertedRefl;
|
||||
|
||||
// the parameters passed to glSpecializeShader
|
||||
rdcstr entryPoint;
|
||||
rdcarray<uint32_t> specIDs;
|
||||
|
||||
@@ -819,7 +819,8 @@ rdcstr GLReplay::DisassembleShader(ResourceId pipeline, const ShaderReflection *
|
||||
ResourceId liveId = m_pDriver->GetResourceManager()->GetLiveID(refl->resourceId);
|
||||
const WrappedOpenGL::ShaderData &shaderDetails = m_pDriver->GetShader(liveId);
|
||||
|
||||
if(shaderDetails.sources.empty() && shaderDetails.spirvWords.empty())
|
||||
if(shaderDetails.sources.empty() && shaderDetails.spirvWords.empty() &&
|
||||
shaderDetails.convertedSpirvWords.empty())
|
||||
return "; Invalid Shader Specified";
|
||||
|
||||
if(target == SPIRVDisassemblyTarget || target.empty())
|
||||
|
||||
@@ -1253,7 +1253,9 @@ void MakeShaderReflection(GLenum shadType, GLuint sepProg, ShaderReflection &ref
|
||||
refl.debugInfo.compiler = KnownShaderTool::Unknown;
|
||||
refl.debugInfo.encoding = ShaderEncoding::GLSL;
|
||||
refl.debugInfo.debuggable = false;
|
||||
refl.debugInfo.debugStatus = "Shader debugging not supported for GLSL shaders";
|
||||
refl.debugInfo.debugStatus =
|
||||
"Shader debugging not supported for legacy GLSL shaders.\n"
|
||||
"Only modern GLSL compatible with SPIR-V compilation can be debugged.";
|
||||
|
||||
if(shadType == eGL_COMPUTE_SHADER)
|
||||
{
|
||||
|
||||
@@ -2033,8 +2033,12 @@ void SetInputs(out Inputs inputs) {}
|
||||
inputDecl += "struct Inputs {\n";
|
||||
inputFetch += "void SetInputs(out Inputs inputs) {\n";
|
||||
|
||||
const ShaderReflection *refl = shadDetails.GetReflection();
|
||||
const SPIRVPatchData &patchData = shadDetails.patchData;
|
||||
// use the converted SPIR-V compiled reflection as it's more likely to have accurate data -
|
||||
// driver reflection can omit inputs even if they're declared and needed for matching
|
||||
const ShaderReflection *refl =
|
||||
shadDetails.convertedSPIRV ? &shadDetails.convertedRefl : shadDetails.GetReflection();
|
||||
const SPIRVPatchData &patchData =
|
||||
shadDetails.convertedSPIRV ? shadDetails.convertedPatchData : shadDetails.patchData;
|
||||
|
||||
rdcarray<rdcpair<rdcstr, size_t>> blockVarsToDeclare;
|
||||
|
||||
@@ -2850,7 +2854,10 @@ ShaderDebugTrace *GLReplay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t y,
|
||||
for(size_t i = 0; i < shadDetails.specIDs.size() && i < shadDetails.specValues.size(); i++)
|
||||
spec.push_back(SpecConstant(shadDetails.specIDs[i], shadDetails.specValues[i], 4));
|
||||
|
||||
const ShaderReflection *refl = shadDetails.GetReflection();
|
||||
// use converted reflection unless we had native SPIR-V reflection because the input fetcher will
|
||||
// use it as well and we might have extra inputs (that were stripped from the driver's GL reflection)
|
||||
const ShaderReflection *refl =
|
||||
shadDetails.convertedSPIRV ? &shadDetails.convertedRefl : shadDetails.GetReflection();
|
||||
|
||||
if(!refl->debugInfo.debuggable)
|
||||
{
|
||||
@@ -2865,7 +2872,10 @@ ShaderDebugTrace *GLReplay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t y,
|
||||
SubgroupSupport subgroupSupport = SubgroupSupport::None;
|
||||
uint32_t numThreads = 4;
|
||||
|
||||
if(shadDetails.patchData.threadScope & rdcspv::ThreadScope::Subgroup)
|
||||
const SPIRVPatchData &patchData =
|
||||
shadDetails.convertedSPIRV ? shadDetails.convertedPatchData : shadDetails.patchData;
|
||||
|
||||
if(patchData.threadScope & rdcspv::ThreadScope::Subgroup)
|
||||
{
|
||||
uint32_t maxSubgroupSize = 1;
|
||||
CalculateSubgroupProperties(maxSubgroupSize, subgroupSupport);
|
||||
@@ -2926,7 +2936,7 @@ ShaderDebugTrace *GLReplay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t y,
|
||||
}
|
||||
|
||||
uint32_t paramAlign, structStride;
|
||||
rdctie(paramAlign, structStride) = GetAlignAndOutputSize(refl, shadDetails.patchData);
|
||||
rdctie(paramAlign, structStride) = GetAlignAndOutputSize(refl, patchData);
|
||||
|
||||
// struct size is ResultDataBase header plus Nx structStride for the number of threads
|
||||
uint32_t structSize = sizeof(rdcspv::ResultDataBase) + structStride * numThreads;
|
||||
@@ -3112,7 +3122,8 @@ ShaderDebugTrace *GLReplay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t y,
|
||||
if(winner)
|
||||
{
|
||||
rdcspv::Debugger *debugger = new rdcspv::Debugger;
|
||||
debugger->Parse(shadDetails.spirvWords);
|
||||
debugger->Parse(shadDetails.convertedSPIRV ? shadDetails.convertedSpirvWords
|
||||
: shadDetails.spirvWords);
|
||||
|
||||
// the per-thread data immediately follows the rdcspv::ResultDataBase header. Every piece of
|
||||
// data is uniformly aligned, either 16-byte by default or 32-byte if larger components exist.
|
||||
@@ -3121,7 +3132,7 @@ ShaderDebugTrace *GLReplay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t y,
|
||||
|
||||
numThreads = 4;
|
||||
|
||||
if(shadDetails.patchData.threadScope & rdcspv::ThreadScope::Subgroup)
|
||||
if(patchData.threadScope & rdcspv::ThreadScope::Subgroup)
|
||||
{
|
||||
RDCASSERTNOTEQUAL(winner->subgroupSize, 0);
|
||||
numThreads = RDCMAX(numThreads, winner->subgroupSize);
|
||||
@@ -3135,7 +3146,7 @@ ShaderDebugTrace *GLReplay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t y,
|
||||
{
|
||||
byte *value = LaneData + t * structStride;
|
||||
|
||||
if(shadDetails.patchData.threadScope & rdcspv::ThreadScope::Subgroup)
|
||||
if(patchData.threadScope & rdcspv::ThreadScope::Subgroup)
|
||||
{
|
||||
rdcspv::SubgroupLaneData *subgroupData = (rdcspv::SubgroupLaneData *)value;
|
||||
apiWrapper->thread_props[t][(size_t)rdcspv::ThreadProperty::Active] = subgroupData->isActive;
|
||||
@@ -3232,8 +3243,8 @@ ShaderDebugTrace *GLReplay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t y,
|
||||
ShaderVariable(rdcstr(), numThreads, 0U, 0U, 0U);
|
||||
|
||||
ret = debugger->BeginDebug(apiWrapper, ShaderStage::Pixel, entryPoint, spec,
|
||||
shadDetails.spirvInstructionLines, shadDetails.patchData,
|
||||
winner->laneIndex, numThreads, numThreads);
|
||||
shadDetails.spirvInstructionLines, patchData, winner->laneIndex,
|
||||
numThreads, numThreads);
|
||||
apiWrapper->ResetReplay();
|
||||
}
|
||||
else
|
||||
|
||||
@@ -282,18 +282,53 @@ void WrappedOpenGL::ShaderData::ProcessCompilation(WrappedOpenGL &drv, ResourceI
|
||||
|
||||
if(reflected)
|
||||
{
|
||||
rdcarray<uint32_t> spirvwords;
|
||||
|
||||
rdcspv::CompilationSettings settings(rdcspv::InputLanguage::OpenGLGLSL,
|
||||
rdcspv::ShaderStage(ShaderIdx(type)));
|
||||
|
||||
settings.gles = IsGLES;
|
||||
settings.debugInfo = true;
|
||||
|
||||
rdcstr s = rdcspv::Compile(settings, sources, spirvwords);
|
||||
if(!spirvwords.empty())
|
||||
spirv.Parse(spirvwords);
|
||||
rdcstr err = rdcspv::Compile(settings, sources, convertedSpirvWords);
|
||||
if(!convertedSpirvWords.empty())
|
||||
{
|
||||
convertedSPIRV = true;
|
||||
spirv.Parse(convertedSpirvWords);
|
||||
|
||||
spirv.MakeReflection(GraphicsAPI::OpenGL, ShaderStage(ShaderIdx(type)), "main", {},
|
||||
convertedRefl, convertedPatchData);
|
||||
}
|
||||
else
|
||||
disassembly = "Disassembly to SPIR-V failed:\n\n" + s;
|
||||
{
|
||||
// enable automapping and try again
|
||||
settings.autoMapBindings = true;
|
||||
settings.autoMapLocations = true;
|
||||
err = rdcspv::Compile(settings, sources, convertedSpirvWords);
|
||||
|
||||
if(!convertedSpirvWords.empty())
|
||||
{
|
||||
convertedSPIRV = true;
|
||||
convertedAutomapped = true;
|
||||
spirv.Parse(convertedSpirvWords);
|
||||
|
||||
spirv.MakeReflection(GraphicsAPI::OpenGL, ShaderStage(ShaderIdx(type)), "main", {},
|
||||
convertedRefl, convertedPatchData);
|
||||
}
|
||||
else
|
||||
{
|
||||
disassembly = "Disassembly to SPIR-V failed:\n\n" + err;
|
||||
}
|
||||
}
|
||||
|
||||
if(convertedSPIRV)
|
||||
{
|
||||
// we could assert here that convertedRefl looks like the real reflection
|
||||
reflection->debugInfo.debuggable = convertedRefl.debugInfo.debuggable;
|
||||
reflection->debugInfo.debugStatus = convertedRefl.debugInfo.debugStatus;
|
||||
reflection->debugInfo.sourceDebugInformation =
|
||||
convertedRefl.debugInfo.sourceDebugInformation;
|
||||
if(reflection->debugInfo.sourceDebugInformation)
|
||||
reflection->debugInfo.compileFlags.flags.push_back({"preferSourceDebug", "1"});
|
||||
}
|
||||
|
||||
reflection->resourceId = id;
|
||||
|
||||
|
||||
@@ -70,6 +70,15 @@ rdcstr rdcspv::Compile(const rdcspv::CompilationSettings &settings, const rdcarr
|
||||
|
||||
glslang::TShader *shader = new glslang::TShader(lang);
|
||||
|
||||
shader->setAutoMapBindings(settings.autoMapBindings);
|
||||
shader->setAutoMapLocations(settings.autoMapLocations);
|
||||
// glslang internally allows up to 4095 for locations - this gives plenty space for I/O where
|
||||
// only 128 components are allowed max
|
||||
shader->setIOLocationBase(3900);
|
||||
// don't set a limit for uniforms, as we don't know a reasonable value and can't make use of
|
||||
// this information
|
||||
// shader->setUniformLocationBase(0);
|
||||
|
||||
shader->setStringsWithLengthsAndNames(strs, NULL, names, (int)sources.size());
|
||||
|
||||
if(!settings.entryPoint.empty())
|
||||
@@ -102,6 +111,9 @@ rdcstr rdcspv::Compile(const rdcspv::CompilationSettings &settings, const rdcarr
|
||||
|
||||
success = program->link(EShMsgDefault);
|
||||
|
||||
if(success && (settings.autoMapBindings || settings.autoMapLocations))
|
||||
success = program->mapIO();
|
||||
|
||||
if(!success)
|
||||
{
|
||||
errors = "Program failed to link:\n\n";
|
||||
|
||||
@@ -60,6 +60,8 @@ struct CompilationSettings
|
||||
InputLanguage lang = InputLanguage::Unknown;
|
||||
bool debugInfo = false;
|
||||
bool gles = false;
|
||||
bool autoMapBindings = false;
|
||||
bool autoMapLocations = false;
|
||||
rdcstr entryPoint;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user