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