blob: f6ea6285d039e2803a58445814b54f530b5aac1a [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"
Brian Salomon13071c52017-03-29 21:28:20 -04009#include "GrAppliedClip.h"
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,
Brian Salomon54d212e2017-03-21 14:22:38 -040025 const SkMatrix& viewMatrix,
26 GrPaint&& paint, GrAA aa,
27 const GrInstancedPipelineInfo& info) {
28 return this->recordShape(ShapeType::kRect, rect, viewMatrix, std::move(paint), rect, aa, info);
29}
30
31std::unique_ptr<GrDrawOp> InstancedRendering::recordRect(const SkRect& rect,
32 const SkMatrix& viewMatrix,
33 GrPaint&& paint, const SkRect& localRect,
Brian Salomonf8334782017-01-03 09:42:58 -050034 GrAA aa,
Brian Salomon54d212e2017-03-21 14:22:38 -040035 const GrInstancedPipelineInfo& info) {
36 return this->recordShape(ShapeType::kRect, rect, viewMatrix, std::move(paint), localRect, aa,
37 info);
csmartdaltona7f29642016-07-07 08:49:11 -070038}
39
Brian Salomonf8334782017-01-03 09:42:58 -050040std::unique_ptr<GrDrawOp> InstancedRendering::recordRect(const SkRect& rect,
Brian Salomon54d212e2017-03-21 14:22:38 -040041 const SkMatrix& viewMatrix,
42 GrPaint&& paint,
Brian Salomonf8334782017-01-03 09:42:58 -050043 const SkMatrix& localMatrix, GrAA aa,
Brian Salomon54d212e2017-03-21 14:22:38 -040044 const GrInstancedPipelineInfo& info) {
csmartdaltona7f29642016-07-07 08:49:11 -070045 if (localMatrix.hasPerspective()) {
46 return nullptr; // Perspective is not yet supported in the local matrix.
47 }
Brian Salomon54d212e2017-03-21 14:22:38 -040048 if (std::unique_ptr<Op> op = this->recordShape(ShapeType::kRect, rect, viewMatrix,
49 std::move(paint), rect, aa, info)) {
Brian Salomon99ad1642016-12-16 09:50:45 -050050 op->getSingleInstance().fInfo |= kLocalMatrix_InfoFlag;
51 op->appendParamsTexel(localMatrix.getScaleX(), localMatrix.getSkewX(),
52 localMatrix.getTranslateX());
53 op->appendParamsTexel(localMatrix.getSkewY(), localMatrix.getScaleY(),
54 localMatrix.getTranslateY());
55 op->fInfo.fHasLocalMatrix = true;
56 return std::move(op);
csmartdaltona7f29642016-07-07 08:49:11 -070057 }
58 return nullptr;
59}
60
Brian Salomonf8334782017-01-03 09:42:58 -050061std::unique_ptr<GrDrawOp> InstancedRendering::recordOval(const SkRect& oval,
Brian Salomon54d212e2017-03-21 14:22:38 -040062 const SkMatrix& viewMatrix,
63 GrPaint&& paint, GrAA aa,
64 const GrInstancedPipelineInfo& info) {
65 return this->recordShape(ShapeType::kOval, oval, viewMatrix, std::move(paint), oval, aa, info);
csmartdaltona7f29642016-07-07 08:49:11 -070066}
67
Brian Salomonf8334782017-01-03 09:42:58 -050068std::unique_ptr<GrDrawOp> InstancedRendering::recordRRect(const SkRRect& rrect,
Brian Salomon54d212e2017-03-21 14:22:38 -040069 const SkMatrix& viewMatrix,
70 GrPaint&& paint, GrAA aa,
71 const GrInstancedPipelineInfo& info) {
Brian Salomonf8334782017-01-03 09:42:58 -050072 if (std::unique_ptr<Op> op =
Brian Salomon54d212e2017-03-21 14:22:38 -040073 this->recordShape(GetRRectShapeType(rrect), rrect.rect(), viewMatrix,
74 std::move(paint), rrect.rect(), aa, info)) {
Brian Salomon99ad1642016-12-16 09:50:45 -050075 op->appendRRectParams(rrect);
76 return std::move(op);
csmartdaltona7f29642016-07-07 08:49:11 -070077 }
78 return nullptr;
79}
80
Brian Salomon54d212e2017-03-21 14:22:38 -040081std::unique_ptr<GrDrawOp> InstancedRendering::recordDRRect(const SkRRect& outer,
82 const SkRRect& inner,
83 const SkMatrix& viewMatrix,
84 GrPaint&& paint, GrAA aa,
85 const GrInstancedPipelineInfo& info) {
csmartdaltona7f29642016-07-07 08:49:11 -070086 if (inner.getType() > SkRRect::kSimple_Type) {
87 return nullptr; // Complex inner round rects are not yet supported.
88 }
89 if (SkRRect::kEmpty_Type == inner.getType()) {
Brian Salomon54d212e2017-03-21 14:22:38 -040090 return this->recordRRect(outer, viewMatrix, std::move(paint), aa, info);
csmartdaltona7f29642016-07-07 08:49:11 -070091 }
Brian Salomonf8334782017-01-03 09:42:58 -050092 if (std::unique_ptr<Op> op =
Brian Salomon54d212e2017-03-21 14:22:38 -040093 this->recordShape(GetRRectShapeType(outer), outer.rect(), viewMatrix,
94 std::move(paint), outer.rect(), aa, info)) {
Brian Salomon99ad1642016-12-16 09:50:45 -050095 op->appendRRectParams(outer);
csmartdaltona7f29642016-07-07 08:49:11 -070096 ShapeType innerShapeType = GetRRectShapeType(inner);
Brian Salomon99ad1642016-12-16 09:50:45 -050097 op->fInfo.fInnerShapeTypes |= GetShapeFlag(innerShapeType);
98 op->getSingleInstance().fInfo |= ((int)innerShapeType << kInnerShapeType_InfoBit);
99 op->appendParamsTexel(inner.rect().asScalars(), 4);
100 op->appendRRectParams(inner);
101 return std::move(op);
csmartdaltona7f29642016-07-07 08:49:11 -0700102 }
103 return nullptr;
104}
105
Brian Salomonf8334782017-01-03 09:42:58 -0500106std::unique_ptr<InstancedRendering::Op> InstancedRendering::recordShape(
Brian Salomon54d212e2017-03-21 14:22:38 -0400107 ShapeType type, const SkRect& bounds, const SkMatrix& viewMatrix, GrPaint&& paint,
108 const SkRect& localRect, GrAA aa, const GrInstancedPipelineInfo& info) {
csmartdaltona7f29642016-07-07 08:49:11 -0700109 SkASSERT(State::kRecordingDraws == fState);
110
csmartdaltone0d36292016-07-29 08:14:20 -0700111 if (info.fIsRenderingToFloat && fGpu->caps()->avoidInstancedDrawsToFPTargets()) {
csmartdaltona7f29642016-07-07 08:49:11 -0700112 return nullptr;
113 }
114
Brian Salomon54d212e2017-03-21 14:22:38 -0400115 GrAAType aaType;
116 if (!this->selectAntialiasMode(viewMatrix, aa, info, &aaType)) {
csmartdaltona7f29642016-07-07 08:49:11 -0700117 return nullptr;
118 }
119
Brian Salomon54d212e2017-03-21 14:22:38 -0400120 GrColor color = paint.getColor();
121 std::unique_ptr<Op> op = this->makeOp(std::move(paint));
122 op->fInfo.setAAType(aaType);
Brian Salomon99ad1642016-12-16 09:50:45 -0500123 op->fInfo.fShapeTypes = GetShapeFlag(type);
Brian Salomon5ff3a5c2017-03-01 14:34:41 -0500124 op->fInfo.fCannotDiscard = true;
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 =
Brian Salomon54d212e2017-03-21 14:22:38 -0400129 (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.fIsMixedSampled || info.fIsMultisampled);
csmartdaltone0d36292016-07-29 08:14:20 -0700203 SkASSERT(GrCaps::InstancedSupport::kNone != fGpu->caps()->instancedSupport());
csmartdaltona7f29642016-07-07 08:49:11 -0700204
205 if (!info.fIsMultisampled || fGpu->caps()->multisampleDisableSupport()) {
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500206 if (GrAA::kNo == aa) {
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500207 *aaType = GrAAType::kNone;
csmartdaltona7f29642016-07-07 08:49:11 -0700208 return true;
209 }
210
211 if (info.canUseCoverageAA() && viewMatrix.preservesRightAngles()) {
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500212 *aaType = GrAAType::kCoverage;
csmartdaltona7f29642016-07-07 08:49:11 -0700213 return true;
214 }
215 }
216
csmartdaltone0d36292016-07-29 08:14:20 -0700217 if (info.fIsMultisampled &&
218 fGpu->caps()->instancedSupport() >= GrCaps::InstancedSupport::kMultisampled) {
Brian Salomon5ff3a5c2017-03-01 14:34:41 -0500219 if (!info.fIsMixedSampled) {
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500220 *aaType = GrAAType::kMSAA;
csmartdaltona7f29642016-07-07 08:49:11 -0700221 return true;
222 }
csmartdaltone0d36292016-07-29 08:14:20 -0700223 if (fGpu->caps()->instancedSupport() >= GrCaps::InstancedSupport::kMixedSampled) {
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500224 *aaType = GrAAType::kMixedSamples;
csmartdaltona7f29642016-07-07 08:49:11 -0700225 return true;
226 }
227 }
228
229 return false;
230}
231
Brian Salomon54d212e2017-03-21 14:22:38 -0400232InstancedRendering::Op::Op(uint32_t classID, GrPaint&& paint, InstancedRendering* ir)
Brian Salomon99ad1642016-12-16 09:50:45 -0500233 : INHERITED(classID)
234 , fInstancedRendering(ir)
Brian Salomon54d212e2017-03-21 14:22:38 -0400235 , fProcessors(std::move(paint))
Brian Salomon99ad1642016-12-16 09:50:45 -0500236 , fIsTracked(false)
237 , fNumDraws(1)
238 , fNumChangesInGeometry(0) {
dskibae4cd0062016-11-29 06:50:35 -0800239 fHeadDraw = fTailDraw = fInstancedRendering->fDrawPool.allocate();
csmartdaltona7f29642016-07-07 08:49:11 -0700240#ifdef SK_DEBUG
241 fHeadDraw->fGeometry = {-1, 0};
242#endif
243 fHeadDraw->fNext = nullptr;
244}
245
Brian Salomon99ad1642016-12-16 09:50:45 -0500246InstancedRendering::Op::~Op() {
csmartdaltona7f29642016-07-07 08:49:11 -0700247 if (fIsTracked) {
Brian Salomon99ad1642016-12-16 09:50:45 -0500248 fInstancedRendering->fTrackedOps.remove(this);
csmartdaltona7f29642016-07-07 08:49:11 -0700249 }
250
251 Draw* draw = fHeadDraw;
252 while (draw) {
253 Draw* next = draw->fNext;
254 fInstancedRendering->fDrawPool.release(draw);
255 draw = next;
256 }
257}
258
Brian Salomon99ad1642016-12-16 09:50:45 -0500259void InstancedRendering::Op::appendRRectParams(const SkRRect& rrect) {
csmartdaltona7f29642016-07-07 08:49:11 -0700260 SkASSERT(!fIsTracked);
261 switch (rrect.getType()) {
262 case SkRRect::kSimple_Type: {
263 const SkVector& radii = rrect.getSimpleRadii();
264 this->appendParamsTexel(radii.x(), radii.y(), rrect.width(), rrect.height());
265 return;
266 }
267 case SkRRect::kNinePatch_Type: {
268 float twoOverW = 2 / rrect.width();
269 float twoOverH = 2 / rrect.height();
270 const SkVector& radiiTL = rrect.radii(SkRRect::kUpperLeft_Corner);
271 const SkVector& radiiBR = rrect.radii(SkRRect::kLowerRight_Corner);
272 this->appendParamsTexel(radiiTL.x() * twoOverW, radiiBR.x() * twoOverW,
273 radiiTL.y() * twoOverH, radiiBR.y() * twoOverH);
274 return;
275 }
276 case SkRRect::kComplex_Type: {
277 /**
278 * The x and y radii of each arc are stored in separate vectors,
279 * in the following order:
280 *
281 * __x1 _ _ _ x3__
282 * y1 | | y2
283 *
284 * | |
285 *
286 * y3 |__ _ _ _ __| y4
287 * x2 x4
288 *
289 */
290 float twoOverW = 2 / rrect.width();
291 float twoOverH = 2 / rrect.height();
292 const SkVector& radiiTL = rrect.radii(SkRRect::kUpperLeft_Corner);
293 const SkVector& radiiTR = rrect.radii(SkRRect::kUpperRight_Corner);
294 const SkVector& radiiBR = rrect.radii(SkRRect::kLowerRight_Corner);
295 const SkVector& radiiBL = rrect.radii(SkRRect::kLowerLeft_Corner);
296 this->appendParamsTexel(radiiTL.x() * twoOverW, radiiBL.x() * twoOverW,
297 radiiTR.x() * twoOverW, radiiBR.x() * twoOverW);
298 this->appendParamsTexel(radiiTL.y() * twoOverH, radiiTR.y() * twoOverH,
299 radiiBL.y() * twoOverH, radiiBR.y() * twoOverH);
300 return;
301 }
302 default: return;
303 }
304}
305
Brian Salomon99ad1642016-12-16 09:50:45 -0500306void InstancedRendering::Op::appendParamsTexel(const SkScalar* vals, int count) {
csmartdaltona7f29642016-07-07 08:49:11 -0700307 SkASSERT(!fIsTracked);
308 SkASSERT(count <= 4 && count >= 0);
309 const float* valsAsFloats = vals; // Ensure SkScalar == float.
310 memcpy(&fParams.push_back(), valsAsFloats, count * sizeof(float));
311 fInfo.fHasParams = true;
312}
313
Brian Salomon99ad1642016-12-16 09:50:45 -0500314void InstancedRendering::Op::appendParamsTexel(SkScalar x, SkScalar y, SkScalar z, SkScalar w) {
csmartdaltona7f29642016-07-07 08:49:11 -0700315 SkASSERT(!fIsTracked);
316 ParamsTexel& texel = fParams.push_back();
317 texel.fX = SkScalarToFloat(x);
318 texel.fY = SkScalarToFloat(y);
319 texel.fZ = SkScalarToFloat(z);
320 texel.fW = SkScalarToFloat(w);
321 fInfo.fHasParams = true;
322}
323
Brian Salomon99ad1642016-12-16 09:50:45 -0500324void InstancedRendering::Op::appendParamsTexel(SkScalar x, SkScalar y, SkScalar z) {
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 fInfo.fHasParams = true;
331}
332
Brian Salomon54d212e2017-03-21 14:22:38 -0400333bool InstancedRendering::Op::xpRequiresDstTexture(const GrCaps& caps, const GrAppliedClip* clip) {
334 GrProcessorSet::FragmentProcessorAnalysis analysis;
Brian Salomonc0b642c2017-03-27 13:09:36 -0400335 GrPipelineAnalysisCoverage coverageInput;
Brian Salomonaf9847e2017-03-01 11:28:27 -0500336 if (GrAAType::kCoverage == fInfo.aaType() ||
337 (GrAAType::kNone == fInfo.aaType() && !fInfo.isSimpleRects() && fInfo.fCannotDiscard)) {
Brian Salomonc0b642c2017-03-27 13:09:36 -0400338 coverageInput = GrPipelineAnalysisCoverage::kSingleChannel;
csmartdaltona7f29642016-07-07 08:49:11 -0700339 } else {
Brian Salomonc0b642c2017-03-27 13:09:36 -0400340 coverageInput = GrPipelineAnalysisCoverage::kNone;
csmartdaltona7f29642016-07-07 08:49:11 -0700341 }
Brian Salomon70288c02017-03-24 12:27:17 -0400342 fProcessors.analyzeAndEliminateFragmentProcessors(&analysis, this->getSingleInstance().fColor,
343 coverageInput, clip, caps);
Brian Salomon13071c52017-03-29 21:28:20 -0400344 fAnalysisColor = analysis.outputColor();
345
csmartdaltona7f29642016-07-07 08:49:11 -0700346 Draw& draw = this->getSingleDraw(); // This will assert if we have > 1 command.
347 SkASSERT(draw.fGeometry.isEmpty());
348 SkASSERT(SkIsPow2(fInfo.fShapeTypes));
349 SkASSERT(!fIsTracked);
350
351 if (kRect_ShapeFlag == fInfo.fShapeTypes) {
Brian Salomonaf9847e2017-03-01 11:28:27 -0500352 draw.fGeometry = InstanceProcessor::GetIndexRangeForRect(fInfo.aaType());
csmartdaltona7f29642016-07-07 08:49:11 -0700353 } else if (kOval_ShapeFlag == fInfo.fShapeTypes) {
Brian Salomonaf9847e2017-03-01 11:28:27 -0500354 draw.fGeometry = InstanceProcessor::GetIndexRangeForOval(fInfo.aaType(), this->bounds());
csmartdaltona7f29642016-07-07 08:49:11 -0700355 } else {
Brian Salomonaf9847e2017-03-01 11:28:27 -0500356 draw.fGeometry = InstanceProcessor::GetIndexRangeForRRect(fInfo.aaType());
csmartdaltona7f29642016-07-07 08:49:11 -0700357 }
358
359 if (!fParams.empty()) {
360 SkASSERT(fInstancedRendering->fParams.count() < (int)kParamsIdx_InfoMask); // TODO: cleaner.
361 this->getSingleInstance().fInfo |= fInstancedRendering->fParams.count();
362 fInstancedRendering->fParams.push_back_n(fParams.count(), fParams.begin());
363 }
364
365 GrColor overrideColor;
Brian Salomon70288c02017-03-24 12:27:17 -0400366 if (analysis.getInputColorOverrideAndColorProcessorEliminationCount(&overrideColor) >= 0) {
csmartdaltona7f29642016-07-07 08:49:11 -0700367 SkASSERT(State::kRecordingDraws == fInstancedRendering->fState);
Brian Salomon54d212e2017-03-21 14:22:38 -0400368 this->getSingleDraw().fInstance.fColor = overrideColor;
csmartdaltona7f29642016-07-07 08:49:11 -0700369 }
Brian Salomon31853842017-03-28 16:32:05 -0400370 fInfo.fCannotTweakAlphaForCoverage = !analysis.isCompatibleWithCoverageAsAlpha();
Brian Salomon54d212e2017-03-21 14:22:38 -0400371
372 fInfo.fUsesLocalCoords = analysis.usesLocalCoords();
Brian Salomon31853842017-03-28 16:32:05 -0400373 return analysis.requiresDstTexture();
Brian Salomond543e0a2017-03-06 16:36:49 -0500374}
csmartdaltona7f29642016-07-07 08:49:11 -0700375
Brian Salomond543e0a2017-03-06 16:36:49 -0500376void InstancedRendering::Op::wasRecorded() {
377 SkASSERT(!fIsTracked);
Brian Salomon99ad1642016-12-16 09:50:45 -0500378 fInstancedRendering->fTrackedOps.addToTail(this);
Brian Salomon54d212e2017-03-21 14:22:38 -0400379 fProcessors.makePendingExecution();
csmartdaltona7f29642016-07-07 08:49:11 -0700380 fIsTracked = true;
381}
382
Brian Salomon99ad1642016-12-16 09:50:45 -0500383bool InstancedRendering::Op::onCombineIfPossible(GrOp* other, const GrCaps& caps) {
384 Op* that = static_cast<Op*>(other);
csmartdaltona7f29642016-07-07 08:49:11 -0700385 SkASSERT(fInstancedRendering == that->fInstancedRendering);
386 SkASSERT(fTailDraw);
387 SkASSERT(that->fTailDraw);
388
Brian Salomon54d212e2017-03-21 14:22:38 -0400389 if (!OpInfo::CanCombine(fInfo, that->fInfo) || fProcessors != that->fProcessors) {
csmartdaltona7f29642016-07-07 08:49:11 -0700390 return false;
391 }
392
Brian Salomon99ad1642016-12-16 09:50:45 -0500393 OpInfo combinedInfo = fInfo | that->fInfo;
csmartdaltona7f29642016-07-07 08:49:11 -0700394 if (!combinedInfo.isSimpleRects()) {
395 // This threshold was chosen with the "shapes_mixed" bench on a MacBook with Intel graphics.
396 // There seems to be a wide range where it doesn't matter if we combine or not. What matters
397 // is that the itty bitty rects combine with other shapes and the giant ones don't.
398 constexpr SkScalar kMaxPixelsToGeneralizeRects = 256 * 256;
399 if (fInfo.isSimpleRects() && fPixelLoad > kMaxPixelsToGeneralizeRects) {
400 return false;
401 }
402 if (that->fInfo.isSimpleRects() && that->fPixelLoad > kMaxPixelsToGeneralizeRects) {
403 return false;
404 }
405 }
406
bsalomon88cf17d2016-07-08 06:40:56 -0700407 this->joinBounds(*that);
csmartdaltona7f29642016-07-07 08:49:11 -0700408 fInfo = combinedInfo;
409 fPixelLoad += that->fPixelLoad;
Brian Salomon13071c52017-03-29 21:28:20 -0400410 fAnalysisColor = GrPipelineAnalysisColor::Combine(fAnalysisColor, that->fAnalysisColor);
Brian Salomon99ad1642016-12-16 09:50:45 -0500411 // Adopt the other op's draws.
csmartdaltona7f29642016-07-07 08:49:11 -0700412 fNumDraws += that->fNumDraws;
413 fNumChangesInGeometry += that->fNumChangesInGeometry;
414 if (fTailDraw->fGeometry != that->fHeadDraw->fGeometry) {
415 ++fNumChangesInGeometry;
416 }
417 fTailDraw->fNext = that->fHeadDraw;
418 fTailDraw = that->fTailDraw;
419
420 that->fHeadDraw = that->fTailDraw = nullptr;
421
422 return true;
423}
424
425void InstancedRendering::beginFlush(GrResourceProvider* rp) {
426 SkASSERT(State::kRecordingDraws == fState);
427 fState = State::kFlushing;
428
Brian Salomon99ad1642016-12-16 09:50:45 -0500429 if (fTrackedOps.isEmpty()) {
csmartdaltona7f29642016-07-07 08:49:11 -0700430 return;
431 }
432
433 if (!fVertexBuffer) {
Hal Canary144caf52016-11-07 17:57:18 -0500434 fVertexBuffer.reset(InstanceProcessor::FindOrCreateVertexBuffer(fGpu.get()));
csmartdaltona7f29642016-07-07 08:49:11 -0700435 if (!fVertexBuffer) {
436 return;
437 }
438 }
439
440 if (!fIndexBuffer) {
Hal Canary144caf52016-11-07 17:57:18 -0500441 fIndexBuffer.reset(InstanceProcessor::FindOrCreateIndex8Buffer(fGpu.get()));
csmartdaltona7f29642016-07-07 08:49:11 -0700442 if (!fIndexBuffer) {
443 return;
444 }
445 }
446
447 if (!fParams.empty()) {
448 fParamsBuffer.reset(rp->createBuffer(fParams.count() * sizeof(ParamsTexel),
449 kTexel_GrBufferType, kDynamic_GrAccessPattern,
csmartdalton485a1202016-07-13 10:16:32 -0700450 GrResourceProvider::kNoPendingIO_Flag |
451 GrResourceProvider::kRequireGpuMemory_Flag,
csmartdaltona7f29642016-07-07 08:49:11 -0700452 fParams.begin()));
453 if (!fParamsBuffer) {
454 return;
455 }
456 }
457
458 this->onBeginFlush(rp);
459}
460
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500461void InstancedRendering::Op::onExecute(GrOpFlushState* state) {
csmartdaltona7f29642016-07-07 08:49:11 -0700462 SkASSERT(State::kFlushing == fInstancedRendering->fState);
463 SkASSERT(state->gpu() == fInstancedRendering->gpu());
464
465 state->gpu()->handleDirtyContext();
Brian Salomon2bf4b3a2017-03-16 14:19:07 -0400466
Brian Salomon54d212e2017-03-21 14:22:38 -0400467 const GrAppliedClip* clip = state->drawOpArgs().fAppliedClip;
Brian Salomon13071c52017-03-29 21:28:20 -0400468 GrPipelineAnalysisCoverage coverage;
469 if (GrAAType::kCoverage == fInfo.aaType() ||
470 (clip && clip->clipCoverageFragmentProcessor()) ||
471 (GrAAType::kNone == fInfo.aaType() && !fInfo.isSimpleRects() && fInfo.fCannotDiscard)) {
472 coverage = GrPipelineAnalysisCoverage::kSingleChannel;
473 } else {
474 coverage = GrPipelineAnalysisCoverage::kNone;
475 }
Brian Salomon54d212e2017-03-21 14:22:38 -0400476
477 GrPipeline pipeline;
478 GrPipeline::InitArgs args;
Brian Salomon13071c52017-03-29 21:28:20 -0400479 args.fInputColor = fAnalysisColor;
480 args.fInputCoverage = coverage;
Brian Salomon54d212e2017-03-21 14:22:38 -0400481 args.fAppliedClip = clip;
482 args.fCaps = &state->caps();
483 args.fProcessors = &fProcessors;
484 args.fFlags = GrAATypeIsHW(fInfo.aaType()) ? GrPipeline::kHWAntialias_Flag : 0;
485 args.fRenderTarget = state->drawOpArgs().fRenderTarget;
486 args.fDstTexture = state->drawOpArgs().fDstTexture;
487 pipeline.init(args);
488
489 if (GrXferBarrierType barrierType = pipeline.xferBarrierType(*state->gpu()->caps())) {
490 state->gpu()->xferBarrier(pipeline.getRenderTarget(), barrierType);
491 }
Hal Canary144caf52016-11-07 17:57:18 -0500492 InstanceProcessor instProc(fInfo, fInstancedRendering->fParamsBuffer.get());
Brian Salomon54d212e2017-03-21 14:22:38 -0400493 fInstancedRendering->onDraw(pipeline, instProc, this);
csmartdaltona7f29642016-07-07 08:49:11 -0700494}
495
496void InstancedRendering::endFlush() {
Brian Salomon92aee3d2016-12-21 09:20:25 -0500497 // The caller is expected to delete all tracked ops (i.e. ops whose applyPipelineOptimizations
csmartdaltona7f29642016-07-07 08:49:11 -0700498 // method has been called) before ending the flush.
Brian Salomon99ad1642016-12-16 09:50:45 -0500499 SkASSERT(fTrackedOps.isEmpty());
csmartdaltona7f29642016-07-07 08:49:11 -0700500 fParams.reset();
501 fParamsBuffer.reset();
502 this->onEndFlush();
503 fState = State::kRecordingDraws;
504 // Hold on to the shape coords and index buffers.
505}
506
507void InstancedRendering::resetGpuResources(ResetType resetType) {
508 fVertexBuffer.reset();
509 fIndexBuffer.reset();
510 fParamsBuffer.reset();
511 this->onResetGpuResources(resetType);
512}
513
514}