blob: 1aec92ec4c49349b7af103a2169d489dc7602461 [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"
bsalomon473addf2015-10-02 07:49:05 -070017#include "GrResourceProvider.h"
robertphillips2334fb62015-06-17 05:43:33 -070018#include "GrStencilAndCoverTextContext.h"
robertphillips2d70dcb2015-10-06 07:38:23 -070019#include "SkSurfacePriv.h"
robertphillipsea461502015-05-26 11:38:03 -070020
joshualitt74417822015-08-07 11:42:16 -070021#include "batches/GrBatch.h"
jvanverth14b8803b2015-08-07 12:18:54 -070022#include "batches/GrDrawAtlasBatch.h"
joshualitt2771b562015-08-07 12:46:26 -070023#include "batches/GrDrawVerticesBatch.h"
joshualitt7fc2a262015-08-10 10:30:14 -070024#include "batches/GrRectBatchFactory.h"
joshualitt74417822015-08-07 11:42:16 -070025
robertphillipsea461502015-05-26 11:38:03 -070026#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == fContext)
robertphillips2d70dcb2015-10-06 07:38:23 -070027#define RETURN_IF_ABANDONED if (fContext->abandoned()) { return; }
28#define RETURN_FALSE_IF_ABANDONED if (fContext->abandoned()) { return false; }
29#define RETURN_NULL_IF_ABANDONED if (fContext->abandoned()) { return nullptr; }
robertphillipsea461502015-05-26 11:38:03 -070030
31class AutoCheckFlush {
32public:
33 AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context); }
34 ~AutoCheckFlush() { fContext->flushIfNecessary(); }
35
36private:
37 GrContext* fContext;
38};
39
robertphillipsa106c622015-10-16 09:07:06 -070040// In MDB mode the reffing of the 'getLastDrawTarget' call's result allows in-progress
41// drawTargets to be picked up and added to by drawContexts lower in the call
42// stack. When this occurs with a closed drawTarget, a new one will be allocated
43// when the drawContext attempts to use it (via getDrawTarget).
robertphillips2334fb62015-06-17 05:43:33 -070044GrDrawContext::GrDrawContext(GrContext* context,
robertphillips2e1e51f2015-10-15 08:01:48 -070045 GrRenderTarget* rt,
robertphillips2d70dcb2015-10-06 07:38:23 -070046 const SkSurfaceProps* surfaceProps)
robertphillipsea461502015-05-26 11:38:03 -070047 : fContext(context)
robertphillips2e1e51f2015-10-15 08:01:48 -070048 , fRenderTarget(rt)
robertphillipsa106c622015-10-16 09:07:06 -070049 , fDrawTarget(SkSafeRef(rt->getLastDrawTarget()))
halcanary96fcdcc2015-08-27 07:41:13 -070050 , fTextContext(nullptr)
robertphillips2d70dcb2015-10-06 07:38:23 -070051 , fSurfaceProps(SkSurfacePropsCopyOrDefault(surfaceProps)) {
robertphillips2e1e51f2015-10-15 08:01:48 -070052 SkDEBUGCODE(this->validate();)
robertphillipsea461502015-05-26 11:38:03 -070053}
54
robertphillips2e1e51f2015-10-15 08:01:48 -070055#ifdef SK_DEBUG
56void GrDrawContext::validate() const {
57 SkASSERT(fRenderTarget);
58 ASSERT_OWNED_RESOURCE(fRenderTarget);
robertphillipsa106c622015-10-16 09:07:06 -070059
60 if (fDrawTarget && !fDrawTarget->isClosed()) {
61 SkASSERT(fRenderTarget->getLastDrawTarget() == fDrawTarget);
62 }
robertphillips2e1e51f2015-10-15 08:01:48 -070063}
64#endif
65
robertphillipsa106c622015-10-16 09:07:06 -070066GrDrawContext::~GrDrawContext() {
67 SkSafeUnref(fDrawTarget);
68}
69
70GrDrawTarget* GrDrawContext::getDrawTarget() {
71 SkDEBUGCODE(this->validate();)
72
73 if (!fDrawTarget || fDrawTarget->isClosed()) {
74 fDrawTarget = fContext->newDrawTarget(fRenderTarget);
75 fRenderTarget->setLastDrawTarget(fDrawTarget);
76 }
77
78 return fDrawTarget;
79}
80
robertphillips2e1e51f2015-10-15 08:01:48 -070081void GrDrawContext::copySurface(GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) {
robertphillips2d70dcb2015-10-06 07:38:23 -070082 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -070083 SkDEBUGCODE(this->validate();)
robertphillips2d70dcb2015-10-06 07:38:23 -070084
robertphillipsa106c622015-10-16 09:07:06 -070085 this->getDrawTarget()->copySurface(fRenderTarget, src, srcRect, dstPoint);
robertphillipsea461502015-05-26 11:38:03 -070086}
87
robertphillips2334fb62015-06-17 05:43:33 -070088
robertphillips2e1e51f2015-10-15 08:01:48 -070089void GrDrawContext::drawText(const GrClip& clip, const GrPaint& grPaint,
robertphillips2334fb62015-06-17 05:43:33 -070090 const SkPaint& skPaint,
91 const SkMatrix& viewMatrix,
92 const char text[], size_t byteLength,
93 SkScalar x, SkScalar y, const SkIRect& clipBounds) {
robertphillips2d70dcb2015-10-06 07:38:23 -070094 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -070095 SkDEBUGCODE(this->validate();)
robertphillips2d70dcb2015-10-06 07:38:23 -070096
robertphillips2334fb62015-06-17 05:43:33 -070097 if (!fTextContext) {
robertphillips2e1e51f2015-10-15 08:01:48 -070098 fTextContext = fContext->textContext(fSurfaceProps, fRenderTarget);
robertphillips2334fb62015-06-17 05:43:33 -070099 }
100
robertphillips2e1e51f2015-10-15 08:01:48 -0700101 fTextContext->drawText(this, fRenderTarget, clip, grPaint, skPaint, viewMatrix,
robertphillips2334fb62015-06-17 05:43:33 -0700102 text, byteLength, x, y, clipBounds);
103
104}
robertphillips2e1e51f2015-10-15 08:01:48 -0700105void GrDrawContext::drawPosText(const GrClip& clip, const GrPaint& grPaint,
robertphillips2334fb62015-06-17 05:43:33 -0700106 const SkPaint& skPaint,
107 const SkMatrix& viewMatrix,
108 const char text[], size_t byteLength,
109 const SkScalar pos[], int scalarsPerPosition,
110 const SkPoint& offset, const SkIRect& clipBounds) {
robertphillips2d70dcb2015-10-06 07:38:23 -0700111 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700112 SkDEBUGCODE(this->validate();)
robertphillips2d70dcb2015-10-06 07:38:23 -0700113
robertphillips2334fb62015-06-17 05:43:33 -0700114 if (!fTextContext) {
robertphillips2e1e51f2015-10-15 08:01:48 -0700115 fTextContext = fContext->textContext(fSurfaceProps, fRenderTarget);
robertphillips2334fb62015-06-17 05:43:33 -0700116 }
117
robertphillips2e1e51f2015-10-15 08:01:48 -0700118 fTextContext->drawPosText(this, fRenderTarget, clip, grPaint, skPaint, viewMatrix, text, byteLength,
robertphillipsf6703fa2015-09-01 05:36:47 -0700119 pos, scalarsPerPosition, offset, clipBounds);
robertphillips2334fb62015-06-17 05:43:33 -0700120
121}
robertphillips2e1e51f2015-10-15 08:01:48 -0700122void GrDrawContext::drawTextBlob(const GrClip& clip, const SkPaint& skPaint,
robertphillips2334fb62015-06-17 05:43:33 -0700123 const SkMatrix& viewMatrix, const SkTextBlob* blob,
124 SkScalar x, SkScalar y,
125 SkDrawFilter* filter, const SkIRect& clipBounds) {
robertphillips2d70dcb2015-10-06 07:38:23 -0700126 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700127 SkDEBUGCODE(this->validate();)
robertphillips2d70dcb2015-10-06 07:38:23 -0700128
robertphillips2334fb62015-06-17 05:43:33 -0700129 if (!fTextContext) {
robertphillips2e1e51f2015-10-15 08:01:48 -0700130 fTextContext = fContext->textContext(fSurfaceProps, fRenderTarget);
robertphillips2334fb62015-06-17 05:43:33 -0700131 }
132
robertphillips2e1e51f2015-10-15 08:01:48 -0700133 fTextContext->drawTextBlob(this, fRenderTarget,
robertphillipsf6703fa2015-09-01 05:36:47 -0700134 clip, skPaint, viewMatrix, blob, x, y, filter, clipBounds);
robertphillipsea461502015-05-26 11:38:03 -0700135}
136
bsalomon1fcc01c2015-09-09 09:48:06 -0700137void GrDrawContext::drawPathsFromRange(const GrPipelineBuilder* pipelineBuilder,
joshualittf2384692015-09-10 11:00:51 -0700138 const SkMatrix& viewMatrix,
139 const SkMatrix& localMatrix,
140 GrColor color,
cdalton8585dd22015-10-08 08:04:09 -0700141 GrPathRange* range,
bsalomon1fcc01c2015-09-09 09:48:06 -0700142 GrPathRangeDraw* draw,
143 int /*GrPathRendering::FillType*/ fill) {
robertphillips2d70dcb2015-10-06 07:38:23 -0700144 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700145 SkDEBUGCODE(this->validate();)
robertphillips2d70dcb2015-10-06 07:38:23 -0700146
robertphillipsa106c622015-10-16 09:07:06 -0700147 this->getDrawTarget()->drawPathsFromRange(*pipelineBuilder, viewMatrix, localMatrix, color,
148 range, draw, (GrPathRendering::FillType) fill);
robertphillipsea461502015-05-26 11:38:03 -0700149}
150
robertphillips2e1e51f2015-10-15 08:01:48 -0700151void GrDrawContext::discard() {
robertphillipsea461502015-05-26 11:38:03 -0700152 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700153 SkDEBUGCODE(this->validate();)
154
robertphillipsea461502015-05-26 11:38:03 -0700155 AutoCheckFlush acf(fContext);
robertphillipsa106c622015-10-16 09:07:06 -0700156 this->getDrawTarget()->discard(fRenderTarget);
robertphillipsea461502015-05-26 11:38:03 -0700157}
158
robertphillips2e1e51f2015-10-15 08:01:48 -0700159void GrDrawContext::clear(const SkIRect* rect,
robertphillipsea461502015-05-26 11:38:03 -0700160 const GrColor color,
161 bool canIgnoreRect) {
162 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700163 SkDEBUGCODE(this->validate();)
robertphillipsea461502015-05-26 11:38:03 -0700164
165 AutoCheckFlush acf(fContext);
robertphillipsa106c622015-10-16 09:07:06 -0700166 this->getDrawTarget()->clear(rect, color, canIgnoreRect, fRenderTarget);
robertphillipsea461502015-05-26 11:38:03 -0700167}
168
169
robertphillips2e1e51f2015-10-15 08:01:48 -0700170void GrDrawContext::drawPaint(const GrClip& clip,
robertphillipsea461502015-05-26 11:38:03 -0700171 const GrPaint& origPaint,
172 const SkMatrix& viewMatrix) {
173 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700174 SkDEBUGCODE(this->validate();)
175
robertphillipsea461502015-05-26 11:38:03 -0700176 // set rect to be big enough to fill the space, but not super-huge, so we
177 // don't overflow fixed-point implementations
178 SkRect r;
179 r.setLTRB(0, 0,
robertphillips2e1e51f2015-10-15 08:01:48 -0700180 SkIntToScalar(fRenderTarget->width()),
181 SkIntToScalar(fRenderTarget->height()));
robertphillipsea461502015-05-26 11:38:03 -0700182 SkTCopyOnFirstWrite<GrPaint> paint(origPaint);
183
184 // by definition this fills the entire clip, no need for AA
185 if (paint->isAntiAlias()) {
186 paint.writable()->setAntiAlias(false);
187 }
188
189 bool isPerspective = viewMatrix.hasPerspective();
190
191 // We attempt to map r by the inverse matrix and draw that. mapRect will
192 // map the four corners and bound them with a new rect. This will not
193 // produce a correct result for some perspective matrices.
194 if (!isPerspective) {
195 SkMatrix inverse;
196 if (!viewMatrix.invert(&inverse)) {
197 SkDebugf("Could not invert matrix\n");
198 return;
199 }
200 inverse.mapRect(&r);
robertphillips2e1e51f2015-10-15 08:01:48 -0700201 this->drawRect(clip, *paint, viewMatrix, r);
robertphillipsea461502015-05-26 11:38:03 -0700202 } else {
203 SkMatrix localMatrix;
204 if (!viewMatrix.invert(&localMatrix)) {
205 SkDebugf("Could not invert matrix\n");
206 return;
207 }
208
209 AutoCheckFlush acf(fContext);
robertphillipsea461502015-05-26 11:38:03 -0700210
robertphillips2e1e51f2015-10-15 08:01:48 -0700211 GrPipelineBuilder pipelineBuilder(*paint, fRenderTarget, clip);
robertphillipsa106c622015-10-16 09:07:06 -0700212 this->getDrawTarget()->drawNonAARect(pipelineBuilder,
213 paint->getColor(),
214 SkMatrix::I(),
215 r,
216 localMatrix);
robertphillipsea461502015-05-26 11:38:03 -0700217 }
218}
219
robertphillipsea461502015-05-26 11:38:03 -0700220static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) {
221 return point.fX >= rect.fLeft && point.fX <= rect.fRight &&
222 point.fY >= rect.fTop && point.fY <= rect.fBottom;
223}
224
robertphillips2e1e51f2015-10-15 08:01:48 -0700225void GrDrawContext::drawRect(const GrClip& clip,
robertphillipsea461502015-05-26 11:38:03 -0700226 const GrPaint& paint,
227 const SkMatrix& viewMatrix,
228 const SkRect& rect,
229 const GrStrokeInfo* strokeInfo) {
230 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700231 SkDEBUGCODE(this->validate();)
232
robertphillipsea461502015-05-26 11:38:03 -0700233 if (strokeInfo && strokeInfo->isDashed()) {
234 SkPath path;
235 path.setIsVolatile(true);
236 path.addRect(rect);
robertphillips2e1e51f2015-10-15 08:01:48 -0700237 this->drawPath(clip, paint, viewMatrix, path, *strokeInfo);
robertphillipsea461502015-05-26 11:38:03 -0700238 return;
239 }
240
241 AutoCheckFlush acf(fContext);
robertphillipsea461502015-05-26 11:38:03 -0700242
robertphillips2e1e51f2015-10-15 08:01:48 -0700243 GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
joshualitt7b670db2015-07-09 13:25:02 -0700244
halcanary96fcdcc2015-08-27 07:41:13 -0700245 SkScalar width = nullptr == strokeInfo ? -1 : strokeInfo->getWidth();
robertphillipsea461502015-05-26 11:38:03 -0700246
247 // Check if this is a full RT draw and can be replaced with a clear. We don't bother checking
248 // cases where the RT is fully inside a stroke.
249 if (width < 0) {
250 SkRect rtRect;
251 pipelineBuilder.getRenderTarget()->getBoundsRect(&rtRect);
252 SkRect clipSpaceRTRect = rtRect;
253 bool checkClip = GrClip::kWideOpen_ClipType != clip.clipType();
254 if (checkClip) {
255 clipSpaceRTRect.offset(SkIntToScalar(clip.origin().fX),
256 SkIntToScalar(clip.origin().fY));
257 }
258 // Does the clip contain the entire RT?
259 if (!checkClip || clip.quickContains(clipSpaceRTRect)) {
260 SkMatrix invM;
261 if (!viewMatrix.invert(&invM)) {
262 return;
263 }
264 // Does the rect bound the RT?
265 SkPoint srcSpaceRTQuad[4];
266 invM.mapRectToQuad(srcSpaceRTQuad, rtRect);
267 if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) &&
268 rect_contains_inclusive(rect, srcSpaceRTQuad[1]) &&
269 rect_contains_inclusive(rect, srcSpaceRTQuad[2]) &&
270 rect_contains_inclusive(rect, srcSpaceRTQuad[3])) {
271 // Will it blend?
272 GrColor clearColor;
cdalton1fa45722015-06-02 10:43:39 -0700273 if (paint.isConstantBlendedColor(&clearColor)) {
robertphillipsa106c622015-10-16 09:07:06 -0700274 this->getDrawTarget()->clear(nullptr, clearColor, true, fRenderTarget);
robertphillipsea461502015-05-26 11:38:03 -0700275 return;
276 }
277 }
278 }
279 }
280
281 GrColor color = paint.getColor();
vbuzinovdded6962015-06-12 08:59:45 -0700282 bool needAA = paint.isAntiAlias() &&
283 !pipelineBuilder.getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -0700284
joshualitt9be0b002015-08-19 11:50:51 -0700285 // The fill path can handle rotation but not skew
286 // The stroke path needs the rect to remain axis aligned (no rotation or skew)
robertphillipsfac9ceb2015-09-03 08:32:08 -0700287 // None of our AA draw rect calls can handle perspective yet
joshualitt9be0b002015-08-19 11:50:51 -0700288 bool canApplyAA = width >=0 ? viewMatrix.rectStaysRect() : viewMatrix.preservesRightAngles();
289
290 if (needAA && canApplyAA) {
robertphillipsfac9ceb2015-09-03 08:32:08 -0700291 SkASSERT(!viewMatrix.hasPerspective());
bsalomonabd30f52015-08-13 13:34:48 -0700292 SkAutoTUnref<GrDrawBatch> batch;
robertphillipsea461502015-05-26 11:38:03 -0700293 if (width >= 0) {
joshualitt10cae832015-09-22 12:50:33 -0700294 batch.reset(GrRectBatchFactory::CreateAAStroke(color, viewMatrix, rect, *strokeInfo));
robertphillipsea461502015-05-26 11:38:03 -0700295 } else {
joshualitt10cae832015-09-22 12:50:33 -0700296 SkRect devBoundRect;
297 viewMatrix.mapRect(&devBoundRect, rect);
joshualittd2b23e02015-08-21 10:53:34 -0700298 batch.reset(GrRectBatchFactory::CreateAAFill(color, viewMatrix, rect, devBoundRect));
robertphillipsea461502015-05-26 11:38:03 -0700299 }
robertphillipsa106c622015-10-16 09:07:06 -0700300 this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
robertphillipsea461502015-05-26 11:38:03 -0700301 return;
302 }
303
304 if (width >= 0) {
robertphillipsea461502015-05-26 11:38:03 -0700305 // Non-AA hairlines are snapped to pixel centers to make which pixels are hit deterministic
robertphillips2e1e51f2015-10-15 08:01:48 -0700306 bool snapToPixelCenters = (0 == width && !fRenderTarget->isUnifiedMultisampled());
joshualittd2b23e02015-08-21 10:53:34 -0700307 SkAutoTUnref<GrDrawBatch> batch(GrRectBatchFactory::CreateNonAAStroke(
bsalomonabd30f52015-08-13 13:34:48 -0700308 color, viewMatrix, rect, width, snapToPixelCenters));
robertphillipsea461502015-05-26 11:38:03 -0700309
310 // Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of
311 // hairline rects. We jam all the vertices to pixel centers to avoid this, but not when MSAA
312 // is enabled because it can cause ugly artifacts.
313 pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_Flag,
314 snapToPixelCenters);
robertphillipsa106c622015-10-16 09:07:06 -0700315 this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
robertphillipsea461502015-05-26 11:38:03 -0700316 } else {
317 // filled BW rect
robertphillipsa106c622015-10-16 09:07:06 -0700318 this->getDrawTarget()->drawNonAARect(pipelineBuilder, color, viewMatrix, rect);
robertphillipsea461502015-05-26 11:38:03 -0700319 }
320}
321
robertphillips2e1e51f2015-10-15 08:01:48 -0700322void GrDrawContext::drawNonAARectToRect(const GrClip& clip,
robertphillipsea461502015-05-26 11:38:03 -0700323 const GrPaint& paint,
324 const SkMatrix& viewMatrix,
325 const SkRect& rectToDraw,
joshualittb6b513b2015-08-21 10:25:18 -0700326 const SkRect& localRect) {
robertphillipsea461502015-05-26 11:38:03 -0700327 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700328 SkDEBUGCODE(this->validate();)
robertphillipsea461502015-05-26 11:38:03 -0700329
robertphillips2e1e51f2015-10-15 08:01:48 -0700330 AutoCheckFlush acf(fContext);
331
332 GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
robertphillipsa106c622015-10-16 09:07:06 -0700333 this->getDrawTarget()->drawNonAARect(pipelineBuilder,
334 paint.getColor(),
335 viewMatrix,
336 rectToDraw,
337 localRect);
joshualittb6b513b2015-08-21 10:25:18 -0700338}
339
robertphillips2e1e51f2015-10-15 08:01:48 -0700340void GrDrawContext::drawNonAARectWithLocalMatrix(const GrClip& clip,
joshualittb6b513b2015-08-21 10:25:18 -0700341 const GrPaint& paint,
342 const SkMatrix& viewMatrix,
343 const SkRect& rectToDraw,
344 const SkMatrix& localMatrix) {
345 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700346 SkDEBUGCODE(this->validate();)
joshualittb6b513b2015-08-21 10:25:18 -0700347
robertphillips2e1e51f2015-10-15 08:01:48 -0700348 AutoCheckFlush acf(fContext);
349
350 GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
robertphillipsa106c622015-10-16 09:07:06 -0700351 this->getDrawTarget()->drawNonAARect(pipelineBuilder,
352 paint.getColor(),
353 viewMatrix,
354 rectToDraw,
355 localMatrix);
robertphillipsea461502015-05-26 11:38:03 -0700356}
357
robertphillips2e1e51f2015-10-15 08:01:48 -0700358void GrDrawContext::drawVertices(const GrClip& clip,
robertphillipsea461502015-05-26 11:38:03 -0700359 const GrPaint& paint,
360 const SkMatrix& viewMatrix,
361 GrPrimitiveType primitiveType,
362 int vertexCount,
363 const SkPoint positions[],
364 const SkPoint texCoords[],
365 const GrColor colors[],
366 const uint16_t indices[],
367 int indexCount) {
368 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700369 SkDEBUGCODE(this->validate();)
robertphillipsea461502015-05-26 11:38:03 -0700370
robertphillips2e1e51f2015-10-15 08:01:48 -0700371 AutoCheckFlush acf(fContext);
372
373 GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
joshualitt7b670db2015-07-09 13:25:02 -0700374
robertphillipsea461502015-05-26 11:38:03 -0700375 // TODO clients should give us bounds
376 SkRect bounds;
377 if (!bounds.setBoundsCheck(positions, vertexCount)) {
378 SkDebugf("drawVertices call empty bounds\n");
379 return;
380 }
381
382 viewMatrix.mapRect(&bounds);
383
384 // If we don't have AA then we outset for a half pixel in each direction to account for
385 // snapping
386 if (!paint.isAntiAlias()) {
387 bounds.outset(0.5f, 0.5f);
388 }
389
joshualitt2771b562015-08-07 12:46:26 -0700390 GrDrawVerticesBatch::Geometry geometry;
robertphillipsea461502015-05-26 11:38:03 -0700391 geometry.fColor = paint.getColor();
bsalomonabd30f52015-08-13 13:34:48 -0700392 SkAutoTUnref<GrDrawBatch> batch(GrDrawVerticesBatch::Create(geometry, primitiveType, viewMatrix,
393 positions, vertexCount, indices,
394 indexCount, colors, texCoords,
395 bounds));
robertphillipsea461502015-05-26 11:38:03 -0700396
robertphillipsa106c622015-10-16 09:07:06 -0700397 this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
robertphillipsea461502015-05-26 11:38:03 -0700398}
399
400///////////////////////////////////////////////////////////////////////////////
401
robertphillips2e1e51f2015-10-15 08:01:48 -0700402void GrDrawContext::drawAtlas(const GrClip& clip,
jvanverth31ff7622015-08-07 10:09:28 -0700403 const GrPaint& paint,
404 const SkMatrix& viewMatrix,
405 int spriteCount,
406 const SkRSXform xform[],
407 const SkRect texRect[],
408 const SkColor colors[]) {
409 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700410 SkDEBUGCODE(this->validate();)
411
jvanverth31ff7622015-08-07 10:09:28 -0700412 AutoCheckFlush acf(fContext);
jvanverth31ff7622015-08-07 10:09:28 -0700413
robertphillips2e1e51f2015-10-15 08:01:48 -0700414 GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
jvanverth31ff7622015-08-07 10:09:28 -0700415
jvanverth14b8803b2015-08-07 12:18:54 -0700416 GrDrawAtlasBatch::Geometry geometry;
jvanverth31ff7622015-08-07 10:09:28 -0700417 geometry.fColor = paint.getColor();
bsalomonabd30f52015-08-13 13:34:48 -0700418 SkAutoTUnref<GrDrawBatch> batch(GrDrawAtlasBatch::Create(geometry, viewMatrix, spriteCount,
419 xform, texRect, colors));
jvanverth31ff7622015-08-07 10:09:28 -0700420
robertphillipsa106c622015-10-16 09:07:06 -0700421 this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
jvanverth31ff7622015-08-07 10:09:28 -0700422}
423
424///////////////////////////////////////////////////////////////////////////////
425
robertphillips2e1e51f2015-10-15 08:01:48 -0700426void GrDrawContext::drawRRect(const GrClip& clip,
robertphillipsea461502015-05-26 11:38:03 -0700427 const GrPaint& paint,
428 const SkMatrix& viewMatrix,
429 const SkRRect& rrect,
430 const GrStrokeInfo& strokeInfo) {
431 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700432 SkDEBUGCODE(this->validate();)
433
robertphillipsea461502015-05-26 11:38:03 -0700434 if (rrect.isEmpty()) {
435 return;
436 }
437
438 if (strokeInfo.isDashed()) {
439 SkPath path;
440 path.setIsVolatile(true);
441 path.addRRect(rrect);
robertphillips2e1e51f2015-10-15 08:01:48 -0700442 this->drawPath(clip, paint, viewMatrix, path, strokeInfo);
robertphillipsea461502015-05-26 11:38:03 -0700443 return;
444 }
445
446 AutoCheckFlush acf(fContext);
robertphillipsea461502015-05-26 11:38:03 -0700447
robertphillips2e1e51f2015-10-15 08:01:48 -0700448 GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
robertphillipsea461502015-05-26 11:38:03 -0700449 GrColor color = paint.getColor();
robertphillips2e1e51f2015-10-15 08:01:48 -0700450
robertphillipsa106c622015-10-16 09:07:06 -0700451 if (!GrOvalRenderer::DrawRRect(this->getDrawTarget(),
joshualittae3d63a2015-07-13 08:44:06 -0700452 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700453 color,
454 viewMatrix,
455 paint.isAntiAlias(),
456 rrect,
457 strokeInfo)) {
458 SkPath path;
459 path.setIsVolatile(true);
460 path.addRRect(rrect);
robertphillipsa106c622015-10-16 09:07:06 -0700461 this->internalDrawPath(this->getDrawTarget(), &pipelineBuilder, viewMatrix, color,
robertphillipsea461502015-05-26 11:38:03 -0700462 paint.isAntiAlias(), path, strokeInfo);
463 }
464}
465
466///////////////////////////////////////////////////////////////////////////////
467
robertphillips2e1e51f2015-10-15 08:01:48 -0700468void GrDrawContext::drawDRRect(const GrClip& clip,
robertphillipsea461502015-05-26 11:38:03 -0700469 const GrPaint& paint,
470 const SkMatrix& viewMatrix,
471 const SkRRect& outer,
472 const SkRRect& inner) {
473 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700474 SkDEBUGCODE(this->validate();)
475
robertphillipsea461502015-05-26 11:38:03 -0700476 if (outer.isEmpty()) {
477 return;
478 }
479
480 AutoCheckFlush acf(fContext);
robertphillipsea461502015-05-26 11:38:03 -0700481
robertphillips2e1e51f2015-10-15 08:01:48 -0700482 GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
robertphillipsea461502015-05-26 11:38:03 -0700483 GrColor color = paint.getColor();
robertphillipsa106c622015-10-16 09:07:06 -0700484 if (!GrOvalRenderer::DrawDRRect(this->getDrawTarget(),
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);
robertphillipsa106c622015-10-16 09:07:06 -0700498 this->internalDrawPath(this->getDrawTarget(), &pipelineBuilder, viewMatrix, color,
robertphillipsea461502015-05-26 11:38:03 -0700499 paint.isAntiAlias(), path, fillRec);
500 }
501}
502
503///////////////////////////////////////////////////////////////////////////////
504
robertphillips2e1e51f2015-10-15 08:01:48 -0700505void GrDrawContext::drawOval(const GrClip& clip,
robertphillipsea461502015-05-26 11:38:03 -0700506 const GrPaint& paint,
507 const SkMatrix& viewMatrix,
508 const SkRect& oval,
509 const GrStrokeInfo& strokeInfo) {
510 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700511 SkDEBUGCODE(this->validate();)
512
robertphillipsea461502015-05-26 11:38:03 -0700513 if (oval.isEmpty()) {
514 return;
515 }
516
517 if (strokeInfo.isDashed()) {
518 SkPath path;
519 path.setIsVolatile(true);
520 path.addOval(oval);
robertphillips2e1e51f2015-10-15 08:01:48 -0700521 this->drawPath(clip, paint, viewMatrix, path, strokeInfo);
robertphillipsea461502015-05-26 11:38:03 -0700522 return;
523 }
524
525 AutoCheckFlush acf(fContext);
robertphillipsea461502015-05-26 11:38:03 -0700526
robertphillips2e1e51f2015-10-15 08:01:48 -0700527 GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
robertphillipsea461502015-05-26 11:38:03 -0700528 GrColor color = paint.getColor();
robertphillips2e1e51f2015-10-15 08:01:48 -0700529
robertphillipsa106c622015-10-16 09:07:06 -0700530 if (!GrOvalRenderer::DrawOval(this->getDrawTarget(),
joshualittae3d63a2015-07-13 08:44:06 -0700531 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700532 color,
533 viewMatrix,
534 paint.isAntiAlias(),
535 oval,
536 strokeInfo)) {
537 SkPath path;
538 path.setIsVolatile(true);
539 path.addOval(oval);
robertphillipsa106c622015-10-16 09:07:06 -0700540 this->internalDrawPath(this->getDrawTarget(), &pipelineBuilder, viewMatrix, color,
robertphillipsea461502015-05-26 11:38:03 -0700541 paint.isAntiAlias(), path, strokeInfo);
542 }
543}
544
545// Can 'path' be drawn as a pair of filled nested rectangles?
joshualittf9c5db22015-07-10 11:31:01 -0700546static bool is_nested_rects(const SkMatrix& viewMatrix,
robertphillipsea461502015-05-26 11:38:03 -0700547 const SkPath& path,
548 const SkStrokeRec& stroke,
549 SkRect rects[2]) {
550 SkASSERT(stroke.isFillStyle());
551
552 if (path.isInverseFillType()) {
553 return false;
554 }
555
556 // TODO: this restriction could be lifted if we were willing to apply
557 // the matrix to all the points individually rather than just to the rect
558 if (!viewMatrix.preservesAxisAlignment()) {
559 return false;
560 }
561
562 SkPath::Direction dirs[2];
563 if (!path.isNestedFillRects(rects, dirs)) {
564 return false;
565 }
566
567 if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) {
568 // The two rects need to be wound opposite to each other
569 return false;
570 }
571
572 // Right now, nested rects where the margin is not the same width
573 // all around do not render correctly
574 const SkScalar* outer = rects[0].asScalars();
575 const SkScalar* inner = rects[1].asScalars();
576
577 bool allEq = true;
578
579 SkScalar margin = SkScalarAbs(outer[0] - inner[0]);
580 bool allGoE1 = margin >= SK_Scalar1;
581
582 for (int i = 1; i < 4; ++i) {
583 SkScalar temp = SkScalarAbs(outer[i] - inner[i]);
584 if (temp < SK_Scalar1) {
585 allGoE1 = false;
586 }
587 if (!SkScalarNearlyEqual(margin, temp)) {
588 allEq = false;
589 }
590 }
591
592 return allEq || allGoE1;
593}
594
robertphillips2e1e51f2015-10-15 08:01:48 -0700595void GrDrawContext::drawBatch(const GrClip& clip,
bsalomonabd30f52015-08-13 13:34:48 -0700596 const GrPaint& paint, GrDrawBatch* batch) {
joshualittb7ee1bf2015-08-10 11:59:02 -0700597 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700598 SkDEBUGCODE(this->validate();)
joshualittb7ee1bf2015-08-10 11:59:02 -0700599
600 AutoCheckFlush acf(fContext);
joshualittb7ee1bf2015-08-10 11:59:02 -0700601
robertphillips2e1e51f2015-10-15 08:01:48 -0700602 GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
robertphillipsa106c622015-10-16 09:07:06 -0700603 this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
joshualittb7ee1bf2015-08-10 11:59:02 -0700604}
605
robertphillips2e1e51f2015-10-15 08:01:48 -0700606void GrDrawContext::drawPath(const GrClip& clip,
robertphillipsea461502015-05-26 11:38:03 -0700607 const GrPaint& paint,
608 const SkMatrix& viewMatrix,
609 const SkPath& path,
610 const GrStrokeInfo& strokeInfo) {
611 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700612 SkDEBUGCODE(this->validate();)
613
robertphillipsea461502015-05-26 11:38:03 -0700614 if (path.isEmpty()) {
615 if (path.isInverseFillType()) {
robertphillips2e1e51f2015-10-15 08:01:48 -0700616 this->drawPaint(clip, paint, viewMatrix);
robertphillipsea461502015-05-26 11:38:03 -0700617 }
618 return;
619 }
620
621 GrColor color = paint.getColor();
622
623 // Note that internalDrawPath may sw-rasterize the path into a scratch texture.
624 // Scratch textures can be recycled after they are returned to the texture
625 // cache. This presents a potential hazard for buffered drawing. However,
626 // the writePixels that uploads to the scratch will perform a flush so we're
627 // OK.
628 AutoCheckFlush acf(fContext);
robertphillipsea461502015-05-26 11:38:03 -0700629
robertphillips2e1e51f2015-10-15 08:01:48 -0700630 GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, 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));
robertphillipsa106c622015-10-16 09:07:06 -0700642 this->getDrawTarget()->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()) {
robertphillipsa106c622015-10-16 09:07:06 -0700650 if (GrOvalRenderer::DrawOval(this->getDrawTarget(),
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 }
robertphillipsa106c622015-10-16 09:07:06 -0700661 this->internalDrawPath(this->getDrawTarget(), &pipelineBuilder, viewMatrix, color,
662 paint.isAntiAlias(), path, strokeInfo);
robertphillipsea461502015-05-26 11:38:03 -0700663}
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
robertphillipsea461502015-05-26 11:38:03 -0700675 // An Assumption here is that path renderer would use some form of tweaking
676 // the src color (either the input alpha or in the frag shader) to implement
677 // aa. If we have some future driver-mojo path AA that can do the right
678 // thing WRT to the blend then we'll need some query on the PR.
679 bool useCoverageAA = useAA &&
vbuzinovdded6962015-06-12 08:59:45 -0700680 !pipelineBuilder->getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -0700681
682
683 GrPathRendererChain::DrawType type =
684 useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType :
685 GrPathRendererChain::kColor_DrawType;
686
687 const SkPath* pathPtr = &path;
688 SkTLazy<SkPath> tmpPath;
689 const GrStrokeInfo* strokeInfoPtr = &strokeInfo;
690
691 // Try a 1st time without stroking the path and without allowing the SW renderer
692 GrPathRenderer* pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr,
693 *strokeInfoPtr, false, type);
694
695 GrStrokeInfo dashlessStrokeInfo(strokeInfo, false);
halcanary96fcdcc2015-08-27 07:41:13 -0700696 if (nullptr == pr && strokeInfo.isDashed()) {
robertphillipsea461502015-05-26 11:38:03 -0700697 // It didn't work above, so try again with dashed stroke converted to a dashless stroke.
698 if (!strokeInfo.applyDashToPath(tmpPath.init(), &dashlessStrokeInfo, *pathPtr)) {
699 return;
700 }
701 pathPtr = tmpPath.get();
702 if (pathPtr->isEmpty()) {
703 return;
704 }
705 strokeInfoPtr = &dashlessStrokeInfo;
706 pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
707 false, type);
708 }
709
halcanary96fcdcc2015-08-27 07:41:13 -0700710 if (nullptr == pr) {
711 if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*strokeInfoPtr, viewMatrix, nullptr) &&
robertphillipsea461502015-05-26 11:38:03 -0700712 !strokeInfoPtr->isFillStyle()) {
713 // It didn't work above, so try again with stroke converted to a fill.
714 if (!tmpPath.isValid()) {
715 tmpPath.init();
716 }
717 dashlessStrokeInfo.setResScale(SkScalarAbs(viewMatrix.getMaxScale()));
718 if (!dashlessStrokeInfo.applyToPath(tmpPath.get(), *pathPtr)) {
719 return;
720 }
721 pathPtr = tmpPath.get();
722 if (pathPtr->isEmpty()) {
723 return;
724 }
725 dashlessStrokeInfo.setFillStyle();
726 strokeInfoPtr = &dashlessStrokeInfo;
727 }
728
729 // This time, allow SW renderer
730 pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
731 true, type);
732 }
733
halcanary96fcdcc2015-08-27 07:41:13 -0700734 if (nullptr == pr) {
robertphillipsea461502015-05-26 11:38:03 -0700735#ifdef SK_DEBUG
736 SkDebugf("Unable to find path renderer compatible with path.\n");
737#endif
738 return;
739 }
740
bsalomon0aff2fa2015-07-31 06:48:27 -0700741 GrPathRenderer::DrawPathArgs args;
742 args.fTarget = target;
743 args.fResourceProvider = fContext->resourceProvider();
744 args.fPipelineBuilder = pipelineBuilder;
745 args.fColor = color;
746 args.fViewMatrix = &viewMatrix;
747 args.fPath = pathPtr;
748 args.fStroke = strokeInfoPtr;
749 args.fAntiAlias = useCoverageAA;
750 pr->drawPath(args);
robertphillipsea461502015-05-26 11:38:03 -0700751}
752
bsalomonabd30f52015-08-13 13:34:48 -0700753void GrDrawContext::drawBatch(GrPipelineBuilder* pipelineBuilder, GrDrawBatch* batch) {
robertphillips2d70dcb2015-10-06 07:38:23 -0700754 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700755 SkDEBUGCODE(this->validate();)
robertphillips2d70dcb2015-10-06 07:38:23 -0700756
robertphillipsa106c622015-10-16 09:07:06 -0700757 this->getDrawTarget()->drawBatch(*pipelineBuilder, batch);
robertphillips2334fb62015-06-17 05:43:33 -0700758}