diff -r 000000000000 -r 6474c204b198 gfx/skia/trunk/src/gpu/GrSWMaskHelper.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gfx/skia/trunk/src/gpu/GrSWMaskHelper.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,212 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrSWMaskHelper.h" +#include "GrDrawState.h" +#include "GrDrawTargetCaps.h" +#include "GrGpu.h" + +#include "SkStrokeRec.h" + +// TODO: try to remove this #include +#include "GrContext.h" + +namespace { +/* + * Convert a boolean operation into a transfer mode code + */ +SkXfermode::Mode op_to_mode(SkRegion::Op op) { + + static const SkXfermode::Mode modeMap[] = { + SkXfermode::kDstOut_Mode, // kDifference_Op + SkXfermode::kModulate_Mode, // kIntersect_Op + SkXfermode::kSrcOver_Mode, // kUnion_Op + SkXfermode::kXor_Mode, // kXOR_Op + SkXfermode::kClear_Mode, // kReverseDifference_Op + SkXfermode::kSrc_Mode, // kReplace_Op + }; + + return modeMap[op]; +} + +} + +/** + * Draw a single rect element of the clip stack into the accumulation bitmap + */ +void GrSWMaskHelper::draw(const SkRect& rect, SkRegion::Op op, + bool antiAlias, uint8_t alpha) { + SkPaint paint; + + SkXfermode* mode = SkXfermode::Create(op_to_mode(op)); + + paint.setXfermode(mode); + paint.setAntiAlias(antiAlias); + paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha)); + + fDraw.drawRect(rect, paint); + + SkSafeUnref(mode); +} + +/** + * Draw a single path element of the clip stack into the accumulation bitmap + */ +void GrSWMaskHelper::draw(const SkPath& path, const SkStrokeRec& stroke, SkRegion::Op op, + bool antiAlias, uint8_t alpha) { + + SkPaint paint; + if (stroke.isHairlineStyle()) { + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeWidth(SK_Scalar1); + } else { + if (stroke.isFillStyle()) { + paint.setStyle(SkPaint::kFill_Style); + } else { + paint.setStyle(SkPaint::kStroke_Style); + paint.setStrokeJoin(stroke.getJoin()); + paint.setStrokeCap(stroke.getCap()); + paint.setStrokeWidth(stroke.getWidth()); + } + } + paint.setAntiAlias(antiAlias); + + if (SkRegion::kReplace_Op == op && 0xFF == alpha) { + SkASSERT(0xFF == paint.getAlpha()); + fDraw.drawPathCoverage(path, paint); + } else { + paint.setXfermodeMode(op_to_mode(op)); + paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha)); + fDraw.drawPath(path, paint); + } +} + +bool GrSWMaskHelper::init(const SkIRect& resultBounds, + const SkMatrix* matrix) { + if (NULL != matrix) { + fMatrix = *matrix; + } else { + fMatrix.setIdentity(); + } + + // Now translate so the bound's UL corner is at the origin + fMatrix.postTranslate(-resultBounds.fLeft * SK_Scalar1, + -resultBounds.fTop * SK_Scalar1); + SkIRect bounds = SkIRect::MakeWH(resultBounds.width(), + resultBounds.height()); + + if (!fBM.allocPixels(SkImageInfo::MakeA8(bounds.fRight, bounds.fBottom))) { + return false; + } + sk_bzero(fBM.getPixels(), fBM.getSafeSize()); + + sk_bzero(&fDraw, sizeof(fDraw)); + fRasterClip.setRect(bounds); + fDraw.fRC = &fRasterClip; + fDraw.fClip = &fRasterClip.bwRgn(); + fDraw.fMatrix = &fMatrix; + fDraw.fBitmap = &fBM; + return true; +} + +/** + * Get a texture (from the texture cache) of the correct size & format. + * Return true on success; false on failure. + */ +bool GrSWMaskHelper::getTexture(GrAutoScratchTexture* texture) { + GrTextureDesc desc; + desc.fWidth = fBM.width(); + desc.fHeight = fBM.height(); + desc.fConfig = kAlpha_8_GrPixelConfig; + + texture->set(fContext, desc); + return NULL != texture->texture(); +} + +/** + * Move the result of the software mask generation back to the gpu + */ +void GrSWMaskHelper::toTexture(GrTexture *texture) { + SkAutoLockPixels alp(fBM); + + // If we aren't reusing scratch textures we don't need to flush before + // writing since no one else will be using 'texture' + bool reuseScratch = fContext->getGpu()->caps()->reuseScratchTextures(); + + // Since we're uploading to it, 'texture' shouldn't have a render target. + SkASSERT(NULL == texture->asRenderTarget()); + + texture->writePixels(0, 0, fBM.width(), fBM.height(), + kAlpha_8_GrPixelConfig, + fBM.getPixels(), fBM.rowBytes(), + reuseScratch ? 0 : GrContext::kDontFlush_PixelOpsFlag); +} + +//////////////////////////////////////////////////////////////////////////////// +/** + * Software rasterizes path to A8 mask (possibly using the context's matrix) + * and uploads the result to a scratch texture. Returns the resulting + * texture on success; NULL on failure. + */ +GrTexture* GrSWMaskHelper::DrawPathMaskToTexture(GrContext* context, + const SkPath& path, + const SkStrokeRec& stroke, + const SkIRect& resultBounds, + bool antiAlias, + SkMatrix* matrix) { + GrAutoScratchTexture ast; + + GrSWMaskHelper helper(context); + + if (!helper.init(resultBounds, matrix)) { + return NULL; + } + + helper.draw(path, stroke, SkRegion::kReplace_Op, antiAlias, 0xFF); + + if (!helper.getTexture(&ast)) { + return NULL; + } + + helper.toTexture(ast.texture()); + + return ast.detach(); +} + +void GrSWMaskHelper::DrawToTargetWithPathMask(GrTexture* texture, + GrDrawTarget* target, + const SkIRect& rect) { + GrDrawState* drawState = target->drawState(); + + GrDrawState::AutoViewMatrixRestore avmr; + if (!avmr.setIdentity(drawState)) { + return; + } + GrDrawState::AutoRestoreEffects are(drawState); + + SkRect dstRect = SkRect::MakeLTRB(SK_Scalar1 * rect.fLeft, + SK_Scalar1 * rect.fTop, + SK_Scalar1 * rect.fRight, + SK_Scalar1 * rect.fBottom); + + // We want to use device coords to compute the texture coordinates. We set our matrix to be + // equal to the view matrix followed by a translation so that the top-left of the device bounds + // maps to 0,0, and then a scaling matrix to normalized coords. We apply this matrix to the + // vertex positions rather than local coords. + SkMatrix maskMatrix; + maskMatrix.setIDiv(texture->width(), texture->height()); + maskMatrix.preTranslate(SkIntToScalar(-rect.fLeft), SkIntToScalar(-rect.fTop)); + maskMatrix.preConcat(drawState->getViewMatrix()); + + drawState->addCoverageEffect( + GrSimpleTextureEffect::Create(texture, + maskMatrix, + GrTextureParams::kNone_FilterMode, + kPosition_GrCoordSet))->unref(); + + target->drawSimpleRect(dstRect); +}