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 GrRect& 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 GrIRect& 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     GrIRect bounds = GrIRect::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, uint8_t alpha) {
    134     SkAutoLockPixels alp(fBM);
    135 
    136     // The destination texture is almost always larger than "fBM". Clear
    137     // it appropriately so we don't get mask artifacts outside of the path's
    138     // bounding box
    139 
    140     // "texture" needs to be installed as the render target for the clear
    141     // and the texture upload but cannot remain the render target upon
    142     // return. Callers typically use it as a texture and it would then
    143     // be both source and dest.
    144     GrDrawState::AutoRenderTargetRestore artr(fContext->getGpu()->drawState(),
    145                                               texture->asRenderTarget());
    146 
    147     fContext->getGpu()->clear(NULL, GrColorPackRGBA(alpha, alpha, alpha, alpha));
    148 
    149     texture->writePixels(0, 0, fBM.width(), fBM.height(),
    150                          kAlpha_8_GrPixelConfig,
    151                          fBM.getPixels(), fBM.rowBytes());
    152 }
    153 
    154 ////////////////////////////////////////////////////////////////////////////////
    155 /**
    156  * Software rasterizes path to A8 mask (possibly using the context's matrix)
    157  * and uploads the result to a scratch texture. Returns the resulting
    158  * texture on success; NULL on failure.
    159  */
    160 GrTexture* GrSWMaskHelper::DrawPathMaskToTexture(GrContext* context,
    161                                                  const SkPath& path,
    162                                                  const SkStrokeRec& stroke,
    163                                                  const GrIRect& resultBounds,
    164                                                  bool antiAlias,
    165                                                  SkMatrix* matrix) {
    166     GrAutoScratchTexture ast;
    167 
    168     GrSWMaskHelper helper(context);
    169 
    170     if (!helper.init(resultBounds, matrix)) {
    171         return NULL;
    172     }
    173 
    174     helper.draw(path, stroke, SkRegion::kReplace_Op, antiAlias, 0xFF);
    175 
    176     if (!helper.getTexture(&ast)) {
    177         return NULL;
    178     }
    179 
    180     helper.toTexture(ast.texture(), 0x00);
    181 
    182     return ast.detach();
    183 }
    184 
    185 void GrSWMaskHelper::DrawToTargetWithPathMask(GrTexture* texture,
    186                                               GrDrawTarget* target,
    187                                               const GrIRect& rect) {
    188     GrDrawState* drawState = target->drawState();
    189 
    190     GrDrawState::AutoDeviceCoordDraw adcd(drawState);
    191     if (!adcd.succeeded()) {
    192         return;
    193     }
    194     enum {
    195         // the SW path renderer shares this stage with glyph
    196         // rendering (kGlyphMaskStage in GrBatchedTextContext)
    197         kPathMaskStage = GrPaint::kTotalStages,
    198     };
    199     GrAssert(!drawState->isStageEnabled(kPathMaskStage));
    200     drawState->createTextureEffect(kPathMaskStage, texture, SkMatrix::I());
    201     SkScalar w = SkIntToScalar(rect.width());
    202     SkScalar h = SkIntToScalar(rect.height());
    203     GrRect maskRect = GrRect::MakeWH(w / texture->width(),
    204                                      h / texture->height());
    205 
    206     const GrRect* srcRects[GrDrawState::kNumStages] = { NULL };
    207     srcRects[kPathMaskStage] = &maskRect;
    208     GrRect dstRect = GrRect::MakeLTRB(
    209                             SK_Scalar1 * rect.fLeft,
    210                             SK_Scalar1 * rect.fTop,
    211                             SK_Scalar1 * rect.fRight,
    212                             SK_Scalar1 * rect.fBottom);
    213     target->drawRect(dstRect, NULL, srcRects, NULL);
    214     drawState->disableStage(kPathMaskStage);
    215 }
    216