diff options
author | Alexei Shlychkov <x0177296@ti.com> | 2012-09-13 04:36:57 -0700 |
---|---|---|
committer | Ziyann <jaraidaniel@gmail.com> | 2014-10-01 13:01:01 +0200 |
commit | e5d10c5f79bacfebb9de16c1f7e5874e21669c7f (patch) | |
tree | b1dd19b75a246ed593522ee443be8710e20f8574 /drivers/misc | |
parent | 05932f1cddaf2fdf7218aafdb7bc6c4924e56550 (diff) | |
download | kernel_samsung_tuna-e5d10c5f79bacfebb9de16c1f7e5874e21669c7f.zip kernel_samsung_tuna-e5d10c5f79bacfebb9de16c1f7e5874e21669c7f.tar.gz kernel_samsung_tuna-e5d10c5f79bacfebb9de16c1f7e5874e21669c7f.tar.bz2 |
gcx: scaler update.
Added special handling for rotation.
Added bandwidth optimizations.
Bug fixes.
Change-Id: I5f188b46355b51444e18a29ebcf0f62a557924d0
Signed-off-by: Alexei Shlychkov <x0177296@ti.com>
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/gcx/gcbv/gcbv.c | 14 | ||||
-rw-r--r-- | drivers/misc/gcx/gcbv/gcbv.h | 33 | ||||
-rw-r--r-- | drivers/misc/gcx/gcbv/gcfilter.c | 1033 | ||||
-rw-r--r-- | drivers/misc/gcx/gcbv/gcparser.c | 37 |
4 files changed, 859 insertions, 258 deletions
diff --git a/drivers/misc/gcx/gcbv/gcbv.c b/drivers/misc/gcx/gcbv/gcbv.c index 9872881..2aa6ffa 100644 --- a/drivers/misc/gcx/gcbv/gcbv.c +++ b/drivers/misc/gcx/gcbv/gcbv.c @@ -1140,6 +1140,13 @@ enum bverror bv_blt(struct bvbltparams *bvbltparams) srcinfo[srccount].index = 0; srcinfo[srccount].buf = bvbltparams->src1; srcinfo[srccount].geom = bvbltparams->src1geom; + srcinfo[srccount].newgeom + = gcbatch->batchflags + & BVBATCH_SRC1; + srcinfo[srccount].newrect + = gcbatch->batchflags + & (BVBATCH_SRC1RECT_ORIGIN | + BVBATCH_SRC1RECT_SIZE); srcrect[srccount] = &bvbltparams->src1rect; bverror = parse_source(bvbltparams, gcbatch, @@ -1180,6 +1187,13 @@ enum bverror bv_blt(struct bvbltparams *bvbltparams) srcinfo[srccount].index = 1; srcinfo[srccount].buf = bvbltparams->src2; srcinfo[srccount].geom = bvbltparams->src2geom; + srcinfo[srccount].newgeom + = gcbatch->batchflags + & BVBATCH_SRC2; + srcinfo[srccount].newrect + = gcbatch->batchflags + & (BVBATCH_SRC2RECT_ORIGIN | + BVBATCH_SRC2RECT_SIZE); srcrect[srccount] = &bvbltparams->src2rect; bverror = parse_source(bvbltparams, gcbatch, diff --git a/drivers/misc/gcx/gcbv/gcbv.h b/drivers/misc/gcx/gcbv/gcbv.h index 6b72f90..fa4b0a2 100644 --- a/drivers/misc/gcx/gcbv/gcbv.h +++ b/drivers/misc/gcx/gcbv/gcbv.h @@ -332,9 +332,11 @@ struct surfaceinfo { /* Surface geometry. */ struct bvsurfgeom *geom; + bool newgeom; /* Rectangle to source from/render to. */ struct gcrect rect; + bool newrect; /* Surface format. */ struct bvformatxlate format; @@ -403,6 +405,27 @@ struct gcfilter { /* Scale factors. */ unsigned int horscalefactor; unsigned int verscalefactor; + + /* Destination angle. */ + bool angleoverride; + int dstangle; + + /* Geometry size that follows angle adjustments. */ + struct bvsurfgeom dstgeom; + + /* Original source and destination rectangles adjusted + * by the source angle. */ + struct gcrect dstrect; + struct gcrect dstrectaux; + + /* Clipped destination rectangle adjusted by the source angle. */ + struct gcrect dstclipped; + struct gcrect dstclippedaux; + + /* Destination rectangles that were clipped, adjusted for + * the surface misalignment and the source angle. */ + struct gcrect dstadjusted; + struct gcrect dstadjustedaux; }; /* Batch header. */ @@ -417,7 +440,7 @@ struct gcbatch { gcbatchend batchend; /* State of the current operation. */ - union { + struct { struct gcblit blit; struct gcfilter filter; } op; @@ -425,6 +448,10 @@ struct gcbatch { /* Destination surface. */ struct surfaceinfo dstinfo; + /* Aux rectangle present. */ + bool haveaux; + struct gcrect dstrectaux; + /* Clipped destination rectangle coordinates. */ struct gcrect dstclipped; struct gcrect dstclippedaux; @@ -442,7 +469,9 @@ struct gcbatch { unsigned int dstwidth; unsigned int dstheight; - /* Physical size of the destination surface. */ + /* Physical size of the source and destination surfaces. */ + unsigned int srcphyswidth; + unsigned int srcphysheight; unsigned int dstphyswidth; unsigned int dstphysheight; diff --git a/drivers/misc/gcx/gcbv/gcfilter.c b/drivers/misc/gcx/gcbv/gcfilter.c index 79806b1..7ffee49 100644 --- a/drivers/misc/gcx/gcbv/gcfilter.c +++ b/drivers/misc/gcx/gcbv/gcfilter.c @@ -60,12 +60,18 @@ #define GCZONE_FILTER (1 << 1) #define GCZONE_BLEND (1 << 2) #define GCZONE_TYPE (1 << 3) +#define GCZONE_SRC (1 << 4) +#define GCZONE_DEST (1 << 5) +#define GCZONE_SURF (1 << 6) GCDBG_FILTERDEF(gcfilter, GCZONE_NONE, "kernel", "filter", "blend", - "type") + "type", + "src", + "dest", + "surf") /******************************************************************************* @@ -74,6 +80,13 @@ GCDBG_FILTERDEF(gcfilter, GCZONE_NONE, #define GC_BITS_PER_CACHELINE (64 * 8) +enum gcscaletype { + GC_SCALE_OPF, + GC_SCALE_HOR, + GC_SCALE_VER, + GC_SCALE_HOR_FLIPPED, + GC_SCALE_VER_FLIPPED +}; /******************************************************************************* * Scale factor format: unsigned 1.31 fixed point. @@ -487,6 +500,7 @@ static enum bverror load_filter(struct bvbltparams *bvbltparams, GCDBG(GCZONE_KERNEL, "kernelsize = %d\n", kernelsize); GCDBG(GCZONE_KERNEL, "srcsize = %d\n", srcsize); GCDBG(GCZONE_KERNEL, "dstsize = %d\n", dstsize); + GCDBG(GCZONE_KERNEL, "scalefactor = 0x%08X\n", scalefactor); /* Is the filter already loaded? */ if ((gccontext->loadedfilter != NULL) && @@ -561,6 +575,8 @@ static enum bverror load_filter(struct bvbltparams *bvbltparams, } load: + GCDBG(GCZONE_KERNEL, "loading filter.\n"); + /* Load the filter. */ bverror = claim_buffer(bvbltparams, batch, sizeof(struct gcmofilterkernel), @@ -596,6 +612,292 @@ static inline unsigned int get_scale_factor(unsigned int srcsize, /******************************************************************************* + * Rotates the specified rectangle to the specified angle. + */ + +static void rotate_gcrect(int angle, + struct bvsurfgeom *srcgeom, struct gcrect *srcrect, + struct bvsurfgeom *dstgeom, struct gcrect *dstrect) +{ + unsigned int width, height; + struct gcrect rect; + + GCENTER(GCZONE_SURF); + + GCDBG(GCZONE_SURF, "src geom size = %dx%d\n", + srcgeom->width, srcgeom->height); + + switch (angle) { + case ROT_ANGLE_0: + GCDBG(GCZONE_SURF, "ROT_ANGLE_0\n"); + + if (dstgeom != srcgeom) { + dstgeom->width = srcgeom->width; + dstgeom->height = srcgeom->height; + } + + if (dstrect != srcrect) + *dstrect = *srcrect; + break; + + case ROT_ANGLE_90: + GCDBG(GCZONE_SURF, "ROT_ANGLE_90\n"); + + width = srcgeom->width; + height = srcgeom->height; + + dstgeom->width = height; + dstgeom->height = width; + + rect.left = height - srcrect->bottom; + rect.top = srcrect->left; + rect.right = height - srcrect->top; + rect.bottom = srcrect->right; + + *dstrect = rect; + break; + + case ROT_ANGLE_180: + GCDBG(GCZONE_SURF, "ROT_ANGLE_180\n"); + + width = srcgeom->width; + height = srcgeom->height; + + if (dstgeom != srcgeom) { + dstgeom->width = width; + dstgeom->height = height; + } + + rect.left = width - srcrect->right; + rect.top = height - srcrect->bottom; + rect.right = width - srcrect->left; + rect.bottom = height - srcrect->top; + + *dstrect = rect; + break; + + case ROT_ANGLE_270: + GCDBG(GCZONE_SURF, "ROT_ANGLE_270\n"); + + width = srcgeom->width; + height = srcgeom->height; + + dstgeom->width = height; + dstgeom->height = width; + + rect.left = srcrect->top; + rect.top = width - srcrect->right; + rect.right = srcrect->bottom; + rect.bottom = width - srcrect->left; + + *dstrect = rect; + break; + } + + GCEXIT(GCZONE_SURF); +} + + +/******************************************************************************* + * Setup destination rotation parameters. + */ + +void process_rotation(struct bvbltparams *bvbltparams, + struct gcbatch *batch, + struct surfaceinfo *srcinfo, + int adjangle) +{ + GCENTER(GCZONE_DEST); + + if (srcinfo->newgeom || + ((batch->batchflags & (BVBATCH_CLIPRECT | + BVBATCH_DESTRECT | + BVBATCH_DST)) != 0)) { + bool orthogonal; + struct gcfilter *gcfilter; + struct surfaceinfo *dstinfo; + int dstoffsetX, dstoffsetY; + + /* Get some shortcuts. */ + dstinfo = &batch->dstinfo; + gcfilter = &batch->op.filter; + + /* Compute the adjusted destination angle. */ + gcfilter->dstangle + = (dstinfo->angle + (4 - srcinfo->angle)) % 4; + GCDBG(GCZONE_DEST, "dstangle = %d\n", gcfilter->dstangle); + + /* Determine whether the new and the old destination angles + * are orthogonal to each other. */ + orthogonal = (gcfilter->dstangle % 2) != (dstinfo->angle % 2); + + switch (gcfilter->dstangle) { + case ROT_ANGLE_0: + /* Determine the origin offset. */ + dstoffsetX = dstinfo->pixalign; + dstoffsetY = 0; + + /* Determine geometry size. */ + if (orthogonal) { + batch->dstwidth = dstinfo->geom->height + - dstinfo->pixalign; + batch->dstheight = dstinfo->geom->width; + } else { + batch->dstwidth = dstinfo->geom->width + - dstinfo->pixalign; + batch->dstheight = dstinfo->geom->height; + } + + /* Determine the physical size. */ + dstinfo->physwidth = batch->dstwidth; + dstinfo->physheight = batch->dstheight; + break; + + case ROT_ANGLE_90: + /* Determine the origin offset. */ + dstoffsetX = 0; + dstoffsetY = dstinfo->pixalign; + + if (orthogonal) { + /* Determine geometry size. */ + batch->dstwidth = dstinfo->geom->height; + batch->dstheight = dstinfo->geom->width + - dstinfo->pixalign; + + /* Determine the physical size. */ + dstinfo->physwidth = dstinfo->geom->width + - dstinfo->pixalign; + dstinfo->physheight = dstinfo->geom->height; + } else { + /* Determine geometry size. */ + batch->dstwidth = dstinfo->geom->width; + batch->dstheight = dstinfo->geom->height + - dstinfo->pixalign; + + /* Determine the physical size. */ + dstinfo->physwidth = dstinfo->geom->height + - dstinfo->pixalign; + dstinfo->physheight = dstinfo->geom->width; + } + break; + + case ROT_ANGLE_180: + /* Determine the origin offset. */ + dstoffsetX = 0; + dstoffsetY = 0; + + /* Determine geometry size. */ + if (orthogonal) { + batch->dstwidth = dstinfo->geom->height + - dstinfo->pixalign; + batch->dstheight = dstinfo->geom->width; + } else { + batch->dstwidth = dstinfo->geom->width + - dstinfo->pixalign; + batch->dstheight = dstinfo->geom->height; + } + + /* 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; + + if (orthogonal) { + /* Determine geometry size. */ + batch->dstwidth = dstinfo->geom->height; + batch->dstheight = dstinfo->geom->width + - dstinfo->pixalign; + + /* Determine the physical size. */ + dstinfo->physwidth = dstinfo->geom->width + - dstinfo->pixalign; + dstinfo->physheight = dstinfo->geom->height; + } else { + /* Determine geometry size. */ + batch->dstwidth = dstinfo->geom->width; + batch->dstheight = dstinfo->geom->height + - dstinfo->pixalign; + + /* Determine the physical size. */ + dstinfo->physwidth = dstinfo->geom->height + - dstinfo->pixalign; + dstinfo->physheight = dstinfo->geom->width; + } + break; + + default: + dstoffsetX = 0; + dstoffsetY = 0; + } + + /* Rotate the original destination rectangle + * to match the new angle. */ + rotate_gcrect(adjangle, + dstinfo->geom, &dstinfo->rect, + &gcfilter->dstgeom, &gcfilter->dstrect); + + /* Rotate the clipped destination rectangle. */ + rotate_gcrect(adjangle, + dstinfo->geom, &batch->dstclipped, + &gcfilter->dstgeom, &gcfilter->dstclipped); + + /* Compute the adjusted the destination rectangle. */ + gcfilter->dstadjusted.left + = gcfilter->dstclipped.left - dstoffsetX; + gcfilter->dstadjusted.top + = gcfilter->dstclipped.top - dstoffsetY; + gcfilter->dstadjusted.right + = gcfilter->dstclipped.right - dstoffsetX; + gcfilter->dstadjusted.bottom + = gcfilter->dstclipped.bottom - dstoffsetY; + + GCPRINT_RECT(GCZONE_DEST, "dstadjusted", + &gcfilter->dstadjusted); + + if (batch->haveaux) { + /* Rotate the original aux destination rectangle + * to match the new angle. */ + rotate_gcrect(adjangle, dstinfo->geom, + &batch->dstrectaux, &gcfilter->dstgeom, + &gcfilter->dstrectaux); + + /* Rotate the aux destination rectangle. */ + rotate_gcrect(adjangle, dstinfo->geom, + &batch->dstclippedaux, &gcfilter->dstgeom, + &gcfilter->dstclippedaux); + + /* Compute the adjust the aux destination rectangle. */ + gcfilter->dstadjustedaux.left + = batch->dstclippedaux.left - dstoffsetX; + gcfilter->dstadjustedaux.top + = batch->dstclippedaux.top - dstoffsetY; + gcfilter->dstadjustedaux.right + = batch->dstclippedaux.right - dstoffsetX; + gcfilter->dstadjustedaux.bottom + = batch->dstclippedaux.bottom - dstoffsetY; + + GCPRINT_RECT(GCZONE_DEST, "dstadjustedaux", + &gcfilter->dstadjustedaux); + } + + 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); +} + + +/******************************************************************************* * Rasterizer setup. */ @@ -608,12 +910,14 @@ static enum bverror startvr(struct bvbltparams *bvbltparams, unsigned int srcx, unsigned int srcy, struct gcrect *dstrect, - struct gcregvrconfig config, - bool prepass) + int srcangle, + int dstangle, + enum gcscaletype scaletype) { enum bverror bverror; struct gccontext *gccontext = get_context(); struct gcalpha *gca; + struct gcfilter *gcfilter; struct gcmovrdst *gcmovrdst; struct gcmovrsrc *gcmovrsrc; @@ -623,15 +927,28 @@ static enum bverror startvr(struct bvbltparams *bvbltparams, struct gcmostartvr *gcmostartvr; struct gcrect srcrect; - int srcpixalign, srcbytealign; - int srcsurfwidth, srcsurfheight; - GCENTER(GCZONE_FILTER); + GCENTERARG(GCZONE_FILTER, "scaletype = %d\n", scaletype); + + /* Get a shortcut to the filter properties. */ + gcfilter = &batch->op.filter; /*********************************************************************** * Program the destination. */ + GCDBG(GCZONE_FILTER, "destination:\n"); + GCDBG(GCZONE_FILTER, " angle = %d\n", dstangle); + GCDBG(GCZONE_FILTER, " pixalign = %d\n", dstinfo->pixalign); + GCDBG(GCZONE_FILTER, " bytealign = %d\n", dstinfo->bytealign); + GCDBG(GCZONE_FILTER, " virtstride = %d\n", dstinfo->geom->virtstride); + GCDBG(GCZONE_FILTER, " format = %d\n", dstinfo->format.format); + GCDBG(GCZONE_FILTER, " swizzle = %d\n", dstinfo->format.swizzle); + GCDBG(GCZONE_FILTER, " premul = %d\n", dstinfo->format.premultiplied); + GCDBG(GCZONE_FILTER, " physwidth = %d\n", dstinfo->physwidth); + GCDBG(GCZONE_FILTER, " physheight = %d\n", dstinfo->physheight); + GCPRINT_RECT(GCZONE_FILTER, " rect", dstrect); + /* Allocate command buffer. */ bverror = claim_buffer(bvbltparams, batch, sizeof(struct gcmovrdst), @@ -661,56 +978,25 @@ static enum bverror startvr(struct bvbltparams *bvbltparams, * Program the source. */ - /* Initialize the source rectangle. */ - srcrect.left = srcinfo->rect.left; - srcrect.top = srcinfo->rect.top; - srcrect.right = srcinfo->rect.right; - srcrect.bottom = srcinfo->rect.bottom; - - /* Compute the source alignments needed to compensate - * for the surface base address misalignment if any. */ - srcpixalign = get_pixel_offset(srcinfo, 0); - srcbytealign = (srcpixalign * (int) srcinfo->format.bitspp) / 8; - - switch (srcinfo->angle) { - case ROT_ANGLE_0: - /* Adjust the source rectangle. */ - srcrect.left -= srcpixalign; - srcrect.right -= srcpixalign; - srcx -= (srcpixalign << 16); - - /* Determine source size. */ - srcsurfwidth = srcinfo->geom->width - srcpixalign; - srcsurfheight = srcinfo->geom->height; - break; - - case ROT_ANGLE_90: - /* Adjust the source rectangle. */ - srcrect.top -= srcpixalign; - srcrect.bottom -= srcpixalign; - srcy -= (srcpixalign << 16); - - /* Determine source size. */ - srcsurfwidth = srcinfo->geom->height - srcpixalign; - srcsurfheight = srcinfo->geom->width; - break; - - case ROT_ANGLE_180: - /* Determine source size. */ - srcsurfwidth = srcinfo->geom->width - srcpixalign; - srcsurfheight = srcinfo->geom->height; - break; - - case ROT_ANGLE_270: - /* Determine source size. */ - srcsurfwidth = srcinfo->geom->height - srcpixalign; - srcsurfheight = srcinfo->geom->width; - break; - - default: - srcsurfwidth = 0; - srcsurfheight = 0; - } + /* Determine adjusted source bounding rectangle and origin. */ + srcrect = srcinfo->rect; + srcrect.left -= srcinfo->pixalign; + srcrect.right -= srcinfo->pixalign; + srcx -= (srcinfo->pixalign << 16); + + GCDBG(GCZONE_FILTER, "source:\n"); + GCDBG(GCZONE_FILTER, " angle = %d\n", srcangle); + GCDBG(GCZONE_FILTER, " pixalign = %d\n", srcinfo->pixalign); + GCDBG(GCZONE_FILTER, " bytealign = %d\n", srcinfo->bytealign); + GCDBG(GCZONE_FILTER, " virtstride = %d\n", srcinfo->geom->virtstride); + GCDBG(GCZONE_FILTER, " format = %d\n", srcinfo->format.format); + GCDBG(GCZONE_FILTER, " swizzle = %d\n", srcinfo->format.swizzle); + GCDBG(GCZONE_FILTER, " premul = %d\n", srcinfo->format.premultiplied); + GCDBG(GCZONE_FILTER, " physwidth = %d\n", srcinfo->physwidth); + GCDBG(GCZONE_FILTER, " physheight = %d\n", srcinfo->physheight); + GCPRINT_RECT(GCZONE_FILTER, " rect", &srcrect); + + GCDBG(GCZONE_FILTER, "src origin: 0x%08X,0x%08X\n", srcx, srcy); /* Allocate command buffer. */ bverror = claim_buffer(bvbltparams, batch, @@ -719,7 +1005,7 @@ static enum bverror startvr(struct bvbltparams *bvbltparams, if (bverror != BVERR_NONE) goto exit; - add_fixup(bvbltparams, batch, &gcmovrsrc->address, srcbytealign); + add_fixup(bvbltparams, batch, &gcmovrsrc->address, srcinfo->bytealign); gcmovrsrc->config_ldst = gcmovrsrc_config_ldst; @@ -727,7 +1013,7 @@ static enum bverror startvr(struct bvbltparams *bvbltparams, gcmovrsrc->stride = srcinfo->geom->virtstride; gcmovrsrc->rotation.raw = 0; - gcmovrsrc->rotation.reg.surf_width = srcsurfwidth; + gcmovrsrc->rotation.reg.surf_width = srcinfo->physwidth; gcmovrsrc->config.raw = 0; gcmovrsrc->config.reg.swizzle = srcinfo->format.swizzle; @@ -754,18 +1040,12 @@ static enum bverror startvr(struct bvbltparams *bvbltparams, /* Program rotation. */ gcmovrsrc->rotation_ldst = gcmovrsrc_rotation_ldst; - gcmovrsrc->rotationheight.reg.height = srcsurfheight; + gcmovrsrc->rotationheight.reg.height = srcinfo->physheight; gcmovrsrc->rotationangle.raw = 0; - gcmovrsrc->rotationangle.reg.src = rotencoding[srcinfo->angle]; - gcmovrsrc->rotationangle.reg.dst = rotencoding[dstinfo->angle]; - - if (prepass) { - gcmovrsrc->rotationangle.reg.src_mirror = GCREG_MIRROR_NONE; - gcmovrsrc->rotationangle.reg.dst_mirror = GCREG_MIRROR_NONE; - } else { - gcmovrsrc->rotationangle.reg.src_mirror = srcinfo->mirror; - gcmovrsrc->rotationangle.reg.dst_mirror = dstinfo->mirror; - } + gcmovrsrc->rotationangle.reg.src = rotencoding[srcangle]; + gcmovrsrc->rotationangle.reg.dst = rotencoding[dstangle]; + gcmovrsrc->rotationangle.reg.src_mirror = srcinfo->mirror; + gcmovrsrc->rotationangle.reg.dst_mirror = dstinfo->mirror; gcmovrsrc->rop_ldst = gcmovrsrc_rop_ldst; gcmovrsrc->rop.raw = 0; @@ -778,25 +1058,122 @@ static enum bverror startvr(struct bvbltparams *bvbltparams, gcmovrsrc->mult.reg.srcglobalpremul = GCREG_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY_DISABLE; - if ((srcinfo->geom->format & OCDFMTDEF_NON_PREMULT) != 0) + if (srcinfo->format.premultiplied) gcmovrsrc->mult.reg.srcpremul - = GCREG_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY_ENABLE; + = GCREG_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY_DISABLE; else gcmovrsrc->mult.reg.srcpremul - = GCREG_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY_DISABLE; + = GCREG_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY_ENABLE; - if ((dstinfo->geom->format & OCDFMTDEF_NON_PREMULT) != 0) { + if (dstinfo->format.premultiplied) { gcmovrsrc->mult.reg.dstpremul - = GCREG_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY_ENABLE; + = GCREG_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY_DISABLE; gcmovrsrc->mult.reg.dstdemul - = GCREG_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY_ENABLE; + = GCREG_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY_DISABLE; } else { gcmovrsrc->mult.reg.dstpremul - = GCREG_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY_DISABLE; + = GCREG_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY_ENABLE; gcmovrsrc->mult.reg.dstdemul - = GCREG_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY_DISABLE; + = GCREG_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY_ENABLE; + } + + /* Program YUV source. */ + if (srcinfo->format.type == BVFMT_YUV) { + struct gcmoyuv1 *gcmoyuv1; + struct gcmoyuv2 *gcmoyuv2; + struct gcmoyuv3 *gcmoyuv3; + int ushift, vshift; + + switch (srcinfo->format.cs.yuv.planecount) { + case 1: + bverror = claim_buffer(bvbltparams, batch, + sizeof(struct gcmoyuv1), + (void **) &gcmoyuv1); + if (bverror != BVERR_NONE) + goto exit; + + gcmoyuv1->pectrl_ldst = gcmoyuv_pectrl_ldst; + gcmoyuv1->pectrl.raw = 0; + gcmoyuv1->pectrl.reg.standard + = srcinfo->format.cs.yuv.std; + gcmoyuv1->pectrl.reg.swizzle + = srcinfo->format.swizzle; + gcmoyuv1->pectrl.reg.convert + = GCREG_PE_CONTROL_YUVRGB_DISABLED; + break; + + case 2: + bverror = claim_buffer(bvbltparams, batch, + sizeof(struct gcmoyuv2), + (void **) &gcmoyuv2); + if (bverror != BVERR_NONE) + goto exit; + + gcmoyuv2->pectrl_ldst = gcmoyuv_pectrl_ldst; + gcmoyuv2->pectrl.raw = 0; + gcmoyuv2->pectrl.reg.standard + = srcinfo->format.cs.yuv.std; + gcmoyuv2->pectrl.reg.swizzle + = srcinfo->format.swizzle; + gcmoyuv2->pectrl.reg.convert + = GCREG_PE_CONTROL_YUVRGB_DISABLED; + + ushift = srcinfo->bytealign + + srcinfo->geom->virtstride + * srcinfo->physheight; + GCDBG(GCZONE_FILTER, "ushift = 0x%08X (%d)\n", + ushift, ushift); + + add_fixup(bvbltparams, batch, &gcmoyuv2->uplaneaddress, + ushift); + + gcmoyuv2->plane_ldst = gcmoyuv2_plane_ldst; + gcmoyuv2->uplaneaddress = GET_MAP_HANDLE(srcmap); + gcmoyuv2->uplanestride = srcinfo->geom->virtstride; + break; + + case 3: + bverror = claim_buffer(bvbltparams, batch, + sizeof(struct gcmoyuv3), + (void **) &gcmoyuv3); + if (bverror != BVERR_NONE) + goto exit; + + gcmoyuv3->pectrl_ldst = gcmoyuv_pectrl_ldst; + gcmoyuv3->pectrl.raw = 0; + gcmoyuv3->pectrl.reg.standard + = srcinfo->format.cs.yuv.std; + gcmoyuv3->pectrl.reg.swizzle + = srcinfo->format.swizzle; + gcmoyuv3->pectrl.reg.convert + = GCREG_PE_CONTROL_YUVRGB_DISABLED; + + ushift = srcinfo->bytealign + + srcinfo->geom->virtstride + * srcinfo->physheight; + vshift = ushift + + srcinfo->geom->virtstride + * srcinfo->physheight / 4; + + GCDBG(GCZONE_FILTER, "ushift = 0x%08X (%d)\n", + ushift, ushift); + GCDBG(GCZONE_FILTER, "vshift = 0x%08X (%d)\n", + vshift, vshift); + + add_fixup(bvbltparams, batch, &gcmoyuv3->uplaneaddress, + ushift); + add_fixup(bvbltparams, batch, &gcmoyuv3->vplaneaddress, + vshift); + + gcmoyuv3->plane_ldst = gcmoyuv3_plane_ldst; + gcmoyuv3->uplaneaddress = GET_MAP_HANDLE(srcmap); + gcmoyuv3->uplanestride = srcinfo->geom->virtstride / 2; + gcmoyuv3->vplaneaddress = GET_MAP_HANDLE(srcmap); + gcmoyuv3->vplanestride = srcinfo->geom->virtstride / 2; + break; + } } /*********************************************************************** @@ -804,7 +1181,7 @@ static enum bverror startvr(struct bvbltparams *bvbltparams, */ gca = srcinfo->gca; - if (prepass || (gca == NULL)) { + if (gca == NULL) { bverror = claim_buffer(bvbltparams, batch, sizeof(struct gcmoalphaoff), (void **) &gcmoalphaoff); @@ -880,19 +1257,47 @@ static enum bverror startvr(struct bvbltparams *bvbltparams, if (bverror != BVERR_NONE) goto exit; - gcmostartvr->scale_ldst = gcmostartvr_scale_ldst; - gcmostartvr->scalex = batch->op.filter.horscalefactor; - gcmostartvr->scaley = batch->op.filter.verscalefactor; + switch (scaletype) { + case GC_SCALE_OPF: + gcmostartvr->scalex = gcfilter->horscalefactor; + gcmostartvr->scaley = gcfilter->verscalefactor; + gcmostartvr->config = gcregvrconfig_onepass; + break; + case GC_SCALE_HOR: + gcmostartvr->scalex = gcfilter->horscalefactor; + gcmostartvr->scaley = 0; + gcmostartvr->config = gcregvrconfig_horizontal; + break; + + case GC_SCALE_VER: + gcmostartvr->scalex = 0; + gcmostartvr->scaley = gcfilter->verscalefactor; + gcmostartvr->config = gcregvrconfig_vertical; + break; + + case GC_SCALE_HOR_FLIPPED: + gcmostartvr->scalex = 0; + gcmostartvr->scaley = gcfilter->horscalefactor; + gcmostartvr->config = gcregvrconfig_vertical; + break; + + case GC_SCALE_VER_FLIPPED: + gcmostartvr->scalex = gcfilter->verscalefactor; + gcmostartvr->scaley = 0; + gcmostartvr->config = gcregvrconfig_horizontal; + break; + } + + gcmostartvr->scale_ldst = gcmostartvr_scale_ldst; gcmostartvr->rect_ldst = gcmostartvr_rect_ldst; + gcmostartvr->config_ldst = gcmostartvr_config_ldst; + gcmostartvr->lt.left = dstrect->left; gcmostartvr->lt.top = dstrect->top; gcmostartvr->rb.right = dstrect->right; gcmostartvr->rb.bottom = dstrect->bottom; - gcmostartvr->config_ldst = gcmostartvr_config_ldst; - gcmostartvr->config = config; - exit: GCEXITARG(GCZONE_FILTER, "bv%s = %d\n", (bverror == BVERR_NONE) ? "result" : "error", bverror); @@ -911,10 +1316,20 @@ enum bverror do_filter(struct bvbltparams *bvbltparams, enum bverror bverror = BVERR_NONE; struct gccontext *gccontext = get_context(); + struct gcfilter *gcfilter; struct surfaceinfo *dstinfo; - struct bvrect *dstrect; - struct gcrect *dstrectclipped; - struct gcrect dstadjusted; + + bool scalex, scaley; + bool singlepass, twopass; + + struct gcrect *srcrect; + struct gcrect *dstrect; + struct gcrect *dstclipped; + struct gcrect *dstadjusted; + + struct bvsurfgeom dstrotated0geom; + struct gcrect dstrotated0; + int dstleftoffs, dsttopoffs, dstrightoffs; int srcleftoffs, srctopoffs, srcrightoffs; @@ -924,14 +1339,19 @@ enum bverror do_filter(struct bvbltparams *bvbltparams, struct gcmovrconfigex *gcmovrconfigex; + int adjangle; unsigned int srcx, srcy; unsigned int srcwidth, srcheight; + unsigned int dstwidth, dstheight; unsigned int horscalefactor, verscalefactor; unsigned int kernelsize; - int horpass, verpass; GCENTER(GCZONE_FILTER); + /* Get some shortcuts. */ + dstinfo = &batch->dstinfo; + gcfilter = &batch->op.filter; + /* Finish previous batch if any. */ bverror = batch->batchend(bvbltparams, batch); if (bverror != BVERR_NONE) @@ -954,77 +1374,132 @@ enum bverror do_filter(struct bvbltparams *bvbltparams, if (bverror != BVERR_NONE) goto exit; - /* Setup rotation. */ - process_dest_rotation(bvbltparams, batch); - - /* Additional stride requirements. */ - if (srcinfo->format.format == GCREG_DE_FORMAT_NV12) { - /* Nv12 may be shifted up to 32 bytes for alignment. - * In the worst case stride must be 32 bytes greater. - */ - int min_stride = srcinfo->geom->width + 32; - - if (srcinfo->geom->virtstride < min_stride) { - BVSETBLTERROR((srcinfo->index == 0) - ? BVERR_SRC1GEOM_STRIDE - : BVERR_SRC2GEOM_STRIDE, - "nv12 source stride too small (%ld < %d)\n", - srcinfo->geom->virtstride, - min_stride); - goto exit; - } + /* Compute the source alignments needed to compensate + * for the surface base address misalignment if any. */ + srcinfo->pixalign = get_pixel_offset(srcinfo, 0); + srcinfo->bytealign = (srcinfo->pixalign + * (int) srcinfo->format.bitspp) / 8; + GCDBG(GCZONE_SRC, "source surface offset (pixels) = %d,0\n", + srcinfo->pixalign); + GCDBG(GCZONE_SRC, "source surface offset (bytes) = %d\n", + srcinfo->bytealign); + + /* Determine physical size. */ + if ((srcinfo->angle % 2) == 0) { + srcinfo->physwidth = srcinfo->geom->width + - srcinfo->pixalign; + srcinfo->physheight = srcinfo->geom->height; + } else { + srcinfo->physwidth = srcinfo->geom->height + - srcinfo->pixalign; + srcinfo->physheight = srcinfo->geom->width; } - - /* Determine the destination rectangle. */ - if ((srcinfo->index == 1) && - ((bvbltparams->flags & BVFLAG_SRC2_AUXDSTRECT) != 0)) { - dstrect = &bvbltparams->src2auxdstrect; - dstrectclipped = &batch->dstclippedaux; + GCDBG(GCZONE_SRC, "source physical size = %dx%d\n", + srcinfo->physwidth, srcinfo->physheight); + + /* OPF does not support source rotation, which can be compensated by + * using destination rotation. Compute the adjustment angle. + * For simplicity use the same algorythm for both OPF and TPF. */ + adjangle = (4 - srcinfo->angle) % 4; + GCDBG(GCZONE_DEST, "adjangle = %d\n", adjangle); + + /* Compute destination rotation. */ + process_rotation(bvbltparams, batch, srcinfo, adjangle); + + /* Rotate the source rectangle to 0 degree. */ + srcrect = &srcinfo->rect; + rotate_gcrect(adjangle, + srcinfo->geom, &srcinfo->rect, + srcinfo->geom, &srcinfo->rect); + + /* Get destination rect shortcuts. */ + if ((srcinfo->index == 1) && batch->haveaux) { + dstrect = &gcfilter->dstrectaux; + dstclipped = &gcfilter->dstclippedaux; + dstadjusted = &gcfilter->dstadjustedaux; } else { - dstrect = &bvbltparams->dstrect; - dstrectclipped = &batch->dstclipped; + dstrect = &gcfilter->dstrect; + dstclipped = &gcfilter->dstclipped; + dstadjusted = &gcfilter->dstadjusted; } - /* Get a shortcut to the destination surface. */ - dstinfo = &batch->dstinfo; + /* Get source rect shortcut. */ + srcrect = &srcinfo->rect; + + /* Determine the source and destination rectangles. */ + srcwidth = srcrect->right - srcrect->left; + srcheight = srcrect->bottom - srcrect->top; + dstwidth = dstrect->right - dstrect->left; + dstheight = dstrect->bottom - dstrect->top; + + GCDBG(GCZONE_FILTER, "adjusted input src size: %dx%d\n", + srcwidth, srcheight); + GCDBG(GCZONE_FILTER, "adjusted input dst size: %dx%d\n", + dstwidth, dstheight); + + /* Determine the data path. */ + scalex = (srcwidth != dstwidth); + scaley = (srcheight != dstheight); + + twopass = scalex && scaley; + if (twopass) { + if (((gcfilter->horkernelsize == 3) || + (gcfilter->horkernelsize == 5)) && + ((gcfilter->verkernelsize == 3) || + (gcfilter->verkernelsize == 5))) { + singlepass = true; + twopass = false; + } else { + singlepass = false; + } + } else { + /* Two pass filter in one pass mode. */ + if (!scalex && !scaley) + GCERR("no scaling needed.\n"); - /* Compute the size of the source rectangle. */ - srcwidth = srcinfo->rect.right - srcinfo->rect.left; - srcheight = srcinfo->rect.bottom - srcinfo->rect.top; + GCDBG(GCZONE_FILTER, "only %s scaling needed.\n", + scalex ? "horizontal" : "vertical"); - /* Compute the scale factors. */ - batch->op.filter.horscalefactor = - horscalefactor = get_scale_factor(srcwidth, dstrect->width); + singlepass = false; + } - batch->op.filter.verscalefactor = - verscalefactor = get_scale_factor(srcheight, dstrect->height); + /* Compute the scale factors. */ + gcfilter->horscalefactor = + horscalefactor = get_scale_factor(srcwidth, dstwidth); + GCDBG(GCZONE_FILTER, "horscalefactor = 0x%08X\n", horscalefactor); - /* Compute adjusted destination rectangle. */ - dstadjusted.left = dstrectclipped->left + batch->dstoffsetX; - dstadjusted.top = dstrectclipped->top + batch->dstoffsetY; - dstadjusted.right = dstrectclipped->right + batch->dstoffsetX; - dstadjusted.bottom = dstrectclipped->bottom + batch->dstoffsetY; + gcfilter->verscalefactor = + verscalefactor = get_scale_factor(srcheight, dstheight); + GCDBG(GCZONE_FILTER, "verscalefactor = 0x%08X\n", verscalefactor); /* Compute the destination offsets. */ - dstleftoffs = dstrectclipped->left - dstrect->left; - dsttopoffs = dstrectclipped->top - dstrect->top; - dstrightoffs = dstrectclipped->right - dstrect->left; + dstleftoffs = dstclipped->left - dstrect->left; + dsttopoffs = dstclipped->top - dstrect->top; + dstrightoffs = dstclipped->right - dstrect->left; /* Compute the source offsets. */ - srcleftoffs = dstleftoffs * horscalefactor; - srctopoffs = dsttopoffs * verscalefactor; - srcrightoffs = (dstrightoffs - 1) * verscalefactor + (1 << 16); + srcleftoffs = dstleftoffs * horscalefactor; + srctopoffs = dsttopoffs * verscalefactor; + srcrightoffs = (dstrightoffs - 1) * horscalefactor + (1 << 16); + + GCDBG(GCZONE_FILTER, "offsets (dst, src):\n"); + GCDBG(GCZONE_FILTER, " left = %d, 0x%08X\n", + dstleftoffs, srcleftoffs); + GCDBG(GCZONE_FILTER, " top = %d, 0x%08X\n", + dsttopoffs, srctopoffs); + GCDBG(GCZONE_FILTER, " right = %d, 0x%08X\n", + dstrightoffs, srcrightoffs); /* Before rendering each destination pixel, the HW will select the * corresponding source center pixel to apply the kernel around. * To make this process precise we need to add 0.5 to source initial * coordinates here; this will make HW pick the next source pixel if * the fraction is equal or greater then 0.5. */ - srcleftoffs += 0x00008000; - srctopoffs += 0x00008000; + srcleftoffs += 0x00008000; + srctopoffs += 0x00008000; srcrightoffs += 0x00008000; - GCDBG(GCZONE_FILTER, "source rectangle:\n"); + GCDBG(GCZONE_FILTER, "source:\n"); GCDBG(GCZONE_FILTER, " stride = %d, geom = %dx%d\n", srcinfo->geom->virtstride, srcinfo->geom->width, srcinfo->geom->height); @@ -1034,15 +1509,11 @@ enum bverror do_filter(struct bvbltparams *bvbltparams, "(0x%08X,0x%08X)-(0x%08X,---)\n", srcleftoffs, srctopoffs, srcrightoffs); - GCDBG(GCZONE_FILTER, "destination rectangle:\n"); + GCDBG(GCZONE_FILTER, "destination:\n"); GCDBG(GCZONE_FILTER, " stride = %d, geom size = %dx%d\n", bvbltparams->dstgeom->virtstride, bvbltparams->dstgeom->width, bvbltparams->dstgeom->height); - GCDBG(GCZONE_FILTER, " rotaton = %d\n", - dstinfo->angle); - GCDBG(GCZONE_FILTER, " rect = (%d,%d)-(%d,%d)\n", - dstrectclipped->left, dstrectclipped->top, - dstrectclipped->right, dstrectclipped->bottom); + GCPRINT_RECT(GCZONE_FILTER, " rect", dstclipped); /* Map the source. */ bverror = do_map(srcinfo->buf.desc, batch, &srcmap); @@ -1058,18 +1529,13 @@ enum bverror do_filter(struct bvbltparams *bvbltparams, goto exit; } - /* Determine needed passes. */ - horpass = (srcwidth != dstrect->width); - verpass = (srcheight != dstrect->height); - /* Do single pass filter if we can. */ - if (((batch->op.filter.horkernelsize == 3) || - (batch->op.filter.horkernelsize == 5)) && - ((batch->op.filter.verkernelsize == 3) || - (batch->op.filter.verkernelsize == 5))) { + if (singlepass) { + GCDBG(GCZONE_TYPE, "single pass\n"); + /* Determine the kernel size to use. */ - kernelsize = max(batch->op.filter.horkernelsize, - batch->op.filter.verkernelsize); + kernelsize = max(gcfilter->horkernelsize, + gcfilter->verkernelsize); /* Set kernel size. */ bverror = claim_buffer(bvbltparams, batch, @@ -1085,23 +1551,26 @@ enum bverror do_filter(struct bvbltparams *bvbltparams, = GCREG_VR_CONFIG_EX_MASK_FILTER_TAP_ENABLED; /* Setup single pass. */ - srcx = (srcinfo->rect.left << 16) + srcleftoffs; - srcy = (srcinfo->rect.top << 16) + srctopoffs; + srcx = (srcrect->left << 16) + srcleftoffs; + srcy = (srcrect->top << 16) + srctopoffs; + GCDBG(GCZONE_SRC, "src origin: 0x%08X,0x%08X\n", srcx, srcy); /* Load the horizontal filter. */ - bverror = load_filter(bvbltparams, batch, GC_FILTER_SYNC, - batch->op.filter.horkernelsize, - batch->op.filter.horscalefactor, - srcwidth, dstrect->width, + bverror = load_filter(bvbltparams, batch, + GC_FILTER_SYNC, + gcfilter->horkernelsize, + gcfilter->horscalefactor, + srcwidth, dstwidth, gcmofilterkernel_horizontal_ldst); if (bverror != BVERR_NONE) goto exit; /* Load the vertical filter. */ - bverror = load_filter(bvbltparams, batch, GC_FILTER_SYNC, - batch->op.filter.verkernelsize, - batch->op.filter.verscalefactor, - srcheight, dstrect->height, + bverror = load_filter(bvbltparams, batch, + GC_FILTER_SYNC, + gcfilter->verkernelsize, + gcfilter->verscalefactor, + srcheight, dstheight, gcmofilterkernel_vertical_ldst); if (bverror != BVERR_NONE) goto exit; @@ -1109,19 +1578,20 @@ enum bverror do_filter(struct bvbltparams *bvbltparams, /* Start the operation. */ bverror = startvr(bvbltparams, batch, srcmap, dstmap, srcinfo, dstinfo, - srcx, srcy, &dstadjusted, - gcregvrconfig_onepass, false); - - GCDBG(GCZONE_TYPE, "single pass\n"); - } else if (horpass && verpass) { + srcx, srcy, dstadjusted, + ROT_ANGLE_0, gcfilter->dstangle, + GC_SCALE_OPF); + } else if (twopass) { unsigned int horkernelhalf; unsigned int leftextra, rightextra; unsigned int tmprectwidth, tmprectheight; - unsigned int tmpalignmask; + unsigned int tmpalignmask, dstalignmask; unsigned int tmpsize; struct surfaceinfo tmpinfo; struct bvsurfgeom tmpgeom; + GCDBG(GCZONE_TYPE, "two pass\n"); + /* Initialize the temporaty surface geometry. */ tmpgeom.structsize = sizeof(struct bvsurfgeom); tmpgeom.orientation = 0; @@ -1131,31 +1601,39 @@ enum bverror do_filter(struct bvbltparams *bvbltparams, /* Initialize the temporaty surface descriptor. */ tmpinfo.index = -1; tmpinfo.geom = &tmpgeom; - tmpinfo.pixalign = 0; - tmpinfo.bytealign = 0; - tmpinfo.angle = srcinfo->angle; - tmpinfo.mirror = srcinfo->mirror; - tmpinfo.rop = srcinfo->rop; + tmpinfo.angle = gcfilter->dstangle; + tmpinfo.mirror = GCREG_MIRROR_NONE; + tmpinfo.rop = 0; + GCDBG(GCZONE_FILTER, "tmp angle = %d\n", tmpinfo.angle); + + /* Transfer blending parameters from the source to the + * temporary buffer so that the blending would happen + * on the second pass. */ tmpinfo.gca = srcinfo->gca; + srcinfo->gca = NULL; /* Determine temporary surface format. */ if (srcinfo->format.type == BVFMT_YUV) { - tmpinfo.format = dstinfo->format; - tmpgeom.format = dstinfo->geom->format; + GCDBG(GCZONE_FILTER, "tmp format = 4:2:2\n"); + tmpgeom.format = OCDFMT_YUYV; + parse_format(bvbltparams, &tmpinfo); } else { - tmpinfo.format = srcinfo->format; + GCDBG(GCZONE_FILTER, "tmp format = src format\n"); tmpgeom.format = srcinfo->geom->format; + tmpinfo.format = srcinfo->format; } - /* Determine pixel alignment. */ + /* Determine pixel alignment masks. */ tmpalignmask = GC_BITS_PER_CACHELINE / tmpinfo.format.bitspp - 1; + dstalignmask = GC_BITS_PER_CACHELINE + / dstinfo->format.bitspp - 1; /* In partial filter blit cases, the vertical pass has to render * more pixel information to the left and to the right of the - * temporary image so that the horizontal pass has its necessary + * temporary image so that the next pass has its necessary * kernel information on the edges of the image. */ - horkernelhalf = batch->op.filter.horkernelsize >> 1; + horkernelhalf = gcfilter->horkernelsize >> 1; leftextra = srcleftoffs >> 16; rightextra = srcwidth - (srcrightoffs >> 16); @@ -1166,28 +1644,55 @@ enum bverror do_filter(struct bvbltparams *bvbltparams, if (rightextra > horkernelhalf) rightextra = horkernelhalf; + GCDBG(GCZONE_FILTER, "leftextra = %d, rightextra = %d\n", + leftextra, rightextra); + /* Determine the source origin. */ - srcx = ((srcinfo->rect.left - leftextra) << 16) + srcleftoffs; - srcy = (srcinfo->rect.top << 16) + srctopoffs; + srcx = ((srcrect->left - leftextra) << 16) + srcleftoffs; + srcy = (srcrect->top << 16) + srctopoffs; + GCDBG(GCZONE_SRC, "src origin: 0x%08X,0x%08X\n", srcx, srcy); /* Determine the size of the temporary image. */ tmprectwidth = leftextra + rightextra + ((srcrightoffs >> 16) - (srcleftoffs >> 16)); - tmprectheight = dstadjusted.bottom - dstadjusted.top; - - /* Determine the destination coordinates. */ - tmpinfo.rect.left = (srcx >> 16) & tmpalignmask; - tmpinfo.rect.top = dstadjusted.top; + tmprectheight = dstadjusted->bottom - dstadjusted->top; + GCDBG(GCZONE_FILTER, "tmp rect size: %dx%d\n", + tmprectwidth, tmprectheight); + + /* Determine the temporary destination coordinates. */ + tmpinfo.rect.left = ((tmpinfo.angle % 2) == 0) + ? (srcx >> 16) & tmpalignmask + : dstadjusted->left & dstalignmask; + tmpinfo.rect.top = 0; tmpinfo.rect.right = tmpinfo.rect.left + tmprectwidth; tmpinfo.rect.bottom = tmpinfo.rect.top + tmprectheight; + GCPRINT_RECT(GCZONE_DEST, "tmp dest", &tmpinfo.rect); - /* Determine the size of the temporaty surface. */ - tmpgeom.width = (tmpinfo.rect.right + tmpalignmask) - & ~tmpalignmask; + /* Determine the temporaty surface dimensions. */ + tmpgeom.width = tmpinfo.rect.right; tmpgeom.height = tmpinfo.rect.bottom; - tmpgeom.virtstride = (tmpgeom.width - * tmpinfo.format.bitspp) / 8; - tmpsize = tmpgeom.virtstride * tmpgeom.height; + GCDBG(GCZONE_FILTER, "tmp dims: %dx%d\n", + tmpgeom.width, tmpgeom.height); + + /* Determine the physical size of the surface. */ + if ((tmpinfo.angle % 2) == 0) { + tmpinfo.physwidth = tmpgeom.width; + tmpinfo.physheight = tmpgeom.height; + } else { + tmpinfo.physwidth = tmpgeom.height; + tmpinfo.physheight = tmpgeom.width; + } + tmpinfo.physwidth = (tmpinfo.physwidth + tmpalignmask) + & ~tmpalignmask; + GCDBG(GCZONE_FILTER, "tmp physical dims: %dx%d\n", + tmpinfo.physwidth, tmpinfo.physheight); + + /* Determine the size of the temporaty surface. */ + tmpgeom.virtstride = (tmpinfo.physwidth + * tmpinfo.format.bitspp) / 8; + tmpsize = tmpgeom.virtstride * tmpinfo.physheight; + GCDBG(GCZONE_FILTER, "tmp stride = %d\n", tmpgeom.virtstride); + GCDBG(GCZONE_FILTER, "tmp size (bytes) = %d\n", tmpsize); /* Allocate the temporary buffer. */ bverror = allocate_temp(bvbltparams, tmpsize); @@ -1202,86 +1707,138 @@ enum bverror do_filter(struct bvbltparams *bvbltparams, goto exit; } - /* Set the temporaty surface size. */ - tmpinfo.physwidth = tmpgeom.width; - tmpinfo.physheight = tmpgeom.height; + /* Compute the temp alignments needed to compensate + * for the surface base address misalignment if any. */ + tmpinfo.pixalign = get_pixel_offset(&tmpinfo, 0); + tmpinfo.bytealign = (tmpinfo.pixalign + * (int) tmpinfo.format.bitspp) / 8; + GCDBG(GCZONE_SRC, "tmp offset (pixels) = %d,0\n", + tmpinfo.pixalign); + GCDBG(GCZONE_SRC, "tmp offset (bytes) = %d\n", + tmpinfo.bytealign); + + /* Adjust physical size. */ + tmpinfo.physwidth -= tmpinfo.pixalign; + GCDBG(GCZONE_FILTER, "tmp adjusted physical dims: %dx%d\n", + tmpinfo.physwidth, tmpinfo.physheight); /* Load the vertical filter. */ - bverror = load_filter(bvbltparams, batch, GC_FILTER_SYNC, - batch->op.filter.verkernelsize, - batch->op.filter.verscalefactor, - srcheight, dstrect->height, + bverror = load_filter(bvbltparams, batch, + GC_FILTER_SYNC, + gcfilter->verkernelsize, + gcfilter->verscalefactor, + srcheight, dstheight, gcmofilterkernel_shared_ldst); if (bverror != BVERR_NONE) goto exit; /* Start the operation. */ + GCDBG(GCZONE_TYPE, "vertical pass\n"); bverror = startvr(bvbltparams, batch, srcmap, tmpmap, srcinfo, &tmpinfo, srcx, srcy, &tmpinfo.rect, - gcregvrconfig_vertical, true); + ROT_ANGLE_0, tmpinfo.angle, + GC_SCALE_VER); if (bverror != BVERR_NONE) goto exit; + /* Fake no rotation. */ + adjangle = (4 - tmpinfo.angle) % 4; + GCDBG(GCZONE_DEST, "adjangle = %d\n", adjangle); + + /* Rotate the source rectangle to 0 degree. */ + rotate_gcrect(adjangle, + tmpinfo.geom, &tmpinfo.rect, + tmpinfo.geom, &tmpinfo.rect); + GCPRINT_RECT(GCZONE_DEST, "tmp src", &tmpinfo.rect); + + /* Rotate the destination rectangle to 0 degree. */ + rotate_gcrect(adjangle, + &gcfilter->dstgeom, dstclipped, + &dstrotated0geom, &dstrotated0); + GCPRINT_RECT(GCZONE_DEST, "dest", &dstrotated0); + + /* Apply adjustment. */ + dstrotated0.left -= dstinfo->pixalign; + dstrotated0.right -= dstinfo->pixalign; + /* Determine the source origin. */ srcx = ((leftextra + tmpinfo.rect.left) << 16) - + (srcleftoffs & 0xFFFF); + + (srcleftoffs & 0xFFFF); srcy = (tmpinfo.rect.top << 16) - + (srctopoffs & 0xFFFF); + + (srctopoffs & 0xFFFF); + GCDBG(GCZONE_SRC, "src origin: 0x%08X,0x%08X\n", + srcx, srcy); /* Load the horizontal filter. */ - bverror = load_filter(bvbltparams, batch, GC_FILTER_SYNC, - batch->op.filter.horkernelsize, - batch->op.filter.horscalefactor, - srcwidth, dstrect->width, + bverror = load_filter(bvbltparams, batch, + GC_FILTER_SYNC, + gcfilter->horkernelsize, + gcfilter->horscalefactor, + srcwidth, dstwidth, gcmofilterkernel_shared_ldst); if (bverror != BVERR_NONE) goto exit; /* Start the operation. */ + GCDBG(GCZONE_TYPE, "horizontal pass\n"); bverror = startvr(bvbltparams, batch, tmpmap, dstmap, &tmpinfo, dstinfo, - srcx, srcy, &dstadjusted, - gcregvrconfig_horizontal, false); + srcx, srcy, &dstrotated0, + ROT_ANGLE_0, ROT_ANGLE_0, + ((gcfilter->dstangle % 2) == 0) + ? GC_SCALE_HOR + : GC_SCALE_HOR_FLIPPED); if (bverror != BVERR_NONE) goto exit; - - GCDBG(GCZONE_TYPE, "two pass\n"); } else { + GCDBG(GCZONE_TYPE, "two pass (%s pass config).\n", + scalex ? "horizontal" : "vertical"); + /* Setup single pass. */ - srcx = (srcinfo->rect.left << 16) + srcleftoffs; - srcy = (srcinfo->rect.top << 16) + srctopoffs; + srcx = (srcrect->left << 16) + srcleftoffs; + srcy = (srcrect->top << 16) + srctopoffs; + GCDBG(GCZONE_SRC, "src origin: 0x%08X,0x%08X\n", srcx, srcy); - if (verpass) - /* Load the vertical filter. */ + if (scalex) { + /* Load the horizontal filter. */ bverror = load_filter(bvbltparams, batch, GC_FILTER_SYNC, - batch->op.filter.verkernelsize, - batch->op.filter.verscalefactor, - srcheight, dstrect->height, + gcfilter->horkernelsize, + gcfilter->horscalefactor, + srcwidth, dstwidth, gcmofilterkernel_shared_ldst); - else - /* Load the horizontal filter. */ + if (bverror != BVERR_NONE) + goto exit; + + /* Start the operation. */ + bverror = startvr(bvbltparams, batch, + srcmap, dstmap, srcinfo, dstinfo, + srcx, srcy, dstadjusted, + ROT_ANGLE_0, gcfilter->dstangle, + GC_SCALE_HOR); + if (bverror != BVERR_NONE) + goto exit; + } else { + /* Load the vertical filter. */ bverror = load_filter(bvbltparams, batch, GC_FILTER_SYNC, - batch->op.filter.horkernelsize, - batch->op.filter.horscalefactor, - srcwidth, dstrect->width, + gcfilter->verkernelsize, + gcfilter->verscalefactor, + srcheight, dstheight, gcmofilterkernel_shared_ldst); + if (bverror != BVERR_NONE) + goto exit; - if (bverror != BVERR_NONE) - goto exit; - - /* Start the operation. */ - bverror = startvr(bvbltparams, batch, - srcmap, dstmap, srcinfo, dstinfo, - srcx, srcy, &dstadjusted, - verpass - ? gcregvrconfig_vertical - : gcregvrconfig_horizontal, - false); - - GCDBG(GCZONE_TYPE, "two pass one pass config.\n"); + /* Start the operation. */ + bverror = startvr(bvbltparams, batch, + srcmap, dstmap, srcinfo, dstinfo, + srcx, srcy, dstadjusted, + ROT_ANGLE_0, gcfilter->dstangle, + GC_SCALE_VER); + if (bverror != BVERR_NONE) + goto exit; + } } exit: diff --git a/drivers/misc/gcx/gcbv/gcparser.c b/drivers/misc/gcx/gcbv/gcparser.c index 4b47eb8..609c862 100644 --- a/drivers/misc/gcx/gcbv/gcparser.c +++ b/drivers/misc/gcx/gcbv/gcparser.c @@ -1442,8 +1442,7 @@ enum bverror parse_destination(struct bvbltparams *bvbltparams, struct surfaceinfo *dstinfo; struct gcrect cliprect; struct gcrect *dstrect; - struct gcrect dstrectaux; - bool haveaux; + struct gcrect *dstrectaux; /* Get a shortcut to the destination surface. */ dstinfo = &batch->dstinfo; @@ -1456,8 +1455,9 @@ enum bverror parse_destination(struct bvbltparams *bvbltparams, dstrect); /* Determine whether aux destination is specified. */ - haveaux = ((bvbltparams->flags & BVFLAG_SRC2_AUXDSTRECT) != 0); - GCDBG(GCZONE_DEST, "aux dest = %d\n", haveaux); + batch->haveaux + = ((bvbltparams->flags & BVFLAG_SRC2_AUXDSTRECT) != 0); + GCDBG(GCZONE_DEST, "aux dest = %d\n", batch->haveaux); /* Is clipping rectangle specified? */ if ((bvbltparams->flags & BVFLAG_CLIP) == BVFLAG_CLIP) { @@ -1515,37 +1515,38 @@ enum bverror parse_destination(struct bvbltparams *bvbltparams, } /* Clip the aux destination. */ - if (haveaux) { - /* Convert and validate aux rectangle. */ + if (batch->haveaux) { + /* Convert the aux rectangle. */ + dstrectaux = &batch->dstrectaux; GCCONVERT_RECT(GCZONE_DEST, "aux destination", &bvbltparams->src2auxdstrect, - &dstrectaux); + dstrectaux); - if (cliprect.left <= dstrectaux.left) + if (cliprect.left <= dstrectaux->left) batch->dstclippedaux.left - = dstrectaux.left; + = dstrectaux->left; else batch->dstclippedaux.left = cliprect.left; - if (cliprect.top <= dstrectaux.top) + if (cliprect.top <= dstrectaux->top) batch->dstclippedaux.top - = dstrectaux.top; + = dstrectaux->top; else batch->dstclippedaux.top = cliprect.top; - if (cliprect.right >= dstrectaux.right) + if (cliprect.right >= dstrectaux->right) batch->dstclippedaux.right - = dstrectaux.right; + = dstrectaux->right; else batch->dstclippedaux.right = cliprect.right; - if (cliprect.bottom >= dstrectaux.bottom) + if (cliprect.bottom >= dstrectaux->bottom) batch->dstclippedaux.bottom - = dstrectaux.bottom; + = dstrectaux->bottom; else batch->dstclippedaux.bottom = cliprect.bottom; @@ -1557,8 +1558,8 @@ enum bverror parse_destination(struct bvbltparams *bvbltparams, batch->clipdelta.bottom = 0; batch->dstclipped = *dstrect; - if (haveaux) - /* Convert and validate aux rectangle. */ + if (batch->haveaux) + /* Convert the aux rectangle. */ GCCONVERT_RECT(GCZONE_DEST, "aux destination", &bvbltparams->src2auxdstrect, @@ -1576,7 +1577,7 @@ enum bverror parse_destination(struct bvbltparams *bvbltparams, goto exit; } - if (haveaux) { + if (batch->haveaux) { GCPRINT_RECT(GCZONE_DEST, "clipped aux dest", &batch->dstclippedaux); |