Merge branch 'bottom-screen' of github.com:fleroviux/Panda3DS into pica-tev-emulation

This commit is contained in:
fleroviux 2023-06-17 12:38:33 +02:00
commit 3aeef23b2e
14 changed files with 160 additions and 62 deletions

14
.clang-format Normal file
View file

@ -0,0 +1,14 @@
BasedOnStyle: Google
IndentWidth: 4
ColumnLimit: 150
AccessModifierOffset: -2
TabWidth: 4
NamespaceIndentation: All
UseTab: ForContinuationAndIndentation
AllowShortEnumsOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
Cpp11BracedListStyle: true
PackConstructorInitializers: BinPack
AlignAfterOpenBracket: BlockIndent

39
.github/workflows/Windows_Build.yml vendored Normal file
View file

@ -0,0 +1,39 @@
name: Windows Build
on:
push:
branches:
- master
pull_request:
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Release
jobs:
build:
# The CMake configure and build commands are platform agnostic and should work equally
# well on Windows or Mac. You can convert this to a matrix build if you need
# cross-platform coverage.
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- name: Fetch submodules
run: git submodule update --init --recursive
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
- name: Build
# Build your program with the given configuration
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
- name: Upload executable
uses: actions/upload-artifact@v2
with:
name: Windows executable
path: './build/Release/Alber.exe'

View file

