• 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 	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