Skip to content

Commit 8c87259

Browse files
author
Tim Foley
authored
Implement IR-level translation of system values for GLSL (shader-slang#413)
The approach here isn't ideal. We already have a pass that transforms HLSL varying input/output types into GLSL global variables. This change makes it so that when those inputs/outputs have system-value semantics, we generate a global variable declaration with the appropriate `gl_*` name (leaving the type the same for now). Later, when emitting code, we just skip emitting declarations for declarations with mangled names that start with `gl_*`. A more complete implementation will be needed later on, which handles cases where the translation requires types to be changed (so that conversion code needs to be inserted).
1 parent 1b93da0 commit 8c87259

File tree

3 files changed

+333
-242
lines changed

3 files changed

+333
-242
lines changed

source/slang/emit.cpp

+22-213
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ struct ExtensionUsageTracker
3333
// Record the GLSL extnsions we have already emitted a `#extension` for
3434
HashSet<String> glslExtensionsRequired;
3535
StringBuilder glslExtensionRequireLines;
36+
37+
ProfileVersion profileVersion = ProfileVersion::GLSL_110;
3638
};
3739

3840
void requireGLSLExtension(
@@ -51,6 +53,16 @@ void requireGLSLExtension(
5153
tracker->glslExtensionsRequired.Add(name);
5254
}
5355

56+
void requireGLSLVersionImpl(
57+
ExtensionUsageTracker* tracker,
58+
ProfileVersion version)
59+
{
60+
// Check if this profile is newer
61+
if ((UInt)version > (UInt)tracker->profileVersion)
62+
{
63+
tracker->profileVersion = version;
64+
}
65+
}
5466

5567

5668
// Shared state for an entire emit session
@@ -4503,182 +4515,6 @@ emitDeclImpl(decl, nullptr);
45034515
return name;
45044516
}
45054517

