blob: faecfe5eed3513a55d72f764d8a34c22e599dff2 [file] [log] [blame]
csmartdaltona7f29642016-07-07 08:49:11 -07001/*
2 * Copyright 2016 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 "InstancedRendering.h"
9
robertphillips5fa7f302016-07-21 09:21:04 -070010#include "GrCaps.h"
Brian Salomon742e31d2016-12-07 17:06:19 -050011#include "GrOpFlushState.h"
csmartdaltona7f29642016-07-07 08:49:11 -070012#include "GrPipeline.h"
13#include "GrResourceProvider.h"
14#include "instanced/InstanceProcessor.h"
15
16namespace gr_instanced {
17
csmartdaltone0d36292016-07-29 08:14:20 -070018InstancedRendering::InstancedRendering(GrGpu* gpu)
csmartdaltona7f29642016-07-07 08:49:11 -070019 : fGpu(SkRef(gpu)),
csmartdaltona7f29642016-07-07 08:49:11 -070020 fState(State::kRecordingDraws),
dskibae4cd0062016-11-29 06:50:35 -080021 fDrawPool(1024, 1024) {
csmartdaltona7f29642016-07-07 08:49:11 -070022}
23
Brian Salomon9afd3712016-12-01 10:59:09 -050024GrDrawOp* InstancedRendering::recordRect(const SkRect& rect, const SkMatrix& viewMatrix,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -050025 GrColor color, GrAA aa,
26 const GrInstancedPipelineInfo& info, GrAAType* aaType) {
27 return this->recordShape(ShapeType::kRect, rect, viewMatrix, color, rect, aa, info, aaType);
csmartdaltona7f29642016-07-07 08:49:11 -070028}
29
Brian Salomon9afd3712016-12-01 10:59:09 -050030GrDrawOp* InstancedRendering::recordRect(const SkRect& rect, const SkMatrix& viewMatrix,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -050031 GrColor color, const SkRect& localRect, GrAA aa,
32 const GrInstancedPipelineInfo& info, GrAAType* aaType) {
33 return this->recordShape(ShapeType::kRect, rect, viewMatrix, color, localRect, aa, info,
34 aaType);
csmartdaltona7f29642016-07-07 08:49:11 -070035}
36
Brian Salomon9afd3712016-12-01 10:59:09 -050037GrDrawOp* InstancedRendering::recordRect(const SkRect& rect, const SkMatrix& viewMatrix,
38 GrColor color, const SkMatrix& localMatrix,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -050039 GrAA aa, const GrInstancedPipelineInfo& info,
40 GrAAType* aaType) {
csmartdaltona7f29642016-07-07 08:49:11 -070041 if (localMatrix.hasPerspective()) {
42 return nullptr; // Perspective is not yet supported in the local matrix.
43 }
Brian Salomon0e8fc8b2016-12-09 15:10:07 -050044 if (Batch* batch = this->recordShape(ShapeType::kRect, rect, viewMatrix, color, rect, aa,
45 info, aaType)) {
csmartdaltona7f29642016-07-07 08:49:11 -070046 batch->getSingleInstance().fInfo |= kLocalMatrix_InfoFlag;
47 batch->appendParamsTexel(localMatrix.getScaleX(), localMatrix.getSkewX(),
48 localMatrix.getTranslateX());
49 batch->appendParamsTexel(localMatrix.getSkewY(), localMatrix.getScaleY(),
50 localMatrix.getTranslateY());
51 batch->fInfo.fHasLocalMatrix = true;
52 return batch;
53 }
54 return nullptr;
55}
56
Brian Salomon9afd3712016-12-01 10:59:09 -050057GrDrawOp* InstancedRendering::recordOval(const SkRect& oval, const SkMatrix& viewMatrix,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -050058 GrColor color, GrAA aa,
59 const GrInstancedPipelineInfo& info, GrAAType* aaType) {
60 return this->recordShape(ShapeType::kOval, oval, viewMatrix, color, oval, aa, info, aaType);
csmartdaltona7f29642016-07-07 08:49:11 -070061}
62
Brian Salomon9afd3712016-12-01 10:59:09 -050063GrDrawOp* InstancedRendering::recordRRect(const SkRRect& rrect, const SkMatrix& viewMatrix,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -050064 GrColor color, GrAA aa,
65 const GrInstancedPipelineInfo& info, GrAAType* aaType) {
csmartdaltona7f29642016-07-07 08:49:11 -070066 if (Batch* batch = this->recordShape(GetRRectShapeType(rrect), rrect.rect(), viewMatrix, color,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -050067 rrect.rect(), aa, info, aaType)) {
csmartdaltona7f29642016-07-07 08:49:11 -070068 batch->appendRRectParams(rrect);
69 return batch;
70 }
71 return nullptr;
72}
73
Brian Salomon9afd3712016-12-01 10:59:09 -050074GrDrawOp* InstancedRendering::recordDRRect(const SkRRect& outer, const SkRRect& inner,
75 const SkMatrix& viewMatrix, GrColor color,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -050076 GrAA aa, const GrInstancedPipelineInfo& info,
77 GrAAType* aaType) {
csmartdaltona7f29642016-07-07 08:49:11 -070078 if (inner.getType() > SkRRect::kSimple_Type) {
79 return nullptr; // Complex inner round rects are not yet supported.
80 }
81 if (SkRRect::kEmpty_Type == inner.getType()) {
Brian Salomon0e8fc8b2016-12-09 15:10:07 -050082 return this->recordRRect(outer, viewMatrix, color, aa, info, aaType);
csmartdaltona7f29642016-07-07 08:49:11 -070083 }
84 if (Batch* batch = this->recordShape(GetRRectShapeType(outer), outer.rect(), viewMatrix, color,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -050085 outer.rect(), aa, info, aaType)) {
csmartdaltona7f29642016-07-07 08:49:11 -070086 batch->appendRRectParams(outer);
87 ShapeType innerShapeType = GetRRectShapeType(inner);
88 batch->fInfo.fInnerShapeTypes |= GetShapeFlag(innerShapeType);
89 batch->getSingleInstance().fInfo |= ((int)innerShapeType << kInnerShapeType_InfoBit);
90 batch->appendParamsTexel(inner.rect().asScalars(), 4);
91 batch->appendRRectParams(inner);
92 return batch;
93 }
94 return nullptr;
95}
96
97InstancedRendering::Batch* InstancedRendering::recordShape(ShapeType type, const SkRect& bounds,
98 const SkMatrix& viewMatrix,
99 GrColor color, const SkRect& localRect,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500100 GrAA aa,
csmartdaltona7f29642016-07-07 08:49:11 -0700101 const GrInstancedPipelineInfo& info,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500102 GrAAType* aaType) {
csmartdaltona7f29642016-07-07 08:49:11 -0700103 SkASSERT(State::kRecordingDraws == fState);
104
csmartdaltone0d36292016-07-29 08:14:20 -0700105 if (info.fIsRenderingToFloat && fGpu->caps()->avoidInstancedDrawsToFPTargets()) {
csmartdaltona7f29642016-07-07 08:49:11 -0700106 return nullptr;
107 }
108
109 AntialiasMode antialiasMode;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500110 if (!this->selectAntialiasMode(viewMatrix, aa, info, aaType, &antialiasMode)) {
csmartdaltona7f29642016-07-07 08:49:11 -0700111 return nullptr;
112 }
113
114 Batch* batch = this->createBatch();
115 batch->fInfo.fAntialiasMode = antialiasMode;
116 batch->fInfo.fShapeTypes = GetShapeFlag(type);
117 batch->fInfo.fCannotDiscard = !info.fCanDiscard;
118
119 Instance& instance = batch->getSingleInstance();
120 instance.fInfo = (int)type << kShapeType_InfoBit;
121
bsalomon88cf17d2016-07-08 06:40:56 -0700122 Batch::HasAABloat aaBloat = (antialiasMode == AntialiasMode::kCoverage)
123 ? Batch::HasAABloat::kYes
124 : Batch::HasAABloat::kNo;
125 Batch::IsZeroArea zeroArea = (bounds.isEmpty()) ? Batch::IsZeroArea::kYes
126 : Batch::IsZeroArea::kNo;
127
csmartdaltona7f29642016-07-07 08:49:11 -0700128 // The instanced shape renderer draws rectangles of [-1, -1, +1, +1], so we find the matrix that
129 // will map this rectangle to the same device coordinates as "viewMatrix * bounds".
130 float sx = 0.5f * bounds.width();
131 float sy = 0.5f * bounds.height();
132 float tx = sx + bounds.fLeft;
133 float ty = sy + bounds.fTop;
134 if (!viewMatrix.hasPerspective()) {
135 float* m = instance.fShapeMatrix2x3;
136 m[0] = viewMatrix.getScaleX() * sx;
137 m[1] = viewMatrix.getSkewX() * sy;
138 m[2] = viewMatrix.getTranslateX() +
139 viewMatrix.getScaleX() * tx + viewMatrix.getSkewX() * ty;
140
141 m[3] = viewMatrix.getSkewY() * sx;
142 m[4] = viewMatrix.getScaleY() * sy;
143 m[5] = viewMatrix.getTranslateY() +
144 viewMatrix.getSkewY() * tx + viewMatrix.getScaleY() * ty;
145
146 // Since 'm' is a 2x3 matrix that maps the rect [-1, +1] into the shape's device-space quad,
147 // it's quite simple to find the bounding rectangle:
148 float devBoundsHalfWidth = fabsf(m[0]) + fabsf(m[1]);
149 float devBoundsHalfHeight = fabsf(m[3]) + fabsf(m[4]);
bsalomon88cf17d2016-07-08 06:40:56 -0700150 SkRect batchBounds;
151 batchBounds.fLeft = m[2] - devBoundsHalfWidth;
152 batchBounds.fRight = m[2] + devBoundsHalfWidth;
153 batchBounds.fTop = m[5] - devBoundsHalfHeight;
154 batchBounds.fBottom = m[5] + devBoundsHalfHeight;
155 batch->setBounds(batchBounds, aaBloat, zeroArea);
csmartdaltona7f29642016-07-07 08:49:11 -0700156
157 // TODO: Is this worth the CPU overhead?
158 batch->fInfo.fNonSquare =
159 fabsf(devBoundsHalfHeight - devBoundsHalfWidth) > 0.5f || // Early out.
160 fabs(m[0] * m[3] + m[1] * m[4]) > 1e-3f || // Skew?
161 fabs(m[0] * m[0] + m[1] * m[1] - m[3] * m[3] - m[4] * m[4]) > 1e-2f; // Diff. lengths?
162 } else {
163 SkMatrix shapeMatrix(viewMatrix);
164 shapeMatrix.preTranslate(tx, ty);
165 shapeMatrix.preScale(sx, sy);
166 instance.fInfo |= kPerspective_InfoFlag;
167
168 float* m = instance.fShapeMatrix2x3;
169 m[0] = SkScalarToFloat(shapeMatrix.getScaleX());
170 m[1] = SkScalarToFloat(shapeMatrix.getSkewX());
171 m[2] = SkScalarToFloat(shapeMatrix.getTranslateX());
172 m[3] = SkScalarToFloat(shapeMatrix.getSkewY());
173 m[4] = SkScalarToFloat(shapeMatrix.getScaleY());
174 m[5] = SkScalarToFloat(shapeMatrix.getTranslateY());
175
176 // Send the perspective column as a param.
177 batch->appendParamsTexel(shapeMatrix[SkMatrix::kMPersp0], shapeMatrix[SkMatrix::kMPersp1],
178 shapeMatrix[SkMatrix::kMPersp2]);
179 batch->fInfo.fHasPerspective = true;
180
bsalomon88cf17d2016-07-08 06:40:56 -0700181 batch->setBounds(bounds, aaBloat, zeroArea);
csmartdaltona7f29642016-07-07 08:49:11 -0700182 batch->fInfo.fNonSquare = true;
183 }
184
185 instance.fColor = color;
186
187 const float* rectAsFloats = localRect.asScalars(); // Ensure SkScalar == float.
188 memcpy(&instance.fLocalRect, rectAsFloats, 4 * sizeof(float));
189
bsalomon88cf17d2016-07-08 06:40:56 -0700190 batch->fPixelLoad = batch->bounds().height() * batch->bounds().width();
csmartdaltona7f29642016-07-07 08:49:11 -0700191 return batch;
192}
193
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500194inline bool InstancedRendering::selectAntialiasMode(const SkMatrix& viewMatrix, GrAA aa,
csmartdaltona7f29642016-07-07 08:49:11 -0700195 const GrInstancedPipelineInfo& info,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500196 GrAAType* aaType,
197 AntialiasMode* antialiasMode) {
csmartdaltona7f29642016-07-07 08:49:11 -0700198 SkASSERT(!info.fColorDisabled || info.fDrawingShapeToStencil);
199 SkASSERT(!info.fIsMixedSampled || info.fIsMultisampled);
csmartdaltone0d36292016-07-29 08:14:20 -0700200 SkASSERT(GrCaps::InstancedSupport::kNone != fGpu->caps()->instancedSupport());
csmartdaltona7f29642016-07-07 08:49:11 -0700201
202 if (!info.fIsMultisampled || fGpu->caps()->multisampleDisableSupport()) {
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500203 if (GrAA::kNo == aa) {
csmartdaltona7f29642016-07-07 08:49:11 -0700204 if (info.fDrawingShapeToStencil && !info.fCanDiscard) {
205 // We can't draw to the stencil buffer without discard (or sample mask if MSAA).
206 return false;
207 }
208 *antialiasMode = AntialiasMode::kNone;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500209 *aaType = GrAAType::kNone;
csmartdaltona7f29642016-07-07 08:49:11 -0700210 return true;
211 }
212
213 if (info.canUseCoverageAA() && viewMatrix.preservesRightAngles()) {
214 *antialiasMode = AntialiasMode::kCoverage;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500215 *aaType = GrAAType::kCoverage;
csmartdaltona7f29642016-07-07 08:49:11 -0700216 return true;
217 }
218 }
219
csmartdaltone0d36292016-07-29 08:14:20 -0700220 if (info.fIsMultisampled &&
221 fGpu->caps()->instancedSupport() >= GrCaps::InstancedSupport::kMultisampled) {
csmartdaltona7f29642016-07-07 08:49:11 -0700222 if (!info.fIsMixedSampled || info.fColorDisabled) {
223 *antialiasMode = AntialiasMode::kMSAA;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500224 *aaType = GrAAType::kMSAA;
csmartdaltona7f29642016-07-07 08:49:11 -0700225 return true;
226 }
csmartdaltone0d36292016-07-29 08:14:20 -0700227 if (fGpu->caps()->instancedSupport() >= GrCaps::InstancedSupport::kMixedSampled) {
csmartdaltona7f29642016-07-07 08:49:11 -0700228 *antialiasMode = AntialiasMode::kMixedSamples;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500229 *aaType = GrAAType::kMixedSamples;
csmartdaltona7f29642016-07-07 08:49:11 -0700230 return true;
231 }
232 }
233
234 return false;
235}
236
237InstancedRendering::Batch::Batch(uint32_t classID, InstancedRendering* ir)
238 : INHERITED(classID),
239 fInstancedRendering(ir),
240 fIsTracked(false),
241 fNumDraws(1),
242 fNumChangesInGeometry(0) {
dskibae4cd0062016-11-29 06:50:35 -0800243 fHeadDraw = fTailDraw = fInstancedRendering->fDrawPool.allocate();
csmartdaltona7f29642016-07-07 08:49:11 -0700244#ifdef SK_DEBUG
245 fHeadDraw->fGeometry = {-1, 0};
246#endif
247 fHeadDraw->fNext = nullptr;
248}
249
250InstancedRendering::Batch::~Batch() {
251 if (fIsTracked) {
252 fInstancedRendering->fTrackedBatches.remove(this);
253 }
254
255 Draw* draw = fHeadDraw;
256 while (draw) {
257 Draw* next = draw->fNext;
258 fInstancedRendering->fDrawPool.release(draw);
259 draw = next;
260 }
261}
262
263void InstancedRendering::Batch::appendRRectParams(const SkRRect& rrect) {
264 SkASSERT(!fIsTracked);
265 switch (rrect.getType()) {
266 case SkRRect::kSimple_Type: {
267 const SkVector& radii = rrect.getSimpleRadii();
268 this->appendParamsTexel(radii.x(), radii.y(), rrect.width(), rrect.height());
269 return;
270 }
271 case SkRRect::kNinePatch_Type: {
272 float twoOverW = 2 / rrect.width();
273 float twoOverH = 2 / rrect.height();
274 const SkVector& radiiTL = rrect.radii(SkRRect::kUpperLeft_Corner);
275 const SkVector& radiiBR = rrect.radii(SkRRect::kLowerRight_Corner);
276 this->appendParamsTexel(radiiTL.x() * twoOverW, radiiBR.x() * twoOverW,
277 radiiTL.y() * twoOverH, radiiBR.y() * twoOverH);
278 return;
279 }
280 case SkRRect::kComplex_Type: {
281 /**
282 * The x and y radii of each arc are stored in separate vectors,
283 * in the following order:
284 *
285 * __x1 _ _ _ x3__
286 * y1 | | y2
287 *
288 * | |
289 *
290 * y3 |__ _ _ _ __| y4
291 * x2 x4
292 *
293 */
294 float twoOverW = 2 / rrect.width();
295 float twoOverH = 2 / rrect.height();
296 const SkVector& radiiTL = rrect.radii(SkRRect::kUpperLeft_Corner);
297 const SkVector& radiiTR = rrect.radii(SkRRect::kUpperRight_Corner);
298 const SkVector& radiiBR = rrect.radii(SkRRect::kLowerRight_Corner);
299 const SkVector& radiiBL = rrect.radii(SkRRect::kLowerLeft_Corner);
300 this->appendParamsTexel(radiiTL.x() * twoOverW, radiiBL.x() * twoOverW,
301 radiiTR.x() * twoOverW, radiiBR.x() * twoOverW);
302 this->appendParamsTexel(radiiTL.y() * twoOverH, radiiTR.y() * twoOverH,
303 radiiBL.y() * twoOverH, radiiBR.y() * twoOverH);
304 return;
305 }
306 default: return;
307 }
308}
309
310void InstancedRendering::Batch::appendParamsTexel(const SkScalar* vals, int count) {
311 SkASSERT(!fIsTracked);
312 SkASSERT(count <= 4 && count >= 0);
313 const float* valsAsFloats = vals; // Ensure SkScalar == float.
314 memcpy(&fParams.push_back(), valsAsFloats, count * sizeof(float));
315 fInfo.fHasParams = true;
316}
317
318void InstancedRendering::Batch::appendParamsTexel(SkScalar x, SkScalar y, SkScalar z, SkScalar w) {
319 SkASSERT(!fIsTracked);
320 ParamsTexel& texel = fParams.push_back();
321 texel.fX = SkScalarToFloat(x);
322 texel.fY = SkScalarToFloat(y);
323 texel.fZ = SkScalarToFloat(z);
324 texel.fW = SkScalarToFloat(w);
325 fInfo.fHasParams = true;
326}
327
328void InstancedRendering::Batch::appendParamsTexel(SkScalar x, SkScalar y, SkScalar z) {
329 SkASSERT(!fIsTracked);
330 ParamsTexel& texel = fParams.push_back();
331 texel.fX = SkScalarToFloat(x);
332 texel.fY = SkScalarToFloat(y);
333 texel.fZ = SkScalarToFloat(z);
334 fInfo.fHasParams = true;
335}
336
337void InstancedRendering::Batch::computePipelineOptimizations(GrInitInvariantOutput* color,
338 GrInitInvariantOutput* coverage,
339 GrBatchToXPOverrides* overrides) const {
340 color->setKnownFourComponents(this->getSingleInstance().fColor);
341
342 if (AntialiasMode::kCoverage == fInfo.fAntialiasMode ||
343 (AntialiasMode::kNone == fInfo.fAntialiasMode &&
344 !fInfo.isSimpleRects() && fInfo.fCannotDiscard)) {
345 coverage->setUnknownSingleComponent();
346 } else {
347 coverage->setKnownSingleComponent(255);
348 }
349}
350
351void InstancedRendering::Batch::initBatchTracker(const GrXPOverridesForBatch& overrides) {
352 Draw& draw = this->getSingleDraw(); // This will assert if we have > 1 command.
353 SkASSERT(draw.fGeometry.isEmpty());
354 SkASSERT(SkIsPow2(fInfo.fShapeTypes));
355 SkASSERT(!fIsTracked);
356
357 if (kRect_ShapeFlag == fInfo.fShapeTypes) {
358 draw.fGeometry = InstanceProcessor::GetIndexRangeForRect(fInfo.fAntialiasMode);
359 } else if (kOval_ShapeFlag == fInfo.fShapeTypes) {
bsalomon88cf17d2016-07-08 06:40:56 -0700360 draw.fGeometry = InstanceProcessor::GetIndexRangeForOval(fInfo.fAntialiasMode,
361 this->bounds());
csmartdaltona7f29642016-07-07 08:49:11 -0700362 } else {
363 draw.fGeometry = InstanceProcessor::GetIndexRangeForRRect(fInfo.fAntialiasMode);
364 }
365
366 if (!fParams.empty()) {
367 SkASSERT(fInstancedRendering->fParams.count() < (int)kParamsIdx_InfoMask); // TODO: cleaner.
368 this->getSingleInstance().fInfo |= fInstancedRendering->fParams.count();
369 fInstancedRendering->fParams.push_back_n(fParams.count(), fParams.begin());
370 }
371
372 GrColor overrideColor;
373 if (overrides.getOverrideColorIfSet(&overrideColor)) {
374 SkASSERT(State::kRecordingDraws == fInstancedRendering->fState);
375 this->getSingleInstance().fColor = overrideColor;
376 }
377 fInfo.fUsesLocalCoords = overrides.readsLocalCoords();
378 fInfo.fCannotTweakAlphaForCoverage = !overrides.canTweakAlphaForCoverage();
379
380 fInstancedRendering->fTrackedBatches.addToTail(this);
381 fIsTracked = true;
382}
383
Brian Salomon25a88092016-12-01 09:36:50 -0500384bool InstancedRendering::Batch::onCombineIfPossible(GrOp* other, const GrCaps& caps) {
csmartdaltona7f29642016-07-07 08:49:11 -0700385 Batch* that = static_cast<Batch*>(other);
386 SkASSERT(fInstancedRendering == that->fInstancedRendering);
387 SkASSERT(fTailDraw);
388 SkASSERT(that->fTailDraw);
389
390 if (!BatchInfo::CanCombine(fInfo, that->fInfo) ||
391 !GrPipeline::CanCombine(*this->pipeline(), this->bounds(),
392 *that->pipeline(), that->bounds(), caps)) {
393 return false;
394 }
395
396 BatchInfo combinedInfo = fInfo | that->fInfo;
397 if (!combinedInfo.isSimpleRects()) {
398 // This threshold was chosen with the "shapes_mixed" bench on a MacBook with Intel graphics.
399 // There seems to be a wide range where it doesn't matter if we combine or not. What matters
400 // is that the itty bitty rects combine with other shapes and the giant ones don't.
401 constexpr SkScalar kMaxPixelsToGeneralizeRects = 256 * 256;
402 if (fInfo.isSimpleRects() && fPixelLoad > kMaxPixelsToGeneralizeRects) {
403 return false;
404 }
405 if (that->fInfo.isSimpleRects() && that->fPixelLoad > kMaxPixelsToGeneralizeRects) {
406 return false;
407 }
408 }
409
bsalomon88cf17d2016-07-08 06:40:56 -0700410 this->joinBounds(*that);
csmartdaltona7f29642016-07-07 08:49:11 -0700411 fInfo = combinedInfo;
412 fPixelLoad += that->fPixelLoad;
413
414 // Adopt the other batch's draws.
415 fNumDraws += that->fNumDraws;
416 fNumChangesInGeometry += that->fNumChangesInGeometry;
417 if (fTailDraw->fGeometry != that->fHeadDraw->fGeometry) {
418 ++fNumChangesInGeometry;
419 }
420 fTailDraw->fNext = that->fHeadDraw;
421 fTailDraw = that->fTailDraw;
422
423 that->fHeadDraw = that->fTailDraw = nullptr;
424
425 return true;
426}
427
428void InstancedRendering::beginFlush(GrResourceProvider* rp) {
429 SkASSERT(State::kRecordingDraws == fState);
430 fState = State::kFlushing;
431
432 if (fTrackedBatches.isEmpty()) {
433 return;
434 }
435
436 if (!fVertexBuffer) {
Hal Canary144caf52016-11-07 17:57:18 -0500437 fVertexBuffer.reset(InstanceProcessor::FindOrCreateVertexBuffer(fGpu.get()));
csmartdaltona7f29642016-07-07 08:49:11 -0700438 if (!fVertexBuffer) {
439 return;
440 }
441 }
442
443 if (!fIndexBuffer) {
Hal Canary144caf52016-11-07 17:57:18 -0500444 fIndexBuffer.reset(InstanceProcessor::FindOrCreateIndex8Buffer(fGpu.get()));
csmartdaltona7f29642016-07-07 08:49:11 -0700445 if (!fIndexBuffer) {
446 return;
447 }
448 }
449
450 if (!fParams.empty()) {
451 fParamsBuffer.reset(rp->createBuffer(fParams.count() * sizeof(ParamsTexel),
452 kTexel_GrBufferType, kDynamic_GrAccessPattern,
csmartdalton485a1202016-07-13 10:16:32 -0700453 GrResourceProvider::kNoPendingIO_Flag |
454 GrResourceProvider::kRequireGpuMemory_Flag,
csmartdaltona7f29642016-07-07 08:49:11 -0700455 fParams.begin()));
456 if (!fParamsBuffer) {
457 return;
458 }
459 }
460
461 this->onBeginFlush(rp);
462}
463
Brian Salomon742e31d2016-12-07 17:06:19 -0500464void InstancedRendering::Batch::onDraw(GrOpFlushState* state, const SkRect& bounds) {
csmartdaltona7f29642016-07-07 08:49:11 -0700465 SkASSERT(State::kFlushing == fInstancedRendering->fState);
466 SkASSERT(state->gpu() == fInstancedRendering->gpu());
467
468 state->gpu()->handleDirtyContext();
469 if (GrXferBarrierType barrierType = this->pipeline()->xferBarrierType(*state->gpu()->caps())) {
470 state->gpu()->xferBarrier(this->pipeline()->getRenderTarget(), barrierType);
471 }
472
Hal Canary144caf52016-11-07 17:57:18 -0500473 InstanceProcessor instProc(fInfo, fInstancedRendering->fParamsBuffer.get());
csmartdaltona7f29642016-07-07 08:49:11 -0700474 fInstancedRendering->onDraw(*this->pipeline(), instProc, this);
475}
476
477void InstancedRendering::endFlush() {
478 // The caller is expected to delete all tracked batches (i.e. batches whose initBatchTracker
479 // method has been called) before ending the flush.
480 SkASSERT(fTrackedBatches.isEmpty());
481 fParams.reset();
482 fParamsBuffer.reset();
483 this->onEndFlush();
484 fState = State::kRecordingDraws;
485 // Hold on to the shape coords and index buffers.
486}
487
488void InstancedRendering::resetGpuResources(ResetType resetType) {
489 fVertexBuffer.reset();
490 fIndexBuffer.reset();
491 fParamsBuffer.reset();
492 this->onResetGpuResources(resetType);
493}
494
495}