blob: 8978e31ad952ae342541a6ceee97202c1001066d [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
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
20class GrCCPRAtlas::Node {
21public:
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
27 Node* previous() const { return fPrevious.get(); }
28
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
40private:
41 const std::unique_ptr<Node> fPrevious;
42 const int fX, fY;
43 GrRectanizerSkyline fRectanizer;
44};
45
46GrCCPRAtlas::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
58GrCCPRAtlas::~GrCCPRAtlas() {
59}
60
61bool 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
74bool 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
103sk_sp<GrRenderTargetContext> GrCCPRAtlas::finalize(GrOnFlushResourceProvider* onFlushRP,
Chris Daltonc1e59632017-09-05 00:30:07 -0600104 std::unique_ptr<GrDrawOp> atlasOp) {
Chris Dalton1a325d22017-07-14 15:17:41 -0600105 SkASSERT(!fTextureProxy);
106
107 GrSurfaceDesc desc;
Chris Dalton1a325d22017-07-14 15:17:41 -0600108 desc.fWidth = fWidth;
109 desc.fHeight = fHeight;
110 desc.fConfig = kAlpha_half_GrPixelConfig;
111 sk_sp<GrRenderTargetContext> rtc = onFlushRP->makeRenderTargetContext(desc, nullptr, nullptr);
112 if (!rtc) {
113 SkDebugf("WARNING: failed to allocate a %ix%i atlas. Some paths will not be drawn.\n",
114 fWidth, fHeight);
115 return nullptr;
116 }
117
118 SkIRect clearRect = SkIRect::MakeSize(fDrawBounds);
119 rtc->clear(&clearRect, 0, true);
120 rtc->addDrawOp(GrNoClip(), std::move(atlasOp));
121
122 fTextureProxy = sk_ref_sp(rtc->asTextureProxy());
123 return rtc;
124}