blob: 127dca3b033d2ae2a25d32e08963a4410747a66e [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 Salomonf8334782017-01-03 09:42:58 -050024std::unique_ptr<GrDrawOp> InstancedRendering::recordRect(const SkRect& rect,
25 const SkMatrix& viewMatrix, GrColor color,
26 GrAA aa,
27 const GrInstancedPipelineInfo& info,
28 GrAAType* aaType) {
Brian Salomon0e8fc8b2016-12-09 15:10:07 -050029 return this->recordShape(ShapeType::kRect, rect, viewMatrix, color, rect, aa, info, aaType);
csmartdaltona7f29642016-07-07 08:49:11 -070030}
31
Brian Salomonf8334782017-01-03 09:42:58 -050032std::unique_ptr<GrDrawOp> InstancedRendering::recordRect(const SkRect& rect,
33 const SkMatrix& viewMatrix, GrColor color,
34 const SkRect& localRect, GrAA aa,
35 const GrInstancedPipelineInfo& info,
36 GrAAType* aaType) {
Brian Salomon0e8fc8b2016-12-09 15:10:07 -050037 return this->recordShape(ShapeType::kRect, rect, viewMatrix, color, localRect, aa, info,
38 aaType);
csmartdaltona7f29642016-07-07 08:49:11 -070039}
40
Brian Salomonf8334782017-01-03 09:42:58 -050041std::unique_ptr<GrDrawOp> InstancedRendering::recordRect(const SkRect& rect,
42 const SkMatrix& viewMatrix, GrColor color,
43 const SkMatrix& localMatrix, GrAA aa,
44 const GrInstancedPipelineInfo& info,
45 GrAAType* aaType) {
csmartdaltona7f29642016-07-07 08:49:11 -070046 if (localMatrix.hasPerspective()) {
47 return nullptr; // Perspective is not yet supported in the local matrix.
48 }
Brian Salomonf8334782017-01-03 09:42:58 -050049 if (std::unique_ptr<Op> op = this->recordShape(ShapeType::kRect, rect, viewMatrix, color, rect,
50 aa, info, aaType)) {
Brian Salomon99ad1642016-12-16 09:50:45 -050051 op->getSingleInstance().fInfo |= kLocalMatrix_InfoFlag;
52 op->appendParamsTexel(localMatrix.getScaleX(), localMatrix.getSkewX(),
53 localMatrix.getTranslateX());
54 op->appendParamsTexel(localMatrix.getSkewY(), localMatrix.getScaleY(),
55 localMatrix.getTranslateY());
56 op->fInfo.fHasLocalMatrix = true;
57 return std::move(op);
csmartdaltona7f29642016-07-07 08:49:11 -070058 }
59 return nullptr;
60}
61
Brian Salomonf8334782017-01-03 09:42:58 -050062std::unique_ptr<GrDrawOp> InstancedRendering::recordOval(const SkRect& oval,
63 const SkMatrix& viewMatrix, GrColor color,
64 GrAA aa,
65 const GrInstancedPipelineInfo& info,
66 GrAAType* aaType) {
Brian Salomon0e8fc8b2016-12-09 15:10:07 -050067 return this->recordShape(ShapeType::kOval, oval, viewMatrix, color, oval, aa, info, aaType);
csmartdaltona7f29642016-07-07 08:49:11 -070068}
69
Brian Salomonf8334782017-01-03 09:42:58 -050070std::unique_ptr<GrDrawOp> InstancedRendering::recordRRect(const SkRRect& rrect,
71 const SkMatrix& viewMatrix, GrColor color,
72 GrAA aa,
73 const GrInstancedPipelineInfo& info,
74 GrAAType* aaType) {
75 if (std::unique_ptr<Op> op =
76 this->recordShape(GetRRectShapeType(rrect), rrect.rect(), viewMatrix, color,
77 rrect.rect(), aa, info, aaType)) {
Brian Salomon99ad1642016-12-16 09:50:45 -050078 op->appendRRectParams(rrect);
79 return std::move(op);
csmartdaltona7f29642016-07-07 08:49:11 -070080 }
81 return nullptr;
82}
83
Brian Salomonf8334782017-01-03 09:42:58 -050084std::unique_ptr<GrDrawOp> InstancedRendering::recordDRRect(
85 const SkRRect& outer, const SkRRect& inner, const SkMatrix& viewMatrix, GrColor color,
86 GrAA aa, const GrInstancedPipelineInfo& info, GrAAType* aaType) {
csmartdaltona7f29642016-07-07 08:49:11 -070087 if (inner.getType() > SkRRect::kSimple_Type) {
88 return nullptr; // Complex inner round rects are not yet supported.
89 }
90 if (SkRRect::kEmpty_Type == inner.getType()) {
Brian Salomon0e8fc8b2016-12-09 15:10:07 -050091 return this->recordRRect(outer, viewMatrix, color, aa, info, aaType);
csmartdaltona7f29642016-07-07 08:49:11 -070092 }
Brian Salomonf8334782017-01-03 09:42:58 -050093 if (std::unique_ptr<Op> op =
94 this->recordShape(GetRRectShapeType(outer), outer.rect(), viewMatrix, color,
95 outer.rect(), aa, info, aaType)) {
Brian Salomon99ad1642016-12-16 09:50:45 -050096 op->appendRRectParams(outer);
csmartdaltona7f29642016-07-07 08:49:11 -070097 ShapeType innerShapeType = GetRRectShapeType(inner);
Brian Salomon99ad1642016-12-16 09:50:45 -050098 op->fInfo.fInnerShapeTypes |= GetShapeFlag(innerShapeType);
99 op->getSingleInstance().fInfo |= ((int)innerShapeType << kInnerShapeType_InfoBit);
100 op->appendParamsTexel(inner.rect().asScalars(), 4);
101 op->appendRRectParams(inner);
102 return std::move(op);
csmartdaltona7f29642016-07-07 08:49:11 -0700103 }
104 return nullptr;
105}
106
Brian Salomonf8334782017-01-03 09:42:58 -0500107std::unique_ptr<InstancedRendering::Op> InstancedRendering::recordShape(
Brian Salomon99ad1642016-12-16 09:50:45 -0500108 ShapeType type, const SkRect& bounds, const SkMatrix& viewMatrix, GrColor color,
109 const SkRect& localRect, GrAA aa, const GrInstancedPipelineInfo& info, GrAAType* aaType) {
csmartdaltona7f29642016-07-07 08:49:11 -0700110 SkASSERT(State::kRecordingDraws == fState);
111
csmartdaltone0d36292016-07-29 08:14:20 -0700112 if (info.fIsRenderingToFloat && fGpu->caps()->avoidInstancedDrawsToFPTargets()) {
csmartdaltona7f29642016-07-07 08:49:11 -0700113 return nullptr;
114 }
115
Brian Salomonaf9847e2017-03-01 11:28:27 -0500116 if (!this->selectAntialiasMode(viewMatrix, aa, info, aaType)) {
csmartdaltona7f29642016-07-07 08:49:11 -0700117 return nullptr;
118 }
119
Brian Salomonf8334782017-01-03 09:42:58 -0500120 std::unique_ptr<Op> op = this->makeOp();
Brian Salomonaf9847e2017-03-01 11:28:27 -0500121 op->fInfo.setAAType(*aaType);
Brian Salomon99ad1642016-12-16 09:50:45 -0500122 op->fInfo.fShapeTypes = GetShapeFlag(type);
123 op->fInfo.fCannotDiscard = !info.fCanDiscard;
csmartdaltona7f29642016-07-07 08:49:11 -0700124
Brian Salomon99ad1642016-12-16 09:50:45 -0500125 Instance& instance = op->getSingleInstance();
csmartdaltona7f29642016-07-07 08:49:11 -0700126 instance.fInfo = (int)type << kShapeType_InfoBit;
127
Brian Salomonaf9847e2017-03-01 11:28:27 -0500128 Op::HasAABloat aaBloat =
129 (*aaType == GrAAType::kCoverage) ? Op::HasAABloat::kYes : Op::HasAABloat::kNo;
Brian Salomon99ad1642016-12-16 09:50:45 -0500130 Op::IsZeroArea zeroArea = (bounds.isEmpty()) ? Op::IsZeroArea::kYes : Op::IsZeroArea::kNo;
bsalomon88cf17d2016-07-08 06:40:56 -0700131
csmartdaltona7f29642016-07-07 08:49:11 -0700132 // The instanced shape renderer draws rectangles of [-1, -1, +1, +1], so we find the matrix that
133 // will map this rectangle to the same device coordinates as "viewMatrix * bounds".
134 float sx = 0.5f * bounds.width();
135 float sy = 0.5f * bounds.height();
136 float tx = sx + bounds.fLeft;
137 float ty = sy + bounds.fTop;
138 if (!viewMatrix.hasPerspective()) {
139 float* m = instance.fShapeMatrix2x3;
140 m[0] = viewMatrix.getScaleX() * sx;
141 m[1] = viewMatrix.getSkewX() * sy;
142 m[2] = viewMatrix.getTranslateX() +
143 viewMatrix.getScaleX() * tx + viewMatrix.getSkewX() * ty;
144
145 m[3] = viewMatrix.getSkewY() * sx;
146 m[4] = viewMatrix.getScaleY() * sy;
147 m[5] = viewMatrix.getTranslateY() +
148 viewMatrix.getSkewY() * tx + viewMatrix.getScaleY() * ty;
149
150 // Since 'm' is a 2x3 matrix that maps the rect [-1, +1] into the shape's device-space quad,
151 // it's quite simple to find the bounding rectangle:
152 float devBoundsHalfWidth = fabsf(m[0]) + fabsf(m[1]);
153 float devBoundsHalfHeight = fabsf(m[3]) + fabsf(m[4]);
Brian Salomon99ad1642016-12-16 09:50:45 -0500154 SkRect opBounds;
155 opBounds.fLeft = m[2] - devBoundsHalfWidth;
156 opBounds.fRight = m[2] + devBoundsHalfWidth;
157 opBounds.fTop = m[5] - devBoundsHalfHeight;
158 opBounds.fBottom = m[5] + devBoundsHalfHeight;
159 op->setBounds(opBounds, aaBloat, zeroArea);
csmartdaltona7f29642016-07-07 08:49:11 -0700160
161 // TODO: Is this worth the CPU overhead?
Brian Salomon99ad1642016-12-16 09:50:45 -0500162 op->fInfo.fNonSquare =
163 fabsf(devBoundsHalfHeight - devBoundsHalfWidth) > 0.5f || // Early out.
164 fabs(m[0] * m[3] + m[1] * m[4]) > 1e-3f || // Skew?
165 fabs(m[0] * m[0] + m[1] * m[1] - m[3] * m[3] - m[4] * m[4]) >
166 1e-2f; // Diff. lengths?
csmartdaltona7f29642016-07-07 08:49:11 -0700167 } else {
168 SkMatrix shapeMatrix(viewMatrix);
169 shapeMatrix.preTranslate(tx, ty);
170 shapeMatrix.preScale(sx, sy);
171 instance.fInfo |= kPerspective_InfoFlag;
172
173 float* m = instance.fShapeMatrix2x3;
174 m[0] = SkScalarToFloat(shapeMatrix.getScaleX());
175 m[1] = SkScalarToFloat(shapeMatrix.getSkewX());
176 m[2] = SkScalarToFloat(shapeMatrix.getTranslateX());
177 m[3] = SkScalarToFloat(shapeMatrix.getSkewY());
178 m[4] = SkScalarToFloat(shapeMatrix.getScaleY());
179 m[5] = SkScalarToFloat(shapeMatrix.getTranslateY());
180
181 // Send the perspective column as a param.
Brian Salomon99ad1642016-12-16 09:50:45 -0500182 op->appendParamsTexel(shapeMatrix[SkMatrix::kMPersp0], shapeMatrix[SkMatrix::kMPersp1],
183 shapeMatrix[SkMatrix::kMPersp2]);
184 op->fInfo.fHasPerspective = true;
csmartdaltona7f29642016-07-07 08:49:11 -0700185
Brian Salomon99ad1642016-12-16 09:50:45 -0500186 op->setBounds(bounds, aaBloat, zeroArea);
187 op->fInfo.fNonSquare = true;
csmartdaltona7f29642016-07-07 08:49:11 -0700188 }
189
190 instance.fColor = color;
191
192 const float* rectAsFloats = localRect.asScalars(); // Ensure SkScalar == float.
193 memcpy(&instance.fLocalRect, rectAsFloats, 4 * sizeof(float));
194
Brian Salomon99ad1642016-12-16 09:50:45 -0500195 op->fPixelLoad = op->bounds().height() * op->bounds().width();
196 return op;
csmartdaltona7f29642016-07-07 08:49:11 -0700197}
198
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500199inline bool InstancedRendering::selectAntialiasMode(const SkMatrix& viewMatrix, GrAA aa,
csmartdaltona7f29642016-07-07 08:49:11 -0700200 const GrInstancedPipelineInfo& info,
Brian Salomonaf9847e2017-03-01 11:28:27 -0500201 GrAAType* aaType) {
csmartdaltona7f29642016-07-07 08:49:11 -0700202 SkASSERT(!info.fColorDisabled || info.fDrawingShapeToStencil);
203 SkASSERT(!info.fIsMixedSampled || info.fIsMultisampled);
csmartdaltone0d36292016-07-29 08:14:20 -0700204 SkASSERT(GrCaps::InstancedSupport::kNone != fGpu->caps()->instancedSupport());
csmartdaltona7f29642016-07-07 08:49:11 -0700205
206 if (!info.fIsMultisampled || fGpu->caps()->multisampleDisableSupport()) {
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500207 if (GrAA::kNo == aa) {
csmartdaltona7f29642016-07-07 08:49:11 -0700208 if (info.fDrawingShapeToStencil && !info.fCanDiscard) {
209 // We can't draw to the stencil buffer without discard (or sample mask if MSAA).
210 return false;
211 }
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500212 *aaType = GrAAType::kNone;
csmartdaltona7f29642016-07-07 08:49:11 -0700213 return true;
214 }
215
216 if (info.canUseCoverageAA() && viewMatrix.preservesRightAngles()) {
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500217 *aaType = GrAAType::kCoverage;
csmartdaltona7f29642016-07-07 08:49:11 -0700218 return true;
219 }
220 }
221
csmartdaltone0d36292016-07-29 08:14:20 -0700222 if (info.fIsMultisampled &&
223 fGpu->caps()->instancedSupport() >= GrCaps::InstancedSupport::kMultisampled) {
csmartdaltona7f29642016-07-07 08:49:11 -0700224 if (!info.fIsMixedSampled || info.fColorDisabled) {
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500225 *aaType = GrAAType::kMSAA;
csmartdaltona7f29642016-07-07 08:49:11 -0700226 return true;
227 }
csmartdaltone0d36292016-07-29 08:14:20 -0700228 if (fGpu->caps()->instancedSupport() >= GrCaps::InstancedSupport::kMixedSampled) {
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
Brian Salomon99ad1642016-12-16 09:50:45 -0500237InstancedRendering::Op::Op(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
Brian Salomon99ad1642016-12-16 09:50:45 -0500250InstancedRendering::Op::~Op() {
csmartdaltona7f29642016-07-07 08:49:11 -0700251 if (fIsTracked) {
Brian Salomon99ad1642016-12-16 09:50:45 -0500252 fInstancedRendering->fTrackedOps.remove(this);
csmartdaltona7f29642016-07-07 08:49:11 -0700253 }
254
255 Draw* draw = fHeadDraw;
256 while (draw) {
257 Draw* next = draw->fNext;
258 fInstancedRendering->fDrawPool.release(draw);
259 draw = next;
260 }
261}
262
Brian Salomon99ad1642016-12-16 09:50:45 -0500263void InstancedRendering::Op::appendRRectParams(const SkRRect& rrect) {
csmartdaltona7f29642016-07-07 08:49:11 -0700264 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
Brian Salomon99ad1642016-12-16 09:50:45 -0500310void InstancedRendering::Op::appendParamsTexel(const SkScalar* vals, int count) {
csmartdaltona7f29642016-07-07 08:49:11 -0700311 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
Brian Salomon99ad1642016-12-16 09:50:45 -0500318void InstancedRendering::Op::appendParamsTexel(SkScalar x, SkScalar y, SkScalar z, SkScalar w) {
csmartdaltona7f29642016-07-07 08:49:11 -0700319 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
Brian Salomon99ad1642016-12-16 09:50:45 -0500328void InstancedRendering::Op::appendParamsTexel(SkScalar x, SkScalar y, SkScalar z) {
csmartdaltona7f29642016-07-07 08:49:11 -0700329 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
Brian Salomon5298dc82017-02-22 11:52:03 -0500337void InstancedRendering::Op::getFragmentProcessorAnalysisInputs(
338 FragmentProcessorAnalysisInputs* input) const {
339 input->colorInput()->setToConstant(this->getSingleInstance().fColor);
csmartdaltona7f29642016-07-07 08:49:11 -0700340
Brian Salomonaf9847e2017-03-01 11:28:27 -0500341 if (GrAAType::kCoverage == fInfo.aaType() ||
342 (GrAAType::kNone == fInfo.aaType() && !fInfo.isSimpleRects() && fInfo.fCannotDiscard)) {
Brian Salomon5298dc82017-02-22 11:52:03 -0500343 input->coverageInput()->setToUnknown();
csmartdaltona7f29642016-07-07 08:49:11 -0700344 } else {
Brian Salomon5298dc82017-02-22 11:52:03 -0500345 input->coverageInput()->setToSolidCoverage();
csmartdaltona7f29642016-07-07 08:49:11 -0700346 }
347}
348
Brian Salomon92aee3d2016-12-21 09:20:25 -0500349void InstancedRendering::Op::applyPipelineOptimizations(
350 const GrPipelineOptimizations& optimizations) {
csmartdaltona7f29642016-07-07 08:49:11 -0700351 Draw& draw = this->getSingleDraw(); // This will assert if we have > 1 command.
352 SkASSERT(draw.fGeometry.isEmpty());
353 SkASSERT(SkIsPow2(fInfo.fShapeTypes));
354 SkASSERT(!fIsTracked);
355
356 if (kRect_ShapeFlag == fInfo.fShapeTypes) {
Brian Salomonaf9847e2017-03-01 11:28:27 -0500357 draw.fGeometry = InstanceProcessor::GetIndexRangeForRect(fInfo.aaType());
csmartdaltona7f29642016-07-07 08:49:11 -0700358 } else if (kOval_ShapeFlag == fInfo.fShapeTypes) {
Brian Salomonaf9847e2017-03-01 11:28:27 -0500359 draw.fGeometry = InstanceProcessor::GetIndexRangeForOval(fInfo.aaType(), this->bounds());
csmartdaltona7f29642016-07-07 08:49:11 -0700360 } else {
Brian Salomonaf9847e2017-03-01 11:28:27 -0500361 draw.fGeometry = InstanceProcessor::GetIndexRangeForRRect(fInfo.aaType());
csmartdaltona7f29642016-07-07 08:49:11 -0700362 }
363
364 if (!fParams.empty()) {
365 SkASSERT(fInstancedRendering->fParams.count() < (int)kParamsIdx_InfoMask); // TODO: cleaner.
366 this->getSingleInstance().fInfo |= fInstancedRendering->fParams.count();
367 fInstancedRendering->fParams.push_back_n(fParams.count(), fParams.begin());
368 }
369
370 GrColor overrideColor;
Brian Salomon92aee3d2016-12-21 09:20:25 -0500371 if (optimizations.getOverrideColorIfSet(&overrideColor)) {
csmartdaltona7f29642016-07-07 08:49:11 -0700372 SkASSERT(State::kRecordingDraws == fInstancedRendering->fState);
373 this->getSingleInstance().fColor = overrideColor;
374 }
Brian Salomon92aee3d2016-12-21 09:20:25 -0500375 fInfo.fUsesLocalCoords = optimizations.readsLocalCoords();
376 fInfo.fCannotTweakAlphaForCoverage = !optimizations.canTweakAlphaForCoverage();
csmartdaltona7f29642016-07-07 08:49:11 -0700377
Brian Salomon99ad1642016-12-16 09:50:45 -0500378 fInstancedRendering->fTrackedOps.addToTail(this);
csmartdaltona7f29642016-07-07 08:49:11 -0700379 fIsTracked = true;
380}
381
Brian Salomon99ad1642016-12-16 09:50:45 -0500382bool InstancedRendering::Op::onCombineIfPossible(GrOp* other, const GrCaps& caps) {
383 Op* that = static_cast<Op*>(other);
csmartdaltona7f29642016-07-07 08:49:11 -0700384 SkASSERT(fInstancedRendering == that->fInstancedRendering);
385 SkASSERT(fTailDraw);
386 SkASSERT(that->fTailDraw);
387
Brian Salomon99ad1642016-12-16 09:50:45 -0500388 if (!OpInfo::CanCombine(fInfo, that->fInfo) ||
389 !GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
390 that->bounds(), caps)) {
csmartdaltona7f29642016-07-07 08:49:11 -0700391 return false;
392 }
393
Brian Salomon99ad1642016-12-16 09:50:45 -0500394 OpInfo combinedInfo = fInfo | that->fInfo;
csmartdaltona7f29642016-07-07 08:49:11 -0700395 if (!combinedInfo.isSimpleRects()) {
396 // This threshold was chosen with the "shapes_mixed" bench on a MacBook with Intel graphics.
397 // There seems to be a wide range where it doesn't matter if we combine or not. What matters
398 // is that the itty bitty rects combine with other shapes and the giant ones don't.
399 constexpr SkScalar kMaxPixelsToGeneralizeRects = 256 * 256;
400 if (fInfo.isSimpleRects() && fPixelLoad > kMaxPixelsToGeneralizeRects) {
401 return false;
402 }
403 if (that->fInfo.isSimpleRects() && that->fPixelLoad > kMaxPixelsToGeneralizeRects) {
404 return false;
405 }
406 }
407
bsalomon88cf17d2016-07-08 06:40:56 -0700408 this->joinBounds(*that);
csmartdaltona7f29642016-07-07 08:49:11 -0700409 fInfo = combinedInfo;
410 fPixelLoad += that->fPixelLoad;
411
Brian Salomon99ad1642016-12-16 09:50:45 -0500412 // Adopt the other op's draws.
csmartdaltona7f29642016-07-07 08:49:11 -0700413 fNumDraws += that->fNumDraws;
414 fNumChangesInGeometry += that->fNumChangesInGeometry;
415 if (fTailDraw->fGeometry != that->fHeadDraw->fGeometry) {
416 ++fNumChangesInGeometry;
417 }
418 fTailDraw->fNext = that->fHeadDraw;
419 fTailDraw = that->fTailDraw;
420
421 that->fHeadDraw = that->fTailDraw = nullptr;
422
423 return true;
424}
425
426void InstancedRendering::beginFlush(GrResourceProvider* rp) {
427 SkASSERT(State::kRecordingDraws == fState);
428 fState = State::kFlushing;
429
Brian Salomon99ad1642016-12-16 09:50:45 -0500430 if (fTrackedOps.isEmpty()) {
csmartdaltona7f29642016-07-07 08:49:11 -0700431 return;
432 }
433
434 if (!fVertexBuffer) {
Hal Canary144caf52016-11-07 17:57:18 -0500435 fVertexBuffer.reset(InstanceProcessor::FindOrCreateVertexBuffer(fGpu.get()));
csmartdaltona7f29642016-07-07 08:49:11 -0700436 if (!fVertexBuffer) {
437 return;
438 }
439 }
440
441 if (!fIndexBuffer) {
Hal Canary144caf52016-11-07 17:57:18 -0500442 fIndexBuffer.reset(InstanceProcessor::FindOrCreateIndex8Buffer(fGpu.get()));
csmartdaltona7f29642016-07-07 08:49:11 -0700443 if (!fIndexBuffer) {
444 return;
445 }
446 }
447
448 if (!fParams.empty()) {
449 fParamsBuffer.reset(rp->createBuffer(fParams.count() * sizeof(ParamsTexel),
450 kTexel_GrBufferType, kDynamic_GrAccessPattern,
csmartdalton485a1202016-07-13 10:16:32 -0700451 GrResourceProvider::kNoPendingIO_Flag |
452 GrResourceProvider::kRequireGpuMemory_Flag,
csmartdaltona7f29642016-07-07 08:49:11 -0700453 fParams.begin()));
454 if (!fParamsBuffer) {
455 return;
456 }
457 }
458
459 this->onBeginFlush(rp);
460}
461
Brian Salomonbde42852016-12-21 11:37:49 -0500462void InstancedRendering::Op::onExecute(GrOpFlushState* state, const SkRect& bounds) {
csmartdaltona7f29642016-07-07 08:49:11 -0700463 SkASSERT(State::kFlushing == fInstancedRendering->fState);
464 SkASSERT(state->gpu() == fInstancedRendering->gpu());
465
466 state->gpu()->handleDirtyContext();
467 if (GrXferBarrierType barrierType = this->pipeline()->xferBarrierType(*state->gpu()->caps())) {
468 state->gpu()->xferBarrier(this->pipeline()->getRenderTarget(), barrierType);
469 }
470
Hal Canary144caf52016-11-07 17:57:18 -0500471 InstanceProcessor instProc(fInfo, fInstancedRendering->fParamsBuffer.get());
csmartdaltona7f29642016-07-07 08:49:11 -0700472 fInstancedRendering->onDraw(*this->pipeline(), instProc, this);
473}
474
475void InstancedRendering::endFlush() {
Brian Salomon92aee3d2016-12-21 09:20:25 -0500476 // The caller is expected to delete all tracked ops (i.e. ops whose applyPipelineOptimizations
csmartdaltona7f29642016-07-07 08:49:11 -0700477 // method has been called) before ending the flush.
Brian Salomon99ad1642016-12-16 09:50:45 -0500478 SkASSERT(fTrackedOps.isEmpty());
csmartdaltona7f29642016-07-07 08:49:11 -0700479 fParams.reset();
480 fParamsBuffer.reset();
481 this->onEndFlush();
482 fState = State::kRecordingDraws;
483 // Hold on to the shape coords and index buffers.
484}
485
486void InstancedRendering::resetGpuResources(ResetType resetType) {
487 fVertexBuffer.reset();
488 fIndexBuffer.reset();
489 fParamsBuffer.reset();
490 this->onResetGpuResources(resetType);
491}
492
493}