Skip to content

Commit 7b32b38

Browse files
authored
[ExecutionTest] Add Wave Range Size HLK Tests (#6348) (#6360)
This PR adds execution testing to wave range size attributes, on top of the already existing WaveSizeTest HLK test. It implements the necessary coverage of the new wave range size attribute, as described in the hlsl-specs here: https://github.com/microsoft/hlsl-specs/blob/main/proposals/0013-wave-size-range.md#execution-testing Fixes #6347 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> (cherry picked from commit b6b6b6d)
1 parent 1f02cdb commit 7b32b38

1 file changed

Lines changed: 228 additions & 51 deletions

File tree

tools/clang/unittests/HLSLExec/ExecutionTest.cpp

Lines changed: 228 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ class ExecutionTest {
328328
TEST_METHOD(WaveIntrinsicsDDITest);
329329
TEST_METHOD(WaveIntrinsicsInPSTest);
330330
TEST_METHOD(WaveSizeTest);
331+
TEST_METHOD(WaveSizeRangeTest);
331332
TEST_METHOD(PartialDerivTest);
332333
TEST_METHOD(DerivativesTest);
333334
TEST_METHOD(ComputeSampleTest);
@@ -13220,22 +13221,208 @@ TEST_F(ExecutionTest, DynamicResourcesDynamicIndexingTest) {
1322013221

1322113222
#define MAX_WAVESIZE 128
1322213223

13223-
#define strinfigy2(arg) #arg
13224-
#define strinfigy(arg) strinfigy2(arg)
13224+
#define stringify2(arg) #arg
13225+
#define stringify(arg) stringify2(arg)
13226+
13227+
void RunWaveSizeTest(UINT minWaveSize, UINT maxWaveSize,
13228+
std::shared_ptr<st::ShaderOpSet> ShaderOpSet,
13229+
CComPtr<ID3D12Device> pDevice,
13230+
dxc::DxcDllSupport &m_support) {
13231+
// format shader source
13232+
const char waveSizeTestShader[] =
13233+
R"(struct TestData {
13234+
uint count;
13235+
};
13236+
RWStructuredBuffer<TestData> data : register(u0);
13237+
13238+
// Note: WAVESIZE will be defined via compiler option -D
13239+
WAVE_SIZE_ATTR
13240+
[numthreads()" stringify(MAX_WAVESIZE) R"(*2,1,1)]
13241+
void main() {
13242+
data[0].count = WaveGetLaneCount();
13243+
})";
13244+
13245+
struct WaveSizeTestData {
13246+
uint32_t count;
13247+
};
13248+
13249+
for (UINT waveSize = minWaveSize; waveSize <= maxWaveSize; waveSize *= 2) {
13250+
// format compiler args
13251+
char compilerOptions[64];
13252+
VERIFY_IS_TRUE(sprintf_s(compilerOptions, sizeof(compilerOptions),
13253+
"-D WAVE_SIZE_ATTR=[wavesize(%d)]",
13254+
waveSize) != -1);
13255+
13256+
// run the shader
13257+
std::shared_ptr<ShaderOpTestResult> test = RunShaderOpTestAfterParse(
13258+
pDevice, m_support, "WaveSizeTest",
13259+
[&](LPCSTR Name, std::vector<BYTE> &Data, st::ShaderOp *pShaderOp) {
13260+
VERIFY_IS_TRUE((0 == strncmp(Name, "UAVBuffer0", 10)));
13261+
pShaderOp->Shaders.at(0).Arguments = compilerOptions;
13262+
pShaderOp->Shaders.at(0).Text = waveSizeTestShader;
13263+
13264+
VERIFY_IS_TRUE(sizeof(WaveSizeTestData) * MAX_WAVESIZE <=
13265+
Data.size());
13266+
WaveSizeTestData *pInData = (WaveSizeTestData *)Data.data();
13267+
memset(pInData, 0, sizeof(WaveSizeTestData) * MAX_WAVESIZE);
13268+
},
13269+
ShaderOpSet);
13270+
13271+
// verify expected values
13272+
MappedData dataUav;
13273+
WaveSizeTestData *pOutData;
13274+
13275+
test->Test->GetReadBackData("UAVBuffer0", &dataUav);
13276+
VERIFY_ARE_EQUAL(sizeof(WaveSizeTestData) * MAX_WAVESIZE, dataUav.size());
13277+
pOutData = (WaveSizeTestData *)dataUav.data();
13278+
13279+
LogCommentFmt(L"Verifying test result for wave size %d", waveSize);
13280+
13281+
VERIFY_ARE_EQUAL(pOutData[0].count, waveSize);
13282+
}
13283+
}
13284+
13285+
bool TestShaderRangeAgainstRequirements(UINT shaderminws, UINT shadermaxws,
13286+
UINT minws, UINT maxws) {
13287+
if (shaderminws > maxws) {
13288+
return false;
13289+
}
13290+
if (shadermaxws < minws) {
13291+
return false;
13292+
}
13293+
return true;
13294+
}
13295+
13296+
void ExecuteWaveSizeRangeInstance(UINT minWaveSize, UINT maxWaveSize,
13297+
std::shared_ptr<st::ShaderOpSet> ShaderOpSet,
13298+
CComPtr<ID3D12Device> pDevice,
13299+
dxc::DxcDllSupport &m_support,
13300+
UINT minShaderWaveSize,
13301+
UINT maxShaderWaveSize,
13302+
UINT prefShaderWaveSize, bool usePreferred) {
13303+
13304+
// format shader source
13305+
const char waveSizeTestShader[] =
13306+
R"(struct TestData {
13307+
uint count;
13308+
};
13309+
RWStructuredBuffer<TestData> data : register(u0);
13310+
13311+
// Note: WAVE_SIZE_ATTR will be defined via compiler option -D
13312+
WAVE_SIZE_ATTR
13313+
[numthreads()" stringify(MAX_WAVESIZE) R"(*2,1,1)]
13314+
void main(uint3 tid : SV_DispatchThreadID) {
13315+
if (tid.x == 0 && tid.y == 0 && tid.z == 0) {
13316+
data[0].count = WaveGetLaneCount();
13317+
}
13318+
})";
13319+
13320+
// format compiler args
13321+
char compilerOptions[64];
13322+
if (usePreferred) {
13323+
// putting spaces in between the %d's below will cause compilation issues.
13324+
VERIFY_IS_TRUE(sprintf_s(compilerOptions, sizeof(compilerOptions),
13325+
"-D WAVE_SIZE_ATTR=[wavesize(%d,%d,%d)]",
13326+
minShaderWaveSize, maxShaderWaveSize,
13327+
prefShaderWaveSize) != -1);
13328+
LogCommentFmt(L"Verifying wave size range test results for (min, max, "
13329+
L"preferred): (%d, %d, %d)",
13330+
minShaderWaveSize, maxShaderWaveSize, prefShaderWaveSize);
13331+
} else {
13332+
VERIFY_IS_TRUE(sprintf_s(compilerOptions, sizeof(compilerOptions),
13333+
"-D WAVE_SIZE_ATTR=[wavesize(%d,%d)]",
13334+
minShaderWaveSize, maxShaderWaveSize) != -1);
13335+
LogCommentFmt(
13336+
L"Verifying wave size range test results for (min, max): (%d, %d)",
13337+
minShaderWaveSize, maxShaderWaveSize);
13338+
}
13339+
13340+
struct WaveSizeTestData {
13341+
uint32_t count;
13342+
};
13343+
13344+
// run the shader
13345+
std::shared_ptr<ShaderOpTestResult> test = RunShaderOpTestAfterParse(
13346+
pDevice, m_support, "WaveSizeTest",
13347+
[&](LPCSTR Name, std::vector<BYTE> &Data, st::ShaderOp *pShaderOp) {
13348+
VERIFY_IS_TRUE((0 == strncmp(Name, "UAVBuffer0", 10)));
13349+
pShaderOp->Shaders.at(0).Arguments = compilerOptions;
13350+
pShaderOp->Shaders.at(0).Text = waveSizeTestShader;
13351+
pShaderOp->Shaders.at(0).Target = "cs_6_8";
13352+
13353+
VERIFY_IS_TRUE(sizeof(WaveSizeTestData) * MAX_WAVESIZE <= Data.size());
13354+
WaveSizeTestData *pInData = (WaveSizeTestData *)Data.data();
13355+
memset(pInData, 0, sizeof(WaveSizeTestData) * MAX_WAVESIZE);
13356+
},
13357+
ShaderOpSet);
13358+
13359+
// verify expected values
13360+
MappedData dataUav;
13361+
WaveSizeTestData *pOutData;
13362+
13363+
// at this point we assume that the waverange size that
13364+
// the shader specifies is legal.
13365+
test->Test->GetReadBackData("UAVBuffer0", &dataUav);
13366+
VERIFY_ARE_EQUAL(sizeof(WaveSizeTestData) * MAX_WAVESIZE, dataUav.size());
13367+
pOutData = (WaveSizeTestData *)dataUav.data();
13368+
13369+
unsigned count = pOutData[0].count;
13370+
if (usePreferred && prefShaderWaveSize >= minWaveSize &&
13371+
prefShaderWaveSize <= maxWaveSize) {
13372+
VERIFY_ARE_EQUAL(count, prefShaderWaveSize);
13373+
} else {
13374+
VERIFY_IS_GREATER_THAN_OR_EQUAL(count, minWaveSize);
13375+
VERIFY_IS_LESS_THAN_OR_EQUAL(count, maxWaveSize);
13376+
}
13377+
}
13378+
13379+
void RunWaveSizeRangeTest(UINT minWaveSize, UINT maxWaveSize,
13380+
std::shared_ptr<st::ShaderOpSet> ShaderOpSet,
13381+
CComPtr<ID3D12Device> pDevice,
13382+
dxc::DxcDllSupport &m_support) {
13383+
13384+
for (UINT minShaderWaveSize = 4; minShaderWaveSize <= maxWaveSize;
13385+
minShaderWaveSize *= 2) {
13386+
for (UINT maxShaderWaveSize = minShaderWaveSize * 2;
13387+
maxShaderWaveSize <= 128; maxShaderWaveSize *= 2) {
13388+
// Only allow valid shader wave ranges
13389+
bool AcceptedByRuntime = TestShaderRangeAgainstRequirements(
13390+
minShaderWaveSize, maxShaderWaveSize, minWaveSize, maxWaveSize);
13391+
if (!AcceptedByRuntime) {
13392+
continue;
13393+
}
13394+
13395+
ExecuteWaveSizeRangeInstance(
13396+
minWaveSize, maxWaveSize, ShaderOpSet, pDevice, m_support,
13397+
minShaderWaveSize, maxShaderWaveSize,
13398+
/* prefShaderWaveSize won't be used, so set it to minShaderWaveSize*/
13399+
minShaderWaveSize, false);
13400+
13401+
for (UINT prefShaderWaveSize = minShaderWaveSize;
13402+
prefShaderWaveSize <= maxShaderWaveSize; prefShaderWaveSize *= 2) {
13403+
13404+
ExecuteWaveSizeRangeInstance(
13405+
minWaveSize, maxWaveSize, ShaderOpSet, pDevice, m_support,
13406+
minShaderWaveSize, maxShaderWaveSize, prefShaderWaveSize, true);
13407+
}
13408+
}
13409+
}
13410+
}
1322513411

