mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-11-03 16:39:01 -06:00 
			
		
		
		
	OpenGL: Use Sampler Objects to decouple sampler config from textures
Fixes #978
This commit is contained in:
		@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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<SamplerInfo, 3> texture_samplers;
 | 
			
		||||
    TextureInfo fb_color_texture;
 | 
			
		||||
    DepthTextureInfo fb_depth_texture;
 | 
			
		||||
    OGLShader shader;
 | 
			
		||||
 
 | 
			
		||||
@@ -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<Math::Vec4<u8>[]> temp_texture_buffer_rgba(new Math::Vec4<u8>[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));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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 <memory>
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user