OLD | NEW |
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2015 Google Inc. | 3 * Copyright 2015 Google Inc. |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 #include "GrAARectRenderer.h" | 9 #include "GrAARectRenderer.h" |
10 #include "GrAtlasTextContext.h" | 10 #include "GrAtlasTextContext.h" |
11 #include "GrBatch.h" | 11 #include "GrBatch.h" |
12 #include "GrBatchTest.h" | 12 #include "GrBatchTest.h" |
13 #include "GrDefaultGeoProcFactory.h" | 13 #include "GrDefaultGeoProcFactory.h" |
14 #include "GrDrawContext.h" | 14 #include "GrDrawContext.h" |
15 #include "GrOvalRenderer.h" | 15 #include "GrOvalRenderer.h" |
16 #include "GrPathRenderer.h" | 16 #include "GrPathRenderer.h" |
17 #include "GrRenderTarget.h" | 17 #include "GrRenderTarget.h" |
18 #include "GrRenderTargetPriv.h" | 18 #include "GrRenderTargetPriv.h" |
| 19 #include "GrStrokeRectBatch.h" |
19 #include "GrStencilAndCoverTextContext.h" | 20 #include "GrStencilAndCoverTextContext.h" |
20 | 21 |
21 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == fContext) | 22 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == fContext) |
22 #define RETURN_IF_ABANDONED if (!fDrawTarget) { return; } | 23 #define RETURN_IF_ABANDONED if (!fDrawTarget) { return; } |
23 #define RETURN_FALSE_IF_ABANDONED if (!fDrawTarget) { return false; } | 24 #define RETURN_FALSE_IF_ABANDONED if (!fDrawTarget) { return false; } |
24 #define RETURN_NULL_IF_ABANDONED if (!fDrawTarget) { return NULL; } | 25 #define RETURN_NULL_IF_ABANDONED if (!fDrawTarget) { return NULL; } |
25 | 26 |
26 class AutoCheckFlush { | 27 class AutoCheckFlush { |
27 public: | 28 public: |
28 AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context);
} | 29 AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context);
} |
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
242 } | 243 } |
243 | 244 |
244 return true; | 245 return true; |
245 } | 246 } |
246 | 247 |
247 static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& po
int) { | 248 static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& po
int) { |
248 return point.fX >= rect.fLeft && point.fX <= rect.fRight && | 249 return point.fX >= rect.fLeft && point.fX <= rect.fRight && |
249 point.fY >= rect.fTop && point.fY <= rect.fBottom; | 250 point.fY >= rect.fTop && point.fY <= rect.fBottom; |
250 } | 251 } |
251 | 252 |
252 class StrokeRectBatch : public GrBatch { | |
253 public: | |
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 | |
278 if (!init.readsColor()) { | |
279 fGeoData[0].fColor = GrColor_ILLEGAL; | |
280 } | |
281 init.getOverrideColorIfSet(&fGeoData[0].fColor); | |
282 | |
283 // setup batch properties | |
284 fBatch.fColorIgnored = !init.readsColor(); | |
285 fBatch.fColor = fGeoData[0].fColor; | |
286 fBatch.fUsesLocalCoords = init.readsLocalCoords(); | |
287 fBatch.fCoverageIgnored = !init.readsCoverage(); | |
288 } | |
289 | |
290 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline
) override { | |
291 SkAutoTUnref<const GrGeometryProcessor> gp; | |
292 { | |
293 using namespace GrDefaultGeoProcFactory; | |
294 Color color(this->color()); | |
295 Coverage coverage(this->coverageIgnored() ? Coverage::kSolid_Type : | |
296 Coverage::kNone_Type); | |
297 LocalCoords localCoords(this->usesLocalCoords() ? LocalCoords::kUseP
osition_Type : | |
298 LocalCoords::kUnus
ed_Type); | |
299 gp.reset(GrDefaultGeoProcFactory::Create(color, coverage, localCoord
s, | |
300 this->viewMatrix())); | |
301 } | |
302 | |
303 batchTarget->initDraw(gp, pipeline); | |
304 | |
305 size_t vertexStride = gp->getVertexStride(); | |
306 | |
307 SkASSERT(vertexStride == sizeof(GrDefaultGeoProcFactory::PositionAttr)); | |
308 | |
309 Geometry& args = fGeoData[0]; | |
310 | |
311 int vertexCount = kVertsPerHairlineRect; | |
312 if (args.fStrokeWidth > 0) { | |
313 vertexCount = kVertsPerStrokeRect; | |
314 } | |
315 | |
316 const GrVertexBuffer* vertexBuffer; | |
317 int firstVertex; | |
318 | |
319 void* verts = batchTarget->makeVertSpace(vertexStride, vertexCount, | |
320 &vertexBuffer, &firstVertex); | |
321 | |
322 if (!verts) { | |
323 SkDebugf("Could not allocate vertices\n"); | |
324 return; | |
325 } | |
326 | |
327 SkPoint* vertex = reinterpret_cast<SkPoint*>(verts); | |
328 | |
329 GrPrimitiveType primType; | |
330 | |
331 if (args.fStrokeWidth > 0) {; | |
332 primType = kTriangleStrip_GrPrimitiveType; | |
333 args.fRect.sort(); | |
334 this->setStrokeRectStrip(vertex, args.fRect, args.fStrokeWidth); | |
335 } else { | |
336 // hairline | |
337 primType = kLineStrip_GrPrimitiveType; | |
338 vertex[0].set(args.fRect.fLeft, args.fRect.fTop); | |
339 vertex[1].set(args.fRect.fRight, args.fRect.fTop); | |
340 vertex[2].set(args.fRect.fRight, args.fRect.fBottom); | |
341 vertex[3].set(args.fRect.fLeft, args.fRect.fBottom); | |
342 vertex[4].set(args.fRect.fLeft, args.fRect.fTop); | |
343 } | |
344 | |
345 GrVertices vertices; | |
346 vertices.init(primType, vertexBuffer, firstVertex, vertexCount); | |
347 batchTarget->draw(vertices); | |
348 } | |
349 | |
350 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } | |
351 | |
352 private: | |
353 StrokeRectBatch(const Geometry& geometry, bool snapToPixelCenters) { | |
354 this->initClassID<StrokeRectBatch>(); | |
355 | |
356 fBatch.fHairline = geometry.fStrokeWidth == 0; | |
357 | |
358 fGeoData.push_back(geometry); | |
359 | |
360 // setup bounds | |
361 fBounds = geometry.fRect; | |
362 SkScalar rad = SkScalarHalf(geometry.fStrokeWidth); | |
363 fBounds.outset(rad, rad); | |
364 geometry.fViewMatrix.mapRect(&fBounds); | |
365 | |
366 // If our caller snaps to pixel centers then we have to round out the bo
unds | |
367 if (snapToPixelCenters) { | |
368 fBounds.roundOut(); | |
369 } | |
370 } | |
371 | |
372 /* create a triangle strip that strokes the specified rect. There are 8 | |
373 unique vertices, but we repeat the last 2 to close up. Alternatively we | |
374 could use an indices array, and then only send 8 verts, but not sure that | |
375 would be faster. | |
376 */ | |
377 void setStrokeRectStrip(SkPoint verts[10], const SkRect& rect, SkScalar widt
h) { | |
378 const SkScalar rad = SkScalarHalf(width); | |
379 // TODO we should be able to enable this assert, but we'd have to filter
these draws | |
380 // this is a bug | |
381 //SkASSERT(rad < rect.width() / 2 && rad < rect.height() / 2); | |
382 | |
383 verts[0].set(rect.fLeft + rad, rect.fTop + rad); | |
384 verts[1].set(rect.fLeft - rad, rect.fTop - rad); | |
385 verts[2].set(rect.fRight - rad, rect.fTop + rad); | |
386 verts[3].set(rect.fRight + rad, rect.fTop - rad); | |
387 verts[4].set(rect.fRight - rad, rect.fBottom - rad); | |
388 verts[5].set(rect.fRight + rad, rect.fBottom + rad); | |
389 verts[6].set(rect.fLeft + rad, rect.fBottom - rad); | |
390 verts[7].set(rect.fLeft - rad, rect.fBottom + rad); | |
391 verts[8] = verts[0]; | |
392 verts[9] = verts[1]; | |
393 } | |
394 | |
395 | |
396 GrColor color() const { return fBatch.fColor; } | |
397 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } | |
398 bool colorIgnored() const { return fBatch.fColorIgnored; } | |
399 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; } | |
400 bool hairline() const { return fBatch.fHairline; } | |
401 bool coverageIgnored() const { return fBatch.fCoverageIgnored; } | |
402 | |
403 bool onCombineIfPossible(GrBatch* t) override { | |
404 //if (!this->pipeline()->isEqual(*t->pipeline())) { | |
405 // return false; | |
406 //} | |
407 // StrokeRectBatch* that = t->cast<StrokeRectBatch>(); | |
408 | |
409 // NonAA stroke rects cannot batch right now | |
410 // TODO make these batchable | |
411 return false; | |
412 } | |
413 | |
414 struct BatchTracker { | |
415 GrColor fColor; | |
416 bool fUsesLocalCoords; | |
417 bool fColorIgnored; | |
418 bool fCoverageIgnored; | |
419 bool fHairline; | |
420 }; | |
421 | |
422 const static int kVertsPerHairlineRect = 5; | |
423 const static int kVertsPerStrokeRect = 10; | |
424 | |
425 BatchTracker fBatch; | |
426 SkSTArray<1, Geometry, true> fGeoData; | |
427 }; | |
428 | |
429 void GrDrawContext::drawRect(GrRenderTarget* rt, | 253 void GrDrawContext::drawRect(GrRenderTarget* rt, |
430 const GrClip& clip, | 254 const GrClip& clip, |
431 const GrPaint& paint, | 255 const GrPaint& paint, |
432 const SkMatrix& viewMatrix, | 256 const SkMatrix& viewMatrix, |
433 const SkRect& rect, | 257 const SkRect& rect, |
434 const GrStrokeInfo* strokeInfo) { | 258 const GrStrokeInfo* strokeInfo) { |
435 RETURN_IF_ABANDONED | 259 RETURN_IF_ABANDONED |
436 if (strokeInfo && strokeInfo->isDashed()) { | 260 if (strokeInfo && strokeInfo->isDashed()) { |
437 SkPath path; | 261 SkPath path; |
438 path.setIsVolatile(true); | 262 path.setIsVolatile(true); |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
506 pipelineBuilder, | 330 pipelineBuilder, |
507 color, | 331 color, |
508 viewMatrix, | 332 viewMatrix, |
509 rect, | 333 rect, |
510 devBoundRect); | 334 devBoundRect); |
511 } | 335 } |
512 return; | 336 return; |
513 } | 337 } |
514 | 338 |
515 if (width >= 0) { | 339 if (width >= 0) { |
516 StrokeRectBatch::Geometry geometry; | 340 GrStrokeRectBatch::Geometry geometry; |
517 geometry.fViewMatrix = viewMatrix; | 341 geometry.fViewMatrix = viewMatrix; |
518 geometry.fColor = color; | 342 geometry.fColor = color; |
519 geometry.fRect = rect; | 343 geometry.fRect = rect; |
520 geometry.fStrokeWidth = width; | 344 geometry.fStrokeWidth = width; |
521 | 345 |
522 // Non-AA hairlines are snapped to pixel centers to make which pixels ar
e hit deterministic | 346 // Non-AA hairlines are snapped to pixel centers to make which pixels ar
e hit deterministic |
523 bool snapToPixelCenters = (0 == width && !rt->isUnifiedMultisampled()); | 347 bool snapToPixelCenters = (0 == width && !rt->isUnifiedMultisampled()); |
524 SkAutoTUnref<GrBatch> batch(StrokeRectBatch::Create(geometry, snapToPixe
lCenters)); | 348 SkAutoTUnref<GrBatch> batch(GrStrokeRectBatch::Create(geometry, snapToPi
xelCenters)); |
525 | 349 |
526 // Depending on sub-pixel coordinates and the particular GPU, we may los
e a corner of | 350 // Depending on sub-pixel coordinates and the particular GPU, we may los
e a corner of |
527 // hairline rects. We jam all the vertices to pixel centers to avoid thi
s, but not when MSAA | 351 // hairline rects. We jam all the vertices to pixel centers to avoid thi
s, but not when MSAA |
528 // is enabled because it can cause ugly artifacts. | 352 // is enabled because it can cause ugly artifacts. |
529 pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_
Flag, | 353 pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_
Flag, |
530 snapToPixelCenters); | 354 snapToPixelCenters); |
531 fDrawTarget->drawBatch(pipelineBuilder, batch); | 355 fDrawTarget->drawBatch(pipelineBuilder, batch); |
532 } else { | 356 } else { |
533 // filled BW rect | 357 // filled BW rect |
534 fDrawTarget->drawSimpleRect(pipelineBuilder, color, viewMatrix, rect); | 358 fDrawTarget->drawSimpleRect(pipelineBuilder, color, viewMatrix, rect); |
(...skipping 676 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1211 } | 1035 } |
1212 | 1036 |
1213 void GrDrawContext::drawBatch(GrPipelineBuilder* pipelineBuilder, GrBatch* batch
) { | 1037 void GrDrawContext::drawBatch(GrPipelineBuilder* pipelineBuilder, GrBatch* batch
) { |
1214 fDrawTarget->drawBatch(*pipelineBuilder, batch); | 1038 fDrawTarget->drawBatch(*pipelineBuilder, batch); |
1215 } | 1039 } |
1216 | 1040 |
1217 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 1041 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
1218 | 1042 |
1219 #ifdef GR_TEST_UTILS | 1043 #ifdef GR_TEST_UTILS |
1220 | 1044 |
1221 BATCH_TEST_DEFINE(StrokeRectBatch) { | |
1222 StrokeRectBatch::Geometry geometry; | |
1223 geometry.fViewMatrix = GrTest::TestMatrix(random); | |
1224 geometry.fColor = GrRandomColor(random); | |
1225 geometry.fRect = GrTest::TestRect(random); | |
1226 geometry.fStrokeWidth = random->nextBool() ? 0.0f : 1.0f; | |
1227 | |
1228 return StrokeRectBatch::Create(geometry, random->nextBool()); | |
1229 } | |
1230 | |
1231 static uint32_t seed_vertices(GrPrimitiveType type) { | 1045 static uint32_t seed_vertices(GrPrimitiveType type) { |
1232 switch (type) { | 1046 switch (type) { |
1233 case kTriangles_GrPrimitiveType: | 1047 case kTriangles_GrPrimitiveType: |
1234 case kTriangleStrip_GrPrimitiveType: | 1048 case kTriangleStrip_GrPrimitiveType: |
1235 case kTriangleFan_GrPrimitiveType: | 1049 case kTriangleFan_GrPrimitiveType: |
1236 return 3; | 1050 return 3; |
1237 case kPoints_GrPrimitiveType: | 1051 case kPoints_GrPrimitiveType: |
1238 return 1; | 1052 return 1; |
1239 case kLines_GrPrimitiveType: | 1053 case kLines_GrPrimitiveType: |
1240 case kLineStrip_GrPrimitiveType: | 1054 case kLineStrip_GrPrimitiveType: |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1334 return DrawVerticesBatch::Create(geometry, type, viewMatrix, | 1148 return DrawVerticesBatch::Create(geometry, type, viewMatrix, |
1335 positions.begin(), vertexCount, | 1149 positions.begin(), vertexCount, |
1336 indices.begin(), hasIndices ? vertexCount :
0, | 1150 indices.begin(), hasIndices ? vertexCount :
0, |
1337 colors.begin(), | 1151 colors.begin(), |
1338 texCoords.begin(), | 1152 texCoords.begin(), |
1339 bounds); | 1153 bounds); |
1340 } | 1154 } |
1341 | 1155 |
1342 #endif | 1156 #endif |
1343 | 1157 |
OLD | NEW |