blob: da4138f4d5ead99ef8565dbfc889ea90c95a5610 [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 Dalton9ca27842018-01-18 12:24:50 -070018#include "ccpr/GrCCPathParser.h"
Chris Dalton1a325d22017-07-14 15:17:41 -060019#include "ops/GrDrawOp.h"
20
Chris Dalton2612bae2018-02-22 13:41:37 -070021static constexpr int kAtlasMinSize = 1024;
22static constexpr int kPadding = 1;
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
57 DrawCoverageCountOp(sk_sp<const GrCCPathParser> parser, CoverageCountBatchID batchID,
58 const SkISize& drawBounds)
59 : INHERITED(ClassID())
60 , fParser(std::move(parser))
61 , fBatchID(batchID)
62 , fDrawBounds(drawBounds) {
63 this->setBounds(SkRect::MakeIWH(fDrawBounds.width(), fDrawBounds.height()),
64 GrOp::HasAABloat::kNo, GrOp::IsZeroArea::kNo);
65 }
66
67 // GrDrawOp interface.
68 const char* name() const override { return "GrCCAtlas::DrawCoverageCountOp"; }
69 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
70 RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*,
71 GrPixelConfigIsClamped) override { return RequiresDstTexture::kNo; }
72 bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override { return false; }
73 void onPrepare(GrOpFlushState*) override {}
74 void onExecute(GrOpFlushState* flushState) override {
75 fParser->drawCoverageCount(flushState, fBatchID,
76 SkIRect::MakeWH(fDrawBounds.width(), fDrawBounds.height()));
77 }
78
79private:
80 const sk_sp<const GrCCPathParser> fParser;
81 const CoverageCountBatchID fBatchID;
82 const SkISize fDrawBounds;
83
84 typedef GrDrawOp INHERITED;
85};
86
Chris Dalton2612bae2018-02-22 13:41:37 -070087GrCCAtlas::GrCCAtlas(const GrCaps& caps, int minSize)
88 : fMaxAtlasSize(SkTMax(minSize, caps.maxPreferredRenderTargetSize())) {
89 // Caller should have cropped any paths to the destination render target instead of asking for
90 // an atlas larger than maxRenderTargetSize.
91 SkASSERT(fMaxAtlasSize <= caps.maxRenderTargetSize());
92 int initialSize = GrNextPow2(minSize + kPadding);
93 initialSize = SkTMax(kAtlasMinSize, initialSize);
Chris Dalton1a325d22017-07-14 15:17:41 -060094 initialSize = SkTMin(initialSize, fMaxAtlasSize);
95 fHeight = fWidth = initialSize;
Chris Dalton2612bae2018-02-22 13:41:37 -070096 fTopNode = skstd::make_unique<Node>(nullptr, 0, 0, fWidth, fHeight);
Chris Dalton1a325d22017-07-14 15:17:41 -060097}
98
Chris Dalton2612bae2018-02-22 13:41:37 -070099GrCCAtlas::~GrCCAtlas() {
100}
Chris Dalton1a325d22017-07-14 15:17:41 -0600101
Chris Dalton383a2ef2018-01-08 17:21:41 -0500102bool GrCCAtlas::addRect(int w, int h, SkIPoint16* loc) {
Chris Dalton9ca27842018-01-18 12:24:50 -0700103 // This can't be called anymore once setCoverageCountBatchID() has been called.
104 SkASSERT(!fCoverageCountBatchID);
Chris Dalton1a325d22017-07-14 15:17:41 -0600105 SkASSERT(!fTextureProxy);
106
107 if (!this->internalPlaceRect(w, h, loc)) {
108 return false;
109 }
110
111 fDrawBounds.fWidth = SkTMax(fDrawBounds.width(), loc->x() + w);
112 fDrawBounds.fHeight = SkTMax(fDrawBounds.height(), loc->y() + h);
113 return true;
114}
115
Chris Dalton383a2ef2018-01-08 17:21:41 -0500116bool GrCCAtlas::internalPlaceRect(int w, int h, SkIPoint16* loc) {
Chris Dalton1a325d22017-07-14 15:17:41 -0600117 for (Node* node = fTopNode.get(); node; node = node->previous()) {
Chris Dalton2612bae2018-02-22 13:41:37 -0700118 if (node->addRect(w, h, loc, fMaxAtlasSize)) {
Chris Dalton1a325d22017-07-14 15:17:41 -0600119 return true;
120 }
121 }
122
123 // The rect didn't fit. Grow the atlas and try again.
124 do {
Chris Dalton1a325d22017-07-14 15:17:41 -0600125 if (fWidth == fMaxAtlasSize && fHeight == fMaxAtlasSize) {
126 return false;
127 }
128 if (fHeight <= fWidth) {
129 int top = fHeight;
130 fHeight = SkTMin(fHeight * 2, fMaxAtlasSize);
131 fTopNode = skstd::make_unique<Node>(std::move(fTopNode), 0, top, fWidth, fHeight);
132 } else {
133 int left = fWidth;
134 fWidth = SkTMin(fWidth * 2, fMaxAtlasSize);
135 fTopNode = skstd::make_unique<Node>(std::move(fTopNode), left, 0, fWidth, fHeight);
136 }
Chris Dalton2612bae2018-02-22 13:41:37 -0700137 } while (!fTopNode->addRect(w, h, loc, fMaxAtlasSize));
Chris Dalton1a325d22017-07-14 15:17:41 -0600138
139 return true;
140}
141
Chris Dalton9ca27842018-01-18 12:24:50 -0700142sk_sp<GrRenderTargetContext> GrCCAtlas::finalize(GrOnFlushResourceProvider* onFlushRP,
143 sk_sp<const GrCCPathParser> parser) {
144 SkASSERT(fCoverageCountBatchID);
Chris Dalton1a325d22017-07-14 15:17:41 -0600145 SkASSERT(!fTextureProxy);
146
147 GrSurfaceDesc desc;
Robert Phillipsce5209a2018-02-13 11:13:51 -0500148 desc.fFlags = kRenderTarget_GrSurfaceFlag;
Chris Dalton1a325d22017-07-14 15:17:41 -0600149 desc.fWidth = fWidth;
150 desc.fHeight = fHeight;
151 desc.fConfig = kAlpha_half_GrPixelConfig;
Brian Salomon2a4f9832018-03-03 22:43:43 -0500152 sk_sp<GrRenderTargetContext> rtc =
153 onFlushRP->makeRenderTargetContext(desc, kTopLeft_GrSurfaceOrigin, nullptr, nullptr);
Chris Dalton1a325d22017-07-14 15:17:41 -0600154 if (!rtc) {
155 SkDebugf("WARNING: failed to allocate a %ix%i atlas. Some paths will not be drawn.\n",
156 fWidth, fHeight);
157 return nullptr;
158 }
159
160 SkIRect clearRect = SkIRect::MakeSize(fDrawBounds);
Chris Dalton344e9032017-12-11 15:42:09 -0700161 rtc->clear(&clearRect, 0, GrRenderTargetContext::CanClearFullscreen::kYes);
Chris Dalton9ca27842018-01-18 12:24:50 -0700162
163 auto op = skstd::make_unique<DrawCoverageCountOp>(std::move(parser), fCoverageCountBatchID,
164 fDrawBounds);
165 rtc->addDrawOp(GrNoClip(), std::move(op));
Chris Dalton1a325d22017-07-14 15:17:41 -0600166
167 fTextureProxy = sk_ref_sp(rtc->asTextureProxy());
168 return rtc;
169}