blob: 99a1ce53906d1dedb6297f17918ebead4f143f7f [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"
robertphillips77a2e522015-10-17 07:43:27 -070013#include "GrDrawingManager.h"
robertphillipsea461502015-05-26 11:38:03 -070014#include "GrOvalRenderer.h"
15#include "GrPathRenderer.h"
robertphillips2334fb62015-06-17 05:43:33 -070016#include "GrRenderTarget.h"
17#include "GrRenderTargetPriv.h"
bsalomon473addf2015-10-02 07:49:05 -070018#include "GrResourceProvider.h"
robertphillips2334fb62015-06-17 05:43:33 -070019#include "GrStencilAndCoverTextContext.h"
robertphillips2d70dcb2015-10-06 07:38:23 -070020#include "SkSurfacePriv.h"
robertphillipsea461502015-05-26 11:38:03 -070021
joshualitt74417822015-08-07 11:42:16 -070022#include "batches/GrBatch.h"
jvanverth14b88032015-08-07 12:18:54 -070023#include "batches/GrDrawAtlasBatch.h"
joshualitt2771b562015-08-07 12:46:26 -070024#include "batches/GrDrawVerticesBatch.h"
joshualitt7fc2a262015-08-10 10:30:14 -070025#include "batches/GrRectBatchFactory.h"
joshualitt74417822015-08-07 11:42:16 -070026
robertphillips77a2e522015-10-17 07:43:27 -070027#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == fDrawingManager->getContext())
28#define RETURN_IF_ABANDONED if (fDrawingManager->abandoned()) { return; }
29#define RETURN_FALSE_IF_ABANDONED if (fDrawingManager->abandoned()) { return false; }
30#define RETURN_NULL_IF_ABANDONED if (fDrawingManager->abandoned()) { return nullptr; }
robertphillipsea461502015-05-26 11:38:03 -070031
32class AutoCheckFlush {
33public:
robertphillips77a2e522015-10-17 07:43:27 -070034 AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) {
35 SkASSERT(fDrawingManager);
36 }
37 ~AutoCheckFlush() { fDrawingManager->getContext()->flushIfNecessary(); }
robertphillipsea461502015-05-26 11:38:03 -070038
39private:
robertphillips77a2e522015-10-17 07:43:27 -070040 GrDrawingManager* fDrawingManager;
robertphillipsea461502015-05-26 11:38:03 -070041};
42
robertphillipsa106c622015-10-16 09:07:06 -070043// In MDB mode the reffing of the 'getLastDrawTarget' call's result allows in-progress
44// drawTargets to be picked up and added to by drawContexts lower in the call
45// stack. When this occurs with a closed drawTarget, a new one will be allocated
46// when the drawContext attempts to use it (via getDrawTarget).
robertphillips77a2e522015-10-17 07:43:27 -070047GrDrawContext::GrDrawContext(GrDrawingManager* drawingMgr,
robertphillips2e1e51f2015-10-15 08:01:48 -070048 GrRenderTarget* rt,
robertphillips2d70dcb2015-10-06 07:38:23 -070049 const SkSurfaceProps* surfaceProps)
robertphillips77a2e522015-10-17 07:43:27 -070050 : fDrawingManager(drawingMgr)
robertphillips2e1e51f2015-10-15 08:01:48 -070051 , fRenderTarget(rt)
robertphillipsa106c622015-10-16 09:07:06 -070052 , fDrawTarget(SkSafeRef(rt->getLastDrawTarget()))
halcanary96fcdcc2015-08-27 07:41:13 -070053 , fTextContext(nullptr)
robertphillips2d70dcb2015-10-06 07:38:23 -070054 , fSurfaceProps(SkSurfacePropsCopyOrDefault(surfaceProps)) {
robertphillips2e1e51f2015-10-15 08:01:48 -070055 SkDEBUGCODE(this->validate();)
robertphillipsea461502015-05-26 11:38:03 -070056}
57
robertphillips2e1e51f2015-10-15 08:01:48 -070058#ifdef SK_DEBUG
59void GrDrawContext::validate() const {
60 SkASSERT(fRenderTarget);
61 ASSERT_OWNED_RESOURCE(fRenderTarget);
robertphillipsa106c622015-10-16 09:07:06 -070062
63 if (fDrawTarget && !fDrawTarget->isClosed()) {
64 SkASSERT(fRenderTarget->getLastDrawTarget() == fDrawTarget);
65 }
robertphillips2e1e51f2015-10-15 08:01:48 -070066}
67#endif
68
robertphillipsa106c622015-10-16 09:07:06 -070069GrDrawContext::~GrDrawContext() {
70 SkSafeUnref(fDrawTarget);
71}
72
73GrDrawTarget* GrDrawContext::getDrawTarget() {
74 SkDEBUGCODE(this->validate();)
75
76 if (!fDrawTarget || fDrawTarget->isClosed()) {
robertphillips77a2e522015-10-17 07:43:27 -070077 fDrawTarget = fDrawingManager->newDrawTarget(fRenderTarget);
robertphillipsa106c622015-10-16 09:07:06 -070078 fRenderTarget->setLastDrawTarget(fDrawTarget);
79 }
80
81 return fDrawTarget;
82}
83
robertphillips2e1e51f2015-10-15 08:01:48 -070084void GrDrawContext::copySurface(GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) {
robertphillips2d70dcb2015-10-06 07:38:23 -070085 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -070086 SkDEBUGCODE(this->validate();)
robertphillips2d70dcb2015-10-06 07:38:23 -070087
robertphillipsa106c622015-10-16 09:07:06 -070088 this->getDrawTarget()->copySurface(fRenderTarget, src, srcRect, dstPoint);
robertphillipsea461502015-05-26 11:38:03 -070089}
90
robertphillips2334fb62015-06-17 05:43:33 -070091
robertphillips2e1e51f2015-10-15 08:01:48 -070092void GrDrawContext::drawText(const GrClip& clip, const GrPaint& grPaint,
robertphillips2334fb62015-06-17 05:43:33 -070093 const SkPaint& skPaint,
94 const SkMatrix& viewMatrix,
95 const char text[], size_t byteLength,
96 SkScalar x, SkScalar y, const SkIRect& clipBounds) {
robertphillips2d70dcb2015-10-06 07:38:23 -070097 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -070098 SkDEBUGCODE(this->validate();)
robertphillips2d70dcb2015-10-06 07:38:23 -070099
robertphillips2334fb62015-06-17 05:43:33 -0700100 if (!fTextContext) {
robertphillips77a2e522015-10-17 07:43:27 -0700101 fTextContext = fDrawingManager->textContext(fSurfaceProps, fRenderTarget);
robertphillips2334fb62015-06-17 05:43:33 -0700102 }
103
robertphillips2e1e51f2015-10-15 08:01:48 -0700104 fTextContext->drawText(this, fRenderTarget, clip, grPaint, skPaint, viewMatrix,
robertphillips2334fb62015-06-17 05:43:33 -0700105 text, byteLength, x, y, clipBounds);
106
107}
robertphillips2e1e51f2015-10-15 08:01:48 -0700108void GrDrawContext::drawPosText(const GrClip& clip, const GrPaint& grPaint,
robertphillips2334fb62015-06-17 05:43:33 -0700109 const SkPaint& skPaint,
110 const SkMatrix& viewMatrix,
111 const char text[], size_t byteLength,
112 const SkScalar pos[], int scalarsPerPosition,
113 const SkPoint& offset, const SkIRect& clipBounds) {
robertphillips2d70dcb2015-10-06 07:38:23 -0700114 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700115 SkDEBUGCODE(this->validate();)
robertphillips2d70dcb2015-10-06 07:38:23 -0700116
robertphillips2334fb62015-06-17 05:43:33 -0700117 if (!fTextContext) {
robertphillips77a2e522015-10-17 07:43:27 -0700118 fTextContext = fDrawingManager->textContext(fSurfaceProps, fRenderTarget);
robertphillips2334fb62015-06-17 05:43:33 -0700119 }
120
robertphillips2e1e51f2015-10-15 08:01:48 -0700121 fTextContext->drawPosText(this, fRenderTarget, clip, grPaint, skPaint, viewMatrix, text, byteLength,
robertphillipsf6703fa2015-09-01 05:36:47 -0700122 pos, scalarsPerPosition, offset, clipBounds);
robertphillips2334fb62015-06-17 05:43:33 -0700123
124}
robertphillips2e1e51f2015-10-15 08:01:48 -0700125void GrDrawContext::drawTextBlob(const GrClip& clip, const SkPaint& skPaint,
robertphillips2334fb62015-06-17 05:43:33 -0700126 const SkMatrix& viewMatrix, const SkTextBlob* blob,
127 SkScalar x, SkScalar y,
128 SkDrawFilter* filter, const SkIRect& clipBounds) {
robertphillips2d70dcb2015-10-06 07:38:23 -0700129 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700130 SkDEBUGCODE(this->validate();)
robertphillips2d70dcb2015-10-06 07:38:23 -0700131
robertphillips2334fb62015-06-17 05:43:33 -0700132 if (!fTextContext) {
robertphillips77a2e522015-10-17 07:43:27 -0700133 fTextContext = fDrawingManager->textContext(fSurfaceProps, fRenderTarget);
robertphillips2334fb62015-06-17 05:43:33 -0700134 }
135
robertphillips2e1e51f2015-10-15 08:01:48 -0700136 fTextContext->drawTextBlob(this, fRenderTarget,
robertphillipsf6703fa2015-09-01 05:36:47 -0700137 clip, skPaint, viewMatrix, blob, x, y, filter, clipBounds);
robertphillipsea461502015-05-26 11:38:03 -0700138}
139
bsalomon1fcc01c2015-09-09 09:48:06 -0700140void GrDrawContext::drawPathsFromRange(const GrPipelineBuilder* pipelineBuilder,
joshualittf2384692015-09-10 11:00:51 -0700141 const SkMatrix& viewMatrix,
142 const SkMatrix& localMatrix,
143 GrColor color,
cdalton8585dd22015-10-08 08:04:09 -0700144 GrPathRange* range,
bsalomon1fcc01c2015-09-09 09:48:06 -0700145 GrPathRangeDraw* draw,
146 int /*GrPathRendering::FillType*/ fill) {
robertphillips2d70dcb2015-10-06 07:38:23 -0700147 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700148 SkDEBUGCODE(this->validate();)
robertphillips2d70dcb2015-10-06 07:38:23 -0700149
robertphillipsa106c622015-10-16 09:07:06 -0700150 this->getDrawTarget()->drawPathsFromRange(*pipelineBuilder, viewMatrix, localMatrix, color,
151 range, draw, (GrPathRendering::FillType) fill);
robertphillipsea461502015-05-26 11:38:03 -0700152}
153
robertphillips2e1e51f2015-10-15 08:01:48 -0700154void GrDrawContext::discard() {
robertphillipsea461502015-05-26 11:38:03 -0700155 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700156 SkDEBUGCODE(this->validate();)
157
robertphillips77a2e522015-10-17 07:43:27 -0700158 AutoCheckFlush acf(fDrawingManager);
robertphillipsa106c622015-10-16 09:07:06 -0700159 this->getDrawTarget()->discard(fRenderTarget);
robertphillipsea461502015-05-26 11:38:03 -0700160}
161
robertphillips2e1e51f2015-10-15 08:01:48 -0700162void GrDrawContext::clear(const SkIRect* rect,
robertphillipsea461502015-05-26 11:38:03 -0700163 const GrColor color,
164 bool canIgnoreRect) {
165 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700166 SkDEBUGCODE(this->validate();)
robertphillipsea461502015-05-26 11:38:03 -0700167
robertphillips77a2e522015-10-17 07:43:27 -0700168 AutoCheckFlush acf(fDrawingManager);
robertphillipsa106c622015-10-16 09:07:06 -0700169 this->getDrawTarget()->clear(rect, color, canIgnoreRect, fRenderTarget);
robertphillipsea461502015-05-26 11:38:03 -0700170}
171
172
robertphillips2e1e51f2015-10-15 08:01:48 -0700173void GrDrawContext::drawPaint(const GrClip& clip,
robertphillipsea461502015-05-26 11:38:03 -0700174 const GrPaint& origPaint,
175 const SkMatrix& viewMatrix) {
176 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700177 SkDEBUGCODE(this->validate();)
178
robertphillipsea461502015-05-26 11:38:03 -0700179 // set rect to be big enough to fill the space, but not super-huge, so we
180 // don't overflow fixed-point implementations
181 SkRect r;
182 r.setLTRB(0, 0,
robertphillips2e1e51f2015-10-15 08:01:48 -0700183 SkIntToScalar(fRenderTarget->width()),
184 SkIntToScalar(fRenderTarget->height()));
robertphillipsea461502015-05-26 11:38:03 -0700185 SkTCopyOnFirstWrite<GrPaint> paint(origPaint);
186
187 // by definition this fills the entire clip, no need for AA
188 if (paint->isAntiAlias()) {
189 paint.writable()->setAntiAlias(false);
190 }
191
192 bool isPerspective = viewMatrix.hasPerspective();
193
194 // We attempt to map r by the inverse matrix and draw that. mapRect will
195 // map the four corners and bound them with a new rect. This will not
196 // produce a correct result for some perspective matrices.
197 if (!isPerspective) {
198 SkMatrix inverse;
199 if (!viewMatrix.invert(&inverse)) {
200 SkDebugf("Could not invert matrix\n");
201 return;
202 }
203 inverse.mapRect(&r);
robertphillips2e1e51f2015-10-15 08:01:48 -0700204 this->drawRect(clip, *paint, viewMatrix, r);
robertphillipsea461502015-05-26 11:38:03 -0700205 } else {
206 SkMatrix localMatrix;
207 if (!viewMatrix.invert(&localMatrix)) {
208 SkDebugf("Could not invert matrix\n");
209 return;
210 }
211
robertphillips77a2e522015-10-17 07:43:27 -0700212 AutoCheckFlush acf(fDrawingManager);
robertphillipsea461502015-05-26 11:38:03 -0700213
robertphillips2e1e51f2015-10-15 08:01:48 -0700214 GrPipelineBuilder pipelineBuilder(*paint, fRenderTarget, clip);
robertphillipsa106c622015-10-16 09:07:06 -0700215 this->getDrawTarget()->drawNonAARect(pipelineBuilder,
216 paint->getColor(),
217 SkMatrix::I(),
218 r,
219 localMatrix);
robertphillipsea461502015-05-26 11:38:03 -0700220 }
221}
222
robertphillipsea461502015-05-26 11:38:03 -0700223static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) {
224 return point.fX >= rect.fLeft && point.fX <= rect.fRight &&
225 point.fY >= rect.fTop && point.fY <= rect.fBottom;
226}
227
robertphillips2e1e51f2015-10-15 08:01:48 -0700228void GrDrawContext::drawRect(const GrClip& clip,
robertphillipsea461502015-05-26 11:38:03 -0700229 const GrPaint& paint,
230 const SkMatrix& viewMatrix,
231 const SkRect& rect,
232 const GrStrokeInfo* strokeInfo) {
233 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700234 SkDEBUGCODE(this->validate();)
235
robertphillipsea461502015-05-26 11:38:03 -0700236 if (strokeInfo && strokeInfo->isDashed()) {
237 SkPath path;
238 path.setIsVolatile(true);
239 path.addRect(rect);
robertphillips2e1e51f2015-10-15 08:01:48 -0700240 this->drawPath(clip, paint, viewMatrix, path, *strokeInfo);
robertphillipsea461502015-05-26 11:38:03 -0700241 return;
242 }
243
robertphillips77a2e522015-10-17 07:43:27 -0700244 AutoCheckFlush acf(fDrawingManager);
robertphillipsea461502015-05-26 11:38:03 -0700245
robertphillips2e1e51f2015-10-15 08:01:48 -0700246 GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
joshualitt7b670db2015-07-09 13:25:02 -0700247
halcanary96fcdcc2015-08-27 07:41:13 -0700248 SkScalar width = nullptr == strokeInfo ? -1 : strokeInfo->getWidth();
robertphillipsea461502015-05-26 11:38:03 -0700249
250 // Check if this is a full RT draw and can be replaced with a clear. We don't bother checking
251 // cases where the RT is fully inside a stroke.
252 if (width < 0) {
253 SkRect rtRect;
254 pipelineBuilder.getRenderTarget()->getBoundsRect(&rtRect);
255 SkRect clipSpaceRTRect = rtRect;
256 bool checkClip = GrClip::kWideOpen_ClipType != clip.clipType();
257 if (checkClip) {
258 clipSpaceRTRect.offset(SkIntToScalar(clip.origin().fX),
259 SkIntToScalar(clip.origin().fY));
260 }
261 // Does the clip contain the entire RT?
262 if (!checkClip || clip.quickContains(clipSpaceRTRect)) {
263 SkMatrix invM;
264 if (!viewMatrix.invert(&invM)) {
265 return;
266 }
267 // Does the rect bound the RT?
268 SkPoint srcSpaceRTQuad[4];
269 invM.mapRectToQuad(srcSpaceRTQuad, rtRect);
270 if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) &&
271 rect_contains_inclusive(rect, srcSpaceRTQuad[1]) &&
272 rect_contains_inclusive(rect, srcSpaceRTQuad[2]) &&
273 rect_contains_inclusive(rect, srcSpaceRTQuad[3])) {
274 // Will it blend?
275 GrColor clearColor;
cdalton1fa45722015-06-02 10:43:39 -0700276 if (paint.isConstantBlendedColor(&clearColor)) {
robertphillipsa106c622015-10-16 09:07:06 -0700277 this->getDrawTarget()->clear(nullptr, clearColor, true, fRenderTarget);
robertphillipsea461502015-05-26 11:38:03 -0700278 return;
279 }
280 }
281 }
282 }
283
284 GrColor color = paint.getColor();
vbuzinovdded6962015-06-12 08:59:45 -0700285 bool needAA = paint.isAntiAlias() &&
286 !pipelineBuilder.getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -0700287
joshualitt9be0b002015-08-19 11:50:51 -0700288 // The fill path can handle rotation but not skew
289 // The stroke path needs the rect to remain axis aligned (no rotation or skew)
robertphillipsfac9ceb2015-09-03 08:32:08 -0700290 // None of our AA draw rect calls can handle perspective yet
joshualitt9be0b002015-08-19 11:50:51 -0700291 bool canApplyAA = width >=0 ? viewMatrix.rectStaysRect() : viewMatrix.preservesRightAngles();
292
293 if (needAA && canApplyAA) {
robertphillipsfac9ceb2015-09-03 08:32:08 -0700294 SkASSERT(!viewMatrix.hasPerspective());
bsalomonabd30f52015-08-13 13:34:48 -0700295 SkAutoTUnref<GrDrawBatch> batch;
robertphillipsea461502015-05-26 11:38:03 -0700296 if (width >= 0) {
joshualitt10cae832015-09-22 12:50:33 -0700297 batch.reset(GrRectBatchFactory::CreateAAStroke(color, viewMatrix, rect, *strokeInfo));
robertphillipsea461502015-05-26 11:38:03 -0700298 } else {
joshualitt10cae832015-09-22 12:50:33 -0700299 SkRect devBoundRect;
300 viewMatrix.mapRect(&devBoundRect, rect);
joshualittd2b23e02015-08-21 10:53:34 -0700301 batch.reset(GrRectBatchFactory::CreateAAFill(color, viewMatrix, rect, devBoundRect));
robertphillipsea461502015-05-26 11:38:03 -0700302 }
robertphillipsa106c622015-10-16 09:07:06 -0700303 this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
robertphillipsea461502015-05-26 11:38:03 -0700304 return;
305 }
306
307 if (width >= 0) {
robertphillipsea461502015-05-26 11:38:03 -0700308 // Non-AA hairlines are snapped to pixel centers to make which pixels are hit deterministic
robertphillips2e1e51f2015-10-15 08:01:48 -0700309 bool snapToPixelCenters = (0 == width && !fRenderTarget->isUnifiedMultisampled());
joshualittd2b23e02015-08-21 10:53:34 -0700310 SkAutoTUnref<GrDrawBatch> batch(GrRectBatchFactory::CreateNonAAStroke(
bsalomonabd30f52015-08-13 13:34:48 -0700311 color, viewMatrix, rect, width, snapToPixelCenters));
robertphillipsea461502015-05-26 11:38:03 -0700312
313 // Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of
314 // hairline rects. We jam all the vertices to pixel centers to avoid this, but not when MSAA
315 // is enabled because it can cause ugly artifacts.
316 pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_Flag,
317 snapToPixelCenters);
robertphillipsa106c622015-10-16 09:07:06 -0700318 this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
robertphillipsea461502015-05-26 11:38:03 -0700319 } else {
320 // filled BW rect
robertphillipsa106c622015-10-16 09:07:06 -0700321 this->getDrawTarget()->drawNonAARect(pipelineBuilder, color, viewMatrix, rect);
robertphillipsea461502015-05-26 11:38:03 -0700322 }
323}
324
robertphillips2e1e51f2015-10-15 08:01:48 -0700325void GrDrawContext::drawNonAARectToRect(const GrClip& clip,
robertphillipsea461502015-05-26 11:38:03 -0700326 const GrPaint& paint,
327 const SkMatrix& viewMatrix,
328 const SkRect& rectToDraw,
joshualittb6b513b2015-08-21 10:25:18 -0700329 const SkRect& localRect) {
robertphillipsea461502015-05-26 11:38:03 -0700330 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700331 SkDEBUGCODE(this->validate();)
robertphillipsea461502015-05-26 11:38:03 -0700332
robertphillips77a2e522015-10-17 07:43:27 -0700333 AutoCheckFlush acf(fDrawingManager);
robertphillips2e1e51f2015-10-15 08:01:48 -0700334
335 GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
robertphillipsa106c622015-10-16 09:07:06 -0700336 this->getDrawTarget()->drawNonAARect(pipelineBuilder,
337 paint.getColor(),
338 viewMatrix,
339 rectToDraw,
340 localRect);
joshualittb6b513b2015-08-21 10:25:18 -0700341}
342
robertphillips2e1e51f2015-10-15 08:01:48 -0700343void GrDrawContext::drawNonAARectWithLocalMatrix(const GrClip& clip,
joshualittb6b513b2015-08-21 10:25:18 -0700344 const GrPaint& paint,
345 const SkMatrix& viewMatrix,
346 const SkRect& rectToDraw,
347 const SkMatrix& localMatrix) {
348 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700349 SkDEBUGCODE(this->validate();)
joshualittb6b513b2015-08-21 10:25:18 -0700350
robertphillips77a2e522015-10-17 07:43:27 -0700351 AutoCheckFlush acf(fDrawingManager);
robertphillips2e1e51f2015-10-15 08:01:48 -0700352
353 GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
robertphillipsa106c622015-10-16 09:07:06 -0700354 this->getDrawTarget()->drawNonAARect(pipelineBuilder,
355 paint.getColor(),
356 viewMatrix,
357 rectToDraw,
358 localMatrix);
robertphillipsea461502015-05-26 11:38:03 -0700359}
360
robertphillips2e1e51f2015-10-15 08:01:48 -0700361void GrDrawContext::drawVertices(const GrClip& clip,
robertphillipsea461502015-05-26 11:38:03 -0700362 const GrPaint& paint,
363 const SkMatrix& viewMatrix,
364 GrPrimitiveType primitiveType,
365 int vertexCount,
366 const SkPoint positions[],
367 const SkPoint texCoords[],
368 const GrColor colors[],
369 const uint16_t indices[],
370 int indexCount) {
371 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700372 SkDEBUGCODE(this->validate();)
robertphillipsea461502015-05-26 11:38:03 -0700373
robertphillips77a2e522015-10-17 07:43:27 -0700374 AutoCheckFlush acf(fDrawingManager);
robertphillips2e1e51f2015-10-15 08:01:48 -0700375
376 GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
joshualitt7b670db2015-07-09 13:25:02 -0700377
robertphillipsea461502015-05-26 11:38:03 -0700378 // TODO clients should give us bounds
379 SkRect bounds;
380 if (!bounds.setBoundsCheck(positions, vertexCount)) {
381 SkDebugf("drawVertices call empty bounds\n");
382 return;
383 }
384
385 viewMatrix.mapRect(&bounds);
386
387 // If we don't have AA then we outset for a half pixel in each direction to account for
388 // snapping
389 if (!paint.isAntiAlias()) {
390 bounds.outset(0.5f, 0.5f);
391 }
392
joshualitt2771b562015-08-07 12:46:26 -0700393 GrDrawVerticesBatch::Geometry geometry;
robertphillipsea461502015-05-26 11:38:03 -0700394 geometry.fColor = paint.getColor();
bsalomonabd30f52015-08-13 13:34:48 -0700395 SkAutoTUnref<GrDrawBatch> batch(GrDrawVerticesBatch::Create(geometry, primitiveType, viewMatrix,
396 positions, vertexCount, indices,
397 indexCount, colors, texCoords,
398 bounds));
robertphillipsea461502015-05-26 11:38:03 -0700399
robertphillipsa106c622015-10-16 09:07:06 -0700400 this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
robertphillipsea461502015-05-26 11:38:03 -0700401}
402
403///////////////////////////////////////////////////////////////////////////////
404
robertphillips2e1e51f2015-10-15 08:01:48 -0700405void GrDrawContext::drawAtlas(const GrClip& clip,
jvanverth31ff7622015-08-07 10:09:28 -0700406 const GrPaint& paint,
407 const SkMatrix& viewMatrix,
408 int spriteCount,
409 const SkRSXform xform[],
410 const SkRect texRect[],
411 const SkColor colors[]) {
412 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700413 SkDEBUGCODE(this->validate();)
414
robertphillips77a2e522015-10-17 07:43:27 -0700415 AutoCheckFlush acf(fDrawingManager);
jvanverth31ff7622015-08-07 10:09:28 -0700416
robertphillips2e1e51f2015-10-15 08:01:48 -0700417 GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
jvanverth31ff7622015-08-07 10:09:28 -0700418
jvanverth14b88032015-08-07 12:18:54 -0700419 GrDrawAtlasBatch::Geometry geometry;
jvanverth31ff7622015-08-07 10:09:28 -0700420 geometry.fColor = paint.getColor();
bsalomonabd30f52015-08-13 13:34:48 -0700421 SkAutoTUnref<GrDrawBatch> batch(GrDrawAtlasBatch::Create(geometry, viewMatrix, spriteCount,
422 xform, texRect, colors));
jvanverth31ff7622015-08-07 10:09:28 -0700423
robertphillipsa106c622015-10-16 09:07:06 -0700424 this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
jvanverth31ff7622015-08-07 10:09:28 -0700425}
426
427///////////////////////////////////////////////////////////////////////////////
428
robertphillips2e1e51f2015-10-15 08:01:48 -0700429void GrDrawContext::drawRRect(const GrClip& clip,
robertphillipsea461502015-05-26 11:38:03 -0700430 const GrPaint& paint,
431 const SkMatrix& viewMatrix,
432 const SkRRect& rrect,
433 const GrStrokeInfo& strokeInfo) {
434 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700435 SkDEBUGCODE(this->validate();)
436
robertphillipsea461502015-05-26 11:38:03 -0700437 if (rrect.isEmpty()) {
438 return;
439 }
440
441 if (strokeInfo.isDashed()) {
442 SkPath path;
443 path.setIsVolatile(true);
444 path.addRRect(rrect);
robertphillips2e1e51f2015-10-15 08:01:48 -0700445 this->drawPath(clip, paint, viewMatrix, path, strokeInfo);
robertphillipsea461502015-05-26 11:38:03 -0700446 return;
447 }
448
robertphillips77a2e522015-10-17 07:43:27 -0700449 AutoCheckFlush acf(fDrawingManager);
robertphillipsea461502015-05-26 11:38:03 -0700450
robertphillips2e1e51f2015-10-15 08:01:48 -0700451 GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
robertphillipsea461502015-05-26 11:38:03 -0700452 GrColor color = paint.getColor();
robertphillips2e1e51f2015-10-15 08:01:48 -0700453
robertphillipsa106c622015-10-16 09:07:06 -0700454 if (!GrOvalRenderer::DrawRRect(this->getDrawTarget(),
joshualittae3d63a2015-07-13 08:44:06 -0700455 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700456 color,
457 viewMatrix,
458 paint.isAntiAlias(),
459 rrect,
460 strokeInfo)) {
461 SkPath path;
462 path.setIsVolatile(true);
463 path.addRRect(rrect);
robertphillipsa106c622015-10-16 09:07:06 -0700464 this->internalDrawPath(this->getDrawTarget(), &pipelineBuilder, viewMatrix, color,
robertphillipsea461502015-05-26 11:38:03 -0700465 paint.isAntiAlias(), path, strokeInfo);
466 }
467}
468
469///////////////////////////////////////////////////////////////////////////////
470
robertphillips2e1e51f2015-10-15 08:01:48 -0700471void GrDrawContext::drawDRRect(const GrClip& clip,
robertphillipsea461502015-05-26 11:38:03 -0700472 const GrPaint& paint,
473 const SkMatrix& viewMatrix,
474 const SkRRect& outer,
475 const SkRRect& inner) {
476 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700477 SkDEBUGCODE(this->validate();)
478
robertphillipsea461502015-05-26 11:38:03 -0700479 if (outer.isEmpty()) {
480 return;
481 }
482
robertphillips77a2e522015-10-17 07:43:27 -0700483 AutoCheckFlush acf(fDrawingManager);
robertphillipsea461502015-05-26 11:38:03 -0700484
robertphillips2e1e51f2015-10-15 08:01:48 -0700485 GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
robertphillipsea461502015-05-26 11:38:03 -0700486 GrColor color = paint.getColor();
robertphillipsa106c622015-10-16 09:07:06 -0700487 if (!GrOvalRenderer::DrawDRRect(this->getDrawTarget(),
joshualittae3d63a2015-07-13 08:44:06 -0700488 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700489 color,
490 viewMatrix,
491 paint.isAntiAlias(),
492 outer,
493 inner)) {
494 SkPath path;
495 path.setIsVolatile(true);
496 path.addRRect(inner);
497 path.addRRect(outer);
498 path.setFillType(SkPath::kEvenOdd_FillType);
499
500 GrStrokeInfo fillRec(SkStrokeRec::kFill_InitStyle);
robertphillipsa106c622015-10-16 09:07:06 -0700501 this->internalDrawPath(this->getDrawTarget(), &pipelineBuilder, viewMatrix, color,
robertphillipsea461502015-05-26 11:38:03 -0700502 paint.isAntiAlias(), path, fillRec);
503 }
504}
505
506///////////////////////////////////////////////////////////////////////////////
507
robertphillips2e1e51f2015-10-15 08:01:48 -0700508void GrDrawContext::drawOval(const GrClip& clip,
robertphillipsea461502015-05-26 11:38:03 -0700509 const GrPaint& paint,
510 const SkMatrix& viewMatrix,
511 const SkRect& oval,
512 const GrStrokeInfo& strokeInfo) {
513 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700514 SkDEBUGCODE(this->validate();)
515
robertphillipsea461502015-05-26 11:38:03 -0700516 if (oval.isEmpty()) {
517 return;
518 }
519
520 if (strokeInfo.isDashed()) {
521 SkPath path;
522 path.setIsVolatile(true);
523 path.addOval(oval);
robertphillips2e1e51f2015-10-15 08:01:48 -0700524 this->drawPath(clip, paint, viewMatrix, path, strokeInfo);
robertphillipsea461502015-05-26 11:38:03 -0700525 return;
526 }
527
robertphillips77a2e522015-10-17 07:43:27 -0700528 AutoCheckFlush acf(fDrawingManager);
robertphillipsea461502015-05-26 11:38:03 -0700529
robertphillips2e1e51f2015-10-15 08:01:48 -0700530 GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
robertphillipsea461502015-05-26 11:38:03 -0700531 GrColor color = paint.getColor();
robertphillips2e1e51f2015-10-15 08:01:48 -0700532
robertphillipsa106c622015-10-16 09:07:06 -0700533 if (!GrOvalRenderer::DrawOval(this->getDrawTarget(),
joshualittae3d63a2015-07-13 08:44:06 -0700534 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700535 color,
536 viewMatrix,
537 paint.isAntiAlias(),
538 oval,
539 strokeInfo)) {
540 SkPath path;
541 path.setIsVolatile(true);
542 path.addOval(oval);
robertphillipsa106c622015-10-16 09:07:06 -0700543 this->internalDrawPath(this->getDrawTarget(), &pipelineBuilder, viewMatrix, color,
robertphillipsea461502015-05-26 11:38:03 -0700544 paint.isAntiAlias(), path, strokeInfo);
545 }
546}
547
548// Can 'path' be drawn as a pair of filled nested rectangles?
joshualittf9c5db22015-07-10 11:31:01 -0700549static bool is_nested_rects(const SkMatrix& viewMatrix,
robertphillipsea461502015-05-26 11:38:03 -0700550 const SkPath& path,
551 const SkStrokeRec& stroke,
552 SkRect rects[2]) {
553 SkASSERT(stroke.isFillStyle());
554
555 if (path.isInverseFillType()) {
556 return false;
557 }
558
559 // TODO: this restriction could be lifted if we were willing to apply
560 // the matrix to all the points individually rather than just to the rect
561 if (!viewMatrix.preservesAxisAlignment()) {
562 return false;
563 }
564
565 SkPath::Direction dirs[2];
566 if (!path.isNestedFillRects(rects, dirs)) {
567 return false;
568 }
569
570 if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) {
571 // The two rects need to be wound opposite to each other
572 return false;
573 }
574
575 // Right now, nested rects where the margin is not the same width
576 // all around do not render correctly
577 const SkScalar* outer = rects[0].asScalars();
578 const SkScalar* inner = rects[1].asScalars();
579
580 bool allEq = true;
581
582 SkScalar margin = SkScalarAbs(outer[0] - inner[0]);
583 bool allGoE1 = margin >= SK_Scalar1;
584
585 for (int i = 1; i < 4; ++i) {
586 SkScalar temp = SkScalarAbs(outer[i] - inner[i]);
587 if (temp < SK_Scalar1) {
588 allGoE1 = false;
589 }
590 if (!SkScalarNearlyEqual(margin, temp)) {
591 allEq = false;
592 }
593 }
594
595 return allEq || allGoE1;
596}
597
robertphillips2e1e51f2015-10-15 08:01:48 -0700598void GrDrawContext::drawBatch(const GrClip& clip,
bsalomonabd30f52015-08-13 13:34:48 -0700599 const GrPaint& paint, GrDrawBatch* batch) {
joshualittb7ee1bf2015-08-10 11:59:02 -0700600 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700601 SkDEBUGCODE(this->validate();)
joshualittb7ee1bf2015-08-10 11:59:02 -0700602
robertphillips77a2e522015-10-17 07:43:27 -0700603 AutoCheckFlush acf(fDrawingManager);
joshualittb7ee1bf2015-08-10 11:59:02 -0700604
robertphillips2e1e51f2015-10-15 08:01:48 -0700605 GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
robertphillipsa106c622015-10-16 09:07:06 -0700606 this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
joshualittb7ee1bf2015-08-10 11:59:02 -0700607}
608
robertphillips2e1e51f2015-10-15 08:01:48 -0700609void GrDrawContext::drawPath(const GrClip& clip,
robertphillipsea461502015-05-26 11:38:03 -0700610 const GrPaint& paint,
611 const SkMatrix& viewMatrix,
612 const SkPath& path,
613 const GrStrokeInfo& strokeInfo) {
614 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700615 SkDEBUGCODE(this->validate();)
616
robertphillipsea461502015-05-26 11:38:03 -0700617 if (path.isEmpty()) {
618 if (path.isInverseFillType()) {
robertphillips2e1e51f2015-10-15 08:01:48 -0700619 this->drawPaint(clip, paint, viewMatrix);
robertphillipsea461502015-05-26 11:38:03 -0700620 }
621 return;
622 }
623
624 GrColor color = paint.getColor();
625
626 // Note that internalDrawPath may sw-rasterize the path into a scratch texture.
627 // Scratch textures can be recycled after they are returned to the texture
628 // cache. This presents a potential hazard for buffered drawing. However,
629 // the writePixels that uploads to the scratch will perform a flush so we're
630 // OK.
robertphillips77a2e522015-10-17 07:43:27 -0700631 AutoCheckFlush acf(fDrawingManager);
robertphillipsea461502015-05-26 11:38:03 -0700632
robertphillips2e1e51f2015-10-15 08:01:48 -0700633 GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
robertphillipsea461502015-05-26 11:38:03 -0700634 if (!strokeInfo.isDashed()) {
635 bool useCoverageAA = paint.isAntiAlias() &&
vbuzinovdded6962015-06-12 08:59:45 -0700636 !pipelineBuilder.getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -0700637
638 if (useCoverageAA && strokeInfo.getWidth() < 0 && !path.isConvex()) {
639 // Concave AA paths are expensive - try to avoid them for special cases
640 SkRect rects[2];
641
joshualittf9c5db22015-07-10 11:31:01 -0700642 if (is_nested_rects(viewMatrix, path, strokeInfo, rects)) {
joshualittd2b23e02015-08-21 10:53:34 -0700643 SkAutoTUnref<GrDrawBatch> batch(GrRectBatchFactory::CreateAAFillNestedRects(
bsalomonabd30f52015-08-13 13:34:48 -0700644 color, viewMatrix, rects));
robertphillipsa106c622015-10-16 09:07:06 -0700645 this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
robertphillipsea461502015-05-26 11:38:03 -0700646 return;
647 }
648 }
649 SkRect ovalRect;
650 bool isOval = path.isOval(&ovalRect);
651
652 if (isOval && !path.isInverseFillType()) {
robertphillipsa106c622015-10-16 09:07:06 -0700653 if (GrOvalRenderer::DrawOval(this->getDrawTarget(),
joshualittae3d63a2015-07-13 08:44:06 -0700654 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700655 color,
656 viewMatrix,
657 paint.isAntiAlias(),
658 ovalRect,
659 strokeInfo)) {
660 return;
661 }
662 }
663 }
robertphillipsa106c622015-10-16 09:07:06 -0700664 this->internalDrawPath(this->getDrawTarget(), &pipelineBuilder, viewMatrix, color,
665 paint.isAntiAlias(), path, strokeInfo);
robertphillipsea461502015-05-26 11:38:03 -0700666}
667
668void GrDrawContext::internalDrawPath(GrDrawTarget* target,
669 GrPipelineBuilder* pipelineBuilder,
670 const SkMatrix& viewMatrix,
671 GrColor color,
672 bool useAA,
673 const SkPath& path,
674 const GrStrokeInfo& strokeInfo) {
675 RETURN_IF_ABANDONED
676 SkASSERT(!path.isEmpty());
677
robertphillipsea461502015-05-26 11:38:03 -0700678 // An Assumption here is that path renderer would use some form of tweaking
679 // the src color (either the input alpha or in the frag shader) to implement
680 // aa. If we have some future driver-mojo path AA that can do the right
681 // thing WRT to the blend then we'll need some query on the PR.
682 bool useCoverageAA = useAA &&
vbuzinovdded6962015-06-12 08:59:45 -0700683 !pipelineBuilder->getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -0700684
685
686 GrPathRendererChain::DrawType type =
687 useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType :
688 GrPathRendererChain::kColor_DrawType;
689
690 const SkPath* pathPtr = &path;
691 SkTLazy<SkPath> tmpPath;
692 const GrStrokeInfo* strokeInfoPtr = &strokeInfo;
693
694 // Try a 1st time without stroking the path and without allowing the SW renderer
robertphillips77a2e522015-10-17 07:43:27 -0700695 GrPathRenderer* pr = fDrawingManager->getContext()->getPathRenderer(target, pipelineBuilder,
696 viewMatrix, *pathPtr,
697 *strokeInfoPtr, false,
698 type);
robertphillipsea461502015-05-26 11:38:03 -0700699
700 GrStrokeInfo dashlessStrokeInfo(strokeInfo, false);
halcanary96fcdcc2015-08-27 07:41:13 -0700701 if (nullptr == pr && strokeInfo.isDashed()) {
robertphillipsea461502015-05-26 11:38:03 -0700702 // It didn't work above, so try again with dashed stroke converted to a dashless stroke.
703 if (!strokeInfo.applyDashToPath(tmpPath.init(), &dashlessStrokeInfo, *pathPtr)) {
704 return;
705 }
706 pathPtr = tmpPath.get();
707 if (pathPtr->isEmpty()) {
708 return;
709 }
710 strokeInfoPtr = &dashlessStrokeInfo;
robertphillips77a2e522015-10-17 07:43:27 -0700711 pr = fDrawingManager->getContext()->getPathRenderer(target, pipelineBuilder, viewMatrix,
712 *pathPtr, *strokeInfoPtr,
713 false, type);
robertphillipsea461502015-05-26 11:38:03 -0700714 }
715
halcanary96fcdcc2015-08-27 07:41:13 -0700716 if (nullptr == pr) {
717 if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*strokeInfoPtr, viewMatrix, nullptr) &&
robertphillipsea461502015-05-26 11:38:03 -0700718 !strokeInfoPtr->isFillStyle()) {
719 // It didn't work above, so try again with stroke converted to a fill.
720 if (!tmpPath.isValid()) {
721 tmpPath.init();
722 }
723 dashlessStrokeInfo.setResScale(SkScalarAbs(viewMatrix.getMaxScale()));
724 if (!dashlessStrokeInfo.applyToPath(tmpPath.get(), *pathPtr)) {
725 return;
726 }
727 pathPtr = tmpPath.get();
728 if (pathPtr->isEmpty()) {
729 return;
730 }
731 dashlessStrokeInfo.setFillStyle();
732 strokeInfoPtr = &dashlessStrokeInfo;
733 }
734
735 // This time, allow SW renderer
robertphillips77a2e522015-10-17 07:43:27 -0700736 pr = fDrawingManager->getContext()->getPathRenderer(target, pipelineBuilder, viewMatrix,
737 *pathPtr, *strokeInfoPtr,
738 true, type);
robertphillipsea461502015-05-26 11:38:03 -0700739 }
740
halcanary96fcdcc2015-08-27 07:41:13 -0700741 if (nullptr == pr) {
robertphillipsea461502015-05-26 11:38:03 -0700742#ifdef SK_DEBUG
743 SkDebugf("Unable to find path renderer compatible with path.\n");
744#endif
745 return;
746 }
747
bsalomon0aff2fa2015-07-31 06:48:27 -0700748 GrPathRenderer::DrawPathArgs args;
749 args.fTarget = target;
robertphillips77a2e522015-10-17 07:43:27 -0700750 args.fResourceProvider = fDrawingManager->getContext()->resourceProvider();
bsalomon0aff2fa2015-07-31 06:48:27 -0700751 args.fPipelineBuilder = pipelineBuilder;
752 args.fColor = color;
753 args.fViewMatrix = &viewMatrix;
754 args.fPath = pathPtr;
755 args.fStroke = strokeInfoPtr;
756 args.fAntiAlias = useCoverageAA;
757 pr->drawPath(args);
robertphillipsea461502015-05-26 11:38:03 -0700758}
759
bsalomonabd30f52015-08-13 13:34:48 -0700760void GrDrawContext::drawBatch(GrPipelineBuilder* pipelineBuilder, GrDrawBatch* batch) {
robertphillips2d70dcb2015-10-06 07:38:23 -0700761 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700762 SkDEBUGCODE(this->validate();)
robertphillips2d70dcb2015-10-06 07:38:23 -0700763
robertphillipsa106c622015-10-16 09:07:06 -0700764 this->getDrawTarget()->drawBatch(*pipelineBuilder, batch);
robertphillips2334fb62015-06-17 05:43:33 -0700765}