blob: 94fcee03134a375d00b199440c4aac10ac7b1518 [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()) {
egdanielec00d942015-09-14 12:56:10 -070066 GrStencilAttachment* sb =
67 fContext->resourceProvider()->attachStencilAttachment(renderTarget);
robertphillips2334fb62015-06-17 05:43:33 -070068 if (sb) {
robertphillipsf6703fa2015-09-01 05:36:47 -070069 return GrStencilAndCoverTextContext::Create(fContext, surfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -070070 }
71 }
72
robertphillipsf6703fa2015-09-01 05:36:47 -070073 return GrAtlasTextContext::Create(fContext, surfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -070074}
75
76void GrDrawContext::drawText(GrRenderTarget* rt, const GrClip& clip, const GrPaint& grPaint,
77 const SkPaint& skPaint,
78 const SkMatrix& viewMatrix,
79 const char text[], size_t byteLength,
80 SkScalar x, SkScalar y, const SkIRect& clipBounds) {
81 if (!fTextContext) {
robertphillipsfcf78292015-06-19 11:49:52 -070082 fTextContext = this->createTextContext(rt, fSurfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -070083 }
84
robertphillipsf6703fa2015-09-01 05:36:47 -070085 fTextContext->drawText(this, rt, clip, grPaint, skPaint, viewMatrix,
robertphillips2334fb62015-06-17 05:43:33 -070086 text, byteLength, x, y, clipBounds);
87
88}
89void GrDrawContext::drawPosText(GrRenderTarget* rt, const GrClip& clip, const GrPaint& grPaint,
90 const SkPaint& skPaint,
91 const SkMatrix& viewMatrix,
92 const char text[], size_t byteLength,
93 const SkScalar pos[], int scalarsPerPosition,
94 const SkPoint& offset, const SkIRect& clipBounds) {
95 if (!fTextContext) {
robertphillipsfcf78292015-06-19 11:49:52 -070096 fTextContext = this->createTextContext(rt, fSurfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -070097 }
98
robertphillipsf6703fa2015-09-01 05:36:47 -070099 fTextContext->drawPosText(this, rt, clip, grPaint, skPaint, viewMatrix, text, byteLength,
100 pos, scalarsPerPosition, offset, clipBounds);
robertphillips2334fb62015-06-17 05:43:33 -0700101
102}
103void GrDrawContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, const SkPaint& skPaint,
104 const SkMatrix& viewMatrix, const SkTextBlob* blob,
105 SkScalar x, SkScalar y,
106 SkDrawFilter* filter, const SkIRect& clipBounds) {
107 if (!fTextContext) {
robertphillipsfcf78292015-06-19 11:49:52 -0700108 fTextContext = this->createTextContext(rt, fSurfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -0700109 }
110
robertphillipsf6703fa2015-09-01 05:36:47 -0700111 fTextContext->drawTextBlob(this, rt,
112 clip, skPaint, viewMatrix, blob, x, y, filter, clipBounds);
robertphillipsea461502015-05-26 11:38:03 -0700113}
114
bsalomon1fcc01c2015-09-09 09:48:06 -0700115void GrDrawContext::drawPathsFromRange(const GrPipelineBuilder* pipelineBuilder,
joshualittf2384692015-09-10 11:00:51 -0700116 const SkMatrix& viewMatrix,
117 const SkMatrix& localMatrix,
118 GrColor color,
bsalomon1fcc01c2015-09-09 09:48:06 -0700119 GrPathRangeDraw* draw,
120 int /*GrPathRendering::FillType*/ fill) {
joshualittf2384692015-09-10 11:00:51 -0700121 fDrawTarget->drawPathsFromRange(*pipelineBuilder, viewMatrix, localMatrix, color, draw,
bsalomon1fcc01c2015-09-09 09:48:06 -0700122 (GrPathRendering::FillType) fill);
robertphillipsea461502015-05-26 11:38:03 -0700123}
124
125void GrDrawContext::discard(GrRenderTarget* renderTarget) {
126 RETURN_IF_ABANDONED
127 SkASSERT(renderTarget);
128 AutoCheckFlush acf(fContext);
129 if (!this->prepareToDraw(renderTarget)) {
130 return;
131 }
132 fDrawTarget->discard(renderTarget);
133}
134
135void GrDrawContext::clear(GrRenderTarget* renderTarget,
136 const SkIRect* rect,
137 const GrColor color,
138 bool canIgnoreRect) {
139 RETURN_IF_ABANDONED
140 SkASSERT(renderTarget);
141
142 AutoCheckFlush acf(fContext);
143 if (!this->prepareToDraw(renderTarget)) {
144 return;
145 }
146 fDrawTarget->clear(rect, color, canIgnoreRect, renderTarget);
147}
148
149
150void GrDrawContext::drawPaint(GrRenderTarget* rt,
151 const GrClip& clip,
152 const GrPaint& origPaint,
153 const SkMatrix& viewMatrix) {
154 RETURN_IF_ABANDONED
155 // set rect to be big enough to fill the space, but not super-huge, so we
156 // don't overflow fixed-point implementations
157 SkRect r;
158 r.setLTRB(0, 0,
159 SkIntToScalar(rt->width()),
160 SkIntToScalar(rt->height()));
161 SkTCopyOnFirstWrite<GrPaint> paint(origPaint);
162
163 // by definition this fills the entire clip, no need for AA
164 if (paint->isAntiAlias()) {
165 paint.writable()->setAntiAlias(false);
166 }
167
168 bool isPerspective = viewMatrix.hasPerspective();
169
170 // We attempt to map r by the inverse matrix and draw that. mapRect will
171 // map the four corners and bound them with a new rect. This will not
172 // produce a correct result for some perspective matrices.
173 if (!isPerspective) {
174 SkMatrix inverse;
175 if (!viewMatrix.invert(&inverse)) {
176 SkDebugf("Could not invert matrix\n");
177 return;
178 }
179 inverse.mapRect(&r);
180 this->drawRect(rt, clip, *paint, viewMatrix, r);
181 } else {
182 SkMatrix localMatrix;
183 if (!viewMatrix.invert(&localMatrix)) {
184 SkDebugf("Could not invert matrix\n");
185 return;
186 }
187
188 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700189 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700190 return;
191 }
192
joshualitt7b670db2015-07-09 13:25:02 -0700193 GrPipelineBuilder pipelineBuilder(*paint, rt, clip);
joshualittd2b23e02015-08-21 10:53:34 -0700194 fDrawTarget->drawNonAARect(pipelineBuilder,
195 paint->getColor(),
196 SkMatrix::I(),
197 r,
198 localMatrix);
robertphillipsea461502015-05-26 11:38:03 -0700199 }
200}
201
robertphillipsea461502015-05-26 11:38:03 -0700202static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) {
203 return point.fX >= rect.fLeft && point.fX <= rect.fRight &&
204 point.fY >= rect.fTop && point.fY <= rect.fBottom;
205}
206
robertphillipsea461502015-05-26 11:38:03 -0700207void GrDrawContext::drawRect(GrRenderTarget* rt,
208 const GrClip& clip,
209 const GrPaint& paint,
210 const SkMatrix& viewMatrix,
211 const SkRect& rect,
212 const GrStrokeInfo* strokeInfo) {
213 RETURN_IF_ABANDONED
214 if (strokeInfo && strokeInfo->isDashed()) {
215 SkPath path;
216 path.setIsVolatile(true);
217 path.addRect(rect);
218 this->drawPath(rt, clip, paint, viewMatrix, path, *strokeInfo);
219 return;
220 }
221
222 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700223 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700224 return;
225 }
226
joshualitt7b670db2015-07-09 13:25:02 -0700227 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
228
halcanary96fcdcc2015-08-27 07:41:13 -0700229 SkScalar width = nullptr == strokeInfo ? -1 : strokeInfo->getWidth();
robertphillipsea461502015-05-26 11:38:03 -0700230
231 // Check if this is a full RT draw and can be replaced with a clear. We don't bother checking
232 // cases where the RT is fully inside a stroke.
233 if (width < 0) {
234 SkRect rtRect;
235 pipelineBuilder.getRenderTarget()->getBoundsRect(&rtRect);
236 SkRect clipSpaceRTRect = rtRect;
237 bool checkClip = GrClip::kWideOpen_ClipType != clip.clipType();
238 if (checkClip) {
239 clipSpaceRTRect.offset(SkIntToScalar(clip.origin().fX),
240 SkIntToScalar(clip.origin().fY));
241 }
242 // Does the clip contain the entire RT?
243 if (!checkClip || clip.quickContains(clipSpaceRTRect)) {
244 SkMatrix invM;
245 if (!viewMatrix.invert(&invM)) {
246 return;
247 }
248 // Does the rect bound the RT?
249 SkPoint srcSpaceRTQuad[4];
250 invM.mapRectToQuad(srcSpaceRTQuad, rtRect);
251 if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) &&
252 rect_contains_inclusive(rect, srcSpaceRTQuad[1]) &&
253 rect_contains_inclusive(rect, srcSpaceRTQuad[2]) &&
254 rect_contains_inclusive(rect, srcSpaceRTQuad[3])) {
255 // Will it blend?
256 GrColor clearColor;
cdalton1fa45722015-06-02 10:43:39 -0700257 if (paint.isConstantBlendedColor(&clearColor)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700258 fDrawTarget->clear(nullptr, clearColor, true, rt);
robertphillipsea461502015-05-26 11:38:03 -0700259 return;
260 }
261 }
262 }
263 }
264
265 GrColor color = paint.getColor();
vbuzinovdded6962015-06-12 08:59:45 -0700266 bool needAA = paint.isAntiAlias() &&
267 !pipelineBuilder.getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -0700268
joshualitt9be0b002015-08-19 11:50:51 -0700269 // The fill path can handle rotation but not skew
270 // The stroke path needs the rect to remain axis aligned (no rotation or skew)
robertphillipsfac9ceb2015-09-03 08:32:08 -0700271 // None of our AA draw rect calls can handle perspective yet
joshualitt9be0b002015-08-19 11:50:51 -0700272 bool canApplyAA = width >=0 ? viewMatrix.rectStaysRect() : viewMatrix.preservesRightAngles();
273
274 if (needAA && canApplyAA) {
robertphillipsfac9ceb2015-09-03 08:32:08 -0700275 SkASSERT(!viewMatrix.hasPerspective());
joshualitt9be0b002015-08-19 11:50:51 -0700276 SkRect devBoundRect;
277 viewMatrix.mapRect(&devBoundRect, rect);
bsalomonabd30f52015-08-13 13:34:48 -0700278 SkAutoTUnref<GrDrawBatch> batch;
robertphillipsea461502015-05-26 11:38:03 -0700279 if (width >= 0) {
joshualittd2b23e02015-08-21 10:53:34 -0700280 batch.reset(GrRectBatchFactory::CreateAAStroke(color, viewMatrix, rect, devBoundRect,
joshualitt14205b12015-08-10 11:40:56 -0700281 *strokeInfo));
robertphillipsea461502015-05-26 11:38:03 -0700282 } else {
joshualittd2b23e02015-08-21 10:53:34 -0700283 batch.reset(GrRectBatchFactory::CreateAAFill(color, viewMatrix, rect, devBoundRect));
robertphillipsea461502015-05-26 11:38:03 -0700284 }
joshualitt14205b12015-08-10 11:40:56 -0700285 fDrawTarget->drawBatch(pipelineBuilder, batch);
robertphillipsea461502015-05-26 11:38:03 -0700286 return;
287 }
288
289 if (width >= 0) {
robertphillipsea461502015-05-26 11:38:03 -0700290 // Non-AA hairlines are snapped to pixel centers to make which pixels are hit deterministic
vbuzinovdded6962015-06-12 08:59:45 -0700291 bool snapToPixelCenters = (0 == width && !rt->isUnifiedMultisampled());
joshualittd2b23e02015-08-21 10:53:34 -0700292 SkAutoTUnref<GrDrawBatch> batch(GrRectBatchFactory::CreateNonAAStroke(
bsalomonabd30f52015-08-13 13:34:48 -0700293 color, viewMatrix, rect, width, snapToPixelCenters));
robertphillipsea461502015-05-26 11:38:03 -0700294
295 // Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of
296 // hairline rects. We jam all the vertices to pixel centers to avoid this, but not when MSAA
297 // is enabled because it can cause ugly artifacts.
298 pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_Flag,
299 snapToPixelCenters);
joshualitt1c735482015-07-13 08:08:25 -0700300 fDrawTarget->drawBatch(pipelineBuilder, batch);
robertphillipsea461502015-05-26 11:38:03 -0700301 } else {
302 // filled BW rect
joshualittd2b23e02015-08-21 10:53:34 -0700303 fDrawTarget->drawNonAARect(pipelineBuilder, color, viewMatrix, rect);
robertphillipsea461502015-05-26 11:38:03 -0700304 }
305}
306
307void GrDrawContext::drawNonAARectToRect(GrRenderTarget* rt,
308 const GrClip& clip,
309 const GrPaint& paint,
310 const SkMatrix& viewMatrix,
311 const SkRect& rectToDraw,
joshualittb6b513b2015-08-21 10:25:18 -0700312 const SkRect& localRect) {
robertphillipsea461502015-05-26 11:38:03 -0700313 RETURN_IF_ABANDONED
314 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700315 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700316 return;
317 }
318
joshualitt7b670db2015-07-09 13:25:02 -0700319 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
joshualittd2b23e02015-08-21 10:53:34 -0700320 fDrawTarget->drawNonAARect(pipelineBuilder,
321 paint.getColor(),
322 viewMatrix,
323 rectToDraw,
324 localRect);
joshualittb6b513b2015-08-21 10:25:18 -0700325}
326
327void GrDrawContext::drawNonAARectWithLocalMatrix(GrRenderTarget* rt,
328 const GrClip& clip,
329 const GrPaint& paint,
330 const SkMatrix& viewMatrix,
331 const SkRect& rectToDraw,
332 const SkMatrix& localMatrix) {
333 RETURN_IF_ABANDONED
334 AutoCheckFlush acf(fContext);
335 if (!this->prepareToDraw(rt)) {
336 return;
337 }
338
339 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
joshualittd2b23e02015-08-21 10:53:34 -0700340 fDrawTarget->drawNonAARect(pipelineBuilder,
341 paint.getColor(),
342 viewMatrix,
343 rectToDraw,
344 localMatrix);
robertphillipsea461502015-05-26 11:38:03 -0700345}
346
robertphillipsea461502015-05-26 11:38:03 -0700347void GrDrawContext::drawVertices(GrRenderTarget* rt,
348 const GrClip& clip,
349 const GrPaint& paint,
350 const SkMatrix& viewMatrix,
351 GrPrimitiveType primitiveType,
352 int vertexCount,
353 const SkPoint positions[],
354 const SkPoint texCoords[],
355 const GrColor colors[],
356 const uint16_t indices[],
357 int indexCount) {
358 RETURN_IF_ABANDONED
359 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700360 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700361 return;
362 }
363
joshualitt7b670db2015-07-09 13:25:02 -0700364 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
365
robertphillipsea461502015-05-26 11:38:03 -0700366 // TODO clients should give us bounds
367 SkRect bounds;
368 if (!bounds.setBoundsCheck(positions, vertexCount)) {
369 SkDebugf("drawVertices call empty bounds\n");
370 return;
371 }
372
373 viewMatrix.mapRect(&bounds);
374
375 // If we don't have AA then we outset for a half pixel in each direction to account for
376 // snapping
377 if (!paint.isAntiAlias()) {
378 bounds.outset(0.5f, 0.5f);
379 }
380
joshualitt2771b562015-08-07 12:46:26 -0700381 GrDrawVerticesBatch::Geometry geometry;
robertphillipsea461502015-05-26 11:38:03 -0700382 geometry.fColor = paint.getColor();
bsalomonabd30f52015-08-13 13:34:48 -0700383 SkAutoTUnref<GrDrawBatch> batch(GrDrawVerticesBatch::Create(geometry, primitiveType, viewMatrix,
384 positions, vertexCount, indices,
385 indexCount, colors, texCoords,
386 bounds));
robertphillipsea461502015-05-26 11:38:03 -0700387
joshualitt1c735482015-07-13 08:08:25 -0700388 fDrawTarget->drawBatch(pipelineBuilder, batch);
robertphillipsea461502015-05-26 11:38:03 -0700389}
390
391///////////////////////////////////////////////////////////////////////////////
392
jvanverth31ff7622015-08-07 10:09:28 -0700393void GrDrawContext::drawAtlas(GrRenderTarget* rt,
394 const GrClip& clip,
395 const GrPaint& paint,
396 const SkMatrix& viewMatrix,
397 int spriteCount,
398 const SkRSXform xform[],
399 const SkRect texRect[],
400 const SkColor colors[]) {
401 RETURN_IF_ABANDONED
402 AutoCheckFlush acf(fContext);
403 if (!this->prepareToDraw(rt)) {
404 return;
405 }
406
407 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
408
jvanverth14b88032015-08-07 12:18:54 -0700409 GrDrawAtlasBatch::Geometry geometry;
jvanverth31ff7622015-08-07 10:09:28 -0700410 geometry.fColor = paint.getColor();
bsalomonabd30f52015-08-13 13:34:48 -0700411 SkAutoTUnref<GrDrawBatch> batch(GrDrawAtlasBatch::Create(geometry, viewMatrix, spriteCount,
412 xform, texRect, colors));
jvanverth31ff7622015-08-07 10:09:28 -0700413
414 fDrawTarget->drawBatch(pipelineBuilder, batch);
415}
416
417///////////////////////////////////////////////////////////////////////////////
418
robertphillipsea461502015-05-26 11:38:03 -0700419void GrDrawContext::drawRRect(GrRenderTarget*rt,
420 const GrClip& clip,
421 const GrPaint& paint,
422 const SkMatrix& viewMatrix,
423 const SkRRect& rrect,
424 const GrStrokeInfo& strokeInfo) {
425 RETURN_IF_ABANDONED
426 if (rrect.isEmpty()) {
427 return;
428 }
429
430 if (strokeInfo.isDashed()) {
431 SkPath path;
432 path.setIsVolatile(true);
433 path.addRRect(rrect);
434 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
435 return;
436 }
437
438 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700439 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700440 return;
441 }
442
joshualitt7b670db2015-07-09 13:25:02 -0700443 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700444 GrColor color = paint.getColor();
445 if (!GrOvalRenderer::DrawRRect(fDrawTarget,
joshualittae3d63a2015-07-13 08:44:06 -0700446 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700447 color,
448 viewMatrix,
449 paint.isAntiAlias(),
450 rrect,
451 strokeInfo)) {
452 SkPath path;
453 path.setIsVolatile(true);
454 path.addRRect(rrect);
455 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
456 paint.isAntiAlias(), path, strokeInfo);
457 }
458}
459
460///////////////////////////////////////////////////////////////////////////////
461
462void GrDrawContext::drawDRRect(GrRenderTarget* rt,
463 const GrClip& clip,
464 const GrPaint& paint,
465 const SkMatrix& viewMatrix,
466 const SkRRect& outer,
467 const SkRRect& inner) {
468 RETURN_IF_ABANDONED
469 if (outer.isEmpty()) {
470 return;
471 }
472
473 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700474 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700475 return;
476 }
477
joshualitt7b670db2015-07-09 13:25:02 -0700478 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700479 GrColor color = paint.getColor();
480 if (!GrOvalRenderer::DrawDRRect(fDrawTarget,
joshualittae3d63a2015-07-13 08:44:06 -0700481 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700482 color,
483 viewMatrix,
484 paint.isAntiAlias(),
485 outer,
486 inner)) {
487 SkPath path;
488 path.setIsVolatile(true);
489 path.addRRect(inner);
490 path.addRRect(outer);
491 path.setFillType(SkPath::kEvenOdd_FillType);
492
493 GrStrokeInfo fillRec(SkStrokeRec::kFill_InitStyle);
494 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
495 paint.isAntiAlias(), path, fillRec);
496 }
497}
498
499///////////////////////////////////////////////////////////////////////////////
500
501void GrDrawContext::drawOval(GrRenderTarget* rt,
502 const GrClip& clip,
503 const GrPaint& paint,
504 const SkMatrix& viewMatrix,
505 const SkRect& oval,
506 const GrStrokeInfo& strokeInfo) {
507 RETURN_IF_ABANDONED
508 if (oval.isEmpty()) {
509 return;
510 }
511
512 if (strokeInfo.isDashed()) {
513 SkPath path;
514 path.setIsVolatile(true);
515 path.addOval(oval);
516 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
517 return;
518 }
519
520 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700521 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700522 return;
523 }
524
joshualitt7b670db2015-07-09 13:25:02 -0700525 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700526 GrColor color = paint.getColor();
527 if (!GrOvalRenderer::DrawOval(fDrawTarget,
joshualittae3d63a2015-07-13 08:44:06 -0700528 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700529 color,
530 viewMatrix,
531 paint.isAntiAlias(),
532 oval,
533 strokeInfo)) {
534 SkPath path;
535 path.setIsVolatile(true);
536 path.addOval(oval);
537 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
538 paint.isAntiAlias(), path, strokeInfo);
539 }
540}
541
542// Can 'path' be drawn as a pair of filled nested rectangles?
joshualittf9c5db22015-07-10 11:31:01 -0700543static bool is_nested_rects(const SkMatrix& viewMatrix,
robertphillipsea461502015-05-26 11:38:03 -0700544 const SkPath& path,
545 const SkStrokeRec& stroke,
546 SkRect rects[2]) {
547 SkASSERT(stroke.isFillStyle());
548
549 if (path.isInverseFillType()) {
550 return false;
551 }
552
553 // TODO: this restriction could be lifted if we were willing to apply
554 // the matrix to all the points individually rather than just to the rect
555 if (!viewMatrix.preservesAxisAlignment()) {
556 return false;
557 }
558
559 SkPath::Direction dirs[2];
560 if (!path.isNestedFillRects(rects, dirs)) {
561 return false;
562 }
563
564 if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) {
565 // The two rects need to be wound opposite to each other
566 return false;
567 }
568
569 // Right now, nested rects where the margin is not the same width
570 // all around do not render correctly
571 const SkScalar* outer = rects[0].asScalars();
572 const SkScalar* inner = rects[1].asScalars();
573
574 bool allEq = true;
575
576 SkScalar margin = SkScalarAbs(outer[0] - inner[0]);
577 bool allGoE1 = margin >= SK_Scalar1;
578
579 for (int i = 1; i < 4; ++i) {
580 SkScalar temp = SkScalarAbs(outer[i] - inner[i]);
581 if (temp < SK_Scalar1) {
582 allGoE1 = false;
583 }
584 if (!SkScalarNearlyEqual(margin, temp)) {
585 allEq = false;
586 }
587 }
588
589 return allEq || allGoE1;
590}
591
joshualittb7ee1bf2015-08-10 11:59:02 -0700592void GrDrawContext::drawBatch(GrRenderTarget* rt, const GrClip& clip,
bsalomonabd30f52015-08-13 13:34:48 -0700593 const GrPaint& paint, GrDrawBatch* batch) {
joshualittb7ee1bf2015-08-10 11:59:02 -0700594 RETURN_IF_ABANDONED
595
596 AutoCheckFlush acf(fContext);
597 if (!this->prepareToDraw(rt)) {
598 return;
599 }
600
601 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
602 fDrawTarget->drawBatch(pipelineBuilder, batch);
603}
604
robertphillipsea461502015-05-26 11:38:03 -0700605void GrDrawContext::drawPath(GrRenderTarget* rt,
606 const GrClip& clip,
607 const GrPaint& paint,
608 const SkMatrix& viewMatrix,
609 const SkPath& path,
610 const GrStrokeInfo& strokeInfo) {
611 RETURN_IF_ABANDONED
612 if (path.isEmpty()) {
613 if (path.isInverseFillType()) {
614 this->drawPaint(rt, clip, paint, viewMatrix);
615 }
616 return;
617 }
618
619 GrColor color = paint.getColor();
620
621 // Note that internalDrawPath may sw-rasterize the path into a scratch texture.
622 // Scratch textures can be recycled after they are returned to the texture
623 // cache. This presents a potential hazard for buffered drawing. However,
624 // the writePixels that uploads to the scratch will perform a flush so we're
625 // OK.
626 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700627 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700628 return;
629 }
630
joshualitt7b670db2015-07-09 13:25:02 -0700631 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700632 if (!strokeInfo.isDashed()) {
633 bool useCoverageAA = paint.isAntiAlias() &&
vbuzinovdded6962015-06-12 08:59:45 -0700634 !pipelineBuilder.getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -0700635
636 if (useCoverageAA && strokeInfo.getWidth() < 0 && !path.isConvex()) {
637 // Concave AA paths are expensive - try to avoid them for special cases
638 SkRect rects[2];
639
joshualittf9c5db22015-07-10 11:31:01 -0700640 if (is_nested_rects(viewMatrix, path, strokeInfo, rects)) {
joshualittd2b23e02015-08-21 10:53:34 -0700641 SkAutoTUnref<GrDrawBatch> batch(GrRectBatchFactory::CreateAAFillNestedRects(
bsalomonabd30f52015-08-13 13:34:48 -0700642 color, viewMatrix, rects));
joshualitt14205b12015-08-10 11:40:56 -0700643 fDrawTarget->drawBatch(pipelineBuilder, batch);
robertphillipsea461502015-05-26 11:38:03 -0700644 return;
645 }
646 }
647 SkRect ovalRect;
648 bool isOval = path.isOval(&ovalRect);
649
650 if (isOval && !path.isInverseFillType()) {
651 if (GrOvalRenderer::DrawOval(fDrawTarget,
joshualittae3d63a2015-07-13 08:44:06 -0700652 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700653 color,
654 viewMatrix,
655 paint.isAntiAlias(),
656 ovalRect,
657 strokeInfo)) {
658 return;
659 }
660 }
661 }
662 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
663 path, strokeInfo);
664}
665
666void GrDrawContext::internalDrawPath(GrDrawTarget* target,
667 GrPipelineBuilder* pipelineBuilder,
668 const SkMatrix& viewMatrix,
669 GrColor color,
670 bool useAA,
671 const SkPath& path,
672 const GrStrokeInfo& strokeInfo) {
673 RETURN_IF_ABANDONED
674 SkASSERT(!path.isEmpty());
675
676
677 // An Assumption here is that path renderer would use some form of tweaking
678 // the src color (either the input alpha or in the frag shader) to implement
679 // aa. If we have some future driver-mojo path AA that can do the right
680 // thing WRT to the blend then we'll need some query on the PR.
681 bool useCoverageAA = useAA &&
vbuzinovdded6962015-06-12 08:59:45 -0700682 !pipelineBuilder->getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -0700683
684
685 GrPathRendererChain::DrawType type =
686 useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType :
687 GrPathRendererChain::kColor_DrawType;
688
689 const SkPath* pathPtr = &path;
690 SkTLazy<SkPath> tmpPath;
691 const GrStrokeInfo* strokeInfoPtr = &strokeInfo;
692
693 // Try a 1st time without stroking the path and without allowing the SW renderer
694 GrPathRenderer* pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr,
695 *strokeInfoPtr, false, type);
696
697 GrStrokeInfo dashlessStrokeInfo(strokeInfo, false);
halcanary96fcdcc2015-08-27 07:41:13 -0700698 if (nullptr == pr && strokeInfo.isDashed()) {
robertphillipsea461502015-05-26 11:38:03 -0700699 // It didn't work above, so try again with dashed stroke converted to a dashless stroke.
700 if (!strokeInfo.applyDashToPath(tmpPath.init(), &dashlessStrokeInfo, *pathPtr)) {
701 return;
702 }
703 pathPtr = tmpPath.get();
704 if (pathPtr->isEmpty()) {
705 return;
706 }
707 strokeInfoPtr = &dashlessStrokeInfo;
708 pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
709 false, type);
710 }
711
halcanary96fcdcc2015-08-27 07:41:13 -0700712 if (nullptr == pr) {
713 if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*strokeInfoPtr, viewMatrix, nullptr) &&
robertphillipsea461502015-05-26 11:38:03 -0700714 !strokeInfoPtr->isFillStyle()) {
715 // It didn't work above, so try again with stroke converted to a fill.
716 if (!tmpPath.isValid()) {
717 tmpPath.init();
718 }
719 dashlessStrokeInfo.setResScale(SkScalarAbs(viewMatrix.getMaxScale()));
720 if (!dashlessStrokeInfo.applyToPath(tmpPath.get(), *pathPtr)) {
721 return;
722 }
723 pathPtr = tmpPath.get();
724 if (pathPtr->isEmpty()) {
725 return;
726 }
727 dashlessStrokeInfo.setFillStyle();
728 strokeInfoPtr = &dashlessStrokeInfo;
729 }
730
731 // This time, allow SW renderer
732 pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
733 true, type);
734 }
735
halcanary96fcdcc2015-08-27 07:41:13 -0700736 if (nullptr == pr) {
robertphillipsea461502015-05-26 11:38:03 -0700737#ifdef SK_DEBUG
738 SkDebugf("Unable to find path renderer compatible with path.\n");
739#endif
740 return;
741 }
742
bsalomon0aff2fa2015-07-31 06:48:27 -0700743 GrPathRenderer::DrawPathArgs args;
744 args.fTarget = target;
745 args.fResourceProvider = fContext->resourceProvider();
746 args.fPipelineBuilder = pipelineBuilder;
747 args.fColor = color;
748 args.fViewMatrix = &viewMatrix;
749 args.fPath = pathPtr;
750 args.fStroke = strokeInfoPtr;
751 args.fAntiAlias = useCoverageAA;
752 pr->drawPath(args);
robertphillipsea461502015-05-26 11:38:03 -0700753}
754
robertphillipsea461502015-05-26 11:38:03 -0700755bool GrDrawContext::prepareToDraw(GrRenderTarget* rt) {
756 RETURN_FALSE_IF_ABANDONED
757
758 ASSERT_OWNED_RESOURCE(rt);
759 SkASSERT(rt);
760 return true;
761}
762
bsalomonabd30f52015-08-13 13:34:48 -0700763void GrDrawContext::drawBatch(GrPipelineBuilder* pipelineBuilder, GrDrawBatch* batch) {
joshualitt1c735482015-07-13 08:08:25 -0700764 fDrawTarget->drawBatch(*pipelineBuilder, batch);
robertphillips2334fb62015-06-17 05:43:33 -0700765}