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" #include "include/core/SkPathBuilder.h"
DEF_SIMPLE_GM(crbug_847759, canvas, 500, 500) { 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 // 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 // squashed oval-like path became slightly non-vertical. This caused a missed pixel of AA just
// outside each tip. // outside each tip.

View File

@ -513,12 +513,16 @@ skia_skgpu_v1_sources = [
"$_src/gpu/GrStencilMaskHelper.h", "$_src/gpu/GrStencilMaskHelper.h",
# Ops # Ops
"$_src/gpu/ops/GrAAConvexPathRenderer.cpp", "$_src/gpu/ops/AAConvexPathRenderer.cpp",
"$_src/gpu/ops/GrAAConvexPathRenderer.h", "$_src/gpu/ops/AAConvexPathRenderer.h",
"$_src/gpu/ops/GrAAHairLinePathRenderer.cpp", "$_src/gpu/ops/AAHairLinePathRenderer.cpp",
"$_src/gpu/ops/GrAAHairLinePathRenderer.h", "$_src/gpu/ops/AAHairLinePathRenderer.h",
"$_src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp", "$_src/gpu/ops/AALinearizingConvexPathRenderer.cpp",
"$_src/gpu/ops/GrAALinearizingConvexPathRenderer.h", "$_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.cpp",
"$_src/gpu/ops/GrAtlasInstancedHelper.h", "$_src/gpu/ops/GrAtlasInstancedHelper.h",
"$_src/gpu/ops/GrAtlasPathRenderer.cpp", "$_src/gpu/ops/GrAtlasPathRenderer.cpp",
@ -527,12 +531,8 @@ skia_skgpu_v1_sources = [
"$_src/gpu/ops/GrAtlasTextOp.h", "$_src/gpu/ops/GrAtlasTextOp.h",
"$_src/gpu/ops/GrClearOp.cpp", "$_src/gpu/ops/GrClearOp.cpp",
"$_src/gpu/ops/GrClearOp.h", "$_src/gpu/ops/GrClearOp.h",
"$_src/gpu/ops/GrDashLinePathRenderer.cpp",
"$_src/gpu/ops/GrDashLinePathRenderer.h",
"$_src/gpu/ops/GrDashOp.cpp", "$_src/gpu/ops/GrDashOp.cpp",
"$_src/gpu/ops/GrDashOp.h", "$_src/gpu/ops/GrDashOp.h",
"$_src/gpu/ops/GrDefaultPathRenderer.cpp",
"$_src/gpu/ops/GrDefaultPathRenderer.h",
"$_src/gpu/ops/GrDrawAtlasOp.cpp", "$_src/gpu/ops/GrDrawAtlasOp.cpp",
"$_src/gpu/ops/GrDrawAtlasOp.h", "$_src/gpu/ops/GrDrawAtlasOp.h",
"$_src/gpu/ops/GrDrawAtlasPathOp.cpp", "$_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. * Used to include or exclude specific GPU path renderers for testing purposes.
*/ */
enum class GpuPathRenderers { enum class GpuPathRenderers {
kNone = 0, // Always use software masks and/or GrDefaultPathRenderer. kNone = 0, // Always use software masks and/or DefaultPathRenderer.
kDashLine = 1 << 0, kDashLine = 1 << 0,
kAtlas = 1 << 1, kAtlas = 1 << 1,
kTessellation = 1 << 2, kTessellation = 1 << 2,

View File

@ -16,12 +16,12 @@
#include "src/gpu/GrRecordingContextPriv.h" #include "src/gpu/GrRecordingContextPriv.h"
#include "src/gpu/GrShaderCaps.h" #include "src/gpu/GrShaderCaps.h"
#include "src/gpu/geometry/GrStyledShape.h" #include "src/gpu/geometry/GrStyledShape.h"
#include "src/gpu/ops/GrAAConvexPathRenderer.h" #include "src/gpu/ops/AAConvexPathRenderer.h"
#include "src/gpu/ops/GrAAHairLinePathRenderer.h" #include "src/gpu/ops/AAHairLinePathRenderer.h"
#include "src/gpu/ops/GrAALinearizingConvexPathRenderer.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/GrAtlasPathRenderer.h"
#include "src/gpu/ops/GrDashLinePathRenderer.h"
#include "src/gpu/ops/GrDefaultPathRenderer.h"
#include "src/gpu/ops/GrTriangulatingPathRenderer.h" #include "src/gpu/ops/GrTriangulatingPathRenderer.h"
#include "src/gpu/ops/SmallPathRenderer.h" #include "src/gpu/ops/SmallPathRenderer.h"
#include "src/gpu/tessellate/GrTessellationPathRenderer.h" #include "src/gpu/tessellate/GrTessellationPathRenderer.h"
@ -29,16 +29,16 @@
GrPathRendererChain::GrPathRendererChain(GrRecordingContext* context, const Options& options) { GrPathRendererChain::GrPathRendererChain(GrRecordingContext* context, const Options& options) {
const GrCaps& caps = *context->priv().caps(); const GrCaps& caps = *context->priv().caps();
if (options.fGpuPathRenderers & GpuPathRenderers::kDashLine) { 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) { 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) { 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) { 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 (options.fGpuPathRenderers & GpuPathRenderers::kAtlas) {
if (auto atlasPathRenderer = GrAtlasPathRenderer::Make(context)) { 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 // 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( GrPathRenderer* GrPathRendererChain::getPathRenderer(

View File

@ -623,7 +623,7 @@ void GrAAConvexTessellator::createOuterRing(const Ring& previousRing, SkScalar o
this->addTri(originalIdx, perp1Idx, perp2Idx); this->addTri(originalIdx, perp1Idx, perp2Idx);
break; break;
default: 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. // only willing to draw mitered or beveled, so we should never get here.
SkASSERT(false); 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 // This introduced a large performance regression for tiny paths for no noticeable
// quality improvement. However, we aren't quite fulfilling our contract of guaranteeing // quality improvement. However, we aren't quite fulfilling our contract of guaranteeing
// the two tangent vectors and this could introduce a missed pixel in // the two tangent vectors and this could introduce a missed pixel in
// GrAAHairlinePathRenderer. // AAHairlinePathRenderer.
newC = (c0 + c1) * 0.5f; newC = (c0 + c1) * 0.5f;
} else if (preserveFirstTangent) { } else if (preserveFirstTangent) {
newC = c0; newC = c0;

View File

@ -5,7 +5,7 @@
* found in the LICENSE file. * 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/SkString.h"
#include "include/core/SkTypes.h" #include "include/core/SkTypes.h"
@ -31,8 +31,7 @@
#include "src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h" #include "src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h"
#include "src/gpu/v1/SurfaceDrawContext_v1.h" #include "src/gpu/v1/SurfaceDrawContext_v1.h"
GrAAConvexPathRenderer::GrAAConvexPathRenderer() { namespace {
}
struct Segment { struct Segment {
enum { enum {
@ -65,7 +64,7 @@ struct Segment {
typedef SkTArray<Segment, true> SegmentArray; 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; SkScalar area = 0;
SkPoint center = {0, 0}; SkPoint center = {0, 0};
int count = segments.count(); 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(); return !SkScalarIsNaN(c->fX) && !SkScalarIsNaN(c->fY) && c->isFinite();
} }
static bool compute_vectors(SegmentArray* segments, bool compute_vectors(SegmentArray* segments,
SkPoint* fanPt, SkPoint* fanPt,
SkPathFirstDirection dir, SkPathFirstDirection dir,
int* vCount, int* vCount,
int* iCount) { int* iCount) {
if (!center_of_mass(*segments, fanPt)) { if (!center_of_mass(*segments, fanPt)) {
return false; return false;
} }
@ -195,7 +194,7 @@ struct DegenerateTestData {
static const SkScalar kClose = (SK_Scalar1 / 16); static const SkScalar kClose = (SK_Scalar1 / 16);
static const SkScalar kCloseSqd = kClose * kClose; 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) { switch (data->fStage) {
case DegenerateTestData::kInitial: case DegenerateTestData::kInitial:
data->fFirstPoint = pt; 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, inline bool get_direction(const SkPath& path, const SkMatrix& m, SkPathFirstDirection* dir) {
SkPathFirstDirection* dir) {
// At this point, we've already returned true from canDraw(), which checked that the path's // 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. // 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 // 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; return true;
} }
static inline void add_line_to_segment(const SkPoint& pt, inline void add_line_to_segment(const SkPoint& pt, SegmentArray* segments) {
SegmentArray* segments) {
segments->push_back(); segments->push_back();
segments->back().fType = Segment::kLine; segments->back().fType = Segment::kLine;
segments->back().fPts[0] = pt; segments->back().fPts[0] = pt;
} }
static inline void add_quad_segment(const SkPoint pts[3], inline void add_quad_segment(const SkPoint pts[3], SegmentArray* segments) {
SegmentArray* segments) {
if (SkPointPriv::DistanceToLineSegmentBetweenSqd(pts[1], pts[0], pts[2]) < kCloseSqd) { if (SkPointPriv::DistanceToLineSegmentBetweenSqd(pts[1], pts[0], pts[2]) < kCloseSqd) {
if (pts[0] != pts[2]) { if (pts[0] != pts[2]) {
add_line_to_segment(pts[2], segments); 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], inline void add_cubic_segments(const SkPoint pts[4],
SkPathFirstDirection dir, SkPathFirstDirection dir,
SegmentArray* segments) { SegmentArray* segments) {
SkSTArray<15, SkPoint, true> quads; SkSTArray<15, SkPoint, true> quads;
GrPathUtils::convertCubicToQuadsConstrainToTangents(pts, SK_Scalar1, dir, &quads); GrPathUtils::convertCubicToQuadsConstrainToTangents(pts, SK_Scalar1, dir, &quads);
int count = quads.count(); 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, bool get_segments(const SkPath& path,
const SkMatrix& m, const SkMatrix& m,
SegmentArray* segments, SegmentArray* segments,
SkPoint* fanPt, SkPoint* fanPt,
int* vCount, int* vCount,
int* iCount) { int* iCount) {
SkPath::Iter iter(path, true); SkPath::Iter iter(path, true);
// This renderer over-emphasizes very thin path regions. We use the distance // This renderer over-emphasizes very thin path regions. We use the distance
// to the path from the sample to compute coverage. Every pixel intersected // to the path from the sample to compute coverage. Every pixel intersected
@ -364,13 +360,13 @@ struct Draw {
typedef SkTArray<Draw, true> DrawArray; typedef SkTArray<Draw, true> DrawArray;
static void create_vertices(const SegmentArray& segments, void create_vertices(const SegmentArray& segments,
const SkPoint& fanPt, const SkPoint& fanPt,
const GrVertexColor& color, const GrVertexColor& color,
DrawArray* draws, DrawArray* draws,
GrVertexWriter& verts, GrVertexWriter& verts,
uint16_t* idxs, uint16_t* idxs,
size_t vertexStride) { size_t vertexStride) {
Draw* draw = &draws->push_back(); Draw* draw = &draws->push_back();
// alias just to make vert/index assignments easier to read. // alias just to make vert/index assignments easier to read.
int* v = &draw->fVertexCnt; int* v = &draw->fVertexCnt;
@ -682,23 +678,6 @@ GrGeometryProcessor* QuadEdgeEffect::TestCreate(GrProcessorTestData* d) {
} }
#endif #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 { class AAConvexPathOp final : public GrMeshDrawOp {
private: private:
using Helper = GrSimpleMeshDrawOpHelperWithStencil; using Helper = GrSimpleMeshDrawOpHelperWithStencil;
@ -912,23 +891,7 @@ private:
using INHERITED = GrMeshDrawOp; using INHERITED = GrMeshDrawOp;
}; };
} // anonymous namespace } // 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;
}
/////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////
@ -942,3 +905,37 @@ GR_DRAW_OP_TEST_DEFINE(AAConvexPathOp) {
} }
#endif #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. * found in the LICENSE file.
*/ */
#include "src/gpu/ops/GrAAHairLinePathRenderer.h" #include "src/gpu/ops/AAHairLinePathRenderer.h"
#include "include/core/SkPoint3.h" #include "include/core/SkPoint3.h"
#include "include/private/SkTemplates.h" #include "include/private/SkTemplates.h"
@ -34,6 +34,12 @@
#define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true> #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 // 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 // AA stroke around the center-curve. See comments in push_quad_index_buffer and
// bloat_quad. Quadratics and conics share an index buffer // bloat_quad. Quadratics and conics share an index buffer
@ -71,7 +77,7 @@ static const int kQuadNumVertices = 5;
static const int kQuadsNumInIdxBuffer = 256; static const int kQuadsNumInIdxBuffer = 256;
GR_DECLARE_STATIC_UNIQUE_KEY(gQuadsIndexBufferKey); 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); GR_DEFINE_STATIC_UNIQUE_KEY(gQuadsIndexBufferKey);
return resourceProvider->findOrCreatePatternedIndexBuffer( return resourceProvider->findOrCreatePatternedIndexBuffer(
kQuadIdxBufPattern, kIdxsPerQuad, kQuadsNumInIdxBuffer, kQuadNumVertices, kQuadIdxBufPattern, kIdxsPerQuad, kQuadsNumInIdxBuffer, kQuadNumVertices,
@ -105,7 +111,7 @@ static const int kLineSegsNumInIdxBuffer = 256;
GR_DECLARE_STATIC_UNIQUE_KEY(gLinesIndexBufferKey); 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); GR_DEFINE_STATIC_UNIQUE_KEY(gLinesIndexBufferKey);
return resourceProvider->findOrCreatePatternedIndexBuffer( return resourceProvider->findOrCreatePatternedIndexBuffer(
kLineSegIdxBufPattern, kIdxsPerLineSeg, kLineSegsNumInIdxBuffer, kLineSegNumVertices, 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 // 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)); static_assert(sizeof(int) == sizeof(float));
#ifdef SK_DEBUG #ifdef SK_DEBUG
static bool tested; static bool tested;
@ -141,7 +147,7 @@ static int get_float_exp(float x) {
// found along the curve segment it will return 1 and // found along the curve segment it will return 1 and
// dst[0] is the original conic. If it returns 2 the dst[0] // dst[0] is the original conic. If it returns 2 the dst[0]
// and dst[1] are the two new conics. // 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); SkScalar t = SkFindQuadMaxCurvature(src);
if (t == 0 || t == 1) { if (t == 0 || t == 1) {
if (dst) { 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. // 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) // 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). // 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]; SkConic dstTemp[2];
int conicCnt = split_conic(src, dstTemp, weight); int conicCnt = split_conic(src, dstTemp, weight);
if (2 == conicCnt) { 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 // returns 0 if quad/conic is degen or close to it
// in this case approx the path with lines // in this case approx the path with lines
// otherwise returns 1 // 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 gDegenerateToLineTol = GrPathUtils::kDefaultTolerance;
static const SkScalar gDegenerateToLineTolSqd = static const SkScalar gDegenerateToLineTolSqd =
gDegenerateToLineTol * gDegenerateToLineTol; gDegenerateToLineTol * gDegenerateToLineTol;
@ -200,14 +206,14 @@ static int is_degen_quad_or_conic(const SkPoint p[3], SkScalar* dsqd) {
return 0; 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; SkScalar dsqd;
return is_degen_quad_or_conic(p, &dsqd); return is_degen_quad_or_conic(p, &dsqd);
} }
// we subdivide the quads to avoid huge overfill // we subdivide the quads to avoid huge overfill
// if it returns -1 then should be drawn as lines // 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; SkScalar dsqd;
if (is_degen_quad_or_conic(p, &dsqd)) { if (is_degen_quad_or_conic(p, &dsqd)) {
return -1; 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 * subdivide large quads to reduce over-fill. This subdivision has to be
* performed before applying the perspective matrix. * performed before applying the perspective matrix.
*/ */
static int gather_lines_and_quads(const SkPath& path, int gather_lines_and_quads(const SkPath& path,
const SkMatrix& m, const SkMatrix& m,
const SkIRect& devClipBounds, const SkIRect& devClipBounds,
SkScalar capLength, SkScalar capLength,
bool convertConicsToQuads, bool convertConicsToQuads,
GrAAHairLinePathRenderer::PtArray* lines, PtArray* lines,
GrAAHairLinePathRenderer::PtArray* quads, PtArray* quads,
GrAAHairLinePathRenderer::PtArray* conics, PtArray* conics,
GrAAHairLinePathRenderer::IntArray* quadSubdivCnts, IntArray* quadSubdivCnts,
GrAAHairLinePathRenderer::FloatArray* conicWeights) { FloatArray* conicWeights) {
SkPath::Iter iter(path, false); SkPath::Iter iter(path, false);
int totalQuadCount = 0; int totalQuadCount = 0;
@ -492,9 +498,9 @@ struct BezierVertex {
static_assert(sizeof(BezierVertex) == 3 * sizeof(SkPoint)); static_assert(sizeof(BezierVertex) == 3 * sizeof(SkPoint));
static void intersect_lines(const SkPoint& ptA, const SkVector& normA, void intersect_lines(const SkPoint& ptA, const SkVector& normA,
const SkPoint& ptB, const SkVector& normB, const SkPoint& ptB, const SkVector& normB,
SkPoint* result) { SkPoint* result) {
SkScalar lineAW = -normA.dot(ptA); SkScalar lineAW = -normA.dot(ptA);
SkScalar lineBW = -normB.dot(ptB); 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 // this should be in the src space, not dev coords, when we have perspective
GrPathUtils::QuadUVMatrix DevToUV(qpts); GrPathUtils::QuadUVMatrix DevToUV(qpts);
DevToUV.apply(verts, kQuadNumVertices, sizeof(BezierVertex), sizeof(SkPoint)); DevToUV.apply(verts, kQuadNumVertices, sizeof(BezierVertex), sizeof(SkPoint));
} }
static void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, void bloat_quad(const SkPoint qpts[3],
const SkMatrix* toSrc, BezierVertex verts[kQuadNumVertices]) { const SkMatrix* toDevice,
const SkMatrix* toSrc,
BezierVertex verts[kQuadNumVertices]) {
SkASSERT(!toDevice == !toSrc); SkASSERT(!toDevice == !toSrc);
// original quad is specified by tri a,b,c // original quad is specified by tri a,b,c
SkPoint a = qpts[0]; 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 // f(x, y, w) = f(P) = K^2 - LM
// K = dot(k, P), L = dot(l, P), M = dot(m, P) // K = dot(k, P), L = dot(l, P), M = dot(m, P)
// k, l, m are calculated in function GrPathUtils::getConicKLM // k, l, m are calculated in function GrPathUtils::getConicKLM
static void set_conic_coeffs(const SkPoint p[3], BezierVertex verts[kQuadNumVertices], void set_conic_coeffs(const SkPoint p[3],
const SkScalar weight) { BezierVertex verts[kQuadNumVertices],
const SkScalar weight) {
SkMatrix klm; SkMatrix klm;
GrPathUtils::getConicKLM(p, weight, &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], void add_conics(const SkPoint p[3],
const SkScalar weight, const SkScalar weight,
const SkMatrix* toDevice, const SkMatrix* toDevice,
const SkMatrix* toSrc, const SkMatrix* toSrc,
BezierVertex** vert) { BezierVertex** vert) {
bloat_quad(p, toDevice, toSrc, *vert); bloat_quad(p, toDevice, toSrc, *vert);
set_conic_coeffs(p, *vert, weight); set_conic_coeffs(p, *vert, weight);
*vert += kQuadNumVertices; *vert += kQuadNumVertices;
} }
static void add_quads(const SkPoint p[3], void add_quads(const SkPoint p[3],
int subdiv, int subdiv,
const SkMatrix* toDevice, const SkMatrix* toDevice,
const SkMatrix* toSrc, const SkMatrix* toSrc,
BezierVertex** vert) { BezierVertex** vert) {
SkASSERT(subdiv >= 0); SkASSERT(subdiv >= 0);
// temporary vertex storage to avoid reading the vertex buffer // temporary vertex storage to avoid reading the vertex buffer
BezierVertex outVerts[kQuadNumVertices] = {}; BezierVertex outVerts[kQuadNumVertices] = {};
@ -670,10 +679,10 @@ static void add_quads(const SkPoint p[3],
*vert += kQuadNumVertices; *vert += kQuadNumVertices;
} }
static void add_line(const SkPoint p[2], void add_line(const SkPoint p[2],
const SkMatrix* toSrc, const SkMatrix* toSrc,
uint8_t coverage, uint8_t coverage,
LineVertex** vert) { LineVertex** vert) {
const SkPoint& a = p[0]; const SkPoint& a = p[0];
const SkPoint& b = p[1]; 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 { class AAHairlineOp final : public GrMeshDrawOp {
private: private:
using Helper = GrSimpleMeshDrawOpHelperWithStencil; using Helper = GrSimpleMeshDrawOpHelperWithStencil;
@ -869,11 +818,11 @@ public:
nullptr); nullptr);
} }
enum Program : uint8_t { enum class Program : uint8_t {
kNone_Program = 0x0, kNone = 0x0,
kLine_Program = 0x1, kLine = 0x1,
kQuad_Program = 0x2, kQuad = 0x2,
kConic_Program = 0x4, kConic = 0x4,
}; };
private: private:
@ -924,10 +873,6 @@ private:
void onPrepareDraws(GrMeshDrawTarget*) override; void onPrepareDraws(GrMeshDrawTarget*) override;
void onExecute(GrOpFlushState*, const SkRect& chainBounds) 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 { CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps) override {
AAHairlineOp* that = t->cast<AAHairlineOp>(); AAHairlineOp* that = t->cast<AAHairlineOp>();
@ -989,14 +934,14 @@ private:
SkPMColor4f fColor; SkPMColor4f fColor;
uint8_t fCoverage; 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 }; GrSimpleMesh* fMeshes[3] = { nullptr };
GrProgramInfo* fProgramInfos[3] = { nullptr }; GrProgramInfo* fProgramInfos[3] = { nullptr };
using INHERITED = GrMeshDrawOp; using INHERITED = GrMeshDrawOp;
}; };
GR_MAKE_BITFIELD_OPS(AAHairlineOp::Program) GR_MAKE_BITFIELD_CLASS_OPS(AAHairlineOp::Program)
void AAHairlineOp::makeLineProgramInfo(const GrCaps& caps, SkArenaAlloc* arena, void AAHairlineOp::makeLineProgramInfo(const GrCaps& caps, SkArenaAlloc* arena,
const GrPipeline* pipeline, 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 // 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 // for quads and conics. In non-DDL mode there are cases where it sometimes isn't needed for a
// given path. // given path.
Program neededPrograms = kLine_Program; Program neededPrograms = Program::kLine;
for (int i = 0; i < fPaths.count(); i++) { for (int i = 0; i < fPaths.count(); i++) {
uint32_t mask = fPaths[i].fPath.getSegmentMasks(); uint32_t mask = fPaths[i].fPath.getSegmentMasks();
if (mask & (SkPath::kQuad_SegmentMask | SkPath::kCubic_SegmentMask)) { if (mask & (SkPath::kQuad_SegmentMask | SkPath::kCubic_SegmentMask)) {
neededPrograms |= kQuad_Program; neededPrograms |= Program::kQuad;
} }
if (mask & SkPath::kConic_SegmentMask) { if (mask & SkPath::kConic_SegmentMask) {
if (convertConicsToQuads) { if (convertConicsToQuads) {
neededPrograms |= kQuad_Program; neededPrograms |= Program::kQuad;
} else { } 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(), auto pipeline = fHelper.createPipeline(caps, arena, writeView.swizzle(),
std::move(appliedClip), dstProxyView); std::move(appliedClip), dstProxyView);
if (fCharacterization & kLine_Program) { if (fCharacterization & Program::kLine) {
this->makeLineProgramInfo(*caps, arena, pipeline, writeView, this->makeLineProgramInfo(*caps, arena, pipeline, writeView,
geometryProcessorViewM, geometryProcessorLocalM, geometryProcessorViewM, geometryProcessorLocalM,
renderPassXferBarriers, colorLoadOp); renderPassXferBarriers, colorLoadOp);
} }
if (fCharacterization & kQuad_Program) { if (fCharacterization & Program::kQuad) {
this->makeQuadProgramInfo(*caps, arena, pipeline, writeView, this->makeQuadProgramInfo(*caps, arena, pipeline, writeView,
geometryProcessorViewM, geometryProcessorLocalM, geometryProcessorViewM, geometryProcessorLocalM,
renderPassXferBarriers, colorLoadOp); renderPassXferBarriers, colorLoadOp);
} }
if (fCharacterization & kConic_Program) { if (fCharacterization & Program::kConic) {
this->makeConicProgramInfo(*caps, arena, pipeline, writeView, this->makeConicProgramInfo(*caps, arena, pipeline, writeView,
geometryProcessorViewM, geometryProcessorLocalM, geometryProcessorViewM, geometryProcessorLocalM,
renderPassXferBarriers, colorLoadOp); renderPassXferBarriers, colorLoadOp);
@ -1193,7 +1138,7 @@ void AAHairlineOp::onPrepareDraws(GrMeshDrawTarget* target) {
} }
SkDEBUGCODE(Program predictedPrograms = this->predictPrograms(&target->caps())); SkDEBUGCODE(Program predictedPrograms = this->predictPrograms(&target->caps()));
Program actualPrograms = kNone_Program; Program actualPrograms = Program::kNone;
// This is hand inlined for maximum performance. // This is hand inlined for maximum performance.
PREALLOC_PTARRAY(128) lines; PREALLOC_PTARRAY(128) lines;
@ -1224,8 +1169,8 @@ void AAHairlineOp::onPrepareDraws(GrMeshDrawTarget* target) {
// do lines first // do lines first
if (lineCount) { if (lineCount) {
SkASSERT(predictedPrograms & kLine_Program); SkASSERT(predictedPrograms & Program::kLine);
actualPrograms |= kLine_Program; actualPrograms |= Program::kLine;
sk_sp<const GrBuffer> linesIndexBuffer = get_lines_index_buffer(target->resourceProvider()); sk_sp<const GrBuffer> linesIndexBuffer = get_lines_index_buffer(target->resourceProvider());
@ -1279,8 +1224,8 @@ void AAHairlineOp::onPrepareDraws(GrMeshDrawTarget* target) {
} }
if (quadCount > 0) { if (quadCount > 0) {
SkASSERT(predictedPrograms & kQuad_Program); SkASSERT(predictedPrograms & Program::kQuad);
actualPrograms |= kQuad_Program; actualPrograms |= Program::kQuad;
fMeshes[1] = target->allocMesh(); fMeshes[1] = target->allocMesh();
fMeshes[1]->setIndexedPatterned(quadsIndexBuffer, kIdxsPerQuad, quadCount, fMeshes[1]->setIndexedPatterned(quadsIndexBuffer, kIdxsPerQuad, quadCount,
@ -1290,8 +1235,8 @@ void AAHairlineOp::onPrepareDraws(GrMeshDrawTarget* target) {
} }
if (conicCount > 0) { if (conicCount > 0) {
SkASSERT(predictedPrograms & kConic_Program); SkASSERT(predictedPrograms & Program::kConic);
actualPrograms |= kConic_Program; actualPrograms |= Program::kConic;
fMeshes[2] = target->allocMesh(); fMeshes[2] = target->allocMesh();
fMeshes[2]->setIndexedPatterned(std::move(quadsIndexBuffer), kIdxsPerQuad, conicCount, 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) { } // anonymous namespace
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;
}
/////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////
@ -1348,3 +1280,49 @@ GR_DRAW_OP_TEST_DEFINE(AAHairlineOp) {
} }
#endif #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. * found in the LICENSE file.
*/ */
#include "src/gpu/ops/GrAALinearizingConvexPathRenderer.h" #include "src/gpu/ops/AALinearizingConvexPathRenderer.h"
#include "include/core/SkString.h" #include "include/core/SkString.h"
#include "src/core/SkGeometry.h" #include "src/core/SkGeometry.h"
@ -28,71 +28,22 @@
#include "src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h" #include "src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h"
#include "src/gpu/v1/SurfaceDrawContext_v1.h" #include "src/gpu/v1/SurfaceDrawContext_v1.h"
///////////////////////////////////////////////////////////////////////////////
namespace {
static const int DEFAULT_BUFFER_SIZE = 100; static const int DEFAULT_BUFFER_SIZE = 100;
// The thicker the stroke, the harder it is to produce high-quality results using tessellation. For // 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. // the time being, we simply drop back to software rendering above this stroke width.
static const SkScalar kMaxStrokeWidth = 20.0; 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 // extract the result vertices and indices from the GrAAConvexTessellator
static void extract_verts(const GrAAConvexTessellator& tess, void extract_verts(const GrAAConvexTessellator& tess,
const SkMatrix* localCoordsMatrix, const SkMatrix* localCoordsMatrix,
void* vertData, void* vertData,
const GrVertexColor& color, const GrVertexColor& color,
uint16_t firstIndex, uint16_t firstIndex,
uint16_t* idxs) { uint16_t* idxs) {
GrVertexWriter verts{vertData}; GrVertexWriter verts{vertData};
for (int i = 0; i < tess.numPts(); ++i) { for (int i = 0; i < tess.numPts(); ++i) {
SkPoint lc; SkPoint lc;
@ -108,10 +59,10 @@ static void extract_verts(const GrAAConvexTessellator& tess,
} }
} }
static GrGeometryProcessor* create_lines_only_gp(SkArenaAlloc* arena, GrGeometryProcessor* create_lines_only_gp(SkArenaAlloc* arena,
bool tweakAlphaForCoverage, bool tweakAlphaForCoverage,
bool usesLocalCoords, bool usesLocalCoords,
bool wideColor) { bool wideColor) {
using namespace GrDefaultGeoProcFactory; using namespace GrDefaultGeoProcFactory;
Coverage::Type coverageType = Coverage::Type coverageType =
@ -124,8 +75,6 @@ static GrGeometryProcessor* create_lines_only_gp(SkArenaAlloc* arena,
return Make(arena, colorType, coverageType, localCoordsType, SkMatrix::I()); return Make(arena, colorType, coverageType, localCoordsType, SkMatrix::I());
} }
namespace {
class AAFlatteningConvexPathOp final : public GrMeshDrawOp { class AAFlatteningConvexPathOp final : public GrMeshDrawOp {
private: private:
using Helper = GrSimpleMeshDrawOpHelperWithStencil; using Helper = GrSimpleMeshDrawOpHelperWithStencil;
@ -388,28 +337,6 @@ private:
} // anonymous namespace } // 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 #if GR_TEST_UTILS
@ -443,3 +370,79 @@ GR_DRAW_OP_TEST_DEFINE(AAFlatteningConvexPathOp) {
} }
#endif #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. * 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/GrAuditTrail.h"
#include "src/gpu/GrGpu.h" #include "src/gpu/GrGpu.h"
@ -14,8 +14,9 @@
#include "src/gpu/ops/GrMeshDrawOp.h" #include "src/gpu/ops/GrMeshDrawOp.h"
#include "src/gpu/v1/SurfaceDrawContext_v1.h" #include "src/gpu/v1/SurfaceDrawContext_v1.h"
GrPathRenderer::CanDrawPath namespace skgpu::v1 {
GrDashLinePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
GrPathRenderer::CanDrawPath DashLinePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
SkPoint pts[2]; SkPoint pts[2];
bool inverted; bool inverted;
if (args.fShape->style().isDashed() && args.fShape->asLine(pts, &inverted)) { if (args.fShape->style().isDashed() && args.fShape->asLine(pts, &inverted)) {
@ -29,9 +30,9 @@ GrDashLinePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
return CanDrawPath::kNo; return CanDrawPath::kNo;
} }
bool GrDashLinePathRenderer::onDrawPath(const DrawPathArgs& args) { bool DashLinePathRenderer::onDrawPath(const DrawPathArgs& args) {
GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(), GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(),
"GrDashLinePathRenderer::onDrawPath"); "DashLinePathRenderer::onDrawPath");
GrDashOp::AAMode aaMode; GrDashOp::AAMode aaMode;
switch (args.fAAType) { switch (args.fAAType) {
case GrAAType::kNone: case GrAAType::kNone:
@ -57,3 +58,5 @@ bool GrDashLinePathRenderer::onDrawPath(const DrawPathArgs& args) {
args.fSurfaceDrawContext->addDrawOp(args.fClip, std::move(op)); args.fSurfaceDrawContext->addDrawOp(args.fClip, std::move(op));
return true; return true;
} }
} // namespace skgpu::v1

View File

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

View File

@ -5,7 +5,7 @@
* found in the LICENSE file. * 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/SkString.h"
#include "include/core/SkStrokeRec.h" #include "include/core/SkStrokeRec.h"
@ -30,15 +30,14 @@
#include "src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h" #include "src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h"
#include "src/gpu/v1/SurfaceDrawContext_v1.h" #include "src/gpu/v1/SurfaceDrawContext_v1.h"
GrDefaultPathRenderer::GrDefaultPathRenderer() {
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Helpers for drawPath // Helpers for drawPath
namespace {
#define STENCIL_OFF 0 // Always disable stencil (even when needed) #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 #if STENCIL_OFF
return true; return true;
#else #else
@ -56,17 +55,6 @@ static inline bool single_pass_shape(const GrStyledShape& shape) {
#endif #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 { class PathGeoBuilder {
public: public:
PathGeoBuilder(GrPrimitiveType primitiveType, PathGeoBuilder(GrPrimitiveType primitiveType,
@ -253,7 +241,7 @@ private:
&fFirstVertex, &fFirstVertex,
&fVerticesInChunk)); &fVerticesInChunk));
if (!fVertices) { if (!fVertices) {
SkDebugf("WARNING: Failed to allocate vertex buffer for GrDefaultPathRenderer.\n"); SkDebugf("WARNING: Failed to allocate vertex buffer for DefaultPathRenderer.\n");
fCurVert = nullptr; fCurVert = nullptr;
fCurIdx = fIndices = nullptr; fCurIdx = fIndices = nullptr;
fSubpathIndexStart = 0; fSubpathIndexStart = 0;
@ -272,7 +260,7 @@ private:
&fIndexBuffer, &fFirstIndex, &fIndexBuffer, &fFirstIndex,
&fIndicesInChunk); &fIndicesInChunk);
if (!fIndices) { if (!fIndices) {
SkDebugf("WARNING: Failed to allocate index buffer for GrDefaultPathRenderer.\n"); SkDebugf("WARNING: Failed to allocate index buffer for DefaultPathRenderer.\n");
fVertices = nullptr; fVertices = nullptr;
fValid = false; fValid = false;
} }
@ -592,14 +580,47 @@ private:
} // anonymous namespace } // anonymous namespace
bool GrDefaultPathRenderer::internalDrawPath(skgpu::v1::SurfaceDrawContext* sdc, ///////////////////////////////////////////////////////////////////////////////////////////////////
GrPaint&& paint,
GrAAType aaType, #if GR_TEST_UTILS
const GrUserStencilSettings& userStencilSettings,
const GrClip* clip, GR_DRAW_OP_TEST_DEFINE(DefaultPathOp) {
const SkMatrix& viewMatrix, SkMatrix viewMatrix = GrTest::TestMatrix(random);
const GrStyledShape& shape,
bool stencilOnly) { // 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(); auto context = sdc->recordingContext();
SkASSERT(GrAAType::kCoverage != aaType); SkASSERT(GrAAType::kCoverage != aaType);
@ -737,8 +758,17 @@ bool GrDefaultPathRenderer::internalDrawPath(skgpu::v1::SurfaceDrawContext* sdc,
return true; 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( bool isHairline = GrIsStrokeHairlineOrEquivalent(
args.fShape->style(), *args.fViewMatrix, nullptr); args.fShape->style(), *args.fViewMatrix, nullptr);
// If we aren't a single_pass_shape or hairline, we require stencil buffers. // 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; return CanDrawPath::kAsBackup;
} }
bool GrDefaultPathRenderer::onDrawPath(const DrawPathArgs& args) { bool DefaultPathRenderer::onDrawPath(const DrawPathArgs& args) {
GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(), GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(),
"GrDefaultPathRenderer::onDrawPath"); "DefaultPathRenderer::onDrawPath");
GrAAType aaType = (GrAAType::kNone != args.fAAType) ? GrAAType::kMSAA : GrAAType::kNone; GrAAType aaType = (GrAAType::kNone != args.fAAType) ? GrAAType::kMSAA : GrAAType::kNone;
return this->internalDrawPath( return this->internalDrawPath(
@ -768,9 +798,9 @@ bool GrDefaultPathRenderer::onDrawPath(const DrawPathArgs& args) {
args.fClip, *args.fViewMatrix, *args.fShape, false); 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(), GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(),
"GrDefaultPathRenderer::onStencilPath"); "DefaultPathRenderer::onStencilPath");
SkASSERT(!args.fShape->inverseFilled()); SkASSERT(!args.fShape->inverseFilled());
GrPaint paint; GrPaint paint;
@ -783,31 +813,4 @@ void GrDefaultPathRenderer::onStencilPath(const StencilPathArgs& args) {
args.fClip, *args.fViewMatrix, *args.fShape, true); args.fClip, *args.fViewMatrix, *args.fShape, true);
} }
/////////////////////////////////////////////////////////////////////////////////////////////////// } // namespace skgpu::v1
#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

View File

@ -5,22 +5,24 @@
* found in the LICENSE file. * found in the LICENSE file.
*/ */
#ifndef GrDefaultPathRenderer_DEFINED #ifndef DefaultPathRenderer_DEFINED
#define GrDefaultPathRenderer_DEFINED #define DefaultPathRenderer_DEFINED
#include "include/core/SkTypes.h" #include "include/core/SkTypes.h"
#include "src/gpu/GrPathRenderer.h" #include "src/gpu/GrPathRenderer.h"
#include "src/gpu/ops/GrPathStencilSettings.h" #include "src/gpu/ops/GrPathStencilSettings.h"
namespace skgpu::v1 {
/** /**
* Subclass that renders the path using the stencil buffer to resolve fill rules * Subclass that renders the path using the stencil buffer to resolve fill rules
* (e.g. winding, even-odd) * (e.g. winding, even-odd)
*/ */
class GrDefaultPathRenderer : public GrPathRenderer { class DefaultPathRenderer final : public GrPathRenderer {
public: public:
GrDefaultPathRenderer(); DefaultPathRenderer() = default;
const char* name() const final { return "Default"; } const char* name() const override { return "Default"; }
private: private:
StencilSupport onGetStencilSupport(const GrStyledShape&) const override; StencilSupport onGetStencilSupport(const GrStyledShape&) const override;
@ -43,4 +45,6 @@ private:
using INHERITED = GrPathRenderer; 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 // 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 // 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. // 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) { 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, sk_gpu_test::GrContextFactory::IsRenderingContext,
reporter, ctxInfo, only_allow_default) { reporter, ctxInfo, only_allow_default) {
auto ctx = ctxInfo.directContext(); 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) { 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. // It used to trigger asserts, now the degenerate quad segments should cause it to be rejected.
SkImageInfo info = SkImageInfo::MakeN32Premul(256, 256); SkImageInfo info = SkImageInfo::MakeN32Premul(256, 256);
auto surface(SkSurface::MakeRenderTarget(ctxInfo.directContext(), SkBudgeted::kNo, info)); auto surface(SkSurface::MakeRenderTarget(ctxInfo.directContext(), SkBudgeted::kNo, info));