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 Program utilities. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "vkPrograms.hpp" 25 #include "vkGlslToSpirV.hpp" 26 #include "vkSpirVAsm.hpp" 27 #include "vkRefUtil.hpp" 28 29 #include "deArrayUtil.hpp" 30 #include "deMemory.h" 31 #include "deInt32.h" 32 33 namespace vk 34 { 35 36 using std::string; 37 using std::vector; 38 39 #if defined(DE_DEBUG) && defined(DEQP_HAVE_SPIRV_TOOLS) 40 # define VALIDATE_BINARIES true 41 #else 42 # define VALIDATE_BINARIES false 43 #endif 44 45 #define SPIRV_BINARY_ENDIANNESS DE_LITTLE_ENDIAN 46 47 // ProgramBinary 48 49 ProgramBinary::ProgramBinary (ProgramFormat format, size_t binarySize, const deUint8* binary) 50 : m_format (format) 51 , m_binary (binary, binary+binarySize) 52 { 53 } 54 55 // Utils 56 57 namespace 58 { 59 60 bool isNativeSpirVBinaryEndianness (void) 61 { 62 #if (DE_ENDIANNESS == SPIRV_BINARY_ENDIANNESS) 63 return true; 64 #else 65 return false; 66 #endif 67 } 68 69 bool isSaneSpirVBinary (const ProgramBinary& binary) 70 { 71 const deUint32 spirvMagicWord = 0x07230203; 72 const deUint32 spirvMagicBytes = isNativeSpirVBinaryEndianness() 73 ? spirvMagicWord 74 : deReverseBytes32(spirvMagicWord); 75 76 DE_ASSERT(binary.getFormat() == PROGRAM_FORMAT_SPIRV); 77 78 if (binary.getSize() % sizeof(deUint32) != 0) 79 return false; 80 81 if (binary.getSize() < sizeof(deUint32)) 82 return false; 83 84 if (*(const deUint32*)binary.getBinary() != spirvMagicBytes) 85 return false; 86 87 return true; 88 } 89 90 ProgramBinary* createProgramBinaryFromSpirV (const vector<deUint32>& binary) 91 { 92 DE_ASSERT(!binary.empty()); 93 94 if (isNativeSpirVBinaryEndianness()) 95 return new ProgramBinary(PROGRAM_FORMAT_SPIRV, binary.size()*sizeof(deUint32), (const deUint8*)&binary[0]); 96 else 97 TCU_THROW(InternalError, "SPIR-V endianness translation not supported"); 98 } 99 100 } // anonymous 101 102 ProgramBinary* buildProgram (const GlslSource& program, glu::ShaderProgramInfo* buildInfo) 103 { 104 const bool validateBinary = VALIDATE_BINARIES; 105 vector<deUint32> binary; 106 107 { 108 vector<deUint32> nonStrippedBinary; 109 110 if (!compileGlslToSpirV(program, &nonStrippedBinary, buildInfo)) 111 TCU_THROW(InternalError, "Compiling GLSL to SPIR-V failed"); 112 113 TCU_CHECK_INTERNAL(!nonStrippedBinary.empty()); 114 stripSpirVDebugInfo(nonStrippedBinary.size(), &nonStrippedBinary[0], &binary); 115 TCU_CHECK_INTERNAL(!binary.empty()); 116 } 117 118 if (validateBinary) 119 { 120 std::ostringstream validationLog; 121 122 if (!validateSpirV(binary.size(), &binary[0], &validationLog)) 123 { 124 buildInfo->program.linkOk = false; 125 buildInfo->program.infoLog += "\n" + validationLog.str(); 126 127 TCU_THROW(InternalError, "Validation failed for compiled SPIR-V binary"); 128 } 129 } 130 131 return createProgramBinaryFromSpirV(binary); 132 } 133 134 ProgramBinary* assembleProgram (const SpirVAsmSource& program, SpirVProgramInfo* buildInfo) 135 { 136 const bool validateBinary = VALIDATE_BINARIES; 137 vector<deUint32> binary; 138 139 if (!assembleSpirV(&program, &binary, buildInfo)) 140 TCU_THROW(InternalError, "Failed to assemble SPIR-V"); 141 142 if (validateBinary) 143 { 144 std::ostringstream validationLog; 145 146 if (!validateSpirV(binary.size(), &binary[0], &validationLog)) 147 { 148 buildInfo->compileOk = false; 149 buildInfo->infoLog += "\n" + validationLog.str(); 150 151 TCU_THROW(InternalError, "Validation failed for assembled SPIR-V binary"); 152 } 153 } 154 155 return createProgramBinaryFromSpirV(binary); 156 } 157 158 void disassembleProgram (const ProgramBinary& program, std::ostream* dst) 159 { 160 if (program.getFormat() == PROGRAM_FORMAT_SPIRV) 161 { 162 TCU_CHECK_INTERNAL(isSaneSpirVBinary(program)); 163 164 if (isNativeSpirVBinaryEndianness()) 165 disassembleSpirV(program.getSize()/sizeof(deUint32), (const deUint32*)program.getBinary(), dst); 166 else 167 TCU_THROW(InternalError, "SPIR-V endianness translation not supported"); 168 } 169 else 170 TCU_THROW(NotSupportedError, "Unsupported program format"); 171 } 172 173 bool validateProgram (const ProgramBinary& program, std::ostream* dst) 174 { 175 if (program.getFormat() == PROGRAM_FORMAT_SPIRV) 176 { 177 if (!isSaneSpirVBinary(program)) 178 { 179 *dst << "Binary doesn't look like SPIR-V at all"; 180 return false; 181 } 182 183 if (isNativeSpirVBinaryEndianness()) 184 return validateSpirV(program.getSize()/sizeof(deUint32), (const deUint32*)program.getBinary(), dst); 185 else 186 TCU_THROW(InternalError, "SPIR-V endianness translation not supported"); 187 } 188 else 189 TCU_THROW(NotSupportedError, "Unsupported program format"); 190 } 191 192 Move<VkShaderModule> createShaderModule (const DeviceInterface& deviceInterface, VkDevice device, const ProgramBinary& binary, VkShaderModuleCreateFlags flags) 193 { 194 if (binary.getFormat() == PROGRAM_FORMAT_SPIRV) 195 { 196 const struct VkShaderModuleCreateInfo shaderModuleInfo = 197 { 198 VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, 199 DE_NULL, 200 flags, 201 (deUintptr)binary.getSize(), 202 (const deUint32*)binary.getBinary(), 203 }; 204 205 return createShaderModule(deviceInterface, device, &shaderModuleInfo); 206 } 207 else 208 TCU_THROW(NotSupportedError, "Unsupported program format"); 209 } 210 211 glu::ShaderType getGluShaderType (VkShaderStageFlagBits shaderStage) 212 { 213 switch (shaderStage) 214 { 215 case VK_SHADER_STAGE_VERTEX_BIT: return glu::SHADERTYPE_VERTEX; 216 case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: return glu::SHADERTYPE_TESSELLATION_CONTROL; 217 case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: return glu::SHADERTYPE_TESSELLATION_EVALUATION; 218 case VK_SHADER_STAGE_GEOMETRY_BIT: return glu::SHADERTYPE_GEOMETRY; 219 case VK_SHADER_STAGE_FRAGMENT_BIT: return glu::SHADERTYPE_FRAGMENT; 220 case VK_SHADER_STAGE_COMPUTE_BIT: return glu::SHADERTYPE_COMPUTE; 221 default: 222 DE_FATAL("Unknown shader stage"); 223 return glu::SHADERTYPE_LAST; 224 } 225 } 226 227 VkShaderStageFlagBits getVkShaderStage (glu::ShaderType shaderType) 228 { 229 static const VkShaderStageFlagBits s_shaderStages[] = 230 { 231 VK_SHADER_STAGE_VERTEX_BIT, 232 VK_SHADER_STAGE_FRAGMENT_BIT, 233 VK_SHADER_STAGE_GEOMETRY_BIT, 234 VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, 235 VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, 236 VK_SHADER_STAGE_COMPUTE_BIT 237 }; 238 239 return de::getSizedArrayElement<glu::SHADERTYPE_LAST>(s_shaderStages, shaderType); 240 } 241 242 } // vk 243