diff --git a/Utilities/geometry.h b/Utilities/geometry.h index ee8aeb2332..b90286c54c 100644 --- a/Utilities/geometry.h +++ b/Utilities/geometry.h @@ -700,6 +700,12 @@ template struct size3_base { T width, height, depth; + + template + explicit constexpr operator size3_base() const + { + return{ static_cast(width), static_cast(height), static_cast(depth) }; + } }; template diff --git a/rpcs3/Emu/RSX/GL/GLCompute.h b/rpcs3/Emu/RSX/GL/GLCompute.h index a8da96e083..03dec70c49 100644 --- a/rpcs3/Emu/RSX/GL/GLCompute.h +++ b/rpcs3/Emu/RSX/GL/GLCompute.h @@ -2,6 +2,7 @@ #include "Emu/IdManager.h" #include "GLHelpers.h" +#include "glutils/program.h" #include "../rsx_utils.h" #include diff --git a/rpcs3/Emu/RSX/GL/GLFragmentProgram.h b/rpcs3/Emu/RSX/GL/GLFragmentProgram.h index ffd6904af7..fa955f22eb 100644 --- a/rpcs3/Emu/RSX/GL/GLFragmentProgram.h +++ b/rpcs3/Emu/RSX/GL/GLFragmentProgram.h @@ -2,6 +2,7 @@ #include "../Program/FragmentProgramDecompiler.h" #include "../Program/GLSLTypes.h" #include "GLHelpers.h" +#include "glutils/program.h" namespace glsl { diff --git a/rpcs3/Emu/RSX/GL/GLHelpers.cpp b/rpcs3/Emu/RSX/GL/GLHelpers.cpp index 9cb505294e..37ec98f188 100644 --- a/rpcs3/Emu/RSX/GL/GLHelpers.cpp +++ b/rpcs3/Emu/RSX/GL/GLHelpers.cpp @@ -10,9 +10,7 @@ namespace gl { std::unordered_map> g_compute_tasks; - blitter *g_hw_blitter = nullptr; capabilities g_driver_caps; - const fbo screen{}; void flush_command_queue(fence& fence_obj) { @@ -171,271 +169,6 @@ namespace gl return g_driver_caps; } - void fbo::create() - { - glGenFramebuffers(1, &m_id); - } - - void fbo::bind() const - { - glBindFramebuffer(GL_FRAMEBUFFER, m_id); - } - - void fbo::blit(const fbo& dst, areai src_area, areai dst_area, buffers buffers_, filter filter_) const - { - bind_as(target::read_frame_buffer); - dst.bind_as(target::draw_frame_buffer); - glBlitFramebuffer( - src_area.x1, src_area.y1, src_area.x2, src_area.y2, - dst_area.x1, dst_area.y1, dst_area.x2, dst_area.y2, - static_cast(buffers_), static_cast(filter_)); - } - - void fbo::bind_as(target target_) const - { - glBindFramebuffer(static_cast(target_), id()); - } - - void fbo::remove() - { - if (m_id != GL_NONE) - { - glDeleteFramebuffers(1, &m_id); - m_id = GL_NONE; - } - } - - bool fbo::created() const - { - return m_id != GL_NONE; - } - - bool fbo::check() const - { - GLenum status = DSA_CALL2_RET(CheckNamedFramebufferStatus, m_id, GL_FRAMEBUFFER); - - if (status != GL_FRAMEBUFFER_COMPLETE) - { - rsx_log.error("FBO check failed: 0x%04x", status); - return false; - } - - return true; - } - - void fbo::recreate() - { - if (created()) - remove(); - - create(); - } - - void fbo::draw_buffer(const attachment& buffer) const - { - GLenum buf = buffer.id(); - DSA_CALL3(NamedFramebufferDrawBuffers, FramebufferDrawBuffers, m_id, 1, &buf); - } - - void fbo::draw_buffers(const std::initializer_list& indexes) const - { - rsx::simple_array ids; - ids.reserve(::size32(indexes)); - - for (auto &index : indexes) - ids.push_back(index.id()); - - DSA_CALL3(NamedFramebufferDrawBuffers, FramebufferDrawBuffers, m_id, static_cast(ids.size()), ids.data()); - } - - void fbo::read_buffer(const attachment& buffer) const - { - DSA_CALL3(NamedFramebufferReadBuffer, FramebufferReadBuffer, m_id, buffer.id()); - } - - void fbo::draw_arrays(rsx::primitive_type mode, GLsizei count, GLint first) const - { - save_binding_state save(*this); - glDrawArrays(draw_mode(mode), first, count); - } - - void fbo::draw_arrays(const buffer& buffer, rsx::primitive_type mode, GLsizei count, GLint first) const - { - buffer.bind(buffer::target::array); - draw_arrays(mode, count, first); - } - - void fbo::draw_arrays(const vao& buffer, rsx::primitive_type mode, GLsizei count, GLint first) const - { - buffer.bind(); - draw_arrays(mode, count, first); - } - - void fbo::draw_elements(rsx::primitive_type mode, GLsizei count, indices_type type, const GLvoid *indices) const - { - save_binding_state save(*this); - glDrawElements(draw_mode(mode), count, static_cast(type), indices); - } - - void fbo::draw_elements(const buffer& buffer, rsx::primitive_type mode, GLsizei count, indices_type type, const GLvoid *indices) const - { - buffer.bind(buffer::target::array); - glDrawElements(draw_mode(mode), count, static_cast(type), indices); - } - - void fbo::draw_elements(rsx::primitive_type mode, GLsizei count, indices_type type, const buffer& indices, usz indices_buffer_offset) const - { - indices.bind(buffer::target::element_array); - glDrawElements(draw_mode(mode), count, static_cast(type), reinterpret_cast(indices_buffer_offset)); - } - - void fbo::draw_elements(const buffer& buffer_, rsx::primitive_type mode, GLsizei count, indices_type type, const buffer& indices, usz indices_buffer_offset) const - { - buffer_.bind(buffer::target::array); - draw_elements(mode, count, type, indices, indices_buffer_offset); - } - - void fbo::draw_elements(rsx::primitive_type mode, GLsizei count, const GLubyte *indices) const - { - draw_elements(mode, count, indices_type::ubyte, indices); - } - - void fbo::draw_elements(const buffer& buffer, rsx::primitive_type mode, GLsizei count, const GLubyte *indices) const - { - draw_elements(buffer, mode, count, indices_type::ubyte, indices); - } - - void fbo::draw_elements(rsx::primitive_type mode, GLsizei count, const GLushort *indices) const - { - draw_elements(mode, count, indices_type::ushort, indices); - } - - void fbo::draw_elements(const buffer& buffer, rsx::primitive_type mode, GLsizei count, const GLushort *indices) const - { - draw_elements(buffer, mode, count, indices_type::ushort, indices); - } - - void fbo::draw_elements(rsx::primitive_type mode, GLsizei count, const GLuint *indices) const - { - draw_elements(mode, count, indices_type::uint, indices); - } - - void fbo::draw_elements(const buffer& buffer, rsx::primitive_type mode, GLsizei count, const GLuint *indices) const - { - draw_elements(buffer, mode, count, indices_type::uint, indices); - } - - void fbo::clear(buffers buffers_) const - { - save_binding_state save(*this); - glClear(static_cast(buffers_)); - } - - void fbo::clear(buffers buffers_, color4f color_value, double depth_value, u8 stencil_value) const - { - save_binding_state save(*this); - glClearColor(color_value.r, color_value.g, color_value.b, color_value.a); - glClearDepth(depth_value); - glClearStencil(stencil_value); - clear(buffers_); - } - - void fbo::copy_from(const void* pixels, const sizei& size, gl::texture::format format_, gl::texture::type type_, class pixel_unpack_settings pixel_settings) const - { - save_binding_state save(*this); - pixel_settings.apply(); - glDrawPixels(size.width, size.height, static_cast(format_), static_cast(type_), pixels); - } - - void fbo::copy_from(const buffer& buf, const sizei& size, gl::texture::format format_, gl::texture::type type_, class pixel_unpack_settings pixel_settings) const - { - save_binding_state save(*this); - buffer::save_binding_state save_buffer(buffer::target::pixel_unpack, buf); - pixel_settings.apply(); - glDrawPixels(size.width, size.height, static_cast(format_), static_cast(type_), nullptr); - } - - void fbo::copy_to(void* pixels, coordi coord, gl::texture::format format_, gl::texture::type type_, class pixel_pack_settings pixel_settings) const - { - save_binding_state save(*this); - pixel_settings.apply(); - glReadPixels(coord.x, coord.y, coord.width, coord.height, static_cast(format_), static_cast(type_), pixels); - } - - void fbo::copy_to(const buffer& buf, coordi coord, gl::texture::format format_, gl::texture::type type_, class pixel_pack_settings pixel_settings) const - { - save_binding_state save(*this); - buffer::save_binding_state save_buffer(buffer::target::pixel_pack, buf); - pixel_settings.apply(); - glReadPixels(coord.x, coord.y, coord.width, coord.height, static_cast(format_), static_cast(type_), nullptr); - } - - fbo fbo::get_bound_draw_buffer() - { - GLint value; - glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &value); - - return{ static_cast(value) }; - } - - fbo fbo::get_bound_read_buffer() - { - GLint value; - glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &value); - - return{ static_cast(value) }; - } - - fbo fbo::get_bound_buffer() - { - GLint value; - glGetIntegerv(GL_FRAMEBUFFER_BINDING, &value); - - return{ static_cast(value) }; - } - - GLuint fbo::id() const - { - return m_id; - } - - void fbo::set_id(GLuint id) - { - m_id = id; - } - - void fbo::set_extents(const size2i& extents) - { - m_size = extents; - } - - size2i fbo::get_extents() const - { - return m_size; - } - - bool fbo::matches(const std::array& color_targets, GLuint depth_stencil_target) const - { - for (u32 index = 0; index < 4; ++index) - { - if (color[index].resource_id() != color_targets[index]) - { - return false; - } - } - - const auto depth_resource = depth.resource_id() | depth_stencil.resource_id(); - return (depth_resource == depth_stencil_target); - } - - bool fbo::references_any(const std::vector& resources) const - { - return std::any_of(m_resource_bindings.cbegin(), m_resource_bindings.cend(), [&resources](const auto& e) - { - return std::find(resources.cbegin(), resources.cend(), e.second) != resources.cend(); - }); - } - bool is_primitive_native(rsx::primitive_type in) { switch (in) @@ -456,201 +189,4 @@ namespace gl fmt::throw_exception("unknown primitive type"); } } - - attrib_t vao::operator[](u32 index) const noexcept - { - return attrib_t(index); - } - - void blitter::scale_image(gl::command_context& cmd, const texture* src, texture* dst, areai src_rect, areai dst_rect, - bool linear_interpolation, const rsx::typeless_xfer& xfer_info) - { - std::unique_ptr typeless_src; - std::unique_ptr typeless_dst; - const gl::texture* real_src = src; - const gl::texture* real_dst = dst; - - // Optimization pass; check for pass-through data transfer - if (!xfer_info.flip_horizontal && !xfer_info.flip_vertical && src_rect.height() == dst_rect.height()) - { - auto src_w = src_rect.width(); - auto dst_w = dst_rect.width(); - - if (xfer_info.src_is_typeless) src_w = static_cast(src_w * xfer_info.src_scaling_hint); - if (xfer_info.dst_is_typeless) dst_w = static_cast(dst_w * xfer_info.dst_scaling_hint); - - if (src_w == dst_w) - { - // Final dimensions are a match - if (xfer_info.src_is_typeless || xfer_info.dst_is_typeless) - { - const coord3i src_region = { { src_rect.x1, src_rect.y1, 0 }, { src_rect.width(), src_rect.height(), 1 } }; - const coord3i dst_region = { { dst_rect.x1, dst_rect.y1, 0 }, { dst_rect.width(), dst_rect.height(), 1 } }; - gl::copy_typeless(cmd, dst, src, static_cast(dst_region), static_cast(src_region)); - } - else - { - glCopyImageSubData(src->id(), GL_TEXTURE_2D, 0, src_rect.x1, src_rect.y1, 0, - dst->id(), GL_TEXTURE_2D, 0, dst_rect.x1, dst_rect.y1, 0, - src_rect.width(), src_rect.height(), 1); - } - - return; - } - } - - if (xfer_info.src_is_typeless) - { - const auto internal_fmt = xfer_info.src_native_format_override ? - GLenum(xfer_info.src_native_format_override) : - get_sized_internal_format(xfer_info.src_gcm_format); - - if (static_cast(internal_fmt) != src->get_internal_format()) - { - const u16 internal_width = static_cast(src->width() * xfer_info.src_scaling_hint); - typeless_src = std::make_unique(GL_TEXTURE_2D, internal_width, src->height(), 1, 1, internal_fmt); - copy_typeless(cmd, typeless_src.get(), src); - - real_src = typeless_src.get(); - src_rect.x1 = static_cast(src_rect.x1 * xfer_info.src_scaling_hint); - src_rect.x2 = static_cast(src_rect.x2 * xfer_info.src_scaling_hint); - } - } - - if (xfer_info.dst_is_typeless) - { - const auto internal_fmt = xfer_info.dst_native_format_override ? - GLenum(xfer_info.dst_native_format_override) : - get_sized_internal_format(xfer_info.dst_gcm_format); - - if (static_cast(internal_fmt) != dst->get_internal_format()) - { - const auto internal_width = static_cast(dst->width() * xfer_info.dst_scaling_hint); - typeless_dst = std::make_unique(GL_TEXTURE_2D, internal_width, dst->height(), 1, 1, internal_fmt); - copy_typeless(cmd, typeless_dst.get(), dst); - - real_dst = typeless_dst.get(); - dst_rect.x1 = static_cast(dst_rect.x1 * xfer_info.dst_scaling_hint); - dst_rect.x2 = static_cast(dst_rect.x2 * xfer_info.dst_scaling_hint); - } - } - - ensure(real_src->aspect() == real_dst->aspect()); - - if (src_rect.width() == dst_rect.width() && src_rect.height() == dst_rect.height() && - !src_rect.is_flipped() && !dst_rect.is_flipped()) - { - glCopyImageSubData(real_src->id(), static_cast(real_src->get_target()), 0, src_rect.x1, src_rect.y1, 0, - real_dst->id(), static_cast(real_dst->get_target()), 0, dst_rect.x1, dst_rect.y1, 0, - src_rect.width(), src_rect.height(), 1); - } - else - { - const bool is_depth_copy = (real_src->aspect() != image_aspect::color); - const filter interp = (linear_interpolation && !is_depth_copy) ? filter::linear : filter::nearest; - gl::fbo::attachment::type attachment; - gl::buffers target; - - if (is_depth_copy) - { - if (real_dst->aspect() & gl::image_aspect::stencil) - { - attachment = fbo::attachment::type::depth_stencil; - target = gl::buffers::depth_stencil; - } - else - { - attachment = fbo::attachment::type::depth; - target = gl::buffers::depth; - } - } - else - { - attachment = fbo::attachment::type::color; - target = gl::buffers::color; - } - - cmd->disable(GL_SCISSOR_TEST); - - save_binding_state saved; - - gl::fbo::attachment src_att{blit_src, static_cast(attachment)}; - src_att = *real_src; - - gl::fbo::attachment dst_att{ blit_dst, static_cast(attachment) }; - dst_att = *real_dst; - - if (xfer_info.flip_horizontal) - { - src_rect.flip_horizontal(); - } - - if (xfer_info.flip_vertical) - { - src_rect.flip_vertical(); - } - - blit_src.blit(blit_dst, src_rect, dst_rect, target, interp); - - // Release the attachments explicitly (not doing so causes glitches, e.g Journey Menu) - src_att = GL_NONE; - dst_att = GL_NONE; - } - - if (xfer_info.dst_is_typeless) - { - // Transfer contents from typeless dst back to original dst - copy_typeless(cmd, dst, typeless_dst.get()); - } - } - - void blitter::fast_clear_image(gl::command_context& cmd, const texture* dst, const color4f& color) - { - save_binding_state saved; - - blit_dst.bind(); - blit_dst.color[0] = *dst; - blit_dst.check(); - - cmd->clear_color(color); - cmd->color_maski(0, true, true, true, true); - - glClear(GL_COLOR_BUFFER_BIT); - blit_dst.color[0] = GL_NONE; - } - - void blitter::fast_clear_image(gl::command_context& cmd, const texture* dst, float /*depth*/, u8 /*stencil*/) - { - fbo::attachment::type attachment; - GLbitfield clear_mask; - - switch (const auto fmt = dst->get_internal_format()) - { - case texture::internal_format::depth16: - case texture::internal_format::depth32f: - clear_mask = GL_DEPTH_BUFFER_BIT; - attachment = fbo::attachment::type::depth; - break; - case texture::internal_format::depth24_stencil8: - case texture::internal_format::depth32f_stencil8: - clear_mask = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; - attachment = fbo::attachment::type::depth_stencil; - break; - default: - fmt::throw_exception("Invalid texture passed to clear depth function, format=0x%x", static_cast(fmt)); - } - - save_binding_state saved; - fbo::attachment attach_point{ blit_dst, attachment }; - - blit_dst.bind(); - attach_point = *dst; - blit_dst.check(); - - cmd->depth_mask(GL_TRUE); - cmd->stencil_mask(0xFF); - - glClear(clear_mask); - attach_point = GL_NONE; - } } diff --git a/rpcs3/Emu/RSX/GL/GLHelpers.h b/rpcs3/Emu/RSX/GL/GLHelpers.h index bd772ae5bb..f741898332 100644 --- a/rpcs3/Emu/RSX/GL/GLHelpers.h +++ b/rpcs3/Emu/RSX/GL/GLHelpers.h @@ -36,1239 +36,4 @@ namespace gl void enable_debugging(); bool is_primitive_native(rsx::primitive_type in); GLenum draw_mode(rsx::primitive_type in); - - void flush_command_queue(fence& fence_obj); - - class exception : public std::exception - { - protected: - std::string m_what; - - public: - const char* what() const noexcept override - { - return m_what.c_str(); - } - }; - - template - class save_binding_state_base - { - GLint m_last_binding; - - public: - save_binding_state_base(const Type& new_state) : save_binding_state_base() - { - new_state.bind(); - } - - save_binding_state_base() - { - glGetIntegerv(GetStateId, &m_last_binding); - } - - ~save_binding_state_base() - { - glBindBuffer(BindId, m_last_binding); - } - }; - - enum class filter - { - nearest = GL_NEAREST, - linear = GL_LINEAR - }; - - enum class min_filter - { - nearest = GL_NEAREST, - linear = GL_LINEAR, - nearest_mipmap_nearest = GL_NEAREST_MIPMAP_NEAREST, - nearest_mipmap_linear = GL_NEAREST_MIPMAP_LINEAR, - linear_mipmap_nearest = GL_LINEAR_MIPMAP_NEAREST, - linear_mipmap_linear = GL_LINEAR_MIPMAP_LINEAR - }; - - enum class buffers - { - none = 0, - color = GL_COLOR_BUFFER_BIT, - depth = GL_DEPTH_BUFFER_BIT, - stencil = GL_STENCIL_BUFFER_BIT, - - color_depth = color | depth, - color_depth_stencil = color | depth | stencil, - color_stencil = color | stencil, - - depth_stencil = depth | stencil - }; - - class vao; - class attrib_t; - - class buffer_pointer - { - public: - enum class type - { - s8 = GL_BYTE, - u8 = GL_UNSIGNED_BYTE, - s16 = GL_SHORT, - u16 = GL_UNSIGNED_SHORT, - s32 = GL_INT, - u32 = GL_UNSIGNED_INT, - f16 = GL_HALF_FLOAT, - f32 = GL_FLOAT, - f64 = GL_DOUBLE, - fixed = GL_FIXED, - s32_2_10_10_10_rev = GL_INT_2_10_10_10_REV, - u32_2_10_10_10_rev = GL_UNSIGNED_INT_2_10_10_10_REV, - u32_10f_11f_11f_rev = GL_UNSIGNED_INT_10F_11F_11F_REV - }; - - private: - vao* m_vao; - u32 m_offset; - u32 m_stride; - u32 m_size = 4; - type m_type = type::f32; - bool m_normalize = false; - - public: - buffer_pointer(vao* vao, u32 offset = 0, u32 stride = 0) - : m_vao(vao) - , m_offset(offset) - , m_stride(stride) - { - } - - const class ::gl::vao& get_vao() const - { - return *m_vao; - } - - class ::gl::vao& get_vao() - { - return *m_vao; - } - - buffer_pointer& offset(u32 value) - { - m_offset = value; - return *this; - } - - u32 offset() const - { - return m_offset; - } - - buffer_pointer& stride(u32 value) - { - m_stride = value; - return *this; - } - - u32 stride() const - { - return m_stride; - } - - buffer_pointer& size(u32 value) - { - m_size = value; - return *this; - } - - u32 size() const - { - return m_size; - } - - buffer_pointer& set_type(type value) - { - m_type = value; - return *this; - } - - type get_type() const - { - return m_type; - } - - buffer_pointer& normalize(bool value) - { - m_normalize = value; - return *this; - } - - bool normalize() const - { - return m_normalize; - } - - buffer_pointer& operator >> (u32 value) - { - return stride(value); - } - - buffer_pointer& config(type type_ = type::f32, u32 size_ = 4, bool normalize_ = false) - { - return set_type(type_).size(size_).normalize(normalize_); - } - }; - - class vao - { - template - class entry - { - vao& m_parent; - - public: - using save_binding_state = save_binding_state_base(BindId)), GetStateId>; - - entry(vao* parent) noexcept : m_parent(*parent) - { - } - - entry& operator = (const buffer& buf) noexcept - { - m_parent.bind(); - buf.bind(BindId); - - return *this; - } - }; - - GLuint m_id = GL_NONE; - - public: - entry pixel_pack_buffer{ this }; - entry pixel_unpack_buffer{ this }; - entry array_buffer{ this }; - entry element_array_buffer{ this }; - - vao() = default; - vao(const vao&) = delete; - - vao(vao&& vao_) noexcept - { - swap(vao_); - } - vao(GLuint id) noexcept - { - set_id(id); - } - - ~vao() noexcept - { - if (created()) - remove(); - } - - void swap(vao& vao_) noexcept - { - auto my_old_id = id(); - set_id(vao_.id()); - vao_.set_id(my_old_id); - } - - vao& operator = (const vao& rhs) = delete; - vao& operator = (vao&& rhs) noexcept - { - swap(rhs); - return *this; - } - - void bind() const noexcept - { - glBindVertexArray(m_id); - } - - void create() noexcept - { - glGenVertexArrays(1, &m_id); - } - - void remove() noexcept - { - if (m_id != GL_NONE) - { - glDeleteVertexArrays(1, &m_id); - m_id = GL_NONE; - } - } - - uint id() const noexcept - { - return m_id; - } - - void set_id(uint id) noexcept - { - m_id = id; - } - - bool created() const noexcept - { - return m_id != GL_NONE; - } - - explicit operator bool() const noexcept - { - return created(); - } - - void enable_for_attributes(std::initializer_list indexes) noexcept - { - for (auto &index : indexes) - { - glEnableVertexAttribArray(index); - } - } - - void disable_for_attributes(std::initializer_list indexes) noexcept - { - for (auto &index : indexes) - { - glDisableVertexAttribArray(index); - } - } - - void enable_for_attribute(GLuint index) noexcept - { - enable_for_attributes({ index }); - } - - void disable_for_attribute(GLuint index) noexcept - { - disable_for_attributes({ index }); - } - - buffer_pointer operator + (u32 offset) noexcept - { - return{ this, offset }; - } - - buffer_pointer operator >> (u32 stride) noexcept - { - return{ this, {}, stride }; - } - - operator buffer_pointer() noexcept - { - return{ this }; - } - - attrib_t operator [] (u32 index) const noexcept; - }; - - class attrib_t - { - GLint m_location; - - public: - attrib_t(GLint location) - : m_location(location) - { - } - - GLint location() const - { - return m_location; - } - - void operator = (float rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib1f(location(), rhs); } - void operator = (double rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib1d(location(), rhs); } - - void operator = (const color1f& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib1f(location(), rhs.r); } - void operator = (const color1d& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib1d(location(), rhs.r); } - void operator = (const color2f& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib2f(location(), rhs.r, rhs.g); } - void operator = (const color2d& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib2d(location(), rhs.r, rhs.g); } - void operator = (const color3f& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib3f(location(), rhs.r, rhs.g, rhs.b); } - void operator = (const color3d& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib3d(location(), rhs.r, rhs.g, rhs.b); } - void operator = (const color4f& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib4f(location(), rhs.r, rhs.g, rhs.b, rhs.a); } - void operator = (const color4d& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib4d(location(), rhs.r, rhs.g, rhs.b, rhs.a); } - - void operator = (buffer_pointer& pointer) const - { - pointer.get_vao().enable_for_attribute(m_location); - glVertexAttribPointer(location(), pointer.size(), static_cast(pointer.get_type()), pointer.normalize(), - pointer.stride(), reinterpret_cast(u64{pointer.offset()})); - } - }; - - class rbo - { - GLuint m_id = GL_NONE; - - public: - rbo() = default; - - rbo(GLuint id) - { - set_id(id); - } - - ~rbo() - { - if (created()) - remove(); - } - - class save_binding_state - { - GLint m_old_value; - - public: - save_binding_state(const rbo& new_state) - { - glGetIntegerv(GL_RENDERBUFFER_BINDING, &m_old_value); - new_state.bind(); - } - - ~save_binding_state() - { - glBindRenderbuffer(GL_RENDERBUFFER, m_old_value); - } - }; - - void recreate() - { - if (created()) - remove(); - - create(); - } - - void recreate(texture::format format, u32 width, u32 height) - { - if (created()) - remove(); - - create(format, width, height); - } - - void create() - { - glGenRenderbuffers(1, &m_id); - } - - void create(texture::format format, u32 width, u32 height) - { - create(); - storage(format, width, height); - } - - void bind() const - { - glBindRenderbuffer(GL_RENDERBUFFER, m_id); - } - - void storage(texture::format format, u32 width, u32 height) - { - save_binding_state save(*this); - glRenderbufferStorage(GL_RENDERBUFFER, static_cast(format), width, height); - } - - void remove() - { - if (m_id != GL_NONE) - { - glDeleteRenderbuffers(1, &m_id); - m_id = GL_NONE; - } - } - - uint id() const - { - return m_id; - } - - void set_id(uint id) - { - m_id = id; - } - - bool created() const - { - return m_id != GL_NONE; - } - - explicit operator bool() const - { - return created(); - } - }; - - enum class indices_type - { - ubyte = GL_UNSIGNED_BYTE, - ushort = GL_UNSIGNED_SHORT, - uint = GL_UNSIGNED_INT - }; - - class fbo - { - GLuint m_id = GL_NONE; - size2i m_size; - - protected: - std::unordered_map m_resource_bindings; - - public: - fbo() = default; - - fbo(GLuint id) - { - set_id(id); - } - - ~fbo() - { - if (created()) - remove(); - } - - class save_binding_state - { - GLint m_last_binding; - bool reset = true; - - public: - save_binding_state(const fbo& new_binding) - { - glGetIntegerv(GL_FRAMEBUFFER_BINDING, &m_last_binding); - - if (m_last_binding + 0u != new_binding.id()) - new_binding.bind(); - else - reset = false; - } - - ~save_binding_state() - { - if (reset) - glBindFramebuffer(GL_FRAMEBUFFER, m_last_binding); - } - }; - - class attachment - { - public: - enum class type - { - color = GL_COLOR_ATTACHMENT0, - depth = GL_DEPTH_ATTACHMENT, - stencil = GL_STENCIL_ATTACHMENT, - depth_stencil = GL_DEPTH_STENCIL_ATTACHMENT - }; - - protected: - GLuint m_id = GL_NONE; - fbo &m_parent; - - attachment(fbo& parent) - : m_parent(parent) - {} - - public: - attachment(fbo& parent, type type) - : m_id(static_cast(type)) - , m_parent(parent) - { - } - - void set_id(uint id) - { - m_id = id; - } - - uint id() const - { - return m_id; - } - - GLuint resource_id() const - { - const auto found = m_parent.m_resource_bindings.find(m_id); - if (found != m_parent.m_resource_bindings.end()) - { - return found->second; - } - - return 0; - } - - void operator = (const rbo& rhs) - { - m_parent.m_resource_bindings[m_id] = rhs.id(); - DSA_CALL2(NamedFramebufferRenderbuffer, m_parent.id(), m_id, GL_RENDERBUFFER, rhs.id()); - } - - void operator = (const texture& rhs) - { - ensure(rhs.get_target() == texture::target::texture2D); - m_parent.m_resource_bindings[m_id] = rhs.id(); - DSA_CALL2(NamedFramebufferTexture, m_parent.id(), m_id, rhs.id(), 0); - } - - void operator = (const GLuint rhs) - { - m_parent.m_resource_bindings[m_id] = rhs; - DSA_CALL2(NamedFramebufferTexture, m_parent.id(), m_id, rhs, 0); - } - }; - - class indexed_attachment : public attachment - { - public: - indexed_attachment(fbo& parent, type type) : attachment(parent, type) - { - } - - attachment operator[](int index) const - { - return{ m_parent, type(id() + index) }; - } - - std::vector range(int from, int count) const - { - std::vector result; - - for (int i = from; i < from + count; ++i) - result.push_back((*this)[i]); - - return result; - } - - using attachment::operator =; - }; - - struct null_attachment : public attachment - { - null_attachment(fbo& parent) - : attachment(parent) - {} - }; - - indexed_attachment color{ *this, attachment::type::color }; - attachment depth{ *this, attachment::type::depth }; - attachment stencil{ *this, attachment::type::stencil }; - attachment depth_stencil{ *this, attachment::type::depth_stencil }; - null_attachment no_color{ *this }; - - enum class target - { - read_frame_buffer = GL_READ_FRAMEBUFFER, - draw_frame_buffer = GL_DRAW_FRAMEBUFFER - }; - - void create(); - void bind() const; - void blit(const fbo& dst, areai src_area, areai dst_area, buffers buffers_ = buffers::color, filter filter_ = filter::nearest) const; - void bind_as(target target_) const; - void remove(); - bool created() const; - bool check() const; - - void recreate(); - void draw_buffer(const attachment& buffer) const; - void draw_buffers(const std::initializer_list& indexes) const; - - void read_buffer(const attachment& buffer) const; - - void draw_arrays(rsx::primitive_type mode, GLsizei count, GLint first = 0) const; - void draw_arrays(const buffer& buffer, rsx::primitive_type mode, GLsizei count, GLint first = 0) const; - void draw_arrays(const vao& buffer, rsx::primitive_type mode, GLsizei count, GLint first = 0) const; - - void draw_elements(rsx::primitive_type mode, GLsizei count, indices_type type, const GLvoid *indices) const; - void draw_elements(const buffer& buffer, rsx::primitive_type mode, GLsizei count, indices_type type, const GLvoid *indices) const; - void draw_elements(rsx::primitive_type mode, GLsizei count, indices_type type, const buffer& indices, usz indices_buffer_offset = 0) const; - void draw_elements(const buffer& buffer_, rsx::primitive_type mode, GLsizei count, indices_type type, const buffer& indices, usz indices_buffer_offset = 0) const; - void draw_elements(rsx::primitive_type mode, GLsizei count, const GLubyte *indices) const; - void draw_elements(const buffer& buffer, rsx::primitive_type mode, GLsizei count, const GLubyte *indices) const; - void draw_elements(rsx::primitive_type mode, GLsizei count, const GLushort *indices) const; - void draw_elements(const buffer& buffer, rsx::primitive_type mode, GLsizei count, const GLushort *indices) const; - void draw_elements(rsx::primitive_type mode, GLsizei count, const GLuint *indices) const; - void draw_elements(const buffer& buffer, rsx::primitive_type mode, GLsizei count, const GLuint *indices) const; - - void clear(buffers buffers_) const; - void clear(buffers buffers_, color4f color_value, double depth_value, u8 stencil_value) const; - - void copy_from(const void* pixels, const sizei& size, gl::texture::format format_, gl::texture::type type_, class pixel_unpack_settings pixel_settings = pixel_unpack_settings()) const; - void copy_from(const buffer& buf, const sizei& size, gl::texture::format format_, gl::texture::type type_, class pixel_unpack_settings pixel_settings = pixel_unpack_settings()) const; - - void copy_to(void* pixels, coordi coord, gl::texture::format format_, gl::texture::type type_, class pixel_pack_settings pixel_settings = pixel_pack_settings()) const; - void copy_to(const buffer& buf, coordi coord, gl::texture::format format_, gl::texture::type type_, class pixel_pack_settings pixel_settings = pixel_pack_settings()) const; - - static fbo get_bound_draw_buffer(); - static fbo get_bound_read_buffer(); - static fbo get_bound_buffer(); - - GLuint id() const; - void set_id(GLuint id); - - void set_extents(const size2i& extents); - size2i get_extents() const; - - bool matches(const std::array& color_targets, GLuint depth_stencil_target) const; - bool references_any(const std::vector& resources) const; - - explicit operator bool() const - { - return created(); - } - }; - - extern const fbo screen; - - 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() - { - const char* str = source.c_str(); - const GLint length = ::narrow(source.length()); - - if (g_cfg.video.log_programs) - { - std::string base_name; - switch (type) - { - case ::glsl::program_domain::glsl_vertex_program: - base_name = "shaderlog/VertexProgram"; - break; - case ::glsl::program_domain::glsl_fragment_program: - base_name = "shaderlog/FragmentProgram"; - break; - case ::glsl::program_domain::glsl_compute_program: - base_name = "shaderlog/ComputeProgram"; - break; - } - - fs::file(fs::get_cache_dir() + base_name + std::to_string(m_id) + ".glsl", fs::rewrite).write(str, length); - } - - glShaderSource(m_id, 1, &str, &length); - - m_init_fence.create(); - flush_command_queue(m_init_fence); - } - - public: - shader() = default; - - shader(GLuint id) - { - set_id(id); - } - - shader(::glsl::program_domain type_, const std::string& src) - { - create(type_, src); - } - - ~shader() - { - if (created()) - remove(); - } - - void create(::glsl::program_domain type_, const std::string& src) - { - type = type_; - source = src; - - GLenum shader_type{}; - switch (type) - { - case ::glsl::program_domain::glsl_vertex_program: - shader_type = GL_VERTEX_SHADER; - break; - case ::glsl::program_domain::glsl_fragment_program: - shader_type = GL_FRAGMENT_SHADER; - break; - case ::glsl::program_domain::glsl_compute_program: - shader_type = GL_COMPUTE_SHADER; - break; - default: - rsx_log.fatal("gl::glsl::shader::compile(): Unhandled shader type (%d)", +type_); - return; - } - - m_id = glCreateShader(shader_type); - precompile(); - } - - shader& compile() - { - std::lock_guard lock(m_compile_lock); - if (m_is_compiled) - { - // Another thread compiled this already - return *this; - } - - ensure(!m_init_fence.is_empty()); // Do not attempt to compile a shader_view!! - m_init_fence.server_wait_sync(); - - glCompileShader(m_id); - - GLint status = GL_FALSE; - glGetShaderiv(m_id, GL_COMPILE_STATUS, &status); - - if (status == GL_FALSE) - { - GLint length = 0; - glGetShaderiv(m_id, GL_INFO_LOG_LENGTH, &length); - - std::string error_msg; - if (length) - { - std::unique_ptr buf(new char[length + 1]); - glGetShaderInfoLog(m_id, length, nullptr, buf.get()); - error_msg = buf.get(); - } - - rsx_log.fatal("Compilation failed: %s\nsource: %s", error_msg, source); - } - - m_compiled_fence.create(); - flush_command_queue(m_compiled_fence); - - m_is_compiled = true; - return *this; - } - - void remove() - { - if (m_id != GL_NONE) - { - glDeleteShader(m_id); - m_id = GL_NONE; - } - } - - uint id() const - { - return m_id; - } - - const std::string& get_source() const - { - return source; - } - - fence get_compile_fence_sync() const - { - return m_compiled_fence; - } - - void set_id(uint id) - { - m_id = id; - } - - bool created() const - { - return m_id != GL_NONE; - } - - bool compiled() const - { - return m_is_compiled; - } - - explicit operator bool() const - { - return created(); - } - }; - - class shader_view : public shader - { - public: - shader_view(GLuint id) : shader(id) - { - } - - ~shader_view() - { - set_id(0); - } - }; - - 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; - int active_texture = 0; - - public: - uniforms_t(program* program) : m_program(*program) - { - } - - void clear() - { - locations.clear(); - active_texture = 0; - } - - bool has_location(const std::string &name, int *location = nullptr) - { - auto found = locations.find(name); - if (found != locations.end()) - { - if (location) - { - *location = found->second; - } - - return (found->second >= 0); - } - - auto result = glGetUniformLocation(m_program.id(), name.c_str()); - locations[name] = result; - - if (location) - { - *location = result; - } - - return (result >= 0); - } - - GLint location(const std::string &name) - { - auto found = locations.find(name); - if (found != locations.end()) - { - if (found->second >= 0) - { - return found->second; - } - else - { - rsx_log.fatal("%s not found.", name); - return -1; - } - } - - auto result = glGetUniformLocation(m_program.id(), name.c_str()); - - if (result < 0) - { - rsx_log.fatal("%s not found.", name); - return result; - } - - locations[name] = result; - return result; - } - - uniform_t operator[](GLint location) - { - return{ m_program, location }; - } - - uniform_t operator[](const std::string &name) - { - return{ m_program, location(name) }; - } - - void swap(uniforms_t& uniforms) - { - locations.swap(uniforms.locations); - std::swap(active_texture, uniforms.active_texture); - } - } uniforms{ this }; - - program& recreate() - { - if (created()) - remove(); - - return create(); - } - - program& create() - { - m_id = glCreateProgram(); - return *this; - } - - void remove() - { - if (m_id != GL_NONE) - { - glDeleteProgram(m_id); - m_id = GL_NONE; - } - uniforms.clear(); - } - - static program get_current_program() - { - GLint id; - glGetIntegerv(GL_CURRENT_PROGRAM, &id); - return{ static_cast(id) }; - } - - void link(std::function init_func = {}) - { - glLinkProgram(m_id); - - GLint status = GL_FALSE; - glGetProgramiv(m_id, GL_LINK_STATUS, &status); - - if (status == GL_FALSE) - { - GLint length = 0; - glGetProgramiv(m_id, GL_INFO_LOG_LENGTH, &length); - - std::string error_msg; - if (length) - { - std::unique_ptr buf(new char[length + 1]); - glGetProgramInfoLog(m_id, length, nullptr, buf.get()); - error_msg = buf.get(); - } - - rsx_log.fatal("Linkage failed: %s", error_msg); - } - else - { - if (init_func) - { - init_func(this); - } - - m_fence.create(); - flush_command_queue(m_fence); - } - } - - void validate() - { - glValidateProgram(m_id); - - GLint status = GL_FALSE; - glGetProgramiv(m_id, GL_VALIDATE_STATUS, &status); - - if (status == GL_FALSE) - { - GLint length = 0; - glGetProgramiv(m_id, GL_INFO_LOG_LENGTH, &length); - - std::string error_msg; - if (length) - { - std::unique_ptr buf(new char[length + 1]); - glGetProgramInfoLog(m_id, length, nullptr, buf.get()); - error_msg = buf.get(); - } - - rsx_log.error("Validation failed: %s", error_msg.c_str()); - } - } - - GLuint id() const - { - return m_id; - } - - void set_id(uint id) - { - uniforms.clear(); - m_id = id; - } - - bool created() const - { - return m_id != GL_NONE; - } - - void sync() - { - if (!m_fence.check_signaled()) - { - m_fence.server_wait_sync(); - } - } - - explicit operator bool() const - { - return created(); - } - - 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; - } - - int attribute_location(const std::string& name) - { - return glGetAttribLocation(m_id, name.c_str()); - } - - int uniform_location(const std::string& name) - { - return glGetUniformLocation(m_id, name.c_str()); - } - - program() = default; - program(const program&) = delete; - program(program&& program_) - { - swap(program_); - } - - program(GLuint id) - { - set_id(id); - } - - ~program() - { - if (created()) - remove(); - } - - void swap(program& program_) - { - auto my_old_id = id(); - set_id(program_.id()); - program_.set_id(my_old_id); - uniforms.swap(program_.uniforms); - } - - program& operator = (const program& rhs) = delete; - program& operator = (program&& rhs) - { - swap(rhs); - return *this; - } - }; - - class program_view : public program - { - public: - program_view(GLuint id) : program(id) - { - } - - ~program_view() - { - set_id(0); - } - }; - } - - class blitter - { - struct save_binding_state - { - GLuint old_fbo; - - save_binding_state() - { - glGetIntegerv(GL_FRAMEBUFFER_BINDING, reinterpret_cast(&old_fbo)); - } - - ~save_binding_state() - { - glBindFramebuffer(GL_FRAMEBUFFER, old_fbo); - } - }; - - fbo blit_src; - fbo blit_dst; - - public: - - void init() - { - blit_src.create(); - blit_dst.create(); - } - - void destroy() - { - blit_dst.remove(); - blit_src.remove(); - } - - void scale_image(gl::command_context& cmd, const texture* src, texture* dst, areai src_rect, areai dst_rect, bool linear_interpolation, - const rsx::typeless_xfer& xfer_info); - - void fast_clear_image(gl::command_context& cmd, const texture* dst, const color4f& color); - void fast_clear_image(gl::command_context& cmd, const texture* dst, float depth, u8 stencil); - }; } diff --git a/rpcs3/Emu/RSX/GL/GLOverlays.h b/rpcs3/Emu/RSX/GL/GLOverlays.h index 18a89dac38..8f3438ca6d 100644 --- a/rpcs3/Emu/RSX/GL/GLOverlays.h +++ b/rpcs3/Emu/RSX/GL/GLOverlays.h @@ -4,6 +4,11 @@ #include "../Common/simple_array.hpp" #include "../Overlays/overlays.h" #include "GLTexture.h" + +#include "glutils/fbo.h" +#include "glutils/program.h" +#include "glutils/vao.hpp" + #include #include @@ -115,6 +120,16 @@ namespace gl void run(gl::command_context& cmd, const buffer* src, const texture* dst, const u32 src_offset, const coordu& dst_region, const pixel_unpack_settings& settings); }; + struct rp_copy_rgba_to_bgra : public overlay_pass + { + void run(gl::command_context& cmd, const texture* src, const texture* dst, const coordu& src_region, const coordu& dst_region); + }; + + struct rp_copy_bgra_to_rgba : public overlay_pass + { + void run(gl::command_context& cmd, const texture* src, const texture* dst, const coordu& src_region, const coordu& dst_region); + }; + // TODO: Replace with a proper manager extern std::unordered_map> g_overlay_passes; diff --git a/rpcs3/Emu/RSX/GL/GLPipelineCompiler.h b/rpcs3/Emu/RSX/GL/GLPipelineCompiler.h index 2fa56902b6..4d4dbc020b 100644 --- a/rpcs3/Emu/RSX/GL/GLPipelineCompiler.h +++ b/rpcs3/Emu/RSX/GL/GLPipelineCompiler.h @@ -1,5 +1,6 @@ #pragma once #include "GLHelpers.h" +#include "glutils/program.h" #include "Emu/RSX/display.h" #include "Utilities/lockless.h" diff --git a/rpcs3/Emu/RSX/GL/GLRenderTargets.h b/rpcs3/Emu/RSX/GL/GLRenderTargets.h index 503494a0f6..0cabb74bd9 100644 --- a/rpcs3/Emu/RSX/GL/GLRenderTargets.h +++ b/rpcs3/Emu/RSX/GL/GLRenderTargets.h @@ -3,6 +3,8 @@ #include "GLHelpers.h" #include "../rsx_utils.h" +#include "glutils/fbo.h" + struct color_swizzle { gl::texture::channel a = gl::texture::channel::a; diff --git a/rpcs3/Emu/RSX/GL/GLShaderInterpreter.h b/rpcs3/Emu/RSX/GL/GLShaderInterpreter.h index 6603488601..6a46035742 100644 --- a/rpcs3/Emu/RSX/GL/GLShaderInterpreter.h +++ b/rpcs3/Emu/RSX/GL/GLShaderInterpreter.h @@ -1,5 +1,6 @@ #pragma once #include "GLHelpers.h" +#include "glutils/program.h" #include "../Program/ProgramStateCache.h" #include "../Common/TextureUtils.h" diff --git a/rpcs3/Emu/RSX/GL/GLTextOut.h b/rpcs3/Emu/RSX/GL/GLTextOut.h index 814d8396c6..40c51f161a 100644 --- a/rpcs3/Emu/RSX/GL/GLTextOut.h +++ b/rpcs3/Emu/RSX/GL/GLTextOut.h @@ -2,6 +2,7 @@ #include "util/types.hpp" #include "GLHelpers.h" +#include "glutils/vao.hpp" #include "../Common/TextGlyphs.h" #include #include diff --git a/rpcs3/Emu/RSX/GL/GLTextureCache.h b/rpcs3/Emu/RSX/GL/GLTextureCache.h index 72a329a28d..6c6e400f44 100644 --- a/rpcs3/Emu/RSX/GL/GLTextureCache.h +++ b/rpcs3/Emu/RSX/GL/GLTextureCache.h @@ -1,8 +1,9 @@ #pragma once -#include "util/types.hpp" - #include "GLRenderTargets.h" +#include "glutils/blitter.h" +#include "glutils/sync.hpp" + #include "../Common/texture_cache.h" #include diff --git a/rpcs3/Emu/RSX/GL/GLVertexProgram.h b/rpcs3/Emu/RSX/GL/GLVertexProgram.h index 1bc0b6262b..2b769c469e 100644 --- a/rpcs3/Emu/RSX/GL/GLVertexProgram.h +++ b/rpcs3/Emu/RSX/GL/GLVertexProgram.h @@ -1,6 +1,7 @@ #pragma once #include "../Program/VertexProgramDecompiler.h" #include "GLHelpers.h" +#include "glutils/program.h" #include diff --git a/rpcs3/Emu/RSX/GL/glutils/blitter.cpp b/rpcs3/Emu/RSX/GL/glutils/blitter.cpp new file mode 100644 index 0000000000..f26dfdbdc0 --- /dev/null +++ b/rpcs3/Emu/RSX/GL/glutils/blitter.cpp @@ -0,0 +1,268 @@ +#include "stdafx.h" +#include "blitter.h" +#include "state_tracker.hpp" + +#include "../GLTexture.h" // TODO: This system also needs to be refactored +#include "../GLOverlays.h" + +namespace gl +{ + static blitter* g_hw_blitter = nullptr; + + void process_bgra_transfer_source(const gl::texture* src, const gl::texture* dst, const coord3i& region) + { + ensure(src->get_internal_format() == texture::internal_format::bgra8); + ensure(dst->get_internal_format() == texture::internal_format::rgba8); + } + + void process_bgra_transfer_dest(const gl::texture* tex, const coord3i& region) + { + ensure(tex->get_internal_format() == texture::internal_format::bgra8); + } + + void blitter::copy_image(gl::command_context& cmd, const texture* src, const texture* dst, int src_level, int dst_level, const position3i& src_offset, const position3i& dst_offset, const size3i& size) const + { + ensure(src_level == 0); + + // Typeless bypass for BGRA8 + std::unique_ptr temp_image; + const texture* real_src = src; + bool handle_bgra8_dest = false; + + if (src->get_internal_format() != dst->get_internal_format()) + { + if (false && src->get_internal_format() == texture::internal_format::bgra8) + { + temp_image = std::make_unique(static_cast(src->get_target()), src->width(), src->height(), src->depth(), src->levels(), GL_RGBA8, rsx::format_class::RSX_FORMAT_CLASS_COLOR); + process_bgra_transfer_source(src, temp_image.get(), { src_offset, size }); + real_src = temp_image.get(); + } + + handle_bgra8_dest = (dst->get_internal_format() == texture::internal_format::bgra8); + } + + glCopyImageSubData(real_src->id(), static_cast(real_src->get_target()), src_level, + src_offset.x, src_offset.y, src_offset.z, + dst->id(), static_cast(dst->get_target()), dst_level, + dst_offset.x, dst_offset.y, dst_offset.z, size.width, size.height, size.depth); + + if (handle_bgra8_dest) + { + process_bgra_transfer_dest(dst, { dst_offset, size }); + } + } + + void blitter::scale_image(gl::command_context& cmd, const texture* src, texture* dst, areai src_rect, areai dst_rect, + bool linear_interpolation, const rsx::typeless_xfer& xfer_info) + { + std::unique_ptr typeless_src; + std::unique_ptr typeless_dst; + const gl::texture* real_src = src; + const gl::texture* real_dst = dst; + + // Optimization pass; check for pass-through data transfer + if (!xfer_info.flip_horizontal && !xfer_info.flip_vertical && src_rect.height() == dst_rect.height()) + { + auto src_w = src_rect.width(); + auto dst_w = dst_rect.width(); + + if (xfer_info.src_is_typeless) src_w = static_cast(src_w * xfer_info.src_scaling_hint); + if (xfer_info.dst_is_typeless) dst_w = static_cast(dst_w * xfer_info.dst_scaling_hint); + + if (src_w == dst_w) + { + // Final dimensions are a match + if (xfer_info.src_is_typeless || xfer_info.dst_is_typeless) + { + const coord3i src_region = { { src_rect.x1, src_rect.y1, 0 }, { src_rect.width(), src_rect.height(), 1 } }; + const coord3i dst_region = { { dst_rect.x1, dst_rect.y1, 0 }, { dst_rect.width(), dst_rect.height(), 1 } }; + gl::copy_typeless(cmd, dst, src, static_cast(dst_region), static_cast(src_region)); + } + else + { + copy_image(cmd, src, dst, 0, 1, { src_rect.x1, src_rect.y1, 0u }, { dst_rect.x1, dst_rect.y1, 0 }, { src_rect.width(), src_rect.height(), 1 }); + } + + return; + } + } + + if (xfer_info.src_is_typeless) + { + const auto internal_fmt = xfer_info.src_native_format_override ? + GLenum(xfer_info.src_native_format_override) : + get_sized_internal_format(xfer_info.src_gcm_format); + + if (static_cast(internal_fmt) != src->get_internal_format()) + { + const u16 internal_width = static_cast(src->width() * xfer_info.src_scaling_hint); + typeless_src = std::make_unique(GL_TEXTURE_2D, internal_width, src->height(), 1, 1, internal_fmt); + copy_typeless(cmd, typeless_src.get(), src); + + real_src = typeless_src.get(); + src_rect.x1 = static_cast(src_rect.x1 * xfer_info.src_scaling_hint); + src_rect.x2 = static_cast(src_rect.x2 * xfer_info.src_scaling_hint); + } + } + + if (xfer_info.dst_is_typeless) + { + const auto internal_fmt = xfer_info.dst_native_format_override ? + GLenum(xfer_info.dst_native_format_override) : + get_sized_internal_format(xfer_info.dst_gcm_format); + + if (static_cast(internal_fmt) != dst->get_internal_format()) + { + const auto internal_width = static_cast(dst->width() * xfer_info.dst_scaling_hint); + typeless_dst = std::make_unique(GL_TEXTURE_2D, internal_width, dst->height(), 1, 1, internal_fmt); + copy_typeless(cmd, typeless_dst.get(), dst); + + real_dst = typeless_dst.get(); + dst_rect.x1 = static_cast(dst_rect.x1 * xfer_info.dst_scaling_hint); + dst_rect.x2 = static_cast(dst_rect.x2 * xfer_info.dst_scaling_hint); + } + } + + if (src->get_internal_format() == texture::internal_format::bgra8 && + real_src == src && + dst->get_internal_format() != src->get_internal_format()) + { + // Not typeless, plus src is bgra8. Needs conversion + typeless_src = std::make_unique(GL_TEXTURE_2D, src->width(), src->height(), 1, 1, GL_RGBA8); + process_bgra_transfer_source(src, typeless_src.get(), {{src_rect.x1, src_rect.y1, 0}, {src_rect.width(), src_rect.height(), 1}}); + real_src = typeless_src.get(); + } + + bool handle_bgra8_dest = false; + if (dst->get_internal_format() == texture::internal_format::bgra8 && + real_dst == dst && + dst->get_internal_format() != src->get_internal_format()) + { + // Not typeless but dst is bgra8. + // Handle the conversion in post + handle_bgra8_dest = true; + } + + ensure(real_src->aspect() == real_dst->aspect()); + + if (src_rect.width() == dst_rect.width() && src_rect.height() == dst_rect.height() && + !src_rect.is_flipped() && !dst_rect.is_flipped()) + { + copy_image(cmd, real_src, real_dst, 0, 1, { src_rect.x1, src_rect.y1, 0 }, { dst_rect.x1, dst_rect.y1, 0 }, { src_rect.width(), src_rect.height(), 1 }); + handle_bgra8_dest = false; // Handled in copy_image + } + else + { + const bool is_depth_copy = (real_src->aspect() != image_aspect::color); + const filter interp = (linear_interpolation && !is_depth_copy) ? filter::linear : filter::nearest; + gl::fbo::attachment::type attachment; + gl::buffers target; + + if (is_depth_copy) + { + if (real_dst->aspect() & gl::image_aspect::stencil) + { + attachment = fbo::attachment::type::depth_stencil; + target = gl::buffers::depth_stencil; + } + else + { + attachment = fbo::attachment::type::depth; + target = gl::buffers::depth; + } + } + else + { + attachment = fbo::attachment::type::color; + target = gl::buffers::color; + } + + cmd->disable(GL_SCISSOR_TEST); + + save_binding_state saved; + + gl::fbo::attachment src_att{ blit_src, static_cast(attachment) }; + src_att = *real_src; + + gl::fbo::attachment dst_att{ blit_dst, static_cast(attachment) }; + dst_att = *real_dst; + + if (xfer_info.flip_horizontal) + { + src_rect.flip_horizontal(); + } + + if (xfer_info.flip_vertical) + { + src_rect.flip_vertical(); + } + + blit_src.blit(blit_dst, src_rect, dst_rect, target, interp); + + // Release the attachments explicitly (not doing so causes glitches, e.g Journey Menu) + src_att = GL_NONE; + dst_att = GL_NONE; + } + + if (xfer_info.dst_is_typeless) + { + // Transfer contents from typeless dst back to original dst + copy_typeless(cmd, dst, typeless_dst.get()); + } + else if (handle_bgra8_dest) + { + // Blit transfer to BGRA8 target + process_bgra_transfer_dest(dst, { {dst_rect.x1, dst_rect.y1, 0}, {dst_rect.width(), dst_rect.height(), 1} }); + } + } + + void blitter::fast_clear_image(gl::command_context& cmd, const texture* dst, const color4f& color) + { + save_binding_state saved; + + blit_dst.bind(); + blit_dst.color[0] = *dst; + blit_dst.check(); + + cmd->clear_color(color); + cmd->color_maski(0, true, true, true, true); + + glClear(GL_COLOR_BUFFER_BIT); + blit_dst.color[0] = GL_NONE; + } + + void blitter::fast_clear_image(gl::command_context& cmd, const texture* dst, float /*depth*/, u8 /*stencil*/) + { + fbo::attachment::type attachment; + GLbitfield clear_mask; + + switch (const auto fmt = dst->get_internal_format()) + { + case texture::internal_format::depth16: + case texture::internal_format::depth32f: + clear_mask = GL_DEPTH_BUFFER_BIT; + attachment = fbo::attachment::type::depth; + break; + case texture::internal_format::depth24_stencil8: + case texture::internal_format::depth32f_stencil8: + clear_mask = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; + attachment = fbo::attachment::type::depth_stencil; + break; + default: + fmt::throw_exception("Invalid texture passed to clear depth function, format=0x%x", static_cast(fmt)); + } + + save_binding_state saved; + fbo::attachment attach_point{ blit_dst, attachment }; + + blit_dst.bind(); + attach_point = *dst; + blit_dst.check(); + + cmd->depth_mask(GL_TRUE); + cmd->stencil_mask(0xFF); + + glClear(clear_mask); + attach_point = GL_NONE; + } +} diff --git a/rpcs3/Emu/RSX/GL/glutils/blitter.h b/rpcs3/Emu/RSX/GL/glutils/blitter.h new file mode 100644 index 0000000000..20ce9d5ad8 --- /dev/null +++ b/rpcs3/Emu/RSX/GL/glutils/blitter.h @@ -0,0 +1,58 @@ +#pragma once + +#include "common.h" +#include "fbo.h" + +namespace gl +{ + class command_context; + class texture; + + class blitter + { + struct save_binding_state + { + GLuint old_fbo; + + save_binding_state() + { + glGetIntegerv(GL_FRAMEBUFFER_BINDING, reinterpret_cast(&old_fbo)); + } + + ~save_binding_state() + { + glBindFramebuffer(GL_FRAMEBUFFER, old_fbo); + } + }; + + fbo blit_src; + fbo blit_dst; + + public: + + void init() + { + blit_src.create(); + blit_dst.create(); + } + + void destroy() + { + blit_dst.remove(); + blit_src.remove(); + } + + void scale_image(gl::command_context& cmd, const texture* src, texture* dst, areai src_rect, areai dst_rect, bool linear_interpolation, + const rsx::typeless_xfer& xfer_info); + + void copy_image(gl::command_context& cmd, const texture* src, const texture* dst, int src_level, int dst_level, const position3i& src_offset, const position3i& dst_offset, const size3i& size) const; + + void fast_clear_image(gl::command_context& cmd, const texture* dst, const color4f& color); + void fast_clear_image(gl::command_context& cmd, const texture* dst, float depth, u8 stencil); + + void copy_image(gl::command_context& cmd, const texture* src, const texture* dst, int src_level, int dst_level, const position3u& src_offset, const position3u& dst_offset, const size3u& size) const + { + copy_image(cmd, src, dst, src_level, dst_level, static_cast(src_offset), static_cast(dst_offset), static_cast(size)); + } + }; +} diff --git a/rpcs3/Emu/RSX/GL/glutils/common.cpp b/rpcs3/Emu/RSX/GL/glutils/common.cpp index 18667ff14a..3c5dfc4db1 100644 --- a/rpcs3/Emu/RSX/GL/glutils/common.cpp +++ b/rpcs3/Emu/RSX/GL/glutils/common.cpp @@ -1,5 +1,6 @@ #pragma once #include "state_tracker.hpp" +#include "vao.hpp" namespace gl { @@ -30,4 +31,9 @@ namespace gl { return { *s_current_state }; } + + attrib_t vao::operator[](u32 index) const noexcept + { + return attrib_t(index); + } } diff --git a/rpcs3/Emu/RSX/GL/glutils/common.h b/rpcs3/Emu/RSX/GL/glutils/common.h index ae6fba9a5a..aecf24ad63 100644 --- a/rpcs3/Emu/RSX/GL/glutils/common.h +++ b/rpcs3/Emu/RSX/GL/glutils/common.h @@ -48,127 +48,25 @@ namespace gl { - // TODO: Move to sync.h - class fence + template + class save_binding_state_base { - GLsync m_value = nullptr; - mutable GLenum flags = GL_SYNC_FLUSH_COMMANDS_BIT; - mutable bool signaled = false; + GLint m_last_binding; public: - - fence() = default; - ~fence() = default; - - void create() + save_binding_state_base(const Type& new_state) : save_binding_state_base() { - m_value = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - flags = GL_SYNC_FLUSH_COMMANDS_BIT; + new_state.bind(); } - void destroy() + save_binding_state_base() { - glDeleteSync(m_value); - m_value = nullptr; + glGetIntegerv(GetStateId, &m_last_binding); } - void reset() + ~save_binding_state_base() { - if (m_value != nullptr) - destroy(); - - create(); - } - - bool is_empty() const - { - return (m_value == nullptr); - } - - bool check_signaled() const - { - ensure(m_value); - - if (signaled) - return true; - - if (flags) - { - GLenum err = glClientWaitSync(m_value, flags, 0); - flags = 0; - - if (!(err == GL_ALREADY_SIGNALED || err == GL_CONDITION_SATISFIED)) - return false; - } - else - { - GLint status = GL_UNSIGNALED; - GLint tmp; - - glGetSynciv(m_value, GL_SYNC_STATUS, 4, &tmp, &status); - - if (status != GL_SIGNALED) - return false; - } - - signaled = true; - return true; - } - - bool wait_for_signal() - { - ensure(m_value); - - if (signaled == GL_FALSE) - { - GLenum err = GL_WAIT_FAILED; - bool done = false; - - while (!done) - { - if (flags) - { - err = glClientWaitSync(m_value, flags, 0); - flags = 0; - - switch (err) - { - default: - rsx_log.error("gl::fence sync returned unknown error 0x%X", err); - [[fallthrough]]; - case GL_ALREADY_SIGNALED: - case GL_CONDITION_SATISFIED: - done = true; - break; - case GL_TIMEOUT_EXPIRED: - continue; - } - } - else - { - GLint status = GL_UNSIGNALED; - GLint tmp; - - glGetSynciv(m_value, GL_SYNC_STATUS, 4, &tmp, &status); - - if (status == GL_SIGNALED) - break; - } - } - - signaled = (err == GL_ALREADY_SIGNALED || err == GL_CONDITION_SATISFIED); - } - - glDeleteSync(m_value); - m_value = nullptr; - - return signaled; - } - - void server_wait_sync() const - { - ensure(m_value != nullptr); - glWaitSync(m_value, 0, GL_TIMEOUT_IGNORED); + glBindBuffer(BindId, m_last_binding); } }; } diff --git a/rpcs3/Emu/RSX/GL/glutils/fbo.cpp b/rpcs3/Emu/RSX/GL/glutils/fbo.cpp new file mode 100644 index 0000000000..38bddb8740 --- /dev/null +++ b/rpcs3/Emu/RSX/GL/glutils/fbo.cpp @@ -0,0 +1,276 @@ +#include "stdafx.h" +#include "fbo.h" +#include "buffer_object.h" +#include "vao.hpp" + +#include "Emu/RSX/Common/simple_array.hpp" + +namespace gl +{ + const fbo screen{}; + + void fbo::create() + { + glGenFramebuffers(1, &m_id); + } + + void fbo::bind() const + { + glBindFramebuffer(GL_FRAMEBUFFER, m_id); + } + + void fbo::blit(const fbo& dst, areai src_area, areai dst_area, buffers buffers_, filter filter_) const + { + bind_as(target::read_frame_buffer); + dst.bind_as(target::draw_frame_buffer); + glBlitFramebuffer( + src_area.x1, src_area.y1, src_area.x2, src_area.y2, + dst_area.x1, dst_area.y1, dst_area.x2, dst_area.y2, + static_cast(buffers_), static_cast(filter_)); + } + + void fbo::bind_as(target target_) const + { + glBindFramebuffer(static_cast(target_), id()); + } + + void fbo::remove() + { + if (m_id != GL_NONE) + { + glDeleteFramebuffers(1, &m_id); + m_id = GL_NONE; + } + } + + bool fbo::created() const + { + return m_id != GL_NONE; + } + + bool fbo::check() const + { + GLenum status = DSA_CALL2_RET(CheckNamedFramebufferStatus, m_id, GL_FRAMEBUFFER); + + if (status != GL_FRAMEBUFFER_COMPLETE) + { + rsx_log.error("FBO check failed: 0x%04x", status); + return false; + } + + return true; + } + + void fbo::recreate() + { + if (created()) + remove(); + + create(); + } + + void fbo::draw_buffer(const attachment& buffer) const + { + GLenum buf = buffer.id(); + DSA_CALL3(NamedFramebufferDrawBuffers, FramebufferDrawBuffers, m_id, 1, &buf); + } + + void fbo::draw_buffers(const std::initializer_list& indexes) const + { + rsx::simple_array ids; + ids.reserve(::size32(indexes)); + + for (auto& index : indexes) + ids.push_back(index.id()); + + DSA_CALL3(NamedFramebufferDrawBuffers, FramebufferDrawBuffers, m_id, static_cast(ids.size()), ids.data()); + } + + void fbo::read_buffer(const attachment& buffer) const + { + DSA_CALL3(NamedFramebufferReadBuffer, FramebufferReadBuffer, m_id, buffer.id()); + } + + void fbo::draw_arrays(GLenum mode, GLsizei count, GLint first) const + { + save_binding_state save(*this); + glDrawArrays(mode, first, count); + } + + void fbo::draw_arrays(const buffer& buffer, GLenum mode, GLsizei count, GLint first) const + { + buffer.bind(buffer::target::array); + draw_arrays(mode, count, first); + } + + void fbo::draw_arrays(const vao& buffer, GLenum mode, GLsizei count, GLint first) const + { + buffer.bind(); + draw_arrays(mode, count, first); + } + + void fbo::draw_elements(GLenum mode, GLsizei count, indices_type type, const GLvoid* indices) const + { + save_binding_state save(*this); + glDrawElements(mode, count, static_cast(type), indices); + } + + void fbo::draw_elements(const buffer& buffer, GLenum mode, GLsizei count, indices_type type, const GLvoid* indices) const + { + buffer.bind(buffer::target::array); + glDrawElements(mode, count, static_cast(type), indices); + } + + void fbo::draw_elements(GLenum mode, GLsizei count, indices_type type, const buffer& indices, usz indices_buffer_offset) const + { + indices.bind(buffer::target::element_array); + glDrawElements(mode, count, static_cast(type), reinterpret_cast(indices_buffer_offset)); + } + + void fbo::draw_elements(const buffer& buffer_, GLenum mode, GLsizei count, indices_type type, const buffer& indices, usz indices_buffer_offset) const + { + buffer_.bind(buffer::target::array); + draw_elements(mode, count, type, indices, indices_buffer_offset); + } + + void fbo::draw_elements(GLenum mode, GLsizei count, const GLubyte* indices) const + { + draw_elements(mode, count, indices_type::ubyte, indices); + } + + void fbo::draw_elements(const buffer& buffer, GLenum mode, GLsizei count, const GLubyte* indices) const + { + draw_elements(buffer, mode, count, indices_type::ubyte, indices); + } + + void fbo::draw_elements(GLenum mode, GLsizei count, const GLushort* indices) const + { + draw_elements(mode, count, indices_type::ushort, indices); + } + + void fbo::draw_elements(const buffer& buffer, GLenum mode, GLsizei count, const GLushort* indices) const + { + draw_elements(buffer, mode, count, indices_type::ushort, indices); + } + + void fbo::draw_elements(GLenum mode, GLsizei count, const GLuint* indices) const + { + draw_elements(mode, count, indices_type::uint, indices); + } + + void fbo::draw_elements(const buffer& buffer, GLenum mode, GLsizei count, const GLuint* indices) const + { + draw_elements(buffer, mode, count, indices_type::uint, indices); + } + + void fbo::clear(buffers buffers_) const + { + save_binding_state save(*this); + glClear(static_cast(buffers_)); + } + + void fbo::clear(buffers buffers_, color4f color_value, double depth_value, u8 stencil_value) const + { + save_binding_state save(*this); + glClearColor(color_value.r, color_value.g, color_value.b, color_value.a); + glClearDepth(depth_value); + glClearStencil(stencil_value); + clear(buffers_); + } + + void fbo::copy_from(const void* pixels, const sizei& size, gl::texture::format format_, gl::texture::type type_, class pixel_unpack_settings pixel_settings) const + { + save_binding_state save(*this); + pixel_settings.apply(); + glDrawPixels(size.width, size.height, static_cast(format_), static_cast(type_), pixels); + } + + void fbo::copy_from(const buffer& buf, const sizei& size, gl::texture::format format_, gl::texture::type type_, class pixel_unpack_settings pixel_settings) const + { + save_binding_state save(*this); + buffer::save_binding_state save_buffer(buffer::target::pixel_unpack, buf); + pixel_settings.apply(); + glDrawPixels(size.width, size.height, static_cast(format_), static_cast(type_), nullptr); + } + + void fbo::copy_to(void* pixels, coordi coord, gl::texture::format format_, gl::texture::type type_, class pixel_pack_settings pixel_settings) const + { + save_binding_state save(*this); + pixel_settings.apply(); + glReadPixels(coord.x, coord.y, coord.width, coord.height, static_cast(format_), static_cast(type_), pixels); + } + + void fbo::copy_to(const buffer& buf, coordi coord, gl::texture::format format_, gl::texture::type type_, class pixel_pack_settings pixel_settings) const + { + save_binding_state save(*this); + buffer::save_binding_state save_buffer(buffer::target::pixel_pack, buf); + pixel_settings.apply(); + glReadPixels(coord.x, coord.y, coord.width, coord.height, static_cast(format_), static_cast(type_), nullptr); + } + + fbo fbo::get_bound_draw_buffer() + { + GLint value; + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &value); + + return{ static_cast(value) }; + } + + fbo fbo::get_bound_read_buffer() + { + GLint value; + glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &value); + + return{ static_cast(value) }; + } + + fbo fbo::get_bound_buffer() + { + GLint value; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &value); + + return{ static_cast(value) }; + } + + GLuint fbo::id() const + { + return m_id; + } + + void fbo::set_id(GLuint id) + { + m_id = id; + } + + void fbo::set_extents(const size2i& extents) + { + m_size = extents; + } + + size2i fbo::get_extents() const + { + return m_size; + } + + bool fbo::matches(const std::array& color_targets, GLuint depth_stencil_target) const + { + for (u32 index = 0; index < 4; ++index) + { + if (color[index].resource_id() != color_targets[index]) + { + return false; + } + } + + const auto depth_resource = depth.resource_id() | depth_stencil.resource_id(); + return (depth_resource == depth_stencil_target); + } + + bool fbo::references_any(const std::vector& resources) const + { + return std::any_of(m_resource_bindings.cbegin(), m_resource_bindings.cend(), [&resources](const auto& e) + { + return std::find(resources.cbegin(), resources.cend(), e.second) != resources.cend(); + }); + } +} diff --git a/rpcs3/Emu/RSX/GL/glutils/fbo.h b/rpcs3/Emu/RSX/GL/glutils/fbo.h new file mode 100644 index 0000000000..785c0b03eb --- /dev/null +++ b/rpcs3/Emu/RSX/GL/glutils/fbo.h @@ -0,0 +1,242 @@ +#pragma once + +#include "common.h" +#include "image.h" +#include "pixel_settings.hpp" + +#include "Utilities/geometry.h" + +namespace gl +{ + enum class buffers + { + none = 0, + color = GL_COLOR_BUFFER_BIT, + depth = GL_DEPTH_BUFFER_BIT, + stencil = GL_STENCIL_BUFFER_BIT, + + color_depth = color | depth, + color_depth_stencil = color | depth | stencil, + color_stencil = color | stencil, + + depth_stencil = depth | stencil + }; + + enum class indices_type + { + ubyte = GL_UNSIGNED_BYTE, + ushort = GL_UNSIGNED_SHORT, + uint = GL_UNSIGNED_INT + }; + + class vao; + + class fbo + { + GLuint m_id = GL_NONE; + size2i m_size; + + protected: + std::unordered_map m_resource_bindings; + + public: + fbo() = default; + + fbo(GLuint id) + { + set_id(id); + } + + ~fbo() + { + if (created()) + remove(); + } + + class save_binding_state + { + GLint m_last_binding; + bool reset = true; + + public: + save_binding_state(const fbo& new_binding) + { + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &m_last_binding); + + if (m_last_binding + 0u != new_binding.id()) + new_binding.bind(); + else + reset = false; + } + + ~save_binding_state() + { + if (reset) + glBindFramebuffer(GL_FRAMEBUFFER, m_last_binding); + } + }; + + class attachment + { + public: + enum class type + { + color = GL_COLOR_ATTACHMENT0, + depth = GL_DEPTH_ATTACHMENT, + stencil = GL_STENCIL_ATTACHMENT, + depth_stencil = GL_DEPTH_STENCIL_ATTACHMENT + }; + + protected: + GLuint m_id = GL_NONE; + fbo& m_parent; + + attachment(fbo& parent) + : m_parent(parent) + {} + + public: + attachment(fbo& parent, type type) + : m_id(static_cast(type)) + , m_parent(parent) + { + } + + void set_id(uint id) + { + m_id = id; + } + + uint id() const + { + return m_id; + } + + GLuint resource_id() const + { + const auto found = m_parent.m_resource_bindings.find(m_id); + if (found != m_parent.m_resource_bindings.end()) + { + return found->second; + } + + return 0; + } + + void operator = (const texture& rhs) + { + ensure(rhs.get_target() == texture::target::texture2D); + m_parent.m_resource_bindings[m_id] = rhs.id(); + DSA_CALL2(NamedFramebufferTexture, m_parent.id(), m_id, rhs.id(), 0); + } + + void operator = (const GLuint rhs) + { + m_parent.m_resource_bindings[m_id] = rhs; + DSA_CALL2(NamedFramebufferTexture, m_parent.id(), m_id, rhs, 0); + } + }; + + class indexed_attachment : public attachment + { + public: + indexed_attachment(fbo& parent, type type) : attachment(parent, type) + { + } + + attachment operator[](int index) const + { + return{ m_parent, type(id() + index) }; + } + + std::vector range(int from, int count) const + { + std::vector result; + + for (int i = from; i < from + count; ++i) + result.push_back((*this)[i]); + + return result; + } + + using attachment::operator =; + }; + + struct null_attachment : public attachment + { + null_attachment(fbo& parent) + : attachment(parent) + {} + }; + + indexed_attachment color{ *this, attachment::type::color }; + attachment depth{ *this, attachment::type::depth }; + attachment stencil{ *this, attachment::type::stencil }; + attachment depth_stencil{ *this, attachment::type::depth_stencil }; + null_attachment no_color{ *this }; + + enum class target + { + read_frame_buffer = GL_READ_FRAMEBUFFER, + draw_frame_buffer = GL_DRAW_FRAMEBUFFER + }; + + void create(); + void bind() const; + void blit(const fbo& dst, areai src_area, areai dst_area, buffers buffers_ = buffers::color, filter filter_ = filter::nearest) const; + void bind_as(target target_) const; + void remove(); + bool created() const; + bool check() const; + + void recreate(); + void draw_buffer(const attachment& buffer) const; + void draw_buffers(const std::initializer_list& indexes) const; + + void read_buffer(const attachment& buffer) const; + + void draw_arrays(GLenum mode, GLsizei count, GLint first = 0) const; + void draw_arrays(const buffer& buffer, GLenum mode, GLsizei count, GLint first = 0) const; + void draw_arrays(const vao& buffer, GLenum mode, GLsizei count, GLint first = 0) const; + + void draw_elements(GLenum mode, GLsizei count, indices_type type, const GLvoid* indices) const; + void draw_elements(const buffer& buffer, GLenum mode, GLsizei count, indices_type type, const GLvoid* indices) const; + void draw_elements(GLenum mode, GLsizei count, indices_type type, const buffer& indices, usz indices_buffer_offset = 0) const; + void draw_elements(const buffer& buffer_, GLenum mode, GLsizei count, indices_type type, const buffer& indices, usz indices_buffer_offset = 0) const; + void draw_elements(GLenum mode, GLsizei count, const GLubyte* indices) const; + void draw_elements(const buffer& buffer, GLenum mode, GLsizei count, const GLubyte* indices) const; + void draw_elements(GLenum mode, GLsizei count, const GLushort* indices) const; + void draw_elements(const buffer& buffer, GLenum mode, GLsizei count, const GLushort* indices) const; + void draw_elements(GLenum mode, GLsizei count, const GLuint* indices) const; + void draw_elements(const buffer& buffer, GLenum mode, GLsizei count, const GLuint* indices) const; + + void clear(buffers buffers_) const; + void clear(buffers buffers_, color4f color_value, double depth_value, u8 stencil_value) const; + + void copy_from(const void* pixels, const sizei& size, gl::texture::format format_, gl::texture::type type_, class pixel_unpack_settings pixel_settings = pixel_unpack_settings()) const; + void copy_from(const buffer& buf, const sizei& size, gl::texture::format format_, gl::texture::type type_, class pixel_unpack_settings pixel_settings = pixel_unpack_settings()) const; + + void copy_to(void* pixels, coordi coord, gl::texture::format format_, gl::texture::type type_, class pixel_pack_settings pixel_settings = pixel_pack_settings()) const; + void copy_to(const buffer& buf, coordi coord, gl::texture::format format_, gl::texture::type type_, class pixel_pack_settings pixel_settings = pixel_pack_settings()) const; + + static fbo get_bound_draw_buffer(); + static fbo get_bound_read_buffer(); + static fbo get_bound_buffer(); + + GLuint id() const; + void set_id(GLuint id); + + void set_extents(const size2i& extents); + size2i get_extents() const; + + bool matches(const std::array& color_targets, GLuint depth_stencil_target) const; + bool references_any(const std::vector& resources) const; + + explicit operator bool() const + { + return created(); + } + }; + + extern const fbo screen; +} diff --git a/rpcs3/Emu/RSX/GL/glutils/image.cpp b/rpcs3/Emu/RSX/GL/glutils/image.cpp index 32f2c4974d..86a1b34459 100644 --- a/rpcs3/Emu/RSX/GL/glutils/image.cpp +++ b/rpcs3/Emu/RSX/GL/glutils/image.cpp @@ -224,7 +224,7 @@ namespace gl } } - void texture_view::create(texture* data, GLenum target, GLenum sized_format, GLenum aspect_flags, const GLenum* argb_swizzle) + void texture_view::create(texture* data, GLenum target, GLuint min_level, GLuint num_levels, GLenum sized_format, GLenum aspect_flags, const GLenum* argb_swizzle) { m_target = target; m_format = sizedfmt_to_ifmt(sized_format); @@ -243,7 +243,7 @@ namespace gl } glGenTextures(1, &m_id); - glTextureView(m_id, target, data->id(), m_format, 0, data->levels(), 0, num_layers); + glTextureView(m_id, target, data->id(), m_format, min_level, num_levels, 0, num_layers); if (argb_swizzle) { diff --git a/rpcs3/Emu/RSX/GL/glutils/image.h b/rpcs3/Emu/RSX/GL/glutils/image.h index f97867b201..77a5b748e4 100644 --- a/rpcs3/Emu/RSX/GL/glutils/image.h +++ b/rpcs3/Emu/RSX/GL/glutils/image.h @@ -25,6 +25,22 @@ namespace gl stencil = 4 }; + enum class filter + { + nearest = GL_NEAREST, + linear = GL_LINEAR + }; + + enum class min_filter + { + nearest = GL_NEAREST, + linear = GL_LINEAR, + nearest_mipmap_nearest = GL_NEAREST_MIPMAP_NEAREST, + nearest_mipmap_linear = GL_NEAREST_MIPMAP_LINEAR, + linear_mipmap_nearest = GL_LINEAR_MIPMAP_NEAREST, + linear_mipmap_linear = GL_LINEAR_MIPMAP_LINEAR + }; + class texture { friend class texture_view; @@ -301,7 +317,7 @@ namespace gl GLenum component_swizzle[4]; - void create(texture* data, GLenum target, GLenum sized_format, GLenum aspect_flags, const GLenum* argb_swizzle = nullptr); + void create(texture* data, GLenum target, GLenum sized_format, GLuint min_level, GLuint num_levels, GLenum aspect_flags, const GLenum* argb_swizzle = nullptr); public: texture_view(const texture_view&) = delete; @@ -311,7 +327,7 @@ namespace gl const GLenum* argb_swizzle = nullptr, GLenum aspect_flags = image_aspect::color | image_aspect::depth) { - create(data, target, sized_format, aspect_flags, argb_swizzle); + create(data, target, sized_format, 0, data->levels(), aspect_flags, argb_swizzle); } texture_view(texture* data, const GLenum* argb_swizzle = nullptr, @@ -319,7 +335,16 @@ namespace gl { GLenum target = static_cast(data->get_target()); GLenum sized_format = static_cast(data->get_internal_format()); - create(data, target, sized_format, aspect_flags, argb_swizzle); + create(data, target, sized_format, 0, data->levels(), aspect_flags, argb_swizzle); + } + + texture_view(texture* data, GLuint mip_level, + const GLenum* argb_swizzle = nullptr, + GLenum aspect_flags = image_aspect::color | image_aspect::depth) + { + GLenum target = static_cast(data->get_target()); + GLenum sized_format = static_cast(data->get_internal_format()); + create(data, target, sized_format, mip_level, 1, aspect_flags, argb_swizzle); } virtual ~texture_view(); diff --git a/rpcs3/Emu/RSX/GL/glutils/program.cpp b/rpcs3/Emu/RSX/GL/glutils/program.cpp new file mode 100644 index 0000000000..8421df0b7d --- /dev/null +++ b/rpcs3/Emu/RSX/GL/glutils/program.cpp @@ -0,0 +1,217 @@ +#include "stdafx.h" +#include "program.h" +#include "state_tracker.hpp" + +#include "Emu/system_config.h" + +namespace gl +{ + namespace glsl + { + void shader::precompile() + { + const char* str = source.c_str(); + const GLint length = ::narrow(source.length()); + + if (g_cfg.video.log_programs) + { + std::string base_name; + switch (type) + { + case ::glsl::program_domain::glsl_vertex_program: + base_name = "shaderlog/VertexProgram"; + break; + case ::glsl::program_domain::glsl_fragment_program: + base_name = "shaderlog/FragmentProgram"; + break; + case ::glsl::program_domain::glsl_compute_program: + base_name = "shaderlog/ComputeProgram"; + break; + } + + fs::file(fs::get_cache_dir() + base_name + std::to_string(m_id) + ".glsl", fs::rewrite).write(str, length); + } + + glShaderSource(m_id, 1, &str, &length); + + m_init_fence.create(); + flush_command_queue(m_init_fence); + } + + void shader::create(::glsl::program_domain type_, const std::string & src) + { + type = type_; + source = src; + + GLenum shader_type{}; + switch (type) + { + case ::glsl::program_domain::glsl_vertex_program: + shader_type = GL_VERTEX_SHADER; + break; + case ::glsl::program_domain::glsl_fragment_program: + shader_type = GL_FRAGMENT_SHADER; + break; + case ::glsl::program_domain::glsl_compute_program: + shader_type = GL_COMPUTE_SHADER; + break; + default: + rsx_log.fatal("gl::glsl::shader::compile(): Unhandled shader type (%d)", +type_); + return; + } + + m_id = glCreateShader(shader_type); + precompile(); + } + + shader& shader::compile() + { + std::lock_guard lock(m_compile_lock); + if (m_is_compiled) + { + // Another thread compiled this already + return *this; + } + + ensure(!m_init_fence.is_empty()); // Do not attempt to compile a shader_view!! + m_init_fence.server_wait_sync(); + + glCompileShader(m_id); + + GLint status = GL_FALSE; + glGetShaderiv(m_id, GL_COMPILE_STATUS, &status); + + if (status == GL_FALSE) + { + GLint length = 0; + glGetShaderiv(m_id, GL_INFO_LOG_LENGTH, &length); + + std::string error_msg; + if (length) + { + std::unique_ptr buf(new char[length + 1]); + glGetShaderInfoLog(m_id, length, nullptr, buf.get()); + error_msg = buf.get(); + } + + rsx_log.fatal("Compilation failed: %s\nsource: %s", error_msg, source); + } + + m_compiled_fence.create(); + flush_command_queue(m_compiled_fence); + + m_is_compiled = true; + return *this; + } + + bool program::uniforms_t::has_location(const std::string & name, int* location) + { + auto found = locations.find(name); + if (found != locations.end()) + { + if (location) + { + *location = found->second; + } + + return (found->second >= 0); + } + + auto result = glGetUniformLocation(m_program.id(), name.c_str()); + locations[name] = result; + + if (location) + { + *location = result; + } + + return (result >= 0); + } + + GLint program::uniforms_t::location(const std::string& name) + { + auto found = locations.find(name); + if (found != locations.end()) + { + if (found->second >= 0) + { + return found->second; + } + else + { + rsx_log.fatal("%s not found.", name); + return -1; + } + } + + auto result = glGetUniformLocation(m_program.id(), name.c_str()); + + if (result < 0) + { + rsx_log.fatal("%s not found.", name); + return result; + } + + locations[name] = result; + return result; + } + + void program::link(std::function init_func) + { + glLinkProgram(m_id); + + GLint status = GL_FALSE; + glGetProgramiv(m_id, GL_LINK_STATUS, &status); + + if (status == GL_FALSE) + { + GLint length = 0; + glGetProgramiv(m_id, GL_INFO_LOG_LENGTH, &length); + + std::string error_msg; + if (length) + { + std::unique_ptr buf(new char[length + 1]); + glGetProgramInfoLog(m_id, length, nullptr, buf.get()); + error_msg = buf.get(); + } + + rsx_log.fatal("Linkage failed: %s", error_msg); + } + else + { + if (init_func) + { + init_func(this); + } + + m_fence.create(); + flush_command_queue(m_fence); + } + } + + void program::validate() + { + glValidateProgram(m_id); + + GLint status = GL_FALSE; + glGetProgramiv(m_id, GL_VALIDATE_STATUS, &status); + + if (status == GL_FALSE) + { + GLint length = 0; + glGetProgramiv(m_id, GL_INFO_LOG_LENGTH, &length); + + std::string error_msg; + if (length) + { + std::unique_ptr buf(new char[length + 1]); + glGetProgramInfoLog(m_id, length, nullptr, buf.get()); + error_msg = buf.get(); + } + + rsx_log.error("Validation failed: %s", error_msg.c_str()); + } + } + } +} diff --git a/rpcs3/Emu/RSX/GL/glutils/program.h b/rpcs3/Emu/RSX/GL/glutils/program.h new file mode 100644 index 0000000000..4349209b8a --- /dev/null +++ b/rpcs3/Emu/RSX/GL/glutils/program.h @@ -0,0 +1,197 @@ +#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() + { + if (created()) + { + remove(); + } + } + + void remove() + { + 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(); } + }; + } +} diff --git a/rpcs3/Emu/RSX/GL/glutils/ring_buffer.h b/rpcs3/Emu/RSX/GL/glutils/ring_buffer.h index 509884c725..565704fd46 100644 --- a/rpcs3/Emu/RSX/GL/glutils/ring_buffer.h +++ b/rpcs3/Emu/RSX/GL/glutils/ring_buffer.h @@ -1,6 +1,7 @@ #pragma once #include "buffer_object.h" +#include "sync.hpp" #include "Utilities/address_range.h" namespace gl diff --git a/rpcs3/Emu/RSX/GL/glutils/state_tracker.hpp b/rpcs3/Emu/RSX/GL/glutils/state_tracker.hpp index 836d5b7b8d..d3b6304a26 100644 --- a/rpcs3/Emu/RSX/GL/glutils/state_tracker.hpp +++ b/rpcs3/Emu/RSX/GL/glutils/state_tracker.hpp @@ -348,4 +348,7 @@ namespace gl void set_primary_context_thread(bool = true); bool is_primary_context_thread(); + + class fence; + void flush_command_queue(fence& fence_obj); } diff --git a/rpcs3/Emu/RSX/GL/glutils/sync.hpp b/rpcs3/Emu/RSX/GL/glutils/sync.hpp new file mode 100644 index 0000000000..4a39bb6171 --- /dev/null +++ b/rpcs3/Emu/RSX/GL/glutils/sync.hpp @@ -0,0 +1,129 @@ +#pragma once + +#include "common.h" + +namespace gl +{ + class fence + { + GLsync m_value = nullptr; + mutable GLenum flags = GL_SYNC_FLUSH_COMMANDS_BIT; + mutable bool signaled = false; + + public: + + fence() = default; + ~fence() = default; + + void create() + { + m_value = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + flags = GL_SYNC_FLUSH_COMMANDS_BIT; + } + + void destroy() + { + glDeleteSync(m_value); + m_value = nullptr; + } + + void reset() + { + if (m_value != nullptr) + destroy(); + + create(); + } + + bool is_empty() const + { + return (m_value == nullptr); + } + + bool check_signaled() const + { + ensure(m_value); + + if (signaled) + return true; + + if (flags) + { + GLenum err = glClientWaitSync(m_value, flags, 0); + flags = 0; + + if (!(err == GL_ALREADY_SIGNALED || err == GL_CONDITION_SATISFIED)) + return false; + } + else + { + GLint status = GL_UNSIGNALED; + GLint tmp; + + glGetSynciv(m_value, GL_SYNC_STATUS, 4, &tmp, &status); + + if (status != GL_SIGNALED) + return false; + } + + signaled = true; + return true; + } + + bool wait_for_signal() + { + ensure(m_value); + + if (signaled == GL_FALSE) + { + GLenum err = GL_WAIT_FAILED; + bool done = false; + + while (!done) + { + if (flags) + { + err = glClientWaitSync(m_value, flags, 0); + flags = 0; + + switch (err) + { + default: + rsx_log.error("gl::fence sync returned unknown error 0x%X", err); + [[fallthrough]]; + case GL_ALREADY_SIGNALED: + case GL_CONDITION_SATISFIED: + done = true; + break; + case GL_TIMEOUT_EXPIRED: + continue; + } + } + else + { + GLint status = GL_UNSIGNALED; + GLint tmp; + + glGetSynciv(m_value, GL_SYNC_STATUS, 4, &tmp, &status); + + if (status == GL_SIGNALED) + break; + } + } + + signaled = (err == GL_ALREADY_SIGNALED || err == GL_CONDITION_SATISFIED); + } + + glDeleteSync(m_value); + m_value = nullptr; + + return signaled; + } + + void server_wait_sync() const + { + ensure(m_value != nullptr); + glWaitSync(m_value, 0, GL_TIMEOUT_IGNORED); + } + }; +} diff --git a/rpcs3/Emu/RSX/GL/glutils/vao.hpp b/rpcs3/Emu/RSX/GL/glutils/vao.hpp new file mode 100644 index 0000000000..410d874df6 --- /dev/null +++ b/rpcs3/Emu/RSX/GL/glutils/vao.hpp @@ -0,0 +1,306 @@ +#pragma once + +#include "common.h" +#include "buffer_object.h" + +#include "Utilities/geometry.h" + +namespace gl +{ + class vao; + + class buffer_pointer + { + public: + enum class type + { + s8 = GL_BYTE, + u8 = GL_UNSIGNED_BYTE, + s16 = GL_SHORT, + u16 = GL_UNSIGNED_SHORT, + s32 = GL_INT, + u32 = GL_UNSIGNED_INT, + f16 = GL_HALF_FLOAT, + f32 = GL_FLOAT, + f64 = GL_DOUBLE, + fixed = GL_FIXED, + s32_2_10_10_10_rev = GL_INT_2_10_10_10_REV, + u32_2_10_10_10_rev = GL_UNSIGNED_INT_2_10_10_10_REV, + u32_10f_11f_11f_rev = GL_UNSIGNED_INT_10F_11F_11F_REV + }; + + private: + vao* m_vao; + u32 m_offset; + u32 m_stride; + u32 m_size = 4; + type m_type = type::f32; + bool m_normalize = false; + + public: + buffer_pointer(vao* vao, u32 offset = 0, u32 stride = 0) + : m_vao(vao) + , m_offset(offset) + , m_stride(stride) + { + } + + const class ::gl::vao& get_vao() const + { + return *m_vao; + } + + class ::gl::vao& get_vao() + { + return *m_vao; + } + + buffer_pointer& offset(u32 value) + { + m_offset = value; + return *this; + } + + u32 offset() const + { + return m_offset; + } + + buffer_pointer& stride(u32 value) + { + m_stride = value; + return *this; + } + + u32 stride() const + { + return m_stride; + } + + buffer_pointer& size(u32 value) + { + m_size = value; + return *this; + } + + u32 size() const + { + return m_size; + } + + buffer_pointer& set_type(type value) + { + m_type = value; + return *this; + } + + type get_type() const + { + return m_type; + } + + buffer_pointer& normalize(bool value) + { + m_normalize = value; + return *this; + } + + bool normalize() const + { + return m_normalize; + } + + buffer_pointer& operator >> (u32 value) + { + return stride(value); + } + + buffer_pointer& config(type type_ = type::f32, u32 size_ = 4, bool normalize_ = false) + { + return set_type(type_).size(size_).normalize(normalize_); + } + }; + + class attrib_t; + + class vao + { + template + class entry + { + vao& m_parent; + + public: + using save_binding_state = save_binding_state_base(BindId)), GetStateId>; + + entry(vao* parent) noexcept : m_parent(*parent) + { + } + + entry& operator = (const buffer& buf) noexcept + { + m_parent.bind(); + buf.bind(BindId); + + return *this; + } + }; + + GLuint m_id = GL_NONE; + + public: + entry pixel_pack_buffer{ this }; + entry pixel_unpack_buffer{ this }; + entry array_buffer{ this }; + entry element_array_buffer{ this }; + + vao() = default; + vao(const vao&) = delete; + + vao(vao&& vao_) noexcept + { + swap(vao_); + } + vao(GLuint id) noexcept + { + set_id(id); + } + + ~vao() noexcept + { + if (created()) + remove(); + } + + void swap(vao& vao_) noexcept + { + auto my_old_id = id(); + set_id(vao_.id()); + vao_.set_id(my_old_id); + } + + vao& operator = (const vao& rhs) = delete; + vao& operator = (vao&& rhs) noexcept + { + swap(rhs); + return *this; + } + + void bind() const noexcept + { + glBindVertexArray(m_id); + } + + void create() noexcept + { + glGenVertexArrays(1, &m_id); + } + + void remove() noexcept + { + if (m_id != GL_NONE) + { + glDeleteVertexArrays(1, &m_id); + m_id = GL_NONE; + } + } + + uint id() const noexcept + { + return m_id; + } + + void set_id(uint id) noexcept + { + m_id = id; + } + + bool created() const noexcept + { + return m_id != GL_NONE; + } + + explicit operator bool() const noexcept + { + return created(); + } + + void enable_for_attributes(std::initializer_list indexes) noexcept + { + for (auto& index : indexes) + { + glEnableVertexAttribArray(index); + } + } + + void disable_for_attributes(std::initializer_list indexes) noexcept + { + for (auto& index : indexes) + { + glDisableVertexAttribArray(index); + } + } + + void enable_for_attribute(GLuint index) noexcept + { + enable_for_attributes({ index }); + } + + void disable_for_attribute(GLuint index) noexcept + { + disable_for_attributes({ index }); + } + + buffer_pointer operator + (u32 offset) noexcept + { + return{ this, offset }; + } + + buffer_pointer operator >> (u32 stride) noexcept + { + return{ this, {}, stride }; + } + + operator buffer_pointer() noexcept + { + return{ this }; + } + + attrib_t operator [] (u32 index) const noexcept; + }; + + class attrib_t + { + GLint m_location; + + public: + attrib_t(GLint location) + : m_location(location) + { + } + + GLint location() const + { + return m_location; + } + + void operator = (float rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib1f(location(), rhs); } + void operator = (double rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib1d(location(), rhs); } + + void operator = (const color1f& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib1f(location(), rhs.r); } + void operator = (const color1d& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib1d(location(), rhs.r); } + void operator = (const color2f& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib2f(location(), rhs.r, rhs.g); } + void operator = (const color2d& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib2d(location(), rhs.r, rhs.g); } + void operator = (const color3f& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib3f(location(), rhs.r, rhs.g, rhs.b); } + void operator = (const color3d& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib3d(location(), rhs.r, rhs.g, rhs.b); } + void operator = (const color4f& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib4f(location(), rhs.r, rhs.g, rhs.b, rhs.a); } + void operator = (const color4d& rhs) const { glDisableVertexAttribArray(location()); glVertexAttrib4d(location(), rhs.r, rhs.g, rhs.b, rhs.a); } + + void operator = (buffer_pointer& pointer) const + { + pointer.get_vao().enable_for_attribute(m_location); + glVertexAttribPointer(location(), pointer.size(), static_cast(pointer.get_type()), pointer.normalize(), + pointer.stride(), reinterpret_cast(u64{ pointer.offset() })); + } + }; +} diff --git a/rpcs3/GLGSRender.vcxproj b/rpcs3/GLGSRender.vcxproj index beb9ff1187..b4721b9cd5 100644 --- a/rpcs3/GLGSRender.vcxproj +++ b/rpcs3/GLGSRender.vcxproj @@ -60,13 +60,18 @@ + + + + + @@ -83,8 +88,11 @@ + + + diff --git a/rpcs3/GLGSRender.vcxproj.filters b/rpcs3/GLGSRender.vcxproj.filters index 322a5839d0..e4076b0388 100644 --- a/rpcs3/GLGSRender.vcxproj.filters +++ b/rpcs3/GLGSRender.vcxproj.filters @@ -29,6 +29,15 @@ glutils + + glutils + + + glutils + + + glutils + @@ -68,6 +77,21 @@ glutils + + glutils + + + glutils + + + glutils + + + glutils + + + glutils +