blob: 245d6d8281777c727bb60b39a11c214ceed93a48 [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
116 AntialiasMode antialiasMode;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500117 if (!this->selectAntialiasMode(viewMatrix, aa, info, aaType, &antialiasMode)) {
csmartdaltona7f29642016-07-07 08:49:11 -0700118 return nullptr;
119 }
120
Brian Salomonf8334782017-01-03 09:42:58 -0500121 std::unique_ptr<Op> op = this->makeOp();
Brian Salomon99ad1642016-12-16 09:50:45 -0500122 op->fInfo.fAntialiasMode = antialiasMode;
123 op->fInfo.fShapeTypes = GetShapeFlag(type);
124 op->fInfo.fCannotDiscard = !info.fCanDiscard;
csmartdaltona7f29642016-07-07 08:49:11 -0700125
Brian Salomon99ad1642016-12-16 09:50:45 -0500126 Instance& instance = op->getSingleInstance();
csmartdaltona7f29642016-07-07 08:49:11 -0700127 instance.fInfo = (int)type << kShapeType_InfoBit;
128
Brian Salomon99ad1642016-12-16 09:50:45 -0500129 Op::HasAABloat aaBloat = (antialiasMode == AntialiasMode::kCoverage) ? Op::HasAABloat::kYes
130 : Op::HasAABloat::kNo;
131 Op::IsZeroArea zeroArea = (bounds.isEmpty()) ? Op::IsZeroArea::kYes : Op::IsZeroArea::kNo;
bsalomon88cf17d2016-07-08 06:40:56 -0700132
csmartdaltona7f29642016-07-07 08:49:11 -0700133 // The instanced shape renderer draws rectangles of [-1, -1, +1, +1], so we find the matrix that
134 // will map this rectangle to the same device coordinates as "viewMatrix * bounds".
135 float sx = 0.5f * bounds.width();
136 float sy = 0.5f * bounds.height();
137 float tx = sx + bounds.fLeft;
138 float ty = sy + bounds.fTop;
139 if (!viewMatrix.hasPerspective()) {
140 float* m = instance.fShapeMatrix2x3;
141 m[0] = viewMatrix.getScaleX() * sx;
142 m[1] = viewMatrix.getSkewX() * sy;
143 m[2] = viewMatrix.getTranslateX() +
144 viewMatrix.getScaleX() * tx + viewMatrix.getSkewX() * ty;
145
146 m[3] = viewMatrix.getSkewY() * sx;
147 m[4] = viewMatrix.getScaleY() * sy;
148 m[5] = viewMatrix.getTranslateY() +
149 viewMatrix.getSkewY() * tx + viewMatrix.getScaleY() * ty;
150
151 // Since 'm' is a 2x3 matrix that maps the rect [-1, +1] into the shape's device-space quad,
152 // it's quite simple to find the bounding rectangle:
153 float devBoundsHalfWidth = fabsf(m[0]) + fabsf(m[1]);
154 float devBoundsHalfHeight = fabsf(m[3]) + fabsf(m[4]);
Brian Salomon99ad1642016-12-16 09:50:45 -0500155 SkRect opBounds;
156 opBounds.fLeft = m[2] - devBoundsHalfWidth;
157 opBounds.fRight = m[2] + devBoundsHalfWidth;
158 opBounds.fTop = m[5] - devBoundsHalfHeight;
159 opBounds.fBottom = m[5] + devBoundsHalfHeight;
160 op->setBounds(opBounds, aaBloat, zeroArea);
csmartdaltona7f29642016-07-07 08:49:11 -0700161
162 // TODO: Is this worth the CPU overhead?
Brian Salomon99ad1642016-12-16 09:50:45 -0500163 op->fInfo.fNonSquare =
164 fabsf(devBoundsHalfHeight - devBoundsHalfWidth) > 0.5f || // Early out.
165 fabs(m[0] * m[3] + m[1] * m[4]) > 1e-3f || // Skew?
166 fabs(m[0] * m[0] + m[1] * m[1] - m[3] * m[3] - m[4] * m[4]) >
167 1e-2f; // Diff. lengths?
csmartdaltona7f29642016-07-07 08:49:11 -0700168 } else {
169 SkMatrix shapeMatrix(viewMatrix);
170 shapeMatrix.preTranslate(tx, ty);
171 shapeMatrix.preScale(sx, sy);
172 instance.fInfo |= kPerspective_InfoFlag;
173
174 float* m = instance.fShapeMatrix2x3;
175 m[0] = SkScalarToFloat(shapeMatrix.getScaleX());
176 m[1] = SkScalarToFloat(shapeMatrix.getSkewX());
177 m[2] = SkScalarToFloat(shapeMatrix.getTranslateX());
178 m[3] = SkScalarToFloat(shapeMatrix.getSkewY());
179 m[4] = SkScalarToFloat(shapeMatrix.getScaleY());
180 m[5] = SkScalarToFloat(shapeMatrix.getTranslateY());
181
182 // Send the perspective column as a param.
Brian Salomon99ad1642016-12-16 09:50:45 -0500183 op->appendParamsTexel(shapeMatrix[SkMatrix::kMPersp0], shapeMatrix[SkMatrix::kMPersp1],
184 shapeMatrix[SkMatrix::kMPersp2]);
185 op->fInfo.fHasPerspective = true;
csmartdaltona7f29642016-07-07 08:49:11 -0700186
Brian Salomon99ad1642016-12-16 09:50:45 -0500187 op->setBounds(bounds, aaBloat, zeroArea);
188 op->fInfo.fNonSquare = true;
csmartdaltona7f29642016-07-07 08:49:11 -0700189 }
190
191 instance.fColor = color;
192
193 const float* rectAsFloats = localRect.asScalars(); // Ensure SkScalar == float.
194 memcpy(&instance.fLocalRect, rectAsFloats, 4 * sizeof(float));
195
Brian Salomon99ad1642016-12-16 09:50:45 -0500196 op->fPixelLoad = op->bounds().height() * op->bounds().width();
197 return op;
csmartdaltona7f29642016-07-07 08:49:11 -0700198}
199
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500200inline bool InstancedRendering::selectAntialiasMode(const SkMatrix& viewMatrix, GrAA aa,
csmartdaltona7f29642016-07-07 08:49:11 -0700201 const GrInstancedPipelineInfo& info,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500202 GrAAType* aaType,
203 AntialiasMode* antialiasMode) {
csmartdaltona7f29642016-07-07 08:49:11 -0700204 SkASSERT(!info.fColorDisabled || info.fDrawingShapeToStencil);
205 SkASSERT(!info.fIsMixedSampled || info.fIsMultisampled);
csmartdaltone0d36292016-07-29 08:14:20 -0700206 SkASSERT(GrCaps::InstancedSupport::kNone != fGpu->caps()->instancedSupport());
csmartdaltona7f29642016-07-07 08:49:11 -0700207
208 if (!info.fIsMultisampled || fGpu->caps()->multisampleDisableSupport()) {
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500209 if (GrAA::kNo == aa) {
csmartdaltona7f29642016-07-07 08:49:11 -0700210 if (info.fDrawingShapeToStencil && !info.fCanDiscard) {
211 // We can't draw to the stencil buffer without discard (or sample mask if MSAA).
212 return false;
213 }
214 *antialiasMode = AntialiasMode::kNone;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500215 *aaType = GrAAType::kNone;
csmartdaltona7f29642016-07-07 08:49:11 -0700216 return true;
217 }
218
219 if (info.canUseCoverageAA() && viewMatrix.preservesRightAngles()) {
220 *antialiasMode = AntialiasMode::kCoverage;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500221 *aaType = GrAAType::kCoverage;
csmartdaltona7f29642016-07-07 08:49:11 -0700222 return true;
223 }
224 }
225
csmartdaltone0d36292016-07-29 08:14:20 -0700226 if (info.fIsMultisampled &&
227 fGpu->caps()->instancedSupport() >= GrCaps::InstancedSupport::kMultisampled) {
csmartdaltona7f29642016-07-07 08:49:11 -0700228 if (!info.fIsMixedSampled || info.fColorDisabled) {
229 *antialiasMode = AntialiasMode::kMSAA;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500230 *aaType = GrAAType::kMSAA;
csmartdaltona7f29642016-07-07 08:49:11 -0700231 return true;
232 }
csmartdaltone0d36292016-07-29 08:14:20 -0700233 if (fGpu->caps()->instancedSupport() >= GrCaps::InstancedSupport::kMixedSampled) {
csmartdaltona7f29642016-07-07 08:49:11 -0700234 *antialiasMode = AntialiasMode::kMixedSamples;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500235 *aaType = GrAAType::kMixedSamples;
csmartdaltona7f29642016-07-07 08:49:11 -0700236 return true;
237 }
238 }
239
240 return false;
241}
242
Brian Salomon99ad1642016-12-16 09:50:45 -0500243InstancedRendering::Op::Op(uint32_t classID, InstancedRendering* ir)
244 : INHERITED(classID)
245 , fInstancedRendering(ir)
246 , fIsTracked(false)
247 , fNumDraws(1)
248 , fNumChangesInGeometry(0) {
dskibae4cd0062016-11-29 06:50:35 -0800249 fHeadDraw = fTailDraw = fInstancedRendering->fDrawPool.allocate();
csmartdaltona7f29642016-07-07 08:49:11 -0700250#ifdef SK_DEBUG
251 fHeadDraw->fGeometry = {-1, 0};
252#endif
253 fHeadDraw->fNext = nullptr;
254}
255
Brian Salomon99ad1642016-12-16 09:50:45 -0500256InstancedRendering::Op::~Op() {
csmartdaltona7f29642016-07-07 08:49:11 -0700257 if (fIsTracked) {
Brian Salomon99ad1642016-12-16 09:50:45 -0500258 fInstancedRendering->fTrackedOps.remove(this);
csmartdaltona7f29642016-07-07 08:49:11 -0700259 }
260
261 Draw* draw = fHeadDraw;
262 while (draw) {
263 Draw* next = draw->fNext;
264 fInstancedRendering->fDrawPool.release(draw);
265 draw = next;
266 }
267}
268
Brian Salomon99ad1642016-12-16 09:50:45 -0500269void InstancedRendering::Op::appendRRectParams(const SkRRect& rrect) {
csmartdaltona7f29642016-07-07 08:49:11 -0700270 SkASSERT(!fIsTracked);
271 switch (rrect.getType()) {
272 case SkRRect::kSimple_Type: {
273 const SkVector& radii = rrect.getSimpleRadii();
274 this->appendParamsTexel(radii.x(), radii.y(), rrect.width(), rrect.height());
275 return;
276 }
277 case SkRRect::kNinePatch_Type: {
278 float twoOverW = 2 / rrect.width();
279 float twoOverH = 2 / rrect.height();
280 const SkVector& radiiTL = rrect.radii(SkRRect::kUpperLeft_Corner);
281 const SkVector& radiiBR = rrect.radii(SkRRect::kLowerRight_Corner);
282 this->appendParamsTexel(radiiTL.x() * twoOverW, radiiBR.x() * twoOverW,
283 radiiTL.y() * twoOverH, radiiBR.y() * twoOverH);
284 return;
285 }
286 case SkRRect::kComplex_Type: {
287 /**
288 * The x and y radii of each arc are stored in separate vectors,
289 * in the following order:
290 *
291 * __x1 _ _ _ x3__
292 * y1 | | y2
293 *
294 * | |
295 *
296 * y3 |__ _ _ _ __| y4
297 * x2 x4
298 *
299 */
300 float twoOverW = 2 / rrect.width();
301 float twoOverH = 2 / rrect.height();
302 const SkVector& radiiTL = rrect.radii(SkRRect::kUpperLeft_Corner);
303 const SkVector& radiiTR = rrect.radii(SkRRect::kUpperRight_Corner);
304 const SkVector& radiiBR = rrect.radii(SkRRect::kLowerRight_Corner);
305 const SkVector& radiiBL = rrect.radii(SkRRect::kLowerLeft_Corner);
306 this->appendParamsTexel(radiiTL.x() * twoOverW, radiiBL.x() * twoOverW,
307 radiiTR.x() * twoOverW, radiiBR.x() * twoOverW);
308 this->appendParamsTexel(radiiTL.y() * twoOverH, radiiTR.y() * twoOverH,
309 radiiBL.y() * twoOverH, radiiBR.y() * twoOverH);
310 return;
311 }
312 default: return;
313 }
314}
315
Brian Salomon99ad1642016-12-16 09:50:45 -0500316void InstancedRendering::Op::appendParamsTexel(const SkScalar* vals, int count) {
csmartdaltona7f29642016-07-07 08:49:11 -0700317 SkASSERT(!fIsTracked);
318 SkASSERT(count <= 4 && count >= 0);
319 const float* valsAsFloats = vals; // Ensure SkScalar == float.
320 memcpy(&fParams.push_back(), valsAsFloats, count * sizeof(float));
321 fInfo.fHasParams = true;
322}
323
Brian Salomon99ad1642016-12-16 09:50:45 -0500324void InstancedRendering::Op::appendParamsTexel(SkScalar x, SkScalar y, SkScalar z, SkScalar w) {
csmartdaltona7f29642016-07-07 08:49:11 -0700325 SkASSERT(!fIsTracked);
326 ParamsTexel& texel = fParams.push_back();
327 texel.fX = SkScalarToFloat(x);
328 texel.fY = SkScalarToFloat(y);
329 texel.fZ = SkScalarToFloat(z);
330 texel.fW = SkScalarToFloat(w);
331 fInfo.fHasParams = true;
332}
333
Brian Salomon99ad1642016-12-16 09:50:45 -0500334void InstancedRendering::Op::appendParamsTexel(SkScalar x, SkScalar y, SkScalar z) {
csmartdaltona7f29642016-07-07 08:49:11 -0700335 SkASSERT(!fIsTracked);
336 ParamsTexel& texel = fParams.push_back();
337 texel.fX = SkScalarToFloat(x);
338 texel.fY = SkScalarToFloat(y);
339 texel.fZ = SkScalarToFloat(z);
340 fInfo.fHasParams = true;
341}
342
Brian Salomon5298dc82017-02-22 11:52:03 -0500343void InstancedRendering::Op::getFragmentProcessorAnalysisInputs(
344 FragmentProcessorAnalysisInputs* input) const {
345 input->colorInput()->setToConstant(this->getSingleInstance().fColor);
csmartdaltona7f29642016-07-07 08:49:11 -0700346
347 if (AntialiasMode::kCoverage == fInfo.fAntialiasMode ||
348 (AntialiasMode::kNone == fInfo.fAntialiasMode &&
349 !fInfo.isSimpleRects() && fInfo.fCannotDiscard)) {
Brian Salomon5298dc82017-02-22 11:52:03 -0500350 input->coverageInput()->setToUnknown();
csmartdaltona7f29642016-07-07 08:49:11 -0700351 } else {
Brian Salomon5298dc82017-02-22 11:52:03 -0500352 input->coverageInput()->setToSolidCoverage();
csmartdaltona7f29642016-07-07 08:49:11 -0700353 }
354}
355
Brian Salomon92aee3d2016-12-21 09:20:25 -0500356void InstancedRendering::Op::applyPipelineOptimizations(
357 const GrPipelineOptimizations& optimizations) {
csmartdaltona7f29642016-07-07 08:49:11 -0700358 Draw& draw = this->getSingleDraw(); // This will assert if we have > 1 command.
359 SkASSERT(draw.fGeometry.isEmpty());
360 SkASSERT(SkIsPow2(fInfo.fShapeTypes));
361 SkASSERT(!fIsTracked);
362
363 if (kRect_ShapeFlag == fInfo.fShapeTypes) {
364 draw.fGeometry = InstanceProcessor::GetIndexRangeForRect(fInfo.fAntialiasMode);
365 } else if (kOval_ShapeFlag == fInfo.fShapeTypes) {
bsalomon88cf17d2016-07-08 06:40:56 -0700366 draw.fGeometry = InstanceProcessor::GetIndexRangeForOval(fInfo.fAntialiasMode,
367 this->bounds());
csmartdaltona7f29642016-07-07 08:49:11 -0700368 } else {
369 draw.fGeometry = InstanceProcessor::GetIndexRangeForRRect(fInfo.fAntialiasMode);
370 }
371
372 if (!fParams.empty()) {
373 SkASSERT(fInstancedRendering->fParams.count() < (int)kParamsIdx_InfoMask); // TODO: cleaner.
374 this->getSingleInstance().fInfo |= fInstancedRendering->fParams.count();
375 fInstancedRendering->fParams.push_back_n(fParams.count(), fParams.begin());
376 }
377
378 GrColor overrideColor;
Brian Salomon92aee3d2016-12-21 09:20:25 -0500379 if (optimizations.getOverrideColorIfSet(&overrideColor)) {
csmartdaltona7f29642016-07-07 08:49:11 -0700380 SkASSERT(State::kRecordingDraws == fInstancedRendering->fState);
381 this->getSingleInstance().fColor = overrideColor;
382 }
Brian Salomon92aee3d2016-12-21 09:20:25 -0500383 fInfo.fUsesLocalCoords = optimizations.readsLocalCoords();
384 fInfo.fCannotTweakAlphaForCoverage = !optimizations.canTweakAlphaForCoverage();
csmartdaltona7f29642016-07-07 08:49:11 -0700385
Brian Salomon99ad1642016-12-16 09:50:45 -0500386 fInstancedRendering->fTrackedOps.addToTail(this);
csmartdaltona7f29642016-07-07 08:49:11 -0700387 fIsTracked = true;
388}
389
Brian Salomon99ad1642016-12-16 09:50:45 -0500390bool InstancedRendering::Op::onCombineIfPossible(GrOp* other, const GrCaps& caps) {
391 Op* that = static_cast<Op*>(other);
csmartdaltona7f29642016-07-07 08:49:11 -0700392 SkASSERT(fInstancedRendering == that->fInstancedRendering);
393 SkASSERT(fTailDraw);
394 SkASSERT(that->fTailDraw);
395
Brian Salomon99ad1642016-12-16 09:50:45 -0500396 if (!OpInfo::CanCombine(fInfo, that->fInfo) ||
397 !GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
398 that->bounds(), caps)) {
csmartdaltona7f29642016-07-07 08:49:11 -0700399 return false;
400 }
401
Brian Salomon99ad1642016-12-16 09:50:45 -0500402 OpInfo combinedInfo = fInfo | that->fInfo;
csmartdaltona7f29642016-07-07 08:49:11 -0700403 if (!combinedInfo.isSimpleRects()) {
404 // This threshold was chosen with the "shapes_mixed" bench on a MacBook with Intel graphics.
405 // There seems to be a wide range where it doesn't matter if we combine or not. What matters
406 // is that the itty bitty rects combine with other shapes and the giant ones don't.
407 constexpr SkScalar kMaxPixelsToGeneralizeRects = 256 * 256;
408 if (fInfo.isSimpleRects() && fPixelLoad > kMaxPixelsToGeneralizeRects) {
409 return false;
410 }
411 if (that->fInfo.isSimpleRects() && that->fPixelLoad > kMaxPixelsToGeneralizeRects) {
412 return false;
413 }
414 }
415
bsalomon88cf17d2016-07-08 06:40:56 -0700416 this->joinBounds(*that);
csmartdaltona7f29642016-07-07 08:49:11 -0700417 fInfo = combinedInfo;
418 fPixelLoad += that->fPixelLoad;
419
Brian Salomon99ad1642016-12-16 09:50:45 -0500420 // Adopt the other op's draws.
csmartdaltona7f29642016-07-07 08:49:11 -0700421 fNumDraws += that->fNumDraws;
422 fNumChangesInGeometry += that->fNumChangesInGeometry;
423 if (fTailDraw->fGeometry != that->fHeadDraw->fGeometry) {
424 ++fNumChangesInGeometry;
425 }
426 fTailDraw->fNext = that->fHeadDraw;
427 fTailDraw = that->fTailDraw;
428
429 that->fHeadDraw = that->fTailDraw = nullptr;
430
431 return true;
432}
433
434void InstancedRendering::beginFlush(GrResourceProvider* rp) {
435 SkASSERT(State::kRecordingDraws == fState);
436 fState = State::kFlushing;
437
Brian Salomon99ad1642016-12-16 09:50:45 -0500438 if (fTrackedOps.isEmpty()) {
csmartdaltona7f29642016-07-07 08:49:11 -0700439 return;
440 }
441
442 if (!fVertexBuffer) {
Hal Canary144caf52016-11-07 17:57:18 -0500443 fVertexBuffer.reset(InstanceProcessor::FindOrCreateVertexBuffer(fGpu.get()));
csmartdaltona7f29642016-07-07 08:49:11 -0700444 if (!fVertexBuffer) {
445 return;
446 }
447 }
448
449 if (!fIndexBuffer) {
Hal Canary144caf52016-11-07 17:57:18 -0500450 fIndexBuffer.reset(InstanceProcessor::FindOrCreateIndex8Buffer(fGpu.get()));
csmartdaltona7f29642016-07-07 08:49:11 -0700451 if (!fIndexBuffer) {
452 return;
453 }
454 }
455
456 if (!fParams.empty()) {
457 fParamsBuffer.reset(rp->createBuffer(fParams.count() * sizeof(ParamsTexel),
458 kTexel_GrBufferType, kDynamic_GrAccessPattern,
csmartdalton485a1202016-07-13 10:16:32 -0700459 GrResourceProvider::kNoPendingIO_Flag |
460 GrResourceProvider::kRequireGpuMemory_Flag,
csmartdaltona7f29642016-07-07 08:49:11 -0700461 fParams.begin()));
462 if (!fParamsBuffer) {
463 return;
464 }
465 }
466
467 this->onBeginFlush(rp);
468}
469
Brian Salomonbde42852016-12-21 11:37:49 -0500470void InstancedRendering::Op::onExecute(GrOpFlushState* state, const SkRect& bounds) {
csmartdaltona7f29642016-07-07 08:49:11 -0700471 SkASSERT(State::kFlushing == fInstancedRendering->fState);
472 SkASSERT(state->gpu() == fInstancedRendering->gpu());
473
474 state->gpu()->handleDirtyContext();
475 if (GrXferBarrierType barrierType = this->pipeline()->xferBarrierType(*state->gpu()->caps())) {
476 state->gpu()->xferBarrier(this->pipeline()->getRenderTarget(), barrierType);
477 }
478
Hal Canary144caf52016-11-07 17:57:18 -0500479 InstanceProcessor instProc(fInfo, fInstancedRendering->fParamsBuffer.get());
csmartdaltona7f29642016-07-07 08:49:11 -0700480 fInstancedRendering->onDraw(*this->pipeline(), instProc, this);
481}
482
483void InstancedRendering::endFlush() {
Brian Salomon92aee3d2016-12-21 09:20:25 -0500484 // The caller is expected to delete all tracked ops (i.e. ops whose applyPipelineOptimizations
csmartdaltona7f29642016-07-07 08:49:11 -0700485 // method has been called) before ending the flush.
Brian Salomon99ad1642016-12-16 09:50:45 -0500486 SkASSERT(fTrackedOps.isEmpty());
csmartdaltona7f29642016-07-07 08:49:11 -0700487 fParams.reset();
488 fParamsBuffer.reset();
489 this->onEndFlush();
490 fState = State::kRecordingDraws;
491 // Hold on to the shape coords and index buffers.
492}
493
494void InstancedRendering::resetGpuResources(ResetType resetType) {
495 fVertexBuffer.reset();
496 fIndexBuffer.reset();
497 fParamsBuffer.reset();
498 this->onResetGpuResources(resetType);
499}
500
501}