blob: b957b9124e88f492c1d02deaf7665244300ea976 [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);
190 GrPipelineBuilder pipelineBuilder;
191 if (!this->prepareToDraw(&pipelineBuilder, rt, clip, paint)) {
192 return;
193 }
194
195 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);
438 GrPipelineBuilder pipelineBuilder;
439 if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) {
440 return;
441 }
442
443 SkScalar width = NULL == strokeInfo ? -1 : strokeInfo->getWidth();
444
445 // Check if this is a full RT draw and can be replaced with a clear. We don't bother checking
446 // cases where the RT is fully inside a stroke.
447 if (width < 0) {
448 SkRect rtRect;
449 pipelineBuilder.getRenderTarget()->getBoundsRect(&rtRect);
450 SkRect clipSpaceRTRect = rtRect;
451 bool checkClip = GrClip::kWideOpen_ClipType != clip.clipType();
452 if (checkClip) {
453 clipSpaceRTRect.offset(SkIntToScalar(clip.origin().fX),
454 SkIntToScalar(clip.origin().fY));
455 }
456 // Does the clip contain the entire RT?
457 if (!checkClip || clip.quickContains(clipSpaceRTRect)) {
458 SkMatrix invM;
459 if (!viewMatrix.invert(&invM)) {
460 return;
461 }
462 // Does the rect bound the RT?
463 SkPoint srcSpaceRTQuad[4];
464 invM.mapRectToQuad(srcSpaceRTQuad, rtRect);
465 if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) &&
466 rect_contains_inclusive(rect, srcSpaceRTQuad[1]) &&
467 rect_contains_inclusive(rect, srcSpaceRTQuad[2]) &&
468 rect_contains_inclusive(rect, srcSpaceRTQuad[3])) {
469 // Will it blend?
470 GrColor clearColor;
cdalton1fa45722015-06-02 10:43:39 -0700471 if (paint.isConstantBlendedColor(&clearColor)) {
robertphillipsea461502015-05-26 11:38:03 -0700472 fDrawTarget->clear(NULL, clearColor, true, rt);
473 return;
474 }
475 }
476 }
477 }
478
479 GrColor color = paint.getColor();
480 SkRect devBoundRect;
vbuzinovdded6962015-06-12 08:59:45 -0700481 bool needAA = paint.isAntiAlias() &&
482 !pipelineBuilder.getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -0700483 bool doAA = needAA && apply_aa_to_rect(fDrawTarget, &pipelineBuilder, &devBoundRect, rect,
484 width, viewMatrix, color);
485
486 if (doAA) {
487 if (width >= 0) {
488 GrAARectRenderer::StrokeAARect(fDrawTarget,
489 &pipelineBuilder,
490 color,
491 viewMatrix,
492 rect,
493 devBoundRect,
494 *strokeInfo);
495 } else {
496 // filled AA rect
497 GrAARectRenderer::FillAARect(fDrawTarget,
498 &pipelineBuilder,
499 color,
500 viewMatrix,
501 rect,
502 devBoundRect);
503 }
504 return;
505 }
506
507 if (width >= 0) {
508 StrokeRectBatch::Geometry geometry;
509 geometry.fViewMatrix = viewMatrix;
510 geometry.fColor = color;
511 geometry.fRect = rect;
512 geometry.fStrokeWidth = width;
513
514 // Non-AA hairlines are snapped to pixel centers to make which pixels are hit deterministic
vbuzinovdded6962015-06-12 08:59:45 -0700515 bool snapToPixelCenters = (0 == width && !rt->isUnifiedMultisampled());
robertphillipsea461502015-05-26 11:38:03 -0700516 SkAutoTUnref<GrBatch> batch(StrokeRectBatch::Create(geometry, snapToPixelCenters));
517
518 // Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of
519 // hairline rects. We jam all the vertices to pixel centers to avoid this, but not when MSAA
520 // is enabled because it can cause ugly artifacts.
521 pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_Flag,
522 snapToPixelCenters);
523 fDrawTarget->drawBatch(&pipelineBuilder, batch);
524 } else {
525 // filled BW rect
526 fDrawTarget->drawSimpleRect(&pipelineBuilder, color, viewMatrix, rect);
527 }
528}
529
530void GrDrawContext::drawNonAARectToRect(GrRenderTarget* rt,
531 const GrClip& clip,
532 const GrPaint& paint,
533 const SkMatrix& viewMatrix,
534 const SkRect& rectToDraw,
535 const SkRect& localRect,
536 const SkMatrix* localMatrix) {
537 RETURN_IF_ABANDONED
538 AutoCheckFlush acf(fContext);
539 GrPipelineBuilder pipelineBuilder;
540 if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) {
541 return;
542 }
543
544 fDrawTarget->drawBWRect(&pipelineBuilder,
545 paint.getColor(),
546 viewMatrix,
547 rectToDraw,
548 &localRect,
549 localMatrix);
550}
551
552static const GrGeometryProcessor* set_vertex_attributes(bool hasLocalCoords,
553 bool hasColors,
554 int* colorOffset,
555 int* texOffset,
556 GrColor color,
557 const SkMatrix& viewMatrix,
558 bool coverageIgnored) {
559 *texOffset = -1;
560 *colorOffset = -1;
561 uint32_t flags = GrDefaultGeoProcFactory::kPosition_GPType;
562 if (hasLocalCoords && hasColors) {
563 *colorOffset = sizeof(SkPoint);
564 *texOffset = sizeof(SkPoint) + sizeof(GrColor);
565 flags |= GrDefaultGeoProcFactory::kColor_GPType |
566 GrDefaultGeoProcFactory::kLocalCoord_GPType;
567 } else if (hasLocalCoords) {
568 *texOffset = sizeof(SkPoint);
569 flags |= GrDefaultGeoProcFactory::kLocalCoord_GPType;
570 } else if (hasColors) {
571 *colorOffset = sizeof(SkPoint);
572 flags |= GrDefaultGeoProcFactory::kColor_GPType;
573 }
574 return GrDefaultGeoProcFactory::Create(flags, color, hasLocalCoords, coverageIgnored,
575 viewMatrix, SkMatrix::I());
576}
577
578class DrawVerticesBatch : public GrBatch {
579public:
580 struct Geometry {
581 GrColor fColor;
582 SkTDArray<SkPoint> fPositions;
583 SkTDArray<uint16_t> fIndices;
584 SkTDArray<GrColor> fColors;
585 SkTDArray<SkPoint> fLocalCoords;
586 };
587
588 static GrBatch* Create(const Geometry& geometry, GrPrimitiveType primitiveType,
589 const SkMatrix& viewMatrix,
590 const SkPoint* positions, int vertexCount,
591 const uint16_t* indices, int indexCount,
592 const GrColor* colors, const SkPoint* localCoords,
593 const SkRect& bounds) {
594 return SkNEW_ARGS(DrawVerticesBatch, (geometry, primitiveType, viewMatrix, positions,
595 vertexCount, indices, indexCount, colors,
596 localCoords, bounds));
597 }
598
599 const char* name() const override { return "DrawVerticesBatch"; }
600
601 void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
602 // When this is called on a batch, there is only one geometry bundle
603 if (this->hasColors()) {
604 out->setUnknownFourComponents();
605 } else {
606 out->setKnownFourComponents(fGeoData[0].fColor);
607 }
608 }
609
610 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
611 out->setKnownSingleComponent(0xff);
612 }
613
614 void initBatchTracker(const GrPipelineInfo& init) override {
615 // Handle any color overrides
bsalomon7765a472015-07-08 11:26:37 -0700616 if (!init.readsColor()) {
robertphillipsea461502015-05-26 11:38:03 -0700617 fGeoData[0].fColor = GrColor_ILLEGAL;
robertphillipsea461502015-05-26 11:38:03 -0700618 }
bsalomon7765a472015-07-08 11:26:37 -0700619 init.getOverrideColorIfSet(&fGeoData[0].fColor);
robertphillipsea461502015-05-26 11:38:03 -0700620
621 // setup batch properties
bsalomon7765a472015-07-08 11:26:37 -0700622 fBatch.fColorIgnored = !init.readsColor();
robertphillipsea461502015-05-26 11:38:03 -0700623 fBatch.fColor = fGeoData[0].fColor;
bsalomon7765a472015-07-08 11:26:37 -0700624 fBatch.fUsesLocalCoords = init.readsLocalCoords();
625 fBatch.fCoverageIgnored = !init.readsCoverage();
robertphillipsea461502015-05-26 11:38:03 -0700626 }
627
628 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override {
629 int colorOffset = -1, texOffset = -1;
630 SkAutoTUnref<const GrGeometryProcessor> gp(
631 set_vertex_attributes(this->hasLocalCoords(), this->hasColors(), &colorOffset,
632 &texOffset, this->color(), this->viewMatrix(),
633 this->coverageIgnored()));
634
635 batchTarget->initDraw(gp, pipeline);
636
637 size_t vertexStride = gp->getVertexStride();
638
639 SkASSERT(vertexStride == sizeof(SkPoint) + (this->hasLocalCoords() ? sizeof(SkPoint) : 0)
640 + (this->hasColors() ? sizeof(GrColor) : 0));
641
642 int instanceCount = fGeoData.count();
643
644 const GrVertexBuffer* vertexBuffer;
645 int firstVertex;
646
647 void* verts = batchTarget->makeVertSpace(vertexStride, this->vertexCount(),
648 &vertexBuffer, &firstVertex);
649
650 if (!verts) {
651 SkDebugf("Could not allocate vertices\n");
652 return;
653 }
654
655 const GrIndexBuffer* indexBuffer = NULL;
656 int firstIndex = 0;
657
658 uint16_t* indices = NULL;
659 if (this->hasIndices()) {
660 indices = batchTarget->makeIndexSpace(this->indexCount(), &indexBuffer, &firstIndex);
661
662 if (!indices) {
663 SkDebugf("Could not allocate indices\n");
664 return;
665 }
666 }
667
668 int indexOffset = 0;
669 int vertexOffset = 0;
670 for (int i = 0; i < instanceCount; i++) {
671 const Geometry& args = fGeoData[i];
672
673 // TODO we can actually cache this interleaved and then just memcopy
674 if (this->hasIndices()) {
675 for (int j = 0; j < args.fIndices.count(); ++j, ++indexOffset) {
676 *(indices + indexOffset) = args.fIndices[j] + vertexOffset;
677 }
678 }
679
680 for (int j = 0; j < args.fPositions.count(); ++j) {
681 *((SkPoint*)verts) = args.fPositions[j];
682 if (this->hasColors()) {
683 *(GrColor*)((intptr_t)verts + colorOffset) = args.fColors[j];
684 }
685 if (this->hasLocalCoords()) {
686 *(SkPoint*)((intptr_t)verts + texOffset) = args.fLocalCoords[j];
687 }
688 verts = (void*)((intptr_t)verts + vertexStride);
689 vertexOffset++;
690 }
691 }
692
693 GrVertices vertices;
694 if (this->hasIndices()) {
695 vertices.initIndexed(this->primitiveType(), vertexBuffer, indexBuffer, firstVertex,
696 firstIndex, this->vertexCount(), this->indexCount());
697
698 } else {
699 vertices.init(this->primitiveType(), vertexBuffer, firstVertex, this->vertexCount());
700 }
701 batchTarget->draw(vertices);
702 }
703
704 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
705
706private:
707 DrawVerticesBatch(const Geometry& geometry, GrPrimitiveType primitiveType,
708 const SkMatrix& viewMatrix,
709 const SkPoint* positions, int vertexCount,
710 const uint16_t* indices, int indexCount,
711 const GrColor* colors, const SkPoint* localCoords, const SkRect& bounds) {
712 this->initClassID<DrawVerticesBatch>();
713 SkASSERT(positions);
714
715 fBatch.fViewMatrix = viewMatrix;
716 Geometry& installedGeo = fGeoData.push_back(geometry);
717
718 installedGeo.fPositions.append(vertexCount, positions);
719 if (indices) {
720 installedGeo.fIndices.append(indexCount, indices);
721 fBatch.fHasIndices = true;
722 } else {
723 fBatch.fHasIndices = false;
724 }
725
726 if (colors) {
727 installedGeo.fColors.append(vertexCount, colors);
728 fBatch.fHasColors = true;
729 } else {
730 fBatch.fHasColors = false;
731 }
732
733 if (localCoords) {
734 installedGeo.fLocalCoords.append(vertexCount, localCoords);
735 fBatch.fHasLocalCoords = true;
736 } else {
737 fBatch.fHasLocalCoords = false;
738 }
739 fBatch.fVertexCount = vertexCount;
740 fBatch.fIndexCount = indexCount;
741 fBatch.fPrimitiveType = primitiveType;
742
743 this->setBounds(bounds);
744 }
745
746 GrPrimitiveType primitiveType() const { return fBatch.fPrimitiveType; }
747 bool batchablePrimitiveType() const {
748 return kTriangles_GrPrimitiveType == fBatch.fPrimitiveType ||
749 kLines_GrPrimitiveType == fBatch.fPrimitiveType ||
750 kPoints_GrPrimitiveType == fBatch.fPrimitiveType;
751 }
752 GrColor color() const { return fBatch.fColor; }
753 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
754 bool colorIgnored() const { return fBatch.fColorIgnored; }
755 const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
756 bool hasColors() const { return fBatch.fHasColors; }
757 bool hasIndices() const { return fBatch.fHasIndices; }
758 bool hasLocalCoords() const { return fBatch.fHasLocalCoords; }
759 int vertexCount() const { return fBatch.fVertexCount; }
760 int indexCount() const { return fBatch.fIndexCount; }
761 bool coverageIgnored() const { return fBatch.fCoverageIgnored; }
762
763 bool onCombineIfPossible(GrBatch* t) override {
764 DrawVerticesBatch* that = t->cast<DrawVerticesBatch>();
765
766 if (!this->batchablePrimitiveType() || this->primitiveType() != that->primitiveType()) {
767 return false;
768 }
769
770 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
771
772 // We currently use a uniform viewmatrix for this batch
773 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
774 return false;
775 }
776
777 if (this->hasColors() != that->hasColors()) {
778 return false;
779 }
780
781 if (this->hasIndices() != that->hasIndices()) {
782 return false;
783 }
784
785 if (this->hasLocalCoords() != that->hasLocalCoords()) {
786 return false;
787 }
788
789 if (!this->hasColors() && this->color() != that->color()) {
790 return false;
791 }
792
793 if (this->color() != that->color()) {
794 fBatch.fColor = GrColor_ILLEGAL;
795 }
796 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
797 fBatch.fVertexCount += that->vertexCount();
798 fBatch.fIndexCount += that->indexCount();
799
800 this->joinBounds(that->bounds());
801 return true;
802 }
803
804 struct BatchTracker {
805 GrPrimitiveType fPrimitiveType;
806 SkMatrix fViewMatrix;
807 GrColor fColor;
808 bool fUsesLocalCoords;
809 bool fColorIgnored;
810 bool fCoverageIgnored;
811 bool fHasColors;
812 bool fHasIndices;
813 bool fHasLocalCoords;
814 int fVertexCount;
815 int fIndexCount;
816 };
817
818 BatchTracker fBatch;
819 SkSTArray<1, Geometry, true> fGeoData;
820};
821
822void GrDrawContext::drawVertices(GrRenderTarget* rt,
823 const GrClip& clip,
824 const GrPaint& paint,
825 const SkMatrix& viewMatrix,
826 GrPrimitiveType primitiveType,
827 int vertexCount,
828 const SkPoint positions[],
829 const SkPoint texCoords[],
830 const GrColor colors[],
831 const uint16_t indices[],
832 int indexCount) {
833 RETURN_IF_ABANDONED
834 AutoCheckFlush acf(fContext);
835 GrPipelineBuilder pipelineBuilder;
836
837 if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) {
838 return;
839 }
840
841 // TODO clients should give us bounds
842 SkRect bounds;
843 if (!bounds.setBoundsCheck(positions, vertexCount)) {
844 SkDebugf("drawVertices call empty bounds\n");
845 return;
846 }
847
848 viewMatrix.mapRect(&bounds);
849
850 // If we don't have AA then we outset for a half pixel in each direction to account for
851 // snapping
852 if (!paint.isAntiAlias()) {
853 bounds.outset(0.5f, 0.5f);
854 }
855
856 DrawVerticesBatch::Geometry geometry;
857 geometry.fColor = paint.getColor();
858 SkAutoTUnref<GrBatch> batch(DrawVerticesBatch::Create(geometry, primitiveType, viewMatrix,
859 positions, vertexCount, indices,
860 indexCount, colors, texCoords,
861 bounds));
862
863 fDrawTarget->drawBatch(&pipelineBuilder, batch);
864}
865
866///////////////////////////////////////////////////////////////////////////////
867
868void GrDrawContext::drawRRect(GrRenderTarget*rt,
869 const GrClip& clip,
870 const GrPaint& paint,
871 const SkMatrix& viewMatrix,
872 const SkRRect& rrect,
873 const GrStrokeInfo& strokeInfo) {
874 RETURN_IF_ABANDONED
875 if (rrect.isEmpty()) {
876 return;
877 }
878
879 if (strokeInfo.isDashed()) {
880 SkPath path;
881 path.setIsVolatile(true);
882 path.addRRect(rrect);
883 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
884 return;
885 }
886
887 AutoCheckFlush acf(fContext);
888 GrPipelineBuilder pipelineBuilder;
889 if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) {
890 return;
891 }
892
893 GrColor color = paint.getColor();
894 if (!GrOvalRenderer::DrawRRect(fDrawTarget,
895 &pipelineBuilder,
896 color,
897 viewMatrix,
898 paint.isAntiAlias(),
899 rrect,
900 strokeInfo)) {
901 SkPath path;
902 path.setIsVolatile(true);
903 path.addRRect(rrect);
904 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
905 paint.isAntiAlias(), path, strokeInfo);
906 }
907}
908
909///////////////////////////////////////////////////////////////////////////////
910
911void GrDrawContext::drawDRRect(GrRenderTarget* rt,
912 const GrClip& clip,
913 const GrPaint& paint,
914 const SkMatrix& viewMatrix,
915 const SkRRect& outer,
916 const SkRRect& inner) {
917 RETURN_IF_ABANDONED
918 if (outer.isEmpty()) {
919 return;
920 }
921
922 AutoCheckFlush acf(fContext);
923 GrPipelineBuilder pipelineBuilder;
924 if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) {
925 return;
926 }
927
928 GrColor color = paint.getColor();
929 if (!GrOvalRenderer::DrawDRRect(fDrawTarget,
930 &pipelineBuilder,
931 color,
932 viewMatrix,
933 paint.isAntiAlias(),
934 outer,
935 inner)) {
936 SkPath path;
937 path.setIsVolatile(true);
938 path.addRRect(inner);
939 path.addRRect(outer);
940 path.setFillType(SkPath::kEvenOdd_FillType);
941
942 GrStrokeInfo fillRec(SkStrokeRec::kFill_InitStyle);
943 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
944 paint.isAntiAlias(), path, fillRec);
945 }
946}
947
948///////////////////////////////////////////////////////////////////////////////
949
950void GrDrawContext::drawOval(GrRenderTarget* rt,
951 const GrClip& clip,
952 const GrPaint& paint,
953 const SkMatrix& viewMatrix,
954 const SkRect& oval,
955 const GrStrokeInfo& strokeInfo) {
956 RETURN_IF_ABANDONED
957 if (oval.isEmpty()) {
958 return;
959 }
960
961 if (strokeInfo.isDashed()) {
962 SkPath path;
963 path.setIsVolatile(true);
964 path.addOval(oval);
965 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
966 return;
967 }
968
969 AutoCheckFlush acf(fContext);
970 GrPipelineBuilder pipelineBuilder;
971 if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) {
972 return;
973 }
974
975 GrColor color = paint.getColor();
976 if (!GrOvalRenderer::DrawOval(fDrawTarget,
977 &pipelineBuilder,
978 color,
979 viewMatrix,
980 paint.isAntiAlias(),
981 oval,
982 strokeInfo)) {
983 SkPath path;
984 path.setIsVolatile(true);
985 path.addOval(oval);
986 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
987 paint.isAntiAlias(), path, strokeInfo);
988 }
989}
990
991// Can 'path' be drawn as a pair of filled nested rectangles?
992static bool is_nested_rects(GrDrawTarget* target,
993 GrPipelineBuilder* pipelineBuilder,
994 GrColor color,
995 const SkMatrix& viewMatrix,
996 const SkPath& path,
997 const SkStrokeRec& stroke,
998 SkRect rects[2]) {
999 SkASSERT(stroke.isFillStyle());
1000
1001 if (path.isInverseFillType()) {
1002 return false;
1003 }
1004
1005 // TODO: this restriction could be lifted if we were willing to apply
1006 // the matrix to all the points individually rather than just to the rect
1007 if (!viewMatrix.preservesAxisAlignment()) {
1008 return false;
1009 }
1010
1011 SkPath::Direction dirs[2];
1012 if (!path.isNestedFillRects(rects, dirs)) {
1013 return false;
1014 }
1015
1016 if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) {
1017 // The two rects need to be wound opposite to each other
1018 return false;
1019 }
1020
1021 // Right now, nested rects where the margin is not the same width
1022 // all around do not render correctly
1023 const SkScalar* outer = rects[0].asScalars();
1024 const SkScalar* inner = rects[1].asScalars();
1025
1026 bool allEq = true;
1027
1028 SkScalar margin = SkScalarAbs(outer[0] - inner[0]);
1029 bool allGoE1 = margin >= SK_Scalar1;
1030
1031 for (int i = 1; i < 4; ++i) {
1032 SkScalar temp = SkScalarAbs(outer[i] - inner[i]);
1033 if (temp < SK_Scalar1) {
1034 allGoE1 = false;
1035 }
1036 if (!SkScalarNearlyEqual(margin, temp)) {
1037 allEq = false;
1038 }
1039 }
1040
1041 return allEq || allGoE1;
1042}
1043
1044void GrDrawContext::drawPath(GrRenderTarget* rt,
1045 const GrClip& clip,
1046 const GrPaint& paint,
1047 const SkMatrix& viewMatrix,
1048 const SkPath& path,
1049 const GrStrokeInfo& strokeInfo) {
1050 RETURN_IF_ABANDONED
1051 if (path.isEmpty()) {
1052 if (path.isInverseFillType()) {
1053 this->drawPaint(rt, clip, paint, viewMatrix);
1054 }
1055 return;
1056 }
1057
1058 GrColor color = paint.getColor();
1059
1060 // Note that internalDrawPath may sw-rasterize the path into a scratch texture.
1061 // Scratch textures can be recycled after they are returned to the texture
1062 // cache. This presents a potential hazard for buffered drawing. However,
1063 // the writePixels that uploads to the scratch will perform a flush so we're
1064 // OK.
1065 AutoCheckFlush acf(fContext);
1066 GrPipelineBuilder pipelineBuilder;
1067 if (!this->prepareToDraw(&pipelineBuilder, rt, clip, &paint)) {
1068 return;
1069 }
1070
1071 if (!strokeInfo.isDashed()) {
1072 bool useCoverageAA = paint.isAntiAlias() &&
vbuzinovdded6962015-06-12 08:59:45 -07001073 !pipelineBuilder.getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -07001074
1075 if (useCoverageAA && strokeInfo.getWidth() < 0 && !path.isConvex()) {
1076 // Concave AA paths are expensive - try to avoid them for special cases
1077 SkRect rects[2];
1078
1079 if (is_nested_rects(fDrawTarget, &pipelineBuilder, color, viewMatrix, path, strokeInfo,
1080 rects)) {
1081 GrAARectRenderer::FillAANestedRects(fDrawTarget, &pipelineBuilder, color,
1082 viewMatrix, rects);
1083 return;
1084 }
1085 }
1086 SkRect ovalRect;
1087 bool isOval = path.isOval(&ovalRect);
1088
1089 if (isOval && !path.isInverseFillType()) {
1090 if (GrOvalRenderer::DrawOval(fDrawTarget,
1091 &pipelineBuilder,
1092 color,
1093 viewMatrix,
1094 paint.isAntiAlias(),
1095 ovalRect,
1096 strokeInfo)) {
1097 return;
1098 }
1099 }
1100 }
1101 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
1102 path, strokeInfo);
1103}
1104
1105void GrDrawContext::internalDrawPath(GrDrawTarget* target,
1106 GrPipelineBuilder* pipelineBuilder,
1107 const SkMatrix& viewMatrix,
1108 GrColor color,
1109 bool useAA,
1110 const SkPath& path,
1111 const GrStrokeInfo& strokeInfo) {
1112 RETURN_IF_ABANDONED
1113 SkASSERT(!path.isEmpty());
1114
1115
1116 // An Assumption here is that path renderer would use some form of tweaking
1117 // the src color (either the input alpha or in the frag shader) to implement
1118 // aa. If we have some future driver-mojo path AA that can do the right
1119 // thing WRT to the blend then we'll need some query on the PR.
1120 bool useCoverageAA = useAA &&
vbuzinovdded6962015-06-12 08:59:45 -07001121 !pipelineBuilder->getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -07001122
1123
1124 GrPathRendererChain::DrawType type =
1125 useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType :
1126 GrPathRendererChain::kColor_DrawType;
1127
1128 const SkPath* pathPtr = &path;
1129 SkTLazy<SkPath> tmpPath;
1130 const GrStrokeInfo* strokeInfoPtr = &strokeInfo;
1131
1132 // Try a 1st time without stroking the path and without allowing the SW renderer
1133 GrPathRenderer* pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr,
1134 *strokeInfoPtr, false, type);
1135
1136 GrStrokeInfo dashlessStrokeInfo(strokeInfo, false);
1137 if (NULL == pr && strokeInfo.isDashed()) {
1138 // It didn't work above, so try again with dashed stroke converted to a dashless stroke.
1139 if (!strokeInfo.applyDashToPath(tmpPath.init(), &dashlessStrokeInfo, *pathPtr)) {
1140 return;
1141 }
1142 pathPtr = tmpPath.get();
1143 if (pathPtr->isEmpty()) {
1144 return;
1145 }
1146 strokeInfoPtr = &dashlessStrokeInfo;
1147 pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
1148 false, type);
1149 }
1150
1151 if (NULL == pr) {
1152 if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*strokeInfoPtr, viewMatrix, NULL) &&
1153 !strokeInfoPtr->isFillStyle()) {
1154 // It didn't work above, so try again with stroke converted to a fill.
1155 if (!tmpPath.isValid()) {
1156 tmpPath.init();
1157 }
1158 dashlessStrokeInfo.setResScale(SkScalarAbs(viewMatrix.getMaxScale()));
1159 if (!dashlessStrokeInfo.applyToPath(tmpPath.get(), *pathPtr)) {
1160 return;
1161 }
1162 pathPtr = tmpPath.get();
1163 if (pathPtr->isEmpty()) {
1164 return;
1165 }
1166 dashlessStrokeInfo.setFillStyle();
1167 strokeInfoPtr = &dashlessStrokeInfo;
1168 }
1169
1170 // This time, allow SW renderer
1171 pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
1172 true, type);
1173 }
1174
1175 if (NULL == pr) {
1176#ifdef SK_DEBUG
1177 SkDebugf("Unable to find path renderer compatible with path.\n");
1178#endif
1179 return;
1180 }
1181
1182 pr->drawPath(target, pipelineBuilder, color, viewMatrix, *pathPtr, *strokeInfoPtr, useCoverageAA);
1183}
1184
1185bool GrDrawContext::prepareToDraw(GrPipelineBuilder* pipelineBuilder,
1186 GrRenderTarget* rt,
1187 const GrClip& clip,
1188 const GrPaint* paint) {
1189 RETURN_FALSE_IF_ABANDONED
1190
1191 ASSERT_OWNED_RESOURCE(rt);
1192 SkASSERT(rt && paint);
1193 pipelineBuilder->setFromPaint(*paint, rt, clip);
1194 return true;
1195}
1196
1197bool GrDrawContext::prepareToDraw(GrRenderTarget* rt) {
1198 RETURN_FALSE_IF_ABANDONED
1199
1200 ASSERT_OWNED_RESOURCE(rt);
1201 SkASSERT(rt);
1202 return true;
1203}
1204
robertphillips2334fb62015-06-17 05:43:33 -07001205void GrDrawContext::drawBatch(GrPipelineBuilder* pipelineBuilder, GrBatch* batch) {
1206 fDrawTarget->drawBatch(pipelineBuilder, batch);
1207}
1208
robertphillipsea461502015-05-26 11:38:03 -07001209///////////////////////////////////////////////////////////////////////////////////////////////////
1210
1211#ifdef GR_TEST_UTILS
1212
1213BATCH_TEST_DEFINE(StrokeRectBatch) {
1214 StrokeRectBatch::Geometry geometry;
1215 geometry.fViewMatrix = GrTest::TestMatrix(random);
1216 geometry.fColor = GrRandomColor(random);
1217 geometry.fRect = GrTest::TestRect(random);
1218 geometry.fStrokeWidth = random->nextBool() ? 0.0f : 1.0f;
1219
1220 return StrokeRectBatch::Create(geometry, random->nextBool());
1221}
1222
1223static uint32_t seed_vertices(GrPrimitiveType type) {
1224 switch (type) {
1225 case kTriangles_GrPrimitiveType:
1226 case kTriangleStrip_GrPrimitiveType:
1227 case kTriangleFan_GrPrimitiveType:
1228 return 3;
1229 case kPoints_GrPrimitiveType:
1230 return 1;
1231 case kLines_GrPrimitiveType:
1232 case kLineStrip_GrPrimitiveType:
1233 return 2;
1234 }
1235 SkFAIL("Incomplete switch\n");
1236 return 0;
1237}
1238
1239static uint32_t primitive_vertices(GrPrimitiveType type) {
1240 switch (type) {
1241 case kTriangles_GrPrimitiveType:
1242 return 3;
1243 case kLines_GrPrimitiveType:
1244 return 2;
1245 case kTriangleStrip_GrPrimitiveType:
1246 case kTriangleFan_GrPrimitiveType:
1247 case kPoints_GrPrimitiveType:
1248 case kLineStrip_GrPrimitiveType:
1249 return 1;
1250 }
1251 SkFAIL("Incomplete switch\n");
1252 return 0;
1253}
1254
1255static SkPoint random_point(SkRandom* random, SkScalar min, SkScalar max) {
1256 SkPoint p;
1257 p.fX = random->nextRangeScalar(min, max);
1258 p.fY = random->nextRangeScalar(min, max);
1259 return p;
1260}
1261
1262static void randomize_params(size_t count, size_t maxVertex, SkScalar min, SkScalar max,
1263 SkRandom* random,
1264 SkTArray<SkPoint>* positions,
1265 SkTArray<SkPoint>* texCoords, bool hasTexCoords,
1266 SkTArray<GrColor>* colors, bool hasColors,
1267 SkTArray<uint16_t>* indices, bool hasIndices) {
1268 for (uint32_t v = 0; v < count; v++) {
1269 positions->push_back(random_point(random, min, max));
1270 if (hasTexCoords) {
1271 texCoords->push_back(random_point(random, min, max));
1272 }
1273 if (hasColors) {
1274 colors->push_back(GrRandomColor(random));
1275 }
1276 if (hasIndices) {
1277 SkASSERT(maxVertex <= SK_MaxU16);
1278 indices->push_back(random->nextULessThan((uint16_t)maxVertex));
1279 }
1280 }
1281}
1282
1283BATCH_TEST_DEFINE(VerticesBatch) {
1284 GrPrimitiveType type = GrPrimitiveType(random->nextULessThan(kLast_GrPrimitiveType + 1));
1285 uint32_t primitiveCount = random->nextRangeU(1, 100);
1286
1287 // TODO make 'sensible' indexbuffers
1288 SkTArray<SkPoint> positions;
1289 SkTArray<SkPoint> texCoords;
1290 SkTArray<GrColor> colors;
1291 SkTArray<uint16_t> indices;
1292
1293 bool hasTexCoords = random->nextBool();
1294 bool hasIndices = random->nextBool();
1295 bool hasColors = random->nextBool();
1296
1297 uint32_t vertexCount = seed_vertices(type) + (primitiveCount - 1) * primitive_vertices(type);
1298
1299 static const SkScalar kMinVertExtent = -100.f;
1300 static const SkScalar kMaxVertExtent = 100.f;
1301 randomize_params(seed_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent,
1302 random,
1303 &positions,
1304 &texCoords, hasTexCoords,
1305 &colors, hasColors,
1306 &indices, hasIndices);
1307
1308 for (uint32_t i = 1; i < primitiveCount; i++) {
1309 randomize_params(primitive_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent,
1310 random,
1311 &positions,
1312 &texCoords, hasTexCoords,
1313 &colors, hasColors,
1314 &indices, hasIndices);
1315 }
1316
1317 SkMatrix viewMatrix = GrTest::TestMatrix(random);
1318 SkRect bounds;
1319 SkDEBUGCODE(bool result = ) bounds.setBoundsCheck(positions.begin(), vertexCount);
1320 SkASSERT(result);
1321
1322 viewMatrix.mapRect(&bounds);
1323
1324 DrawVerticesBatch::Geometry geometry;
1325 geometry.fColor = GrRandomColor(random);
1326 return DrawVerticesBatch::Create(geometry, type, viewMatrix,
1327 positions.begin(), vertexCount,
1328 indices.begin(), hasIndices ? vertexCount : 0,
1329 colors.begin(),
1330 texCoords.begin(),
1331 bounds);
1332}
1333
1334#endif
1335