diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index 58124a3cf..a5bb79a13 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -389,7 +389,7 @@ void Canvas::setupGrab() // bind the framebuffer object. gl.bindFramebuffer(GL_FRAMEBUFFER, fbo); - gl.setViewport(OpenGL::Viewport(0, 0, width, height)); + gl.setViewport({0, 0, width, height}); // Set up the projection matrix gl.matrices.projection.push_back(Matrix::ortho(0.0, width, 0.0, height)); diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 2e5f36801..a1925c74e 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -219,7 +219,7 @@ void Graphics::setViewportSize(int width, int height) setCanvas(); // Set the viewport to top-left corner. - gl.setViewport(OpenGL::Viewport(0, 0, width, height)); + gl.setViewport({0, 0, width, height}); // If a canvas was bound before this function was called, it needs to be // made aware of the new system viewport size. @@ -512,7 +512,7 @@ bool Graphics::isCreated() const void Graphics::setScissor(int x, int y, int width, int height) { - OpenGL::Viewport box(x, y, width, height); + OpenGL::Viewport box = {x, y, width, height}; states.back().scissor = true; glEnable(GL_SCISSOR_TEST); diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index 8ae2c8344..f0e3acd84 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -52,8 +52,9 @@ OpenGL::OpenGL() , contextInitialized(false) , maxAnisotropy(1.0f) , maxTextureSize(0) - , maxRenderTargets(0) + , maxRenderTargets(1) , maxRenderbufferSamples(0) + , maxTextureUnits(1) , vendor(VENDOR_UNKNOWN) , state() { @@ -83,6 +84,8 @@ void OpenGL::setupContext() if (!contextInitialized) return; + initMaxValues(); + state.color = Color(255, 255, 255, 255); GLfloat glcolor[4] = {1.0f, 1.0f, 1.0f, 1.0f}; glVertexAttrib4fv(ATTRIB_COLOR, glcolor); @@ -102,11 +105,7 @@ void OpenGL::setupContext() // Initialize multiple texture unit support for shaders. state.boundTextures.clear(); - - GLint maxtextureunits; - glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxtextureunits); - - state.boundTextures.resize(maxtextureunits, 0); + state.boundTextures.resize(maxTextureUnits, 0); GLenum curgltextureunit; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint *) &curgltextureunit); @@ -125,7 +124,6 @@ void OpenGL::setupContext() BlendState blend = {GL_ONE, GL_ONE, GL_ZERO, GL_ZERO, GL_FUNC_ADD}; setBlendState(blend); - initMaxValues(); createDefaultTexture(); // Invalidate the cached matrices by setting some elements to NaN. @@ -257,6 +255,8 @@ void OpenGL::initMaxValues() } else maxRenderbufferSamples = 0; + + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits); } void OpenGL::initMatrices() @@ -484,21 +484,29 @@ void OpenGL::bindTexture(GLuint texture) } } -void OpenGL::bindTextureToUnit(GLuint texture, int textureunit, bool restoreprev) +void OpenGL::bindTextures(GLuint first, GLsizei count, const GLuint *textures) { - if (textureunit < 0 || (size_t) textureunit >= state.boundTextures.size()) - throw love::Exception("Invalid texture unit index."); + if (first + count > (GLuint) maxTextureUnits) + return; - if (texture != state.boundTextures[textureunit]) + if (GLAD_VERSION_4_4 || GLAD_ARB_multi_bind) + glBindTextures(first, count, textures); + else { - int oldtextureunit = state.curTextureUnit; - setTextureUnit(textureunit); + for (GLint i = 0; i < count; i++) + { + GLuint texture = textures != nullptr ? textures[i] : 0; - state.boundTextures[textureunit] = texture; - glBindTexture(GL_TEXTURE_2D, texture); + if (state.boundTextures[first + i] != texture) + { + glActiveTexture(GL_TEXTURE0 + first + i); + glBindTexture(GL_TEXTURE_2D, texture); - if (restoreprev) - setTextureUnit(oldtextureunit); + state.boundTextures[first + i] = texture; + } + } + + glActiveTexture(GL_TEXTURE0 + state.curTextureUnit); } } @@ -598,6 +606,11 @@ int OpenGL::getMaxRenderbufferSamples() const return maxRenderbufferSamples; } +int OpenGL::getMaxTextureUnits() const +{ + return maxTextureUnits; +} + void OpenGL::updateTextureMemorySize(size_t oldsize, size_t newsize) { int64 memsize = (int64) stats.textureMemory + ((int64 )newsize - (int64) oldsize); diff --git a/src/modules/graphics/opengl/OpenGL.h b/src/modules/graphics/opengl/OpenGL.h index 87b833fd6..e902b81d0 100644 --- a/src/modules/graphics/opengl/OpenGL.h +++ b/src/modules/graphics/opengl/OpenGL.h @@ -55,7 +55,6 @@ enum VertexAttribID ATTRIB_POS = 0, ATTRIB_TEXCOORD, ATTRIB_COLOR, - ATTRIB_PSEUDO_INSTANCE_ID, // Instance ID used with pseudo-instancing. ATTRIB_MAX_ENUM }; @@ -93,14 +92,6 @@ public: int x, y; int w, h; - Viewport() - : x(0), y(0), w(0), h(0) - {} - - Viewport(int _x, int _y, int _w, int _h) - : x(_x), y(_y), w(_w), h(_h) - {} - bool operator == (const Viewport &rhs) const { return x == rhs.x && y == rhs.y && w == rhs.w && h == rhs.h; @@ -271,12 +262,10 @@ public: void bindTexture(GLuint texture); /** - * Helper for binding a texture to a specific texture unit. - * - * @param textureunit Index in the range of [0, maxtextureunits-1] - * @param restoreprev Restore previously bound texture unit when done. + * Binds multiple textures to texture units without changing the active + * texture unit. Equivalent to glBindTextures. **/ - void bindTextureToUnit(GLuint texture, int textureunit, bool restoreprev); + void bindTextures(GLuint first, GLsizei count, const GLuint *textures); /** * Helper for deleting an OpenGL texture. @@ -311,6 +300,11 @@ public: **/ int getMaxRenderbufferSamples() const; + /** + * Returns the maximum number of accessible texture units. + **/ + int getMaxTextureUnits() const; + void updateTextureMemorySize(size_t oldsize, size_t newsize); /** @@ -337,6 +331,7 @@ private: int maxTextureSize; int maxRenderTargets; int maxRenderbufferSamples; + int maxTextureUnits; Vendor vendor; diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index 2e6250b68..657c458a0 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -66,7 +66,6 @@ Shader *Shader::defaultShader = nullptr; Shader::ShaderSource Shader::defaultCode[Graphics::RENDERER_MAX_ENUM]; -GLint Shader::maxTexUnits = 0; std::vector Shader::textureCounters; Shader::Shader(const ShaderSource &source) @@ -80,16 +79,9 @@ Shader::Shader(const ShaderSource &source) if (source.vertex.empty() && source.pixel.empty()) throw love::Exception("Cannot create shader: no source code!"); - if (maxTexUnits <= 0) - { - GLint maxtexunits; - glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxtexunits); - maxTexUnits = std::max(maxtexunits - 1, 0); - } - // initialize global texture id counters if needed - if (textureCounters.size() < (size_t) maxTexUnits) - textureCounters.resize(maxTexUnits, 0); + if ((int) textureCounters.size() < gl.getMaxTextureUnits()) + textureCounters.resize(gl.getMaxTextureUnits(), 0); // load shader source and create program object loadVolatile(); @@ -224,7 +216,7 @@ bool Shader::loadVolatile() // zero out active texture list activeTexUnits.clear(); - activeTexUnits.insert(activeTexUnits.begin(), maxTexUnits, 0); + activeTexUnits.insert(activeTexUnits.begin(), gl.getMaxTextureUnits(), 0); std::vector shaderids; @@ -263,16 +255,8 @@ bool Shader::loadVolatile() // Bind generic vertex attribute indices to names in the shader. for (int i = 0; i < int(ATTRIB_MAX_ENUM); i++) { - VertexAttribID attrib = (VertexAttribID) i; - - // FIXME: We skip this both because pseudo-instancing is temporarily - // disabled (see graphics.lua), and because binding a non-existant - // attribute name to a location causes a shader linker warning. - if (attrib == ATTRIB_PSEUDO_INSTANCE_ID) - continue; - const char *name = nullptr; - if (attribNames.find(attrib, name)) + if (attribNames.find((VertexAttribID) i, name)) glBindAttribLocation(program, i, (const GLchar *) name); } @@ -336,7 +320,7 @@ void Shader::unloadVolatile() // active texture list is probably invalid, clear it activeTexUnits.clear(); - activeTexUnits.resize(maxTexUnits, 0); + activeTexUnits.resize(gl.getMaxTextureUnits(), 0); // same with uniform location list uniforms.clear(); @@ -398,14 +382,7 @@ void Shader::attach(bool temporary) { // make sure all sent textures are properly bound to their respective texture units // note: list potentially contains texture ids of deleted/invalid textures! - for (size_t i = 0; i < activeTexUnits.size(); ++i) - { - if (activeTexUnits[i] > 0) - gl.bindTextureToUnit(activeTexUnits[i], (int) i + 1, false); - } - - // We always want to use texture unit 0 for everyhing else. - gl.setTextureUnit(0); + gl.bindTextures(1, (GLsizei) activeTexUnits.size(), &activeTexUnits[0]); } } @@ -546,13 +523,10 @@ void Shader::sendTexture(const std::string &name, Texture *texture) checkSetUniformError(u, 1, 1, UNIFORM_SAMPLER); // bind texture to assigned texture unit and send uniform to shader program - gl.bindTextureToUnit(gltex, texunit, false); + gl.bindTextures(texunit, 1, &gltex); glUniform1i(u.location, texunit); - // reset texture unit - gl.setTextureUnit(0); - // increment global shader texture id counter for this texture unit, if we haven't already if (activeTexUnits[texunit-1] == 0) ++textureCounters[texunit-1]; @@ -849,7 +823,6 @@ StringMap::Entry Shader::attribNameEntries[] = {"VertexPosition", ATTRIB_POS}, {"VertexTexCoord", ATTRIB_TEXCOORD}, {"VertexColor", ATTRIB_COLOR}, - {"love_PseudoInstanceID", ATTRIB_PSEUDO_INSTANCE_ID}, }; StringMap Shader::attribNames(Shader::attribNameEntries, sizeof(Shader::attribNameEntries)); diff --git a/src/modules/graphics/opengl/Shader.h b/src/modules/graphics/opengl/Shader.h index 6091664e5..8b6dc1102 100644 --- a/src/modules/graphics/opengl/Shader.h +++ b/src/modules/graphics/opengl/Shader.h @@ -250,9 +250,6 @@ private: Canvas *lastCanvas; OpenGL::Viewport lastViewport; - // Max GPU texture units available for sent images - static GLint maxTexUnits; - // Counts total number of textures bound to each texture unit in all shaders static std::vector textureCounters; diff --git a/src/modules/graphics/opengl/wrap_Image.cpp b/src/modules/graphics/opengl/wrap_Image.cpp index d27fe81f0..b99d856f0 100644 --- a/src/modules/graphics/opengl/wrap_Image.cpp +++ b/src/modules/graphics/opengl/wrap_Image.cpp @@ -94,15 +94,9 @@ int w_Image_getData(lua_State *L) Image *i = luax_checkimage(L, 1); if (i->isCompressed()) - { - love::image::CompressedData *t = i->getCompressedData(); - luax_pushtype(L, IMAGE_COMPRESSED_DATA_ID, t); - } + luax_pushtype(L, IMAGE_COMPRESSED_DATA_ID, i->getCompressedData()); else - { - love::image::ImageData *t = i->getImageData(); - luax_pushtype(L, IMAGE_IMAGE_DATA_ID, t); - } + luax_pushtype(L, IMAGE_IMAGE_DATA_ID, i->getImageData()); return 1; } diff --git a/src/modules/graphics/opengl/wrap_Shader.cpp b/src/modules/graphics/opengl/wrap_Shader.cpp index aa13d83b2..cd5421b4a 100644 --- a/src/modules/graphics/opengl/wrap_Shader.cpp +++ b/src/modules/graphics/opengl/wrap_Shader.cpp @@ -308,7 +308,7 @@ int w_Shader_send(lua_State *L) // Texture (Image or Canvas). p = (Proxy *) lua_touserdata(L, 3); - if (typeFlags[p->type][GRAPHICS_TEXT_ID]) + if (typeFlags[p->type][GRAPHICS_TEXTURE_ID]) return w_Shader_sendTexture(L); break;