shader-slang / slang

Making it easier to work with shaders
http://shader-slang.com
MIT License
2.15k stars 184 forks source link

SPIR-V: Some hull shaders fail during emitting #4914

Closed ArielG-NV closed 1 month ago

ArielG-NV commented 2 months ago

Problem:

Repro:

//GLSL: location = 0 //GLSL-NOT: location = 0 //GLSL: location = 1 //GLSL-NOT: location = 1 //GLSL: location = 2

//SPIRV: location 0 //SPIRV-NOT: location 0 //SPIRV: location 1 //SPIRV-NOT: location 1 //SPIRV: location = 2

//SPIRV: location = 0 //HLSL: hullMain

struct HsOut { float2 pos; float2 hm; };

struct HscOut { float EdgeTessFactor[4] : SV_TessFactor; float InsideTessFactor[2] : SV_InsideTessFactor; uint instanceId; };

[domain("quad")] [partitioning("integer")] [outputtopology("triangle_ccw")] [outputcontrolpoints(4)] [patchconstantfunc("constants")] HsOut hullMain() { HsOut o; o.pos = 1; o.hm = 2; return o; }

HscOut constants() { HscOut o; o.instanceId = 123; o.EdgeTessFactor[0] = 1; o.EdgeTessFactor[1] = 2; o.EdgeTessFactor[2] = 3; o.EdgeTessFactor[3] = 4; o.InsideTessFactor[0] = 0.5; o.InsideTessFactor[1] = 0.5; return o; }


Info:
* The failing `kIROp_Param` is likely created during the following code
auto constantOutputType = constantFunc->getResultType();
IRTypeLayout* constantOutputLayout = createPatchConstantFuncResultTypeLayout(builder, constantOutputType);
IRVarLayout::Builder resultVarLayoutBuilder(&builder, constantOutputLayout);
if (auto semanticDecor = constantFunc->findDecoration<IRSemanticDecoration>())
    resultVarLayoutBuilder.setSystemValueSemantic(semanticDecor->getSemanticName(), 0);
csyonghe commented 2 months ago

@ArielG-NV Can you post the IR showing the problematic IRParam?

ArielG-NV commented 2 months ago

(sorry for the late reply, I did not notice a message on this issue)

@csyonghe Method to dump IR:

//#if 0
        dumpIRIfEnabled(codeGenContext, irModule, "PRE GLSL LEGALIZED");
//#endif

        legalizeEntryPointsForGLSL(
            session,
            irModule,
            irEntryPoints,
            codeGenContext,
            glslExtensionTrackerPtr);

//#if 0
            dumpIRIfEnabled(codeGenContext, irModule, "GLSL LEGALIZED");
//#endif
            validateIRModuleIfEnabled(codeGenContext, irModule);
    }

Pre-legalization:

[export("_SV13testGeoShader5HsOut3pos")]
[nameHint("pos")]
let  %pos       : _     = key
[export("_SV13testGeoShader5HsOut2hm")]
[nameHint("hm")]
let  %hm        : _     = key
[export("_ST13testGeoShader5HsOut")]
[nameHint("HsOut")]
struct %HsOut   : Type
{
        field(%pos, Vec(Float, 2 : Int))
        field(%hm, Vec(Float, 2 : Int))
}
...
[readNone]
[keepAlive]
[entryPoint(2 : Int, "hullMain", "testGeoShader")]
[outputControlPoints(4 : Int)]
[outputTopology("triangle_ccw")]
[partioning("integer")]
[domain("quad")]
[patchConstantFunc(%constants)]
[export("_S13testGeoShader8hullMainp0p13testGeoShader5HsOut")]
[nameHint("hullMain")]
[layout(%1)]
func %hullMain  : Func(%HsOut)
{
block %31:
        [nameHint("o")]
        let  %o1        : Ptr(%HsOut)   = var
        let  %32        : Ptr(Vec(Float, 2 : Int))      = get_field_addr(%o1, %pos)
        @ConstExpr let  %33     : Vec(Float, 2 : Int)   = MakeVectorFromScalar(1 : Float)
        store(%32, %33)
        let  %34        : Ptr(Vec(Float, 2 : Int))      = get_field_addr(%o1, %hm)
        @ConstExpr let  %35     : Vec(Float, 2 : Int)   = MakeVectorFromScalar(2 : Float)
        store(%34, %35)
        let  %36        : %HsOut        = load(%o1)
        return_val(%36)
}

Post-legalization:

[layout(%26)]
[nameHint("entryPointParam_hullMain.pos")]
let  %entryPointParamx5FhullMainx5Fpos  : Out(Array(Vec(Float, 2 : Int), 4 : Int))      = global_param
[layout(%23)]
[nameHint("entryPointParam_hullMain.hm")]
let  %entryPointParamx5FhullMainx5Fhm   : Out(Array(Vec(Float, 2 : Int), 4 : Int))      = global_param

