From d0ede79db34fe9261e08162cd17619ca54162e10 Mon Sep 17 00:00:00 2001 From: Koen Kooi Date: Fri, 13 Nov 2009 10:16:04 +0100 Subject: pixman git: bump SRCREV to one where almost all patches are upstream --- ...01-ARM-Removal-of-unused-broken-NEON-code.patch | 830 --------------- ...uction-of-the-new-framework-for-NEON-fast.patch | 1061 -------------------- ...pixman_composite_src_8888_0565_asm_neon-f.patch | 63 -- ...pixman_composite_add_8000_8000_asm_neon-f.patch | 60 -- ...-pixman_composite_over_8888_8888_asm_neon.patch | 87 -- ...-a-set-of-NEON-functions-not-fully-optimi.patch | 540 ---------- .../0007-ARM-Enabled-new-NEON-optimizations.patch | 592 ----------- recipes/xorg-lib/pixman/neon-24bpp.patch | 264 ----- recipes/xorg-lib/pixman/over-8888-0565.patch | 296 ------ recipes/xorg-lib/pixman_git.bb | 14 +- 10 files changed, 2 insertions(+), 3805 deletions(-) delete mode 100644 recipes/xorg-lib/pixman/0001-ARM-Removal-of-unused-broken-NEON-code.patch delete mode 100644 recipes/xorg-lib/pixman/0002-ARM-Introduction-of-the-new-framework-for-NEON-fast.patch delete mode 100644 recipes/xorg-lib/pixman/0003-ARM-Added-pixman_composite_src_8888_0565_asm_neon-f.patch delete mode 100644 recipes/xorg-lib/pixman/0004-ARM-Added-pixman_composite_add_8000_8000_asm_neon-f.patch delete mode 100644 recipes/xorg-lib/pixman/0005-ARM-Added-pixman_composite_over_8888_8888_asm_neon.patch delete mode 100644 recipes/xorg-lib/pixman/0006-ARM-Added-a-set-of-NEON-functions-not-fully-optimi.patch delete mode 100644 recipes/xorg-lib/pixman/0007-ARM-Enabled-new-NEON-optimizations.patch delete mode 100644 recipes/xorg-lib/pixman/neon-24bpp.patch delete mode 100644 recipes/xorg-lib/pixman/over-8888-0565.patch (limited to 'recipes') diff --git a/recipes/xorg-lib/pixman/0001-ARM-Removal-of-unused-broken-NEON-code.patch b/recipes/xorg-lib/pixman/0001-ARM-Removal-of-unused-broken-NEON-code.patch deleted file mode 100644 index 227b95e87d..0000000000 --- a/recipes/xorg-lib/pixman/0001-ARM-Removal-of-unused-broken-NEON-code.patch +++ /dev/null @@ -1,830 +0,0 @@ -From 2761591638f8c56732398b1fc6cf4bc7ca5005fd Mon Sep 17 00:00:00 2001 -From: Siarhei Siamashka -Date: Mon, 27 Jul 2009 01:21:26 +0300 -Subject: [PATCH 1/7] ARM: Removal of unused/broken NEON code - ---- - pixman/pixman-arm-neon.c | 786 ---------------------------------------------- - 1 files changed, 0 insertions(+), 786 deletions(-) - -diff --git a/pixman/pixman-arm-neon.c b/pixman/pixman-arm-neon.c -index 0a29e50..9caef61 100644 ---- a/pixman/pixman-arm-neon.c -+++ b/pixman/pixman-arm-neon.c -@@ -1901,710 +1901,6 @@ pixman_fill_neon (uint32_t *bits, - #endif - } - --/* TODO: is there a more generic way of doing this being introduced? */ --#define NEON_SCANLINE_BUFFER_PIXELS (1024) -- --static inline void --neon_quadword_copy (void * dst, -- void * src, -- uint32_t count, /* of quadwords */ -- uint32_t trailer_count /* of bytes */) --{ -- uint8_t *t_dst = dst, *t_src = src; -- -- /* Uses aligned multi-register loads to maximise read bandwidth -- * on uncached memory such as framebuffers -- * The accesses do not have the aligned qualifiers, so that the copy -- * may convert between aligned-uncached and unaligned-cached memory. -- * It is assumed that the CPU can infer alignedness from the address. -- */ -- --#ifdef USE_GCC_INLINE_ASM -- -- asm volatile ( -- " cmp %[count], #8 \n" -- " blt 1f @ skip oversized fragments \n" -- "0: @ start with eight quadwords at a time \n" -- " sub %[count], %[count], #8 \n" -- " vld1.8 {d16, d17, d18, d19}, [%[src]]! \n" -- " vld1.8 {d20, d21, d22, d23}, [%[src]]! \n" -- " vld1.8 {d24, d25, d26, d27}, [%[src]]! \n" -- " vld1.8 {d28, d29, d30, d31}, [%[src]]! \n" -- " cmp %[count], #8 \n" -- " vst1.8 {d16, d17, d18, d19}, [%[dst]]! \n" -- " vst1.8 {d20, d21, d22, d23}, [%[dst]]! \n" -- " vst1.8 {d24, d25, d26, d27}, [%[dst]]! \n" -- " vst1.8 {d28, d29, d30, d31}, [%[dst]]! \n" -- " bge 0b \n" -- "1: @ four quadwords \n" -- " tst %[count], #4 \n" -- " beq 2f @ skip oversized fragment \n" -- " vld1.8 {d16, d17, d18, d19}, [%[src]]! \n" -- " vld1.8 {d20, d21, d22, d23}, [%[src]]! \n" -- " vst1.8 {d16, d17, d18, d19}, [%[dst]]! \n" -- " vst1.8 {d20, d21, d22, d23}, [%[dst]]! \n" -- "2: @ two quadwords \n" -- " tst %[count], #2 \n" -- " beq 3f @ skip oversized fragment \n" -- " vld1.8 {d16, d17, d18, d19}, [%[src]]! \n" -- " vst1.8 {d16, d17, d18, d19}, [%[dst]]! \n" -- "3: @ one quadword \n" -- " tst %[count], #1 \n" -- " beq 4f @ skip oversized fragment \n" -- " vld1.8 {d16, d17}, [%[src]]! \n" -- " vst1.8 {d16, d17}, [%[dst]]! \n" -- "4: @ end \n" -- -- /* Clobbered input registers marked as input/outputs */ -- : [dst] "+r" (t_dst), [src] "+r" (t_src), [count] "+r" (count) -- -- /* No unclobbered inputs */ -- : -- -- /* Clobbered vector registers */ -- : "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23", "d24", "d25", -- "d26", "d27", "d28", "d29", "d30", "d31", "cc", "memory"); -- --#else -- -- while (count >= 8) -- { -- uint8x16x4_t t1 = vld4q_u8 (t_src); -- uint8x16x4_t t2 = vld4q_u8 (t_src + sizeof(uint8x16x4_t)); -- -- t_src += sizeof(uint8x16x4_t) * 2; -- vst4q_u8 (t_dst, t1); -- vst4q_u8 (t_dst + sizeof(uint8x16x4_t), t2); -- t_dst += sizeof(uint8x16x4_t) * 2; -- count -= 8; -- } -- -- if (count & 4) -- { -- uint8x16x4_t t1 = vld4q_u8 (t_src); -- -- t_src += sizeof(uint8x16x4_t); -- vst4q_u8 (t_dst, t1); -- t_dst += sizeof(uint8x16x4_t); -- } -- -- if (count & 2) -- { -- uint8x8x4_t t1 = vld4_u8 (t_src); -- -- t_src += sizeof(uint8x8x4_t); -- vst4_u8 (t_dst, t1); -- t_dst += sizeof(uint8x8x4_t); -- } -- -- if (count & 1) -- { -- uint8x16_t t1 = vld1q_u8 (t_src); -- -- t_src += sizeof(uint8x16_t); -- vst1q_u8 (t_dst, t1); -- t_dst += sizeof(uint8x16_t); -- } -- --#endif /* !USE_GCC_INLINE_ASM */ -- -- if (trailer_count) -- { -- if (trailer_count & 8) -- { -- uint8x8_t t1 = vld1_u8 (t_src); -- -- t_src += sizeof(uint8x8_t); -- vst1_u8 (t_dst, t1); -- t_dst += sizeof(uint8x8_t); -- } -- -- if (trailer_count & 4) -- { -- *((uint32_t*) t_dst) = *((uint32_t*) t_src); -- -- t_dst += 4; -- t_src += 4; -- } -- -- if (trailer_count & 2) -- { -- *((uint16_t*) t_dst) = *((uint16_t*) t_src); -- -- t_dst += 2; -- t_src += 2; -- } -- -- if (trailer_count & 1) -- { -- *t_dst++ = *t_src++; -- } -- } --} -- --static inline void --solid_over_565_8_pix_neon (uint32_t glyph_colour, -- uint16_t *dest, -- uint8_t * in_mask, -- uint32_t dest_stride, /* bytes, not elements */ -- uint32_t mask_stride, -- uint32_t count /* 8-pixel groups */) --{ -- /* Inner loop of glyph blitter (solid colour, alpha mask) */ -- --#ifdef USE_GCC_INLINE_ASM -- -- asm volatile ( -- " vld4.8 {d20[], d21[], d22[], d23[]}, [%[glyph_colour]] @ splat solid colour components \n" -- "0: @ loop \n" -- " vld1.16 {d0, d1}, [%[dest]] @ load first pixels from framebuffer \n" -- " vld1.8 {d17}, [%[in_mask]] @ load alpha mask of glyph \n" -- " vmull.u8 q9, d17, d23 @ apply glyph colour alpha to mask \n" -- " vshrn.u16 d17, q9, #8 @ reformat it to match original mask \n" -- " vmvn d18, d17 @ we need the inverse mask for the background \n" -- " vsli.u16 q3, q0, #5 @ duplicate framebuffer blue bits \n" -- " vshrn.u16 d2, q0, #8 @ unpack red from framebuffer pixels \n" -- " vshrn.u16 d4, q0, #3 @ unpack green \n" -- " vsri.u8 d2, d2, #5 @ duplicate red bits (extend 5 to 8) \n" -- " vshrn.u16 d6, q3, #2 @ unpack extended blue (truncate 10 to 8) \n" -- " vsri.u8 d4, d4, #6 @ duplicate green bits (extend 6 to 8) \n" -- " vmull.u8 q1, d2, d18 @ apply inverse mask to background red... \n" -- " vmull.u8 q2, d4, d18 @ ...green... \n" -- " vmull.u8 q3, d6, d18 @ ...blue \n" -- " subs %[count], %[count], #1 @ decrement/test loop counter \n" -- " vmlal.u8 q1, d17, d22 @ add masked foreground red... \n" -- " vmlal.u8 q2, d17, d21 @ ...green... \n" -- " vmlal.u8 q3, d17, d20 @ ...blue \n" -- " add %[in_mask], %[in_mask], %[mask_stride] @ advance mask pointer, while we wait \n" -- " vsri.16 q1, q2, #5 @ pack green behind red \n" -- " vsri.16 q1, q3, #11 @ pack blue into pixels \n" -- " vst1.16 {d2, d3}, [%[dest]] @ store composited pixels \n" -- " add %[dest], %[dest], %[dest_stride] @ advance framebuffer pointer \n" -- " bne 0b @ next please \n" -- -- /* Clobbered registers marked as input/outputs */ -- : [dest] "+r" (dest), [in_mask] "+r" (in_mask), [count] "+r" (count) -- -- /* Inputs */ -- : [dest_stride] "r" (dest_stride), [mask_stride] "r" (mask_stride), [glyph_colour] "r" (&glyph_colour) -- -- /* Clobbers, including the inputs we modify, and potentially lots of memory */ -- : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d17", "d18", "d19", -- "d20", "d21", "d22", "d23", "d24", "d25", "cc", "memory" -- ); -- --#else -- -- uint8x8x4_t solid_colour = vld4_dup_u8 ((uint8_t*) &glyph_colour); -- -- while (count--) -- { -- uint16x8_t pixels = vld1q_u16 (dest); -- uint8x8_t mask = vshrn_n_u16 (vmull_u8 (solid_colour.val[3], vld1_u8 (in_mask)), 8); -- uint8x8_t mask_image = vmvn_u8 (mask); -- -- uint8x8_t t_red = vshrn_n_u16 (pixels, 8); -- uint8x8_t t_green = vshrn_n_u16 (pixels, 3); -- uint8x8_t t_blue = vshrn_n_u16 (vsli_n_u8 (pixels, pixels, 5), 2); -- -- uint16x8_t s_red = vmull_u8 (vsri_n_u8 (t_red, t_red, 5), mask_image); -- uint16x8_t s_green = vmull_u8 (vsri_n_u8 (t_green, t_green, 6), mask_image); -- uint16x8_t s_blue = vmull_u8 (t_blue, mask_image); -- -- s_red = vmlal (s_red, mask, solid_colour.val[2]); -- s_green = vmlal (s_green, mask, solid_colour.val[1]); -- s_blue = vmlal (s_blue, mask, solid_colour.val[0]); -- -- pixels = vsri_n_u16 (s_red, s_green, 5); -- pixels = vsri_n_u16 (pixels, s_blue, 11); -- vst1q_u16 (dest, pixels); -- -- dest += dest_stride; -- mask += mask_stride; -- } -- --#endif --} -- --#if 0 /* this is broken currently */ --static void --neon_composite_over_n_8_0565 (pixman_implementation_t * impl, -- pixman_op_t op, -- pixman_image_t * src_image, -- pixman_image_t * mask_image, -- pixman_image_t * dst_image, -- int32_t src_x, -- int32_t src_y, -- int32_t mask_x, -- int32_t mask_y, -- int32_t dest_x, -- int32_t dest_y, -- int32_t width, -- int32_t height) --{ -- uint32_t src, srca; -- uint16_t *dst_line, *aligned_line; -- uint8_t *mask_line; -- uint32_t dst_stride, mask_stride; -- uint32_t kernel_count, copy_count, copy_tail; -- uint8_t kernel_offset, copy_offset; -- -- src = _pixman_image_get_solid (src_image, dst_image->bits.format); -- -- /* bail out if fully transparent or degenerate */ -- srca = src >> 24; -- if (src == 0) -- return; -- -- if (width == 0 || height == 0) -- return; -- -- if (width > NEON_SCANLINE_BUFFER_PIXELS) -- { -- /* split the blit, so we can use a fixed-size scanline buffer -- * TODO: there must be a more elegant way of doing this. -- */ -- int x; -- for (x = 0; x < width; x += NEON_SCANLINE_BUFFER_PIXELS) -- { -- neon_composite_over_n_8_0565 ( -- impl, op, -- src_image, mask_image, dst_image, -- src_x + x, src_y, mask_x + x, mask_y, dest_x + x, dest_y, -- (x + NEON_SCANLINE_BUFFER_PIXELS > width) ? width - x : NEON_SCANLINE_BUFFER_PIXELS, height); -- } -- -- return; -- } -- -- PIXMAN_IMAGE_GET_LINE (dst_image, dest_x, dest_y, uint16_t, dst_stride, dst_line, 1); -- PIXMAN_IMAGE_GET_LINE (mask_image, mask_x, mask_y, uint8_t, mask_stride, mask_line, 1); -- -- /* keep within minimum number of aligned quadwords on width -- * while also keeping the minimum number of columns to process -- */ -- { -- unsigned long aligned_left = (unsigned long)(dst_line) & ~0xF; -- unsigned long aligned_right = (((unsigned long)(dst_line + width)) + 0xF) & ~0xF; -- unsigned long ceiling_length = (((unsigned long) width) * sizeof(*dst_line) + 0xF) & ~0xF; -- -- /* the fast copy should be quadword aligned */ -- copy_offset = dst_line - ((uint16_t*) aligned_left); -- aligned_line = dst_line - copy_offset; -- copy_count = (uint32_t) ((aligned_right - aligned_left) >> 4); -- copy_tail = 0; -- -- if (aligned_right - aligned_left > ceiling_length) -- { -- /* unaligned routine is tightest */ -- kernel_count = (uint32_t) (ceiling_length >> 4); -- kernel_offset = copy_offset; -- } -- else -- { -- /* aligned routine is equally tight, so it is safer to align */ -- kernel_count = copy_count; -- kernel_offset = 0; -- } -- -- /* We should avoid reading beyond scanline ends for safety */ -- if (aligned_line < (dst_line - dest_x) || -- (aligned_line + (copy_count * 16 / sizeof(*dst_line))) > ((dst_line - dest_x) + dst_image->bits.width)) -- { -- /* switch to precise read */ -- copy_offset = kernel_offset = 0; -- aligned_line = dst_line; -- kernel_count = (uint32_t) (ceiling_length >> 4); -- copy_count = (width * sizeof(*dst_line)) >> 4; -- copy_tail = (width * sizeof(*dst_line)) & 0xF; -- } -- } -- -- { -- uint16_t scan_line[NEON_SCANLINE_BUFFER_PIXELS + 8]; /* deliberately not initialised */ -- uint8_t glyph_line[NEON_SCANLINE_BUFFER_PIXELS + 8]; -- int y = height; -- -- /* row-major order */ -- /* left edge, middle block, right edge */ -- for ( ; y--; mask_line += mask_stride, aligned_line += dst_stride, dst_line += dst_stride) -- { -- /* We don't want to overrun the edges of the glyph, -- * so realign the edge data into known buffers -- */ -- neon_quadword_copy (glyph_line + copy_offset, mask_line, width >> 4, width & 0xF); -- -- /* Uncached framebuffer access is really, really slow -- * if we do it piecemeal. It should be much faster if we -- * grab it all at once. One scanline should easily fit in -- * L1 cache, so this should not waste RAM bandwidth. -- */ -- neon_quadword_copy (scan_line, aligned_line, copy_count, copy_tail); -- -- /* Apply the actual filter */ -- solid_over_565_8_pix_neon ( -- src, scan_line + kernel_offset, -- glyph_line + kernel_offset, 8 * sizeof(*dst_line), -- 8, kernel_count); -- -- /* Copy the modified scanline back */ -- neon_quadword_copy (dst_line, scan_line + copy_offset, -- width >> 3, (width & 7) * 2); -- } -- } --} --#endif -- --#ifdef USE_GCC_INLINE_ASM -- --static inline void --plain_over_565_8_pix_neon (uint32_t colour, -- uint16_t *dest, -- uint32_t dest_stride, /* bytes, not elements */ -- uint32_t count /* 8-pixel groups */) --{ -- /* Inner loop for plain translucent rects -- * (solid colour without alpha mask) -- */ -- asm volatile ( -- " vld4.8 {d20[], d21[], d22[], d23[]}, [%[colour]] @ solid colour load/splat \n" -- " vmull.u8 q12, d23, d22 @ premultiply alpha red \n" -- " vmull.u8 q13, d23, d21 @ premultiply alpha green \n" -- " vmull.u8 q14, d23, d20 @ premultiply alpha blue \n" -- " vmvn d18, d23 @ inverse alpha for background \n" -- "0: @ loop\n" -- " vld1.16 {d0, d1}, [%[dest]] @ load first pixels from framebuffer \n" -- " vshrn.u16 d2, q0, #8 @ unpack red from framebuffer pixels \n" -- " vshrn.u16 d4, q0, #3 @ unpack green \n" -- " vsli.u16 q3, q0, #5 @ duplicate framebuffer blue bits \n" -- " vsri.u8 d2, d2, #5 @ duplicate red bits (extend 5 to 8) \n" -- " vsri.u8 d4, d4, #6 @ duplicate green bits (extend 6 to 8) \n" -- " vshrn.u16 d6, q3, #2 @ unpack extended blue (truncate 10 to 8) \n" -- " vmov q0, q12 @ retrieve foreground red \n" -- " vmlal.u8 q0, d2, d18 @ blend red - my kingdom for a four-operand MLA \n" -- " vmov q1, q13 @ retrieve foreground green \n" -- " vmlal.u8 q1, d4, d18 @ blend green \n" -- " vmov q2, q14 @ retrieve foreground blue \n" -- " vmlal.u8 q2, d6, d18 @ blend blue \n" -- " subs %[count], %[count], #1 @ decrement/test loop counter \n" -- " vsri.16 q0, q1, #5 @ pack green behind red \n" -- " vsri.16 q0, q2, #11 @ pack blue into pixels \n" -- " vst1.16 {d0, d1}, [%[dest]] @ store composited pixels \n" -- " add %[dest], %[dest], %[dest_stride] @ advance framebuffer pointer \n" -- " bne 0b @ next please \n" -- -- /* Clobbered registers marked as input/outputs */ -- : [dest] "+r" (dest), [count] "+r" (count) -- -- /* Inputs */ -- : [dest_stride] "r" (dest_stride), [colour] "r" (&colour) -- -- /* Clobbers, including the inputs we modify, and -- * potentially lots of memory -- */ -- : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d18", "d19", -- "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", -- "cc", "memory" -- ); --} -- --static void --neon_composite_over_n_0565 (pixman_implementation_t * impl, -- pixman_op_t op, -- pixman_image_t * src_image, -- pixman_image_t * mask_image, -- pixman_image_t * dst_image, -- int32_t src_x, -- int32_t src_y, -- int32_t mask_x, -- int32_t mask_y, -- int32_t dest_x, -- int32_t dest_y, -- int32_t width, -- int32_t height) --{ -- uint32_t src, srca; -- uint16_t *dst_line, *aligned_line; -- uint32_t dst_stride; -- uint32_t kernel_count, copy_count, copy_tail; -- uint8_t kernel_offset, copy_offset; -- -- src = _pixman_image_get_solid (src_image, dst_image->bits.format); -- -- /* bail out if fully transparent */ -- srca = src >> 24; -- if (src == 0) -- return; -- -- if (width == 0 || height == 0) -- return; -- -- if (width > NEON_SCANLINE_BUFFER_PIXELS) -- { -- /* split the blit, so we can use a fixed-size scanline buffer * -- * TODO: there must be a more elegant way of doing this. -- */ -- int x; -- -- for (x = 0; x < width; x += NEON_SCANLINE_BUFFER_PIXELS) -- { -- neon_composite_over_n_0565 ( -- impl, op, -- src_image, mask_image, dst_image, -- src_x + x, src_y, mask_x + x, mask_y, dest_x + x, dest_y, -- (x + NEON_SCANLINE_BUFFER_PIXELS > width) ? width - x : NEON_SCANLINE_BUFFER_PIXELS, height); -- } -- return; -- } -- -- PIXMAN_IMAGE_GET_LINE (dst_image, dest_x, dest_y, uint16_t, dst_stride, dst_line, 1); -- -- /* keep within minimum number of aligned quadwords on width -- * while also keeping the minimum number of columns to process -- */ -- { -- unsigned long aligned_left = (unsigned long)(dst_line) & ~0xF; -- unsigned long aligned_right = (((unsigned long)(dst_line + width)) + 0xF) & ~0xF; -- unsigned long ceiling_length = (((unsigned long) width) * sizeof(*dst_line) + 0xF) & ~0xF; -- -- /* the fast copy should be quadword aligned */ -- copy_offset = dst_line - ((uint16_t*) aligned_left); -- aligned_line = dst_line - copy_offset; -- copy_count = (uint32_t) ((aligned_right - aligned_left) >> 4); -- copy_tail = 0; -- -- if (aligned_right - aligned_left > ceiling_length) -- { -- /* unaligned routine is tightest */ -- kernel_count = (uint32_t) (ceiling_length >> 4); -- kernel_offset = copy_offset; -- } -- else -- { -- /* aligned routine is equally tight, so it is safer to align */ -- kernel_count = copy_count; -- kernel_offset = 0; -- } -- -- /* We should avoid reading beyond scanline ends for safety */ -- if (aligned_line < (dst_line - dest_x) || -- (aligned_line + (copy_count * 16 / sizeof(*dst_line))) > ((dst_line - dest_x) + dst_image->bits.width)) -- { -- /* switch to precise read */ -- copy_offset = kernel_offset = 0; -- aligned_line = dst_line; -- kernel_count = (uint32_t) (ceiling_length >> 4); -- copy_count = (width * sizeof(*dst_line)) >> 4; -- copy_tail = (width * sizeof(*dst_line)) & 0xF; -- } -- } -- -- { -- uint16_t scan_line[NEON_SCANLINE_BUFFER_PIXELS + 8]; /* deliberately not initialised */ -- -- /* row-major order */ -- /* left edge, middle block, right edge */ -- for ( ; height--; aligned_line += dst_stride, dst_line += dst_stride) -- { -- /* Uncached framebuffer access is really, really slow if we do it piecemeal. -- * It should be much faster if we grab it all at once. -- * One scanline should easily fit in L1 cache, so this should -- * not waste RAM bandwidth. -- */ -- neon_quadword_copy (scan_line, aligned_line, copy_count, copy_tail); -- -- /* Apply the actual filter */ -- plain_over_565_8_pix_neon ( -- src, scan_line + kernel_offset, 8 * sizeof(*dst_line), kernel_count); -- -- /* Copy the modified scanline back */ -- neon_quadword_copy ( -- dst_line, scan_line + copy_offset, width >> 3, (width & 7) * 2); -- } -- } --} -- --static inline void --ARGB8_over_565_8_pix_neon (uint32_t *src, -- uint16_t *dest, -- uint32_t src_stride, /* bytes, not elements */ -- uint32_t count /* 8-pixel groups */) --{ -- asm volatile ( -- "0: @ loop\n" -- " pld [%[src], %[src_stride]] @ preload from next scanline \n" -- " vld1.16 {d0, d1}, [%[dest]] @ load pixels from framebuffer \n" -- " vld4.8 {d20, d21, d22, d23},[%[src]]! @ load source image pixels \n" -- " vsli.u16 q3, q0, #5 @ duplicate framebuffer blue bits \n" -- " vshrn.u16 d2, q0, #8 @ unpack red from framebuffer pixels \n" -- " vshrn.u16 d4, q0, #3 @ unpack green \n" -- " vmvn d18, d23 @ we need the inverse alpha for the background \n" -- " vsri.u8 d2, d2, #5 @ duplicate red bits (extend 5 to 8) \n" -- " vshrn.u16 d6, q3, #2 @ unpack extended blue (truncate 10 to 8) \n" -- " vsri.u8 d4, d4, #6 @ duplicate green bits (extend 6 to 8) \n" -- " vmull.u8 q1, d2, d18 @ apply inverse alpha to background red... \n" -- " vmull.u8 q2, d4, d18 @ ...green... \n" -- " vmull.u8 q3, d6, d18 @ ...blue \n" -- " subs %[count], %[count], #1 @ decrement/test loop counter \n" -- " vmlal.u8 q1, d23, d22 @ add blended foreground red... \n" -- " vmlal.u8 q2, d23, d21 @ ...green... \n" -- " vmlal.u8 q3, d23, d20 @ ...blue \n" -- " vsri.16 q1, q2, #5 @ pack green behind red \n" -- " vsri.16 q1, q3, #11 @ pack blue into pixels \n" -- " vst1.16 {d2, d3}, [%[dest]]! @ store composited pixels \n" -- " bne 0b @ next please \n" -- -- /* Clobbered registers marked as input/outputs */ -- : [dest] "+r" (dest), [src] "+r" (src), [count] "+r" (count) -- -- /* Inputs */ -- : [src_stride] "r" (src_stride) -- -- /* Clobbers, including the inputs we modify, and potentially lots of memory */ -- : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d17", "d18", "d20", -- "d21", "d22", "d23", "cc", "memory" -- ); --} -- --static void --neon_composite_over_8888_0565 (pixman_implementation_t * impl, -- pixman_op_t op, -- pixman_image_t * src_image, -- pixman_image_t * mask_image, -- pixman_image_t * dst_image, -- int32_t src_x, -- int32_t src_y, -- int32_t mask_x, -- int32_t mask_y, -- int32_t dest_x, -- int32_t dest_y, -- int32_t width, -- int32_t height) --{ -- uint32_t *src_line; -- uint16_t *dst_line, *aligned_line; -- uint32_t dst_stride, src_stride; -- uint32_t kernel_count, copy_count, copy_tail; -- uint8_t kernel_offset, copy_offset; -- -- /* we assume mask is opaque -- * so the only alpha to deal with is embedded in src -- */ -- if (width > NEON_SCANLINE_BUFFER_PIXELS) -- { -- /* split the blit, so we can use a fixed-size scanline buffer */ -- int x; -- for (x = 0; x < width; x += NEON_SCANLINE_BUFFER_PIXELS) -- { -- neon_composite_over_8888_0565 ( -- impl, op, -- src_image, mask_image, dst_image, -- src_x + x, src_y, mask_x + x, mask_y, dest_x + x, dest_y, -- (x + NEON_SCANLINE_BUFFER_PIXELS > width) ? width - x : NEON_SCANLINE_BUFFER_PIXELS, height); -- } -- return; -- } -- -- PIXMAN_IMAGE_GET_LINE (dst_image, dest_x, dest_y, uint16_t, dst_stride, dst_line, 1); -- PIXMAN_IMAGE_GET_LINE (src_image, src_x, src_y, uint32_t, src_stride, src_line, 1); -- -- /* keep within minimum number of aligned quadwords on width -- * while also keeping the minimum number of columns to process -- */ -- { -- unsigned long aligned_left = (unsigned long)(dst_line) & ~0xF; -- unsigned long aligned_right = (((unsigned long)(dst_line + width)) + 0xF) & ~0xF; -- unsigned long ceiling_length = (((unsigned long) width) * sizeof(*dst_line) + 0xF) & ~0xF; -- -- /* the fast copy should be quadword aligned */ -- copy_offset = dst_line - ((uint16_t*) aligned_left); -- aligned_line = dst_line - copy_offset; -- copy_count = (uint32_t) ((aligned_right - aligned_left) >> 4); -- copy_tail = 0; -- -- if (aligned_right - aligned_left > ceiling_length) -- { -- /* unaligned routine is tightest */ -- kernel_count = (uint32_t) (ceiling_length >> 4); -- kernel_offset = copy_offset; -- } -- else -- { -- /* aligned routine is equally tight, so it is safer to align */ -- kernel_count = copy_count; -- kernel_offset = 0; -- } -- -- /* We should avoid reading beyond scanline ends for safety */ -- if (aligned_line < (dst_line - dest_x) || -- (aligned_line + (copy_count * 16 / sizeof(*dst_line))) > ((dst_line - dest_x) + dst_image->bits.width)) -- { -- /* switch to precise read */ -- copy_offset = kernel_offset = 0; -- aligned_line = dst_line; -- kernel_count = (uint32_t) (ceiling_length >> 4); -- copy_count = (width * sizeof(*dst_line)) >> 4; -- copy_tail = (width * sizeof(*dst_line)) & 0xF; -- } -- } -- -- /* Preload the first input scanline */ -- { -- uint8_t *src_ptr = (uint8_t*) src_line; -- uint32_t count = (width + 15) / 16; -- --#ifdef USE_GCC_INLINE_ASM -- asm volatile ( -- "0: @ loop \n" -- " subs %[count], %[count], #1 \n" -- " pld [%[src]] \n" -- " add %[src], %[src], #64 \n" -- " bgt 0b \n" -- -- /* Clobbered input registers marked as input/outputs */ -- : [src] "+r" (src_ptr), [count] "+r" (count) -- : /* no unclobbered inputs */ -- : "cc" -- ); --#else -- do -- { -- __pld (src_ptr); -- src_ptr += 64; -- } -- while (--count); --#endif -- } -- -- { -- uint16_t scan_line[NEON_SCANLINE_BUFFER_PIXELS + 8]; /* deliberately not initialised */ -- -- /* row-major order */ -- /* left edge, middle block, right edge */ -- for ( ; height--; src_line += src_stride, aligned_line += dst_stride) -- { -- /* Uncached framebuffer access is really, really slow if we do -- * it piecemeal. It should be much faster if we grab it all at -- * once. One scanline should easily fit in L1 cache, so this -- * should not waste RAM bandwidth. -- */ -- neon_quadword_copy (scan_line, aligned_line, copy_count, copy_tail); -- -- /* Apply the actual filter */ -- ARGB8_over_565_8_pix_neon ( -- src_line, scan_line + kernel_offset, -- src_stride * sizeof(*src_line), kernel_count); -- -- /* Copy the modified scanline back */ -- neon_quadword_copy (dst_line, -- scan_line + copy_offset, -- width >> 3, (width & 7) * 2); -- } -- } --} -- --#endif /* USE_GCC_INLINE_ASM */ -- - static const pixman_fast_path_t arm_neon_fast_path_array[] = - { - { PIXMAN_OP_ADD, PIXMAN_solid, PIXMAN_a8, PIXMAN_a8, neon_composite_add_n_8_8, 0 }, -@@ -2618,12 +1914,6 @@ static const pixman_fast_path_t arm_neon_fast_path_array[] = - #ifdef USE_GCC_INLINE_ASM - { PIXMAN_OP_SRC, PIXMAN_r5g6b5, PIXMAN_null, PIXMAN_r5g6b5, neon_composite_src_16_16, 0 }, - { PIXMAN_OP_SRC, PIXMAN_b5g6r5, PIXMAN_null, PIXMAN_b5g6r5, neon_composite_src_16_16, 0 }, --#if 0 /* this code has some bugs */ -- { PIXMAN_OP_OVER, PIXMAN_solid, PIXMAN_null, PIXMAN_r5g6b5, neon_composite_over_n_0565, 0 }, -- { PIXMAN_OP_OVER, PIXMAN_solid, PIXMAN_null, PIXMAN_b5g6r5, neon_composite_over_n_0565, 0 }, -- { PIXMAN_OP_OVER, PIXMAN_a8r8g8b8, PIXMAN_null, PIXMAN_r5g6b5, neon_composite_over_8888_0565, 0 }, -- { PIXMAN_OP_OVER, PIXMAN_a8b8g8r8, PIXMAN_null, PIXMAN_b5g6r5, neon_composite_over_8888_0565, 0 }, --#endif - #endif - { PIXMAN_OP_OVER, PIXMAN_a8r8g8b8, PIXMAN_null, PIXMAN_a8r8g8b8, neon_composite_over_8888_8888, 0 }, - { PIXMAN_OP_OVER, PIXMAN_a8r8g8b8, PIXMAN_null, PIXMAN_x8r8g8b8, neon_composite_over_8888_8888, 0 }, -@@ -2674,79 +1964,6 @@ arm_neon_composite (pixman_implementation_t *imp, - } - - static pixman_bool_t --pixman_blt_neon (void *src_bits, -- void *dst_bits, -- int src_stride, -- int dst_stride, -- int src_bpp, -- int dst_bpp, -- int src_x, -- int src_y, -- int dst_x, -- int dst_y, -- int width, -- int height) --{ -- if (!width || !height) -- return TRUE; -- -- /* accelerate only straight copies involving complete bytes */ -- if (src_bpp != dst_bpp || (src_bpp & 7)) -- return FALSE; -- -- { -- uint32_t bytes_per_pixel = src_bpp >> 3; -- uint32_t byte_width = width * bytes_per_pixel; -- /* parameter is in words for some reason */ -- int32_t src_stride_bytes = src_stride * 4; -- int32_t dst_stride_bytes = dst_stride * 4; -- uint8_t *src_bytes = ((uint8_t*) src_bits) + -- src_y * src_stride_bytes + src_x * bytes_per_pixel; -- uint8_t *dst_bytes = ((uint8_t*) dst_bits) + -- dst_y * dst_stride_bytes + dst_x * bytes_per_pixel; -- uint32_t quadword_count = byte_width / 16; -- uint32_t offset = byte_width % 16; -- -- while (height--) -- { -- neon_quadword_copy (dst_bytes, src_bytes, quadword_count, offset); -- src_bytes += src_stride_bytes; -- dst_bytes += dst_stride_bytes; -- } -- } -- -- return TRUE; --} -- --static pixman_bool_t --arm_neon_blt (pixman_implementation_t *imp, -- uint32_t * src_bits, -- uint32_t * dst_bits, -- int src_stride, -- int dst_stride, -- int src_bpp, -- int dst_bpp, -- int src_x, -- int src_y, -- int dst_x, -- int dst_y, -- int width, -- int height) --{ -- if (pixman_blt_neon ( -- src_bits, dst_bits, src_stride, dst_stride, src_bpp, dst_bpp, -- src_x, src_y, dst_x, dst_y, width, height)) -- { -- return TRUE; -- } -- -- return _pixman_implementation_blt ( -- imp->delegate, -- src_bits, dst_bits, src_stride, dst_stride, src_bpp, dst_bpp, -- src_x, src_y, dst_x, dst_y, width, height); --} -- --static pixman_bool_t - arm_neon_fill (pixman_implementation_t *imp, - uint32_t * bits, - int stride, -@@ -2771,9 +1988,6 @@ _pixman_implementation_create_arm_neon (void) - pixman_implementation_t *imp = _pixman_implementation_create (general); - - imp->composite = arm_neon_composite; --#if 0 /* this code has some bugs */ -- imp->blt = arm_neon_blt; --#endif - imp->fill = arm_neon_fill; - - return imp; --- -1.6.2.4 - diff --git a/recipes/xorg-lib/pixman/0002-ARM-Introduction-of-the-new-framework-for-NEON-fast.patch b/recipes/xorg-lib/pixman/0002-ARM-Introduction-of-the-new-framework-for-NEON-fast.patch deleted file mode 100644 index af0a8aa7a0..0000000000 --- a/recipes/xorg-lib/pixman/0002-ARM-Introduction-of-the-new-framework-for-NEON-fast.patch +++ /dev/null @@ -1,1061 +0,0 @@ -From d9d9173581331a3bf7e5d123db32025588b7f044 Mon Sep 17 00:00:00 2001 -From: Siarhei Siamashka -Date: Sat, 10 Oct 2009 00:20:51 +0300 -Subject: [PATCH 2/7] ARM: Introduction of the new framework for NEON fast path optimizations - -GNU assembler and its macro preprocessor is now used to generate -NEON optimized functions from a common template. This automatically -takes care of nuisances like ensuring optimal alignment, dealing with -leading/trailing pixels, doing prefetch, etc. - -As the first use for this framework, this commit also includes an -implementation of pixman_composite_over_8888_0565_asm_neon function. ---- - configure.ac | 1 + - pixman/Makefile.am | 4 +- - pixman/pixman-arm-neon-asm.S | 309 +++++++++++++++++++++ - pixman/pixman-arm-neon-asm.h | 620 ++++++++++++++++++++++++++++++++++++++++++ - pixman/pixman-arm-neon.c | 55 ++++ - 5 files changed, 988 insertions(+), 1 deletions(-) - create mode 100644 pixman/pixman-arm-neon-asm.S - create mode 100644 pixman/pixman-arm-neon-asm.h - -diff --git a/configure.ac b/configure.ac -index c548174..522af15 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -71,6 +71,7 @@ AC_CANONICAL_HOST - test_CFLAGS=${CFLAGS+set} # We may override autoconf default CFLAGS. - - AC_PROG_CC -+AM_PROG_AS - AC_PROG_LIBTOOL - AC_CHECK_FUNCS([getisax]) - AC_C_BIGENDIAN -diff --git a/pixman/Makefile.am b/pixman/Makefile.am -index 6020623..2543c6a 100644 ---- a/pixman/Makefile.am -+++ b/pixman/Makefile.am -@@ -109,7 +109,9 @@ endif - if USE_ARM_NEON - noinst_LTLIBRARIES += libpixman-arm-neon.la - libpixman_arm_neon_la_SOURCES = \ -- pixman-arm-neon.c -+ pixman-arm-neon.c \ -+ pixman-arm-neon-asm.S \ -+ pixman-arm-neon-asm.h - libpixman_arm_neon_la_CFLAGS = $(DEP_CFLAGS) $(ARM_NEON_CFLAGS) - libpixman_arm_neon_la_LIBADD = $(DEP_LIBS) - libpixman_1_la_LIBADD += libpixman-arm-neon.la -diff --git a/pixman/pixman-arm-neon-asm.S b/pixman/pixman-arm-neon-asm.S -new file mode 100644 -index 0000000..843899f ---- /dev/null -+++ b/pixman/pixman-arm-neon-asm.S -@@ -0,0 +1,309 @@ -+/* -+ * Copyright © 2009 Nokia Corporation -+ * -+ * Permission to use, copy, modify, distribute, and sell this software and its -+ * documentation for any purpose is hereby granted without fee, provided that -+ * the above copyright notice appear in all copies and that both that -+ * copyright notice and this permission notice appear in supporting -+ * documentation, and that the name of Nokia Corporation not be used in -+ * advertising or publicity pertaining to distribution of the software without -+ * specific, written prior permission. Nokia Corporation makes no -+ * representations about the suitability of this software for any purpose. -+ * It is provided "as is" without express or implied warranty. -+ * -+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS -+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY -+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN -+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING -+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -+ * SOFTWARE. -+ * -+ * Author: Siarhei Siamashka (siarhei.siamashka@nokia.com) -+ */ -+ -+/* Prevent the stack from becoming executable for no reason... */ -+#if defined(__linux__) && defined(__ELF__) -+.section .note.GNU-stack,"",%progbits -+#endif -+ -+ .text -+ .fpu neon -+ .altmacro -+ -+#include "pixman-arm-neon-asm.h" -+ -+/* -+ * This file contains implementations of NEON optimized pixel processing -+ * functions functions. There is no full and detailed tutorial, but some -+ * functions (those which are exposing some new or interesting features) -+ * are extensively commented and can be used as examples. -+ * -+ * You may want to have a look at the following functions: -+ * - pixman_composite_over_8888_0565_asm_neon -+ */ -+ -+/* -+ * Implementation of pixman_composite_over_8888_0565_asm_neon -+ * -+ * This function takes a8r8g8b8 source buffer, r5g6b5 destination buffer and -+ * performs OVER compositing operation. Function fast_composite_over_8888_0565 -+ * from pixman-fast-path.c does the same in C and can be used as a reference. -+ * -+ * First we need to have some NEON assembly code which can do the actual -+ * operation on the pixels and provide it to the template macro -+ * -+ * Template macro quite conveniently takes care of all the necessary code for -+ * memory reading and writing (including quite tricky cases of handling -+ * unaligned leading/trailing pixels), so we only need to deal with the data -+ * in NEON registers. -+ * -+ * NEON registers allocation in general is recommented to be the following: -+ * d0, d1, d2, d3 - contain loaded source pixel data -+ * d4, d5, d6, d7 - contain loaded destination pixels (if they are needed) -+ * d24, d25, d26, d27 - contain loading mask pixel data (if mask is used) -+ * d28, d29, d30, d31 - place for storing the result (destination pixels) -+ * -+ * As can be seen above, four 64-bit NEON registers are used for keeping -+ * intermediate pixel data and up to 8 pixels can be processed in one step -+ * for 32bpp formats (16 pixels for 16bpp, 32 pixels for 8bpp). -+ * -+ * This particular function uses the following allocation: -+ * d0, d1, d2, d3 - contain loaded source pixel data -+ * d4, d5 - contain loaded destination pixels (they are needed) -+ * d28, d29 - place for storing the result (destination pixels) -+ */ -+ -+/* -+ * Step one. We need to have some code to do some arithmetics on pixel data. -+ * This is implemented as a pair of macros: '*_head' and '*_tail'. When used -+ * back-to-back, they take pixel data from {d0, d1, d2, d3} and {d4, d5}, -+ * perform all the needed calculations and write the result to {d28, d29}. -+ * The rationale for having two macros and not just one will be explained -+ * later. In practice, any single monolitic function which does the work can -+ * be split into two parts in any arbitrary way without affecting correctness. -+ * -+ * There is one special trick here too. Common template macro already makes -+ * our life a bit easier by doing R, G, B, A color components deinterleaving -+ * for 32bpp pixel formats. So it means that instead of having 8 packed -+ * pixels in {d0, d1, d2, d3} registers, we actually use d0 register for -+ * blue channel (a vector of eight 8-bit values), d1 register for green, -+ * d2 for red and d3 for alpha. There is no magic and simple conversion -+ * can be done with a few NEON instructions. -+ * -+ * Packed to planar conversion: -+ * vuzp.8 d0, d1 -+ * vuzp.8 d2, d3 -+ * vuzp.8 d1, d3 -+ * vuzp.8 d0, d2 -+ * -+ * Planar to packed conversion: -+ * vzip.8 d0, d2 -+ * vzip.8 d1, d3 -+ * vzip.8 d2, d3 -+ * vzip.8 d0, d1 -+ * -+ * Pixel can be loaded directly in planar format using VLD4.8 NEON -+ * instruction. But it is 1 cycle slower than VLD1.32 and sometimes -+ * code can be scheduled so that four extra VUZP.8 after VLD1.32 may -+ * be dual-issued with the other instructions resulting in overal -+ * 1 cycle improvement. -+ * -+ * But anyway, here is the code: -+ */ -+.macro pixman_composite_over_8888_0565_process_pixblock_head -+ /* convert 8 r5g6b5 pixel data from {d4, d5} to planar 8-bit format -+ and put data into d6 - red, d7 - green, d30 - blue */ -+ vshrn.u16 d6, q2, #8 -+ vshrn.u16 d7, q2, #3 -+ vsli.u16 q2, q2, #5 -+ vsri.u8 d6, d6, #5 -+ vmvn.8 d3, d3 /* invert source alpha */ -+ vsri.u8 d7, d7, #6 -+ vshrn.u16 d30, q2, #2 -+ /* now do alpha blending, storing results in 8-bit planar format -+ into d16 - red, d19 - green, d18 - blue */ -+ vmull.u8 q10, d3, d6 -+ vmull.u8 q11, d3, d7 -+ vmull.u8 q12, d3, d30 -+ vrshr.u16 q13, q10, #8 -+ vrshr.u16 q3, q11, #8 -+ vrshr.u16 q15, q12, #8 -+ vraddhn.u16 d20, q10, q13 -+ vraddhn.u16 d23, q11, q3 -+ vraddhn.u16 d22, q12, q15 -+.endm -+ -+.macro pixman_composite_over_8888_0565_process_pixblock_tail -+ /* ... continue alpha blending */ -+ vqadd.u8 d16, d2, d20 -+ vqadd.u8 q9, q0, q11 -+ /* convert the result to r5g6b5 and store it into {d28, d29} */ -+ vshll.u8 q14, d16, #8 -+ vshll.u8 q8, d19, #8 -+ vshll.u8 q9, d18, #8 -+ vsri.u16 q14, q8, #5 -+ vsri.u16 q14, q9, #11 -+.endm -+ -+/* -+ * OK, now we got almost everything that we need. Using the above two -+ * macros, the work can be done right. But now we want to optimize -+ * it a bit. ARM Cortex-A8 is an in-order core, and benefits really -+ * a lot from good code scheduling and software pipelining. -+ * -+ * Let's construct some code, which will run in the core main loop. -+ * Some pseudo-code of the main loop will look like this: -+ * head -+ * while (...) { -+ * tail -+ * head -+ * } -+ * tail -+ * -+ * It may look a bit weird, but this setup allows to hide instruction -+ * latencies better and also utilize dual-issue capability more efficiently. -+ * -+ * So what we need now is a '*_tail_head' macro, which will be used -+ * in the core main loop. A trivial straightforward implementation -+ * of this macro would look like this: -+ * -+ * pixman_composite_over_8888_0565_process_pixblock_tail -+ * vst1.16 {d28, d29}, [DST_W, :128]! -+ * vld1.16 {d4, d5}, [DST_R, :128]! -+ * vld4.32 {d0, d1, d2, d3}, [SRC]! -+ * pixman_composite_over_8888_0565_process_pixblock_head -+ * cache_preload 8, 8 -+ * -+ * Now it also got some VLD/VST instructions. We simply can't move from -+ * processing one block of pixels to the other one with just arithmetics. -+ * The previously processed data needs to be written to memory and new -+ * data needs to be fetched. Fortunately, this main loop does not deal -+ * with partial leading/trailing pixels and can load/store a full block -+ * of pixels in a bulk. Additionally, destination buffer is 16 bytes -+ * aligned here (which is good for performance). -+ * -+ * New things here are DST_R, DST_W, SRC and MASK identifiers. These -+ * are the aliases for ARM registers which are used as pointers for -+ * accessing data. We maintain separate pointers for reading and writing -+ * destination buffer. -+ * -+ * Another new thing is 'cache_preload' macro. It is used for prefetching -+ * data into CPU cache and improve performance when dealing with large -+ * images which are far larger than cache size. It uses one argument -+ * (actually two, but they need to be the same here) - number of pixels -+ * in a block. Looking into 'pixman-arm-neon-asm.h' can provide some -+ * details about this macro. Moreover, if good performance is needed -+ * the code from this macro needs to be copied into '*_tail_head' macro -+ * and mixed with the rest of code for optimal instructions scheduling. -+ * We are actually doing it below. -+ * -+ * Now after all the explanations, here is the optimized code. -+ * Different instruction streams (originaling from '*_head', '*_tail' -+ * and 'cache_preload' macro) use different indentation levels for -+ * better readability. Actually taking the code from one of these -+ * indentation levels and ignoring a few VLD/VST instructions would -+ * result in exactly the code from '*_head', '*_tail' or 'cache_preload' -+ * macro! -+ */ -+ -+#if 1 -+ -+.macro pixman_composite_over_8888_0565_process_pixblock_tail_head -+ vqadd.u8 d16, d2, d20 -+ vld1.16 {d4, d5}, [DST_R, :128]! -+ vqadd.u8 q9, q0, q11 -+ vshrn.u16 d6, q2, #8 -+ vld4.8 {d0, d1, d2, d3}, [SRC]! -+ vshrn.u16 d7, q2, #3 -+ vsli.u16 q2, q2, #5 -+ vshll.u8 q14, d16, #8 -+ add PF_X, PF_X, #8 -+ vshll.u8 q8, d19, #8 -+ tst PF_CTL, #0xF -+ vsri.u8 d6, d6, #5 -+ addne PF_X, PF_X, #8 -+ vmvn.8 d3, d3 -+ subne PF_CTL, PF_CTL, #1 -+ vsri.u8 d7, d7, #6 -+ vshrn.u16 d30, q2, #2 -+ vmull.u8 q10, d3, d6 -+ pld [PF_SRC, PF_X, lsl #src_bpp_shift] -+ vmull.u8 q11, d3, d7 -+ vmull.u8 q12, d3, d30 -+ pld [PF_DST, PF_X, lsl #dst_bpp_shift] -+ vsri.u16 q14, q8, #5 -+ cmp PF_X, ORIG_W -+ vshll.u8 q9, d18, #8 -+ vrshr.u16 q13, q10, #8 -+ subge PF_X, PF_X, ORIG_W -+ vrshr.u16 q3, q11, #8 -+ vrshr.u16 q15, q12, #8 -+ subges PF_CTL, PF_CTL, #0x10 -+ vsri.u16 q14, q9, #11 -+ ldrgeb DUMMY, [PF_SRC, SRC_STRIDE, lsl #src_bpp_shift]! -+ vraddhn.u16 d20, q10, q13 -+ vraddhn.u16 d23, q11, q3 -+ ldrgeb DUMMY, [PF_DST, DST_STRIDE, lsl #dst_bpp_shift]! -+ vraddhn.u16 d22, q12, q15 -+ vst1.16 {d28, d29}, [DST_W, :128]! -+.endm -+ -+#else -+ -+/* If we did not care much about the performance, we would just use this... */ -+.macro pixman_composite_over_8888_0565_process_pixblock_tail_head -+ pixman_composite_over_8888_0565_process_pixblock_tail -+ vst1.16 {d28, d29}, [DST_W, :128]! -+ vld1.16 {d4, d5}, [DST_R, :128]! -+ vld4.32 {d0, d1, d2, d3}, [SRC]! -+ pixman_composite_over_8888_0565_process_pixblock_head -+ cache_preload 8, 8 -+.endm -+ -+#endif -+ -+/* -+ * And now the final part. We are using 'generate_composite_function' macro -+ * to put all the stuff together. We are specifying the name of the function -+ * which we want to get, number of bits per pixel for the source, mask and -+ * destination (0 if unused, like mask in this case). Next come some bit -+ * flags: -+ * FLAG_DST_READWRITE - tells that the destination buffer is both read -+ * and written, for write-only buffer we would use -+ * FLAG_DST_WRITEONLY flag instead -+ * FLAG_DEINTERLEAVE_32BPP - tells that we prefer to work with planar data -+ * and separate color channels for 32bpp format. -+ * The next things are: -+ * - the number of pixels processed per iteration (8 in this case, because -+ * that' the maximum what can fit into four 64-bit NEON registers). -+ * - prefetch distance, measured in pixel blocks. In this case it is 5 times -+ * by 8 pixels. That would be 40 pixels, or up to 160 bytes. Optimal -+ * prefetch distance can be selected by running some benchmarks. -+ * -+ * After that we specify some macros, these are 'default_init', -+ * 'default_cleanup' (it is possible to have custom init/cleanup to be -+ * able to save/restore some extra NEON registers like d8-d15 or do -+ * anything else) followed by -+ * 'pixman_composite_over_8888_0565_process_pixblock_head', -+ * 'pixman_composite_over_8888_0565_process_pixblock_tail' and -+ * 'pixman_composite_over_8888_0565_process_pixblock_tail_head' -+ * which we got implemented above. -+ * -+ * The last part is the NEON registers allocation scheme. -+ */ -+generate_composite_function \ -+ pixman_composite_over_8888_0565_asm_neon, 32, 0, 16, \ -+ FLAG_DST_READWRITE | FLAG_DEINTERLEAVE_32BPP, \ -+ 8, /* number of pixels, processed in a single block */ \ -+ 5, /* prefetch distance */ \ -+ default_init, \ -+ default_cleanup, \ -+ pixman_composite_over_8888_0565_process_pixblock_head, \ -+ pixman_composite_over_8888_0565_process_pixblock_tail, \ -+ pixman_composite_over_8888_0565_process_pixblock_tail_head, \ -+ 28, /* dst_w_basereg */ \ -+ 4, /* dst_r_basereg */ \ -+ 0, /* src_basereg */ \ -+ 24 /* mask_basereg */ -diff --git a/pixman/pixman-arm-neon-asm.h b/pixman/pixman-arm-neon-asm.h -new file mode 100644 -index 0000000..d276ab9 ---- /dev/null -+++ b/pixman/pixman-arm-neon-asm.h -@@ -0,0 +1,620 @@ -+/* -+ * Copyright © 2009 Nokia Corporation -+ * -+ * Permission to use, copy, modify, distribute, and sell this software and its -+ * documentation for any purpose is hereby granted without fee, provided that -+ * the above copyright notice appear in all copies and that both that -+ * copyright notice and this permission notice appear in supporting -+ * documentation, and that the name of Nokia Corporation not be used in -+ * advertising or publicity pertaining to distribution of the software without -+ * specific, written prior permission. Nokia Corporation makes no -+ * representations about the suitability of this software for any purpose. -+ * It is provided "as is" without express or implied warranty. -+ * -+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS -+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY -+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN -+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING -+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -+ * SOFTWARE. -+ * -+ * Author: Siarhei Siamashka (siarhei.siamashka@nokia.com) -+ */ -+ -+/* -+ * This file contains a macro ('generate_composite_function') which can -+ * construct 2D image processing functions, based on a common template. -+ * Any combinations of source, destination and mask images with 8bpp, -+ * 16bpp, 32bpp color formats are supported. -+ * -+ * This macro takes care of: -+ * - handling of leading and trailing unaligned pixels -+ * - doing most of the work related to L2 cache preload -+ * - encourages the use of software pipelining for better instructions -+ * scheduling -+ * -+ * The user of this macro has to provide some configuration parameters -+ * (bit depths for the images, prefetch distance, etc.) and a set of -+ * macros, which should implement basic code chunks responsible for -+ * pixels processing. See 'pixman-arm-neon-asm.S' file for the usage -+ * examples. -+ * -+ * TODO: -+ * - support for 24bpp formats -+ * - try overlapped pixel method (from Ian Rickards) when processing -+ * exactly two blocks of pixels -+ */ -+ -+.set FLAG_DST_WRITEONLY, 0 -+.set FLAG_DST_READWRITE, 1 -+.set FLAG_DEINTERLEAVE_32BPP, 2 -+ -+/* -+ * It is possible to set this to 0 and improve performance a bit if unaligned -+ * memory accesses are supported -+ */ -+#define RESPECT_STRICT_ALIGNMENT 1 -+ -+/* -+ * Definitions of supplementary pixld/pixst macros (for partial load/store of -+ * pixel data) -+ */ -+ -+.macro pixldst1 op, elem_size, reg1, mem_operand, abits -+.if abits > 0 -+ op&.&elem_size {d®1}, [&mem_operand&, :&abits&]! -+.else -+ op&.&elem_size {d®1}, [&mem_operand&]! -+.endif -+.endm -+ -+.macro pixldst2 op, elem_size, reg1, reg2, mem_operand, abits -+.if abits > 0 -+ op&.&elem_size {d®1, d®2}, [&mem_operand&, :&abits&]! -+.else -+ op&.&elem_size {d®1, d®2}, [&mem_operand&]! -+.endif -+.endm -+ -+.macro pixldst4 op, elem_size, reg1, reg2, reg3, reg4, mem_operand, abits -+.if abits > 0 -+ op&.&elem_size {d®1, d®2, d®3, d®4}, [&mem_operand&, :&abits&]! -+.else -+ op&.&elem_size {d®1, d®2, d®3, d®4}, [&mem_operand&]! -+.endif -+.endm -+ -+.macro pixldst0 op, elem_size, reg1, idx, mem_operand, abits -+ op&.&elem_size {d®1[idx]}, [&mem_operand&]! -+.endm -+ -+.macro pixldst numbytes, op, elem_size, basereg, mem_operand, abits -+.if numbytes == 32 -+ pixldst4 op, elem_size, %(basereg+4), %(basereg+5), \ -+ %(basereg+6), %(basereg+7), mem_operand, abits -+.elseif numbytes == 16 -+ pixldst2 op, elem_size, %(basereg+2), %(basereg+3), mem_operand, abits -+.elseif numbytes == 8 -+ pixldst1 op, elem_size, %(basereg+1), mem_operand, abits -+.elseif numbytes == 4 -+ .if !RESPECT_STRICT_ALIGNMENT || (elem_size == 32) -+ pixldst0 op, 32, %(basereg+0), 1, mem_operand, abits -+ .elseif elem_size == 16 -+ pixldst0 op, 16, %(basereg+0), 2, mem_operand, abits -+ pixldst0 op, 16, %(basereg+0), 3, mem_operand, abits -+ .else -+ pixldst0 op, 8, %(basereg+0), 4, mem_operand, abits -+ pixldst0 op, 8, %(basereg+0), 5, mem_operand, abits -+ pixldst0 op, 8, %(basereg+0), 6, mem_operand, abits -+ pixldst0 op, 8, %(basereg+0), 7, mem_operand, abits -+ .endif -+.elseif numbytes == 2 -+ .if !RESPECT_STRICT_ALIGNMENT || (elem_size == 16) -+ pixldst0 op, 16, %(basereg+0), 1, mem_operand, abits -+ .else -+ pixldst0 op, 8, %(basereg+0), 2, mem_operand, abits -+ pixldst0 op, 8, %(basereg+0), 3, mem_operand, abits -+ .endif -+.elseif numbytes == 1 -+ pixldst0 op, 8, %(basereg+0), 1, mem_operand, abits -+.else -+ .error "unsupported size: numbytes" -+.endif -+.endm -+ -+.macro pixld numpix, bpp, basereg, mem_operand, abits=0 -+.if bpp > 0 -+.if (bpp == 32) && (numpix == 8) && (DEINTERLEAVE_32BPP_ENABLED != 0) -+ pixldst4 vld4, 8, %(basereg+4), %(basereg+5), \ -+ %(basereg+6), %(basereg+7), mem_operand, abits -+.else -+ pixldst %(numpix * bpp / 8), vld1, %(bpp), basereg, mem_operand, abits -+.endif -+.endif -+.endm -+ -+.macro pixst numpix, bpp, basereg, mem_operand, abits=0 -+.if bpp > 0 -+.if (bpp == 32) && (numpix == 8) && (DEINTERLEAVE_32BPP_ENABLED != 0) -+ pixldst4 vst4, 8, %(basereg+4), %(basereg+5), \ -+ %(basereg+6), %(basereg+7), mem_operand, abits -+.else -+ pixldst %(numpix * bpp / 8), vst1, %(bpp), basereg, mem_operand, abits -+.endif -+.endif -+.endm -+ -+.macro pixld_a numpix, bpp, basereg, mem_operand -+.if (bpp * numpix) <= 128 -+ pixld numpix, bpp, basereg, mem_operand, %(bpp * numpix) -+.else -+ pixld numpix, bpp, basereg, mem_operand, 128 -+.endif -+.endm -+ -+.macro pixst_a numpix, bpp, basereg, mem_operand -+.if (bpp * numpix) <= 128 -+ pixst numpix, bpp, basereg, mem_operand, %(bpp * numpix) -+.else -+ pixst numpix, bpp, basereg, mem_operand, 128 -+.endif -+.endm -+ -+.macro vuzp8 reg1, reg2 -+ vuzp.8 d®1, d®2 -+.endm -+ -+.macro vzip8 reg1, reg2 -+ vzip.8 d®1, d®2 -+.endm -+ -+/* deinterleave B, G, R, A channels for eight 32bpp pixels in 4 registers */ -+.macro pixdeinterleave bpp, basereg -+.if (bpp == 32) && (DEINTERLEAVE_32BPP_ENABLED != 0) -+ vuzp8 %(basereg+0), %(basereg+1) -+ vuzp8 %(basereg+2), %(basereg+3) -+ vuzp8 %(basereg+1), %(basereg+3) -+ vuzp8 %(basereg+0), %(basereg+2) -+.endif -+.endm -+ -+/* interleave B, G, R, A channels for eight 32bpp pixels in 4 registers */ -+.macro pixinterleave bpp, basereg -+.if (bpp == 32) && (DEINTERLEAVE_32BPP_ENABLED != 0) -+ vzip8 %(basereg+0), %(basereg+2) -+ vzip8 %(basereg+1), %(basereg+3) -+ vzip8 %(basereg+2), %(basereg+3) -+ vzip8 %(basereg+0), %(basereg+1) -+.endif -+.endm -+ -+/* -+ * This is a macro for implementing cache preload. The main idea is that -+ * cache preload logic is mostly independent from the rest of pixels -+ * processing code. It starts at the top left pixel and moves forward -+ * across pixels and can jump across lines. Prefetch distance is handled -+ * in an 'incremental' way: it starts from 0 and advances to the optimal -+ * distance over time. After reaching optimal prefetch distance, it is -+ * kept constant. There are some checks which prevent prefetching -+ * unneeded pixel lines below the image (but it still prefetch a bit -+ * more data on the right side of the image - not a big issue and may -+ * be actually helpful when rendering text glyphs). Additional trick is -+ * the use of LDR instruction for prefetch instead of PLD when moving to -+ * the next line, the point is that we have a high chance of getting TLB -+ * miss in this case, and PLD would be useless. -+ * -+ * This sounds like it may introduce a noticeable overhead (when working with -+ * fully cached data). But in reality, due to having a separate pipeline and -+ * instruction queue for NEON unit in ARM Cortex-A8, normal ARM code can -+ * execute simultaneously with NEON and be completely shadowed by it. Thus -+ * we get no performance overhead at all (*). This looks like a very nice -+ * feature of Cortex-A8, if used wisely. We don't have a hardware hardware -+ * prefetcher, but still can implement some rather advanced prefetch logic -+ * in sofware for almost zero cost! -+ * -+ * (*) The overhead of the prefetcher is visible when running some trivial -+ * pixels processing like simple copy. Anyway, having prefetch is a must -+ * when working with graphics data. -+ */ -+.macro cache_preload std_increment, boost_increment -+.if (src_bpp_shift >= 0) || (dst_r_bpp != 0) || (mask_bpp_shift >= 0) -+.if regs_shortage -+ ldr ORIG_W, [sp] /* If we are short on regs, ORIG_W is kept on stack */ -+.endif -+.if std_increment != 0 -+ add PF_X, PF_X, #std_increment -+.endif -+ tst PF_CTL, #0xF -+ addne PF_X, PF_X, #boost_increment -+ subne PF_CTL, PF_CTL, #1 -+ cmp PF_X, ORIG_W -+.if src_bpp_shift >= 0 -+ pld [PF_SRC, PF_X, lsl #src_bpp_shift] -+.endif -+.if dst_r_bpp != 0 -+ pld [PF_DST, PF_X, lsl #dst_bpp_shift] -+.endif -+.if mask_bpp_shift >= 0 -+ pld [PF_MASK, PF_X, lsl #mask_bpp_shift] -+.endif -+ subge PF_X, PF_X, ORIG_W -+ subges PF_CTL, PF_CTL, #0x10 -+.if src_bpp_shift >= 0 -+ ldrgeb DUMMY, [PF_SRC, SRC_STRIDE, lsl #src_bpp_shift]! -+.endif -+.if dst_r_bpp != 0 -+ ldrgeb DUMMY, [PF_DST, DST_STRIDE, lsl #dst_bpp_shift]! -+.endif -+.if mask_bpp_shift >= 0 -+ ldrgeb DUMMY, [PF_MASK, MASK_STRIDE, lsl #mask_bpp_shift]! -+.endif -+.endif -+.endm -+ -+/* -+ * Registers are allocated in the following way by default: -+ * d0, d1, d2, d3 - reserved for loading source pixel data -+ * d4, d5, d6, d7 - reserved for loading destination pixel data -+ * d24, d25, d26, d27 - reserved for loading mask pixel data -+ * d28, d29, d30, d31 - final destination pixel data for writeback to memory -+ */ -+.macro generate_composite_function fname, \ -+ src_bpp, \ -+ mask_bpp, \ -+ dst_w_bpp, \ -+ flags, \ -+ pixblock_size, \ -+ prefetch_distance, \ -+ init, \ -+ cleanup, \ -+ process_pixblock_head, \ -+ process_pixblock_tail, \ -+ process_pixblock_tail_head, \ -+ dst_w_basereg = 28, \ -+ dst_r_basereg = 4, \ -+ src_basereg = 0, \ -+ mask_basereg = 24 -+ -+ .global fname -+fname: -+ -+ W .req r0 /* width (is updated during processing) */ -+ H .req r1 /* height (is updated during processing) */ -+ DST_W .req r2 /* destination buffer pointer for writes */ -+ DST_STRIDE .req r3 /* destination image stride */ -+ SRC .req r4 /* source buffer pointer */ -+ SRC_STRIDE .req r5 /* source image stride */ -+ DST_R .req r6 /* destination buffer pointer for reads */ -+ -+ MASK .req r7 /* mask pointer */ -+ MASK_STRIDE .req r8 /* mask stride */ -+ -+ PF_CTL .req r9 -+ PF_X .req r10 -+ PF_SRC .req r11 -+ PF_DST .req r12 -+ PF_MASK .req r14 -+ -+.if mask_bpp == 0 -+ ORIG_W .req r7 /* saved original width */ -+ DUMMY .req r8 /* temporary register */ -+ .set regs_shortage, 0 -+.elseif src_bpp == 0 -+ ORIG_W .req r4 /* saved original width */ -+ DUMMY .req r5 /* temporary register */ -+ .set regs_shortage, 0 -+.else -+ ORIG_W .req r1 /* saved original width */ -+ DUMMY .req r1 /* temporary register */ -+ .set regs_shortage, 1 -+.endif -+ -+ push {r4-r12, lr} -+ -+ .set mask_bpp_shift, -1 -+ -+.if src_bpp == 32 -+ .set src_bpp_shift, 2 -+.elseif src_bpp == 16 -+ .set src_bpp_shift, 1 -+.elseif src_bpp == 8 -+ .set src_bpp_shift, 0 -+.elseif src_bpp == 0 -+ .set src_bpp_shift, -1 -+.else -+ .error "requested src bpp (src_bpp) is not supported" -+.endif -+.if mask_bpp == 32 -+ .set mask_bpp_shift, 2 -+.elseif mask_bpp == 8 -+ .set mask_bpp_shift, 0 -+.elseif mask_bpp == 0 -+ .set mask_bpp_shift, -1 -+.else -+ .error "requested mask bpp (mask_bpp) is not supported" -+.endif -+.if dst_w_bpp == 32 -+ .set dst_bpp_shift, 2 -+.elseif dst_w_bpp == 16 -+ .set dst_bpp_shift, 1 -+.elseif dst_w_bpp == 8 -+ .set dst_bpp_shift, 0 -+.else -+ .error "requested dst bpp (dst_w_bpp) is not supported" -+.endif -+ -+.if (((flags) & FLAG_DST_READWRITE) != 0) -+ .set dst_r_bpp, dst_w_bpp -+.else -+ .set dst_r_bpp, 0 -+.endif -+.if (((flags) & FLAG_DEINTERLEAVE_32BPP) != 0) -+ .set DEINTERLEAVE_32BPP_ENABLED, 1 -+.else -+ .set DEINTERLEAVE_32BPP_ENABLED, 0 -+.endif -+ -+.if prefetch_distance < 0 || prefetch_distance > 15 -+ .error "invalid prefetch distance (prefetch_distance)" -+.endif -+ -+.if src_bpp > 0 -+ ldr SRC, [sp, #40] -+.end