mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	Merge pull request #5420 from citra-emu/xglTextureBarrier
videocore: When an image is the current framebuffer and is sampled, make a copy instead of using glTextureBarrier
This commit is contained in:
		
						commit
						f4e727cc19
					
				
					 3 changed files with 99 additions and 12 deletions
				
			
		|  | @ -61,11 +61,6 @@ RasterizerOpenGL::RasterizerOpenGL() | |||
|                     "Shadow might not be able to render because of unsupported OpenGL extensions."); | ||||
|     } | ||||
| 
 | ||||
|     if (!GLAD_GL_ARB_texture_barrier) { | ||||
|         LOG_WARNING(Render_OpenGL, | ||||
|                     "ARB_texture_barrier not supported. Some games might produce artifacts."); | ||||
|     } | ||||
| 
 | ||||
|     // Clipping plane 0 is always enabled for PICA fixed clip plane z <= 0
 | ||||
|     state.clip_distance[0] = true; | ||||
| 
 | ||||
|  | @ -643,10 +638,10 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) { | |||
|         uniform_block_data.dirty = true; | ||||
|     } | ||||
| 
 | ||||
|     bool need_texture_barrier = false; | ||||
|     auto CheckBarrier = [&need_texture_barrier, &color_surface](GLuint handle) { | ||||
|     bool need_duplicate_texture = false; | ||||
|     auto CheckBarrier = [&need_duplicate_texture, &color_surface](GLuint handle) { | ||||
|         if (color_surface && color_surface->texture.handle == handle) { | ||||
|             need_texture_barrier = true; | ||||
|             need_duplicate_texture = true; | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|  | @ -776,6 +771,43 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     OGLTexture temp_tex; | ||||
|     if (need_duplicate_texture) { | ||||
|         // The game is trying to use a surface as a texture and framebuffer at the same time
 | ||||
|         // which causes unpredictable behavior on the host.
 | ||||
|         // Making a copy to sample from eliminates this issue and seems to be fairly cheap.
 | ||||
|         temp_tex.Create(); | ||||
|         glBindTexture(GL_TEXTURE_2D, temp_tex.handle); | ||||
|         auto [internal_format, format, type] = GetFormatTuple(color_surface->pixel_format); | ||||
|         OGLTexture::Allocate(GL_TEXTURE_2D, color_surface->max_level + 1, internal_format, format, | ||||
|                              type, color_surface->GetScaledWidth(), | ||||
|                              color_surface->GetScaledHeight()); | ||||
|         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | ||||
|         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | ||||
|         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | ||||
|         glBindTexture(GL_TEXTURE_2D, state.texture_units[0].texture_2d); | ||||
| 
 | ||||
|         for (std::size_t level{0}; level <= color_surface->max_level; ++level) { | ||||
|             glCopyImageSubData(color_surface->texture.handle, GL_TEXTURE_2D, level, 0, 0, 0, | ||||
|                                temp_tex.handle, GL_TEXTURE_2D, level, 0, 0, 0, | ||||
|                                color_surface->GetScaledWidth() >> level, | ||||
|                                color_surface->GetScaledHeight() >> level, 1); | ||||
|         } | ||||
| 
 | ||||
|         for (auto& unit : state.texture_units) { | ||||
|             if (unit.texture_2d == color_surface->texture.handle) { | ||||
|                 unit.texture_2d = temp_tex.handle; | ||||
|             } | ||||
|         } | ||||
|         for (auto shadow_unit : {&state.image_shadow_texture_nx, &state.image_shadow_texture_ny, | ||||
|                                  &state.image_shadow_texture_nz, &state.image_shadow_texture_px, | ||||
|                                  &state.image_shadow_texture_py, &state.image_shadow_texture_pz}) { | ||||
|             if (*shadow_unit == color_surface->texture.handle) { | ||||
|                 *shadow_unit = temp_tex.handle; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Sync and bind the shader
 | ||||
|     if (shader_dirty) { | ||||
|         SetShader(); | ||||
|  | @ -850,10 +882,6 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) { | |||
|                         GL_TEXTURE_UPDATE_BARRIER_BIT | GL_FRAMEBUFFER_BARRIER_BIT); | ||||
|     } | ||||
| 
 | ||||
|     if (need_texture_barrier && GLAD_GL_ARB_texture_barrier) { | ||||
|         glTextureBarrier(); | ||||
|     } | ||||
| 
 | ||||
|     // Mark framebuffer surfaces as dirty
 | ||||
|     Common::Rectangle<u32> draw_rect_unscaled{draw_rect.left / res_scale, draw_rect.top / res_scale, | ||||
|                                               draw_rect.right / res_scale, | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ | |||
| #include "video_core/renderer_opengl/gl_resource_manager.h" | ||||
| #include "video_core/renderer_opengl/gl_shader_util.h" | ||||
| #include "video_core/renderer_opengl/gl_state.h" | ||||
| #include "video_core/renderer_opengl/gl_vars.h" | ||||
| 
 | ||||
| MICROPROFILE_DEFINE(OpenGL_ResourceCreation, "OpenGL", "Resource Creation", MP_RGB(128, 128, 192)); | ||||
| MICROPROFILE_DEFINE(OpenGL_ResourceDeletion, "OpenGL", "Resource Deletion", MP_RGB(128, 128, 192)); | ||||
|  | @ -51,6 +52,61 @@ void OGLTexture::Release() { | |||
|     handle = 0; | ||||
| } | ||||
| 
 | ||||
| void OGLTexture::Allocate(GLenum target, GLsizei levels, GLenum internalformat, GLenum format, | ||||
|                           GLenum type, GLsizei width, GLsizei height, GLsizei depth) { | ||||
|     const bool tex_storage = GLAD_GL_ARB_texture_storage || GLES; | ||||
| 
 | ||||
|     switch (target) { | ||||
|     case GL_TEXTURE_1D: | ||||
|     case GL_TEXTURE: | ||||
|         if (tex_storage) { | ||||
|             glTexStorage1D(target, levels, internalformat, width); | ||||
|         } else { | ||||
|             for (GLsizei level{0}; level < levels; ++level) { | ||||
|                 glTexImage1D(target, level, internalformat, width, 0, format, type, nullptr); | ||||
|                 width >>= 1; | ||||
|             } | ||||
|         } | ||||
|         break; | ||||
|     case GL_TEXTURE_2D: | ||||
|     case GL_TEXTURE_1D_ARRAY: | ||||
|     case GL_TEXTURE_RECTANGLE: | ||||
|     case GL_TEXTURE_CUBE_MAP: | ||||
|         if (tex_storage) { | ||||
|             glTexStorage2D(target, levels, internalformat, width, height); | ||||
|         } else { | ||||
|             for (GLsizei level{0}; level < levels; ++level) { | ||||
|                 glTexImage2D(target, level, internalformat, width, height, 0, format, type, | ||||
|                              nullptr); | ||||
|                 width >>= 1; | ||||
|                 if (target != GL_TEXTURE_1D_ARRAY) | ||||
|                     height >>= 1; | ||||
|             } | ||||
|         } | ||||
|         break; | ||||
|     case GL_TEXTURE_3D: | ||||
|     case GL_TEXTURE_2D_ARRAY: | ||||
|     case GL_TEXTURE_CUBE_MAP_ARRAY: | ||||
|         if (tex_storage) { | ||||
|             glTexStorage3D(target, levels, internalformat, width, height, depth); | ||||
|         } else { | ||||
|             for (GLsizei level{0}; level < levels; ++level) { | ||||
|                 glTexImage3D(target, level, internalformat, width, height, depth, 0, format, type, | ||||
|                              nullptr); | ||||
|             } | ||||
|             width >>= 1; | ||||
|             height >>= 1; | ||||
|             if (target == GL_TEXTURE_3D) | ||||
|                 depth >>= 1; | ||||
|         } | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     if (!tex_storage) { | ||||
|         glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, levels - 1); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void OGLSampler::Create() { | ||||
|     if (handle != 0) | ||||
|         return; | ||||
|  |  | |||
|  | @ -59,6 +59,9 @@ public: | |||
|     /// Deletes the internal OpenGL resource
 | ||||
|     void Release(); | ||||
| 
 | ||||
|     static void Allocate(GLenum target, GLsizei levels, GLenum internalformat, GLenum format, | ||||
|                          GLenum type, GLsizei width, GLsizei height = 1, GLsizei depth = 1); | ||||
| 
 | ||||
|     GLuint handle = 0; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue