From 4bb88c4a45707fb88150aa7952b4c9b9f55b1749 Mon Sep 17 00:00:00 2001 From: Kai-Hwa Yao Date: Sun, 9 Jul 2017 22:58:41 -0700 Subject: Allow glslang wrapper to output regular SPIRV before disassembly --- tools/glslang/glslang.cpp | 34 ++++++++++++++++++++-------------- tools/glslang/glslang.h | 4 +++- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/tools/glslang/glslang.cpp b/tools/glslang/glslang.cpp index cf563faff..fb697675e 100644 --- a/tools/glslang/glslang.cpp +++ b/tools/glslang/glslang.cpp @@ -51,21 +51,22 @@ static TBuiltInResource gResources = }; static void dump( - std::string const& text, - glslang_OutputFunc outputFunc, - void* outputUserData, - FILE* fallbackStream) + void const* data, + size_t size, + glslang_OutputFunc outputFunc, + void* outputUserData, + FILE* fallbackStream) { if( outputFunc ) { - outputFunc(text.c_str(), outputUserData); + outputFunc(data, size, outputUserData); } else { - fprintf(fallbackStream, "%s", text.c_str()); + fwrite(data, 1, size, fallbackStream); // also output it for debug purposes - OutputDebugStringA(text.c_str()); + OutputDebugStringA((char const*)data); } } @@ -73,7 +74,7 @@ static void dumpDiagnostics( glslang_CompileRequest* request, std::string const& log) { - dump(log, request->diagnosticFunc, request->diagnosticUserData, stderr); + dump(log.c_str(), log.length(), request->diagnosticFunc, request->diagnosticUserData, stderr); } extern "C" @@ -161,14 +162,19 @@ int glslang_compile(glslang_CompileRequest* request) dumpDiagnostics(request, logger.getAllMessages()); - std::stringstream spirvAsmStream; - - spv::Disassemble(spirvAsmStream, spirv); - - dump(spirvAsmStream.str(), request->outputFunc, request->outputUserData, stdout); + 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(spirv[0]), request->outputFunc, request->outputUserData, stdout); + } } - glslang::FinalizeProcess(); return 0; diff --git a/tools/glslang/glslang.h b/tools/glslang/glslang.h index 73c8a978e..8686f019e 100644 --- a/tools/glslang/glslang.h +++ b/tools/glslang/glslang.h @@ -2,7 +2,7 @@ #ifndef GLSLANG_H_INCLUDED #define GLSLANG_H_INCLUDED -typedef void (*glslang_OutputFunc)(char const* text, void* userData); +typedef void (*glslang_OutputFunc)(void const* data, size_t size, void* userData); struct glslang_CompileRequest { @@ -16,6 +16,8 @@ struct glslang_CompileRequest void* outputUserData; int slangStage; + + bool disassembleResult; }; typedef int (*glslang_CompileFunc)(glslang_CompileRequest* request); -- cgit v1.2.3 From 7c0ebeee95cb72f086a261ed6c55f33571bb62db Mon Sep 17 00:00:00 2001 From: Kai-Hwa Yao Date: Mon, 10 Jul 2017 13:50:16 -0700 Subject: Refactored compile output to work with raw data instead of Strings --- slang.h | 22 +++++++++- source/slang/compiler.cpp | 100 +++++++++++++++++----------------------------- source/slang/compiler.h | 4 +- source/slang/slang.cpp | 27 +++++++++++-- 4 files changed, 82 insertions(+), 71 deletions(-) diff --git a/slang.h b/slang.h index 87419bf45..56d962490 100644 --- a/slang.h +++ b/slang.h @@ -314,7 +314,7 @@ extern "C" spGetTranslationUnitCount( SlangCompileRequest* request); - /** Get the output code associated with a specific translation unit + /** Get the output code associated with a specific translation unit. The lifetime of the output pointer is the same as `request`. */ @@ -322,7 +322,16 @@ extern "C" SlangCompileRequest* request, int translationUnitIndex); - /** Get the output code associated with a specific entry point. + /** Get the output bytecode associated with a specific translation unit. + + The lifetime of the output pointer is the same as `request`. + */ + SLANG_API void const* spGetTranslationUnitCode( + SlangCompileRequest* request, + int translationUnitIndex, + size_t* outSize); + + /** Get the output source code associated with a specific entry point. The lifetime of the output pointer is the same as `request`. */ @@ -330,6 +339,15 @@ extern "C" SlangCompileRequest* request, int entryPointIndex); + /** Get the output bytecode associated with a specific entry point. + + The lifetime of the output pointer is the same as `request`. + */ + SLANG_API void const* spGetEntryPointCode( + SlangCompileRequest* request, + int entryPointIndex, + size_t* outSize); + /* Note(tfoley): working on new reflection interface... */ diff --git a/source/slang/compiler.cpp b/source/slang/compiler.cpp index 2f6204eb2..3225aafb2 100644 --- a/source/slang/compiler.cpp +++ b/source/slang/compiler.cpp @@ -197,6 +197,7 @@ namespace Slang 0, &codeBlob, &diagnosticsBlob); + List data; if (codeBlob) { @@ -243,7 +244,7 @@ namespace Slang } #endif - String EmitDXBytecodeAssemblyForEntryPoint( + List EmitDXBytecodeAssemblyForEntryPoint( EntryPointRequest* entryPoint) { static pD3DDisassemble D3DDisassemble_ = nullptr; @@ -259,7 +260,7 @@ namespace Slang List dxbc = EmitDXBytecodeForEntryPoint(entryPoint); if (!dxbc.Count()) { - return ""; + return List(); } ID3DBlob* codeBlob; @@ -270,10 +271,10 @@ namespace Slang nullptr, &codeBlob); - String result; + List result; if (codeBlob) { - result = String((char const*) codeBlob->GetBufferPointer()); + result.AddRange((uint8_t*)codeBlob->GetBufferPointer(), codeBlob->GetBufferSize()); codeBlob->Release(); } if (FAILED(hr)) @@ -314,8 +315,9 @@ namespace Slang } - String emitSPIRVAssemblyForEntryPoint( - EntryPointRequest* entryPoint) + List emitSPIRVForEntryPoint( + EntryPointRequest* entryPoint, + bool spirvAssembly) { String rawGLSL = emitGLSLForEntryPoint(entryPoint); @@ -329,34 +331,32 @@ namespace Slang assert(glslang_compile); } - StringBuilder diagnosticBuilder; - StringBuilder outputBuilder; + List diagnosticOutput; + List output; - auto outputFunc = [](char const* text, void* userData) + auto outputFunc = [](void const* data, size_t size, void* userData) { - *(StringBuilder*)userData << text; + ((List*)userData)->AddRange((uint8_t*)data, size); }; glslang_CompileRequest request; request.sourcePath = "slang"; request.sourceText = rawGLSL.begin(); - request.slangStage = (SlangStage) entryPoint->profile.GetStage(); + request.slangStage = (SlangStage)entryPoint->profile.GetStage(); + request.disassembleResult = spirvAssembly; request.diagnosticFunc = outputFunc; - request.diagnosticUserData = &diagnosticBuilder; + request.diagnosticUserData = &diagnosticOutput; request.outputFunc = outputFunc; - request.outputUserData = &outputBuilder; + request.outputUserData = &output; int err = glslang_compile(&request); - String diagnostics = diagnosticBuilder.ProduceString(); - String output = outputBuilder.ProduceString(); - - if(err) + if (err) { - OutputDebugStringA(diagnostics.Buffer()); - fprintf(stderr, "%s", diagnostics.Buffer()); + OutputDebugStringA((char const *)diagnosticOutput.Buffer()); + fwrite(diagnosticOutput.Buffer(), 1, diagnosticOutput.Count(), stderr); exit(1); } @@ -397,67 +397,42 @@ namespace Slang case CodeGenTarget::HLSL: { String code = emitHLSLForEntryPoint(entryPoint); - result.outputSource = code; + result.outputSource.AddRange((uint8_t*)code.Buffer(), code.Length()); } break; case CodeGenTarget::GLSL: { String code = emitGLSLForEntryPoint(entryPoint); - result.outputSource = code; + result.outputSource.AddRange((uint8_t*)code.Buffer(), code.Length()); } break; case CodeGenTarget::DXBytecode: { - auto code = EmitDXBytecodeForEntryPoint(entryPoint); - - // TODO(tfoley): Need to figure out an appropriate interface - // for returning binary code, in addition to source. -#if 0 - if (context.compileResult) - { - StringBuilder sb; - sb.Append((char*) code.begin(), code.Count()); - - String codeString = sb.ProduceString(); - result.outputSource = codeString; - } - else -#endif - { - int col = 0; - for(auto ii : code) - { - if(col != 0) fputs(" ", stdout); - fprintf(stdout, "%02X", ii); - col++; - if(col == 8) - { - fputs("\n", stdout); - col = 0; - } - } - if(col != 0) - { - fputs("\n", stdout); - } - } - return result; + List code = EmitDXBytecodeForEntryPoint(entryPoint); + result.outputSource.AddRange(code.Buffer(), code.Count()); } break; case CodeGenTarget::DXBytecodeAssembly: { - String code = EmitDXBytecodeAssemblyForEntryPoint(entryPoint); - result.outputSource = code; + List code = EmitDXBytecodeAssemblyForEntryPoint(entryPoint); + result.outputSource.AddRange(code.Buffer(), code.Count()); + } + break; + + case CodeGenTarget::SPIRV: + { + List code = emitSPIRVForEntryPoint(entryPoint, false); + result.outputSource.AddRange(code.Buffer(), code.Count()); } break; case CodeGenTarget::SPIRVAssembly: { - String code = emitSPIRVAssemblyForEntryPoint(entryPoint); - result.outputSource = code; + List code = emitSPIRVForEntryPoint(entryPoint, true); + result.outputSource.AddRange(code.Buffer(), code.Count()); } break; @@ -493,14 +468,11 @@ namespace Slang // The result for the translation unit will just be the concatenation // of the results for each entry point. This doesn't actually make // much sense, but it is good enough for now. - // - // TODO: Replace this with a packaged JSON and/or binary format. - StringBuilder sb; for (auto& entryPoint : translationUnit->entryPoints) { - sb << entryPoint->result.outputSource; + UInt size = entryPoint->result.outputSource.Count(); + result.outputSource.AddRange(entryPoint->result.outputSource.Buffer(), size); } - result.outputSource = sb.ProduceString(); return result; } diff --git a/source/slang/compiler.h b/source/slang/compiler.h index cb7eb6265..3763faec7 100644 --- a/source/slang/compiler.h +++ b/source/slang/compiler.h @@ -54,7 +54,7 @@ namespace Slang // Result of compiling an entry point struct EntryPointResult { - String outputSource; + List outputSource; }; // Describes an entry point that we've been requested to compile @@ -108,7 +108,7 @@ namespace Slang // Result of compiling a translation unit struct TranslationUnitResult { - String outputSource; + List outputSource; }; // A single translation unit requested to be compiled. diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index af68060cd..7f30e91c2 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -862,7 +862,18 @@ SLANG_API char const* spGetTranslationUnitSource( int translationUnitIndex) { auto req = REQ(request); - return req->translationUnits[translationUnitIndex]->result.outputSource.Buffer(); + return (char const*)req->translationUnits[translationUnitIndex]->result.outputSource.Buffer(); +} + +SLANG_API void const* spGetTranslationUnitCode( + SlangCompileRequest* request, + int translationUnitIndex, + size_t* outSize) +{ + auto req = REQ(request); + Slang::TranslationUnitResult& result = req->translationUnits[translationUnitIndex]->result; + *outSize = (size_t)result.outputSource.Count(); + return result.outputSource.Buffer(); } SLANG_API char const* spGetEntryPointSource( @@ -870,10 +881,21 @@ SLANG_API char const* spGetEntryPointSource( int entryPointIndex) { auto req = REQ(request); - return req->entryPoints[entryPointIndex]->result.outputSource.Buffer(); + return (char const*)req->entryPoints[entryPointIndex]->result.outputSource.Buffer(); } +SLANG_API void const* spGetEntryPointCode( + SlangCompileRequest* request, + int entryPointIndex, + size_t* outSize) +{ + auto req = REQ(request); + Slang::EntryPointResult& result = req->entryPoints[entryPointIndex]->result; + *outSize = (size_t)result.outputSource.Count(); + return result.outputSource.Buffer(); +} + // Reflection API SLANG_API SlangReflection* spGetReflection( @@ -885,5 +907,4 @@ SLANG_API SlangReflection* spGetReflection( return (SlangReflection*) req->layout.Ptr(); } - // ... rest of reflection API implementation is in `Reflection.cpp` -- cgit v1.2.3 From 61a816c1e898155aa93c5a740e2b7aad7d7b4fa1 Mon Sep 17 00:00:00 2001 From: Kai-Hwa Yao Date: Mon, 10 Jul 2017 14:11:26 -0700 Subject: Don't assume vector contains contents --- tools/glslang/glslang.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/glslang/glslang.cpp b/tools/glslang/glslang.cpp index fb697675e..e396528d9 100644 --- a/tools/glslang/glslang.cpp +++ b/tools/glslang/glslang.cpp @@ -171,7 +171,7 @@ int glslang_compile(glslang_CompileRequest* request) } else { - dump(spirv.data(), spirv.size() * sizeof(spirv[0]), request->outputFunc, request->outputUserData, stdout); + dump(spirv.data(), spirv.size() * sizeof(unsigned int), request->outputFunc, request->outputUserData, stdout); } } -- cgit v1.2.3 From 22c7a4de0c3810fcfc1099843e42b315c366a7c5 Mon Sep 17 00:00:00 2001 From: Kai-Hwa Yao Date: Mon, 10 Jul 2017 17:44:14 -0700 Subject: Removed spGetTranslationUnitCode; Unified EntryPointResult/TranslationUnitResult, added helper functionality; Ensure null termination when printing raw data --- slang.h | 9 ------- source/slang/compiler.cpp | 68 ++++++++++++++++++++++++++++++++++------------- source/slang/compiler.h | 33 +++++++++++++++-------- source/slang/slang.cpp | 22 ++++----------- tools/glslang/glslang.cpp | 3 ++- 5 files changed, 78 insertions(+), 57 deletions(-) diff --git a/slang.h b/slang.h index 56d962490..f5da206ce 100644 --- a/slang.h +++ b/slang.h @@ -322,15 +322,6 @@ extern "C" SlangCompileRequest* request, int translationUnitIndex); - /** Get the output bytecode associated with a specific translation unit. - - The lifetime of the output pointer is the same as `request`. - */ - SLANG_API void const* spGetTranslationUnitCode( - SlangCompileRequest* request, - int translationUnitIndex, - size_t* outSize); - /** Get the output source code associated with a specific entry point. The lifetime of the output pointer is the same as `request`. diff --git a/source/slang/compiler.cpp b/source/slang/compiler.cpp index 3225aafb2..c04c2150d 100644 --- a/source/slang/compiler.cpp +++ b/source/slang/compiler.cpp @@ -33,6 +33,33 @@ namespace Slang { + // CompileResult + + void CompileResult::append(CompileResult const& result) + { + // Find which to append to + ResultFormat appendTo = ResultFormat::None; + + if (format == ResultFormat::None) + { + format = result.format; + appendTo = result.format; + } + else if (format == result.format) + { + appendTo = format; + } + + if (appendTo == ResultFormat::Text) + { + outputString.append(result.outputString.Buffer()); + } + else if (appendTo == ResultFormat::Binary) + { + outputBinary.AddRange(result.outputBinary.Buffer(), result.outputBinary.Count()); + } + } + // EntryPointRequest TranslationUnitRequest* EntryPointRequest::getTranslationUnit() @@ -355,8 +382,11 @@ namespace Slang if (err) { - OutputDebugStringA((char const *)diagnosticOutput.Buffer()); - fwrite(diagnosticOutput.Buffer(), 1, diagnosticOutput.Count(), stderr); + char const* diagnosticString = (char const*)diagnosticOutput.Buffer(); + String debugStr(diagnosticString, diagnosticString + diagnosticOutput.Count()); + + OutputDebugStringA(debugStr.Buffer()); + fprintf(stderr, "%s", debugStr.Buffer()); exit(1); } @@ -385,10 +415,10 @@ namespace Slang #endif // Do emit logic for a single entry point - EntryPointResult emitEntryPoint( + CompileResult emitEntryPoint( EntryPointRequest* entryPoint) { - EntryPointResult result; + CompileResult result; auto compileRequest = entryPoint->compileRequest; @@ -397,42 +427,42 @@ namespace Slang case CodeGenTarget::HLSL: { String code = emitHLSLForEntryPoint(entryPoint); - result.outputSource.AddRange((uint8_t*)code.Buffer(), code.Length()); + result = CompileResult(code); } break; case CodeGenTarget::GLSL: { String code = emitGLSLForEntryPoint(entryPoint); - result.outputSource.AddRange((uint8_t*)code.Buffer(), code.Length()); + result = CompileResult(code); } break; case CodeGenTarget::DXBytecode: { List code = EmitDXBytecodeForEntryPoint(entryPoint); - result.outputSource.AddRange(code.Buffer(), code.Count()); + result = CompileResult(code); } break; case CodeGenTarget::DXBytecodeAssembly: { List code = EmitDXBytecodeAssemblyForEntryPoint(entryPoint); - result.outputSource.AddRange(code.Buffer(), code.Count()); + result = CompileResult(code); } break; case CodeGenTarget::SPIRV: { List code = emitSPIRVForEntryPoint(entryPoint, false); - result.outputSource.AddRange(code.Buffer(), code.Count()); + result = CompileResult(code); } break; case CodeGenTarget::SPIRVAssembly: { List code = emitSPIRVForEntryPoint(entryPoint, true); - result.outputSource.AddRange(code.Buffer(), code.Count()); + result = CompileResult(code); } break; @@ -449,18 +479,16 @@ namespace Slang } return result; - - } - TranslationUnitResult emitTranslationUnitEntryPoints( + CompileResult emitTranslationUnitEntryPoints( TranslationUnitRequest* translationUnit) { - TranslationUnitResult result; + CompileResult result; for (auto& entryPoint : translationUnit->entryPoints) { - EntryPointResult entryPointResult = emitEntryPoint(entryPoint.Ptr()); + CompileResult entryPointResult = emitEntryPoint(entryPoint.Ptr()); entryPoint->result = entryPointResult; } @@ -468,10 +496,11 @@ namespace Slang // The result for the translation unit will just be the concatenation // of the results for each entry point. This doesn't actually make // much sense, but it is good enough for now. + // + // TODO: Replace this with a packaged JSON and/or binary format. for (auto& entryPoint : translationUnit->entryPoints) { - UInt size = entryPoint->result.outputSource.Count(); - result.outputSource.AddRange(entryPoint->result.outputSource.Buffer(), size); + result.append(entryPoint->result); } return result; @@ -479,7 +508,7 @@ namespace Slang // Do emit logic for an entire translation unit, which might // have zero or more entry points - TranslationUnitResult emitTranslationUnit( + CompileResult emitTranslationUnit( TranslationUnitRequest* translationUnit) { return emitTranslationUnitEntryPoints(translationUnit); @@ -518,8 +547,9 @@ namespace Slang // For most targets, we will do things per-translation-unit for( auto translationUnit : compileRequest->translationUnits ) { - TranslationUnitResult translationUnitResult = emitTranslationUnit(translationUnit.Ptr()); + CompileResult translationUnitResult = emitTranslationUnit(translationUnit.Ptr()); translationUnit->result = translationUnitResult; } } + } diff --git a/source/slang/compiler.h b/source/slang/compiler.h index 3763faec7..2b440ad85 100644 --- a/source/slang/compiler.h +++ b/source/slang/compiler.h @@ -48,13 +48,30 @@ namespace Slang ReflectionJSON = SLANG_REFLECTION_JSON, }; + enum class ResultFormat + { + None, + Text, + Binary + }; + class CompileRequest; class TranslationUnitRequest; - // Result of compiling an entry point - struct EntryPointResult + // Result of compiling an entry point. + // Should only ever be string OR binary. + class CompileResult { - List outputSource; + public: + CompileResult() = default; + CompileResult(String const& str) : format(ResultFormat::Text), outputString(str) {} + CompileResult(List const& buffer) : format(ResultFormat::Binary), outputBinary(buffer) {} + + void append(CompileResult const& result); + + ResultFormat format = ResultFormat::None; + String outputString; + List outputBinary; }; // Describes an entry point that we've been requested to compile @@ -80,7 +97,7 @@ namespace Slang // The resulting output for the enry point // // TODO: low-level code generation should be a distinct step - EntryPointResult result; + CompileResult result; // The translation unit that this entry point came from TranslationUnitRequest* getTranslationUnit(); @@ -105,12 +122,6 @@ namespace Slang String content; }; - // Result of compiling a translation unit - struct TranslationUnitResult - { - List outputSource; - }; - // A single translation unit requested to be compiled. // class TranslationUnitRequest : public RefObject @@ -144,7 +155,7 @@ namespace Slang // The resulting output for the translation unit // // TODO: low-level code generation should be a distinct step - TranslationUnitResult result; + CompileResult result; }; // A directory to be searched when looking for files (e.g., `#include`) diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index 7f30e91c2..0561f30a9 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -862,18 +862,7 @@ SLANG_API char const* spGetTranslationUnitSource( int translationUnitIndex) { auto req = REQ(request); - return (char const*)req->translationUnits[translationUnitIndex]->result.outputSource.Buffer(); -} - -SLANG_API void const* spGetTranslationUnitCode( - SlangCompileRequest* request, - int translationUnitIndex, - size_t* outSize) -{ - auto req = REQ(request); - Slang::TranslationUnitResult& result = req->translationUnits[translationUnitIndex]->result; - *outSize = (size_t)result.outputSource.Count(); - return result.outputSource.Buffer(); + return req->translationUnits[translationUnitIndex]->result.outputString.Buffer(); } SLANG_API char const* spGetEntryPointSource( @@ -881,8 +870,7 @@ SLANG_API char const* spGetEntryPointSource( int entryPointIndex) { auto req = REQ(request); - return (char const*)req->entryPoints[entryPointIndex]->result.outputSource.Buffer(); - + return req->entryPoints[entryPointIndex]->result.outputString.Buffer(); } SLANG_API void const* spGetEntryPointCode( @@ -891,9 +879,9 @@ SLANG_API void const* spGetEntryPointCode( size_t* outSize) { auto req = REQ(request); - Slang::EntryPointResult& result = req->entryPoints[entryPointIndex]->result; - *outSize = (size_t)result.outputSource.Count(); - return result.outputSource.Buffer(); + Slang::CompileResult& result = req->entryPoints[entryPointIndex]->result; + if(outSize) *outSize = result.outputBinary.Count(); + return result.outputBinary.Buffer(); } // Reflection API diff --git a/tools/glslang/glslang.cpp b/tools/glslang/glslang.cpp index e396528d9..f07937b97 100644 --- a/tools/glslang/glslang.cpp +++ b/tools/glslang/glslang.cpp @@ -66,7 +66,8 @@ static void dump( fwrite(data, 1, size, fallbackStream); // also output it for debug purposes - OutputDebugStringA((char const*)data); + std::string str((char const*)data, size); + OutputDebugStringA(str.c_str()); } } -- cgit v1.2.3