1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2019 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief SPIR-V non semantic info tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vkApiVersion.hpp"
25 
26 #include "vktSpvAsmNonSemanticInfoTests.hpp"
27 #include "vktTestCase.hpp"
28 #include "vktSpvAsmComputeShaderCase.hpp"
29 #include "vktSpvAsmGraphicsShaderTestUtil.hpp"
30 
31 #include <limits>
32 
33 namespace vkt
34 {
35 namespace SpirVAssembly
36 {
37 
38 using namespace vk;
39 
40 enum TestType
41 {
42     TT_BASIC = 0,
43     TT_NONEXISTING_INSTRUCTION_SET,
44     TT_LARGE_INSTRUCTION_NUMBER,
45     TT_MANY_PARAMETERS,
46     TT_ANY_CONSTANT_TYPE,
47     TT_ANY_CONSTANT_TYPE_USED,
48     TT_ANY_NON_CONSTANT_TYPE,
49     TT_PLACEMENT
50 };
51 
getComputeShaderSpec()52 static ComputeShaderSpec getComputeShaderSpec()
53 {
54     uint32_t numElements = 10;
55     std::vector<float> inoutFloats(10, 0);
56     for (size_t ndx = 0; ndx < numElements; ++ndx)
57         inoutFloats[ndx] = 1.0f * static_cast<float>(ndx);
58 
59     // in one of tests we need to do imageLoad
60     // we don't need any special values in here
61     std::vector<int> inputInts(256, 0);
62 
63     ComputeShaderSpec spec;
64     spec.extensions.push_back("VK_KHR_shader_non_semantic_info");
65     spec.inputs.push_back(BufferSp(new Float32Buffer(inoutFloats)));
66     spec.inputs.push_back(Resource(BufferSp(new Int32Buffer(inputInts)), vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE));
67     spec.outputs.push_back(BufferSp(new Float32Buffer(inoutFloats)));
68     spec.numWorkGroups = tcu::IVec3(numElements, 1, 1);
69     return spec;
70 }
71 
72 class SpvAsmSpirvNonSemanticInfoBasicInstance : public ComputeShaderSpec, public SpvAsmComputeShaderInstance
73 {
74 public:
75     SpvAsmSpirvNonSemanticInfoBasicInstance(Context &ctx, TestType type);
76 
77     tcu::TestStatus iterate(void);
78 
79 protected:
80     TestType m_testType;
81 };
82 
SpvAsmSpirvNonSemanticInfoBasicInstance(Context & ctx,TestType type)83 SpvAsmSpirvNonSemanticInfoBasicInstance::SpvAsmSpirvNonSemanticInfoBasicInstance(Context &ctx, TestType type)
84     : ComputeShaderSpec(getComputeShaderSpec())
85     , SpvAsmComputeShaderInstance(ctx, *this)
86     , m_testType(type)
87 {
88 }
89 
iterate(void)90 tcu::TestStatus SpvAsmSpirvNonSemanticInfoBasicInstance::iterate(void)
91 {
92     return SpvAsmComputeShaderInstance::iterate();
93 }
94 
95 class SpvAsmSpirvNonSemanticInfoBasicCase : public TestCase
96 {
97 public:
98     SpvAsmSpirvNonSemanticInfoBasicCase(tcu::TestContext &testCtx, const char *name, TestType type);
99 
100     void checkSupport(Context &context) const;
101     void initPrograms(vk::SourceCollections &programCollection) const;
102     TestInstance *createInstance(Context &context) const;
103 
104 protected:
105     TestType m_testType;
106 };
107 
SpvAsmSpirvNonSemanticInfoBasicCase(tcu::TestContext & testCtx,const char * name,TestType type)108 SpvAsmSpirvNonSemanticInfoBasicCase::SpvAsmSpirvNonSemanticInfoBasicCase(tcu::TestContext &testCtx, const char *name,
109                                                                          TestType type)
110     : TestCase(testCtx, name)
111     , m_testType(type)
112 {
113 }
114 
checkSupport(Context & context) const115 void SpvAsmSpirvNonSemanticInfoBasicCase::checkSupport(Context &context) const
116 {
117     context.requireDeviceFunctionality("VK_KHR_shader_non_semantic_info");
118 }
119 
initPrograms(SourceCollections & programCollection) const120 void SpvAsmSpirvNonSemanticInfoBasicCase::initPrograms(SourceCollections &programCollection) const
121 {
122     std::string extendedInstructions    = "%extInstSet = OpExtInstImport \"NonSemantic.KHR.DebugInfo\"\n";
123     std::string additionalDecorations   = "";
124     std::string additionalPreamble      = "";
125     std::string additionalTypesAndConst = "";
126     std::string beginningOfMain         = "";
127     std::string middleOfMain            = "";
128 
129     switch (m_testType)
130     {
131     case TT_BASIC:
132         // Minimal test of basic functionality
133 
134         additionalPreamble += "%fileStr = OpString \"path\\to\\source.file\"\n"
135                               "OpSource GLSL 430 %fileStr\n";
136         middleOfMain += "%tmp = OpExtInst %void %extInstSet 1 %main %fileStr\n";
137         break;
138 
139     case TT_NONEXISTING_INSTRUCTION_SET:
140         // Testing non existing instruction set
141 
142         extendedInstructions = "%extInstSet = OpExtInstImport \"NonSemantic.P.B.NonexistingSet\"\n";
143         additionalPreamble += "%testStrA = OpString \"this.is.test\"\n"
144                               "%testStrB = OpString \"yet another test\"\n";
145         middleOfMain += "%tmpA = OpExtInst %void %extInstSet 55 %id %testStrA %testStrB\n"
146                         "OpLine %testStrA 1 1\n"
147                         "%tmpB = OpExtInst %void %extInstSet 99 %testStrA %main %testStrA\n"
148                         "OpLine %testStrB 2 2\n"
149                         "OpNoLine\n";
150         break;
151 
152     case TT_LARGE_INSTRUCTION_NUMBER:
153     {
154         // Any instruction number should work - testing large values near uint::max
155 
156         uint32_t instNr = std::numeric_limits<uint32_t>::max() - 1;
157         middleOfMain += "%tmpA = OpExtInst %void %extInstSet " + std::to_string(instNr) + " %main\n" +
158                         "%tmpB = OpExtInst %void %extInstSet 4294967290 %main\n";
159         break;
160     }
161 
162     case TT_MANY_PARAMETERS:
163         // Many parameters should work - testing 100 parameters
164 
165         middleOfMain += "%tmp = OpExtInst %void %extInstSet 1234";
166         for (uint32_t parameterIndex = 0; parameterIndex < 100; parameterIndex++)
167         {
168             std::string iStr       = std::to_string(parameterIndex);
169             std::string strVarName = std::string("%testStr") + iStr;
170             additionalPreamble += strVarName + " = OpString \"" + iStr + "\"\n";
171             middleOfMain += std::string(" ") + strVarName;
172         }
173         middleOfMain += "\n";
174         break;
175 
176     case TT_ANY_CONSTANT_TYPE:
177     case TT_ANY_CONSTANT_TYPE_USED:
178     {
179         // Any type of constant parameter should work - testing undef,
180         // int, uint, float, struct, vector, array, string, matrix
181 
182         additionalDecorations = "OpMemberDecorate %struct 0 Offset 0\n"
183                                 "OpMemberDecorate %struct 1 Offset 4\n"
184                                 "OpMemberDecorate %struct 2 Offset 16\n";
185 
186         std::string types = "%struct             = OpTypeStruct %f32 %fvec3 %i32\n"
187                             "%c_array_size       = OpConstant %u32 4\n"
188                             "%array4             = OpTypeArray %f32 %c_array_size\n"
189                             "%matrix3x3          = OpTypeMatrix %fvec3 3\n";
190 
191         std::string constans = "%undef      = OpUndef %i32\n"
192                                "%c_i32      = OpConstant %i32 -45\n"
193                                "%c_u32      = OpConstant %u32 99\n"
194                                "%c_f32      = OpConstant %f32 0.0\n"
195                                "%c_fvec3    = OpConstantComposite %fvec3 %c_f32 %c_f32 %c_f32\n"
196                                "%c_struct   = OpConstantComposite %struct %c_f32 %c_fvec3 %undef\n"
197                                "%c_array    = OpConstantComposite %array4 %c_f32 %c_f32 %c_f32 %c_f32\n"
198                                "%c_matrix   = OpConstantComposite %matrix3x3 %c_fvec3 %c_fvec3 %c_fvec3\n";
199 
200         additionalPreamble += "%testStr = OpString \"\"\n";
201         additionalTypesAndConst = types + constans;
202         middleOfMain += "%tmp = OpExtInst %void %extInstSet 999 %main %undef %c_i32 %c_u32 %c_f32 %c_struct %c_fvec3 "
203                         "%c_array %testStr %c_matrix\n";
204         if (m_testType == TT_ANY_CONSTANT_TYPE)
205             break;
206 
207         // use all constans outside of OpExtInst
208         middleOfMain += "%tmp01      = OpCompositeExtract %f32 %c_fvec3 2\n"
209                         "%tmp02      = OpFAdd %f32 %tmp01 %c_f32\n"
210                         "%tmp03      = OpCompositeExtract %f32 %c_struct 0\n"
211                         "%tmp04      = OpFAdd %f32 %tmp02 %tmp03\n"
212                         "%tmp05      = OpCompositeExtract %f32 %c_array 1\n"
213                         "%tmp06      = OpFAdd %f32 %tmp04 %tmp05\n"
214                         "%tmp07      = OpCompositeExtract %fvec3 %c_matrix 1\n"
215                         "%tmp08      = OpCompositeExtract %f32 %tmp07 1\n"
216                         "%tmp09      = OpFMul %f32 %tmp06 %tmp08\n"
217                         "%tmp10      = OpConvertSToF %f32 %c_i32\n"
218                         "%tmp11      = OpFMul %f32 %tmp09 %tmp10\n"
219                         "              OpStore %outloc %tmp11\n";
220         break;
221     }
222 
223     case TT_ANY_NON_CONSTANT_TYPE:
224     {
225         // Any type of existing semantic result ID should be referencable. Testing
226         // the result of a semantic OpExtInst, an entry point, variables of different types,
227         // result IDs of buffer and texture loads, result IDs of arithmetic instructions,
228         // result of an OpLoad, result of a comparison / logical instruction.
229 
230         additionalDecorations = "OpMemberDecorate %struct 0 Offset 0\n"
231                                 "OpMemberDecorate %struct 1 Offset 4\n"
232                                 "OpMemberDecorate %struct 2 Offset 16\n";
233         extendedInstructions += "%std450 = OpExtInstImport \"GLSL.std.450\"\n";
234         additionalTypesAndConst = "%struct             = OpTypeStruct %f32 %fvec3 %f32\n"
235                                   "%struct_ptr         = OpTypePointer Function %struct\n"
236                                   "%c_array_size       = OpConstant %u32 4\n"
237                                   "%array4             = OpTypeArray %f32 %c_array_size\n"
238                                   "%array4_ptr         = OpTypePointer Function %array4\n"
239                                   "%matrix3x3          = OpTypeMatrix %fvec3 3\n"
240                                   "%matrix3x3_ptr      = OpTypePointer Function %matrix3x3\n"
241                                   "%ivec2              = OpTypeVector %i32 2\n"
242                                   "%fvec4              = OpTypeVector %f32 4\n"
243                                   "%uv                 = OpConstantComposite %ivec2 %zero %zero\n";
244 
245         beginningOfMain = "%struct_var = OpVariable %struct_ptr Function\n"
246                           "%array_var  = OpVariable %array4_ptr Function\n"
247                           "%matrix_var = OpVariable %matrix3x3_ptr Function\n";
248         middleOfMain    = "%tmp01      = OpExtInst %void %extInstSet 486 %main %id %x %idval %struct_var %array_var "
249                           "%matrix_var %uvec3ptr %indata\n"
250                           "%arithmRes  = OpIAdd %u32 %x %x\n"
251                           "%extInstRes = OpExtInst %f32 %std450 FAbs %inval\n"
252                           "%logicRes   = OpIsNan %bool %inval\n"
253                           "%imgLoadRes = OpLoad %image_type %image\n"
254                           "%tmp02      = OpExtInst %void %extInstSet 963 %tmp01 %arithmRes %inloc %outloc %inval "
255                           "%extInstRes %logicRes %imgLoadRes %std450\n";
256         break;
257     }
258 
259     case TT_PLACEMENT:
260         // The instructions should be able to be placed at global scope,
261         // in the types/constants section and between function definitions
262 
263         additionalTypesAndConst = "%extInstA   = OpExtInst %void %extInstSet 1 %id\n" // at global scope
264                                   "%floatf     = OpTypeFunction %f32 %f32\n"
265                                   "%funDefA    = OpFunction %f32 None %floatf\n"
266                                   "%funApa     = OpFunctionParameter %f32\n"
267                                   "%funA       = OpLabel\n"
268                                   "              OpReturnValue %funApa\n"
269                                   "              OpFunctionEnd\n"
270                                   "%extInstB  = OpExtInst %void %extInstSet 3 %id\n"; // between definitions
271         middleOfMain += "%aRes       = OpFunctionCall %f32 %funDefA %inval\n"
272                         "%extInstC   = OpExtInst %void %extInstSet 4 %aRes\n" // within a block
273                         "              OpStore %outloc %aRes\n";
274         break;
275     }
276 
277     std::string source =
278         getComputeAsmShaderPreamble("", "OpExtension \"SPV_KHR_non_semantic_info\"\n" + extendedInstructions) +
279         additionalPreamble + "OpDecorate %id BuiltIn GlobalInvocationId\n" +
280         "OpDecorate %buf BufferBlock\n"
281         "OpDecorate %indata DescriptorSet 0\n"
282         "OpDecorate %indata Binding 0\n"
283         "OpDecorate %image DescriptorSet 0\n"
284         "OpDecorate %image Binding 1\n"
285         "OpDecorate %image NonWritable\n"
286         "OpDecorate %outdata DescriptorSet 0\n"
287         "OpDecorate %outdata Binding 2\n"
288         "OpDecorate %f32arr ArrayStride 4\n"
289         "OpMemberDecorate %buf 0 Offset 0\n" +
290         additionalDecorations + std::string(getComputeAsmCommonTypes()) +
291         std::string(getComputeAsmInputOutputBuffer()) +
292         "%id         = OpVariable %uvec3ptr Input\n"
293         "%image_type = OpTypeImage %f32 2D 0 0 0 2 Rgba8\n"
294         "%image_ptr  = OpTypePointer UniformConstant %image_type\n"
295         "%image      = OpVariable %image_ptr UniformConstant\n"
296         "%zero       = OpConstant %i32 0\n" +
297         additionalTypesAndConst +
298         "%main       = OpFunction %void None %voidf\n"
299         "%label      = OpLabel\n" +
300         beginningOfMain +
301         "%idval      = OpLoad %uvec3 %id\n"
302         "%x          = OpCompositeExtract %u32 %idval 0\n"
303         "%inloc      = OpAccessChain %f32ptr %indata %zero %x\n"
304         "%outloc     = OpAccessChain %f32ptr %outdata %zero %x\n"
305         "%inval      = OpLoad %f32 %inloc\n" +
306         middleOfMain +
307         "             OpStore %outloc %inval\n"
308         "             OpReturn\n"
309         "             OpFunctionEnd\n";
310 
311     programCollection.spirvAsmSources.add("compute") << source;
312 }
313 
createInstance(Context & context) const314 TestInstance *SpvAsmSpirvNonSemanticInfoBasicCase::createInstance(Context &context) const
315 {
316     return new SpvAsmSpirvNonSemanticInfoBasicInstance(context, m_testType);
317 }
318 
createNonSemanticInfoGroup(tcu::TestContext & testCtx)319 tcu::TestCaseGroup *createNonSemanticInfoGroup(tcu::TestContext &testCtx)
320 {
321     // Test for VK_KHR_shader_non_semantic_info
322     de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "non_semantic_info"));
323 
324     struct TestData
325     {
326         const char *name;
327         TestType type;
328     };
329     std::vector<TestData> testList = {
330         {"basic", TT_BASIC},
331         {"dummy_instruction_set", TT_NONEXISTING_INSTRUCTION_SET},
332         {"large_instruction_number", TT_LARGE_INSTRUCTION_NUMBER},
333         {"many_parameters", TT_MANY_PARAMETERS},
334         {"any_constant_type", TT_ANY_CONSTANT_TYPE},
335         {"any_constant_type_used", TT_ANY_CONSTANT_TYPE_USED},
336         {"any_non_constant_type", TT_ANY_NON_CONSTANT_TYPE},
337         {"placement", TT_PLACEMENT},
338     };
339 
340     for (const auto &item : testList)
341         group->addChild(new SpvAsmSpirvNonSemanticInfoBasicCase(testCtx, item.name, item.type));
342 
343     return group.release();
344 }
345 
346 } // namespace SpirVAssembly
347 } // namespace vkt
348