• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 #include "GrCCAtlas.h"
9 
10 #include "GrCaps.h"
11 #include "GrOnFlushResourceProvider.h"
12 #include "GrProxyProvider.h"
13 #include "GrRectanizer_skyline.h"
14 #include "GrRenderTargetContext.h"
15 #include "GrTexture.h"
16 #include "GrTextureProxy.h"
17 #include "SkMakeUnique.h"
18 #include "SkMathPriv.h"
19 #include "ccpr/GrCCPathCache.h"
20 #include <atomic>
21 
22 class GrCCAtlas::Node {
23 public:
Node(std::unique_ptr<Node> previous,int l,int t,int r,int b)24     Node(std::unique_ptr<Node> previous, int l, int t, int r, int b)
25             : fPrevious(std::move(previous)), fX(l), fY(t), fRectanizer(r - l, b - t) {}
26 
previous() const27     Node* previous() const { return fPrevious.get(); }
28 
addRect(int w,int h,SkIPoint16 * loc,int maxAtlasSize)29     bool addRect(int w, int h, SkIPoint16* loc, int maxAtlasSize) {
30         // Pad all paths except those that are expected to take up an entire physical texture.
31         if (w < maxAtlasSize) {
32             w = SkTMin(w + kPadding, maxAtlasSize);
33         }
34         if (h < maxAtlasSize) {
35             h = SkTMin(h + kPadding, maxAtlasSize);
36         }
37         if (!fRectanizer.addRect(w, h, loc)) {
38             return false;
39         }
40         loc->fX += fX;
41         loc->fY += fY;
42         return true;
43     }
44 
45 private:
46     const std::unique_ptr<Node> fPrevious;
47     const int fX, fY;
48     GrRectanizerSkyline fRectanizer;
49 };
50 
GrCCAtlas(CoverageType coverageType,const Specs & specs,const GrCaps & caps)51 GrCCAtlas::GrCCAtlas(CoverageType coverageType, const Specs& specs, const GrCaps& caps)
52         : fCoverageType(coverageType)
53         , fMaxTextureSize(SkTMax(SkTMax(specs.fMinHeight, specs.fMinWidth),
54                                  specs.fMaxPreferredTextureSize)) {
55     // Caller should have cropped any paths to the destination render target instead of asking for
56     // an atlas larger than maxRenderTargetSize.
57     SkASSERT(fMaxTextureSize <= caps.maxTextureSize());
58     SkASSERT(specs.fMaxPreferredTextureSize > 0);
59 
60     // Begin with the first pow2 dimensions whose area is theoretically large enough to contain the
61     // pending paths, favoring height over width if necessary.
62     int log2area = SkNextLog2(SkTMax(specs.fApproxNumPixels, 1));
63     fHeight = 1 << ((log2area + 1) / 2);
64     fWidth = 1 << (log2area / 2);
65 
66     fWidth = SkTClamp(fWidth, specs.fMinTextureSize, specs.fMaxPreferredTextureSize);
67     fHeight = SkTClamp(fHeight, specs.fMinTextureSize, specs.fMaxPreferredTextureSize);
68 
69     if (fWidth < specs.fMinWidth || fHeight < specs.fMinHeight) {
70         // They want to stuff a particularly large path into the atlas. Just punt and go with their
71         // min width and height. The atlas will grow as needed.
72         fWidth = SkTMin(specs.fMinWidth + kPadding, fMaxTextureSize);
73         fHeight = SkTMin(specs.fMinHeight + kPadding, fMaxTextureSize);
74     }
75 
76     fTopNode = skstd::make_unique<Node>(nullptr, 0, 0, fWidth, fHeight);
77 
78     GrColorType colorType = (CoverageType::kFP16_CoverageCount == fCoverageType)
79             ? GrColorType::kAlpha_F16 : GrColorType::kAlpha_8;
80     const GrBackendFormat format =
81             caps.getBackendFormatFromGrColorType(colorType, GrSRGBEncoded::kNo);
82     GrPixelConfig pixelConfig = (CoverageType::kFP16_CoverageCount == fCoverageType)
83             ? kAlpha_half_GrPixelConfig : kAlpha_8_GrPixelConfig;
84 
85     fTextureProxy = GrProxyProvider::MakeFullyLazyProxy(
86             [this, pixelConfig](GrResourceProvider* resourceProvider) {
87                     if (!resourceProvider) {
88                         return sk_sp<GrTexture>();
89                     }
90                     if (!fBackingTexture) {
91                         GrSurfaceDesc desc;
92                         desc.fFlags = kRenderTarget_GrSurfaceFlag;
93                         desc.fWidth = fWidth;
94                         desc.fHeight = fHeight;
95                         desc.fConfig = pixelConfig;
96                         fBackingTexture = resourceProvider->createTexture(desc, SkBudgeted::kYes);
97                     }
98                     return fBackingTexture;
99             },
100             format, GrProxyProvider::Renderable::kYes, kTextureOrigin, pixelConfig, caps);
101 }
102 
~GrCCAtlas()103 GrCCAtlas::~GrCCAtlas() {
104 }
105 
addRect(const SkIRect & devIBounds,SkIVector * offset)106 bool GrCCAtlas::addRect(const SkIRect& devIBounds, SkIVector* offset) {
107     // This can't be called anymore once makeRenderTargetContext() has been called.
108     SkASSERT(!fTextureProxy->isInstantiated());
109 
110     SkIPoint16 location;
111     if (!this->internalPlaceRect(devIBounds.width(), devIBounds.height(), &location)) {
112         return false;
113     }
114     offset->set(location.x() - devIBounds.left(), location.y() - devIBounds.top());
115 
116     fDrawBounds.fWidth = SkTMax(fDrawBounds.width(), location.x() + devIBounds.width());
117     fDrawBounds.fHeight = SkTMax(fDrawBounds.height(), location.y() + devIBounds.height());
118     return true;
119 }
120 
internalPlaceRect(int w,int h,SkIPoint16 * loc)121 bool GrCCAtlas::internalPlaceRect(int w, int h, SkIPoint16* loc) {
122     for (Node* node = fTopNode.get(); node; node = node->previous()) {
123         if (node->addRect(w, h, loc, fMaxTextureSize)) {
124             return true;
125         }
126     }
127 
128     // The rect didn't fit. Grow the atlas and try again.
129     do {
130         if (fWidth == fMaxTextureSize && fHeight == fMaxTextureSize) {
131             return false;
132         }
133         if (fHeight <= fWidth) {
134             int top = fHeight;
135             fHeight = SkTMin(fHeight * 2, fMaxTextureSize);
136             fTopNode = skstd::make_unique<Node>(std::move(fTopNode), 0, top, fWidth, fHeight);
137         } else {
138             int left = fWidth;
139             fWidth = SkTMin(fWidth * 2, fMaxTextureSize);
140             fTopNode = skstd::make_unique<Node>(std::move(fTopNode), left, 0, fWidth, fHeight);
141         }
142     } while (!fTopNode->addRect(w, h, loc, fMaxTextureSize));
143 
144     return true;
145 }
146 
setFillBatchID(int id)147 void GrCCAtlas::setFillBatchID(int id) {
148     // This can't be called anymore once makeRenderTargetContext() has been called.
149     SkASSERT(!fTextureProxy->isInstantiated());
150     fFillBatchID = id;
151 }
152 
setStrokeBatchID(int id)153 void GrCCAtlas::setStrokeBatchID(int id) {
154     // This can't be called anymore once makeRenderTargetContext() has been called.
155     SkASSERT(!fTextureProxy->isInstantiated());
156     fStrokeBatchID = id;
157 }
158 
next_atlas_unique_id()159 static uint32_t next_atlas_unique_id() {
160     static std::atomic<uint32_t> nextID;
161     return nextID++;
162 }
163 
refOrMakeCachedAtlas(GrOnFlushResourceProvider * onFlushRP)164 sk_sp<GrCCCachedAtlas> GrCCAtlas::refOrMakeCachedAtlas(GrOnFlushResourceProvider* onFlushRP) {
165     if (!fCachedAtlas) {
166         static const GrUniqueKey::Domain kAtlasDomain = GrUniqueKey::GenerateDomain();
167 
168         GrUniqueKey atlasUniqueKey;
169         GrUniqueKey::Builder builder(&atlasUniqueKey, kAtlasDomain, 1, "CCPR Atlas");
170         builder[0] = next_atlas_unique_id();
171         builder.finish();
172 
173         onFlushRP->assignUniqueKeyToProxy(atlasUniqueKey, fTextureProxy.get());
174 
175         fCachedAtlas = sk_make_sp<GrCCCachedAtlas>(fCoverageType, atlasUniqueKey, fTextureProxy);
176     }
177 
178     SkASSERT(fCachedAtlas->coverageType() == fCoverageType);
179     SkASSERT(fCachedAtlas->getOnFlushProxy() == fTextureProxy.get());
180     return fCachedAtlas;
181 }
182 
makeRenderTargetContext(GrOnFlushResourceProvider * onFlushRP,sk_sp<GrTexture> backingTexture)183 sk_sp<GrRenderTargetContext> GrCCAtlas::makeRenderTargetContext(
184         GrOnFlushResourceProvider* onFlushRP, sk_sp<GrTexture> backingTexture) {
185     SkASSERT(!fTextureProxy->isInstantiated());  // This method should only be called once.
186     // Caller should have cropped any paths to the destination render target instead of asking for
187     // an atlas larger than maxRenderTargetSize.
188     SkASSERT(SkTMax(fHeight, fWidth) <= fMaxTextureSize);
189     SkASSERT(fMaxTextureSize <= onFlushRP->caps()->maxRenderTargetSize());
190 
191     if (backingTexture) {
192         SkASSERT(backingTexture->config() == kAlpha_half_GrPixelConfig);
193         SkASSERT(backingTexture->width() == fWidth);
194         SkASSERT(backingTexture->height() == fHeight);
195         fBackingTexture = std::move(backingTexture);
196     }
197 
198     sk_sp<GrRenderTargetContext> rtc =
199             onFlushRP->makeRenderTargetContext(fTextureProxy, nullptr, nullptr);
200     if (!rtc) {
201         SkDebugf("WARNING: failed to allocate a %ix%i atlas. Some paths will not be drawn.\n",
202                  fWidth, fHeight);
203         return nullptr;
204     }
205 
206     SkIRect clearRect = SkIRect::MakeSize(fDrawBounds);
207     rtc->clear(&clearRect, SK_PMColor4fTRANSPARENT,
208                GrRenderTargetContext::CanClearFullscreen::kYes);
209     return rtc;
210 }
211 
addRect(const SkIRect & devIBounds,SkIVector * devToAtlasOffset)212 GrCCAtlas* GrCCAtlasStack::addRect(const SkIRect& devIBounds, SkIVector* devToAtlasOffset) {
213     GrCCAtlas* retiredAtlas = nullptr;
214     if (fAtlases.empty() || !fAtlases.back().addRect(devIBounds, devToAtlasOffset)) {
215         // The retired atlas is out of room and can't grow any bigger.
216         retiredAtlas = !fAtlases.empty() ? &fAtlases.back() : nullptr;
217         fAtlases.emplace_back(fCoverageType, fSpecs, *fCaps);
218         SkASSERT(devIBounds.width() <= fSpecs.fMinWidth);
219         SkASSERT(devIBounds.height() <= fSpecs.fMinHeight);
220         SkAssertResult(fAtlases.back().addRect(devIBounds, devToAtlasOffset));
221     }
222     return retiredAtlas;
223 }
224