blob: 1d350c335bf721cd444a58931ab5886de49de2d0 [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,
bsalomon63e99f72014-07-21 08:03:14 -070049 const GrEffectKey& key,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000050 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
bsalomon63e99f72014-07-21 08:03:14 -070091 static void GenKey(const GrDrawEffect&, const GrGLCaps&, GrEffectKeyBuilder*) {}
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000092
kkinnunen7510b222014-07-30 00:04:16 -070093 virtual void setData(const GrGLProgramDataManager& pdman, const GrDrawEffect&) SK_OVERRIDE {}
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000094
95 private:
commit-bot@chromium.org261dc562013-10-04 15:42:56 +000096 typedef GrGLVertexEffect INHERITED;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000097 };
98
99
100private:
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000101 GrAlignedRectEffect() : GrVertexEffect() {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000102 this->addVertexAttrib(kVec4f_GrSLType);
103 }
104
105 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
106
107 GR_DECLARE_EFFECT_TEST;
108
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000109 typedef GrVertexEffect INHERITED;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000110};
111
112
113GR_DEFINE_EFFECT_TEST(GrAlignedRectEffect);
114
bsalomon83d081a2014-07-08 09:56:10 -0700115GrEffect* GrAlignedRectEffect::TestCreate(SkRandom* random,
116 GrContext* context,
117 const GrDrawTargetCaps&,
118 GrTexture* textures[]) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000119 return GrAlignedRectEffect::Create();
120}
121
122///////////////////////////////////////////////////////////////////////////////
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000123class GrGLRectEffect;
124
125/**
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000126 * The output of this effect is a modulation of the input color and coverage
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000127 * for an arbitrarily oriented rect. The rect is specified as:
128 * Center of the rect
129 * Unit vector point down the height of the rect
130 * Half width + 0.5
131 * Half height + 0.5
132 * The center and vector are stored in a vec4 varying ("RectEdge") with the
133 * center in the xy components and the vector in the zw components.
134 * The munged width and height are stored in a vec2 varying ("WidthHeight")
135 * with the width in x and the height in y.
136 */
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000137class GrRectEffect : public GrVertexEffect {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000138public:
bsalomon83d081a2014-07-08 09:56:10 -0700139 static GrEffect* Create() {
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000140 GR_CREATE_STATIC_EFFECT(gRectEffect, GrRectEffect, ());
141 gRectEffect->ref();
142 return gRectEffect;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000143 }
144
145 virtual ~GrRectEffect() {}
146
147 static const char* Name() { return "RectEdge"; }
148
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000149 virtual void getConstantColorComponents(GrColor* color,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000150 uint32_t* validFlags) const SK_OVERRIDE {
151 *validFlags = 0;
152 }
153
154 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
155 return GrTBackendEffectFactory<GrRectEffect>::getInstance();
156 }
157
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000158 class GLEffect : public GrGLVertexEffect {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000159 public:
160 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
161 : INHERITED (factory) {}
162
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000163 virtual void emitCode(GrGLFullShaderBuilder* builder,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000164 const GrDrawEffect& drawEffect,
bsalomon63e99f72014-07-21 08:03:14 -0700165 const GrEffectKey& key,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000166 const char* outputColor,
167 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +0000168 const TransformedCoordsArray&,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000169 const TextureSamplerArray& samplers) SK_OVERRIDE {
170 // setup the varying for the center point and the unit vector
171 // that points down the height of the rect
172 const char *vsRectEdgeName, *fsRectEdgeName;
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000173 builder->addVarying(kVec4f_GrSLType, "RectEdge",
174 &vsRectEdgeName, &fsRectEdgeName);
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000175 const SkString* attr0Name =
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000176 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
177 builder->vsCodeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000178
179 // setup the varying for width/2+.5 and height/2+.5
180 const char *vsWidthHeightName, *fsWidthHeightName;
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000181 builder->addVarying(kVec2f_GrSLType, "WidthHeight",
182 &vsWidthHeightName, &fsWidthHeightName);
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000183 const SkString* attr1Name =
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000184 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
185 builder->vsCodeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000186
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000187 // TODO: compute all these offsets, spans, and scales in the VS
188 builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.x) - 0.5;\n", fsWidthHeightName);
189 builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.y) - 0.5;\n", fsWidthHeightName);
190 builder->fsCodeAppend("\tfloat outset = 0.5;\n");
191 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
192 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
193 builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n");
194 builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n");
195 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
196 // value of coverage that is used. In other words it is the coverage that is
197 // used in the interior of the rect after the ramp.
198 builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
199 builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000200
201 // Compute the coverage for the rect's width
bsalomon22900002014-06-24 11:16:52 -0700202 builder->fsCodeAppendf("\tvec2 offset = %s.xy - %s.xy;\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000203 builder->fragmentPosition(), fsRectEdgeName);
204 builder->fsCodeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
205 fsRectEdgeName, fsRectEdgeName);
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000206 builder->fsCodeAppendf(
207 "\tfloat coverage = scaleW*clamp((%s.x-perpDot)/spanW, 0.0, 1.0);\n",
208 fsWidthHeightName);
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000209
210 // Compute the coverage for the rect's height and merge with the width
211 builder->fsCodeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
212 fsRectEdgeName);
213 builder->fsCodeAppendf(
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000214 "\tcoverage = coverage*scaleH*clamp((%s.y-perpDot)/spanH, 0.0, 1.0);\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000215 fsWidthHeightName);
216
commit-bot@chromium.org824c3462013-10-10 06:30:18 +0000217
218 builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000219 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("coverage")).c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000220 }
221
bsalomon63e99f72014-07-21 08:03:14 -0700222 static void GenKey(const GrDrawEffect&, const GrGLCaps&, GrEffectKeyBuilder*) {}
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000223
kkinnunen7510b222014-07-30 00:04:16 -0700224 virtual void setData(const GrGLProgramDataManager& pdman, const GrDrawEffect&) SK_OVERRIDE {}
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000225
226 private:
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000227 typedef GrGLVertexEffect INHERITED;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000228 };
229
230
231private:
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000232 GrRectEffect() : GrVertexEffect() {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000233 this->addVertexAttrib(kVec4f_GrSLType);
234 this->addVertexAttrib(kVec2f_GrSLType);
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000235 this->setWillReadFragmentPosition();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000236 }
237
238 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
239
240 GR_DECLARE_EFFECT_TEST;
241
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000242 typedef GrVertexEffect INHERITED;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000243};
244
245
246GR_DEFINE_EFFECT_TEST(GrRectEffect);
247
bsalomon83d081a2014-07-08 09:56:10 -0700248GrEffect* GrRectEffect::TestCreate(SkRandom* random,
249 GrContext* context,
250 const GrDrawTargetCaps&,
251 GrTexture* textures[]) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000252 return GrRectEffect::Create();
253}
254
255///////////////////////////////////////////////////////////////////////////////
256
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000257namespace {
bsalomon9c0822a2014-08-11 11:07:48 -0700258extern const GrVertexAttrib gAARectAttribs[] = {
259 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
260 {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding},
261 {kVec4ub_GrVertexAttribType, sizeof(SkPoint) + sizeof(SkColor), kCoverage_GrVertexAttribBinding},
robertphillips@google.com42903302013-04-20 12:26:07 +0000262};
263
bsalomonc30aaa02014-08-13 07:15:29 -0700264// Should the coverage be multiplied into the color attrib or use a separate attrib.
265enum CoverageAttribType {
266 kUseColor_CoverageAttribType,
267 kUseCoverage_CoverageAttribType,
268};
269}
270
271static CoverageAttribType set_rect_attribs(GrDrawState* drawState) {
272 if (drawState->canTweakAlphaForCoverage()) {
273 drawState->setVertexAttribs<gAARectAttribs>(2);
274 return kUseColor_CoverageAttribType;
275 } else {
276 drawState->setVertexAttribs<gAARectAttribs>(3);
277 return kUseCoverage_CoverageAttribType;
278 }
279}
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
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000287void GrAARectRenderer::reset() {
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000288 SkSafeSetNull(fAAFillRectIndexBuffer);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000289 SkSafeSetNull(fAAMiterStrokeRectIndexBuffer);
290 SkSafeSetNull(fAABevelStrokeRectIndexBuffer);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000291}
292
robertphillips@google.com6d067302012-12-18 21:47:47 +0000293static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000294 0, 1, 5, 5, 4, 0,
295 1, 2, 6, 6, 5, 1,
296 2, 3, 7, 7, 6, 2,
297 3, 0, 4, 4, 7, 3,
298 4, 5, 6, 6, 7, 4,
299};
300
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000301static const int kIndicesPerAAFillRect = SK_ARRAY_COUNT(gFillAARectIdx);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000302static const int kVertsPerAAFillRect = 8;
303static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000304
305GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000306 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
307 sizeof(uint16_t) *
308 kNumAAFillRectsInIndexBuffer;
309
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000310 if (NULL == fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000311 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000312 if (NULL != fAAFillRectIndexBuffer) {
commit-bot@chromium.org8341eb72014-05-07 20:51:05 +0000313 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->map();
robertphillips@google.com6d067302012-12-18 21:47:47 +0000314 bool useTempData = (NULL == data);
315 if (useTempData) {
316 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
317 }
318 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
319 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
320 // the inner rect (for AA) and 2 for the inner rect.
321 int baseIdx = i * kIndicesPerAAFillRect;
322 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
323 for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
324 data[baseIdx+j] = baseVert + gFillAARectIdx[j];
325 }
326 }
327 if (useTempData) {
328 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +0000329 SkFAIL("Can't get AA Fill Rect indices into buffer!");
robertphillips@google.com6d067302012-12-18 21:47:47 +0000330 }
331 SkDELETE_ARRAY(data);
332 } else {
commit-bot@chromium.org8341eb72014-05-07 20:51:05 +0000333 fAAFillRectIndexBuffer->unmap();
robertphillips@google.com6d067302012-12-18 21:47:47 +0000334 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000335 }
336 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000337
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000338 return fAAFillRectIndexBuffer;
339}
340
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000341static const uint16_t gMiterStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000342 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
343 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
344 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
345 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
346
347 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
348 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
349 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
350 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
351
352 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
353 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
354 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
355 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
356};
357
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000358/**
359 * As in miter-stroke, index = a + b, and a is the current index, b is the shift
360 * from the first index. The index layout:
361 * outer AA line: 0~3, 4~7
362 * outer edge: 8~11, 12~15
363 * inner edge: 16~19
364 * inner AA line: 20~23
365 * Following comes a bevel-stroke rect and its indices:
366 *
367 * 4 7
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000368 * *********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000369 * * ______________________________ *
370 * * / 12 15 \ *
371 * * / \ *
372 * 0 * |8 16_____________________19 11 | * 3
373 * * | | | | *
374 * * | | **************** | | *
375 * * | | * 20 23 * | | *
376 * * | | * * | | *
377 * * | | * 21 22 * | | *
378 * * | | **************** | | *
379 * * | |____________________| | *
380 * 1 * |9 17 18 10| * 2
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000381 * * \ / *
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000382 * * \13 __________________________14/ *
383 * * *
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000384 * **********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000385 * 5 6
386 */
387static const uint16_t gBevelStrokeAARectIdx[] = {
388 // Draw outer AA, from outer AA line to outer edge, shift is 0.
389 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
390 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
391 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
392 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
393 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
394 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
395 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
396 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
397
398 // Draw the stroke, from outer edge to inner edge, shift is 8.
399 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
400 1 + 8, 5 + 8, 9 + 8,
401 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
402 6 + 8, 2 + 8, 10 + 8,
403 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
404 3 + 8, 7 + 8, 11 + 8,
405 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
406 4 + 8, 0 + 8, 8 + 8,
407
408 // Draw the inner AA, from inner edge to inner AA line, shift is 16.
409 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
410 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
411 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
412 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
413};
414
415int GrAARectRenderer::aaStrokeRectIndexCount(bool miterStroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000416 return miterStroke ? SK_ARRAY_COUNT(gMiterStrokeAARectIdx) :
417 SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000418}
419
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000420GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu, bool miterStroke) {
421 if (miterStroke) {
422 if (NULL == fAAMiterStrokeRectIndexBuffer) {
423 fAAMiterStrokeRectIndexBuffer =
424 gpu->createIndexBuffer(sizeof(gMiterStrokeAARectIdx), false);
425 if (NULL != fAAMiterStrokeRectIndexBuffer) {
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000426#ifdef SK_DEBUG
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000427 bool updated =
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000428#endif
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000429 fAAMiterStrokeRectIndexBuffer->updateData(gMiterStrokeAARectIdx,
430 sizeof(gMiterStrokeAARectIdx));
431 GR_DEBUGASSERT(updated);
432 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000433 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000434 return fAAMiterStrokeRectIndexBuffer;
435 } else {
436 if (NULL == fAABevelStrokeRectIndexBuffer) {
437 fAABevelStrokeRectIndexBuffer =
438 gpu->createIndexBuffer(sizeof(gBevelStrokeAARectIdx), false);
439 if (NULL != fAABevelStrokeRectIndexBuffer) {
440#ifdef SK_DEBUG
441 bool updated =
442#endif
443 fAABevelStrokeRectIndexBuffer->updateData(gBevelStrokeAARectIdx,
444 sizeof(gBevelStrokeAARectIdx));
445 GR_DEBUGASSERT(updated);
446 }
447 }
448 return fAABevelStrokeRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000449 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000450}
451
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000452void GrAARectRenderer::geometryFillAARect(GrGpu* gpu,
453 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000454 const SkRect& rect,
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000455 const SkMatrix& combinedMatrix,
bsalomon9c0822a2014-08-11 11:07:48 -0700456 const SkRect& devRect) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000457 GrDrawState* drawState = target->drawState();
458
bsalomon9c0822a2014-08-11 11:07:48 -0700459 GrColor color = drawState->getColor();
460
bsalomonc30aaa02014-08-13 07:15:29 -0700461 CoverageAttribType covAttribType = set_rect_attribs(drawState);
462 if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
bsalomon9c0822a2014-08-11 11:07:48 -0700463 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
464 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000465
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000466 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000467 if (!geo.succeeded()) {
468 GrPrintf("Failed to get space for vertices!\n");
469 return;
470 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000471
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000472 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
473 if (NULL == indexBuffer) {
474 GrPrintf("Failed to create index buffer!\n");
475 return;
476 }
477
478 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000479 size_t vsize = drawState->getVertexSize();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000480
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000481 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
482 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000483
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
bsalomon9c0822a2014-08-11 11:07:48 -0700536 // Make verts point to vertex color and then set all the color and coverage vertex attrs values.
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000537 verts += sizeof(SkPoint);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000538 for (int i = 0; i < 4; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700539 if (kUseCoverage_CoverageAttribType == covAttribType) {
540 *reinterpret_cast<GrColor*>(verts + i * vsize) = color;
541 *reinterpret_cast<GrColor*>(verts + i * vsize + sizeof(GrColor)) = 0;
542 } else {
543 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
544 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000545 }
546
robertphillips@google.com908aed82013-05-28 13:16:20 +0000547 int scale;
548 if (inset < SK_ScalarHalf) {
549 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
550 SkASSERT(scale >= 0 && scale <= 255);
551 } else {
552 scale = 0xff;
553 }
554
bsalomon9c0822a2014-08-11 11:07:48 -0700555 GrColor innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700556 if (kUseCoverage_CoverageAttribType == covAttribType) {
557 innerCoverage = GrColorPackRGBA(scale, scale, scale, scale);
558 } else {
559 innerCoverage = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
560 }
561 verts += 4 * vsize;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000562 for (int i = 0; i < 4; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700563 if (kUseCoverage_CoverageAttribType == covAttribType) {
564 *reinterpret_cast<GrColor*>(verts + i * vsize) = color;
565 *reinterpret_cast<GrColor*>(verts + i * vsize + sizeof(GrColor)) = innerCoverage;
566 } else {
567 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerCoverage;
568 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000569 }
570
571 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000572 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
573 kVertsPerAAFillRect,
574 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000575 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000576}
577
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000578namespace {
579
580// Rotated
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000581struct RectVertex {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000582 SkPoint fPos;
583 SkPoint fCenter;
584 SkPoint fDir;
585 SkPoint fWidthHeight;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000586};
587
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000588// Rotated
robertphillips@google.com42903302013-04-20 12:26:07 +0000589extern const GrVertexAttrib gAARectVertexAttribs[] = {
590 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000591 { kVec4f_GrVertexAttribType, sizeof(SkPoint), kEffect_GrVertexAttribBinding },
592 { kVec2f_GrVertexAttribType, 3*sizeof(SkPoint), kEffect_GrVertexAttribBinding }
robertphillips@google.com42903302013-04-20 12:26:07 +0000593};
594
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000595// Axis Aligned
596struct AARectVertex {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000597 SkPoint fPos;
598 SkPoint fOffset;
599 SkPoint fWidthHeight;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000600};
601
602// Axis Aligned
603extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
604 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000605 { kVec4f_GrVertexAttribType, sizeof(SkPoint), kEffect_GrVertexAttribBinding },
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000606};
607
robertphillips@google.com42903302013-04-20 12:26:07 +0000608};
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000609
610void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
611 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000612 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000613 const SkMatrix& combinedMatrix) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000614 GrDrawState* drawState = target->drawState();
615
616 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
617 combinedMatrix.mapPoints(&center, 1);
618
619 // compute transformed (0, 1) vector
620 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
621 dir.normalize();
622
623 // compute transformed (width, 0) and (0, height) vectors
624 SkVector vec[2] = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000625 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
626 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000627 };
628
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000629 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
630 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
robertphillips@google.com42903302013-04-20 12:26:07 +0000631 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs));
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000632 SkASSERT(sizeof(RectVertex) == drawState->getVertexSize());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000633
634 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
635 if (!geo.succeeded()) {
636 GrPrintf("Failed to get space for vertices!\n");
637 return;
638 }
639
640 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
641
bsalomon83d081a2014-07-08 09:56:10 -0700642 GrEffect* effect = GrRectEffect::Create();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000643 static const int kRectAttrIndex = 1;
644 static const int kWidthIndex = 2;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000645 drawState->addCoverageEffect(effect, kRectAttrIndex, kWidthIndex)->unref();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000646
647 for (int i = 0; i < 4; ++i) {
648 verts[i].fCenter = center;
649 verts[i].fDir = dir;
650 verts[i].fWidthHeight.fX = newWidth;
651 verts[i].fWidthHeight.fY = newHeight;
652 }
653
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000654 SkRect devRect;
655 combinedMatrix.mapRect(&devRect, rect);
656
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000657 SkRect devBounds = {
658 devRect.fLeft - SK_ScalarHalf,
659 devRect.fTop - SK_ScalarHalf,
660 devRect.fRight + SK_ScalarHalf,
661 devRect.fBottom + SK_ScalarHalf
662 };
663
664 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
665 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
666 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
667 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
668
669 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
670 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
671 target->resetIndexSource();
672}
673
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000674void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu,
675 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000676 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000677 const SkMatrix& combinedMatrix) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000678 GrDrawState* drawState = target->drawState();
679 SkASSERT(combinedMatrix.rectStaysRect());
680
681 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs));
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000682 SkASSERT(sizeof(AARectVertex) == drawState->getVertexSize());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000683
684 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
685 if (!geo.succeeded()) {
686 GrPrintf("Failed to get space for vertices!\n");
687 return;
688 }
689
690 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
691
bsalomon83d081a2014-07-08 09:56:10 -0700692 GrEffect* effect = GrAlignedRectEffect::Create();
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000693 static const int kOffsetIndex = 1;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000694 drawState->addCoverageEffect(effect, kOffsetIndex)->unref();
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000695
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000696 SkRect devRect;
697 combinedMatrix.mapRect(&devRect, rect);
698
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000699 SkRect devBounds = {
700 devRect.fLeft - SK_ScalarHalf,
701 devRect.fTop - SK_ScalarHalf,
702 devRect.fRight + SK_ScalarHalf,
703 devRect.fBottom + SK_ScalarHalf
704 };
705
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000706 SkPoint widthHeight = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000707 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
708 SkScalarHalf(devRect.height()) + SK_ScalarHalf
709 };
710
711 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
712 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
713 verts[0].fWidthHeight = widthHeight;
714
715 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
716 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
717 verts[1].fWidthHeight = widthHeight;
718
719 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
720 verts[2].fOffset = widthHeight;
721 verts[2].fWidthHeight = widthHeight;
722
723 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
724 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
725 verts[3].fWidthHeight = widthHeight;
726
727 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
728 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
729 target->resetIndexSource();
730}
731
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000732void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000733 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000734 const SkRect& rect,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000735 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000736 const SkRect& devRect,
bsalomon9c0822a2014-08-11 11:07:48 -0700737 const SkStrokeRec& stroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000738 SkVector devStrokeSize;
egdanield58a0ba2014-06-11 10:30:05 -0700739 SkScalar width = stroke.getWidth();
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000740 if (width > 0) {
741 devStrokeSize.set(width, width);
742 combinedMatrix.mapVectors(&devStrokeSize, 1);
743 devStrokeSize.setAbs(devStrokeSize);
744 } else {
745 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
746 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000747
robertphillips@google.com18136d12013-05-10 11:05:58 +0000748 const SkScalar dx = devStrokeSize.fX;
749 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000750 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
751 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000752
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000753 // Temporarily #if'ed out. We don't want to pass in the devRect but
754 // right now it is computed in GrContext::apply_aa_to_rect and we don't
755 // want to throw away the work
756#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000757 SkRect devRect;
758 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000759#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000760
bsalomon@google.com81712882012-11-01 17:12:34 +0000761 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000762 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000763 SkScalar w = devRect.width() - dx;
764 SkScalar h = devRect.height() - dy;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000765 spare = SkTMin(w, h);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000766 }
767
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000768 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000769 devOutside.outset(rx, ry);
770
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000771 bool miterStroke = true;
yunchao.he2bff2302014-07-28 19:18:49 -0700772 // For hairlines, make bevel and round joins appear the same as mitered ones.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000773 // small miter limit means right angles show bevel...
yunchao.he2bff2302014-07-28 19:18:49 -0700774 if ((width > 0) && (stroke.getJoin() != SkPaint::kMiter_Join ||
775 stroke.getMiter() < SK_ScalarSqrt2)) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000776 miterStroke = false;
777 }
778
779 if (spare <= 0 && miterStroke) {
bsalomon9c0822a2014-08-11 11:07:48 -0700780 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000781 return;
782 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000783
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000784 SkRect devInside(devRect);
785 devInside.inset(rx, ry);
786
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000787 SkRect devOutsideAssist(devRect);
788
789 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
790 // to draw the outer of the rect. Because there are 8 vertices on the outer
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000791 // edge, while vertex number of inner edge is 4, the same as miter-stroke.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000792 if (!miterStroke) {
793 devOutside.inset(0, ry);
794 devOutsideAssist.outset(0, ry);
795 }
796
bsalomon9c0822a2014-08-11 11:07:48 -0700797 this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist, devInside, miterStroke);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000798}
799
800void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu,
801 GrDrawTarget* target,
802 const SkRect& devOutside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000803 const SkRect& devOutsideAssist,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000804 const SkRect& devInside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000805 bool miterStroke) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000806 GrDrawState* drawState = target->drawState();
807
bsalomonc30aaa02014-08-13 07:15:29 -0700808 CoverageAttribType covAttribType = set_rect_attribs(drawState);
bsalomon9c0822a2014-08-11 11:07:48 -0700809
810 GrColor color = drawState->getColor();
bsalomonc30aaa02014-08-13 07:15:29 -0700811 if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
bsalomon9c0822a2014-08-11 11:07:48 -0700812 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
813 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000814
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000815 int innerVertexNum = 4;
816 int outerVertexNum = miterStroke ? 4 : 8;
817 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
818
819 GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000820 if (!geo.succeeded()) {
821 GrPrintf("Failed to get space for vertices!\n");
822 return;
823 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000824 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu, miterStroke);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000825 if (NULL == indexBuffer) {
826 GrPrintf("Failed to create index buffer!\n");
827 return;
828 }
829
830 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000831 size_t vsize = drawState->getVertexSize();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000832
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000833 // We create vertices for four nested rectangles. There are two ramps from 0 to full
834 // coverage, one on the exterior of the stroke and the other on the interior.
835 // The following pointers refer to the four rects, from outermost to innermost.
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000836 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
837 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vsize);
838 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vsize);
839 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000840
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000841#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
robertphillips@google.com353f0972013-06-28 17:57:06 +0000842 // TODO: this only really works if the X & Y margins are the same all around
843 // the rect
844 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
845 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
846 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000847 if (miterStroke) {
848 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
849 } else {
850 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom);
851 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000852 SkASSERT(inset >= 0);
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000853#else
854 SkScalar inset = SK_ScalarHalf;
855#endif
robertphillips@google.com353f0972013-06-28 17:57:06 +0000856
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000857 if (miterStroke) {
858 // outermost
859 set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
860 // inner two
861 set_inset_fan(fan1Pos, vsize, devOutside, inset, inset);
862 set_inset_fan(fan2Pos, vsize, devInside, -inset, -inset);
863 // innermost
864 set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf);
865 } else {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000866 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vsize);
867 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + (outerVertexNum + 4) * vsize);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000868 // outermost
869 set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
870 set_inset_fan(fan0AssistPos, vsize, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf);
871 // outer one of the inner two
872 set_inset_fan(fan1Pos, vsize, devOutside, inset, inset);
873 set_inset_fan(fan1AssistPos, vsize, devOutsideAssist, inset, inset);
874 // inner one of the inner two
875 set_inset_fan(fan2Pos, vsize, devInside, -inset, -inset);
876 // innermost
877 set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf);
878 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000879
bsalomon9c0822a2014-08-11 11:07:48 -0700880 // Make verts point to vertex color and then set all the color and coverage vertex attrs values.
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000881 // The outermost rect has 0 coverage
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000882 verts += sizeof(SkPoint);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000883 for (int i = 0; i < outerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700884 if (kUseCoverage_CoverageAttribType == covAttribType) {
885 *reinterpret_cast<GrColor*>(verts + i * vsize) = color;
886 *reinterpret_cast<GrColor*>(verts + i * vsize + sizeof(GrColor)) = 0;
887 } else {
888 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
889 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000890 }
891
bsalomon9c0822a2014-08-11 11:07:48 -0700892 // scale is the coverage for the the inner two rects.
robertphillips@google.com353f0972013-06-28 17:57:06 +0000893 int scale;
894 if (inset < SK_ScalarHalf) {
895 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
896 SkASSERT(scale >= 0 && scale <= 255);
897 } else {
898 scale = 0xff;
899 }
900
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000901 verts += outerVertexNum * vsize;
bsalomonc30aaa02014-08-13 07:15:29 -0700902 GrColor innerCoverage;
903 if (kUseCoverage_CoverageAttribType == covAttribType) {
904 innerCoverage = GrColorPackRGBA(scale, scale, scale, scale);
905 } else {
906 innerCoverage = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
907 }
908
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000909 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700910 if (kUseCoverage_CoverageAttribType == covAttribType) {
911 *reinterpret_cast<GrColor*>(verts + i * vsize) = color;
912 *reinterpret_cast<GrColor*>(verts + i * vsize + sizeof(GrColor)) = innerCoverage;
913 } else {
914 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerCoverage;
915 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000916 }
917
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000918 // The innermost rect has 0 coverage
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000919 verts += (outerVertexNum + innerVertexNum) * vsize;
920 for (int i = 0; i < innerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700921 if (kUseCoverage_CoverageAttribType == covAttribType) {
922 *reinterpret_cast<GrColor*>(verts + i * vsize) = color;
923 *reinterpret_cast<GrColor*>(verts + i * vsize + sizeof(GrColor)) = 0;
924 } else {
925 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
926 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000927 }
928
929 target->setIndexSourceToBuffer(indexBuffer);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000930 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0,
931 totalVertexNum, aaStrokeRectIndexCount(miterStroke));
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000932}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000933
934void GrAARectRenderer::fillAANestedRects(GrGpu* gpu,
935 GrDrawTarget* target,
936 const SkRect rects[2],
bsalomon9c0822a2014-08-11 11:07:48 -0700937 const SkMatrix& combinedMatrix) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000938 SkASSERT(combinedMatrix.rectStaysRect());
939 SkASSERT(!rects[1].isEmpty());
940
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000941 SkRect devOutside, devOutsideAssist, devInside;
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000942 combinedMatrix.mapRect(&devOutside, rects[0]);
943 // can't call mapRect for devInside since it calls sort
944 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
945
946 if (devInside.isEmpty()) {
bsalomon9c0822a2014-08-11 11:07:48 -0700947 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000948 return;
949 }
950
bsalomon9c0822a2014-08-11 11:07:48 -0700951 this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist, devInside, true);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000952}