GrCCAtlas.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  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. #include "src/gpu/ccpr/GrCCAtlas.h"
  8. #include "include/gpu/GrRenderTarget.h"
  9. #include "include/gpu/GrTexture.h"
  10. #include "src/core/SkIPoint16.h"
  11. #include "src/core/SkMakeUnique.h"
  12. #include "src/core/SkMathPriv.h"
  13. #include "src/gpu/GrCaps.h"
  14. #include "src/gpu/GrOnFlushResourceProvider.h"
  15. #include "src/gpu/GrProxyProvider.h"
  16. #include "src/gpu/GrRectanizer_skyline.h"
  17. #include "src/gpu/GrRenderTargetContext.h"
  18. #include "src/gpu/GrTextureProxy.h"
  19. #include "src/gpu/ccpr/GrCCPathCache.h"
  20. #include <atomic>
  21. class GrCCAtlas::Node {
  22. public:
  23. Node(std::unique_ptr<Node> previous, int l, int t, int r, int b)
  24. : fPrevious(std::move(previous)), fX(l), fY(t), fRectanizer(r - l, b - t) {}
  25. Node* previous() const { return fPrevious.get(); }
  26. bool addRect(int w, int h, SkIPoint16* loc, int maxAtlasSize) {
  27. // Pad all paths except those that are expected to take up an entire physical texture.
  28. if (w < maxAtlasSize) {
  29. w = SkTMin(w + kPadding, maxAtlasSize);
  30. }
  31. if (h < maxAtlasSize) {
  32. h = SkTMin(h + kPadding, maxAtlasSize);
  33. }
  34. if (!fRectanizer.addRect(w, h, loc)) {
  35. return false;
  36. }
  37. loc->fX += fX;
  38. loc->fY += fY;
  39. return true;
  40. }
  41. private:
  42. const std::unique_ptr<Node> fPrevious;
  43. const int fX, fY;
  44. GrRectanizerSkyline fRectanizer;
  45. };
  46. sk_sp<GrTextureProxy> GrCCAtlas::MakeLazyAtlasProxy(
  47. const LazyInstantiateAtlasCallback& callback, CoverageType coverageType, const GrCaps& caps) {
  48. GrColorType colorType;
  49. GrPixelConfig pixelConfig;
  50. int sampleCount;
  51. switch (coverageType) {
  52. case CoverageType::kFP16_CoverageCount:
  53. colorType = GrColorType::kAlpha_F16;
  54. pixelConfig = kAlpha_half_GrPixelConfig;
  55. sampleCount = 1;
  56. break;
  57. case CoverageType::kA8_Multisample:
  58. SkASSERT(caps.internalMultisampleCount(kAlpha_8_GrPixelConfig) > 1);
  59. colorType = GrColorType::kAlpha_8;
  60. pixelConfig = kAlpha_8_GrPixelConfig;
  61. sampleCount = (caps.mixedSamplesSupport())
  62. ? 1 : caps.internalMultisampleCount(pixelConfig);
  63. break;
  64. case CoverageType::kA8_LiteralCoverage:
  65. colorType = GrColorType::kAlpha_8;
  66. pixelConfig = kAlpha_8_GrPixelConfig;
  67. sampleCount = 1;
  68. break;
  69. }
  70. const GrBackendFormat format = caps.getBackendFormatFromColorType(colorType);
  71. sk_sp<GrTextureProxy> proxy = GrProxyProvider::MakeFullyLazyProxy(
  72. std::bind(callback, std::placeholders::_1, pixelConfig, sampleCount), format,
  73. GrRenderable::kYes, sampleCount, GrProtected::kNo, kTextureOrigin, pixelConfig, caps);
  74. return proxy;
  75. }
  76. GrCCAtlas::GrCCAtlas(CoverageType coverageType, const Specs& specs, const GrCaps& caps)
  77. : fCoverageType(coverageType)
  78. , fMaxTextureSize(SkTMax(SkTMax(specs.fMinHeight, specs.fMinWidth),
  79. specs.fMaxPreferredTextureSize)) {
  80. // Caller should have cropped any paths to the destination render target instead of asking for
  81. // an atlas larger than maxRenderTargetSize.
  82. SkASSERT(fMaxTextureSize <= caps.maxTextureSize());
  83. SkASSERT(specs.fMaxPreferredTextureSize > 0);
  84. // Begin with the first pow2 dimensions whose area is theoretically large enough to contain the
  85. // pending paths, favoring height over width if necessary.
  86. int log2area = SkNextLog2(SkTMax(specs.fApproxNumPixels, 1));
  87. fHeight = 1 << ((log2area + 1) / 2);
  88. fWidth = 1 << (log2area / 2);
  89. fWidth = SkTClamp(fWidth, specs.fMinTextureSize, specs.fMaxPreferredTextureSize);
  90. fHeight = SkTClamp(fHeight, specs.fMinTextureSize, specs.fMaxPreferredTextureSize);
  91. if (fWidth < specs.fMinWidth || fHeight < specs.fMinHeight) {
  92. // They want to stuff a particularly large path into the atlas. Just punt and go with their
  93. // min width and height. The atlas will grow as needed.
  94. fWidth = SkTMin(specs.fMinWidth + kPadding, fMaxTextureSize);
  95. fHeight = SkTMin(specs.fMinHeight + kPadding, fMaxTextureSize);
  96. }
  97. fTopNode = skstd::make_unique<Node>(nullptr, 0, 0, fWidth, fHeight);
  98. fTextureProxy = MakeLazyAtlasProxy([this](
  99. GrResourceProvider* resourceProvider, GrPixelConfig pixelConfig, int sampleCount) {
  100. if (!fBackingTexture) {
  101. GrSurfaceDesc desc;
  102. desc.fWidth = fWidth;
  103. desc.fHeight = fHeight;
  104. desc.fConfig = pixelConfig;
  105. fBackingTexture = resourceProvider->createTexture(
  106. desc, GrRenderable::kYes, sampleCount, SkBudgeted::kYes, GrProtected::kNo,
  107. GrResourceProvider::Flags::kNoPendingIO);
  108. }
  109. return fBackingTexture;
  110. }, fCoverageType, caps);
  111. fTextureProxy->priv().setIgnoredByResourceAllocator();
  112. }
  113. GrCCAtlas::~GrCCAtlas() {
  114. }
  115. bool GrCCAtlas::addRect(const SkIRect& devIBounds, SkIVector* offset) {
  116. // This can't be called anymore once makeRenderTargetContext() has been called.
  117. SkASSERT(!fTextureProxy->isInstantiated());
  118. SkIPoint16 location;
  119. if (!this->internalPlaceRect(devIBounds.width(), devIBounds.height(), &location)) {
  120. return false;
  121. }
  122. offset->set(location.x() - devIBounds.left(), location.y() - devIBounds.top());
  123. fDrawBounds.fWidth = SkTMax(fDrawBounds.width(), location.x() + devIBounds.width());
  124. fDrawBounds.fHeight = SkTMax(fDrawBounds.height(), location.y() + devIBounds.height());
  125. return true;
  126. }
  127. bool GrCCAtlas::internalPlaceRect(int w, int h, SkIPoint16* loc) {
  128. for (Node* node = fTopNode.get(); node; node = node->previous()) {
  129. if (node->addRect(w, h, loc, fMaxTextureSize)) {
  130. return true;
  131. }
  132. }
  133. // The rect didn't fit. Grow the atlas and try again.
  134. do {
  135. if (fWidth == fMaxTextureSize && fHeight == fMaxTextureSize) {
  136. return false;
  137. }
  138. if (fHeight <= fWidth) {
  139. int top = fHeight;
  140. fHeight = SkTMin(fHeight * 2, fMaxTextureSize);
  141. fTopNode = skstd::make_unique<Node>(std::move(fTopNode), 0, top, fWidth, fHeight);
  142. } else {
  143. int left = fWidth;
  144. fWidth = SkTMin(fWidth * 2, fMaxTextureSize);
  145. fTopNode = skstd::make_unique<Node>(std::move(fTopNode), left, 0, fWidth, fHeight);
  146. }
  147. } while (!fTopNode->addRect(w, h, loc, fMaxTextureSize));
  148. return true;
  149. }
  150. void GrCCAtlas::setFillBatchID(int id) {
  151. // This can't be called anymore once makeRenderTargetContext() has been called.
  152. SkASSERT(!fTextureProxy->isInstantiated());
  153. fFillBatchID = id;
  154. }
  155. void GrCCAtlas::setStrokeBatchID(int id) {
  156. // This can't be called anymore once makeRenderTargetContext() has been called.
  157. SkASSERT(!fTextureProxy->isInstantiated());
  158. fStrokeBatchID = id;
  159. }
  160. void GrCCAtlas::setEndStencilResolveInstance(int idx) {
  161. // This can't be called anymore once makeRenderTargetContext() has been called.
  162. SkASSERT(!fTextureProxy->isInstantiated());
  163. fEndStencilResolveInstance = idx;
  164. }
  165. static uint32_t next_atlas_unique_id() {
  166. static std::atomic<uint32_t> nextID;
  167. return nextID++;
  168. }
  169. sk_sp<GrCCCachedAtlas> GrCCAtlas::refOrMakeCachedAtlas(GrOnFlushResourceProvider* onFlushRP) {
  170. if (!fCachedAtlas) {
  171. static const GrUniqueKey::Domain kAtlasDomain = GrUniqueKey::GenerateDomain();
  172. GrUniqueKey atlasUniqueKey;
  173. GrUniqueKey::Builder builder(&atlasUniqueKey, kAtlasDomain, 1, "CCPR Atlas");
  174. builder[0] = next_atlas_unique_id();
  175. builder.finish();
  176. onFlushRP->assignUniqueKeyToProxy(atlasUniqueKey, fTextureProxy.get());
  177. fCachedAtlas = sk_make_sp<GrCCCachedAtlas>(fCoverageType, atlasUniqueKey, fTextureProxy);
  178. }
  179. SkASSERT(fCachedAtlas->coverageType() == fCoverageType);
  180. SkASSERT(fCachedAtlas->getOnFlushProxy() == fTextureProxy.get());
  181. return fCachedAtlas;
  182. }
  183. sk_sp<GrRenderTargetContext> GrCCAtlas::makeRenderTargetContext(
  184. GrOnFlushResourceProvider* onFlushRP, sk_sp<GrTexture> backingTexture) {
  185. SkASSERT(!fTextureProxy->isInstantiated()); // This method should only be called once.
  186. // Caller should have cropped any paths to the destination render target instead of asking for
  187. // an atlas larger than maxRenderTargetSize.
  188. SkASSERT(SkTMax(fHeight, fWidth) <= fMaxTextureSize);
  189. SkASSERT(fMaxTextureSize <= onFlushRP->caps()->maxRenderTargetSize());
  190. // Finalize the content size of our proxy. The GPU can potentially make optimizations if it
  191. // knows we only intend to write out a smaller sub-rectangle of the backing texture.
  192. fTextureProxy->priv().setLazySize(fDrawBounds.width(), fDrawBounds.height());
  193. if (backingTexture) {
  194. #ifdef SK_DEBUG
  195. auto backingRT = backingTexture->asRenderTarget();
  196. SkASSERT(backingRT);
  197. SkASSERT(backingRT->config() == fTextureProxy->config());
  198. SkASSERT(backingRT->numSamples() == fTextureProxy->asRenderTargetProxy()->numSamples());
  199. SkASSERT(backingRT->width() == fWidth);
  200. SkASSERT(backingRT->height() == fHeight);
  201. #endif
  202. fBackingTexture = std::move(backingTexture);
  203. }
  204. auto colorType = (CoverageType::kFP16_CoverageCount == fCoverageType)
  205. ? GrColorType::kAlpha_F16 : GrColorType::kAlpha_8;
  206. sk_sp<GrRenderTargetContext> rtc =
  207. onFlushRP->makeRenderTargetContext(fTextureProxy, colorType, nullptr, nullptr);
  208. if (!rtc) {
  209. SkDebugf("WARNING: failed to allocate a %ix%i atlas. Some paths will not be drawn.\n",
  210. fWidth, fHeight);
  211. return nullptr;
  212. }
  213. SkIRect clearRect = SkIRect::MakeSize(fDrawBounds);
  214. rtc->clear(&clearRect, SK_PMColor4fTRANSPARENT,
  215. GrRenderTargetContext::CanClearFullscreen::kYes);
  216. return rtc;
  217. }
  218. GrCCAtlas* GrCCAtlasStack::addRect(const SkIRect& devIBounds, SkIVector* devToAtlasOffset) {
  219. GrCCAtlas* retiredAtlas = nullptr;
  220. if (fAtlases.empty() || !fAtlases.back().addRect(devIBounds, devToAtlasOffset)) {
  221. // The retired atlas is out of room and can't grow any bigger.
  222. retiredAtlas = !fAtlases.empty() ? &fAtlases.back() : nullptr;
  223. fAtlases.emplace_back(fCoverageType, fSpecs, *fCaps);
  224. SkASSERT(devIBounds.width() <= fSpecs.fMinWidth);
  225. SkASSERT(devIBounds.height() <= fSpecs.fMinHeight);
  226. SkAssertResult(fAtlases.back().addRect(devIBounds, devToAtlasOffset));
  227. }
  228. return retiredAtlas;
  229. }