mirror of
https://github.com/love2d/love.git
synced 2026-08-12 08:30:56 +02:00
vulkan: move shader compilation into Shader
This commit is contained in:
@@ -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++)
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -117,7 +117,6 @@ public:
|
||||
Language language;
|
||||
EntryPoint stages[SHADERSTAGE_MAX_ENUM];
|
||||
bool usesMRT;
|
||||
bool vulkan;
|
||||
};
|
||||
|
||||
struct MatrixSize
|
||||
|
||||
@@ -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, {});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user