blob: 03eed8cab6a292ed2635353cb7a00c0645fa07c4 [file] [log] [blame]
Chris Dalton383a2ef2018-01-08 17:21:41 -05001/*
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
Chris Dalton9414c962018-06-14 10:14:50 -060011#include "GrAllocator.h"
Chris Dalton4da70192018-06-18 09:51:36 -060012#include "GrNonAtomicRef.h"
13#include "GrResourceKey.h"
Chris Daltonafde18f2018-06-22 12:44:19 -060014#include "GrTexture.h"
Chris Dalton383a2ef2018-01-08 17:21:41 -050015#include "SkRefCnt.h"
16#include "SkSize.h"
17
Chris Dalton351e80c2019-01-06 22:51:00 -070018class GrCCCachedAtlas;
Chris Dalton383a2ef2018-01-08 17:21:41 -050019class GrOnFlushResourceProvider;
20class GrRenderTargetContext;
21class GrTextureProxy;
22struct SkIPoint16;
Chris Dalton4da70192018-06-18 09:51:36 -060023struct SkIRect;
Chris Dalton383a2ef2018-01-08 17:21:41 -050024
25/**
26 * This class implements a dynamic size GrRectanizer that grows until it reaches the implementation-
27 * dependent max texture size. When finalized, it also creates and stores a GrTextureProxy for the
28 * underlying atlas.
29 */
30class GrCCAtlas {
31public:
Chris Dalton9414c962018-06-14 10:14:50 -060032 // As long as GrSurfaceOrigin exists, we just have to decide on one for the atlas texture.
33 static constexpr GrSurfaceOrigin kTextureOrigin = kTopLeft_GrSurfaceOrigin;
Chris Dalton42c21152018-06-13 15:28:19 -060034 static constexpr int kPadding = 1; // Amount of padding below and to the right of each path.
Chris Dalton9ca27842018-01-18 12:24:50 -070035
Chris Dalton42c21152018-06-13 15:28:19 -060036 // This struct encapsulates the minimum and desired requirements for an atlas, as well as an
37 // approximate number of pixels to help select a good initial size.
38 struct Specs {
39 int fMaxPreferredTextureSize = 0;
40 int fMinTextureSize = 0;
41 int fMinWidth = 0; // If there are 100 20x10 paths, this should be 20.
42 int fMinHeight = 0; // If there are 100 20x10 paths, this should be 10.
43 int fApproxNumPixels = 0;
44
45 // Add space for a rect in the desired atlas specs.
46 void accountForSpace(int width, int height);
47 };
48
Chris Dalton351e80c2019-01-06 22:51:00 -070049 enum class CoverageType : bool {
50 kFP16_CoverageCount,
51 kA8_LiteralCoverage
52 };
53
54 GrCCAtlas(CoverageType, const Specs&, const GrCaps&);
Chris Dalton383a2ef2018-01-08 17:21:41 -050055 ~GrCCAtlas();
56
Chris Dalton4c458b12018-06-16 17:22:59 -060057 GrTextureProxy* textureProxy() const { return fTextureProxy.get(); }
Chris Daltonafde18f2018-06-22 12:44:19 -060058 int currentWidth() const { return fWidth; }
59 int currentHeight() const { return fHeight; }
Chris Dalton4c458b12018-06-16 17:22:59 -060060
Chris Dalton9414c962018-06-14 10:14:50 -060061 // Attempts to add a rect to the atlas. If successful, returns the integer offset from
62 // device-space pixels where the path will be drawn, to atlas pixels where its mask resides.
63 bool addRect(const SkIRect& devIBounds, SkIVector* atlasOffset);
Chris Dalton383a2ef2018-01-08 17:21:41 -050064 const SkISize& drawBounds() { return fDrawBounds; }
65
Chris Dalton09a7bb22018-08-31 19:53:15 +080066 // This is an optional space for the caller to jot down which user-defined batches to use when
Chris Dalton9414c962018-06-14 10:14:50 -060067 // they render the content of this atlas.
Chris Dalton09a7bb22018-08-31 19:53:15 +080068 void setFillBatchID(int id);
69 int getFillBatchID() const { return fFillBatchID; }
70 void setStrokeBatchID(int id);
71 int getStrokeBatchID() const { return fStrokeBatchID; }
Chris Dalton9ca27842018-01-18 12:24:50 -070072
Chris Dalton351e80c2019-01-06 22:51:00 -070073 sk_sp<GrCCCachedAtlas> refOrMakeCachedAtlas(GrOnFlushResourceProvider*);
Chris Dalton4da70192018-06-18 09:51:36 -060074
Chris Dalton4c458b12018-06-16 17:22:59 -060075 // Instantiates our texture proxy for the atlas and returns a pre-cleared GrRenderTargetContext
76 // that the caller may use to render the content. After this call, it is no longer valid to call
77 // addRect(), setUserBatchID(), or this method again.
Chris Daltonafde18f2018-06-22 12:44:19 -060078 //
79 // 'backingTexture', if provided, is a renderable texture with which to instantiate our proxy.
80 // If null then we will create a texture using the resource provider. The purpose of this param
81 // is to provide a guaranteed way to recycle a stashed atlas texture from a previous flush.
82 sk_sp<GrRenderTargetContext> makeRenderTargetContext(GrOnFlushResourceProvider*,
83 sk_sp<GrTexture> backingTexture = nullptr);
Chris Dalton383a2ef2018-01-08 17:21:41 -050084
85private:
86 class Node;
87
88 bool internalPlaceRect(int w, int h, SkIPoint16* loc);
89
Chris Dalton351e80c2019-01-06 22:51:00 -070090 const CoverageType fCoverageType;
Chris Dalton42c21152018-06-13 15:28:19 -060091 const int fMaxTextureSize;
Chris Dalton2612bae2018-02-22 13:41:37 -070092 int fWidth, fHeight;
Chris Dalton383a2ef2018-01-08 17:21:41 -050093 std::unique_ptr<Node> fTopNode;
Chris Dalton2612bae2018-02-22 13:41:37 -070094 SkISize fDrawBounds = {0, 0};
Chris Dalton383a2ef2018-01-08 17:21:41 -050095
Chris Dalton09a7bb22018-08-31 19:53:15 +080096 int fFillBatchID;
97 int fStrokeBatchID;
Chris Dalton4da70192018-06-18 09:51:36 -060098
Chris Dalton351e80c2019-01-06 22:51:00 -070099 sk_sp<GrCCCachedAtlas> fCachedAtlas;
Chris Dalton383a2ef2018-01-08 17:21:41 -0500100 sk_sp<GrTextureProxy> fTextureProxy;
Chris Daltonafde18f2018-06-22 12:44:19 -0600101 sk_sp<GrTexture> fBackingTexture;
Chris Dalton383a2ef2018-01-08 17:21:41 -0500102};
103
Chris Dalton9414c962018-06-14 10:14:50 -0600104/**
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:
Chris Dalton351e80c2019-01-06 22:51:00 -0700110 using CoverageType = GrCCAtlas::CoverageType;
111
112 GrCCAtlasStack(CoverageType coverageType, const GrCCAtlas::Specs& specs, const GrCaps* caps)
113 : fCoverageType(coverageType), fSpecs(specs), fCaps(caps) {}
Chris Dalton9414c962018-06-14 10:14:50 -0600114
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 class Iter {
121 public:
122 Iter(GrCCAtlasStack& stack) : fImpl(&stack.fAtlases) {}
123 bool next() { return fImpl.next(); }
124 GrCCAtlas* operator->() const { return fImpl.get(); }
125 private:
126 typename GrTAllocator<GrCCAtlas>::Iter fImpl;
127 };
128
129 // Adds a rect to the current atlas and returns the offset from device space to atlas space.
130 // Call current() to get the atlas it was added to.
131 //
132 // If the return value is non-null, it means the given rect did not fit in the then-current
133 // atlas, so it was retired and a new one was added to the stack. The return value is the
134 // newly-retired atlas. The caller should call setUserBatchID() on the retired atlas before
135 // moving on.
Chris Dalton4c458b12018-06-16 17:22:59 -0600136 GrCCAtlas* addRect(const SkIRect& devIBounds, SkIVector* devToAtlasOffset);
Chris Dalton9414c962018-06-14 10:14:50 -0600137
138private:
Chris Dalton351e80c2019-01-06 22:51:00 -0700139 const CoverageType fCoverageType;
Chris Dalton9414c962018-06-14 10:14:50 -0600140 const GrCCAtlas::Specs fSpecs;
Chris Dalton4c458b12018-06-16 17:22:59 -0600141 const GrCaps* const fCaps;
Chris Dalton9414c962018-06-14 10:14:50 -0600142 GrSTAllocator<4, GrCCAtlas> fAtlases;
143};
144
Chris Dalton42c21152018-06-13 15:28:19 -0600145inline void GrCCAtlas::Specs::accountForSpace(int width, int height) {
146 fMinWidth = SkTMax(width, fMinWidth);
147 fMinHeight = SkTMax(height, fMinHeight);
148 fApproxNumPixels += (width + kPadding) * (height + kPadding);
149}
150
Chris Dalton383a2ef2018-01-08 17:21:41 -0500151#endif