[pixel shader fail(sm<6)]
// Overlapping register(cX) reservations are not allowed except on SM6, where they are aliased.
// On SM1 this gives hr 0x88760b59.
float a : register(c0);
float b : register(c0);

float4 main() : sv_target
{
    return a + b;
}


[pixel shader]
// Overlapping reservations when both variables are unused.
float4 a : register(c3);
float4 b : register(c3);

float4 main() : sv_target
{
    return 42;
}

[pixel shader fail(sm>=4 & sm<6)]
// Overlapping reservations when only one variable is used.
float4 a : register(c3);
float4 b : register(c3);

float4 main() : sv_target
{
    return b;
}


[pixel shader fail(sm>=4 & sm<6)]
// Overlapping reservations when both variables are used, but their bind_count (used size) doesn't
// cause an overlap.
float4 a[2] : register(c3); // bind count: 1
float4 b : register(c4);

float4 main() : sv_target
{
    return a[0] + b;
}


[pixel shader]
// It is not required to provide a register(cX) for all elements in the $Globals buffer.
float4 a; // will get register(c1)
float4 b : register(c0);

float4 main() : sv_target
{
    return float4(a.xw, b.yz);
}

[test]
uniform 0 float4 0.1 0.2 0.3 0.4
uniform 4 float4 1.1 1.2 1.3 1.4
draw quad
probe (0, 0) rgba (1.1, 1.4, 0.2, 0.3)


[pixel shader]
float4 a[3]; // will get register(c3)
float4 b[2] : register(c1);

float4 main() : sv_target
{
    return float4(a[1].xy, b[0].zw);
}

[test]
uniform 0 float4 0.1 0.2 0.3 0.4
uniform 4 float4 1.1 1.2 1.3 1.4
uniform 8 float4 2.1 2.2 2.3 2.4
uniform 12 float4 3.1 3.2 3.3 3.4
uniform 16 float4 4.1 4.2 4.3 4.4
draw quad
probe (0, 0) rgba (4.1, 4.2, 1.3, 1.4)


[require]
shader model < 4.0

[pixel shader]
float a : register(c2);
float b; // will get register c0 in SM1

float4 main() : sv_target
{
    return float4(a, b, 0.0, 0.0);
}

[test]
uniform 0 float4 0.1 0.2 0.3 0.4
uniform 4 float4 1.1 1.2 1.3 1.4
uniform 8 float4 2.1 2.2 2.3 2.4
uniform 12 float4 3.1 3.2 3.3 3.4
draw quad
probe (0, 0) rgba (2.1, 0.1, 0.0, 0.0)


[require]
shader model >= 4.0

[pixel shader]
float a : register(c2);
float b; // will get offset equivalent to c2.y in SM4 and SM6

float4 main() : sv_target
{
    return float4(a, b, 0.0, 0.0);
}

[test]
uniform 0 float4 0.1 0.2 0.3 0.4
uniform 4 float4 1.1 1.2 1.3 1.4
uniform 8 float4 2.1 2.2 2.3 2.4
uniform 12 float4 3.1 3.2 3.3 3.4
draw quad
probe (0, 0) rgba (2.1, 2.2, 0.0, 0.0)


[require]
shader model >= 6.0

[pixel shader]
// Variables with overlapping register(cX) reservations are aliased in SM6.
float2 a : register(c2);
float3 b : register(c2);

float4 main() : sv_target
{
    return float4(a, b.yz);
}

[test]
uniform 0 float4 0.1 0.2 0.3 0.4
uniform 4 float4 1.1 1.2 1.3 1.4
uniform 8 float4 2.1 2.2 2.3 2.4
draw quad
probe (0, 0) rgba (2.1, 2.2, 2.2, 2.3)


% Results differ between SM1 and SM4 because in the latter variables can share the same register,
% using different writemasks.
[require]
shader model < 4.0

[pixel shader]
struct
{
    float2 a;
    float b;
} apple : register(c2);

