Merge pull request #2266 from yuriks/fix-displaytransfer
OpenGL: Fix DisplayTransfer accel when input width != output width
This commit is contained in:
		@@ -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;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user