| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "GrNonAAStrokeRectBatch.h" | 8 #include "GrNonAAStrokeRectBatch.h" |
| 9 | 9 |
| 10 #include "GrBatchTest.h" | 10 #include "GrBatchTest.h" |
| (...skipping 19 matching lines...) Expand all Loading... |
| 30 verts[2].set(rect.fRight - rad, rect.fTop + rad); | 30 verts[2].set(rect.fRight - rad, rect.fTop + rad); |
| 31 verts[3].set(rect.fRight + rad, rect.fTop - rad); | 31 verts[3].set(rect.fRight + rad, rect.fTop - rad); |
| 32 verts[4].set(rect.fRight - rad, rect.fBottom - rad); | 32 verts[4].set(rect.fRight - rad, rect.fBottom - rad); |
| 33 verts[5].set(rect.fRight + rad, rect.fBottom + rad); | 33 verts[5].set(rect.fRight + rad, rect.fBottom + rad); |
| 34 verts[6].set(rect.fLeft + rad, rect.fBottom - rad); | 34 verts[6].set(rect.fLeft + rad, rect.fBottom - rad); |
| 35 verts[7].set(rect.fLeft - rad, rect.fBottom + rad); | 35 verts[7].set(rect.fLeft - rad, rect.fBottom + rad); |
| 36 verts[8] = verts[0]; | 36 verts[8] = verts[0]; |
| 37 verts[9] = verts[1]; | 37 verts[9] = verts[1]; |
| 38 } | 38 } |
| 39 | 39 |
| 40 // Allow all hairlines and all miters, so long as the miter limit doesn't produc
e beveled corners. |
| 41 inline static bool allowed_stroke(const SkStrokeRec& stroke) { |
| 42 SkASSERT(stroke.getStyle() == SkStrokeRec::kStroke_Style || |
| 43 stroke.getStyle() == SkStrokeRec::kHairline_Style); |
| 44 return !stroke.getWidth() || |
| 45 (stroke.getJoin() == SkPaint::kMiter_Join && stroke.getMiter() > SK_S
calarSqrt2); |
| 46 } |
| 47 |
| 40 class NonAAStrokeRectBatch : public GrVertexBatch { | 48 class NonAAStrokeRectBatch : public GrVertexBatch { |
| 41 public: | 49 public: |
| 42 DEFINE_BATCH_CLASS_ID | 50 DEFINE_BATCH_CLASS_ID |
| 43 | 51 |
| 44 struct Geometry { | 52 const char* name() const override { return "NonAAStrokeRectBatch"; } |
| 45 SkMatrix fViewMatrix; | |
| 46 SkRect fRect; | |
| 47 SkScalar fStrokeWidth; | |
| 48 GrColor fColor; | |
| 49 }; | |
| 50 | |
| 51 static NonAAStrokeRectBatch* Create() { | |
| 52 return new NonAAStrokeRectBatch; | |
| 53 } | |
| 54 | |
| 55 const char* name() const override { return "GrStrokeRectBatch"; } | |
| 56 | 53 |
| 57 void computePipelineOptimizations(GrInitInvariantOutput* color, | 54 void computePipelineOptimizations(GrInitInvariantOutput* color, |
| 58 GrInitInvariantOutput* coverage, | 55 GrInitInvariantOutput* coverage, |
| 59 GrBatchToXPOverrides* overrides) const ove
rride { | 56 GrBatchToXPOverrides* overrides) const ove
rride { |
| 60 // When this is called on a batch, there is only one geometry bundle | 57 // When this is called on a batch, there is only one geometry bundle |
| 61 color->setKnownFourComponents(fGeoData[0].fColor); | 58 color->setKnownFourComponents(fColor); |
| 62 coverage->setKnownSingleComponent(0xff); | 59 coverage->setKnownSingleComponent(0xff); |
| 63 } | 60 } |
| 64 | 61 |
| 65 void append(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect, | 62 static GrDrawBatch* Create(GrColor color, const SkMatrix& viewMatrix, const
SkRect& rect, |
| 66 SkScalar strokeWidth) { | 63 const SkStrokeRec& stroke, bool snapToPixelCenter
s) { |
| 67 Geometry& geometry = fGeoData.push_back(); | 64 if (!allowed_stroke(stroke)) { |
| 68 geometry.fViewMatrix = viewMatrix; | 65 return nullptr; |
| 69 geometry.fRect = rect; | 66 } |
| 70 geometry.fStrokeWidth = strokeWidth; | 67 NonAAStrokeRectBatch* batch = new NonAAStrokeRectBatch(); |
| 71 geometry.fColor = color; | 68 batch->fColor = color; |
| 69 batch->fViewMatrix = viewMatrix; |
| 70 batch->fRect = rect; |
| 71 // Sort the rect for hairlines |
| 72 batch->fRect.sort(); |
| 73 batch->fStrokeWidth = stroke.getWidth(); |
| 72 | 74 |
| 73 // Sort the rect for hairlines | 75 batch->fBounds = batch->fRect; |
| 74 geometry.fRect.sort(); | 76 SkScalar rad = SkScalarHalf(batch->fStrokeWidth); |
| 75 } | 77 batch->fBounds.outset(rad, rad); |
| 76 | 78 batch->fViewMatrix.mapRect(&batch->fBounds); |
| 77 void appendAndUpdateBounds(GrColor color, const SkMatrix& viewMatrix, const
SkRect& rect, | |
| 78 SkScalar strokeWidth, bool snapToPixelCenters) { | |
| 79 this->append(color, viewMatrix, rect, strokeWidth); | |
| 80 | |
| 81 SkRect bounds; | |
| 82 this->setupBounds(&bounds, fGeoData.back(), snapToPixelCenters); | |
| 83 this->joinBounds(bounds); | |
| 84 } | |
| 85 | |
| 86 void init(bool snapToPixelCenters) { | |
| 87 const Geometry& geo = fGeoData[0]; | |
| 88 fBatch.fHairline = geo.fStrokeWidth == 0; | |
| 89 | |
| 90 // setup bounds | |
| 91 this->setupBounds(&fBounds, geo, snapToPixelCenters); | |
| 92 } | |
| 93 | |
| 94 private: | |
| 95 void setupBounds(SkRect* bounds, const Geometry& geo, bool snapToPixelCenter
s) { | |
| 96 *bounds = geo.fRect; | |
| 97 SkScalar rad = SkScalarHalf(geo.fStrokeWidth); | |
| 98 bounds->outset(rad, rad); | |
| 99 geo.fViewMatrix.mapRect(&fBounds); | |
| 100 | 79 |
| 101 // If our caller snaps to pixel centers then we have to round out the bo
unds | 80 // If our caller snaps to pixel centers then we have to round out the bo
unds |
| 102 if (snapToPixelCenters) { | 81 if (snapToPixelCenters) { |
| 103 // We want to be consistent with how we snap non-aa lines. To match
what we do in | 82 // We want to be consistent with how we snap non-aa lines. To match
what we do in |
| 104 // GrGLSLVertexShaderBuilder, we first floor all the vertex values a
nd then add half a | 83 // GrGLSLVertexShaderBuilder, we first floor all the vertex values a
nd then add half a |
| 105 // pixel to force us to pixel centers. | 84 // pixel to force us to pixel centers. |
| 106 bounds->set(SkScalarFloorToScalar(bounds->fLeft), | 85 batch->fBounds.set(SkScalarFloorToScalar(batch->fBounds.fLeft), |
| 107 SkScalarFloorToScalar(bounds->fTop), | 86 SkScalarFloorToScalar(batch->fBounds.fTop), |
| 108 SkScalarFloorToScalar(bounds->fRight), | 87 SkScalarFloorToScalar(batch->fBounds.fRight), |
| 109 SkScalarFloorToScalar(bounds->fBottom)); | 88 SkScalarFloorToScalar(batch->fBounds.fBottom)); |
| 110 bounds->offset(0.5f, 0.5f); | 89 batch->fBounds.offset(0.5f, 0.5f); |
| 111 | 90 |
| 112 // Round out the bounds to integer values | 91 // Round out the bounds to integer values |
| 113 bounds->roundOut(); | 92 batch->fBounds.roundOut(); |
| 114 } | 93 } |
| 94 return batch; |
| 115 } | 95 } |
| 116 | 96 |
| 97 private: |
| 98 NonAAStrokeRectBatch() : INHERITED(ClassID()) {} |
| 99 |
| 117 void onPrepareDraws(Target* target) const override { | 100 void onPrepareDraws(Target* target) const override { |
| 118 sk_sp<GrGeometryProcessor> gp; | 101 sk_sp<GrGeometryProcessor> gp; |
| 119 { | 102 { |
| 120 using namespace GrDefaultGeoProcFactory; | 103 using namespace GrDefaultGeoProcFactory; |
| 121 Color color(this->color()); | 104 Color color(fColor); |
| 122 Coverage coverage(this->coverageIgnored() ? Coverage::kSolid_Type : | 105 Coverage coverage(fOverrides.readsCoverage() ? Coverage::kSolid_Type |
| 123 Coverage::kNone_Type); | 106 : Coverage::kNone_Type)
; |
| 124 LocalCoords localCoords(this->usesLocalCoords() ? LocalCoords::kUseP
osition_Type : | 107 LocalCoords localCoords(fOverrides.readsLocalCoords() ? LocalCoords:
:kUsePosition_Type : |
| 125 LocalCoords::kUnus
ed_Type); | 108 LocalCoords:
:kUnused_Type); |
| 126 gp = GrDefaultGeoProcFactory::Make(color, coverage, localCoords, thi
s->viewMatrix()); | 109 gp = GrDefaultGeoProcFactory::Make(color, coverage, localCoords, fVi
ewMatrix); |
| 127 } | 110 } |
| 128 | 111 |
| 129 size_t vertexStride = gp->getVertexStride(); | 112 size_t vertexStride = gp->getVertexStride(); |
| 130 | 113 |
| 131 SkASSERT(vertexStride == sizeof(GrDefaultGeoProcFactory::PositionAttr)); | 114 SkASSERT(vertexStride == sizeof(GrDefaultGeoProcFactory::PositionAttr)); |
| 132 | 115 |
| 133 const Geometry& args = fGeoData[0]; | |
| 134 | |
| 135 int vertexCount = kVertsPerHairlineRect; | 116 int vertexCount = kVertsPerHairlineRect; |
| 136 if (args.fStrokeWidth > 0) { | 117 if (fStrokeWidth > 0) { |
| 137 vertexCount = kVertsPerStrokeRect; | 118 vertexCount = kVertsPerStrokeRect; |
| 138 } | 119 } |
| 139 | 120 |
| 140 const GrBuffer* vertexBuffer; | 121 const GrBuffer* vertexBuffer; |
| 141 int firstVertex; | 122 int firstVertex; |
| 142 | 123 |
| 143 void* verts = target->makeVertexSpace(vertexStride, vertexCount, &vertex
Buffer, | 124 void* verts = target->makeVertexSpace(vertexStride, vertexCount, &vertex
Buffer, |
| 144 &firstVertex); | 125 &firstVertex); |
| 145 | 126 |
| 146 if (!verts) { | 127 if (!verts) { |
| 147 SkDebugf("Could not allocate vertices\n"); | 128 SkDebugf("Could not allocate vertices\n"); |
| 148 return; | 129 return; |
| 149 } | 130 } |
| 150 | 131 |
| 151 SkPoint* vertex = reinterpret_cast<SkPoint*>(verts); | 132 SkPoint* vertex = reinterpret_cast<SkPoint*>(verts); |
| 152 | 133 |
| 153 GrPrimitiveType primType; | 134 GrPrimitiveType primType; |
| 154 if (args.fStrokeWidth > 0) { | 135 if (fStrokeWidth > 0) { |
| 155 primType = kTriangleStrip_GrPrimitiveType; | 136 primType = kTriangleStrip_GrPrimitiveType; |
| 156 init_stroke_rect_strip(vertex, args.fRect, args.fStrokeWidth); | 137 init_stroke_rect_strip(vertex, fRect, fStrokeWidth); |
| 157 } else { | 138 } else { |
| 158 // hairline | 139 // hairline |
| 159 primType = kLineStrip_GrPrimitiveType; | 140 primType = kLineStrip_GrPrimitiveType; |
| 160 vertex[0].set(args.fRect.fLeft, args.fRect.fTop); | 141 vertex[0].set(fRect.fLeft, fRect.fTop); |
| 161 vertex[1].set(args.fRect.fRight, args.fRect.fTop); | 142 vertex[1].set(fRect.fRight, fRect.fTop); |
| 162 vertex[2].set(args.fRect.fRight, args.fRect.fBottom); | 143 vertex[2].set(fRect.fRight, fRect.fBottom); |
| 163 vertex[3].set(args.fRect.fLeft, args.fRect.fBottom); | 144 vertex[3].set(fRect.fLeft, fRect.fBottom); |
| 164 vertex[4].set(args.fRect.fLeft, args.fRect.fTop); | 145 vertex[4].set(fRect.fLeft, fRect.fTop); |
| 165 } | 146 } |
| 166 | 147 |
| 167 GrMesh mesh; | 148 GrMesh mesh; |
| 168 mesh.init(primType, vertexBuffer, firstVertex, vertexCount); | 149 mesh.init(primType, vertexBuffer, firstVertex, vertexCount); |
| 169 target->draw(gp.get(), mesh); | 150 target->draw(gp.get(), mesh); |
| 170 } | 151 } |
| 171 | 152 |
| 172 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { | 153 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { |
| 173 // Handle any color overrides | 154 overrides.getOverrideColorIfSet(&fColor); |
| 174 if (!overrides.readsColor()) { | 155 fOverrides = overrides; |
| 175 fGeoData[0].fColor = GrColor_ILLEGAL; | |
| 176 } | |
| 177 overrides.getOverrideColorIfSet(&fGeoData[0].fColor); | |
| 178 | |
| 179 // setup batch properties | |
| 180 fBatch.fColorIgnored = !overrides.readsColor(); | |
| 181 fBatch.fColor = fGeoData[0].fColor; | |
| 182 fBatch.fUsesLocalCoords = overrides.readsLocalCoords(); | |
| 183 fBatch.fCoverageIgnored = !overrides.readsCoverage(); | |
| 184 } | 156 } |
| 185 | 157 |
| 186 NonAAStrokeRectBatch() : INHERITED(ClassID()) {} | |
| 187 | |
| 188 GrColor color() const { return fBatch.fColor; } | |
| 189 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } | |
| 190 bool colorIgnored() const { return fBatch.fColorIgnored; } | |
| 191 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; } | |
| 192 bool hairline() const { return fBatch.fHairline; } | |
| 193 bool coverageIgnored() const { return fBatch.fCoverageIgnored; } | |
| 194 | |
| 195 bool onCombineIfPossible(GrBatch* t, const GrCaps&) override { | 158 bool onCombineIfPossible(GrBatch* t, const GrCaps&) override { |
| 196 // if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *t->pi
peline(), | |
| 197 // t->bounds(), caps)) { | |
| 198 // return false; | |
| 199 // } | |
| 200 // GrStrokeRectBatch* that = t->cast<StrokeRectBatch>(); | |
| 201 | |
| 202 // NonAA stroke rects cannot batch right now | 159 // NonAA stroke rects cannot batch right now |
| 203 // TODO make these batchable | 160 // TODO make these batchable |
| 204 return false; | 161 return false; |
| 205 } | 162 } |
| 206 | 163 |
| 207 struct BatchTracker { | 164 GrColor fColor; |
| 208 GrColor fColor; | 165 SkMatrix fViewMatrix; |
| 209 bool fUsesLocalCoords; | 166 SkRect fRect; |
| 210 bool fColorIgnored; | 167 SkScalar fStrokeWidth; |
| 211 bool fCoverageIgnored; | 168 |
| 212 bool fHairline; | 169 GrXPOverridesForBatch fOverrides; |
| 213 }; | |
| 214 | 170 |
| 215 const static int kVertsPerHairlineRect = 5; | 171 const static int kVertsPerHairlineRect = 5; |
| 216 const static int kVertsPerStrokeRect = 10; | 172 const static int kVertsPerStrokeRect = 10; |
| 217 | 173 |
| 218 BatchTracker fBatch; | |
| 219 SkSTArray<1, Geometry, true> fGeoData; | |
| 220 | 174 |
| 221 typedef GrVertexBatch INHERITED; | 175 typedef GrVertexBatch INHERITED; |
| 222 }; | 176 }; |
| 223 | 177 |
| 224 // Allow all hairlines and all miters, so long as the miter limit doesn't produc
e beveled corners. | |
| 225 inline static bool allowed_stroke(const SkStrokeRec& stroke) { | |
| 226 SkASSERT(stroke.getStyle() == SkStrokeRec::kStroke_Style || | |
| 227 stroke.getStyle() == SkStrokeRec::kHairline_Style); | |
| 228 return !stroke.getWidth() || | |
| 229 (stroke.getJoin() == SkPaint::kMiter_Join && stroke.getMiter() > SK_
ScalarSqrt2); | |
| 230 } | |
| 231 | |
| 232 namespace GrNonAAStrokeRectBatch { | 178 namespace GrNonAAStrokeRectBatch { |
| 233 | 179 |
| 234 GrDrawBatch* Create(GrColor color, | 180 GrDrawBatch* Create(GrColor color, |
| 235 const SkMatrix& viewMatrix, | 181 const SkMatrix& viewMatrix, |
| 236 const SkRect& rect, | 182 const SkRect& rect, |
| 237 const SkStrokeRec& stroke, | 183 const SkStrokeRec& stroke, |
| 238 bool snapToPixelCenters) { | 184 bool snapToPixelCenters) { |
| 239 if (!allowed_stroke(stroke)) { | 185 return NonAAStrokeRectBatch::Create(color, viewMatrix, rect, stroke, snapToP
ixelCenters); |
| 240 return nullptr; | |
| 241 } | |
| 242 NonAAStrokeRectBatch* batch = NonAAStrokeRectBatch::Create(); | |
| 243 batch->append(color, viewMatrix, rect, stroke.getWidth()); | |
| 244 batch->init(snapToPixelCenters); | |
| 245 return batch; | |
| 246 } | 186 } |
| 247 | 187 |
| 248 }; | 188 } |
| 249 | 189 |
| 250 #ifdef GR_TEST_UTILS | 190 #ifdef GR_TEST_UTILS |
| 251 | 191 |
| 252 DRAW_BATCH_TEST_DEFINE(NonAAStrokeRectBatch) { | 192 DRAW_BATCH_TEST_DEFINE(NonAAStrokeRectBatch) { |
| 253 SkMatrix viewMatrix = GrTest::TestMatrix(random); | 193 SkMatrix viewMatrix = GrTest::TestMatrix(random); |
| 254 GrColor color = GrRandomColor(random); | 194 GrColor color = GrRandomColor(random); |
| 255 SkRect rect = GrTest::TestRect(random); | 195 SkRect rect = GrTest::TestRect(random); |
| 256 SkScalar strokeWidth = random->nextBool() ? 0.0f : 2.0f; | 196 SkScalar strokeWidth = random->nextBool() ? 0.0f : 2.0f; |
| 257 SkPaint paint; | 197 SkPaint paint; |
| 258 paint.setStrokeWidth(strokeWidth); | 198 paint.setStrokeWidth(strokeWidth); |
| 259 paint.setStyle(SkPaint::kStroke_Style); | 199 paint.setStyle(SkPaint::kStroke_Style); |
| 260 paint.setStrokeJoin(SkPaint::kMiter_Join); | 200 paint.setStrokeJoin(SkPaint::kMiter_Join); |
| 261 SkStrokeRec strokeRec(paint); | 201 SkStrokeRec strokeRec(paint); |
| 262 return GrNonAAStrokeRectBatch::Create(color, viewMatrix, rect, strokeRec, ra
ndom->nextBool()); | 202 return GrNonAAStrokeRectBatch::Create(color, viewMatrix, rect, strokeRec, ra
ndom->nextBool()); |
| 263 } | 203 } |
| 264 | 204 |
| 265 #endif | 205 #endif |
| OLD | NEW |