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