blob: 4a762bcb9ae1f1b9517379c0e8977755e9e5561b [file] [log] [blame]
Chris Dalton383a2ef2018-01-08 17:21:41 -05001/*
2 * Copyright 2017 Google Inc.
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 GrCCAtlas_DEFINED
9#define GrCCAtlas_DEFINED
10
Chris Dalton9414c962018-06-14 10:14:50 -060011#include "GrAllocator.h"
Chris Dalton4da70192018-06-18 09:51:36 -060012#include "GrNonAtomicRef.h"
13#include "GrResourceKey.h"
Chris Daltonafde18f2018-06-22 12:44:19 -060014#include "GrTexture.h"
Chris Dalton383a2ef2018-01-08 17:21:41 -050015#include "SkRefCnt.h"
16#include "SkSize.h"
17
Chris Dalton383a2ef2018-01-08 17:21:41 -050018class GrOnFlushResourceProvider;
19class GrRenderTargetContext;
20class GrTextureProxy;
21struct SkIPoint16;
Chris Dalton4da70192018-06-18 09:51:36 -060022struct SkIRect;
Chris Dalton383a2ef2018-01-08 17:21:41 -050023
24/**
25 * This class implements a dynamic size GrRectanizer that grows until it reaches the implementation-
26 * dependent max texture size. When finalized, it also creates and stores a GrTextureProxy for the
27 * underlying atlas.
28 */
29class GrCCAtlas {
30public:
Chris Dalton9414c962018-06-14 10:14:50 -060031 // As long as GrSurfaceOrigin exists, we just have to decide on one for the atlas texture.
32 static constexpr GrSurfaceOrigin kTextureOrigin = kTopLeft_GrSurfaceOrigin;
Chris Dalton42c21152018-06-13 15:28:19 -060033 static constexpr int kPadding = 1; // Amount of padding below and to the right of each path.
Chris Dalton9ca27842018-01-18 12:24:50 -070034
Chris Dalton42c21152018-06-13 15:28:19 -060035 // This struct encapsulates the minimum and desired requirements for an atlas, as well as an
36 // approximate number of pixels to help select a good initial size.
37 struct Specs {
38 int fMaxPreferredTextureSize = 0;
39 int fMinTextureSize = 0;
40 int fMinWidth = 0; // If there are 100 20x10 paths, this should be 20.
41 int fMinHeight = 0; // If there are 100 20x10 paths, this should be 10.
42 int fApproxNumPixels = 0;
43
44 // Add space for a rect in the desired atlas specs.
45 void accountForSpace(int width, int height);
46 };
47
Chris Dalton2e825a32019-01-04 22:14:27 +000048 GrCCAtlas(GrPixelConfig, const Specs&, const GrCaps&);
Chris Dalton383a2ef2018-01-08 17:21:41 -050049 ~GrCCAtlas();
50
Chris Dalton4c458b12018-06-16 17:22:59 -060051 GrTextureProxy* textureProxy() const { return fTextureProxy.get(); }
Chris Daltonafde18f2018-06-22 12:44:19 -060052 int currentWidth() const { return fWidth; }
53 int currentHeight() const { return fHeight; }
Chris Dalton4c458b12018-06-16 17:22:59 -060054
Chris Dalton9414c962018-06-14 10:14:50 -060055 // Attempts to add a rect to the atlas. If successful, returns the integer offset from
56 // device-space pixels where the path will be drawn, to atlas pixels where its mask resides.
57 bool addRect(const SkIRect& devIBounds, SkIVector* atlasOffset);
Chris Dalton383a2ef2018-01-08 17:21:41 -050058 const SkISize& drawBounds() { return fDrawBounds; }
59
Chris Dalton09a7bb22018-08-31 19:53:15 +080060 // This is an optional space for the caller to jot down which user-defined batches to use when
Chris Dalton9414c962018-06-14 10:14:50 -060061 // they render the content of this atlas.
Chris Dalton09a7bb22018-08-31 19:53:15 +080062 void setFillBatchID(int id);
63 int getFillBatchID() const { return fFillBatchID; }
64 void setStrokeBatchID(int id);
65 int getStrokeBatchID() const { return fStrokeBatchID; }
Chris Dalton9ca27842018-01-18 12:24:50 -070066
Chris Dalton2e825a32019-01-04 22:14:27 +000067 // Manages a unique resource cache key that gets assigned to the atlas texture. The unique key
68 // does not get assigned to the texture proxy until it is instantiated.
69 const GrUniqueKey& getOrAssignUniqueKey(GrOnFlushResourceProvider*);
70 const GrUniqueKey& uniqueKey() const { return fUniqueKey; }
71
72 // An object for simple bookkeeping on the atlas texture once it has a unique key. In practice,
73 // we use it to track the percentage of the original atlas pixels that could still ever
74 // potentially be reused (i.e., those which still represent an extant path). When the percentage
75 // of useful pixels drops below 50%, the entire texture is purged from the resource cache.
76 struct CachedAtlasInfo : public GrNonAtomicRef<CachedAtlasInfo> {
77 CachedAtlasInfo(uint32_t contextUniqueID) : fContextUniqueID(contextUniqueID) {}
78 const uint32_t fContextUniqueID;
79 int fNumPathPixels = 0;
80 int fNumInvalidatedPathPixels = 0;
81 bool fIsPurgedFromResourceCache = false;
82 };
83 sk_sp<CachedAtlasInfo> refOrMakeCachedAtlasInfo(uint32_t contextUniqueID);
Chris Dalton4da70192018-06-18 09:51:36 -060084
Chris Dalton4c458b12018-06-16 17:22:59 -060085 // Instantiates our texture proxy for the atlas and returns a pre-cleared GrRenderTargetContext
86 // that the caller may use to render the content. After this call, it is no longer valid to call
87 // addRect(), setUserBatchID(), or this method again.
Chris Daltonafde18f2018-06-22 12:44:19 -060088 //
89 // 'backingTexture', if provided, is a renderable texture with which to instantiate our proxy.
90 // If null then we will create a texture using the resource provider. The purpose of this param
91 // is to provide a guaranteed way to recycle a stashed atlas texture from a previous flush.
92 sk_sp<GrRenderTargetContext> makeRenderTargetContext(GrOnFlushResourceProvider*,
93 sk_sp<GrTexture> backingTexture = nullptr);
Chris Dalton383a2ef2018-01-08 17:21:41 -050094
95private:
96 class Node;
97
98 bool internalPlaceRect(int w, int h, SkIPoint16* loc);
99
Chris Dalton42c21152018-06-13 15:28:19 -0600100 const int fMaxTextureSize;
Chris Dalton2612bae2018-02-22 13:41:37 -0700101 int fWidth, fHeight;
Chris Dalton383a2ef2018-01-08 17:21:41 -0500102 std::unique_ptr<Node> fTopNode;
Chris Dalton2612bae2018-02-22 13:41:37 -0700103 SkISize fDrawBounds = {0, 0};
Chris Dalton383a2ef2018-01-08 17:21:41 -0500104
Chris Dalton09a7bb22018-08-31 19:53:15 +0800105 int fFillBatchID;
106 int fStrokeBatchID;
Chris Dalton4da70192018-06-18 09:51:36 -0600107
Chris Dalton2e825a32019-01-04 22:14:27 +0000108 // Not every atlas will have a unique key -- a mainline CCPR one won't if we don't stash any
109 // paths, and only the first atlas in the stack is eligible to be stashed.
110 GrUniqueKey fUniqueKey;
111
112 sk_sp<CachedAtlasInfo> fCachedAtlasInfo;
Chris Dalton383a2ef2018-01-08 17:21:41 -0500113 sk_sp<GrTextureProxy> fTextureProxy;
Chris Daltonafde18f2018-06-22 12:44:19 -0600114 sk_sp<GrTexture> fBackingTexture;
Chris Dalton383a2ef2018-01-08 17:21:41 -0500115};
116
Chris Dalton9414c962018-06-14 10:14:50 -0600117/**
118 * This class implements an unbounded stack of atlases. When the current atlas reaches the
119 * implementation-dependent max texture size, a new one is pushed to the back and we continue on.
120 */
121class GrCCAtlasStack {
122public:
Chris Dalton2e825a32019-01-04 22:14:27 +0000123 GrCCAtlasStack(GrPixelConfig pixelConfig, const GrCCAtlas::Specs& specs, const GrCaps* caps)
124 : fPixelConfig(pixelConfig), fSpecs(specs), fCaps(caps) {}
Chris Dalton9414c962018-06-14 10:14:50 -0600125
126 bool empty() const { return fAtlases.empty(); }
127 const GrCCAtlas& front() const { SkASSERT(!this->empty()); return fAtlases.front(); }
128 GrCCAtlas& front() { SkASSERT(!this->empty()); return fAtlases.front(); }
129 GrCCAtlas& current() { SkASSERT(!this->empty()); return fAtlases.back(); }
130
131 class Iter {
132 public:
133 Iter(GrCCAtlasStack& stack) : fImpl(&stack.fAtlases) {}
134 bool next() { return fImpl.next(); }
135 GrCCAtlas* operator->() const { return fImpl.get(); }
136 private:
137 typename GrTAllocator<GrCCAtlas>::Iter fImpl;
138 };
139
140 // Adds a rect to the current atlas and returns the offset from device space to atlas space.
141 // Call current() to get the atlas it was added to.
142 //
143 // If the return value is non-null, it means the given rect did not fit in the then-current
144 // atlas, so it was retired and a new one was added to the stack. The return value is the
145 // newly-retired atlas. The caller should call setUserBatchID() on the retired atlas before
146 // moving on.
Chris Dalton4c458b12018-06-16 17:22:59 -0600147 GrCCAtlas* addRect(const SkIRect& devIBounds, SkIVector* devToAtlasOffset);
Chris Dalton9414c962018-06-14 10:14:50 -0600148
149private:
Chris Dalton2e825a32019-01-04 22:14:27 +0000150 const GrPixelConfig fPixelConfig;
Chris Dalton9414c962018-06-14 10:14:50 -0600151 const GrCCAtlas::Specs fSpecs;
Chris Dalton4c458b12018-06-16 17:22:59 -0600152 const GrCaps* const fCaps;
Chris Dalton9414c962018-06-14 10:14:50 -0600153 GrSTAllocator<4, GrCCAtlas> fAtlases;
154};
155
Chris Dalton42c21152018-06-13 15:28:19 -0600156inline void GrCCAtlas::Specs::accountForSpace(int width, int height) {
157 fMinWidth = SkTMax(width, fMinWidth);
158 fMinHeight = SkTMax(height, fMinHeight);
159 fApproxNumPixels += (width + kPadding) * (height + kPadding);
160}
161
Chris Dalton383a2ef2018-01-08 17:21:41 -0500162#endif