mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	OpenGL: Use Sampler Objects to decouple sampler config from textures
Fixes #978
This commit is contained in:
		
							parent
							
								
									466e608c19
								
							
						
					
					
						commit
						b044c047c4
					
				
					 4 changed files with 76 additions and 21 deletions
				
			
		|  | @ -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()); |         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
 |     // Generate VBO and VAO
 | ||||||
|     vertex_buffer.Create(); |     vertex_buffer.Create(); | ||||||
|     vertex_array.Create(); |     vertex_array.Create(); | ||||||
|  | @ -445,6 +451,45 @@ void RasterizerOpenGL::NotifyFlush(PAddr addr, u32 size) { | ||||||
|     res_cache.NotifyFlush(addr, 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) { | void RasterizerOpenGL::ReconfigureColorTexture(TextureInfo& texture, Pica::Regs::ColorFormat format, u32 width, u32 height) { | ||||||
|     GLint internal_format; |     GLint internal_format; | ||||||
| 
 | 
 | ||||||
|  | @ -772,6 +817,7 @@ void RasterizerOpenGL::SyncDrawState() { | ||||||
|         const auto& texture = pica_textures[texture_index]; |         const auto& texture = pica_textures[texture_index]; | ||||||
| 
 | 
 | ||||||
|         if (texture.enabled) { |         if (texture.enabled) { | ||||||
|  |             texture_samplers[texture_index].SyncWithConfig(texture.config); | ||||||
|             res_cache.LoadAndBindTexture(state, texture_index, texture); |             res_cache.LoadAndBindTexture(state, texture_index, texture); | ||||||
|         } else { |         } else { | ||||||
|             state.texture_units[texture_index].texture_2d = 0; |             state.texture_units[texture_index].texture_2d = 0; | ||||||
|  |  | ||||||
|  | @ -80,6 +80,24 @@ private: | ||||||
|         GLenum gl_type; |         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
 |     /// Structure that the hardware rendered vertices are composed of
 | ||||||
|     struct HardwareVertex { |     struct HardwareVertex { | ||||||
|         HardwareVertex(const Pica::Shader::OutputVertex& v) { |         HardwareVertex(const Pica::Shader::OutputVertex& v) { | ||||||
|  | @ -193,6 +211,7 @@ private: | ||||||
|     PAddr last_fb_depth_addr; |     PAddr last_fb_depth_addr; | ||||||
| 
 | 
 | ||||||
|     // Hardware rasterizer
 |     // Hardware rasterizer
 | ||||||
|  |     std::array<SamplerInfo, 3> texture_samplers; | ||||||
|     TextureInfo fb_color_texture; |     TextureInfo fb_color_texture; | ||||||
|     DepthTextureInfo fb_depth_texture; |     DepthTextureInfo fb_depth_texture; | ||||||
|     OGLShader shader; |     OGLShader shader; | ||||||
|  |  | ||||||
|  | @ -20,9 +20,8 @@ RasterizerCacheOpenGL::~RasterizerCacheOpenGL() { | ||||||
| 
 | 
 | ||||||
| MICROPROFILE_DEFINE(OpenGL_TextureUpload, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192)); | 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) { | void RasterizerCacheOpenGL::LoadAndBindTexture(OpenGLState &state, unsigned texture_unit, const Pica::DebugUtils::TextureInfo& info) { | ||||||
|     PAddr texture_addr = config.config.GetPhysicalAddress(); |     const auto cached_texture = texture_cache.find(info.physical_address); | ||||||
|     const auto cached_texture = texture_cache.find(texture_addr); |  | ||||||
| 
 | 
 | ||||||
|     if (cached_texture != texture_cache.end()) { |     if (cached_texture != texture_cache.end()) { | ||||||
|         state.texture_units[texture_unit].texture_2d = cached_texture->second->texture.handle; |         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(); |         state.Apply(); | ||||||
|         glActiveTexture(GL_TEXTURE0 + texture_unit); |         glActiveTexture(GL_TEXTURE0 + texture_unit); | ||||||
| 
 | 
 | ||||||
|         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, PicaToGL::TextureFilterMode(config.config.mag_filter)); |         u8* texture_src_data = Memory::GetPhysicalPointer(info.physical_address); | ||||||
|         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); |  | ||||||
| 
 | 
 | ||||||
|         new_texture->width = info.width; |         new_texture->width = info.width; | ||||||
|         new_texture->height = info.height; |         new_texture->height = info.height; | ||||||
|         new_texture->size = info.stride * 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); |         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]); |         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()); |         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_state.h" | ||||||
| #include "gl_resource_manager.h" | #include "gl_resource_manager.h" | ||||||
|  | #include "video_core/debug_utils/debug_utils.h" | ||||||
| #include "video_core/pica.h" | #include "video_core/pica.h" | ||||||
| 
 | 
 | ||||||
| #include <memory> | #include <memory> | ||||||
|  | @ -16,7 +17,11 @@ public: | ||||||
|     ~RasterizerCacheOpenGL(); |     ~RasterizerCacheOpenGL(); | ||||||
| 
 | 
 | ||||||
|     /// Loads a texture from 3DS memory to OpenGL and caches it (if not already cached)
 |     /// 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
 |     /// Flush any cached resource that touches the flushed region
 | ||||||
|     void NotifyFlush(PAddr addr, u32 size, bool ignore_hash = false); |     void NotifyFlush(PAddr addr, u32 size, bool ignore_hash = false); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue