From 197dfb9738494b4fe278cad41e4f2506e02a0ca7 Mon Sep 17 00:00:00 2001 From: niki Date: Sun, 6 Feb 2022 22:56:24 +0100 Subject: [PATCH] start implementing vulkan Shader type --- src/modules/graphics/Graphics.cpp | 3 +- src/modules/graphics/Graphics.h | 2 +- src/modules/graphics/Shader.cpp | 56 ++++++++++++++------- src/modules/graphics/Shader.h | 1 + src/modules/graphics/vulkan/Graphics.cpp | 13 ++++- src/modules/graphics/vulkan/Graphics.h | 12 ++++- src/modules/graphics/vulkan/Shader.cpp | 31 ++++++------ src/modules/graphics/vulkan/Shader.h | 28 +++++++++-- src/modules/graphics/vulkan/ShaderStage.cpp | 55 +++++++++++++++++++- 9 files changed, 157 insertions(+), 44 deletions(-) diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index a98cc8140..87f279029 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -342,7 +342,7 @@ ShaderStage *Graphics::newShaderStage(ShaderStageType stage, const std::string & return s; } -Shader *Graphics::newShader(const std::vector &stagessource) +Shader *Graphics::newShader(const std::vector &stagessource, bool vulkan) { StrongRef stages[SHADERSTAGE_MAX_ENUM] = {}; @@ -353,6 +353,7 @@ Shader *Graphics::newShader(const std::vector &stagessource) for (const std::string &source : stagessource) { Shader::SourceInfo info = Shader::getSourceInfo(source); + info.vulkan = vulkan; bool isanystage = false; for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++) diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index 253875769..95005303f 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -449,7 +449,7 @@ public: SpriteBatch *newSpriteBatch(Texture *texture, int size, BufferDataUsage usage); ParticleSystem *newParticleSystem(Texture *texture, int size); - Shader *newShader(const std::vector &stagessource); + Shader *newShader(const std::vector &stagessource, bool vulkan = false); Shader *newComputeShader(const std::string &source); virtual Buffer *newBuffer(const Buffer::Settings &settings, const std::vector &format, const void *data, size_t size, size_t arraylength) = 0; diff --git a/src/modules/graphics/Shader.cpp b/src/modules/graphics/Shader.cpp index 4d9f562bb..6b89b26f7 100644 --- a/src/modules/graphics/Shader.cpp +++ b/src/modules/graphics/Shader.cpp @@ -83,13 +83,27 @@ 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"( -// 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]; +#ifdef USE_VULKAN + VULKAN_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 // These are initialized in love_initializeBuiltinUniforms below. GLSL ES can't // do it as an initializer. @@ -264,12 +278,12 @@ static const char vertex_header[] = R"( static const char vertex_functions[] = R"()"; static const char vertex_main[] = R"( -attribute vec4 VertexPosition; -attribute vec4 VertexTexCoord; -attribute vec4 VertexColor; +VULKAN_LOCATION(0) attribute vec4 VertexPosition; +VULKAN_LOCATION(1) attribute vec4 VertexTexCoord; +VULKAN_LOCATION(2) attribute vec4 VertexColor; -varying vec4 VaryingTexCoord; -varying vec4 VaryingColor; +VULKAN_LOCATION(0) varying vec4 VaryingTexCoord; +VULKAN_LOCATION(1) varying vec4 VaryingColor; vec4 position(mat4 clipSpaceFromLocal, vec4 localPosition); @@ -309,9 +323,9 @@ static const char pixel_header[] = R"( )"; static const char pixel_functions[] = R"( -uniform sampler2D love_VideoYChannel; -uniform sampler2D love_VideoCbChannel; -uniform sampler2D love_VideoCrChannel; +VULKAN_BINDING(1) uniform sampler2D love_VideoYChannel; +VULKAN_BINDING(2) uniform sampler2D love_VideoCbChannel; +VULKAN_BINDING(3) uniform sampler2D love_VideoCrChannel; vec4 VideoTexel(vec2 texcoords) { vec3 yuv; @@ -337,9 +351,9 @@ static const char pixel_main[] = R"( #define love_PixelColor gl_FragColor #endif -uniform sampler2D MainTex; -varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord; -varying mediump vec4 VaryingColor; +VULKAN_BINDING(4) uniform sampler2D MainTex; +VULKAN_LOCATION(0) varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord; +VULKAN_LOCATION(1) varying mediump vec4 VaryingColor; vec4 effect(vec4 vcolor, Image tex, vec2 texcoord, vec2 pixcoord); @@ -374,8 +388,8 @@ static const char pixel_main_custom[] = R"( #define LOVE_MULTI_CANVASES 1 #endif -varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord; -varying mediump vec4 VaryingColor; +VULKAN_LOCATION(0) varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord; +VULKAN_LOCATION(1) varying mediump vec4 VaryingColor; void effect(); @@ -562,6 +576,9 @@ std::string Shader::createShaderStageCode(Graphics *gfx, ShaderStageType stage, if (glsl1on3) lang = LANGUAGE_GLSL3; + if (info.vulkan) + lang = LANGUAGE_GLSL4; + glsl::StageInfo stageinfo = glsl::stageInfo[stage]; std::stringstream ss; @@ -574,6 +591,8 @@ std::string Shader::createShaderStageCode(Graphics *gfx, ShaderStageType stage, ss << "#define LOVE_GAMMA_CORRECT 1\n"; if (info.usesMRT) ss << "#define LOVE_MULTI_RENDER_TARGETS 1\n"; + if (info.vulkan) + ss << "#define USE_VULKAN\n"; ss << glsl::global_syntax; ss << stageinfo.header; ss << stageinfo.uniforms; @@ -893,7 +912,8 @@ bool Shader::validateInternal(StrongRef stages[], std::string &err, { LocalUniform u = {}; auto &values = u.initializerValues; - const glslang::TConstUnionArray *constarray = info.getConstArray(); + // const glslang::TConstUnionArray *constarray = info.getConstArray(); was this function deprecated in a later version? + const glslang::TConstUnionArray* constarray = nullptr; // Store initializer values for local uniforms. Some love graphics // backends strip these out of the shader so we need to be able to diff --git a/src/modules/graphics/Shader.h b/src/modules/graphics/Shader.h index c8d0ed838..ca3278a09 100644 --- a/src/modules/graphics/Shader.h +++ b/src/modules/graphics/Shader.h @@ -112,6 +112,7 @@ public: Language language; EntryPoint stages[SHADERSTAGE_MAX_ENUM]; bool usesMRT; + bool vulkan; }; struct MatrixSize diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 9eb0dd99e..da3767c86 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -215,6 +215,17 @@ namespace love { batchedDrawState.indexBuffer = new StreamBuffer(device, physicalDevice, BUFFERUSAGE_INDEX, sizeof(uint16) * LOVE_UINT16_MAX); } + for (int i = 0; i < Shader::STANDARD_MAX_ENUM; i++) { + auto stype = (Shader::StandardShader)i; + + if (!Shader::standardShaders[i]) { + std::vector stages; + stages.push_back(Shader::getDefaultCode(stype, SHADERSTAGE_VERTEX)); + stages.push_back(Shader::getDefaultCode(stype, SHADERSTAGE_PIXEL)); + Shader::standardShaders[i] = newShader(stages, true); + } + } + return true; } @@ -759,7 +770,7 @@ namespace love { rasterizer.rasterizerDiscardEnable = VK_FALSE; rasterizer.polygonMode = VK_POLYGON_MODE_FILL; rasterizer.lineWidth = 1.0f; - rasterizer.cullMode = VK_CULL_MODE_BACK_BIT; + rasterizer.cullMode = VK_CULL_MODE_FRONT_BIT; rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; rasterizer.depthBiasEnable = VK_FALSE; rasterizer.depthBiasConstantFactor = 0.0f; diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index 935c2171f..79f9f2334 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -3,6 +3,8 @@ #include "graphics/Graphics.h" #include "StreamBuffer.h" +#include "ShaderStage.h" +#include "Shader.h" #include #include @@ -66,8 +68,14 @@ namespace love { void drawQuads(int start, int count, const VertexAttributes& attributes, const BufferBindings& buffers, Texture* texture) override { std::cout << "drawQuads "; } protected: - graphics::ShaderStage* newShaderStageInternal(ShaderStageType stage, const std::string& cachekey, const std::string& source, bool gles) override { std::cout << "newShaderStageInternal "; return nullptr; } - graphics::Shader* newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM]) override { std::cout << "newShaderInternal "; return nullptr; } + graphics::ShaderStage* newShaderStageInternal(ShaderStageType stage, const std::string& cachekey, const std::string& source, bool gles) override { + std::cout << "newShaderStageInternal "; + return new ShaderStage(this, stage, source, gles, cachekey); + } + graphics::Shader* newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM]) override { + std::cout << "newShaderInternal "; + return new Shader(stages); + } graphics::StreamBuffer* newStreamBuffer(BufferUsage type, size_t size) override; bool dispatch(int x, int y, int z) override { std::cout << "dispatch "; return false; } void initCapabilities() override { std::cout << "initCapabilities "; } diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index 3e26be7e4..c9ab5a8cb 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -1,7 +1,5 @@ #include "Shader.h" -#include "libraries/glslang/glslang/Public/ShaderLang.h" -#include "libraries/glslang/SPIRV/GlslangToSpv.h" #include namespace love { @@ -21,24 +19,25 @@ namespace love { Shader::Shader(StrongRef stages[]) : graphics::Shader(stages) { - - if (false) { - for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++) { - if (!stages[i]) - continue; + for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++) { + if (!stages[i]) + continue; - auto stage = dynamic_cast(stages[i].get()); + auto stage = dynamic_cast(stages[i].get()); - VkPipelineShaderStageCreateInfo shaderStageInfo{}; - shaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - shaderStageInfo.stage = getStageBit(stage->getStageType()); - shaderStageInfo.module = stage->getShaderModule(); - shaderStageInfo.pName = "main"; + VkPipelineShaderStageCreateInfo shaderStageInfo{}; + shaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shaderStageInfo.stage = getStageBit(stage->getStageType()); + shaderStageInfo.module = stage->getShaderModule(); + shaderStageInfo.pName = "main"; - shaderStages.push_back(shaderStageInfo); - } + shaderStages.push_back(shaderStageInfo); } } + + int Shader::getVertexAttributeIndex(const std::string& name) { + return vertexAttributeIndices.at(name); + } } } -} \ No newline at end of file +} diff --git a/src/modules/graphics/vulkan/Shader.h b/src/modules/graphics/vulkan/Shader.h index 45f552e2a..0370ee63e 100644 --- a/src/modules/graphics/vulkan/Shader.h +++ b/src/modules/graphics/vulkan/Shader.h @@ -3,10 +3,10 @@ #include #include -#include "libraries/glslang/glslang/Public/ShaderLang.h" -#include "libraries/glslang/SPIRV/GlslangToSpv.h" #include +#include + namespace love { namespace graphics { @@ -26,7 +26,7 @@ namespace love { std::string getWarnings() const override { return ""; } - int getVertexAttributeIndex(const std::string& name) override { return 0; } + int getVertexAttributeIndex(const std::string& name) override; const UniformInfo* getUniformInfo(const std::string& name) const override { return nullptr; } const UniformInfo* getUniformInfo(BuiltinUniform builtin) const override { return nullptr; } @@ -41,7 +41,29 @@ namespace love { void setVideoTextures(Texture* ytexture, Texture* cbtexture, Texture* crtexture) override {} private: + struct Vec4 { + float x, y, z, w; + }; + + struct LoveUniformsPerDraw { + Vec4 uniformsPerDraw[13]; + }; + std::vector shaderStages; + + std::map vertexAttributeIndices = { + { "VertexPosition", 0 }, + { "VertexTexCoord", 1 }, + { "VertexColor", 2 } + }; + + std::map uniformBindings = { + { "love_UniformsPerDraw", 0 }, + { "love_VideoYChannel", 1 }, + { "love_VideoCbChannel", 2 }, + { "love_VideoCrChannel", 3 }, + { "MainTex", 4 } + }; }; } } diff --git a/src/modules/graphics/vulkan/ShaderStage.cpp b/src/modules/graphics/vulkan/ShaderStage.cpp index dfcf0095b..09426df90 100644 --- a/src/modules/graphics/vulkan/ShaderStage.cpp +++ b/src/modules/graphics/vulkan/ShaderStage.cpp @@ -9,12 +9,63 @@ namespace love { namespace graphics { namespace vulkan { + static int someIndex = 0; + + static std::string getFileEnding(ShaderStageType type) { + switch (type) { + case SHADERSTAGE_VERTEX: + return ".vert"; + case SHADERSTAGE_PIXEL: + return ".frag"; + default: + throw love::Exception("unsupported shader stage type"); + } + } + + static std::vector readFile(const std::string& filename) { + std::ifstream file(filename, std::ios::ate | std::ios::binary); + + if (!file.is_open()) { + throw std::runtime_error("failed to open file!"); + } + + size_t fileSize = (size_t)file.tellg(); + std::vector buffer(fileSize); + + file.seekg(0); + file.read(buffer.data(), fileSize); + + file.close(); + + return buffer; + } + + static int shaderSourceId = 0; + + std::vector 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()); + + return readFile(outputFileName); + } + 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) { + auto code = compileShader(glsl, stage); + VkShaderModuleCreateInfo createInfo{}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - createInfo.codeSize = 0; - createInfo.pCode = nullptr; + createInfo.codeSize = code.size(); + createInfo.pCode = reinterpret_cast(code.data()); Graphics* vkGfx = (Graphics*)gfx; device = vkGfx->getDevice();