diff options
| author | Tim Foley <tfoley@nvidia.com> | 2017-07-13 12:10:08 -0700 |
|---|---|---|
| committer | Tim Foley <tfoley@nvidia.com> | 2017-07-13 13:00:38 -0700 |
| commit | 6d7be3694fbaae525b2f4463630c35bed487cd5b (patch) | |
| tree | a9bac151f79bba23df11c90d5906a3009dad29bd | |
| parent | 4bc59f896c9df970ec27a57c397977fc4721d3cd (diff) | |
Add support for dumping intermediates for debugging.
Calling:
spSetDumpIntermedites(compileRequest, true);
will set up a mode where Slang tries to dump every intermediate HLSL, GLSL, DXBC, SPIR-V, etc. file it generates. If SPIR-V or DXBC is requested then we also dump assembly of those.
Right now the files are all named as `slang-<counter>.<ext>`, and get dropped in whatever the working directory is, but I'm open to ideas on how to improve that.
Note: this change introduces a new binary interface to `glslang`, so pulling it requires an updated `glslang.dll`.
| -rw-r--r-- | slang.h | 7 | ||||
| -rw-r--r-- | source/slang/compiler.cpp | 213 | ||||
| -rw-r--r-- | source/slang/compiler.h | 14 | ||||
| -rw-r--r-- | source/slang/slang.cpp | 8 | ||||
| -rw-r--r-- | tools/glslang/glslang.cpp | 69 | ||||
| -rw-r--r-- | tools/glslang/glslang.h | 12 |
6 files changed, 270 insertions, 53 deletions
@@ -170,6 +170,13 @@ extern "C" SlangCompileFlags flags); /*! + @brief Set whether to dump intermediate results (for debugging) or not. + */ + SLANG_API void spSetDumpIntermediates( + SlangCompileRequest* request, + int enable); + + /*! @brief Sets the target for code generation. @param ctx The compilation context. @param target The code generation target. Possible values are: diff --git a/source/slang/compiler.cpp b/source/slang/compiler.cpp index 4c3885ebf..96fccced1 100644 --- a/source/slang/compiler.cpp +++ b/source/slang/compiler.cpp @@ -26,6 +26,10 @@ #include <d3dcompiler.h> #endif +#ifdef _MSC_VER +#pragma warning(disable: 4996) +#endif + #ifdef CreateDirectory #undef CreateDirectory #endif @@ -78,8 +82,6 @@ namespace Slang return Profile::Unknown; } - - // String emitHLSLForEntryPoint( @@ -209,6 +211,7 @@ namespace Slang } auto hlslCode = emitHLSLForEntryPoint(entryPoint); + maybeDumpIntermediate(entryPoint->compileRequest, hlslCode.Buffer(), CodeGenTarget::HLSL); ID3DBlob* codeBlob; ID3DBlob* diagnosticsBlob; @@ -270,8 +273,10 @@ namespace Slang } #endif - String EmitDXBytecodeAssemblyForEntryPoint( - EntryPointRequest* entryPoint) + String dissassembleDXBC( + CompileRequest*, + void const* data, + size_t size) { static pD3DDisassemble D3DDisassemble_ = nullptr; if (!D3DDisassemble_) @@ -283,16 +288,15 @@ namespace Slang assert(D3DDisassemble_); } - List<uint8_t> dxbc = EmitDXBytecodeForEntryPoint(entryPoint); - if (!dxbc.Count()) + if (!data || !size) { return String(); } ID3DBlob* codeBlob; HRESULT hr = D3DDisassemble_( - &dxbc[0], - dxbc.Count(), + data, + size, 0, nullptr, &codeBlob); @@ -312,6 +316,21 @@ namespace Slang return result; } + String EmitDXBytecodeAssemblyForEntryPoint( + EntryPointRequest* entryPoint) + { + + List<uint8_t> dxbc = EmitDXBytecodeForEntryPoint(entryPoint); + if (!dxbc.Count()) + { + return String(); + } + + String result = dissassembleDXBC(entryPoint->compileRequest, dxbc.Buffer(), dxbc.Count()); + + return result; + } + #if 0 String EmitDXBytecodeAssembly( ExtraContext& context) @@ -332,7 +351,6 @@ namespace Slang } #endif - HMODULE getGLSLCompilerDLL() { // TODO(tfoley): let user specify version of glslang DLL to use. @@ -342,11 +360,11 @@ namespace Slang return glslCompiler; } - int invokeGLSLCompilerForEntryPoint( - EntryPointRequest* entryPoint, + + int invokeGLSLCompiler( + CompileRequest* slangCompileRequest, glslang_CompileRequest& request) { - String rawGLSL = emitGLSLForEntryPoint(entryPoint); static glslang_CompileFunc glslang_compile = nullptr; if (!glslang_compile) @@ -364,10 +382,6 @@ namespace Slang (*(String*)userData).append((char const*)data, (char const*)data + size); }; - request.sourcePath = "slang"; - request.sourceText = rawGLSL.begin(); - request.slangStage = (SlangStage)entryPoint->profile.GetStage(); - request.diagnosticFunc = diagnosticOutputFunc; request.diagnosticUserData = &diagnosticOutput; @@ -375,7 +389,7 @@ namespace Slang if (err) { - entryPoint->compileRequest->mSink.diagnoseRaw( + slangCompileRequest->mSink.diagnoseRaw( Severity::Error, diagnosticOutput.begin()); return err; @@ -384,54 +398,79 @@ namespace Slang return 0; } - - List<uint8_t> emitSPIRVForEntryPoint( - EntryPointRequest* entryPoint) + String dissassembleSPIRV( + CompileRequest* slangRequest, + void const* data, + size_t size) { - List<uint8_t> output; + String output; auto outputFunc = [](void const* data, size_t size, void* userData) { - ((List<uint8_t>*)userData)->AddRange((uint8_t*)data, size); + (*(String*)userData).append((char const*)data, (char const*)data + size); }; glslang_CompileRequest request; + request.action = GLSLANG_ACTION_DISSASSEMBLE_SPIRV; + + request.inputBegin = data; + request.inputEnd = (char*)data + size; + request.outputFunc = outputFunc; request.outputUserData = &output; - request.disassembleResult = false; - int err = invokeGLSLCompilerForEntryPoint(entryPoint, request); + int err = invokeGLSLCompiler(slangRequest, request); if (err) { - return List<uint8_t>(); + String(); } return output; } - String emitSPIRVAssemblyForEntryPoint( + List<uint8_t> emitSPIRVForEntryPoint( EntryPointRequest* entryPoint) { - String output; + String rawGLSL = emitGLSLForEntryPoint(entryPoint); + maybeDumpIntermediate(entryPoint->compileRequest, rawGLSL.Buffer(), CodeGenTarget::GLSL); + + List<uint8_t> output; auto outputFunc = [](void const* data, size_t size, void* userData) { - (*(String*)userData).append((char const*)data, (char const*)data + size); + ((List<uint8_t>*)userData)->AddRange((uint8_t*)data, size); }; glslang_CompileRequest request; + request.action = GLSLANG_ACTION_COMPILE_GLSL_TO_SPIRV; + request.sourcePath = "slang"; + request.slangStage = (SlangStage)entryPoint->profile.GetStage(); + + request.inputBegin = rawGLSL.begin(); + request.inputEnd = rawGLSL.end(); + request.outputFunc = outputFunc; request.outputUserData = &output; - request.disassembleResult = true; - int err = invokeGLSLCompilerForEntryPoint(entryPoint, request); + int err = invokeGLSLCompiler(entryPoint->compileRequest, request); if (err) { - String(); + return List<uint8_t>(); } return output; } + + String emitSPIRVAssemblyForEntryPoint( + EntryPointRequest* entryPoint) + { + List<uint8_t> spirv = emitSPIRVForEntryPoint(entryPoint); + if (spirv.Count() == 0) + return String(); + + String result = dissassembleSPIRV(entryPoint->compileRequest, spirv.begin(), spirv.Count()); + return result; + } #endif #if 0 @@ -461,12 +500,14 @@ namespace Slang CompileResult result; auto compileRequest = entryPoint->compileRequest; + auto target = compileRequest->Target; - switch (compileRequest->Target) + switch (target) { case CodeGenTarget::HLSL: { String code = emitHLSLForEntryPoint(entryPoint); + maybeDumpIntermediate(compileRequest, code.Buffer(), target); result = CompileResult(code); } break; @@ -474,6 +515,7 @@ namespace Slang case CodeGenTarget::GLSL: { String code = emitGLSLForEntryPoint(entryPoint); + maybeDumpIntermediate(compileRequest, code.Buffer(), target); result = CompileResult(code); } break; @@ -481,6 +523,7 @@ namespace Slang case CodeGenTarget::DXBytecode: { List<uint8_t> code = EmitDXBytecodeForEntryPoint(entryPoint); + maybeDumpIntermediate(compileRequest, code.Buffer(), code.Count(), target); result = CompileResult(code); } break; @@ -488,6 +531,7 @@ namespace Slang case CodeGenTarget::DXBytecodeAssembly: { String code = EmitDXBytecodeAssemblyForEntryPoint(entryPoint); + maybeDumpIntermediate(compileRequest, code.Buffer(), target); result = CompileResult(code); } break; @@ -495,6 +539,7 @@ namespace Slang case CodeGenTarget::SPIRV: { List<uint8_t> code = emitSPIRVForEntryPoint(entryPoint); + maybeDumpIntermediate(compileRequest, code.Buffer(), code.Count(), target); result = CompileResult(code); } break; @@ -502,6 +547,7 @@ namespace Slang case CodeGenTarget::SPIRVAssembly: { String code = emitSPIRVAssemblyForEntryPoint(entryPoint); + maybeDumpIntermediate(compileRequest, code.Buffer(), target); result = CompileResult(code); } break; @@ -604,4 +650,107 @@ namespace Slang } + // Debug logic for dumping intermediate outputs + + // + + void dumpIntermediate( + CompileRequest*, + void const* data, + size_t size, + char const* ext, + bool isBinary) + { + static int counter = 0; + int id = counter++; + + String path; + path.append("slang-"); + path.append(id); + path.append(ext); + + FILE* file = fopen(path.Buffer(), isBinary ? "wb" : "w"); + if (!file) return; + + fwrite(data, size, 1, file); + fclose(file); + } + + void dumpIntermediateText( + CompileRequest* compileRequest, + void const* data, + size_t size, + char const* ext) + { + dumpIntermediate(compileRequest, data, size, ext, false); + } + + void dumpIntermediateBinary( + CompileRequest* compileRequest, + void const* data, + size_t size, + char const* ext) + { + dumpIntermediate(compileRequest, data, size, ext, true); + } + + void maybeDumpIntermediate( + CompileRequest* compileRequest, + void const* data, + size_t size, + CodeGenTarget target) + { + if (!compileRequest->shouldDumpIntermediates) + return; + + switch (target) + { + default: + break; + + case CodeGenTarget::HLSL: + dumpIntermediateText(compileRequest, data, size, ".hlsl"); + break; + + case CodeGenTarget::GLSL: + dumpIntermediateText(compileRequest, data, size, ".glsl"); + break; + + case CodeGenTarget::SPIRVAssembly: + dumpIntermediateText(compileRequest, data, size, ".spv.asm"); + break; + + case CodeGenTarget::DXBytecodeAssembly: + dumpIntermediateText(compileRequest, data, size, ".dxbc.asm"); + break; + + case CodeGenTarget::SPIRV: + dumpIntermediateBinary(compileRequest, data, size, ".spv"); + { + String spirvAssembly = dissassembleSPIRV(compileRequest, data, size); + dumpIntermediateText(compileRequest, spirvAssembly.begin(), spirvAssembly.Length(), ".spv.asm"); + } + break; + + case CodeGenTarget::DXBytecode: + dumpIntermediateBinary(compileRequest, data, size, ".dxbc"); + { + String dxbcAssembly = dissassembleDXBC(compileRequest, data, size); + dumpIntermediateText(compileRequest, dxbcAssembly.begin(), dxbcAssembly.Length(), ".dxbc.asm"); + } + break; + } + } + + void maybeDumpIntermediate( + CompileRequest* compileRequest, + char const* text, + CodeGenTarget target) + { + if (!compileRequest->shouldDumpIntermediates) + return; + + maybeDumpIntermediate(compileRequest, text, strlen(text), target); + } + } diff --git a/source/slang/compiler.h b/source/slang/compiler.h index 2b440ad85..a7d104b5f 100644 --- a/source/slang/compiler.h +++ b/source/slang/compiler.h @@ -207,6 +207,9 @@ namespace Slang // Compile flags to be shared by all translation units SlangCompileFlags compileFlags = 0; + // Should we dump intermediate results along the way, for debugging? + bool shouldDumpIntermediates = false; + // Output stuff DiagnosticSink mSink; String mDiagnosticOutput; @@ -277,6 +280,17 @@ namespace Slang void generateOutput( CompileRequest* compileRequest); + + // Helper to dump intermediate output when debugging + void maybeDumpIntermediate( + CompileRequest* compileRequest, + void const* data, + size_t size, + CodeGenTarget target); + void maybeDumpIntermediate( + CompileRequest* compileRequest, + char const* text, + CodeGenTarget target); } #endif
\ No newline at end of file diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index bfc499c1b..89db62ec8 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -668,6 +668,14 @@ SLANG_API void spSetCompileFlags( REQ(request)->compileFlags = flags; } +SLANG_API void spSetDumpIntermediates( + SlangCompileRequest* request, + int enable) +{ + REQ(request)->shouldDumpIntermediates = enable != 0; +} + + SLANG_API void spSetCodeGenTarget( SlangCompileRequest* request, int target) diff --git a/tools/glslang/glslang.cpp b/tools/glslang/glslang.cpp index f07937b97..98bcf14d6 100644 --- a/tools/glslang/glslang.cpp +++ b/tools/glslang/glslang.cpp @@ -78,12 +78,8 @@ static void dumpDiagnostics( dump(log.c_str(), log.length(), request->diagnosticFunc, request->diagnosticUserData, stderr); } -extern "C" -_declspec(dllexport) -int glslang_compile(glslang_CompileRequest* request) +static int glslang_compileGLSLToSPIRV(glslang_CompileRequest* request) { - glslang::InitializeProcess(); - EShLanguage glslangStage; switch( request->slangStage ) { @@ -109,12 +105,15 @@ int glslang_compile(glslang_CompileRequest* request) glslang::TProgram* program = new glslang::TProgram(); auto programPtr = std::unique_ptr<glslang::TProgram>(program); - int sourceTextLength = (int) strlen(request->sourceText); + char const* sourceText = (char const*)request->inputBegin; + char const* sourceTextEnd = (char const*)request->inputEnd; + + int sourceTextLength = (int)(sourceTextEnd - sourceText); shader->setPreamble("#extension GL_GOOGLE_cpp_style_line_directive : require\n"); shader->setStringsWithLengthsAndNames( - &request->sourceText, + &sourceText, &sourceTextLength, &request->sourcePath, 1); @@ -163,20 +162,52 @@ int glslang_compile(glslang_CompileRequest* request) dumpDiagnostics(request, logger.getAllMessages()); - if (request->disassembleResult) - { - std::stringstream spirvAsmStream; - spv::Disassemble(spirvAsmStream, spirv); - std::string result = spirvAsmStream.str(); - dump(result.c_str(), result.length(), request->outputFunc, request->outputUserData, stdout); - } - else - { - dump(spirv.data(), spirv.size() * sizeof(unsigned int), request->outputFunc, request->outputUserData, stdout); - } + dump(spirv.data(), spirv.size() * sizeof(unsigned int), request->outputFunc, request->outputUserData, stdout); } - glslang::FinalizeProcess(); + return 0; +} + +static int glslang_dissassembleSPIRV(glslang_CompileRequest* request) +{ + typedef unsigned int SPIRVWord; + + SPIRVWord const* spirvBegin = (SPIRVWord const*)request->inputBegin; + SPIRVWord const* spirvEnd = (SPIRVWord const*)request->inputEnd; + + std::vector<SPIRVWord> spirv(spirvBegin, spirvEnd); + + std::stringstream spirvAsmStream; + spv::Disassemble(spirvAsmStream, spirv); + std::string result = spirvAsmStream.str(); + dump(result.c_str(), result.length(), request->outputFunc, request->outputUserData, stdout); return 0; } + +extern "C" +_declspec(dllexport) +int glslang_compile(glslang_CompileRequest* request) +{ + glslang::InitializeProcess(); + + int result = 0; + switch(request->action) + { + default: + result = 1; + break; + + case GLSLANG_ACTION_COMPILE_GLSL_TO_SPIRV: + result = glslang_compileGLSLToSPIRV(request); + break; + + case GLSLANG_ACTION_DISSASSEMBLE_SPIRV: + result = glslang_dissassembleSPIRV(request); + break; + } + + glslang::FinalizeProcess(); + + return result; +} diff --git a/tools/glslang/glslang.h b/tools/glslang/glslang.h index 8686f019e..f02d43882 100644 --- a/tools/glslang/glslang.h +++ b/tools/glslang/glslang.h @@ -4,10 +4,18 @@ typedef void (*glslang_OutputFunc)(void const* data, size_t size, void* userData); +enum +{ + GLSLANG_ACTION_COMPILE_GLSL_TO_SPIRV, + GLSLANG_ACTION_DISSASSEMBLE_SPIRV, +}; + struct glslang_CompileRequest { char const* sourcePath; - char const* sourceText; + + void const* inputBegin; + void const* inputEnd; glslang_OutputFunc diagnosticFunc; void* diagnosticUserData; @@ -17,7 +25,7 @@ struct glslang_CompileRequest int slangStage; - bool disassembleResult; + unsigned action; }; typedef int (*glslang_CompileFunc)(glslang_CompileRequest* request); |
