Home | History | Annotate | Download | only in spirv_assembly
      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 
     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 
     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_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 
    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 
    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 
    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 
    199 SpvAsmGraphicsSpirvVersionsInstance::SpvAsmGraphicsSpirvVersionsInstance (Context& ctx, const TestParameters& testParameters)
    200 	: TestInstance		(ctx)
    201 	, m_testParameters	(testParameters)
    202 {
    203 }
    204 
    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 
    226 SpvAsmComputeSpirvVersionsInstance::SpvAsmComputeSpirvVersionsInstance (Context& ctx, const TestParameters& testParameters)
    227 	: ComputeShaderSpec(getComputeShaderSpec(testParameters))
    228 	, SpvAsmComputeShaderInstance(ctx, *this, COMPUTE_TEST_USES_NONE)
    229 	, m_testParameters(testParameters)
    230 {
    231 	if (m_testParameters.operation != OPERATION_COMPUTE)
    232 		TCU_THROW(InternalError, "Invalid operation specified");
    233 }
    234 
    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 
    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 
    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 
    269 void SpvAsmSpirvVersionsCase::initPrograms (SourceCollections& programCollection) const
    270 {
    271 	const SpirVAsmBuildOptions	spirVAsmBuildOptions	(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 
    338 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 
    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