blob: c67f6f48bff07d0057921eccf9dfbe51e6781253 [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
9#include "GrAARectRenderer.h"
robertphillips2334fb62015-06-17 05:43:33 -070010#include "GrAtlasTextContext.h"
robertphillipsea461502015-05-26 11:38:03 -070011#include "GrBatchTest.h"
jvanverth31ff7622015-08-07 10:09:28 -070012#include "GrColor.h"
robertphillipsea461502015-05-26 11:38:03 -070013#include "GrDrawContext.h"
14#include "GrOvalRenderer.h"
15#include "GrPathRenderer.h"
robertphillips2334fb62015-06-17 05:43:33 -070016#include "GrRenderTarget.h"
17#include "GrRenderTargetPriv.h"
18#include "GrStencilAndCoverTextContext.h"
robertphillipsea461502015-05-26 11:38:03 -070019
joshualitt74417822015-08-07 11:42:16 -070020#include "batches/GrBatch.h"
jvanverth14b88032015-08-07 12:18:54 -070021#include "batches/GrDrawAtlasBatch.h"
joshualitt2771b562015-08-07 12:46:26 -070022#include "batches/GrDrawVerticesBatch.h"
joshualitt74417822015-08-07 11:42:16 -070023#include "batches/GrStrokeRectBatch.h"
24
jvanverth31ff7622015-08-07 10:09:28 -070025#include "SkGr.h"
26#include "SkRSXform.h"
27
robertphillipsea461502015-05-26 11:38:03 -070028#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == fContext)
29#define RETURN_IF_ABANDONED if (!fDrawTarget) { return; }
30#define RETURN_FALSE_IF_ABANDONED if (!fDrawTarget) { return false; }
31#define RETURN_NULL_IF_ABANDONED if (!fDrawTarget) { return NULL; }
32
33class AutoCheckFlush {
34public:
35 AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context); }
36 ~AutoCheckFlush() { fContext->flushIfNecessary(); }
37
38private:
39 GrContext* fContext;
40};
41
robertphillips2334fb62015-06-17 05:43:33 -070042GrDrawContext::GrDrawContext(GrContext* context,
43 GrDrawTarget* drawTarget,
robertphillipsfcf78292015-06-19 11:49:52 -070044 const SkSurfaceProps& surfaceProps)
robertphillipsea461502015-05-26 11:38:03 -070045 : fContext(context)
robertphillips2334fb62015-06-17 05:43:33 -070046 , fDrawTarget(SkRef(drawTarget))
47 , fTextContext(NULL)
robertphillipsfcf78292015-06-19 11:49:52 -070048 , fSurfaceProps(surfaceProps) {
robertphillipsea461502015-05-26 11:38:03 -070049}
50
robertphillips4b195e52015-05-26 14:37:00 -070051GrDrawContext::~GrDrawContext() {
52 SkSafeUnref(fDrawTarget);
robertphillips2334fb62015-06-17 05:43:33 -070053 SkDELETE(fTextContext);
robertphillips4b195e52015-05-26 14:37:00 -070054}
55
robertphillipsea461502015-05-26 11:38:03 -070056void GrDrawContext::copySurface(GrRenderTarget* dst, GrSurface* src,
57 const SkIRect& srcRect, const SkIPoint& dstPoint) {
58 if (!this->prepareToDraw(dst)) {
59 return;
60 }
61
62 fDrawTarget->copySurface(dst, src, srcRect, dstPoint);
63}
64
robertphillips2334fb62015-06-17 05:43:33 -070065GrTextContext* GrDrawContext::createTextContext(GrRenderTarget* renderTarget,
robertphillipsfcf78292015-06-19 11:49:52 -070066 const SkSurfaceProps& surfaceProps) {
robertphillips2334fb62015-06-17 05:43:33 -070067 if (fContext->caps()->shaderCaps()->pathRenderingSupport() &&
cdaltone04edd82015-06-29 14:15:19 -070068 renderTarget->isStencilBufferMultisampled() &&
69 fSurfaceProps.isUseDistanceFieldFonts()) { // FIXME: Rename the dff flag to be more general.
robertphillips2334fb62015-06-17 05:43:33 -070070 GrStencilAttachment* sb = renderTarget->renderTargetPriv().attachStencilAttachment();
71 if (sb) {
robertphillipsfcf78292015-06-19 11:49:52 -070072 return GrStencilAndCoverTextContext::Create(fContext, this, surfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -070073 }
74 }
75
robertphillipsfcf78292015-06-19 11:49:52 -070076 return GrAtlasTextContext::Create(fContext, this, surfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -070077}
78
79void GrDrawContext::drawText(GrRenderTarget* rt, const GrClip& clip, const GrPaint& grPaint,
80 const SkPaint& skPaint,
81 const SkMatrix& viewMatrix,
82 const char text[], size_t byteLength,
83 SkScalar x, SkScalar y, const SkIRect& clipBounds) {
84 if (!fTextContext) {
robertphillipsfcf78292015-06-19 11:49:52 -070085 fTextContext = this->createTextContext(rt, fSurfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -070086 }
87
88 fTextContext->drawText(rt, clip, grPaint, skPaint, viewMatrix,
89 text, byteLength, x, y, clipBounds);
90
91}
92void GrDrawContext::drawPosText(GrRenderTarget* rt, const GrClip& clip, const GrPaint& grPaint,
93 const SkPaint& skPaint,
94 const SkMatrix& viewMatrix,
95 const char text[], size_t byteLength,
96 const SkScalar pos[], int scalarsPerPosition,
97 const SkPoint& offset, const SkIRect& clipBounds) {
98 if (!fTextContext) {
robertphillipsfcf78292015-06-19 11:49:52 -070099 fTextContext = this->createTextContext(rt, fSurfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -0700100 }
101
102 fTextContext->drawPosText(rt, clip, grPaint, skPaint, viewMatrix, text, byteLength,
103 pos, scalarsPerPosition, offset, clipBounds);
104
105}
106void GrDrawContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, const SkPaint& skPaint,
107 const SkMatrix& viewMatrix, const SkTextBlob* blob,
108 SkScalar x, SkScalar y,
109 SkDrawFilter* filter, const SkIRect& clipBounds) {
110 if (!fTextContext) {
robertphillipsfcf78292015-06-19 11:49:52 -0700111 fTextContext = this->createTextContext(rt, fSurfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -0700112 }
113
114 fTextContext->drawTextBlob(rt, clip, skPaint, viewMatrix, blob, x, y, filter, clipBounds);
robertphillipsea461502015-05-26 11:38:03 -0700115}
116
117void GrDrawContext::drawPaths(GrPipelineBuilder* pipelineBuilder,
118 const GrPathProcessor* pathProc,
119 const GrPathRange* pathRange,
120 const void* indices,
121 int /*GrDrawTarget::PathIndexType*/ indexType,
122 const float transformValues[],
123 int /*GrDrawTarget::PathTransformType*/ transformType,
124 int count,
125 int /*GrPathRendering::FillType*/ fill) {
joshualitt1c735482015-07-13 08:08:25 -0700126 fDrawTarget->drawPaths(*pipelineBuilder, pathProc, pathRange,
robertphillipsea461502015-05-26 11:38:03 -0700127 indices, (GrDrawTarget::PathIndexType) indexType,
128 transformValues,
129 (GrDrawTarget::PathTransformType) transformType,
130 count, (GrPathRendering::FillType) fill);
131}
132
133void GrDrawContext::discard(GrRenderTarget* renderTarget) {
134 RETURN_IF_ABANDONED
135 SkASSERT(renderTarget);
136 AutoCheckFlush acf(fContext);
137 if (!this->prepareToDraw(renderTarget)) {
138 return;
139 }
140 fDrawTarget->discard(renderTarget);
141}
142
143void GrDrawContext::clear(GrRenderTarget* renderTarget,
144 const SkIRect* rect,
145 const GrColor color,
146 bool canIgnoreRect) {
147 RETURN_IF_ABANDONED
148 SkASSERT(renderTarget);
149
150 AutoCheckFlush acf(fContext);
151 if (!this->prepareToDraw(renderTarget)) {
152 return;
153 }
154 fDrawTarget->clear(rect, color, canIgnoreRect, renderTarget);
155}
156
157
158void GrDrawContext::drawPaint(GrRenderTarget* rt,
159 const GrClip& clip,
160 const GrPaint& origPaint,
161 const SkMatrix& viewMatrix) {
162 RETURN_IF_ABANDONED
163 // set rect to be big enough to fill the space, but not super-huge, so we
164 // don't overflow fixed-point implementations
165 SkRect r;
166 r.setLTRB(0, 0,
167 SkIntToScalar(rt->width()),
168 SkIntToScalar(rt->height()));
169 SkTCopyOnFirstWrite<GrPaint> paint(origPaint);
170
171 // by definition this fills the entire clip, no need for AA
172 if (paint->isAntiAlias()) {
173 paint.writable()->setAntiAlias(false);
174 }
175
176 bool isPerspective = viewMatrix.hasPerspective();
177
178 // We attempt to map r by the inverse matrix and draw that. mapRect will
179 // map the four corners and bound them with a new rect. This will not
180 // produce a correct result for some perspective matrices.
181 if (!isPerspective) {
182 SkMatrix inverse;
183 if (!viewMatrix.invert(&inverse)) {
184 SkDebugf("Could not invert matrix\n");
185 return;
186 }
187 inverse.mapRect(&r);
188 this->drawRect(rt, clip, *paint, viewMatrix, r);
189 } else {
190 SkMatrix localMatrix;
191 if (!viewMatrix.invert(&localMatrix)) {
192 SkDebugf("Could not invert matrix\n");
193 return;
194 }
195
196 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700197 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700198 return;
199 }
200
joshualitt7b670db2015-07-09 13:25:02 -0700201 GrPipelineBuilder pipelineBuilder(*paint, rt, clip);
joshualitt1c735482015-07-13 08:08:25 -0700202 fDrawTarget->drawBWRect(pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700203 paint->getColor(),
204 SkMatrix::I(),
205 r,
206 NULL,
207 &localMatrix);
208 }
209}
210
211static inline bool is_irect(const SkRect& r) {
212 return SkScalarIsInt(r.fLeft) && SkScalarIsInt(r.fTop) &&
213 SkScalarIsInt(r.fRight) && SkScalarIsInt(r.fBottom);
214}
215
216static bool apply_aa_to_rect(GrDrawTarget* target,
217 GrPipelineBuilder* pipelineBuilder,
218 SkRect* devBoundRect,
219 const SkRect& rect,
220 SkScalar strokeWidth,
221 const SkMatrix& combinedMatrix,
222 GrColor color) {
robertphillipsd8aa59d2015-08-05 09:07:12 -0700223 if (pipelineBuilder->getRenderTarget()->isUnifiedMultisampled() ||
224 !combinedMatrix.preservesAxisAlignment()) {
robertphillipsea461502015-05-26 11:38:03 -0700225 return false;
226 }
227
robertphillipsea461502015-05-26 11:38:03 -0700228 combinedMatrix.mapRect(devBoundRect, rect);
229 if (!combinedMatrix.rectStaysRect()) {
230 return true;
231 }
232
233 if (strokeWidth < 0) {
234 return !is_irect(*devBoundRect);
235 }
236
237 return true;
238}
239
240static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) {
241 return point.fX >= rect.fLeft && point.fX <= rect.fRight &&
242 point.fY >= rect.fTop && point.fY <= rect.fBottom;
243}
244
robertphillipsea461502015-05-26 11:38:03 -0700245void GrDrawContext::drawRect(GrRenderTarget* rt,
246 const GrClip& clip,
247 const GrPaint& paint,
248 const SkMatrix& viewMatrix,
249 const SkRect& rect,
250 const GrStrokeInfo* strokeInfo) {
251 RETURN_IF_ABANDONED
252 if (strokeInfo && strokeInfo->isDashed()) {
253 SkPath path;
254 path.setIsVolatile(true);
255 path.addRect(rect);
256 this->drawPath(rt, clip, paint, viewMatrix, path, *strokeInfo);
257 return;
258 }
259
260 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700261 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700262 return;
263 }
264
joshualitt7b670db2015-07-09 13:25:02 -0700265 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
266
robertphillipsea461502015-05-26 11:38:03 -0700267 SkScalar width = NULL == strokeInfo ? -1 : strokeInfo->getWidth();
268
269 // Check if this is a full RT draw and can be replaced with a clear. We don't bother checking
270 // cases where the RT is fully inside a stroke.
271 if (width < 0) {
272 SkRect rtRect;
273 pipelineBuilder.getRenderTarget()->getBoundsRect(&rtRect);
274 SkRect clipSpaceRTRect = rtRect;
275 bool checkClip = GrClip::kWideOpen_ClipType != clip.clipType();
276 if (checkClip) {
277 clipSpaceRTRect.offset(SkIntToScalar(clip.origin().fX),
278 SkIntToScalar(clip.origin().fY));
279 }
280 // Does the clip contain the entire RT?
281 if (!checkClip || clip.quickContains(clipSpaceRTRect)) {
282 SkMatrix invM;
283 if (!viewMatrix.invert(&invM)) {
284 return;
285 }
286 // Does the rect bound the RT?
287 SkPoint srcSpaceRTQuad[4];
288 invM.mapRectToQuad(srcSpaceRTQuad, rtRect);
289 if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) &&
290 rect_contains_inclusive(rect, srcSpaceRTQuad[1]) &&
291 rect_contains_inclusive(rect, srcSpaceRTQuad[2]) &&
292 rect_contains_inclusive(rect, srcSpaceRTQuad[3])) {
293 // Will it blend?
294 GrColor clearColor;
cdalton1fa45722015-06-02 10:43:39 -0700295 if (paint.isConstantBlendedColor(&clearColor)) {
robertphillipsea461502015-05-26 11:38:03 -0700296 fDrawTarget->clear(NULL, clearColor, true, rt);
297 return;
298 }
299 }
300 }
301 }
302
303 GrColor color = paint.getColor();
304 SkRect devBoundRect;
vbuzinovdded6962015-06-12 08:59:45 -0700305 bool needAA = paint.isAntiAlias() &&
306 !pipelineBuilder.getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -0700307 bool doAA = needAA && apply_aa_to_rect(fDrawTarget, &pipelineBuilder, &devBoundRect, rect,
308 width, viewMatrix, color);
309
310 if (doAA) {
311 if (width >= 0) {
312 GrAARectRenderer::StrokeAARect(fDrawTarget,
joshualitt1c735482015-07-13 08:08:25 -0700313 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700314 color,
315 viewMatrix,
316 rect,
317 devBoundRect,
318 *strokeInfo);
319 } else {
320 // filled AA rect
321 GrAARectRenderer::FillAARect(fDrawTarget,
joshualitt1c735482015-07-13 08:08:25 -0700322 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700323 color,
324 viewMatrix,
325 rect,
326 devBoundRect);
327 }
328 return;
329 }
330
331 if (width >= 0) {
bsalomonee14a622015-08-05 10:34:05 -0700332 GrStrokeRectBatch::Geometry geometry;
robertphillipsea461502015-05-26 11:38:03 -0700333 geometry.fViewMatrix = viewMatrix;
334 geometry.fColor = color;
335 geometry.fRect = rect;
336 geometry.fStrokeWidth = width;
337
338 // Non-AA hairlines are snapped to pixel centers to make which pixels are hit deterministic
vbuzinovdded6962015-06-12 08:59:45 -0700339 bool snapToPixelCenters = (0 == width && !rt->isUnifiedMultisampled());
bsalomonee14a622015-08-05 10:34:05 -0700340 SkAutoTUnref<GrBatch> batch(GrStrokeRectBatch::Create(geometry, snapToPixelCenters));
robertphillipsea461502015-05-26 11:38:03 -0700341
342 // Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of
343 // hairline rects. We jam all the vertices to pixel centers to avoid this, but not when MSAA
344 // is enabled because it can cause ugly artifacts.
345 pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_Flag,
346 snapToPixelCenters);
joshualitt1c735482015-07-13 08:08:25 -0700347 fDrawTarget->drawBatch(pipelineBuilder, batch);
robertphillipsea461502015-05-26 11:38:03 -0700348 } else {
349 // filled BW rect
joshualitt1c735482015-07-13 08:08:25 -0700350 fDrawTarget->drawSimpleRect(pipelineBuilder, color, viewMatrix, rect);
robertphillipsea461502015-05-26 11:38:03 -0700351 }
352}
353
354void GrDrawContext::drawNonAARectToRect(GrRenderTarget* rt,
355 const GrClip& clip,
356 const GrPaint& paint,
357 const SkMatrix& viewMatrix,
358 const SkRect& rectToDraw,
359 const SkRect& localRect,
360 const SkMatrix* localMatrix) {
361 RETURN_IF_ABANDONED
362 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700363 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700364 return;
365 }
366
joshualitt7b670db2015-07-09 13:25:02 -0700367 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
joshualitt1c735482015-07-13 08:08:25 -0700368 fDrawTarget->drawBWRect(pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700369 paint.getColor(),
370 viewMatrix,
371 rectToDraw,
372 &localRect,
373 localMatrix);
374}
375
robertphillipsea461502015-05-26 11:38:03 -0700376void GrDrawContext::drawVertices(GrRenderTarget* rt,
377 const GrClip& clip,
378 const GrPaint& paint,
379 const SkMatrix& viewMatrix,
380 GrPrimitiveType primitiveType,
381 int vertexCount,
382 const SkPoint positions[],
383 const SkPoint texCoords[],
384 const GrColor colors[],
385 const uint16_t indices[],
386 int indexCount) {
387 RETURN_IF_ABANDONED
388 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700389 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700390 return;
391 }
392
joshualitt7b670db2015-07-09 13:25:02 -0700393 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
394
robertphillipsea461502015-05-26 11:38:03 -0700395 // TODO clients should give us bounds
396 SkRect bounds;
397 if (!bounds.setBoundsCheck(positions, vertexCount)) {
398 SkDebugf("drawVertices call empty bounds\n");
399 return;
400 }
401
402 viewMatrix.mapRect(&bounds);
403
404 // If we don't have AA then we outset for a half pixel in each direction to account for
405 // snapping
406 if (!paint.isAntiAlias()) {
407 bounds.outset(0.5f, 0.5f);
408 }
409
joshualitt2771b562015-08-07 12:46:26 -0700410 GrDrawVerticesBatch::Geometry geometry;
robertphillipsea461502015-05-26 11:38:03 -0700411 geometry.fColor = paint.getColor();
joshualitt2771b562015-08-07 12:46:26 -0700412 SkAutoTUnref<GrBatch> batch(GrDrawVerticesBatch::Create(geometry, primitiveType, viewMatrix,
413 positions, vertexCount, indices,
414 indexCount, colors, texCoords,
415 bounds));
robertphillipsea461502015-05-26 11:38:03 -0700416
joshualitt1c735482015-07-13 08:08:25 -0700417 fDrawTarget->drawBatch(pipelineBuilder, batch);
robertphillipsea461502015-05-26 11:38:03 -0700418}
419
420///////////////////////////////////////////////////////////////////////////////
421
jvanverth31ff7622015-08-07 10:09:28 -0700422void GrDrawContext::drawAtlas(GrRenderTarget* rt,
423 const GrClip& clip,
424 const GrPaint& paint,
425 const SkMatrix& viewMatrix,
426 int spriteCount,
427 const SkRSXform xform[],
428 const SkRect texRect[],
429 const SkColor colors[]) {
430 RETURN_IF_ABANDONED
431 AutoCheckFlush acf(fContext);
432 if (!this->prepareToDraw(rt)) {
433 return;
434 }
435
436 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
437
438 // now build the renderable geometry
439 const int vertCount = spriteCount * 4;
440 SkAutoTMalloc<SkPoint> vertStorage(vertCount * 2);
441 SkPoint* verts = vertStorage.get();
442 SkPoint* texs = verts + vertCount;
443
444 for (int i = 0; i < spriteCount; ++i) {
445 xform[i].toQuad(texRect[i].width(), texRect[i].height(), verts);
446 texRect[i].toQuad(texs);
447 verts += 4;
448 texs += 4;
449 }
450
451 // TODO clients should give us bounds
452 SkRect bounds;
453 if (!bounds.setBoundsCheck(vertStorage.get(), vertCount)) {
454 SkDebugf("drawAtlas call empty bounds\n");
455 return;
456 }
457
458 viewMatrix.mapRect(&bounds);
459
460 // If we don't have AA then we outset for a half pixel in each direction to account for
461 // snapping
462 if (!paint.isAntiAlias()) {
463 bounds.outset(0.5f, 0.5f);
464 }
465
466 SkAutoTMalloc<GrColor> colorStorage;
467 GrColor* vertCols = NULL;
468 if (colors) {
469 colorStorage.reset(vertCount);
470 vertCols = colorStorage.get();
471
472 int paintAlpha = GrColorUnpackA(paint.getColor());
473
474 // need to convert byte order and from non-PM to PM
475 for (int i = 0; i < spriteCount; ++i) {
476 SkColor color = colors[i];
477 if (paintAlpha != 255) {
478 color = SkColorSetA(color, SkMulDiv255Round(SkColorGetA(color), paintAlpha));
479 }
480 GrColor grColor = SkColor2GrColor(color);
481
482 vertCols[0] = vertCols[1] = vertCols[2] = vertCols[3] = grColor;
483 vertCols += 4;
484 }
485 }
486
487 verts = vertStorage.get();
488 texs = verts + vertCount;
489 vertCols = colorStorage.get();
490
jvanverth14b88032015-08-07 12:18:54 -0700491 GrDrawAtlasBatch::Geometry geometry;
jvanverth31ff7622015-08-07 10:09:28 -0700492 geometry.fColor = paint.getColor();
jvanverth14b88032015-08-07 12:18:54 -0700493 SkAutoTUnref<GrBatch> batch(GrDrawAtlasBatch::Create(geometry, viewMatrix, verts, vertCount,
494 vertCols, texs, bounds));
jvanverth31ff7622015-08-07 10:09:28 -0700495
496 fDrawTarget->drawBatch(pipelineBuilder, batch);
497}
498
499///////////////////////////////////////////////////////////////////////////////
500
robertphillipsea461502015-05-26 11:38:03 -0700501void GrDrawContext::drawRRect(GrRenderTarget*rt,
502 const GrClip& clip,
503 const GrPaint& paint,
504 const SkMatrix& viewMatrix,
505 const SkRRect& rrect,
506 const GrStrokeInfo& strokeInfo) {
507 RETURN_IF_ABANDONED
508 if (rrect.isEmpty()) {
509 return;
510 }
511
512 if (strokeInfo.isDashed()) {
513 SkPath path;
514 path.setIsVolatile(true);
515 path.addRRect(rrect);
516 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
517 return;
518 }
519
520 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700521 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700522 return;
523 }
524
joshualitt7b670db2015-07-09 13:25:02 -0700525 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700526 GrColor color = paint.getColor();
527 if (!GrOvalRenderer::DrawRRect(fDrawTarget,
joshualittae3d63a2015-07-13 08:44:06 -0700528 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700529 color,
530 viewMatrix,
531 paint.isAntiAlias(),
532 rrect,
533 strokeInfo)) {
534 SkPath path;
535 path.setIsVolatile(true);
536 path.addRRect(rrect);
537 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
538 paint.isAntiAlias(), path, strokeInfo);
539 }
540}
541
542///////////////////////////////////////////////////////////////////////////////
543
544void GrDrawContext::drawDRRect(GrRenderTarget* rt,
545 const GrClip& clip,
546 const GrPaint& paint,
547 const SkMatrix& viewMatrix,
548 const SkRRect& outer,
549 const SkRRect& inner) {
550 RETURN_IF_ABANDONED
551 if (outer.isEmpty()) {
552 return;
553 }
554
555 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700556 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700557 return;
558 }
559
joshualitt7b670db2015-07-09 13:25:02 -0700560 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700561 GrColor color = paint.getColor();
562 if (!GrOvalRenderer::DrawDRRect(fDrawTarget,
joshualittae3d63a2015-07-13 08:44:06 -0700563 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700564 color,
565 viewMatrix,
566 paint.isAntiAlias(),
567 outer,
568 inner)) {
569 SkPath path;
570 path.setIsVolatile(true);
571 path.addRRect(inner);
572 path.addRRect(outer);
573 path.setFillType(SkPath::kEvenOdd_FillType);
574
575 GrStrokeInfo fillRec(SkStrokeRec::kFill_InitStyle);
576 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
577 paint.isAntiAlias(), path, fillRec);
578 }
579}
580
581///////////////////////////////////////////////////////////////////////////////
582
583void GrDrawContext::drawOval(GrRenderTarget* rt,
584 const GrClip& clip,
585 const GrPaint& paint,
586 const SkMatrix& viewMatrix,
587 const SkRect& oval,
588 const GrStrokeInfo& strokeInfo) {
589 RETURN_IF_ABANDONED
590 if (oval.isEmpty()) {
591 return;
592 }
593
594 if (strokeInfo.isDashed()) {
595 SkPath path;
596 path.setIsVolatile(true);
597 path.addOval(oval);
598 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
599 return;
600 }
601
602 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700603 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700604 return;
605 }
606
joshualitt7b670db2015-07-09 13:25:02 -0700607 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700608 GrColor color = paint.getColor();
609 if (!GrOvalRenderer::DrawOval(fDrawTarget,
joshualittae3d63a2015-07-13 08:44:06 -0700610 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700611 color,
612 viewMatrix,
613 paint.isAntiAlias(),
614 oval,
615 strokeInfo)) {
616 SkPath path;
617 path.setIsVolatile(true);
618 path.addOval(oval);
619 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
620 paint.isAntiAlias(), path, strokeInfo);
621 }
622}
623
624// Can 'path' be drawn as a pair of filled nested rectangles?
joshualittf9c5db22015-07-10 11:31:01 -0700625static bool is_nested_rects(const SkMatrix& viewMatrix,
robertphillipsea461502015-05-26 11:38:03 -0700626 const SkPath& path,
627 const SkStrokeRec& stroke,
628 SkRect rects[2]) {
629 SkASSERT(stroke.isFillStyle());
630
631 if (path.isInverseFillType()) {
632 return false;
633 }
634
635 // TODO: this restriction could be lifted if we were willing to apply
636 // the matrix to all the points individually rather than just to the rect
637 if (!viewMatrix.preservesAxisAlignment()) {
638 return false;
639 }
640
641 SkPath::Direction dirs[2];
642 if (!path.isNestedFillRects(rects, dirs)) {
643 return false;
644 }
645
646 if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) {
647 // The two rects need to be wound opposite to each other
648 return false;
649 }
650
651 // Right now, nested rects where the margin is not the same width
652 // all around do not render correctly
653 const SkScalar* outer = rects[0].asScalars();
654 const SkScalar* inner = rects[1].asScalars();
655
656 bool allEq = true;
657
658 SkScalar margin = SkScalarAbs(outer[0] - inner[0]);
659 bool allGoE1 = margin >= SK_Scalar1;
660
661 for (int i = 1; i < 4; ++i) {
662 SkScalar temp = SkScalarAbs(outer[i] - inner[i]);
663 if (temp < SK_Scalar1) {
664 allGoE1 = false;
665 }
666 if (!SkScalarNearlyEqual(margin, temp)) {
667 allEq = false;
668 }
669 }
670
671 return allEq || allGoE1;
672}
673
674void GrDrawContext::drawPath(GrRenderTarget* rt,
675 const GrClip& clip,
676 const GrPaint& paint,
677 const SkMatrix& viewMatrix,
678 const SkPath& path,
679 const GrStrokeInfo& strokeInfo) {
680 RETURN_IF_ABANDONED
681 if (path.isEmpty()) {
682 if (path.isInverseFillType()) {
683 this->drawPaint(rt, clip, paint, viewMatrix);
684 }
685 return;
686 }
687
688 GrColor color = paint.getColor();
689
690 // Note that internalDrawPath may sw-rasterize the path into a scratch texture.
691 // Scratch textures can be recycled after they are returned to the texture
692 // cache. This presents a potential hazard for buffered drawing. However,
693 // the writePixels that uploads to the scratch will perform a flush so we're
694 // OK.
695 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700696 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700697 return;
698 }
699
joshualitt7b670db2015-07-09 13:25:02 -0700700 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700701 if (!strokeInfo.isDashed()) {
702 bool useCoverageAA = paint.isAntiAlias() &&
vbuzinovdded6962015-06-12 08:59:45 -0700703 !pipelineBuilder.getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -0700704
705 if (useCoverageAA && strokeInfo.getWidth() < 0 && !path.isConvex()) {
706 // Concave AA paths are expensive - try to avoid them for special cases
707 SkRect rects[2];
708
joshualittf9c5db22015-07-10 11:31:01 -0700709 if (is_nested_rects(viewMatrix, path, strokeInfo, rects)) {
joshualitt1c735482015-07-13 08:08:25 -0700710 GrAARectRenderer::FillAANestedRects(fDrawTarget, pipelineBuilder, color,
robertphillipsea461502015-05-26 11:38:03 -0700711 viewMatrix, rects);
712 return;
713 }
714 }
715 SkRect ovalRect;
716 bool isOval = path.isOval(&ovalRect);
717
718 if (isOval && !path.isInverseFillType()) {
719 if (GrOvalRenderer::DrawOval(fDrawTarget,
joshualittae3d63a2015-07-13 08:44:06 -0700720 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700721 color,
722 viewMatrix,
723 paint.isAntiAlias(),
724 ovalRect,
725 strokeInfo)) {
726 return;
727 }
728 }
729 }
730 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
731 path, strokeInfo);
732}
733
734void GrDrawContext::internalDrawPath(GrDrawTarget* target,
735 GrPipelineBuilder* pipelineBuilder,
736 const SkMatrix& viewMatrix,
737 GrColor color,
738 bool useAA,
739 const SkPath& path,
740 const GrStrokeInfo& strokeInfo) {
741 RETURN_IF_ABANDONED
742 SkASSERT(!path.isEmpty());
743
744
745 // An Assumption here is that path renderer would use some form of tweaking
746 // the src color (either the input alpha or in the frag shader) to implement
747 // aa. If we have some future driver-mojo path AA that can do the right
748 // thing WRT to the blend then we'll need some query on the PR.
749 bool useCoverageAA = useAA &&
vbuzinovdded6962015-06-12 08:59:45 -0700750 !pipelineBuilder->getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -0700751
752
753 GrPathRendererChain::DrawType type =
754 useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType :
755 GrPathRendererChain::kColor_DrawType;
756
757 const SkPath* pathPtr = &path;
758 SkTLazy<SkPath> tmpPath;
759 const GrStrokeInfo* strokeInfoPtr = &strokeInfo;
760
761 // Try a 1st time without stroking the path and without allowing the SW renderer
762 GrPathRenderer* pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr,
763 *strokeInfoPtr, false, type);
764
765 GrStrokeInfo dashlessStrokeInfo(strokeInfo, false);
766 if (NULL == pr && strokeInfo.isDashed()) {
767 // It didn't work above, so try again with dashed stroke converted to a dashless stroke.
768 if (!strokeInfo.applyDashToPath(tmpPath.init(), &dashlessStrokeInfo, *pathPtr)) {
769 return;
770 }
771 pathPtr = tmpPath.get();
772 if (pathPtr->isEmpty()) {
773 return;
774 }
775 strokeInfoPtr = &dashlessStrokeInfo;
776 pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
777 false, type);
778 }
779
780 if (NULL == pr) {
781 if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*strokeInfoPtr, viewMatrix, NULL) &&
782 !strokeInfoPtr->isFillStyle()) {
783 // It didn't work above, so try again with stroke converted to a fill.
784 if (!tmpPath.isValid()) {
785 tmpPath.init();
786 }
787 dashlessStrokeInfo.setResScale(SkScalarAbs(viewMatrix.getMaxScale()));
788 if (!dashlessStrokeInfo.applyToPath(tmpPath.get(), *pathPtr)) {
789 return;
790 }
791 pathPtr = tmpPath.get();
792 if (pathPtr->isEmpty()) {
793 return;
794 }
795 dashlessStrokeInfo.setFillStyle();
796 strokeInfoPtr = &dashlessStrokeInfo;
797 }
798
799 // This time, allow SW renderer
800 pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
801 true, type);
802 }
803
804 if (NULL == pr) {
805#ifdef SK_DEBUG
806 SkDebugf("Unable to find path renderer compatible with path.\n");
807#endif
808 return;
809 }
810
bsalomon0aff2fa2015-07-31 06:48:27 -0700811 GrPathRenderer::DrawPathArgs args;
812 args.fTarget = target;
813 args.fResourceProvider = fContext->resourceProvider();
814 args.fPipelineBuilder = pipelineBuilder;
815 args.fColor = color;
816 args.fViewMatrix = &viewMatrix;
817 args.fPath = pathPtr;
818 args.fStroke = strokeInfoPtr;
819 args.fAntiAlias = useCoverageAA;
820 pr->drawPath(args);
robertphillipsea461502015-05-26 11:38:03 -0700821}
822
robertphillipsea461502015-05-26 11:38:03 -0700823bool GrDrawContext::prepareToDraw(GrRenderTarget* rt) {
824 RETURN_FALSE_IF_ABANDONED
825
826 ASSERT_OWNED_RESOURCE(rt);
827 SkASSERT(rt);
828 return true;
829}
830
robertphillips2334fb62015-06-17 05:43:33 -0700831void GrDrawContext::drawBatch(GrPipelineBuilder* pipelineBuilder, GrBatch* batch) {
joshualitt1c735482015-07-13 08:08:25 -0700832 fDrawTarget->drawBatch(*pipelineBuilder, batch);
robertphillips2334fb62015-06-17 05:43:33 -0700833}