diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index 945286051..b451bc301 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -402,7 +402,7 @@ Shader *Graphics::newShader(const std::vector &stagessource, const } - return newShaderInternal(stages); + return newShaderInternal(stages, options); } Shader *Graphics::newComputeShader(const std::string &source, const Shader::CompileOptions &options) @@ -418,7 +418,7 @@ Shader *Graphics::newComputeShader(const std::string &source, const Shader::Comp // shouldn't be much reuse. stages[SHADERSTAGE_COMPUTE].set(newShaderStage(SHADERSTAGE_COMPUTE, source, options, info, false)); - return newShaderInternal(stages); + return newShaderInternal(stages, options); } Buffer *Graphics::newBuffer(const Buffer::Settings &settings, DataFormat format, const void *data, size_t size, size_t arraylength) diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index 580095d86..e668b6925 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -1020,7 +1020,7 @@ protected: ShaderStage *newShaderStage(ShaderStageType stage, const std::string &source, const Shader::CompileOptions &options, const Shader::SourceInfo &info, bool cache); virtual ShaderStage *newShaderStageInternal(ShaderStageType stage, const std::string &cachekey, const std::string &source, bool gles) = 0; - virtual Shader *newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM]) = 0; + virtual Shader *newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM], const Shader::CompileOptions &options) = 0; virtual StreamBuffer *newStreamBuffer(BufferUsage type, size_t size) = 0; virtual GraphicsReadback *newReadbackInternal(ReadbackMethod method, Buffer *buffer, size_t offset, size_t size, data::ByteData *dest, size_t destoffset) = 0; diff --git a/src/modules/graphics/Shader.cpp b/src/modules/graphics/Shader.cpp index 5ace1031d..ca708efe7 100644 --- a/src/modules/graphics/Shader.cpp +++ b/src/modules/graphics/Shader.cpp @@ -686,8 +686,9 @@ std::string Shader::createShaderStageCode(Graphics *gfx, ShaderStageType stage, return ss.str(); } -Shader::Shader(StrongRef _stages[]) +Shader::Shader(StrongRef _stages[], const CompileOptions &options) : stages() + , debugName(options.debugName) { std::string err; if (!validateInternal(_stages, err, validationReflection)) @@ -1250,6 +1251,20 @@ bool Shader::fillUniformReflectionData(UniformInfo &u) return true; } +std::string Shader::getShaderStageDebugName(ShaderStageType stage) const +{ + std::string name = debugName; + + if (!name.empty()) + { + const char *stagename = "unknown"; + ShaderStage::getConstant(stage, stagename); + name += " (" + std::string(stagename) + ")"; + } + + return name; +} + bool Shader::initialize() { return glslang::InitializeProcess(); diff --git a/src/modules/graphics/Shader.h b/src/modules/graphics/Shader.h index 64e824cb8..8e6671c1d 100644 --- a/src/modules/graphics/Shader.h +++ b/src/modules/graphics/Shader.h @@ -111,6 +111,7 @@ public: struct CompileOptions { std::map defines; + std::string debugName; }; struct SourceInfo @@ -189,7 +190,7 @@ public: // Pointer to the default Shader. static Shader *standardShaders[STANDARD_MAX_ENUM]; - Shader(StrongRef stages[]); + Shader(StrongRef stages[], const CompileOptions &options); virtual ~Shader(); /** @@ -217,6 +218,8 @@ public: **/ virtual std::string getWarnings() const = 0; + const std::string &getDebugName() const { return debugName; } + virtual int getVertexAttributeIndex(const std::string &name) = 0; virtual const UniformInfo *getUniformInfo(const std::string &name) const = 0; @@ -291,6 +294,8 @@ protected: bool fillUniformReflectionData(UniformInfo &u); + std::string getShaderStageDebugName(ShaderStageType stage) const; + static bool validateInternal(StrongRef stages[], std::string& err, ValidationReflection &reflection); static DataBaseType getDataBaseType(PixelFormat format); static bool isResourceBaseTypeCompatible(DataBaseType a, DataBaseType b); @@ -302,6 +307,8 @@ protected: ValidationReflection validationReflection; + std::string debugName; + }; // Shader } // graphics diff --git a/src/modules/graphics/metal/Graphics.h b/src/modules/graphics/metal/Graphics.h index f7ee9db1e..d735349ce 100644 --- a/src/modules/graphics/metal/Graphics.h +++ b/src/modules/graphics/metal/Graphics.h @@ -196,7 +196,7 @@ private: }; love::graphics::ShaderStage *newShaderStageInternal(ShaderStageType stage, const std::string &cachekey, const std::string &source, bool gles) override; - love::graphics::Shader *newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM]) override; + love::graphics::Shader *newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM], const Shader::CompileOptions &options) override; love::graphics::StreamBuffer *newStreamBuffer(BufferUsage usage, size_t size) override; love::graphics::GraphicsReadback *newReadbackInternal(ReadbackMethod method, love::graphics::Buffer *buffer, size_t offset, size_t size, data::ByteData *dest, size_t destoffset) override; diff --git a/src/modules/graphics/metal/Graphics.mm b/src/modules/graphics/metal/Graphics.mm index b260a6ab3..0f960652b 100644 --- a/src/modules/graphics/metal/Graphics.mm +++ b/src/modules/graphics/metal/Graphics.mm @@ -438,9 +438,9 @@ love::graphics::ShaderStage *Graphics::newShaderStageInternal(ShaderStageType st return new ShaderStage(this, stage, source, gles, cachekey); } -love::graphics::Shader *Graphics::newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM]) +love::graphics::Shader *Graphics::newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM], const Shader::CompileOptions &options) { - return new Shader(device, stages); + return new Shader(device, stages, options); } love::graphics::Buffer *Graphics::newBuffer(const Buffer::Settings &settings, const std::vector &format, const void *data, size_t size, size_t arraylength) diff --git a/src/modules/graphics/metal/Shader.h b/src/modules/graphics/metal/Shader.h index 49a6e2b7e..5ff3a3c20 100644 --- a/src/modules/graphics/metal/Shader.h +++ b/src/modules/graphics/metal/Shader.h @@ -100,7 +100,7 @@ public: Access access; }; - Shader(id device, StrongRef stages[SHADERSTAGE_MAX_ENUM]); + Shader(id device, StrongRef stages[SHADERSTAGE_MAX_ENUM], const CompileOptions &options); virtual ~Shader(); // Implements Shader. diff --git a/src/modules/graphics/metal/Shader.mm b/src/modules/graphics/metal/Shader.mm index ec5dc4e3c..ce6770e61 100644 --- a/src/modules/graphics/metal/Shader.mm +++ b/src/modules/graphics/metal/Shader.mm @@ -249,8 +249,8 @@ static EShLanguage getGLSLangStage(ShaderStageType stage) return EShLangCount; } -Shader::Shader(id device, StrongRef stages[SHADERSTAGE_MAX_ENUM]) - : love::graphics::Shader(stages) +Shader::Shader(id device, StrongRef stages[SHADERSTAGE_MAX_ENUM], const CompileOptions &options) + : love::graphics::Shader(stages, options) , functions() , builtinUniformInfo() , localUniformStagingData(nullptr) @@ -759,6 +759,10 @@ void Shader::compileFromGLSLang(id device, const glslang::TProgram &p functions[stageindex] = [library newFunctionWithName:library.functionNames[0]]; + std::string debugname = getShaderStageDebugName((ShaderStageType)stageindex); + if (!debugname.empty()) + functions[stageindex].label = @(debugname.c_str()); + auto setTextureBinding = [this](CompilerMSL &msl, int stageindex, const spirv_cross::Resource &resource) -> void { auto it = uniforms.find(resource.name); diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index ff9297092..e2b863049 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -168,9 +168,9 @@ love::graphics::ShaderStage *Graphics::newShaderStageInternal(ShaderStageType st return new ShaderStage(this, stage, source, gles, cachekey); } -love::graphics::Shader *Graphics::newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM]) +love::graphics::Shader *Graphics::newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM], const Shader::CompileOptions &options) { - return new Shader(stages); + return new Shader(stages, options); } love::graphics::Buffer *Graphics::newBuffer(const Buffer::Settings &settings, const std::vector &format, const void *data, size_t size, size_t arraylength) diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index 09b01ce10..2b3525b0d 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -139,7 +139,7 @@ private: }; love::graphics::ShaderStage *newShaderStageInternal(ShaderStageType stage, const std::string &cachekey, const std::string &source, bool gles) override; - love::graphics::Shader *newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM]) override; + love::graphics::Shader *newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM], const Shader::CompileOptions &options) override; love::graphics::StreamBuffer *newStreamBuffer(BufferUsage type, size_t size) override; love::graphics::GraphicsReadback *newReadbackInternal(ReadbackMethod method, love::graphics::Buffer *buffer, size_t offset, size_t size, data::ByteData *dest, size_t destoffset) override; diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index a89b09f04..e99642d99 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -43,8 +43,8 @@ static bool isBuffer(Shader::UniformType utype) return utype == Shader::UNIFORM_TEXELBUFFER || utype == Shader::UNIFORM_STORAGEBUFFER; } -Shader::Shader(StrongRef stages[SHADERSTAGE_MAX_ENUM]) - : love::graphics::Shader(stages) +Shader::Shader(StrongRef stages[SHADERSTAGE_MAX_ENUM], const CompileOptions &options) + : love::graphics::Shader(stages, options) , program(0) , splitUniformsPerDraw(false) , builtinUniforms() @@ -512,6 +512,9 @@ bool Shader::loadVolatile() if (program == 0) throw love::Exception("Cannot create shader program object."); + if (!debugName.empty() && (GLAD_VERSION_4_3 || GLAD_ES_VERSION_3_2)) + glObjectLabel(GL_PROGRAM, program, -1, debugName.c_str()); + for (const auto &stage : stages) { if (stage.get() != nullptr) diff --git a/src/modules/graphics/opengl/Shader.h b/src/modules/graphics/opengl/Shader.h index 5f38a5196..0712ba9bb 100644 --- a/src/modules/graphics/opengl/Shader.h +++ b/src/modules/graphics/opengl/Shader.h @@ -52,7 +52,7 @@ public: GLenum internalFormat; }; - Shader(StrongRef stages[SHADERSTAGE_MAX_ENUM]); + Shader(StrongRef stages[SHADERSTAGE_MAX_ENUM], const CompileOptions &options); virtual ~Shader(); // Implements Volatile diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index d6710e4aa..b6886fe96 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -1150,9 +1150,9 @@ graphics::ShaderStage *Graphics::newShaderStageInternal(ShaderStageType stage, c return new ShaderStage(this, stage, source, gles, cachekey); } -graphics::Shader *Graphics::newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM]) +graphics::Shader *Graphics::newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM], const Shader::CompileOptions &options) { - return new Shader(stages); + return new Shader(stages, options); } graphics::StreamBuffer *Graphics::newStreamBuffer(BufferUsage type, size_t size) diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index 20c31cd80..62a6cb075 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -328,7 +328,7 @@ public: protected: graphics::ShaderStage *newShaderStageInternal(ShaderStageType stage, const std::string &cachekey, const std::string &source, bool gles) override; - graphics::Shader *newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM]) override; + graphics::Shader *newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM], const Shader::CompileOptions &options) override; graphics::StreamBuffer *newStreamBuffer(BufferUsage type, size_t size) override; bool dispatch(love::graphics::Shader *shader, int x, int y, int z) override; bool dispatch(love::graphics::Shader *shader, love::graphics::Buffer *indirectargs, size_t argsoffset) override; diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index 473623f42..ce686cd42 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -241,8 +241,8 @@ static bool usesLocalUniformData(const graphics::Shader::UniformInfo *info) info->baseType == graphics::Shader::UNIFORM_UINT; } -Shader::Shader(StrongRef stages[]) - : graphics::Shader(stages) +Shader::Shader(StrongRef stages[], const CompileOptions &options) + : graphics::Shader(stages, options) { auto gfx = Module::getInstance(Module::ModuleType::M_GRAPHICS); vgfx = dynamic_cast(gfx); @@ -949,6 +949,19 @@ void Shader::compileShaders() if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) throw love::Exception("failed to create shader module"); + std::string debugname = getShaderStageDebugName(shaderStage); + if (!debugname.empty() && vgfx->getEnabledOptionalInstanceExtensions().debugInfo) + { + auto device = vgfx->getDevice(); + + VkDebugUtilsObjectNameInfoEXT nameInfo{}; + nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; + nameInfo.objectType = VK_OBJECT_TYPE_SHADER_MODULE; + nameInfo.objectHandle = (uint64_t)shaderModule; + nameInfo.pObjectName = debugname.c_str(); + vkSetDebugUtilsObjectNameEXT(device, &nameInfo); + } + shaderModules.push_back(shaderModule); VkPipelineShaderStageCreateInfo shaderStageInfo{}; diff --git a/src/modules/graphics/vulkan/Shader.h b/src/modules/graphics/vulkan/Shader.h index af997b408..40ef6f778 100644 --- a/src/modules/graphics/vulkan/Shader.h +++ b/src/modules/graphics/vulkan/Shader.h @@ -52,7 +52,7 @@ class Shader final , public Volatile { public: - Shader(StrongRef stages[]); + Shader(StrongRef stages[], const CompileOptions &options); virtual ~Shader(); bool loadVolatile() override; diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index ef879fc2f..5bbeba3d9 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -1463,6 +1463,11 @@ static int w_getShaderSource(lua_State *L, int startidx, std::vectorgetDebugName(); + if (debugName.empty()) + lua_pushnil(L); + else + luax_pushstring(L, debugName); + return 1; +} + static const luaL_Reg w_Shader_functions[] = { { "getWarnings", w_Shader_getWarnings }, @@ -525,6 +536,7 @@ static const luaL_Reg w_Shader_functions[] = { "hasUniform", w_Shader_hasUniform }, { "hasStage", w_Shader_hasStage }, { "getLocalThreadgroupSize", w_Shader_getLocalThreadgroupSize }, + { "getDebugName", w_Shader_getDebugName }, { 0, 0 } }; diff --git a/testing/tests/graphics.lua b/testing/tests/graphics.lua index b1b946a50..34e849a1d 100644 --- a/testing/tests/graphics.lua +++ b/testing/tests/graphics.lua @@ -710,11 +710,12 @@ love.test.graphics.Shader = function(test) return transform_projection * vertex_position; } ]] - local shader1 = love.graphics.newShader(pixelcode1, vertexcode1) + local shader1 = love.graphics.newShader(pixelcode1, vertexcode1, {debugname = 'testshader'}) test:assertObject(shader1) test:assertEquals('vertex shader:\npixel shader:\n', shader1:getWarnings(), 'check shader valid') test:assertFalse(shader1:hasUniform('tex1'), 'check invalid uniform') test:assertTrue(shader1:hasUniform('tex2'), 'check valid uniform') + test:assertEquals('testshader', shader1:getDebugName()) -- check invalid shader local pixelcode2 = [[