blob: 026b7b19aa644d2b42268e7774c77a9c04fdbab2 [file] [log] [blame]
Chris Daltonc3176002021-07-23 15:33:09 -06001/*
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
Robert Phillips43e70f12021-08-19 11:12:48 -04008#ifndef AtlasPathRenderer_DEFINED
9#define AtlasPathRenderer_DEFINED
Chris Daltonc3176002021-07-23 15:33:09 -060010
Robert Phillips400f52e2021-07-26 13:23:10 -040011#include "include/gpu/GrTypes.h"
Chris Daltonc3176002021-07-23 15:33:09 -060012#include "include/private/SkTHash.h"
13#include "src/core/SkIPoint16.h"
14#include "src/gpu/GrDynamicAtlas.h"
15#include "src/gpu/GrFragmentProcessor.h"
16#include "src/gpu/GrOnFlushResourceProvider.h"
Robert Phillipsdb0ec082021-08-19 12:30:12 -040017#include "src/gpu/v1/PathRenderer.h"
Chris Daltonc3176002021-07-23 15:33:09 -060018
19class GrAtlasRenderTask;
20class GrOp;
21class GrRecordingContext;
22
Robert Phillips43e70f12021-08-19 11:12:48 -040023namespace skgpu::v1 {
24
Chris Daltonc3176002021-07-23 15:33:09 -060025// Draws paths by first rendering their coverage mask into an offscreen atlas.
Robert Phillipsdb0ec082021-08-19 12:30:12 -040026class AtlasPathRenderer final : public PathRenderer, public GrOnFlushCallbackObject {
Chris Daltonc3176002021-07-23 15:33:09 -060027public:
28 static bool IsSupported(GrRecordingContext*);
29
30 // Returns a GrAtlasPathRenderer if it is supported, otherwise null.
Robert Phillips43e70f12021-08-19 11:12:48 -040031 static sk_sp<AtlasPathRenderer> Make(GrRecordingContext* rContext);
Chris Daltonc3176002021-07-23 15:33:09 -060032
Robert Phillips43e70f12021-08-19 11:12:48 -040033 const char* name() const override { return "GrAtlasPathRenderer"; }
Chris Daltonc3176002021-07-23 15:33:09 -060034
35 // Returns a fragment processor that modulates inputFP by the given deviceSpacePath's coverage,
36 // implemented using an internal atlas.
37 //
38 // Returns 'inputFP' wrapped in GrFPFailure() if the path was too large, or if the current atlas
39 // is full and already used by either opBeingClipped or inputFP. (Currently, "too large" means
Chris Dalton66deeb22021-07-23 13:57:03 -060040 // larger than fMaxAtlasSize in either dimension, more than 256^2 total pixels, or more than
41 // 128^2 total pixels if the surfaceDrawContext supports MSAA or DMSAA.)
Chris Daltonc3176002021-07-23 15:33:09 -060042 //
43 // Also returns GrFPFailure() if the view matrix has perspective.
Robert Phillips4dca8312021-07-28 15:13:20 -040044 GrFPResult makeAtlasClipEffect(const skgpu::v1::SurfaceDrawContext*,
Chris Daltonc3176002021-07-23 15:33:09 -060045 const GrOp* opBeingClipped,
46 std::unique_ptr<GrFragmentProcessor> inputFP,
47 const SkIRect& drawBounds,
48 const SkMatrix&,
49 const SkPath&);
50
51private:
52 // The atlas is not compatible with DDL. We can only use it on direct contexts.
Robert Phillips43e70f12021-08-19 11:12:48 -040053 AtlasPathRenderer(GrDirectContext*);
54
55 StencilSupport onGetStencilSupport(const GrStyledShape&) const override {
56 return kNoSupport_StencilSupport;
57 }
58
59 CanDrawPath onCanDrawPath(const CanDrawPathArgs&) const override;
60
61 bool onDrawPath(const DrawPathArgs&) override;
Chris Daltonc3176002021-07-23 15:33:09 -060062
Chris Dalton66deeb22021-07-23 13:57:03 -060063 // Returns true if the given device-space path bounds are small enough to fit in an atlas and to
64 // benefit from atlasing. (Currently, "small enough" means no larger than fMaxAtlasSize in
65 // either dimension, no more than 256^2 total pixels, or no more than 128^2 total pixels if the
66 // fallbackAAType is kMSAA.)
67 bool pathFitsInAtlas(const SkRect& pathDevBounds, GrAAType fallbackAAType) const;
Chris Daltonc3176002021-07-23 15:33:09 -060068
69 // Returns true if the draw being set up already uses the given atlasProxy.
70 using DrawRefsAtlasCallback = std::function<bool(const GrSurfaceProxy* atlasProxy)>;
71
72 // Adds the filled path to an atlas.
73 //
74 // pathFitsInAtlas() and is_visible() both must have returned true before making this call.
75 //
76 // Fails and returns false if the current atlas is full and already in use according to
77 // DrawRefsAtlasCallback.
78 bool addPathToAtlas(GrRecordingContext*,
79 const SkMatrix&,
80 const SkPath&,
81 const SkRect& pathDevBounds,
82 SkIRect* devIBounds,
83 SkIPoint16* locationInAtlas,
84 bool* transposedInAtlas,
85 const DrawRefsAtlasCallback&);
86
87 // Instantiates texture(s) for all atlases we've created since the last flush. Atlases that are
88 // the same size will be instantiated with the same backing texture.
89 void preFlush(GrOnFlushResourceProvider*, SkSpan<const uint32_t> taskIDs) override;
90
91 float fAtlasMaxSize = 0;
Chris Dalton72fd33a2021-07-28 14:19:13 -060092 float fAtlasMaxPathWidth = 0;
Chris Daltonc3176002021-07-23 15:33:09 -060093 int fAtlasInitialSize = 0;
94
95 // A collection of all atlases we've created and used since the last flush. We instantiate these
96 // at flush time during preFlush().
97 SkSTArray<4, sk_sp<GrAtlasRenderTask>> fAtlasRenderTasks;
98
99 // This simple cache remembers the locations of cacheable path masks in the most recent atlas.
100 // Its main motivation is for clip paths.
101 struct AtlasPathKey {
102 void set(const SkMatrix&, const SkPath&);
103 bool operator==(const AtlasPathKey& k) const {
104 static_assert(sizeof(*this) == sizeof(uint32_t) * 6);
105 return !memcmp(this, &k, sizeof(*this));
106 }
107 uint32_t fPathGenID;
108 float fAffineMatrix[4];
109 uint8_t fSubpixelPositionKey[2];
110 uint16_t fFillRule;
111 };
112 SkTHashMap<AtlasPathKey, SkIPoint16> fAtlasPathCache;
113};
114
Robert Phillips43e70f12021-08-19 11:12:48 -0400115} // namespace skgpu::v1
Robert Phillips400f52e2021-07-26 13:23:10 -0400116
117#endif // GrAtlasPathRenderer_DEFINED