float4 main() : sv_target
{
    return float4(apple.a, apple.b, 0);
}

[test]
uniform 0 float4 0.1 0.2 0.3 0.4
uniform 4 float4 1.1 1.2 1.3 1.4
uniform 8 float4 2.1 2.2 2.3 2.4
uniform 12 float4 3.1 3.2 3.3 3.4
draw quad
probe (0, 0) rgba (2.1, 2.2, 3.1, 0.0)


[require]
shader model >= 4.0

[pixel shader]
struct
{
    float2 a;
    float b;
} apple : register(c2);

float4 main() : sv_target
{
    return float4(apple.a, apple.b, 0);
}

[test]
uniform 0 float4 0.1 0.2 0.3 0.4
uniform 4 float4 1.1 1.2 1.3 1.4
uniform 8 float4 2.1 2.2 2.3 2.4
uniform 12 float4 3.1 3.2 3.3 3.4
draw quad
probe (0, 0) rgba (2.1, 2.2, 2.3, 0.0)


[pixel shader]
// On SM4, register(cX) has no effect unless in the $Globals buffer.
cbuffer extra
{
    float a : register(c1);
};

float4 main() : sv_target
{
    return a;
}

[test]
uniform 0 float 100
uniform 4 float 101
draw quad
probe (0, 0) rgba (100, 100, 100, 100)


[pixel shader fail(sm>=6)]
// On SM4 register(cX) has no effect unless in the $Globals buffer.
float4 main(uniform float a : register(c1)) : sv_target
{
    return a;
}

[test]
uniform 0 float 100
uniform 4 float 101
draw quad
probe (0, 0) rgba (100, 100, 100, 100)

[pixel shader]
cbuffer c
{
    float a : packoffset(c1);
    float b : packoffset(c2) : register(c1);
    // ^ register(c1) ignored for cbuffer that is not $Globals.
}

float4 main() : sv_target
{
    return float4(a, b, 0, 0);
}

[test]
uniform 0 float 200
uniform 4 float 201
uniform 8 float 202
draw quad
probe (0,0) rgba (201.0, 202.0, 0.0, 0.0)

[pixel shader]
cbuffer c
{
    float a : packoffset(c1) : packoffset(c2);
}

float4 main() : sv_target
{
    return float4(a, 0, 0, 0);
}

[test]
uniform 0 float 201
uniform 4 float 202
uniform 8 float 203
draw quad
probe (0,0) rgba (203.0, 0.0, 0.0, 0.0)

[pixel shader fail(sm<4)]
int k : register(i0); // register(cX) is also required.

float4 main() : sv_target
{
    return k;
}


[require]
% All shader models.

% In SM1, most variables are needed in the "c" register group, for float operations.
% If a variable is needed in the "c" register group, register() reservations in other groups can be
% provided only if a register(cX) reservation is also provided.

[pixel shader fail(sm<4) todo(sm<4)]
int k : register(i0);
// ^^ register(cX) is also required in SM1.

float4 main() : sv_target
{
    return k;
}

[pixel shader todo]
int k : register(i0) : register(c1);
// Shader compiles because a "c" register reservation is provided for "k".

float4 main() : sv_target
{
    return k;
}


[require]
shader model >= 3.0
% model 2.0 doesn't support unrollable loops.

[pixel shader todo(sm<4)]
int k : register(i0);
// ^^ register(cX) is not required since "k" is just needed in the "i" register group.

float4 main() : sv_target
{
    float f = 0;

    for (int i = 0; i < k; ++i)
        f += i;
    return f;
}


[pixel shader todo]
int k : register(c0) : register(b0);
// ^^ unlike the "c" register group, a reservation is not required for the "i" group, even though "k" is needed on it.

float4 main() : sv_target
{
    float f = 0;

    for (int i = 0; i < k; ++i)
        f += i;
    return f;
}

% Expressions as offsets.
[require]
% All shader models.

[pixel shader]
// no offset at all, implicitly c0.
float a : register (c);

