1 /* gskngltexturepool.c
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 #include "config.h"
22
23 #include <gdk/gdktextureprivate.h>
24
25 #include "gskngltexturepoolprivate.h"
26 #include "ninesliceprivate.h"
27
28 void
gsk_ngl_texture_free(GskNglTexture * texture)29 gsk_ngl_texture_free (GskNglTexture *texture)
30 {
31 if (texture != NULL)
32 {
33 g_assert (texture->link.prev == NULL);
34 g_assert (texture->link.next == NULL);
35
36 if (texture->user)
37 g_clear_pointer (&texture->user, gdk_texture_clear_render_data);
38
39 if (texture->texture_id != 0)
40 {
41 glDeleteTextures (1, &texture->texture_id);
42 texture->texture_id = 0;
43 }
44
45 for (guint i = 0; i < texture->n_slices; i++)
46 {
47 glDeleteTextures (1, &texture->slices[i].texture_id);
48 texture->slices[i].texture_id = 0;
49 }
50
51 g_clear_pointer (&texture->slices, g_free);
52 g_clear_pointer (&texture->nine_slice, g_free);
53
54 g_slice_free (GskNglTexture, texture);
55 }
56 }
57
58 void
gsk_ngl_texture_pool_init(GskNglTexturePool * self)59 gsk_ngl_texture_pool_init (GskNglTexturePool *self)
60 {
61 g_queue_init (&self->queue);
62 }
63
64 void
gsk_ngl_texture_pool_clear(GskNglTexturePool * self)65 gsk_ngl_texture_pool_clear (GskNglTexturePool *self)
66 {
67 guint *free_me = NULL;
68 guint *texture_ids;
69 guint i = 0;
70
71 if G_LIKELY (self->queue.length <= 1024)
72 texture_ids = g_newa (guint, self->queue.length);
73 else
74 texture_ids = free_me = g_new (guint, self->queue.length);
75
76 while (self->queue.length > 0)
77 {
78 GskNglTexture *head = g_queue_peek_head (&self->queue);
79
80 g_queue_unlink (&self->queue, &head->link);
81
82 texture_ids[i++] = head->texture_id;
83 head->texture_id = 0;
84
85 gsk_ngl_texture_free (head);
86 }
87
88 g_assert (self->queue.length == 0);
89
90 if (i > 0)
91 glDeleteTextures (i, texture_ids);
92
93 g_free (free_me);
94 }
95
96 void
gsk_ngl_texture_pool_put(GskNglTexturePool * self,GskNglTexture * texture)97 gsk_ngl_texture_pool_put (GskNglTexturePool *self,
98 GskNglTexture *texture)
99 {
100 g_assert (self != NULL);
101 g_assert (texture != NULL);
102 g_assert (texture->user == NULL);
103 g_assert (texture->link.prev == NULL);
104 g_assert (texture->link.next == NULL);
105 g_assert (texture->link.data == texture);
106
107 if (texture->permanent)
108 gsk_ngl_texture_free (texture);
109 else
110 g_queue_push_tail_link (&self->queue, &texture->link);
111 }
112
113 GskNglTexture *
gsk_ngl_texture_pool_get(GskNglTexturePool * self,int width,int height,int min_filter,int mag_filter)114 gsk_ngl_texture_pool_get (GskNglTexturePool *self,
115 int width,
116 int height,
117 int min_filter,
118 int mag_filter)
119 {
120 GskNglTexture *texture;
121
122 g_assert (self != NULL);
123
124 texture = g_slice_new0 (GskNglTexture);
125 texture->link.data = texture;
126 texture->min_filter = min_filter;
127 texture->mag_filter = mag_filter;
128
129 glGenTextures (1, &texture->texture_id);
130
131 glActiveTexture (GL_TEXTURE0);
132 glBindTexture (GL_TEXTURE_2D, texture->texture_id);
133 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter);
134 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter);
135 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
136 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
137
138 if (gdk_gl_context_get_use_es (gdk_gl_context_get_current ()))
139 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
140 else
141 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
142
143 glBindTexture (GL_TEXTURE_2D, 0);
144
145 return texture;
146 }
147
148 GskNglTexture *
gsk_ngl_texture_new(guint texture_id,int width,int height,int min_filter,int mag_filter,gint64 frame_id)149 gsk_ngl_texture_new (guint texture_id,
150 int width,
151 int height,
152 int min_filter,
153 int mag_filter,
154 gint64 frame_id)
155 {
156 GskNglTexture *texture;
157
158 texture = g_slice_new0 (GskNglTexture);
159 texture->texture_id = texture_id;
160 texture->link.data = texture;
161 texture->min_filter = min_filter;
162 texture->mag_filter = mag_filter;
163 texture->width = width;
164 texture->height = height;
165 texture->last_used_in_frame = frame_id;
166
167 return texture;
168 }
169
170 const GskNglTextureNineSlice *
gsk_ngl_texture_get_nine_slice(GskNglTexture * texture,const GskRoundedRect * outline,float extra_pixels_x,float extra_pixels_y)171 gsk_ngl_texture_get_nine_slice (GskNglTexture *texture,
172 const GskRoundedRect *outline,
173 float extra_pixels_x,
174 float extra_pixels_y)
175 {
176 g_assert (texture != NULL);
177 g_assert (outline != NULL);
178
179 if G_UNLIKELY (texture->nine_slice == NULL)
180 {
181 texture->nine_slice = g_new0 (GskNglTextureNineSlice, 9);
182
183 nine_slice_rounded_rect (texture->nine_slice, outline);
184 nine_slice_grow (texture->nine_slice, extra_pixels_x, extra_pixels_y);
185 nine_slice_to_texture_coords (texture->nine_slice, texture->width, texture->height);
186 }
187
188 return texture->nine_slice;
189 }
190