From 0b207ae11065c740f2644a89fc13207a5343554e Mon Sep 17 00:00:00 2001 From: Antoine Azar Date: Sun, 6 Apr 2008 10:56:53 -0400 Subject: [PATCH] Optimize operators based on source or dest opacity. Check if we can replace our operator by a simpler one if the src or dest are opaque The output operator should be mathematically equivalent to the source. --- pixman/pixman-combine.c | 3 +- pixman/pixman-image.c | 84 +++++++++++++++++++++++++++++++++ pixman/pixman-pict.c | 121 ++++++++++++++++++++++++++++++++++-------------- pixman/pixman-private.h | 6 +++ 4 files changed, 179 insertions(+), 35 deletions(-) diff --git a/pixman/pixman-combine.c b/pixman/pixman-combine.c index be08af4..d201736 100644 --- a/pixman/pixman-combine.c +++ b/pixman/pixman-combine.c @@ -13,7 +13,6 @@ * this difference will have two versions using the same convention. */ - /* * Combine src and mask */ @@ -1210,6 +1209,7 @@ static CombineFuncU pixman_fbCombineFuncU[] = { fbCombineConjointAtopU, fbCombineConjointAtopReverseU, fbCombineConjointXorU, + NULL /* Noop */ }; static CombineFuncC pixman_fbCombineFuncC[] = { @@ -1257,6 +1257,7 @@ static CombineFuncC pixman_fbCombineFuncC[] = { fbCombineConjointAtopC, fbCombineConjointAtopReverseC, fbCombineConjointXorC, + NULL /* Noop */ }; FbComposeFunctions pixman_composeFunctions = { diff --git a/pixman/pixman-image.c b/pixman/pixman-image.c index 9b6846e..30c294b 100644 --- a/pixman/pixman-image.c +++ b/pixman/pixman-image.c @@ -717,3 +717,87 @@ pixman_image_fill_rectangles (pixman_op_t op, return TRUE; } + +pixman_bool_t +pixman_image_can_get_solid (pixman_image_t *image) +{ + if (image->type == SOLID) + return TRUE; + + if (image->type != BITS || + image->bits.width != 1 || + image->bits.height != 1) + { + return FALSE; + } + + if (image->common.repeat != PIXMAN_REPEAT_NORMAL) + return FALSE; + + switch (image->bits.format) + { + case PIXMAN_a8r8g8b8: + case PIXMAN_x8r8g8b8: + case PIXMAN_a8b8g8r8: + case PIXMAN_x8b8g8r8: + case PIXMAN_r8g8b8: + case PIXMAN_b8g8r8: + case PIXMAN_r5g6b5: + case PIXMAN_b5g6r5: + return TRUE; + default: + return FALSE; + } +} + +pixman_bool_t +pixman_image_is_opaque(pixman_image_t *image) +{ + int i = 0; + int gradientNumberOfColors = 0; + + if(image->common.alpha_map) + return FALSE; + + switch(image->type) + { + case BITS: + if(PIXMAN_FORMAT_A(image->bits.format)) + return FALSE; + break; + + case LINEAR: + case CONICAL: + case RADIAL: + gradientNumberOfColors = image->gradient.n_stops; + i=0; + while(igradient.stops[i].color.alpha != 0xffff) + return FALSE; + i++; + } + break; + + case SOLID: + if(Alpha(image->solid.color) != 0xff) + return FALSE; + break; + } + + /* Convolution filters can introduce translucency if the sum of the weights + is lower than 1. */ + if (image->common.filter == PIXMAN_FILTER_CONVOLUTION) + return FALSE; + + if (image->common.repeat == PIXMAN_REPEAT_NONE) + { + if (image->common.filter != PIXMAN_FILTER_NEAREST) + return FALSE; + + if (image->common.transform) + return FALSE; + } + + return TRUE; +} \ No newline at end of file diff --git a/pixman/pixman-pict.c b/pixman/pixman-pict.c index b7c0773..f01a643 100644 --- a/pixman/pixman-pict.c +++ b/pixman/pixman-pict.c @@ -1261,38 +1261,6 @@ pixman_walk_composite_region (pixman_op_t op, pixman_region_fini (®); } -static pixman_bool_t -can_get_solid (pixman_image_t *image) -{ - if (image->type == SOLID) - return TRUE; - - if (image->type != BITS || - image->bits.width != 1 || - image->bits.height != 1) - { - return FALSE; - } - - if (image->common.repeat != PIXMAN_REPEAT_NORMAL) - return FALSE; - - switch (image->bits.format) - { - case PIXMAN_a8r8g8b8: - case PIXMAN_x8r8g8b8: - case PIXMAN_a8b8g8r8: - case PIXMAN_x8b8g8r8: - case PIXMAN_r8g8b8: - case PIXMAN_b8g8r8: - case PIXMAN_r5g6b5: - case PIXMAN_b5g6r5: - return TRUE; - default: - return FALSE; - } -} - #define SCANLINE_BUFFER_LENGTH 2048 static void @@ -1554,7 +1522,7 @@ get_fast_path (const FastPathInfo *fast_paths, if (info->op != op) continue; - if ((info->src_format == PIXMAN_solid && can_get_solid (pSrc)) || + if ((info->src_format == PIXMAN_solid && pixman_image_can_get_solid (pSrc)) || (pSrc->type == BITS && info->src_format == pSrc->bits.format)) { valid_src = TRUE; @@ -1596,6 +1564,82 @@ get_fast_path (const FastPathInfo *fast_paths, return NULL; } +/* + * Operator optimizations based on source or destination opacity + */ +typedef struct +{ + pixman_op_t op; + pixman_op_t opSrcDstOpaque; + pixman_op_t opSrcOpaque; + pixman_op_t opDstOpaque; +} OptimizedOperatorInfo; + +static const OptimizedOperatorInfo optimized_operators[] = +{ + /* Input Operator SRC&DST Opaque SRC Opaque DST Opaque */ + { PIXMAN_OP_OVER, PIXMAN_OP_SRC, PIXMAN_OP_SRC, PIXMAN_OP_OVER }, + { PIXMAN_OP_OVER_REVERSE, PIXMAN_OP_DST, PIXMAN_OP_OVER_REVERSE, PIXMAN_OP_DST }, + { PIXMAN_OP_IN, PIXMAN_OP_SRC, PIXMAN_OP_IN, PIXMAN_OP_SRC }, + { PIXMAN_OP_IN_REVERSE, PIXMAN_OP_DST, PIXMAN_OP_DST, PIXMAN_OP_IN_REVERSE }, + { PIXMAN_OP_OUT, PIXMAN_OP_CLEAR, PIXMAN_OP_OUT, PIXMAN_OP_CLEAR }, + { PIXMAN_OP_OUT_REVERSE, PIXMAN_OP_CLEAR, PIXMAN_OP_CLEAR, PIXMAN_OP_OUT_REVERSE }, + { PIXMAN_OP_ATOP, PIXMAN_OP_SRC, PIXMAN_OP_IN, PIXMAN_OP_OVER }, + { PIXMAN_OP_ATOP_REVERSE, PIXMAN_OP_DST, PIXMAN_OP_OVER_REVERSE, PIXMAN_OP_IN_REVERSE }, + { PIXMAN_OP_XOR, PIXMAN_OP_CLEAR, PIXMAN_OP_OUT, PIXMAN_OP_OUT_REVERSE }, + { PIXMAN_OP_SATURATE, PIXMAN_OP_DST, PIXMAN_OP_OVER_REVERSE, PIXMAN_OP_DST }, + { PIXMAN_OP_NONE } +}; + + +/* + * Check if the current operator could be optimized + */ +static const OptimizedOperatorInfo* +pixman_operator_can_be_optimized(pixman_op_t op) +{ + const OptimizedOperatorInfo *info; + + for (info = optimized_operators; info->op != PIXMAN_OP_NONE; info++) + { + if(info->op == op) + return info; + } + return NULL; +} + +/* + * Optimize the current operator based on opacity of source or destination + * The output operator should be mathematically equivalent to the source. + */ +static pixman_op_t +pixman_optimize_operator(pixman_op_t op, pixman_image_t *pSrc, pixman_image_t *pMask, pixman_image_t *pDst ) +{ + pixman_bool_t is_source_opaque; + pixman_bool_t is_dest_opaque; + const OptimizedOperatorInfo *info = pixman_operator_can_be_optimized(op); + + if(!info || pMask) + return op; + + is_source_opaque = pixman_image_is_opaque(pSrc); + is_dest_opaque = pixman_image_is_opaque(pDst); + + if(is_source_opaque == FALSE && is_dest_opaque == FALSE) + return op; + + if(is_source_opaque && is_dest_opaque) + return info->opSrcDstOpaque; + else if(is_source_opaque) + return info->opSrcOpaque; + else if(is_dest_opaque) + return info->opDstOpaque; + + return op; + +} + + void pixman_image_composite (pixman_op_t op, pixman_image_t * pSrc, @@ -1652,7 +1696,15 @@ pixman_image_composite (pixman_op_t op, } } - if ((pSrc->type == BITS || can_get_solid (pSrc)) && (!pMask || pMask->type == BITS) + /* + * Check if we can replace our operator by a simpler one if the src or dest are opaque + * The output operator should be mathematically equivalent to the source. + */ + op = pixman_optimize_operator(op, pSrc, pMask, pDst); + if(op == PIXMAN_OP_DST) + return; + + if ((pSrc->type == BITS || pixman_image_can_get_solid (pSrc)) && (!pMask || pMask->type == BITS) && !srcTransform && !maskTransform && !maskAlphaMap && !srcAlphaMap && !dstAlphaMap && (pSrc->common.filter != PIXMAN_FILTER_CONVOLUTION) @@ -1753,6 +1805,7 @@ pixman_image_composite (pixman_op_t op, } + #ifdef USE_MMX /* The CPU detection code needs to be in a file not compiled with * "-mmmx -msse", as gcc would generate CMOV instructions otherwise diff --git a/pixman/pixman-private.h b/pixman/pixman-private.h index 2da0b41..e236767 100644 --- a/pixman/pixman-private.h +++ b/pixman/pixman-private.h @@ -837,6 +837,12 @@ pixman_rasterize_edges_accessors (pixman_image_t *image, pixman_fixed_t t, pixman_fixed_t b); +pixman_bool_t +pixman_image_is_opaque(pixman_image_t *image); + +pixman_bool_t +pixman_image_can_get_solid (pixman_image_t *image); + #ifdef PIXMAN_TIMING -- 2.7.4