• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 	switch (testParameters.operation)
103 	{
104 		case OPERATION_GRAPHICS_VERTEX:					return createInstanceContext(vertFragPipelineStages, opSimpleTest);
105 		case OPERATION_GRAPHICS_TESSELATION_EVALUATION:	return createInstanceContext(tessPipelineStages, opSimpleTest);
106 		case OPERATION_GRAPHICS_TESSELATION_CONTROL:	return createInstanceContext(tessPipelineStages, opSimpleTest);
107 		case OPERATION_GRAPHICS_GEOMETRY:				return createInstanceContext(geomPipelineStages, opSimpleTest);
108 		case OPERATION_GRAPHICS_FRAGMENT:				return createInstanceContext(vertFragPipelineStages, opSimpleTest);
109 		default:										TCU_THROW(InternalError, "Invalid operation specified");
110 	}
111 }
112 
getComputeSourceCode(std::string & computeSourceCode)113 static void getComputeSourceCode (std::string& computeSourceCode)
114 {
115 	computeSourceCode =
116 		string(getComputeAsmShaderPreamble()) +
117 
118 		"OpSource GLSL 430\n"
119 		"OpName %main           \"main\"\n"
120 		"OpName %id             \"gl_GlobalInvocationID\"\n"
121 
122 		"OpDecorate %id BuiltIn GlobalInvocationId\n" +
123 
124 		string(getComputeAsmInputOutputBufferTraits()) +
125 		string(getComputeAsmCommonTypes()) +
126 		string(getComputeAsmInputOutputBuffer()) +
127 
128 		"%id        = OpVariable %uvec3ptr Input\n"
129 		"%zero      = OpConstant %i32 0\n"
130 
131 		"%main      = OpFunction %void None %voidf\n"
132 		"%label     = OpLabel\n"
133 		"%idval     = OpLoad %uvec3 %id\n"
134 		"%x         = OpCompositeExtract %u32 %idval 0\n"
135 
136 		"             OpNop\n" // Inside a function body
137 
138 		"%inloc     = OpAccessChain %f32ptr %indata %zero %x\n"
139 		"%inval     = OpLoad %f32 %inloc\n"
140 		"%neg       = OpFNegate %f32 %inval\n"
141 		"%outloc    = OpAccessChain %f32ptr %outdata %zero %x\n"
142 		"             OpStore %outloc %neg\n"
143 		"             OpReturn\n"
144 		"             OpFunctionEnd\n";
145 }
146 
getComputeShaderSpec(const TestParameters & testParameters)147 static ComputeShaderSpec getComputeShaderSpec (const TestParameters& testParameters)
148 {
149 	ComputeShaderSpec	spec;
150 	const deUint32		seed			= (static_cast<deUint32>(testParameters.operation)<<16) ^ static_cast<deUint32>(testParameters.spirvVersion);
151 	de::Random			rnd				(seed);
152 	const int			numElements		= 100;
153 	vector<float>		positiveFloats	(numElements, 0);
154 	vector<float>		negativeFloats	(numElements, 0);
155 
156 	for (size_t ndx = 0; ndx < numElements; ++ndx)
157 	{
158 		positiveFloats[ndx] = rnd.getFloat(1.0f, 100.0f);
159 		negativeFloats[ndx] = -positiveFloats[ndx];
160 	}
161 
162 	// Shader source code can be retrieved to complete definition of ComputeShaderSpec, though it is not required at this stage
163 	// getComputeSourceCode (spec.assembly);
164 
165 	spec.inputs.push_back(BufferSp(new Float32Buffer(positiveFloats)));
166 	spec.outputs.push_back(BufferSp(new Float32Buffer(negativeFloats)));
167 	spec.numWorkGroups = tcu::IVec3(numElements, 1, 1);
168 
169 	return spec;
170 }
171 
isSpirVersionsAsRequested(const BinaryCollection & binaryCollection,SpirvVersion requestedSpirvVersion)172 static bool isSpirVersionsAsRequested (const BinaryCollection& binaryCollection, SpirvVersion requestedSpirvVersion)
173 {
174 	bool	result	= true;
175 
176 	DE_ASSERT(!binaryCollection.empty());
177 
178 	for (vk::BinaryCollection::Iterator binaryIt = binaryCollection.begin(); binaryIt != binaryCollection.end(); ++binaryIt)
179 	{
180 		SpirvVersion	binarySpirvVersion	= extractSpirvVersion	(binaryIt.getProgram());
181 
182 		if (binarySpirvVersion != requestedSpirvVersion)
183 			result = false;
184 	}
185 
186 	return result;
187 }
188 
189 class SpvAsmGraphicsSpirvVersionsInstance : public TestInstance
190 {
191 public:
192 					SpvAsmGraphicsSpirvVersionsInstance	(Context& ctx, const TestParameters& testParameters);
193 	tcu::TestStatus	iterate								(void);
194 
195 private:
196 	TestParameters	m_testParameters;
197 };
198 
SpvAsmGraphicsSpirvVersionsInstance(Context & ctx,const TestParameters & testParameters)199 SpvAsmGraphicsSpirvVersionsInstance::SpvAsmGraphicsSpirvVersionsInstance (Context& ctx, const TestParameters& testParameters)
200 	: TestInstance		(ctx)
201 	, m_testParameters	(testParameters)
202 {
203 }
204 
iterate(void)205 tcu::TestStatus SpvAsmGraphicsSpirvVersionsInstance::iterate (void)
206 {
207 	InstanceContext instanceContext = initGraphicsInstanceContext(m_testParameters);
208 
209 	if (!isSpirVersionsAsRequested(m_context.getBinaryCollection(), m_testParameters.spirvVersion))
210 		return tcu::TestStatus::fail("Binary SPIR-V version is different from requested");
211 
212 	return runAndVerifyDefaultPipeline(m_context, instanceContext);
213 }
214 
215 
216 class SpvAsmComputeSpirvVersionsInstance : public ComputeShaderSpec, public SpvAsmComputeShaderInstance
217 {
218 public:
219 					SpvAsmComputeSpirvVersionsInstance	(Context& ctx, const TestParameters& testParameters);
220 	tcu::TestStatus	iterate								(void);
221 
222 private:
223 	TestParameters	m_testParameters;
224 };
225 
SpvAsmComputeSpirvVersionsInstance(Context & ctx,const TestParameters & testParameters)226 SpvAsmComputeSpirvVersionsInstance::SpvAsmComputeSpirvVersionsInstance (Context& ctx, const TestParameters& testParameters)
227 	: ComputeShaderSpec(getComputeShaderSpec(testParameters))
228 	, SpvAsmComputeShaderInstance(ctx, *this)
229 	, m_testParameters(testParameters)
230 {
231 	if (m_testParameters.operation != OPERATION_COMPUTE)
232 		TCU_THROW(InternalError, "Invalid operation specified");
233 }
234 
iterate(void)235 tcu::TestStatus SpvAsmComputeSpirvVersionsInstance::iterate (void)
236 {
237 	if (!isSpirVersionsAsRequested(m_context.getBinaryCollection(), m_testParameters.spirvVersion))
238 		return tcu::TestStatus::fail("Binary SPIR-V version is different from requested");
239 
240 	return SpvAsmComputeShaderInstance::iterate();
241 }
242 
243 
244 class SpvAsmSpirvVersionsCase : public TestCase
245 {
246 public:
247 							SpvAsmSpirvVersionsCase	(tcu::TestContext& testCtx, const char* name, const char* description, const TestParameters& testParameters);
248 	void					initPrograms			(vk::SourceCollections& programCollection) const;
249 	TestInstance*			createInstance			(Context& context) const;
250 
251 private:
252 	const TestParameters	m_testParameters;
253 };
254 
SpvAsmSpirvVersionsCase(tcu::TestContext & testCtx,const char * name,const char * description,const TestParameters & testParameters)255 SpvAsmSpirvVersionsCase::SpvAsmSpirvVersionsCase (tcu::TestContext& testCtx, const char* name, const char* description, const TestParameters& testParameters)
256 	: TestCase			(testCtx, name, description)
257 	, m_testParameters	(testParameters)
258 {
259 }
260 
validateVulkanVersion(const deUint32 usedVulkanVersion,const SpirvVersion testedSpirvVersion)261 void validateVulkanVersion (const deUint32 usedVulkanVersion, const SpirvVersion testedSpirvVersion)
262 {
263 	const SpirvVersion	usedSpirvVersionForAsm	= getMaxSpirvVersionForAsm(usedVulkanVersion);
264 
265 	if (testedSpirvVersion > usedSpirvVersionForAsm)
266 		TCU_THROW(NotSupportedError, "Specified SPIR-V version is not supported by the device/instance");
267 }
268 
initPrograms(SourceCollections & programCollection) const269 void SpvAsmSpirvVersionsCase::initPrograms (SourceCollections& programCollection) const
270 {
271 	const SpirVAsmBuildOptions	spirVAsmBuildOptions	(programCollection.usedVulkanVersion, m_testParameters.spirvVersion);
272 
273 	validateVulkanVersion(programCollection.usedVulkanVersion, m_testParameters.spirvVersion);
274 
275 	switch (m_testParameters.operation)
276 	{
277 		case OPERATION_COMPUTE:
278 		{
279 			std::string comp;
280 
281 			getComputeSourceCode(comp);
282 
283 			programCollection.spirvAsmSources.add("compute", &spirVAsmBuildOptions) << comp;
284 
285 			break;
286 		}
287 
288 		case OPERATION_GRAPHICS_VERTEX:
289 		{
290 			InstanceContext instanceContext = initGraphicsInstanceContext(m_testParameters);
291 
292 			addShaderCodeCustomVertex(programCollection, instanceContext, &spirVAsmBuildOptions);
293 
294 			break;
295 		}
296 
297 		case OPERATION_GRAPHICS_TESSELATION_EVALUATION:
298 		{
299 			InstanceContext instanceContext = initGraphicsInstanceContext(m_testParameters);
300 
301 			addShaderCodeCustomTessEval(programCollection, instanceContext, &spirVAsmBuildOptions);
302 
303 			break;
304 		}
305 
306 		case OPERATION_GRAPHICS_TESSELATION_CONTROL:
307 		{
308 			InstanceContext instanceContext = initGraphicsInstanceContext(m_testParameters);
309 
310 			addShaderCodeCustomTessControl(programCollection, instanceContext, &spirVAsmBuildOptions);
311 
312 			break;
313 		}
314 
315 		case OPERATION_GRAPHICS_GEOMETRY:
316 		{
317 			InstanceContext instanceContext = initGraphicsInstanceContext(m_testParameters);
318 
319 			addShaderCodeCustomGeometry(programCollection, instanceContext, &spirVAsmBuildOptions);
320 
321 			break;
322 		}
323 
324 		case OPERATION_GRAPHICS_FRAGMENT:
325 		{
326 			InstanceContext instanceContext = initGraphicsInstanceContext(m_testParameters);
327 
328 			addShaderCodeCustomFragment(programCollection, instanceContext, &spirVAsmBuildOptions);
329 
330 			break;
331 		}
332 
333 		default:
334 			TCU_THROW(InternalError, "Invalid operation specified");
335 	}
336 }
337 
createInstance(Context & context) const338 TestInstance* SpvAsmSpirvVersionsCase::createInstance (Context& context) const
339 {
340 	validateVulkanVersion(context.getUsedApiVersion(), m_testParameters.spirvVersion);
341 
342 	switch (m_testParameters.operation)
343 	{
344 		case OPERATION_COMPUTE:
345 			return new SpvAsmComputeSpirvVersionsInstance(context, m_testParameters);
346 
347 		case OPERATION_GRAPHICS_VERTEX:
348 		case OPERATION_GRAPHICS_TESSELATION_EVALUATION:
349 		case OPERATION_GRAPHICS_TESSELATION_CONTROL:
350 		case OPERATION_GRAPHICS_GEOMETRY:
351 		case OPERATION_GRAPHICS_FRAGMENT:
352 			return new SpvAsmGraphicsSpirvVersionsInstance(context, m_testParameters);
353 
354 		default:
355 			TCU_THROW(InternalError, "Invalid operation specified");
356 	}
357 }
358 
createSpivVersionCheckTests(tcu::TestContext & testCtx,const bool compute)359 tcu::TestCaseGroup* createSpivVersionCheckTests (tcu::TestContext& testCtx, const bool compute)
360 {
361 	const char*	operationNames[OPERATION_LAST]	=
362 	{
363 		"compute",
364 		"vertex",
365 		"tesselation_evaluation",
366 		"tesselation_control",
367 		"geometry",
368 		"fragment",
369 	};
370 
371 	de::MovePtr<tcu::TestCaseGroup>	group	(new tcu::TestCaseGroup(testCtx, "spirv_version", "Test SPIR-V version is supported"));
372 
373 	for (SpirvVersion spirvVersion = SPIRV_VERSION_1_0; spirvVersion < SPIRV_VERSION_LAST; ++spirvVersion)
374 	{
375 		std::string spirvVersionName = getSpirvVersionName(spirvVersion);
376 
377 		std::replace(spirvVersionName.begin(), spirvVersionName.end(), '.', '_');
378 
379 		for (Operation operation = OPERATION_COMPUTE; operation < OPERATION_LAST; ++operation)
380 		{
381 			if ((compute && operation == OPERATION_COMPUTE) || (!compute && operation != OPERATION_COMPUTE))
382 			{
383 				const std::string		testName		= spirvVersionName + "_" + operationNames[static_cast<deUint32>(operation)];
384 				const TestParameters	testParameters	=
385 				{
386 					operation,
387 					spirvVersion
388 				};
389 
390 				group->addChild(new SpvAsmSpirvVersionsCase(testCtx, testName.c_str(), "", testParameters));
391 			}
392 		}
393 	}
394 
395 	return group.release();
396 }
397 
398 } // SpirVAssembly
399 } // vkt
400