1 /* 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 8 #include "GrCCPRAtlas.h" 9 10 #include "GrOnFlushResourceProvider.h" 11 #include "GrClip.h" 12 #include "GrRectanizer_skyline.h" 13 #include "GrTextureProxy.h" 14 #include "GrRenderTargetContext.h" 15 #include "SkMakeUnique.h" 16 #include "SkMathPriv.h" 17 #include "ccpr/GrCCPRCoverageProcessor.h" 18 #include "ops/GrDrawOp.h" 19 20 class GrCCPRAtlas::Node { 21 public: 22 Node(std::unique_ptr<Node> previous, int l, int t, int r, int b) 23 : fPrevious(std::move(previous)) 24 , fX(l), fY(t) 25 , fRectanizer(r - l, b - t) {} 26 27 Node* previous() const { return fPrevious.get(); } 28 29 bool addRect(int w, int h, SkIPoint16* loc) { 30 static constexpr int kPad = 1; 31 32 if (!fRectanizer.addRect(w + kPad, h + kPad, loc)) { 33 return false; 34 } 35 loc->fX += fX; 36 loc->fY += fY; 37 return true; 38 } 39 40 private: 41 const std::unique_ptr<Node> fPrevious; 42 const int fX, fY; 43 GrRectanizerSkyline fRectanizer; 44 }; 45 46 GrCCPRAtlas::GrCCPRAtlas(const GrCaps& caps, int minWidth, int minHeight) 47 : fMaxAtlasSize(caps.maxRenderTargetSize()) 48 , fDrawBounds{0, 0} { 49 SkASSERT(fMaxAtlasSize <= caps.maxTextureSize()); 50 SkASSERT(SkTMax(minWidth, minHeight) <= fMaxAtlasSize); 51 int initialSize = GrNextPow2(SkTMax(minWidth, minHeight)); 52 initialSize = SkTMax(int(kMinSize), initialSize); 53 initialSize = SkTMin(initialSize, fMaxAtlasSize); 54 fHeight = fWidth = initialSize; 55 fTopNode = skstd::make_unique<Node>(nullptr, 0, 0, initialSize, initialSize); 56 } 57 58 GrCCPRAtlas::~GrCCPRAtlas() { 59 } 60 61 bool GrCCPRAtlas::addRect(int w, int h, SkIPoint16* loc) { 62 // This can't be called anymore once finalize() has been called. 63 SkASSERT(!fTextureProxy); 64 65 if (!this->internalPlaceRect(w, h, loc)) { 66 return false; 67 } 68 69 fDrawBounds.fWidth = SkTMax(fDrawBounds.width(), loc->x() + w); 70 fDrawBounds.fHeight = SkTMax(fDrawBounds.height(), loc->y() + h); 71 return true; 72 } 73 74 bool GrCCPRAtlas::internalPlaceRect(int w, int h, SkIPoint16* loc) { 75 SkASSERT(SkTMax(w, h) < fMaxAtlasSize); 76 77 for (Node* node = fTopNode.get(); node; node = node->previous()) { 78 if (node->addRect(w, h, loc)) { 79 return true; 80 } 81 } 82 83 // The rect didn't fit. Grow the atlas and try again. 84 do { 85 SkASSERT(SkTMax(fWidth, fHeight) <= fMaxAtlasSize); 86 if (fWidth == fMaxAtlasSize && fHeight == fMaxAtlasSize) { 87 return false; 88 } 89 if (fHeight <= fWidth) { 90 int top = fHeight; 91 fHeight = SkTMin(fHeight * 2, fMaxAtlasSize); 92 fTopNode = skstd::make_unique<Node>(std::move(fTopNode), 0, top, fWidth, fHeight); 93 } else { 94 int left = fWidth; 95 fWidth = SkTMin(fWidth * 2, fMaxAtlasSize); 96 fTopNode = skstd::make_unique<Node>(std::move(fTopNode), left, 0, fWidth, fHeight); 97 } 98 } while (!fTopNode->addRect(w, h, loc)); 99 100 return true; 101 } 102 103 sk_sp<GrRenderTargetContext> GrCCPRAtlas::finalize(GrOnFlushResourceProvider* onFlushRP, 104 std::unique_ptr<GrDrawOp> atlasOp) { 105 SkASSERT(!fTextureProxy); 106 107 GrSurfaceDesc desc; 108 desc.fOrigin = GrCCPRCoverageProcessor::kAtlasOrigin; 109 desc.fWidth = fWidth; 110 desc.fHeight = fHeight; 111 desc.fConfig = kAlpha_half_GrPixelConfig; 112 sk_sp<GrRenderTargetContext> rtc = onFlushRP->makeRenderTargetContext(desc, nullptr, nullptr); 113 if (!rtc) { 114 SkDebugf("WARNING: failed to allocate a %ix%i atlas. Some paths will not be drawn.\n", 115 fWidth, fHeight); 116 return nullptr; 117 } 118 119 SkIRect clearRect = SkIRect::MakeSize(fDrawBounds); 120 rtc->clear(&clearRect, 0, true); 121 rtc->addDrawOp(GrNoClip(), std::move(atlasOp)); 122 123 fTextureProxy = sk_ref_sp(rtc->asTextureProxy()); 124 return rtc; 125 } 126