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_DUMMY_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 deUint32 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, TestType type)
109 : TestCase (testCtx, name, "")
110 , m_testType(type)
111 {
112 }
113
checkSupport(Context & context) const114 void SpvAsmSpirvNonSemanticInfoBasicCase::checkSupport(Context& context) const
115 {
116 context.requireDeviceFunctionality("VK_KHR_shader_non_semantic_info");
117 }
118
initPrograms(SourceCollections & programCollection) const119 void SpvAsmSpirvNonSemanticInfoBasicCase::initPrograms (SourceCollections& programCollection) const
120 {
121 std::string extendedInstructions = "%extInstSet = OpExtInstImport \"NonSemantic.KHR.DebugInfo\"\n";
122 std::string additionalDecorations = "";
123 std::string additionalPreamble = "";
124 std::string additionalTypesAndConst = "";
125 std::string beginningOfMain = "";
126 std::string middleOfMain = "";
127
128 switch (m_testType)
129 {
130 case TT_BASIC:
131 // Minimal test of basic functionality
132
133 additionalPreamble +=
134 "%fileStr = OpString \"path\\to\\source.file\"\n"
135 "OpSource GLSL 430 %fileStr\n";
136 middleOfMain +=
137 "%tmp = OpExtInst %void %extInstSet 1 %main %fileStr\n";
138 break;
139
140 case TT_DUMMY_INSTRUCTION_SET:
141 // Testing non existing instruction set
142
143 extendedInstructions =
144 "%extInstSet = OpExtInstImport \"NonSemantic.P.B.DummySet\"\n";
145 additionalPreamble +=
146 "%testStrA = OpString \"this.is.test\"\n"
147 "%testStrB = OpString \"yet another test\"\n";
148 middleOfMain +=
149 "%tmpA = OpExtInst %void %extInstSet 55 %id %testStrA %testStrB\n"
150 "OpLine %testStrA 1 1\n"
151 "%tmpB = OpExtInst %void %extInstSet 99 %testStrA %main %testStrA\n"
152 "OpLine %testStrB 2 2\n"
153 "OpNoLine\n";
154 break;
155
156 case TT_LARGE_INSTRUCTION_NUMBER:
157 {
158 // Any instruction number should work - testing large values near uint::max
159
160 deUint32 instNr = std::numeric_limits<deUint32>::max() - 1;
161 middleOfMain +=
162 "%tmpA = OpExtInst %void %extInstSet " + std::to_string(instNr) + " %main\n" +
163 "%tmpB = OpExtInst %void %extInstSet 4294967290 %main\n";
164 break;
165 }
166
167 case TT_MANY_PARAMETERS:
168 // Many parameters should work - testing 100 parameters
169
170 middleOfMain +=
171 "%tmp = OpExtInst %void %extInstSet 1234";
172 for (deUint32 parameterIndex = 0; parameterIndex < 100; parameterIndex++)
173 {
174 std::string iStr = std::to_string(parameterIndex);
175 std::string strVarName = std::string("%testStr") + iStr;
176 additionalPreamble += strVarName + " = OpString \"" + iStr +"\"\n";
177 middleOfMain += std::string(" ") + strVarName;
178 }
179 middleOfMain += "\n";
180 break;
181
182 case TT_ANY_CONSTANT_TYPE:
183 case TT_ANY_CONSTANT_TYPE_USED:
184 {
185 // Any type of constant parameter should work - testing undef,
186 // int, uint, float, struct, vector, array, string, matrix
187
188 additionalDecorations =
189 "OpMemberDecorate %struct 0 Offset 0\n"
190 "OpMemberDecorate %struct 1 Offset 4\n"
191 "OpMemberDecorate %struct 2 Offset 16\n";
192
193 std::string types =
194 "%struct = OpTypeStruct %f32 %fvec3 %i32\n"
195 "%c_array_size = OpConstant %u32 4\n"
196 "%array4 = OpTypeArray %f32 %c_array_size\n"
197 "%matrix3x3 = OpTypeMatrix %fvec3 3\n";
198
199 std::string constans =
200 "%undef = OpUndef %i32\n"
201 "%c_i32 = OpConstant %i32 -45\n"
202 "%c_u32 = OpConstant %u32 99\n"
203 "%c_f32 = OpConstant %f32 0.0\n"
204 "%c_fvec3 = OpConstantComposite %fvec3 %c_f32 %c_f32 %c_f32\n"
205 "%c_struct = OpConstantComposite %struct %c_f32 %c_fvec3 %undef\n"
206 "%c_array = OpConstantComposite %array4 %c_f32 %c_f32 %c_f32 %c_f32\n"
207 "%c_matrix = OpConstantComposite %matrix3x3 %c_fvec3 %c_fvec3 %c_fvec3\n";
208
209 additionalPreamble +=
210 "%testStr = OpString \"\"\n";
211 additionalTypesAndConst = types + constans;
212 middleOfMain += "%tmp = OpExtInst %void %extInstSet 999 %main %undef %c_i32 %c_u32 %c_f32 %c_struct %c_fvec3 %c_array %testStr %c_matrix\n";
213 if (m_testType == TT_ANY_CONSTANT_TYPE)
214 break;
215
216 // use all constans outside of OpExtInst
217 middleOfMain +=
218 "%tmp01 = OpCompositeExtract %f32 %c_fvec3 2\n"
219 "%tmp02 = OpFAdd %f32 %tmp01 %c_f32\n"
220 "%tmp03 = OpCompositeExtract %f32 %c_struct 0\n"
221 "%tmp04 = OpFAdd %f32 %tmp02 %tmp03\n"
222 "%tmp05 = OpCompositeExtract %f32 %c_array 1\n"
223 "%tmp06 = OpFAdd %f32 %tmp04 %tmp05\n"
224 "%tmp07 = OpCompositeExtract %fvec3 %c_matrix 1\n"
225 "%tmp08 = OpCompositeExtract %f32 %tmp07 1\n"
226 "%tmp09 = OpFMul %f32 %tmp06 %tmp08\n"
227 "%tmp10 = OpConvertSToF %f32 %c_i32\n"
228 "%tmp11 = OpFMul %f32 %tmp09 %tmp10\n"
229 " OpStore %outloc %tmp11\n";
230 break;
231 }
232
233 case TT_ANY_NON_CONSTANT_TYPE:
234 {
235 // Any type of existing semantic result ID should be referencable. Testing
236 // the result of a semantic OpExtInst, an entry point, variables of different types,
237 // result IDs of buffer and texture loads, result IDs of arithmetic instructions,
238 // result of an OpLoad, result of a comparison / logical instruction.
239
240 additionalDecorations =
241 "OpMemberDecorate %struct 0 Offset 0\n"
242 "OpMemberDecorate %struct 1 Offset 4\n"
243 "OpMemberDecorate %struct 2 Offset 16\n";
244 extendedInstructions +=
245 "%std450 = OpExtInstImport \"GLSL.std.450\"\n";
246 additionalTypesAndConst =
247 "%struct = OpTypeStruct %f32 %fvec3 %f32\n"
248 "%struct_ptr = OpTypePointer Function %struct\n"
249 "%c_array_size = OpConstant %u32 4\n"
250 "%array4 = OpTypeArray %f32 %c_array_size\n"
251 "%array4_ptr = OpTypePointer Function %array4\n"
252 "%matrix3x3 = OpTypeMatrix %fvec3 3\n"
253 "%matrix3x3_ptr = OpTypePointer Function %matrix3x3\n"
254 "%uvec2 = OpTypeVector %u32 2\n"
255 "%fvec4 = OpTypeVector %f32 4\n"
256 "%uv = OpConstantComposite %uvec2 %zero %zero\n";
257
258 beginningOfMain =
259 "%struct_var = OpVariable %struct_ptr Function\n"
260 "%array_var = OpVariable %array4_ptr Function\n"
261 "%matrix_var = OpVariable %matrix3x3_ptr Function\n";
262 middleOfMain =
263 "%tmp01 = OpExtInst %void %extInstSet 486 %main %id %x %idval %struct_var %array_var %matrix_var %uvec3ptr %indata\n"
264 "%arithmRes = OpIAdd %u32 %x %x\n"
265 "%extInstRes = OpExtInst %f32 %std450 FAbs %inval\n"
266 "%logicRes = OpIsNan %bool %inval\n"
267 "%imgLoadRes = OpLoad %image_type %image\n"
268 "%tmp02 = OpExtInst %void %extInstSet 963 %tmp01 %arithmRes %inloc %outloc %inval %extInstRes %logicRes %imgLoadRes %std450\n";
269 break;
270 }
271
272 case TT_PLACEMENT:
273 // The instructions should be able to be placed at global scope,
274 // in the types/constants section and between function definitions
275
276 additionalTypesAndConst =
277 "%extInstA = OpExtInst %void %extInstSet 1 %id\n" // at global scope
278 "%floatf = OpTypeFunction %f32 %f32\n"
279 "%funDefA = OpFunction %f32 None %floatf\n"
280 "%funApa = OpFunctionParameter %f32\n"
281 "%funA = OpLabel\n"
282 " OpReturnValue %funApa\n"
283 " OpFunctionEnd\n"
284 "%extInstB = OpExtInst %void %extInstSet 3 %id\n"; // between definitions
285 middleOfMain +=
286 "%aRes = OpFunctionCall %f32 %funDefA %inval\n"
287 "%extInstC = OpExtInst %void %extInstSet 4 %aRes\n" // within a block
288 " OpStore %outloc %aRes\n";
289 break;
290 }
291
292 std::string source =
293 getComputeAsmShaderPreamble("", "OpExtension \"SPV_KHR_non_semantic_info\"\n" + extendedInstructions) +
294 additionalPreamble +
295 "OpDecorate %id BuiltIn GlobalInvocationId\n" +
296 "OpDecorate %buf BufferBlock\n"
297 "OpDecorate %indata DescriptorSet 0\n"
298 "OpDecorate %indata Binding 0\n"
299 "OpDecorate %image DescriptorSet 0\n"
300 "OpDecorate %image Binding 1\n"
301 "OpDecorate %image NonWritable\n"
302 "OpDecorate %outdata DescriptorSet 0\n"
303 "OpDecorate %outdata Binding 2\n"
304 "OpDecorate %f32arr ArrayStride 4\n"
305 "OpMemberDecorate %buf 0 Offset 0\n" +
306 additionalDecorations +
307 std::string(getComputeAsmCommonTypes()) +
308 std::string(getComputeAsmInputOutputBuffer()) +
309 "%id = OpVariable %uvec3ptr Input\n"
310 "%image_type = OpTypeImage %f32 2D 0 0 0 2 Rgba8\n"
311 "%image_ptr = OpTypePointer UniformConstant %image_type\n"
312 "%image = OpVariable %image_ptr UniformConstant\n"
313 "%zero = OpConstant %i32 0\n" +
314 additionalTypesAndConst +
315 "%main = OpFunction %void None %voidf\n"
316 "%label = OpLabel\n" +
317 beginningOfMain +
318 "%idval = OpLoad %uvec3 %id\n"
319 "%x = OpCompositeExtract %u32 %idval 0\n"
320 "%inloc = OpAccessChain %f32ptr %indata %zero %x\n"
321 "%outloc = OpAccessChain %f32ptr %outdata %zero %x\n"
322 "%inval = OpLoad %f32 %inloc\n" +
323 middleOfMain +
324 " OpStore %outloc %inval\n"
325 " OpReturn\n"
326 " OpFunctionEnd\n";
327
328 programCollection.spirvAsmSources.add("compute") << source;
329 }
330
createInstance(Context & context) const331 TestInstance* SpvAsmSpirvNonSemanticInfoBasicCase::createInstance (Context& context) const
332 {
333 return new SpvAsmSpirvNonSemanticInfoBasicInstance(context, m_testType);
334 }
335
createNonSemanticInfoGroup(tcu::TestContext & testCtx)336 tcu::TestCaseGroup* createNonSemanticInfoGroup(tcu::TestContext& testCtx)
337 {
338 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "non_semantic_info", "Test for VK_KHR_shader_non_semantic_info"));
339
340 struct TestData
341 {
342 const char* name;
343 TestType type;
344 };
345 std::vector<TestData> testList =
346 {
347 { "basic", TT_BASIC },
348 { "dummy_instruction_set", TT_DUMMY_INSTRUCTION_SET },
349 { "large_instruction_number", TT_LARGE_INSTRUCTION_NUMBER },
350 { "many_parameters", TT_MANY_PARAMETERS },
351 { "any_constant_type", TT_ANY_CONSTANT_TYPE },
352 { "any_constant_type_used", TT_ANY_CONSTANT_TYPE_USED },
353 { "any_non_constant_type", TT_ANY_NON_CONSTANT_TYPE },
354 { "placement", TT_PLACEMENT },
355 };
356
357 for (const auto& item : testList)
358 group->addChild(new SpvAsmSpirvNonSemanticInfoBasicCase(testCtx, item.name, item.type));
359
360 return group.release();
361 }
362
363 } // SpirVAssembly
364 } // vkt
365