#pragma once #include "common.h" #include "sync.hpp" #include "Emu/RSX/Program/GLSLTypes.h" #include "Utilities/geometry.h" #include "Utilities/mutex.h" namespace gl { namespace glsl { class shader { std::string source; ::glsl::program_domain type; GLuint m_id = GL_NONE; fence m_compiled_fence; fence m_init_fence; shared_mutex m_compile_lock; atomic_t m_is_compiled{}; void precompile(); public: shader() = default; shader(::glsl::program_domain type_, const std::string& src) { create(type_, src); } ~shader() { remove(); } void remove() { if (m_id) { glDeleteShader(m_id); m_id = GL_NONE; } } void create(::glsl::program_domain type_, const std::string& src); shader& compile(); uint id() const { return m_id; } const std::string& get_source() const { return source; } fence get_compile_fence_sync() const { return m_compiled_fence; } bool created() const { return m_id != GL_NONE; } bool compiled() const { return m_is_compiled; } explicit operator bool() const { return created(); } }; class program { GLuint m_id = GL_NONE; fence m_fence; public: class uniform_t { program& m_program; GLint m_location; public: uniform_t(program& program, GLint location) : m_program(program) , m_location(location) { } GLint location() const { return m_location; } void operator = (int rhs) const { glProgramUniform1i(m_program.id(), location(), rhs); } void operator = (unsigned rhs) const { glProgramUniform1ui(m_program.id(), location(), rhs); } void operator = (float rhs) const { glProgramUniform1f(m_program.id(), location(), rhs); } void operator = (bool rhs) const { glProgramUniform1ui(m_program.id(), location(), rhs ? 1 : 0); } void operator = (const color1i& rhs) const { glProgramUniform1i(m_program.id(), location(), rhs.r); } void operator = (const color1f& rhs) const { glProgramUniform1f(m_program.id(), location(), rhs.r); } void operator = (const color2i& rhs) const { glProgramUniform2i(m_program.id(), location(), rhs.r, rhs.g); } void operator = (const color2f& rhs) const { glProgramUniform2f(m_program.id(), location(), rhs.r, rhs.g); } void operator = (const color3i& rhs) const { glProgramUniform3i(m_program.id(), location(), rhs.r, rhs.g, rhs.b); } void operator = (const color3f& rhs) const { glProgramUniform3f(m_program.id(), location(), rhs.r, rhs.g, rhs.b); } void operator = (const color4i& rhs) const { glProgramUniform4i(m_program.id(), location(), rhs.r, rhs.g, rhs.b, rhs.a); } void operator = (const color4f& rhs) const { glProgramUniform4f(m_program.id(), location(), rhs.r, rhs.g, rhs.b, rhs.a); } void operator = (const areaf& rhs) const { glProgramUniform4f(m_program.id(), location(), rhs.x1, rhs.y1, rhs.x2, rhs.y2); } void operator = (const areai& rhs) const { glProgramUniform4i(m_program.id(), location(), rhs.x1, rhs.y1, rhs.x2, rhs.y2); } void operator = (const std::vector& rhs) const { glProgramUniform1iv(m_program.id(), location(), ::size32(rhs), rhs.data()); } }; class uniforms_t { program& m_program; std::unordered_map locations; public: uniforms_t(program* program) : m_program(*program) {} void clear() { locations.clear(); } bool has_location(const std::string& name, int* location = nullptr); GLint location(const std::string& name); uniform_t operator[](GLint location) { return{ m_program, location }; } uniform_t operator[](const std::string& name) { return{ m_program, location(name) }; } } uniforms{ this }; public: program() = default; program(const program&) = delete; ~program() { if (created()) { remove(); } } program& recreate() { remove(); return create(); } program& create() { m_id = glCreateProgram(); return *this; } void remove() { glDeleteProgram(m_id); m_id = GL_NONE; uniforms.clear(); } void link(std::function init_func = {}); void validate(); void sync() { if (!m_fence.check_signaled()) { m_fence.server_wait_sync(); } } program& attach(const shader& shader_) { glAttachShader(m_id, shader_.id()); return *this; } program& bind_attribute_location(const std::string& name, int index) { glBindAttribLocation(m_id, index, name.c_str()); return *this; } program& bind_fragment_data_location(const std::string& name, int color_number) { glBindFragDataLocation(m_id, color_number, name.c_str()); return *this; } GLuint id() const { return m_id; } bool created() const { return m_id != GL_NONE; } explicit operator bool() const { return created(); } }; } }