float4 main() : sv_target
{
    return a;
}

[test]
uniform 0 float 1.0
draw quad
probe (0, 0) rgba (1.0, 1.0, 1.0, 1.0)

[pixel shader]
// Numeric expr, no offset in the identifier. DXC ignores this.
float a : register (c[1 + 1 * 2 * 0]);

float4 main() : sv_target
{
    return a;
}

[test]
uniform 0 float 1.0
uniform 4 float 2.0
draw quad
if(sm<6) probe (0, 0) rgba (2.0, 2.0, 2.0, 2.0)
if(sm>=6) probe (0, 0) rgba(1.0, 1.0, 1.0, 1.0)

[pixel shader]
// Numeric expr. DXC also ignores this.
float a : register (c0[1 + 1 * 2 * 0]);

float4 main() : sv_target
{
    return a;
}

[test]
uniform 0 float 0.0
uniform 4 float 1.0
draw quad
if(sm<6) probe (0, 0) rgba (1.0, 1.0, 1.0, 1.0)
if(sm>=6) probe (0, 0) rgba (0.0, 0.0, 0.0, 0.0)

[pixel shader]
// Float offsets truncate.
float a : register (c0[0.6 + 0.6]);

float4 main() : sv_target
{
    return a;
}

[test]
uniform 0 float 0.0
uniform 4 float 1.0
draw quad
if(sm<6) probe (0, 0) rgba (1.0, 1.0, 1.0, 1.0)
if(sm>=6) probe (0, 0) rgba (0.0, 0.0, 0.0, 0.0)

[pixel shader]
// Booleans are interpreted as integers in the usual way.
float a : register (c0[true + false * true]);

float4 main() : sv_target
{
    return a;
}

[test]
uniform 0 float 0.0
uniform 4 float 1.0
draw quad
if(sm<6) probe (0, 0) rgba (1.0, 1.0, 1.0, 1.0)
if(sm>=6) probe (0, 0) rgba (0.0, 0.0, 0.0, 0.0)

[pixel shader fail(sm>=6)]
// Negative offsets. DXC fails to compile this.
float a : register (c2[-1]);

float4 main() : sv_target
{
    return a;
}

[test]
uniform 4 float 1.0
draw quad
probe (0, 0) rgba (1.0, 1.0, 1.0, 1.0)

% Weird FXC behavior.
% SM4 accepts anything for 'b' reservations and discards it silently for global numeric variables.

[pixel shader fail(sm<4 | sm>=6)]
float a : register(banana);

float4 main() : sv_target
{
    return a;
}

[test]
uniform 0 float 1.0
draw quad
probe (0, 0) rgba(1.0, 1.0, 1.0, 1.0)

% Testing other reservation types. This is a parse failure, i.e "X3530: register sa not valid"

[pixel shader fail]

sampler s : register(samply);

float4 main() : sv_target
{
    return tex2D(s, float2(0, 0));
}

% This seems to parse fine, but fails with a different error message: "X3530: sampler requires an 's' or 't' register".
% Resource types probably have extra validation.

[pixel shader fail]

sampler s : register(banana);

float4 main() : sv_target
{
    return tex2D(s, float2(0, 0));
}

% Trailing characters after the reservation index are okay in SM < 6, except for 'b' reservations

[pixel shader fail(sm>=6)]

float a : register(c1manymanyletters);

float4 main() : sv_target
{
    return a;
}

[test]
uniform 0 float 0.0
uniform 4 float 2.0
draw quad
probe (0, 0) rgba(2.0, 2.0, 2.0, 2.0)

[require]
shader model >= 4.0

[pixel shader fail]

cbuffer buf : register(b0manymanyletters)
{
    float a;
}

float4 main() : sv_target
{
    return a;
}

% SM4 fails, but not during parsing: it tries to reserve slot 4294967295 (i.e UINT_MAX) for the constant buffer.
% It'll attempt to reserve the same slot even if an offset is passed in brackets, which suggests it uses -1
% as a "parsing failure" flag.

