diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | source/slang/lower.cpp | 151 | ||||
| -rw-r--r-- | tests/render/unused-discard.hlsl | 151 | ||||
| -rw-r--r-- | tests/render/unused-discard.slang | 27 |
4 files changed, 316 insertions, 14 deletions
diff --git a/.gitignore b/.gitignore index e62d06013..2e654c7bb 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ intermediate/ !*.slang.*.expected *.expected.png *.actual.png +tests/render/*.expected # files generated by other shader compilers *.spv diff --git a/source/slang/lower.cpp b/source/slang/lower.cpp index 9f117106b..d77e573d4 100644 --- a/source/slang/lower.cpp +++ b/source/slang/lower.cpp @@ -1299,17 +1299,20 @@ struct LoweringVisitor RefPtr<ImportDecl> visitImportDecl(ImportDecl* decl) { - // No need to translate things here if we are - // in "full" mode, because we will selectively - // translate the imported declarations at their - // use sites(s). - if (!shared->isRewrite) - return nullptr; - - for (auto dd : decl->importedModuleDecl->Members) - { - translateDeclRef(dd); - } + // We could unconditionally output the declarations in the + // imported code, but this could cause problems if any + // of those declarations used capabilities not allowed + // by the target pipeline stage (e.g., `discard` is + // an error in a GLSL vertex shader file, even if + // it is in a function that never gets called). + // + // As a result, we just ignore the `import` step, + // and allow declarations to be pulled in by + // their use sites. + // + // If this proves to be a problem, we will need + // a pass that resolves which declarations in imported + // modules are "valid" for the chosen target stage. // Don't actually include a representation of // the import declaration in the output @@ -1528,6 +1531,14 @@ struct LoweringVisitor VaryingParameterArraySpec* arraySpecs = nullptr; }; + RefPtr<ExpressionSyntaxNode> createGLSLBuiltinRef( + char const* name) + { + RefPtr<VarExpressionSyntaxNode> globalVarRef = new VarExpressionSyntaxNode(); + globalVarRef->name = name; + return globalVarRef; + } + void lowerSimpleShaderParameterToGLSLGlobal( VaryingParameterInfo const& info, @@ -1567,9 +1578,121 @@ struct LoweringVisitor } else if (ns == "sv_position") { - RefPtr<VarExpressionSyntaxNode> globalVarRef = new VarExpressionSyntaxNode(); - globalVarRef->name = "gl_Position"; - globalVarExpr = globalVarRef; + if (info.direction == VaryingParameterDirection::Input) + { + globalVarExpr = createGLSLBuiltinRef("gl_FragCoord"); + } + else + { + globalVarExpr = createGLSLBuiltinRef("gl_Position"); + } + } + else if (ns == "sv_clipdistance") + { + globalVarExpr = createGLSLBuiltinRef("gl_ClipDistance"); + } + else if (ns == "sv_culldistance") + { + // TODO: ARB_cull_distance + globalVarExpr = createGLSLBuiltinRef("gl_CullDistance"); + } + else if (ns == "sv_coverage") + { + if (info.direction == VaryingParameterDirection::Input) + { + globalVarExpr = createGLSLBuiltinRef("gl_SampleMaskIn"); + } + else + { + globalVarExpr = createGLSLBuiltinRef("gl_SampleMask"); + } + } + else if (ns == "sv_depth") + { + globalVarExpr = createGLSLBuiltinRef("gl_FragDepth"); + } + else if (ns == "sv_depthgreaterequal") + { + // TODO: layout(depth_greater) out float gl_FragDepth; + globalVarExpr = createGLSLBuiltinRef("gl_FragDepth"); + } + else if (ns == "sv_depthlessequal") + { + // TODO: layout(depth_less) out float gl_FragDepth; + globalVarExpr = createGLSLBuiltinRef("gl_FragDepth"); + } + else if (ns == "sv_dispatchthreadid") + { + globalVarExpr = createGLSLBuiltinRef("gl_GlobalInvocationID"); + } + else if (ns == "sv_domainlocation") + { + globalVarExpr = createGLSLBuiltinRef("gl_TessCoord"); + } + else if (ns == "sv_groupid") + { + globalVarExpr = createGLSLBuiltinRef("gl_WorkGroupID"); + } + else if (ns == "sv_groupindex") + { + globalVarExpr = createGLSLBuiltinRef("gl_LocationInvocationIndex"); + } + else if (ns == "sv_groupthreadid") + { + globalVarExpr = createGLSLBuiltinRef("gl_LocalInvocationID"); + } + else if (ns == "sv_gsinstanceid") + { + globalVarExpr = createGLSLBuiltinRef("gl_InvocationID"); + } + else if (ns == "sv_insidetessfactor") + { + globalVarExpr = createGLSLBuiltinRef("gl_TessLevelInner"); + } + else if (ns == "sv_instanceid") + { + globalVarExpr = createGLSLBuiltinRef("gl_InstanceIndex"); + } + else if (ns == "sv_isfrontface") + { + globalVarExpr = createGLSLBuiltinRef("gl_FrontFacing"); + } + else if (ns == "sv_outputcontrolpointid") + { + globalVarExpr = createGLSLBuiltinRef("gl_InvocationID"); + } + else if (ns == "sv_outputcontrolpointid") + { + globalVarExpr = createGLSLBuiltinRef("gl_InvocationID"); + } + else if (ns == "sv_primitiveid") + { + globalVarExpr = createGLSLBuiltinRef("gl_PrimitiveID"); + } + else if (ns == "sv_rendertargetarrayindex") + { + globalVarExpr = createGLSLBuiltinRef("gl_Layer"); + } + else if (ns == "sv_sampleindex") + { + globalVarExpr = createGLSLBuiltinRef("gl_SampleID"); + } + else if (ns == "sv_stencilref") + { + // TODO: ARB_shader_stencil_export + globalVarExpr = createGLSLBuiltinRef("gl_SampleID"); + } + else if (ns == "sv_tessfactor") + { + globalVarExpr = createGLSLBuiltinRef("gl_TessLevelOuter"); + } + else if (ns == "sv_vertexid") + { + globalVarExpr = createGLSLBuiltinRef("gl_VertexIndex"); + } + else if (ns == "sv_viewportarrayindex") + { + globalVarExpr = createGLSLBuiltinRef("gl_ViewportIndex"); } else { diff --git a/tests/render/unused-discard.hlsl b/tests/render/unused-discard.hlsl new file mode 100644 index 000000000..dad2f78e3 --- /dev/null +++ b/tests/render/unused-discard.hlsl @@ -0,0 +1,151 @@ +//TEST(smoke,render):COMPARE_HLSL_GLSL_RENDER: + +// This is a basic test case for cross-compilation behavior. +// +// We will define distinct HLSL and GLSL entry points, +// but the two will share a dependency on a file of +// pure Spire code that provides the actual shading logic. + + +// Pull in Spire code depdendency using extended syntax: +__import unused_discard; + +#if defined(__HLSL__) + +cbuffer Uniforms +{ + float4x4 modelViewProjection; +}; + +struct AssembledVertex +{ + float3 position; + float3 color; +}; + +struct CoarseVertex +{ + float3 color; +}; + +struct Fragment +{ + float4 color; +}; + +// Vertex Shader + +struct VertexStageInput +{ + AssembledVertex assembledVertex : A; +}; + +struct VertexStageOutput +{ + CoarseVertex coarseVertex : CoarseVertex; + float4 sv_position : SV_Position; +}; + +VertexStageOutput vertexMain(VertexStageInput input) +{ + VertexStageOutput output; + + float3 position = input.assembledVertex.position; + float3 color = input.assembledVertex.color; + + output.coarseVertex.color = color; + output.sv_position = mul(modelViewProjection, float4(position, 1.0)); + + return output; + +} + +// Fragment Shader + +struct FragmentStageInput +{ + CoarseVertex coarseVertex : CoarseVertex; +}; + +struct FragmentStageOutput +{ + Fragment fragment : SV_Target; +}; + +FragmentStageOutput fragmentMain(FragmentStageInput input) +{ + FragmentStageOutput output; + + float3 color = input.coarseVertex.color; + + color = transformColor(color); + + doConditionalDiscard(color); + + output.fragment.color = float4(color, 1.0); + + return output; +} + +#elif defined(__GLSL__) + +#version 420 + +uniform Uniforms +{ + mat4x4 modelViewProjection; +}; + +#define ASSEMBLED_VERTEX(QUAL) \ + /* */ + +#define V2F(QUAL) \ + layout(location = 0) QUAL vec3 coarse_color; \ + /* */ + +// Vertex Shader + +#ifdef __GLSL_VERTEX__ + +layout(location = 0) +in vec3 assembled_position; + +layout(location = 1) +in vec3 assembled_color; + +V2F(out) + +void main() +{ + vec3 position = assembled_position; + vec3 color = assembled_color; + + coarse_color = color; +// gl_Position = modelViewProjection * vec4(position, 1.0); + gl_Position = vec4(position, 1.0) * modelViewProjection; +} + +#endif + +#ifdef __GLSL_FRAGMENT__ + +V2F(in) + +layout(location = 0) +out vec4 fragment_color; + +void main() +{ + vec3 color = coarse_color; + + color = transformColor(color); + + doConditionalDiscard(color); + + fragment_color = vec4(color, 1.0); +} + + +#endif + +#endif diff --git a/tests/render/unused-discard.slang b/tests/render/unused-discard.slang new file mode 100644 index 000000000..034735840 --- /dev/null +++ b/tests/render/unused-discard.slang @@ -0,0 +1,27 @@ +//TEST_IGNORE_FILE: + +// This file implements the "library" code +// that both the HLSL and GLSL shaders share. +// +// This code is written in Slang (more or less +// just HLSL), and will be translated as needed +// for each of the targets. + +float3 transformColor(float3 color) +{ + float3 result; + + result.x = sin(20.0 * (color.x + color.y)); + result.y = saturate(cos(color.z * 30.0)); + result.z = sin(color.x * color.y * color.z * 100.0); + + result = 0.5 * (result + 1); + + return result; +} + +void doConditionalDiscard(float3 color) +{ + if(color.x < 0.5) + discard; +} |
