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/GrTAllocator.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
72 static sk_sp<GrTextureProxy> MakeLazyAtlasProxy(const LazyInstantiateAtlasCallback& callback,
73 CoverageType coverageType, const GrCaps& caps,
74 GrSurfaceProxy::UseAllocator useAllocator) {
75 return GrDynamicAtlas::MakeLazyAtlasProxy(callback, CoverageTypeToColorType(coverageType),
76 CoverageTypeHasInternalMultisample(coverageType),
77 caps, useAllocator);
78 }
79
80 GrCCAtlas(CoverageType, const Specs&, const GrCaps&);
81 ~GrCCAtlas() override;
82
83 // This is an optional space for the caller to jot down user-defined instance data to use when
84 // rendering atlas content.
85 void setFillBatchID(int id);
86 int getFillBatchID() const { return fFillBatchID; }
87 void setStrokeBatchID(int id);
88 int getStrokeBatchID() const { return fStrokeBatchID; }
89 void setEndStencilResolveInstance(int idx);
90 int getEndStencilResolveInstance() const { return fEndStencilResolveInstance; }
91
92 sk_sp<GrCCCachedAtlas> refOrMakeCachedAtlas(GrOnFlushResourceProvider*);
93
94private:
95 const CoverageType fCoverageType;
96 int fFillBatchID;
97 int fStrokeBatchID;
98 int fEndStencilResolveInstance;
99 sk_sp<GrCCCachedAtlas> fCachedAtlas;
100};
101
102/**
103 * This class implements an unbounded stack of atlases. When the current atlas reaches the
104 * implementation-dependent max texture size, a new one is pushed to the back and we continue on.
105 */
106class GrCCAtlasStack {
107public:
108 using CoverageType = GrCCAtlas::CoverageType;
109 using CCAtlasAllocator = GrTAllocator<GrCCAtlas, 4>;
110
111 GrCCAtlasStack(CoverageType coverageType, const GrCCAtlas::Specs& specs, const GrCaps* caps)
112 : fCoverageType(coverageType), fSpecs(specs), fCaps(caps) {}
113
114 CoverageType coverageType() const { return fCoverageType; }
115 bool empty() const { return fAtlases.empty(); }
116 const GrCCAtlas& front() const { SkASSERT(!this->empty()); return fAtlases.front(); }
117 GrCCAtlas& front() { SkASSERT(!this->empty()); return fAtlases.front(); }
118 GrCCAtlas& current() { SkASSERT(!this->empty()); return fAtlases.back(); }
119
120 CCAtlasAllocator::Iter atlases() { return fAtlases.items(); }
121 CCAtlasAllocator::CIter atlases() const { return fAtlases.items(); }
122
123 // Adds a rect to the current atlas and returns the offset from device space to atlas space.
124 // Call current() to get the atlas it was added to.
125 //
126 // If the return value is non-null, it means the given rect did not fit in the then-current
127 // atlas, so it was retired and a new one was added to the stack. The return value is the
128 // newly-retired atlas. The caller should call setUserBatchID() on the retired atlas before
129 // moving on.
130 GrCCAtlas* addRect(const SkIRect& devIBounds, SkIVector* devToAtlasOffset);
131
132private:
133 const CoverageType fCoverageType;
134 const GrCCAtlas::Specs fSpecs;
135 const GrCaps* const fCaps;
136 CCAtlasAllocator fAtlases;
137};
138
139inline void GrCCAtlas::Specs::accountForSpace(int width, int height) {
140 fMinWidth = std::max(width, fMinWidth);
141 fMinHeight = std::max(height, fMinHeight);
142 fApproxNumPixels += (width + kPadding) * (height + kPadding);
143}
144
145#endif
146