vulkan: move shader compilation into Shader

This commit is contained in:
niki
2022-07-18 22:28:41 +02:00
parent a544d51c22
commit 00974b5820
8 changed files with 270 additions and 274 deletions
+3 -1
View File
@@ -368,7 +368,9 @@ Shader *Graphics::newShader(const std::vector<std::string> &stagessource, const
for (const std::string &source : stagessource)
{
Shader::SourceInfo info = Shader::getSourceInfo(source);
info.vulkan = options.defines.find("vulkan") != options.defines.end();
if (capabilities.features[FEATURE_GLSL4]) {
info.language = Shader::LANGUAGE_GLSL4;
}
bool isanystage = false;
for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++)
+22 -40
View File
@@ -56,8 +56,10 @@ static const char global_syntax[] = R"(
#endif
#if __VERSION__ >= 300
#define LOVE_IO_LOCATION(x) layout (location = x)
#define LOVE_IO_BINDING(x) layout (binding = x)
#else
#define LOVE_IO_LOCATION(x)
#define LOVE_IO_BINDING(x)
#endif
#define number float
#define Image sampler2D
@@ -83,27 +85,13 @@ static const char global_syntax[] = R"(
#ifdef GL_OES_standard_derivatives
#extension GL_OES_standard_derivatives : enable
#endif
#ifdef USE_VULKAN
#define VULKAN_LOCATION(x) layout(location=x)
#define VULKAN_BINDING(x) layout(binding=x)
#else
#define VULKAN_LOCATION(x)
#define VULKAN_BINDING(x)
#endif
)";
static const char render_uniforms[] = R"(
#ifdef USE_VULKAN
layout(binding=0) uniform LoveUniformsPerDraw {
vec4 uniformsPerDraw[13];
} udp;
#define love_UniformsPerDraw udp.uniformsPerDraw
#else
// According to the GLSL ES 1.0 spec, uniform precision must match between stages,
// but we can't guarantee that highp is always supported in fragment shaders...
// We *really* don't want to use mediump for these in vertex shaders though.
uniform LOVE_HIGHP_OR_MEDIUMP vec4 love_UniformsPerDraw[13];
#endif
// According to the GLSL ES 1.0 spec, uniform precision must match between stages,
// but we can't guarantee that highp is always supported in fragment shaders...
// We *really* don't want to use mediump for these in vertex shaders though.
uniform LOVE_HIGHP_OR_MEDIUMP vec4 love_UniformsPerDraw[13];
// These are initialized in love_initializeBuiltinUniforms below. GLSL ES can't
// do it as an initializer.
@@ -278,12 +266,12 @@ static const char vertex_header[] = R"(
static const char vertex_functions[] = R"()";
static const char vertex_main[] = R"(
VULKAN_LOCATION(0) attribute vec4 VertexPosition;
VULKAN_LOCATION(1) attribute vec4 VertexTexCoord;
VULKAN_LOCATION(2) attribute vec4 VertexColor;
LOVE_IO_LOCATION(0) attribute vec4 VertexPosition;
LOVE_IO_LOCATION(1) attribute vec4 VertexTexCoord;
LOVE_IO_LOCATION(2) attribute vec4 VertexColor;
VULKAN_LOCATION(0) varying vec4 VaryingTexCoord;
VULKAN_LOCATION(1) varying vec4 VaryingColor;
LOVE_IO_LOCATION(0) varying vec4 VaryingTexCoord;
LOVE_IO_LOCATION(1) varying vec4 VaryingColor;
vec4 position(mat4 clipSpaceFromLocal, vec4 localPosition);
@@ -323,9 +311,9 @@ static const char pixel_header[] = R"(
)";
static const char pixel_functions[] = R"(
VULKAN_BINDING(2) uniform sampler2D love_VideoYChannel;
VULKAN_BINDING(3) uniform sampler2D love_VideoCbChannel;
VULKAN_BINDING(4) uniform sampler2D love_VideoCrChannel;
LOVE_IO_BINDING(2) uniform sampler2D love_VideoYChannel;
LOVE_IO_BINDING(3) uniform sampler2D love_VideoCbChannel;
LOVE_IO_BINDING(4) uniform sampler2D love_VideoCrChannel;
vec4 VideoTexel(vec2 texcoords) {
vec3 yuv;
@@ -351,9 +339,9 @@ static const char pixel_main[] = R"(
#define love_PixelColor gl_FragColor
#endif
VULKAN_BINDING(1) uniform sampler2D MainTex;
VULKAN_LOCATION(0) varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord;
VULKAN_LOCATION(1) varying mediump vec4 VaryingColor;
LOVE_IO_BINDING(1) uniform sampler2D MainTex;
LOVE_IO_LOCATION(0) varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord;
LOVE_IO_LOCATION(1) varying mediump vec4 VaryingColor;
vec4 effect(vec4 vcolor, Image tex, vec2 texcoord, vec2 pixcoord);
@@ -388,8 +376,8 @@ static const char pixel_main_custom[] = R"(
#define LOVE_MULTI_CANVASES 1
#endif
VULKAN_LOCATION(0) varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord;
VULKAN_LOCATION(1) varying mediump vec4 VaryingColor;
LOVE_IO_LOCATION(0) varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord;
LOVE_IO_LOCATION(1) varying mediump vec4 VaryingColor;
void effect();
@@ -580,15 +568,9 @@ std::string Shader::createShaderStageCode(Graphics *gfx, ShaderStageType stage,
std::stringstream ss;
if (info.vulkan) {
ss << "#version 450\n";
ss << "#define USE_VULKAN 1\n";
}
else {
ss << (gles ? glsl::versions[lang].glsles : glsl::versions[lang].glsl) << "\n";
if (glsl1on3)
ss << "#define LOVE_GLSL1_ON_GLSL3 1\n";
}
ss << (gles ? glsl::versions[lang].glsles : glsl::versions[lang].glsl) << "\n";
if (glsl1on3)
ss << "#define LOVE_GLSL1_ON_GLSL3 1\n";
if (isGammaCorrect())
ss << "#define LOVE_GAMMA_CORRECT 1\n";
-1
View File
@@ -117,7 +117,6 @@ public:
Language language;
EntryPoint stages[SHADERSTAGE_MAX_ENUM];
bool usesMRT;
bool vulkan;
};
struct MatrixSize
+1 -1
View File
@@ -1077,7 +1077,7 @@ namespace love {
std::vector<std::string> stages;
stages.push_back(Shader::getDefaultCode(stype, SHADERSTAGE_VERTEX));
stages.push_back(Shader::getDefaultCode(stype, SHADERSTAGE_PIXEL));
Shader::standardShaders[i] = newShader(stages, { { {"vulkan", "1"} } });
Shader::standardShaders[i] = newShader(stages, {});
}
}
}
+234 -5
View File
@@ -1,10 +1,122 @@
#include "Shader.h"
#include "Graphics.h"
#include "libraries/glslang/glslang/Public/ShaderLang.h"
#include "libraries/glslang/SPIRV/GlslangToSpv.h"
#include "libraries/spirv_cross/spirv_cross.hpp"
#include <vector>
namespace love {
namespace graphics {
namespace vulkan {
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 VkShaderStageFlagBits getStageBit(ShaderStageType type) {
switch (type) {
case SHADERSTAGE_VERTEX:
@@ -17,22 +129,139 @@ namespace love {
throw love::Exception("invalid type");
}
static EShLanguage getGlslShaderType(ShaderStageType stage) {
switch (stage) {
case SHADERSTAGE_VERTEX:
return EShLangVertex;
case SHADERSTAGE_PIXEL:
return EShLangFragment;
case SHADERSTAGE_COMPUTE:
return EShLangCompute;
default:
throw love::Exception("unkonwn shader stage type");
}
}
Shader::Shader(StrongRef<love::graphics::ShaderStage> stages[])
: graphics::Shader(stages) {
loadVolatile();
}
bool Shader::loadVolatile() {
using namespace glslang;
using namespace spirv_cross;
TProgram* program = new TProgram();
auto gfx = Module::getInstance<Graphics>(Module::ModuleType::M_GRAPHICS);
for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++) {
if (!stages[i])
if (!stages[i])
continue;
auto stage = dynamic_cast<ShaderStage*>(stages[i].get());
auto stage = (ShaderStageType)i;
auto glslangShaderStage = getGlslShaderType(stage);
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->setEnvInputVulkanRulesRelaxed();
tshader->setGlobalUniformBinding(0);
tshader->setGlobalUniformSet(0);
auto& glsl = stages[i]->getSource();
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)) {
const char* msg1 = tshader->getInfoLog();
const char* msg2 = tshader->getInfoDebugLog();
throw love::Exception("error while parsing shader");
}
program->addShader(tshader);
}
if (!program->link(EShMsgDefault)) {
throw love::Exception("link failed! %s\n", program->getInfoLog());
}
if (!program->mapIO()) {
throw love::Exception("mapIO failed");
}
for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++) {
auto glslangStage = getGlslShaderType((ShaderStageType)i);
auto intermediate = program->getIntermediate(glslangStage);
if (intermediate == nullptr) {
continue;
}
spv::SpvBuildLogger logger;
glslang::SpvOptions opt;
opt.validate = true;
std::vector<uint32_t> spirv;
GlslangToSpv(*intermediate, spirv, &logger, &opt);
std::string msgs = logger.getAllMessages();
VkShaderModuleCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
createInfo.codeSize = spirv.size() * sizeof(uint32_t);
createInfo.pCode = spirv.data();
Graphics* vkGfx = (Graphics*)gfx;
auto device = vkGfx->getDevice();
VkShaderModule shaderModule;
if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) {
throw love::Exception("failed to create shader module");
}
shaderModules.push_back(shaderModule);
VkPipelineShaderStageCreateInfo shaderStageInfo{};
shaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
shaderStageInfo.stage = getStageBit(stage->getStageType());
shaderStageInfo.module = stage->getShaderModule();
shaderStageInfo.stage = getStageBit((ShaderStageType)i);
shaderStageInfo.module = shaderModule;
shaderStageInfo.pName = "main";
shaderStages.push_back(shaderStageInfo);
}
return true;
}
void Shader::unloadVolatile() {
if (shaderModules.size() == 0) {
return;
}
auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
auto device = gfx->getDevice();
// fixme: we shouldn't do a greedy wait here.
vkDeviceWaitIdle(device);
for (const auto shaderModule : shaderModules) {
vkDestroyShaderModule(device, shaderModule, nullptr);
}
shaderModules.clear();
shaderStages.clear();
}
Shader::~Shader() {
unloadVolatile();
}
void Shader::attach() {
+7 -3
View File
@@ -13,10 +13,13 @@
namespace love {
namespace graphics {
namespace vulkan {
class Shader final : public graphics::Shader {
class Shader final : public graphics::Shader, public Volatile {
public:
Shader(StrongRef<love::graphics::ShaderStage> stages[]);
virtual ~Shader() = default;
virtual ~Shader();
bool loadVolatile() override;
void unloadVolatile() override;
const std::vector<VkPipelineShaderStageCreateInfo>& getShaderStages() const {
return shaderStages;
@@ -44,6 +47,7 @@ namespace love {
private:
std::vector<VkPipelineShaderStageCreateInfo> shaderStages;
std::vector<VkShaderModule> shaderModules;
std::map<std::string, int> vertexAttributeIndices = {
{ "VertexPosition", 0 },
@@ -59,7 +63,7 @@ namespace love {
{ "MainTex", 4 }
};
std::map<std::string, UniformInfo> uniforms;
};
}
}
+2 -208
View File
@@ -14,215 +14,9 @@
namespace love {
namespace graphics {
namespace vulkan {
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 EShLanguage getGlslShaderType(ShaderStageType stage) {
switch (stage) {
case SHADERSTAGE_VERTEX:
return EShLangVertex;
case SHADERSTAGE_PIXEL:
return EShLangFragment;
case SHADERSTAGE_COMPUTE:
return EShLangCompute;
default:
throw love::Exception("unkonwn shader stage type");
}
}
static std::vector<uint32_t> compileShaderWithGlslang(const std::string& glsl, ShaderStageType stage) {
using namespace glslang;
auto glslangShaderStage = getGlslShaderType(stage);
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)) {
const char* msg1 = tshader->getInfoLog();
const char* msg2 = tshader->getInfoDebugLog();
throw love::Exception("error while parsing shader");
}
auto intermediate = tshader->getIntermediate();
if (intermediate == nullptr) {
throw love::Exception("error when getting the intermediate");
}
spv::SpvBuildLogger logger;
SpvOptions opt;
opt.validate = true;
std::vector<uint32_t> spirv;
GlslangToSpv(*intermediate, spirv, &logger, &opt);
delete tshader;
return spirv;
}
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), gfx(gfx) {
loadVolatile();
}
bool ShaderStage::loadVolatile() {
auto stage = getStageType();
auto glsl = getSource();
auto code = compileShaderWithGlslang(glsl, stage);
VkShaderModuleCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
createInfo.codeSize = code.size() * sizeof(uint32_t);
createInfo.pCode = code.data();
Graphics* vkGfx = (Graphics*)gfx;
device = vkGfx->getDevice();
if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) {
throw love::Exception("failed to create shader module");
}
return true;
}
void ShaderStage::unloadVolatile() {
if (shaderModule == VK_NULL_HANDLE)
return;
// FIXME: objects for deletion should probably be put on a queue
// instead of greedy waiting here.
vkDeviceWaitIdle(device);
vkDestroyShaderModule(device, shaderModule, nullptr);
shaderModule = VK_NULL_HANDLE;
}
ShaderStage::~ShaderStage() {
unloadVolatile();
: love::graphics::ShaderStage(gfx, stage, glsl, gles, cachekey) {
// the compilation is done in Shader.
}
}
}
+1 -15
View File
@@ -8,27 +8,13 @@
namespace love {
namespace graphics {
namespace vulkan {
class ShaderStage final : public graphics::ShaderStage, public Volatile {
class ShaderStage final : public graphics::ShaderStage {
public:
ShaderStage(love::graphics::Graphics* gfx, ShaderStageType stage, const std::string& glsl, bool gles, const std::string& cachekey);
virtual ~ShaderStage();
virtual bool loadVolatile() override;
virtual void unloadVolatile() override;
VkShaderModule getShaderModule() const {
return shaderModule;
}
ptrdiff_t getHandle() const {
return 0;
}
private:
VkShaderModule shaderModule = VK_NULL_HANDLE;
VkDevice device;
love::graphics::Graphics* gfx;
};
}
}