summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--slang.h1
-rw-r--r--source/core/smart-pointer.h2
-rw-r--r--source/slang/compiled-program.h13
-rw-r--r--source/slang/compiler.cpp28
-rw-r--r--source/slang/compiler.h8
-rw-r--r--source/slang/emit.cpp130
-rw-r--r--source/slang/lower.cpp136
-rw-r--r--source/slang/modifier-defs.h1
-rw-r--r--source/slang/options.cpp2
-rw-r--r--source/slang/parameter-binding.cpp95
-rw-r--r--source/slang/reflection.cpp11
-rw-r--r--source/slang/slang-stdlib.cpp29
-rw-r--r--source/slang/slang.cpp56
-rw-r--r--source/slang/slang.vcxproj1
-rw-r--r--source/slang/slang.vcxproj.filters1
-rw-r--r--source/slang/syntax-visitors.h1
-rw-r--r--source/slang/type-layout.cpp13
-rw-r--r--source/slang/type-layout.h7
-rw-r--r--tests/preprocessor/import.hlsl2
-rw-r--r--tests/reflection/cross-compile.slang23
-rw-r--r--tests/reflection/cross-compile.slang.expected48
-rw-r--r--tests/render/cross-compile0.hlsl4
-rw-r--r--tests/render/imported-parameters.hlsl4
-rw-r--r--tests/render/pound-import.hlsl4
24 files changed, 500 insertions, 120 deletions
diff --git a/slang.h b/slang.h
index b6f35f255..87419bf45 100644
--- a/slang.h
+++ b/slang.h
@@ -66,6 +66,7 @@ extern "C"
enum
{
SLANG_TARGET_UNKNOWN,
+ SLANG_TARGET_NONE,
SLANG_GLSL,
SLANG_GLSL_VULKAN,
SLANG_GLSL_VULKAN_ONE_DESC,
diff --git a/source/core/smart-pointer.h b/source/core/smart-pointer.h
index 19ddde931..fea149e06 100644
--- a/source/core/smart-pointer.h
+++ b/source/core/smart-pointer.h
@@ -163,7 +163,7 @@ namespace Slang
~RefPtr()
{
- releaseReference(pointer);
+ releaseReference((Slang::RefObject*) pointer);
}
T& operator*() const
diff --git a/source/slang/compiled-program.h b/source/slang/compiled-program.h
deleted file mode 100644
index 7f5b674a0..000000000
--- a/source/slang/compiled-program.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef BAKER_SL_COMPILED_PROGRAM_H
-#define BAKER_SL_COMPILED_PROGRAM_H
-
-#include "../core/basic.h"
-#include "diagnostics.h"
-#include "syntax.h"
-#include "type-layout.h"
-
-namespace Slang
-{
-}
-
-#endif \ No newline at end of file
diff --git a/source/slang/compiler.cpp b/source/slang/compiler.cpp
index 19623a7aa..2f6204eb2 100644
--- a/source/slang/compiler.cpp
+++ b/source/slang/compiler.cpp
@@ -461,6 +461,10 @@ namespace Slang
}
break;
+ case CodeGenTarget::None:
+ // The user requested no output
+ break;
+
// Note(tfoley): We currently hit this case when compiling the stdlib
case CodeGenTarget::Unknown:
break;
@@ -520,17 +524,9 @@ namespace Slang
void generateOutput(
CompileRequest* compileRequest)
{
- switch (compileRequest->Target)
+ // Allow for an "extra" target to verride things first.
+ switch (compileRequest->extraTarget)
{
- default:
- // For most targets, we will do things per-translation-unit
- for( auto translationUnit : compileRequest->translationUnits )
- {
- TranslationUnitResult translationUnitResult = emitTranslationUnit(translationUnit.Ptr());
- translationUnit->result = translationUnitResult;
- }
- break;
-
case CodeGenTarget::ReflectionJSON:
{
String reflectionJSON = emitReflectionJSON(compileRequest->layout.Ptr());
@@ -538,8 +534,20 @@ namespace Slang
// HACK(tfoley): just print it out since that is what people probably expect.
// TODO: need a way to control where output gets routed across all possible targets.
fprintf(stdout, "%s", reflectionJSON.begin());
+
+ return;
}
break;
+
+ default:
+ break;
+ }
+
+ // For most targets, we will do things per-translation-unit
+ for( auto translationUnit : compileRequest->translationUnits )
+ {
+ TranslationUnitResult translationUnitResult = emitTranslationUnit(translationUnit.Ptr());
+ translationUnit->result = translationUnitResult;
}
}
}
diff --git a/source/slang/compiler.h b/source/slang/compiler.h
index b3bcd7ba1..cb7eb6265 100644
--- a/source/slang/compiler.h
+++ b/source/slang/compiler.h
@@ -3,11 +3,9 @@
#include "../core/basic.h"
-#include "compiled-program.h"
#include "diagnostics.h"
#include "profile.h"
#include "syntax.h"
-#include "type-layout.h"
#include "../../slang.h"
@@ -15,6 +13,7 @@ namespace Slang
{
struct IncludeHandler;
class CompileRequest;
+ class ProgramLayout;
enum class CompilerMode
{
@@ -37,6 +36,7 @@ namespace Slang
enum class CodeGenTarget
{
Unknown = SLANG_TARGET_UNKNOWN,
+ None = SLANG_TARGET_NONE,
GLSL = SLANG_GLSL,
GLSL_Vulkan = SLANG_GLSL_VULKAN,
GLSL_Vulkan_OneDesc = SLANG_GLSL_VULKAN_ONE_DESC,
@@ -170,6 +170,10 @@ 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/emit.cpp b/source/slang/emit.cpp
index c135090c1..155e1e39a 100644
--- a/source/slang/emit.cpp
+++ b/source/slang/emit.cpp
@@ -48,6 +48,10 @@ struct SharedEmitContext
StructTypeLayout* globalStructLayout;
ProgramLayout* programLayout;
+
+ ProgramSyntaxNode* program;
+
+ bool needHackSamplerForTexelFetch = false;
};
struct EmitContext
@@ -1758,6 +1762,66 @@ struct EmitVisitor
}
break;
+ case 'P':
+ {
+ // Okay, we need a collosal hack to deal with the fact that GLSL `texelFetch()`
+ // for Vulkan seems to be completely broken by design. It's signature wants
+ // a `sampler2D` for consistency with its peers, but the actual SPIR-V operation
+ // ignores the sampler paart of it, and just used the `texture2D` part.
+ //
+ // The HLSL equivalent (e.g., `Texture2D.Load()`) doesn't provide a sampler
+ // argument, so we seemingly need to conjure one out of thin air. :(
+ //
+ // We are going to hack this *hard* for now.
+
+ // Try to find a suitable sampler-type shader parameter in the global scope
+ // (fingers crossed)
+ RefPtr<VarDeclBase> samplerVar;
+ for (auto d : context->shared->program->Members)
+ {
+ if (auto varDecl = d.As<VarDeclBase>())
+ {
+ if (auto samplerType = varDecl->Type.type->As<SamplerStateType>())
+ {
+ samplerVar = varDecl;
+ break;
+ }
+ }
+ }
+
+ if (auto memberExpr = callExpr->FunctionExpr.As<MemberExpressionSyntaxNode>())
+ {
+ auto base = memberExpr->BaseExpression;
+ if (auto baseTextureType = base->Type->As<TextureType>())
+ {
+ emitGLSLTextureOrTextureSamplerType(baseTextureType, "sampler");
+ Emit("(");
+ EmitExpr(memberExpr->BaseExpression);
+ Emit(",");
+ if (samplerVar)
+ {
+ EmitDeclRef(makeDeclRef(samplerVar.Ptr()));
+ }
+ else
+ {
+ Emit("SLANG_hack_samplerForTexelFetch");
+ context->shared->needHackSamplerForTexelFetch = true;
+ }
+ Emit(")");
+ }
+ else
+ {
+ assert(!"unexpected");
+ }
+
+ }
+ else
+ {
+ assert(!"unexpected");
+ }
+ }
+ break;
+
default:
assert(!"unexpected");
break;
@@ -2095,6 +2159,11 @@ struct EmitVisitor
void EmitStmt(RefPtr<StatementSyntaxNode> stmt)
{
+ // TODO(tfoley): this shouldn't occur, but sometimes
+ // lowering will get confused by an empty function body...
+ if (!stmt)
+ return;
+
// Try to ensure that debugging can find the right location
advanceToSourceLocation(stmt->Position);
@@ -2476,6 +2545,9 @@ struct EmitVisitor
#define CASE(TYPE, KEYWORD) \
else if(auto mod_##TYPE = mod.As<TYPE>()) Emit(#KEYWORD " ")
+ #define CASE2(TYPE, HLSL_NAME, GLSL_NAME) \
+ else if(auto mod_##TYPE = mod.As<TYPE>()) Emit((context->shared->target == CodeGenTarget::GLSL) ? GLSL_NAME : HLSL_NAME)
+
CASE(RowMajorLayoutModifier, row_major);
CASE(ColumnMajorLayoutModifier, column_major);
CASE(HLSLNoInterpolationModifier, nointerpolation);
@@ -2502,6 +2574,7 @@ struct EmitVisitor
CASE(ConstModifier, const);
#undef CASE
+ #undef CASE2
else if (auto staticModifier = mod.As<HLSLStaticModifier>())
{
@@ -2949,7 +3022,8 @@ struct EmitVisitor
}
void emitGLSLLayoutQualifiers(
- RefPtr<VarLayout> layout)
+ RefPtr<VarLayout> layout,
+ LayoutResourceKind filter = LayoutResourceKind::None)
{
if(!layout) return;
@@ -2964,6 +3038,13 @@ struct EmitVisitor
for( auto info : layout->resourceInfos )
{
+ // Skip info that doesn't match our filter
+ if (filter != LayoutResourceKind::None
+ && filter != info.kind)
+ {
+ continue;
+ }
+
emitGLSLLayoutQualifier(info);
}
}
@@ -3095,7 +3176,33 @@ struct EmitVisitor
return;
}
- emitGLSLLayoutQualifiers(layout);
+
+ if (context->shared->target == CodeGenTarget::GLSL)
+ {
+ if (decl->HasModifier<InModifier>())
+ {
+ emitGLSLLayoutQualifiers(layout, LayoutResourceKind::VertexInput);
+ }
+ else if (decl->HasModifier<OutModifier>())
+ {
+ emitGLSLLayoutQualifiers(layout, LayoutResourceKind::FragmentOutput);
+ }
+ else
+ {
+ emitGLSLLayoutQualifiers(layout);
+ }
+
+ // If we have a uniform that wasn't tagged `uniform` in GLSL, then fix that here
+ if (layout
+ && !decl->HasModifier<HLSLUniformModifier>())
+ {
+ if (layout->FindResourceInfo(LayoutResourceKind::Uniform)
+ || layout->FindResourceInfo(LayoutResourceKind::DescriptorTableSlot))
+ {
+ Emit("uniform ");
+ }
+ }
+ }
EmitVarDeclCommon(decl);
@@ -3288,6 +3395,9 @@ String emitEntryPoint(
// There may be global-scope modifiers that we should emit now
visitor.emitGLSLPreprocessorDirectives(translationUnitSyntax);
+ String prefix = sharedContext.sb.ProduceString();
+ sharedContext.sb.Clear();
+
switch(target)
{
case CodeGenTarget::GLSL:
@@ -3303,6 +3413,8 @@ String emitEntryPoint(
auto lowered = lowerEntryPoint(entryPoint, programLayout, target);
+ sharedContext.program = lowered.program;
+
visitor.EmitDeclsInContainer(lowered.program.Ptr());
#if 0
@@ -3324,7 +3436,19 @@ String emitEntryPoint(
String code = sharedContext.sb.ProduceString();
- return code;
+ StringBuilder finalResultBuilder;
+ finalResultBuilder << prefix;
+
+ if (sharedContext.needHackSamplerForTexelFetch)
+ {
+ finalResultBuilder << "layout(set = 0, binding = 0) uniform sampler SLANG_hack_samplerForTexelFetch;\n";
+ }
+
+ finalResultBuilder << code;
+
+ String finalResult = finalResultBuilder.ProduceString();
+
+ return finalResult;
}
} // namespace Slang
diff --git a/source/slang/lower.cpp b/source/slang/lower.cpp
index 0bb047791..165812fae 100644
--- a/source/slang/lower.cpp
+++ b/source/slang/lower.cpp
@@ -1,6 +1,7 @@
// lower.cpp
#include "lower.h"
+#include "type-layout.h"
#include "visitor.h"
namespace Slang
@@ -193,6 +194,8 @@ public:
struct SharedLoweringContext
{
+ CompileRequest* compileRequest;
+
ProgramLayout* programLayout;
// The target we are going to generate code for.
@@ -1371,6 +1374,23 @@ struct LoweringVisitor
return loweredDecl;
}
+ SourceLanguage getSourceLanguage(ProgramSyntaxNode* moduleDecl)
+ {
+ for (auto translationUnit : shared->compileRequest->translationUnits)
+ {
+ if (moduleDecl == translationUnit->SyntaxNode)
+ return translationUnit->sourceLanguage;
+ }
+
+ for (auto loadedModuleDecl : shared->compileRequest->loadedModulesList)
+ {
+ if (moduleDecl == loadedModuleDecl)
+ return SourceLanguage::Slang;
+ }
+
+ return SourceLanguage::Unknown;
+ }
+
RefPtr<VarDeclBase> visitVariable(
Variable* decl)
{
@@ -1525,38 +1545,93 @@ struct LoweringVisitor
type = arrayType;
}
- // TODO: if we are declaring an SOA-ized array,
- // this is where those array dimensions would need
- // to be tacked on.
+ // We need to create a reference to the global-scope declaration
+ // of the proper GLSL input/output variable. This might
+ // be a user-defined input/output, or a system-defined `gl_` one.
+ RefPtr<ExpressionSyntaxNode> globalVarExpr;
- RefPtr<Variable> globalVarDecl = new Variable();
- globalVarDecl->Name.Content = info.name;
- globalVarDecl->Type.type = type;
+ // Handle system-value inputs/outputs
+ assert(varLayout);
+ auto systemValueSemantic = varLayout->systemValueSemantic;
+ if (systemValueSemantic.Length() != 0)
+ {
+ auto ns = systemValueSemantic.ToLower();
- ensureDeclHasAValidName(globalVarDecl);
+ if (ns == "sv_target")
+ {
+ // Note: we do *not* need to generate some kind of `gl_`
+ // builtin for fragment-shader outputs: they are just
+ // ordinary `out` variables, with ordinary `location`s,
+ // as far as GLSL is concerned.
+ }
+ else if (ns == "sv_position")
+ {
+ RefPtr<VarExpressionSyntaxNode> globalVarRef = new VarExpressionSyntaxNode();
+ globalVarRef->name = "gl_Position";
+ globalVarExpr = globalVarRef;
+ }
+ else
+ {
+ assert(!"unhandled");
+ }
+ }
- addMember(shared->loweredProgram, globalVarDecl);
+ // If we didn't match some kind of builtin input/output,
+ // then declare a user input/output variable instead
+ if (!globalVarExpr)
+ {
+ RefPtr<Variable> globalVarDecl = new Variable();
+ globalVarDecl->Name.Content = info.name;
+ globalVarDecl->Type.type = type;
- // Add the layout information
- RefPtr<ComputedLayoutModifier> modifier = new ComputedLayoutModifier();
- modifier->layout = varLayout;
- addModifier(globalVarDecl, modifier);
+ ensureDeclHasAValidName(globalVarDecl);
- // Need to generate an assignment in the right direction.
+ addMember(shared->loweredProgram, globalVarDecl);
+
+ // Add the layout information
+ RefPtr<ComputedLayoutModifier> modifier = new ComputedLayoutModifier();
+ modifier->layout = varLayout;
+ addModifier(globalVarDecl, modifier);
+
+ // Add appropriate in/out modifier
+ switch (info.direction)
+ {
+ case VaryingParameterDirection::Input:
+ addModifier(globalVarDecl, new InModifier());
+ break;
+
+ case VaryingParameterDirection::Output:
+ addModifier(globalVarDecl, new OutModifier());
+ break;
+ }
+
+
+ RefPtr<VarExpressionSyntaxNode> globalVarRef = new VarExpressionSyntaxNode();
+ globalVarRef->Position = globalVarDecl->Position;
+ globalVarRef->declRef = makeDeclRef(globalVarDecl.Ptr());
+ globalVarRef->name = globalVarDecl->getName();
+
+ globalVarExpr = globalVarRef;
+ }
+
+ // TODO: if we are declaring an SOA-ized array,
+ // this is where those array dimensions would need
+ // to be tacked on.
//
- // TODO: for now I am just dealing with input:
+ // That is, this logic should be getting collected into a loop,
+ // and so we need to have a loop variable we can use to
+ // index into the two different expressions.
+
+ // Need to generate an assignment in the right direction.
switch (info.direction)
{
case VaryingParameterDirection::Input:
- addModifier(globalVarDecl, new InModifier());
- assign(varExpr, globalVarDecl);
+ assign(varExpr, globalVarExpr);
break;
case VaryingParameterDirection::Output:
- addModifier(globalVarDecl, new OutModifier());
-
- assign(globalVarDecl, varExpr);
+ assign(globalVarExpr, varExpr);
break;
}
}
@@ -1683,6 +1758,18 @@ struct LoweringVisitor
info.name = name;
info.direction = direction;
+ // Ensure that we don't get name collisions on `inout` variables
+ switch (direction)
+ {
+ case VaryingParameterDirection::Input:
+ info.name = "SLANG_in_" + name;
+ break;
+
+ case VaryingParameterDirection::Output:
+ info.name = "SLANG_out_" + name;
+ break;
+ }
+
lowerShaderParameterToGLSLGLobalsRec(
info,
localVarDecl->getType(),
@@ -1713,10 +1800,14 @@ struct LoweringVisitor
if (loweredEntryPointFunc->getName() == "main")
loweredEntryPointFunc->Name.Content = "main_";
+ RefPtr<BlockStmt> bodyStmt = new BlockStmt();
+ bodyStmt->scopeDecl = new ScopeDecl();
+
// We will want to generate declarations into the body of our new `main()`
LoweringVisitor subVisitor = *this;
subVisitor.isBuildingStmt = true;
subVisitor.stmtBeingBuilt = nullptr;
+ subVisitor.parentDecl = bodyStmt->scopeDecl;
// The parameters of the entry-point function will be translated to
// both a local variable (for passing to/from the entry point func),
@@ -1769,7 +1860,7 @@ struct LoweringVisitor
{
resultVarDecl = new Variable();
resultVarDecl->Position = loweredEntryPointFunc->Position;
- resultVarDecl->Name.Content = "_main_result";
+ resultVarDecl->Name.Content = "main_result";
resultVarDecl->Type = TypeExp(loweredEntryPointFunc->ReturnType);
ensureDeclHasAValidName(resultVarDecl);
@@ -1838,7 +1929,9 @@ struct LoweringVisitor
VaryingParameterDirection::Output);
}
- mainDecl->Body = subVisitor.stmtBeingBuilt;
+ bodyStmt->body = subVisitor.stmtBeingBuilt;
+
+ mainDecl->Body = bodyStmt;
// Once we are done building the body, we append our new declaration to the program.
@@ -2003,6 +2096,7 @@ LoweredEntryPoint lowerEntryPoint(
CodeGenTarget target)
{
SharedLoweringContext sharedContext;
+ sharedContext.compileRequest = entryPoint->compileRequest;
sharedContext.programLayout = programLayout;
sharedContext.target = target;
diff --git a/source/slang/modifier-defs.h b/source/slang/modifier-defs.h
index e50288600..083da79f0 100644
--- a/source/slang/modifier-defs.h
+++ b/source/slang/modifier-defs.h
@@ -6,7 +6,6 @@
#define SIMPLE_MODIFIER(NAME) \
SIMPLE_SYNTAX_CLASS(NAME##Modifier, Modifier)
-SIMPLE_MODIFIER(Uniform);
SIMPLE_MODIFIER(In);
SIMPLE_MODIFIER(Out);
SIMPLE_MODIFIER(Const);
diff --git a/source/slang/options.cpp b/source/slang/options.cpp
index db949e78d..bb292a4dc 100644
--- a/source/slang/options.cpp
+++ b/source/slang/options.cpp
@@ -5,6 +5,7 @@
#include "../../slang.h"
+#include "compiler.h"
#include "profile.h"
#include <assert.h>
@@ -229,6 +230,7 @@ struct OptionsParser
CASE(spirv, SPIRV);
CASE(spirv-assembly, SPIRV_ASM);
+ CASE(none, TARGET_NONE);
#undef CASE
diff --git a/source/slang/parameter-binding.cpp b/source/slang/parameter-binding.cpp
index 5811fd9fa..0683c7f8c 100644
--- a/source/slang/parameter-binding.cpp
+++ b/source/slang/parameter-binding.cpp
@@ -137,9 +137,6 @@ struct SharedParameterBindingContext
// The program layout we are trying to construct
RefPtr<ProgramLayout> programLayout;
- // The source language we are trying to use
- SourceLanguage sourceLanguage;
-
// Information on what ranges of "registers" have already
// been claimed, for each resource type
UsedRanges usedResourceRanges[kLayoutResourceKindCount];
@@ -160,6 +157,9 @@ struct ParameterBindingContext
// What stage (if any) are we compiling for?
Stage stage;
+
+ // The source language we are trying to use
+ SourceLanguage sourceLanguage;
};
struct LayoutSemanticInfo
@@ -398,7 +398,7 @@ getTypeLayoutForGlobalShaderParameter(
ParameterBindingContext* context,
VarDeclBase* varDecl)
{
- switch( context->shared->sourceLanguage )
+ switch( context->sourceLanguage )
{
case SourceLanguage::Slang:
case SourceLanguage::HLSL:
@@ -788,6 +788,7 @@ static RefPtr<TypeLayout> processSimpleEntryPointParameter(
ParameterBindingContext* context,
RefPtr<ExpressionType> type,
EntryPointParameterState const& inState,
+ RefPtr<VarLayout> varLayout,
int semanticSlotCount = 1)
{
EntryPointParameterState state = inState;
@@ -817,6 +818,13 @@ static RefPtr<TypeLayout> processSimpleEntryPointParameter(
}
}
+ // Remember the system-value semantic so that we can query it later
+ if (varLayout)
+ {
+ varLayout->systemValueSemantic = semanticName;
+ varLayout->systemValueSemanticIndex = semanticIndex;
+ }
+
// TODO: add some kind of usage information for system input/output
}
else
@@ -847,13 +855,15 @@ static RefPtr<TypeLayout> processSimpleEntryPointParameter(
static RefPtr<TypeLayout> processEntryPointParameter(
ParameterBindingContext* context,
RefPtr<ExpressionType> type,
- EntryPointParameterState const& state);
+ EntryPointParameterState const& state,
+ RefPtr<VarLayout> varLayout);
static RefPtr<TypeLayout> processEntryPointParameterWithPossibleSemantic(
ParameterBindingContext* context,
Decl* declForSemantic,
RefPtr<ExpressionType> type,
- EntryPointParameterState const& state)
+ EntryPointParameterState const& state,
+ RefPtr<VarLayout> varLayout)
{
// If there is no explicit semantic already in effect, *and* we find an explicit
// semantic on the associated declaration, then we'll use it.
@@ -868,7 +878,7 @@ static RefPtr<TypeLayout> processEntryPointParameterWithPossibleSemantic(
subState.optSemanticName = &semanticInfo.name;
subState.ioSemanticIndex = &semanticIndex;
- processEntryPointParameter(context, type, subState);
+ processEntryPointParameter(context, type, subState, varLayout);
}
}
@@ -876,29 +886,30 @@ static RefPtr<TypeLayout> processEntryPointParameterWithPossibleSemantic(
// *or* we couldn't find an explicit semantic to apply on the given
// declaration, so we will just recursive with whatever we have at
// the moment.
- return processEntryPointParameter(context, type, state);
+ return processEntryPointParameter(context, type, state, varLayout);
}
static RefPtr<TypeLayout> processEntryPointParameter(
ParameterBindingContext* context,
RefPtr<ExpressionType> type,
- EntryPointParameterState const& state)
+ EntryPointParameterState const& state,
+ RefPtr<VarLayout> varLayout)
{
// Scalar and vector types are treated as outputs directly
if(auto basicType = type->As<BasicExpressionType>())
{
- return processSimpleEntryPointParameter(context, basicType, state);
+ return processSimpleEntryPointParameter(context, basicType, state, varLayout);
}
else if(auto vectorType = type->As<VectorExpressionType>())
{
- return processSimpleEntryPointParameter(context, vectorType, state);
+ return processSimpleEntryPointParameter(context, vectorType, state, varLayout);
}
// A matrix is processed as if it was an array of rows
else if( auto matrixType = type->As<MatrixExpressionType>() )
{
auto rowCount = GetIntVal(matrixType->getRowCount());
- return processSimpleEntryPointParameter(context, matrixType, state, (int) rowCount);
+ return processSimpleEntryPointParameter(context, matrixType, state, varLayout, (int) rowCount);
}
else if( auto arrayType = type->As<ArrayExpressionType>() )
{
@@ -908,13 +919,13 @@ static RefPtr<TypeLayout> processEntryPointParameter(
auto elementCount = (UInt) GetIntVal(arrayType->ArrayLength);
// We use the first element to derive the layout for the element type
- auto elementTypeLayout = processEntryPointParameter(context, arrayType->BaseType, state);
+ auto elementTypeLayout = processEntryPointParameter(context, arrayType->BaseType, state, varLayout);
// We still walk over subsequent elements to make sure they consume resources
// as needed
for( UInt ii = 1; ii < elementCount; ++ii )
{
- processEntryPointParameter(context, arrayType->BaseType, state);
+ processEntryPointParameter(context, arrayType->BaseType, state, nullptr);
}
RefPtr<ArrayTypeLayout> arrayTypeLayout = new ArrayTypeLayout();
@@ -946,14 +957,16 @@ static RefPtr<TypeLayout> processEntryPointParameter(
// Need to recursively walk the fields of the structure now...
for( auto field : GetFields(structDeclRef) )
{
+ RefPtr<VarLayout> fieldVarLayout = new VarLayout();
+ fieldVarLayout->varDecl = field;
+
auto fieldTypeLayout = processEntryPointParameterWithPossibleSemantic(
context,
field.getDecl(),
GetType(field),
- state);
+ state,
+ fieldVarLayout);
- RefPtr<VarLayout> fieldVarLayout = new VarLayout();
- fieldVarLayout->varDecl = field;
fieldVarLayout->typeLayout = fieldTypeLayout;
for (auto rr : fieldTypeLayout->resourceInfos)
@@ -1045,7 +1058,7 @@ static void collectEntryPointParameters(
// We have an entry-point parameter, and need to figure out what to do with it.
// TODO: need to handle `uniform`-qualified parameters here
- if (paramDecl->HasModifier<UniformModifier>())
+ if (paramDecl->HasModifier<HLSLUniformModifier>())
continue;
state.directionMask = 0;
@@ -1062,14 +1075,16 @@ static void collectEntryPointParameters(
state.directionMask |= kEntryPointParameterDirection_Output;
}
+ RefPtr<VarLayout> paramVarLayout = new VarLayout();
+ paramVarLayout->varDecl = makeDeclRef(paramDecl.Ptr());
+
auto paramTypeLayout = processEntryPointParameterWithPossibleSemantic(
context,
paramDecl.Ptr(),
paramDecl->Type.type,
- state);
+ state,
+ paramVarLayout);
- RefPtr<VarLayout> paramVarLayout = new VarLayout();
- paramVarLayout->varDecl = makeDeclRef(paramDecl.Ptr());
paramVarLayout->typeLayout = paramTypeLayout;
for (auto rr : paramTypeLayout->resourceInfos)
@@ -1089,13 +1104,15 @@ static void collectEntryPointParameters(
{
state.directionMask = kEntryPointParameterDirection_Output;
+ RefPtr<VarLayout> resultLayout = new VarLayout();
+
auto resultTypeLayout = processEntryPointParameterWithPossibleSemantic(
context,
entryPointFuncDecl,
resultType,
- state);
+ state,
+ resultLayout);
- RefPtr<VarLayout> resultLayout = new VarLayout();
resultLayout->typeLayout = resultTypeLayout;
for (auto rr : resultTypeLayout->resourceInfos)
@@ -1167,6 +1184,7 @@ static void collectParameters(
for( auto& translationUnit : request->translationUnits )
{
context->stage = inferStageForTranslationUnit(translationUnit.Ptr());
+ context->sourceLanguage = translationUnit->sourceLanguage;
// First look at global-scope parameters
collectGlobalScopeParameters(context, translationUnit->SyntaxNode.Ptr());
@@ -1189,31 +1207,13 @@ static void collectParameters(
void generateParameterBindings(
CompileRequest* request)
{
- // TODO: infer a language or set of language rules to use based on the
- // source files and entry points given
- auto language = SourceLanguage::Unknown;
- for( auto& translationUnit : request->translationUnits )
- {
- auto translationUnitLanguage = translationUnit->sourceLanguage;
- if( language == SourceLanguage::Unknown )
- {
- language = translationUnitLanguage;
- }
- else if( language == translationUnitLanguage )
- {
- // same language: nothing to do...
- }
- else
- {
- // mismatch!
- // TODO(tfoley): emit a diagnostic
- }
- }
+ // Try to find rules based on the selected code-generation target
+ auto rules = GetLayoutRulesFamilyImpl(request->Target);
- // TODO(tfoley): We should really be picking layout rules
- // based on the *target* language, and not the source...
- auto rules = GetLayoutRulesFamilyImpl(language);
- assert(rules);
+ // If there was no target, or there are no rules for the target,
+ // then bail out here.
+ if (!rules)
+ return;
RefPtr<ProgramLayout> programLayout = new ProgramLayout;
@@ -1222,7 +1222,6 @@ void generateParameterBindings(
SharedParameterBindingContext sharedContext;
sharedContext.defaultLayoutRules = rules;
sharedContext.programLayout = programLayout;
- sharedContext.sourceLanguage = language;
// Create a sub-context to collect parameters that get
// declared into the global scope
diff --git a/source/slang/reflection.cpp b/source/slang/reflection.cpp
index d62da70c1..eb27df398 100644
--- a/source/slang/reflection.cpp
+++ b/source/slang/reflection.cpp
@@ -112,7 +112,7 @@ SLANG_API SlangTypeKind spReflectionType_GetKind(SlangReflectionType* inType)
{
return SLANG_TYPE_KIND_SAMPLER_STATE;
}
- else if (auto textureType = type->As<TextureType>())
+ else if (auto textureType = type->As<TextureTypeBase>())
{
return SLANG_TYPE_KIND_RESOURCE;
}
@@ -326,7 +326,7 @@ SLANG_API SlangResourceShape spReflectionType_GetResourceShape(SlangReflectionTy
type = arrayType->BaseType.Ptr();
}
- if(auto textureType = type->As<TextureType>())
+ if(auto textureType = type->As<TextureTypeBase>())
{
return textureType->getShape();
}
@@ -363,7 +363,7 @@ SLANG_API SlangResourceAccess spReflectionType_GetResourceAccess(SlangReflection
type = arrayType->BaseType.Ptr();
}
- if(auto textureType = type->As<TextureType>())
+ if(auto textureType = type->As<TextureTypeBase>())
{
return textureType->getAccess();
}
@@ -385,6 +385,9 @@ SLANG_API SlangResourceAccess spReflectionType_GetResourceAccess(SlangReflection
CASE(HLSLByteAddressBufferType, SLANG_BYTE_ADDRESS_BUFFER, SLANG_RESOURCE_ACCESS_READ);
CASE(HLSLRWByteAddressBufferType, SLANG_BYTE_ADDRESS_BUFFER, SLANG_RESOURCE_ACCESS_READ_WRITE);
CASE(UntypedBufferResourceType, SLANG_BYTE_ADDRESS_BUFFER, SLANG_RESOURCE_ACCESS_READ);
+
+ // This isn't entirely accurate, but I can live with it for now
+ CASE(GLSLShaderStorageBufferType, SLANG_STRUCTURED_BUFFER, SLANG_RESOURCE_ACCESS_READ_WRITE);
#undef CASE
return SLANG_RESOURCE_ACCESS_NONE;
@@ -400,7 +403,7 @@ SLANG_API SlangReflectionType* spReflectionType_GetResourceResultType(SlangRefle
type = arrayType->BaseType.Ptr();
}
- if (auto textureType = type->As<TextureType>())
+ if (auto textureType = type->As<TextureTypeBase>())
{
return convert(textureType->elementType.Ptr());
}
diff --git a/source/slang/slang-stdlib.cpp b/source/slang/slang-stdlib.cpp
index e2d5829b4..23d66201a 100644
--- a/source/slang/slang-stdlib.cpp
+++ b/source/slang/slang-stdlib.cpp
@@ -1431,6 +1431,22 @@ namespace Slang
{
int loadCoordCount = kBaseTextureTypes[tt].coordCount + isArray + (isMultisample?0:1);
+ // When translating to GLSL, we need to break apart the `location` argument.
+ //
+ // TODO: this should realy be handled by having this member actually get lowered!
+ int glslLoadCoordCount = kBaseTextureTypes[tt].coordCount + isArray;
+ static const char* kGLSLLoadCoordsSwizzle[] = { "", "", "x", "xy", "xyz", "xyzw" };
+ static const char* kGLSLLoadLODSwizzle[] = { "", "", "y", "z", "w", "error" };
+
+ if (isMultisample)
+ {
+ sb << "__intrinsic(glsl, \"texelFetch($P, $0, $1)\")\n";
+ }
+ else
+ {
+ sb << "__intrinsic(glsl, \"texelFetch($P, ($0)." << kGLSLLoadCoordsSwizzle[loadCoordCount] << ", ($0)." << kGLSLLoadLODSwizzle[loadCoordCount] << ")\")\n";
+ }
+ sb << "__intrinsic\n";
sb << "T Load(";
sb << "int" << loadCoordCount << " location";
if(isMultisample)
@@ -1439,6 +1455,15 @@ namespace Slang
}
sb << ");\n";
+ if (isMultisample)
+ {
+ sb << "__intrinsic(glsl, \"texelFetchOffset($P, $0, $1, $2)\")\n";
+ }
+ else
+ {
+ sb << "__intrinsic(glsl, \"texelFetch($P, ($0)." << kGLSLLoadCoordsSwizzle[loadCoordCount] << ", ($0)." << kGLSLLoadLODSwizzle[loadCoordCount] << ", $1)\")\n";
+ }
+ sb << "__intrinsic\n";
sb << "T Load(";
sb << "int" << loadCoordCount << " location";
if(isMultisample)
@@ -1470,11 +1495,15 @@ namespace Slang
{
// `Sample()`
+ sb << "__intrinsic(glsl, \"texture($p, $1)\")\n";
+ sb << "__intrinsic\n";
sb << "T Sample(SamplerState s, ";
sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location);\n";
if( baseShape != TextureType::ShapeCube )
{
+ sb << "__intrinsic(glsl, \"textureOffset($p, $1)\")\n";
+ sb << "__intrinsic\n";
sb << "T Sample(SamplerState s, ";
sb << "float" << kBaseTextureTypes[tt].coordCount + isArray << " location, ";
sb << "int" << kBaseTextureTypes[tt].coordCount << " offset);\n";
diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp
index e5bfcb923..af68060cd 100644
--- a/source/slang/slang.cpp
+++ b/source/slang/slang.cpp
@@ -179,6 +179,30 @@ void CompileRequest::checkAllTranslationUnits()
checkTranslationUnit(translationUnit.Ptr());
}
}
+// Try to infer a single common source language for a request
+static SourceLanguage inferSourceLanguage(CompileRequest* request)
+{
+ SourceLanguage language = SourceLanguage::Unknown;
+ for (auto& translationUnit : request->translationUnits)
+ {
+ // Allow any other language to overide Slang as a choice
+ if (language == SourceLanguage::Unknown
+ || language == SourceLanguage::Slang)
+ {
+ language = translationUnit->sourceLanguage;
+ }
+ else if (language == translationUnit->sourceLanguage)
+ {
+ // same language as we currently have, so keep going
+ }
+ else
+ {
+ // we found a mismatch, so inference fails
+ return SourceLanguage::Unknown;
+ }
+ }
+ return language;
+}
int CompileRequest::executeActionsInner()
{
@@ -197,6 +221,26 @@ int CompileRequest::executeActionsInner()
}
}
+ // If no code-generation target was specified, then try to infer one from the source language,
+ // just to make sure we can do something reasonable when `reflection-json` is specified
+ if (Target == CodeGenTarget::Unknown)
+ {
+ auto language = inferSourceLanguage(this);
+ switch (language)
+ {
+ case SourceLanguage::HLSL:
+ Target = CodeGenTarget::DXBytecodeAssembly;
+ break;
+
+ case SourceLanguage::GLSL:
+ Target = CodeGenTarget::SPIRVAssembly;
+ break;
+
+ default:
+ break;
+ }
+ }
+
#if 0
// If we are being asked to do pass-through, then we need to do that here...
if (passThrough != PassThroughMode::None)
@@ -628,7 +672,17 @@ SLANG_API void spSetCodeGenTarget(
SlangCompileRequest* request,
int target)
{
- REQ(request)->Target = (Slang::CodeGenTarget)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;
+ }
}
SLANG_API void spSetPassThrough(
diff --git a/source/slang/slang.vcxproj b/source/slang/slang.vcxproj
index 441bc5e45..17fdea627 100644
--- a/source/slang/slang.vcxproj
+++ b/source/slang/slang.vcxproj
@@ -165,7 +165,6 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\slang.h" />
- <ClInclude Include="compiled-program.h" />
<ClInclude Include="compiler.h" />
<ClInclude Include="decl-defs.h" />
<ClInclude Include="diagnostic-defs.h" />
diff --git a/source/slang/slang.vcxproj.filters b/source/slang/slang.vcxproj.filters
index 21b533a10..a276ae95b 100644
--- a/source/slang/slang.vcxproj.filters
+++ b/source/slang/slang.vcxproj.filters
@@ -4,7 +4,6 @@
<Natvis Include="slang.natvis" />
</ItemGroup>
<ItemGroup>
- <ClInclude Include="compiled-program.h" />
<ClInclude Include="compiler.h" />
<ClInclude Include="diagnostic-defs.h" />
<ClInclude Include="diagnostics.h" />
diff --git a/source/slang/syntax-visitors.h b/source/slang/syntax-visitors.h
index 85a20a7cf..4ccc7fa0b 100644
--- a/source/slang/syntax-visitors.h
+++ b/source/slang/syntax-visitors.h
@@ -3,7 +3,6 @@
#include "diagnostics.h"
#include "syntax.h"
-#include "compiled-program.h"
namespace Slang
{
diff --git a/source/slang/type-layout.cpp b/source/slang/type-layout.cpp
index 10c7327ce..31c8ed607 100644
--- a/source/slang/type-layout.cpp
+++ b/source/slang/type-layout.cpp
@@ -543,15 +543,18 @@ LayoutRulesFamilyImpl* GetLayoutRulesFamilyImpl(LayoutRulesFamily rule)
}
}
-LayoutRulesFamilyImpl* GetLayoutRulesFamilyImpl(SourceLanguage language)
+LayoutRulesFamilyImpl* GetLayoutRulesFamilyImpl(CodeGenTarget target)
{
- switch (language)
+ switch (target)
{
- case SourceLanguage::Slang:
- case SourceLanguage::HLSL:
+ case CodeGenTarget::HLSL:
+ case CodeGenTarget::DXBytecode:
+ case CodeGenTarget::DXBytecodeAssembly:
return &kHLSLLayoutRulesFamilyImpl;
- case SourceLanguage::GLSL:
+ case CodeGenTarget::GLSL:
+ case CodeGenTarget::SPIRV:
+ case CodeGenTarget::SPIRVAssembly:
return &kGLSLLayoutRulesFamilyImpl;
default:
diff --git a/source/slang/type-layout.h b/source/slang/type-layout.h
index ce1f8864d..262a8c3b1 100644
--- a/source/slang/type-layout.h
+++ b/source/slang/type-layout.h
@@ -2,6 +2,7 @@
#define SLANG_TYPE_LAYOUT_H
#include "../core/basic.h"
+#include "compiler.h"
#include "profile.h"
#include "syntax.h"
@@ -236,6 +237,10 @@ public:
// Additional flags
VarLayoutFlags flags = 0;
+ // System-value semantic (and index) if this is a system value
+ String systemValueSemantic;
+ int systemValueSemanticIndex;
+
// The start register(s) for any resources
struct ResourceInfo
{
@@ -513,7 +518,7 @@ struct LayoutRulesFamilyImpl
LayoutRulesImpl* GetLayoutRulesImpl(LayoutRule rule);
LayoutRulesFamilyImpl* GetLayoutRulesFamilyImpl(LayoutRulesFamily rule);
-LayoutRulesFamilyImpl* GetLayoutRulesFamilyImpl(SourceLanguage language);
+LayoutRulesFamilyImpl* GetLayoutRulesFamilyImpl(CodeGenTarget target);
SimpleLayoutInfo GetLayout(ExpressionType* type, LayoutRulesImpl* rules);
diff --git a/tests/preprocessor/import.hlsl b/tests/preprocessor/import.hlsl
index 486023678..f0618a667 100644
--- a/tests/preprocessor/import.hlsl
+++ b/tests/preprocessor/import.hlsl
@@ -1,4 +1,4 @@
-//TEST:SIMPLE:-profile vs_5_0
+//TEST:SIMPLE:-target none -profile vs_5_0
// Confirm that `#import` interacts with preprocessor as expected
diff --git a/tests/reflection/cross-compile.slang b/tests/reflection/cross-compile.slang
new file mode 100644
index 000000000..12376c82a
--- /dev/null
+++ b/tests/reflection/cross-compile.slang
@@ -0,0 +1,23 @@
+//TEST(smoke):SIMPLE:-profile glsl_fragment -target glsl -target reflection-json
+
+// Confirm that when targetting GLSL via cross compilation,
+// we use the Vulkan layout rules instead of HLSL ones
+//
+// Specifically, we expect all of our top-level parameters
+// to get distinct registers in the same descriptor set,
+// rather than all getting register `0` because they
+// occupy different names register spaces (as they would in D3D)
+
+Texture2D t;
+
+SamplerState s;
+
+cbuffer C
+{
+ float3 c;
+}
+
+float4 main() : SV_Target
+{
+ return 0.0;
+} \ No newline at end of file
diff --git a/tests/reflection/cross-compile.slang.expected b/tests/reflection/cross-compile.slang.expected
new file mode 100644
index 000000000..3bb730f66
--- /dev/null
+++ b/tests/reflection/cross-compile.slang.expected
@@ -0,0 +1,48 @@
+result code = 0
+standard error = {
+}
+standard output = {
+{
+ "parameters": [
+ {
+ "name": "t",
+ "binding": {"kind": "descriptorTableSlot", "index": 0},
+ "type": {
+ "kind": "resource",
+ "baseShape": "texture2D"
+ }
+ },
+ {
+ "name": "s",
+ "binding": {"kind": "descriptorTableSlot", "index": 1},
+ "type": {
+ "kind": "samplerState"
+ }
+ },
+ {
+ "name": "C",
+ "binding": {"kind": "descriptorTableSlot", "index": 2},
+ "type": {
+ "kind": "constantBuffer",
+ "elementType": {
+ "kind": "struct",
+ "fields": [
+ {
+ "name": "c",
+ "type": {
+ "kind": "vector",
+ "elementCount": 3,
+ "elementType": {
+ "kind": "scalar",
+ "scalarType": "float32"
+ }
+ },
+ "binding": {"kind": "uniform", "offset": 0, "size": 12}
+ }
+ ]
+ }
+ }
+ }
+ ]
+}
+}
diff --git a/tests/render/cross-compile0.hlsl b/tests/render/cross-compile0.hlsl
index d300e2bd5..d40f3460f 100644
--- a/tests/render/cross-compile0.hlsl
+++ b/tests/render/cross-compile0.hlsl
@@ -97,8 +97,8 @@ uniform Uniforms
#define ASSEMBLED_VERTEX(QUAL) \
/* */
-#define V2F(QUAL) \
- QUAL vec3 coarse_color; \
+#define V2F(QUAL) \
+ layout(location = 0) QUAL vec3 coarse_color; \
/* */
// Vertex Shader
diff --git a/tests/render/imported-parameters.hlsl b/tests/render/imported-parameters.hlsl
index 605214fc9..99216728e 100644
--- a/tests/render/imported-parameters.hlsl
+++ b/tests/render/imported-parameters.hlsl
@@ -84,8 +84,8 @@ FragmentStageOutput fragmentMain(FragmentStageInput input)
#define ASSEMBLED_VERTEX(QUAL) \
/* */
-#define V2F(QUAL) \
- QUAL vec3 coarse_color; \
+#define V2F(QUAL) \
+ layout(location = 0) QUAL vec3 coarse_color; \
/* */
// Vertex Shader
diff --git a/tests/render/pound-import.hlsl b/tests/render/pound-import.hlsl
index a9b625fb6..07b195966 100644
--- a/tests/render/pound-import.hlsl
+++ b/tests/render/pound-import.hlsl
@@ -97,8 +97,8 @@ uniform Uniforms
#define ASSEMBLED_VERTEX(QUAL) \
/* */
-#define V2F(QUAL) \
- QUAL vec3 coarse_color; \
+#define V2F(QUAL) \
+ layout(location = 0) QUAL vec3 coarse_color; \
/* */
// Vertex Shader