/* * SPIRVSupport.cpp * * Copyright (c) 2015-2020 The Brenwill Workshop Ltd. (http://www.brenwill.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "SPIRVSupport.h" #include "MVKStrings.h" #include #include #import using namespace mvk; using namespace std; void mvk::spirvToBytes(const vector& spv, vector& bytes) { // Assumes desired endianness. size_t byteCnt = spv.size() * sizeof(uint32_t); char* cBytes = (char*)spv.data(); bytes.clear(); bytes.insert(bytes.end(), cBytes, cBytes + byteCnt); } void mvk::spirvToHeaderBytes(const vector& spv, vector& bytes, const string& varName) { bytes.clear(); charvectorbuf cb(&bytes); ostream hdr(&cb); size_t spvCnt = spv.size(); hdr << "// Automatically generated. Do not edit.\n\n"; hdr << "#include \n\n"; hdr << "\tstatic const uint32_t " << cleanseVarName(varName) << '[' << spvCnt << "] = {"; // Output the SPIR-V content, 8 elements per line if (spvCnt > 0) { hdr << "\n\t\t" << spv.front(); for (size_t spvIdx = 1; spvIdx < spvCnt; spvIdx++) { hdr << (spvIdx % 8 ? ", " : ",\n\t\t") << spv[spvIdx]; } } hdr << "\n\t};\n"; } void mvk::bytesToSPIRV(const vector& bytes, vector& spv) { size_t spvCnt = bytes.size() / sizeof(uint32_t); uint32_t* cSPV = (uint32_t*)bytes.data(); spv.clear(); spv.insert(spv.end(), cSPV, cSPV + spvCnt); ensureSPIRVEndianness(spv); } bool mvk::ensureSPIRVEndianness(vector& spv) { if (spv.empty()) { return false; } // Nothing to convert uint32_t magNum = spv.front(); if (magNum == spv::MagicNumber) { return false; } // No need to convert if (CFSwapInt32(magNum) == spv::MagicNumber) { // Yep, it's SPIR-V, but wrong endianness for (auto& elem : spv) { elem = CFSwapInt32(elem); } return true; } return false; // Not SPIR-V, so don't convert } // Optionally exclude including SPIRV-Tools components. #ifdef MVK_EXCLUDE_SPIRV_TOOLS void mvk::logSPIRV(vector& /*spirv*/, string& spvLog) { spvLog.append("\n"); spvLog.append("Decompiled SPIR-V is unavailable. To log decompiled SPIR-V code,\n"); spvLog.append("build MoltenVK without the MVK_EXCLUDE_SPIRV_TOOLS build setting."); spvLog.append("\n"); } #else #include void mvk::logSPIRV(vector& spirv, string& spvLog) { if ( !((spirv.size() > 4) && (spirv[0] == spv::MagicNumber) && (spirv[4] == 0)) ) { return; } uint32_t options = (SPV_BINARY_TO_TEXT_OPTION_INDENT); spv_text text; spv_diagnostic diagnostic = nullptr; spv_context context = spvContextCreate(SPV_ENV_VULKAN_1_0); spv_result_t error = spvBinaryToText(context, spirv.data(), spirv.size(), options, &text, &diagnostic); spvContextDestroy(context); if (error) { spvDiagnosticPrint(diagnostic); spvDiagnosticDestroy(diagnostic); return; } spvLog.append(text->str, text->length); spvTextDestroy(text); } #endif