blob: f86e7834f0dc06bec6bda1ccfab5879fa71189dc [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"
joshualitt7fc2a262015-08-10 10:30:14 -070023#include "batches/GrRectBatchFactory.h"
joshualitt74417822015-08-07 11:42:16 -070024
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) {
robertphillipsea461502015-05-26 11:38:03 -0700332 // Non-AA hairlines are snapped to pixel centers to make which pixels are hit deterministic
vbuzinovdded6962015-06-12 08:59:45 -0700333 bool snapToPixelCenters = (0 == width && !rt->isUnifiedMultisampled());
joshualitt7fc2a262015-08-10 10:30:14 -0700334 SkAutoTUnref<GrBatch> batch(GrRectBatchFactory::CreateStrokeBW(color, viewMatrix, rect,
335 width, snapToPixelCenters));
robertphillipsea461502015-05-26 11:38:03 -0700336
337 // Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of
338 // hairline rects. We jam all the vertices to pixel centers to avoid this, but not when MSAA
339 // is enabled because it can cause ugly artifacts.
340 pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_Flag,
341 snapToPixelCenters);
joshualitt1c735482015-07-13 08:08:25 -0700342 fDrawTarget->drawBatch(pipelineBuilder, batch);
robertphillipsea461502015-05-26 11:38:03 -0700343 } else {
344 // filled BW rect
joshualitt1c735482015-07-13 08:08:25 -0700345 fDrawTarget->drawSimpleRect(pipelineBuilder, color, viewMatrix, rect);
robertphillipsea461502015-05-26 11:38:03 -0700346 }
347}
348
349void GrDrawContext::drawNonAARectToRect(GrRenderTarget* rt,
350 const GrClip& clip,
351 const GrPaint& paint,
352 const SkMatrix& viewMatrix,
353 const SkRect& rectToDraw,
354 const SkRect& localRect,
355 const SkMatrix* localMatrix) {
356 RETURN_IF_ABANDONED
357 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700358 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700359 return;
360 }
361
joshualitt7b670db2015-07-09 13:25:02 -0700362 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
joshualitt1c735482015-07-13 08:08:25 -0700363 fDrawTarget->drawBWRect(pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700364 paint.getColor(),
365 viewMatrix,
366 rectToDraw,
367 &localRect,
368 localMatrix);
369}
370
robertphillipsea461502015-05-26 11:38:03 -0700371void GrDrawContext::drawVertices(GrRenderTarget* rt,
372 const GrClip& clip,
373 const GrPaint& paint,
374 const SkMatrix& viewMatrix,
375 GrPrimitiveType primitiveType,
376 int vertexCount,
377 const SkPoint positions[],
378 const SkPoint texCoords[],
379 const GrColor colors[],
380 const uint16_t indices[],
381 int indexCount) {
382 RETURN_IF_ABANDONED
383 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700384 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700385 return;
386 }
387
joshualitt7b670db2015-07-09 13:25:02 -0700388 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
389
robertphillipsea461502015-05-26 11:38:03 -0700390 // TODO clients should give us bounds
391 SkRect bounds;
392 if (!bounds.setBoundsCheck(positions, vertexCount)) {
393 SkDebugf("drawVertices call empty bounds\n");
394 return;
395 }
396
397 viewMatrix.mapRect(&bounds);
398
399 // If we don't have AA then we outset for a half pixel in each direction to account for
400 // snapping
401 if (!paint.isAntiAlias()) {
402 bounds.outset(0.5f, 0.5f);
403 }
404
joshualitt2771b562015-08-07 12:46:26 -0700405 GrDrawVerticesBatch::Geometry geometry;
robertphillipsea461502015-05-26 11:38:03 -0700406 geometry.fColor = paint.getColor();
joshualitt2771b562015-08-07 12:46:26 -0700407 SkAutoTUnref<GrBatch> batch(GrDrawVerticesBatch::Create(geometry, primitiveType, viewMatrix,
408 positions, vertexCount, indices,
409 indexCount, colors, texCoords,
410 bounds));
robertphillipsea461502015-05-26 11:38:03 -0700411
joshualitt1c735482015-07-13 08:08:25 -0700412 fDrawTarget->drawBatch(pipelineBuilder, batch);
robertphillipsea461502015-05-26 11:38:03 -0700413}
414
415///////////////////////////////////////////////////////////////////////////////
416
jvanverth31ff7622015-08-07 10:09:28 -0700417void GrDrawContext::drawAtlas(GrRenderTarget* rt,
418 const GrClip& clip,
419 const GrPaint& paint,
420 const SkMatrix& viewMatrix,
421 int spriteCount,
422 const SkRSXform xform[],
423 const SkRect texRect[],
424 const SkColor colors[]) {
425 RETURN_IF_ABANDONED
426 AutoCheckFlush acf(fContext);
427 if (!this->prepareToDraw(rt)) {
428 return;
429 }
430
431 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
432
433 // now build the renderable geometry
434 const int vertCount = spriteCount * 4;
435 SkAutoTMalloc<SkPoint> vertStorage(vertCount * 2);
436 SkPoint* verts = vertStorage.get();
437 SkPoint* texs = verts + vertCount;
438
439 for (int i = 0; i < spriteCount; ++i) {
440 xform[i].toQuad(texRect[i].width(), texRect[i].height(), verts);
441 texRect[i].toQuad(texs);
442 verts += 4;
443 texs += 4;
444 }
445
446 // TODO clients should give us bounds
447 SkRect bounds;
448 if (!bounds.setBoundsCheck(vertStorage.get(), vertCount)) {
449 SkDebugf("drawAtlas call empty bounds\n");
450 return;
451 }
452
453 viewMatrix.mapRect(&bounds);
454
455 // If we don't have AA then we outset for a half pixel in each direction to account for
456 // snapping
457 if (!paint.isAntiAlias()) {
458 bounds.outset(0.5f, 0.5f);
459 }
460
461 SkAutoTMalloc<GrColor> colorStorage;
462 GrColor* vertCols = NULL;
463 if (colors) {
464 colorStorage.reset(vertCount);
465 vertCols = colorStorage.get();
466
467 int paintAlpha = GrColorUnpackA(paint.getColor());
468
469 // need to convert byte order and from non-PM to PM
470 for (int i = 0; i < spriteCount; ++i) {
471 SkColor color = colors[i];
472 if (paintAlpha != 255) {
473 color = SkColorSetA(color, SkMulDiv255Round(SkColorGetA(color), paintAlpha));
474 }
475 GrColor grColor = SkColor2GrColor(color);
476
477 vertCols[0] = vertCols[1] = vertCols[2] = vertCols[3] = grColor;
478 vertCols += 4;
479 }
480 }
481
482 verts = vertStorage.get();
483 texs = verts + vertCount;
484 vertCols = colorStorage.get();
485
jvanverth14b88032015-08-07 12:18:54 -0700486 GrDrawAtlasBatch::Geometry geometry;
jvanverth31ff7622015-08-07 10:09:28 -0700487 geometry.fColor = paint.getColor();
jvanverth14b88032015-08-07 12:18:54 -0700488 SkAutoTUnref<GrBatch> batch(GrDrawAtlasBatch::Create(geometry, viewMatrix, verts, vertCount,
489 vertCols, texs, bounds));
jvanverth31ff7622015-08-07 10:09:28 -0700490
491 fDrawTarget->drawBatch(pipelineBuilder, batch);
492}
493
494///////////////////////////////////////////////////////////////////////////////
495
robertphillipsea461502015-05-26 11:38:03 -0700496void GrDrawContext::drawRRect(GrRenderTarget*rt,
497 const GrClip& clip,
498 const GrPaint& paint,
499 const SkMatrix& viewMatrix,
500 const SkRRect& rrect,
501 const GrStrokeInfo& strokeInfo) {
502 RETURN_IF_ABANDONED
503 if (rrect.isEmpty()) {
504 return;
505 }
506
507 if (strokeInfo.isDashed()) {
508 SkPath path;
509 path.setIsVolatile(true);
510 path.addRRect(rrect);
511 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
512 return;
513 }
514
515 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700516 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700517 return;
518 }
519
joshualitt7b670db2015-07-09 13:25:02 -0700520 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700521 GrColor color = paint.getColor();
522 if (!GrOvalRenderer::DrawRRect(fDrawTarget,
joshualittae3d63a2015-07-13 08:44:06 -0700523 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700524 color,
525 viewMatrix,
526 paint.isAntiAlias(),
527 rrect,
528 strokeInfo)) {
529 SkPath path;
530 path.setIsVolatile(true);
531 path.addRRect(rrect);
532 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
533 paint.isAntiAlias(), path, strokeInfo);
534 }
535}
536
537///////////////////////////////////////////////////////////////////////////////
538
539void GrDrawContext::drawDRRect(GrRenderTarget* rt,
540 const GrClip& clip,
541 const GrPaint& paint,
542 const SkMatrix& viewMatrix,
543 const SkRRect& outer,
544 const SkRRect& inner) {
545 RETURN_IF_ABANDONED
546 if (outer.isEmpty()) {
547 return;
548 }
549
550 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700551 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700552 return;
553 }
554
joshualitt7b670db2015-07-09 13:25:02 -0700555 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700556 GrColor color = paint.getColor();
557 if (!GrOvalRenderer::DrawDRRect(fDrawTarget,
joshualittae3d63a2015-07-13 08:44:06 -0700558 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700559 color,
560 viewMatrix,
561 paint.isAntiAlias(),
562 outer,
563 inner)) {
564 SkPath path;
565 path.setIsVolatile(true);
566 path.addRRect(inner);
567 path.addRRect(outer);
568 path.setFillType(SkPath::kEvenOdd_FillType);
569
570 GrStrokeInfo fillRec(SkStrokeRec::kFill_InitStyle);
571 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
572 paint.isAntiAlias(), path, fillRec);
573 }
574}
575
576///////////////////////////////////////////////////////////////////////////////
577
578void GrDrawContext::drawOval(GrRenderTarget* rt,
579 const GrClip& clip,
580 const GrPaint& paint,
581 const SkMatrix& viewMatrix,
582 const SkRect& oval,
583 const GrStrokeInfo& strokeInfo) {
584 RETURN_IF_ABANDONED
585 if (oval.isEmpty()) {
586 return;
587 }
588
589 if (strokeInfo.isDashed()) {
590 SkPath path;
591 path.setIsVolatile(true);
592 path.addOval(oval);
593 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
594 return;
595 }
596
597 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700598 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700599 return;
600 }
601
joshualitt7b670db2015-07-09 13:25:02 -0700602 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700603 GrColor color = paint.getColor();
604 if (!GrOvalRenderer::DrawOval(fDrawTarget,
joshualittae3d63a2015-07-13 08:44:06 -0700605 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700606 color,
607 viewMatrix,
608 paint.isAntiAlias(),
609 oval,
610 strokeInfo)) {
611 SkPath path;
612 path.setIsVolatile(true);
613 path.addOval(oval);
614 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
615 paint.isAntiAlias(), path, strokeInfo);
616 }
617}
618
619// Can 'path' be drawn as a pair of filled nested rectangles?
joshualittf9c5db22015-07-10 11:31:01 -0700620static bool is_nested_rects(const SkMatrix& viewMatrix,
robertphillipsea461502015-05-26 11:38:03 -0700621 const SkPath& path,
622 const SkStrokeRec& stroke,
623 SkRect rects[2]) {
624 SkASSERT(stroke.isFillStyle());
625
626 if (path.isInverseFillType()) {
627 return false;
628 }
629
630 // TODO: this restriction could be lifted if we were willing to apply
631 // the matrix to all the points individually rather than just to the rect
632 if (!viewMatrix.preservesAxisAlignment()) {
633 return false;
634 }
635
636 SkPath::Direction dirs[2];
637 if (!path.isNestedFillRects(rects, dirs)) {
638 return false;
639 }
640
641 if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) {
642 // The two rects need to be wound opposite to each other
643 return false;
644 }
645
646 // Right now, nested rects where the margin is not the same width
647 // all around do not render correctly
648 const SkScalar* outer = rects[0].asScalars();
649 const SkScalar* inner = rects[1].asScalars();
650
651 bool allEq = true;
652
653 SkScalar margin = SkScalarAbs(outer[0] - inner[0]);
654 bool allGoE1 = margin >= SK_Scalar1;
655
656 for (int i = 1; i < 4; ++i) {
657 SkScalar temp = SkScalarAbs(outer[i] - inner[i]);
658 if (temp < SK_Scalar1) {
659 allGoE1 = false;
660 }
661 if (!SkScalarNearlyEqual(margin, temp)) {
662 allEq = false;
663 }
664 }
665
666 return allEq || allGoE1;
667}
668
669void GrDrawContext::drawPath(GrRenderTarget* rt,
670 const GrClip& clip,
671 const GrPaint& paint,
672 const SkMatrix& viewMatrix,
673 const SkPath& path,
674 const GrStrokeInfo& strokeInfo) {
675 RETURN_IF_ABANDONED
676 if (path.isEmpty()) {
677 if (path.isInverseFillType()) {
678 this->drawPaint(rt, clip, paint, viewMatrix);
679 }
680 return;
681 }
682
683 GrColor color = paint.getColor();
684
685 // Note that internalDrawPath may sw-rasterize the path into a scratch texture.
686 // Scratch textures can be recycled after they are returned to the texture
687 // cache. This presents a potential hazard for buffered drawing. However,
688 // the writePixels that uploads to the scratch will perform a flush so we're
689 // OK.
690 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700691 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700692 return;
693 }
694
joshualitt7b670db2015-07-09 13:25:02 -0700695 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700696 if (!strokeInfo.isDashed()) {
697 bool useCoverageAA = paint.isAntiAlias() &&
vbuzinovdded6962015-06-12 08:59:45 -0700698 !pipelineBuilder.getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -0700699
700 if (useCoverageAA && strokeInfo.getWidth() < 0 && !path.isConvex()) {
701 // Concave AA paths are expensive - try to avoid them for special cases
702 SkRect rects[2];
703
joshualittf9c5db22015-07-10 11:31:01 -0700704 if (is_nested_rects(viewMatrix, path, strokeInfo, rects)) {
joshualitt1c735482015-07-13 08:08:25 -0700705 GrAARectRenderer::FillAANestedRects(fDrawTarget, pipelineBuilder, color,
robertphillipsea461502015-05-26 11:38:03 -0700706 viewMatrix, rects);
707 return;
708 }
709 }
710 SkRect ovalRect;
711 bool isOval = path.isOval(&ovalRect);
712
713 if (isOval && !path.isInverseFillType()) {
714 if (GrOvalRenderer::DrawOval(fDrawTarget,
joshualittae3d63a2015-07-13 08:44:06 -0700715 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700716 color,
717 viewMatrix,
718 paint.isAntiAlias(),
719 ovalRect,
720 strokeInfo)) {
721 return;
722 }
723 }
724 }
725 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
726 path, strokeInfo);
727}
728
729void GrDrawContext::internalDrawPath(GrDrawTarget* target,
730 GrPipelineBuilder* pipelineBuilder,
731 const SkMatrix& viewMatrix,
732 GrColor color,
733 bool useAA,
734 const SkPath& path,
735 const GrStrokeInfo& strokeInfo) {
736 RETURN_IF_ABANDONED
737 SkASSERT(!path.isEmpty());
738
739
740 // An Assumption here is that path renderer would use some form of tweaking
741 // the src color (either the input alpha or in the frag shader) to implement
742 // aa. If we have some future driver-mojo path AA that can do the right
743 // thing WRT to the blend then we'll need some query on the PR.
744 bool useCoverageAA = useAA &&
vbuzinovdded6962015-06-12 08:59:45 -0700745 !pipelineBuilder->getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -0700746
747
748 GrPathRendererChain::DrawType type =
749 useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType :
750 GrPathRendererChain::kColor_DrawType;
751
752 const SkPath* pathPtr = &path;
753 SkTLazy<SkPath> tmpPath;
754 const GrStrokeInfo* strokeInfoPtr = &strokeInfo;
755
756 // Try a 1st time without stroking the path and without allowing the SW renderer
757 GrPathRenderer* pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr,
758 *strokeInfoPtr, false, type);
759
760 GrStrokeInfo dashlessStrokeInfo(strokeInfo, false);
761 if (NULL == pr && strokeInfo.isDashed()) {
762 // It didn't work above, so try again with dashed stroke converted to a dashless stroke.
763 if (!strokeInfo.applyDashToPath(tmpPath.init(), &dashlessStrokeInfo, *pathPtr)) {
764 return;
765 }
766 pathPtr = tmpPath.get();
767 if (pathPtr->isEmpty()) {
768 return;
769 }
770 strokeInfoPtr = &dashlessStrokeInfo;
771 pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
772 false, type);
773 }
774
775 if (NULL == pr) {
776 if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*strokeInfoPtr, viewMatrix, NULL) &&
777 !strokeInfoPtr->isFillStyle()) {
778 // It didn't work above, so try again with stroke converted to a fill.
779 if (!tmpPath.isValid()) {
780 tmpPath.init();
781 }
782 dashlessStrokeInfo.setResScale(SkScalarAbs(viewMatrix.getMaxScale()));
783 if (!dashlessStrokeInfo.applyToPath(tmpPath.get(), *pathPtr)) {
784 return;
785 }
786 pathPtr = tmpPath.get();
787 if (pathPtr->isEmpty()) {
788 return;
789 }
790 dashlessStrokeInfo.setFillStyle();
791 strokeInfoPtr = &dashlessStrokeInfo;
792 }
793
794 // This time, allow SW renderer
795 pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
796 true, type);
797 }
798
799 if (NULL == pr) {
800#ifdef SK_DEBUG
801 SkDebugf("Unable to find path renderer compatible with path.\n");
802#endif
803 return;
804 }
805
bsalomon0aff2fa2015-07-31 06:48:27 -0700806 GrPathRenderer::DrawPathArgs args;
807 args.fTarget = target;
808 args.fResourceProvider = fContext->resourceProvider();
809 args.fPipelineBuilder = pipelineBuilder;
810 args.fColor = color;
811 args.fViewMatrix = &viewMatrix;
812 args.fPath = pathPtr;
813 args.fStroke = strokeInfoPtr;
814 args.fAntiAlias = useCoverageAA;
815 pr->drawPath(args);
robertphillipsea461502015-05-26 11:38:03 -0700816}
817
robertphillipsea461502015-05-26 11:38:03 -0700818bool GrDrawContext::prepareToDraw(GrRenderTarget* rt) {
819 RETURN_FALSE_IF_ABANDONED
820
821 ASSERT_OWNED_RESOURCE(rt);
822 SkASSERT(rt);
823 return true;
824}
825
robertphillips2334fb62015-06-17 05:43:33 -0700826void GrDrawContext::drawBatch(GrPipelineBuilder* pipelineBuilder, GrBatch* batch) {
joshualitt1c735482015-07-13 08:08:25 -0700827 fDrawTarget->drawBatch(*pipelineBuilder, batch);
robertphillips2334fb62015-06-17 05:43:33 -0700828}