4506-
String getGLSLSystemValueName(
4507-
IRValue* varDecl,
4508-
VarLayout* varLayout)
4509-
{
4510-
auto semanticNameSpelling = varLayout->systemValueSemantic;
4511-
auto semanticName = semanticNameSpelling.ToLower();
4512-
4513-
if(semanticName == "sv_position")
4514-
{
4515-
// TODO: need to pick between `gl_Position` and
4516-
// `gl_FragCoord` based on whether this is an input
4517-
// or an output.
4518-
return "gl_Position";
4519-
}
4520-
else if(semanticName == "sv_target")
4521-
{
4522-
// Note: we do *not* need to generate some kind of `gl_`
4523-
// builtin for fragment-shader outputs: they are just
4524-
// ordinary `out` variables, with ordinary `location`s,
4525-
// as far as GLSL is concerned.
4526-
return "";
4527-
}
4528-
else if(semanticName == "sv_clipdistance")
4529-
{
4530-
// TODO: type conversion is required here.
4531-
return "gl_ClipDistance";
4532-
}
4533-
else if(semanticName == "sv_culldistance")
4534-
{
4535-
requireGLSLExtension("ARB_cull_distance");
4536-
4537-
// TODO: type conversion is required here.
4538-
return "gl_CullDistance";
4539-
}
4540-
else if(semanticName == "sv_coverage")
4541-
{
4542-
// TODO: deal with `gl_SampleMaskIn` when used as an input.
4543-
4544-
// TODO: type conversion is required here.
4545-
return "gl_SampleMask";
4546-
}
4547-
else if(semanticName == "sv_depth")
4548-
{
4549-
return "gl_FragDepth";
4550-
}
4551-
else if(semanticName == "sv_depthgreaterequal")
4552-
{
4553-
// TODO: layout(depth_greater) out float gl_FragDepth;
4554-
return "gl_FragDepth";
4555-
}
4556-
else if(semanticName == "sv_depthlessequal")
4557-
{
4558-
// TODO: layout(depth_greater) out float gl_FragDepth;
4559-
return "gl_FragDepth";
4560-
}
4561-
else if(semanticName == "sv_dispatchthreadid")
4562-
{
4563-
return "gl_GlobalInvocationID";
4564-
}
4565-
else if(semanticName == "sv_domainlocation")
4566-
{
4567-
return "gl_TessCoord";
4568-
}
4569-
else if(semanticName == "sv_groupid")
4570-
{
4571-
return "gl_WorkGroupID";
4572-
}
4573-
else if(semanticName == "sv_groupindex")
4574-
{
4575-
return "gl_LocalInvocationIndex";
4576-
}
4577-
else if(semanticName == "sv_groupthreadid")
4578-
{
4579-
return "gl_LocalInvocationID";
4580-
}
4581-
else if(semanticName == "sv_gsinstanceid")
4582-
{
4583-
return "gl_InvocationID";
4584-
}
4585-
else if(semanticName == "sv_instanceid")
4586-
{
4587-
return "gl_InstanceIndex";
4588-
}
4589-
else if(semanticName == "sv_isfrontface")
4590-
{
4591-
return "gl_FrontFacing";
4592-
}
4593-
else if(semanticName == "sv_outputcontrolpointid")
4594-
{
4595-
return "gl_InvocationID";
4596-
}
4597-
else if(semanticName == "sv_primitiveid")
4598-
{
4599-
return "gl_PrimitiveID";
4600-
}
4601-
else if (semanticName == "sv_rendertargetarrayindex")
4602-
{
4603-
switch (context->shared->entryPoint->profile.GetStage())
4604-
{
4605-
case Stage::Geometry:
4606-
requireGLSLVersion(ProfileVersion::GLSL_150);
4607-
break;
4608-
4609-
case Stage::Fragment:
4610-
requireGLSLVersion(ProfileVersion::GLSL_430);
4611-
break;
4612-
4613-
default:
4614-
requireGLSLVersion(ProfileVersion::GLSL_450);
4615-
requireGLSLExtension("GL_ARB_shader_viewport_layer_array");
4616-
break;
4617-
}
4618-
4619-
return "gl_Layer";
4620-
}
4621-
else if (semanticName == "sv_sampleindex")
4622-
{
4623-
return "gl_SampleID";
4624-
}
4625-
else if (semanticName == "sv_stencilref")
4626-
{
4627-
requireGLSLExtension("ARB_shader_stencil_export");
4628-
return "gl_FragStencilRef";
4629-
}
4630-
else if (semanticName == "sv_tessfactor")
4631-
{
4632-
return "gl_TessLevelOuter";
4633-
}
4634-
else if (semanticName == "sv_vertexid")
4635-
{
4636-
return "gl_VertexIndex";
4637-
}
4638-
else if (semanticName == "sv_viewportarrayindex")
4639-
{
4640-
return "gl_ViewportIndex";
4641-
}
4642-
else if (semanticName == "nv_x_right")
4643-
{
4644-
requireGLSLVersion(ProfileVersion::GLSL_450);
4645-
requireGLSLExtension("GL_NVX_multiview_per_view_attributes");
4646-
4647-
// The actual output in GLSL is:
4648-
//
4649-
// vec4 gl_PositionPerViewNV[];
4650-
//
4651-
// and is meant to support an arbitrary number of views,
4652-
// while the HLSL case just defines a second position
4653-
// output.
4654-
//
4655-
// For now we will hack this by:
4656-
// 1. Mapping an `NV_X_Right` output to `gl_PositionPerViewNV[1]`
4657-
// (that is, just one element of the output array)
4658-
// 2. Adding logic to copy the traditional `gl_Position` output
4659-
// over to `gl_PositionPerViewNV[0]`
4660-
//
4661-
4662-
return "gl_PositionPerViewNV[1]";
4663-
4664-
// shared->requiresCopyGLPositionToPositionPerView = true;
4665-
}
4666-
else if (semanticName == "nv_viewport_mask")
4667-
{
4668-
requireGLSLVersion(ProfileVersion::GLSL_450);
4669-
requireGLSLExtension("GL_NVX_multiview_per_view_attributes");
4670-
4671-
return "gl_ViewportMaskPerViewNV";
4672-
// globalVarExpr = createGLSLBuiltinRef("gl_ViewportMaskPerViewNV",
4673-
// getUnsizedArrayType(getIntType()));
4674-
}
4675-
else
4676-
{
4677-
getSink()->diagnose(varDecl->sourceLoc, Diagnostics::unknownSystemValueSemantic, semanticNameSpelling);
4678-
return semanticName;
4679-
}
4680-
}
4681-
46824518
String getIRName(
46834519
IRValue* inst)
46844520
{
@@ -4695,23 +4531,6 @@ emitDeclImpl(decl, nullptr);
46954531
break;
46964532
}
46974533

