blob: e56a729d22d40e3ec954de7e5cdd9b03fb858d61 [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
robertphillipsea461502015-05-26 11:38:03 -070024#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == fContext)
25#define RETURN_IF_ABANDONED if (!fDrawTarget) { return; }
26#define RETURN_FALSE_IF_ABANDONED if (!fDrawTarget) { return false; }
halcanary96fcdcc2015-08-27 07:41:13 -070027#define RETURN_NULL_IF_ABANDONED if (!fDrawTarget) { return nullptr; }
robertphillipsea461502015-05-26 11:38:03 -070028
29class AutoCheckFlush {
30public:
31 AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context); }
32 ~AutoCheckFlush() { fContext->flushIfNecessary(); }
33
34private:
35 GrContext* fContext;
36};
37
robertphillips2334fb62015-06-17 05:43:33 -070038GrDrawContext::GrDrawContext(GrContext* context,
39 GrDrawTarget* drawTarget,
robertphillipsfcf78292015-06-19 11:49:52 -070040 const SkSurfaceProps& surfaceProps)
robertphillipsea461502015-05-26 11:38:03 -070041 : fContext(context)
robertphillips2334fb62015-06-17 05:43:33 -070042 , fDrawTarget(SkRef(drawTarget))
halcanary96fcdcc2015-08-27 07:41:13 -070043 , fTextContext(nullptr)
robertphillipsfcf78292015-06-19 11:49:52 -070044 , fSurfaceProps(surfaceProps) {
robertphillipsea461502015-05-26 11:38:03 -070045}
46
robertphillips4b195e52015-05-26 14:37:00 -070047GrDrawContext::~GrDrawContext() {
48 SkSafeUnref(fDrawTarget);
halcanary385fe4d2015-08-26 13:07:48 -070049 delete fTextContext;
robertphillips4b195e52015-05-26 14:37:00 -070050}
51
robertphillipsea461502015-05-26 11:38:03 -070052void GrDrawContext::copySurface(GrRenderTarget* dst, GrSurface* src,
53 const SkIRect& srcRect, const SkIPoint& dstPoint) {
54 if (!this->prepareToDraw(dst)) {
55 return;
56 }
57
58 fDrawTarget->copySurface(dst, src, srcRect, dstPoint);
59}
60
robertphillips2334fb62015-06-17 05:43:33 -070061GrTextContext* GrDrawContext::createTextContext(GrRenderTarget* renderTarget,
robertphillipsfcf78292015-06-19 11:49:52 -070062 const SkSurfaceProps& surfaceProps) {
robertphillips2334fb62015-06-17 05:43:33 -070063 if (fContext->caps()->shaderCaps()->pathRenderingSupport() &&
cdaltone04edd82015-06-29 14:15:19 -070064 renderTarget->isStencilBufferMultisampled() &&
65 fSurfaceProps.isUseDistanceFieldFonts()) { // FIXME: Rename the dff flag to be more general.
robertphillips2334fb62015-06-17 05:43:33 -070066 GrStencilAttachment* sb = renderTarget->renderTargetPriv().attachStencilAttachment();
67 if (sb) {
robertphillipsfcf78292015-06-19 11:49:52 -070068 return GrStencilAndCoverTextContext::Create(fContext, this, surfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -070069 }
70 }
71
robertphillipsfcf78292015-06-19 11:49:52 -070072 return GrAtlasTextContext::Create(fContext, this, surfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -070073}
74
75void GrDrawContext::drawText(GrRenderTarget* rt, const GrClip& clip, const GrPaint& grPaint,
76 const SkPaint& skPaint,
77 const SkMatrix& viewMatrix,
78 const char text[], size_t byteLength,
79 SkScalar x, SkScalar y, const SkIRect& clipBounds) {
80 if (!fTextContext) {
robertphillipsfcf78292015-06-19 11:49:52 -070081 fTextContext = this->createTextContext(rt, fSurfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -070082 }
83
84 fTextContext->drawText(rt, clip, grPaint, skPaint, viewMatrix,
85 text, byteLength, x, y, clipBounds);
86
87}
88void GrDrawContext::drawPosText(GrRenderTarget* rt, const GrClip& clip, const GrPaint& grPaint,
89 const SkPaint& skPaint,
90 const SkMatrix& viewMatrix,
91 const char text[], size_t byteLength,
92 const SkScalar pos[], int scalarsPerPosition,
93 const SkPoint& offset, const SkIRect& clipBounds) {
94 if (!fTextContext) {
robertphillipsfcf78292015-06-19 11:49:52 -070095 fTextContext = this->createTextContext(rt, fSurfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -070096 }
97
98 fTextContext->drawPosText(rt, clip, grPaint, skPaint, viewMatrix, text, byteLength,
99 pos, scalarsPerPosition, offset, clipBounds);
100
101}
102void GrDrawContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, const SkPaint& skPaint,
103 const SkMatrix& viewMatrix, const SkTextBlob* blob,
104 SkScalar x, SkScalar y,
105 SkDrawFilter* filter, const SkIRect& clipBounds) {
106 if (!fTextContext) {
robertphillipsfcf78292015-06-19 11:49:52 -0700107 fTextContext = this->createTextContext(rt, fSurfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -0700108 }
109
110 fTextContext->drawTextBlob(rt, clip, skPaint, viewMatrix, blob, x, y, filter, clipBounds);
robertphillipsea461502015-05-26 11:38:03 -0700111}
112
113void GrDrawContext::drawPaths(GrPipelineBuilder* pipelineBuilder,
114 const GrPathProcessor* pathProc,
115 const GrPathRange* pathRange,
116 const void* indices,
117 int /*GrDrawTarget::PathIndexType*/ indexType,
118 const float transformValues[],
119 int /*GrDrawTarget::PathTransformType*/ transformType,
120 int count,
121 int /*GrPathRendering::FillType*/ fill) {
joshualitt1c735482015-07-13 08:08:25 -0700122 fDrawTarget->drawPaths(*pipelineBuilder, pathProc, pathRange,
robertphillipsea461502015-05-26 11:38:03 -0700123 indices, (GrDrawTarget::PathIndexType) indexType,
124 transformValues,
125 (GrDrawTarget::PathTransformType) transformType,
126 count, (GrPathRendering::FillType) fill);
127}
128
129void GrDrawContext::discard(GrRenderTarget* renderTarget) {
130 RETURN_IF_ABANDONED
131 SkASSERT(renderTarget);
132 AutoCheckFlush acf(fContext);
133 if (!this->prepareToDraw(renderTarget)) {
134 return;
135 }
136 fDrawTarget->discard(renderTarget);
137}
138
139void GrDrawContext::clear(GrRenderTarget* renderTarget,
140 const SkIRect* rect,
141 const GrColor color,
142 bool canIgnoreRect) {
143 RETURN_IF_ABANDONED
144 SkASSERT(renderTarget);
145
146 AutoCheckFlush acf(fContext);
147 if (!this->prepareToDraw(renderTarget)) {
148 return;
149 }
150 fDrawTarget->clear(rect, color, canIgnoreRect, renderTarget);
151}
152
153
154void GrDrawContext::drawPaint(GrRenderTarget* rt,
155 const GrClip& clip,
156 const GrPaint& origPaint,
157 const SkMatrix& viewMatrix) {
158 RETURN_IF_ABANDONED
159 // set rect to be big enough to fill the space, but not super-huge, so we
160 // don't overflow fixed-point implementations
161 SkRect r;
162 r.setLTRB(0, 0,
163 SkIntToScalar(rt->width()),
164 SkIntToScalar(rt->height()));
165 SkTCopyOnFirstWrite<GrPaint> paint(origPaint);
166
167 // by definition this fills the entire clip, no need for AA
168 if (paint->isAntiAlias()) {
169 paint.writable()->setAntiAlias(false);
170 }
171
172 bool isPerspective = viewMatrix.hasPerspective();
173
174 // We attempt to map r by the inverse matrix and draw that. mapRect will
175 // map the four corners and bound them with a new rect. This will not
176 // produce a correct result for some perspective matrices.
177 if (!isPerspective) {
178 SkMatrix inverse;
179 if (!viewMatrix.invert(&inverse)) {
180 SkDebugf("Could not invert matrix\n");
181 return;
182 }
183 inverse.mapRect(&r);
184 this->drawRect(rt, clip, *paint, viewMatrix, r);
185 } else {
186 SkMatrix localMatrix;
187 if (!viewMatrix.invert(&localMatrix)) {
188 SkDebugf("Could not invert matrix\n");
189 return;
190 }
191
192 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700193 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700194 return;
195 }
196
joshualitt7b670db2015-07-09 13:25:02 -0700197 GrPipelineBuilder pipelineBuilder(*paint, rt, clip);
joshualittd2b23e02015-08-21 10:53:34 -0700198 fDrawTarget->drawNonAARect(pipelineBuilder,
199 paint->getColor(),
200 SkMatrix::I(),
201 r,
202 localMatrix);
robertphillipsea461502015-05-26 11:38:03 -0700203 }
204}
205
robertphillipsea461502015-05-26 11:38:03 -0700206static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) {
207 return point.fX >= rect.fLeft && point.fX <= rect.fRight &&
208 point.fY >= rect.fTop && point.fY <= rect.fBottom;
209}
210
robertphillipsea461502015-05-26 11:38:03 -0700211void GrDrawContext::drawRect(GrRenderTarget* rt,
212 const GrClip& clip,
213 const GrPaint& paint,
214 const SkMatrix& viewMatrix,
215 const SkRect& rect,
216 const GrStrokeInfo* strokeInfo) {
217 RETURN_IF_ABANDONED
218 if (strokeInfo && strokeInfo->isDashed()) {
219 SkPath path;
220 path.setIsVolatile(true);
221 path.addRect(rect);
222 this->drawPath(rt, clip, paint, viewMatrix, path, *strokeInfo);
223 return;
224 }
225
226 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700227 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700228 return;
229 }
230
joshualitt7b670db2015-07-09 13:25:02 -0700231 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
232
halcanary96fcdcc2015-08-27 07:41:13 -0700233 SkScalar width = nullptr == strokeInfo ? -1 : strokeInfo->getWidth();
robertphillipsea461502015-05-26 11:38:03 -0700234
235 // Check if this is a full RT draw and can be replaced with a clear. We don't bother checking
236 // cases where the RT is fully inside a stroke.
237 if (width < 0) {
238 SkRect rtRect;
239 pipelineBuilder.getRenderTarget()->getBoundsRect(&rtRect);
240 SkRect clipSpaceRTRect = rtRect;
241 bool checkClip = GrClip::kWideOpen_ClipType != clip.clipType();
242 if (checkClip) {
243 clipSpaceRTRect.offset(SkIntToScalar(clip.origin().fX),
244 SkIntToScalar(clip.origin().fY));
245 }
246 // Does the clip contain the entire RT?
247 if (!checkClip || clip.quickContains(clipSpaceRTRect)) {
248 SkMatrix invM;
249 if (!viewMatrix.invert(&invM)) {
250 return;
251 }
252 // Does the rect bound the RT?
253 SkPoint srcSpaceRTQuad[4];
254 invM.mapRectToQuad(srcSpaceRTQuad, rtRect);
255 if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) &&
256 rect_contains_inclusive(rect, srcSpaceRTQuad[1]) &&
257 rect_contains_inclusive(rect, srcSpaceRTQuad[2]) &&
258 rect_contains_inclusive(rect, srcSpaceRTQuad[3])) {
259 // Will it blend?
260 GrColor clearColor;
cdalton1fa45722015-06-02 10:43:39 -0700261 if (paint.isConstantBlendedColor(&clearColor)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700262 fDrawTarget->clear(nullptr, clearColor, true, rt);
robertphillipsea461502015-05-26 11:38:03 -0700263 return;
264 }
265 }
266 }
267 }
268
269 GrColor color = paint.getColor();
vbuzinovdded6962015-06-12 08:59:45 -0700270 bool needAA = paint.isAntiAlias() &&
271 !pipelineBuilder.getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -0700272
joshualitt9be0b002015-08-19 11:50:51 -0700273 // The fill path can handle rotation but not skew
274 // The stroke path needs the rect to remain axis aligned (no rotation or skew)
275 // None of our draw rect calls can handle perspective yet
276 SkASSERT(!viewMatrix.hasPerspective());
277 bool canApplyAA = width >=0 ? viewMatrix.rectStaysRect() : viewMatrix.preservesRightAngles();
278
279 if (needAA && canApplyAA) {
280 SkRect devBoundRect;
281 viewMatrix.mapRect(&devBoundRect, rect);
bsalomonabd30f52015-08-13 13:34:48 -0700282 SkAutoTUnref<GrDrawBatch> batch;
robertphillipsea461502015-05-26 11:38:03 -0700283 if (width >= 0) {
joshualittd2b23e02015-08-21 10:53:34 -0700284 batch.reset(GrRectBatchFactory::CreateAAStroke(color, viewMatrix, rect, devBoundRect,
joshualitt14205b12015-08-10 11:40:56 -0700285 *strokeInfo));
robertphillipsea461502015-05-26 11:38:03 -0700286 } else {
joshualittd2b23e02015-08-21 10:53:34 -0700287 batch.reset(GrRectBatchFactory::CreateAAFill(color, viewMatrix, rect, devBoundRect));
robertphillipsea461502015-05-26 11:38:03 -0700288 }
joshualitt14205b12015-08-10 11:40:56 -0700289 fDrawTarget->drawBatch(pipelineBuilder, batch);
robertphillipsea461502015-05-26 11:38:03 -0700290 return;
291 }
292
293 if (width >= 0) {
robertphillipsea461502015-05-26 11:38:03 -0700294 // Non-AA hairlines are snapped to pixel centers to make which pixels are hit deterministic
vbuzinovdded6962015-06-12 08:59:45 -0700295 bool snapToPixelCenters = (0 == width && !rt->isUnifiedMultisampled());
joshualittd2b23e02015-08-21 10:53:34 -0700296 SkAutoTUnref<GrDrawBatch> batch(GrRectBatchFactory::CreateNonAAStroke(
bsalomonabd30f52015-08-13 13:34:48 -0700297 color, viewMatrix, rect, width, snapToPixelCenters));
robertphillipsea461502015-05-26 11:38:03 -0700298
299 // Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of
300 // hairline rects. We jam all the vertices to pixel centers to avoid this, but not when MSAA
301 // is enabled because it can cause ugly artifacts.
302 pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_Flag,
303 snapToPixelCenters);
joshualitt1c735482015-07-13 08:08:25 -0700304 fDrawTarget->drawBatch(pipelineBuilder, batch);
robertphillipsea461502015-05-26 11:38:03 -0700305 } else {
306 // filled BW rect
joshualittd2b23e02015-08-21 10:53:34 -0700307 fDrawTarget->drawNonAARect(pipelineBuilder, color, viewMatrix, rect);
robertphillipsea461502015-05-26 11:38:03 -0700308 }
309}
310
311void GrDrawContext::drawNonAARectToRect(GrRenderTarget* rt,
312 const GrClip& clip,
313 const GrPaint& paint,
314 const SkMatrix& viewMatrix,
315 const SkRect& rectToDraw,
joshualittb6b513b2015-08-21 10:25:18 -0700316 const SkRect& localRect) {
robertphillipsea461502015-05-26 11:38:03 -0700317 RETURN_IF_ABANDONED
318 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700319 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700320 return;
321 }
322
joshualitt7b670db2015-07-09 13:25:02 -0700323 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
joshualittd2b23e02015-08-21 10:53:34 -0700324 fDrawTarget->drawNonAARect(pipelineBuilder,
325 paint.getColor(),
326 viewMatrix,
327 rectToDraw,
328 localRect);
joshualittb6b513b2015-08-21 10:25:18 -0700329}
330
331void GrDrawContext::drawNonAARectWithLocalMatrix(GrRenderTarget* rt,
332 const GrClip& clip,
333 const GrPaint& paint,
334 const SkMatrix& viewMatrix,
335 const SkRect& rectToDraw,
336 const SkMatrix& localMatrix) {
337 RETURN_IF_ABANDONED
338 AutoCheckFlush acf(fContext);
339 if (!this->prepareToDraw(rt)) {
340 return;
341 }
342
343 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
joshualittd2b23e02015-08-21 10:53:34 -0700344 fDrawTarget->drawNonAARect(pipelineBuilder,
345 paint.getColor(),
346 viewMatrix,
347 rectToDraw,
348 localMatrix);
robertphillipsea461502015-05-26 11:38:03 -0700349}
350
robertphillipsea461502015-05-26 11:38:03 -0700351void GrDrawContext::drawVertices(GrRenderTarget* rt,
352 const GrClip& clip,
353 const GrPaint& paint,
354 const SkMatrix& viewMatrix,
355 GrPrimitiveType primitiveType,
356 int vertexCount,
357 const SkPoint positions[],
358 const SkPoint texCoords[],
359 const GrColor colors[],
360 const uint16_t indices[],
361 int indexCount) {
362 RETURN_IF_ABANDONED
363 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700364 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700365 return;
366 }
367
joshualitt7b670db2015-07-09 13:25:02 -0700368 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
369
robertphillipsea461502015-05-26 11:38:03 -0700370 // TODO clients should give us bounds
371 SkRect bounds;
372 if (!bounds.setBoundsCheck(positions, vertexCount)) {
373 SkDebugf("drawVertices call empty bounds\n");
374 return;
375 }
376
377 viewMatrix.mapRect(&bounds);
378
379 // If we don't have AA then we outset for a half pixel in each direction to account for
380 // snapping
381 if (!paint.isAntiAlias()) {
382 bounds.outset(0.5f, 0.5f);
383 }
384
joshualitt2771b562015-08-07 12:46:26 -0700385 GrDrawVerticesBatch::Geometry geometry;
robertphillipsea461502015-05-26 11:38:03 -0700386 geometry.fColor = paint.getColor();
bsalomonabd30f52015-08-13 13:34:48 -0700387 SkAutoTUnref<GrDrawBatch> batch(GrDrawVerticesBatch::Create(geometry, primitiveType, viewMatrix,
388 positions, vertexCount, indices,
389 indexCount, colors, texCoords,
390 bounds));
robertphillipsea461502015-05-26 11:38:03 -0700391
joshualitt1c735482015-07-13 08:08:25 -0700392 fDrawTarget->drawBatch(pipelineBuilder, batch);
robertphillipsea461502015-05-26 11:38:03 -0700393}
394
395///////////////////////////////////////////////////////////////////////////////
396
jvanverth31ff7622015-08-07 10:09:28 -0700397void GrDrawContext::drawAtlas(GrRenderTarget* rt,
398 const GrClip& clip,
399 const GrPaint& paint,
400 const SkMatrix& viewMatrix,
401 int spriteCount,
402 const SkRSXform xform[],
403 const SkRect texRect[],
404 const SkColor colors[]) {
405 RETURN_IF_ABANDONED
406 AutoCheckFlush acf(fContext);
407 if (!this->prepareToDraw(rt)) {
408 return;
409 }
410
411 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
412
jvanverth14b88032015-08-07 12:18:54 -0700413 GrDrawAtlasBatch::Geometry geometry;
jvanverth31ff7622015-08-07 10:09:28 -0700414 geometry.fColor = paint.getColor();
bsalomonabd30f52015-08-13 13:34:48 -0700415 SkAutoTUnref<GrDrawBatch> batch(GrDrawAtlasBatch::Create(geometry, viewMatrix, spriteCount,
416 xform, texRect, colors));
jvanverth31ff7622015-08-07 10:09:28 -0700417
418 fDrawTarget->drawBatch(pipelineBuilder, batch);
419}
420
421///////////////////////////////////////////////////////////////////////////////
422
robertphillipsea461502015-05-26 11:38:03 -0700423void GrDrawContext::drawRRect(GrRenderTarget*rt,
424 const GrClip& clip,
425 const GrPaint& paint,
426 const SkMatrix& viewMatrix,
427 const SkRRect& rrect,
428 const GrStrokeInfo& strokeInfo) {
429 RETURN_IF_ABANDONED
430 if (rrect.isEmpty()) {
431 return;
432 }
433
434 if (strokeInfo.isDashed()) {
435 SkPath path;
436 path.setIsVolatile(true);
437 path.addRRect(rrect);
438 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
439 return;
440 }
441
442 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700443 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700444 return;
445 }
446
joshualitt7b670db2015-07-09 13:25:02 -0700447 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700448 GrColor color = paint.getColor();
449 if (!GrOvalRenderer::DrawRRect(fDrawTarget,
joshualittae3d63a2015-07-13 08:44:06 -0700450 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700451 color,
452 viewMatrix,
453 paint.isAntiAlias(),
454 rrect,
455 strokeInfo)) {
456 SkPath path;
457 path.setIsVolatile(true);
458 path.addRRect(rrect);
459 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
460 paint.isAntiAlias(), path, strokeInfo);
461 }
462}
463
464///////////////////////////////////////////////////////////////////////////////
465
466void GrDrawContext::drawDRRect(GrRenderTarget* rt,
467 const GrClip& clip,
468 const GrPaint& paint,
469 const SkMatrix& viewMatrix,
470 const SkRRect& outer,
471 const SkRRect& inner) {
472 RETURN_IF_ABANDONED
473 if (outer.isEmpty()) {
474 return;
475 }
476
477 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700478 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700479 return;
480 }
481
joshualitt7b670db2015-07-09 13:25:02 -0700482 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700483 GrColor color = paint.getColor();
484 if (!GrOvalRenderer::DrawDRRect(fDrawTarget,
joshualittae3d63a2015-07-13 08:44:06 -0700485 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700486 color,
487 viewMatrix,
488 paint.isAntiAlias(),
489 outer,
490 inner)) {
491 SkPath path;
492 path.setIsVolatile(true);
493 path.addRRect(inner);
494 path.addRRect(outer);
495 path.setFillType(SkPath::kEvenOdd_FillType);
496
497 GrStrokeInfo fillRec(SkStrokeRec::kFill_InitStyle);
498 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
499 paint.isAntiAlias(), path, fillRec);
500 }
501}
502
503///////////////////////////////////////////////////////////////////////////////
504
505void GrDrawContext::drawOval(GrRenderTarget* rt,
506 const GrClip& clip,
507 const GrPaint& paint,
508 const SkMatrix& viewMatrix,
509 const SkRect& oval,
510 const GrStrokeInfo& strokeInfo) {
511 RETURN_IF_ABANDONED
512 if (oval.isEmpty()) {
513 return;
514 }
515
516 if (strokeInfo.isDashed()) {
517 SkPath path;
518 path.setIsVolatile(true);
519 path.addOval(oval);
520 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
521 return;
522 }
523
524 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700525 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700526 return;
527 }
528
joshualitt7b670db2015-07-09 13:25:02 -0700529 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700530 GrColor color = paint.getColor();
531 if (!GrOvalRenderer::DrawOval(fDrawTarget,
joshualittae3d63a2015-07-13 08:44:06 -0700532 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700533 color,
534 viewMatrix,
535 paint.isAntiAlias(),
536 oval,
537 strokeInfo)) {
538 SkPath path;
539 path.setIsVolatile(true);
540 path.addOval(oval);
541 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
542 paint.isAntiAlias(), path, strokeInfo);
543 }
544}
545
546// Can 'path' be drawn as a pair of filled nested rectangles?
joshualittf9c5db22015-07-10 11:31:01 -0700547static bool is_nested_rects(const SkMatrix& viewMatrix,
robertphillipsea461502015-05-26 11:38:03 -0700548 const SkPath& path,
549 const SkStrokeRec& stroke,
550 SkRect rects[2]) {
551 SkASSERT(stroke.isFillStyle());
552
553 if (path.isInverseFillType()) {
554 return false;
555 }
556
557 // TODO: this restriction could be lifted if we were willing to apply
558 // the matrix to all the points individually rather than just to the rect
559 if (!viewMatrix.preservesAxisAlignment()) {
560 return false;
561 }
562
563 SkPath::Direction dirs[2];
564 if (!path.isNestedFillRects(rects, dirs)) {
565 return false;
566 }
567
568 if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) {
569 // The two rects need to be wound opposite to each other
570 return false;
571 }
572
573 // Right now, nested rects where the margin is not the same width
574 // all around do not render correctly
575 const SkScalar* outer = rects[0].asScalars();
576 const SkScalar* inner = rects[1].asScalars();
577
578 bool allEq = true;
579
580 SkScalar margin = SkScalarAbs(outer[0] - inner[0]);
581 bool allGoE1 = margin >= SK_Scalar1;
582
583 for (int i = 1; i < 4; ++i) {
584 SkScalar temp = SkScalarAbs(outer[i] - inner[i]);
585 if (temp < SK_Scalar1) {
586 allGoE1 = false;
587 }
588 if (!SkScalarNearlyEqual(margin, temp)) {
589 allEq = false;
590 }
591 }
592
593 return allEq || allGoE1;
594}
595
joshualittb7ee1bf2015-08-10 11:59:02 -0700596void GrDrawContext::drawBatch(GrRenderTarget* rt, const GrClip& clip,
bsalomonabd30f52015-08-13 13:34:48 -0700597 const GrPaint& paint, GrDrawBatch* batch) {
joshualittb7ee1bf2015-08-10 11:59:02 -0700598 RETURN_IF_ABANDONED
599
600 AutoCheckFlush acf(fContext);
601 if (!this->prepareToDraw(rt)) {
602 return;
603 }
604
605 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
606 fDrawTarget->drawBatch(pipelineBuilder, batch);
607}
608
robertphillipsea461502015-05-26 11:38:03 -0700609void GrDrawContext::drawPath(GrRenderTarget* rt,
610 const GrClip& clip,
611 const GrPaint& paint,
612 const SkMatrix& viewMatrix,
613 const SkPath& path,
614 const GrStrokeInfo& strokeInfo) {
615 RETURN_IF_ABANDONED
616 if (path.isEmpty()) {
617 if (path.isInverseFillType()) {
618 this->drawPaint(rt, clip, paint, viewMatrix);
619 }
620 return;
621 }
622
623 GrColor color = paint.getColor();
624
625 // Note that internalDrawPath may sw-rasterize the path into a scratch texture.
626 // Scratch textures can be recycled after they are returned to the texture
627 // cache. This presents a potential hazard for buffered drawing. However,
628 // the writePixels that uploads to the scratch will perform a flush so we're
629 // OK.
630 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700631 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700632 return;
633 }
634
joshualitt7b670db2015-07-09 13:25:02 -0700635 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700636 if (!strokeInfo.isDashed()) {
637 bool useCoverageAA = paint.isAntiAlias() &&
vbuzinovdded6962015-06-12 08:59:45 -0700638 !pipelineBuilder.getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -0700639
640 if (useCoverageAA && strokeInfo.getWidth() < 0 && !path.isConvex()) {
641 // Concave AA paths are expensive - try to avoid them for special cases
642 SkRect rects[2];
643
joshualittf9c5db22015-07-10 11:31:01 -0700644 if (is_nested_rects(viewMatrix, path, strokeInfo, rects)) {
joshualittd2b23e02015-08-21 10:53:34 -0700645 SkAutoTUnref<GrDrawBatch> batch(GrRectBatchFactory::CreateAAFillNestedRects(
bsalomonabd30f52015-08-13 13:34:48 -0700646 color, viewMatrix, rects));
joshualitt14205b12015-08-10 11:40:56 -0700647 fDrawTarget->drawBatch(pipelineBuilder, batch);
robertphillipsea461502015-05-26 11:38:03 -0700648 return;
649 }
650 }
651 SkRect ovalRect;
652 bool isOval = path.isOval(&ovalRect);
653
654 if (isOval && !path.isInverseFillType()) {
655 if (GrOvalRenderer::DrawOval(fDrawTarget,
joshualittae3d63a2015-07-13 08:44:06 -0700656 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700657 color,
658 viewMatrix,
659 paint.isAntiAlias(),
660 ovalRect,
661 strokeInfo)) {
662 return;
663 }
664 }
665 }
666 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
667 path, strokeInfo);
668}
669
670void GrDrawContext::internalDrawPath(GrDrawTarget* target,
671 GrPipelineBuilder* pipelineBuilder,
672 const SkMatrix& viewMatrix,
673 GrColor color,
674 bool useAA,
675 const SkPath& path,
676 const GrStrokeInfo& strokeInfo) {
677 RETURN_IF_ABANDONED
678 SkASSERT(!path.isEmpty());
679
680
681 // An Assumption here is that path renderer would use some form of tweaking
682 // the src color (either the input alpha or in the frag shader) to implement
683 // aa. If we have some future driver-mojo path AA that can do the right
684 // thing WRT to the blend then we'll need some query on the PR.
685 bool useCoverageAA = useAA &&
vbuzinovdded6962015-06-12 08:59:45 -0700686 !pipelineBuilder->getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -0700687
688
689 GrPathRendererChain::DrawType type =
690 useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType :
691 GrPathRendererChain::kColor_DrawType;
692
693 const SkPath* pathPtr = &path;
694 SkTLazy<SkPath> tmpPath;
695 const GrStrokeInfo* strokeInfoPtr = &strokeInfo;
696
697 // Try a 1st time without stroking the path and without allowing the SW renderer
698 GrPathRenderer* pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr,
699 *strokeInfoPtr, false, type);
700
701 GrStrokeInfo dashlessStrokeInfo(strokeInfo, false);
halcanary96fcdcc2015-08-27 07:41:13 -0700702 if (nullptr == pr && strokeInfo.isDashed()) {
robertphillipsea461502015-05-26 11:38:03 -0700703 // It didn't work above, so try again with dashed stroke converted to a dashless stroke.
704 if (!strokeInfo.applyDashToPath(tmpPath.init(), &dashlessStrokeInfo, *pathPtr)) {
705 return;
706 }
707 pathPtr = tmpPath.get();
708 if (pathPtr->isEmpty()) {
709 return;
710 }
711 strokeInfoPtr = &dashlessStrokeInfo;
712 pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
713 false, type);
714 }
715
halcanary96fcdcc2015-08-27 07:41:13 -0700716 if (nullptr == pr) {
717 if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*strokeInfoPtr, viewMatrix, nullptr) &&
robertphillipsea461502015-05-26 11:38:03 -0700718 !strokeInfoPtr->isFillStyle()) {
719 // It didn't work above, so try again with stroke converted to a fill.
720 if (!tmpPath.isValid()) {
721 tmpPath.init();
722 }
723 dashlessStrokeInfo.setResScale(SkScalarAbs(viewMatrix.getMaxScale()));
724 if (!dashlessStrokeInfo.applyToPath(tmpPath.get(), *pathPtr)) {
725 return;
726 }
727 pathPtr = tmpPath.get();
728 if (pathPtr->isEmpty()) {
729 return;
730 }
731 dashlessStrokeInfo.setFillStyle();
732 strokeInfoPtr = &dashlessStrokeInfo;
733 }
734
735 // This time, allow SW renderer
736 pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
737 true, type);
738 }
739
halcanary96fcdcc2015-08-27 07:41:13 -0700740 if (nullptr == pr) {
robertphillipsea461502015-05-26 11:38:03 -0700741#ifdef SK_DEBUG
742 SkDebugf("Unable to find path renderer compatible with path.\n");
743#endif
744 return;
745 }
746
bsalomon0aff2fa2015-07-31 06:48:27 -0700747 GrPathRenderer::DrawPathArgs args;
748 args.fTarget = target;
749 args.fResourceProvider = fContext->resourceProvider();
750 args.fPipelineBuilder = pipelineBuilder;
751 args.fColor = color;
752 args.fViewMatrix = &viewMatrix;
753 args.fPath = pathPtr;
754 args.fStroke = strokeInfoPtr;
755 args.fAntiAlias = useCoverageAA;
756 pr->drawPath(args);
robertphillipsea461502015-05-26 11:38:03 -0700757}
758
robertphillipsea461502015-05-26 11:38:03 -0700759bool GrDrawContext::prepareToDraw(GrRenderTarget* rt) {
760 RETURN_FALSE_IF_ABANDONED
761
762 ASSERT_OWNED_RESOURCE(rt);
763 SkASSERT(rt);
764 return true;
765}
766
bsalomonabd30f52015-08-13 13:34:48 -0700767void GrDrawContext::drawBatch(GrPipelineBuilder* pipelineBuilder, GrDrawBatch* batch) {
joshualitt1c735482015-07-13 08:08:25 -0700768 fDrawTarget->drawBatch(*pipelineBuilder, batch);
robertphillips2334fb62015-06-17 05:43:33 -0700769}