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:
parent
fdcf153f6c
commit
461c539a04
@ -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.
|
||||
|
20
gn/gpu.gni
20
gn/gpu.gni
@ -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",
|
||||
|
@ -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,
|
||||
|
@ -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(
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
31
src/gpu/ops/AAConvexPathRenderer.h
Normal file
31
src/gpu/ops/AAConvexPathRenderer.h
Normal 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
|
@ -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
|
||||
|
31
src/gpu/ops/AAHairLinePathRenderer.h
Normal file
31
src/gpu/ops/AAHairLinePathRenderer.h
Normal 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
|
@ -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
|
31
src/gpu/ops/AALinearizingConvexPathRenderer.h
Normal file
31
src/gpu/ops/AALinearizingConvexPathRenderer.h
Normal 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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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();
|
||||
|
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user