From dd17b2ecb86787163f1fd7ccf6cff9b43c6e82c4 Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Tue, 31 Jan 2023 21:34:42 +0200 Subject: [PATCH] [PICA] Start working on textures --- CMakeLists.txt | 3 +- include/PICA/gpu.hpp | 60 ++++++++++++++--------------- include/renderer_gl/renderer_gl.hpp | 6 ++- include/renderer_gl/textures.hpp | 60 +++++++++++++++++++++++++++++ src/core/renderer_gl/textures.cpp | 52 +++++++++++++++++++++++++ 5 files changed, 149 insertions(+), 32 deletions(-) create mode 100644 include/renderer_gl/textures.hpp create mode 100644 src/core/renderer_gl/textures.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a7a1b61b..9cd039ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,7 +64,7 @@ set(SERVICE_SOURCE_FILES src/core/services/service_manager.cpp src/core/services set(PICA_SOURCE_FILES src/core/PICA/gpu.cpp src/core/PICA/regs.cpp src/core/PICA/shader_unit.cpp src/core/PICA/shader_interpreter.cpp ) -set(RENDERER_GL_SOURCE_FILES src/core/renderer_gl/renderer_gl.cpp) +set(RENDERER_GL_SOURCE_FILES src/core/renderer_gl/renderer_gl.cpp src/core/renderer_gl/textures.cpp) set(LOADER_SOURCE_FILES src/core/loader/elf.cpp src/core/loader/ncsd.cpp src/core/loader/ncch.cpp) set(FS_SOURCE_FILES src/core/fs/archive_self_ncch.cpp src/core/fs/archive_save_data.cpp src/core/fs/archive_sdmc.cpp @@ -87,6 +87,7 @@ set(HEADER_FILES include/emulator.hpp include/helpers.hpp include/opengl.hpp inc include/renderer_gl/surfaces.hpp include/renderer_gl/surface_cache.hpp include/services/ac.hpp include/services/am.hpp include/services/boss.hpp include/services/frd.hpp include/services/nim.hpp include/fs/archive_ext_save_data.hpp include/services/shared_font.hpp include/fs/archive_ncch.hpp + include/renderer_gl/textures.hpp ) set(THIRD_PARTY_SOURCE_FILES third_party/imgui/imgui.cpp diff --git a/include/PICA/gpu.hpp b/include/PICA/gpu.hpp index 32655035..040292a9 100644 --- a/include/PICA/gpu.hpp +++ b/include/PICA/gpu.hpp @@ -20,36 +20,6 @@ class GPU { static constexpr u32 vramSize = 6_MB; std::array regs; // GPU internal registers - // Read a value of type T from physical address paddr - // This is necessary because vertex attribute fetching uses physical addresses - template - T readPhysical(u32 paddr) { - if (paddr >= PhysicalAddrs::FCRAM && paddr <= PhysicalAddrs::FCRAMEnd) { - u8* fcram = mem.getFCRAM(); - u32 index = paddr - PhysicalAddrs::FCRAM; - - return *(T*)&fcram[index]; - } else { - Helpers::panic("[PICA] Read unimplemented paddr %08X", paddr); - } - } - - // Get a pointer of type T* to the data starting from physical address paddr - template - T* getPointerPhys(u32 paddr) { - if (paddr >= PhysicalAddrs::FCRAM && paddr <= PhysicalAddrs::FCRAMEnd) { - u8* fcram = mem.getFCRAM(); - u32 index = paddr - PhysicalAddrs::FCRAM; - - return (T*)&fcram[index]; - } else if (paddr >= PhysicalAddrs::VRAM && paddr <= PhysicalAddrs::VRAMEnd) { - u32 index = paddr - PhysicalAddrs::VRAM; - return (T*)&vram[index]; - } else [[unlikely]] { - Helpers::panic("[GPU] Tried to access unknown physical address: %08X", paddr); - } - } - template void drawArrays(); @@ -97,4 +67,34 @@ public: void clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control) { renderer.clearBuffer(startAddress, endAddress, value, control); } + + // Read a value of type T from physical address paddr + // This is necessary because vertex attribute fetching uses physical addresses + template + T readPhysical(u32 paddr) { + if (paddr >= PhysicalAddrs::FCRAM && paddr <= PhysicalAddrs::FCRAMEnd) { + u8* fcram = mem.getFCRAM(); + u32 index = paddr - PhysicalAddrs::FCRAM; + + return *(T*)&fcram[index]; + } else { + Helpers::panic("[PICA] Read unimplemented paddr %08X", paddr); + } + } + + // Get a pointer of type T* to the data starting from physical address paddr + template + T* getPointerPhys(u32 paddr) { + if (paddr >= PhysicalAddrs::FCRAM && paddr <= PhysicalAddrs::FCRAMEnd) { + u8* fcram = mem.getFCRAM(); + u32 index = paddr - PhysicalAddrs::FCRAM; + + return (T*)&fcram[index]; + } else if (paddr >= PhysicalAddrs::VRAM && paddr <= PhysicalAddrs::VRAMEnd) { + u32 index = paddr - PhysicalAddrs::VRAM; + return (T*)&vram[index]; + } else [[unlikely]] { + Helpers::panic("[GPU] Tried to access unknown physical address: %08X", paddr); + } + } }; \ No newline at end of file diff --git a/include/renderer_gl/renderer_gl.hpp b/include/renderer_gl/renderer_gl.hpp index 072f0d11..ad4be9f4 100644 --- a/include/renderer_gl/renderer_gl.hpp +++ b/include/renderer_gl/renderer_gl.hpp @@ -5,12 +5,16 @@ #include "opengl.hpp" #include "surface_cache.hpp" +// More circular dependencies! +class GPU; + struct Vertex { OpenGL::vec4 position; OpenGL::vec4 colour; }; class Renderer { + GPU& gpu; OpenGL::Program triangleProgram; OpenGL::Program displayProgram; @@ -42,7 +46,7 @@ class Renderer { MAKE_LOG_FUNCTION(log, rendererLogger) public: - Renderer(const std::array& internalRegs) : regs(internalRegs) {} + Renderer(GPU& gpu, const std::array& internalRegs) : gpu(gpu), regs(internalRegs) {} void reset(); void display(); // Display the 3DS screen contents to the window diff --git a/include/renderer_gl/textures.hpp b/include/renderer_gl/textures.hpp new file mode 100644 index 00000000..31c7200e --- /dev/null +++ b/include/renderer_gl/textures.hpp @@ -0,0 +1,60 @@ +#pragma once +#include +#include "boost/icl/interval.hpp" +#include "helpers.hpp" +#include "opengl.hpp" + +template +using Interval = boost::icl::right_open_interval; + +struct Texture { + enum class Formats : u32 { + RGBA8 = 0, + RGB8 = 1, + RGBA5551 = 2, + RGB565 = 3, + RGBA4 = 4, + IA8 = 5, + RG8 = 6, + I8 = 7, + A8 = 8, + IA4 = 9, + I4 = 10, + A4 = 11, + ETC1 = 12, + ETC1A4 = 13, + + Trash1 = 14, Trash2 = 15 // TODO: What are these? + }; + + u32 location; + Formats format; + OpenGL::uvec2 size; + bool valid; + + // Range of VRAM taken up by buffer + Interval range; + // OpenGL resources allocated to buffer + OpenGL::Texture texture; + + Texture() : valid(false) {} + + Texture(u32 loc, Formats 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); + } + + // For 2 textures to "match" we only care about their locations, formats, and dimensions to match + // For other things, such as filtering mode, etc, we can just switch the attributes of the cached texture + bool matches(Texture& other) { + return location == other.location && format == other.format && + size.x() == other.size.x() && size.y() == other.size.y(); + } + + void allocate(); + void free(); + u64 sizeInBytes(); +}; \ No newline at end of file diff --git a/src/core/renderer_gl/textures.cpp b/src/core/renderer_gl/textures.cpp new file mode 100644 index 00000000..a1e01088 --- /dev/null +++ b/src/core/renderer_gl/textures.cpp @@ -0,0 +1,52 @@ +#include "renderer_gl/textures.hpp" + +void Texture::allocate() { + Helpers::panic("Tried to allocate texture"); +} + +void Texture::free() { + valid = false; + + if (texture.exists()) + Helpers::panic("Make this texture free itself"); +} + +u64 Texture::sizeInBytes() { + u64 pixelCount = u64(size.x()) * u64(size.y()); + + switch (format) { + case Formats::RGBA8: // 4 bytes per pixel + return pixelCount * 4; + + case Formats::RGB8: // 3 bytes per pixel + return pixelCount * 3; + + case Formats::RGBA5551: // 2 bytes per pixel + case Formats::RGB565: + case Formats::RGBA4: + case Formats::RG8: + case Formats::IA8: + return pixelCount * 2; + + case Formats::A8: // 1 byte per pixel + case Formats::I8: + case Formats::IA4: + return pixelCount; + + case Formats::I4: // 4 bits per pixel + case Formats::A4: + return pixelCount / 2; + + case Formats::ETC1: // Compressed formats + case Formats::ETC1A4: { + // Number of 8x8 tiles + const u64 tileCount = pixelCount / 64; + // Each 8x8 consists of 4 4x4 tiles, which are 8 bytes each on ETC1 and 16 bytes each on ETC1A4 + const u64 tileSize = 4 * (format == Formats::ETC1 ? 8 : 16); + return tileCount * tileSize; + } + + default: + Helpers::panic("[PICA] Attempted to get size of invalid texture type"); + } +} \ No newline at end of file