blob: 02868ef9b701fbfd8cf7597ecef370ff3a822448 [file] [log] [blame]
robertphillips@google.com58b20212012-06-27 20:44:52 +00001/*
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
sugoi@google.com12b4e272012-12-06 20:13:11 +000012#include "SkStroke.h"
13
robertphillips@google.com58b20212012-06-27 20:44:52 +000014// TODO: try to remove this #include
15#include "GrContext.h"
16
17namespace {
18/*
19 * Convert a boolean operation into a transfer mode code
20 */
21SkXfermode::Mode op_to_mode(SkRegion::Op op) {
22
23 static const SkXfermode::Mode modeMap[] = {
24 SkXfermode::kDstOut_Mode, // kDifference_Op
25 SkXfermode::kMultiply_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
robertphillips@google.com58b20212012-06-27 20:44:52 +000035}
36
37/**
38 * Draw a single rect element of the clip stack into the accumulation bitmap
39 */
rmistry@google.comfbfcd562012-08-23 18:09:54 +000040void GrSWMaskHelper::draw(const GrRect& rect, SkRegion::Op op,
robertphillips@google.com366f1c62012-06-29 21:38:47 +000041 bool antiAlias, uint8_t alpha) {
robertphillips@google.com58b20212012-06-27 20:44:52 +000042 SkPaint paint;
43
44 SkXfermode* mode = SkXfermode::Create(op_to_mode(op));
45
46 paint.setXfermode(mode);
47 paint.setAntiAlias(antiAlias);
robertphillips@google.com366f1c62012-06-29 21:38:47 +000048 paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha));
robertphillips@google.com58b20212012-06-27 20:44:52 +000049
robertphillips@google.com366f1c62012-06-29 21:38:47 +000050 fDraw.drawRect(rect, paint);
robertphillips@google.com58b20212012-06-27 20:44:52 +000051
52 SkSafeUnref(mode);
53}
54
55/**
56 * Draw a single path element of the clip stack into the accumulation bitmap
57 */
sugoi@google.com12b4e272012-12-06 20:13:11 +000058void GrSWMaskHelper::draw(const SkPath& path, const SkStroke& stroke, SkRegion::Op op,
59 bool antiAlias, uint8_t alpha) {
robertphillips@google.com58b20212012-06-27 20:44:52 +000060
61 SkPaint paint;
sugoi@google.com12b4e272012-12-06 20:13:11 +000062 SkScalar width = stroke.getWidthIfStroked();
63 if (0 == width) {
robertphillips@google.com58b20212012-06-27 20:44:52 +000064 paint.setStyle(SkPaint::kStroke_Style);
65 paint.setStrokeWidth(SK_Scalar1);
66 } else {
sugoi@google.com12b4e272012-12-06 20:13:11 +000067 if (stroke.getDoFill()) {
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(width);
robertphillips@google.com58b20212012-06-27 20:44:52 +000074 }
75 }
76 SkXfermode* mode = SkXfermode::Create(op_to_mode(op));
77
78 paint.setXfermode(mode);
79 paint.setAntiAlias(antiAlias);
robertphillips@google.com366f1c62012-06-29 21:38:47 +000080 paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha));
robertphillips@google.com58b20212012-06-27 20:44:52 +000081
sugoi@google.com12b4e272012-12-06 20:13:11 +000082 fDraw.drawPath(path, paint);
robertphillips@google.com58b20212012-06-27 20:44:52 +000083
84 SkSafeUnref(mode);
85}
86
rmistry@google.comfbfcd562012-08-23 18:09:54 +000087bool GrSWMaskHelper::init(const GrIRect& resultBounds,
bsalomon@google.comb9086a02012-11-01 18:02:54 +000088 const SkMatrix* matrix) {
robertphillips@google.com366f1c62012-06-29 21:38:47 +000089 if (NULL != matrix) {
90 fMatrix = *matrix;
robertphillips@google.com58b20212012-06-27 20:44:52 +000091 } else {
92 fMatrix.setIdentity();
93 }
94
robertphillips@google.com366f1c62012-06-29 21:38:47 +000095 // 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());
robertphillips@google.com58b20212012-06-27 20:44:52 +0000100
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/**
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000117 * Get a texture (from the texture cache) of the correct size & format.
118 * Return true on success; false on failure.
robertphillips@google.com58b20212012-06-27 20:44:52 +0000119 */
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000120bool GrSWMaskHelper::getTexture(GrAutoScratchTexture* texture) {
robertphillips@google.com58b20212012-06-27 20:44:52 +0000121 GrTextureDesc desc;
122 desc.fWidth = fBM.width();
123 desc.fHeight = fBM.height();
124 desc.fConfig = kAlpha_8_GrPixelConfig;
125
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000126 texture->set(fContext, desc);
127 return NULL != texture->texture();
robertphillips@google.com58b20212012-06-27 20:44:52 +0000128}
129
130/**
131 * Move the result of the software mask generation back to the gpu
132 */
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000133void GrSWMaskHelper::toTexture(GrTexture *texture, uint8_t alpha) {
robertphillips@google.com58b20212012-06-27 20:44:52 +0000134 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
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000139
robertphillips@google.com58b20212012-06-27 20:44:52 +0000140 // "texture" needs to be installed as the render target for the clear
141 // and the texture upload but cannot remain the render target upon
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000142 // return. Callers typically use it as a texture and it would then
robertphillips@google.com58b20212012-06-27 20:44:52 +0000143 // be both source and dest.
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000144 GrDrawState::AutoRenderTargetRestore artr(fContext->getGpu()->drawState(),
robertphillips@google.com58b20212012-06-27 20:44:52 +0000145 texture->asRenderTarget());
146
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000147 fContext->getGpu()->clear(NULL, SkColorSetARGB(alpha, alpha, alpha, alpha));
robertphillips@google.com58b20212012-06-27 20:44:52 +0000148
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000149 texture->writePixels(0, 0, fBM.width(), fBM.height(),
robertphillips@google.com58b20212012-06-27 20:44:52 +0000150 kAlpha_8_GrPixelConfig,
151 fBM.getPixels(), fBM.rowBytes());
152}
153
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000154////////////////////////////////////////////////////////////////////////////////
155/**
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000156 * Software rasterizes path to A8 mask (possibly using the context's matrix)
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000157 * and uploads the result to a scratch texture. Returns the resulting
158 * texture on success; NULL on failure.
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000159 */
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000160GrTexture* GrSWMaskHelper::DrawPathMaskToTexture(GrContext* context,
161 const SkPath& path,
sugoi@google.com12b4e272012-12-06 20:13:11 +0000162 const SkStroke& stroke,
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000163 const GrIRect& resultBounds,
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000164 bool antiAlias,
bsalomon@google.comb9086a02012-11-01 18:02:54 +0000165 SkMatrix* matrix) {
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000166 GrAutoScratchTexture ast;
167
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000168 GrSWMaskHelper helper(context);
169
170 if (!helper.init(resultBounds, matrix)) {
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000171 return NULL;
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000172 }
173
sugoi@google.com12b4e272012-12-06 20:13:11 +0000174 helper.draw(path, stroke, SkRegion::kReplace_Op, antiAlias, 0xFF);
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000175
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000176 if (!helper.getTexture(&ast)) {
177 return NULL;
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000178 }
179
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000180 helper.toTexture(ast.texture(), 0x00);
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000181
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000182 return ast.detach();
183}
184
185void GrSWMaskHelper::DrawToTargetWithPathMask(GrTexture* texture,
186 GrDrawTarget* target,
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000187 const GrIRect& rect) {
188 GrDrawState* drawState = target->drawState();
189
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000190 GrDrawState::AutoDeviceCoordDraw adcd(drawState);
bsalomon@google.come3d32162012-07-20 13:37:06 +0000191 if (!adcd.succeeded()) {
192 return;
193 }
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000194 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));
bsalomon@google.com08283af2012-10-26 13:01:20 +0000200 drawState->stage(kPathMaskStage)->reset();
tomhudson@google.com1e8f0162012-07-20 16:25:18 +0000201 drawState->createTextureEffect(kPathMaskStage, texture);
bsalomon@google.com81712882012-11-01 17:12:34 +0000202 SkScalar w = SkIntToScalar(rect.width());
203 SkScalar h = SkIntToScalar(rect.height());
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000204 GrRect maskRect = GrRect::MakeWH(w / texture->width(),
205 h / texture->height());
206
207 const GrRect* srcRects[GrDrawState::kNumStages] = { NULL };
208 srcRects[kPathMaskStage] = &maskRect;
robertphillips@google.com5dfb6722012-07-09 16:32:28 +0000209 GrRect dstRect = GrRect::MakeLTRB(
210 SK_Scalar1 * rect.fLeft,
211 SK_Scalar1 * rect.fTop,
212 SK_Scalar1 * rect.fRight,
213 SK_Scalar1 * rect.fBottom);
bsalomon@google.come3d32162012-07-20 13:37:06 +0000214 target->drawRect(dstRect, NULL, srcRects, NULL);
tomhudson@google.com676e6602012-07-10 17:21:48 +0000215 drawState->disableStage(kPathMaskStage);
robertphillips@google.com366f1c62012-06-29 21:38:47 +0000216}
217