mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	Merge pull request #2266 from yuriks/fix-displaytransfer
OpenGL: Fix DisplayTransfer accel when input width != output width
This commit is contained in:
		
						commit
						17ce07943d
					
				
					 4 changed files with 29 additions and 19 deletions
				
			
		|  | @ -346,7 +346,7 @@ static void SetAxiConfigQoSMode(Service::Interface* self) { | |||
| 
 | ||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; // No error
 | ||||
| 
 | ||||
|     LOG_WARNING(Service_GSP, "(STUBBED) called mode=0x%08X", mode); | ||||
|     LOG_DEBUG(Service_GSP, "(STUBBED) called mode=0x%08X", mode); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  |  | |||
|  | @ -715,7 +715,11 @@ bool RasterizerOpenGL::AccelerateDisplayTransfer(const GPU::Regs::DisplayTransfe | |||
| 
 | ||||
|     CachedSurface src_params; | ||||
|     src_params.addr = config.GetPhysicalInputAddress(); | ||||
|     src_params.width = config.output_width; | ||||
|     // It's important to use the correct source input width to properly skip over parts of the input
 | ||||
|     // image which will be cropped from the output but still affect the stride of the input image.
 | ||||
|     src_params.width = config.input_width; | ||||
|     // Using the output's height is fine because we don't read or skip over the remaining part of
 | ||||
|     // the image, and it allows for smaller texture cache lookup rectangles.
 | ||||
|     src_params.height = config.output_height; | ||||
|     src_params.is_tiled = !config.input_linear; | ||||
|     src_params.pixel_format = CachedSurface::PixelFormatFromGPUPixelFormat(config.input_format); | ||||
|  | @ -736,6 +740,11 @@ bool RasterizerOpenGL::AccelerateDisplayTransfer(const GPU::Regs::DisplayTransfe | |||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     // Adjust the source rectangle to take into account parts of the input lines being cropped
 | ||||
|     if (config.input_width > config.output_width) { | ||||
|         src_rect.right -= (config.input_width - config.output_width) * src_surface->res_scale_width; | ||||
|     } | ||||
| 
 | ||||
|     // Require destination surface to have same resolution scale as source to preserve scaling
 | ||||
|     dst_params.res_scale_width = src_surface->res_scale_width; | ||||
|     dst_params.res_scale_height = src_surface->res_scale_height; | ||||
|  | @ -938,7 +947,7 @@ bool RasterizerOpenGL::AccelerateDisplay(const GPU::Regs::FramebufferConfig& con | |||
|     src_params.addr = framebuffer_addr; | ||||
|     src_params.width = config.width; | ||||
|     src_params.height = config.height; | ||||
|     src_params.stride = pixel_stride; | ||||
|     src_params.pixel_stride = pixel_stride; | ||||
|     src_params.is_tiled = false; | ||||
|     src_params.pixel_format = CachedSurface::PixelFormatFromGPUPixelFormat(config.color_format); | ||||
| 
 | ||||
|  |  | |||
|  | @ -158,24 +158,21 @@ bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex, | |||
|         buffers = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; | ||||
|     } | ||||
| 
 | ||||
|     if (OpenGLState::CheckFBStatus(GL_READ_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { | ||||
|         return false; | ||||
|     } | ||||
|     bool can_blit = OpenGLState::CheckFBStatus(GL_READ_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE && | ||||
|                     OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE; | ||||
| 
 | ||||
|     if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { | ||||
|         return false; | ||||
|     if (can_blit) { | ||||
|         glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom, | ||||
|                           dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, buffers, | ||||
|                           buffers == GL_COLOR_BUFFER_BIT ? GL_LINEAR : GL_NEAREST); | ||||
|     } | ||||
| 
 | ||||
|     glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom, dst_rect.left, | ||||
|                       dst_rect.top, dst_rect.right, dst_rect.bottom, buffers, | ||||
|                       buffers == GL_COLOR_BUFFER_BIT ? GL_LINEAR : GL_NEAREST); | ||||
| 
 | ||||
|     // Restore previous framebuffer bindings
 | ||||
|     cur_state.draw.read_framebuffer = old_fbs[0]; | ||||
|     cur_state.draw.draw_framebuffer = old_fbs[1]; | ||||
|     cur_state.Apply(); | ||||
| 
 | ||||
|     return true; | ||||
|     return can_blit; | ||||
| } | ||||
| 
 | ||||
| bool RasterizerCacheOpenGL::TryBlitSurfaces(CachedSurface* src_surface, | ||||
|  | @ -291,6 +288,9 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo | |||
| 
 | ||||
|     MICROPROFILE_SCOPE(OpenGL_SurfaceUpload); | ||||
| 
 | ||||
|     // Stride only applies to linear images.
 | ||||
|     ASSERT(params.pixel_stride == 0 || !params.is_tiled); | ||||
| 
 | ||||
|     std::shared_ptr<CachedSurface> new_surface = std::make_shared<CachedSurface>(); | ||||
| 
 | ||||
|     new_surface->addr = params.addr; | ||||
|  | @ -299,7 +299,7 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo | |||
|     new_surface->texture.Create(); | ||||
|     new_surface->width = params.width; | ||||
|     new_surface->height = params.height; | ||||
|     new_surface->stride = params.stride; | ||||
|     new_surface->pixel_stride = params.pixel_stride; | ||||
|     new_surface->res_scale_width = params.res_scale_width; | ||||
|     new_surface->res_scale_height = params.res_scale_height; | ||||
| 
 | ||||
|  | @ -325,14 +325,15 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo | |||
|         cur_state.Apply(); | ||||
|         glActiveTexture(GL_TEXTURE0); | ||||
| 
 | ||||
|         glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)new_surface->stride); | ||||
|         if (!new_surface->is_tiled) { | ||||
|             // TODO: Ensure this will always be a color format, not a depth or other format
 | ||||
|             ASSERT((size_t)new_surface->pixel_format < fb_format_tuples.size()); | ||||
|             const FormatTuple& tuple = fb_format_tuples[(unsigned int)params.pixel_format]; | ||||
| 
 | ||||
|             glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)new_surface->pixel_stride); | ||||
|             glTexImage2D(GL_TEXTURE_2D, 0, tuple.internal_format, params.width, params.height, 0, | ||||
|                          tuple.format, tuple.type, texture_src_data); | ||||
|             glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | ||||
|         } else { | ||||
|             SurfaceType type = CachedSurface::GetFormatType(new_surface->pixel_format); | ||||
|             if (type != SurfaceType::Depth && type != SurfaceType::DepthStencil) { | ||||
|  | @ -391,7 +392,6 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo | |||
|                              0, tuple.format, tuple.type, temp_fb_depth_buffer.data()); | ||||
|             } | ||||
|         } | ||||
|         glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); | ||||
| 
 | ||||
