summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile12
-rw-r--r--slang.h1
-rw-r--r--slang.sln13
-rw-r--r--source/slang/compiler.cpp40
-rw-r--r--source/slang/compiler.h5
-rw-r--r--source/slang/options.cpp4
-rw-r--r--source/slang/reflection.cpp734
-rw-r--r--source/slang/reflection.h3
-rw-r--r--source/slang/slang.cpp12
-rw-r--r--tests/reflection/arrays.hlsl2
-rw-r--r--tests/reflection/cross-compile.slang2
-rw-r--r--tests/reflection/gh-55.glsl2
-rw-r--r--tests/reflection/global-uniforms.hlsl2
-rw-r--r--tests/reflection/image-types.glsl2
-rw-r--r--tests/reflection/multi-file.hlsl2
-rw-r--r--tests/reflection/reflect-imported-code.hlsl2
-rw-r--r--tests/reflection/reflection0.hlsl2
-rw-r--r--tests/reflection/resource-in-cbuffer.hlsl2
-rw-r--r--tests/reflection/sample-rate-input.glsl2
-rw-r--r--tests/reflection/std430-layout.glsl2
-rw-r--r--tests/reflection/thread-group-size.comp2
-rw-r--r--tests/reflection/thread-group-size.hlsl2
-rw-r--r--tools/slang-reflection-test/main.cpp752
-rw-r--r--tools/slang-reflection-test/slang-reflection-test.vcxproj163
-rw-r--r--tools/slang-reflection-test/slang-reflection-test.vcxproj.filters22
-rw-r--r--tools/slang-test/main.cpp62
26 files changed, 1037 insertions, 812 deletions
diff --git a/Makefile b/Makefile
index 995685d5c..c4ed43922 100644
--- a/Makefile
+++ b/Makefile
@@ -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:
diff --git a/slang.h b/slang.h
index 5a8591d84..510168e66 100644
--- a/slang.h
+++ b/slang.h
@@ -89,7 +89,6 @@ extern "C"
SLANG_SPIRV_ASM,
SLANG_DXBC,
SLANG_DXBC_ASM,
- SLANG_REFLECTION_JSON,
SLANG_IR,
SLANG_IR_ASM,
};
diff --git a/slang.sln b/slang.sln
index 2c672886e..33b903056 100644
--- a/slang.sln
+++ b/slang.sln
@@ -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 },