blob: 5ef39f85cb16806146c3b363b0837d2137108897 [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 Dalton383a2ef2018-01-08 17:21:41 -050021class GrCCAtlas::Node {
Chris Dalton1a325d22017-07-14 15:17:41 -060022public:
23 Node(std::unique_ptr<Node> previous, int l, int t, int r, int b)
Chris Dalton383a2ef2018-01-08 17:21:41 -050024 : fPrevious(std::move(previous)), fX(l), fY(t), fRectanizer(r - l, b - t) {}
Chris Dalton1a325d22017-07-14 15:17:41 -060025
26 Node* previous() const { return fPrevious.get(); }
27
28 bool addRect(int w, int h, SkIPoint16* loc) {
29 static constexpr int kPad = 1;
30
31 if (!fRectanizer.addRect(w + kPad, h + kPad, loc)) {
32 return false;
33 }
34 loc->fX += fX;
35 loc->fY += fY;
36 return true;
37 }
38
39private:
Chris Dalton383a2ef2018-01-08 17:21:41 -050040 const std::unique_ptr<Node> fPrevious;
41 const int fX, fY;
42 GrRectanizerSkyline fRectanizer;
Chris Dalton1a325d22017-07-14 15:17:41 -060043};
44
Chris Dalton9ca27842018-01-18 12:24:50 -070045class GrCCAtlas::DrawCoverageCountOp : public GrDrawOp {
46public:
47 DEFINE_OP_CLASS_ID
48
49 DrawCoverageCountOp(sk_sp<const GrCCPathParser> parser, CoverageCountBatchID batchID,
50 const SkISize& drawBounds)
51 : INHERITED(ClassID())
52 , fParser(std::move(parser))
53 , fBatchID(batchID)
54 , fDrawBounds(drawBounds) {
55 this->setBounds(SkRect::MakeIWH(fDrawBounds.width(), fDrawBounds.height()),
56 GrOp::HasAABloat::kNo, GrOp::IsZeroArea::kNo);
57 }
58
59 // GrDrawOp interface.
60 const char* name() const override { return "GrCCAtlas::DrawCoverageCountOp"; }
61 FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; }
62 RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*,
63 GrPixelConfigIsClamped) override { return RequiresDstTexture::kNo; }
64 bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override { return false; }
65 void onPrepare(GrOpFlushState*) override {}
66 void onExecute(GrOpFlushState* flushState) override {
67 fParser->drawCoverageCount(flushState, fBatchID,
68 SkIRect::MakeWH(fDrawBounds.width(), fDrawBounds.height()));
69 }
70
71private:
72 const sk_sp<const GrCCPathParser> fParser;
73 const CoverageCountBatchID fBatchID;
74 const SkISize fDrawBounds;
75
76 typedef GrDrawOp INHERITED;
77};
78
Chris Dalton383a2ef2018-01-08 17:21:41 -050079GrCCAtlas::GrCCAtlas(const GrCaps& caps, int minWidth, int minHeight)
80 : fMaxAtlasSize(caps.maxRenderTargetSize()), fDrawBounds{0, 0} {
Chris Dalton1a325d22017-07-14 15:17:41 -060081 SkASSERT(fMaxAtlasSize <= caps.maxTextureSize());
82 SkASSERT(SkTMax(minWidth, minHeight) <= fMaxAtlasSize);
83 int initialSize = GrNextPow2(SkTMax(minWidth, minHeight));
84 initialSize = SkTMax(int(kMinSize), initialSize);
85 initialSize = SkTMin(initialSize, fMaxAtlasSize);
86 fHeight = fWidth = initialSize;
87 fTopNode = skstd::make_unique<Node>(nullptr, 0, 0, initialSize, initialSize);
88}
89
Chris Dalton383a2ef2018-01-08 17:21:41 -050090GrCCAtlas::~GrCCAtlas() {}
Chris Dalton1a325d22017-07-14 15:17:41 -060091
Chris Dalton383a2ef2018-01-08 17:21:41 -050092bool GrCCAtlas::addRect(int w, int h, SkIPoint16* loc) {
Chris Dalton9ca27842018-01-18 12:24:50 -070093 // This can't be called anymore once setCoverageCountBatchID() has been called.
94 SkASSERT(!fCoverageCountBatchID);
Chris Dalton1a325d22017-07-14 15:17:41 -060095 SkASSERT(!fTextureProxy);
96
97 if (!this->internalPlaceRect(w, h, loc)) {
98 return false;
99 }
100
101 fDrawBounds.fWidth = SkTMax(fDrawBounds.width(), loc->x() + w);
102 fDrawBounds.fHeight = SkTMax(fDrawBounds.height(), loc->y() + h);
103 return true;
104}
105
Chris Dalton383a2ef2018-01-08 17:21:41 -0500106bool GrCCAtlas::internalPlaceRect(int w, int h, SkIPoint16* loc) {
Chris Dalton1a325d22017-07-14 15:17:41 -0600107 SkASSERT(SkTMax(w, h) < fMaxAtlasSize);
108
109 for (Node* node = fTopNode.get(); node; node = node->previous()) {
110 if (node->addRect(w, h, loc)) {
111 return true;
112 }
113 }
114
115 // The rect didn't fit. Grow the atlas and try again.
116 do {
117 SkASSERT(SkTMax(fWidth, fHeight) <= fMaxAtlasSize);
118 if (fWidth == fMaxAtlasSize && fHeight == fMaxAtlasSize) {
119 return false;
120 }
121 if (fHeight <= fWidth) {
122 int top = fHeight;
123 fHeight = SkTMin(fHeight * 2, fMaxAtlasSize);
124 fTopNode = skstd::make_unique<Node>(std::move(fTopNode), 0, top, fWidth, fHeight);
125 } else {
126 int left = fWidth;
127 fWidth = SkTMin(fWidth * 2, fMaxAtlasSize);
128 fTopNode = skstd::make_unique<Node>(std::move(fTopNode), left, 0, fWidth, fHeight);
129 }
130 } while (!fTopNode->addRect(w, h, loc));
131
132 return true;
133}
134
Chris Dalton9ca27842018-01-18 12:24:50 -0700135sk_sp<GrRenderTargetContext> GrCCAtlas::finalize(GrOnFlushResourceProvider* onFlushRP,
136 sk_sp<const GrCCPathParser> parser) {
137 SkASSERT(fCoverageCountBatchID);
Chris Dalton1a325d22017-07-14 15:17:41 -0600138 SkASSERT(!fTextureProxy);
139
140 GrSurfaceDesc desc;
Chris Dalton1a325d22017-07-14 15:17:41 -0600141 desc.fWidth = fWidth;
142 desc.fHeight = fHeight;
143 desc.fConfig = kAlpha_half_GrPixelConfig;
144 sk_sp<GrRenderTargetContext> rtc = onFlushRP->makeRenderTargetContext(desc, nullptr, nullptr);
145 if (!rtc) {
146 SkDebugf("WARNING: failed to allocate a %ix%i atlas. Some paths will not be drawn.\n",
147 fWidth, fHeight);
148 return nullptr;
149 }
150
151 SkIRect clearRect = SkIRect::MakeSize(fDrawBounds);
Chris Dalton344e9032017-12-11 15:42:09 -0700152 rtc->clear(&clearRect, 0, GrRenderTargetContext::CanClearFullscreen::kYes);
Chris Dalton9ca27842018-01-18 12:24:50 -0700153
154 auto op = skstd::make_unique<DrawCoverageCountOp>(std::move(parser), fCoverageCountBatchID,
155 fDrawBounds);
156 rtc->addDrawOp(GrNoClip(), std::move(op));
Chris Dalton1a325d22017-07-14 15:17:41 -0600157
158 fTextureProxy = sk_ref_sp(rtc->asTextureProxy());
159 return rtc;
160}