|         // If not 1x scale, blit 1x texture to a new scaled texture and replace texture in surface
 | ||||
|         if (new_surface->res_scale_width != 1.f || new_surface->res_scale_height != 1.f) { | ||||
|  | @ -701,13 +701,14 @@ void RasterizerCacheOpenGL::FlushSurface(CachedSurface* surface) { | |||
|     cur_state.Apply(); | ||||
|     glActiveTexture(GL_TEXTURE0); | ||||
| 
 | ||||
|     glPixelStorei(GL_PACK_ROW_LENGTH, (GLint)surface->stride); | ||||
|     if (!surface->is_tiled) { | ||||
|         // TODO: Ensure this will always be a color format, not a depth or other format
 | ||||
|         ASSERT((size_t)surface->pixel_format < fb_format_tuples.size()); | ||||
|         const FormatTuple& tuple = fb_format_tuples[(unsigned int)surface->pixel_format]; | ||||
| 
 | ||||
|         glPixelStorei(GL_PACK_ROW_LENGTH, (GLint)surface->pixel_stride); | ||||
|         glGetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type, dst_buffer); | ||||
|         glPixelStorei(GL_PACK_ROW_LENGTH, 0); | ||||
|     } else { | ||||
|         SurfaceType type = CachedSurface::GetFormatType(surface->pixel_format); | ||||
|         if (type != SurfaceType::Depth && type != SurfaceType::DepthStencil) { | ||||
|  | @ -750,7 +751,6 @@ void RasterizerCacheOpenGL::FlushSurface(CachedSurface* surface) { | |||
|                              false); | ||||
|         } | ||||
|     } | ||||
|     glPixelStorei(GL_PACK_ROW_LENGTH, 0); | ||||
| 
 | ||||
|     surface->dirty = false; | ||||
| 
 | ||||
|  |  | |||
|  | @ -171,7 +171,8 @@ struct CachedSurface { | |||
|     OGLTexture texture; | ||||
|     u32 width; | ||||
|     u32 height; | ||||
|     u32 stride = 0; | ||||
|     /// Stride between lines, in pixels. Only valid for images in linear format.
 | ||||
|     u32 pixel_stride = 0; | ||||
|     float res_scale_width = 1.f; | ||||
|     float res_scale_height = 1.f; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue