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

Side by Side Diff: src/gpu/GrInstancedRendering.cpp

Issue 1897203002: Implement instanced rendering for simple shapes (Closed) Base URL: https://skia.googlesource.com/skia.git@upload2_requireHWAA
Patch Set: comments Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/gpu/GrInstancedRendering.h ('k') | src/gpu/GrInstancedRenderingTypes.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
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 "GrInstancedRendering.h"
9
10 #include "GrBatchFlushState.h"
11 #include "GrPipeline.h"
12 #include "GrResourceProvider.h"
13 #include "effects/GrInstanceProcessor.h"
14
15 GrInstancedRendering::GrInstancedRendering(GrGpu* gpu, uint32_t supportedAAModes ,
16 size_t sizeofBatchClass)
17 : fGpu(SkRef(gpu)),
18 fSupportedAAModes(supportedAAModes),
19 fState(State::kRecordingDraws),
20 fBatchAllocator(sizeofBatchClass) {
21 SkDEBUGCODE(fInUseBatchCount = 0;)
22 }
23
24 GrDrawBatch* GrInstancedRendering::recordRect(const SkRect& rect, const SkMatrix & viewMatrix,
25 GrColor color, bool antialias, uin t32_t flags,
26 bool* useHWAA) {
27 return this->recordShape(kRect_ShapeType, rect, viewMatrix, color, rect, ant ialias, flags,
28 useHWAA);
29 }
30
31 GrDrawBatch* GrInstancedRendering::recordRect(const SkRect& rect, const SkMatrix & viewMatrix,
32 GrColor color, const SkRect& local Rect,
33 bool antialias, uint32_t flags, bo ol* useHWAA) {
34 return this->recordShape(kRect_ShapeType, rect, viewMatrix, color, localRect , antialias, flags,
35 useHWAA);
36 }
37
38 GrDrawBatch* GrInstancedRendering::recordRect(const SkRect& rect, const SkMatrix & viewMatrix,
39 GrColor color, const SkMatrix& loc alMatrix,
40 bool antialias, uint32_t flags, bo ol* useHWAA) {
41 if (localMatrix.hasPerspective()) {
42 return nullptr; // Perspective is not yet supported in the local matrix.
43 }
44 if (Batch* batch = this->recordShape(kRect_ShapeType, rect, viewMatrix, colo r, rect, antialias,
45 flags, useHWAA)) {
46 fInstances.back().fInfo |= kLocalMatrix_InfoFlag;
47 this->appendParamsTexel(localMatrix.getScaleX(), localMatrix.getSkewX(),
48 localMatrix.getTranslateX());
49 this->appendParamsTexel(localMatrix.getSkewY(), localMatrix.getScaleY(),
50 localMatrix.getTranslateY());
51 batch->fInfo.fHasLocalMatrix = true;
52 batch->fInfo.fHasParams = true;
53 return batch;
54 }
55 return nullptr;
56 }
57
58 GrDrawBatch* GrInstancedRendering::recordOval(const SkRect& oval, const SkMatrix & viewMatrix,
59 GrColor color, bool antialias, uin t32_t flags,
60 bool* useHWAA) {
61 return this->recordShape(kOval_ShapeType, oval, viewMatrix, color, oval, ant ialias, flags,
62 useHWAA);
63 }
64
65 GrDrawBatch* GrInstancedRendering::recordRRect(const SkRRect& rrect, const SkMat rix& viewMatrix,
66 GrColor color, bool antialias, ui nt32_t flags,
67 bool* useHWAA) {
68 if (Batch* batch = this->recordShape(RRectShapeType(rrect), rrect.rect(), vi ewMatrix, color,
69 rrect.rect(), antialias, flags, useHWAA )) {
70 this->appendRRectParams(rrect, &batch->fInfo);
71 return batch;
72 }
73 return nullptr;
74 }
75
76 GrDrawBatch* GrInstancedRendering::recordDRRect(const SkRRect& outer, const SkRR ect& inner,
77 const SkMatrix& viewMatrix, GrCo lor color,
78 bool antialias, uint32_t flags, bool* useHWAA) {
79 if (inner.getType() > SkRRect::kSimple_Type) {
80 return nullptr; // Complex inner round rects are not yet supported.
81 }
82 if (SkRRect::kEmpty_Type == inner.getType()) {
83 return this->recordRRect(outer, viewMatrix, color, antialias, flags, use HWAA);
84 }
85 if (Batch* batch = this->recordShape(RRectShapeType(outer), outer.rect(), vi ewMatrix, color,
86 outer.rect(), antialias, flags, useHWAA )) {
87 this->appendRRectParams(outer, &batch->fInfo);
88 ShapeType innerShapeType = RRectShapeType(inner);
89 batch->fInfo.fInnerShapeTypes |= (1 << innerShapeType);
90 fInstances.back().fInfo |= (innerShapeType << kInnerShapeType_InfoBit);
91 this->appendParamsTexel(inner.rect().asScalars(), 4);
92 this->appendRRectParams(inner, &batch->fInfo);
93 batch->fInfo.fHasParams = true;
94 return batch;
95 }
96 return nullptr;
97 }
98
99 GrInstancedRendering::Batch* GrInstancedRendering::recordShape(ShapeType type, c onst SkRect& bounds,
100 const SkMatrix& v iewMatrix,
101 GrColor color,
102 const SkRect& loc alRect,
103 bool antialias, u int32_t flags,
104 bool* useHWAA) {
105 SkASSERT(State::kRecordingDraws == fState);
106
107 uint32_t paramsIdx = fParams.count();
108 if (paramsIdx > kParamsIdx_InfoMask) {
109 return nullptr; // paramsIdx is too large for its allotted space.
110 }
111
112 AntialiasMode antialiasMode;
113 if (!this->selectAntialiasMode(viewMatrix, antialias, flags, &antialiasMode, useHWAA)) {
114 return nullptr;
115 }
116
117 Batch* batch = this->constructBatch(fBatchAllocator.push_back(), fInstances. count());
118 SkASSERT(batch == fBatchAllocator.back()); // We rely on batch ptr equality with the allocator.
119 SkDEBUGCODE(++fInUseBatchCount;)
120 batch->fInfo.fAntialiasMode = antialiasMode;
121 batch->fInfo.fShapeTypes = (1 << type);
122 batch->fInfo.fCannotDiscard = !(flags & kUseDiscard_Flag);
123
124 Instance& instance = fInstances.push_back();
125 instance.fInfo = (type << kShapeType_InfoBit) | paramsIdx;
126
127 // The instanced shape renderer draws rectangles of [-1, -1, +1, +1], so we find the matrix that
128 // will map this rectangle to the same device coordinates as "viewMatrix * b ounds".
129 float sx = 0.5f * bounds.width();
130 float sy = 0.5f * bounds.height();
131 float tx = sx + bounds.fLeft;
132 float ty = sy + bounds.fTop;
133 if (!viewMatrix.hasPerspective()) {
134 float* m = instance.fShapeMatrix2x3;
135 m[0] = viewMatrix.getScaleX() * sx;
136 m[1] = viewMatrix.getSkewX() * sy;
137 m[2] = viewMatrix.getTranslateX() +
138 viewMatrix.getScaleX() * tx + viewMatrix.getSkewX() * ty;
139
140 m[3] = viewMatrix.getSkewY() * sx;
141 m[4] = viewMatrix.getScaleY() * sy;
142 m[5] = viewMatrix.getTranslateY() +
143 viewMatrix.getSkewY() * tx + viewMatrix.getScaleY() * ty;
144
145 // Since 'm' is a 2x3 matrix that maps the rect [-1, +1] into the shape' s device-space quad,
146 // it's quite simple to find the bounding rectangle:
147 float devBoundsHalfWidth = fabsf(m[0]) + fabsf(m[1]);
148 float devBoundsHalfHeight = fabsf(m[3]) + fabsf(m[4]);
149 batch->fBounds.fLeft = m[2] - devBoundsHalfWidth;
150 batch->fBounds.fRight = m[2] + devBoundsHalfWidth;
151 batch->fBounds.fTop = m[5] - devBoundsHalfHeight;
152 batch->fBounds.fBottom = m[5] + devBoundsHalfHeight;
153
154 // TODO: Is this worth the CPU overhead?
155 batch->fInfo.fNonSquare =
156 fabsf(devBoundsHalfHeight - devBoundsHalfWidth) > 0.5f || // Early o ut.
157 fabs(m[0] * m[3] + m[1] * m[4]) > 1e-3f || // Skew?
158 fabs(m[0] * m[0] + m[1] * m[1] - m[3] * m[3] - m[4] * m[4]) > 1e-2f; // Diff. lengths?
159 } else {
160 SkMatrix shapeMatrix(viewMatrix);
161 shapeMatrix.preTranslate(tx, ty);
162 shapeMatrix.preScale(sx, sy);
163 instance.fInfo |= kPerspective_InfoFlag;
164
165 float* m = instance.fShapeMatrix2x3;
166 m[0] = SkScalarToFloat(shapeMatrix.getScaleX());
167 m[1] = SkScalarToFloat(shapeMatrix.getSkewX());
168 m[2] = SkScalarToFloat(shapeMatrix.getTranslateX());
169 m[3] = SkScalarToFloat(shapeMatrix.getSkewY());
170 m[4] = SkScalarToFloat(shapeMatrix.getScaleY());
171 m[5] = SkScalarToFloat(shapeMatrix.getTranslateY());
172
173 // Send the perspective column as a param.
174 this->appendParamsTexel(shapeMatrix[SkMatrix::kMPersp0], shapeMatrix[SkM atrix::kMPersp1],
175 shapeMatrix[SkMatrix::kMPersp2]);
176 batch->fInfo.fHasPerspective = true;
177 batch->fInfo.fHasParams = true;
178
179 viewMatrix.mapRect(&batch->fBounds, bounds);
180
181 batch->fInfo.fNonSquare = true;
182 }
183
184 instance.fColor = color;
185
186 const float* rectAsFloats = localRect.asScalars(); // Ensure SkScalar == flo at.
187 memcpy(&instance.fLocalRect, rectAsFloats, 4 * sizeof(float));
188
189 return batch;
190 }
191
192 inline bool GrInstancedRendering::selectAntialiasMode(const SkMatrix& viewMatrix , bool antialias,
193 uint32_t flags, AntialiasM ode* antialiasMode,
194 bool* useHWAA) {
195 SkASSERT(flags & (kColorWrite_Flag | kStencilWrite_Flag));
196 SkASSERT((flags & (kColorBufferMSAA_Flag | kStencilBufferMSAA_Flag)) != kCol orBufferMSAA_Flag);
197
198 if (!antialias) {
199 if (!(fSupportedAAModes & kNone_AntialiasFlag)) {
200 return false;
201 }
202 if ((flags & (kStencilWrite_Flag | kUseDiscard_Flag)) == kStencilWrite_F lag) {
203 // We can only subtract coverage from the stencil output via discard when no MSAA.
204 return false;
205 }
206 *antialiasMode = kNone_AntialiasMode;
207 *useHWAA = false;
208 return true;
209 }
210
211 if (!(flags & (kColorBufferMSAA_Flag | kStencilWrite_Flag)) &&
212 viewMatrix.preservesRightAngles()) {
213 SkASSERT(fSupportedAAModes & kCoverage_AntialiasFlag);
214 *antialiasMode = kCoverage_AntialiasMode;
215 *useHWAA = false;
216 return true;
217 }
218
219 if ((fSupportedAAModes & kMSAA_AntialiasFlag) && (flags & kStencilBufferMSAA _Flag)) {
220 if ((flags ^ kColorWrite_Flag) & (kColorWrite_Flag | kColorBufferMSAA_Fl ag)) {
221 // We either do not write color, or the color buffer is multisampled .
222 *antialiasMode = kMSAA_AntialiasMode;
223 *useHWAA = true;
224 return true;
225 }
226 if (fSupportedAAModes & kMixedSamples_AntialiasFlag) {
227 *antialiasMode = kMixedSamples_AntialiasMode;
228 *useHWAA = true;
229 return true;
230 }
231 }
232
233 return false;
234 }
235
236 void GrInstancedRendering::appendRRectParams(const SkRRect& rrect, BatchInfo* ba tchInfo) {
237 switch (rrect.getType()) {
238 case SkRRect::kSimple_Type: {
239 const SkVector& radii = rrect.getSimpleRadii();
240 this->appendParamsTexel(radii.x(), radii.y(), rrect.width(), rrect.h eight());
241 batchInfo->fHasParams = true;
242 return;
243 }
244 case SkRRect::kNinePatch_Type: {
245 float twoOverW = 2 / rrect.width();
246 float twoOverH = 2 / rrect.height();
247 const SkVector& radiiTL = rrect.radii(SkRRect::kUpperLeft_Corner);
248 const SkVector& radiiBR = rrect.radii(SkRRect::kLowerRight_Corner);
249 this->appendParamsTexel(radiiTL.x() * twoOverW, radiiBR.x() * twoOve rW,
250 radiiTL.y() * twoOverH, radiiBR.y() * twoOve rH);
251 batchInfo->fHasParams = true;
252 return;
253 }
254 case SkRRect::kComplex_Type: {
255 /**
256 * The x and y radii of each arc are stored in separate vectors,
257 * in the following order:
258 *
259 * __x1 _ _ _ x3__
260 * y1 | | y2
261 *
262 * | |
263 *
264 * y3 |__ _ _ _ __| y4
265 * x2 x4
266 *
267 */
268 float twoOverW = 2 / rrect.width();
269 float twoOverH = 2 / rrect.height();
270 const SkVector& radiiTL = rrect.radii(SkRRect::kUpperLeft_Corner);
271 const SkVector& radiiTR = rrect.radii(SkRRect::kUpperRight_Corner);
272 const SkVector& radiiBR = rrect.radii(SkRRect::kLowerRight_Corner);
273 const SkVector& radiiBL = rrect.radii(SkRRect::kLowerLeft_Corner);
274 this->appendParamsTexel(radiiTL.x() * twoOverW, radiiBL.x() * twoOve rW,
275 radiiTR.x() * twoOverW, radiiBR.x() * twoOve rW);
276 this->appendParamsTexel(radiiTL.y() * twoOverH, radiiTR.y() * twoOve rH,
277 radiiBL.y() * twoOverH, radiiBR.y() * twoOve rH);
278 batchInfo->fHasParams = true;
279 return;
280 }
281 default: return;
282 }
283 }
284
285 void GrInstancedRendering::appendParamsTexel(const SkScalar* vals, int count) {
286 SkASSERT(count <= 4 && count >= 0);
287 const float* valsAsFloats = vals; // Ensure SkScalar == float.
288 memcpy(&fParams.push_back(), valsAsFloats, count * sizeof(float));
289 }
290
291 void GrInstancedRendering::appendParamsTexel(SkScalar x, SkScalar y, SkScalar z, SkScalar w) {
292 ParamsTexel& texel = fParams.push_back();
293 texel.fX = SkScalarToFloat(x);
294 texel.fY = SkScalarToFloat(y);
295 texel.fZ = SkScalarToFloat(z);
296 texel.fW = SkScalarToFloat(w);
297 }
298
299 void GrInstancedRendering::appendParamsTexel(SkScalar x, SkScalar y, SkScalar z) {
300 ParamsTexel& texel = fParams.push_back();
301 texel.fX = SkScalarToFloat(x);
302 texel.fY = SkScalarToFloat(y);
303 texel.fZ = SkScalarToFloat(z);
304 }
305
306 void GrInstancedRendering::Batch::computePipelineOptimizations(GrInitInvariantOu tput* color,
307 GrInitInvariantOutpu t* coverage,
308 GrBatchToXPOverrides * overrides) const {
309 // We need to be careful about fInfo here and consider how it might change a s batches combine.
310 // e.g. We can't make an assumption based on fInfo.isSimpleRects() because t he batch might
311 // later combine with an oval.
312 color->setUnknownFourComponents();
313 if (fInfo.fAntialiasMode >= kMSAA_AntialiasMode) {
314 coverage->setKnownSingleComponent(255);
315 } else if (kNone_AntialiasMode == fInfo.fAntialiasMode && !fInfo.fCannotDisc ard) {
316 // We can rely on fCannotDiscard because this particular field does not change.
317 coverage->setKnownSingleComponent(255);
318 } else {
319 coverage->setUnknownSingleComponent();
320 }
321 }
322
323 void GrInstancedRendering::Batch::initBatchTracker(const GrXPOverridesForBatch& overrides) {
324 fInfo.fUsesLocalCoords = overrides.readsLocalCoords();
325 fInfo.fCannotTweakAlphaForCoverage = !overrides.canTweakAlphaForCoverage();
326
327 GrColor overrideColor;
328 if (overrides.getOverrideColorIfSet(&overrideColor)) {
329 SkASSERT(State::kRecordingDraws == fInstancedRendering->fState);
330 SkASSERT(!fIsCombined);
331 fInstancedRendering->fInstances[fFirstInstanceIdx].fColor = overrideColo r;
332 }
333 }
334
335 void GrInstancedRendering::beginFlush(GrResourceProvider* rp) {
336 SkASSERT(State::kRecordingDraws == fState);
337 fState = State::kFlushing;
338
339 if (fInstances.empty()) {
340 return;
341 }
342
343 if (!fVertexBuffer) {
344 fVertexBuffer.reset(GrInstanceProcessor::FindOrCreateVertexBuffer(fGpu)) ;
345 if (!fVertexBuffer) {
346 return;
347 }
348 }
349
350 if (!fIndexBuffer) {
351 fIndexBuffer.reset(GrInstanceProcessor::FindOrCreateIndex8Buffer(fGpu));
352 if (!fIndexBuffer) {
353 return;
354 }
355 }
356
357 fInstanceBuffer.reset(rp->createBuffer(fInstances.count() * sizeof(Instance) ,
358 kVertex_GrBufferType, kDynamic_GrAcce ssPattern,
359 GrResourceProvider::kNoPendingIO_Flag ,
360 fInstances.begin()));
361 if (!fInstanceBuffer) {
362 return;
363 }
364
365 if (!fParams.empty()) {
366 fParamsBuffer.reset(rp->createBuffer(fParams.count() * sizeof(ParamsTexe l),
367 kTexel_GrBufferType, kDynamic_GrAcc essPattern,
368 GrResourceProvider::kNoPendingIO_Fl ag,
369 fParams.begin()));
370 if (!fParamsBuffer) {
371 return;
372 }
373 }
374
375 this->onBeginFlush(rp);
376 }
377
378 void GrInstancedRendering::Batch::onDraw(GrBatchFlushState* state) {
379 SkASSERT(State::kFlushing == fInstancedRendering->fState);
380 SkASSERT(state->gpu() == fInstancedRendering->gpu());
381
382 GrInstanceProcessor instProc(fInfo, fInstancedRendering->fParamsBuffer);
383 fInstancedRendering->onDraw(*this->pipeline(), instProc, this);
384 }
385
386 void GrInstancedRendering::Batch::onDelete() const {
387 this->~Batch();
388 SkDEBUGCODE(--fInstancedRendering->fInUseBatchCount);
389 if (this == fInstancedRendering->fBatchAllocator.back()) {
390 fInstancedRendering->fBatchAllocator.pop_back();
391 }
392 }
393
394 void GrInstancedRendering::endFlush() {
395 SkASSERT(0 == fInUseBatchCount);
396 fBatchAllocator.reset();
397 // Hold on to the shape coords and index buffers.
398 fInstances.reset();
399 fParams.reset();
400 fInstanceBuffer.reset();
401 fParamsBuffer.reset();
402 this->onEndFlush();
403 fState = State::kRecordingDraws;
404 }
405
406 void GrInstancedRendering::resetGpuResources(ResetType resetType) {
407 fVertexBuffer.reset();
408 fIndexBuffer.reset();
409 fInstanceBuffer.reset();
410 fParamsBuffer.reset();
411 this->onResetGpuResources(resetType);
412 }
OLDNEW
« no previous file with comments | « src/gpu/GrInstancedRendering.h ('k') | src/gpu/GrInstancedRenderingTypes.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698