Update to latest Vulkan-LoaderAndValidationLayers version. Update to latest VulkanSamples version. Update to latest SPIRV-Cross version.
272 lines
11 KiB
C++
272 lines
11 KiB
C++
/*
|
|
* GLSLToSPIRVConverter.cpp
|
|
*
|
|
* Copyright (c) 2014-2018 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 "GLSLToSPIRVConverter.h"
|
|
#include "MVKCommonEnvironment.h"
|
|
#include "SPIRVToMSLConverter.h"
|
|
#include "MVKStrings.h"
|
|
#include "GlslangToSpv.h"
|
|
#include "../glslang/SPIRV/disassemble.h"
|
|
#include "doc.h"
|
|
#include <sstream>
|
|
|
|
using namespace std;
|
|
using namespace mvk;
|
|
|
|
|
|
#pragma mark -
|
|
#pragma mark GLSLToSPIRVConverter
|
|
|
|
/** Configures the specified limit resources structure used by the GLSL compiler. */
|
|
void configureGLSLCompilerResources(TBuiltInResource* glslCompilerResources);
|
|
|
|
/** Returns the GLSL compiler language type corresponding to the specified MoltenVK shader stage. */
|
|
EShLanguage eshLanguageFromMVKShaderStage(const MVKShaderStage mvkShaderStage);
|
|
|
|
MVK_PUBLIC_SYMBOL void GLSLToSPIRVConverter::setGLSL(const string& glslSrc) { _glsl = glslSrc; }
|
|
|
|
MVK_PUBLIC_SYMBOL const string& GLSLToSPIRVConverter::getGLSL() { return _glsl; }
|
|
|
|
MVK_PUBLIC_SYMBOL bool GLSLToSPIRVConverter::convert(MVKShaderStage shaderStage,
|
|
bool shouldLogGLSL,
|
|
bool shouldLogSPIRV) {
|
|
_wasConverted = true;
|
|
_resultLog.clear();
|
|
_spirv.clear();
|
|
|
|
if (shouldLogGLSL) { logGLSL("Converting"); }
|
|
|
|
EShMessages messages = (EShMessages)(EShMsgDefault | EShMsgSpvRules | EShMsgVulkanRules);
|
|
|
|
EShLanguage stage = eshLanguageFromMVKShaderStage(shaderStage);
|
|
TBuiltInResource glslCompilerResources;
|
|
configureGLSLCompilerResources(&glslCompilerResources);
|
|
const char *glslStrings[1];
|
|
glslStrings[0] = _glsl.data();
|
|
|
|
// Create and compile a shader from the source code
|
|
glslang::TShader glslShader(stage);
|
|
glslShader.setStrings(glslStrings, 1);
|
|
if (glslShader.parse(&glslCompilerResources, 100, false, messages)) {
|
|
if (shouldLogGLSL) {
|
|
logMsg(glslShader.getInfoLog());
|
|
logMsg(glslShader.getInfoDebugLog());
|
|
}
|
|
} else {
|
|
logError(glslShader.getInfoLog());
|
|
logError(glslShader.getInfoDebugLog());
|
|
return logError("Error compiling GLSL when converting GLSL to SPIR-V.");
|
|
}
|
|
|
|
// Create and link a shader program containing the single shader
|
|
glslang::TProgram glslProgram;
|
|
glslProgram.addShader(&glslShader);
|
|
if ( !glslProgram.link(messages) ) {
|
|
logError(glslProgram.getInfoLog());
|
|
logError(glslProgram.getInfoDebugLog());
|
|
return logError("Error creating GLSL program when converting GLSL to SPIR-V.");
|
|
}
|
|
|
|
// Output the SPIR-V code from the shader program
|
|
glslang::GlslangToSpv(*glslProgram.getIntermediate(stage), _spirv);
|
|
|
|
if (shouldLogSPIRV) { logSPIRV("Converted"); }
|
|
|
|
return _wasConverted;
|
|
}
|
|
|
|
MVK_PUBLIC_SYMBOL const vector<uint32_t>& GLSLToSPIRVConverter::getSPIRV() { return _spirv; }
|
|
|
|
MVK_PUBLIC_SYMBOL bool GLSLToSPIRVConverter::getWasConverted() { return _wasConverted; }
|
|
|
|
MVK_PUBLIC_SYMBOL const string& GLSLToSPIRVConverter::getResultLog() { return _resultLog; }
|
|
|
|
/** Appends the message text to the result log. */
|
|
void GLSLToSPIRVConverter::logMsg(const char* logMsg) {
|
|
string trimMsg = trim(logMsg);
|
|
if ( !trimMsg.empty() ) {
|
|
_resultLog += trimMsg;
|
|
_resultLog += "\n\n";
|
|
}
|
|
}
|
|
|
|
/** Appends the error text to the result log, sets the wasConverted property to false, and returns it. */
|
|
bool GLSLToSPIRVConverter::logError(const char* errMsg) {
|
|
logMsg(errMsg);
|
|
_wasConverted = false;
|
|
return _wasConverted;
|
|
}
|
|
|
|
/** Appends the SPIR-V to the result log, indicating whether it is being converted or was converted. */
|
|
void GLSLToSPIRVConverter::logSPIRV(const char* opDesc) {
|
|
|
|
string spvLog;
|
|
mvk::logSPIRV(_spirv, spvLog);
|
|
|
|
_resultLog += opDesc;
|
|
_resultLog += " SPIR-V:\n";
|
|
_resultLog += spvLog;
|
|
_resultLog += "\nEnd SPIR-V\n\n";
|
|
}
|
|
|
|
/** Validates that the SPIR-V code will disassemble during logging. */
|
|
bool GLSLToSPIRVConverter::validateSPIRV() {
|
|
if (_spirv.size() < 5) { return false; }
|
|
if (_spirv[0] != spv::MagicNumber) { return false; }
|
|
if (_spirv[4] != 0) { return false; }
|
|
return true;
|
|
}
|
|
|
|
/** Appends the GLSL to the result log, indicating whether it is being converted or was converted. */
|
|
void GLSLToSPIRVConverter::logGLSL(const char* opDesc) {
|
|
_resultLog += opDesc;
|
|
_resultLog += " GLSL:\n";
|
|
_resultLog += _glsl;
|
|
_resultLog += "\nEnd GLSL\n\n";
|
|
}
|
|
|
|
|
|
#pragma mark -
|
|
#pragma mark Support functions
|
|
|
|
void configureGLSLCompilerResources(TBuiltInResource* glslCompilerResources) {
|
|
glslCompilerResources->maxLights = 32;
|
|
glslCompilerResources->maxClipPlanes = 6;
|
|
glslCompilerResources->maxTextureUnits = 32;
|
|
glslCompilerResources->maxTextureCoords = 32;
|
|
glslCompilerResources->maxVertexAttribs = 64;
|
|
glslCompilerResources->maxVertexUniformComponents = 4096;
|
|
glslCompilerResources->maxVaryingFloats = 64;
|
|
glslCompilerResources->maxVertexTextureImageUnits = 32;
|
|
glslCompilerResources->maxCombinedTextureImageUnits = 80;
|
|
glslCompilerResources->maxTextureImageUnits = 32;
|
|
glslCompilerResources->maxFragmentUniformComponents = 4096;
|
|
glslCompilerResources->maxDrawBuffers = 32;
|
|
glslCompilerResources->maxVertexUniformVectors = 128;
|
|
glslCompilerResources->maxVaryingVectors = 8;
|
|
glslCompilerResources->maxFragmentUniformVectors = 16;
|
|
glslCompilerResources->maxVertexOutputVectors = 16;
|
|
glslCompilerResources->maxFragmentInputVectors = 15;
|
|
glslCompilerResources->minProgramTexelOffset = -8;
|
|
glslCompilerResources->maxProgramTexelOffset = 7;
|
|
glslCompilerResources->maxClipDistances = 8;
|
|
glslCompilerResources->maxComputeWorkGroupCountX = 65535;
|
|
glslCompilerResources->maxComputeWorkGroupCountY = 65535;
|
|
glslCompilerResources->maxComputeWorkGroupCountZ = 65535;
|
|
glslCompilerResources->maxComputeWorkGroupSizeX = 1024;
|
|
glslCompilerResources->maxComputeWorkGroupSizeY = 1024;
|
|
glslCompilerResources->maxComputeWorkGroupSizeZ = 64;
|
|
glslCompilerResources->maxComputeUniformComponents = 1024;
|
|
glslCompilerResources->maxComputeTextureImageUnits = 16;
|
|
glslCompilerResources->maxComputeImageUniforms = 8;
|
|
glslCompilerResources->maxComputeAtomicCounters = 8;
|
|
glslCompilerResources->maxComputeAtomicCounterBuffers = 1;
|
|
glslCompilerResources->maxVaryingComponents = 60;
|
|
glslCompilerResources->maxVertexOutputComponents = 64;
|
|
glslCompilerResources->maxGeometryInputComponents = 64;
|
|
glslCompilerResources->maxGeometryOutputComponents = 128;
|
|
glslCompilerResources->maxFragmentInputComponents = 128;
|
|
glslCompilerResources->maxImageUnits = 8;
|
|
glslCompilerResources->maxCombinedImageUnitsAndFragmentOutputs = 8;
|
|
glslCompilerResources->maxCombinedShaderOutputResources = 8;
|
|
glslCompilerResources->maxImageSamples = 0;
|
|
glslCompilerResources->maxVertexImageUniforms = 0;
|
|
glslCompilerResources->maxTessControlImageUniforms = 0;
|
|
glslCompilerResources->maxTessEvaluationImageUniforms = 0;
|
|
glslCompilerResources->maxGeometryImageUniforms = 0;
|
|
glslCompilerResources->maxFragmentImageUniforms = 8;
|
|
glslCompilerResources->maxCombinedImageUniforms = 8;
|
|
glslCompilerResources->maxGeometryTextureImageUnits = 16;
|
|
glslCompilerResources->maxGeometryOutputVertices = 256;
|
|
glslCompilerResources->maxGeometryTotalOutputComponents = 1024;
|
|
glslCompilerResources->maxGeometryUniformComponents = 1024;
|
|
glslCompilerResources->maxGeometryVaryingComponents = 64;
|
|
glslCompilerResources->maxTessControlInputComponents = 128;
|
|
glslCompilerResources->maxTessControlOutputComponents = 128;
|
|
glslCompilerResources->maxTessControlTextureImageUnits = 16;
|
|
glslCompilerResources->maxTessControlUniformComponents = 1024;
|
|
glslCompilerResources->maxTessControlTotalOutputComponents = 4096;
|
|
glslCompilerResources->maxTessEvaluationInputComponents = 128;
|
|
glslCompilerResources->maxTessEvaluationOutputComponents = 128;
|
|
glslCompilerResources->maxTessEvaluationTextureImageUnits = 16;
|
|
glslCompilerResources->maxTessEvaluationUniformComponents = 1024;
|
|
glslCompilerResources->maxTessPatchComponents = 120;
|
|
glslCompilerResources->maxPatchVertices = 32;
|
|
glslCompilerResources->maxTessGenLevel = 64;
|
|
glslCompilerResources->maxViewports = 16;
|
|
glslCompilerResources->maxVertexAtomicCounters = 0;
|
|
glslCompilerResources->maxTessControlAtomicCounters = 0;
|
|
glslCompilerResources->maxTessEvaluationAtomicCounters = 0;
|
|
glslCompilerResources->maxGeometryAtomicCounters = 0;
|
|
glslCompilerResources->maxFragmentAtomicCounters = 8;
|
|
glslCompilerResources->maxCombinedAtomicCounters = 8;
|
|
glslCompilerResources->maxAtomicCounterBindings = 1;
|
|
glslCompilerResources->maxVertexAtomicCounterBuffers = 0;
|
|
glslCompilerResources->maxTessControlAtomicCounterBuffers = 0;
|
|
glslCompilerResources->maxTessEvaluationAtomicCounterBuffers = 0;
|
|
glslCompilerResources->maxGeometryAtomicCounterBuffers = 0;
|
|
glslCompilerResources->maxFragmentAtomicCounterBuffers = 1;
|
|
glslCompilerResources->maxCombinedAtomicCounterBuffers = 1;
|
|
glslCompilerResources->maxAtomicCounterBufferSize = 16384;
|
|
glslCompilerResources->maxTransformFeedbackBuffers = 4;
|
|
glslCompilerResources->maxTransformFeedbackInterleavedComponents = 64;
|
|
glslCompilerResources->maxCullDistances = 8;
|
|
glslCompilerResources->maxCombinedClipAndCullDistances = 8;
|
|
glslCompilerResources->maxSamples = 4;
|
|
glslCompilerResources->limits.nonInductiveForLoops = 1;
|
|
glslCompilerResources->limits.whileLoops = 1;
|
|
glslCompilerResources->limits.doWhileLoops = 1;
|
|
glslCompilerResources->limits.generalUniformIndexing = 1;
|
|
glslCompilerResources->limits.generalAttributeMatrixVectorIndexing = 1;
|
|
glslCompilerResources->limits.generalVaryingIndexing = 1;
|
|
glslCompilerResources->limits.generalSamplerIndexing = 1;
|
|
glslCompilerResources->limits.generalVariableIndexing = 1;
|
|
glslCompilerResources->limits.generalConstantMatrixVectorIndexing = 1;
|
|
}
|
|
|
|
EShLanguage eshLanguageFromMVKShaderStage(const MVKShaderStage mvkShaderStage) {
|
|
switch (mvkShaderStage) {
|
|
case kMVKShaderStageVertex: return EShLangVertex;
|
|
case kMVKShaderStageTessControl: return EShLangTessControl;
|
|
case kMVKShaderStageTessEval: return EShLangTessEvaluation;
|
|
case kMVKShaderStageGeometry: return EShLangGeometry;
|
|
case kMVKShaderStageFragment: return EShLangFragment;
|
|
case kMVKShaderStageCompute: return EShLangCompute;
|
|
default: return EShLangVertex;
|
|
}
|
|
}
|
|
|
|
|
|
#pragma mark Library initialization
|
|
|
|
/**
|
|
* Called automatically when the framework is loaded and initialized.
|
|
*
|
|
* Initialize the
|
|
*/
|
|
static bool _wasShaderConverterInitialized = false;
|
|
__attribute__((constructor)) static void MVKShaderConverterInit() {
|
|
if (_wasShaderConverterInitialized ) { return; }
|
|
|
|
glslang::InitializeProcess();
|
|
|
|
_wasShaderConverterInitialized = true;
|
|
}
|
|
|
|
|