Skip to content

Commit ccdc39f

Browse files
authored
ExecutionTest for SampleCmpLevel (microsoft#4286)
A mipmapped texture containing the value of LOD at each location in each level is used to sample at each level using SampleCmpLevel and confirm that the correct level is used for the comparison. Additionally, the result of SampleCmpLevelZero is compared to the SampleCmpLevel equivalent
1 parent c44a4a9 commit ccdc39f

File tree

2 files changed

+235
-0
lines changed

2 files changed

+235
-0
lines changed

tools/clang/test/HLSL/ShaderOpArith.xml

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -857,6 +857,156 @@
857857
]]>
858858
</Shader>
859859
</ShaderOp>
860+
<ShaderOp Name="SampleCmpLevel" PS="PS" VS="VS" CS="CS" AS="AS" MS="MS" TopologyType="TRIANGLE">
861+
<RootSignature>
862+
RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT),
863+
DescriptorTable(SRV(t0,numDescriptors=1), UAV(u0), UAV(u1), UAV(u2)),
864+
StaticSampler(s0, addressU = TEXTURE_ADDRESS_WRAP, addressV = TEXTURE_ADDRESS_WRAP, filter = FILTER_MIN_MAG_LINEAR_MIP_POINT),
865+
StaticSampler(s1, addressU = TEXTURE_ADDRESS_WRAP, addressV = TEXTURE_ADDRESS_WRAP, filter = FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT)
866+
</RootSignature>
867+
<Resource Name="VBuffer" Dimension="BUFFER" InitialResourceState="COPY_DEST" Init="FromBytes" Topology="TRIANGLELIST">
868+
{ { -1.0f, 1.0f, 0.0f }, { 0.0f, 0.0f } },
869+
{ { 1.0f, 1.0f, 0.0f }, { 1.0f, 0.0f } },
870+
{ { -1.0f, -1.0f, 0.0f }, { 0.0f, 1.0f } },
871+
872+
{ { -1.0f, -1.0f, 0.0f }, { 0.0f, 1.0f } },
873+
{ { 1.0f, 1.0f, 0.0f }, { 1.0f, 0.0f } },
874+
{ { 1.0f, -1.0f, 0.0f }, { 1.0f, 1.0f } }
875+
</Resource>
876+
<Resource Name="T0" Dimension="Texture2D" Width="336" Height="336" MipLevels="7" InitialResourceState="COPY_DEST" Init="ByName" Format="R32_FLOAT" />
877+
<Resource Name="RTarget" Dimension="TEXTURE2D" Width="84" Height="4" Format="R32G32B32A32_FLOAT" Flags="ALLOW_RENDER_TARGET" InitialResourceState="COPY_DEST" />
878+
<Resource Name="U0" Dimension="BUFFER" Width="8192"
879+
Flags="ALLOW_UNORDERED_ACCESS" InitialResourceState="COPY_DEST"
880+
Init="Zero" ReadBack="true" />
881+
<Resource Name="U1" Dimension="BUFFER" Width="1024"
882+
Flags="ALLOW_UNORDERED_ACCESS" InitialResourceState="COPY_DEST"
883+
Init="Zero" ReadBack="true" />
884+
<Resource Name="U2" Dimension="BUFFER" Width="1024"
885+
Flags="ALLOW_UNORDERED_ACCESS" InitialResourceState="COPY_DEST"
886+
Init="Zero" ReadBack="true" />
887+
888+
<RootValues>
889+
<RootValue HeapName="ResHeap" />
890+
</RootValues>
891+
<DescriptorHeap Name="ResHeap" Type="CBV_SRV_UAV">
892+
<Descriptor Name='T0' Kind='SRV' ResName='T0' />
893+
<Descriptor Name='U0' Kind='UAV' ResName='U0'
894+
NumElements="336" StructureByteStride="8" />
895+
<Descriptor Name='U1' Kind='UAV' ResName='U1'
896+
NumElements="128" StructureByteStride="8" />
897+
<Descriptor Name='U2' Kind='UAV' ResName='U2'
898+
NumElements="128" StructureByteStride="8" />
899+
</DescriptorHeap>
900+
<DescriptorHeap Name="RtvHeap" NumDescriptors="1" Type="RTV">
901+
<Descriptor Name="RTarget" Kind="RTV"/>
902+
</DescriptorHeap>
903+
904+
<InputElements>
905+
<InputElement SemanticName="POSITION" Format="R32G32B32_FLOAT" AlignedByteOffset="0" />
906+
<InputElement SemanticName="TEXCOORD" Format="R32G32_FLOAT" AlignedByteOffset="12" />
907+
</InputElements>
908+
<RenderTargets>
909+
<RenderTarget Name="RTarget"/>
910+
</RenderTargets>
911+
<Shader Name="CS" Target="cs_6_7" EntryPoint="CSMain" Text="@PS"/>
912+
<Shader Name="AS" Target="as_6_7" EntryPoint="ASMain" Text="@PS"/>
913+
<Shader Name="MS" Target="ms_6_7" EntryPoint="MSMain" Text="@PS"/>
914+
<Shader Name="VS" Target="vs_6_7" EntryPoint="VSMain" Text="@PS"/>
915+
<Shader Name="PS" Target="ps_6_7" EntryPoint="PSMain">
916+
<![CDATA[
917+
#define MAX_MIP 7
918+
struct PSInput {
919+
float4 position : SV_POSITION;
920+
float2 uv : TEXCOORD;
921+
};
922+
923+
Texture2D<float> g_tex : register(t0);
924+
RWStructuredBuffer<uint2> g_bufMain : register(u0);
925+
RWStructuredBuffer<uint2> g_bufMesh : register(u1);
926+
RWStructuredBuffer<uint2> g_bufAmp : register(u2);
927+
928+
SamplerState g_samp : register(s0); // Just used for the pre-6.7 fakes
929+
SamplerComparisonState g_sampCmp : register(s1);
930+
931+
uint2 DoSampleCmpLevel( float2 coord, uint lod ) {
932+
float expected = float(lod) + 0.5;
933+
#if __SHADER_TARGET_MAJOR > 6 || (__SHADER_TARGET_MAJOR == 6 && __SHADER_TARGET_MINOR >= 7)
934+
return uint2( g_tex.SampleCmpLevelZero(g_sampCmp, coord, expected) == g_tex.SampleCmpLevel(g_sampCmp, coord, expected, 0),
935+
g_tex.SampleCmpLevel(g_sampCmp, coord, expected, lod));
936+
#else
937+
// The initial compare is meaningless here, so just give the value expected
938+
return uint2(1, g_tex.SampleLevel(g_samp, coord, lod) == expected);
939+
#endif
940+
}
941+
942+
static float4 g_Verts[6] = {
943+
{ -1.0f, 1.0f, 0.0f, 1.0f },
944+
{ 1.0f, 1.0f, 0.0f, 1.0f },
945+
{ -1.0f, -1.0f, 0.0f, 1.0f },
946+
947+
{ -1.0f, -1.0f, 0.0f, 1.0f },
948+
{ 1.0f, 1.0f, 0.0f, 1.0f },
949+
{ 1.0f, -1.0f, 0.0f, 1.0f }};
950+
951+
static float2 g_UV[6] = {
952+
{ 0.0f, 0.0f },
953+
{ 1.0f, 0.0f },
954+
{ 0.0f, 1.0f },
955+
956+
{ 0.0f, 1.0f },
957+
{ 1.0f, 0.0f },
958+
{ 1.0f, 1.0f }};
959+
960+
struct Payload {
961+
uint nothing;
962+
};
963+
964+
[NumThreads(8, 2, 1)]
965+
void ASMain(uint ix : SV_GroupIndex) {
966+
Payload payload;
967+
g_bufAmp[ix % MAX_MIP] = DoSampleCmpLevel(float2(0.5, 0.5), ix % MAX_MIP);
968+
payload.nothing = 0;
969+
DispatchMesh(1, 1, 1, payload);
970+
}
971+
972+
[NumThreads(8, 2, 1)]
973+
[OutputTopology("triangle")]
974+
void MSMain(
975+
uint ix : SV_GroupIndex,
976+
in payload Payload payload,
977+
out vertices PSInput verts[6],
978+
out indices uint3 tris[2]) {
979+
SetMeshOutputCounts(6, 2);
980+
// Assign static fullscreen 2 tri quad
981+
verts[ix%6].position = g_Verts[ix%6];
982+
verts[ix%6].uv = g_UV[ix%6];
983+
tris[ix&1] = uint3((ix&1)*3, (ix&1)*3 + 1, (ix&1)*3 + 2);
984+
g_bufMesh[ix % MAX_MIP] = DoSampleCmpLevel(float2(0.5, 0.5), ix % MAX_MIP);
985+
}
986+
987+
988+
PSInput VSMain(float3 position : POSITION, float2 uv : TEXCOORD) {
989+
PSInput result;
990+
result.position = float4(position, 1.0);
991+
result.uv = uv;
992+
return result;
993+
}
994+
995+
float4 PSMain(PSInput input) : SV_TARGET {
996+
uint ix = uint(input.uv.x * 336);
997+
g_bufMain[ix % MAX_MIP] = DoSampleCmpLevel(input.uv, ix % MAX_MIP);
998+
return 1;
999+
}
1000+
1001+
[NumThreads(16, 1, 1)]
1002+
void CSMain(uint ix : SV_GroupIndex) {
1003+
// all mip levels contain the same values, so 0.5,0.5 is just as good as any
1004+
g_bufMain[ix % MAX_MIP] = DoSampleCmpLevel(float2(0.5, 0.5), ix % MAX_MIP);
1005+
}
1006+
1007+
]]>
1008+
</Shader>
1009+
</ShaderOp>
8601010
<ShaderOp Name="OOB" PS="PS" VS="VS">
8611011
<RootSignature>RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT), CBV(b0), DescriptorTable(SRV(t0,numDescriptors=2))</RootSignature>
8621012
<Resource Name="CB0" Dimension="BUFFER" InitialResourceState="COPY_DEST" Init="FromBytes" TransitionTo="VERTEX_AND_CONSTANT_BUFFER">

