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