% DXC fails during parsing.

[pixel shader fail]
cbuffer buf : register(banana)
{
    float a;
}

float4 main() : sv_target
{
    return a;
}

% Some versions of fxc's SM5.1 completely ignore bracket exprs for samplers and textures.
% This was fixed (?) in later versions.

[sampler 0]
filter linear linear linear
address clamp clamp clamp

[sampler 1]
filter point point point
address clamp clamp clamp

[srv 0]
size (2d, 1, 2)
0.0 0.0 0.0 0.0     1.0 1.0 1.0 1.0

[srv 1]
size (2d, 1, 2)
1.0 1.0 1.0 1.0     2.0 2.0 2.0 2.0

[require]
shader model >= 4.0

[pixel shader]
Texture2D tex : register(t[1]);
sampler sam : register(s[1]);

float4 main() : sv_target
{
    return tex.Sample(sam, float2(0, 0.5));
}

[test]
todo(msl) draw quad
if(sm<6) probe (0, 0) rgba(2.0, 2.0, 2.0, 2.0)
if(sm>=6) probe (0, 0) rgba(0.5, 0.5, 0.5, 0.5)

% cbuffer reservation limits.
[pixel shader]
cbuffer buf0 : register(b0)
{
    float a;
};

cbuffer buf1 : register(b1)
{
    float b;
};

cbuffer buf2 : register(b2)
{
    float c;
};

cbuffer buf3 : register(b3)
{
    float d;
};

cbuffer buf4 : register(b4)
{
    float e;
};

cbuffer buf5 : register(b5)
{
    float f;
};

cbuffer buf6 : register(b6)
{
    float g;
};

cbuffer buf7 : register(b7)
{
    float h;
};

cbuffer buf8 : register(b8)
{
    float i;
};

cbuffer buf9 : register(b9)
{
    float j;
};

cbuffer buf10 : register(b10)
{
    float k;
};

cbuffer buf11 : register(b11)
{
    float l;
};

cbuffer buf12 : register(b12)
{
    float m;
};

cbuffer buf13 : register(b13)
{
    float n;
};

float4 main() : sv_target
{
    return a * b * c * d * e * f * g * h * i * j * k * l * m * n;
}

[pixel shader fail(sm>=6)]
// $Globals and $Params count towards the 14 cbuffer limit.
float glob;

cbuffer buf0 : register(b0)
{
    float a;
};

cbuffer buf1 : register(b1)
{
    float b;
};

cbuffer buf2 : register(b2)
{
    float c;
};

cbuffer buf3 : register(b3)
{
    float d;
};

cbuffer buf4 : register(b4)
{
    float e;
};

cbuffer buf5 : register(b5)
{
    float f;
};

cbuffer buf6 : register(b6)
{
    float g;
};

cbuffer buf7 : register(b7)
{
    float h;
};

cbuffer buf8 : register(b8)
{
    float i;
};

cbuffer buf9 : register(b9)
{
    float j;
};

cbuffer buf10 : register(b10)
{
    float k;
};

cbuffer buf11 : register(b11)
{
    float l;
};

float4 main(uniform float param) : sv_target
{
    return glob * param * a * b * c * d * e * f * g * h * i * j * k * l;
}

[pixel shader fail]
float glob;

cbuffer buf0 : register(b0)
{
    float a;
};

cbuffer buf1 : register(b1)
{
    float b;
};

cbuffer buf2 : register(b2)
{
    float c;
};

cbuffer buf3 : register(b3)
{
    float d;
};

cbuffer buf4 : register(b4)
{
    float e;
};

cbuffer buf5 : register(b5)
{
    float f;
};

cbuffer buf6 : register(b6)
{
    float g;
};

cbuffer buf7 : register(b7)
{
    float h;
};

cbuffer buf8 : register(b8)
{
    float i;
};