4698-
if(getTarget(context) == CodeGenTarget::GLSL)
4699-
{
4700-
if(auto layoutMod = inst->findDecoration<IRLayoutDecoration>())
4701-
{
4702-
auto layout = layoutMod->layout;
4703-
if(auto varLayout = layout.As<VarLayout>())
4704-
{
4705-
if(varLayout->systemValueSemantic.Length() != 0)
4706-
{
4707-
auto translated = getGLSLSystemValueName(inst, varLayout);
4708-
if(translated.Length())
4709-
return translated;
4710-
}
4711-
}
4712-
}
4713-
}
4714-
47154534
if(auto decoration = inst->findDecoration<IRHighLevelDeclDecoration>())
47164535
{
47174536
auto decl = decoration->decl;
@@ -7743,26 +7562,15 @@ emitDeclImpl(decl, nullptr);
77437562
// We want to skip the declaration of any system-value variables
77447563
// when outputting GLSL (well, except in the case where they
77457564
// actually *require* redeclaration...).
7746-
7747-
if(auto layoutMod = varDecl->findDecoration<IRLayoutDecoration>())
7565+
//
7566+
// TODO: can we detect this more robustly?
7567+
if(varDecl->mangledName.StartsWith("gl_"))
77487568
{
7749-
auto layout = layoutMod->layout;
7750-
if(auto varLayout = layout.As<VarLayout>())
7751-
{
7752-
if(varLayout->systemValueSemantic.Length() != 0)
7753-
{
7754-
auto translated = getGLSLSystemValueName(varDecl, varLayout);
7755-
if( translated.Length() )
7756-
{
7757-
// The variable seems to translate to an OpenGL
7758-
// system value, so we will assume that it doesn't
7759-
// need to be declared.
7760-
//
7761-
// TODO: handle case where we *should* declare the variable.
7762-
return;
7763-
}
7764-
}
7765-
}
7569+
// The variable represents an OpenGL system value,
7570+
// so we will assume that it doesn't need to be declared.
7571+
//
7572+
// TODO: handle case where we *should* declare the variable.
7573+
return;
77667574
}
77677575
}
77687576

@@ -8220,7 +8028,8 @@ String emitEntryPoint(
82208028

82218029
specializeIRForEntryPoint(
82228030
irSpecializationState,
8223-
entryPoint);
8031+
entryPoint,
8032+
&sharedContext.extensionUsageTracker);
82248033

82258034
// If the user specified the flag that they want us to dump
82268035
// IR, then do it here, for the target-specific, but

source/slang/ir-insts.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -682,14 +682,17 @@ IRGlobalValue* getSpecializedGlobalValueForDeclRef(
682682
IRSpecializationState* state,
683683
DeclRef<Decl> const& declRef);
684684

685+
struct ExtensionUsageTracker;
686+
685687
// Clone the IR values reachable from the given entry point
686688
// into the IR module assocaited with the specialization state.
687689
// When multiple definitions of a symbol are found, the one
688690
// that is best specialized for the given `targetReq` will be
689691
// used.
690692
void specializeIRForEntryPoint(
691693
IRSpecializationState* state,
692-
EntryPointRequest* entryPointRequest);
694+
EntryPointRequest* entryPointRequest,
695+
ExtensionUsageTracker* extensionUsageTracker);
693696

694697
// Find suitable uses of the `specialize` instruction that
695698
// can be replaced with references to specialized functions.

0 commit comments

Comments
 (0)