1/*
2 * Copyright 2019 Google LLC.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef GrTessellationPathRenderer_DEFINED
9#define GrTessellationPathRenderer_DEFINED
10
11#include "src/gpu/GrDynamicAtlas.h"
12#include "src/gpu/GrOnFlushResourceProvider.h"
13#include "src/gpu/GrPathRenderer.h"
14#include <map>
15
16// This is the tie-in point for path rendering via GrPathTessellateOp. This path renderer draws
17// paths using a hybrid Red Book "stencil, then cover" method. Curves get linearized by GPU
18// tessellation shaders. This path renderer doesn't apply analytic AA, so it requires a render
19// target that supports either MSAA or mixed samples if AA is desired.
20class GrTessellationPathRenderer : public GrPathRenderer, public GrOnFlushCallbackObject {
21public:
22 // Don't allow linearized segments to be off by more than 1/4th of a pixel from the true curve.
23 constexpr static float kLinearizationIntolerance = 4;
24
25 // This is the maximum resolve level supported by our internal indirect draw shaders. (Indirect
26 // draws are an alternative to hardware tessellation, and we can use them when hardware support
27 // is lacking.)
28 //
29 // At a given resolveLevel, a curve gets linearized into 2^resolveLevel line segments. So the
30 // finest resolveLevel supported by our indirect draw shaders is 2^10 == 1024 line segments.
31 //
32 // 1024 line segments is enough resolution (with intolerance == 4) to guarantee we can render a
33 // 123575px x 123575px path. (See GrWangsFormula::worst_case_cubic.)
34 constexpr static int kMaxResolveLevel = 10;
35
36 // We send these flags to the internal tessellation Ops to control how a path gets rendered.
37 enum class OpFlags {
38 kNone = 0,
39 // Used when tessellation is not supported, or when a path will require more resolution than
40 // the max number of segments supported by the hardware.
41 kDisableHWTessellation = (1 << 0),
42 kStencilOnly = (1 << 1),
43 kWireframe = (1 << 2)
44 };
45
46 static bool IsSupported(const GrCaps&);
47
48 GrTessellationPathRenderer(const GrCaps&);
49 const char* name() const final { return "GrTessellationPathRenderer"; }
50 StencilSupport onGetStencilSupport(const GrStyledShape& shape) const override {
51 // TODO: Single-pass (e.g., convex) paths can have full support.
52 return kStencilOnly_StencilSupport;
53 }
54 CanDrawPath onCanDrawPath(const CanDrawPathArgs&) const override;
55 bool onDrawPath(const DrawPathArgs&) override;
56 void onStencilPath(const StencilPathArgs&) override;
57 void preFlush(GrOnFlushResourceProvider*, const uint32_t* opsTaskIDs,
58 int numOpsTaskIDs) override;
59
60private:
61 void initAtlasFlags(const GrCaps&);
62 SkPath* getAtlasUberPath(SkPathFillType fillType, bool antialias) {
63 int idx = (int)antialias << 1;
64 idx |= (int)fillType & 1;
65 return &fAtlasUberPaths[idx];
66 }
67 // Allocates space in fAtlas if the path is small and simple enough, and if there is room.
68 bool tryAddPathToAtlas(const GrCaps&, const SkMatrix&, const SkPath&, const SkRect& devBounds,
69 GrAAType, SkIRect* devIBounds, SkIPoint16* locationInAtlas,
70 bool* transposedInAtlas);
71 void renderAtlas(GrOnFlushResourceProvider*);
72
73 GrDynamicAtlas fAtlas;
74 OpFlags fStencilAtlasFlags;
75 int fMaxAtlasPathWidth;
76 SkPath fAtlasUberPaths[4]; // 2 fillTypes * 2 antialias modes.
77};
78
79GR_MAKE_BITFIELD_CLASS_OPS(GrTessellationPathRenderer::OpFlags);
80
81#endif
82