diff --git a/data/shaders/drawimage.frag b/data/shaders/drawimage.frag index 4566f0f7fe..e5deded42b 100644 --- a/data/shaders/drawimage.frag +++ b/data/shaders/drawimage.frag @@ -1,12 +1,13 @@ #version 150 -uniform ivec4 uClip; -uniform int uFlags; -uniform vec4 uColour; -uniform usampler2DArray uTexture; uniform vec4 uPalette[256]; -uniform vec2 uTexCoordScale; -uniform int uTexSlot; +uniform usampler2DArray uTexture; + +flat in ivec4 fClip; +flat in int fFlags; +in vec4 fColour; +in vec2 fTexCoordScale; +flat in int fTexSlot; in vec2 fPosition; in vec2 fTextureCoordinate; @@ -15,16 +16,16 @@ out vec4 oColour; void main() { - if (fPosition.x < uClip.x || fPosition.x > uClip.z || - fPosition.y < uClip.y || fPosition.y > uClip.w) + if (fPosition.x < fClip.x || fPosition.x > fClip.z || + fPosition.y < fClip.y || fPosition.y > fClip.w) { discard; } - vec4 texel = uPalette[texture(uTexture, vec3(fTextureCoordinate * uTexCoordScale, float(uTexSlot))).r]; - if ((uFlags & 1) != 0) + vec4 texel = uPalette[texture(uTexture, vec3(fTextureCoordinate * fTexCoordScale, float(fTexSlot))).r]; + if ((fFlags & 1) != 0) { - oColour = vec4(uColour.rgb, uColour.a * texel.a); + oColour = vec4(fColour.rgb, fColour.a * texel.a); } else { diff --git a/data/shaders/drawimage.vert b/data/shaders/drawimage.vert index 84b893c0dc..c6d33f57cc 100644 --- a/data/shaders/drawimage.vert +++ b/data/shaders/drawimage.vert @@ -1,32 +1,43 @@ #version 150 uniform ivec2 uScreenSize; -uniform ivec4 uBounds; uniform ivec4 uTextureCoordinates; +in ivec4 ivClip; +in vec2 ivTexCoordScale; +in int ivTexSlot; +in int ivFlags; +in vec4 ivColour; +in ivec4 ivBounds; + in uint vIndex; -out vec2 fPosition; -out vec2 fTextureCoordinate; +out vec2 fTextureCoordinate; +out vec2 fPosition; +flat out ivec4 fClip; +flat out int fFlags; +out vec4 fColour; +out vec2 fTexCoordScale; +flat out int fTexSlot; void main() { vec2 pos; switch (vIndex) { case 0u: - pos = uBounds.xy; + pos = ivBounds.xy; fTextureCoordinate = uTextureCoordinates.xy; break; case 1u: - pos = uBounds.zy; + pos = ivBounds.zy; fTextureCoordinate = uTextureCoordinates.zy; break; case 2u: - pos = uBounds.xw; + pos = ivBounds.xw; fTextureCoordinate = uTextureCoordinates.xw; break; case 3u: - pos = uBounds.zw; + pos = ivBounds.zw; fTextureCoordinate = uTextureCoordinates.zw; break; } @@ -38,5 +49,11 @@ void main() pos.y = (pos.y * (2.0 / uScreenSize.y)) - 1.0; pos.y *= -1; + fClip = ivClip; + fFlags = ivFlags; + fColour = ivColour; + fTexCoordScale = ivTexCoordScale; + fTexSlot = ivTexSlot; + gl_Position = vec4(pos, 0.0, 1.0); } diff --git a/src/drawing/engines/opengl/DrawImageShader.cpp b/src/drawing/engines/opengl/DrawImageShader.cpp index d9346ce3d3..09ee1ce3b4 100644 --- a/src/drawing/engines/opengl/DrawImageShader.cpp +++ b/src/drawing/engines/opengl/DrawImageShader.cpp @@ -23,6 +23,7 @@ DrawImageShader::DrawImageShader() : OpenGLShaderProgram("drawimage") GetLocations(); glGenBuffers(1, &_vbo); + glGenBuffers(1, &_vboInstances); glGenVertexArrays(1, &_vao); GLuint vertices[] = { 0, 1, 2, 2, 1, 3 }; @@ -34,7 +35,6 @@ DrawImageShader::DrawImageShader() : OpenGLShaderProgram("drawimage") glVertexAttribIPointer(vIndex, 1, GL_INT, 0, nullptr); Use(); - SetFlags(0); SetTextureCoordinates(0, 0, 1, 1); glUniform1i(uTexture, 0); } @@ -42,6 +42,7 @@ DrawImageShader::DrawImageShader() : OpenGLShaderProgram("drawimage") DrawImageShader::~DrawImageShader() { glDeleteBuffers(1, &_vbo); + glDeleteBuffers(1, &_vboInstances); glDeleteVertexArrays(1, &_vao); glBindVertexArray(_vao); @@ -50,15 +51,9 @@ DrawImageShader::~DrawImageShader() void DrawImageShader::GetLocations() { uScreenSize = GetUniformLocation("uScreenSize"); - uClip = GetUniformLocation("uClip"); - uBounds = GetUniformLocation("uBounds"); - uTextureCoordinates = GetUniformLocation("uTextureCoordinates"); uTexture = GetUniformLocation("uTexture"); - uColour = GetUniformLocation("uColour"); - uFlags = GetUniformLocation("uFlags"); uPalette = GetUniformLocation("uPalette"); - uTexCoordScale = GetUniformLocation("uTexCoordScale"); - uTexSlot = GetUniformLocation("uTexSlot"); + uTextureCoordinates = GetUniformLocation("uTextureCoordinates"); vIndex = GetAttributeLocation("vIndex"); } @@ -68,14 +63,9 @@ void DrawImageShader::SetScreenSize(sint32 width, sint32 height) glUniform2i(uScreenSize, width, height); } -void DrawImageShader::SetClip(sint32 left, sint32 top, sint32 right, sint32 bottom) +void DrawImageShader::SetPalette(const vec4f *glPalette) { - glUniform4i(uClip, left, top, right, bottom); -} - -void DrawImageShader::SetBounds(sint32 left, sint32 top, sint32 right, sint32 bottom) -{ - glUniform4i(uBounds, left, top, right, bottom); + glUniform4fv(uPalette, 256, (const GLfloat *) glPalette); } void DrawImageShader::SetTextureCoordinates(sint32 left, sint32 top, sint32 right, sint32 bottom) @@ -83,36 +73,38 @@ void DrawImageShader::SetTextureCoordinates(sint32 left, sint32 top, sint32 righ glUniform4i(uTextureCoordinates, left, top, right, bottom); } -void DrawImageShader::SetTextureCoordScale(float width, float height) { - glUniform2f(uTexCoordScale, width, height); -} - -void DrawImageShader::SetTextureSlot(GLuint slot) +void DrawImageShader::DrawInstances(const std::vector& instances) { - glUniform1i(uTexSlot, slot); -} - -void DrawImageShader::SetColour(vec4f colour) -{ - glUniform4f(uColour, colour.r, colour.g, colour.b, colour.a); -} - -void DrawImageShader::SetFlags(uint32 flags) -{ - glUniform1i(uFlags, flags); -} - -void DrawImageShader::SetPalette(const vec4f *glPalette) -{ - glUniform4fv(uPalette, 256, (const GLfloat *) glPalette); -} - -void DrawImageShader::Draw(sint32 left, sint32 top, sint32 right, sint32 bottom) -{ - SetBounds(left, top, right, bottom); + // Copy instance data to vbo for single-use + glBindBuffer(GL_ARRAY_BUFFER, _vboInstances); + glBufferData(GL_ARRAY_BUFFER, sizeof(instances[0]) * instances.size(), instances.data(), GL_STREAM_DRAW); + // Bind vertex attributes glBindVertexArray(_vao); - glDrawArrays(GL_TRIANGLES, 0, 6); + + glVertexAttribIPointer(GetAttributeLocation("ivClip"), 4, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, clip)); + glVertexAttribPointer(GetAttributeLocation("ivTexCoordScale"), 2, GL_FLOAT, GL_FALSE, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texCoordScale)); + glVertexAttribIPointer(GetAttributeLocation("ivTexSlot"), 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texSlot)); + glVertexAttribIPointer(GetAttributeLocation("ivFlags"), 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, flags)); + glVertexAttribPointer(GetAttributeLocation("ivColour"), 4, GL_FLOAT, GL_FALSE, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, colour)); + glVertexAttribIPointer(GetAttributeLocation("ivBounds"), 4, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, bounds)); + + glEnableVertexAttribArray(GetAttributeLocation("ivClip")); + glEnableVertexAttribArray(GetAttributeLocation("ivTexCoordScale")); + glEnableVertexAttribArray(GetAttributeLocation("ivTexSlot")); + glEnableVertexAttribArray(GetAttributeLocation("ivFlags")); + glEnableVertexAttribArray(GetAttributeLocation("ivColour")); + glEnableVertexAttribArray(GetAttributeLocation("ivBounds")); + + glVertexAttribDivisor(GetAttributeLocation("ivClip"), 1); + glVertexAttribDivisor(GetAttributeLocation("ivTexCoordScale"), 1); + glVertexAttribDivisor(GetAttributeLocation("ivTexSlot"), 1); + glVertexAttribDivisor(GetAttributeLocation("ivFlags"), 1); + glVertexAttribDivisor(GetAttributeLocation("ivColour"), 1); + glVertexAttribDivisor(GetAttributeLocation("ivBounds"), 1); + + // Draw instances + glDrawArraysInstanced(GL_TRIANGLES, 0, 6, instances.size()); } #endif /* DISABLE_OPENGL */ diff --git a/src/drawing/engines/opengl/DrawImageShader.h b/src/drawing/engines/opengl/DrawImageShader.h index ca955842db..3c45b1194c 100644 --- a/src/drawing/engines/opengl/DrawImageShader.h +++ b/src/drawing/engines/opengl/DrawImageShader.h @@ -19,24 +19,30 @@ #include "GLSLTypes.h" #include "OpenGLShaderProgram.h" #include +#include + +// Per-instance data for images +struct DrawImageInstance { + vec4i clip; + vec2f texCoordScale; + int texSlot; + int flags; + vec4f colour; + vec4i bounds; +}; class DrawImageShader : public OpenGLShaderProgram { private: GLuint uScreenSize; - GLuint uClip; - GLuint uBounds; - GLuint uTextureCoordinates; GLuint uTexture; - GLuint uColour; - GLuint uFlags; GLuint uPalette; - GLuint uTexCoordScale; - GLuint uTexSlot; + GLuint uTextureCoordinates; GLuint vIndex; GLuint _vbo; + GLuint _vboInstances; GLuint _vao; SDL_Color _palette[256]; @@ -46,15 +52,9 @@ public: ~DrawImageShader() override; void SetScreenSize(sint32 width, sint32 height); - void SetClip(sint32 left, sint32 top, sint32 right, sint32 bottom); - void SetBounds(sint32 left, sint32 top, sint32 right, sint32 bottom); - void SetTextureCoordinates(sint32 left, sint32 top, sint32 right, sint32 bottom); - void SetTextureCoordScale(float width, float height); - void SetTextureSlot(GLuint slot); - void SetColour(vec4f colour); - void SetFlags(uint32 flags); void SetPalette(const vec4f *glPalette); - void Draw(sint32 left, sint32 top, sint32 right, sint32 bottom); + void SetTextureCoordinates(sint32 left, sint32 top, sint32 right, sint32 bottom); + void DrawInstances(const std::vector& instances); private: void GetLocations(); diff --git a/src/drawing/engines/opengl/OpenGLAPI.cpp b/src/drawing/engines/opengl/OpenGLAPI.cpp index fc28162e97..61d0483140 100644 --- a/src/drawing/engines/opengl/OpenGLAPI.cpp +++ b/src/drawing/engines/opengl/OpenGLAPI.cpp @@ -110,6 +110,8 @@ static const char * TryLoadAllProcAddresses() SetupOpenGLFunction(glVertexAttribPointer); SetupOpenGLFunction(glTexStorage3D); SetupOpenGLFunction(glDebugMessageCallback); + SetupOpenGLFunction(glDrawArraysInstanced); + SetupOpenGLFunction(glVertexAttribDivisor); return nullptr; } diff --git a/src/drawing/engines/opengl/OpenGLAPI.h b/src/drawing/engines/opengl/OpenGLAPI.h index 3da30a2286..fc9a1bd0e2 100644 --- a/src/drawing/engines/opengl/OpenGLAPI.h +++ b/src/drawing/engines/opengl/OpenGLAPI.h @@ -162,6 +162,8 @@ GLAPI_DECL PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer GLAP GLAPI_DECL PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer GLAPI_SET; GLAPI_DECL PFNGLTEXSTORAGE3DPROC glTexStorage3D GLAPI_SET; GLAPI_DECL PFNGLDEBUGMESSAGECALLBACKPROC glDebugMessageCallback GLAPI_SET; +GLAPI_DECL PFNGLDRAWARRAYSINSTANCEDPROC glDrawArraysInstanced GLAPI_SET; +GLAPI_DECL PFNGLVERTEXATTRIBDIVISORPROC glVertexAttribDivisor GLAPI_SET; #endif /* OPENGL_NO_LINK */ diff --git a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp index b505626e6d..9b3a8831aa 100644 --- a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp +++ b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp @@ -803,7 +803,8 @@ void OpenGLDrawingContext::DrawSpriteRawMasked(sint32 x, sint32 y, uint32 maskIm _commandBuffers.maskedImages.push_back(command); // Currently not properly ordered with regular images yet - FlushCommandBuffers(); + // TODO: uncomment once masked images are mixed with normal images using depth sorting + //FlushCommandBuffers(); } void OpenGLDrawingContext::DrawSpriteSolid(uint32 image, sint32 x, sint32 y, uint8 colour) @@ -943,18 +944,29 @@ void OpenGLDrawingContext::FlushLines() { } void OpenGLDrawingContext::FlushImages() { + if (_commandBuffers.images.size() == 0) return; + OpenGLAPI::SetTexture(0, GL_TEXTURE_2D_ARRAY, _textureCache->GetArrayTexture()); + + std::vector instances; + instances.reserve(_commandBuffers.images.size()); for (const auto& command : _commandBuffers.images) { - _drawImageShader->Use(); - _drawImageShader->SetClip(command.clip[0], command.clip[1], command.clip[2], command.clip[3]); - _drawImageShader->SetTextureCoordScale(command.texColour.dimensions.x, command.texColour.dimensions.y); - _drawImageShader->SetTextureSlot(command.texColour.slot); - _drawImageShader->SetFlags(command.flags); - _drawImageShader->SetColour(command.colour); - _drawImageShader->Draw(command.bounds[0], command.bounds[1], command.bounds[2], command.bounds[3]); + DrawImageInstance instance; + + instance.clip = {command.clip[0], command.clip[1], command.clip[2], command.clip[3]}; + instance.texCoordScale = command.texColour.dimensions; + instance.texSlot = command.texColour.slot; + instance.flags = command.flags; + instance.colour = command.colour; + instance.bounds = {command.bounds[0], command.bounds[1], command.bounds[2], command.bounds[3]}; + + instances.push_back(instance); } + _drawImageShader->Use(); + _drawImageShader->DrawInstances(instances); + _commandBuffers.images.clear(); } diff --git a/src/drawing/engines/opengl/TextureCache.cpp b/src/drawing/engines/opengl/TextureCache.cpp index 264ba7ff58..bc4472275f 100644 --- a/src/drawing/engines/opengl/TextureCache.cpp +++ b/src/drawing/engines/opengl/TextureCache.cpp @@ -64,7 +64,7 @@ CachedTextureInfo TextureCache::GetOrLoadImageTexture(uint32 image) auto cacheInfo = LoadImageTexture(image); _imageTextureMap[image & 0x7FFFF] = cacheInfo; - printf("%d slots left\n", (int) _freeSlots.size()); + //printf("%d slots left\n", (int) _freeSlots.size()); return cacheInfo; } @@ -86,7 +86,7 @@ CachedTextureInfo TextureCache::GetOrLoadGlyphTexture(uint32 image, uint8 * pale auto cacheInfo = LoadGlyphTexture(image, palette); _glyphTextureMap[glyphId] = cacheInfo; - printf("%d slots left\n", (int) _freeSlots.size()); + //printf("%d slots left\n", (int) _freeSlots.size()); return cacheInfo; }