blob: 3d3be749d0668b5f95dadc6a01b629c738c0f934 [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() &&
bsalomonafcd7cd2015-08-31 12:39:41 -070065 fSurfaceProps.isUseDeviceIndependentFonts()) {
robertphillips2334fb62015-06-17 05:43:33 -070066 GrStencilAttachment* sb = renderTarget->renderTargetPriv().attachStencilAttachment();
67 if (sb) {
robertphillipsf6703fa2015-09-01 05:36:47 -070068 return GrStencilAndCoverTextContext::Create(fContext, surfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -070069 }
70 }
71
robertphillipsf6703fa2015-09-01 05:36:47 -070072 return GrAtlasTextContext::Create(fContext, 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
robertphillipsf6703fa2015-09-01 05:36:47 -070084 fTextContext->drawText(this, rt, clip, grPaint, skPaint, viewMatrix,
robertphillips2334fb62015-06-17 05:43:33 -070085 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
robertphillipsf6703fa2015-09-01 05:36:47 -070098 fTextContext->drawPosText(this, rt, clip, grPaint, skPaint, viewMatrix, text, byteLength,
99 pos, scalarsPerPosition, offset, clipBounds);
robertphillips2334fb62015-06-17 05:43:33 -0700100
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
robertphillipsf6703fa2015-09-01 05:36:47 -0700110 fTextContext->drawTextBlob(this, rt,
111 clip, skPaint, viewMatrix, blob, x, y, filter, clipBounds);
robertphillipsea461502015-05-26 11:38:03 -0700112}
113
bsalomon1fcc01c2015-09-09 09:48:06 -0700114void GrDrawContext::drawPathsFromRange(const GrPipelineBuilder* pipelineBuilder,
joshualittf2384692015-09-10 11:00:51 -0700115 const SkMatrix& viewMatrix,
116 const SkMatrix& localMatrix,
117 GrColor color,
bsalomon1fcc01c2015-09-09 09:48:06 -0700118 GrPathRangeDraw* draw,
119 int /*GrPathRendering::FillType*/ fill) {
joshualittf2384692015-09-10 11:00:51 -0700120 fDrawTarget->drawPathsFromRange(*pipelineBuilder, viewMatrix, localMatrix, color, draw,
bsalomon1fcc01c2015-09-09 09:48:06 -0700121 (GrPathRendering::FillType) fill);
robertphillipsea461502015-05-26 11:38:03 -0700122}
123
124void GrDrawContext::discard(GrRenderTarget* renderTarget) {
125 RETURN_IF_ABANDONED
126 SkASSERT(renderTarget);
127 AutoCheckFlush acf(fContext);
128 if (!this->prepareToDraw(renderTarget)) {
129 return;
130 }
131 fDrawTarget->discard(renderTarget);
132}
133
134void GrDrawContext::clear(GrRenderTarget* renderTarget,
135 const SkIRect* rect,
136 const GrColor color,
137 bool canIgnoreRect) {
138 RETURN_IF_ABANDONED
139 SkASSERT(renderTarget);
140
141 AutoCheckFlush acf(fContext);
142 if (!this->prepareToDraw(renderTarget)) {
143 return;
144 }
145 fDrawTarget->clear(rect, color, canIgnoreRect, renderTarget);
146}
147
148
149void GrDrawContext::drawPaint(GrRenderTarget* rt,
150 const GrClip& clip,
151 const GrPaint& origPaint,
152 const SkMatrix& viewMatrix) {
153 RETURN_IF_ABANDONED
154 // set rect to be big enough to fill the space, but not super-huge, so we
155 // don't overflow fixed-point implementations
156 SkRect r;
157 r.setLTRB(0, 0,
158 SkIntToScalar(rt->width()),
159 SkIntToScalar(rt->height()));
160 SkTCopyOnFirstWrite<GrPaint> paint(origPaint);
161
162 // by definition this fills the entire clip, no need for AA
163 if (paint->isAntiAlias()) {
164 paint.writable()->setAntiAlias(false);
165 }
166
167 bool isPerspective = viewMatrix.hasPerspective();
168
169 // We attempt to map r by the inverse matrix and draw that. mapRect will
170 // map the four corners and bound them with a new rect. This will not
171 // produce a correct result for some perspective matrices.
172 if (!isPerspective) {
173 SkMatrix inverse;
174 if (!viewMatrix.invert(&inverse)) {
175 SkDebugf("Could not invert matrix\n");
176 return;
177 }
178 inverse.mapRect(&r);
179 this->drawRect(rt, clip, *paint, viewMatrix, r);
180 } else {
181 SkMatrix localMatrix;
182 if (!viewMatrix.invert(&localMatrix)) {
183 SkDebugf("Could not invert matrix\n");
184 return;
185 }
186
187 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700188 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700189 return;
190 }
191
joshualitt7b670db2015-07-09 13:25:02 -0700192 GrPipelineBuilder pipelineBuilder(*paint, rt, clip);
joshualittd2b23e02015-08-21 10:53:34 -0700193 fDrawTarget->drawNonAARect(pipelineBuilder,
194 paint->getColor(),
195 SkMatrix::I(),
196 r,
197 localMatrix);
robertphillipsea461502015-05-26 11:38:03 -0700198 }
199}
200
robertphillipsea461502015-05-26 11:38:03 -0700201static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) {
202 return point.fX >= rect.fLeft && point.fX <= rect.fRight &&
203 point.fY >= rect.fTop && point.fY <= rect.fBottom;
204}
205
robertphillipsea461502015-05-26 11:38:03 -0700206void GrDrawContext::drawRect(GrRenderTarget* rt,
207 const GrClip& clip,
208 const GrPaint& paint,
209 const SkMatrix& viewMatrix,
210 const SkRect& rect,
211 const GrStrokeInfo* strokeInfo) {
212 RETURN_IF_ABANDONED
213 if (strokeInfo && strokeInfo->isDashed()) {
214 SkPath path;
215 path.setIsVolatile(true);
216 path.addRect(rect);
217 this->drawPath(rt, clip, paint, viewMatrix, path, *strokeInfo);
218 return;
219 }
220
221 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700222 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700223 return;
224 }
225
joshualitt7b670db2015-07-09 13:25:02 -0700226 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
227
halcanary96fcdcc2015-08-27 07:41:13 -0700228 SkScalar width = nullptr == strokeInfo ? -1 : strokeInfo->getWidth();
robertphillipsea461502015-05-26 11:38:03 -0700229
230 // Check if this is a full RT draw and can be replaced with a clear. We don't bother checking
231 // cases where the RT is fully inside a stroke.
232 if (width < 0) {
233 SkRect rtRect;
234 pipelineBuilder.getRenderTarget()->getBoundsRect(&rtRect);
235 SkRect clipSpaceRTRect = rtRect;
236 bool checkClip = GrClip::kWideOpen_ClipType != clip.clipType();
237 if (checkClip) {
238 clipSpaceRTRect.offset(SkIntToScalar(clip.origin().fX),
239 SkIntToScalar(clip.origin().fY));
240 }
241 // Does the clip contain the entire RT?
242 if (!checkClip || clip.quickContains(clipSpaceRTRect)) {
243 SkMatrix invM;
244 if (!viewMatrix.invert(&invM)) {
245 return;
246 }
247 // Does the rect bound the RT?
248 SkPoint srcSpaceRTQuad[4];
249 invM.mapRectToQuad(srcSpaceRTQuad, rtRect);
250 if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) &&
251 rect_contains_inclusive(rect, srcSpaceRTQuad[1]) &&
252 rect_contains_inclusive(rect, srcSpaceRTQuad[2]) &&
253 rect_contains_inclusive(rect, srcSpaceRTQuad[3])) {
254 // Will it blend?
255 GrColor clearColor;
cdalton1fa45722015-06-02 10:43:39 -0700256 if (paint.isConstantBlendedColor(&clearColor)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700257 fDrawTarget->clear(nullptr, clearColor, true, rt);
robertphillipsea461502015-05-26 11:38:03 -0700258 return;
259 }
260 }
261 }
262 }
263
264 GrColor color = paint.getColor();
vbuzinovdded6962015-06-12 08:59:45 -0700265 bool needAA = paint.isAntiAlias() &&
266 !pipelineBuilder.getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -0700267
joshualitt9be0b002015-08-19 11:50:51 -0700268 // The fill path can handle rotation but not skew
269 // The stroke path needs the rect to remain axis aligned (no rotation or skew)
robertphillipsfac9ceb2015-09-03 08:32:08 -0700270 // None of our AA draw rect calls can handle perspective yet
joshualitt9be0b002015-08-19 11:50:51 -0700271 bool canApplyAA = width >=0 ? viewMatrix.rectStaysRect() : viewMatrix.preservesRightAngles();
272
273 if (needAA && canApplyAA) {
robertphillipsfac9ceb2015-09-03 08:32:08 -0700274 SkASSERT(!viewMatrix.hasPerspective());
joshualitt9be0b002015-08-19 11:50:51 -0700275 SkRect devBoundRect;
276 viewMatrix.mapRect(&devBoundRect, rect);
bsalomonabd30f52015-08-13 13:34:48 -0700277 SkAutoTUnref<GrDrawBatch> batch;
robertphillipsea461502015-05-26 11:38:03 -0700278 if (width >= 0) {
joshualittd2b23e02015-08-21 10:53:34 -0700279 batch.reset(GrRectBatchFactory::CreateAAStroke(color, viewMatrix, rect, devBoundRect,
joshualitt14205b12015-08-10 11:40:56 -0700280 *strokeInfo));
robertphillipsea461502015-05-26 11:38:03 -0700281 } else {
joshualittd2b23e02015-08-21 10:53:34 -0700282 batch.reset(GrRectBatchFactory::CreateAAFill(color, viewMatrix, rect, devBoundRect));
robertphillipsea461502015-05-26 11:38:03 -0700283 }
joshualitt14205b12015-08-10 11:40:56 -0700284 fDrawTarget->drawBatch(pipelineBuilder, batch);
robertphillipsea461502015-05-26 11:38:03 -0700285 return;
286 }
287
288 if (width >= 0) {
robertphillipsea461502015-05-26 11:38:03 -0700289 // Non-AA hairlines are snapped to pixel centers to make which pixels are hit deterministic
vbuzinovdded6962015-06-12 08:59:45 -0700290 bool snapToPixelCenters = (0 == width && !rt->isUnifiedMultisampled());
joshualittd2b23e02015-08-21 10:53:34 -0700291 SkAutoTUnref<GrDrawBatch> batch(GrRectBatchFactory::CreateNonAAStroke(
bsalomonabd30f52015-08-13 13:34:48 -0700292 color, viewMatrix, rect, width, snapToPixelCenters));
robertphillipsea461502015-05-26 11:38:03 -0700293
294 // Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of
295 // hairline rects. We jam all the vertices to pixel centers to avoid this, but not when MSAA
296 // is enabled because it can cause ugly artifacts.
297 pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_Flag,
298 snapToPixelCenters);
joshualitt1c735482015-07-13 08:08:25 -0700299 fDrawTarget->drawBatch(pipelineBuilder, batch);
robertphillipsea461502015-05-26 11:38:03 -0700300 } else {
301 // filled BW rect
joshualittd2b23e02015-08-21 10:53:34 -0700302 fDrawTarget->drawNonAARect(pipelineBuilder, color, viewMatrix, rect);
robertphillipsea461502015-05-26 11:38:03 -0700303 }
304}
305
306void GrDrawContext::drawNonAARectToRect(GrRenderTarget* rt,
307 const GrClip& clip,
308 const GrPaint& paint,
309 const SkMatrix& viewMatrix,
310 const SkRect& rectToDraw,
joshualittb6b513b2015-08-21 10:25:18 -0700311 const SkRect& localRect) {
robertphillipsea461502015-05-26 11:38:03 -0700312 RETURN_IF_ABANDONED
313 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700314 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700315 return;
316 }
317
joshualitt7b670db2015-07-09 13:25:02 -0700318 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
joshualittd2b23e02015-08-21 10:53:34 -0700319 fDrawTarget->drawNonAARect(pipelineBuilder,
320 paint.getColor(),
321 viewMatrix,
322 rectToDraw,
323 localRect);
joshualittb6b513b2015-08-21 10:25:18 -0700324}
325
326void GrDrawContext::drawNonAARectWithLocalMatrix(GrRenderTarget* rt,
327 const GrClip& clip,
328 const GrPaint& paint,
329 const SkMatrix& viewMatrix,
330 const SkRect& rectToDraw,
331 const SkMatrix& localMatrix) {
332 RETURN_IF_ABANDONED
333 AutoCheckFlush acf(fContext);
334 if (!this->prepareToDraw(rt)) {
335 return;
336 }
337
338 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
joshualittd2b23e02015-08-21 10:53:34 -0700339 fDrawTarget->drawNonAARect(pipelineBuilder,
340 paint.getColor(),
341 viewMatrix,
342 rectToDraw,
343 localMatrix);
robertphillipsea461502015-05-26 11:38:03 -0700344}
345
robertphillipsea461502015-05-26 11:38:03 -0700346void GrDrawContext::drawVertices(GrRenderTarget* rt,
347 const GrClip& clip,
348 const GrPaint& paint,
349 const SkMatrix& viewMatrix,
350 GrPrimitiveType primitiveType,
351 int vertexCount,
352 const SkPoint positions[],
353 const SkPoint texCoords[],
354 const GrColor colors[],
355 const uint16_t indices[],
356 int indexCount) {
357 RETURN_IF_ABANDONED
358 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700359 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700360 return;
361 }
362
joshualitt7b670db2015-07-09 13:25:02 -0700363 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
364
robertphillipsea461502015-05-26 11:38:03 -0700365 // TODO clients should give us bounds
366 SkRect bounds;
367 if (!bounds.setBoundsCheck(positions, vertexCount)) {
368 SkDebugf("drawVertices call empty bounds\n");
369 return;
370 }
371
372 viewMatrix.mapRect(&bounds);
373
374 // If we don't have AA then we outset for a half pixel in each direction to account for
375 // snapping
376 if (!paint.isAntiAlias()) {
377 bounds.outset(0.5f, 0.5f);
378 }
379
joshualitt2771b562015-08-07 12:46:26 -0700380 GrDrawVerticesBatch::Geometry geometry;
robertphillipsea461502015-05-26 11:38:03 -0700381 geometry.fColor = paint.getColor();
bsalomonabd30f52015-08-13 13:34:48 -0700382 SkAutoTUnref<GrDrawBatch> batch(GrDrawVerticesBatch::Create(geometry, primitiveType, viewMatrix,
383 positions, vertexCount, indices,
384 indexCount, colors, texCoords,
385 bounds));
robertphillipsea461502015-05-26 11:38:03 -0700386
joshualitt1c735482015-07-13 08:08:25 -0700387 fDrawTarget->drawBatch(pipelineBuilder, batch);
robertphillipsea461502015-05-26 11:38:03 -0700388}
389
390///////////////////////////////////////////////////////////////////////////////
391
jvanverth31ff7622015-08-07 10:09:28 -0700392void GrDrawContext::drawAtlas(GrRenderTarget* rt,
393 const GrClip& clip,
394 const GrPaint& paint,
395 const SkMatrix& viewMatrix,
396 int spriteCount,
397 const SkRSXform xform[],
398 const SkRect texRect[],
399 const SkColor colors[]) {
400 RETURN_IF_ABANDONED
401 AutoCheckFlush acf(fContext);
402 if (!this->prepareToDraw(rt)) {
403 return;
404 }
405
406 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
407
jvanverth14b88032015-08-07 12:18:54 -0700408 GrDrawAtlasBatch::Geometry geometry;
jvanverth31ff7622015-08-07 10:09:28 -0700409 geometry.fColor = paint.getColor();
bsalomonabd30f52015-08-13 13:34:48 -0700410 SkAutoTUnref<GrDrawBatch> batch(GrDrawAtlasBatch::Create(geometry, viewMatrix, spriteCount,
411 xform, texRect, colors));
jvanverth31ff7622015-08-07 10:09:28 -0700412
413 fDrawTarget->drawBatch(pipelineBuilder, batch);
414}
415
416///////////////////////////////////////////////////////////////////////////////
417
robertphillipsea461502015-05-26 11:38:03 -0700418void GrDrawContext::drawRRect(GrRenderTarget*rt,
419 const GrClip& clip,
420 const GrPaint& paint,
421 const SkMatrix& viewMatrix,
422 const SkRRect& rrect,
423 const GrStrokeInfo& strokeInfo) {
424 RETURN_IF_ABANDONED
425 if (rrect.isEmpty()) {
426 return;
427 }
428
429 if (strokeInfo.isDashed()) {
430 SkPath path;
431 path.setIsVolatile(true);
432 path.addRRect(rrect);
433 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
434 return;
435 }
436
437 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700438 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700439 return;
440 }
441
joshualitt7b670db2015-07-09 13:25:02 -0700442 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700443 GrColor color = paint.getColor();
444 if (!GrOvalRenderer::DrawRRect(fDrawTarget,
joshualittae3d63a2015-07-13 08:44:06 -0700445 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700446 color,
447 viewMatrix,
448 paint.isAntiAlias(),
449 rrect,
450 strokeInfo)) {
451 SkPath path;
452 path.setIsVolatile(true);
453 path.addRRect(rrect);
454 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
455 paint.isAntiAlias(), path, strokeInfo);
456 }
457}
458
459///////////////////////////////////////////////////////////////////////////////
460
461void GrDrawContext::drawDRRect(GrRenderTarget* rt,
462 const GrClip& clip,
463 const GrPaint& paint,
464 const SkMatrix& viewMatrix,
465 const SkRRect& outer,
466 const SkRRect& inner) {
467 RETURN_IF_ABANDONED
468 if (outer.isEmpty()) {
469 return;
470 }
471
472 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700473 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700474 return;
475 }
476
joshualitt7b670db2015-07-09 13:25:02 -0700477 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700478 GrColor color = paint.getColor();
479 if (!GrOvalRenderer::DrawDRRect(fDrawTarget,
joshualittae3d63a2015-07-13 08:44:06 -0700480 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700481 color,
482 viewMatrix,
483 paint.isAntiAlias(),
484 outer,
485 inner)) {
486 SkPath path;
487 path.setIsVolatile(true);
488 path.addRRect(inner);
489 path.addRRect(outer);
490 path.setFillType(SkPath::kEvenOdd_FillType);
491
492 GrStrokeInfo fillRec(SkStrokeRec::kFill_InitStyle);
493 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
494 paint.isAntiAlias(), path, fillRec);
495 }
496}
497
498///////////////////////////////////////////////////////////////////////////////
499
500void GrDrawContext::drawOval(GrRenderTarget* rt,
501 const GrClip& clip,
502 const GrPaint& paint,
503 const SkMatrix& viewMatrix,
504 const SkRect& oval,
505 const GrStrokeInfo& strokeInfo) {
506 RETURN_IF_ABANDONED
507 if (oval.isEmpty()) {
508 return;
509 }
510
511 if (strokeInfo.isDashed()) {
512 SkPath path;
513 path.setIsVolatile(true);
514 path.addOval(oval);
515 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
516 return;
517 }
518
519 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700520 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700521 return;
522 }
523
joshualitt7b670db2015-07-09 13:25:02 -0700524 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700525 GrColor color = paint.getColor();
526 if (!GrOvalRenderer::DrawOval(fDrawTarget,
joshualittae3d63a2015-07-13 08:44:06 -0700527 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700528 color,
529 viewMatrix,
530 paint.isAntiAlias(),
531 oval,
532 strokeInfo)) {
533 SkPath path;
534 path.setIsVolatile(true);
535 path.addOval(oval);
536 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
537 paint.isAntiAlias(), path, strokeInfo);
538 }
539}
540
541// Can 'path' be drawn as a pair of filled nested rectangles?
joshualittf9c5db22015-07-10 11:31:01 -0700542static bool is_nested_rects(const SkMatrix& viewMatrix,
robertphillipsea461502015-05-26 11:38:03 -0700543 const SkPath& path,
544 const SkStrokeRec& stroke,
545 SkRect rects[2]) {
546 SkASSERT(stroke.isFillStyle());
547
548 if (path.isInverseFillType()) {
549 return false;
550 }
551
552 // TODO: this restriction could be lifted if we were willing to apply
553 // the matrix to all the points individually rather than just to the rect
554 if (!viewMatrix.preservesAxisAlignment()) {
555 return false;
556 }
557
558 SkPath::Direction dirs[2];
559 if (!path.isNestedFillRects(rects, dirs)) {
560 return false;
561 }
562
563 if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) {
564 // The two rects need to be wound opposite to each other
565 return false;
566 }
567
568 // Right now, nested rects where the margin is not the same width
569 // all around do not render correctly
570 const SkScalar* outer = rects[0].asScalars();
571 const SkScalar* inner = rects[1].asScalars();
572
573 bool allEq = true;
574
575 SkScalar margin = SkScalarAbs(outer[0] - inner[0]);
576 bool allGoE1 = margin >= SK_Scalar1;
577
578 for (int i = 1; i < 4; ++i) {
579 SkScalar temp = SkScalarAbs(outer[i] - inner[i]);
580 if (temp < SK_Scalar1) {
581 allGoE1 = false;
582 }
583 if (!SkScalarNearlyEqual(margin, temp)) {
584 allEq = false;
585 }
586 }
587
588 return allEq || allGoE1;
589}
590
joshualittb7ee1bf2015-08-10 11:59:02 -0700591void GrDrawContext::drawBatch(GrRenderTarget* rt, const GrClip& clip,
bsalomonabd30f52015-08-13 13:34:48 -0700592 const GrPaint& paint, GrDrawBatch* batch) {
joshualittb7ee1bf2015-08-10 11:59:02 -0700593 RETURN_IF_ABANDONED
594
595 AutoCheckFlush acf(fContext);
596 if (!this->prepareToDraw(rt)) {
597 return;
598 }
599
600 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
601 fDrawTarget->drawBatch(pipelineBuilder, batch);
602}
603
robertphillipsea461502015-05-26 11:38:03 -0700604void GrDrawContext::drawPath(GrRenderTarget* rt,
605 const GrClip& clip,
606 const GrPaint& paint,
607 const SkMatrix& viewMatrix,
608 const SkPath& path,
609 const GrStrokeInfo& strokeInfo) {
610 RETURN_IF_ABANDONED
611 if (path.isEmpty()) {
612 if (path.isInverseFillType()) {
613 this->drawPaint(rt, clip, paint, viewMatrix);
614 }
615 return;
616 }
617
618 GrColor color = paint.getColor();
619
620 // Note that internalDrawPath may sw-rasterize the path into a scratch texture.
621 // Scratch textures can be recycled after they are returned to the texture
622 // cache. This presents a potential hazard for buffered drawing. However,
623 // the writePixels that uploads to the scratch will perform a flush so we're
624 // OK.
625 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700626 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700627 return;
628 }
629
joshualitt7b670db2015-07-09 13:25:02 -0700630 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700631 if (!strokeInfo.isDashed()) {
632 bool useCoverageAA = paint.isAntiAlias() &&
vbuzinovdded6962015-06-12 08:59:45 -0700633 !pipelineBuilder.getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -0700634
635 if (useCoverageAA && strokeInfo.getWidth() < 0 && !path.isConvex()) {
636 // Concave AA paths are expensive - try to avoid them for special cases
637 SkRect rects[2];
638
joshualittf9c5db22015-07-10 11:31:01 -0700639 if (is_nested_rects(viewMatrix, path, strokeInfo, rects)) {
joshualittd2b23e02015-08-21 10:53:34 -0700640 SkAutoTUnref<GrDrawBatch> batch(GrRectBatchFactory::CreateAAFillNestedRects(
bsalomonabd30f52015-08-13 13:34:48 -0700641 color, viewMatrix, rects));
joshualitt14205b12015-08-10 11:40:56 -0700642 fDrawTarget->drawBatch(pipelineBuilder, batch);
robertphillipsea461502015-05-26 11:38:03 -0700643 return;
644 }
645 }
646 SkRect ovalRect;
647 bool isOval = path.isOval(&ovalRect);
648
649 if (isOval && !path.isInverseFillType()) {
650 if (GrOvalRenderer::DrawOval(fDrawTarget,
joshualittae3d63a2015-07-13 08:44:06 -0700651 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700652 color,
653 viewMatrix,
654 paint.isAntiAlias(),
655 ovalRect,
656 strokeInfo)) {
657 return;
658 }
659 }
660 }
661 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
662 path, strokeInfo);
663}
664
665void GrDrawContext::internalDrawPath(GrDrawTarget* target,
666 GrPipelineBuilder* pipelineBuilder,
667 const SkMatrix& viewMatrix,
668 GrColor color,
669 bool useAA,
670 const SkPath& path,
671 const GrStrokeInfo& strokeInfo) {
672 RETURN_IF_ABANDONED
673 SkASSERT(!path.isEmpty());
674
675
676 // An Assumption here is that path renderer would use some form of tweaking
677 // the src color (either the input alpha or in the frag shader) to implement
678 // aa. If we have some future driver-mojo path AA that can do the right
679 // thing WRT to the blend then we'll need some query on the PR.
680 bool useCoverageAA = useAA &&
vbuzinovdded6962015-06-12 08:59:45 -0700681 !pipelineBuilder->getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -0700682
683
684 GrPathRendererChain::DrawType type =
685 useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType :
686 GrPathRendererChain::kColor_DrawType;
687
688 const SkPath* pathPtr = &path;
689 SkTLazy<SkPath> tmpPath;
690 const GrStrokeInfo* strokeInfoPtr = &strokeInfo;
691
692 // Try a 1st time without stroking the path and without allowing the SW renderer
693 GrPathRenderer* pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr,
694 *strokeInfoPtr, false, type);
695
696 GrStrokeInfo dashlessStrokeInfo(strokeInfo, false);
halcanary96fcdcc2015-08-27 07:41:13 -0700697 if (nullptr == pr && strokeInfo.isDashed()) {
robertphillipsea461502015-05-26 11:38:03 -0700698 // It didn't work above, so try again with dashed stroke converted to a dashless stroke.
699 if (!strokeInfo.applyDashToPath(tmpPath.init(), &dashlessStrokeInfo, *pathPtr)) {
700 return;
701 }
702 pathPtr = tmpPath.get();
703 if (pathPtr->isEmpty()) {
704 return;
705 }
706 strokeInfoPtr = &dashlessStrokeInfo;
707 pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
708 false, type);
709 }
710
halcanary96fcdcc2015-08-27 07:41:13 -0700711 if (nullptr == pr) {
712 if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*strokeInfoPtr, viewMatrix, nullptr) &&
robertphillipsea461502015-05-26 11:38:03 -0700713 !strokeInfoPtr->isFillStyle()) {
714 // It didn't work above, so try again with stroke converted to a fill.
715 if (!tmpPath.isValid()) {
716 tmpPath.init();
717 }
718 dashlessStrokeInfo.setResScale(SkScalarAbs(viewMatrix.getMaxScale()));
719 if (!dashlessStrokeInfo.applyToPath(tmpPath.get(), *pathPtr)) {
720 return;
721 }
722 pathPtr = tmpPath.get();
723 if (pathPtr->isEmpty()) {
724 return;
725 }
726 dashlessStrokeInfo.setFillStyle();
727 strokeInfoPtr = &dashlessStrokeInfo;
728 }
729
730 // This time, allow SW renderer
731 pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
732 true, type);
733 }
734
halcanary96fcdcc2015-08-27 07:41:13 -0700735 if (nullptr == pr) {
robertphillipsea461502015-05-26 11:38:03 -0700736#ifdef SK_DEBUG
737 SkDebugf("Unable to find path renderer compatible with path.\n");
738#endif
739 return;
740 }
741
bsalomon0aff2fa2015-07-31 06:48:27 -0700742 GrPathRenderer::DrawPathArgs args;
743 args.fTarget = target;
744 args.fResourceProvider = fContext->resourceProvider();
745 args.fPipelineBuilder = pipelineBuilder;
746 args.fColor = color;
747 args.fViewMatrix = &viewMatrix;
748 args.fPath = pathPtr;
749 args.fStroke = strokeInfoPtr;
750 args.fAntiAlias = useCoverageAA;
751 pr->drawPath(args);
robertphillipsea461502015-05-26 11:38:03 -0700752}
753
robertphillipsea461502015-05-26 11:38:03 -0700754bool GrDrawContext::prepareToDraw(GrRenderTarget* rt) {
755 RETURN_FALSE_IF_ABANDONED
756
757 ASSERT_OWNED_RESOURCE(rt);
758 SkASSERT(rt);
759 return true;
760}
761
bsalomonabd30f52015-08-13 13:34:48 -0700762void GrDrawContext::drawBatch(GrPipelineBuilder* pipelineBuilder, GrDrawBatch* batch) {
joshualitt1c735482015-07-13 08:08:25 -0700763 fDrawTarget->drawBatch(*pipelineBuilder, batch);
robertphillips2334fb62015-06-17 05:43:33 -0700764}