From fc0b28bf6af81428b7ac045614eea97fbf9c4a70 Mon Sep 17 00:00:00 2001 From: Aaron Plattner Date: Fri, 6 Jun 2008 18:05:15 -0700 Subject: [PATCH] Add wide source picture, external alpha, and transformed image routines. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The wide external alpha path should work correctly with wide formats. The wide transformed fetch code for now just does a 32-bit fetch and then expands, which will lose precision. Source pictures, for now, are evaluated at depth 32 and then are expanded to depth 64. We could get higher precision by evaluating them directly at depth 64, but this should be good enough for now. Signed-off-by: Søren Sandmann Pedersen --- pixman/pixman-compose.c | 87 +++++++++++++++++++++++++++++-------- pixman/pixman-private.h | 19 +++++++++ pixman/pixman-source.c | 28 ++++++++++++ pixman/pixman-transformed.c | 102 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 218 insertions(+), 18 deletions(-) diff --git a/pixman/pixman-compose.c b/pixman/pixman-compose.c index c5773eb..812e70d 100644 --- a/pixman/pixman-compose.c +++ b/pixman/pixman-compose.c @@ -174,6 +174,62 @@ typedef void (*scanStoreProc)(pixman_image_t *, int, int, int, uint32_t *); typedef void (*scanFetchProc)(pixman_image_t *, int, int, int, uint32_t *, uint32_t *, uint32_t); +static inline scanFetchProc get_fetch_source_pict(const int wide) +{ + if (wide) + return (scanFetchProc)pixmanFetchSourcePict64; + else + return (scanFetchProc)pixmanFetchSourcePict; +} + +static inline scanFetchProc get_fetch_solid(const int wide) +{ + if (wide) + return (scanFetchProc)fbFetchSolid64; + else + return (scanFetchProc)fbFetchSolid; +} + +static inline scanFetchProc get_fetch(const int wide) +{ + if (wide) + return (scanFetchProc)fbFetch64; + else + return (scanFetchProc)fbFetch; +} + +static inline scanFetchProc get_fetch_external_alpha(const int wide) +{ + if (wide) + return (scanFetchProc)ACCESS(fbFetchExternalAlpha64); + else + return (scanFetchProc)ACCESS(fbFetchExternalAlpha); +} + +static inline scanFetchProc get_fetch_transformed(const int wide) +{ + if (wide) + return (scanFetchProc)ACCESS(fbFetchTransformed64); + else + return (scanFetchProc)ACCESS(fbFetchTransformed); +} + +static inline scanStoreProc get_store(const int wide) +{ + if (wide) + return (scanStoreProc)fbStore64; + else + return (scanStoreProc)fbStore; +} + +static inline scanStoreProc get_store_external_alpha(const int wide) +{ + if (wide) + return (scanStoreProc)ACCESS(fbStoreExternalAlpha64); + else + return (scanStoreProc)ACCESS(fbStoreExternalAlpha); +} + #ifndef PIXMAN_FB_ACCESSORS static #endif @@ -195,7 +251,7 @@ PIXMAN_COMPOSITE_RECT_GENERAL (const FbComposeData *data, fetchSrc = NULL; else if (IS_SOURCE_IMAGE (data->src)) { - fetchSrc = (scanFetchProc)pixmanFetchSourcePict; + fetchSrc = get_fetch_source_pict(wide); srcClass = SourcePictureClassify ((source_image_t *)data->src, data->xSrc, data->ySrc, data->width, data->height); @@ -206,25 +262,23 @@ PIXMAN_COMPOSITE_RECT_GENERAL (const FbComposeData *data, if (bits->common.alpha_map) { - // TODO: Need wide external alpha routine. - fetchSrc = (scanFetchProc)ACCESS(fbFetchExternalAlpha); + fetchSrc = get_fetch_external_alpha(wide); } else if ((bits->common.repeat == PIXMAN_REPEAT_NORMAL || bits->common.repeat == PIXMAN_REPEAT_PAD) && bits->width == 1 && bits->height == 1) { - fetchSrc = wide ? (scanFetchProc)fbFetchSolid64 : (scanFetchProc)fbFetchSolid; + fetchSrc = get_fetch_solid(wide); srcClass = SOURCE_IMAGE_CLASS_HORIZONTAL; } else if (!bits->common.transform && bits->common.filter != PIXMAN_FILTER_CONVOLUTION && bits->common.repeat != PIXMAN_REPEAT_PAD) { - fetchSrc = wide ? (scanFetchProc)fbFetch64 : (scanFetchProc)fbFetch; + fetchSrc = get_fetch(wide); } else { - // TODO: Need wide transformed fetch. - fetchSrc = (scanFetchProc)ACCESS(fbFetchTransformed); + fetchSrc = get_fetch_transformed(wide); } } @@ -247,37 +301,34 @@ PIXMAN_COMPOSITE_RECT_GENERAL (const FbComposeData *data, if (bits->common.alpha_map) { - // TODO: Need wide external alpha routine. - fetchMask = (scanFetchProc)ACCESS(fbFetchExternalAlpha); + fetchMask = get_fetch_external_alpha(wide); } else if ((bits->common.repeat == PIXMAN_REPEAT_NORMAL || bits->common.repeat == PIXMAN_REPEAT_PAD) && bits->width == 1 && bits->height == 1) { - fetchMask = wide ? (scanFetchProc)fbFetchSolid64 : (scanFetchProc)fbFetchSolid; + fetchMask = get_fetch_solid(wide); maskClass = SOURCE_IMAGE_CLASS_HORIZONTAL; } else if (!bits->common.transform && bits->common.filter != PIXMAN_FILTER_CONVOLUTION && bits->common.repeat != PIXMAN_REPEAT_PAD) - fetchMask = wide ? (scanFetchProc)fbFetch64 : (scanFetchProc)fbFetch; + fetchMask = get_fetch(wide); else - // TODO: Need wide transformed fetch. - fetchMask = (scanFetchProc)ACCESS(fbFetchTransformed); + fetchMask = get_fetch_transformed(wide); } } if (data->dest->common.alpha_map) { - // TODO: Need wide external alpha routine. - fetchDest = (scanFetchProc)ACCESS(fbFetchExternalAlpha); - store = (scanStoreProc)ACCESS(fbStoreExternalAlpha); + fetchDest = get_fetch_external_alpha(wide); + store = get_store_external_alpha(wide); if (data->op == PIXMAN_OP_CLEAR || data->op == PIXMAN_OP_SRC) fetchDest = NULL; } else { - fetchDest = wide ? (scanFetchProc)fbFetch64 : (scanFetchProc)fbFetch; - store = wide ? (scanStoreProc)fbStore64 : (scanStoreProc)fbStore; + fetchDest = get_fetch(wide); + store = get_store(wide); switch (data->op) { diff --git a/pixman/pixman-private.h b/pixman/pixman-private.h index 5a2f89e..fa1311d 100644 --- a/pixman/pixman-private.h +++ b/pixman/pixman-private.h @@ -219,6 +219,8 @@ void pixman_contract(uint32_t *dst, const uint64_t *src, int width); void pixmanFetchSourcePict(source_image_t *, int x, int y, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits); +void pixmanFetchSourcePict64(source_image_t *, int x, int y, int width, + uint64_t *buffer, uint64_t *mask, uint32_t maskBits); void fbFetchTransformed(bits_image_t *, int x, int y, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits); @@ -236,6 +238,22 @@ void fbFetchExternalAlpha_accessors(bits_image_t *, int x, int y, int width, uint32_t *buffer, uint32_t *mask, uint32_t maskBits); +void fbFetchTransformed64(bits_image_t *, int x, int y, int width, + uint64_t *buffer, uint64_t *mask, uint32_t maskBits); +void fbStoreExternalAlpha64(bits_image_t *, int x, int y, int width, + uint64_t *buffer); +void fbFetchExternalAlpha64(bits_image_t *, int x, int y, int width, + uint64_t *buffer, uint64_t *mask, uint32_t maskBits); + +void fbFetchTransformed64_accessors(bits_image_t *, int x, int y, int width, + uint64_t *buffer, uint64_t *mask, + uint32_t maskBits); +void fbStoreExternalAlpha64_accessors(bits_image_t *, int x, int y, int width, + uint64_t *buffer); +void fbFetchExternalAlpha64_accessors(bits_image_t *, int x, int y, int width, + uint64_t *buffer, uint64_t *mask, + uint32_t maskBits); + /* end */ typedef enum @@ -469,6 +487,7 @@ union pixman_image (uint32_t) ((uint8_t) ((t) | (0 - ((t) >> 8)))) << (i)) #define div_255(x) (((x) + 0x80 + (((x) + 0x80) >> 8)) >> 8) +#define div_65535(x) (((x) + 0x8000 + (((x) + 0x8000) >> 16)) >> 16) #define MOD(a,b) ((a) < 0 ? ((b) - ((-(a) - 1) % (b))) - 1 : (a) % (b)) diff --git a/pixman/pixman-source.c b/pixman/pixman-source.c index a5a4235..6a640fa 100644 --- a/pixman/pixman-source.c +++ b/pixman/pixman-source.c @@ -27,6 +27,7 @@ #include #endif +#include #include #include "pixman-private.h" @@ -679,3 +680,30 @@ void pixmanFetchSourcePict(source_image_t * pict, int x, int y, int width, } } } + +/* + * For now, just evaluate the source picture at 32bpp and expand. We could + * produce smoother gradients by evaluating them at higher color depth, but + * that's a project for the future. + */ +void pixmanFetchSourcePict64(source_image_t * pict, int x, int y, int width, + uint64_t *buffer, uint64_t *mask, uint32_t maskBits) +{ + uint32_t *mask8 = NULL; + + // Contract the mask image, if one exists, so that the 32-bit fetch function + // can use it. + if (mask) { + mask8 = pixman_malloc_ab(width, sizeof(uint32_t)); + pixman_contract(mask8, mask, width); + } + + // Fetch the source image into the first half of buffer. + pixmanFetchSourcePict(pict, x, y, width, (uint32_t*)buffer, mask8, + maskBits); + + // Expand from 32bpp to 64bpp in place. + pixman_expand(buffer, (uint32_t*)buffer, PIXMAN_a8r8g8b8, width); + + free(mask8); +} diff --git a/pixman/pixman-transformed.c b/pixman/pixman-transformed.c index cff1ba2..9f566bf 100644 --- a/pixman/pixman-transformed.c +++ b/pixman/pixman-transformed.c @@ -2,6 +2,7 @@ * * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. * 2005 Lars Knoll & Zack Rusin, Trolltech + * 2008 Aaron Plattner, NVIDIA Corporation * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -36,6 +37,11 @@ #define Green(x) (((x) >> 8) & 0xff) #define Blue(x) ((x) & 0xff) +#define Alpha64(x) ((x) >> 48) +#define Red64(x) (((x) >> 32) & 0xffff) +#define Green64(x) (((x) >> 16) & 0xffff) +#define Blue64(x) ((x) & 0xffff) + /* * Fetch from region strategies */ @@ -632,6 +638,30 @@ ACCESS(fbFetchTransformed)(bits_image_t * pict, int x, int y, int width, } } +void +ACCESS(fbFetchTransformed64)(bits_image_t * pict, int x, int y, int width, + uint64_t *buffer, uint64_t *mask, uint32_t maskBits) +{ + // TODO: Don't lose precision for wide pictures! + uint32_t *mask8 = NULL; + + // Contract the mask image, if one exists, so that the 32-bit fetch function + // can use it. + if (mask) { + mask8 = pixman_malloc_ab(width, sizeof(uint32_t)); + pixman_contract(mask8, mask, width); + } + + // Fetch the image into the first half of buffer. + ACCESS(fbFetchTransformed)(pict, x, y, width, (uint32_t*)buffer, mask8, + maskBits); + + // Expand from 32bpp to 64bpp in place. + pixman_expand(buffer, (uint32_t*)buffer, pict->format, width); + + free(mask8); +} + #define SCANLINE_BUFFER_LENGTH 2048 void @@ -670,6 +700,45 @@ ACCESS(fbFetchExternalAlpha)(bits_image_t * pict, int x, int y, int width, } void +ACCESS(fbFetchExternalAlpha64)(bits_image_t * pict, int x, int y, int width, + uint64_t *buffer, uint64_t *mask, + uint32_t maskBits) +{ + int i; + uint64_t _alpha_buffer[SCANLINE_BUFFER_LENGTH]; + uint64_t *alpha_buffer = _alpha_buffer; + uint64_t maskBits64; + + if (!pict->common.alpha_map) { + ACCESS(fbFetchTransformed64) (pict, x, y, width, buffer, mask, maskBits); + return; + } + if (width > SCANLINE_BUFFER_LENGTH) + alpha_buffer = (uint64_t *) pixman_malloc_ab (width, sizeof(uint64_t)); + + ACCESS(fbFetchTransformed64)(pict, x, y, width, buffer, mask, maskBits); + ACCESS(fbFetchTransformed64)((bits_image_t *)pict->common.alpha_map, x - pict->common.alpha_origin.x, + y - pict->common.alpha_origin.y, width, + alpha_buffer, mask, maskBits); + + pixman_expand(&maskBits64, &maskBits, PIXMAN_a8r8g8b8, 1); + + for (i = 0; i < width; ++i) { + if (!mask || mask[i] & maskBits64) + { + int64_t a = alpha_buffer[i]>>48; + *(buffer + i) = (a << 48) + | (div_65535(Red64(*(buffer + i)) * a) << 32) + | (div_65535(Green64(*(buffer + i)) * a) << 16) + | (div_65535(Blue64(*(buffer + i)) * a)); + } + } + + if (alpha_buffer != _alpha_buffer) + free(alpha_buffer); +} + +void ACCESS(fbStoreExternalAlpha)(bits_image_t * pict, int x, int y, int width, uint32_t *buffer) { @@ -710,3 +779,36 @@ ACCESS(fbStoreExternalAlpha)(bits_image_t * pict, int x, int y, int width, alpha_bits, buffer, ax - pict->common.alpha_origin.x, width, aindexed); } +void +ACCESS(fbStoreExternalAlpha64)(bits_image_t * pict, int x, int y, int width, + uint64_t *buffer) +{ + uint32_t *bits, *alpha_bits; + int32_t stride, astride; + int ax, ay; + storeProc64 store; + storeProc64 astore; + const pixman_indexed_t * indexed = pict->indexed; + const pixman_indexed_t * aindexed; + + store = ACCESS(pixman_storeProcForPicture64)(pict); + astore = ACCESS(pixman_storeProcForPicture64)(pict->common.alpha_map); + aindexed = pict->common.alpha_map->indexed; + + ax = x; + ay = y; + + bits = pict->bits; + stride = pict->rowstride; + + alpha_bits = pict->common.alpha_map->bits; + astride = pict->common.alpha_map->rowstride; + + bits += y*stride; + alpha_bits += (ay - pict->common.alpha_origin.y)*astride; + + + store((pixman_image_t *)pict, bits, buffer, x, width, indexed); + astore((pixman_image_t *)pict->common.alpha_map, + alpha_bits, buffer, ax - pict->common.alpha_origin.x, width, aindexed); +} -- 2.7.4