1e5c31af7Sopenharmony_ci/*------------------------------------------------------------------------- 2e5c31af7Sopenharmony_ci * Vulkan CTS Framework 3e5c31af7Sopenharmony_ci * -------------------- 4e5c31af7Sopenharmony_ci * 5e5c31af7Sopenharmony_ci * Copyright (c) 2019 Google Inc. 6e5c31af7Sopenharmony_ci * 7e5c31af7Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 8e5c31af7Sopenharmony_ci * you may not use this file except in compliance with the License. 9e5c31af7Sopenharmony_ci * You may obtain a copy of the License at 10e5c31af7Sopenharmony_ci * 11e5c31af7Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 12e5c31af7Sopenharmony_ci * 13e5c31af7Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 14e5c31af7Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 15e5c31af7Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16e5c31af7Sopenharmony_ci * See the License for the specific language governing permissions and 17e5c31af7Sopenharmony_ci * limitations under the License. 18e5c31af7Sopenharmony_ci * 19e5c31af7Sopenharmony_ci *//*! 20e5c31af7Sopenharmony_ci * \file 21e5c31af7Sopenharmony_ci * \brief Program utilities. 22e5c31af7Sopenharmony_ci *//*--------------------------------------------------------------------*/ 23e5c31af7Sopenharmony_ci 24e5c31af7Sopenharmony_ci#include "spirv-tools/optimizer.hpp" 25e5c31af7Sopenharmony_ci 26e5c31af7Sopenharmony_ci#include "qpInfo.h" 27e5c31af7Sopenharmony_ci 28e5c31af7Sopenharmony_ci#include "vkPrograms.hpp" 29e5c31af7Sopenharmony_ci#include "vkShaderToSpirV.hpp" 30e5c31af7Sopenharmony_ci#include "vkSpirVAsm.hpp" 31e5c31af7Sopenharmony_ci#include "vkRefUtil.hpp" 32e5c31af7Sopenharmony_ci 33e5c31af7Sopenharmony_ci#include "deMutex.hpp" 34e5c31af7Sopenharmony_ci#include "deFilePath.hpp" 35e5c31af7Sopenharmony_ci#include "deArrayUtil.hpp" 36e5c31af7Sopenharmony_ci#include "deMemory.h" 37e5c31af7Sopenharmony_ci#include "deInt32.h" 38e5c31af7Sopenharmony_ci 39e5c31af7Sopenharmony_ci#include "tcuCommandLine.hpp" 40e5c31af7Sopenharmony_ci 41e5c31af7Sopenharmony_ci#include <map> 42e5c31af7Sopenharmony_ci#include <mutex> 43e5c31af7Sopenharmony_ci 44e5c31af7Sopenharmony_ci#if DE_OS == DE_OS_ANDROID 45e5c31af7Sopenharmony_ci#define DISABLE_SHADERCACHE_IPC 46e5c31af7Sopenharmony_ci#endif 47e5c31af7Sopenharmony_ci 48e5c31af7Sopenharmony_cinamespace vk 49e5c31af7Sopenharmony_ci{ 50e5c31af7Sopenharmony_ci 51e5c31af7Sopenharmony_ciusing std::string; 52e5c31af7Sopenharmony_ciusing std::vector; 53e5c31af7Sopenharmony_ciusing std::map; 54e5c31af7Sopenharmony_ci 55e5c31af7Sopenharmony_ci#if defined(DE_DEBUG) 56e5c31af7Sopenharmony_ci# define VALIDATE_BINARIES true 57e5c31af7Sopenharmony_ci#else 58e5c31af7Sopenharmony_ci# define VALIDATE_BINARIES false 59e5c31af7Sopenharmony_ci#endif 60e5c31af7Sopenharmony_ci 61e5c31af7Sopenharmony_ci#define SPIRV_BINARY_ENDIANNESS DE_LITTLE_ENDIAN 62e5c31af7Sopenharmony_ci 63e5c31af7Sopenharmony_ci// ProgramBinary 64e5c31af7Sopenharmony_ci 65e5c31af7Sopenharmony_ciProgramBinary::ProgramBinary (ProgramFormat format, size_t binarySize, const deUint8* binary) 66e5c31af7Sopenharmony_ci : m_format (format) 67e5c31af7Sopenharmony_ci , m_binary (binary, binary+binarySize) 68e5c31af7Sopenharmony_ci , m_used (false) 69e5c31af7Sopenharmony_ci{ 70e5c31af7Sopenharmony_ci} 71e5c31af7Sopenharmony_ci 72e5c31af7Sopenharmony_ci// Utils 73e5c31af7Sopenharmony_ci 74e5c31af7Sopenharmony_cinamespace 75e5c31af7Sopenharmony_ci{ 76e5c31af7Sopenharmony_ci 77e5c31af7Sopenharmony_cibool isNativeSpirVBinaryEndianness (void) 78e5c31af7Sopenharmony_ci{ 79e5c31af7Sopenharmony_ci#if (DE_ENDIANNESS == SPIRV_BINARY_ENDIANNESS) 80e5c31af7Sopenharmony_ci return true; 81e5c31af7Sopenharmony_ci#else 82e5c31af7Sopenharmony_ci return false; 83e5c31af7Sopenharmony_ci#endif 84e5c31af7Sopenharmony_ci} 85e5c31af7Sopenharmony_ci 86e5c31af7Sopenharmony_cibool isSaneSpirVBinary (const ProgramBinary& binary) 87e5c31af7Sopenharmony_ci{ 88e5c31af7Sopenharmony_ci const deUint32 spirvMagicWord = 0x07230203; 89e5c31af7Sopenharmony_ci const deUint32 spirvMagicBytes = isNativeSpirVBinaryEndianness() 90e5c31af7Sopenharmony_ci ? spirvMagicWord 91e5c31af7Sopenharmony_ci : deReverseBytes32(spirvMagicWord); 92e5c31af7Sopenharmony_ci 93e5c31af7Sopenharmony_ci DE_ASSERT(binary.getFormat() == PROGRAM_FORMAT_SPIRV); 94e5c31af7Sopenharmony_ci 95e5c31af7Sopenharmony_ci if (binary.getSize() % sizeof(deUint32) != 0) 96e5c31af7Sopenharmony_ci return false; 97e5c31af7Sopenharmony_ci 98e5c31af7Sopenharmony_ci if (binary.getSize() < sizeof(deUint32)) 99e5c31af7Sopenharmony_ci return false; 100e5c31af7Sopenharmony_ci 101e5c31af7Sopenharmony_ci if (*(const deUint32*)binary.getBinary() != spirvMagicBytes) 102e5c31af7Sopenharmony_ci return false; 103e5c31af7Sopenharmony_ci 104e5c31af7Sopenharmony_ci return true; 105e5c31af7Sopenharmony_ci} 106e5c31af7Sopenharmony_ci 107e5c31af7Sopenharmony_civoid optimizeCompiledBinary (vector<deUint32>& binary, int optimizationRecipe, const SpirvVersion spirvVersion) 108e5c31af7Sopenharmony_ci{ 109e5c31af7Sopenharmony_ci spv_target_env targetEnv = SPV_ENV_VULKAN_1_0; 110e5c31af7Sopenharmony_ci 111e5c31af7Sopenharmony_ci // Map SpirvVersion with spv_target_env: 112e5c31af7Sopenharmony_ci switch (spirvVersion) 113e5c31af7Sopenharmony_ci { 114e5c31af7Sopenharmony_ci case SPIRV_VERSION_1_0: targetEnv = SPV_ENV_VULKAN_1_0; break; 115e5c31af7Sopenharmony_ci case SPIRV_VERSION_1_1: 116e5c31af7Sopenharmony_ci case SPIRV_VERSION_1_2: 117e5c31af7Sopenharmony_ci case SPIRV_VERSION_1_3: targetEnv = SPV_ENV_VULKAN_1_1; break; 118e5c31af7Sopenharmony_ci case SPIRV_VERSION_1_4: targetEnv = SPV_ENV_VULKAN_1_1_SPIRV_1_4; break; 119e5c31af7Sopenharmony_ci case SPIRV_VERSION_1_5: targetEnv = SPV_ENV_VULKAN_1_2; break; 120e5c31af7Sopenharmony_ci case SPIRV_VERSION_1_6: targetEnv = SPV_ENV_VULKAN_1_3; break; 121e5c31af7Sopenharmony_ci default: 122e5c31af7Sopenharmony_ci TCU_THROW(InternalError, "Unexpected SPIR-V version requested"); 123e5c31af7Sopenharmony_ci } 124e5c31af7Sopenharmony_ci 125e5c31af7Sopenharmony_ci spvtools::Optimizer optimizer(targetEnv); 126e5c31af7Sopenharmony_ci 127e5c31af7Sopenharmony_ci switch (optimizationRecipe) 128e5c31af7Sopenharmony_ci { 129e5c31af7Sopenharmony_ci case 1: 130e5c31af7Sopenharmony_ci optimizer.RegisterPerformancePasses(); 131e5c31af7Sopenharmony_ci break; 132e5c31af7Sopenharmony_ci case 2: 133e5c31af7Sopenharmony_ci optimizer.RegisterSizePasses(); 134e5c31af7Sopenharmony_ci break; 135e5c31af7Sopenharmony_ci default: 136e5c31af7Sopenharmony_ci TCU_THROW(InternalError, "Unknown optimization recipe requested"); 137e5c31af7Sopenharmony_ci } 138e5c31af7Sopenharmony_ci 139e5c31af7Sopenharmony_ci spvtools::OptimizerOptions optimizer_options; 140e5c31af7Sopenharmony_ci optimizer_options.set_run_validator(false); 141e5c31af7Sopenharmony_ci const bool ok = optimizer.Run(binary.data(), binary.size(), &binary, optimizer_options); 142e5c31af7Sopenharmony_ci 143e5c31af7Sopenharmony_ci if (!ok) 144e5c31af7Sopenharmony_ci TCU_THROW(InternalError, "Optimizer call failed"); 145e5c31af7Sopenharmony_ci} 146e5c31af7Sopenharmony_ci 147e5c31af7Sopenharmony_ciProgramBinary* createProgramBinaryFromSpirV (const vector<deUint32>& binary) 148e5c31af7Sopenharmony_ci{ 149e5c31af7Sopenharmony_ci DE_ASSERT(!binary.empty()); 150e5c31af7Sopenharmony_ci 151e5c31af7Sopenharmony_ci if (isNativeSpirVBinaryEndianness()) 152e5c31af7Sopenharmony_ci return new ProgramBinary(PROGRAM_FORMAT_SPIRV, binary.size()*sizeof(deUint32), (const deUint8*)&binary[0]); 153e5c31af7Sopenharmony_ci else 154e5c31af7Sopenharmony_ci TCU_THROW(InternalError, "SPIR-V endianness translation not supported"); 155e5c31af7Sopenharmony_ci} 156e5c31af7Sopenharmony_ci 157e5c31af7Sopenharmony_ci} // anonymous 158e5c31af7Sopenharmony_ci 159e5c31af7Sopenharmony_civoid validateCompiledBinary(const vector<deUint32>& binary, glu::ShaderProgramInfo* buildInfo, const SpirvValidatorOptions& options) 160e5c31af7Sopenharmony_ci{ 161e5c31af7Sopenharmony_ci std::ostringstream validationLog; 162e5c31af7Sopenharmony_ci 163e5c31af7Sopenharmony_ci if (!validateSpirV(binary.size(), &binary[0], &validationLog, options)) 164e5c31af7Sopenharmony_ci { 165e5c31af7Sopenharmony_ci buildInfo->program.linkOk = false; 166e5c31af7Sopenharmony_ci buildInfo->program.infoLog += "\n" + validationLog.str(); 167e5c31af7Sopenharmony_ci 168e5c31af7Sopenharmony_ci TCU_THROW(InternalError, "Validation failed for compiled SPIR-V binary"); 169e5c31af7Sopenharmony_ci } 170e5c31af7Sopenharmony_ci} 171e5c31af7Sopenharmony_ci 172e5c31af7Sopenharmony_civoid validateCompiledBinary(const vector<deUint32>& binary, SpirVProgramInfo* buildInfo, const SpirvValidatorOptions& options) 173e5c31af7Sopenharmony_ci{ 174e5c31af7Sopenharmony_ci std::ostringstream validationLog; 175e5c31af7Sopenharmony_ci 176e5c31af7Sopenharmony_ci if (!validateSpirV(binary.size(), &binary[0], &validationLog, options)) 177e5c31af7Sopenharmony_ci { 178e5c31af7Sopenharmony_ci buildInfo->compileOk = false; 179e5c31af7Sopenharmony_ci buildInfo->infoLog += "\n" + validationLog.str(); 180e5c31af7Sopenharmony_ci 181e5c31af7Sopenharmony_ci TCU_THROW(InternalError, "Validation failed for compiled SPIR-V binary"); 182e5c31af7Sopenharmony_ci } 183e5c31af7Sopenharmony_ci} 184e5c31af7Sopenharmony_ci 185e5c31af7Sopenharmony_ci// IPC functions 186e5c31af7Sopenharmony_ci#ifndef DISABLE_SHADERCACHE_IPC 187e5c31af7Sopenharmony_ci#include "vkIPC.inl" 188e5c31af7Sopenharmony_ci#endif 189e5c31af7Sopenharmony_ci 190e5c31af7Sopenharmony_ci// Overridable wrapper for de::Mutex 191e5c31af7Sopenharmony_ciclass cacheMutex 192e5c31af7Sopenharmony_ci{ 193e5c31af7Sopenharmony_cipublic: 194e5c31af7Sopenharmony_ci cacheMutex () {} 195e5c31af7Sopenharmony_ci virtual ~cacheMutex () {} 196e5c31af7Sopenharmony_ci virtual void lock () { localMutex.lock(); } 197e5c31af7Sopenharmony_ci virtual void unlock () { localMutex.unlock(); } 198e5c31af7Sopenharmony_ciprivate: 199e5c31af7Sopenharmony_ci de::Mutex localMutex; 200e5c31af7Sopenharmony_ci}; 201e5c31af7Sopenharmony_ci 202e5c31af7Sopenharmony_ci#ifndef DISABLE_SHADERCACHE_IPC 203e5c31af7Sopenharmony_ci// Overriden cacheMutex that uses IPC instead 204e5c31af7Sopenharmony_ciclass cacheMutexIPC : public cacheMutex 205e5c31af7Sopenharmony_ci{ 206e5c31af7Sopenharmony_cipublic: 207e5c31af7Sopenharmony_ci cacheMutexIPC () 208e5c31af7Sopenharmony_ci { 209e5c31af7Sopenharmony_ci ipc_sem_init(&guard, "cts_shadercache_ipc_guard"); 210e5c31af7Sopenharmony_ci ipc_sem_create(&guard, 1); 211e5c31af7Sopenharmony_ci } 212e5c31af7Sopenharmony_ci virtual ~cacheMutexIPC () 213e5c31af7Sopenharmony_ci { 214e5c31af7Sopenharmony_ci ipc_sem_close(&guard); 215e5c31af7Sopenharmony_ci } 216e5c31af7Sopenharmony_ci virtual void lock () { ipc_sem_decrement(&guard); } 217e5c31af7Sopenharmony_ci virtual void unlock () { ipc_sem_increment(&guard); } 218e5c31af7Sopenharmony_ciprivate: 219e5c31af7Sopenharmony_ci ipc_sharedsemaphore guard; 220e5c31af7Sopenharmony_ci}; 221e5c31af7Sopenharmony_ci#endif 222e5c31af7Sopenharmony_ci 223e5c31af7Sopenharmony_ci// Each cache node takes 4 * 4 = 16 bytes; 1M items takes 16M memory. 224e5c31af7Sopenharmony_ciconst deUint32 cacheMaxItems = 1024 * 1024; 225e5c31af7Sopenharmony_cicacheMutex* cacheFileMutex = nullptr; 226e5c31af7Sopenharmony_cideUint32* cacheMempool = nullptr; 227e5c31af7Sopenharmony_ci#ifndef DISABLE_SHADERCACHE_IPC 228e5c31af7Sopenharmony_ciipc_sharedmemory cacheIPCMemory; 229e5c31af7Sopenharmony_ci#endif 230e5c31af7Sopenharmony_ci 231e5c31af7Sopenharmony_cistruct cacheNode 232e5c31af7Sopenharmony_ci{ 233e5c31af7Sopenharmony_ci deUint32 key; 234e5c31af7Sopenharmony_ci deUint32 data; 235e5c31af7Sopenharmony_ci deUint32 right_child; 236e5c31af7Sopenharmony_ci deUint32 left_child; 237e5c31af7Sopenharmony_ci}; 238e5c31af7Sopenharmony_ci 239e5c31af7Sopenharmony_cicacheNode* cacheSearch (deUint32 key) 240e5c31af7Sopenharmony_ci{ 241e5c31af7Sopenharmony_ci cacheNode* r = (cacheNode*)(cacheMempool + 1); 242e5c31af7Sopenharmony_ci int* tail = (int*)cacheMempool; 243e5c31af7Sopenharmony_ci unsigned int p = 0; 244e5c31af7Sopenharmony_ci 245e5c31af7Sopenharmony_ci if (!*tail) { 246e5c31af7Sopenharmony_ci // Cache is empty. 247e5c31af7Sopenharmony_ci return 0; 248e5c31af7Sopenharmony_ci } 249e5c31af7Sopenharmony_ci 250e5c31af7Sopenharmony_ci while (1) 251e5c31af7Sopenharmony_ci { 252e5c31af7Sopenharmony_ci if (r[p].key == key) 253e5c31af7Sopenharmony_ci return &r[p]; 254e5c31af7Sopenharmony_ci 255e5c31af7Sopenharmony_ci if (key > r[p].key) 256e5c31af7Sopenharmony_ci p = r[p].right_child; 257e5c31af7Sopenharmony_ci else 258e5c31af7Sopenharmony_ci p = r[p].left_child; 259e5c31af7Sopenharmony_ci 260e5c31af7Sopenharmony_ci if (p == 0) 261e5c31af7Sopenharmony_ci return 0; 262e5c31af7Sopenharmony_ci } 263e5c31af7Sopenharmony_ci} 264e5c31af7Sopenharmony_ci 265e5c31af7Sopenharmony_civoid cacheInsert (deUint32 key, deUint32 data) 266e5c31af7Sopenharmony_ci{ 267e5c31af7Sopenharmony_ci cacheNode* r = (cacheNode*)(cacheMempool + 1); 268e5c31af7Sopenharmony_ci int* tail = (int*)cacheMempool; 269e5c31af7Sopenharmony_ci int newnode = *tail; 270e5c31af7Sopenharmony_ci 271e5c31af7Sopenharmony_ci DE_ASSERT(newnode < cacheMaxItems); 272e5c31af7Sopenharmony_ci 273e5c31af7Sopenharmony_ci // If we run out of cache space, reset the cache index. 274e5c31af7Sopenharmony_ci if (newnode >= cacheMaxItems) 275e5c31af7Sopenharmony_ci { 276e5c31af7Sopenharmony_ci *tail = 0; 277e5c31af7Sopenharmony_ci newnode = 0; 278e5c31af7Sopenharmony_ci } 279e5c31af7Sopenharmony_ci 280e5c31af7Sopenharmony_ci r[*tail].data = data; 281e5c31af7Sopenharmony_ci r[*tail].key = key; 282e5c31af7Sopenharmony_ci r[*tail].left_child = 0; 283e5c31af7Sopenharmony_ci r[*tail].right_child = 0; 284e5c31af7Sopenharmony_ci 285e5c31af7Sopenharmony_ci (*tail)++; 286e5c31af7Sopenharmony_ci 287e5c31af7Sopenharmony_ci if (newnode == 0) 288e5c31af7Sopenharmony_ci { 289e5c31af7Sopenharmony_ci // first 290e5c31af7Sopenharmony_ci return; 291e5c31af7Sopenharmony_ci } 292e5c31af7Sopenharmony_ci 293e5c31af7Sopenharmony_ci int p = 0; 294e5c31af7Sopenharmony_ci while (1) 295e5c31af7Sopenharmony_ci { 296e5c31af7Sopenharmony_ci if (r[p].key == key) 297e5c31af7Sopenharmony_ci { 298e5c31af7Sopenharmony_ci // collision; use the latest data 299e5c31af7Sopenharmony_ci r[p].data = data; 300e5c31af7Sopenharmony_ci (*tail)--; 301e5c31af7Sopenharmony_ci return; 302e5c31af7Sopenharmony_ci } 303e5c31af7Sopenharmony_ci 304e5c31af7Sopenharmony_ci if (key > r[p].key) 305e5c31af7Sopenharmony_ci { 306e5c31af7Sopenharmony_ci if (r[p].right_child != 0) 307e5c31af7Sopenharmony_ci { 308e5c31af7Sopenharmony_ci p = r[p].right_child; 309e5c31af7Sopenharmony_ci } 310e5c31af7Sopenharmony_ci else 311e5c31af7Sopenharmony_ci { 312e5c31af7Sopenharmony_ci r[p].right_child = newnode; 313e5c31af7Sopenharmony_ci return; 314e5c31af7Sopenharmony_ci } 315e5c31af7Sopenharmony_ci } 316e5c31af7Sopenharmony_ci else 317e5c31af7Sopenharmony_ci { 318e5c31af7Sopenharmony_ci if (r[p].left_child != 0) 319e5c31af7Sopenharmony_ci { 320e5c31af7Sopenharmony_ci p = r[p].left_child; 321e5c31af7Sopenharmony_ci } 322e5c31af7Sopenharmony_ci else 323e5c31af7Sopenharmony_ci { 324e5c31af7Sopenharmony_ci r[p].left_child = newnode; 325e5c31af7Sopenharmony_ci return; 326e5c31af7Sopenharmony_ci } 327e5c31af7Sopenharmony_ci } 328e5c31af7Sopenharmony_ci } 329e5c31af7Sopenharmony_ci} 330e5c31af7Sopenharmony_ci 331e5c31af7Sopenharmony_ci// Called via atexit() 332e5c31af7Sopenharmony_civoid shaderCacheClean () 333e5c31af7Sopenharmony_ci{ 334e5c31af7Sopenharmony_ci delete cacheFileMutex; 335e5c31af7Sopenharmony_ci delete[] cacheMempool; 336e5c31af7Sopenharmony_ci} 337e5c31af7Sopenharmony_ci 338e5c31af7Sopenharmony_ci#ifndef DISABLE_SHADERCACHE_IPC 339e5c31af7Sopenharmony_ci// Called via atexit() 340e5c31af7Sopenharmony_civoid shaderCacheCleanIPC () 341e5c31af7Sopenharmony_ci{ 342e5c31af7Sopenharmony_ci delete cacheFileMutex; 343e5c31af7Sopenharmony_ci ipc_mem_close(&cacheIPCMemory); 344e5c31af7Sopenharmony_ci} 345e5c31af7Sopenharmony_ci#endif 346e5c31af7Sopenharmony_ci 347e5c31af7Sopenharmony_civoid shaderCacheFirstRunCheck (const tcu::CommandLine& commandLine) 348e5c31af7Sopenharmony_ci{ 349e5c31af7Sopenharmony_ci bool first = true; 350e5c31af7Sopenharmony_ci 351e5c31af7Sopenharmony_ci // We need to solve two problems here: 352e5c31af7Sopenharmony_ci // 1) The cache and cache mutex only have to be initialized once by the first thread that arrives here. 353e5c31af7Sopenharmony_ci // 2) We must prevent other threads from exiting early from this function thinking they don't have to initialize the cache and 354e5c31af7Sopenharmony_ci // cache mutex, only to try to lock the cache mutex while the first thread is still initializing it. To prevent this, we must 355e5c31af7Sopenharmony_ci // hold an initialization mutex (declared below) while initializing the cache and cache mutex, making other threads wait. 356e5c31af7Sopenharmony_ci 357e5c31af7Sopenharmony_ci // Used to check and set cacheFileFirstRun. We make it static, and C++11 guarantees it will only be initialized once. 358e5c31af7Sopenharmony_ci static std::mutex cacheFileFirstRunMutex; 359e5c31af7Sopenharmony_ci static bool cacheFileFirstRun = true; 360e5c31af7Sopenharmony_ci 361e5c31af7Sopenharmony_ci // Is cacheFileFirstRun true for this thread? 362e5c31af7Sopenharmony_ci bool needInit = false; 363e5c31af7Sopenharmony_ci 364e5c31af7Sopenharmony_ci // Check cacheFileFirstRun only while holding the mutex, and hold it while initializing the cache. 365e5c31af7Sopenharmony_ci const std::lock_guard<std::mutex> lock(cacheFileFirstRunMutex); 366e5c31af7Sopenharmony_ci if (cacheFileFirstRun) 367e5c31af7Sopenharmony_ci { 368e5c31af7Sopenharmony_ci needInit = true; 369e5c31af7Sopenharmony_ci cacheFileFirstRun = false; 370e5c31af7Sopenharmony_ci } 371e5c31af7Sopenharmony_ci 372e5c31af7Sopenharmony_ci if (needInit) 373e5c31af7Sopenharmony_ci { 374e5c31af7Sopenharmony_ci#ifndef DISABLE_SHADERCACHE_IPC 375e5c31af7Sopenharmony_ci if (commandLine.isShaderCacheIPCEnabled()) 376e5c31af7Sopenharmony_ci { 377e5c31af7Sopenharmony_ci // IPC path, allocate shared mutex and shared memory 378e5c31af7Sopenharmony_ci cacheFileMutex = new cacheMutexIPC; 379e5c31af7Sopenharmony_ci cacheFileMutex->lock(); 380e5c31af7Sopenharmony_ci ipc_mem_init(&cacheIPCMemory, "cts_shadercache_memory", sizeof(deUint32) * (cacheMaxItems * 4 + 1)); 381e5c31af7Sopenharmony_ci if (ipc_mem_open_existing(&cacheIPCMemory) != 0) 382e5c31af7Sopenharmony_ci { 383e5c31af7Sopenharmony_ci ipc_mem_create(&cacheIPCMemory); 384e5c31af7Sopenharmony_ci cacheMempool = (deUint32*)ipc_mem_access(&cacheIPCMemory); 385e5c31af7Sopenharmony_ci cacheMempool[0] = 0; 386e5c31af7Sopenharmony_ci } 387e5c31af7Sopenharmony_ci else 388e5c31af7Sopenharmony_ci { 389e5c31af7Sopenharmony_ci cacheMempool = (deUint32*)ipc_mem_access(&cacheIPCMemory); 390e5c31af7Sopenharmony_ci first = false; 391e5c31af7Sopenharmony_ci } 392e5c31af7Sopenharmony_ci atexit(shaderCacheCleanIPC); 393e5c31af7Sopenharmony_ci } 394e5c31af7Sopenharmony_ci else 395e5c31af7Sopenharmony_ci#endif 396e5c31af7Sopenharmony_ci { 397e5c31af7Sopenharmony_ci // Non-IPC path, allocate local mutex and memory 398e5c31af7Sopenharmony_ci cacheFileMutex = new cacheMutex; 399e5c31af7Sopenharmony_ci cacheFileMutex->lock(); 400e5c31af7Sopenharmony_ci cacheMempool = new deUint32[cacheMaxItems * 4 + 1]; 401e5c31af7Sopenharmony_ci cacheMempool[0] = 0; 402e5c31af7Sopenharmony_ci 403e5c31af7Sopenharmony_ci atexit(shaderCacheClean); 404e5c31af7Sopenharmony_ci } 405e5c31af7Sopenharmony_ci 406e5c31af7Sopenharmony_ci if (first) 407e5c31af7Sopenharmony_ci { 408e5c31af7Sopenharmony_ci if (commandLine.isShaderCacheTruncateEnabled()) 409e5c31af7Sopenharmony_ci { 410e5c31af7Sopenharmony_ci // Open file with "w" access to truncate it 411e5c31af7Sopenharmony_ci FILE* f = fopen(commandLine.getShaderCacheFilename(), "wb"); 412e5c31af7Sopenharmony_ci if (f) 413e5c31af7Sopenharmony_ci fclose(f); 414e5c31af7Sopenharmony_ci } 415e5c31af7Sopenharmony_ci else 416e5c31af7Sopenharmony_ci { 417e5c31af7Sopenharmony_ci // Parse chunked shader cache file for hashes and offsets 418e5c31af7Sopenharmony_ci FILE* file = fopen(commandLine.getShaderCacheFilename(), "rb"); 419e5c31af7Sopenharmony_ci int count = 0; 420e5c31af7Sopenharmony_ci if (file) 421e5c31af7Sopenharmony_ci { 422e5c31af7Sopenharmony_ci deUint32 chunksize = 0; 423e5c31af7Sopenharmony_ci deUint32 hash = 0; 424e5c31af7Sopenharmony_ci deUint32 offset = 0; 425e5c31af7Sopenharmony_ci bool ok = true; 426e5c31af7Sopenharmony_ci while (ok) 427e5c31af7Sopenharmony_ci { 428e5c31af7Sopenharmony_ci offset = (deUint32)ftell(file); 429e5c31af7Sopenharmony_ci if (ok) ok = fread(&chunksize, 1, 4, file) == 4; 430e5c31af7Sopenharmony_ci if (ok) ok = fread(&hash, 1, 4, file) == 4; 431e5c31af7Sopenharmony_ci if (ok) cacheInsert(hash, offset); 432e5c31af7Sopenharmony_ci if (ok) ok = fseek(file, offset + chunksize, SEEK_SET) == 0; 433e5c31af7Sopenharmony_ci count++; 434e5c31af7Sopenharmony_ci } 435e5c31af7Sopenharmony_ci fclose(file); 436e5c31af7Sopenharmony_ci } 437e5c31af7Sopenharmony_ci } 438e5c31af7Sopenharmony_ci } 439e5c31af7Sopenharmony_ci cacheFileMutex->unlock(); 440e5c31af7Sopenharmony_ci } 441e5c31af7Sopenharmony_ci} 442e5c31af7Sopenharmony_ci 443e5c31af7Sopenharmony_cistd::string intToString (deUint32 integer) 444e5c31af7Sopenharmony_ci{ 445e5c31af7Sopenharmony_ci std::stringstream temp_sstream; 446e5c31af7Sopenharmony_ci 447e5c31af7Sopenharmony_ci temp_sstream << integer; 448e5c31af7Sopenharmony_ci 449e5c31af7Sopenharmony_ci return temp_sstream.str(); 450e5c31af7Sopenharmony_ci} 451e5c31af7Sopenharmony_ci 452e5c31af7Sopenharmony_ci// 32-bit FNV-1 hash 453e5c31af7Sopenharmony_cideUint32 shadercacheHash (const char* str) 454e5c31af7Sopenharmony_ci{ 455e5c31af7Sopenharmony_ci deUint32 hash = 0x811c9dc5; 456e5c31af7Sopenharmony_ci deUint32 c; 457e5c31af7Sopenharmony_ci while ((c = (deUint32)*str++) != 0) 458e5c31af7Sopenharmony_ci { 459e5c31af7Sopenharmony_ci hash *= 16777619; 460e5c31af7Sopenharmony_ci hash ^= c; 461e5c31af7Sopenharmony_ci } 462e5c31af7Sopenharmony_ci return hash; 463e5c31af7Sopenharmony_ci} 464e5c31af7Sopenharmony_ci 465e5c31af7Sopenharmony_civk::ProgramBinary* shadercacheLoad (const std::string& shaderstring, const char* shaderCacheFilename, deUint32 hash) 466e5c31af7Sopenharmony_ci{ 467e5c31af7Sopenharmony_ci deInt32 format; 468e5c31af7Sopenharmony_ci deInt32 length; 469e5c31af7Sopenharmony_ci deInt32 sourcelength; 470e5c31af7Sopenharmony_ci deUint32 temp; 471e5c31af7Sopenharmony_ci deUint8* bin = 0; 472e5c31af7Sopenharmony_ci char* source = 0; 473e5c31af7Sopenharmony_ci deBool ok = true; 474e5c31af7Sopenharmony_ci deBool diff = true; 475e5c31af7Sopenharmony_ci cacheNode* node = 0; 476e5c31af7Sopenharmony_ci cacheFileMutex->lock(); 477e5c31af7Sopenharmony_ci 478e5c31af7Sopenharmony_ci node = cacheSearch(hash); 479e5c31af7Sopenharmony_ci if (node == 0) 480e5c31af7Sopenharmony_ci { 481e5c31af7Sopenharmony_ci cacheFileMutex->unlock(); 482e5c31af7Sopenharmony_ci return 0; 483e5c31af7Sopenharmony_ci } 484e5c31af7Sopenharmony_ci FILE* file = fopen(shaderCacheFilename, "rb"); 485e5c31af7Sopenharmony_ci ok = file != 0; 486e5c31af7Sopenharmony_ci 487e5c31af7Sopenharmony_ci if (ok) ok = fseek(file, node->data, SEEK_SET) == 0; 488e5c31af7Sopenharmony_ci if (ok) ok = fread(&temp, 1, 4, file) == 4; // Chunk size (skip) 489e5c31af7Sopenharmony_ci if (ok) ok = fread(&temp, 1, 4, file) == 4; // Stored hash 490e5c31af7Sopenharmony_ci if (ok) ok = temp == hash; // Double check 491e5c31af7Sopenharmony_ci if (ok) ok = fread(&format, 1, 4, file) == 4; 492e5c31af7Sopenharmony_ci if (ok) ok = fread(&length, 1, 4, file) == 4; 493e5c31af7Sopenharmony_ci if (ok) ok = length > 0; // Quick check 494e5c31af7Sopenharmony_ci if (ok) bin = new deUint8[length]; 495e5c31af7Sopenharmony_ci if (ok) ok = fread(bin, 1, length, file) == (size_t)length; 496e5c31af7Sopenharmony_ci if (ok) ok = fread(&sourcelength, 1, 4, file) == 4; 497e5c31af7Sopenharmony_ci if (ok && sourcelength > 0) 498e5c31af7Sopenharmony_ci { 499e5c31af7Sopenharmony_ci source = new char[sourcelength + 1]; 500e5c31af7Sopenharmony_ci ok = fread(source, 1, sourcelength, file) == (size_t)sourcelength; 501e5c31af7Sopenharmony_ci source[sourcelength] = 0; 502e5c31af7Sopenharmony_ci diff = shaderstring != std::string(source); 503e5c31af7Sopenharmony_ci } 504e5c31af7Sopenharmony_ci if (!ok || diff) 505e5c31af7Sopenharmony_ci { 506e5c31af7Sopenharmony_ci // Mismatch 507e5c31af7Sopenharmony_ci delete[] source; 508e5c31af7Sopenharmony_ci delete[] bin; 509e5c31af7Sopenharmony_ci } 510e5c31af7Sopenharmony_ci else 511e5c31af7Sopenharmony_ci { 512e5c31af7Sopenharmony_ci delete[] source; 513e5c31af7Sopenharmony_ci if (file) fclose(file); 514e5c31af7Sopenharmony_ci cacheFileMutex->unlock(); 515e5c31af7Sopenharmony_ci vk::ProgramBinary* res = new vk::ProgramBinary((vk::ProgramFormat)format, length, bin); 516e5c31af7Sopenharmony_ci delete[] bin; 517e5c31af7Sopenharmony_ci return res; 518e5c31af7Sopenharmony_ci } 519e5c31af7Sopenharmony_ci if (file) fclose(file); 520e5c31af7Sopenharmony_ci cacheFileMutex->unlock(); 521e5c31af7Sopenharmony_ci return 0; 522e5c31af7Sopenharmony_ci} 523e5c31af7Sopenharmony_ci 524e5c31af7Sopenharmony_civoid shadercacheSave (const vk::ProgramBinary* binary, const std::string& shaderstring, const char* shaderCacheFilename, deUint32 hash) 525e5c31af7Sopenharmony_ci{ 526e5c31af7Sopenharmony_ci if (binary == 0) 527e5c31af7Sopenharmony_ci return; 528e5c31af7Sopenharmony_ci deInt32 format = binary->getFormat(); 529e5c31af7Sopenharmony_ci deUint32 length = (deUint32)binary->getSize(); 530e5c31af7Sopenharmony_ci deUint32 chunksize; 531e5c31af7Sopenharmony_ci deUint32 offset; 532e5c31af7Sopenharmony_ci const deUint8* bin = binary->getBinary(); 533e5c31af7Sopenharmony_ci const de::FilePath filePath (shaderCacheFilename); 534e5c31af7Sopenharmony_ci cacheNode* node = 0; 535e5c31af7Sopenharmony_ci 536e5c31af7Sopenharmony_ci cacheFileMutex->lock(); 537e5c31af7Sopenharmony_ci 538e5c31af7Sopenharmony_ci node = cacheSearch(hash); 539e5c31af7Sopenharmony_ci 540e5c31af7Sopenharmony_ci if (node) 541e5c31af7Sopenharmony_ci { 542e5c31af7Sopenharmony_ci FILE* file = fopen(shaderCacheFilename, "rb"); 543e5c31af7Sopenharmony_ci deBool ok = (file != 0); 544e5c31af7Sopenharmony_ci deBool diff = DE_TRUE; 545e5c31af7Sopenharmony_ci deInt32 sourcelength; 546e5c31af7Sopenharmony_ci deUint32 temp; 547e5c31af7Sopenharmony_ci 548e5c31af7Sopenharmony_ci deUint32 cachedLength = 0; 549e5c31af7Sopenharmony_ci 550e5c31af7Sopenharmony_ci if (ok) ok = fseek(file, node->data, SEEK_SET) == 0; 551e5c31af7Sopenharmony_ci if (ok) ok = fread(&temp, 1, 4, file) == 4; // Chunk size (skip) 552e5c31af7Sopenharmony_ci if (ok) ok = fread(&temp, 1, 4, file) == 4; // Stored hash 553e5c31af7Sopenharmony_ci if (ok) ok = temp == hash; // Double check 554e5c31af7Sopenharmony_ci if (ok) ok = fread(&temp, 1, 4, file) == 4; 555e5c31af7Sopenharmony_ci if (ok) ok = fread(&cachedLength, 1, 4, file) == 4; 556e5c31af7Sopenharmony_ci if (ok) ok = cachedLength > 0; // Quick check 557e5c31af7Sopenharmony_ci if (ok) fseek(file, cachedLength, SEEK_CUR); // skip binary 558e5c31af7Sopenharmony_ci if (ok) ok = fread(&sourcelength, 1, 4, file) == 4; 559e5c31af7Sopenharmony_ci 560e5c31af7Sopenharmony_ci if (ok && sourcelength > 0) 561e5c31af7Sopenharmony_ci { 562e5c31af7Sopenharmony_ci char* source; 563e5c31af7Sopenharmony_ci source = new char[sourcelength + 1]; 564e5c31af7Sopenharmony_ci ok = fread(source, 1, sourcelength, file) == (size_t)sourcelength; 565e5c31af7Sopenharmony_ci source[sourcelength] = 0; 566e5c31af7Sopenharmony_ci diff = shaderstring != std::string(source); 567e5c31af7Sopenharmony_ci delete[] source; 568e5c31af7Sopenharmony_ci } 569e5c31af7Sopenharmony_ci 570e5c31af7Sopenharmony_ci if (ok && !diff) 571e5c31af7Sopenharmony_ci { 572e5c31af7Sopenharmony_ci // Already in cache (written by another thread, probably) 573e5c31af7Sopenharmony_ci fclose(file); 574e5c31af7Sopenharmony_ci cacheFileMutex->unlock(); 575e5c31af7Sopenharmony_ci return; 576e5c31af7Sopenharmony_ci } 577e5c31af7Sopenharmony_ci fclose(file); 578e5c31af7Sopenharmony_ci } 579e5c31af7Sopenharmony_ci 580e5c31af7Sopenharmony_ci if (!de::FilePath(filePath.getDirName()).exists()) 581e5c31af7Sopenharmony_ci de::createDirectoryAndParents(filePath.getDirName().c_str()); 582e5c31af7Sopenharmony_ci 583e5c31af7Sopenharmony_ci FILE* file = fopen(shaderCacheFilename, "ab"); 584e5c31af7Sopenharmony_ci if (!file) 585e5c31af7Sopenharmony_ci { 586e5c31af7Sopenharmony_ci cacheFileMutex->unlock(); 587e5c31af7Sopenharmony_ci return; 588e5c31af7Sopenharmony_ci } 589e5c31af7Sopenharmony_ci // Append mode starts writing from the end of the file, 590e5c31af7Sopenharmony_ci // but unless we do a seek, ftell returns 0. 591e5c31af7Sopenharmony_ci fseek(file, 0, SEEK_END); 592e5c31af7Sopenharmony_ci offset = (deUint32)ftell(file); 593e5c31af7Sopenharmony_ci chunksize = 4 + 4 + 4 + 4 + length + 4 + (deUint32)shaderstring.length(); 594e5c31af7Sopenharmony_ci fwrite(&chunksize, 1, 4, file); 595e5c31af7Sopenharmony_ci fwrite(&hash, 1, 4, file); 596e5c31af7Sopenharmony_ci fwrite(&format, 1, 4, file); 597e5c31af7Sopenharmony_ci fwrite(&length, 1, 4, file); 598e5c31af7Sopenharmony_ci fwrite(bin, 1, length, file); 599e5c31af7Sopenharmony_ci length = (deUint32)shaderstring.length(); 600e5c31af7Sopenharmony_ci fwrite(&length, 1, 4, file); 601e5c31af7Sopenharmony_ci fwrite(shaderstring.c_str(), 1, length, file); 602e5c31af7Sopenharmony_ci fclose(file); 603e5c31af7Sopenharmony_ci cacheInsert(hash, offset); 604e5c31af7Sopenharmony_ci 605e5c31af7Sopenharmony_ci cacheFileMutex->unlock(); 606e5c31af7Sopenharmony_ci} 607e5c31af7Sopenharmony_ci 608e5c31af7Sopenharmony_ci// Insert any information that may affect compilation into the shader string. 609e5c31af7Sopenharmony_civoid getCompileEnvironment (std::string& shaderstring) 610e5c31af7Sopenharmony_ci{ 611e5c31af7Sopenharmony_ci shaderstring += "GLSL:"; 612e5c31af7Sopenharmony_ci shaderstring += qpGetReleaseGlslName(); 613e5c31af7Sopenharmony_ci shaderstring += "\nSpir-v Tools:"; 614e5c31af7Sopenharmony_ci shaderstring += qpGetReleaseSpirvToolsName(); 615e5c31af7Sopenharmony_ci shaderstring += "\nSpir-v Headers:"; 616e5c31af7Sopenharmony_ci shaderstring += qpGetReleaseSpirvHeadersName(); 617e5c31af7Sopenharmony_ci shaderstring += "\n"; 618e5c31af7Sopenharmony_ci} 619e5c31af7Sopenharmony_ci 620e5c31af7Sopenharmony_ci// Insert compilation options into the shader string. 621e5c31af7Sopenharmony_civoid getBuildOptions (std::string& shaderstring, const ShaderBuildOptions& buildOptions, int optimizationRecipe) 622e5c31af7Sopenharmony_ci{ 623e5c31af7Sopenharmony_ci shaderstring += "Target Spir-V "; 624e5c31af7Sopenharmony_ci shaderstring += getSpirvVersionName(buildOptions.targetVersion); 625e5c31af7Sopenharmony_ci shaderstring += "\n"; 626e5c31af7Sopenharmony_ci if (buildOptions.flags & ShaderBuildOptions::FLAG_ALLOW_RELAXED_OFFSETS) 627e5c31af7Sopenharmony_ci shaderstring += "Flag:Allow relaxed offsets\n"; 628e5c31af7Sopenharmony_ci if (buildOptions.flags & ShaderBuildOptions::FLAG_USE_STORAGE_BUFFER_STORAGE_CLASS) 629e5c31af7Sopenharmony_ci shaderstring += "Flag:Use storage buffer storage class\n"; 630e5c31af7Sopenharmony_ci if (optimizationRecipe != 0) 631e5c31af7Sopenharmony_ci { 632e5c31af7Sopenharmony_ci shaderstring += "Optimization recipe "; 633e5c31af7Sopenharmony_ci shaderstring += de::toString(optimizationRecipe); 634e5c31af7Sopenharmony_ci shaderstring += "\n"; 635e5c31af7Sopenharmony_ci } 636e5c31af7Sopenharmony_ci} 637e5c31af7Sopenharmony_ci 638e5c31af7Sopenharmony_ciProgramBinary* buildProgram (const GlslSource& program, glu::ShaderProgramInfo* buildInfo, const tcu::CommandLine& commandLine) 639e5c31af7Sopenharmony_ci{ 640e5c31af7Sopenharmony_ci const SpirvVersion spirvVersion = program.buildOptions.targetVersion; 641e5c31af7Sopenharmony_ci const bool validateBinary = VALIDATE_BINARIES; 642e5c31af7Sopenharmony_ci vector<deUint32> binary; 643e5c31af7Sopenharmony_ci std::string cachekey; 644e5c31af7Sopenharmony_ci std::string shaderstring; 645e5c31af7Sopenharmony_ci vk::ProgramBinary* res = 0; 646e5c31af7Sopenharmony_ci const int optimizationRecipe = commandLine.getOptimizationRecipe(); 647e5c31af7Sopenharmony_ci deUint32 hash = 0; 648e5c31af7Sopenharmony_ci 649e5c31af7Sopenharmony_ci if (commandLine.isShadercacheEnabled()) 650e5c31af7Sopenharmony_ci { 651e5c31af7Sopenharmony_ci shaderCacheFirstRunCheck(commandLine); 652e5c31af7Sopenharmony_ci getCompileEnvironment(cachekey); 653e5c31af7Sopenharmony_ci getBuildOptions(cachekey, program.buildOptions, optimizationRecipe); 654e5c31af7Sopenharmony_ci 655e5c31af7Sopenharmony_ci for (int i = 0; i < glu::SHADERTYPE_LAST; i++) 656e5c31af7Sopenharmony_ci { 657e5c31af7Sopenharmony_ci if (!program.sources[i].empty()) 658e5c31af7Sopenharmony_ci { 659e5c31af7Sopenharmony_ci cachekey += glu::getShaderTypeName((glu::ShaderType)i); 660e5c31af7Sopenharmony_ci 661e5c31af7Sopenharmony_ci for (std::vector<std::string>::const_iterator it = program.sources[i].begin(); it != program.sources[i].end(); ++it) 662e5c31af7Sopenharmony_ci shaderstring += *it; 663e5c31af7Sopenharmony_ci } 664e5c31af7Sopenharmony_ci } 665e5c31af7Sopenharmony_ci 666e5c31af7Sopenharmony_ci cachekey = cachekey + shaderstring; 667e5c31af7Sopenharmony_ci 668e5c31af7Sopenharmony_ci hash = shadercacheHash(cachekey.c_str()); 669e5c31af7Sopenharmony_ci 670e5c31af7Sopenharmony_ci res = shadercacheLoad(cachekey, commandLine.getShaderCacheFilename(), hash); 671e5c31af7Sopenharmony_ci 672e5c31af7Sopenharmony_ci if (res) 673e5c31af7Sopenharmony_ci { 674e5c31af7Sopenharmony_ci buildInfo->program.infoLog = "Loaded from cache"; 675e5c31af7Sopenharmony_ci buildInfo->program.linkOk = true; 676e5c31af7Sopenharmony_ci buildInfo->program.linkTimeUs = 0; 677e5c31af7Sopenharmony_ci 678e5c31af7Sopenharmony_ci for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; shaderType++) 679e5c31af7Sopenharmony_ci { 680e5c31af7Sopenharmony_ci if (!program.sources[shaderType].empty()) 681e5c31af7Sopenharmony_ci { 682e5c31af7Sopenharmony_ci glu::ShaderInfo shaderBuildInfo; 683e5c31af7Sopenharmony_ci 684e5c31af7Sopenharmony_ci shaderBuildInfo.type = (glu::ShaderType)shaderType; 685e5c31af7Sopenharmony_ci shaderBuildInfo.source = shaderstring; 686e5c31af7Sopenharmony_ci shaderBuildInfo.compileTimeUs = 0; 687e5c31af7Sopenharmony_ci shaderBuildInfo.compileOk = true; 688e5c31af7Sopenharmony_ci 689e5c31af7Sopenharmony_ci buildInfo->shaders.push_back(shaderBuildInfo); 690e5c31af7Sopenharmony_ci } 691e5c31af7Sopenharmony_ci } 692e5c31af7Sopenharmony_ci } 693e5c31af7Sopenharmony_ci } 694e5c31af7Sopenharmony_ci 695e5c31af7Sopenharmony_ci if (!res) 696e5c31af7Sopenharmony_ci { 697e5c31af7Sopenharmony_ci { 698e5c31af7Sopenharmony_ci vector<deUint32> nonStrippedBinary; 699e5c31af7Sopenharmony_ci 700e5c31af7Sopenharmony_ci if (!compileGlslToSpirV(program, &nonStrippedBinary, buildInfo)) 701e5c31af7Sopenharmony_ci TCU_THROW(InternalError, "Compiling GLSL to SPIR-V failed"); 702e5c31af7Sopenharmony_ci 703e5c31af7Sopenharmony_ci TCU_CHECK_INTERNAL(!nonStrippedBinary.empty()); 704e5c31af7Sopenharmony_ci stripSpirVDebugInfo(nonStrippedBinary.size(), &nonStrippedBinary[0], &binary); 705e5c31af7Sopenharmony_ci TCU_CHECK_INTERNAL(!binary.empty()); 706e5c31af7Sopenharmony_ci } 707e5c31af7Sopenharmony_ci 708e5c31af7Sopenharmony_ci if (optimizationRecipe != 0) 709e5c31af7Sopenharmony_ci { 710e5c31af7Sopenharmony_ci validateCompiledBinary(binary, buildInfo, program.buildOptions.getSpirvValidatorOptions()); 711e5c31af7Sopenharmony_ci optimizeCompiledBinary(binary, optimizationRecipe, spirvVersion); 712e5c31af7Sopenharmony_ci } 713e5c31af7Sopenharmony_ci 714e5c31af7Sopenharmony_ci if (validateBinary) 715e5c31af7Sopenharmony_ci { 716e5c31af7Sopenharmony_ci validateCompiledBinary(binary, buildInfo, program.buildOptions.getSpirvValidatorOptions()); 717e5c31af7Sopenharmony_ci } 718e5c31af7Sopenharmony_ci 719e5c31af7Sopenharmony_ci res = createProgramBinaryFromSpirV(binary); 720e5c31af7Sopenharmony_ci if (commandLine.isShadercacheEnabled()) 721e5c31af7Sopenharmony_ci shadercacheSave(res, cachekey, commandLine.getShaderCacheFilename(), hash); 722e5c31af7Sopenharmony_ci } 723e5c31af7Sopenharmony_ci return res; 724e5c31af7Sopenharmony_ci} 725e5c31af7Sopenharmony_ci 726e5c31af7Sopenharmony_ciProgramBinary* buildProgram (const HlslSource& program, glu::ShaderProgramInfo* buildInfo, const tcu::CommandLine& commandLine) 727e5c31af7Sopenharmony_ci{ 728e5c31af7Sopenharmony_ci const SpirvVersion spirvVersion = program.buildOptions.targetVersion; 729e5c31af7Sopenharmony_ci const bool validateBinary = VALIDATE_BINARIES; 730e5c31af7Sopenharmony_ci vector<deUint32> binary; 731e5c31af7Sopenharmony_ci std::string cachekey; 732e5c31af7Sopenharmony_ci std::string shaderstring; 733e5c31af7Sopenharmony_ci vk::ProgramBinary* res = 0; 734e5c31af7Sopenharmony_ci const int optimizationRecipe = commandLine.getOptimizationRecipe(); 735e5c31af7Sopenharmony_ci deInt32 hash = 0; 736e5c31af7Sopenharmony_ci 737e5c31af7Sopenharmony_ci if (commandLine.isShadercacheEnabled()) 738e5c31af7Sopenharmony_ci { 739e5c31af7Sopenharmony_ci shaderCacheFirstRunCheck(commandLine); 740e5c31af7Sopenharmony_ci getCompileEnvironment(cachekey); 741e5c31af7Sopenharmony_ci getBuildOptions(cachekey, program.buildOptions, optimizationRecipe); 742e5c31af7Sopenharmony_ci 743e5c31af7Sopenharmony_ci for (int i = 0; i < glu::SHADERTYPE_LAST; i++) 744e5c31af7Sopenharmony_ci { 745e5c31af7Sopenharmony_ci if (!program.sources[i].empty()) 746e5c31af7Sopenharmony_ci { 747e5c31af7Sopenharmony_ci cachekey += glu::getShaderTypeName((glu::ShaderType)i); 748e5c31af7Sopenharmony_ci 749e5c31af7Sopenharmony_ci for (std::vector<std::string>::const_iterator it = program.sources[i].begin(); it != program.sources[i].end(); ++it) 750e5c31af7Sopenharmony_ci shaderstring += *it; 751e5c31af7Sopenharmony_ci } 752e5c31af7Sopenharmony_ci } 753e5c31af7Sopenharmony_ci 754e5c31af7Sopenharmony_ci cachekey = cachekey + shaderstring; 755e5c31af7Sopenharmony_ci 756e5c31af7Sopenharmony_ci hash = shadercacheHash(cachekey.c_str()); 757e5c31af7Sopenharmony_ci 758e5c31af7Sopenharmony_ci res = shadercacheLoad(cachekey, commandLine.getShaderCacheFilename(), hash); 759e5c31af7Sopenharmony_ci 760e5c31af7Sopenharmony_ci if (res) 761e5c31af7Sopenharmony_ci { 762e5c31af7Sopenharmony_ci buildInfo->program.infoLog = "Loaded from cache"; 763e5c31af7Sopenharmony_ci buildInfo->program.linkOk = true; 764e5c31af7Sopenharmony_ci buildInfo->program.linkTimeUs = 0; 765e5c31af7Sopenharmony_ci 766e5c31af7Sopenharmony_ci for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; shaderType++) 767e5c31af7Sopenharmony_ci { 768e5c31af7Sopenharmony_ci if (!program.sources[shaderType].empty()) 769e5c31af7Sopenharmony_ci { 770e5c31af7Sopenharmony_ci glu::ShaderInfo shaderBuildInfo; 771e5c31af7Sopenharmony_ci 772e5c31af7Sopenharmony_ci shaderBuildInfo.type = (glu::ShaderType)shaderType; 773e5c31af7Sopenharmony_ci shaderBuildInfo.source = shaderstring; 774e5c31af7Sopenharmony_ci shaderBuildInfo.compileTimeUs = 0; 775e5c31af7Sopenharmony_ci shaderBuildInfo.compileOk = true; 776e5c31af7Sopenharmony_ci 777e5c31af7Sopenharmony_ci buildInfo->shaders.push_back(shaderBuildInfo); 778e5c31af7Sopenharmony_ci } 779e5c31af7Sopenharmony_ci } 780e5c31af7Sopenharmony_ci } 781e5c31af7Sopenharmony_ci } 782e5c31af7Sopenharmony_ci 783e5c31af7Sopenharmony_ci if (!res) 784e5c31af7Sopenharmony_ci { 785e5c31af7Sopenharmony_ci { 786e5c31af7Sopenharmony_ci vector<deUint32> nonStrippedBinary; 787e5c31af7Sopenharmony_ci 788e5c31af7Sopenharmony_ci if (!compileHlslToSpirV(program, &nonStrippedBinary, buildInfo)) 789e5c31af7Sopenharmony_ci TCU_THROW(InternalError, "Compiling HLSL to SPIR-V failed"); 790e5c31af7Sopenharmony_ci 791e5c31af7Sopenharmony_ci TCU_CHECK_INTERNAL(!nonStrippedBinary.empty()); 792e5c31af7Sopenharmony_ci stripSpirVDebugInfo(nonStrippedBinary.size(), &nonStrippedBinary[0], &binary); 793e5c31af7Sopenharmony_ci TCU_CHECK_INTERNAL(!binary.empty()); 794e5c31af7Sopenharmony_ci } 795e5c31af7Sopenharmony_ci 796e5c31af7Sopenharmony_ci if (optimizationRecipe != 0) 797e5c31af7Sopenharmony_ci { 798e5c31af7Sopenharmony_ci validateCompiledBinary(binary, buildInfo, program.buildOptions.getSpirvValidatorOptions()); 799e5c31af7Sopenharmony_ci optimizeCompiledBinary(binary, optimizationRecipe, spirvVersion); 800e5c31af7Sopenharmony_ci } 801e5c31af7Sopenharmony_ci 802e5c31af7Sopenharmony_ci if (validateBinary) 803e5c31af7Sopenharmony_ci { 804e5c31af7Sopenharmony_ci validateCompiledBinary(binary, buildInfo, program.buildOptions.getSpirvValidatorOptions()); 805e5c31af7Sopenharmony_ci } 806e5c31af7Sopenharmony_ci 807e5c31af7Sopenharmony_ci res = createProgramBinaryFromSpirV(binary); 808e5c31af7Sopenharmony_ci if (commandLine.isShadercacheEnabled()) 809e5c31af7Sopenharmony_ci { 810e5c31af7Sopenharmony_ci shadercacheSave(res, cachekey, commandLine.getShaderCacheFilename(), hash); 811e5c31af7Sopenharmony_ci } 812e5c31af7Sopenharmony_ci } 813e5c31af7Sopenharmony_ci return res; 814e5c31af7Sopenharmony_ci} 815e5c31af7Sopenharmony_ci 816e5c31af7Sopenharmony_ciProgramBinary* assembleProgram (const SpirVAsmSource& program, SpirVProgramInfo* buildInfo, const tcu::CommandLine& commandLine) 817e5c31af7Sopenharmony_ci{ 818e5c31af7Sopenharmony_ci const SpirvVersion spirvVersion = program.buildOptions.targetVersion; 819e5c31af7Sopenharmony_ci const bool validateBinary = VALIDATE_BINARIES; 820e5c31af7Sopenharmony_ci vector<deUint32> binary; 821e5c31af7Sopenharmony_ci vk::ProgramBinary* res = 0; 822e5c31af7Sopenharmony_ci std::string cachekey; 823e5c31af7Sopenharmony_ci const int optimizationRecipe = commandLine.isSpirvOptimizationEnabled() ? commandLine.getOptimizationRecipe() : 0; 824e5c31af7Sopenharmony_ci deUint32 hash = 0; 825e5c31af7Sopenharmony_ci 826e5c31af7Sopenharmony_ci if (commandLine.isShadercacheEnabled()) 827e5c31af7Sopenharmony_ci { 828e5c31af7Sopenharmony_ci shaderCacheFirstRunCheck(commandLine); 829e5c31af7Sopenharmony_ci getCompileEnvironment(cachekey); 830e5c31af7Sopenharmony_ci cachekey += "Target Spir-V "; 831e5c31af7Sopenharmony_ci cachekey += getSpirvVersionName(spirvVersion); 832e5c31af7Sopenharmony_ci cachekey += "\n"; 833e5c31af7Sopenharmony_ci if (optimizationRecipe != 0) 834e5c31af7Sopenharmony_ci { 835e5c31af7Sopenharmony_ci cachekey += "Optimization recipe "; 836e5c31af7Sopenharmony_ci cachekey += de::toString(optimizationRecipe); 837e5c31af7Sopenharmony_ci cachekey += "\n"; 838e5c31af7Sopenharmony_ci } 839e5c31af7Sopenharmony_ci 840e5c31af7Sopenharmony_ci cachekey += program.source; 841e5c31af7Sopenharmony_ci 842e5c31af7Sopenharmony_ci hash = shadercacheHash(cachekey.c_str()); 843e5c31af7Sopenharmony_ci 844e5c31af7Sopenharmony_ci res = shadercacheLoad(cachekey, commandLine.getShaderCacheFilename(), hash); 845e5c31af7Sopenharmony_ci 846e5c31af7Sopenharmony_ci if (res) 847e5c31af7Sopenharmony_ci { 848e5c31af7Sopenharmony_ci buildInfo->source = program.source; 849e5c31af7Sopenharmony_ci buildInfo->compileOk = true; 850e5c31af7Sopenharmony_ci buildInfo->compileTimeUs = 0; 851e5c31af7Sopenharmony_ci buildInfo->infoLog = "Loaded from cache"; 852e5c31af7Sopenharmony_ci } 853e5c31af7Sopenharmony_ci } 854e5c31af7Sopenharmony_ci 855e5c31af7Sopenharmony_ci if (!res) 856e5c31af7Sopenharmony_ci { 857e5c31af7Sopenharmony_ci 858e5c31af7Sopenharmony_ci if (!assembleSpirV(&program, &binary, buildInfo, spirvVersion)) 859e5c31af7Sopenharmony_ci TCU_THROW(InternalError, "Failed to assemble SPIR-V"); 860e5c31af7Sopenharmony_ci 861e5c31af7Sopenharmony_ci if (optimizationRecipe != 0) 862e5c31af7Sopenharmony_ci { 863e5c31af7Sopenharmony_ci validateCompiledBinary(binary, buildInfo, program.buildOptions.getSpirvValidatorOptions()); 864e5c31af7Sopenharmony_ci optimizeCompiledBinary(binary, optimizationRecipe, spirvVersion); 865e5c31af7Sopenharmony_ci } 866e5c31af7Sopenharmony_ci 867e5c31af7Sopenharmony_ci if (validateBinary) 868e5c31af7Sopenharmony_ci { 869e5c31af7Sopenharmony_ci validateCompiledBinary(binary, buildInfo, program.buildOptions.getSpirvValidatorOptions()); 870e5c31af7Sopenharmony_ci } 871e5c31af7Sopenharmony_ci 872e5c31af7Sopenharmony_ci res = createProgramBinaryFromSpirV(binary); 873e5c31af7Sopenharmony_ci if (commandLine.isShadercacheEnabled()) 874e5c31af7Sopenharmony_ci { 875e5c31af7Sopenharmony_ci shadercacheSave(res, cachekey, commandLine.getShaderCacheFilename(), hash); 876e5c31af7Sopenharmony_ci } 877e5c31af7Sopenharmony_ci } 878e5c31af7Sopenharmony_ci return res; 879e5c31af7Sopenharmony_ci} 880e5c31af7Sopenharmony_ci 881e5c31af7Sopenharmony_civoid disassembleProgram (const ProgramBinary& program, std::ostream* dst) 882e5c31af7Sopenharmony_ci{ 883e5c31af7Sopenharmony_ci if (program.getFormat() == PROGRAM_FORMAT_SPIRV) 884e5c31af7Sopenharmony_ci { 885e5c31af7Sopenharmony_ci TCU_CHECK_INTERNAL(isSaneSpirVBinary(program)); 886e5c31af7Sopenharmony_ci 887e5c31af7Sopenharmony_ci if (isNativeSpirVBinaryEndianness()) 888e5c31af7Sopenharmony_ci disassembleSpirV(program.getSize()/sizeof(deUint32), (const deUint32*)program.getBinary(), dst, 889e5c31af7Sopenharmony_ci extractSpirvVersion(program)); 890e5c31af7Sopenharmony_ci else 891e5c31af7Sopenharmony_ci TCU_THROW(InternalError, "SPIR-V endianness translation not supported"); 892e5c31af7Sopenharmony_ci } 893e5c31af7Sopenharmony_ci else 894e5c31af7Sopenharmony_ci TCU_THROW(NotSupportedError, "Unsupported program format"); 895e5c31af7Sopenharmony_ci} 896e5c31af7Sopenharmony_ci 897e5c31af7Sopenharmony_cibool validateProgram (const ProgramBinary& program, std::ostream* dst, const SpirvValidatorOptions& options) 898e5c31af7Sopenharmony_ci{ 899e5c31af7Sopenharmony_ci if (program.getFormat() == PROGRAM_FORMAT_SPIRV) 900e5c31af7Sopenharmony_ci { 901e5c31af7Sopenharmony_ci if (!isSaneSpirVBinary(program)) 902e5c31af7Sopenharmony_ci { 903e5c31af7Sopenharmony_ci *dst << "Binary doesn't look like SPIR-V at all"; 904e5c31af7Sopenharmony_ci return false; 905e5c31af7Sopenharmony_ci } 906e5c31af7Sopenharmony_ci 907e5c31af7Sopenharmony_ci if (isNativeSpirVBinaryEndianness()) 908e5c31af7Sopenharmony_ci return validateSpirV(program.getSize()/sizeof(deUint32), (const deUint32*)program.getBinary(), dst, options); 909e5c31af7Sopenharmony_ci else 910e5c31af7Sopenharmony_ci TCU_THROW(InternalError, "SPIR-V endianness translation not supported"); 911e5c31af7Sopenharmony_ci } 912e5c31af7Sopenharmony_ci else 913e5c31af7Sopenharmony_ci TCU_THROW(NotSupportedError, "Unsupported program format"); 914e5c31af7Sopenharmony_ci} 915e5c31af7Sopenharmony_ci 916e5c31af7Sopenharmony_ciMove<VkShaderModule> createShaderModule (const DeviceInterface& deviceInterface, VkDevice device, const ProgramBinary& binary, VkShaderModuleCreateFlags flags) 917e5c31af7Sopenharmony_ci{ 918e5c31af7Sopenharmony_ci if (binary.getFormat() == PROGRAM_FORMAT_SPIRV) 919e5c31af7Sopenharmony_ci { 920e5c31af7Sopenharmony_ci const struct VkShaderModuleCreateInfo shaderModuleInfo = 921e5c31af7Sopenharmony_ci { 922e5c31af7Sopenharmony_ci VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, 923e5c31af7Sopenharmony_ci DE_NULL, 924e5c31af7Sopenharmony_ci flags, 925e5c31af7Sopenharmony_ci (deUintptr)binary.getSize(), 926e5c31af7Sopenharmony_ci (const deUint32*)binary.getBinary(), 927e5c31af7Sopenharmony_ci }; 928e5c31af7Sopenharmony_ci 929e5c31af7Sopenharmony_ci binary.setUsed(); 930e5c31af7Sopenharmony_ci 931e5c31af7Sopenharmony_ci return createShaderModule(deviceInterface, device, &shaderModuleInfo); 932e5c31af7Sopenharmony_ci } 933e5c31af7Sopenharmony_ci else 934e5c31af7Sopenharmony_ci TCU_THROW(NotSupportedError, "Unsupported program format"); 935e5c31af7Sopenharmony_ci} 936e5c31af7Sopenharmony_ci 937e5c31af7Sopenharmony_ciglu::ShaderType getGluShaderType (VkShaderStageFlagBits shaderStage) 938e5c31af7Sopenharmony_ci{ 939e5c31af7Sopenharmony_ci switch (shaderStage) 940e5c31af7Sopenharmony_ci { 941e5c31af7Sopenharmony_ci case VK_SHADER_STAGE_VERTEX_BIT: return glu::SHADERTYPE_VERTEX; 942e5c31af7Sopenharmony_ci case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: return glu::SHADERTYPE_TESSELLATION_CONTROL; 943e5c31af7Sopenharmony_ci case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: return glu::SHADERTYPE_TESSELLATION_EVALUATION; 944e5c31af7Sopenharmony_ci case VK_SHADER_STAGE_GEOMETRY_BIT: return glu::SHADERTYPE_GEOMETRY; 945e5c31af7Sopenharmony_ci case VK_SHADER_STAGE_FRAGMENT_BIT: return glu::SHADERTYPE_FRAGMENT; 946e5c31af7Sopenharmony_ci case VK_SHADER_STAGE_COMPUTE_BIT: return glu::SHADERTYPE_COMPUTE; 947e5c31af7Sopenharmony_ci default: 948e5c31af7Sopenharmony_ci DE_FATAL("Unknown shader stage"); 949e5c31af7Sopenharmony_ci return glu::SHADERTYPE_LAST; 950e5c31af7Sopenharmony_ci } 951e5c31af7Sopenharmony_ci} 952e5c31af7Sopenharmony_ci 953e5c31af7Sopenharmony_ciVkShaderStageFlagBits getVkShaderStage (glu::ShaderType shaderType) 954e5c31af7Sopenharmony_ci{ 955e5c31af7Sopenharmony_ci static const VkShaderStageFlagBits s_shaderStages[] = 956e5c31af7Sopenharmony_ci { 957e5c31af7Sopenharmony_ci VK_SHADER_STAGE_VERTEX_BIT, 958e5c31af7Sopenharmony_ci VK_SHADER_STAGE_FRAGMENT_BIT, 959e5c31af7Sopenharmony_ci VK_SHADER_STAGE_GEOMETRY_BIT, 960e5c31af7Sopenharmony_ci VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, 961e5c31af7Sopenharmony_ci VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, 962e5c31af7Sopenharmony_ci VK_SHADER_STAGE_COMPUTE_BIT, 963e5c31af7Sopenharmony_ci#ifndef CTS_USES_VULKANSC 964e5c31af7Sopenharmony_ci VK_SHADER_STAGE_RAYGEN_BIT_NV, 965e5c31af7Sopenharmony_ci VK_SHADER_STAGE_ANY_HIT_BIT_NV, 966e5c31af7Sopenharmony_ci VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV, 967e5c31af7Sopenharmony_ci VK_SHADER_STAGE_MISS_BIT_NV, 968e5c31af7Sopenharmony_ci VK_SHADER_STAGE_INTERSECTION_BIT_NV, 969e5c31af7Sopenharmony_ci VK_SHADER_STAGE_CALLABLE_BIT_NV, 970e5c31af7Sopenharmony_ci VK_SHADER_STAGE_TASK_BIT_NV, 971e5c31af7Sopenharmony_ci VK_SHADER_STAGE_MESH_BIT_NV, 972e5c31af7Sopenharmony_ci#else // CTS_USES_VULKANSC 973e5c31af7Sopenharmony_ci (VkShaderStageFlagBits)64u, 974e5c31af7Sopenharmony_ci (VkShaderStageFlagBits)128u, 975e5c31af7Sopenharmony_ci (VkShaderStageFlagBits)256u, 976e5c31af7Sopenharmony_ci (VkShaderStageFlagBits)512u, 977e5c31af7Sopenharmony_ci (VkShaderStageFlagBits)1024u, 978e5c31af7Sopenharmony_ci (VkShaderStageFlagBits)2048u, 979e5c31af7Sopenharmony_ci (VkShaderStageFlagBits)4096u, 980e5c31af7Sopenharmony_ci (VkShaderStageFlagBits)8192u 981e5c31af7Sopenharmony_ci#endif // CTS_USES_VULKANSC 982e5c31af7Sopenharmony_ci }; 983e5c31af7Sopenharmony_ci 984e5c31af7Sopenharmony_ci return de::getSizedArrayElement<glu::SHADERTYPE_LAST>(s_shaderStages, shaderType); 985e5c31af7Sopenharmony_ci} 986e5c31af7Sopenharmony_ci 987e5c31af7Sopenharmony_ci// Baseline version, to be used for shaders which don't specify a version 988e5c31af7Sopenharmony_civk::SpirvVersion getBaselineSpirvVersion (const deUint32 /* vulkanVersion */) 989e5c31af7Sopenharmony_ci{ 990e5c31af7Sopenharmony_ci return vk::SPIRV_VERSION_1_0; 991e5c31af7Sopenharmony_ci} 992e5c31af7Sopenharmony_ci 993e5c31af7Sopenharmony_ci// Max supported versions for each Vulkan version, without requiring a Vulkan extension. 994e5c31af7Sopenharmony_civk::SpirvVersion getMaxSpirvVersionForVulkan (const deUint32 vulkanVersion) 995e5c31af7Sopenharmony_ci{ 996e5c31af7Sopenharmony_ci vk::SpirvVersion result = vk::SPIRV_VERSION_LAST; 997e5c31af7Sopenharmony_ci 998e5c31af7Sopenharmony_ci deUint32 vulkanVersionVariantMajorMinor = VK_MAKE_API_VERSION(VK_API_VERSION_VARIANT(vulkanVersion), VK_API_VERSION_MAJOR(vulkanVersion), VK_API_VERSION_MINOR(vulkanVersion), 0); 999e5c31af7Sopenharmony_ci if (vulkanVersionVariantMajorMinor == VK_API_VERSION_1_0) 1000e5c31af7Sopenharmony_ci result = vk::SPIRV_VERSION_1_0; 1001e5c31af7Sopenharmony_ci else if (vulkanVersionVariantMajorMinor == VK_API_VERSION_1_1) 1002e5c31af7Sopenharmony_ci result = vk::SPIRV_VERSION_1_3; 1003e5c31af7Sopenharmony_ci#ifndef CTS_USES_VULKANSC 1004e5c31af7Sopenharmony_ci else if (vulkanVersionVariantMajorMinor == VK_API_VERSION_1_2) 1005e5c31af7Sopenharmony_ci result = vk::SPIRV_VERSION_1_5; 1006e5c31af7Sopenharmony_ci else if (vulkanVersionVariantMajorMinor >= VK_API_VERSION_1_3) 1007e5c31af7Sopenharmony_ci result = vk::SPIRV_VERSION_1_6; 1008e5c31af7Sopenharmony_ci#else 1009e5c31af7Sopenharmony_ci else if (vulkanVersionVariantMajorMinor >= VK_API_VERSION_1_2) 1010e5c31af7Sopenharmony_ci result = vk::SPIRV_VERSION_1_5; 1011e5c31af7Sopenharmony_ci#endif // CTS_USES_VULKANSC 1012e5c31af7Sopenharmony_ci 1013e5c31af7Sopenharmony_ci DE_ASSERT(result < vk::SPIRV_VERSION_LAST); 1014e5c31af7Sopenharmony_ci 1015e5c31af7Sopenharmony_ci return result; 1016e5c31af7Sopenharmony_ci} 1017e5c31af7Sopenharmony_ci 1018e5c31af7Sopenharmony_civk::SpirvVersion getMaxSpirvVersionForAsm (const deUint32 vulkanVersion) 1019e5c31af7Sopenharmony_ci{ 1020e5c31af7Sopenharmony_ci return getMaxSpirvVersionForVulkan(vulkanVersion); 1021e5c31af7Sopenharmony_ci} 1022e5c31af7Sopenharmony_ci 1023e5c31af7Sopenharmony_civk::SpirvVersion getMaxSpirvVersionForGlsl (const deUint32 vulkanVersion) 1024e5c31af7Sopenharmony_ci{ 1025e5c31af7Sopenharmony_ci return getMaxSpirvVersionForVulkan(vulkanVersion); 1026e5c31af7Sopenharmony_ci} 1027e5c31af7Sopenharmony_ci 1028e5c31af7Sopenharmony_ciSpirvVersion extractSpirvVersion (const ProgramBinary& binary) 1029e5c31af7Sopenharmony_ci{ 1030e5c31af7Sopenharmony_ci DE_STATIC_ASSERT(SPIRV_VERSION_1_6 + 1 == SPIRV_VERSION_LAST); 1031e5c31af7Sopenharmony_ci 1032e5c31af7Sopenharmony_ci if (binary.getFormat() != PROGRAM_FORMAT_SPIRV) 1033e5c31af7Sopenharmony_ci TCU_THROW(InternalError, "Binary is not in SPIR-V format"); 1034e5c31af7Sopenharmony_ci 1035e5c31af7Sopenharmony_ci if (!isSaneSpirVBinary(binary) || binary.getSize() < sizeof(SpirvBinaryHeader)) 1036e5c31af7Sopenharmony_ci TCU_THROW(InternalError, "Invalid SPIR-V header format"); 1037e5c31af7Sopenharmony_ci 1038e5c31af7Sopenharmony_ci const deUint32 spirvBinaryVersion10 = 0x00010000; 1039e5c31af7Sopenharmony_ci const deUint32 spirvBinaryVersion11 = 0x00010100; 1040e5c31af7Sopenharmony_ci const deUint32 spirvBinaryVersion12 = 0x00010200; 1041e5c31af7Sopenharmony_ci const deUint32 spirvBinaryVersion13 = 0x00010300; 1042e5c31af7Sopenharmony_ci const deUint32 spirvBinaryVersion14 = 0x00010400; 1043e5c31af7Sopenharmony_ci const deUint32 spirvBinaryVersion15 = 0x00010500; 1044e5c31af7Sopenharmony_ci const deUint32 spirvBinaryVersion16 = 0x00010600; 1045e5c31af7Sopenharmony_ci const SpirvBinaryHeader* header = reinterpret_cast<const SpirvBinaryHeader*>(binary.getBinary()); 1046e5c31af7Sopenharmony_ci const deUint32 spirvVersion = isNativeSpirVBinaryEndianness() 1047e5c31af7Sopenharmony_ci ? header->version 1048e5c31af7Sopenharmony_ci : deReverseBytes32(header->version); 1049e5c31af7Sopenharmony_ci SpirvVersion result = SPIRV_VERSION_LAST; 1050e5c31af7Sopenharmony_ci 1051e5c31af7Sopenharmony_ci switch (spirvVersion) 1052e5c31af7Sopenharmony_ci { 1053e5c31af7Sopenharmony_ci case spirvBinaryVersion10: result = SPIRV_VERSION_1_0; break; //!< SPIR-V 1.0 1054e5c31af7Sopenharmony_ci case spirvBinaryVersion11: result = SPIRV_VERSION_1_1; break; //!< SPIR-V 1.1 1055e5c31af7Sopenharmony_ci case spirvBinaryVersion12: result = SPIRV_VERSION_1_2; break; //!< SPIR-V 1.2 1056e5c31af7Sopenharmony_ci case spirvBinaryVersion13: result = SPIRV_VERSION_1_3; break; //!< SPIR-V 1.3 1057e5c31af7Sopenharmony_ci case spirvBinaryVersion14: result = SPIRV_VERSION_1_4; break; //!< SPIR-V 1.4 1058e5c31af7Sopenharmony_ci case spirvBinaryVersion15: result = SPIRV_VERSION_1_5; break; //!< SPIR-V 1.5 1059e5c31af7Sopenharmony_ci case spirvBinaryVersion16: result = SPIRV_VERSION_1_6; break; //!< SPIR-V 1.6 1060e5c31af7Sopenharmony_ci default: TCU_THROW(InternalError, "Unknown SPIR-V version detected in binary"); 1061e5c31af7Sopenharmony_ci } 1062e5c31af7Sopenharmony_ci 1063e5c31af7Sopenharmony_ci return result; 1064e5c31af7Sopenharmony_ci} 1065e5c31af7Sopenharmony_ci 1066e5c31af7Sopenharmony_cistd::string getSpirvVersionName (const SpirvVersion spirvVersion) 1067e5c31af7Sopenharmony_ci{ 1068e5c31af7Sopenharmony_ci DE_STATIC_ASSERT(SPIRV_VERSION_1_6 + 1 == SPIRV_VERSION_LAST); 1069e5c31af7Sopenharmony_ci DE_ASSERT(spirvVersion < SPIRV_VERSION_LAST); 1070e5c31af7Sopenharmony_ci 1071e5c31af7Sopenharmony_ci std::string result; 1072e5c31af7Sopenharmony_ci 1073e5c31af7Sopenharmony_ci switch (spirvVersion) 1074e5c31af7Sopenharmony_ci { 1075e5c31af7Sopenharmony_ci case SPIRV_VERSION_1_0: result = "1.0"; break; //!< SPIR-V 1.0 1076e5c31af7Sopenharmony_ci case SPIRV_VERSION_1_1: result = "1.1"; break; //!< SPIR-V 1.1 1077e5c31af7Sopenharmony_ci case SPIRV_VERSION_1_2: result = "1.2"; break; //!< SPIR-V 1.2 1078e5c31af7Sopenharmony_ci case SPIRV_VERSION_1_3: result = "1.3"; break; //!< SPIR-V 1.3 1079e5c31af7Sopenharmony_ci case SPIRV_VERSION_1_4: result = "1.4"; break; //!< SPIR-V 1.4 1080e5c31af7Sopenharmony_ci case SPIRV_VERSION_1_5: result = "1.5"; break; //!< SPIR-V 1.5 1081e5c31af7Sopenharmony_ci case SPIRV_VERSION_1_6: result = "1.6"; break; //!< SPIR-V 1.6 1082e5c31af7Sopenharmony_ci default: result = "Unknown"; 1083e5c31af7Sopenharmony_ci } 1084e5c31af7Sopenharmony_ci 1085e5c31af7Sopenharmony_ci return result; 1086e5c31af7Sopenharmony_ci} 1087e5c31af7Sopenharmony_ci 1088e5c31af7Sopenharmony_ciSpirvVersion& operator++(SpirvVersion& spirvVersion) 1089e5c31af7Sopenharmony_ci{ 1090e5c31af7Sopenharmony_ci if (spirvVersion == SPIRV_VERSION_LAST) 1091e5c31af7Sopenharmony_ci spirvVersion = SPIRV_VERSION_1_0; 1092e5c31af7Sopenharmony_ci else 1093e5c31af7Sopenharmony_ci spirvVersion = static_cast<SpirvVersion>(static_cast<deUint32>(spirvVersion) + 1); 1094e5c31af7Sopenharmony_ci 1095e5c31af7Sopenharmony_ci return spirvVersion; 1096e5c31af7Sopenharmony_ci} 1097e5c31af7Sopenharmony_ci 1098e5c31af7Sopenharmony_ci} // vk 1099