[readNone]
[keepAlive]
[entryPoint(2 : Int, "main", "testGeoShader")]
[outputControlPoints(4 : Int)]
[outputTopology("triangle_ccw")]
[partioning("integer")]
[domain("quad")]
[patchConstantFunc(%constants)]
[export("_S13testGeoShader8hullMainp0p13testGeoShader5HsOut")]
[nameHint("hullMain")]
[layout(%28)]
func %hullMain  : Func(Void)
{
block %57:
        let  %58        : Ptr(Vec(Float, 2 : Int))      = getElementPtr(%entryPointParamx5FhullMainx5Fpos, %59)
        let  %60        : Ptr(Vec(Float, 2 : Int))      = getElementPtr(%entryPointParamx5FhullMainx5Fhm, %59)
        loop(%61, %62, %61)

block %61:
        [nameHint("o")]
        let  %o1        : Ptr(%HsOut)   = var
        let  %63        : Ptr(Vec(Float, 2 : Int))      = get_field_addr(%o1, %pos)
        @ConstExpr let  %64     : Vec(Float, 2 : Int)   = MakeVectorFromScalar(1 : Float)
        store(%63, %64)
        let  %65        : Ptr(Vec(Float, 2 : Int))      = get_field_addr(%o1, %hm)
        @ConstExpr let  %66     : Vec(Float, 2 : Int)   = MakeVectorFromScalar(2 : Float)
        store(%65, %66)
        let  %67        : %HsOut        = load(%o1)
        unconditionalBranch(%62, %67)

block %62(
                param %68       : %HsOut):
        unconditionalBranch(%69)

block %69:
        let  %70        : Vec(Float, 2 : Int)   = get_field(%68, %pos)
        store(%58, %70)
        let  %71        : Vec(Float, 2 : Int)   = get_field(%68, %hm)
        store(%60, %71)
        unconditionalBranch(%72)

block %72:
        ControlBarrier
        let  %73        : Bool  = cmpEQ(%74, 0 : Int)
        let  %75        : Ptr(Vec(Float, 2 : Int))      = getElementPtr(%entryPointParamx5FhullMainx5Fpos, 0 : Int)
        let  %76        : Ptr(Vec(Float, 2 : Int))      = getElementPtr(%entryPointParamx5FhullMainx5Fhm, 0 : Int)
        let  %77        : Vec(Float, 2 : Int)   = load(%75)
        let  %78        : Vec(Float, 2 : Int)   = load(%76)
        let  %79        : %HsOut        = makeStruct(%77, %78)
        let  %80        : Ptr(Vec(Float, 2 : Int))      = getElementPtr(%entryPointParamx5FhullMainx5Fpos, 1 : Int)
        let  %81        : Ptr(Vec(Float, 2 : Int))      = getElementPtr(%entryPointParamx5FhullMainx5Fhm, 1 : Int)
        let  %82        : Vec(Float, 2 : Int)   = load(%80)
        let  %83        : Vec(Float, 2 : Int)   = load(%81)
        let  %84        : %HsOut        = makeStruct(%82, %83)
        let  %85        : Ptr(Vec(Float, 2 : Int))      = getElementPtr(%entryPointParamx5FhullMainx5Fpos, 2 : Int)
        let  %86        : Ptr(Vec(Float, 2 : Int))      = getElementPtr(%entryPointParamx5FhullMainx5Fhm, 2 : Int)
        let  %87        : Vec(Float, 2 : Int)   = load(%85)
        let  %88        : Vec(Float, 2 : Int)   = load(%86)
        let  %89        : %HsOut        = makeStruct(%87, %88)
        let  %90        : Ptr(Vec(Float, 2 : Int))      = getElementPtr(%entryPointParamx5FhullMainx5Fpos, 3 : Int)
        let  %91        : Ptr(Vec(Float, 2 : Int))      = getElementPtr(%entryPointParamx5FhullMainx5Fhm, 3 : Int)
        let  %92        : Vec(Float, 2 : Int)   = load(%90)
        let  %93        : Vec(Float, 2 : Int)   = load(%91)
        let  %94        : %HsOut        = makeStruct(%92, %93)
        let  %95        : Array(%HsOut, 4 : Int)        = makeArray(%79, %84, %89, %94)
        ifElse(%73, %96, %97, %97)

block %96:
        call %constants()
        unconditionalBranch(%97)

block %97:
        return_val(void_constant)
}

Post-legalization causes an error due to getElementPtr(%entryPointParamx5FhullMainx5Fpos, %59) being emitted. More specifically, the GlobalParam created is not legalized in later passes and therefore fails in slang-emit-spirv since this is disallowed IR.