More OpenGL state management stuff

This commit is contained in:
wheremyfoodat 2023-07-05 00:43:49 +03:00
parent e01f0ea4d0
commit 139c8759c9
3 changed files with 96 additions and 21 deletions

View file

@ -20,10 +20,19 @@
struct GLStateManager { struct GLStateManager {
bool blendEnabled; bool blendEnabled;
bool depthEnabled; bool depthEnabled;
bool scissorEnabled;
GLuint boundVAO;
GLuint boundVBO;
GLuint currentProgram;
void reset(); void reset();
void resetBlend(); void resetBlend();
void resetDepth(); void resetDepth();
void resetVAO();
void resetVBO();
void resetProgram();
void resetScissor();
void enableDepth() { void enableDepth() {
if (!depthEnabled) { if (!depthEnabled) {
@ -52,6 +61,45 @@ struct GLStateManager {
OpenGL::disableBlend(); 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<GLStateManager>(), "OpenGL State Manager class is not trivially constructible!"); static_assert(std::is_trivially_constructible<GLStateManager>(), "OpenGL State Manager class is not trivially constructible!");

View file

@ -592,7 +592,7 @@ void Renderer::reset() {
if (triangleProgram.exists()) { if (triangleProgram.exists()) {
const auto oldProgram = OpenGL::getProgram(); const auto oldProgram = OpenGL::getProgram();
triangleProgram.use(); gl.useProgram(triangleProgram);
oldAlphaControl = 0; // Default alpha control to 0 oldAlphaControl = 0; // Default alpha control to 0
oldTexUnitConfig = 0; // Default tex unit config to 0 oldTexUnitConfig = 0; // Default tex unit config to 0
@ -606,7 +606,7 @@ void Renderer::reset() {
glUniform1f(depthOffsetLoc, oldDepthOffset); glUniform1f(depthOffsetLoc, oldDepthOffset);
glUniform1i(depthmapEnableLoc, oldDepthmapEnable); 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 vert(vertexShader, OpenGL::Vertex);
OpenGL::Shader frag(fragmentShader, OpenGL::Fragment); OpenGL::Shader frag(fragmentShader, OpenGL::Fragment);
triangleProgram.create({ vert, frag }); triangleProgram.create({ vert, frag });
triangleProgram.use(); gl.useProgram(triangleProgram);
alphaControlLoc = OpenGL::uniformLocation(triangleProgram, "u_alphaControl"); alphaControlLoc = OpenGL::uniformLocation(triangleProgram, "u_alphaControl");
texUnitConfigLoc = OpenGL::uniformLocation(triangleProgram, "u_textureConfig"); texUnitConfigLoc = OpenGL::uniformLocation(triangleProgram, "u_textureConfig");
@ -642,13 +642,13 @@ void Renderer::initGraphicsContext() {
OpenGL::Shader fragDisplay(displayFragmentShader, OpenGL::Fragment); OpenGL::Shader fragDisplay(displayFragmentShader, OpenGL::Fragment);
displayProgram.create({ vertDisplay, fragDisplay }); displayProgram.create({ vertDisplay, fragDisplay });
displayProgram.use(); gl.useProgram(displayProgram);
glUniform1i(OpenGL::uniformLocation(displayProgram, "u_texture"), 0); // Init sampler object glUniform1i(OpenGL::uniformLocation(displayProgram, "u_texture"), 0); // Init sampler object
vbo.createFixedSize(sizeof(Vertex) * vertexBufferSize, GL_STREAM_DRAW); vbo.createFixedSize(sizeof(Vertex) * vertexBufferSize, GL_STREAM_DRAW);
vbo.bind(); gl.bindVBO(vbo);
vao.create(); vao.create();
vao.bind(); gl.bindVAO(vao);
// Position (x, y, z, w) attributes // Position (x, y, z, w) attributes
vao.setAttributeFloat<float>(0, 4, sizeof(Vertex), offsetof(Vertex, s.positions)); vao.setAttributeFloat<float>(0, 4, sizeof(Vertex), offsetof(Vertex, s.positions));
@ -725,9 +725,9 @@ void Renderer::setupBlending() {
}; };
if (!blendingEnabled) { if (!blendingEnabled) {
OpenGL::disableBlend(); gl.disableBlend();
} else { } else {
OpenGL::enableBlend(); gl.enableBlend();
// Get blending equations // Get blending equations
const u32 blendControl = regs[PICA::InternalRegs::BlendFunc]; const u32 blendControl = regs[PICA::InternalRegs::BlendFunc];
@ -852,11 +852,11 @@ void Renderer::drawVertices(PICA::PrimType primType, std::span<const Vertex> ver
// TODO: We should implement a GL state tracker that tracks settings like scissor, blending, bound program, etc // 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" // 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 // And not actually perform the very expensive driver call for it
OpenGL::disableScissor(); gl.disableScissor();
vbo.bind(); gl.bindVBO(vbo);
vao.bind(); gl.bindVAO(vao);
triangleProgram.use(); gl.useProgram(triangleProgram);
// Adjust alpha test if necessary // Adjust alpha test if necessary
const u32 alphaControl = regs[PICA::InternalRegs::AlphaTestConfig]; const u32 alphaControl = regs[PICA::InternalRegs::AlphaTestConfig];
@ -924,18 +924,18 @@ void Renderer::drawVertices(PICA::PrimType primType, std::span<const Vertex> ver
// Note: The code below must execute after we've bound the colour buffer & its framebuffer // 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 // Because it attaches a depth texture to the aforementioned colour buffer
if (depthEnable) { if (depthEnable) {
OpenGL::enableDepth(); gl.enableDepth();
glDepthFunc(depthModes[depthFunc]); glDepthFunc(depthModes[depthFunc]);
glDepthMask(depthWriteEnable ? GL_TRUE : GL_FALSE); glDepthMask(depthWriteEnable ? GL_TRUE : GL_FALSE);
bindDepthBuffer(); bindDepthBuffer();
} else { } else {
if (depthWriteEnable) { if (depthWriteEnable) {
OpenGL::enableDepth(); gl.enableDepth();
glDepthFunc(GL_ALWAYS); glDepthFunc(GL_ALWAYS);
glDepthMask(GL_TRUE); glDepthMask(GL_TRUE);
bindDepthBuffer(); bindDepthBuffer();
} else { } else {
OpenGL::disableDepth(); gl.disableDepth();
} }
} }
@ -947,7 +947,7 @@ constexpr u32 topScreenBuffer = 0x1f000000;
constexpr u32 bottomScreenBuffer = 0x1f05dc00; constexpr u32 bottomScreenBuffer = 0x1f05dc00;
void Renderer::display() { void Renderer::display() {
OpenGL::disableScissor(); gl.disableScissor();
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
screenFramebuffer.bind(OpenGL::ReadFramebuffer); screenFramebuffer.bind(OpenGL::ReadFramebuffer);
@ -1038,12 +1038,14 @@ void Renderer::displayTransfer(u32 inputAddr, u32 outputAddr, u32 inputSize, u32
tex.bind(); tex.bind();
screenFramebuffer.bind(OpenGL::DrawFramebuffer); screenFramebuffer.bind(OpenGL::DrawFramebuffer);
OpenGL::disableBlend(); gl.disableBlend();
OpenGL::disableDepth(); gl.disableDepth();
OpenGL::disableScissor(); gl.disableScissor();
gl.useProgram(displayProgram);
gl.bindVAO(dummyVAO);
OpenGL::disableClipPlane(0); OpenGL::disableClipPlane(0);
OpenGL::disableClipPlane(1); 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 // 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 // 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 OpenGL::setViewport(0, 240, 400, 240); // Top screen viewport
} }
dummyVAO.bind();
OpenGL::draw(OpenGL::TriangleStrip, 4); // Actually draw our 3DS screen OpenGL::draw(OpenGL::TriangleStrip, 4); // Actually draw our 3DS screen
} }

View file

@ -10,7 +10,33 @@ void GLStateManager::resetDepth() {
OpenGL::disableDepth(); 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() { void GLStateManager::reset() {
resetBlend(); resetBlend();
resetDepth(); resetDepth();
resetVAO();
resetVBO();
resetProgram();
resetScissor();
} }