Add wide source picture, external alpha, and transformed image routines.
authorAaron Plattner <aplattner@nvidia.com>
Sat, 7 Jun 2008 01:05:15 +0000 (18:05 -0700)
committerSøren Sandmann Pedersen <sandmann@redhat.com>
Fri, 13 Jun 2008 04:11:37 +0000 (00:11 -0400)
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 <sandmann@redhat.com>
pixman/pixman-compose.c
pixman/pixman-private.h
pixman/pixman-source.c
pixman/pixman-transformed.c

index c5773eba3ff5960a4f23b887e618969c58baeed6..812e70dd14b4d41ae8b33007b4f85b16b22628a9 100644 (file)
@@ -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)
        {
index 5a2f89e0c5cc8cf653e58dc5bfca5af7459dc5b4..fa1311d0f5480040a42f5c85fe2a98980ad6339d 100644 (file)
@@ -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))
 
index a5a4235870e0bf86c7ef8ff0574c6a5ed0c42793..6a640fa67f9302cd40ca6bfafa68bfb0f1db01e7 100644 (file)
@@ -27,6 +27,7 @@
 #include <config.h>
 #endif
 
+#include <stdlib.h>
 #include <math.h>
 
 #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);
+}
index cff1ba2259091c0c43e7e153de01a0892192940d..9f566bfc5cd5737f52b2f4879bd9cb9387cfc892 100644 (file)
@@ -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
 #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
@@ -669,6 +699,45 @@ ACCESS(fbFetchExternalAlpha)(bits_image_t * pict, int x, int y, int width,
         free(alpha_buffer);
 }
 
+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);
+}