diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 10d1a3cb3c..6a71895c7f 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -397,6 +397,7 @@ void GLGSRender::end() std::chrono::time_point textures_start = steady_clock::now(); //Setup textures + //Setting unused texture to 0 is not needed, but makes program validation happy if we choose to enforce it for (int i = 0; i < rsx::limits::fragment_textures_count; ++i) { int location; @@ -411,6 +412,7 @@ void GLGSRender::end() { m_gl_textures[i].set_target(get_gl_target_for_texture(rsx::method_registers.fragment_textures[i])); __glcheck m_gl_texture_cache.upload_texture(i, rsx::method_registers.fragment_textures[i], m_gl_textures[i], m_rtts); + __glcheck m_gl_sampler_states[i].apply(rsx::method_registers.fragment_textures[i]); } } @@ -561,6 +563,12 @@ void GLGSRender::on_init_thread() if (g_cfg_rsx_overlay) m_text_printer.init(); + for (int i = 0; i < rsx::limits::fragment_textures_count; ++i) + { + m_gl_sampler_states[i].create(); + m_gl_sampler_states[i].bind(i); + } + m_gl_texture_cache.initialize(this); } @@ -595,6 +603,11 @@ void GLGSRender::on_exit() tex.remove(); } + for (auto &sampler : m_gl_sampler_states) + { + sampler.remove(); + } + m_attrib_ring_buffer->remove(); m_transform_constants_buffer->remove(); m_fragment_constants_buffer->remove(); diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.h b/rpcs3/Emu/RSX/GL/GLGSRender.h index 60d01b2c15..3adbc78671 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.h +++ b/rpcs3/Emu/RSX/GL/GLGSRender.h @@ -58,6 +58,7 @@ private: rsx::gl::texture m_gl_textures[rsx::limits::fragment_textures_count]; rsx::gl::texture m_gl_vertex_textures[rsx::limits::vertex_textures_count]; + gl::sampler_state m_gl_sampler_states[rsx::limits::fragment_textures_count]; gl::glsl::program *m_program; diff --git a/rpcs3/Emu/RSX/GL/GLProcTable.h b/rpcs3/Emu/RSX/GL/GLProcTable.h index 3c55e3fca9..5d03d216cf 100644 --- a/rpcs3/Emu/RSX/GL/GLProcTable.h +++ b/rpcs3/Emu/RSX/GL/GLProcTable.h @@ -172,6 +172,13 @@ OPENGL_PROC(PFNGLMULTIDRAWARRAYSPROC, MultiDrawArrays); OPENGL_PROC(PFNGLGETTEXTUREIMAGEEXTPROC, GetTextureImageEXT); +//Sampler Objects +OPENGL_PROC(PFNGLGENSAMPLERSPROC, GenSamplers); +OPENGL_PROC(PFNGLDELETESAMPLERSPROC, DeleteSamplers); +OPENGL_PROC(PFNGLBINDSAMPLERPROC, BindSampler); +OPENGL_PROC(PFNGLSAMPLERPARAMETERIPROC, SamplerParameteri); +OPENGL_PROC(PFNGLSAMPLERPARAMETERFVPROC, SamplerParameterfv); + //Texture Buffers OPENGL_PROC(PFNGLTEXBUFFERPROC, TexBuffer); OPENGL_PROC(PFNGLTEXTUREBUFFERRANGEEXTPROC, TextureBufferRangeEXT); diff --git a/rpcs3/Emu/RSX/GL/GLTexture.cpp b/rpcs3/Emu/RSX/GL/GLTexture.cpp index 809c9dd3e7..ce269a5c8c 100644 --- a/rpcs3/Emu/RSX/GL/GLTexture.cpp +++ b/rpcs3/Emu/RSX/GL/GLTexture.cpp @@ -67,6 +67,54 @@ namespace gl } fmt::throw_exception("Compressed or unknown texture format 0x%x" HERE, texture_format); } + + GLenum wrap_mode(rsx::texture_wrap_mode wrap) + { + switch (wrap) + { + case rsx::texture_wrap_mode::wrap: return GL_REPEAT; + case rsx::texture_wrap_mode::mirror: return GL_MIRRORED_REPEAT; + case rsx::texture_wrap_mode::clamp_to_edge: return GL_CLAMP_TO_EDGE; + case rsx::texture_wrap_mode::border: return GL_CLAMP_TO_BORDER; + case rsx::texture_wrap_mode::clamp: return GL_CLAMP_TO_BORDER; + case rsx::texture_wrap_mode::mirror_once_clamp_to_edge: return GL_MIRROR_CLAMP_TO_EDGE_EXT; + case rsx::texture_wrap_mode::mirror_once_border: return GL_MIRROR_CLAMP_TO_BORDER_EXT; + case rsx::texture_wrap_mode::mirror_once_clamp: return GL_MIRROR_CLAMP_EXT; + } + + LOG_ERROR(RSX, "Texture wrap error: bad wrap (%d)", (u32)wrap); + return GL_REPEAT; + } + + float max_aniso(rsx::texture_max_anisotropy aniso) + { + switch (aniso) + { + case rsx::texture_max_anisotropy::x1: return 1.0f; + case rsx::texture_max_anisotropy::x2: return 2.0f; + case rsx::texture_max_anisotropy::x4: return 4.0f; + case rsx::texture_max_anisotropy::x6: return 6.0f; + case rsx::texture_max_anisotropy::x8: return 8.0f; + case rsx::texture_max_anisotropy::x10: return 10.0f; + case rsx::texture_max_anisotropy::x12: return 12.0f; + case rsx::texture_max_anisotropy::x16: return 16.0f; + } + + LOG_ERROR(RSX, "Texture anisotropy error: bad max aniso (%d)", (u32)aniso); + return 1.0f; + } + + //Apply sampler state settings + void sampler_state::apply(rsx::fragment_texture& tex) + { + const f32 border_color = (f32)tex.border_color() / 255; + const f32 border_color_array[] = { border_color, border_color, border_color, border_color }; + + glSamplerParameteri(samplerHandle, GL_TEXTURE_WRAP_S, wrap_mode(tex.wrap_s())); + glSamplerParameteri(samplerHandle, GL_TEXTURE_WRAP_T, wrap_mode(tex.wrap_t())); + glSamplerParameteri(samplerHandle, GL_TEXTURE_WRAP_R, wrap_mode(tex.wrap_r())); + glSamplerParameterfv(samplerHandle, GL_TEXTURE_BORDER_COLOR, border_color_array); + } } namespace @@ -230,42 +278,6 @@ namespace rsx glGenTextures(1, &m_id); } - int texture::gl_wrap(rsx::texture_wrap_mode wrap) - { - switch (wrap) - { - case rsx::texture_wrap_mode::wrap: return GL_REPEAT; - case rsx::texture_wrap_mode::mirror: return GL_MIRRORED_REPEAT; - case rsx::texture_wrap_mode::clamp_to_edge: return GL_CLAMP_TO_EDGE; - case rsx::texture_wrap_mode::border: return GL_CLAMP_TO_BORDER; - case rsx::texture_wrap_mode::clamp: return GL_CLAMP_TO_BORDER; - case rsx::texture_wrap_mode::mirror_once_clamp_to_edge: return GL_MIRROR_CLAMP_TO_EDGE_EXT; - case rsx::texture_wrap_mode::mirror_once_border: return GL_MIRROR_CLAMP_TO_BORDER_EXT; - case rsx::texture_wrap_mode::mirror_once_clamp: return GL_MIRROR_CLAMP_EXT; - } - - LOG_ERROR(RSX, "Texture wrap error: bad wrap (%d)", (u32)wrap); - return GL_REPEAT; - } - - float texture::max_aniso(rsx::texture_max_anisotropy aniso) - { - switch (aniso) - { - case rsx::texture_max_anisotropy::x1: return 1.0f; - case rsx::texture_max_anisotropy::x2: return 2.0f; - case rsx::texture_max_anisotropy::x4: return 4.0f; - case rsx::texture_max_anisotropy::x6: return 6.0f; - case rsx::texture_max_anisotropy::x8: return 8.0f; - case rsx::texture_max_anisotropy::x10: return 10.0f; - case rsx::texture_max_anisotropy::x12: return 12.0f; - case rsx::texture_max_anisotropy::x16: return 16.0f; - } - - LOG_ERROR(RSX, "Texture anisotropy error: bad max aniso (%d)", (u32)aniso); - return 1.0f; - } - u16 texture::get_pitch_modifier(u32 format) { switch (format) @@ -431,8 +443,8 @@ namespace rsx return true; return false; - } - + } + void texture::init(int index, rsx::fragment_texture& tex) { switch (tex.dimension()) @@ -527,9 +539,9 @@ namespace rsx __glcheck glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_G, remap_values[2]); __glcheck glTexParameteri(m_target, GL_TEXTURE_SWIZZLE_B, remap_values[3]); - __glcheck glTexParameteri(m_target, GL_TEXTURE_WRAP_S, gl_wrap(tex.wrap_s())); - __glcheck glTexParameteri(m_target, GL_TEXTURE_WRAP_T, gl_wrap(tex.wrap_t())); - __glcheck glTexParameteri(m_target, GL_TEXTURE_WRAP_R, gl_wrap(tex.wrap_r())); + __glcheck glTexParameteri(m_target, GL_TEXTURE_WRAP_S, ::gl::wrap_mode(tex.wrap_s())); + __glcheck glTexParameteri(m_target, GL_TEXTURE_WRAP_T, ::gl::wrap_mode(tex.wrap_t())); + __glcheck glTexParameteri(m_target, GL_TEXTURE_WRAP_R, ::gl::wrap_mode(tex.wrap_r())); if (tex.get_exact_mipmap_count() <= 1 || m_target == GL_TEXTURE_RECTANGLE) { @@ -569,7 +581,7 @@ namespace rsx } __glcheck glTexParameteri(m_target, GL_TEXTURE_MAG_FILTER, gl_tex_mag_filter(tex.mag_filter())); - __glcheck glTexParameterf(m_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_aniso(tex.max_aniso())); + __glcheck glTexParameterf(m_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, ::gl::max_aniso(tex.max_aniso())); } void texture::init(int index, rsx::vertex_texture& tex) diff --git a/rpcs3/Emu/RSX/GL/GLTexture.h b/rpcs3/Emu/RSX/GL/GLTexture.h index e12271fa3f..464a9c05a6 100644 --- a/rpcs3/Emu/RSX/GL/GLTexture.h +++ b/rpcs3/Emu/RSX/GL/GLTexture.h @@ -5,7 +5,42 @@ namespace rsx { class vertex_texture; class fragment_texture; +} +namespace gl +{ + GLenum get_sized_internal_format(u32 gcm_format); + std::tuple get_format_type(u32 texture_format); + GLenum wrap_mode(rsx::texture_wrap_mode wrap); + float max_aniso(rsx::texture_max_anisotropy aniso); + + class sampler_state + { + GLuint samplerHandle = 0; + + public: + + void create() + { + glGenSamplers(1, &samplerHandle); + } + + void remove() + { + glDeleteSamplers(1, &samplerHandle); + } + + void bind(int index) + { + glBindSampler(index, samplerHandle); + } + + void apply(rsx::fragment_texture& tex); + }; +} + +namespace rsx +{ namespace gl { class texture @@ -16,28 +51,6 @@ namespace rsx public: void create(); - int gl_wrap(rsx::texture_wrap_mode in); - - float max_aniso(rsx::texture_max_anisotropy aniso); - - inline static u8 convert_4_to_8(u8 v) - { - // Swizzle bits: 00001234 -> 12341234 - return (v << 4) | (v); - } - - inline static u8 convert_5_to_8(u8 v) - { - // Swizzle bits: 00012345 -> 12345123 - return (v << 3) | (v >> 2); - } - - inline static u8 convert_6_to_8(u8 v) - { - // Swizzle bits: 00123456 -> 12345612 - return (v << 2) | (v >> 4); - } - void init(int index, rsx::fragment_texture& tex); void init(int index, rsx::vertex_texture& tex); @@ -64,9 +77,3 @@ namespace rsx }; } } - -namespace gl -{ - GLenum get_sized_internal_format(u32 gcm_format); - std::tuple get_format_type(u32 texture_format); -} diff --git a/rpcs3/Emu/RSX/GL/GLTextureCache.h b/rpcs3/Emu/RSX/GL/GLTextureCache.h index 3234b61a0c..c5cab86d9b 100644 --- a/rpcs3/Emu/RSX/GL/GLTextureCache.h +++ b/rpcs3/Emu/RSX/GL/GLTextureCache.h @@ -1073,7 +1073,7 @@ namespace gl const u32 dst_address = (u32)((u64)dst.pixels - (u64)vm::base(0)); //Check if src/dst are parts of render targets - surface_subresource src_subres = m_rtts.get_surface_subresource_if_applicable(src_address, src.width, src.slice_h, src.pitch, true, true); + surface_subresource src_subres = m_rtts.get_surface_subresource_if_applicable(src_address, src.width, src.height, src.pitch, true, true); src_is_render_target = src_subres.surface != nullptr; //Prepare areas and offsets