% Uppercase register set names
[pixel shader]
cbuffer Constants : register(B1)
{
};
Texture2D tex : register(T1);
float4 foo : register(C0);

float4 main() : sv_target
{
    return foo;
}

[test]
uniform 0 float4 1.0 2.0 3.0 4.0
todo(glsl) draw quad
probe (0, 0) rgba (1.0, 2.0, 3.0, 4.0)

[pixel shader fail(sm>=6)]
// Annotations
cbuffer cb : register(b1) < int i = 1; >
{
    float4 m1;
};

cbuffer cb < int i = 2; >
{
    float4 m2;
};

float4 main() : sv_target
{
    return m1 + m2;
}


[pixel shader]
// Test empty constant buffer.
cbuffer Constants : register(b1)
{
};

float4 foo;

float4 main() : sv_target
{
    return foo;
}

[pixel shader fail(sm>=6)]
// The 'single' modifier is not a keyword. It's meaningful only for fx_5_0.
single cbuffer cb
{
    float4 single;
};

float4 main() : sv_target
{
    return single;
}

[test]
uniform 0 float4 1.0 2.0 3.0 4.0
todo(glsl) draw quad
probe (0, 0) rgba (1.0, 2.0, 3.0, 4.0)

[pixel shader fail(sm>=6)]
// 'single' modifier is usable when there is a variable with the same name
cbuffer cb
{
    float4 single;
};

single cbuffer cb2
{
    float4 var;
};

float4 main() : sv_target
{
    return single;
}

[test]
uniform 0 float4 1.0 2.0 3.0 4.0
todo(glsl) draw quad
probe (0, 0) rgba (1.0, 2.0, 3.0, 4.0)

[pixel shader]
typedef float4 single;
single var;

float4 main() : sv_target
{
    return var;
}

[test]
uniform 0 float4 1.0 2.0 3.0 4.0
todo(glsl) draw quad
probe (0, 0) rgba (1.0, 2.0, 3.0, 4.0)

[pixel shader fail]
typedef float4 single;
single cbuffer cb
{
    float4 var;
};

float4 main() : sv_target
{
    return var;
}

% SM1 buffer offset allocation follows different rules than SM4.
% Those would have to be tested separately.
[require]
shader model >= 4.0


[pixel shader fail]
cbuffer buffer
{
    float4 a : packoffset(c1invalid_extra_chars);
}

float4 main() : sv_target
{
    return 0;
}


% Respect register boundaries
[pixel shader]
cbuffer buffer
{
    float2 a;
    float2 b;
    float2 c;
    float3 d;
}

float4 main() : sv_target
{
    return float4(a.x, b.x, c.x, d.x);
}

[test]
uniform 0 float4 0.0 1.0 2.0 3.0
uniform 4 float4 4.0 5.0 6.0 7.0
uniform 8 float4 8.0 9.0 10.0 11.0
uniform 12 float4 12.0 13.0 14.0 15.0
todo(glsl) draw quad
probe (0, 0) rgba (0.0, 2.0, 4.0, 8.0)


[pixel shader]
cbuffer buffer
{
    float a;
    float b[2];
    float c;
}

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

[test]
uniform 0 float4 0.0 1.0 2.0 3.0
uniform 4 float4 4.0 5.0 6.0 7.0
uniform 8 float4 8.0 9.0 10.0 11.0
todo(glsl) draw quad
probe (0, 0) rgba (0.0, 4.0, 8.0, 9.0)


[pixel shader]
cbuffer buffer
{
    float a;
    struct
    {
        float b;
        float c;
    } p;
    float d;
}

float4 main() : sv_target
{
    return float4(a, p.b, p.c, d);
}

[test]
uniform 0 float4 0.0 1.0 2.0 3.0
uniform 4 float4 4.0 5.0 6.0 7.0
uniform 8 float4 8.0 9.0 10.0 11.0
uniform 12 float4 12.0 13.0 14.0 15.0
todo(glsl) draw quad
probe (0, 0) rgba (0.0, 4.0, 5.0, 6.0)


[pixel shader fail(sm<6)]
// Elements cannot overlap if buffer is used.
cbuffer buffer
{
    float c : packoffset(c0);
    float4 a[2] : packoffset(c1);
    float4 b[2] : packoffset(c2);
}

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

[test]
uniform 0 float4 1.0 0.0 0.0 0.0
uniform 4 float4 2.0 0.0 0.0 0.0
uniform 8 float4 3.0 0.0 0.0 0.0
uniform 12 float4 4.0 0.0 0.0 0.0
todo(sm<6) draw quad
probe (0, 0) rgba (1.0, 3.0, 3.0, 4.0)


