/*------------------------------------------------------------------------- * Vulkan Conformance Tests * ------------------------ * * Copyright (c) 2019 The Khronos Group Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief SPIR-V non semantic info tests *//*--------------------------------------------------------------------*/ #include "vkApiVersion.hpp" #include "vktSpvAsmNonSemanticInfoTests.hpp" #include "vktTestCase.hpp" #include "vktSpvAsmComputeShaderCase.hpp" #include "vktSpvAsmGraphicsShaderTestUtil.hpp" #include namespace vkt { namespace SpirVAssembly { using namespace vk; enum TestType { TT_BASIC = 0, TT_NONEXISTING_INSTRUCTION_SET, TT_LARGE_INSTRUCTION_NUMBER, TT_MANY_PARAMETERS, TT_ANY_CONSTANT_TYPE, TT_ANY_CONSTANT_TYPE_USED, TT_ANY_NON_CONSTANT_TYPE, TT_PLACEMENT }; static ComputeShaderSpec getComputeShaderSpec () { deUint32 numElements = 10; std::vector inoutFloats (10, 0); for (size_t ndx = 0; ndx < numElements; ++ndx) inoutFloats[ndx] = 1.0f * static_cast(ndx); // in one of tests we need to do imageLoad // we don't need any special values in here std::vector inputInts(256, 0); ComputeShaderSpec spec; spec.extensions.push_back("VK_KHR_shader_non_semantic_info"); spec.inputs.push_back(BufferSp(new Float32Buffer(inoutFloats))); spec.inputs.push_back(Resource(BufferSp(new Int32Buffer(inputInts)), vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)); spec.outputs.push_back(BufferSp(new Float32Buffer(inoutFloats))); spec.numWorkGroups = tcu::IVec3(numElements, 1, 1); return spec; } class SpvAsmSpirvNonSemanticInfoBasicInstance : public ComputeShaderSpec, public SpvAsmComputeShaderInstance { public: SpvAsmSpirvNonSemanticInfoBasicInstance (Context& ctx, TestType type); tcu::TestStatus iterate (void); protected: TestType m_testType; }; SpvAsmSpirvNonSemanticInfoBasicInstance::SpvAsmSpirvNonSemanticInfoBasicInstance(Context& ctx, TestType type) : ComputeShaderSpec(getComputeShaderSpec()) , SpvAsmComputeShaderInstance(ctx, *this) , m_testType(type) { } tcu::TestStatus SpvAsmSpirvNonSemanticInfoBasicInstance::iterate (void) { return SpvAsmComputeShaderInstance::iterate(); } class SpvAsmSpirvNonSemanticInfoBasicCase : public TestCase { public: SpvAsmSpirvNonSemanticInfoBasicCase (tcu::TestContext& testCtx, const char* name, TestType type); void checkSupport (Context& context) const; void initPrograms (vk::SourceCollections& programCollection) const; TestInstance* createInstance (Context& context) const; protected: TestType m_testType; }; SpvAsmSpirvNonSemanticInfoBasicCase::SpvAsmSpirvNonSemanticInfoBasicCase(tcu::TestContext& testCtx, const char* name, TestType type) : TestCase (testCtx, name, "") , m_testType(type) { } void SpvAsmSpirvNonSemanticInfoBasicCase::checkSupport(Context& context) const { context.requireDeviceFunctionality("VK_KHR_shader_non_semantic_info"); } void SpvAsmSpirvNonSemanticInfoBasicCase::initPrograms (SourceCollections& programCollection) const { std::string extendedInstructions = "%extInstSet = OpExtInstImport \"NonSemantic.KHR.DebugInfo\"\n"; std::string additionalDecorations = ""; std::string additionalPreamble = ""; std::string additionalTypesAndConst = ""; std::string beginningOfMain = ""; std::string middleOfMain = ""; switch (m_testType) { case TT_BASIC: // Minimal test of basic functionality additionalPreamble += "%fileStr = OpString \"path\\to\\source.file\"\n" "OpSource GLSL 430 %fileStr\n"; middleOfMain += "%tmp = OpExtInst %void %extInstSet 1 %main %fileStr\n"; break; case TT_NONEXISTING_INSTRUCTION_SET: // Testing non existing instruction set extendedInstructions = "%extInstSet = OpExtInstImport \"NonSemantic.P.B.NonexistingSet\"\n"; additionalPreamble += "%testStrA = OpString \"this.is.test\"\n" "%testStrB = OpString \"yet another test\"\n"; middleOfMain += "%tmpA = OpExtInst %void %extInstSet 55 %id %testStrA %testStrB\n" "OpLine %testStrA 1 1\n" "%tmpB = OpExtInst %void %extInstSet 99 %testStrA %main %testStrA\n" "OpLine %testStrB 2 2\n" "OpNoLine\n"; break; case TT_LARGE_INSTRUCTION_NUMBER: { // Any instruction number should work - testing large values near uint::max deUint32 instNr = std::numeric_limits::max() - 1; middleOfMain += "%tmpA = OpExtInst %void %extInstSet " + std::to_string(instNr) + " %main\n" + "%tmpB = OpExtInst %void %extInstSet 4294967290 %main\n"; break; } case TT_MANY_PARAMETERS: // Many parameters should work - testing 100 parameters middleOfMain += "%tmp = OpExtInst %void %extInstSet 1234"; for (deUint32 parameterIndex = 0; parameterIndex < 100; parameterIndex++) { std::string iStr = std::to_string(parameterIndex); std::string strVarName = std::string("%testStr") + iStr; additionalPreamble += strVarName + " = OpString \"" + iStr +"\"\n"; middleOfMain += std::string(" ") + strVarName; } middleOfMain += "\n"; break; case TT_ANY_CONSTANT_TYPE: case TT_ANY_CONSTANT_TYPE_USED: { // Any type of constant parameter should work - testing undef, // int, uint, float, struct, vector, array, string, matrix additionalDecorations = "OpMemberDecorate %struct 0 Offset 0\n" "OpMemberDecorate %struct 1 Offset 4\n" "OpMemberDecorate %struct 2 Offset 16\n"; std::string types = "%struct = OpTypeStruct %f32 %fvec3 %i32\n" "%c_array_size = OpConstant %u32 4\n" "%array4 = OpTypeArray %f32 %c_array_size\n" "%matrix3x3 = OpTypeMatrix %fvec3 3\n"; std::string constans = "%undef = OpUndef %i32\n" "%c_i32 = OpConstant %i32 -45\n" "%c_u32 = OpConstant %u32 99\n" "%c_f32 = OpConstant %f32 0.0\n" "%c_fvec3 = OpConstantComposite %fvec3 %c_f32 %c_f32 %c_f32\n" "%c_struct = OpConstantComposite %struct %c_f32 %c_fvec3 %undef\n" "%c_array = OpConstantComposite %array4 %c_f32 %c_f32 %c_f32 %c_f32\n" "%c_matrix = OpConstantComposite %matrix3x3 %c_fvec3 %c_fvec3 %c_fvec3\n"; additionalPreamble += "%testStr = OpString \"\"\n"; additionalTypesAndConst = types + constans; middleOfMain += "%tmp = OpExtInst %void %extInstSet 999 %main %undef %c_i32 %c_u32 %c_f32 %c_struct %c_fvec3 %c_array %testStr %c_matrix\n"; if (m_testType == TT_ANY_CONSTANT_TYPE) break; // use all constans outside of OpExtInst middleOfMain += "%tmp01 = OpCompositeExtract %f32 %c_fvec3 2\n" "%tmp02 = OpFAdd %f32 %tmp01 %c_f32\n" "%tmp03 = OpCompositeExtract %f32 %c_struct 0\n" "%tmp04 = OpFAdd %f32 %tmp02 %tmp03\n" "%tmp05 = OpCompositeExtract %f32 %c_array 1\n" "%tmp06 = OpFAdd %f32 %tmp04 %tmp05\n" "%tmp07 = OpCompositeExtract %fvec3 %c_matrix 1\n" "%tmp08 = OpCompositeExtract %f32 %tmp07 1\n" "%tmp09 = OpFMul %f32 %tmp06 %tmp08\n" "%tmp10 = OpConvertSToF %f32 %c_i32\n" "%tmp11 = OpFMul %f32 %tmp09 %tmp10\n" " OpStore %outloc %tmp11\n"; break; } case TT_ANY_NON_CONSTANT_TYPE: { // Any type of existing semantic result ID should be referencable. Testing // the result of a semantic OpExtInst, an entry point, variables of different types, // result IDs of buffer and texture loads, result IDs of arithmetic instructions, // result of an OpLoad, result of a comparison / logical instruction. additionalDecorations = "OpMemberDecorate %struct 0 Offset 0\n" "OpMemberDecorate %struct 1 Offset 4\n" "OpMemberDecorate %struct 2 Offset 16\n"; extendedInstructions += "%std450 = OpExtInstImport \"GLSL.std.450\"\n"; additionalTypesAndConst = "%struct = OpTypeStruct %f32 %fvec3 %f32\n" "%struct_ptr = OpTypePointer Function %struct\n" "%c_array_size = OpConstant %u32 4\n" "%array4 = OpTypeArray %f32 %c_array_size\n" "%array4_ptr = OpTypePointer Function %array4\n" "%matrix3x3 = OpTypeMatrix %fvec3 3\n" "%matrix3x3_ptr = OpTypePointer Function %matrix3x3\n" "%uvec2 = OpTypeVector %u32 2\n" "%fvec4 = OpTypeVector %f32 4\n" "%uv = OpConstantComposite %uvec2 %zero %zero\n"; beginningOfMain = "%struct_var = OpVariable %struct_ptr Function\n" "%array_var = OpVariable %array4_ptr Function\n" "%matrix_var = OpVariable %matrix3x3_ptr Function\n"; middleOfMain = "%tmp01 = OpExtInst %void %extInstSet 486 %main %id %x %idval %struct_var %array_var %matrix_var %uvec3ptr %indata\n" "%arithmRes = OpIAdd %u32 %x %x\n" "%extInstRes = OpExtInst %f32 %std450 FAbs %inval\n" "%logicRes = OpIsNan %bool %inval\n" "%imgLoadRes = OpLoad %image_type %image\n" "%tmp02 = OpExtInst %void %extInstSet 963 %tmp01 %arithmRes %inloc %outloc %inval %extInstRes %logicRes %imgLoadRes %std450\n"; break; } case TT_PLACEMENT: // The instructions should be able to be placed at global scope, // in the types/constants section and between function definitions additionalTypesAndConst = "%extInstA = OpExtInst %void %extInstSet 1 %id\n" // at global scope "%floatf = OpTypeFunction %f32 %f32\n" "%funDefA = OpFunction %f32 None %floatf\n" "%funApa = OpFunctionParameter %f32\n" "%funA = OpLabel\n" " OpReturnValue %funApa\n" " OpFunctionEnd\n" "%extInstB = OpExtInst %void %extInstSet 3 %id\n"; // between definitions middleOfMain += "%aRes = OpFunctionCall %f32 %funDefA %inval\n" "%extInstC = OpExtInst %void %extInstSet 4 %aRes\n" // within a block " OpStore %outloc %aRes\n"; break; } std::string source = getComputeAsmShaderPreamble("", "OpExtension \"SPV_KHR_non_semantic_info\"\n" + extendedInstructions) + additionalPreamble + "OpDecorate %id BuiltIn GlobalInvocationId\n" + "OpDecorate %buf BufferBlock\n" "OpDecorate %indata DescriptorSet 0\n" "OpDecorate %indata Binding 0\n" "OpDecorate %image DescriptorSet 0\n" "OpDecorate %image Binding 1\n" "OpDecorate %image NonWritable\n" "OpDecorate %outdata DescriptorSet 0\n" "OpDecorate %outdata Binding 2\n" "OpDecorate %f32arr ArrayStride 4\n" "OpMemberDecorate %buf 0 Offset 0\n" + additionalDecorations + std::string(getComputeAsmCommonTypes()) + std::string(getComputeAsmInputOutputBuffer()) + "%id = OpVariable %uvec3ptr Input\n" "%image_type = OpTypeImage %f32 2D 0 0 0 2 Rgba8\n" "%image_ptr = OpTypePointer UniformConstant %image_type\n" "%image = OpVariable %image_ptr UniformConstant\n" "%zero = OpConstant %i32 0\n" + additionalTypesAndConst + "%main = OpFunction %void None %voidf\n" "%label = OpLabel\n" + beginningOfMain + "%idval = OpLoad %uvec3 %id\n" "%x = OpCompositeExtract %u32 %idval 0\n" "%inloc = OpAccessChain %f32ptr %indata %zero %x\n" "%outloc = OpAccessChain %f32ptr %outdata %zero %x\n" "%inval = OpLoad %f32 %inloc\n" + middleOfMain + " OpStore %outloc %inval\n" " OpReturn\n" " OpFunctionEnd\n"; programCollection.spirvAsmSources.add("compute") << source; } TestInstance* SpvAsmSpirvNonSemanticInfoBasicCase::createInstance (Context& context) const { return new SpvAsmSpirvNonSemanticInfoBasicInstance(context, m_testType); } tcu::TestCaseGroup* createNonSemanticInfoGroup(tcu::TestContext& testCtx) { de::MovePtr group (new tcu::TestCaseGroup(testCtx, "non_semantic_info", "Test for VK_KHR_shader_non_semantic_info")); struct TestData { const char* name; TestType type; }; std::vector testList = { { "basic", TT_BASIC }, { "dummy_instruction_set", TT_NONEXISTING_INSTRUCTION_SET }, { "large_instruction_number", TT_LARGE_INSTRUCTION_NUMBER }, { "many_parameters", TT_MANY_PARAMETERS }, { "any_constant_type", TT_ANY_CONSTANT_TYPE }, { "any_constant_type_used", TT_ANY_CONSTANT_TYPE_USED }, { "any_non_constant_type", TT_ANY_NON_CONSTANT_TYPE }, { "placement", TT_PLACEMENT }, }; for (const auto& item : testList) group->addChild(new SpvAsmSpirvNonSemanticInfoBasicCase(testCtx, item.name, item.type)); return group.release(); } } // SpirVAssembly } // vkt