mirror of
https://github.com/love2d/love.git
synced 2026-08-19 12:14:20 +02:00
use glslang to compile vulkan ShaderStage
Before this commit a system call to glslc was made to compile the shaders dynamically during runtime. That was obviously a very hacky way, so now the proper way was implemented.
This commit is contained in:
@@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
#include "Graphics.h"
|
#include "Graphics.h"
|
||||||
|
|
||||||
|
#include "libraries/glslang/glslang/Public/ShaderLang.h"
|
||||||
|
#include "libraries/glslang/SPIRV/GlslangToSpv.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
@@ -11,68 +14,184 @@
|
|||||||
namespace love {
|
namespace love {
|
||||||
namespace graphics {
|
namespace graphics {
|
||||||
namespace vulkan {
|
namespace vulkan {
|
||||||
static int someIndex = 0;
|
static const TBuiltInResource defaultTBuiltInResource = {
|
||||||
|
/* .MaxLights = */ 32,
|
||||||
|
/* .MaxClipPlanes = */ 6,
|
||||||
|
/* .MaxTextureUnits = */ 32,
|
||||||
|
/* .MaxTextureCoords = */ 32,
|
||||||
|
/* .MaxVertexAttribs = */ 64,
|
||||||
|
/* .MaxVertexUniformComponents = */ 16384,
|
||||||
|
/* .MaxVaryingFloats = */ 128,
|
||||||
|
/* .MaxVertexTextureImageUnits = */ 32,
|
||||||
|
/* .MaxCombinedTextureImageUnits = */ 80,
|
||||||
|
/* .MaxTextureImageUnits = */ 32,
|
||||||
|
/* .MaxFragmentUniformComponents = */ 16384,
|
||||||
|
/* .MaxDrawBuffers = */ 8,
|
||||||
|
/* .MaxVertexUniformVectors = */ 4096,
|
||||||
|
/* .MaxVaryingVectors = */ 32,
|
||||||
|
/* .MaxFragmentUniformVectors = */ 4096,
|
||||||
|
/* .MaxVertexOutputVectors = */ 32,
|
||||||
|
/* .MaxFragmentInputVectors = */ 31,
|
||||||
|
/* .MinProgramTexelOffset = */ -8,
|
||||||
|
/* .MaxProgramTexelOffset = */ 7,
|
||||||
|
/* .MaxClipDistances = */ 8,
|
||||||
|
/* .MaxComputeWorkGroupCountX = */ 65535,
|
||||||
|
/* .MaxComputeWorkGroupCountY = */ 65535,
|
||||||
|
/* .MaxComputeWorkGroupCountZ = */ 65535,
|
||||||
|
/* .MaxComputeWorkGroupSizeX = */ 1024,
|
||||||
|
/* .MaxComputeWorkGroupSizeY = */ 1024,
|
||||||
|
/* .MaxComputeWorkGroupSizeZ = */ 64,
|
||||||
|
/* .MaxComputeUniformComponents = */ 1024,
|
||||||
|
/* .MaxComputeTextureImageUnits = */ 32,
|
||||||
|
/* .MaxComputeImageUniforms = */ 16,
|
||||||
|
/* .MaxComputeAtomicCounters = */ 4096,
|
||||||
|
/* .MaxComputeAtomicCounterBuffers = */ 8,
|
||||||
|
/* .MaxVaryingComponents = */ 128,
|
||||||
|
/* .MaxVertexOutputComponents = */ 128,
|
||||||
|
/* .MaxGeometryInputComponents = */ 128,
|
||||||
|
/* .MaxGeometryOutputComponents = */ 128,
|
||||||
|
/* .MaxFragmentInputComponents = */ 128,
|
||||||
|
/* .MaxImageUnits = */ 192,
|
||||||
|
/* .MaxCombinedImageUnitsAndFragmentOutputs = */ 144,
|
||||||
|
/* .MaxCombinedShaderOutputResources = */ 144,
|
||||||
|
/* .MaxImageSamples = */ 32,
|
||||||
|
/* .MaxVertexImageUniforms = */ 16,
|
||||||
|
/* .MaxTessControlImageUniforms = */ 16,
|
||||||
|
/* .MaxTessEvaluationImageUniforms = */ 16,
|
||||||
|
/* .MaxGeometryImageUniforms = */ 16,
|
||||||
|
/* .MaxFragmentImageUniforms = */ 16,
|
||||||
|
/* .MaxCombinedImageUniforms = */ 80,
|
||||||
|
/* .MaxGeometryTextureImageUnits = */ 16,
|
||||||
|
/* .MaxGeometryOutputVertices = */ 256,
|
||||||
|
/* .MaxGeometryTotalOutputComponents = */ 1024,
|
||||||
|
/* .MaxGeometryUniformComponents = */ 1024,
|
||||||
|
/* .MaxGeometryVaryingComponents = */ 64,
|
||||||
|
/* .MaxTessControlInputComponents = */ 128,
|
||||||
|
/* .MaxTessControlOutputComponents = */ 128,
|
||||||
|
/* .MaxTessControlTextureImageUnits = */ 16,
|
||||||
|
/* .MaxTessControlUniformComponents = */ 1024,
|
||||||
|
/* .MaxTessControlTotalOutputComponents = */ 4096,
|
||||||
|
/* .MaxTessEvaluationInputComponents = */ 128,
|
||||||
|
/* .MaxTessEvaluationOutputComponents = */ 128,
|
||||||
|
/* .MaxTessEvaluationTextureImageUnits = */ 16,
|
||||||
|
/* .MaxTessEvaluationUniformComponents = */ 1024,
|
||||||
|
/* .MaxTessPatchComponents = */ 120,
|
||||||
|
/* .MaxPatchVertices = */ 32,
|
||||||
|
/* .MaxTessGenLevel = */ 64,
|
||||||
|
/* .MaxViewports = */ 16,
|
||||||
|
/* .MaxVertexAtomicCounters = */ 4096,
|
||||||
|
/* .MaxTessControlAtomicCounters = */ 4096,
|
||||||
|
/* .MaxTessEvaluationAtomicCounters = */ 4096,
|
||||||
|
/* .MaxGeometryAtomicCounters = */ 4096,
|
||||||
|
/* .MaxFragmentAtomicCounters = */ 4096,
|
||||||
|
/* .MaxCombinedAtomicCounters = */ 4096,
|
||||||
|
/* .MaxAtomicCounterBindings = */ 8,
|
||||||
|
/* .MaxVertexAtomicCounterBuffers = */ 8,
|
||||||
|
/* .MaxTessControlAtomicCounterBuffers = */ 8,
|
||||||
|
/* .MaxTessEvaluationAtomicCounterBuffers = */ 8,
|
||||||
|
/* .MaxGeometryAtomicCounterBuffers = */ 8,
|
||||||
|
/* .MaxFragmentAtomicCounterBuffers = */ 8,
|
||||||
|
/* .MaxCombinedAtomicCounterBuffers = */ 8,
|
||||||
|
/* .MaxAtomicCounterBufferSize = */ 16384,
|
||||||
|
/* .MaxTransformFeedbackBuffers = */ 4,
|
||||||
|
/* .MaxTransformFeedbackInterleavedComponents = */ 64,
|
||||||
|
/* .MaxCullDistances = */ 8,
|
||||||
|
/* .MaxCombinedClipAndCullDistances = */ 8,
|
||||||
|
/* .MaxSamples = */ 32,
|
||||||
|
/* .maxMeshOutputVerticesNV = */ 256,
|
||||||
|
/* .maxMeshOutputPrimitivesNV = */ 512,
|
||||||
|
/* .maxMeshWorkGroupSizeX_NV = */ 32,
|
||||||
|
/* .maxMeshWorkGroupSizeY_NV = */ 1,
|
||||||
|
/* .maxMeshWorkGroupSizeZ_NV = */ 1,
|
||||||
|
/* .maxTaskWorkGroupSizeX_NV = */ 32,
|
||||||
|
/* .maxTaskWorkGroupSizeY_NV = */ 1,
|
||||||
|
/* .maxTaskWorkGroupSizeZ_NV = */ 1,
|
||||||
|
/* .maxMeshViewCountNV = */ 4,
|
||||||
|
/* .maxDualSourceDrawBuffersEXT = */ 1,
|
||||||
|
/* .limits = */ {
|
||||||
|
/* .nonInductiveForLoops = */ 1,
|
||||||
|
/* .whileLoops = */ 1,
|
||||||
|
/* .doWhileLoops = */ 1,
|
||||||
|
/* .generalUniformIndexing = */ 1,
|
||||||
|
/* .generalAttributeMatrixVectorIndexing = */ 1,
|
||||||
|
/* .generalVaryingIndexing = */ 1,
|
||||||
|
/* .generalSamplerIndexing = */ 1,
|
||||||
|
/* .generalVariableIndexing = */ 1,
|
||||||
|
/* .generalConstantMatrixVectorIndexing = */ 1,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static std::string getFileEnding(ShaderStageType type) {
|
static EShLanguage getGlslShaderType(ShaderStageType stage) {
|
||||||
switch (type) {
|
switch (stage) {
|
||||||
case SHADERSTAGE_VERTEX:
|
case SHADERSTAGE_VERTEX:
|
||||||
return ".vert";
|
return EShLangVertex;
|
||||||
case SHADERSTAGE_PIXEL:
|
case SHADERSTAGE_PIXEL:
|
||||||
return ".frag";
|
return EShLangFragment;
|
||||||
|
case SHADERSTAGE_COMPUTE:
|
||||||
|
return EShLangCompute;
|
||||||
default:
|
default:
|
||||||
throw love::Exception("unsupported shader stage type");
|
throw love::Exception("unkonwn shader stage type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<char> readFile(const std::string& filename) {
|
static std::vector<uint32_t> compileShaderWithGlslang(const std::string& glsl, ShaderStageType stage) {
|
||||||
std::ifstream file(filename, std::ios::ate | std::ios::binary);
|
using namespace glslang;
|
||||||
|
|
||||||
if (!file.is_open()) {
|
auto glslangShaderStage = getGlslShaderType(stage);
|
||||||
throw std::runtime_error("failed to open file!");
|
auto tshader = new TShader(glslangShaderStage);
|
||||||
|
|
||||||
|
tshader->setEnvInput(EShSourceGlsl, glslangShaderStage, EShClientVulkan, 450);
|
||||||
|
tshader->setEnvClient(EShClientVulkan, EShTargetVulkan_1_2);
|
||||||
|
tshader->setEnvTarget(EshTargetSpv, EShTargetSpv_1_5);
|
||||||
|
tshader->setAutoMapLocations(true);
|
||||||
|
tshader->setAutoMapBindings(true);
|
||||||
|
|
||||||
|
/*
|
||||||
|
tshader->getEnvInputVulkanRulesRelaxed();
|
||||||
|
tshader->setGlobalUniformBinding(0);
|
||||||
|
tshader->setGlobalUniformSet(0);
|
||||||
|
*/
|
||||||
|
|
||||||
|
const char* csrc = glsl.c_str();
|
||||||
|
const int sourceLength = glsl.length();
|
||||||
|
tshader->setStringsWithLengths(&csrc, &sourceLength, 1);
|
||||||
|
|
||||||
|
int defaultVersio = 450;
|
||||||
|
EProfile defaultProfile = ECoreProfile;
|
||||||
|
bool forceDefault = false;
|
||||||
|
bool forwardCompat = true;
|
||||||
|
|
||||||
|
if (!tshader->parse(&defaultTBuiltInResource, defaultVersio, defaultProfile, forceDefault, forwardCompat, EShMsgSuppressWarnings)) {
|
||||||
|
std::cout << "error while parsing shader" << std::endl;
|
||||||
|
|
||||||
|
throw love::Exception("error while parsing shader");
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t fileSize = (size_t)file.tellg();
|
auto intermediate = tshader->getIntermediate();
|
||||||
std::vector<char> buffer(fileSize);
|
|
||||||
|
|
||||||
file.seekg(0);
|
if (intermediate == nullptr) {
|
||||||
file.read(buffer.data(), fileSize);
|
throw love::Exception("error when getting the intermediate");
|
||||||
|
}
|
||||||
|
spv::SpvBuildLogger logger;
|
||||||
|
SpvOptions opt;
|
||||||
|
opt.validate = true;
|
||||||
|
|
||||||
file.close();
|
std::vector<uint32_t> spirv;
|
||||||
|
GlslangToSpv(*intermediate, spirv, &logger, &opt);
|
||||||
|
|
||||||
return buffer;
|
delete tshader;
|
||||||
}
|
|
||||||
|
|
||||||
static int shaderSourceId = 0;
|
return spirv;
|
||||||
|
|
||||||
std::vector<char> compileShader(const std::string& glsl, ShaderStageType stage) {
|
|
||||||
// fixme: use glslang or shaderc for this
|
|
||||||
|
|
||||||
std::string inputFileName = std::string("temp") + std::to_string(shaderSourceId++) + getFileEnding(stage);
|
|
||||||
std::string outputFileName = std::string("temp.spv");
|
|
||||||
|
|
||||||
std::ofstream out(inputFileName);
|
|
||||||
out << glsl;
|
|
||||||
out.close();
|
|
||||||
|
|
||||||
std::string command = std::string("glslc -fauto-bind-uniforms ") + inputFileName + " -o " + outputFileName;
|
|
||||||
system(command.c_str());
|
|
||||||
|
|
||||||
auto result = readFile(outputFileName);
|
|
||||||
|
|
||||||
std::remove(inputFileName.c_str());
|
|
||||||
std::remove(outputFileName.c_str());
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderStage::ShaderStage(love::graphics::Graphics* gfx, ShaderStageType stage, const std::string& glsl, bool gles, const std::string& cachekey)
|
ShaderStage::ShaderStage(love::graphics::Graphics* gfx, ShaderStageType stage, const std::string& glsl, bool gles, const std::string& cachekey)
|
||||||
: love::graphics::ShaderStage(gfx, stage, glsl, gles, cachekey) {
|
: love::graphics::ShaderStage(gfx, stage, glsl, gles, cachekey) {
|
||||||
auto code = compileShader(glsl, stage);
|
auto code = compileShaderWithGlslang(glsl, stage);
|
||||||
|
|
||||||
VkShaderModuleCreateInfo createInfo{};
|
VkShaderModuleCreateInfo createInfo{};
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||||
createInfo.codeSize = code.size();
|
createInfo.codeSize = code.size() * sizeof(uint32_t);
|
||||||
createInfo.pCode = reinterpret_cast<uint32_t*>(code.data());
|
createInfo.pCode = code.data();
|
||||||
|
|
||||||
Graphics* vkGfx = (Graphics*)gfx;
|
Graphics* vkGfx = (Graphics*)gfx;
|
||||||
device = vkGfx->getDevice();
|
device = vkGfx->getDevice();
|
||||||
|
|||||||
Reference in New Issue
Block a user