@ -1,4 +1,5 @@
#pragma once #pragma once
#include "helpers.hpp"
namespace PICAInternalRegs { namespace PICAInternalRegs {
enum : u32 { enum : u32 {
@ -71,7 +72,7 @@ namespace PICAInternalRegs {
FixedAttribData0 = 0x233, FixedAttribData0 = 0x233,
FixedAttribData1 = 0x234, FixedAttribData1 = 0x234,
FixedAttribData2 = 0x235, FixedAttribData2 = 0x235,
// Command processor registers // Command processor registers
CmdBufSize0 = 0x238, CmdBufSize0 = 0x238,
CmdBufSize1 = 0x239, CmdBufSize1 = 0x239,

View file

@ -1,5 +1,7 @@
#pragma once #pragma once
#include <span>
#include "dynarmic/interface/A32/a32.h" #include "dynarmic/interface/A32/a32.h"
#include "dynarmic/interface/A32/config.h" #include "dynarmic/interface/A32/config.h"
#include "dynarmic/interface/exclusive_monitor.h" #include "dynarmic/interface/exclusive_monitor.h"
@ -132,17 +134,11 @@ public:
return jit->Regs()[index]; return jit->Regs()[index];
} }
std::array<u32, 16>& regs() { std::span<u32, 16> regs() { return jit->Regs(); }
return jit->Regs();
}
// Get reference to array of FPRs. This array consists of the FPRs as single precision values // Get reference to array of FPRs. This array consists of the FPRs as single precision values
// Hence why its base type is u32 // Hence why its base type is u32
// Note: Dynarmic keeps 64 VFP registers as VFPv3 extends the VFP register set to 64 registers. std::span<u32, 32> fprs() { return std::span(jit->ExtRegs()).first<32>(); }
// However the 3DS ARM11 is an ARMv6k processor with VFPv2, so only the first 32 registers are actually used
std::array<u32, 64>& fprs() {
return jit->ExtRegs();
}
void setCPSR(u32 value) { void setCPSR(u32 value) {
jit->SetCpsr(value); jit->SetCpsr(value);

View file

@ -2,10 +2,12 @@
#include <array> #include <array>
#include <cassert> #include <cassert>
#include <limits> #include <limits>
#include <span>
#include <string> #include <string>
#include <vector> #include <vector>
#include "kernel_types.hpp"
#include "helpers.hpp" #include "helpers.hpp"
#include "kernel_types.hpp"
#include "logger.hpp" #include "logger.hpp"
#include "memory.hpp" #include "memory.hpp"
#include "resource_limits.hpp" #include "resource_limits.hpp"
@ -14,7 +16,7 @@
class CPU; class CPU;
class Kernel { class Kernel {
std::array<u32, 16>& regs; std::span<u32, 16> regs;
CPU& cpu; CPU& cpu;
Memory& mem; Memory& mem;

View file

@ -30,6 +30,19 @@
#include "gl3w.h" #include "gl3w.h"
// Check if we have C++20. If yes, we can add C++20 std::span support
#ifdef _MSVC_LANG // MSVC does not properly define __cplusplus without a compiler flag...
#if _MSVC_LANG >= 202002L
#define OPENGL_HAVE_CPP20
#endif
#elif __cplusplus >= 202002L
#define OPENGL_HAVE_CPP20
#endif // MSVC_LANG
#ifdef OPENGL_HAVE_CPP20
#include <span>
#endif
// Uncomment the following define if you want GL objects to automatically free themselves when their lifetime ends // Uncomment the following define if you want GL objects to automatically free themselves when their lifetime ends
// #define OPENGL_DESTRUCTORS // #define OPENGL_DESTRUCTORS
@ -389,17 +402,30 @@ namespace OpenGL {
void free() { glDeleteBuffers(1, &m_handle); } void free() { glDeleteBuffers(1, &m_handle); }
// Reallocates the buffer on every call. Prefer the sub version if possible. // Reallocates the buffer on every call. Prefer the sub version if possible.
template <typename VertType> template <typename VertType>
void bufferVerts(VertType* vertices, int vertCount, GLenum usage = GL_DYNAMIC_DRAW) { void bufferVerts(VertType* vertices, int vertCount, GLenum usage = GL_DYNAMIC_DRAW) {
glBufferData(GL_ARRAY_BUFFER, sizeof(VertType) * vertCount, vertices, usage); glBufferData(GL_ARRAY_BUFFER, sizeof(VertType) * vertCount, vertices, usage);
} }
// Only use if you used createFixedSize // Only use if you used createFixedSize
template <typename VertType> template <typename VertType>
void bufferVertsSub(VertType* vertices, int vertCount, GLintptr offset = 0) { void bufferVertsSub(VertType* vertices, int vertCount, GLintptr offset = 0) {
glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(VertType) * vertCount, vertices); glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(VertType) * vertCount, vertices);
} }
};
// If C++20 is available, add overloads that take std::span instead of raw pointers
#ifdef OPENGL_HAVE_CPP20
template <typename VertType>
void bufferVerts(std::span<const VertType> vertices, GLenum usage = GL_DYNAMIC_DRAW) {
glBufferData(GL_ARRAY_BUFFER, sizeof(VertType) * vertices.size(), vertices.data(), usage);
}
template <typename VertType>
void bufferVertsSub(std::span<const VertType> vertices, GLintptr offset = 0) {
glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(VertType) * vertices.size(), vertices.data());
}
#endif
};
enum DepthFunc { enum DepthFunc {
Never = GL_NEVER, // Depth test never passes Never = GL_NEVER, // Depth test never passes

View file

@ -1,5 +1,7 @@
#pragma once #pragma once
#include <array> #include <array>
#include <span>
#include "helpers.hpp" #include "helpers.hpp"
#include "logger.hpp" #include "logger.hpp"
#include "opengl.hpp" #include "opengl.hpp"
@ -50,11 +52,11 @@ class Renderer {
SurfaceCache<ColourBuffer, 10> colourBufferCache; SurfaceCache<ColourBuffer, 10> colourBufferCache;
SurfaceCache<Texture, 256> textureCache; SurfaceCache<Texture, 256> textureCache;
OpenGL::uvec2 fbSize; // The size of the framebuffer (ie both the colour and depth buffer)' OpenGL::uvec2 fbSize; // The size of the framebuffer (ie both the colour and depth buffer)'
u32 colourBufferLoc; // Location in 3DS VRAM for the colour buffer
ColourBuffer::Formats colourBufferFormat; // Format of the colours stored in the colour buffer
u32 colourBufferLoc; // Location in 3DS VRAM for the colour buffer
ColourBuffer::Formats colourBufferFormat; // Format of the colours stored in the colour buffer
// Same for the depth/stencil buffer // Same for the depth/stencil buffer
u32 depthBufferLoc; u32 depthBufferLoc;
DepthBuffer::Formats depthBufferFormat; DepthBuffer::Formats depthBufferFormat;
@ -63,7 +65,7 @@ class Renderer {
OpenGL::VertexArray dummyVAO; OpenGL::VertexArray dummyVAO;
OpenGL::VertexBuffer dummyVBO; OpenGL::VertexBuffer dummyVBO;
static constexpr u32 regNum = 0x300; // Number of internal PICA registers static constexpr u32 regNum = 0x300; // Number of internal PICA registers
const std::array<u32, regNum>& regs; const std::array<u32, regNum>& regs;
OpenGL::Texture screenTexture; OpenGL::Texture screenTexture;
@ -77,16 +79,16 @@ class Renderer {
void bindDepthBuffer(); void bindDepthBuffer();
void setupTextureEnvState(); void setupTextureEnvState();
public: public:
Renderer(GPU& gpu, const std::array<u32, regNum>& internalRegs) : gpu(gpu), regs(internalRegs) {} Renderer(GPU& gpu, const std::array<u32, regNum>& internalRegs) : gpu(gpu), regs(internalRegs) {}
void reset(); void reset();
void display(); // Display the 3DS screen contents to the window void display(); // Display the 3DS screen contents to the window
void initGraphicsContext(); // Initialize graphics context void initGraphicsContext(); // Initialize graphics context
void getGraphicsContext(); // Set up graphics context for rendering void getGraphicsContext(); // Set up graphics context for rendering
void clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control); // Clear a GPU buffer in VRAM void clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control); // Clear a GPU buffer in VRAM
void displayTransfer(u32 inputAddr, u32 outputAddr, u32 inputSize, u32 outputSize, u32 flags); // Perform display transfer void displayTransfer(u32 inputAddr, u32 outputAddr, u32 inputSize, u32 outputSize, u32 flags); // Perform display transfer
void drawVertices(OpenGL::Primitives primType, Vertex* vertices, u32 count); // Draw the given vertices void drawVertices(OpenGL::Primitives primType, std::span<const Vertex> vertices); // Draw the given vertices
void setFBSize(u32 width, u32 height) { void setFBSize(u32 width, u32 height) {
fbSize.x() = width; fbSize.x() = width;

View file

@ -1,6 +1,8 @@
#pragma once #pragma once
#include <array> #include <array>
#include <optional> #include <optional>
#include <span>
#include "kernel_types.hpp" #include "kernel_types.hpp"
#include "logger.hpp" #include "logger.hpp"
#include "memory.hpp" #include "memory.hpp"
@ -14,16 +16,16 @@
#include "services/cfg.hpp" #include "services/cfg.hpp"
#include "services/dlp_srvr.hpp" #include "services/dlp_srvr.hpp"
#include "services/dsp.hpp" #include "services/dsp.hpp"
#include "services/hid.hpp"
#include "services/frd.hpp" #include "services/frd.hpp"
#include "services/fs.hpp" #include "services/fs.hpp"
#include "services/gsp_gpu.hpp" #include "services/gsp_gpu.hpp"
#include "services/gsp_lcd.hpp" #include "services/gsp_lcd.hpp"
#include "services/hid.hpp"
#include "services/ldr_ro.hpp" #include "services/ldr_ro.hpp"
#include "services/mic.hpp" #include "services/mic.hpp"
#include "services/ndm.hpp"
#include "services/nfc.hpp" #include "services/nfc.hpp"
#include "services/nim.hpp" #include "services/nim.hpp"
#include "services/ndm.hpp"
#include "services/ptm.hpp" #include "services/ptm.hpp"
#include "services/y2r.hpp" #include "services/y2r.hpp"
@ -31,7 +33,7 @@
class Kernel; class Kernel;
class ServiceManager { class ServiceManager {
std::array<u32, 16>& regs; std::span<u32, 16> regs;
Memory& mem; Memory& mem;
Kernel& kernel; Kernel& kernel;
@ -69,8 +71,8 @@ class ServiceManager {
void registerClient(u32 messagePointer); void registerClient(u32 messagePointer);
void subscribe(u32 messagePointer); void subscribe(u32 messagePointer);
public: public:
ServiceManager(std::array<u32, 16>& regs, Memory& mem, GPU& gpu, u32& currentPID, Kernel& kernel); ServiceManager(std::span<u32, 16> regs, Memory& mem, GPU& gpu, u32& currentPID, Kernel& kernel);
void reset(); void reset();
void initializeFS() { fs.initializeFilesystem(); } void initializeFS() { fs.initializeFilesystem(); }
void handleSyncRequest(u32 messagePointer); void handleSyncRequest(u32 messagePointer);

View file

@ -1,7 +1,13 @@
# Panda3DS # Panda3DS
[![Windows Build](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Windows_Build.yml/badge.svg?branch=master)](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Windows_Build.yml) [![MacOS Build](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/MacOS_Build.yml/badge.svg?branch=master)](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/MacOS_Build.yml) [![Linux Build](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Linux_Build.yml/badge.svg?branch=master)](https://github.com/wheremyfoodat/Panda3DS/actions/workflows/Linux_Build.yml)
Panda3DS is an HLE, red-panda-themed Nintendo 3DS emulator written in C++ which started out as a fun project out of curiosity, but evolved into something that can sort of play games! Panda3DS is an HLE, red-panda-themed Nintendo 3DS emulator written in C++ which started out as a fun project out of curiosity, but evolved into something that can sort of play games!
# Discussion
Join our Discord server by pressing on the banner below!
[![Discord Banner 2](https://discord.com/api/guilds/1118695732958994532/widget.png?style=banner2)](https://discord.gg/ZYbugsEmsw)
![screenshot1](docs/img/MK7_Car_Select.png) ![screenshot2](docs/img/OoT_Title.png) ![screenshot3](docs/img/Mayro.png) ![screenshot1](docs/img/MK7_Car_Select.png) ![screenshot2](docs/img/OoT_Title.png) ![screenshot3](docs/img/Mayro.png)
# Compatibility # Compatibility

View file

@ -1,7 +1,10 @@
#include "PICA/gpu.hpp" #include "PICA/gpu.hpp"
#include <array>
#include <cstdio>
#include "PICA/float_types.hpp" #include "PICA/float_types.hpp"
#include "PICA/regs.hpp" #include "PICA/regs.hpp"
#include <cstdio>
using namespace Floats; using namespace Floats;
@ -41,7 +44,7 @@ void GPU::drawArrays(bool indexed) {
drawArrays<false>(); drawArrays<false>();
} }
Vertex* vertices = new Vertex[Renderer::vertexBufferSize]; static std::array<Vertex, Renderer::vertexBufferSize> vertices;
template <bool indexed> template <bool indexed>
void GPU::drawArrays() { void GPU::drawArrays() {
@ -205,7 +208,7 @@ void GPU::drawArrays() {
OpenGL::Triangle, OpenGL::TriangleStrip, OpenGL::TriangleFan, OpenGL::Triangle OpenGL::Triangle, OpenGL::TriangleStrip, OpenGL::TriangleFan, OpenGL::Triangle
}; };
const auto shape = primTypes[primType]; const auto shape = primTypes[primType];
renderer.drawVertices(shape, vertices, vertexCount); renderer.drawVertices(shape, std::span(vertices).first(vertexCount));
} }
Vertex GPU::getImmediateModeVertex() { Vertex GPU::getImmediateModeVertex() {

View file

@ -157,7 +157,7 @@ void GPU::writeInternalReg(u32 index, u32 value, u32 mask) {
// If we've reached 3 verts, issue a draw call // If we've reached 3 verts, issue a draw call
// Handle rendering depending on the primitive type // Handle rendering depending on the primitive type
if (immediateModeVertIndex == 3) { if (immediateModeVertIndex == 3) {
renderer.drawVertices(OpenGL::Triangle, &immediateModeVertices[0], 3); renderer.drawVertices(OpenGL::Triangle, immediateModeVertices);
switch (primType) { switch (primType) {
// Triangle or geometry primitive. Draw a triangle and discard all vertices // Triangle or geometry primitive. Draw a triangle and discard all vertices

View file

@ -1,8 +1,10 @@
#include <cassert> #include <cassert>
#include <cstring> #include <cstring>
#include "kernel.hpp"
#include "arm_defs.hpp" #include "arm_defs.hpp"
// This header needs to be included because I did stupid forward decl hack so the kernel and CPU can both access each other #include "kernel.hpp"
// This header needs to be included because I did stupid forward decl hack so the kernel and CPU can both access each
// other
#include "cpu.hpp" #include "cpu.hpp"
#include "resource_limits.hpp" #include "resource_limits.hpp"
@ -20,17 +22,17 @@ void Kernel::switchThread(int newThreadIndex) {
} }
// Backup context // Backup context
std::memcpy(&oldThread.gprs[0], &cpu.regs()[0], 16 * sizeof(u32)); // Backup the 16 GPRs std::memcpy(oldThread.gprs.data(), cpu.regs().data(), cpu.regs().size_bytes()); // Backup the 16 GPRs
std::memcpy(&oldThread.fprs[0], &cpu.fprs()[0], 32 * sizeof(u32)); // Backup the 32 FPRs std::memcpy(oldThread.fprs.data(), cpu.fprs().data(), cpu.fprs().size_bytes()); // Backup the 32 FPRs
oldThread.cpsr = cpu.getCPSR(); // Backup CPSR oldThread.cpsr = cpu.getCPSR(); // Backup CPSR
oldThread.fpscr = cpu.getFPSCR(); // Backup FPSCR oldThread.fpscr = cpu.getFPSCR(); // Backup FPSCR
// Load new context // Load new context
std::memcpy(&cpu.regs()[0], &newThread.gprs[0], 16 * sizeof(u32)); // Load 16 GPRs std::memcpy(cpu.regs().data(), newThread.gprs.data(), cpu.regs().size_bytes()); // Load 16 GPRs
std::memcpy(&cpu.fprs()[0], &newThread.fprs[0], 32 * sizeof(u32)); // Load 32 FPRs std::memcpy(cpu.fprs().data(), newThread.fprs.data(), cpu.fprs().size_bytes()); // Load 32 FPRs
cpu.setCPSR(newThread.cpsr); // Load CPSR cpu.setCPSR(newThread.cpsr); // Load CPSR
cpu.setFPSCR(newThread.fpscr); // Load FPSCR cpu.setFPSCR(newThread.fpscr); // Load FPSCR
cpu.setTLSBase(newThread.tlsBase); // Load CP15 thread-local-storage pointer register cpu.setTLSBase(newThread.tlsBase); // Load CP15 thread-local-storage pointer register
currentThreadIndex = newThreadIndex; currentThreadIndex = newThreadIndex;
} }

View file

@ -475,7 +475,10 @@ void Renderer::setupTextureEnvState() {
glUniform4f(textureEnvBufferColorLoc, r, g, b, a); glUniform4f(textureEnvBufferColorLoc, r, g, b, a);
} }
void Renderer::drawVertices(OpenGL::Primitives primType, Vertex* vertices, u32 count) { void Renderer::drawVertices(OpenGL::Primitives primType, std::span<const Vertex> vertices) {
// 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(); OpenGL::disableScissor();
vbo.bind(); vbo.bind();
@ -570,8 +573,8 @@ void Renderer::drawVertices(OpenGL::Primitives primType, Vertex* vertices, u32 c
} }
} }
vbo.bufferVertsSub(vertices, count); vbo.bufferVertsSub(vertices);
OpenGL::draw(primType, count); OpenGL::draw(primType, vertices.size());
} }
constexpr u32 topScreenBuffer = 0x1f000000; constexpr u32 topScreenBuffer = 0x1f000000;

View file

@ -1,13 +1,15 @@
#include "services/service_manager.hpp" #include "services/service_manager.hpp"
#include <map> #include <map>
#include "ipc.hpp" #include "ipc.hpp"
#include "kernel.hpp" #include "kernel.hpp"
ServiceManager::ServiceManager(std::array<u32, 16>& regs, Memory& mem, GPU& gpu, u32& currentPID, Kernel& kernel) ServiceManager::ServiceManager(std::span<u32, 16> regs, Memory& mem, GPU& gpu, u32& currentPID, Kernel& kernel)
: regs(regs), mem(mem), kernel(kernel), ac(mem), am(mem), boss(mem), act(mem), apt(mem, kernel), cam(mem), : regs(regs), mem(mem), kernel(kernel), ac(mem), am(mem), boss(mem), act(mem), apt(mem, kernel), cam(mem),
cecd(mem, kernel), cfg(mem), dlp_srvr(mem), dsp(mem, kernel), hid(mem, kernel), frd(mem), fs(mem, kernel), cecd(mem, kernel), cfg(mem), dlp_srvr(mem), dsp(mem, kernel), hid(mem, kernel), frd(mem), fs(mem, kernel),
gsp_gpu(mem, gpu, kernel, currentPID), gsp_lcd(mem), ldr(mem), mic(mem), nfc(mem, kernel), nim(mem), ndm(mem), gsp_gpu(mem, gpu, kernel, currentPID), gsp_lcd(mem), ldr(mem), mic(mem), nfc(mem, kernel), nim(mem), ndm(mem),
ptm(mem), y2r(mem, kernel) {} ptm(mem), y2r(mem, kernel) {}
static constexpr int MAX_NOTIFICATION_COUNT = 16; static constexpr int MAX_NOTIFICATION_COUNT = 16;