From 88724975618927c7a98b444f056e5dcbaf6f392c Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Wed, 27 Dec 2023 21:28:02 +0100 Subject: [PATCH] graphics: handle default textures in high level code. Previously each backend had to set up default textures with its own code, which needs some care for it to be robust. --- src/modules/graphics/Graphics.cpp | 99 ++++++++++++++++++-- src/modules/graphics/Graphics.h | 7 ++ src/modules/graphics/Mesh.cpp | 4 +- src/modules/graphics/ParticleSystem.cpp | 3 +- src/modules/graphics/SpriteBatch.cpp | 5 +- src/modules/graphics/TextBatch.cpp | 5 +- src/modules/graphics/metal/Graphics.h | 3 - src/modules/graphics/metal/Graphics.mm | 22 ----- src/modules/graphics/metal/Shader.mm | 13 ++- src/modules/graphics/opengl/Graphics.cpp | 5 +- src/modules/graphics/opengl/OpenGL.cpp | 114 +---------------------- src/modules/graphics/opengl/OpenGL.h | 7 -- src/modules/graphics/opengl/Shader.cpp | 51 ++++++---- src/modules/graphics/vulkan/Graphics.cpp | 16 +--- src/modules/graphics/vulkan/Graphics.h | 2 - 15 files changed, 167 insertions(+), 189 deletions(-) diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index c06cf548e..945286051 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -195,6 +195,7 @@ Graphics::Graphics() , quadIndexBuffer(nullptr) , fanIndexBuffer(nullptr) , capabilities() + , defaultTextures() , cachedShaderStages() { transformStack.reserve(16); @@ -217,6 +218,8 @@ Graphics::~Graphics() if (fanIndexBuffer != nullptr) fanIndexBuffer->release(); + releaseDefaultResources(); + // Clean up standard shaders before the active shader. If we do it after, // the active shader may try to activate a standard shader when deactivating // itself, which will cause problems since it calls Graphics methods in the @@ -530,6 +533,90 @@ bool Graphics::validateShader(bool gles, const std::vector &stagess return Shader::validate(stages, err); } +Texture *Graphics::getDefaultTexture(TextureType type, DataBaseType dataType) +{ + Texture *tex = defaultTextures[type][dataType]; + if (tex != nullptr) + return tex; + + Texture::Settings settings; + settings.type = type; + + switch (dataType) + { + case DATA_BASETYPE_INT: + settings.format = PIXELFORMAT_RGBA8_INT; + break; + case DATA_BASETYPE_UINT: + settings.format = PIXELFORMAT_RGBA8_UINT; + break; + case DATA_BASETYPE_FLOAT: + default: + settings.format = PIXELFORMAT_RGBA8_UNORM; + break; + } + + std::string name = "default_"; + + const char *tname = "unknown"; + Texture::getConstant(type, tname); + name += tname; + + const char *formatname = "unknown"; + love::getConstant(settings.format, formatname); + name += std::string("_") + formatname; + + settings.debugName = name; + + tex = newTexture(settings); + + SamplerState s; + s.minFilter = s.magFilter = SamplerState::FILTER_NEAREST; + s.wrapU = s.wrapV = s.wrapW = SamplerState::WRAP_CLAMP; + tex->setSamplerState(s); + + uint8 pixel[] = {255, 255, 255, 255}; + if (isPixelFormatInteger(settings.format)) + pixel[0] = pixel[1] = pixel[2] = pixel[3] = 1; + + for (int slice = 0; slice < (type == TEXTURE_CUBE ? 6 : 1); slice++) + tex->replacePixels(pixel, sizeof(pixel), slice, 0, {0, 0, 1, 1}, false); + + defaultTextures[type][dataType] = tex; + + return tex; +} + +void Graphics::releaseDefaultResources() +{ + for (int type = 0; type < TEXTURE_MAX_ENUM; type++) + { + for (int dataType = 0; dataType < DATA_BASETYPE_MAX_ENUM; dataType++) + { + if (defaultTextures[type][dataType]) + defaultTextures[type][dataType]->release(); + defaultTextures[type][dataType] = nullptr; + } + } +} + +Texture *Graphics::getTextureOrDefaultForActiveShader(Texture *tex) +{ + if (tex != nullptr) + return tex; + + Shader *shader = Shader::current; + + if (shader != nullptr) + { + auto texinfo = shader->getMainTextureInfo(); + if (texinfo != nullptr && texinfo->textureType != TEXTURE_MAX_ENUM) + return getDefaultTexture(texinfo->textureType, texinfo->dataBaseType); + } + + return getDefaultTexture(TEXTURE_2D, DATA_BASETYPE_FLOAT); +} + int Graphics::getWidth() const { return width; @@ -1825,7 +1912,7 @@ void Graphics::flushBatchedDraws() cmd.indexCount = sbstate.indexCount; cmd.indexType = INDEX_UINT16; cmd.indexBufferOffset = sbstate.indexBuffer->unmap(usedsizes[2]); - cmd.texture = sbstate.texture; + cmd.texture = getTextureOrDefaultForActiveShader(sbstate.texture); draw(cmd); sbstate.indexBufferMap = StreamBuffer::MapInfo(); @@ -1836,7 +1923,7 @@ void Graphics::flushBatchedDraws() cmd.primitiveType = sbstate.primitiveMode; cmd.vertexStart = 0; cmd.vertexCount = sbstate.vertexCount; - cmd.texture = sbstate.texture; + cmd.texture = getTextureOrDefaultForActiveShader(sbstate.texture); draw(cmd); } @@ -1933,7 +2020,7 @@ void Graphics::drawFromShader(PrimitiveType primtype, int vertexcount, int insta cmd.primitiveType = primtype; cmd.vertexCount = vertexcount; cmd.instanceCount = std::max(1, instancecount); - cmd.texture = maintexture; + cmd.texture = getTextureOrDefaultForActiveShader(maintexture); draw(cmd); } @@ -1974,7 +2061,7 @@ void Graphics::drawFromShader(Buffer *indexbuffer, int indexcount, int instancec cmd.indexType = getIndexDataType(indexbuffer->getDataMember(0).decl.format); cmd.indexBufferOffset = startindex * getIndexDataSize(cmd.indexType); - cmd.texture = maintexture; + cmd.texture = getTextureOrDefaultForActiveShader(maintexture); draw(cmd); } @@ -2001,7 +2088,7 @@ void Graphics::drawFromShaderIndirect(PrimitiveType primtype, Buffer *indirectar cmd.primitiveType = primtype; cmd.indirectBuffer = indirectargs; cmd.indirectBufferOffset = argsindex * indirectargs->getArrayStride(); - cmd.texture = maintexture; + cmd.texture = getTextureOrDefaultForActiveShader(maintexture); draw(cmd); } @@ -2029,7 +2116,7 @@ void Graphics::drawFromShaderIndirect(Buffer *indexbuffer, Buffer *indirectargs, cmd.indexType = getIndexDataType(indexbuffer->getDataMember(0).decl.format); cmd.indirectBuffer = indirectargs; cmd.indexBufferOffset = argsindex * indirectargs->getArrayStride(); - cmd.texture = maintexture; + cmd.texture = getTextureOrDefaultForActiveShader(maintexture); draw(cmd); } diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index 320e95497..580095d86 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -487,6 +487,9 @@ class Graphics : public Module bool validateShader(bool gles, const std::vector &stages, const Shader::CompileOptions &options, std::string &err); + Texture *getDefaultTexture(TextureType type, DataBaseType dataType); + Texture *getTextureOrDefaultForActiveShader(Texture *tex); + /** * Resets the current color, background color, line style, and so forth. **/ @@ -1039,6 +1042,8 @@ class Graphics : public Module void updatePendingReadbacks(); + void releaseDefaultResources(); + void restoreState(const DisplayState &s); void restoreStateChecked(const DisplayState &s); @@ -1094,6 +1099,8 @@ class Graphics : public Module void checkSetDefaultFont(); int calculateEllipsePoints(float rx, float ry) const; + Texture *defaultTextures[TEXTURE_MAX_ENUM][DATA_BASETYPE_MAX_ENUM]; + std::vector scratchBuffer; std::unordered_map cachedShaderStages[SHADERSTAGE_MAX_ENUM]; diff --git a/src/modules/graphics/Mesh.cpp b/src/modules/graphics/Mesh.cpp index f9c705e85..381daf723 100644 --- a/src/modules/graphics/Mesh.cpp +++ b/src/modules/graphics/Mesh.cpp @@ -667,7 +667,7 @@ void Mesh::drawInternal(Graphics *gfx, const Matrix4 &m, int instancecount, Buff cmd.primitiveType = primitiveType; cmd.indexType = indexDataType; cmd.instanceCount = instancecount; - cmd.texture = texture; + cmd.texture = gfx->getTextureOrDefaultForActiveShader(texture); cmd.cullMode = gfx->getMeshCullMode(); cmd.indexBufferOffset = r.getOffset() * indexbuffer->getArrayStride(); @@ -691,7 +691,7 @@ void Mesh::drawInternal(Graphics *gfx, const Matrix4 &m, int instancecount, Buff cmd.vertexStart = (int) r.getOffset(); cmd.vertexCount = (int) r.getSize(); cmd.instanceCount = instancecount; - cmd.texture = texture; + cmd.texture = gfx->getTextureOrDefaultForActiveShader(texture); cmd.cullMode = gfx->getMeshCullMode(); cmd.indirectBuffer = indirectargs; diff --git a/src/modules/graphics/ParticleSystem.cpp b/src/modules/graphics/ParticleSystem.cpp index ef077c0b9..0f51b1324 100644 --- a/src/modules/graphics/ParticleSystem.cpp +++ b/src/modules/graphics/ParticleSystem.cpp @@ -1086,7 +1086,8 @@ void ParticleSystem::draw(Graphics *gfx, const Matrix4 &m) BufferBindings vertexbuffers; vertexbuffers.set(0, buffer, 0); - gfx->drawQuads(0, pCount, vertexAttributes, vertexbuffers, texture); + Texture *tex = gfx->getTextureOrDefaultForActiveShader(texture); + gfx->drawQuads(0, pCount, vertexAttributes, vertexbuffers, tex); } bool ParticleSystem::getConstant(const char *in, AreaSpreadDistribution &out) diff --git a/src/modules/graphics/SpriteBatch.cpp b/src/modules/graphics/SpriteBatch.cpp index 8fe6f5ea6..e8f5f9c79 100644 --- a/src/modules/graphics/SpriteBatch.cpp +++ b/src/modules/graphics/SpriteBatch.cpp @@ -395,7 +395,10 @@ void SpriteBatch::draw(Graphics *gfx, const Matrix4 &m) count = std::min(count, next - start); if (count > 0) - gfx->drawQuads(start, count, attributes, buffers, texture); + { + Texture *tex = gfx->getTextureOrDefaultForActiveShader(texture); + gfx->drawQuads(start, count, attributes, buffers, tex); + } } } // graphics diff --git a/src/modules/graphics/TextBatch.cpp b/src/modules/graphics/TextBatch.cpp index 2a5deab46..86e62df5b 100644 --- a/src/modules/graphics/TextBatch.cpp +++ b/src/modules/graphics/TextBatch.cpp @@ -290,7 +290,10 @@ void TextBatch::draw(Graphics *gfx, const Matrix4 &m) Graphics::TempTransform transform(gfx, m); for (const Font::DrawCommand &cmd : drawCommands) - gfx->drawQuads(cmd.startvertex / 4, cmd.vertexcount / 4, vertexAttributes, vertexBuffers, cmd.texture); + { + Texture *tex = gfx->getTextureOrDefaultForActiveShader(cmd.texture); + gfx->drawQuads(cmd.startvertex / 4, cmd.vertexcount / 4, vertexAttributes, vertexBuffers, tex); + } } } // graphics diff --git a/src/modules/graphics/metal/Graphics.h b/src/modules/graphics/metal/Graphics.h index 610f7d5de..f7ee9db1e 100644 --- a/src/modules/graphics/metal/Graphics.h +++ b/src/modules/graphics/metal/Graphics.h @@ -139,7 +139,6 @@ class Graphics final : public love::graphics::Graphics StreamBuffer *getUniformBuffer() const { return uniformBuffer; } Buffer *getDefaultAttributesBuffer() const { return defaultAttributesBuffer; } - Texture *getDefaultTexture(TextureType textype) const { return defaultTextures[textype]; } int getClosestMSAASamples(int requestedsamples); @@ -247,8 +246,6 @@ class Graphics final : public love::graphics::Graphics Buffer *defaultAttributesBuffer; - Texture *defaultTextures[TEXTURE_MAX_ENUM]; - std::map cachedSamplers; std::unordered_map cachedDepthStencilStates; diff --git a/src/modules/graphics/metal/Graphics.mm b/src/modules/graphics/metal/Graphics.mm index e300530b1..b260a6ab3 100644 --- a/src/modules/graphics/metal/Graphics.mm +++ b/src/modules/graphics/metal/Graphics.mm @@ -281,7 +281,6 @@ static inline void setSampler(id encoder, Graphics::Re , renderBindings() , uniformBufferOffset(0) , defaultAttributesBuffer(nullptr) - , defaultTextures() , families() { @autoreleasepool { if (@available(macOS 10.15, iOS 13.0, *)) @@ -346,17 +345,6 @@ static inline void setSampler(id encoder, Graphics::Re defaultAttributesBuffer = newBuffer(attribsettings, dataformat, &defaults, sizeof(DefaultVertexAttributes), 0); } - uint8 defaultpixel[] = {255, 255, 255, 255}; - for (int i = 0; i < TEXTURE_MAX_ENUM; i++) - { - Texture::Settings settings; - settings.type = (TextureType) i; - settings.format = PIXELFORMAT_RGBA8_UNORM; - defaultTextures[i] = newTexture(settings); - Rect r = {0, 0, 1, 1}; - defaultTextures[i]->replacePixels(defaultpixel, sizeof(defaultpixel), 0, 0, r, false); - } - if (batchedDrawState.vb[0] == nullptr) { // Initial sizes that should be good enough for most cases. It will @@ -426,9 +414,6 @@ static inline void setSampler(id encoder, Graphics::Re commandQueue = nil; device = nil; - for (int i = 0; i < TEXTURE_MAX_ENUM; i++) - defaultTextures[i]->release(); - for (auto &kvp : cachedSamplers) CFBridgingRelease(kvp.second); @@ -1144,13 +1129,6 @@ static bool isClampOne(SamplerState::WrapMode w) if (b.isMainTexture) { - if (maintex == nullptr) - { - auto texinfo = shader->getMainTextureInfo(); - if (texinfo != nullptr && texinfo->textureType != TEXTURE_MAX_ENUM) - maintex = defaultTextures[texinfo->textureType]; - } - texture = getMTLTexture(maintex); samplertex = maintex; } diff --git a/src/modules/graphics/metal/Shader.mm b/src/modules/graphics/metal/Shader.mm index c9ffb8f21..ec5dc4e3c 100644 --- a/src/modules/graphics/metal/Shader.mm +++ b/src/modules/graphics/metal/Shader.mm @@ -524,7 +524,7 @@ static EShLanguage getGLSLangStage(ShaderStageType stage) if (u.baseType == UNIFORM_SAMPLER) { - auto tex = Graphics::getInstance()->getDefaultTexture(u.textureType); + auto tex = Graphics::getInstance()->getDefaultTexture(u.textureType, u.dataBaseType); for (int i = 0; i < u.count; i++) { tex->retain(); @@ -538,8 +538,15 @@ static EShLanguage getGLSLangStage(ShaderStageType stage) } else if (u.baseType == UNIFORM_STORAGETEXTURE) { + Texture *tex = nullptr; + if ((u.access & ACCESS_WRITE) == 0) + tex = Graphics::getInstance()->getDefaultTexture(u.textureType, u.dataBaseType); for (int i = 0; i < u.count; i++) - u.textures[i] = nullptr; + { + if (tex) + tex->retain(); + u.textures[i] = tex; + } } uniforms[u.name] = u; @@ -983,7 +990,7 @@ static EShLanguage getGLSLangStage(ShaderStageType stage) else { auto gfx = Graphics::getInstance(); - tex = gfx->getDefaultTexture(info->textureType); + tex = gfx->getDefaultTexture(info->textureType, info->dataBaseType); } tex->retain(); diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index e76da4ad7..ff9297092 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -1765,7 +1765,10 @@ uint32 Graphics::computePixelFormatUsage(PixelFormat format, bool readable) // Make sure at least something is bound to a color attachment. I believe // this is required on ES2 but I'm not positive. if (isPixelFormatDepthStencil(format)) - gl.framebufferTexture(GL_COLOR_ATTACHMENT0, TEXTURE_2D, gl.getDefaultTexture(TEXTURE_2D, DATA_BASETYPE_FLOAT), 0, 0, 0); + { + love::graphics::Texture *tex = getDefaultTexture(TEXTURE_2D, DATA_BASETYPE_FLOAT); + gl.framebufferTexture(GL_COLOR_ATTACHMENT0, TEXTURE_2D, (GLuint) tex->getHandle(), 0, 0, 0); + } if (readable) { diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index 7ad47cb08..4d99efb55 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -323,8 +323,6 @@ void OpenGL::setupContext() setStencilWriteMask(state.stencilWriteMask); setColorWriteMask(state.colorWriteMask); - createDefaultTexture(); - contextInitialized = true; #ifdef LOVE_ANDROID @@ -341,18 +339,6 @@ void OpenGL::deInitContext() if (!contextInitialized) return; - for (int i = 0; i < TEXTURE_MAX_ENUM; i++) - { - for (int datatype = DATA_BASETYPE_FLOAT; datatype <= DATA_BASETYPE_UINT; datatype++) - { - if (state.defaultTexture[i][datatype] != 0) - { - gl.deleteTexture(state.defaultTexture[i][datatype]); - state.defaultTexture[i][datatype] = 0; - } - } - } - contextInitialized = false; } @@ -604,71 +590,6 @@ void OpenGL::initMaxValues() maxLODBias = 0.0f; } -void OpenGL::createDefaultTexture() -{ - // Set the 'default' texture as a repeating white pixel. Otherwise, texture - // calls inside a shader would return black when drawing graphics primitives - // which would create the need to use different "passthrough" shaders for - // untextured primitives vs images. - const GLubyte pix[] = {255, 255, 255, 255}; - const GLubyte intpix[] = {1, 1, 1, 1}; - - SamplerState s; - s.minFilter = s.magFilter = SamplerState::FILTER_NEAREST; - s.wrapU = s.wrapV = s.wrapW = SamplerState::WRAP_CLAMP; - - for (int i = 0; i < TEXTURE_MAX_ENUM; i++) - { - for (int datatype = (int)DATA_BASETYPE_FLOAT; datatype <= (int)DATA_BASETYPE_UINT; datatype++) - { - state.defaultTexture[i][datatype] = 0; - - TextureType type = (TextureType) i; - - if (!isTextureTypeSupported(type)) - continue; - - if (datatype != DATA_BASETYPE_FLOAT && !(GLAD_VERSION_3_0 || GLAD_ES_VERSION_3_0)) - continue; - - GLuint curtexture = state.boundTextures[type][0]; - - glGenTextures(1, &state.defaultTexture[type][datatype]); - bindTextureToUnit(type, state.defaultTexture[type][datatype], 0, false); - - setSamplerState(type, s); - - PixelFormat format = PIXELFORMAT_RGBA8_UNORM; - if (datatype == DATA_BASETYPE_INT) - format = PIXELFORMAT_RGBA8_INT; - else if (datatype == DATA_BASETYPE_UINT) - format = PIXELFORMAT_RGBA8_UINT; - - const GLubyte *p = datatype == DATA_BASETYPE_FLOAT ? pix : intpix; - - rawTexStorage(type, 1, format, 1, 1); - - TextureFormat fmt = convertPixelFormat(format, false); - int slices = type == TEXTURE_CUBE ? 6 : 1; - - for (int slice = 0; slice < slices; slice++) - { - GLenum gltarget = getGLTextureType(type); - - if (type == TEXTURE_CUBE) - gltarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice; - - if (type == TEXTURE_2D || type == TEXTURE_CUBE) - glTexSubImage2D(gltarget, 0, 0, 0, 1, 1, fmt.externalformat, fmt.type, p); - else if (type == TEXTURE_2D_ARRAY || type == TEXTURE_VOLUME) - glTexSubImage3D(gltarget, 0, 0, 0, slice, 1, 1, 1, fmt.externalformat, fmt.type, p); - } - - bindTextureToUnit(type, curtexture, 0, false); - } - } -} - void OpenGL::prepareDraw(love::graphics::Graphics *gfx) { TempDebugGroup debuggroup("Prepare OpenGL draw"); @@ -702,6 +623,7 @@ GLenum OpenGL::getGLBufferType(BufferUsage usage) case BUFFERUSAGE_VERTEX: return GL_ARRAY_BUFFER; case BUFFERUSAGE_INDEX: return GL_ELEMENT_ARRAY_BUFFER; case BUFFERUSAGE_TEXEL: return GL_TEXTURE_BUFFER; + case BUFFERUSAGE_UNIFORM: return GL_UNIFORM_BUFFER; case BUFFERUSAGE_SHADER_STORAGE: return GL_SHADER_STORAGE_BUFFER; case BUFFERUSAGE_INDIRECT_ARGUMENTS: return GL_DRAW_INDIRECT_BUFFER; case BUFFERUSAGE_MAX_ENUM: return GL_ZERO; @@ -1191,11 +1113,6 @@ GLuint OpenGL::getDefaultFBO() const #endif } -GLuint OpenGL::getDefaultTexture(TextureType type, DataBaseType datatype) const -{ - return state.defaultTexture[type][datatype]; -} - void OpenGL::setTextureUnit(int textureunit) { if (textureunit != state.curTextureUnit) @@ -1234,31 +1151,8 @@ void OpenGL::bindBufferTextureToUnit(GLuint texture, int textureunit, bool resto void OpenGL::bindTextureToUnit(Texture *texture, int textureunit, bool restoreprev, bool bindforedit) { - TextureType textype = TEXTURE_2D; - GLuint handle = 0; - - if (texture != nullptr) - { - textype = texture->getTextureType(); - handle = (GLuint) texture->getHandle(); - } - else - { - DataBaseType datatype = DATA_BASETYPE_FLOAT; - - if (textureunit == 0 && Shader::current != nullptr) - { - const Shader::UniformInfo *info = Shader::current->getMainTextureInfo(); - if (info != nullptr) - { - textype = info->textureType; - datatype = info->dataBaseType; - } - } - - handle = getDefaultTexture(textype, datatype); - } - + TextureType textype = texture->getTextureType(); + GLuint handle = (GLuint) texture->getHandle(); bindTextureToUnit(textype, handle, textureunit, restoreprev, bindforedit); } @@ -1537,6 +1431,8 @@ bool OpenGL::isBufferUsageSupported(BufferUsage usage) const return true; case BUFFERUSAGE_TEXEL: return GLAD_VERSION_3_1 || GLAD_ES_VERSION_3_2; + case BUFFERUSAGE_UNIFORM: + return GLAD_VERSION_3_1 || GLAD_ES_VERSION_3_0; case BUFFERUSAGE_SHADER_STORAGE: return (GLAD_VERSION_4_3 && isCoreProfile()) || GLAD_ES_VERSION_3_1; case BUFFERUSAGE_INDIRECT_ARGUMENTS: diff --git a/src/modules/graphics/opengl/OpenGL.h b/src/modules/graphics/opengl/OpenGL.h index e3cbff100..32f2bf8c1 100644 --- a/src/modules/graphics/opengl/OpenGL.h +++ b/src/modules/graphics/opengl/OpenGL.h @@ -330,11 +330,6 @@ class OpenGL **/ GLuint getDefaultFBO() const; - /** - * Gets the ID for love's default texture (used for "untextured" primitives.) - **/ - GLuint getDefaultTexture(TextureType type, DataBaseType datatype) const; - /** * Gets the texture ID for love's default texel buffer. **/ @@ -492,7 +487,6 @@ class OpenGL void initVendor(); void initOpenGLFunctions(); void initMaxValues(); - void createDefaultTexture(); bool contextInitialized; @@ -550,7 +544,6 @@ class OpenGL GLuint boundFramebuffers[2]; - GLuint defaultTexture[TEXTURE_MAX_ENUM][DATA_BASETYPE_MAX_ENUM]; GLuint defaultTexelBuffer; GLuint defaultStorageBuffer; diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index bfd728a1e..a89b09f04 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -110,6 +110,8 @@ void Shader::mapActiveUniforms() std::map olduniforms = uniforms; uniforms.clear(); + auto gfx = Module::getInstance(Module::M_GRAPHICS); + for (int uindex = 0; uindex < numuniforms; uindex++) { GLsizei namelen = 0; @@ -140,7 +142,7 @@ void Shader::mapActiveUniforms() continue; if (!fillUniformReflectionData(u)) - continue;; + continue; if ((u.baseType == UNIFORM_SAMPLER && builtin != BUILTIN_TEXTURE_MAIN) || u.baseType == UNIFORM_TEXELBUFFER) { @@ -156,7 +158,7 @@ void Shader::mapActiveUniforms() else { unit.isTexelBuffer = false; - unit.texture = gl.getDefaultTexture(u.textureType, u.dataBaseType); + unit.texture = 0; // Handled below. } for (int i = 0; i < u.count; i++) @@ -165,7 +167,7 @@ void Shader::mapActiveUniforms() else if (u.baseType == UNIFORM_STORAGETEXTURE) { StorageTextureBinding binding = {}; - binding.gltexture = gl.getDefaultTexture(u.textureType, u.dataBaseType); + binding.gltexture = 0; // Handled below. binding.type = u.textureType; if ((u.access & (ACCESS_READ | ACCESS_WRITE)) != 0) @@ -247,7 +249,13 @@ void Shader::mapActiveUniforms() else { u.textures = new love::graphics::Texture*[u.count]; - memset(u.textures, 0, sizeof(Texture *) * u.count); + + auto *tex = gfx->getDefaultTexture(u.textureType, u.dataBaseType); + for (int i = 0; i < u.count; i++) + { + tex->retain(); + u.textures[i] = tex; + } } } else if (u.baseType == UNIFORM_STORAGETEXTURE) @@ -259,7 +267,20 @@ void Shader::mapActiveUniforms() glUniform1iv(u.location, u.count, u.ints); u.textures = new love::graphics::Texture*[u.count]; - memset(u.textures, 0, sizeof(Texture *) * u.count); + + if ((u.access & ACCESS_WRITE) != 0) + { + memset(u.textures, 0, sizeof(Texture *) * u.count); + } + else + { + auto *tex = gfx->getDefaultTexture(u.textureType, u.dataBaseType); + for (int i = 0; i < u.count; i++) + { + tex->retain(); + u.textures[i] = tex; + } + } } } @@ -777,9 +798,15 @@ void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **tex { if (!validateTexture(info, tex, internalUpdate)) continue; - tex->retain(); + } + else + { + auto gfx = Module::getInstance(Module::M_GRAPHICS); + tex = gfx->getDefaultTexture(info->textureType, info->dataBaseType); } + tex->retain(); + if (info->textures[i] != nullptr) info->textures[i]->release(); @@ -787,11 +814,7 @@ void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **tex if (isstoragetex) { - GLuint gltex = 0; - if (tex != nullptr) - gltex = (GLuint) tex->getHandle(); - else - gltex = gl.getDefaultTexture(info->textureType, info->dataBaseType); + GLuint gltex = (GLuint) tex->getHandle(); int bindingindex = info->ints[i]; auto &binding = storageTextureBindings[bindingindex]; @@ -804,11 +827,7 @@ void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **tex } else { - GLuint gltex = 0; - if (textures[i] != nullptr) - gltex = (GLuint) tex->getHandle(); - else - gltex = gl.getDefaultTexture(info->textureType, info->dataBaseType); + GLuint gltex = (GLuint) tex->getHandle(); int texunit = info->ints[i]; diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index d3ca164f1..d6710e4aa 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -157,7 +157,6 @@ Graphics::~Graphics() { defaultConstantTexCoord.set(nullptr); defaultConstantColor.set(nullptr); - defaultTexture.set(nullptr); Volatile::unloadAll(); cleanup(); @@ -676,7 +675,6 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int defaultConstantColor = newBuffer(settings, { format }, whiteColor, sizeof(whiteColor), 1); } - createDefaultTexture(); createDefaultShaders(); Shader::current = Shader::standardShaders[Shader::StandardShader::STANDARD_DEFAULT]; createQuadIndexBuffer(); @@ -2384,10 +2382,7 @@ void Graphics::prepareDraw(const VertexAttributes &attributes, const BufferBindi offsets.push_back((VkDeviceSize)0); } - if (texture == nullptr) - configuration.shader->setMainTex(defaultTexture); - else - configuration.shader->setMainTex(texture); + configuration.shader->setMainTex(texture); ensureGraphicsPipelineConfiguration(configuration); @@ -3035,15 +3030,6 @@ void Graphics::createSyncObjects() throw love::Exception("failed to create synchronization objects for a frame!"); } -void Graphics::createDefaultTexture() -{ - Texture::Settings settings; - defaultTexture.set(newTexture(settings, nullptr), Acquire::NORETAIN); - - uint8_t whitePixels[] = {255, 255, 255, 255}; - defaultTexture->replacePixels(whitePixels, sizeof(whitePixels), 0, 0, { 0, 0, 1, 1 }, false); -} - void Graphics::cleanup() { for (auto &cleanUpFns : cleanUpFunctions) diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index b4173c009..20c31cd80 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -367,7 +367,6 @@ class Graphics final : public love::graphics::Graphics void createCommandPool(); void createCommandBuffers(); void createSyncObjects(); - void createDefaultTexture(); void cleanup(); void cleanupSwapChain(); void recreateSwapChain(); @@ -442,7 +441,6 @@ class Graphics final : public love::graphics::Graphics bool swapChainRecreationRequested = false; bool transitionColorDepthLayouts = false; VmaAllocator vmaAllocator = VK_NULL_HANDLE; - StrongRef defaultTexture; StrongRef defaultConstantColor; StrongRef defaultConstantTexCoord; // functions that need to be called to cleanup objects that were needed for rendering a frame.