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 static spv_target_env mapTargetSpvEnvironment(SpirvVersion spirvVersion) 43 { 44 spv_target_env result = SPV_ENV_UNIVERSAL_1_0; 45 46 switch (spirvVersion) 47 { 48 case SPIRV_VERSION_1_0: result = SPV_ENV_UNIVERSAL_1_0; break; //!< SPIR-V 1.0 49 case SPIRV_VERSION_1_1: result = SPV_ENV_UNIVERSAL_1_1; break; //!< SPIR-V 1.1 50 case SPIRV_VERSION_1_2: result = SPV_ENV_UNIVERSAL_1_2; break; //!< SPIR-V 1.2 51 case SPIRV_VERSION_1_3: result = SPV_ENV_UNIVERSAL_1_3; break; //!< SPIR-V 1.3 52 default: TCU_THROW(InternalError, "Unknown SPIR-V version"); 53 } 54 55 return result; 56 } 57 58 bool assembleSpirV (const SpirVAsmSource* program, std::vector<deUint32>* dst, SpirVProgramInfo* buildInfo, SpirvVersion spirvVersion) 59 { 60 const spv_context context = spvContextCreate(mapTargetSpvEnvironment(spirvVersion)); 61 spv_binary binary = DE_NULL; 62 spv_diagnostic diagnostic = DE_NULL; 63 64 if (!context) 65 throw std::bad_alloc(); 66 67 try 68 { 69 const std::string& spvSource = program->source; 70 const deUint64 compileStartTime = deGetMicroseconds(); 71 const spv_result_t compileOk = spvTextToBinary(context, spvSource.c_str(), spvSource.size(), &binary, &diagnostic); 72 73 buildInfo->source = spvSource; 74 buildInfo->infoLog = diagnostic? diagnostic->error : ""; // \todo [2015-07-13 pyry] Include debug log? 75 buildInfo->compileTimeUs = deGetMicroseconds() - compileStartTime; 76 buildInfo->compileOk = (compileOk == SPV_SUCCESS); 77 78 if (buildInfo->compileOk) 79 { 80 DE_ASSERT(binary->wordCount > 0); 81 dst->resize(binary->wordCount); 82 std::copy(&binary->code[0], &binary->code[0] + binary->wordCount, dst->begin()); 83 } 84 85 spvBinaryDestroy(binary); 86 spvDiagnosticDestroy(diagnostic); 87 spvContextDestroy(context); 88 89 return compileOk == SPV_SUCCESS; 90 } 91 catch (...) 92 { 93 spvBinaryDestroy(binary); 94 spvDiagnosticDestroy(diagnostic); 95 spvContextDestroy(context); 96 97 throw; 98 } 99 } 100 101 void disassembleSpirV (size_t binarySizeInWords, const deUint32* binary, std::ostream* dst, SpirvVersion spirvVersion) 102 { 103 const spv_context context = spvContextCreate(mapTargetSpvEnvironment(spirvVersion)); 104 spv_text text = DE_NULL; 105 spv_diagnostic diagnostic = DE_NULL; 106 107 if (!context) 108 throw std::bad_alloc(); 109 110 try 111 { 112 const spv_result_t result = spvBinaryToText(context, binary, binarySizeInWords, 0, &text, &diagnostic); 113 114 if (result != SPV_SUCCESS) 115 TCU_THROW(InternalError, "Disassembling SPIR-V failed"); 116 117 *dst << text->str; 118 119 spvTextDestroy(text); 120 spvDiagnosticDestroy(diagnostic); 121 spvContextDestroy(context); 122 } 123 catch (...) 124 { 125 spvTextDestroy(text); 126 spvDiagnosticDestroy(diagnostic); 127 spvContextDestroy(context); 128 129 throw; 130 } 131 } 132 133 bool validateSpirV (size_t binarySizeInWords, const deUint32* binary, std::ostream* infoLog, SpirvVersion spirvVersion) 134 { 135 const spv_context context = spvContextCreate(mapTargetSpvEnvironment(spirvVersion)); 136 spv_diagnostic diagnostic = DE_NULL; 137 138 try 139 { 140 spv_const_binary_t cbinary = { binary, binarySizeInWords }; 141 const spv_result_t valid = spvValidate(context, &cbinary, &diagnostic); 142 143 if (diagnostic) 144 *infoLog << diagnostic->error; 145 146 spvDiagnosticDestroy(diagnostic); 147 spvContextDestroy(context); 148 149 return valid == SPV_SUCCESS; 150 } 151 catch (...) 152 { 153 spvDiagnosticDestroy(diagnostic); 154 spvContextDestroy(context); 155 156 throw; 157 } 158 } 159 160 #else // defined(DEQP_HAVE_SPIRV_TOOLS) 161 162 bool assembleSpirV (const SpirVAsmSource*, std::vector<deUint32>*, SpirVProgramInfo*, SpirvVersion) 163 { 164 TCU_THROW(NotSupportedError, "SPIR-V assembly not supported (DEQP_HAVE_SPIRV_TOOLS not defined)"); 165 } 166 167 void disassembleSpirV (size_t, const deUint32*, std::ostream*, SpirvVersion) 168 { 169 TCU_THROW(NotSupportedError, "SPIR-V disassembling not supported (DEQP_HAVE_SPIRV_TOOLS not defined)"); 170 } 171 172 bool validateSpirV (size_t, const deUint32*, std::ostream*, SpirvVersion) 173 { 174 TCU_THROW(NotSupportedError, "SPIR-V validation not supported (DEQP_HAVE_SPIRV_TOOLS not defined)"); 175 } 176 177 #endif 178 179 } // vk 180