gtk/gsk/gl/gskglprogram.c
Matthias Clasen 144f727d5a Rename ngl to gl
We have only one gl renderer now, and it is
a bit odd for it not be called gl.
2021-10-07 13:05:53 -04:00

174 lines
4.9 KiB
C

/* gskglprogram.c
*
* Copyright 2020 Christian Hergert <chergert@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "config.h"
#include "gskglcommandqueueprivate.h"
#include "gskglprogramprivate.h"
#include "gskgluniformstateprivate.h"
G_DEFINE_TYPE (GskGLProgram, gsk_gl_program, G_TYPE_OBJECT)
GskGLProgram *
gsk_gl_program_new (GskGLDriver *driver,
const char *name,
int program_id)
{
GskGLProgram *self;
g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), NULL);
g_return_val_if_fail (program_id >= -1, NULL);
self = g_object_new (GSK_TYPE_GL_PROGRAM, NULL);
self->id = program_id;
self->name = g_strdup (name);
self->driver = g_object_ref (driver);
self->n_mappings = 0;
return self;
}
static void
gsk_gl_program_finalize (GObject *object)
{
GskGLProgram *self = (GskGLProgram *)object;
if (self->id >= 0)
g_warning ("Leaking GLSL program %d (%s)",
self->id,
self->name ? self->name : "");
g_clear_pointer (&self->name, g_free);
g_clear_object (&self->driver);
G_OBJECT_CLASS (gsk_gl_program_parent_class)->finalize (object);
}
static void
gsk_gl_program_class_init (GskGLProgramClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gsk_gl_program_finalize;
}
static void
gsk_gl_program_init (GskGLProgram *self)
{
self->id = -1;
for (guint i = 0; i < G_N_ELEMENTS (self->mappings); i++)
self->mappings[i].location = -1;
}
/**
* gsk_gl_program_add_uniform:
* @self: a `GskGLProgram`
* @name: the name of the uniform such as "u_source"
* @key: the identifier to use for the uniform
*
* This method will create a mapping between @key and the location
* of the uniform on the GPU. This simplifies calling code to not
* need to know where the uniform location is and only register it
* when creating the program.
*
* You might use this with an enum of all your uniforms for the
* program and then register each of them like:
*
* ```
* gsk_gl_program_add_uniform (program, "u_source", UNIFORM_SOURCE);
* ```
*
* That allows you to set values for the program with something
* like the following:
*
* ```
* gsk_gl_program_set_uniform1i (program, UNIFORM_SOURCE, 1);
* ```
*
* Returns: %TRUE if the uniform was found; otherwise %FALSE
*/
gboolean
gsk_gl_program_add_uniform (GskGLProgram *self,
const char *name,
guint key)
{
GLint location;
g_return_val_if_fail (GSK_IS_GL_PROGRAM (self), FALSE);
g_return_val_if_fail (name != NULL, FALSE);
g_return_val_if_fail (key < G_N_ELEMENTS (self->mappings), FALSE);
location = glGetUniformLocation (self->id, name);
/* Register the information even if unused */
self->mappings[key].name = g_intern_string (name);
self->mappings[key].location = location;
if (key >= self->n_mappings)
self->n_mappings = key + 1;
#if 0
g_print ("program [%d] %s uniform %s [%u of %u] at location %d.\n",
self->id, self->name, name, key, self->n_mappings, location);
#endif
return location > -1;
}
/**
* gsk_gl_program_delete:
* @self: a `GskGLProgram`
*
* Deletes the GLSL program.
*/
void
gsk_gl_program_delete (GskGLProgram *self)
{
g_return_if_fail (GSK_IS_GL_PROGRAM (self));
g_return_if_fail (self->driver->command_queue != NULL);
gsk_gl_command_queue_delete_program (self->driver->command_queue, self->id);
self->id = -1;
}
/**
* gsk_gl_program_uniforms_added:
* @self: a `GskGLProgram`
* @has_attachments: if any uniform is for a bind/texture attachment
*
* This function should be called after all of the uniforms ahve
* been added with gsk_gl_program_add_uniform().
*
* This function will setup the uniform state so that the program
* has fast access to the data buffers without as many lookups at
* runtime for comparison data.
*/
void
gsk_gl_program_uniforms_added (GskGLProgram *self,
gboolean has_attachments)
{
g_return_if_fail (GSK_IS_GL_PROGRAM (self));
g_return_if_fail (self->uniforms == NULL);
self->uniforms = self->driver->command_queue->uniforms;
self->program_info = gsk_gl_uniform_state_get_program (self->uniforms, self->id, self->mappings, self->n_mappings);
self->program_info->has_attachments = has_attachments;
}