diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index b556ea65b..0260a28ce 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -68,6 +68,12 @@ void RasterizerOpenGL::InitObjects() { uniform_tev_cfg.updates_combiner_buffer_color_alpha = glGetUniformLocation(shader.handle, (tev_ref_str + ".updates_combiner_buffer_color_alpha").c_str()); } + // Create sampler objects + for (int i = 0; i < texture_samplers.size(); ++i) { + texture_samplers[i].Create(); + state.texture_units[i].sampler = texture_samplers[i].sampler.handle; + } + // Generate VBO and VAO vertex_buffer.Create(); vertex_array.Create(); @@ -445,6 +451,45 @@ void RasterizerOpenGL::NotifyFlush(PAddr addr, u32 size) { res_cache.NotifyFlush(addr, size); } +void RasterizerOpenGL::SamplerInfo::Create() { + sampler.Create(); + mag_filter = min_filter = TextureConfig::Linear; + wrap_s = wrap_t = TextureConfig::Repeat; + border_color = 0; + + glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // default is GL_LINEAR_MIPMAP_LINEAR + // Other attributes have correct defaults +} + +void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Pica::Regs::TextureConfig& config) { + GLuint s = sampler.handle; + + if (mag_filter != config.mag_filter) { + mag_filter = config.mag_filter; + glSamplerParameteri(s, GL_TEXTURE_MAG_FILTER, PicaToGL::TextureFilterMode(mag_filter)); + } + if (min_filter != config.min_filter) { + min_filter = config.min_filter; + glSamplerParameteri(s, GL_TEXTURE_MIN_FILTER, PicaToGL::TextureFilterMode(min_filter)); + } + + if (wrap_s != config.wrap_s) { + wrap_s = config.wrap_s; + glSamplerParameteri(s, GL_TEXTURE_WRAP_S, PicaToGL::WrapMode(wrap_s)); + } + if (wrap_t != config.wrap_t) { + wrap_t = config.wrap_t; + glSamplerParameteri(s, GL_TEXTURE_WRAP_T, PicaToGL::WrapMode(wrap_t)); + } + + if (wrap_s == TextureConfig::ClampToBorder || wrap_t == TextureConfig::ClampToBorder) { + if (border_color != config.border_color.raw) { + auto gl_color = PicaToGL::ColorRGBA8(border_color); + glSamplerParameterfv(s, GL_TEXTURE_BORDER_COLOR, gl_color.data()); + } + } +} + void RasterizerOpenGL::ReconfigureColorTexture(TextureInfo& texture, Pica::Regs::ColorFormat format, u32 width, u32 height) { GLint internal_format; @@ -772,6 +817,7 @@ void RasterizerOpenGL::SyncDrawState() { const auto& texture = pica_textures[texture_index]; if (texture.enabled) { + texture_samplers[texture_index].SyncWithConfig(texture.config); res_cache.LoadAndBindTexture(state, texture_index, texture); } else { state.texture_units[texture_index].texture_2d = 0; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index a02d5c856..24560d7f8 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -80,6 +80,24 @@ private: GLenum gl_type; }; + struct SamplerInfo { + using TextureConfig = Pica::Regs::TextureConfig; + + OGLSampler sampler; + + /// Creates the sampler object, initializing its state so that it's in sync with the SamplerInfo struct. + void Create(); + /// Syncs the sampler object with the config, updating any necessary state. + void SyncWithConfig(const TextureConfig& config); + + private: + TextureConfig::TextureFilter mag_filter; + TextureConfig::TextureFilter min_filter; + TextureConfig::WrapMode wrap_s; + TextureConfig::WrapMode wrap_t; + u32 border_color; + }; + /// Structure that the hardware rendered vertices are composed of struct HardwareVertex { HardwareVertex(const Pica::Shader::OutputVertex& v) { @@ -193,6 +211,7 @@ private: PAddr last_fb_depth_addr; // Hardware rasterizer + std::array texture_samplers; TextureInfo fb_color_texture; DepthTextureInfo fb_depth_texture; OGLShader shader; diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 5d9a80cd4..d9ccf2a3f 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -20,9 +20,8 @@ RasterizerCacheOpenGL::~RasterizerCacheOpenGL() { MICROPROFILE_DEFINE(OpenGL_TextureUpload, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192)); -void RasterizerCacheOpenGL::LoadAndBindTexture(OpenGLState &state, unsigned texture_unit, const Pica::Regs::FullTextureConfig& config) { - PAddr texture_addr = config.config.GetPhysicalAddress(); - const auto cached_texture = texture_cache.find(texture_addr); +void RasterizerCacheOpenGL::LoadAndBindTexture(OpenGLState &state, unsigned texture_unit, const Pica::DebugUtils::TextureInfo& info) { + const auto cached_texture = texture_cache.find(info.physical_address); if (cached_texture != texture_cache.end()) { state.texture_units[texture_unit].texture_2d = cached_texture->second->texture.handle; @@ -37,26 +36,12 @@ void RasterizerCacheOpenGL::LoadAndBindTexture(OpenGLState &state, unsigned text state.Apply(); glActiveTexture(GL_TEXTURE0 + texture_unit); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, PicaToGL::TextureFilterMode(config.config.mag_filter)); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, PicaToGL::TextureFilterMode(config.config.min_filter)); - - GLenum wrap_s = PicaToGL::WrapMode(config.config.wrap_s); - GLenum wrap_t = PicaToGL::WrapMode(config.config.wrap_t); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t); - - if (wrap_s == GL_CLAMP_TO_BORDER || wrap_t == GL_CLAMP_TO_BORDER) { - auto border_color = PicaToGL::ColorRGBA8(config.config.border_color.raw); - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color.data()); - } - - const auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config.config, config.format); - u8* texture_src_data = Memory::GetPhysicalPointer(texture_addr); + u8* texture_src_data = Memory::GetPhysicalPointer(info.physical_address); new_texture->width = info.width; new_texture->height = info.height; new_texture->size = info.stride * info.height; - new_texture->addr = texture_addr; + new_texture->addr = info.physical_address; new_texture->hash = Common::ComputeHash64(texture_src_data, new_texture->size); std::unique_ptr[]> temp_texture_buffer_rgba(new Math::Vec4[info.width * info.height]); @@ -69,7 +54,7 @@ void RasterizerCacheOpenGL::LoadAndBindTexture(OpenGLState &state, unsigned text glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, info.width, info.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, temp_texture_buffer_rgba.get()); - texture_cache.emplace(texture_addr, std::move(new_texture)); + texture_cache.emplace(info.physical_address, std::move(new_texture)); } } diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index d8f9edf59..ec56237b5 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -6,6 +6,7 @@ #include "gl_state.h" #include "gl_resource_manager.h" +#include "video_core/debug_utils/debug_utils.h" #include "video_core/pica.h" #include @@ -16,7 +17,11 @@ public: ~RasterizerCacheOpenGL(); /// Loads a texture from 3DS memory to OpenGL and caches it (if not already cached) - void LoadAndBindTexture(OpenGLState &state, unsigned texture_unit, const Pica::Regs::FullTextureConfig& config); + void LoadAndBindTexture(OpenGLState &state, unsigned texture_unit, const Pica::DebugUtils::TextureInfo& info); + + void LoadAndBindTexture(OpenGLState &state, unsigned texture_unit, const Pica::Regs::FullTextureConfig& config) { + LoadAndBindTexture(state, texture_unit, Pica::DebugUtils::TextureInfo::FromPicaRegister(config.config, config.format)); + } /// Flush any cached resource that touches the flushed region void NotifyFlush(PAddr addr, u32 size, bool ignore_hash = false);