[pixel shader]
// Elements can overlap if buffer is not used.
cbuffer buffer
{
    float4 a[2] : packoffset(c1);
    float4 b[2] : packoffset(c2);
}

float4 main() : sv_target
{
    return 0;
}


[pixel shader]
cbuffer buffer
{
    float4 a : packoffset(c1);
    float4 b : packoffset(C2);
}

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

[test]
uniform 0 float4 1.0 2.0 3.0 4.0
uniform 4 float4 5.0 6.0 7.0 8.0
uniform 8 float4 9.0 10.0 11.0 12.0
todo(glsl) draw quad
probe (0, 0) rgba (509, 610, 711, 812)


[pixel shader]
struct apple
{
    float2 a;
    float b;
    float4 c;
};

cbuffer buffer
{
    float4 foo : packoffset(c3);
    struct apple bar : packoffset(c1);
}

float4 main() : sv_target
{
    return 1000 * foo + 100 * float4(bar.a, 0, 0) + 10 * float4(bar.b, 0, 0, 0) + bar.c;
}

[test]
uniform 0 float4 0.0 1.0 2.0 3.0
uniform 4 float4 4.0 5.0 6.0 7.0
uniform 8 float4 8.0 9.0 10.0 11.0
uniform 12 float4 12.0 13.0 14.0 15.0
todo(glsl) draw quad
probe (0, 0) rgba (12468.0, 13509.0, 14010.0, 15011.0)


[pixel shader]
cbuffer buffer
{
    float2 c : packoffset(c0.y);
}

float4 main() : sv_target
{
    return float4(c, c);
}

[test]
uniform 0 float4 1.0 2.0 3.0 4.0
todo(glsl) draw quad
probe (0, 0) rgba (2.0, 3.0, 2.0, 3.0)


[pixel shader fail]
// Elements must respect register boundaries.
cbuffer buffer
{
    float4 c : packoffset(c0.z);
}

float4 main() : sv_target
{
    return 0;
}


[pixel shader fail(sm<6)]
// Matrices must be aligned.
cbuffer buffer
{
    float1x1 m : packoffset(c0.y);
}

float4 main() : sv_target
{
    return 0;
}


[pixel shader fail(sm<6)]
// Arrays must be aligned.
cbuffer buffer
{
    float a[1] : packoffset(c0.y);
}

float4 main() : sv_target
{
    return 0;
}


[pixel shader fail(sm<6)]
// Structs must be aligned.
struct apple
{
    float p;
};

cbuffer buffer
{
    struct apple a : packoffset(c0.y);
}

float4 main() : sv_target
{
    return 0;
}


[pixel shader fail]
// Invalid offset on unused buffer.
cbuffer buffer
{
    float3 a : packoffset(c0.z);
}

float4 main() : sv_target
{
    return 0;
}


[pixel shader fail]
// Invalid offset on unused variable.
cbuffer buffer
{
    float a : packoffset(c0);
    float3 b : packoffset(c0.z);
}

float4 main() : sv_target
{
    return a;
}


[pixel shader]
cbuffer buffer
{
    float4 a : packoffset(c1);
    float1 b : packoffset(c0);
    float1 c : packoffset(c0.y);
}

float4 main() : sv_target
{
    return 100 * a + 10 * b + c;
}

[test]
uniform 0 float 1.0
uniform 1 float 2.0
uniform 4 float4 5.0 6.0 7.0 8.0
todo(glsl) draw quad
probe (0, 0) rgba (512.0, 612.0, 712.0, 812.0)


[pixel shader fail(sm<6)]
// packoffset cannot be used unless all elements use it.
cbuffer buffer
{
    float4 a : packoffset(c0);
    float4 b;
}

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


[pixel shader]
cbuffer buffer
{
    float2 c : packoffset(c0.b);
}

float4 main() : sv_target
{
    return float4(c, c);
}

[test]
uniform 0 float4 1.0 2.0 3.0 4.0
todo(glsl) draw quad
probe (0, 0) rgba (3.0, 4.0, 3.0, 4.0)


[pixel shader fail]
cbuffer buffer
{
    float2 c : packoffset(c0.xy);
}

float4 main() : sv_target
{
    return 0;
}


[pixel shader fail]
cbuffer buffer
{
    float4x4 mat : packoffset(c0._m00);
}

