Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
texturecache.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2#include <unordered_map>
3#include <vector>
4#include <cassert>
5#include <boost/unordered_map.hpp> // For hash of pair
6#include "helper/mathfns.h"
7#include "texturecache.h"
8
9namespace Inkscape {
10namespace UI {
11namespace Widget {
12
13namespace {
14
15class BasicTextureCache : public TextureCache
16{
17 static int constexpr min_dimension = 16;
18 static int constexpr expiration_timeout = 10000;
19
20 static int constexpr dim_to_ind(int dim) { return Util::floorlog2((dim - 1) / min_dimension) + 1; }
21 static int constexpr ind_to_maxdim(int index) { return min_dimension * (1 << index); }
22
23 static std::pair<int, int> dims_to_inds(Geom::IntPoint const &dims) { return { dim_to_ind(dims.x()), dim_to_ind(dims.y()) }; }
24 static Geom::IntPoint inds_to_maxdims(std::pair<int, int> const &inds) { return { ind_to_maxdim(inds.first), ind_to_maxdim(inds.second) }; }
25
26 // A cache of POT textures.
27 struct Bucket
28 {
29 std::vector<Texture> unused;
30 int used = 0;
32 };
33 boost::unordered_map<std::pair<int, int>, Bucket> buckets;
34
35 // Used to periodicially discard excess cached textures.
37
38public:
39 Texture request(Geom::IntPoint const &dimensions) override
40 {
41 // Find the bucket that the dimensions fall into.
42 auto indexes = dims_to_inds(dimensions);
43 auto &b = buckets[indexes];
44
45 // Reuse or create a texture of the appropriate dimensions.
46 Texture tex;
47 if (!b.unused.empty()) {
48 tex = std::move(b.unused.back());
49 b.unused.pop_back();
50 glBindTexture(GL_TEXTURE_2D, tex.id());
51 } else {
52 tex = Texture(inds_to_maxdims(indexes)); // binds
53 }
54
55 // Record the new use count of the bucket.
56 b.used++;
57 if (b.used > b.high_use_count) {
58 // If the use count has gone above the high-water mark, record this, and reset the timer for when to clean up excess unused textures.
59 b.high_use_count = b.used;
61 }
62
63 return tex;
64 }
65
66 void finish(Texture tex) override
67 {
68 auto indexes = dims_to_inds(tex.size());
69 auto &b = buckets[indexes];
70
71 // Orphan the texture, if possible.
72 tex.invalidate();
73
74 // Put the texture back in its corresponding bucket's cache of unused textures.
75 b.unused.emplace_back(std::move(tex));
76 b.used--;
77
78 // If the expiration timeout has been reached, prune the cache of textures down to what was actually used in the last cycle.
80 if (expiration_timer >= expiration_timeout) {
82
83 for (auto &[k, b] : buckets) {
84 int max_unused = b.high_use_count - b.used;
85 assert(max_unused >= 0);
86 if (b.unused.size() > max_unused) {
87 b.unused.resize(max_unused);
88 }
89 b.high_use_count = b.used;
90 }
91 }
92 }
93};
94
95} // namespace
96
97std::unique_ptr<TextureCache> TextureCache::create()
98{
99 return std::make_unique<BasicTextureCache>();
100}
101
102} // namespace Widget
103} // namespace UI
104} // namespace Inkscape
105
106/*
107 Local Variables:
108 mode:c++
109 c-file-style:"stroustrup"
110 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
111 indent-tabs-mode:nil
112 fill-column:99
113 End:
114*/
115// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
Two-dimensional point with integer coordinates.
Definition int-point.h:57
constexpr IntCoord x() const noexcept
Definition int-point.h:77
constexpr IntCoord y() const noexcept
Definition int-point.h:79
static std::unique_ptr< TextureCache > create()
int constexpr floorlog2(T x)
Returns floor(log_2(x)), assuming x >= 1.
Definition mathfns.h:62
Helper class to stream background task notifications as a series of messages.
std::vector< Bucket > buckets
int high_use_count
bool used
int index
static int constexpr expiration_timeout
static int constexpr min_dimension
std::vector< Texture > unused
int expiration_timer
Geom::IntPoint dimensions(const Cairo::RefPtr< Cairo::ImageSurface > &surface)
Definition util.cpp:353