From 7bbf37bb638e81f317369727a40637f7a34263c9 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Fri, 18 Aug 2023 16:19:54 +0300 Subject: [PATCH] Implement reading texture from NULL --- include/renderer_gl/renderer_gl.hpp | 1 + src/core/renderer_gl/renderer_gl.cpp | 34 ++++++++++++++++++++++++---- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/include/renderer_gl/renderer_gl.hpp b/include/renderer_gl/renderer_gl.hpp index dc3e69c2..dab33ae8 100644 --- a/include/renderer_gl/renderer_gl.hpp +++ b/include/renderer_gl/renderer_gl.hpp @@ -55,6 +55,7 @@ class RendererGL final : public Renderer { OpenGL::Texture screenTexture; GLuint lightLUTTextureArray; OpenGL::Framebuffer screenFramebuffer; + OpenGL::Texture blankTexture; OpenGL::Framebuffer getColourFBO(); OpenGL::Texture getTexture(Texture& tex); diff --git a/src/core/renderer_gl/renderer_gl.cpp b/src/core/renderer_gl/renderer_gl.cpp index 3eb36de5..6d29e7d3 100644 --- a/src/core/renderer_gl/renderer_gl.cpp +++ b/src/core/renderer_gl/renderer_gl.cpp @@ -118,6 +118,7 @@ void RendererGL::initGraphicsContext(SDL_Window* window) { dummyVBO.create(); dummyVAO.create(); + gl.disableScissor(); // Create texture and framebuffer for the 3DS screen const u32 screenTextureWidth = 400; // Top screen is 400 pixels wide, bottom is 320 @@ -126,6 +127,24 @@ void RendererGL::initGraphicsContext(SDL_Window* window) { glGenTextures(1, &lightLUTTextureArray); auto prevTexture = OpenGL::getTex2D(); + + // Create a plain black texture for when a game reads an invalid texture. It is common for games to configure the PICA to read texture info from NULL. + // Some games that do this are Pokemon X, Cars 2, Tomodachi Life, and more. We bind the texture to an FBO, clear it, and free the FBO + blankTexture.create(8, 8, GL_RGBA8); + blankTexture.bind(); + blankTexture.setMinFilter(OpenGL::Linear); + blankTexture.setMagFilter(OpenGL::Linear); + + OpenGL::Framebuffer dummyFBO; + dummyFBO.createWithDrawTexture(blankTexture); // Create FBO and bind our texture to it + dummyFBO.bind(OpenGL::DrawFramebuffer); + + // Clear the texture and then delete FBO + OpenGL::setViewport(8, 8); + gl.setClearColour(0.0, 0.0, 0.0, 1.0); + OpenGL::clearColor(); + dummyFBO.free(); + screenTexture.create(screenTextureWidth, screenTextureHeight, GL_RGBA8); screenTexture.bind(); screenTexture.setMinFilter(OpenGL::Linear); @@ -143,7 +162,6 @@ void RendererGL::initGraphicsContext(SDL_Window* window) { GLint oldViewport[4]; glGetIntegerv(GL_VIEWPORT, oldViewport); OpenGL::setViewport(screenTextureWidth, screenTextureHeight); - gl.setClearColour(0.0, 0.0, 0.0, 1.0); OpenGL::clearColor(); OpenGL::setViewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]); @@ -321,9 +339,17 @@ void RendererGL::bindTexturesToSlots() { u32 format = regs[ioBase + (i == 0 ? 13 : 5)] & 0xF; glActiveTexture(GL_TEXTURE0 + i); - Texture targetTex(addr, static_cast(format), width, height, config); - OpenGL::Texture tex = getTexture(targetTex); - tex.bind(); + + if (addr != 0) [[likely]] { + Texture targetTex(addr, static_cast(format), width, height, config); + OpenGL::Texture tex = getTexture(targetTex); + tex.bind(); + } else { + // Mapping a texture from NULL. PICA seems to read the last sampled colour, but for now we will display a black texture instead since it is far easier. + // Games that do this don't really care what it does, they just expect the PICA to not crash, since it doesn't have a PU/MMU and can do all sorts of + // Weird invalid memory accesses without crashing + blankTexture.bind(); + } } glActiveTexture(GL_TEXTURE0 + 3);