blob: 89eff1a99b20e2514e36a37ac0d1786beb408567 [file] [log] [blame]
Chris Dalton1a325d22017-07-14 15:17:41 -06001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/gpu/ccpr/GrCCAtlas.h"
Chris Dalton1a325d22017-07-14 15:17:41 -06009
Chris Daltonc3318f02019-07-19 14:20:53 -060010#include "include/gpu/GrRenderTarget.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "include/gpu/GrTexture.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "src/core/SkIPoint16.h"
13#include "src/core/SkMakeUnique.h"
14#include "src/core/SkMathPriv.h"
15#include "src/gpu/GrCaps.h"
16#include "src/gpu/GrOnFlushResourceProvider.h"
17#include "src/gpu/GrProxyProvider.h"
18#include "src/gpu/GrRectanizer_skyline.h"
19#include "src/gpu/GrRenderTargetContext.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040020#include "src/gpu/GrTextureProxy.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050021#include "src/gpu/ccpr/GrCCPathCache.h"
Mike Klein0ec1c572018-12-04 11:52:51 -050022#include <atomic>
Chris Dalton1a325d22017-07-14 15:17:41 -060023
Chris Dalton383a2ef2018-01-08 17:21:41 -050024class GrCCAtlas::Node {
Chris Dalton1a325d22017-07-14 15:17:41 -060025public:
26 Node(std::unique_ptr<Node> previous, int l, int t, int r, int b)
Chris Dalton383a2ef2018-01-08 17:21:41 -050027 : fPrevious(std::move(previous)), fX(l), fY(t), fRectanizer(r - l, b - t) {}
Chris Dalton1a325d22017-07-14 15:17:41 -060028
29 Node* previous() const { return fPrevious.get(); }
30
Chris Dalton2612bae2018-02-22 13:41:37 -070031 bool addRect(int w, int h, SkIPoint16* loc, int maxAtlasSize) {
32 // Pad all paths except those that are expected to take up an entire physical texture.
33 if (w < maxAtlasSize) {
34 w = SkTMin(w + kPadding, maxAtlasSize);
35 }
36 if (h < maxAtlasSize) {
37 h = SkTMin(h + kPadding, maxAtlasSize);
38 }
39 if (!fRectanizer.addRect(w, h, loc)) {
Chris Dalton1a325d22017-07-14 15:17:41 -060040 return false;
41 }
42 loc->fX += fX;
43 loc->fY += fY;
44 return true;
45 }
46
47private:
Chris Dalton383a2ef2018-01-08 17:21:41 -050048 const std::unique_ptr<Node> fPrevious;
49 const int fX, fY;
50 GrRectanizerSkyline fRectanizer;
Chris Dalton1a325d22017-07-14 15:17:41 -060051};
52
Chris Daltonc3318f02019-07-19 14:20:53 -060053sk_sp<GrTextureProxy> GrCCAtlas::MakeLazyAtlasProxy(
54 const LazyInstantiateAtlasCallback& callback, CoverageType coverageType, const GrCaps& caps) {
Chris Daltonc3318f02019-07-19 14:20:53 -060055 GrPixelConfig pixelConfig;
56 int sampleCount;
57
Greg Danieleadfac92019-08-02 09:03:53 -040058 GrBackendFormat format;
Chris Daltonc3318f02019-07-19 14:20:53 -060059 switch (coverageType) {
60 case CoverageType::kFP16_CoverageCount:
Greg Danieleadfac92019-08-02 09:03:53 -040061 format = caps.getDefaultBackendFormat(GrColorType::kAlpha_F16, GrRenderable::kYes);
Chris Daltonc3318f02019-07-19 14:20:53 -060062 pixelConfig = kAlpha_half_GrPixelConfig;
63 sampleCount = 1;
64 break;
65 case CoverageType::kA8_Multisample:
Greg Danieleadfac92019-08-02 09:03:53 -040066 format = caps.getDefaultBackendFormat(GrColorType::kAlpha_8, GrRenderable::kYes);
67 SkASSERT(caps.internalMultisampleCount(format) > 1);
Chris Daltonc3318f02019-07-19 14:20:53 -060068 pixelConfig = kAlpha_8_GrPixelConfig;
Greg Danieleadfac92019-08-02 09:03:53 -040069 sampleCount = (caps.mixedSamplesSupport()) ? 1 : caps.internalMultisampleCount(format);
Chris Daltonc3318f02019-07-19 14:20:53 -060070 break;
71 case CoverageType::kA8_LiteralCoverage:
Greg Danieleadfac92019-08-02 09:03:53 -040072 format = caps.getDefaultBackendFormat(GrColorType::kAlpha_8, GrRenderable::kYes);
Chris Daltonc3318f02019-07-19 14:20:53 -060073 pixelConfig = kAlpha_8_GrPixelConfig;
74 sampleCount = 1;
75 break;
76 }
77
Brian Salomon4eb38b72019-08-05 12:58:39 -040078 auto instantiate = [cb = std::move(callback), pixelConfig, format,
79 sampleCount](GrResourceProvider* rp) {
80 return cb(rp, pixelConfig, format, sampleCount);
81 };
Chris Daltonc3318f02019-07-19 14:20:53 -060082 sk_sp<GrTextureProxy> proxy = GrProxyProvider::MakeFullyLazyProxy(
Brian Salomon4eb38b72019-08-05 12:58:39 -040083 std::move(instantiate), format, GrRenderable::kYes, sampleCount, GrProtected::kNo,
84 kTextureOrigin, pixelConfig, caps);
Chris Daltonc3318f02019-07-19 14:20:53 -060085
86 return proxy;
87}
88
Chris Dalton351e80c2019-01-06 22:51:00 -070089GrCCAtlas::GrCCAtlas(CoverageType coverageType, const Specs& specs, const GrCaps& caps)
90 : fCoverageType(coverageType)
91 , fMaxTextureSize(SkTMax(SkTMax(specs.fMinHeight, specs.fMinWidth),
Chris Dalton42c21152018-06-13 15:28:19 -060092 specs.fMaxPreferredTextureSize)) {
Chris Dalton4c458b12018-06-16 17:22:59 -060093 // Caller should have cropped any paths to the destination render target instead of asking for
94 // an atlas larger than maxRenderTargetSize.
95 SkASSERT(fMaxTextureSize <= caps.maxTextureSize());
Chris Dalton42c21152018-06-13 15:28:19 -060096 SkASSERT(specs.fMaxPreferredTextureSize > 0);
97
98 // Begin with the first pow2 dimensions whose area is theoretically large enough to contain the
99 // pending paths, favoring height over width if necessary.
100 int log2area = SkNextLog2(SkTMax(specs.fApproxNumPixels, 1));
101 fHeight = 1 << ((log2area + 1) / 2);
102 fWidth = 1 << (log2area / 2);
103
104 fWidth = SkTClamp(fWidth, specs.fMinTextureSize, specs.fMaxPreferredTextureSize);
105 fHeight = SkTClamp(fHeight, specs.fMinTextureSize, specs.fMaxPreferredTextureSize);
106
107 if (fWidth < specs.fMinWidth || fHeight < specs.fMinHeight) {
108 // They want to stuff a particularly large path into the atlas. Just punt and go with their
109 // min width and height. The atlas will grow as needed.
110 fWidth = SkTMin(specs.fMinWidth + kPadding, fMaxTextureSize);
111 fHeight = SkTMin(specs.fMinHeight + kPadding, fMaxTextureSize);
112 }
113
Chris Dalton2612bae2018-02-22 13:41:37 -0700114 fTopNode = skstd::make_unique<Node>(nullptr, 0, 0, fWidth, fHeight);
Chris Dalton4c458b12018-06-16 17:22:59 -0600115
Brian Salomon4eb38b72019-08-05 12:58:39 -0400116 fTextureProxy = MakeLazyAtlasProxy(
117 [this](GrResourceProvider* resourceProvider, GrPixelConfig pixelConfig,
118 const GrBackendFormat& format, int sampleCount) {
119 if (!fBackingTexture) {
120 GrSurfaceDesc desc;
121 desc.fWidth = fWidth;
122 desc.fHeight = fHeight;
123 desc.fConfig = pixelConfig;
124 fBackingTexture = resourceProvider->createTexture(
125 desc, format, GrRenderable::kYes, sampleCount, SkBudgeted::kYes,
126 GrProtected::kNo, GrResourceProvider::Flags::kNoPendingIO);
127 }
128 return fBackingTexture;
129 },
130 fCoverageType, caps);
Robert Phillips5f78adf2019-04-22 12:41:39 -0400131
132 fTextureProxy->priv().setIgnoredByResourceAllocator();
Chris Dalton1a325d22017-07-14 15:17:41 -0600133}
134
Chris Dalton2612bae2018-02-22 13:41:37 -0700135GrCCAtlas::~GrCCAtlas() {
136}
Chris Dalton1a325d22017-07-14 15:17:41 -0600137
Chris Dalton9414c962018-06-14 10:14:50 -0600138bool GrCCAtlas::addRect(const SkIRect& devIBounds, SkIVector* offset) {
Chris Dalton4c458b12018-06-16 17:22:59 -0600139 // This can't be called anymore once makeRenderTargetContext() has been called.
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400140 SkASSERT(!fTextureProxy->isInstantiated());
Chris Dalton1a325d22017-07-14 15:17:41 -0600141
Chris Dalton9414c962018-06-14 10:14:50 -0600142 SkIPoint16 location;
143 if (!this->internalPlaceRect(devIBounds.width(), devIBounds.height(), &location)) {
Chris Dalton1a325d22017-07-14 15:17:41 -0600144 return false;
145 }
Chris Dalton9414c962018-06-14 10:14:50 -0600146 offset->set(location.x() - devIBounds.left(), location.y() - devIBounds.top());
Chris Dalton1a325d22017-07-14 15:17:41 -0600147
Chris Dalton9414c962018-06-14 10:14:50 -0600148 fDrawBounds.fWidth = SkTMax(fDrawBounds.width(), location.x() + devIBounds.width());
149 fDrawBounds.fHeight = SkTMax(fDrawBounds.height(), location.y() + devIBounds.height());
Chris Dalton1a325d22017-07-14 15:17:41 -0600150 return true;
151}
152
Chris Dalton383a2ef2018-01-08 17:21:41 -0500153bool GrCCAtlas::internalPlaceRect(int w, int h, SkIPoint16* loc) {
Chris Dalton1a325d22017-07-14 15:17:41 -0600154 for (Node* node = fTopNode.get(); node; node = node->previous()) {
Chris Dalton42c21152018-06-13 15:28:19 -0600155 if (node->addRect(w, h, loc, fMaxTextureSize)) {
Chris Dalton1a325d22017-07-14 15:17:41 -0600156 return true;
157 }
158 }
159
160 // The rect didn't fit. Grow the atlas and try again.
161 do {
Chris Dalton42c21152018-06-13 15:28:19 -0600162 if (fWidth == fMaxTextureSize && fHeight == fMaxTextureSize) {
Chris Dalton1a325d22017-07-14 15:17:41 -0600163 return false;
164 }
165 if (fHeight <= fWidth) {
166 int top = fHeight;
Chris Dalton42c21152018-06-13 15:28:19 -0600167 fHeight = SkTMin(fHeight * 2, fMaxTextureSize);
Chris Dalton1a325d22017-07-14 15:17:41 -0600168 fTopNode = skstd::make_unique<Node>(std::move(fTopNode), 0, top, fWidth, fHeight);
169 } else {
170 int left = fWidth;
Chris Dalton42c21152018-06-13 15:28:19 -0600171 fWidth = SkTMin(fWidth * 2, fMaxTextureSize);
Chris Dalton1a325d22017-07-14 15:17:41 -0600172 fTopNode = skstd::make_unique<Node>(std::move(fTopNode), left, 0, fWidth, fHeight);
173 }
Chris Dalton42c21152018-06-13 15:28:19 -0600174 } while (!fTopNode->addRect(w, h, loc, fMaxTextureSize));
Chris Dalton1a325d22017-07-14 15:17:41 -0600175
176 return true;
177}
178
Chris Dalton09a7bb22018-08-31 19:53:15 +0800179void GrCCAtlas::setFillBatchID(int id) {
Chris Dalton4c458b12018-06-16 17:22:59 -0600180 // This can't be called anymore once makeRenderTargetContext() has been called.
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400181 SkASSERT(!fTextureProxy->isInstantiated());
Chris Dalton09a7bb22018-08-31 19:53:15 +0800182 fFillBatchID = id;
183}
184
185void GrCCAtlas::setStrokeBatchID(int id) {
186 // This can't be called anymore once makeRenderTargetContext() has been called.
187 SkASSERT(!fTextureProxy->isInstantiated());
188 fStrokeBatchID = id;
Chris Dalton4c458b12018-06-16 17:22:59 -0600189}
190
Chris Daltonc3318f02019-07-19 14:20:53 -0600191void GrCCAtlas::setEndStencilResolveInstance(int idx) {
192 // This can't be called anymore once makeRenderTargetContext() has been called.
193 SkASSERT(!fTextureProxy->isInstantiated());
194 fEndStencilResolveInstance = idx;
195}
196
Chris Dalton4da70192018-06-18 09:51:36 -0600197static uint32_t next_atlas_unique_id() {
Mike Klein0ec1c572018-12-04 11:52:51 -0500198 static std::atomic<uint32_t> nextID;
199 return nextID++;
Chris Dalton4da70192018-06-18 09:51:36 -0600200}
201
Chris Dalton351e80c2019-01-06 22:51:00 -0700202sk_sp<GrCCCachedAtlas> GrCCAtlas::refOrMakeCachedAtlas(GrOnFlushResourceProvider* onFlushRP) {
203 if (!fCachedAtlas) {
204 static const GrUniqueKey::Domain kAtlasDomain = GrUniqueKey::GenerateDomain();
Chris Dalton4da70192018-06-18 09:51:36 -0600205
Chris Dalton351e80c2019-01-06 22:51:00 -0700206 GrUniqueKey atlasUniqueKey;
207 GrUniqueKey::Builder builder(&atlasUniqueKey, kAtlasDomain, 1, "CCPR Atlas");
Chris Dalton4da70192018-06-18 09:51:36 -0600208 builder[0] = next_atlas_unique_id();
209 builder.finish();
210
Chris Dalton351e80c2019-01-06 22:51:00 -0700211 onFlushRP->assignUniqueKeyToProxy(atlasUniqueKey, fTextureProxy.get());
Chris Daltond6fa4542019-01-04 13:23:51 -0700212
Chris Dalton351e80c2019-01-06 22:51:00 -0700213 fCachedAtlas = sk_make_sp<GrCCCachedAtlas>(fCoverageType, atlasUniqueKey, fTextureProxy);
Chris Dalton2e825a32019-01-04 22:14:27 +0000214 }
Chris Dalton351e80c2019-01-06 22:51:00 -0700215
216 SkASSERT(fCachedAtlas->coverageType() == fCoverageType);
217 SkASSERT(fCachedAtlas->getOnFlushProxy() == fTextureProxy.get());
218 return fCachedAtlas;
Chris Dalton4da70192018-06-18 09:51:36 -0600219}
220
Chris Dalton4c458b12018-06-16 17:22:59 -0600221sk_sp<GrRenderTargetContext> GrCCAtlas::makeRenderTargetContext(
Chris Daltonafde18f2018-06-22 12:44:19 -0600222 GrOnFlushResourceProvider* onFlushRP, sk_sp<GrTexture> backingTexture) {
Brian Salomonfd98c2c2018-07-31 17:25:29 -0400223 SkASSERT(!fTextureProxy->isInstantiated()); // This method should only be called once.
Chris Dalton4da70192018-06-18 09:51:36 -0600224 // Caller should have cropped any paths to the destination render target instead of asking for
225 // an atlas larger than maxRenderTargetSize.
226 SkASSERT(SkTMax(fHeight, fWidth) <= fMaxTextureSize);
Chris Dalton42c21152018-06-13 15:28:19 -0600227 SkASSERT(fMaxTextureSize <= onFlushRP->caps()->maxRenderTargetSize());
Chris Dalton1a325d22017-07-14 15:17:41 -0600228
Chris Daltonf91b7552019-04-29 16:21:18 -0600229 // Finalize the content size of our proxy. The GPU can potentially make optimizations if it
230 // knows we only intend to write out a smaller sub-rectangle of the backing texture.
231 fTextureProxy->priv().setLazySize(fDrawBounds.width(), fDrawBounds.height());
232
Chris Daltonafde18f2018-06-22 12:44:19 -0600233 if (backingTexture) {
Chris Daltonc3318f02019-07-19 14:20:53 -0600234#ifdef SK_DEBUG
235 auto backingRT = backingTexture->asRenderTarget();
236 SkASSERT(backingRT);
237 SkASSERT(backingRT->config() == fTextureProxy->config());
238 SkASSERT(backingRT->numSamples() == fTextureProxy->asRenderTargetProxy()->numSamples());
239 SkASSERT(backingRT->width() == fWidth);
240 SkASSERT(backingRT->height() == fHeight);
241#endif
Chris Daltonafde18f2018-06-22 12:44:19 -0600242 fBackingTexture = std::move(backingTexture);
243 }
Chris Daltonc3318f02019-07-19 14:20:53 -0600244 auto colorType = (CoverageType::kFP16_CoverageCount == fCoverageType)
245 ? GrColorType::kAlpha_F16 : GrColorType::kAlpha_8;
Brian Salomon2a4f9832018-03-03 22:43:43 -0500246 sk_sp<GrRenderTargetContext> rtc =
Brian Salomond6287472019-06-24 15:50:07 -0400247 onFlushRP->makeRenderTargetContext(fTextureProxy, colorType, nullptr, nullptr);
Chris Dalton1a325d22017-07-14 15:17:41 -0600248 if (!rtc) {
249 SkDebugf("WARNING: failed to allocate a %ix%i atlas. Some paths will not be drawn.\n",
250 fWidth, fHeight);
251 return nullptr;
252 }
253
254 SkIRect clearRect = SkIRect::MakeSize(fDrawBounds);
Brian Osman9a9baae2018-11-05 15:06:26 -0500255 rtc->clear(&clearRect, SK_PMColor4fTRANSPARENT,
256 GrRenderTargetContext::CanClearFullscreen::kYes);
Chris Dalton1a325d22017-07-14 15:17:41 -0600257 return rtc;
258}
Chris Dalton9414c962018-06-14 10:14:50 -0600259
Chris Dalton4c458b12018-06-16 17:22:59 -0600260GrCCAtlas* GrCCAtlasStack::addRect(const SkIRect& devIBounds, SkIVector* devToAtlasOffset) {
Chris Dalton9414c962018-06-14 10:14:50 -0600261 GrCCAtlas* retiredAtlas = nullptr;
Chris Dalton4c458b12018-06-16 17:22:59 -0600262 if (fAtlases.empty() || !fAtlases.back().addRect(devIBounds, devToAtlasOffset)) {
Chris Dalton9414c962018-06-14 10:14:50 -0600263 // The retired atlas is out of room and can't grow any bigger.
264 retiredAtlas = !fAtlases.empty() ? &fAtlases.back() : nullptr;
Chris Dalton351e80c2019-01-06 22:51:00 -0700265 fAtlases.emplace_back(fCoverageType, fSpecs, *fCaps);
Chris Dalton9414c962018-06-14 10:14:50 -0600266 SkASSERT(devIBounds.width() <= fSpecs.fMinWidth);
267 SkASSERT(devIBounds.height() <= fSpecs.fMinHeight);
Chris Dalton4c458b12018-06-16 17:22:59 -0600268 SkAssertResult(fAtlases.back().addRect(devIBounds, devToAtlasOffset));
Chris Dalton9414c962018-06-14 10:14:50 -0600269 }
270 return retiredAtlas;
271}