Move several more PathRenderers to skgpu::v1 namespace

Bug: skia:11837
Change-Id: Ifa1da88aafcaa96e0e885facaeb849cc9963bcfe
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/439938
Commit-Queue: Robert Phillips <robertphillips@google.com>
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
This commit is contained in:
Robert Phillips 2021-08-17 16:42:51 -04:00 committed by SkCQ
parent fdcf153f6c
commit 461c539a04
21 changed files with 485 additions and 479 deletions

View File

@ -11,7 +11,7 @@
#include "include/core/SkPathBuilder.h"
DEF_SIMPLE_GM(crbug_847759, canvas, 500, 500) {
// This path exposed an issue in GrAAHairlinePathRenderer. When converting from cubics to quads
// This path exposed an issue in AAHairlinePathRenderer. When converting from cubics to quads
// we produced quads where the previously vertical tangents at the left and right tips of the
// squashed oval-like path became slightly non-vertical. This caused a missed pixel of AA just
// outside each tip.

View File

@ -513,12 +513,16 @@ skia_skgpu_v1_sources = [
"$_src/gpu/GrStencilMaskHelper.h",
# Ops
"$_src/gpu/ops/GrAAConvexPathRenderer.cpp",
"$_src/gpu/ops/GrAAConvexPathRenderer.h",
"$_src/gpu/ops/GrAAHairLinePathRenderer.cpp",
"$_src/gpu/ops/GrAAHairLinePathRenderer.h",
"$_src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp",
"$_src/gpu/ops/GrAALinearizingConvexPathRenderer.h",
"$_src/gpu/ops/AAConvexPathRenderer.cpp",
"$_src/gpu/ops/AAConvexPathRenderer.h",
"$_src/gpu/ops/AAHairLinePathRenderer.cpp",
"$_src/gpu/ops/AAHairLinePathRenderer.h",
"$_src/gpu/ops/AALinearizingConvexPathRenderer.cpp",
"$_src/gpu/ops/AALinearizingConvexPathRenderer.h",
"$_src/gpu/ops/DashLinePathRenderer.cpp",
"$_src/gpu/ops/DashLinePathRenderer.h",
"$_src/gpu/ops/DefaultPathRenderer.cpp",
"$_src/gpu/ops/DefaultPathRenderer.h",
"$_src/gpu/ops/GrAtlasInstancedHelper.cpp",
"$_src/gpu/ops/GrAtlasInstancedHelper.h",
"$_src/gpu/ops/GrAtlasPathRenderer.cpp",
@ -527,12 +531,8 @@ skia_skgpu_v1_sources = [
"$_src/gpu/ops/GrAtlasTextOp.h",
"$_src/gpu/ops/GrClearOp.cpp",
"$_src/gpu/ops/GrClearOp.h",
"$_src/gpu/ops/GrDashLinePathRenderer.cpp",
"$_src/gpu/ops/GrDashLinePathRenderer.h",
"$_src/gpu/ops/GrDashOp.cpp",
"$_src/gpu/ops/GrDashOp.h",
"$_src/gpu/ops/GrDefaultPathRenderer.cpp",
"$_src/gpu/ops/GrDefaultPathRenderer.h",
"$_src/gpu/ops/GrDrawAtlasOp.cpp",
"$_src/gpu/ops/GrDrawAtlasOp.h",
"$_src/gpu/ops/GrDrawAtlasPathOp.cpp",

View File

@ -854,7 +854,7 @@ typedef uint64_t GrFence;
* Used to include or exclude specific GPU path renderers for testing purposes.
*/
enum class GpuPathRenderers {
kNone = 0, // Always use software masks and/or GrDefaultPathRenderer.
kNone = 0, // Always use software masks and/or DefaultPathRenderer.
kDashLine = 1 << 0,
kAtlas = 1 << 1,
kTessellation = 1 << 2,

View File

@ -16,12 +16,12 @@
#include "src/gpu/GrRecordingContextPriv.h"
#include "src/gpu/GrShaderCaps.h"
#include "src/gpu/geometry/GrStyledShape.h"
#include "src/gpu/ops/GrAAConvexPathRenderer.h"
#include "src/gpu/ops/GrAAHairLinePathRenderer.h"
#include "src/gpu/ops/GrAALinearizingConvexPathRenderer.h"
#include "src/gpu/ops/AAConvexPathRenderer.h"
#include "src/gpu/ops/AAHairLinePathRenderer.h"
#include "src/gpu/ops/AALinearizingConvexPathRenderer.h"
#include "src/gpu/ops/DashLinePathRenderer.h"
#include "src/gpu/ops/DefaultPathRenderer.h"
#include "src/gpu/ops/GrAtlasPathRenderer.h"
#include "src/gpu/ops/GrDashLinePathRenderer.h"
#include "src/gpu/ops/GrDefaultPathRenderer.h"
#include "src/gpu/ops/GrTriangulatingPathRenderer.h"
#include "src/gpu/ops/SmallPathRenderer.h"
#include "src/gpu/tessellate/GrTessellationPathRenderer.h"
@ -29,16 +29,16 @@
GrPathRendererChain::GrPathRendererChain(GrRecordingContext* context, const Options& options) {
const GrCaps& caps = *context->priv().caps();
if (options.fGpuPathRenderers & GpuPathRenderers::kDashLine) {
fChain.push_back(sk_make_sp<GrDashLinePathRenderer>());
fChain.push_back(sk_make_sp<skgpu::v1::DashLinePathRenderer>());
}
if (options.fGpuPathRenderers & GpuPathRenderers::kAAConvex) {
fChain.push_back(sk_make_sp<GrAAConvexPathRenderer>());
fChain.push_back(sk_make_sp<skgpu::v1::AAConvexPathRenderer>());
}
if (options.fGpuPathRenderers & GpuPathRenderers::kAAHairline) {
fChain.push_back(sk_make_sp<GrAAHairLinePathRenderer>());
fChain.push_back(sk_make_sp<skgpu::v1::AAHairLinePathRenderer>());
}
if (options.fGpuPathRenderers & GpuPathRenderers::kAALinearizing) {
fChain.push_back(sk_make_sp<GrAALinearizingConvexPathRenderer>());
fChain.push_back(sk_make_sp<skgpu::v1::AALinearizingConvexPathRenderer>());
}
if (options.fGpuPathRenderers & GpuPathRenderers::kAtlas) {
if (auto atlasPathRenderer = GrAtlasPathRenderer::Make(context)) {
@ -62,7 +62,7 @@ GrPathRendererChain::GrPathRendererChain(GrRecordingContext* context, const Opti
}
// We always include the default path renderer (as well as SW), so we can draw any path
fChain.push_back(sk_make_sp<GrDefaultPathRenderer>());
fChain.push_back(sk_make_sp<skgpu::v1::DefaultPathRenderer>());
}
GrPathRenderer* GrPathRendererChain::getPathRenderer(

View File

@ -623,7 +623,7 @@ void GrAAConvexTessellator::createOuterRing(const Ring& previousRing, SkScalar o
this->addTri(originalIdx, perp1Idx, perp2Idx);
break;
default:
// kRound_Join is unsupported for now. GrAALinearizingConvexPathRenderer is
// kRound_Join is unsupported for now. AALinearizingConvexPathRenderer is
// only willing to draw mitered or beveled, so we should never get here.
SkASSERT(false);
}

View File

@ -357,7 +357,7 @@ void convert_noninflect_cubic_to_quads(const SkPoint p[4],
// This introduced a large performance regression for tiny paths for no noticeable
// quality improvement. However, we aren't quite fulfilling our contract of guaranteeing
// the two tangent vectors and this could introduce a missed pixel in
// GrAAHairlinePathRenderer.
// AAHairlinePathRenderer.
newC = (c0 + c1) * 0.5f;
} else if (preserveFirstTangent) {
newC = c0;

View File

@ -5,7 +5,7 @@
* found in the LICENSE file.
*/
#include "src/gpu/ops/GrAAConvexPathRenderer.h"
#include "src/gpu/ops/AAConvexPathRenderer.h"
#include "include/core/SkString.h"
#include "include/core/SkTypes.h"
@ -31,8 +31,7 @@
#include "src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h"
#include "src/gpu/v1/SurfaceDrawContext_v1.h"
GrAAConvexPathRenderer::GrAAConvexPathRenderer() {
}
namespace {
struct Segment {
enum {
@ -65,7 +64,7 @@ struct Segment {
typedef SkTArray<Segment, true> SegmentArray;
static bool center_of_mass(const SegmentArray& segments, SkPoint* c) {
bool center_of_mass(const SegmentArray& segments, SkPoint* c) {
SkScalar area = 0;
SkPoint center = {0, 0};
int count = segments.count();
@ -115,11 +114,11 @@ static bool center_of_mass(const SegmentArray& segments, SkPoint* c) {
return !SkScalarIsNaN(c->fX) && !SkScalarIsNaN(c->fY) && c->isFinite();
}
static bool compute_vectors(SegmentArray* segments,
SkPoint* fanPt,
SkPathFirstDirection dir,
int* vCount,
int* iCount) {
bool compute_vectors(SegmentArray* segments,
SkPoint* fanPt,
SkPathFirstDirection dir,
int* vCount,
int* iCount) {
if (!center_of_mass(*segments, fanPt)) {
return false;
}
@ -195,7 +194,7 @@ struct DegenerateTestData {
static const SkScalar kClose = (SK_Scalar1 / 16);
static const SkScalar kCloseSqd = kClose * kClose;
static void update_degenerate_test(DegenerateTestData* data, const SkPoint& pt) {
void update_degenerate_test(DegenerateTestData* data, const SkPoint& pt) {
switch (data->fStage) {
case DegenerateTestData::kInitial:
data->fFirstPoint = pt;
@ -222,8 +221,7 @@ static void update_degenerate_test(DegenerateTestData* data, const SkPoint& pt)
}
}
static inline bool get_direction(const SkPath& path, const SkMatrix& m,
SkPathFirstDirection* dir) {
inline bool get_direction(const SkPath& path, const SkMatrix& m, SkPathFirstDirection* dir) {
// At this point, we've already returned true from canDraw(), which checked that the path's
// direction could be determined, so this should just be fetching the cached direction.
// However, if perspective is involved, we're operating on a transformed path, which may no
@ -244,15 +242,13 @@ static inline bool get_direction(const SkPath& path, const SkMatrix& m,
return true;
}
static inline void add_line_to_segment(const SkPoint& pt,
SegmentArray* segments) {
inline void add_line_to_segment(const SkPoint& pt, SegmentArray* segments) {
segments->push_back();
segments->back().fType = Segment::kLine;
segments->back().fPts[0] = pt;
}
static inline void add_quad_segment(const SkPoint pts[3],
SegmentArray* segments) {
inline void add_quad_segment(const SkPoint pts[3], SegmentArray* segments) {
if (SkPointPriv::DistanceToLineSegmentBetweenSqd(pts[1], pts[0], pts[2]) < kCloseSqd) {
if (pts[0] != pts[2]) {
add_line_to_segment(pts[2], segments);
@ -265,9 +261,9 @@ static inline void add_quad_segment(const SkPoint pts[3],
}
}
static inline void add_cubic_segments(const SkPoint pts[4],
SkPathFirstDirection dir,
SegmentArray* segments) {
inline void add_cubic_segments(const SkPoint pts[4],
SkPathFirstDirection dir,
SegmentArray* segments) {
SkSTArray<15, SkPoint, true> quads;
GrPathUtils::convertCubicToQuadsConstrainToTangents(pts, SK_Scalar1, dir, &quads);
int count = quads.count();
@ -276,12 +272,12 @@ static inline void add_cubic_segments(const SkPoint pts[4],
}
}
static bool get_segments(const SkPath& path,
const SkMatrix& m,
SegmentArray* segments,
SkPoint* fanPt,
int* vCount,
int* iCount) {
bool get_segments(const SkPath& path,
const SkMatrix& m,
SegmentArray* segments,
SkPoint* fanPt,
int* vCount,
int* iCount) {
SkPath::Iter iter(path, true);
// This renderer over-emphasizes very thin path regions. We use the distance
// to the path from the sample to compute coverage. Every pixel intersected
@ -364,13 +360,13 @@ struct Draw {
typedef SkTArray<Draw, true> DrawArray;
static void create_vertices(const SegmentArray& segments,
const SkPoint& fanPt,
const GrVertexColor& color,
DrawArray* draws,
GrVertexWriter& verts,
uint16_t* idxs,
size_t vertexStride) {
void create_vertices(const SegmentArray& segments,
const SkPoint& fanPt,
const GrVertexColor& color,
DrawArray* draws,
GrVertexWriter& verts,
uint16_t* idxs,
size_t vertexStride) {
Draw* draw = &draws->push_back();
// alias just to make vert/index assignments easier to read.
int* v = &draw->fVertexCnt;
@ -682,23 +678,6 @@ GrGeometryProcessor* QuadEdgeEffect::TestCreate(GrProcessorTestData* d) {
}
#endif
///////////////////////////////////////////////////////////////////////////////
GrPathRenderer::CanDrawPath
GrAAConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
// This check requires convexity and known direction, since the direction is used to build
// the geometry segments. Degenerate convex paths will fall through to some other path renderer.
if (args.fCaps->shaderCaps()->shaderDerivativeSupport() &&
(GrAAType::kCoverage == args.fAAType) && args.fShape->style().isSimpleFill() &&
!args.fShape->inverseFilled() && args.fShape->knownToBeConvex() &&
args.fShape->knownDirection()) {
return CanDrawPath::kYes;
}
return CanDrawPath::kNo;
}
namespace {
class AAConvexPathOp final : public GrMeshDrawOp {
private:
using Helper = GrSimpleMeshDrawOpHelperWithStencil;
@ -912,23 +891,7 @@ private:
using INHERITED = GrMeshDrawOp;
};
} // anonymous namespace
bool GrAAConvexPathRenderer::onDrawPath(const DrawPathArgs& args) {
GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(),
"GrAAConvexPathRenderer::onDrawPath");
SkASSERT(args.fSurfaceDrawContext->numSamples() <= 1);
SkASSERT(!args.fShape->isEmpty());
SkPath path;
args.fShape->asPath(&path);
GrOp::Owner op = AAConvexPathOp::Make(args.fContext, std::move(args.fPaint),
*args.fViewMatrix,
path, args.fUserStencilSettings);
args.fSurfaceDrawContext->addDrawOp(args.fClip, std::move(op));
return true;
}
} // anonymous namespace
///////////////////////////////////////////////////////////////////////////////////////////////////
@ -942,3 +905,37 @@ GR_DRAW_OP_TEST_DEFINE(AAConvexPathOp) {
}
#endif
///////////////////////////////////////////////////////////////////////////////
namespace skgpu::v1 {
GrPathRenderer::CanDrawPath AAConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
// This check requires convexity and known direction, since the direction is used to build
// the geometry segments. Degenerate convex paths will fall through to some other path renderer.
if (args.fCaps->shaderCaps()->shaderDerivativeSupport() &&
(GrAAType::kCoverage == args.fAAType) && args.fShape->style().isSimpleFill() &&
!args.fShape->inverseFilled() && args.fShape->knownToBeConvex() &&
args.fShape->knownDirection()) {
return CanDrawPath::kYes;
}
return CanDrawPath::kNo;
}
bool AAConvexPathRenderer::onDrawPath(const DrawPathArgs& args) {
GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(),
"AAConvexPathRenderer::onDrawPath");
SkASSERT(args.fSurfaceDrawContext->numSamples() <= 1);
SkASSERT(!args.fShape->isEmpty());
SkPath path;
args.fShape->asPath(&path);
GrOp::Owner op = AAConvexPathOp::Make(args.fContext, std::move(args.fPaint),
*args.fViewMatrix,
path, args.fUserStencilSettings);
args.fSurfaceDrawContext->addDrawOp(args.fClip, std::move(op));
return true;
}
} // namespace skgpu::v1

View File

@ -0,0 +1,31 @@
/*
* Copyright 2012 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef AAConvexPathRenderer_DEFINED
#define AAConvexPathRenderer_DEFINED
#include "src/gpu/GrPathRenderer.h"
namespace skgpu::v1 {
class AAConvexPathRenderer final : public GrPathRenderer {
public:
AAConvexPathRenderer() = default;
const char* name() const override { return "AAConvex"; }
private:
CanDrawPath onCanDrawPath(const CanDrawPathArgs&) const override;
bool onDrawPath(const DrawPathArgs&) override;
using INHERITED = GrPathRenderer;
};
} // namespace skgpu::v1
#endif // AAConvexPathRenderer_DEFINED

View File

@ -5,7 +5,7 @@
* found in the LICENSE file.
*/
#include "src/gpu/ops/GrAAHairLinePathRenderer.h"
#include "src/gpu/ops/AAHairLinePathRenderer.h"
#include "include/core/SkPoint3.h"
#include "include/private/SkTemplates.h"
@ -34,6 +34,12 @@
#define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true>
using PtArray = SkTArray<SkPoint, true>;
using IntArray = SkTArray<int, true>;
using FloatArray = SkTArray<float, true>;
namespace {
// quadratics are rendered as 5-sided polys in order to bound the
// AA stroke around the center-curve. See comments in push_quad_index_buffer and
// bloat_quad. Quadratics and conics share an index buffer
@ -71,7 +77,7 @@ static const int kQuadNumVertices = 5;
static const int kQuadsNumInIdxBuffer = 256;
GR_DECLARE_STATIC_UNIQUE_KEY(gQuadsIndexBufferKey);
static sk_sp<const GrBuffer> get_quads_index_buffer(GrResourceProvider* resourceProvider) {
sk_sp<const GrBuffer> get_quads_index_buffer(GrResourceProvider* resourceProvider) {
GR_DEFINE_STATIC_UNIQUE_KEY(gQuadsIndexBufferKey);
return resourceProvider->findOrCreatePatternedIndexBuffer(
kQuadIdxBufPattern, kIdxsPerQuad, kQuadsNumInIdxBuffer, kQuadNumVertices,
@ -105,7 +111,7 @@ static const int kLineSegsNumInIdxBuffer = 256;
GR_DECLARE_STATIC_UNIQUE_KEY(gLinesIndexBufferKey);
static sk_sp<const GrBuffer> get_lines_index_buffer(GrResourceProvider* resourceProvider) {
sk_sp<const GrBuffer> get_lines_index_buffer(GrResourceProvider* resourceProvider) {
GR_DEFINE_STATIC_UNIQUE_KEY(gLinesIndexBufferKey);
return resourceProvider->findOrCreatePatternedIndexBuffer(
kLineSegIdxBufPattern, kIdxsPerLineSeg, kLineSegsNumInIdxBuffer, kLineSegNumVertices,
@ -113,7 +119,7 @@ static sk_sp<const GrBuffer> get_lines_index_buffer(GrResourceProvider* resource
}
// Takes 178th time of logf on Z600 / VC2010
static int get_float_exp(float x) {
int get_float_exp(float x) {
static_assert(sizeof(int) == sizeof(float));
#ifdef SK_DEBUG
static bool tested;
@ -141,7 +147,7 @@ static int get_float_exp(float x) {
// found along the curve segment it will return 1 and
// dst[0] is the original conic. If it returns 2 the dst[0]
// and dst[1] are the two new conics.
static int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
SkScalar t = SkFindQuadMaxCurvature(src);
if (t == 0 || t == 1) {
if (dst) {
@ -164,7 +170,7 @@ static int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weig
// Calls split_conic on the entire conic and then once more on each subsection.
// Most cases will result in either 1 conic (chop point is not within t range)
// or 3 points (split once and then one subsection is split again).
static int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
SkConic dstTemp[2];
int conicCnt = split_conic(src, dstTemp, weight);
if (2 == conicCnt) {
@ -179,7 +185,7 @@ static int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weigh
// returns 0 if quad/conic is degen or close to it
// in this case approx the path with lines
// otherwise returns 1
static int is_degen_quad_or_conic(const SkPoint p[3], SkScalar* dsqd) {
int is_degen_quad_or_conic(const SkPoint p[3], SkScalar* dsqd) {
static const SkScalar gDegenerateToLineTol = GrPathUtils::kDefaultTolerance;
static const SkScalar gDegenerateToLineTolSqd =
gDegenerateToLineTol * gDegenerateToLineTol;
@ -200,14 +206,14 @@ static int is_degen_quad_or_conic(const SkPoint p[3], SkScalar* dsqd) {
return 0;
}
static int is_degen_quad_or_conic(const SkPoint p[3]) {
int is_degen_quad_or_conic(const SkPoint p[3]) {
SkScalar dsqd;
return is_degen_quad_or_conic(p, &dsqd);
}
// we subdivide the quads to avoid huge overfill
// if it returns -1 then should be drawn as lines
static int num_quad_subdivs(const SkPoint p[3]) {
int num_quad_subdivs(const SkPoint p[3]) {
SkScalar dsqd;
if (is_degen_quad_or_conic(p, &dsqd)) {
return -1;
@ -243,16 +249,16 @@ static int num_quad_subdivs(const SkPoint p[3]) {
* subdivide large quads to reduce over-fill. This subdivision has to be
* performed before applying the perspective matrix.
*/
static int gather_lines_and_quads(const SkPath& path,
const SkMatrix& m,
const SkIRect& devClipBounds,
SkScalar capLength,
bool convertConicsToQuads,
GrAAHairLinePathRenderer::PtArray* lines,
GrAAHairLinePathRenderer::PtArray* quads,
GrAAHairLinePathRenderer::PtArray* conics,
GrAAHairLinePathRenderer::IntArray* quadSubdivCnts,
GrAAHairLinePathRenderer::FloatArray* conicWeights) {
int gather_lines_and_quads(const SkPath& path,
const SkMatrix& m,
const SkIRect& devClipBounds,
SkScalar capLength,
bool convertConicsToQuads,
PtArray* lines,
PtArray* quads,
PtArray* conics,
IntArray* quadSubdivCnts,
FloatArray* conicWeights) {
SkPath::Iter iter(path, false);
int totalQuadCount = 0;
@ -492,9 +498,9 @@ struct BezierVertex {
static_assert(sizeof(BezierVertex) == 3 * sizeof(SkPoint));
static void intersect_lines(const SkPoint& ptA, const SkVector& normA,
const SkPoint& ptB, const SkVector& normB,
SkPoint* result) {
void intersect_lines(const SkPoint& ptA, const SkVector& normA,
const SkPoint& ptB, const SkVector& normB,
SkPoint* result) {
SkScalar lineAW = -normA.dot(ptA);
SkScalar lineBW = -normB.dot(ptB);
@ -514,14 +520,16 @@ static void intersect_lines(const SkPoint& ptA, const SkVector& normA,
}
}
static void set_uv_quad(const SkPoint qpts[3], BezierVertex verts[kQuadNumVertices]) {
void set_uv_quad(const SkPoint qpts[3], BezierVertex verts[kQuadNumVertices]) {
// this should be in the src space, not dev coords, when we have perspective
GrPathUtils::QuadUVMatrix DevToUV(qpts);
DevToUV.apply(verts, kQuadNumVertices, sizeof(BezierVertex), sizeof(SkPoint));
}
static void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice,
const SkMatrix* toSrc, BezierVertex verts[kQuadNumVertices]) {
void bloat_quad(const SkPoint qpts[3],
const SkMatrix* toDevice,
const SkMatrix* toSrc,
BezierVertex verts[kQuadNumVertices]) {
SkASSERT(!toDevice == !toSrc);
// original quad is specified by tri a,b,c
SkPoint a = qpts[0];
@ -610,8 +618,9 @@ static void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice,
// f(x, y, w) = f(P) = K^2 - LM
// K = dot(k, P), L = dot(l, P), M = dot(m, P)
// k, l, m are calculated in function GrPathUtils::getConicKLM
static void set_conic_coeffs(const SkPoint p[3], BezierVertex verts[kQuadNumVertices],
const SkScalar weight) {
void set_conic_coeffs(const SkPoint p[3],
BezierVertex verts[kQuadNumVertices],
const SkScalar weight) {
SkMatrix klm;
GrPathUtils::getConicKLM(p, weight, &klm);
@ -622,21 +631,21 @@ static void set_conic_coeffs(const SkPoint p[3], BezierVertex verts[kQuadNumVert
}
}
static void add_conics(const SkPoint p[3],
const SkScalar weight,
const SkMatrix* toDevice,
const SkMatrix* toSrc,
BezierVertex** vert) {
void add_conics(const SkPoint p[3],
const SkScalar weight,
const SkMatrix* toDevice,
const SkMatrix* toSrc,
BezierVertex** vert) {
bloat_quad(p, toDevice, toSrc, *vert);
set_conic_coeffs(p, *vert, weight);
*vert += kQuadNumVertices;
}
static void add_quads(const SkPoint p[3],
int subdiv,
const SkMatrix* toDevice,
const SkMatrix* toSrc,
BezierVertex** vert) {
void add_quads(const SkPoint p[3],
int subdiv,
const SkMatrix* toDevice,
const SkMatrix* toSrc,
BezierVertex** vert) {
SkASSERT(subdiv >= 0);
// temporary vertex storage to avoid reading the vertex buffer
BezierVertex outVerts[kQuadNumVertices] = {};
@ -670,10 +679,10 @@ static void add_quads(const SkPoint p[3],
*vert += kQuadNumVertices;
}
static void add_line(const SkPoint p[2],
const SkMatrix* toSrc,
uint8_t coverage,
LineVertex** vert) {
void add_line(const SkPoint p[2],
const SkMatrix* toSrc,
uint8_t coverage,
LineVertex** vert) {
const SkPoint& a = p[0];
const SkPoint& b = p[1];
@ -736,66 +745,6 @@ static void add_line(const SkPoint p[2],
///////////////////////////////////////////////////////////////////////////////
GrPathRenderer::CanDrawPath
GrAAHairLinePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
if (GrAAType::kCoverage != args.fAAType) {
return CanDrawPath::kNo;
}
if (!GrIsStrokeHairlineOrEquivalent(args.fShape->style(), *args.fViewMatrix, nullptr)) {
return CanDrawPath::kNo;
}
// We don't currently handle dashing in this class though perhaps we should.
if (args.fShape->style().pathEffect()) {
return CanDrawPath::kNo;
}
if (SkPath::kLine_SegmentMask == args.fShape->segmentMask() ||
args.fCaps->shaderCaps()->shaderDerivativeSupport()) {
return CanDrawPath::kYes;
}
return CanDrawPath::kNo;
}
template <class VertexType>
bool check_bounds(const SkMatrix& viewMatrix, const SkRect& devBounds, void* vertices, int vCount)
{
SkRect tolDevBounds = devBounds;
// The bounds ought to be tight, but in perspective the below code runs the verts
// through the view matrix to get back to dev coords, which can introduce imprecision.
if (viewMatrix.hasPerspective()) {
tolDevBounds.outset(SK_Scalar1 / 1000, SK_Scalar1 / 1000);
} else {
// Non-persp matrices cause this path renderer to draw in device space.
SkASSERT(viewMatrix.isIdentity());
}
SkRect actualBounds;
VertexType* verts = reinterpret_cast<VertexType*>(vertices);
bool first = true;
for (int i = 0; i < vCount; ++i) {
SkPoint pos = verts[i].fPos;
// This is a hack to workaround the fact that we move some degenerate segments offscreen.
if (SK_ScalarMax == pos.fX) {
continue;
}
viewMatrix.mapPoints(&pos, 1);
if (first) {
actualBounds.setLTRB(pos.fX, pos.fY, pos.fX, pos.fY);
first = false;
} else {
SkRectPriv::GrowToInclude(&actualBounds, pos);
}
}
if (!first) {
return tolDevBounds.contains(actualBounds);
}
return true;
}
class AAHairlineOp final : public GrMeshDrawOp {
private:
using Helper = GrSimpleMeshDrawOpHelperWithStencil;
@ -869,11 +818,11 @@ public:
nullptr);
}
enum Program : uint8_t {
kNone_Program = 0x0,
kLine_Program = 0x1,
kQuad_Program = 0x2,
kConic_Program = 0x4,
enum class Program : uint8_t {
kNone = 0x0,
kLine = 0x1,
kQuad = 0x2,
kConic = 0x4,
};
private:
@ -924,10 +873,6 @@ private:
void onPrepareDraws(GrMeshDrawTarget*) override;
void onExecute(GrOpFlushState*, const SkRect& chainBounds) override;
typedef SkTArray<SkPoint, true> PtArray;
typedef SkTArray<int, true> IntArray;
typedef SkTArray<float, true> FloatArray;
CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps) override {
AAHairlineOp* that = t->cast<AAHairlineOp>();
@ -989,14 +934,14 @@ private:
SkPMColor4f fColor;
uint8_t fCoverage;
Program fCharacterization = kNone_Program; // holds a mask of required programs
Program fCharacterization = Program::kNone; // holds a mask of required programs
GrSimpleMesh* fMeshes[3] = { nullptr };
GrProgramInfo* fProgramInfos[3] = { nullptr };
using INHERITED = GrMeshDrawOp;
};
GR_MAKE_BITFIELD_OPS(AAHairlineOp::Program)
GR_MAKE_BITFIELD_CLASS_OPS(AAHairlineOp::Program)
void AAHairlineOp::makeLineProgramInfo(const GrCaps& caps, SkArenaAlloc* arena,
const GrPipeline* pipeline,
@ -1087,19 +1032,19 @@ AAHairlineOp::Program AAHairlineOp::predictPrograms(const GrCaps* caps) const {
// When predicting the programs we always include the lineProgram bc it is used as a fallback
// for quads and conics. In non-DDL mode there are cases where it sometimes isn't needed for a
// given path.
Program neededPrograms = kLine_Program;
Program neededPrograms = Program::kLine;
for (int i = 0; i < fPaths.count(); i++) {
uint32_t mask = fPaths[i].fPath.getSegmentMasks();
if (mask & (SkPath::kQuad_SegmentMask | SkPath::kCubic_SegmentMask)) {
neededPrograms |= kQuad_Program;
neededPrograms |= Program::kQuad;
}
if (mask & SkPath::kConic_SegmentMask) {
if (convertConicsToQuads) {
neededPrograms |= kQuad_Program;
neededPrograms |= Program::kQuad;
} else {
neededPrograms |= kConic_Program;
neededPrograms |= Program::kConic;
}
}
}
@ -1133,17 +1078,17 @@ void AAHairlineOp::onCreateProgramInfo(const GrCaps* caps,
auto pipeline = fHelper.createPipeline(caps, arena, writeView.swizzle(),
std::move(appliedClip), dstProxyView);
if (fCharacterization & kLine_Program) {
if (fCharacterization & Program::kLine) {
this->makeLineProgramInfo(*caps, arena, pipeline, writeView,
geometryProcessorViewM, geometryProcessorLocalM,
renderPassXferBarriers, colorLoadOp);
}
if (fCharacterization & kQuad_Program) {
if (fCharacterization & Program::kQuad) {
this->makeQuadProgramInfo(*caps, arena, pipeline, writeView,
geometryProcessorViewM, geometryProcessorLocalM,
renderPassXferBarriers, colorLoadOp);
}
if (fCharacterization & kConic_Program) {
if (fCharacterization & Program::kConic) {
this->makeConicProgramInfo(*caps, arena, pipeline, writeView,
geometryProcessorViewM, geometryProcessorLocalM,
renderPassXferBarriers, colorLoadOp);
@ -1193,7 +1138,7 @@ void AAHairlineOp::onPrepareDraws(GrMeshDrawTarget* target) {
}
SkDEBUGCODE(Program predictedPrograms = this->predictPrograms(&target->caps()));
Program actualPrograms = kNone_Program;
Program actualPrograms = Program::kNone;
// This is hand inlined for maximum performance.
PREALLOC_PTARRAY(128) lines;
@ -1224,8 +1169,8 @@ void AAHairlineOp::onPrepareDraws(GrMeshDrawTarget* target) {
// do lines first
if (lineCount) {
SkASSERT(predictedPrograms & kLine_Program);
actualPrograms |= kLine_Program;
SkASSERT(predictedPrograms & Program::kLine);
actualPrograms |= Program::kLine;
sk_sp<const GrBuffer> linesIndexBuffer = get_lines_index_buffer(target->resourceProvider());
@ -1279,8 +1224,8 @@ void AAHairlineOp::onPrepareDraws(GrMeshDrawTarget* target) {
}
if (quadCount > 0) {
SkASSERT(predictedPrograms & kQuad_Program);
actualPrograms |= kQuad_Program;
SkASSERT(predictedPrograms & Program::kQuad);
actualPrograms |= Program::kQuad;
fMeshes[1] = target->allocMesh();
fMeshes[1]->setIndexedPatterned(quadsIndexBuffer, kIdxsPerQuad, quadCount,
@ -1290,8 +1235,8 @@ void AAHairlineOp::onPrepareDraws(GrMeshDrawTarget* target) {
}
if (conicCount > 0) {
SkASSERT(predictedPrograms & kConic_Program);
actualPrograms |= kConic_Program;
SkASSERT(predictedPrograms & Program::kConic);
actualPrograms |= Program::kConic;
fMeshes[2] = target->allocMesh();
fMeshes[2]->setIndexedPatterned(std::move(quadsIndexBuffer), kIdxsPerQuad, conicCount,
@ -1318,20 +1263,7 @@ void AAHairlineOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBoun
}
}
bool GrAAHairLinePathRenderer::onDrawPath(const DrawPathArgs& args) {
GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(),
"GrAAHairlinePathRenderer::onDrawPath");
SkASSERT(args.fSurfaceDrawContext->numSamples() <= 1);
SkPath path;
args.fShape->asPath(&path);
GrOp::Owner op =
AAHairlineOp::Make(args.fContext, std::move(args.fPaint), *args.fViewMatrix, path,
args.fShape->style(), *args.fClipConservativeBounds,
args.fUserStencilSettings);
args.fSurfaceDrawContext->addDrawOp(args.fClip, std::move(op));
return true;
}
} // anonymous namespace
///////////////////////////////////////////////////////////////////////////////////////////////////
@ -1348,3 +1280,49 @@ GR_DRAW_OP_TEST_DEFINE(AAHairlineOp) {
}
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////
namespace skgpu::v1 {
GrPathRenderer::CanDrawPath
AAHairLinePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
if (GrAAType::kCoverage != args.fAAType) {
return CanDrawPath::kNo;
}
if (!GrIsStrokeHairlineOrEquivalent(args.fShape->style(), *args.fViewMatrix, nullptr)) {
return CanDrawPath::kNo;
}
// We don't currently handle dashing in this class though perhaps we should.
if (args.fShape->style().pathEffect()) {
return CanDrawPath::kNo;
}
if (SkPath::kLine_SegmentMask == args.fShape->segmentMask() ||
args.fCaps->shaderCaps()->shaderDerivativeSupport()) {
return CanDrawPath::kYes;
}
return CanDrawPath::kNo;
}
bool AAHairLinePathRenderer::onDrawPath(const DrawPathArgs& args) {
GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(),
"AAHairlinePathRenderer::onDrawPath");
SkASSERT(args.fSurfaceDrawContext->numSamples() <= 1);
SkPath path;
args.fShape->asPath(&path);
GrOp::Owner op =
AAHairlineOp::Make(args.fContext, std::move(args.fPaint), *args.fViewMatrix, path,
args.fShape->style(), *args.fClipConservativeBounds,
args.fUserStencilSettings);
args.fSurfaceDrawContext->addDrawOp(args.fClip, std::move(op));
return true;
}
} // namespace skgpu::v1

View File

@ -0,0 +1,31 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef AAHairLinePathRenderer_DEFINED
#define AAHairLinePathRenderer_DEFINED
#include "src/gpu/GrPathRenderer.h"
namespace skgpu::v1 {
class AAHairLinePathRenderer final : public GrPathRenderer {
public:
AAHairLinePathRenderer() = default;
const char* name() const override { return "AAHairline"; }
private:
CanDrawPath onCanDrawPath(const CanDrawPathArgs&) const override;
bool onDrawPath(const DrawPathArgs&) override;
using INHERITED = GrPathRenderer;
};
} // namespace skgpu::v1
#endif // AAHairLinePathRenderer_DEFINED

View File

@ -5,7 +5,7 @@
* found in the LICENSE file.
*/
#include "src/gpu/ops/GrAALinearizingConvexPathRenderer.h"
#include "src/gpu/ops/AALinearizingConvexPathRenderer.h"
#include "include/core/SkString.h"
#include "src/core/SkGeometry.h"
@ -28,71 +28,22 @@
#include "src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h"
#include "src/gpu/v1/SurfaceDrawContext_v1.h"
///////////////////////////////////////////////////////////////////////////////
namespace {
static const int DEFAULT_BUFFER_SIZE = 100;
// The thicker the stroke, the harder it is to produce high-quality results using tessellation. For
// the time being, we simply drop back to software rendering above this stroke width.
static const SkScalar kMaxStrokeWidth = 20.0;
GrAALinearizingConvexPathRenderer::GrAALinearizingConvexPathRenderer() = default;
///////////////////////////////////////////////////////////////////////////////
GrPathRenderer::CanDrawPath
GrAALinearizingConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
if (GrAAType::kCoverage != args.fAAType) {
return CanDrawPath::kNo;
}
if (!args.fShape->knownToBeConvex()) {
return CanDrawPath::kNo;
}
if (args.fShape->style().pathEffect()) {
return CanDrawPath::kNo;
}
if (args.fShape->inverseFilled()) {
return CanDrawPath::kNo;
}
if (args.fShape->bounds().width() <= 0 && args.fShape->bounds().height() <= 0) {
// Stroked zero length lines should draw, but this PR doesn't handle that case
return CanDrawPath::kNo;
}
const SkStrokeRec& stroke = args.fShape->style().strokeRec();
if (stroke.getStyle() == SkStrokeRec::kStroke_Style ||
stroke.getStyle() == SkStrokeRec::kStrokeAndFill_Style) {
if (!args.fViewMatrix->isSimilarity()) {
return CanDrawPath::kNo;
}
SkScalar strokeWidth = args.fViewMatrix->getMaxScale() * stroke.getWidth();
if (strokeWidth < 1.0f && stroke.getStyle() == SkStrokeRec::kStroke_Style) {
return CanDrawPath::kNo;
}
if (strokeWidth > kMaxStrokeWidth ||
!args.fShape->knownToBeClosed() ||
stroke.getJoin() == SkPaint::Join::kRound_Join) {
return CanDrawPath::kNo;
}
return CanDrawPath::kYes;
}
if (stroke.getStyle() != SkStrokeRec::kFill_Style) {
return CanDrawPath::kNo;
}
// This can almost handle perspective. It would need to use 3 component explicit local coords
// when there are FPs that require them. This is difficult to test because AAConvexPathRenderer
// takes almost all filled paths that could get here. So just avoid perspective fills.
if (args.fViewMatrix->hasPerspective()) {
return CanDrawPath::kNo;
}
return CanDrawPath::kYes;
}
// extract the result vertices and indices from the GrAAConvexTessellator
static void extract_verts(const GrAAConvexTessellator& tess,
const SkMatrix* localCoordsMatrix,
void* vertData,
const GrVertexColor& color,
uint16_t firstIndex,
uint16_t* idxs) {
void extract_verts(const GrAAConvexTessellator& tess,
const SkMatrix* localCoordsMatrix,
void* vertData,
const GrVertexColor& color,
uint16_t firstIndex,
uint16_t* idxs) {
GrVertexWriter verts{vertData};
for (int i = 0; i < tess.numPts(); ++i) {
SkPoint lc;
@ -108,10 +59,10 @@ static void extract_verts(const GrAAConvexTessellator& tess,
}
}
static GrGeometryProcessor* create_lines_only_gp(SkArenaAlloc* arena,
bool tweakAlphaForCoverage,
bool usesLocalCoords,
bool wideColor) {
GrGeometryProcessor* create_lines_only_gp(SkArenaAlloc* arena,
bool tweakAlphaForCoverage,
bool usesLocalCoords,
bool wideColor) {
using namespace GrDefaultGeoProcFactory;
Coverage::Type coverageType =
@ -124,8 +75,6 @@ static GrGeometryProcessor* create_lines_only_gp(SkArenaAlloc* arena,
return Make(arena, colorType, coverageType, localCoordsType, SkMatrix::I());
}
namespace {
class AAFlatteningConvexPathOp final : public GrMeshDrawOp {
private:
using Helper = GrSimpleMeshDrawOpHelperWithStencil;
@ -388,28 +337,6 @@ private:
} // anonymous namespace
bool GrAALinearizingConvexPathRenderer::onDrawPath(const DrawPathArgs& args) {
GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(),
"GrAALinearizingConvexPathRenderer::onDrawPath");
SkASSERT(args.fSurfaceDrawContext->numSamples() <= 1);
SkASSERT(!args.fShape->isEmpty());
SkASSERT(!args.fShape->style().pathEffect());
SkPath path;
args.fShape->asPath(&path);
bool fill = args.fShape->style().isSimpleFill();
const SkStrokeRec& stroke = args.fShape->style().strokeRec();
SkScalar strokeWidth = fill ? -1.0f : stroke.getWidth();
SkPaint::Join join = fill ? SkPaint::Join::kMiter_Join : stroke.getJoin();
SkScalar miterLimit = stroke.getMiter();
GrOp::Owner op = AAFlatteningConvexPathOp::Make(
args.fContext, std::move(args.fPaint), *args.fViewMatrix, path, strokeWidth,
stroke.getStyle(), join, miterLimit, args.fUserStencilSettings);
args.fSurfaceDrawContext->addDrawOp(args.fClip, std::move(op));
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
#if GR_TEST_UTILS
@ -443,3 +370,79 @@ GR_DRAW_OP_TEST_DEFINE(AAFlatteningConvexPathOp) {
}
#endif
///////////////////////////////////////////////////////////////////////////////
namespace skgpu::v1 {
GrPathRenderer::CanDrawPath
AALinearizingConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
if (GrAAType::kCoverage != args.fAAType) {
return CanDrawPath::kNo;
}
if (!args.fShape->knownToBeConvex()) {
return CanDrawPath::kNo;
}
if (args.fShape->style().pathEffect()) {
return CanDrawPath::kNo;
}
if (args.fShape->inverseFilled()) {
return CanDrawPath::kNo;
}
if (args.fShape->bounds().width() <= 0 && args.fShape->bounds().height() <= 0) {
// Stroked zero length lines should draw, but this PR doesn't handle that case
return CanDrawPath::kNo;
}
const SkStrokeRec& stroke = args.fShape->style().strokeRec();
if (stroke.getStyle() == SkStrokeRec::kStroke_Style ||
stroke.getStyle() == SkStrokeRec::kStrokeAndFill_Style) {
if (!args.fViewMatrix->isSimilarity()) {
return CanDrawPath::kNo;
}
SkScalar strokeWidth = args.fViewMatrix->getMaxScale() * stroke.getWidth();
if (strokeWidth < 1.0f && stroke.getStyle() == SkStrokeRec::kStroke_Style) {
return CanDrawPath::kNo;
}
if (strokeWidth > kMaxStrokeWidth ||
!args.fShape->knownToBeClosed() ||
stroke.getJoin() == SkPaint::Join::kRound_Join) {
return CanDrawPath::kNo;
}
return CanDrawPath::kYes;
}
if (stroke.getStyle() != SkStrokeRec::kFill_Style) {
return CanDrawPath::kNo;
}
// This can almost handle perspective. It would need to use 3 component explicit local coords
// when there are FPs that require them. This is difficult to test because AAConvexPathRenderer
// takes almost all filled paths that could get here. So just avoid perspective fills.
if (args.fViewMatrix->hasPerspective()) {
return CanDrawPath::kNo;
}
return CanDrawPath::kYes;
}
bool AALinearizingConvexPathRenderer::onDrawPath(const DrawPathArgs& args) {
GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(),
"AALinearizingConvexPathRenderer::onDrawPath");
SkASSERT(args.fSurfaceDrawContext->numSamples() <= 1);
SkASSERT(!args.fShape->isEmpty());
SkASSERT(!args.fShape->style().pathEffect());
SkPath path;
args.fShape->asPath(&path);
bool fill = args.fShape->style().isSimpleFill();
const SkStrokeRec& stroke = args.fShape->style().strokeRec();
SkScalar strokeWidth = fill ? -1.0f : stroke.getWidth();
SkPaint::Join join = fill ? SkPaint::Join::kMiter_Join : stroke.getJoin();
SkScalar miterLimit = stroke.getMiter();
GrOp::Owner op = AAFlatteningConvexPathOp::Make(
args.fContext, std::move(args.fPaint), *args.fViewMatrix, path, strokeWidth,
stroke.getStyle(), join, miterLimit, args.fUserStencilSettings);
args.fSurfaceDrawContext->addDrawOp(args.fClip, std::move(op));
return true;
}
} // namespace skgpu::v1

View File

@ -0,0 +1,31 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef AALinearizingConvexPathRenderer_DEFINED
#define AALinearizingConvexPathRenderer_DEFINED
#include "src/gpu/GrPathRenderer.h"
namespace skgpu::v1 {
class AALinearizingConvexPathRenderer final : public GrPathRenderer {
public:
AALinearizingConvexPathRenderer() = default;
const char* name() const override { return "AALinear"; }
private:
CanDrawPath onCanDrawPath(const CanDrawPathArgs&) const override;
bool onDrawPath(const DrawPathArgs&) override;
using INHERITED = GrPathRenderer;
};
} // namespace skgpu::v1
#endif // AALinearizingConvexPathRenderer_DEFINED

View File

@ -5,7 +5,7 @@
* found in the LICENSE file.
*/
#include "src/gpu/ops/GrDashLinePathRenderer.h"
#include "src/gpu/ops/DashLinePathRenderer.h"
#include "src/gpu/GrAuditTrail.h"
#include "src/gpu/GrGpu.h"
@ -14,8 +14,9 @@
#include "src/gpu/ops/GrMeshDrawOp.h"
#include "src/gpu/v1/SurfaceDrawContext_v1.h"
GrPathRenderer::CanDrawPath
GrDashLinePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
namespace skgpu::v1 {
GrPathRenderer::CanDrawPath DashLinePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
SkPoint pts[2];
bool inverted;
if (args.fShape->style().isDashed() && args.fShape->asLine(pts, &inverted)) {
@ -29,9 +30,9 @@ GrDashLinePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
return CanDrawPath::kNo;
}
bool GrDashLinePathRenderer::onDrawPath(const DrawPathArgs& args) {
bool DashLinePathRenderer::onDrawPath(const DrawPathArgs& args) {
GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(),
"GrDashLinePathRenderer::onDrawPath");
"DashLinePathRenderer::onDrawPath");
GrDashOp::AAMode aaMode;
switch (args.fAAType) {
case GrAAType::kNone:
@ -57,3 +58,5 @@ bool GrDashLinePathRenderer::onDrawPath(const DrawPathArgs& args) {
args.fSurfaceDrawContext->addDrawOp(args.fClip, std::move(op));
return true;
}
} // namespace skgpu::v1

View File

@ -5,17 +5,22 @@
* found in the LICENSE file.
*/
#ifndef GrDashLinePathRenderer_DEFINED
#define GrDashLinePathRenderer_DEFINED
#ifndef DashLinePathRenderer_DEFINED
#define DashLinePathRenderer_DEFINED
#include "src/gpu/GrPathRenderer.h"
class GrGpu;
class GrDashLinePathRenderer : public GrPathRenderer {
private:
const char* name() const final { return "DashLine"; }
namespace skgpu::v1 {
class DashLinePathRenderer final : public GrPathRenderer {
public:
DashLinePathRenderer() = default;
const char* name() const override { return "DashLine"; }
private:
CanDrawPath onCanDrawPath(const CanDrawPathArgs&) const override;
StencilSupport onGetStencilSupport(const GrStyledShape&) const override {
@ -25,8 +30,10 @@ private:
bool onDrawPath(const DrawPathArgs&) override;
sk_sp<GrGpu> fGpu;
using INHERITED = GrPathRenderer;
};
} // namespace skgpu::v1
#endif
#endif // DashLinePathRenderer_DEFINED

View File

@ -5,7 +5,7 @@
* found in the LICENSE file.
*/
#include "src/gpu/ops/GrDefaultPathRenderer.h"
#include "src/gpu/ops/DefaultPathRenderer.h"
#include "include/core/SkString.h"
#include "include/core/SkStrokeRec.h"
@ -30,15 +30,14 @@
#include "src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h"
#include "src/gpu/v1/SurfaceDrawContext_v1.h"
GrDefaultPathRenderer::GrDefaultPathRenderer() {
}
////////////////////////////////////////////////////////////////////////////////
// Helpers for drawPath
namespace {
#define STENCIL_OFF 0 // Always disable stencil (even when needed)
static inline bool single_pass_shape(const GrStyledShape& shape) {
inline bool single_pass_shape(const GrStyledShape& shape) {
#if STENCIL_OFF
return true;
#else
@ -56,17 +55,6 @@ static inline bool single_pass_shape(const GrStyledShape& shape) {
#endif
}
GrPathRenderer::StencilSupport
GrDefaultPathRenderer::onGetStencilSupport(const GrStyledShape& shape) const {
if (single_pass_shape(shape)) {
return GrPathRenderer::kNoRestriction_StencilSupport;
} else {
return GrPathRenderer::kStencilOnly_StencilSupport;
}
}
namespace {
class PathGeoBuilder {
public:
PathGeoBuilder(GrPrimitiveType primitiveType,
@ -253,7 +241,7 @@ private:
&fFirstVertex,
&fVerticesInChunk));
if (!fVertices) {
SkDebugf("WARNING: Failed to allocate vertex buffer for GrDefaultPathRenderer.\n");
SkDebugf("WARNING: Failed to allocate vertex buffer for DefaultPathRenderer.\n");
fCurVert = nullptr;
fCurIdx = fIndices = nullptr;
fSubpathIndexStart = 0;
@ -272,7 +260,7 @@ private:
&fIndexBuffer, &fFirstIndex,
&fIndicesInChunk);
if (!fIndices) {
SkDebugf("WARNING: Failed to allocate index buffer for GrDefaultPathRenderer.\n");
SkDebugf("WARNING: Failed to allocate index buffer for DefaultPathRenderer.\n");
fVertices = nullptr;
fValid = false;
}
@ -592,14 +580,47 @@ private:
} // anonymous namespace
bool GrDefaultPathRenderer::internalDrawPath(skgpu::v1::SurfaceDrawContext* sdc,
GrPaint&& paint,
GrAAType aaType,
const GrUserStencilSettings& userStencilSettings,
const GrClip* clip,
const SkMatrix& viewMatrix,
const GrStyledShape& shape,
bool stencilOnly) {
///////////////////////////////////////////////////////////////////////////////////////////////////
#if GR_TEST_UTILS
GR_DRAW_OP_TEST_DEFINE(DefaultPathOp) {
SkMatrix viewMatrix = GrTest::TestMatrix(random);
// For now just hairlines because the other types of draws require two ops.
// TODO we should figure out a way to combine the stencil and cover steps into one op.
GrStyle style(SkStrokeRec::kHairline_InitStyle);
const SkPath& path = GrTest::TestPath(random);
// Compute srcSpaceTol
SkRect bounds = path.getBounds();
SkScalar tol = GrPathUtils::kDefaultTolerance;
SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, bounds);
viewMatrix.mapRect(&bounds);
uint8_t coverage = GrRandomCoverage(random);
GrAAType aaType = GrAAType::kNone;
if (numSamples > 1 && random->nextBool()) {
aaType = GrAAType::kMSAA;
}
return DefaultPathOp::Make(context, std::move(paint), path, srcSpaceTol, coverage, viewMatrix,
true, aaType, bounds, GrGetRandomStencil(random, context));
}
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////
namespace skgpu::v1 {
bool DefaultPathRenderer::internalDrawPath(skgpu::v1::SurfaceDrawContext* sdc,
GrPaint&& paint,
GrAAType aaType,
const GrUserStencilSettings& userStencilSettings,
const GrClip* clip,
const SkMatrix& viewMatrix,
const GrStyledShape& shape,
bool stencilOnly) {
auto context = sdc->recordingContext();
SkASSERT(GrAAType::kCoverage != aaType);
@ -737,8 +758,17 @@ bool GrDefaultPathRenderer::internalDrawPath(skgpu::v1::SurfaceDrawContext* sdc,
return true;
}
GrPathRenderer::CanDrawPath
GrDefaultPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
GrPathRenderer::StencilSupport
DefaultPathRenderer::onGetStencilSupport(const GrStyledShape& shape) const {
if (single_pass_shape(shape)) {
return GrPathRenderer::kNoRestriction_StencilSupport;
} else {
return GrPathRenderer::kStencilOnly_StencilSupport;
}
}
GrPathRenderer::CanDrawPath DefaultPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
bool isHairline = GrIsStrokeHairlineOrEquivalent(
args.fShape->style(), *args.fViewMatrix, nullptr);
// If we aren't a single_pass_shape or hairline, we require stencil buffers.
@ -758,9 +788,9 @@ GrDefaultPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
return CanDrawPath::kAsBackup;
}
bool GrDefaultPathRenderer::onDrawPath(const DrawPathArgs& args) {
bool DefaultPathRenderer::onDrawPath(const DrawPathArgs& args) {
GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(),
"GrDefaultPathRenderer::onDrawPath");
"DefaultPathRenderer::onDrawPath");
GrAAType aaType = (GrAAType::kNone != args.fAAType) ? GrAAType::kMSAA : GrAAType::kNone;
return this->internalDrawPath(
@ -768,9 +798,9 @@ bool GrDefaultPathRenderer::onDrawPath(const DrawPathArgs& args) {
args.fClip, *args.fViewMatrix, *args.fShape, false);
}
void GrDefaultPathRenderer::onStencilPath(const StencilPathArgs& args) {
void DefaultPathRenderer::onStencilPath(const StencilPathArgs& args) {
GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(),
"GrDefaultPathRenderer::onStencilPath");
"DefaultPathRenderer::onStencilPath");
SkASSERT(!args.fShape->inverseFilled());
GrPaint paint;
@ -783,31 +813,4 @@ void GrDefaultPathRenderer::onStencilPath(const StencilPathArgs& args) {
args.fClip, *args.fViewMatrix, *args.fShape, true);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
#if GR_TEST_UTILS
GR_DRAW_OP_TEST_DEFINE(DefaultPathOp) {
SkMatrix viewMatrix = GrTest::TestMatrix(random);
// For now just hairlines because the other types of draws require two ops.
// TODO we should figure out a way to combine the stencil and cover steps into one op.
GrStyle style(SkStrokeRec::kHairline_InitStyle);
const SkPath& path = GrTest::TestPath(random);
// Compute srcSpaceTol
SkRect bounds = path.getBounds();
SkScalar tol = GrPathUtils::kDefaultTolerance;
SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, bounds);
viewMatrix.mapRect(&bounds);
uint8_t coverage = GrRandomCoverage(random);
GrAAType aaType = GrAAType::kNone;
if (numSamples > 1 && random->nextBool()) {
aaType = GrAAType::kMSAA;
}
return DefaultPathOp::Make(context, std::move(paint), path, srcSpaceTol, coverage, viewMatrix,
true, aaType, bounds, GrGetRandomStencil(random, context));
}
#endif
} // namespace skgpu::v1

View File

@ -5,22 +5,24 @@
* found in the LICENSE file.
*/
#ifndef GrDefaultPathRenderer_DEFINED
#define GrDefaultPathRenderer_DEFINED
#ifndef DefaultPathRenderer_DEFINED
#define DefaultPathRenderer_DEFINED
#include "include/core/SkTypes.h"
#include "src/gpu/GrPathRenderer.h"
#include "src/gpu/ops/GrPathStencilSettings.h"
namespace skgpu::v1 {
/**
* Subclass that renders the path using the stencil buffer to resolve fill rules
* (e.g. winding, even-odd)
*/
class GrDefaultPathRenderer : public GrPathRenderer {
class DefaultPathRenderer final : public GrPathRenderer {
public:
GrDefaultPathRenderer();
DefaultPathRenderer() = default;
const char* name() const final { return "Default"; }
const char* name() const override { return "Default"; }
private:
StencilSupport onGetStencilSupport(const GrStyledShape&) const override;
@ -43,4 +45,6 @@ private:
using INHERITED = GrPathRenderer;
};
#endif
} // namespace skgpu::v1
#endif // DefaultPathRenderer_DEFINED

View File

@ -1,25 +0,0 @@
/*
* Copyright 2012 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrAAConvexPathRenderer_DEFINED
#define GrAAConvexPathRenderer_DEFINED
#include "src/gpu/GrPathRenderer.h"
class GrAAConvexPathRenderer : public GrPathRenderer {
public:
const char* name() const final { return "AAConvex"; }
GrAAConvexPathRenderer();
private:
CanDrawPath onCanDrawPath(const CanDrawPathArgs&) const override;
bool onDrawPath(const DrawPathArgs&) override;
};
#endif

View File

@ -1,32 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrAAHairLinePathRenderer_DEFINED
#define GrAAHairLinePathRenderer_DEFINED
#include "src/gpu/GrPathRenderer.h"
class GrAAHairLinePathRenderer : public GrPathRenderer {
public:
GrAAHairLinePathRenderer() {}
const char* name() const final { return "AAHairline"; }
typedef SkTArray<SkPoint, true> PtArray;
typedef SkTArray<int, true> IntArray;
typedef SkTArray<float, true> FloatArray;
private:
CanDrawPath onCanDrawPath(const CanDrawPathArgs&) const override;
bool onDrawPath(const DrawPathArgs&) override;
using INHERITED = GrPathRenderer;
};
#endif

View File

@ -1,25 +0,0 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrAALinearizingConvexPathRenderer_DEFINED
#define GrAALinearizingConvexPathRenderer_DEFINED
#include "src/gpu/GrPathRenderer.h"
class GrAALinearizingConvexPathRenderer : public GrPathRenderer {
public:
const char* name() const final { return "AALinear"; }
GrAALinearizingConvexPathRenderer();
private:
CanDrawPath onCanDrawPath(const CanDrawPathArgs&) const override;
bool onDrawPath(const DrawPathArgs&) override;
};
#endif

View File

@ -72,7 +72,7 @@ static const int kPad = 3;
// create a new render target context that will reuse the prior GrSurface
// draw a normally wound concave path that touches outside of the approx fit RTC's content rect
//
// When the bug manifests the GrDefaultPathRenderer/GrMSAAPathRenderer is/was leaving the stencil
// When the bug manifests the DefaultPathRenderer/GrMSAAPathRenderer is/was leaving the stencil
// buffer outside of the first content rect in a bad state and the second draw would be incorrect.
static void run_test(GrDirectContext* dContext, skiatest::Reporter* reporter) {
@ -130,7 +130,7 @@ static void run_test(GrDirectContext* dContext, skiatest::Reporter* reporter) {
}
}
DEF_GPUTEST_FOR_CONTEXTS(GrDefaultPathRendererTest,
DEF_GPUTEST_FOR_CONTEXTS(DefaultPathRendererTest,
sk_gpu_test::GrContextFactory::IsRenderingContext,
reporter, ctxInfo, only_allow_default) {
auto ctx = ctxInfo.directContext();

View File

@ -114,7 +114,7 @@ DEF_GPUTEST_FOR_ALL_CONTEXTS(GrDrawCollapsedPath, reporter, ctxInfo) {
}
DEF_GPUTEST_FOR_ALL_CONTEXTS(PathTest_CrBug1232834, reporter, ctxInfo) {
// GrAAHairlinePathRenderer chops this path to quads that include infinities (and then NaNs).
// AAHairlinePathRenderer chops this path to quads that include infinities (and then NaNs).
// It used to trigger asserts, now the degenerate quad segments should cause it to be rejected.
SkImageInfo info = SkImageInfo::MakeN32Premul(256, 256);
auto surface(SkSurface::MakeRenderTarget(ctxInfo.directContext(), SkBudgeted::kNo, info));