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 35namespace vk 36{ 37 38using std::string; 39using std::vector; 40using 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 52ProgramBinary::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 60namespace 61{ 62 63bool isNativeSpirVBinaryEndianness (void) 64{ 65#if (DE_ENDIANNESS == SPIRV_BINARY_ENDIANNESS) 66 return true; 67#else 68 return false; 69#endif 70} 71 72bool 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 93ProgramBinary* 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 105ProgramBinary* 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 135ProgramBinary* 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 159void 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 174bool 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 193Move<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 212glu::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 228VkShaderStageFlagBits 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