blob: 5e950dc15215525db664a436994a48b79ba77a70 [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
9#include "GrAARectRenderer.h"
robertphillips2334fb62015-06-17 05:43:33 -070010#include "GrAtlasTextContext.h"
robertphillipsea461502015-05-26 11:38:03 -070011#include "GrBatch.h"
12#include "GrBatchTest.h"
13#include "GrDefaultGeoProcFactory.h"
14#include "GrDrawContext.h"
15#include "GrOvalRenderer.h"
16#include "GrPathRenderer.h"
robertphillips2334fb62015-06-17 05:43:33 -070017#include "GrRenderTarget.h"
18#include "GrRenderTargetPriv.h"
19#include "GrStencilAndCoverTextContext.h"
robertphillipsea461502015-05-26 11:38:03 -070020
21#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == fContext)
22#define RETURN_IF_ABANDONED if (!fDrawTarget) { return; }
23#define RETURN_FALSE_IF_ABANDONED if (!fDrawTarget) { return false; }
24#define RETURN_NULL_IF_ABANDONED if (!fDrawTarget) { return NULL; }
25
26class AutoCheckFlush {
27public:
28 AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context); }
29 ~AutoCheckFlush() { fContext->flushIfNecessary(); }
30
31private:
32 GrContext* fContext;
33};
34
robertphillips2334fb62015-06-17 05:43:33 -070035GrDrawContext::GrDrawContext(GrContext* context,
36 GrDrawTarget* drawTarget,
robertphillipsfcf78292015-06-19 11:49:52 -070037 const SkSurfaceProps& surfaceProps)
robertphillipsea461502015-05-26 11:38:03 -070038 : fContext(context)
robertphillips2334fb62015-06-17 05:43:33 -070039 , fDrawTarget(SkRef(drawTarget))
40 , fTextContext(NULL)
robertphillipsfcf78292015-06-19 11:49:52 -070041 , fSurfaceProps(surfaceProps) {
robertphillipsea461502015-05-26 11:38:03 -070042}
43
robertphillips4b195e52015-05-26 14:37:00 -070044GrDrawContext::~GrDrawContext() {
45 SkSafeUnref(fDrawTarget);
robertphillips2334fb62015-06-17 05:43:33 -070046 SkDELETE(fTextContext);
robertphillips4b195e52015-05-26 14:37:00 -070047}
48
robertphillipsea461502015-05-26 11:38:03 -070049void GrDrawContext::copySurface(GrRenderTarget* dst, GrSurface* src,
50 const SkIRect& srcRect, const SkIPoint& dstPoint) {
51 if (!this->prepareToDraw(dst)) {
52 return;
53 }
54
55 fDrawTarget->copySurface(dst, src, srcRect, dstPoint);
56}
57
robertphillips2334fb62015-06-17 05:43:33 -070058GrTextContext* GrDrawContext::createTextContext(GrRenderTarget* renderTarget,
robertphillipsfcf78292015-06-19 11:49:52 -070059 const SkSurfaceProps& surfaceProps) {
robertphillips2334fb62015-06-17 05:43:33 -070060 if (fContext->caps()->shaderCaps()->pathRenderingSupport() &&
cdaltone04edd82015-06-29 14:15:19 -070061 renderTarget->isStencilBufferMultisampled() &&
62 fSurfaceProps.isUseDistanceFieldFonts()) { // FIXME: Rename the dff flag to be more general.
robertphillips2334fb62015-06-17 05:43:33 -070063 GrStencilAttachment* sb = renderTarget->renderTargetPriv().attachStencilAttachment();
64 if (sb) {
robertphillipsfcf78292015-06-19 11:49:52 -070065 return GrStencilAndCoverTextContext::Create(fContext, this, surfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -070066 }
67 }
68
robertphillipsfcf78292015-06-19 11:49:52 -070069 return GrAtlasTextContext::Create(fContext, this, surfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -070070}
71
72void GrDrawContext::drawText(GrRenderTarget* rt, const GrClip& clip, const GrPaint& grPaint,
73 const SkPaint& skPaint,
74 const SkMatrix& viewMatrix,
75 const char text[], size_t byteLength,
76 SkScalar x, SkScalar y, const SkIRect& clipBounds) {
77 if (!fTextContext) {
robertphillipsfcf78292015-06-19 11:49:52 -070078 fTextContext = this->createTextContext(rt, fSurfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -070079 }
80
81 fTextContext->drawText(rt, clip, grPaint, skPaint, viewMatrix,
82 text, byteLength, x, y, clipBounds);
83
84}
85void GrDrawContext::drawPosText(GrRenderTarget* rt, const GrClip& clip, const GrPaint& grPaint,
86 const SkPaint& skPaint,
87 const SkMatrix& viewMatrix,
88 const char text[], size_t byteLength,
89 const SkScalar pos[], int scalarsPerPosition,
90 const SkPoint& offset, const SkIRect& clipBounds) {
91 if (!fTextContext) {
robertphillipsfcf78292015-06-19 11:49:52 -070092 fTextContext = this->createTextContext(rt, fSurfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -070093 }
94
95 fTextContext->drawPosText(rt, clip, grPaint, skPaint, viewMatrix, text, byteLength,
96 pos, scalarsPerPosition, offset, clipBounds);
97
98}
99void GrDrawContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, const SkPaint& skPaint,
100 const SkMatrix& viewMatrix, const SkTextBlob* blob,
101 SkScalar x, SkScalar y,
102 SkDrawFilter* filter, const SkIRect& clipBounds) {
103 if (!fTextContext) {
robertphillipsfcf78292015-06-19 11:49:52 -0700104 fTextContext = this->createTextContext(rt, fSurfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -0700105 }
106
107 fTextContext->drawTextBlob(rt, clip, skPaint, viewMatrix, blob, x, y, filter, clipBounds);
robertphillipsea461502015-05-26 11:38:03 -0700108}
109
110void GrDrawContext::drawPaths(GrPipelineBuilder* pipelineBuilder,
111 const GrPathProcessor* pathProc,
112 const GrPathRange* pathRange,
113 const void* indices,
114 int /*GrDrawTarget::PathIndexType*/ indexType,
115 const float transformValues[],
116 int /*GrDrawTarget::PathTransformType*/ transformType,
117 int count,
118 int /*GrPathRendering::FillType*/ fill) {
119 fDrawTarget->drawPaths(pipelineBuilder, pathProc, pathRange,
120 indices, (GrDrawTarget::PathIndexType) indexType,
121 transformValues,
122 (GrDrawTarget::PathTransformType) transformType,
123 count, (GrPathRendering::FillType) fill);
124}
125
126void GrDrawContext::discard(GrRenderTarget* renderTarget) {
127 RETURN_IF_ABANDONED
128 SkASSERT(renderTarget);
129 AutoCheckFlush acf(fContext);
130 if (!this->prepareToDraw(renderTarget)) {
131 return;
132 }
133 fDrawTarget->discard(renderTarget);
134}
135
136void GrDrawContext::clear(GrRenderTarget* renderTarget,
137 const SkIRect* rect,
138 const GrColor color,
139 bool canIgnoreRect) {
140 RETURN_IF_ABANDONED
141 SkASSERT(renderTarget);
142
143 AutoCheckFlush acf(fContext);
144 if (!this->prepareToDraw(renderTarget)) {
145 return;
146 }
147 fDrawTarget->clear(rect, color, canIgnoreRect, renderTarget);
148}
149
150
151void GrDrawContext::drawPaint(GrRenderTarget* rt,
152 const GrClip& clip,
153 const GrPaint& origPaint,
154 const SkMatrix& viewMatrix) {
155 RETURN_IF_ABANDONED
156 // set rect to be big enough to fill the space, but not super-huge, so we
157 // don't overflow fixed-point implementations
158 SkRect r;
159 r.setLTRB(0, 0,
160 SkIntToScalar(rt->width()),
161 SkIntToScalar(rt->height()));
162 SkTCopyOnFirstWrite<GrPaint> paint(origPaint);
163
164 // by definition this fills the entire clip, no need for AA
165 if (paint->isAntiAlias()) {
166 paint.writable()->setAntiAlias(false);
167 }
168
169 bool isPerspective = viewMatrix.hasPerspective();
170
171 // We attempt to map r by the inverse matrix and draw that. mapRect will
172 // map the four corners and bound them with a new rect. This will not
173 // produce a correct result for some perspective matrices.
174 if (!isPerspective) {
175 SkMatrix inverse;
176 if (!viewMatrix.invert(&inverse)) {
177 SkDebugf("Could not invert matrix\n");
178 return;
179 }
180 inverse.mapRect(&r);
181 this->drawRect(rt, clip, *paint, viewMatrix, r);
182 } else {
183 SkMatrix localMatrix;
184 if (!viewMatrix.invert(&localMatrix)) {
185 SkDebugf("Could not invert matrix\n");
186 return;
187 }
188
189 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700190 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700191 return;
192 }
193
joshualitt7b670db2015-07-09 13:25:02 -0700194 GrPipelineBuilder pipelineBuilder(*paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700195 fDrawTarget->drawBWRect(&pipelineBuilder,
196 paint->getColor(),
197 SkMatrix::I(),
198 r,
199 NULL,
200 &localMatrix);
201 }
202}
203
204static inline bool is_irect(const SkRect& r) {
205 return SkScalarIsInt(r.fLeft) && SkScalarIsInt(r.fTop) &&
206 SkScalarIsInt(r.fRight) && SkScalarIsInt(r.fBottom);
207}
208
209static bool apply_aa_to_rect(GrDrawTarget* target,
210 GrPipelineBuilder* pipelineBuilder,
211 SkRect* devBoundRect,
212 const SkRect& rect,
213 SkScalar strokeWidth,
214 const SkMatrix& combinedMatrix,
215 GrColor color) {
vbuzinovdded6962015-06-12 08:59:45 -0700216 if (pipelineBuilder->getRenderTarget()->isUnifiedMultisampled()) {
robertphillipsea461502015-05-26 11:38:03 -0700217 return false;
218 }
219
220#if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
221 if (strokeWidth >= 0) {
222#endif
223 if (!combinedMatrix.preservesAxisAlignment()) {
224 return false;
225 }
226
227#if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
228 } else {
229 if (!combinedMatrix.preservesRightAngles()) {
230 return false;
231 }
232 }
233#endif
234
235 combinedMatrix.mapRect(devBoundRect, rect);
236 if (!combinedMatrix.rectStaysRect()) {
237 return true;
238 }
239
240 if (strokeWidth < 0) {
241 return !is_irect(*devBoundRect);
242 }
243
244 return true;
245}
246
247static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) {
248 return point.fX >= rect.fLeft && point.fX <= rect.fRight &&
249 point.fY >= rect.fTop && point.fY <= rect.fBottom;
250}
251
252class StrokeRectBatch : public GrBatch {
253public:
254 struct Geometry {
255 GrColor fColor;
256 SkMatrix fViewMatrix;
257 SkRect fRect;
258 SkScalar fStrokeWidth;
259 };
260
261 static GrBatch* Create(const Geometry& geometry, bool snapToPixelCenters) {
262 return SkNEW_ARGS(StrokeRectBatch, (geometry, snapToPixelCenters));
263 }
264
265 const char* name() const override { return "StrokeRectBatch"; }
266
267 void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
268 // When this is called on a batch, there is only one geometry bundle
269 out->setKnownFourComponents(fGeoData[0].fColor);
270 }
271
272 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
273 out->setKnownSingleComponent(0xff);
274 }
275
276 void initBatchTracker(const GrPipelineInfo& init) override {
277 // Handle any color overrides
bsalomon7765a472015-07-08 11:26:37 -0700278 if (!init.readsColor()) {
robertphillipsea461502015-05-26 11:38:03 -0700279 fGeoData[0].fColor = GrColor_ILLEGAL;
robertphillipsea461502015-05-26 11:38:03 -0700280 }
bsalomon7765a472015-07-08 11:26:37 -0700281 init.getOverrideColorIfSet(&fGeoData[0].fColor);
robertphillipsea461502015-05-26 11:38:03 -0700282
283 // setup batch properties
bsalomon7765a472015-07-08 11:26:37 -0700284 fBatch.fColorIgnored = !init.readsColor();
robertphillipsea461502015-05-26 11:38:03 -0700285 fBatch.fColor = fGeoData[0].fColor;
bsalomon7765a472015-07-08 11:26:37 -0700286 fBatch.fUsesLocalCoords = init.readsLocalCoords();
287 fBatch.fCoverageIgnored = !init.readsCoverage();
robertphillipsea461502015-05-26 11:38:03 -0700288 }
289
290 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override {
291 SkAutoTUnref<const GrGeometryProcessor> gp(
292 GrDefaultGeoProcFactory::Create(GrDefaultGeoProcFactory::kPosition_GPType,
293 this->color(),
294 this->usesLocalCoords(),
295 this->coverageIgnored(),
296 this->viewMatrix(),
297 SkMatrix::I()));
298
299 batchTarget->initDraw(gp, pipeline);
300
301 size_t vertexStride = gp->getVertexStride();
302
303 SkASSERT(vertexStride == sizeof(GrDefaultGeoProcFactory::PositionAttr));
304
305 Geometry& args = fGeoData[0];
306
307 int vertexCount = kVertsPerHairlineRect;
308 if (args.fStrokeWidth > 0) {
309 vertexCount = kVertsPerStrokeRect;
310 }
311
312 const GrVertexBuffer* vertexBuffer;
313 int firstVertex;
314
315 void* verts = batchTarget->makeVertSpace(vertexStride, vertexCount,
316 &vertexBuffer, &firstVertex);
317
318 if (!verts) {
319 SkDebugf("Could not allocate vertices\n");
320 return;
321 }
322
323 SkPoint* vertex = reinterpret_cast<SkPoint*>(verts);
324
325 GrPrimitiveType primType;
326
327 if (args.fStrokeWidth > 0) {;
328 primType = kTriangleStrip_GrPrimitiveType;
329 args.fRect.sort();
330 this->setStrokeRectStrip(vertex, args.fRect, args.fStrokeWidth);
331 } else {
332 // hairline
333 primType = kLineStrip_GrPrimitiveType;
334 vertex[0].set(args.fRect.fLeft, args.fRect.fTop);
335 vertex[1].set(args.fRect.fRight, args.fRect.fTop);
336 vertex[2].set(args.fRect.fRight, args.fRect.fBottom);
337 vertex[3].set(args.fRect.fLeft, args.fRect.fBottom);
338 vertex[4].set(args.fRect.fLeft, args.fRect.fTop);
339 }
340
341 GrVertices vertices;
342 vertices.init(primType, vertexBuffer, firstVertex, vertexCount);
343 batchTarget->draw(vertices);
344 }
345
346 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
347
348private:
349 StrokeRectBatch(const Geometry& geometry, bool snapToPixelCenters) {
350 this->initClassID<StrokeRectBatch>();
351
352 fBatch.fHairline = geometry.fStrokeWidth == 0;
353
354 fGeoData.push_back(geometry);
355
356 // setup bounds
357 fBounds = geometry.fRect;
358 SkScalar rad = SkScalarHalf(geometry.fStrokeWidth);
359 fBounds.outset(rad, rad);
360 geometry.fViewMatrix.mapRect(&fBounds);
361
362 // If our caller snaps to pixel centers then we have to round out the bounds
363 if (snapToPixelCenters) {
364 fBounds.roundOut();
365 }
366 }
367
368 /* create a triangle strip that strokes the specified rect. There are 8
369 unique vertices, but we repeat the last 2 to close up. Alternatively we
370 could use an indices array, and then only send 8 verts, but not sure that
371 would be faster.
372 */
373 void setStrokeRectStrip(SkPoint verts[10], const SkRect& rect, SkScalar width) {
374 const SkScalar rad = SkScalarHalf(width);
375 // TODO we should be able to enable this assert, but we'd have to filter these draws
376 // this is a bug
377 //SkASSERT(rad < rect.width() / 2 && rad < rect.height() / 2);
378
379 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
380 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
381 verts[2].set(rect.fRight - rad, rect.fTop + rad);
382 verts[3].set(rect.fRight + rad, rect.fTop - rad);
383 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
384 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
385 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
386 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
387 verts[8] = verts[0];
388 verts[9] = verts[1];
389 }
390
391
392 GrColor color() const { return fBatch.fColor; }
393 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
394 bool colorIgnored() const { return fBatch.fColorIgnored; }
395 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
396 bool hairline() const { return fBatch.fHairline; }
397 bool coverageIgnored() const { return fBatch.fCoverageIgnored; }
398
399 bool onCombineIfPossible(GrBatch* t) override {
400 // StrokeRectBatch* that = t->cast<StrokeRectBatch>();
401
402 // NonAA stroke rects cannot batch right now
403 // TODO make these batchable
404 return false;
405 }
406
407 struct BatchTracker {
408 GrColor fColor;
409 bool fUsesLocalCoords;
410 bool fColorIgnored;
411 bool fCoverageIgnored;
412 bool fHairline;
413 };
414
415 const static int kVertsPerHairlineRect = 5;
416 const static int kVertsPerStrokeRect = 10;
417
418 BatchTracker fBatch;
419 SkSTArray<1, Geometry, true> fGeoData;
420};
421
422void GrDrawContext::drawRect(GrRenderTarget* rt,
423 const GrClip& clip,
424 const GrPaint& paint,
425 const SkMatrix& viewMatrix,
426 const SkRect& rect,
427 const GrStrokeInfo* strokeInfo) {
428 RETURN_IF_ABANDONED
429 if (strokeInfo && strokeInfo->isDashed()) {
430 SkPath path;
431 path.setIsVolatile(true);
432 path.addRect(rect);
433 this->drawPath(rt, clip, paint, viewMatrix, path, *strokeInfo);
434 return;
435 }
436
437 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700438 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700439 return;
440 }
441
joshualitt7b670db2015-07-09 13:25:02 -0700442 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
443
robertphillipsea461502015-05-26 11:38:03 -0700444 SkScalar width = NULL == strokeInfo ? -1 : strokeInfo->getWidth();
445
446 // Check if this is a full RT draw and can be replaced with a clear. We don't bother checking
447 // cases where the RT is fully inside a stroke.
448 if (width < 0) {
449 SkRect rtRect;
450 pipelineBuilder.getRenderTarget()->getBoundsRect(&rtRect);
451 SkRect clipSpaceRTRect = rtRect;
452 bool checkClip = GrClip::kWideOpen_ClipType != clip.clipType();
453 if (checkClip) {
454 clipSpaceRTRect.offset(SkIntToScalar(clip.origin().fX),
455 SkIntToScalar(clip.origin().fY));
456 }
457 // Does the clip contain the entire RT?
458 if (!checkClip || clip.quickContains(clipSpaceRTRect)) {
459 SkMatrix invM;
460 if (!viewMatrix.invert(&invM)) {
461 return;
462 }
463 // Does the rect bound the RT?
464 SkPoint srcSpaceRTQuad[4];
465 invM.mapRectToQuad(srcSpaceRTQuad, rtRect);
466 if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) &&
467 rect_contains_inclusive(rect, srcSpaceRTQuad[1]) &&
468 rect_contains_inclusive(rect, srcSpaceRTQuad[2]) &&
469 rect_contains_inclusive(rect, srcSpaceRTQuad[3])) {
470 // Will it blend?
471 GrColor clearColor;
cdalton1fa45722015-06-02 10:43:39 -0700472 if (paint.isConstantBlendedColor(&clearColor)) {
robertphillipsea461502015-05-26 11:38:03 -0700473 fDrawTarget->clear(NULL, clearColor, true, rt);
474 return;
475 }
476 }
477 }
478 }
479
480 GrColor color = paint.getColor();
481 SkRect devBoundRect;
vbuzinovdded6962015-06-12 08:59:45 -0700482 bool needAA = paint.isAntiAlias() &&
483 !pipelineBuilder.getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -0700484 bool doAA = needAA && apply_aa_to_rect(fDrawTarget, &pipelineBuilder, &devBoundRect, rect,
485 width, viewMatrix, color);
486
487 if (doAA) {
488 if (width >= 0) {
489 GrAARectRenderer::StrokeAARect(fDrawTarget,
490 &pipelineBuilder,
491 color,
492 viewMatrix,
493 rect,
494 devBoundRect,
495 *strokeInfo);
496 } else {
497 // filled AA rect
498 GrAARectRenderer::FillAARect(fDrawTarget,
499 &pipelineBuilder,
500 color,
501 viewMatrix,
502 rect,
503 devBoundRect);
504 }
505 return;
506 }
507
508 if (width >= 0) {
509 StrokeRectBatch::Geometry geometry;
510 geometry.fViewMatrix = viewMatrix;
511 geometry.fColor = color;
512 geometry.fRect = rect;
513 geometry.fStrokeWidth = width;
514
515 // Non-AA hairlines are snapped to pixel centers to make which pixels are hit deterministic
vbuzinovdded6962015-06-12 08:59:45 -0700516 bool snapToPixelCenters = (0 == width && !rt->isUnifiedMultisampled());
robertphillipsea461502015-05-26 11:38:03 -0700517 SkAutoTUnref<GrBatch> batch(StrokeRectBatch::Create(geometry, snapToPixelCenters));
518
519 // Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of
520 // hairline rects. We jam all the vertices to pixel centers to avoid this, but not when MSAA
521 // is enabled because it can cause ugly artifacts.
522 pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_Flag,
523 snapToPixelCenters);
524 fDrawTarget->drawBatch(&pipelineBuilder, batch);
525 } else {
526 // filled BW rect
527 fDrawTarget->drawSimpleRect(&pipelineBuilder, color, viewMatrix, rect);
528 }
529}
530
531void GrDrawContext::drawNonAARectToRect(GrRenderTarget* rt,
532 const GrClip& clip,
533 const GrPaint& paint,
534 const SkMatrix& viewMatrix,
535 const SkRect& rectToDraw,
536 const SkRect& localRect,
537 const SkMatrix* localMatrix) {
538 RETURN_IF_ABANDONED
539 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700540 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700541 return;
542 }
543
joshualitt7b670db2015-07-09 13:25:02 -0700544 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700545 fDrawTarget->drawBWRect(&pipelineBuilder,
546 paint.getColor(),
547 viewMatrix,
548 rectToDraw,
549 &localRect,
550 localMatrix);
551}
552
553static const GrGeometryProcessor* set_vertex_attributes(bool hasLocalCoords,
554 bool hasColors,
555 int* colorOffset,
556 int* texOffset,
557 GrColor color,
558 const SkMatrix& viewMatrix,
559 bool coverageIgnored) {
560 *texOffset = -1;
561 *colorOffset = -1;
562 uint32_t flags = GrDefaultGeoProcFactory::kPosition_GPType;
563 if (hasLocalCoords && hasColors) {
564 *colorOffset = sizeof(SkPoint);
565 *texOffset = sizeof(SkPoint) + sizeof(GrColor);
566 flags |= GrDefaultGeoProcFactory::kColor_GPType |
567 GrDefaultGeoProcFactory::kLocalCoord_GPType;
568 } else if (hasLocalCoords) {
569 *texOffset = sizeof(SkPoint);
570 flags |= GrDefaultGeoProcFactory::kLocalCoord_GPType;
571 } else if (hasColors) {
572 *colorOffset = sizeof(SkPoint);
573 flags |= GrDefaultGeoProcFactory::kColor_GPType;
574 }
575 return GrDefaultGeoProcFactory::Create(flags, color, hasLocalCoords, coverageIgnored,
576 viewMatrix, SkMatrix::I());
577}
578
579class DrawVerticesBatch : public GrBatch {
580public:
581 struct Geometry {
582 GrColor fColor;
583 SkTDArray<SkPoint> fPositions;
584 SkTDArray<uint16_t> fIndices;
585 SkTDArray<GrColor> fColors;
586 SkTDArray<SkPoint> fLocalCoords;
587 };
588
589 static GrBatch* Create(const Geometry& geometry, GrPrimitiveType primitiveType,
590 const SkMatrix& viewMatrix,
591 const SkPoint* positions, int vertexCount,
592 const uint16_t* indices, int indexCount,
593 const GrColor* colors, const SkPoint* localCoords,
594 const SkRect& bounds) {
595 return SkNEW_ARGS(DrawVerticesBatch, (geometry, primitiveType, viewMatrix, positions,
596 vertexCount, indices, indexCount, colors,
597 localCoords, bounds));
598 }
599
600 const char* name() const override { return "DrawVerticesBatch"; }
601
602 void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
603 // When this is called on a batch, there is only one geometry bundle
604 if (this->hasColors()) {
605 out->setUnknownFourComponents();
606 } else {
607 out->setKnownFourComponents(fGeoData[0].fColor);
608 }
609 }
610
611 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
612 out->setKnownSingleComponent(0xff);
613 }
614
615 void initBatchTracker(const GrPipelineInfo& init) override {
616 // Handle any color overrides
bsalomon7765a472015-07-08 11:26:37 -0700617 if (!init.readsColor()) {
robertphillipsea461502015-05-26 11:38:03 -0700618 fGeoData[0].fColor = GrColor_ILLEGAL;
robertphillipsea461502015-05-26 11:38:03 -0700619 }
bsalomon7765a472015-07-08 11:26:37 -0700620 init.getOverrideColorIfSet(&fGeoData[0].fColor);
robertphillipsea461502015-05-26 11:38:03 -0700621
622 // setup batch properties
bsalomon7765a472015-07-08 11:26:37 -0700623 fBatch.fColorIgnored = !init.readsColor();
robertphillipsea461502015-05-26 11:38:03 -0700624 fBatch.fColor = fGeoData[0].fColor;
bsalomon7765a472015-07-08 11:26:37 -0700625 fBatch.fUsesLocalCoords = init.readsLocalCoords();
626 fBatch.fCoverageIgnored = !init.readsCoverage();
robertphillipsea461502015-05-26 11:38:03 -0700627 }
628
629 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override {
630 int colorOffset = -1, texOffset = -1;
631 SkAutoTUnref<const GrGeometryProcessor> gp(
632 set_vertex_attributes(this->hasLocalCoords(), this->hasColors(), &colorOffset,
633 &texOffset, this->color(), this->viewMatrix(),
634 this->coverageIgnored()));
635
636 batchTarget->initDraw(gp, pipeline);
637
638 size_t vertexStride = gp->getVertexStride();
639
640 SkASSERT(vertexStride == sizeof(SkPoint) + (this->hasLocalCoords() ? sizeof(SkPoint) : 0)
641 + (this->hasColors() ? sizeof(GrColor) : 0));
642
643 int instanceCount = fGeoData.count();
644
645 const GrVertexBuffer* vertexBuffer;
646 int firstVertex;
647
648 void* verts = batchTarget->makeVertSpace(vertexStride, this->vertexCount(),
649 &vertexBuffer, &firstVertex);
650
651 if (!verts) {
652 SkDebugf("Could not allocate vertices\n");
653 return;
654 }
655
656 const GrIndexBuffer* indexBuffer = NULL;
657 int firstIndex = 0;
658
659 uint16_t* indices = NULL;
660 if (this->hasIndices()) {
661 indices = batchTarget->makeIndexSpace(this->indexCount(), &indexBuffer, &firstIndex);
662
663 if (!indices) {
664 SkDebugf("Could not allocate indices\n");
665 return;
666 }
667 }
668
669 int indexOffset = 0;
670 int vertexOffset = 0;
671 for (int i = 0; i < instanceCount; i++) {
672 const Geometry& args = fGeoData[i];
673
674 // TODO we can actually cache this interleaved and then just memcopy
675 if (this->hasIndices()) {
676 for (int j = 0; j < args.fIndices.count(); ++j, ++indexOffset) {
677 *(indices + indexOffset) = args.fIndices[j] + vertexOffset;
678 }
679 }
680
681 for (int j = 0; j < args.fPositions.count(); ++j) {
682 *((SkPoint*)verts) = args.fPositions[j];
683 if (this->hasColors()) {
684 *(GrColor*)((intptr_t)verts + colorOffset) = args.fColors[j];
685 }
686 if (this->hasLocalCoords()) {
687 *(SkPoint*)((intptr_t)verts + texOffset) = args.fLocalCoords[j];
688 }
689 verts = (void*)((intptr_t)verts + vertexStride);
690 vertexOffset++;
691 }
692 }
693
694 GrVertices vertices;
695 if (this->hasIndices()) {
696 vertices.initIndexed(this->primitiveType(), vertexBuffer, indexBuffer, firstVertex,
697 firstIndex, this->vertexCount(), this->indexCount());
698
699 } else {
700 vertices.init(this->primitiveType(), vertexBuffer, firstVertex, this->vertexCount());
701 }
702 batchTarget->draw(vertices);
703 }
704
705 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
706
707private:
708 DrawVerticesBatch(const Geometry& geometry, GrPrimitiveType primitiveType,
709 const SkMatrix& viewMatrix,
710 const SkPoint* positions, int vertexCount,
711 const uint16_t* indices, int indexCount,
712 const GrColor* colors, const SkPoint* localCoords, const SkRect& bounds) {
713 this->initClassID<DrawVerticesBatch>();
714 SkASSERT(positions);
715
716 fBatch.fViewMatrix = viewMatrix;
717 Geometry& installedGeo = fGeoData.push_back(geometry);
718
719 installedGeo.fPositions.append(vertexCount, positions);
720 if (indices) {
721 installedGeo.fIndices.append(indexCount, indices);
722 fBatch.fHasIndices = true;
723 } else {
724 fBatch.fHasIndices = false;
725 }
726
727 if (colors) {
728 installedGeo.fColors.append(vertexCount, colors);
729 fBatch.fHasColors = true;
730 } else {
731 fBatch.fHasColors = false;
732 }
733
734 if (localCoords) {
735 installedGeo.fLocalCoords.append(vertexCount, localCoords);
736 fBatch.fHasLocalCoords = true;
737 } else {
738 fBatch.fHasLocalCoords = false;
739 }
740 fBatch.fVertexCount = vertexCount;
741 fBatch.fIndexCount = indexCount;
742 fBatch.fPrimitiveType = primitiveType;
743
744 this->setBounds(bounds);
745 }
746
747 GrPrimitiveType primitiveType() const { return fBatch.fPrimitiveType; }
748 bool batchablePrimitiveType() const {
749 return kTriangles_GrPrimitiveType == fBatch.fPrimitiveType ||
750 kLines_GrPrimitiveType == fBatch.fPrimitiveType ||
751 kPoints_GrPrimitiveType == fBatch.fPrimitiveType;
752 }
753 GrColor color() const { return fBatch.fColor; }
754 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
755 bool colorIgnored() const { return fBatch.fColorIgnored; }
756 const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
757 bool hasColors() const { return fBatch.fHasColors; }
758 bool hasIndices() const { return fBatch.fHasIndices; }
759 bool hasLocalCoords() const { return fBatch.fHasLocalCoords; }
760 int vertexCount() const { return fBatch.fVertexCount; }
761 int indexCount() const { return fBatch.fIndexCount; }
762 bool coverageIgnored() const { return fBatch.fCoverageIgnored; }
763
764 bool onCombineIfPossible(GrBatch* t) override {
765 DrawVerticesBatch* that = t->cast<DrawVerticesBatch>();
766
767 if (!this->batchablePrimitiveType() || this->primitiveType() != that->primitiveType()) {
768 return false;
769 }
770
771 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
772
773 // We currently use a uniform viewmatrix for this batch
774 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
775 return false;
776 }
777
778 if (this->hasColors() != that->hasColors()) {
779 return false;
780 }
781
782 if (this->hasIndices() != that->hasIndices()) {
783 return false;
784 }
785
786 if (this->hasLocalCoords() != that->hasLocalCoords()) {
787 return false;
788 }
789
790 if (!this->hasColors() && this->color() != that->color()) {
791 return false;
792 }
793
794 if (this->color() != that->color()) {
795 fBatch.fColor = GrColor_ILLEGAL;
796 }
797 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
798 fBatch.fVertexCount += that->vertexCount();
799 fBatch.fIndexCount += that->indexCount();
800
801 this->joinBounds(that->bounds());
802 return true;
803 }
804
805 struct BatchTracker {
806 GrPrimitiveType fPrimitiveType;
807 SkMatrix fViewMatrix;
808 GrColor fColor;
809 bool fUsesLocalCoords;
810 bool fColorIgnored;
811 bool fCoverageIgnored;
812 bool fHasColors;
813 bool fHasIndices;
814 bool fHasLocalCoords;
815 int fVertexCount;
816 int fIndexCount;
817 };
818
819 BatchTracker fBatch;
820 SkSTArray<1, Geometry, true> fGeoData;
821};
822
823void GrDrawContext::drawVertices(GrRenderTarget* rt,
824 const GrClip& clip,
825 const GrPaint& paint,
826 const SkMatrix& viewMatrix,
827 GrPrimitiveType primitiveType,
828 int vertexCount,
829 const SkPoint positions[],
830 const SkPoint texCoords[],
831 const GrColor colors[],
832 const uint16_t indices[],
833 int indexCount) {
834 RETURN_IF_ABANDONED
835 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700836 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700837 return;
838 }
839
joshualitt7b670db2015-07-09 13:25:02 -0700840 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
841
robertphillipsea461502015-05-26 11:38:03 -0700842 // TODO clients should give us bounds
843 SkRect bounds;
844 if (!bounds.setBoundsCheck(positions, vertexCount)) {
845 SkDebugf("drawVertices call empty bounds\n");
846 return;
847 }
848
849 viewMatrix.mapRect(&bounds);
850
851 // If we don't have AA then we outset for a half pixel in each direction to account for
852 // snapping
853 if (!paint.isAntiAlias()) {
854 bounds.outset(0.5f, 0.5f);
855 }
856
857 DrawVerticesBatch::Geometry geometry;
858 geometry.fColor = paint.getColor();
859 SkAutoTUnref<GrBatch> batch(DrawVerticesBatch::Create(geometry, primitiveType, viewMatrix,
860 positions, vertexCount, indices,
861 indexCount, colors, texCoords,
862 bounds));
863
864 fDrawTarget->drawBatch(&pipelineBuilder, batch);
865}
866
867///////////////////////////////////////////////////////////////////////////////
868
869void GrDrawContext::drawRRect(GrRenderTarget*rt,
870 const GrClip& clip,
871 const GrPaint& paint,
872 const SkMatrix& viewMatrix,
873 const SkRRect& rrect,
874 const GrStrokeInfo& strokeInfo) {
875 RETURN_IF_ABANDONED
876 if (rrect.isEmpty()) {
877 return;
878 }
879
880 if (strokeInfo.isDashed()) {
881 SkPath path;
882 path.setIsVolatile(true);
883 path.addRRect(rrect);
884 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
885 return;
886 }
887
888 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700889 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700890 return;
891 }
892
joshualitt7b670db2015-07-09 13:25:02 -0700893 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700894 GrColor color = paint.getColor();
895 if (!GrOvalRenderer::DrawRRect(fDrawTarget,
896 &pipelineBuilder,
897 color,
898 viewMatrix,
899 paint.isAntiAlias(),
900 rrect,
901 strokeInfo)) {
902 SkPath path;
903 path.setIsVolatile(true);
904 path.addRRect(rrect);
905 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
906 paint.isAntiAlias(), path, strokeInfo);
907 }
908}
909
910///////////////////////////////////////////////////////////////////////////////
911
912void GrDrawContext::drawDRRect(GrRenderTarget* rt,
913 const GrClip& clip,
914 const GrPaint& paint,
915 const SkMatrix& viewMatrix,
916 const SkRRect& outer,
917 const SkRRect& inner) {
918 RETURN_IF_ABANDONED
919 if (outer.isEmpty()) {
920 return;
921 }
922
923 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700924 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700925 return;
926 }
927
joshualitt7b670db2015-07-09 13:25:02 -0700928 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700929 GrColor color = paint.getColor();
930 if (!GrOvalRenderer::DrawDRRect(fDrawTarget,
931 &pipelineBuilder,
932 color,
933 viewMatrix,
934 paint.isAntiAlias(),
935 outer,
936 inner)) {
937 SkPath path;
938 path.setIsVolatile(true);
939 path.addRRect(inner);
940 path.addRRect(outer);
941 path.setFillType(SkPath::kEvenOdd_FillType);
942
943 GrStrokeInfo fillRec(SkStrokeRec::kFill_InitStyle);
944 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
945 paint.isAntiAlias(), path, fillRec);
946 }
947}
948
949///////////////////////////////////////////////////////////////////////////////
950
951void GrDrawContext::drawOval(GrRenderTarget* rt,
952 const GrClip& clip,
953 const GrPaint& paint,
954 const SkMatrix& viewMatrix,
955 const SkRect& oval,
956 const GrStrokeInfo& strokeInfo) {
957 RETURN_IF_ABANDONED
958 if (oval.isEmpty()) {
959 return;
960 }
961
962 if (strokeInfo.isDashed()) {
963 SkPath path;
964 path.setIsVolatile(true);
965 path.addOval(oval);
966 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
967 return;
968 }
969
970 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700971 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700972 return;
973 }
974
joshualitt7b670db2015-07-09 13:25:02 -0700975 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700976 GrColor color = paint.getColor();
977 if (!GrOvalRenderer::DrawOval(fDrawTarget,
978 &pipelineBuilder,
979 color,
980 viewMatrix,
981 paint.isAntiAlias(),
982 oval,
983 strokeInfo)) {
984 SkPath path;
985 path.setIsVolatile(true);
986 path.addOval(oval);
987 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
988 paint.isAntiAlias(), path, strokeInfo);
989 }
990}
991
992// Can 'path' be drawn as a pair of filled nested rectangles?
993static bool is_nested_rects(GrDrawTarget* target,
994 GrPipelineBuilder* pipelineBuilder,
995 GrColor color,
996 const SkMatrix& viewMatrix,
997 const SkPath& path,
998 const SkStrokeRec& stroke,
999 SkRect rects[2]) {
1000 SkASSERT(stroke.isFillStyle());
1001
1002 if (path.isInverseFillType()) {
1003 return false;
1004 }
1005
1006 // TODO: this restriction could be lifted if we were willing to apply
1007 // the matrix to all the points individually rather than just to the rect
1008 if (!viewMatrix.preservesAxisAlignment()) {
1009 return false;
1010 }
1011
1012 SkPath::Direction dirs[2];
1013 if (!path.isNestedFillRects(rects, dirs)) {
1014 return false;
1015 }
1016
1017 if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) {
1018 // The two rects need to be wound opposite to each other
1019 return false;
1020 }
1021
1022 // Right now, nested rects where the margin is not the same width
1023 // all around do not render correctly
1024 const SkScalar* outer = rects[0].asScalars();
1025 const SkScalar* inner = rects[1].asScalars();
1026
1027 bool allEq = true;
1028
1029 SkScalar margin = SkScalarAbs(outer[0] - inner[0]);
1030 bool allGoE1 = margin >= SK_Scalar1;
1031
1032 for (int i = 1; i < 4; ++i) {
1033 SkScalar temp = SkScalarAbs(outer[i] - inner[i]);
1034 if (temp < SK_Scalar1) {
1035 allGoE1 = false;
1036 }
1037 if (!SkScalarNearlyEqual(margin, temp)) {
1038 allEq = false;
1039 }
1040 }
1041
1042 return allEq || allGoE1;
1043}
1044
1045void GrDrawContext::drawPath(GrRenderTarget* rt,
1046 const GrClip& clip,
1047 const GrPaint& paint,
1048 const SkMatrix& viewMatrix,
1049 const SkPath& path,
1050 const GrStrokeInfo& strokeInfo) {
1051 RETURN_IF_ABANDONED
1052 if (path.isEmpty()) {
1053 if (path.isInverseFillType()) {
1054 this->drawPaint(rt, clip, paint, viewMatrix);
1055 }
1056 return;
1057 }
1058
1059 GrColor color = paint.getColor();
1060
1061 // Note that internalDrawPath may sw-rasterize the path into a scratch texture.
1062 // Scratch textures can be recycled after they are returned to the texture
1063 // cache. This presents a potential hazard for buffered drawing. However,
1064 // the writePixels that uploads to the scratch will perform a flush so we're
1065 // OK.
1066 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -07001067 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -07001068 return;
1069 }
1070
joshualitt7b670db2015-07-09 13:25:02 -07001071 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -07001072 if (!strokeInfo.isDashed()) {
1073 bool useCoverageAA = paint.isAntiAlias() &&
vbuzinovdded6962015-06-12 08:59:45 -07001074 !pipelineBuilder.getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -07001075
1076 if (useCoverageAA && strokeInfo.getWidth() < 0 && !path.isConvex()) {
1077 // Concave AA paths are expensive - try to avoid them for special cases
1078 SkRect rects[2];
1079
1080 if (is_nested_rects(fDrawTarget, &pipelineBuilder, color, viewMatrix, path, strokeInfo,
1081 rects)) {
1082 GrAARectRenderer::FillAANestedRects(fDrawTarget, &pipelineBuilder, color,
1083 viewMatrix, rects);
1084 return;
1085 }
1086 }
1087 SkRect ovalRect;
1088 bool isOval = path.isOval(&ovalRect);
1089
1090 if (isOval && !path.isInverseFillType()) {
1091 if (GrOvalRenderer::DrawOval(fDrawTarget,
1092 &pipelineBuilder,
1093 color,
1094 viewMatrix,
1095 paint.isAntiAlias(),
1096 ovalRect,
1097 strokeInfo)) {
1098 return;
1099 }
1100 }
1101 }
1102 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
1103 path, strokeInfo);
1104}
1105
1106void GrDrawContext::internalDrawPath(GrDrawTarget* target,
1107 GrPipelineBuilder* pipelineBuilder,
1108 const SkMatrix& viewMatrix,
1109 GrColor color,
1110 bool useAA,
1111 const SkPath& path,
1112 const GrStrokeInfo& strokeInfo) {
1113 RETURN_IF_ABANDONED
1114 SkASSERT(!path.isEmpty());
1115
1116
1117 // An Assumption here is that path renderer would use some form of tweaking
1118 // the src color (either the input alpha or in the frag shader) to implement
1119 // aa. If we have some future driver-mojo path AA that can do the right
1120 // thing WRT to the blend then we'll need some query on the PR.
1121 bool useCoverageAA = useAA &&
vbuzinovdded6962015-06-12 08:59:45 -07001122 !pipelineBuilder->getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -07001123
1124
1125 GrPathRendererChain::DrawType type =
1126 useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType :
1127 GrPathRendererChain::kColor_DrawType;
1128
1129 const SkPath* pathPtr = &path;
1130 SkTLazy<SkPath> tmpPath;
1131 const GrStrokeInfo* strokeInfoPtr = &strokeInfo;
1132
1133 // Try a 1st time without stroking the path and without allowing the SW renderer
1134 GrPathRenderer* pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr,
1135 *strokeInfoPtr, false, type);
1136
1137 GrStrokeInfo dashlessStrokeInfo(strokeInfo, false);
1138 if (NULL == pr && strokeInfo.isDashed()) {
1139 // It didn't work above, so try again with dashed stroke converted to a dashless stroke.
1140 if (!strokeInfo.applyDashToPath(tmpPath.init(), &dashlessStrokeInfo, *pathPtr)) {
1141 return;
1142 }
1143 pathPtr = tmpPath.get();
1144 if (pathPtr->isEmpty()) {
1145 return;
1146 }
1147 strokeInfoPtr = &dashlessStrokeInfo;
1148 pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
1149 false, type);
1150 }
1151
1152 if (NULL == pr) {
1153 if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*strokeInfoPtr, viewMatrix, NULL) &&
1154 !strokeInfoPtr->isFillStyle()) {
1155 // It didn't work above, so try again with stroke converted to a fill.
1156 if (!tmpPath.isValid()) {
1157 tmpPath.init();
1158 }
1159 dashlessStrokeInfo.setResScale(SkScalarAbs(viewMatrix.getMaxScale()));
1160 if (!dashlessStrokeInfo.applyToPath(tmpPath.get(), *pathPtr)) {
1161 return;
1162 }
1163 pathPtr = tmpPath.get();
1164 if (pathPtr->isEmpty()) {
1165 return;
1166 }
1167 dashlessStrokeInfo.setFillStyle();
1168 strokeInfoPtr = &dashlessStrokeInfo;
1169 }
1170
1171 // This time, allow SW renderer
1172 pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
1173 true, type);
1174 }
1175
1176 if (NULL == pr) {
1177#ifdef SK_DEBUG
1178 SkDebugf("Unable to find path renderer compatible with path.\n");
1179#endif
1180 return;
1181 }
1182
1183 pr->drawPath(target, pipelineBuilder, color, viewMatrix, *pathPtr, *strokeInfoPtr, useCoverageAA);
1184}
1185
robertphillipsea461502015-05-26 11:38:03 -07001186bool GrDrawContext::prepareToDraw(GrRenderTarget* rt) {
1187 RETURN_FALSE_IF_ABANDONED
1188
1189 ASSERT_OWNED_RESOURCE(rt);
1190 SkASSERT(rt);
1191 return true;
1192}
1193
robertphillips2334fb62015-06-17 05:43:33 -07001194void GrDrawContext::drawBatch(GrPipelineBuilder* pipelineBuilder, GrBatch* batch) {
1195 fDrawTarget->drawBatch(pipelineBuilder, batch);
1196}
1197
robertphillipsea461502015-05-26 11:38:03 -07001198///////////////////////////////////////////////////////////////////////////////////////////////////
1199
1200#ifdef GR_TEST_UTILS
1201
1202BATCH_TEST_DEFINE(StrokeRectBatch) {
1203 StrokeRectBatch::Geometry geometry;
1204 geometry.fViewMatrix = GrTest::TestMatrix(random);
1205 geometry.fColor = GrRandomColor(random);
1206 geometry.fRect = GrTest::TestRect(random);
1207 geometry.fStrokeWidth = random->nextBool() ? 0.0f : 1.0f;
1208
1209 return StrokeRectBatch::Create(geometry, random->nextBool());
1210}
1211
1212static uint32_t seed_vertices(GrPrimitiveType type) {
1213 switch (type) {
1214 case kTriangles_GrPrimitiveType:
1215 case kTriangleStrip_GrPrimitiveType:
1216 case kTriangleFan_GrPrimitiveType:
1217 return 3;
1218 case kPoints_GrPrimitiveType:
1219 return 1;
1220 case kLines_GrPrimitiveType:
1221 case kLineStrip_GrPrimitiveType:
1222 return 2;
1223 }
1224 SkFAIL("Incomplete switch\n");
1225 return 0;
1226}
1227
1228static uint32_t primitive_vertices(GrPrimitiveType type) {
1229 switch (type) {
1230 case kTriangles_GrPrimitiveType:
1231 return 3;
1232 case kLines_GrPrimitiveType:
1233 return 2;
1234 case kTriangleStrip_GrPrimitiveType:
1235 case kTriangleFan_GrPrimitiveType:
1236 case kPoints_GrPrimitiveType:
1237 case kLineStrip_GrPrimitiveType:
1238 return 1;
1239 }
1240 SkFAIL("Incomplete switch\n");
1241 return 0;
1242}
1243
1244static SkPoint random_point(SkRandom* random, SkScalar min, SkScalar max) {
1245 SkPoint p;
1246 p.fX = random->nextRangeScalar(min, max);
1247 p.fY = random->nextRangeScalar(min, max);
1248 return p;
1249}
1250
1251static void randomize_params(size_t count, size_t maxVertex, SkScalar min, SkScalar max,
1252 SkRandom* random,
1253 SkTArray<SkPoint>* positions,
1254 SkTArray<SkPoint>* texCoords, bool hasTexCoords,
1255 SkTArray<GrColor>* colors, bool hasColors,
1256 SkTArray<uint16_t>* indices, bool hasIndices) {
1257 for (uint32_t v = 0; v < count; v++) {
1258 positions->push_back(random_point(random, min, max));
1259 if (hasTexCoords) {
1260 texCoords->push_back(random_point(random, min, max));
1261 }
1262 if (hasColors) {
1263 colors->push_back(GrRandomColor(random));
1264 }
1265 if (hasIndices) {
1266 SkASSERT(maxVertex <= SK_MaxU16);
1267 indices->push_back(random->nextULessThan((uint16_t)maxVertex));
1268 }
1269 }
1270}
1271
1272BATCH_TEST_DEFINE(VerticesBatch) {
1273 GrPrimitiveType type = GrPrimitiveType(random->nextULessThan(kLast_GrPrimitiveType + 1));
1274 uint32_t primitiveCount = random->nextRangeU(1, 100);
1275
1276 // TODO make 'sensible' indexbuffers
1277 SkTArray<SkPoint> positions;
1278 SkTArray<SkPoint> texCoords;
1279 SkTArray<GrColor> colors;
1280 SkTArray<uint16_t> indices;
1281
1282 bool hasTexCoords = random->nextBool();
1283 bool hasIndices = random->nextBool();
1284 bool hasColors = random->nextBool();
1285
1286 uint32_t vertexCount = seed_vertices(type) + (primitiveCount - 1) * primitive_vertices(type);
1287
1288 static const SkScalar kMinVertExtent = -100.f;
1289 static const SkScalar kMaxVertExtent = 100.f;
1290 randomize_params(seed_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent,
1291 random,
1292 &positions,
1293 &texCoords, hasTexCoords,
1294 &colors, hasColors,
1295 &indices, hasIndices);
1296
1297 for (uint32_t i = 1; i < primitiveCount; i++) {
1298 randomize_params(primitive_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent,
1299 random,
1300 &positions,
1301 &texCoords, hasTexCoords,
1302 &colors, hasColors,
1303 &indices, hasIndices);
1304 }
1305
1306 SkMatrix viewMatrix = GrTest::TestMatrix(random);
1307 SkRect bounds;
1308 SkDEBUGCODE(bool result = ) bounds.setBoundsCheck(positions.begin(), vertexCount);
1309 SkASSERT(result);
1310
1311 viewMatrix.mapRect(&bounds);
1312
1313 DrawVerticesBatch::Geometry geometry;
1314 geometry.fColor = GrRandomColor(random);
1315 return DrawVerticesBatch::Create(geometry, type, viewMatrix,
1316 positions.begin(), vertexCount,
1317 indices.begin(), hasIndices ? vertexCount : 0,
1318 colors.begin(),
1319 texCoords.begin(),
1320 bounds);
1321}
1322
1323#endif
1324