2 * Copyright 2012 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "GrAARectRenderer.h"
10 #include "gl/builders/GrGLFullProgramBuilder.h"
11 #include "gl/GrGLProcessor.h"
12 #include "gl/GrGLGeometryProcessor.h"
13 #include "GrTBackendProcessorFactory.h"
14 #include "SkColorPriv.h"
15 #include "GrGeometryProcessor.h"
17 ///////////////////////////////////////////////////////////////////////////////
18 class GrGLAlignedRectEffect;
20 // Axis Aligned special case
21 class GrAlignedRectEffect : public GrGeometryProcessor {
23 static GrGeometryProcessor* Create() {
24 GR_CREATE_STATIC_GEOMETRY_PROCESSOR(gAlignedRectEffect, GrAlignedRectEffect, ());
25 gAlignedRectEffect->ref();
26 return gAlignedRectEffect;
29 virtual ~GrAlignedRectEffect() {}
31 static const char* Name() { return "AlignedRectEdge"; }
33 virtual void getConstantColorComponents(GrColor* color,
34 uint32_t* validFlags) const SK_OVERRIDE {
38 const GrShaderVar& inRect() const { return fInRect; }
40 virtual const GrBackendGeometryProcessorFactory& getFactory() const SK_OVERRIDE {
41 return GrTBackendGeometryProcessorFactory<GrAlignedRectEffect>::getInstance();
44 class GLProcessor : public GrGLGeometryProcessor {
46 GLProcessor(const GrBackendProcessorFactory& factory, const GrProcessor&)
47 : INHERITED (factory) {}
49 virtual void emitCode(GrGLFullProgramBuilder* builder,
50 const GrGeometryProcessor& geometryProcessor,
51 const GrProcessorKey& key,
52 const char* outputColor,
53 const char* inputColor,
54 const TransformedCoordsArray&,
55 const TextureSamplerArray& samplers) SK_OVERRIDE {
56 // setup the varying for the Axis aligned rect effect
57 // xy -> interpolated offset
58 // zw -> w/2+0.5, h/2+0.5
59 const char *vsRectName, *fsRectName;
60 builder->addVarying(kVec4f_GrSLType, "Rect", &vsRectName, &fsRectName);
62 const GrShaderVar& inRect = geometryProcessor.cast<GrAlignedRectEffect>().inRect();
63 GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
64 vsBuilder->codeAppendf("\t%s = %s;\n", vsRectName, inRect.c_str());
66 GrGLProcessorFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
67 // TODO: compute all these offsets, spans, and scales in the VS
68 fsBuilder->codeAppendf("\tfloat insetW = min(1.0, %s.z) - 0.5;\n", fsRectName);
69 fsBuilder->codeAppendf("\tfloat insetH = min(1.0, %s.w) - 0.5;\n", fsRectName);
70 fsBuilder->codeAppend("\tfloat outset = 0.5;\n");
71 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
72 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
73 fsBuilder->codeAppend("\tfloat spanW = insetW + outset;\n");
74 fsBuilder->codeAppend("\tfloat spanH = insetH + outset;\n");
75 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
76 // value of coverage that is used. In other words it is the coverage that is
77 // used in the interior of the rect after the ramp.
78 fsBuilder->codeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
79 fsBuilder->codeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
81 // Compute the coverage for the rect's width
82 fsBuilder->codeAppendf(
83 "\tfloat coverage = scaleW*clamp((%s.z-abs(%s.x))/spanW, 0.0, 1.0);\n", fsRectName,
85 // Compute the coverage for the rect's height and merge with the width
86 fsBuilder->codeAppendf(
87 "\tcoverage = coverage*scaleH*clamp((%s.w-abs(%s.y))/spanH, 0.0, 1.0);\n",
88 fsRectName, fsRectName);
91 fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
92 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("coverage")).c_str());
95 static void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder*) {}
97 virtual void setData(const GrGLProgramDataManager& pdman, const GrProcessor&) SK_OVERRIDE {}
100 typedef GrGLGeometryProcessor INHERITED;
105 GrAlignedRectEffect()
106 : fInRect(this->addVertexAttrib(GrShaderVar("inRect",
108 GrShaderVar::kAttribute_TypeModifier))) {
111 const GrShaderVar& fInRect;
113 virtual bool onIsEqual(const GrProcessor&) const SK_OVERRIDE { return true; }
115 GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
117 typedef GrGeometryProcessor INHERITED;
121 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrAlignedRectEffect);
123 GrGeometryProcessor* GrAlignedRectEffect::TestCreate(SkRandom* random,
125 const GrDrawTargetCaps&,
126 GrTexture* textures[]) {
127 return GrAlignedRectEffect::Create();
130 ///////////////////////////////////////////////////////////////////////////////
131 class GrGLRectEffect;
134 * The output of this effect is a modulation of the input color and coverage
135 * for an arbitrarily oriented rect. The rect is specified as:
137 * Unit vector point down the height of the rect
140 * The center and vector are stored in a vec4 varying ("RectEdge") with the
141 * center in the xy components and the vector in the zw components.
142 * The munged width and height are stored in a vec2 varying ("WidthHeight")
143 * with the width in x and the height in y.
146 class GrRectEffect : public GrGeometryProcessor {
148 static GrGeometryProcessor* Create() {
149 GR_CREATE_STATIC_GEOMETRY_PROCESSOR(gRectEffect, GrRectEffect, ());
154 virtual ~GrRectEffect() {}
156 static const char* Name() { return "RectEdge"; }
158 virtual void getConstantColorComponents(GrColor* color,
159 uint32_t* validFlags) const SK_OVERRIDE {
163 const GrShaderVar& inRectEdge() const { return fInRectEdge; }
164 const GrShaderVar& inWidthHeight() const { return fInWidthHeight; }
166 virtual const GrBackendGeometryProcessorFactory& getFactory() const SK_OVERRIDE {
167 return GrTBackendGeometryProcessorFactory<GrRectEffect>::getInstance();
170 class GLProcessor : public GrGLGeometryProcessor {
172 GLProcessor(const GrBackendProcessorFactory& factory, const GrProcessor&)
173 : INHERITED (factory) {}
175 virtual void emitCode(GrGLFullProgramBuilder* builder,
176 const GrGeometryProcessor& geometryProcessor,
177 const GrProcessorKey& key,
178 const char* outputColor,
179 const char* inputColor,
180 const TransformedCoordsArray&,
181 const TextureSamplerArray& samplers) SK_OVERRIDE {
182 // setup the varying for the center point and the unit vector
183 // that points down the height of the rect
184 const char *vsRectEdgeName, *fsRectEdgeName;
185 builder->addVarying(kVec4f_GrSLType, "RectEdge",
186 &vsRectEdgeName, &fsRectEdgeName);
188 const GrRectEffect& rectEffect = geometryProcessor.cast<GrRectEffect>();
189 GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
190 vsBuilder->codeAppendf("%s = %s;", vsRectEdgeName, rectEffect.inRectEdge().c_str());
192 // setup the varying for width/2+.5 and height/2+.5
193 const char *vsWidthHeightName, *fsWidthHeightName;
194 builder->addVarying(kVec2f_GrSLType, "WidthHeight",
195 &vsWidthHeightName, &fsWidthHeightName);
196 vsBuilder->codeAppendf("%s = %s;",
198 rectEffect.inWidthHeight().c_str());
200 GrGLProcessorFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
201 // TODO: compute all these offsets, spans, and scales in the VS
202 fsBuilder->codeAppendf("\tfloat insetW = min(1.0, %s.x) - 0.5;\n", fsWidthHeightName);
203 fsBuilder->codeAppendf("\tfloat insetH = min(1.0, %s.y) - 0.5;\n", fsWidthHeightName);
204 fsBuilder->codeAppend("\tfloat outset = 0.5;\n");
205 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
206 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
207 fsBuilder->codeAppend("\tfloat spanW = insetW + outset;\n");
208 fsBuilder->codeAppend("\tfloat spanH = insetH + outset;\n");
209 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
210 // value of coverage that is used. In other words it is the coverage that is
211 // used in the interior of the rect after the ramp.
212 fsBuilder->codeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
213 fsBuilder->codeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
215 // Compute the coverage for the rect's width
216 fsBuilder->codeAppendf("\tvec2 offset = %s.xy - %s.xy;\n",
217 fsBuilder->fragmentPosition(), fsRectEdgeName);
218 fsBuilder->codeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
219 fsRectEdgeName, fsRectEdgeName);
220 fsBuilder->codeAppendf(
221 "\tfloat coverage = scaleW*clamp((%s.x-perpDot)/spanW, 0.0, 1.0);\n",
224 // Compute the coverage for the rect's height and merge with the width
225 fsBuilder->codeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
227 fsBuilder->codeAppendf(
228 "\tcoverage = coverage*scaleH*clamp((%s.y-perpDot)/spanH, 0.0, 1.0);\n",
232 fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
233 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("coverage")).c_str());
236 static void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder*) {}
238 virtual void setData(const GrGLProgramDataManager& pdman, const GrProcessor&) SK_OVERRIDE {}
241 typedef GrGLGeometryProcessor INHERITED;
248 : fInRectEdge(this->addVertexAttrib(GrShaderVar("inRectEdge",
250 GrShaderVar::kAttribute_TypeModifier)))
251 , fInWidthHeight(this->addVertexAttrib(
252 GrShaderVar("inWidthHeight",
254 GrShaderVar::kAttribute_TypeModifier))) {
255 this->setWillReadFragmentPosition();
258 virtual bool onIsEqual(const GrProcessor&) const SK_OVERRIDE { return true; }
260 const GrShaderVar& fInRectEdge;
261 const GrShaderVar& fInWidthHeight;
263 GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
265 typedef GrGeometryProcessor INHERITED;
269 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrRectEffect);
271 GrGeometryProcessor* GrRectEffect::TestCreate(SkRandom* random,
273 const GrDrawTargetCaps&,
274 GrTexture* textures[]) {
275 return GrRectEffect::Create();
278 ///////////////////////////////////////////////////////////////////////////////
281 extern const GrVertexAttrib gAARectAttribs[] = {
282 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
283 {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding},
284 {kVec4ub_GrVertexAttribType, sizeof(SkPoint) + sizeof(SkColor), kCoverage_GrVertexAttribBinding},
287 // Should the coverage be multiplied into the color attrib or use a separate attrib.
288 enum CoverageAttribType {
289 kUseColor_CoverageAttribType,
290 kUseCoverage_CoverageAttribType,
294 static CoverageAttribType set_rect_attribs(GrDrawState* drawState) {
295 if (drawState->canTweakAlphaForCoverage()) {
296 drawState->setVertexAttribs<gAARectAttribs>(2, sizeof(SkPoint) + sizeof(SkColor));
297 return kUseColor_CoverageAttribType;
299 drawState->setVertexAttribs<gAARectAttribs>(3, sizeof(SkPoint) + 2 * sizeof(SkColor));
300 return kUseCoverage_CoverageAttribType;
304 static void set_inset_fan(SkPoint* pts, size_t stride,
305 const SkRect& r, SkScalar dx, SkScalar dy) {
306 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
307 r.fRight - dx, r.fBottom - dy, stride);
310 void GrAARectRenderer::reset() {
311 SkSafeSetNull(fAAFillRectIndexBuffer);
312 SkSafeSetNull(fAAMiterStrokeRectIndexBuffer);
313 SkSafeSetNull(fAABevelStrokeRectIndexBuffer);
316 static const uint16_t gFillAARectIdx[] = {
324 static const int kIndicesPerAAFillRect = SK_ARRAY_COUNT(gFillAARectIdx);
325 static const int kVertsPerAAFillRect = 8;
326 static const int kNumAAFillRectsInIndexBuffer = 256;
328 GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
329 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
331 kNumAAFillRectsInIndexBuffer;
333 if (NULL == fAAFillRectIndexBuffer) {
334 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
335 if (fAAFillRectIndexBuffer) {
336 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->map();
337 bool useTempData = (NULL == data);
339 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
341 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
342 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
343 // the inner rect (for AA) and 2 for the inner rect.
344 int baseIdx = i * kIndicesPerAAFillRect;
345 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
346 for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
347 data[baseIdx+j] = baseVert + gFillAARectIdx[j];
351 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
352 SkFAIL("Can't get AA Fill Rect indices into buffer!");
354 SkDELETE_ARRAY(data);
356 fAAFillRectIndexBuffer->unmap();
361 return fAAFillRectIndexBuffer;
364 static const uint16_t gMiterStrokeAARectIdx[] = {
365 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
366 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
367 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
368 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
370 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
371 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
372 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
373 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
375 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
376 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
377 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
378 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
382 * As in miter-stroke, index = a + b, and a is the current index, b is the shift
383 * from the first index. The index layout:
384 * outer AA line: 0~3, 4~7
385 * outer edge: 8~11, 12~15
387 * inner AA line: 20~23
388 * Following comes a bevel-stroke rect and its indices:
391 * *********************************
392 * * ______________________________ *
395 * 0 * |8 16_____________________19 11 | * 3
397 * * | | **************** | | *
398 * * | | * 20 23 * | | *
400 * * | | * 21 22 * | | *
401 * * | | **************** | | *
402 * * | |____________________| | *
403 * 1 * |9 17 18 10| * 2
405 * * \13 __________________________14/ *
407 * **********************************
410 static const uint16_t gBevelStrokeAARectIdx[] = {
411 // Draw outer AA, from outer AA line to outer edge, shift is 0.
412 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
413 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
414 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
415 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
416 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
417 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
418 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
419 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
421 // Draw the stroke, from outer edge to inner edge, shift is 8.
422 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
424 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
425 6 + 8, 2 + 8, 10 + 8,
426 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
427 3 + 8, 7 + 8, 11 + 8,
428 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
431 // Draw the inner AA, from inner edge to inner AA line, shift is 16.
432 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
433 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
434 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
435 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
438 int GrAARectRenderer::aaStrokeRectIndexCount(bool miterStroke) {
439 return miterStroke ? SK_ARRAY_COUNT(gMiterStrokeAARectIdx) :
440 SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
443 GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu, bool miterStroke) {
445 if (NULL == fAAMiterStrokeRectIndexBuffer) {
446 fAAMiterStrokeRectIndexBuffer =
447 gpu->createIndexBuffer(sizeof(gMiterStrokeAARectIdx), false);
448 if (fAAMiterStrokeRectIndexBuffer) {
452 fAAMiterStrokeRectIndexBuffer->updateData(gMiterStrokeAARectIdx,
453 sizeof(gMiterStrokeAARectIdx));
454 GR_DEBUGASSERT(updated);
457 return fAAMiterStrokeRectIndexBuffer;
459 if (NULL == fAABevelStrokeRectIndexBuffer) {
460 fAABevelStrokeRectIndexBuffer =
461 gpu->createIndexBuffer(sizeof(gBevelStrokeAARectIdx), false);
462 if (fAABevelStrokeRectIndexBuffer) {
466 fAABevelStrokeRectIndexBuffer->updateData(gBevelStrokeAARectIdx,
467 sizeof(gBevelStrokeAARectIdx));
468 GR_DEBUGASSERT(updated);
471 return fAABevelStrokeRectIndexBuffer;
475 void GrAARectRenderer::geometryFillAARect(GrGpu* gpu,
476 GrDrawTarget* target,
478 const SkMatrix& combinedMatrix,
479 const SkRect& devRect) {
480 GrDrawState* drawState = target->drawState();
482 GrColor color = drawState->getColor();
484 CoverageAttribType covAttribType = set_rect_attribs(drawState);
485 if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
486 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
489 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
490 if (!geo.succeeded()) {
491 GrPrintf("Failed to get space for vertices!\n");
495 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
496 if (NULL == indexBuffer) {
497 GrPrintf("Failed to create index buffer!\n");
501 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
502 size_t vstride = drawState->getVertexStride();
504 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
505 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
507 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
508 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
510 if (combinedMatrix.rectStaysRect()) {
511 // Temporarily #if'ed out. We don't want to pass in the devRect but
512 // right now it is computed in GrContext::apply_aa_to_rect and we don't
513 // want to throw away the work
516 combinedMatrix.mapRect(&devRect, rect);
519 set_inset_fan(fan0Pos, vstride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
520 set_inset_fan(fan1Pos, vstride, devRect, inset, inset);
522 // compute transformed (1, 0) and (0, 1) vectors
524 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
525 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
529 vec[0].scale(SK_ScalarHalf);
531 vec[1].scale(SK_ScalarHalf);
533 // create the rotated rect
534 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
535 rect.fRight, rect.fBottom, vstride);
536 combinedMatrix.mapPointsWithStride(fan0Pos, vstride, 4);
538 // Now create the inset points and then outset the original
542 *((SkPoint*)((intptr_t)fan1Pos + 0 * vstride)) =
543 *((SkPoint*)((intptr_t)fan0Pos + 0 * vstride)) + vec[0] + vec[1];
544 *((SkPoint*)((intptr_t)fan0Pos + 0 * vstride)) -= vec[0] + vec[1];
546 *((SkPoint*)((intptr_t)fan1Pos + 1 * vstride)) =
547 *((SkPoint*)((intptr_t)fan0Pos + 1 * vstride)) + vec[0] - vec[1];
548 *((SkPoint*)((intptr_t)fan0Pos + 1 * vstride)) -= vec[0] - vec[1];
550 *((SkPoint*)((intptr_t)fan1Pos + 2 * vstride)) =
551 *((SkPoint*)((intptr_t)fan0Pos + 2 * vstride)) - vec[0] - vec[1];
552 *((SkPoint*)((intptr_t)fan0Pos + 2 * vstride)) += vec[0] + vec[1];
554 *((SkPoint*)((intptr_t)fan1Pos + 3 * vstride)) =
555 *((SkPoint*)((intptr_t)fan0Pos + 3 * vstride)) - vec[0] + vec[1];
556 *((SkPoint*)((intptr_t)fan0Pos + 3 * vstride)) += vec[0] - vec[1];
559 // Make verts point to vertex color and then set all the color and coverage vertex attrs values.
560 verts += sizeof(SkPoint);
561 for (int i = 0; i < 4; ++i) {
562 if (kUseCoverage_CoverageAttribType == covAttribType) {
563 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
564 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
566 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
571 if (inset < SK_ScalarHalf) {
572 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
573 SkASSERT(scale >= 0 && scale <= 255);
578 GrColor innerCoverage;
579 if (kUseCoverage_CoverageAttribType == covAttribType) {
580 innerCoverage = GrColorPackRGBA(scale, scale, scale, scale);
582 innerCoverage = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
584 verts += 4 * vstride;
585 for (int i = 0; i < 4; ++i) {
586 if (kUseCoverage_CoverageAttribType == covAttribType) {
587 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
588 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
590 *reinterpret_cast<GrColor*>(verts + i * vstride) = innerCoverage;
594 target->setIndexSourceToBuffer(indexBuffer);
595 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
597 kIndicesPerAAFillRect);
598 target->resetIndexSource();
608 SkPoint fWidthHeight;
612 extern const GrVertexAttrib gAARectVertexAttribs[] = {
613 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
614 { kVec4f_GrVertexAttribType, sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding },
615 { kVec2f_GrVertexAttribType, 3*sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding }
619 struct AARectVertex {
622 SkPoint fWidthHeight;
626 extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
627 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
628 { kVec4f_GrVertexAttribType, sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding },
633 void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
634 GrDrawTarget* target,
636 const SkMatrix& combinedMatrix) {
637 GrDrawState* drawState = target->drawState();
639 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
640 combinedMatrix.mapPoints(¢er, 1);
642 // compute transformed (0, 1) vector
643 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
646 // compute transformed (width, 0) and (0, height) vectors
648 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
649 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
652 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
653 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
654 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs),
657 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
658 if (!geo.succeeded()) {
659 GrPrintf("Failed to get space for vertices!\n");
663 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
665 GrGeometryProcessor* gp = GrRectEffect::Create();
666 drawState->setGeometryProcessor(gp)->unref();
668 for (int i = 0; i < 4; ++i) {
669 verts[i].fCenter = center;
671 verts[i].fWidthHeight.fX = newWidth;
672 verts[i].fWidthHeight.fY = newHeight;
676 combinedMatrix.mapRect(&devRect, rect);
679 devRect.fLeft - SK_ScalarHalf,
680 devRect.fTop - SK_ScalarHalf,
681 devRect.fRight + SK_ScalarHalf,
682 devRect.fBottom + SK_ScalarHalf
685 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
686 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
687 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
688 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
690 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
691 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
692 target->resetIndexSource();
695 void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu,
696 GrDrawTarget* target,
698 const SkMatrix& combinedMatrix) {
699 GrDrawState* drawState = target->drawState();
700 SkASSERT(combinedMatrix.rectStaysRect());
702 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs),
703 sizeof(AARectVertex));
705 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
706 if (!geo.succeeded()) {
707 GrPrintf("Failed to get space for vertices!\n");
711 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
713 GrGeometryProcessor* gp = GrAlignedRectEffect::Create();
714 drawState->setGeometryProcessor(gp)->unref();
717 combinedMatrix.mapRect(&devRect, rect);
720 devRect.fLeft - SK_ScalarHalf,
721 devRect.fTop - SK_ScalarHalf,
722 devRect.fRight + SK_ScalarHalf,
723 devRect.fBottom + SK_ScalarHalf
726 SkPoint widthHeight = {
727 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
728 SkScalarHalf(devRect.height()) + SK_ScalarHalf
731 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
732 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
733 verts[0].fWidthHeight = widthHeight;
735 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
736 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
737 verts[1].fWidthHeight = widthHeight;
739 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
740 verts[2].fOffset = widthHeight;
741 verts[2].fWidthHeight = widthHeight;
743 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
744 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
745 verts[3].fWidthHeight = widthHeight;
747 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
748 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
749 target->resetIndexSource();
752 void GrAARectRenderer::strokeAARect(GrGpu* gpu,
753 GrDrawTarget* target,
755 const SkMatrix& combinedMatrix,
756 const SkRect& devRect,
757 const SkStrokeRec& stroke) {
758 SkVector devStrokeSize;
759 SkScalar width = stroke.getWidth();
761 devStrokeSize.set(width, width);
762 combinedMatrix.mapVectors(&devStrokeSize, 1);
763 devStrokeSize.setAbs(devStrokeSize);
765 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
768 const SkScalar dx = devStrokeSize.fX;
769 const SkScalar dy = devStrokeSize.fY;
770 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
771 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
773 // Temporarily #if'ed out. We don't want to pass in the devRect but
774 // right now it is computed in GrContext::apply_aa_to_rect and we don't
775 // want to throw away the work
778 combinedMatrix.mapRect(&devRect, rect);
783 SkScalar w = devRect.width() - dx;
784 SkScalar h = devRect.height() - dy;
785 spare = SkTMin(w, h);
788 SkRect devOutside(devRect);
789 devOutside.outset(rx, ry);
791 bool miterStroke = true;
792 // For hairlines, make bevel and round joins appear the same as mitered ones.
793 // small miter limit means right angles show bevel...
794 if ((width > 0) && (stroke.getJoin() != SkPaint::kMiter_Join ||
795 stroke.getMiter() < SK_ScalarSqrt2)) {
799 if (spare <= 0 && miterStroke) {
800 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside);
804 SkRect devInside(devRect);
805 devInside.inset(rx, ry);
807 SkRect devOutsideAssist(devRect);
809 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
810 // to draw the outer of the rect. Because there are 8 vertices on the outer
811 // edge, while vertex number of inner edge is 4, the same as miter-stroke.
813 devOutside.inset(0, ry);
814 devOutsideAssist.outset(0, ry);
817 this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist, devInside, miterStroke);
820 void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu,
821 GrDrawTarget* target,
822 const SkRect& devOutside,
823 const SkRect& devOutsideAssist,
824 const SkRect& devInside,
826 GrDrawState* drawState = target->drawState();
828 CoverageAttribType covAttribType = set_rect_attribs(drawState);
830 GrColor color = drawState->getColor();
831 if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
832 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
835 int innerVertexNum = 4;
836 int outerVertexNum = miterStroke ? 4 : 8;
837 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
839 GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, 0);
840 if (!geo.succeeded()) {
841 GrPrintf("Failed to get space for vertices!\n");
844 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu, miterStroke);
845 if (NULL == indexBuffer) {
846 GrPrintf("Failed to create index buffer!\n");
850 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
851 size_t vstride = drawState->getVertexStride();
853 // We create vertices for four nested rectangles. There are two ramps from 0 to full
854 // coverage, one on the exterior of the stroke and the other on the interior.
855 // The following pointers refer to the four rects, from outermost to innermost.
856 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
857 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vstride);
858 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vstride);
859 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vstride);
861 #ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
862 // TODO: this only really works if the X & Y margins are the same all around
864 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
865 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
866 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
868 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
870 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom);
872 SkASSERT(inset >= 0);
874 SkScalar inset = SK_ScalarHalf;
879 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
881 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
882 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
884 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
886 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
887 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + (outerVertexNum + 4) * vstride);
889 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
890 set_inset_fan(fan0AssistPos, vstride, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf);
891 // outer one of the inner two
892 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
893 set_inset_fan(fan1AssistPos, vstride, devOutsideAssist, inset, inset);
894 // inner one of the inner two
895 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
897 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
900 // Make verts point to vertex color and then set all the color and coverage vertex attrs values.
901 // The outermost rect has 0 coverage
902 verts += sizeof(SkPoint);
903 for (int i = 0; i < outerVertexNum; ++i) {
904 if (kUseCoverage_CoverageAttribType == covAttribType) {
905 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
906 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
908 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
912 // scale is the coverage for the the inner two rects.
914 if (inset < SK_ScalarHalf) {
915 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
916 SkASSERT(scale >= 0 && scale <= 255);
921 verts += outerVertexNum * vstride;
922 GrColor innerCoverage;
923 if (kUseCoverage_CoverageAttribType == covAttribType) {
924 innerCoverage = GrColorPackRGBA(scale, scale, scale, scale);
926 innerCoverage = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
929 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
930 if (kUseCoverage_CoverageAttribType == covAttribType) {
931 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
932 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
934 *reinterpret_cast<GrColor*>(verts + i * vstride) = innerCoverage;
938 // The innermost rect has 0 coverage
939 verts += (outerVertexNum + innerVertexNum) * vstride;
940 for (int i = 0; i < innerVertexNum; ++i) {
941 if (kUseCoverage_CoverageAttribType == covAttribType) {
942 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
943 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
945 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
949 target->setIndexSourceToBuffer(indexBuffer);
950 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0,
951 totalVertexNum, aaStrokeRectIndexCount(miterStroke));
954 void GrAARectRenderer::fillAANestedRects(GrGpu* gpu,
955 GrDrawTarget* target,
956 const SkRect rects[2],
957 const SkMatrix& combinedMatrix) {
958 SkASSERT(combinedMatrix.rectStaysRect());
959 SkASSERT(!rects[1].isEmpty());
961 SkRect devOutside, devOutsideAssist, devInside;
962 combinedMatrix.mapRect(&devOutside, rects[0]);
963 // can't call mapRect for devInside since it calls sort
964 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
966 if (devInside.isEmpty()) {
967 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside);
971 this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist, devInside, true);