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 if (!compileGlslToSpirV(program, &binary, buildInfo)) 114 TCU_THROW(InternalError, "Compiling GLSL to SPIR-V failed"); 115 116 if (validateBinary) 117 { 118 std::ostringstream validationLog; 119 120 if (!validateSpirV(binary.size(), &binary[0], &validationLog)) 121 { 122 buildInfo->program.linkOk = false; 123 buildInfo->program.infoLog += "\n" + validationLog.str(); 124 125 TCU_THROW(InternalError, "Validation failed for compiled SPIR-V binary"); 126 } 127 } 128 129 return createProgramBinaryFromSpirV(binary); 130 } 131 else 132 TCU_THROW(NotSupportedError, "Unsupported program format"); 133 } 134 135 ProgramBinary* assembleProgram (const SpirVAsmSource& program, SpirVProgramInfo* buildInfo) 136 { 137 const bool validateBinary = VALIDATE_BINARIES; 138 vector<deUint32> binary; 139 140 if (!assembleSpirV(&program, &binary, buildInfo)) 141 TCU_THROW(InternalError, "Failed to assemble SPIR-V"); 142 143 if (validateBinary) 144 { 145 std::ostringstream validationLog; 146 147 if (!validateSpirV(binary.size(), &binary[0], &validationLog)) 148 { 149 buildInfo->compileOk = false; 150 buildInfo->infoLog += "\n" + validationLog.str(); 151 152 TCU_THROW(InternalError, "Validation failed for assembled SPIR-V binary"); 153 } 154 } 155 156 return createProgramBinaryFromSpirV(binary); 157 } 158 159 void disassembleProgram (const ProgramBinary& program, std::ostream* dst) 160 { 161 if (program.getFormat() == PROGRAM_FORMAT_SPIRV) 162 { 163 TCU_CHECK_INTERNAL(isSaneSpirVBinary(program)); 164 165 if (isNativeSpirVBinaryEndianness()) 166 disassembleSpirV(program.getSize()/sizeof(deUint32), (const deUint32*)program.getBinary(), dst); 167 else 168 TCU_THROW(InternalError, "SPIR-V endianness translation not supported"); 169 } 170 else 171 TCU_THROW(NotSupportedError, "Unsupported program format"); 172 } 173 174 bool validateProgram (const ProgramBinary& program, std::ostream* dst) 175 { 176 if (program.getFormat() == PROGRAM_FORMAT_SPIRV) 177 { 178 if (!isSaneSpirVBinary(program)) 179 { 180 *dst << "Binary doesn't look like SPIR-V at all"; 181 return false; 182 } 183 184 if (isNativeSpirVBinaryEndianness()) 185 return validateSpirV(program.getSize()/sizeof(deUint32), (const deUint32*)program.getBinary(), dst); 186 else 187 TCU_THROW(InternalError, "SPIR-V endianness translation not supported"); 188 } 189 else 190 TCU_THROW(NotSupportedError, "Unsupported program format"); 191 } 192 193 Move<VkShaderModule> createShaderModule (const DeviceInterface& deviceInterface, VkDevice device, const ProgramBinary& binary, VkShaderModuleCreateFlags flags) 194 { 195 if (binary.getFormat() == PROGRAM_FORMAT_SPIRV) 196 { 197 const struct VkShaderModuleCreateInfo shaderModuleInfo = 198 { 199 VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, 200 DE_NULL, 201 flags, 202 (deUintptr)binary.getSize(), 203 (const deUint32*)binary.getBinary(), 204 }; 205 206 return createShaderModule(deviceInterface, device, &shaderModuleInfo); 207 } 208 else 209 TCU_THROW(NotSupportedError, "Unsupported program format"); 210 } 211 212 glu::ShaderType getGluShaderType (VkShaderStageFlagBits shaderStage) 213 { 214 switch (shaderStage) 215 { 216 case VK_SHADER_STAGE_VERTEX_BIT: return glu::SHADERTYPE_VERTEX; 217 case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: return glu::SHADERTYPE_TESSELLATION_CONTROL; 218 case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: return glu::SHADERTYPE_TESSELLATION_EVALUATION; 219 case VK_SHADER_STAGE_GEOMETRY_BIT: return glu::SHADERTYPE_GEOMETRY; 220 case VK_SHADER_STAGE_FRAGMENT_BIT: return glu::SHADERTYPE_FRAGMENT; 221 case VK_SHADER_STAGE_COMPUTE_BIT: return glu::SHADERTYPE_COMPUTE; 222 default: 223 DE_FATAL("Unknown shader stage"); 224 return glu::SHADERTYPE_LAST; 225 } 226 } 227 228 VkShaderStageFlagBits getVkShaderStage (glu::ShaderType shaderType) 229 { 230 static const VkShaderStageFlagBits s_shaderStages[] = 231 { 232 VK_SHADER_STAGE_VERTEX_BIT, 233 VK_SHADER_STAGE_FRAGMENT_BIT, 234 VK_SHADER_STAGE_GEOMETRY_BIT, 235 VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, 236 VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, 237 VK_SHADER_STAGE_COMPUTE_BIT 238 }; 239 240 return de::getSizedArrayElement<glu::SHADERTYPE_LAST>(s_shaderStages, shaderType); 241 } 242 243 } // vk 244