From dc660aa26cad84b5b1079723811c5d8868a4de89 Mon Sep 17 00:00:00 2001 From: baldurk Date: Thu, 11 Jul 2019 11:50:46 +0100 Subject: [PATCH] Allow building SPIR-V with debug info and check debug info in reflection --- renderdoc/data/glsl_shaders.cpp | 62 +++++++++++++++++++ renderdoc/driver/gl/gl_shader_refl.cpp | 5 ++ renderdoc/driver/gl/wrappers/gl_emulated.cpp | 10 ++- .../driver/gl/wrappers/gl_shader_funcs.cpp | 6 -- .../driver/shaders/spirv/spirv_compile.cpp | 19 +++++- .../driver/shaders/spirv/spirv_compile.h | 1 + .../shaders/spirv/spirv_disassemble.cpp | 1 + .../driver/shaders/spirv/spirv_reflect.cpp | 1 + 8 files changed, 95 insertions(+), 10 deletions(-) diff --git a/renderdoc/data/glsl_shaders.cpp b/renderdoc/data/glsl_shaders.cpp index daea6f63e..d578c9f4a 100644 --- a/renderdoc/data/glsl_shaders.cpp +++ b/renderdoc/data/glsl_shaders.cpp @@ -196,6 +196,11 @@ void main() { ShaderBindpointMapping mapping; compile(ShaderStage::Fragment, source, "main", refl, mapping); + if(testType == ShaderType::eShaderGLSPIRV) + CHECK(refl.encoding == ShaderEncoding::SPIRV); + else + CHECK(refl.encoding == ShaderEncoding::GLSL); + REQUIRE_ARRAY_SIZE(refl.constantBlocks.size(), 1); { CHECK(refl.constantBlocks[0].name == "$Globals"); @@ -308,6 +313,8 @@ void main() { ShaderBindpointMapping mapping; compile(ShaderStage::Fragment, source, "main", refl, mapping); + CHECK(refl.encoding == ShaderEncoding::SPIRV); + REQUIRE_ARRAY_SIZE(refl.samplers.size(), 1); { CHECK(refl.samplers[0].name == "S"); @@ -526,6 +533,61 @@ void main() { RDCFATAL("Unexpected test type"); } + SECTION("Debug information") + { + std::string source = R"( +#version 450 core + +layout(location = 3) in vec2 a_input; +layout(location = 6) flat in uvec3 z_input; + +layout(location = 0) out vec4 a_output; +layout(location = 1) out vec3 z_output; +layout(location = 2) out int b_output; + +void main() { + a_output = vec4(a_input.y + gl_FragCoord.x, 0, 0, 1); + z_output = vec3(a_output.xy, a_output.z); + b_output = int(z_input.x); + gl_FragDepth = float(z_output.y); +} + +)"; + + ShaderReflection refl; + ShaderBindpointMapping mapping; + compile(ShaderStage::Fragment, source, "main", refl, mapping); + + CHECK(refl.entryPoint == "main"); + CHECK(refl.stage == ShaderStage::Fragment); + + CHECK(refl.debugInfo.encoding == ShaderEncoding::GLSL); + + REQUIRE(refl.debugInfo.files.size() == 1); + + CHECK(refl.debugInfo.files[0].contents == source); + + if(testType == eShaderGLSL) + { + CHECK(refl.debugInfo.files[0].filename == "main.glsl"); + } + else + { + CHECK(refl.debugInfo.files[0].filename == "source0.glsl"); + + REQUIRE(refl.debugInfo.compileFlags.flags.size() == 1); + + CHECK(refl.debugInfo.compileFlags.flags[0].name == "@cmdline"); + + if(testType == eShaderGLSPIRV) + CHECK(refl.debugInfo.compileFlags.flags[0].value == + " --client opengl100 --target-env opengl --entry-point main"); + else + CHECK(refl.debugInfo.compileFlags.flags[0].value == + " --client vulkan100 --target-env vulkan1.0 --entry-point main"); + } + }; + SECTION("Input and output signatures") { std::string source = R"( diff --git a/renderdoc/driver/gl/gl_shader_refl.cpp b/renderdoc/driver/gl/gl_shader_refl.cpp index 79483be23..493d56f3f 100644 --- a/renderdoc/driver/gl/gl_shader_refl.cpp +++ b/renderdoc/driver/gl/gl_shader_refl.cpp @@ -1103,6 +1103,11 @@ static void AddSigParameter(std::vector &sigs, uint32_t ®Index, void MakeShaderReflection(GLenum shadType, GLuint sepProg, ShaderReflection &refl, const FixedFunctionVertexOutputs &outputUsage) { + refl.stage = MakeShaderStage(shadType); + refl.entryPoint = "main"; + refl.encoding = ShaderEncoding::GLSL; + refl.debugInfo.encoding = ShaderEncoding::GLSL; + if(shadType == eGL_COMPUTE_SHADER) { GL.glGetProgramiv(sepProg, eGL_COMPUTE_WORK_GROUP_SIZE, (GLint *)refl.dispatchThreadsDimension); diff --git a/renderdoc/driver/gl/wrappers/gl_emulated.cpp b/renderdoc/driver/gl/wrappers/gl_emulated.cpp index 11a7853f9..8e7a0b6de 100644 --- a/renderdoc/driver/gl/wrappers/gl_emulated.cpp +++ b/renderdoc/driver/gl/wrappers/gl_emulated.cpp @@ -3469,6 +3469,10 @@ void MakeOfflineShaderReflection(ShaderStage stage, const std::string &source, MakeShaderReflection(ShaderEnum((size_t)stage), fakeProg, refl, outputUsage); + refl.debugInfo.files.resize(1); + refl.debugInfo.files[0].filename = "main.glsl"; + refl.debugInfo.files[0].contents = source; + // implement some stubs for testing GL.glGetUniformLocation = &_testStub_GetUniformLocation; GL.glGetUniformiv = &_testStub_GetUniformiv; @@ -3488,8 +3492,6 @@ void MakeOfflineShaderReflection(ShaderStage stage, const std::string &source, // helper function that uses the replay proxy system to compile and reflect the shader using the // current driver. Unused by default but you can change the unit test below to call this function // instead of MakeOfflineShaderReflection. -// -// Note that we can't fill out ShaderBindpointMapping easily on the actual driver void MakeOnlineShaderReflection(ShaderStage stage, const std::string &source, const std::string &entryPoint, ShaderReflection &refl, ShaderBindpointMapping &mapping) @@ -3526,6 +3528,10 @@ void MakeOnlineShaderReflection(ShaderStage stage, const std::string &source, refl = *driver->GetShader(id, ShaderEntryPoint("main", ShaderStage::Fragment)); + // Note that we can't fill out ShaderBindpointMapping easily on the actual driver through the + // replay interface + WARN("Using online reflection - all checks with ShaderBindpointMapping will fail"); + driver->FreeCustomShader(id); driver->Shutdown(); diff --git a/renderdoc/driver/gl/wrappers/gl_shader_funcs.cpp b/renderdoc/driver/gl/wrappers/gl_shader_funcs.cpp index d571d6b9d..03a929d48 100644 --- a/renderdoc/driver/gl/wrappers/gl_shader_funcs.cpp +++ b/renderdoc/driver/gl/wrappers/gl_shader_funcs.cpp @@ -272,15 +272,9 @@ void WrappedOpenGL::ShaderData::ProcessCompilation(WrappedOpenGL &drv, ResourceI disassembly = s; reflection.resourceId = id; - reflection.entryPoint = "main"; - reflection.stage = MakeShaderStage(type); - - reflection.encoding = ShaderEncoding::GLSL; reflection.rawBytes.assign((byte *)concatenated.c_str(), concatenated.size()); - reflection.debugInfo.encoding = ShaderEncoding::GLSL; - reflection.debugInfo.files.resize(1); reflection.debugInfo.files[0].filename = "main.glsl"; reflection.debugInfo.files[0].contents = concatenated; diff --git a/renderdoc/driver/shaders/spirv/spirv_compile.cpp b/renderdoc/driver/shaders/spirv/spirv_compile.cpp index 06fd5cb57..70b84f218 100644 --- a/renderdoc/driver/shaders/spirv/spirv_compile.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_compile.cpp @@ -41,9 +41,16 @@ std::string rdcspv::Compile(const rdcspv::CompilationSettings &settings, std::string errors = ""; const char **strs = new const char *[sources.size()]; + const char **names = new const char *[sources.size()]; + std::vector names_str; + names_str.resize(sources.size()); for(size_t i = 0; i < sources.size(); i++) + { strs[i] = sources[i].c_str(); + names_str[i] = StringFormat::Fmt("source%d.glsl", i); + names[i] = names_str[i].c_str(); + } RDCCOMPILE_ASSERT((int)EShLangVertex == (int)rdcspv::ShaderStage::Vertex && (int)EShLangTessControl == (int)rdcspv::ShaderStage::TessControl && @@ -58,7 +65,7 @@ std::string rdcspv::Compile(const rdcspv::CompilationSettings &settings, glslang::TShader *shader = new glslang::TShader(lang); - shader->setStrings(strs, (int)sources.size()); + shader->setStringsWithLengthsAndNames(strs, NULL, names, (int)sources.size()); if(!settings.entryPoint.empty()) shader->setEntryPoint(settings.entryPoint.c_str()); @@ -70,6 +77,9 @@ std::string rdcspv::Compile(const rdcspv::CompilationSettings &settings, if(settings.lang == rdcspv::InputLanguage::VulkanHLSL) flags = EShMessages(flags | EShMsgVulkanRules | EShMsgReadHlsl); + if(settings.debugInfo) + flags = EShMessages(flags | EShMsgDebugInfo); + bool success = shader->parse(GetDefaultResources(), 110, false, flags); if(!success) @@ -101,7 +111,11 @@ std::string rdcspv::Compile(const rdcspv::CompilationSettings &settings, // if we successfully compiled and linked, we must have the stage we started with RDCASSERT(intermediate); - glslang::GlslangToSpv(*intermediate, spirv); + glslang::SpvOptions opts; + if(settings.debugInfo) + opts.generateDebugInfo = true; + + glslang::GlslangToSpv(*intermediate, spirv, &opts); } delete program; @@ -111,6 +125,7 @@ std::string rdcspv::Compile(const rdcspv::CompilationSettings &settings, } delete[] strs; + delete[] names; return errors; } diff --git a/renderdoc/driver/shaders/spirv/spirv_compile.h b/renderdoc/driver/shaders/spirv/spirv_compile.h index e0f91452e..7b08737a4 100644 --- a/renderdoc/driver/shaders/spirv/spirv_compile.h +++ b/renderdoc/driver/shaders/spirv/spirv_compile.h @@ -55,6 +55,7 @@ struct CompilationSettings ShaderStage stage = ShaderStage::Invalid; InputLanguage lang = InputLanguage::Unknown; + bool debugInfo = false; std::string entryPoint; }; diff --git a/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp b/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp index b88caafbc..4f1bab490 100644 --- a/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp @@ -4209,6 +4209,7 @@ void SPVModule::MakeReflection(GraphicsAPI sourceAPI, ShaderStage stage, // VKTODOLOW filter to only functions/resources used by entryPoint reflection.entryPoint = entryPoint; reflection.stage = stage; + reflection.encoding = ShaderEncoding::SPIRV; // TODO sort these so that the entry point is in the first file if(!sourceFiles.empty()) diff --git a/renderdoc/driver/shaders/spirv/spirv_reflect.cpp b/renderdoc/driver/shaders/spirv/spirv_reflect.cpp index 4765cf91b..72f5fe047 100644 --- a/renderdoc/driver/shaders/spirv/spirv_reflect.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_reflect.cpp @@ -218,6 +218,7 @@ TEST_CASE("Validate SPIR-V reflection", "[spirv][reflection]") ? rdcspv::InputLanguage::VulkanGLSL : rdcspv::InputLanguage::OpenGLGLSL, rdcspv::ShaderStage(stage)); + settings.debugInfo = true; std::string errors = rdcspv::Compile(settings, {source}, spirv); INFO("SPIR-V compile output: " << errors);