spirv-val: Add SPV_KHR_ray_tracing storage class (#4868)

* Added VUID labels
This commit is contained in:
Spencer Fricke 2022-08-30 00:09:06 +09:00 committed by GitHub
parent a98f05d02f
commit f76431cbaf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 432 additions and 18 deletions

View File

@ -438,11 +438,11 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) {
storage_class != SpvStorageClassCrossWorkgroup &&
storage_class != SpvStorageClassPrivate &&
storage_class != SpvStorageClassFunction &&
storage_class != SpvStorageClassRayPayloadNV &&
storage_class != SpvStorageClassIncomingRayPayloadNV &&
storage_class != SpvStorageClassHitAttributeNV &&
storage_class != SpvStorageClassCallableDataNV &&
storage_class != SpvStorageClassIncomingCallableDataNV) {
storage_class != SpvStorageClassRayPayloadKHR &&
storage_class != SpvStorageClassIncomingRayPayloadKHR &&
storage_class != SpvStorageClassHitAttributeKHR &&
storage_class != SpvStorageClassCallableDataKHR &&
storage_class != SpvStorageClassIncomingCallableDataKHR) {
bool storage_input_or_output = storage_class == SpvStorageClassInput ||
storage_class == SpvStorageClassOutput;
bool builtin = false;
@ -889,8 +889,11 @@ spv_result_t ValidateLoad(ValidationState_t& _, const Instruction* inst) {
<< "' is not a pointer type.";
}
const auto pointee_type = _.FindDef(pointer_type->GetOperandAs<uint32_t>(2));
if (!pointee_type || result_type->id() != pointee_type->id()) {
uint32_t pointee_data_type;
uint32_t storage_class;
if (!_.GetPointerTypeInfo(pointer_type->id(), &pointee_data_type,
&storage_class) ||
result_type->id() != pointee_data_type) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "OpLoad Result Type <id> '" << _.getIdName(inst->type_id())
<< "' does not match Pointer <id> '" << _.getIdName(pointer->id())
@ -964,6 +967,26 @@ spv_result_t ValidateStore(ValidationState_t& _, const Instruction* inst) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "OpStore Pointer <id> '" << _.getIdName(pointer_id)
<< "' storage class is read-only";
} else if (storage_class == SpvStorageClassShaderRecordBufferKHR) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "ShaderRecordBufferKHR Storage Class variables are read only";
} else if (storage_class == SpvStorageClassHitAttributeKHR) {
std::string errorVUID = _.VkErrorID(4703);
_.function(inst->function()->id())
->RegisterExecutionModelLimitation(
[errorVUID](SpvExecutionModel model, std::string* message) {
if (model == SpvExecutionModelAnyHitKHR ||
model == SpvExecutionModelClosestHitKHR) {
if (message) {
*message =
errorVUID +
"HitAttributeKHR Storage Class variables are read only "
"with AnyHitKHR and ClosestHitKHR";
}
return false;
}
return true;
});
}
if (spvIsVulkanEnv(_.context()->target_env) &&

View File

@ -608,7 +608,8 @@ void ValidationState_t::RegisterStorageClassConsumer(
std::string errorVUID = VkErrorID(4644);
function(consumer->function()->id())
->RegisterExecutionModelLimitation([errorVUID](
SpvExecutionModel model, std::string* message) {
SpvExecutionModel model,
std::string* message) {
if (model == SpvExecutionModelGLCompute ||
model == SpvExecutionModelRayGenerationKHR ||
model == SpvExecutionModelIntersectionKHR ||
@ -634,7 +635,8 @@ void ValidationState_t::RegisterStorageClassConsumer(
std::string errorVUID = VkErrorID(4645);
function(consumer->function()->id())
->RegisterExecutionModelLimitation([errorVUID](
SpvExecutionModel model, std::string* message) {
SpvExecutionModel model,
std::string* message) {
if (model != SpvExecutionModelGLCompute &&
model != SpvExecutionModelTaskNV &&
model != SpvExecutionModelMeshNV) {
@ -650,6 +652,116 @@ void ValidationState_t::RegisterStorageClassConsumer(
});
}
}
if (storage_class == SpvStorageClassCallableDataKHR) {
std::string errorVUID = VkErrorID(4704);
function(consumer->function()->id())
->RegisterExecutionModelLimitation([errorVUID](SpvExecutionModel model,
std::string* message) {
if (model != SpvExecutionModelRayGenerationKHR &&
model != SpvExecutionModelClosestHitKHR &&
model != SpvExecutionModelCallableKHR &&
model != SpvExecutionModelMissKHR) {
if (message) {
*message = errorVUID +
"CallableDataKHR Storage Class is limited to "
"RayGenerationKHR, ClosestHitKHR, CallableKHR, and "
"MissKHR execution model";
}
return false;
}
return true;
});
} else if (storage_class == SpvStorageClassIncomingCallableDataKHR) {
std::string errorVUID = VkErrorID(4705);
function(consumer->function()->id())
->RegisterExecutionModelLimitation([errorVUID](SpvExecutionModel model,
std::string* message) {
if (model != SpvExecutionModelCallableKHR) {
if (message) {
*message = errorVUID +
"IncomingCallableDataKHR Storage Class is limited to "
"CallableKHR execution model";
}
return false;
}
return true;
});
} else if (storage_class == SpvStorageClassRayPayloadKHR) {
std::string errorVUID = VkErrorID(4698);
function(consumer->function()->id())
->RegisterExecutionModelLimitation([errorVUID](SpvExecutionModel model,
std::string* message) {
if (model != SpvExecutionModelRayGenerationKHR &&
model != SpvExecutionModelClosestHitKHR &&
model != SpvExecutionModelMissKHR) {
if (message) {
*message =
errorVUID +
"RayPayloadKHR Storage Class is limited to RayGenerationKHR, "
"ClosestHitKHR, and MissKHR execution model";
}
return false;
}
return true;
});
} else if (storage_class == SpvStorageClassHitAttributeKHR) {
std::string errorVUID = VkErrorID(4701);
function(consumer->function()->id())
->RegisterExecutionModelLimitation(
[errorVUID](SpvExecutionModel model, std::string* message) {
if (model != SpvExecutionModelIntersectionKHR &&
model != SpvExecutionModelAnyHitKHR &&
model != SpvExecutionModelClosestHitKHR) {
if (message) {
*message = errorVUID +
"HitAttributeKHR Storage Class is limited to "
"IntersectionKHR, AnyHitKHR, sand ClosestHitKHR "
"execution model";
}
return false;
}
return true;
});
} else if (storage_class == SpvStorageClassIncomingRayPayloadKHR) {
std::string errorVUID = VkErrorID(4699);
function(consumer->function()->id())
->RegisterExecutionModelLimitation(
[errorVUID](SpvExecutionModel model, std::string* message) {
if (model != SpvExecutionModelAnyHitKHR &&
model != SpvExecutionModelClosestHitKHR &&
model != SpvExecutionModelMissKHR) {
if (message) {
*message =
errorVUID +
"IncomingRayPayloadKHR Storage Class is limited to "
"AnyHitKHR, ClosestHitKHR, and MissKHR execution model";
}
return false;
}
return true;
});
} else if (storage_class == SpvStorageClassShaderRecordBufferKHR) {
function(consumer->function()->id())
->RegisterExecutionModelLimitation(
[](SpvExecutionModel model, std::string* message) {
if (model != SpvExecutionModelRayGenerationKHR &&
model != SpvExecutionModelIntersectionKHR &&
model != SpvExecutionModelAnyHitKHR &&
model != SpvExecutionModelClosestHitKHR &&
model != SpvExecutionModelCallableKHR &&
model != SpvExecutionModelMissKHR) {
if (message) {
*message =
"ShaderRecordBufferKHR Storage Class is limited to "
"RayGenerationKHR, IntersectionKHR, AnyHitKHR, "
"ClosestHitKHR, CallableKHR, and MissKHR execution model";
}
return false;
}
return true;
});
}
}
uint32_t ValidationState_t::getIdBound() const { return id_bound_; }
@ -1911,6 +2023,18 @@ std::string ValidationState_t::VkErrorID(uint32_t id,
return VUID_WRAP(VUID-StandaloneSpirv-OpGroupNonUniformBallotBitCount-04685);
case 4686:
return VUID_WRAP(VUID-StandaloneSpirv-None-04686);
case 4698:
return VUID_WRAP(VUID-StandaloneSpirv-RayPayloadKHR-04698);
case 4699:
return VUID_WRAP(VUID-StandaloneSpirv-IncomingRayPayloadKHR-04699);
case 4701:
return VUID_WRAP(VUID-StandaloneSpirv-HitAttributeKHR-04701);
case 4703:
return VUID_WRAP(VUID-StandaloneSpirv-HitAttributeKHR-04703);
case 4704:
return VUID_WRAP(VUID-StandaloneSpirv-CallableDataKHR-04704);
case 4705:
return VUID_WRAP(VUID-StandaloneSpirv-IncomingCallableDataKHR-04705);
case 4708:
return VUID_WRAP(VUID-StandaloneSpirv-PhysicalStorageBuffer64-04708);
case 4710:

View File

@ -251,30 +251,46 @@ TEST_F(ValidateStorage, RelaxedLogicalPointerFunctionParamBad) {
HasSubstr("OpFunctionCall Argument <id> '"));
}
TEST_P(ValidateStorageExecutionModel, VulkanOutsideStoreFailure) {
std::stringstream ss;
std::string GenerateExecutionModelCode(const std::string& execution_model,
const std::string& storage_class,
bool store) {
const std::string mode = (execution_model.compare("GLCompute") == 0)
? "OpExecutionMode %func LocalSize 1 1 1"
: "";
const std::string operation =
(store) ? "OpStore %var %int0" : "%load = OpLoad %intt %var";
std::ostringstream ss;
ss << R"(
OpCapability Shader
OpCapability RayTracingKHR
OpExtension "SPV_KHR_ray_tracing"
OpMemoryModel Logical GLSL450
OpEntryPoint )"
<< GetParam() << R"( %func "func" %output
OpDecorate %output Location 0
<< execution_model << R"( %func "func" %var
)" << mode << R"(
OpDecorate %var Location 0
%intt = OpTypeInt 32 0
%int0 = OpConstant %intt 0
%voidt = OpTypeVoid
%vfunct = OpTypeFunction %voidt
%outputptrt = OpTypePointer Output %intt
%output = OpVariable %outputptrt Output
%ptr = OpTypePointer )"
<< storage_class << R"( %intt
%var = OpVariable %ptr )" << storage_class << R"(
%func = OpFunction %voidt None %vfunct
%funcl = OpLabel
OpStore %output %int0
)" << operation << R"(
OpReturn
OpFunctionEnd
)";
CompileSuccessfully(ss.str(), SPV_ENV_VULKAN_1_0);
return ss.str();
}
TEST_P(ValidateStorageExecutionModel, VulkanOutsideStoreFailure) {
std::string execution_model = GetParam();
CompileSuccessfully(
GenerateExecutionModelCode(execution_model, "Output", true).c_str(),
SPV_ENV_VULKAN_1_0);
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
EXPECT_THAT(getDiagnosticString(),
AnyVUID("VUID-StandaloneSpirv-None-04644"));
@ -285,11 +301,262 @@ TEST_P(ValidateStorageExecutionModel, VulkanOutsideStoreFailure) {
"ClosestHitKHR, MissKHR, or CallableKHR execution models"));
}
TEST_P(ValidateStorageExecutionModel, CallableDataStore) {
std::string execution_model = GetParam();
CompileSuccessfully(
GenerateExecutionModelCode(execution_model, "CallableDataKHR", true)
.c_str(),
SPV_ENV_VULKAN_1_2);
if (execution_model.compare("RayGenerationKHR") == 0 ||
execution_model.compare("ClosestHitKHR") == 0 ||
execution_model.compare("CallableKHR") == 0 ||
execution_model.compare("MissKHR") == 0) {
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
} else {
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
EXPECT_THAT(getDiagnosticString(),
AnyVUID("VUID-StandaloneSpirv-CallableDataKHR-04704"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"CallableDataKHR Storage Class is limited to RayGenerationKHR, "
"ClosestHitKHR, CallableKHR, and MissKHR execution model"));
}
}
TEST_P(ValidateStorageExecutionModel, CallableDataLoad) {
std::string execution_model = GetParam();
CompileSuccessfully(
GenerateExecutionModelCode(execution_model, "CallableDataKHR", false)
.c_str(),
SPV_ENV_VULKAN_1_2);
if (execution_model.compare("RayGenerationKHR") == 0 ||
execution_model.compare("ClosestHitKHR") == 0 ||
execution_model.compare("CallableKHR") == 0 ||
execution_model.compare("MissKHR") == 0) {
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
} else {
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
EXPECT_THAT(getDiagnosticString(),
AnyVUID("VUID-StandaloneSpirv-CallableDataKHR-04704"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"CallableDataKHR Storage Class is limited to RayGenerationKHR, "
"ClosestHitKHR, CallableKHR, and MissKHR execution model"));
}
}
TEST_P(ValidateStorageExecutionModel, IncomingCallableDataStore) {
std::string execution_model = GetParam();
CompileSuccessfully(GenerateExecutionModelCode(
execution_model, "IncomingCallableDataKHR", true)
.c_str(),
SPV_ENV_VULKAN_1_2);
if (execution_model.compare("CallableKHR") == 0) {
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
} else {
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
EXPECT_THAT(getDiagnosticString(),
AnyVUID("VUID-StandaloneSpirv-IncomingCallableDataKHR-04705"));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("IncomingCallableDataKHR Storage Class is limited to "
"CallableKHR execution model"));
}
}
TEST_P(ValidateStorageExecutionModel, IncomingCallableDataLoad) {
std::string execution_model = GetParam();
CompileSuccessfully(GenerateExecutionModelCode(
execution_model, "IncomingCallableDataKHR", false)
.c_str(),
SPV_ENV_VULKAN_1_2);
if (execution_model.compare("CallableKHR") == 0) {
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
} else {
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
EXPECT_THAT(getDiagnosticString(),
AnyVUID("VUID-StandaloneSpirv-IncomingCallableDataKHR-04705"));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("IncomingCallableDataKHR Storage Class is limited to "
"CallableKHR execution model"));
}
}
TEST_P(ValidateStorageExecutionModel, RayPayloadStore) {
std::string execution_model = GetParam();
CompileSuccessfully(
GenerateExecutionModelCode(execution_model, "RayPayloadKHR", true)
.c_str(),
SPV_ENV_VULKAN_1_2);
if (execution_model.compare("RayGenerationKHR") == 0 ||
execution_model.compare("ClosestHitKHR") == 0 ||
execution_model.compare("MissKHR") == 0) {
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
} else {
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
EXPECT_THAT(getDiagnosticString(),
AnyVUID("VUID-StandaloneSpirv-RayPayloadKHR-04698"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("RayPayloadKHR Storage Class is limited to RayGenerationKHR, "
"ClosestHitKHR, and MissKHR execution model"));
}
}
TEST_P(ValidateStorageExecutionModel, RayPayloadLoad) {
std::string execution_model = GetParam();
CompileSuccessfully(
GenerateExecutionModelCode(execution_model, "RayPayloadKHR", false)
.c_str(),
SPV_ENV_VULKAN_1_2);
if (execution_model.compare("RayGenerationKHR") == 0 ||
execution_model.compare("ClosestHitKHR") == 0 ||
execution_model.compare("MissKHR") == 0) {
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
} else {
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
EXPECT_THAT(getDiagnosticString(),
AnyVUID("VUID-StandaloneSpirv-RayPayloadKHR-04698"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("RayPayloadKHR Storage Class is limited to RayGenerationKHR, "
"ClosestHitKHR, and MissKHR execution model"));
}
}
TEST_P(ValidateStorageExecutionModel, HitAttributeStore) {
std::string execution_model = GetParam();
CompileSuccessfully(
GenerateExecutionModelCode(execution_model, "HitAttributeKHR", true)
.c_str(),
SPV_ENV_VULKAN_1_2);
if (execution_model.compare("IntersectionKHR") == 0) {
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
} else if (execution_model.compare("AnyHitKHR") == 0 ||
execution_model.compare("ClosestHitKHR") == 0) {
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
EXPECT_THAT(getDiagnosticString(),
AnyVUID("VUID-StandaloneSpirv-HitAttributeKHR-04703"));
EXPECT_THAT(getDiagnosticString(),
HasSubstr("HitAttributeKHR Storage Class variables are read "
"only with AnyHitKHR and ClosestHitKHR"));
} else {
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
EXPECT_THAT(getDiagnosticString(),
AnyVUID("VUID-StandaloneSpirv-HitAttributeKHR-04701"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"HitAttributeKHR Storage Class is limited to IntersectionKHR, "
"AnyHitKHR, sand ClosestHitKHR execution model"));
}
}
TEST_P(ValidateStorageExecutionModel, HitAttributeLoad) {
std::string execution_model = GetParam();
CompileSuccessfully(
GenerateExecutionModelCode(execution_model, "HitAttributeKHR", false)
.c_str(),
SPV_ENV_VULKAN_1_2);
if (execution_model.compare("IntersectionKHR") == 0 ||
execution_model.compare("AnyHitKHR") == 0 ||
execution_model.compare("ClosestHitKHR") == 0) {
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
} else {
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
EXPECT_THAT(getDiagnosticString(),
AnyVUID("VUID-StandaloneSpirv-HitAttributeKHR-04701"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr(
"HitAttributeKHR Storage Class is limited to IntersectionKHR, "
"AnyHitKHR, sand ClosestHitKHR execution model"));
}
}
TEST_P(ValidateStorageExecutionModel, IncomingRayPayloadStore) {
std::string execution_model = GetParam();
CompileSuccessfully(
GenerateExecutionModelCode(execution_model, "IncomingRayPayloadKHR", true)
.c_str(),
SPV_ENV_VULKAN_1_2);
if (execution_model.compare("AnyHitKHR") == 0 ||
execution_model.compare("ClosestHitKHR") == 0 ||
execution_model.compare("MissKHR") == 0) {
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
} else {
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
EXPECT_THAT(getDiagnosticString(),
AnyVUID("VUID-StandaloneSpirv-IncomingRayPayloadKHR-04699"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("IncomingRayPayloadKHR Storage Class is limited to "
"AnyHitKHR, ClosestHitKHR, and MissKHR execution model"));
}
}
TEST_P(ValidateStorageExecutionModel, IncomingRayPayloadLoad) {
std::string execution_model = GetParam();
CompileSuccessfully(GenerateExecutionModelCode(execution_model,
"IncomingRayPayloadKHR", false)
.c_str(),
SPV_ENV_VULKAN_1_2);
if (execution_model.compare("AnyHitKHR") == 0 ||
execution_model.compare("ClosestHitKHR") == 0 ||
execution_model.compare("MissKHR") == 0) {
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
} else {
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
EXPECT_THAT(getDiagnosticString(),
AnyVUID("VUID-StandaloneSpirv-IncomingRayPayloadKHR-04699"));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("IncomingRayPayloadKHR Storage Class is limited to "
"AnyHitKHR, ClosestHitKHR, and MissKHR execution model"));
}
}
TEST_P(ValidateStorageExecutionModel, ShaderRecordBufferStore) {
std::string execution_model = GetParam();
CompileSuccessfully(
GenerateExecutionModelCode(execution_model, "ShaderRecordBufferKHR", true)
.c_str(),
SPV_ENV_VULKAN_1_2);
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("ShaderRecordBufferKHR Storage Class variables are read only"));
}
TEST_P(ValidateStorageExecutionModel, ShaderRecordBufferLoad) {
std::string execution_model = GetParam();
CompileSuccessfully(GenerateExecutionModelCode(execution_model,
"ShaderRecordBufferKHR", false)
.c_str(),
SPV_ENV_VULKAN_1_2);
if (execution_model.compare("RayGenerationKHR") == 0 ||
execution_model.compare("IntersectionKHR") == 0 ||
execution_model.compare("AnyHitKHR") == 0 ||
execution_model.compare("ClosestHitKHR") == 0 ||
execution_model.compare("CallableKHR") == 0 ||
execution_model.compare("MissKHR") == 0) {
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2));
} else {
ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2));
EXPECT_THAT(
getDiagnosticString(),
HasSubstr("ShaderRecordBufferKHR Storage Class is limited to "
"RayGenerationKHR, IntersectionKHR, AnyHitKHR, "
"ClosestHitKHR, CallableKHR, and MissKHR execution model"));
}
}
INSTANTIATE_TEST_SUITE_P(MatrixExecutionModel, ValidateStorageExecutionModel,
::testing::Values("RayGenerationKHR",
"IntersectionKHR", "AnyHitKHR",
"ClosestHitKHR", "MissKHR",
"CallableKHR"));
"CallableKHR", "GLCompute"));
} // namespace
} // namespace val