1/* gskglprogram.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 "gskglcommandqueueprivate.h"
24#include "gskglprogramprivate.h"
25#include "gskgluniformstateprivate.h"
26
27G_DEFINE_TYPE (GskGLProgram, gsk_gl_program, G_TYPE_OBJECT)
28
29GskGLProgram *
30gsk_gl_program_new (GskGLDriver *driver,
31 const char *name,
32 int program_id)
33{
34 GskGLProgram *self;
35
36 g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), NULL);
37 g_return_val_if_fail (program_id >= -1, NULL);
38
39 self = g_object_new (GSK_TYPE_GL_PROGRAM, NULL);
40 self->id = program_id;
41 self->name = g_strdup (str: name);
42 self->driver = g_object_ref (driver);
43 self->n_mappings = 0;
44
45 return self;
46}
47
48static void
49gsk_gl_program_finalize (GObject *object)
50{
51 GskGLProgram *self = (GskGLProgram *)object;
52
53 if (self->id >= 0)
54 g_warning ("Leaking GLSL program %d (%s)",
55 self->id,
56 self->name ? self->name : "");
57
58 g_clear_pointer (&self->name, g_free);
59 g_clear_object (&self->driver);
60
61 G_OBJECT_CLASS (gsk_gl_program_parent_class)->finalize (object);
62}
63
64static void
65gsk_gl_program_class_init (GskGLProgramClass *klass)
66{
67 GObjectClass *object_class = G_OBJECT_CLASS (klass);
68
69 object_class->finalize = gsk_gl_program_finalize;
70}
71
72static void
73gsk_gl_program_init (GskGLProgram *self)
74{
75 self->id = -1;
76
77 for (guint i = 0; i < G_N_ELEMENTS (self->mappings); i++)
78 self->mappings[i].location = -1;
79}
80
81/**
82 * gsk_gl_program_add_uniform:
83 * @self: a `GskGLProgram`
84 * @name: the name of the uniform such as "u_source"
85 * @key: the identifier to use for the uniform
86 *
87 * This method will create a mapping between @key and the location
88 * of the uniform on the GPU. This simplifies calling code to not
89 * need to know where the uniform location is and only register it
90 * when creating the program.
91 *
92 * You might use this with an enum of all your uniforms for the
93 * program and then register each of them like:
94 *
95 * ```
96 * gsk_gl_program_add_uniform (program, "u_source", UNIFORM_SOURCE);
97 * ```
98 *
99 * That allows you to set values for the program with something
100 * like the following:
101 *
102 * ```
103 * gsk_gl_program_set_uniform1i (program, UNIFORM_SOURCE, 1);
104 * ```
105 *
106 * Returns: %TRUE if the uniform was found; otherwise %FALSE
107 */
108gboolean
109gsk_gl_program_add_uniform (GskGLProgram *self,
110 const char *name,
111 guint key)
112{
113 GLint location;
114
115 g_return_val_if_fail (GSK_IS_GL_PROGRAM (self), FALSE);
116 g_return_val_if_fail (name != NULL, FALSE);
117 g_return_val_if_fail (key < G_N_ELEMENTS (self->mappings), FALSE);
118
119 location = glGetUniformLocation (self->id, name);
120
121 /* Register the information even if unused */
122 self->mappings[key].name = g_intern_string (string: name);
123 self->mappings[key].location = location;
124 if (key >= self->n_mappings)
125 self->n_mappings = key + 1;
126
127#if 0
128 g_print ("program [%d] %s uniform %s [%u of %u] at location %d.\n",
129 self->id, self->name, name, key, self->n_mappings, location);
130#endif
131
132 return location > -1;
133}
134
135/**
136 * gsk_gl_program_delete:
137 * @self: a `GskGLProgram`
138 *
139 * Deletes the GLSL program.
140 */
141void
142gsk_gl_program_delete (GskGLProgram *self)
143{
144 g_return_if_fail (GSK_IS_GL_PROGRAM (self));
145 g_return_if_fail (self->driver->command_queue != NULL);
146
147 gsk_gl_command_queue_delete_program (self: self->driver->command_queue, program_id: self->id);
148 self->id = -1;
149}
150
151/**
152 * gsk_gl_program_uniforms_added:
153 * @self: a `GskGLProgram`
154 * @has_attachments: if any uniform is for a bind/texture attachment
155 *
156 * This function should be called after all of the uniforms ahve
157 * been added with gsk_gl_program_add_uniform().
158 *
159 * This function will setup the uniform state so that the program
160 * has fast access to the data buffers without as many lookups at
161 * runtime for comparison data.
162 */
163void
164gsk_gl_program_uniforms_added (GskGLProgram *self,
165 gboolean has_attachments)
166{
167 g_return_if_fail (GSK_IS_GL_PROGRAM (self));
168 g_return_if_fail (self->uniforms == NULL);
169
170 self->uniforms = self->driver->command_queue->uniforms;
171 self->program_info = gsk_gl_uniform_state_get_program (state: self->uniforms, program: self->id, mappings: self->mappings, n_mappings: self->n_mappings);
172 self->program_info->has_attachments = has_attachments;
173}
174

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