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#ifndef GrCCAtlas_DEFINED
9#define GrCCAtlas_DEFINED
10
11#include "src/gpu/GrDynamicAtlas.h"
12#include "src/gpu/GrTBlockList.h"
13#include "src/gpu/ccpr/GrCCPathProcessor.h"
14
15class GrCCCachedAtlas;
16
17/**
18 * GrDynamicAtlas with CCPR caching capabilities.
19 */
20class GrCCAtlas : public GrDynamicAtlas {
21public:
22 // This struct encapsulates the minimum and desired requirements for an atlas, as well as an
23 // approximate number of pixels to help select a good initial size.
24 struct Specs {
25 int fMaxPreferredTextureSize = 0;
26 int fMinTextureSize = 0;
27 int fMinWidth = 0; // If there are 100 20x10 paths, this should be 20.
28 int fMinHeight = 0; // If there are 100 20x10 paths, this should be 10.
29 int fApproxNumPixels = 0;
30
31 // Add space for a rect in the desired atlas specs.
32 void accountForSpace(int width, int height);
33 };
34
35 enum class CoverageType {
36 kFP16_CoverageCount,
37 kA8_Multisample,
38 kA8_LiteralCoverage
39 };
40
41 static constexpr GrColorType CoverageTypeToColorType(CoverageType coverageType) {
42 switch (coverageType) {
43 case CoverageType::kFP16_CoverageCount:
44 return GrColorType::kAlpha_F16;
45 case CoverageType::kA8_Multisample:
46 case CoverageType::kA8_LiteralCoverage:
47 return GrColorType::kAlpha_8;
48 }
49 SkUNREACHABLE;
50 }
51
52 static constexpr InternalMultisample CoverageTypeHasInternalMultisample(
53 CoverageType coverageType) {
54 switch (coverageType) {
55 case CoverageType::kFP16_CoverageCount:
56 case CoverageType::kA8_LiteralCoverage:
57 return InternalMultisample::kNo;
58 case CoverageType::kA8_Multisample:
59 return InternalMultisample::kYes;
60 }
61 SkUNREACHABLE;
62 }
63
64 static constexpr GrCCPathProcessor::CoverageMode CoverageTypeToPathCoverageMode(
65 CoverageType coverageType) {
66 return (GrCCAtlas::CoverageType::kFP16_CoverageCount == coverageType)
67 ? GrCCPathProcessor::CoverageMode::kCoverageCount
68 : GrCCPathProcessor::CoverageMode::kLiteral;
69 }
70
71 static sk_sp<GrTextureProxy> MakeLazyAtlasProxy(LazyInstantiateAtlasCallback&& callback,
72 CoverageType coverageType,
73 const GrCaps& caps,
74 GrSurfaceProxy::UseAllocator useAllocator) {
75 return GrDynamicAtlas::MakeLazyAtlasProxy(std::move(callback),
76 CoverageTypeToColorType(coverageType),
77 CoverageTypeHasInternalMultisample(coverageType),
78 caps,
79 useAllocator);
80 }
81
82 GrCCAtlas(CoverageType, const Specs&, const GrCaps&);
83 ~GrCCAtlas() override;
84
85 // This is an optional space for the caller to jot down user-defined instance data to use when
86 // rendering atlas content.
87 void setFillBatchID(int id);
88 int getFillBatchID() const { return fFillBatchID; }
89 void setStrokeBatchID(int id);
90 int getStrokeBatchID() const { return fStrokeBatchID; }
91 void setEndStencilResolveInstance(int idx);
92 int getEndStencilResolveInstance() const { return fEndStencilResolveInstance; }
93
94 sk_sp<GrCCCachedAtlas> refOrMakeCachedAtlas(GrOnFlushResourceProvider*);
95
96private:
97 const CoverageType fCoverageType;
98 int fFillBatchID;
99 int fStrokeBatchID;
100 int fEndStencilResolveInstance;
101 sk_sp<GrCCCachedAtlas> fCachedAtlas;
102};
103
104/**
105 * This class implements an unbounded stack of atlases. When the current atlas reaches the
106 * implementation-dependent max texture size, a new one is pushed to the back and we continue on.
107 */
108class GrCCAtlasStack {
109public:
110 using CoverageType = GrCCAtlas::CoverageType;
111 using CCAtlasAllocator = GrTBlockList<GrCCAtlas, 4>;
112
113 GrCCAtlasStack(CoverageType coverageType, const GrCCAtlas::Specs& specs, const GrCaps* caps)
114 : fCoverageType(coverageType), fSpecs(specs), fCaps(caps) {}
115
116 CoverageType coverageType() const { return fCoverageType; }
117 bool empty() const { return fAtlases.empty(); }
118 const GrCCAtlas& front() const { SkASSERT(!this->empty()); return fAtlases.front(); }
119 GrCCAtlas& front() { SkASSERT(!this->empty()); return fAtlases.front(); }
120 GrCCAtlas& current() { SkASSERT(!this->empty()); return fAtlases.back(); }
121
122 CCAtlasAllocator::Iter atlases() { return fAtlases.items(); }
123 CCAtlasAllocator::CIter atlases() const { return fAtlases.items(); }
124
125 // Adds a rect to the current atlas and returns the offset from device space to atlas space.
126 // Call current() to get the atlas it was added to.
127 //
128 // If the return value is non-null, it means the given rect did not fit in the then-current
129 // atlas, so it was retired and a new one was added to the stack. The return value is the
130 // newly-retired atlas. The caller should call setUserBatchID() on the retired atlas before
131 // moving on.
132 GrCCAtlas* addRect(const SkIRect& devIBounds, SkIVector* devToAtlasOffset);
133
134private:
135 const CoverageType fCoverageType;
136 const GrCCAtlas::Specs fSpecs;
137 const GrCaps* const fCaps;
138 CCAtlasAllocator fAtlases;
139};
140
141inline void GrCCAtlas::Specs::accountForSpace(int width, int height) {
142 fMinWidth = std::max(width, fMinWidth);
143 fMinHeight = std::max(height, fMinHeight);
144 fApproxNumPixels += (width + kPadding) * (height + kPadding);
145}
146
147#endif
148