blob: be82d5b88fe7d2fe6077d8f3944bf51b1ef62bfd [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 {
258
bsalomon9c0822a2014-08-11 11:07:48 -0700259extern const GrVertexAttrib gAARectAttribs[] = {
260 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
261 {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding},
262 {kVec4ub_GrVertexAttribType, sizeof(SkPoint) + sizeof(SkColor), kCoverage_GrVertexAttribBinding},
robertphillips@google.com42903302013-04-20 12:26:07 +0000263};
264
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000265static void set_inset_fan(SkPoint* pts, size_t stride,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000266 const SkRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000267 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
268 r.fRight - dx, r.fBottom - dy, stride);
269}
270
271};
272
273void GrAARectRenderer::reset() {
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000274 SkSafeSetNull(fAAFillRectIndexBuffer);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000275 SkSafeSetNull(fAAMiterStrokeRectIndexBuffer);
276 SkSafeSetNull(fAABevelStrokeRectIndexBuffer);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000277}
278
robertphillips@google.com6d067302012-12-18 21:47:47 +0000279static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000280 0, 1, 5, 5, 4, 0,
281 1, 2, 6, 6, 5, 1,
282 2, 3, 7, 7, 6, 2,
283 3, 0, 4, 4, 7, 3,
284 4, 5, 6, 6, 7, 4,
285};
286
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000287static const int kIndicesPerAAFillRect = SK_ARRAY_COUNT(gFillAARectIdx);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000288static const int kVertsPerAAFillRect = 8;
289static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000290
291GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000292 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
293 sizeof(uint16_t) *
294 kNumAAFillRectsInIndexBuffer;
295
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000296 if (NULL == fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000297 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000298 if (NULL != fAAFillRectIndexBuffer) {
commit-bot@chromium.org8341eb72014-05-07 20:51:05 +0000299 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->map();
robertphillips@google.com6d067302012-12-18 21:47:47 +0000300 bool useTempData = (NULL == data);
301 if (useTempData) {
302 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
303 }
304 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
305 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
306 // the inner rect (for AA) and 2 for the inner rect.
307 int baseIdx = i * kIndicesPerAAFillRect;
308 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
309 for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
310 data[baseIdx+j] = baseVert + gFillAARectIdx[j];
311 }
312 }
313 if (useTempData) {
314 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +0000315 SkFAIL("Can't get AA Fill Rect indices into buffer!");
robertphillips@google.com6d067302012-12-18 21:47:47 +0000316 }
317 SkDELETE_ARRAY(data);
318 } else {
commit-bot@chromium.org8341eb72014-05-07 20:51:05 +0000319 fAAFillRectIndexBuffer->unmap();
robertphillips@google.com6d067302012-12-18 21:47:47 +0000320 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000321 }
322 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000323
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000324 return fAAFillRectIndexBuffer;
325}
326
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000327static const uint16_t gMiterStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000328 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
329 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
330 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
331 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
332
333 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
334 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
335 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
336 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
337
338 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
339 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
340 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
341 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
342};
343
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000344/**
345 * As in miter-stroke, index = a + b, and a is the current index, b is the shift
346 * from the first index. The index layout:
347 * outer AA line: 0~3, 4~7
348 * outer edge: 8~11, 12~15
349 * inner edge: 16~19
350 * inner AA line: 20~23
351 * Following comes a bevel-stroke rect and its indices:
352 *
353 * 4 7
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000354 * *********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000355 * * ______________________________ *
356 * * / 12 15 \ *
357 * * / \ *
358 * 0 * |8 16_____________________19 11 | * 3
359 * * | | | | *
360 * * | | **************** | | *
361 * * | | * 20 23 * | | *
362 * * | | * * | | *
363 * * | | * 21 22 * | | *
364 * * | | **************** | | *
365 * * | |____________________| | *
366 * 1 * |9 17 18 10| * 2
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000367 * * \ / *
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000368 * * \13 __________________________14/ *
369 * * *
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000370 * **********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000371 * 5 6
372 */
373static const uint16_t gBevelStrokeAARectIdx[] = {
374 // Draw outer AA, from outer AA line to outer edge, shift is 0.
375 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
376 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
377 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
378 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
379 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
380 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
381 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
382 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
383
384 // Draw the stroke, from outer edge to inner edge, shift is 8.
385 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
386 1 + 8, 5 + 8, 9 + 8,
387 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
388 6 + 8, 2 + 8, 10 + 8,
389 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
390 3 + 8, 7 + 8, 11 + 8,
391 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
392 4 + 8, 0 + 8, 8 + 8,
393
394 // Draw the inner AA, from inner edge to inner AA line, shift is 16.
395 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
396 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
397 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
398 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
399};
400
401int GrAARectRenderer::aaStrokeRectIndexCount(bool miterStroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000402 return miterStroke ? SK_ARRAY_COUNT(gMiterStrokeAARectIdx) :
403 SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000404}
405
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000406GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu, bool miterStroke) {
407 if (miterStroke) {
408 if (NULL == fAAMiterStrokeRectIndexBuffer) {
409 fAAMiterStrokeRectIndexBuffer =
410 gpu->createIndexBuffer(sizeof(gMiterStrokeAARectIdx), false);
411 if (NULL != fAAMiterStrokeRectIndexBuffer) {
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000412#ifdef SK_DEBUG
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000413 bool updated =
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000414#endif
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000415 fAAMiterStrokeRectIndexBuffer->updateData(gMiterStrokeAARectIdx,
416 sizeof(gMiterStrokeAARectIdx));
417 GR_DEBUGASSERT(updated);
418 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000419 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000420 return fAAMiterStrokeRectIndexBuffer;
421 } else {
422 if (NULL == fAABevelStrokeRectIndexBuffer) {
423 fAABevelStrokeRectIndexBuffer =
424 gpu->createIndexBuffer(sizeof(gBevelStrokeAARectIdx), false);
425 if (NULL != fAABevelStrokeRectIndexBuffer) {
426#ifdef SK_DEBUG
427 bool updated =
428#endif
429 fAABevelStrokeRectIndexBuffer->updateData(gBevelStrokeAARectIdx,
430 sizeof(gBevelStrokeAARectIdx));
431 GR_DEBUGASSERT(updated);
432 }
433 }
434 return fAABevelStrokeRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000435 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000436}
437
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000438void GrAARectRenderer::geometryFillAARect(GrGpu* gpu,
439 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000440 const SkRect& rect,
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000441 const SkMatrix& combinedMatrix,
bsalomon9c0822a2014-08-11 11:07:48 -0700442 const SkRect& devRect) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000443 GrDrawState* drawState = target->drawState();
444
bsalomon9c0822a2014-08-11 11:07:48 -0700445 GrColor color = drawState->getColor();
446
447 drawState->setVertexAttribs<gAARectAttribs>(SK_ARRAY_COUNT(gAARectAttribs));
448 if (GrColorIsOpaque(color)) {
449 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
450 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000451
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000452 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000453 if (!geo.succeeded()) {
454 GrPrintf("Failed to get space for vertices!\n");
455 return;
456 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000457
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000458 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
459 if (NULL == indexBuffer) {
460 GrPrintf("Failed to create index buffer!\n");
461 return;
462 }
463
464 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000465 size_t vsize = drawState->getVertexSize();
bsalomon9c0822a2014-08-11 11:07:48 -0700466 SkASSERT(sizeof(SkPoint) + 2 * sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000467
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000468 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
469 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000470
robertphillips@google.com908aed82013-05-28 13:16:20 +0000471 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
472 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
473
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000474 if (combinedMatrix.rectStaysRect()) {
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000475 // Temporarily #if'ed out. We don't want to pass in the devRect but
476 // right now it is computed in GrContext::apply_aa_to_rect and we don't
477 // want to throw away the work
478#if 0
robertphillips@google.com91b71162013-05-10 14:09:54 +0000479 SkRect devRect;
480 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000481#endif
robertphillips@google.com91b71162013-05-10 14:09:54 +0000482
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000483 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
robertphillips@google.com908aed82013-05-28 13:16:20 +0000484 set_inset_fan(fan1Pos, vsize, devRect, inset, inset);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000485 } else {
486 // compute transformed (1, 0) and (0, 1) vectors
487 SkVector vec[2] = {
488 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
489 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
490 };
491
492 vec[0].normalize();
493 vec[0].scale(SK_ScalarHalf);
494 vec[1].normalize();
495 vec[1].scale(SK_ScalarHalf);
496
robertphillips@google.com91b71162013-05-10 14:09:54 +0000497 // create the rotated rect
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000498 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
499 rect.fRight, rect.fBottom, vsize);
500 combinedMatrix.mapPointsWithStride(fan0Pos, vsize, 4);
501
robertphillips@google.com91b71162013-05-10 14:09:54 +0000502 // Now create the inset points and then outset the original
503 // rotated points
504
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000505 // TL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000506 *((SkPoint*)((intptr_t)fan1Pos + 0 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000507 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) + vec[0] + vec[1];
508 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) -= vec[0] + vec[1];
509 // BL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000510 *((SkPoint*)((intptr_t)fan1Pos + 1 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000511 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) + vec[0] - vec[1];
512 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) -= vec[0] - vec[1];
513 // BR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000514 *((SkPoint*)((intptr_t)fan1Pos + 2 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000515 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) - vec[0] - vec[1];
516 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) += vec[0] + vec[1];
517 // TR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000518 *((SkPoint*)((intptr_t)fan1Pos + 3 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000519 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) - vec[0] + vec[1];
520 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) += vec[0] - vec[1];
521 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000522
bsalomon9c0822a2014-08-11 11:07:48 -0700523 // 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 +0000524 verts += sizeof(SkPoint);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000525 for (int i = 0; i < 4; ++i) {
bsalomon9c0822a2014-08-11 11:07:48 -0700526 *reinterpret_cast<GrColor*>(verts + i * vsize) = color;
527 *reinterpret_cast<GrColor*>(verts + i * vsize + sizeof(GrColor)) = 0;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000528 }
529
robertphillips@google.com908aed82013-05-28 13:16:20 +0000530 int scale;
531 if (inset < SK_ScalarHalf) {
532 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
533 SkASSERT(scale >= 0 && scale <= 255);
534 } else {
535 scale = 0xff;
536 }
537
bsalomon9c0822a2014-08-11 11:07:48 -0700538 GrColor innerCoverage;
539 innerCoverage = GrColorPackRGBA(scale, scale, scale, scale); verts += 4 * vsize;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000540 for (int i = 0; i < 4; ++i) {
bsalomon9c0822a2014-08-11 11:07:48 -0700541 *reinterpret_cast<GrColor*>(verts + i * vsize) = color;
542 *reinterpret_cast<GrColor*>(verts + i * vsize + sizeof(GrColor)) = innerCoverage;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000543 }
544
545 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000546 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
547 kVertsPerAAFillRect,
548 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000549 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000550}
551
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000552namespace {
553
554// Rotated
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000555struct RectVertex {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000556 SkPoint fPos;
557 SkPoint fCenter;
558 SkPoint fDir;
559 SkPoint fWidthHeight;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000560};
561
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000562// Rotated
robertphillips@google.com42903302013-04-20 12:26:07 +0000563extern const GrVertexAttrib gAARectVertexAttribs[] = {
564 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000565 { kVec4f_GrVertexAttribType, sizeof(SkPoint), kEffect_GrVertexAttribBinding },
566 { kVec2f_GrVertexAttribType, 3*sizeof(SkPoint), kEffect_GrVertexAttribBinding }
robertphillips@google.com42903302013-04-20 12:26:07 +0000567};
568
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000569// Axis Aligned
570struct AARectVertex {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000571 SkPoint fPos;
572 SkPoint fOffset;
573 SkPoint fWidthHeight;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000574};
575
576// Axis Aligned
577extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
578 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000579 { kVec4f_GrVertexAttribType, sizeof(SkPoint), kEffect_GrVertexAttribBinding },
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000580};
581
robertphillips@google.com42903302013-04-20 12:26:07 +0000582};
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000583
584void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
585 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000586 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000587 const SkMatrix& combinedMatrix) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000588 GrDrawState* drawState = target->drawState();
589
590 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
591 combinedMatrix.mapPoints(&center, 1);
592
593 // compute transformed (0, 1) vector
594 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
595 dir.normalize();
596
597 // compute transformed (width, 0) and (0, height) vectors
598 SkVector vec[2] = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000599 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
600 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000601 };
602
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000603 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
604 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
robertphillips@google.com42903302013-04-20 12:26:07 +0000605 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs));
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000606 SkASSERT(sizeof(RectVertex) == drawState->getVertexSize());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000607
608 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
609 if (!geo.succeeded()) {
610 GrPrintf("Failed to get space for vertices!\n");
611 return;
612 }
613
614 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
615
bsalomon83d081a2014-07-08 09:56:10 -0700616 GrEffect* effect = GrRectEffect::Create();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000617 static const int kRectAttrIndex = 1;
618 static const int kWidthIndex = 2;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000619 drawState->addCoverageEffect(effect, kRectAttrIndex, kWidthIndex)->unref();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000620
621 for (int i = 0; i < 4; ++i) {
622 verts[i].fCenter = center;
623 verts[i].fDir = dir;
624 verts[i].fWidthHeight.fX = newWidth;
625 verts[i].fWidthHeight.fY = newHeight;
626 }
627
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000628 SkRect devRect;
629 combinedMatrix.mapRect(&devRect, rect);
630
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000631 SkRect devBounds = {
632 devRect.fLeft - SK_ScalarHalf,
633 devRect.fTop - SK_ScalarHalf,
634 devRect.fRight + SK_ScalarHalf,
635 devRect.fBottom + SK_ScalarHalf
636 };
637
638 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
639 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
640 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
641 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
642
643 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
644 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
645 target->resetIndexSource();
646}
647
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000648void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu,
649 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000650 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000651 const SkMatrix& combinedMatrix) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000652 GrDrawState* drawState = target->drawState();
653 SkASSERT(combinedMatrix.rectStaysRect());
654
655 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs));
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000656 SkASSERT(sizeof(AARectVertex) == drawState->getVertexSize());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000657
658 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
659 if (!geo.succeeded()) {
660 GrPrintf("Failed to get space for vertices!\n");
661 return;
662 }
663
664 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
665
bsalomon83d081a2014-07-08 09:56:10 -0700666 GrEffect* effect = GrAlignedRectEffect::Create();
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000667 static const int kOffsetIndex = 1;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000668 drawState->addCoverageEffect(effect, kOffsetIndex)->unref();
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000669
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000670 SkRect devRect;
671 combinedMatrix.mapRect(&devRect, rect);
672
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000673 SkRect devBounds = {
674 devRect.fLeft - SK_ScalarHalf,
675 devRect.fTop - SK_ScalarHalf,
676 devRect.fRight + SK_ScalarHalf,
677 devRect.fBottom + SK_ScalarHalf
678 };
679
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000680 SkPoint widthHeight = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000681 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
682 SkScalarHalf(devRect.height()) + SK_ScalarHalf
683 };
684
685 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
686 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
687 verts[0].fWidthHeight = widthHeight;
688
689 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
690 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
691 verts[1].fWidthHeight = widthHeight;
692
693 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
694 verts[2].fOffset = widthHeight;
695 verts[2].fWidthHeight = widthHeight;
696
697 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
698 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
699 verts[3].fWidthHeight = widthHeight;
700
701 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
702 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
703 target->resetIndexSource();
704}
705
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000706void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000707 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000708 const SkRect& rect,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000709 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000710 const SkRect& devRect,
bsalomon9c0822a2014-08-11 11:07:48 -0700711 const SkStrokeRec& stroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000712 SkVector devStrokeSize;
egdanield58a0ba2014-06-11 10:30:05 -0700713 SkScalar width = stroke.getWidth();
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000714 if (width > 0) {
715 devStrokeSize.set(width, width);
716 combinedMatrix.mapVectors(&devStrokeSize, 1);
717 devStrokeSize.setAbs(devStrokeSize);
718 } else {
719 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
720 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000721
robertphillips@google.com18136d12013-05-10 11:05:58 +0000722 const SkScalar dx = devStrokeSize.fX;
723 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000724 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
725 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000726
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000727 // Temporarily #if'ed out. We don't want to pass in the devRect but
728 // right now it is computed in GrContext::apply_aa_to_rect and we don't
729 // want to throw away the work
730#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000731 SkRect devRect;
732 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000733#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000734
bsalomon@google.com81712882012-11-01 17:12:34 +0000735 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000736 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000737 SkScalar w = devRect.width() - dx;
738 SkScalar h = devRect.height() - dy;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000739 spare = SkTMin(w, h);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000740 }
741
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000742 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000743 devOutside.outset(rx, ry);
744
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000745 bool miterStroke = true;
yunchao.he2bff2302014-07-28 19:18:49 -0700746 // For hairlines, make bevel and round joins appear the same as mitered ones.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000747 // small miter limit means right angles show bevel...
yunchao.he2bff2302014-07-28 19:18:49 -0700748 if ((width > 0) && (stroke.getJoin() != SkPaint::kMiter_Join ||
749 stroke.getMiter() < SK_ScalarSqrt2)) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000750 miterStroke = false;
751 }
752
753 if (spare <= 0 && miterStroke) {
bsalomon9c0822a2014-08-11 11:07:48 -0700754 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000755 return;
756 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000757
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000758 SkRect devInside(devRect);
759 devInside.inset(rx, ry);
760
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000761 SkRect devOutsideAssist(devRect);
762
763 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
764 // to draw the outer of the rect. Because there are 8 vertices on the outer
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000765 // edge, while vertex number of inner edge is 4, the same as miter-stroke.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000766 if (!miterStroke) {
767 devOutside.inset(0, ry);
768 devOutsideAssist.outset(0, ry);
769 }
770
bsalomon9c0822a2014-08-11 11:07:48 -0700771 this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist, devInside, miterStroke);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000772}
773
774void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu,
775 GrDrawTarget* target,
776 const SkRect& devOutside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000777 const SkRect& devOutsideAssist,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000778 const SkRect& devInside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000779 bool miterStroke) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000780 GrDrawState* drawState = target->drawState();
781
bsalomon9c0822a2014-08-11 11:07:48 -0700782 drawState->setVertexAttribs<gAARectAttribs>(SK_ARRAY_COUNT(gAARectAttribs));
783
784 GrColor color = drawState->getColor();
785 if (GrColorIsOpaque(color)) {
786 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
787 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000788
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000789 int innerVertexNum = 4;
790 int outerVertexNum = miterStroke ? 4 : 8;
791 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
792
793 GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000794 if (!geo.succeeded()) {
795 GrPrintf("Failed to get space for vertices!\n");
796 return;
797 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000798 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu, miterStroke);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000799 if (NULL == indexBuffer) {
800 GrPrintf("Failed to create index buffer!\n");
801 return;
802 }
803
804 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000805 size_t vsize = drawState->getVertexSize();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000806
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000807 // We create vertices for four nested rectangles. There are two ramps from 0 to full
808 // coverage, one on the exterior of the stroke and the other on the interior.
809 // The following pointers refer to the four rects, from outermost to innermost.
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000810 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
811 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vsize);
812 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vsize);
813 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000814
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000815#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
robertphillips@google.com353f0972013-06-28 17:57:06 +0000816 // TODO: this only really works if the X & Y margins are the same all around
817 // the rect
818 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
819 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
820 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000821 if (miterStroke) {
822 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
823 } else {
824 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom);
825 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000826 SkASSERT(inset >= 0);
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000827#else
828 SkScalar inset = SK_ScalarHalf;
829#endif
robertphillips@google.com353f0972013-06-28 17:57:06 +0000830
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000831 if (miterStroke) {
832 // outermost
833 set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
834 // inner two
835 set_inset_fan(fan1Pos, vsize, devOutside, inset, inset);
836 set_inset_fan(fan2Pos, vsize, devInside, -inset, -inset);
837 // innermost
838 set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf);
839 } else {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000840 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vsize);
841 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + (outerVertexNum + 4) * vsize);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000842 // outermost
843 set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
844 set_inset_fan(fan0AssistPos, vsize, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf);
845 // outer one of the inner two
846 set_inset_fan(fan1Pos, vsize, devOutside, inset, inset);
847 set_inset_fan(fan1AssistPos, vsize, devOutsideAssist, inset, inset);
848 // inner one of the inner two
849 set_inset_fan(fan2Pos, vsize, devInside, -inset, -inset);
850 // innermost
851 set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf);
852 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000853
bsalomon9c0822a2014-08-11 11:07:48 -0700854 // 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 +0000855 // The outermost rect has 0 coverage
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000856 verts += sizeof(SkPoint);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000857 for (int i = 0; i < outerVertexNum; ++i) {
bsalomon9c0822a2014-08-11 11:07:48 -0700858 *reinterpret_cast<GrColor*>(verts + i * vsize) = color;
859 *reinterpret_cast<GrColor*>(verts + i * vsize + sizeof(GrColor)) = 0;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000860 }
861
bsalomon9c0822a2014-08-11 11:07:48 -0700862 // scale is the coverage for the the inner two rects.
robertphillips@google.com353f0972013-06-28 17:57:06 +0000863 int scale;
864 if (inset < SK_ScalarHalf) {
865 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
866 SkASSERT(scale >= 0 && scale <= 255);
867 } else {
868 scale = 0xff;
869 }
870
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000871 verts += outerVertexNum * vsize;
bsalomon9c0822a2014-08-11 11:07:48 -0700872 GrColor innerCoverage = GrColorPackRGBA(scale, scale, scale, scale);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000873 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
bsalomon9c0822a2014-08-11 11:07:48 -0700874 *reinterpret_cast<GrColor*>(verts + i * vsize) = color;
875 *reinterpret_cast<GrColor*>(verts + i * vsize + sizeof(GrColor)) = innerCoverage;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000876 }
877
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000878 // The innermost rect has 0 coverage
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000879 verts += (outerVertexNum + innerVertexNum) * vsize;
880 for (int i = 0; i < innerVertexNum; ++i) {
bsalomon9c0822a2014-08-11 11:07:48 -0700881 *reinterpret_cast<GrColor*>(verts + i * vsize) = color;
882 *reinterpret_cast<GrColor*>(verts + i * vsize + sizeof(GrColor)) = 0;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000883 }
884
885 target->setIndexSourceToBuffer(indexBuffer);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000886 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0,
887 totalVertexNum, aaStrokeRectIndexCount(miterStroke));
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000888}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000889
890void GrAARectRenderer::fillAANestedRects(GrGpu* gpu,
891 GrDrawTarget* target,
892 const SkRect rects[2],
bsalomon9c0822a2014-08-11 11:07:48 -0700893 const SkMatrix& combinedMatrix) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000894 SkASSERT(combinedMatrix.rectStaysRect());
895 SkASSERT(!rects[1].isEmpty());
896
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000897 SkRect devOutside, devOutsideAssist, devInside;
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000898 combinedMatrix.mapRect(&devOutside, rects[0]);
899 // can't call mapRect for devInside since it calls sort
900 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
901
902 if (devInside.isEmpty()) {
bsalomon9c0822a2014-08-11 11:07:48 -0700903 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000904 return;
905 }
906
bsalomon9c0822a2014-08-11 11:07:48 -0700907 this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist, devInside, true);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000908}