From 876625d7e3916ecf540b9cc795a100227c18d5b3 Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Thu, 19 Sep 2024 22:41:31 -0300 Subject: [PATCH] move common shader:send texture/buffer code to platform-agnostic layer. Fixes issues in the Metal backend when a shader using a readonly buffer is created. --- src/modules/graphics/Shader.cpp | 129 +++++++++++++++- src/modules/graphics/Shader.h | 14 +- src/modules/graphics/metal/Shader.h | 6 +- src/modules/graphics/metal/Shader.mm | 150 ++++--------------- src/modules/graphics/opengl/Shader.cpp | 197 ++++++------------------- src/modules/graphics/opengl/Shader.h | 8 +- src/modules/graphics/vulkan/Shader.cpp | 140 ++++-------------- src/modules/graphics/vulkan/Shader.h | 8 +- 8 files changed, 239 insertions(+), 413 deletions(-) diff --git a/src/modules/graphics/Shader.cpp b/src/modules/graphics/Shader.cpp index 4d62d9a45..f252d7662 100644 --- a/src/modules/graphics/Shader.cpp +++ b/src/modules/graphics/Shader.cpp @@ -797,6 +797,125 @@ bool Shader::hasUniform(const std::string &name) const return it != reflection.allUniforms.end() && it->second->active; } +void Shader::setVideoTextures(love::graphics::Texture *ytexture, love::graphics::Texture *cbtexture, love::graphics::Texture *crtexture) +{ + const BuiltinUniform builtins[3] = { + BUILTIN_TEXTURE_VIDEO_Y, + BUILTIN_TEXTURE_VIDEO_CB, + BUILTIN_TEXTURE_VIDEO_CR, + }; + + love::graphics::Texture *textures[3] = {ytexture, cbtexture, crtexture}; + + for (int i = 0; i < 3; i++) + { + const UniformInfo *info = getUniformInfo(builtins[i]); + if (info != nullptr) + sendTextures(info, &textures[i], 1, true); + } +} + +void Shader::sendTextures(const UniformInfo *info, Texture **textures, int count) +{ + Shader::sendTextures(info, textures, count, false); +} + +void Shader::sendBuffers(const UniformInfo *info, Buffer **buffers, int count) +{ + Shader::sendBuffers(info, buffers, count, false); +} + +void Shader::sendTextures(const UniformInfo *info, Texture **textures, int count, bool internalUpdate) +{ + UniformType basetype = info->baseType; + + if (basetype != UNIFORM_SAMPLER && basetype != UNIFORM_STORAGETEXTURE) + return; + + if (!internalUpdate && current == this) + flushBatchedDraws(); + + count = std::min(count, info->count); + + for (int i = 0; i < count; i++) + { + love::graphics::Texture *tex = textures[i]; + bool isdefault = tex == nullptr; + + if (tex != nullptr) + { + if (!validateTexture(info, tex, internalUpdate)) + continue; + } + else + { + auto gfx = Module::getInstance(Module::M_GRAPHICS); + tex = gfx->getDefaultTexture(info->textureType, info->dataBaseType, info->isDepthSampler); + } + + tex->retain(); + + int resourceindex = info->resourceIndex + i; + + if (activeTextures[resourceindex] != nullptr) + activeTextures[resourceindex]->release(); + + activeTextures[resourceindex] = tex; + + applyTexture(info, i, tex, basetype, isdefault); + } +} + +void Shader::sendBuffers(const UniformInfo *info, Buffer **buffers, int count, bool internalUpdate) +{ + UniformType basetype = info->baseType; + + if (basetype != UNIFORM_TEXELBUFFER && basetype != UNIFORM_STORAGEBUFFER) + return; + + if (!internalUpdate && current == this) + flushBatchedDraws(); + + count = std::min(count, info->count); + + for (int i = 0; i < count; i++) + { + love::graphics::Buffer *buffer = buffers[i]; + bool isdefault = buffer == nullptr; + + if (buffer != nullptr) + { + if (!validateBuffer(info, buffer, internalUpdate)) + continue; + } + else + { + auto gfx = Module::getInstance(Module::M_GRAPHICS); + if (basetype == UNIFORM_TEXELBUFFER) + buffer = gfx->getDefaultTexelBuffer(info->dataBaseType); + else + buffer = gfx->getDefaultStorageBuffer(); + } + + buffer->retain(); + + int resourceindex = info->resourceIndex + i; + + if (activeBuffers[resourceindex] != nullptr) + activeBuffers[resourceindex]->release(); + + activeBuffers[resourceindex] = buffer; + + applyBuffer(info, i, buffer, basetype, isdefault); + } +} + +void Shader::flushBatchedDraws() const +{ + if (current == this) + Graphics::flushBatchedDrawsGlobal(); +} + const Shader::UniformInfo *Shader::getMainTextureInfo() const { return getUniformInfo(BUILTIN_TEXTURE_MAIN); @@ -1532,17 +1651,15 @@ bool Shader::validateBuffer(const UniformInfo *info, Buffer *buffer, bool intern { if (info->bufferStride != buffer->getArrayStride()) { - if (internalUpdate) - return false; - else + // Don't prevent this from working for internally bound default resources. + if (!internalUpdate) throw love::Exception("Shader storage block '%s' has an array stride of %d bytes, but the given Buffer has an array stride of %d bytes.", info->name.c_str(), info->bufferStride, buffer->getArrayStride()); } else if (info->bufferMemberCount != buffer->getDataMembers().size()) { - if (internalUpdate) - return false; - else + // Don't prevent this from working for internally bound default resources. + if (!internalUpdate) throw love::Exception("Shader storage block '%s' has a struct with %d fields, but the given Buffer has a format with %d members.", info->name.c_str(), info->bufferMemberCount, buffer->getDataMembers().size()); } diff --git a/src/modules/graphics/Shader.h b/src/modules/graphics/Shader.h index a28af1a4b..b5c10d719 100644 --- a/src/modules/graphics/Shader.h +++ b/src/modules/graphics/Shader.h @@ -245,8 +245,8 @@ class Shader : public Object, public Resource virtual void updateUniform(const UniformInfo *info, int count) = 0; - virtual void sendTextures(const UniformInfo *info, Texture **textures, int count) = 0; - virtual void sendBuffers(const UniformInfo *info, Buffer **buffers, int count) = 0; + void sendTextures(const UniformInfo *info, Texture **textures, int count); + void sendBuffers(const UniformInfo *info, Buffer **buffers, int count); /** * Gets whether a uniform with the specified name exists and is actively @@ -257,7 +257,7 @@ class Shader : public Object, public Resource /** * Sets the textures used when rendering a video. For internal use only. **/ - virtual void setVideoTextures(Texture *ytexture, Texture *cbtexture, Texture *crtexture) = 0; + void setVideoTextures(Texture *ytexture, Texture *cbtexture, Texture *crtexture); const UniformInfo *getMainTextureInfo() const; void validateDrawState(PrimitiveType primtype, Texture *maintexture) const; @@ -319,6 +319,14 @@ class Shader : public Object, public Resource // std140 uniform buffer alignment-aware copy. void copyToUniformBuffer(const UniformInfo *info, const void *src, void *dst, int count) const; + void sendTextures(const UniformInfo *info, Texture **textures, int count, bool internalupdate); + void sendBuffers(const UniformInfo *info, Buffer **buffers, int count, bool internalupdate); + + virtual void applyTexture(const UniformInfo *info, int i, Texture *texture, UniformType basetype, bool isdefault) = 0; + virtual void applyBuffer(const UniformInfo *info, int i, Buffer *buffer, UniformType basetype, bool isdefault) = 0; + + void flushBatchedDraws() const; + static std::string canonicaliizeUniformName(const std::string &name); static bool validateInternal(StrongRef stages[], std::string& err, Reflection &reflection); static DataBaseType getDataBaseType(PixelFormat format); diff --git a/src/modules/graphics/metal/Shader.h b/src/modules/graphics/metal/Shader.h index 943060176..2faa2f62d 100644 --- a/src/modules/graphics/metal/Shader.h +++ b/src/modules/graphics/metal/Shader.h @@ -109,10 +109,7 @@ class Shader final : public love::graphics::Shader int getVertexAttributeIndex(const std::string &name) override; const UniformInfo *getUniformInfo(BuiltinUniform builtin) const override; void updateUniform(const UniformInfo *info, int count) override; - void sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count) override; - void sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count) override; ptrdiff_t getHandle() const override { return 0; } - void setVideoTextures(love::graphics::Texture *ytexture, love::graphics::Texture *cbtexture, love::graphics::Texture *crtexture) override; id getCachedRenderPipeline(Graphics *gfx, const RenderPipelineKey &key); id getComputePipeline() const { return computePipeline; } @@ -140,6 +137,9 @@ class Shader final : public love::graphics::Shader void buildLocalUniforms(const spirv_cross::CompilerMSL &msl, const spirv_cross::SPIRType &type, size_t baseoffset, const std::string &basename); void compileFromGLSLang(id device, const glslang::TProgram &program); + void applyTexture(const UniformInfo *info, int i, love::graphics::Texture *texture, UniformType basetype, bool isdefault) override; + void applyBuffer(const UniformInfo *info, int i, love::graphics::Buffer *buffer, UniformType basetype, bool isdefault) override; + id functions[SHADERSTAGE_MAX_ENUM]; UniformInfo *builtinUniformInfo[BUILTIN_MAX_ENUM]; diff --git a/src/modules/graphics/metal/Shader.mm b/src/modules/graphics/metal/Shader.mm index f42e7a3fe..59b1187c3 100644 --- a/src/modules/graphics/metal/Shader.mm +++ b/src/modules/graphics/metal/Shader.mm @@ -675,11 +675,11 @@ static EShLanguage getGLSLangStage(ShaderStageType stage) { case UNIFORM_SAMPLER: case UNIFORM_STORAGETEXTURE: - sendTextures(info, &activeTextures[info->resourceIndex], info->count); + sendTextures(info, &activeTextures[info->resourceIndex], info->count, true); break; case UNIFORM_TEXELBUFFER: case UNIFORM_STORAGEBUFFER: - sendBuffers(info, &activeBuffers[info->resourceIndex], info->count); + sendBuffers(info, &activeBuffers[info->resourceIndex], info->count, true); break; default: break; @@ -741,139 +741,47 @@ static EShLanguage getGLSLangStage(ShaderStageType stage) copyToUniformBuffer(info, info->data, dst, count); } -void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count) +void Shader::applyTexture(const UniformInfo *info, int i, love::graphics::Texture *texture, UniformType /*basetype*/, bool isdefault) { @autoreleasepool { - if (info->baseType != UNIFORM_SAMPLER && info->baseType != UNIFORM_STORAGETEXTURE) + if (info->location < 0) return; - if (current == this) - Graphics::flushBatchedDrawsGlobal(); - - count = std::min(count, info->count); + int bindingindex = info->location + i; + if (bindingindex < 0) + return; - for (int i = 0; i < count; i++) + auto &binding = textureBindings[bindingindex]; + if (isdefault && (binding.access & ACCESS_WRITE) != 0) { - love::graphics::Texture *tex = textures[i]; - bool isdefault = tex == nullptr; - - if (tex != nullptr) - { - if (!validateTexture(info, tex, false)) - continue; - } - else - { - auto gfx = Graphics::getInstance(); - tex = gfx->getDefaultTexture(info->textureType, info->dataBaseType, info->isDepthSampler); - } - - tex->retain(); - - int resourceindex = info->resourceIndex + i; - - if (activeTextures[resourceindex] != nullptr) - activeTextures[resourceindex]->release(); - - activeTextures[resourceindex] = tex; - - if (info->location < 0) - continue; - - int bindingindex = info->location + i; - if (bindingindex < 0) - continue; - - auto &binding = textureBindings[bindingindex]; - if (isdefault && (binding.access & ACCESS_WRITE) != 0) - { - binding.texture = nil; - binding.samplerTexture = nullptr; - } - else - { - binding.texture = getMTLTexture(tex); - binding.samplerTexture = tex; - } + binding.texture = nil; + binding.samplerTexture = nullptr; + } + else + { + binding.texture = getMTLTexture(texture); + binding.samplerTexture = texture; } }} -void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count) -{ - bool texelbinding = info->baseType == UNIFORM_TEXELBUFFER; - bool storagebinding = info->baseType == UNIFORM_STORAGEBUFFER; - - if (!texelbinding && !storagebinding) +void Shader::applyBuffer(const UniformInfo *info, int i, love::graphics::Buffer *buffer, UniformType basetype, bool isdefault) +{ @autoreleasepool { + if (info->location < 0) return; - if (current == this) - Graphics::flushBatchedDrawsGlobal(); - - count = std::min(count, info->count); - - for (int i = 0; i < count; i++) + int bindingindex = info->location + i; + if (basetype == UNIFORM_TEXELBUFFER && bindingindex >= 0) { - love::graphics::Buffer *buffer = buffers[i]; - bool isdefault = buffer == nullptr; - - if (buffer != nullptr) - { - if (!validateBuffer(info, buffer, false)) - continue; - } - else - { - auto gfx = Graphics::getInstance(); - if (texelbinding) - buffer = gfx->getDefaultTexelBuffer(info->dataBaseType); - else - buffer = gfx->getDefaultStorageBuffer(); - } - - buffer->retain(); - - int resourceindex = info->resourceIndex + i; - - if (activeBuffers[resourceindex] != nullptr) - activeBuffers[resourceindex]->release(); - - activeBuffers[resourceindex] = buffer; - - if (info->location < 0) - continue; - - int bindingindex = info->location + i; - if (texelbinding && bindingindex >= 0) - { - textureBindings[bindingindex].texture = getMTLTexture(buffer); - } - else if (storagebinding && bindingindex >= 0) - { - auto &binding = bufferBindings[bindingindex]; - if (isdefault && (binding.access & ACCESS_WRITE) != 0) - binding.buffer = nil; - else - binding.buffer = getMTLBuffer(buffer); - } + textureBindings[bindingindex].texture = getMTLTexture(buffer); } -} - -void Shader::setVideoTextures(love::graphics::Texture *ytexture, love::graphics::Texture *cbtexture, love::graphics::Texture *crtexture) -{ - const BuiltinUniform builtins[3] = { - BUILTIN_TEXTURE_VIDEO_Y, - BUILTIN_TEXTURE_VIDEO_CB, - BUILTIN_TEXTURE_VIDEO_CR, - }; - - love::graphics::Texture *textures[3] = {ytexture, cbtexture, crtexture}; - - for (int i = 0; i < 3; i++) + else if (basetype == UNIFORM_STORAGEBUFFER && bindingindex >= 0) { - const UniformInfo *info = builtinUniformInfo[builtins[i]]; - if (info != nullptr) - sendTextures(info, &textures[i], 1); + auto &binding = bufferBindings[bindingindex]; + if (isdefault && (binding.access & ACCESS_WRITE) != 0) + binding.buffer = nil; + else + binding.buffer = getMTLBuffer(buffer); } -} +}} id Shader::getCachedRenderPipeline(graphics::Graphics *gfx, const RenderPipelineKey &key) { diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index 42e4828b0..e008e0402 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -553,172 +553,78 @@ void Shader::updateUniform(const UniformInfo *info, int count, bool internalupda } } -void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count) +void Shader::applyTexture(const UniformInfo *info, int i, love::graphics::Texture *texture, UniformType basetype, bool isdefault) { - Shader::sendTextures(info, textures, count, false); -} - -void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count, bool internalUpdate) -{ - bool issampler = info->baseType == UNIFORM_SAMPLER; - bool isstoragetex = info->baseType == UNIFORM_STORAGETEXTURE; - - if (!issampler && !isstoragetex) - return; - bool shaderactive = current == this; - if (!internalUpdate && shaderactive) - flushBatchedDraws(); - - count = std::min(count, info->count); - - // Bind the textures to the texture units. - for (int i = 0; i < count; i++) + if (basetype == UNIFORM_STORAGETEXTURE) { - love::graphics::Texture *tex = textures[i]; - bool isdefault = tex == nullptr; - - if (tex != nullptr) - { - if (!validateTexture(info, tex, internalUpdate)) - continue; - } - else - { - auto gfx = Module::getInstance(Module::M_GRAPHICS); - tex = gfx->getDefaultTexture(info->textureType, info->dataBaseType, info->isDepthSampler); - } - - tex->retain(); - - int resourceindex = info->resourceIndex + i; - - if (activeTextures[resourceindex] != nullptr) - activeTextures[resourceindex]->release(); + GLuint gltex = (GLuint) texture->getHandle(); - activeTextures[resourceindex] = tex; + int bindingindex = info->ints[i]; + auto &binding = storageTextureBindings[bindingindex]; - if (isstoragetex) + if (isdefault && (info->access & ACCESS_WRITE) != 0) { - GLuint gltex = (GLuint) tex->getHandle(); - - int bindingindex = info->ints[i]; - auto &binding = storageTextureBindings[bindingindex]; - - if (isdefault && (info->access & ACCESS_WRITE) != 0) - { - binding.texture = nullptr; - binding.gltexture = 0; - } - else - { - binding.texture = tex; - binding.gltexture = gltex; - - if (shaderactive) - glBindImageTexture(bindingindex, binding.gltexture, 0, GL_TRUE, 0, binding.access, binding.internalFormat); - } + binding.texture = nullptr; + binding.gltexture = 0; } else { - GLuint gltex = (GLuint) tex->getHandle(); - - int texunit = info->ints[i]; + binding.texture = texture; + binding.gltexture = gltex; if (shaderactive) - gl.bindTextureToUnit(info->textureType, gltex, texunit, false, false); - - // Store texture id so it can be re-bound to the texture unit later. - textureUnits[texunit].texture = gltex; + glBindImageTexture(bindingindex, binding.gltexture, 0, GL_TRUE, 0, binding.access, binding.internalFormat); } } -} + else + { + GLuint gltex = (GLuint) texture->getHandle(); -void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count) -{ - Shader::sendBuffers(info, buffers, count, false); -} + int texunit = info->ints[i]; -void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count, bool internalUpdate) -{ - bool texelbinding = info->baseType == UNIFORM_TEXELBUFFER; - bool storagebinding = info->baseType == UNIFORM_STORAGEBUFFER; + if (shaderactive) + gl.bindTextureToUnit(info->textureType, gltex, texunit, false, false); - if (!texelbinding && !storagebinding) - return; + // Store texture id so it can be re-bound to the texture unit later. + textureUnits[texunit].texture = gltex; + } +} +void Shader::applyBuffer(const UniformInfo *info, int i, love::graphics::Buffer *buffer, UniformType basetype, bool isdefault) +{ bool shaderactive = current == this; - if (!internalUpdate && shaderactive) - flushBatchedDraws(); - - count = std::min(count, info->count); - - for (int i = 0; i < count; i++) + if (basetype == UNIFORM_TEXELBUFFER) { - love::graphics::Buffer *buffer = buffers[i]; - bool isdefault = buffer == nullptr; + GLuint gltex = (GLuint) buffer->getTexelBufferHandle(); + int texunit = info->ints[i]; - if (buffer != nullptr) - { - if (!validateBuffer(info, buffer, internalUpdate)) - continue; - } - else - { - auto gfx = Module::getInstance(Module::M_GRAPHICS); - if (texelbinding) - buffer = gfx->getDefaultTexelBuffer(info->dataBaseType); - else - buffer = gfx->getDefaultStorageBuffer(); - } - - buffer->retain(); - - int resourceindex = info->resourceIndex + i; - - if (activeBuffers[resourceindex] != nullptr) - activeBuffers[resourceindex]->release(); - - activeBuffers[resourceindex] = buffer; - - if (texelbinding) - { - GLuint gltex = (GLuint) buffer->getTexelBufferHandle(); - int texunit = info->ints[i]; - - if (shaderactive) - gl.bindBufferTextureToUnit(gltex, texunit, false, false); + if (shaderactive) + gl.bindBufferTextureToUnit(gltex, texunit, false, false); - // Store texture id so it can be re-bound to the texture unit later. - textureUnits[texunit].texture = gltex; - } - else if (storagebinding) - { - GLuint glbuffer = (GLuint)buffer->getHandle(); - int bindingindex = info->ints[i]; + // Store texture id so it can be re-bound to the texture unit later. + textureUnits[texunit].texture = gltex; + } + else if (basetype == UNIFORM_STORAGEBUFFER) + { + GLuint glbuffer = (GLuint)buffer->getHandle(); + int bindingindex = info->ints[i]; - if (shaderactive) - gl.bindIndexedBuffer(glbuffer, BUFFERUSAGE_SHADER_STORAGE, bindingindex); + if (shaderactive) + gl.bindIndexedBuffer(glbuffer, BUFFERUSAGE_SHADER_STORAGE, bindingindex); - auto activeindex = storageBufferBindingIndexToActiveBinding[bindingindex]; + auto activeindex = storageBufferBindingIndexToActiveBinding[bindingindex]; - if (activeindex.first >= 0) - activeStorageBufferBindings[activeindex.first].buffer = glbuffer; + if (activeindex.first >= 0) + activeStorageBufferBindings[activeindex.first].buffer = glbuffer; - if (activeindex.second >= 0) - activeWritableStorageBuffers[activeindex.second] = isdefault ? nullptr : buffer; - } + if (activeindex.second >= 0) + activeWritableStorageBuffers[activeindex.second] = isdefault ? nullptr : buffer; } } -void Shader::flushBatchedDraws() const -{ - if (current == this) - Graphics::flushBatchedDrawsGlobal(); -} - ptrdiff_t Shader::getHandle() const { return program; @@ -736,25 +642,6 @@ int Shader::getVertexAttributeIndex(const std::string &name) return location; } -void Shader::setVideoTextures(love::graphics::Texture *ytexture, love::graphics::Texture *cbtexture, love::graphics::Texture *crtexture) -{ - const BuiltinUniform builtins[3] = { - BUILTIN_TEXTURE_VIDEO_Y, - BUILTIN_TEXTURE_VIDEO_CB, - BUILTIN_TEXTURE_VIDEO_CR, - }; - - love::graphics::Texture *textures[3] = {ytexture, cbtexture, crtexture}; - - for (int i = 0; i < 3; i++) - { - const UniformInfo *info = builtinUniformInfo[builtins[i]]; - - if (info != nullptr) - sendTextures(info, &textures[i], 1, true); - } -} - void Shader::updateBuiltinUniforms(love::graphics::Graphics *gfx, int viewportW, int viewportH) { if (current != this) diff --git a/src/modules/graphics/opengl/Shader.h b/src/modules/graphics/opengl/Shader.h index 078debc56..2499e2540 100644 --- a/src/modules/graphics/opengl/Shader.h +++ b/src/modules/graphics/opengl/Shader.h @@ -65,10 +65,7 @@ class Shader final : public love::graphics::Shader, public Volatile int getVertexAttributeIndex(const std::string &name) override; const UniformInfo *getUniformInfo(BuiltinUniform builtin) const override; void updateUniform(const UniformInfo *info, int count) override; - void sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count) override; - void sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count) override; ptrdiff_t getHandle() const override; - void setVideoTextures(love::graphics::Texture *ytexture, love::graphics::Texture *cbtexture, love::graphics::Texture *crtexture) override; void updateBuiltinUniforms(love::graphics::Graphics *gfx, int viewportW, int viewportH); @@ -95,10 +92,9 @@ class Shader final : public love::graphics::Shader, public Volatile void mapActiveUniforms(); void updateUniform(const UniformInfo *info, int count, bool internalupdate); - void sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count, bool internalupdate); - void sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count, bool internalupdate); - void flushBatchedDraws() const; + void applyTexture(const UniformInfo *info, int i, love::graphics::Texture *texture, UniformType basetype, bool isdefault) override; + void applyBuffer(const UniformInfo *info, int i, love::graphics::Buffer *buffer, UniformType basetype, bool isdefault) override; // Get any warnings or errors generated only by the shader program object. std::string getProgramWarnings() const; diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index 286c92cf0..4340e6f97 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -367,83 +367,14 @@ void Shader::updateUniform(const UniformInfo *info, int count) } } -void Shader::sendTextures(const UniformInfo *info, graphics::Texture **textures, int count) +void Shader::applyTexture(const UniformInfo *info, int i, love::graphics::Texture *texture, UniformType /*basetype*/, bool isdefault) { - bool issampler = info->baseType == UNIFORM_SAMPLER; - bool isstoragetex = info->baseType == UNIFORM_STORAGETEXTURE; - - count = std::min(count, info->count); - - if (current == this) - Graphics::flushBatchedDrawsGlobal(); - - for (int i = 0; i < count; i++) - { - love::graphics::Texture *tex = textures[i]; - bool isdefault = tex == nullptr; - - if (tex != nullptr) - { - if (!validateTexture(info, tex, false)) - continue; - } - else - { - auto gfx = Module::getInstance(Module::M_GRAPHICS); - tex = gfx->getDefaultTexture(info->textureType, info->dataBaseType, info->isDepthSampler); - } - - int resourceindex = info->resourceIndex + i; - auto prevtexture = activeTextures[resourceindex]; - activeTextures[resourceindex] = tex; - activeTextures[resourceindex]->retain(); - if (prevtexture) - prevtexture->release(); - - if (tex != prevtexture) - setTextureDescriptor(info, (isdefault && (info->access & ACCESS_WRITE) != 0) ? nullptr : tex, i); - } + setTextureDescriptor(info, (isdefault && (info->access & ACCESS_WRITE) != 0) ? nullptr : texture, i); } -void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count) +void Shader::applyBuffer(const UniformInfo *info, int i, love::graphics::Buffer *buffer, UniformType /*basetype*/, bool isdefault) { - bool texelbinding = info->baseType == UNIFORM_TEXELBUFFER; - bool storagebinding = info->baseType == UNIFORM_STORAGEBUFFER; - - count = std::min(count, info->count); - - if (current == this) - Graphics::flushBatchedDrawsGlobal(); - - for (int i = 0; i < count; i++) - { - love::graphics::Buffer *buffer = buffers[i]; - bool isdefault = buffer == nullptr; - - if (buffer != nullptr) - { - if (!validateBuffer(info, buffer, false)) - continue; - } - else - { - auto gfx = Module::getInstance(Module::M_GRAPHICS); - if (texelbinding) - buffer = gfx->getDefaultTexelBuffer(info->dataBaseType); - else - buffer = gfx->getDefaultStorageBuffer(); - } - - int resourceindex = info->resourceIndex + i; - auto prevbuffer = activeBuffers[resourceindex]; - activeBuffers[resourceindex] = buffer; - activeBuffers[resourceindex]->retain(); - if (prevbuffer) - prevbuffer->release(); - - if (buffer != prevbuffer) - setBufferDescriptor(info, (isdefault && (info->access & ACCESS_WRITE) != 0) ? nullptr : buffer, i); - } + setBufferDescriptor(info, (isdefault && (info->access & ACCESS_WRITE) != 0) ? nullptr : buffer, i); } void Shader::buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross::SPIRType &type, size_t baseoff, const std::string &basename) @@ -1078,37 +1009,6 @@ void Shader::createDescriptorPoolSizes() } } -void Shader::setVideoTextures(graphics::Texture *ytexture, graphics::Texture *cbtexture, graphics::Texture *crtexture) -{ - std::array textures = { - ytexture, cbtexture, crtexture - }; - - std::array builtIns = { - BUILTIN_TEXTURE_VIDEO_Y, - BUILTIN_TEXTURE_VIDEO_CB, - BUILTIN_TEXTURE_VIDEO_CR, - }; - - static_assert(textures.size() == builtIns.size(), "expected number of textures to be the same"); - - for (size_t i = 0; i < textures.size(); i++) - { - const UniformInfo *u = builtinUniformInfo[builtIns[i]]; - if (u != nullptr) - { - auto prevtexture = activeTextures[u->resourceIndex]; - textures[i]->retain(); - if (prevtexture) - prevtexture->release(); - activeTextures[u->resourceIndex] = textures[i]; - - if (textures[i] != prevtexture) - setTextureDescriptor(u, textures[i], 0); - } - } -} - void Shader::setMainTex(graphics::Texture *texture) { const UniformInfo *u = builtinUniformInfo[BUILTIN_TEXTURE_MAIN]; @@ -1134,10 +1034,13 @@ void Shader::setTextureDescriptor(const UniformInfo *info, love::graphics::Textu // Samplers may change after this call, so they're set just before the // descriptor set is used instead of here. - imageInfo.imageLayout = vkTexture != nullptr ? vkTexture->getImageLayout() : VK_IMAGE_LAYOUT_UNDEFINED; - imageInfo.imageView = vkTexture != nullptr ? (VkImageView)vkTexture->getRenderTargetHandle() : VK_NULL_HANDLE; - - resourceDescriptorsDirty = true; + VkImageView view = vkTexture != nullptr ? (VkImageView)vkTexture->getRenderTargetHandle() : VK_NULL_HANDLE; + if (view != imageInfo.imageView) + { + imageInfo.imageLayout = vkTexture != nullptr ? vkTexture->getImageLayout() : VK_IMAGE_LAYOUT_UNDEFINED; + imageInfo.imageView = view; + resourceDescriptorsDirty = true; + } } void Shader::setBufferDescriptor(const UniformInfo *info, love::graphics::Buffer *buffer, int index) @@ -1145,16 +1048,25 @@ void Shader::setBufferDescriptor(const UniformInfo *info, love::graphics::Buffer if (info->baseType == UNIFORM_STORAGEBUFFER) { VkDescriptorBufferInfo &bufferInfo = descriptorBuffers[info->bindingStartIndex + index]; - bufferInfo.buffer = buffer != nullptr ? (VkBuffer)buffer->getHandle() : VK_NULL_HANDLE; - bufferInfo.offset = 0; - bufferInfo.range = buffer != nullptr ? buffer->getSize() : 0; + VkBuffer vkbuffer = buffer != nullptr ? (VkBuffer)buffer->getHandle() : VK_NULL_HANDLE; + VkDeviceSize range = buffer != nullptr ? buffer->getSize() : 0; + if (vkbuffer != bufferInfo.buffer || bufferInfo.offset != 0 || range != bufferInfo.range) + { + bufferInfo.buffer = vkbuffer; + bufferInfo.offset = 0; + bufferInfo.range = range; + resourceDescriptorsDirty = true; + } } else if (info->baseType == UNIFORM_TEXELBUFFER) { - descriptorBufferViews[info->bindingStartIndex + index] = buffer != nullptr ? (VkBufferView)buffer->getTexelBufferHandle() : VK_NULL_HANDLE; + VkBufferView view = buffer != nullptr ? (VkBufferView)buffer->getTexelBufferHandle() : VK_NULL_HANDLE; + if (view != descriptorBufferViews[info->bindingStartIndex + index]) + { + descriptorBufferViews[info->bindingStartIndex + index] = view; + resourceDescriptorsDirty = true; + } } - - resourceDescriptorsDirty = true; } void Shader::createDescriptorPool() diff --git a/src/modules/graphics/vulkan/Shader.h b/src/modules/graphics/vulkan/Shader.h index 4d8c903d9..7751f3d4c 100644 --- a/src/modules/graphics/vulkan/Shader.h +++ b/src/modules/graphics/vulkan/Shader.h @@ -153,11 +153,6 @@ class Shader final void updateUniform(const UniformInfo *info, int count) override; - void sendTextures(const UniformInfo *info, graphics::Texture **textures, int count) override; - void sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count) override; - - void setVideoTextures(graphics::Texture *ytexture, graphics::Texture *cbtexture, graphics::Texture *crtexture) override; - void setMainTex(graphics::Texture *texture); VkPipeline getCachedGraphicsPipeline(Graphics *vgfx, const GraphicsPipelineConfigurationCore &configuration); @@ -175,6 +170,9 @@ class Shader final void setTextureDescriptor(const UniformInfo *info, love::graphics::Texture *texture, int index); void setBufferDescriptor(const UniformInfo *info, love::graphics::Buffer *buffer, int index); + void applyTexture(const UniformInfo *info, int i, love::graphics::Texture *texture, UniformType basetype, bool isdefault) override; + void applyBuffer(const UniformInfo *info, int i, love::graphics::Buffer *buffer, UniformType basetype, bool isdefault) override; + VkPipeline computePipeline = VK_NULL_HANDLE; VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE;