mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2025-12-11 10:02:27 +01:00
Improve performance of panning the viewport with OpenGL renderer (#24413)
* Improve performance of panning the viewport with OpenGL renderer * Use a shader to perform the copy rect operation * Clear the frame buffer after its initialized * Handle Y flip in shader, be explicit about FBO draw state * Target 330 core, remove the y flip handling * Explicitly use GL_RGB8 and not GL_RGB * Add more error handling, clear depth when depth is created * Lets try this * Make sure blend and depth are disabled * Bind the source fbo for reading * Try this alternative approach * Set read and draw buffer before glBlitFramebuffer * Apple is forcing my hand * Update changelog.txt
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
#version 150
|
||||
#version 330 core
|
||||
|
||||
uniform vec4 uPalette[256];
|
||||
uniform usampler2D uTexture;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#version 150
|
||||
#version 330 core
|
||||
|
||||
in vec4 vPosition;
|
||||
in vec2 vTextureCoordinate;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#version 150
|
||||
#version 330 core
|
||||
|
||||
// clang-format off
|
||||
uniform usampler2D uOpaqueTex;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#version 150
|
||||
#version 330 core
|
||||
|
||||
in vec4 vPosition;
|
||||
in vec2 vTextureCoordinate;
|
||||
|
||||
11
data/shaders/copyrect.frag
Normal file
11
data/shaders/copyrect.frag
Normal file
@@ -0,0 +1,11 @@
|
||||
#version 330 core
|
||||
|
||||
in vec2 fTextureCoordinate;
|
||||
out vec4 fragColor;
|
||||
|
||||
uniform sampler2D uTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
fragColor = texture(uTexture, fTextureCoordinate);
|
||||
}
|
||||
17
data/shaders/copyrect.vert
Normal file
17
data/shaders/copyrect.vert
Normal file
@@ -0,0 +1,17 @@
|
||||
#version 330 core
|
||||
|
||||
in vec2 vPosition;
|
||||
in vec2 vTextureCoordinate;
|
||||
|
||||
out vec2 fTextureCoordinate;
|
||||
|
||||
uniform vec4 uSourceRect;
|
||||
uniform vec2 uTextureSize;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = vec4(vPosition, 0.0, 1.0);
|
||||
vec2 srcPos = vec2(uSourceRect.xy);
|
||||
vec2 srcSize = vec2(uSourceRect.zw);
|
||||
fTextureCoordinate = (srcPos + vTextureCoordinate * srcSize) / uTextureSize;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
#version 150
|
||||
#version 330 core
|
||||
|
||||
flat in uint fColour;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#version 150
|
||||
#version 330 core
|
||||
|
||||
// Allows for about 8 million draws per frame
|
||||
const float DEPTH_INCREMENT = 1.0 / float(1u << 22u);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#version 150
|
||||
#version 330 core
|
||||
|
||||
// clang-format off
|
||||
const int MASK_REMAP_COUNT = 3;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#version 150
|
||||
#version 330 core
|
||||
|
||||
// Allows for about 8 million draws per frame
|
||||
const float DEPTH_INCREMENT = 1.0 / float(1u << 22u);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
- Improved: [#24364] Improve the fallback vehicle sprites for Zero G Rolls, and allow small ones to be built without cheats if the fallbacks are available.
|
||||
- Improved: [#24368] Clicking the in-game update notication now leads to a more user-friendly download page.
|
||||
- Improved: [#24409] Steam installs of RCT Classic are now detected automatically.
|
||||
- Improved: [#24413] Better performance when moving the viewport on Windows and Linux platforms.
|
||||
- Improved: [#24417] Improve the fallback vehicle sprites for Dive Loops.
|
||||
- Change: [#24342] g2.dat is now split into g2.dat and fonts.dat.
|
||||
- Change: [#24362] The Windows installer now prevents installing to the same folder as RollerCoaster Tycoon 2 or Classic.
|
||||
|
||||
96
src/openrct2-ui/drawing/engines/opengl/CopyRectShader.cpp
Normal file
96
src/openrct2-ui/drawing/engines/opengl/CopyRectShader.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
/*****************************************************************************
|
||||
* Copyright (c) 2014-2025 OpenRCT2 developers
|
||||
*
|
||||
* For a complete list of all authors, please refer to contributors.md
|
||||
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||
*
|
||||
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef DISABLE_OPENGL
|
||||
|
||||
#include "CopyRectShader.h"
|
||||
|
||||
using namespace OpenRCT2::Ui;
|
||||
|
||||
namespace
|
||||
{
|
||||
struct VDStruct
|
||||
{
|
||||
GLfloat position[2];
|
||||
GLfloat texturecoordinate[2];
|
||||
};
|
||||
} // namespace
|
||||
|
||||
constexpr VDStruct kVertexData[4] = {
|
||||
{ -1.0f, -1.0f, 0.0f, 0.0f },
|
||||
{ 1.0f, -1.0f, 1.0f, 0.0f },
|
||||
{ -1.0f, 1.0f, 0.0f, 1.0f },
|
||||
{ 1.0f, 1.0f, 1.0f, 1.0f },
|
||||
};
|
||||
|
||||
CopyRectShader::CopyRectShader()
|
||||
: OpenGLShaderProgram("copyrect")
|
||||
{
|
||||
GetLocations();
|
||||
|
||||
glCall(glGenBuffers, 1, &_vbo);
|
||||
glCall(glGenVertexArrays, 1, &_vao);
|
||||
|
||||
glCall(glBindBuffer, GL_ARRAY_BUFFER, _vbo);
|
||||
glCall(glBufferData, GL_ARRAY_BUFFER, sizeof(kVertexData), kVertexData, GL_STATIC_DRAW);
|
||||
|
||||
glCall(glBindVertexArray, _vao);
|
||||
glCall(
|
||||
glVertexAttribPointer, vPosition, 2, GL_FLOAT, GL_FALSE, glSizeOf<VDStruct>(),
|
||||
reinterpret_cast<void*>(offsetof(VDStruct, position)));
|
||||
glCall(
|
||||
glVertexAttribPointer, vTextureCoordinate, 2, GL_FLOAT, GL_FALSE, glSizeOf<VDStruct>(),
|
||||
reinterpret_cast<void*>(offsetof(VDStruct, texturecoordinate)));
|
||||
|
||||
glCall(glEnableVertexAttribArray, vPosition);
|
||||
glCall(glEnableVertexAttribArray, vTextureCoordinate);
|
||||
|
||||
Use();
|
||||
glCall(glUniform1i, uTexture, 0); // Bind texture to unit 0
|
||||
}
|
||||
|
||||
CopyRectShader::~CopyRectShader()
|
||||
{
|
||||
glCall(glDeleteBuffers, 1, &_vbo);
|
||||
glCall(glDeleteVertexArrays, 1, &_vao);
|
||||
}
|
||||
|
||||
void CopyRectShader::GetLocations()
|
||||
{
|
||||
uTexture = GetUniformLocation("uTexture");
|
||||
uSourceRect = GetUniformLocation("uSourceRect");
|
||||
uTextureSize = GetUniformLocation("uTextureSize");
|
||||
vPosition = GetAttributeLocation("vPosition");
|
||||
vTextureCoordinate = GetAttributeLocation("vTextureCoordinate");
|
||||
}
|
||||
|
||||
void CopyRectShader::SetTexture(GLuint texture)
|
||||
{
|
||||
OpenGLAPI::SetTexture(0, GL_TEXTURE_2D, texture);
|
||||
}
|
||||
|
||||
void CopyRectShader::SetSourceRect(int32_t x, int32_t y, int32_t width, int32_t height)
|
||||
{
|
||||
glUniform4f(
|
||||
uSourceRect, static_cast<GLfloat>(x), static_cast<GLfloat>(y), static_cast<GLfloat>(width),
|
||||
static_cast<GLfloat>(height));
|
||||
}
|
||||
|
||||
void CopyRectShader::SetTextureSize(int32_t width, int32_t height)
|
||||
{
|
||||
glUniform2f(uTextureSize, static_cast<GLfloat>(width), static_cast<GLfloat>(height));
|
||||
}
|
||||
|
||||
void CopyRectShader::Draw()
|
||||
{
|
||||
glCall(glBindVertexArray, _vao);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
|
||||
#endif /* DISABLE_OPENGL */
|
||||
43
src/openrct2-ui/drawing/engines/opengl/CopyRectShader.h
Normal file
43
src/openrct2-ui/drawing/engines/opengl/CopyRectShader.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*****************************************************************************
|
||||
* Copyright (c) 2014-2025 OpenRCT2 developers
|
||||
*
|
||||
* For a complete list of all authors, please refer to contributors.md
|
||||
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||
*
|
||||
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||
*****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GLSLTypes.h"
|
||||
#include "OpenGLShaderProgram.h"
|
||||
|
||||
namespace OpenRCT2::Ui
|
||||
{
|
||||
class CopyRectShader final : public OpenGLShaderProgram
|
||||
{
|
||||
private:
|
||||
GLint uTexture{ -1 };
|
||||
GLint uSourceRect{ -1 };
|
||||
GLint uTextureSize{ -1 };
|
||||
|
||||
GLint vPosition{ -1 };
|
||||
GLint vTextureCoordinate{ -1 };
|
||||
|
||||
GLuint _vbo{};
|
||||
GLuint _vao{};
|
||||
|
||||
public:
|
||||
CopyRectShader();
|
||||
~CopyRectShader() override;
|
||||
|
||||
static void SetTexture(GLuint texture);
|
||||
void SetSourceRect(int32_t x, int32_t y, int32_t width, int32_t height);
|
||||
void SetTextureSize(int32_t width, int32_t height);
|
||||
|
||||
void Draw();
|
||||
|
||||
private:
|
||||
void GetLocations();
|
||||
};
|
||||
} // namespace OpenRCT2::Ui
|
||||
@@ -44,6 +44,13 @@
|
||||
#define glGetIntegerv __static__glGetIntegerv
|
||||
#define glGetTexImage __static__glGetTexImage
|
||||
#define glTexSubImage2D __static__glTexSubImage2D
|
||||
#define glDrawBuffers __static__glDrawBuffers
|
||||
#define glCheckFramebufferStatus __static__glCheckFramebufferStatus
|
||||
#define glClearDepth __static__glClearDepth
|
||||
#define glReadBuffer __static__glReadBuffer
|
||||
#define glDrawBuffer __static__glDrawBuffer
|
||||
|
||||
// END [Do not define 1.1 function signatures]
|
||||
|
||||
#endif
|
||||
|
||||
@@ -81,6 +88,11 @@
|
||||
#undef glGetIntegerv
|
||||
#undef glGetTexImage
|
||||
#undef glTexSubImage2D
|
||||
#undef glDrawBuffers
|
||||
#undef glCheckFramebufferStatus
|
||||
#undef glClearDepth
|
||||
#undef glReadBuffer
|
||||
#undef glDrawBuffer
|
||||
|
||||
// 1.1 function signatures
|
||||
using PFNGLBEGINPROC = void(APIENTRYP)(GLenum mode);
|
||||
@@ -116,6 +128,11 @@ using PFNGLGETTEXIMAGEPROC = void(APIENTRYP)(GLenum target, GLint level, GLenum
|
||||
using PFNGLTEXSUBIMAGE2D = void(APIENTRYP)(
|
||||
GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
|
||||
const GLvoid* pixels);
|
||||
using PFNGLDRAWBUFFERSPROC = void(APIENTRYP)(GLsizei n, const GLenum* bufs);
|
||||
using PFNGLCHECKFRAMEBUFFERSTATUSPROC = GLenum(APIENTRYP)(GLenum target);
|
||||
using PFNGLCLEARDEPTHPROC = void(APIENTRYP)(GLdouble depth);
|
||||
using PFNGLREADBUFFERPROC = void(APIENTRYP)(GLenum mode);
|
||||
using PFNGLDRAWBUFFERPROC = void(APIENTRYP)(GLenum mode);
|
||||
|
||||
#define OPENGL_PROC(TYPE, PROC) extern TYPE PROC;
|
||||
#include "OpenGLAPIProc.h"
|
||||
|
||||
@@ -91,6 +91,7 @@ OPENGL_PROC(PFNGLUNIFORM2FPROC, glUniform2f)
|
||||
OPENGL_PROC(PFNGLUNIFORM4FPROC, glUniform4f)
|
||||
OPENGL_PROC(PFNGLUNIFORM4IPROC, glUniform4i)
|
||||
OPENGL_PROC(PFNGLUNIFORM4FVPROC, glUniform4fv)
|
||||
OPENGL_PROC(PFNGLUNIFORM2FVPROC, glUniform2fv)
|
||||
OPENGL_PROC(PFNGLUSEPROGRAMPROC, glUseProgram)
|
||||
OPENGL_PROC(PFNGLVERTEXATTRIBIPOINTERPROC, glVertexAttribIPointer)
|
||||
OPENGL_PROC(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer)
|
||||
@@ -103,3 +104,8 @@ extern "C" void glVertexAttribDivisor(GLuint index, GLuint divisor);
|
||||
#endif
|
||||
OPENGL_PROC(PFNGLBLENDFUNCSEPARATEPROC, glBlendFuncSeparate)
|
||||
OPENGL_PROC(PFNGLTEXSUBIMAGE2D, glTexSubImage2D)
|
||||
OPENGL_PROC(PFNGLDRAWBUFFERSPROC, glDrawBuffers)
|
||||
OPENGL_PROC(PFNGLCHECKFRAMEBUFFERSTATUSPROC, glCheckFramebufferStatus)
|
||||
OPENGL_PROC(PFNGLCLEARDEPTHPROC, glClearDepth)
|
||||
OPENGL_PROC(PFNGLREADBUFFERPROC, glReadBuffer)
|
||||
OPENGL_PROC(PFNGLDRAWBUFFERPROC, glDrawBuffer)
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "../DrawingEngineFactory.hpp"
|
||||
#include "ApplyPaletteShader.h"
|
||||
#include "CopyRectShader.h"
|
||||
#include "DrawCommands.h"
|
||||
#include "DrawLineShader.h"
|
||||
#include "DrawRectShader.h"
|
||||
@@ -208,9 +209,12 @@ private:
|
||||
std::unique_ptr<OpenGLDrawingContext> _drawingContext;
|
||||
|
||||
std::unique_ptr<ApplyPaletteShader> _applyPaletteShader;
|
||||
std::unique_ptr<CopyRectShader> _copyRectShader;
|
||||
|
||||
std::unique_ptr<OpenGLFramebuffer> _screenFramebuffer;
|
||||
std::unique_ptr<OpenGLFramebuffer> _scaleFramebuffer;
|
||||
std::unique_ptr<OpenGLFramebuffer> _smoothScaleFramebuffer;
|
||||
std::unique_ptr<OpenGLFramebuffer> _tempFramebuffer;
|
||||
OpenGLWeatherDrawer _weatherDrawer;
|
||||
InvalidationGrid _invalidationGrid;
|
||||
|
||||
@@ -236,9 +240,9 @@ public:
|
||||
void Initialise() override
|
||||
{
|
||||
OpenGLVersion requiredVersion = kOpenGLMinimumRequiredVersion;
|
||||
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);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
|
||||
_context = SDL_GL_CreateContext(_window);
|
||||
if (_context == nullptr)
|
||||
@@ -257,6 +261,7 @@ public:
|
||||
_drawingContext->Initialise();
|
||||
|
||||
_applyPaletteShader = std::make_unique<ApplyPaletteShader>();
|
||||
_copyRectShader = std::make_unique<CopyRectShader>();
|
||||
}
|
||||
|
||||
void Resize(uint32_t width, uint32_t height) override
|
||||
@@ -266,6 +271,7 @@ public:
|
||||
ConfigureDirtyGrid();
|
||||
|
||||
_drawingContext->Resize(width, height);
|
||||
_tempFramebuffer = std::make_unique<OpenGLFramebuffer>(width, height);
|
||||
|
||||
_drawingContext->StartNewDraw();
|
||||
_drawingContext->Clear(_mainRT, PaletteIndex::pi10);
|
||||
@@ -414,24 +420,70 @@ public:
|
||||
|
||||
_drawingContext->FlushCommandBuffers();
|
||||
|
||||
OpenGLFramebuffer& framebuffer = _drawingContext->GetFinalFramebuffer();
|
||||
framebuffer.Bind();
|
||||
framebuffer.GetPixels(_mainRT);
|
||||
auto& framebuffer = _drawingContext->GetFinalFramebuffer();
|
||||
|
||||
const int32_t texWidth = static_cast<int32_t>(framebuffer.GetWidth());
|
||||
const int32_t texHeight = static_cast<int32_t>(framebuffer.GetHeight());
|
||||
|
||||
// Originally 0x00683359
|
||||
// Adjust for move off screen
|
||||
// NOTE: when zooming, there can be x, y, dx, dy combinations that go off the
|
||||
// screen; hence the checks. This code should ultimately not be called when
|
||||
// zooming because this function is specific to updating the screen on move
|
||||
int32_t lmargin = std::min(x - dx, 0);
|
||||
int32_t rmargin = std::min(static_cast<int32_t>(_width) - (x - dx + width), 0);
|
||||
int32_t rmargin = std::min(texWidth - (x - dx + width), 0);
|
||||
int32_t tmargin = std::min(y - dy, 0);
|
||||
int32_t bmargin = std::min(static_cast<int32_t>(_height) - (y - dy + height), 0);
|
||||
int32_t bmargin = std::min(texHeight - (y - dy + height), 0);
|
||||
x -= lmargin;
|
||||
y -= tmargin;
|
||||
width += lmargin + rmargin;
|
||||
height += tmargin + bmargin;
|
||||
|
||||
if (width <= 0 || height <= 0)
|
||||
return;
|
||||
|
||||
#ifndef __MACOSX__
|
||||
|
||||
auto& tempBuffer = *_tempFramebuffer;
|
||||
|
||||
const auto flipYAxis = [texHeight](int32_t yPos, int32_t h) {
|
||||
// Convert to OpenGL bottom-left origin coords.
|
||||
return texHeight - yPos - h;
|
||||
};
|
||||
|
||||
int32_t srcX = x - dx;
|
||||
int32_t srcY = flipYAxis(y - dy, height);
|
||||
int32_t destX = x;
|
||||
int32_t destY = flipYAxis(y, height);
|
||||
|
||||
glCall(glDisable, GL_BLEND);
|
||||
glCall(glDisable, GL_DEPTH_TEST);
|
||||
|
||||
// First pass: Copy from main to temp
|
||||
GLuint mainTexture = framebuffer.GetTexture();
|
||||
tempBuffer.BindDraw();
|
||||
framebuffer.BindRead();
|
||||
glCall(glViewport, 0, 0, width, height);
|
||||
_copyRectShader->Use();
|
||||
_copyRectShader->SetTexture(mainTexture);
|
||||
_copyRectShader->SetSourceRect(srcX, srcY, width, height);
|
||||
_copyRectShader->SetTextureSize(texWidth, texHeight);
|
||||
_copyRectShader->Draw();
|
||||
|
||||
// Second pass: Copy from temp to main
|
||||
GLuint tempTexture = tempBuffer.GetTexture();
|
||||
framebuffer.BindDraw();
|
||||
tempBuffer.BindRead();
|
||||
glCall(glViewport, destX, destY, width, height);
|
||||
_copyRectShader->Use();
|
||||
_copyRectShader->SetTexture(tempTexture);
|
||||
_copyRectShader->SetSourceRect(0, 0, width, height);
|
||||
_copyRectShader->SetTextureSize(texWidth, texHeight);
|
||||
_copyRectShader->Draw();
|
||||
|
||||
#else
|
||||
|
||||
// Slow but functional path for MacOS, OpenGL is deprecated on MacOS
|
||||
// and there seems to be issues that aren't present on other platforms.
|
||||
|
||||
framebuffer.GetPixels(_mainRT);
|
||||
|
||||
int32_t stride = _mainRT.LineStride();
|
||||
uint8_t* to = _mainRT.bits + y * stride + x;
|
||||
uint8_t* from = _mainRT.bits + (y - dy) * stride + x - dx;
|
||||
@@ -453,6 +505,8 @@ public:
|
||||
}
|
||||
|
||||
framebuffer.SetPixels(_mainRT);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
IDrawingContext* GetDrawingContext() override
|
||||
|
||||
@@ -33,20 +33,22 @@ OpenGLFramebuffer::OpenGLFramebuffer(int32_t width, int32_t height, bool depth,
|
||||
_width = width;
|
||||
_height = height;
|
||||
|
||||
glGenTextures(1, &_texture);
|
||||
glBindTexture(GL_TEXTURE_2D, _texture);
|
||||
glCall(glGenTextures, 1, &_texture);
|
||||
glCall(glBindTexture, GL_TEXTURE_2D, _texture);
|
||||
if (integer)
|
||||
{
|
||||
int internalFormat = word ? GL_R16UI : GL_R8UI;
|
||||
int type = word ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE;
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, GL_RED_INTEGER, type, nullptr);
|
||||
glCall(glTexImage2D, GL_TEXTURE_2D, 0, internalFormat, width, height, 0, GL_RED_INTEGER, type, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
|
||||
glCall(glTexImage2D, GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
}
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glCall(glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glCall(glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glCall(glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glCall(glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
if (depth)
|
||||
{
|
||||
@@ -57,36 +59,125 @@ OpenGLFramebuffer::OpenGLFramebuffer(int32_t width, int32_t height, bool depth,
|
||||
_depth = 0;
|
||||
}
|
||||
|
||||
glGenFramebuffers(1, &_id);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, _id);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _depth, 0);
|
||||
glCall(glGenFramebuffers, 1, &_id);
|
||||
glCall(glBindFramebuffer, GL_FRAMEBUFFER, _id);
|
||||
glCall(glFramebufferTexture2D, GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture, 0);
|
||||
|
||||
if (depth)
|
||||
{
|
||||
glCall(glFramebufferTexture2D, GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _depth, 0);
|
||||
}
|
||||
|
||||
// Verify completeness
|
||||
const GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE)
|
||||
{
|
||||
const char* errorMsg = "Unknown error";
|
||||
switch (status)
|
||||
{
|
||||
case GL_FRAMEBUFFER_UNDEFINED:
|
||||
errorMsg = "Undefined";
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
||||
errorMsg = "Incomplete attachment";
|
||||
break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
|
||||
errorMsg = "Missing attachment";
|
||||
break;
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED:
|
||||
errorMsg = "Unsupported combination";
|
||||
break;
|
||||
}
|
||||
LOG_ERROR("Framebuffer incomplete: (%u) %s", status, errorMsg);
|
||||
}
|
||||
|
||||
const GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0 };
|
||||
glCall(glDrawBuffers, 1, drawBuffers);
|
||||
|
||||
// Clear the framebuffer.
|
||||
glCall(glClearColor, 0, 0, 0, 0);
|
||||
|
||||
if (depth)
|
||||
{
|
||||
glCall(glClearDepth, 1.0f);
|
||||
glCall(glClear, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
else
|
||||
{
|
||||
glCall(glClear, GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
glCall(glBindFramebuffer, GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
OpenGLFramebuffer::~OpenGLFramebuffer()
|
||||
{
|
||||
if (_id != kBackBufferID)
|
||||
{
|
||||
glDeleteTextures(1, &_texture);
|
||||
glDeleteTextures(1, &_depth);
|
||||
glDeleteFramebuffers(1, &_id);
|
||||
glCall(glDeleteTextures, 1, &_texture);
|
||||
glCall(glDeleteTextures, 1, &_depth);
|
||||
glCall(glDeleteFramebuffers, 1, &_id);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLFramebuffer::Bind() const
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, _id);
|
||||
glViewport(0, 0, static_cast<GLsizei>(_width), static_cast<GLsizei>(_height));
|
||||
glCall(glBindFramebuffer, GL_FRAMEBUFFER, _id);
|
||||
glCall(glViewport, 0, 0, static_cast<GLsizei>(_width), static_cast<GLsizei>(_height));
|
||||
}
|
||||
|
||||
void OpenGLFramebuffer::BindDraw() const
|
||||
{
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _id);
|
||||
glCall(glBindFramebuffer, GL_DRAW_FRAMEBUFFER, _id);
|
||||
}
|
||||
|
||||
void OpenGLFramebuffer::BindRead() const
|
||||
{
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, _id);
|
||||
glCall(glBindFramebuffer, GL_READ_FRAMEBUFFER, _id);
|
||||
}
|
||||
|
||||
void OpenGLFramebuffer::SwapColourBuffer(OpenGLFramebuffer& other)
|
||||
{
|
||||
std::swap(_texture, other._texture);
|
||||
|
||||
glCall(glBindFramebuffer, GL_FRAMEBUFFER, _id);
|
||||
glCall(glFramebufferTexture2D, GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture, 0);
|
||||
|
||||
glCall(glBindFramebuffer, GL_FRAMEBUFFER, other._id);
|
||||
glCall(glFramebufferTexture2D, GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, other._texture, 0);
|
||||
}
|
||||
|
||||
GLuint OpenGLFramebuffer::SwapDepthTexture(GLuint depth)
|
||||
{
|
||||
std::swap(_depth, depth);
|
||||
|
||||
glCall(glBindFramebuffer, GL_FRAMEBUFFER, _id);
|
||||
glCall(glFramebufferTexture2D, GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _depth, 0);
|
||||
|
||||
return depth;
|
||||
}
|
||||
|
||||
void OpenGLFramebuffer::Copy(OpenGLFramebuffer& src, GLenum filter)
|
||||
{
|
||||
BindDraw();
|
||||
src.BindRead();
|
||||
glCall(glBlitFramebuffer, 0, 0, src.GetWidth(), src.GetHeight(), 0, 0, _width, _height, GL_COLOR_BUFFER_BIT, filter);
|
||||
Bind();
|
||||
}
|
||||
|
||||
GLuint OpenGLFramebuffer::CreateDepthTexture(int32_t width, int32_t height)
|
||||
{
|
||||
GLuint depth;
|
||||
glCall(glGenTextures, 1, &depth);
|
||||
glCall(glBindTexture, GL_TEXTURE_2D, depth);
|
||||
glCall(
|
||||
glTexImage2D, GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
|
||||
glCall(glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glCall(glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glCall(glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
|
||||
glCall(glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glCall(glTexParameteri, GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
return depth;
|
||||
}
|
||||
|
||||
void OpenGLFramebuffer::GetPixels(RenderTarget& rt) const
|
||||
@@ -94,9 +185,9 @@ void OpenGLFramebuffer::GetPixels(RenderTarget& rt) const
|
||||
assert(rt.width == _width && rt.height == _height);
|
||||
|
||||
auto pixels = std::make_unique<uint8_t[]>(_width * _height);
|
||||
glBindTexture(GL_TEXTURE_2D, _texture);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, pixels.get());
|
||||
glCall(glBindTexture, GL_TEXTURE_2D, _texture);
|
||||
glCall(glPixelStorei, GL_PACK_ALIGNMENT, 1);
|
||||
glCall(glGetTexImage, GL_TEXTURE_2D, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, pixels.get());
|
||||
|
||||
// Flip pixels vertically on copy
|
||||
uint8_t* src = pixels.get() + ((_height - 1) * _width);
|
||||
@@ -109,47 +200,6 @@ void OpenGLFramebuffer::GetPixels(RenderTarget& rt) const
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLFramebuffer::SwapColourBuffer(OpenGLFramebuffer& other)
|
||||
{
|
||||
std::swap(_texture, other._texture);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, _id);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture, 0);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, other._id);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, other._texture, 0);
|
||||
}
|
||||
|
||||
GLuint OpenGLFramebuffer::SwapDepthTexture(GLuint depth)
|
||||
{
|
||||
std::swap(_depth, depth);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, _id);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _depth, 0);
|
||||
|
||||
return depth;
|
||||
}
|
||||
|
||||
void OpenGLFramebuffer::Copy(OpenGLFramebuffer& src, GLenum filter)
|
||||
{
|
||||
BindDraw();
|
||||
src.BindRead();
|
||||
glBlitFramebuffer(0, 0, src.GetWidth(), src.GetHeight(), 0, 0, _width, _height, GL_COLOR_BUFFER_BIT, filter);
|
||||
Bind();
|
||||
}
|
||||
|
||||
GLuint OpenGLFramebuffer::CreateDepthTexture(int32_t width, int32_t height)
|
||||
{
|
||||
GLuint depth;
|
||||
glGenTextures(1, &depth);
|
||||
glBindTexture(GL_TEXTURE_2D, depth);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
|
||||
return depth;
|
||||
}
|
||||
|
||||
void OpenGLFramebuffer::SetPixels(const RenderTarget& rt)
|
||||
{
|
||||
assert(rt.width == _width && rt.height == _height);
|
||||
@@ -165,12 +215,9 @@ void OpenGLFramebuffer::SetPixels(const RenderTarget& rt)
|
||||
dst -= _width;
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, _texture);
|
||||
CheckGLError();
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
CheckGLError();
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, _width, _height, GL_RED_INTEGER, GL_UNSIGNED_BYTE, pixels.get());
|
||||
CheckGLError();
|
||||
glCall(glBindTexture, GL_TEXTURE_2D, _texture);
|
||||
glCall(glPixelStorei, GL_UNPACK_ALIGNMENT, 1);
|
||||
glCall(glTexSubImage2D, GL_TEXTURE_2D, 0, 0, 0, _width, _height, GL_RED_INTEGER, GL_UNSIGNED_BYTE, pixels.get());
|
||||
}
|
||||
|
||||
#endif /* DISABLE_OPENGL */
|
||||
|
||||
@@ -42,6 +42,10 @@ namespace OpenRCT2::Ui
|
||||
{
|
||||
return _height;
|
||||
}
|
||||
GLuint GetFBO() const
|
||||
{
|
||||
return _id;
|
||||
}
|
||||
GLuint GetTexture() const
|
||||
{
|
||||
return _texture;
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
<ClInclude Include="drawing\engines\DrawingEngineFactory.hpp" />
|
||||
<ClInclude Include="drawing\engines\opengl\ApplyPaletteShader.h" />
|
||||
<ClInclude Include="drawing\engines\opengl\ApplyTransparencyShader.h" />
|
||||
<ClInclude Include="drawing\engines\opengl\CopyRectShader.h" />
|
||||
<ClInclude Include="drawing\engines\opengl\DrawCommands.h" />
|
||||
<ClInclude Include="drawing\engines\opengl\DrawLineShader.h" />
|
||||
<ClInclude Include="drawing\engines\opengl\DrawRectShader.h" />
|
||||
@@ -119,6 +120,7 @@
|
||||
<ClCompile Include="drawing\engines\HardwareDisplayDrawingEngine.cpp" />
|
||||
<ClCompile Include="drawing\engines\opengl\ApplyPaletteShader.cpp" />
|
||||
<ClCompile Include="drawing\engines\opengl\ApplyTransparencyShader.cpp" />
|
||||
<ClCompile Include="drawing\engines\opengl\CopyRectShader.cpp" />
|
||||
<ClCompile Include="drawing\engines\opengl\DrawLineShader.cpp" />
|
||||
<ClCompile Include="drawing\engines\opengl\DrawRectShader.cpp" />
|
||||
<ClCompile Include="drawing\engines\opengl\OpenGLAPI.cpp" />
|
||||
|
||||
Reference in New Issue
Block a user