diff options
Diffstat (limited to 'source/slang/emit.cpp')
| -rw-r--r-- | source/slang/emit.cpp | 427 |
1 files changed, 377 insertions, 50 deletions
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp index 18216de81..dd9830c24 100644 --- a/source/slang/emit.cpp +++ b/source/slang/emit.cpp @@ -4520,22 +4520,178 @@ emitDeclImpl(decl, nullptr); } String getGLSLSystemValueName( + IRValue* varDecl, VarLayout* varLayout) { - auto semanticName = varLayout->systemValueSemantic; - semanticName = semanticName.ToLower(); + 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 { - return "gl_Unknown"; + getSink()->diagnose(varDecl->sourceLoc, Diagnostics::unknownSystemValueSemantic, semanticNameSpelling); + return semanticName; } } @@ -4564,7 +4720,7 @@ emitDeclImpl(decl, nullptr); { if(varLayout->systemValueSemantic.Length() != 0) { - auto translated = getGLSLSystemValueName(varLayout); + auto translated = getGLSLSystemValueName(inst, varLayout); if(translated.Length()) return translated; } @@ -4945,6 +5101,11 @@ emitDeclImpl(decl, nullptr); if(getTarget(ctx) == CodeGenTarget::GLSL) return true; } + else if(type->As<HLSLStructuredBufferTypeBase>()) + { + if(getTarget(ctx) == CodeGenTarget::GLSL) + return true; + } // By default we will *not* fold things into their use sites. return false; @@ -6242,65 +6403,146 @@ emitDeclImpl(decl, nullptr); } } - void emitIRSimpleFunc( - EmitContext* ctx, - IRFunc* func) + void emitIREntryPointAttributes_HLSL( + EmitContext* /*ctx*/, + EntryPointLayout* entryPointLayout) { - auto resultType = func->getResultType(); + auto profile = entryPointLayout->profile; + auto stage = profile.GetStage(); - // Deal with decorations that need - // to be emitted as attributes - auto entryPointLayout = asEntryPoint(func); - if (entryPointLayout) + switch (stage) { - auto profile = entryPointLayout->profile; - auto stage = profile.GetStage(); - - switch (stage) + case Stage::Compute: { - case Stage::Compute: + static const UInt kAxisCount = 3; + UInt sizeAlongAxis[kAxisCount]; + + // TODO: this is kind of gross because we are using a public + // reflection API function, rather than some kind of internal + // utility it forwards to... + spReflectionEntryPoint_getComputeThreadGroupSize( + (SlangReflectionEntryPoint*)entryPointLayout, + kAxisCount, + &sizeAlongAxis[0]); + + emit("[numthreads("); + for (int ii = 0; ii < 3; ++ii) { - static const UInt kAxisCount = 3; - UInt sizeAlongAxis[kAxisCount]; - - // TODO: this is kind of gross because we are using a public - // reflection API function, rather than some kind of internal - // utility it forwards to... - spReflectionEntryPoint_getComputeThreadGroupSize( - (SlangReflectionEntryPoint*)entryPointLayout, - kAxisCount, - &sizeAlongAxis[0]); - - emit("[numthreads("); - for (int ii = 0; ii < 3; ++ii) - { - if (ii != 0) emit(", "); - Emit(sizeAlongAxis[ii]); - } - emit(")]\n"); + if (ii != 0) emit(", "); + Emit(sizeAlongAxis[ii]); } - break; - case Stage::Geometry: + emit(")]\n"); + } + break; + case Stage::Geometry: + { + if (auto attrib = entryPointLayout->entryPoint->FindModifier<HLSLMaxVertexCountAttribute>()) { - if (auto attrib = entryPointLayout->entryPoint->FindModifier<HLSLMaxVertexCountAttribute>()) - { - emit("[maxvertexcount("); - Emit(attrib->value); - emit(")]\n"); - } - if (auto attrib = entryPointLayout->entryPoint->FindModifier<HLSLInstanceAttribute>()) + emit("[maxvertexcount("); + Emit(attrib->value); + emit(")]\n"); + } + if (auto attrib = entryPointLayout->entryPoint->FindModifier<HLSLInstanceAttribute>()) + { + emit("[instance("); + Emit(attrib->value); + emit(")]\n"); + } + } + break; + // TODO: There are other stages that will need this kind of handling. + default: + break; + } + } + + void emitIREntryPointAttributes_GLSL( + EmitContext* /*ctx*/, + EntryPointLayout* entryPointLayout) + { + auto profile = entryPointLayout->profile; + auto stage = profile.GetStage(); + + switch (stage) + { + case Stage::Compute: + { + static const UInt kAxisCount = 3; + UInt sizeAlongAxis[kAxisCount]; + + // TODO: this is kind of gross because we are using a public + // reflection API function, rather than some kind of internal + // utility it forwards to... + spReflectionEntryPoint_getComputeThreadGroupSize( + (SlangReflectionEntryPoint*)entryPointLayout, + kAxisCount, + &sizeAlongAxis[0]); + + emit("layout("); + char const* axes[] = { "x", "y", "z" }; + for (int ii = 0; ii < 3; ++ii) { - emit("[instance("); - Emit(attrib->value); - emit(")]\n"); + if (ii != 0) emit(", "); + emit("local_size_"); + emit(axes[ii]); + emit(" = "); + Emit(sizeAlongAxis[ii]); } + emit(") in;"); } break; - // TODO: There are other stages that will need this kind of handling. - default: - break; + case Stage::Geometry: + { + if (auto attrib = entryPointLayout->entryPoint->FindModifier<HLSLMaxVertexCountAttribute>()) + { + // TODO: need to include primitive type + emit("layout(max_vertices = "); + Emit(attrib->value); + emit(") out;\n"); + } + if (auto attrib = entryPointLayout->entryPoint->FindModifier<HLSLInstanceAttribute>()) + { + emit("layout(invocations = "); + Emit(attrib->value); + emit(") in;\n"); } } + break; + // TODO: There are other stages that will need this kind of handling. + default: + break; + } + } + + void emitIREntryPointAttributes( + EmitContext* ctx, + EntryPointLayout* entryPointLayout) + { + switch(getTarget(ctx)) + { + case CodeGenTarget::HLSL: + emitIREntryPointAttributes_HLSL(ctx, entryPointLayout); + break; + + case CodeGenTarget::GLSL: + emitIREntryPointAttributes_GLSL(ctx, entryPointLayout); + break; + } + } + + void emitIRSimpleFunc( + EmitContext* ctx, + IRFunc* func) + { + auto resultType = func->getResultType(); + + // Deal with decorations that need + // to be emitted as attributes + auto entryPointLayout = asEntryPoint(func); + if (entryPointLayout) + { + emitIREntryPointAttributes(ctx, entryPointLayout); + } auto name = getIRFuncName(func); @@ -6922,6 +7164,52 @@ emitDeclImpl(decl, nullptr); emit(";\n"); } + RefPtr<Type> unwrapArray(Type* type) + { + Type* t = type; + while( auto arrayType = t->As<ArrayExpressionType>() ) + { + t = arrayType->baseType; + } + return t; + } + + void emitIRStructuredBuffer_GLSL( + EmitContext* ctx, + IRGlobalVar* varDecl, + HLSLStructuredBufferTypeBase* structuredBufferType) + { + // Shader storage buffer is an OpenGL 430 feature + // + // TODO: we should require either the extension or the version... + requireGLSLVersion(430); + + emit("layout(std430) buffer "); + + // Generate a dummy name for the block + emit("_S"); + Emit(ctx->shared->uniqueIDCounter++); + + emit(" {\n"); + + + auto elementType = structuredBufferType->getElementType(); + emitIRType(ctx, elementType, getIRName(varDecl) + "[]"); + emit(";\n"); + + emit("}"); + + // TODO: we need to consider the case where the type of the variable is + // an *array* of structured buffers, in which case we need to declare + // the block as an array too. + // + // The main challenge here is that then the block will have a name, + // and also the field inside the block will have a name, so that when + // the user had written `a[i][j]` we now need to emit `a[i].someName[j]`. + + emit(";\n"); + } + void emitIRGlobalVar( EmitContext* ctx, IRGlobalVar* varDecl) @@ -6955,6 +7243,45 @@ emitDeclImpl(decl, nullptr); return; } + if(getTarget(ctx) == CodeGenTarget::GLSL) + { + // When outputting GLSL, we need to transform any declaration of + // a `*StructuredBuffer<T>` into an ordinary `buffer` declaration. + if( auto structuredBufferType = unwrapArray(varType)->As<HLSLStructuredBufferTypeBase>() ) + { + emitIRStructuredBuffer_GLSL( + ctx, + varDecl, + structuredBufferType); + return; + } + + // 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>()) + { + 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; + } + } + } + } + } + // Need to emit appropriate modifiers here. auto layout = getVarLayout(ctx, varDecl); |
