From 0f5c41cd69d31dcd0a172e1720bfe4daa3977dca Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Sat, 12 Aug 2023 17:02:00 +0300 Subject: [PATCH] Add clear colour to GL state manager --- include/renderer_gl/gl_state.hpp | 16 +- include/renderer_gl/surfaces.hpp | 233 +++++++++++++-------------- src/core/renderer_gl/gl_state.cpp | 10 ++ src/core/renderer_gl/renderer_gl.cpp | 7 +- 4 files changed, 138 insertions(+), 128 deletions(-) diff --git a/include/renderer_gl/gl_state.hpp b/include/renderer_gl/gl_state.hpp index f2680eb4..69960f1e 100644 --- a/include/renderer_gl/gl_state.hpp +++ b/include/renderer_gl/gl_state.hpp @@ -34,6 +34,8 @@ struct GLStateManager { bool redMask, greenMask, blueMask, alphaMask; bool depthMask; + float clearRed, clearBlue, clearGreen, clearAlpha; + GLuint stencilMask; GLuint boundVAO; GLuint boundVBO; @@ -44,6 +46,7 @@ struct GLStateManager { void reset(); void resetBlend(); + void resetClearing(); void resetClipping(); void resetColourMask(); void resetDepth(); @@ -209,8 +212,19 @@ struct GLStateManager { } } + void setClearColour(float r, float g, float b, float a) { + if (clearRed != r || clearGreen != g || clearBlue != b || clearAlpha != a) { + clearRed = r; + clearGreen = g; + clearBlue = b; + clearAlpha = a; + + OpenGL::setClearColor(r, g, b, a); + } + } + void setDepthFunc(OpenGL::DepthFunc func) { setDepthFunc(static_cast(func)); } }; static_assert(std::is_trivially_constructible(), "OpenGL State Manager class is not trivially constructible!"); -static_assert(std::is_trivially_destructible(), "OpenGL State Manager class is not trivially destructible!"); +static_assert(std::is_trivially_destructible(), "OpenGL State Manager class is not trivially destructible!"); \ No newline at end of file diff --git a/include/renderer_gl/surfaces.hpp b/include/renderer_gl/surfaces.hpp index 043c63d0..1c2976d6 100644 --- a/include/renderer_gl/surfaces.hpp +++ b/include/renderer_gl/surfaces.hpp @@ -9,83 +9,63 @@ template using Interval = boost::icl::right_open_interval; struct ColourBuffer { - u32 location; - PICA::ColorFmt format; - OpenGL::uvec2 size; - bool valid; + u32 location; + PICA::ColorFmt format; + OpenGL::uvec2 size; + bool valid; - // Range of VRAM taken up by buffer - Interval range; - // OpenGL resources allocated to buffer - OpenGL::Texture texture; - OpenGL::Framebuffer fbo; + // Range of VRAM taken up by buffer + Interval range; + // OpenGL resources allocated to buffer + OpenGL::Texture texture; + OpenGL::Framebuffer fbo; - GLenum internalFormat; - GLenum fmt; - GLenum type; + ColourBuffer() : valid(false) {} - ColourBuffer() : valid(false) {} - - ColourBuffer(u32 loc, PICA::ColorFmt format, u32 x, u32 y, bool valid = true) - : location(loc), format(format), size({x, y}), valid(valid) { - - u64 endLoc = (u64)loc + sizeInBytes(); - // Check if start and end are valid here - range = Interval(loc, (u32)endLoc); - } + ColourBuffer(u32 loc, PICA::ColorFmt format, u32 x, u32 y, bool valid = true) : location(loc), format(format), size({x, y}), valid(valid) { + u64 endLoc = (u64)loc + sizeInBytes(); + // Check if start and end are valid here + range = Interval(loc, (u32)endLoc); + } void allocate() { - // Internal formats for the texture based on format - static constexpr std::array internalFormats = { - GL_RGBA8, GL_RGB8, GL_RGB5_A1, GL_RGB565, GL_RGBA4 - }; - - // Format of the texture - static constexpr std::array formats = { - GL_RGBA, GL_BGR, GL_RGBA, GL_RGB, GL_RGBA, - }; - - static constexpr std::array types = { - GL_UNSIGNED_INT_8_8_8_8, GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_5_5_1, - GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT_4_4_4_4, - }; - - internalFormat = internalFormats[(int)format]; - fmt = formats[(int)format]; - type = types[(int)format]; - - - // Create texture for the FBO, setting up filters and the like - // Reading back the current texture is slow, but allocate calls should be few and far between. - // If this becomes a bottleneck, we can fix it semi-easily - auto prevTexture = OpenGL::getTex2D(); - texture.create(size.x(), size.y(), internalFormat); - texture.bind(); - texture.setMinFilter(OpenGL::Linear); - texture.setMagFilter(OpenGL::Linear); - glBindTexture(GL_TEXTURE_2D, prevTexture); + // Create texture for the FBO, setting up filters and the like + // Reading back the current texture is slow, but allocate calls should be few and far between. + // If this becomes a bottleneck, we can fix it semi-easily + auto prevTexture = OpenGL::getTex2D(); + texture.create(size.x(), size.y(), GL_RGBA8); + texture.bind(); + texture.setMinFilter(OpenGL::Linear); + texture.setMagFilter(OpenGL::Linear); + glBindTexture(GL_TEXTURE_2D, prevTexture); #ifdef GPU_DEBUG_INFO const auto name = Helpers::format("Surface %dx%d %s from 0x%08X", size.x(), size.y(), PICA::textureFormatToString(format), location); OpenGL::setObjectLabel(GL_TEXTURE, texture.handle(), name.c_str()); #endif - fbo.createWithDrawTexture(texture); - fbo.bind(OpenGL::DrawAndReadFramebuffer); + fbo.createWithDrawTexture(texture); + fbo.bind(OpenGL::DrawAndReadFramebuffer); - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - Helpers::panic("Incomplete framebuffer"); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + Helpers::panic("Incomplete framebuffer"); + } - // TODO: This should not clear the framebuffer contents. It should load them from VRAM. - GLint oldViewport[4]; - glGetIntegerv(GL_VIEWPORT, oldViewport); - OpenGL::setViewport(size.x(), size.y()); - OpenGL::setClearColor(0.0, 0.0, 0.0, 1.0); - OpenGL::clearColor(); - OpenGL::setViewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]); - } + // TODO: This should not clear the framebuffer contents. It should load them from VRAM. + GLint oldViewport[4]; + GLfloat oldClearColour[4]; - void free() { + glGetIntegerv(GL_VIEWPORT, oldViewport); + glGetFloatv(GL_COLOR_CLEAR_VALUE, oldClearColour); + + OpenGL::setViewport(size.x(), size.y()); + OpenGL::setClearColor(0.0, 0.0, 0.0, 1.0); + OpenGL::clearColor(); + OpenGL::setViewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]); + OpenGL::setClearColor(oldClearColour[0], oldClearColour[1], oldClearColour[2], oldClearColour[3]); + } + + void free() { valid = false; if (texture.exists() || fbo.exists()) { @@ -103,88 +83,93 @@ struct ColourBuffer { return Math::Rect{x0, size.y() - y0, x0 + width, size.y() - height - y0}; } - bool matches(ColourBuffer& other) { - return location == other.location && format == other.format && - size.x() == other.size.x() && size.y() == other.size.y(); - } + bool matches(ColourBuffer& other) { + return location == other.location && format == other.format && size.x() == other.size.x() && size.y() == other.size.y(); + } - size_t sizeInBytes() { - return (size_t)size.x() * (size_t)size.y() * PICA::sizePerPixel(format); - } + size_t sizeInBytes() { + return (size_t)size.x() * (size_t)size.y() * PICA::sizePerPixel(format); + } }; struct DepthBuffer { - u32 location; - PICA::DepthFmt format; - OpenGL::uvec2 size; // Implicitly set to the size of the framebuffer - bool valid; + u32 location; + PICA::DepthFmt format; + OpenGL::uvec2 size; // Implicitly set to the size of the framebuffer + bool valid; - // Range of VRAM taken up by buffer - Interval range; - // OpenGL texture used for storing depth/stencil - OpenGL::Texture texture; - OpenGL::Framebuffer fbo; + // Range of VRAM taken up by buffer + Interval range; + // OpenGL texture used for storing depth/stencil + OpenGL::Texture texture; + OpenGL::Framebuffer fbo; - DepthBuffer() : valid(false) {} + DepthBuffer() : valid(false) {} - DepthBuffer(u32 loc, PICA::DepthFmt format, u32 x, u32 y, bool valid = true) : - location(loc), format(format), size({x, y}), valid(valid) { + DepthBuffer(u32 loc, PICA::DepthFmt format, u32 x, u32 y, bool valid = true) : location(loc), format(format), size({x, y}), valid(valid) { + u64 endLoc = (u64)loc + sizeInBytes(); + // Check if start and end are valid here + range = Interval(loc, (u32)endLoc); + } - u64 endLoc = (u64)loc + sizeInBytes(); - // Check if start and end are valid here - range = Interval(loc, (u32)endLoc); - } + void allocate() { + // Create texture for the FBO, setting up filters and the like + // Reading back the current texture is slow, but allocate calls should be few and far between. + // If this becomes a bottleneck, we can fix it semi-easily + auto prevTexture = OpenGL::getTex2D(); - void allocate() { - // Create texture for the FBO, setting up filters and the like - // Reading back the current texture is slow, but allocate calls should be few and far between. - // If this becomes a bottleneck, we can fix it semi-easily - auto prevTexture = OpenGL::getTex2D(); + // Internal formats for the texture based on format + static constexpr std::array internalFormats = { + GL_DEPTH_COMPONENT16, + GL_DEPTH_COMPONENT24, + GL_DEPTH_COMPONENT24, + GL_DEPTH24_STENCIL8, + }; - // Internal formats for the texture based on format - static constexpr std::array internalFormats = { - GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT24, GL_DEPTH24_STENCIL8 - }; + // Format of the texture + static constexpr std::array formats = { + GL_DEPTH_COMPONENT, + GL_DEPTH_COMPONENT, + GL_DEPTH_COMPONENT, + GL_DEPTH_STENCIL, + }; + + static constexpr std::array types = { + GL_UNSIGNED_SHORT, + GL_UNSIGNED_INT, + GL_UNSIGNED_INT, + GL_UNSIGNED_INT_24_8, + }; - // Format of the texture - static constexpr std::array formats = { - GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL - }; + auto internalFormat = internalFormats[(int)format]; + auto fmt = formats[(int)format]; + auto type = types[(int)format]; - static constexpr std::array types = { - GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, GL_UNSIGNED_INT, GL_UNSIGNED_INT_24_8 - }; + texture.createDSTexture(size.x(), size.y(), internalFormat, fmt, nullptr, type, GL_TEXTURE_2D); + texture.bind(); + texture.setMinFilter(OpenGL::Nearest); + texture.setMagFilter(OpenGL::Nearest); - auto internalFormat = internalFormats[(int)format]; - auto fmt = formats[(int)format]; - auto type = types[(int)format]; + glBindTexture(GL_TEXTURE_2D, prevTexture); + fbo.createWithDrawTexture(texture, fmt == GL_DEPTH_STENCIL ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT); - texture.createDSTexture(size.x(), size.y(), internalFormat, fmt, nullptr, type, GL_TEXTURE_2D); - texture.bind(); - texture.setMinFilter(OpenGL::Nearest); - texture.setMagFilter(OpenGL::Nearest); - - glBindTexture(GL_TEXTURE_2D, prevTexture); - - fbo.createWithDrawTexture(texture, fmt == GL_DEPTH_STENCIL ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT); - - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { Helpers::panic("Incomplete framebuffer"); - } + } + } - void free() { + void free() { valid = false; if (texture.exists()) { texture.free(); } } - bool matches(DepthBuffer& other) { - return location == other.location && format == other.format && - size.x() == other.size.x() && size.y() == other.size.y(); - } + bool matches(DepthBuffer& other) { + return location == other.location && format == other.format && size.x() == other.size.x() && size.y() == other.size.y(); + } - size_t sizeInBytes() { - return (size_t)size.x() * (size_t)size.y() * PICA::sizePerPixel(format); - } + size_t sizeInBytes() { + return (size_t)size.x() * (size_t)size.y() * PICA::sizePerPixel(format); + } }; diff --git a/src/core/renderer_gl/gl_state.cpp b/src/core/renderer_gl/gl_state.cpp index 4a512f44..d2eec0d5 100644 --- a/src/core/renderer_gl/gl_state.cpp +++ b/src/core/renderer_gl/gl_state.cpp @@ -10,6 +10,15 @@ void GLStateManager::resetBlend() { OpenGL::setLogicOp(GL_COPY); } +void GLStateManager::resetClearing() { + clearRed = 0.f; + clearBlue = 0.f; + clearGreen = 0.f; + clearAlpha = 1.f; + + OpenGL::setClearColor(clearRed, clearBlue, clearGreen, clearAlpha); +} + void GLStateManager::resetClipping() { // Disable all (supported) clip planes enabledClipPlanes = 0; @@ -64,6 +73,7 @@ void GLStateManager::resetProgram() { void GLStateManager::reset() { resetBlend(); + resetClearing(); resetClipping(); resetColourMask(); resetDepth(); diff --git a/src/core/renderer_gl/renderer_gl.cpp b/src/core/renderer_gl/renderer_gl.cpp index 181696e5..21f961ba 100644 --- a/src/core/renderer_gl/renderer_gl.cpp +++ b/src/core/renderer_gl/renderer_gl.cpp @@ -141,7 +141,7 @@ void RendererGL::initGraphicsContext(SDL_Window* window) { GLint oldViewport[4]; glGetIntegerv(GL_VIEWPORT, oldViewport); OpenGL::setViewport(screenTextureWidth, screenTextureHeight); - OpenGL::setClearColor(0.0, 0.0, 0.0, 1.0); + gl.setClearColour(0.0, 0.0, 0.0, 1.0); OpenGL::clearColor(); OpenGL::setViewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]); @@ -473,7 +473,7 @@ void RendererGL::display() { auto bottomScreen = colourBufferCache.findFromAddress(bottomScreenAddr); screenFramebuffer.bind(OpenGL::DrawFramebuffer); - OpenGL::setClearColor(0.f); + gl.setClearColour(0.f, 0.f, 0.f, 1.f); OpenGL::clearColor(); if (topScreen) { @@ -504,8 +504,9 @@ void RendererGL::clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 co const float b = getBits<8, 8>(value) / 255.0f; const float a = (value & 0xff) / 255.0f; color->get().fbo.bind(OpenGL::DrawFramebuffer); + gl.setColourMask(true, true, true, true); - OpenGL::setClearColor(r, g, b, a); + gl.setClearColour(r, g, b, a); OpenGL::clearColor(); return; }