tools/clang/unittests/HLSL/ExecutionTest.cpp

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,7 @@ class ExecutionTest {
305305
TEST_METHOD(DerivativesTest);
306306
TEST_METHOD(ComputeSampleTest);
307307
TEST_METHOD(ATOProgOffset);
308+
TEST_METHOD(ATOSampleCmpLevelTest);
308309
TEST_METHOD(AtomicsTest);
309310
TEST_METHOD(Atomics64Test);
310311
TEST_METHOD(AtomicsRawHeap64Test);
@@ -3799,6 +3800,90 @@ TEST_F(ExecutionTest, ATOProgOffset) {
37993800

38003801
}
38013802

3803+
// A mipmapped texture containing the value of LOD at each location in each
3804+
// level is used to sample at each level using SampleCmpLevel and confirm
3805+
// that the correct level is used for the comparison.
3806+
TEST_F(ExecutionTest, ATOSampleCmpLevelTest) {
3807+
WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
3808+
CComPtr<IStream> pStream;
3809+
ReadHlslDataIntoNewStream(L"ShaderOpArith.xml", &pStream);
3810+
3811+
CComPtr<ID3D12Device> pDevice;
3812+
if (!CreateDevice(&pDevice, D3D_SHADER_MODEL_6_7))
3813+
return;
3814+
3815+
std::shared_ptr<st::ShaderOpSet> ShaderOpSet =
3816+
std::make_shared<st::ShaderOpSet>();
3817+
st::ParseShaderOpSetFromStream(pStream, ShaderOpSet.get());
3818+
3819+
st::ShaderOp *pShaderOp = ShaderOpSet->GetShaderOp("SampleCmpLevel");
3820+
3821+
// Initialize texture with the LOD number in each corresponding mip level
3822+
auto SampleInitFn = [&](LPCSTR Name, std::vector<BYTE> &Data, st::ShaderOp *pShaderOp) {
3823+
UNREFERENCED_PARAMETER(pShaderOp);
3824+
D3D12_RESOURCE_DESC &texDesc = pShaderOp->GetResourceByName(Name)->Desc;
3825+
UINT texWidth = (UINT)texDesc.Width;
3826+
UINT texHeight = (UINT)texDesc.Height;
3827+
size_t size = sizeof(float) * texWidth * texHeight * 2;
3828+
Data.resize(size);
3829+
float *pPrimitives = (float *)Data.data();
3830+
float val = 0.5;
3831+
int ix = 0;
3832+
while (texHeight > 0 && texWidth > 0) {
3833+
if(!texHeight) texHeight = 1;
3834+
if(!texWidth) texWidth = 1;
3835+
for (size_t j = 0; j < texHeight; ++j) {
3836+
for (size_t i = 0; i < texWidth; ++i) {
3837+
pPrimitives[ix++] = val;
3838+
}
3839+
}
3840+
val += 1.0;
3841+
texHeight >>= 1;
3842+
texWidth >>= 1;
3843+
}
3844+
};
3845+
3846+
// Test compute shader
3847+
std::shared_ptr<ShaderOpTestResult> test = RunShaderOpTestAfterParse(pDevice, m_support, "SampleCmpLevel", SampleInitFn, ShaderOpSet);
3848+
MappedData data;
3849+
3850+
test->Test->GetReadBackData("U0", &data);
3851+
const UINT *pPixels = (UINT *)data.data();
3852+
3853+
// Check that each LOD matches what's expected
3854+
unsigned count = 2*7;
3855+
// Since the results consist of a boolean, which should be true followed by the result of a sampcmplvl,
3856+
// the only result expected is 1.
3857+
for (unsigned i = 0; i < count; i++)
3858+
VERIFY_ARE_EQUAL(pPixels[i], 1U);
3859+
3860+
if (DoesDeviceSupportMeshShaders(pDevice)) {
3861+
// Disable CS so mesh goes forward
3862+
pShaderOp->CS = nullptr;
3863+
test = RunShaderOpTestAfterParse(pDevice, m_support, "SampleCmpLevel", SampleInitFn, ShaderOpSet);
3864+
3865+
test->Test->GetReadBackData("U0", &data);
3866+
pPixels = (UINT *)data.data();
3867+
3868+
for (unsigned i = 0; i < count; i++)
3869+
VERIFY_ARE_EQUAL(pPixels[i], 1U);
3870+
3871+
test->Test->GetReadBackData("U1", &data);
3872+
pPixels = (UINT *)data.data();
3873+
3874+
for (unsigned i = 0; i < count; i++)
3875+
VERIFY_ARE_EQUAL(pPixels[i], 1U);
3876+
3877+
test->Test->GetReadBackData("U2", &data);
3878+
pPixels = (UINT *)data.data();
3879+
3880+
for (unsigned i = 0; i < count; i++)
3881+
VERIFY_ARE_EQUAL(pPixels[i], 1U);
3882+
}
3883+
}
3884+
3885+
3886+
38023887
// Executing a simple binop to verify shadel model 6.1 support; runs with
38033888
// ShaderModel61.CoreRequirement
38043889
TEST_F(ExecutionTest, BasicShaderModel61) {

0 commit comments

Comments
 (0)