gfx/skia/trunk/src/gpu/GrSWMaskHelper.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/gpu/GrSWMaskHelper.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,212 @@
     1.4 +/*
     1.5 + * Copyright 2012 Google Inc.
     1.6 + *
     1.7 + * Use of this source code is governed by a BSD-style license that can be
     1.8 + * found in the LICENSE file.
     1.9 + */
    1.10 +
    1.11 +#include "GrSWMaskHelper.h"
    1.12 +#include "GrDrawState.h"
    1.13 +#include "GrDrawTargetCaps.h"
    1.14 +#include "GrGpu.h"
    1.15 +
    1.16 +#include "SkStrokeRec.h"
    1.17 +
    1.18 +// TODO: try to remove this #include
    1.19 +#include "GrContext.h"
    1.20 +
    1.21 +namespace {
    1.22 +/*
    1.23 + * Convert a boolean operation into a transfer mode code
    1.24 + */
    1.25 +SkXfermode::Mode op_to_mode(SkRegion::Op op) {
    1.26 +
    1.27 +    static const SkXfermode::Mode modeMap[] = {
    1.28 +        SkXfermode::kDstOut_Mode,   // kDifference_Op
    1.29 +        SkXfermode::kModulate_Mode, // kIntersect_Op
    1.30 +        SkXfermode::kSrcOver_Mode,  // kUnion_Op
    1.31 +        SkXfermode::kXor_Mode,      // kXOR_Op
    1.32 +        SkXfermode::kClear_Mode,    // kReverseDifference_Op
    1.33 +        SkXfermode::kSrc_Mode,      // kReplace_Op
    1.34 +    };
    1.35 +
    1.36 +    return modeMap[op];
    1.37 +}
    1.38 +
    1.39 +}
    1.40 +
    1.41 +/**
    1.42 + * Draw a single rect element of the clip stack into the accumulation bitmap
    1.43 + */
    1.44 +void GrSWMaskHelper::draw(const SkRect& rect, SkRegion::Op op,
    1.45 +                          bool antiAlias, uint8_t alpha) {
    1.46 +    SkPaint paint;
    1.47 +
    1.48 +    SkXfermode* mode = SkXfermode::Create(op_to_mode(op));
    1.49 +
    1.50 +    paint.setXfermode(mode);
    1.51 +    paint.setAntiAlias(antiAlias);
    1.52 +    paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha));
    1.53 +
    1.54 +    fDraw.drawRect(rect, paint);
    1.55 +
    1.56 +    SkSafeUnref(mode);
    1.57 +}
    1.58 +
    1.59 +/**
    1.60 + * Draw a single path element of the clip stack into the accumulation bitmap
    1.61 + */
    1.62 +void GrSWMaskHelper::draw(const SkPath& path, const SkStrokeRec& stroke, SkRegion::Op op,
    1.63 +                          bool antiAlias, uint8_t alpha) {
    1.64 +
    1.65 +    SkPaint paint;
    1.66 +    if (stroke.isHairlineStyle()) {
    1.67 +        paint.setStyle(SkPaint::kStroke_Style);
    1.68 +        paint.setStrokeWidth(SK_Scalar1);
    1.69 +    } else {
    1.70 +        if (stroke.isFillStyle()) {
    1.71 +            paint.setStyle(SkPaint::kFill_Style);
    1.72 +        } else {
    1.73 +            paint.setStyle(SkPaint::kStroke_Style);
    1.74 +            paint.setStrokeJoin(stroke.getJoin());
    1.75 +            paint.setStrokeCap(stroke.getCap());
    1.76 +            paint.setStrokeWidth(stroke.getWidth());
    1.77 +        }
    1.78 +    }
    1.79 +    paint.setAntiAlias(antiAlias);
    1.80 +
    1.81 +    if (SkRegion::kReplace_Op == op && 0xFF == alpha) {
    1.82 +        SkASSERT(0xFF == paint.getAlpha());
    1.83 +        fDraw.drawPathCoverage(path, paint);
    1.84 +    } else {
    1.85 +        paint.setXfermodeMode(op_to_mode(op));
    1.86 +        paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha));
    1.87 +        fDraw.drawPath(path, paint);
    1.88 +    }
    1.89 +}
    1.90 +
    1.91 +bool GrSWMaskHelper::init(const SkIRect& resultBounds,
    1.92 +                          const SkMatrix* matrix) {
    1.93 +    if (NULL != matrix) {
    1.94 +        fMatrix = *matrix;
    1.95 +    } else {
    1.96 +        fMatrix.setIdentity();
    1.97 +    }
    1.98 +
    1.99 +    // Now translate so the bound's UL corner is at the origin
   1.100 +    fMatrix.postTranslate(-resultBounds.fLeft * SK_Scalar1,
   1.101 +                          -resultBounds.fTop * SK_Scalar1);
   1.102 +    SkIRect bounds = SkIRect::MakeWH(resultBounds.width(),
   1.103 +                                     resultBounds.height());
   1.104 +
   1.105 +    if (!fBM.allocPixels(SkImageInfo::MakeA8(bounds.fRight, bounds.fBottom))) {
   1.106 +        return false;
   1.107 +    }
   1.108 +    sk_bzero(fBM.getPixels(), fBM.getSafeSize());
   1.109 +
   1.110 +    sk_bzero(&fDraw, sizeof(fDraw));
   1.111 +    fRasterClip.setRect(bounds);
   1.112 +    fDraw.fRC    = &fRasterClip;
   1.113 +    fDraw.fClip  = &fRasterClip.bwRgn();
   1.114 +    fDraw.fMatrix = &fMatrix;
   1.115 +    fDraw.fBitmap = &fBM;
   1.116 +    return true;
   1.117 +}
   1.118 +
   1.119 +/**
   1.120 + * Get a texture (from the texture cache) of the correct size & format.
   1.121 + * Return true on success; false on failure.
   1.122 + */
   1.123 +bool GrSWMaskHelper::getTexture(GrAutoScratchTexture* texture) {
   1.124 +    GrTextureDesc desc;
   1.125 +    desc.fWidth = fBM.width();
   1.126 +    desc.fHeight = fBM.height();
   1.127 +    desc.fConfig = kAlpha_8_GrPixelConfig;
   1.128 +
   1.129 +    texture->set(fContext, desc);
   1.130 +    return NULL != texture->texture();
   1.131 +}
   1.132 +
   1.133 +/**
   1.134 + * Move the result of the software mask generation back to the gpu
   1.135 + */
   1.136 +void GrSWMaskHelper::toTexture(GrTexture *texture) {
   1.137 +    SkAutoLockPixels alp(fBM);
   1.138 +
   1.139 +    // If we aren't reusing scratch textures we don't need to flush before
   1.140 +    // writing since no one else will be using 'texture'
   1.141 +    bool reuseScratch = fContext->getGpu()->caps()->reuseScratchTextures();
   1.142 +
   1.143 +    // Since we're uploading to it, 'texture' shouldn't have a render target.
   1.144 +    SkASSERT(NULL == texture->asRenderTarget());
   1.145 +
   1.146 +    texture->writePixels(0, 0, fBM.width(), fBM.height(),
   1.147 +                         kAlpha_8_GrPixelConfig,
   1.148 +                         fBM.getPixels(), fBM.rowBytes(),
   1.149 +                         reuseScratch ? 0 : GrContext::kDontFlush_PixelOpsFlag);
   1.150 +}
   1.151 +
   1.152 +////////////////////////////////////////////////////////////////////////////////
   1.153 +/**
   1.154 + * Software rasterizes path to A8 mask (possibly using the context's matrix)
   1.155 + * and uploads the result to a scratch texture. Returns the resulting
   1.156 + * texture on success; NULL on failure.
   1.157 + */
   1.158 +GrTexture* GrSWMaskHelper::DrawPathMaskToTexture(GrContext* context,
   1.159 +                                                 const SkPath& path,
   1.160 +                                                 const SkStrokeRec& stroke,
   1.161 +                                                 const SkIRect& resultBounds,
   1.162 +                                                 bool antiAlias,
   1.163 +                                                 SkMatrix* matrix) {
   1.164 +    GrAutoScratchTexture ast;
   1.165 +
   1.166 +    GrSWMaskHelper helper(context);
   1.167 +
   1.168 +    if (!helper.init(resultBounds, matrix)) {
   1.169 +        return NULL;
   1.170 +    }
   1.171 +
   1.172 +    helper.draw(path, stroke, SkRegion::kReplace_Op, antiAlias, 0xFF);
   1.173 +
   1.174 +    if (!helper.getTexture(&ast)) {
   1.175 +        return NULL;
   1.176 +    }
   1.177 +
   1.178 +    helper.toTexture(ast.texture());
   1.179 +
   1.180 +    return ast.detach();
   1.181 +}
   1.182 +
   1.183 +void GrSWMaskHelper::DrawToTargetWithPathMask(GrTexture* texture,
   1.184 +                                              GrDrawTarget* target,
   1.185 +                                              const SkIRect& rect) {
   1.186 +    GrDrawState* drawState = target->drawState();
   1.187 +
   1.188 +    GrDrawState::AutoViewMatrixRestore avmr;
   1.189 +    if (!avmr.setIdentity(drawState)) {
   1.190 +        return;
   1.191 +    }
   1.192 +    GrDrawState::AutoRestoreEffects are(drawState);
   1.193 +
   1.194 +    SkRect dstRect = SkRect::MakeLTRB(SK_Scalar1 * rect.fLeft,
   1.195 +                                      SK_Scalar1 * rect.fTop,
   1.196 +                                      SK_Scalar1 * rect.fRight,
   1.197 +                                      SK_Scalar1 * rect.fBottom);
   1.198 +
   1.199 +    // We want to use device coords to compute the texture coordinates. We set our matrix to be
   1.200 +    // equal to the view matrix followed by a translation so that the top-left of the device bounds
   1.201 +    // maps to 0,0, and then a scaling matrix to normalized coords. We apply this matrix to the
   1.202 +    // vertex positions rather than local coords.
   1.203 +    SkMatrix maskMatrix;
   1.204 +    maskMatrix.setIDiv(texture->width(), texture->height());
   1.205 +    maskMatrix.preTranslate(SkIntToScalar(-rect.fLeft), SkIntToScalar(-rect.fTop));
   1.206 +    maskMatrix.preConcat(drawState->getViewMatrix());
   1.207 +
   1.208 +    drawState->addCoverageEffect(
   1.209 +                         GrSimpleTextureEffect::Create(texture,
   1.210 +                                                       maskMatrix,
   1.211 +                                                       GrTextureParams::kNone_FilterMode,
   1.212 +                                                       kPosition_GrCoordSet))->unref();
   1.213 +
   1.214 +    target->drawSimpleRect(dstRect);
   1.215 +}

mercurial