Home | History | Annotate | Download | only in gpu
      1 /*
      2  * Copyright 2012 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "GrSWMaskHelper.h"
      9 #include "GrDrawState.h"
     10 #include "GrGpu.h"
     11 
     12 #include "SkStrokeRec.h"
     13 
     14 // TODO: try to remove this #include
     15 #include "GrContext.h"
     16 
     17 namespace {
     18 /*
     19  * Convert a boolean operation into a transfer mode code
     20  */
     21 SkXfermode::Mode op_to_mode(SkRegion::Op op) {
     22 
     23     static const SkXfermode::Mode modeMap[] = {
     24         SkXfermode::kDstOut_Mode,   // kDifference_Op
     25         SkXfermode::kModulate_Mode, // kIntersect_Op
     26         SkXfermode::kSrcOver_Mode,  // kUnion_Op
     27         SkXfermode::kXor_Mode,      // kXOR_Op
     28         SkXfermode::kClear_Mode,    // kReverseDifference_Op
     29         SkXfermode::kSrc_Mode,      // kReplace_Op
     30     };
     31 
     32     return modeMap[op];
     33 }
     34 
     35 }
     36 
     37 /**
     38  * Draw a single rect element of the clip stack into the accumulation bitmap
     39  */
     40 void GrSWMaskHelper::draw(const SkRect& rect, SkRegion::Op op,
     41                           bool antiAlias, uint8_t alpha) {
     42     SkPaint paint;
     43 
     44     SkXfermode* mode = SkXfermode::Create(op_to_mode(op));
     45 
     46     paint.setXfermode(mode);
     47     paint.setAntiAlias(antiAlias);
     48     paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha));
     49 
     50     fDraw.drawRect(rect, paint);
     51 
     52     SkSafeUnref(mode);
     53 }
     54 
     55 /**
     56  * Draw a single path element of the clip stack into the accumulation bitmap
     57  */
     58 void GrSWMaskHelper::draw(const SkPath& path, const SkStrokeRec& stroke, SkRegion::Op op,
     59                           bool antiAlias, uint8_t alpha) {
     60 
     61     SkPaint paint;
     62     if (stroke.isHairlineStyle()) {
     63         paint.setStyle(SkPaint::kStroke_Style);
     64         paint.setStrokeWidth(SK_Scalar1);
     65     } else {
     66         if (stroke.isFillStyle()) {
     67             paint.setStyle(SkPaint::kFill_Style);
     68         } else {
     69             paint.setStyle(SkPaint::kStroke_Style);
     70             paint.setStrokeJoin(stroke.getJoin());
     71             paint.setStrokeCap(stroke.getCap());
     72             paint.setStrokeWidth(stroke.getWidth());
     73         }
     74     }
     75 
     76     SkXfermode* mode = SkXfermode::Create(op_to_mode(op));
     77 
     78     paint.setXfermode(mode);
     79     paint.setAntiAlias(antiAlias);
     80     paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha));
     81 
     82     fDraw.drawPath(path, paint);
     83 
     84     SkSafeUnref(mode);
     85 }
     86 
     87 bool GrSWMaskHelper::init(const SkIRect& resultBounds,
     88                           const SkMatrix* matrix) {
     89     if (NULL != matrix) {
     90         fMatrix = *matrix;
     91     } else {
     92         fMatrix.setIdentity();
     93     }
     94 
     95     // Now translate so the bound's UL corner is at the origin
     96     fMatrix.postTranslate(-resultBounds.fLeft * SK_Scalar1,
     97                           -resultBounds.fTop * SK_Scalar1);
     98     SkIRect bounds = SkIRect::MakeWH(resultBounds.width(),
     99                                      resultBounds.height());
    100 
    101     fBM.setConfig(SkBitmap::kA8_Config, bounds.fRight, bounds.fBottom);
    102     if (!fBM.allocPixels()) {
    103         return false;
    104     }
    105     sk_bzero(fBM.getPixels(), fBM.getSafeSize());
    106 
    107     sk_bzero(&fDraw, sizeof(fDraw));
    108     fRasterClip.setRect(bounds);
    109     fDraw.fRC    = &fRasterClip;
    110     fDraw.fClip  = &fRasterClip.bwRgn();
    111     fDraw.fMatrix = &fMatrix;
    112     fDraw.fBitmap = &fBM;
    113     return true;
    114 }
    115 
    116 /**
    117  * Get a texture (from the texture cache) of the correct size & format.
    118  * Return true on success; false on failure.
    119  */
    120 bool GrSWMaskHelper::getTexture(GrAutoScratchTexture* texture) {
    121     GrTextureDesc desc;
    122     desc.fWidth = fBM.width();
    123     desc.fHeight = fBM.height();
    124     desc.fConfig = kAlpha_8_GrPixelConfig;
    125 
    126     texture->set(fContext, desc);
    127     return NULL != texture->texture();
    128 }
    129 
    130 /**
    131  * Move the result of the software mask generation back to the gpu
    132  */
    133 void GrSWMaskHelper::toTexture(GrTexture *texture) {
    134     SkAutoLockPixels alp(fBM);
    135 
    136     texture->writePixels(0, 0, fBM.width(), fBM.height(),
    137                          kAlpha_8_GrPixelConfig,
    138                          fBM.getPixels(), fBM.rowBytes());
    139 }
    140 
    141 ////////////////////////////////////////////////////////////////////////////////
    142 /**
    143  * Software rasterizes path to A8 mask (possibly using the context's matrix)
    144  * and uploads the result to a scratch texture. Returns the resulting
    145  * texture on success; NULL on failure.
    146  */
    147 GrTexture* GrSWMaskHelper::DrawPathMaskToTexture(GrContext* context,
    148                                                  const SkPath& path,
    149                                                  const SkStrokeRec& stroke,
    150                                                  const SkIRect& resultBounds,
    151                                                  bool antiAlias,
    152                                                  SkMatrix* matrix) {
    153     GrAutoScratchTexture ast;
    154 
    155     GrSWMaskHelper helper(context);
    156 
    157     if (!helper.init(resultBounds, matrix)) {
    158         return NULL;
    159     }
    160 
    161     helper.draw(path, stroke, SkRegion::kReplace_Op, antiAlias, 0xFF);
    162 
    163     if (!helper.getTexture(&ast)) {
    164         return NULL;
    165     }
    166 
    167     helper.toTexture(ast.texture());
    168 
    169     return ast.detach();
    170 }
    171 
    172 void GrSWMaskHelper::DrawToTargetWithPathMask(GrTexture* texture,
    173                                               GrDrawTarget* target,
    174                                               const SkIRect& rect) {
    175     GrDrawState* drawState = target->drawState();
    176 
    177     GrDrawState::AutoViewMatrixRestore avmr;
    178     if (!avmr.setIdentity(drawState)) {
    179         return;
    180     }
    181     GrDrawState::AutoRestoreEffects are(drawState);
    182 
    183     SkRect dstRect = SkRect::MakeLTRB(SK_Scalar1 * rect.fLeft,
    184                                       SK_Scalar1 * rect.fTop,
    185                                       SK_Scalar1 * rect.fRight,
    186                                       SK_Scalar1 * rect.fBottom);
    187 
    188     // We want to use device coords to compute the texture coordinates. We set our matrix to be
    189     // equal to the view matrix followed by a translation so that the top-left of the device bounds
    190     // maps to 0,0, and then a scaling matrix to normalized coords. We apply this matrix to the
    191     // vertex positions rather than local coords.
    192     SkMatrix maskMatrix;
    193     maskMatrix.setIDiv(texture->width(), texture->height());
    194     maskMatrix.preTranslate(SkIntToScalar(-rect.fLeft), SkIntToScalar(-rect.fTop));
    195     maskMatrix.preConcat(drawState->getViewMatrix());
    196 
    197     drawState->addCoverageEffect(
    198                          GrSimpleTextureEffect::Create(texture,
    199                                                        maskMatrix,
    200                                                        GrTextureParams::kNone_FilterMode,
    201                                                        GrEffect::kPosition_CoordsType))->unref();
    202 
    203     target->drawSimpleRect(dstRect);
    204 }
    205