blob: 761c63f2bf1d99d0a8245529d21182370661c12f [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"
bsalomon848faf02014-07-11 10:01:02 -070011#include "gl/GrGLShaderBuilder.h"
commit-bot@chromium.org261dc562013-10-04 15:42:56 +000012#include "gl/GrGLVertexEffect.h"
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000013#include "GrTBackendEffectFactory.h"
robertphillips@google.com908aed82013-05-28 13:16:20 +000014#include "SkColorPriv.h"
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +000015#include "effects/GrVertexEffect.h"
robertphillips@google.comf6747b02012-06-12 00:32:28 +000016
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000017///////////////////////////////////////////////////////////////////////////////
18class GrGLAlignedRectEffect;
19
20// Axis Aligned special case
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +000021class GrAlignedRectEffect : public GrVertexEffect {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000022public:
bsalomon83d081a2014-07-08 09:56:10 -070023 static GrEffect* Create() {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000024 GR_CREATE_STATIC_EFFECT(gAlignedRectEffect, GrAlignedRectEffect, ());
25 gAlignedRectEffect->ref();
26 return gAlignedRectEffect;
27 }
28
29 virtual ~GrAlignedRectEffect() {}
30
31 static const char* Name() { return "AlignedRectEdge"; }
32
33 virtual void getConstantColorComponents(GrColor* color,
34 uint32_t* validFlags) const SK_OVERRIDE {
35 *validFlags = 0;
36 }
37
38 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
39 return GrTBackendEffectFactory<GrAlignedRectEffect>::getInstance();
40 }
41
commit-bot@chromium.org261dc562013-10-04 15:42:56 +000042 class GLEffect : public GrGLVertexEffect {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000043 public:
44 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
45 : INHERITED (factory) {}
46
commit-bot@chromium.org261dc562013-10-04 15:42:56 +000047 virtual void emitCode(GrGLFullShaderBuilder* builder,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000048 const GrDrawEffect& drawEffect,
49 EffectKey key,
50 const char* outputColor,
51 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +000052 const TransformedCoordsArray&,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000053 const TextureSamplerArray& samplers) SK_OVERRIDE {
54 // setup the varying for the Axis aligned rect effect
55 // xy -> interpolated offset
56 // zw -> w/2+0.5, h/2+0.5
57 const char *vsRectName, *fsRectName;
commit-bot@chromium.org261dc562013-10-04 15:42:56 +000058 builder->addVarying(kVec4f_GrSLType, "Rect", &vsRectName, &fsRectName);
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000059 const SkString* attr0Name =
commit-bot@chromium.org261dc562013-10-04 15:42:56 +000060 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
61 builder->vsCodeAppendf("\t%s = %s;\n", vsRectName, attr0Name->c_str());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000062
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000063 // TODO: compute all these offsets, spans, and scales in the VS
64 builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.z) - 0.5;\n", fsRectName);
65 builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.w) - 0.5;\n", fsRectName);
66 builder->fsCodeAppend("\tfloat outset = 0.5;\n");
67 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
68 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
69 builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n");
70 builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n");
71 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
72 // value of coverage that is used. In other words it is the coverage that is
73 // used in the interior of the rect after the ramp.
robertphillips@google.com07a05242013-06-14 17:45:30 +000074 builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
75 builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000076
77 // Compute the coverage for the rect's width
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000078 builder->fsCodeAppendf(
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000079 "\tfloat coverage = scaleW*clamp((%s.z-abs(%s.x))/spanW, 0.0, 1.0);\n", fsRectName,
80 fsRectName);
81 // Compute the coverage for the rect's height and merge with the width
egdaniel@google.comf1d7de72013-06-14 19:25:53 +000082 builder->fsCodeAppendf(
83 "\tcoverage = coverage*scaleH*clamp((%s.w-abs(%s.y))/spanH, 0.0, 1.0);\n",
84 fsRectName, fsRectName);
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000085
commit-bot@chromium.org824c3462013-10-10 06:30:18 +000086
87 builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +000088 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("coverage")).c_str());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000089 }
90
91 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
92 return 0;
93 }
94
95 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
96
97 private:
commit-bot@chromium.org261dc562013-10-04 15:42:56 +000098 typedef GrGLVertexEffect INHERITED;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000099 };
100
101
102private:
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000103 GrAlignedRectEffect() : GrVertexEffect() {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000104 this->addVertexAttrib(kVec4f_GrSLType);
105 }
106
107 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
108
109 GR_DECLARE_EFFECT_TEST;
110
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000111 typedef GrVertexEffect INHERITED;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000112};
113
114
115GR_DEFINE_EFFECT_TEST(GrAlignedRectEffect);
116
bsalomon83d081a2014-07-08 09:56:10 -0700117GrEffect* GrAlignedRectEffect::TestCreate(SkRandom* random,
118 GrContext* context,
119 const GrDrawTargetCaps&,
120 GrTexture* textures[]) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000121 return GrAlignedRectEffect::Create();
122}
123
124///////////////////////////////////////////////////////////////////////////////
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000125class GrGLRectEffect;
126
127/**
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000128 * The output of this effect is a modulation of the input color and coverage
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000129 * for an arbitrarily oriented rect. The rect is specified as:
130 * Center of the rect
131 * Unit vector point down the height of the rect
132 * Half width + 0.5
133 * Half height + 0.5
134 * The center and vector are stored in a vec4 varying ("RectEdge") with the
135 * center in the xy components and the vector in the zw components.
136 * The munged width and height are stored in a vec2 varying ("WidthHeight")
137 * with the width in x and the height in y.
138 */
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000139class GrRectEffect : public GrVertexEffect {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000140public:
bsalomon83d081a2014-07-08 09:56:10 -0700141 static GrEffect* Create() {
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000142 GR_CREATE_STATIC_EFFECT(gRectEffect, GrRectEffect, ());
143 gRectEffect->ref();
144 return gRectEffect;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000145 }
146
147 virtual ~GrRectEffect() {}
148
149 static const char* Name() { return "RectEdge"; }
150
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000151 virtual void getConstantColorComponents(GrColor* color,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000152 uint32_t* validFlags) const SK_OVERRIDE {
153 *validFlags = 0;
154 }
155
156 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
157 return GrTBackendEffectFactory<GrRectEffect>::getInstance();
158 }
159
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000160 class GLEffect : public GrGLVertexEffect {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000161 public:
162 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
163 : INHERITED (factory) {}
164
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000165 virtual void emitCode(GrGLFullShaderBuilder* builder,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000166 const GrDrawEffect& drawEffect,
167 EffectKey key,
168 const char* outputColor,
169 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +0000170 const TransformedCoordsArray&,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000171 const TextureSamplerArray& samplers) SK_OVERRIDE {
172 // setup the varying for the center point and the unit vector
173 // that points down the height of the rect
174 const char *vsRectEdgeName, *fsRectEdgeName;
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000175 builder->addVarying(kVec4f_GrSLType, "RectEdge",
176 &vsRectEdgeName, &fsRectEdgeName);
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000177 const SkString* attr0Name =
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000178 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
179 builder->vsCodeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000180
181 // setup the varying for width/2+.5 and height/2+.5
182 const char *vsWidthHeightName, *fsWidthHeightName;
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000183 builder->addVarying(kVec2f_GrSLType, "WidthHeight",
184 &vsWidthHeightName, &fsWidthHeightName);
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000185 const SkString* attr1Name =
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000186 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
187 builder->vsCodeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000188
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000189 // TODO: compute all these offsets, spans, and scales in the VS
190 builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.x) - 0.5;\n", fsWidthHeightName);
191 builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.y) - 0.5;\n", fsWidthHeightName);
192 builder->fsCodeAppend("\tfloat outset = 0.5;\n");
193 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
194 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
195 builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n");
196 builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n");
197 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
198 // value of coverage that is used. In other words it is the coverage that is
199 // used in the interior of the rect after the ramp.
200 builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
201 builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000202
203 // Compute the coverage for the rect's width
bsalomon22900002014-06-24 11:16:52 -0700204 builder->fsCodeAppendf("\tvec2 offset = %s.xy - %s.xy;\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000205 builder->fragmentPosition(), fsRectEdgeName);
206 builder->fsCodeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
207 fsRectEdgeName, fsRectEdgeName);
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000208 builder->fsCodeAppendf(
209 "\tfloat coverage = scaleW*clamp((%s.x-perpDot)/spanW, 0.0, 1.0);\n",
210 fsWidthHeightName);
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000211
212 // Compute the coverage for the rect's height and merge with the width
213 builder->fsCodeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
214 fsRectEdgeName);
215 builder->fsCodeAppendf(
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000216 "\tcoverage = coverage*scaleH*clamp((%s.y-perpDot)/spanH, 0.0, 1.0);\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000217 fsWidthHeightName);
218
commit-bot@chromium.org824c3462013-10-10 06:30:18 +0000219
220 builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000221 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("coverage")).c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000222 }
223
224 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
225 return 0;
226 }
227
228 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
229
230 private:
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000231 typedef GrGLVertexEffect INHERITED;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000232 };
233
234
235private:
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000236 GrRectEffect() : GrVertexEffect() {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000237 this->addVertexAttrib(kVec4f_GrSLType);
238 this->addVertexAttrib(kVec2f_GrSLType);
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000239 this->setWillReadFragmentPosition();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000240 }
241
242 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
243
244 GR_DECLARE_EFFECT_TEST;
245
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000246 typedef GrVertexEffect INHERITED;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000247};
248
249
250GR_DEFINE_EFFECT_TEST(GrRectEffect);
251
bsalomon83d081a2014-07-08 09:56:10 -0700252GrEffect* GrRectEffect::TestCreate(SkRandom* random,
253 GrContext* context,
254 const GrDrawTargetCaps&,
255 GrTexture* textures[]) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000256 return GrRectEffect::Create();
257}
258
259///////////////////////////////////////////////////////////////////////////////
260
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000261namespace {
262
robertphillips@google.com42903302013-04-20 12:26:07 +0000263extern const GrVertexAttrib gAARectCoverageAttribs[] = {
264 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000265 {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kCoverage_GrVertexAttribBinding},
robertphillips@google.com42903302013-04-20 12:26:07 +0000266};
267
268extern const GrVertexAttrib gAARectColorAttribs[] = {
269 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000270 {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding},
robertphillips@google.com42903302013-04-20 12:26:07 +0000271};
272
273static void set_aa_rect_vertex_attributes(GrDrawState* drawState, bool useCoverage) {
274 if (useCoverage) {
275 drawState->setVertexAttribs<gAARectCoverageAttribs>(SK_ARRAY_COUNT(gAARectCoverageAttribs));
276 } else {
277 drawState->setVertexAttribs<gAARectColorAttribs>(SK_ARRAY_COUNT(gAARectColorAttribs));
278 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000279}
280
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000281static void set_inset_fan(SkPoint* pts, size_t stride,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000282 const SkRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000283 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
284 r.fRight - dx, r.fBottom - dy, stride);
285}
286
287};
288
289void GrAARectRenderer::reset() {
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000290 SkSafeSetNull(fAAFillRectIndexBuffer);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000291 SkSafeSetNull(fAAMiterStrokeRectIndexBuffer);
292 SkSafeSetNull(fAABevelStrokeRectIndexBuffer);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000293}
294
robertphillips@google.com6d067302012-12-18 21:47:47 +0000295static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000296 0, 1, 5, 5, 4, 0,
297 1, 2, 6, 6, 5, 1,
298 2, 3, 7, 7, 6, 2,
299 3, 0, 4, 4, 7, 3,
300 4, 5, 6, 6, 7, 4,
301};
302
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000303static const int kIndicesPerAAFillRect = SK_ARRAY_COUNT(gFillAARectIdx);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000304static const int kVertsPerAAFillRect = 8;
305static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000306
307GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000308 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
309 sizeof(uint16_t) *
310 kNumAAFillRectsInIndexBuffer;
311
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000312 if (NULL == fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000313 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000314 if (NULL != fAAFillRectIndexBuffer) {
commit-bot@chromium.org8341eb72014-05-07 20:51:05 +0000315 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->map();
robertphillips@google.com6d067302012-12-18 21:47:47 +0000316 bool useTempData = (NULL == data);
317 if (useTempData) {
318 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
319 }
320 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
321 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
322 // the inner rect (for AA) and 2 for the inner rect.
323 int baseIdx = i * kIndicesPerAAFillRect;
324 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
325 for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
326 data[baseIdx+j] = baseVert + gFillAARectIdx[j];
327 }
328 }
329 if (useTempData) {
330 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +0000331 SkFAIL("Can't get AA Fill Rect indices into buffer!");
robertphillips@google.com6d067302012-12-18 21:47:47 +0000332 }
333 SkDELETE_ARRAY(data);
334 } else {
commit-bot@chromium.org8341eb72014-05-07 20:51:05 +0000335 fAAFillRectIndexBuffer->unmap();
robertphillips@google.com6d067302012-12-18 21:47:47 +0000336 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000337 }
338 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000339
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000340 return fAAFillRectIndexBuffer;
341}
342
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000343static const uint16_t gMiterStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000344 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
345 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
346 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
347 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
348
349 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
350 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
351 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
352 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
353
354 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
355 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
356 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
357 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
358};
359
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000360/**
361 * As in miter-stroke, index = a + b, and a is the current index, b is the shift
362 * from the first index. The index layout:
363 * outer AA line: 0~3, 4~7
364 * outer edge: 8~11, 12~15
365 * inner edge: 16~19
366 * inner AA line: 20~23
367 * Following comes a bevel-stroke rect and its indices:
368 *
369 * 4 7
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000370 * *********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000371 * * ______________________________ *
372 * * / 12 15 \ *
373 * * / \ *
374 * 0 * |8 16_____________________19 11 | * 3
375 * * | | | | *
376 * * | | **************** | | *
377 * * | | * 20 23 * | | *
378 * * | | * * | | *
379 * * | | * 21 22 * | | *
380 * * | | **************** | | *
381 * * | |____________________| | *
382 * 1 * |9 17 18 10| * 2
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000383 * * \ / *
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000384 * * \13 __________________________14/ *
385 * * *
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000386 * **********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000387 * 5 6
388 */
389static const uint16_t gBevelStrokeAARectIdx[] = {
390 // Draw outer AA, from outer AA line to outer edge, shift is 0.
391 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
392 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
393 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
394 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
395 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
396 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
397 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
398 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
399
400 // Draw the stroke, from outer edge to inner edge, shift is 8.
401 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
402 1 + 8, 5 + 8, 9 + 8,
403 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
404 6 + 8, 2 + 8, 10 + 8,
405 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
406 3 + 8, 7 + 8, 11 + 8,
407 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
408 4 + 8, 0 + 8, 8 + 8,
409
410 // Draw the inner AA, from inner edge to inner AA line, shift is 16.
411 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
412 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
413 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
414 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
415};
416
417int GrAARectRenderer::aaStrokeRectIndexCount(bool miterStroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000418 return miterStroke ? SK_ARRAY_COUNT(gMiterStrokeAARectIdx) :
419 SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000420}
421
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000422GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu, bool miterStroke) {
423 if (miterStroke) {
424 if (NULL == fAAMiterStrokeRectIndexBuffer) {
425 fAAMiterStrokeRectIndexBuffer =
426 gpu->createIndexBuffer(sizeof(gMiterStrokeAARectIdx), false);
427 if (NULL != fAAMiterStrokeRectIndexBuffer) {
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000428#ifdef SK_DEBUG
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000429 bool updated =
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000430#endif
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000431 fAAMiterStrokeRectIndexBuffer->updateData(gMiterStrokeAARectIdx,
432 sizeof(gMiterStrokeAARectIdx));
433 GR_DEBUGASSERT(updated);
434 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000435 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000436 return fAAMiterStrokeRectIndexBuffer;
437 } else {
438 if (NULL == fAABevelStrokeRectIndexBuffer) {
439 fAABevelStrokeRectIndexBuffer =
440 gpu->createIndexBuffer(sizeof(gBevelStrokeAARectIdx), false);
441 if (NULL != fAABevelStrokeRectIndexBuffer) {
442#ifdef SK_DEBUG
443 bool updated =
444#endif
445 fAABevelStrokeRectIndexBuffer->updateData(gBevelStrokeAARectIdx,
446 sizeof(gBevelStrokeAARectIdx));
447 GR_DEBUGASSERT(updated);
448 }
449 }
450 return fAABevelStrokeRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000451 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000452}
453
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000454void GrAARectRenderer::geometryFillAARect(GrGpu* gpu,
455 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000456 const SkRect& rect,
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000457 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000458 const SkRect& devRect,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000459 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000460 GrDrawState* drawState = target->drawState();
461
robertphillips@google.com42903302013-04-20 12:26:07 +0000462 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000463
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000464 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000465 if (!geo.succeeded()) {
466 GrPrintf("Failed to get space for vertices!\n");
467 return;
468 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000469
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000470 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
471 if (NULL == indexBuffer) {
472 GrPrintf("Failed to create index buffer!\n");
473 return;
474 }
475
476 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000477 size_t vsize = drawState->getVertexSize();
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000478 SkASSERT(sizeof(SkPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000479
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000480 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
481 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000482
robertphillips@google.com908aed82013-05-28 13:16:20 +0000483 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
484 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
485
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000486 if (combinedMatrix.rectStaysRect()) {
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000487 // Temporarily #if'ed out. We don't want to pass in the devRect but
488 // right now it is computed in GrContext::apply_aa_to_rect and we don't
489 // want to throw away the work
490#if 0
robertphillips@google.com91b71162013-05-10 14:09:54 +0000491 SkRect devRect;
492 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000493#endif
robertphillips@google.com91b71162013-05-10 14:09:54 +0000494
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000495 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
robertphillips@google.com908aed82013-05-28 13:16:20 +0000496 set_inset_fan(fan1Pos, vsize, devRect, inset, inset);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000497 } else {
498 // compute transformed (1, 0) and (0, 1) vectors
499 SkVector vec[2] = {
500 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
501 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
502 };
503
504 vec[0].normalize();
505 vec[0].scale(SK_ScalarHalf);
506 vec[1].normalize();
507 vec[1].scale(SK_ScalarHalf);
508
robertphillips@google.com91b71162013-05-10 14:09:54 +0000509 // create the rotated rect
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000510 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
511 rect.fRight, rect.fBottom, vsize);
512 combinedMatrix.mapPointsWithStride(fan0Pos, vsize, 4);
513
robertphillips@google.com91b71162013-05-10 14:09:54 +0000514 // Now create the inset points and then outset the original
515 // rotated points
516
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000517 // TL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000518 *((SkPoint*)((intptr_t)fan1Pos + 0 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000519 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) + vec[0] + vec[1];
520 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) -= vec[0] + vec[1];
521 // BL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000522 *((SkPoint*)((intptr_t)fan1Pos + 1 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000523 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) + vec[0] - vec[1];
524 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) -= vec[0] - vec[1];
525 // BR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000526 *((SkPoint*)((intptr_t)fan1Pos + 2 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000527 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) - vec[0] - vec[1];
528 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) += vec[0] + vec[1];
529 // TR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000530 *((SkPoint*)((intptr_t)fan1Pos + 3 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000531 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) - vec[0] + vec[1];
532 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) += vec[0] - vec[1];
533 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000534
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000535 verts += sizeof(SkPoint);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000536 for (int i = 0; i < 4; ++i) {
537 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
538 }
539
robertphillips@google.com908aed82013-05-28 13:16:20 +0000540 int scale;
541 if (inset < SK_ScalarHalf) {
542 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
543 SkASSERT(scale >= 0 && scale <= 255);
544 } else {
545 scale = 0xff;
546 }
547
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000548 GrColor innerColor;
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000549 if (useVertexCoverage) {
robertphillips@google.com353f0972013-06-28 17:57:06 +0000550 innerColor = GrColorPackRGBA(scale, scale, scale, scale);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000551 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000552 if (0xff == scale) {
skia.committer@gmail.com0d55dd72013-07-02 07:00:59 +0000553 innerColor = target->getDrawState().getColor();
554 } else {
555 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
556 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000557 }
558
559 verts += 4 * vsize;
560 for (int i = 0; i < 4; ++i) {
561 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
562 }
563
564 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000565 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
566 kVertsPerAAFillRect,
567 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000568 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000569}
570
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000571namespace {
572
573// Rotated
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000574struct RectVertex {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000575 SkPoint fPos;
576 SkPoint fCenter;
577 SkPoint fDir;
578 SkPoint fWidthHeight;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000579};
580
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000581// Rotated
robertphillips@google.com42903302013-04-20 12:26:07 +0000582extern const GrVertexAttrib gAARectVertexAttribs[] = {
583 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000584 { kVec4f_GrVertexAttribType, sizeof(SkPoint), kEffect_GrVertexAttribBinding },
585 { kVec2f_GrVertexAttribType, 3*sizeof(SkPoint), kEffect_GrVertexAttribBinding }
robertphillips@google.com42903302013-04-20 12:26:07 +0000586};
587
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000588// Axis Aligned
589struct AARectVertex {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000590 SkPoint fPos;
591 SkPoint fOffset;
592 SkPoint fWidthHeight;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000593};
594
595// Axis Aligned
596extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
597 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000598 { kVec4f_GrVertexAttribType, sizeof(SkPoint), kEffect_GrVertexAttribBinding },
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000599};
600
robertphillips@google.com42903302013-04-20 12:26:07 +0000601};
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000602
603void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
604 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000605 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000606 const SkMatrix& combinedMatrix) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000607 GrDrawState* drawState = target->drawState();
608
609 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
610 combinedMatrix.mapPoints(&center, 1);
611
612 // compute transformed (0, 1) vector
613 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
614 dir.normalize();
615
616 // compute transformed (width, 0) and (0, height) vectors
617 SkVector vec[2] = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000618 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
619 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000620 };
621
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000622 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
623 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
robertphillips@google.com42903302013-04-20 12:26:07 +0000624 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs));
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000625 SkASSERT(sizeof(RectVertex) == drawState->getVertexSize());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000626
627 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
628 if (!geo.succeeded()) {
629 GrPrintf("Failed to get space for vertices!\n");
630 return;
631 }
632
633 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
634
bsalomon83d081a2014-07-08 09:56:10 -0700635 GrEffect* effect = GrRectEffect::Create();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000636 static const int kRectAttrIndex = 1;
637 static const int kWidthIndex = 2;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000638 drawState->addCoverageEffect(effect, kRectAttrIndex, kWidthIndex)->unref();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000639
640 for (int i = 0; i < 4; ++i) {
641 verts[i].fCenter = center;
642 verts[i].fDir = dir;
643 verts[i].fWidthHeight.fX = newWidth;
644 verts[i].fWidthHeight.fY = newHeight;
645 }
646
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000647 SkRect devRect;
648 combinedMatrix.mapRect(&devRect, rect);
649
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000650 SkRect devBounds = {
651 devRect.fLeft - SK_ScalarHalf,
652 devRect.fTop - SK_ScalarHalf,
653 devRect.fRight + SK_ScalarHalf,
654 devRect.fBottom + SK_ScalarHalf
655 };
656
657 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
658 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
659 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
660 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
661
662 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
663 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
664 target->resetIndexSource();
665}
666
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000667void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu,
668 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000669 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000670 const SkMatrix& combinedMatrix) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000671 GrDrawState* drawState = target->drawState();
672 SkASSERT(combinedMatrix.rectStaysRect());
673
674 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs));
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000675 SkASSERT(sizeof(AARectVertex) == drawState->getVertexSize());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000676
677 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
678 if (!geo.succeeded()) {
679 GrPrintf("Failed to get space for vertices!\n");
680 return;
681 }
682
683 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
684
bsalomon83d081a2014-07-08 09:56:10 -0700685 GrEffect* effect = GrAlignedRectEffect::Create();
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000686 static const int kOffsetIndex = 1;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000687 drawState->addCoverageEffect(effect, kOffsetIndex)->unref();
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000688
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000689 SkRect devRect;
690 combinedMatrix.mapRect(&devRect, rect);
691
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000692 SkRect devBounds = {
693 devRect.fLeft - SK_ScalarHalf,
694 devRect.fTop - SK_ScalarHalf,
695 devRect.fRight + SK_ScalarHalf,
696 devRect.fBottom + SK_ScalarHalf
697 };
698
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000699 SkPoint widthHeight = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000700 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
701 SkScalarHalf(devRect.height()) + SK_ScalarHalf
702 };
703
704 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
705 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
706 verts[0].fWidthHeight = widthHeight;
707
708 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
709 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
710 verts[1].fWidthHeight = widthHeight;
711
712 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
713 verts[2].fOffset = widthHeight;
714 verts[2].fWidthHeight = widthHeight;
715
716 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
717 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
718 verts[3].fWidthHeight = widthHeight;
719
720 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
721 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
722 target->resetIndexSource();
723}
724
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000725void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000726 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000727 const SkRect& rect,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000728 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000729 const SkRect& devRect,
egdanield58a0ba2014-06-11 10:30:05 -0700730 const SkStrokeRec& stroke,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000731 bool useVertexCoverage) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000732 SkVector devStrokeSize;
egdanield58a0ba2014-06-11 10:30:05 -0700733 SkScalar width = stroke.getWidth();
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000734 if (width > 0) {
735 devStrokeSize.set(width, width);
736 combinedMatrix.mapVectors(&devStrokeSize, 1);
737 devStrokeSize.setAbs(devStrokeSize);
738 } else {
739 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
740 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000741
robertphillips@google.com18136d12013-05-10 11:05:58 +0000742 const SkScalar dx = devStrokeSize.fX;
743 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000744 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
745 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000746
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000747 // Temporarily #if'ed out. We don't want to pass in the devRect but
748 // right now it is computed in GrContext::apply_aa_to_rect and we don't
749 // want to throw away the work
750#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000751 SkRect devRect;
752 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000753#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000754
bsalomon@google.com81712882012-11-01 17:12:34 +0000755 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000756 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000757 SkScalar w = devRect.width() - dx;
758 SkScalar h = devRect.height() - dy;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000759 spare = SkTMin(w, h);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000760 }
761
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000762 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000763 devOutside.outset(rx, ry);
764
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000765 bool miterStroke = true;
766 // small miter limit means right angles show bevel...
egdanield58a0ba2014-06-11 10:30:05 -0700767 if (stroke.getJoin() != SkPaint::kMiter_Join || stroke.getMiter() < SK_ScalarSqrt2) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000768 miterStroke = false;
769 }
770
771 if (spare <= 0 && miterStroke) {
skia.committer@gmail.com845220b2013-05-20 11:51:35 +0000772 this->fillAARect(gpu, target, devOutside, SkMatrix::I(),
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000773 devOutside, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000774 return;
775 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000776
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000777 SkRect devInside(devRect);
778 devInside.inset(rx, ry);
779
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000780 SkRect devOutsideAssist(devRect);
781
782 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
783 // to draw the outer of the rect. Because there are 8 vertices on the outer
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000784 // edge, while vertex number of inner edge is 4, the same as miter-stroke.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000785 if (!miterStroke) {
786 devOutside.inset(0, ry);
787 devOutsideAssist.outset(0, ry);
788 }
789
790 this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist,
791 devInside, useVertexCoverage, miterStroke);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000792}
793
794void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu,
795 GrDrawTarget* target,
796 const SkRect& devOutside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000797 const SkRect& devOutsideAssist,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000798 const SkRect& devInside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000799 bool useVertexCoverage,
800 bool miterStroke) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000801 GrDrawState* drawState = target->drawState();
802
robertphillips@google.com42903302013-04-20 12:26:07 +0000803 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000804
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000805 int innerVertexNum = 4;
806 int outerVertexNum = miterStroke ? 4 : 8;
807 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
808
809 GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000810 if (!geo.succeeded()) {
811 GrPrintf("Failed to get space for vertices!\n");
812 return;
813 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000814 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu, miterStroke);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000815 if (NULL == indexBuffer) {
816 GrPrintf("Failed to create index buffer!\n");
817 return;
818 }
819
820 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000821 size_t vsize = drawState->getVertexSize();
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000822 SkASSERT(sizeof(SkPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000823
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000824 // We create vertices for four nested rectangles. There are two ramps from 0 to full
825 // coverage, one on the exterior of the stroke and the other on the interior.
826 // The following pointers refer to the four rects, from outermost to innermost.
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000827 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
828 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vsize);
829 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vsize);
830 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000831
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000832#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
robertphillips@google.com353f0972013-06-28 17:57:06 +0000833 // TODO: this only really works if the X & Y margins are the same all around
834 // the rect
835 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
836 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
837 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000838 if (miterStroke) {
839 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
840 } else {
841 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom);
842 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000843 SkASSERT(inset >= 0);
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000844#else
845 SkScalar inset = SK_ScalarHalf;
846#endif
robertphillips@google.com353f0972013-06-28 17:57:06 +0000847
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000848 if (miterStroke) {
849 // outermost
850 set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
851 // inner two
852 set_inset_fan(fan1Pos, vsize, devOutside, inset, inset);
853 set_inset_fan(fan2Pos, vsize, devInside, -inset, -inset);
854 // innermost
855 set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf);
856 } else {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000857 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vsize);
858 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + (outerVertexNum + 4) * vsize);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000859 // outermost
860 set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
861 set_inset_fan(fan0AssistPos, vsize, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf);
862 // outer one of the inner two
863 set_inset_fan(fan1Pos, vsize, devOutside, inset, inset);
864 set_inset_fan(fan1AssistPos, vsize, devOutsideAssist, inset, inset);
865 // inner one of the inner two
866 set_inset_fan(fan2Pos, vsize, devInside, -inset, -inset);
867 // innermost
868 set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf);
869 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000870
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000871 // The outermost rect has 0 coverage
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000872 verts += sizeof(SkPoint);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000873 for (int i = 0; i < outerVertexNum; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000874 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
875 }
876
robertphillips@google.com353f0972013-06-28 17:57:06 +0000877 int scale;
878 if (inset < SK_ScalarHalf) {
879 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
880 SkASSERT(scale >= 0 && scale <= 255);
881 } else {
882 scale = 0xff;
883 }
884
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000885 // The inner two rects have full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000886 GrColor innerColor;
887 if (useVertexCoverage) {
robertphillips@google.com353f0972013-06-28 17:57:06 +0000888 innerColor = GrColorPackRGBA(scale, scale, scale, scale);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000889 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000890 if (0xff == scale) {
skia.committer@gmail.com0d55dd72013-07-02 07:00:59 +0000891 innerColor = target->getDrawState().getColor();
892 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000893 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
894 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000895 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000896
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000897 verts += outerVertexNum * vsize;
898 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000899 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
900 }
901
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000902 // The innermost rect has 0 coverage
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000903 verts += (outerVertexNum + innerVertexNum) * vsize;
904 for (int i = 0; i < innerVertexNum; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000905 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
906 }
907
908 target->setIndexSourceToBuffer(indexBuffer);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000909 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0,
910 totalVertexNum, aaStrokeRectIndexCount(miterStroke));
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000911}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000912
913void GrAARectRenderer::fillAANestedRects(GrGpu* gpu,
914 GrDrawTarget* target,
915 const SkRect rects[2],
916 const SkMatrix& combinedMatrix,
917 bool useVertexCoverage) {
918 SkASSERT(combinedMatrix.rectStaysRect());
919 SkASSERT(!rects[1].isEmpty());
920
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000921 SkRect devOutside, devOutsideAssist, devInside;
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000922 combinedMatrix.mapRect(&devOutside, rects[0]);
923 // can't call mapRect for devInside since it calls sort
924 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
925
926 if (devInside.isEmpty()) {
927 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside, useVertexCoverage);
928 return;
929 }
930
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000931 this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist,
932 devInside, useVertexCoverage, true);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000933}