summaryrefslogtreecommitdiffstats
path: root/bltsville/gcbv/mirror/gcparser.c
diff options
context:
space:
mode:
Diffstat (limited to 'bltsville/gcbv/mirror/gcparser.c')
-rw-r--r--bltsville/gcbv/mirror/gcparser.c2090
1 files changed, 2090 insertions, 0 deletions
diff --git a/bltsville/gcbv/mirror/gcparser.c b/bltsville/gcbv/mirror/gcparser.c
new file mode 100644
index 0000000..5bfbdb6
--- /dev/null
+++ b/bltsville/gcbv/mirror/gcparser.c
@@ -0,0 +1,2090 @@
+/*
+ * Copyright(c) 2012,
+ * Texas Instruments, Inc. and Vivante Corporation.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Vivante Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "gcbv.h"
+
+#define GCZONE_NONE 0
+#define GCZONE_ALL (~0U)
+#define GCZONE_FORMAT (1 << 0)
+#define GCZONE_FORMAT_VERBOSE (1 << 1)
+#define GCZONE_BLEND (1 << 2)
+#define GCZONE_OFFSET (1 << 3)
+#define GCZONE_DEST (1 << 4)
+#define GCZONE_SRC (1 << 5)
+#define GCZONE_SCALING (1 << 6)
+
+GCDBG_FILTERDEF(parser, GCZONE_NONE,
+ "format",
+ "formatverbose",
+ "blend",
+ "offset",
+ "dest",
+ "src",
+ "scaling")
+
+
+/*******************************************************************************
+ * Internal macros.
+ */
+
+#define GCCONVERT_RECT(zone, name, bvrect, gcrect) \
+{ \
+ (gcrect)->left = (bvrect)->left; \
+ (gcrect)->top = (bvrect)->top; \
+ (gcrect)->right = (bvrect)->left + (bvrect)->width; \
+ (gcrect)->bottom = (bvrect)->top + (bvrect)->height; \
+ \
+ GCPRINT_RECT(zone, name, gcrect); \
+}
+
+
+/*******************************************************************************
+ * Pixel format parser.
+ */
+
+#define OCDFMTDEF_PLACEMENT_SHIFT 9
+#define OCDFMTDEF_PLACEMENT_MASK (3 << OCDFMTDEF_PLACEMENT_SHIFT)
+
+#define BVCOMP(Shift, Size) \
+ { Shift, Size, ((1 << Size) - 1) << Shift }
+
+#define BVRED(Shift, Size) \
+ BVCOMP(Shift, Size)
+
+#define BVGREEN(Shift, Size) \
+ BVCOMP(Shift, Size)
+
+#define BVBLUE(Shift, Size) \
+ BVCOMP(Shift, Size)
+
+#define BVALPHA(Shift, Size) \
+ BVCOMP(Shift, Size)
+
+static const unsigned int rgba16swizzle[] = {
+ GCREG_DE_SWIZZLE_ARGB,
+ GCREG_DE_SWIZZLE_RGBA,
+ GCREG_DE_SWIZZLE_ABGR,
+ GCREG_DE_SWIZZLE_BGRA
+};
+
+static const unsigned int rgb16swizzle[] = {
+ GCREG_DE_SWIZZLE_ARGB,
+ GCREG_DE_SWIZZLE_ARGB,
+ GCREG_DE_SWIZZLE_ABGR,
+ GCREG_DE_SWIZZLE_ABGR
+};
+
+static const unsigned int rgba32swizzle[] = {
+ GCREG_DE_SWIZZLE_BGRA,
+ GCREG_DE_SWIZZLE_ABGR,
+ GCREG_DE_SWIZZLE_RGBA,
+ GCREG_DE_SWIZZLE_ARGB
+};
+
+static const struct bvcsrgb xrgb4444_bits[] = {
+ { BVRED(8, 4), BVGREEN(4, 4), BVBLUE(0, 4), BVALPHA(12, 0) },
+ { BVRED(12, 4), BVGREEN(8, 4), BVBLUE(4, 4), BVALPHA(0, 0) },
+ { BVRED(0, 4), BVGREEN(4, 4), BVBLUE(8, 4), BVALPHA(12, 0) },
+ { BVRED(4, 4), BVGREEN(8, 4), BVBLUE(12, 4), BVALPHA(0, 0) }
+};
+
+static const struct bvcsrgb argb4444_bits[] = {
+ { BVRED(8, 4), BVGREEN(4, 4), BVBLUE(0, 4), BVALPHA(12, 4) },
+ { BVRED(12, 4), BVGREEN(8, 4), BVBLUE(4, 4), BVALPHA(0, 4) },
+ { BVRED(0, 4), BVGREEN(4, 4), BVBLUE(8, 4), BVALPHA(12, 4) },
+ { BVRED(4, 4), BVGREEN(8, 4), BVBLUE(12, 4), BVALPHA(0, 4) }
+};
+
+static const struct bvcsrgb xrgb1555_bits[] = {
+ { BVRED(10, 5), BVGREEN(5, 5), BVBLUE(0, 5), BVALPHA(15, 0) },
+ { BVRED(11, 5), BVGREEN(6, 5), BVBLUE(1, 5), BVALPHA(0, 0) },
+ { BVRED(0, 5), BVGREEN(5, 5), BVBLUE(10, 5), BVALPHA(15, 0) },
+ { BVRED(1, 5), BVGREEN(6, 5), BVBLUE(11, 5), BVALPHA(0, 0) }
+};
+
+static const struct bvcsrgb argb1555_bits[] = {
+ { BVRED(10, 5), BVGREEN(5, 5), BVBLUE(0, 5), BVALPHA(15, 1) },
+ { BVRED(11, 5), BVGREEN(6, 5), BVBLUE(1, 5), BVALPHA(0, 1) },
+ { BVRED(0, 5), BVGREEN(5, 5), BVBLUE(10, 5), BVALPHA(15, 1) },
+ { BVRED(1, 5), BVGREEN(6, 5), BVBLUE(11, 5), BVALPHA(0, 1) }
+};
+
+static const struct bvcsrgb rgb565_bits[] = {
+ { BVRED(11, 5), BVGREEN(5, 6), BVBLUE(0, 5), BVALPHA(0, 0) },
+ { BVRED(11, 5), BVGREEN(5, 6), BVBLUE(0, 5), BVALPHA(0, 0) },
+ { BVRED(0, 5), BVGREEN(5, 6), BVBLUE(11, 5), BVALPHA(0, 0) },
+ { BVRED(0, 5), BVGREEN(5, 6), BVBLUE(11, 5), BVALPHA(0, 0) }
+};
+
+static const struct bvcsrgb xrgb8888_bits[] = {
+ { BVRED(8, 8), BVGREEN(16, 8), BVBLUE(24, 8), BVALPHA(0, 0) },
+ { BVRED(0, 8), BVGREEN(8, 8), BVBLUE(16, 8), BVALPHA(24, 0) },
+ { BVRED(24, 8), BVGREEN(16, 8), BVBLUE(8, 8), BVALPHA(0, 0) },
+ { BVRED(16, 8), BVGREEN(8, 8), BVBLUE(0, 8), BVALPHA(24, 0) }
+};
+
+static const struct bvcsrgb argb8888_bits[] = {
+ { BVRED(8, 8), BVGREEN(16, 8), BVBLUE(24, 8), BVALPHA(0, 8) },
+ { BVRED(0, 8), BVGREEN(8, 8), BVBLUE(16, 8), BVALPHA(24, 8) },
+ { BVRED(24, 8), BVGREEN(16, 8), BVBLUE(8, 8), BVALPHA(0, 8) },
+ { BVRED(16, 8), BVGREEN(8, 8), BVBLUE(0, 8), BVALPHA(24, 8) }
+};
+
+static const unsigned int container[] = {
+ 8, /* OCDFMTDEF_CONTAINER_8BIT */
+ 16, /* OCDFMTDEF_CONTAINER_16BIT */
+ 24, /* OCDFMTDEF_CONTAINER_24BIT */
+ 32, /* OCDFMTDEF_CONTAINER_32BIT */
+ ~0U, /* reserved */
+ 48, /* OCDFMTDEF_CONTAINER_48BIT */
+ ~0U, /* reserved */
+ 64 /* OCDFMTDEF_CONTAINER_64BIT */
+};
+
+enum bverror parse_format(struct bvbltparams *bvbltparams,
+ struct surfaceinfo *surfaceinfo)
+{
+ enum bverror bverror = BVERR_NONE;
+ struct bvformatxlate *format;
+ enum ocdformat ocdformat;
+ unsigned int cs, std, alpha, subsample, layout;
+ unsigned int reversed, leftjust, swizzle, cont, bits;
+
+ format = &surfaceinfo->format;
+ ocdformat = surfaceinfo->geom->format;
+ GCENTERARG(GCZONE_FORMAT, "ocdformat = 0x%08X\n", ocdformat);
+
+ cs = (ocdformat & OCDFMTDEF_CS_MASK)
+ >> OCDFMTDEF_CS_SHIFT;
+ std = (ocdformat & OCDFMTDEF_STD_MASK)
+ >> OCDFMTDEF_STD_SHIFT;
+ alpha = ocdformat & OCDFMTDEF_ALPHA;
+ subsample = (ocdformat & OCDFMTDEF_SUBSAMPLE_MASK)
+ >> OCDFMTDEF_SUBSAMPLE_SHIFT;
+ layout = (ocdformat & OCDFMTDEF_LAYOUT_MASK)
+ >> OCDFMTDEF_LAYOUT_SHIFT;
+ cont = (ocdformat & OCDFMTDEF_CONTAINER_MASK)
+ >> OCDFMTDEF_CONTAINER_SHIFT;
+ bits = ((ocdformat & OCDFMTDEF_COMPONENTSIZEMINUS1_MASK)
+ >> OCDFMTDEF_COMPONENTSIZEMINUS1_SHIFT) + 1;
+
+ GCDBG(GCZONE_FORMAT_VERBOSE, "std = %d\n", std);
+ GCDBG(GCZONE_FORMAT_VERBOSE, "cs = %d\n", cs);
+ GCDBG(GCZONE_FORMAT_VERBOSE, "alpha = %d\n", alpha ? 1 : 0);
+ GCDBG(GCZONE_FORMAT_VERBOSE, "subsample = %d\n", subsample);
+ GCDBG(GCZONE_FORMAT_VERBOSE, "layout = %d\n", layout);
+ GCDBG(GCZONE_FORMAT_VERBOSE, "cont = %d\n", cont);
+ GCDBG(GCZONE_FORMAT_VERBOSE, "bits = %d\n", bits);
+
+ switch (cs) {
+ case (OCDFMTDEF_CS_RGB >> OCDFMTDEF_CS_SHIFT):
+ GCDBG(GCZONE_FORMAT, "OCDFMTDEF_CS_RGB\n");
+
+ /* Determine the swizzle. */
+ swizzle = (ocdformat & OCDFMTDEF_PLACEMENT_MASK)
+ >> OCDFMTDEF_PLACEMENT_SHIFT;
+ GCDBG(GCZONE_FORMAT, "swizzle = %d\n", swizzle);
+
+ /* RGB color space. */
+ format->type = BVFMT_RGB;
+
+ /* Has to be 0 for RGB. */
+ if (std != 0) {
+ BVSETBLTERROR(BVERR_UNK,
+ "unsupported standard");
+ goto exit;
+ }
+
+ /* Determine premultuplied or not. */
+ if (alpha == OCDFMTDEF_ALPHA) {
+ format->premultiplied
+ = ((ocdformat & OCDFMTDEF_NON_PREMULT) == 0);
+ } else {
+ format->premultiplied = true;
+
+ if ((ocdformat & OCDFMTDEF_FILL_EMPTY_0) != 0) {
+ BVSETBLTERROR(BVERR_UNK,
+ "0 filling is not supported");
+ goto exit;
+ }
+ }
+ GCDBG(GCZONE_FORMAT, "premultiplied = %d\n",
+ format->premultiplied);
+
+ /* No subsample support. */
+ if (subsample !=
+ (OCDFMTDEF_SUBSAMPLE_NONE >> OCDFMTDEF_SUBSAMPLE_SHIFT)) {
+ BVSETBLTERROR(BVERR_UNK,
+ "subsampling for RGB is not supported");
+ goto exit;
+ }
+
+ /* Only packed RGB is supported. */
+ if (layout !=
+ (OCDFMTDEF_PACKED >> OCDFMTDEF_LAYOUT_SHIFT)) {
+ BVSETBLTERROR(BVERR_UNK,
+ "only packed RGBA formats are supported");
+ goto exit;
+ }
+
+ /* Determine the format. */
+ switch (bits) {
+ case 12:
+ format->bitspp = 16;
+ format->allocbitspp = 16;
+ format->swizzle = rgba16swizzle[swizzle];
+
+ if (alpha == OCDFMTDEF_ALPHA) {
+ format->format = GCREG_DE_FORMAT_A4R4G4B4;
+ format->cs.rgb.comp = &argb4444_bits[swizzle];
+ } else {
+ format->format = GCREG_DE_FORMAT_X4R4G4B4;
+ format->cs.rgb.comp = &xrgb4444_bits[swizzle];
+ }
+ break;
+
+ case 15:
+ format->bitspp = 16;
+ format->allocbitspp = 16;
+ format->swizzle = rgba16swizzle[swizzle];
+
+ if (alpha == OCDFMTDEF_ALPHA) {
+ format->format = GCREG_DE_FORMAT_A1R5G5B5;
+ format->cs.rgb.comp = &argb1555_bits[swizzle];
+ } else {
+ format->format = GCREG_DE_FORMAT_X1R5G5B5;
+ format->cs.rgb.comp = &xrgb1555_bits[swizzle];
+ }
+ break;
+
+ case 16:
+ if (alpha == OCDFMTDEF_ALPHA) {
+ BVSETBLTERROR(BVERR_UNK,
+ "alpha component is not supported"
+ "for this format.");
+ goto exit;
+ }
+
+ format->bitspp = 16;
+ format->allocbitspp = 16;
+ format->swizzle = rgb16swizzle[swizzle];
+ format->format = GCREG_DE_FORMAT_R5G6B5;
+ format->cs.rgb.comp = &rgb565_bits[swizzle];
+ break;
+
+ case 24:
+ format->bitspp = 32;
+ format->allocbitspp = 32;
+ format->swizzle = rgba32swizzle[swizzle];
+
+ if (alpha == OCDFMTDEF_ALPHA) {
+ format->format = GCREG_DE_FORMAT_A8R8G8B8;
+ format->cs.rgb.comp = &argb8888_bits[swizzle];
+ } else {
+ format->format = GCREG_DE_FORMAT_X8R8G8B8;
+ format->cs.rgb.comp = &xrgb8888_bits[swizzle];
+ }
+ break;
+
+ default:
+ BVSETBLTERROR(BVERR_UNK,
+ "unsupported bit width %d", bits);
+ goto exit;
+ }
+
+ if (format->allocbitspp != container[cont]) {
+ BVSETBLTERROR(BVERR_UNK,
+ "unsupported container");
+ goto exit;
+ }
+ break;
+
+ case (OCDFMTDEF_CS_YCbCr >> OCDFMTDEF_CS_SHIFT):
+ GCDBG(GCZONE_FORMAT, "OCDFMTDEF_CS_YCbCr\n");
+
+ /* YUV color space. */
+ format->type = BVFMT_YUV;
+
+ /* Determine the swizzle. */
+ reversed = ocdformat & OCDFMTDEF_REVERSED;
+ leftjust = ocdformat & OCDFMTDEF_LEFT_JUSTIFIED;
+ GCDBG(GCZONE_FORMAT_VERBOSE, "reversed = %d\n",
+ reversed ? 1 : 0);
+ GCDBG(GCZONE_FORMAT_VERBOSE, "leftjust = %d\n",
+ leftjust ? 1 : 0);
+
+ /* Parse the standard. */
+ switch (std) {
+ case OCDFMTDEF_STD_ITUR_601_YCbCr >> OCDFMTDEF_STD_SHIFT:
+ GCDBG(GCZONE_FORMAT, "OCDFMTDEF_STD_ITUR_601_YCbCr\n");
+ format->cs.yuv.std = GCREG_PE_CONTROL_YUV_601;
+ break;
+
+ case OCDFMTDEF_STD_ITUR_709_YCbCr >> OCDFMTDEF_STD_SHIFT:
+ GCDBG(GCZONE_FORMAT, "OCDFMTDEF_STD_ITUR_709_YCbCr\n");
+ format->cs.yuv.std = GCREG_PE_CONTROL_YUV_709;
+ break;
+
+ default:
+ BVSETBLTERROR(BVERR_UNK,
+ "unsupported color standard");
+ goto exit;
+ }
+
+ /* Alpha is not supported. */
+ if (alpha == OCDFMTDEF_ALPHA) {
+ BVSETBLTERROR(BVERR_UNK,
+ "alpha channel is not supported");
+ goto exit;
+ }
+
+ format->premultiplied = true;
+
+ /* Parse subsampling. */
+ switch (subsample) {
+ case OCDFMTDEF_SUBSAMPLE_422_YCbCr >> OCDFMTDEF_SUBSAMPLE_SHIFT:
+ GCDBG(GCZONE_FORMAT, "OCDFMTDEF_SUBSAMPLE_422_YCbCr\n");
+
+ /* Parse layout. */
+ switch (layout) {
+ case OCDFMTDEF_PACKED >> OCDFMTDEF_LAYOUT_SHIFT:
+ GCDBG(GCZONE_FORMAT, "OCDFMTDEF_PACKED\n");
+
+ if (container[cont] != 32) {
+ BVSETBLTERROR(BVERR_UNK,
+ "unsupported container");
+ goto exit;
+ }
+
+ format->bitspp = 16;
+ format->allocbitspp = 16;
+ format->format = leftjust
+ ? GCREG_DE_FORMAT_YUY2
+ : GCREG_DE_FORMAT_UYVY;
+ format->swizzle = reversed
+ ? GCREG_PE_CONTROL_UV_SWIZZLE_VU
+ : GCREG_PE_CONTROL_UV_SWIZZLE_UV;
+ format->cs.yuv.planecount = 1;
+ format->cs.yuv.xsample = 2;
+ format->cs.yuv.ysample = 1;
+ break;
+
+ default:
+ BVSETBLTERROR(BVERR_UNK,
+ "specified 4:2:2 layout "
+ "is not supported");
+ goto exit;
+ }
+ break;
+
+ case OCDFMTDEF_SUBSAMPLE_420_YCbCr >> OCDFMTDEF_SUBSAMPLE_SHIFT:
+
+ /* Parse layout. */
+ switch (layout) {
+ case OCDFMTDEF_2_PLANE_YCbCr
+ >> OCDFMTDEF_LAYOUT_SHIFT:
+ GCDBG(GCZONE_FORMAT,
+ "OCDFMTDEF_2_PLANE_YCbCr\n");
+
+ if (container[cont] != 48) {
+ BVSETBLTERROR(BVERR_UNK,
+ "unsupported container");
+ goto exit;
+ }
+
+ format->bitspp = 8;
+ format->allocbitspp = 12;
+ format->format = GCREG_DE_FORMAT_NV12;
+ format->swizzle = reversed
+ ? GCREG_PE_CONTROL_UV_SWIZZLE_VU
+ : GCREG_PE_CONTROL_UV_SWIZZLE_UV;
+ format->cs.yuv.planecount = 2;
+ format->cs.yuv.xsample = 2;
+ format->cs.yuv.ysample = 2;
+ break;
+
+ case OCDFMTDEF_3_PLANE_STACKED
+ >> OCDFMTDEF_LAYOUT_SHIFT:
+ GCDBG(GCZONE_FORMAT,
+ "OCDFMTDEF_3_PLANE_STACKED\n");
+
+ if (container[cont] != 48) {
+ BVSETBLTERROR(BVERR_UNK,
+ "unsupported container");
+ goto exit;
+ }
+
+ format->bitspp = 8;
+ format->allocbitspp = 12;
+ format->format = GCREG_DE_FORMAT_YV12;
+ format->swizzle = reversed
+ ? GCREG_PE_CONTROL_UV_SWIZZLE_VU
+ : GCREG_PE_CONTROL_UV_SWIZZLE_UV;
+ format->cs.yuv.planecount = 3;
+ format->cs.yuv.xsample = 2;
+ format->cs.yuv.ysample = 2;
+ break;
+
+ default:
+ BVSETBLTERROR(BVERR_UNK,
+ "specified 4:2:2 layout "
+ "is not supported");
+ goto exit;
+ }
+ break;
+
+ default:
+ BVSETBLTERROR(BVERR_UNK,
+ "specified subsampling is not supported");
+ goto exit;
+ }
+
+ if (format->allocbitspp != bits) {
+ BVSETBLTERROR(BVERR_UNK,
+ "unsupported bit width %d", bits);
+ goto exit;
+ }
+ break;
+
+ default:
+ BVSETBLTERROR(BVERR_UNK,
+ "unsupported color space %d", cs);
+ goto exit;
+ }
+
+ GCDBG(GCZONE_FORMAT, "bpp = %d\n", format->bitspp);
+ GCDBG(GCZONE_FORMAT, "gcformat = %d\n", format->format);
+ GCDBG(GCZONE_FORMAT, "gcswizzle = %d\n", format->swizzle);
+
+ bverror = BVERR_NONE;
+
+exit:
+ GCEXITARG(GCZONE_FORMAT, "bv%s = %d\n",
+ (bverror == BVERR_NONE) ? "result" : "error", bverror);
+ return bverror;
+}
+
+
+/*******************************************************************************
+ * Alpha blending parser.
+ */
+
+#define BVBLENDMATCH(Mode, Inverse, Normal) \
+( \
+ BVBLENDDEF_ ## Mode | \
+ BVBLENDDEF_ ## Inverse | \
+ BVBLENDDEF_ ## Normal \
+)
+
+#define BVSRC1USE(Use) \
+ Use
+
+#define BVSRC2USE(Use) \
+ Use
+
+#define BVBLENDUNDEFINED() \
+ { ~0, ~0, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }
+
+struct bvblendxlate {
+ unsigned char match1;
+ unsigned char match2;
+
+ struct gcblendconfig k1;
+ struct gcblendconfig k2;
+};
+
+static struct bvblendxlate blendxlate[64] = {
+ /**********************************************************************/
+ /* #0: color factor: 00 00 00 A:(1-C1,C1)=zero
+ alpha factor: zero ==> 00 00 00 */
+ {
+ 0x00,
+ 0x00,
+
+ {
+ GCREG_BLENDING_MODE_ZERO,
+ GCREG_FACTOR_INVERSE_DISABLE,
+ BVSRC1USE(false), BVSRC2USE(false)
+ },
+
+ {
+ GCREG_BLENDING_MODE_ZERO,
+ GCREG_FACTOR_INVERSE_DISABLE,
+ BVSRC1USE(false), BVSRC2USE(false)
+ }
+ },
+
+ /* #1: color factor: 00 00 01 A:(1-C1,A1)=A1
+ alpha factor: A1 ==> 00 00 01 or 00 10 01 */
+ {
+ BVBLENDMATCH(ONLY_A, INV_C1, NORM_A1),
+ BVBLENDMATCH(ONLY_A, INV_C2, NORM_A1),
+
+ {
+ GCREG_BLENDING_MODE_NORMAL,
+ GCREG_FACTOR_INVERSE_ENABLE,
+ BVSRC1USE(true), BVSRC2USE(false)
+ },
+
+ {
+ GCREG_BLENDING_MODE_NORMAL,
+ GCREG_FACTOR_INVERSE_DISABLE,
+ BVSRC1USE(true), BVSRC2USE(true)
+ }
+ },
+
+ /* #2: color factor: 00 00 10 A:(1-C1,C2)=undefined
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #3: color factor: 00 00 11 A:(1-C1,A2)=A2
+ alpha factor: A2 ==> 00 00 11 or 00 10 11 */
+ {
+ BVBLENDMATCH(ONLY_A, INV_C1, NORM_A2),
+ BVBLENDMATCH(ONLY_A, INV_C2, NORM_A2),
+
+ {
+ GCREG_BLENDING_MODE_NORMAL,
+ GCREG_FACTOR_INVERSE_DISABLE,
+ BVSRC1USE(true), BVSRC2USE(true)
+ },
+
+ {
+ GCREG_BLENDING_MODE_NORMAL,
+ GCREG_FACTOR_INVERSE_ENABLE,
+ BVSRC1USE(false), BVSRC2USE(true)
+ }
+ },
+
+ /* #4: color factor: 00 01 00 A:(1-A1,C1)=1-A1
+ alpha factor: 1-A1 ==> 00 01 00 or 00 01 10 */
+ {
+ BVBLENDMATCH(ONLY_A, INV_A1, NORM_C1),
+ BVBLENDMATCH(ONLY_A, INV_A1, NORM_C2),
+
+ {
+ GCREG_BLENDING_MODE_INVERSED,
+ GCREG_FACTOR_INVERSE_ENABLE,
+ BVSRC1USE(true), BVSRC2USE(false)
+ },
+
+ {
+ GCREG_BLENDING_MODE_INVERSED,
+ GCREG_FACTOR_INVERSE_DISABLE,
+ BVSRC1USE(true), BVSRC2USE(true)
+ }
+ },
+
+ /* #5: color factor: 00 01 01 A:(1-A1,A1)=undefined
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #6: color factor: 00 01 10 A:(1-A1,C2)=1-A1
+ alpha factor: 1-A1 ==> 00 01 00 or 00 01 10 */
+ {
+ BVBLENDMATCH(ONLY_A, INV_A1, NORM_C1),
+ BVBLENDMATCH(ONLY_A, INV_A1, NORM_C2),
+
+ {
+ GCREG_BLENDING_MODE_INVERSED,
+ GCREG_FACTOR_INVERSE_ENABLE,
+ BVSRC1USE(true), BVSRC2USE(false)
+ },
+
+ {
+ GCREG_BLENDING_MODE_INVERSED,
+ GCREG_FACTOR_INVERSE_DISABLE,
+ BVSRC1USE(true), BVSRC2USE(true)
+ }
+ },
+
+ /* #7: color factor: 00 01 11 A:(1-A1,A2)=undefined
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #8: color factor: 00 10 00 A:(1-C2,C1)=undefined
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #9: color factor: 00 10 01 A:(1-C2,A1)=A1
+ alpha factor: A1 ==> 00 00 01 or 00 10 01 */
+ {
+ BVBLENDMATCH(ONLY_A, INV_C1, NORM_A1),
+ BVBLENDMATCH(ONLY_A, INV_C2, NORM_A1),
+
+ {
+ GCREG_BLENDING_MODE_NORMAL,
+ GCREG_FACTOR_INVERSE_ENABLE,
+ BVSRC1USE(true), BVSRC2USE(false)
+ },
+
+ {
+ GCREG_BLENDING_MODE_NORMAL,
+ GCREG_FACTOR_INVERSE_DISABLE,
+ BVSRC1USE(true), BVSRC2USE(true)
+ }
+ },
+
+ /* #10: color factor: 00 10 10 A:(1-C2,C2)=undefined
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #11: color factor: 00 10 11 A:(1-C2,A2)=A2
+ alpha factor: A2 ==> 00 00 11 or 00 10 11 */
+ {
+ BVBLENDMATCH(ONLY_A, INV_C1, NORM_A2),
+ BVBLENDMATCH(ONLY_A, INV_C2, NORM_A2),
+
+ {
+ GCREG_BLENDING_MODE_NORMAL,
+ GCREG_FACTOR_INVERSE_DISABLE,
+ BVSRC1USE(true), BVSRC2USE(true)
+ },
+
+ {
+ GCREG_BLENDING_MODE_NORMAL,
+ GCREG_FACTOR_INVERSE_ENABLE,
+ BVSRC1USE(false), BVSRC2USE(true)
+ }
+ },
+
+ /* #12: color factor: 00 11 00 A:(1-A2,C1)=1-A2
+ alpha factor: 1-A2 ==> 00 11 00 or 00 11 10 */
+ {
+ BVBLENDMATCH(ONLY_A, INV_A2, NORM_C1),
+ BVBLENDMATCH(ONLY_A, INV_A2, NORM_C2),
+
+ {
+ GCREG_BLENDING_MODE_INVERSED,
+ GCREG_FACTOR_INVERSE_DISABLE,
+ BVSRC1USE(true), BVSRC2USE(true)
+ },
+
+ {
+ GCREG_BLENDING_MODE_INVERSED,
+ GCREG_FACTOR_INVERSE_ENABLE,
+ BVSRC1USE(false), BVSRC2USE(true)
+ }
+ },
+
+ /* #13: color factor: 00 11 01 A:(1-A2,A1)=undefined
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #14: color factor: 00 11 10 A:(1-A2,C2)=1-A2
+ alpha factor: 1-A2 ==> 00 11 00 or 00 11 10 */
+ {
+ BVBLENDMATCH(ONLY_A, INV_A2, NORM_C1),
+ BVBLENDMATCH(ONLY_A, INV_A2, NORM_C2),
+
+ {
+ GCREG_BLENDING_MODE_INVERSED,
+ GCREG_FACTOR_INVERSE_DISABLE,
+ BVSRC1USE(true), BVSRC2USE(true)
+ },
+
+ {
+ GCREG_BLENDING_MODE_INVERSED,
+ GCREG_FACTOR_INVERSE_ENABLE,
+ BVSRC1USE(false), BVSRC2USE(true)
+ }
+ },
+
+ /* #15: color factor: 00 11 11 A:(1-A2,A2)=undefined
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /**********************************************************************/
+ /* #16: color factor: 01 00 00 MIN:(1-C1,C1) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #17: color factor: 01 00 01 MIN:(1-C1,A1) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #18: color factor: 01 00 10 MIN:(1-C1,C2) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #19: color factor: 01 00 11 MIN:(1-C1,A2) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #20: color factor: 01 01 00 MIN:(1-A1,C1) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #21: color factor: 01 01 01 MIN:(1-A1,A1) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #22: color factor: 01 01 10 MIN:(1-A1,C2) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #23: color factor: 01 01 11 MIN:(1-A1,A2)
+ alpha factor: one ==> 11 11 11 */
+ {
+ 0x3F,
+ 0x3F,
+
+ {
+ GCREG_BLENDING_MODE_SATURATED_DEST_ALPHA,
+ GCREG_FACTOR_INVERSE_DISABLE,
+ BVSRC1USE(true), BVSRC2USE(true)
+ },
+
+ {
+ GCREG_BLENDING_MODE_SATURATED_ALPHA,
+ GCREG_FACTOR_INVERSE_DISABLE,
+ BVSRC1USE(true), BVSRC2USE(true)
+ }
+ },
+
+ /* #24: color factor: 01 10 00 MIN:(1-C2,C1) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #25: color factor: 01 10 01 MIN:(1-C2,A1) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #26: color factor: 01 10 10 MIN:(1-C2,C2) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #27: color factor: 01 10 11 MIN:(1-C2,A2) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #28: color factor: 01 11 00 MIN:(1-A2,C1) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #29: color factor: 01 11 01 MIN:(1-A2,A1)
+ alpha factor: one ==> 11 11 11 */
+ {
+ 0x3F,
+ 0x3F,
+
+ {
+ GCREG_BLENDING_MODE_SATURATED_ALPHA,
+ GCREG_FACTOR_INVERSE_DISABLE,
+ BVSRC1USE(true), BVSRC2USE(true)
+ },
+
+ {
+ GCREG_BLENDING_MODE_SATURATED_DEST_ALPHA,
+ GCREG_FACTOR_INVERSE_DISABLE,
+ BVSRC1USE(true), BVSRC2USE(true)
+ }
+ },
+
+ /* #30: color factor: 01 11 10 MIN:(1-A2,C2) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #31: color factor: 01 11 11 MIN:(1-A2,A2) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /**********************************************************************/
+ /* #32: color factor: 10 00 00 MAX:(1-C1,C1) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #33: color factor: 10 00 01 MAX:(1-C1,A1) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #34: color factor: 10 00 10 MAX:(1-C1,C2) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #35: color factor: 10 00 11 MAX:(1-C1,A2) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #36: color factor: 10 01 00 MAX:(1-A1,C1) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #37: color factor: 10 01 01 MAX:(1-A1,A1) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #38: color factor: 10 01 10 MAX:(1-A1,C2) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #39: color factor: 10 01 11 MAX:(1-A1,A2) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #40: color factor: 10 10 00 MAX:(1-C2,C1) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #41: color factor: 10 10 01 MAX:(1-C2,A1) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #42: color factor: 10 10 10 MAX:(1-C2,C2) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #43: color factor: 10 10 11 MAX:(1-C2,A2) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #44: color factor: 10 11 00 MAX:(1-A2,C1) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #45: color factor: 10 11 01 MAX:(1-A2,A1) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #46: color factor: 10 11 10 MAX:(1-A2,C2) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #47: color factor: 10 11 11 MAX:(1-A2,A2) ==> not supported
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /**********************************************************************/
+ /* #48: color factor: 11 00 00 C:(1-C1,C1)=undefined
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #49: color factor: 11 00 01 C:(1-C1,A1)=1-C1
+ alpha factor: 1-A1 ==> 00 01 00 or 00 01 10 */
+ {
+ BVBLENDMATCH(ONLY_A, INV_A1, NORM_C1),
+ BVBLENDMATCH(ONLY_A, INV_A1, NORM_C2),
+
+ {
+ GCREG_BLENDING_MODE_COLOR_INVERSED,
+ GCREG_FACTOR_INVERSE_ENABLE,
+ BVSRC1USE(true), BVSRC2USE(false)
+ },
+
+ {
+ GCREG_BLENDING_MODE_COLOR_INVERSED,
+ GCREG_FACTOR_INVERSE_DISABLE,
+ BVSRC1USE(true), BVSRC2USE(true)
+ }
+ },
+
+ /* #50: color factor: 11 00 10 C:(1-C1,C2)=undefined
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #51: color factor: 11 00 11 C:(1-C1,A2)=1-C1
+ alpha factor: 1-A1 ==> 00 01 00 or 00 01 10 */
+ {
+ BVBLENDMATCH(ONLY_A, INV_A1, NORM_C1),
+ BVBLENDMATCH(ONLY_A, INV_A1, NORM_C2),
+
+ {
+ GCREG_BLENDING_MODE_COLOR_INVERSED,
+ GCREG_FACTOR_INVERSE_ENABLE,
+ BVSRC1USE(true), BVSRC2USE(false)
+ },
+
+ {
+ GCREG_BLENDING_MODE_COLOR_INVERSED,
+ GCREG_FACTOR_INVERSE_DISABLE,
+ BVSRC1USE(true), BVSRC2USE(true)
+ }
+ },
+
+ /* #52: color factor: 11 01 00 C:(1-A1,C1)=C1
+ alpha factor: A1 ==> 00 00 01 or 00 10 01 */
+ {
+ BVBLENDMATCH(ONLY_A, INV_C1, NORM_A1),
+ BVBLENDMATCH(ONLY_A, INV_C2, NORM_A1),
+
+ {
+ GCREG_BLENDING_MODE_COLOR,
+ GCREG_FACTOR_INVERSE_ENABLE,
+ BVSRC1USE(true), BVSRC2USE(false)
+ },
+
+ {
+ GCREG_BLENDING_MODE_COLOR,
+ GCREG_FACTOR_INVERSE_DISABLE,
+ BVSRC1USE(true), BVSRC2USE(true)
+ }
+ },
+
+ /* #53: color factor: 11 01 01 C:(1-A1,A1)=undefined
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #54: color factor: 11 01 10 C:(1-A1,C2)=C2
+ alpha factor: A2 ==> 00 00 11 or 00 10 11 */
+ {
+ BVBLENDMATCH(ONLY_A, INV_C1, NORM_A2),
+ BVBLENDMATCH(ONLY_A, INV_C2, NORM_A2),
+
+ {
+ GCREG_BLENDING_MODE_COLOR,
+ GCREG_FACTOR_INVERSE_DISABLE,
+ BVSRC1USE(true), BVSRC2USE(true)
+ },
+
+ {
+ GCREG_BLENDING_MODE_COLOR,
+ GCREG_FACTOR_INVERSE_ENABLE,
+ BVSRC1USE(false), BVSRC2USE(true)
+ }
+ },
+
+ /* #55: color factor: 11 01 11 C:(1-A1,A2)=undefined
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #56: color factor: 11 10 00 C:(1-C2,C1)=undefined
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #57: color factor: 11 10 01 C:(1-C2,A1)=1-C2
+ alpha factor: 1-A2 ==> 00 11 00 or 00 11 10 */
+ {
+ BVBLENDMATCH(ONLY_A, INV_A2, NORM_C1),
+ BVBLENDMATCH(ONLY_A, INV_A2, NORM_C2),
+
+ {
+ GCREG_BLENDING_MODE_COLOR_INVERSED,
+ GCREG_FACTOR_INVERSE_DISABLE,
+ BVSRC1USE(true), BVSRC2USE(true)
+ },
+
+ {
+ GCREG_BLENDING_MODE_COLOR_INVERSED,
+ GCREG_FACTOR_INVERSE_ENABLE,
+ BVSRC1USE(false), BVSRC2USE(true)
+ }
+ },
+
+ /* #58: color factor: 11 10 10 C:(1-C2,C2)=undefined
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #59: color factor: 11 10 11 C:(1-C2,A2)=1-C2
+ alpha factor: 1-A2 ==> 00 11 00 or 00 11 10 */
+ {
+ BVBLENDMATCH(ONLY_A, INV_A2, NORM_C1),
+ BVBLENDMATCH(ONLY_A, INV_A2, NORM_C2),
+
+ {
+ GCREG_BLENDING_MODE_COLOR_INVERSED,
+ GCREG_FACTOR_INVERSE_DISABLE,
+ BVSRC1USE(true), BVSRC2USE(true)
+ },
+
+ {
+ GCREG_BLENDING_MODE_COLOR_INVERSED,
+ GCREG_FACTOR_INVERSE_ENABLE,
+ BVSRC1USE(false), BVSRC2USE(false)
+ }
+ },
+
+ /* #60: color factor: 11 11 00 C:(1-A2,C1)=C1
+ alpha factor: A1 ==> 00 00 01 or 00 10 01 */
+ {
+ BVBLENDMATCH(ONLY_A, INV_C1, NORM_A1),
+ BVBLENDMATCH(ONLY_A, INV_C2, NORM_A1),
+
+ {
+ GCREG_BLENDING_MODE_COLOR,
+ GCREG_FACTOR_INVERSE_ENABLE,
+ BVSRC1USE(true), BVSRC2USE(false)
+ },
+
+ {
+ GCREG_BLENDING_MODE_COLOR,
+ GCREG_FACTOR_INVERSE_DISABLE,
+ BVSRC1USE(true), BVSRC2USE(true)
+ }
+ },
+
+ /* #61: color factor: 11 11 01 C:(1-A2,A1)=undefined
+ alpha factor: N/A */
+ BVBLENDUNDEFINED(),
+
+ /* #62: color factor: 11 11 10 C:(1-A2,C2)=C2
+ alpha factor: A2 ==> 00 00 11 or 00 10 11 */
+ {
+ BVBLENDMATCH(ONLY_A, INV_C1, NORM_A2),
+ BVBLENDMATCH(ONLY_A, INV_C2, NORM_A2),
+
+ {
+ GCREG_BLENDING_MODE_COLOR,
+ GCREG_FACTOR_INVERSE_DISABLE,
+ BVSRC1USE(true), BVSRC2USE(true)
+ },
+
+ {
+ GCREG_BLENDING_MODE_COLOR,
+ GCREG_FACTOR_INVERSE_ENABLE,
+ BVSRC1USE(false), BVSRC2USE(true)
+ }
+ },
+
+ /* #63: color factor: 11 11 11 C:(1-A2,A2)=one
+ alpha factor: one ==> 11 11 11 */
+ {
+ 0x3F,
+ 0x3F,
+
+ {
+ GCREG_BLENDING_MODE_ONE,
+ GCREG_FACTOR_INVERSE_DISABLE,
+ BVSRC1USE(true), BVSRC2USE(false)
+ },
+
+ {
+ GCREG_BLENDING_MODE_ONE,
+ GCREG_FACTOR_INVERSE_DISABLE,
+ BVSRC1USE(false), BVSRC2USE(true)
+ }
+ }
+};
+
+enum bverror parse_blend(struct bvbltparams *bvbltparams,
+ enum bvblend blend,
+ struct gcalpha *gca)
+{
+ enum bverror bverror;
+ unsigned int global;
+ unsigned int k1, k2, k3, k4;
+ struct bvblendxlate *k1_xlate;
+ struct bvblendxlate *k2_xlate;
+ unsigned int alpha;
+
+ GCENTERARG(GCZONE_BLEND, "blend = 0x%08X (%s)\n",
+ blend, gc_bvblend_name(blend));
+
+ if ((blend & BVBLENDDEF_REMOTE) != 0) {
+ BVSETBLTERROR(BVERR_BLEND, "remote alpha not supported");
+ goto exit;
+ }
+
+ global = (blend & BVBLENDDEF_GLOBAL_MASK) >> BVBLENDDEF_GLOBAL_SHIFT;
+
+ switch (global) {
+ case (BVBLENDDEF_GLOBAL_NONE >> BVBLENDDEF_GLOBAL_SHIFT):
+ GCDBG(GCZONE_BLEND, "BVBLENDDEF_GLOBAL_NONE\n");
+
+ gca->src_global_color =
+ gca->dst_global_color = 0;
+
+ gca->src_global_alpha_mode = GCREG_GLOBAL_ALPHA_MODE_NORMAL;
+ gca->dst_global_alpha_mode = GCREG_GLOBAL_ALPHA_MODE_NORMAL;
+ break;
+
+ case (BVBLENDDEF_GLOBAL_UCHAR >> BVBLENDDEF_GLOBAL_SHIFT):
+ GCDBG(GCZONE_BLEND, "BVBLENDDEF_GLOBAL_UCHAR\n");
+
+ gca->src_global_color =
+ gca->dst_global_color =
+ ((unsigned int) bvbltparams->globalalpha.size8) << 24;
+
+ gca->src_global_alpha_mode = GCREG_GLOBAL_ALPHA_MODE_GLOBAL;
+ gca->dst_global_alpha_mode = GCREG_GLOBAL_ALPHA_MODE_GLOBAL;
+ break;
+
+ case (BVBLENDDEF_GLOBAL_FLOAT >> BVBLENDDEF_GLOBAL_SHIFT):
+ GCDBG(GCZONE_BLEND, "BVBLENDDEF_GLOBAL_FLOAT\n");
+
+ alpha = gcfp2norm8(bvbltparams->globalalpha.fp);
+
+ gca->src_global_color =
+ gca->dst_global_color = alpha << 24;
+
+ gca->src_global_alpha_mode = GCREG_GLOBAL_ALPHA_MODE_GLOBAL;
+ gca->dst_global_alpha_mode = GCREG_GLOBAL_ALPHA_MODE_GLOBAL;
+ break;
+
+ default:
+ BVSETBLTERROR(BVERR_BLEND, "invalid global alpha mode");
+ goto exit;
+ }
+
+ /*
+ Co = k1 x C1 + k2 x C2
+ Ao = k3 x A1 + k4 x A2
+ */
+
+ k1 = (blend >> 18) & 0x3F;
+ k2 = (blend >> 12) & 0x3F;
+ k3 = (blend >> 6) & 0x3F;
+ k4 = blend & 0x3F;
+
+ GCDBG(GCZONE_BLEND, "k1 = %d\n", k1);
+ GCDBG(GCZONE_BLEND, "k2 = %d\n", k2);
+ GCDBG(GCZONE_BLEND, "k3 = %d\n", k3);
+ GCDBG(GCZONE_BLEND, "k4 = %d\n", k4);
+
+ k1_xlate = &blendxlate[k1];
+ k2_xlate = &blendxlate[k2];
+
+ if (((k3 != k1_xlate->match1) && (k3 != k1_xlate->match2)) ||
+ ((k4 != k2_xlate->match1) && (k4 != k2_xlate->match2))) {
+ BVSETBLTERROR(BVERR_BLEND,
+ "not supported coefficient combination");
+ goto exit;
+ }
+
+ gca->k1 = &k1_xlate->k1;
+ gca->k2 = &k2_xlate->k2;
+
+ gca->src1used = gca->k1->src1used | gca->k2->src1used;
+ gca->src2used = gca->k1->src2used | gca->k2->src2used;
+
+ bverror = BVERR_NONE;
+
+exit:
+ GCEXITARG(BVERR_BLEND, "bv%s = %d\n",
+ (bverror == BVERR_NONE) ? "result" : "error", bverror);
+ return bverror;
+}
+
+
+/*******************************************************************************
+ * Rotation and mirror.
+ */
+
+#define BVFLAG_FLIP_MASK 0x00000003
+
+#define BVFLAG_FLIP_SRC1_SHIFT 14
+#define BVFLAG_FLIP_SRC2_SHIFT 16
+#define BVFLAG_FLIP_MASK_SHIFT 18
+
+#define GCREG_MIRROR_NONE 0x0
+#define GCREG_MIRROR_X 0x1
+#define GCREG_MIRROR_Y 0x2
+#define GCREG_MIRROR_XY 0x3
+
+#define GCREG_ROT_ANGLE_ROT0 0x0
+#define GCREG_ROT_ANGLE_ROT90 0x4
+#define GCREG_ROT_ANGLE_ROT180 0x5
+#define GCREG_ROT_ANGLE_ROT270 0x6
+
+#define ROT_ANGLE_INVALID -1
+#define ROT_ANGLE_0 0
+#define ROT_ANGLE_90 1
+#define ROT_ANGLE_180 2
+#define ROT_ANGLE_270 3
+
+/* NOTE: BLTsville rotation is defined conunter clock wise. */
+const unsigned int rotencoding[] = {
+ GCREG_ROT_ANGLE_ROT0, /* ROT_ANGLE_0 */
+ GCREG_ROT_ANGLE_ROT270, /* ROT_ANGLE_90 */
+ GCREG_ROT_ANGLE_ROT180, /* ROT_ANGLE_180 */
+ GCREG_ROT_ANGLE_ROT90 /* ROT_ANGLE_270 */
+};
+
+static inline int get_angle(int orientation)
+{
+ int angle;
+
+ /* Normalize the angle. */
+ angle = orientation % 360;
+
+ /* Flip to positive. */
+ if (angle < 0)
+ angle = 360 + angle;
+
+ /* Translate the angle. */
+ switch (angle) {
+ case 0: return ROT_ANGLE_0;
+ case 90: return ROT_ANGLE_90;
+ case 180: return ROT_ANGLE_180;
+ case 270: return ROT_ANGLE_270;
+ }
+
+ /* Not supported angle. */
+ return ROT_ANGLE_INVALID;
+}
+
+
+/*******************************************************************************
+ * Surface compare and validation.
+ */
+
+bool valid_rect(struct bvsurfgeom *bvsurfgeom, struct gcrect *gcrect)
+{
+ int width, height;
+
+ if ((gcrect->left < 0) || (gcrect->top < 0)) {
+ GCERR("invalid rectangle origin: %d,%d.\n",
+ gcrect->left, gcrect->top);
+ return false;
+ }
+
+ width = gcrect->right - gcrect->left;
+ height = gcrect->bottom - gcrect->top;
+ if ((width <= 0) || (height <= 0)) {
+ GCERR("invalid rectangle size: %d,%d.\n",
+ width, height);
+ return false;
+ }
+
+ if (gcrect->right > (int) bvsurfgeom->width) {
+ GCERR("right coordinate (%d) exceeds surface width (%d).\n",
+ gcrect->right, bvsurfgeom->width);
+ return false;
+ }
+
+ if (gcrect->bottom > (int) bvsurfgeom->height) {
+ GCERR("bottom coordinate (%d) exceeds surface height (%d).\n",
+ gcrect->bottom, bvsurfgeom->height);
+ return false;
+ }
+
+ return true;
+}
+
+static bool valid_geom(struct surfaceinfo *surfaceinfo)
+{
+ unsigned int size;
+ unsigned int height;
+
+ /* Compute the size of the surface. */
+ size = (surfaceinfo->geom->width *
+ surfaceinfo->geom->height *
+ surfaceinfo->format.allocbitspp) / 8;
+
+ /* Make sure the size is not greater then the surface. */
+ if (size > surfaceinfo->buf.desc->length) {
+ GCERR("invalid geometry detected:\n");
+ GCERR(" specified dimensions: %dx%d, %d bitspp\n",
+ surfaceinfo->geom->width,
+ surfaceinfo->geom->height,
+ surfaceinfo->format.bitspp);
+ GCERR(" surface size based on the dimensions: %d\n",
+ size);
+ GCERR(" specified surface size: %lu\n",
+ surfaceinfo->buf.desc->length);
+ return false;
+ }
+
+ /* Determine the height of the image. */
+ height = ((surfaceinfo->angle % 2) == 0)
+ ? surfaceinfo->geom->height
+ : surfaceinfo->geom->width;
+
+ /* Compute the size using the stide. */
+ size = surfaceinfo->geom->virtstride * height;
+
+ /* Make sure the size is not greater then the surface. */
+ if (size > surfaceinfo->buf.desc->length) {
+ GCERR("invalid geometry detected:\n");
+ GCERR(" specified dimensions: %dx%d, %d bitspp\n",
+ surfaceinfo->geom->width,
+ surfaceinfo->geom->height,
+ surfaceinfo->format.bitspp);
+ GCERR(" physical image height = %d\n", height);
+ GCERR(" image stride = %d\n", surfaceinfo->geom->virtstride);
+ GCERR(" computed surface size = %d\n", size);
+ GCERR(" specified surface size: %lu\n",
+ surfaceinfo->buf.desc->length);
+ return false;
+ }
+
+ return true;
+}
+
+int get_pixel_offset(struct surfaceinfo *surfaceinfo, int offset)
+{
+ unsigned int alignment;
+ int byteoffset;
+ unsigned int alignedoffset;
+ int pixeloffset;
+
+ GCENTERARG(GCZONE_OFFSET, "surfaceinfo=0x%08X, offset=%d\n",
+ surfaceinfo, offset);
+
+ alignment = (surfaceinfo->format.type == BVFMT_YUV)
+ ? (64 - 1)
+ : (16 - 1);
+
+ GCDBG(GCZONE_OFFSET, "bpp = %d\n", surfaceinfo->format.bitspp);
+ GCDBG(GCZONE_OFFSET, "alignment = %d\n", alignment);
+
+ /* Determine offset in bytes from the base modified by the
+ * given offset. */
+ if (surfaceinfo->buf.desc->auxtype == BVAT_PHYSDESC) {
+ struct bvphysdesc *bvphysdesc;
+ bvphysdesc = (struct bvphysdesc *)
+ surfaceinfo->buf.desc->auxptr;
+ GCDBG(GCZONE_OFFSET, "physical descriptor = 0x%08X\n",
+ bvphysdesc);
+ GCDBG(GCZONE_OFFSET, "first page = 0x%08X\n",
+ bvphysdesc->pagearray[0]);
+ GCDBG(GCZONE_OFFSET, "page offset = 0x%08X\n",
+ bvphysdesc->pageoffset);
+
+ byteoffset = bvphysdesc->pageoffset + offset;
+ } else {
+ GCDBG(GCZONE_OFFSET, "no physical descriptor.\n");
+ byteoffset = (unsigned int)
+ surfaceinfo->buf.desc->virtaddr + offset;
+ }
+
+ GCDBG(GCZONE_OFFSET, "byteoffset = %d\n", byteoffset);
+
+ /* Compute the aligned offset. */
+ alignedoffset = byteoffset & alignment;
+
+ /* Convert to pixels. */
+ pixeloffset = alignedoffset * 8 / surfaceinfo->format.bitspp;
+
+ GCDBG(GCZONE_OFFSET, "alignedoffset = %d\n", alignedoffset);
+ GCDBG(GCZONE_OFFSET, "pixeloffset = %d\n", -pixeloffset);
+
+ GCEXIT(GCZONE_OFFSET);
+ return -pixeloffset;
+}
+
+enum bverror parse_destination(struct bvbltparams *bvbltparams,
+ struct gcbatch *batch)
+{
+ enum bverror bverror = BVERR_NONE;
+
+ GCENTER(GCZONE_DEST);
+
+ GCDBG(GCZONE_DEST, "parsing destination\n");
+
+ /* Did the destination surface change? */
+ if ((batch->batchflags & BVBATCH_DST) != 0) {
+ struct surfaceinfo *dstinfo;
+
+ /* Initialize the destination descriptor. */
+ dstinfo = &batch->dstinfo;
+ dstinfo->index = -1;
+ dstinfo->buf.desc = bvbltparams->dstdesc;
+ dstinfo->geom = bvbltparams->dstgeom;
+
+ /* Initialize members that are not used. */
+ dstinfo->mirror = GCREG_MIRROR_NONE;
+ dstinfo->rop = 0;
+ dstinfo->gca = NULL;
+
+ /* Parse the destination format. */
+ if (parse_format(bvbltparams, dstinfo) != BVERR_NONE) {
+ bverror = BVERR_DSTGEOM_FORMAT;
+ goto exit;
+ }
+
+ /* Parse orientation. */
+ dstinfo->angle = get_angle(dstinfo->geom->orientation);
+ if (dstinfo->angle == ROT_ANGLE_INVALID) {
+ BVSETBLTERROR(BVERR_DSTGEOM,
+ "unsupported destination orientation %d.",
+ dstinfo->geom->orientation);
+ goto exit;
+ }
+
+ /* Compute the destination alignments needed to compensate
+ * for the surface base address misalignment if any. */
+ dstinfo->xpixalign = get_pixel_offset(dstinfo, 0);
+ dstinfo->ypixalign = 0;
+ dstinfo->bytealign = (dstinfo->xpixalign
+ * (int) dstinfo->format.bitspp) / 8;
+
+ GCDBG(GCZONE_DEST, " buffer length = %d\n",
+ dstinfo->buf.desc->length);
+ GCDBG(GCZONE_DEST, " rotation %d degrees.\n",
+ dstinfo->angle * 90);
+
+ if (dstinfo->buf.desc->auxtype == BVAT_PHYSDESC) {
+ struct bvphysdesc *bvphysdesc;
+ bvphysdesc = (struct bvphysdesc *)
+ dstinfo->buf.desc->auxptr;
+ GCDBG(GCZONE_DEST, " physical descriptor = 0x%08X\n",
+ bvphysdesc);
+ GCDBG(GCZONE_DEST, " first page = 0x%08X\n",
+ bvphysdesc->pagearray[0]);
+ GCDBG(GCZONE_DEST, " page offset = 0x%08X\n",
+ bvphysdesc->pageoffset);
+ } else {
+ GCDBG(GCZONE_DEST, " virtual address = 0x%08X\n",
+ (unsigned int) dstinfo->buf.desc->virtaddr);
+ }
+
+ GCDBG(GCZONE_DEST, " stride = %ld\n",
+ dstinfo->geom->virtstride);
+ GCDBG(GCZONE_DEST, " geometry size = %dx%d\n",
+ dstinfo->geom->width, dstinfo->geom->height);
+ GCDBG(GCZONE_DEST, " surface offset (pixels) = %d,%d\n",
+ dstinfo->xpixalign, dstinfo->ypixalign);
+ GCDBG(GCZONE_DEST, " surface offset (bytes) = %d\n",
+ dstinfo->bytealign);
+
+ /* Check for unsupported dest formats. */
+ if ((dstinfo->format.type == BVFMT_YUV) &&
+ (dstinfo->format.cs.yuv.planecount > 1)) {
+ BVSETBLTERROR(BVERR_DSTGEOM_FORMAT,
+ "destination format unsupported");
+ goto exit;
+ }
+
+ /* Destination stride must be 8 pixel aligned. */
+ if ((dstinfo->geom->virtstride
+ & (dstinfo->format.bitspp - 1)) != 0) {
+ BVSETBLTERROR(BVERR_DSTGEOM_STRIDE,
+ "destination stride must be 8 pixel "
+ "aligned.");
+ goto exit;
+ }
+
+ /* Validate geometry. */
+ if (!valid_geom(dstinfo)) {
+ BVSETBLTERROR(BVERR_DSTGEOM,
+ "destination geom exceeds surface size");
+ goto exit;
+ }
+ }
+
+ /* Did clipping/destination rects change? */
+ if ((batch->batchflags & (BVBATCH_CLIPRECT |
+ BVBATCH_DESTRECT |
+ BVBATCH_DST)) != 0) {
+ struct surfaceinfo *dstinfo;
+ struct gcrect cliprect;
+ struct gcrect *dstrect;
+ struct gcrect *dstrectaux;
+
+ /* Get a shortcut to the destination surface. */
+ dstinfo = &batch->dstinfo;
+
+ /* Determine destination rectangle. */
+ dstrect = &dstinfo->rect;
+ GCCONVERT_RECT(GCZONE_DEST,
+ " rect",
+ &bvbltparams->dstrect,
+ dstrect);
+
+ /* Determine whether aux destination is specified. */
+ batch->haveaux
+ = ((bvbltparams->flags & BVFLAG_SRC2_AUXDSTRECT) != 0);
+ GCDBG(GCZONE_DEST, " have aux dest = %d\n", batch->haveaux);
+
+ /* Is clipping rectangle specified? */
+ if ((bvbltparams->flags & BVFLAG_CLIP) == BVFLAG_CLIP) {
+ /* Convert the clipping rectangle. */
+ GCCONVERT_RECT(GCZONE_DEST,
+ " clipping",
+ &bvbltparams->cliprect,
+ &cliprect);
+
+ if ((cliprect.left < GC_CLIP_RESET_LEFT) ||
+ (cliprect.top < GC_CLIP_RESET_TOP) ||
+ (cliprect.right > GC_CLIP_RESET_RIGHT) ||
+ (cliprect.bottom > GC_CLIP_RESET_BOTTOM)) {
+ BVSETERROR(BVERR_CLIP_RECT,
+ "clip rect is invalid");
+ goto exit;
+ }
+
+ /* Compute clipping deltas and the adjusted
+ * destination rect. */
+ if (cliprect.left <= dstrect->left) {
+ batch->clipdelta.left = 0;
+ batch->dstclipped.left = dstrect->left;
+ } else {
+ batch->clipdelta.left = cliprect.left
+ - dstrect->left;
+ batch->dstclipped.left = cliprect.left;
+ }
+
+ if (cliprect.top <= dstrect->top) {
+ batch->clipdelta.top = 0;
+ batch->dstclipped.top = dstrect->top;
+ } else {
+ batch->clipdelta.top = cliprect.top
+ - dstrect->top;
+ batch->dstclipped.top = cliprect.top;
+ }
+
+ if (cliprect.right >= dstrect->right) {
+ batch->clipdelta.right = 0;
+ batch->dstclipped.right = dstrect->right;
+ } else {
+ batch->clipdelta.right = cliprect.right
+ - dstrect->right;
+ batch->dstclipped.right = cliprect.right;
+ }
+
+ if (cliprect.bottom >= dstrect->bottom) {
+ batch->clipdelta.bottom = 0;
+ batch->dstclipped.bottom = dstrect->bottom;
+ } else {
+ batch->clipdelta.bottom = cliprect.bottom
+ - dstrect->bottom;
+ batch->dstclipped.bottom = cliprect.bottom;
+ }
+
+ /* Clip the aux destination. */
+ if (batch->haveaux) {
+ /* Convert the aux rectangle. */
+ dstrectaux = &batch->dstrectaux;
+ GCCONVERT_RECT(GCZONE_DEST,
+ " aux rect",
+ &bvbltparams->src2auxdstrect,
+ dstrectaux);
+
+ if (cliprect.left <= dstrectaux->left)
+ batch->dstclippedaux.left
+ = dstrectaux->left;
+ else
+ batch->dstclippedaux.left
+ = cliprect.left;
+
+ if (cliprect.top <= dstrectaux->top)
+ batch->dstclippedaux.top
+ = dstrectaux->top;
+ else
+ batch->dstclippedaux.top
+ = cliprect.top;
+
+ if (cliprect.right >= dstrectaux->right)
+ batch->dstclippedaux.right
+ = dstrectaux->right;
+ else
+ batch->dstclippedaux.right
+ = cliprect.right;
+
+ if (cliprect.bottom >= dstrectaux->bottom)
+ batch->dstclippedaux.bottom
+ = dstrectaux->bottom;
+ else
+ batch->dstclippedaux.bottom
+ = cliprect.bottom;
+ }
+ } else {
+ batch->clipdelta.left =
+ batch->clipdelta.top =
+ batch->clipdelta.right =
+ batch->clipdelta.bottom = 0;
+
+ batch->dstclipped = *dstrect;
+ if (batch->haveaux)
+ /* Convert the aux rectangle. */
+ GCCONVERT_RECT(GCZONE_DEST,
+ " aux rect",
+ &bvbltparams->src2auxdstrect,
+ &batch->dstclippedaux);
+ }
+
+ GCPRINT_RECT(GCZONE_DEST, " clipped dest",
+ &batch->dstclipped);
+
+ /* Validate the destination rectangle. */
+ if (!valid_rect(dstinfo->geom, &batch->dstclipped)) {
+ BVSETBLTERROR(BVERR_DSTRECT,
+ "invalid destination rectangle.");
+ goto exit;
+ }
+
+ if (batch->haveaux) {
+ GCPRINT_RECT(GCZONE_DEST, " clipped aux dest",
+ &batch->dstclippedaux);
+
+ /* Validate the aux destination rectangle. */
+ if (!valid_rect(dstinfo->geom, &batch->dstclippedaux)) {
+ BVSETBLTERROR(BVERR_DSTRECT,
+ "invalid aux destination "
+ "rectangle.");
+ goto exit;
+ }
+ }
+
+ GCDBG(GCZONE_DEST,
+ " clipping delta = (%d,%d)-(%d,%d)\n",
+ batch->clipdelta.left,
+ batch->clipdelta.top,
+ batch->clipdelta.right,
+ batch->clipdelta.bottom);
+ }
+
+exit:
+ GCEXITARG(GCZONE_DEST, "bv%s = %d\n",
+ (bverror == BVERR_NONE) ? "result" : "error", bverror);
+ return bverror;
+}
+
+void process_dest_rotation(struct bvbltparams *bvbltparams,
+ struct gcbatch *batch)
+{
+ GCENTER(GCZONE_DEST);
+
+ /* Did clipping/destination rects change? */
+ if ((batch->batchflags & (BVBATCH_CLIPRECT |
+ BVBATCH_DESTRECT |
+ BVBATCH_DST)) != 0) {
+ struct surfaceinfo *dstinfo;
+ int dstoffsetX, dstoffsetY;
+
+ /* Initialize the destination descriptor. */
+ dstinfo = &batch->dstinfo;
+
+ switch (dstinfo->angle) {
+ case ROT_ANGLE_0:
+ /* Determine the origin offset. */
+ dstoffsetX = dstinfo->xpixalign;
+ dstoffsetY = dstinfo->ypixalign;
+
+ /* Determine geometry size. */
+ batch->dstwidth = dstinfo->geom->width
+ - dstinfo->xpixalign;
+ batch->dstheight = dstinfo->geom->height
+ - dstinfo->ypixalign;
+
+ /* Determine the physical size. */
+ dstinfo->physwidth = batch->dstwidth;
+ dstinfo->physheight = batch->dstheight;
+ break;
+
+ case ROT_ANGLE_90:
+ /* Determine the origin offset. */
+ dstoffsetX = dstinfo->ypixalign;
+ dstoffsetY = dstinfo->xpixalign;
+
+ /* Determine geometry size. */
+ batch->dstwidth = dstinfo->geom->width
+ - dstinfo->ypixalign;
+ batch->dstheight = dstinfo->geom->height
+ - dstinfo->xpixalign;
+
+ /* Determine the physical size. */
+ dstinfo->physwidth = dstinfo->geom->height
+ - dstinfo->xpixalign;
+ dstinfo->physheight = dstinfo->geom->width
+ - dstinfo->ypixalign;
+ break;
+
+ case ROT_ANGLE_180:
+ /* Determine the origin offset. */
+ dstoffsetX = 0;
+ dstoffsetY = 0;
+
+ /* Determine geometry size. */
+ batch->dstwidth = dstinfo->geom->width
+ - dstinfo->xpixalign;
+ batch->dstheight = dstinfo->geom->height
+ - dstinfo->ypixalign;
+
+ /* Determine the physical size. */
+ dstinfo->physwidth = batch->dstwidth;
+ dstinfo->physheight = batch->dstheight;
+ break;
+
+ case ROT_ANGLE_270:
+ /* Determine the origin offset. */
+ dstoffsetX = 0;
+ dstoffsetY = 0;
+
+ /* Determine geometry size. */
+ batch->dstwidth = dstinfo->geom->width
+ - dstinfo->ypixalign;
+ batch->dstheight = dstinfo->geom->height
+ - dstinfo->xpixalign;
+
+ /* Determine the physical size. */
+ dstinfo->physwidth = dstinfo->geom->height
+ - dstinfo->xpixalign;
+ dstinfo->physheight = dstinfo->geom->width
+ - dstinfo->ypixalign;
+ break;
+
+ default:
+ dstoffsetX = 0;
+ dstoffsetY = 0;
+ }
+
+ /* Compute adjusted destination rectangles. */
+ batch->dstadjusted.left
+ = batch->dstclipped.left
+ - dstoffsetX;
+ batch->dstadjusted.top
+ = batch->dstclipped.top
+ - dstoffsetY;
+ batch->dstadjusted.right
+ = batch->dstclipped.right
+ - dstoffsetX;
+ batch->dstadjusted.bottom
+ = batch->dstclipped.bottom
+ - dstoffsetY;
+
+ GCPRINT_RECT(GCZONE_DEST, "adjusted dest",
+ &batch->dstadjusted);
+
+ GCDBG(GCZONE_DEST, "aligned geometry size = %dx%d\n",
+ batch->dstwidth, batch->dstheight);
+ GCDBG(GCZONE_DEST, "aligned physical size = %dx%d\n",
+ dstinfo->physwidth, dstinfo->physheight);
+ GCDBG(GCZONE_DEST, "origin offset (pixels) = %d,%d\n",
+ dstoffsetX, dstoffsetY);
+ }
+
+ GCEXIT(GCZONE_DEST);
+}
+
+enum bverror parse_source(struct bvbltparams *bvbltparams,
+ struct gcbatch *batch,
+ struct bvrect *srcrect,
+ struct surfaceinfo *srcinfo)
+{
+ enum bverror bverror = BVERR_NONE;
+
+ GCENTER(GCZONE_SRC);
+ GCDBG(GCZONE_SRC, "parsing source #%d\n",
+ srcinfo->index + 1);
+
+ /* Parse the source format. */
+ if (parse_format(bvbltparams, srcinfo) != BVERR_NONE) {
+ bverror = (srcinfo->index == 0)
+ ? BVERR_SRC1GEOM_FORMAT
+ : BVERR_SRC2GEOM_FORMAT;
+ goto exit;
+ }
+
+ /* Parse orientation. */
+ srcinfo->angle = get_angle(srcinfo->geom->orientation);
+ if (srcinfo->angle == ROT_ANGLE_INVALID) {
+ BVSETBLTERROR((srcinfo->index == 0)
+ ? BVERR_SRC1GEOM
+ : BVERR_SRC2GEOM,
+ "unsupported source%d orientation %d.",
+ srcinfo->index + 1,
+ srcinfo->geom->orientation);
+ goto exit;
+ }
+
+ /* Determine source mirror. */
+ srcinfo->mirror = (srcinfo->index == 0)
+ ? (bvbltparams->flags >> BVFLAG_FLIP_SRC1_SHIFT)
+ & BVFLAG_FLIP_MASK
+ : (bvbltparams->flags >> BVFLAG_FLIP_SRC2_SHIFT)
+ & BVFLAG_FLIP_MASK;
+
+ GCDBG(GCZONE_SRC, " buffer length = %d\n", srcinfo->buf.desc->length);
+ GCDBG(GCZONE_SRC, " rotation %d degrees.\n", srcinfo->angle * 90);
+
+ if (srcinfo->buf.desc->auxtype == BVAT_PHYSDESC) {
+ struct bvphysdesc *bvphysdesc;
+ bvphysdesc = (struct bvphysdesc *) srcinfo->buf.desc->auxptr;
+ GCDBG(GCZONE_SRC, " physical descriptor = 0x%08X\n",
+ bvphysdesc);
+ GCDBG(GCZONE_SRC, " first page = 0x%08X\n",
+ bvphysdesc->pagearray[0]);
+ GCDBG(GCZONE_SRC, " page offset = 0x%08X\n",
+ bvphysdesc->pageoffset);
+ } else {
+ GCDBG(GCZONE_SRC, " virtual address = 0x%08X\n",
+ (unsigned int) srcinfo->buf.desc->virtaddr);
+ }
+
+ GCDBG(GCZONE_SRC, " stride = %ld\n",
+ srcinfo->geom->virtstride);
+ GCDBG(GCZONE_SRC, " geometry size = %dx%d\n",
+ srcinfo->geom->width, srcinfo->geom->height);
+ GCDBG(GCZONE_SRC, " mirror = %d\n", srcinfo->mirror);
+
+ /* Convert the rectangle. */
+ GCCONVERT_RECT(GCZONE_SRC,
+ " rect", srcrect, &srcinfo->rect);
+
+ /* Source must be 8 pixel aligned. */
+ if ((srcinfo->geom->virtstride
+ & (srcinfo->format.bitspp - 1)) != 0) {
+ BVSETBLTERROR((srcinfo->index == 0)
+ ? BVERR_SRC1GEOM_STRIDE
+ : BVERR_SRC2GEOM_STRIDE,
+ "source stride must be 8 pixel aligned.");
+ goto exit;
+ }
+
+ /* Planar YUV? */
+ if ((srcinfo->format.type == BVFMT_YUV) &&
+ (srcinfo->format.cs.yuv.planecount > 1)) {
+ int xpixalign;
+
+ /* Source rotation is not supported. */
+ if (srcinfo->angle != ROT_ANGLE_0) {
+ BVSETBLTERROR((srcinfo->index == 0)
+ ? BVERR_SRC1_ROT
+ : BVERR_SRC2_ROT,
+ "rotation of planar YUV is "
+ "not supported");
+ goto exit;
+ }
+
+ /* Check base address alignment. */
+ xpixalign = get_pixel_offset(srcinfo, 0);
+ if (xpixalign != 0) {
+ BVSETBLTERROR((srcinfo->index == 0)
+ ? BVERR_SRC1DESC_ALIGNMENT
+ : BVERR_SRC2DESC_ALIGNMENT,
+ "planar YUV base address must be "
+ "64 byte aligned.");
+ goto exit;
+ }
+ }
+
+ /* Validate source geometry. */
+ if (!valid_geom(srcinfo)) {
+ BVSETBLTERROR((srcinfo->index == 0)
+ ? BVERR_SRC1GEOM
+ : BVERR_SRC2GEOM,
+ "source%d geom exceeds surface size.",
+ srcinfo->index + 1);
+ goto exit;
+ }
+
+exit:
+ GCEXITARG(GCZONE_SRC, "bv%s = %d\n",
+ (bverror == BVERR_NONE) ? "result" : "error", bverror);
+ return bverror;
+}
+
+static enum bverror parse_implicitscale(struct bvbltparams *bvbltparams,
+ struct gcbatch *batch)
+{
+ enum bverror bverror = BVERR_NONE;
+ unsigned int quality;
+ unsigned int technique;
+ unsigned int imagetype;
+
+ GCENTER(GCZONE_SCALING);
+
+ quality = (bvbltparams->scalemode & BVSCALEDEF_QUALITY_MASK)
+ >> BVSCALEDEF_QUALITY_SHIFT;
+ technique = (bvbltparams->scalemode & BVSCALEDEF_TECHNIQUE_MASK)
+ >> BVSCALEDEF_TECHNIQUE_SHIFT;
+ imagetype = (bvbltparams->scalemode & BVSCALEDEF_TYPE_MASK)
+ >> BVSCALEDEF_TYPE_SHIFT;
+
+ GCDBG(GCZONE_SCALING, "quality = %d\n", quality);
+ GCDBG(GCZONE_SCALING, "technique = %d\n", technique);
+ GCDBG(GCZONE_SCALING, "imagetype = %d\n", imagetype);
+
+ switch (quality) {
+ case BVSCALEDEF_FASTEST >> BVSCALEDEF_QUALITY_SHIFT:
+ batch->op.filter.horkernelsize = 3;
+ batch->op.filter.verkernelsize = 3;
+ break;
+
+ case BVSCALEDEF_GOOD >> BVSCALEDEF_QUALITY_SHIFT:
+ batch->op.filter.horkernelsize = 5;
+ batch->op.filter.verkernelsize = 5;
+ break;
+
+ case BVSCALEDEF_BETTER >> BVSCALEDEF_QUALITY_SHIFT:
+ batch->op.filter.horkernelsize = 7;
+ batch->op.filter.verkernelsize = 7;
+ break;
+
+ case BVSCALEDEF_BEST >> BVSCALEDEF_QUALITY_SHIFT:
+ batch->op.filter.horkernelsize = 9;
+ batch->op.filter.verkernelsize = 9;
+ break;
+
+ default:
+ BVSETBLTERROR(BVERR_SCALE_MODE,
+ "unsupported scale quality 0x%02X", quality);
+ goto exit;
+ }
+
+ switch (technique) {
+ case BVSCALEDEF_DONT_CARE >> BVSCALEDEF_TECHNIQUE_SHIFT:
+ case BVSCALEDEF_NOT_NEAREST_NEIGHBOR >> BVSCALEDEF_TECHNIQUE_SHIFT:
+ break;
+
+ case BVSCALEDEF_POINT_SAMPLE >> BVSCALEDEF_TECHNIQUE_SHIFT:
+ batch->op.filter.horkernelsize = 1;
+ batch->op.filter.verkernelsize = 1;
+ break;
+
+ case BVSCALEDEF_INTERPOLATED >> BVSCALEDEF_TECHNIQUE_SHIFT:
+ break;
+
+ default:
+ BVSETBLTERROR(BVERR_SCALE_MODE,
+ "unsupported scale technique %d", technique);
+ goto exit;
+ }
+
+ switch (imagetype) {
+ case 0:
+ case BVSCALEDEF_PHOTO >> BVSCALEDEF_TYPE_SHIFT:
+ case BVSCALEDEF_DRAWING >> BVSCALEDEF_TYPE_SHIFT:
+ break;
+
+ default:
+ BVSETBLTERROR(BVERR_SCALE_MODE,
+ "unsupported image type %d", imagetype);
+ goto exit;
+ }
+
+ GCDBG(GCZONE_SCALING, "kernel size = %dx%d\n",
+ batch->op.filter.horkernelsize,
+ batch->op.filter.verkernelsize);
+
+exit:
+ GCEXIT(GCZONE_SCALING);
+ return bverror;
+}
+
+static enum bverror parse_explicitscale(struct bvbltparams *bvbltparams,
+ struct gcbatch *batch)
+{
+ enum bverror bverror = BVERR_NONE;
+ unsigned int horsize;
+ unsigned int versize;
+
+ GCENTER(GCZONE_SCALING);
+
+ horsize = (bvbltparams->scalemode & BVSCALEDEF_HORZ_MASK)
+ >> BVSCALEDEF_HORZ_SHIFT;
+ versize = (bvbltparams->scalemode & BVSCALEDEF_VERT_MASK)
+ >> BVSCALEDEF_VERT_SHIFT;
+
+ GCDBG(GCZONE_SCALING, "horsize = %d\n", horsize);
+ GCDBG(GCZONE_SCALING, "versize = %d\n", versize);
+
+ switch (horsize) {
+ case BVSCALEDEF_NEAREST_NEIGHBOR:
+ batch->op.filter.horkernelsize = 1;
+ break;
+
+ case BVSCALEDEF_LINEAR:
+ case BVSCALEDEF_CUBIC:
+ case BVSCALEDEF_3_TAP:
+ batch->op.filter.horkernelsize = 3;
+ break;
+
+ case BVSCALEDEF_5_TAP:
+ batch->op.filter.horkernelsize = 5;
+ break;
+
+ case BVSCALEDEF_7_TAP:
+ batch->op.filter.horkernelsize = 7;
+ break;
+
+ case BVSCALEDEF_9_TAP:
+ batch->op.filter.horkernelsize = 9;
+ break;
+
+ default:
+ BVSETBLTERROR(BVERR_SCALE_MODE,
+ "unsupported horizontal kernel size %d", horsize);
+ goto exit;
+ }
+
+ switch (versize) {
+ case BVSCALEDEF_NEAREST_NEIGHBOR:
+ batch->op.filter.verkernelsize = 1;
+ break;
+
+ case BVSCALEDEF_LINEAR:
+ case BVSCALEDEF_CUBIC:
+ case BVSCALEDEF_3_TAP:
+ batch->op.filter.verkernelsize = 3;
+ break;
+
+ case BVSCALEDEF_5_TAP:
+ batch->op.filter.verkernelsize = 5;
+ break;
+
+ case BVSCALEDEF_7_TAP:
+ batch->op.filter.verkernelsize = 7;
+ break;
+
+ case BVSCALEDEF_9_TAP:
+ batch->op.filter.verkernelsize = 9;
+ break;
+
+ default:
+ BVSETBLTERROR(BVERR_SCALE_MODE,
+ "unsupported vertical kernel size %d", versize);
+ goto exit;
+ }
+
+ GCDBG(GCZONE_SCALING, "kernel size = %dx%d\n",
+ batch->op.filter.horkernelsize,
+ batch->op.filter.verkernelsize);
+
+exit:
+ GCEXIT(GCZONE_SCALING);
+ return bverror;
+}
+
+enum bverror parse_scalemode(struct bvbltparams *bvbltparams,
+ struct gcbatch *batch)
+{
+ enum bverror bverror;
+ unsigned int scaleclass;
+
+ GCENTER(GCZONE_SCALING);
+
+ scaleclass = (bvbltparams->scalemode & BVSCALEDEF_CLASS_MASK)
+ >> BVSCALEDEF_CLASS_SHIFT;
+
+ GCDBG(GCZONE_SCALING, "scaleclass = %d\n", scaleclass);
+
+ switch (scaleclass) {
+ case BVSCALEDEF_IMPLICIT >> BVSCALEDEF_CLASS_SHIFT:
+ bverror = parse_implicitscale(bvbltparams, batch);
+ break;
+
+ case BVSCALEDEF_EXPLICIT >> BVSCALEDEF_CLASS_SHIFT:
+ bverror = parse_explicitscale(bvbltparams, batch);
+ break;
+
+ default:
+ BVSETBLTERROR(BVERR_SCALE_MODE,
+ "unsupported scale class %d", scaleclass);
+ goto exit;
+ }
+
+exit:
+ GCEXIT(GCZONE_SCALING);
+ return bverror;
+}