summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Foley <tim.foley.is@gmail.com>2017-07-10 19:45:21 -0700
committerGitHub <noreply@github.com>2017-07-10 19:45:21 -0700
commita923aff63a7b0d8847a50459361111347e3c527e (patch)
treee53bfd90d2b9e4b04d22f58548999a33b7944d46
parent5577e2d5e8bb374a00d9ecdd8e2c667ace546036 (diff)
parent22c7a4de0c3810fcfc1099843e42b315c366a7c5 (diff)
Merge pull request #67 from kyaoNV/spirv
SPIR-V Support
-rw-r--r--slang.h13
-rw-r--r--source/slang/compiler.cpp144
-rw-r--r--source/slang/compiler.h33
-rw-r--r--source/slang/slang.cpp15
-rw-r--r--tools/glslang/glslang.cpp35
-rw-r--r--tools/glslang/glslang.h4
6 files changed, 142 insertions, 102 deletions
diff --git a/slang.h b/slang.h
index 87419bf45..f5da206ce 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,7 @@ extern "C"
SlangCompileRequest* request,
int translationUnitIndex);
- /** Get the output code associated with a specific entry point.
+ /** Get the output source code associated with a specific entry point.
The lifetime of the output pointer is the same as `request`.
*/
@@ -330,6 +330,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..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()
@@ -197,6 +224,7 @@ namespace Slang
0,
&codeBlob,
&diagnosticsBlob);
+
List<uint8_t> data;
if (codeBlob)
{
@@ -243,7 +271,7 @@ namespace Slang
}
#endif
- String EmitDXBytecodeAssemblyForEntryPoint(
+ List<uint8_t> EmitDXBytecodeAssemblyForEntryPoint(
EntryPointRequest* entryPoint)
{
static pD3DDisassemble D3DDisassemble_ = nullptr;
@@ -259,7 +287,7 @@ namespace Slang
List<uint8_t> dxbc = EmitDXBytecodeForEntryPoint(entryPoint);
if (!dxbc.Count())
{
- return "";
+ return List<uint8_t>();
}
ID3DBlob* codeBlob;
@@ -270,10 +298,10 @@ namespace Slang
nullptr,
&codeBlob);
- String result;
+ List<uint8_t> result;
if (codeBlob)
{
- result = String((char const*) codeBlob->GetBufferPointer());
+ result.AddRange((uint8_t*)codeBlob->GetBufferPointer(), codeBlob->GetBufferSize());
codeBlob->Release();
}
if (FAILED(hr))
@@ -314,8 +342,9 @@ namespace Slang
}
- String emitSPIRVAssemblyForEntryPoint(
- EntryPointRequest* entryPoint)
+ List<uint8_t> emitSPIRVForEntryPoint(
+ EntryPointRequest* entryPoint,
+ bool spirvAssembly)
{
String rawGLSL = emitGLSLForEntryPoint(entryPoint);
@@ -329,34 +358,35 @@ namespace Slang
assert(glslang_compile);
}
- StringBuilder diagnosticBuilder;
- StringBuilder outputBuilder;
+ List<uint8_t> diagnosticOutput;
+ List<uint8_t> output;
- auto outputFunc = [](char const* text, void* userData)
+ auto outputFunc = [](void const* data, size_t size, void* userData)
{
- *(StringBuilder*)userData << text;
+ ((List<uint8_t>*)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());
+ 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,67 +427,42 @@ namespace Slang
case CodeGenTarget::HLSL:
{
String code = emitHLSLForEntryPoint(entryPoint);
- result.outputSource = code;
+ result = CompileResult(code);
}
break;
case CodeGenTarget::GLSL:
{
String code = emitGLSLForEntryPoint(entryPoint);
- result.outputSource = code;
+ result = CompileResult(code);
}
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<uint8_t> code = EmitDXBytecodeForEntryPoint(entryPoint);
+ result = CompileResult(code);
}
break;
case CodeGenTarget::DXBytecodeAssembly:
{
- String code = EmitDXBytecodeAssemblyForEntryPoint(entryPoint);
- result.outputSource = code;
+ List<uint8_t> code = EmitDXBytecodeAssemblyForEntryPoint(entryPoint);
+ result = CompileResult(code);
+ }
+ break;
+
+ case CodeGenTarget::SPIRV:
+ {
+ List<uint8_t> code = emitSPIRVForEntryPoint(entryPoint, false);
+ result = CompileResult(code);
}
break;
case CodeGenTarget::SPIRVAssembly:
{
- String code = emitSPIRVAssemblyForEntryPoint(entryPoint);
- result.outputSource = code;
+ List<uint8_t> code = emitSPIRVForEntryPoint(entryPoint, true);
+ result = CompileResult(code);
}
break;
@@ -474,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;
}
@@ -495,19 +498,17 @@ namespace Slang
// 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;
+ result.append(entryPoint->result);
}
- result.outputSource = sb.ProduceString();
return result;
}
// 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);
@@ -546,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 cb7eb6265..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
{
- String outputSource;
+ public:
+ CompileResult() = default;
+ CompileResult(String const& str) : format(ResultFormat::Text), outputString(str) {}
+ CompileResult(List<uint8_t> const& buffer) : format(ResultFormat::Binary), outputBinary(buffer) {}
+
+ void append(CompileResult const& result);
+
+ ResultFormat format = ResultFormat::None;
+ String outputString;
+ List<uint8_t> 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
- {
- String 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 af68060cd..0561f30a9 100644
--- a/source/slang/slang.cpp
+++ b/source/slang/slang.cpp
@@ -862,7 +862,7 @@ SLANG_API char const* spGetTranslationUnitSource(
int translationUnitIndex)
{
auto req = REQ(request);
- return req->translationUnits[translationUnitIndex]->result.outputSource.Buffer();
+ return req->translationUnits[translationUnitIndex]->result.outputString.Buffer();
}
SLANG_API char const* spGetEntryPointSource(
@@ -870,8 +870,18 @@ SLANG_API char const* spGetEntryPointSource(
int entryPointIndex)
{
auto req = REQ(request);
- return req->entryPoints[entryPointIndex]->result.outputSource.Buffer();
+ return req->entryPoints[entryPointIndex]->result.outputString.Buffer();
+}
+SLANG_API void const* spGetEntryPointCode(
+ SlangCompileRequest* request,
+ int entryPointIndex,
+ size_t* outSize)
+{
+ auto req = REQ(request);
+ Slang::CompileResult& result = req->entryPoints[entryPointIndex]->result;
+ if(outSize) *outSize = result.outputBinary.Count();
+ return result.outputBinary.Buffer();
}
// Reflection API
@@ -885,5 +895,4 @@ SLANG_API SlangReflection* spGetReflection(
return (SlangReflection*) req->layout.Ptr();
}
-
// ... rest of reflection API implementation is in `Reflection.cpp`
diff --git a/tools/glslang/glslang.cpp b/tools/glslang/glslang.cpp
index cf563faff..f07937b97 100644
--- a/tools/glslang/glslang.cpp
+++ b/tools/glslang/glslang.cpp
@@ -51,21 +51,23 @@ 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());
+ std::string str((char const*)data, size);
+ OutputDebugStringA(str.c_str());
}
}
@@ -73,7 +75,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 +163,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(unsigned int), 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);