From 139c8759c920437756ed9f5af9e55786d467974c Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Wed, 5 Jul 2023 00:43:49 +0300 Subject: [PATCH] More OpenGL state management stuff --- include/gl_state.hpp | 48 ++++++++++++++++++++++++++++ src/core/renderer_gl/renderer_gl.cpp | 43 +++++++++++++------------ src/gl_state.cpp | 26 +++++++++++++++ 3 files changed, 96 insertions(+), 21 deletions(-) diff --git a/include/gl_state.hpp b/include/gl_state.hpp index 3c9458d5..6a495c72 100644 --- a/include/gl_state.hpp +++ b/include/gl_state.hpp @@ -20,10 +20,19 @@ struct GLStateManager { bool blendEnabled; bool depthEnabled; + bool scissorEnabled; + + GLuint boundVAO; + GLuint boundVBO; + GLuint currentProgram; void reset(); void resetBlend(); void resetDepth(); + void resetVAO(); + void resetVBO(); + void resetProgram(); + void resetScissor(); void enableDepth() { if (!depthEnabled) { @@ -52,6 +61,45 @@ struct GLStateManager { OpenGL::disableBlend(); } } + + void enableScissor() { + if (!scissorEnabled) { + scissorEnabled = true; + OpenGL::enableScissor(); + } + } + + void disableScissor() { + if (scissorEnabled) { + scissorEnabled = false; + OpenGL::disableScissor(); + } + } + + void bindVAO(GLuint handle) { + if (boundVAO != handle) { + boundVAO = handle; + glBindVertexArray(handle); + } + } + + void bindVBO(GLuint handle) { + if (boundVBO != handle) { + boundVBO = handle; + glBindBuffer(GL_ARRAY_BUFFER, handle); + } + } + + void useProgram(GLuint handle) { + if (currentProgram != handle) { + currentProgram = handle; + glUseProgram(handle); + } + } + + void bindVAO(const OpenGL::VertexArray& vao) { bindVAO(vao.handle()); } + void bindVBO(const OpenGL::VertexBuffer& vbo) { bindVBO(vbo.handle()); } + void useProgram(const OpenGL::Program& program) { useProgram(program.handle()); } }; static_assert(std::is_trivially_constructible(), "OpenGL State Manager class is not trivially constructible!"); diff --git a/src/core/renderer_gl/renderer_gl.cpp b/src/core/renderer_gl/renderer_gl.cpp index de8a7375..b93834a2 100644 --- a/src/core/renderer_gl/renderer_gl.cpp +++ b/src/core/renderer_gl/renderer_gl.cpp @@ -592,7 +592,7 @@ void Renderer::reset() { if (triangleProgram.exists()) { const auto oldProgram = OpenGL::getProgram(); - triangleProgram.use(); + gl.useProgram(triangleProgram); oldAlphaControl = 0; // Default alpha control to 0 oldTexUnitConfig = 0; // Default tex unit config to 0 @@ -606,7 +606,7 @@ void Renderer::reset() { glUniform1f(depthOffsetLoc, oldDepthOffset); glUniform1i(depthmapEnableLoc, oldDepthmapEnable); - glUseProgram(oldProgram); // Switch to old GL program + gl.useProgram(oldProgram); // Switch to old GL program } } @@ -614,7 +614,7 @@ void Renderer::initGraphicsContext() { OpenGL::Shader vert(vertexShader, OpenGL::Vertex); OpenGL::Shader frag(fragmentShader, OpenGL::Fragment); triangleProgram.create({ vert, frag }); - triangleProgram.use(); + gl.useProgram(triangleProgram); alphaControlLoc = OpenGL::uniformLocation(triangleProgram, "u_alphaControl"); texUnitConfigLoc = OpenGL::uniformLocation(triangleProgram, "u_textureConfig"); @@ -642,13 +642,13 @@ void Renderer::initGraphicsContext() { OpenGL::Shader fragDisplay(displayFragmentShader, OpenGL::Fragment); displayProgram.create({ vertDisplay, fragDisplay }); - displayProgram.use(); + gl.useProgram(displayProgram); glUniform1i(OpenGL::uniformLocation(displayProgram, "u_texture"), 0); // Init sampler object vbo.createFixedSize(sizeof(Vertex) * vertexBufferSize, GL_STREAM_DRAW); - vbo.bind(); + gl.bindVBO(vbo); vao.create(); - vao.bind(); + gl.bindVAO(vao); // Position (x, y, z, w) attributes vao.setAttributeFloat(0, 4, sizeof(Vertex), offsetof(Vertex, s.positions)); @@ -725,9 +725,9 @@ void Renderer::setupBlending() { }; if (!blendingEnabled) { - OpenGL::disableBlend(); + gl.disableBlend(); } else { - OpenGL::enableBlend(); + gl.enableBlend(); // Get blending equations const u32 blendControl = regs[PICA::InternalRegs::BlendFunc]; @@ -852,11 +852,11 @@ void Renderer::drawVertices(PICA::PrimType primType, std::span ver // TODO: We should implement a GL state tracker that tracks settings like scissor, blending, bound program, etc // This way if we attempt to eg do multiple glEnable(GL_BLEND) calls in a row, it will say "Oh blending is already enabled" // And not actually perform the very expensive driver call for it - OpenGL::disableScissor(); + gl.disableScissor(); - vbo.bind(); - vao.bind(); - triangleProgram.use(); + gl.bindVBO(vbo); + gl.bindVAO(vao); + gl.useProgram(triangleProgram); // Adjust alpha test if necessary const u32 alphaControl = regs[PICA::InternalRegs::AlphaTestConfig]; @@ -924,18 +924,18 @@ void Renderer::drawVertices(PICA::PrimType primType, std::span ver // Note: The code below must execute after we've bound the colour buffer & its framebuffer // Because it attaches a depth texture to the aforementioned colour buffer if (depthEnable) { - OpenGL::enableDepth(); + gl.enableDepth(); glDepthFunc(depthModes[depthFunc]); glDepthMask(depthWriteEnable ? GL_TRUE : GL_FALSE); bindDepthBuffer(); } else { if (depthWriteEnable) { - OpenGL::enableDepth(); + gl.enableDepth(); glDepthFunc(GL_ALWAYS); glDepthMask(GL_TRUE); bindDepthBuffer(); } else { - OpenGL::disableDepth(); + gl.disableDepth(); } } @@ -947,7 +947,7 @@ constexpr u32 topScreenBuffer = 0x1f000000; constexpr u32 bottomScreenBuffer = 0x1f05dc00; void Renderer::display() { - OpenGL::disableScissor(); + gl.disableScissor(); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); screenFramebuffer.bind(OpenGL::ReadFramebuffer); @@ -1038,12 +1038,14 @@ void Renderer::displayTransfer(u32 inputAddr, u32 outputAddr, u32 inputSize, u32 tex.bind(); screenFramebuffer.bind(OpenGL::DrawFramebuffer); - OpenGL::disableBlend(); - OpenGL::disableDepth(); - OpenGL::disableScissor(); + gl.disableBlend(); + gl.disableDepth(); + gl.disableScissor(); + gl.useProgram(displayProgram); + gl.bindVAO(dummyVAO); + OpenGL::disableClipPlane(0); OpenGL::disableClipPlane(1); - displayProgram.use(); // Hack: Detect whether we are writing to the top or bottom screen by checking output gap and drawing to the proper part of the output texture // We consider output gap == 320 to mean bottom, and anything else to mean top @@ -1053,6 +1055,5 @@ void Renderer::displayTransfer(u32 inputAddr, u32 outputAddr, u32 inputSize, u32 OpenGL::setViewport(0, 240, 400, 240); // Top screen viewport } - dummyVAO.bind(); OpenGL::draw(OpenGL::TriangleStrip, 4); // Actually draw our 3DS screen } \ No newline at end of file diff --git a/src/gl_state.cpp b/src/gl_state.cpp index 902971ab..030797a4 100644 --- a/src/gl_state.cpp +++ b/src/gl_state.cpp @@ -10,7 +10,33 @@ void GLStateManager::resetDepth() { OpenGL::disableDepth(); } +void GLStateManager::resetScissor() { + scissorEnabled = false; + OpenGL::disableScissor(); + OpenGL::setScissor(0, 0, 0, 0); +} + +void GLStateManager::resetVAO() { + boundVAO = 0; + glBindVertexArray(0); +} + +void GLStateManager::resetVBO() { + boundVBO = 0; + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +void GLStateManager::resetProgram() { + currentProgram = 0; + glUseProgram(0); +} + void GLStateManager::reset() { resetBlend(); resetDepth(); + + resetVAO(); + resetVBO(); + resetProgram(); + resetScissor(); } \ No newline at end of file