blob: df84ed75a49c3c8003d8815c28579da10f8369ff [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 Dalton2612bae2018-02-22 13:41:37 -070024static constexpr int kAtlasMinSize = 1024;
25static constexpr int kPadding = 1;
26
Chris Dalton383a2ef2018-01-08 17:21:41 -050027class GrCCAtlas::Node {
Chris Dalton1a325d22017-07-14 15:17:41 -060028public:
29 Node(std::unique_ptr<Node> previous, int l, int t, int r, int b)
Chris Dalton383a2ef2018-01-08 17:21:41 -050030 : fPrevious(std::move(previous)), fX(l), fY(t), fRectanizer(r - l, b - t) {}
Chris Dalton1a325d22017-07-14 15:17:41 -060031
32 Node* previous() const { return fPrevious.get(); }
33
Chris Dalton2612bae2018-02-22 13:41:37 -070034 bool addRect(int w, int h, SkIPoint16* loc, int maxAtlasSize) {
35 // Pad all paths except those that are expected to take up an entire physical texture.
36 if (w < maxAtlasSize) {
37 w = SkTMin(w + kPadding, maxAtlasSize);
38 }
39 if (h < maxAtlasSize) {
40 h = SkTMin(h + kPadding, maxAtlasSize);
41 }
42 if (!fRectanizer.addRect(w, h, loc)) {
Chris Dalton1a325d22017-07-14 15:17:41 -060043 return false;
44 }
45 loc->fX += fX;
46 loc->fY += fY;
47 return true;
48 }
49
50private:
Chris Dalton383a2ef2018-01-08 17:21:41 -050051 const std::unique_ptr<Node> fPrevious;
52 const int fX, fY;
53 GrRectanizerSkyline fRectanizer;
Chris Dalton1a325d22017-07-14 15:17:41 -060054};
55
Chris Dalton9ca27842018-01-18 12:24:50 -070056class GrCCAtlas::DrawCoverageCountOp : public GrDrawOp {
57public:
58 DEFINE_OP_CLASS_ID
59
Robert Phillips88a32ef2018-06-07 11:05:56 -040060 static std::unique_ptr<GrDrawOp> Make(GrContext* context,
61 sk_sp<const GrCCPathParser> parser,
62 CoverageCountBatchID batchID,
63 const SkISize& drawBounds) {
64 return std::unique_ptr<GrDrawOp>(new DrawCoverageCountOp(std::move(parser),
65 batchID, drawBounds));
Chris Dalton9ca27842018-01-18 12:24:50 -070066 }
67
68 // GrDrawOp interface.
69 const char* name() const override { return "GrCCAtlas::DrawCoverageCountOp"; }
70 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
71 RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*,
72 GrPixelConfigIsClamped) override { return RequiresDstTexture::kNo; }
73 bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override { return false; }
74 void onPrepare(GrOpFlushState*) override {}
75 void onExecute(GrOpFlushState* flushState) override {
76 fParser->drawCoverageCount(flushState, fBatchID,
77 SkIRect::MakeWH(fDrawBounds.width(), fDrawBounds.height()));
78 }
79
80private:
Robert Phillips7c525e62018-06-12 10:11:12 -040081 friend class GrOpMemoryPool; // for ctor
82
Robert Phillips88a32ef2018-06-07 11:05:56 -040083 DrawCoverageCountOp(sk_sp<const GrCCPathParser> parser, CoverageCountBatchID batchID,
84 const SkISize& drawBounds)
85 : INHERITED(ClassID())
86 , fParser(std::move(parser))
87 , fBatchID(batchID)
88 , fDrawBounds(drawBounds) {
89 this->setBounds(SkRect::MakeIWH(fDrawBounds.width(), fDrawBounds.height()),
90 GrOp::HasAABloat::kNo, GrOp::IsZeroArea::kNo);
91 }
92
Chris Dalton9ca27842018-01-18 12:24:50 -070093 const sk_sp<const GrCCPathParser> fParser;
94 const CoverageCountBatchID fBatchID;
95 const SkISize fDrawBounds;
96
97 typedef GrDrawOp INHERITED;
98};
99
Chris Dalton2612bae2018-02-22 13:41:37 -0700100GrCCAtlas::GrCCAtlas(const GrCaps& caps, int minSize)
101 : fMaxAtlasSize(SkTMax(minSize, caps.maxPreferredRenderTargetSize())) {
102 // Caller should have cropped any paths to the destination render target instead of asking for
103 // an atlas larger than maxRenderTargetSize.
104 SkASSERT(fMaxAtlasSize <= caps.maxRenderTargetSize());
105 int initialSize = GrNextPow2(minSize + kPadding);
106 initialSize = SkTMax(kAtlasMinSize, initialSize);
Chris Dalton1a325d22017-07-14 15:17:41 -0600107 initialSize = SkTMin(initialSize, fMaxAtlasSize);
108 fHeight = fWidth = initialSize;
Chris Dalton2612bae2018-02-22 13:41:37 -0700109 fTopNode = skstd::make_unique<Node>(nullptr, 0, 0, fWidth, fHeight);
Chris Dalton1a325d22017-07-14 15:17:41 -0600110}
111
Chris Dalton2612bae2018-02-22 13:41:37 -0700112GrCCAtlas::~GrCCAtlas() {
113}
Chris Dalton1a325d22017-07-14 15:17:41 -0600114
Chris Dalton383a2ef2018-01-08 17:21:41 -0500115bool GrCCAtlas::addRect(int w, int h, SkIPoint16* loc) {
Chris Dalton9ca27842018-01-18 12:24:50 -0700116 // This can't be called anymore once setCoverageCountBatchID() has been called.
117 SkASSERT(!fCoverageCountBatchID);
Chris Dalton1a325d22017-07-14 15:17:41 -0600118 SkASSERT(!fTextureProxy);
119
120 if (!this->internalPlaceRect(w, h, loc)) {
121 return false;
122 }
123
124 fDrawBounds.fWidth = SkTMax(fDrawBounds.width(), loc->x() + w);
125 fDrawBounds.fHeight = SkTMax(fDrawBounds.height(), loc->y() + h);
126 return true;
127}
128
Chris Dalton383a2ef2018-01-08 17:21:41 -0500129bool GrCCAtlas::internalPlaceRect(int w, int h, SkIPoint16* loc) {
Chris Dalton1a325d22017-07-14 15:17:41 -0600130 for (Node* node = fTopNode.get(); node; node = node->previous()) {
Chris Dalton2612bae2018-02-22 13:41:37 -0700131 if (node->addRect(w, h, loc, fMaxAtlasSize)) {
Chris Dalton1a325d22017-07-14 15:17:41 -0600132 return true;
133 }
134 }
135
136 // The rect didn't fit. Grow the atlas and try again.
137 do {
Chris Dalton1a325d22017-07-14 15:17:41 -0600138 if (fWidth == fMaxAtlasSize && fHeight == fMaxAtlasSize) {
139 return false;
140 }
141 if (fHeight <= fWidth) {
142 int top = fHeight;
143 fHeight = SkTMin(fHeight * 2, fMaxAtlasSize);
144 fTopNode = skstd::make_unique<Node>(std::move(fTopNode), 0, top, fWidth, fHeight);
145 } else {
146 int left = fWidth;
147 fWidth = SkTMin(fWidth * 2, fMaxAtlasSize);
148 fTopNode = skstd::make_unique<Node>(std::move(fTopNode), left, 0, fWidth, fHeight);
149 }
Chris Dalton2612bae2018-02-22 13:41:37 -0700150 } while (!fTopNode->addRect(w, h, loc, fMaxAtlasSize));
Chris Dalton1a325d22017-07-14 15:17:41 -0600151
152 return true;
153}
154
Chris Dalton9ca27842018-01-18 12:24:50 -0700155sk_sp<GrRenderTargetContext> GrCCAtlas::finalize(GrOnFlushResourceProvider* onFlushRP,
156 sk_sp<const GrCCPathParser> parser) {
157 SkASSERT(fCoverageCountBatchID);
Chris Dalton1a325d22017-07-14 15:17:41 -0600158 SkASSERT(!fTextureProxy);
159
160 GrSurfaceDesc desc;
Robert Phillipsce5209a2018-02-13 11:13:51 -0500161 desc.fFlags = kRenderTarget_GrSurfaceFlag;
Chris Dalton1a325d22017-07-14 15:17:41 -0600162 desc.fWidth = fWidth;
163 desc.fHeight = fHeight;
164 desc.fConfig = kAlpha_half_GrPixelConfig;
Brian Salomon2a4f9832018-03-03 22:43:43 -0500165 sk_sp<GrRenderTargetContext> rtc =
166 onFlushRP->makeRenderTargetContext(desc, kTopLeft_GrSurfaceOrigin, nullptr, nullptr);
Chris Dalton1a325d22017-07-14 15:17:41 -0600167 if (!rtc) {
168 SkDebugf("WARNING: failed to allocate a %ix%i atlas. Some paths will not be drawn.\n",
169 fWidth, fHeight);
170 return nullptr;
171 }
172
173 SkIRect clearRect = SkIRect::MakeSize(fDrawBounds);
Chris Dalton344e9032017-12-11 15:42:09 -0700174 rtc->clear(&clearRect, 0, GrRenderTargetContext::CanClearFullscreen::kYes);
Chris Dalton9ca27842018-01-18 12:24:50 -0700175
Robert Phillips88a32ef2018-06-07 11:05:56 -0400176 GrContext* context = rtc->surfPriv().getContext();
177
178 std::unique_ptr<GrDrawOp> op = DrawCoverageCountOp::Make(context,
179 std::move(parser),
180 fCoverageCountBatchID,
181 fDrawBounds);
Chris Dalton9ca27842018-01-18 12:24:50 -0700182 rtc->addDrawOp(GrNoClip(), std::move(op));
Chris Dalton1a325d22017-07-14 15:17:41 -0600183
184 fTextureProxy = sk_ref_sp(rtc->asTextureProxy());
185 return rtc;
186}