Actually implement the damn thing

This commit is contained in:
offtkp 2024-08-08 16:39:59 +03:00
parent c396b3f225
commit 67069a8826
7 changed files with 274 additions and 21 deletions

View file

@ -206,6 +206,24 @@ namespace PICA {
return std::memcmp(this, &config, sizeof(FragmentConfig)) == 0;
}
FragmentConfig& operator=(const FragmentConfig& config) {
// BitField copy constructor is deleted for reasons, so we have to do this manually
outConfig.raw = config.outConfig.raw;
texConfig = config.texConfig;
fogConfig.raw = config.fogConfig.raw;
lighting.raw = config.lighting.raw;
for (int i = 0; i < 7; i++) {
lighting.luts[i].raw = config.lighting.luts[i].raw;
}
for (int i = 0; i < 8; i++) {
lighting.lights[i].raw = config.lighting.lights[i].raw;
}
// If this fails you probably added a new field to the struct and forgot to update the copy constructor
static_assert(sizeof(FragmentConfig) == sizeof(outConfig.raw) + sizeof(texConfig) + sizeof(fogConfig.raw) + sizeof(lighting.raw) + 7 * sizeof(LightingLUTConfig) + 8 * sizeof(Light));
return *this;
}
FragmentConfig(const std::array<u32, 0x300>& regs) : lighting(regs) {
auto alphaTestConfig = regs[InternalRegs::AlphaTestConfig];
auto alphaTestFunction = Helpers::getBits<4, 3>(alphaTestConfig);

View file

@ -0,0 +1,54 @@
#pragma once
#include <atomic>
#include <thread>
#include "opengl.hpp"
#include "renderer_gl/renderer_gl.hpp"
#include "PICA/pica_frag_config.hpp"
#include "lockfree/spsc/queue.hpp"
namespace PICA::ShaderGen
{
class FragmentGenerator;
}
namespace AsyncCompiler
{
void* createContext(void* userdata);
void makeCurrent(void* userdata, void* context);
void destroyContext(void* context);
}
struct CompilingProgram
{
CachedProgram* program;
PICA::FragmentConfig* config;
};
struct AsyncCompilerThread
{
explicit AsyncCompilerThread(PICA::ShaderGen::FragmentGenerator& fragShaderGen, void* userdata);
~AsyncCompilerThread();
// Called from the emulator thread to queue a fragment configuration for compilation
// Returns false if the queue is full, true otherwise
void PushFragmentConfig(const PICA::FragmentConfig& config, CachedProgram* cachedProgram);
// Wait for all queued fragment configurations to be compiled
void Finish();
private:
PICA::ShaderGen::FragmentGenerator& fragShaderGen;
OpenGL::Shader defaultShadergenVs;
// Our lockfree queue only allows for trivial types, so we preallocate enough structs
// to avoid dynamic allocation on each push
int preallocatedProgramsIndex;
static constexpr int preallocatedProgramsSize = 256;
std::array<CompilingProgram*, preallocatedProgramsSize> preallocatedPrograms;
lockfree::spsc::Queue<CompilingProgram*, preallocatedProgramsSize - 1> programQueue;
std::atomic_bool running;
std::atomic_flag hasWork = ATOMIC_FLAG_INIT;
std::thread thread;
};

View file

@ -23,6 +23,15 @@
// More circular dependencies!
class GPU;
// Cached recompiled fragment shader
struct CachedProgram {
OpenGL::Program program;
std::atomic_bool compiling = false;
bool needsInitialization = true;
};
struct AsyncCompilerThread;
class RendererGL final : public Renderer {
GLStateManager gl = {};
@ -72,12 +81,10 @@ class RendererGL final : public Renderer {
OpenGL::Shader defaultShadergenVs;
GLuint shadergenFragmentUBO;
// Cached recompiled fragment shader
struct CachedProgram {
OpenGL::Program program;
};
std::unordered_map<PICA::FragmentConfig, CachedProgram> shaderCache;
AsyncCompilerThread* asyncCompiler = nullptr;
OpenGL::Framebuffer getColourFBO();
OpenGL::Texture getTexture(Texture& tex);
OpenGL::Program& getSpecializedShader();
@ -101,7 +108,6 @@ class RendererGL final : public Renderer {
void reset() override;
void display() override; // Display the 3DS screen contents to the window
void initGraphicsContext(SDL_Window* window) override; // Initialize graphics context
void clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control) override; // Clear a GPU buffer in VRAM
void displayTransfer(u32 inputAddr, u32 outputAddr, u32 inputSize, u32 outputSize, u32 flags) override; // Perform display transfer
void textureCopy(u32 inputAddr, u32 outputAddr, u32 totalBytes, u32 inputSize, u32 outputSize, u32 flags) override;
@ -123,7 +129,9 @@ class RendererGL final : public Renderer {
void initUbershader(OpenGL::Program& program);
#ifdef PANDA3DS_FRONTEND_QT
virtual void initGraphicsContext([[maybe_unused]] GL::Context* context) override { initGraphicsContextInternal(); }
virtual void initGraphicsContext(GL::Context* context) override;
#elif defined(PANDA3DS_FRONTEND_SDL)
virtual void initGraphicsContext(SDL_Window* window) override;
#endif
// Take a screenshot of the screen and store it in a file