summaryrefslogtreecommitdiff
path: root/source/slang/ir.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/ir.cpp')
-rw-r--r--source/slang/ir.cpp335
1 files changed, 307 insertions, 28 deletions
diff --git a/source/slang/ir.cpp b/source/slang/ir.cpp
index 3d04e9807..441db09a6 100644
--- a/source/slang/ir.cpp
+++ b/source/slang/ir.cpp
@@ -2871,7 +2871,242 @@ namespace Slang
GlobalVaryingDeclarator* next;
};
+ struct GLSLSystemValueInfo
+ {
+ char const* name;
+ };
+
+ void requireGLSLVersionImpl(
+ ExtensionUsageTracker* tracker,
+ ProfileVersion version);
+
+ void requireGLSLExtension(
+ ExtensionUsageTracker* tracker,
+ String const& name);
+
+ struct GLSLLegalizationContext
+ {
+ ExtensionUsageTracker* extensionUsageTracker;
+ DiagnosticSink* sink;
+ Stage stage;
+
+ void requireGLSLExtension(String const& name)
+ {
+ Slang::requireGLSLExtension(extensionUsageTracker, name);
+ }
+
+ void requireGLSLVersion(ProfileVersion version)
+ {
+ Slang::requireGLSLVersionImpl(extensionUsageTracker, version);
+ }
+
+ Stage getStage()
+ {
+ return stage;
+ }
+
+ DiagnosticSink* getSink()
+ {
+ return sink;
+ }
+ };
+
+ GLSLSystemValueInfo* getGLSLSystemValueInfo(
+ GLSLLegalizationContext* context,
+ VarLayout* varLayout,
+ LayoutResourceKind kind,
+ GLSLSystemValueInfo* inStorage)
+ {
+ char const* name = nullptr;
+
+ auto semanticNameSpelling = varLayout->systemValueSemantic;
+ if(semanticNameSpelling.Length() == 0)
+ return nullptr;
+
+ auto semanticName = semanticNameSpelling.ToLower();
+
+ if(semanticName == "sv_position")
+ {
+ // TODO: need to pick between `gl_Position` and
+ // `gl_FragCoord` based on whether this is an input
+ // or an output.
+ if( kind == LayoutResourceKind::VaryingOutput )
+ {
+ name = "gl_Position";
+ }
+ else
+ {
+ name = "gl_FragCoord";
+ }
+ }
+ else if(semanticName == "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.
+ return nullptr;
+ }
+ else if(semanticName == "sv_clipdistance")
+ {
+ // TODO: type conversion is required here.
+ name = "gl_ClipDistance";
+ }
+ else if(semanticName == "sv_culldistance")
+ {
+ context->requireGLSLExtension("ARB_cull_distance");
+
+ // TODO: type conversion is required here.
+ name = "gl_CullDistance";
+ }
+ else if(semanticName == "sv_coverage")
+ {
+ // TODO: deal with `gl_SampleMaskIn` when used as an input.
+
+ // TODO: type conversion is required here.
+ name = "gl_SampleMask";
+ }
+ else if(semanticName == "sv_depth")
+ {
+ name = "gl_FragDepth";
+ }
+ else if(semanticName == "sv_depthgreaterequal")
+ {
+ // TODO: layout(depth_greater) out float gl_FragDepth;
+ name = "gl_FragDepth";
+ }
+ else if(semanticName == "sv_depthlessequal")
+ {
+ // TODO: layout(depth_greater) out float gl_FragDepth;
+ name = "gl_FragDepth";
+ }
+ else if(semanticName == "sv_dispatchthreadid")
+ {
+ name = "gl_GlobalInvocationID";
+ }
+ else if(semanticName == "sv_domainlocation")
+ {
+ name = "gl_TessCoord";
+ }
+ else if(semanticName == "sv_groupid")
+ {
+ name = "gl_WorkGroupID";
+ }
+ else if(semanticName == "sv_groupindex")
+ {
+ name = "gl_LocalInvocationIndex";
+ }
+ else if(semanticName == "sv_groupthreadid")
+ {
+ name = "gl_LocalInvocationID";
+ }
+ else if(semanticName == "sv_gsinstanceid")
+ {
+ name = "gl_InvocationID";
+ }
+ else if(semanticName == "sv_instanceid")
+ {
+ name = "gl_InstanceIndex";
+ }
+ else if(semanticName == "sv_isfrontface")
+ {
+ name = "gl_FrontFacing";
+ }
+ else if(semanticName == "sv_outputcontrolpointid")
+ {
+ name = "gl_InvocationID";
+ }
+ else if(semanticName == "sv_primitiveid")
+ {
+ name = "gl_PrimitiveID";
+ }
+ else if (semanticName == "sv_rendertargetarrayindex")
+ {
+ switch (context->getStage())
+ {
+ case Stage::Geometry:
+ context->requireGLSLVersion(ProfileVersion::GLSL_150);
+ break;
+
+ case Stage::Fragment:
+ context->requireGLSLVersion(ProfileVersion::GLSL_430);
+ break;
+
+ default:
+ context->requireGLSLVersion(ProfileVersion::GLSL_450);
+ context->requireGLSLExtension("GL_ARB_shader_viewport_layer_array");
+ break;
+ }
+
+ name = "gl_Layer";
+ }
+ else if (semanticName == "sv_sampleindex")
+ {
+ name = "gl_SampleID";
+ }
+ else if (semanticName == "sv_stencilref")
+ {
+ context->requireGLSLExtension("ARB_shader_stencil_export");
+ name = "gl_FragStencilRef";
+ }
+ else if (semanticName == "sv_tessfactor")
+ {
+ name = "gl_TessLevelOuter";
+ }
+ else if (semanticName == "sv_vertexid")
+ {
+ name = "gl_VertexIndex";
+ }
+ else if (semanticName == "sv_viewportarrayindex")
+ {
+ name = "gl_ViewportIndex";
+ }
+ else if (semanticName == "nv_x_right")
+ {
+ context->requireGLSLVersion(ProfileVersion::GLSL_450);
+ context->requireGLSLExtension("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]`
+ //
+
+ name = "gl_PositionPerViewNV[1]";
+
+// shared->requiresCopyGLPositionToPositionPerView = true;
+ }
+ else if (semanticName == "nv_viewport_mask")
+ {
+ context->requireGLSLVersion(ProfileVersion::GLSL_450);
+ context->requireGLSLExtension("GL_NVX_multiview_per_view_attributes");
+
+ name = "gl_ViewportMaskPerViewNV";
+// globalVarExpr = createGLSLBuiltinRef("gl_ViewportMaskPerViewNV",
+// getUnsizedArrayType(getIntType()));
+ }
+
+ if( name )
+ {
+ inStorage->name = name;
+ return inStorage;
+ }
+
+ context->getSink()->diagnose(varLayout->varDecl.getDecl()->loc, Diagnostics::unknownSystemValueSemantic, semanticNameSpelling);
+ return nullptr;
+ }
+
ScalarizedVal createSimpleGLSLGlobalVarying(
+ GLSLLegalizationContext* context,
IRBuilder* builder,
Type* inType,
VarLayout* inVarLayout,
@@ -2880,13 +3115,18 @@ namespace Slang
UInt bindingIndex,
GlobalVaryingDeclarator* declarator)
{
- // TODO: detect when the layout represents a system input/output
- if( inVarLayout->systemValueSemantic.Length() != 0 )
- {
- // This variable represents a system input/output,
- // and we should probably handle that differently, right?
- }
+ // Check if we have a system value on our hands.
+ GLSLSystemValueInfo systemValueInfoStorage;
+ auto systemValueInfo = getGLSLSystemValueInfo(
+ context,
+ inVarLayout,
+ kind,
+ &systemValueInfoStorage);
+ // Construct the actual type and type-layout for the global variable
+ //
+ // TODO: in the case of a system value, we may need to override the type
+ //
RefPtr<Type> type = inType;
RefPtr<TypeLayout> typeLayout = inTypeLayout;
for( auto dd = declarator; dd; dd = dd->next )
@@ -2919,13 +3159,6 @@ namespace Slang
typeLayout = arrayTypeLayout;
}
- // Simple case: just create a global variable of the matching type,
- // and then use the value of the global as a replacement for the
- // value of the original parameter.
- //
- auto globalVariable = addGlobalVariable(builder->getModule(), type);
- moveValueBefore(globalVariable, builder->getFunc());
-
// We need to construct a fresh layout for the variable, even
// if the original had its own layout, because it might be
// an `inout` parameter, and we only want to deal with the case
@@ -2941,12 +3174,25 @@ namespace Slang
varLayout->stage = inVarLayout->stage;
varLayout->AddResourceInfo(kind)->index = bindingIndex;
+ // Simple case: just create a global variable of the matching type,
+ // and then use the value of the global as a replacement for the
+ // value of the original parameter.
+ //
+ auto globalVariable = addGlobalVariable(builder->getModule(), type);
+ moveValueBefore(globalVariable, builder->getFunc());
+
+ if( systemValueInfo )
+ {
+ globalVariable->mangledName = systemValueInfo->name;
+ }
+
builder->addLayoutDecoration(globalVariable, varLayout);
return ScalarizedVal::address(globalVariable);
}
ScalarizedVal createGLSLGlobalVaryingsImpl(
+ GLSLLegalizationContext* context,
IRBuilder* builder,
Type* type,
VarLayout* varLayout,
@@ -2957,16 +3203,22 @@ namespace Slang
{
if( type->As<BasicExpressionType>() )
{
- return createSimpleGLSLGlobalVarying(builder, type, varLayout, typeLayout, kind, bindingIndex, declarator);
+ return createSimpleGLSLGlobalVarying(
+ context,
+ builder, type, varLayout, typeLayout, kind, bindingIndex, declarator);
}
else if( type->As<VectorExpressionType>() )
{
- return createSimpleGLSLGlobalVarying(builder, type, varLayout, typeLayout, kind, bindingIndex, declarator);
+ return createSimpleGLSLGlobalVarying(
+ context,
+ builder, type, varLayout, typeLayout, kind, bindingIndex, declarator);
}
else if( type->As<MatrixExpressionType>() )
{
// TODO: a matrix-type varying should probably be handled like an array of rows
- return createSimpleGLSLGlobalVarying(builder, type, varLayout, typeLayout, kind, bindingIndex, declarator);
+ return createSimpleGLSLGlobalVarying(
+ context,
+ builder, type, varLayout, typeLayout, kind, bindingIndex, declarator);
}
else if( auto arrayType = type->As<ArrayExpressionType>() )
{
@@ -2984,6 +3236,7 @@ namespace Slang
arrayDeclarator.next = declarator;
return createGLSLGlobalVaryingsImpl(
+ context,
builder,
elementType,
varLayout,
@@ -3020,6 +3273,7 @@ namespace Slang
fieldBindingIndex += fieldResInfo->index;
auto fieldVal = createGLSLGlobalVaryingsImpl(
+ context,
builder,
ff->typeLayout->type,
ff,
@@ -3041,19 +3295,24 @@ namespace Slang
}
// Default case is to fall back on the simple behavior
- return createSimpleGLSLGlobalVarying(builder, type, varLayout, typeLayout, kind, bindingIndex, declarator);
+ return createSimpleGLSLGlobalVarying(
+ context,
+ builder, type, varLayout, typeLayout, kind, bindingIndex, declarator);
}
ScalarizedVal createGLSLGlobalVaryings(
- IRBuilder* builder,
- Type* type,
- VarLayout* layout,
- LayoutResourceKind kind)
+ GLSLLegalizationContext* context,
+ IRBuilder* builder,
+ Type* type,
+ VarLayout* layout,
+ LayoutResourceKind kind)
{
UInt bindingIndex = 0;
if(auto rr = layout->FindResourceInfo(kind))
bindingIndex = rr->index;
- return createGLSLGlobalVaryingsImpl(builder, type, layout, layout->typeLayout, kind, bindingIndex, nullptr);
+ return createGLSLGlobalVaryingsImpl(
+ context,
+ builder, type, layout, layout->typeLayout, kind, bindingIndex, nullptr);
}
ScalarizedVal extractField(
@@ -3189,8 +3448,15 @@ namespace Slang
void legalizeEntryPointForGLSL(
Session* session,
IRFunc* func,
- EntryPointLayout* entryPointLayout)
+ EntryPointLayout* entryPointLayout,
+ DiagnosticSink* sink,
+ ExtensionUsageTracker* extensionUsageTracker)
{
+ GLSLLegalizationContext context;
+ context.stage = entryPointLayout->profile.GetStage();
+ context.sink = sink;
+ context.extensionUsageTracker = extensionUsageTracker;
+
auto module = func->parentModule;
// We require that the entry-point function has no uses,
@@ -3250,6 +3516,7 @@ namespace Slang
// code to write to that variable.
auto resultGlobal = createGLSLGlobalVaryings(
+ &context,
&builder,
resultType,
entryPointLayout->resultLayout,
@@ -3345,7 +3612,9 @@ namespace Slang
// In the `in out` case we need to declare two
// sets of global variables: one for the `in`
// side and one for the `out` side.
- auto globalInputVal = createGLSLGlobalVaryings(&builder, valueType, paramLayout, LayoutResourceKind::VertexInput);
+ auto globalInputVal = createGLSLGlobalVaryings(
+ &context,
+ &builder, valueType, paramLayout, LayoutResourceKind::VertexInput);
assign(&builder, localVal, globalInputVal);
}
@@ -3358,7 +3627,9 @@ namespace Slang
// We also need one or more global variabels to write the output to
// when the function is done. We create them here.
- auto globalOutputVal = createGLSLGlobalVaryings(&builder, valueType, paramLayout, LayoutResourceKind::FragmentOutput);
+ auto globalOutputVal = createGLSLGlobalVaryings(
+ &context,
+ &builder, valueType, paramLayout, LayoutResourceKind::FragmentOutput);
// Now we need to iterate over all the blocks in the function looking
// for any `return*` instructions, so that we can write to the output variable
@@ -3392,7 +3663,9 @@ namespace Slang
// and attach the required layout information to it along
// the way.
- auto globalValue = createGLSLGlobalVaryings(&builder, paramType, paramLayout, LayoutResourceKind::VertexInput);
+ auto globalValue = createGLSLGlobalVaryings(
+ &context,
+ &builder, paramType, paramLayout, LayoutResourceKind::VertexInput);
// Next we need to replace uses of the parameter with
// references to the variable(s). We are going to do that
@@ -4636,7 +4909,8 @@ namespace Slang
void specializeIRForEntryPoint(
IRSpecializationState* state,
- EntryPointRequest* entryPointRequest)
+ EntryPointRequest* entryPointRequest,
+ ExtensionUsageTracker* extensionUsageTracker)
{
auto target = state->target;
@@ -4675,7 +4949,12 @@ namespace Slang
{
case CodeGenTarget::GLSL:
{
- legalizeEntryPointForGLSL(session, irEntryPoint, entryPointLayout);
+ legalizeEntryPointForGLSL(
+ session,
+ irEntryPoint,
+ entryPointLayout,
+ &compileRequest->mSink,
+ extensionUsageTracker);
}
break;