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