cbuffer buf9 : register(b9)
{
    float j;
};

cbuffer buf10 : register(b10)
{
    float k;
};

cbuffer buf11 : register(b11)
{
    float l;
};

cbuffer buf12 : register(b12)
{
    float m;
};

float4 main(uniform float param) : sv_target
{
    return glob * param * a * b * c * d * e * f * g * h * i * j * k * l * m;
}

[pixel shader fail]
// Unused cbuffers still reserve their slot, and count towards the limit.
float glob;

cbuffer buf0 : register(b0)
{
    float a;
};

cbuffer buf1 : register(b1)
{
    float b;
};

cbuffer buf2 : register(b2)
{
    float c;
};

cbuffer buf3 : register(b3)
{
    float d;
};

cbuffer buf4 : register(b4)
{
    float e;
};

cbuffer buf5 : register(b5)
{
    float f;
};

cbuffer buf6 : register(b6)
{
    float g;
};

cbuffer buf7 : register(b7)
{
    float h;
};

cbuffer buf8 : register(b8)
{
    float i;
};

cbuffer buf9 : register(b9)
{
    float j;
};

cbuffer buf10 : register(b10)
{
    float k;
};

cbuffer buf11 : register(b11)
{
    float l;
};

cbuffer buf12 : register(b12)
{
    float m;
};

float4 main(uniform float param) : sv_target
{
    return glob * param * a * b * c * d * e * f * g * h * i * j * k * l;
}

[pixel shader]
// Multiple cbuffers can share the same reservation if only one of them is actually used.

cbuffer buf0 : register(b0)
{
    float a;
};

cbuffer buf1 : register(b0)
{
    float b;
};

float4 other_main() : sv_target
{
    return a * a;
}

float4 main() : sv_target
{
    return b;
}

[require]
shader model >= 5.1

[pixel shader fail(sm>=6)]
// 5.1 and up have unlimited CBV slots.
float glob;

cbuffer buf0 : register(b0)
{
    float a;
};

cbuffer buf1 : register(b1)
{
    float b;
};

cbuffer buf2 : register(b2)
{
    float c;
};

cbuffer buf3 : register(b3)
{
    float d;
};

cbuffer buf4 : register(b4)
{
    float e;
};

cbuffer buf5 : register(b5)
{
    float f;
};

cbuffer buf6 : register(b6)
{
    float g;
};

cbuffer buf7 : register(b7)
{
    float h;
};

cbuffer buf8 : register(b8)
{
    float i;
};

cbuffer buf9 : register(b9)
{
    float j;
};

cbuffer buf10 : register(b10)
{
    float k;
};

cbuffer buf11 : register(b11)
{
    float l;
};

cbuffer buf12 : register(b12)
{
    float m;
};

float4 main(uniform float param) : sv_target
{
    return glob * param * a * b * c * d * e * f * g * h * i * j * k * l * m;
}

[pixel shader]
// SM6 doesn't support uniform parameters (why??)
float glob;

cbuffer buf0 : register(b0)
{
    float a;
};

cbuffer buf1 : register(b1)
{
    float b;
};

cbuffer buf2 : register(b2)
{
    float c;
};

cbuffer buf3 : register(b3)
{
    float d;
};

cbuffer buf4 : register(b4)
{
    float e;
};

cbuffer buf5 : register(b5)
{
    float f;
};

cbuffer buf6 : register(b6)
{
    float g;
};

cbuffer buf7 : register(b7)
{
    float h;
};

cbuffer buf8 : register(b8)
{
    float i;
};

cbuffer buf9 : register(b9)
{
    float j;
};

cbuffer buf10 : register(b10)
{
    float k;
};

cbuffer buf11 : register(b11)
{
    float l;
};

cbuffer buf12 : register(b12)
{
    float m;
};

cbuffer buf13 : register(b13)
{
    float n;
};

float4 main() : sv_target
{
    return glob * a * b * c * d * e * f * g * h * i * j * k * l * m * n;
}
