• 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 "GrCCPRAtlas.h"
9 
10 #include "GrOnFlushResourceProvider.h"
11 #include "GrClip.h"
12 #include "GrRectanizer_skyline.h"
13 #include "GrTextureProxy.h"
14 #include "GrRenderTargetContext.h"
15 #include "SkMakeUnique.h"
16 #include "SkMathPriv.h"
17 #include "ccpr/GrCCPRCoverageProcessor.h"
18 #include "ops/GrDrawOp.h"
19 
20 class GrCCPRAtlas::Node {
21 public:
Node(std::unique_ptr<Node> previous,int l,int t,int r,int b)22     Node(std::unique_ptr<Node> previous, int l, int t, int r, int b)
23             : fPrevious(std::move(previous))
24             , fX(l), fY(t)
25             , fRectanizer(r - l, b - t) {}
26 
previous() const27     Node* previous() const { return fPrevious.get(); }
28 
addRect(int w,int h,SkIPoint16 * loc)29     bool addRect(int w, int h, SkIPoint16* loc) {
30         static constexpr int kPad = 1;
31 
32         if (!fRectanizer.addRect(w + kPad, h + kPad, loc)) {
33             return false;
34         }
35         loc->fX += fX;
36         loc->fY += fY;
37         return true;
38     }
39 
40 private:
41     const std::unique_ptr<Node>   fPrevious;
42     const int                     fX, fY;
43     GrRectanizerSkyline           fRectanizer;
44 };
45 
GrCCPRAtlas(const GrCaps & caps,int minWidth,int minHeight)46 GrCCPRAtlas::GrCCPRAtlas(const GrCaps& caps, int minWidth, int minHeight)
47         : fMaxAtlasSize(caps.maxRenderTargetSize())
48         , fDrawBounds{0, 0} {
49     SkASSERT(fMaxAtlasSize <= caps.maxTextureSize());
50     SkASSERT(SkTMax(minWidth, minHeight) <= fMaxAtlasSize);
51     int initialSize = GrNextPow2(SkTMax(minWidth, minHeight));
52     initialSize = SkTMax(int(kMinSize), initialSize);
53     initialSize = SkTMin(initialSize, fMaxAtlasSize);
54     fHeight = fWidth = initialSize;
55     fTopNode = skstd::make_unique<Node>(nullptr, 0, 0, initialSize, initialSize);
56 }
57 
~GrCCPRAtlas()58 GrCCPRAtlas::~GrCCPRAtlas() {
59 }
60 
addRect(int w,int h,SkIPoint16 * loc)61 bool GrCCPRAtlas::addRect(int w, int h, SkIPoint16* loc) {
62     // This can't be called anymore once finalize() has been called.
63     SkASSERT(!fTextureProxy);
64 
65     if (!this->internalPlaceRect(w, h, loc)) {
66         return false;
67     }
68 
69     fDrawBounds.fWidth = SkTMax(fDrawBounds.width(), loc->x() + w);
70     fDrawBounds.fHeight = SkTMax(fDrawBounds.height(), loc->y() + h);
71     return true;
72 }
73 
internalPlaceRect(int w,int h,SkIPoint16 * loc)74 bool GrCCPRAtlas::internalPlaceRect(int w, int h, SkIPoint16* loc) {
75     SkASSERT(SkTMax(w, h) < fMaxAtlasSize);
76 
77     for (Node* node = fTopNode.get(); node; node = node->previous()) {
78         if (node->addRect(w, h, loc)) {
79             return true;
80         }
81     }
82 
83     // The rect didn't fit. Grow the atlas and try again.
84     do {
85         SkASSERT(SkTMax(fWidth, fHeight) <= fMaxAtlasSize);
86         if (fWidth == fMaxAtlasSize && fHeight == fMaxAtlasSize) {
87             return false;
88         }
89         if (fHeight <= fWidth) {
90             int top = fHeight;
91             fHeight = SkTMin(fHeight * 2, fMaxAtlasSize);
92             fTopNode = skstd::make_unique<Node>(std::move(fTopNode), 0, top, fWidth, fHeight);
93         } else {
94             int left = fWidth;
95             fWidth = SkTMin(fWidth * 2, fMaxAtlasSize);
96             fTopNode = skstd::make_unique<Node>(std::move(fTopNode), left, 0, fWidth, fHeight);
97         }
98     } while (!fTopNode->addRect(w, h, loc));
99 
100     return true;
101 }
102 
finalize(GrOnFlushResourceProvider * onFlushRP,std::unique_ptr<GrDrawOp> atlasOp)103 sk_sp<GrRenderTargetContext> GrCCPRAtlas::finalize(GrOnFlushResourceProvider* onFlushRP,
104                                                      std::unique_ptr<GrDrawOp> atlasOp) {
105     SkASSERT(!fTextureProxy);
106 
107     GrSurfaceDesc desc;
108     desc.fOrigin = GrCCPRCoverageProcessor::kAtlasOrigin;
109     desc.fWidth = fWidth;
110     desc.fHeight = fHeight;
111     desc.fConfig = kAlpha_half_GrPixelConfig;
112     sk_sp<GrRenderTargetContext> rtc = onFlushRP->makeRenderTargetContext(desc, nullptr, nullptr);
113     if (!rtc) {
114         SkDebugf("WARNING: failed to allocate a %ix%i atlas. Some paths will not be drawn.\n",
115                  fWidth, fHeight);
116         return nullptr;
117     }
118 
119     SkIRect clearRect = SkIRect::MakeSize(fDrawBounds);
120     rtc->clear(&clearRect, 0, true);
121     rtc->addDrawOp(GrNoClip(), std::move(atlasOp));
122 
123     fTextureProxy = sk_ref_sp(rtc->asTextureProxy());
124     return rtc;
125 }
126