diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index e951b5bd7c..36135d5b46 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -455,6 +455,8 @@ target_sources(rpcs3_emu PRIVATE RSX/Capture/rsx_capture.cpp RSX/Capture/rsx_replay.cpp RSX/GL/glutils/buffer_object.cpp + RSX/GL/glutils/common.cpp + RSX/GL/glutils/image.cpp RSX/GL/glutils/ring_buffer.cpp RSX/GL/GLCommonDecompiler.cpp RSX/GL/GLCompute.cpp diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index c8b3388d50..803bd273f0 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -96,6 +96,7 @@ void GLGSRender::on_init_thread() m_occlusion_type = g_cfg.video.precise_zpass_count ? GL_SAMPLES_PASSED : GL_ANY_SAMPLES_PASSED; gl::init(); + gl::set_command_context(gl_state); //Enable adaptive vsync if vsync is requested gl::set_swapinterval(g_cfg.video.vsync ? -1 : 0); diff --git a/rpcs3/Emu/RSX/GL/GLHelpers.cpp b/rpcs3/Emu/RSX/GL/GLHelpers.cpp index 8ac1c75361..9cb505294e 100644 --- a/rpcs3/Emu/RSX/GL/GLHelpers.cpp +++ b/rpcs3/Emu/RSX/GL/GLHelpers.cpp @@ -14,18 +14,6 @@ namespace gl capabilities g_driver_caps; const fbo screen{}; - static thread_local bool s_tls_primary_context_thread = false; - - void set_primary_context_thread(bool value) - { - s_tls_primary_context_thread = value; - } - - bool is_primary_context_thread() - { - return s_tls_primary_context_thread; - } - void flush_command_queue(fence& fence_obj) { fence_obj.check_signaled(); diff --git a/rpcs3/Emu/RSX/GL/GLHelpers.h b/rpcs3/Emu/RSX/GL/GLHelpers.h index e986fd74d2..bd772ae5bb 100644 --- a/rpcs3/Emu/RSX/GL/GLHelpers.h +++ b/rpcs3/Emu/RSX/GL/GLHelpers.h @@ -7,7 +7,6 @@ #include #include -#include "GLExecutionState.h" #include "../GCM.h" #include "../Common/TextureUtils.h" #include "../Program/GLSLTypes.h" @@ -22,33 +21,15 @@ #include "glutils/common.h" // TODO: Include on use #include "glutils/buffer_object.h" - -#define GL_FRAGMENT_TEXTURES_START 0 -#define GL_VERTEX_TEXTURES_START (GL_FRAGMENT_TEXTURES_START + 16) -#define GL_STENCIL_MIRRORS_START (GL_VERTEX_TEXTURES_START + 4) -#define GL_STREAM_BUFFER_START (GL_STENCIL_MIRRORS_START + 16) - -#define UBO_SLOT(x) (x) -#define SSBO_SLOT(x) (x) - -#define GL_VERTEX_PARAMS_BIND_SLOT UBO_SLOT(0) -#define GL_VERTEX_LAYOUT_BIND_SLOT UBO_SLOT(1) -#define GL_VERTEX_CONSTANT_BUFFERS_BIND_SLOT UBO_SLOT(2) -#define GL_FRAGMENT_CONSTANT_BUFFERS_BIND_SLOT UBO_SLOT(3) -#define GL_FRAGMENT_STATE_BIND_SLOT UBO_SLOT(4) -#define GL_FRAGMENT_TEXTURE_PARAMS_BIND_SLOT UBO_SLOT(5) -#define GL_RASTERIZER_STATE_BIND_SLOT UBO_SLOT(6) -#define GL_INTERPRETER_VERTEX_BLOCK SSBO_SLOT(0) -#define GL_INTERPRETER_FRAGMENT_BLOCK SSBO_SLOT(1) -#define GL_COMPUTE_BUFFER_SLOT(index) SSBO_SLOT(2 + index) +#include "glutils/image.h" +#include "glutils/pixel_settings.hpp" +#include "glutils/state_tracker.hpp" // Noop keyword outside of Windows (used in log_debug) #if !defined(_WIN32) && !defined(APIENTRY) #define APIENTRY #endif -//using enum rsx::format_class; -using namespace ::rsx::format_class_; namespace gl { @@ -56,13 +37,8 @@ namespace gl bool is_primitive_native(rsx::primitive_type in); GLenum draw_mode(rsx::primitive_type in); - void set_primary_context_thread(bool = true); - bool is_primary_context_thread(); void flush_command_queue(fence& fence_obj); - // Texture helpers - std::array apply_swizzle_remap(const std::array& swizzle_remap, const std::pair, std::array>& decoded_remap); - class exception : public std::exception { protected: @@ -127,157 +103,6 @@ namespace gl depth_stencil = depth | stencil }; - class pixel_pack_settings - { - bool m_swap_bytes = false; - bool m_lsb_first = false; - int m_row_length = 0; - int m_image_height = 0; - int m_skip_rows = 0; - int m_skip_pixels = 0; - int m_skip_images = 0; - int m_alignment = 4; - - public: - void apply() const - { - glPixelStorei(GL_PACK_SWAP_BYTES, m_swap_bytes ? GL_TRUE : GL_FALSE); - glPixelStorei(GL_PACK_LSB_FIRST, m_lsb_first ? GL_TRUE : GL_FALSE); - glPixelStorei(GL_PACK_ROW_LENGTH, m_row_length); - glPixelStorei(GL_PACK_IMAGE_HEIGHT, m_image_height); - glPixelStorei(GL_PACK_SKIP_ROWS, m_skip_rows); - glPixelStorei(GL_PACK_SKIP_PIXELS, m_skip_pixels); - glPixelStorei(GL_PACK_SKIP_IMAGES, m_skip_images); - glPixelStorei(GL_PACK_ALIGNMENT, m_alignment); - } - - pixel_pack_settings& swap_bytes(bool value = true) - { - m_swap_bytes = value; - return *this; - } - pixel_pack_settings& lsb_first(bool value = true) - { - m_lsb_first = value; - return *this; - } - pixel_pack_settings& row_length(int value) - { - m_row_length = value; - return *this; - } - pixel_pack_settings& image_height(int value) - { - m_image_height = value; - return *this; - } - pixel_pack_settings& skip_rows(int value) - { - m_skip_rows = value; - return *this; - } - pixel_pack_settings& skip_pixels(int value) - { - m_skip_pixels = value; - return *this; - } - pixel_pack_settings& skip_images(int value) - { - m_skip_images = value; - return *this; - } - pixel_pack_settings& alignment(int value) - { - m_alignment = value; - return *this; - } - - bool get_swap_bytes() const - { - return m_swap_bytes; - } - int get_row_length() const - { - return m_row_length; - } - }; - - class pixel_unpack_settings - { - bool m_swap_bytes = false; - bool m_lsb_first = false; - int m_row_length = 0; - int m_image_height = 0; - int m_skip_rows = 0; - int m_skip_pixels = 0; - int m_skip_images = 0; - int m_alignment = 4; - - public: - void apply() const - { - glPixelStorei(GL_UNPACK_SWAP_BYTES, m_swap_bytes ? GL_TRUE : GL_FALSE); - glPixelStorei(GL_UNPACK_LSB_FIRST, m_lsb_first ? GL_TRUE : GL_FALSE); - glPixelStorei(GL_UNPACK_ROW_LENGTH, m_row_length); - glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, m_image_height); - glPixelStorei(GL_UNPACK_SKIP_ROWS, m_skip_rows); - glPixelStorei(GL_UNPACK_SKIP_PIXELS, m_skip_pixels); - glPixelStorei(GL_UNPACK_SKIP_IMAGES, m_skip_images); - glPixelStorei(GL_UNPACK_ALIGNMENT, m_alignment); - } - - pixel_unpack_settings& swap_bytes(bool value = true) - { - m_swap_bytes = value; - return *this; - } - pixel_unpack_settings& lsb_first(bool value = true) - { - m_lsb_first = value; - return *this; - } - pixel_unpack_settings& row_length(int value) - { - m_row_length = value; - return *this; - } - pixel_unpack_settings& image_height(int value) - { - m_image_height = value; - return *this; - } - pixel_unpack_settings& skip_rows(int value) - { - m_skip_rows = value; - return *this; - } - pixel_unpack_settings& skip_pixels(int value) - { - m_skip_pixels = value; - return *this; - } - pixel_unpack_settings& skip_images(int value) - { - m_skip_images = value; - return *this; - } - pixel_unpack_settings& alignment(int value) - { - m_alignment = value; - return *this; - } - - bool get_swap_bytes() const - { - return m_swap_bytes; - } - - int get_row_length() const - { - return m_row_length; - } - }; - class vao; class attrib_t; @@ -574,694 +399,6 @@ namespace gl } }; - enum image_aspect : u32 - { - color = 1, - depth = 2, - stencil = 4 - }; - - class texture - { - friend class texture_view; - - public: - enum class type - { - ubyte = GL_UNSIGNED_BYTE, - ushort = GL_UNSIGNED_SHORT, - uint = GL_UNSIGNED_INT, - - ubyte_3_3_2 = GL_UNSIGNED_BYTE_3_3_2, - ubyte_2_3_3_rev = GL_UNSIGNED_BYTE_2_3_3_REV, - - ushort_5_6_5 = GL_UNSIGNED_SHORT_5_6_5, - ushort_5_6_5_rev = GL_UNSIGNED_SHORT_5_6_5_REV, - ushort_4_4_4_4 = GL_UNSIGNED_SHORT_4_4_4_4, - ushort_4_4_4_4_rev = GL_UNSIGNED_SHORT_4_4_4_4_REV, - ushort_5_5_5_1 = GL_UNSIGNED_SHORT_5_5_5_1, - ushort_1_5_5_5_rev = GL_UNSIGNED_SHORT_1_5_5_5_REV, - - uint_8_8_8_8 = GL_UNSIGNED_INT_8_8_8_8, - uint_8_8_8_8_rev = GL_UNSIGNED_INT_8_8_8_8_REV, - uint_10_10_10_2 = GL_UNSIGNED_INT_10_10_10_2, - uint_2_10_10_10_rev = GL_UNSIGNED_INT_2_10_10_10_REV, - uint_24_8 = GL_UNSIGNED_INT_24_8, - float32_uint8 = GL_FLOAT_32_UNSIGNED_INT_24_8_REV, - - sbyte = GL_BYTE, - sshort = GL_SHORT, - sint = GL_INT, - f16 = GL_HALF_FLOAT, - f32 = GL_FLOAT, - f64 = GL_DOUBLE, - }; - - enum class channel - { - zero = GL_ZERO, - one = GL_ONE, - r = GL_RED, - g = GL_GREEN, - b = GL_BLUE, - a = GL_ALPHA, - }; - - enum class format - { - r = GL_RED, - rg = GL_RG, - rgb = GL_RGB, - rgba = GL_RGBA, - - bgr = GL_BGR, - bgra = GL_BGRA, - - stencil = GL_STENCIL_INDEX, - depth = GL_DEPTH_COMPONENT, - depth_stencil = GL_DEPTH_STENCIL - }; - - enum class internal_format - { - stencil8 = GL_STENCIL_INDEX8, - depth16 = GL_DEPTH_COMPONENT16, - depth32f = GL_DEPTH_COMPONENT32F, - depth24_stencil8 = GL_DEPTH24_STENCIL8, - depth32f_stencil8 = GL_DEPTH32F_STENCIL8, - - compressed_rgb_s3tc_dxt1 = GL_COMPRESSED_RGB_S3TC_DXT1_EXT, - compressed_rgba_s3tc_dxt1 = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, - compressed_rgba_s3tc_dxt3 = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, - compressed_rgba_s3tc_dxt5 = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, - - //Sized internal formats, see opengl spec document on glTexImage2D, table 3 - rgba8 = GL_RGBA8, - rgb565 = GL_RGB565, - rgb5a1 = GL_RGB5_A1, - rgba4 = GL_RGBA4, - r8 = GL_R8, - r16 = GL_R16, - r32f = GL_R32F, - rg8 = GL_RG8, - rg16 = GL_RG16, - rg16f = GL_RG16F, - rgba16f = GL_RGBA16F, - rgba32f = GL_RGBA32F - }; - - enum class wrap - { - repeat = GL_REPEAT, - mirrored_repeat = GL_MIRRORED_REPEAT, - clamp_to_edge = GL_CLAMP_TO_EDGE, - clamp_to_border = GL_CLAMP_TO_BORDER, - mirror_clamp = GL_MIRROR_CLAMP_EXT, - //mirror_clamp_to_edge = GL_MIRROR_CLAMP_TO_EDGE, - mirror_clamp_to_border = GL_MIRROR_CLAMP_TO_BORDER_EXT - }; - - enum class compare_mode - { - none = GL_NONE, - ref_to_texture = GL_COMPARE_REF_TO_TEXTURE - }; - - enum class target - { - texture1D = GL_TEXTURE_1D, - texture2D = GL_TEXTURE_2D, - texture3D = GL_TEXTURE_3D, - textureCUBE = GL_TEXTURE_CUBE_MAP, - textureBuffer = GL_TEXTURE_BUFFER - }; - - protected: - GLuint m_id = GL_NONE; - GLuint m_width = 0; - GLuint m_height = 0; - GLuint m_depth = 0; - GLuint m_mipmaps = 0; - GLuint m_pitch = 0; - GLuint m_compressed = GL_FALSE; - GLuint m_aspect_flags = 0; - - target m_target = target::texture2D; - internal_format m_internal_format = internal_format::rgba8; - std::array m_component_layout; - - rsx::format_class m_format_class = RSX_FORMAT_CLASS_UNDEFINED; - - class save_binding_state - { - GLenum target = GL_NONE; - GLuint old_binding = GL_NONE; - - public: - save_binding_state(GLenum target) - { - this->target = target; - switch (target) - { - case GL_TEXTURE_1D: - glGetIntegerv(GL_TEXTURE_BINDING_1D, reinterpret_cast(&old_binding)); - break; - case GL_TEXTURE_2D: - glGetIntegerv(GL_TEXTURE_BINDING_2D, reinterpret_cast(&old_binding)); - break; - case GL_TEXTURE_3D: - glGetIntegerv(GL_TEXTURE_BINDING_3D, reinterpret_cast(&old_binding)); - break; - case GL_TEXTURE_CUBE_MAP: - glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, reinterpret_cast(&old_binding)); - break; - case GL_TEXTURE_2D_ARRAY: - glGetIntegerv(GL_TEXTURE_BINDING_2D_ARRAY, reinterpret_cast(&old_binding)); - break; - case GL_TEXTURE_BUFFER: - glGetIntegerv(GL_TEXTURE_BINDING_BUFFER, reinterpret_cast(&old_binding)); - break; - } - } - - ~save_binding_state() - { - glBindTexture(target, old_binding); - } - }; - - public: - texture(const texture&) = delete; - texture(texture&& texture_) = delete; - - texture(GLenum target, GLuint width, GLuint height, GLuint depth, GLuint mipmaps, GLenum sized_format, - rsx::format_class format_class = rsx::RSX_FORMAT_CLASS_UNDEFINED) - { - save_binding_state save(target); - glGenTextures(1, &m_id); - glBindTexture(target, m_id); //Must bind to initialize the new texture - - switch (target) - { - default: - fmt::throw_exception("Invalid image target 0x%X", target); - case GL_TEXTURE_1D: - glTexStorage1D(target, mipmaps, sized_format, width); - height = depth = 1; - break; - case GL_TEXTURE_2D: - case GL_TEXTURE_CUBE_MAP: - glTexStorage2D(target, mipmaps, sized_format, width, height); - depth = 1; - break; - case GL_TEXTURE_3D: - case GL_TEXTURE_2D_ARRAY: - glTexStorage3D(target, mipmaps, sized_format, width, height, depth); - break; - case GL_TEXTURE_BUFFER: - break; - } - - if (target != GL_TEXTURE_BUFFER) - { - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_REPEAT); - glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, mipmaps - 1); - - m_width = width; - m_height = height; - m_depth = depth; - m_mipmaps = mipmaps; - m_aspect_flags = image_aspect::color; - - switch (sized_format) - { - case GL_DEPTH_COMPONENT16: - { - m_pitch = width * 2; - m_aspect_flags = image_aspect::depth; - break; - } - case GL_DEPTH_COMPONENT32F: - { - m_pitch = width * 4; - m_aspect_flags = image_aspect::depth; - break; - } - case GL_DEPTH24_STENCIL8: - case GL_DEPTH32F_STENCIL8: - { - m_pitch = width * 4; - m_aspect_flags = image_aspect::depth | image_aspect::stencil; - break; - } - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - { - m_compressed = true; - m_pitch = utils::align(width, 4) / 2; - break; - } - case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: - { - m_compressed = true; - m_pitch = utils::align(width, 4); - break; - } - default: - { - GLenum query_target = (target == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : target; - GLint r, g, b, a; - - glGetTexLevelParameteriv(query_target, 0, GL_TEXTURE_RED_SIZE, &r); - glGetTexLevelParameteriv(query_target, 0, GL_TEXTURE_GREEN_SIZE, &g); - glGetTexLevelParameteriv(query_target, 0, GL_TEXTURE_BLUE_SIZE, &b); - glGetTexLevelParameteriv(query_target, 0, GL_TEXTURE_ALPHA_SIZE, &a); - - m_pitch = width * (r + g + b + a) / 8; - break; - } - } - - if (!m_pitch) - { - fmt::throw_exception("Unhandled GL format 0x%X", sized_format); - } - - if (format_class == RSX_FORMAT_CLASS_UNDEFINED) - { - if (m_aspect_flags != image_aspect::color) - { - rsx_log.error("Undefined format class for depth texture is not allowed"); - } - else - { - format_class = RSX_FORMAT_CLASS_COLOR; - } - } - } - - m_target = static_cast(target); - m_internal_format = static_cast(sized_format); - m_component_layout = { GL_ALPHA, GL_RED, GL_GREEN, GL_BLUE }; - m_format_class = format_class; - } - - virtual ~texture() - { - if (m_id != GL_NONE) - { - glDeleteTextures(1, &m_id); - m_id = GL_NONE; - } - } - - void set_native_component_layout(const std::array& layout) - { - m_component_layout[0] = layout[0]; - m_component_layout[1] = layout[1]; - m_component_layout[2] = layout[2]; - m_component_layout[3] = layout[3]; - } - - target get_target() const noexcept - { - return m_target; - } - - static bool compressed_format(internal_format format_) noexcept - { - switch (format_) - { - case internal_format::compressed_rgb_s3tc_dxt1: - case internal_format::compressed_rgba_s3tc_dxt1: - case internal_format::compressed_rgba_s3tc_dxt3: - case internal_format::compressed_rgba_s3tc_dxt5: - return true; - default: - return false; - } - } - - uint id() const noexcept - { - return m_id; - } - - explicit operator bool() const noexcept - { - return (m_id != GL_NONE); - } - - GLuint width() const - { - return m_width; - } - - GLuint height() const - { - return m_height; - } - - GLuint depth() const - { - return m_depth; - } - - GLuint levels() const - { - return m_mipmaps; - } - - GLuint pitch() const - { - return m_pitch; - } - - constexpr GLubyte samples() const - { - return 1; - } - - GLboolean compressed() const - { - return m_compressed; - } - - GLuint aspect() const - { - return m_aspect_flags; - } - - rsx::format_class format_class() const - { - return m_format_class; - } - - sizeu size2D() const - { - return{ m_width, m_height }; - } - - size3u size3D() const - { - const auto depth = (m_target == target::textureCUBE) ? 6 : m_depth; - return{ m_width, m_height, depth }; - } - - texture::internal_format get_internal_format() const - { - return m_internal_format; - } - - std::array get_native_component_layout() const - { - return m_component_layout; - } - - void copy_from(const void* src, texture::format format, texture::type type, int level, const coord3u region, const pixel_unpack_settings& pixel_settings) - { - pixel_settings.apply(); - - switch (const auto target_ =static_cast(m_target)) - { - case GL_TEXTURE_1D: - { - DSA_CALL(TextureSubImage1D, m_id, GL_TEXTURE_1D, level, region.x, region.width, static_cast(format), static_cast(type), src); - break; - } - case GL_TEXTURE_2D: - { - DSA_CALL(TextureSubImage2D, m_id, GL_TEXTURE_2D, level, region.x, region.y, region.width, region.height, static_cast(format), static_cast(type), src); - break; - } - case GL_TEXTURE_3D: - case GL_TEXTURE_2D_ARRAY: - { - DSA_CALL(TextureSubImage3D, m_id, target_, level, region.x, region.y, region.z, region.width, region.height, region.depth, static_cast(format), static_cast(type), src); - break; - } - case GL_TEXTURE_CUBE_MAP: - { - if (get_driver_caps().ARB_dsa_supported) - { - glTextureSubImage3D(m_id, level, region.x, region.y, region.z, region.width, region.height, region.depth, static_cast(format), static_cast(type), src); - } - else - { - rsx_log.warning("Cubemap upload via texture::copy_from is halfplemented!"); - auto ptr = static_cast(src); - const auto end = std::min(6u, region.z + region.depth); - for (unsigned face = region.z; face < end; ++face) - { - glTextureSubImage2DEXT(m_id, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, region.x, region.y, region.width, region.height, static_cast(format), static_cast(type), ptr); - ptr += (region.width * region.height * 4); //TODO - } - } - break; - } - } - } - - void copy_from(const void* src, texture::format format, texture::type type, const pixel_unpack_settings& pixel_settings) - { - const coord3u region = { {}, size3D() }; - copy_from(src, format, type, 0, region, pixel_settings); - } - - void copy_from(buffer &buf, u32 gl_format_type, u32 offset, u32 length) - { - if (get_target() != target::textureBuffer) - fmt::throw_exception("OpenGL error: texture cannot copy from buffer"); - - DSA_CALL(TextureBufferRange, m_id, GL_TEXTURE_BUFFER, gl_format_type, buf.id(), offset, length); - } - - void copy_from(buffer_view &view) - { - copy_from(*view.value(), view.format(), view.offset(), view.range()); - } - - void copy_to(void* dst, texture::format format, texture::type type, int level, const coord3u& region, const pixel_pack_settings& pixel_settings) const - { - pixel_settings.apply(); - const auto& caps = get_driver_caps(); - - if (!region.x && !region.y && !region.z && - region.width == m_width && region.height == m_height && region.depth == m_depth) - { - if (caps.ARB_dsa_supported) - glGetTextureImage(m_id, level, static_cast(format), static_cast(type), s32{smax}, dst); - else - glGetTextureImageEXT(m_id, static_cast(m_target), level, static_cast(format), static_cast(type), dst); - } - else if (caps.ARB_dsa_supported) - { - glGetTextureSubImage(m_id, level, region.x, region.y, region.z, region.width, region.height, region.depth, - static_cast(format), static_cast(type), s32{smax}, dst); - } - else - { - // Worst case scenario. For some reason, EXT_dsa does not have glGetTextureSubImage - const auto target_ = static_cast(m_target); - texture tmp{ target_, region.width, region.height, region.depth, 1, static_cast(m_internal_format) }; - glCopyImageSubData(m_id, target_, level, region.x, region.y, region.z, tmp.id(), target_, 0, 0, 0, 0, - region.width, region.height, region.depth); - - const coord3u region2 = { {0, 0, 0}, region.size }; - tmp.copy_to(dst, format, type, 0, region2, pixel_settings); - } - } - - void copy_to(void* dst, texture::format format, texture::type type, const pixel_pack_settings& pixel_settings) const - { - const coord3u region = { {}, size3D() }; - copy_to(dst, format, type, 0, region, pixel_settings); - } - }; - - class texture_view - { - GLuint m_id = GL_NONE; - GLenum m_target = 0; - GLenum m_format = 0; - GLenum m_aspect_flags = 0; - texture *m_image_data = nullptr; - - GLenum component_swizzle[4]; - - void create(texture* data, GLenum target, GLenum sized_format, GLenum aspect_flags, const GLenum* argb_swizzle = nullptr) - { - m_target = target; - m_format = sized_format; - m_image_data = data; - m_aspect_flags = aspect_flags; - - u32 num_layers; - switch (target) - { - default: - num_layers = 1; break; - case GL_TEXTURE_CUBE_MAP: - num_layers = 6; break; - case GL_TEXTURE_2D_ARRAY: - num_layers = data->depth(); break; - } - - glGenTextures(1, &m_id); - glTextureView(m_id, target, data->id(), sized_format, 0, data->levels(), 0, num_layers); - - if (argb_swizzle) - { - component_swizzle[0] = argb_swizzle[1]; - component_swizzle[1] = argb_swizzle[2]; - component_swizzle[2] = argb_swizzle[3]; - component_swizzle[3] = argb_swizzle[0]; - - texture::save_binding_state save(m_target); - glBindTexture(m_target, m_id); - glTexParameteriv(m_target, GL_TEXTURE_SWIZZLE_RGBA, reinterpret_cast(component_swizzle)); - } - else - { - component_swizzle[0] = GL_RED; - component_swizzle[1] = GL_GREEN; - component_swizzle[2] = GL_BLUE; - component_swizzle[3] = GL_ALPHA; - } - - if (aspect_flags & image_aspect::stencil) - { - constexpr u32 depth_stencil_mask = (image_aspect::depth | image_aspect::stencil); - ensure((aspect_flags & depth_stencil_mask) != depth_stencil_mask); // "Invalid aspect mask combination" - - texture::save_binding_state save(m_target); - glBindTexture(m_target, m_id); - glTexParameteri(m_target, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX); - } - } - - public: - texture_view(const texture_view&) = delete; - texture_view(texture_view&&) = delete; - - texture_view(texture* data, GLenum target, GLenum sized_format, - const GLenum* argb_swizzle = nullptr, - GLenum aspect_flags = image_aspect::color | image_aspect::depth) - { - create(data, target, sized_format, aspect_flags, argb_swizzle); - } - - texture_view(texture* data, 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, aspect_flags, argb_swizzle); - } - - ~texture_view() - { - if (m_id != GL_NONE) - { - glDeleteTextures(1, &m_id); - m_id = GL_NONE; - } - } - - GLuint id() const - { - return m_id; - } - - GLenum target() const - { - return m_target; - } - - GLenum internal_format() const - { - return m_format; - } - - GLenum aspect() const - { - return m_aspect_flags; - } - - bool compare_swizzle(const GLenum* argb_swizzle) const - { - return (argb_swizzle[0] == component_swizzle[3] && - argb_swizzle[1] == component_swizzle[0] && - argb_swizzle[2] == component_swizzle[1] && - argb_swizzle[3] == component_swizzle[2]); - } - - void bind(gl::command_context& cmd, GLuint layer) const - { - cmd->bind_texture(layer, m_target, m_id); - } - - texture* image() const - { - return m_image_data; - } - - std::array component_mapping() const - { - return{ component_swizzle[3], component_swizzle[0], component_swizzle[1], component_swizzle[2] }; - } - - u32 encoded_component_map() const - { - // Unused, OGL supports proper component swizzles - return 0u; - } - }; - - class viewable_image : public texture - { - std::unordered_multimap> views; - -public: - using texture::texture; - - texture_view* get_view(u32 remap_encoding, const std::pair, std::array>& remap, GLenum aspect_flags = image_aspect::color | image_aspect::depth) - { - auto found = views.equal_range(remap_encoding); - for (auto It = found.first; It != found.second; ++It) - { - if (It->second->aspect() & aspect_flags) - { - return It->second.get(); - } - } - - ensure(aspect() & aspect_flags); - auto mapping = apply_swizzle_remap(get_native_component_layout(), remap); - auto view = std::make_unique(this, mapping.data(), aspect_flags); - auto result = view.get(); - views.emplace(remap_encoding, std::move(view)); - return result; - } - - void set_native_component_layout(const std::array& layout) - { - if (m_component_layout[0] != layout[0] || - m_component_layout[1] != layout[1] || - m_component_layout[2] != layout[2] || - m_component_layout[3] != layout[3]) - { - texture::set_native_component_layout(layout); - views.clear(); - } - } - }; - class rbo { GLuint m_id = GL_NONE; diff --git a/rpcs3/Emu/RSX/GL/glutils/common.cpp b/rpcs3/Emu/RSX/GL/glutils/common.cpp new file mode 100644 index 0000000000..18667ff14a --- /dev/null +++ b/rpcs3/Emu/RSX/GL/glutils/common.cpp @@ -0,0 +1,33 @@ +#pragma once +#include "state_tracker.hpp" + +namespace gl +{ + static thread_local bool s_tls_primary_context_thread = false; + static gl::driver_state* s_current_state = nullptr; + + void set_primary_context_thread(bool value) + { + s_tls_primary_context_thread = value; + } + + bool is_primary_context_thread() + { + return s_tls_primary_context_thread; + } + + void set_command_context(gl::command_context& ctx) + { + s_current_state = ctx.operator->(); + } + + void set_command_context(gl::driver_state& ctx) + { + s_current_state = &ctx; + } + + gl::command_context get_command_context() + { + return { *s_current_state }; + } +} diff --git a/rpcs3/Emu/RSX/GL/glutils/common.h b/rpcs3/Emu/RSX/GL/glutils/common.h index df78e1246c..5eb15e869e 100644 --- a/rpcs3/Emu/RSX/GL/glutils/common.h +++ b/rpcs3/Emu/RSX/GL/glutils/common.h @@ -2,6 +2,26 @@ #include "capabilities.hpp" +#define GL_FRAGMENT_TEXTURES_START 0 +#define GL_VERTEX_TEXTURES_START (GL_FRAGMENT_TEXTURES_START + 16) +#define GL_STENCIL_MIRRORS_START (GL_VERTEX_TEXTURES_START + 4) +#define GL_STREAM_BUFFER_START (GL_STENCIL_MIRRORS_START + 16) +#define GL_TEMP_IMAGE_SLOT 31 + +#define UBO_SLOT(x) (x) +#define SSBO_SLOT(x) (x) + +#define GL_VERTEX_PARAMS_BIND_SLOT UBO_SLOT(0) +#define GL_VERTEX_LAYOUT_BIND_SLOT UBO_SLOT(1) +#define GL_VERTEX_CONSTANT_BUFFERS_BIND_SLOT UBO_SLOT(2) +#define GL_FRAGMENT_CONSTANT_BUFFERS_BIND_SLOT UBO_SLOT(3) +#define GL_FRAGMENT_STATE_BIND_SLOT UBO_SLOT(4) +#define GL_FRAGMENT_TEXTURE_PARAMS_BIND_SLOT UBO_SLOT(5) +#define GL_RASTERIZER_STATE_BIND_SLOT UBO_SLOT(6) +#define GL_INTERPRETER_VERTEX_BLOCK SSBO_SLOT(0) +#define GL_INTERPRETER_FRAGMENT_BLOCK SSBO_SLOT(1) +#define GL_COMPUTE_BUFFER_SLOT(index) SSBO_SLOT(2 + index) + //Function call wrapped in ARB_DSA vs EXT_DSA compat check #define DSA_CALL(func, object_name, target, ...)\ if (::gl::get_driver_caps().ARB_dsa_supported)\ diff --git a/rpcs3/Emu/RSX/GL/glutils/image.cpp b/rpcs3/Emu/RSX/GL/glutils/image.cpp new file mode 100644 index 0000000000..040fb718c5 --- /dev/null +++ b/rpcs3/Emu/RSX/GL/glutils/image.cpp @@ -0,0 +1,298 @@ +#include "stdafx.h" +#include "image.h" +#include "buffer_object.h" +#include "state_tracker.hpp" +#include "pixel_settings.hpp" + +namespace gl +{ + texture::texture(GLenum target, GLuint width, GLuint height, GLuint depth, GLuint mipmaps, GLenum sized_format, rsx::format_class format_class) + { + glGenTextures(1, &m_id); + + // Must bind to initialize the new texture + gl::get_command_context()->bind_texture(GL_TEMP_IMAGE_SLOT, target, m_id); + + switch (target) + { + default: + fmt::throw_exception("Invalid image target 0x%X", target); + case GL_TEXTURE_1D: + glTexStorage1D(target, mipmaps, sized_format, width); + height = depth = 1; + break; + case GL_TEXTURE_2D: + case GL_TEXTURE_CUBE_MAP: + glTexStorage2D(target, mipmaps, sized_format, width, height); + depth = 1; + break; + case GL_TEXTURE_3D: + case GL_TEXTURE_2D_ARRAY: + glTexStorage3D(target, mipmaps, sized_format, width, height, depth); + break; + case GL_TEXTURE_BUFFER: + break; + } + + if (target != GL_TEXTURE_BUFFER) + { + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_REPEAT); + glTexParameteri(target, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, mipmaps - 1); + + m_width = width; + m_height = height; + m_depth = depth; + m_mipmaps = mipmaps; + m_aspect_flags = image_aspect::color; + + switch (sized_format) + { + case GL_DEPTH_COMPONENT16: + { + m_pitch = width * 2; + m_aspect_flags = image_aspect::depth; + break; + } + case GL_DEPTH_COMPONENT32F: + { + m_pitch = width * 4; + m_aspect_flags = image_aspect::depth; + break; + } + case GL_DEPTH24_STENCIL8: + case GL_DEPTH32F_STENCIL8: + { + m_pitch = width * 4; + m_aspect_flags = image_aspect::depth | image_aspect::stencil; + break; + } + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + { + m_compressed = true; + m_pitch = utils::align(width, 4) / 2; + break; + } + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + { + m_compressed = true; + m_pitch = utils::align(width, 4); + break; + } + default: + { + GLenum query_target = (target == GL_TEXTURE_CUBE_MAP) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : target; + GLint r, g, b, a; + + glGetTexLevelParameteriv(query_target, 0, GL_TEXTURE_RED_SIZE, &r); + glGetTexLevelParameteriv(query_target, 0, GL_TEXTURE_GREEN_SIZE, &g); + glGetTexLevelParameteriv(query_target, 0, GL_TEXTURE_BLUE_SIZE, &b); + glGetTexLevelParameteriv(query_target, 0, GL_TEXTURE_ALPHA_SIZE, &a); + + m_pitch = width * (r + g + b + a) / 8; + break; + } + } + + if (!m_pitch) + { + fmt::throw_exception("Unhandled GL format 0x%X", sized_format); + } + + if (format_class == RSX_FORMAT_CLASS_UNDEFINED) + { + if (m_aspect_flags != image_aspect::color) + { + rsx_log.error("Undefined format class for depth texture is not allowed"); + } + else + { + format_class = RSX_FORMAT_CLASS_COLOR; + } + } + } + + m_target = static_cast(target); + m_internal_format = static_cast(sized_format); + m_component_layout = { GL_ALPHA, GL_RED, GL_GREEN, GL_BLUE }; + m_format_class = format_class; + } + + void texture::copy_from(const void* src, texture::format format, texture::type type, int level, const coord3u region, const pixel_unpack_settings& pixel_settings) + { + pixel_settings.apply(); + + switch (const auto target_ = static_cast(m_target)) + { + case GL_TEXTURE_1D: + { + DSA_CALL(TextureSubImage1D, m_id, GL_TEXTURE_1D, level, region.x, region.width, static_cast(format), static_cast(type), src); + break; + } + case GL_TEXTURE_2D: + { + DSA_CALL(TextureSubImage2D, m_id, GL_TEXTURE_2D, level, region.x, region.y, region.width, region.height, static_cast(format), static_cast(type), src); + break; + } + case GL_TEXTURE_3D: + case GL_TEXTURE_2D_ARRAY: + { + DSA_CALL(TextureSubImage3D, m_id, target_, level, region.x, region.y, region.z, region.width, region.height, region.depth, static_cast(format), static_cast(type), src); + break; + } + case GL_TEXTURE_CUBE_MAP: + { + if (get_driver_caps().ARB_dsa_supported) + { + glTextureSubImage3D(m_id, level, region.x, region.y, region.z, region.width, region.height, region.depth, static_cast(format), static_cast(type), src); + } + else + { + rsx_log.warning("Cubemap upload via texture::copy_from is halfplemented!"); + auto ptr = static_cast(src); + const auto end = std::min(6u, region.z + region.depth); + for (unsigned face = region.z; face < end; ++face) + { + glTextureSubImage2DEXT(m_id, GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, region.x, region.y, region.width, region.height, static_cast(format), static_cast(type), ptr); + ptr += (region.width * region.height * 4); //TODO + } + } + break; + } + } + } + + void texture::copy_from(buffer& buf, u32 gl_format_type, u32 offset, u32 length) + { + if (get_target() != target::textureBuffer) + fmt::throw_exception("OpenGL error: texture cannot copy from buffer"); + + DSA_CALL(TextureBufferRange, m_id, GL_TEXTURE_BUFFER, gl_format_type, buf.id(), offset, length); + } + + void texture::copy_from(buffer_view& view) + { + copy_from(*view.value(), view.format(), view.offset(), view.range()); + } + + void texture::copy_to(void* dst, texture::format format, texture::type type, int level, const coord3u& region, const pixel_pack_settings& pixel_settings) const + { + pixel_settings.apply(); + const auto& caps = get_driver_caps(); + + if (!region.x && !region.y && !region.z && + region.width == m_width && region.height == m_height && region.depth == m_depth) + { + if (caps.ARB_dsa_supported) + glGetTextureImage(m_id, level, static_cast(format), static_cast(type), s32{ smax }, dst); + else + glGetTextureImageEXT(m_id, static_cast(m_target), level, static_cast(format), static_cast(type), dst); + } + else if (caps.ARB_dsa_supported) + { + glGetTextureSubImage(m_id, level, region.x, region.y, region.z, region.width, region.height, region.depth, + static_cast(format), static_cast(type), s32{ smax }, dst); + } + else + { + // Worst case scenario. For some reason, EXT_dsa does not have glGetTextureSubImage + const auto target_ = static_cast(m_target); + texture tmp{ target_, region.width, region.height, region.depth, 1, static_cast(m_internal_format) }; + glCopyImageSubData(m_id, target_, level, region.x, region.y, region.z, tmp.id(), target_, 0, 0, 0, 0, + region.width, region.height, region.depth); + + const coord3u region2 = { {0, 0, 0}, region.size }; + tmp.copy_to(dst, format, type, 0, region2, pixel_settings); + } + } + + void texture_view::create(texture* data, GLenum target, GLenum sized_format, GLenum aspect_flags, const GLenum* argb_swizzle) + { + m_target = target; + m_format = sized_format; + m_image_data = data; + m_aspect_flags = aspect_flags; + + u32 num_layers; + switch (target) + { + default: + num_layers = 1; break; + case GL_TEXTURE_CUBE_MAP: + num_layers = 6; break; + case GL_TEXTURE_2D_ARRAY: + num_layers = data->depth(); break; + } + + glGenTextures(1, &m_id); + glTextureView(m_id, target, data->id(), sized_format, 0, data->levels(), 0, num_layers); + + if (argb_swizzle) + { + component_swizzle[0] = argb_swizzle[1]; + component_swizzle[1] = argb_swizzle[2]; + component_swizzle[2] = argb_swizzle[3]; + component_swizzle[3] = argb_swizzle[0]; + + gl::get_command_context()->bind_texture(GL_TEMP_IMAGE_SLOT, m_target, m_id); + glTexParameteriv(m_target, GL_TEXTURE_SWIZZLE_RGBA, reinterpret_cast(component_swizzle)); + } + else + { + component_swizzle[0] = GL_RED; + component_swizzle[1] = GL_GREEN; + component_swizzle[2] = GL_BLUE; + component_swizzle[3] = GL_ALPHA; + } + + if (aspect_flags & image_aspect::stencil) + { + constexpr u32 depth_stencil_mask = (image_aspect::depth | image_aspect::stencil); + ensure((aspect_flags & depth_stencil_mask) != depth_stencil_mask); // "Invalid aspect mask combination" + + gl::get_command_context()->bind_texture(GL_TEMP_IMAGE_SLOT, m_target, m_id); + glTexParameteri(m_target, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX); + } + } + + void texture_view::bind(gl::command_context& cmd, GLuint layer) const + { + cmd->bind_texture(layer, m_target, m_id); + } + + texture_view* viewable_image::get_view(u32 remap_encoding, const std::pair, std::array>& remap, GLenum aspect_flags) + { + auto found = views.equal_range(remap_encoding); + for (auto It = found.first; It != found.second; ++It) + { + if (It->second->aspect() & aspect_flags) + { + return It->second.get(); + } + } + + ensure(aspect() & aspect_flags); + auto mapping = apply_swizzle_remap(get_native_component_layout(), remap); + auto view = std::make_unique(this, mapping.data(), aspect_flags); + auto result = view.get(); + views.emplace(remap_encoding, std::move(view)); + return result; + } + + void viewable_image::set_native_component_layout(const std::array& layout) + { + if (m_component_layout[0] != layout[0] || + m_component_layout[1] != layout[1] || + m_component_layout[2] != layout[2] || + m_component_layout[3] != layout[3]) + { + texture::set_native_component_layout(layout); + views.clear(); + } + } +} \ No newline at end of file diff --git a/rpcs3/Emu/RSX/GL/glutils/image.h b/rpcs3/Emu/RSX/GL/glutils/image.h new file mode 100644 index 0000000000..63dff29506 --- /dev/null +++ b/rpcs3/Emu/RSX/GL/glutils/image.h @@ -0,0 +1,393 @@ +#pragma once + +#include "common.h" + +#include "Utilities/geometry.h" +#include "Emu/RSX/Common/TextureUtils.h" + +//using enum rsx::format_class; +using namespace ::rsx::format_class_; + +namespace gl +{ + class buffer; + class buffer_view; + class command_context; + class pixel_pack_settings; + class pixel_unpack_settings; + + enum image_aspect : u32 + { + color = 1, + depth = 2, + stencil = 4 + }; + + class texture + { + friend class texture_view; + + public: + enum class type + { + ubyte = GL_UNSIGNED_BYTE, + ushort = GL_UNSIGNED_SHORT, + uint = GL_UNSIGNED_INT, + + ubyte_3_3_2 = GL_UNSIGNED_BYTE_3_3_2, + ubyte_2_3_3_rev = GL_UNSIGNED_BYTE_2_3_3_REV, + + ushort_5_6_5 = GL_UNSIGNED_SHORT_5_6_5, + ushort_5_6_5_rev = GL_UNSIGNED_SHORT_5_6_5_REV, + ushort_4_4_4_4 = GL_UNSIGNED_SHORT_4_4_4_4, + ushort_4_4_4_4_rev = GL_UNSIGNED_SHORT_4_4_4_4_REV, + ushort_5_5_5_1 = GL_UNSIGNED_SHORT_5_5_5_1, + ushort_1_5_5_5_rev = GL_UNSIGNED_SHORT_1_5_5_5_REV, + + uint_8_8_8_8 = GL_UNSIGNED_INT_8_8_8_8, + uint_8_8_8_8_rev = GL_UNSIGNED_INT_8_8_8_8_REV, + uint_10_10_10_2 = GL_UNSIGNED_INT_10_10_10_2, + uint_2_10_10_10_rev = GL_UNSIGNED_INT_2_10_10_10_REV, + uint_24_8 = GL_UNSIGNED_INT_24_8, + float32_uint8 = GL_FLOAT_32_UNSIGNED_INT_24_8_REV, + + sbyte = GL_BYTE, + sshort = GL_SHORT, + sint = GL_INT, + f16 = GL_HALF_FLOAT, + f32 = GL_FLOAT, + f64 = GL_DOUBLE, + }; + + enum class channel + { + zero = GL_ZERO, + one = GL_ONE, + r = GL_RED, + g = GL_GREEN, + b = GL_BLUE, + a = GL_ALPHA, + }; + + enum class format + { + r = GL_RED, + rg = GL_RG, + rgb = GL_RGB, + rgba = GL_RGBA, + + bgr = GL_BGR, + bgra = GL_BGRA, + + stencil = GL_STENCIL_INDEX, + depth = GL_DEPTH_COMPONENT, + depth_stencil = GL_DEPTH_STENCIL + }; + + enum class internal_format + { + stencil8 = GL_STENCIL_INDEX8, + depth16 = GL_DEPTH_COMPONENT16, + depth32f = GL_DEPTH_COMPONENT32F, + depth24_stencil8 = GL_DEPTH24_STENCIL8, + depth32f_stencil8 = GL_DEPTH32F_STENCIL8, + + compressed_rgb_s3tc_dxt1 = GL_COMPRESSED_RGB_S3TC_DXT1_EXT, + compressed_rgba_s3tc_dxt1 = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, + compressed_rgba_s3tc_dxt3 = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, + compressed_rgba_s3tc_dxt5 = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, + + //Sized internal formats, see opengl spec document on glTexImage2D, table 3 + rgba8 = GL_RGBA8, + rgb565 = GL_RGB565, + rgb5a1 = GL_RGB5_A1, + rgba4 = GL_RGBA4, + r8 = GL_R8, + r16 = GL_R16, + r32f = GL_R32F, + rg8 = GL_RG8, + rg16 = GL_RG16, + rg16f = GL_RG16F, + rgba16f = GL_RGBA16F, + rgba32f = GL_RGBA32F + }; + + enum class wrap + { + repeat = GL_REPEAT, + mirrored_repeat = GL_MIRRORED_REPEAT, + clamp_to_edge = GL_CLAMP_TO_EDGE, + clamp_to_border = GL_CLAMP_TO_BORDER, + mirror_clamp = GL_MIRROR_CLAMP_EXT, + //mirror_clamp_to_edge = GL_MIRROR_CLAMP_TO_EDGE, + mirror_clamp_to_border = GL_MIRROR_CLAMP_TO_BORDER_EXT + }; + + enum class compare_mode + { + none = GL_NONE, + ref_to_texture = GL_COMPARE_REF_TO_TEXTURE + }; + + enum class target + { + texture1D = GL_TEXTURE_1D, + texture2D = GL_TEXTURE_2D, + texture3D = GL_TEXTURE_3D, + textureCUBE = GL_TEXTURE_CUBE_MAP, + textureBuffer = GL_TEXTURE_BUFFER + }; + + protected: + GLuint m_id = GL_NONE; + GLuint m_width = 0; + GLuint m_height = 0; + GLuint m_depth = 0; + GLuint m_mipmaps = 0; + GLuint m_pitch = 0; + GLuint m_compressed = GL_FALSE; + GLuint m_aspect_flags = 0; + + target m_target = target::texture2D; + internal_format m_internal_format = internal_format::rgba8; + std::array m_component_layout; + + rsx::format_class m_format_class = RSX_FORMAT_CLASS_UNDEFINED; + + public: + texture(const texture&) = delete; + texture(texture&& texture_) = delete; + + texture(GLenum target, GLuint width, GLuint height, GLuint depth, GLuint mipmaps, GLenum sized_format, rsx::format_class format_class = rsx::RSX_FORMAT_CLASS_UNDEFINED); + + virtual ~texture() + { + glDeleteTextures(1, &m_id); + m_id = GL_NONE; + } + + // Getters/setters + void set_native_component_layout(const std::array& layout) + { + m_component_layout[0] = layout[0]; + m_component_layout[1] = layout[1]; + m_component_layout[2] = layout[2]; + m_component_layout[3] = layout[3]; + } + + target get_target() const noexcept + { + return m_target; + } + + static bool compressed_format(internal_format format_) noexcept + { + switch (format_) + { + case internal_format::compressed_rgb_s3tc_dxt1: + case internal_format::compressed_rgba_s3tc_dxt1: + case internal_format::compressed_rgba_s3tc_dxt3: + case internal_format::compressed_rgba_s3tc_dxt5: + return true; + default: + return false; + } + } + + uint id() const noexcept + { + return m_id; + } + + explicit operator bool() const noexcept + { + return (m_id != GL_NONE); + } + + GLuint width() const + { + return m_width; + } + + GLuint height() const + { + return m_height; + } + + GLuint depth() const + { + return m_depth; + } + + GLuint levels() const + { + return m_mipmaps; + } + + GLuint pitch() const + { + return m_pitch; + } + + constexpr GLubyte samples() const + { + return 1; + } + + GLboolean compressed() const + { + return m_compressed; + } + + GLuint aspect() const + { + return m_aspect_flags; + } + + rsx::format_class format_class() const + { + return m_format_class; + } + + sizeu size2D() const + { + return{ m_width, m_height }; + } + + size3u size3D() const + { + const auto depth = (m_target == target::textureCUBE) ? 6 : m_depth; + return{ m_width, m_height, depth }; + } + + texture::internal_format get_internal_format() const + { + return m_internal_format; + } + + std::array get_native_component_layout() const + { + return m_component_layout; + } + + // Data management + void copy_from(const void* src, texture::format format, texture::type type, int level, const coord3u region, const pixel_unpack_settings& pixel_settings); + + void copy_from(buffer& buf, u32 gl_format_type, u32 offset, u32 length); + + void copy_from(buffer_view& view); + + void copy_to(void* dst, texture::format format, texture::type type, int level, const coord3u& region, const pixel_pack_settings& pixel_settings) const; + + // Convenience wrappers + void copy_from(const void* src, texture::format format, texture::type type, const pixel_unpack_settings& pixel_settings) + { + const coord3u region = { {}, size3D() }; + copy_from(src, format, type, 0, region, pixel_settings); + } + + void copy_to(void* dst, texture::format format, texture::type type, const pixel_pack_settings& pixel_settings) const + { + const coord3u region = { {}, size3D() }; + copy_to(dst, format, type, 0, region, pixel_settings); + } + }; + + class texture_view + { + GLuint m_id = GL_NONE; + GLenum m_target = 0; + GLenum m_format = 0; + GLenum m_aspect_flags = 0; + texture* m_image_data = nullptr; + + GLenum component_swizzle[4]; + + void create(texture* data, GLenum target, GLenum sized_format, GLenum aspect_flags, const GLenum* argb_swizzle = nullptr); + + public: + texture_view(const texture_view&) = delete; + texture_view(texture_view&&) = delete; + + texture_view(texture* data, GLenum target, GLenum sized_format, + const GLenum* argb_swizzle = nullptr, + GLenum aspect_flags = image_aspect::color | image_aspect::depth) + { + create(data, target, sized_format, aspect_flags, argb_swizzle); + } + + texture_view(texture* data, 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, aspect_flags, argb_swizzle); + } + + virtual ~texture_view() + { + glDeleteTextures(1, &m_id); + m_id = GL_NONE; + } + + GLuint id() const + { + return m_id; + } + + GLenum target() const + { + return m_target; + } + + GLenum internal_format() const + { + return m_format; + } + + GLenum aspect() const + { + return m_aspect_flags; + } + + bool compare_swizzle(const GLenum* argb_swizzle) const + { + return (argb_swizzle[0] == component_swizzle[3] && + argb_swizzle[1] == component_swizzle[0] && + argb_swizzle[2] == component_swizzle[1] && + argb_swizzle[3] == component_swizzle[2]); + } + + texture* image() const + { + return m_image_data; + } + + std::array component_mapping() const + { + return{ component_swizzle[3], component_swizzle[0], component_swizzle[1], component_swizzle[2] }; + } + + u32 encoded_component_map() const + { + // Unused, OGL supports proper component swizzles + return 0u; + } + + void bind(gl::command_context& cmd, GLuint layer) const; + }; + + class viewable_image : public texture + { + std::unordered_multimap> views; + + public: + using texture::texture; + + texture_view* get_view(u32 remap_encoding, const std::pair, std::array>& remap, GLenum aspect_flags = image_aspect::color | image_aspect::depth); + void set_native_component_layout(const std::array& layout); + }; + + // Texture helpers + std::array apply_swizzle_remap(const std::array& swizzle_remap, const std::pair, std::array>& decoded_remap); +} diff --git a/rpcs3/Emu/RSX/GL/glutils/pixel_settings.hpp b/rpcs3/Emu/RSX/GL/glutils/pixel_settings.hpp new file mode 100644 index 0000000000..475b5f3b8e --- /dev/null +++ b/rpcs3/Emu/RSX/GL/glutils/pixel_settings.hpp @@ -0,0 +1,157 @@ +#pragma once + +#include "common.h" + +namespace gl +{ + class pixel_pack_settings + { + bool m_swap_bytes = false; + bool m_lsb_first = false; + int m_row_length = 0; + int m_image_height = 0; + int m_skip_rows = 0; + int m_skip_pixels = 0; + int m_skip_images = 0; + int m_alignment = 4; + + public: + void apply() const + { + glPixelStorei(GL_PACK_SWAP_BYTES, m_swap_bytes ? GL_TRUE : GL_FALSE); + glPixelStorei(GL_PACK_LSB_FIRST, m_lsb_first ? GL_TRUE : GL_FALSE); + glPixelStorei(GL_PACK_ROW_LENGTH, m_row_length); + glPixelStorei(GL_PACK_IMAGE_HEIGHT, m_image_height); + glPixelStorei(GL_PACK_SKIP_ROWS, m_skip_rows); + glPixelStorei(GL_PACK_SKIP_PIXELS, m_skip_pixels); + glPixelStorei(GL_PACK_SKIP_IMAGES, m_skip_images); + glPixelStorei(GL_PACK_ALIGNMENT, m_alignment); + } + + pixel_pack_settings& swap_bytes(bool value = true) + { + m_swap_bytes = value; + return *this; + } + pixel_pack_settings& lsb_first(bool value = true) + { + m_lsb_first = value; + return *this; + } + pixel_pack_settings& row_length(int value) + { + m_row_length = value; + return *this; + } + pixel_pack_settings& image_height(int value) + { + m_image_height = value; + return *this; + } + pixel_pack_settings& skip_rows(int value) + { + m_skip_rows = value; + return *this; + } + pixel_pack_settings& skip_pixels(int value) + { + m_skip_pixels = value; + return *this; + } + pixel_pack_settings& skip_images(int value) + { + m_skip_images = value; + return *this; + } + pixel_pack_settings& alignment(int value) + { + m_alignment = value; + return *this; + } + + bool get_swap_bytes() const + { + return m_swap_bytes; + } + int get_row_length() const + { + return m_row_length; + } + }; + + class pixel_unpack_settings + { + bool m_swap_bytes = false; + bool m_lsb_first = false; + int m_row_length = 0; + int m_image_height = 0; + int m_skip_rows = 0; + int m_skip_pixels = 0; + int m_skip_images = 0; + int m_alignment = 4; + + public: + void apply() const + { + glPixelStorei(GL_UNPACK_SWAP_BYTES, m_swap_bytes ? GL_TRUE : GL_FALSE); + glPixelStorei(GL_UNPACK_LSB_FIRST, m_lsb_first ? GL_TRUE : GL_FALSE); + glPixelStorei(GL_UNPACK_ROW_LENGTH, m_row_length); + glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, m_image_height); + glPixelStorei(GL_UNPACK_SKIP_ROWS, m_skip_rows); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, m_skip_pixels); + glPixelStorei(GL_UNPACK_SKIP_IMAGES, m_skip_images); + glPixelStorei(GL_UNPACK_ALIGNMENT, m_alignment); + } + + pixel_unpack_settings& swap_bytes(bool value = true) + { + m_swap_bytes = value; + return *this; + } + pixel_unpack_settings& lsb_first(bool value = true) + { + m_lsb_first = value; + return *this; + } + pixel_unpack_settings& row_length(int value) + { + m_row_length = value; + return *this; + } + pixel_unpack_settings& image_height(int value) + { + m_image_height = value; + return *this; + } + pixel_unpack_settings& skip_rows(int value) + { + m_skip_rows = value; + return *this; + } + pixel_unpack_settings& skip_pixels(int value) + { + m_skip_pixels = value; + return *this; + } + pixel_unpack_settings& skip_images(int value) + { + m_skip_images = value; + return *this; + } + pixel_unpack_settings& alignment(int value) + { + m_alignment = value; + return *this; + } + + bool get_swap_bytes() const + { + return m_swap_bytes; + } + + int get_row_length() const + { + return m_row_length; + } + }; +} diff --git a/rpcs3/Emu/RSX/GL/GLExecutionState.h b/rpcs3/Emu/RSX/GL/glutils/state_tracker.hpp similarity index 90% rename from rpcs3/Emu/RSX/GL/GLExecutionState.h rename to rpcs3/Emu/RSX/GL/glutils/state_tracker.hpp index 1259dd42ca..6f2c584d24 100644 --- a/rpcs3/Emu/RSX/GL/GLExecutionState.h +++ b/rpcs3/Emu/RSX/GL/glutils/state_tracker.hpp @@ -1,322 +1,329 @@ -#pragma once - -#include "glutils/capabilities.hpp" - -#include "Utilities/geometry.h" -#include - -namespace gl -{ - struct driver_state - { - const u32 DEPTH_BOUNDS_MIN = 0xFFFF0001; - const u32 DEPTH_BOUNDS_MAX = 0xFFFF0002; - const u32 DEPTH_RANGE_MIN = 0xFFFF0003; - const u32 DEPTH_RANGE_MAX = 0xFFFF0004; - - std::unordered_map properties = {}; - std::unordered_map> indexed_properties = {}; - - GLuint current_program = GL_NONE; - std::array, 48> bound_textures{ {} }; - - bool enable(u32 test, GLenum cap) - { - auto found = properties.find(cap); - if (found != properties.end() && found->second == test) - return !!test; - - properties[cap] = test; - - if (test) - glEnable(cap); - else - glDisable(cap); - - return !!test; - } - - bool enablei(u32 test, GLenum cap, u32 index) - { - auto found = indexed_properties.find(cap); - const bool exists = found != indexed_properties.end(); - - if (!exists) - { - indexed_properties[cap] = {}; - indexed_properties[cap][index] = test; - } - else - { - if (found->second[index] == test) - return !!test; - - found->second[index] = test; - } - - if (test) - glEnablei(cap, index); - else - glDisablei(cap, index); - - return !!test; - } - - bool enable(GLenum cap) - { - return enable(GL_TRUE, cap); - } - - bool enablei(GLenum cap, u32 index) - { - return enablei(GL_TRUE, cap, index); - } - - bool disable(GLenum cap) - { - return enable(GL_FALSE, cap); - } - - bool disablei(GLenum cap, u32 index) - { - return enablei(GL_FALSE, cap, index); - } - - inline bool test_property(GLenum property, u32 test) const - { - auto found = properties.find(property); - if (found == properties.end()) - return false; - - return (found->second == test); - } - - inline bool test_propertyi(GLenum property, u32 test, GLint index) const - { - auto found = indexed_properties.find(property); - if (found == indexed_properties.end()) - return false; - - return found->second[index] == test; - } - - void depth_func(GLenum func) - { - if (!test_property(GL_DEPTH_FUNC, func)) - { - glDepthFunc(func); - properties[GL_DEPTH_FUNC] = func; - } - } - - void depth_mask(GLboolean mask) - { - if (!test_property(GL_DEPTH_WRITEMASK, mask)) - { - glDepthMask(mask); - properties[GL_DEPTH_WRITEMASK] = mask; - } - } - - void clear_depth(GLfloat depth) - { - u32 value = std::bit_cast(depth); - if (!test_property(GL_DEPTH_CLEAR_VALUE, value)) - { - glClearDepth(depth); - properties[GL_DEPTH_CLEAR_VALUE] = value; - } - } - - void stencil_mask(GLuint mask) - { - if (!test_property(GL_STENCIL_WRITEMASK, mask)) - { - glStencilMask(mask); - properties[GL_STENCIL_WRITEMASK] = mask; - } - } - - void clear_stencil(GLint stencil) - { - u32 value = std::bit_cast(stencil); - if (!test_property(GL_STENCIL_CLEAR_VALUE, value)) - { - glClearStencil(stencil); - properties[GL_STENCIL_CLEAR_VALUE] = value; - } - } - - void color_maski(GLint index, u32 mask) - { - if (!test_propertyi(GL_COLOR_WRITEMASK, mask, index)) - { - glColorMaski(index, ((mask & 0x10) ? 1 : 0), ((mask & 0x20) ? 1 : 0), ((mask & 0x40) ? 1 : 0), ((mask & 0x80) ? 1 : 0)); - indexed_properties[GL_COLOR_WRITEMASK][index] = mask; - } - } - - void color_maski(GLint index, bool r, bool g, bool b, bool a) - { - u32 mask = 0; - if (r) mask |= 0x10; - if (g) mask |= 0x20; - if (b) mask |= 0x40; - if (a) mask |= 0x80; - - color_maski(index, mask); - } - - void clear_color(u8 r, u8 g, u8 b, u8 a) - { - u32 value = u32{r} | u32{g} << 8 | u32{b} << 16 | u32{a} << 24; - if (!test_property(GL_COLOR_CLEAR_VALUE, value)) - { - glClearColor(r / 255.f, g / 255.f, b / 255.f, a / 255.f); - properties[GL_COLOR_CLEAR_VALUE] = value; - } - } - - void clear_color(const color4f& color) - { - clear_color(static_cast(color.r * 255), static_cast(color.g * 255), static_cast(color.b * 255), static_cast(color.a * 255)); - } - - void depth_bounds(float min, float max) - { - u32 depth_min = std::bit_cast(min); - u32 depth_max = std::bit_cast(max); - - if (!test_property(DEPTH_BOUNDS_MIN, depth_min) || !test_property(DEPTH_BOUNDS_MAX, depth_max)) - { - if (get_driver_caps().NV_depth_buffer_float_supported) - { - glDepthBoundsdNV(min, max); - } - else - { - glDepthBoundsEXT(min, max); - } - - properties[DEPTH_BOUNDS_MIN] = depth_min; - properties[DEPTH_BOUNDS_MAX] = depth_max; - } - } - - void depth_range(float min, float max) - { - u32 depth_min = std::bit_cast(min); - u32 depth_max = std::bit_cast(max); - - if (!test_property(DEPTH_RANGE_MIN, depth_min) || !test_property(DEPTH_RANGE_MAX, depth_max)) - { - if (get_driver_caps().NV_depth_buffer_float_supported) - { - glDepthRangedNV(min, max); - } - else - { - glDepthRange(min, max); - } - - properties[DEPTH_RANGE_MIN] = depth_min; - properties[DEPTH_RANGE_MAX] = depth_max; - } - } - - void logic_op(GLenum op) - { - if (!test_property(GL_COLOR_LOGIC_OP, op)) - { - glLogicOp(op); - properties[GL_COLOR_LOGIC_OP] = op; - } - } - - void line_width(GLfloat width) - { - u32 value = std::bit_cast(width); - - if (!test_property(GL_LINE_WIDTH, value)) - { - glLineWidth(width); - properties[GL_LINE_WIDTH] = value; - } - } - - void front_face(GLenum face) - { - if (!test_property(GL_FRONT_FACE, face)) - { - glFrontFace(face); - properties[GL_FRONT_FACE] = face; - } - } - - void cull_face(GLenum mode) - { - if (!test_property(GL_CULL_FACE_MODE, mode)) - { - glCullFace(mode); - properties[GL_CULL_FACE_MODE] = mode; - } - } - - void polygon_offset(float factor, float units) - { - u32 _units = std::bit_cast(units); - u32 _factor = std::bit_cast(factor); - - if (!test_property(GL_POLYGON_OFFSET_UNITS, _units) || !test_property(GL_POLYGON_OFFSET_FACTOR, _factor)) - { - glPolygonOffset(factor, units); - - properties[GL_POLYGON_OFFSET_UNITS] = _units; - properties[GL_POLYGON_OFFSET_FACTOR] = _factor; - } - } - - void use_program(GLuint program) - { - if (current_program == program) - { - return; - } - - current_program = program; - glUseProgram(program); - } - - void bind_texture(GLuint layer, GLenum target, GLuint name) - { - ensure(layer < 48); - - auto& bound = bound_textures[layer][target]; - if (bound != name) - { - glActiveTexture(GL_TEXTURE0 + layer); - glBindTexture(target, name); - - bound = name; - } - } - }; - - class command_context - { - driver_state* drv; - - public: - command_context() - : drv(nullptr) - {} - - command_context(driver_state& drv_) - : drv(&drv_) - {} - - driver_state* operator -> () { - return drv; - } - }; -} \ No newline at end of file +#pragma once + +#include "capabilities.hpp" + +#include "Utilities/geometry.h" +#include + +namespace gl +{ + struct driver_state + { + const u32 DEPTH_BOUNDS_MIN = 0xFFFF0001; + const u32 DEPTH_BOUNDS_MAX = 0xFFFF0002; + const u32 DEPTH_RANGE_MIN = 0xFFFF0003; + const u32 DEPTH_RANGE_MAX = 0xFFFF0004; + + std::unordered_map properties = {}; + std::unordered_map> indexed_properties = {}; + + GLuint current_program = GL_NONE; + std::array, 48> bound_textures{ {} }; + + bool enable(u32 test, GLenum cap) + { + auto found = properties.find(cap); + if (found != properties.end() && found->second == test) + return !!test; + + properties[cap] = test; + + if (test) + glEnable(cap); + else + glDisable(cap); + + return !!test; + } + + bool enablei(u32 test, GLenum cap, u32 index) + { + auto found = indexed_properties.find(cap); + const bool exists = found != indexed_properties.end(); + + if (!exists) + { + indexed_properties[cap] = {}; + indexed_properties[cap][index] = test; + } + else + { + if (found->second[index] == test) + return !!test; + + found->second[index] = test; + } + + if (test) + glEnablei(cap, index); + else + glDisablei(cap, index); + + return !!test; + } + + bool enable(GLenum cap) + { + return enable(GL_TRUE, cap); + } + + bool enablei(GLenum cap, u32 index) + { + return enablei(GL_TRUE, cap, index); + } + + bool disable(GLenum cap) + { + return enable(GL_FALSE, cap); + } + + bool disablei(GLenum cap, u32 index) + { + return enablei(GL_FALSE, cap, index); + } + + inline bool test_property(GLenum property, u32 test) const + { + auto found = properties.find(property); + if (found == properties.end()) + return false; + + return (found->second == test); + } + + inline bool test_propertyi(GLenum property, u32 test, GLint index) const + { + auto found = indexed_properties.find(property); + if (found == indexed_properties.end()) + return false; + + return found->second[index] == test; + } + + void depth_func(GLenum func) + { + if (!test_property(GL_DEPTH_FUNC, func)) + { + glDepthFunc(func); + properties[GL_DEPTH_FUNC] = func; + } + } + + void depth_mask(GLboolean mask) + { + if (!test_property(GL_DEPTH_WRITEMASK, mask)) + { + glDepthMask(mask); + properties[GL_DEPTH_WRITEMASK] = mask; + } + } + + void clear_depth(GLfloat depth) + { + u32 value = std::bit_cast(depth); + if (!test_property(GL_DEPTH_CLEAR_VALUE, value)) + { + glClearDepth(depth); + properties[GL_DEPTH_CLEAR_VALUE] = value; + } + } + + void stencil_mask(GLuint mask) + { + if (!test_property(GL_STENCIL_WRITEMASK, mask)) + { + glStencilMask(mask); + properties[GL_STENCIL_WRITEMASK] = mask; + } + } + + void clear_stencil(GLint stencil) + { + u32 value = std::bit_cast(stencil); + if (!test_property(GL_STENCIL_CLEAR_VALUE, value)) + { + glClearStencil(stencil); + properties[GL_STENCIL_CLEAR_VALUE] = value; + } + } + + void color_maski(GLint index, u32 mask) + { + if (!test_propertyi(GL_COLOR_WRITEMASK, mask, index)) + { + glColorMaski(index, ((mask & 0x10) ? 1 : 0), ((mask & 0x20) ? 1 : 0), ((mask & 0x40) ? 1 : 0), ((mask & 0x80) ? 1 : 0)); + indexed_properties[GL_COLOR_WRITEMASK][index] = mask; + } + } + + void color_maski(GLint index, bool r, bool g, bool b, bool a) + { + u32 mask = 0; + if (r) mask |= 0x10; + if (g) mask |= 0x20; + if (b) mask |= 0x40; + if (a) mask |= 0x80; + + color_maski(index, mask); + } + + void clear_color(u8 r, u8 g, u8 b, u8 a) + { + u32 value = u32{ r } | u32{ g } << 8 | u32{ b } << 16 | u32{ a } << 24; + if (!test_property(GL_COLOR_CLEAR_VALUE, value)) + { + glClearColor(r / 255.f, g / 255.f, b / 255.f, a / 255.f); + properties[GL_COLOR_CLEAR_VALUE] = value; + } + } + + void clear_color(const color4f& color) + { + clear_color(static_cast(color.r * 255), static_cast(color.g * 255), static_cast(color.b * 255), static_cast(color.a * 255)); + } + + void depth_bounds(float min, float max) + { + u32 depth_min = std::bit_cast(min); + u32 depth_max = std::bit_cast(max); + + if (!test_property(DEPTH_BOUNDS_MIN, depth_min) || !test_property(DEPTH_BOUNDS_MAX, depth_max)) + { + if (get_driver_caps().NV_depth_buffer_float_supported) + { + glDepthBoundsdNV(min, max); + } + else + { + glDepthBoundsEXT(min, max); + } + + properties[DEPTH_BOUNDS_MIN] = depth_min; + properties[DEPTH_BOUNDS_MAX] = depth_max; + } + } + + void depth_range(float min, float max) + { + u32 depth_min = std::bit_cast(min); + u32 depth_max = std::bit_cast(max); + + if (!test_property(DEPTH_RANGE_MIN, depth_min) || !test_property(DEPTH_RANGE_MAX, depth_max)) + { + if (get_driver_caps().NV_depth_buffer_float_supported) + { + glDepthRangedNV(min, max); + } + else + { + glDepthRange(min, max); + } + + properties[DEPTH_RANGE_MIN] = depth_min; + properties[DEPTH_RANGE_MAX] = depth_max; + } + } + + void logic_op(GLenum op) + { + if (!test_property(GL_COLOR_LOGIC_OP, op)) + { + glLogicOp(op); + properties[GL_COLOR_LOGIC_OP] = op; + } + } + + void line_width(GLfloat width) + { + u32 value = std::bit_cast(width); + + if (!test_property(GL_LINE_WIDTH, value)) + { + glLineWidth(width); + properties[GL_LINE_WIDTH] = value; + } + } + + void front_face(GLenum face) + { + if (!test_property(GL_FRONT_FACE, face)) + { + glFrontFace(face); + properties[GL_FRONT_FACE] = face; + } + } + + void cull_face(GLenum mode) + { + if (!test_property(GL_CULL_FACE_MODE, mode)) + { + glCullFace(mode); + properties[GL_CULL_FACE_MODE] = mode; + } + } + + void polygon_offset(float factor, float units) + { + u32 _units = std::bit_cast(units); + u32 _factor = std::bit_cast(factor); + + if (!test_property(GL_POLYGON_OFFSET_UNITS, _units) || !test_property(GL_POLYGON_OFFSET_FACTOR, _factor)) + { + glPolygonOffset(factor, units); + + properties[GL_POLYGON_OFFSET_UNITS] = _units; + properties[GL_POLYGON_OFFSET_FACTOR] = _factor; + } + } + + void use_program(GLuint program) + { + if (current_program == program) + { + return; + } + + current_program = program; + glUseProgram(program); + } + + void bind_texture(GLuint layer, GLenum target, GLuint name) + { + ensure(layer < 48); + + auto& bound = bound_textures[layer][target]; + if (bound != name) + { + glActiveTexture(GL_TEXTURE0 + layer); + glBindTexture(target, name); + + bound = name; + } + } + }; + + class command_context + { + driver_state* drv; + + public: + command_context() + : drv(nullptr) + {} + + command_context(driver_state& drv_) + : drv(&drv_) + {} + + driver_state* operator -> () { + return drv; + } + }; + + void set_command_context(gl::command_context& ctx); + void set_command_context(gl::driver_state& ctx); + gl::command_context get_command_context(); + + void set_primary_context_thread(bool = true); + bool is_primary_context_thread(); +} diff --git a/rpcs3/GLGSRender.vcxproj b/rpcs3/GLGSRender.vcxproj index d2c43837dd..beb9ff1187 100644 --- a/rpcs3/GLGSRender.vcxproj +++ b/rpcs3/GLGSRender.vcxproj @@ -52,7 +52,6 @@ - @@ -64,7 +63,10 @@ + + + @@ -82,7 +84,9 @@ + + diff --git a/rpcs3/GLGSRender.vcxproj.filters b/rpcs3/GLGSRender.vcxproj.filters index 07be953468..322a5839d0 100644 --- a/rpcs3/GLGSRender.vcxproj.filters +++ b/rpcs3/GLGSRender.vcxproj.filters @@ -23,6 +23,12 @@ glutils + + glutils + + + glutils + @@ -39,7 +45,6 @@ - @@ -54,6 +59,15 @@ glutils + + glutils + + + glutils + + + glutils +