blob: 055382cf9bbd7c26ae6945b7e310a28cce27445e [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
Chris Dalton383a2ef2018-01-08 17:21:41 -05008#include "GrCCAtlas.h"
Chris Dalton1a325d22017-07-14 15:17:41 -06009
Chris Dalton1a325d22017-07-14 15:17:41 -060010#include "GrClip.h"
Chris Dalton383a2ef2018-01-08 17:21:41 -050011#include "GrOnFlushResourceProvider.h"
Chris Dalton1a325d22017-07-14 15:17:41 -060012#include "GrRectanizer_skyline.h"
Chris Dalton1a325d22017-07-14 15:17:41 -060013#include "GrRenderTargetContext.h"
Chris Dalton383a2ef2018-01-08 17:21:41 -050014#include "GrTextureProxy.h"
Chris Dalton1a325d22017-07-14 15:17:41 -060015#include "SkMakeUnique.h"
16#include "SkMathPriv.h"
Chris Dalton383a2ef2018-01-08 17:21:41 -050017#include "ccpr/GrCCCoverageProcessor.h"
Chris Dalton1a325d22017-07-14 15:17:41 -060018#include "ops/GrDrawOp.h"
19
Chris Dalton383a2ef2018-01-08 17:21:41 -050020class GrCCAtlas::Node {
Chris Dalton1a325d22017-07-14 15:17:41 -060021public:
22 Node(std::unique_ptr<Node> previous, int l, int t, int r, int b)
Chris Dalton383a2ef2018-01-08 17:21:41 -050023 : fPrevious(std::move(previous)), fX(l), fY(t), fRectanizer(r - l, b - t) {}
Chris Dalton1a325d22017-07-14 15:17:41 -060024
25 Node* previous() const { return fPrevious.get(); }
26
27 bool addRect(int w, int h, SkIPoint16* loc) {
28 static constexpr int kPad = 1;
29
30 if (!fRectanizer.addRect(w + kPad, h + kPad, loc)) {
31 return false;
32 }
33 loc->fX += fX;
34 loc->fY += fY;
35 return true;
36 }
37
38private:
Chris Dalton383a2ef2018-01-08 17:21:41 -050039 const std::unique_ptr<Node> fPrevious;
40 const int fX, fY;
41 GrRectanizerSkyline fRectanizer;
Chris Dalton1a325d22017-07-14 15:17:41 -060042};
43
Chris Dalton383a2ef2018-01-08 17:21:41 -050044GrCCAtlas::GrCCAtlas(const GrCaps& caps, int minWidth, int minHeight)
45 : fMaxAtlasSize(caps.maxRenderTargetSize()), fDrawBounds{0, 0} {
Chris Dalton1a325d22017-07-14 15:17:41 -060046 SkASSERT(fMaxAtlasSize <= caps.maxTextureSize());
47 SkASSERT(SkTMax(minWidth, minHeight) <= fMaxAtlasSize);
48 int initialSize = GrNextPow2(SkTMax(minWidth, minHeight));
49 initialSize = SkTMax(int(kMinSize), initialSize);
50 initialSize = SkTMin(initialSize, fMaxAtlasSize);
51 fHeight = fWidth = initialSize;
52 fTopNode = skstd::make_unique<Node>(nullptr, 0, 0, initialSize, initialSize);
53}
54
Chris Dalton383a2ef2018-01-08 17:21:41 -050055GrCCAtlas::~GrCCAtlas() {}
Chris Dalton1a325d22017-07-14 15:17:41 -060056
Chris Dalton383a2ef2018-01-08 17:21:41 -050057bool GrCCAtlas::addRect(int w, int h, SkIPoint16* loc) {
Chris Dalton1a325d22017-07-14 15:17:41 -060058 // This can't be called anymore once finalize() has been called.
59 SkASSERT(!fTextureProxy);
60
61 if (!this->internalPlaceRect(w, h, loc)) {
62 return false;
63 }
64
65 fDrawBounds.fWidth = SkTMax(fDrawBounds.width(), loc->x() + w);
66 fDrawBounds.fHeight = SkTMax(fDrawBounds.height(), loc->y() + h);
67 return true;
68}
69
Chris Dalton383a2ef2018-01-08 17:21:41 -050070bool GrCCAtlas::internalPlaceRect(int w, int h, SkIPoint16* loc) {
Chris Dalton1a325d22017-07-14 15:17:41 -060071 SkASSERT(SkTMax(w, h) < fMaxAtlasSize);
72
73 for (Node* node = fTopNode.get(); node; node = node->previous()) {
74 if (node->addRect(w, h, loc)) {
75 return true;
76 }
77 }
78
79 // The rect didn't fit. Grow the atlas and try again.
80 do {
81 SkASSERT(SkTMax(fWidth, fHeight) <= fMaxAtlasSize);
82 if (fWidth == fMaxAtlasSize && fHeight == fMaxAtlasSize) {
83 return false;
84 }
85 if (fHeight <= fWidth) {
86 int top = fHeight;
87 fHeight = SkTMin(fHeight * 2, fMaxAtlasSize);
88 fTopNode = skstd::make_unique<Node>(std::move(fTopNode), 0, top, fWidth, fHeight);
89 } else {
90 int left = fWidth;
91 fWidth = SkTMin(fWidth * 2, fMaxAtlasSize);
92 fTopNode = skstd::make_unique<Node>(std::move(fTopNode), left, 0, fWidth, fHeight);
93 }
94 } while (!fTopNode->addRect(w, h, loc));
95
96 return true;
97}
98
Chris Dalton383a2ef2018-01-08 17:21:41 -050099sk_sp<GrRenderTargetContext> GrCCAtlas::finalize(
100 GrOnFlushResourceProvider* onFlushRP, std::unique_ptr<GrDrawOp> atlasOp) {
Chris Dalton1a325d22017-07-14 15:17:41 -0600101 SkASSERT(!fTextureProxy);
102
103 GrSurfaceDesc desc;
Chris Dalton1a325d22017-07-14 15:17:41 -0600104 desc.fWidth = fWidth;
105 desc.fHeight = fHeight;
106 desc.fConfig = kAlpha_half_GrPixelConfig;
107 sk_sp<GrRenderTargetContext> rtc = onFlushRP->makeRenderTargetContext(desc, nullptr, nullptr);
108 if (!rtc) {
109 SkDebugf("WARNING: failed to allocate a %ix%i atlas. Some paths will not be drawn.\n",
110 fWidth, fHeight);
111 return nullptr;
112 }
113
114 SkIRect clearRect = SkIRect::MakeSize(fDrawBounds);
Chris Dalton344e9032017-12-11 15:42:09 -0700115 rtc->clear(&clearRect, 0, GrRenderTargetContext::CanClearFullscreen::kYes);
Chris Dalton1a325d22017-07-14 15:17:41 -0600116 rtc->addDrawOp(GrNoClip(), std::move(atlasOp));
117
118 fTextureProxy = sk_ref_sp(rtc->asTextureProxy());
119 return rtc;
120}