1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2018 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "src/gpu/ops/QuadPerEdgeAA.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/private/SkVx.h" 11cb93a386Sopenharmony_ci#include "src/gpu/GrMeshDrawTarget.h" 12cb93a386Sopenharmony_ci#include "src/gpu/GrResourceProvider.h" 13cb93a386Sopenharmony_ci#include "src/gpu/SkGr.h" 14cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrQuadUtils.h" 15cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLColorSpaceXformHelper.h" 16cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" 17cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLVarying.h" 18cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h" 19cb93a386Sopenharmony_ci 20cb93a386Sopenharmony_cistatic_assert((int)GrQuadAAFlags::kLeft == SkCanvas::kLeft_QuadAAFlag); 21cb93a386Sopenharmony_cistatic_assert((int)GrQuadAAFlags::kTop == SkCanvas::kTop_QuadAAFlag); 22cb93a386Sopenharmony_cistatic_assert((int)GrQuadAAFlags::kRight == SkCanvas::kRight_QuadAAFlag); 23cb93a386Sopenharmony_cistatic_assert((int)GrQuadAAFlags::kBottom == SkCanvas::kBottom_QuadAAFlag); 24cb93a386Sopenharmony_cistatic_assert((int)GrQuadAAFlags::kNone == SkCanvas::kNone_QuadAAFlags); 25cb93a386Sopenharmony_cistatic_assert((int)GrQuadAAFlags::kAll == SkCanvas::kAll_QuadAAFlags); 26cb93a386Sopenharmony_ci 27cb93a386Sopenharmony_cinamespace skgpu::v1::QuadPerEdgeAA { 28cb93a386Sopenharmony_ci 29cb93a386Sopenharmony_cinamespace { 30cb93a386Sopenharmony_ci 31cb93a386Sopenharmony_ciusing VertexSpec = skgpu::v1::QuadPerEdgeAA::VertexSpec; 32cb93a386Sopenharmony_ciusing CoverageMode = skgpu::v1::QuadPerEdgeAA::CoverageMode; 33cb93a386Sopenharmony_ciusing ColorType = skgpu::v1::QuadPerEdgeAA::ColorType; 34cb93a386Sopenharmony_ci 35cb93a386Sopenharmony_ci// Generic WriteQuadProc that can handle any VertexSpec. It writes the 4 vertices in triangle strip 36cb93a386Sopenharmony_ci// order, although the data per-vertex is dependent on the VertexSpec. 37cb93a386Sopenharmony_civoid write_quad_generic(VertexWriter* vb, 38cb93a386Sopenharmony_ci const VertexSpec& spec, 39cb93a386Sopenharmony_ci const GrQuad* deviceQuad, 40cb93a386Sopenharmony_ci const GrQuad* localQuad, 41cb93a386Sopenharmony_ci const float coverage[4], 42cb93a386Sopenharmony_ci const SkPMColor4f& color, 43cb93a386Sopenharmony_ci const SkRect& geomSubset, 44cb93a386Sopenharmony_ci const SkRect& texSubset) { 45cb93a386Sopenharmony_ci static constexpr auto If = VertexWriter::If<float>; 46cb93a386Sopenharmony_ci 47cb93a386Sopenharmony_ci SkASSERT(!spec.hasLocalCoords() || localQuad); 48cb93a386Sopenharmony_ci 49cb93a386Sopenharmony_ci CoverageMode mode = spec.coverageMode(); 50cb93a386Sopenharmony_ci for (int i = 0; i < 4; ++i) { 51cb93a386Sopenharmony_ci // save position, this is a float2 or float3 or float4 depending on the combination of 52cb93a386Sopenharmony_ci // perspective and coverage mode. 53cb93a386Sopenharmony_ci *vb << deviceQuad->x(i) 54cb93a386Sopenharmony_ci << deviceQuad->y(i) 55cb93a386Sopenharmony_ci << If(spec.deviceQuadType() == GrQuad::Type::kPerspective, deviceQuad->w(i)) 56cb93a386Sopenharmony_ci << If(mode == CoverageMode::kWithPosition, coverage[i]); 57cb93a386Sopenharmony_ci 58cb93a386Sopenharmony_ci // save color 59cb93a386Sopenharmony_ci if (spec.hasVertexColors()) { 60cb93a386Sopenharmony_ci bool wide = spec.colorType() == ColorType::kFloat; 61cb93a386Sopenharmony_ci *vb << GrVertexColor(color * (mode == CoverageMode::kWithColor ? coverage[i] : 1.f), 62cb93a386Sopenharmony_ci wide); 63cb93a386Sopenharmony_ci } 64cb93a386Sopenharmony_ci 65cb93a386Sopenharmony_ci // save local position 66cb93a386Sopenharmony_ci if (spec.hasLocalCoords()) { 67cb93a386Sopenharmony_ci *vb << localQuad->x(i) 68cb93a386Sopenharmony_ci << localQuad->y(i) 69cb93a386Sopenharmony_ci << If(spec.localQuadType() == GrQuad::Type::kPerspective, localQuad->w(i)); 70cb93a386Sopenharmony_ci } 71cb93a386Sopenharmony_ci 72cb93a386Sopenharmony_ci // save the geometry subset 73cb93a386Sopenharmony_ci if (spec.requiresGeometrySubset()) { 74cb93a386Sopenharmony_ci *vb << geomSubset; 75cb93a386Sopenharmony_ci } 76cb93a386Sopenharmony_ci 77cb93a386Sopenharmony_ci // save the texture subset 78cb93a386Sopenharmony_ci if (spec.hasSubset()) { 79cb93a386Sopenharmony_ci *vb << texSubset; 80cb93a386Sopenharmony_ci } 81cb93a386Sopenharmony_ci } 82cb93a386Sopenharmony_ci} 83cb93a386Sopenharmony_ci 84cb93a386Sopenharmony_ci// Specialized WriteQuadProcs for particular VertexSpecs that show up frequently (determined 85cb93a386Sopenharmony_ci// experimentally through recorded GMs, SKPs, and SVGs, as well as SkiaRenderer's usage patterns): 86cb93a386Sopenharmony_ci 87cb93a386Sopenharmony_ci// 2D (XY), no explicit coverage, vertex color, no locals, no geometry subset, no texture subsetn 88cb93a386Sopenharmony_ci// This represents simple, solid color or shader, non-AA (or AA with cov. as alpha) rects. 89cb93a386Sopenharmony_civoid write_2d_color(VertexWriter* vb, 90cb93a386Sopenharmony_ci const VertexSpec& spec, 91cb93a386Sopenharmony_ci const GrQuad* deviceQuad, 92cb93a386Sopenharmony_ci const GrQuad* localQuad, 93cb93a386Sopenharmony_ci const float coverage[4], 94cb93a386Sopenharmony_ci const SkPMColor4f& color, 95cb93a386Sopenharmony_ci const SkRect& geomSubset, 96cb93a386Sopenharmony_ci const SkRect& texSubset) { 97cb93a386Sopenharmony_ci // Assert assumptions about VertexSpec 98cb93a386Sopenharmony_ci SkASSERT(spec.deviceQuadType() != GrQuad::Type::kPerspective); 99cb93a386Sopenharmony_ci SkASSERT(!spec.hasLocalCoords()); 100cb93a386Sopenharmony_ci SkASSERT(spec.coverageMode() == CoverageMode::kNone || 101cb93a386Sopenharmony_ci spec.coverageMode() == CoverageMode::kWithColor); 102cb93a386Sopenharmony_ci SkASSERT(spec.hasVertexColors()); 103cb93a386Sopenharmony_ci SkASSERT(!spec.requiresGeometrySubset()); 104cb93a386Sopenharmony_ci SkASSERT(!spec.hasSubset()); 105cb93a386Sopenharmony_ci // We don't assert that localQuad == nullptr, since it is possible for FillRectOp to 106cb93a386Sopenharmony_ci // accumulate local coords conservatively (paint not trivial), and then after analysis realize 107cb93a386Sopenharmony_ci // the processors don't need local coordinates. 108cb93a386Sopenharmony_ci 109cb93a386Sopenharmony_ci bool wide = spec.colorType() == ColorType::kFloat; 110cb93a386Sopenharmony_ci for (int i = 0; i < 4; ++i) { 111cb93a386Sopenharmony_ci // If this is not coverage-with-alpha, make sure coverage == 1 so it doesn't do anything 112cb93a386Sopenharmony_ci SkASSERT(spec.coverageMode() == CoverageMode::kWithColor || coverage[i] == 1.f); 113cb93a386Sopenharmony_ci *vb << deviceQuad->x(i) 114cb93a386Sopenharmony_ci << deviceQuad->y(i) 115cb93a386Sopenharmony_ci << GrVertexColor(color * coverage[i], wide); 116cb93a386Sopenharmony_ci } 117cb93a386Sopenharmony_ci} 118cb93a386Sopenharmony_ci 119cb93a386Sopenharmony_ci// 2D (XY), no explicit coverage, UV locals, no color, no geometry subset, no texture subset 120cb93a386Sopenharmony_ci// This represents opaque, non AA, textured rects 121cb93a386Sopenharmony_civoid write_2d_uv(VertexWriter* vb, 122cb93a386Sopenharmony_ci const VertexSpec& spec, 123cb93a386Sopenharmony_ci const GrQuad* deviceQuad, 124cb93a386Sopenharmony_ci const GrQuad* localQuad, 125cb93a386Sopenharmony_ci const float coverage[4], 126cb93a386Sopenharmony_ci const SkPMColor4f& color, 127cb93a386Sopenharmony_ci const SkRect& geomSubset, 128cb93a386Sopenharmony_ci const SkRect& texSubset) { 129cb93a386Sopenharmony_ci // Assert assumptions about VertexSpec 130cb93a386Sopenharmony_ci SkASSERT(spec.deviceQuadType() != GrQuad::Type::kPerspective); 131cb93a386Sopenharmony_ci SkASSERT(spec.hasLocalCoords() && spec.localQuadType() != GrQuad::Type::kPerspective); 132cb93a386Sopenharmony_ci SkASSERT(spec.coverageMode() == CoverageMode::kNone); 133cb93a386Sopenharmony_ci SkASSERT(!spec.hasVertexColors()); 134cb93a386Sopenharmony_ci SkASSERT(!spec.requiresGeometrySubset()); 135cb93a386Sopenharmony_ci SkASSERT(!spec.hasSubset()); 136cb93a386Sopenharmony_ci SkASSERT(localQuad); 137cb93a386Sopenharmony_ci 138cb93a386Sopenharmony_ci for (int i = 0; i < 4; ++i) { 139cb93a386Sopenharmony_ci *vb << deviceQuad->x(i) 140cb93a386Sopenharmony_ci << deviceQuad->y(i) 141cb93a386Sopenharmony_ci << localQuad->x(i) 142cb93a386Sopenharmony_ci << localQuad->y(i); 143cb93a386Sopenharmony_ci } 144cb93a386Sopenharmony_ci} 145cb93a386Sopenharmony_ci 146cb93a386Sopenharmony_ci// 2D (XY), no explicit coverage, UV locals, vertex color, no geometry or texture subsets 147cb93a386Sopenharmony_ci// This represents transparent, non AA (or AA with cov. as alpha), textured rects 148cb93a386Sopenharmony_civoid write_2d_color_uv(VertexWriter* vb, 149cb93a386Sopenharmony_ci const VertexSpec& spec, 150cb93a386Sopenharmony_ci const GrQuad* deviceQuad, 151cb93a386Sopenharmony_ci const GrQuad* localQuad, 152cb93a386Sopenharmony_ci const float coverage[4], 153cb93a386Sopenharmony_ci const SkPMColor4f& color, 154cb93a386Sopenharmony_ci const SkRect& geomSubset, 155cb93a386Sopenharmony_ci const SkRect& texSubset) { 156cb93a386Sopenharmony_ci // Assert assumptions about VertexSpec 157cb93a386Sopenharmony_ci SkASSERT(spec.deviceQuadType() != GrQuad::Type::kPerspective); 158cb93a386Sopenharmony_ci SkASSERT(spec.hasLocalCoords() && spec.localQuadType() != GrQuad::Type::kPerspective); 159cb93a386Sopenharmony_ci SkASSERT(spec.coverageMode() == CoverageMode::kNone || 160cb93a386Sopenharmony_ci spec.coverageMode() == CoverageMode::kWithColor); 161cb93a386Sopenharmony_ci SkASSERT(spec.hasVertexColors()); 162cb93a386Sopenharmony_ci SkASSERT(!spec.requiresGeometrySubset()); 163cb93a386Sopenharmony_ci SkASSERT(!spec.hasSubset()); 164cb93a386Sopenharmony_ci SkASSERT(localQuad); 165cb93a386Sopenharmony_ci 166cb93a386Sopenharmony_ci bool wide = spec.colorType() == ColorType::kFloat; 167cb93a386Sopenharmony_ci for (int i = 0; i < 4; ++i) { 168cb93a386Sopenharmony_ci // If this is not coverage-with-alpha, make sure coverage == 1 so it doesn't do anything 169cb93a386Sopenharmony_ci SkASSERT(spec.coverageMode() == CoverageMode::kWithColor || coverage[i] == 1.f); 170cb93a386Sopenharmony_ci *vb << deviceQuad->x(i) 171cb93a386Sopenharmony_ci << deviceQuad->y(i) 172cb93a386Sopenharmony_ci << GrVertexColor(color * coverage[i], wide) 173cb93a386Sopenharmony_ci << localQuad->x(i) 174cb93a386Sopenharmony_ci << localQuad->y(i); 175cb93a386Sopenharmony_ci } 176cb93a386Sopenharmony_ci} 177cb93a386Sopenharmony_ci 178cb93a386Sopenharmony_ci// 2D (XY), explicit coverage, UV locals, no color, no geometry subset, no texture subset 179cb93a386Sopenharmony_ci// This represents opaque, AA, textured rects 180cb93a386Sopenharmony_civoid write_2d_cov_uv(VertexWriter* vb, 181cb93a386Sopenharmony_ci const VertexSpec& spec, 182cb93a386Sopenharmony_ci const GrQuad* deviceQuad, 183cb93a386Sopenharmony_ci const GrQuad* localQuad, 184cb93a386Sopenharmony_ci const float coverage[4], 185cb93a386Sopenharmony_ci const SkPMColor4f& color, 186cb93a386Sopenharmony_ci const SkRect& geomSubset, 187cb93a386Sopenharmony_ci const SkRect& texSubset) { 188cb93a386Sopenharmony_ci // Assert assumptions about VertexSpec 189cb93a386Sopenharmony_ci SkASSERT(spec.deviceQuadType() != GrQuad::Type::kPerspective); 190cb93a386Sopenharmony_ci SkASSERT(spec.hasLocalCoords() && spec.localQuadType() != GrQuad::Type::kPerspective); 191cb93a386Sopenharmony_ci SkASSERT(spec.coverageMode() == CoverageMode::kWithPosition); 192cb93a386Sopenharmony_ci SkASSERT(!spec.hasVertexColors()); 193cb93a386Sopenharmony_ci SkASSERT(!spec.requiresGeometrySubset()); 194cb93a386Sopenharmony_ci SkASSERT(!spec.hasSubset()); 195cb93a386Sopenharmony_ci SkASSERT(localQuad); 196cb93a386Sopenharmony_ci 197cb93a386Sopenharmony_ci for (int i = 0; i < 4; ++i) { 198cb93a386Sopenharmony_ci *vb << deviceQuad->x(i) 199cb93a386Sopenharmony_ci << deviceQuad->y(i) 200cb93a386Sopenharmony_ci << coverage[i] 201cb93a386Sopenharmony_ci << localQuad->x(i) 202cb93a386Sopenharmony_ci << localQuad->y(i); 203cb93a386Sopenharmony_ci } 204cb93a386Sopenharmony_ci} 205cb93a386Sopenharmony_ci 206cb93a386Sopenharmony_ci// NOTE: The three _strict specializations below match the non-strict uv functions above, except 207cb93a386Sopenharmony_ci// that they also write the UV subset. These are included to benefit SkiaRenderer, which must make 208cb93a386Sopenharmony_ci// use of both fast and strict constrained subsets. When testing _strict was not that common across 209cb93a386Sopenharmony_ci// GMS, SKPs, and SVGs but we have little visibility into actual SkiaRenderer statistics. If 210cb93a386Sopenharmony_ci// SkiaRenderer can avoid subsets more, these 3 functions should probably be removed for simplicity. 211cb93a386Sopenharmony_ci 212cb93a386Sopenharmony_ci// 2D (XY), no explicit coverage, UV locals, no color, tex subset but no geometry subset 213cb93a386Sopenharmony_ci// This represents opaque, non AA, textured rects with strict uv sampling 214cb93a386Sopenharmony_civoid write_2d_uv_strict(VertexWriter* vb, 215cb93a386Sopenharmony_ci const VertexSpec& spec, 216cb93a386Sopenharmony_ci const GrQuad* deviceQuad, 217cb93a386Sopenharmony_ci const GrQuad* localQuad, 218cb93a386Sopenharmony_ci const float coverage[4], 219cb93a386Sopenharmony_ci const SkPMColor4f& color, 220cb93a386Sopenharmony_ci const SkRect& geomSubset, 221cb93a386Sopenharmony_ci const SkRect& texSubset) { 222cb93a386Sopenharmony_ci // Assert assumptions about VertexSpec 223cb93a386Sopenharmony_ci SkASSERT(spec.deviceQuadType() != GrQuad::Type::kPerspective); 224cb93a386Sopenharmony_ci SkASSERT(spec.hasLocalCoords() && spec.localQuadType() != GrQuad::Type::kPerspective); 225cb93a386Sopenharmony_ci SkASSERT(spec.coverageMode() == CoverageMode::kNone); 226cb93a386Sopenharmony_ci SkASSERT(!spec.hasVertexColors()); 227cb93a386Sopenharmony_ci SkASSERT(!spec.requiresGeometrySubset()); 228cb93a386Sopenharmony_ci SkASSERT(spec.hasSubset()); 229cb93a386Sopenharmony_ci SkASSERT(localQuad); 230cb93a386Sopenharmony_ci 231cb93a386Sopenharmony_ci for (int i = 0; i < 4; ++i) { 232cb93a386Sopenharmony_ci *vb << deviceQuad->x(i) 233cb93a386Sopenharmony_ci << deviceQuad->y(i) 234cb93a386Sopenharmony_ci << localQuad->x(i) 235cb93a386Sopenharmony_ci << localQuad->y(i) 236cb93a386Sopenharmony_ci << texSubset; 237cb93a386Sopenharmony_ci } 238cb93a386Sopenharmony_ci} 239cb93a386Sopenharmony_ci 240cb93a386Sopenharmony_ci// 2D (XY), no explicit coverage, UV locals, vertex color, tex subset but no geometry subset 241cb93a386Sopenharmony_ci// This represents transparent, non AA (or AA with cov. as alpha), textured rects with strict sample 242cb93a386Sopenharmony_civoid write_2d_color_uv_strict(VertexWriter* vb, 243cb93a386Sopenharmony_ci const VertexSpec& spec, 244cb93a386Sopenharmony_ci const GrQuad* deviceQuad, 245cb93a386Sopenharmony_ci const GrQuad* localQuad, 246cb93a386Sopenharmony_ci const float coverage[4], 247cb93a386Sopenharmony_ci const SkPMColor4f& color, 248cb93a386Sopenharmony_ci const SkRect& geomSubset, 249cb93a386Sopenharmony_ci const SkRect& texSubset) { 250cb93a386Sopenharmony_ci // Assert assumptions about VertexSpec 251cb93a386Sopenharmony_ci SkASSERT(spec.deviceQuadType() != GrQuad::Type::kPerspective); 252cb93a386Sopenharmony_ci SkASSERT(spec.hasLocalCoords() && spec.localQuadType() != GrQuad::Type::kPerspective); 253cb93a386Sopenharmony_ci SkASSERT(spec.coverageMode() == CoverageMode::kNone || 254cb93a386Sopenharmony_ci spec.coverageMode() == CoverageMode::kWithColor); 255cb93a386Sopenharmony_ci SkASSERT(spec.hasVertexColors()); 256cb93a386Sopenharmony_ci SkASSERT(!spec.requiresGeometrySubset()); 257cb93a386Sopenharmony_ci SkASSERT(spec.hasSubset()); 258cb93a386Sopenharmony_ci SkASSERT(localQuad); 259cb93a386Sopenharmony_ci 260cb93a386Sopenharmony_ci bool wide = spec.colorType() == ColorType::kFloat; 261cb93a386Sopenharmony_ci for (int i = 0; i < 4; ++i) { 262cb93a386Sopenharmony_ci // If this is not coverage-with-alpha, make sure coverage == 1 so it doesn't do anything 263cb93a386Sopenharmony_ci SkASSERT(spec.coverageMode() == CoverageMode::kWithColor || coverage[i] == 1.f); 264cb93a386Sopenharmony_ci *vb << deviceQuad->x(i) 265cb93a386Sopenharmony_ci << deviceQuad->y(i) 266cb93a386Sopenharmony_ci << GrVertexColor(color * coverage[i], wide) 267cb93a386Sopenharmony_ci << localQuad->x(i) 268cb93a386Sopenharmony_ci << localQuad->y(i) 269cb93a386Sopenharmony_ci << texSubset; 270cb93a386Sopenharmony_ci } 271cb93a386Sopenharmony_ci} 272cb93a386Sopenharmony_ci 273cb93a386Sopenharmony_ci// 2D (XY), explicit coverage, UV locals, no color, tex subset but no geometry subset 274cb93a386Sopenharmony_ci// This represents opaque, AA, textured rects with strict uv sampling 275cb93a386Sopenharmony_civoid write_2d_cov_uv_strict(VertexWriter* vb, 276cb93a386Sopenharmony_ci const VertexSpec& spec, 277cb93a386Sopenharmony_ci const GrQuad* deviceQuad, 278cb93a386Sopenharmony_ci const GrQuad* localQuad, 279cb93a386Sopenharmony_ci const float coverage[4], 280cb93a386Sopenharmony_ci const SkPMColor4f& color, 281cb93a386Sopenharmony_ci const SkRect& geomSubset, 282cb93a386Sopenharmony_ci const SkRect& texSubset) { 283cb93a386Sopenharmony_ci // Assert assumptions about VertexSpec 284cb93a386Sopenharmony_ci SkASSERT(spec.deviceQuadType() != GrQuad::Type::kPerspective); 285cb93a386Sopenharmony_ci SkASSERT(spec.hasLocalCoords() && spec.localQuadType() != GrQuad::Type::kPerspective); 286cb93a386Sopenharmony_ci SkASSERT(spec.coverageMode() == CoverageMode::kWithPosition); 287cb93a386Sopenharmony_ci SkASSERT(!spec.hasVertexColors()); 288cb93a386Sopenharmony_ci SkASSERT(!spec.requiresGeometrySubset()); 289cb93a386Sopenharmony_ci SkASSERT(spec.hasSubset()); 290cb93a386Sopenharmony_ci SkASSERT(localQuad); 291cb93a386Sopenharmony_ci 292cb93a386Sopenharmony_ci for (int i = 0; i < 4; ++i) { 293cb93a386Sopenharmony_ci *vb << deviceQuad->x(i) 294cb93a386Sopenharmony_ci << deviceQuad->y(i) 295cb93a386Sopenharmony_ci << coverage[i] 296cb93a386Sopenharmony_ci << localQuad->x(i) 297cb93a386Sopenharmony_ci << localQuad->y(i) 298cb93a386Sopenharmony_ci << texSubset; 299cb93a386Sopenharmony_ci } 300cb93a386Sopenharmony_ci} 301cb93a386Sopenharmony_ci 302cb93a386Sopenharmony_ci} // anonymous namespace 303cb93a386Sopenharmony_ci 304cb93a386Sopenharmony_ciIndexBufferOption CalcIndexBufferOption(GrAAType aa, int numQuads) { 305cb93a386Sopenharmony_ci if (aa == GrAAType::kCoverage) { 306cb93a386Sopenharmony_ci return IndexBufferOption::kPictureFramed; 307cb93a386Sopenharmony_ci } else if (numQuads > 1) { 308cb93a386Sopenharmony_ci return IndexBufferOption::kIndexedRects; 309cb93a386Sopenharmony_ci } else { 310cb93a386Sopenharmony_ci return IndexBufferOption::kTriStrips; 311cb93a386Sopenharmony_ci } 312cb93a386Sopenharmony_ci} 313cb93a386Sopenharmony_ci 314cb93a386Sopenharmony_ci// This is a more elaborate version of fitsInBytes() that allows "no color" for white 315cb93a386Sopenharmony_ciColorType MinColorType(SkPMColor4f color) { 316cb93a386Sopenharmony_ci if (color == SK_PMColor4fWHITE) { 317cb93a386Sopenharmony_ci return ColorType::kNone; 318cb93a386Sopenharmony_ci } else { 319cb93a386Sopenharmony_ci return color.fitsInBytes() ? ColorType::kByte : ColorType::kFloat; 320cb93a386Sopenharmony_ci } 321cb93a386Sopenharmony_ci} 322cb93a386Sopenharmony_ci 323cb93a386Sopenharmony_ci////////////////// Tessellator Implementation 324cb93a386Sopenharmony_ci 325cb93a386Sopenharmony_ciTessellator::WriteQuadProc Tessellator::GetWriteQuadProc(const VertexSpec& spec) { 326cb93a386Sopenharmony_ci // All specialized writing functions requires 2D geometry and no geometry subset. This is not 327cb93a386Sopenharmony_ci // the same as just checking device type vs. kRectilinear since non-AA general 2D quads do not 328cb93a386Sopenharmony_ci // require a geometry subset and could then go through a fast path. 329cb93a386Sopenharmony_ci if (spec.deviceQuadType() != GrQuad::Type::kPerspective && !spec.requiresGeometrySubset()) { 330cb93a386Sopenharmony_ci CoverageMode mode = spec.coverageMode(); 331cb93a386Sopenharmony_ci if (spec.hasVertexColors()) { 332cb93a386Sopenharmony_ci if (mode != CoverageMode::kWithPosition) { 333cb93a386Sopenharmony_ci // Vertex colors, but no explicit coverage 334cb93a386Sopenharmony_ci if (!spec.hasLocalCoords()) { 335cb93a386Sopenharmony_ci // Non-UV with vertex colors (possibly with coverage folded into alpha) 336cb93a386Sopenharmony_ci return write_2d_color; 337cb93a386Sopenharmony_ci } else if (spec.localQuadType() != GrQuad::Type::kPerspective) { 338cb93a386Sopenharmony_ci // UV locals with vertex colors (possibly with coverage-as-alpha) 339cb93a386Sopenharmony_ci return spec.hasSubset() ? write_2d_color_uv_strict : write_2d_color_uv; 340cb93a386Sopenharmony_ci } 341cb93a386Sopenharmony_ci } 342cb93a386Sopenharmony_ci // Else fall through; this is a spec that requires vertex colors and explicit coverage, 343cb93a386Sopenharmony_ci // which means it's anti-aliased and the FPs don't support coverage as alpha, or 344cb93a386Sopenharmony_ci // it uses 3D local coordinates. 345cb93a386Sopenharmony_ci } else if (spec.hasLocalCoords() && spec.localQuadType() != GrQuad::Type::kPerspective) { 346cb93a386Sopenharmony_ci if (mode == CoverageMode::kWithPosition) { 347cb93a386Sopenharmony_ci // UV locals with explicit coverage 348cb93a386Sopenharmony_ci return spec.hasSubset() ? write_2d_cov_uv_strict : write_2d_cov_uv; 349cb93a386Sopenharmony_ci } else { 350cb93a386Sopenharmony_ci SkASSERT(mode == CoverageMode::kNone); 351cb93a386Sopenharmony_ci return spec.hasSubset() ? write_2d_uv_strict : write_2d_uv; 352cb93a386Sopenharmony_ci } 353cb93a386Sopenharmony_ci } 354cb93a386Sopenharmony_ci // Else fall through to generic vertex function; this is a spec that has no vertex colors 355cb93a386Sopenharmony_ci // and [no|uvr] local coords, which doesn't happen often enough to warrant specialization. 356cb93a386Sopenharmony_ci } 357cb93a386Sopenharmony_ci 358cb93a386Sopenharmony_ci // Arbitrary spec hits the slow path 359cb93a386Sopenharmony_ci return write_quad_generic; 360cb93a386Sopenharmony_ci} 361cb93a386Sopenharmony_ci 362cb93a386Sopenharmony_ciTessellator::Tessellator(const VertexSpec& spec, char* vertices) 363cb93a386Sopenharmony_ci : fVertexSpec(spec) 364cb93a386Sopenharmony_ci , fVertexWriter{vertices} 365cb93a386Sopenharmony_ci , fWriteProc(Tessellator::GetWriteQuadProc(spec)) {} 366cb93a386Sopenharmony_ci 367cb93a386Sopenharmony_civoid Tessellator::append(GrQuad* deviceQuad, GrQuad* localQuad, 368cb93a386Sopenharmony_ci const SkPMColor4f& color, const SkRect& uvSubset, GrQuadAAFlags aaFlags) { 369cb93a386Sopenharmony_ci // We allow Tessellator to be created with a null vertices pointer for convenience, but it is 370cb93a386Sopenharmony_ci // assumed it will never actually be used in those cases. 371cb93a386Sopenharmony_ci SkASSERT(fVertexWriter); 372cb93a386Sopenharmony_ci SkASSERT(deviceQuad->quadType() <= fVertexSpec.deviceQuadType()); 373cb93a386Sopenharmony_ci SkASSERT(localQuad || !fVertexSpec.hasLocalCoords()); 374cb93a386Sopenharmony_ci SkASSERT(!fVertexSpec.hasLocalCoords() || localQuad->quadType() <= fVertexSpec.localQuadType()); 375cb93a386Sopenharmony_ci 376cb93a386Sopenharmony_ci static const float kFullCoverage[4] = {1.f, 1.f, 1.f, 1.f}; 377cb93a386Sopenharmony_ci static const float kZeroCoverage[4] = {0.f, 0.f, 0.f, 0.f}; 378cb93a386Sopenharmony_ci static const SkRect kIgnoredSubset = SkRect::MakeEmpty(); 379cb93a386Sopenharmony_ci 380cb93a386Sopenharmony_ci if (fVertexSpec.usesCoverageAA()) { 381cb93a386Sopenharmony_ci SkASSERT(fVertexSpec.coverageMode() == CoverageMode::kWithColor || 382cb93a386Sopenharmony_ci fVertexSpec.coverageMode() == CoverageMode::kWithPosition); 383cb93a386Sopenharmony_ci // Must calculate inner and outer quadrilaterals for the vertex coverage ramps, and possibly 384cb93a386Sopenharmony_ci // a geometry subset if corners are not right angles 385cb93a386Sopenharmony_ci SkRect geomSubset; 386cb93a386Sopenharmony_ci if (fVertexSpec.requiresGeometrySubset()) { 387cb93a386Sopenharmony_ci#ifdef SK_USE_LEGACY_AA_QUAD_SUBSET 388cb93a386Sopenharmony_ci geomSubset = deviceQuad->bounds(); 389cb93a386Sopenharmony_ci geomSubset.outset(0.5f, 0.5f); // account for AA expansion 390cb93a386Sopenharmony_ci#else 391cb93a386Sopenharmony_ci // Our GP code expects a 0.5 outset rect (coverage is computed as 0 at the values of 392cb93a386Sopenharmony_ci // the uniform). However, if we have quad edges that aren't supposed to be antialiased 393cb93a386Sopenharmony_ci // they may lie close to the bounds. So in that case we outset by an additional 0.5. 394cb93a386Sopenharmony_ci // This is a sort of backup clipping mechanism for cases where quad outsetting of nearly 395cb93a386Sopenharmony_ci // parallel edges produces long thin extrusions from the original geometry. 396cb93a386Sopenharmony_ci float outset = aaFlags == GrQuadAAFlags::kAll ? 0.5f : 1.f; 397cb93a386Sopenharmony_ci geomSubset = deviceQuad->bounds().makeOutset(outset, outset); 398cb93a386Sopenharmony_ci#endif 399cb93a386Sopenharmony_ci } 400cb93a386Sopenharmony_ci 401cb93a386Sopenharmony_ci if (aaFlags == GrQuadAAFlags::kNone) { 402cb93a386Sopenharmony_ci // Have to write the coverage AA vertex structure, but there's no math to be done for a 403cb93a386Sopenharmony_ci // non-aa quad batched into a coverage AA op. 404cb93a386Sopenharmony_ci fWriteProc(&fVertexWriter, fVertexSpec, deviceQuad, localQuad, kFullCoverage, color, 405cb93a386Sopenharmony_ci geomSubset, uvSubset); 406cb93a386Sopenharmony_ci // Since we pass the same corners in, the outer vertex structure will have 0 area and 407cb93a386Sopenharmony_ci // the coverage interpolation from 1 to 0 will not be visible. 408cb93a386Sopenharmony_ci fWriteProc(&fVertexWriter, fVertexSpec, deviceQuad, localQuad, kZeroCoverage, color, 409cb93a386Sopenharmony_ci geomSubset, uvSubset); 410cb93a386Sopenharmony_ci } else { 411cb93a386Sopenharmony_ci // Reset the tessellation helper to match the current geometry 412cb93a386Sopenharmony_ci fAAHelper.reset(*deviceQuad, localQuad); 413cb93a386Sopenharmony_ci 414cb93a386Sopenharmony_ci // Edge inset/outset distance ordered LBTR, set to 0.5 for a half pixel if the AA flag 415cb93a386Sopenharmony_ci // is turned on, or 0.0 if the edge is not anti-aliased. 416cb93a386Sopenharmony_ci skvx::Vec<4, float> edgeDistances; 417cb93a386Sopenharmony_ci if (aaFlags == GrQuadAAFlags::kAll) { 418cb93a386Sopenharmony_ci edgeDistances = 0.5f; 419cb93a386Sopenharmony_ci } else { 420cb93a386Sopenharmony_ci edgeDistances = { (aaFlags & GrQuadAAFlags::kLeft) ? 0.5f : 0.f, 421cb93a386Sopenharmony_ci (aaFlags & GrQuadAAFlags::kBottom) ? 0.5f : 0.f, 422cb93a386Sopenharmony_ci (aaFlags & GrQuadAAFlags::kTop) ? 0.5f : 0.f, 423cb93a386Sopenharmony_ci (aaFlags & GrQuadAAFlags::kRight) ? 0.5f : 0.f }; 424cb93a386Sopenharmony_ci } 425cb93a386Sopenharmony_ci 426cb93a386Sopenharmony_ci // Write inner vertices first 427cb93a386Sopenharmony_ci float coverage[4]; 428cb93a386Sopenharmony_ci fAAHelper.inset(edgeDistances, deviceQuad, localQuad).store(coverage); 429cb93a386Sopenharmony_ci fWriteProc(&fVertexWriter, fVertexSpec, deviceQuad, localQuad, coverage, color, 430cb93a386Sopenharmony_ci geomSubset, uvSubset); 431cb93a386Sopenharmony_ci 432cb93a386Sopenharmony_ci // Then outer vertices, which use 0.f for their coverage. If the inset was degenerate 433cb93a386Sopenharmony_ci // to a line (had all coverages < 1), tweak the outset distance so the outer frame's 434cb93a386Sopenharmony_ci // narrow axis reaches out to 2px, which gives better animation under translation. 435cb93a386Sopenharmony_ci const bool hairline = aaFlags == GrQuadAAFlags::kAll && 436cb93a386Sopenharmony_ci coverage[0] < 1.f && 437cb93a386Sopenharmony_ci coverage[1] < 1.f && 438cb93a386Sopenharmony_ci coverage[2] < 1.f && 439cb93a386Sopenharmony_ci coverage[3] < 1.f; 440cb93a386Sopenharmony_ci if (hairline) { 441cb93a386Sopenharmony_ci skvx::Vec<4, float> len = fAAHelper.getEdgeLengths(); 442cb93a386Sopenharmony_ci // Using max guards us against trying to scale a degenerate triangle edge of 0 len 443cb93a386Sopenharmony_ci // up to 2px. The shuffles are so that edge 0's adjustment is based on the lengths 444cb93a386Sopenharmony_ci // of its connecting edges (1 and 2), and so forth. 445cb93a386Sopenharmony_ci skvx::Vec<4, float> maxWH = max(skvx::shuffle<1, 0, 3, 2>(len), 446cb93a386Sopenharmony_ci skvx::shuffle<2, 3, 0, 1>(len)); 447cb93a386Sopenharmony_ci // wh + 2e' = 2, so e' = (2 - wh) / 2 => e' = e * (2 - wh). But if w or h > 1, then 448cb93a386Sopenharmony_ci // 2 - wh < 1 and represents the non-narrow axis so clamp to 1. 449cb93a386Sopenharmony_ci edgeDistances *= max(1.f, 2.f - maxWH); 450cb93a386Sopenharmony_ci } 451cb93a386Sopenharmony_ci fAAHelper.outset(edgeDistances, deviceQuad, localQuad); 452cb93a386Sopenharmony_ci fWriteProc(&fVertexWriter, fVertexSpec, deviceQuad, localQuad, kZeroCoverage, color, 453cb93a386Sopenharmony_ci geomSubset, uvSubset); 454cb93a386Sopenharmony_ci } 455cb93a386Sopenharmony_ci } else { 456cb93a386Sopenharmony_ci // No outsetting needed, just write a single quad with full coverage 457cb93a386Sopenharmony_ci SkASSERT(fVertexSpec.coverageMode() == CoverageMode::kNone && 458cb93a386Sopenharmony_ci !fVertexSpec.requiresGeometrySubset()); 459cb93a386Sopenharmony_ci fWriteProc(&fVertexWriter, fVertexSpec, deviceQuad, localQuad, kFullCoverage, color, 460cb93a386Sopenharmony_ci kIgnoredSubset, uvSubset); 461cb93a386Sopenharmony_ci } 462cb93a386Sopenharmony_ci} 463cb93a386Sopenharmony_ci 464cb93a386Sopenharmony_cisk_sp<const GrBuffer> GetIndexBuffer(GrMeshDrawTarget* target, 465cb93a386Sopenharmony_ci IndexBufferOption indexBufferOption) { 466cb93a386Sopenharmony_ci auto resourceProvider = target->resourceProvider(); 467cb93a386Sopenharmony_ci 468cb93a386Sopenharmony_ci switch (indexBufferOption) { 469cb93a386Sopenharmony_ci case IndexBufferOption::kPictureFramed: return resourceProvider->refAAQuadIndexBuffer(); 470cb93a386Sopenharmony_ci case IndexBufferOption::kIndexedRects: return resourceProvider->refNonAAQuadIndexBuffer(); 471cb93a386Sopenharmony_ci case IndexBufferOption::kTriStrips: // fall through 472cb93a386Sopenharmony_ci default: return nullptr; 473cb93a386Sopenharmony_ci } 474cb93a386Sopenharmony_ci} 475cb93a386Sopenharmony_ci 476cb93a386Sopenharmony_ciint QuadLimit(IndexBufferOption option) { 477cb93a386Sopenharmony_ci switch (option) { 478cb93a386Sopenharmony_ci case IndexBufferOption::kPictureFramed: return GrResourceProvider::MaxNumAAQuads(); 479cb93a386Sopenharmony_ci case IndexBufferOption::kIndexedRects: return GrResourceProvider::MaxNumNonAAQuads(); 480cb93a386Sopenharmony_ci case IndexBufferOption::kTriStrips: return SK_MaxS32; // not limited by an indexBuffer 481cb93a386Sopenharmony_ci } 482cb93a386Sopenharmony_ci 483cb93a386Sopenharmony_ci SkUNREACHABLE; 484cb93a386Sopenharmony_ci} 485cb93a386Sopenharmony_ci 486cb93a386Sopenharmony_civoid IssueDraw(const GrCaps& caps, GrOpsRenderPass* renderPass, const VertexSpec& spec, 487cb93a386Sopenharmony_ci int runningQuadCount, int quadsInDraw, int maxVerts, int absVertBufferOffset) { 488cb93a386Sopenharmony_ci if (spec.indexBufferOption() == IndexBufferOption::kTriStrips) { 489cb93a386Sopenharmony_ci int offset = absVertBufferOffset + 490cb93a386Sopenharmony_ci runningQuadCount * GrResourceProvider::NumVertsPerNonAAQuad(); 491cb93a386Sopenharmony_ci renderPass->draw(4, offset); 492cb93a386Sopenharmony_ci return; 493cb93a386Sopenharmony_ci } 494cb93a386Sopenharmony_ci 495cb93a386Sopenharmony_ci SkASSERT(spec.indexBufferOption() == IndexBufferOption::kPictureFramed || 496cb93a386Sopenharmony_ci spec.indexBufferOption() == IndexBufferOption::kIndexedRects); 497cb93a386Sopenharmony_ci 498cb93a386Sopenharmony_ci int maxNumQuads, numIndicesPerQuad, numVertsPerQuad; 499cb93a386Sopenharmony_ci 500cb93a386Sopenharmony_ci if (spec.indexBufferOption() == IndexBufferOption::kPictureFramed) { 501cb93a386Sopenharmony_ci // AA uses 8 vertices and 30 indices per quad, basically nested rectangles 502cb93a386Sopenharmony_ci maxNumQuads = GrResourceProvider::MaxNumAAQuads(); 503cb93a386Sopenharmony_ci numIndicesPerQuad = GrResourceProvider::NumIndicesPerAAQuad(); 504cb93a386Sopenharmony_ci numVertsPerQuad = GrResourceProvider::NumVertsPerAAQuad(); 505cb93a386Sopenharmony_ci } else { 506cb93a386Sopenharmony_ci // Non-AA uses 4 vertices and 6 indices per quad 507cb93a386Sopenharmony_ci maxNumQuads = GrResourceProvider::MaxNumNonAAQuads(); 508cb93a386Sopenharmony_ci numIndicesPerQuad = GrResourceProvider::NumIndicesPerNonAAQuad(); 509cb93a386Sopenharmony_ci numVertsPerQuad = GrResourceProvider::NumVertsPerNonAAQuad(); 510cb93a386Sopenharmony_ci } 511cb93a386Sopenharmony_ci 512cb93a386Sopenharmony_ci SkASSERT(runningQuadCount + quadsInDraw <= maxNumQuads); 513cb93a386Sopenharmony_ci 514cb93a386Sopenharmony_ci if (caps.avoidLargeIndexBufferDraws()) { 515cb93a386Sopenharmony_ci // When we need to avoid large index buffer draws we modify the base vertex of the draw 516cb93a386Sopenharmony_ci // which, in GL, requires rebinding all vertex attrib arrays, so a base index is generally 517cb93a386Sopenharmony_ci // preferred. 518cb93a386Sopenharmony_ci int offset = absVertBufferOffset + runningQuadCount * numVertsPerQuad; 519cb93a386Sopenharmony_ci 520cb93a386Sopenharmony_ci renderPass->drawIndexPattern(numIndicesPerQuad, quadsInDraw, maxNumQuads, numVertsPerQuad, 521cb93a386Sopenharmony_ci offset); 522cb93a386Sopenharmony_ci } else { 523cb93a386Sopenharmony_ci int baseIndex = runningQuadCount * numIndicesPerQuad; 524cb93a386Sopenharmony_ci int numIndicesToDraw = quadsInDraw * numIndicesPerQuad; 525cb93a386Sopenharmony_ci 526cb93a386Sopenharmony_ci int minVertex = runningQuadCount * numVertsPerQuad; 527cb93a386Sopenharmony_ci int maxVertex = (runningQuadCount + quadsInDraw) * numVertsPerQuad - 1; // inclusive 528cb93a386Sopenharmony_ci 529cb93a386Sopenharmony_ci renderPass->drawIndexed(numIndicesToDraw, baseIndex, minVertex, maxVertex, 530cb93a386Sopenharmony_ci absVertBufferOffset); 531cb93a386Sopenharmony_ci } 532cb93a386Sopenharmony_ci} 533cb93a386Sopenharmony_ci 534cb93a386Sopenharmony_ci////////////////// VertexSpec Implementation 535cb93a386Sopenharmony_ci 536cb93a386Sopenharmony_ciint VertexSpec::deviceDimensionality() const { 537cb93a386Sopenharmony_ci return this->deviceQuadType() == GrQuad::Type::kPerspective ? 3 : 2; 538cb93a386Sopenharmony_ci} 539cb93a386Sopenharmony_ci 540cb93a386Sopenharmony_ciint VertexSpec::localDimensionality() const { 541cb93a386Sopenharmony_ci return fHasLocalCoords ? (this->localQuadType() == GrQuad::Type::kPerspective ? 3 : 2) : 0; 542cb93a386Sopenharmony_ci} 543cb93a386Sopenharmony_ci 544cb93a386Sopenharmony_ciCoverageMode VertexSpec::coverageMode() const { 545cb93a386Sopenharmony_ci if (this->usesCoverageAA()) { 546cb93a386Sopenharmony_ci if (this->compatibleWithCoverageAsAlpha() && this->hasVertexColors() && 547cb93a386Sopenharmony_ci !this->requiresGeometrySubset()) { 548cb93a386Sopenharmony_ci // Using a geometric subset acts as a second source of coverage and folding 549cb93a386Sopenharmony_ci // the original coverage into color makes it impossible to apply the color's 550cb93a386Sopenharmony_ci // alpha to the geometric subset's coverage when the original shape is clipped. 551cb93a386Sopenharmony_ci return CoverageMode::kWithColor; 552cb93a386Sopenharmony_ci } else { 553cb93a386Sopenharmony_ci return CoverageMode::kWithPosition; 554cb93a386Sopenharmony_ci } 555cb93a386Sopenharmony_ci } else { 556cb93a386Sopenharmony_ci return CoverageMode::kNone; 557cb93a386Sopenharmony_ci } 558cb93a386Sopenharmony_ci} 559cb93a386Sopenharmony_ci 560cb93a386Sopenharmony_ci// This needs to stay in sync w/ QuadPerEdgeAAGeometryProcessor::initializeAttrs 561cb93a386Sopenharmony_cisize_t VertexSpec::vertexSize() const { 562cb93a386Sopenharmony_ci bool needsPerspective = (this->deviceDimensionality() == 3); 563cb93a386Sopenharmony_ci CoverageMode coverageMode = this->coverageMode(); 564cb93a386Sopenharmony_ci 565cb93a386Sopenharmony_ci size_t count = 0; 566cb93a386Sopenharmony_ci 567cb93a386Sopenharmony_ci if (coverageMode == CoverageMode::kWithPosition) { 568cb93a386Sopenharmony_ci if (needsPerspective) { 569cb93a386Sopenharmony_ci count += GrVertexAttribTypeSize(kFloat4_GrVertexAttribType); 570cb93a386Sopenharmony_ci } else { 571cb93a386Sopenharmony_ci count += GrVertexAttribTypeSize(kFloat2_GrVertexAttribType) + 572cb93a386Sopenharmony_ci GrVertexAttribTypeSize(kFloat_GrVertexAttribType); 573cb93a386Sopenharmony_ci } 574cb93a386Sopenharmony_ci } else { 575cb93a386Sopenharmony_ci if (needsPerspective) { 576cb93a386Sopenharmony_ci count += GrVertexAttribTypeSize(kFloat3_GrVertexAttribType); 577cb93a386Sopenharmony_ci } else { 578cb93a386Sopenharmony_ci count += GrVertexAttribTypeSize(kFloat2_GrVertexAttribType); 579cb93a386Sopenharmony_ci } 580cb93a386Sopenharmony_ci } 581cb93a386Sopenharmony_ci 582cb93a386Sopenharmony_ci if (this->requiresGeometrySubset()) { 583cb93a386Sopenharmony_ci count += GrVertexAttribTypeSize(kFloat4_GrVertexAttribType); 584cb93a386Sopenharmony_ci } 585cb93a386Sopenharmony_ci 586cb93a386Sopenharmony_ci count += this->localDimensionality() * GrVertexAttribTypeSize(kFloat_GrVertexAttribType); 587cb93a386Sopenharmony_ci 588cb93a386Sopenharmony_ci if (ColorType::kByte == this->colorType()) { 589cb93a386Sopenharmony_ci count += GrVertexAttribTypeSize(kUByte4_norm_GrVertexAttribType); 590cb93a386Sopenharmony_ci } else if (ColorType::kFloat == this->colorType()) { 591cb93a386Sopenharmony_ci count += GrVertexAttribTypeSize(kFloat4_GrVertexAttribType); 592cb93a386Sopenharmony_ci } 593cb93a386Sopenharmony_ci 594cb93a386Sopenharmony_ci if (this->hasSubset()) { 595cb93a386Sopenharmony_ci count += GrVertexAttribTypeSize(kFloat4_GrVertexAttribType); 596cb93a386Sopenharmony_ci } 597cb93a386Sopenharmony_ci 598cb93a386Sopenharmony_ci return count; 599cb93a386Sopenharmony_ci} 600cb93a386Sopenharmony_ci 601cb93a386Sopenharmony_ci////////////////// Geometry Processor Implementation 602cb93a386Sopenharmony_ci 603cb93a386Sopenharmony_ciclass QuadPerEdgeAAGeometryProcessor : public GrGeometryProcessor { 604cb93a386Sopenharmony_cipublic: 605cb93a386Sopenharmony_ci static GrGeometryProcessor* Make(SkArenaAlloc* arena, const VertexSpec& spec) { 606cb93a386Sopenharmony_ci return arena->make([&](void* ptr) { 607cb93a386Sopenharmony_ci return new (ptr) QuadPerEdgeAAGeometryProcessor(spec); 608cb93a386Sopenharmony_ci }); 609cb93a386Sopenharmony_ci } 610cb93a386Sopenharmony_ci 611cb93a386Sopenharmony_ci static GrGeometryProcessor* Make(SkArenaAlloc* arena, 612cb93a386Sopenharmony_ci const VertexSpec& vertexSpec, 613cb93a386Sopenharmony_ci const GrShaderCaps& caps, 614cb93a386Sopenharmony_ci const GrBackendFormat& backendFormat, 615cb93a386Sopenharmony_ci GrSamplerState samplerState, 616cb93a386Sopenharmony_ci const GrSwizzle& swizzle, 617cb93a386Sopenharmony_ci sk_sp<GrColorSpaceXform> textureColorSpaceXform, 618cb93a386Sopenharmony_ci Saturate saturate) { 619cb93a386Sopenharmony_ci return arena->make([&](void* ptr) { 620cb93a386Sopenharmony_ci return new (ptr) QuadPerEdgeAAGeometryProcessor( 621cb93a386Sopenharmony_ci vertexSpec, caps, backendFormat, samplerState, swizzle, 622cb93a386Sopenharmony_ci std::move(textureColorSpaceXform), saturate); 623cb93a386Sopenharmony_ci }); 624cb93a386Sopenharmony_ci } 625cb93a386Sopenharmony_ci 626cb93a386Sopenharmony_ci const char* name() const override { return "QuadPerEdgeAAGeometryProcessor"; } 627cb93a386Sopenharmony_ci 628cb93a386Sopenharmony_ci SkString getShaderDfxInfo() const override { 629cb93a386Sopenharmony_ci uint32_t coverageKey = 0; 630cb93a386Sopenharmony_ci if (fCoverageMode != CoverageMode::kNone) { 631cb93a386Sopenharmony_ci coverageKey = fGeomSubset.isInitialized() 632cb93a386Sopenharmony_ci ? 0x3 633cb93a386Sopenharmony_ci : (CoverageMode::kWithPosition == fCoverageMode ? 0x1 : 0x2); 634cb93a386Sopenharmony_ci } 635cb93a386Sopenharmony_ci SkString format; 636cb93a386Sopenharmony_ci format.printf("ShaderDfx_QuadPerEdgeAA_%d_%d_%d_%d_%d_%d_%d_%d_%d_%d", 637cb93a386Sopenharmony_ci fTexSubset.isInitialized(), fSampler.isInitialized(), fNeedsPerspective, fSaturate == Saturate::kYes, 638cb93a386Sopenharmony_ci fLocalCoord.isInitialized(), 639cb93a386Sopenharmony_ci fLocalCoord.isInitialized() ? kFloat3_GrVertexAttribType == fLocalCoord.cpuType() : 2, 640cb93a386Sopenharmony_ci fColor.isInitialized(), 641cb93a386Sopenharmony_ci fColor.isInitialized() ? kFloat4_GrVertexAttribType == fColor.cpuType() : 2, 642cb93a386Sopenharmony_ci coverageKey, GrColorSpaceXform::XformKey(fTextureColorSpaceXform.get())); 643cb93a386Sopenharmony_ci return format; 644cb93a386Sopenharmony_ci } 645cb93a386Sopenharmony_ci 646cb93a386Sopenharmony_ci void addToKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override { 647cb93a386Sopenharmony_ci // texturing, device-dimensions are single bit flags 648cb93a386Sopenharmony_ci b->addBool(fTexSubset.isInitialized(), "subset"); 649cb93a386Sopenharmony_ci b->addBool(fSampler.isInitialized(), "textured"); 650cb93a386Sopenharmony_ci b->addBool(fNeedsPerspective, "perspective"); 651cb93a386Sopenharmony_ci b->addBool((fSaturate == Saturate::kYes), "saturate"); 652cb93a386Sopenharmony_ci 653cb93a386Sopenharmony_ci b->addBool(fLocalCoord.isInitialized(), "hasLocalCoords"); 654cb93a386Sopenharmony_ci if (fLocalCoord.isInitialized()) { 655cb93a386Sopenharmony_ci // 2D (0) or 3D (1) 656cb93a386Sopenharmony_ci b->addBits(1, (kFloat3_GrVertexAttribType == fLocalCoord.cpuType()), "localCoordsType"); 657cb93a386Sopenharmony_ci } 658cb93a386Sopenharmony_ci b->addBool(fColor.isInitialized(), "hasColor"); 659cb93a386Sopenharmony_ci if (fColor.isInitialized()) { 660cb93a386Sopenharmony_ci // bytes (0) or floats (1) 661cb93a386Sopenharmony_ci b->addBits(1, (kFloat4_GrVertexAttribType == fColor.cpuType()), "colorType"); 662cb93a386Sopenharmony_ci } 663cb93a386Sopenharmony_ci // and coverage mode, 00 for none, 01 for withposition, 10 for withcolor, 11 for 664cb93a386Sopenharmony_ci // position+geomsubset 665cb93a386Sopenharmony_ci uint32_t coverageKey = 0; 666cb93a386Sopenharmony_ci SkASSERT(!fGeomSubset.isInitialized() || fCoverageMode == CoverageMode::kWithPosition); 667cb93a386Sopenharmony_ci if (fCoverageMode != CoverageMode::kNone) { 668cb93a386Sopenharmony_ci coverageKey = fGeomSubset.isInitialized() 669cb93a386Sopenharmony_ci ? 0x3 670cb93a386Sopenharmony_ci : (CoverageMode::kWithPosition == fCoverageMode ? 0x1 : 0x2); 671cb93a386Sopenharmony_ci } 672cb93a386Sopenharmony_ci b->addBits(2, coverageKey, "coverageMode"); 673cb93a386Sopenharmony_ci 674cb93a386Sopenharmony_ci b->add32(GrColorSpaceXform::XformKey(fTextureColorSpaceXform.get()), "colorSpaceXform"); 675cb93a386Sopenharmony_ci } 676cb93a386Sopenharmony_ci 677cb93a386Sopenharmony_ci std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const override { 678cb93a386Sopenharmony_ci class Impl : public ProgramImpl { 679cb93a386Sopenharmony_ci public: 680cb93a386Sopenharmony_ci void setData(const GrGLSLProgramDataManager& pdman, 681cb93a386Sopenharmony_ci const GrShaderCaps&, 682cb93a386Sopenharmony_ci const GrGeometryProcessor& geomProc) override { 683cb93a386Sopenharmony_ci const auto& gp = geomProc.cast<QuadPerEdgeAAGeometryProcessor>(); 684cb93a386Sopenharmony_ci fTextureColorSpaceXformHelper.setData(pdman, gp.fTextureColorSpaceXform.get()); 685cb93a386Sopenharmony_ci } 686cb93a386Sopenharmony_ci 687cb93a386Sopenharmony_ci private: 688cb93a386Sopenharmony_ci void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { 689cb93a386Sopenharmony_ci using Interpolation = GrGLSLVaryingHandler::Interpolation; 690cb93a386Sopenharmony_ci 691cb93a386Sopenharmony_ci const auto& gp = args.fGeomProc.cast<QuadPerEdgeAAGeometryProcessor>(); 692cb93a386Sopenharmony_ci fTextureColorSpaceXformHelper.emitCode(args.fUniformHandler, 693cb93a386Sopenharmony_ci gp.fTextureColorSpaceXform.get()); 694cb93a386Sopenharmony_ci 695cb93a386Sopenharmony_ci args.fVaryingHandler->emitAttributes(gp); 696cb93a386Sopenharmony_ci 697cb93a386Sopenharmony_ci if (gp.fCoverageMode == CoverageMode::kWithPosition) { 698cb93a386Sopenharmony_ci // Strip last channel from the vertex attribute to remove coverage and get the 699cb93a386Sopenharmony_ci // actual position 700cb93a386Sopenharmony_ci if (gp.fNeedsPerspective) { 701cb93a386Sopenharmony_ci args.fVertBuilder->codeAppendf("float3 position = %s.xyz;", 702cb93a386Sopenharmony_ci gp.fPosition.name()); 703cb93a386Sopenharmony_ci } else { 704cb93a386Sopenharmony_ci args.fVertBuilder->codeAppendf("float2 position = %s.xy;", 705cb93a386Sopenharmony_ci gp.fPosition.name()); 706cb93a386Sopenharmony_ci } 707cb93a386Sopenharmony_ci gpArgs->fPositionVar = {"position", 708cb93a386Sopenharmony_ci gp.fNeedsPerspective ? kFloat3_GrSLType 709cb93a386Sopenharmony_ci : kFloat2_GrSLType, 710cb93a386Sopenharmony_ci GrShaderVar::TypeModifier::None}; 711cb93a386Sopenharmony_ci } else { 712cb93a386Sopenharmony_ci // No coverage to eliminate 713cb93a386Sopenharmony_ci gpArgs->fPositionVar = gp.fPosition.asShaderVar(); 714cb93a386Sopenharmony_ci } 715cb93a386Sopenharmony_ci 716cb93a386Sopenharmony_ci // This attribute will be uninitialized if earlier FP analysis determined no 717cb93a386Sopenharmony_ci // local coordinates are needed (and this will not include the inline texture 718cb93a386Sopenharmony_ci // fetch this GP does before invoking FPs). 719cb93a386Sopenharmony_ci gpArgs->fLocalCoordVar = gp.fLocalCoord.asShaderVar(); 720cb93a386Sopenharmony_ci 721cb93a386Sopenharmony_ci // Solid color before any texturing gets modulated in 722cb93a386Sopenharmony_ci const char* blendDst; 723cb93a386Sopenharmony_ci if (gp.fColor.isInitialized()) { 724cb93a386Sopenharmony_ci SkASSERT(gp.fCoverageMode != CoverageMode::kWithColor || !gp.fNeedsPerspective); 725cb93a386Sopenharmony_ci // The color cannot be flat if the varying coverage has been modulated into it 726cb93a386Sopenharmony_ci args.fFragBuilder->codeAppendf("half4 %s;", args.fOutputColor); 727cb93a386Sopenharmony_ci args.fVaryingHandler->addPassThroughAttribute( 728cb93a386Sopenharmony_ci gp.fColor.asShaderVar(), 729cb93a386Sopenharmony_ci args.fOutputColor, 730cb93a386Sopenharmony_ci gp.fCoverageMode == CoverageMode::kWithColor 731cb93a386Sopenharmony_ci ? Interpolation::kInterpolated 732cb93a386Sopenharmony_ci : Interpolation::kCanBeFlat); 733cb93a386Sopenharmony_ci blendDst = args.fOutputColor; 734cb93a386Sopenharmony_ci } else { 735cb93a386Sopenharmony_ci // Output color must be initialized to something 736cb93a386Sopenharmony_ci args.fFragBuilder->codeAppendf("half4 %s = half4(1);", args.fOutputColor); 737cb93a386Sopenharmony_ci blendDst = nullptr; 738cb93a386Sopenharmony_ci } 739cb93a386Sopenharmony_ci 740cb93a386Sopenharmony_ci // If there is a texture, must also handle texture coordinates and reading from 741cb93a386Sopenharmony_ci // the texture in the fragment shader before continuing to fragment processors. 742cb93a386Sopenharmony_ci if (gp.fSampler.isInitialized()) { 743cb93a386Sopenharmony_ci // Texture coordinates clamped by the subset on the fragment shader; if the GP 744cb93a386Sopenharmony_ci // has a texture, it's guaranteed to have local coordinates 745cb93a386Sopenharmony_ci args.fFragBuilder->codeAppend("float2 texCoord;"); 746cb93a386Sopenharmony_ci if (gp.fLocalCoord.cpuType() == kFloat3_GrVertexAttribType) { 747cb93a386Sopenharmony_ci // Can't do a pass through since we need to perform perspective division 748cb93a386Sopenharmony_ci GrGLSLVarying v(gp.fLocalCoord.gpuType()); 749cb93a386Sopenharmony_ci args.fVaryingHandler->addVarying(gp.fLocalCoord.name(), &v); 750cb93a386Sopenharmony_ci args.fVertBuilder->codeAppendf("%s = %s;", 751cb93a386Sopenharmony_ci v.vsOut(), gp.fLocalCoord.name()); 752cb93a386Sopenharmony_ci args.fFragBuilder->codeAppendf("texCoord = %s.xy / %s.z;", 753cb93a386Sopenharmony_ci v.fsIn(), v.fsIn()); 754cb93a386Sopenharmony_ci } else { 755cb93a386Sopenharmony_ci args.fVaryingHandler->addPassThroughAttribute(gp.fLocalCoord.asShaderVar(), 756cb93a386Sopenharmony_ci "texCoord"); 757cb93a386Sopenharmony_ci } 758cb93a386Sopenharmony_ci 759cb93a386Sopenharmony_ci // Clamp the now 2D localCoordName variable by the subset if it is provided 760cb93a386Sopenharmony_ci if (gp.fTexSubset.isInitialized()) { 761cb93a386Sopenharmony_ci args.fFragBuilder->codeAppend("float4 subset;"); 762cb93a386Sopenharmony_ci args.fVaryingHandler->addPassThroughAttribute(gp.fTexSubset.asShaderVar(), 763cb93a386Sopenharmony_ci "subset", 764cb93a386Sopenharmony_ci Interpolation::kCanBeFlat); 765cb93a386Sopenharmony_ci args.fFragBuilder->codeAppend( 766cb93a386Sopenharmony_ci "texCoord = clamp(texCoord, subset.LT, subset.RB);"); 767cb93a386Sopenharmony_ci } 768cb93a386Sopenharmony_ci 769cb93a386Sopenharmony_ci // Now modulate the starting output color by the texture lookup 770cb93a386Sopenharmony_ci args.fFragBuilder->codeAppendf( 771cb93a386Sopenharmony_ci "%s = %s(", 772cb93a386Sopenharmony_ci args.fOutputColor, 773cb93a386Sopenharmony_ci (gp.fSaturate == Saturate::kYes) ? "saturate" : ""); 774cb93a386Sopenharmony_ci args.fFragBuilder->appendTextureLookupAndBlend( 775cb93a386Sopenharmony_ci blendDst, SkBlendMode::kModulate, args.fTexSamplers[0], 776cb93a386Sopenharmony_ci "texCoord", &fTextureColorSpaceXformHelper); 777cb93a386Sopenharmony_ci args.fFragBuilder->codeAppend(");"); 778cb93a386Sopenharmony_ci } else { 779cb93a386Sopenharmony_ci // Saturate is only intended for use with a proxy to account for the fact 780cb93a386Sopenharmony_ci // that TextureOp skips SkPaint conversion, which normally handles this. 781cb93a386Sopenharmony_ci SkASSERT(gp.fSaturate == Saturate::kNo); 782cb93a386Sopenharmony_ci } 783cb93a386Sopenharmony_ci 784cb93a386Sopenharmony_ci // And lastly, output the coverage calculation code 785cb93a386Sopenharmony_ci if (gp.fCoverageMode == CoverageMode::kWithPosition) { 786cb93a386Sopenharmony_ci GrGLSLVarying coverage(kFloat_GrSLType); 787cb93a386Sopenharmony_ci args.fVaryingHandler->addVarying("coverage", &coverage); 788cb93a386Sopenharmony_ci if (gp.fNeedsPerspective) { 789cb93a386Sopenharmony_ci // Multiply by "W" in the vertex shader, then by 1/w (sk_FragCoord.w) in 790cb93a386Sopenharmony_ci // the fragment shader to get screen-space linear coverage. 791cb93a386Sopenharmony_ci args.fVertBuilder->codeAppendf("%s = %s.w * %s.z;", 792cb93a386Sopenharmony_ci coverage.vsOut(), gp.fPosition.name(), 793cb93a386Sopenharmony_ci gp.fPosition.name()); 794cb93a386Sopenharmony_ci args.fFragBuilder->codeAppendf("float coverage = %s * sk_FragCoord.w;", 795cb93a386Sopenharmony_ci coverage.fsIn()); 796cb93a386Sopenharmony_ci } else { 797cb93a386Sopenharmony_ci args.fVertBuilder->codeAppendf("%s = %s;", 798cb93a386Sopenharmony_ci coverage.vsOut(), gp.fCoverage.name()); 799cb93a386Sopenharmony_ci args.fFragBuilder->codeAppendf("float coverage = %s;", coverage.fsIn()); 800cb93a386Sopenharmony_ci } 801cb93a386Sopenharmony_ci 802cb93a386Sopenharmony_ci if (gp.fGeomSubset.isInitialized()) { 803cb93a386Sopenharmony_ci // Calculate distance from sk_FragCoord to the 4 edges of the subset 804cb93a386Sopenharmony_ci // and clamp them to (0, 1). Use the minimum of these and the original 805cb93a386Sopenharmony_ci // coverage. This only has to be done in the exterior triangles, the 806cb93a386Sopenharmony_ci // interior of the quad geometry can never be clipped by the subset box. 807cb93a386Sopenharmony_ci args.fFragBuilder->codeAppend("float4 geoSubset;"); 808cb93a386Sopenharmony_ci args.fVaryingHandler->addPassThroughAttribute(gp.fGeomSubset.asShaderVar(), 809cb93a386Sopenharmony_ci "geoSubset", 810cb93a386Sopenharmony_ci Interpolation::kCanBeFlat); 811cb93a386Sopenharmony_ci#ifdef SK_USE_LEGACY_AA_QUAD_SUBSET 812cb93a386Sopenharmony_ci args.fFragBuilder->codeAppend( 813cb93a386Sopenharmony_ci "if (coverage < 0.5) {" 814cb93a386Sopenharmony_ci " float4 dists4 = clamp(float4(1, 1, -1, -1) * " 815cb93a386Sopenharmony_ci "(sk_FragCoord.xyxy - geoSubset), 0, 1);" 816cb93a386Sopenharmony_ci " float2 dists2 = dists4.xy * dists4.zw;" 817cb93a386Sopenharmony_ci " coverage = min(coverage, dists2.x * dists2.y);" 818cb93a386Sopenharmony_ci "}"); 819cb93a386Sopenharmony_ci#else 820cb93a386Sopenharmony_ci args.fFragBuilder->codeAppend( 821cb93a386Sopenharmony_ci // This is lifted from GrAARectEffect. It'd be nice if we could 822cb93a386Sopenharmony_ci // invoke a FP from a GP rather than duplicate this code. 823cb93a386Sopenharmony_ci "half4 dists4 = clamp(half4(1, 1, -1, -1) * " 824cb93a386Sopenharmony_ci "half4(sk_FragCoord.xyxy - geoSubset), 0, 1);\n" 825cb93a386Sopenharmony_ci "half2 dists2 = dists4.xy + dists4.zw - 1;\n" 826cb93a386Sopenharmony_ci "half subsetCoverage = dists2.x * dists2.y;\n" 827cb93a386Sopenharmony_ci "coverage = min(coverage, subsetCoverage);"); 828cb93a386Sopenharmony_ci#endif 829cb93a386Sopenharmony_ci } 830cb93a386Sopenharmony_ci 831cb93a386Sopenharmony_ci args.fFragBuilder->codeAppendf("half4 %s = half4(half(coverage));", 832cb93a386Sopenharmony_ci args.fOutputCoverage); 833cb93a386Sopenharmony_ci } else { 834cb93a386Sopenharmony_ci // Set coverage to 1, since it's either non-AA or the coverage was already 835cb93a386Sopenharmony_ci // folded into the output color 836cb93a386Sopenharmony_ci SkASSERT(!gp.fGeomSubset.isInitialized()); 837cb93a386Sopenharmony_ci args.fFragBuilder->codeAppendf("const half4 %s = half4(1);", 838cb93a386Sopenharmony_ci args.fOutputCoverage); 839cb93a386Sopenharmony_ci } 840cb93a386Sopenharmony_ci } 841cb93a386Sopenharmony_ci 842cb93a386Sopenharmony_ci GrGLSLColorSpaceXformHelper fTextureColorSpaceXformHelper; 843cb93a386Sopenharmony_ci }; 844cb93a386Sopenharmony_ci 845cb93a386Sopenharmony_ci return std::make_unique<Impl>(); 846cb93a386Sopenharmony_ci } 847cb93a386Sopenharmony_ci 848cb93a386Sopenharmony_ciprivate: 849cb93a386Sopenharmony_ci using Saturate = skgpu::v1::TextureOp::Saturate; 850cb93a386Sopenharmony_ci 851cb93a386Sopenharmony_ci QuadPerEdgeAAGeometryProcessor(const VertexSpec& spec) 852cb93a386Sopenharmony_ci : INHERITED(kQuadPerEdgeAAGeometryProcessor_ClassID) 853cb93a386Sopenharmony_ci , fTextureColorSpaceXform(nullptr) { 854cb93a386Sopenharmony_ci SkASSERT(!spec.hasSubset()); 855cb93a386Sopenharmony_ci this->initializeAttrs(spec); 856cb93a386Sopenharmony_ci this->setTextureSamplerCnt(0); 857cb93a386Sopenharmony_ci } 858cb93a386Sopenharmony_ci 859cb93a386Sopenharmony_ci QuadPerEdgeAAGeometryProcessor(const VertexSpec& spec, 860cb93a386Sopenharmony_ci const GrShaderCaps& caps, 861cb93a386Sopenharmony_ci const GrBackendFormat& backendFormat, 862cb93a386Sopenharmony_ci GrSamplerState samplerState, 863cb93a386Sopenharmony_ci const GrSwizzle& swizzle, 864cb93a386Sopenharmony_ci sk_sp<GrColorSpaceXform> textureColorSpaceXform, 865cb93a386Sopenharmony_ci Saturate saturate) 866cb93a386Sopenharmony_ci : INHERITED(kQuadPerEdgeAAGeometryProcessor_ClassID) 867cb93a386Sopenharmony_ci , fSaturate(saturate) 868cb93a386Sopenharmony_ci , fTextureColorSpaceXform(std::move(textureColorSpaceXform)) 869cb93a386Sopenharmony_ci , fSampler(samplerState, backendFormat, swizzle) { 870cb93a386Sopenharmony_ci SkASSERT(spec.hasLocalCoords()); 871cb93a386Sopenharmony_ci this->initializeAttrs(spec); 872cb93a386Sopenharmony_ci this->setTextureSamplerCnt(1); 873cb93a386Sopenharmony_ci } 874cb93a386Sopenharmony_ci 875cb93a386Sopenharmony_ci // This needs to stay in sync w/ VertexSpec::vertexSize 876cb93a386Sopenharmony_ci void initializeAttrs(const VertexSpec& spec) { 877cb93a386Sopenharmony_ci fNeedsPerspective = spec.deviceDimensionality() == 3; 878cb93a386Sopenharmony_ci fCoverageMode = spec.coverageMode(); 879cb93a386Sopenharmony_ci 880cb93a386Sopenharmony_ci if (fCoverageMode == CoverageMode::kWithPosition) { 881cb93a386Sopenharmony_ci if (fNeedsPerspective) { 882cb93a386Sopenharmony_ci fPosition = {"positionWithCoverage", kFloat4_GrVertexAttribType, kFloat4_GrSLType}; 883cb93a386Sopenharmony_ci } else { 884cb93a386Sopenharmony_ci fPosition = {"position", kFloat2_GrVertexAttribType, kFloat2_GrSLType}; 885cb93a386Sopenharmony_ci fCoverage = {"coverage", kFloat_GrVertexAttribType, kFloat_GrSLType}; 886cb93a386Sopenharmony_ci } 887cb93a386Sopenharmony_ci } else { 888cb93a386Sopenharmony_ci if (fNeedsPerspective) { 889cb93a386Sopenharmony_ci fPosition = {"position", kFloat3_GrVertexAttribType, kFloat3_GrSLType}; 890cb93a386Sopenharmony_ci } else { 891cb93a386Sopenharmony_ci fPosition = {"position", kFloat2_GrVertexAttribType, kFloat2_GrSLType}; 892cb93a386Sopenharmony_ci } 893cb93a386Sopenharmony_ci } 894cb93a386Sopenharmony_ci 895cb93a386Sopenharmony_ci // Need a geometry subset when the quads are AA and not rectilinear, since their AA 896cb93a386Sopenharmony_ci // outsetting can go beyond a half pixel. 897cb93a386Sopenharmony_ci if (spec.requiresGeometrySubset()) { 898cb93a386Sopenharmony_ci fGeomSubset = {"geomSubset", kFloat4_GrVertexAttribType, kFloat4_GrSLType}; 899cb93a386Sopenharmony_ci } 900cb93a386Sopenharmony_ci 901cb93a386Sopenharmony_ci int localDim = spec.localDimensionality(); 902cb93a386Sopenharmony_ci if (localDim == 3) { 903cb93a386Sopenharmony_ci fLocalCoord = {"localCoord", kFloat3_GrVertexAttribType, kFloat3_GrSLType}; 904cb93a386Sopenharmony_ci } else if (localDim == 2) { 905cb93a386Sopenharmony_ci fLocalCoord = {"localCoord", kFloat2_GrVertexAttribType, kFloat2_GrSLType}; 906cb93a386Sopenharmony_ci } // else localDim == 0 and attribute remains uninitialized 907cb93a386Sopenharmony_ci 908cb93a386Sopenharmony_ci if (spec.hasVertexColors()) { 909cb93a386Sopenharmony_ci fColor = MakeColorAttribute("color", ColorType::kFloat == spec.colorType()); 910cb93a386Sopenharmony_ci } 911cb93a386Sopenharmony_ci 912cb93a386Sopenharmony_ci if (spec.hasSubset()) { 913cb93a386Sopenharmony_ci fTexSubset = {"texSubset", kFloat4_GrVertexAttribType, kFloat4_GrSLType}; 914cb93a386Sopenharmony_ci } 915cb93a386Sopenharmony_ci 916cb93a386Sopenharmony_ci this->setVertexAttributes(&fPosition, 6); 917cb93a386Sopenharmony_ci } 918cb93a386Sopenharmony_ci 919cb93a386Sopenharmony_ci const TextureSampler& onTextureSampler(int) const override { return fSampler; } 920cb93a386Sopenharmony_ci 921cb93a386Sopenharmony_ci Attribute fPosition; // May contain coverage as last channel 922cb93a386Sopenharmony_ci Attribute fCoverage; // Used for non-perspective position to avoid Intel Metal issues 923cb93a386Sopenharmony_ci Attribute fColor; // May have coverage modulated in if the FPs support it 924cb93a386Sopenharmony_ci Attribute fLocalCoord; 925cb93a386Sopenharmony_ci Attribute fGeomSubset; // Screen-space bounding box on geometry+aa outset 926cb93a386Sopenharmony_ci Attribute fTexSubset; // Texture-space bounding box on local coords 927cb93a386Sopenharmony_ci 928cb93a386Sopenharmony_ci // The positions attribute may have coverage built into it, so float3 is an ambiguous type 929cb93a386Sopenharmony_ci // and may mean 2d with coverage, or 3d with no coverage 930cb93a386Sopenharmony_ci bool fNeedsPerspective; 931cb93a386Sopenharmony_ci // Should saturate() be called on the color? Only relevant when created with a texture. 932cb93a386Sopenharmony_ci Saturate fSaturate = Saturate::kNo; 933cb93a386Sopenharmony_ci CoverageMode fCoverageMode; 934cb93a386Sopenharmony_ci 935cb93a386Sopenharmony_ci // Color space will be null and fSampler.isInitialized() returns false when the GP is configured 936cb93a386Sopenharmony_ci // to skip texturing. 937cb93a386Sopenharmony_ci sk_sp<GrColorSpaceXform> fTextureColorSpaceXform; 938cb93a386Sopenharmony_ci TextureSampler fSampler; 939cb93a386Sopenharmony_ci 940cb93a386Sopenharmony_ci using INHERITED = GrGeometryProcessor; 941cb93a386Sopenharmony_ci}; 942cb93a386Sopenharmony_ci 943cb93a386Sopenharmony_ciGrGeometryProcessor* MakeProcessor(SkArenaAlloc* arena, const VertexSpec& spec) { 944cb93a386Sopenharmony_ci return QuadPerEdgeAAGeometryProcessor::Make(arena, spec); 945cb93a386Sopenharmony_ci} 946cb93a386Sopenharmony_ci 947cb93a386Sopenharmony_ciGrGeometryProcessor* MakeTexturedProcessor(SkArenaAlloc* arena, 948cb93a386Sopenharmony_ci const VertexSpec& spec, 949cb93a386Sopenharmony_ci const GrShaderCaps& caps, 950cb93a386Sopenharmony_ci const GrBackendFormat& backendFormat, 951cb93a386Sopenharmony_ci GrSamplerState samplerState, 952cb93a386Sopenharmony_ci const GrSwizzle& swizzle, 953cb93a386Sopenharmony_ci sk_sp<GrColorSpaceXform> textureColorSpaceXform, 954cb93a386Sopenharmony_ci Saturate saturate) { 955cb93a386Sopenharmony_ci return QuadPerEdgeAAGeometryProcessor::Make(arena, spec, caps, backendFormat, samplerState, 956cb93a386Sopenharmony_ci swizzle, std::move(textureColorSpaceXform), 957cb93a386Sopenharmony_ci saturate); 958cb93a386Sopenharmony_ci} 959cb93a386Sopenharmony_ci 960cb93a386Sopenharmony_ci} // namespace skgpu::v1::QuadPerEdgeAA 961