blob: aa599ca8323804a716efc446fd3825bac10f9ea0 [file] [log] [blame]
robertphillips@google.comf6747b02012-06-12 00:32:28 +00001/*
2 * Copyright 2012 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 "GrAARectRenderer.h"
robertphillips@google.comf6747b02012-06-12 00:32:28 +00009#include "GrGpu.h"
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000010#include "gl/GrGLEffect.h"
commit-bot@chromium.org261dc562013-10-04 15:42:56 +000011#include "gl/GrGLVertexEffect.h"
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000012#include "GrTBackendEffectFactory.h"
robertphillips@google.com908aed82013-05-28 13:16:20 +000013#include "SkColorPriv.h"
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +000014#include "effects/GrVertexEffect.h"
robertphillips@google.comf6747b02012-06-12 00:32:28 +000015
robertphillips@google.com4d73ac22012-06-13 18:54:08 +000016SK_DEFINE_INST_COUNT(GrAARectRenderer)
robertphillips@google.comf6747b02012-06-12 00:32:28 +000017
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000018///////////////////////////////////////////////////////////////////////////////
19class GrGLAlignedRectEffect;
20
21// Axis Aligned special case
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +000022class GrAlignedRectEffect : public GrVertexEffect {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000023public:
24 static GrEffectRef* Create() {
25 GR_CREATE_STATIC_EFFECT(gAlignedRectEffect, GrAlignedRectEffect, ());
26 gAlignedRectEffect->ref();
27 return gAlignedRectEffect;
28 }
29
30 virtual ~GrAlignedRectEffect() {}
31
32 static const char* Name() { return "AlignedRectEdge"; }
33
34 virtual void getConstantColorComponents(GrColor* color,
35 uint32_t* validFlags) const SK_OVERRIDE {
36 *validFlags = 0;
37 }
38
39 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
40 return GrTBackendEffectFactory<GrAlignedRectEffect>::getInstance();
41 }
42
commit-bot@chromium.org261dc562013-10-04 15:42:56 +000043 class GLEffect : public GrGLVertexEffect {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000044 public:
45 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
46 : INHERITED (factory) {}
47
commit-bot@chromium.org261dc562013-10-04 15:42:56 +000048 virtual void emitCode(GrGLFullShaderBuilder* builder,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000049 const GrDrawEffect& drawEffect,
50 EffectKey key,
51 const char* outputColor,
52 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +000053 const TransformedCoordsArray&,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000054 const TextureSamplerArray& samplers) SK_OVERRIDE {
55 // setup the varying for the Axis aligned rect effect
56 // xy -> interpolated offset
57 // zw -> w/2+0.5, h/2+0.5
58 const char *vsRectName, *fsRectName;
commit-bot@chromium.org261dc562013-10-04 15:42:56 +000059 builder->addVarying(kVec4f_GrSLType, "Rect", &vsRectName, &fsRectName);
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000060 const SkString* attr0Name =
commit-bot@chromium.org261dc562013-10-04 15:42:56 +000061 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
62 builder->vsCodeAppendf("\t%s = %s;\n", vsRectName, attr0Name->c_str());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000063
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000064 // TODO: compute all these offsets, spans, and scales in the VS
65 builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.z) - 0.5;\n", fsRectName);
66 builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.w) - 0.5;\n", fsRectName);
67 builder->fsCodeAppend("\tfloat outset = 0.5;\n");
68 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
69 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
70 builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n");
71 builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n");
72 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
73 // value of coverage that is used. In other words it is the coverage that is
74 // used in the interior of the rect after the ramp.
robertphillips@google.com07a05242013-06-14 17:45:30 +000075 builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
76 builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000077
78 // Compute the coverage for the rect's width
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000079 builder->fsCodeAppendf(
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000080 "\tfloat coverage = scaleW*clamp((%s.z-abs(%s.x))/spanW, 0.0, 1.0);\n", fsRectName,
81 fsRectName);
82 // Compute the coverage for the rect's height and merge with the width
egdaniel@google.comf1d7de72013-06-14 19:25:53 +000083 builder->fsCodeAppendf(
84 "\tcoverage = coverage*scaleH*clamp((%s.w-abs(%s.y))/spanH, 0.0, 1.0);\n",
85 fsRectName, fsRectName);
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000086
commit-bot@chromium.org824c3462013-10-10 06:30:18 +000087
88 builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +000089 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("coverage")).c_str());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000090 }
91
92 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
93 return 0;
94 }
95
96 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
97
98 private:
commit-bot@chromium.org261dc562013-10-04 15:42:56 +000099 typedef GrGLVertexEffect INHERITED;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000100 };
101
102
103private:
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000104 GrAlignedRectEffect() : GrVertexEffect() {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000105 this->addVertexAttrib(kVec4f_GrSLType);
106 }
107
108 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
109
110 GR_DECLARE_EFFECT_TEST;
111
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000112 typedef GrVertexEffect INHERITED;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000113};
114
115
116GR_DEFINE_EFFECT_TEST(GrAlignedRectEffect);
117
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000118GrEffectRef* GrAlignedRectEffect::TestCreate(SkRandom* random,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000119 GrContext* context,
120 const GrDrawTargetCaps&,
121 GrTexture* textures[]) {
122 return GrAlignedRectEffect::Create();
123}
124
125///////////////////////////////////////////////////////////////////////////////
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000126class GrGLRectEffect;
127
128/**
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000129 * The output of this effect is a modulation of the input color and coverage
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000130 * for an arbitrarily oriented rect. The rect is specified as:
131 * Center of the rect
132 * Unit vector point down the height of the rect
133 * Half width + 0.5
134 * Half height + 0.5
135 * The center and vector are stored in a vec4 varying ("RectEdge") with the
136 * center in the xy components and the vector in the zw components.
137 * The munged width and height are stored in a vec2 varying ("WidthHeight")
138 * with the width in x and the height in y.
139 */
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000140class GrRectEffect : public GrVertexEffect {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000141public:
142 static GrEffectRef* Create() {
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000143 GR_CREATE_STATIC_EFFECT(gRectEffect, GrRectEffect, ());
144 gRectEffect->ref();
145 return gRectEffect;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000146 }
147
148 virtual ~GrRectEffect() {}
149
150 static const char* Name() { return "RectEdge"; }
151
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000152 virtual void getConstantColorComponents(GrColor* color,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000153 uint32_t* validFlags) const SK_OVERRIDE {
154 *validFlags = 0;
155 }
156
157 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
158 return GrTBackendEffectFactory<GrRectEffect>::getInstance();
159 }
160
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000161 class GLEffect : public GrGLVertexEffect {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000162 public:
163 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
164 : INHERITED (factory) {}
165
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000166 virtual void emitCode(GrGLFullShaderBuilder* builder,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000167 const GrDrawEffect& drawEffect,
168 EffectKey key,
169 const char* outputColor,
170 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +0000171 const TransformedCoordsArray&,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000172 const TextureSamplerArray& samplers) SK_OVERRIDE {
173 // setup the varying for the center point and the unit vector
174 // that points down the height of the rect
175 const char *vsRectEdgeName, *fsRectEdgeName;
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000176 builder->addVarying(kVec4f_GrSLType, "RectEdge",
177 &vsRectEdgeName, &fsRectEdgeName);
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000178 const SkString* attr0Name =
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000179 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
180 builder->vsCodeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000181
182 // setup the varying for width/2+.5 and height/2+.5
183 const char *vsWidthHeightName, *fsWidthHeightName;
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000184 builder->addVarying(kVec2f_GrSLType, "WidthHeight",
185 &vsWidthHeightName, &fsWidthHeightName);
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000186 const SkString* attr1Name =
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000187 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
188 builder->vsCodeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000189
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000190 // TODO: compute all these offsets, spans, and scales in the VS
191 builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.x) - 0.5;\n", fsWidthHeightName);
192 builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.y) - 0.5;\n", fsWidthHeightName);
193 builder->fsCodeAppend("\tfloat outset = 0.5;\n");
194 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
195 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
196 builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n");
197 builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n");
198 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
199 // value of coverage that is used. In other words it is the coverage that is
200 // used in the interior of the rect after the ramp.
201 builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
202 builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000203
204 // Compute the coverage for the rect's width
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000205 builder->fsCodeAppendf("\tvec2 offset = %s.xy - %s.xy;\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000206 builder->fragmentPosition(), fsRectEdgeName);
207 builder->fsCodeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
208 fsRectEdgeName, fsRectEdgeName);
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000209 builder->fsCodeAppendf(
210 "\tfloat coverage = scaleW*clamp((%s.x-perpDot)/spanW, 0.0, 1.0);\n",
211 fsWidthHeightName);
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000212
213 // Compute the coverage for the rect's height and merge with the width
214 builder->fsCodeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
215 fsRectEdgeName);
216 builder->fsCodeAppendf(
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000217 "\tcoverage = coverage*scaleH*clamp((%s.y-perpDot)/spanH, 0.0, 1.0);\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000218 fsWidthHeightName);
219
commit-bot@chromium.org824c3462013-10-10 06:30:18 +0000220
221 builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000222 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("coverage")).c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000223 }
224
225 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
226 return 0;
227 }
228
229 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
230
231 private:
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000232 typedef GrGLVertexEffect INHERITED;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000233 };
234
235
236private:
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000237 GrRectEffect() : GrVertexEffect() {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000238 this->addVertexAttrib(kVec4f_GrSLType);
239 this->addVertexAttrib(kVec2f_GrSLType);
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000240 this->setWillReadFragmentPosition();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000241 }
242
243 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
244
245 GR_DECLARE_EFFECT_TEST;
246
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000247 typedef GrVertexEffect INHERITED;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000248};
249
250
251GR_DEFINE_EFFECT_TEST(GrRectEffect);
252
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000253GrEffectRef* GrRectEffect::TestCreate(SkRandom* random,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000254 GrContext* context,
255 const GrDrawTargetCaps&,
256 GrTexture* textures[]) {
257 return GrRectEffect::Create();
258}
259
260///////////////////////////////////////////////////////////////////////////////
261
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000262namespace {
263
robertphillips@google.com42903302013-04-20 12:26:07 +0000264extern const GrVertexAttrib gAARectCoverageAttribs[] = {
265 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
266 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kCoverage_GrVertexAttribBinding},
267};
268
269extern const GrVertexAttrib gAARectColorAttribs[] = {
270 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
271 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kColor_GrVertexAttribBinding},
272};
273
274static void set_aa_rect_vertex_attributes(GrDrawState* drawState, bool useCoverage) {
275 if (useCoverage) {
276 drawState->setVertexAttribs<gAARectCoverageAttribs>(SK_ARRAY_COUNT(gAARectCoverageAttribs));
277 } else {
278 drawState->setVertexAttribs<gAARectColorAttribs>(SK_ARRAY_COUNT(gAARectColorAttribs));
279 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000280}
281
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000282static void set_inset_fan(GrPoint* pts, size_t stride,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000283 const SkRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000284 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
285 r.fRight - dx, r.fBottom - dy, stride);
286}
287
288};
289
290void GrAARectRenderer::reset() {
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000291 SkSafeSetNull(fAAFillRectIndexBuffer);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000292 SkSafeSetNull(fAAMiterStrokeRectIndexBuffer);
293 SkSafeSetNull(fAABevelStrokeRectIndexBuffer);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000294}
295
robertphillips@google.com6d067302012-12-18 21:47:47 +0000296static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000297 0, 1, 5, 5, 4, 0,
298 1, 2, 6, 6, 5, 1,
299 2, 3, 7, 7, 6, 2,
300 3, 0, 4, 4, 7, 3,
301 4, 5, 6, 6, 7, 4,
302};
303
robertphillips@google.com6d067302012-12-18 21:47:47 +0000304static const int kIndicesPerAAFillRect = GR_ARRAY_COUNT(gFillAARectIdx);
305static const int kVertsPerAAFillRect = 8;
306static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000307
308GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000309 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
310 sizeof(uint16_t) *
311 kNumAAFillRectsInIndexBuffer;
312
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000313 if (NULL == fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000314 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000315 if (NULL != fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000316 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->lock();
317 bool useTempData = (NULL == data);
318 if (useTempData) {
319 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
320 }
321 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
322 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
323 // the inner rect (for AA) and 2 for the inner rect.
324 int baseIdx = i * kIndicesPerAAFillRect;
325 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
326 for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
327 data[baseIdx+j] = baseVert + gFillAARectIdx[j];
328 }
329 }
330 if (useTempData) {
331 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
332 GrCrash("Can't get AA Fill Rect indices into buffer!");
333 }
334 SkDELETE_ARRAY(data);
335 } else {
336 fAAFillRectIndexBuffer->unlock();
337 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000338 }
339 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000340
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000341 return fAAFillRectIndexBuffer;
342}
343
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000344static const uint16_t gMiterStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000345 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
346 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
347 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
348 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
349
350 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
351 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
352 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
353 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
354
355 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
356 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
357 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
358 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
359};
360
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000361/**
362 * As in miter-stroke, index = a + b, and a is the current index, b is the shift
363 * from the first index. The index layout:
364 * outer AA line: 0~3, 4~7
365 * outer edge: 8~11, 12~15
366 * inner edge: 16~19
367 * inner AA line: 20~23
368 * Following comes a bevel-stroke rect and its indices:
369 *
370 * 4 7
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000371 * *********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000372 * * ______________________________ *
373 * * / 12 15 \ *
374 * * / \ *
375 * 0 * |8 16_____________________19 11 | * 3
376 * * | | | | *
377 * * | | **************** | | *
378 * * | | * 20 23 * | | *
379 * * | | * * | | *
380 * * | | * 21 22 * | | *
381 * * | | **************** | | *
382 * * | |____________________| | *
383 * 1 * |9 17 18 10| * 2
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000384 * * \ / *
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000385 * * \13 __________________________14/ *
386 * * *
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000387 * **********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000388 * 5 6
389 */
390static const uint16_t gBevelStrokeAARectIdx[] = {
391 // Draw outer AA, from outer AA line to outer edge, shift is 0.
392 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
393 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
394 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
395 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
396 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
397 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
398 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
399 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
400
401 // Draw the stroke, from outer edge to inner edge, shift is 8.
402 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
403 1 + 8, 5 + 8, 9 + 8,
404 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
405 6 + 8, 2 + 8, 10 + 8,
406 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
407 3 + 8, 7 + 8, 11 + 8,
408 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
409 4 + 8, 0 + 8, 8 + 8,
410
411 // Draw the inner AA, from inner edge to inner AA line, shift is 16.
412 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
413 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
414 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
415 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
416};
417
418int GrAARectRenderer::aaStrokeRectIndexCount(bool miterStroke) {
419 return miterStroke ? GR_ARRAY_COUNT(gMiterStrokeAARectIdx) :
420 GR_ARRAY_COUNT(gBevelStrokeAARectIdx);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000421}
422
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000423GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu, bool miterStroke) {
424 if (miterStroke) {
425 if (NULL == fAAMiterStrokeRectIndexBuffer) {
426 fAAMiterStrokeRectIndexBuffer =
427 gpu->createIndexBuffer(sizeof(gMiterStrokeAARectIdx), false);
428 if (NULL != fAAMiterStrokeRectIndexBuffer) {
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000429#ifdef SK_DEBUG
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000430 bool updated =
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000431#endif
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000432 fAAMiterStrokeRectIndexBuffer->updateData(gMiterStrokeAARectIdx,
433 sizeof(gMiterStrokeAARectIdx));
434 GR_DEBUGASSERT(updated);
435 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000436 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000437 return fAAMiterStrokeRectIndexBuffer;
438 } else {
439 if (NULL == fAABevelStrokeRectIndexBuffer) {
440 fAABevelStrokeRectIndexBuffer =
441 gpu->createIndexBuffer(sizeof(gBevelStrokeAARectIdx), false);
442 if (NULL != fAABevelStrokeRectIndexBuffer) {
443#ifdef SK_DEBUG
444 bool updated =
445#endif
446 fAABevelStrokeRectIndexBuffer->updateData(gBevelStrokeAARectIdx,
447 sizeof(gBevelStrokeAARectIdx));
448 GR_DEBUGASSERT(updated);
449 }
450 }
451 return fAABevelStrokeRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000452 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000453}
454
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000455void GrAARectRenderer::geometryFillAARect(GrGpu* gpu,
456 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000457 const SkRect& rect,
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000458 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000459 const SkRect& devRect,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000460 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000461 GrDrawState* drawState = target->drawState();
462
robertphillips@google.com42903302013-04-20 12:26:07 +0000463 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000464
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000465 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000466 if (!geo.succeeded()) {
467 GrPrintf("Failed to get space for vertices!\n");
468 return;
469 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000470
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000471 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
472 if (NULL == indexBuffer) {
473 GrPrintf("Failed to create index buffer!\n");
474 return;
475 }
476
477 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000478 size_t vsize = drawState->getVertexSize();
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000479 SkASSERT(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000480
481 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
482 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
483
robertphillips@google.com908aed82013-05-28 13:16:20 +0000484 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
485 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
486
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000487 if (combinedMatrix.rectStaysRect()) {
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000488 // Temporarily #if'ed out. We don't want to pass in the devRect but
489 // right now it is computed in GrContext::apply_aa_to_rect and we don't
490 // want to throw away the work
491#if 0
robertphillips@google.com91b71162013-05-10 14:09:54 +0000492 SkRect devRect;
493 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000494#endif
robertphillips@google.com91b71162013-05-10 14:09:54 +0000495
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000496 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
robertphillips@google.com908aed82013-05-28 13:16:20 +0000497 set_inset_fan(fan1Pos, vsize, devRect, inset, inset);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000498 } else {
499 // compute transformed (1, 0) and (0, 1) vectors
500 SkVector vec[2] = {
501 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
502 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
503 };
504
505 vec[0].normalize();
506 vec[0].scale(SK_ScalarHalf);
507 vec[1].normalize();
508 vec[1].scale(SK_ScalarHalf);
509
robertphillips@google.com91b71162013-05-10 14:09:54 +0000510 // create the rotated rect
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000511 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
512 rect.fRight, rect.fBottom, vsize);
513 combinedMatrix.mapPointsWithStride(fan0Pos, vsize, 4);
514
robertphillips@google.com91b71162013-05-10 14:09:54 +0000515 // Now create the inset points and then outset the original
516 // rotated points
517
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000518 // TL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000519 *((SkPoint*)((intptr_t)fan1Pos + 0 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000520 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) + vec[0] + vec[1];
521 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) -= vec[0] + vec[1];
522 // BL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000523 *((SkPoint*)((intptr_t)fan1Pos + 1 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000524 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) + vec[0] - vec[1];
525 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) -= vec[0] - vec[1];
526 // BR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000527 *((SkPoint*)((intptr_t)fan1Pos + 2 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000528 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) - vec[0] - vec[1];
529 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) += vec[0] + vec[1];
530 // TR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000531 *((SkPoint*)((intptr_t)fan1Pos + 3 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000532 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) - vec[0] + vec[1];
533 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) += vec[0] - vec[1];
534 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000535
536 verts += sizeof(GrPoint);
537 for (int i = 0; i < 4; ++i) {
538 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
539 }
540
robertphillips@google.com908aed82013-05-28 13:16:20 +0000541 int scale;
542 if (inset < SK_ScalarHalf) {
543 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
544 SkASSERT(scale >= 0 && scale <= 255);
545 } else {
546 scale = 0xff;
547 }
548
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000549 GrColor innerColor;
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000550 if (useVertexCoverage) {
robertphillips@google.com353f0972013-06-28 17:57:06 +0000551 innerColor = GrColorPackRGBA(scale, scale, scale, scale);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000552 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000553 if (0xff == scale) {
skia.committer@gmail.com0d55dd72013-07-02 07:00:59 +0000554 innerColor = target->getDrawState().getColor();
555 } else {
556 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
557 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000558 }
559
560 verts += 4 * vsize;
561 for (int i = 0; i < 4; ++i) {
562 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
563 }
564
565 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000566 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
567 kVertsPerAAFillRect,
568 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000569 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000570}
571
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000572namespace {
573
574// Rotated
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000575struct RectVertex {
576 GrPoint fPos;
577 GrPoint fCenter;
578 GrPoint fDir;
579 GrPoint fWidthHeight;
580};
581
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000582// Rotated
robertphillips@google.com42903302013-04-20 12:26:07 +0000583extern const GrVertexAttrib gAARectVertexAttribs[] = {
584 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
585 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
586 { kVec2f_GrVertexAttribType, 3*sizeof(GrPoint), kEffect_GrVertexAttribBinding }
587};
588
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000589// Axis Aligned
590struct AARectVertex {
591 GrPoint fPos;
592 GrPoint fOffset;
593 GrPoint fWidthHeight;
594};
595
596// Axis Aligned
597extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
598 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
599 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
600};
601
robertphillips@google.com42903302013-04-20 12:26:07 +0000602};
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000603
604void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
605 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000606 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000607 const SkMatrix& combinedMatrix) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000608 GrDrawState* drawState = target->drawState();
609
610 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
611 combinedMatrix.mapPoints(&center, 1);
612
613 // compute transformed (0, 1) vector
614 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
615 dir.normalize();
616
617 // compute transformed (width, 0) and (0, height) vectors
618 SkVector vec[2] = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000619 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
620 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000621 };
622
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000623 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
624 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
robertphillips@google.com42903302013-04-20 12:26:07 +0000625 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs));
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000626 SkASSERT(sizeof(RectVertex) == drawState->getVertexSize());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000627
628 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
629 if (!geo.succeeded()) {
630 GrPrintf("Failed to get space for vertices!\n");
631 return;
632 }
633
634 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
635
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000636 GrEffectRef* effect = GrRectEffect::Create();
637 static const int kRectAttrIndex = 1;
638 static const int kWidthIndex = 2;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000639 drawState->addCoverageEffect(effect, kRectAttrIndex, kWidthIndex)->unref();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000640
641 for (int i = 0; i < 4; ++i) {
642 verts[i].fCenter = center;
643 verts[i].fDir = dir;
644 verts[i].fWidthHeight.fX = newWidth;
645 verts[i].fWidthHeight.fY = newHeight;
646 }
647
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000648 SkRect devRect;
649 combinedMatrix.mapRect(&devRect, rect);
650
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000651 SkRect devBounds = {
652 devRect.fLeft - SK_ScalarHalf,
653 devRect.fTop - SK_ScalarHalf,
654 devRect.fRight + SK_ScalarHalf,
655 devRect.fBottom + SK_ScalarHalf
656 };
657
658 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
659 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
660 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
661 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
662
663 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
664 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
665 target->resetIndexSource();
666}
667
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000668void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu,
669 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000670 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000671 const SkMatrix& combinedMatrix) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000672 GrDrawState* drawState = target->drawState();
673 SkASSERT(combinedMatrix.rectStaysRect());
674
675 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs));
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000676 SkASSERT(sizeof(AARectVertex) == drawState->getVertexSize());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000677
678 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
679 if (!geo.succeeded()) {
680 GrPrintf("Failed to get space for vertices!\n");
681 return;
682 }
683
684 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
685
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000686 GrEffectRef* effect = GrAlignedRectEffect::Create();
687 static const int kOffsetIndex = 1;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000688 drawState->addCoverageEffect(effect, kOffsetIndex)->unref();
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000689
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000690 SkRect devRect;
691 combinedMatrix.mapRect(&devRect, rect);
692
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000693 SkRect devBounds = {
694 devRect.fLeft - SK_ScalarHalf,
695 devRect.fTop - SK_ScalarHalf,
696 devRect.fRight + SK_ScalarHalf,
697 devRect.fBottom + SK_ScalarHalf
698 };
699
700 GrPoint widthHeight = {
701 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
702 SkScalarHalf(devRect.height()) + SK_ScalarHalf
703 };
704
705 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
706 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
707 verts[0].fWidthHeight = widthHeight;
708
709 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
710 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
711 verts[1].fWidthHeight = widthHeight;
712
713 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
714 verts[2].fOffset = widthHeight;
715 verts[2].fWidthHeight = widthHeight;
716
717 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
718 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
719 verts[3].fWidthHeight = widthHeight;
720
721 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
722 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
723 target->resetIndexSource();
724}
725
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000726void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000727 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000728 const SkRect& rect,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000729 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000730 const SkRect& devRect,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000731 const SkStrokeRec* stroke,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000732 bool useVertexCoverage) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000733 GrVec devStrokeSize;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000734 SkScalar width = stroke->getWidth();
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000735 if (width > 0) {
736 devStrokeSize.set(width, width);
737 combinedMatrix.mapVectors(&devStrokeSize, 1);
738 devStrokeSize.setAbs(devStrokeSize);
739 } else {
740 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
741 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000742
robertphillips@google.com18136d12013-05-10 11:05:58 +0000743 const SkScalar dx = devStrokeSize.fX;
744 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000745 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
746 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000747
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000748 // Temporarily #if'ed out. We don't want to pass in the devRect but
749 // right now it is computed in GrContext::apply_aa_to_rect and we don't
750 // want to throw away the work
751#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000752 SkRect devRect;
753 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000754#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000755
bsalomon@google.com81712882012-11-01 17:12:34 +0000756 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000757 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000758 SkScalar w = devRect.width() - dx;
759 SkScalar h = devRect.height() - dy;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000760 spare = GrMin(w, h);
761 }
762
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000763 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000764 devOutside.outset(rx, ry);
765
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000766 bool miterStroke = true;
767 // small miter limit means right angles show bevel...
768 if (stroke->getJoin() != SkPaint::kMiter_Join || stroke->getMiter() < SK_ScalarSqrt2) {
769 miterStroke = false;
770 }
771
772 if (spare <= 0 && miterStroke) {
skia.committer@gmail.com845220b2013-05-20 11:51:35 +0000773 this->fillAARect(gpu, target, devOutside, SkMatrix::I(),
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000774 devOutside, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000775 return;
776 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000777
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000778 SkRect devInside(devRect);
779 devInside.inset(rx, ry);
780
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000781 SkRect devOutsideAssist(devRect);
782
783 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
784 // to draw the outer of the rect. Because there are 8 vertices on the outer
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000785 // edge, while vertex number of inner edge is 4, the same as miter-stroke.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000786 if (!miterStroke) {
787 devOutside.inset(0, ry);
788 devOutsideAssist.outset(0, ry);
789 }
790
791 this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist,
792 devInside, useVertexCoverage, miterStroke);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000793}
794
795void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu,
796 GrDrawTarget* target,
797 const SkRect& devOutside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000798 const SkRect& devOutsideAssist,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000799 const SkRect& devInside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000800 bool useVertexCoverage,
801 bool miterStroke) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000802 GrDrawState* drawState = target->drawState();
803
robertphillips@google.com42903302013-04-20 12:26:07 +0000804 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000805
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000806 int innerVertexNum = 4;
807 int outerVertexNum = miterStroke ? 4 : 8;
808 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
809
810 GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000811 if (!geo.succeeded()) {
812 GrPrintf("Failed to get space for vertices!\n");
813 return;
814 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000815 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu, miterStroke);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000816 if (NULL == indexBuffer) {
817 GrPrintf("Failed to create index buffer!\n");
818 return;
819 }
820
821 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000822 size_t vsize = drawState->getVertexSize();
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000823 SkASSERT(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000824
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000825 // We create vertices for four nested rectangles. There are two ramps from 0 to full
826 // coverage, one on the exterior of the stroke and the other on the interior.
827 // The following pointers refer to the four rects, from outermost to innermost.
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000828 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000829 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + outerVertexNum * vsize);
830 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 2 * outerVertexNum * vsize);
831 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000832
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000833#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
robertphillips@google.com353f0972013-06-28 17:57:06 +0000834 // TODO: this only really works if the X & Y margins are the same all around
835 // the rect
836 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
837 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
838 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000839 if (miterStroke) {
840 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
841 } else {
842 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom);
843 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000844 SkASSERT(inset >= 0);
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000845#else
846 SkScalar inset = SK_ScalarHalf;
847#endif
robertphillips@google.com353f0972013-06-28 17:57:06 +0000848
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000849 if (miterStroke) {
850 // outermost
851 set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
852 // inner two
853 set_inset_fan(fan1Pos, vsize, devOutside, inset, inset);
854 set_inset_fan(fan2Pos, vsize, devInside, -inset, -inset);
855 // innermost
856 set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf);
857 } else {
858 GrPoint* fan0AssistPos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
859 GrPoint* fan1AssistPos = reinterpret_cast<GrPoint*>(verts + (outerVertexNum + 4) * vsize);
860 // outermost
861 set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
862 set_inset_fan(fan0AssistPos, vsize, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf);
863 // outer one of the inner two
864 set_inset_fan(fan1Pos, vsize, devOutside, inset, inset);
865 set_inset_fan(fan1AssistPos, vsize, devOutsideAssist, inset, inset);
866 // inner one of the inner two
867 set_inset_fan(fan2Pos, vsize, devInside, -inset, -inset);
868 // innermost
869 set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf);
870 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000871
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000872 // The outermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000873 verts += sizeof(GrPoint);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000874 for (int i = 0; i < outerVertexNum; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000875 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
876 }
877
robertphillips@google.com353f0972013-06-28 17:57:06 +0000878 int scale;
879 if (inset < SK_ScalarHalf) {
880 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
881 SkASSERT(scale >= 0 && scale <= 255);
882 } else {
883 scale = 0xff;
884 }
885
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000886 // The inner two rects have full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000887 GrColor innerColor;
888 if (useVertexCoverage) {
robertphillips@google.com353f0972013-06-28 17:57:06 +0000889 innerColor = GrColorPackRGBA(scale, scale, scale, scale);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000890 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000891 if (0xff == scale) {
skia.committer@gmail.com0d55dd72013-07-02 07:00:59 +0000892 innerColor = target->getDrawState().getColor();
893 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000894 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
895 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000896 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000897
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000898 verts += outerVertexNum * vsize;
899 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000900 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
901 }
902
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000903 // The innermost rect has 0 coverage
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000904 verts += (outerVertexNum + innerVertexNum) * vsize;
905 for (int i = 0; i < innerVertexNum; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000906 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
907 }
908
909 target->setIndexSourceToBuffer(indexBuffer);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000910 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0,
911 totalVertexNum, aaStrokeRectIndexCount(miterStroke));
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000912}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000913
914void GrAARectRenderer::fillAANestedRects(GrGpu* gpu,
915 GrDrawTarget* target,
916 const SkRect rects[2],
917 const SkMatrix& combinedMatrix,
918 bool useVertexCoverage) {
919 SkASSERT(combinedMatrix.rectStaysRect());
920 SkASSERT(!rects[1].isEmpty());
921
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000922 SkRect devOutside, devOutsideAssist, devInside;
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000923 combinedMatrix.mapRect(&devOutside, rects[0]);
924 // can't call mapRect for devInside since it calls sort
925 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
926
927 if (devInside.isEmpty()) {
928 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside, useVertexCoverage);
929 return;
930 }
931
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000932 this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist,
933 devInside, useVertexCoverage, true);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000934}