From 76dca35b3fabbe77d4c01640423bdf5ce93d27d4 Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Wed, 19 Jul 2017 08:32:44 -0700 Subject: Translate NV single-pass stereo extension from Slang to GLSL - The easy part here is treating `NV_` prefixed semantics as another case of "system-value" semantics - Mapping the new semantics (`NV_X_RIGHT` and `NV_VIEWPORT_MASK`) to their GLSL equivalents is harder - Instead of a single "right-eye vertex" output, GLSL defines an array of per-view positions - Instead of a vector of masks, GLSL defines an array of per-view masks - Another point here is that a lot of semantics that appear as `uint` in HLSL are `int` in GLSL, which can lead to conversion issues. - The approach here is to have the lowering pass introduce a notion of assignment with "fixups," which will try to cast things as needed - When assigning to a simple value with the "wrong" type, introduce a cast - When assigning to an array from a vector, break out multiple assignments of individual vector/array elements - In order to facilitate the above, I needed to add actual types to the magic expressions I introduce to represent GLSL builtin variables. These were taken by scanning the online documentation for GL, so they might not be perfect. - Major issues with the approach in this change: - No attempt is being made here to check that the original declaration used a type appropriate to the semantic. The assumption is that this logic only ever triggers for Slang entry points, or GLSL entry points using a Slang `struct` type for input/output (and for right now Slang code is only ever written by "understanding" developers) - In the case of a Slang entry point, we always copy varying parameters in/out around the call to `main_`, so this approach should handle calls to functions with `out` or `in out` parameters okay, but it is *not* robust to cases where we don't want to copy in all the entry point parameters first thing (e.g., a GS), so that will have to change - In the GLSL case (or if we revise the approach to Slang entry points), there is going to be a problem if these converted varying parameters are ever passed as arguments to `out` or `in out` parameters. In these cases we need to do more sleight-of-hand to reify a temporary variable and do the necessary copy-in/copy-out. Being able to do that logic relies on having correct information about callees, which requires having robust semantic analysis of the function body. There is only so much we can do... - A better long-term approach would not rely on an ad-hoc "fixup" conversion during assignment, but would instead implement the GLSL builtin variables as, effectively, global "property" declarations that have both `get` and `set` accessors, and then tunnel a reference to such a property down through lowering, where it can lower to uses of the "getter" or "setter" as appropriate in context (and the result type of the getter/setter can be what we'd want/expect). --- source/slang-glslang/slang-glslang.vcxproj | 8 +- source/slang/emit.cpp | 44 ++- source/slang/emit.h | 5 + source/slang/lower.cpp | 508 ++++++++++++++++++++++++++--- source/slang/lower.h | 9 +- source/slang/parameter-binding.cpp | 3 +- 6 files changed, 500 insertions(+), 77 deletions(-) (limited to 'source') diff --git a/source/slang-glslang/slang-glslang.vcxproj b/source/slang-glslang/slang-glslang.vcxproj index 7f6761c4a..be617f363 100644 --- a/source/slang-glslang/slang-glslang.vcxproj +++ b/source/slang-glslang/slang-glslang.vcxproj @@ -96,7 +96,7 @@ Level3 Disabled - WIN32;_DEBUG;_WINDOWS;_USRDLL;GLSLANG_EXPORTS;%(PreprocessorDefinitions) + NV_EXTENSIONS;AMD_EXTENSIONS;WIN32;_DEBUG;_WINDOWS;_USRDLL;GLSLANG_EXPORTS;%(PreprocessorDefinitions) Windows @@ -109,7 +109,7 @@ Level3 Disabled - _DEBUG;_WINDOWS;_USRDLL;GLSLANG_EXPORTS;%(PreprocessorDefinitions) + NV_EXTENSIONS;AMD_EXTENSIONS;_DEBUG;_WINDOWS;_USRDLL;GLSLANG_EXPORTS;%(PreprocessorDefinitions) Windows @@ -124,7 +124,7 @@ MaxSpeed true true - WIN32;NDEBUG;_WINDOWS;_USRDLL;GLSLANG_EXPORTS;%(PreprocessorDefinitions) + NV_EXTENSIONS;AMD_EXTENSIONS;WIN32;NDEBUG;_WINDOWS;_USRDLL;GLSLANG_EXPORTS;%(PreprocessorDefinitions) Windows @@ -141,7 +141,7 @@ MaxSpeed true true - NDEBUG;_WINDOWS;_USRDLL;GLSLANG_EXPORTS;%(PreprocessorDefinitions) + NV_EXTENSIONS;AMD_EXTENSIONS;NDEBUG;_WINDOWS;_USRDLL;GLSLANG_EXPORTS;%(PreprocessorDefinitions) Windows diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp index 4754578b3..ee90510a9 100644 --- a/source/slang/emit.cpp +++ b/source/slang/emit.cpp @@ -15,6 +15,31 @@ namespace Slang { +struct ExtensionUsageTracker +{ + // Record the GLSL extnsions we have already emitted a `#extension` for + HashSet glslExtensionsRequired; + StringBuilder glslExtensionRequireLines; +}; + +void requireGLSLExtension( + ExtensionUsageTracker* tracker, + String const& name) +{ + if (tracker->glslExtensionsRequired.Contains(name)) + return; + + StringBuilder& sb = tracker->glslExtensionRequireLines; + + sb.append("#extension "); + sb.append(name); + sb.append(" : require\n"); + + tracker->glslExtensionsRequired.Add(name); +} + + + // Shared state for an entire emit session struct SharedEmitContext { @@ -61,9 +86,7 @@ struct SharedEmitContext bool needHackSamplerForTexelFetch = false; - // Record the GLSL extnsions we have already emitted a `#extension` for - HashSet glslExtensionsRequired; - StringBuilder glslExtensionRequireLines; + ExtensionUsageTracker extensionUsageTracker; }; struct EmitContext @@ -1668,16 +1691,7 @@ struct EmitVisitor void requireGLSLExtension(String const& name) { - if (context->shared->glslExtensionsRequired.Contains(name)) - return; - - StringBuilder& sb = context->shared->glslExtensionRequireLines; - - sb.append("#extension "); - sb.append(name); - sb.append(" : require\n"); - - context->shared->glslExtensionsRequired.Add(name); + Slang::requireGLSLExtension(&context->shared->extensionUsageTracker, name); } void requireGLSLVersion(ProfileVersion version) @@ -3774,7 +3788,7 @@ String emitEntryPoint( // because the lowering process might change how we emit some // boilerplate at the start of the ouput for GLSL (e.g., what // version we require). - auto lowered = lowerEntryPoint(entryPoint, programLayout, target); + auto lowered = lowerEntryPoint(entryPoint, programLayout, target, &sharedContext.extensionUsageTracker); sharedContext.program = lowered.program; // Note that we emit the main body code of the program *before* @@ -3797,7 +3811,7 @@ String emitEntryPoint( StringBuilder finalResultBuilder; finalResultBuilder << prefix; - finalResultBuilder << sharedContext.glslExtensionRequireLines.ProduceString(); + finalResultBuilder << sharedContext.extensionUsageTracker.glslExtensionRequireLines.ProduceString(); if (sharedContext.needHackSamplerForTexelFetch) { diff --git a/source/slang/emit.h b/source/slang/emit.h index da1ac9f08..5d546bdf4 100644 --- a/source/slang/emit.h +++ b/source/slang/emit.h @@ -12,6 +12,11 @@ namespace Slang class ProgramLayout; class TranslationUnitRequest; + struct ExtensionUsageTracker; + void requireGLSLExtension( + ExtensionUsageTracker* tracker, + String const& name); + // Emit code for a single entry point, based on // the input translation unit. String emitEntryPoint( diff --git a/source/slang/lower.cpp b/source/slang/lower.cpp index 52b865ba3..54afc283c 100644 --- a/source/slang/lower.cpp +++ b/source/slang/lower.cpp @@ -1,6 +1,7 @@ // lower.cpp #include "lower.h" +#include "emit.h" #include "type-layout.h" #include "visitor.h" @@ -253,6 +254,8 @@ struct SharedLoweringContext CompileRequest* compileRequest; EntryPointRequest* entryPointRequest; + ExtensionUsageTracker* extensionUsageTracker; + ProgramLayout* programLayout; EntryPointLayout* entryPointLayout; @@ -278,7 +281,8 @@ struct SharedLoweringContext // Counter used for generating unique temporary names int nameCounter = 0; - bool isRewrite; + bool isRewrite = false; + bool requiresCopyGLPositionToPositionPerView = false; }; static void attachLayout( @@ -786,9 +790,242 @@ struct LoweringVisitor return expr; } - RefPtr createAssignExpr( + // When constructing assignment syntax, we can either + // just leave things alone, or create code that will + // try to coerce types to "fix up" differences in + // the apparent type of things. + enum class AssignMode + { + Default, + WithFixups, + }; + + RefPtr createSimpleAssignExpr( + RefPtr leftExpr, + RefPtr rightExpr) + { + RefPtr loweredExpr = new AssignExpr(); + loweredExpr->Type = leftExpr->Type; + loweredExpr->left = leftExpr; + loweredExpr->right = rightExpr; + return loweredExpr; + } + + RefPtr convertExprForAssignmentWithFixups( + RefPtr leftType, + RefPtr rightExpr) + { + auto rightType = rightExpr->Type.type; + if (auto leftArrayType = leftType->As()) + { + // LHS type was an array + + if (auto rightVecType = rightType->As()) + { + // RHS type was a vector + if (auto leftElemVecType = leftArrayType->BaseType->As()) + { + // LHS element type was also a vector, so this is a "scalar splat + // to array" case. + } + else + { + // LHS is an array of non-vectors, while RHS is a vector, + // so in this case we want to splat out the vector elements + // to create an array and use that. + rightExpr = maybeMoveTemp(rightExpr); + + RefPtr ctorExpr = new AggTypeCtorExpr(); + ctorExpr->Position = rightExpr->Position; + ctorExpr->Type.type = leftType; + ctorExpr->base.type = leftType; + + int elementCount = (int) GetIntVal(rightVecType->elementCount); + for (int ee = 0; ee < elementCount; ++ee) + { + RefPtr swizzleExpr = new SwizzleExpr(); + swizzleExpr->Position = rightExpr->Position; + swizzleExpr->Type.type = rightVecType->elementType; + swizzleExpr->base = rightExpr; + swizzleExpr->elementCount = 1; + swizzleExpr->elementIndices[0] = ee; + + auto convertedArgExpr = convertExprForAssignmentWithFixups( + leftArrayType->BaseType, + swizzleExpr); + + ctorExpr->Arguments.Add(convertedArgExpr); + } + + return ctorExpr; + } + } + } + + // Default case: if the types didn't match, try to insert + // an explicit cast to deal with the issue. + return createCastExpr(leftType, rightExpr); + + } + + RefPtr createConstIntExpr(IntegerLiteralValue value) + { + RefPtr expr = new ConstantExpressionSyntaxNode(); + expr->Type.type = getIntType(); + expr->ConstType = ConstantExpressionSyntaxNode::ConstantType::Int; + expr->integerValue = value; + return expr; + } + + struct SeqExprBuilder + { + RefPtr expr; + RefPtr* link = nullptr; + }; + + RefPtr createSimpleVarExpr(char const* name) + { + RefPtr varExpr = new VarExpressionSyntaxNode(); + varExpr->name = name; + return varExpr; + } + + RefPtr createSeqExpr( + RefPtr left, + RefPtr right) + { + RefPtr seqExpr = new InfixExpr(); + seqExpr->Position = left->Position; + seqExpr->Type = right->Type; + seqExpr->FunctionExpr = createSimpleVarExpr(","); + seqExpr->Arguments.Add(left); + seqExpr->Arguments.Add(right); + return seqExpr; + } + + void addExpr(SeqExprBuilder* builder, RefPtr expr) + { + // No expression to add? Do nothing. + if (!expr) return; + + if (!builder->expr) + { + // No expression so far? + // Set up a single-expression result. + + builder->expr = expr; + builder->link = &builder->expr; + return; + } + + // There is an existing expression, so we need to append + // to the sequence of expressions. The invariant is + // that `link` points to the last expression in the + // sequence. + + // We will extract the old last element, and construct + // a new sequence expression ("operator comma") that + // concatenates with with our new last expression. + auto oldLastExpr = *builder->link; + auto seqExpr = createSeqExpr(oldLastExpr, expr); + + // Now we need to overwrite the old last expression, + // wherever it occured in the AST (which we handily + // stored in `link`) and set our `link` to track + // the new last expression (which will be the second + // argument to our sequence expression). + *builder->link = seqExpr; + builder->link = &seqExpr->Arguments[1]; + } + + RefPtr createSimpleAssignExprWithFixups( RefPtr leftExpr, RefPtr rightExpr) + { + auto leftType = leftExpr->Type.type; + auto rightType = rightExpr->Type.type; + + // If types are unknown, or match, then just do + // things the ordinary way. + if (!leftType + || !rightType + || leftType->As() + || rightType->As() + || leftType->Equals(rightType)) + { + return createSimpleAssignExpr(leftExpr, rightExpr); + } + + // Otherwise, start to look at the types involved, + // and see if we can do something. + + if (auto leftArrayType = leftType->As()) + { + // LHS type was an array + + if (auto rightVecType = rightType->As()) + { + // RHS type was a vector + if (auto leftElemVecType = leftArrayType->BaseType->As()) + { + // LHS element type was also a vector, so this is a "scalar splat + // to array" case. + } + else + { + // LHS is an array of non-vectors, while RHS is a vector, + // so in this case we want to splat out the vector elements + // to create an array and use that. + leftExpr = maybeMoveTemp(leftExpr); + rightExpr = maybeMoveTemp(rightExpr); + + SeqExprBuilder builder; + + int elementCount = (int) GetIntVal(rightVecType->elementCount); + for (int ee = 0; ee < elementCount; ++ee) + { + // LHS array element + RefPtr arrayElemExpr = new IndexExpressionSyntaxNode(); + arrayElemExpr->Position = leftExpr->Position; + arrayElemExpr->Type.type = leftArrayType->BaseType; + arrayElemExpr->BaseExpression = leftExpr; + arrayElemExpr->IndexExpression = createConstIntExpr(ee); + + // RHS swizzle + RefPtr swizzleExpr = new SwizzleExpr(); + swizzleExpr->Position = rightExpr->Position; + swizzleExpr->Type.type = rightVecType->elementType; + swizzleExpr->base = rightExpr; + swizzleExpr->elementCount = 1; + swizzleExpr->elementIndices[0] = ee; + + auto elemAssignExpr = createSimpleAssignExprWithFixups( + arrayElemExpr, + swizzleExpr); + + addExpr(&builder, elemAssignExpr); + } + + return builder.expr; + } + } + } + + + + + // TODO: are there any cases we can't solve with a cast? + + // Try to convert the right-hand-side expression to have the type + // we expect on the left-hand side + auto convertedRightExpr = convertExprForAssignmentWithFixups(leftType, rightExpr); + return createSimpleAssignExpr(leftExpr, convertedRightExpr); + } + + RefPtr createAssignExpr( + RefPtr leftExpr, + RefPtr rightExpr, + AssignMode mode = AssignMode::Default) { auto leftTuple = leftExpr.As(); auto rightTuple = rightExpr.As(); @@ -803,7 +1040,8 @@ struct LoweringVisitor resultTuple->primaryExpr = createAssignExpr( leftTuple->primaryExpr, - rightTuple->primaryExpr); + rightTuple->primaryExpr, + mode); } auto elementCount = leftTuple->tupleElements.Count(); @@ -818,7 +1056,8 @@ struct LoweringVisitor resultElement.tupleFieldDeclRef = leftElement.tupleFieldDeclRef; resultElement.expr = createAssignExpr( leftElement.expr, - rightElement.expr); + rightElement.expr, + mode); resultTuple->tupleElements.Add(resultElement); } @@ -852,7 +1091,8 @@ struct LoweringVisitor elem.originalFieldDeclRef = leftElem.originalFieldDeclRef; elem.expr = createAssignExpr( leftElem.expr, - rightElem.expr); + rightElem.expr, + mode); } } else if (leftVaryingTuple) @@ -888,14 +1128,15 @@ struct LoweringVisitor RefPtr rightElemExpr = new MemberExpressionSyntaxNode(); rightElemExpr->Position = rightExpr->Position; - rightElemExpr->Type = leftElem.expr->Type; + rightElemExpr->Type.type = GetType(leftElem.originalFieldDeclRef); rightElemExpr->declRef = leftElem.originalFieldDeclRef; rightElemExpr->name = leftElem.originalFieldDeclRef.GetName(); rightElemExpr->BaseExpression = rightExpr; auto subExpr = createAssignExpr( leftElem.expr, - rightElemExpr); + rightElemExpr, + mode); RefPtr seqExpr = new InfixExpr(); seqExpr->FunctionExpr = createUncheckedVarRef(","); @@ -942,7 +1183,8 @@ struct LoweringVisitor auto subExpr = createAssignExpr( leftElemExpr, - rightElem.expr); + rightElem.expr, + mode); RefPtr seqExpr = new InfixExpr(); seqExpr->FunctionExpr = createUncheckedVarRef(","); @@ -957,12 +1199,14 @@ struct LoweringVisitor // Default case: no tuples of any kind... + switch (mode) + { + default: + return createSimpleAssignExpr(leftExpr, rightExpr); - RefPtr loweredExpr = new AssignExpr(); - loweredExpr->Type = leftExpr->Type; - loweredExpr->left = leftExpr; - loweredExpr->right = rightExpr; - return loweredExpr; + case AssignMode::WithFixups: + return createSimpleAssignExprWithFixups(leftExpr, rightExpr); + } } RefPtr visitAssignExpr( @@ -1462,6 +1706,11 @@ struct LoweringVisitor } } } + else if (auto varExpr = expr.As()) + { + // Skip an expression that is just a reference to a single variable + return; + } RefPtr stmt = new ExpressionStatementSyntaxNode(); stmt->Expression = expr; @@ -1710,9 +1959,10 @@ struct LoweringVisitor void assign( RefPtr destExpr, - RefPtr srcExpr) + RefPtr srcExpr, + AssignMode mode = AssignMode::Default) { - auto assignExpr = createAssignExpr(destExpr, srcExpr); + auto assignExpr = createAssignExpr(destExpr, srcExpr, mode); addExprStmt(assignExpr); } @@ -1726,6 +1976,38 @@ struct LoweringVisitor assign(expr, createVarRef(expr->Position, varDecl)); } + RefPtr createCastExpr( + RefPtr type, + RefPtr expr) + { + RefPtr castExpr = new ExplicitCastExpr(); + castExpr->Position = expr->Position; + castExpr->Type.type = type; + castExpr->TargetType.type = type; + castExpr->Expression = expr; + return castExpr; + } + + // Like `assign`, but with some extra logic to handle cases + // where the types don't actually line up, because of + // differences in how something is declared in HLSL vs. GLSL + void assignWithFixups( + RefPtr destExpr, + RefPtr srcExpr) + { + assign(destExpr, srcExpr, AssignMode::WithFixups); + } + + void assignWithFixups(VarDeclBase* varDecl, RefPtr expr) + { + assignWithFixups(createVarRef(expr->Position, varDecl), expr); + } + + void assignWithFixups(RefPtr expr, VarDeclBase* varDecl) + { + assignWithFixups(expr, createVarRef(expr->Position, varDecl)); + } + void visitReturnStatementSyntaxNode(ReturnStatementSyntaxNode* stmt) { auto loweredStmt = new ReturnStatementSyntaxNode(); @@ -2926,10 +3208,12 @@ struct LoweringVisitor }; RefPtr createGLSLBuiltinRef( - char const* name) + char const* name, + RefPtr type) { RefPtr globalVarRef = new VarExpressionSyntaxNode(); globalVarRef->name = name; + globalVarRef->Type.type = type; return globalVarRef; } @@ -2970,6 +3254,82 @@ struct LoweringVisitor Slang::requireGLSLVersion(entryPoint, version); } + RefPtr getFloatType() + { + return ExpressionType::GetFloat(); + } + + RefPtr getIntType() + { + return ExpressionType::GetInt(); + } + + RefPtr getUIntType() + { + return ExpressionType::GetUInt(); + } + + RefPtr getBoolType() + { + return ExpressionType::GetBool(); + } + + RefPtr getVectorType( + RefPtr elementType, + RefPtr elementCount) + { + auto vectorGenericDecl = findMagicDecl("Vector").As(); + auto vectorTypeDecl = vectorGenericDecl->inner; + + auto substitutions = new Substitutions(); + substitutions->genericDecl = vectorGenericDecl.Ptr(); + substitutions->args.Add(elementType); + substitutions->args.Add(elementCount); + + auto declRef = DeclRef(vectorTypeDecl.Ptr(), substitutions); + + return DeclRefType::Create(declRef)->As(); + } + + RefPtr getConstantIntVal(IntegerLiteralValue value) + { + RefPtr intVal = new ConstantIntVal(); + intVal->value = value; + return intVal; + } + + RefPtr getVectorType( + RefPtr elementType, + int elementCount) + { + return getVectorType(elementType, getConstantIntVal(elementCount)); + } + + RefPtr getUnsizedArrayType( + RefPtr elementType) + { + RefPtr arrayType = new ArrayExpressionType(); + arrayType->BaseType = elementType; + return arrayType; + } + + RefPtr getArrayType( + RefPtr elementType, + RefPtr elementCount) + { + RefPtr arrayType = new ArrayExpressionType(); + arrayType->BaseType = elementType; + arrayType->ArrayLength = elementCount; + return arrayType; + } + + RefPtr getArrayType( + RefPtr elementType, + IntegerLiteralValue elementCount) + { + return getArrayType(elementType, getConstantIntVal(elementCount)); + } + RefPtr lowerSimpleShaderParameterToGLSLGlobal( VaryingParameterInfo const& info, RefPtr varType, @@ -2986,6 +3346,8 @@ struct LoweringVisitor type = arrayType; } + assert(type); + // 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. @@ -3009,94 +3371,90 @@ struct LoweringVisitor { if (info.direction == VaryingParameterDirection::Input) { - globalVarExpr = createGLSLBuiltinRef("gl_FragCoord"); + globalVarExpr = createGLSLBuiltinRef("gl_FragCoord", getVectorType(getFloatType(), 4)); } else { - globalVarExpr = createGLSLBuiltinRef("gl_Position"); + globalVarExpr = createGLSLBuiltinRef("gl_Position", getVectorType(getFloatType(), 4)); } } else if (ns == "sv_clipdistance") { - globalVarExpr = createGLSLBuiltinRef("gl_ClipDistance"); + globalVarExpr = createGLSLBuiltinRef("gl_ClipDistance", getUnsizedArrayType(getFloatType())); } else if (ns == "sv_culldistance") { - // TODO: ARB_cull_distance - globalVarExpr = createGLSLBuiltinRef("gl_CullDistance"); + requireGLSLExtension(shared->extensionUsageTracker, "ARB_cull_distance"); + globalVarExpr = createGLSLBuiltinRef("gl_CullDistance", getUnsizedArrayType(getFloatType())); } else if (ns == "sv_coverage") { if (info.direction == VaryingParameterDirection::Input) { - globalVarExpr = createGLSLBuiltinRef("gl_SampleMaskIn"); + globalVarExpr = createGLSLBuiltinRef("gl_SampleMaskIn", getUnsizedArrayType(getIntType())); } else { - globalVarExpr = createGLSLBuiltinRef("gl_SampleMask"); + globalVarExpr = createGLSLBuiltinRef("gl_SampleMask", getUnsizedArrayType(getIntType())); } } else if (ns == "sv_depth") { - globalVarExpr = createGLSLBuiltinRef("gl_FragDepth"); + globalVarExpr = createGLSLBuiltinRef("gl_FragDepth", getFloatType()); } else if (ns == "sv_depthgreaterequal") { // TODO: layout(depth_greater) out float gl_FragDepth; - globalVarExpr = createGLSLBuiltinRef("gl_FragDepth"); + globalVarExpr = createGLSLBuiltinRef("gl_FragDepth", getFloatType()); } else if (ns == "sv_depthlessequal") { // TODO: layout(depth_less) out float gl_FragDepth; - globalVarExpr = createGLSLBuiltinRef("gl_FragDepth"); + globalVarExpr = createGLSLBuiltinRef("gl_FragDepth", getFloatType()); } else if (ns == "sv_dispatchthreadid") { - globalVarExpr = createGLSLBuiltinRef("gl_GlobalInvocationID"); + globalVarExpr = createGLSLBuiltinRef("gl_GlobalInvocationID", getVectorType(getUIntType(), 3)); } else if (ns == "sv_domainlocation") { - globalVarExpr = createGLSLBuiltinRef("gl_TessCoord"); + globalVarExpr = createGLSLBuiltinRef("gl_TessCoord", getVectorType(getFloatType(), 3)); } else if (ns == "sv_groupid") { - globalVarExpr = createGLSLBuiltinRef("gl_WorkGroupID"); + globalVarExpr = createGLSLBuiltinRef("gl_WorkGroupID", getVectorType(getUIntType(), 3)); } else if (ns == "sv_groupindex") { - globalVarExpr = createGLSLBuiltinRef("gl_LocationInvocationIndex"); + globalVarExpr = createGLSLBuiltinRef("gl_LocalInvocationIndex", getUIntType()); } else if (ns == "sv_groupthreadid") { - globalVarExpr = createGLSLBuiltinRef("gl_LocalInvocationID"); + globalVarExpr = createGLSLBuiltinRef("gl_LocalInvocationID", getVectorType(getUIntType(), 3)); } else if (ns == "sv_gsinstanceid") { - globalVarExpr = createGLSLBuiltinRef("gl_InvocationID"); + globalVarExpr = createGLSLBuiltinRef("gl_InvocationID", getIntType()); } else if (ns == "sv_insidetessfactor") { - globalVarExpr = createGLSLBuiltinRef("gl_TessLevelInner"); + globalVarExpr = createGLSLBuiltinRef("gl_TessLevelInner", getArrayType(getFloatType(), 2)); } else if (ns == "sv_instanceid") { - globalVarExpr = createGLSLBuiltinRef("gl_InstanceIndex"); + globalVarExpr = createGLSLBuiltinRef("gl_InstanceIndex", getIntType()); } else if (ns == "sv_isfrontface") { - globalVarExpr = createGLSLBuiltinRef("gl_FrontFacing"); - } - else if (ns == "sv_outputcontrolpointid") - { - globalVarExpr = createGLSLBuiltinRef("gl_InvocationID"); + globalVarExpr = createGLSLBuiltinRef("gl_FrontFacing", getBoolType()); } else if (ns == "sv_outputcontrolpointid") { - globalVarExpr = createGLSLBuiltinRef("gl_InvocationID"); + globalVarExpr = createGLSLBuiltinRef("gl_InvocationID", getIntType()); } else if (ns == "sv_primitiveid") { - globalVarExpr = createGLSLBuiltinRef("gl_PrimitiveID"); + globalVarExpr = createGLSLBuiltinRef("gl_PrimitiveID", getIntType()); } else if (ns == "sv_rendertargetarrayindex") { @@ -3104,28 +3462,61 @@ struct LoweringVisitor { requireGLSLVersion(ProfileVersion::GLSL_430); } - globalVarExpr = createGLSLBuiltinRef("gl_Layer"); + globalVarExpr = createGLSLBuiltinRef("gl_Layer", getIntType()); } else if (ns == "sv_sampleindex") { - globalVarExpr = createGLSLBuiltinRef("gl_SampleID"); + setSampleRateFlag(); + globalVarExpr = createGLSLBuiltinRef("gl_SampleID", getIntType()); } else if (ns == "sv_stencilref") { - // TODO: ARB_shader_stencil_export - globalVarExpr = createGLSLBuiltinRef("gl_SampleID"); + requireGLSLExtension(shared->extensionUsageTracker, "ARB_shader_stencil_export"); + globalVarExpr = createGLSLBuiltinRef("gl_FragStencilRef", getIntType()); } else if (ns == "sv_tessfactor") { - globalVarExpr = createGLSLBuiltinRef("gl_TessLevelOuter"); + globalVarExpr = createGLSLBuiltinRef("gl_TessLevelOuter", getArrayType(getFloatType(), 4)); } else if (ns == "sv_vertexid") { - globalVarExpr = createGLSLBuiltinRef("gl_VertexIndex"); + globalVarExpr = createGLSLBuiltinRef("gl_VertexIndex", getIntType()); } else if (ns == "sv_viewportarrayindex") { - globalVarExpr = createGLSLBuiltinRef("gl_ViewportIndex"); + globalVarExpr = createGLSLBuiltinRef("gl_ViewportIndex", getIntType()); + } + else if (ns == "nv_x_right") + { + requireGLSLVersion(ProfileVersion::GLSL_450); + requireGLSLExtension(shared->extensionUsageTracker, "GL_NVX_multiview_per_view_attributes"); + + // The actual output in GLSL is: + // + // vec4 gl_PositionPerViewNV[]; + // + // and is meant to support an arbitrary number of views, + // while the HLSL case just defines a second position + // output. + // + // For now we will hack this by: + // 1. Mapping an `NV_X_Right` output to `gl_PositionPerViewNV[1]` + // (that is, just one element of the output array) + // 2. Adding logic to copy the traditional `gl_Position` output + // over to `gl_PositionPerViewNV[0]` + // + + globalVarExpr = createGLSLBuiltinRef("gl_PositionPerViewNV[1]", + getVectorType(getFloatType(), 4)); + + shared->requiresCopyGLPositionToPositionPerView = true; + } + else if (ns == "nv_viewport_mask") + { + requireGLSLVersion(ProfileVersion::GLSL_450); + requireGLSLExtension(shared->extensionUsageTracker, "GL_NVX_multiview_per_view_attributes"); + globalVarExpr = createGLSLBuiltinRef("gl_ViewportMaskPerViewNV", + getUnsizedArrayType(getIntType())); } else { @@ -3193,6 +3584,7 @@ struct LoweringVisitor RefPtr globalVarRef = new VarExpressionSyntaxNode(); globalVarRef->Position = globalVarDecl->Position; + globalVarRef->Type.type = globalVarDecl->Type.type; globalVarRef->declRef = makeDeclRef(globalVarDecl.Ptr()); globalVarRef->name = globalVarDecl->getName(); @@ -3451,7 +3843,7 @@ struct LoweringVisitor paramPair.layout, VaryingParameterDirection::Input); - subVisitor.assign(paramPair.lowered, loweredExpr); + subVisitor.assignWithFixups(paramPair.lowered, loweredExpr); } } @@ -3521,7 +3913,7 @@ struct LoweringVisitor paramPair.layout, VaryingParameterDirection::Output); - subVisitor.assign(loweredExpr, paramPair.lowered); + subVisitor.assignWithFixups(loweredExpr, paramPair.lowered); } } if (resultVarDecl) @@ -3536,7 +3928,13 @@ struct LoweringVisitor resultVarDecl->Type.type, entryPointLayout->resultLayout); - subVisitor.assign(loweredExpr, resultVarDecl); + subVisitor.assignWithFixups(loweredExpr, resultVarDecl); + } + if (shared->requiresCopyGLPositionToPositionPerView) + { + subVisitor.assign( + createSimpleVarExpr("gl_PositionPerViewNV[0]"), + createSimpleVarExpr("gl_Position")); } bodyStmt->body = subVisitor.stmtBeingBuilt; @@ -3701,15 +4099,17 @@ bool isRewriteRequest( LoweredEntryPoint lowerEntryPoint( - EntryPointRequest* entryPoint, - ProgramLayout* programLayout, - CodeGenTarget target) + EntryPointRequest* entryPoint, + ProgramLayout* programLayout, + CodeGenTarget target, + ExtensionUsageTracker* extensionUsageTracker) { SharedLoweringContext sharedContext; sharedContext.compileRequest = entryPoint->compileRequest; sharedContext.entryPointRequest = entryPoint; sharedContext.programLayout = programLayout; sharedContext.target = target; + sharedContext.extensionUsageTracker = extensionUsageTracker; auto translationUnit = entryPoint->getTranslationUnit(); diff --git a/source/slang/lower.h b/source/slang/lower.h index c690ea025..688c1df8f 100644 --- a/source/slang/lower.h +++ b/source/slang/lower.h @@ -17,6 +17,8 @@ namespace Slang class ProgramLayout; class TranslationUnitRequest; + struct ExtensionUsageTracker; + struct LoweredEntryPoint { // The actual lowered entry point @@ -31,8 +33,9 @@ namespace Slang // Emit code for a single entry point, based on // the input translation unit. LoweredEntryPoint lowerEntryPoint( - EntryPointRequest* entryPoint, - ProgramLayout* programLayout, - CodeGenTarget target); + EntryPointRequest* entryPoint, + ProgramLayout* programLayout, + CodeGenTarget target, + ExtensionUsageTracker* extensionUsageTracker); } #endif diff --git a/source/slang/parameter-binding.cpp b/source/slang/parameter-binding.cpp index 17c2bb193..2f2bbec05 100644 --- a/source/slang/parameter-binding.cpp +++ b/source/slang/parameter-binding.cpp @@ -1081,7 +1081,8 @@ static RefPtr processSimpleEntryPointParameter( String sn = semanticName.ToLower(); RefPtr typeLayout = new TypeLayout(); - if (sn.StartsWith("sv_")) + if (sn.StartsWith("sv_") + || sn.StartsWith("nv_")) { // System-value semantic. -- cgit v1.2.3