Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(721)

Side by Side Diff: src/gpu/batches/GrBWFillRectBatch.cpp

Issue 1301203002: Revert "fill rect batch refactor into separate batches" (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/gpu/batches/GrAAFillRectBatch.cpp ('k') | src/gpu/batches/GrTInstanceBatch.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 "GrBWFillRectBatch.h" 8 #include "GrBWFillRectBatch.h"
9 9
10 #include "GrBatchFlushState.h" 10 #include "GrBatchFlushState.h"
11 #include "GrColor.h" 11 #include "GrColor.h"
12 #include "GrDefaultGeoProcFactory.h" 12 #include "GrDefaultGeoProcFactory.h"
13 #include "GrPrimitiveProcessor.h" 13 #include "GrPrimitiveProcessor.h"
14 #include "GrQuad.h" 14 #include "GrQuad.h"
15 #include "GrResourceProvider.h"
16 #include "GrTInstanceBatch.h"
17 #include "GrVertexBatch.h" 15 #include "GrVertexBatch.h"
18 16
19 // Common functions 17 class GrBatchFlushState;
20 class BWFillRectBatchBase { 18 class SkMatrix;
21 public: 19 struct SkRect;
22 static const int kVertsPerInstance = 4; 20
23 static const int kIndicesPerInstance = 6; 21 class BWFillRectBatch : public GrVertexBatch {
24
25 static const GrIndexBuffer* GetIndexBuffer(GrResourceProvider* rp) {
26 return rp->refQuadIndexBuffer();
27 }
28
29 template <typename Geometry>
30 static void SetBounds(const Geometry& geo, SkRect* outBounds) {
31 geo.fViewMatrix.mapRect(outBounds, geo.fRect);
32 }
33 };
34
35 /** We always use per-vertex colors so that rects can be batched across color ch anges. Sometimes
36 we have explicit local coords and sometimes not. We *could* always provide explicit local
37 coords and just duplicate the positions when the caller hasn't provided a lo cal coord rect,
38 but we haven't seen a use case which frequently switches between local rect and no local
39 rect draws.
40
41 The color param is used to determine whether the opaque hint can be set on t he draw state.
42 The caller must populate the vertex colors itself.
43
44 The vertex attrib order is always pos, color, [local coords].
45 */
46 static const GrGeometryProcessor* create_gp(const SkMatrix& viewMatrix,
47 bool readsCoverage,
48 bool hasExplicitLocalCoords,
49 const SkMatrix* localMatrix) {
50 using namespace GrDefaultGeoProcFactory;
51 Color color(Color::kAttribute_Type);
52 Coverage coverage(readsCoverage ? Coverage::kSolid_Type : Coverage::kNone_Ty pe);
53
54 // if we have a local rect, then we apply the localMatrix directly to the lo calRect to
55 // generate vertex local coords
56 if (hasExplicitLocalCoords) {
57 LocalCoords localCoords(LocalCoords::kHasExplicit_Type);
58 return GrDefaultGeoProcFactory::Create(color, coverage, localCoords, SkM atrix::I());
59 } else {
60 LocalCoords localCoords(LocalCoords::kUsePosition_Type, localMatrix ? lo calMatrix : NULL);
61 return GrDefaultGeoProcFactory::CreateForDeviceSpace(color, coverage, lo calCoords,
62 viewMatrix);
63 }
64 }
65
66 static void tesselate(intptr_t vertices,
67 size_t vertexStride,
68 GrColor color,
69 const SkMatrix& viewMatrix,
70 const SkRect& rect,
71 const SkRect* localRect,
72 const SkMatrix* localMatrix) {
73 SkPoint* positions = reinterpret_cast<SkPoint*>(vertices);
74
75 positions->setRectFan(rect.fLeft, rect.fTop,
76 rect.fRight, rect.fBottom, vertexStride);
77 viewMatrix.mapPointsWithStride(positions, vertexStride, BWFillRectBatchBase: :kVertsPerInstance);
78
79 // TODO we should only do this if local coords are being read
80 if (localRect) {
81 static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
82 SkPoint* coords = reinterpret_cast<SkPoint*>(vertices + kLocalOffset);
83 coords->setRectFan(localRect->fLeft, localRect->fTop,
84 localRect->fRight, localRect->fBottom,
85 vertexStride);
86 if (localMatrix) {
87 localMatrix->mapPointsWithStride(coords, vertexStride,
88 BWFillRectBatchBase::kVertsPerInsta nce);
89 }
90 }
91
92 static const int kColorOffset = sizeof(SkPoint);
93 GrColor* vertColor = reinterpret_cast<GrColor*>(vertices + kColorOffset);
94 for (int j = 0; j < 4; ++j) {
95 *vertColor = color;
96 vertColor = (GrColor*) ((intptr_t) vertColor + vertexStride);
97 }
98 }
99
100 class BWFillRectBatchNoLocalMatrixImp : public BWFillRectBatchBase {
101 public:
102 struct Geometry {
103 SkMatrix fViewMatrix;
104 SkRect fRect;
105 GrColor fColor;
106 };
107
108 static const char* Name() { return "BWFillRectBatchNoLocalMatrix"; }
109
110 static bool CanCombine(const Geometry& mine, const Geometry& theirs,
111 const GrPipelineOptimizations& opts) {
112 // We apply the viewmatrix to the rect points on the cpu. However, if t he pipeline uses
113 // local coords then we won't be able to batch. We could actually uploa d the viewmatrix
114 // using vertex attributes in these cases, but haven't investigated that
115 return !opts.readsLocalCoords() || mine.fViewMatrix.cheapEqualTo(theirs. fViewMatrix);
116 }
117
118 static const GrGeometryProcessor* CreateGP(const Geometry& geo,
119 const GrPipelineOptimizations& op ts) {
120 const GrGeometryProcessor* gp = create_gp(geo.fViewMatrix, opts.readsCov erage(), false,
121 NULL);
122
123 SkASSERT(gp->getVertexStride() == sizeof(GrDefaultGeoProcFactory::Positi onColorAttr));
124 return gp;
125 }
126
127 static void Tesselate(intptr_t vertices, size_t vertexStride, const Geometry & geo,
128 const GrPipelineOptimizations& opts) {
129 tesselate(vertices, vertexStride, geo.fColor, geo.fViewMatrix, geo.fRect , NULL, NULL);
130 }
131 };
132
133 class BWFillRectBatchLocalMatrixImp : public BWFillRectBatchBase {
134 public:
135 struct Geometry {
136 SkMatrix fViewMatrix;
137 SkMatrix fLocalMatrix;
138 SkRect fRect;
139 GrColor fColor;
140 };
141
142 static const char* Name() { return "BWFillRectBatchLocalMatrix"; }
143
144 static bool CanCombine(const Geometry& mine, const Geometry& theirs,
145 const GrPipelineOptimizations& opts) {
146 // We apply the viewmatrix to the rect points on the cpu. However, if t he pipeline uses
147 // local coords then we won't be able to batch. We could actually uploa d the viewmatrix
148 // using vertex attributes in these cases, but haven't investigated that
149 return !opts.readsLocalCoords() || mine.fViewMatrix.cheapEqualTo(theirs. fViewMatrix);
150 }
151
152 static const GrGeometryProcessor* CreateGP(const Geometry& geo,
153 const GrPipelineOptimizations& op ts) {
154 const GrGeometryProcessor* gp = create_gp(geo.fViewMatrix, opts.readsCov erage(), false,
155 &geo.fLocalMatrix);
156
157 SkASSERT(gp->getVertexStride() == sizeof(GrDefaultGeoProcFactory::Positi onColorAttr));
158 return gp;
159 }
160
161 static void Tesselate(intptr_t vertices, size_t vertexStride, const Geometry & geo,
162 const GrPipelineOptimizations& opts) {
163 tesselate(vertices, vertexStride, geo.fColor, geo.fViewMatrix, geo.fRect , NULL,
164 &geo.fLocalMatrix);
165 }
166 };
167
168 class BWFillRectBatchLocalRectImp : public BWFillRectBatchBase {
169 public: 22 public:
170 struct Geometry { 23 struct Geometry {
171 SkMatrix fViewMatrix; 24 SkMatrix fViewMatrix;
172 SkRect fRect; 25 SkRect fRect;
173 SkRect fLocalRect; 26 SkRect fLocalRect;
27 SkMatrix fLocalMatrix;
174 GrColor fColor; 28 GrColor fColor;
29 bool fHasLocalRect;
30 bool fHasLocalMatrix;
175 }; 31 };
176 32
177 static const char* Name() { return "BWFillRectBatchLocalRect"; } 33 static GrDrawBatch* Create(const Geometry& geometry) {
178 34 return SkNEW_ARGS(BWFillRectBatch, (geometry));
179 static bool CanCombine(const Geometry& mine, const Geometry& theirs, 35 }
180 const GrPipelineOptimizations& opts) { 36
37 const char* name() const override { return "RectBatch"; }
38
39 void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
40 // When this is called on a batch, there is only one geometry bundle
41 out->setKnownFourComponents(fGeoData[0].fColor);
42 }
43
44 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
45 out->setKnownSingleComponent(0xff);
46 }
47
48 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
49
50 private:
51 BWFillRectBatch(const Geometry& geometry) {
52 this->initClassID<BWFillRectBatch>();
53 fGeoData.push_back(geometry);
54
55 fBounds = geometry.fRect;
56 geometry.fViewMatrix.mapRect(&fBounds);
57 }
58
59 GrColor color() const { return fBatch.fColor; }
60 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
61 bool colorIgnored() const { return fBatch.fColorIgnored; }
62 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
63 const SkMatrix& localMatrix() const { return fGeoData[0].fLocalMatrix; }
64 bool hasLocalRect() const { return fGeoData[0].fHasLocalRect; }
65 bool hasLocalMatrix() const { return fGeoData[0].fHasLocalMatrix; }
66 bool coverageIgnored() const { return fBatch.fCoverageIgnored; }
67
68 void initBatchTracker(const GrPipelineOptimizations& init) override {
69 // Handle any color overrides
70 if (!init.readsColor()) {
71 fGeoData[0].fColor = GrColor_ILLEGAL;
72 }
73 init.getOverrideColorIfSet(&fGeoData[0].fColor);
74
75 // setup batch properties
76 fBatch.fColorIgnored = !init.readsColor();
77 fBatch.fColor = fGeoData[0].fColor;
78 fBatch.fUsesLocalCoords = init.readsLocalCoords();
79 fBatch.fCoverageIgnored = !init.readsCoverage();
80 }
81
82 void onPrepareDraws(Target* target) override {
83 SkAutoTUnref<const GrGeometryProcessor> gp(this->createRectGP());
84 if (!gp) {
85 SkDebugf("Could not create GrGeometryProcessor\n");
86 return;
87 }
88
89 target->initDraw(gp, this->pipeline());
90
91 int instanceCount = fGeoData.count();
92 size_t vertexStride = gp->getVertexStride();
93 SkASSERT(this->hasLocalRect() ?
94 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorLo calCoordAttr) :
95 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAt tr));
96 QuadHelper helper;
97 void* vertices = helper.init(target, vertexStride, instanceCount);
98
99 if (!vertices) {
100 return;
101 }
102
103 for (int i = 0; i < instanceCount; i++) {
104 const Geometry& geom = fGeoData[i];
105
106 intptr_t offset = reinterpret_cast<intptr_t>(vertices) +
107 kVerticesPerQuad * i * vertexStride;
108 SkPoint* positions = reinterpret_cast<SkPoint*>(offset);
109
110 positions->setRectFan(geom.fRect.fLeft, geom.fRect.fTop,
111 geom.fRect.fRight, geom.fRect.fBottom, vertexS tride);
112 geom.fViewMatrix.mapPointsWithStride(positions, vertexStride, kVerti cesPerQuad);
113
114 // TODO we should only do this if local coords are being read
115 if (geom.fHasLocalRect) {
116 static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor );
117 SkPoint* coords = reinterpret_cast<SkPoint*>(offset + kLocalOffs et);
118 coords->setRectFan(geom.fLocalRect.fLeft, geom.fLocalRect.fTop,
119 geom.fLocalRect.fRight, geom.fLocalRect.fBott om,
120 vertexStride);
121 if (geom.fHasLocalMatrix) {
122 geom.fLocalMatrix.mapPointsWithStride(coords, vertexStride, kVerticesPerQuad);
123 }
124 }
125
126 static const int kColorOffset = sizeof(SkPoint);
127 GrColor* vertColor = reinterpret_cast<GrColor*>(offset + kColorOffse t);
128 for (int j = 0; j < 4; ++j) {
129 *vertColor = geom.fColor;
130 vertColor = (GrColor*) ((intptr_t) vertColor + vertexStride);
131 }
132 }
133
134 helper.recordDraw(target);
135 }
136
137 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override {
138 BWFillRectBatch* that = t->cast<BWFillRectBatch>();
139 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pi peline(),
140 that->bounds(), caps)) {
141 return false;
142 }
143
144 if (this->hasLocalRect() != that->hasLocalRect()) {
145 return false;
146 }
147
148 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
149 if (!this->hasLocalRect() && this->usesLocalCoords()) {
150 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
151 return false;
152 }
153
154 if (this->hasLocalMatrix() != that->hasLocalMatrix()) {
155 return false;
156 }
157
158 if (this->hasLocalMatrix() && !this->localMatrix().cheapEqualTo(that ->localMatrix())) {
159 return false;
160 }
161 }
162
163 if (this->color() != that->color()) {
164 fBatch.fColor = GrColor_ILLEGAL;
165 }
166 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin()) ;
167 this->joinBounds(that->bounds());
181 return true; 168 return true;
182 } 169 }
183 170
184 static const GrGeometryProcessor* CreateGP(const Geometry& geo, 171
185 const GrPipelineOptimizations& op ts) { 172 /** We always use per-vertex colors so that rects can be batched across colo r changes. Sometimes
186 const GrGeometryProcessor* gp = create_gp(geo.fViewMatrix, opts.readsCov erage(), true, 173 we have explicit local coords and sometimes not. We *could* always prov ide explicit local
187 NULL); 174 coords and just duplicate the positions when the caller hasn't provided a local coord rect,
188 175 but we haven't seen a use case which frequently switches between local r ect and no local
189 SkASSERT(gp->getVertexStride() == 176 rect draws.
190 sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr)); 177
191 return gp; 178 The color param is used to determine whether the opaque hint can be set on the draw state.
192 } 179 The caller must populate the vertex colors itself.
193 180
194 static void Tesselate(intptr_t vertices, size_t vertexStride, const Geometry & geo, 181 The vertex attrib order is always pos, color, [local coords].
195 const GrPipelineOptimizations& opts) { 182 */
196 tesselate(vertices, vertexStride, geo.fColor, geo.fViewMatrix, geo.fRect , &geo.fLocalRect, 183 const GrGeometryProcessor* createRectGP() const {
197 NULL); 184 using namespace GrDefaultGeoProcFactory;
198 } 185 Color color(Color::kAttribute_Type);
186 Coverage coverage(this->coverageIgnored() ? Coverage::kNone_Type : Cover age::kSolid_Type);
187
188 // if we have a local rect, then we apply the localMatrix directly to th e localRect to
189 // generate vertex local coords
190 if (this->hasLocalRect()) {
191 LocalCoords localCoords(LocalCoords::kHasExplicit_Type);
192 return GrDefaultGeoProcFactory::Create(color, coverage, localCoords, SkMatrix::I());
193 } else {
194 LocalCoords localCoords(LocalCoords::kUsePosition_Type,
195 this->hasLocalMatrix() ? &this->localMatrix( ) : NULL);
196 return GrDefaultGeoProcFactory::CreateForDeviceSpace(color, coverage , localCoords,
197 this->viewMatri x());
198 }
199 }
200
201 struct BatchTracker {
202 GrColor fColor;
203 bool fUsesLocalCoords;
204 bool fColorIgnored;
205 bool fCoverageIgnored;
206 };
207
208 BatchTracker fBatch;
209 SkSTArray<1, Geometry, true> fGeoData;
199 }; 210 };
200 211
201 class BWFillRectBatchLocalMatrixLocalRectImp : public BWFillRectBatchBase {
202 public:
203 struct Geometry {
204 SkMatrix fViewMatrix;
205 SkMatrix fLocalMatrix;
206 SkRect fRect;
207 SkRect fLocalRect;
208 GrColor fColor;
209 };
210
211 static const char* Name() { return "BWFillRectBatchLocalMatrixLocalRect"; }
212
213 static bool CanCombine(const Geometry& mine, const Geometry& theirs,
214 const GrPipelineOptimizations& opts) {
215 return true;
216 }
217
218 static const GrGeometryProcessor* CreateGP(const Geometry& geo,
219 const GrPipelineOptimizations& op ts) {
220 const GrGeometryProcessor* gp = create_gp(geo.fViewMatrix, opts.readsCov erage(), true,
221 NULL);
222
223 SkASSERT(gp->getVertexStride() ==
224 sizeof(GrDefaultGeoProcFactory::PositionColorLocalCoordAttr));
225 return gp;
226 }
227
228 static void Tesselate(intptr_t vertices, size_t vertexStride, const Geometry & geo,
229 const GrPipelineOptimizations& opts) {
230 tesselate(vertices, vertexStride, geo.fColor, geo.fViewMatrix, geo.fRect , &geo.fLocalRect,
231 &geo.fLocalMatrix);
232 }
233 };
234
235 typedef GrTInstanceBatch<BWFillRectBatchNoLocalMatrixImp> BWFillRectBatchSimple;
236 typedef GrTInstanceBatch<BWFillRectBatchLocalMatrixImp> BWFillRectBatchLocalMatr ix;
237 typedef GrTInstanceBatch<BWFillRectBatchLocalRectImp> BWFillRectBatchLocalRect;
238 typedef GrTInstanceBatch<BWFillRectBatchLocalMatrixLocalRectImp> BWFillRectBatch LocalMatrixLocalRect;
239
240 namespace GrBWFillRectBatch { 212 namespace GrBWFillRectBatch {
241 GrDrawBatch* Create(GrColor color, 213 GrDrawBatch* Create(GrColor color,
242 const SkMatrix& viewMatrix, 214 const SkMatrix& viewMatrix,
243 const SkRect& rect, 215 const SkRect& rect,
244 const SkRect* localRect, 216 const SkRect* localRect,
245 const SkMatrix* localMatrix) { 217 const SkMatrix* localMatrix) {
246 // TODO bubble these up as separate calls 218 BWFillRectBatch::Geometry geometry;
247 if (localRect && localMatrix) { 219 geometry.fColor = color;
248 BWFillRectBatchLocalMatrixLocalRect* batch = BWFillRectBatchLocalMatrixL ocalRect::Create(); 220 geometry.fViewMatrix = viewMatrix;
249 BWFillRectBatchLocalMatrixLocalRect::Geometry& geo = *batch->geometry(); 221 geometry.fRect = rect;
250 geo.fColor = color; 222
251 geo.fViewMatrix = viewMatrix; 223 if (localRect) {
252 geo.fLocalMatrix = *localMatrix; 224 geometry.fHasLocalRect = true;
253 geo.fRect = rect; 225 geometry.fLocalRect = *localRect;
254 geo.fLocalRect = *localRect;
255 batch->init();
256 return batch;
257 } else if (localRect) {
258 BWFillRectBatchLocalRect* batch = BWFillRectBatchLocalRect::Create();
259 BWFillRectBatchLocalRect::Geometry& geo = *batch->geometry();
260 geo.fColor = color;
261 geo.fViewMatrix = viewMatrix;
262 geo.fRect = rect;
263 geo.fLocalRect = *localRect;
264 batch->init();
265 return batch;
266 } else if (localMatrix) {
267 BWFillRectBatchLocalMatrix* batch = BWFillRectBatchLocalMatrix::Create() ;
268 BWFillRectBatchLocalMatrix::Geometry& geo = *batch->geometry();
269 geo.fColor = color;
270 geo.fViewMatrix = viewMatrix;
271 geo.fLocalMatrix = *localMatrix;
272 geo.fRect = rect;
273 batch->init();
274 return batch;
275 } else { 226 } else {
276 BWFillRectBatchSimple* batch = BWFillRectBatchSimple::Create(); 227 geometry.fHasLocalRect = false;
277 BWFillRectBatchSimple::Geometry& geo = *batch->geometry();
278 geo.fColor = color;
279 geo.fViewMatrix = viewMatrix;
280 geo.fRect = rect;
281 batch->init();
282 return batch;
283 } 228 }
229
230 if (localMatrix) {
231 geometry.fHasLocalMatrix = true;
232 geometry.fLocalMatrix = *localMatrix;
233 } else {
234 geometry.fHasLocalMatrix = false;
235 }
236
237 return BWFillRectBatch::Create(geometry);
284 } 238 }
285 }; 239 };
286 240
287 //////////////////////////////////////////////////////////////////////////////// /////////////////// 241 //////////////////////////////////////////////////////////////////////////////// ///////////////////
288 242
289 #ifdef GR_TEST_UTILS 243 #ifdef GR_TEST_UTILS
290 244
291 #include "GrBatchTest.h" 245 #include "GrBatchTest.h"
292 246
293 DRAW_BATCH_TEST_DEFINE(RectBatch) { 247 DRAW_BATCH_TEST_DEFINE(RectBatch) {
294 GrColor color = GrRandomColor(random); 248 BWFillRectBatch::Geometry geometry;
295 SkRect rect = GrTest::TestRect(random); 249 geometry.fColor = GrRandomColor(random);
296 SkRect localRect = GrTest::TestRect(random);
297 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
298 SkMatrix localMatrix = GrTest::TestMatrix(random);
299 250
300 bool hasLocalRect = random->nextBool(); 251 geometry.fRect = GrTest::TestRect(random);
301 bool hasLocalMatrix = random->nextBool(); 252 geometry.fHasLocalRect = random->nextBool();
302 return GrBWFillRectBatch::Create(color, viewMatrix, rect, hasLocalRect ? &lo calRect : nullptr, 253
303 hasLocalMatrix ? &localMatrix : nullptr); 254 if (geometry.fHasLocalRect) {
255 geometry.fViewMatrix = GrTest::TestMatrixInvertible(random);
256 geometry.fLocalRect = GrTest::TestRect(random);
257 } else {
258 geometry.fViewMatrix = GrTest::TestMatrix(random);
259 }
260
261 geometry.fHasLocalMatrix = random->nextBool();
262 if (geometry.fHasLocalMatrix) {
263 geometry.fLocalMatrix = GrTest::TestMatrix(random);
264 }
265
266 return BWFillRectBatch::Create(geometry);
304 } 267 }
305 268
306 #endif 269 #endif
OLDNEW
« no previous file with comments | « src/gpu/batches/GrAAFillRectBatch.cpp ('k') | src/gpu/batches/GrTInstanceBatch.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698