blob: 6aa45a10a5fb038d8b493d4aecbdd5f8dcd056f0 [file] [log] [blame]
robertphillipsea461502015-05-26 11:38:03 -07001
2/*
3 * Copyright 2015 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
robertphillips2334fb62015-06-17 05:43:33 -07009#include "GrAtlasTextContext.h"
robertphillipsea461502015-05-26 11:38:03 -070010#include "GrBatchTest.h"
jvanverth31ff7622015-08-07 10:09:28 -070011#include "GrColor.h"
robertphillipsea461502015-05-26 11:38:03 -070012#include "GrDrawContext.h"
13#include "GrOvalRenderer.h"
14#include "GrPathRenderer.h"
robertphillips2334fb62015-06-17 05:43:33 -070015#include "GrRenderTarget.h"
16#include "GrRenderTargetPriv.h"
17#include "GrStencilAndCoverTextContext.h"
robertphillipsea461502015-05-26 11:38:03 -070018
joshualitt74417822015-08-07 11:42:16 -070019#include "batches/GrBatch.h"
jvanverth14b88032015-08-07 12:18:54 -070020#include "batches/GrDrawAtlasBatch.h"
joshualitt2771b562015-08-07 12:46:26 -070021#include "batches/GrDrawVerticesBatch.h"
joshualitt7fc2a262015-08-10 10:30:14 -070022#include "batches/GrRectBatchFactory.h"
joshualitt74417822015-08-07 11:42:16 -070023
jvanverth31ff7622015-08-07 10:09:28 -070024#include "SkGr.h"
25#include "SkRSXform.h"
26
robertphillipsea461502015-05-26 11:38:03 -070027#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == fContext)
28#define RETURN_IF_ABANDONED if (!fDrawTarget) { return; }
29#define RETURN_FALSE_IF_ABANDONED if (!fDrawTarget) { return false; }
30#define RETURN_NULL_IF_ABANDONED if (!fDrawTarget) { return NULL; }
31
32class AutoCheckFlush {
33public:
34 AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context); }
35 ~AutoCheckFlush() { fContext->flushIfNecessary(); }
36
37private:
38 GrContext* fContext;
39};
40
robertphillips2334fb62015-06-17 05:43:33 -070041GrDrawContext::GrDrawContext(GrContext* context,
42 GrDrawTarget* drawTarget,
robertphillipsfcf78292015-06-19 11:49:52 -070043 const SkSurfaceProps& surfaceProps)
robertphillipsea461502015-05-26 11:38:03 -070044 : fContext(context)
robertphillips2334fb62015-06-17 05:43:33 -070045 , fDrawTarget(SkRef(drawTarget))
46 , fTextContext(NULL)
robertphillipsfcf78292015-06-19 11:49:52 -070047 , fSurfaceProps(surfaceProps) {
robertphillipsea461502015-05-26 11:38:03 -070048}
49
robertphillips4b195e52015-05-26 14:37:00 -070050GrDrawContext::~GrDrawContext() {
51 SkSafeUnref(fDrawTarget);
robertphillips2334fb62015-06-17 05:43:33 -070052 SkDELETE(fTextContext);
robertphillips4b195e52015-05-26 14:37:00 -070053}
54
robertphillipsea461502015-05-26 11:38:03 -070055void GrDrawContext::copySurface(GrRenderTarget* dst, GrSurface* src,
56 const SkIRect& srcRect, const SkIPoint& dstPoint) {
57 if (!this->prepareToDraw(dst)) {
58 return;
59 }
60
61 fDrawTarget->copySurface(dst, src, srcRect, dstPoint);
62}
63
robertphillips2334fb62015-06-17 05:43:33 -070064GrTextContext* GrDrawContext::createTextContext(GrRenderTarget* renderTarget,
robertphillipsfcf78292015-06-19 11:49:52 -070065 const SkSurfaceProps& surfaceProps) {
robertphillips2334fb62015-06-17 05:43:33 -070066 if (fContext->caps()->shaderCaps()->pathRenderingSupport() &&
cdaltone04edd82015-06-29 14:15:19 -070067 renderTarget->isStencilBufferMultisampled() &&
68 fSurfaceProps.isUseDistanceFieldFonts()) { // FIXME: Rename the dff flag to be more general.
robertphillips2334fb62015-06-17 05:43:33 -070069 GrStencilAttachment* sb = renderTarget->renderTargetPriv().attachStencilAttachment();
70 if (sb) {
robertphillipsfcf78292015-06-19 11:49:52 -070071 return GrStencilAndCoverTextContext::Create(fContext, this, surfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -070072 }
73 }
74
robertphillipsfcf78292015-06-19 11:49:52 -070075 return GrAtlasTextContext::Create(fContext, this, surfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -070076}
77
78void GrDrawContext::drawText(GrRenderTarget* rt, const GrClip& clip, const GrPaint& grPaint,
79 const SkPaint& skPaint,
80 const SkMatrix& viewMatrix,
81 const char text[], size_t byteLength,
82 SkScalar x, SkScalar y, const SkIRect& clipBounds) {
83 if (!fTextContext) {
robertphillipsfcf78292015-06-19 11:49:52 -070084 fTextContext = this->createTextContext(rt, fSurfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -070085 }
86
87 fTextContext->drawText(rt, clip, grPaint, skPaint, viewMatrix,
88 text, byteLength, x, y, clipBounds);
89
90}
91void GrDrawContext::drawPosText(GrRenderTarget* rt, const GrClip& clip, const GrPaint& grPaint,
92 const SkPaint& skPaint,
93 const SkMatrix& viewMatrix,
94 const char text[], size_t byteLength,
95 const SkScalar pos[], int scalarsPerPosition,
96 const SkPoint& offset, const SkIRect& clipBounds) {
97 if (!fTextContext) {
robertphillipsfcf78292015-06-19 11:49:52 -070098 fTextContext = this->createTextContext(rt, fSurfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -070099 }
100
101 fTextContext->drawPosText(rt, clip, grPaint, skPaint, viewMatrix, text, byteLength,
102 pos, scalarsPerPosition, offset, clipBounds);
103
104}
105void GrDrawContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, const SkPaint& skPaint,
106 const SkMatrix& viewMatrix, const SkTextBlob* blob,
107 SkScalar x, SkScalar y,
108 SkDrawFilter* filter, const SkIRect& clipBounds) {
109 if (!fTextContext) {
robertphillipsfcf78292015-06-19 11:49:52 -0700110 fTextContext = this->createTextContext(rt, fSurfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -0700111 }
112
113 fTextContext->drawTextBlob(rt, clip, skPaint, viewMatrix, blob, x, y, filter, clipBounds);
robertphillipsea461502015-05-26 11:38:03 -0700114}
115
116void GrDrawContext::drawPaths(GrPipelineBuilder* pipelineBuilder,
117 const GrPathProcessor* pathProc,
118 const GrPathRange* pathRange,
119 const void* indices,
120 int /*GrDrawTarget::PathIndexType*/ indexType,
121 const float transformValues[],
122 int /*GrDrawTarget::PathTransformType*/ transformType,
123 int count,
124 int /*GrPathRendering::FillType*/ fill) {
joshualitt1c735482015-07-13 08:08:25 -0700125 fDrawTarget->drawPaths(*pipelineBuilder, pathProc, pathRange,
robertphillipsea461502015-05-26 11:38:03 -0700126 indices, (GrDrawTarget::PathIndexType) indexType,
127 transformValues,
128 (GrDrawTarget::PathTransformType) transformType,
129 count, (GrPathRendering::FillType) fill);
130}
131
132void GrDrawContext::discard(GrRenderTarget* renderTarget) {
133 RETURN_IF_ABANDONED
134 SkASSERT(renderTarget);
135 AutoCheckFlush acf(fContext);
136 if (!this->prepareToDraw(renderTarget)) {
137 return;
138 }
139 fDrawTarget->discard(renderTarget);
140}
141
142void GrDrawContext::clear(GrRenderTarget* renderTarget,
143 const SkIRect* rect,
144 const GrColor color,
145 bool canIgnoreRect) {
146 RETURN_IF_ABANDONED
147 SkASSERT(renderTarget);
148
149 AutoCheckFlush acf(fContext);
150 if (!this->prepareToDraw(renderTarget)) {
151 return;
152 }
153 fDrawTarget->clear(rect, color, canIgnoreRect, renderTarget);
154}
155
156
157void GrDrawContext::drawPaint(GrRenderTarget* rt,
158 const GrClip& clip,
159 const GrPaint& origPaint,
160 const SkMatrix& viewMatrix) {
161 RETURN_IF_ABANDONED
162 // set rect to be big enough to fill the space, but not super-huge, so we
163 // don't overflow fixed-point implementations
164 SkRect r;
165 r.setLTRB(0, 0,
166 SkIntToScalar(rt->width()),
167 SkIntToScalar(rt->height()));
168 SkTCopyOnFirstWrite<GrPaint> paint(origPaint);
169
170 // by definition this fills the entire clip, no need for AA
171 if (paint->isAntiAlias()) {
172 paint.writable()->setAntiAlias(false);
173 }
174
175 bool isPerspective = viewMatrix.hasPerspective();
176
177 // We attempt to map r by the inverse matrix and draw that. mapRect will
178 // map the four corners and bound them with a new rect. This will not
179 // produce a correct result for some perspective matrices.
180 if (!isPerspective) {
181 SkMatrix inverse;
182 if (!viewMatrix.invert(&inverse)) {
183 SkDebugf("Could not invert matrix\n");
184 return;
185 }
186 inverse.mapRect(&r);
187 this->drawRect(rt, clip, *paint, viewMatrix, r);
188 } else {
189 SkMatrix localMatrix;
190 if (!viewMatrix.invert(&localMatrix)) {
191 SkDebugf("Could not invert matrix\n");
192 return;
193 }
194
195 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700196 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700197 return;
198 }
199
joshualitt7b670db2015-07-09 13:25:02 -0700200 GrPipelineBuilder pipelineBuilder(*paint, rt, clip);
joshualitt1c735482015-07-13 08:08:25 -0700201 fDrawTarget->drawBWRect(pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700202 paint->getColor(),
203 SkMatrix::I(),
204 r,
205 NULL,
206 &localMatrix);
207 }
208}
209
210static inline bool is_irect(const SkRect& r) {
211 return SkScalarIsInt(r.fLeft) && SkScalarIsInt(r.fTop) &&
212 SkScalarIsInt(r.fRight) && SkScalarIsInt(r.fBottom);
213}
214
215static bool apply_aa_to_rect(GrDrawTarget* target,
216 GrPipelineBuilder* pipelineBuilder,
217 SkRect* devBoundRect,
218 const SkRect& rect,
219 SkScalar strokeWidth,
220 const SkMatrix& combinedMatrix,
221 GrColor color) {
robertphillipsd8aa59d2015-08-05 09:07:12 -0700222 if (pipelineBuilder->getRenderTarget()->isUnifiedMultisampled() ||
223 !combinedMatrix.preservesAxisAlignment()) {
robertphillipsea461502015-05-26 11:38:03 -0700224 return false;
225 }
226
robertphillipsea461502015-05-26 11:38:03 -0700227 combinedMatrix.mapRect(devBoundRect, rect);
228 if (!combinedMatrix.rectStaysRect()) {
229 return true;
230 }
231
232 if (strokeWidth < 0) {
233 return !is_irect(*devBoundRect);
234 }
235
236 return true;
237}
238
239static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) {
240 return point.fX >= rect.fLeft && point.fX <= rect.fRight &&
241 point.fY >= rect.fTop && point.fY <= rect.fBottom;
242}
243
robertphillipsea461502015-05-26 11:38:03 -0700244void GrDrawContext::drawRect(GrRenderTarget* rt,
245 const GrClip& clip,
246 const GrPaint& paint,
247 const SkMatrix& viewMatrix,
248 const SkRect& rect,
249 const GrStrokeInfo* strokeInfo) {
250 RETURN_IF_ABANDONED
251 if (strokeInfo && strokeInfo->isDashed()) {
252 SkPath path;
253 path.setIsVolatile(true);
254 path.addRect(rect);
255 this->drawPath(rt, clip, paint, viewMatrix, path, *strokeInfo);
256 return;
257 }
258
259 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700260 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700261 return;
262 }
263
joshualitt7b670db2015-07-09 13:25:02 -0700264 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
265
robertphillipsea461502015-05-26 11:38:03 -0700266 SkScalar width = NULL == strokeInfo ? -1 : strokeInfo->getWidth();
267
268 // Check if this is a full RT draw and can be replaced with a clear. We don't bother checking
269 // cases where the RT is fully inside a stroke.
270 if (width < 0) {
271 SkRect rtRect;
272 pipelineBuilder.getRenderTarget()->getBoundsRect(&rtRect);
273 SkRect clipSpaceRTRect = rtRect;
274 bool checkClip = GrClip::kWideOpen_ClipType != clip.clipType();
275 if (checkClip) {
276 clipSpaceRTRect.offset(SkIntToScalar(clip.origin().fX),
277 SkIntToScalar(clip.origin().fY));
278 }
279 // Does the clip contain the entire RT?
280 if (!checkClip || clip.quickContains(clipSpaceRTRect)) {
281 SkMatrix invM;
282 if (!viewMatrix.invert(&invM)) {
283 return;
284 }
285 // Does the rect bound the RT?
286 SkPoint srcSpaceRTQuad[4];
287 invM.mapRectToQuad(srcSpaceRTQuad, rtRect);
288 if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) &&
289 rect_contains_inclusive(rect, srcSpaceRTQuad[1]) &&
290 rect_contains_inclusive(rect, srcSpaceRTQuad[2]) &&
291 rect_contains_inclusive(rect, srcSpaceRTQuad[3])) {
292 // Will it blend?
293 GrColor clearColor;
cdalton1fa45722015-06-02 10:43:39 -0700294 if (paint.isConstantBlendedColor(&clearColor)) {
robertphillipsea461502015-05-26 11:38:03 -0700295 fDrawTarget->clear(NULL, clearColor, true, rt);
296 return;
297 }
298 }
299 }
300 }
301
302 GrColor color = paint.getColor();
303 SkRect devBoundRect;
vbuzinovdded6962015-06-12 08:59:45 -0700304 bool needAA = paint.isAntiAlias() &&
305 !pipelineBuilder.getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -0700306 bool doAA = needAA && apply_aa_to_rect(fDrawTarget, &pipelineBuilder, &devBoundRect, rect,
307 width, viewMatrix, color);
308
309 if (doAA) {
joshualitt14205b12015-08-10 11:40:56 -0700310 SkAutoTUnref<GrBatch> batch;
robertphillipsea461502015-05-26 11:38:03 -0700311 if (width >= 0) {
joshualitt14205b12015-08-10 11:40:56 -0700312 batch.reset(GrRectBatchFactory::CreateStrokeAA(color, viewMatrix, rect, devBoundRect,
313 *strokeInfo));
robertphillipsea461502015-05-26 11:38:03 -0700314 } else {
joshualitt14205b12015-08-10 11:40:56 -0700315 batch.reset(GrRectBatchFactory::CreateFillAA(color, viewMatrix, rect, devBoundRect));
robertphillipsea461502015-05-26 11:38:03 -0700316 }
joshualitt14205b12015-08-10 11:40:56 -0700317 fDrawTarget->drawBatch(pipelineBuilder, batch);
robertphillipsea461502015-05-26 11:38:03 -0700318 return;
319 }
320
321 if (width >= 0) {
robertphillipsea461502015-05-26 11:38:03 -0700322 // Non-AA hairlines are snapped to pixel centers to make which pixels are hit deterministic
vbuzinovdded6962015-06-12 08:59:45 -0700323 bool snapToPixelCenters = (0 == width && !rt->isUnifiedMultisampled());
joshualitt7fc2a262015-08-10 10:30:14 -0700324 SkAutoTUnref<GrBatch> batch(GrRectBatchFactory::CreateStrokeBW(color, viewMatrix, rect,
325 width, snapToPixelCenters));
robertphillipsea461502015-05-26 11:38:03 -0700326
327 // Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of
328 // hairline rects. We jam all the vertices to pixel centers to avoid this, but not when MSAA
329 // is enabled because it can cause ugly artifacts.
330 pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_Flag,
331 snapToPixelCenters);
joshualitt1c735482015-07-13 08:08:25 -0700332 fDrawTarget->drawBatch(pipelineBuilder, batch);
robertphillipsea461502015-05-26 11:38:03 -0700333 } else {
334 // filled BW rect
joshualitt1c735482015-07-13 08:08:25 -0700335 fDrawTarget->drawSimpleRect(pipelineBuilder, color, viewMatrix, rect);
robertphillipsea461502015-05-26 11:38:03 -0700336 }
337}
338
339void GrDrawContext::drawNonAARectToRect(GrRenderTarget* rt,
340 const GrClip& clip,
341 const GrPaint& paint,
342 const SkMatrix& viewMatrix,
343 const SkRect& rectToDraw,
344 const SkRect& localRect,
345 const SkMatrix* localMatrix) {
346 RETURN_IF_ABANDONED
347 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700348 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700349 return;
350 }
351
joshualitt7b670db2015-07-09 13:25:02 -0700352 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
joshualitt1c735482015-07-13 08:08:25 -0700353 fDrawTarget->drawBWRect(pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700354 paint.getColor(),
355 viewMatrix,
356 rectToDraw,
357 &localRect,
358 localMatrix);
359}
360
robertphillipsea461502015-05-26 11:38:03 -0700361void GrDrawContext::drawVertices(GrRenderTarget* rt,
362 const GrClip& clip,
363 const GrPaint& paint,
364 const SkMatrix& viewMatrix,
365 GrPrimitiveType primitiveType,
366 int vertexCount,
367 const SkPoint positions[],
368 const SkPoint texCoords[],
369 const GrColor colors[],
370 const uint16_t indices[],
371 int indexCount) {
372 RETURN_IF_ABANDONED
373 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700374 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700375 return;
376 }
377
joshualitt7b670db2015-07-09 13:25:02 -0700378 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
379
robertphillipsea461502015-05-26 11:38:03 -0700380 // TODO clients should give us bounds
381 SkRect bounds;
382 if (!bounds.setBoundsCheck(positions, vertexCount)) {
383 SkDebugf("drawVertices call empty bounds\n");
384 return;
385 }
386
387 viewMatrix.mapRect(&bounds);
388
389 // If we don't have AA then we outset for a half pixel in each direction to account for
390 // snapping
391 if (!paint.isAntiAlias()) {
392 bounds.outset(0.5f, 0.5f);
393 }
394
joshualitt2771b562015-08-07 12:46:26 -0700395 GrDrawVerticesBatch::Geometry geometry;
robertphillipsea461502015-05-26 11:38:03 -0700396 geometry.fColor = paint.getColor();
joshualitt2771b562015-08-07 12:46:26 -0700397 SkAutoTUnref<GrBatch> batch(GrDrawVerticesBatch::Create(geometry, primitiveType, viewMatrix,
398 positions, vertexCount, indices,
399 indexCount, colors, texCoords,
400 bounds));
robertphillipsea461502015-05-26 11:38:03 -0700401
joshualitt1c735482015-07-13 08:08:25 -0700402 fDrawTarget->drawBatch(pipelineBuilder, batch);
robertphillipsea461502015-05-26 11:38:03 -0700403}
404
405///////////////////////////////////////////////////////////////////////////////
406
jvanverth31ff7622015-08-07 10:09:28 -0700407void GrDrawContext::drawAtlas(GrRenderTarget* rt,
408 const GrClip& clip,
409 const GrPaint& paint,
410 const SkMatrix& viewMatrix,
411 int spriteCount,
412 const SkRSXform xform[],
413 const SkRect texRect[],
414 const SkColor colors[]) {
415 RETURN_IF_ABANDONED
416 AutoCheckFlush acf(fContext);
417 if (!this->prepareToDraw(rt)) {
418 return;
419 }
420
421 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
422
423 // now build the renderable geometry
424 const int vertCount = spriteCount * 4;
425 SkAutoTMalloc<SkPoint> vertStorage(vertCount * 2);
426 SkPoint* verts = vertStorage.get();
427 SkPoint* texs = verts + vertCount;
428
429 for (int i = 0; i < spriteCount; ++i) {
430 xform[i].toQuad(texRect[i].width(), texRect[i].height(), verts);
431 texRect[i].toQuad(texs);
432 verts += 4;
433 texs += 4;
434 }
435
436 // TODO clients should give us bounds
437 SkRect bounds;
438 if (!bounds.setBoundsCheck(vertStorage.get(), vertCount)) {
439 SkDebugf("drawAtlas call empty bounds\n");
440 return;
441 }
442
443 viewMatrix.mapRect(&bounds);
444
445 // If we don't have AA then we outset for a half pixel in each direction to account for
446 // snapping
447 if (!paint.isAntiAlias()) {
448 bounds.outset(0.5f, 0.5f);
449 }
450
451 SkAutoTMalloc<GrColor> colorStorage;
452 GrColor* vertCols = NULL;
453 if (colors) {
454 colorStorage.reset(vertCount);
455 vertCols = colorStorage.get();
456
457 int paintAlpha = GrColorUnpackA(paint.getColor());
458
459 // need to convert byte order and from non-PM to PM
460 for (int i = 0; i < spriteCount; ++i) {
461 SkColor color = colors[i];
462 if (paintAlpha != 255) {
463 color = SkColorSetA(color, SkMulDiv255Round(SkColorGetA(color), paintAlpha));
464 }
465 GrColor grColor = SkColor2GrColor(color);
466
467 vertCols[0] = vertCols[1] = vertCols[2] = vertCols[3] = grColor;
468 vertCols += 4;
469 }
470 }
471
472 verts = vertStorage.get();
473 texs = verts + vertCount;
474 vertCols = colorStorage.get();
475
jvanverth14b88032015-08-07 12:18:54 -0700476 GrDrawAtlasBatch::Geometry geometry;
jvanverth31ff7622015-08-07 10:09:28 -0700477 geometry.fColor = paint.getColor();
jvanverth14b88032015-08-07 12:18:54 -0700478 SkAutoTUnref<GrBatch> batch(GrDrawAtlasBatch::Create(geometry, viewMatrix, verts, vertCount,
479 vertCols, texs, bounds));
jvanverth31ff7622015-08-07 10:09:28 -0700480
481 fDrawTarget->drawBatch(pipelineBuilder, batch);
482}
483
484///////////////////////////////////////////////////////////////////////////////
485
robertphillipsea461502015-05-26 11:38:03 -0700486void GrDrawContext::drawRRect(GrRenderTarget*rt,
487 const GrClip& clip,
488 const GrPaint& paint,
489 const SkMatrix& viewMatrix,
490 const SkRRect& rrect,
491 const GrStrokeInfo& strokeInfo) {
492 RETURN_IF_ABANDONED
493 if (rrect.isEmpty()) {
494 return;
495 }
496
497 if (strokeInfo.isDashed()) {
498 SkPath path;
499 path.setIsVolatile(true);
500 path.addRRect(rrect);
501 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
502 return;
503 }
504
505 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700506 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700507 return;
508 }
509
joshualitt7b670db2015-07-09 13:25:02 -0700510 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700511 GrColor color = paint.getColor();
512 if (!GrOvalRenderer::DrawRRect(fDrawTarget,
joshualittae3d63a2015-07-13 08:44:06 -0700513 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700514 color,
515 viewMatrix,
516 paint.isAntiAlias(),
517 rrect,
518 strokeInfo)) {
519 SkPath path;
520 path.setIsVolatile(true);
521 path.addRRect(rrect);
522 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
523 paint.isAntiAlias(), path, strokeInfo);
524 }
525}
526
527///////////////////////////////////////////////////////////////////////////////
528
529void GrDrawContext::drawDRRect(GrRenderTarget* rt,
530 const GrClip& clip,
531 const GrPaint& paint,
532 const SkMatrix& viewMatrix,
533 const SkRRect& outer,
534 const SkRRect& inner) {
535 RETURN_IF_ABANDONED
536 if (outer.isEmpty()) {
537 return;
538 }
539
540 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700541 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700542 return;
543 }
544
joshualitt7b670db2015-07-09 13:25:02 -0700545 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700546 GrColor color = paint.getColor();
547 if (!GrOvalRenderer::DrawDRRect(fDrawTarget,
joshualittae3d63a2015-07-13 08:44:06 -0700548 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700549 color,
550 viewMatrix,
551 paint.isAntiAlias(),
552 outer,
553 inner)) {
554 SkPath path;
555 path.setIsVolatile(true);
556 path.addRRect(inner);
557 path.addRRect(outer);
558 path.setFillType(SkPath::kEvenOdd_FillType);
559
560 GrStrokeInfo fillRec(SkStrokeRec::kFill_InitStyle);
561 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
562 paint.isAntiAlias(), path, fillRec);
563 }
564}
565
566///////////////////////////////////////////////////////////////////////////////
567
568void GrDrawContext::drawOval(GrRenderTarget* rt,
569 const GrClip& clip,
570 const GrPaint& paint,
571 const SkMatrix& viewMatrix,
572 const SkRect& oval,
573 const GrStrokeInfo& strokeInfo) {
574 RETURN_IF_ABANDONED
575 if (oval.isEmpty()) {
576 return;
577 }
578
579 if (strokeInfo.isDashed()) {
580 SkPath path;
581 path.setIsVolatile(true);
582 path.addOval(oval);
583 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
584 return;
585 }
586
587 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700588 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700589 return;
590 }
591
joshualitt7b670db2015-07-09 13:25:02 -0700592 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700593 GrColor color = paint.getColor();
594 if (!GrOvalRenderer::DrawOval(fDrawTarget,
joshualittae3d63a2015-07-13 08:44:06 -0700595 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700596 color,
597 viewMatrix,
598 paint.isAntiAlias(),
599 oval,
600 strokeInfo)) {
601 SkPath path;
602 path.setIsVolatile(true);
603 path.addOval(oval);
604 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
605 paint.isAntiAlias(), path, strokeInfo);
606 }
607}
608
609// Can 'path' be drawn as a pair of filled nested rectangles?
joshualittf9c5db22015-07-10 11:31:01 -0700610static bool is_nested_rects(const SkMatrix& viewMatrix,
robertphillipsea461502015-05-26 11:38:03 -0700611 const SkPath& path,
612 const SkStrokeRec& stroke,
613 SkRect rects[2]) {
614 SkASSERT(stroke.isFillStyle());
615
616 if (path.isInverseFillType()) {
617 return false;
618 }
619
620 // TODO: this restriction could be lifted if we were willing to apply
621 // the matrix to all the points individually rather than just to the rect
622 if (!viewMatrix.preservesAxisAlignment()) {
623 return false;
624 }
625
626 SkPath::Direction dirs[2];
627 if (!path.isNestedFillRects(rects, dirs)) {
628 return false;
629 }
630
631 if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) {
632 // The two rects need to be wound opposite to each other
633 return false;
634 }
635
636 // Right now, nested rects where the margin is not the same width
637 // all around do not render correctly
638 const SkScalar* outer = rects[0].asScalars();
639 const SkScalar* inner = rects[1].asScalars();
640
641 bool allEq = true;
642
643 SkScalar margin = SkScalarAbs(outer[0] - inner[0]);
644 bool allGoE1 = margin >= SK_Scalar1;
645
646 for (int i = 1; i < 4; ++i) {
647 SkScalar temp = SkScalarAbs(outer[i] - inner[i]);
648 if (temp < SK_Scalar1) {
649 allGoE1 = false;
650 }
651 if (!SkScalarNearlyEqual(margin, temp)) {
652 allEq = false;
653 }
654 }
655
656 return allEq || allGoE1;
657}
658
659void GrDrawContext::drawPath(GrRenderTarget* rt,
660 const GrClip& clip,
661 const GrPaint& paint,
662 const SkMatrix& viewMatrix,
663 const SkPath& path,
664 const GrStrokeInfo& strokeInfo) {
665 RETURN_IF_ABANDONED
666 if (path.isEmpty()) {
667 if (path.isInverseFillType()) {
668 this->drawPaint(rt, clip, paint, viewMatrix);
669 }
670 return;
671 }
672
673 GrColor color = paint.getColor();
674
675 // Note that internalDrawPath may sw-rasterize the path into a scratch texture.
676 // Scratch textures can be recycled after they are returned to the texture
677 // cache. This presents a potential hazard for buffered drawing. However,
678 // the writePixels that uploads to the scratch will perform a flush so we're
679 // OK.
680 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700681 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700682 return;
683 }
684
joshualitt7b670db2015-07-09 13:25:02 -0700685 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700686 if (!strokeInfo.isDashed()) {
687 bool useCoverageAA = paint.isAntiAlias() &&
vbuzinovdded6962015-06-12 08:59:45 -0700688 !pipelineBuilder.getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -0700689
690 if (useCoverageAA && strokeInfo.getWidth() < 0 && !path.isConvex()) {
691 // Concave AA paths are expensive - try to avoid them for special cases
692 SkRect rects[2];
693
joshualittf9c5db22015-07-10 11:31:01 -0700694 if (is_nested_rects(viewMatrix, path, strokeInfo, rects)) {
joshualitt14205b12015-08-10 11:40:56 -0700695 SkAutoTUnref<GrBatch> batch(GrRectBatchFactory::CreateFillNestedRectsAA(color,
696 viewMatrix,
697 rects));
698 fDrawTarget->drawBatch(pipelineBuilder, batch);
robertphillipsea461502015-05-26 11:38:03 -0700699 return;
700 }
701 }
702 SkRect ovalRect;
703 bool isOval = path.isOval(&ovalRect);
704
705 if (isOval && !path.isInverseFillType()) {
706 if (GrOvalRenderer::DrawOval(fDrawTarget,
joshualittae3d63a2015-07-13 08:44:06 -0700707 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700708 color,
709 viewMatrix,
710 paint.isAntiAlias(),
711 ovalRect,
712 strokeInfo)) {
713 return;
714 }
715 }
716 }
717 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
718 path, strokeInfo);
719}
720
721void GrDrawContext::internalDrawPath(GrDrawTarget* target,
722 GrPipelineBuilder* pipelineBuilder,
723 const SkMatrix& viewMatrix,
724 GrColor color,
725 bool useAA,
726 const SkPath& path,
727 const GrStrokeInfo& strokeInfo) {
728 RETURN_IF_ABANDONED
729 SkASSERT(!path.isEmpty());
730
731
732 // An Assumption here is that path renderer would use some form of tweaking
733 // the src color (either the input alpha or in the frag shader) to implement
734 // aa. If we have some future driver-mojo path AA that can do the right
735 // thing WRT to the blend then we'll need some query on the PR.
736 bool useCoverageAA = useAA &&
vbuzinovdded6962015-06-12 08:59:45 -0700737 !pipelineBuilder->getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -0700738
739
740 GrPathRendererChain::DrawType type =
741 useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType :
742 GrPathRendererChain::kColor_DrawType;
743
744 const SkPath* pathPtr = &path;
745 SkTLazy<SkPath> tmpPath;
746 const GrStrokeInfo* strokeInfoPtr = &strokeInfo;
747
748 // Try a 1st time without stroking the path and without allowing the SW renderer
749 GrPathRenderer* pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr,
750 *strokeInfoPtr, false, type);
751
752 GrStrokeInfo dashlessStrokeInfo(strokeInfo, false);
753 if (NULL == pr && strokeInfo.isDashed()) {
754 // It didn't work above, so try again with dashed stroke converted to a dashless stroke.
755 if (!strokeInfo.applyDashToPath(tmpPath.init(), &dashlessStrokeInfo, *pathPtr)) {
756 return;
757 }
758 pathPtr = tmpPath.get();
759 if (pathPtr->isEmpty()) {
760 return;
761 }
762 strokeInfoPtr = &dashlessStrokeInfo;
763 pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
764 false, type);
765 }
766
767 if (NULL == pr) {
768 if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*strokeInfoPtr, viewMatrix, NULL) &&
769 !strokeInfoPtr->isFillStyle()) {
770 // It didn't work above, so try again with stroke converted to a fill.
771 if (!tmpPath.isValid()) {
772 tmpPath.init();
773 }
774 dashlessStrokeInfo.setResScale(SkScalarAbs(viewMatrix.getMaxScale()));
775 if (!dashlessStrokeInfo.applyToPath(tmpPath.get(), *pathPtr)) {
776 return;
777 }
778 pathPtr = tmpPath.get();
779 if (pathPtr->isEmpty()) {
780 return;
781 }
782 dashlessStrokeInfo.setFillStyle();
783 strokeInfoPtr = &dashlessStrokeInfo;
784 }
785
786 // This time, allow SW renderer
787 pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
788 true, type);
789 }
790
791 if (NULL == pr) {
792#ifdef SK_DEBUG
793 SkDebugf("Unable to find path renderer compatible with path.\n");
794#endif
795 return;
796 }
797
bsalomon0aff2fa2015-07-31 06:48:27 -0700798 GrPathRenderer::DrawPathArgs args;
799 args.fTarget = target;
800 args.fResourceProvider = fContext->resourceProvider();
801 args.fPipelineBuilder = pipelineBuilder;
802 args.fColor = color;
803 args.fViewMatrix = &viewMatrix;
804 args.fPath = pathPtr;
805 args.fStroke = strokeInfoPtr;
806 args.fAntiAlias = useCoverageAA;
807 pr->drawPath(args);
robertphillipsea461502015-05-26 11:38:03 -0700808}
809
robertphillipsea461502015-05-26 11:38:03 -0700810bool GrDrawContext::prepareToDraw(GrRenderTarget* rt) {
811 RETURN_FALSE_IF_ABANDONED
812
813 ASSERT_OWNED_RESOURCE(rt);
814 SkASSERT(rt);
815 return true;
816}
817
robertphillips2334fb62015-06-17 05:43:33 -0700818void GrDrawContext::drawBatch(GrPipelineBuilder* pipelineBuilder, GrBatch* batch) {
joshualitt1c735482015-07-13 08:08:25 -0700819 fDrawTarget->drawBatch(*pipelineBuilder, batch);
robertphillips2334fb62015-06-17 05:43:33 -0700820}