1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2017 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 Versions check cases
22 *//*--------------------------------------------------------------------*/
23
24 #include "vkApiVersion.hpp"
25
26 #include "vktSpvAsmSpirvVersionTests.hpp"
27 #include "vktTestCase.hpp"
28 #include "vktSpvAsmComputeShaderCase.hpp"
29 #include "vktSpvAsmGraphicsShaderTestUtil.hpp"
30
31 namespace vkt
32 {
33 namespace SpirVAssembly
34 {
35
36 using namespace vk;
37 using std::map;
38 using std::string;
39 using std::vector;
40 using tcu::RGBA;
41
42 enum Operation
43 {
44 OPERATION_COMPUTE = 0,
45 OPERATION_GRAPHICS_VERTEX,
46 OPERATION_GRAPHICS_TESSELATION_EVALUATION,
47 OPERATION_GRAPHICS_TESSELATION_CONTROL,
48 OPERATION_GRAPHICS_GEOMETRY,
49 OPERATION_GRAPHICS_FRAGMENT,
50 OPERATION_LAST
51 };
52
operator ++(Operation & operation)53 Operation& operator++ (Operation& operation)
54 {
55 if (operation == OPERATION_LAST)
56 operation = OPERATION_COMPUTE;
57 else
58 operation = static_cast<Operation>(static_cast<deUint32>(operation) + 1);
59
60 return operation;
61 }
62
63 struct TestParameters
64 {
65 Operation operation;
66 SpirvVersion spirvVersion;
67 };
68
initGraphicsInstanceContext(const TestParameters & testParameters)69 static InstanceContext initGraphicsInstanceContext (const TestParameters& testParameters)
70 {
71 static const ShaderElement vertFragPipelineStages[] =
72 {
73 ShaderElement("vert", "main", VK_SHADER_STAGE_VERTEX_BIT),
74 ShaderElement("frag", "main", VK_SHADER_STAGE_FRAGMENT_BIT),
75 };
76 static const ShaderElement tessPipelineStages[] =
77 {
78 ShaderElement("vert", "main", VK_SHADER_STAGE_VERTEX_BIT),
79 ShaderElement("tessc", "main", VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT),
80 ShaderElement("tesse", "main", VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT),
81 ShaderElement("frag", "main", VK_SHADER_STAGE_FRAGMENT_BIT),
82 };
83 static const ShaderElement geomPipelineStages[] =
84 {
85 ShaderElement("vert", "main", VK_SHADER_STAGE_VERTEX_BIT),
86 ShaderElement("geom", "main", VK_SHADER_STAGE_GEOMETRY_BIT),
87 ShaderElement("frag", "main", VK_SHADER_STAGE_FRAGMENT_BIT),
88 };
89 map<string, string> opSimpleTest;
90
91 opSimpleTest["testfun"] =
92 "%test_code = OpFunction %v4f32 None %v4f32_v4f32_function\n"
93 "%param1 = OpFunctionParameter %v4f32\n"
94 "%label_testfun = OpLabel\n"
95 "%a = OpVectorExtractDynamic %f32 %param1 %c_i32_0\n"
96 "%b = OpFAdd %f32 %a %a\n"
97 "%c = OpFSub %f32 %b %a\n"
98 "%ret = OpVectorInsertDynamic %v4f32 %param1 %c %c_i32_0\n"
99 "OpReturnValue %ret\n"
100 "OpFunctionEnd\n";
101
102 if (testParameters.spirvVersion > SPIRV_VERSION_1_3)
103 opSimpleTest["GL_entrypoint"] = "%BP_vertexIdInCurrentPatch";
104
105 switch (testParameters.operation)
106 {
107 case OPERATION_GRAPHICS_VERTEX: return createInstanceContext(vertFragPipelineStages, opSimpleTest);
108 case OPERATION_GRAPHICS_TESSELATION_EVALUATION: return createInstanceContext(tessPipelineStages, opSimpleTest);
109 case OPERATION_GRAPHICS_TESSELATION_CONTROL: return createInstanceContext(tessPipelineStages, opSimpleTest);
110 case OPERATION_GRAPHICS_GEOMETRY: return createInstanceContext(geomPipelineStages, opSimpleTest);
111 case OPERATION_GRAPHICS_FRAGMENT: return createInstanceContext(vertFragPipelineStages, opSimpleTest);
112 default: TCU_THROW(InternalError, "Invalid operation specified");
113 }
114 }
115
getComputeSourceCode(std::string & computeSourceCode,SpirvVersion spirvVersion)116 static void getComputeSourceCode (std::string& computeSourceCode, SpirvVersion spirvVersion)
117 {
118 computeSourceCode = "";
119 if (spirvVersion > SPIRV_VERSION_1_3)
120 computeSourceCode += string(getComputeAsmShaderPreamble("", "", "", "", "%indata %outdata"));
121 else
122 computeSourceCode += string(getComputeAsmShaderPreamble());
123
124 computeSourceCode +=
125 "OpSource GLSL 430\n"
126 "OpName %main \"main\"\n"
127 "OpName %id \"gl_GlobalInvocationID\"\n"
128
129 "OpDecorate %id BuiltIn GlobalInvocationId\n" +
130
131 string(getComputeAsmInputOutputBufferTraits((spirvVersion > SPIRV_VERSION_1_3) ? "Block" : "BufferBlock")) +
132 string(getComputeAsmCommonTypes((spirvVersion > SPIRV_VERSION_1_3) ? "StorageBuffer" : "Uniform")) +
133 string(getComputeAsmInputOutputBuffer((spirvVersion > SPIRV_VERSION_1_3) ? "StorageBuffer" : "Uniform")) +
134
135 "%id = OpVariable %uvec3ptr Input\n"
136 "%zero = OpConstant %i32 0\n"
137
138 "%main = OpFunction %void None %voidf\n"
139 "%label = OpLabel\n"
140 "%idval = OpLoad %uvec3 %id\n"
141 "%x = OpCompositeExtract %u32 %idval 0\n"
142
143 " OpNop\n" // Inside a function body
144
145 "%inloc = OpAccessChain %f32ptr %indata %zero %x\n"
146 "%inval = OpLoad %f32 %inloc\n"
147 "%neg = OpFNegate %f32 %inval\n"
148 "%outloc = OpAccessChain %f32ptr %outdata %zero %x\n"
149 " OpStore %outloc %neg\n"
150 " OpReturn\n"
151 " OpFunctionEnd\n";
152 }
153
getComputeShaderSpec(const TestParameters & testParameters)154 static ComputeShaderSpec getComputeShaderSpec (const TestParameters& testParameters)
155 {
156 ComputeShaderSpec spec;
157 const deUint32 seed = (static_cast<deUint32>(testParameters.operation)<<16) ^ static_cast<deUint32>(testParameters.spirvVersion);
158 de::Random rnd (seed);
159 const int numElements = 100;
160 vector<float> positiveFloats (numElements, 0);
161 vector<float> negativeFloats (numElements, 0);
162
163 for (size_t ndx = 0; ndx < numElements; ++ndx)
164 {
165 positiveFloats[ndx] = rnd.getFloat(1.0f, 100.0f);
166 negativeFloats[ndx] = -positiveFloats[ndx];
167 }
168
169 // Shader source code can be retrieved to complete definition of ComputeShaderSpec, though it is not required at this stage
170 // getComputeSourceCode (spec.assembly);
171
172 spec.inputs.push_back(BufferSp(new Float32Buffer(positiveFloats)));
173 spec.outputs.push_back(BufferSp(new Float32Buffer(negativeFloats)));
174 spec.numWorkGroups = tcu::IVec3(numElements, 1, 1);
175
176 return spec;
177 }
178
isSpirVersionsAsRequested(const BinaryCollection & binaryCollection,SpirvVersion requestedSpirvVersion)179 static bool isSpirVersionsAsRequested (const BinaryCollection& binaryCollection, SpirvVersion requestedSpirvVersion)
180 {
181 bool result = true;
182
183 DE_ASSERT(!binaryCollection.empty());
184
185 for (vk::BinaryCollection::Iterator binaryIt = binaryCollection.begin(); binaryIt != binaryCollection.end(); ++binaryIt)
186 {
187 SpirvVersion binarySpirvVersion = extractSpirvVersion (binaryIt.getProgram());
188
189 if (binarySpirvVersion != requestedSpirvVersion)
190 result = false;
191 }
192
193 return result;
194 }
195
196 class SpvAsmGraphicsSpirvVersionsInstance : public TestInstance
197 {
198 public:
199 SpvAsmGraphicsSpirvVersionsInstance (Context& ctx, const TestParameters& testParameters);
200 tcu::TestStatus iterate (void);
201
202 private:
203 TestParameters m_testParameters;
204 };
205
SpvAsmGraphicsSpirvVersionsInstance(Context & ctx,const TestParameters & testParameters)206 SpvAsmGraphicsSpirvVersionsInstance::SpvAsmGraphicsSpirvVersionsInstance (Context& ctx, const TestParameters& testParameters)
207 : TestInstance (ctx)
208 , m_testParameters (testParameters)
209 {
210 }
211
iterate(void)212 tcu::TestStatus SpvAsmGraphicsSpirvVersionsInstance::iterate (void)
213 {
214 InstanceContext instanceContext = initGraphicsInstanceContext(m_testParameters);
215
216 if (!isSpirVersionsAsRequested(m_context.getBinaryCollection(), m_testParameters.spirvVersion))
217 return tcu::TestStatus::fail("Binary SPIR-V version is different from requested");
218
219 return runAndVerifyDefaultPipeline(m_context, instanceContext);
220 }
221
222
223 class SpvAsmComputeSpirvVersionsInstance : public ComputeShaderSpec, public SpvAsmComputeShaderInstance
224 {
225 public:
226 SpvAsmComputeSpirvVersionsInstance (Context& ctx, const TestParameters& testParameters);
227 tcu::TestStatus iterate (void);
228
229 private:
230 TestParameters m_testParameters;
231 };
232
SpvAsmComputeSpirvVersionsInstance(Context & ctx,const TestParameters & testParameters)233 SpvAsmComputeSpirvVersionsInstance::SpvAsmComputeSpirvVersionsInstance (Context& ctx, const TestParameters& testParameters)
234 : ComputeShaderSpec(getComputeShaderSpec(testParameters))
235 , SpvAsmComputeShaderInstance(ctx, *this)
236 , m_testParameters(testParameters)
237 {
238 if (m_testParameters.operation != OPERATION_COMPUTE)
239 TCU_THROW(InternalError, "Invalid operation specified");
240 }
241
iterate(void)242 tcu::TestStatus SpvAsmComputeSpirvVersionsInstance::iterate (void)
243 {
244 if (!isSpirVersionsAsRequested(m_context.getBinaryCollection(), m_testParameters.spirvVersion))
245 return tcu::TestStatus::fail("Binary SPIR-V version is different from requested");
246
247 return SpvAsmComputeShaderInstance::iterate();
248 }
249
250
251 class SpvAsmSpirvVersionsCase : public TestCase
252 {
253 public:
254 SpvAsmSpirvVersionsCase (tcu::TestContext& testCtx, const char* name, const char* description, const TestParameters& testParameters);
255 void initPrograms (vk::SourceCollections& programCollection) const;
256 TestInstance* createInstance (Context& context) const;
257
258 private:
259 const TestParameters m_testParameters;
260 };
261
SpvAsmSpirvVersionsCase(tcu::TestContext & testCtx,const char * name,const char * description,const TestParameters & testParameters)262 SpvAsmSpirvVersionsCase::SpvAsmSpirvVersionsCase (tcu::TestContext& testCtx, const char* name, const char* description, const TestParameters& testParameters)
263 : TestCase (testCtx, name, description)
264 , m_testParameters (testParameters)
265 {
266 }
267
validateVulkanVersion(const deUint32 usedVulkanVersion,const SpirvVersion testedSpirvVersion)268 void validateVulkanVersion (const deUint32 usedVulkanVersion, const SpirvVersion testedSpirvVersion)
269 {
270 const SpirvVersion usedSpirvVersionForAsm = getMaxSpirvVersionForAsm(usedVulkanVersion);
271
272 if (testedSpirvVersion > usedSpirvVersionForAsm)
273 TCU_THROW(NotSupportedError, "Specified SPIR-V version is not supported by the device/instance");
274 }
275
initPrograms(SourceCollections & programCollection) const276 void SpvAsmSpirvVersionsCase::initPrograms (SourceCollections& programCollection) const
277 {
278 const SpirVAsmBuildOptions spirVAsmBuildOptions (programCollection.usedVulkanVersion, m_testParameters.spirvVersion);
279
280 validateVulkanVersion(programCollection.usedVulkanVersion, m_testParameters.spirvVersion);
281
282 switch (m_testParameters.operation)
283 {
284 case OPERATION_COMPUTE:
285 {
286 std::string comp;
287
288 getComputeSourceCode(comp, m_testParameters.spirvVersion);
289
290 programCollection.spirvAsmSources.add("compute", &spirVAsmBuildOptions) << comp;
291
292 break;
293 }
294
295 case OPERATION_GRAPHICS_VERTEX:
296 {
297 InstanceContext instanceContext = initGraphicsInstanceContext(m_testParameters);
298
299 addShaderCodeCustomVertex(programCollection, instanceContext, &spirVAsmBuildOptions);
300
301 break;
302 }
303
304 case OPERATION_GRAPHICS_TESSELATION_EVALUATION:
305 {
306 InstanceContext instanceContext = initGraphicsInstanceContext(m_testParameters);
307
308 addShaderCodeCustomTessEval(programCollection, instanceContext, &spirVAsmBuildOptions);
309
310 break;
311 }
312
313 case OPERATION_GRAPHICS_TESSELATION_CONTROL:
314 {
315 InstanceContext instanceContext = initGraphicsInstanceContext(m_testParameters);
316
317 addShaderCodeCustomTessControl(programCollection, instanceContext, &spirVAsmBuildOptions);
318
319 break;
320 }
321
322 case OPERATION_GRAPHICS_GEOMETRY:
323 {
324 InstanceContext instanceContext = initGraphicsInstanceContext(m_testParameters);
325
326 addShaderCodeCustomGeometry(programCollection, instanceContext, &spirVAsmBuildOptions);
327
328 break;
329 }
330
331 case OPERATION_GRAPHICS_FRAGMENT:
332 {
333 InstanceContext instanceContext = initGraphicsInstanceContext(m_testParameters);
334
335 addShaderCodeCustomFragment(programCollection, instanceContext, &spirVAsmBuildOptions);
336
337 break;
338 }
339
340 default:
341 TCU_THROW(InternalError, "Invalid operation specified");
342 }
343 }
344
createInstance(Context & context) const345 TestInstance* SpvAsmSpirvVersionsCase::createInstance (Context& context) const
346 {
347 validateVulkanVersion(context.getUsedApiVersion(), m_testParameters.spirvVersion);
348
349 switch (m_testParameters.operation)
350 {
351 case OPERATION_COMPUTE:
352 return new SpvAsmComputeSpirvVersionsInstance(context, m_testParameters);
353
354 case OPERATION_GRAPHICS_VERTEX:
355 case OPERATION_GRAPHICS_TESSELATION_EVALUATION:
356 case OPERATION_GRAPHICS_TESSELATION_CONTROL:
357 case OPERATION_GRAPHICS_GEOMETRY:
358 case OPERATION_GRAPHICS_FRAGMENT:
359 return new SpvAsmGraphicsSpirvVersionsInstance(context, m_testParameters);
360
361 default:
362 TCU_THROW(InternalError, "Invalid operation specified");
363 }
364 }
365
createSpivVersionCheckTests(tcu::TestContext & testCtx,const bool compute)366 tcu::TestCaseGroup* createSpivVersionCheckTests (tcu::TestContext& testCtx, const bool compute)
367 {
368 const char* operationNames[OPERATION_LAST] =
369 {
370 "compute",
371 "vertex",
372 "tesselation_evaluation",
373 "tesselation_control",
374 "geometry",
375 "fragment",
376 };
377
378 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "spirv_version", "Test SPIR-V version is supported"));
379
380 for (SpirvVersion spirvVersion = SPIRV_VERSION_1_0; spirvVersion < SPIRV_VERSION_LAST; ++spirvVersion)
381 {
382 std::string spirvVersionName = getSpirvVersionName(spirvVersion);
383
384 std::replace(spirvVersionName.begin(), spirvVersionName.end(), '.', '_');
385
386 for (Operation operation = OPERATION_COMPUTE; operation < OPERATION_LAST; ++operation)
387 {
388 if ((compute && operation == OPERATION_COMPUTE) || (!compute && operation != OPERATION_COMPUTE))
389 {
390 const std::string testName = spirvVersionName + "_" + operationNames[static_cast<deUint32>(operation)];
391 const TestParameters testParameters =
392 {
393 operation,
394 spirvVersion
395 };
396
397 group->addChild(new SpvAsmSpirvVersionsCase(testCtx, testName.c_str(), "", testParameters));
398 }
399 }
400 }
401
402 return group.release();
403 }
404
405 } // SpirVAssembly
406 } // vkt
407