blob: 5d77f853d140d46c8b55f735fdd6d7d1089ba991 [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 "GrBatchTest.h"
jvanverth31ff7622015-08-07 10:09:28 -070012#include "GrColor.h"
robertphillipsea461502015-05-26 11:38:03 -070013#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
joshualitt74417822015-08-07 11:42:16 -070021#include "batches/GrBatch.h"
jvanverth14b88032015-08-07 12:18:54 -070022#include "batches/GrDrawAtlasBatch.h"
joshualitt74417822015-08-07 11:42:16 -070023#include "batches/GrStrokeRectBatch.h"
24
jvanverth31ff7622015-08-07 10:09:28 -070025#include "SkGr.h"
26#include "SkRSXform.h"
27
robertphillipsea461502015-05-26 11:38:03 -070028#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == fContext)
29#define RETURN_IF_ABANDONED if (!fDrawTarget) { return; }
30#define RETURN_FALSE_IF_ABANDONED if (!fDrawTarget) { return false; }
31#define RETURN_NULL_IF_ABANDONED if (!fDrawTarget) { return NULL; }
32
33class AutoCheckFlush {
34public:
35 AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context); }
36 ~AutoCheckFlush() { fContext->flushIfNecessary(); }
37
38private:
39 GrContext* fContext;
40};
41
robertphillips2334fb62015-06-17 05:43:33 -070042GrDrawContext::GrDrawContext(GrContext* context,
43 GrDrawTarget* drawTarget,
robertphillipsfcf78292015-06-19 11:49:52 -070044 const SkSurfaceProps& surfaceProps)
robertphillipsea461502015-05-26 11:38:03 -070045 : fContext(context)
robertphillips2334fb62015-06-17 05:43:33 -070046 , fDrawTarget(SkRef(drawTarget))
47 , fTextContext(NULL)
robertphillipsfcf78292015-06-19 11:49:52 -070048 , fSurfaceProps(surfaceProps) {
robertphillipsea461502015-05-26 11:38:03 -070049}
50
robertphillips4b195e52015-05-26 14:37:00 -070051GrDrawContext::~GrDrawContext() {
52 SkSafeUnref(fDrawTarget);
robertphillips2334fb62015-06-17 05:43:33 -070053 SkDELETE(fTextContext);
robertphillips4b195e52015-05-26 14:37:00 -070054}
55
robertphillipsea461502015-05-26 11:38:03 -070056void GrDrawContext::copySurface(GrRenderTarget* dst, GrSurface* src,
57 const SkIRect& srcRect, const SkIPoint& dstPoint) {
58 if (!this->prepareToDraw(dst)) {
59 return;
60 }
61
62 fDrawTarget->copySurface(dst, src, srcRect, dstPoint);
63}
64
robertphillips2334fb62015-06-17 05:43:33 -070065GrTextContext* GrDrawContext::createTextContext(GrRenderTarget* renderTarget,
robertphillipsfcf78292015-06-19 11:49:52 -070066 const SkSurfaceProps& surfaceProps) {
robertphillips2334fb62015-06-17 05:43:33 -070067 if (fContext->caps()->shaderCaps()->pathRenderingSupport() &&
cdaltone04edd82015-06-29 14:15:19 -070068 renderTarget->isStencilBufferMultisampled() &&
69 fSurfaceProps.isUseDistanceFieldFonts()) { // FIXME: Rename the dff flag to be more general.
robertphillips2334fb62015-06-17 05:43:33 -070070 GrStencilAttachment* sb = renderTarget->renderTargetPriv().attachStencilAttachment();
71 if (sb) {
robertphillipsfcf78292015-06-19 11:49:52 -070072 return GrStencilAndCoverTextContext::Create(fContext, this, surfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -070073 }
74 }
75
robertphillipsfcf78292015-06-19 11:49:52 -070076 return GrAtlasTextContext::Create(fContext, this, surfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -070077}
78
79void GrDrawContext::drawText(GrRenderTarget* rt, const GrClip& clip, const GrPaint& grPaint,
80 const SkPaint& skPaint,
81 const SkMatrix& viewMatrix,
82 const char text[], size_t byteLength,
83 SkScalar x, SkScalar y, const SkIRect& clipBounds) {
84 if (!fTextContext) {
robertphillipsfcf78292015-06-19 11:49:52 -070085 fTextContext = this->createTextContext(rt, fSurfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -070086 }
87
88 fTextContext->drawText(rt, clip, grPaint, skPaint, viewMatrix,
89 text, byteLength, x, y, clipBounds);
90
91}
92void GrDrawContext::drawPosText(GrRenderTarget* rt, const GrClip& clip, const GrPaint& grPaint,
93 const SkPaint& skPaint,
94 const SkMatrix& viewMatrix,
95 const char text[], size_t byteLength,
96 const SkScalar pos[], int scalarsPerPosition,
97 const SkPoint& offset, const SkIRect& clipBounds) {
98 if (!fTextContext) {
robertphillipsfcf78292015-06-19 11:49:52 -070099 fTextContext = this->createTextContext(rt, fSurfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -0700100 }
101
102 fTextContext->drawPosText(rt, clip, grPaint, skPaint, viewMatrix, text, byteLength,
103 pos, scalarsPerPosition, offset, clipBounds);
104
105}
106void GrDrawContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, const SkPaint& skPaint,
107 const SkMatrix& viewMatrix, const SkTextBlob* blob,
108 SkScalar x, SkScalar y,
109 SkDrawFilter* filter, const SkIRect& clipBounds) {
110 if (!fTextContext) {
robertphillipsfcf78292015-06-19 11:49:52 -0700111 fTextContext = this->createTextContext(rt, fSurfaceProps);
robertphillips2334fb62015-06-17 05:43:33 -0700112 }
113
114 fTextContext->drawTextBlob(rt, clip, skPaint, viewMatrix, blob, x, y, filter, clipBounds);
robertphillipsea461502015-05-26 11:38:03 -0700115}
116
117void GrDrawContext::drawPaths(GrPipelineBuilder* pipelineBuilder,
118 const GrPathProcessor* pathProc,
119 const GrPathRange* pathRange,
120 const void* indices,
121 int /*GrDrawTarget::PathIndexType*/ indexType,
122 const float transformValues[],
123 int /*GrDrawTarget::PathTransformType*/ transformType,
124 int count,
125 int /*GrPathRendering::FillType*/ fill) {
joshualitt1c735482015-07-13 08:08:25 -0700126 fDrawTarget->drawPaths(*pipelineBuilder, pathProc, pathRange,
robertphillipsea461502015-05-26 11:38:03 -0700127 indices, (GrDrawTarget::PathIndexType) indexType,
128 transformValues,
129 (GrDrawTarget::PathTransformType) transformType,
130 count, (GrPathRendering::FillType) fill);
131}
132
133void GrDrawContext::discard(GrRenderTarget* renderTarget) {
134 RETURN_IF_ABANDONED
135 SkASSERT(renderTarget);
136 AutoCheckFlush acf(fContext);
137 if (!this->prepareToDraw(renderTarget)) {
138 return;
139 }
140 fDrawTarget->discard(renderTarget);
141}
142
143void GrDrawContext::clear(GrRenderTarget* renderTarget,
144 const SkIRect* rect,
145 const GrColor color,
146 bool canIgnoreRect) {
147 RETURN_IF_ABANDONED
148 SkASSERT(renderTarget);
149
150 AutoCheckFlush acf(fContext);
151 if (!this->prepareToDraw(renderTarget)) {
152 return;
153 }
154 fDrawTarget->clear(rect, color, canIgnoreRect, renderTarget);
155}
156
157
158void GrDrawContext::drawPaint(GrRenderTarget* rt,
159 const GrClip& clip,
160 const GrPaint& origPaint,
161 const SkMatrix& viewMatrix) {
162 RETURN_IF_ABANDONED
163 // set rect to be big enough to fill the space, but not super-huge, so we
164 // don't overflow fixed-point implementations
165 SkRect r;
166 r.setLTRB(0, 0,
167 SkIntToScalar(rt->width()),
168 SkIntToScalar(rt->height()));
169 SkTCopyOnFirstWrite<GrPaint> paint(origPaint);
170
171 // by definition this fills the entire clip, no need for AA
172 if (paint->isAntiAlias()) {
173 paint.writable()->setAntiAlias(false);
174 }
175
176 bool isPerspective = viewMatrix.hasPerspective();
177
178 // We attempt to map r by the inverse matrix and draw that. mapRect will
179 // map the four corners and bound them with a new rect. This will not
180 // produce a correct result for some perspective matrices.
181 if (!isPerspective) {
182 SkMatrix inverse;
183 if (!viewMatrix.invert(&inverse)) {
184 SkDebugf("Could not invert matrix\n");
185 return;
186 }
187 inverse.mapRect(&r);
188 this->drawRect(rt, clip, *paint, viewMatrix, r);
189 } else {
190 SkMatrix localMatrix;
191 if (!viewMatrix.invert(&localMatrix)) {
192 SkDebugf("Could not invert matrix\n");
193 return;
194 }
195
196 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700197 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700198 return;
199 }
200
joshualitt7b670db2015-07-09 13:25:02 -0700201 GrPipelineBuilder pipelineBuilder(*paint, rt, clip);
joshualitt1c735482015-07-13 08:08:25 -0700202 fDrawTarget->drawBWRect(pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700203 paint->getColor(),
204 SkMatrix::I(),
205 r,
206 NULL,
207 &localMatrix);
208 }
209}
210
211static inline bool is_irect(const SkRect& r) {
212 return SkScalarIsInt(r.fLeft) && SkScalarIsInt(r.fTop) &&
213 SkScalarIsInt(r.fRight) && SkScalarIsInt(r.fBottom);
214}
215
216static bool apply_aa_to_rect(GrDrawTarget* target,
217 GrPipelineBuilder* pipelineBuilder,
218 SkRect* devBoundRect,
219 const SkRect& rect,
220 SkScalar strokeWidth,
221 const SkMatrix& combinedMatrix,
222 GrColor color) {
robertphillipsd8aa59d2015-08-05 09:07:12 -0700223 if (pipelineBuilder->getRenderTarget()->isUnifiedMultisampled() ||
224 !combinedMatrix.preservesAxisAlignment()) {
robertphillipsea461502015-05-26 11:38:03 -0700225 return false;
226 }
227
robertphillipsea461502015-05-26 11:38:03 -0700228 combinedMatrix.mapRect(devBoundRect, rect);
229 if (!combinedMatrix.rectStaysRect()) {
230 return true;
231 }
232
233 if (strokeWidth < 0) {
234 return !is_irect(*devBoundRect);
235 }
236
237 return true;
238}
239
240static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) {
241 return point.fX >= rect.fLeft && point.fX <= rect.fRight &&
242 point.fY >= rect.fTop && point.fY <= rect.fBottom;
243}
244
robertphillipsea461502015-05-26 11:38:03 -0700245void GrDrawContext::drawRect(GrRenderTarget* rt,
246 const GrClip& clip,
247 const GrPaint& paint,
248 const SkMatrix& viewMatrix,
249 const SkRect& rect,
250 const GrStrokeInfo* strokeInfo) {
251 RETURN_IF_ABANDONED
252 if (strokeInfo && strokeInfo->isDashed()) {
253 SkPath path;
254 path.setIsVolatile(true);
255 path.addRect(rect);
256 this->drawPath(rt, clip, paint, viewMatrix, path, *strokeInfo);
257 return;
258 }
259
260 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700261 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700262 return;
263 }
264
joshualitt7b670db2015-07-09 13:25:02 -0700265 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
266
robertphillipsea461502015-05-26 11:38:03 -0700267 SkScalar width = NULL == strokeInfo ? -1 : strokeInfo->getWidth();
268
269 // Check if this is a full RT draw and can be replaced with a clear. We don't bother checking
270 // cases where the RT is fully inside a stroke.
271 if (width < 0) {
272 SkRect rtRect;
273 pipelineBuilder.getRenderTarget()->getBoundsRect(&rtRect);
274 SkRect clipSpaceRTRect = rtRect;
275 bool checkClip = GrClip::kWideOpen_ClipType != clip.clipType();
276 if (checkClip) {
277 clipSpaceRTRect.offset(SkIntToScalar(clip.origin().fX),
278 SkIntToScalar(clip.origin().fY));
279 }
280 // Does the clip contain the entire RT?
281 if (!checkClip || clip.quickContains(clipSpaceRTRect)) {
282 SkMatrix invM;
283 if (!viewMatrix.invert(&invM)) {
284 return;
285 }
286 // Does the rect bound the RT?
287 SkPoint srcSpaceRTQuad[4];
288 invM.mapRectToQuad(srcSpaceRTQuad, rtRect);
289 if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) &&
290 rect_contains_inclusive(rect, srcSpaceRTQuad[1]) &&
291 rect_contains_inclusive(rect, srcSpaceRTQuad[2]) &&
292 rect_contains_inclusive(rect, srcSpaceRTQuad[3])) {
293 // Will it blend?
294 GrColor clearColor;
cdalton1fa45722015-06-02 10:43:39 -0700295 if (paint.isConstantBlendedColor(&clearColor)) {
robertphillipsea461502015-05-26 11:38:03 -0700296 fDrawTarget->clear(NULL, clearColor, true, rt);
297 return;
298 }
299 }
300 }
301 }
302
303 GrColor color = paint.getColor();
304 SkRect devBoundRect;
vbuzinovdded6962015-06-12 08:59:45 -0700305 bool needAA = paint.isAntiAlias() &&
306 !pipelineBuilder.getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -0700307 bool doAA = needAA && apply_aa_to_rect(fDrawTarget, &pipelineBuilder, &devBoundRect, rect,
308 width, viewMatrix, color);
309
310 if (doAA) {
311 if (width >= 0) {
312 GrAARectRenderer::StrokeAARect(fDrawTarget,
joshualitt1c735482015-07-13 08:08:25 -0700313 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700314 color,
315 viewMatrix,
316 rect,
317 devBoundRect,
318 *strokeInfo);
319 } else {
320 // filled AA rect
321 GrAARectRenderer::FillAARect(fDrawTarget,
joshualitt1c735482015-07-13 08:08:25 -0700322 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700323 color,
324 viewMatrix,
325 rect,
326 devBoundRect);
327 }
328 return;
329 }
330
331 if (width >= 0) {
bsalomonee14a622015-08-05 10:34:05 -0700332 GrStrokeRectBatch::Geometry geometry;
robertphillipsea461502015-05-26 11:38:03 -0700333 geometry.fViewMatrix = viewMatrix;
334 geometry.fColor = color;
335 geometry.fRect = rect;
336 geometry.fStrokeWidth = width;
337
338 // Non-AA hairlines are snapped to pixel centers to make which pixels are hit deterministic
vbuzinovdded6962015-06-12 08:59:45 -0700339 bool snapToPixelCenters = (0 == width && !rt->isUnifiedMultisampled());
bsalomonee14a622015-08-05 10:34:05 -0700340 SkAutoTUnref<GrBatch> batch(GrStrokeRectBatch::Create(geometry, snapToPixelCenters));
robertphillipsea461502015-05-26 11:38:03 -0700341
342 // Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of
343 // hairline rects. We jam all the vertices to pixel centers to avoid this, but not when MSAA
344 // is enabled because it can cause ugly artifacts.
345 pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_Flag,
346 snapToPixelCenters);
joshualitt1c735482015-07-13 08:08:25 -0700347 fDrawTarget->drawBatch(pipelineBuilder, batch);
robertphillipsea461502015-05-26 11:38:03 -0700348 } else {
349 // filled BW rect
joshualitt1c735482015-07-13 08:08:25 -0700350 fDrawTarget->drawSimpleRect(pipelineBuilder, color, viewMatrix, rect);
robertphillipsea461502015-05-26 11:38:03 -0700351 }
352}
353
354void GrDrawContext::drawNonAARectToRect(GrRenderTarget* rt,
355 const GrClip& clip,
356 const GrPaint& paint,
357 const SkMatrix& viewMatrix,
358 const SkRect& rectToDraw,
359 const SkRect& localRect,
360 const SkMatrix* localMatrix) {
361 RETURN_IF_ABANDONED
362 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700363 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700364 return;
365 }
366
joshualitt7b670db2015-07-09 13:25:02 -0700367 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
joshualitt1c735482015-07-13 08:08:25 -0700368 fDrawTarget->drawBWRect(pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700369 paint.getColor(),
370 viewMatrix,
371 rectToDraw,
372 &localRect,
373 localMatrix);
374}
375
376static const GrGeometryProcessor* set_vertex_attributes(bool hasLocalCoords,
377 bool hasColors,
378 int* colorOffset,
379 int* texOffset,
380 GrColor color,
381 const SkMatrix& viewMatrix,
382 bool coverageIgnored) {
joshualittdf0c5572015-08-03 11:35:28 -0700383 using namespace GrDefaultGeoProcFactory;
robertphillipsea461502015-05-26 11:38:03 -0700384 *texOffset = -1;
385 *colorOffset = -1;
joshualittdf0c5572015-08-03 11:35:28 -0700386 Color gpColor(color);
387 if (hasColors) {
388 gpColor.fType = Color::kAttribute_Type;
389 }
390
391 Coverage coverage(coverageIgnored ? Coverage::kNone_Type : Coverage::kSolid_Type);
392 LocalCoords localCoords(hasLocalCoords ? LocalCoords::kHasExplicit_Type :
393 LocalCoords::kUsePosition_Type);
robertphillipsea461502015-05-26 11:38:03 -0700394 if (hasLocalCoords && hasColors) {
395 *colorOffset = sizeof(SkPoint);
396 *texOffset = sizeof(SkPoint) + sizeof(GrColor);
robertphillipsea461502015-05-26 11:38:03 -0700397 } else if (hasLocalCoords) {
398 *texOffset = sizeof(SkPoint);
robertphillipsea461502015-05-26 11:38:03 -0700399 } else if (hasColors) {
400 *colorOffset = sizeof(SkPoint);
robertphillipsea461502015-05-26 11:38:03 -0700401 }
joshualittdf0c5572015-08-03 11:35:28 -0700402 return GrDefaultGeoProcFactory::Create(gpColor, coverage, localCoords, viewMatrix);
robertphillipsea461502015-05-26 11:38:03 -0700403}
404
405class DrawVerticesBatch : public GrBatch {
406public:
407 struct Geometry {
408 GrColor fColor;
409 SkTDArray<SkPoint> fPositions;
410 SkTDArray<uint16_t> fIndices;
411 SkTDArray<GrColor> fColors;
412 SkTDArray<SkPoint> fLocalCoords;
413 };
414
415 static GrBatch* Create(const Geometry& geometry, GrPrimitiveType primitiveType,
416 const SkMatrix& viewMatrix,
417 const SkPoint* positions, int vertexCount,
418 const uint16_t* indices, int indexCount,
419 const GrColor* colors, const SkPoint* localCoords,
420 const SkRect& bounds) {
421 return SkNEW_ARGS(DrawVerticesBatch, (geometry, primitiveType, viewMatrix, positions,
422 vertexCount, indices, indexCount, colors,
423 localCoords, bounds));
424 }
425
426 const char* name() const override { return "DrawVerticesBatch"; }
427
428 void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
429 // When this is called on a batch, there is only one geometry bundle
430 if (this->hasColors()) {
431 out->setUnknownFourComponents();
432 } else {
433 out->setKnownFourComponents(fGeoData[0].fColor);
434 }
435 }
436
437 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
438 out->setKnownSingleComponent(0xff);
439 }
440
441 void initBatchTracker(const GrPipelineInfo& init) override {
442 // Handle any color overrides
bsalomon7765a472015-07-08 11:26:37 -0700443 if (!init.readsColor()) {
robertphillipsea461502015-05-26 11:38:03 -0700444 fGeoData[0].fColor = GrColor_ILLEGAL;
robertphillipsea461502015-05-26 11:38:03 -0700445 }
bsalomon7765a472015-07-08 11:26:37 -0700446 init.getOverrideColorIfSet(&fGeoData[0].fColor);
robertphillipsea461502015-05-26 11:38:03 -0700447
448 // setup batch properties
bsalomon7765a472015-07-08 11:26:37 -0700449 fBatch.fColorIgnored = !init.readsColor();
robertphillipsea461502015-05-26 11:38:03 -0700450 fBatch.fColor = fGeoData[0].fColor;
bsalomon7765a472015-07-08 11:26:37 -0700451 fBatch.fUsesLocalCoords = init.readsLocalCoords();
452 fBatch.fCoverageIgnored = !init.readsCoverage();
robertphillipsea461502015-05-26 11:38:03 -0700453 }
454
bsalomonfb1141a2015-08-06 08:52:49 -0700455 void generateGeometry(GrBatchTarget* batchTarget) override {
robertphillipsea461502015-05-26 11:38:03 -0700456 int colorOffset = -1, texOffset = -1;
457 SkAutoTUnref<const GrGeometryProcessor> gp(
458 set_vertex_attributes(this->hasLocalCoords(), this->hasColors(), &colorOffset,
459 &texOffset, this->color(), this->viewMatrix(),
460 this->coverageIgnored()));
461
bsalomonfb1141a2015-08-06 08:52:49 -0700462 batchTarget->initDraw(gp, this->pipeline());
robertphillipsea461502015-05-26 11:38:03 -0700463
464 size_t vertexStride = gp->getVertexStride();
465
466 SkASSERT(vertexStride == sizeof(SkPoint) + (this->hasLocalCoords() ? sizeof(SkPoint) : 0)
467 + (this->hasColors() ? sizeof(GrColor) : 0));
468
469 int instanceCount = fGeoData.count();
470
471 const GrVertexBuffer* vertexBuffer;
472 int firstVertex;
473
474 void* verts = batchTarget->makeVertSpace(vertexStride, this->vertexCount(),
475 &vertexBuffer, &firstVertex);
476
477 if (!verts) {
478 SkDebugf("Could not allocate vertices\n");
479 return;
480 }
481
482 const GrIndexBuffer* indexBuffer = NULL;
483 int firstIndex = 0;
484
485 uint16_t* indices = NULL;
486 if (this->hasIndices()) {
487 indices = batchTarget->makeIndexSpace(this->indexCount(), &indexBuffer, &firstIndex);
488
489 if (!indices) {
490 SkDebugf("Could not allocate indices\n");
491 return;
492 }
493 }
494
495 int indexOffset = 0;
496 int vertexOffset = 0;
497 for (int i = 0; i < instanceCount; i++) {
498 const Geometry& args = fGeoData[i];
499
500 // TODO we can actually cache this interleaved and then just memcopy
501 if (this->hasIndices()) {
502 for (int j = 0; j < args.fIndices.count(); ++j, ++indexOffset) {
503 *(indices + indexOffset) = args.fIndices[j] + vertexOffset;
504 }
505 }
506
507 for (int j = 0; j < args.fPositions.count(); ++j) {
508 *((SkPoint*)verts) = args.fPositions[j];
509 if (this->hasColors()) {
510 *(GrColor*)((intptr_t)verts + colorOffset) = args.fColors[j];
511 }
512 if (this->hasLocalCoords()) {
513 *(SkPoint*)((intptr_t)verts + texOffset) = args.fLocalCoords[j];
514 }
515 verts = (void*)((intptr_t)verts + vertexStride);
516 vertexOffset++;
517 }
518 }
519
520 GrVertices vertices;
521 if (this->hasIndices()) {
522 vertices.initIndexed(this->primitiveType(), vertexBuffer, indexBuffer, firstVertex,
523 firstIndex, this->vertexCount(), this->indexCount());
524
525 } else {
526 vertices.init(this->primitiveType(), vertexBuffer, firstVertex, this->vertexCount());
527 }
528 batchTarget->draw(vertices);
529 }
530
531 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
532
533private:
534 DrawVerticesBatch(const Geometry& geometry, GrPrimitiveType primitiveType,
535 const SkMatrix& viewMatrix,
536 const SkPoint* positions, int vertexCount,
537 const uint16_t* indices, int indexCount,
538 const GrColor* colors, const SkPoint* localCoords, const SkRect& bounds) {
539 this->initClassID<DrawVerticesBatch>();
540 SkASSERT(positions);
541
542 fBatch.fViewMatrix = viewMatrix;
543 Geometry& installedGeo = fGeoData.push_back(geometry);
544
545 installedGeo.fPositions.append(vertexCount, positions);
546 if (indices) {
547 installedGeo.fIndices.append(indexCount, indices);
548 fBatch.fHasIndices = true;
549 } else {
550 fBatch.fHasIndices = false;
551 }
552
553 if (colors) {
554 installedGeo.fColors.append(vertexCount, colors);
555 fBatch.fHasColors = true;
556 } else {
557 fBatch.fHasColors = false;
558 }
559
560 if (localCoords) {
561 installedGeo.fLocalCoords.append(vertexCount, localCoords);
562 fBatch.fHasLocalCoords = true;
563 } else {
564 fBatch.fHasLocalCoords = false;
565 }
566 fBatch.fVertexCount = vertexCount;
567 fBatch.fIndexCount = indexCount;
568 fBatch.fPrimitiveType = primitiveType;
569
570 this->setBounds(bounds);
571 }
572
573 GrPrimitiveType primitiveType() const { return fBatch.fPrimitiveType; }
574 bool batchablePrimitiveType() const {
575 return kTriangles_GrPrimitiveType == fBatch.fPrimitiveType ||
576 kLines_GrPrimitiveType == fBatch.fPrimitiveType ||
577 kPoints_GrPrimitiveType == fBatch.fPrimitiveType;
578 }
579 GrColor color() const { return fBatch.fColor; }
580 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
581 bool colorIgnored() const { return fBatch.fColorIgnored; }
582 const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
583 bool hasColors() const { return fBatch.fHasColors; }
584 bool hasIndices() const { return fBatch.fHasIndices; }
585 bool hasLocalCoords() const { return fBatch.fHasLocalCoords; }
586 int vertexCount() const { return fBatch.fVertexCount; }
587 int indexCount() const { return fBatch.fIndexCount; }
588 bool coverageIgnored() const { return fBatch.fCoverageIgnored; }
589
590 bool onCombineIfPossible(GrBatch* t) override {
joshualitt8cab9a72015-07-16 09:13:50 -0700591 if (!this->pipeline()->isEqual(*t->pipeline())) {
592 return false;
593 }
594
robertphillipsea461502015-05-26 11:38:03 -0700595 DrawVerticesBatch* that = t->cast<DrawVerticesBatch>();
596
597 if (!this->batchablePrimitiveType() || this->primitiveType() != that->primitiveType()) {
598 return false;
599 }
600
601 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
602
603 // We currently use a uniform viewmatrix for this batch
604 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
605 return false;
606 }
607
608 if (this->hasColors() != that->hasColors()) {
609 return false;
610 }
611
612 if (this->hasIndices() != that->hasIndices()) {
613 return false;
614 }
615
616 if (this->hasLocalCoords() != that->hasLocalCoords()) {
617 return false;
618 }
619
620 if (!this->hasColors() && this->color() != that->color()) {
621 return false;
622 }
623
624 if (this->color() != that->color()) {
625 fBatch.fColor = GrColor_ILLEGAL;
626 }
627 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
628 fBatch.fVertexCount += that->vertexCount();
629 fBatch.fIndexCount += that->indexCount();
630
631 this->joinBounds(that->bounds());
632 return true;
633 }
634
635 struct BatchTracker {
636 GrPrimitiveType fPrimitiveType;
637 SkMatrix fViewMatrix;
638 GrColor fColor;
639 bool fUsesLocalCoords;
640 bool fColorIgnored;
641 bool fCoverageIgnored;
642 bool fHasColors;
643 bool fHasIndices;
644 bool fHasLocalCoords;
645 int fVertexCount;
646 int fIndexCount;
647 };
648
649 BatchTracker fBatch;
650 SkSTArray<1, Geometry, true> fGeoData;
651};
652
653void GrDrawContext::drawVertices(GrRenderTarget* rt,
654 const GrClip& clip,
655 const GrPaint& paint,
656 const SkMatrix& viewMatrix,
657 GrPrimitiveType primitiveType,
658 int vertexCount,
659 const SkPoint positions[],
660 const SkPoint texCoords[],
661 const GrColor colors[],
662 const uint16_t indices[],
663 int indexCount) {
664 RETURN_IF_ABANDONED
665 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700666 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700667 return;
668 }
669
joshualitt7b670db2015-07-09 13:25:02 -0700670 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
671
robertphillipsea461502015-05-26 11:38:03 -0700672 // TODO clients should give us bounds
673 SkRect bounds;
674 if (!bounds.setBoundsCheck(positions, vertexCount)) {
675 SkDebugf("drawVertices call empty bounds\n");
676 return;
677 }
678
679 viewMatrix.mapRect(&bounds);
680
681 // If we don't have AA then we outset for a half pixel in each direction to account for
682 // snapping
683 if (!paint.isAntiAlias()) {
684 bounds.outset(0.5f, 0.5f);
685 }
686
687 DrawVerticesBatch::Geometry geometry;
688 geometry.fColor = paint.getColor();
689 SkAutoTUnref<GrBatch> batch(DrawVerticesBatch::Create(geometry, primitiveType, viewMatrix,
690 positions, vertexCount, indices,
691 indexCount, colors, texCoords,
692 bounds));
693
joshualitt1c735482015-07-13 08:08:25 -0700694 fDrawTarget->drawBatch(pipelineBuilder, batch);
robertphillipsea461502015-05-26 11:38:03 -0700695}
696
697///////////////////////////////////////////////////////////////////////////////
698
jvanverth31ff7622015-08-07 10:09:28 -0700699void GrDrawContext::drawAtlas(GrRenderTarget* rt,
700 const GrClip& clip,
701 const GrPaint& paint,
702 const SkMatrix& viewMatrix,
703 int spriteCount,
704 const SkRSXform xform[],
705 const SkRect texRect[],
706 const SkColor colors[]) {
707 RETURN_IF_ABANDONED
708 AutoCheckFlush acf(fContext);
709 if (!this->prepareToDraw(rt)) {
710 return;
711 }
712
713 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
714
715 // now build the renderable geometry
716 const int vertCount = spriteCount * 4;
717 SkAutoTMalloc<SkPoint> vertStorage(vertCount * 2);
718 SkPoint* verts = vertStorage.get();
719 SkPoint* texs = verts + vertCount;
720
721 for (int i = 0; i < spriteCount; ++i) {
722 xform[i].toQuad(texRect[i].width(), texRect[i].height(), verts);
723 texRect[i].toQuad(texs);
724 verts += 4;
725 texs += 4;
726 }
727
728 // TODO clients should give us bounds
729 SkRect bounds;
730 if (!bounds.setBoundsCheck(vertStorage.get(), vertCount)) {
731 SkDebugf("drawAtlas call empty bounds\n");
732 return;
733 }
734
735 viewMatrix.mapRect(&bounds);
736
737 // If we don't have AA then we outset for a half pixel in each direction to account for
738 // snapping
739 if (!paint.isAntiAlias()) {
740 bounds.outset(0.5f, 0.5f);
741 }
742
743 SkAutoTMalloc<GrColor> colorStorage;
744 GrColor* vertCols = NULL;
745 if (colors) {
746 colorStorage.reset(vertCount);
747 vertCols = colorStorage.get();
748
749 int paintAlpha = GrColorUnpackA(paint.getColor());
750
751 // need to convert byte order and from non-PM to PM
752 for (int i = 0; i < spriteCount; ++i) {
753 SkColor color = colors[i];
754 if (paintAlpha != 255) {
755 color = SkColorSetA(color, SkMulDiv255Round(SkColorGetA(color), paintAlpha));
756 }
757 GrColor grColor = SkColor2GrColor(color);
758
759 vertCols[0] = vertCols[1] = vertCols[2] = vertCols[3] = grColor;
760 vertCols += 4;
761 }
762 }
763
764 verts = vertStorage.get();
765 texs = verts + vertCount;
766 vertCols = colorStorage.get();
767
jvanverth14b88032015-08-07 12:18:54 -0700768 GrDrawAtlasBatch::Geometry geometry;
jvanverth31ff7622015-08-07 10:09:28 -0700769 geometry.fColor = paint.getColor();
jvanverth14b88032015-08-07 12:18:54 -0700770 SkAutoTUnref<GrBatch> batch(GrDrawAtlasBatch::Create(geometry, viewMatrix, verts, vertCount,
771 vertCols, texs, bounds));
jvanverth31ff7622015-08-07 10:09:28 -0700772
773 fDrawTarget->drawBatch(pipelineBuilder, batch);
774}
775
776///////////////////////////////////////////////////////////////////////////////
777
robertphillipsea461502015-05-26 11:38:03 -0700778void GrDrawContext::drawRRect(GrRenderTarget*rt,
779 const GrClip& clip,
780 const GrPaint& paint,
781 const SkMatrix& viewMatrix,
782 const SkRRect& rrect,
783 const GrStrokeInfo& strokeInfo) {
784 RETURN_IF_ABANDONED
785 if (rrect.isEmpty()) {
786 return;
787 }
788
789 if (strokeInfo.isDashed()) {
790 SkPath path;
791 path.setIsVolatile(true);
792 path.addRRect(rrect);
793 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
794 return;
795 }
796
797 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700798 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700799 return;
800 }
801
joshualitt7b670db2015-07-09 13:25:02 -0700802 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700803 GrColor color = paint.getColor();
804 if (!GrOvalRenderer::DrawRRect(fDrawTarget,
joshualittae3d63a2015-07-13 08:44:06 -0700805 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700806 color,
807 viewMatrix,
808 paint.isAntiAlias(),
809 rrect,
810 strokeInfo)) {
811 SkPath path;
812 path.setIsVolatile(true);
813 path.addRRect(rrect);
814 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
815 paint.isAntiAlias(), path, strokeInfo);
816 }
817}
818
819///////////////////////////////////////////////////////////////////////////////
820
821void GrDrawContext::drawDRRect(GrRenderTarget* rt,
822 const GrClip& clip,
823 const GrPaint& paint,
824 const SkMatrix& viewMatrix,
825 const SkRRect& outer,
826 const SkRRect& inner) {
827 RETURN_IF_ABANDONED
828 if (outer.isEmpty()) {
829 return;
830 }
831
832 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700833 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700834 return;
835 }
836
joshualitt7b670db2015-07-09 13:25:02 -0700837 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700838 GrColor color = paint.getColor();
839 if (!GrOvalRenderer::DrawDRRect(fDrawTarget,
joshualittae3d63a2015-07-13 08:44:06 -0700840 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700841 color,
842 viewMatrix,
843 paint.isAntiAlias(),
844 outer,
845 inner)) {
846 SkPath path;
847 path.setIsVolatile(true);
848 path.addRRect(inner);
849 path.addRRect(outer);
850 path.setFillType(SkPath::kEvenOdd_FillType);
851
852 GrStrokeInfo fillRec(SkStrokeRec::kFill_InitStyle);
853 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
854 paint.isAntiAlias(), path, fillRec);
855 }
856}
857
858///////////////////////////////////////////////////////////////////////////////
859
860void GrDrawContext::drawOval(GrRenderTarget* rt,
861 const GrClip& clip,
862 const GrPaint& paint,
863 const SkMatrix& viewMatrix,
864 const SkRect& oval,
865 const GrStrokeInfo& strokeInfo) {
866 RETURN_IF_ABANDONED
867 if (oval.isEmpty()) {
868 return;
869 }
870
871 if (strokeInfo.isDashed()) {
872 SkPath path;
873 path.setIsVolatile(true);
874 path.addOval(oval);
875 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
876 return;
877 }
878
879 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700880 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700881 return;
882 }
883
joshualitt7b670db2015-07-09 13:25:02 -0700884 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700885 GrColor color = paint.getColor();
886 if (!GrOvalRenderer::DrawOval(fDrawTarget,
joshualittae3d63a2015-07-13 08:44:06 -0700887 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700888 color,
889 viewMatrix,
890 paint.isAntiAlias(),
891 oval,
892 strokeInfo)) {
893 SkPath path;
894 path.setIsVolatile(true);
895 path.addOval(oval);
896 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color,
897 paint.isAntiAlias(), path, strokeInfo);
898 }
899}
900
901// Can 'path' be drawn as a pair of filled nested rectangles?
joshualittf9c5db22015-07-10 11:31:01 -0700902static bool is_nested_rects(const SkMatrix& viewMatrix,
robertphillipsea461502015-05-26 11:38:03 -0700903 const SkPath& path,
904 const SkStrokeRec& stroke,
905 SkRect rects[2]) {
906 SkASSERT(stroke.isFillStyle());
907
908 if (path.isInverseFillType()) {
909 return false;
910 }
911
912 // TODO: this restriction could be lifted if we were willing to apply
913 // the matrix to all the points individually rather than just to the rect
914 if (!viewMatrix.preservesAxisAlignment()) {
915 return false;
916 }
917
918 SkPath::Direction dirs[2];
919 if (!path.isNestedFillRects(rects, dirs)) {
920 return false;
921 }
922
923 if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) {
924 // The two rects need to be wound opposite to each other
925 return false;
926 }
927
928 // Right now, nested rects where the margin is not the same width
929 // all around do not render correctly
930 const SkScalar* outer = rects[0].asScalars();
931 const SkScalar* inner = rects[1].asScalars();
932
933 bool allEq = true;
934
935 SkScalar margin = SkScalarAbs(outer[0] - inner[0]);
936 bool allGoE1 = margin >= SK_Scalar1;
937
938 for (int i = 1; i < 4; ++i) {
939 SkScalar temp = SkScalarAbs(outer[i] - inner[i]);
940 if (temp < SK_Scalar1) {
941 allGoE1 = false;
942 }
943 if (!SkScalarNearlyEqual(margin, temp)) {
944 allEq = false;
945 }
946 }
947
948 return allEq || allGoE1;
949}
950
951void GrDrawContext::drawPath(GrRenderTarget* rt,
952 const GrClip& clip,
953 const GrPaint& paint,
954 const SkMatrix& viewMatrix,
955 const SkPath& path,
956 const GrStrokeInfo& strokeInfo) {
957 RETURN_IF_ABANDONED
958 if (path.isEmpty()) {
959 if (path.isInverseFillType()) {
960 this->drawPaint(rt, clip, paint, viewMatrix);
961 }
962 return;
963 }
964
965 GrColor color = paint.getColor();
966
967 // Note that internalDrawPath may sw-rasterize the path into a scratch texture.
968 // Scratch textures can be recycled after they are returned to the texture
969 // cache. This presents a potential hazard for buffered drawing. However,
970 // the writePixels that uploads to the scratch will perform a flush so we're
971 // OK.
972 AutoCheckFlush acf(fContext);
joshualitt7b670db2015-07-09 13:25:02 -0700973 if (!this->prepareToDraw(rt)) {
robertphillipsea461502015-05-26 11:38:03 -0700974 return;
975 }
976
joshualitt7b670db2015-07-09 13:25:02 -0700977 GrPipelineBuilder pipelineBuilder(paint, rt, clip);
robertphillipsea461502015-05-26 11:38:03 -0700978 if (!strokeInfo.isDashed()) {
979 bool useCoverageAA = paint.isAntiAlias() &&
vbuzinovdded6962015-06-12 08:59:45 -0700980 !pipelineBuilder.getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -0700981
982 if (useCoverageAA && strokeInfo.getWidth() < 0 && !path.isConvex()) {
983 // Concave AA paths are expensive - try to avoid them for special cases
984 SkRect rects[2];
985
joshualittf9c5db22015-07-10 11:31:01 -0700986 if (is_nested_rects(viewMatrix, path, strokeInfo, rects)) {
joshualitt1c735482015-07-13 08:08:25 -0700987 GrAARectRenderer::FillAANestedRects(fDrawTarget, pipelineBuilder, color,
robertphillipsea461502015-05-26 11:38:03 -0700988 viewMatrix, rects);
989 return;
990 }
991 }
992 SkRect ovalRect;
993 bool isOval = path.isOval(&ovalRect);
994
995 if (isOval && !path.isInverseFillType()) {
996 if (GrOvalRenderer::DrawOval(fDrawTarget,
joshualittae3d63a2015-07-13 08:44:06 -0700997 pipelineBuilder,
robertphillipsea461502015-05-26 11:38:03 -0700998 color,
999 viewMatrix,
1000 paint.isAntiAlias(),
1001 ovalRect,
1002 strokeInfo)) {
1003 return;
1004 }
1005 }
1006 }
1007 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
1008 path, strokeInfo);
1009}
1010
1011void GrDrawContext::internalDrawPath(GrDrawTarget* target,
1012 GrPipelineBuilder* pipelineBuilder,
1013 const SkMatrix& viewMatrix,
1014 GrColor color,
1015 bool useAA,
1016 const SkPath& path,
1017 const GrStrokeInfo& strokeInfo) {
1018 RETURN_IF_ABANDONED
1019 SkASSERT(!path.isEmpty());
1020
1021
1022 // An Assumption here is that path renderer would use some form of tweaking
1023 // the src color (either the input alpha or in the frag shader) to implement
1024 // aa. If we have some future driver-mojo path AA that can do the right
1025 // thing WRT to the blend then we'll need some query on the PR.
1026 bool useCoverageAA = useAA &&
vbuzinovdded6962015-06-12 08:59:45 -07001027 !pipelineBuilder->getRenderTarget()->isUnifiedMultisampled();
robertphillipsea461502015-05-26 11:38:03 -07001028
1029
1030 GrPathRendererChain::DrawType type =
1031 useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType :
1032 GrPathRendererChain::kColor_DrawType;
1033
1034 const SkPath* pathPtr = &path;
1035 SkTLazy<SkPath> tmpPath;
1036 const GrStrokeInfo* strokeInfoPtr = &strokeInfo;
1037
1038 // Try a 1st time without stroking the path and without allowing the SW renderer
1039 GrPathRenderer* pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr,
1040 *strokeInfoPtr, false, type);
1041
1042 GrStrokeInfo dashlessStrokeInfo(strokeInfo, false);
1043 if (NULL == pr && strokeInfo.isDashed()) {
1044 // It didn't work above, so try again with dashed stroke converted to a dashless stroke.
1045 if (!strokeInfo.applyDashToPath(tmpPath.init(), &dashlessStrokeInfo, *pathPtr)) {
1046 return;
1047 }
1048 pathPtr = tmpPath.get();
1049 if (pathPtr->isEmpty()) {
1050 return;
1051 }
1052 strokeInfoPtr = &dashlessStrokeInfo;
1053 pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
1054 false, type);
1055 }
1056
1057 if (NULL == pr) {
1058 if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*strokeInfoPtr, viewMatrix, NULL) &&
1059 !strokeInfoPtr->isFillStyle()) {
1060 // It didn't work above, so try again with stroke converted to a fill.
1061 if (!tmpPath.isValid()) {
1062 tmpPath.init();
1063 }
1064 dashlessStrokeInfo.setResScale(SkScalarAbs(viewMatrix.getMaxScale()));
1065 if (!dashlessStrokeInfo.applyToPath(tmpPath.get(), *pathPtr)) {
1066 return;
1067 }
1068 pathPtr = tmpPath.get();
1069 if (pathPtr->isEmpty()) {
1070 return;
1071 }
1072 dashlessStrokeInfo.setFillStyle();
1073 strokeInfoPtr = &dashlessStrokeInfo;
1074 }
1075
1076 // This time, allow SW renderer
1077 pr = fContext->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
1078 true, type);
1079 }
1080
1081 if (NULL == pr) {
1082#ifdef SK_DEBUG
1083 SkDebugf("Unable to find path renderer compatible with path.\n");
1084#endif
1085 return;
1086 }
1087
bsalomon0aff2fa2015-07-31 06:48:27 -07001088 GrPathRenderer::DrawPathArgs args;
1089 args.fTarget = target;
1090 args.fResourceProvider = fContext->resourceProvider();
1091 args.fPipelineBuilder = pipelineBuilder;
1092 args.fColor = color;
1093 args.fViewMatrix = &viewMatrix;
1094 args.fPath = pathPtr;
1095 args.fStroke = strokeInfoPtr;
1096 args.fAntiAlias = useCoverageAA;
1097 pr->drawPath(args);
robertphillipsea461502015-05-26 11:38:03 -07001098}
1099
robertphillipsea461502015-05-26 11:38:03 -07001100bool GrDrawContext::prepareToDraw(GrRenderTarget* rt) {
1101 RETURN_FALSE_IF_ABANDONED
1102
1103 ASSERT_OWNED_RESOURCE(rt);
1104 SkASSERT(rt);
1105 return true;
1106}
1107
robertphillips2334fb62015-06-17 05:43:33 -07001108void GrDrawContext::drawBatch(GrPipelineBuilder* pipelineBuilder, GrBatch* batch) {
joshualitt1c735482015-07-13 08:08:25 -07001109 fDrawTarget->drawBatch(*pipelineBuilder, batch);
robertphillips2334fb62015-06-17 05:43:33 -07001110}
1111
robertphillipsea461502015-05-26 11:38:03 -07001112///////////////////////////////////////////////////////////////////////////////////////////////////
1113
1114#ifdef GR_TEST_UTILS
1115
robertphillipsea461502015-05-26 11:38:03 -07001116static uint32_t seed_vertices(GrPrimitiveType type) {
1117 switch (type) {
1118 case kTriangles_GrPrimitiveType:
1119 case kTriangleStrip_GrPrimitiveType:
1120 case kTriangleFan_GrPrimitiveType:
1121 return 3;
1122 case kPoints_GrPrimitiveType:
1123 return 1;
1124 case kLines_GrPrimitiveType:
1125 case kLineStrip_GrPrimitiveType:
1126 return 2;
1127 }
1128 SkFAIL("Incomplete switch\n");
1129 return 0;
1130}
1131
1132static uint32_t primitive_vertices(GrPrimitiveType type) {
1133 switch (type) {
1134 case kTriangles_GrPrimitiveType:
1135 return 3;
1136 case kLines_GrPrimitiveType:
1137 return 2;
1138 case kTriangleStrip_GrPrimitiveType:
1139 case kTriangleFan_GrPrimitiveType:
1140 case kPoints_GrPrimitiveType:
1141 case kLineStrip_GrPrimitiveType:
1142 return 1;
1143 }
1144 SkFAIL("Incomplete switch\n");
1145 return 0;
1146}
1147
1148static SkPoint random_point(SkRandom* random, SkScalar min, SkScalar max) {
1149 SkPoint p;
1150 p.fX = random->nextRangeScalar(min, max);
1151 p.fY = random->nextRangeScalar(min, max);
1152 return p;
1153}
1154
1155static void randomize_params(size_t count, size_t maxVertex, SkScalar min, SkScalar max,
1156 SkRandom* random,
1157 SkTArray<SkPoint>* positions,
1158 SkTArray<SkPoint>* texCoords, bool hasTexCoords,
1159 SkTArray<GrColor>* colors, bool hasColors,
1160 SkTArray<uint16_t>* indices, bool hasIndices) {
1161 for (uint32_t v = 0; v < count; v++) {
1162 positions->push_back(random_point(random, min, max));
1163 if (hasTexCoords) {
1164 texCoords->push_back(random_point(random, min, max));
1165 }
1166 if (hasColors) {
1167 colors->push_back(GrRandomColor(random));
1168 }
1169 if (hasIndices) {
1170 SkASSERT(maxVertex <= SK_MaxU16);
1171 indices->push_back(random->nextULessThan((uint16_t)maxVertex));
1172 }
1173 }
1174}
1175
1176BATCH_TEST_DEFINE(VerticesBatch) {
1177 GrPrimitiveType type = GrPrimitiveType(random->nextULessThan(kLast_GrPrimitiveType + 1));
1178 uint32_t primitiveCount = random->nextRangeU(1, 100);
1179
1180 // TODO make 'sensible' indexbuffers
1181 SkTArray<SkPoint> positions;
1182 SkTArray<SkPoint> texCoords;
1183 SkTArray<GrColor> colors;
1184 SkTArray<uint16_t> indices;
1185
1186 bool hasTexCoords = random->nextBool();
1187 bool hasIndices = random->nextBool();
1188 bool hasColors = random->nextBool();
1189
1190 uint32_t vertexCount = seed_vertices(type) + (primitiveCount - 1) * primitive_vertices(type);
1191
1192 static const SkScalar kMinVertExtent = -100.f;
1193 static const SkScalar kMaxVertExtent = 100.f;
1194 randomize_params(seed_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent,
1195 random,
1196 &positions,
1197 &texCoords, hasTexCoords,
1198 &colors, hasColors,
1199 &indices, hasIndices);
1200
1201 for (uint32_t i = 1; i < primitiveCount; i++) {
1202 randomize_params(primitive_vertices(type), vertexCount, kMinVertExtent, kMaxVertExtent,
1203 random,
1204 &positions,
1205 &texCoords, hasTexCoords,
1206 &colors, hasColors,
1207 &indices, hasIndices);
1208 }
1209
1210 SkMatrix viewMatrix = GrTest::TestMatrix(random);
1211 SkRect bounds;
1212 SkDEBUGCODE(bool result = ) bounds.setBoundsCheck(positions.begin(), vertexCount);
1213 SkASSERT(result);
1214
1215 viewMatrix.mapRect(&bounds);
1216
1217 DrawVerticesBatch::Geometry geometry;
1218 geometry.fColor = GrRandomColor(random);
1219 return DrawVerticesBatch::Create(geometry, type, viewMatrix,
1220 positions.begin(), vertexCount,
1221 indices.begin(), hasIndices ? vertexCount : 0,
1222 colors.begin(),
1223 texCoords.begin(),
1224 bounds);
1225}
1226
1227#endif
1228