diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index 8edf2da28c..920caaa832 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -471,6 +471,7 @@ target_sources(rpcs3_emu PRIVATE RSX/GL/glutils/image.cpp RSX/GL/glutils/program.cpp RSX/GL/glutils/ring_buffer.cpp + RSX/GL/glutils/sampler.cpp RSX/GL/GLCommonDecompiler.cpp RSX/GL/GLCompute.cpp RSX/GL/GLDraw.cpp diff --git a/rpcs3/Emu/RSX/GL/GLCompute.cpp b/rpcs3/Emu/RSX/GL/GLCompute.cpp index 7194412a03..b6924901a2 100644 --- a/rpcs3/Emu/RSX/GL/GLCompute.cpp +++ b/rpcs3/Emu/RSX/GL/GLCompute.cpp @@ -305,6 +305,15 @@ namespace gl auto depth_view = src->get_view(GL_REMAP_IDENTITY, rsx::default_remap_vector, gl::image_aspect::depth); auto stencil_view = src->get_view(GL_REMAP_IDENTITY, rsx::default_remap_vector, gl::image_aspect::stencil); + if (!m_sampler) + { + m_sampler.create(); + m_sampler.apply_defaults(); + } + + gl::saved_sampler_state save_0(GL_COMPUTE_BUFFER_SLOT(0), m_sampler); + gl::saved_sampler_state save_1(GL_COMPUTE_BUFFER_SLOT(1), m_sampler); + depth_view->bind(cmd, GL_COMPUTE_BUFFER_SLOT(0)); stencil_view->bind(cmd, GL_COMPUTE_BUFFER_SLOT(1)); dst->bind_range(gl::buffer::target::ssbo, GL_COMPUTE_BUFFER_SLOT(2), out_offset, row_pitch * 4 * region.height); @@ -345,6 +354,14 @@ namespace gl auto data_view = src->get_view(GL_REMAP_IDENTITY, rsx::default_remap_vector, gl::image_aspect::color); + if (!m_sampler) + { + m_sampler.create(); + m_sampler.apply_defaults(); + } + + gl::saved_sampler_state save(GL_COMPUTE_BUFFER_SLOT(0), m_sampler); + data_view->bind(cmd, GL_COMPUTE_BUFFER_SLOT(0)); dst->bind_range(gl::buffer::target::ssbo, GL_COMPUTE_BUFFER_SLOT(1), out_offset, row_pitch * 4 * region.height); diff --git a/rpcs3/Emu/RSX/GL/GLCompute.h b/rpcs3/Emu/RSX/GL/GLCompute.h index 247966dd9e..2e911f7ae4 100644 --- a/rpcs3/Emu/RSX/GL/GLCompute.h +++ b/rpcs3/Emu/RSX/GL/GLCompute.h @@ -25,7 +25,7 @@ namespace gl void initialize(); void create(); - void destroy(); + virtual void destroy(); virtual void bind_resources() {} @@ -343,8 +343,13 @@ namespace gl struct pixel_buffer_layout; - struct cs_image_to_ssbo : compute_task + class cs_image_to_ssbo : public compute_task { + protected: + gl::sampler_state m_sampler; + + public: + void destroy() override { m_sampler.remove(); compute_task::destroy(); } virtual void run(gl::command_context& cmd, gl::viewable_image* src, const gl::buffer* dst, u32 out_offset, const coordu& region, const gl::pixel_buffer_layout& layout) = 0; }; diff --git a/rpcs3/Emu/RSX/GL/GLHelpers.h b/rpcs3/Emu/RSX/GL/GLHelpers.h index f741898332..3ab61751df 100644 --- a/rpcs3/Emu/RSX/GL/GLHelpers.h +++ b/rpcs3/Emu/RSX/GL/GLHelpers.h @@ -22,6 +22,7 @@ // TODO: Include on use #include "glutils/buffer_object.h" #include "glutils/image.h" +#include "glutils/sampler.h" #include "glutils/pixel_settings.hpp" #include "glutils/state_tracker.hpp" diff --git a/rpcs3/Emu/RSX/GL/GLOverlays.h b/rpcs3/Emu/RSX/GL/GLOverlays.h index 8a79b7913e..b332555283 100644 --- a/rpcs3/Emu/RSX/GL/GLOverlays.h +++ b/rpcs3/Emu/RSX/GL/GLOverlays.h @@ -35,28 +35,6 @@ namespace gl GLenum primitives = GL_TRIANGLE_STRIP; GLenum input_filter = GL_NEAREST; - struct saved_sampler_state - { - GLuint saved = GL_NONE; - GLuint unit = 0; - - saved_sampler_state(GLuint _unit, const gl::sampler_state& sampler) - { - glActiveTexture(GL_TEXTURE0 + _unit); - glGetIntegerv(GL_SAMPLER_BINDING, reinterpret_cast(&saved)); - - unit = _unit; - sampler.bind(_unit); - } - - saved_sampler_state(const saved_sampler_state&) = delete; - - ~saved_sampler_state() - { - glBindSampler(unit, saved); - } - }; - void create(); void destroy(); diff --git a/rpcs3/Emu/RSX/GL/GLTexture.cpp b/rpcs3/Emu/RSX/GL/GLTexture.cpp index 147ef28b0b..76ab759205 100644 --- a/rpcs3/Emu/RSX/GL/GLTexture.cpp +++ b/rpcs3/Emu/RSX/GL/GLTexture.cpp @@ -199,197 +199,6 @@ namespace gl return ret; } - GLenum get_srgb_format(GLenum in_format) - { - switch (in_format) - { - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; - case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: - return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: - return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; - case GL_RGBA8: - return GL_SRGB8_ALPHA8; - default: - //rsx_log.error("No gamma conversion for format 0x%X", in_format); - return in_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_EDGE; - 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; - } - - rsx_log.error("Texture wrap error: bad wrap (%d)", static_cast(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; - } - - rsx_log.error("Texture anisotropy error: bad max aniso (%d)", static_cast(aniso)); - return 1.0f; - } - - int tex_min_filter(rsx::texture_minify_filter min_filter) - { - switch (min_filter) - { - case rsx::texture_minify_filter::nearest: return GL_NEAREST; - case rsx::texture_minify_filter::linear: return GL_LINEAR; - case rsx::texture_minify_filter::nearest_nearest: return GL_NEAREST_MIPMAP_NEAREST; - case rsx::texture_minify_filter::linear_nearest: return GL_LINEAR_MIPMAP_NEAREST; - case rsx::texture_minify_filter::nearest_linear: return GL_NEAREST_MIPMAP_LINEAR; - case rsx::texture_minify_filter::linear_linear: return GL_LINEAR_MIPMAP_LINEAR; - case rsx::texture_minify_filter::convolution_min: return GL_LINEAR_MIPMAP_LINEAR; - } - fmt::throw_exception("Unknown min filter"); - } - - int tex_mag_filter(rsx::texture_magnify_filter mag_filter) - { - switch (mag_filter) - { - case rsx::texture_magnify_filter::nearest: return GL_NEAREST; - case rsx::texture_magnify_filter::linear: return GL_LINEAR; - case rsx::texture_magnify_filter::convolution_mag: return GL_LINEAR; - } - fmt::throw_exception("Unknown mag filter"); - } - - // Apply sampler state settings - void sampler_state::apply(const rsx::fragment_texture& tex, const rsx::sampled_image_descriptor_base* sampled_image) - { - set_parameteri(GL_TEXTURE_WRAP_S, wrap_mode(tex.wrap_s())); - set_parameteri(GL_TEXTURE_WRAP_T, wrap_mode(tex.wrap_t())); - set_parameteri(GL_TEXTURE_WRAP_R, wrap_mode(tex.wrap_r())); - - if (const auto color = tex.border_color(); - get_parameteri(GL_TEXTURE_BORDER_COLOR) != color) - { - m_propertiesi[GL_TEXTURE_BORDER_COLOR] = color; - - const color4f border_color = rsx::decode_border_color(color); - glSamplerParameterfv(samplerHandle, GL_TEXTURE_BORDER_COLOR, border_color.rgba); - } - - if (sampled_image->upload_context != rsx::texture_upload_context::shader_read || - tex.get_exact_mipmap_count() == 1) - { - GLint min_filter = tex_min_filter(tex.min_filter()); - - if (min_filter != GL_LINEAR && min_filter != GL_NEAREST) - { - switch (min_filter) - { - case GL_NEAREST_MIPMAP_NEAREST: - case GL_NEAREST_MIPMAP_LINEAR: - min_filter = GL_NEAREST; break; - case GL_LINEAR_MIPMAP_NEAREST: - case GL_LINEAR_MIPMAP_LINEAR: - min_filter = GL_LINEAR; break; - default: - rsx_log.error("No mipmap fallback defined for rsx_min_filter = 0x%X", static_cast(tex.min_filter())); - min_filter = GL_NEAREST; - } - } - - set_parameteri(GL_TEXTURE_MIN_FILTER, min_filter); - set_parameterf(GL_TEXTURE_LOD_BIAS, 0.f); - set_parameterf(GL_TEXTURE_MIN_LOD, -1000.f); - set_parameterf(GL_TEXTURE_MAX_LOD, 1000.f); - } - else - { - set_parameteri(GL_TEXTURE_MIN_FILTER, tex_min_filter(tex.min_filter())); - set_parameterf(GL_TEXTURE_LOD_BIAS, tex.bias()); - set_parameterf(GL_TEXTURE_MIN_LOD, tex.min_lod()); - set_parameterf(GL_TEXTURE_MAX_LOD, tex.max_lod()); - } - - const f32 af_level = max_aniso(tex.max_aniso()); - set_parameterf(GL_TEXTURE_MAX_ANISOTROPY_EXT, af_level); - set_parameteri(GL_TEXTURE_MAG_FILTER, tex_mag_filter(tex.mag_filter())); - - const u32 texture_format = tex.format() & ~(CELL_GCM_TEXTURE_UN | CELL_GCM_TEXTURE_LN); - if (texture_format == CELL_GCM_TEXTURE_DEPTH16 || texture_format == CELL_GCM_TEXTURE_DEPTH24_D8 || - texture_format == CELL_GCM_TEXTURE_DEPTH16_FLOAT || texture_format == CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT) - { - //NOTE: The stored texture function is reversed wrt the textureProj compare function - GLenum compare_mode = static_cast(tex.zfunc()) | GL_NEVER; - - switch (compare_mode) - { - case GL_GREATER: compare_mode = GL_LESS; break; - case GL_GEQUAL: compare_mode = GL_LEQUAL; break; - case GL_LESS: compare_mode = GL_GREATER; break; - case GL_LEQUAL: compare_mode = GL_GEQUAL; break; - } - - set_parameteri(GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - set_parameteri(GL_TEXTURE_COMPARE_FUNC, compare_mode); - } - else - set_parameteri(GL_TEXTURE_COMPARE_MODE, GL_NONE); - } - - void sampler_state::apply(const rsx::vertex_texture& tex, const rsx::sampled_image_descriptor_base* /*sampled_image*/) - { - if (const auto color = tex.border_color(); - get_parameteri(GL_TEXTURE_BORDER_COLOR) != color) - { - m_propertiesi[GL_TEXTURE_BORDER_COLOR] = color; - - const color4f border_color = rsx::decode_border_color(color); - glSamplerParameterfv(samplerHandle, GL_TEXTURE_BORDER_COLOR, border_color.rgba); - } - - set_parameteri(GL_TEXTURE_WRAP_S, wrap_mode(tex.wrap_s())); - set_parameteri(GL_TEXTURE_WRAP_T, wrap_mode(tex.wrap_t())); - set_parameteri(GL_TEXTURE_WRAP_R, wrap_mode(tex.wrap_r())); - set_parameteri(GL_TEXTURE_MIN_FILTER, GL_NEAREST); - set_parameteri(GL_TEXTURE_MAG_FILTER, GL_NEAREST); - set_parameterf(GL_TEXTURE_LOD_BIAS, tex.bias()); - set_parameterf(GL_TEXTURE_MIN_LOD, tex.min_lod()); - set_parameterf(GL_TEXTURE_MAX_LOD, tex.max_lod()); - set_parameteri(GL_TEXTURE_COMPARE_MODE, GL_NONE); - } - - void sampler_state::apply_defaults(GLenum default_filter) - { - set_parameteri(GL_TEXTURE_WRAP_S, GL_REPEAT); - set_parameteri(GL_TEXTURE_WRAP_T, GL_REPEAT); - set_parameteri(GL_TEXTURE_WRAP_R, GL_REPEAT); - set_parameteri(GL_TEXTURE_MIN_FILTER, default_filter); - set_parameteri(GL_TEXTURE_MAG_FILTER, default_filter); - set_parameterf(GL_TEXTURE_LOD_BIAS, 0.f); - set_parameteri(GL_TEXTURE_MIN_LOD, 0); - set_parameteri(GL_TEXTURE_MAX_LOD, 0); - set_parameteri(GL_TEXTURE_COMPARE_MODE, GL_NONE); - } - std::array get_swizzle_remap(u32 texture_format) { // NOTE: This must be in ARGB order in all forms below. diff --git a/rpcs3/Emu/RSX/GL/GLTexture.h b/rpcs3/Emu/RSX/GL/GLTexture.h index 1f2eb8d7da..8793a2718b 100644 --- a/rpcs3/Emu/RSX/GL/GLTexture.h +++ b/rpcs3/Emu/RSX/GL/GLTexture.h @@ -35,8 +35,6 @@ namespace gl GLenum get_sized_internal_format(u32 texture_format); std::tuple get_format_type(u32 texture_format); pixel_buffer_layout get_format_type(texture::internal_format format); - GLenum wrap_mode(rsx::texture_wrap_mode wrap); - float max_aniso(rsx::texture_max_anisotropy aniso); std::array get_swizzle_remap(u32 texture_format); viewable_image* create_texture(u32 gcm_format, u16 width, u16 height, u16 depth, u16 mipmaps, rsx::texture_dimension_extended type); @@ -53,73 +51,6 @@ namespace gl void upload_texture(gl::command_context& cmd, texture* dst, u32 gcm_format, bool is_swizzled, const std::vector& subresources_layout); - class sampler_state - { - GLuint samplerHandle = 0; - std::unordered_map m_propertiesi; - std::unordered_map m_propertiesf; - - public: - - void create() - { - glGenSamplers(1, &samplerHandle); - } - - void remove() - { - glDeleteSamplers(1, &samplerHandle); - } - - void bind(int index) const - { - glBindSampler(index, samplerHandle); - } - - void set_parameteri(GLenum pname, GLuint value) - { - auto prop = m_propertiesi.find(pname); - if (prop != m_propertiesi.end() && - prop->second == value) - { - return; - } - - m_propertiesi[pname] = value; - glSamplerParameteri(samplerHandle, pname, value); - } - - void set_parameterf(GLenum pname, GLfloat value) - { - auto prop = m_propertiesf.find(pname); - if (prop != m_propertiesf.end() && - prop->second == value) - { - return; - } - - m_propertiesf[pname] = value; - glSamplerParameterf(samplerHandle, pname, value); - } - - GLuint get_parameteri(GLenum pname) - { - auto prop = m_propertiesi.find(pname); - return (prop == m_propertiesi.end()) ? 0 : prop->second; - } - - GLfloat get_parameterf(GLenum pname) - { - auto prop = m_propertiesf.find(pname); - return (prop == m_propertiesf.end()) ? 0 : prop->second; - } - - void apply(const rsx::fragment_texture& tex, const rsx::sampled_image_descriptor_base* sampled_image); - void apply(const rsx::vertex_texture& tex, const rsx::sampled_image_descriptor_base* sampled_image); - - void apply_defaults(GLenum default_filter = GL_NEAREST); - }; - namespace debug { extern std::unique_ptr g_vis_texture; diff --git a/rpcs3/Emu/RSX/GL/glutils/sampler.cpp b/rpcs3/Emu/RSX/GL/glutils/sampler.cpp new file mode 100644 index 0000000000..57f505a89d --- /dev/null +++ b/rpcs3/Emu/RSX/GL/glutils/sampler.cpp @@ -0,0 +1,185 @@ +#include "stdafx.h" +#include "sampler.h" + +#include "Emu/RSX/gcm_enums.h" +#include "Emu/RSX/rsx_utils.h" +#include "Emu/RSX/Common/TextureUtils.h" + +//GLenum wrap_mode(rsx::texture_wrap_mode wrap); +//float max_aniso(rsx::texture_max_anisotropy aniso); + +namespace gl +{ + 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_EDGE; + 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; + } + + rsx_log.error("Texture wrap error: bad wrap (%d)", static_cast(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; + } + + rsx_log.error("Texture anisotropy error: bad max aniso (%d)", static_cast(aniso)); + return 1.0f; + } + + int tex_min_filter(rsx::texture_minify_filter min_filter) + { + switch (min_filter) + { + case rsx::texture_minify_filter::nearest: return GL_NEAREST; + case rsx::texture_minify_filter::linear: return GL_LINEAR; + case rsx::texture_minify_filter::nearest_nearest: return GL_NEAREST_MIPMAP_NEAREST; + case rsx::texture_minify_filter::linear_nearest: return GL_LINEAR_MIPMAP_NEAREST; + case rsx::texture_minify_filter::nearest_linear: return GL_NEAREST_MIPMAP_LINEAR; + case rsx::texture_minify_filter::linear_linear: return GL_LINEAR_MIPMAP_LINEAR; + case rsx::texture_minify_filter::convolution_min: return GL_LINEAR_MIPMAP_LINEAR; + } + fmt::throw_exception("Unknown min filter"); + } + + int tex_mag_filter(rsx::texture_magnify_filter mag_filter) + { + switch (mag_filter) + { + case rsx::texture_magnify_filter::nearest: return GL_NEAREST; + case rsx::texture_magnify_filter::linear: return GL_LINEAR; + case rsx::texture_magnify_filter::convolution_mag: return GL_LINEAR; + } + fmt::throw_exception("Unknown mag filter"); + } + + // Apply sampler state settings + void sampler_state::apply(const rsx::fragment_texture& tex, const rsx::sampled_image_descriptor_base* sampled_image) + { + set_parameteri(GL_TEXTURE_WRAP_S, wrap_mode(tex.wrap_s())); + set_parameteri(GL_TEXTURE_WRAP_T, wrap_mode(tex.wrap_t())); + set_parameteri(GL_TEXTURE_WRAP_R, wrap_mode(tex.wrap_r())); + + if (const auto color = tex.border_color(); + get_parameteri(GL_TEXTURE_BORDER_COLOR) != color) + { + m_propertiesi[GL_TEXTURE_BORDER_COLOR] = color; + + const color4f border_color = rsx::decode_border_color(color); + glSamplerParameterfv(sampler_handle, GL_TEXTURE_BORDER_COLOR, border_color.rgba); + } + + if (sampled_image->upload_context != rsx::texture_upload_context::shader_read || + tex.get_exact_mipmap_count() == 1) + { + GLint min_filter = tex_min_filter(tex.min_filter()); + + if (min_filter != GL_LINEAR && min_filter != GL_NEAREST) + { + switch (min_filter) + { + case GL_NEAREST_MIPMAP_NEAREST: + case GL_NEAREST_MIPMAP_LINEAR: + min_filter = GL_NEAREST; break; + case GL_LINEAR_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_LINEAR: + min_filter = GL_LINEAR; break; + default: + rsx_log.error("No mipmap fallback defined for rsx_min_filter = 0x%X", static_cast(tex.min_filter())); + min_filter = GL_NEAREST; + } + } + + set_parameteri(GL_TEXTURE_MIN_FILTER, min_filter); + set_parameterf(GL_TEXTURE_LOD_BIAS, 0.f); + set_parameterf(GL_TEXTURE_MIN_LOD, -1000.f); + set_parameterf(GL_TEXTURE_MAX_LOD, 1000.f); + } + else + { + set_parameteri(GL_TEXTURE_MIN_FILTER, tex_min_filter(tex.min_filter())); + set_parameterf(GL_TEXTURE_LOD_BIAS, tex.bias()); + set_parameterf(GL_TEXTURE_MIN_LOD, tex.min_lod()); + set_parameterf(GL_TEXTURE_MAX_LOD, tex.max_lod()); + } + + const f32 af_level = max_aniso(tex.max_aniso()); + set_parameterf(GL_TEXTURE_MAX_ANISOTROPY_EXT, af_level); + set_parameteri(GL_TEXTURE_MAG_FILTER, tex_mag_filter(tex.mag_filter())); + + const u32 texture_format = tex.format() & ~(CELL_GCM_TEXTURE_UN | CELL_GCM_TEXTURE_LN); + if (texture_format == CELL_GCM_TEXTURE_DEPTH16 || texture_format == CELL_GCM_TEXTURE_DEPTH24_D8 || + texture_format == CELL_GCM_TEXTURE_DEPTH16_FLOAT || texture_format == CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT) + { + //NOTE: The stored texture function is reversed wrt the textureProj compare function + GLenum compare_mode = static_cast(tex.zfunc()) | GL_NEVER; + + switch (compare_mode) + { + case GL_GREATER: compare_mode = GL_LESS; break; + case GL_GEQUAL: compare_mode = GL_LEQUAL; break; + case GL_LESS: compare_mode = GL_GREATER; break; + case GL_LEQUAL: compare_mode = GL_GEQUAL; break; + } + + set_parameteri(GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + set_parameteri(GL_TEXTURE_COMPARE_FUNC, compare_mode); + } + else + set_parameteri(GL_TEXTURE_COMPARE_MODE, GL_NONE); + } + + void sampler_state::apply(const rsx::vertex_texture& tex, const rsx::sampled_image_descriptor_base* /*sampled_image*/) + { + if (const auto color = tex.border_color(); + get_parameteri(GL_TEXTURE_BORDER_COLOR) != color) + { + m_propertiesi[GL_TEXTURE_BORDER_COLOR] = color; + + const color4f border_color = rsx::decode_border_color(color); + glSamplerParameterfv(sampler_handle, GL_TEXTURE_BORDER_COLOR, border_color.rgba); + } + + set_parameteri(GL_TEXTURE_WRAP_S, wrap_mode(tex.wrap_s())); + set_parameteri(GL_TEXTURE_WRAP_T, wrap_mode(tex.wrap_t())); + set_parameteri(GL_TEXTURE_WRAP_R, wrap_mode(tex.wrap_r())); + set_parameteri(GL_TEXTURE_MIN_FILTER, GL_NEAREST); + set_parameteri(GL_TEXTURE_MAG_FILTER, GL_NEAREST); + set_parameterf(GL_TEXTURE_LOD_BIAS, tex.bias()); + set_parameterf(GL_TEXTURE_MIN_LOD, tex.min_lod()); + set_parameterf(GL_TEXTURE_MAX_LOD, tex.max_lod()); + set_parameteri(GL_TEXTURE_COMPARE_MODE, GL_NONE); + } + + void sampler_state::apply_defaults(GLenum default_filter) + { + set_parameteri(GL_TEXTURE_WRAP_S, GL_REPEAT); + set_parameteri(GL_TEXTURE_WRAP_T, GL_REPEAT); + set_parameteri(GL_TEXTURE_WRAP_R, GL_REPEAT); + set_parameteri(GL_TEXTURE_MIN_FILTER, default_filter); + set_parameteri(GL_TEXTURE_MAG_FILTER, default_filter); + set_parameterf(GL_TEXTURE_LOD_BIAS, 0.f); + set_parameteri(GL_TEXTURE_MIN_LOD, 0); + set_parameteri(GL_TEXTURE_MAX_LOD, 0); + set_parameteri(GL_TEXTURE_COMPARE_MODE, GL_NONE); + } +} diff --git a/rpcs3/Emu/RSX/GL/glutils/sampler.h b/rpcs3/Emu/RSX/GL/glutils/sampler.h new file mode 100644 index 0000000000..10ed7e8d65 --- /dev/null +++ b/rpcs3/Emu/RSX/GL/glutils/sampler.h @@ -0,0 +1,107 @@ +#pragma once + +#include "common.h" + +namespace rsx +{ + class fragment_texture; + class vertex_texture; + struct sampled_image_descriptor_base; +} + +namespace gl +{ + class sampler_state + { + GLuint sampler_handle = 0; + std::unordered_map m_propertiesi; + std::unordered_map m_propertiesf; + + public: + + void create() + { + glGenSamplers(1, &sampler_handle); + } + + void remove() + { + if (sampler_handle) + { + glDeleteSamplers(1, &sampler_handle); + } + } + + void bind(int index) const + { + glBindSampler(index, sampler_handle); + } + + void set_parameteri(GLenum pname, GLuint value) + { + auto prop = m_propertiesi.find(pname); + if (prop != m_propertiesi.end() && + prop->second == value) + { + return; + } + + m_propertiesi[pname] = value; + glSamplerParameteri(sampler_handle, pname, value); + } + + void set_parameterf(GLenum pname, GLfloat value) + { + auto prop = m_propertiesf.find(pname); + if (prop != m_propertiesf.end() && + prop->second == value) + { + return; + } + + m_propertiesf[pname] = value; + glSamplerParameterf(sampler_handle, pname, value); + } + + GLuint get_parameteri(GLenum pname) + { + auto prop = m_propertiesi.find(pname); + return (prop == m_propertiesi.end()) ? 0 : prop->second; + } + + GLfloat get_parameterf(GLenum pname) + { + auto prop = m_propertiesf.find(pname); + return (prop == m_propertiesf.end()) ? 0 : prop->second; + } + + void apply(const rsx::fragment_texture& tex, const rsx::sampled_image_descriptor_base* sampled_image); + void apply(const rsx::vertex_texture& tex, const rsx::sampled_image_descriptor_base* sampled_image); + + void apply_defaults(GLenum default_filter = GL_NEAREST); + + operator bool() const { return sampler_handle != GL_NONE; } + }; + + struct saved_sampler_state + { + GLuint saved = GL_NONE; + GLuint unit = 0; + + saved_sampler_state(GLuint _unit, const gl::sampler_state& sampler) + { + glActiveTexture(GL_TEXTURE0 + _unit); + glGetIntegerv(GL_SAMPLER_BINDING, reinterpret_cast(&saved)); + + unit = _unit; + sampler.bind(_unit); + } + + saved_sampler_state(const saved_sampler_state&) = delete; + + ~saved_sampler_state() + { + glBindSampler(unit, saved); + } + }; +} diff --git a/rpcs3/Emu/RSX/Overlays/overlay_message.cpp b/rpcs3/Emu/RSX/Overlays/overlay_message.cpp index 75f7edaf8f..aabe0f4b7c 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_message.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_message.cpp @@ -47,7 +47,7 @@ namespace rsx if (m_cur_pos != index) { m_cur_pos = index; - m_text.set_pos(10, index * 18); + m_text.set_pos(10, static_cast(index * 18)); } if ((m_expiration_time - time) < 2'000'000) diff --git a/rpcs3/GLGSRender.vcxproj b/rpcs3/GLGSRender.vcxproj index b4721b9cd5..9b6b848b9b 100644 --- a/rpcs3/GLGSRender.vcxproj +++ b/rpcs3/GLGSRender.vcxproj @@ -68,6 +68,7 @@ + @@ -95,6 +96,7 @@ + diff --git a/rpcs3/GLGSRender.vcxproj.filters b/rpcs3/GLGSRender.vcxproj.filters index e4076b0388..1ec2b74013 100644 --- a/rpcs3/GLGSRender.vcxproj.filters +++ b/rpcs3/GLGSRender.vcxproj.filters @@ -38,6 +38,9 @@ glutils + + glutils + @@ -92,6 +95,9 @@ glutils + + glutils +