blob: 551b2a048e969cb6fa4c184c5134c903d8182a52 [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"
Robert Phillips7c525e62018-06-12 10:11:12 -040011#include "GrMemoryPool.h"
Chris Dalton383a2ef2018-01-08 17:21:41 -050012#include "GrOnFlushResourceProvider.h"
Robert Phillips88a32ef2018-06-07 11:05:56 -040013#include "GrSurfaceContextPriv.h"
Chris Dalton1a325d22017-07-14 15:17:41 -060014#include "GrRectanizer_skyline.h"
Chris Dalton1a325d22017-07-14 15:17:41 -060015#include "GrRenderTargetContext.h"
Robert Phillips7c525e62018-06-12 10:11:12 -040016#include "GrSurfaceContextPriv.h"
Chris Dalton383a2ef2018-01-08 17:21:41 -050017#include "GrTextureProxy.h"
Chris Dalton1a325d22017-07-14 15:17:41 -060018#include "SkMakeUnique.h"
19#include "SkMathPriv.h"
Chris Dalton383a2ef2018-01-08 17:21:41 -050020#include "ccpr/GrCCCoverageProcessor.h"
Chris Dalton9ca27842018-01-18 12:24:50 -070021#include "ccpr/GrCCPathParser.h"
Chris Dalton1a325d22017-07-14 15:17:41 -060022#include "ops/GrDrawOp.h"
23
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 Dalton9ca27842018-01-18 12:24:50 -070053class GrCCAtlas::DrawCoverageCountOp : public GrDrawOp {
54public:
55 DEFINE_OP_CLASS_ID
56
Robert Phillips88a32ef2018-06-07 11:05:56 -040057 static std::unique_ptr<GrDrawOp> Make(GrContext* context,
58 sk_sp<const GrCCPathParser> parser,
59 CoverageCountBatchID batchID,
60 const SkISize& drawBounds) {
61 return std::unique_ptr<GrDrawOp>(new DrawCoverageCountOp(std::move(parser),
62 batchID, drawBounds));
Chris Dalton9ca27842018-01-18 12:24:50 -070063 }
64
65 // GrDrawOp interface.
66 const char* name() const override { return "GrCCAtlas::DrawCoverageCountOp"; }
67 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
68 RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*,
69 GrPixelConfigIsClamped) override { return RequiresDstTexture::kNo; }
70 bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override { return false; }
71 void onPrepare(GrOpFlushState*) override {}
72 void onExecute(GrOpFlushState* flushState) override {
73 fParser->drawCoverageCount(flushState, fBatchID,
74 SkIRect::MakeWH(fDrawBounds.width(), fDrawBounds.height()));
75 }
76
77private:
Robert Phillips7c525e62018-06-12 10:11:12 -040078 friend class GrOpMemoryPool; // for ctor
79
Robert Phillips88a32ef2018-06-07 11:05:56 -040080 DrawCoverageCountOp(sk_sp<const GrCCPathParser> parser, CoverageCountBatchID batchID,
81 const SkISize& drawBounds)
82 : INHERITED(ClassID())
83 , fParser(std::move(parser))
84 , fBatchID(batchID)
85 , fDrawBounds(drawBounds) {
86 this->setBounds(SkRect::MakeIWH(fDrawBounds.width(), fDrawBounds.height()),
87 GrOp::HasAABloat::kNo, GrOp::IsZeroArea::kNo);
88 }
89
Chris Dalton9ca27842018-01-18 12:24:50 -070090 const sk_sp<const GrCCPathParser> fParser;
91 const CoverageCountBatchID fBatchID;
92 const SkISize fDrawBounds;
93
94 typedef GrDrawOp INHERITED;
95};
96
Chris Dalton42c21152018-06-13 15:28:19 -060097GrCCAtlas::GrCCAtlas(const Specs& specs)
98 : fMaxTextureSize(SkTMax(SkTMax(specs.fMinHeight, specs.fMinWidth),
99 specs.fMaxPreferredTextureSize)) {
100 SkASSERT(specs.fMaxPreferredTextureSize > 0);
101
102 // Begin with the first pow2 dimensions whose area is theoretically large enough to contain the
103 // pending paths, favoring height over width if necessary.
104 int log2area = SkNextLog2(SkTMax(specs.fApproxNumPixels, 1));
105 fHeight = 1 << ((log2area + 1) / 2);
106 fWidth = 1 << (log2area / 2);
107
108 fWidth = SkTClamp(fWidth, specs.fMinTextureSize, specs.fMaxPreferredTextureSize);
109 fHeight = SkTClamp(fHeight, specs.fMinTextureSize, specs.fMaxPreferredTextureSize);
110
111 if (fWidth < specs.fMinWidth || fHeight < specs.fMinHeight) {
112 // They want to stuff a particularly large path into the atlas. Just punt and go with their
113 // min width and height. The atlas will grow as needed.
114 fWidth = SkTMin(specs.fMinWidth + kPadding, fMaxTextureSize);
115 fHeight = SkTMin(specs.fMinHeight + kPadding, fMaxTextureSize);
116 }
117
Chris Dalton2612bae2018-02-22 13:41:37 -0700118 fTopNode = skstd::make_unique<Node>(nullptr, 0, 0, fWidth, fHeight);
Chris Dalton1a325d22017-07-14 15:17:41 -0600119}
120
Chris Dalton2612bae2018-02-22 13:41:37 -0700121GrCCAtlas::~GrCCAtlas() {
122}
Chris Dalton1a325d22017-07-14 15:17:41 -0600123
Chris Dalton383a2ef2018-01-08 17:21:41 -0500124bool GrCCAtlas::addRect(int w, int h, SkIPoint16* loc) {
Chris Dalton9ca27842018-01-18 12:24:50 -0700125 // This can't be called anymore once setCoverageCountBatchID() has been called.
126 SkASSERT(!fCoverageCountBatchID);
Chris Dalton1a325d22017-07-14 15:17:41 -0600127 SkASSERT(!fTextureProxy);
128
129 if (!this->internalPlaceRect(w, h, loc)) {
130 return false;
131 }
132
133 fDrawBounds.fWidth = SkTMax(fDrawBounds.width(), loc->x() + w);
134 fDrawBounds.fHeight = SkTMax(fDrawBounds.height(), loc->y() + h);
135 return true;
136}
137
Chris Dalton383a2ef2018-01-08 17:21:41 -0500138bool GrCCAtlas::internalPlaceRect(int w, int h, SkIPoint16* loc) {
Chris Dalton1a325d22017-07-14 15:17:41 -0600139 for (Node* node = fTopNode.get(); node; node = node->previous()) {
Chris Dalton42c21152018-06-13 15:28:19 -0600140 if (node->addRect(w, h, loc, fMaxTextureSize)) {
Chris Dalton1a325d22017-07-14 15:17:41 -0600141 return true;
142 }
143 }
144
145 // The rect didn't fit. Grow the atlas and try again.
146 do {
Chris Dalton42c21152018-06-13 15:28:19 -0600147 if (fWidth == fMaxTextureSize && fHeight == fMaxTextureSize) {
Chris Dalton1a325d22017-07-14 15:17:41 -0600148 return false;
149 }
150 if (fHeight <= fWidth) {
151 int top = fHeight;
Chris Dalton42c21152018-06-13 15:28:19 -0600152 fHeight = SkTMin(fHeight * 2, fMaxTextureSize);
Chris Dalton1a325d22017-07-14 15:17:41 -0600153 fTopNode = skstd::make_unique<Node>(std::move(fTopNode), 0, top, fWidth, fHeight);
154 } else {
155 int left = fWidth;
Chris Dalton42c21152018-06-13 15:28:19 -0600156 fWidth = SkTMin(fWidth * 2, fMaxTextureSize);
Chris Dalton1a325d22017-07-14 15:17:41 -0600157 fTopNode = skstd::make_unique<Node>(std::move(fTopNode), left, 0, fWidth, fHeight);
158 }
Chris Dalton42c21152018-06-13 15:28:19 -0600159 } while (!fTopNode->addRect(w, h, loc, fMaxTextureSize));
Chris Dalton1a325d22017-07-14 15:17:41 -0600160
161 return true;
162}
163
Chris Dalton9ca27842018-01-18 12:24:50 -0700164sk_sp<GrRenderTargetContext> GrCCAtlas::finalize(GrOnFlushResourceProvider* onFlushRP,
165 sk_sp<const GrCCPathParser> parser) {
166 SkASSERT(fCoverageCountBatchID);
Chris Dalton1a325d22017-07-14 15:17:41 -0600167 SkASSERT(!fTextureProxy);
Chris Dalton42c21152018-06-13 15:28:19 -0600168 // Caller should have cropped any paths to the destination render target instead of asking for
169 // an atlas larger than maxRenderTargetSize.
170 SkASSERT(fMaxTextureSize <= onFlushRP->caps()->maxRenderTargetSize());
Chris Dalton1a325d22017-07-14 15:17:41 -0600171
172 GrSurfaceDesc desc;
Robert Phillipsce5209a2018-02-13 11:13:51 -0500173 desc.fFlags = kRenderTarget_GrSurfaceFlag;
Chris Dalton1a325d22017-07-14 15:17:41 -0600174 desc.fWidth = fWidth;
175 desc.fHeight = fHeight;
176 desc.fConfig = kAlpha_half_GrPixelConfig;
Brian Salomon2a4f9832018-03-03 22:43:43 -0500177 sk_sp<GrRenderTargetContext> rtc =
178 onFlushRP->makeRenderTargetContext(desc, kTopLeft_GrSurfaceOrigin, nullptr, nullptr);
Chris Dalton1a325d22017-07-14 15:17:41 -0600179 if (!rtc) {
180 SkDebugf("WARNING: failed to allocate a %ix%i atlas. Some paths will not be drawn.\n",
181 fWidth, fHeight);
182 return nullptr;
183 }
184
185 SkIRect clearRect = SkIRect::MakeSize(fDrawBounds);
Chris Dalton344e9032017-12-11 15:42:09 -0700186 rtc->clear(&clearRect, 0, GrRenderTargetContext::CanClearFullscreen::kYes);
Chris Dalton9ca27842018-01-18 12:24:50 -0700187
Robert Phillips88a32ef2018-06-07 11:05:56 -0400188 GrContext* context = rtc->surfPriv().getContext();
189
190 std::unique_ptr<GrDrawOp> op = DrawCoverageCountOp::Make(context,
191 std::move(parser),
192 fCoverageCountBatchID,
193 fDrawBounds);
Chris Dalton9ca27842018-01-18 12:24:50 -0700194 rtc->addDrawOp(GrNoClip(), std::move(op));
Chris Dalton1a325d22017-07-14 15:17:41 -0600195
196 fTextureProxy = sk_ref_sp(rtc->asTextureProxy());
197 return rtc;
198}