vkd3d/tests/hlsl/cbuffer.shader_test
Elizabeth Figura 8fcbbfb8b1 tests/shader_runner: Test versions where the compilation result changes.
Adjust the algorithm for deciding for which profiles to test compilation.

We first ensure that if the compilation result changes (most often as the result
of a feature introduced in a specific version), we test the versions immediately
on either side of the change, to validate that vkd3d-shader is emulating the
same version behaviour.

We then ensure that we are testing at least one version from each set of sm1,
sm4, and sm6.
2024-12-17 16:35:09 +01:00

982 lines
13 KiB
Plaintext

% 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
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
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
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
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
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
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
draw quad
probe (0, 0) rgba (0.0, 4.0, 5.0, 6.0)
[pixel shader fail]
// 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);
}
[pixel shader fail(sm>=6)]
// 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
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
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
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]
// Matrices must be aligned.
cbuffer buffer
{
float1x1 m : packoffset(c0.y);
}
float4 main() : sv_target
{
return 0;
}
[pixel shader fail]
// Arrays must be aligned.
cbuffer buffer
{
float a[1] : packoffset(c0.y);
}
float4 main() : sv_target
{
return 0;
}
[pixel shader fail]
// 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
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
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(msl) 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(msl) 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]
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
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>=5.1) todo(sm>=5.1)]
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
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(msl) 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]
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
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;
}