float4 main() : sv_target
{
    return 0;
}


[pixel shader fail]
cbuffer buffer
{
    float4 a : packoffset(c0._m00);
}

float4 main() : sv_target
{
    return 0;
}


[pixel shader fail]
cbuffer buffer
{
    float2 c : packoffset(c0.xz);
}

float4 main() : sv_target
{
    return 0;
}


% packoffset cannot be used outside a constant buffer.
[pixel shader fail]
float4 a : packoffset(c0);

float4 main() : sv_target
{
    return 0;
}

[pixel shader fail]
float4 foo(float4 a : packoffset(c0))
{
    return a;
}

float4 main() : sv_target
{
    return 0;
}

[pixel shader fail]
float4 foo(float4 a) : packoffset(c0)
{
    return a;
}

float4 main() : sv_target
{
    return 0;
}

[pixel shader fail]
struct apple
{
    float4 a : packoffset(c0);
};

cbuffer buffer
{
    struct apple a;
}

float4 main() : sv_target
{
    return 0;
}

[pixel shader fail]
cbuffer buffer
{
    struct
    {
        float4 a : packoffset(c0);
    } s;
}

float4 main() : sv_target
{
    return 0;
}


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

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


[pixel shader]
// Resources are allowed inside constant buffers but they behave as regular resources.
cbuffer buffer
{
    float4 a;
    Texture2D tex;
    sampler sam;
    float4 b;
}

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

[test]
uniform 0 float4 1.0 0.0 0.0 0.0
uniform 4 float4 0.0 2.0 0.0 0.0
uniform 8 float4 0.0 0.0 3.0 0.0
todo(glsl) draw quad
probe (0, 0) rgba (1.0, 2.0, 0.0, 4.0)


% packoffset() cannot be used to specify other types of registers
[pixel shader fail]
cbuffer buffer
{
    sampler sam : packoffset(s0);
}

float4 main() : sv_target
{
    return 0;
}

[pixel shader fail]
cbuffer buffer
{
    Texture2D tex : packoffset(t0);
}

float4 main() : sv_target
{
    return 0;
}


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

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


[pixel shader]
// packoffset() can be used in Textures, doesn't change the allocated t register.
cbuffer buffer
{
    Texture2D tex : packoffset(c1);
}

float4 main() : sv_target
{
    return tex.Load(int3(0, 0, 0));
}

[test]
todo(glsl) draw quad
probe (0, 0) rgba (1.0, 1.0, 1.0, 1.0)


% Samplers cannot have packoffset(), unless register() is also specified, or they are not used.
% Note: In SM1 the rules are different: packoffset() is allowed for samplers, but they cannot be
% used together with other numeric fields, which seems like a bug.
[pixel shader fail(sm<6) todo]
Texture2D tex;

cbuffer buffer
{
    sampler sam : packoffset(c1);
}

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

[pixel shader todo]
Texture2D tex;

cbuffer buffer
{
    sampler sam : packoffset(c1) : register(s0);
}

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

[pixel shader]
cbuffer buffer
{
    sampler sam : packoffset(c1);
}

float4 main() : sv_target
{
    return 0;
}

[pixel shader]
cbuffer buffer
{
    sampler sam : packoffset(c1);
    float4 a : packoffset(c0);
}

float4 main() : sv_target
{
    return a;
}


% When packoffset is used in one field, resources are also expected to have a reservation.
[pixel shader fail(sm<6)]
cbuffer buffer
{
    float4 foo : packoffset(c0);
    Texture2D tex;
}

float4 main() : sv_target
{
    return 0;
}

[pixel shader fail(sm<6)]
cbuffer buffer
{
    float4 foo : packoffset(c0);
    sampler sam;
}

float4 main() : sv_target
{
    return 0;
}

% register() can be used instead of packoffset().
[pixel shader]
cbuffer buffer
{
    float4 foo : packoffset(c0);
    Texture2D tex : register(T1);
}

float4 main() : sv_target
{
    return 0;
}

[pixel shader]
cbuffer buffer
{
    float4 foo : packoffset(c0);
    sampler sam : register(s1);
}

float4 main() : sv_target
{
    return 0;
}

% Using register() alone is considered manual packing for resources, so the other fields expect packoffset().
[pixel shader fail(sm<6)]
cbuffer buffer
{
    float4 foo;
    Texture2D tex : register(t1);
}

float4 main() : sv_target
{
    return 0;
}

