blob: d4a07f54a7476ee881f68374c55eba29e518065b [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"
12#include "GrTypes.h"
13#include "GrTypesPriv.h"
Chris Dalton383a2ef2018-01-08 17:21:41 -050014#include "SkRefCnt.h"
15#include "SkSize.h"
16
Chris Dalton383a2ef2018-01-08 17:21:41 -050017class GrOnFlushResourceProvider;
18class GrRenderTargetContext;
19class GrTextureProxy;
20struct SkIPoint16;
21
22/**
23 * This class implements a dynamic size GrRectanizer that grows until it reaches the implementation-
24 * dependent max texture size. When finalized, it also creates and stores a GrTextureProxy for the
25 * underlying atlas.
26 */
27class GrCCAtlas {
28public:
Chris Dalton9414c962018-06-14 10:14:50 -060029 // As long as GrSurfaceOrigin exists, we just have to decide on one for the atlas texture.
30 static constexpr GrSurfaceOrigin kTextureOrigin = kTopLeft_GrSurfaceOrigin;
Chris Dalton42c21152018-06-13 15:28:19 -060031 static constexpr int kPadding = 1; // Amount of padding below and to the right of each path.
Chris Dalton9ca27842018-01-18 12:24:50 -070032
Chris Dalton42c21152018-06-13 15:28:19 -060033 // This struct encapsulates the minimum and desired requirements for an atlas, as well as an
34 // approximate number of pixels to help select a good initial size.
35 struct Specs {
36 int fMaxPreferredTextureSize = 0;
37 int fMinTextureSize = 0;
38 int fMinWidth = 0; // If there are 100 20x10 paths, this should be 20.
39 int fMinHeight = 0; // If there are 100 20x10 paths, this should be 10.
40 int fApproxNumPixels = 0;
41
42 // Add space for a rect in the desired atlas specs.
43 void accountForSpace(int width, int height);
44 };
45
46 GrCCAtlas(const Specs&);
Chris Dalton383a2ef2018-01-08 17:21:41 -050047 ~GrCCAtlas();
48
Chris Dalton9414c962018-06-14 10:14:50 -060049 // Attempts to add a rect to the atlas. If successful, returns the integer offset from
50 // device-space pixels where the path will be drawn, to atlas pixels where its mask resides.
51 bool addRect(const SkIRect& devIBounds, SkIVector* atlasOffset);
Chris Dalton383a2ef2018-01-08 17:21:41 -050052 const SkISize& drawBounds() { return fDrawBounds; }
53
Chris Dalton9414c962018-06-14 10:14:50 -060054 // This is an optional space for the caller to jot down which user-defined batch to use when
55 // they render the content of this atlas.
56 void setUserBatchID(int id) { SkASSERT(!fTextureProxy); fUserBatchID = id; }
57 int getUserBatchID() const { return fUserBatchID; }
Chris Dalton9ca27842018-01-18 12:24:50 -070058
Chris Dalton9414c962018-06-14 10:14:50 -060059 // Creates our texture proxy for the atlas and returns a pre-cleared GrRenderTargetContext that
60 // the caller may use to render the content. After this call, it is no longer valid to call
61 // addRect() or setUserBatchID().
62 sk_sp<GrRenderTargetContext> initInternalTextureProxy(GrOnFlushResourceProvider*,
63 GrPixelConfig);
Chris Dalton383a2ef2018-01-08 17:21:41 -050064 GrTextureProxy* textureProxy() const { return fTextureProxy.get(); }
65
66private:
67 class Node;
68
69 bool internalPlaceRect(int w, int h, SkIPoint16* loc);
70
Chris Dalton42c21152018-06-13 15:28:19 -060071 const int fMaxTextureSize;
Chris Dalton2612bae2018-02-22 13:41:37 -070072 int fWidth, fHeight;
Chris Dalton383a2ef2018-01-08 17:21:41 -050073 std::unique_ptr<Node> fTopNode;
Chris Dalton2612bae2018-02-22 13:41:37 -070074 SkISize fDrawBounds = {0, 0};
Chris Dalton383a2ef2018-01-08 17:21:41 -050075
Chris Dalton9414c962018-06-14 10:14:50 -060076 int fUserBatchID;
Chris Dalton383a2ef2018-01-08 17:21:41 -050077 sk_sp<GrTextureProxy> fTextureProxy;
78};
79
Chris Dalton9414c962018-06-14 10:14:50 -060080/**
81 * This class implements an unbounded stack of atlases. When the current atlas reaches the
82 * implementation-dependent max texture size, a new one is pushed to the back and we continue on.
83 */
84class GrCCAtlasStack {
85public:
86 GrCCAtlasStack(const GrCCAtlas::Specs& specs) : fSpecs(specs) {}
87
88 bool empty() const { return fAtlases.empty(); }
89 const GrCCAtlas& front() const { SkASSERT(!this->empty()); return fAtlases.front(); }
90 GrCCAtlas& front() { SkASSERT(!this->empty()); return fAtlases.front(); }
91 GrCCAtlas& current() { SkASSERT(!this->empty()); return fAtlases.back(); }
92
93 class Iter {
94 public:
95 Iter(GrCCAtlasStack& stack) : fImpl(&stack.fAtlases) {}
96 bool next() { return fImpl.next(); }
97 GrCCAtlas* operator->() const { return fImpl.get(); }
98 private:
99 typename GrTAllocator<GrCCAtlas>::Iter fImpl;
100 };
101
102 // Adds a rect to the current atlas and returns the offset from device space to atlas space.
103 // Call current() to get the atlas it was added to.
104 //
105 // If the return value is non-null, it means the given rect did not fit in the then-current
106 // atlas, so it was retired and a new one was added to the stack. The return value is the
107 // newly-retired atlas. The caller should call setUserBatchID() on the retired atlas before
108 // moving on.
109 GrCCAtlas* addRect(const SkIRect& devIBounds, SkIVector* offset);
110
111private:
112 const GrCCAtlas::Specs fSpecs;
113 GrSTAllocator<4, GrCCAtlas> fAtlases;
114};
115
Chris Dalton42c21152018-06-13 15:28:19 -0600116inline void GrCCAtlas::Specs::accountForSpace(int width, int height) {
117 fMinWidth = SkTMax(width, fMinWidth);
118 fMinHeight = SkTMax(height, fMinHeight);
119 fApproxNumPixels += (width + kPadding) * (height + kPadding);
120}
121
Chris Dalton383a2ef2018-01-08 17:21:41 -0500122#endif