From 277dce634595f270bc3dfbf9518e91d28f95dca6 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Fri, 17 Nov 2023 19:48:33 +0100 Subject: [PATCH] swrenderer: Optimize image rendering Do the match on the format before the loop --- .../core/software_renderer/draw_functions.rs | 164 ++++++++++++------ 1 file changed, 109 insertions(+), 55 deletions(-) diff --git a/internal/core/software_renderer/draw_functions.rs b/internal/core/software_renderer/draw_functions.rs index 190307a86b..039f5e6caa 100644 --- a/internal/core/software_renderer/draw_functions.rs +++ b/internal/core/software_renderer/draw_functions.rs @@ -24,7 +24,6 @@ pub(super) fn draw_texture_line( *texture; let source_size = source_size.cast::(); let span_size = span.size.cast::(); - let bpp = format.bpp(); let y = (line - span.origin.y_length()).cast::(); let line_buffer = &mut line_buffer[span.origin.x as usize..][..span.size.width as usize]; @@ -39,11 +38,21 @@ pub(super) fn draw_texture_line( pos += (span_size.width as isize - 1) * delta; delta = -delta; }; - for pix in line_buffer { - fetch_blend_pixel(pix, format, data, (pos as usize >> 8) * bpp, alpha, color); - pos += delta; - } + fetch_blend_pixel( + line_buffer, + format, + data, + alpha, + color, + #[inline(always)] + |bpp| { + let p = (pos as usize >> 8) * bpp; + pos += delta; + p + }, + ); } else { + let bpp = format.bpp(); let col = y * source_size.width / span_size.height; let col = col * bpp; let stride = pixel_stride as usize * bpp; @@ -53,74 +62,119 @@ pub(super) fn draw_texture_line( } else { (0, row_delta) }; - for pix in line_buffer { - let pos = (row as usize >> 8) * stride + col; - fetch_blend_pixel(pix, format, data, pos, alpha, color); - row += row_delta; - } + fetch_blend_pixel( + line_buffer, + format, + data, + alpha, + color, + #[inline(always)] + |_| { + let pos = (row as usize >> 8) * stride + col; + row += row_delta; + pos + }, + ); }; - #[inline] fn fetch_blend_pixel( - pix: &mut impl TargetPixel, + line_buffer: &mut [impl TargetPixel], format: PixelFormat, data: &[u8], - pos: usize, alpha: u8, color: Color, + mut pos: impl FnMut(usize) -> usize, ) { - let c = match format { + match format { PixelFormat::Rgb => { - let p = &data[pos..pos + 3]; - if alpha == 0xff { - *pix = TargetPixel::from_rgb(p[0], p[1], p[2]); - return; - } else { - PremultipliedRgbaColor::premultiply(Color::from_argb_u8( - alpha, p[0], p[1], p[2], - )) + for pix in line_buffer { + let pos = pos(3); + let p = &data[pos..pos + 3]; + if alpha == 0xff { + *pix = TargetPixel::from_rgb(p[0], p[1], p[2]); + } else { + pix.blend(PremultipliedRgbaColor::premultiply(Color::from_argb_u8( + alpha, p[0], p[1], p[2], + ))) + } } } PixelFormat::Rgba => { - let alpha = ((data[pos + 3] as u16 * alpha as u16) / 255) as u8; - PremultipliedRgbaColor::premultiply(if color.alpha() == 0 { - Color::from_argb_u8(alpha, data[pos + 0], data[pos + 1], data[pos + 2]) - } else { - Color::from_argb_u8(alpha, color.red(), color.green(), color.blue()) - }) - } - PixelFormat::RgbaPremultiplied => { - if color.alpha() > 0 { - PremultipliedRgbaColor::premultiply(Color::from_argb_u8( - ((data[pos + 3] as u16 * alpha as u16) / 255) as u8, - color.red(), - color.green(), - color.blue(), - )) - } else if alpha == 0xff { - PremultipliedRgbaColor { - alpha: data[pos + 3], - red: data[pos + 0], - green: data[pos + 1], - blue: data[pos + 2], + if color.alpha() == 0 { + for pix in line_buffer { + let pos = pos(4); + let alpha = ((data[pos + 3] as u16 * alpha as u16) / 255) as u8; + let c = PremultipliedRgbaColor::premultiply(Color::from_argb_u8( + alpha, + data[pos + 0], + data[pos + 1], + data[pos + 2], + )); + pix.blend(c); } } else { - PremultipliedRgbaColor { - alpha: (data[pos + 3] as u16 * alpha as u16 / 255) as u8, - red: (data[pos + 0] as u16 * alpha as u16 / 255) as u8, - green: (data[pos + 1] as u16 * alpha as u16 / 255) as u8, - blue: (data[pos + 2] as u16 * alpha as u16 / 255) as u8, + for pix in line_buffer { + let pos = pos(4); + let alpha = ((data[pos + 3] as u16 * alpha as u16) / 255) as u8; + let c = PremultipliedRgbaColor::premultiply(Color::from_argb_u8( + alpha, + color.red(), + color.green(), + color.blue(), + )); + pix.blend(c); } } } - PixelFormat::AlphaMap => PremultipliedRgbaColor::premultiply(Color::from_argb_u8( - ((data[pos] as u16 * alpha as u16) / 255) as u8, - color.red(), - color.green(), - color.blue(), - )), + PixelFormat::RgbaPremultiplied => { + if color.alpha() > 0 { + for pix in line_buffer { + let pos = pos(4); + let c = PremultipliedRgbaColor::premultiply(Color::from_argb_u8( + ((data[pos + 3] as u16 * alpha as u16) / 255) as u8, + color.red(), + color.green(), + color.blue(), + )); + pix.blend(c); + } + } else if alpha == 0xff { + for pix in line_buffer { + let pos = pos(4); + let c = PremultipliedRgbaColor { + alpha: data[pos + 3], + red: data[pos + 0], + green: data[pos + 1], + blue: data[pos + 2], + }; + pix.blend(c); + } + } else { + for pix in line_buffer { + let pos = pos(4); + let c = PremultipliedRgbaColor { + alpha: (data[pos + 3] as u16 * alpha as u16 / 255) as u8, + red: (data[pos + 0] as u16 * alpha as u16 / 255) as u8, + green: (data[pos + 1] as u16 * alpha as u16 / 255) as u8, + blue: (data[pos + 2] as u16 * alpha as u16 / 255) as u8, + }; + pix.blend(c); + } + } + } + PixelFormat::AlphaMap => { + for pix in line_buffer { + let pos = pos(1); + let c = PremultipliedRgbaColor::premultiply(Color::from_argb_u8( + ((data[pos] as u16 * alpha as u16) / 255) as u8, + color.red(), + color.green(), + color.blue(), + )); + pix.blend(c); + } + } }; - pix.blend(c); } }