blob: 582d2e8e048ed6e2c5ac83b3b5f1e6dcd2c909f9 [file] [log] [blame]
joshualitt9ff64252015-08-10 09:03:51 -07001/*
2 * Copyright 2015 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 "GrAAFillRectBatch.h"
9
joshualitt37eb1842015-08-12 06:36:57 -070010#include "GrBatch.h"
11#include "GrColor.h"
joshualitt9ff64252015-08-10 09:03:51 -070012#include "GrDefaultGeoProcFactory.h"
13#include "GrResourceKey.h"
14#include "GrResourceProvider.h"
joshualitt37eb1842015-08-12 06:36:57 -070015#include "GrTypes.h"
16#include "SkMatrix.h"
17#include "SkRect.h"
joshualitt9ff64252015-08-10 09:03:51 -070018
19GR_DECLARE_STATIC_UNIQUE_KEY(gAAFillRectIndexBufferKey);
20
21static void set_inset_fan(SkPoint* pts, size_t stride,
22 const SkRect& r, SkScalar dx, SkScalar dy) {
23 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
24 r.fRight - dx, r.fBottom - dy, stride);
25}
26
27static const GrGeometryProcessor* create_fill_rect_gp(bool tweakAlphaForCoverage,
28 const SkMatrix& viewMatrix,
29 bool usesLocalCoords,
30 bool coverageIgnored) {
31 using namespace GrDefaultGeoProcFactory;
32
33 Color color(Color::kAttribute_Type);
34 Coverage::Type coverageType;
35 // TODO remove coverage if coverage is ignored
36 /*if (coverageIgnored) {
37 coverageType = Coverage::kNone_Type;
38 } else*/ if (tweakAlphaForCoverage) {
39 coverageType = Coverage::kSolid_Type;
40 } else {
41 coverageType = Coverage::kAttribute_Type;
42 }
43 Coverage coverage(coverageType);
44 LocalCoords localCoords(usesLocalCoords ? LocalCoords::kUsePosition_Type :
45 LocalCoords::kUnused_Type);
46 return CreateForDeviceSpace(color, coverage, localCoords, viewMatrix);
47}
48
joshualitt37eb1842015-08-12 06:36:57 -070049class AAFillRectBatch : public GrBatch {
50public:
51 struct Geometry {
52 GrColor fColor;
53 SkMatrix fViewMatrix;
54 SkRect fRect;
55 SkRect fDevRect;
joshualitt9ff64252015-08-10 09:03:51 -070056 };
joshualitt9ff64252015-08-10 09:03:51 -070057
joshualitt37eb1842015-08-12 06:36:57 -070058 static GrBatch* Create(GrColor color,
59 const SkMatrix& viewMatrix,
60 const SkRect& rect,
61 const SkRect& devRect) {
62 return SkNEW_ARGS(AAFillRectBatch, (color, viewMatrix, rect, devRect));
joshualitt9ff64252015-08-10 09:03:51 -070063 }
64
joshualitt37eb1842015-08-12 06:36:57 -070065 const char* name() const override { return "AAFillRectBatch"; }
joshualitt9ff64252015-08-10 09:03:51 -070066
joshualitt37eb1842015-08-12 06:36:57 -070067 void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
68 // When this is called on a batch, there is only one geometry bundle
69 out->setKnownFourComponents(fGeoData[0].fColor);
joshualitt9ff64252015-08-10 09:03:51 -070070 }
71
joshualitt37eb1842015-08-12 06:36:57 -070072 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
73 out->setUnknownSingleComponent();
joshualitt9ff64252015-08-10 09:03:51 -070074 }
75
joshualitt37eb1842015-08-12 06:36:57 -070076 void initBatchTracker(const GrPipelineOptimizations& opt) override {
77 // Handle any color overrides
78 if (!opt.readsColor()) {
79 fGeoData[0].fColor = GrColor_ILLEGAL;
80 }
81 opt.getOverrideColorIfSet(&fGeoData[0].fColor);
82
83 // setup batch properties
84 fBatch.fColorIgnored = !opt.readsColor();
85 fBatch.fColor = fGeoData[0].fColor;
86 fBatch.fUsesLocalCoords = opt.readsLocalCoords();
87 fBatch.fCoverageIgnored = !opt.readsCoverage();
88 fBatch.fCanTweakAlphaForCoverage = opt.canTweakAlphaForCoverage();
joshualitt9ff64252015-08-10 09:03:51 -070089 }
90
joshualitt37eb1842015-08-12 06:36:57 -070091 void generateGeometry(GrBatchTarget* batchTarget) override {
92 bool canTweakAlphaForCoverage = this->canTweakAlphaForCoverage();
joshualitt9ff64252015-08-10 09:03:51 -070093
joshualitt37eb1842015-08-12 06:36:57 -070094 SkAutoTUnref<const GrGeometryProcessor> gp(create_fill_rect_gp(canTweakAlphaForCoverage,
95 this->viewMatrix(),
96 this->usesLocalCoords(),
97 this->coverageIgnored()));
98 if (!gp) {
99 SkDebugf("Couldn't create GrGeometryProcessor\n");
100 return;
101 }
joshualitt9ff64252015-08-10 09:03:51 -0700102
joshualitt37eb1842015-08-12 06:36:57 -0700103 batchTarget->initDraw(gp, this->pipeline());
joshualitt9ff64252015-08-10 09:03:51 -0700104
joshualitt37eb1842015-08-12 06:36:57 -0700105 size_t vertexStride = gp->getVertexStride();
106 SkASSERT(canTweakAlphaForCoverage ?
107 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr) :
108 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
109 int instanceCount = fGeoData.count();
joshualitt9ff64252015-08-10 09:03:51 -0700110
joshualitt37eb1842015-08-12 06:36:57 -0700111 SkAutoTUnref<const GrIndexBuffer> indexBuffer(this->getIndexBuffer(
112 batchTarget->resourceProvider()));
113 InstancedHelper helper;
114 void* vertices = helper.init(batchTarget, kTriangles_GrPrimitiveType, vertexStride,
115 indexBuffer, kVertsPerAAFillRect, kIndicesPerAAFillRect,
116 instanceCount);
117 if (!vertices || !indexBuffer) {
118 SkDebugf("Could not allocate vertices\n");
119 return;
120 }
121
122 for (int i = 0; i < instanceCount; i++) {
123 const Geometry& args = fGeoData[i];
124 this->generateAAFillRectGeometry(vertices,
125 i * kVertsPerAAFillRect * vertexStride,
126 vertexStride,
127 args.fColor,
128 args.fViewMatrix,
129 args.fRect,
130 args.fDevRect,
131 canTweakAlphaForCoverage);
132 }
133
134 helper.issueDraw(batchTarget);
135 }
136
137 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
138
139private:
140 AAFillRectBatch(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect,
141 const SkRect& devRect) {
142 this->initClassID<AAFillRectBatch>();
143 Geometry& geometry = fGeoData.push_back();
144 geometry.fRect = rect;
145 geometry.fViewMatrix = viewMatrix;
146 geometry.fDevRect = devRect;
147 geometry.fColor = color;
148
149 this->setBounds(geometry.fDevRect);
150 }
151
152 static const int kNumAAFillRectsInIndexBuffer = 256;
153 static const int kVertsPerAAFillRect = 8;
154 static const int kIndicesPerAAFillRect = 30;
155
156 const GrIndexBuffer* getIndexBuffer(GrResourceProvider* resourceProvider) {
157 GR_DEFINE_STATIC_UNIQUE_KEY(gAAFillRectIndexBufferKey);
158
159 static const uint16_t gFillAARectIdx[] = {
160 0, 1, 5, 5, 4, 0,
161 1, 2, 6, 6, 5, 1,
162 2, 3, 7, 7, 6, 2,
163 3, 0, 4, 4, 7, 3,
164 4, 5, 6, 6, 7, 4,
joshualitt9ff64252015-08-10 09:03:51 -0700165 };
joshualitt37eb1842015-08-12 06:36:57 -0700166 GR_STATIC_ASSERT(SK_ARRAY_COUNT(gFillAARectIdx) == kIndicesPerAAFillRect);
167 return resourceProvider->findOrCreateInstancedIndexBuffer(gFillAARectIdx,
168 kIndicesPerAAFillRect, kNumAAFillRectsInIndexBuffer, kVertsPerAAFillRect,
169 gAAFillRectIndexBufferKey);
joshualitt9ff64252015-08-10 09:03:51 -0700170 }
171
joshualitt37eb1842015-08-12 06:36:57 -0700172 GrColor color() const { return fBatch.fColor; }
173 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
174 bool canTweakAlphaForCoverage() const { return fBatch.fCanTweakAlphaForCoverage; }
175 bool colorIgnored() const { return fBatch.fColorIgnored; }
176 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
177 bool coverageIgnored() const { return fBatch.fCoverageIgnored; }
178
179 bool onCombineIfPossible(GrBatch* t) override {
180 if (!this->pipeline()->isEqual(*t->pipeline())) {
181 return false;
182 }
183
184 AAFillRectBatch* that = t->cast<AAFillRectBatch>();
185
186 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
187 // We apply the viewmatrix to the rect points on the cpu. However, if the pipeline uses
188 // local coords then we won't be able to batch. We could actually upload the viewmatrix
189 // using vertex attributes in these cases, but haven't investigated that
190 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
191 return false;
192 }
193
194 if (this->color() != that->color()) {
195 fBatch.fColor = GrColor_ILLEGAL;
196 }
197
198 // In the event of two batches, one who can tweak, one who cannot, we just fall back to
199 // not tweaking
200 if (this->canTweakAlphaForCoverage() != that->canTweakAlphaForCoverage()) {
201 fBatch.fCanTweakAlphaForCoverage = false;
202 }
203
204 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
205 this->joinBounds(that->bounds());
206 return true;
207 }
208
209 void generateAAFillRectGeometry(void* vertices,
210 size_t offset,
211 size_t vertexStride,
212 GrColor color,
213 const SkMatrix& viewMatrix,
214 const SkRect& rect,
215 const SkRect& devRect,
216 bool tweakAlphaForCoverage) const {
217 intptr_t verts = reinterpret_cast<intptr_t>(vertices) + offset;
218
219 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
220 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vertexStride);
221
222 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
223 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
224
225 if (viewMatrix.rectStaysRect()) {
226 set_inset_fan(fan0Pos, vertexStride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
227 set_inset_fan(fan1Pos, vertexStride, devRect, inset, inset);
joshualitt9ff64252015-08-10 09:03:51 -0700228 } else {
joshualitt37eb1842015-08-12 06:36:57 -0700229 // compute transformed (1, 0) and (0, 1) vectors
230 SkVector vec[2] = {
231 { viewMatrix[SkMatrix::kMScaleX], viewMatrix[SkMatrix::kMSkewY] },
232 { viewMatrix[SkMatrix::kMSkewX], viewMatrix[SkMatrix::kMScaleY] }
233 };
234
235 vec[0].normalize();
236 vec[0].scale(SK_ScalarHalf);
237 vec[1].normalize();
238 vec[1].scale(SK_ScalarHalf);
239
240 // create the rotated rect
241 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
242 rect.fRight, rect.fBottom, vertexStride);
243 viewMatrix.mapPointsWithStride(fan0Pos, vertexStride, 4);
244
245 // Now create the inset points and then outset the original
246 // rotated points
247
248 // TL
249 *((SkPoint*)((intptr_t)fan1Pos + 0 * vertexStride)) =
250 *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) + vec[0] + vec[1];
251 *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) -= vec[0] + vec[1];
252 // BL
253 *((SkPoint*)((intptr_t)fan1Pos + 1 * vertexStride)) =
254 *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) + vec[0] - vec[1];
255 *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) -= vec[0] - vec[1];
256 // BR
257 *((SkPoint*)((intptr_t)fan1Pos + 2 * vertexStride)) =
258 *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) - vec[0] - vec[1];
259 *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) += vec[0] + vec[1];
260 // TR
261 *((SkPoint*)((intptr_t)fan1Pos + 3 * vertexStride)) =
262 *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) - vec[0] + vec[1];
263 *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) += vec[0] - vec[1];
264 }
265
266 // Make verts point to vertex color and then set all the color and coverage vertex attrs
267 // values.
268 verts += sizeof(SkPoint);
269 for (int i = 0; i < 4; ++i) {
270 if (tweakAlphaForCoverage) {
271 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0;
272 } else {
273 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
274 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = 0;
275 }
276 }
277
278 int scale;
279 if (inset < SK_ScalarHalf) {
280 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
281 SkASSERT(scale >= 0 && scale <= 255);
282 } else {
283 scale = 0xff;
284 }
285
286 verts += 4 * vertexStride;
287
288 float innerCoverage = GrNormalizeByteToFloat(scale);
289 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
290
291 for (int i = 0; i < 4; ++i) {
292 if (tweakAlphaForCoverage) {
293 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
294 } else {
295 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
296 *reinterpret_cast<float*>(verts + i * vertexStride +
297 sizeof(GrColor)) = innerCoverage;
298 }
joshualitt9ff64252015-08-10 09:03:51 -0700299 }
300 }
301
joshualitt37eb1842015-08-12 06:36:57 -0700302 struct BatchTracker {
303 GrColor fColor;
304 bool fUsesLocalCoords;
305 bool fColorIgnored;
306 bool fCoverageIgnored;
307 bool fCanTweakAlphaForCoverage;
308 };
joshualitt9ff64252015-08-10 09:03:51 -0700309
joshualitt37eb1842015-08-12 06:36:57 -0700310 BatchTracker fBatch;
311 SkSTArray<1, Geometry, true> fGeoData;
312};
joshualitt9ff64252015-08-10 09:03:51 -0700313
joshualitt37eb1842015-08-12 06:36:57 -0700314namespace GrAAFillRectBatch {
joshualitt9ff64252015-08-10 09:03:51 -0700315
joshualitt37eb1842015-08-12 06:36:57 -0700316GrBatch* Create(GrColor color,
317 const SkMatrix& viewMatrix,
318 const SkRect& rect,
319 const SkRect& devRect) {
320 return AAFillRectBatch::Create(color, viewMatrix, rect, devRect);
joshualitt9ff64252015-08-10 09:03:51 -0700321}
322
joshualitt37eb1842015-08-12 06:36:57 -0700323};
324
joshualitt9ff64252015-08-10 09:03:51 -0700325///////////////////////////////////////////////////////////////////////////////////////////////////
326
327#ifdef GR_TEST_UTILS
328
329#include "GrBatchTest.h"
330
331BATCH_TEST_DEFINE(AAFillRectBatch) {
joshualitt37eb1842015-08-12 06:36:57 -0700332 GrColor color = GrRandomColor(random);
333 SkMatrix viewMatrix = GrTest::TestMatrix(random);
334 SkRect rect = GrTest::TestRect(random);
335 SkRect devRect = GrTest::TestRect(random);
336 return AAFillRectBatch::Create(color, viewMatrix, rect, devRect);
joshualitt9ff64252015-08-10 09:03:51 -0700337}
338
339#endif