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 "src/gpu/ccpr/GrCCAtlas.h"
9
10#include "src/gpu/GrOnFlushResourceProvider.h"
11#include "src/gpu/ccpr/GrCCPathCache.h"
12
13static SkISize choose_initial_atlas_size(const GrCCAtlas::Specs& specs) {
14 // Begin with the first pow2 dimensions whose area is theoretically large enough to contain the
15 // pending paths, favoring height over width if necessary.
16 int log2area = SkNextLog2(std::max(specs.fApproxNumPixels, 1));
17 int height = 1 << ((log2area + 1) / 2);
18 int width = 1 << (log2area / 2);
19
20 width = SkTPin(width, specs.fMinTextureSize, specs.fMaxPreferredTextureSize);
21 height = SkTPin(height, specs.fMinTextureSize, specs.fMaxPreferredTextureSize);
22
23 return SkISize::Make(width, height);
24}
25
26static int choose_max_atlas_size(const GrCCAtlas::Specs& specs, const GrCaps& caps) {
27 return (std::max(specs.fMinHeight, specs.fMinWidth) <= specs.fMaxPreferredTextureSize) ?
28 specs.fMaxPreferredTextureSize : caps.maxRenderTargetSize();
29}
30
31GrCCAtlas::GrCCAtlas(CoverageType coverageType, const Specs& specs, const GrCaps& caps)
32 : GrDynamicAtlas(CoverageTypeToColorType(coverageType),
33 CoverageTypeHasInternalMultisample(coverageType),
34 choose_initial_atlas_size(specs), choose_max_atlas_size(specs, caps), caps)
35 , fCoverageType(coverageType) {
36 SkASSERT(specs.fMaxPreferredTextureSize > 0);
37}
38
39GrCCAtlas::~GrCCAtlas() {
40}
41
42void GrCCAtlas::setFillBatchID(int id) {
43 // This can't be called anymore once makeRenderTargetContext() has been called.
44 SkASSERT(!this->isInstantiated());
45 fFillBatchID = id;
46}
47
48void GrCCAtlas::setStrokeBatchID(int id) {
49 // This can't be called anymore once makeRenderTargetContext() has been called.
50 SkASSERT(!this->isInstantiated());
51 fStrokeBatchID = id;
52}
53
54void GrCCAtlas::setEndStencilResolveInstance(int idx) {
55 // This can't be called anymore once makeRenderTargetContext() has been called.
56 SkASSERT(!this->isInstantiated());
57 fEndStencilResolveInstance = idx;
58}
59
60static uint32_t next_atlas_unique_id() {
61 static std::atomic<uint32_t> nextID;
62 return nextID++;
63}
64
65sk_sp<GrCCCachedAtlas> GrCCAtlas::refOrMakeCachedAtlas(GrOnFlushResourceProvider* onFlushRP) {
66 if (!fCachedAtlas) {
67 static const GrUniqueKey::Domain kAtlasDomain = GrUniqueKey::GenerateDomain();
68
69 GrUniqueKey atlasUniqueKey;
70 GrUniqueKey::Builder builder(&atlasUniqueKey, kAtlasDomain, 1, "CCPR Atlas");
71 builder[0] = next_atlas_unique_id();
72 builder.finish();
73
74 onFlushRP->assignUniqueKeyToProxy(atlasUniqueKey, this->textureProxy());
75
76 fCachedAtlas = sk_make_sp<GrCCCachedAtlas>(fCoverageType, atlasUniqueKey,
77 sk_ref_sp(this->textureProxy()));
78 }
79
80 SkASSERT(fCachedAtlas->coverageType() == fCoverageType);
81 SkASSERT(fCachedAtlas->getOnFlushProxy() == this->textureProxy());
82 return fCachedAtlas;
83}
84
85GrCCAtlas* GrCCAtlasStack::addRect(const SkIRect& devIBounds, SkIVector* devToAtlasOffset) {
86 GrCCAtlas* retiredAtlas = nullptr;
87 if (fAtlases.empty() || !fAtlases.back().addRect(devIBounds, devToAtlasOffset)) {
88 // The retired atlas is out of room and can't grow any bigger.
89 retiredAtlas = !fAtlases.empty() ? &fAtlases.back() : nullptr;
90 fAtlases.emplace_back(fCoverageType, fSpecs, *fCaps);
91 SkASSERT(devIBounds.width() <= fSpecs.fMinWidth);
92 SkASSERT(devIBounds.height() <= fSpecs.fMinHeight);
93 SkAssertResult(fAtlases.back().addRect(devIBounds, devToAtlasOffset));
94 }
95 return retiredAtlas;
96}
97