1/* gskgliconlibrary.c
2 *
3 * Copyright 2020 Christian Hergert <chergert@redhat.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * SPDX-License-Identifier: LGPL-2.1-or-later
19 */
20
21#include "config.h"
22
23#include <gdk/gdkglcontextprivate.h>
24#include <gdk/gdkmemoryformatprivate.h>
25#include <gdk/gdkprofilerprivate.h>
26#include <gdk/gdktextureprivate.h>
27
28#include "gskglcommandqueueprivate.h"
29#include "gskgldriverprivate.h"
30#include "gskgliconlibraryprivate.h"
31
32struct _GskGLIconLibrary
33{
34 GskGLTextureLibrary parent_instance;
35};
36
37G_DEFINE_TYPE (GskGLIconLibrary, gsk_gl_icon_library, GSK_TYPE_GL_TEXTURE_LIBRARY)
38
39GskGLIconLibrary *
40gsk_gl_icon_library_new (GskGLDriver *driver)
41{
42 g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), NULL);
43
44 return g_object_new (GSK_TYPE_GL_ICON_LIBRARY,
45 first_property_name: "driver", driver,
46 NULL);
47}
48
49static void
50gsk_gl_icon_data_free (gpointer data)
51{
52 GskGLIconData *icon_data = data;
53
54 g_clear_object (&icon_data->source_texture);
55 g_slice_free (GskGLIconData, icon_data);
56}
57
58static void
59gsk_gl_icon_library_class_init (GskGLIconLibraryClass *klass)
60{
61}
62
63static void
64gsk_gl_icon_library_init (GskGLIconLibrary *self)
65{
66 GskGLTextureLibrary *tl = (GskGLTextureLibrary *)self;
67
68 tl->max_entry_size = 128;
69 gsk_gl_texture_library_set_funcs (self: tl,
70 NULL, NULL, NULL,
71 value_destroy: gsk_gl_icon_data_free);
72}
73
74void
75gsk_gl_icon_library_add (GskGLIconLibrary *self,
76 GdkTexture *key,
77 const GskGLIconData **out_value)
78{
79 GskGLTextureLibrary *tl = (GskGLTextureLibrary *)self;
80 G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME;
81 cairo_surface_t *surface;
82 GskGLIconData *icon_data;
83 guint8 *pixel_data;
84 guint8 *surface_data;
85 guint8 *free_data = NULL;
86 guint gl_format;
87 guint gl_type;
88 guint packed_x;
89 guint packed_y;
90 int width;
91 int height;
92 guint texture_id;
93
94 g_assert (GSK_IS_GL_ICON_LIBRARY (self));
95 g_assert (GDK_IS_TEXTURE (key));
96 g_assert (out_value != NULL);
97
98 width = key->width;
99 height = key->height;
100
101 icon_data = gsk_gl_texture_library_pack (self: tl,
102 key,
103 valuelen: sizeof (GskGLIconData),
104 width, height, padding: 1,
105 out_packed_x: &packed_x, out_packed_y: &packed_y);
106 icon_data->source_texture = g_object_ref (key);
107
108 /* actually upload the texture */
109 surface = gdk_texture_download_surface (texture: key);
110 surface_data = cairo_image_surface_get_data (surface);
111 gdk_gl_context_push_debug_group_printf (context: gdk_gl_context_get_current (),
112 format: "Uploading texture");
113
114 if (gdk_gl_context_get_use_es (context: gdk_gl_context_get_current ()))
115 {
116 pixel_data = free_data = g_malloc (n_bytes: width * height * 4);
117 gdk_memory_convert (dest_data: pixel_data, dest_stride: width * 4,
118 dest_format: GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
119 src_data: surface_data, src_stride: cairo_image_surface_get_stride (surface),
120 GDK_MEMORY_DEFAULT, width, height);
121 gl_format = GL_RGBA;
122 gl_type = GL_UNSIGNED_BYTE;
123 }
124 else
125 {
126 pixel_data = surface_data;
127 gl_format = GL_BGRA;
128 gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
129 }
130
131 texture_id = GSK_GL_TEXTURE_ATLAS_ENTRY_TEXTURE (d: icon_data);
132
133 glBindTexture (GL_TEXTURE_2D, texture_id);
134
135 glTexSubImage2D (GL_TEXTURE_2D, 0,
136 packed_x + 1, packed_y + 1,
137 width, height,
138 gl_format, gl_type,
139 pixel_data);
140 /* Padding top */
141 glTexSubImage2D (GL_TEXTURE_2D, 0,
142 packed_x + 1, packed_y,
143 width, 1,
144 gl_format, gl_type,
145 pixel_data);
146 /* Padding left */
147 glTexSubImage2D (GL_TEXTURE_2D, 0,
148 packed_x, packed_y + 1,
149 1, height,
150 gl_format, gl_type,
151 pixel_data);
152 /* Padding top left */
153 glTexSubImage2D (GL_TEXTURE_2D, 0,
154 packed_x, packed_y,
155 1, 1,
156 gl_format, gl_type,
157 pixel_data);
158
159 /* Padding right */
160 glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
161 glPixelStorei (GL_UNPACK_SKIP_PIXELS, width - 1);
162 glTexSubImage2D (GL_TEXTURE_2D, 0,
163 packed_x + width + 1, packed_y + 1,
164 1, height,
165 gl_format, gl_type,
166 pixel_data);
167 /* Padding top right */
168 glTexSubImage2D (GL_TEXTURE_2D, 0,
169 packed_x + width + 1, packed_y,
170 1, 1,
171 gl_format, gl_type,
172 pixel_data);
173 /* Padding bottom */
174 glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
175 glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
176 glPixelStorei (GL_UNPACK_SKIP_ROWS, height - 1);
177 glTexSubImage2D (GL_TEXTURE_2D, 0,
178 packed_x + 1, packed_y + 1 + height,
179 width, 1,
180 gl_format, gl_type,
181 pixel_data);
182 /* Padding bottom left */
183 glTexSubImage2D (GL_TEXTURE_2D, 0,
184 packed_x, packed_y + 1 + height,
185 1, 1,
186 gl_format, gl_type,
187 pixel_data);
188 /* Padding bottom right */
189 glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
190 glPixelStorei (GL_UNPACK_SKIP_PIXELS, width - 1);
191 glTexSubImage2D (GL_TEXTURE_2D, 0,
192 packed_x + 1 + width, packed_y + 1 + height,
193 1, 1,
194 gl_format, gl_type,
195 pixel_data);
196 /* Reset this */
197 glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
198 glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
199 glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
200
201 gdk_gl_context_pop_debug_group (context: gdk_gl_context_get_current ());
202
203 *out_value = icon_data;
204
205 cairo_surface_destroy (surface);
206 g_free (mem: free_data);
207
208 tl->driver->command_queue->n_uploads++;
209
210 if (gdk_profiler_is_running ())
211 {
212 char message[64];
213 g_snprintf (string: message, n: sizeof message, format: "Size %dx%d", width, height);
214 gdk_profiler_add_mark (start_time, GDK_PROFILER_CURRENT_TIME-start_time, "Upload Icon", message);
215 }
216}
217

source code of gtk/gsk/gl/gskgliconlibrary.c