• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "GrNonAAStrokeRectBatch.h"
9 
10 #include "GrBatchTest.h"
11 #include "GrBatchFlushState.h"
12 #include "GrColor.h"
13 #include "GrDefaultGeoProcFactory.h"
14 #include "GrVertexBatch.h"
15 #include "SkRandom.h"
16 
17 /*  create a triangle strip that strokes the specified rect. There are 8
18     unique vertices, but we repeat the last 2 to close up. Alternatively we
19     could use an indices array, and then only send 8 verts, but not sure that
20     would be faster.
21     */
init_stroke_rect_strip(SkPoint verts[10],const SkRect & rect,SkScalar width)22 static void init_stroke_rect_strip(SkPoint verts[10], const SkRect& rect, SkScalar width) {
23     const SkScalar rad = SkScalarHalf(width);
24     // TODO we should be able to enable this assert, but we'd have to filter these draws
25     // this is a bug
26     //SkASSERT(rad < rect.width() / 2 && rad < rect.height() / 2);
27 
28     verts[0].set(rect.fLeft + rad, rect.fTop + rad);
29     verts[1].set(rect.fLeft - rad, rect.fTop - rad);
30     verts[2].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);
33     verts[5].set(rect.fRight + rad, rect.fBottom + rad);
34     verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
35     verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
36     verts[8] = verts[0];
37     verts[9] = verts[1];
38 }
39 
40 class NonAAStrokeRectBatch : public GrVertexBatch {
41 public:
42     DEFINE_BATCH_CLASS_ID
43 
44     struct Geometry {
45         SkMatrix fViewMatrix;
46         SkRect fRect;
47         SkScalar fStrokeWidth;
48         GrColor fColor;
49     };
50 
Create()51     static NonAAStrokeRectBatch* Create() {
52         return new NonAAStrokeRectBatch;
53     }
54 
name() const55     const char* name() const override { return "GrStrokeRectBatch"; }
56 
computePipelineOptimizations(GrInitInvariantOutput * color,GrInitInvariantOutput * coverage,GrBatchToXPOverrides * overrides) const57     void computePipelineOptimizations(GrInitInvariantOutput* color,
58                                       GrInitInvariantOutput* coverage,
59                                       GrBatchToXPOverrides* overrides) const override {
60         // When this is called on a batch, there is only one geometry bundle
61         color->setKnownFourComponents(fGeoData[0].fColor);
62         coverage->setKnownSingleComponent(0xff);
63     }
64 
append(GrColor color,const SkMatrix & viewMatrix,const SkRect & rect,SkScalar strokeWidth)65     void append(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect,
66                 SkScalar strokeWidth) {
67         Geometry& geometry = fGeoData.push_back();
68         geometry.fViewMatrix = viewMatrix;
69         geometry.fRect = rect;
70         geometry.fStrokeWidth = strokeWidth;
71         geometry.fColor = color;
72 
73         // Sort the rect for hairlines
74         geometry.fRect.sort();
75     }
76 
appendAndUpdateBounds(GrColor color,const SkMatrix & viewMatrix,const SkRect & rect,SkScalar strokeWidth,bool snapToPixelCenters)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 
init(bool snapToPixelCenters)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:
setupBounds(SkRect * bounds,const Geometry & geo,bool snapToPixelCenters)95     void setupBounds(SkRect* bounds, const Geometry& geo, bool snapToPixelCenters) {
96         *bounds = geo.fRect;
97         SkScalar rad = SkScalarHalf(geo.fStrokeWidth);
98         bounds->outset(rad, rad);
99         geo.fViewMatrix.mapRect(&fBounds);
100 
101         // If our caller snaps to pixel centers then we have to round out the bounds
102         if (snapToPixelCenters) {
103             bounds->roundOut();
104         }
105     }
106 
onPrepareDraws(Target * target) const107     void onPrepareDraws(Target* target) const override {
108         SkAutoTUnref<const GrGeometryProcessor> gp;
109         {
110             using namespace GrDefaultGeoProcFactory;
111             Color color(this->color());
112             Coverage coverage(this->coverageIgnored() ? Coverage::kSolid_Type :
113                                                         Coverage::kNone_Type);
114             LocalCoords localCoords(this->usesLocalCoords() ? LocalCoords::kUsePosition_Type :
115                                                               LocalCoords::kUnused_Type);
116             gp.reset(GrDefaultGeoProcFactory::Create(color, coverage, localCoords,
117                                                      this->viewMatrix()));
118         }
119 
120         target->initDraw(gp, this->pipeline());
121 
122         size_t vertexStride = gp->getVertexStride();
123 
124         SkASSERT(vertexStride == sizeof(GrDefaultGeoProcFactory::PositionAttr));
125 
126         const Geometry& args = fGeoData[0];
127 
128         int vertexCount = kVertsPerHairlineRect;
129         if (args.fStrokeWidth > 0) {
130             vertexCount = kVertsPerStrokeRect;
131         }
132 
133         const GrVertexBuffer* vertexBuffer;
134         int firstVertex;
135 
136         void* verts = target->makeVertexSpace(vertexStride, vertexCount, &vertexBuffer,
137                                               &firstVertex);
138 
139         if (!verts) {
140             SkDebugf("Could not allocate vertices\n");
141             return;
142         }
143 
144         SkPoint* vertex = reinterpret_cast<SkPoint*>(verts);
145 
146         GrPrimitiveType primType;
147         if (args.fStrokeWidth > 0) {;
148             primType = kTriangleStrip_GrPrimitiveType;
149             init_stroke_rect_strip(vertex, args.fRect, args.fStrokeWidth);
150         } else {
151             // hairline
152             primType = kLineStrip_GrPrimitiveType;
153             vertex[0].set(args.fRect.fLeft, args.fRect.fTop);
154             vertex[1].set(args.fRect.fRight, args.fRect.fTop);
155             vertex[2].set(args.fRect.fRight, args.fRect.fBottom);
156             vertex[3].set(args.fRect.fLeft, args.fRect.fBottom);
157             vertex[4].set(args.fRect.fLeft, args.fRect.fTop);
158         }
159 
160         GrVertices vertices;
161         vertices.init(primType, vertexBuffer, firstVertex, vertexCount);
162         target->draw(vertices);
163     }
164 
initBatchTracker(const GrXPOverridesForBatch & overrides)165     void initBatchTracker(const GrXPOverridesForBatch& overrides) override {
166         // Handle any color overrides
167         if (!overrides.readsColor()) {
168             fGeoData[0].fColor = GrColor_ILLEGAL;
169         }
170         overrides.getOverrideColorIfSet(&fGeoData[0].fColor);
171 
172         // setup batch properties
173         fBatch.fColorIgnored = !overrides.readsColor();
174         fBatch.fColor = fGeoData[0].fColor;
175         fBatch.fUsesLocalCoords = overrides.readsLocalCoords();
176         fBatch.fCoverageIgnored = !overrides.readsCoverage();
177     }
178 
NonAAStrokeRectBatch()179     NonAAStrokeRectBatch() : INHERITED(ClassID()) {}
180 
color() const181     GrColor color() const { return fBatch.fColor; }
usesLocalCoords() const182     bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
colorIgnored() const183     bool colorIgnored() const { return fBatch.fColorIgnored; }
viewMatrix() const184     const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
hairline() const185     bool hairline() const { return fBatch.fHairline; }
coverageIgnored() const186     bool coverageIgnored() const { return fBatch.fCoverageIgnored; }
187 
onCombineIfPossible(GrBatch * t,const GrCaps &)188     bool onCombineIfPossible(GrBatch* t, const GrCaps&) override {
189         // if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *t->pipeline(),
190         //     t->bounds(), caps)) {
191         //     return false;
192         // }
193         // GrStrokeRectBatch* that = t->cast<StrokeRectBatch>();
194 
195         // NonAA stroke rects cannot batch right now
196         // TODO make these batchable
197         return false;
198     }
199 
200     struct BatchTracker {
201         GrColor fColor;
202         bool fUsesLocalCoords;
203         bool fColorIgnored;
204         bool fCoverageIgnored;
205         bool fHairline;
206     };
207 
208     const static int kVertsPerHairlineRect = 5;
209     const static int kVertsPerStrokeRect = 10;
210 
211     BatchTracker fBatch;
212     SkSTArray<1, Geometry, true> fGeoData;
213 
214     typedef GrVertexBatch INHERITED;
215 };
216 
217 namespace GrNonAAStrokeRectBatch {
218 
Create(GrColor color,const SkMatrix & viewMatrix,const SkRect & rect,SkScalar strokeWidth,bool snapToPixelCenters)219 GrDrawBatch* Create(GrColor color,
220                     const SkMatrix& viewMatrix,
221                     const SkRect& rect,
222                     SkScalar strokeWidth,
223                     bool snapToPixelCenters) {
224     NonAAStrokeRectBatch* batch = NonAAStrokeRectBatch::Create();
225     batch->append(color, viewMatrix, rect, strokeWidth);
226     batch->init(snapToPixelCenters);
227     return batch;
228 }
229 
Append(GrBatch * origBatch,GrColor color,const SkMatrix & viewMatrix,const SkRect & rect,SkScalar strokeWidth,bool snapToPixelCenters)230 void Append(GrBatch* origBatch,
231             GrColor color,
232             const SkMatrix& viewMatrix,
233             const SkRect& rect,
234             SkScalar strokeWidth,
235             bool snapToPixelCenters) {
236     NonAAStrokeRectBatch* batch = origBatch->cast<NonAAStrokeRectBatch>();
237     batch->appendAndUpdateBounds(color, viewMatrix, rect, strokeWidth, snapToPixelCenters);
238 }
239 
240 };
241 
242 #ifdef GR_TEST_UTILS
243 
DRAW_BATCH_TEST_DEFINE(NonAAStrokeRectBatch)244 DRAW_BATCH_TEST_DEFINE(NonAAStrokeRectBatch) {
245     SkMatrix viewMatrix = GrTest::TestMatrix(random);
246     GrColor color = GrRandomColor(random);
247     SkRect rect = GrTest::TestRect(random);
248     SkScalar strokeWidth = random->nextBool() ? 0.0f : 1.0f;
249 
250     return GrNonAAStrokeRectBatch::Create(color, viewMatrix, rect, strokeWidth, random->nextBool());
251 }
252 
253 #endif
254