1 | /* gskgltexturelibraryprivate.h |
2 | * |
3 | * Copyright 2020 Christian Hergert <chergert@redhat.com> |
4 | * |
5 | * This file is free software; you can redistribute it and/or modify it under |
6 | * the terms of the GNU Lesser General Public License as published by the Free |
7 | * Software Foundation; either version 2.1 of the License, or (at your option) |
8 | * any later version. |
9 | * |
10 | * This file is distributed in the hope that it will be useful, but WITHOUT |
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
13 | * License for more details. |
14 | * |
15 | * You should have received a copy of the GNU General Public License along |
16 | * with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | * |
18 | * SPDX-License-Identifier: LGPL-2.1-or-later |
19 | */ |
20 | |
21 | #ifndef __GSK_GL_TEXTURE_LIBRARY_PRIVATE_H__ |
22 | #define __GSK_GL_TEXTURE_LIBRARY_PRIVATE_H__ |
23 | |
24 | #include "gskgltypesprivate.h" |
25 | #include "gskgltextureprivate.h" |
26 | |
27 | #include "stb_rect_pack.h" |
28 | |
29 | G_BEGIN_DECLS |
30 | |
31 | #define GSK_TYPE_GL_TEXTURE_LIBRARY (gsk_gl_texture_library_get_type ()) |
32 | #define GSK_GL_TEXTURE_LIBRARY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_GL_TEXTURE_LIBRARY, GskGLTextureLibrary)) |
33 | #define GSK_IS_GL_TEXTURE_LIBRARY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_GL_TEXTURE_LIBRARY)) |
34 | #define GSK_GL_TEXTURE_LIBRARY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_GL_TEXTURE_LIBRARY, GskGLTextureLibraryClass)) |
35 | #define GSK_IS_GL_TEXTURE_LIBRARY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_GL_TEXTURE_LIBRARY)) |
36 | #define GSK_GL_TEXTURE_LIBRARY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_GL_TEXTURE_LIBRARY, GskGLTextureLibraryClass)) |
37 | |
38 | typedef struct _GskGLTextureAtlas |
39 | { |
40 | struct stbrp_context context; |
41 | struct stbrp_node *nodes; |
42 | |
43 | int width; |
44 | int height; |
45 | |
46 | guint texture_id; |
47 | |
48 | /* Pixels of rects that have been used at some point, |
49 | * But are now unused. |
50 | */ |
51 | int unused_pixels; |
52 | |
53 | void *user_data; |
54 | } GskGLTextureAtlas; |
55 | |
56 | typedef struct _GskGLTextureAtlasEntry |
57 | { |
58 | /* A backreference to either the atlas or texture containing |
59 | * the contents of the atlas entry. For larger items, no atlas |
60 | * is used and instead a direct texture. |
61 | */ |
62 | union { |
63 | GskGLTextureAtlas *atlas; |
64 | GskGLTexture *texture; |
65 | }; |
66 | |
67 | /* The area within the atlas translated to 0..1 bounds */ |
68 | struct { |
69 | float x; |
70 | float y; |
71 | float x2; |
72 | float y2; |
73 | } area; |
74 | |
75 | /* Number of pixels in the entry, used to calculate usage |
76 | * of an atlas while processing. |
77 | */ |
78 | guint n_pixels : 29; |
79 | |
80 | /* If entry has marked pixels as used in the atlas this frame */ |
81 | guint used : 1; |
82 | |
83 | /* If entry was accessed this frame */ |
84 | guint accessed : 1; |
85 | |
86 | /* When true, backref is an atlas, otherwise texture */ |
87 | guint is_atlased : 1; |
88 | } GskGLTextureAtlasEntry; |
89 | |
90 | typedef struct _GskGLTextureLibrary |
91 | { |
92 | GObject parent_instance; |
93 | GskGLDriver *driver; |
94 | GHashTable *hash_table; |
95 | guint max_entry_size; |
96 | } GskGLTextureLibrary; |
97 | |
98 | typedef struct _GskGLTextureLibraryClass |
99 | { |
100 | GObjectClass parent_class; |
101 | |
102 | void (*begin_frame) (GskGLTextureLibrary *library, |
103 | gint64 frame_id, |
104 | GPtrArray *removed_atlases); |
105 | } GskGLTextureLibraryClass; |
106 | |
107 | G_DEFINE_AUTOPTR_CLEANUP_FUNC (GskGLTextureLibrary, g_object_unref) |
108 | |
109 | GType gsk_gl_texture_library_get_type (void) G_GNUC_CONST; |
110 | void gsk_gl_texture_library_set_funcs (GskGLTextureLibrary *self, |
111 | GHashFunc hash_func, |
112 | GEqualFunc equal_func, |
113 | GDestroyNotify key_destroy, |
114 | GDestroyNotify value_destroy); |
115 | void gsk_gl_texture_library_begin_frame (GskGLTextureLibrary *self, |
116 | gint64 frame_id, |
117 | GPtrArray *removed_atlases); |
118 | gpointer gsk_gl_texture_library_pack (GskGLTextureLibrary *self, |
119 | gpointer key, |
120 | gsize valuelen, |
121 | guint width, |
122 | guint height, |
123 | int padding, |
124 | guint *out_packed_x, |
125 | guint *out_packed_y); |
126 | |
127 | static inline void |
128 | gsk_gl_texture_atlas_mark_unused (GskGLTextureAtlas *self, |
129 | int n_pixels) |
130 | { |
131 | g_assert (n_pixels >= 0); |
132 | |
133 | self->unused_pixels += n_pixels; |
134 | } |
135 | |
136 | static inline void |
137 | gsk_gl_texture_atlas_entry_mark_used (GskGLTextureAtlasEntry *entry) |
138 | { |
139 | if (entry->used == TRUE || entry->is_atlased == FALSE) |
140 | return; |
141 | |
142 | entry->atlas->unused_pixels -= entry->n_pixels; |
143 | entry->used = TRUE; |
144 | } |
145 | |
146 | static inline void |
147 | gsk_gl_texture_atlas_entry_mark_unused (GskGLTextureAtlasEntry *entry) |
148 | { |
149 | if (entry->used == FALSE || entry->is_atlased == FALSE) |
150 | return; |
151 | |
152 | entry->atlas->unused_pixels += entry->n_pixels; |
153 | entry->used = FALSE; |
154 | } |
155 | |
156 | static inline gboolean |
157 | gsk_gl_texture_library_lookup (GskGLTextureLibrary *self, |
158 | gconstpointer key, |
159 | GskGLTextureAtlasEntry **out_entry) |
160 | { |
161 | GskGLTextureAtlasEntry *entry = g_hash_table_lookup (hash_table: self->hash_table, key); |
162 | |
163 | if G_LIKELY (entry != NULL && entry->accessed && entry->used) |
164 | { |
165 | *out_entry = entry; |
166 | return TRUE; |
167 | } |
168 | |
169 | if (entry != NULL) |
170 | { |
171 | gsk_gl_texture_atlas_entry_mark_used (entry); |
172 | entry->accessed = TRUE; |
173 | *out_entry = entry; |
174 | return TRUE; |
175 | } |
176 | |
177 | return FALSE; |
178 | } |
179 | |
180 | static inline guint |
181 | GSK_GL_TEXTURE_ATLAS_ENTRY_TEXTURE (gconstpointer d) |
182 | { |
183 | const GskGLTextureAtlasEntry *e = d; |
184 | |
185 | return e->is_atlased ? e->atlas->texture_id |
186 | : e->texture ? e->texture->texture_id : 0; |
187 | } |
188 | |
189 | static inline double |
190 | gsk_gl_texture_atlas_get_unused_ratio (const GskGLTextureAtlas *self) |
191 | { |
192 | if (self->unused_pixels > 0) |
193 | return (double)(self->unused_pixels) / (double)(self->width * self->height); |
194 | return 0.0; |
195 | } |
196 | |
197 | static inline gboolean |
198 | gsk_gl_texture_library_can_cache (GskGLTextureLibrary *self, |
199 | int width, |
200 | int height) |
201 | { |
202 | g_assert (self->max_entry_size > 0); |
203 | return width <= self->max_entry_size && height <= self->max_entry_size; |
204 | } |
205 | |
206 | G_END_DECLS |
207 | |
208 | #endif /* __GSK_GL_TEXTURE_LIBRARY_PRIVATE_H__ */ |
209 | |