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