| 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 |