blob: afa82c4ec7e5bcb730587e1ced9c49866888d0c0 [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"
Robert Phillips88a32ef2018-06-07 11:05:56 -040012#include "GrSurfaceContextPriv.h"
Chris Dalton1a325d22017-07-14 15:17:41 -060013#include "GrRectanizer_skyline.h"
Chris Dalton1a325d22017-07-14 15:17:41 -060014#include "GrRenderTargetContext.h"
Chris Dalton383a2ef2018-01-08 17:21:41 -050015#include "GrTextureProxy.h"
Chris Dalton1a325d22017-07-14 15:17:41 -060016#include "SkMakeUnique.h"
17#include "SkMathPriv.h"
Chris Dalton383a2ef2018-01-08 17:21:41 -050018#include "ccpr/GrCCCoverageProcessor.h"
Chris Dalton9ca27842018-01-18 12:24:50 -070019#include "ccpr/GrCCPathParser.h"
Chris Dalton1a325d22017-07-14 15:17:41 -060020#include "ops/GrDrawOp.h"
21
Chris Dalton2612bae2018-02-22 13:41:37 -070022static constexpr int kAtlasMinSize = 1024;
23static constexpr int kPadding = 1;
24
Chris Dalton383a2ef2018-01-08 17:21:41 -050025class GrCCAtlas::Node {
Chris Dalton1a325d22017-07-14 15:17:41 -060026public:
27 Node(std::unique_ptr<Node> previous, int l, int t, int r, int b)
Chris Dalton383a2ef2018-01-08 17:21:41 -050028 : fPrevious(std::move(previous)), fX(l), fY(t), fRectanizer(r - l, b - t) {}
Chris Dalton1a325d22017-07-14 15:17:41 -060029
30 Node* previous() const { return fPrevious.get(); }
31
Chris Dalton2612bae2018-02-22 13:41:37 -070032 bool addRect(int w, int h, SkIPoint16* loc, int maxAtlasSize) {
33 // Pad all paths except those that are expected to take up an entire physical texture.
34 if (w < maxAtlasSize) {
35 w = SkTMin(w + kPadding, maxAtlasSize);
36 }
37 if (h < maxAtlasSize) {
38 h = SkTMin(h + kPadding, maxAtlasSize);
39 }
40 if (!fRectanizer.addRect(w, h, loc)) {
Chris Dalton1a325d22017-07-14 15:17:41 -060041 return false;
42 }
43 loc->fX += fX;
44 loc->fY += fY;
45 return true;
46 }
47
48private:
Chris Dalton383a2ef2018-01-08 17:21:41 -050049 const std::unique_ptr<Node> fPrevious;
50 const int fX, fY;
51 GrRectanizerSkyline fRectanizer;
Chris Dalton1a325d22017-07-14 15:17:41 -060052};
53
Chris Dalton9ca27842018-01-18 12:24:50 -070054class GrCCAtlas::DrawCoverageCountOp : public GrDrawOp {
55public:
56 DEFINE_OP_CLASS_ID
57
Robert Phillips88a32ef2018-06-07 11:05:56 -040058 static std::unique_ptr<GrDrawOp> Make(GrContext* context,
59 sk_sp<const GrCCPathParser> parser,
60 CoverageCountBatchID batchID,
61 const SkISize& drawBounds) {
62 return std::unique_ptr<GrDrawOp>(new DrawCoverageCountOp(std::move(parser),
63 batchID, drawBounds));
Chris Dalton9ca27842018-01-18 12:24:50 -070064 }
65
66 // GrDrawOp interface.
67 const char* name() const override { return "GrCCAtlas::DrawCoverageCountOp"; }
68 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
69 RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*,
70 GrPixelConfigIsClamped) override { return RequiresDstTexture::kNo; }
71 bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override { return false; }
72 void onPrepare(GrOpFlushState*) override {}
73 void onExecute(GrOpFlushState* flushState) override {
74 fParser->drawCoverageCount(flushState, fBatchID,
75 SkIRect::MakeWH(fDrawBounds.width(), fDrawBounds.height()));
76 }
77
78private:
Robert Phillips88a32ef2018-06-07 11:05:56 -040079 DrawCoverageCountOp(sk_sp<const GrCCPathParser> parser, CoverageCountBatchID batchID,
80 const SkISize& drawBounds)
81 : INHERITED(ClassID())
82 , fParser(std::move(parser))
83 , fBatchID(batchID)
84 , fDrawBounds(drawBounds) {
85 this->setBounds(SkRect::MakeIWH(fDrawBounds.width(), fDrawBounds.height()),
86 GrOp::HasAABloat::kNo, GrOp::IsZeroArea::kNo);
87 }
88
Chris Dalton9ca27842018-01-18 12:24:50 -070089 const sk_sp<const GrCCPathParser> fParser;
90 const CoverageCountBatchID fBatchID;
91 const SkISize fDrawBounds;
92
93 typedef GrDrawOp INHERITED;
94};
95
Chris Dalton2612bae2018-02-22 13:41:37 -070096GrCCAtlas::GrCCAtlas(const GrCaps& caps, int minSize)
97 : fMaxAtlasSize(SkTMax(minSize, caps.maxPreferredRenderTargetSize())) {
98 // Caller should have cropped any paths to the destination render target instead of asking for
99 // an atlas larger than maxRenderTargetSize.
100 SkASSERT(fMaxAtlasSize <= caps.maxRenderTargetSize());
101 int initialSize = GrNextPow2(minSize + kPadding);
102 initialSize = SkTMax(kAtlasMinSize, initialSize);
Chris Dalton1a325d22017-07-14 15:17:41 -0600103 initialSize = SkTMin(initialSize, fMaxAtlasSize);
104 fHeight = fWidth = initialSize;
Chris Dalton2612bae2018-02-22 13:41:37 -0700105 fTopNode = skstd::make_unique<Node>(nullptr, 0, 0, fWidth, fHeight);
Chris Dalton1a325d22017-07-14 15:17:41 -0600106}
107
Chris Dalton2612bae2018-02-22 13:41:37 -0700108GrCCAtlas::~GrCCAtlas() {
109}
Chris Dalton1a325d22017-07-14 15:17:41 -0600110
Chris Dalton383a2ef2018-01-08 17:21:41 -0500111bool GrCCAtlas::addRect(int w, int h, SkIPoint16* loc) {
Chris Dalton9ca27842018-01-18 12:24:50 -0700112 // This can't be called anymore once setCoverageCountBatchID() has been called.
113 SkASSERT(!fCoverageCountBatchID);
Chris Dalton1a325d22017-07-14 15:17:41 -0600114 SkASSERT(!fTextureProxy);
115
116 if (!this->internalPlaceRect(w, h, loc)) {
117 return false;
118 }
119
120 fDrawBounds.fWidth = SkTMax(fDrawBounds.width(), loc->x() + w);
121 fDrawBounds.fHeight = SkTMax(fDrawBounds.height(), loc->y() + h);
122 return true;
123}
124
Chris Dalton383a2ef2018-01-08 17:21:41 -0500125bool GrCCAtlas::internalPlaceRect(int w, int h, SkIPoint16* loc) {
Chris Dalton1a325d22017-07-14 15:17:41 -0600126 for (Node* node = fTopNode.get(); node; node = node->previous()) {
Chris Dalton2612bae2018-02-22 13:41:37 -0700127 if (node->addRect(w, h, loc, fMaxAtlasSize)) {
Chris Dalton1a325d22017-07-14 15:17:41 -0600128 return true;
129 }
130 }
131
132 // The rect didn't fit. Grow the atlas and try again.
133 do {
Chris Dalton1a325d22017-07-14 15:17:41 -0600134 if (fWidth == fMaxAtlasSize && fHeight == fMaxAtlasSize) {
135 return false;
136 }
137 if (fHeight <= fWidth) {
138 int top = fHeight;
139 fHeight = SkTMin(fHeight * 2, fMaxAtlasSize);
140 fTopNode = skstd::make_unique<Node>(std::move(fTopNode), 0, top, fWidth, fHeight);
141 } else {
142 int left = fWidth;
143 fWidth = SkTMin(fWidth * 2, fMaxAtlasSize);
144 fTopNode = skstd::make_unique<Node>(std::move(fTopNode), left, 0, fWidth, fHeight);
145 }
Chris Dalton2612bae2018-02-22 13:41:37 -0700146 } while (!fTopNode->addRect(w, h, loc, fMaxAtlasSize));
Chris Dalton1a325d22017-07-14 15:17:41 -0600147
148 return true;
149}
150
Chris Dalton9ca27842018-01-18 12:24:50 -0700151sk_sp<GrRenderTargetContext> GrCCAtlas::finalize(GrOnFlushResourceProvider* onFlushRP,
152 sk_sp<const GrCCPathParser> parser) {
153 SkASSERT(fCoverageCountBatchID);
Chris Dalton1a325d22017-07-14 15:17:41 -0600154 SkASSERT(!fTextureProxy);
155
156 GrSurfaceDesc desc;
Robert Phillipsce5209a2018-02-13 11:13:51 -0500157 desc.fFlags = kRenderTarget_GrSurfaceFlag;
Chris Dalton1a325d22017-07-14 15:17:41 -0600158 desc.fWidth = fWidth;
159 desc.fHeight = fHeight;
160 desc.fConfig = kAlpha_half_GrPixelConfig;
Brian Salomon2a4f9832018-03-03 22:43:43 -0500161 sk_sp<GrRenderTargetContext> rtc =
162 onFlushRP->makeRenderTargetContext(desc, kTopLeft_GrSurfaceOrigin, nullptr, nullptr);
Chris Dalton1a325d22017-07-14 15:17:41 -0600163 if (!rtc) {
164 SkDebugf("WARNING: failed to allocate a %ix%i atlas. Some paths will not be drawn.\n",
165 fWidth, fHeight);
166 return nullptr;
167 }
168
169 SkIRect clearRect = SkIRect::MakeSize(fDrawBounds);
Chris Dalton344e9032017-12-11 15:42:09 -0700170 rtc->clear(&clearRect, 0, GrRenderTargetContext::CanClearFullscreen::kYes);
Chris Dalton9ca27842018-01-18 12:24:50 -0700171
Robert Phillips88a32ef2018-06-07 11:05:56 -0400172 GrContext* context = rtc->surfPriv().getContext();
173
174 std::unique_ptr<GrDrawOp> op = DrawCoverageCountOp::Make(context,
175 std::move(parser),
176 fCoverageCountBatchID,
177 fDrawBounds);
Chris Dalton9ca27842018-01-18 12:24:50 -0700178 rtc->addDrawOp(GrNoClip(), std::move(op));
Chris Dalton1a325d22017-07-14 15:17:41 -0600179
180 fTextureProxy = sk_ref_sp(rtc->asTextureProxy());
181 return rtc;
182}