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 +}