1322613412
void ExecutionTest::WaveSizeTest() {
1322713413
WEX::TestExecution::SetVerifyOutput verifySettings(
1322813414
WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
1322913415

1323013416
CComPtr<ID3D12Device> pDevice;
13231-
if (!CreateDevice(&pDevice, D3D_SHADER_MODEL_6_6)) {
13417+
if (!CreateDevice(&pDevice, D3D_SHADER_MODEL_6_6,
13418+
/*skipUnsupported*/ false)) {
1323213419
return;
1323313420
}
1323413421

1323513422
// Check Wave support
1323613423
if (!DoesDeviceSupportWaveOps(pDevice)) {
1323713424
// Optional feature, so it's correct to not support it if declared as such.
13238-
WEX::Logging::Log::Comment(L"Device does not support wave operations.");
13425+
WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped);
1323913426
return;
1324013427
}
1324113428

@@ -13258,61 +13445,51 @@ void ExecutionTest::WaveSizeTest() {
1325813445
ReadHlslDataIntoNewStream(L"ShaderOpArith.xml", &pStream);
1325913446
st::ParseShaderOpSetFromStream(pStream, ShaderOpSet.get());
1326013447

13261-
// format shader source
13262-
const char waveSizeTestShader[] =
13263-
"struct TestData { \r\n"
13264-
" uint count; \r\n"
13265-
"}; \r\n"
13266-
"RWStructuredBuffer<TestData> data : register(u0); \r\n"
13267-
"\r\n"
13268-
"// Note: WAVESIZE will be defined via compiler option -D\r\n"
13269-
"[wavesize(WAVESIZE)]\r\n"
13270-
"[numthreads(" strinfigy(
13271-
MAX_WAVESIZE) "*2,1,1)]\r\n"
13272-
"void main(uint3 tid : SV_DispatchThreadID ) { \r\n"
13273-
" data[tid.x].count = WaveActiveSum(1); \r\n"
13274-
"}\r\n";
13448+
LogCommentFmt(L"Testing WaveSize attribute for shader model 6.6.");
13449+
RunWaveSizeTest(minWaveSize, maxWaveSize, ShaderOpSet, pDevice, m_support);
13450+
}
1327513451

13276-
struct WaveSizeTestData {
13277-
uint32_t count;
13278-
};
13452+
void ExecutionTest::WaveSizeRangeTest() {
13453+
WEX::TestExecution::SetVerifyOutput verifySettings(
13454+
WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
1327913455

13280-
for (UINT waveSize = minWaveSize; waveSize <= maxWaveSize; waveSize *= 2) {
13281-
// format compiler args
13282-
char compilerOptions[32];
13283-
VERIFY_IS_TRUE(sprintf_s(compilerOptions, sizeof(compilerOptions),
13284-
"-D WAVESIZE=%d", waveSize) != -1);
13456+
CComPtr<ID3D12Device> pDevice;
13457+
if (!CreateDevice(&pDevice, D3D_SHADER_MODEL_6_8,
13458+
/*skipUnsupported*/ false)) {
13459+
return;
13460+
}
1328513461

13286-
// run the shader
13287-
std::shared_ptr<ShaderOpTestResult> test = RunShaderOpTestAfterParse(
13288-
pDevice, m_support, "WaveSizeTest",
13289-
[&](LPCSTR Name, std::vector<BYTE> &Data, st::ShaderOp *pShaderOp) {
13290-
VERIFY_IS_TRUE((0 == strncmp(Name, "UAVBuffer0", 10)));
13291-
pShaderOp->Shaders.at(0).Arguments = compilerOptions;
13292-
pShaderOp->Shaders.at(0).Text = waveSizeTestShader;
13462+
// Check Wave support
13463+
if (!DoesDeviceSupportWaveOps(pDevice)) {
13464+
// Optional feature, so it's correct to not support it if declared as such.
13465+
WEX::Logging::Log::Result(WEX::Logging::TestResults::Skipped);
13466+
return;
13467+
}
1329313468

13294-
VERIFY_IS_TRUE(sizeof(WaveSizeTestData) * MAX_WAVESIZE <=
13295-
Data.size());
13296-
WaveSizeTestData *pInData = (WaveSizeTestData *)Data.data();
13297-
memset(pInData, 0, sizeof(WaveSizeTestData) * MAX_WAVESIZE);
13298-
},
13299-
ShaderOpSet);
13469+
// Get supported wave sizes
13470+
D3D12_FEATURE_DATA_D3D12_OPTIONS1 waveOpts;
13471+
VERIFY_SUCCEEDED(
13472+
pDevice->CheckFeatureSupport((D3D12_FEATURE)D3D12_FEATURE_D3D12_OPTIONS1,
13473+
&waveOpts, sizeof(waveOpts)));
13474+
UINT minWaveSize = waveOpts.WaveLaneCountMin;
13475+
UINT maxWaveSize = waveOpts.WaveLaneCountMax;
1330013476

13301-
// verify expected values
13302-
MappedData dataUav;
13303-
WaveSizeTestData *pOutData;
13477+
DXASSERT_NOMSG(minWaveSize <= maxWaveSize);
13478+
DXASSERT((minWaveSize & (minWaveSize - 1)) == 0, "must be a power of 2");
13479+
DXASSERT((maxWaveSize & (maxWaveSize - 1)) == 0, "must be a power of 2");
1330413480

13305-
test->Test->GetReadBackData("UAVBuffer0", &dataUav);
13306-
VERIFY_ARE_EQUAL(sizeof(WaveSizeTestData) * MAX_WAVESIZE, dataUav.size());
13307-
pOutData = (WaveSizeTestData *)dataUav.data();
13481+
// read shader config
13482+
CComPtr<IStream> pStream;
13483+
std::shared_ptr<st::ShaderOpSet> ShaderOpSet =
13484+
std::make_shared<st::ShaderOpSet>();
13485+
ReadHlslDataIntoNewStream(L"ShaderOpArith.xml", &pStream);
13486+
st::ParseShaderOpSetFromStream(pStream, ShaderOpSet.get());
1330813487

13309-
LogCommentFmt(L"Verifying test result for wave size %d", waveSize);
13488+
LogCommentFmt(L"Testing WaveSize Range attribute for shader model 6.8.");
13489+
RunWaveSizeTest(minWaveSize, maxWaveSize, ShaderOpSet, pDevice, m_support);
1331013490

13311-
for (unsigned i = 0; i < MAX_WAVESIZE; i++) {
13312-
if (!VERIFY_ARE_EQUAL(pOutData[i].count, waveSize))
13313-
break;
13314-
}
13315-
}
13491+
RunWaveSizeRangeTest(minWaveSize, maxWaveSize, ShaderOpSet, pDevice,
13492+
m_support);
1331613493
}
1331713494

1331813495
// Atomic operation testing

0 commit comments

Comments
 (0)