Home | History | Annotate | Download | only in vulkan
      1 /*-------------------------------------------------------------------------
      2  * Vulkan CTS Framework
      3  * --------------------
      4  *
      5  * Copyright (c) 2015 Google 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 assembly to binary.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "vkSpirVAsm.hpp"
     25 #include "vkSpirVProgram.hpp"
     26 #include "deClock.h"
     27 
     28 #include <algorithm>
     29 
     30 #if defined(DEQP_HAVE_SPIRV_TOOLS)
     31 #	include "spirv-tools/libspirv.h"
     32 #endif
     33 
     34 namespace vk
     35 {
     36 
     37 using std::string;
     38 using std::vector;
     39 
     40 #if defined(DEQP_HAVE_SPIRV_TOOLS)
     41 
     42 // Convert a Vulkan version number to a SPIRV-Tools target environment enum.
     43 static spv_target_env mapVulkanVersionToSpirvToolsEnv(deUint32 vulkanVersion)
     44 {
     45 	switch (vulkanVersion)
     46 	{
     47 		case VK_MAKE_VERSION(1, 0, 0): return SPV_ENV_VULKAN_1_0;
     48 		case VK_MAKE_VERSION(1, 1, 0): return SPV_ENV_VULKAN_1_1;
     49 		default:
     50 			break;
     51 	}
     52 	TCU_THROW(InternalError, "Unexpected Vulkan Version version requested");
     53 	return SPV_ENV_VULKAN_1_0;
     54 }
     55 
     56 static spv_target_env mapTargetSpvEnvironment(SpirvVersion spirvVersion)
     57 {
     58 	spv_target_env result = SPV_ENV_UNIVERSAL_1_0;
     59 
     60 	switch (spirvVersion)
     61 	{
     62 		case SPIRV_VERSION_1_0: result = SPV_ENV_UNIVERSAL_1_0; break;	//!< SPIR-V 1.0
     63 		case SPIRV_VERSION_1_1: result = SPV_ENV_UNIVERSAL_1_1; break;	//!< SPIR-V 1.1
     64 		case SPIRV_VERSION_1_2: result = SPV_ENV_UNIVERSAL_1_2; break;	//!< SPIR-V 1.2
     65 		case SPIRV_VERSION_1_3: result = SPV_ENV_UNIVERSAL_1_3; break;	//!< SPIR-V 1.3
     66 		default:				TCU_THROW(InternalError, "Unknown SPIR-V version");
     67 	}
     68 
     69 	return result;
     70 }
     71 
     72 bool assembleSpirV (const SpirVAsmSource* program, std::vector<deUint32>* dst, SpirVProgramInfo* buildInfo, SpirvVersion spirvVersion)
     73 {
     74 	const spv_context	context		= spvContextCreate(mapTargetSpvEnvironment(spirvVersion));
     75 	spv_binary			binary		= DE_NULL;
     76 	spv_diagnostic		diagnostic	= DE_NULL;
     77 
     78 	if (!context)
     79 		throw std::bad_alloc();
     80 
     81 	try
     82 	{
     83 		const std::string&	spvSource			= program->source;
     84 		const deUint64		compileStartTime	= deGetMicroseconds();
     85 		const spv_result_t	compileOk			= spvTextToBinary(context, spvSource.c_str(), spvSource.size(), &binary, &diagnostic);
     86 
     87 		buildInfo->source			= spvSource;
     88 		buildInfo->infoLog			= diagnostic? diagnostic->error : ""; // \todo [2015-07-13 pyry] Include debug log?
     89 		buildInfo->compileTimeUs	= deGetMicroseconds() - compileStartTime;
     90 		buildInfo->compileOk		= (compileOk == SPV_SUCCESS);
     91 
     92 		if (buildInfo->compileOk)
     93 		{
     94 			DE_ASSERT(binary->wordCount > 0);
     95 			dst->resize(binary->wordCount);
     96 			std::copy(&binary->code[0], &binary->code[0] + binary->wordCount, dst->begin());
     97 		}
     98 
     99 		spvBinaryDestroy(binary);
    100 		spvDiagnosticDestroy(diagnostic);
    101 		spvContextDestroy(context);
    102 
    103 		return compileOk == SPV_SUCCESS;
    104 	}
    105 	catch (...)
    106 	{
    107 		spvBinaryDestroy(binary);
    108 		spvDiagnosticDestroy(diagnostic);
    109 		spvContextDestroy(context);
    110 
    111 		throw;
    112 	}
    113 }
    114 
    115 void disassembleSpirV (size_t binarySizeInWords, const deUint32* binary, std::ostream* dst, SpirvVersion spirvVersion)
    116 {
    117 	const spv_context	context		= spvContextCreate(mapTargetSpvEnvironment(spirvVersion));
    118 	spv_text			text		= DE_NULL;
    119 	spv_diagnostic		diagnostic	= DE_NULL;
    120 
    121 	if (!context)
    122 		throw std::bad_alloc();
    123 
    124 	try
    125 	{
    126 		const spv_result_t	result	= spvBinaryToText(context, binary, binarySizeInWords, 0, &text, &diagnostic);
    127 
    128 		if (result != SPV_SUCCESS)
    129 			TCU_THROW(InternalError, "Disassembling SPIR-V failed");
    130 
    131 		*dst << text->str;
    132 
    133 		spvTextDestroy(text);
    134 		spvDiagnosticDestroy(diagnostic);
    135 		spvContextDestroy(context);
    136 	}
    137 	catch (...)
    138 	{
    139 		spvTextDestroy(text);
    140 		spvDiagnosticDestroy(diagnostic);
    141 		spvContextDestroy(context);
    142 
    143 		throw;
    144 	}
    145 }
    146 
    147 bool validateSpirV (size_t binarySizeInWords, const deUint32* binary, std::ostream* infoLog, const SpirvValidatorOptions &val_options)
    148 {
    149 	const spv_context	context		= spvContextCreate(mapVulkanVersionToSpirvToolsEnv(val_options.vulkanVersion));
    150 	spv_diagnostic		diagnostic	= DE_NULL;
    151 
    152 	try
    153 	{
    154 		spv_const_binary_t		cbinary	= { binary, binarySizeInWords };
    155 
    156 		spv_validator_options options = spvValidatorOptionsCreate();
    157 
    158 		switch (val_options.blockLayout)
    159 		{
    160 			case SpirvValidatorOptions::kDefaultBlockLayout:
    161 				break;
    162 			case SpirvValidatorOptions::kNoneBlockLayout:
    163 				spvValidatorOptionsSetSkipBlockLayout(options, true);
    164 				break;
    165 			case SpirvValidatorOptions::kRelaxedBlockLayout:
    166 				spvValidatorOptionsSetRelaxBlockLayout(options, true);
    167 				break;
    168 			case SpirvValidatorOptions::kScalarBlockLayout:
    169 				spvValidatorOptionsSetScalarBlockLayout(options, true);
    170 				break;
    171 		}
    172 
    173 		const spv_result_t		valid	= spvValidateWithOptions(context, options, &cbinary, &diagnostic);
    174 		const bool				passed	= (valid == SPV_SUCCESS);
    175 
    176 		if (diagnostic)
    177 		{
    178 			// Print the diagnostic whether validation passes or fails.
    179 			// In theory we could get a warning even in the pass case, but there are no cases
    180 			// like that now.
    181 			*infoLog << "Validation " << (passed ? "PASSED: " : "FAILED: ") << diagnostic->error << "\n";
    182 
    183 			spv_text text;
    184 			spvBinaryToText(context, binary, binarySizeInWords, SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES | SPV_BINARY_TO_TEXT_OPTION_INDENT, &text, DE_NULL);
    185 
    186 			*infoLog << text->str << "\n";
    187 			spvTextDestroy(text);
    188 		}
    189 
    190 		spvValidatorOptionsDestroy(options);
    191 		spvDiagnosticDestroy(diagnostic);
    192 		spvContextDestroy(context);
    193 
    194 		return passed;
    195 	}
    196 	catch (...)
    197 	{
    198 		spvDiagnosticDestroy(diagnostic);
    199 		spvContextDestroy(context);
    200 
    201 		throw;
    202 	}
    203 }
    204 
    205 #else // defined(DEQP_HAVE_SPIRV_TOOLS)
    206 
    207 bool assembleSpirV (const SpirVAsmSource*, std::vector<deUint32>*, SpirVProgramInfo*, SpirvVersion)
    208 {
    209 	TCU_THROW(NotSupportedError, "SPIR-V assembly not supported (DEQP_HAVE_SPIRV_TOOLS not defined)");
    210 }
    211 
    212 void disassembleSpirV (size_t, const deUint32*, std::ostream*, SpirvVersion)
    213 {
    214 	TCU_THROW(NotSupportedError, "SPIR-V disassembling not supported (DEQP_HAVE_SPIRV_TOOLS not defined)");
    215 }
    216 
    217 bool validateSpirV (size_t, const deUint32*, std::ostream*, const SpirvValidatorOptions&)
    218 {
    219 	TCU_THROW(NotSupportedError, "SPIR-V validation not supported (DEQP_HAVE_SPIRV_TOOLS not defined)");
    220 }
    221 
    222 #endif
    223 
    224 } // vk
    225