A kissable commit

Minor fixes
This commit is contained in:
offtkp 2024-07-19 18:49:21 +03:00
parent 1b779cafa1
commit 78ac8d2c0d
10 changed files with 649 additions and 27 deletions

View file

@ -0,0 +1,75 @@
// For asynchronous shader compilation (hybrid mode)
// See docs/3ds/async_shader_compilation.md for more info
#pragma once
#include <atomic>
#include <vector>
#include <thread>
#include "helpers.hpp"
#include "opengl.hpp"
#include "PICA/pica_frag_config.hpp"
#include "spsc/queue.hpp"
// We make the assumption that not more than 256 shaders will be queued at once.
// This may seem like a hack, but it's a reasonable assumption and it allows us to not have
// to implement a waiting mechanism (wait until the queue is not full)
// In the unlikely event that either queue is full, a panic will be triggered.
constexpr size_t maxInFlightShaderCount = 256;
// A compiled program, ready to be passed to glProgramBinary
struct CompiledProgram
{
CompiledProgram(const PICA::FragmentConfig& fsConfig)
: fsConfig(fsConfig)
{}
PICA::FragmentConfig fsConfig;
std::vector<u8> binary;
u32 binaryFormat;
};
namespace PICA
{
namespace ShaderGen
{
class FragmentGenerator;
}
};
struct AsyncCompilerState
{
// The constructor will start the thread that will compile the shaders and create an OpenGL context
explicit AsyncCompilerState(PICA::ShaderGen::FragmentGenerator& fragShaderGen);
// The destructor will first set the stop flag and join the thread (which will wait until it exits)
// and then clean up the queues
~AsyncCompilerState();
// Called from the emulator thread to queue a fragment configuration for compilation
// Returns false if the queue is full, true otherwise
bool PushFragmentConfig(const PICA::FragmentConfig& config);
// Called from the emulator thread to get a compiled program
// Returns true if a compiled program is available, false otherwise
bool PopCompiledProgram(CompiledProgram*& program);
// Manually starts the thread
void Start();
// Manually stops the thread
void Stop();
private:
void createGLContext();
void destroyGLContext();
PICA::ShaderGen::FragmentGenerator& fragShaderGen;
OpenGL::Shader defaultShadergenVs;
// Pointers are used in these queues because the lock-free queue require trivial types
lockfree::spsc::Queue<PICA::FragmentConfig*, maxInFlightShaderCount> configQueue;
lockfree::spsc::Queue<CompiledProgram*, maxInFlightShaderCount> compiledQueue;
std::atomic_bool running = false;
std::thread shaderCompilationThread;
};

View file

@ -6,6 +6,7 @@
#include <span>
#include <unordered_map>
#include "async_compiler.hpp"
#include "PICA/float_types.hpp"
#include "PICA/pica_frag_config.hpp"
#include "PICA/pica_hash.hpp"
@ -22,6 +23,13 @@
// More circular dependencies!
class GPU;
// Cached recompiled fragment shader
struct CachedProgram {
OpenGL::Program program;
uint uboBinding;
bool ready = false;
};
class RendererGL final : public Renderer {
GLStateManager gl = {};
@ -76,10 +84,14 @@ class RendererGL final : public Renderer {
OpenGL::Program program;
};
std::unordered_map<PICA::FragmentConfig, CachedProgram> shaderCache;
std::unique_ptr<AsyncCompilerState> asyncCompiler;
void startCompilationThread();
void stopCompilationThread();
OpenGL::Framebuffer getColourFBO();
OpenGL::Texture getTexture(Texture& tex);
OpenGL::Program& getSpecializedShader();
OpenGL::Program& getSpecializedShader(const PICA::FragmentConfig& fsConfig);
PICA::ShaderGen::FragmentGenerator fragShaderGen;