diff options
Diffstat (limited to 'bltsville/gcbv/mirror/gcblit.c')
-rw-r--r-- | bltsville/gcbv/mirror/gcblit.c | 771 |
1 files changed, 771 insertions, 0 deletions
diff --git a/bltsville/gcbv/mirror/gcblit.c b/bltsville/gcbv/mirror/gcblit.c new file mode 100644 index 0000000..5dae273 --- /dev/null +++ b/bltsville/gcbv/mirror/gcblit.c @@ -0,0 +1,771 @@ +/* + * 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_BLEND (1 << 0) +#define GCZONE_SURF (1 << 1) +#define GCZONE_BLIT (1 << 3) + +GCDBG_FILTERDEF(blit, GCZONE_NONE, + "blend", + "surf", + "blit") + + +static enum bverror do_blit_end(struct bvbltparams *bvbltparams, + struct gcbatch *batch) +{ + enum bverror bverror; + struct gcblit *gcblit; + struct gcmobltconfig *gcmobltconfig; + struct gcmostartde *gcmostartde; + + GCENTER(GCZONE_BLIT); + + /* Get a shortcut to the operation specific data. */ + gcblit = &batch->op.blit; + + GCDBG(GCZONE_BLIT, "finalizing the blit, scrcount = %d\n", + gcblit->srccount); + + /*********************************************************************** + * Configure the operation. + */ + + /* Allocate command buffer. */ + bverror = claim_buffer(bvbltparams, batch, + sizeof(struct gcmobltconfig), + (void **) &gcmobltconfig); + if (bverror != BVERR_NONE) + goto exit; + + /* Configure multi-source control. */ + gcmobltconfig->multisource_ldst = gcmobltconfig_multisource_ldst; + gcmobltconfig->multisource.raw = 0; + gcmobltconfig->multisource.reg.srccount = gcblit->srccount - 1; + + GCDBG(GCZONE_BLIT, "blockenable = %d\n", gcblit->blockenable); + if (gcblit->blockenable) { + gcmobltconfig->multisource.reg.horblock + = GCREG_DE_MULTI_SOURCE_HORIZONTAL_BLOCK_PIXEL16; + gcmobltconfig->multisource.reg.verblock + = GCREG_DE_MULTI_SOURCE_VERTICAL_BLOCK_LINE64; + } else { + gcmobltconfig->multisource.reg.horblock + = GCREG_DE_MULTI_SOURCE_HORIZONTAL_BLOCK_PIXEL128; + gcmobltconfig->multisource.reg.verblock + = GCREG_DE_MULTI_SOURCE_VERTICAL_BLOCK_LINE1; + } + + /* Set destination configuration. */ + GCDBG(GCZONE_BLIT, " swizzle code = %d\n", gcblit->swizzle); + GCDBG(GCZONE_BLIT, " format code = %d\n", gcblit->format); + + gcmobltconfig->dstconfig_ldst = gcmobltconfig_dstconfig_ldst; + gcmobltconfig->dstconfig.raw = 0; + gcmobltconfig->dstconfig.reg.swizzle = gcblit->swizzle; + gcmobltconfig->dstconfig.reg.format = gcblit->format; + gcmobltconfig->dstconfig.reg.command = gcblit->multisrc + ? GCREG_DEST_CONFIG_COMMAND_MULTI_SOURCE_BLT + : GCREG_DEST_CONFIG_COMMAND_BIT_BLT; + + /*********************************************************************** + * Start the operation. + */ + + /* Allocate command buffer. */ + bverror = claim_buffer(bvbltparams, batch, + sizeof(struct gcmostartde), + (void **) &gcmostartde); + if (bverror != BVERR_NONE) + goto exit; + + /* Set START_DE command. */ + gcmostartde->startde.cmd.fld = gcfldstartde; + + /* Set destination rectangle. */ + gcmostartde->rect.left = gcblit->dstrect.left; + gcmostartde->rect.top = gcblit->dstrect.top; + gcmostartde->rect.right = gcblit->dstrect.right; + gcmostartde->rect.bottom = gcblit->dstrect.bottom; + + GCDBG(GCZONE_BLIT, "dstrect = (%d,%d)-(%d,%d)\n", + gcmostartde->rect.left, gcmostartde->rect.top, + gcmostartde->rect.right, gcmostartde->rect.bottom); + + /* Reset the finalizer. */ + batch->batchend = do_end; + + gc_debug_blt(gcblit->srccount, + abs(gcblit->dstrect.right - gcblit->dstrect.left), + abs(gcblit->dstrect.bottom - gcblit->dstrect.top)); + +exit: + GCEXITARG(GCZONE_BLIT, "bv%s = %d\n", + (bverror == BVERR_NONE) ? "result" : "error", bverror); + return bverror; +} + +enum bverror do_blit(struct bvbltparams *bvbltparams, + struct gcbatch *batch, + struct surfaceinfo *srcinfo) +{ + enum bverror bverror = BVERR_NONE; + struct gccontext *gccontext = get_context(); + + struct gcmosrc0 *gcmosrc0; + struct gcmosrc *gcmosrc; + struct gcblit *gcblit; + + unsigned int index; + struct bvbuffmap *dstmap = NULL; + struct bvbuffmap *srcmap = NULL; + + struct surfaceinfo *dstinfo; + int dstshiftX, dstshiftY; + int dstpixalign, dstbyteshift; + int dstoffsetX, dstoffsetY; + + int srcshiftX, srcshiftY, srctopedge; + struct gcrect srcclipped; + int srcsurfwidth, srcsurfheight; + unsigned int physwidth, physheight; + int orthogonal; + int multisrc; + + GCENTER(GCZONE_BLIT); + + /* 3-plane source not supported. */ + if ((srcinfo->format.type == BVFMT_YUV) && + (srcinfo->format.cs.yuv.planecount == 3)) { + BVSETBLTERROR((srcinfo->index == 0) + ? BVERR_SRC1GEOM_FORMAT + : BVERR_SRC2GEOM_FORMAT, + "unsupported source%d format.", + srcinfo->index + 1); + goto exit; + } + + /* Get a shortcut to the destination surface. */ + dstinfo = &batch->dstinfo; + + /* Parse destination parameters. */ + bverror = parse_destination(bvbltparams, batch); + if (bverror != BVERR_NONE) + goto exit; + + /* Setup rotation. */ + process_dest_rotation(bvbltparams, batch); + + + /*********************************************************************** + * Determine source surface alignment offset. + */ + + /* Determine whether the source and the destination are orthogonal + * to each other. */ + orthogonal = (srcinfo->angle % 2) != (dstinfo->angle % 2); + + /* Compute clipped source rectangle. */ + srcclipped.left = srcinfo->rect.left + batch->clipdelta.left; + srcclipped.top = srcinfo->rect.top + batch->clipdelta.top; + srcclipped.right = srcinfo->rect.right + batch->clipdelta.right; + srcclipped.bottom = srcinfo->rect.bottom + batch->clipdelta.bottom; + GCPRINT_RECT(GCZONE_SURF, "clipped source", &srcclipped); + + /* Validate the source rectangle. */ + if (!valid_rect(srcinfo->geom, &srcclipped)) { + BVSETBLTERROR((srcinfo->index == 0) + ? BVERR_SRC1RECT + : BVERR_SRC2RECT, + "invalid source rectangle."); + goto exit; + } + + /* Compute the source surface shift. */ + switch (srcinfo->angle) { + case ROT_ANGLE_0: + srctopedge = srcclipped.top; + srcshiftX = srcclipped.left - batch->dstadjusted.left; + srcshiftY = srctopedge - batch->dstadjusted.top; + break; + + case ROT_ANGLE_90: + srctopedge = srcinfo->geom->width - srcclipped.left; + srcshiftX = srcclipped.top - batch->dstadjusted.top; + srcshiftY = srctopedge + - (batch->dstwidth - batch->dstadjusted.left); + srctopedge += 1; + break; + + case ROT_ANGLE_180: + srctopedge = srcinfo->geom->height - srcclipped.top; + srcshiftX = (srcinfo->geom->width - srcclipped.left) + - (batch->dstwidth - batch->dstadjusted.left); + srcshiftY = srctopedge + - (batch->dstheight - batch->dstadjusted.top); + srctopedge += 1; + break; + + case ROT_ANGLE_270: + srctopedge = srcclipped.left; + srcshiftX = (srcinfo->geom->height - srcclipped.top) + - (batch->dstheight - batch->dstadjusted.top); + srcshiftY = srctopedge - batch->dstadjusted.left; + break; + + default: + srctopedge = 0; + srcshiftX = 0; + srcshiftY = 0; + } + + /* We cannot be in the middle of a sample, currently only YUV formats + * can have subsamples. Adjust vertical position as necessary. + * Horizontal position will be adjusted based on the byte offset and + * base address alignment requirement. This assumes that if we are + * aligned on the base address, then we are also aligned at the + * beginning of a sample. */ + if (srcinfo->format.type == BVFMT_YUV) { + int mody = (srctopedge + srcshiftY) + % srcinfo->format.cs.yuv.ysample; + + if (mody < 0) + mody = srcinfo->format.cs.yuv.ysample + mody; + + srcshiftY -= mody; + srcinfo->ypixalign = -mody; + } else { + srcinfo->ypixalign = 0; + } + + /* Compute the source surface offset in bytes. */ + srcinfo->bytealign = srcshiftY * (int) srcinfo->geom->virtstride + + srcshiftX * (int) srcinfo->format.bitspp / 8; + + /* Compute the source offset in pixels needed to compensate + * for the surface base address misalignment if any. */ + srcinfo->xpixalign = get_pixel_offset(srcinfo, srcinfo->bytealign); + + GCDBG(GCZONE_SURF, "source surface %d:\n", srcinfo->index + 1); + GCDBG(GCZONE_SURF, " surface offset (pixels) = %d,%d\n", + srcshiftX, srcshiftY); + GCDBG(GCZONE_SURF, " surface offset (bytes) = 0x%08X\n", + srcinfo->bytealign); + GCDBG(GCZONE_SURF, " srcpixalign = %d,%d\n", + srcinfo->xpixalign, srcinfo->ypixalign); + + /* Apply the source alignment. */ + srcinfo->bytealign += srcinfo->xpixalign + * (int) srcinfo->format.bitspp / 8; + srcshiftX += srcinfo->xpixalign; + + /* NOTE: at this point the source is ready to be presented, + * srcinfo->xpixalign and srcinfo->ypixalign represent additional + * adjustments for the DESTINATION. */ + + GCDBG(GCZONE_SURF, " adjusted surface offset (pixels) = %d,%d\n", + srcshiftX, srcshiftY); + GCDBG(GCZONE_SURF, " adjusted surface offset (bytes) = 0x%08X\n", + srcinfo->bytealign); + + /* Compute U/V plane offsets. */ + if ((srcinfo->format.type == BVFMT_YUV) && + (srcinfo->format.cs.yuv.planecount > 1)) + set_computeyuv(srcinfo, srcshiftX, srcshiftY); + + /* Set precomputed destination adjustments based on the destination + * base address misalignment only. */ + dstshiftX = dstinfo->xpixalign; + dstshiftY = dstinfo->ypixalign; + + /* Apply source adjustemnts. */ + if (srcinfo->angle == dstinfo->angle) { + dstshiftX += srcinfo->xpixalign; + dstshiftY += srcinfo->ypixalign; + } else if (((srcinfo->angle + 3) % 4) == dstinfo->angle) { + dstshiftY += srcinfo->xpixalign; + } else if (((srcinfo->angle + 1) % 4) == dstinfo->angle) { + dstshiftX += srcinfo->ypixalign; + } + + /* Compute the destination surface offset in bytes. */ + dstbyteshift = dstshiftY * (int) dstinfo->geom->virtstride + + dstshiftX * (int) dstinfo->format.bitspp / 8; + + /* Compute the destination offset in pixels needed to compensate + * for the surface base address misalignment if any. If dstpixalign + * comes out anything other than zero, multisource blit cannot be + * performed. */ + dstpixalign = get_pixel_offset(dstinfo, dstbyteshift); + + GCDBG(GCZONE_SURF, "destination surface:\n"); + GCDBG(GCZONE_SURF, " surface offset (pixels) = %d,%d\n", + dstshiftX, dstshiftY); + GCDBG(GCZONE_SURF, " surface offset (bytes) = 0x%08X\n", + dstbyteshift); + GCDBG(GCZONE_SURF, " realignment = %d\n", + dstpixalign); + + if ((dstpixalign != 0) || + ((srcinfo->xpixalign != 0) && (srcinfo->angle == dstinfo->angle))) { + /* Adjust the destination to match the source geometry. */ + switch (srcinfo->angle) { + case ROT_ANGLE_0: + /* Adjust coordinates. */ + srcclipped.left -= srcshiftX; + srcclipped.top -= srcshiftY; + + /* Determine source size. */ + srcsurfwidth = srcinfo->geom->width + - srcinfo->xpixalign; + srcsurfheight = srcinfo->geom->height; + break; + + case ROT_ANGLE_90: + /* Adjust top coordinate. */ + srcclipped.top -= srcshiftX; + + /* Determine source size. */ + srcsurfwidth = srcinfo->geom->height + - srcinfo->xpixalign; + srcsurfheight = srcinfo->geom->width; + break; + + case ROT_ANGLE_180: + /* Determine source size. */ + srcsurfwidth = srcinfo->geom->width + - srcinfo->xpixalign; + srcsurfheight = srcinfo->geom->height; + break; + + case ROT_ANGLE_270: + /* Adjust coordinates. */ + srcclipped.left -= srcshiftY; + + /* Determine source size. */ + srcsurfwidth = srcinfo->geom->height + - srcinfo->xpixalign; + srcsurfheight = srcinfo->geom->width; + break; + + default: + srcsurfwidth = 0; + srcsurfheight = 0; + } + + GCDBG(GCZONE_SURF, "srcrect origin = %d,%d\n", + srcclipped.left, srcclipped.top); + GCDBG(GCZONE_SURF, "source physical size = %dx%d\n", + srcsurfwidth, srcsurfheight); + + /* Overwrite destination byte offset. */ + dstbyteshift = dstinfo->bytealign; + + /* No adjustment necessary for single-source. */ + dstoffsetX = 0; + dstoffsetY = 0; + + /* Set the physical destination size. */ + physwidth = dstinfo->physwidth; + physheight = dstinfo->physheight; + + /* Disable multi source for the cases where the destination + * and the source address alignments do not match. */ + multisrc = 0; + GCDBG(GCZONE_SURF, "multi-source disabled.\n"); + } else { + /* Source origin is not used in multi-source setup. */ + srcclipped.left = 0; + srcclipped.top = 0; + + /* Adjust the destination to match the source geometry. */ + switch (srcinfo->angle) { + case ROT_ANGLE_0: + /* Adjust the destination horizontally. */ + dstoffsetX = srcinfo->xpixalign; + dstoffsetY = srcinfo->ypixalign; + + /* Apply the source alignment. */ + if ((dstinfo->angle % 2) == 0) { + physwidth = dstinfo->physwidth + - srcinfo->xpixalign; + physheight = dstinfo->physheight + - srcinfo->ypixalign; + } else { + physwidth = dstinfo->physwidth + - srcinfo->ypixalign; + physheight = dstinfo->physheight + - srcinfo->xpixalign; + } + break; + + case ROT_ANGLE_90: + /* Adjust the destination vertically. */ + dstoffsetX = srcinfo->ypixalign; + dstoffsetY = srcinfo->xpixalign; + + /* Apply the source alignment. */ + if ((dstinfo->angle % 2) == 0) { + physwidth = dstinfo->physwidth + - srcinfo->ypixalign; + physheight = dstinfo->physheight + - srcinfo->xpixalign; + } else { + physwidth = dstinfo->physwidth + - srcinfo->xpixalign; + physheight = dstinfo->physheight + - srcinfo->ypixalign; + } + break; + + case ROT_ANGLE_180: + /* No adjustment necessary. */ + dstoffsetX = 0; + dstoffsetY = 0; + + /* Apply the source alignment. */ + if ((dstinfo->angle % 2) == 0) { + physwidth = dstinfo->physwidth + - srcinfo->xpixalign; + physheight = dstinfo->physheight + - srcinfo->ypixalign; + } else { + physwidth = dstinfo->physwidth + - srcinfo->ypixalign; + physheight = dstinfo->physheight + - srcinfo->xpixalign; + } + break; + + case ROT_ANGLE_270: + /* No adjustment necessary. */ + dstoffsetX = 0; + dstoffsetY = 0; + + /* Apply the source alignment. */ + if ((dstinfo->angle % 2) == 0) { + physwidth = dstinfo->physwidth + - srcinfo->ypixalign; + physheight = dstinfo->physheight + - srcinfo->xpixalign; + } else { + physwidth = dstinfo->physwidth + - srcinfo->xpixalign; + physheight = dstinfo->physheight + - srcinfo->ypixalign; + } + break; + + default: + physwidth = 0; + physheight = 0; + dstoffsetX = 0; + dstoffsetY = 0; + } + + /* Source geometry is now the same as the destination. */ + if (orthogonal) { + srcsurfwidth = physheight; + srcsurfheight = physwidth; + } else { + srcsurfwidth = physwidth; + srcsurfheight = physheight; + } + + /* Enable multi-source. */ + multisrc = 1; + GCDBG(GCZONE_SURF, "multi-source enabled.\n"); + } + + /* Misaligned source may cause the destination parameters + * to change, verify whether this has happened. */ + if ((batch->dstbyteshift != dstbyteshift) || + (batch->dstphyswidth != physwidth) || + (batch->dstphysheight != physheight) || + (batch->dstoffsetX != dstoffsetX) || + (batch->dstoffsetY != dstoffsetY)) { + /* Set new values. */ + batch->dstbyteshift = dstbyteshift; + batch->dstphyswidth = physwidth; + batch->dstphysheight = physheight; + batch->dstoffsetX = dstoffsetX; + batch->dstoffsetY = dstoffsetY; + + /* Now we need to end the current batch and program + * the hardware with the new destination. */ + batch->batchflags |= BVBATCH_DST; + } + + /* Check if we need to finalize existing batch. */ + if ((batch->batchend != do_blit_end) || + (batch->op.blit.srccount == 4) || + (batch->op.blit.multisrc == 0) || + (multisrc == 0) || + ((batch->batchflags & (BVBATCH_DST | + BVBATCH_CLIPRECT | + BVBATCH_DESTRECT)) != 0)) { + /* Finalize existing batch if any. */ + bverror = batch->batchend(bvbltparams, batch); + if (bverror != BVERR_NONE) + goto exit; + + /* Blit batch. */ + batch->batchend = do_blit_end; + + /* Initialize the new batch. */ + gcblit = &batch->op.blit; + gcblit->blockenable = 0; + gcblit->srccount = 0; + gcblit->multisrc = multisrc; + + /* Set the destination format. */ + gcblit->format = dstinfo->format.format; + gcblit->swizzle = dstinfo->format.swizzle; + + /* Set the destination coordinates. */ + gcblit->dstrect.left = batch->dstadjusted.left - dstoffsetX; + gcblit->dstrect.top = batch->dstadjusted.top - dstoffsetY; + gcblit->dstrect.right = batch->dstadjusted.right - dstoffsetX; + gcblit->dstrect.bottom = batch->dstadjusted.bottom - dstoffsetY; + + /* Map the destination. */ + bverror = do_map(dstinfo->buf.desc, batch, &dstmap); + if (bverror != BVERR_NONE) { + bvbltparams->errdesc = gccontext->bverrorstr; + goto exit; + } + + /* Set the new destination. */ + bverror = set_dst(bvbltparams, batch, dstmap); + if (bverror != BVERR_NONE) + goto exit; + + /* Reset the modified flag. */ + batch->batchflags &= ~(BVBATCH_DST | + BVBATCH_CLIPRECT | + BVBATCH_DESTRECT); + } + + /* Map the source. */ + bverror = do_map(srcinfo->buf.desc, batch, &srcmap); + if (bverror != BVERR_NONE) { + bvbltparams->errdesc = gccontext->bverrorstr; + goto exit; + } + + /*********************************************************************** + ** Configure source. + */ + + /* We need to walk in blocks if the source and the destination + * surfaces are orthogonal to each other. */ + batch->op.blit.blockenable |= orthogonal; + + /* Shortcut to the register index. */ + index = batch->op.blit.srccount; + + /* Set surface parameters. */ + if (index == 0) { + /* Allocate command buffer. */ + bverror = claim_buffer(bvbltparams, batch, + sizeof(struct gcmosrc0), + (void **) &gcmosrc0); + if (bverror != BVERR_NONE) + goto exit; + + add_fixup(bvbltparams, batch, &gcmosrc0->address, + srcinfo->bytealign); + + gcmosrc0->config_ldst = gcmosrc0_config_ldst; + gcmosrc0->address = GET_MAP_HANDLE(srcmap); + gcmosrc0->stride = srcinfo->geom->virtstride; + gcmosrc0->rotation.raw = 0; + gcmosrc0->rotation.reg.surf_width = srcsurfwidth; + gcmosrc0->config.raw = 0; + gcmosrc0->config.reg.swizzle = srcinfo->format.swizzle; + gcmosrc0->config.reg.format = srcinfo->format.format; + gcmosrc0->origin.reg.x = srcclipped.left; + gcmosrc0->origin.reg.y = srcclipped.top; + gcmosrc0->size.reg = gcregsrcsize_max; + + gcmosrc0->rotation_ldst = gcmosrc0_rotation_ldst; + gcmosrc0->rotationheight.reg.height = srcsurfheight; + gcmosrc0->rotationangle.raw = 0; + gcmosrc0->rotationangle.reg.src = rotencoding[srcinfo->angle]; + gcmosrc0->rotationangle.reg.dst = rotencoding[dstinfo->angle]; + gcmosrc0->rotationangle.reg.src_mirror = srcinfo->mirror; + gcmosrc0->rotationangle.reg.dst_mirror = GCREG_MIRROR_NONE; + + gcmosrc0->rop_ldst = gcmosrc0_rop_ldst; + gcmosrc0->rop.raw = 0; + gcmosrc0->rop.reg.type = GCREG_ROP_TYPE_ROP3; + gcmosrc0->rop.reg.fg = (unsigned char) srcinfo->rop; + + gcmosrc0->mult_ldst = gcmosrc0_mult_ldst; + gcmosrc0->mult.raw = 0; + gcmosrc0->mult.reg.srcglobalpremul + = GCREG_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY_DISABLE; + + if (srcinfo->format.premultiplied) + gcmosrc0->mult.reg.srcpremul + = GCREG_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY_DISABLE; + else + gcmosrc0->mult.reg.srcpremul + = GCREG_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY_ENABLE; + + if (dstinfo->format.premultiplied) { + gcmosrc0->mult.reg.dstpremul + = GCREG_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY_DISABLE; + + gcmosrc0->mult.reg.dstdemul + = GCREG_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY_DISABLE; + } else { + gcmosrc0->mult.reg.dstpremul + = GCREG_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY_ENABLE; + + gcmosrc0->mult.reg.dstdemul + = GCREG_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY_ENABLE; + } + + /* Program blending. */ + bverror = set_blending(bvbltparams, batch, srcinfo); + if (bverror != BVERR_NONE) + goto exit; + + /* Program YUV source. */ + if (srcinfo->format.type == BVFMT_YUV) { + bverror = set_yuvsrc(bvbltparams, batch, + srcinfo, srcmap); + if (bverror != BVERR_NONE) + goto exit; + } + } else { + /* Allocate command buffer. */ + bverror = claim_buffer(bvbltparams, batch, + sizeof(struct gcmosrc), + (void **) &gcmosrc); + if (bverror != BVERR_NONE) + goto exit; + + add_fixup(bvbltparams, batch, &gcmosrc->address, + srcinfo->bytealign); + + gcmosrc->address_ldst = gcmosrc_address_ldst[index]; + gcmosrc->address = GET_MAP_HANDLE(srcmap); + gcmosrc->stride_ldst = gcmosrc_stride_ldst[index]; + gcmosrc->stride = srcinfo->geom->virtstride; + + gcmosrc->rotation_ldst = gcmosrc_rotation_ldst[index]; + gcmosrc->rotation.raw = 0; + gcmosrc->rotation.reg.surf_width = srcsurfwidth; + + gcmosrc->config_ldst = gcmosrc_config_ldst[index]; + gcmosrc->config.raw = 0; + gcmosrc->config.reg.swizzle = srcinfo->format.swizzle; + gcmosrc->config.reg.format = srcinfo->format.format; + + gcmosrc->origin_ldst = gcmosrc_origin_ldst[index]; + gcmosrc->origin.reg.x = srcclipped.left; + gcmosrc->origin.reg.y = srcclipped.top; + + gcmosrc->size_ldst = gcmosrc_size_ldst[index]; + gcmosrc->size.reg = gcregsrcsize_max; + + gcmosrc->rotationheight_ldst + = gcmosrc_rotationheight_ldst[index]; + gcmosrc->rotationheight.reg.height = srcsurfheight; + + gcmosrc->rotationangle_ldst + = gcmosrc_rotationangle_ldst[index]; + gcmosrc->rotationangle.raw = 0; + gcmosrc->rotationangle.reg.src = rotencoding[srcinfo->angle]; + gcmosrc->rotationangle.reg.dst = rotencoding[dstinfo->angle]; + gcmosrc->rotationangle.reg.src_mirror = srcinfo->mirror; + gcmosrc->rotationangle.reg.dst_mirror = GCREG_MIRROR_NONE; + + gcmosrc->rop_ldst = gcmosrc_rop_ldst[index]; + gcmosrc->rop.raw = 0; + gcmosrc->rop.reg.type = GCREG_ROP_TYPE_ROP3; + gcmosrc->rop.reg.fg = (unsigned char) srcinfo->rop; + + gcmosrc->mult_ldst = gcmosrc_mult_ldst[index]; + gcmosrc->mult.raw = 0; + gcmosrc->mult.reg.srcglobalpremul + = GCREG_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY_DISABLE; + + if (srcinfo->format.premultiplied) + gcmosrc->mult.reg.srcpremul + = GCREG_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY_DISABLE; + else + gcmosrc->mult.reg.srcpremul + = GCREG_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY_ENABLE; + + if (dstinfo->format.premultiplied) { + gcmosrc->mult.reg.dstpremul + = GCREG_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY_DISABLE; + + gcmosrc->mult.reg.dstdemul + = GCREG_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY_DISABLE; + } else { + gcmosrc->mult.reg.dstpremul + = GCREG_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY_ENABLE; + + gcmosrc->mult.reg.dstdemul + = GCREG_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY_ENABLE; + } + + /* Program blending. */ + bverror = set_blending_index(bvbltparams, batch, + srcinfo, index); + if (bverror != BVERR_NONE) + goto exit; + + /* Program YUV source. */ + if (srcinfo->format.type == BVFMT_YUV) { + bverror = set_yuvsrc_index(bvbltparams, batch, + srcinfo, srcmap, index); + if (bverror != BVERR_NONE) + goto exit; + } + } + + batch->op.blit.srccount += 1; + +exit: + GCEXITARG(GCZONE_BLIT, "bv%s = %d\n", + (bverror == BVERR_NONE) ? "result" : "error", bverror); + return bverror; +} |