[pixel shader fail(sm<6)]
cbuffer buffer
{
    float4 foo;
    sampler sam : register(s1);
}

float4 main() : sv_target
{
    return 0;
}

% register(c#) is ignored and does not count as manual packing.
[pixel shader]
cbuffer buffer
{
    float4 foo : register(c1);
    Texture2D tex;
}

float4 main() : sv_target
{
    return foo;
}

[test]
uniform 0 float4 1.0 2.0 3.0 4.0
uniform 4 float4 0.0 0.0 0.0 0.0
todo(glsl) draw quad
probe (0, 0) rgba (1.0, 2.0, 3.0, 4.0)

[pixel shader fail(sm<6)]
cbuffer buffer
{
    float4 foo : register(c1);
    Texture2D tex : register(t1);
}

float4 main() : sv_target
{
    return foo;
}

% However, valid register reservations count as manual packing even if they
% don't make sense for the given variable.
% sm6 just rejects incorrect reservations.

[pixel shader fail(sm>=6)]
cbuffer buffer
{
    float4 bar : register(t1);
}

float4 main() : sv_target
{
    return 0;
}

[pixel shader fail(sm>=6)]
cbuffer buffer
{
    float4 foo : packoffset(c0);
    float4 bar : register(t1);
    Texture2D tex : register(s2);
}

float4 main() : sv_target
{
    return foo + bar;
}

[test]
uniform 0 float4 1.0 2.0 3.0 4.0
uniform 4 float4 0.1 0.2 0.3 0.4
todo(glsl) draw quad
probe (0, 0) rgba (1.1, 2.2, 3.3, 4.4)


[require]
shader model >= 5.0

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

[pixel shader]
struct apple
{
    float2 a;
    Texture2D tex;
    float b;
};

cbuffer buffer
{
    float4 foo : packoffset(c3);
    struct apple bar : packoffset(c1);
    struct apple baz : register(u3);
}

float4 main() : sv_target
{
    return 10 * foo + float4(bar.a, 0, 0) + float4(0, 0, bar.b, 0) + bar.tex.Load(int3(0, 0, 0));
}

[test]
uniform 0 float4 0.0 1.0 2.0 3.0
uniform 4 float4 4.0 5.0 6.0 7.0
uniform 8 float4 8.0 9.0 10.0 11.0
uniform 12 float4 12.0 13.0 14.0 15.0
uniform 16 float4 16.0 17.0 18.0 19.0
todo(glsl) draw quad
probe (0, 0) rgba (124.0, 135.0, 146.0, 150.5)

[require]
shader model >= 5.1

[pixel shader fail]
float4 ConstantBuffer;

float4 main() : sv_target
{
    return ConstantBuffer;
}

[pixel shader fail]
struct s
{
    float4 m;
};

float4 cb;
ConstantBuffer<s> cb;

float4 main() : sv_target
{
    return 0;
}

[pixel shader fail(sm>=6)]
struct s
{
    float4 m;
};

float4 main() : sv_target
{
    // Local variable do not create resource definitions,
    // acting like a constant
    ConstantBuffer<s> cb = (s)1;
    float4 var = 0.1f;
    var += cb.m;
    return var;
}

[test]
todo(glsl) draw quad
probe (0, 0) rgba (1.1, 1.1, 1.1, 1.1)

[pixel shader]
struct s
{
    float4 m;
};
ConstantBuffer<s> cb;

float4 func(s arg)
{
    return arg.m;
}

float4 main() : sv_target
{
    return func(cb);
}

[test]
uniform 0 float4 1.0 2.0 3.0 4.0
todo(glsl) draw quad
probe (0, 0) rgba (1.0, 2.0, 3.0, 4.0)

[pixel shader fail todo]
struct s
{
    float4 m;
};

float4 main() : sv_target
{
    ConstantBuffer<s> cb = (s)0;
    cb.m = 1.0f;
    return cb.m;
}

[pixel shader]
struct s
{
    float4 m;
};

float4 var;

ConstantBuffer<s> cb[2][3] : register(b1);
cbuffer cb
{
    float4 m2;
};

float4 main() : sv_target
{
    return 0;
}

[pixel shader fail todo]
struct s
{
    float4 m;
};

ConstantBuffer<s> func(s arg)
{
    return arg;
}

float4 main() : sv_target
{
    return 0;
}

[require]
shader model >= 2.0
shader model < 5.1

[pixel shader]
float4 ConstantBuffer;

float4 main() : sv_target
{
    return ConstantBuffer;
}