diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang/emit.cpp | 235 | ||||
| -rw-r--r-- | source/slang/ir-insts.h | 5 | ||||
| -rw-r--r-- | source/slang/ir.cpp | 335 |
3 files changed, 333 insertions, 242 deletions
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp index 0cd896ced..e5fb6a8be 100644 --- a/source/slang/emit.cpp +++ b/source/slang/emit.cpp @@ -33,6 +33,8 @@ struct ExtensionUsageTracker // Record the GLSL extnsions we have already emitted a `#extension` for HashSet<String> glslExtensionsRequired; StringBuilder glslExtensionRequireLines; + + ProfileVersion profileVersion = ProfileVersion::GLSL_110; }; void requireGLSLExtension( @@ -51,6 +53,16 @@ void requireGLSLExtension( tracker->glslExtensionsRequired.Add(name); } +void requireGLSLVersionImpl( + ExtensionUsageTracker* tracker, + ProfileVersion version) +{ + // Check if this profile is newer + if ((UInt)version > (UInt)tracker->profileVersion) + { + tracker->profileVersion = version; + } +} // Shared state for an entire emit session @@ -4503,182 +4515,6 @@ emitDeclImpl(decl, nullptr); return name; } - String getGLSLSystemValueName( - IRValue* varDecl, - VarLayout* varLayout) - { - auto semanticNameSpelling = varLayout->systemValueSemantic; - 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. - return "gl_Position"; - } - 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 ""; - } - else if(semanticName == "sv_clipdistance") - { - // TODO: type conversion is required here. - return "gl_ClipDistance"; - } - else if(semanticName == "sv_culldistance") - { - requireGLSLExtension("ARB_cull_distance"); - - // TODO: type conversion is required here. - return "gl_CullDistance"; - } - else if(semanticName == "sv_coverage") - { - // TODO: deal with `gl_SampleMaskIn` when used as an input. - - // TODO: type conversion is required here. - return "gl_SampleMask"; - } - else if(semanticName == "sv_depth") - { - return "gl_FragDepth"; - } - else if(semanticName == "sv_depthgreaterequal") - { - // TODO: layout(depth_greater) out float gl_FragDepth; - return "gl_FragDepth"; - } - else if(semanticName == "sv_depthlessequal") - { - // TODO: layout(depth_greater) out float gl_FragDepth; - return "gl_FragDepth"; - } - else if(semanticName == "sv_dispatchthreadid") - { - return "gl_GlobalInvocationID"; - } - else if(semanticName == "sv_domainlocation") - { - return "gl_TessCoord"; - } - else if(semanticName == "sv_groupid") - { - return "gl_WorkGroupID"; - } - else if(semanticName == "sv_groupindex") - { - return "gl_LocalInvocationIndex"; - } - else if(semanticName == "sv_groupthreadid") - { - return "gl_LocalInvocationID"; - } - else if(semanticName == "sv_gsinstanceid") - { - return "gl_InvocationID"; - } - else if(semanticName == "sv_instanceid") - { - return "gl_InstanceIndex"; - } - else if(semanticName == "sv_isfrontface") - { - return "gl_FrontFacing"; - } - else if(semanticName == "sv_outputcontrolpointid") - { - return "gl_InvocationID"; - } - else if(semanticName == "sv_primitiveid") - { - return "gl_PrimitiveID"; - } - else if (semanticName == "sv_rendertargetarrayindex") - { - switch (context->shared->entryPoint->profile.GetStage()) - { - case Stage::Geometry: - requireGLSLVersion(ProfileVersion::GLSL_150); - break; - - case Stage::Fragment: - requireGLSLVersion(ProfileVersion::GLSL_430); - break; - - default: - requireGLSLVersion(ProfileVersion::GLSL_450); - requireGLSLExtension("GL_ARB_shader_viewport_layer_array"); - break; - } - - return "gl_Layer"; - } - else if (semanticName == "sv_sampleindex") - { - return "gl_SampleID"; - } - else if (semanticName == "sv_stencilref") - { - requireGLSLExtension("ARB_shader_stencil_export"); - return "gl_FragStencilRef"; - } - else if (semanticName == "sv_tessfactor") - { - return "gl_TessLevelOuter"; - } - else if (semanticName == "sv_vertexid") - { - return "gl_VertexIndex"; - } - else if (semanticName == "sv_viewportarrayindex") - { - return "gl_ViewportIndex"; - } - else if (semanticName == "nv_x_right") - { - requireGLSLVersion(ProfileVersion::GLSL_450); - 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]` - // - - return "gl_PositionPerViewNV[1]"; - -// shared->requiresCopyGLPositionToPositionPerView = true; - } - else if (semanticName == "nv_viewport_mask") - { - requireGLSLVersion(ProfileVersion::GLSL_450); - requireGLSLExtension("GL_NVX_multiview_per_view_attributes"); - - return "gl_ViewportMaskPerViewNV"; -// globalVarExpr = createGLSLBuiltinRef("gl_ViewportMaskPerViewNV", -// getUnsizedArrayType(getIntType())); - } - else - { - getSink()->diagnose(varDecl->sourceLoc, Diagnostics::unknownSystemValueSemantic, semanticNameSpelling); - return semanticName; - } - } - String getIRName( IRValue* inst) { @@ -4695,23 +4531,6 @@ emitDeclImpl(decl, nullptr); break; } - if(getTarget(context) == CodeGenTarget::GLSL) - { - if(auto layoutMod = inst->findDecoration<IRLayoutDecoration>()) - { - auto layout = layoutMod->layout; - if(auto varLayout = layout.As<VarLayout>()) - { - if(varLayout->systemValueSemantic.Length() != 0) - { - auto translated = getGLSLSystemValueName(inst, varLayout); - if(translated.Length()) - return translated; - } - } - } - } - if(auto decoration = inst->findDecoration<IRHighLevelDeclDecoration>()) { auto decl = decoration->decl; @@ -7743,26 +7562,15 @@ emitDeclImpl(decl, nullptr); // We want to skip the declaration of any system-value variables // when outputting GLSL (well, except in the case where they // actually *require* redeclaration...). - - if(auto layoutMod = varDecl->findDecoration<IRLayoutDecoration>()) + // + // TODO: can we detect this more robustly? + if(varDecl->mangledName.StartsWith("gl_")) { - auto layout = layoutMod->layout; - if(auto varLayout = layout.As<VarLayout>()) - { - if(varLayout->systemValueSemantic.Length() != 0) - { - auto translated = getGLSLSystemValueName(varDecl, varLayout); - if( translated.Length() ) - { - // The variable seems to translate to an OpenGL - // system value, so we will assume that it doesn't - // need to be declared. - // - // TODO: handle case where we *should* declare the variable. - return; - } - } - } + // The variable represents an OpenGL system value, + // so we will assume that it doesn't need to be declared. + // + // TODO: handle case where we *should* declare the variable. + return; } } @@ -8220,7 +8028,8 @@ String emitEntryPoint( specializeIRForEntryPoint( irSpecializationState, - entryPoint); + entryPoint, + &sharedContext.extensionUsageTracker); // If the user specified the flag that they want us to dump // IR, then do it here, for the target-specific, but diff --git a/source/slang/ir-insts.h b/source/slang/ir-insts.h index f53004ae4..e2c1c2e03 100644 --- a/source/slang/ir-insts.h +++ b/source/slang/ir-insts.h @@ -682,6 +682,8 @@ IRGlobalValue* getSpecializedGlobalValueForDeclRef( IRSpecializationState* state, DeclRef<Decl> const& declRef); +struct ExtensionUsageTracker; + // Clone the IR values reachable from the given entry point // into the IR module assocaited with the specialization state. // When multiple definitions of a symbol are found, the one @@ -689,7 +691,8 @@ IRGlobalValue* getSpecializedGlobalValueForDeclRef( // used. void specializeIRForEntryPoint( IRSpecializationState* state, - EntryPointRequest* entryPointRequest); + EntryPointRequest* entryPointRequest, + ExtensionUsageTracker* extensionUsageTracker); // Find suitable uses of the `specialize` instruction that // can be replaced with references to specialized functions. 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; |
