diff options
| author | Tim Foley <tfoleyNV@users.noreply.github.com> | 2017-10-13 18:14:42 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-10-13 18:14:42 -0700 |
| commit | 64ddefb90cf440df7879d1f2f9cc61de71e0f181 (patch) | |
| tree | 03d113b2e58c9e232021df38350744226600f79c | |
| parent | 575230b93370fea86ecccb53fba73927280e917b (diff) | |
Move reflection JSON generation into separate text fixture (#211)
Move reflection JSON generation into separate test fixture
26 files changed, 1037 insertions, 812 deletions
@@ -106,6 +106,9 @@ SLANG_GLSLANG_HEADERS := source/slang-glslang/*.h SLANG_EVAL_TEST_SOURCES := tools/eval-test/*.cpp SLANG_EVAL_TEST_HEADERS := +SLANG_REFLECTION_TEST_SOURCES := tools/slang-reflection-test/*.cpp +SLANG_REFLECTION_TEST_HEADERS := + # Add `glslang` sources to the build or `slang-glslang` # # Note: We aren't going to wasttte time trying to work with @@ -135,10 +138,11 @@ SLANGC := $(OUTPUTDIR)slangc$(BIN_SUFFIX) SLANG_GLSLANG := $(OUTPUTDIR)$(SHARED_LIB_PREFIX)slang-glslang$(SHARED_LIB_SUFFIX) SLANG_TEST := $(OUTPUTDIR)slang-test$(BIN_SUFFIX) SLANG_EVAL_TEST := $(OUTPUTDIR)slang-eval-test$(BIN_SUFFIX) +SLANG_REFLECTION_TEST := $(OUTPUTDIR)slang-reflection-test$(BIN_SUFFIX) # By default, when the user invokes `make`, we will build the # `slang` shared library, and the `slangc` front-end application. -all: slang slang-glslang slangc slang-test slang-eval-test +all: slang slang-glslang slangc slang-test slang-eval-test slang-reflection-test mkdirs: $(OUTPUTDIR) @@ -148,6 +152,7 @@ slangc: mkdirs $(SLANGC) slang-glslang: mkdirs $(SLANG_GLSLANG) slang-test: mkdirs $(SLANG_TEST) slang-eval-test: mkdirs $(SLANG_EVAL_TEST) +slang-reflection-test: mkdirs $(SLANG_REFLECTION_TEST) $(SLANG): $(SLANG_SOURCES) $(SLANG_HEADERS) $(CXX) $(SHARED_LIB_LDFLAGS) -o $@ -DSLANG_DYNAMIC_EXPORT $(SHARED_LIB_CFLAGS) $(SLANG_SOURCES) -ldl $(RELATIVE_RPATH_INCANTATION) @@ -164,10 +169,13 @@ $(SLANG_TEST): $(SLANG_TEST_SOURCES) $(SLANG_TEST_HEADERS) $(SLANG) $(SLANG_EVAL_TEST): $(SLANG_EVAL_TEST_SOURCES) $(SLANG) $(CXX) $(LDFLAGS) -o $@ $(CFLAGS) $(SLANG_EVAL_TEST_SOURCES) $(RELATIVE_RPATH_INCANTATION) -lslang +$(SLANG_REFLECTION_TEST): $(SLANG_REFLECTION_TEST_SOURCES) $(SLANG) + $(CXX) $(LDFLAGS) -o $@ $(CFLAGS) $(SLANG_REFLECTION_TEST_SOURCES) $(RELATIVE_RPATH_INCANTATION) -lslang + $(OUTPUTDIR): mkdir -p $(OUTPUTDIR) -test: $(SLANG_TEST) $(SLANG_EVAL_TEST) +test: $(SLANG_TEST) $(SLANG_EVAL_TEST) $(SLANG_REFLECTION_TEST) $(SLANG_TEST) -bindir $(OUTPUTDIR) -category $(SLANG_TEST_CATEGORY) $(SLANG_TEST_FLAGS) clean: @@ -89,7 +89,6 @@ extern "C" SLANG_SPIRV_ASM, SLANG_DXBC, SLANG_DXBC_ASM, - SLANG_REFLECTION_JSON, SLANG_IR, SLANG_IR_ASM, }; @@ -28,7 +28,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "slang-glslang", "source\sla EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "slang-generate", "tools\slang-generate\slang-generate.vcxproj", "{66174227-8541-41FC-A6DF-4764FC66F78E}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "eval-test", "tools\eval-test\eval-test.vcxproj", "{205FCAB9-A13F-4980-86FA-F6221A7095EE}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "slang-eval-test", "tools\eval-test\eval-test.vcxproj", "{205FCAB9-A13F-4980-86FA-F6221A7095EE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "slang-reflection-test", "tools\slang-reflection-test\slang-reflection-test.vcxproj", "{22C45F4F-FB6B-4535-BED1-D3F5D0C71047}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -110,6 +112,14 @@ Global {205FCAB9-A13F-4980-86FA-F6221A7095EE}.Release|Win32.Build.0 = Release|Win32 {205FCAB9-A13F-4980-86FA-F6221A7095EE}.Release|x64.ActiveCfg = Release|x64 {205FCAB9-A13F-4980-86FA-F6221A7095EE}.Release|x64.Build.0 = Release|x64 + {22C45F4F-FB6B-4535-BED1-D3F5D0C71047}.Debug|Win32.ActiveCfg = Debug|Win32 + {22C45F4F-FB6B-4535-BED1-D3F5D0C71047}.Debug|Win32.Build.0 = Debug|Win32 + {22C45F4F-FB6B-4535-BED1-D3F5D0C71047}.Debug|x64.ActiveCfg = Debug|x64 + {22C45F4F-FB6B-4535-BED1-D3F5D0C71047}.Debug|x64.Build.0 = Debug|x64 + {22C45F4F-FB6B-4535-BED1-D3F5D0C71047}.Release|Win32.ActiveCfg = Release|Win32 + {22C45F4F-FB6B-4535-BED1-D3F5D0C71047}.Release|Win32.Build.0 = Release|Win32 + {22C45F4F-FB6B-4535-BED1-D3F5D0C71047}.Release|x64.ActiveCfg = Release|x64 + {22C45F4F-FB6B-4535-BED1-D3F5D0C71047}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -120,5 +130,6 @@ Global {96610759-07B9-4EEB-A974-5C634A2E742B} = {74C5F0DC-93BB-4BF3-AC65-8C65491570F7} {66174227-8541-41FC-A6DF-4764FC66F78E} = {74C5F0DC-93BB-4BF3-AC65-8C65491570F7} {205FCAB9-A13F-4980-86FA-F6221A7095EE} = {74C5F0DC-93BB-4BF3-AC65-8C65491570F7} + {22C45F4F-FB6B-4535-BED1-D3F5D0C71047} = {74C5F0DC-93BB-4BF3-AC65-8C65491570F7} EndGlobalSection EndGlobal diff --git a/source/slang/compiler.cpp b/source/slang/compiler.cpp index d7de5c42e..d57c9b6cf 100644 --- a/source/slang/compiler.cpp +++ b/source/slang/compiler.cpp @@ -815,50 +815,14 @@ namespace Slang translationUnit->result = translationUnitResult; } - - // Allow for an "extra" target to verride things before we finish. - String extraResult; - switch (compileRequest->extraTarget) - { - case CodeGenTarget::ReflectionJSON: - { - String reflectionJSON = emitReflectionJSON(compileRequest->layout.Ptr()); - - // Clobber existing output so we don't have to deal with it - for( auto translationUnit : compileRequest->translationUnits ) - { - translationUnit->result = CompileResult(); - } - for( auto entryPoint : compileRequest->entryPoints ) - { - entryPoint->result = CompileResult(); - } - - extraResult = reflectionJSON; - } - break; - - default: - break; - } - // If we are in command-line mode, we might be expected to actually // write output to one or more files here. if (compileRequest->isCommandLineCompile) { - switch (compileRequest->extraTarget) + for( auto entryPoint : compileRequest->entryPoints ) { - case CodeGenTarget::ReflectionJSON: - fprintf(stdout, "%s", extraResult.begin()); - break; - - default: - for( auto entryPoint : compileRequest->entryPoints ) - { - writeEntryPointResult(entryPoint); - } - break; + writeEntryPointResult(entryPoint); } } diff --git a/source/slang/compiler.h b/source/slang/compiler.h index 1919699a1..ca06e3a65 100644 --- a/source/slang/compiler.h +++ b/source/slang/compiler.h @@ -47,7 +47,6 @@ namespace Slang SPIRVAssembly = SLANG_SPIRV_ASM, DXBytecode = SLANG_DXBC, DXBytecodeAssembly = SLANG_DXBC_ASM, - ReflectionJSON = SLANG_REFLECTION_JSON, SlangIR = SLANG_IR, SlangIRAssembly = SLANG_IR_ASM, }; @@ -187,10 +186,6 @@ namespace Slang // What target language are we compiling to? CodeGenTarget Target = CodeGenTarget::Unknown; - // An "extra" target that might override the first one - // when it comes to deciding output format, etc. - CodeGenTarget extraTarget = CodeGenTarget::Unknown; - // Directories to search for `#include` files or `import`ed modules List<SearchDirectory> searchDirectories; diff --git a/source/slang/options.cpp b/source/slang/options.cpp index 6b21798f5..693081f2a 100644 --- a/source/slang/options.cpp +++ b/source/slang/options.cpp @@ -310,10 +310,6 @@ struct OptionsParser #undef CASE - else if (name == "reflection-json") - { - target = SLANG_REFLECTION_JSON; - } else { fprintf(stderr, "unknown code generation target '%S'\n", name.ToWString().begin()); diff --git a/source/slang/reflection.cpp b/source/slang/reflection.cpp index 5e18e8cfd..3ef3effab 100644 --- a/source/slang/reflection.cpp +++ b/source/slang/reflection.cpp @@ -851,737 +851,3 @@ SLANG_API SlangReflectionEntryPoint* spReflection_getEntryPointByIndex(SlangRefl return convert(program->entryPoints[(int) index].Ptr()); } - - - - - - - - - - - - - - - - - - - - -namespace Slang { - -// Debug helper code: dump reflection data after generation - -struct PrettyWriter -{ - StringBuilder sb; - bool startOfLine = true; - int indent = 0; -}; - -static void adjust(PrettyWriter& writer) -{ - if (!writer.startOfLine) - return; - - int indent = writer.indent; - for (int ii = 0; ii < indent; ++ii) - writer.sb << " "; - - writer.startOfLine = false; -} - -static void indent(PrettyWriter& writer) -{ - writer.indent++; -} - -static void dedent(PrettyWriter& writer) -{ - writer.indent--; -} - -static void write(PrettyWriter& writer, char const* text) -{ - // TODO: can do this more efficiently... - char const* cursor = text; - for(;;) - { - char c = *cursor++; - if (!c) break; - - if (c == '\n') - { - writer.startOfLine = true; - } - else - { - adjust(writer); - } - - writer.sb << c; - } -} - -static void write(PrettyWriter& writer, UInt val) -{ - adjust(writer); - writer.sb << ((unsigned int) val); -} - -static void emitReflectionVarInfoJSON(PrettyWriter& writer, slang::VariableReflection* var); -static void emitReflectionTypeLayoutJSON(PrettyWriter& writer, slang::TypeLayoutReflection* type); -static void emitReflectionTypeJSON(PrettyWriter& writer, slang::TypeReflection* type); - -static void emitReflectionVarBindingInfoJSON( - PrettyWriter& writer, - SlangParameterCategory category, - UInt index, - UInt count, - UInt space = 0) -{ - if( category == SLANG_PARAMETER_CATEGORY_UNIFORM ) - { - write(writer,"\"kind\": \"uniform\""); - write(writer, ", "); - write(writer,"\"offset\": "); - write(writer, index); - write(writer, ", "); - write(writer, "\"size\": "); - write(writer, count); - } - else - { - write(writer, "\"kind\": \""); - switch( category ) - { - #define CASE(NAME, KIND) case SLANG_PARAMETER_CATEGORY_##NAME: write(writer, #KIND); break - CASE(CONSTANT_BUFFER, constantBuffer); - CASE(SHADER_RESOURCE, shaderResource); - CASE(UNORDERED_ACCESS, unorderedAccess); - CASE(VERTEX_INPUT, vertexInput); - CASE(FRAGMENT_OUTPUT, fragmentOutput); - CASE(SAMPLER_STATE, samplerState); - CASE(UNIFORM, uniform); - CASE(DESCRIPTOR_TABLE_SLOT, descriptorTableSlot); - CASE(SPECIALIZATION_CONSTANT, specializationConstant); - CASE(MIXED, mixed); - #undef CASE - - default: - write(writer, "unknown"); - SLANG_UNEXPECTED("unhandled case"); - break; - } - write(writer, "\""); - if( space ) - { - write(writer, ", "); - write(writer, "\"space\": "); - write(writer, space); - } - write(writer, ", "); - write(writer, "\"index\": "); - write(writer, index); - if( count != 1) - { - write(writer, ", "); - write(writer, "\"count\": "); - write(writer, count); - } - } -} - -static void emitReflectionVarBindingInfoJSON( - PrettyWriter& writer, - slang::VariableLayoutReflection* var) -{ - auto typeLayout = var->getTypeLayout(); - auto categoryCount = var->getCategoryCount(); - - if( categoryCount != 1 ) - { - write(writer,"\"bindings\": [\n"); - } - else - { - write(writer,"\"binding\": "); - } - indent(writer); - - for(uint32_t cc = 0; cc < categoryCount; ++cc ) - { - auto category = var->getCategoryByIndex(cc); - auto index = var->getOffset(category); - auto space = var->getBindingSpace(category); - auto count = typeLayout->getSize(category); - - if (cc != 0) write(writer, ",\n"); - - write(writer,"{"); - emitReflectionVarBindingInfoJSON( - writer, - category, - index, - count, - space); - write(writer,"}"); - } - - dedent(writer); - if( categoryCount != 1 ) - { - write(writer,"\n]"); - } -} - -static void emitReflectionNameInfoJSON( - PrettyWriter& writer, - char const* name) -{ - // TODO: deal with escaping special characters if/when needed - write(writer, "\"name\": \""); - write(writer, name); - write(writer, "\""); -} - -static void emitReflectionVarLayoutJSON( - PrettyWriter& writer, - slang::VariableLayoutReflection* var) -{ - write(writer, "{\n"); - indent(writer); - - emitReflectionNameInfoJSON(writer, var->getName()); - write(writer, ",\n"); - - write(writer, "\"type\": "); - emitReflectionTypeLayoutJSON(writer, var->getTypeLayout()); - write(writer, ",\n"); - - emitReflectionVarBindingInfoJSON(writer, var); - - dedent(writer); - write(writer, "\n}"); -} - -static void emitReflectionScalarTypeInfoJSON( - PrettyWriter& writer, - SlangScalarType scalarType) -{ - write(writer, "\"scalarType\": \""); - switch (scalarType) - { - default: - write(writer, "unknown"); - SLANG_UNEXPECTED("unhandled case"); - break; -#define CASE(TAG, ID) case slang::TypeReflection::ScalarType::TAG: write(writer, #ID); break - CASE(Void, void); - CASE(Bool, bool); - CASE(Int32, int32); - CASE(UInt32, uint32); - CASE(Int64, int64); - CASE(UInt64, uint64); - CASE(Float16, float16); - CASE(Float32, float32); - CASE(Float64, float64); -#undef CASE - } - write(writer, "\""); -} - -static void emitReflectionTypeInfoJSON( - PrettyWriter& writer, - slang::TypeReflection* type) -{ - switch( type->getKind() ) - { - case slang::TypeReflection::Kind::SamplerState: - write(writer, "\"kind\": \"samplerState\""); - break; - - case slang::TypeReflection::Kind::Resource: - { - auto shape = type->getResourceShape(); - auto access = type->getResourceAccess(); - write(writer, "\"kind\": \"resource\""); - write(writer, ",\n"); - write(writer, "\"baseShape\": \""); - switch (shape & SLANG_RESOURCE_BASE_SHAPE_MASK) - { - default: - write(writer, "unknown"); - SLANG_UNEXPECTED("unhandled case"); - break; - -#define CASE(SHAPE, NAME) case SLANG_##SHAPE: write(writer, #NAME); break - CASE(TEXTURE_1D, texture1D); - CASE(TEXTURE_2D, texture2D); - CASE(TEXTURE_3D, texture3D); - CASE(TEXTURE_CUBE, textureCube); - CASE(TEXTURE_BUFFER, textureBuffer); - CASE(STRUCTURED_BUFFER, structuredBuffer); - CASE(BYTE_ADDRESS_BUFFER, byteAddressBuffer); -#undef CASE - } - write(writer, "\""); - if (shape & SLANG_TEXTURE_ARRAY_FLAG) - { - write(writer, ",\n"); - write(writer, "\"array\": true"); - } - if (shape & SLANG_TEXTURE_MULTISAMPLE_FLAG) - { - write(writer, ",\n"); - write(writer, "\"multisample\": true"); - } - - if( access != SLANG_RESOURCE_ACCESS_READ ) - { - write(writer, ",\n\"access\": \""); - switch(access) - { - default: - write(writer, "unknown"); - SLANG_UNEXPECTED("unhandled case"); - break; - - case SLANG_RESOURCE_ACCESS_READ: - break; - - case SLANG_RESOURCE_ACCESS_READ_WRITE: write(writer, "readWrite"); break; - case SLANG_RESOURCE_ACCESS_RASTER_ORDERED: write(writer, "rasterOrdered"); break; - case SLANG_RESOURCE_ACCESS_APPEND: write(writer, "append"); break; - case SLANG_RESOURCE_ACCESS_CONSUME: write(writer, "consume"); break; - } - write(writer, "\""); - } - } - break; - - case slang::TypeReflection::Kind::ConstantBuffer: - write(writer, "\"kind\": \"constantBuffer\""); - write(writer, ",\n"); - write(writer, "\"elementType\": "); - emitReflectionTypeJSON( - writer, - type->getElementType()); - break; - - case slang::TypeReflection::Kind::TextureBuffer: - write(writer, "\"kind\": \"textureBuffer\""); - write(writer, ",\n"); - write(writer, "\"elementType\": "); - emitReflectionTypeJSON( - writer, - type->getElementType()); - break; - - case slang::TypeReflection::Kind::ShaderStorageBuffer: - write(writer, "\"kind\": \"shaderStorageBuffer\""); - write(writer, ",\n"); - write(writer, "\"elementType\": "); - emitReflectionTypeJSON( - writer, - type->getElementType()); - break; - - case slang::TypeReflection::Kind::Scalar: - write(writer, "\"kind\": \"scalar\""); - write(writer, ",\n"); - emitReflectionScalarTypeInfoJSON( - writer, - type->getScalarType()); - break; - - case slang::TypeReflection::Kind::Vector: - write(writer, "\"kind\": \"vector\""); - write(writer, ",\n"); - write(writer, "\"elementCount\": "); - write(writer, type->getElementCount()); - write(writer, ",\n"); - write(writer, "\"elementType\": "); - emitReflectionTypeJSON( - writer, - type->getElementType()); - break; - - case slang::TypeReflection::Kind::Matrix: - write(writer, "\"kind\": \"matrix\""); - write(writer, ",\n"); - write(writer, "\"rowCount\": "); - write(writer, type->getRowCount()); - write(writer, ",\n"); - write(writer, "\"columnCount\": "); - write(writer, type->getColumnCount()); - write(writer, ",\n"); - write(writer, "\"elementType\": "); - emitReflectionTypeJSON( - writer, - type->getElementType()); - break; - - case slang::TypeReflection::Kind::Array: - { - auto arrayType = type; - write(writer, "\"kind\": \"array\""); - write(writer, ",\n"); - write(writer, "\"elementCount\": "); - write(writer, arrayType->getElementCount()); - write(writer, ",\n"); - write(writer, "\"elementType\": "); - emitReflectionTypeJSON(writer, arrayType->getElementType()); - } - break; - - case slang::TypeReflection::Kind::Struct: - { - write(writer, "\"kind\": \"struct\",\n"); - write(writer, "\"fields\": [\n"); - indent(writer); - - auto structType = type; - auto fieldCount = structType->getFieldCount(); - for( uint32_t ff = 0; ff < fieldCount; ++ff ) - { - if (ff != 0) write(writer, ",\n"); - emitReflectionVarInfoJSON( - writer, - structType->getFieldByIndex(ff)); - } - dedent(writer); - write(writer, "\n]"); - } - break; - - default: - SLANG_UNEXPECTED("unhandled case"); - break; - } -} - -static void emitReflectionTypeLayoutInfoJSON( - PrettyWriter& writer, - slang::TypeLayoutReflection* typeLayout) -{ - switch( typeLayout->getKind() ) - { - default: - emitReflectionTypeInfoJSON(writer, typeLayout->getType()); - break; - - case slang::TypeReflection::Kind::Array: - { - auto arrayTypeLayout = typeLayout; - auto elementTypeLayout = arrayTypeLayout->getElementTypeLayout(); - write(writer, "\"kind\": \"array\""); - write(writer, ",\n"); - write(writer, "\"elementCount\": "); - write(writer, arrayTypeLayout->getElementCount()); - write(writer, ",\n"); - write(writer, "\"elementType\": "); - emitReflectionTypeLayoutJSON( - writer, - elementTypeLayout); - if (arrayTypeLayout->getSize(SLANG_PARAMETER_CATEGORY_UNIFORM) != 0) - { - write(writer, ",\n"); - write(writer, "\"uniformStride\": "); - write(writer, arrayTypeLayout->getElementStride(SLANG_PARAMETER_CATEGORY_UNIFORM)); - } - } - break; - - case slang::TypeReflection::Kind::Struct: - { - write(writer, "\"kind\": \"struct\",\n"); - write(writer, "\"fields\": [\n"); - indent(writer); - - auto structTypeLayout = typeLayout; - auto fieldCount = structTypeLayout->getFieldCount(); - for( uint32_t ff = 0; ff < fieldCount; ++ff ) - { - if (ff != 0) write(writer, ",\n"); - emitReflectionVarLayoutJSON( - writer, - structTypeLayout->getFieldByIndex(ff)); - } - dedent(writer); - write(writer, "\n]"); - } - break; - - case slang::TypeReflection::Kind::ConstantBuffer: - write(writer, "\"kind\": \"constantBuffer\""); - write(writer, ",\n"); - write(writer, "\"elementType\": "); - emitReflectionTypeLayoutJSON( - writer, - typeLayout->getElementTypeLayout()); - break; - - case slang::TypeReflection::Kind::TextureBuffer: - write(writer, "\"kind\": \"textureBuffer\""); - write(writer, ",\n"); - write(writer, "\"elementType\": "); - emitReflectionTypeLayoutJSON( - writer, - typeLayout->getElementTypeLayout()); - break; - - case slang::TypeReflection::Kind::ShaderStorageBuffer: - write(writer, "\"kind\": \"shaderStorageBuffer\""); - write(writer, ",\n"); - write(writer, "\"elementType\": "); - emitReflectionTypeLayoutJSON( - writer, - typeLayout->getElementTypeLayout()); - break; - } - - // TODO: emit size info for types -} - -static void emitReflectionTypeLayoutJSON( - PrettyWriter& writer, - slang::TypeLayoutReflection* typeLayout) -{ - write(writer, "{\n"); - indent(writer); - emitReflectionTypeLayoutInfoJSON(writer, typeLayout); - dedent(writer); - write(writer, "\n}"); -} - -static void emitReflectionTypeJSON( - PrettyWriter& writer, - slang::TypeReflection* type) -{ - write(writer, "{\n"); - indent(writer); - emitReflectionTypeInfoJSON(writer, type); - dedent(writer); - write(writer, "\n}"); -} - -static void emitReflectionVarInfoJSON( - PrettyWriter& writer, - slang::VariableReflection* var) -{ - emitReflectionNameInfoJSON(writer, var->getName()); - write(writer, ",\n"); - - write(writer, "\"type\": "); - emitReflectionTypeJSON(writer, var->getType()); -} - -static void emitReflectionParamJSON( - PrettyWriter& writer, - slang::VariableLayoutReflection* param) -{ - write(writer, "{\n"); - indent(writer); - - emitReflectionNameInfoJSON(writer, param->getName()); - write(writer, ",\n"); - - emitReflectionVarBindingInfoJSON(writer, param); - write(writer, ",\n"); - - write(writer, "\"type\": "); - emitReflectionTypeLayoutJSON(writer, param->getTypeLayout()); - - dedent(writer); - write(writer, "\n}"); -} - -template<typename T> -struct Range -{ -public: - Range( - T begin, - T end) - : mBegin(begin) - , mEnd(end) - {} - - struct Iterator - { - public: - explicit Iterator(T value) - : mValue(value) - {} - - T operator*() const { return mValue; } - void operator++() { mValue++; } - - bool operator!=(Iterator const& other) - { - return mValue != other.mValue; - } - - private: - T mValue; - }; - - Iterator begin() const { return Iterator(mBegin); } - Iterator end() const { return Iterator(mEnd); } - -private: - T mBegin; - T mEnd; -}; - -template<typename T> -Range<T> range(T begin, T end) -{ - return Range<T>(begin, end); -} - -template<typename T> -Range<T> range(T end) -{ - return Range<T>(T(0), end); -} - -static void emitReflectionEntryPointJSON( - PrettyWriter& writer, - slang::EntryPointReflection* entryPoint) -{ - write(writer, "{\n"); - indent(writer); - - emitReflectionNameInfoJSON(writer, entryPoint->getName()); - - switch (entryPoint->getStage()) - { - case SLANG_STAGE_VERTEX: write(writer, ",\n\"stage:\": \"vertex\""); break; - case SLANG_STAGE_HULL: write(writer, ",\n\"stage:\": \"hull\""); break; - case SLANG_STAGE_DOMAIN: write(writer, ",\n\"stage:\": \"domain\""); break; - case SLANG_STAGE_GEOMETRY: write(writer, ",\n\"stage:\": \"geometry\""); break; - case SLANG_STAGE_FRAGMENT: write(writer, ",\n\"stage:\": \"fragment\""); break; - case SLANG_STAGE_COMPUTE: write(writer, ",\n\"stage:\": \"compute\""); break; - default: - break; - } - - auto parameterCount = entryPoint->getParameterCount(); - if (parameterCount) - { - write(writer, ",\n\"parameters\": [\n"); - indent(writer); - - for( auto pp : range(parameterCount) ) - { - if(pp != 0) write(writer, ",\n"); - - auto parameter = entryPoint->getParameterByIndex(pp); - emitReflectionParamJSON(writer, parameter); - } - - dedent(writer); - write(writer, "\n]"); - } - - if (entryPoint->usesAnySampleRateInput()) - { - write(writer, ",\n\"usesAnySampleRateInput\": true"); - } - - if (entryPoint->getStage() == SLANG_STAGE_COMPUTE) - { - SlangUInt threadGroupSize[3]; - entryPoint->getComputeThreadGroupSize(3, threadGroupSize); - - write(writer, ",\n\"threadGroupSize\": ["); - for (int ii = 0; ii < 3; ++ii) - { - if (ii != 0) write(writer, ", "); - write(writer, threadGroupSize[ii]); - } - write(writer, "]"); - } - - dedent(writer); - write(writer, "\n}"); -} - -static void emitReflectionJSON( - PrettyWriter& writer, - slang::ShaderReflection* programReflection) -{ - write(writer, "{\n"); - indent(writer); - write(writer, "\"parameters\": [\n"); - indent(writer); - - auto parameterCount = programReflection->getParameterCount(); - for( auto pp : range(parameterCount) ) - { - if(pp != 0) write(writer, ",\n"); - - auto parameter = programReflection->getParameterByIndex(pp); - emitReflectionParamJSON(writer, parameter); - } - - dedent(writer); - write(writer, "\n]"); - - auto entryPointCount = programReflection->getEntryPointCount(); - if (entryPointCount) - { - write(writer, ",\n\"entryPoints\": [\n"); - indent(writer); - - for (auto ee : range(entryPointCount)) - { - if (ee != 0) write(writer, ",\n"); - - auto entryPoint = programReflection->getEntryPointByIndex(ee); - emitReflectionEntryPointJSON(writer, entryPoint); - } - - dedent(writer); - write(writer, "\n]"); - } - - dedent(writer); - write(writer, "\n}\n"); -} - -#if 0 -ReflectionBlob* ReflectionBlob::Create( - CollectionOfTranslationUnits* program) -{ - ReflectionGenerationContext context; - ReflectionBlob* blob = GenerateReflectionBlob(&context, program); -#if 0 - String debugDump = blob->emitAsJSON(); - OutputDebugStringA("REFLECTION BLOB\n"); - OutputDebugStringA(debugDump.begin()); -#endif - return blob; -} -#endif - -// JSON emit logic - - - -String emitReflectionJSON( - ProgramLayout* programLayout) -{ - auto programReflection = (slang::ShaderReflection*) programLayout; - - PrettyWriter writer; - emitReflectionJSON(writer, programReflection); - return writer.sb.ProduceString(); -} - -} diff --git a/source/slang/reflection.h b/source/slang/reflection.h index 3eef47c6b..6c0b39564 100644 --- a/source/slang/reflection.h +++ b/source/slang/reflection.h @@ -19,9 +19,6 @@ typedef uint64_t UInt64; class ProgramLayout; class TypeLayout; -String emitReflectionJSON( - ProgramLayout* programLayout); - // SlangTypeKind getReflectionTypeKind(Type* type); diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index 65abbb3f2..66ff9e429 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -708,17 +708,7 @@ SLANG_API void spSetCodeGenTarget( SlangCompileRequest* request, int target) { - if (target == SLANG_REFLECTION_JSON) - { - // HACK: We special case this because reflection JSON is actually - // an additional output step that layers on top of an existing - // target - REQ(request)->extraTarget = Slang::CodeGenTarget::ReflectionJSON; - } - else - { - REQ(request)->Target = (Slang::CodeGenTarget)target; - } + REQ(request)->Target = (Slang::CodeGenTarget)target; } SLANG_API void spSetPassThrough( diff --git a/tests/reflection/arrays.hlsl b/tests/reflection/arrays.hlsl index 3ef512d31..d013bc498 100644 --- a/tests/reflection/arrays.hlsl +++ b/tests/reflection/arrays.hlsl @@ -1,4 +1,4 @@ -//TEST:SIMPLE:-profile ps_4_0 -target hlsl -target reflection-json +//TEST:REFLECTION:-profile ps_4_0 -target hlsl // Confirm that we can generate reflection info for arrays // diff --git a/tests/reflection/cross-compile.slang b/tests/reflection/cross-compile.slang index 12376c82a..600f3ed0f 100644 --- a/tests/reflection/cross-compile.slang +++ b/tests/reflection/cross-compile.slang @@ -1,4 +1,4 @@ -//TEST(smoke):SIMPLE:-profile glsl_fragment -target glsl -target reflection-json +//TEST(smoke):REFLECTION:-profile glsl_fragment -target glsl // Confirm that when targetting GLSL via cross compilation, // we use the Vulkan layout rules instead of HLSL ones diff --git a/tests/reflection/gh-55.glsl b/tests/reflection/gh-55.glsl index ab8177c77..f6db07482 100644 --- a/tests/reflection/gh-55.glsl +++ b/tests/reflection/gh-55.glsl @@ -1,4 +1,4 @@ -//TEST(smoke):SIMPLE:-profile ps_4_0 -target glsl -target reflection-json +//TEST(smoke):REFLECTION:-profile ps_4_0 -target glsl // Confirm fix for GitHub issue #55 diff --git a/tests/reflection/global-uniforms.hlsl b/tests/reflection/global-uniforms.hlsl index 4ad1a4bbb..884042cfa 100644 --- a/tests/reflection/global-uniforms.hlsl +++ b/tests/reflection/global-uniforms.hlsl @@ -1,4 +1,4 @@ -//TEST:SIMPLE:-profile ps_4_0 -target hlsl -target reflection-json +//TEST:REFLECTION:-profile ps_4_0 -target hlsl // Confirm that we handle uniforms at global scope diff --git a/tests/reflection/image-types.glsl b/tests/reflection/image-types.glsl index bf7c396af..9bba69d3d 100644 --- a/tests/reflection/image-types.glsl +++ b/tests/reflection/image-types.glsl @@ -1,4 +1,4 @@ -//TEST(smoke):SIMPLE:-profile ps_4_0 -target glsl -target reflection-json +//TEST(smoke):REFLECTION:-profile ps_4_0 -target glsl // Confirm that we expose GLSL `image` types through reflection diff --git a/tests/reflection/multi-file.hlsl b/tests/reflection/multi-file.hlsl index 47264f2ec..3282c12f4 100644 --- a/tests/reflection/multi-file.hlsl +++ b/tests/reflection/multi-file.hlsl @@ -1,4 +1,4 @@ -//TEST:SIMPLE:-profile ps_4_0 -entry mainFS -target hlsl -target reflection-json tests/reflection/multi-file-extra.hlsl -profile vs_4_0 -entry mainVS +//TEST:REFLECTION:-profile ps_4_0 -entry mainFS -target hlsl tests/reflection/multi-file-extra.hlsl -profile vs_4_0 -entry mainVS // Here we are testing the case where multiple translation units are provided // at once, so that we want combined reflection information for the resulting diff --git a/tests/reflection/reflect-imported-code.hlsl b/tests/reflection/reflect-imported-code.hlsl index 04f58af19..c3562af35 100644 --- a/tests/reflection/reflect-imported-code.hlsl +++ b/tests/reflection/reflect-imported-code.hlsl @@ -1,4 +1,4 @@ -//TEST:SIMPLE:-profile ps_4_0 -target hlsl -target reflection-json +//TEST:REFLECTION:-profile ps_4_0 -target hlsl // Confirm that shader parameters in imported modules get reflected properly. diff --git a/tests/reflection/reflection0.hlsl b/tests/reflection/reflection0.hlsl index 944bb795e..22232b59a 100644 --- a/tests/reflection/reflection0.hlsl +++ b/tests/reflection/reflection0.hlsl @@ -1,4 +1,4 @@ -//TEST:SIMPLE:-profile ps_4_0 -target hlsl -target reflection-json +//TEST:REFLECTION:-profile ps_4_0 -target hlsl // Confirm that basic reflection info can be output diff --git a/tests/reflection/resource-in-cbuffer.hlsl b/tests/reflection/resource-in-cbuffer.hlsl index b54399bd7..b96f73113 100644 --- a/tests/reflection/resource-in-cbuffer.hlsl +++ b/tests/reflection/resource-in-cbuffer.hlsl @@ -1,4 +1,4 @@ -//TEST(smoke):SIMPLE:-profile ps_4_0 -target hlsl -target reflection-json +//TEST(smoke):REFLECTION:-profile ps_4_0 -target hlsl // Confirm that we can generate reflection // information for resources nested inside diff --git a/tests/reflection/sample-rate-input.glsl b/tests/reflection/sample-rate-input.glsl index 66763f45d..b8151aee1 100644 --- a/tests/reflection/sample-rate-input.glsl +++ b/tests/reflection/sample-rate-input.glsl @@ -1,4 +1,4 @@ -//TEST(smoke):SIMPLE:-profile ps_4_0 -no-checking -target reflection-json +//TEST(smoke):REFLECTION:-profile ps_4_0 -no-checking // Check that we report sample-rate entry point input correctly diff --git a/tests/reflection/std430-layout.glsl b/tests/reflection/std430-layout.glsl index 8afda8e0c..73e48a8a0 100644 --- a/tests/reflection/std430-layout.glsl +++ b/tests/reflection/std430-layout.glsl @@ -1,5 +1,5 @@ #version 450 -//TEST(smoke):SIMPLE:-profile ps_4_0 -target glsl -target reflection-json +//TEST(smoke):REFLECTION:-profile ps_4_0 -target glsl // Confirm fix for GitHub issue #55 diff --git a/tests/reflection/thread-group-size.comp b/tests/reflection/thread-group-size.comp index fac755433..ff29490a5 100644 --- a/tests/reflection/thread-group-size.comp +++ b/tests/reflection/thread-group-size.comp @@ -1,4 +1,4 @@ -//TEST:SIMPLE:-no-checking -target glsl -target reflection-json +//TEST:REFLECTION:-no-checking -target glsl // Confirm that we provide reflection data for the `local_size_*` attributes diff --git a/tests/reflection/thread-group-size.hlsl b/tests/reflection/thread-group-size.hlsl index eb2fb98ad..7e0400b46 100644 --- a/tests/reflection/thread-group-size.hlsl +++ b/tests/reflection/thread-group-size.hlsl @@ -1,4 +1,4 @@ -//TEST:SIMPLE:-profile cs_5_0 -target hlsl -target reflection-json +//TEST:REFLECTION:-profile cs_5_0 -target hlsl // Confirm that we provide reflection data for the `numthreads` attribute diff --git a/tools/slang-reflection-test/main.cpp b/tools/slang-reflection-test/main.cpp new file mode 100644 index 000000000..9568dc3fe --- /dev/null +++ b/tools/slang-reflection-test/main.cpp @@ -0,0 +1,752 @@ +// main.cpp + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <slang.h> + +struct PrettyWriter +{ + bool startOfLine = true; + int indent = 0; +}; + +static void writeRaw(PrettyWriter& writer, char const* begin, char const* end) +{ + fprintf(stdout, "%.*s", int(end - begin), begin); +} + +static void writeRaw(PrettyWriter& writer, char const* begin) +{ + writeRaw(writer, begin, begin + strlen(begin)); +} + +static void writeRawChar(PrettyWriter& writer, int c) +{ + char buffer[] = { (char) c, 0 }; + writeRaw(writer, buffer); +} + +static void adjust(PrettyWriter& writer) +{ + if (!writer.startOfLine) + return; + + int indent = writer.indent; + for (int ii = 0; ii < indent; ++ii) + writeRaw(writer, " "); + + writer.startOfLine = false; +} + +static void indent(PrettyWriter& writer) +{ + writer.indent++; +} + +static void dedent(PrettyWriter& writer) +{ + writer.indent--; +} + +static void write(PrettyWriter& writer, char const* text) +{ + // TODO: can do this more efficiently... + char const* cursor = text; + for(;;) + { + char c = *cursor++; + if (!c) break; + + if (c == '\n') + { + writer.startOfLine = true; + } + else + { + adjust(writer); + } + + writeRawChar(writer, c); + } +} + +static void write(PrettyWriter& writer, SlangUInt val) +{ + adjust(writer); + fprintf(stdout, "%llu", (unsigned long long)val); +} + +static void emitReflectionVarInfoJSON(PrettyWriter& writer, slang::VariableReflection* var); +static void emitReflectionTypeLayoutJSON(PrettyWriter& writer, slang::TypeLayoutReflection* type); +static void emitReflectionTypeJSON(PrettyWriter& writer, slang::TypeReflection* type); + +static void emitReflectionVarBindingInfoJSON( + PrettyWriter& writer, + SlangParameterCategory category, + SlangUInt index, + SlangUInt count, + SlangUInt space = 0) +{ + if( category == SLANG_PARAMETER_CATEGORY_UNIFORM ) + { + write(writer,"\"kind\": \"uniform\""); + write(writer, ", "); + write(writer,"\"offset\": "); + write(writer, index); + write(writer, ", "); + write(writer, "\"size\": "); + write(writer, count); + } + else + { + write(writer, "\"kind\": \""); + switch( category ) + { + #define CASE(NAME, KIND) case SLANG_PARAMETER_CATEGORY_##NAME: write(writer, #KIND); break + CASE(CONSTANT_BUFFER, constantBuffer); + CASE(SHADER_RESOURCE, shaderResource); + CASE(UNORDERED_ACCESS, unorderedAccess); + CASE(VERTEX_INPUT, vertexInput); + CASE(FRAGMENT_OUTPUT, fragmentOutput); + CASE(SAMPLER_STATE, samplerState); + CASE(UNIFORM, uniform); + CASE(DESCRIPTOR_TABLE_SLOT, descriptorTableSlot); + CASE(SPECIALIZATION_CONSTANT, specializationConstant); + CASE(MIXED, mixed); + #undef CASE + + default: + write(writer, "unknown"); + assert(!"unhandled case"); + break; + } + write(writer, "\""); + if( space ) + { + write(writer, ", "); + write(writer, "\"space\": "); + write(writer, space); + } + write(writer, ", "); + write(writer, "\"index\": "); + write(writer, index); + if( count != 1) + { + write(writer, ", "); + write(writer, "\"count\": "); + write(writer, count); + } + } +} + +static void emitReflectionVarBindingInfoJSON( + PrettyWriter& writer, + slang::VariableLayoutReflection* var) +{ + auto typeLayout = var->getTypeLayout(); + auto categoryCount = var->getCategoryCount(); + + if( categoryCount != 1 ) + { + write(writer,"\"bindings\": [\n"); + } + else + { + write(writer,"\"binding\": "); + } + indent(writer); + + for(uint32_t cc = 0; cc < categoryCount; ++cc ) + { + auto category = var->getCategoryByIndex(cc); + auto index = var->getOffset(category); + auto space = var->getBindingSpace(category); + auto count = typeLayout->getSize(category); + + if (cc != 0) write(writer, ",\n"); + + write(writer,"{"); + emitReflectionVarBindingInfoJSON( + writer, + category, + index, + count, + space); + write(writer,"}"); + } + + dedent(writer); + if( categoryCount != 1 ) + { + write(writer,"\n]"); + } +} + +static void emitReflectionNameInfoJSON( + PrettyWriter& writer, + char const* name) +{ + // TODO: deal with escaping special characters if/when needed + write(writer, "\"name\": \""); + write(writer, name); + write(writer, "\""); +} + +static void emitReflectionVarLayoutJSON( + PrettyWriter& writer, + slang::VariableLayoutReflection* var) +{ + write(writer, "{\n"); + indent(writer); + + emitReflectionNameInfoJSON(writer, var->getName()); + write(writer, ",\n"); + + write(writer, "\"type\": "); + emitReflectionTypeLayoutJSON(writer, var->getTypeLayout()); + write(writer, ",\n"); + + emitReflectionVarBindingInfoJSON(writer, var); + + dedent(writer); + write(writer, "\n}"); +} + +static void emitReflectionScalarTypeInfoJSON( + PrettyWriter& writer, + SlangScalarType scalarType) +{ + write(writer, "\"scalarType\": \""); + switch (scalarType) + { + default: + write(writer, "unknown"); + assert(!"unhandled case"); + break; +#define CASE(TAG, ID) case slang::TypeReflection::ScalarType::TAG: write(writer, #ID); break + CASE(Void, void); + CASE(Bool, bool); + CASE(Int32, int32); + CASE(UInt32, uint32); + CASE(Int64, int64); + CASE(UInt64, uint64); + CASE(Float16, float16); + CASE(Float32, float32); + CASE(Float64, float64); +#undef CASE + } + write(writer, "\""); +} + +static void emitReflectionTypeInfoJSON( + PrettyWriter& writer, + slang::TypeReflection* type) +{ + switch( type->getKind() ) + { + case slang::TypeReflection::Kind::SamplerState: + write(writer, "\"kind\": \"samplerState\""); + break; + + case slang::TypeReflection::Kind::Resource: + { + auto shape = type->getResourceShape(); + auto access = type->getResourceAccess(); + write(writer, "\"kind\": \"resource\""); + write(writer, ",\n"); + write(writer, "\"baseShape\": \""); + switch (shape & SLANG_RESOURCE_BASE_SHAPE_MASK) + { + default: + write(writer, "unknown"); + assert(!"unhandled case"); + break; + +#define CASE(SHAPE, NAME) case SLANG_##SHAPE: write(writer, #NAME); break + CASE(TEXTURE_1D, texture1D); + CASE(TEXTURE_2D, texture2D); + CASE(TEXTURE_3D, texture3D); + CASE(TEXTURE_CUBE, textureCube); + CASE(TEXTURE_BUFFER, textureBuffer); + CASE(STRUCTURED_BUFFER, structuredBuffer); + CASE(BYTE_ADDRESS_BUFFER, byteAddressBuffer); +#undef CASE + } + write(writer, "\""); + if (shape & SLANG_TEXTURE_ARRAY_FLAG) + { + write(writer, ",\n"); + write(writer, "\"array\": true"); + } + if (shape & SLANG_TEXTURE_MULTISAMPLE_FLAG) + { + write(writer, ",\n"); + write(writer, "\"multisample\": true"); + } + + if( access != SLANG_RESOURCE_ACCESS_READ ) + { + write(writer, ",\n\"access\": \""); + switch(access) + { + default: + write(writer, "unknown"); + assert(!"unhandled case"); + break; + + case SLANG_RESOURCE_ACCESS_READ: + break; + + case SLANG_RESOURCE_ACCESS_READ_WRITE: write(writer, "readWrite"); break; + case SLANG_RESOURCE_ACCESS_RASTER_ORDERED: write(writer, "rasterOrdered"); break; + case SLANG_RESOURCE_ACCESS_APPEND: write(writer, "append"); break; + case SLANG_RESOURCE_ACCESS_CONSUME: write(writer, "consume"); break; + } + write(writer, "\""); + } + } + break; + + case slang::TypeReflection::Kind::ConstantBuffer: + write(writer, "\"kind\": \"constantBuffer\""); + write(writer, ",\n"); + write(writer, "\"elementType\": "); + emitReflectionTypeJSON( + writer, + type->getElementType()); + break; + + case slang::TypeReflection::Kind::TextureBuffer: + write(writer, "\"kind\": \"textureBuffer\""); + write(writer, ",\n"); + write(writer, "\"elementType\": "); + emitReflectionTypeJSON( + writer, + type->getElementType()); + break; + + case slang::TypeReflection::Kind::ShaderStorageBuffer: + write(writer, "\"kind\": \"shaderStorageBuffer\""); + write(writer, ",\n"); + write(writer, "\"elementType\": "); + emitReflectionTypeJSON( + writer, + type->getElementType()); + break; + + case slang::TypeReflection::Kind::Scalar: + write(writer, "\"kind\": \"scalar\""); + write(writer, ",\n"); + emitReflectionScalarTypeInfoJSON( + writer, + type->getScalarType()); + break; + + case slang::TypeReflection::Kind::Vector: + write(writer, "\"kind\": \"vector\""); + write(writer, ",\n"); + write(writer, "\"elementCount\": "); + write(writer, type->getElementCount()); + write(writer, ",\n"); + write(writer, "\"elementType\": "); + emitReflectionTypeJSON( + writer, + type->getElementType()); + break; + + case slang::TypeReflection::Kind::Matrix: + write(writer, "\"kind\": \"matrix\""); + write(writer, ",\n"); + write(writer, "\"rowCount\": "); + write(writer, type->getRowCount()); + write(writer, ",\n"); + write(writer, "\"columnCount\": "); + write(writer, type->getColumnCount()); + write(writer, ",\n"); + write(writer, "\"elementType\": "); + emitReflectionTypeJSON( + writer, + type->getElementType()); + break; + + case slang::TypeReflection::Kind::Array: + { + auto arrayType = type; + write(writer, "\"kind\": \"array\""); + write(writer, ",\n"); + write(writer, "\"elementCount\": "); + write(writer, arrayType->getElementCount()); + write(writer, ",\n"); + write(writer, "\"elementType\": "); + emitReflectionTypeJSON(writer, arrayType->getElementType()); + } + break; + + case slang::TypeReflection::Kind::Struct: + { + write(writer, "\"kind\": \"struct\",\n"); + write(writer, "\"fields\": [\n"); + indent(writer); + + auto structType = type; + auto fieldCount = structType->getFieldCount(); + for( uint32_t ff = 0; ff < fieldCount; ++ff ) + { + if (ff != 0) write(writer, ",\n"); + emitReflectionVarInfoJSON( + writer, + structType->getFieldByIndex(ff)); + } + dedent(writer); + write(writer, "\n]"); + } + break; + + default: + assert(!"unhandled case"); + break; + } +} + +static void emitReflectionTypeLayoutInfoJSON( + PrettyWriter& writer, + slang::TypeLayoutReflection* typeLayout) +{ + switch( typeLayout->getKind() ) + { + default: + emitReflectionTypeInfoJSON(writer, typeLayout->getType()); + break; + + case slang::TypeReflection::Kind::Array: + { + auto arrayTypeLayout = typeLayout; + auto elementTypeLayout = arrayTypeLayout->getElementTypeLayout(); + write(writer, "\"kind\": \"array\""); + write(writer, ",\n"); + write(writer, "\"elementCount\": "); + write(writer, arrayTypeLayout->getElementCount()); + write(writer, ",\n"); + write(writer, "\"elementType\": "); + emitReflectionTypeLayoutJSON( + writer, + elementTypeLayout); + if (arrayTypeLayout->getSize(SLANG_PARAMETER_CATEGORY_UNIFORM) != 0) + { + write(writer, ",\n"); + write(writer, "\"uniformStride\": "); + write(writer, arrayTypeLayout->getElementStride(SLANG_PARAMETER_CATEGORY_UNIFORM)); + } + } + break; + + case slang::TypeReflection::Kind::Struct: + { + write(writer, "\"kind\": \"struct\",\n"); + write(writer, "\"fields\": [\n"); + indent(writer); + + auto structTypeLayout = typeLayout; + auto fieldCount = structTypeLayout->getFieldCount(); + for( uint32_t ff = 0; ff < fieldCount; ++ff ) + { + if (ff != 0) write(writer, ",\n"); + emitReflectionVarLayoutJSON( + writer, + structTypeLayout->getFieldByIndex(ff)); + } + dedent(writer); + write(writer, "\n]"); + } + break; + + case slang::TypeReflection::Kind::ConstantBuffer: + write(writer, "\"kind\": \"constantBuffer\""); + write(writer, ",\n"); + write(writer, "\"elementType\": "); + emitReflectionTypeLayoutJSON( + writer, + typeLayout->getElementTypeLayout()); + break; + + case slang::TypeReflection::Kind::TextureBuffer: + write(writer, "\"kind\": \"textureBuffer\""); + write(writer, ",\n"); + write(writer, "\"elementType\": "); + emitReflectionTypeLayoutJSON( + writer, + typeLayout->getElementTypeLayout()); + break; + + case slang::TypeReflection::Kind::ShaderStorageBuffer: + write(writer, "\"kind\": \"shaderStorageBuffer\""); + write(writer, ",\n"); + write(writer, "\"elementType\": "); + emitReflectionTypeLayoutJSON( + writer, + typeLayout->getElementTypeLayout()); + break; + } + + // TODO: emit size info for types +} + +static void emitReflectionTypeLayoutJSON( + PrettyWriter& writer, + slang::TypeLayoutReflection* typeLayout) +{ + write(writer, "{\n"); + indent(writer); + emitReflectionTypeLayoutInfoJSON(writer, typeLayout); + dedent(writer); + write(writer, "\n}"); +} + +static void emitReflectionTypeJSON( + PrettyWriter& writer, + slang::TypeReflection* type) +{ + write(writer, "{\n"); + indent(writer); + emitReflectionTypeInfoJSON(writer, type); + dedent(writer); + write(writer, "\n}"); +} + +static void emitReflectionVarInfoJSON( + PrettyWriter& writer, + slang::VariableReflection* var) +{ + emitReflectionNameInfoJSON(writer, var->getName()); + write(writer, ",\n"); + + write(writer, "\"type\": "); + emitReflectionTypeJSON(writer, var->getType()); +} + +static void emitReflectionParamJSON( + PrettyWriter& writer, + slang::VariableLayoutReflection* param) +{ + write(writer, "{\n"); + indent(writer); + + emitReflectionNameInfoJSON(writer, param->getName()); + write(writer, ",\n"); + + emitReflectionVarBindingInfoJSON(writer, param); + write(writer, ",\n"); + + write(writer, "\"type\": "); + emitReflectionTypeLayoutJSON(writer, param->getTypeLayout()); + + dedent(writer); + write(writer, "\n}"); +} + +template<typename T> +struct Range +{ +public: + Range( + T begin, + T end) + : mBegin(begin) + , mEnd(end) + {} + + struct Iterator + { + public: + explicit Iterator(T value) + : mValue(value) + {} + + T operator*() const { return mValue; } + void operator++() { mValue++; } + + bool operator!=(Iterator const& other) + { + return mValue != other.mValue; + } + + private: + T mValue; + }; + + Iterator begin() const { return Iterator(mBegin); } + Iterator end() const { return Iterator(mEnd); } + +private: + T mBegin; + T mEnd; +}; + +template<typename T> +Range<T> range(T begin, T end) +{ + return Range<T>(begin, end); +} + +template<typename T> +Range<T> range(T end) +{ + return Range<T>(T(0), end); +} + +static void emitReflectionEntryPointJSON( + PrettyWriter& writer, + slang::EntryPointReflection* entryPoint) +{ + write(writer, "{\n"); + indent(writer); + + emitReflectionNameInfoJSON(writer, entryPoint->getName()); + + switch (entryPoint->getStage()) + { + case SLANG_STAGE_VERTEX: write(writer, ",\n\"stage:\": \"vertex\""); break; + case SLANG_STAGE_HULL: write(writer, ",\n\"stage:\": \"hull\""); break; + case SLANG_STAGE_DOMAIN: write(writer, ",\n\"stage:\": \"domain\""); break; + case SLANG_STAGE_GEOMETRY: write(writer, ",\n\"stage:\": \"geometry\""); break; + case SLANG_STAGE_FRAGMENT: write(writer, ",\n\"stage:\": \"fragment\""); break; + case SLANG_STAGE_COMPUTE: write(writer, ",\n\"stage:\": \"compute\""); break; + default: + break; + } + + auto parameterCount = entryPoint->getParameterCount(); + if (parameterCount) + { + write(writer, ",\n\"parameters\": [\n"); + indent(writer); + + for( auto pp : range(parameterCount) ) + { + if(pp != 0) write(writer, ",\n"); + + auto parameter = entryPoint->getParameterByIndex(pp); + emitReflectionParamJSON(writer, parameter); + } + + dedent(writer); + write(writer, "\n]"); + } + + if (entryPoint->usesAnySampleRateInput()) + { + write(writer, ",\n\"usesAnySampleRateInput\": true"); + } + + if (entryPoint->getStage() == SLANG_STAGE_COMPUTE) + { + SlangUInt threadGroupSize[3]; + entryPoint->getComputeThreadGroupSize(3, threadGroupSize); + + write(writer, ",\n\"threadGroupSize\": ["); + for (int ii = 0; ii < 3; ++ii) + { + if (ii != 0) write(writer, ", "); + write(writer, threadGroupSize[ii]); + } + write(writer, "]"); + } + + dedent(writer); + write(writer, "\n}"); +} + +static void emitReflectionJSON( + PrettyWriter& writer, + slang::ShaderReflection* programReflection) +{ + write(writer, "{\n"); + indent(writer); + write(writer, "\"parameters\": [\n"); + indent(writer); + + auto parameterCount = programReflection->getParameterCount(); + for( auto pp : range(parameterCount) ) + { + if(pp != 0) write(writer, ",\n"); + + auto parameter = programReflection->getParameterByIndex(pp); + emitReflectionParamJSON(writer, parameter); + } + + dedent(writer); + write(writer, "\n]"); + + auto entryPointCount = programReflection->getEntryPointCount(); + if (entryPointCount) + { + write(writer, ",\n\"entryPoints\": [\n"); + indent(writer); + + for (auto ee : range(entryPointCount)) + { + if (ee != 0) write(writer, ",\n"); + + auto entryPoint = programReflection->getEntryPointByIndex(ee); + emitReflectionEntryPointJSON(writer, entryPoint); + } + + dedent(writer); + write(writer, "\n]"); + } + + dedent(writer); + write(writer, "\n}\n"); +} + +void emitReflectionJSON( + SlangReflection* reflection) +{ + auto programReflection = (slang::ShaderReflection*) reflection; + + PrettyWriter writer; + emitReflectionJSON(writer, programReflection); +} + + +int main( + int argc, + char** argv) +{ + // Parse any command-line options + + SlangSession* session = spCreateSession(nullptr); + SlangCompileRequest* request = spCreateCompileRequest(session); + + char const* appName = "slang-reflection-test"; + if(argc > 0) appName = argv[0]; + + int err = spProcessCommandLineArguments(request, &argv[1], argc - 1); + if( err ) + { + char const* output = spGetDiagnosticOutput(request); + fputs(output, stderr); + exit(1); + } + + if( spCompile(request) != 0 ) + { + char const* output = spGetDiagnosticOutput(request); + fputs(output, stderr); + exit(1); + } + + // Okay, let's go through and emit reflection info on whatever + // we have. + + SlangReflection* reflection = spGetReflection(request); + emitReflectionJSON(reflection); + + spDestroyCompileRequest(request); + spDestroySession(session); + + return 0; +} diff --git a/tools/slang-reflection-test/slang-reflection-test.vcxproj b/tools/slang-reflection-test/slang-reflection-test.vcxproj new file mode 100644 index 000000000..5ac386d57 --- /dev/null +++ b/tools/slang-reflection-test/slang-reflection-test.vcxproj @@ -0,0 +1,163 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{22C45F4F-FB6B-4535-BED1-D3F5D0C71047}</ProjectGuid> + <Keyword>Win32Proj</Keyword> + <RootNamespace>slangreflectiontest</RootNamespace> + <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v140</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v140</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v140</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v140</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="Shared"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\..\build\slang-build.props" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\..\build\slang-build.props" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\..\build\slang-build.props" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + <Import Project="..\..\build\slang-build.props" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <LinkIncremental>true</LinkIncremental> + <IncludePath>$(SolutionDir);$(IncludePath)</IncludePath> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <LinkIncremental>true</LinkIncremental> + <IncludePath>$(SolutionDir);$(IncludePath)</IncludePath> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <LinkIncremental>false</LinkIncremental> + <IncludePath>$(SolutionDir);$(IncludePath)</IncludePath> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <LinkIncremental>false</LinkIncremental> + <IncludePath>$(SolutionDir);$(IncludePath)</IncludePath> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <PrecompiledHeader> + </PrecompiledHeader> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <PrecompiledHeader> + </PrecompiledHeader> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="main.cpp" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\..\source\slang\slang.vcxproj"> + <Project>{db00da62-0533-4afd-b59f-a67d5b3a0808}</Project> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/tools/slang-reflection-test/slang-reflection-test.vcxproj.filters b/tools/slang-reflection-test/slang-reflection-test.vcxproj.filters new file mode 100644 index 000000000..0d8d9e457 --- /dev/null +++ b/tools/slang-reflection-test/slang-reflection-test.vcxproj.filters @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="main.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/tools/slang-test/main.cpp b/tools/slang-test/main.cpp index 0bf2ff6af..83d512cc1 100644 --- a/tools/slang-test/main.cpp +++ b/tools/slang-test/main.cpp @@ -691,6 +691,67 @@ TestResult runSimpleTest(TestInput& input) return result; } +TestResult runReflectionTest(TestInput& input) +{ + auto filePath = input.filePath; + auto outputStem = input.outputStem; + + OSProcessSpawner spawner; + + spawner.pushExecutablePath(String(options.binDir) + "slang-reflection-test" + osGetExecutableSuffix()); + spawner.pushArgument(filePath); + + for( auto arg : input.testOptions->args ) + { + spawner.pushArgument(arg); + } + + if (spawnAndWait(outputStem, spawner) != kOSError_None) + { + return kTestResult_Fail; + } + + String actualOutput = getOutput(spawner); + + String expectedOutputPath = outputStem + ".expected"; + String expectedOutput; + try + { + expectedOutput = Slang::File::ReadAllText(expectedOutputPath); + } + catch (Slang::IOException) + { + } + + // If no expected output file was found, then we + // expect everything to be empty + if (expectedOutput.Length() == 0) + { + expectedOutput = "result code = 0\nstandard error = {\n}\nstandard output = {\n}\n"; + } + + TestResult result = kTestResult_Pass; + + // Otherwise we compare to the expected output + if (actualOutput != expectedOutput) + { + result = kTestResult_Fail; + } + + // If the test failed, then we write the actual output to a file + // so that we can easily diff it from the command line and + // diagnose the problem. + if (result == kTestResult_Fail) + { + String actualOutputPath = outputStem + ".actual"; + Slang::File::WriteAllText(actualOutputPath, actualOutput); + + maybeDumpOutput(expectedOutput, actualOutput); + } + + return result; +} + TestResult runEvalTest(TestInput& input) { // We are going to load and evaluate the code @@ -1235,6 +1296,7 @@ TestResult runTest( TestCallback callback; } kTestCommands[] = { { "SIMPLE", &runSimpleTest }, + { "REFLECTION", &runReflectionTest }, #if SLANG_TEST_SUPPORT_HLSL { "COMPARE_HLSL", &runHLSLComparisonTest }, { "COMPARE_HLSL_RENDER", &runHLSLRenderComparisonTest }, |
