From e7626064f2ef8a7091a32e833dda3c67a8be5a97 Mon Sep 17 00:00:00 2001 From: Alexander Overvoorde Date: Wed, 20 Jul 2016 03:25:00 +0200 Subject: [PATCH 01/24] Change OpenGL renderer to use command buffers --- openrct2.vcxproj | 1 + src/drawing/engines/opengl/DrawCommands.h | 50 ++++ src/drawing/engines/opengl/FillRectShader.cpp | 5 + src/drawing/engines/opengl/FillRectShader.h | 4 + .../engines/opengl/OpenGLDrawingEngine.cpp | 224 +++++++++++++++--- 5 files changed, 248 insertions(+), 36 deletions(-) create mode 100644 src/drawing/engines/opengl/DrawCommands.h diff --git a/openrct2.vcxproj b/openrct2.vcxproj index 91b965c2ce..f8caad1f7a 100644 --- a/openrct2.vcxproj +++ b/openrct2.vcxproj @@ -383,6 +383,7 @@ + diff --git a/src/drawing/engines/opengl/DrawCommands.h b/src/drawing/engines/opengl/DrawCommands.h new file mode 100644 index 0000000000..87a3853780 --- /dev/null +++ b/src/drawing/engines/opengl/DrawCommands.h @@ -0,0 +1,50 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** +* OpenRCT2, an open source clone of Roller Coaster Tycoon 2. +* +* OpenRCT2 is the work of many authors, a full list can be found in contributors.md +* For more information, visit https://github.com/OpenRCT2/OpenRCT2 +* +* OpenRCT2 is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* A full copy of the GNU General Public License can be found in licence.txt +*****************************************************************************/ +#pragma endregion + +#pragma once + +#include "../../../common.h" +#include "OpenGLAPI.h" +#include "GLSLTypes.h" + +struct DrawRectCommand { + uint32 flags; + GLuint sourceFramebuffer; + vec4f colours[2]; + sint32 clip[4]; + sint32 bounds[4]; +}; + +struct DrawLineCommand { + vec4f colour; + sint32 clip[4]; + sint32 pos[4]; +}; + +struct DrawImageCommand { + uint32 flags; + vec4f colour; + sint32 clip[4]; + GLuint texColour; + sint32 bounds[4]; +}; + +struct DrawImageMaskedCommand { + sint32 clip[4]; + GLuint texMask; + GLuint texColour; + sint32 bounds[4]; +}; \ No newline at end of file diff --git a/src/drawing/engines/opengl/FillRectShader.cpp b/src/drawing/engines/opengl/FillRectShader.cpp index 0baf1065c1..3bf5bb363c 100644 --- a/src/drawing/engines/opengl/FillRectShader.cpp +++ b/src/drawing/engines/opengl/FillRectShader.cpp @@ -87,6 +87,7 @@ void FillRectShader::SetColour(int index, vec4f colour) void FillRectShader::SetSourceFramebuffer(GLuint texture) { + _sourceFramebuffer = texture; OpenGLAPI::SetTexture2D(0, texture); } @@ -98,4 +99,8 @@ void FillRectShader::Draw(sint32 left, sint32 top, sint32 right, sint32 bottom) glDrawArrays(GL_TRIANGLES, 0, 6); } +GLuint FillRectShader::GetSourceFramebuffer() const { + return _sourceFramebuffer; +} + #endif /* DISABLE_OPENGL */ diff --git a/src/drawing/engines/opengl/FillRectShader.h b/src/drawing/engines/opengl/FillRectShader.h index d96c33c705..80af878fc6 100644 --- a/src/drawing/engines/opengl/FillRectShader.h +++ b/src/drawing/engines/opengl/FillRectShader.h @@ -36,6 +36,8 @@ private: GLuint _vbo; GLuint _vao; + GLuint _sourceFramebuffer = 0; + public: FillRectShader(); ~FillRectShader() override; @@ -49,6 +51,8 @@ public: void Draw(sint32 left, sint32 top, sint32 right, sint32 bottom); + GLuint GetSourceFramebuffer() const; + private: void GetLocations(); }; diff --git a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp index f0b0df073a..84f66ccfd6 100644 --- a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp +++ b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp @@ -39,6 +39,7 @@ IDrawingEngine * DrawingEngineFactory::CreateOpenGL() #include "FillRectShader.h" #include "SwapFramebuffer.h" #include "TextureCache.h" +#include "DrawCommands.h" #include "../../../core/Console.hpp" #include "../../../core/Exception.hpp" @@ -191,6 +192,13 @@ private: sint32 _clipRight; sint32 _clipBottom; + struct { + std::vector rectangles; + std::vector lines; + std::vector images; + std::vector maskedImages; + } _commandBuffers; + public: explicit OpenGLDrawingContext(OpenGLDrawingEngine * engine); ~OpenGLDrawingContext() override; @@ -210,6 +218,13 @@ public: void DrawSpriteSolid(uint32 image, sint32 x, sint32 y, uint8 colour) override; void DrawGlyph(uint32 image, sint32 x, sint32 y, uint8 * palette) override; + void FlushCommandBuffers(); + + void FlushRectangles(); + void FlushLines(); + void FlushImages(); + void FlushMaskedImages(); + void SetDPI(rct_drawpixelinfo * dpi); }; @@ -325,11 +340,14 @@ public: gfx_draw_pickedup_peep(&_bitsDPI); + _drawingContext->FlushCommandBuffers(); _swapFramebuffer->SwapCopy(); rct2_draw(&_bitsDPI); } + _drawingContext->FlushCommandBuffers(); + // Scale up to window _screenFramebuffer->Bind(); _copyFramebufferShader->Use(); @@ -512,6 +530,8 @@ void OpenGLDrawingContext::Initialise() void OpenGLDrawingContext::Resize(sint32 width, sint32 height) { + FlushCommandBuffers(); + _drawImageShader->Use(); _drawImageShader->SetScreenSize(width, height); _drawImageMaskedShader->Use(); @@ -524,6 +544,8 @@ void OpenGLDrawingContext::Resize(sint32 width, sint32 height) void OpenGLDrawingContext::ResetPalette() { + FlushCommandBuffers(); + _textureCache->SetPalette(_engine->Palette); _drawImageShader->Use(); _drawImageShader->SetPalette(_engine->GLPalette); @@ -543,6 +565,9 @@ void OpenGLDrawingContext::FillRect(uint32 colour, sint32 left, sint32 top, sint right += _offsetX; bottom += _offsetY; + DrawRectCommand command = {}; + command.sourceFramebuffer = _fillRectShader->GetSourceFramebuffer(); + vec4f paletteColour[2]; paletteColour[0] = _engine->GLPalette[(colour >> 0) & 0xFF]; paletteColour[1] = paletteColour[0]; @@ -550,8 +575,7 @@ void OpenGLDrawingContext::FillRect(uint32 colour, sint32 left, sint32 top, sint { paletteColour[1].a = 0; - _fillRectShader->Use(); - _fillRectShader->SetFlags(0); + command.flags = 0; } else if (colour & 0x2000000) { @@ -568,20 +592,29 @@ void OpenGLDrawingContext::FillRect(uint32 colour, sint32 left, sint32 top, sint paletteColour[1] = paletteColour[0]; GLuint srcTexture = _engine->SwapCopyReturningSourceTexture(); - _fillRectShader->Use(); - _fillRectShader->SetFlags(1); - _fillRectShader->SetSourceFramebuffer(srcTexture); + command.flags = 1; + command.sourceFramebuffer = srcTexture; } else { - _fillRectShader->Use(); - _fillRectShader->SetFlags(0); + command.flags = 0; } - _fillRectShader->SetColour(0, paletteColour[0]); - _fillRectShader->SetColour(1, paletteColour[1]); - _fillRectShader->SetClip(_clipLeft, _clipTop, _clipRight, _clipBottom); - _fillRectShader->Draw(left, top, right + 1, bottom + 1); + command.colours[0] = paletteColour[0]; + command.colours[1] = paletteColour[1]; + + command.clip[0] = _clipLeft; + command.clip[1] = _clipTop; + command.clip[2] = _clipRight; + command.clip[3] = _clipBottom; + + command.bounds[0] = left; + command.bounds[1] = top; + command.bounds[2] = right + 1; + command.bounds[3] = bottom + 1; + + _commandBuffers.rectangles.push_back(command); + FlushCommandBuffers(); } void OpenGLDrawingContext::DrawLine(uint32 colour, sint32 x1, sint32 y1, sint32 x2, sint32 y2) @@ -592,11 +625,22 @@ void OpenGLDrawingContext::DrawLine(uint32 colour, sint32 x1, sint32 y1, sint32 y2 += _offsetY; vec4f paletteColour = _engine->GLPalette[colour & 0xFF]; + + DrawLineCommand command = {}; + command.colour = paletteColour; - _drawLineShader->Use(); - _drawLineShader->SetClip(_clipLeft, _clipTop, _clipRight, _clipBottom); - _drawLineShader->SetColour(paletteColour); - _drawLineShader->Draw(x1, y1, x2, y2); + command.clip[0] = _clipLeft; + command.clip[1] = _clipTop; + command.clip[2] = _clipRight; + command.clip[3] = _clipBottom; + + command.pos[0] = x1; + command.pos[1] = y1; + command.pos[2] = x2; + command.pos[3] = y2; + + _commandBuffers.lines.push_back(command); + FlushCommandBuffers(); } void OpenGLDrawingContext::DrawSprite(uint32 image, sint32 x, sint32 y, uint32 tertiaryColour) @@ -664,10 +708,24 @@ void OpenGLDrawingContext::DrawSprite(uint32 image, sint32 x, sint32 y, uint32 t right += _clipLeft; bottom += _clipTop; - _drawImageShader->Use(); - _drawImageShader->SetClip(_clipLeft, _clipTop, _clipRight, _clipBottom); - _drawImageShader->SetTexture(texture); - _drawImageShader->Draw(left, top, right, bottom); + DrawImageCommand command = {}; + + command.flags = 0; + + command.clip[0] = _clipLeft; + command.clip[1] = _clipTop; + command.clip[2] = _clipRight; + command.clip[3] = _clipBottom; + + command.texColour = texture; + + command.bounds[0] = left; + command.bounds[1] = top; + command.bounds[2] = right; + command.bounds[3] = bottom; + + _commandBuffers.images.push_back(command); + FlushCommandBuffers(); } void OpenGLDrawingContext::DrawSpriteRawMasked(sint32 x, sint32 y, uint32 maskImage, uint32 colourImage) @@ -714,11 +772,23 @@ void OpenGLDrawingContext::DrawSpriteRawMasked(sint32 x, sint32 y, uint32 maskIm right += _clipLeft; bottom += _clipTop; - _drawImageMaskedShader->Use(); - _drawImageMaskedShader->SetClip(_clipLeft, _clipTop, _clipRight, _clipBottom); - _drawImageMaskedShader->SetTextureMask(textureMask); - _drawImageMaskedShader->SetTextureColour(textureColour); - _drawImageMaskedShader->Draw(left, top, right, bottom); + DrawImageMaskedCommand command = {}; + + command.clip[0] = _clipLeft; + command.clip[1] = _clipTop; + command.clip[2] = _clipRight; + command.clip[3] = _clipBottom; + + command.texMask = textureMask; + command.texColour = textureColour; + + command.bounds[0] = left; + command.bounds[1] = top; + command.bounds[2] = right; + command.bounds[3] = bottom; + + _commandBuffers.maskedImages.push_back(command); + FlushCommandBuffers(); } void OpenGLDrawingContext::DrawSpriteSolid(uint32 image, sint32 x, sint32 y, uint8 colour) @@ -754,13 +824,25 @@ void OpenGLDrawingContext::DrawSpriteSolid(uint32 image, sint32 x, sint32 y, uin right += _offsetX; bottom += _offsetY; - _drawImageShader->Use(); - _drawImageShader->SetClip(_clipLeft, _clipTop, _clipRight, _clipBottom); - _drawImageShader->SetTexture(texture); - _drawImageShader->SetFlags(1); - _drawImageShader->SetColour(paletteColour); - _drawImageShader->Draw(left, top, right, bottom); - _drawImageShader->SetFlags(0); + DrawImageCommand command = {}; + + command.flags = 1; + command.colour = paletteColour; + + command.clip[0] = _clipLeft; + command.clip[1] = _clipTop; + command.clip[2] = _clipRight; + command.clip[3] = _clipBottom; + + command.texColour = texture; + + command.bounds[0] = left; + command.bounds[1] = top; + command.bounds[2] = right; + command.bounds[3] = bottom; + + _commandBuffers.images.push_back(command); + FlushCommandBuffers(); } void OpenGLDrawingContext::DrawGlyph(uint32 image, sint32 x, sint32 y, uint8 * palette) @@ -794,11 +876,81 @@ void OpenGLDrawingContext::DrawGlyph(uint32 image, sint32 x, sint32 y, uint8 * p right += _offsetX; bottom += _offsetY; - _drawImageShader->Use(); - _drawImageShader->SetClip(_clipLeft, _clipTop, _clipRight, _clipBottom); - _drawImageShader->SetTexture(texture); - _drawImageShader->Draw(left, top, right, bottom); - _drawImageShader->SetFlags(0); + DrawImageCommand command = {}; + + command.flags = 0; + + command.clip[0] = _clipLeft; + command.clip[1] = _clipTop; + command.clip[2] = _clipRight; + command.clip[3] = _clipBottom; + + command.texColour = texture; + + command.bounds[0] = left; + command.bounds[1] = top; + command.bounds[2] = right; + command.bounds[3] = bottom; + + _commandBuffers.images.push_back(command); + FlushCommandBuffers(); +} + +void OpenGLDrawingContext::FlushCommandBuffers() { + FlushRectangles(); + FlushLines(); + FlushImages(); + FlushMaskedImages(); +} + +void OpenGLDrawingContext::FlushRectangles() { + for (const auto& command : _commandBuffers.rectangles) { + _fillRectShader->Use(); + _fillRectShader->SetFlags(command.flags); + _fillRectShader->SetSourceFramebuffer(command.sourceFramebuffer); + _fillRectShader->SetColour(0, command.colours[0]); + _fillRectShader->SetColour(1, command.colours[1]); + _fillRectShader->SetClip(command.clip[0], command.clip[1], command.clip[2], command.clip[3]); + _fillRectShader->Draw(command.bounds[0], command.bounds[1], command.bounds[2], command.bounds[3]); + } + + _commandBuffers.rectangles.clear(); +} + +void OpenGLDrawingContext::FlushLines() { + for (const auto& command : _commandBuffers.lines) { + _drawLineShader->Use(); + _drawLineShader->SetColour(command.colour); + _drawLineShader->SetClip(command.clip[0], command.clip[1], command.clip[2], command.clip[3]); + _drawLineShader->Draw(command.pos[0], command.pos[1], command.pos[2], command.pos[3]); + } + + _commandBuffers.lines.clear(); +} + +void OpenGLDrawingContext::FlushImages() { + for (const auto& command : _commandBuffers.images) { + _drawImageShader->Use(); + _drawImageShader->SetClip(_clipLeft, _clipTop, _clipRight, _clipBottom); + _drawImageShader->SetTexture(command.texColour); + _drawImageShader->SetFlags(command.flags); + _drawImageShader->SetColour(command.colour); + _drawImageShader->Draw(command.bounds[0], command.bounds[1], command.bounds[2], command.bounds[3]); + } + + _commandBuffers.images.clear(); +} + +void OpenGLDrawingContext::FlushMaskedImages() { + for (const auto& command : _commandBuffers.maskedImages) { + _drawImageMaskedShader->Use(); + _drawImageMaskedShader->SetClip(command.clip[0], command.clip[1], command.clip[2], command.clip[3]); + _drawImageMaskedShader->SetTextureMask(command.texMask); + _drawImageMaskedShader->SetTextureColour(command.texColour); + _drawImageMaskedShader->Draw(command.bounds[0], command.bounds[1], command.bounds[2], command.bounds[3]); + } + + _commandBuffers.maskedImages.clear(); } void OpenGLDrawingContext::SetDPI(rct_drawpixelinfo * dpi) From 09b07174e370cb9e2254f44af30fc02ca34c7b34 Mon Sep 17 00:00:00 2001 From: Alexander Overvoorde Date: Thu, 21 Jul 2016 22:15:41 +0200 Subject: [PATCH 02/24] Change command buffer flushes to only be called when necessary This currently breaks sprite draw order, I do not know why --- src/drawing/engines/opengl/OpenGLDrawingEngine.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp index 84f66ccfd6..6d52a9b854 100644 --- a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp +++ b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp @@ -566,6 +566,7 @@ void OpenGLDrawingContext::FillRect(uint32 colour, sint32 left, sint32 top, sint bottom += _offsetY; DrawRectCommand command = {}; + command.sourceFramebuffer = _fillRectShader->GetSourceFramebuffer(); vec4f paletteColour[2]; @@ -614,6 +615,8 @@ void OpenGLDrawingContext::FillRect(uint32 colour, sint32 left, sint32 top, sint command.bounds[3] = bottom + 1; _commandBuffers.rectangles.push_back(command); + + // Must be rendered in order, depends on already rendered contents FlushCommandBuffers(); } @@ -627,6 +630,7 @@ void OpenGLDrawingContext::DrawLine(uint32 colour, sint32 x1, sint32 y1, sint32 vec4f paletteColour = _engine->GLPalette[colour & 0xFF]; DrawLineCommand command = {}; + command.colour = paletteColour; command.clip[0] = _clipLeft; @@ -640,6 +644,8 @@ void OpenGLDrawingContext::DrawLine(uint32 colour, sint32 x1, sint32 y1, sint32 command.pos[3] = y2; _commandBuffers.lines.push_back(command); + + // Must be rendered in order right now, because it does not yet use depth FlushCommandBuffers(); } @@ -725,7 +731,6 @@ void OpenGLDrawingContext::DrawSprite(uint32 image, sint32 x, sint32 y, uint32 t command.bounds[3] = bottom; _commandBuffers.images.push_back(command); - FlushCommandBuffers(); } void OpenGLDrawingContext::DrawSpriteRawMasked(sint32 x, sint32 y, uint32 maskImage, uint32 colourImage) @@ -788,7 +793,6 @@ void OpenGLDrawingContext::DrawSpriteRawMasked(sint32 x, sint32 y, uint32 maskIm command.bounds[3] = bottom; _commandBuffers.maskedImages.push_back(command); - FlushCommandBuffers(); } void OpenGLDrawingContext::DrawSpriteSolid(uint32 image, sint32 x, sint32 y, uint8 colour) @@ -842,7 +846,6 @@ void OpenGLDrawingContext::DrawSpriteSolid(uint32 image, sint32 x, sint32 y, uin command.bounds[3] = bottom; _commandBuffers.images.push_back(command); - FlushCommandBuffers(); } void OpenGLDrawingContext::DrawGlyph(uint32 image, sint32 x, sint32 y, uint8 * palette) @@ -893,12 +896,12 @@ void OpenGLDrawingContext::DrawGlyph(uint32 image, sint32 x, sint32 y, uint8 * p command.bounds[3] = bottom; _commandBuffers.images.push_back(command); - FlushCommandBuffers(); } void OpenGLDrawingContext::FlushCommandBuffers() { FlushRectangles(); FlushLines(); + FlushImages(); FlushMaskedImages(); } From afd83fa13d09315814327000b57e0027f192870f Mon Sep 17 00:00:00 2001 From: Alexander Overvoorde Date: Fri, 22 Jul 2016 22:20:16 +0200 Subject: [PATCH 03/24] Fix clipping in FlushImages --- src/drawing/engines/opengl/OpenGLDrawingEngine.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp index 6d52a9b854..c5e3bace6a 100644 --- a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp +++ b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp @@ -793,6 +793,9 @@ void OpenGLDrawingContext::DrawSpriteRawMasked(sint32 x, sint32 y, uint32 maskIm command.bounds[3] = bottom; _commandBuffers.maskedImages.push_back(command); + + // Currently not properly ordered with regular images yet + FlushCommandBuffers(); } void OpenGLDrawingContext::DrawSpriteSolid(uint32 image, sint32 x, sint32 y, uint8 colour) @@ -934,7 +937,7 @@ void OpenGLDrawingContext::FlushLines() { void OpenGLDrawingContext::FlushImages() { for (const auto& command : _commandBuffers.images) { _drawImageShader->Use(); - _drawImageShader->SetClip(_clipLeft, _clipTop, _clipRight, _clipBottom); + _drawImageShader->SetClip(command.clip[0], command.clip[1], command.clip[2], command.clip[3]); _drawImageShader->SetTexture(command.texColour); _drawImageShader->SetFlags(command.flags); _drawImageShader->SetColour(command.colour); From f8f996dfd6ac0b6e4db93b06f8bcb2a42954c816 Mon Sep 17 00:00:00 2001 From: Alexander Overvoorde Date: Fri, 22 Jul 2016 22:58:52 +0200 Subject: [PATCH 04/24] Fix indentation --- src/drawing/engines/opengl/DrawCommands.h | 34 +-- .../engines/opengl/OpenGLDrawingEngine.cpp | 270 +++++++++--------- 2 files changed, 153 insertions(+), 151 deletions(-) diff --git a/src/drawing/engines/opengl/DrawCommands.h b/src/drawing/engines/opengl/DrawCommands.h index 87a3853780..4107104924 100644 --- a/src/drawing/engines/opengl/DrawCommands.h +++ b/src/drawing/engines/opengl/DrawCommands.h @@ -21,30 +21,30 @@ #include "GLSLTypes.h" struct DrawRectCommand { - uint32 flags; - GLuint sourceFramebuffer; - vec4f colours[2]; - sint32 clip[4]; - sint32 bounds[4]; + uint32 flags; + GLuint sourceFramebuffer; + vec4f colours[2]; + sint32 clip[4]; + sint32 bounds[4]; }; struct DrawLineCommand { - vec4f colour; - sint32 clip[4]; - sint32 pos[4]; + vec4f colour; + sint32 clip[4]; + sint32 pos[4]; }; struct DrawImageCommand { - uint32 flags; - vec4f colour; - sint32 clip[4]; - GLuint texColour; - sint32 bounds[4]; + uint32 flags; + vec4f colour; + sint32 clip[4]; + GLuint texColour; + sint32 bounds[4]; }; struct DrawImageMaskedCommand { - sint32 clip[4]; - GLuint texMask; - GLuint texColour; - sint32 bounds[4]; + sint32 clip[4]; + GLuint texMask; + GLuint texColour; + sint32 bounds[4]; }; \ No newline at end of file diff --git a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp index c5e3bace6a..ed438d5eac 100644 --- a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp +++ b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp @@ -192,12 +192,12 @@ private: sint32 _clipRight; sint32 _clipBottom; - struct { - std::vector rectangles; - std::vector lines; - std::vector images; - std::vector maskedImages; - } _commandBuffers; + struct { + std::vector rectangles; + std::vector lines; + std::vector images; + std::vector maskedImages; + } _commandBuffers; public: explicit OpenGLDrawingContext(OpenGLDrawingEngine * engine); @@ -218,12 +218,12 @@ public: void DrawSpriteSolid(uint32 image, sint32 x, sint32 y, uint8 colour) override; void DrawGlyph(uint32 image, sint32 x, sint32 y, uint8 * palette) override; - void FlushCommandBuffers(); + void FlushCommandBuffers(); - void FlushRectangles(); - void FlushLines(); - void FlushImages(); - void FlushMaskedImages(); + void FlushRectangles(); + void FlushLines(); + void FlushImages(); + void FlushMaskedImages(); void SetDPI(rct_drawpixelinfo * dpi); }; @@ -340,13 +340,13 @@ public: gfx_draw_pickedup_peep(&_bitsDPI); - _drawingContext->FlushCommandBuffers(); + _drawingContext->FlushCommandBuffers(); _swapFramebuffer->SwapCopy(); rct2_draw(&_bitsDPI); } - _drawingContext->FlushCommandBuffers(); + _drawingContext->FlushCommandBuffers(); // Scale up to window _screenFramebuffer->Bind(); @@ -530,7 +530,7 @@ void OpenGLDrawingContext::Initialise() void OpenGLDrawingContext::Resize(sint32 width, sint32 height) { - FlushCommandBuffers(); + FlushCommandBuffers(); _drawImageShader->Use(); _drawImageShader->SetScreenSize(width, height); @@ -544,7 +544,7 @@ void OpenGLDrawingContext::Resize(sint32 width, sint32 height) void OpenGLDrawingContext::ResetPalette() { - FlushCommandBuffers(); + FlushCommandBuffers(); _textureCache->SetPalette(_engine->Palette); _drawImageShader->Use(); @@ -565,9 +565,9 @@ void OpenGLDrawingContext::FillRect(uint32 colour, sint32 left, sint32 top, sint right += _offsetX; bottom += _offsetY; - DrawRectCommand command = {}; + DrawRectCommand command = {}; - command.sourceFramebuffer = _fillRectShader->GetSourceFramebuffer(); + command.sourceFramebuffer = _fillRectShader->GetSourceFramebuffer(); vec4f paletteColour[2]; paletteColour[0] = _engine->GLPalette[(colour >> 0) & 0xFF]; @@ -576,7 +576,7 @@ void OpenGLDrawingContext::FillRect(uint32 colour, sint32 left, sint32 top, sint { paletteColour[1].a = 0; - command.flags = 0; + command.flags = 0; } else if (colour & 0x2000000) { @@ -593,31 +593,31 @@ void OpenGLDrawingContext::FillRect(uint32 colour, sint32 left, sint32 top, sint paletteColour[1] = paletteColour[0]; GLuint srcTexture = _engine->SwapCopyReturningSourceTexture(); - command.flags = 1; - command.sourceFramebuffer = srcTexture; + command.flags = 1; + command.sourceFramebuffer = srcTexture; } else { - command.flags = 0; + command.flags = 0; } - command.colours[0] = paletteColour[0]; - command.colours[1] = paletteColour[1]; + command.colours[0] = paletteColour[0]; + command.colours[1] = paletteColour[1]; - command.clip[0] = _clipLeft; - command.clip[1] = _clipTop; - command.clip[2] = _clipRight; - command.clip[3] = _clipBottom; + command.clip[0] = _clipLeft; + command.clip[1] = _clipTop; + command.clip[2] = _clipRight; + command.clip[3] = _clipBottom; - command.bounds[0] = left; - command.bounds[1] = top; - command.bounds[2] = right + 1; - command.bounds[3] = bottom + 1; + command.bounds[0] = left; + command.bounds[1] = top; + command.bounds[2] = right + 1; + command.bounds[3] = bottom + 1; - _commandBuffers.rectangles.push_back(command); + _commandBuffers.rectangles.push_back(command); - // Must be rendered in order, depends on already rendered contents - FlushCommandBuffers(); + // Must be rendered in order, depends on already rendered contents + FlushCommandBuffers(); } void OpenGLDrawingContext::DrawLine(uint32 colour, sint32 x1, sint32 y1, sint32 x2, sint32 y2) @@ -628,25 +628,25 @@ void OpenGLDrawingContext::DrawLine(uint32 colour, sint32 x1, sint32 y1, sint32 y2 += _offsetY; vec4f paletteColour = _engine->GLPalette[colour & 0xFF]; - - DrawLineCommand command = {}; + + DrawLineCommand command = {}; - command.colour = paletteColour; + command.colour = paletteColour; - command.clip[0] = _clipLeft; - command.clip[1] = _clipTop; - command.clip[2] = _clipRight; - command.clip[3] = _clipBottom; + command.clip[0] = _clipLeft; + command.clip[1] = _clipTop; + command.clip[2] = _clipRight; + command.clip[3] = _clipBottom; - command.pos[0] = x1; - command.pos[1] = y1; - command.pos[2] = x2; - command.pos[3] = y2; + command.pos[0] = x1; + command.pos[1] = y1; + command.pos[2] = x2; + command.pos[3] = y2; - _commandBuffers.lines.push_back(command); + _commandBuffers.lines.push_back(command); - // Must be rendered in order right now, because it does not yet use depth - FlushCommandBuffers(); + // Must be rendered in order right now, because it does not yet use depth + FlushCommandBuffers(); } void OpenGLDrawingContext::DrawSprite(uint32 image, sint32 x, sint32 y, uint32 tertiaryColour) @@ -716,21 +716,21 @@ void OpenGLDrawingContext::DrawSprite(uint32 image, sint32 x, sint32 y, uint32 t DrawImageCommand command = {}; - command.flags = 0; + command.flags = 0; - command.clip[0] = _clipLeft; - command.clip[1] = _clipTop; - command.clip[2] = _clipRight; - command.clip[3] = _clipBottom; + command.clip[0] = _clipLeft; + command.clip[1] = _clipTop; + command.clip[2] = _clipRight; + command.clip[3] = _clipBottom; - command.texColour = texture; + command.texColour = texture; - command.bounds[0] = left; - command.bounds[1] = top; - command.bounds[2] = right; - command.bounds[3] = bottom; + command.bounds[0] = left; + command.bounds[1] = top; + command.bounds[2] = right; + command.bounds[3] = bottom; - _commandBuffers.images.push_back(command); + _commandBuffers.images.push_back(command); } void OpenGLDrawingContext::DrawSpriteRawMasked(sint32 x, sint32 y, uint32 maskImage, uint32 colourImage) @@ -777,22 +777,22 @@ void OpenGLDrawingContext::DrawSpriteRawMasked(sint32 x, sint32 y, uint32 maskIm right += _clipLeft; bottom += _clipTop; - DrawImageMaskedCommand command = {}; + DrawImageMaskedCommand command = {}; - command.clip[0] = _clipLeft; - command.clip[1] = _clipTop; - command.clip[2] = _clipRight; - command.clip[3] = _clipBottom; + command.clip[0] = _clipLeft; + command.clip[1] = _clipTop; + command.clip[2] = _clipRight; + command.clip[3] = _clipBottom; - command.texMask = textureMask; - command.texColour = textureColour; + command.texMask = textureMask; + command.texColour = textureColour; - command.bounds[0] = left; - command.bounds[1] = top; - command.bounds[2] = right; - command.bounds[3] = bottom; + command.bounds[0] = left; + command.bounds[1] = top; + command.bounds[2] = right; + command.bounds[3] = bottom; - _commandBuffers.maskedImages.push_back(command); + _commandBuffers.maskedImages.push_back(command); // Currently not properly ordered with regular images yet FlushCommandBuffers(); @@ -831,24 +831,24 @@ void OpenGLDrawingContext::DrawSpriteSolid(uint32 image, sint32 x, sint32 y, uin right += _offsetX; bottom += _offsetY; - DrawImageCommand command = {}; + DrawImageCommand command = {}; - command.flags = 1; - command.colour = paletteColour; + command.flags = 1; + command.colour = paletteColour; - command.clip[0] = _clipLeft; - command.clip[1] = _clipTop; - command.clip[2] = _clipRight; - command.clip[3] = _clipBottom; + command.clip[0] = _clipLeft; + command.clip[1] = _clipTop; + command.clip[2] = _clipRight; + command.clip[3] = _clipBottom; - command.texColour = texture; + command.texColour = texture; - command.bounds[0] = left; - command.bounds[1] = top; - command.bounds[2] = right; - command.bounds[3] = bottom; + command.bounds[0] = left; + command.bounds[1] = top; + command.bounds[2] = right; + command.bounds[3] = bottom; - _commandBuffers.images.push_back(command); + _commandBuffers.images.push_back(command); } void OpenGLDrawingContext::DrawGlyph(uint32 image, sint32 x, sint32 y, uint8 * palette) @@ -882,81 +882,83 @@ void OpenGLDrawingContext::DrawGlyph(uint32 image, sint32 x, sint32 y, uint8 * p right += _offsetX; bottom += _offsetY; - DrawImageCommand command = {}; + DrawImageCommand command = {}; - command.flags = 0; + command.flags = 0; - command.clip[0] = _clipLeft; - command.clip[1] = _clipTop; - command.clip[2] = _clipRight; - command.clip[3] = _clipBottom; + command.clip[0] = _clipLeft; + command.clip[1] = _clipTop; + command.clip[2] = _clipRight; + command.clip[3] = _clipBottom; - command.texColour = texture; + command.texColour = texture; - command.bounds[0] = left; - command.bounds[1] = top; - command.bounds[2] = right; - command.bounds[3] = bottom; + command.bounds[0] = left; + command.bounds[1] = top; + command.bounds[2] = right; + command.bounds[3] = bottom; - _commandBuffers.images.push_back(command); + _commandBuffers.images.push_back(command); } void OpenGLDrawingContext::FlushCommandBuffers() { - FlushRectangles(); - FlushLines(); + FlushRectangles(); + FlushLines(); - FlushImages(); - FlushMaskedImages(); + FlushImages(); + FlushMaskedImages(); } void OpenGLDrawingContext::FlushRectangles() { - for (const auto& command : _commandBuffers.rectangles) { - _fillRectShader->Use(); - _fillRectShader->SetFlags(command.flags); - _fillRectShader->SetSourceFramebuffer(command.sourceFramebuffer); - _fillRectShader->SetColour(0, command.colours[0]); - _fillRectShader->SetColour(1, command.colours[1]); - _fillRectShader->SetClip(command.clip[0], command.clip[1], command.clip[2], command.clip[3]); - _fillRectShader->Draw(command.bounds[0], command.bounds[1], command.bounds[2], command.bounds[3]); - } + for (const auto& command : _commandBuffers.rectangles) { + _fillRectShader->Use(); + _fillRectShader->SetFlags(command.flags); + _fillRectShader->SetSourceFramebuffer(command.sourceFramebuffer); + _fillRectShader->SetColour(0, command.colours[0]); + _fillRectShader->SetColour(1, command.colours[1]); + _fillRectShader->SetClip(command.clip[0], command.clip[1], command.clip[2], command.clip[3]); + _fillRectShader->Draw(command.bounds[0], command.bounds[1], command.bounds[2], command.bounds[3]); + } - _commandBuffers.rectangles.clear(); + _commandBuffers.rectangles.clear(); } void OpenGLDrawingContext::FlushLines() { - for (const auto& command : _commandBuffers.lines) { - _drawLineShader->Use(); - _drawLineShader->SetColour(command.colour); - _drawLineShader->SetClip(command.clip[0], command.clip[1], command.clip[2], command.clip[3]); - _drawLineShader->Draw(command.pos[0], command.pos[1], command.pos[2], command.pos[3]); - } + for (const auto& command : _commandBuffers.lines) { + _drawLineShader->Use(); + _drawLineShader->SetColour(command.colour); + _drawLineShader->SetClip(command.clip[0], command.clip[1], command.clip[2], command.clip[3]); + _drawLineShader->Draw(command.pos[0], command.pos[1], command.pos[2], command.pos[3]); + } - _commandBuffers.lines.clear(); + _commandBuffers.lines.clear(); } void OpenGLDrawingContext::FlushImages() { - for (const auto& command : _commandBuffers.images) { - _drawImageShader->Use(); - _drawImageShader->SetClip(command.clip[0], command.clip[1], command.clip[2], command.clip[3]); - _drawImageShader->SetTexture(command.texColour); - _drawImageShader->SetFlags(command.flags); - _drawImageShader->SetColour(command.colour); - _drawImageShader->Draw(command.bounds[0], command.bounds[1], command.bounds[2], command.bounds[3]); - } + // DEBUG: disabled until new array based texture cache is finished + /*for (const auto& command : _commandBuffers.images) { + _drawImageShader->Use(); + _drawImageShader->SetClip(command.clip[0], command.clip[1], command.clip[2], command.clip[3]); + _drawImageShader->SetTexture(command.texColour); + _drawImageShader->SetFlags(command.flags); + _drawImageShader->SetColour(command.colour); + _drawImageShader->Draw(command.bounds[0], command.bounds[1], command.bounds[2], command.bounds[3]); + }*/ - _commandBuffers.images.clear(); + _commandBuffers.images.clear(); } void OpenGLDrawingContext::FlushMaskedImages() { - for (const auto& command : _commandBuffers.maskedImages) { - _drawImageMaskedShader->Use(); - _drawImageMaskedShader->SetClip(command.clip[0], command.clip[1], command.clip[2], command.clip[3]); - _drawImageMaskedShader->SetTextureMask(command.texMask); - _drawImageMaskedShader->SetTextureColour(command.texColour); - _drawImageMaskedShader->Draw(command.bounds[0], command.bounds[1], command.bounds[2], command.bounds[3]); - } + // DEBUG: disabled until new array based texture cache is finished + /*for (const auto& command : _commandBuffers.maskedImages) { + _drawImageMaskedShader->Use(); + _drawImageMaskedShader->SetClip(command.clip[0], command.clip[1], command.clip[2], command.clip[3]); + _drawImageMaskedShader->SetTextureMask(command.texMask); + _drawImageMaskedShader->SetTextureColour(command.texColour); + _drawImageMaskedShader->Draw(command.bounds[0], command.bounds[1], command.bounds[2], command.bounds[3]); + }*/ - _commandBuffers.maskedImages.clear(); + _commandBuffers.maskedImages.clear(); } void OpenGLDrawingContext::SetDPI(rct_drawpixelinfo * dpi) From 84f2a8c17cd35af1a3a5905fae289c500b5a72f8 Mon Sep 17 00:00:00 2001 From: Alexander Overvoorde Date: Fri, 22 Jul 2016 23:49:55 +0200 Subject: [PATCH 05/24] Rewrite texture cache to use array texture --- data/shaders/drawimage.frag | 14 ++- .../engines/opengl/CopyFramebufferShader.cpp | 2 +- src/drawing/engines/opengl/DrawCommands.h | 6 +- .../engines/opengl/DrawImageMaskedShader.cpp | 4 +- .../engines/opengl/DrawImageShader.cpp | 10 +- src/drawing/engines/opengl/DrawImageShader.h | 5 +- src/drawing/engines/opengl/FillRectShader.cpp | 2 +- src/drawing/engines/opengl/OpenGLAPI.cpp | 12 +- src/drawing/engines/opengl/OpenGLAPI.h | 10 +- .../engines/opengl/OpenGLDrawingEngine.cpp | 30 +++-- src/drawing/engines/opengl/TextureCache.cpp | 110 +++++++++--------- src/drawing/engines/opengl/TextureCache.h | 32 ++++- 12 files changed, 147 insertions(+), 90 deletions(-) diff --git a/data/shaders/drawimage.frag b/data/shaders/drawimage.frag index c07dba6ea6..4566f0f7fe 100644 --- a/data/shaders/drawimage.frag +++ b/data/shaders/drawimage.frag @@ -1,10 +1,12 @@ #version 150 -uniform ivec4 uClip; -uniform int uFlags; -uniform vec4 uColour; -uniform usampler2D uTexture; -uniform vec4 uPalette[256]; +uniform ivec4 uClip; +uniform int uFlags; +uniform vec4 uColour; +uniform usampler2DArray uTexture; +uniform vec4 uPalette[256]; +uniform vec2 uTexCoordScale; +uniform int uTexSlot; in vec2 fPosition; in vec2 fTextureCoordinate; @@ -19,7 +21,7 @@ void main() discard; } - vec4 texel = uPalette[texture(uTexture, fTextureCoordinate).r]; + vec4 texel = uPalette[texture(uTexture, vec3(fTextureCoordinate * uTexCoordScale, float(uTexSlot))).r]; if ((uFlags & 1) != 0) { oColour = vec4(uColour.rgb, uColour.a * texel.a); diff --git a/src/drawing/engines/opengl/CopyFramebufferShader.cpp b/src/drawing/engines/opengl/CopyFramebufferShader.cpp index b188f26128..605ef33c68 100644 --- a/src/drawing/engines/opengl/CopyFramebufferShader.cpp +++ b/src/drawing/engines/opengl/CopyFramebufferShader.cpp @@ -71,7 +71,7 @@ void CopyFramebufferShader::SetTextureCoordinates(sint32 left, sint32 top, sint3 void CopyFramebufferShader::SetTexture(GLuint texture) { - OpenGLAPI::SetTexture2D(0, texture); + OpenGLAPI::SetTexture(0, GL_TEXTURE_2D, texture); } void CopyFramebufferShader::Draw() diff --git a/src/drawing/engines/opengl/DrawCommands.h b/src/drawing/engines/opengl/DrawCommands.h index 4107104924..86b7e36544 100644 --- a/src/drawing/engines/opengl/DrawCommands.h +++ b/src/drawing/engines/opengl/DrawCommands.h @@ -38,13 +38,13 @@ struct DrawImageCommand { uint32 flags; vec4f colour; sint32 clip[4]; - GLuint texColour; + CachedTextureInfo texColour; sint32 bounds[4]; }; struct DrawImageMaskedCommand { sint32 clip[4]; - GLuint texMask; - GLuint texColour; + CachedTextureInfo texMask; + CachedTextureInfo texColour; sint32 bounds[4]; }; \ No newline at end of file diff --git a/src/drawing/engines/opengl/DrawImageMaskedShader.cpp b/src/drawing/engines/opengl/DrawImageMaskedShader.cpp index f5e2e2d5c1..e785eb9d78 100644 --- a/src/drawing/engines/opengl/DrawImageMaskedShader.cpp +++ b/src/drawing/engines/opengl/DrawImageMaskedShader.cpp @@ -75,12 +75,12 @@ void DrawImageMaskedShader::SetBounds(sint32 left, sint32 top, sint32 right, sin void DrawImageMaskedShader::SetTextureMask(GLuint texture) { - OpenGLAPI::SetTexture2D(0, texture); + OpenGLAPI::SetTexture(0, GL_TEXTURE_2D, texture); } void DrawImageMaskedShader::SetTextureColour(GLuint texture) { - OpenGLAPI::SetTexture2D(1, texture); + OpenGLAPI::SetTexture(1, GL_TEXTURE_2D, texture); } void DrawImageMaskedShader::SetPalette(const vec4f *glPalette) diff --git a/src/drawing/engines/opengl/DrawImageShader.cpp b/src/drawing/engines/opengl/DrawImageShader.cpp index 94d7358309..d9346ce3d3 100644 --- a/src/drawing/engines/opengl/DrawImageShader.cpp +++ b/src/drawing/engines/opengl/DrawImageShader.cpp @@ -57,6 +57,8 @@ void DrawImageShader::GetLocations() uColour = GetUniformLocation("uColour"); uFlags = GetUniformLocation("uFlags"); uPalette = GetUniformLocation("uPalette"); + uTexCoordScale = GetUniformLocation("uTexCoordScale"); + uTexSlot = GetUniformLocation("uTexSlot"); vIndex = GetAttributeLocation("vIndex"); } @@ -81,9 +83,13 @@ void DrawImageShader::SetTextureCoordinates(sint32 left, sint32 top, sint32 righ glUniform4i(uTextureCoordinates, left, top, right, bottom); } -void DrawImageShader::SetTexture(GLuint texture) +void DrawImageShader::SetTextureCoordScale(float width, float height) { + glUniform2f(uTexCoordScale, width, height); +} + +void DrawImageShader::SetTextureSlot(GLuint slot) { - OpenGLAPI::SetTexture2D(0, texture); + glUniform1i(uTexSlot, slot); } void DrawImageShader::SetColour(vec4f colour) diff --git a/src/drawing/engines/opengl/DrawImageShader.h b/src/drawing/engines/opengl/DrawImageShader.h index 09171debd9..ca955842db 100644 --- a/src/drawing/engines/opengl/DrawImageShader.h +++ b/src/drawing/engines/opengl/DrawImageShader.h @@ -31,6 +31,8 @@ private: GLuint uColour; GLuint uFlags; GLuint uPalette; + GLuint uTexCoordScale; + GLuint uTexSlot; GLuint vIndex; @@ -47,7 +49,8 @@ public: 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 SetTexture(GLuint texture); + void SetTextureCoordScale(float width, float height); + void SetTextureSlot(GLuint slot); void SetColour(vec4f colour); void SetFlags(uint32 flags); void SetPalette(const vec4f *glPalette); diff --git a/src/drawing/engines/opengl/FillRectShader.cpp b/src/drawing/engines/opengl/FillRectShader.cpp index 3bf5bb363c..c6fe3542d8 100644 --- a/src/drawing/engines/opengl/FillRectShader.cpp +++ b/src/drawing/engines/opengl/FillRectShader.cpp @@ -88,7 +88,7 @@ void FillRectShader::SetColour(int index, vec4f colour) void FillRectShader::SetSourceFramebuffer(GLuint texture) { _sourceFramebuffer = texture; - OpenGLAPI::SetTexture2D(0, texture); + OpenGLAPI::SetTexture(0, GL_TEXTURE_2D, texture); } void FillRectShader::Draw(sint32 left, sint32 top, sint32 right, sint32 bottom) diff --git a/src/drawing/engines/opengl/OpenGLAPI.cpp b/src/drawing/engines/opengl/OpenGLAPI.cpp index 8683262160..fc28162e97 100644 --- a/src/drawing/engines/opengl/OpenGLAPI.cpp +++ b/src/drawing/engines/opengl/OpenGLAPI.cpp @@ -68,6 +68,7 @@ static const char * TryLoadAllProcAddresses() SetupOpenGLFunction(glTexImage2D); SetupOpenGLFunction(glTexParameteri); SetupOpenGLFunction(glViewport); + SetupOpenGLFunction(glTexSubImage3D); // 2.0+ functions SetupOpenGLFunction(glAttachShader); @@ -100,12 +101,15 @@ static const char * TryLoadAllProcAddresses() SetupOpenGLFunction(glShaderSource); SetupOpenGLFunction(glUniform1i); SetupOpenGLFunction(glUniform2i); + SetupOpenGLFunction(glUniform2f); SetupOpenGLFunction(glUniform4f); SetupOpenGLFunction(glUniform4i); SetupOpenGLFunction(glUniform4fv); SetupOpenGLFunction(glUseProgram); SetupOpenGLFunction(glVertexAttribIPointer); SetupOpenGLFunction(glVertexAttribPointer); + SetupOpenGLFunction(glTexStorage3D); + SetupOpenGLFunction(glDebugMessageCallback); return nullptr; } @@ -118,13 +122,13 @@ namespace OpenGLState GLuint CurrentProgram = UINT32_MAX; } -void OpenGLAPI::SetTexture2D(uint16 index, GLuint texture) +void OpenGLAPI::SetTexture(uint16 index, GLenum type, GLuint texture) { if (OpenGLState::ActiveTexture != index) { glActiveTexture(GL_TEXTURE0 + index); } - glBindTexture(GL_TEXTURE_2D, texture); + glBindTexture(type, texture); } bool OpenGLAPI::Initialise() @@ -140,4 +144,8 @@ bool OpenGLAPI::Initialise() return true; } +void APIENTRY OpenGLAPI::DebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* msg, const void* userData) { + Console::Error::WriteLine(msg); +} + #endif /* DISABLE_OPENGL */ diff --git a/src/drawing/engines/opengl/OpenGLAPI.h b/src/drawing/engines/opengl/OpenGLAPI.h index 5fa377bd9c..3da30a2286 100644 --- a/src/drawing/engines/opengl/OpenGLAPI.h +++ b/src/drawing/engines/opengl/OpenGLAPI.h @@ -40,6 +40,7 @@ #define glTexImage2D __static__glTexImage2D #define glTexParameteri __static__glTexParameteri #define glViewport __static__glViewport +#define glTexSubImage3D __static__glTexSubImage3D #endif @@ -67,6 +68,7 @@ #undef glTexImage2D #undef glTexParameteri #undef glViewport +#undef glTexSubImage3D // 1.1 function signatures typedef void (APIENTRYP PFNGLBEGINPROC )(GLenum mode); @@ -118,6 +120,7 @@ GLAPI_DECL PFNGLREADPIXELSPROC glReadPixels GLAP GLAPI_DECL PFNGLTEXIMAGE2DPROC glTexImage2D GLAPI_SET; GLAPI_DECL PFNGLTEXPARAMETERIPROC glTexParameteri GLAPI_SET; GLAPI_DECL PFNGLVIEWPORTPROC glViewport GLAPI_SET; +GLAPI_DECL PFNGLTEXSUBIMAGE3DPROC glTexSubImage3D GLAPI_SET; // 2.0+ function pointers GLAPI_DECL PFNGLATTACHSHADERPROC glAttachShader GLAPI_SET; @@ -150,12 +153,15 @@ GLAPI_DECL PFNGLLINKPROGRAMPROC glLinkProgram GLAP GLAPI_DECL PFNGLSHADERSOURCEPROC glShaderSource GLAPI_SET; GLAPI_DECL PFNGLUNIFORM1IPROC glUniform1i GLAPI_SET; GLAPI_DECL PFNGLUNIFORM2IPROC glUniform2i GLAPI_SET; +GLAPI_DECL PFNGLUNIFORM2FPROC glUniform2f GLAPI_SET; GLAPI_DECL PFNGLUNIFORM4FPROC glUniform4f GLAPI_SET; GLAPI_DECL PFNGLUNIFORM4IPROC glUniform4i GLAPI_SET; GLAPI_DECL PFNGLUNIFORM4FVPROC glUniform4fv GLAPI_SET; GLAPI_DECL PFNGLUSEPROGRAMPROC glUseProgram GLAPI_SET; GLAPI_DECL PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer GLAPI_SET; GLAPI_DECL PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer GLAPI_SET; +GLAPI_DECL PFNGLTEXSTORAGE3DPROC glTexStorage3D GLAPI_SET; +GLAPI_DECL PFNGLDEBUGMESSAGECALLBACKPROC glDebugMessageCallback GLAPI_SET; #endif /* OPENGL_NO_LINK */ @@ -172,7 +178,9 @@ inline void CheckGLError() namespace OpenGLAPI { bool Initialise(); - void SetTexture2D(uint16 index, GLuint texture); + void SetTexture(uint16 index, GLenum type, GLuint texture); + + void APIENTRY DebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* msg, const void* userData); } namespace OpenGLState diff --git a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp index ed438d5eac..b505626e6d 100644 --- a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp +++ b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp @@ -275,6 +275,11 @@ public: SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, requiredVersion.Major); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, requiredVersion.Minor); + +#ifdef DEBUG + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); +#endif + _context = SDL_GL_CreateContext(_window); if (_context == nullptr) { @@ -289,6 +294,10 @@ public: throw Exception("Unable to initialise OpenGL."); } +#ifdef DEBUG + glDebugMessageCallback(OpenGLAPI::DebugCallback, nullptr); +#endif + _drawingContext->Initialise(); glEnable(GL_BLEND); @@ -676,8 +685,6 @@ void OpenGLDrawingContext::DrawSprite(uint32 image, sint32 x, sint32 y, uint32 t } } - GLuint texture = _textureCache->GetOrLoadImageTexture(image); - uint8 zoomLevel = (1 << _dpi->zoom_level); sint32 drawOffsetX = g1Element->x_offset; @@ -723,6 +730,7 @@ void OpenGLDrawingContext::DrawSprite(uint32 image, sint32 x, sint32 y, uint32 t command.clip[2] = _clipRight; command.clip[3] = _clipBottom; + auto texture = _textureCache->GetOrLoadImageTexture(image); command.texColour = texture; command.bounds[0] = left; @@ -738,8 +746,8 @@ void OpenGLDrawingContext::DrawSpriteRawMasked(sint32 x, sint32 y, uint32 maskIm rct_g1_element * g1ElementMask = gfx_get_g1_element(maskImage & 0x7FFFF); rct_g1_element * g1ElementColour = gfx_get_g1_element(colourImage & 0x7FFFF); - GLuint textureMask = _textureCache->GetOrLoadImageTexture(maskImage); - GLuint textureColour = _textureCache->GetOrLoadImageTexture(colourImage); + auto textureMask = _textureCache->GetOrLoadImageTexture(maskImage); + auto textureColour = _textureCache->GetOrLoadImageTexture(colourImage); uint8 zoomLevel = (1 << _dpi->zoom_level); @@ -805,7 +813,7 @@ void OpenGLDrawingContext::DrawSpriteSolid(uint32 image, sint32 x, sint32 y, uin int g1Id = image & 0x7FFFF; rct_g1_element * g1Element = gfx_get_g1_element(g1Id); - GLuint texture = _textureCache->GetOrLoadImageTexture(image); + auto texture = _textureCache->GetOrLoadImageTexture(image); sint32 drawOffsetX = g1Element->x_offset; sint32 drawOffsetY = g1Element->y_offset; @@ -856,7 +864,7 @@ void OpenGLDrawingContext::DrawGlyph(uint32 image, sint32 x, sint32 y, uint8 * p int g1Id = image & 0x7FFFF; rct_g1_element * g1Element = gfx_get_g1_element(g1Id); - GLuint texture = _textureCache->GetOrLoadGlyphTexture(image, palette); + auto texture = _textureCache->GetOrLoadGlyphTexture(image, palette); sint32 drawOffsetX = g1Element->x_offset; sint32 drawOffsetY = g1Element->y_offset; @@ -935,15 +943,17 @@ void OpenGLDrawingContext::FlushLines() { } void OpenGLDrawingContext::FlushImages() { - // DEBUG: disabled until new array based texture cache is finished - /*for (const auto& command : _commandBuffers.images) { + OpenGLAPI::SetTexture(0, GL_TEXTURE_2D_ARRAY, _textureCache->GetArrayTexture()); + + for (const auto& command : _commandBuffers.images) { _drawImageShader->Use(); _drawImageShader->SetClip(command.clip[0], command.clip[1], command.clip[2], command.clip[3]); - _drawImageShader->SetTexture(command.texColour); + _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]); - }*/ + } _commandBuffers.images.clear(); } diff --git a/src/drawing/engines/opengl/TextureCache.cpp b/src/drawing/engines/opengl/TextureCache.cpp index 09c9063612..264ba7ff58 100644 --- a/src/drawing/engines/opengl/TextureCache.cpp +++ b/src/drawing/engines/opengl/TextureCache.cpp @@ -41,32 +41,38 @@ void TextureCache::SetPalette(const SDL_Color * palette) void TextureCache::InvalidateImage(uint32 image) { + InitializeArrayTexture(); + auto kvp = _imageTextureMap.find(image); if (kvp != _imageTextureMap.end()) { - GLuint texture = kvp->second; - glDeleteTextures(1, &texture); - _imageTextureMap.erase(kvp); + _freeSlots.push_back(kvp->second.slot); } } -GLuint TextureCache::GetOrLoadImageTexture(uint32 image) +CachedTextureInfo TextureCache::GetOrLoadImageTexture(uint32 image) { + InitializeArrayTexture(); + auto kvp = _imageTextureMap.find(image & 0x7FFFF); if (kvp != _imageTextureMap.end()) { return kvp->second; } - GLuint texture = LoadImageTexture(image); - _imageTextureMap[image & 0x7FFFF] = texture; + auto cacheInfo = LoadImageTexture(image); + _imageTextureMap[image & 0x7FFFF] = cacheInfo; - return texture; + printf("%d slots left\n", (int) _freeSlots.size()); + + return cacheInfo; } -GLuint TextureCache::GetOrLoadGlyphTexture(uint32 image, uint8 * palette) +CachedTextureInfo TextureCache::GetOrLoadGlyphTexture(uint32 image, uint8 * palette) { + InitializeArrayTexture(); + GlyphId glyphId; glyphId.Image = image; Memory::Copy(&glyphId.Palette, palette, sizeof(glyphId.Palette)); @@ -77,46 +83,58 @@ GLuint TextureCache::GetOrLoadGlyphTexture(uint32 image, uint8 * palette) return kvp->second; } - GLuint texture = LoadGlyphTexture(image, palette); - _glyphTextureMap[glyphId] = texture; + auto cacheInfo = LoadGlyphTexture(image, palette); + _glyphTextureMap[glyphId] = cacheInfo; - return texture; + printf("%d slots left\n", (int) _freeSlots.size()); + + return cacheInfo; } -GLuint TextureCache::LoadImageTexture(uint32 image) -{ - GLuint texture; - glGenTextures(1, &texture); +void TextureCache::InitializeArrayTexture() { + if (!_arrayTextureInitialized) { + glGenTextures(1, &_arrayTexture); + glBindTexture(GL_TEXTURE_2D_ARRAY, _arrayTexture); + glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_R8UI, TEXTURE_CACHE_ARRAY_WIDTH, TEXTURE_CACHE_ARRAY_HEIGHT, TEXTURE_CACHE_ARRAY_DEPTH); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + _freeSlots.resize(TEXTURE_CACHE_ARRAY_DEPTH); + for (size_t i = 0; i < _freeSlots.size(); i++) _freeSlots[i] = i; + + _arrayTextureInitialized = true; + } +} + +CachedTextureInfo TextureCache::LoadImageTexture(uint32 image) +{ rct_drawpixelinfo * dpi = GetImageAsDPI(image, 0); - glBindTexture(GL_TEXTURE_2D, texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glTexImage2D(GL_TEXTURE_2D, 0, GL_R8UI, dpi->width, dpi->height, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, dpi->bits); + GLuint slot = _freeSlots.back(); + _freeSlots.pop_back(); + + glBindTexture(GL_TEXTURE_2D_ARRAY, _arrayTexture); + glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, slot, dpi->width, dpi->height, 1, GL_RED_INTEGER, GL_UNSIGNED_BYTE, dpi->bits); DeleteDPI(dpi); - return texture; + return{slot, {dpi->width / (float) TEXTURE_CACHE_ARRAY_WIDTH, dpi->height / (float) TEXTURE_CACHE_ARRAY_HEIGHT}}; } -GLuint TextureCache::LoadGlyphTexture(uint32 image, uint8 * palette) +CachedTextureInfo TextureCache::LoadGlyphTexture(uint32 image, uint8 * palette) { - GLuint texture; - glGenTextures(1, &texture); - rct_drawpixelinfo * dpi = GetGlyphAsDPI(image, palette); - glBindTexture(GL_TEXTURE_2D, texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glTexImage2D(GL_TEXTURE_2D, 0, GL_R8UI, dpi->width, dpi->height, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, dpi->bits); + GLuint slot = _freeSlots.back(); + _freeSlots.pop_back(); + + glBindTexture(GL_TEXTURE_2D_ARRAY, _arrayTexture); + glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, slot, dpi->width, dpi->height, 1, GL_RED_INTEGER, GL_UNSIGNED_BYTE, dpi->bits); DeleteDPI(dpi); - return texture; + return {slot, {dpi->width / (float) TEXTURE_CACHE_ARRAY_WIDTH, dpi->height / (float) TEXTURE_CACHE_ARRAY_HEIGHT}}; } void * TextureCache::GetImageAsARGB(uint32 image, uint32 tertiaryColour, uint32 * outWidth, uint32 * outHeight) @@ -204,30 +222,8 @@ void * TextureCache::ConvertDPIto32bpp(const rct_drawpixelinfo * dpi) void TextureCache::FreeTextures() { - // Free images - size_t numTextures = _imageTextureMap.size(); - auto textures = std::vector(numTextures); - for (auto kvp : _imageTextureMap) - { - textures.push_back(kvp.second); - } - if (textures.size() > 0) - { - glDeleteTextures(textures.size(), textures.data()); - } - - // Free glyphs - numTextures = _glyphTextureMap.size(); - textures.clear(); - textures.reserve(numTextures); - for (auto kvp : _glyphTextureMap) - { - textures.push_back(kvp.second); - } - if (textures.size() > 0) - { - glDeleteTextures(textures.size(), textures.data()); - } + // Free array texture + glDeleteTextures(1, &_arrayTexture); } rct_drawpixelinfo * TextureCache::CreateDPI(sint32 width, sint32 height) @@ -253,4 +249,8 @@ void TextureCache::DeleteDPI(rct_drawpixelinfo* dpi) delete dpi; } +GLuint TextureCache::GetArrayTexture() { + return _arrayTexture; +} + #endif /* DISABLE_OPENGL */ diff --git a/src/drawing/engines/opengl/TextureCache.h b/src/drawing/engines/opengl/TextureCache.h index 0d26a47bd3..7f33603897 100644 --- a/src/drawing/engines/opengl/TextureCache.h +++ b/src/drawing/engines/opengl/TextureCache.h @@ -20,6 +20,7 @@ #include #include "../../../common.h" #include "OpenGLAPI.h" +#include "GLSLTypes.h" struct rct_drawpixelinfo; @@ -50,11 +51,27 @@ struct GlyphId }; }; +// TODO: Currently hardcoded to support 2048 simultaneous images of 256 x 256 dimensions +constexpr size_t TEXTURE_CACHE_ARRAY_DEPTH = 2048; +constexpr short TEXTURE_CACHE_ARRAY_WIDTH = 256; +constexpr short TEXTURE_CACHE_ARRAY_HEIGHT = 256; + +struct CachedTextureInfo { + GLuint slot; + vec2f dimensions; +}; + class TextureCache { private: - std::unordered_map _imageTextureMap; - std::unordered_map _glyphTextureMap; + bool _arrayTextureInitialized = false; + GLuint _arrayTexture; + + std::vector _freeSlots; + + std::unordered_map _imageTextureMap; + std::unordered_map _glyphTextureMap; + SDL_Color _palette[256]; public: @@ -62,12 +79,15 @@ public: ~TextureCache(); void SetPalette(const SDL_Color * palette); void InvalidateImage(uint32 image); - GLuint GetOrLoadImageTexture(uint32 image); - GLuint GetOrLoadGlyphTexture(uint32 image, uint8 * palette); + CachedTextureInfo GetOrLoadImageTexture(uint32 image); + CachedTextureInfo GetOrLoadGlyphTexture(uint32 image, uint8 * palette); + + GLuint GetArrayTexture(); private: - GLuint LoadImageTexture(uint32 image); - GLuint LoadGlyphTexture(uint32 image, uint8 * palette); + void InitializeArrayTexture(); + CachedTextureInfo LoadImageTexture(uint32 image); + CachedTextureInfo LoadGlyphTexture(uint32 image, uint8 * palette); void * GetImageAsARGB(uint32 image, uint32 tertiaryColour, uint32 * outWidth, uint32 * outHeight); rct_drawpixelinfo * GetImageAsDPI(uint32 image, uint32 tertiaryColour); void * GetGlyphAsARGB(uint32 image, uint8 * palette, uint32 * outWidth, uint32 * outHeight); From fbb7029de4566dd35dc36cc2d2580f93a5d0bd2a Mon Sep 17 00:00:00 2001 From: Alexander Overvoorde Date: Sat, 23 Jul 2016 00:56:41 +0200 Subject: [PATCH 06/24] Implement sprite batch drawing using instancing --- data/shaders/drawimage.frag | 23 +++--- data/shaders/drawimage.vert | 31 ++++++-- .../engines/opengl/DrawImageShader.cpp | 76 +++++++++---------- src/drawing/engines/opengl/DrawImageShader.h | 30 ++++---- src/drawing/engines/opengl/OpenGLAPI.cpp | 2 + src/drawing/engines/opengl/OpenGLAPI.h | 2 + .../engines/opengl/OpenGLDrawingEngine.cpp | 28 +++++-- src/drawing/engines/opengl/TextureCache.cpp | 4 +- 8 files changed, 111 insertions(+), 85 deletions(-) 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; } From 360a92e9061ce441c521b372e3948081eae0f31b Mon Sep 17 00:00:00 2001 From: Alexander Overvoorde Date: Sat, 23 Jul 2016 02:30:13 +0200 Subject: [PATCH 07/24] Merge draw image and draw masked image shaders --- data/shaders/drawimage.frag | 21 +++- data/shaders/drawimage.vert | 12 ++- data/shaders/drawimagemasked.frag | 24 ----- data/shaders/drawimagemasked.vert | 41 -------- openrct2.vcxproj | 2 - src/drawing/engines/opengl/DrawCommands.h | 7 +- .../engines/opengl/DrawImageMaskedShader.cpp | 99 ------------------- .../engines/opengl/DrawImageMaskedShader.h | 52 ---------- .../engines/opengl/DrawImageShader.cpp | 12 ++- src/drawing/engines/opengl/DrawImageShader.h | 4 +- .../engines/opengl/OpenGLDrawingEngine.cpp | 45 +++------ 11 files changed, 52 insertions(+), 267 deletions(-) delete mode 100644 data/shaders/drawimagemasked.frag delete mode 100644 data/shaders/drawimagemasked.vert delete mode 100644 src/drawing/engines/opengl/DrawImageMaskedShader.cpp delete mode 100644 src/drawing/engines/opengl/DrawImageMaskedShader.h diff --git a/data/shaders/drawimage.frag b/data/shaders/drawimage.frag index e5deded42b..fca2da5edb 100644 --- a/data/shaders/drawimage.frag +++ b/data/shaders/drawimage.frag @@ -7,7 +7,9 @@ flat in ivec4 fClip; flat in int fFlags; in vec4 fColour; in vec2 fTexCoordScale; -flat in int fTexSlot; +flat in int fTexColourSlot; +flat in int fTexMaskSlot; +flat in int fMask; in vec2 fPosition; in vec2 fTextureCoordinate; @@ -22,13 +24,22 @@ void main() discard; } - vec4 texel = uPalette[texture(uTexture, vec3(fTextureCoordinate * fTexCoordScale, float(fTexSlot))).r]; - if ((fFlags & 1) != 0) + vec4 mask = uPalette[texture(uTexture, vec3(fTextureCoordinate * fTexCoordScale, float(fTexMaskSlot))).r]; + vec4 texel = uPalette[texture(uTexture, vec3(fTextureCoordinate * fTexCoordScale, float(fTexColourSlot))).r]; + + if (fMask) { - oColour = vec4(fColour.rgb, fColour.a * texel.a); + oColour = texel * mask; } else { - oColour = texel; + if ((fFlags & 1) != 0) + { + oColour = vec4(fColour.rgb, fColour.a * texel.a); + } + else + { + oColour = texel; + } } } diff --git a/data/shaders/drawimage.vert b/data/shaders/drawimage.vert index c6d33f57cc..7e45caa44c 100644 --- a/data/shaders/drawimage.vert +++ b/data/shaders/drawimage.vert @@ -5,10 +5,12 @@ uniform ivec4 uTextureCoordinates; in ivec4 ivClip; in vec2 ivTexCoordScale; -in int ivTexSlot; +in int ivTexColourSlot; +in int ivTexMaskSlot; in int ivFlags; in vec4 ivColour; in ivec4 ivBounds; +in int ivMask; in uint vIndex; @@ -18,7 +20,9 @@ flat out ivec4 fClip; flat out int fFlags; out vec4 fColour; out vec2 fTexCoordScale; -flat out int fTexSlot; +flat out int fTexColourSlot; +flat out int fTexMaskSlot; +flat out int fMask; void main() { @@ -53,7 +57,9 @@ void main() fFlags = ivFlags; fColour = ivColour; fTexCoordScale = ivTexCoordScale; - fTexSlot = ivTexSlot; + fTexColourSlot = ivTexColourSlot; + fTexMaskSlot = ivTexMaskSlot; + fMask = ivMask; gl_Position = vec4(pos, 0.0, 1.0); } diff --git a/data/shaders/drawimagemasked.frag b/data/shaders/drawimagemasked.frag deleted file mode 100644 index 03423395d0..0000000000 --- a/data/shaders/drawimagemasked.frag +++ /dev/null @@ -1,24 +0,0 @@ -#version 150 - -uniform ivec4 uClip; -uniform usampler2D uTextureMask; -uniform usampler2D uTextureColour; -uniform vec4 uPalette[256]; - -in vec2 fPosition; -in vec2 fTextureCoordinate; - -out vec4 oColour; - -void main() -{ - if (fPosition.x < uClip.x || fPosition.x > uClip.z || - fPosition.y < uClip.y || fPosition.y > uClip.w) - { - discard; - } - - vec4 mask = uPalette[texture(uTextureMask, fTextureCoordinate).r]; - vec4 colour = uPalette[texture(uTextureColour, fTextureCoordinate).r]; - oColour = colour * mask; -} diff --git a/data/shaders/drawimagemasked.vert b/data/shaders/drawimagemasked.vert deleted file mode 100644 index e4b505daec..0000000000 --- a/data/shaders/drawimagemasked.vert +++ /dev/null @@ -1,41 +0,0 @@ -#version 150 - -uniform ivec2 uScreenSize; -uniform ivec4 uBounds; - -in uint vIndex; - -out vec2 fPosition; -out vec2 fTextureCoordinate; - -void main() -{ - vec2 pos; - switch (vIndex) { - case 0u: - pos = uBounds.xy; - fTextureCoordinate = vec2(0, 0); - break; - case 1u: - pos = uBounds.zy; - fTextureCoordinate = vec2(1, 0); - break; - case 2u: - pos = uBounds.xw; - fTextureCoordinate = vec2(0, 1); - break; - case 3u: - pos = uBounds.zw; - fTextureCoordinate = vec2(1, 1); - break; - } - - fPosition = pos; - - // Transform screen coordinates to viewport - pos.x = (pos.x * (2.0 / uScreenSize.x)) - 1.0; - pos.y = (pos.y * (2.0 / uScreenSize.y)) - 1.0; - pos.y *= -1; - - gl_Position = vec4(pos, 0.0, 1.0); -} diff --git a/openrct2.vcxproj b/openrct2.vcxproj index f8caad1f7a..4d00677ce6 100644 --- a/openrct2.vcxproj +++ b/openrct2.vcxproj @@ -56,7 +56,6 @@ - @@ -384,7 +383,6 @@ - diff --git a/src/drawing/engines/opengl/DrawCommands.h b/src/drawing/engines/opengl/DrawCommands.h index 86b7e36544..d6b8c33fe2 100644 --- a/src/drawing/engines/opengl/DrawCommands.h +++ b/src/drawing/engines/opengl/DrawCommands.h @@ -37,14 +37,9 @@ struct DrawLineCommand { struct DrawImageCommand { uint32 flags; vec4f colour; - sint32 clip[4]; - CachedTextureInfo texColour; - sint32 bounds[4]; -}; - -struct DrawImageMaskedCommand { sint32 clip[4]; CachedTextureInfo texMask; CachedTextureInfo texColour; sint32 bounds[4]; + bool mask; }; \ No newline at end of file diff --git a/src/drawing/engines/opengl/DrawImageMaskedShader.cpp b/src/drawing/engines/opengl/DrawImageMaskedShader.cpp deleted file mode 100644 index e785eb9d78..0000000000 --- a/src/drawing/engines/opengl/DrawImageMaskedShader.cpp +++ /dev/null @@ -1,99 +0,0 @@ -#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers -/***************************************************************************** - * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. - * - * OpenRCT2 is the work of many authors, a full list can be found in contributors.md - * For more information, visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * A full copy of the GNU General Public License can be found in licence.txt - *****************************************************************************/ -#pragma endregion - -#ifndef DISABLE_OPENGL - -#include "DrawImageMaskedShader.h" - -DrawImageMaskedShader::DrawImageMaskedShader() : OpenGLShaderProgram("drawimagemasked") -{ - GetLocations(); - - glGenBuffers(1, &_vbo); - glGenVertexArrays(1, &_vao); - - GLuint vertices[] = { 0, 1, 2, 2, 1, 3 }; - glBindBuffer(GL_ARRAY_BUFFER, _vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - - glBindVertexArray(_vao); - glEnableVertexAttribArray(vIndex); - glVertexAttribIPointer(vIndex, 1, GL_INT, 0, 0); - - Use(); - glUniform1i(uTextureMask, 0); - glUniform1i(uTextureColour, 1); -} - -DrawImageMaskedShader::~DrawImageMaskedShader() -{ - glDeleteBuffers(1, &_vbo); - glDeleteVertexArrays(1, &_vao); - - glBindVertexArray(_vao); -} - -void DrawImageMaskedShader::GetLocations() -{ - uScreenSize = GetUniformLocation("uScreenSize"); - uClip = GetUniformLocation("uClip"); - uBounds = GetUniformLocation("uBounds"); - uTextureMask = GetUniformLocation("uTextureMask"); - uTextureColour = GetUniformLocation("uTextureColour"); - uPalette = GetUniformLocation("uPalette"); - - vIndex = GetAttributeLocation("vIndex"); -} - -void DrawImageMaskedShader::SetScreenSize(sint32 width, sint32 height) -{ - glUniform2i(uScreenSize, width, height); -} - -void DrawImageMaskedShader::SetClip(sint32 left, sint32 top, sint32 right, sint32 bottom) -{ - glUniform4i(uClip, left, top, right, bottom); -} - -void DrawImageMaskedShader::SetBounds(sint32 left, sint32 top, sint32 right, sint32 bottom) -{ - glUniform4i(uBounds, left, top, right, bottom); -} - -void DrawImageMaskedShader::SetTextureMask(GLuint texture) -{ - OpenGLAPI::SetTexture(0, GL_TEXTURE_2D, texture); -} - -void DrawImageMaskedShader::SetTextureColour(GLuint texture) -{ - OpenGLAPI::SetTexture(1, GL_TEXTURE_2D, texture); -} - -void DrawImageMaskedShader::SetPalette(const vec4f *glPalette) -{ - glUniform4fv(uPalette, 256, (const GLfloat *) glPalette); -} - -void DrawImageMaskedShader::Draw(sint32 left, sint32 top, sint32 right, sint32 bottom) -{ - SetBounds(left, top, right, bottom); - - glBindVertexArray(_vao); - glDrawArrays(GL_TRIANGLES, 0, 6); -} - -#endif /* DISABLE_OPENGL */ diff --git a/src/drawing/engines/opengl/DrawImageMaskedShader.h b/src/drawing/engines/opengl/DrawImageMaskedShader.h deleted file mode 100644 index d42c28b1b8..0000000000 --- a/src/drawing/engines/opengl/DrawImageMaskedShader.h +++ /dev/null @@ -1,52 +0,0 @@ -#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers -/***************************************************************************** - * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. - * - * OpenRCT2 is the work of many authors, a full list can be found in contributors.md - * For more information, visit https://github.com/OpenRCT2/OpenRCT2 - * - * OpenRCT2 is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * A full copy of the GNU General Public License can be found in licence.txt - *****************************************************************************/ -#pragma endregion - -#pragma once - -#include "GLSLTypes.h" -#include "OpenGLShaderProgram.h" -#include - -class DrawImageMaskedShader : public OpenGLShaderProgram -{ -private: - GLuint uScreenSize; - GLuint uClip; - GLuint uBounds; - GLuint uTextureMask; - GLuint uTextureColour; - GLuint uPalette; - - GLuint vIndex; - - GLuint _vbo; - GLuint _vao; - -public: - DrawImageMaskedShader(); - ~DrawImageMaskedShader() 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 SetTextureMask(GLuint texture); - void SetTextureColour(GLuint texture); - void SetPalette(const vec4f *glPalette); - void Draw(sint32 left, sint32 top, sint32 right, sint32 bottom); - -private: - void GetLocations(); -}; diff --git a/src/drawing/engines/opengl/DrawImageShader.cpp b/src/drawing/engines/opengl/DrawImageShader.cpp index 09ee1ce3b4..ff74de062c 100644 --- a/src/drawing/engines/opengl/DrawImageShader.cpp +++ b/src/drawing/engines/opengl/DrawImageShader.cpp @@ -84,24 +84,30 @@ void DrawImageShader::DrawInstances(const std::vector& instan 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("ivTexColourSlot"), 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texColourSlot)); + glVertexAttribIPointer(GetAttributeLocation("ivTexMaskSlot"), 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texMaskSlot)); 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)); + glVertexAttribIPointer(GetAttributeLocation("ivMask"), 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, mask)); glEnableVertexAttribArray(GetAttributeLocation("ivClip")); glEnableVertexAttribArray(GetAttributeLocation("ivTexCoordScale")); - glEnableVertexAttribArray(GetAttributeLocation("ivTexSlot")); + glEnableVertexAttribArray(GetAttributeLocation("ivTexColourSlot")); + glEnableVertexAttribArray(GetAttributeLocation("ivTexMaskSlot")); glEnableVertexAttribArray(GetAttributeLocation("ivFlags")); glEnableVertexAttribArray(GetAttributeLocation("ivColour")); glEnableVertexAttribArray(GetAttributeLocation("ivBounds")); + glEnableVertexAttribArray(GetAttributeLocation("ivMask")); glVertexAttribDivisor(GetAttributeLocation("ivClip"), 1); glVertexAttribDivisor(GetAttributeLocation("ivTexCoordScale"), 1); - glVertexAttribDivisor(GetAttributeLocation("ivTexSlot"), 1); + glVertexAttribDivisor(GetAttributeLocation("ivTexColourSlot"), 1); + glVertexAttribDivisor(GetAttributeLocation("ivTexMaskSlot"), 1); glVertexAttribDivisor(GetAttributeLocation("ivFlags"), 1); glVertexAttribDivisor(GetAttributeLocation("ivColour"), 1); glVertexAttribDivisor(GetAttributeLocation("ivBounds"), 1); + glVertexAttribDivisor(GetAttributeLocation("ivMask"), 1); // Draw instances glDrawArraysInstanced(GL_TRIANGLES, 0, 6, instances.size()); diff --git a/src/drawing/engines/opengl/DrawImageShader.h b/src/drawing/engines/opengl/DrawImageShader.h index 3c45b1194c..6118ed0fa3 100644 --- a/src/drawing/engines/opengl/DrawImageShader.h +++ b/src/drawing/engines/opengl/DrawImageShader.h @@ -25,10 +25,12 @@ struct DrawImageInstance { vec4i clip; vec2f texCoordScale; - int texSlot; + int texColourSlot; + int texMaskSlot; int flags; vec4f colour; vec4i bounds; + int mask; }; class DrawImageShader : public OpenGLShaderProgram diff --git a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp index 9b3a8831aa..ef40a9343f 100644 --- a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp +++ b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp @@ -34,7 +34,6 @@ IDrawingEngine * DrawingEngineFactory::CreateOpenGL() #include "OpenGLFramebuffer.h" #include "CopyFramebufferShader.h" #include "DrawImageShader.h" -#include "DrawImageMaskedShader.h" #include "DrawLineShader.h" #include "FillRectShader.h" #include "SwapFramebuffer.h" @@ -179,7 +178,6 @@ private: rct_drawpixelinfo * _dpi; DrawImageShader * _drawImageShader = nullptr; - DrawImageMaskedShader * _drawImageMaskedShader = nullptr; DrawLineShader * _drawLineShader = nullptr; FillRectShader * _fillRectShader = nullptr; @@ -196,7 +194,6 @@ private: std::vector rectangles; std::vector lines; std::vector images; - std::vector maskedImages; } _commandBuffers; public: @@ -223,7 +220,6 @@ public: void FlushRectangles(); void FlushLines(); void FlushImages(); - void FlushMaskedImages(); void SetDPI(rct_drawpixelinfo * dpi); }; @@ -294,6 +290,9 @@ public: throw Exception("Unable to initialise OpenGL."); } + // TODO: Remove when OpenGL optimization is done + SDL_GL_SetSwapInterval(0); + #ifdef DEBUG glDebugMessageCallback(OpenGLAPI::DebugCallback, nullptr); #endif @@ -517,7 +516,6 @@ OpenGLDrawingContext::OpenGLDrawingContext(OpenGLDrawingEngine * engine) OpenGLDrawingContext::~OpenGLDrawingContext() { delete _drawImageShader; - delete _drawImageMaskedShader; delete _drawLineShader; delete _fillRectShader; @@ -532,7 +530,6 @@ IDrawingEngine * OpenGLDrawingContext::GetEngine() void OpenGLDrawingContext::Initialise() { _drawImageShader = new DrawImageShader(); - _drawImageMaskedShader = new DrawImageMaskedShader(); _drawLineShader = new DrawLineShader(); _fillRectShader = new FillRectShader(); } @@ -543,8 +540,6 @@ void OpenGLDrawingContext::Resize(sint32 width, sint32 height) _drawImageShader->Use(); _drawImageShader->SetScreenSize(width, height); - _drawImageMaskedShader->Use(); - _drawImageMaskedShader->SetScreenSize(width, height); _drawLineShader->Use(); _drawLineShader->SetScreenSize(width, height); _fillRectShader->Use(); @@ -558,8 +553,6 @@ void OpenGLDrawingContext::ResetPalette() _textureCache->SetPalette(_engine->Palette); _drawImageShader->Use(); _drawImageShader->SetPalette(_engine->GLPalette); - _drawImageMaskedShader->Use(); - _drawImageMaskedShader->SetPalette(_engine->GLPalette); } void OpenGLDrawingContext::Clear(uint32 colour) @@ -724,6 +717,7 @@ void OpenGLDrawingContext::DrawSprite(uint32 image, sint32 x, sint32 y, uint32 t DrawImageCommand command = {}; command.flags = 0; + command.mask = false; command.clip[0] = _clipLeft; command.clip[1] = _clipTop; @@ -785,7 +779,9 @@ void OpenGLDrawingContext::DrawSpriteRawMasked(sint32 x, sint32 y, uint32 maskIm right += _clipLeft; bottom += _clipTop; - DrawImageMaskedCommand command = {}; + DrawImageCommand command = {}; + + command.mask = true; command.clip[0] = _clipLeft; command.clip[1] = _clipTop; @@ -800,11 +796,7 @@ void OpenGLDrawingContext::DrawSpriteRawMasked(sint32 x, sint32 y, uint32 maskIm command.bounds[2] = right; command.bounds[3] = bottom; - _commandBuffers.maskedImages.push_back(command); - - // Currently not properly ordered with regular images yet - // TODO: uncomment once masked images are mixed with normal images using depth sorting - //FlushCommandBuffers(); + _commandBuffers.images.push_back(command); } void OpenGLDrawingContext::DrawSpriteSolid(uint32 image, sint32 x, sint32 y, uint8 colour) @@ -843,6 +835,7 @@ void OpenGLDrawingContext::DrawSpriteSolid(uint32 image, sint32 x, sint32 y, uin DrawImageCommand command = {}; command.flags = 1; + command.mask = false; command.colour = paletteColour; command.clip[0] = _clipLeft; @@ -894,6 +887,7 @@ void OpenGLDrawingContext::DrawGlyph(uint32 image, sint32 x, sint32 y, uint8 * p DrawImageCommand command = {}; command.flags = 0; + command.mask = false; command.clip[0] = _clipLeft; command.clip[1] = _clipTop; @@ -915,7 +909,6 @@ void OpenGLDrawingContext::FlushCommandBuffers() { FlushLines(); FlushImages(); - FlushMaskedImages(); } void OpenGLDrawingContext::FlushRectangles() { @@ -956,10 +949,13 @@ void OpenGLDrawingContext::FlushImages() { 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.texColourSlot = command.texColour.slot; + instance.texMaskSlot = command.texMask.slot; + if (!command.mask) instance.texMaskSlot = instance.texColourSlot; instance.flags = command.flags; instance.colour = command.colour; instance.bounds = {command.bounds[0], command.bounds[1], command.bounds[2], command.bounds[3]}; + instance.mask = command.mask; instances.push_back(instance); } @@ -970,19 +966,6 @@ void OpenGLDrawingContext::FlushImages() { _commandBuffers.images.clear(); } -void OpenGLDrawingContext::FlushMaskedImages() { - // DEBUG: disabled until new array based texture cache is finished - /*for (const auto& command : _commandBuffers.maskedImages) { - _drawImageMaskedShader->Use(); - _drawImageMaskedShader->SetClip(command.clip[0], command.clip[1], command.clip[2], command.clip[3]); - _drawImageMaskedShader->SetTextureMask(command.texMask); - _drawImageMaskedShader->SetTextureColour(command.texColour); - _drawImageMaskedShader->Draw(command.bounds[0], command.bounds[1], command.bounds[2], command.bounds[3]); - }*/ - - _commandBuffers.maskedImages.clear(); -} - void OpenGLDrawingContext::SetDPI(rct_drawpixelinfo * dpi) { rct_drawpixelinfo * screenDPI = _engine->GetDPI(); From f16ec771c3c5e9225e4c68b718b168a0e4e487e9 Mon Sep 17 00:00:00 2001 From: Alexander Overvoorde Date: Sat, 23 Jul 2016 02:36:43 +0200 Subject: [PATCH 08/24] Clean up DrawImageShader code --- .../engines/opengl/DrawImageShader.cpp | 73 ++++++++++--------- src/drawing/engines/opengl/DrawImageShader.h | 8 ++ .../engines/opengl/OpenGLDrawingEngine.cpp | 1 - 3 files changed, 48 insertions(+), 34 deletions(-) diff --git a/src/drawing/engines/opengl/DrawImageShader.cpp b/src/drawing/engines/opengl/DrawImageShader.cpp index ff74de062c..649a39771d 100644 --- a/src/drawing/engines/opengl/DrawImageShader.cpp +++ b/src/drawing/engines/opengl/DrawImageShader.cpp @@ -31,9 +31,38 @@ DrawImageShader::DrawImageShader() : OpenGLShaderProgram("drawimage") glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glBindVertexArray(_vao); - glEnableVertexAttribArray(vIndex); + glVertexAttribIPointer(vIndex, 1, GL_INT, 0, nullptr); + glBindBuffer(GL_ARRAY_BUFFER, _vboInstances); + glVertexAttribIPointer(vClip, 4, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, clip)); + glVertexAttribPointer(vTexCoordScale, 2, GL_FLOAT, GL_FALSE, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texCoordScale)); + glVertexAttribIPointer(vTexColourSlot, 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texColourSlot)); + glVertexAttribIPointer(vTexMaskSlot, 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texMaskSlot)); + glVertexAttribIPointer(vFlags, 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, flags)); + glVertexAttribPointer(vColour, 4, GL_FLOAT, GL_FALSE, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, colour)); + glVertexAttribIPointer(vBounds, 4, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, bounds)); + glVertexAttribIPointer(vMask, 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, mask)); + + glEnableVertexAttribArray(vIndex); + glEnableVertexAttribArray(vClip); + glEnableVertexAttribArray(vTexCoordScale); + glEnableVertexAttribArray(vTexColourSlot); + glEnableVertexAttribArray(vTexMaskSlot); + glEnableVertexAttribArray(vFlags); + glEnableVertexAttribArray(vColour); + glEnableVertexAttribArray(vBounds); + glEnableVertexAttribArray(vMask); + + glVertexAttribDivisor(vClip, 1); + glVertexAttribDivisor(vTexCoordScale, 1); + glVertexAttribDivisor(vTexColourSlot, 1); + glVertexAttribDivisor(vTexMaskSlot, 1); + glVertexAttribDivisor(vFlags, 1); + glVertexAttribDivisor(vColour, 1); + glVertexAttribDivisor(vBounds, 1); + glVertexAttribDivisor(vMask, 1); + Use(); SetTextureCoordinates(0, 0, 1, 1); glUniform1i(uTexture, 0); @@ -56,6 +85,14 @@ void DrawImageShader::GetLocations() uTextureCoordinates = GetUniformLocation("uTextureCoordinates"); vIndex = GetAttributeLocation("vIndex"); + vClip = GetAttributeLocation("ivClip"); + vTexCoordScale = GetAttributeLocation("ivTexCoordScale"); + vTexColourSlot = GetAttributeLocation("ivTexColourSlot"); + vTexMaskSlot = GetAttributeLocation("ivTexMaskSlot"); + vFlags = GetAttributeLocation("ivFlags"); + vColour = GetAttributeLocation("ivColour"); + vBounds = GetAttributeLocation("ivBounds"); + vMask = GetAttributeLocation("ivMask"); } void DrawImageShader::SetScreenSize(sint32 width, sint32 height) @@ -75,41 +112,11 @@ void DrawImageShader::SetTextureCoordinates(sint32 left, sint32 top, sint32 righ void DrawImageShader::DrawInstances(const std::vector& instances) { - // Copy instance data to vbo for single-use + glBindVertexArray(_vao); + glBindBuffer(GL_ARRAY_BUFFER, _vboInstances); glBufferData(GL_ARRAY_BUFFER, sizeof(instances[0]) * instances.size(), instances.data(), GL_STREAM_DRAW); - // Bind vertex attributes - glBindVertexArray(_vao); - - 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("ivTexColourSlot"), 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texColourSlot)); - glVertexAttribIPointer(GetAttributeLocation("ivTexMaskSlot"), 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texMaskSlot)); - 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)); - glVertexAttribIPointer(GetAttributeLocation("ivMask"), 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, mask)); - - glEnableVertexAttribArray(GetAttributeLocation("ivClip")); - glEnableVertexAttribArray(GetAttributeLocation("ivTexCoordScale")); - glEnableVertexAttribArray(GetAttributeLocation("ivTexColourSlot")); - glEnableVertexAttribArray(GetAttributeLocation("ivTexMaskSlot")); - glEnableVertexAttribArray(GetAttributeLocation("ivFlags")); - glEnableVertexAttribArray(GetAttributeLocation("ivColour")); - glEnableVertexAttribArray(GetAttributeLocation("ivBounds")); - glEnableVertexAttribArray(GetAttributeLocation("ivMask")); - - glVertexAttribDivisor(GetAttributeLocation("ivClip"), 1); - glVertexAttribDivisor(GetAttributeLocation("ivTexCoordScale"), 1); - glVertexAttribDivisor(GetAttributeLocation("ivTexColourSlot"), 1); - glVertexAttribDivisor(GetAttributeLocation("ivTexMaskSlot"), 1); - glVertexAttribDivisor(GetAttributeLocation("ivFlags"), 1); - glVertexAttribDivisor(GetAttributeLocation("ivColour"), 1); - glVertexAttribDivisor(GetAttributeLocation("ivBounds"), 1); - glVertexAttribDivisor(GetAttributeLocation("ivMask"), 1); - - // Draw instances glDrawArraysInstanced(GL_TRIANGLES, 0, 6, instances.size()); } diff --git a/src/drawing/engines/opengl/DrawImageShader.h b/src/drawing/engines/opengl/DrawImageShader.h index 6118ed0fa3..f5fde0a5ca 100644 --- a/src/drawing/engines/opengl/DrawImageShader.h +++ b/src/drawing/engines/opengl/DrawImageShader.h @@ -42,6 +42,14 @@ private: GLuint uTextureCoordinates; GLuint vIndex; + GLuint vClip; + GLuint vTexCoordScale; + GLuint vTexColourSlot; + GLuint vTexMaskSlot; + GLuint vFlags; + GLuint vColour; + GLuint vBounds; + GLuint vMask; GLuint _vbo; GLuint _vboInstances; diff --git a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp index ef40a9343f..fff81fb93e 100644 --- a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp +++ b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp @@ -951,7 +951,6 @@ void OpenGLDrawingContext::FlushImages() { instance.texCoordScale = command.texColour.dimensions; instance.texColourSlot = command.texColour.slot; instance.texMaskSlot = command.texMask.slot; - if (!command.mask) instance.texMaskSlot = instance.texColourSlot; instance.flags = command.flags; instance.colour = command.colour; instance.bounds = {command.bounds[0], command.bounds[1], command.bounds[2], command.bounds[3]}; From 99a41ee828208ec816a543c216f6c40e422cfa46 Mon Sep 17 00:00:00 2001 From: Alexander Overvoorde Date: Sat, 23 Jul 2016 15:44:51 +0200 Subject: [PATCH 09/24] Fix implicit boolean in GLSL code --- data/shaders/drawimage.frag | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/shaders/drawimage.frag b/data/shaders/drawimage.frag index fca2da5edb..8f39ab6695 100644 --- a/data/shaders/drawimage.frag +++ b/data/shaders/drawimage.frag @@ -27,7 +27,7 @@ void main() vec4 mask = uPalette[texture(uTexture, vec3(fTextureCoordinate * fTexCoordScale, float(fTexMaskSlot))).r]; vec4 texel = uPalette[texture(uTexture, vec3(fTextureCoordinate * fTexCoordScale, float(fTexColourSlot))).r]; - if (fMask) + if ((fMask & 1) != 0) { oColour = texel * mask; } From d8ce023170678328b151490494baaf33b75aee11 Mon Sep 17 00:00:00 2001 From: Alexander Overvoorde Date: Sat, 23 Jul 2016 16:55:47 +0200 Subject: [PATCH 10/24] Change TextureCache to use atlas instead of array --- data/shaders/drawimage.frag | 13 ++-- data/shaders/drawimage.vert | 26 +++---- .../engines/opengl/DrawImageShader.cpp | 27 ++----- src/drawing/engines/opengl/DrawImageShader.h | 12 +-- src/drawing/engines/opengl/OpenGLAPI.cpp | 4 +- src/drawing/engines/opengl/OpenGLAPI.h | 9 +-- .../engines/opengl/OpenGLDrawingEngine.cpp | 16 ++-- src/drawing/engines/opengl/TextureCache.cpp | 77 +++++++++++++------ src/drawing/engines/opengl/TextureCache.h | 25 +++--- 9 files changed, 114 insertions(+), 95 deletions(-) diff --git a/data/shaders/drawimage.frag b/data/shaders/drawimage.frag index 8f39ab6695..81e9085c8c 100644 --- a/data/shaders/drawimage.frag +++ b/data/shaders/drawimage.frag @@ -1,14 +1,13 @@ #version 150 uniform vec4 uPalette[256]; -uniform usampler2DArray uTexture; +uniform usampler2D uTexture; flat in ivec4 fClip; flat in int fFlags; in vec4 fColour; -in vec2 fTexCoordScale; -flat in int fTexColourSlot; -flat in int fTexMaskSlot; +in vec2 fTexColourCoords; +in vec2 fTexMaskCoords; flat in int fMask; in vec2 fPosition; @@ -24,10 +23,10 @@ void main() discard; } - vec4 mask = uPalette[texture(uTexture, vec3(fTextureCoordinate * fTexCoordScale, float(fTexMaskSlot))).r]; - vec4 texel = uPalette[texture(uTexture, vec3(fTextureCoordinate * fTexCoordScale, float(fTexColourSlot))).r]; + vec4 mask = uPalette[texture(uTexture, fTexMaskCoords).r]; + vec4 texel = uPalette[texture(uTexture, fTexColourCoords).r]; - if ((fMask & 1) != 0) + if (fMask != 0) { oColour = texel * mask; } diff --git a/data/shaders/drawimage.vert b/data/shaders/drawimage.vert index 7e45caa44c..2b2f8a0097 100644 --- a/data/shaders/drawimage.vert +++ b/data/shaders/drawimage.vert @@ -1,12 +1,10 @@ #version 150 uniform ivec2 uScreenSize; -uniform ivec4 uTextureCoordinates; in ivec4 ivClip; -in vec2 ivTexCoordScale; -in int ivTexColourSlot; -in int ivTexMaskSlot; +in vec4 ivTexColourBounds; +in vec4 ivTexMaskBounds; in int ivFlags; in vec4 ivColour; in ivec4 ivBounds; @@ -19,9 +17,8 @@ out vec2 fPosition; flat out ivec4 fClip; flat out int fFlags; out vec4 fColour; -out vec2 fTexCoordScale; -flat out int fTexColourSlot; -flat out int fTexMaskSlot; +out vec2 fTexColourCoords; +out vec2 fTexMaskCoords; flat out int fMask; void main() @@ -30,19 +27,23 @@ void main() switch (vIndex) { case 0u: pos = ivBounds.xy; - fTextureCoordinate = uTextureCoordinates.xy; + fTexColourCoords = ivTexColourBounds.xy; + fTexMaskCoords = ivTexMaskBounds.xy; break; case 1u: pos = ivBounds.zy; - fTextureCoordinate = uTextureCoordinates.zy; + fTexColourCoords = ivTexColourBounds.zy; + fTexMaskCoords = ivTexMaskBounds.zy; break; case 2u: pos = ivBounds.xw; - fTextureCoordinate = uTextureCoordinates.xw; + fTexColourCoords = ivTexColourBounds.xw; + fTexMaskCoords = ivTexMaskBounds.xw; break; case 3u: pos = ivBounds.zw; - fTextureCoordinate = uTextureCoordinates.zw; + fTexColourCoords = ivTexColourBounds.zw; + fTexMaskCoords = ivTexMaskBounds.zw; break; } @@ -56,9 +57,6 @@ void main() fClip = ivClip; fFlags = ivFlags; fColour = ivColour; - fTexCoordScale = ivTexCoordScale; - fTexColourSlot = ivTexColourSlot; - fTexMaskSlot = ivTexMaskSlot; fMask = ivMask; 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 649a39771d..48adf55b18 100644 --- a/src/drawing/engines/opengl/DrawImageShader.cpp +++ b/src/drawing/engines/opengl/DrawImageShader.cpp @@ -36,9 +36,8 @@ DrawImageShader::DrawImageShader() : OpenGLShaderProgram("drawimage") glBindBuffer(GL_ARRAY_BUFFER, _vboInstances); glVertexAttribIPointer(vClip, 4, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, clip)); - glVertexAttribPointer(vTexCoordScale, 2, GL_FLOAT, GL_FALSE, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texCoordScale)); - glVertexAttribIPointer(vTexColourSlot, 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texColourSlot)); - glVertexAttribIPointer(vTexMaskSlot, 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texMaskSlot)); + glVertexAttribPointer(vTexColourBounds, 4, GL_FLOAT, GL_FALSE, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texColourBounds)); + glVertexAttribPointer(vTexMaskBounds, 4, GL_FLOAT, GL_FALSE, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texMaskBounds)); glVertexAttribIPointer(vFlags, 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, flags)); glVertexAttribPointer(vColour, 4, GL_FLOAT, GL_FALSE, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, colour)); glVertexAttribIPointer(vBounds, 4, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, bounds)); @@ -46,25 +45,22 @@ DrawImageShader::DrawImageShader() : OpenGLShaderProgram("drawimage") glEnableVertexAttribArray(vIndex); glEnableVertexAttribArray(vClip); - glEnableVertexAttribArray(vTexCoordScale); - glEnableVertexAttribArray(vTexColourSlot); - glEnableVertexAttribArray(vTexMaskSlot); + glEnableVertexAttribArray(vTexColourBounds); + glEnableVertexAttribArray(vTexMaskBounds); glEnableVertexAttribArray(vFlags); glEnableVertexAttribArray(vColour); glEnableVertexAttribArray(vBounds); glEnableVertexAttribArray(vMask); glVertexAttribDivisor(vClip, 1); - glVertexAttribDivisor(vTexCoordScale, 1); - glVertexAttribDivisor(vTexColourSlot, 1); - glVertexAttribDivisor(vTexMaskSlot, 1); + glVertexAttribDivisor(vTexColourBounds, 1); + glVertexAttribDivisor(vTexMaskBounds, 1); glVertexAttribDivisor(vFlags, 1); glVertexAttribDivisor(vColour, 1); glVertexAttribDivisor(vBounds, 1); glVertexAttribDivisor(vMask, 1); Use(); - SetTextureCoordinates(0, 0, 1, 1); glUniform1i(uTexture, 0); } @@ -82,13 +78,11 @@ void DrawImageShader::GetLocations() uScreenSize = GetUniformLocation("uScreenSize"); uTexture = GetUniformLocation("uTexture"); uPalette = GetUniformLocation("uPalette"); - uTextureCoordinates = GetUniformLocation("uTextureCoordinates"); vIndex = GetAttributeLocation("vIndex"); vClip = GetAttributeLocation("ivClip"); - vTexCoordScale = GetAttributeLocation("ivTexCoordScale"); - vTexColourSlot = GetAttributeLocation("ivTexColourSlot"); - vTexMaskSlot = GetAttributeLocation("ivTexMaskSlot"); + vTexColourBounds = GetAttributeLocation("ivTexColourBounds"); + vTexMaskBounds = GetAttributeLocation("ivTexMaskBounds"); vFlags = GetAttributeLocation("ivFlags"); vColour = GetAttributeLocation("ivColour"); vBounds = GetAttributeLocation("ivBounds"); @@ -105,11 +99,6 @@ void DrawImageShader::SetPalette(const vec4f *glPalette) glUniform4fv(uPalette, 256, (const GLfloat *) glPalette); } -void DrawImageShader::SetTextureCoordinates(sint32 left, sint32 top, sint32 right, sint32 bottom) -{ - glUniform4i(uTextureCoordinates, left, top, right, bottom); -} - void DrawImageShader::DrawInstances(const std::vector& instances) { glBindVertexArray(_vao); diff --git a/src/drawing/engines/opengl/DrawImageShader.h b/src/drawing/engines/opengl/DrawImageShader.h index f5fde0a5ca..03474f184e 100644 --- a/src/drawing/engines/opengl/DrawImageShader.h +++ b/src/drawing/engines/opengl/DrawImageShader.h @@ -24,9 +24,8 @@ // Per-instance data for images struct DrawImageInstance { vec4i clip; - vec2f texCoordScale; - int texColourSlot; - int texMaskSlot; + vec4f texColourBounds; + vec4f texMaskBounds; int flags; vec4f colour; vec4i bounds; @@ -39,13 +38,11 @@ private: GLuint uScreenSize; GLuint uTexture; GLuint uPalette; - GLuint uTextureCoordinates; GLuint vIndex; GLuint vClip; - GLuint vTexCoordScale; - GLuint vTexColourSlot; - GLuint vTexMaskSlot; + GLuint vTexColourBounds; + GLuint vTexMaskBounds; GLuint vFlags; GLuint vColour; GLuint vBounds; @@ -63,7 +60,6 @@ public: void SetScreenSize(sint32 width, sint32 height); void SetPalette(const vec4f *glPalette); - void SetTextureCoordinates(sint32 left, sint32 top, sint32 right, sint32 bottom); void DrawInstances(const std::vector& instances); private: diff --git a/src/drawing/engines/opengl/OpenGLAPI.cpp b/src/drawing/engines/opengl/OpenGLAPI.cpp index 61d0483140..1fb3e165b6 100644 --- a/src/drawing/engines/opengl/OpenGLAPI.cpp +++ b/src/drawing/engines/opengl/OpenGLAPI.cpp @@ -68,7 +68,7 @@ static const char * TryLoadAllProcAddresses() SetupOpenGLFunction(glTexImage2D); SetupOpenGLFunction(glTexParameteri); SetupOpenGLFunction(glViewport); - SetupOpenGLFunction(glTexSubImage3D); + SetupOpenGLFunction(glTexSubImage2D); // 2.0+ functions SetupOpenGLFunction(glAttachShader); @@ -108,8 +108,6 @@ static const char * TryLoadAllProcAddresses() SetupOpenGLFunction(glUseProgram); SetupOpenGLFunction(glVertexAttribIPointer); SetupOpenGLFunction(glVertexAttribPointer); - SetupOpenGLFunction(glTexStorage3D); - SetupOpenGLFunction(glDebugMessageCallback); SetupOpenGLFunction(glDrawArraysInstanced); SetupOpenGLFunction(glVertexAttribDivisor); diff --git a/src/drawing/engines/opengl/OpenGLAPI.h b/src/drawing/engines/opengl/OpenGLAPI.h index fc9a1bd0e2..2c7e7ce7a1 100644 --- a/src/drawing/engines/opengl/OpenGLAPI.h +++ b/src/drawing/engines/opengl/OpenGLAPI.h @@ -40,7 +40,7 @@ #define glTexImage2D __static__glTexImage2D #define glTexParameteri __static__glTexParameteri #define glViewport __static__glViewport -#define glTexSubImage3D __static__glTexSubImage3D +#define glTexSubImage2D __static__glTexSubImage2D #endif @@ -68,7 +68,7 @@ #undef glTexImage2D #undef glTexParameteri #undef glViewport -#undef glTexSubImage3D +#undef glTexSubImage2D // 1.1 function signatures typedef void (APIENTRYP PFNGLBEGINPROC )(GLenum mode); @@ -89,6 +89,7 @@ typedef void (APIENTRYP PFNGLREADPIXELSPROC )(GLint x, GLint y, GLsizei wid typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC )(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC )(GLenum target, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLVIEWPORTPROC )(GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* data); #ifdef NO_EXTERN_GLAPI // Defines the function pointers @@ -120,7 +121,7 @@ GLAPI_DECL PFNGLREADPIXELSPROC glReadPixels GLAP GLAPI_DECL PFNGLTEXIMAGE2DPROC glTexImage2D GLAPI_SET; GLAPI_DECL PFNGLTEXPARAMETERIPROC glTexParameteri GLAPI_SET; GLAPI_DECL PFNGLVIEWPORTPROC glViewport GLAPI_SET; -GLAPI_DECL PFNGLTEXSUBIMAGE3DPROC glTexSubImage3D GLAPI_SET; +GLAPI_DECL PFNGLTEXSUBIMAGE2DPROC glTexSubImage2D GLAPI_SET; // 2.0+ function pointers GLAPI_DECL PFNGLATTACHSHADERPROC glAttachShader GLAPI_SET; @@ -160,8 +161,6 @@ GLAPI_DECL PFNGLUNIFORM4FVPROC glUniform4fv GLAP GLAPI_DECL PFNGLUSEPROGRAMPROC glUseProgram GLAPI_SET; GLAPI_DECL PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer GLAPI_SET; 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; diff --git a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp index fff81fb93e..4a71767553 100644 --- a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp +++ b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp @@ -63,7 +63,7 @@ struct OpenGLVersion GLint Minor; }; -constexpr OpenGLVersion OPENGL_MINIMUM_REQUIRED_VERSION = { 3, 2 }; +constexpr OpenGLVersion OPENGL_MINIMUM_REQUIRED_VERSION = { 3, 3 }; static const vec3f TransparentColourTable[144 - 44] = { @@ -294,7 +294,10 @@ public: SDL_GL_SetSwapInterval(0); #ifdef DEBUG - glDebugMessageCallback(OpenGLAPI::DebugCallback, nullptr); + PFNGLDEBUGMESSAGECALLBACKPROC debugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKPROC) SDL_GL_GetProcAddress("glDebugMessageCallback"); + if (debugMessageCallback != nullptr) { + debugMessageCallback(OpenGLAPI::DebugCallback, nullptr); + } #endif _drawingContext->Initialise(); @@ -939,7 +942,7 @@ void OpenGLDrawingContext::FlushLines() { void OpenGLDrawingContext::FlushImages() { if (_commandBuffers.images.size() == 0) return; - OpenGLAPI::SetTexture(0, GL_TEXTURE_2D_ARRAY, _textureCache->GetArrayTexture()); + OpenGLAPI::SetTexture(0, GL_TEXTURE_2D, _textureCache->GetAtlasTexture()); std::vector instances; instances.reserve(_commandBuffers.images.size()); @@ -948,9 +951,8 @@ void OpenGLDrawingContext::FlushImages() { DrawImageInstance instance; instance.clip = {command.clip[0], command.clip[1], command.clip[2], command.clip[3]}; - instance.texCoordScale = command.texColour.dimensions; - instance.texColourSlot = command.texColour.slot; - instance.texMaskSlot = command.texMask.slot; + instance.texColourBounds = command.texColour.bounds; + instance.texMaskBounds = command.texMask.bounds; instance.flags = command.flags; instance.colour = command.colour; instance.bounds = {command.bounds[0], command.bounds[1], command.bounds[2], command.bounds[3]}; @@ -961,7 +963,7 @@ void OpenGLDrawingContext::FlushImages() { _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 bc4472275f..c6bc1d8aa3 100644 --- a/src/drawing/engines/opengl/TextureCache.cpp +++ b/src/drawing/engines/opengl/TextureCache.cpp @@ -41,7 +41,7 @@ void TextureCache::SetPalette(const SDL_Color * palette) void TextureCache::InvalidateImage(uint32 image) { - InitializeArrayTexture(); + InitializeAtlasTexture(); auto kvp = _imageTextureMap.find(image); if (kvp != _imageTextureMap.end()) @@ -53,7 +53,7 @@ void TextureCache::InvalidateImage(uint32 image) CachedTextureInfo TextureCache::GetOrLoadImageTexture(uint32 image) { - InitializeArrayTexture(); + InitializeAtlasTexture(); auto kvp = _imageTextureMap.find(image & 0x7FFFF); if (kvp != _imageTextureMap.end()) @@ -64,14 +64,14 @@ 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()); // TODO REMOVE return cacheInfo; } CachedTextureInfo TextureCache::GetOrLoadGlyphTexture(uint32 image, uint8 * palette) { - InitializeArrayTexture(); + InitializeAtlasTexture(); GlyphId glyphId; glyphId.Image = image; @@ -86,24 +86,24 @@ 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()); // TODO REMOVE return cacheInfo; } -void TextureCache::InitializeArrayTexture() { - if (!_arrayTextureInitialized) { - glGenTextures(1, &_arrayTexture); - glBindTexture(GL_TEXTURE_2D_ARRAY, _arrayTexture); - glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_R8UI, TEXTURE_CACHE_ARRAY_WIDTH, TEXTURE_CACHE_ARRAY_HEIGHT, TEXTURE_CACHE_ARRAY_DEPTH); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); +void TextureCache::InitializeAtlasTexture() { + if (!_atlasTextureInitialized) { + glGenTextures(1, &_atlasTexture); + glBindTexture(GL_TEXTURE_2D, _atlasTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_R8UI, TEXTURE_CACHE_ATLAS_WIDTH, TEXTURE_CACHE_ATLAS_HEIGHT, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, nullptr); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - _freeSlots.resize(TEXTURE_CACHE_ARRAY_DEPTH); + _freeSlots.resize(TEXTURE_CACHE_MAX_IMAGES); for (size_t i = 0; i < _freeSlots.size(); i++) _freeSlots[i] = i; - _arrayTextureInitialized = true; + _atlasTextureInitialized = true; } } @@ -114,12 +114,17 @@ CachedTextureInfo TextureCache::LoadImageTexture(uint32 image) GLuint slot = _freeSlots.back(); _freeSlots.pop_back(); - glBindTexture(GL_TEXTURE_2D_ARRAY, _arrayTexture); - glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, slot, dpi->width, dpi->height, 1, GL_RED_INTEGER, GL_UNSIGNED_BYTE, dpi->bits); + if (dpi->width > TEXTURE_CACHE_MAX_IMAGE_WIDTH) dpi->width = TEXTURE_CACHE_MAX_IMAGE_WIDTH; + if (dpi->height > TEXTURE_CACHE_MAX_IMAGE_HEIGHT) dpi->height = TEXTURE_CACHE_MAX_IMAGE_HEIGHT; + + vec4i coords = CalculateAtlasCoordinates(slot, dpi->width, dpi->height); + + glBindTexture(GL_TEXTURE_2D, _atlasTexture); + glTexSubImage2D(GL_TEXTURE_2D, 0, coords.x, coords.y, dpi->width, dpi->height, GL_RED_INTEGER, GL_UNSIGNED_BYTE, dpi->bits); DeleteDPI(dpi); - return{slot, {dpi->width / (float) TEXTURE_CACHE_ARRAY_WIDTH, dpi->height / (float) TEXTURE_CACHE_ARRAY_HEIGHT}}; + return {slot, ConvertToNormalizedCoordinates(coords)}; } CachedTextureInfo TextureCache::LoadGlyphTexture(uint32 image, uint8 * palette) @@ -129,12 +134,17 @@ CachedTextureInfo TextureCache::LoadGlyphTexture(uint32 image, uint8 * palette) GLuint slot = _freeSlots.back(); _freeSlots.pop_back(); - glBindTexture(GL_TEXTURE_2D_ARRAY, _arrayTexture); - glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, slot, dpi->width, dpi->height, 1, GL_RED_INTEGER, GL_UNSIGNED_BYTE, dpi->bits); + if (dpi->width > TEXTURE_CACHE_MAX_IMAGE_WIDTH) dpi->width = TEXTURE_CACHE_MAX_IMAGE_WIDTH; + if (dpi->height > TEXTURE_CACHE_MAX_IMAGE_HEIGHT) dpi->height = TEXTURE_CACHE_MAX_IMAGE_HEIGHT; + + vec4i coords = CalculateAtlasCoordinates(slot, dpi->width, dpi->height); + + glBindTexture(GL_TEXTURE_2D, _atlasTexture); + glTexSubImage2D(GL_TEXTURE_2D, 0, coords.x, coords.y, dpi->width, dpi->height, GL_RED_INTEGER, GL_UNSIGNED_BYTE, dpi->bits); DeleteDPI(dpi); - return {slot, {dpi->width / (float) TEXTURE_CACHE_ARRAY_WIDTH, dpi->height / (float) TEXTURE_CACHE_ARRAY_HEIGHT}}; + return{slot, ConvertToNormalizedCoordinates(coords)}; } void * TextureCache::GetImageAsARGB(uint32 image, uint32 tertiaryColour, uint32 * outWidth, uint32 * outHeight) @@ -223,7 +233,28 @@ void * TextureCache::ConvertDPIto32bpp(const rct_drawpixelinfo * dpi) void TextureCache::FreeTextures() { // Free array texture - glDeleteTextures(1, &_arrayTexture); + glDeleteTextures(1, &_atlasTexture); +} + +vec4i TextureCache::CalculateAtlasCoordinates(GLuint slot, int width, int height) { + int row = slot / TEXTURE_CACHE_IMAGES_U; + int col = slot % TEXTURE_CACHE_IMAGES_U; + + return vec4i{ + TEXTURE_CACHE_MAX_IMAGE_WIDTH * col, + TEXTURE_CACHE_MAX_IMAGE_HEIGHT * row, + TEXTURE_CACHE_MAX_IMAGE_WIDTH * col + width, + TEXTURE_CACHE_MAX_IMAGE_HEIGHT * row + height, + }; +} + +vec4f TextureCache::ConvertToNormalizedCoordinates(vec4i coordinates) { + return vec4f{ + coordinates.x / (float) TEXTURE_CACHE_ATLAS_WIDTH, + coordinates.y / (float) TEXTURE_CACHE_ATLAS_HEIGHT, + coordinates.z / (float) TEXTURE_CACHE_ATLAS_WIDTH, + coordinates.w / (float) TEXTURE_CACHE_ATLAS_HEIGHT + }; } rct_drawpixelinfo * TextureCache::CreateDPI(sint32 width, sint32 height) @@ -249,8 +280,8 @@ void TextureCache::DeleteDPI(rct_drawpixelinfo* dpi) delete dpi; } -GLuint TextureCache::GetArrayTexture() { - return _arrayTexture; +GLuint TextureCache::GetAtlasTexture() { + return _atlasTexture; } #endif /* DISABLE_OPENGL */ diff --git a/src/drawing/engines/opengl/TextureCache.h b/src/drawing/engines/opengl/TextureCache.h index 7f33603897..57a549dd9e 100644 --- a/src/drawing/engines/opengl/TextureCache.h +++ b/src/drawing/engines/opengl/TextureCache.h @@ -51,21 +51,26 @@ struct GlyphId }; }; -// TODO: Currently hardcoded to support 2048 simultaneous images of 256 x 256 dimensions -constexpr size_t TEXTURE_CACHE_ARRAY_DEPTH = 2048; -constexpr short TEXTURE_CACHE_ARRAY_WIDTH = 256; -constexpr short TEXTURE_CACHE_ARRAY_HEIGHT = 256; +// TODO: Derive from hardware limits instead +// TODO: Support > 64x64 images +constexpr int TEXTURE_CACHE_ATLAS_WIDTH = 8192; +constexpr int TEXTURE_CACHE_ATLAS_HEIGHT = 8192; +constexpr int TEXTURE_CACHE_MAX_IMAGE_WIDTH = 64; +constexpr int TEXTURE_CACHE_MAX_IMAGE_HEIGHT = 64; +constexpr int TEXTURE_CACHE_IMAGES_U = TEXTURE_CACHE_ATLAS_WIDTH / TEXTURE_CACHE_MAX_IMAGE_WIDTH; +constexpr int TEXTURE_CACHE_IMAGES_V = TEXTURE_CACHE_ATLAS_HEIGHT / TEXTURE_CACHE_MAX_IMAGE_HEIGHT; +constexpr int TEXTURE_CACHE_MAX_IMAGES = TEXTURE_CACHE_IMAGES_U * TEXTURE_CACHE_IMAGES_V; struct CachedTextureInfo { GLuint slot; - vec2f dimensions; + vec4f bounds; }; class TextureCache { private: - bool _arrayTextureInitialized = false; - GLuint _arrayTexture; + bool _atlasTextureInitialized = false; + GLuint _atlasTexture; std::vector _freeSlots; @@ -82,10 +87,10 @@ public: CachedTextureInfo GetOrLoadImageTexture(uint32 image); CachedTextureInfo GetOrLoadGlyphTexture(uint32 image, uint8 * palette); - GLuint GetArrayTexture(); + GLuint GetAtlasTexture(); private: - void InitializeArrayTexture(); + void InitializeAtlasTexture(); CachedTextureInfo LoadImageTexture(uint32 image); CachedTextureInfo LoadGlyphTexture(uint32 image, uint8 * palette); void * GetImageAsARGB(uint32 image, uint32 tertiaryColour, uint32 * outWidth, uint32 * outHeight); @@ -94,6 +99,8 @@ private: rct_drawpixelinfo * GetGlyphAsDPI(uint32 image, uint8 * palette); void * ConvertDPIto32bpp(const rct_drawpixelinfo * dpi); void FreeTextures(); + vec4i CalculateAtlasCoordinates(GLuint slot, int width, int height); + vec4f ConvertToNormalizedCoordinates(vec4i coordinates); static rct_drawpixelinfo * CreateDPI(sint32 width, sint32 height); static void DeleteDPI(rct_drawpixelinfo * dpi); From 90565fe2be447d1382bd7730a1a83bc0add12686 Mon Sep 17 00:00:00 2001 From: Alexander Overvoorde Date: Sat, 23 Jul 2016 17:09:42 +0200 Subject: [PATCH 11/24] Fix FPS counter accuracy for high frame rates --- src/rct2.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/rct2.c b/src/rct2.c index 98d4e536c0..873529c841 100644 --- a/src/rct2.c +++ b/src/rct2.c @@ -301,21 +301,20 @@ void rct2_draw(rct_drawpixelinfo *dpi) gCurrentDrawCount++; } -static uint32 _lastFPSUpdateTicks; -static uint32 _lastFPSTicks; -static float _currentFPS; +static time_t _lastSecond; +static int _currentFPS; +static int _frames; -static float rct2_measure_fps() +static void rct2_measure_fps() { - uint32 currentTicks = SDL_GetTicks(); - if (currentTicks - _lastFPSUpdateTicks > 500) { - _lastFPSUpdateTicks = currentTicks; + _frames++; - uint32 frameDelta = currentTicks - _lastFPSTicks; - _currentFPS = 1000.0f / frameDelta; - } - _lastFPSTicks = currentTicks; - return _currentFPS; + if (time(NULL) != _lastSecond) { + _currentFPS = _frames; + _frames = 0; + } + + _lastSecond = time(NULL); } static void rct2_draw_fps(rct_drawpixelinfo *dpi) @@ -332,9 +331,8 @@ static void rct2_draw_fps(rct_drawpixelinfo *dpi) ch = utf8_write_codepoint(ch, FORMAT_MEDIUMFONT); ch = utf8_write_codepoint(ch, FORMAT_OUTLINE); ch = utf8_write_codepoint(ch, FORMAT_WHITE); - - const char *formatString = (_currentFPS >= 100.0f ? "%.0f" : "%.1f"); - sprintf(ch, formatString, _currentFPS); + + sprintf(ch, "%d", _currentFPS); // Draw Text int stringWidth = gfx_get_string_width(buffer); From 9e6db9244600064f97f94e6ccade2f43eaae9d01 Mon Sep 17 00:00:00 2001 From: Alexander Overvoorde Date: Sat, 23 Jul 2016 17:30:16 +0200 Subject: [PATCH 12/24] Fix type error --- src/drawing/engines/opengl/OpenGLDrawingEngine.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp index 4a71767553..384e76b487 100644 --- a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp +++ b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp @@ -294,9 +294,10 @@ public: SDL_GL_SetSwapInterval(0); #ifdef DEBUG - PFNGLDEBUGMESSAGECALLBACKPROC debugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKPROC) SDL_GL_GetProcAddress("glDebugMessageCallback"); - if (debugMessageCallback != nullptr) { - debugMessageCallback(OpenGLAPI::DebugCallback, nullptr); + typedef void (APIENTRYP debugMessageCallback)(GLDEBUGPROC callback, const void *userParam); + debugMessageCallback glDebugMessageCallback = (debugMessageCallback) SDL_GL_GetProcAddress("glDebugMessageCallback"); + if (glDebugMessageCallback != nullptr) { + glDebugMessageCallback(OpenGLAPI::DebugCallback, nullptr); } #endif From c8a0cedf33dcde132e6804922292cbdf63a4d803 Mon Sep 17 00:00:00 2001 From: Alexander Overvoorde Date: Sat, 23 Jul 2016 17:32:15 +0200 Subject: [PATCH 13/24] Change rct2_measure_fps to only call time() once --- src/rct2.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/rct2.c b/src/rct2.c index 873529c841..7fccdfcb4e 100644 --- a/src/rct2.c +++ b/src/rct2.c @@ -309,12 +309,14 @@ static void rct2_measure_fps() { _frames++; - if (time(NULL) != _lastSecond) { + time_t currentTime = time(NULL); + + if (currentTime != _lastSecond) { _currentFPS = _frames; _frames = 0; } - _lastSecond = time(NULL); + _lastSecond = currentTime; } static void rct2_draw_fps(rct_drawpixelinfo *dpi) From bb3fe8b8043185fd2dd7e1bbec227b48a09db436 Mon Sep 17 00:00:00 2001 From: Alexander Overvoorde Date: Sat, 23 Jul 2016 18:33:53 +0200 Subject: [PATCH 14/24] Implement multiple texture atlas system to handle small and large images --- data/shaders/drawimage.frag | 7 +- data/shaders/drawimage.vert | 3 + .../engines/opengl/DrawImageShader.cpp | 4 + src/drawing/engines/opengl/DrawImageShader.h | 2 + src/drawing/engines/opengl/OpenGLAPI.cpp | 3 +- src/drawing/engines/opengl/OpenGLAPI.h | 12 +- .../engines/opengl/OpenGLDrawingEngine.cpp | 7 +- src/drawing/engines/opengl/TextureCache.cpp | 102 ++++++---------- src/drawing/engines/opengl/TextureCache.h | 109 +++++++++++++++--- 9 files changed, 159 insertions(+), 90 deletions(-) diff --git a/data/shaders/drawimage.frag b/data/shaders/drawimage.frag index 81e9085c8c..87a96aa1eb 100644 --- a/data/shaders/drawimage.frag +++ b/data/shaders/drawimage.frag @@ -1,11 +1,12 @@ #version 150 uniform vec4 uPalette[256]; -uniform usampler2D uTexture; +uniform usampler2DArray uTexture; flat in ivec4 fClip; flat in int fFlags; in vec4 fColour; +flat in int fTexAtlasIndex; in vec2 fTexColourCoords; in vec2 fTexMaskCoords; flat in int fMask; @@ -23,8 +24,8 @@ void main() discard; } - vec4 mask = uPalette[texture(uTexture, fTexMaskCoords).r]; - vec4 texel = uPalette[texture(uTexture, fTexColourCoords).r]; + vec4 mask = uPalette[texture(uTexture, vec3(fTexMaskCoords, float(fTexAtlasIndex))).r]; + vec4 texel = uPalette[texture(uTexture, vec3(fTexColourCoords, float(fTexAtlasIndex))).r]; if (fMask != 0) { diff --git a/data/shaders/drawimage.vert b/data/shaders/drawimage.vert index 2b2f8a0097..0ff5c67588 100644 --- a/data/shaders/drawimage.vert +++ b/data/shaders/drawimage.vert @@ -3,6 +3,7 @@ uniform ivec2 uScreenSize; in ivec4 ivClip; +in int ivTexAtlasIndex; in vec4 ivTexColourBounds; in vec4 ivTexMaskBounds; in int ivFlags; @@ -17,6 +18,7 @@ out vec2 fPosition; flat out ivec4 fClip; flat out int fFlags; out vec4 fColour; +flat out int fTexAtlasIndex; out vec2 fTexColourCoords; out vec2 fTexMaskCoords; flat out int fMask; @@ -58,6 +60,7 @@ void main() fFlags = ivFlags; fColour = ivColour; fMask = ivMask; + fTexAtlasIndex = ivTexAtlasIndex; 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 48adf55b18..7d2b3b1d81 100644 --- a/src/drawing/engines/opengl/DrawImageShader.cpp +++ b/src/drawing/engines/opengl/DrawImageShader.cpp @@ -36,6 +36,7 @@ DrawImageShader::DrawImageShader() : OpenGLShaderProgram("drawimage") glBindBuffer(GL_ARRAY_BUFFER, _vboInstances); glVertexAttribIPointer(vClip, 4, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, clip)); + glVertexAttribIPointer(vTexAtlasIndex, 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texAtlasIndex)); glVertexAttribPointer(vTexColourBounds, 4, GL_FLOAT, GL_FALSE, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texColourBounds)); glVertexAttribPointer(vTexMaskBounds, 4, GL_FLOAT, GL_FALSE, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texMaskBounds)); glVertexAttribIPointer(vFlags, 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, flags)); @@ -45,6 +46,7 @@ DrawImageShader::DrawImageShader() : OpenGLShaderProgram("drawimage") glEnableVertexAttribArray(vIndex); glEnableVertexAttribArray(vClip); + glEnableVertexAttribArray(vTexAtlasIndex); glEnableVertexAttribArray(vTexColourBounds); glEnableVertexAttribArray(vTexMaskBounds); glEnableVertexAttribArray(vFlags); @@ -53,6 +55,7 @@ DrawImageShader::DrawImageShader() : OpenGLShaderProgram("drawimage") glEnableVertexAttribArray(vMask); glVertexAttribDivisor(vClip, 1); + glVertexAttribDivisor(vTexAtlasIndex, 1); glVertexAttribDivisor(vTexColourBounds, 1); glVertexAttribDivisor(vTexMaskBounds, 1); glVertexAttribDivisor(vFlags, 1); @@ -81,6 +84,7 @@ void DrawImageShader::GetLocations() vIndex = GetAttributeLocation("vIndex"); vClip = GetAttributeLocation("ivClip"); + vTexAtlasIndex = GetAttributeLocation("ivTexAtlasIndex"); vTexColourBounds = GetAttributeLocation("ivTexColourBounds"); vTexMaskBounds = GetAttributeLocation("ivTexMaskBounds"); vFlags = GetAttributeLocation("ivFlags"); diff --git a/src/drawing/engines/opengl/DrawImageShader.h b/src/drawing/engines/opengl/DrawImageShader.h index 03474f184e..425735ffa7 100644 --- a/src/drawing/engines/opengl/DrawImageShader.h +++ b/src/drawing/engines/opengl/DrawImageShader.h @@ -24,6 +24,7 @@ // Per-instance data for images struct DrawImageInstance { vec4i clip; + int texAtlasIndex; vec4f texColourBounds; vec4f texMaskBounds; int flags; @@ -41,6 +42,7 @@ private: GLuint vIndex; GLuint vClip; + GLuint vTexAtlasIndex; GLuint vTexColourBounds; GLuint vTexMaskBounds; GLuint vFlags; diff --git a/src/drawing/engines/opengl/OpenGLAPI.cpp b/src/drawing/engines/opengl/OpenGLAPI.cpp index 1fb3e165b6..2c738c3436 100644 --- a/src/drawing/engines/opengl/OpenGLAPI.cpp +++ b/src/drawing/engines/opengl/OpenGLAPI.cpp @@ -68,7 +68,8 @@ static const char * TryLoadAllProcAddresses() SetupOpenGLFunction(glTexImage2D); SetupOpenGLFunction(glTexParameteri); SetupOpenGLFunction(glViewport); - SetupOpenGLFunction(glTexSubImage2D); + SetupOpenGLFunction(glTexSubImage3D); + SetupOpenGLFunction(glTexImage3D); // 2.0+ functions SetupOpenGLFunction(glAttachShader); diff --git a/src/drawing/engines/opengl/OpenGLAPI.h b/src/drawing/engines/opengl/OpenGLAPI.h index 2c7e7ce7a1..a3cab1ae9f 100644 --- a/src/drawing/engines/opengl/OpenGLAPI.h +++ b/src/drawing/engines/opengl/OpenGLAPI.h @@ -40,7 +40,8 @@ #define glTexImage2D __static__glTexImage2D #define glTexParameteri __static__glTexParameteri #define glViewport __static__glViewport -#define glTexSubImage2D __static__glTexSubImage2D +#define glTexSubImage3D __static__glTexSubImage3D +#define glTexImage3D __static__glTexImage3D #endif @@ -68,7 +69,8 @@ #undef glTexImage2D #undef glTexParameteri #undef glViewport -#undef glTexSubImage2D +#undef glTexSubImage3D +#undef glTexImage3D // 1.1 function signatures typedef void (APIENTRYP PFNGLBEGINPROC )(GLenum mode); @@ -89,7 +91,8 @@ typedef void (APIENTRYP PFNGLREADPIXELSPROC )(GLint x, GLint y, GLsizei wid typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC )(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC )(GLenum target, GLenum pname, GLint param); typedef void (APIENTRYP PFNGLVIEWPORTPROC )(GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* data); +typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* data); +typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC )(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid * data); #ifdef NO_EXTERN_GLAPI // Defines the function pointers @@ -121,7 +124,8 @@ GLAPI_DECL PFNGLREADPIXELSPROC glReadPixels GLAP GLAPI_DECL PFNGLTEXIMAGE2DPROC glTexImage2D GLAPI_SET; GLAPI_DECL PFNGLTEXPARAMETERIPROC glTexParameteri GLAPI_SET; GLAPI_DECL PFNGLVIEWPORTPROC glViewport GLAPI_SET; -GLAPI_DECL PFNGLTEXSUBIMAGE2DPROC glTexSubImage2D GLAPI_SET; +GLAPI_DECL PFNGLTEXSUBIMAGE3DPROC glTexSubImage3D GLAPI_SET; +GLAPI_DECL PFNGLTEXIMAGE3DPROC glTexImage3D GLAPI_SET; // 2.0+ function pointers GLAPI_DECL PFNGLATTACHSHADERPROC glAttachShader GLAPI_SET; diff --git a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp index 384e76b487..5659337ea4 100644 --- a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp +++ b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp @@ -943,7 +943,7 @@ void OpenGLDrawingContext::FlushLines() { void OpenGLDrawingContext::FlushImages() { if (_commandBuffers.images.size() == 0) return; - OpenGLAPI::SetTexture(0, GL_TEXTURE_2D, _textureCache->GetAtlasTexture()); + OpenGLAPI::SetTexture(0, GL_TEXTURE_2D_ARRAY, _textureCache->GetAtlasTextureArray()); std::vector instances; instances.reserve(_commandBuffers.images.size()); @@ -952,8 +952,9 @@ void OpenGLDrawingContext::FlushImages() { DrawImageInstance instance; instance.clip = {command.clip[0], command.clip[1], command.clip[2], command.clip[3]}; - instance.texColourBounds = command.texColour.bounds; - instance.texMaskBounds = command.texMask.bounds; + instance.texAtlasIndex = command.texColour.index; + instance.texColourBounds = command.texColour.normalizedBounds; + instance.texMaskBounds = command.texMask.normalizedBounds; instance.flags = command.flags; instance.colour = command.colour; instance.bounds = {command.bounds[0], command.bounds[1], command.bounds[2], command.bounds[3]}; diff --git a/src/drawing/engines/opengl/TextureCache.cpp b/src/drawing/engines/opengl/TextureCache.cpp index c6bc1d8aa3..74e35dffc7 100644 --- a/src/drawing/engines/opengl/TextureCache.cpp +++ b/src/drawing/engines/opengl/TextureCache.cpp @@ -17,6 +17,7 @@ #ifndef DISABLE_OPENGL #include +#include #include "../../../core/Memory.hpp" #include "TextureCache.h" @@ -41,19 +42,19 @@ void TextureCache::SetPalette(const SDL_Color * palette) void TextureCache::InvalidateImage(uint32 image) { - InitializeAtlasTexture(); + InitialiseAtlases(); auto kvp = _imageTextureMap.find(image); if (kvp != _imageTextureMap.end()) { + _atlases[kvp->second.index].Free(kvp->second); _imageTextureMap.erase(kvp); - _freeSlots.push_back(kvp->second.slot); } } CachedTextureInfo TextureCache::GetOrLoadImageTexture(uint32 image) { - InitializeAtlasTexture(); + InitialiseAtlases(); auto kvp = _imageTextureMap.find(image & 0x7FFFF); if (kvp != _imageTextureMap.end()) @@ -64,14 +65,12 @@ CachedTextureInfo TextureCache::GetOrLoadImageTexture(uint32 image) auto cacheInfo = LoadImageTexture(image); _imageTextureMap[image & 0x7FFFF] = cacheInfo; - //printf("%d slots left\n", (int) _freeSlots.size()); // TODO REMOVE - return cacheInfo; } CachedTextureInfo TextureCache::GetOrLoadGlyphTexture(uint32 image, uint8 * palette) { - InitializeAtlasTexture(); + InitialiseAtlases(); GlyphId glyphId; glyphId.Image = image; @@ -86,65 +85,49 @@ CachedTextureInfo TextureCache::GetOrLoadGlyphTexture(uint32 image, uint8 * pale auto cacheInfo = LoadGlyphTexture(image, palette); _glyphTextureMap[glyphId] = cacheInfo; - //printf("%d slots left\n", (int) _freeSlots.size()); // TODO REMOVE - return cacheInfo; } -void TextureCache::InitializeAtlasTexture() { - if (!_atlasTextureInitialized) { - glGenTextures(1, &_atlasTexture); - glBindTexture(GL_TEXTURE_2D, _atlasTexture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_R8UI, TEXTURE_CACHE_ATLAS_WIDTH, TEXTURE_CACHE_ATLAS_HEIGHT, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); +void TextureCache::InitialiseAtlases() { + if (!_atlasInitialised) { + // Create an array texture to hold all of the atlases + glGenTextures(1, &_atlasTextureArray); + glBindTexture(GL_TEXTURE_2D_ARRAY, _atlasTextureArray); + glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_R8UI, TEXTURE_CACHE_ATLAS_WIDTH, TEXTURE_CACHE_ATLAS_HEIGHT, _atlases.size(), 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, nullptr); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - _freeSlots.resize(TEXTURE_CACHE_MAX_IMAGES); - for (size_t i = 0; i < _freeSlots.size(); i++) _freeSlots[i] = i; - - _atlasTextureInitialized = true; + _atlasInitialised = true; } } CachedTextureInfo TextureCache::LoadImageTexture(uint32 image) { rct_drawpixelinfo * dpi = GetImageAsDPI(image, 0); - - GLuint slot = _freeSlots.back(); - _freeSlots.pop_back(); - - if (dpi->width > TEXTURE_CACHE_MAX_IMAGE_WIDTH) dpi->width = TEXTURE_CACHE_MAX_IMAGE_WIDTH; - if (dpi->height > TEXTURE_CACHE_MAX_IMAGE_HEIGHT) dpi->height = TEXTURE_CACHE_MAX_IMAGE_HEIGHT; - - vec4i coords = CalculateAtlasCoordinates(slot, dpi->width, dpi->height); - - glBindTexture(GL_TEXTURE_2D, _atlasTexture); - glTexSubImage2D(GL_TEXTURE_2D, 0, coords.x, coords.y, dpi->width, dpi->height, GL_RED_INTEGER, GL_UNSIGNED_BYTE, dpi->bits); + auto cacheInfo = AllocateFromAppropriateAtlas(dpi->width, dpi->height); + + glBindTexture(GL_TEXTURE_2D_ARRAY, _atlasTextureArray); + glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, cacheInfo.bounds.x, cacheInfo.bounds.y, cacheInfo.index, dpi->width, dpi->height, 1, GL_RED_INTEGER, GL_UNSIGNED_BYTE, dpi->bits); + DeleteDPI(dpi); - return {slot, ConvertToNormalizedCoordinates(coords)}; + return cacheInfo; } CachedTextureInfo TextureCache::LoadGlyphTexture(uint32 image, uint8 * palette) { rct_drawpixelinfo * dpi = GetGlyphAsDPI(image, palette); - GLuint slot = _freeSlots.back(); - _freeSlots.pop_back(); + auto cacheInfo = AllocateFromAppropriateAtlas(dpi->width, dpi->height); - if (dpi->width > TEXTURE_CACHE_MAX_IMAGE_WIDTH) dpi->width = TEXTURE_CACHE_MAX_IMAGE_WIDTH; - if (dpi->height > TEXTURE_CACHE_MAX_IMAGE_HEIGHT) dpi->height = TEXTURE_CACHE_MAX_IMAGE_HEIGHT; - - vec4i coords = CalculateAtlasCoordinates(slot, dpi->width, dpi->height); - - glBindTexture(GL_TEXTURE_2D, _atlasTexture); - glTexSubImage2D(GL_TEXTURE_2D, 0, coords.x, coords.y, dpi->width, dpi->height, GL_RED_INTEGER, GL_UNSIGNED_BYTE, dpi->bits); + glBindTexture(GL_TEXTURE_2D_ARRAY, _atlasTextureArray); + glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, cacheInfo.bounds.x, cacheInfo.bounds.y, cacheInfo.index, dpi->width, dpi->height, 1, GL_RED_INTEGER, GL_UNSIGNED_BYTE, dpi->bits); DeleteDPI(dpi); - return{slot, ConvertToNormalizedCoordinates(coords)}; + return cacheInfo; } void * TextureCache::GetImageAsARGB(uint32 image, uint32 tertiaryColour, uint32 * outWidth, uint32 * outHeight) @@ -163,6 +146,16 @@ void * TextureCache::GetImageAsARGB(uint32 image, uint32 tertiaryColour, uint32 return pixels32; } +CachedTextureInfo TextureCache::AllocateFromAppropriateAtlas(int imageWidth, int imageHeight) { + for (Atlas& atlas : _atlases) { + if (atlas.GetFreeSlots() > 0 && atlas.SupportsImage(imageWidth, imageHeight)) { + return atlas.Allocate(imageWidth, imageHeight); + } + } + + throw std::runtime_error("no atlas with free slots left that supports image!"); +} + rct_drawpixelinfo * TextureCache::GetImageAsDPI(uint32 image, uint32 tertiaryColour) { rct_g1_element * g1Element = gfx_get_g1_element(image & 0x7FFFF); @@ -233,28 +226,7 @@ void * TextureCache::ConvertDPIto32bpp(const rct_drawpixelinfo * dpi) void TextureCache::FreeTextures() { // Free array texture - glDeleteTextures(1, &_atlasTexture); -} - -vec4i TextureCache::CalculateAtlasCoordinates(GLuint slot, int width, int height) { - int row = slot / TEXTURE_CACHE_IMAGES_U; - int col = slot % TEXTURE_CACHE_IMAGES_U; - - return vec4i{ - TEXTURE_CACHE_MAX_IMAGE_WIDTH * col, - TEXTURE_CACHE_MAX_IMAGE_HEIGHT * row, - TEXTURE_CACHE_MAX_IMAGE_WIDTH * col + width, - TEXTURE_CACHE_MAX_IMAGE_HEIGHT * row + height, - }; -} - -vec4f TextureCache::ConvertToNormalizedCoordinates(vec4i coordinates) { - return vec4f{ - coordinates.x / (float) TEXTURE_CACHE_ATLAS_WIDTH, - coordinates.y / (float) TEXTURE_CACHE_ATLAS_HEIGHT, - coordinates.z / (float) TEXTURE_CACHE_ATLAS_WIDTH, - coordinates.w / (float) TEXTURE_CACHE_ATLAS_HEIGHT - }; + glDeleteTextures(1, &_atlasTextureArray); } rct_drawpixelinfo * TextureCache::CreateDPI(sint32 width, sint32 height) @@ -280,8 +252,8 @@ void TextureCache::DeleteDPI(rct_drawpixelinfo* dpi) delete dpi; } -GLuint TextureCache::GetAtlasTexture() { - return _atlasTexture; +GLuint TextureCache::GetAtlasTextureArray() { + return _atlasTextureArray; } #endif /* DISABLE_OPENGL */ diff --git a/src/drawing/engines/opengl/TextureCache.h b/src/drawing/engines/opengl/TextureCache.h index 57a549dd9e..17adcc93ee 100644 --- a/src/drawing/engines/opengl/TextureCache.h +++ b/src/drawing/engines/opengl/TextureCache.h @@ -17,6 +17,7 @@ #pragma once #include +#include #include #include "../../../common.h" #include "OpenGLAPI.h" @@ -52,27 +53,108 @@ struct GlyphId }; // TODO: Derive from hardware limits instead -// TODO: Support > 64x64 images +// TODO: Handle no more slots remaining (allocate more atlases?) +// TODO: Handle images larger than 256x256 constexpr int TEXTURE_CACHE_ATLAS_WIDTH = 8192; constexpr int TEXTURE_CACHE_ATLAS_HEIGHT = 8192; -constexpr int TEXTURE_CACHE_MAX_IMAGE_WIDTH = 64; -constexpr int TEXTURE_CACHE_MAX_IMAGE_HEIGHT = 64; -constexpr int TEXTURE_CACHE_IMAGES_U = TEXTURE_CACHE_ATLAS_WIDTH / TEXTURE_CACHE_MAX_IMAGE_WIDTH; -constexpr int TEXTURE_CACHE_IMAGES_V = TEXTURE_CACHE_ATLAS_HEIGHT / TEXTURE_CACHE_MAX_IMAGE_HEIGHT; -constexpr int TEXTURE_CACHE_MAX_IMAGES = TEXTURE_CACHE_IMAGES_U * TEXTURE_CACHE_IMAGES_V; +// Location of an image (texture atlas index, slot and normalized coordinates) struct CachedTextureInfo { + GLuint index; GLuint slot; - vec4f bounds; + vec4i bounds; + vec4f normalizedBounds; +}; + +// Represents a texture atlas that images of a given maximum size can be allocated from +// Atlases are all stored in the same 2D texture array, occupying the specified index +class Atlas { +private: + GLuint _index; + int _imageWidth, _imageHeight; + std::vector _freeSlots; + + int _cols, _rows; + +public: + Atlas(GLuint index, int imageWidth, int imageHeight) { + _index = index; + _imageWidth = imageWidth; + _imageHeight = imageHeight; + + _cols = TEXTURE_CACHE_ATLAS_WIDTH / imageWidth; + _rows = TEXTURE_CACHE_ATLAS_HEIGHT / imageHeight; + + _freeSlots.resize(_cols * _rows); + for (size_t i = 0; i < _freeSlots.size(); i++) { + _freeSlots[i] = i; + } + } + + CachedTextureInfo Allocate(int actualWidth, int actualHeight) { + assert(_freeSlots.size() > 0); + + GLuint slot = _freeSlots.back(); + _freeSlots.pop_back(); + + auto bounds = GetSlotCoordinates(slot, actualWidth, actualHeight); + +#ifdef DEBUG + printf("texture atlas (%d, %d) has %d slots left\n", _imageWidth, _imageHeight, GetFreeSlots()); +#endif + + return {_index, slot, bounds, NormalizeCoordinates(bounds)}; + } + + void Free(const CachedTextureInfo& info) { + assert(_index == info.index); + + _freeSlots.push_back(info.slot); + } + + bool SupportsImage(int actualWidth, int actualHeight) const { + return actualWidth <= _imageWidth && actualHeight <= _imageHeight; + } + + int GetFreeSlots() const { + return (int) _freeSlots.size(); + } + +private: + vec4i GetSlotCoordinates(GLuint slot, int actualWidth, int actualHeight) { + int row = slot / _cols; + int col = slot % _cols; + + return vec4i{ + _imageWidth * col, + _imageHeight * row, + _imageWidth * col + actualWidth, + _imageHeight * row + actualHeight, + }; + } + + static vec4f NormalizeCoordinates(const vec4i& coords) { + return vec4f{ + coords.x / (float) TEXTURE_CACHE_ATLAS_WIDTH, + coords.y / (float) TEXTURE_CACHE_ATLAS_HEIGHT, + coords.z / (float) TEXTURE_CACHE_ATLAS_WIDTH, + coords.w / (float) TEXTURE_CACHE_ATLAS_HEIGHT + }; + } }; class TextureCache { private: - bool _atlasTextureInitialized = false; - GLuint _atlasTexture; + bool _atlasInitialised = false; - std::vector _freeSlots; + GLuint _atlasTextureArray; + + // Atlases should be ordered from small to large image support + std::array _atlases = { + Atlas{0, 64, 64}, + Atlas{1, 256, 256} + }; std::unordered_map _imageTextureMap; std::unordered_map _glyphTextureMap; @@ -87,20 +169,19 @@ public: CachedTextureInfo GetOrLoadImageTexture(uint32 image); CachedTextureInfo GetOrLoadGlyphTexture(uint32 image, uint8 * palette); - GLuint GetAtlasTexture(); + GLuint GetAtlasTextureArray(); private: - void InitializeAtlasTexture(); + void InitialiseAtlases(); CachedTextureInfo LoadImageTexture(uint32 image); CachedTextureInfo LoadGlyphTexture(uint32 image, uint8 * palette); + CachedTextureInfo AllocateFromAppropriateAtlas(int imageWidth, int imageHeight); void * GetImageAsARGB(uint32 image, uint32 tertiaryColour, uint32 * outWidth, uint32 * outHeight); rct_drawpixelinfo * GetImageAsDPI(uint32 image, uint32 tertiaryColour); void * GetGlyphAsARGB(uint32 image, uint8 * palette, uint32 * outWidth, uint32 * outHeight); rct_drawpixelinfo * GetGlyphAsDPI(uint32 image, uint8 * palette); void * ConvertDPIto32bpp(const rct_drawpixelinfo * dpi); void FreeTextures(); - vec4i CalculateAtlasCoordinates(GLuint slot, int width, int height); - vec4f ConvertToNormalizedCoordinates(vec4i coordinates); static rct_drawpixelinfo * CreateDPI(sint32 width, sint32 height); static void DeleteDPI(rct_drawpixelinfo * dpi); From c506e08ac240672e31038dca0479624d60daadc7 Mon Sep 17 00:00:00 2001 From: Alexander Overvoorde Date: Sat, 23 Jul 2016 18:58:51 +0200 Subject: [PATCH 15/24] Add more atlases to increase space efficiency and derive atlas size from device limits --- src/drawing/engines/opengl/OpenGLAPI.cpp | 1 + src/drawing/engines/opengl/OpenGLAPI.h | 4 +++ src/drawing/engines/opengl/TextureCache.cpp | 12 ++++++- src/drawing/engines/opengl/TextureCache.h | 36 +++++++++++++-------- 4 files changed, 38 insertions(+), 15 deletions(-) diff --git a/src/drawing/engines/opengl/OpenGLAPI.cpp b/src/drawing/engines/opengl/OpenGLAPI.cpp index 2c738c3436..ca698fcca0 100644 --- a/src/drawing/engines/opengl/OpenGLAPI.cpp +++ b/src/drawing/engines/opengl/OpenGLAPI.cpp @@ -70,6 +70,7 @@ static const char * TryLoadAllProcAddresses() SetupOpenGLFunction(glViewport); SetupOpenGLFunction(glTexSubImage3D); SetupOpenGLFunction(glTexImage3D); + SetupOpenGLFunction(glGetIntegerv); // 2.0+ functions SetupOpenGLFunction(glAttachShader); diff --git a/src/drawing/engines/opengl/OpenGLAPI.h b/src/drawing/engines/opengl/OpenGLAPI.h index a3cab1ae9f..19d8e5dd7e 100644 --- a/src/drawing/engines/opengl/OpenGLAPI.h +++ b/src/drawing/engines/opengl/OpenGLAPI.h @@ -42,6 +42,7 @@ #define glViewport __static__glViewport #define glTexSubImage3D __static__glTexSubImage3D #define glTexImage3D __static__glTexImage3D +#define glGetIntegerv __static__glGetIntegerv #endif @@ -71,6 +72,7 @@ #undef glViewport #undef glTexSubImage3D #undef glTexImage3D +#undef glGetIntegerv // 1.1 function signatures typedef void (APIENTRYP PFNGLBEGINPROC )(GLenum mode); @@ -93,6 +95,7 @@ typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC )(GLenum target, GLenum pname, typedef void (APIENTRYP PFNGLVIEWPORTPROC )(GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* data); typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC )(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid * data); +typedef void (APIENTRYP PFNGLGETINTERGERVPROC )(GLenum pname, GLint * data); #ifdef NO_EXTERN_GLAPI // Defines the function pointers @@ -126,6 +129,7 @@ GLAPI_DECL PFNGLTEXPARAMETERIPROC glTexParameteri GLAP GLAPI_DECL PFNGLVIEWPORTPROC glViewport GLAPI_SET; GLAPI_DECL PFNGLTEXSUBIMAGE3DPROC glTexSubImage3D GLAPI_SET; GLAPI_DECL PFNGLTEXIMAGE3DPROC glTexImage3D GLAPI_SET; +GLAPI_DECL PFNGLGETINTERGERVPROC glGetIntegerv GLAPI_SET; // 2.0+ function pointers GLAPI_DECL PFNGLATTACHSHADERPROC glAttachShader GLAPI_SET; diff --git a/src/drawing/engines/opengl/TextureCache.cpp b/src/drawing/engines/opengl/TextureCache.cpp index 74e35dffc7..973ab3d1c6 100644 --- a/src/drawing/engines/opengl/TextureCache.cpp +++ b/src/drawing/engines/opengl/TextureCache.cpp @@ -90,14 +90,24 @@ CachedTextureInfo TextureCache::GetOrLoadGlyphTexture(uint32 image, uint8 * pale void TextureCache::InitialiseAtlases() { if (!_atlasInitialised) { + // Determine width and height to use for texture atlases + GLint maxSize; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize); + if (maxSize > TEXTURE_CACHE_MAX_ATLAS_SIZE) maxSize = TEXTURE_CACHE_MAX_ATLAS_SIZE; + // Create an array texture to hold all of the atlases glGenTextures(1, &_atlasTextureArray); glBindTexture(GL_TEXTURE_2D_ARRAY, _atlasTextureArray); - glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_R8UI, TEXTURE_CACHE_ATLAS_WIDTH, TEXTURE_CACHE_ATLAS_HEIGHT, _atlases.size(), 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, nullptr); + glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_R8UI, maxSize, maxSize, _atlases.size(), 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, nullptr); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + // Initialise atlases + for (auto& atlas : _atlases) { + atlas.Initialise(maxSize, maxSize); + } + _atlasInitialised = true; } } diff --git a/src/drawing/engines/opengl/TextureCache.h b/src/drawing/engines/opengl/TextureCache.h index 17adcc93ee..e2ca9889b7 100644 --- a/src/drawing/engines/opengl/TextureCache.h +++ b/src/drawing/engines/opengl/TextureCache.h @@ -52,11 +52,11 @@ struct GlyphId }; }; -// TODO: Derive from hardware limits instead // TODO: Handle no more slots remaining (allocate more atlases?) // TODO: Handle images larger than 256x256 -constexpr int TEXTURE_CACHE_ATLAS_WIDTH = 8192; -constexpr int TEXTURE_CACHE_ATLAS_HEIGHT = 8192; + +// This is the maximum width and height of each atlas (2048 -> 4 MB) +constexpr int TEXTURE_CACHE_MAX_ATLAS_SIZE = 2048; // Location of an image (texture atlas index, slot and normalized coordinates) struct CachedTextureInfo { @@ -72,6 +72,7 @@ class Atlas { private: GLuint _index; int _imageWidth, _imageHeight; + int _atlasWidth, _atlasHeight; std::vector _freeSlots; int _cols, _rows; @@ -81,9 +82,14 @@ public: _index = index; _imageWidth = imageWidth; _imageHeight = imageHeight; + } - _cols = TEXTURE_CACHE_ATLAS_WIDTH / imageWidth; - _rows = TEXTURE_CACHE_ATLAS_HEIGHT / imageHeight; + void Initialise(int atlasWidth, int atlasHeight) { + _atlasWidth = atlasWidth; + _atlasHeight = atlasHeight; + + _cols = _atlasWidth / _imageWidth; + _rows = _atlasHeight / _imageHeight; _freeSlots.resize(_cols * _rows); for (size_t i = 0; i < _freeSlots.size(); i++) { @@ -121,7 +127,7 @@ public: } private: - vec4i GetSlotCoordinates(GLuint slot, int actualWidth, int actualHeight) { + vec4i GetSlotCoordinates(GLuint slot, int actualWidth, int actualHeight) const { int row = slot / _cols; int col = slot % _cols; @@ -133,12 +139,12 @@ private: }; } - static vec4f NormalizeCoordinates(const vec4i& coords) { + vec4f NormalizeCoordinates(const vec4i& coords) const { return vec4f{ - coords.x / (float) TEXTURE_CACHE_ATLAS_WIDTH, - coords.y / (float) TEXTURE_CACHE_ATLAS_HEIGHT, - coords.z / (float) TEXTURE_CACHE_ATLAS_WIDTH, - coords.w / (float) TEXTURE_CACHE_ATLAS_HEIGHT + coords.x / (float) _atlasWidth, + coords.y / (float) _atlasHeight, + coords.z / (float) _atlasWidth, + coords.w / (float) _atlasHeight }; } }; @@ -151,9 +157,11 @@ private: GLuint _atlasTextureArray; // Atlases should be ordered from small to large image support - std::array _atlases = { - Atlas{0, 64, 64}, - Atlas{1, 256, 256} + std::array _atlases = { + Atlas{0, 32, 32}, + Atlas{1, 64, 64}, + Atlas{2, 128, 128}, + Atlas{3, 256, 256} }; std::unordered_map _imageTextureMap; From c107101aff7382218d67db3f03e338727339746c Mon Sep 17 00:00:00 2001 From: Alexander Overvoorde Date: Sat, 23 Jul 2016 20:31:41 +0200 Subject: [PATCH 16/24] Implement dynamic atlas allocation in texture cache --- src/drawing/engines/opengl/OpenGLAPI.cpp | 1 + src/drawing/engines/opengl/OpenGLAPI.h | 4 + .../engines/opengl/OpenGLDrawingEngine.cpp | 2 +- src/drawing/engines/opengl/TextureCache.cpp | 94 +++++++++++++------ src/drawing/engines/opengl/TextureCache.h | 81 +++++++++------- 5 files changed, 116 insertions(+), 66 deletions(-) diff --git a/src/drawing/engines/opengl/OpenGLAPI.cpp b/src/drawing/engines/opengl/OpenGLAPI.cpp index ca698fcca0..22a8388404 100644 --- a/src/drawing/engines/opengl/OpenGLAPI.cpp +++ b/src/drawing/engines/opengl/OpenGLAPI.cpp @@ -71,6 +71,7 @@ static const char * TryLoadAllProcAddresses() SetupOpenGLFunction(glTexSubImage3D); SetupOpenGLFunction(glTexImage3D); SetupOpenGLFunction(glGetIntegerv); + SetupOpenGLFunction(glGetTexImage); // 2.0+ functions SetupOpenGLFunction(glAttachShader); diff --git a/src/drawing/engines/opengl/OpenGLAPI.h b/src/drawing/engines/opengl/OpenGLAPI.h index 19d8e5dd7e..9fa2363d85 100644 --- a/src/drawing/engines/opengl/OpenGLAPI.h +++ b/src/drawing/engines/opengl/OpenGLAPI.h @@ -43,6 +43,7 @@ #define glTexSubImage3D __static__glTexSubImage3D #define glTexImage3D __static__glTexImage3D #define glGetIntegerv __static__glGetIntegerv +#define glGetTexImage __static__glGetTexImage #endif @@ -73,6 +74,7 @@ #undef glTexSubImage3D #undef glTexImage3D #undef glGetIntegerv +#undef glGetTexImage // 1.1 function signatures typedef void (APIENTRYP PFNGLBEGINPROC )(GLenum mode); @@ -96,6 +98,7 @@ typedef void (APIENTRYP PFNGLVIEWPORTPROC )(GLint x, GLint y, GLsizei wid typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* data); typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC )(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid * data); typedef void (APIENTRYP PFNGLGETINTERGERVPROC )(GLenum pname, GLint * data); +typedef void (APIENTRYP PFNGLGETTEXIMAGEPROC )(GLenum target, GLint level, GLenum format, GLenum type, GLvoid * img); #ifdef NO_EXTERN_GLAPI // Defines the function pointers @@ -130,6 +133,7 @@ GLAPI_DECL PFNGLVIEWPORTPROC glViewport GLAP GLAPI_DECL PFNGLTEXSUBIMAGE3DPROC glTexSubImage3D GLAPI_SET; GLAPI_DECL PFNGLTEXIMAGE3DPROC glTexImage3D GLAPI_SET; GLAPI_DECL PFNGLGETINTERGERVPROC glGetIntegerv GLAPI_SET; +GLAPI_DECL PFNGLGETTEXIMAGEPROC glGetTexImage GLAPI_SET; // 2.0+ function pointers GLAPI_DECL PFNGLATTACHSHADERPROC glAttachShader GLAPI_SET; diff --git a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp index 5659337ea4..668aa91a67 100644 --- a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp +++ b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp @@ -943,7 +943,7 @@ void OpenGLDrawingContext::FlushLines() { void OpenGLDrawingContext::FlushImages() { if (_commandBuffers.images.size() == 0) return; - OpenGLAPI::SetTexture(0, GL_TEXTURE_2D_ARRAY, _textureCache->GetAtlasTextureArray()); + OpenGLAPI::SetTexture(0, GL_TEXTURE_2D_ARRAY, _textureCache->GetAtlasesTexture()); std::vector instances; instances.reserve(_commandBuffers.images.size()); diff --git a/src/drawing/engines/opengl/TextureCache.cpp b/src/drawing/engines/opengl/TextureCache.cpp index 973ab3d1c6..fd8b9e0561 100644 --- a/src/drawing/engines/opengl/TextureCache.cpp +++ b/src/drawing/engines/opengl/TextureCache.cpp @@ -42,8 +42,6 @@ void TextureCache::SetPalette(const SDL_Color * palette) void TextureCache::InvalidateImage(uint32 image) { - InitialiseAtlases(); - auto kvp = _imageTextureMap.find(image); if (kvp != _imageTextureMap.end()) { @@ -54,8 +52,6 @@ void TextureCache::InvalidateImage(uint32 image) CachedTextureInfo TextureCache::GetOrLoadImageTexture(uint32 image) { - InitialiseAtlases(); - auto kvp = _imageTextureMap.find(image & 0x7FFFF); if (kvp != _imageTextureMap.end()) { @@ -70,8 +66,6 @@ CachedTextureInfo TextureCache::GetOrLoadImageTexture(uint32 image) CachedTextureInfo TextureCache::GetOrLoadGlyphTexture(uint32 image, uint8 * palette) { - InitialiseAtlases(); - GlyphId glyphId; glyphId.Image = image; Memory::Copy(&glyphId.Palette, palette, sizeof(glyphId.Palette)); @@ -88,37 +82,55 @@ CachedTextureInfo TextureCache::GetOrLoadGlyphTexture(uint32 image, uint8 * pale return cacheInfo; } -void TextureCache::InitialiseAtlases() { - if (!_atlasInitialised) { +void TextureCache::CreateAtlasesTexture() { + if (!_atlasesTextureInitialised) { // Determine width and height to use for texture atlases - GLint maxSize; - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize); - if (maxSize > TEXTURE_CACHE_MAX_ATLAS_SIZE) maxSize = TEXTURE_CACHE_MAX_ATLAS_SIZE; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &_atlasesTextureDimensions); + if (_atlasesTextureDimensions > TEXTURE_CACHE_MAX_ATLAS_SIZE) { + _atlasesTextureDimensions = TEXTURE_CACHE_MAX_ATLAS_SIZE; + } + + // Determine maximum number of atlases (minimum of size and array limit) + glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &_atlasesTextureIndicesLimit); + if (_atlasesTextureDimensions < _atlasesTextureIndicesLimit) _atlasesTextureIndicesLimit = _atlasesTextureDimensions; // Create an array texture to hold all of the atlases - glGenTextures(1, &_atlasTextureArray); - glBindTexture(GL_TEXTURE_2D_ARRAY, _atlasTextureArray); - glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_R8UI, maxSize, maxSize, _atlases.size(), 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, nullptr); + glGenTextures(1, &_atlasesTexture); + glBindTexture(GL_TEXTURE_2D_ARRAY, _atlasesTexture); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - // Initialise atlases - for (auto& atlas : _atlases) { - atlas.Initialise(maxSize, maxSize); - } - - _atlasInitialised = true; + _atlasesTextureInitialised = true; + _atlasesTextureIndices = 0; } } +void TextureCache::EnlargeAtlasesTexture(GLuint newEntries) { + CreateAtlasesTexture(); + + GLuint newIndices = _atlasesTextureIndices + newEntries; + + // Retrieve current array data + std::vector oldPixels(_atlasesTextureDimensions * _atlasesTextureDimensions * _atlasesTextureIndices); + glGetTexImage(GL_TEXTURE_2D_ARRAY, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, oldPixels.data()); + + // Reallocate array + glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_R8UI, _atlasesTextureDimensions, _atlasesTextureDimensions, newIndices, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, nullptr); + + // Restore old data + glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, _atlasesTextureDimensions, _atlasesTextureDimensions, _atlasesTextureIndices, GL_RED_INTEGER, GL_UNSIGNED_BYTE, oldPixels.data()); + + _atlasesTextureIndices = newIndices; +} + CachedTextureInfo TextureCache::LoadImageTexture(uint32 image) { rct_drawpixelinfo * dpi = GetImageAsDPI(image, 0); - auto cacheInfo = AllocateFromAppropriateAtlas(dpi->width, dpi->height); + auto cacheInfo = AllocateImage(dpi->width, dpi->height); - glBindTexture(GL_TEXTURE_2D_ARRAY, _atlasTextureArray); + glBindTexture(GL_TEXTURE_2D_ARRAY, _atlasesTexture); glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, cacheInfo.bounds.x, cacheInfo.bounds.y, cacheInfo.index, dpi->width, dpi->height, 1, GL_RED_INTEGER, GL_UNSIGNED_BYTE, dpi->bits); DeleteDPI(dpi); @@ -130,9 +142,9 @@ CachedTextureInfo TextureCache::LoadGlyphTexture(uint32 image, uint8 * palette) { rct_drawpixelinfo * dpi = GetGlyphAsDPI(image, palette); - auto cacheInfo = AllocateFromAppropriateAtlas(dpi->width, dpi->height); + auto cacheInfo = AllocateImage(dpi->width, dpi->height); - glBindTexture(GL_TEXTURE_2D_ARRAY, _atlasTextureArray); + glBindTexture(GL_TEXTURE_2D_ARRAY, _atlasesTexture); glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, cacheInfo.bounds.x, cacheInfo.bounds.y, cacheInfo.index, dpi->width, dpi->height, 1, GL_RED_INTEGER, GL_UNSIGNED_BYTE, dpi->bits); DeleteDPI(dpi); @@ -156,14 +168,36 @@ void * TextureCache::GetImageAsARGB(uint32 image, uint32 tertiaryColour, uint32 return pixels32; } -CachedTextureInfo TextureCache::AllocateFromAppropriateAtlas(int imageWidth, int imageHeight) { +CachedTextureInfo TextureCache::AllocateImage(int imageWidth, int imageHeight) { + CreateAtlasesTexture(); + + // Find an atlas that fits this image for (Atlas& atlas : _atlases) { - if (atlas.GetFreeSlots() > 0 && atlas.SupportsImage(imageWidth, imageHeight)) { + if (atlas.GetFreeSlots() > 0 && atlas.IsImageSuitable(imageWidth, imageHeight)) { return atlas.Allocate(imageWidth, imageHeight); } } - throw std::runtime_error("no atlas with free slots left that supports image!"); + // If there is no such atlas, then create a new one + if ((int) _atlases.size() >= _atlasesTextureIndicesLimit) { + throw std::runtime_error("more texture atlases required, but device limit reached!"); + } + + int atlasIndex = (int) _atlases.size(); + int atlasSize = (int) powf(2, (float) Atlas::CalculateImageSizeOrder(imageWidth, imageHeight)); + +#ifdef DEBUG + printf("new texture atlas #%d (size %d) allocated\n", atlasIndex, atlasSize); +#endif + + _atlases.push_back(std::move(Atlas(atlasIndex, atlasSize))); + _atlases.back().Initialise(_atlasesTextureDimensions, _atlasesTextureDimensions); + + // Enlarge texture array to support new atlas + EnlargeAtlasesTexture(1); + + // And allocate from the new atlas + return _atlases.back().Allocate(imageWidth, imageHeight); } rct_drawpixelinfo * TextureCache::GetImageAsDPI(uint32 image, uint32 tertiaryColour) @@ -236,7 +270,7 @@ void * TextureCache::ConvertDPIto32bpp(const rct_drawpixelinfo * dpi) void TextureCache::FreeTextures() { // Free array texture - glDeleteTextures(1, &_atlasTextureArray); + glDeleteTextures(1, &_atlasesTexture); } rct_drawpixelinfo * TextureCache::CreateDPI(sint32 width, sint32 height) @@ -262,8 +296,8 @@ void TextureCache::DeleteDPI(rct_drawpixelinfo* dpi) delete dpi; } -GLuint TextureCache::GetAtlasTextureArray() { - return _atlasTextureArray; +GLuint TextureCache::GetAtlasesTexture() { + return _atlasesTexture; } #endif /* DISABLE_OPENGL */ diff --git a/src/drawing/engines/opengl/TextureCache.h b/src/drawing/engines/opengl/TextureCache.h index e2ca9889b7..f662663aeb 100644 --- a/src/drawing/engines/opengl/TextureCache.h +++ b/src/drawing/engines/opengl/TextureCache.h @@ -17,7 +17,8 @@ #pragma once #include -#include +#include +#include #include #include "../../../common.h" #include "OpenGLAPI.h" @@ -52,12 +53,14 @@ struct GlyphId }; }; -// TODO: Handle no more slots remaining (allocate more atlases?) -// TODO: Handle images larger than 256x256 - -// This is the maximum width and height of each atlas (2048 -> 4 MB) +// This is the maximum width and height of each atlas, basically the +// granularity at which new atlases are allocated (2048 -> 4 MB of VRAM) constexpr int TEXTURE_CACHE_MAX_ATLAS_SIZE = 2048; +// Pixel dimensions of smallest supported slots in texture atlases +// Must be a power of 2! +constexpr int TEXTURE_CACHE_SMALLEST_SLOT = 32; + // Location of an image (texture atlas index, slot and normalized coordinates) struct CachedTextureInfo { GLuint index; @@ -68,28 +71,28 @@ struct CachedTextureInfo { // Represents a texture atlas that images of a given maximum size can be allocated from // Atlases are all stored in the same 2D texture array, occupying the specified index +// Slots in atlases are always squares. class Atlas { private: GLuint _index; - int _imageWidth, _imageHeight; + int _imageSize; int _atlasWidth, _atlasHeight; std::vector _freeSlots; int _cols, _rows; public: - Atlas(GLuint index, int imageWidth, int imageHeight) { + Atlas(GLuint index, int imageSize) { _index = index; - _imageWidth = imageWidth; - _imageHeight = imageHeight; + _imageSize = imageSize; } void Initialise(int atlasWidth, int atlasHeight) { _atlasWidth = atlasWidth; _atlasHeight = atlasHeight; - _cols = _atlasWidth / _imageWidth; - _rows = _atlasHeight / _imageHeight; + _cols = _atlasWidth / _imageSize; + _rows = _atlasHeight / _imageSize; _freeSlots.resize(_cols * _rows); for (size_t i = 0; i < _freeSlots.size(); i++) { @@ -105,10 +108,6 @@ public: auto bounds = GetSlotCoordinates(slot, actualWidth, actualHeight); -#ifdef DEBUG - printf("texture atlas (%d, %d) has %d slots left\n", _imageWidth, _imageHeight, GetFreeSlots()); -#endif - return {_index, slot, bounds, NormalizeCoordinates(bounds)}; } @@ -118,24 +117,39 @@ public: _freeSlots.push_back(info.slot); } - bool SupportsImage(int actualWidth, int actualHeight) const { - return actualWidth <= _imageWidth && actualHeight <= _imageHeight; + // Checks if specified image would be tightly packed in this atlas + // by checking if it is within the right power of 2 range + bool IsImageSuitable(int actualWidth, int actualHeight) const { + int imageOrder = CalculateImageSizeOrder(actualWidth, actualHeight); + int atlasOrder = (int) log2(_imageSize); + + return imageOrder == atlasOrder; } int GetFreeSlots() const { return (int) _freeSlots.size(); } + static int CalculateImageSizeOrder(int actualWidth, int actualHeight) { + int actualSize = std::max(actualWidth, actualHeight); + + if (actualSize < TEXTURE_CACHE_SMALLEST_SLOT) { + actualSize = TEXTURE_CACHE_SMALLEST_SLOT; + } + + return (int) ceil(log2f((float) actualSize)); + } + private: vec4i GetSlotCoordinates(GLuint slot, int actualWidth, int actualHeight) const { int row = slot / _cols; int col = slot % _cols; return vec4i{ - _imageWidth * col, - _imageHeight * row, - _imageWidth * col + actualWidth, - _imageHeight * row + actualHeight, + _imageSize * col, + _imageSize * row, + _imageSize * col + actualWidth, + _imageSize * row + actualHeight, }; } @@ -152,17 +166,13 @@ private: class TextureCache { private: - bool _atlasInitialised = false; + bool _atlasesTextureInitialised = false; - GLuint _atlasTextureArray; - - // Atlases should be ordered from small to large image support - std::array _atlases = { - Atlas{0, 32, 32}, - Atlas{1, 64, 64}, - Atlas{2, 128, 128}, - Atlas{3, 256, 256} - }; + GLuint _atlasesTexture; + GLint _atlasesTextureDimensions; + GLuint _atlasesTextureIndices; + GLint _atlasesTextureIndicesLimit; + std::vector _atlases; std::unordered_map _imageTextureMap; std::unordered_map _glyphTextureMap; @@ -176,14 +186,15 @@ public: void InvalidateImage(uint32 image); CachedTextureInfo GetOrLoadImageTexture(uint32 image); CachedTextureInfo GetOrLoadGlyphTexture(uint32 image, uint8 * palette); - - GLuint GetAtlasTextureArray(); + + GLuint GetAtlasesTexture(); private: - void InitialiseAtlases(); + void CreateAtlasesTexture(); + void EnlargeAtlasesTexture(GLuint newEntries); CachedTextureInfo LoadImageTexture(uint32 image); CachedTextureInfo LoadGlyphTexture(uint32 image, uint8 * palette); - CachedTextureInfo AllocateFromAppropriateAtlas(int imageWidth, int imageHeight); + CachedTextureInfo AllocateImage(int imageWidth, int imageHeight); void * GetImageAsARGB(uint32 image, uint32 tertiaryColour, uint32 * outWidth, uint32 * outHeight); rct_drawpixelinfo * GetImageAsDPI(uint32 image, uint32 tertiaryColour); void * GetGlyphAsARGB(uint32 image, uint8 * palette, uint32 * outWidth, uint32 * outHeight); From 6acbbcfb6bf3f850c255d599378357d48d39ea0a Mon Sep 17 00:00:00 2001 From: Alexander Overvoorde Date: Sat, 23 Jul 2016 20:43:03 +0200 Subject: [PATCH 17/24] Fix assumption that colour texture and mask texture originate from same atlas --- data/shaders/drawimage.frag | 7 ++++--- data/shaders/drawimage.vert | 9 ++++++--- src/drawing/engines/opengl/DrawImageShader.cpp | 12 ++++++++---- src/drawing/engines/opengl/DrawImageShader.h | 6 ++++-- src/drawing/engines/opengl/OpenGLDrawingEngine.cpp | 3 ++- 5 files changed, 24 insertions(+), 13 deletions(-) diff --git a/data/shaders/drawimage.frag b/data/shaders/drawimage.frag index 87a96aa1eb..c4ae8ce042 100644 --- a/data/shaders/drawimage.frag +++ b/data/shaders/drawimage.frag @@ -6,8 +6,9 @@ uniform usampler2DArray uTexture; flat in ivec4 fClip; flat in int fFlags; in vec4 fColour; -flat in int fTexAtlasIndex; +flat in int fTexColourAtlas; in vec2 fTexColourCoords; +flat in int fTexMaskAtlas; in vec2 fTexMaskCoords; flat in int fMask; @@ -24,8 +25,8 @@ void main() discard; } - vec4 mask = uPalette[texture(uTexture, vec3(fTexMaskCoords, float(fTexAtlasIndex))).r]; - vec4 texel = uPalette[texture(uTexture, vec3(fTexColourCoords, float(fTexAtlasIndex))).r]; + vec4 texel = uPalette[texture(uTexture, vec3(fTexColourCoords, float(fTexColourAtlas))).r]; + vec4 mask = uPalette[texture(uTexture, vec3(fTexMaskCoords, float(fTexMaskAtlas))).r]; if (fMask != 0) { diff --git a/data/shaders/drawimage.vert b/data/shaders/drawimage.vert index 0ff5c67588..064a5e3e56 100644 --- a/data/shaders/drawimage.vert +++ b/data/shaders/drawimage.vert @@ -3,8 +3,9 @@ uniform ivec2 uScreenSize; in ivec4 ivClip; -in int ivTexAtlasIndex; +in int ivTexColourAtlas; in vec4 ivTexColourBounds; +in int ivTexMaskAtlas; in vec4 ivTexMaskBounds; in int ivFlags; in vec4 ivColour; @@ -18,8 +19,9 @@ out vec2 fPosition; flat out ivec4 fClip; flat out int fFlags; out vec4 fColour; -flat out int fTexAtlasIndex; +flat out int fTexColourAtlas; out vec2 fTexColourCoords; +flat out int fTexMaskAtlas; out vec2 fTexMaskCoords; flat out int fMask; @@ -60,7 +62,8 @@ void main() fFlags = ivFlags; fColour = ivColour; fMask = ivMask; - fTexAtlasIndex = ivTexAtlasIndex; + fTexColourAtlas = ivTexColourAtlas; + fTexMaskAtlas = ivTexMaskAtlas; 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 7d2b3b1d81..69c6b8d6ba 100644 --- a/src/drawing/engines/opengl/DrawImageShader.cpp +++ b/src/drawing/engines/opengl/DrawImageShader.cpp @@ -36,8 +36,9 @@ DrawImageShader::DrawImageShader() : OpenGLShaderProgram("drawimage") glBindBuffer(GL_ARRAY_BUFFER, _vboInstances); glVertexAttribIPointer(vClip, 4, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, clip)); - glVertexAttribIPointer(vTexAtlasIndex, 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texAtlasIndex)); + glVertexAttribIPointer(vTexColourAtlas, 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texColourAtlas)); glVertexAttribPointer(vTexColourBounds, 4, GL_FLOAT, GL_FALSE, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texColourBounds)); + glVertexAttribIPointer(vTexMaskAtlas, 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texMaskAtlas)); glVertexAttribPointer(vTexMaskBounds, 4, GL_FLOAT, GL_FALSE, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texMaskBounds)); glVertexAttribIPointer(vFlags, 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, flags)); glVertexAttribPointer(vColour, 4, GL_FLOAT, GL_FALSE, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, colour)); @@ -46,8 +47,9 @@ DrawImageShader::DrawImageShader() : OpenGLShaderProgram("drawimage") glEnableVertexAttribArray(vIndex); glEnableVertexAttribArray(vClip); - glEnableVertexAttribArray(vTexAtlasIndex); + glEnableVertexAttribArray(vTexColourAtlas); glEnableVertexAttribArray(vTexColourBounds); + glEnableVertexAttribArray(vTexMaskAtlas); glEnableVertexAttribArray(vTexMaskBounds); glEnableVertexAttribArray(vFlags); glEnableVertexAttribArray(vColour); @@ -55,8 +57,9 @@ DrawImageShader::DrawImageShader() : OpenGLShaderProgram("drawimage") glEnableVertexAttribArray(vMask); glVertexAttribDivisor(vClip, 1); - glVertexAttribDivisor(vTexAtlasIndex, 1); + glVertexAttribDivisor(vTexColourAtlas, 1); glVertexAttribDivisor(vTexColourBounds, 1); + glVertexAttribDivisor(vTexMaskAtlas, 1); glVertexAttribDivisor(vTexMaskBounds, 1); glVertexAttribDivisor(vFlags, 1); glVertexAttribDivisor(vColour, 1); @@ -84,8 +87,9 @@ void DrawImageShader::GetLocations() vIndex = GetAttributeLocation("vIndex"); vClip = GetAttributeLocation("ivClip"); - vTexAtlasIndex = GetAttributeLocation("ivTexAtlasIndex"); + vTexColourAtlas = GetAttributeLocation("ivTexColourAtlas"); vTexColourBounds = GetAttributeLocation("ivTexColourBounds"); + vTexMaskAtlas = GetAttributeLocation("ivTexMaskAtlas"); vTexMaskBounds = GetAttributeLocation("ivTexMaskBounds"); vFlags = GetAttributeLocation("ivFlags"); vColour = GetAttributeLocation("ivColour"); diff --git a/src/drawing/engines/opengl/DrawImageShader.h b/src/drawing/engines/opengl/DrawImageShader.h index 425735ffa7..f4609bf581 100644 --- a/src/drawing/engines/opengl/DrawImageShader.h +++ b/src/drawing/engines/opengl/DrawImageShader.h @@ -24,8 +24,9 @@ // Per-instance data for images struct DrawImageInstance { vec4i clip; - int texAtlasIndex; + int texColourAtlas; vec4f texColourBounds; + int texMaskAtlas; vec4f texMaskBounds; int flags; vec4f colour; @@ -42,8 +43,9 @@ private: GLuint vIndex; GLuint vClip; - GLuint vTexAtlasIndex; + GLuint vTexColourAtlas; GLuint vTexColourBounds; + GLuint vTexMaskAtlas; GLuint vTexMaskBounds; GLuint vFlags; GLuint vColour; diff --git a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp index 668aa91a67..2d06e255c2 100644 --- a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp +++ b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp @@ -952,8 +952,9 @@ void OpenGLDrawingContext::FlushImages() { DrawImageInstance instance; instance.clip = {command.clip[0], command.clip[1], command.clip[2], command.clip[3]}; - instance.texAtlasIndex = command.texColour.index; + instance.texColourAtlas = command.texColour.index; instance.texColourBounds = command.texColour.normalizedBounds; + instance.texMaskAtlas = command.texMask.index; instance.texMaskBounds = command.texMask.normalizedBounds; instance.flags = command.flags; instance.colour = command.colour; From aab5180afba8263492bf4b91168ef9e6049f482a Mon Sep 17 00:00:00 2001 From: Alexander Overvoorde Date: Sat, 23 Jul 2016 21:00:47 +0200 Subject: [PATCH 18/24] Remove DrawImageMaskedShader from XCode project --- OpenRCT2.xcodeproj/project.pbxproj | 1 - 1 file changed, 1 deletion(-) diff --git a/OpenRCT2.xcodeproj/project.pbxproj b/OpenRCT2.xcodeproj/project.pbxproj index 6b0c460d07..ccf9084fd8 100644 --- a/OpenRCT2.xcodeproj/project.pbxproj +++ b/OpenRCT2.xcodeproj/project.pbxproj @@ -119,7 +119,6 @@ D41B741D1C210A7A0080A7B9 /* libiconv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D41B741C1C210A7A0080A7B9 /* libiconv.tbd */; }; D41B74731C2125E50080A7B9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D41B74721C2125E50080A7B9 /* Assets.xcassets */; }; D43407D61D0E14BE00C2B3D4 /* CopyFramebufferShader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D43407C01D0E14BE00C2B3D4 /* CopyFramebufferShader.cpp */; }; - D43407D71D0E14BE00C2B3D4 /* DrawImageMaskedShader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D43407C21D0E14BE00C2B3D4 /* DrawImageMaskedShader.cpp */; }; D43407D81D0E14BE00C2B3D4 /* DrawImageShader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D43407C41D0E14BE00C2B3D4 /* DrawImageShader.cpp */; }; D43407D91D0E14BE00C2B3D4 /* DrawLineShader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D43407C61D0E14BE00C2B3D4 /* DrawLineShader.cpp */; }; D43407DA1D0E14BE00C2B3D4 /* FillRectShader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D43407C81D0E14BE00C2B3D4 /* FillRectShader.cpp */; }; From acb5c68eacca88cb1f3c80055828f487865ac47a Mon Sep 17 00:00:00 2001 From: Alexander Overvoorde Date: Sat, 23 Jul 2016 21:48:26 +0200 Subject: [PATCH 19/24] Remove debug code --- src/drawing/engines/opengl/OpenGLAPI.cpp | 4 ---- src/drawing/engines/opengl/OpenGLAPI.h | 2 -- .../engines/opengl/OpenGLDrawingEngine.cpp | 15 --------------- 3 files changed, 21 deletions(-) diff --git a/src/drawing/engines/opengl/OpenGLAPI.cpp b/src/drawing/engines/opengl/OpenGLAPI.cpp index 22a8388404..09641de1f4 100644 --- a/src/drawing/engines/opengl/OpenGLAPI.cpp +++ b/src/drawing/engines/opengl/OpenGLAPI.cpp @@ -147,8 +147,4 @@ bool OpenGLAPI::Initialise() return true; } -void APIENTRY OpenGLAPI::DebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* msg, const void* userData) { - Console::Error::WriteLine(msg); -} - #endif /* DISABLE_OPENGL */ diff --git a/src/drawing/engines/opengl/OpenGLAPI.h b/src/drawing/engines/opengl/OpenGLAPI.h index 9fa2363d85..3bf9324a60 100644 --- a/src/drawing/engines/opengl/OpenGLAPI.h +++ b/src/drawing/engines/opengl/OpenGLAPI.h @@ -192,8 +192,6 @@ namespace OpenGLAPI { bool Initialise(); void SetTexture(uint16 index, GLenum type, GLuint texture); - - void APIENTRY DebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* msg, const void* userData); } namespace OpenGLState diff --git a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp index 2d06e255c2..af4f71a8d3 100644 --- a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp +++ b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp @@ -272,10 +272,6 @@ public: SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, requiredVersion.Major); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, requiredVersion.Minor); -#ifdef DEBUG - SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); -#endif - _context = SDL_GL_CreateContext(_window); if (_context == nullptr) { @@ -290,17 +286,6 @@ public: throw Exception("Unable to initialise OpenGL."); } - // TODO: Remove when OpenGL optimization is done - SDL_GL_SetSwapInterval(0); - -#ifdef DEBUG - typedef void (APIENTRYP debugMessageCallback)(GLDEBUGPROC callback, const void *userParam); - debugMessageCallback glDebugMessageCallback = (debugMessageCallback) SDL_GL_GetProcAddress("glDebugMessageCallback"); - if (glDebugMessageCallback != nullptr) { - glDebugMessageCallback(OpenGLAPI::DebugCallback, nullptr); - } -#endif - _drawingContext->Initialise(); glEnable(GL_BLEND); From c56a683eed458670934b0711509041ff3ecb1927 Mon Sep 17 00:00:00 2001 From: Alexander Overvoorde Date: Sat, 23 Jul 2016 22:12:17 +0200 Subject: [PATCH 20/24] Disable OpenGL vsync when uncap fps option is enabled --- src/drawing/IDrawingEngine.h | 2 ++ src/drawing/NewDrawing.cpp | 9 +++++++++ src/drawing/NewDrawing.h | 1 + src/drawing/engines/SoftwareDrawingEngine.cpp | 5 +++++ src/drawing/engines/opengl/OpenGLDrawingEngine.cpp | 5 +++++ src/windows/options.c | 1 + 6 files changed, 23 insertions(+) diff --git a/src/drawing/IDrawingEngine.h b/src/drawing/IDrawingEngine.h index 537939ae91..90bee4d6a1 100644 --- a/src/drawing/IDrawingEngine.h +++ b/src/drawing/IDrawingEngine.h @@ -41,6 +41,8 @@ interface IDrawingEngine virtual void Resize(uint32 width, uint32 height) abstract; virtual void SetPalette(SDL_Color * colours) abstract; + virtual void SetUncappedFrameRate(bool uncapped) abstract; + virtual void Invalidate(sint32 left, sint32 top, sint32 right, sint32 bottom) abstract; virtual void Draw() abstract; virtual void CopyRect(sint32 x, sint32 y, sint32 width, sint32 height, sint32 dx, sint32 dy) abstract; diff --git a/src/drawing/NewDrawing.cpp b/src/drawing/NewDrawing.cpp index bbfaec4c7c..e8c7c3b7c9 100644 --- a/src/drawing/NewDrawing.cpp +++ b/src/drawing/NewDrawing.cpp @@ -83,6 +83,7 @@ extern "C" try { _drawingEngine->Initialise(gWindow); + _drawingEngine->SetUncappedFrameRate(gConfigGeneral.uncap_fps == 1); } catch (Exception ex) { @@ -164,6 +165,14 @@ extern "C" } } + void drawing_engine_set_fps_uncapped(bool uncapped) + { + if (_drawingEngine != nullptr) + { + _drawingEngine->SetUncappedFrameRate(uncapped); + } + } + void gfx_set_dirty_blocks(sint16 left, sint16 top, sint16 right, sint16 bottom) { if (_drawingEngine != nullptr) diff --git a/src/drawing/NewDrawing.h b/src/drawing/NewDrawing.h index a017306082..f484f61b63 100644 --- a/src/drawing/NewDrawing.h +++ b/src/drawing/NewDrawing.h @@ -33,6 +33,7 @@ void drawing_engine_dispose(); rct_drawpixelinfo * drawing_engine_get_dpi(); bool drawing_engine_has_dirty_optimisations(); void drawing_engine_invalidate_image(uint32 image); +void drawing_engine_set_fps_uncapped(bool uncapped); #ifdef __cplusplus } diff --git a/src/drawing/engines/SoftwareDrawingEngine.cpp b/src/drawing/engines/SoftwareDrawingEngine.cpp index b9bfbe3f60..5066d7a2e6 100644 --- a/src/drawing/engines/SoftwareDrawingEngine.cpp +++ b/src/drawing/engines/SoftwareDrawingEngine.cpp @@ -327,6 +327,11 @@ public: } } + void SetUncappedFrameRate(bool uncapped) + { + // Not applicable for this engine + } + void Invalidate(sint32 left, sint32 top, sint32 right, sint32 bottom) override { left = Math::Max(left, 0); diff --git a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp index af4f71a8d3..286c8d921f 100644 --- a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp +++ b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp @@ -47,6 +47,7 @@ IDrawingEngine * DrawingEngineFactory::CreateOpenGL() #include "../../IDrawingContext.h" #include "../../IDrawingEngine.h" #include "../../Rain.h" +#include "../../../config.h" extern "C" { @@ -317,6 +318,10 @@ public: _drawingContext->ResetPalette(); } + void SetUncappedFrameRate(bool uncapped) { + SDL_GL_SetSwapInterval(uncapped ? 0 : 1); + } + void Invalidate(sint32 left, sint32 top, sint32 right, sint32 bottom) override { } diff --git a/src/windows/options.c b/src/windows/options.c index 58cd9933cc..daaa9d1c00 100644 --- a/src/windows/options.c +++ b/src/windows/options.c @@ -587,6 +587,7 @@ static void window_options_mouseup(rct_window *w, int widgetIndex) switch (widgetIndex) { case WIDX_UNCAP_FPS_CHECKBOX: gConfigGeneral.uncap_fps ^= 1; + drawing_engine_set_fps_uncapped(gConfigGeneral.uncap_fps); config_save_default(); window_invalidate(w); break; From 8256b7f83b36378779858548adb490ea60a8b722 Mon Sep 17 00:00:00 2001 From: Alexander Overvoorde Date: Sat, 23 Jul 2016 22:37:28 +0200 Subject: [PATCH 21/24] Fix missing override keyword for SetUncappedFrameRate functions --- src/drawing/engines/SoftwareDrawingEngine.cpp | 2 +- src/drawing/engines/opengl/OpenGLDrawingEngine.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/drawing/engines/SoftwareDrawingEngine.cpp b/src/drawing/engines/SoftwareDrawingEngine.cpp index 5066d7a2e6..cad2dfca96 100644 --- a/src/drawing/engines/SoftwareDrawingEngine.cpp +++ b/src/drawing/engines/SoftwareDrawingEngine.cpp @@ -327,7 +327,7 @@ public: } } - void SetUncappedFrameRate(bool uncapped) + void SetUncappedFrameRate(bool uncapped) override { // Not applicable for this engine } diff --git a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp index 286c8d921f..7124bdd50f 100644 --- a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp +++ b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp @@ -318,7 +318,8 @@ public: _drawingContext->ResetPalette(); } - void SetUncappedFrameRate(bool uncapped) { + void SetUncappedFrameRate(bool uncapped) override + { SDL_GL_SetSwapInterval(uncapped ? 0 : 1); } From 1b157dbb318764af412ae26bede6995574742581 Mon Sep 17 00:00:00 2001 From: LRFLEW Date: Sat, 23 Jul 2016 22:50:30 -0500 Subject: [PATCH 22/24] Completely Remove DrawImageMaskedShader from XCode project --- OpenRCT2.xcodeproj/project.pbxproj | 5 ----- 1 file changed, 5 deletions(-) diff --git a/OpenRCT2.xcodeproj/project.pbxproj b/OpenRCT2.xcodeproj/project.pbxproj index ccf9084fd8..0d487ce5d3 100644 --- a/OpenRCT2.xcodeproj/project.pbxproj +++ b/OpenRCT2.xcodeproj/project.pbxproj @@ -503,8 +503,6 @@ D41B74721C2125E50080A7B9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = distribution/osx/Assets.xcassets; sourceTree = SOURCE_ROOT; }; D43407C01D0E14BE00C2B3D4 /* CopyFramebufferShader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CopyFramebufferShader.cpp; sourceTree = ""; }; D43407C11D0E14BE00C2B3D4 /* CopyFramebufferShader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopyFramebufferShader.h; sourceTree = ""; }; - D43407C21D0E14BE00C2B3D4 /* DrawImageMaskedShader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DrawImageMaskedShader.cpp; sourceTree = ""; }; - D43407C31D0E14BE00C2B3D4 /* DrawImageMaskedShader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DrawImageMaskedShader.h; sourceTree = ""; }; D43407C41D0E14BE00C2B3D4 /* DrawImageShader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DrawImageShader.cpp; sourceTree = ""; }; D43407C51D0E14BE00C2B3D4 /* DrawImageShader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DrawImageShader.h; sourceTree = ""; }; D43407C61D0E14BE00C2B3D4 /* DrawLineShader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DrawLineShader.cpp; sourceTree = ""; }; @@ -1299,8 +1297,6 @@ children = ( D43407C01D0E14BE00C2B3D4 /* CopyFramebufferShader.cpp */, D43407C11D0E14BE00C2B3D4 /* CopyFramebufferShader.h */, - D43407C21D0E14BE00C2B3D4 /* DrawImageMaskedShader.cpp */, - D43407C31D0E14BE00C2B3D4 /* DrawImageMaskedShader.h */, D43407C41D0E14BE00C2B3D4 /* DrawImageShader.cpp */, D43407C51D0E14BE00C2B3D4 /* DrawImageShader.h */, D43407C61D0E14BE00C2B3D4 /* DrawLineShader.cpp */, @@ -2409,7 +2405,6 @@ C686F9311CDBC3B7009F9BFC /* ghost_train.c in Sources */, D44272821CC81B3200D84D28 /* shortcut_key_change.c in Sources */, D442722A1CC81B3200D84D28 /* localisation.c in Sources */, - D43407D71D0E14BE00C2B3D4 /* DrawImageMaskedShader.cpp in Sources */, D44272731CC81B3200D84D28 /* new_ride.c in Sources */, D442721A1CC81B3200D84D28 /* console.c in Sources */, D44271FB1CC81B3200D84D28 /* ScreenshotCommands.cpp in Sources */, From 96be7bd861c36c56fec9abfff63f9b12670f11ed Mon Sep 17 00:00:00 2001 From: Alexander Overvoorde Date: Sun, 24 Jul 2016 21:01:33 +0200 Subject: [PATCH 23/24] Update changelog with improved FPS calculation --- distribution/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 6cda7d3d8e..1a334ae3b3 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -20,6 +20,7 @@ - Feature: Objects directory is scanned recursively. - Improve: Performance and reliability of loading objects. - Improve: Screenshots are now saved with the name of the park and the current date and time. +- Improve: More accurate frame rate calculation - Removed: BMP screenshots. - Removed: Intamin and Phoenix easter eggs. - Fix: [#1038] Guest List is out of order. From 3842728f38227553afcf67358a215d8d0bc5d284 Mon Sep 17 00:00:00 2001 From: Alexander Overvoorde Date: Wed, 27 Jul 2016 16:31:25 +0200 Subject: [PATCH 24/24] Fix indentation and code style in various files --- .../engines/opengl/OpenGLDrawingEngine.cpp | 18 ++++--- src/drawing/engines/opengl/TextureCache.cpp | 28 ++++++---- src/drawing/engines/opengl/TextureCache.h | 52 +++++++++++++------ src/rct2.c | 16 +++--- src/windows/options.c | 2 +- 5 files changed, 75 insertions(+), 41 deletions(-) diff --git a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp index 7124bdd50f..119729a808 100644 --- a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp +++ b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp @@ -899,15 +899,18 @@ void OpenGLDrawingContext::DrawGlyph(uint32 image, sint32 x, sint32 y, uint8 * p _commandBuffers.images.push_back(command); } -void OpenGLDrawingContext::FlushCommandBuffers() { +void OpenGLDrawingContext::FlushCommandBuffers() +{ FlushRectangles(); FlushLines(); FlushImages(); } -void OpenGLDrawingContext::FlushRectangles() { - for (const auto& command : _commandBuffers.rectangles) { +void OpenGLDrawingContext::FlushRectangles() +{ + for (const auto& command : _commandBuffers.rectangles) + { _fillRectShader->Use(); _fillRectShader->SetFlags(command.flags); _fillRectShader->SetSourceFramebuffer(command.sourceFramebuffer); @@ -921,7 +924,8 @@ void OpenGLDrawingContext::FlushRectangles() { } void OpenGLDrawingContext::FlushLines() { - for (const auto& command : _commandBuffers.lines) { + for (const auto& command : _commandBuffers.lines) + { _drawLineShader->Use(); _drawLineShader->SetColour(command.colour); _drawLineShader->SetClip(command.clip[0], command.clip[1], command.clip[2], command.clip[3]); @@ -931,7 +935,8 @@ void OpenGLDrawingContext::FlushLines() { _commandBuffers.lines.clear(); } -void OpenGLDrawingContext::FlushImages() { +void OpenGLDrawingContext::FlushImages() +{ if (_commandBuffers.images.size() == 0) return; OpenGLAPI::SetTexture(0, GL_TEXTURE_2D_ARRAY, _textureCache->GetAtlasesTexture()); @@ -939,7 +944,8 @@ void OpenGLDrawingContext::FlushImages() { std::vector instances; instances.reserve(_commandBuffers.images.size()); - for (const auto& command : _commandBuffers.images) { + for (const auto& command : _commandBuffers.images) + { DrawImageInstance instance; instance.clip = {command.clip[0], command.clip[1], command.clip[2], command.clip[3]}; diff --git a/src/drawing/engines/opengl/TextureCache.cpp b/src/drawing/engines/opengl/TextureCache.cpp index fd8b9e0561..0608ed0e0f 100644 --- a/src/drawing/engines/opengl/TextureCache.cpp +++ b/src/drawing/engines/opengl/TextureCache.cpp @@ -82,8 +82,10 @@ CachedTextureInfo TextureCache::GetOrLoadGlyphTexture(uint32 image, uint8 * pale return cacheInfo; } -void TextureCache::CreateAtlasesTexture() { - if (!_atlasesTextureInitialised) { +void TextureCache::CreateAtlasesTexture() +{ + if (!_atlasesTextureInitialised) + { // Determine width and height to use for texture atlases glGetIntegerv(GL_MAX_TEXTURE_SIZE, &_atlasesTextureDimensions); if (_atlasesTextureDimensions > TEXTURE_CACHE_MAX_ATLAS_SIZE) { @@ -106,13 +108,14 @@ void TextureCache::CreateAtlasesTexture() { } } -void TextureCache::EnlargeAtlasesTexture(GLuint newEntries) { +void TextureCache::EnlargeAtlasesTexture(GLuint newEntries) +{ CreateAtlasesTexture(); GLuint newIndices = _atlasesTextureIndices + newEntries; // Retrieve current array data - std::vector oldPixels(_atlasesTextureDimensions * _atlasesTextureDimensions * _atlasesTextureIndices); + auto oldPixels = std::vector(_atlasesTextureDimensions * _atlasesTextureDimensions * _atlasesTextureIndices); glGetTexImage(GL_TEXTURE_2D_ARRAY, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, oldPixels.data()); // Reallocate array @@ -168,18 +171,22 @@ void * TextureCache::GetImageAsARGB(uint32 image, uint32 tertiaryColour, uint32 return pixels32; } -CachedTextureInfo TextureCache::AllocateImage(int imageWidth, int imageHeight) { +CachedTextureInfo TextureCache::AllocateImage(int imageWidth, int imageHeight) +{ CreateAtlasesTexture(); // Find an atlas that fits this image - for (Atlas& atlas : _atlases) { - if (atlas.GetFreeSlots() > 0 && atlas.IsImageSuitable(imageWidth, imageHeight)) { + for (Atlas& atlas : _atlases) + { + if (atlas.GetFreeSlots() > 0 && atlas.IsImageSuitable(imageWidth, imageHeight)) + { return atlas.Allocate(imageWidth, imageHeight); } } // If there is no such atlas, then create a new one - if ((int) _atlases.size() >= _atlasesTextureIndicesLimit) { + if ((int) _atlases.size() >= _atlasesTextureIndicesLimit) + { throw std::runtime_error("more texture atlases required, but device limit reached!"); } @@ -187,7 +194,7 @@ CachedTextureInfo TextureCache::AllocateImage(int imageWidth, int imageHeight) { int atlasSize = (int) powf(2, (float) Atlas::CalculateImageSizeOrder(imageWidth, imageHeight)); #ifdef DEBUG - printf("new texture atlas #%d (size %d) allocated\n", atlasIndex, atlasSize); + log_verbose("new texture atlas #%d (size %d) allocated\n", atlasIndex, atlasSize); #endif _atlases.push_back(std::move(Atlas(atlasIndex, atlasSize))); @@ -296,7 +303,8 @@ void TextureCache::DeleteDPI(rct_drawpixelinfo* dpi) delete dpi; } -GLuint TextureCache::GetAtlasesTexture() { +GLuint TextureCache::GetAtlasesTexture() +{ return _atlasesTexture; } diff --git a/src/drawing/engines/opengl/TextureCache.h b/src/drawing/engines/opengl/TextureCache.h index f662663aeb..bee3e055b6 100644 --- a/src/drawing/engines/opengl/TextureCache.h +++ b/src/drawing/engines/opengl/TextureCache.h @@ -16,9 +16,9 @@ #pragma once +#include #include #include -#include #include #include "../../../common.h" #include "OpenGLAPI.h" @@ -62,7 +62,8 @@ constexpr int TEXTURE_CACHE_MAX_ATLAS_SIZE = 2048; constexpr int TEXTURE_CACHE_SMALLEST_SLOT = 32; // Location of an image (texture atlas index, slot and normalized coordinates) -struct CachedTextureInfo { +struct CachedTextureInfo +{ GLuint index; GLuint slot; vec4i bounds; @@ -72,7 +73,8 @@ struct CachedTextureInfo { // Represents a texture atlas that images of a given maximum size can be allocated from // Atlases are all stored in the same 2D texture array, occupying the specified index // Slots in atlases are always squares. -class Atlas { +class Atlas +{ private: GLuint _index; int _imageSize; @@ -82,12 +84,14 @@ private: int _cols, _rows; public: - Atlas(GLuint index, int imageSize) { + Atlas(GLuint index, int imageSize) + { _index = index; _imageSize = imageSize; } - void Initialise(int atlasWidth, int atlasHeight) { + void Initialise(int atlasWidth, int atlasHeight) + { _atlasWidth = atlasWidth; _atlasHeight = atlasHeight; @@ -95,12 +99,14 @@ public: _rows = _atlasHeight / _imageSize; _freeSlots.resize(_cols * _rows); - for (size_t i = 0; i < _freeSlots.size(); i++) { + for (size_t i = 0; i < _freeSlots.size(); i++) + { _freeSlots[i] = i; } } - CachedTextureInfo Allocate(int actualWidth, int actualHeight) { + CachedTextureInfo Allocate(int actualWidth, int actualHeight) + { assert(_freeSlots.size() > 0); GLuint slot = _freeSlots.back(); @@ -108,10 +114,17 @@ public: auto bounds = GetSlotCoordinates(slot, actualWidth, actualHeight); - return {_index, slot, bounds, NormalizeCoordinates(bounds)}; + return + { + _index, + slot, + bounds, + NormalizeCoordinates(bounds) + }; } - void Free(const CachedTextureInfo& info) { + void Free(const CachedTextureInfo& info) + { assert(_index == info.index); _freeSlots.push_back(info.slot); @@ -119,18 +132,21 @@ public: // Checks if specified image would be tightly packed in this atlas // by checking if it is within the right power of 2 range - bool IsImageSuitable(int actualWidth, int actualHeight) const { + bool IsImageSuitable(int actualWidth, int actualHeight) const + { int imageOrder = CalculateImageSizeOrder(actualWidth, actualHeight); int atlasOrder = (int) log2(_imageSize); return imageOrder == atlasOrder; } - int GetFreeSlots() const { + int GetFreeSlots() const + { return (int) _freeSlots.size(); } - static int CalculateImageSizeOrder(int actualWidth, int actualHeight) { + static int CalculateImageSizeOrder(int actualWidth, int actualHeight) + { int actualSize = std::max(actualWidth, actualHeight); if (actualSize < TEXTURE_CACHE_SMALLEST_SLOT) { @@ -141,11 +157,13 @@ public: } private: - vec4i GetSlotCoordinates(GLuint slot, int actualWidth, int actualHeight) const { + vec4i GetSlotCoordinates(GLuint slot, int actualWidth, int actualHeight) const + { int row = slot / _cols; int col = slot % _cols; - return vec4i{ + return vec4i + { _imageSize * col, _imageSize * row, _imageSize * col + actualWidth, @@ -153,8 +171,10 @@ private: }; } - vec4f NormalizeCoordinates(const vec4i& coords) const { - return vec4f{ + vec4f NormalizeCoordinates(const vec4i& coords) const + { + return vec4f + { coords.x / (float) _atlasWidth, coords.y / (float) _atlasHeight, coords.z / (float) _atlasWidth, diff --git a/src/rct2.c b/src/rct2.c index 7fccdfcb4e..50b9827125 100644 --- a/src/rct2.c +++ b/src/rct2.c @@ -307,16 +307,16 @@ static int _frames; static void rct2_measure_fps() { - _frames++; + _frames++; - time_t currentTime = time(NULL); + time_t currentTime = time(NULL); - if (currentTime != _lastSecond) { - _currentFPS = _frames; - _frames = 0; - } + if (currentTime != _lastSecond) { + _currentFPS = _frames; + _frames = 0; + } - _lastSecond = currentTime; + _lastSecond = currentTime; } static void rct2_draw_fps(rct_drawpixelinfo *dpi) @@ -333,7 +333,7 @@ static void rct2_draw_fps(rct_drawpixelinfo *dpi) ch = utf8_write_codepoint(ch, FORMAT_MEDIUMFONT); ch = utf8_write_codepoint(ch, FORMAT_OUTLINE); ch = utf8_write_codepoint(ch, FORMAT_WHITE); - + sprintf(ch, "%d", _currentFPS); // Draw Text diff --git a/src/windows/options.c b/src/windows/options.c index daaa9d1c00..8d7692b71b 100644 --- a/src/windows/options.c +++ b/src/windows/options.c @@ -587,7 +587,7 @@ static void window_options_mouseup(rct_window *w, int widgetIndex) switch (widgetIndex) { case WIDX_UNCAP_FPS_CHECKBOX: gConfigGeneral.uncap_fps ^= 1; - drawing_engine_set_fps_uncapped(gConfigGeneral.uncap_fps); + drawing_engine_set_fps_uncapped(gConfigGeneral.uncap_fps); config_save_default(); window_invalidate(w); break;