diff --git a/demos/node-editor/node-editor-window.c b/demos/node-editor/node-editor-window.c index 058ced5b3a5a282cfa2f380c636e8a78b7279c3d..c084bc659dc56c3073fa8d3ee01ae0f08394a8c8 100644 --- a/demos/node-editor/node-editor-window.c +++ b/demos/node-editor/node-editor-window.c @@ -925,7 +925,7 @@ export_image_response_cb (GObject *source, GdkTexture *texture; GskRenderer *renderer; - renderer = gsk_ngl_renderer_new (); + renderer = gsk_gl_renderer_new (); if (!gsk_renderer_realize_for_display (renderer, gdk_display_get_default (), NULL)) { g_object_unref (renderer); @@ -1234,9 +1234,6 @@ node_editor_window_realize (GtkWidget *widget) node_editor_window_add_renderer (self, gsk_gl_renderer_new (), "OpenGL"); - node_editor_window_add_renderer (self, - gsk_ngl_renderer_new (), - "NGL"); #ifdef GDK_RENDERING_VULKAN node_editor_window_add_renderer (self, gsk_vulkan_renderer_new (), diff --git a/docs/reference/gtk/running.md b/docs/reference/gtk/running.md index 2b7187fce70e76d5386949222d19121560d1e87b..c358ca6ddbc4ca32531fe9255f4f6be986dd712c 100644 --- a/docs/reference/gtk/running.md +++ b/docs/reference/gtk/running.md @@ -434,9 +434,15 @@ using and the GDK backend supports them: `cairo` : Selects the fallback Cairo renderer +`opengl` +: Selects the OpenGL renderer + `ngl` : Selects the OpenGL renderer +`gl`: +: Selects the OpenGL renderer. + `vulkan` : Selects the Vulkan renderer diff --git a/gdk/gdkdmabufegl.c b/gdk/gdkdmabufegl.c index c7d08459829454e44782038df18465e0deed51f8..a8325ca32b98df4761181e68cc2e7b9c2ae6014b 100644 --- a/gdk/gdkdmabufegl.c +++ b/gdk/gdkdmabufegl.c @@ -229,7 +229,6 @@ gdk_dmabuf_egl_create_image (GdkDisplay *display, typedef struct _GskRenderer GskRenderer; extern GskRenderer * gsk_gl_renderer_new (void); -extern GskRenderer * gsk_ngl_renderer_new (void); extern gboolean gsk_renderer_realize_for_display (GskRenderer *renderer, GdkDisplay *display, GError **error); @@ -276,7 +275,7 @@ gdk_dmabuf_egl_init (GdkDisplay *display) return; } - renderer = gsk_ngl_renderer_new (); + renderer = gsk_gl_renderer_new (); if (!gsk_renderer_realize_for_display (renderer, display, &error)) { diff --git a/gsk/gl/gskglattachmentstate.c b/gsk/gl/gskglattachmentstate.c deleted file mode 100644 index 3765e95f79921786ea090faf0c8f3a8c5f26d6ae..0000000000000000000000000000000000000000 --- a/gsk/gl/gskglattachmentstate.c +++ /dev/null @@ -1,116 +0,0 @@ -/* gskglattachmentstate.c - * - * Copyright 2020 Christian Hergert - * - * This file 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 file 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 General Public License along - * with this program. If not, see . - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#include "config.h" - -#include "gskglattachmentstateprivate.h" - -GskGLAttachmentState * -gsk_gl_attachment_state_new (void) -{ - GskGLAttachmentState *self; - - self = g_atomic_rc_box_new0 (GskGLAttachmentState); - - self->fbo.changed = FALSE; - self->fbo.id = 0; - self->n_changed = 0; - - /* Initialize textures, assume we are 2D by default since it - * doesn't really matter until we bind something other than - * GL_TEXTURE0 to it anyway. - */ - for (guint i = 0; i < G_N_ELEMENTS (self->textures); i++) - { - self->textures[i].target = GL_TEXTURE_2D; - self->textures[i].texture = GL_TEXTURE0; - self->textures[i].id = 0; - self->textures[i].changed = FALSE; - self->textures[i].initial = TRUE; - self->textures[i].sampler = sampler_index (GL_LINEAR, GL_LINEAR); - } - - return self; -} - -GskGLAttachmentState * -gsk_gl_attachment_state_ref (GskGLAttachmentState *self) -{ - return g_atomic_rc_box_acquire (self); -} - -void -gsk_gl_attachment_state_unref (GskGLAttachmentState *self) -{ - g_atomic_rc_box_release (self); -} - -void -gsk_gl_attachment_state_bind_texture (GskGLAttachmentState *self, - GLenum target, - GLenum texture, - guint id, - GLint min_filter, - GLint mag_filter) -{ - GskGLBindTexture *attach; - unsigned int sampler; - - g_assert (self != NULL); - g_assert (target == GL_TEXTURE_1D || - target == GL_TEXTURE_2D || - target == GL_TEXTURE_3D || - target == GL_TEXTURE_EXTERNAL_OES); - g_assert (texture >= GL_TEXTURE0 && texture <= GL_TEXTURE16); - g_assert (texture - GL_TEXTURE0 < G_N_ELEMENTS (self->textures)); - - attach = &self->textures[texture - GL_TEXTURE0]; - - sampler = sampler_index (min_filter, mag_filter); - - if (attach->target != target || attach->texture != texture || attach->id != id || - attach->sampler != sampler) - { - attach->target = target; - attach->texture = texture; - attach->id = id; - attach->initial = FALSE; - attach->sampler = sampler; - - if (attach->changed == FALSE) - { - attach->changed = TRUE; - self->n_changed++; - } - } -} - -void -gsk_gl_attachment_state_bind_framebuffer (GskGLAttachmentState *self, - guint id) -{ - g_assert (self != NULL); - - if (self->fbo.id != id) - { - self->fbo.id = id; - self->fbo.changed = TRUE; - } -} diff --git a/gsk/gl/gskglattachmentstateprivate.h b/gsk/gl/gskglattachmentstateprivate.h deleted file mode 100644 index e2ecf1a539418b3bfe188ce65fcc8c6cf02d504e..0000000000000000000000000000000000000000 --- a/gsk/gl/gskglattachmentstateprivate.h +++ /dev/null @@ -1,102 +0,0 @@ -/* gskglattachmentstateprivate.h - * - * Copyright 2020 Christian Hergert - * - * This file 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 file 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 General Public License along - * with this program. If not, see . - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#pragma once - -#include "gskgltypesprivate.h" - -G_BEGIN_DECLS - -typedef struct _GskGLAttachmentState GskGLAttachmentState; -typedef struct _GskGLBindFramebuffer GskGLBindFramebuffer; -typedef struct _GskGLBindTexture GskGLBindTexture; - -#define GSK_GL_N_FILTERS 3 -#define SAMPLER_EXTERNAL 9 - -G_STATIC_ASSERT (SAMPLER_EXTERNAL >= GSK_GL_N_FILTERS * GSK_GL_N_FILTERS); - -static inline guint -filter_index (GLint filter) -{ - switch (filter) - { - case GL_LINEAR: - return 0; - case GL_NEAREST: - return 1; - case GL_LINEAR_MIPMAP_LINEAR: - return 2; - default: - g_assert_not_reached (); - } -} - -static inline guint -sampler_index (GLint min_filter, - GLint mag_filter) -{ - return filter_index (min_filter) * GSK_GL_N_FILTERS + filter_index (mag_filter); -} - -struct _GskGLBindTexture -{ - guint changed : 1; - guint initial : 1; - GLenum target : 26; - guint sampler : 4; - GLenum texture; - guint id; -}; - -G_STATIC_ASSERT (sizeof (GskGLBindTexture) == 12); - -struct _GskGLBindFramebuffer -{ - guint changed : 1; - guint id : 31; -}; - -G_STATIC_ASSERT (sizeof (GskGLBindFramebuffer) == 4); - -/* Increase if shaders add more textures */ -#define GSK_GL_MAX_TEXTURES_PER_PROGRAM 4 - -struct _GskGLAttachmentState -{ - GskGLBindFramebuffer fbo; - GskGLBindTexture textures[GSK_GL_MAX_TEXTURES_PER_PROGRAM]; - guint n_changed; -}; - -GskGLAttachmentState *gsk_gl_attachment_state_new (void); -GskGLAttachmentState *gsk_gl_attachment_state_ref (GskGLAttachmentState *self); -void gsk_gl_attachment_state_unref (GskGLAttachmentState *self); -void gsk_gl_attachment_state_bind_texture (GskGLAttachmentState *self, - GLenum target, - GLenum texture, - guint id, - GLint min_filter, - GLint mag_filter); -void gsk_gl_attachment_state_bind_framebuffer (GskGLAttachmentState *self, - guint id); - -G_END_DECLS - diff --git a/gsk/gl/gskglbuffer.c b/gsk/gl/gskglbuffer.c deleted file mode 100644 index 63aabd1dc3b8b8d98e04350f3d10c9c21396618e..0000000000000000000000000000000000000000 --- a/gsk/gl/gskglbuffer.c +++ /dev/null @@ -1,69 +0,0 @@ -/* gskglbufferprivate.h - * - * Copyright 2020 Christian Hergert - * - * This file 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 file 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 General Public License along - * with this program. If not, see . - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#include "config.h" - -#include - -#include "gskglbufferprivate.h" - -/** - * gsk_gl_buffer_init: - * @target: the target buffer such as %GL_ARRAY_BUFFER or %GL_UNIFORM_BUFFER - * @element_size: the size of elements within the buffer - * - * Creates a new `GskGLBuffer` which can be used to deliver data to shaders - * within a GLSL program. You can use this to store vertices such as with - * %GL_ARRAY_BUFFER or uniform data with %GL_UNIFORM_BUFFER. - */ -void -gsk_gl_buffer_init (GskGLBuffer *self, - GLenum target, - guint element_size) -{ - memset (self, 0, sizeof *self); - - /* Default to 2 pages, power-of-two growth from there */ - self->buffer_len = 4096 * 2; - self->buffer = g_malloc (self->buffer_len); - self->target = target; - self->element_size = element_size; -} - -GLuint -gsk_gl_buffer_submit (GskGLBuffer *buffer) -{ - GLuint id; - - glGenBuffers (1, &id); - glBindBuffer (buffer->target, id); - glBufferData (buffer->target, buffer->buffer_pos, buffer->buffer, GL_STATIC_DRAW); - - buffer->buffer_pos = 0; - buffer->count = 0; - - return id; -} - -void -gsk_gl_buffer_destroy (GskGLBuffer *buffer) -{ - g_clear_pointer (&buffer->buffer, g_free); -} diff --git a/gsk/gl/gskglbufferprivate.h b/gsk/gl/gskglbufferprivate.h deleted file mode 100644 index fa4e65cc37786f362400e87819f0ac36a780d14a..0000000000000000000000000000000000000000 --- a/gsk/gl/gskglbufferprivate.h +++ /dev/null @@ -1,80 +0,0 @@ -/* gskglbufferprivate.h - * - * Copyright 2020 Christian Hergert - * - * This file 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 file 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 General Public License along - * with this program. If not, see . - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#pragma once - -#include "gskgltypesprivate.h" - -G_BEGIN_DECLS - -typedef struct _GskGLBuffer -{ - guint8 *buffer; - gsize buffer_pos; - gsize buffer_len; - guint count; - GLenum target; - gsize element_size; -} GskGLBuffer; - -void gsk_gl_buffer_init (GskGLBuffer *self, - GLenum target, - guint element_size); -void gsk_gl_buffer_destroy (GskGLBuffer *buffer); -GLuint gsk_gl_buffer_submit (GskGLBuffer *buffer); - -static inline gpointer -gsk_gl_buffer_advance (GskGLBuffer *buffer, - guint count) -{ - gpointer ret; - gsize to_alloc = count * buffer->element_size; - - if G_UNLIKELY (buffer->buffer_pos + to_alloc > buffer->buffer_len) - { - while (buffer->buffer_pos + to_alloc > buffer->buffer_len) - buffer->buffer_len *= 2; - buffer->buffer = g_realloc (buffer->buffer, buffer->buffer_len); - } - - ret = buffer->buffer + buffer->buffer_pos; - - buffer->buffer_pos += to_alloc; - buffer->count += count; - - return ret; -} - -static inline void -gsk_gl_buffer_retract (GskGLBuffer *buffer, - guint count) -{ - buffer->buffer_pos -= count * buffer->element_size; - buffer->count -= count; -} - -static inline guint -gsk_gl_buffer_get_offset (GskGLBuffer *buffer) -{ - return buffer->count; -} - -G_END_DECLS - diff --git a/gsk/gl/gskglcommandqueue.c b/gsk/gl/gskglcommandqueue.c deleted file mode 100644 index ae4ee166869f62768ba16a704937001afc481696..0000000000000000000000000000000000000000 --- a/gsk/gl/gskglcommandqueue.c +++ /dev/null @@ -1,1782 +0,0 @@ -/* gskglcommandqueue.c - * - * Copyright 2017 Timm Bäder - * Copyright 2018 Matthias Clasen - * Copyright 2018 Alexander Larsson - * Copyright 2020 Christian Hergert - * - * 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 . - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#include "config.h" - -#include - -#include -#include -#include -#include -#include -#include - -#include "gskglattachmentstateprivate.h" -#include "gskglbufferprivate.h" -#include "gskglcommandqueueprivate.h" -#include "gskgluniformstateprivate.h" - -#include "inlinearray.h" - -G_DEFINE_TYPE (GskGLCommandQueue, gsk_gl_command_queue, G_TYPE_OBJECT) - -#if 0 -G_GNUC_UNUSED static inline void -print_uniform (GskGLUniformFormat format, - guint array_count, - gconstpointer valueptr) -{ - const union { - graphene_matrix_t matrix[0]; - GskRoundedRect rounded_rect[0]; - float fval[0]; - int ival[0]; - guint uval[0]; - } *data = valueptr; - - switch (format) - { - case GSK_GL_UNIFORM_FORMAT_1F: - g_printerr ("1f<%f>", data->fval[0]); - break; - - case GSK_GL_UNIFORM_FORMAT_2F: - g_printerr ("2f<%f,%f>", data->fval[0], data->fval[1]); - break; - - case GSK_GL_UNIFORM_FORMAT_3F: - g_printerr ("3f<%f,%f,%f>", data->fval[0], data->fval[1], data->fval[2]); - break; - - case GSK_GL_UNIFORM_FORMAT_4F: - g_printerr ("4f<%f,%f,%f,%f>", data->fval[0], data->fval[1], data->fval[2], data->fval[3]); - break; - - case GSK_GL_UNIFORM_FORMAT_1I: - case GSK_GL_UNIFORM_FORMAT_TEXTURE: - g_printerr ("1i<%d>", data->ival[0]); - break; - - case GSK_GL_UNIFORM_FORMAT_1UI: - g_printerr ("1ui<%u>", data->uval[0]); - break; - - case GSK_GL_UNIFORM_FORMAT_COLOR: { - char *str = gdk_rgba_to_string (valueptr); - g_printerr ("%s", str); - g_free (str); - break; - } - - case GSK_GL_UNIFORM_FORMAT_ROUNDED_RECT: { - char *str = gsk_rounded_rect_to_string (valueptr); - g_printerr ("%s", str); - g_free (str); - break; - } - - case GSK_GL_UNIFORM_FORMAT_MATRIX: { - float mat[16]; - graphene_matrix_to_float (&data->matrix[0], mat); - g_printerr ("matrix<"); - for (guint i = 0; i < G_N_ELEMENTS (mat)-1; i++) - g_printerr ("%f,", mat[i]); - g_printerr ("%f>", mat[G_N_ELEMENTS (mat)-1]); - break; - } - - case GSK_GL_UNIFORM_FORMAT_1FV: - case GSK_GL_UNIFORM_FORMAT_2FV: - case GSK_GL_UNIFORM_FORMAT_3FV: - case GSK_GL_UNIFORM_FORMAT_4FV: - /* non-V variants are -4 from V variants */ - format -= 4; - g_printerr ("["); - for (guint i = 0; i < array_count; i++) - { - print_uniform (format, 0, valueptr); - if (i + 1 != array_count) - g_printerr (","); - valueptr = ((guint8*)valueptr + gsk_gl_uniform_format_size (format)); - } - g_printerr ("]"); - break; - - case GSK_GL_UNIFORM_FORMAT_2I: - g_printerr ("2i<%d,%d>", data->ival[0], data->ival[1]); - break; - - case GSK_GL_UNIFORM_FORMAT_3I: - g_printerr ("3i<%d,%d,%d>", data->ival[0], data->ival[1], data->ival[2]); - break; - - case GSK_GL_UNIFORM_FORMAT_4I: - g_printerr ("3i<%d,%d,%d,%d>", data->ival[0], data->ival[1], data->ival[2], data->ival[3]); - break; - - case GSK_GL_UNIFORM_FORMAT_LAST: - default: - g_assert_not_reached (); - } -} - -G_GNUC_UNUSED static inline void -gsk_gl_command_queue_print_batch (GskGLCommandQueue *self, - const GskGLCommandBatch *batch) -{ - static const char *command_kinds[] = { "Clear", "Draw", }; - guint framebuffer_id; - - g_assert (GSK_IS_GL_COMMAND_QUEUE (self)); - g_assert (batch != NULL); - - if (batch->any.kind == GSK_GL_COMMAND_KIND_CLEAR) - framebuffer_id = batch->clear.framebuffer; - else if (batch->any.kind == GSK_GL_COMMAND_KIND_DRAW) - framebuffer_id = batch->draw.framebuffer; - else - return; - - g_printerr ("Batch {\n"); - g_printerr (" Kind: %s\n", command_kinds[batch->any.kind]); - g_printerr (" Viewport: %dx%d\n", batch->any.viewport.width, batch->any.viewport.height); - g_printerr (" Framebuffer: %d\n", framebuffer_id); - - if (batch->any.kind == GSK_GL_COMMAND_KIND_DRAW) - { - g_printerr (" Program: %d\n", batch->any.program); - g_printerr (" Vertices: %d\n", batch->draw.vbo_count); - - for (guint i = 0; i < batch->draw.bind_count; i++) - { - const GskGLCommandBind *bind = &self->batch_binds.items[batch->draw.bind_offset + i]; - g_printerr (" Bind[%d]: %u\n", bind->texture, bind->id); - } - - for (guint i = 0; i < batch->draw.uniform_count; i++) - { - const GskGLCommandUniform *uniform = &self->batch_uniforms.items[batch->draw.uniform_offset + i]; - g_printerr (" Uniform[%02d]: ", uniform->location); - print_uniform (uniform->info.format, - uniform->info.array_count, - gsk_gl_uniform_state_get_uniform_data (self->uniforms, uniform->info.offset)); - g_printerr ("\n"); - } - } - else if (batch->any.kind == GSK_GL_COMMAND_KIND_CLEAR) - { - g_printerr (" Bits: 0x%x\n", batch->clear.bits); - } - - g_printerr ("}\n"); -} - -G_GNUC_UNUSED static inline void -gsk_gl_command_queue_capture_png (GskGLCommandQueue *self, - const char *filename, - guint width, - guint height, - gboolean flip_y) -{ - guint stride; - guint8 *data; - GBytes *bytes; - GdkTexture *texture; - - g_assert (GSK_IS_GL_COMMAND_QUEUE (self)); - g_assert (filename != NULL); - - stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, width); - data = g_malloc_n (height, stride); - - glReadPixels (0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, data); - - if (flip_y) - { - guint8 *flipped = g_malloc_n (height, stride); - - for (guint i = 0; i < height; i++) - memcpy (flipped + (height * stride) - ((i + 1) * stride), - data + (stride * i), - stride); - - g_free (data); - data = flipped; - } - - bytes = g_bytes_new_take (data, height * stride); - texture = gdk_memory_texture_new (width, height, GDK_MEMORY_DEFAULT, bytes, stride); - g_bytes_unref (bytes); - - gdk_texture_save_to_png (texture, filename); - g_object_unref (texture); -} -#endif - -static inline gboolean -will_ignore_batch (GskGLCommandQueue *self) -{ - if G_LIKELY (self->batches.len < G_MAXINT16) - return FALSE; - - if (!self->have_truncated) - { - self->have_truncated = TRUE; - g_critical ("GL command queue too large, truncating further batches."); - } - - return TRUE; -} - -static inline GLint -min_filter_from_index (guint index) -{ - GLint filters[3] = { GL_LINEAR, GL_NEAREST, GL_LINEAR_MIPMAP_LINEAR }; - - g_assert (index < GSK_GL_N_FILTERS); - - return filters[index]; -} - -static inline GLint -mag_filter_from_index (guint index) -{ - GLint filters[3] = { GL_LINEAR, GL_NEAREST, GL_LINEAR }; - - g_assert (index < GSK_GL_N_FILTERS); - - return filters[index]; -} - -static inline guint -snapshot_attachments (const GskGLAttachmentState *state, - GskGLCommandBinds *array) -{ - GskGLCommandBind *bind = gsk_gl_command_binds_append_n (array, G_N_ELEMENTS (state->textures)); - guint count = 0; - - for (guint i = 0; i < G_N_ELEMENTS (state->textures); i++) - { - if (state->textures[i].id) - { - bind[count].id = state->textures[i].id; - bind[count].texture = state->textures[i].texture; - if (state->textures[i].target == GL_TEXTURE_EXTERNAL_OES) - bind[count].sampler = SAMPLER_EXTERNAL; - else - bind[count].sampler = state->textures[i].sampler; - count++; - } - } - - if (count != G_N_ELEMENTS (state->textures)) - array->len -= G_N_ELEMENTS (state->textures) - count; - - return count; -} - -static inline guint -snapshot_uniforms (GskGLUniformState *state, - GskGLUniformProgram *program, - GskGLCommandUniforms *array) -{ - GskGLCommandUniform *uniform = gsk_gl_command_uniforms_append_n (array, program->n_mappings); - guint count = 0; - - for (guint i = 0; i < program->n_mappings; i++) - { - const GskGLUniformMapping *mapping = &program->mappings[i]; - - if (!mapping->info.initial && mapping->info.format && mapping->location > -1) - { - uniform[count].location = mapping->location; - uniform[count].info = mapping->info; - count++; - } - } - - if (count != program->n_mappings) - array->len -= program->n_mappings - count; - - return count; -} - -static inline gboolean -snapshots_equal (GskGLCommandQueue *self, - GskGLCommandBatch *first, - GskGLCommandBatch *second) -{ - if (first->draw.bind_count != second->draw.bind_count || - first->draw.uniform_count != second->draw.uniform_count) - return FALSE; - - for (guint i = 0; i < first->draw.bind_count; i++) - { - const GskGLCommandBind *fb = &self->batch_binds.items[first->draw.bind_offset+i]; - const GskGLCommandBind *sb = &self->batch_binds.items[second->draw.bind_offset+i]; - - if (fb->id != sb->id || fb->texture != sb->texture) - return FALSE; - } - - for (guint i = 0; i < first->draw.uniform_count; i++) - { - const GskGLCommandUniform *fu = &self->batch_uniforms.items[first->draw.uniform_offset+i]; - const GskGLCommandUniform *su = &self->batch_uniforms.items[second->draw.uniform_offset+i]; - gconstpointer fdata; - gconstpointer sdata; - gsize len; - - /* Short circuit if we'd end up with the same memory */ - if (fu->info.offset == su->info.offset) - continue; - - if (fu->info.format != su->info.format || - fu->info.array_count != su->info.array_count) - return FALSE; - - fdata = gsk_gl_uniform_state_get_uniform_data (self->uniforms, fu->info.offset); - sdata = gsk_gl_uniform_state_get_uniform_data (self->uniforms, su->info.offset); - - switch (fu->info.format) - { - case GSK_GL_UNIFORM_FORMAT_1F: - case GSK_GL_UNIFORM_FORMAT_1FV: - case GSK_GL_UNIFORM_FORMAT_1I: - case GSK_GL_UNIFORM_FORMAT_TEXTURE: - case GSK_GL_UNIFORM_FORMAT_1UI: - len = 4; - break; - - case GSK_GL_UNIFORM_FORMAT_2F: - case GSK_GL_UNIFORM_FORMAT_2FV: - case GSK_GL_UNIFORM_FORMAT_2I: - len = 8; - break; - - case GSK_GL_UNIFORM_FORMAT_3F: - case GSK_GL_UNIFORM_FORMAT_3FV: - case GSK_GL_UNIFORM_FORMAT_3I: - len = 12; - break; - - case GSK_GL_UNIFORM_FORMAT_4F: - case GSK_GL_UNIFORM_FORMAT_4FV: - case GSK_GL_UNIFORM_FORMAT_4I: - len = 16; - break; - - - case GSK_GL_UNIFORM_FORMAT_MATRIX: - len = sizeof (float) * 16; - break; - - case GSK_GL_UNIFORM_FORMAT_ROUNDED_RECT: - len = sizeof (float) * 12; - break; - - case GSK_GL_UNIFORM_FORMAT_COLOR: - len = sizeof (float) * 4; - break; - - default: - g_assert_not_reached (); - } - - len *= fu->info.array_count; - - if (memcmp (fdata, sdata, len) != 0) - return FALSE; - } - - return TRUE; -} - -static void -gsk_gl_command_queue_dispose (GObject *object) -{ - GskGLCommandQueue *self = (GskGLCommandQueue *)object; - - g_assert (GSK_IS_GL_COMMAND_QUEUE (self)); - - g_clear_object (&self->profiler); - g_clear_object (&self->gl_profiler); - g_clear_object (&self->context); - g_clear_pointer (&self->attachments, gsk_gl_attachment_state_unref); - g_clear_pointer (&self->uniforms, gsk_gl_uniform_state_unref); - - if (self->has_samplers) - glDeleteSamplers (G_N_ELEMENTS (self->samplers), self->samplers); - - gsk_gl_command_batches_clear (&self->batches); - gsk_gl_command_binds_clear (&self->batch_binds); - gsk_gl_command_uniforms_clear (&self->batch_uniforms); - gsk_gl_syncs_clear (&self->syncs); - - gsk_gl_buffer_destroy (&self->vertices); - - G_OBJECT_CLASS (gsk_gl_command_queue_parent_class)->dispose (object); -} - -static void -gsk_gl_command_queue_class_init (GskGLCommandQueueClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->dispose = gsk_gl_command_queue_dispose; -} - -static void -gsk_gl_command_queue_init (GskGLCommandQueue *self) -{ - self->max_texture_size = -1; - - gsk_gl_command_batches_init (&self->batches, 128); - gsk_gl_command_binds_init (&self->batch_binds, 1024); - gsk_gl_command_uniforms_init (&self->batch_uniforms, 2048); - gsk_gl_syncs_init (&self->syncs, 10); - - gsk_gl_buffer_init (&self->vertices, GL_ARRAY_BUFFER, sizeof (GskGLDrawVertex)); -} - -GskGLCommandQueue * -gsk_gl_command_queue_new (GdkGLContext *context, - GskGLUniformState *uniforms) -{ - GskGLCommandQueue *self; - guint i; - - g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL); - - self = g_object_new (GSK_TYPE_GL_COMMAND_QUEUE, NULL); - self->context = g_object_ref (context); - self->attachments = gsk_gl_attachment_state_new (); - - /* Use shared uniform state if we're provided one */ - if (uniforms != NULL) - self->uniforms = gsk_gl_uniform_state_ref (uniforms); - else - self->uniforms = gsk_gl_uniform_state_new (); - - /* Determine max texture size immediately and restore context */ - gdk_gl_context_make_current (context); - - glGetIntegerv (GL_MAX_TEXTURE_SIZE, &self->max_texture_size); - if (g_getenv ("GSK_MAX_TEXTURE_SIZE")) - { - int max_texture_size = atoi (g_getenv ("GSK_MAX_TEXTURE_SIZE")); - if (max_texture_size == 0) - { - g_warning ("Failed to parse %s", "GSK_MAX_TEXTURE_SIZE"); - } - else - { - max_texture_size = MAX (max_texture_size, 512); - GSK_DEBUG (RENDERER, - "Limiting texture size in the GL renderer to %d (via %s)", - max_texture_size, "GSK_MAX_TEXTURE_SIZE"); - self->max_texture_size = MIN (self->max_texture_size, max_texture_size); - } - } - - self->has_samplers = gdk_gl_context_check_version (context, "3.3", "3.0"); - self->can_swizzle = gdk_gl_context_check_version (context, "3.0", "3.0"); - - /* create the samplers */ - if (self->has_samplers) - { - glGenSamplers (G_N_ELEMENTS (self->samplers), self->samplers); - for (i = 0; i < G_N_ELEMENTS (self->samplers); i++) - { - glSamplerParameteri (self->samplers[i], GL_TEXTURE_MIN_FILTER, min_filter_from_index (i / GSK_GL_N_FILTERS)); - glSamplerParameteri (self->samplers[i], GL_TEXTURE_MAG_FILTER, mag_filter_from_index (i % GSK_GL_N_FILTERS)); - glSamplerParameteri (self->samplers[i], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glSamplerParameteri (self->samplers[i], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - } - - return g_steal_pointer (&self); -} - -static inline GskGLCommandBatch * -begin_next_batch (GskGLCommandQueue *self) -{ - GskGLCommandBatch *batch; - - g_assert (GSK_IS_GL_COMMAND_QUEUE (self)); - - /* GskGLCommandBatch contains an embedded linked list using integers into the - * self->batches array. We can't use pointer because the batches could be - * realloc()'d at runtime. - * - * Before we execute the command queue, we sort the batches by framebuffer but - * leave the batches in place as we can just tweak the links via prev/next. - * - * Generally we only traverse forwards, so we could ignore the previous field. - * But to optimize the reordering of batches by framebuffer we walk backwards - * so we sort by most-recently-seen framebuffer to ensure draws happen in the - * proper order. - */ - - batch = gsk_gl_command_batches_append (&self->batches); - batch->any.next_batch_index = -1; - batch->any.prev_batch_index = self->tail_batch_index; - - return batch; -} - -static void -enqueue_batch (GskGLCommandQueue *self) -{ - guint index; - - g_assert (GSK_IS_GL_COMMAND_QUEUE (self)); - g_assert (self->batches.len > 0); - - /* Batches are linked lists but using indexes into the batches array instead - * of pointers. This is for two main reasons. First, 16-bit indexes allow us - * to store the information in 4 bytes, where as two pointers would take 16 - * bytes. Furthermore, we have an array here so pointers would get - * invalidated if we realloc()'d (and that can happen from time to time). - */ - - index = self->batches.len - 1; - - if (self->head_batch_index == -1) - self->head_batch_index = index; - - if (self->tail_batch_index != -1) - { - GskGLCommandBatch *prev = &self->batches.items[self->tail_batch_index]; - - prev->any.next_batch_index = index; - } - - self->tail_batch_index = index; -} - -static void -discard_batch (GskGLCommandQueue *self) -{ - g_assert (GSK_IS_GL_COMMAND_QUEUE (self)); - g_assert (self->batches.len > 0); - - self->batches.len--; -} - -gboolean -gsk_gl_command_queue_begin_draw (GskGLCommandQueue *self, - GskGLUniformProgram *program, - guint width, - guint height) -{ - GskGLCommandBatch *batch; - - g_assert (GSK_IS_GL_COMMAND_QUEUE (self)); - g_assert (self->in_draw == FALSE); - g_assert (width <= G_MAXUINT16); - g_assert (height <= G_MAXUINT16); - - /* Our internal links use 16-bits, so that is our max number - * of batches we can have in one frame. - */ - if (will_ignore_batch (self)) - return FALSE; - - self->program_info = program; - - batch = begin_next_batch (self); - batch->any.kind = GSK_GL_COMMAND_KIND_DRAW; - batch->any.program = program->program_id; - batch->any.next_batch_index = -1; - batch->any.viewport.width = width; - batch->any.viewport.height = height; - batch->draw.blend = 1; - batch->draw.framebuffer = 0; - batch->draw.uniform_count = 0; - batch->draw.uniform_offset = self->batch_uniforms.len; - batch->draw.bind_count = 0; - batch->draw.bind_offset = self->batch_binds.len; - batch->draw.vbo_count = 0; - batch->draw.vbo_offset = gsk_gl_buffer_get_offset (&self->vertices); - - self->fbo_max = MAX (self->fbo_max, batch->draw.framebuffer); - - self->in_draw = TRUE; - - return TRUE; -} - -void -gsk_gl_command_queue_end_draw (GskGLCommandQueue *self) -{ - GskGLCommandBatch *last_batch; - GskGLCommandBatch *batch; - - g_assert (GSK_IS_GL_COMMAND_QUEUE (self)); - g_assert (self->batches.len > 0); - - if (will_ignore_batch (self)) - { - self->in_draw = FALSE; - return; - } - - batch = gsk_gl_command_batches_tail (&self->batches); - - g_assert (self->in_draw == TRUE); - g_assert (batch->any.kind == GSK_GL_COMMAND_KIND_DRAW); - - if G_UNLIKELY (batch->draw.vbo_count == 0) - { - discard_batch (self); - self->in_draw = FALSE; - return; - } - - /* Track the destination framebuffer in case it changed */ - batch->draw.framebuffer = self->attachments->fbo.id; - self->attachments->fbo.changed = FALSE; - self->fbo_max = MAX (self->fbo_max, self->attachments->fbo.id); - - /* Save our full uniform state for this draw so we can possibly - * reorder the draw later. - */ - batch->draw.uniform_offset = self->batch_uniforms.len; - batch->draw.uniform_count = snapshot_uniforms (self->uniforms, self->program_info, &self->batch_uniforms); - - /* Track the bind attachments that changed */ - if (self->program_info->has_attachments) - { - batch->draw.bind_offset = self->batch_binds.len; - batch->draw.bind_count = snapshot_attachments (self->attachments, &self->batch_binds); - } - else - { - batch->draw.bind_offset = 0; - batch->draw.bind_count = 0; - } - - if (self->batches.len > 1) - last_batch = &self->batches.items[self->batches.len - 2]; - else - last_batch = NULL; - - /* Do simple chaining of draw to last batch. */ - if (last_batch != NULL && - last_batch->any.kind == GSK_GL_COMMAND_KIND_DRAW && - last_batch->any.program == batch->any.program && - last_batch->any.viewport.width == batch->any.viewport.width && - last_batch->any.viewport.height == batch->any.viewport.height && - last_batch->draw.blend == batch->draw.blend && - last_batch->draw.framebuffer == batch->draw.framebuffer && - last_batch->draw.vbo_offset + last_batch->draw.vbo_count == batch->draw.vbo_offset && - last_batch->draw.vbo_count + batch->draw.vbo_count <= 0xffff && - snapshots_equal (self, last_batch, batch)) - { - last_batch->draw.vbo_count += batch->draw.vbo_count; - discard_batch (self); - } - else - { - enqueue_batch (self); - } - - self->in_draw = FALSE; - self->program_info = NULL; -} - -/** - * gsk_gl_command_queue_split_draw: - * @self a `GskGLCommandQueue` - * - * This function is like calling gsk_gl_command_queue_end_draw() followed by - * a gsk_gl_command_queue_begin_draw() with the same parameters as a - * previous begin draw (if shared uniforms where not changed further). - * - * This is useful to avoid comparisons inside of loops where we know shared - * uniforms are not changing. - * - * This generally should just be called from gsk_gl_program_split_draw() - * as that is where the begin/end flow happens from the render job. - */ -void -gsk_gl_command_queue_split_draw (GskGLCommandQueue *self) -{ - GskGLCommandBatch *batch; - GskGLUniformProgram *program; - guint width; - guint height; - - g_assert (GSK_IS_GL_COMMAND_QUEUE (self)); - g_assert (self->batches.len > 0); - - if (will_ignore_batch (self)) - return; - - g_assert (self->in_draw == TRUE); - - program = self->program_info; - - batch = gsk_gl_command_batches_tail (&self->batches); - - g_assert (batch->any.kind == GSK_GL_COMMAND_KIND_DRAW); - - width = batch->any.viewport.width; - height = batch->any.viewport.height; - - gsk_gl_command_queue_end_draw (self); - gsk_gl_command_queue_begin_draw (self, program, width, height); -} - -void -gsk_gl_command_queue_clear (GskGLCommandQueue *self, - guint clear_bits, - const graphene_rect_t *viewport) -{ - GskGLCommandBatch *batch; - - g_assert (GSK_IS_GL_COMMAND_QUEUE (self)); - g_assert (self->in_draw == FALSE); - - if (will_ignore_batch (self)) - return; - - if (clear_bits == 0) - clear_bits = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; - - batch = begin_next_batch (self); - batch->any.kind = GSK_GL_COMMAND_KIND_CLEAR; - batch->any.viewport.width = viewport->size.width; - batch->any.viewport.height = viewport->size.height; - batch->clear.bits = clear_bits; - batch->clear.framebuffer = self->attachments->fbo.id; - batch->any.next_batch_index = -1; - batch->any.program = 0; - - self->fbo_max = MAX (self->fbo_max, batch->clear.framebuffer); - - enqueue_batch (self); - - self->attachments->fbo.changed = FALSE; -} - -GdkGLContext * -gsk_gl_command_queue_get_context (GskGLCommandQueue *self) -{ - g_return_val_if_fail (GSK_IS_GL_COMMAND_QUEUE (self), NULL); - - return self->context; -} - -void -gsk_gl_command_queue_make_current (GskGLCommandQueue *self) -{ - g_assert (GSK_IS_GL_COMMAND_QUEUE (self)); - g_assert (GDK_IS_GL_CONTEXT (self->context)); - - gdk_gl_context_make_current (self->context); -} - -void -gsk_gl_command_queue_delete_program (GskGLCommandQueue *self, - guint program) -{ - g_assert (GSK_IS_GL_COMMAND_QUEUE (self)); - - glDeleteProgram (program); -} - -static inline void -apply_viewport (guint *current_width, - guint *current_height, - guint width, - guint height) -{ - if G_UNLIKELY (*current_width != width || *current_height != height) - { - *current_width = width; - *current_height = height; - glViewport (0, 0, width, height); - } -} - -static inline void -apply_scissor (gboolean *state, - guint framebuffer, - const graphene_rect_t *scissor, - gboolean has_scissor, - guint default_framebuffer) -{ - g_assert (framebuffer != (guint)-1); - - if (framebuffer != default_framebuffer || !has_scissor) - { - if (*state != FALSE) - { - glDisable (GL_SCISSOR_TEST); - *state = FALSE; - } - } - else - { - if (*state != TRUE) - { - glEnable (GL_SCISSOR_TEST); - glScissor (scissor->origin.x, - scissor->origin.y, - scissor->size.width, - scissor->size.height); - *state = TRUE; - } - } -} - -static inline gboolean -apply_framebuffer (int *framebuffer, - guint new_framebuffer) -{ - if G_UNLIKELY (new_framebuffer != *framebuffer) - { - *framebuffer = new_framebuffer; - glBindFramebuffer (GL_FRAMEBUFFER, new_framebuffer); - return TRUE; - } - - return FALSE; -} - -static inline void -gsk_gl_command_queue_unlink (GskGLCommandQueue *self, - GskGLCommandBatch *batch) -{ - if (batch->any.prev_batch_index == -1) - self->head_batch_index = batch->any.next_batch_index; - else - self->batches.items[batch->any.prev_batch_index].any.next_batch_index = batch->any.next_batch_index; - - if (batch->any.next_batch_index == -1) - self->tail_batch_index = batch->any.prev_batch_index; - else - self->batches.items[batch->any.next_batch_index].any.prev_batch_index = batch->any.prev_batch_index; - - batch->any.prev_batch_index = -1; - batch->any.next_batch_index = -1; -} - -static inline void -gsk_gl_command_queue_insert_before (GskGLCommandQueue *self, - GskGLCommandBatch *batch, - GskGLCommandBatch *sibling) -{ - int sibling_index; - int index; - - g_assert (batch >= self->batches.items); - g_assert (batch < &self->batches.items[self->batches.len]); - g_assert (sibling >= self->batches.items); - g_assert (sibling < &self->batches.items[self->batches.len]); - - index = gsk_gl_command_batches_index_of (&self->batches, batch); - sibling_index = gsk_gl_command_batches_index_of (&self->batches, sibling); - - batch->any.next_batch_index = sibling_index; - batch->any.prev_batch_index = sibling->any.prev_batch_index; - - if (batch->any.prev_batch_index > -1) - self->batches.items[batch->any.prev_batch_index].any.next_batch_index = index; - - sibling->any.prev_batch_index = index; - - if (batch->any.prev_batch_index == -1) - self->head_batch_index = index; -} - -static void -gsk_gl_command_queue_sort_batches (GskGLCommandQueue *self) -{ - int *seen; - int *seen_free = NULL; - int index; - - g_assert (GSK_IS_GL_COMMAND_QUEUE (self)); - g_assert (self->tail_batch_index >= 0); - g_assert (self->fbo_max >= 0); - - /* Create our seen list with most recent index set to -1, - * meaning we haven't yet seen that framebuffer. - */ - if (self->fbo_max < 1024) - seen = g_alloca (sizeof (int) * (self->fbo_max + 1)); - else - seen = seen_free = g_new0 (int, (self->fbo_max + 1)); - for (int i = 0; i <= self->fbo_max; i++) - seen[i] = -1; - - /* Walk in reverse, and if we've seen that framebuffer before, we want to - * delay this operation until right before the last batch we saw for that - * framebuffer. - * - * We can do this because we don't use a framebuffer's texture until it has - * been completely drawn. - */ - index = self->tail_batch_index; - - while (index >= 0) - { - GskGLCommandBatch *batch = &self->batches.items[index]; - int cur_index = index; - int fbo = -1; - - g_assert (index > -1); - g_assert (index < self->batches.len); - - switch (batch->any.kind) - { - case GSK_GL_COMMAND_KIND_DRAW: - fbo = batch->draw.framebuffer; - break; - - case GSK_GL_COMMAND_KIND_CLEAR: - fbo = batch->clear.framebuffer; - break; - - default: - g_assert_not_reached (); - } - - index = batch->any.prev_batch_index; - - g_assert (index >= -1); - g_assert (index < (int)self->batches.len); - g_assert (fbo >= -1); - - if (fbo == -1) - continue; - - g_assert (fbo <= self->fbo_max); - g_assert (seen[fbo] >= -1); - g_assert (seen[fbo] < (int)self->batches.len); - - if (seen[fbo] != -1 && seen[fbo] != batch->any.next_batch_index) - { - int mru_index = seen[fbo]; - GskGLCommandBatch *mru = &self->batches.items[mru_index]; - - g_assert (mru_index > -1); - - gsk_gl_command_queue_unlink (self, batch); - - g_assert (batch->any.prev_batch_index == -1); - g_assert (batch->any.next_batch_index == -1); - - gsk_gl_command_queue_insert_before (self, batch, mru); - - g_assert (batch->any.prev_batch_index > -1 || - self->head_batch_index == cur_index); - g_assert (batch->any.next_batch_index == seen[fbo]); - } - - g_assert (cur_index > -1); - g_assert (seen[fbo] >= -1); - - seen[fbo] = cur_index; - } - - g_free (seen_free); -} - -/** - * gsk_gl_command_queue_execute: - * @self: a `GskGLCommandQueue` - * @surface_height: the height of the backing surface - * @scale: the scale of the backing surface - * @scissor: (nullable): the scissor clip if any - * @default_framebuffer: the default framebuffer id if not zero - * - * Executes all of the batches in the command queue. - * - * Typically, the scissor rect is only applied when rendering to the default - * framebuffer (zero in most cases). However, if @default_framebuffer is not - * zero, it will be checked to see if the rendering target matches so that - * the scissor rect is applied. This should be used in cases where rendering - * to the backbuffer for display is not the default GL framebuffer of zero. - * Currently, this happens when rendering on macOS using IOSurface. - */ -void -gsk_gl_command_queue_execute (GskGLCommandQueue *self, - guint surface_height, - float scale, - const cairo_region_t *scissor, - guint default_framebuffer) -{ - G_GNUC_UNUSED guint count = 0; - graphene_rect_t scissor_test = GRAPHENE_RECT_INIT (0, 0, 0, 0); - gboolean has_scissor = scissor != NULL; - gboolean scissor_state = -1; - guint program = 0; - guint width = 0; - guint height = 0; - G_GNUC_UNUSED unsigned int n_binds = 0; - G_GNUC_UNUSED unsigned int n_fbos = 0; - G_GNUC_UNUSED unsigned int n_uniforms = 0; - G_GNUC_UNUSED unsigned int n_programs = 0; - guint vao_id; - guint vbo_id; - int textures[GSK_GL_MAX_TEXTURES_PER_PROGRAM]; - int samplers[GSK_GL_MAX_TEXTURES_PER_PROGRAM]; - int framebuffer = -1; - int next_batch_index; - int active = -1; - - g_assert (GSK_IS_GL_COMMAND_QUEUE (self)); - g_assert (self->in_draw == FALSE); - - if (self->batches.len == 0) - return; - - for (guint i = 0; i < G_N_ELEMENTS (textures); i++) - textures[i] = -1; - for (guint i = 0; i < G_N_ELEMENTS (samplers); i++) - samplers[i] = -1; - - gsk_gl_command_queue_sort_batches (self); - - gsk_gl_command_queue_make_current (self); - - gsk_gl_profiler_begin_gpu_region (self->gl_profiler); - gsk_profiler_timer_begin (self->profiler, self->metrics.cpu_time); - - glDisable (GL_DEPTH_TEST); - - /* Pre-multiplied alpha */ - glEnable (GL_BLEND); - glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - glBlendEquation (GL_FUNC_ADD); - - if (gdk_gl_context_has_vertex_arrays (self->context)) - { - glGenVertexArrays (1, &vao_id); - glBindVertexArray (vao_id); - } - - vbo_id = gsk_gl_buffer_submit (&self->vertices); - - /* 0 = position location */ - glEnableVertexAttribArray (0); - glVertexAttribPointer (0, 2, GL_FLOAT, GL_FALSE, - sizeof (GskGLDrawVertex), - GSIZE_TO_POINTER ((gsize) G_STRUCT_OFFSET (GskGLDrawVertex, position))); - - /* 1 = texture coord location */ - glEnableVertexAttribArray (1); - glVertexAttribPointer (1, 2, GL_FLOAT, GL_FALSE, - sizeof (GskGLDrawVertex), - GSIZE_TO_POINTER ((gsize) G_STRUCT_OFFSET (GskGLDrawVertex, uv))); - - /* 2 = color location */ - glEnableVertexAttribArray (2); - glVertexAttribPointer (2, 4, GL_HALF_FLOAT, GL_FALSE, - sizeof (GskGLDrawVertex), - GSIZE_TO_POINTER ((gsize) G_STRUCT_OFFSET (GskGLDrawVertex, color))); - - /* 3 = color2 location */ - glEnableVertexAttribArray (3); - glVertexAttribPointer (3, 4, GL_HALF_FLOAT, GL_FALSE, - sizeof (GskGLDrawVertex), - GSIZE_TO_POINTER ((gsize) G_STRUCT_OFFSET (GskGLDrawVertex, color2))); - - /* Setup initial scissor clip */ - if (scissor != NULL && cairo_region_num_rectangles (scissor) > 0) - { - cairo_rectangle_int_t r; - - g_assert (cairo_region_num_rectangles (scissor) == 1); - cairo_region_get_rectangle (scissor, 0, &r); - - scissor_test.origin.x = (int) floor (r.x * scale); - scissor_test.origin.y = (int) floor (surface_height - (r.height * scale) - (r.y * scale)); - scissor_test.size.width = (int) ceil (r.width * scale); - scissor_test.size.height = (int) ceil (r.height * scale); - } - - next_batch_index = self->head_batch_index; - - while (next_batch_index >= 0) - { - const GskGLCommandBatch *batch = &self->batches.items[next_batch_index]; - - g_assert (next_batch_index >= 0); - g_assert (next_batch_index < self->batches.len); - g_assert (batch->any.next_batch_index != next_batch_index); - - count++; - - switch (batch->any.kind) - { - case GSK_GL_COMMAND_KIND_CLEAR: - if (apply_framebuffer (&framebuffer, batch->clear.framebuffer)) - { - apply_scissor (&scissor_state, framebuffer, &scissor_test, has_scissor, default_framebuffer); - n_fbos++; - } - - apply_viewport (&width, - &height, - batch->any.viewport.width, - batch->any.viewport.height); - - glClearColor (0, 0, 0, 0); - glClear (batch->clear.bits); - break; - - case GSK_GL_COMMAND_KIND_DRAW: - if (batch->any.program != program) - { - program = batch->any.program; - glUseProgram (program); - - n_programs++; - } - - if (apply_framebuffer (&framebuffer, batch->draw.framebuffer)) - { - apply_scissor (&scissor_state, framebuffer, &scissor_test, has_scissor, default_framebuffer); - n_fbos++; - } - - apply_viewport (&width, - &height, - batch->any.viewport.width, - batch->any.viewport.height); - - if G_UNLIKELY (batch->draw.bind_count > 0) - { - const GskGLCommandBind *bind = &self->batch_binds.items[batch->draw.bind_offset]; - - g_assert (bind->texture < G_N_ELEMENTS (textures)); - for (guint i = 0; i < batch->draw.bind_count; i++) - { - if (textures[bind->texture] != bind->id) - { - GskGLSync *s; - - if (active != bind->texture) - { - active = bind->texture; - glActiveTexture (GL_TEXTURE0 + bind->texture); - } - - s = gsk_gl_syncs_get_sync (&self->syncs, bind->id); - if (s && s->sync) - { - glWaitSync ((GLsync) s->sync, 0, GL_TIMEOUT_IGNORED); - s->sync = NULL; - } - - if (bind->sampler == SAMPLER_EXTERNAL) - glBindTexture (GL_TEXTURE_EXTERNAL_OES, bind->id); - else - glBindTexture (GL_TEXTURE_2D, bind->id); - textures[bind->texture] = bind->id; - if (!self->has_samplers) - { - if (bind->sampler == SAMPLER_EXTERNAL) - { - glTexParameteri (GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri (GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } - else - { - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter_from_index (bind->sampler / GSK_GL_N_FILTERS)); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter_from_index (bind->sampler % GSK_GL_N_FILTERS)); - } - } - } - - if (samplers[bind->texture] != bind->sampler) - { - if (self->has_samplers) - glBindSampler (bind->texture, self->samplers[bind->sampler]); - else - { - if (bind->sampler == SAMPLER_EXTERNAL) - { - glTexParameteri (GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri (GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } - else - { - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter_from_index (bind->sampler / GSK_GL_N_FILTERS)); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter_from_index (bind->sampler % GSK_GL_N_FILTERS)); - } - } - samplers[bind->texture] = bind->sampler; - } - - bind++; - } - - n_binds += batch->draw.bind_count; - } - - if (batch->draw.uniform_count > 0) - { - const GskGLCommandUniform *u = &self->batch_uniforms.items[batch->draw.uniform_offset]; - - for (guint i = 0; i < batch->draw.uniform_count; i++, u++) - gsk_gl_uniform_state_apply (self->uniforms, program, u->location, u->info); - - n_uniforms += batch->draw.uniform_count; - } - - if (batch->draw.blend == 0) - glDisable (GL_BLEND); - - glDrawArrays (GL_TRIANGLES, batch->draw.vbo_offset, batch->draw.vbo_count); - - if (batch->draw.blend == 0) - glEnable (GL_BLEND); - break; - - default: - g_assert_not_reached (); - } - -#if 0 - if (batch->any.kind == GSK_GL_COMMAND_KIND_DRAW || - batch->any.kind == GSK_GL_COMMAND_KIND_CLEAR) - { - char filename[128]; - g_snprintf (filename, sizeof filename, - "capture%03u_batch%03d_kind%u_program%u_u%u_b%u_fb%u_ctx%p.png", - count, next_batch_index, - batch->any.kind, batch->any.program, - batch->any.kind == GSK_GL_COMMAND_KIND_DRAW ? batch->draw.uniform_count : 0, - batch->any.kind == GSK_GL_COMMAND_KIND_DRAW ? batch->draw.bind_count : 0, - framebuffer, - gdk_gl_context_get_current ()); - gsk_gl_command_queue_capture_png (self, filename, width, height, TRUE); - gsk_gl_command_queue_print_batch (self, batch); - } -#endif - - next_batch_index = batch->any.next_batch_index; - } - - glDeleteBuffers (1, &vbo_id); - if (gdk_gl_context_has_vertex_arrays (self->context)) - glDeleteVertexArrays (1, &vao_id); - - gdk_profiler_set_int_counter (self->metrics.n_binds, n_binds); - gdk_profiler_set_int_counter (self->metrics.n_uniforms, n_uniforms); - gdk_profiler_set_int_counter (self->metrics.n_fbos, n_fbos); - gdk_profiler_set_int_counter (self->metrics.n_programs, n_programs); - gdk_profiler_set_int_counter (self->metrics.n_uploads, self->n_uploads); - gdk_profiler_set_int_counter (self->metrics.queue_depth, self->batches.len); - - { - gint64 start_time G_GNUC_UNUSED = gsk_profiler_timer_get_start (self->profiler, self->metrics.cpu_time); - gint64 cpu_time = gsk_profiler_timer_end (self->profiler, self->metrics.cpu_time); - gint64 gpu_time = gsk_gl_profiler_end_gpu_region (self->gl_profiler); - - gsk_profiler_timer_set (self->profiler, self->metrics.gpu_time, gpu_time); - gsk_profiler_timer_set (self->profiler, self->metrics.cpu_time, cpu_time); - gsk_profiler_counter_inc (self->profiler, self->metrics.n_frames); - - gsk_profiler_push_samples (self->profiler); - } -} - -void -gsk_gl_command_queue_begin_frame (GskGLCommandQueue *self) -{ - g_assert (GSK_IS_GL_COMMAND_QUEUE (self)); - g_assert (self->batches.len == 0); - - gsk_gl_command_queue_make_current (self); - - self->fbo_max = 0; - self->tail_batch_index = -1; - self->head_batch_index = -1; - self->in_frame = TRUE; -} - -/** - * gsk_gl_command_queue_end_frame: - * @self: a `GskGLCommandQueue` - * - * This function performs cleanup steps that need to be done after - * a frame has finished. This is not performed as part of the command - * queue execution to allow for the frame to be submitted as soon - * as possible. - * - * However, it should be executed after the draw contexts end_frame - * has been called to swap the OpenGL framebuffers. - */ -void -gsk_gl_command_queue_end_frame (GskGLCommandQueue *self) -{ - g_assert (GSK_IS_GL_COMMAND_QUEUE (self)); - - gsk_gl_command_queue_make_current (self); - gsk_gl_uniform_state_end_frame (self->uniforms); - - /* Reset attachments so we don't hold on to any textures - * that might be released after the frame. - */ - for (guint i = 0; i < G_N_ELEMENTS (self->attachments->textures); i++) - { - if (self->attachments->textures[i].id != 0) - { - glActiveTexture (GL_TEXTURE0 + i); - glBindTexture (self->attachments->textures[i].target, 0); - - self->attachments->textures[i].id = 0; - self->attachments->textures[i].changed = FALSE; - self->attachments->textures[i].initial = TRUE; - } - } - - self->batches.len = 0; - self->batch_binds.len = 0; - self->batch_uniforms.len = 0; - self->syncs.len = 0; - self->n_uploads = 0; - self->tail_batch_index = -1; - self->in_frame = FALSE; -} - -gboolean -gsk_gl_command_queue_create_render_target (GskGLCommandQueue *self, - int width, - int height, - int format, - guint *out_fbo_id, - guint *out_texture_id) -{ - GLuint fbo_id = 0; - GLint texture_id; - - g_assert (GSK_IS_GL_COMMAND_QUEUE (self)); - g_assert (width > 0); - g_assert (height > 0); - g_assert (out_fbo_id != NULL); - g_assert (out_texture_id != NULL); - - texture_id = gsk_gl_command_queue_create_texture (self, - width, height, - format); - - if (texture_id == -1) - { - *out_fbo_id = 0; - *out_texture_id = 0; - return FALSE; - } - - fbo_id = gsk_gl_command_queue_create_framebuffer (self); - - glBindFramebuffer (GL_FRAMEBUFFER, fbo_id); - glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_id, 0); - g_assert_cmphex (glCheckFramebufferStatus (GL_FRAMEBUFFER), ==, GL_FRAMEBUFFER_COMPLETE); - - *out_fbo_id = fbo_id; - *out_texture_id = texture_id; - - return TRUE; -} - -int -gsk_gl_command_queue_create_texture (GskGLCommandQueue *self, - int width, - int height, - int format) -{ - GLuint texture_id = 0; - - g_assert (GSK_IS_GL_COMMAND_QUEUE (self)); - - if G_UNLIKELY (self->max_texture_size == -1) - glGetIntegerv (GL_MAX_TEXTURE_SIZE, &self->max_texture_size); - - if (width > self->max_texture_size || height > self->max_texture_size) - return -1; - - glGenTextures (1, &texture_id); - - glActiveTexture (GL_TEXTURE0); - glBindTexture (GL_TEXTURE_2D, texture_id); - - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - switch (format) - { - case 0: - break; - case GL_RGBA8: - glTexImage2D (GL_TEXTURE_2D, 0, format, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - break; - case GL_RGBA16F: - glTexImage2D (GL_TEXTURE_2D, 0, format, width, height, 0, GL_RGBA, GL_HALF_FLOAT, NULL); - break; - case GL_RGBA32F: - glTexImage2D (GL_TEXTURE_2D, 0, format, width, height, 0, GL_RGBA, GL_FLOAT, NULL); - break; - default: - /* If you add new formats, make sure to set the correct format and type here - * so that GLES doesn't barf invalid operations at you. - * Because it is very important that these 3 values match when data is set to - * NULL, do you hear me? - */ - g_assert_not_reached (); - break; - } - - /* Restore the previous texture if it was set */ - if (self->attachments->textures[0].id != 0 && - self->attachments->textures[0].target == GL_TEXTURE_2D) - glBindTexture (self->attachments->textures[0].target, self->attachments->textures[0].id); - - return (int)texture_id; -} - -guint -gsk_gl_command_queue_create_framebuffer (GskGLCommandQueue *self) -{ - GLuint fbo_id; - - g_assert (GSK_IS_GL_COMMAND_QUEUE (self)); - - glGenFramebuffers (1, &fbo_id); - - return fbo_id; -} - -static GdkMemoryFormat -memory_format_gl_format (GskGLCommandQueue *self, - GdkMemoryFormat data_format, - gboolean ensure_mipmap, - gboolean *out_can_mipmap, - GLint *gl_internalformat, - GLint *gl_internalsrgbformat, - GLenum *gl_format, - GLenum *gl_type, - GLint gl_swizzle[4]) -{ - GdkGLMemoryFlags flags, required_flags; - GdkMemoryFormat alt_format; - const GdkMemoryFormat *fallbacks; - gsize i; - - /* No support for straight formats yet */ - if (gdk_memory_format_alpha (data_format) == GDK_MEMORY_ALPHA_STRAIGHT) - data_format = gdk_memory_format_get_premultiplied (data_format); - - required_flags = GDK_GL_FORMAT_USABLE | GDK_GL_FORMAT_FILTERABLE; - if (ensure_mipmap) - required_flags |= GDK_GL_FORMAT_RENDERABLE; - - /* First, try the format itself */ - flags = gdk_gl_context_get_format_flags (self->context, data_format); - if ((flags & required_flags) == required_flags) - { - gdk_memory_format_gl_format (data_format, - gdk_gl_context_get_use_es (self->context), - gl_internalformat, - gl_internalsrgbformat, - gl_format, - gl_type, - gl_swizzle); - *out_can_mipmap = (flags & GDK_GL_FORMAT_RENDERABLE) ? TRUE : FALSE; - return data_format; - } - - /* Second, try the potential RGBA format */ - if (gdk_memory_format_gl_rgba_format (data_format, - gdk_gl_context_get_use_es (self->context), - &alt_format, - gl_internalformat, - gl_internalsrgbformat, - gl_format, - gl_type, - gl_swizzle)) - { - flags = gdk_gl_context_get_format_flags (self->context, alt_format); - if ((flags & required_flags) == required_flags) - { - *out_can_mipmap = (flags & GDK_GL_FORMAT_RENDERABLE) ? TRUE : FALSE; - - if (self->can_swizzle) - return data_format; - - gdk_memory_format_gl_format (alt_format, - gdk_gl_context_get_use_es (self->context), - gl_internalformat, - gl_internalsrgbformat, - gl_format, - gl_type, - gl_swizzle); - - return alt_format; - } - } - - /* Next, try the fallbacks */ - fallbacks = gdk_memory_format_get_fallbacks (data_format); - for (i = 0; fallbacks[i] != -1; i++) - { - flags = gdk_gl_context_get_format_flags (self->context, fallbacks[i]); - if (((flags & required_flags) == required_flags)) - { - gdk_memory_format_gl_format (fallbacks[i], - gdk_gl_context_get_use_es (self->context), - gl_internalformat, - gl_internalsrgbformat, - gl_format, - gl_type, - gl_swizzle); - - *out_can_mipmap = (flags & GDK_GL_FORMAT_RENDERABLE) ? TRUE : FALSE; - return fallbacks[i]; - } - } - - g_assert_not_reached (); - - return GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; -} - -static void -gsk_gl_command_queue_do_upload_texture_chunk (GskGLCommandQueue *self, - GdkTexture *texture, - int x, - int y, - GdkMemoryFormat data_format, - GLenum gl_format, - GLenum gl_type, - GLint gl_swizzle[4]) - -{ - G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME; - const guchar *data; - gsize stride; - GBytes *bytes; - GdkTextureDownloader downloader; - int width, height; - gsize bpp; - - width = gdk_texture_get_width (texture); - height = gdk_texture_get_height (texture); - - if (GSK_DEBUG_CHECK (FALLBACK) && - data_format != gdk_texture_get_format (texture)) - { - GEnumClass *enum_class = g_type_class_ref (GDK_TYPE_MEMORY_FORMAT); - - gdk_debug_message ("Unsupported format %s, converting on CPU to %s", - g_enum_get_value (enum_class, gdk_texture_get_format (texture))->value_nick, - g_enum_get_value (enum_class, data_format)->value_nick); - - g_type_class_unref (enum_class); - } - - gdk_texture_downloader_init (&downloader, texture); - gdk_texture_downloader_set_format (&downloader, data_format); - bytes = gdk_texture_downloader_download_bytes (&downloader, &stride); - gdk_texture_downloader_finish (&downloader); - data = g_bytes_get_data (bytes, NULL); - bpp = gdk_memory_format_bytes_per_pixel (data_format); - - if (gdk_profiler_is_running ()) - { - gdk_profiler_end_markf (start_time, - "Download texture chunk", - "Tile %dx%d Size %dx%d", x, y, width, height); - start_time = GDK_PROFILER_CURRENT_TIME; - } - - glPixelStorei (GL_UNPACK_ALIGNMENT, gdk_memory_format_alignment (data_format)); - - /* GL_UNPACK_ROW_LENGTH is available on desktop GL, OpenGL ES >= 3.0, or if - * the GL_EXT_unpack_subimage extension for OpenGL ES 2.0 is available - */ - if (stride == width * bpp) - { - glTexSubImage2D (GL_TEXTURE_2D, 0, x, y, width, height, gl_format, gl_type, data); - } - else if (stride % bpp == 0) - { - glPixelStorei (GL_UNPACK_ROW_LENGTH, stride / bpp); - - glTexSubImage2D (GL_TEXTURE_2D, 0, x, y, width, height, gl_format, gl_type, data); - - glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); - } - else - { - for (int i = 0; i < height; i++) - glTexSubImage2D (GL_TEXTURE_2D, 0, x, y + i, width, 1, gl_format, gl_type, data + (i * stride)); - } - - glPixelStorei (GL_UNPACK_ALIGNMENT, 4); - - /* Only apply swizzle if really needed, might not even be - * supported if default values are set - */ - if (gl_swizzle[0] != GL_RED || gl_swizzle[1] != GL_GREEN || gl_swizzle[2] != GL_BLUE || gl_swizzle[3] != GL_ALPHA) - { - /* Set each channel independently since GLES 3.0 doesn't support the iv method */ - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, gl_swizzle[0]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, gl_swizzle[1]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, gl_swizzle[2]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, gl_swizzle[3]); - } - - g_bytes_unref (bytes); - - if (gdk_profiler_is_running ()) - gdk_profiler_end_markf (start_time, - "Upload texture chunk", - "Tile %dx%d Size %dx%d", x, y, width, height); -} - -int -gsk_gl_command_queue_upload_texture_chunks (GskGLCommandQueue *self, - gboolean ensure_mipmap, - unsigned int n_chunks, - GskGLTextureChunk *chunks, - gboolean *out_can_mipmap) -{ - G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME; - int width, height; - GdkMemoryFormat data_format; - GLint gl_internalformat, gl_internalsrgbformat; - GLenum gl_format; - GLenum gl_type; - GLint gl_swizzle[4]; - int texture_id; - - g_assert (GSK_IS_GL_COMMAND_QUEUE (self)); - - width = height = 0; - for (unsigned int i = 0; i < n_chunks; i++) - { - GskGLTextureChunk *c = &chunks[i]; - - width = MAX (width, c->x + gdk_texture_get_width (c->texture)); - height = MAX (height, c->y + gdk_texture_get_height (c->texture)); - } - - if (width > self->max_texture_size || height > self->max_texture_size) - { - g_warning ("Attempt to create texture of size %ux%u but max size is %d. " - "Clipping will occur.", - width, height, self->max_texture_size); - width = MIN (width, self->max_texture_size); - height = MIN (height, self->max_texture_size); - } - - texture_id = gsk_gl_command_queue_create_texture (self, width, height, 0); - if (texture_id == -1) - return texture_id; - - self->n_uploads++; - - /* Switch to texture0 as 2D. We'll restore it later. */ - glActiveTexture (GL_TEXTURE0); - glBindTexture (GL_TEXTURE_2D, texture_id); - - /* Initialize the texture */ - data_format = gdk_texture_get_format (chunks[0].texture); - data_format = memory_format_gl_format (self, - data_format, - ensure_mipmap, - out_can_mipmap, - &gl_internalformat, - &gl_internalsrgbformat, - &gl_format, - &gl_type, - gl_swizzle); - - glTexImage2D (GL_TEXTURE_2D, 0, gl_internalformat, width, height, 0, gl_format, gl_type, NULL); - - for (unsigned int i = 0; i < n_chunks; i++) - { - GskGLTextureChunk *c = &chunks[i]; - gsk_gl_command_queue_do_upload_texture_chunk (self, c->texture, c->x, c->y, data_format, gl_format, gl_type, gl_swizzle); - } - - /* Restore previous texture state if any */ - if (self->attachments->textures[0].id > 0) - glBindTexture (self->attachments->textures[0].target, - self->attachments->textures[0].id); - - if (gdk_profiler_is_running ()) - gdk_profiler_add_markf (start_time, GDK_PROFILER_CURRENT_TIME-start_time, - "Upload Texture", - "Size %dx%d", width, height); - - return texture_id; -} - -int -gsk_gl_command_queue_upload_texture (GskGLCommandQueue *self, - GdkTexture *texture, - gboolean ensure_mipmap, - gboolean *out_can_mipmap) -{ - return gsk_gl_command_queue_upload_texture_chunks (self, - ensure_mipmap, - 1, - &(GskGLTextureChunk){ texture, 0, 0}, - out_can_mipmap); -} - -void -gsk_gl_command_queue_set_profiler (GskGLCommandQueue *self, - GskProfiler *profiler) -{ - g_assert (GSK_IS_GL_COMMAND_QUEUE (self)); - g_assert (GSK_IS_PROFILER (profiler)); - - if (g_set_object (&self->profiler, profiler)) - { - self->gl_profiler = gsk_gl_profiler_new (self->context); - - self->metrics.n_frames = gsk_profiler_add_counter (profiler, "frames", "Frames", FALSE); - self->metrics.cpu_time = gsk_profiler_add_timer (profiler, "cpu-time", "CPU Time", FALSE, TRUE); - self->metrics.gpu_time = gsk_profiler_add_timer (profiler, "gpu-time", "GPU Time", FALSE, TRUE); - - self->metrics.n_binds = gdk_profiler_define_int_counter ("attachments", "Number of texture attachments"); - self->metrics.n_fbos = gdk_profiler_define_int_counter ("fbos", "Number of framebuffers attached"); - self->metrics.n_uniforms = gdk_profiler_define_int_counter ("uniforms", "Number of uniforms changed"); - self->metrics.n_uploads = gdk_profiler_define_int_counter ("uploads", "Number of texture uploads"); - self->metrics.n_programs = gdk_profiler_define_int_counter ("programs", "Number of program changes"); - self->metrics.queue_depth = gdk_profiler_define_int_counter ("gl-queue-depth", "Depth of GL command batches"); - } -} diff --git a/gsk/gl/gskglcommandqueueprivate.h b/gsk/gl/gskglcommandqueueprivate.h deleted file mode 100644 index f9100a69b56356ba81bf00e3e4b2133d4e852c18..0000000000000000000000000000000000000000 --- a/gsk/gl/gskglcommandqueueprivate.h +++ /dev/null @@ -1,431 +0,0 @@ -/* gskglcommandqueueprivate.h - * - * Copyright 2020 Christian Hergert - * - * 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 . - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#pragma once - -#include - -#include "gskgltypesprivate.h" -#include "gskglbufferprivate.h" -#include "gskglattachmentstateprivate.h" -#include "gskgluniformstateprivate.h" - -#include "inlinearray.h" - -#include "gskglprofilerprivate.h" - -G_BEGIN_DECLS - -#define GSK_TYPE_GL_COMMAND_QUEUE (gsk_gl_command_queue_get_type()) - -G_DECLARE_FINAL_TYPE (GskGLCommandQueue, gsk_gl_command_queue, GSK, GL_COMMAND_QUEUE, GObject) - -typedef enum _GskGLCommandKind -{ - /* The batch will perform a glClear() */ - GSK_GL_COMMAND_KIND_CLEAR, - - /* The batch will perform a glDrawArrays() */ - GSK_GL_COMMAND_KIND_DRAW, -} GskGLCommandKind; - -typedef struct _GskGLCommandBind -{ - /* @texture is the value passed to glActiveTexture(), the "slot" the - * texture will be placed into. We always use GL_TEXTURE_2D so we don't - * waste any bits here to indicate that. - */ - guint texture : 4; - - /* the sampler to use. We set sampler to 15 to indicate external textures */ - guint sampler : 4; - - /* The identifier for the texture created with glGenTextures(). */ - guint id: 24; -} GskGLCommandBind; - -G_STATIC_ASSERT (sizeof (GskGLCommandBind) == 4); - -typedef struct _GskGLCommandBatchAny -{ - /* A GskGLCommandKind indicating what the batch will do */ - guint kind : 8; - - /* The program's identifier to use for determining if we can merge two - * batches together into a single set of draw operations. We put this - * here instead of the GskGLCommandDraw so that we can use the extra - * bits here without making the structure larger. - */ - guint program : 24; - - /* The index of the next batch following this one. This is used - * as a sort of integer-based linked list to simplify out-of-order - * batching without moving memory around. -1 indicates last batch. - */ - gint16 next_batch_index; - - /* Same but for reverse direction as we sort in reverse to get the - * batches ordered by framebuffer. - */ - gint16 prev_batch_index; - - /* The viewport size of the batch. We check this as we process - * batches to determine if we need to resize the viewport. - */ - struct { - guint16 width; - guint16 height; - } viewport; -} GskGLCommandBatchAny; - -G_STATIC_ASSERT (sizeof (GskGLCommandBatchAny) == 12); - -typedef struct _GskGLCommandDraw -{ - GskGLCommandBatchAny head; - - guint blend : 1; - - /* There doesn't seem to be a limit on the framebuffer identifier that - * can be returned, so we have to use a whole unsigned for the framebuffer - * we are drawing to. When processing batches, we check to see if this - * changes and adjust the render target accordingly. Some sorting is - * performed to reduce the amount we change framebuffers. - */ - guint framebuffer : 31; - - /* The number of uniforms to change. This must be less than or equal to - * GL_MAX_UNIFORM_LOCATIONS but only guaranteed up to 1024 by any OpenGL - * implementation to be conformant. - */ - guint uniform_count : 11; - - /* The number of textures to bind, which is only guaranteed up to 16 - * by the OpenGL specification to be conformant. - */ - guint bind_count : 5; - - /* GL_MAX_ELEMENTS_VERTICES specifies 33000 for this which requires 16-bit - * to address all possible counts <= GL_MAX_ELEMENTS_VERTICES. - */ - guint vbo_count : 16; - - /* The offset within the VBO containing @vbo_count vertices to send with - * glDrawArrays(). - */ - guint vbo_offset; - - /* The offset within the array of uniform changes to be made containing - * @uniform_count `GskGLCommandUniform` elements to apply. - */ - guint uniform_offset; - - /* The offset within the array of bind changes to be made containing - * @bind_count `GskGLCommandBind` elements to apply. - */ - guint bind_offset; -} GskGLCommandDraw; - -G_STATIC_ASSERT (sizeof (GskGLCommandDraw) == 32); - -typedef struct _GskGLCommandClear -{ - GskGLCommandBatchAny any; - guint bits; - guint framebuffer; -} GskGLCommandClear; - -G_STATIC_ASSERT (sizeof (GskGLCommandClear) == 20); - -typedef struct _GskGLCommandUniform -{ - GskGLUniformInfo info; - guint location; -} GskGLCommandUniform; - -G_STATIC_ASSERT (sizeof (GskGLCommandUniform) == 8); - -typedef union _GskGLCommandBatch -{ - GskGLCommandBatchAny any; - GskGLCommandDraw draw; - GskGLCommandClear clear; -} GskGLCommandBatch; - -G_STATIC_ASSERT (sizeof (GskGLCommandBatch) == 32); - -typedef struct _GskGLSync { - guint id; - gpointer sync; -} GskGLSync; - -DEFINE_INLINE_ARRAY (GskGLCommandBatches, gsk_gl_command_batches, GskGLCommandBatch) -DEFINE_INLINE_ARRAY (GskGLCommandBinds, gsk_gl_command_binds, GskGLCommandBind) -DEFINE_INLINE_ARRAY (GskGLCommandUniforms, gsk_gl_command_uniforms, GskGLCommandUniform) -DEFINE_INLINE_ARRAY (GskGLSyncs, gsk_gl_syncs, GskGLSync) - -struct _GskGLCommandQueue -{ - GObject parent_instance; - - /* The GdkGLContext we make current before executing GL commands. */ - GdkGLContext *context; - - /* Array of GskGLCommandBatch which is a fixed size structure that will - * point into offsets of other arrays so that all similar data is stored - * together. The idea here is that we reduce the need for pointers so that - * using g_realloc()'d arrays is fine. - */ - GskGLCommandBatches batches; - - /* Contains array of vertices and some wrapper code to help upload them - * to the GL driver. We can also tweak this to use double buffered arrays - * if we find that to be faster on some hardware and/or drivers. - */ - GskGLBuffer vertices; - - /* The GskGLAttachmentState contains information about our FBO and texture - * attachments as we process incoming operations. We snapshot them into - * various batches so that we can compare differences between merge - * candidates. - */ - GskGLAttachmentState *attachments; - - /* The uniform state across all programs. We snapshot this into batches so - * that we can compare uniform state between batches to give us more - * chances at merging draw commands. - */ - GskGLUniformState *uniforms; - - /* Current program if we are in a draw so that we can send commands - * to the uniform state as needed. - */ - GskGLUniformProgram *program_info; - - /* The profiler instance to deliver timing/etc data */ - GskProfiler *profiler; - GskGLProfiler *gl_profiler; - - /* Array of GskGLCommandBind which denote what textures need to be attached - * to which slot. GskGLCommandDraw.bind_offset and bind_count reference this - * array to determine what to attach. - */ - GskGLCommandBinds batch_binds; - - /* Array of GskGLCommandUniform denoting which uniforms must be updated - * before the glDrawArrays() may be called. These are referenced from the - * GskGLCommandDraw.uniform_offset and uniform_count fields. - */ - GskGLCommandUniforms batch_uniforms; - - /* Array of samplers that we use for mag/min filter handling. It is indexed - * by the sampler_index() function. - * - * Note that when samplers are not supported (hello GLES), we fall back to - * setting the texture filter, but that needs to be done for every texture. - * - * Also note that we don't use all of these samplers since some combinations - * are invalid. An index of SAMPLER_EXTERNAL is used to indicate an external - * texture, which needs special sampler treatment. - */ - GLuint samplers[GSK_GL_N_FILTERS * GSK_GL_N_FILTERS]; - - /* Array of sync objects to wait on. - */ - GskGLSyncs syncs; - - /* Discovered max texture size when loading the command queue so that we - * can either scale down or slice textures to fit within this size. Assumed - * to be both height and width. - */ - int max_texture_size; - - /* The index of the last batch in @batches, which may not be the element - * at the end of the array, as batches can be reordered. This is used to - * update the "next" index when adding a new batch. - */ - gint16 tail_batch_index; - gint16 head_batch_index; - - /* Max framebuffer we used, so we can sort items faster */ - guint fbo_max; - - /* Various GSK and GDK metric counter ids */ - struct { - GQuark n_frames; - GQuark cpu_time; - GQuark gpu_time; - guint n_binds; - guint n_fbos; - guint n_uniforms; - guint n_uploads; - guint n_programs; - guint queue_depth; - } metrics; - - /* Counter for uploads on the frame */ - guint n_uploads; - - /* If the GL context is new enough for sampler support */ - guint has_samplers : 1; - - /* If the GL context is new enough to support swizzling (ie is not GLES2) */ - guint can_swizzle : 1; - - /* If we're inside a begin/end_frame pair */ - guint in_frame : 1; - - /* If we're inside of a begin_draw()/end_draw() pair. */ - guint in_draw : 1; - - /* If we've warned about truncating batches */ - guint have_truncated : 1; -}; - -GskGLCommandQueue *gsk_gl_command_queue_new (GdkGLContext *context, - GskGLUniformState *uniforms); -void gsk_gl_command_queue_set_profiler (GskGLCommandQueue *self, - GskProfiler *profiler); -GdkGLContext *gsk_gl_command_queue_get_context (GskGLCommandQueue *self); -void gsk_gl_command_queue_make_current (GskGLCommandQueue *self); -void gsk_gl_command_queue_begin_frame (GskGLCommandQueue *self); -void gsk_gl_command_queue_end_frame (GskGLCommandQueue *self); -void gsk_gl_command_queue_execute (GskGLCommandQueue *self, - guint surface_height, - float scale, - const cairo_region_t *scissor, - guint default_framebuffer); -int gsk_gl_command_queue_upload_texture (GskGLCommandQueue *self, - GdkTexture *texture, - gboolean ensure_mipmap, - gboolean *out_can_mipmap); -int gsk_gl_command_queue_create_texture (GskGLCommandQueue *self, - int width, - int height, - int format); - - -typedef struct { - GdkTexture *texture; - int x; - int y; -} GskGLTextureChunk; - -int gsk_gl_command_queue_upload_texture_chunks(GskGLCommandQueue *self, - gboolean ensure_mipmap, - unsigned int n_chunks, - GskGLTextureChunk *chunks, - gboolean *out_can_mipmap); - -guint gsk_gl_command_queue_create_framebuffer (GskGLCommandQueue *self); -gboolean gsk_gl_command_queue_create_render_target (GskGLCommandQueue *self, - int width, - int height, - int format, - guint *out_fbo_id, - guint *out_texture_id); -void gsk_gl_command_queue_delete_program (GskGLCommandQueue *self, - guint program_id); -void gsk_gl_command_queue_clear (GskGLCommandQueue *self, - guint clear_bits, - const graphene_rect_t *viewport); -gboolean gsk_gl_command_queue_begin_draw (GskGLCommandQueue *self, - GskGLUniformProgram *program_info, - guint width, - guint height); -void gsk_gl_command_queue_end_draw (GskGLCommandQueue *self); -void gsk_gl_command_queue_split_draw (GskGLCommandQueue *self); - -static inline GskGLCommandBatch * -gsk_gl_command_queue_get_batch (GskGLCommandQueue *self) -{ - return gsk_gl_command_batches_tail (&self->batches); -} - -static inline GskGLDrawVertex * -gsk_gl_command_queue_add_vertices (GskGLCommandQueue *self) -{ - gsk_gl_command_queue_get_batch (self)->draw.vbo_count += GSK_GL_N_VERTICES; - return gsk_gl_buffer_advance (&self->vertices, GSK_GL_N_VERTICES); -} - -static inline GskGLDrawVertex * -gsk_gl_command_queue_add_n_vertices (GskGLCommandQueue *self, - guint count) -{ - /* This is a batch form of gsk_gl_command_queue_add_vertices(). Note that - * it does *not* add the count to .draw.vbo_count as the caller is responsible - * for that. - */ - return gsk_gl_buffer_advance (&self->vertices, GSK_GL_N_VERTICES * count); -} - -static inline void -gsk_gl_command_queue_retract_n_vertices (GskGLCommandQueue *self, - guint count) -{ - /* Like gsk_gl_command_queue_add_n_vertices(), this does not tweak - * the draw vbo_count. - */ - gsk_gl_buffer_retract (&self->vertices, GSK_GL_N_VERTICES * count); -} - -static inline guint -gsk_gl_command_queue_bind_framebuffer (GskGLCommandQueue *self, - guint framebuffer) -{ - guint ret = self->attachments->fbo.id; - gsk_gl_attachment_state_bind_framebuffer (self->attachments, framebuffer); - return ret; -} - -static inline GskGLSync * -gsk_gl_syncs_get_sync (GskGLSyncs *syncs, - guint id) -{ - for (unsigned int i = 0; i < syncs->len; i++) - { - GskGLSync *sync = &syncs->items[i]; - if (sync->id == id) - return sync; - } - return NULL; -} - -static inline void -gsk_gl_syncs_add_sync (GskGLSyncs *syncs, - guint id, - gpointer sync) -{ - GskGLSync *s; - - s = gsk_gl_syncs_get_sync (syncs, id); - if (s) - g_assert (s->sync == sync); - else - { - s = gsk_gl_syncs_append (syncs); - s->id = id; - s->sync = sync; - } -} - -G_END_DECLS - diff --git a/gsk/gl/gskglcompiler.c b/gsk/gl/gskglcompiler.c deleted file mode 100644 index 74b42a18aa6a79118e92e2b70e89007c01402416..0000000000000000000000000000000000000000 --- a/gsk/gl/gskglcompiler.c +++ /dev/null @@ -1,703 +0,0 @@ -/* gskglcompiler.c - * - * Copyright 2020 Christian Hergert - * - * 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 . - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#include "config.h" - -#include -#include -#include - -#include "gskglcommandqueueprivate.h" -#include "gskglcompilerprivate.h" -#include "gskglprogramprivate.h" - -#define SHADER_VERSION_GLES "100" -#define SHADER_VERSION_GLES3 "300 es" -#define SHADER_VERSION_GL2_LEGACY "110" -#define SHADER_VERSION_GL3_LEGACY "130" -#define SHADER_VERSION_GL3 "150" - -struct _GskGLCompiler -{ - GObject parent_instance; - - GskGLDriver *driver; - - GBytes *all_preamble; - GBytes *fragment_preamble; - GBytes *vertex_preamble; - GBytes *fragment_source; - GBytes *fragment_suffix; - GBytes *vertex_source; - GBytes *vertex_suffix; - - GArray *attrib_locations; - - const char *glsl_version; - - guint gl3 : 1; - guint gles : 1; - guint gles3 : 1; - guint legacy : 1; - guint debug_shaders : 1; -}; - -typedef struct _GskGLProgramAttrib -{ - const char *name; - guint location; -} GskGLProgramAttrib; - -static GBytes *empty_bytes; - -G_DEFINE_TYPE (GskGLCompiler, gsk_gl_compiler, G_TYPE_OBJECT) - -static void -gsk_gl_compiler_finalize (GObject *object) -{ - GskGLCompiler *self = (GskGLCompiler *)object; - - g_clear_pointer (&self->all_preamble, g_bytes_unref); - g_clear_pointer (&self->fragment_preamble, g_bytes_unref); - g_clear_pointer (&self->vertex_preamble, g_bytes_unref); - g_clear_pointer (&self->vertex_suffix, g_bytes_unref); - g_clear_pointer (&self->fragment_source, g_bytes_unref); - g_clear_pointer (&self->fragment_suffix, g_bytes_unref); - g_clear_pointer (&self->vertex_source, g_bytes_unref); - g_clear_pointer (&self->attrib_locations, g_array_unref); - g_clear_object (&self->driver); - - G_OBJECT_CLASS (gsk_gl_compiler_parent_class)->finalize (object); -} - -static void -gsk_gl_compiler_class_init (GskGLCompilerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = gsk_gl_compiler_finalize; - - empty_bytes = g_bytes_new (NULL, 0); -} - -static void -gsk_gl_compiler_init (GskGLCompiler *self) -{ - self->glsl_version = "150"; - self->attrib_locations = g_array_new (FALSE, FALSE, sizeof (GskGLProgramAttrib)); - self->all_preamble = g_bytes_ref (empty_bytes); - self->vertex_preamble = g_bytes_ref (empty_bytes); - self->fragment_preamble = g_bytes_ref (empty_bytes); - self->vertex_source = g_bytes_ref (empty_bytes); - self->vertex_suffix = g_bytes_ref (empty_bytes); - self->fragment_source = g_bytes_ref (empty_bytes); - self->fragment_suffix = g_bytes_ref (empty_bytes); -} - -GskGLCompiler * -gsk_gl_compiler_new (GskGLDriver *driver, - gboolean debug_shaders) -{ - GskGLCompiler *self; - GdkGLContext *context; - - g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), NULL); - g_return_val_if_fail (driver->shared_command_queue != NULL, NULL); - - self = g_object_new (GSK_TYPE_GL_COMPILER, NULL); - self->driver = g_object_ref (driver); - self->debug_shaders = !!debug_shaders; - - context = gsk_gl_driver_get_context (self->driver); - - if (gdk_gl_context_get_use_es (context)) - { - int maj, min; - - /* for OpenGL/ES 3.0+, use "300 es" as our shader version */ - gdk_gl_context_get_version (context, &maj, &min); - - if (maj >= 3) - { - self->glsl_version = SHADER_VERSION_GLES3; - self->gles3 = TRUE; - } - else - { - self->glsl_version = SHADER_VERSION_GLES; - self->gles = TRUE; - } - } - else if (gdk_gl_context_is_legacy (context)) - { - int maj, min; - - gdk_gl_context_get_version (context, &maj, &min); - - /* On Windows, legacy contexts can give us a GL 4.x context */ - if (maj >= 3) - self->glsl_version = SHADER_VERSION_GL3_LEGACY; - else - self->glsl_version = SHADER_VERSION_GL2_LEGACY; - - self->legacy = TRUE; - } - else - { - self->glsl_version = SHADER_VERSION_GL3; - self->gl3 = TRUE; - } - - gsk_gl_command_queue_make_current (self->driver->shared_command_queue); - - return g_steal_pointer (&self); -} - -void -gsk_gl_compiler_bind_attribute (GskGLCompiler *self, - const char *name, - guint location) -{ - GskGLProgramAttrib attrib; - - g_return_if_fail (GSK_IS_GL_COMPILER (self)); - g_return_if_fail (name != NULL); - g_return_if_fail (location < 32); - - attrib.name = g_intern_string (name); - attrib.location = location; - - g_array_append_val (self->attrib_locations, attrib); -} - -void -gsk_gl_compiler_clear_attributes (GskGLCompiler *self) -{ - g_return_if_fail (GSK_IS_GL_COMPILER (self)); - - g_array_set_size (self->attrib_locations, 0); -} - -void -gsk_gl_compiler_set_preamble (GskGLCompiler *self, - GskGLCompilerKind kind, - GBytes *preamble_bytes) -{ - GBytes **loc = NULL; - - g_return_if_fail (GSK_IS_GL_COMPILER (self)); - g_return_if_fail (preamble_bytes != NULL); - - if (kind == GSK_GL_COMPILER_ALL) - loc = &self->all_preamble; - else if (kind == GSK_GL_COMPILER_FRAGMENT) - loc = &self->fragment_preamble; - else if (kind == GSK_GL_COMPILER_VERTEX) - loc = &self->vertex_preamble; - else - g_return_if_reached (); - - g_assert (loc != NULL); - - if (*loc != preamble_bytes) - { - g_clear_pointer (loc, g_bytes_unref); - *loc = preamble_bytes ? g_bytes_ref (preamble_bytes) : NULL; - } -} - -void -gsk_gl_compiler_set_preamble_from_resource (GskGLCompiler *self, - GskGLCompilerKind kind, - const char *resource_path) -{ - GError *error = NULL; - GBytes *bytes; - - g_return_if_fail (GSK_IS_GL_COMPILER (self)); - g_return_if_fail (kind == GSK_GL_COMPILER_ALL || - kind == GSK_GL_COMPILER_VERTEX || - kind == GSK_GL_COMPILER_FRAGMENT); - g_return_if_fail (resource_path != NULL); - - bytes = g_resources_lookup_data (resource_path, - G_RESOURCE_LOOKUP_FLAGS_NONE, - &error); - - if (bytes == NULL) - g_warning ("Cannot set shader from resource: %s", error->message); - else - gsk_gl_compiler_set_preamble (self, kind, bytes); - - g_clear_pointer (&bytes, g_bytes_unref); - g_clear_error (&error); -} - -void -gsk_gl_compiler_set_source (GskGLCompiler *self, - GskGLCompilerKind kind, - GBytes *source_bytes) -{ - GBytes **loc = NULL; - - g_return_if_fail (GSK_IS_GL_COMPILER (self)); - g_return_if_fail (kind == GSK_GL_COMPILER_ALL || - kind == GSK_GL_COMPILER_VERTEX || - kind == GSK_GL_COMPILER_FRAGMENT); - - if (source_bytes == NULL) - source_bytes = empty_bytes; - - /* If kind is ALL, then we need to split the fragment and - * vertex shaders from the bytes and assign them individually. - * This safely scans for FRAGMENT_SHADER and VERTEX_SHADER as - * specified within the GLSL resources. Some care is taken to - * use GBytes which reference the original bytes instead of - * copying them. - */ - if (kind == GSK_GL_COMPILER_ALL) - { - gsize len = 0; - const char *source; - const char *vertex_shader_start; - const char *fragment_shader_start; - const char *endpos; - GBytes *fragment_bytes; - GBytes *vertex_bytes; - - g_clear_pointer (&self->fragment_source, g_bytes_unref); - g_clear_pointer (&self->vertex_source, g_bytes_unref); - - source = g_bytes_get_data (source_bytes, &len); - endpos = source + len; - vertex_shader_start = g_strstr_len (source, len, "VERTEX_SHADER"); - fragment_shader_start = g_strstr_len (source, len, "FRAGMENT_SHADER"); - - if (vertex_shader_start == NULL) - { - g_warning ("Failed to locate VERTEX_SHADER in shader source"); - return; - } - - if (fragment_shader_start == NULL) - { - g_warning ("Failed to locate FRAGMENT_SHADER in shader source"); - return; - } - - if (vertex_shader_start > fragment_shader_start) - { - g_warning ("VERTEX_SHADER must come before FRAGMENT_SHADER"); - return; - } - - /* Locate next newlines */ - while (vertex_shader_start < endpos && vertex_shader_start[0] != '\n') - vertex_shader_start++; - while (fragment_shader_start < endpos && fragment_shader_start[0] != '\n') - fragment_shader_start++; - - vertex_bytes = g_bytes_new_from_bytes (source_bytes, - vertex_shader_start - source, - fragment_shader_start - vertex_shader_start); - fragment_bytes = g_bytes_new_from_bytes (source_bytes, - fragment_shader_start - source, - endpos - fragment_shader_start); - - gsk_gl_compiler_set_source (self, GSK_GL_COMPILER_VERTEX, vertex_bytes); - gsk_gl_compiler_set_source (self, GSK_GL_COMPILER_FRAGMENT, fragment_bytes); - - g_bytes_unref (fragment_bytes); - g_bytes_unref (vertex_bytes); - - return; - } - - if (kind == GSK_GL_COMPILER_FRAGMENT) - loc = &self->fragment_source; - else if (kind == GSK_GL_COMPILER_VERTEX) - loc = &self->vertex_source; - else - g_return_if_reached (); - - if (*loc != source_bytes) - { - g_clear_pointer (loc, g_bytes_unref); - *loc = g_bytes_ref (source_bytes); - } -} - -void -gsk_gl_compiler_set_source_from_resource (GskGLCompiler *self, - GskGLCompilerKind kind, - const char *resource_path) -{ - GError *error = NULL; - GBytes *bytes; - - g_return_if_fail (GSK_IS_GL_COMPILER (self)); - g_return_if_fail (kind == GSK_GL_COMPILER_ALL || - kind == GSK_GL_COMPILER_VERTEX || - kind == GSK_GL_COMPILER_FRAGMENT); - g_return_if_fail (resource_path != NULL); - - bytes = g_resources_lookup_data (resource_path, - G_RESOURCE_LOOKUP_FLAGS_NONE, - &error); - - if (bytes == NULL) - g_warning ("Cannot set shader from resource: %s", error->message); - else - gsk_gl_compiler_set_source (self, kind, bytes); - - g_clear_pointer (&bytes, g_bytes_unref); - g_clear_error (&error); -} - -void -gsk_gl_compiler_set_suffix (GskGLCompiler *self, - GskGLCompilerKind kind, - GBytes *suffix_bytes) -{ - GBytes **loc; - - g_return_if_fail (GSK_IS_GL_COMPILER (self)); - g_return_if_fail (kind == GSK_GL_COMPILER_VERTEX || - kind == GSK_GL_COMPILER_FRAGMENT); - g_return_if_fail (suffix_bytes != NULL); - - if (suffix_bytes == NULL) - suffix_bytes = empty_bytes; - - if (kind == GSK_GL_COMPILER_FRAGMENT) - loc = &self->fragment_suffix; - else if (kind == GSK_GL_COMPILER_VERTEX) - loc = &self->vertex_suffix; - else - g_return_if_reached (); - - if (*loc != suffix_bytes) - { - g_clear_pointer (loc, g_bytes_unref); - *loc = g_bytes_ref (suffix_bytes); - } -} - -void -gsk_gl_compiler_set_suffix_from_resource (GskGLCompiler *self, - GskGLCompilerKind kind, - const char *resource_path) -{ - GError *error = NULL; - GBytes *bytes; - - g_return_if_fail (GSK_IS_GL_COMPILER (self)); - g_return_if_fail (kind == GSK_GL_COMPILER_VERTEX || - kind == GSK_GL_COMPILER_FRAGMENT); - g_return_if_fail (resource_path != NULL); - - bytes = g_resources_lookup_data (resource_path, - G_RESOURCE_LOOKUP_FLAGS_NONE, - &error); - - if (bytes == NULL) - g_warning ("Cannot set suffix from resource: %s", error->message); - else - gsk_gl_compiler_set_suffix (self, kind, bytes); - - g_clear_pointer (&bytes, g_bytes_unref); - g_clear_error (&error); -} - -static void -prepend_line_numbers (char *code, - GString *s) -{ - char *p; - int line; - - p = code; - line = 1; - while (*p) - { - char *end = strchr (p, '\n'); - if (end) - end = end + 1; /* Include newline */ - else - end = p + strlen (p); - - g_string_append_printf (s, "%3d| ", line++); - g_string_append_len (s, p, end - p); - - p = end; - } -} - -static gboolean -check_shader_error (int shader_id, - GError **error) -{ - GLint status; - GLint log_len; - GLint code_len; - char *buffer; - char *code; - GString *s; - - glGetShaderiv (shader_id, GL_COMPILE_STATUS, &status); - - if G_LIKELY (status == GL_TRUE) - return TRUE; - - glGetShaderiv (shader_id, GL_INFO_LOG_LENGTH, &log_len); - buffer = g_malloc0 (log_len + 1); - glGetShaderInfoLog (shader_id, log_len, NULL, buffer); - - glGetShaderiv (shader_id, GL_SHADER_SOURCE_LENGTH, &code_len); - code = g_malloc0 (code_len + 1); - glGetShaderSource (shader_id, code_len, NULL, code); - - s = g_string_new (""); - prepend_line_numbers (code, s); - - g_set_error (error, - GDK_GL_ERROR, - GDK_GL_ERROR_COMPILATION_FAILED, - "Compilation failure in shader.\n" - "Source Code: %s\n" - "\n" - "Error Message:\n" - "%s\n" - "\n", - s->str, - buffer); - - g_string_free (s, TRUE); - g_free (buffer); - g_free (code); - - return FALSE; -} - -static void -print_shader_info (const char *prefix, - int shader_id, - const char *name) -{ - if (GSK_DEBUG_CHECK(SHADERS)) - { - int code_len; - - glGetShaderiv (shader_id, GL_SHADER_SOURCE_LENGTH, &code_len); - - if (code_len > 0) - { - char *code; - GString *s; - - code = g_malloc0 (code_len + 1); - glGetShaderSource (shader_id, code_len, NULL, code); - - s = g_string_new (NULL); - prepend_line_numbers (code, s); - - g_message ("%s %d, %s:\n%s", - prefix, shader_id, - name ? name : "unnamed", - s->str); - g_string_free (s, TRUE); - g_free (code); - } - } -} - -static const char * -get_shader_string (GBytes *bytes) -{ - /* 0 length bytes will give us NULL back */ - const char *str = g_bytes_get_data (bytes, NULL); - return str ? str : ""; -} - -GskGLProgram * -gsk_gl_compiler_compile (GskGLCompiler *self, - const char *name, - const char *clip, - GError **error) -{ - char version[32]; - const char *debug = ""; - const char *legacy = ""; - const char *gl3 = ""; - const char *gles = ""; - const char *gles3 = ""; - int program_id; - int vertex_id; - int fragment_id; - int status; - - g_return_val_if_fail (GSK_IS_GL_COMPILER (self), NULL); - g_return_val_if_fail (self->all_preamble != NULL, NULL); - g_return_val_if_fail (self->fragment_preamble != NULL, NULL); - g_return_val_if_fail (self->vertex_preamble != NULL, NULL); - g_return_val_if_fail (self->fragment_source != NULL, NULL); - g_return_val_if_fail (self->vertex_source != NULL, NULL); - g_return_val_if_fail (self->driver != NULL, NULL); - - gsk_gl_command_queue_make_current (self->driver->command_queue); - - g_snprintf (version, sizeof version, "#version %s\n", self->glsl_version); - - if (self->debug_shaders) - debug = "#define GSK_DEBUG 1\n"; - - if (self->legacy) - legacy = "#define GSK_LEGACY 1\n"; - - if (self->gles) - gles = "#define GSK_GLES 1\n"; - - if (self->gles3) - gles3 = "#define GSK_GLES3 1\n"; - - if (self->gl3) - gl3 = "#define GSK_GL3 1\n"; - - vertex_id = glCreateShader (GL_VERTEX_SHADER); - glShaderSource (vertex_id, - 11, - (const char *[]) { - version, debug, legacy, gl3, gles, gles3, clip, - get_shader_string (self->all_preamble), - get_shader_string (self->vertex_preamble), - get_shader_string (self->vertex_source), - get_shader_string (self->vertex_suffix), - }, - (int[]) { - strlen (version), - strlen (debug), - strlen (legacy), - strlen (gl3), - strlen (gles), - strlen (gles3), - strlen (clip), - g_bytes_get_size (self->all_preamble), - g_bytes_get_size (self->vertex_preamble), - g_bytes_get_size (self->vertex_source), - g_bytes_get_size (self->vertex_suffix), - }); - glCompileShader (vertex_id); - - if (!check_shader_error (vertex_id, error)) - { - glDeleteShader (vertex_id); - return NULL; - } - - print_shader_info ("Vertex shader", vertex_id, name); - - fragment_id = glCreateShader (GL_FRAGMENT_SHADER); - glShaderSource (fragment_id, - 11, - (const char *[]) { - version, debug, legacy, gl3, gles, gles3, clip, - get_shader_string (self->all_preamble), - get_shader_string (self->fragment_preamble), - get_shader_string (self->fragment_source), - get_shader_string (self->fragment_suffix), - }, - (int[]) { - strlen (version), - strlen (debug), - strlen (legacy), - strlen (gl3), - strlen (gles), - strlen (gles3), - strlen (clip), - g_bytes_get_size (self->all_preamble), - g_bytes_get_size (self->fragment_preamble), - g_bytes_get_size (self->fragment_source), - g_bytes_get_size (self->fragment_suffix), - }); - glCompileShader (fragment_id); - - if (!check_shader_error (fragment_id, error)) - { - glDeleteShader (vertex_id); - glDeleteShader (fragment_id); - return NULL; - } - - print_shader_info ("Fragment shader", fragment_id, name); - - program_id = glCreateProgram (); - glAttachShader (program_id, vertex_id); - glAttachShader (program_id, fragment_id); - - for (guint i = 0; i < self->attrib_locations->len; i++) - { - const GskGLProgramAttrib *attrib; - - attrib = &g_array_index (self->attrib_locations, GskGLProgramAttrib, i); - glBindAttribLocation (program_id, attrib->location, attrib->name); - } - - glLinkProgram (program_id); - - glGetProgramiv (program_id, GL_LINK_STATUS, &status); - - glDetachShader (program_id, vertex_id); - glDeleteShader (vertex_id); - - glDetachShader (program_id, fragment_id); - glDeleteShader (fragment_id); - - if (status == GL_FALSE) - { - char *buffer = NULL; - int log_len = 0; - - glGetProgramiv (program_id, GL_INFO_LOG_LENGTH, &log_len); - - if (log_len > 0) - { - /* log_len includes NULL */ - buffer = g_malloc0 (log_len); - glGetProgramInfoLog (program_id, log_len, NULL, buffer); - } - - g_warning ("Linking failure in shader:\n%s", - buffer ? buffer : ""); - - g_set_error (error, - GDK_GL_ERROR, - GDK_GL_ERROR_LINK_FAILED, - "Linking failure in shader: %s", - buffer ? buffer : ""); - - g_free (buffer); - - glDeleteProgram (program_id); - - return NULL; - } - - return gsk_gl_program_new (self->driver, name, program_id); -} diff --git a/gsk/gl/gskglcompilerprivate.h b/gsk/gl/gskglcompilerprivate.h deleted file mode 100644 index 82a2dda81a200b8ba92655eb0c3e133612958e25..0000000000000000000000000000000000000000 --- a/gsk/gl/gskglcompilerprivate.h +++ /dev/null @@ -1,68 +0,0 @@ -/* gskglcompilerprivate.h - * - * Copyright 2020 Christian Hergert - * - * 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 . - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#pragma once - -#include "gskgltypesprivate.h" - -G_BEGIN_DECLS - -typedef enum _GskGLCompilerKind -{ - GSK_GL_COMPILER_ALL, - GSK_GL_COMPILER_FRAGMENT, - GSK_GL_COMPILER_VERTEX, -} GskGLCompilerKind; - -#define GSK_TYPE_GL_COMPILER (gsk_gl_compiler_get_type()) - -G_DECLARE_FINAL_TYPE (GskGLCompiler, gsk_gl_compiler, GSK, GL_COMPILER, GObject) - -GskGLCompiler * gsk_gl_compiler_new (GskGLDriver *driver, - gboolean debug); -void gsk_gl_compiler_set_preamble (GskGLCompiler *self, - GskGLCompilerKind kind, - GBytes *preamble_bytes); -void gsk_gl_compiler_set_preamble_from_resource (GskGLCompiler *self, - GskGLCompilerKind kind, - const char *resource_path); -void gsk_gl_compiler_set_source (GskGLCompiler *self, - GskGLCompilerKind kind, - GBytes *source_bytes); -void gsk_gl_compiler_set_source_from_resource (GskGLCompiler *self, - GskGLCompilerKind kind, - const char *resource_path); -void gsk_gl_compiler_set_suffix (GskGLCompiler *self, - GskGLCompilerKind kind, - GBytes *suffix_bytes); -void gsk_gl_compiler_set_suffix_from_resource (GskGLCompiler *self, - GskGLCompilerKind kind, - const char *resource_path); -void gsk_gl_compiler_bind_attribute (GskGLCompiler *self, - const char *name, - guint location); -void gsk_gl_compiler_clear_attributes (GskGLCompiler *self); -GskGLProgram * gsk_gl_compiler_compile (GskGLCompiler *self, - const char *name, - const char *clip, - GError **error); - -G_END_DECLS - diff --git a/gsk/gl/gskgldriver.c b/gsk/gl/gskgldriver.c deleted file mode 100644 index 1d0a1542454ad9f94bcef95ca90558a7303372ed..0000000000000000000000000000000000000000 --- a/gsk/gl/gskgldriver.c +++ /dev/null @@ -1,1867 +0,0 @@ -/* gskgldriver.c - * - * Copyright 2017 Timm Bäder - * Copyright 2018 Matthias Clasen - * Copyright 2018 Alexander Larsson - * Copyright 2020 Christian Hergert - * - * 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 . - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#include "config.h" - -#include "gskgldriverprivate.h" - -#include -#include -#include - -#include "gskglcommandqueueprivate.h" -#include "gskglcompilerprivate.h" -#include "gskglglyphlibraryprivate.h" -#include "gskgliconlibraryprivate.h" -#include "gskglprogramprivate.h" -#include "gskglshadowlibraryprivate.h" -#include "fp16private.h" - -#include -#include -#include -#include -#include -#include - -#include -#include - - -G_DEFINE_TYPE (GskGLDriver, gsk_gl_driver, G_TYPE_OBJECT) - -static guint -texture_key_hash (gconstpointer v) -{ - const GskTextureKey *k = (const GskTextureKey *)v; - - /* Optimize for 0..3 where 0 is the scaled out case. Usually - * we'll be squarely on 1 or 2 for standard vs HiDPI. When rendering - * to a texture scaled out like in node-editor, we might be < 1. - */ - guint scale_x = floorf (k->scale_x); - guint scale_y = floorf (k->scale_y); - - return GPOINTER_TO_SIZE (k->pointer) ^ - ((scale_x << 8) | - (scale_y << 4) | - k->pointer_is_child); -} - -static gboolean -texture_key_equal (gconstpointer v1, - gconstpointer v2) -{ - const GskTextureKey *k1 = (const GskTextureKey *)v1; - const GskTextureKey *k2 = (const GskTextureKey *)v2; - - return k1->pointer == k2->pointer && - k1->scale_x == k2->scale_x && - k1->scale_y == k2->scale_y && - k1->pointer_is_child == k2->pointer_is_child && - (!k1->pointer_is_child || memcmp (&k1->parent_rect, &k2->parent_rect, sizeof k1->parent_rect) == 0); -} - -static void -remove_texture_key_for_id (GskGLDriver *self, - guint texture_id) -{ - GskTextureKey *key; - - g_assert (GSK_IS_GL_DRIVER (self)); - g_assert (texture_id > 0); - - /* g_hash_table_remove() will cause @key to be freed */ - if (g_hash_table_steal_extended (self->texture_id_to_key, - GUINT_TO_POINTER (texture_id), - NULL, - (gpointer *)&key)) - g_hash_table_remove (self->key_to_texture_id, key); -} - -static void -gsk_gl_texture_destroyed (gpointer data) -{ - ((GskGLTexture *)data)->user = NULL; -} - -static void -gsk_gl_driver_autorelease_texture (GskGLDriver *self, - guint texture_id) -{ - g_assert (GSK_IS_GL_DRIVER (self)); - - g_array_append_val (self->texture_pool, texture_id); -} - -static guint -gsk_gl_driver_collect_unused_textures (GskGLDriver *self, - gint64 watermark) -{ - GHashTableIter iter; - gpointer k, v; - guint old_size; - guint collected; - - g_assert (GSK_IS_GL_DRIVER (self)); - - old_size = g_hash_table_size (self->textures); - - g_hash_table_iter_init (&iter, self->textures); - while (g_hash_table_iter_next (&iter, &k, &v)) - { - GskGLTexture *t = v; - - if (t->user || t->permanent) - continue; - - if (t->last_used_in_frame <= watermark) - { - g_hash_table_iter_steal (&iter); - - g_assert (t->link.prev == NULL); - g_assert (t->link.next == NULL); - g_assert (t->link.data == t); - - remove_texture_key_for_id (self, t->texture_id); - gsk_gl_driver_autorelease_texture (self, t->texture_id); - t->texture_id = 0; - gsk_gl_texture_free (t); - } - } - - collected = old_size - g_hash_table_size (self->textures); - - return collected; -} - -static void -remove_program (gpointer data) -{ - GskGLProgram *program = data; - - g_assert (!program || GSK_IS_GL_PROGRAM (program)); - - if (program != NULL) - { - gsk_gl_program_delete (program); - g_object_unref (program); - } -} - -static void -gsk_gl_driver_shader_weak_cb (gpointer data, - GObject *where_object_was) -{ - GskGLDriver *self = data; - - g_assert (GSK_IS_GL_DRIVER (self)); - - if (self->shader_cache != NULL) - { - if (self->command_queue != NULL) - gsk_gl_command_queue_make_current (self->command_queue); - - g_hash_table_remove (self->shader_cache, where_object_was); - } -} - -G_GNUC_UNUSED G_GNUC_NULL_TERMINATED static inline GBytes * -join_sources (GBytes *first_bytes, - ...) -{ - GByteArray *byte_array = g_byte_array_new (); - GBytes *bytes = first_bytes; - va_list args; - - va_start (args, first_bytes); - while (bytes != NULL) - { - gsize len; - const guint8 *data = g_bytes_get_data (bytes, &len); - if (len > 0) - g_byte_array_append (byte_array, data, len); - g_bytes_unref (bytes); - bytes = va_arg (args, GBytes *); - } - va_end (args); - - return g_byte_array_free_to_bytes (byte_array); -} - -static void -gsk_gl_driver_dispose (GObject *object) -{ - GskGLDriver *self = (GskGLDriver *)object; - - g_assert (GSK_IS_GL_DRIVER (self)); - g_assert (self->in_frame == FALSE); - - if (self->shared_command_queue) - gsk_gl_command_queue_make_current (self->shared_command_queue); - -#define GSK_GL_NO_UNIFORMS -#define GSK_GL_SHADER_RESOURCE(name) -#define GSK_GL_SHADER_STRING(str) -#define GSK_GL_SHADER_SINGLE(name) -#define GSK_GL_SHADER_JOINED(kind, ...) -#define GSK_GL_ADD_UNIFORM(pos, KEY, name) -#define GSK_GL_DEFINE_PROGRAM(name, resource, uniforms) \ - GSK_GL_DELETE_PROGRAM(name); \ - GSK_GL_DELETE_PROGRAM(name ## _no_clip); \ - GSK_GL_DELETE_PROGRAM(name ## _rect_clip); -#define GSK_GL_DEFINE_PROGRAM_NO_CLIP(name, resource, uniforms) \ - GSK_GL_DELETE_PROGRAM(name); -#define GSK_GL_DELETE_PROGRAM(name) \ - G_STMT_START { \ - if (self->name) \ - gsk_gl_program_delete (self->name); \ - g_clear_object (&self->name); \ - } G_STMT_END; -# include "gskglprograms.defs" -#undef GSK_GL_NO_UNIFORMS -#undef GSK_GL_SHADER_RESOURCE -#undef GSK_GL_SHADER_STRING -#undef GSK_GL_SHADER_SINGLE -#undef GSK_GL_SHADER_JOINED -#undef GSK_GL_ADD_UNIFORM -#undef GSK_GL_DEFINE_PROGRAM -#undef GSK_GL_DEFINE_PROGRAM_NO_CLIP - -G_GNUC_BEGIN_IGNORE_DEPRECATIONS - if (self->shader_cache != NULL) - { - GHashTableIter iter; - gpointer k, v; - - g_hash_table_iter_init (&iter, self->shader_cache); - while (g_hash_table_iter_next (&iter, &k, &v)) - { - GskGLShader *shader = k; - g_object_weak_unref (G_OBJECT (shader), - gsk_gl_driver_shader_weak_cb, - self); - g_hash_table_iter_remove (&iter); - } - - g_clear_pointer (&self->shader_cache, g_hash_table_unref); - } -G_GNUC_END_IGNORE_DEPRECATIONS - - if (self->command_queue != NULL) - { - gsk_gl_command_queue_make_current (self->command_queue); - gsk_gl_driver_collect_unused_textures (self, 0); - g_clear_object (&self->command_queue); - } - - if (self->autorelease_framebuffers != NULL && - self->autorelease_framebuffers->len > 0) - { - glDeleteFramebuffers (self->autorelease_framebuffers->len, - (GLuint *)(gpointer)self->autorelease_framebuffers->data); - self->autorelease_framebuffers->len = 0; - } - - g_clear_object (&self->glyphs_library); - g_clear_object (&self->icons_library); - g_clear_object (&self->shadows_library); - - g_clear_pointer (&self->texture_pool, g_array_unref); - - g_clear_pointer (&self->autorelease_framebuffers, g_array_unref); - g_clear_pointer (&self->key_to_texture_id, g_hash_table_unref); - g_clear_pointer (&self->textures, g_hash_table_unref); - g_clear_pointer (&self->key_to_texture_id, g_hash_table_unref); - g_clear_pointer (&self->texture_id_to_key, g_hash_table_unref); - g_clear_pointer (&self->render_targets, g_ptr_array_unref); - g_clear_pointer (&self->shader_cache, g_hash_table_unref); - - g_clear_object (&self->command_queue); - g_clear_object (&self->shared_command_queue); - - G_OBJECT_CLASS (gsk_gl_driver_parent_class)->dispose (object); -} - -static void -gsk_gl_driver_class_init (GskGLDriverClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->dispose = gsk_gl_driver_dispose; -} - -static void -gsk_gl_driver_init (GskGLDriver *self) -{ - self->autorelease_framebuffers = g_array_new (FALSE, FALSE, sizeof (guint)); - self->textures = g_hash_table_new_full (NULL, NULL, NULL, - (GDestroyNotify)gsk_gl_texture_free); - self->texture_id_to_key = g_hash_table_new (NULL, NULL); - self->key_to_texture_id = g_hash_table_new_full (texture_key_hash, - texture_key_equal, - g_free, - NULL); - self->shader_cache = g_hash_table_new_full (NULL, NULL, NULL, remove_program); - self->texture_pool = g_array_new (FALSE, FALSE, sizeof (guint)); - self->render_targets = g_ptr_array_new (); -} - -static gboolean -gsk_gl_driver_load_programs (GskGLDriver *self, - GError **error) -{ - GskGLCompiler *compiler; - gboolean ret = FALSE; - G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME; - - g_assert (GSK_IS_GL_DRIVER (self)); - g_assert (GSK_IS_GL_COMMAND_QUEUE (self->command_queue)); - - compiler = gsk_gl_compiler_new (self, self->debug); - - /* Setup preambles that are shared by all shaders */ - gsk_gl_compiler_set_preamble_from_resource (compiler, - GSK_GL_COMPILER_ALL, - "/org/gtk/libgsk/gl/preamble.glsl"); - gsk_gl_compiler_set_preamble_from_resource (compiler, - GSK_GL_COMPILER_VERTEX, - "/org/gtk/libgsk/gl/preamble.vs.glsl"); - gsk_gl_compiler_set_preamble_from_resource (compiler, - GSK_GL_COMPILER_FRAGMENT, - "/org/gtk/libgsk/gl/preamble.fs.glsl"); - - /* Setup attributes that are provided via VBO */ - gsk_gl_compiler_bind_attribute (compiler, "aPosition", 0); - gsk_gl_compiler_bind_attribute (compiler, "aUv", 1); - gsk_gl_compiler_bind_attribute (compiler, "aColor", 2); - gsk_gl_compiler_bind_attribute (compiler, "aColor2", 3); - - /* Use XMacros to register all of our programs and their uniforms */ -#define GSK_GL_NO_UNIFORMS -#define GSK_GL_SHADER_RESOURCE(name) \ - g_resources_lookup_data("/org/gtk/libgsk/gl/" name, 0, NULL) -#define GSK_GL_SHADER_STRING(str) \ - g_bytes_new_static(str, strlen(str)) -#define GSK_GL_SHADER_SINGLE(bytes) \ - G_STMT_START { \ - GBytes *b = bytes; \ - gsk_gl_compiler_set_source (compiler, GSK_GL_COMPILER_ALL, b); \ - g_bytes_unref (b); \ - } G_STMT_END; -#define GSK_GL_SHADER_JOINED(kind, ...) \ - G_STMT_START { \ - GBytes *bytes = join_sources(__VA_ARGS__); \ - gsk_gl_compiler_set_source (compiler, GSK_GL_COMPILER_##kind, bytes); \ - g_bytes_unref (bytes); \ - } G_STMT_END; -#define GSK_GL_ADD_UNIFORM(pos, KEY, name) \ - gsk_gl_program_add_uniform (program, #name, UNIFORM_##KEY); -#define GSK_GL_DEFINE_PROGRAM(name, sources, uniforms) \ - gsk_gl_compiler_set_source (compiler, GSK_GL_COMPILER_VERTEX, NULL); \ - gsk_gl_compiler_set_source (compiler, GSK_GL_COMPILER_FRAGMENT, NULL); \ - sources \ - GSK_GL_COMPILE_PROGRAM(name ## _no_clip, uniforms, "#define NO_CLIP 1\n"); \ - GSK_GL_COMPILE_PROGRAM(name ## _rect_clip, uniforms, "#define RECT_CLIP 1\n"); \ - GSK_GL_COMPILE_PROGRAM(name, uniforms, ""); -#define GSK_GL_DEFINE_PROGRAM_NO_CLIP(name, sources, uniforms) \ - gsk_gl_compiler_set_source (compiler, GSK_GL_COMPILER_VERTEX, NULL); \ - gsk_gl_compiler_set_source (compiler, GSK_GL_COMPILER_FRAGMENT, NULL); \ - sources \ - GSK_GL_COMPILE_PROGRAM(name, uniforms, "#define NO_CLIP 1\n"); -#define GSK_GL_COMPILE_PROGRAM(name, uniforms, clip) \ - G_STMT_START { \ - GskGLProgram *program; \ - gboolean have_alpha; \ - gboolean have_source; \ - \ - if (!(program = gsk_gl_compiler_compile (compiler, #name, clip, error))) \ - goto failure; \ - \ - have_alpha = gsk_gl_program_add_uniform (program, "u_alpha", UNIFORM_SHARED_ALPHA); \ - have_source = gsk_gl_program_add_uniform (program, "u_source", UNIFORM_SHARED_SOURCE); \ - gsk_gl_program_add_uniform (program, "u_clip_rect", UNIFORM_SHARED_CLIP_RECT); \ - gsk_gl_program_add_uniform (program, "u_viewport", UNIFORM_SHARED_VIEWPORT); \ - gsk_gl_program_add_uniform (program, "u_projection", UNIFORM_SHARED_PROJECTION); \ - gsk_gl_program_add_uniform (program, "u_modelview", UNIFORM_SHARED_MODELVIEW); \ - \ - uniforms \ - \ - gsk_gl_program_uniforms_added (program, have_source); \ - if (have_alpha) \ - gsk_gl_program_set_uniform1f (program, UNIFORM_SHARED_ALPHA, 0, 1.0f); \ - \ - *(GskGLProgram **)(((guint8 *)self) + G_STRUCT_OFFSET (GskGLDriver, name)) = \ - g_steal_pointer (&program); \ - } G_STMT_END; -# include "gskglprograms.defs" -#undef GSK_GL_DEFINE_PROGRAM -#undef GSK_GL_DEFINE_PROGRAM_NO_CLIP -#undef GSK_GL_ADD_UNIFORM -#undef GSK_GL_SHADER_SINGLE -#undef GSK_GL_SHADER_JOINED -#undef GSK_GL_SHADER_RESOURCE -#undef GSK_GL_SHADER_STRING -#undef GSK_GL_NO_UNIFORMS - - ret = TRUE; - -failure: - g_clear_object (&compiler); - - gdk_profiler_end_mark (start_time, "Load GL programs", NULL); - - return ret; -} - -/** - * gsk_gl_driver_autorelease_framebuffer: - * @self: a `GskGLDriver` - * @framebuffer_id: the id of the OpenGL framebuffer - * - * Marks @framebuffer_id to be deleted when the current frame has cmopleted. - */ -static void -gsk_gl_driver_autorelease_framebuffer (GskGLDriver *self, - guint framebuffer_id) -{ - g_assert (GSK_IS_GL_DRIVER (self)); - - g_array_append_val (self->autorelease_framebuffers, framebuffer_id); -} - -static GskGLDriver * -gsk_gl_driver_new (GskGLCommandQueue *command_queue, - gboolean debug_shaders, - GError **error) -{ - GskGLDriver *self; - GdkGLContext *context; - gint64 before G_GNUC_UNUSED; - - g_return_val_if_fail (GSK_IS_GL_COMMAND_QUEUE (command_queue), NULL); - - before = GDK_PROFILER_CURRENT_TIME; - - context = gsk_gl_command_queue_get_context (command_queue); - - gdk_gl_context_make_current (context); - - self = g_object_new (GSK_TYPE_GL_DRIVER, NULL); - self->command_queue = g_object_ref (command_queue); - self->shared_command_queue = g_object_ref (command_queue); - self->debug = !!debug_shaders; - - if (!gsk_gl_driver_load_programs (self, error)) - { - g_object_unref (self); - return NULL; - } - - self->glyphs_library = gsk_gl_glyph_library_new (self); - self->icons_library = gsk_gl_icon_library_new (self); - self->shadows_library = gsk_gl_shadow_library_new (self); - - gdk_profiler_end_mark (before, "Create GL driver", NULL); - - return g_steal_pointer (&self); -} - -static void -free_driver (GskGLDriver *driver) -{ - g_object_run_dispose (G_OBJECT (driver)); - g_object_unref (driver); -} - -static void -display_closed (GdkDisplay *display) -{ - g_object_set_data (G_OBJECT (display), "GSK_GL_DRIVER", NULL); -} - -/** - * gsk_gl_driver_for_display: - * @display: A #GdkDisplay that is known to support GL - * @debug_shaders: if debug information for shaders should be displayed - * @error: location for error information - * - * Retrieves a driver for a shared display. Generally this is shared across all GL - * contexts for a display so that fewer programs are necessary for driving output. - * - * Returns: (transfer full): a `GskGLDriver` if successful; otherwise %NULL and - * @error is set. - */ -GskGLDriver * -gsk_gl_driver_for_display (GdkDisplay *display, - gboolean debug_shaders, - GError **error) -{ - GdkGLContext *context; - GskGLCommandQueue *command_queue = NULL; - GskGLDriver *driver; - - g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL); - - if ((driver = g_object_get_data (G_OBJECT (display), "GSK_GL_DRIVER"))) - return g_object_ref (driver); - - context = gdk_display_get_gl_context (display); - g_assert (context); - - gdk_gl_context_make_current (context); - - /* Initially we create a command queue using the shared context. However, - * as frames are processed this will be replaced with the command queue - * for a given renderer. But since the programs are compiled into the - * shared context, all other contexts sharing with it will have access - * to those programs. - */ - command_queue = gsk_gl_command_queue_new (context, NULL); - - if (!(driver = gsk_gl_driver_new (command_queue, debug_shaders, error))) - goto failure; - - g_object_set_data_full (G_OBJECT (display), - "GSK_GL_DRIVER", - g_object_ref (driver), - (GDestroyNotify) free_driver); - g_signal_connect (display, "closed", G_CALLBACK (display_closed), NULL); - -failure: - g_clear_object (&command_queue); - - return g_steal_pointer (&driver); -} - -/** - * gsk_gl_driver_begin_frame: - * @self: a `GskGLDriver` - * @command_queue: A `GskGLCommandQueue` from the renderer - * - * Begin a new frame. - * - * Texture atlases, pools, and other resources will be prepared to draw the - * next frame. The command queue should be one that was created for the - * target context to be drawn into (the context of the renderer's surface). - */ -void -gsk_gl_driver_begin_frame (GskGLDriver *self, - GskGLCommandQueue *command_queue) -{ - gint64 last_frame_id; - - g_return_if_fail (GSK_IS_GL_DRIVER (self)); - g_return_if_fail (GSK_IS_GL_COMMAND_QUEUE (command_queue)); - g_return_if_fail (self->in_frame == FALSE); - - last_frame_id = self->current_frame_id; - - self->in_frame = TRUE; - self->current_frame_id++; - - g_set_object (&self->command_queue, command_queue); - - gsk_gl_command_queue_begin_frame (self->command_queue); - - /* Mark unused pixel regions of the atlases */ - gsk_gl_texture_library_begin_frame (GSK_GL_TEXTURE_LIBRARY (self->icons_library), - self->current_frame_id); - gsk_gl_texture_library_begin_frame (GSK_GL_TEXTURE_LIBRARY (self->glyphs_library), - self->current_frame_id); - - /* Cleanup old shadows */ - gsk_gl_shadow_library_begin_frame (self->shadows_library); - - /* Remove all textures that are from a previous frame or are no - * longer used by linked GdkTexture. We do this at the beginning - * of the following frame instead of the end so that we reduce chances - * we block on any resources while delivering our frames. - */ - gsk_gl_driver_collect_unused_textures (self, last_frame_id - 1); -} - -/** - * gsk_gl_driver_end_frame: - * @self: a `GskGLDriver` - * - * Clean up resources from drawing the current frame. - * - * Temporary resources used while drawing will be released. - */ -void -gsk_gl_driver_end_frame (GskGLDriver *self) -{ - g_return_if_fail (GSK_IS_GL_DRIVER (self)); - g_return_if_fail (self->in_frame == TRUE); - - gsk_gl_command_queue_make_current (self->command_queue); - gsk_gl_command_queue_end_frame (self->command_queue); - - self->in_frame = FALSE; -} - -/** - * gsk_gl_driver_after_frame: - * @self: a `GskGLDriver` - * - * This function does post-frame cleanup operations. - * - * To reduce the chances of blocking on the driver it is performed - * after the frame has swapped buffers. - */ -void -gsk_gl_driver_after_frame (GskGLDriver *self) -{ - g_return_if_fail (GSK_IS_GL_DRIVER (self)); - g_return_if_fail (self->in_frame == FALSE); - - /* Release any render targets (possibly adding them to - * self->autorelease_framebuffers) so we can release the FBOs immediately - * afterwards. - */ - while (self->render_targets->len > 0) - { - GskGLRenderTarget *render_target = g_ptr_array_index (self->render_targets, self->render_targets->len - 1); - - gsk_gl_driver_autorelease_framebuffer (self, render_target->framebuffer_id); - gsk_gl_driver_autorelease_texture (self, render_target->texture_id); - g_free (render_target); - - self->render_targets->len--; - } - - /* Now that we have collected render targets, release all the FBOs */ - if (self->autorelease_framebuffers->len > 0) - { - glDeleteFramebuffers (self->autorelease_framebuffers->len, - (GLuint *)(gpointer)self->autorelease_framebuffers->data); - self->autorelease_framebuffers->len = 0; - } - - /* Release any cached textures we used during the frame */ - if (self->texture_pool->len > 0) - { - glDeleteTextures (self->texture_pool->len, - (GLuint *)(gpointer)self->texture_pool->data); - self->texture_pool->len = 0; - } - - /* Reset command queue to our shared queue in case we have operations - * that need to be processed outside of a frame (such as callbacks - * from external systems such as GDK). - */ - g_set_object (&self->command_queue, self->shared_command_queue); -} - -GdkGLContext * -gsk_gl_driver_get_context (GskGLDriver *self) -{ - g_return_val_if_fail (GSK_IS_GL_DRIVER (self), NULL); - g_return_val_if_fail (GSK_IS_GL_COMMAND_QUEUE (self->command_queue), NULL); - - return gsk_gl_command_queue_get_context (self->command_queue); -} - -/** - * gsk_gl_driver_cache_texture: - * @self: a `GskGLDriver` - * @key: the key for the texture - * @texture_id: the id of the texture to be cached - * - * Inserts @texture_id into the texture cache using @key. - * - * Textures can be looked up by @key after calling this function using - * gsk_gl_driver_lookup_texture(). - * - * Textures that have not been used within a number of frames will be - * purged from the texture cache automatically. - */ -void -gsk_gl_driver_cache_texture (GskGLDriver *self, - const GskTextureKey *key, - guint texture_id) -{ - g_assert (GSK_IS_GL_DRIVER (self)); - g_assert (key != NULL); - g_assert (texture_id > 0); - g_assert (g_hash_table_contains (self->textures, GUINT_TO_POINTER (texture_id))); - - if (!g_hash_table_contains (self->key_to_texture_id, key)) - { - GskTextureKey *k; - - k = g_memdup2 (key, sizeof *key); - - g_assert (!g_hash_table_contains (self->texture_id_to_key, GUINT_TO_POINTER (texture_id))); - g_hash_table_insert (self->key_to_texture_id, k, GUINT_TO_POINTER (texture_id)); - g_hash_table_insert (self->texture_id_to_key, GUINT_TO_POINTER (texture_id), k); - } -} - -#if defined(HAVE_DMABUF) && defined (HAVE_EGL) -static void -set_viewport_for_size (GskGLDriver *self, - GskGLProgram *program, - float width, - float height) -{ - float viewport[4] = { 0, 0, width, height }; - - gsk_gl_uniform_state_set4fv (program->uniforms, - program->program_info, - UNIFORM_SHARED_VIEWPORT, 0, - 1, - (const float *)&viewport); - self->stamps[UNIFORM_SHARED_VIEWPORT]++; -} - -#define ORTHO_NEAR_PLANE -10000 -#define ORTHO_FAR_PLANE 10000 - -static void -set_projection_for_size (GskGLDriver *self, - GskGLProgram *program, - float width, - float height) -{ - graphene_matrix_t projection; - - graphene_matrix_init_ortho (&projection, 0, width, 0, height, ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE); - graphene_matrix_scale (&projection, 1, -1, 1); - - gsk_gl_uniform_state_set_matrix (program->uniforms, - program->program_info, - UNIFORM_SHARED_PROJECTION, 0, - &projection); - self->stamps[UNIFORM_SHARED_PROJECTION]++; -} - -static void -reset_modelview (GskGLDriver *self, - GskGLProgram *program) -{ - graphene_matrix_t modelview; - - graphene_matrix_init_identity (&modelview); - - gsk_gl_uniform_state_set_matrix (program->uniforms, - program->program_info, - UNIFORM_SHARED_MODELVIEW, 0, - &modelview); - self->stamps[UNIFORM_SHARED_MODELVIEW]++; -} - -static void -draw_rect (GskGLCommandQueue *command_queue, - float min_x, - float min_y, - float max_x, - float max_y) -{ - GskGLDrawVertex *vertices = gsk_gl_command_queue_add_vertices (command_queue); - float min_u = 0; - float max_u = 1; - float min_v = 1; - float max_v = 0; - guint16 c = FP16_ZERO; - - vertices[0] = (GskGLDrawVertex) { .position = { min_x, min_y }, .uv = { min_u, min_v }, .color = { c, c, c, c } }; - vertices[1] = (GskGLDrawVertex) { .position = { min_x, max_y }, .uv = { min_u, max_v }, .color = { c, c, c, c } }; - vertices[2] = (GskGLDrawVertex) { .position = { max_x, min_y }, .uv = { max_u, min_v }, .color = { c, c, c, c } }; - vertices[3] = (GskGLDrawVertex) { .position = { max_x, max_y }, .uv = { max_u, max_v }, .color = { c, c, c, c } }; - vertices[4] = (GskGLDrawVertex) { .position = { min_x, max_y }, .uv = { min_u, max_v }, .color = { c, c, c, c } }; - vertices[5] = (GskGLDrawVertex) { .position = { max_x, min_y }, .uv = { max_u, min_v }, .color = { c, c, c, c } }; -} - -static unsigned int release_render_target (GskGLDriver *self, - GskGLRenderTarget *render_target, - gboolean release_texture, - gboolean cache_texture); - -static guint -gsk_gl_driver_import_dmabuf_texture (GskGLDriver *self, - GdkDmabufTexture *texture) -{ - GdkGLContext *context = self->command_queue->context; - int max_texture_size = self->command_queue->max_texture_size; - const GdkDmabuf *dmabuf; - guint texture_id; - int width, height; - GskGLProgram *program; - GskGLRenderTarget *render_target; - guint prev_fbo; - gboolean external; - GdkMemoryFormat format; - gboolean premultiply; - - gdk_gl_context_make_current (context); - - width = gdk_texture_get_width (GDK_TEXTURE (texture)); - height = gdk_texture_get_height (GDK_TEXTURE (texture)); - - if (width > max_texture_size || height > max_texture_size) - { - GDK_DISPLAY_DEBUG (gdk_gl_context_get_display (context), DMABUF, - "Can't import dmabuf bigger than MAX_TEXTURE_SIZE (%d)", - max_texture_size); - return 0; - } - - dmabuf = gdk_dmabuf_texture_get_dmabuf (texture); - format = gdk_texture_get_format (GDK_TEXTURE (texture)); - premultiply = gdk_memory_format_alpha (format) == GDK_MEMORY_ALPHA_STRAIGHT; - - texture_id = gdk_gl_context_import_dmabuf (context, - width, height, - dmabuf, - &external); - if (texture_id == 0) - return 0; - - if (!external && !premultiply) - return texture_id; - - gsk_gl_driver_autorelease_texture (self, texture_id); - - if (external) - program = self->external; - else - program = self->premultiply; - - if (!gsk_gl_driver_create_render_target (self, width, height, GL_RGBA8, &render_target)) - return texture_id; - - prev_fbo = gsk_gl_command_queue_bind_framebuffer (self->command_queue, render_target->framebuffer_id); - gsk_gl_command_queue_clear (self->command_queue, 0, &GRAPHENE_RECT_INIT (0, 0, width, height)); - - if (gsk_gl_command_queue_begin_draw (self->command_queue, program->program_info, width, height)) - { - set_projection_for_size (self, program, width, height); - set_viewport_for_size (self, program, width, height); - reset_modelview (self, program); - - if (external) - { - gsk_gl_program_set_uniform_texture (program, - UNIFORM_EXTERNAL_SOURCE, 0, - GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE0, texture_id); - - gsk_gl_program_set_uniform1i (program, UNIFORM_PREMULTIPLY, 0, premultiply); - } - else - { - gsk_gl_program_set_uniform_texture (program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, GL_TEXTURE0, texture_id); - } - - draw_rect (self->command_queue, 0, 0, width, height); - - gsk_gl_command_queue_end_draw (self->command_queue); - } - - gsk_gl_command_queue_bind_framebuffer (self->command_queue, prev_fbo); - - return release_render_target (self, render_target, FALSE, FALSE); -} - -#else - -static guint -gsk_gl_driver_import_dmabuf_texture (GskGLDriver *self, - GdkDmabufTexture *texture) -{ - return 0; -} - -#endif /* HAVE_DMABUF && HAVE_EGL */ - -/** - * gsk_gl_driver_load_texture: - * @self: a `GdkTexture` - * @texture: a `GdkTexture` - * @ensure_mipmap: Mipmaps for this texture must exist for downscaling - * - * Loads a `GdkTexture` by uploading the contents to the GPU when - * necessary. If @texture is a `GdkGLTexture`, it can be used without - * uploading contents to the GPU. - * - * If the texture has already been uploaded and not yet released - * from cache, this function returns that texture id without further - * work. - * - * If the texture has not been used for a number of frames, it will - * be removed from cache. - * - * There is no need to release the resulting texture identifier after - * using it. It will be released automatically. - * - * Returns: a texture identifier - */ -guint -gsk_gl_driver_load_texture (GskGLDriver *self, - GdkTexture *texture, - gboolean ensure_mipmap) -{ - GdkGLContext *context; - GdkMemoryTexture *downloaded_texture; - GskGLTexture *t; - guint texture_id; - int height; - int width; - gboolean can_mipmap = FALSE; - - g_return_val_if_fail (GSK_IS_GL_DRIVER (self), 0); - g_return_val_if_fail (GDK_IS_TEXTURE (texture), 0); - g_return_val_if_fail (GSK_IS_GL_COMMAND_QUEUE (self->command_queue), 0); - - context = self->command_queue->context; - - texture_id = 0; - downloaded_texture = NULL; - - t = gdk_texture_get_render_data (texture, self); - if (t && t->texture_id) - { - if (ensure_mipmap && t->can_mipmap && !t->has_mipmap) - { - glBindTexture (GL_TEXTURE_2D, t->texture_id); - glGenerateMipmap (GL_TEXTURE_2D); - t->has_mipmap = TRUE; - } - - if (!ensure_mipmap || t->has_mipmap) - return t->texture_id; - - gdk_texture_clear_render_data (texture); - } - - if (GDK_IS_DMABUF_TEXTURE (texture) && !ensure_mipmap) - { - texture_id = gsk_gl_driver_import_dmabuf_texture (self, GDK_DMABUF_TEXTURE (texture)); - } - else if (GDK_IS_GL_TEXTURE (texture)) - { - GdkGLTexture *gl_texture = (GdkGLTexture *) texture; - GdkGLContext *texture_context = gdk_gl_texture_get_context (gl_texture); - - if (gdk_gl_context_is_shared (context, texture_context) && - (!ensure_mipmap || gdk_gl_texture_has_mipmap (gl_texture)) && - gdk_memory_format_alpha (gdk_texture_get_format (texture)) != GDK_MEMORY_ALPHA_STRAIGHT) - { - /* A GL texture from the same GL context is a simple task... */ - return gdk_gl_texture_get_id (gl_texture); - } - } - - if (texture_id == 0) - { - downloaded_texture = gdk_memory_texture_from_texture (texture); - - /* The download_texture() call may have switched the GL context. Make sure - * the right context is at work again. - */ - gdk_gl_context_make_current (context); - - texture_id = gsk_gl_command_queue_upload_texture (self->command_queue, GDK_TEXTURE (downloaded_texture), ensure_mipmap, &can_mipmap); - } - - width = gdk_texture_get_width (texture); - height = gdk_texture_get_height (texture); - - t = gsk_gl_texture_new (texture_id, - width, height, - self->current_frame_id); - t->can_mipmap = can_mipmap; - if (ensure_mipmap) - { - g_assert (can_mipmap); - glBindTexture (GL_TEXTURE_2D, t->texture_id); - glGenerateMipmap (GL_TEXTURE_2D); - t->has_mipmap = TRUE; - } - - g_hash_table_insert (self->textures, GUINT_TO_POINTER (texture_id), t); - - if (gdk_texture_set_render_data (texture, self, t, gsk_gl_texture_destroyed)) - t->user = texture; - - gdk_gl_context_label_object_printf (context, GL_TEXTURE, t->texture_id, - "GdkTexture<%p> %d", texture, t->texture_id); - - g_clear_object (&downloaded_texture); - - return t->texture_id; -} - -/** - * gsk_gl_driver_create_texture: - * @self: a `GskGLDriver` - * @width: the width of the texture - * @height: the height of the texture - * @format: format for the texture - * - * Creates a new texture immediately that can be used by the caller - * to upload data, map to a framebuffer, or other uses which may - * modify the texture immediately. - * - * Typical examples for @format are GL_RGBA8, GL_RGBA16F or GL_RGBA32F. - * - * Use gsk_gl_driver_release_texture() to release this texture back into - * the pool so it may be reused later in the pipeline. - * - * Returns: a `GskGLTexture` which can be returned to the pool with - * gsk_gl_driver_release_texture(). - */ -GskGLTexture * -gsk_gl_driver_create_texture (GskGLDriver *self, - float width, - float height, - int format) -{ - GskGLTexture *texture; - guint texture_id; - - g_return_val_if_fail (GSK_IS_GL_DRIVER (self), NULL); - - texture_id = gsk_gl_command_queue_create_texture (self->command_queue, - width, height, - format); - texture = gsk_gl_texture_new (texture_id, - width, height, - self->current_frame_id); - g_hash_table_insert (self->textures, - GUINT_TO_POINTER (texture->texture_id), - texture); - - return texture; -} - -/** - * gsk_gl_driver_release_texture: - * @self: a `GskGLDriver` - * @texture: a `GskGLTexture` - * - * Releases @texture back into the pool so that it can be used later - * in the command stream by future batches. This helps reduce VRAM - * usage on the GPU. - * - * When the frame has completed, pooled textures will be released - * to free additional VRAM back to the system. - */ -void -gsk_gl_driver_release_texture (GskGLDriver *self, - GskGLTexture *texture) -{ - guint texture_id; - - g_assert (GSK_IS_GL_DRIVER (self)); - g_assert (texture != NULL); - - texture_id = texture->texture_id; - texture->texture_id = 0; - gsk_gl_texture_free (texture); - - if (texture_id > 0) - remove_texture_key_for_id (self, texture_id); - - g_hash_table_steal (self->textures, GUINT_TO_POINTER (texture_id)); - gsk_gl_driver_autorelease_texture (self, texture_id); -} - -/** - * gsk_gl_driver_create_render_target: - * @self: a `GskGLDriver` - * @width: the width for the render target - * @height: the height for the render target - * @format: the format to use - * @out_render_target: (out): a location for the render target - * - * Creates a new render target which contains a framebuffer and a texture - * bound to that framebuffer of the size @width x @height and using the - * appropriate filters. - * - * Typical examples for @format are GK_RGBA8, GL_RGBA16F or GL_RGBA32F. - * - * Use gsk_gl_driver_release_render_target() when you are finished with - * the render target to release it. You may steal the texture from the - * render target when releasing it. - * - * Returns: %TRUE if successful; otherwise %FALSE and @out_fbo_id and - * @out_texture_id are undefined. - */ -gboolean -gsk_gl_driver_create_render_target (GskGLDriver *self, - int width, - int height, - int format, - GskGLRenderTarget **out_render_target) -{ - guint framebuffer_id; - guint texture_id; - - g_return_val_if_fail (GSK_IS_GL_DRIVER (self), FALSE); - g_return_val_if_fail (GSK_IS_GL_COMMAND_QUEUE (self->command_queue), FALSE); - g_return_val_if_fail (out_render_target != NULL, FALSE); - -#if 0 - if (self->render_targets->len > 0) - { - for (guint i = self->render_targets->len; i > 0; i--) - { - GskGLRenderTarget *render_target = g_ptr_array_index (self->render_targets, i-1); - - if (render_target->width == width && - render_target->height == height) - { - *out_render_target = g_ptr_array_steal_index_fast (self->render_targets, i-1); - return TRUE; - } - } - } -#endif - - if (gsk_gl_command_queue_create_render_target (self->command_queue, - width, height, - format, - &framebuffer_id, &texture_id)) - { - GskGLRenderTarget *render_target; - - render_target = g_new0 (GskGLRenderTarget, 1); - render_target->format = format; - render_target->width = width; - render_target->height = height; - render_target->framebuffer_id = framebuffer_id; - render_target->texture_id = texture_id; - - *out_render_target = render_target; - - return TRUE; - } - - *out_render_target = NULL; - - return FALSE; -} - -static unsigned int -release_render_target (GskGLDriver *self, - GskGLRenderTarget *render_target, - gboolean release_texture, - gboolean cache_texture) -{ - guint texture_id; - - g_return_val_if_fail (GSK_IS_GL_DRIVER (self), 0); - g_return_val_if_fail (render_target != NULL, 0); - - if (release_texture) - { - texture_id = 0; - g_ptr_array_add (self->render_targets, render_target); - } - else - { - texture_id = render_target->texture_id; - - if (cache_texture) - { - GskGLTexture *texture; - - texture = gsk_gl_texture_new (render_target->texture_id, - render_target->width, - render_target->height, - self->current_frame_id); - g_hash_table_insert (self->textures, - GUINT_TO_POINTER (texture_id), - g_steal_pointer (&texture)); - } - - gsk_gl_driver_autorelease_framebuffer (self, render_target->framebuffer_id); - g_free (render_target); - - } - - return texture_id; -} - -/** - * gsk_gl_driver_release_render_target: - * @self: a `GskGLDriver` - * @render_target: a `GskGLRenderTarget` created with - * gsk_gl_driver_create_render_target(). - * @release_texture: if the texture should also be released - * - * Releases a render target that was previously created. An attempt may - * be made to cache the render target so that future creations of render - * targets are performed faster. - * - * If @release_texture is %FALSE, the backing texture id is returned and - * the framebuffer is released. Otherwise, both the texture and framebuffer - * are released or cached until the end of the frame. - * - * This may be called when building the render job as the texture or - * framebuffer will not be removed immediately. - * - * Returns: a texture id if @release_texture is %FALSE, otherwise zero. - */ -guint -gsk_gl_driver_release_render_target (GskGLDriver *self, - GskGLRenderTarget *render_target, - gboolean release_texture) -{ - return release_render_target (self, render_target, release_texture, TRUE); -} - -G_GNUC_BEGIN_IGNORE_DEPRECATIONS - -/** - * gsk_gl_driver_lookup_shader: - * @self: a `GskGLDriver` - * @shader: the shader to lookup or load - * @error: a location for a `GError` - * - * Attempts to load @shader from the shader cache. - * - * If it has not been loaded, then it will compile the shader on demand. - * - * Returns: (nullable) (transfer none): a `GskGLShader` - */ -GskGLProgram * -gsk_gl_driver_lookup_shader (GskGLDriver *self, - GskGLShader *shader, - GError **error) -{ - GskGLProgram *program; - - g_return_val_if_fail (self != NULL, NULL); - g_return_val_if_fail (shader != NULL, NULL); - - program = g_hash_table_lookup (self->shader_cache, shader); - - if (program == NULL) - { - const GskGLUniform *uniforms; - GskGLCompiler *compiler; - GBytes *suffix; - int n_required_textures; - int n_uniforms; - - uniforms = gsk_gl_shader_get_uniforms (shader, &n_uniforms); - if (n_uniforms > GSK_GL_PROGRAM_MAX_CUSTOM_ARGS) - { - g_set_error (error, - GDK_GL_ERROR, - GDK_GL_ERROR_UNSUPPORTED_FORMAT, - "Tried to use %d uniforms, while only %d is supported", - n_uniforms, - GSK_GL_PROGRAM_MAX_CUSTOM_ARGS); - return NULL; - } - - n_required_textures = gsk_gl_shader_get_n_textures (shader); - if (n_required_textures > GSK_GL_PROGRAM_MAX_CUSTOM_TEXTURES) - { - g_set_error (error, - GDK_GL_ERROR, - GDK_GL_ERROR_UNSUPPORTED_FORMAT, - "Tried to use %d textures, while only %d is supported", - n_required_textures, - GSK_GL_PROGRAM_MAX_CUSTOM_TEXTURES); - return NULL; - } - - compiler = gsk_gl_compiler_new (self, FALSE); - suffix = gsk_gl_shader_get_source (shader); - - gsk_gl_compiler_set_preamble_from_resource (compiler, - GSK_GL_COMPILER_ALL, - "/org/gtk/libgsk/gl/preamble.glsl"); - gsk_gl_compiler_set_preamble_from_resource (compiler, - GSK_GL_COMPILER_VERTEX, - "/org/gtk/libgsk/gl/preamble.vs.glsl"); - gsk_gl_compiler_set_preamble_from_resource (compiler, - GSK_GL_COMPILER_FRAGMENT, - "/org/gtk/libgsk/gl/preamble.fs.glsl"); - gsk_gl_compiler_set_source_from_resource (compiler, - GSK_GL_COMPILER_ALL, - "/org/gtk/libgsk/gl/custom.glsl"); - gsk_gl_compiler_set_suffix (compiler, GSK_GL_COMPILER_FRAGMENT, suffix); - - /* Setup attributes that are provided via VBO */ - gsk_gl_compiler_bind_attribute (compiler, "aPosition", 0); - gsk_gl_compiler_bind_attribute (compiler, "aUv", 1); - gsk_gl_compiler_bind_attribute (compiler, "aColor", 2); - gsk_gl_compiler_bind_attribute (compiler, "aColor2", 3); - - if ((program = gsk_gl_compiler_compile (compiler, NULL, "", error))) - { - gboolean have_alpha; - - gsk_gl_program_add_uniform (program, "u_source", UNIFORM_SHARED_SOURCE); - gsk_gl_program_add_uniform (program, "u_clip_rect", UNIFORM_SHARED_CLIP_RECT); - gsk_gl_program_add_uniform (program, "u_viewport", UNIFORM_SHARED_VIEWPORT); - gsk_gl_program_add_uniform (program, "u_projection", UNIFORM_SHARED_PROJECTION); - gsk_gl_program_add_uniform (program, "u_modelview", UNIFORM_SHARED_MODELVIEW); - have_alpha = gsk_gl_program_add_uniform (program, "u_alpha", UNIFORM_SHARED_ALPHA); - - gsk_gl_program_add_uniform (program, "u_size", UNIFORM_CUSTOM_SIZE); - gsk_gl_program_add_uniform (program, "u_texture1", UNIFORM_CUSTOM_TEXTURE1); - gsk_gl_program_add_uniform (program, "u_texture2", UNIFORM_CUSTOM_TEXTURE2); - gsk_gl_program_add_uniform (program, "u_texture3", UNIFORM_CUSTOM_TEXTURE3); - gsk_gl_program_add_uniform (program, "u_texture4", UNIFORM_CUSTOM_TEXTURE4); - - /* Custom arguments (max is 8) */ - for (guint i = 0; i < n_uniforms; i++) - gsk_gl_program_add_uniform (program, uniforms[i].name, UNIFORM_CUSTOM_ARG0+i); - - gsk_gl_program_uniforms_added (program, TRUE); - - if (have_alpha) - gsk_gl_program_set_uniform1f (program, UNIFORM_SHARED_ALPHA, 0, 1.0f); - - g_hash_table_insert (self->shader_cache, shader, program); - g_object_weak_ref (G_OBJECT (shader), - gsk_gl_driver_shader_weak_cb, - self); - } - - g_object_unref (compiler); - } - - return program; -} - -G_GNUC_END_IGNORE_DEPRECATIONS - -#if 0 -void -gsk_gl_driver_save_texture_to_png (GskGLDriver *driver, - int texture_id, - int width, - int height, - const char *filename) -{ - GdkGLTextureBuilder *builder; - GdkTexture *texture; - - builder = gdk_gl_texture_builder_new (); - gdk_gl_texture_builder_set_context (builder, gsk_gl_driver_get_context (driver)); - gdk_gl_texture_builder_set_id (builder, texture_id); - gdk_gl_texture_builder_set_width (builder, width); - gdk_gl_texture_builder_set_height (builder, height); - - texture = gdk_gl_texture_builder_build (builder, NULL, NULL); - gdk_texture_save_to_png (texture, filename); - - g_object_unref (texture); - g_object_unref (builder); -} - -void -gsk_gl_driver_save_atlases_to_png (GskGLDriver *self, - const char *directory) -{ - GPtrArray *atlases; - - g_return_if_fail (GSK_IS_GL_DRIVER (self)); - - if (directory == NULL) - directory = "."; - -#define copy_atlases(dst, library) \ - g_ptr_array_extend(dst, GSK_GL_TEXTURE_LIBRARY(library)->atlases, NULL, NULL) - atlases = g_ptr_array_new (); - copy_atlases (atlases, self->glyphs_library); - copy_atlases (atlases, self->icons_library); -#undef copy_atlases - - for (guint i = 0; i < atlases->len; i++) - { - GskGLTextureAtlas *atlas = g_ptr_array_index (atlases, i); - char *filename = g_strdup_printf ("%s%sframe-%d-atlas-%d.png", - directory, - G_DIR_SEPARATOR_S, - (int)self->current_frame_id, - atlas->texture_id); - gsk_gl_driver_save_texture_to_png (self, atlas->texture_id, atlas->width, atlas->height, filename); - g_free (filename); - } - - g_ptr_array_unref (atlases); -} -#endif - -GskGLCommandQueue * -gsk_gl_driver_create_command_queue (GskGLDriver *self, - GdkGLContext *context) -{ - g_return_val_if_fail (GSK_IS_GL_DRIVER (self), NULL); - g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL); - - return gsk_gl_command_queue_new (context, self->shared_command_queue->uniforms); -} - -void -gsk_gl_driver_add_texture_slices (GskGLDriver *self, - GdkTexture *texture, - gboolean ensure_mipmap, - GskGLTextureSlice **out_slices, - guint *out_n_slices) -{ - int max_slice_size; - GskGLTextureSlice *slices; - GskGLTexture *t; - guint n_slices; - guint cols; - guint rows; - int tex_width; - int tex_height; - int x = 0, y = 0; - GdkMemoryTexture *memtex; - GdkMemoryFormat format; - gsize bpp; - int extra_pixels; - GdkMemoryTexture *memtex1 = NULL; - GdkMemoryTexture *memtex2 = NULL; - GdkMemoryTexture *memtex3 = NULL; - GdkMemoryTexture *memtex4 = NULL; - gboolean can_mipmap = TRUE, slice_can_mipmap; - - g_assert (GSK_IS_GL_DRIVER (self)); - g_assert (GDK_IS_TEXTURE (texture)); - g_assert (out_slices != NULL); - g_assert (out_n_slices != NULL); - - max_slice_size = self->command_queue->max_texture_size / 2; - tex_width = texture->width; - tex_height = texture->height; - - cols = (texture->width / max_slice_size) + 1; - rows = (texture->height / max_slice_size) + 1; - - n_slices = cols * rows; - - t = gdk_texture_get_render_data (texture, self); - - if (t) - { - if (t->n_slices == n_slices && - (t->has_mipmap || !ensure_mipmap)) - { - *out_slices = t->slices; - *out_n_slices = t->n_slices; - return; - } - - gdk_texture_clear_render_data (texture); - } - - slices = g_new0 (GskGLTextureSlice, n_slices); - memtex = gdk_memory_texture_from_texture (texture); - - if (ensure_mipmap) - { - guchar *data1, *data2, *data3, *data4; - guchar *top_row, *bot_row, *left_row, *right_row; - GdkTexture *tmp; - int w; - GBytes *bytes; - - /* We need some extra pixels around our tiles, in order for - * GL to properly determine the right level of detail to use. - * This number should probably depend on the scale, but for - * now we just hardcode it. - * - * We create some auxiliary textures to hold the extra pixels: - * - * +---------------------+ - * | memtex1 | - * *---+-------------+---+ - * | | | | - * memtex2| memtex |memtex3 - * | | | | - * *---+-------------+---+ - * | memtex4 | | - * +---------------------+ - */ - - extra_pixels = 15; - - top_row = g_malloc (4 * tex_width); - tmp = gdk_memory_texture_new_subtexture (memtex, 0, 0, tex_width, 1); - gdk_texture_download (tmp, top_row, 4 * tex_width); - g_object_unref (tmp); - - bot_row = g_malloc (4 * tex_width); - tmp = gdk_memory_texture_new_subtexture (memtex, 0, tex_height - 1, tex_width, 1); - gdk_texture_download (tmp, bot_row, 4 * tex_width); - g_object_unref (tmp); - - left_row = g_malloc (4 * tex_height); - tmp = gdk_memory_texture_new_subtexture (memtex, 0, 0, 1, tex_height); - gdk_texture_download (tmp, left_row, 4); - g_object_unref (tmp); - - right_row = g_malloc (4 * tex_height); - tmp = gdk_memory_texture_new_subtexture (memtex, tex_width - 1, 0, 1, tex_height); - gdk_texture_download (tmp, right_row, 4); - g_object_unref (tmp); - - w = tex_width + 2 * extra_pixels; - - data1 = g_malloc (4 * w * extra_pixels); - data2 = g_malloc (4 * extra_pixels * tex_height); - data3 = g_malloc (4 * extra_pixels * tex_height); - data4 = g_malloc (4 * w * extra_pixels); - - format = gdk_texture_get_format (GDK_TEXTURE (memtex)); - bpp = gdk_memory_format_bytes_per_pixel (format); - - for (int i = 0; i < w; i++) - { - int ii = CLAMP (i, extra_pixels, (tex_width - 1) + extra_pixels) - extra_pixels; - - for (int j = 0; j < extra_pixels; j++) - { - for (int k = 0; k < bpp; k++) - { - data1[(j * w + i) * 4 + k] = top_row[ii * 4 + k]; - data4[(j * w + i) * 4 + k] = bot_row[ii * 4 + k]; - } - } - } - - for (int i = 0; i < extra_pixels; i++) - { - for (int j = 0; j < tex_height; j++) - { - for (int k = 0; k < bpp; k++) - { - data2[(j * extra_pixels + i) * 4 + k] = left_row[j * 4 + k]; - data3[(j * extra_pixels + i) * 4 + k] = right_row[j * 4 + k]; - } - } - } - - g_free (top_row); - g_free (bot_row); - g_free (left_row); - g_free (right_row); - - bytes = g_bytes_new_take (data1, 4 * w * extra_pixels); - memtex1 = GDK_MEMORY_TEXTURE (gdk_memory_texture_new (w, extra_pixels, format, bytes, 4 * w)); - g_bytes_unref (bytes); - - bytes = g_bytes_new_take (data2, 4 * extra_pixels * tex_height); - memtex2 = GDK_MEMORY_TEXTURE (gdk_memory_texture_new (extra_pixels, tex_height, format, bytes, 4 * extra_pixels)); - g_bytes_unref (bytes); - - bytes = g_bytes_new_take (data3, 4 * extra_pixels * tex_height); - memtex3 = GDK_MEMORY_TEXTURE (gdk_memory_texture_new (extra_pixels, tex_height, format, bytes, 4 * extra_pixels)); - g_bytes_unref (bytes); - - bytes = g_bytes_new_take (data4, 4 * w * extra_pixels); - memtex4 = GDK_MEMORY_TEXTURE (gdk_memory_texture_new (w, extra_pixels, format, bytes, 4 * w)); - g_bytes_unref (bytes); - } - else - extra_pixels = 0; - - x = 0; - for (guint col = 0; col < cols; col++) - { - int slice_width = col + 1 < cols ? tex_width / cols : tex_width - x; - - y = 0; - for (guint row = 0; row < rows; row++) - { - int slice_height = row + 1 < rows ? tex_height / rows : tex_height - y; - int slice_index = (col * rows) + row; - guint texture_id; - - if (ensure_mipmap) - { - GskGLTextureChunk chunks[5]; - unsigned int n_chunks = 0; - - if (row == 0) - { - chunks[n_chunks].texture = gdk_memory_texture_new_subtexture (memtex1, - x, 0, - slice_width + 2 * extra_pixels, extra_pixels); - chunks[n_chunks].x = 0; - chunks[n_chunks].y = 0; - n_chunks++; - } - - if (row == rows - 1) - { - chunks[n_chunks].texture = gdk_memory_texture_new_subtexture (memtex4, - x, 0, - slice_width + 2 * extra_pixels, extra_pixels); - chunks[n_chunks].x = 0; - chunks[n_chunks].y = slice_height + extra_pixels; - n_chunks++; - } - - if (col == 0) - { - int yy = y - extra_pixels; - int hh = slice_height + 2 * extra_pixels; - int y0 = 0; - - if (row == 0) - { - yy = 0; - y0 = extra_pixels; - hh -= extra_pixels; - } - if (row == rows - 1) - { - hh -= extra_pixels; - } - - chunks[n_chunks].texture = gdk_memory_texture_new_subtexture (memtex2, - 0, yy, extra_pixels, hh); - chunks[n_chunks].x = 0; - chunks[n_chunks].y = y0; - n_chunks++; - } - - if (col == cols - 1) - { - int yy = y - extra_pixels; - int hh = slice_height + 2 * extra_pixels; - int y0 = 0; - - if (row == 0) - { - yy = 0; - y0 = extra_pixels; - hh -= extra_pixels; - } - if (row == rows - 1) - { - hh -= extra_pixels; - } - - chunks[n_chunks].texture = gdk_memory_texture_new_subtexture (memtex3, - 0, yy, extra_pixels, hh); - chunks[n_chunks].x = slice_width + extra_pixels; - chunks[n_chunks].y = y0; - n_chunks++; - } - - { - int xx = x - extra_pixels; - int yy = y - extra_pixels; - int ww = slice_width + 2 * extra_pixels; - int hh = slice_height + 2 * extra_pixels; - int x0 = 0; - int y0 = 0; - if (col == 0) - { - xx = 0; - ww -= extra_pixels; - x0 = extra_pixels; - } - if (col == cols - 1) - { - ww -= extra_pixels; - } - if (row == 0) - { - yy = 0; - hh -= extra_pixels; - y0 = extra_pixels; - } - if (row == rows - 1) - { - hh -= extra_pixels; - } - - chunks[n_chunks].texture = gdk_memory_texture_new_subtexture (memtex, xx, yy, ww, hh); - chunks[n_chunks].x = x0; - chunks[n_chunks].y = y0; - n_chunks++; - } - - texture_id = gsk_gl_command_queue_upload_texture_chunks (self->command_queue, TRUE, n_chunks, chunks, &slice_can_mipmap); - - glBindTexture (GL_TEXTURE_2D, texture_id); - glGenerateMipmap (GL_TEXTURE_2D); - - for (unsigned int i = 0; i < n_chunks; i++) - g_object_unref (chunks[i].texture); - } - else - { - GdkTexture *subtex; - - subtex = gdk_memory_texture_new_subtexture (memtex, x, y, slice_width, slice_height); - texture_id = gsk_gl_command_queue_upload_texture (self->command_queue, subtex, FALSE, &slice_can_mipmap); - g_object_unref (subtex); - } - - can_mipmap &= slice_can_mipmap; - - slices[slice_index].rect.x = x; - slices[slice_index].rect.y = y; - slices[slice_index].rect.width = slice_width; - slices[slice_index].rect.height = slice_height; - slices[slice_index].texture_id = texture_id; - slices[slice_index].area.x = extra_pixels / (float) (slice_width + 2 * extra_pixels); - slices[slice_index].area.y = extra_pixels / (float) (slice_height + 2 * extra_pixels); - slices[slice_index].area.x2 = (extra_pixels + slice_width) / (float) (slice_width + 2 * extra_pixels); - slices[slice_index].area.y2 = (extra_pixels + slice_height) / (float) (slice_height + 2 * extra_pixels); - - y += slice_height; - } - - x += slice_width; - } - - g_object_unref (memtex); - g_clear_object (&memtex1); - g_clear_object (&memtex2); - g_clear_object (&memtex3); - g_clear_object (&memtex4); - - /* Allocate one Texture for the entire thing. */ - t = gsk_gl_texture_new (0, - tex_width, tex_height, - self->current_frame_id); - t->can_mipmap = can_mipmap; - t->has_mipmap = ensure_mipmap; - - /* Use gsk_gl_texture_free() as destroy notify here since we are - * not inserting this GskGLTexture into self->textures! - */ - gdk_texture_set_render_data (texture, self, t, - (GDestroyNotify)gsk_gl_texture_free); - - t->slices = *out_slices = slices; - t->n_slices = *out_n_slices = n_slices; -} - -GskGLTexture * -gsk_gl_driver_mark_texture_permanent (GskGLDriver *self, - guint texture_id) -{ - GskGLTexture *t; - - g_return_val_if_fail (GSK_IS_GL_DRIVER (self), NULL); - g_return_val_if_fail (texture_id > 0, NULL); - - if ((t = g_hash_table_lookup (self->textures, GUINT_TO_POINTER (texture_id)))) - t->permanent = TRUE; - - return t; -} - -void -gsk_gl_driver_release_texture_by_id (GskGLDriver *self, - guint texture_id) -{ - GskGLTexture *texture; - - g_return_if_fail (GSK_IS_GL_DRIVER (self)); - g_return_if_fail (texture_id > 0); - - remove_texture_key_for_id (self, texture_id); - - if ((texture = g_hash_table_lookup (self->textures, GUINT_TO_POINTER (texture_id)))) - gsk_gl_driver_release_texture (self, texture); -} - -typedef struct _GskGLTextureState -{ - GdkGLContext *context; - GLuint texture_id; - GLsync sync; -} GskGLTextureState; - -static void -create_texture_from_texture_destroy (gpointer data) -{ - GskGLTextureState *state = data; - - g_assert (state != NULL); - g_assert (GDK_IS_GL_CONTEXT (state->context)); - - gdk_gl_context_make_current (state->context); - glDeleteTextures (1, &state->texture_id); - if (state->sync) - glDeleteSync (state->sync); - g_clear_object (&state->context); - g_free (state); -} - -GdkTexture * -gsk_gl_driver_create_gdk_texture (GskGLDriver *self, - guint texture_id, - GdkMemoryFormat format) -{ - GskGLTextureState *state; - GdkGLTextureBuilder *builder; - GskGLTexture *texture; - GdkTexture *result; - - g_return_val_if_fail (GSK_IS_GL_DRIVER (self), NULL); - g_return_val_if_fail (self->command_queue != NULL, NULL); - g_return_val_if_fail (GDK_IS_GL_CONTEXT (self->command_queue->context), NULL); - g_return_val_if_fail (texture_id > 0, NULL); - g_return_val_if_fail (!g_hash_table_contains (self->texture_id_to_key, GUINT_TO_POINTER (texture_id)), NULL); - - /* We must be tracking this texture_id already to use it */ - if (!(texture = g_hash_table_lookup (self->textures, GUINT_TO_POINTER (texture_id)))) - g_return_val_if_reached (NULL); - - state = g_new0 (GskGLTextureState, 1); - state->texture_id = texture_id; - state->context = g_object_ref (self->shared_command_queue->context); - state->sync = glFenceSync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - - g_hash_table_steal (self->textures, GUINT_TO_POINTER (texture_id)); - - builder = gdk_gl_texture_builder_new (); - gdk_gl_texture_builder_set_context (builder, self->shared_command_queue->context); - gdk_gl_texture_builder_set_id (builder, texture_id); - gdk_gl_texture_builder_set_format (builder, format); - gdk_gl_texture_builder_set_width (builder, texture->width); - gdk_gl_texture_builder_set_height (builder, texture->height); - gdk_gl_texture_builder_set_sync (builder, state->sync); - - result = gdk_gl_texture_builder_build (builder, - create_texture_from_texture_destroy, - state); - - texture->texture_id = 0; - gsk_gl_texture_free (texture); - g_object_unref (builder); - - return result; -} diff --git a/gsk/gl/gskgldriverprivate.h b/gsk/gl/gskgldriverprivate.h deleted file mode 100644 index 9eb84b17a24828783df7e4d0813e0f167a7ff4d5..0000000000000000000000000000000000000000 --- a/gsk/gl/gskgldriverprivate.h +++ /dev/null @@ -1,261 +0,0 @@ -/* gskgldriverprivate.h - * - * Copyright 2020 Christian Hergert - * - * This file 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 file 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 General Public License along - * with this program. If not, see . - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#pragma once - -#include - -#include "gskgltypesprivate.h" -#include "gskgltextureprivate.h" - -G_BEGIN_DECLS - -enum { - UNIFORM_SHARED_ALPHA, - UNIFORM_SHARED_SOURCE, - UNIFORM_SHARED_CLIP_RECT, - UNIFORM_SHARED_VIEWPORT, - UNIFORM_SHARED_PROJECTION, - UNIFORM_SHARED_MODELVIEW, - - UNIFORM_SHARED_LAST -}; - -enum { - UNIFORM_CUSTOM_SIZE = UNIFORM_SHARED_LAST, - UNIFORM_CUSTOM_TEXTURE1, - UNIFORM_CUSTOM_TEXTURE2, - UNIFORM_CUSTOM_TEXTURE3, - UNIFORM_CUSTOM_TEXTURE4, - UNIFORM_CUSTOM_ARG0, - UNIFORM_CUSTOM_ARG1, - UNIFORM_CUSTOM_ARG2, - UNIFORM_CUSTOM_ARG3, - UNIFORM_CUSTOM_ARG4, - UNIFORM_CUSTOM_ARG5, - UNIFORM_CUSTOM_ARG6, - UNIFORM_CUSTOM_ARG7, - - UNIFORM_CUSTOM_LAST -}; - -typedef struct { - gconstpointer pointer; - float scale_x; - float scale_y; - int pointer_is_child; - graphene_rect_t parent_rect; /* Valid when pointer_is_child */ -} GskTextureKey; - -#define GSK_GL_NO_UNIFORMS CONCAT_EXPANDED(UNIFORM_INVALID_,__COUNTER__) -#define CONCAT_EXPANDED(a,b) CONCAT_EXPANDED2(a,b) -#define CONCAT_EXPANDED2(a,b) a##b -#define GSK_GL_ADD_UNIFORM(pos, KEY, name) UNIFORM_##KEY = UNIFORM_SHARED_LAST + pos, -#define GSK_GL_DEFINE_PROGRAM(name, resource, uniforms) enum { uniforms }; -#define GSK_GL_DEFINE_PROGRAM_NO_CLIP(name, resource, uniforms) enum { uniforms }; -# include "gskglprograms.defs" -#undef GSK_GL_DEFINE_PROGRAM_NO_CLIP -#undef GSK_GL_DEFINE_PROGRAM -#undef GSK_GL_ADD_UNIFORM -#undef GSK_GL_NO_UNIFORMS -#undef CONCAT_EXPANDED -#undef CONCAT_EXPANDED2 - -#define GSK_TYPE_GL_DRIVER (gsk_gl_driver_get_type()) - -G_DECLARE_FINAL_TYPE (GskGLDriver, gsk_gl_driver, GSK, GL_DRIVER, GObject) - -struct _GskGLRenderTarget -{ - guint framebuffer_id; - guint texture_id; - int format; - int width; - int height; -}; - -struct _GskGLDriver -{ - GObject parent_instance; - - GskGLCommandQueue *shared_command_queue; - GskGLCommandQueue *command_queue; - - GskGLGlyphLibrary *glyphs_library; - GskGLIconLibrary *icons_library; - GskGLShadowLibrary *shadows_library; - - GArray *texture_pool; - GHashTable *textures; - GHashTable *key_to_texture_id; - GHashTable *texture_id_to_key; - - GHashTable *shader_cache; - - GArray *autorelease_framebuffers; - GPtrArray *render_targets; - -#define GSK_GL_NO_UNIFORMS -#define GSK_GL_ADD_UNIFORM(pos, KEY, name) -#define GSK_GL_DEFINE_PROGRAM(name, resource, uniforms) \ - GskGLProgram *name ## _no_clip; \ - GskGLProgram *name ## _rect_clip; \ - GskGLProgram *name; -#define GSK_GL_DEFINE_PROGRAM_NO_CLIP(name, resource, uniforms) \ - GskGLProgram *name; -# include "gskglprograms.defs" -#undef GSK_GL_NO_UNIFORMS -#undef GSK_GL_ADD_UNIFORM -#undef GSK_GL_DEFINE_PROGRAM -#undef GSK_GL_DEFINE_PROGRAM_NO_CLIP - - gint64 current_frame_id; - - /* Used to reduce number of comparisons */ - guint stamps[UNIFORM_SHARED_LAST]; - - guint debug : 1; - guint in_frame : 1; -}; - -GskGLDriver * gsk_gl_driver_for_display (GdkDisplay *display, - gboolean debug_shaders, - GError **error); -GskGLCommandQueue * gsk_gl_driver_create_command_queue (GskGLDriver *self, - GdkGLContext *context); -GdkGLContext * gsk_gl_driver_get_context (GskGLDriver *self); -gboolean gsk_gl_driver_create_render_target (GskGLDriver *self, - int width, - int height, - int format, - GskGLRenderTarget **render_target); -guint gsk_gl_driver_release_render_target (GskGLDriver *self, - GskGLRenderTarget *render_target, - gboolean release_texture); -void gsk_gl_driver_begin_frame (GskGLDriver *self, - GskGLCommandQueue *command_queue); -void gsk_gl_driver_end_frame (GskGLDriver *self); -void gsk_gl_driver_after_frame (GskGLDriver *self); -GdkTexture * gsk_gl_driver_create_gdk_texture (GskGLDriver *self, - guint texture_id, - GdkMemoryFormat format); -void gsk_gl_driver_cache_texture (GskGLDriver *self, - const GskTextureKey *key, - guint texture_id); -guint gsk_gl_driver_load_texture (GskGLDriver *self, - GdkTexture *texture, - gboolean ensure_mipmap); -GskGLTexture * gsk_gl_driver_create_texture (GskGLDriver *self, - float width, - float height, - int format); -void gsk_gl_driver_release_texture (GskGLDriver *self, - GskGLTexture *texture); -void gsk_gl_driver_release_texture_by_id (GskGLDriver *self, - guint texture_id); -GskGLTexture * gsk_gl_driver_mark_texture_permanent (GskGLDriver *self, - guint texture_id); -void gsk_gl_driver_add_texture_slices (GskGLDriver *self, - GdkTexture *texture, - gboolean ensure_mipmap, - GskGLTextureSlice **out_slices, - guint *out_n_slices); -G_GNUC_BEGIN_IGNORE_DEPRECATIONS -GskGLProgram * gsk_gl_driver_lookup_shader (GskGLDriver *self, - GskGLShader *shader, - GError **error); -G_GNUC_END_IGNORE_DEPRECATIONS - -#if 0 -void gsk_gl_driver_save_texture_to_png (GskGLDriver *self, - int texture_id, - int width, - int height, - const char *filename); -void gsk_gl_driver_save_atlases_to_png (GskGLDriver *self, - const char *filename); -#endif - -static inline GskGLTexture * -gsk_gl_driver_get_texture_by_id (GskGLDriver *self, - guint texture_id) -{ - return g_hash_table_lookup (self->textures, GUINT_TO_POINTER (texture_id)); -} - -/** - * gsk_gl_driver_lookup_texture: - * @self: a `GskGLDriver` - * @key: the key for the texture - * @has_mipmap: (out): Return location for whether the texture has a mipmap - * - * Looks up a texture in the texture cache by @key. - * - * If the texture could not be found, then zero is returned. - * - * Returns: a positive integer if the texture was found; otherwise 0. - */ -static inline guint -gsk_gl_driver_lookup_texture (GskGLDriver *self, - const GskTextureKey *key, - gboolean *has_mipmap) -{ - gpointer id; - - if (g_hash_table_lookup_extended (self->key_to_texture_id, key, NULL, &id)) - { - GskGLTexture *texture = g_hash_table_lookup (self->textures, id); - - if (texture != NULL) - texture->last_used_in_frame = self->current_frame_id; - - if (has_mipmap) - *has_mipmap = texture ? texture->has_mipmap : FALSE; - - return GPOINTER_TO_UINT (id); - } - - return 0; -} - -static inline void -gsk_gl_driver_slice_texture (GskGLDriver *self, - GdkTexture *texture, - gboolean ensure_mipmap, - GskGLTextureSlice **out_slices, - guint *out_n_slices) -{ - GskGLTexture *t; - - t = gdk_texture_get_render_data (texture, self); - - if (t && t->slices && - (t->has_mipmap || !ensure_mipmap)) - { - *out_slices = t->slices; - *out_n_slices = t->n_slices; - return; - } - - gsk_gl_driver_add_texture_slices (self, texture, ensure_mipmap, out_slices, out_n_slices); -} - -G_END_DECLS - diff --git a/gsk/gl/gskglglyphlibrary.c b/gsk/gl/gskglglyphlibrary.c deleted file mode 100644 index c6d85f78093619d8aab44cb5da8e94f5eef61e1f..0000000000000000000000000000000000000000 --- a/gsk/gl/gskglglyphlibrary.c +++ /dev/null @@ -1,439 +0,0 @@ -/* gskglglyphlibrary.c - * - * Copyright 2020 Christian Hergert - * - * 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 . - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#include "config.h" - -#include -#include -#include - -#include "gskglcommandqueueprivate.h" -#include "gskgldriverprivate.h" -#include "gskglglyphlibraryprivate.h" - -#include "gskdebugprivate.h" - -#define MAX_GLYPH_SIZE 128 - -G_DEFINE_TYPE (GskGLGlyphLibrary, gsk_gl_glyph_library, GSK_TYPE_GL_TEXTURE_LIBRARY) - -GskGLGlyphLibrary * -gsk_gl_glyph_library_new (GskGLDriver *driver) -{ - g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), NULL); - - return g_object_new (GSK_TYPE_GL_GLYPH_LIBRARY, - "driver", driver, - NULL); -} - -static guint -gsk_gl_glyph_key_hash (gconstpointer data) -{ - const GskGLGlyphKey *key = data; - - /* We do not store the hash within the key because GHashTable will already - * store the hash value for us and so this is called only a single time per - * cached item. This saves an extra 4 bytes per GskGLGlyphKey which means on - * 64-bit, we fit nicely within 2 pointers (the smallest allocation size - * for GSlice). - */ - - return GPOINTER_TO_UINT (key->font) ^ - key->glyph ^ - (key->xshift << 24) ^ - (key->yshift << 26) ^ - key->scale; -} - -static gboolean -gsk_gl_glyph_key_equal (gconstpointer v1, - gconstpointer v2) -{ - return memcmp (v1, v2, sizeof (GskGLGlyphKey)) == 0; -} - -static void -gsk_gl_glyph_key_free (gpointer data) -{ - GskGLGlyphKey *key = data; - - g_clear_object (&key->font); - g_free (key); -} - -static void -gsk_gl_glyph_value_free (gpointer data) -{ - g_free (data); -} - -static void -gsk_gl_glyph_library_clear_cache (GskGLTextureLibrary *library) -{ - GskGLGlyphLibrary *self = (GskGLGlyphLibrary *)library; - - g_assert (GSK_IS_GL_GLYPH_LIBRARY (self)); - - memset (self->front, 0, sizeof self->front); -} - -static void -gsk_gl_glyph_library_init_atlas (GskGLTextureLibrary *self, - GskGLTextureAtlas *atlas) -{ - gboolean packed G_GNUC_UNUSED; - int x, y; - guint gl_format; - guint gl_type; - guint8 pixel_data[4 * 3 * 3]; - - g_assert (GSK_IS_GL_GLYPH_LIBRARY (self)); - g_assert (atlas != NULL); - - /* Insert a single pixel at 0,0 for use in coloring */ - - gdk_gl_context_push_debug_group_printf (gdk_gl_context_get_current (), - "Initializing Atlas"); - - packed = gsk_gl_texture_library_allocate (self, atlas, 3, 3, &x, &y); - g_assert (packed); - g_assert (x == 0 && y == 0); - - memset (pixel_data, 255, sizeof pixel_data); - - if (gdk_gl_context_get_use_es (gdk_gl_context_get_current ())) - { - gl_format = GL_RGBA; - gl_type = GL_UNSIGNED_BYTE; - } - else - { - gl_format = GL_BGRA; - gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; - } - glBindTexture (GL_TEXTURE_2D, atlas->texture_id); - - glTexSubImage2D (GL_TEXTURE_2D, 0, - 0, 0, - 3, 3, - gl_format, gl_type, - pixel_data); - - gdk_gl_context_pop_debug_group (gdk_gl_context_get_current ()); - - self->driver->command_queue->n_uploads++; -} - - -static void -gsk_gl_glyph_library_finalize (GObject *object) -{ - GskGLGlyphLibrary *self = (GskGLGlyphLibrary *)object; - - g_clear_pointer (&self->surface_data, g_free); - - G_OBJECT_CLASS (gsk_gl_glyph_library_parent_class)->finalize (object); -} - -static void -gsk_gl_glyph_library_class_init (GskGLGlyphLibraryClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GskGLTextureLibraryClass *library_class = GSK_GL_TEXTURE_LIBRARY_CLASS (klass); - - object_class->finalize = gsk_gl_glyph_library_finalize; - - library_class->clear_cache = gsk_gl_glyph_library_clear_cache; - library_class->init_atlas = gsk_gl_glyph_library_init_atlas; -} - -static void -gsk_gl_glyph_library_init (GskGLGlyphLibrary *self) -{ - GskGLTextureLibrary *tl = (GskGLTextureLibrary *)self; - - tl->max_entry_size = MAX_GLYPH_SIZE; - gsk_gl_texture_library_set_funcs (tl, - gsk_gl_glyph_key_hash, - gsk_gl_glyph_key_equal, - gsk_gl_glyph_key_free, - gsk_gl_glyph_value_free); -} - -static cairo_surface_t * -gsk_gl_glyph_library_create_surface (GskGLGlyphLibrary *self, - int stride, - int width, - int height, - int uwidth, - int uheight) -{ - cairo_surface_t *surface; - gsize n_bytes; - - g_assert (GSK_IS_GL_GLYPH_LIBRARY (self)); - g_assert (width > 0); - g_assert (height > 0); - - n_bytes = stride * height; - - if G_LIKELY (n_bytes > self->surface_data_len) - { - self->surface_data = g_realloc (self->surface_data, n_bytes); - self->surface_data_len = n_bytes; - } - - memset (self->surface_data, 0, n_bytes); - surface = cairo_image_surface_create_for_data (self->surface_data, - CAIRO_FORMAT_ARGB32, - width, height, stride); - cairo_surface_set_device_scale (surface, width / (double)uwidth, height / (double)uheight); - - return surface; -} - -static void -render_glyph (cairo_surface_t *surface, - const GskGLGlyphKey *key, - const GskGLGlyphValue *value) -{ - cairo_t *cr; - PangoGlyphString glyph_string; - PangoGlyphInfo glyph_info; - - g_assert (surface != NULL); - - cr = cairo_create (surface); - cairo_set_source_rgba (cr, 1, 1, 1, 1); - - glyph_info.glyph = key->glyph; - glyph_info.geometry.width = value->ink_rect.width * 1024; - glyph_info.geometry.x_offset = (0.25 * key->xshift - value->ink_rect.x) * 1024; - glyph_info.geometry.y_offset = (0.25 * key->yshift - value->ink_rect.y) * 1024; - - glyph_string.num_glyphs = 1; - glyph_string.glyphs = &glyph_info; - - pango_cairo_show_glyph_string (cr, key->font, &glyph_string); - cairo_destroy (cr); - - cairo_surface_flush (surface); -} - -static void -gsk_gl_glyph_library_upload_glyph (GskGLGlyphLibrary *self, - const GskGLGlyphKey *key, - const GskGLGlyphValue *value, - int packed_x, - int packed_y, - int width, - int height, - int uwidth, - int uheight) -{ - GskGLTextureLibrary *tl = (GskGLTextureLibrary *)self; - G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME; - cairo_surface_t *surface; - guchar *pixel_data; - guchar *free_data = NULL; - guint gl_format; - guint gl_type; - guint texture_id; - gsize stride; - - g_assert (GSK_IS_GL_GLYPH_LIBRARY (self)); - g_assert (key != NULL); - g_assert (value != NULL); - - stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, width); - - gdk_gl_context_push_debug_group_printf (gdk_gl_context_get_current (), - "Uploading glyph %d", - key->glyph); - - surface = gsk_gl_glyph_library_create_surface (self, stride, width, height, uwidth, uheight); - render_glyph (surface, key, value); - - texture_id = GSK_GL_TEXTURE_ATLAS_ENTRY_TEXTURE (value); - - g_assert (texture_id > 0); - - if (gdk_gl_context_get_use_es (gdk_gl_context_get_current ())) - { - pixel_data = free_data = g_malloc (width * height * 4); - gdk_memory_convert (pixel_data, width * 4, - GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, - GDK_COLOR_STATE_SRGB, - cairo_image_surface_get_data (surface), - stride, - GDK_MEMORY_DEFAULT, - GDK_COLOR_STATE_SRGB, - width, height); - stride = width * 4; - gl_format = GL_RGBA; - gl_type = GL_UNSIGNED_BYTE; - } - else - { - pixel_data = cairo_image_surface_get_data (surface); - gl_format = GL_BGRA; - gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; - } - - glPixelStorei (GL_UNPACK_ROW_LENGTH, stride / 4); - glBindTexture (GL_TEXTURE_2D, texture_id); - - glTexSubImage2D (GL_TEXTURE_2D, 0, - packed_x + 1, packed_y + 1, - width, height, - gl_format, gl_type, - pixel_data); - - /* Padding top */ - glTexSubImage2D (GL_TEXTURE_2D, 0, - packed_x + 1, packed_y, - width, 1, - gl_format, gl_type, - pixel_data); - /* Padding left */ - glTexSubImage2D (GL_TEXTURE_2D, 0, - packed_x, packed_y + 1, - 1, height, - gl_format, gl_type, - pixel_data); - /* Padding top left */ - glTexSubImage2D (GL_TEXTURE_2D, 0, - packed_x, packed_y, - 1, 1, - gl_format, gl_type, - pixel_data); - /* Padding right */ - glPixelStorei (GL_UNPACK_ROW_LENGTH, width); - glPixelStorei (GL_UNPACK_SKIP_PIXELS, width - 1); - glTexSubImage2D (GL_TEXTURE_2D, 0, - packed_x + width + 1, packed_y + 1, - 1, height, - gl_format, gl_type, - pixel_data); - /* Padding top right */ - glTexSubImage2D (GL_TEXTURE_2D, 0, - packed_x + width + 1, packed_y, - 1, 1, - gl_format, gl_type, - pixel_data); - /* Padding bottom */ - glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0); - glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); - glPixelStorei (GL_UNPACK_SKIP_ROWS, height - 1); - glTexSubImage2D (GL_TEXTURE_2D, 0, - packed_x + 1, packed_y + 1 + height, - width, 1, - gl_format, gl_type, - pixel_data); - /* Padding bottom left */ - glTexSubImage2D (GL_TEXTURE_2D, 0, - packed_x, packed_y + 1 + height, - 1, 1, - gl_format, gl_type, - pixel_data); - /* Padding bottom right */ - glPixelStorei (GL_UNPACK_ROW_LENGTH, width); - glPixelStorei (GL_UNPACK_SKIP_PIXELS, width - 1); - glTexSubImage2D (GL_TEXTURE_2D, 0, - packed_x + 1 + width, packed_y + 1 + height, - 1, 1, - gl_format, gl_type, - pixel_data); - /* Reset this */ - glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0); - glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); - glPixelStorei (GL_UNPACK_SKIP_ROWS, 0); - - cairo_surface_destroy (surface); - g_free (free_data); - - gdk_gl_context_pop_debug_group (gdk_gl_context_get_current ()); - - tl->driver->command_queue->n_uploads++; - - if (gdk_profiler_is_running ()) - { - char message[64]; - g_snprintf (message, sizeof message, "Size %dx%d", width, height); - gdk_profiler_add_mark (start_time, GDK_PROFILER_CURRENT_TIME-start_time, "Upload glyph", message); - } -} - -gboolean -gsk_gl_glyph_library_add (GskGLGlyphLibrary *self, - GskGLGlyphKey *key, - const GskGLGlyphValue **out_value) -{ - GskGLTextureLibrary *tl = (GskGLTextureLibrary *)self; - PangoRectangle ink_rect; - GskGLGlyphValue *value; - int width; - int height; - guint packed_x; - guint packed_y; - - g_assert (GSK_IS_GL_GLYPH_LIBRARY (self)); - g_assert (key != NULL); - g_assert (out_value != NULL); - - pango_font_get_glyph_extents (key->font, key->glyph, &ink_rect, NULL); - pango_extents_to_pixels (&ink_rect, NULL); - - ink_rect.x -= 1; - ink_rect.width += 2; - ink_rect.y -= 1; - ink_rect.height += 2; - - width = (int) ceil (ink_rect.width * key->scale / 1024.0); - height = (int) ceil (ink_rect.height * key->scale / 1024.0); - - GSK_DEBUG (CACHE, "font %p glyph %u: %u x %u pixels", key->font, key->glyph, width, height); - - value = gsk_gl_texture_library_pack (tl, - key, - sizeof *value, - width, - height, - 1, - &packed_x, &packed_y); - - memcpy (&value->ink_rect, &ink_rect, sizeof ink_rect); - - if (key->scale > 0 && width > 0 && height > 0) - gsk_gl_glyph_library_upload_glyph (self, - key, - value, - packed_x, - packed_y, - width, - height, - ink_rect.width, - ink_rect.height); - - *out_value = value; - - return GSK_GL_TEXTURE_ATLAS_ENTRY_TEXTURE (value) != 0; -} diff --git a/gsk/gl/gskglglyphlibraryprivate.h b/gsk/gl/gskglglyphlibraryprivate.h deleted file mode 100644 index b3022b4630f45cf390fb213daa6595a1d3771253..0000000000000000000000000000000000000000 --- a/gsk/gl/gskglglyphlibraryprivate.h +++ /dev/null @@ -1,103 +0,0 @@ -/* gskglglyphlibraryprivate.h - * - * Copyright 2020 Christian Hergert - * - * 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 . - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#pragma once - -#include - -#include "gskgltexturelibraryprivate.h" - -G_BEGIN_DECLS - -#define GSK_TYPE_GL_GLYPH_LIBRARY (gsk_gl_glyph_library_get_type()) - -typedef struct _GskGLGlyphKey -{ - PangoFont *font; - PangoGlyph glyph; - guint xshift : 2; - guint yshift : 2; - guint scale : 28; /* times 1024 */ -} GskGLGlyphKey; - -typedef struct _GskGLGlyphValue -{ - GskGLTextureAtlasEntry entry; - PangoRectangle ink_rect; -} GskGLGlyphValue; - -#if GLIB_SIZEOF_VOID_P == 8 -G_STATIC_ASSERT (sizeof (GskGLGlyphKey) == 16); -#elif GLIB_SIZEOF_VOID_P == 4 -G_STATIC_ASSERT (sizeof (GskGLGlyphKey) == 12); -#endif - -G_DECLARE_FINAL_TYPE (GskGLGlyphLibrary, gsk_gl_glyph_library, GSK, GL_GLYPH_LIBRARY, GskGLTextureLibrary) - -struct _GskGLGlyphLibrary -{ - GskGLTextureLibrary parent_instance; - guint8 *surface_data; - gsize surface_data_len; - struct { - GskGLGlyphKey key; - const GskGLGlyphValue *value; - } front[256]; -}; - -GskGLGlyphLibrary *gsk_gl_glyph_library_new (GskGLDriver *driver); -gboolean gsk_gl_glyph_library_add (GskGLGlyphLibrary *self, - GskGLGlyphKey *key, - const GskGLGlyphValue **out_value); - -static inline guint -gsk_gl_glyph_library_lookup_or_add (GskGLGlyphLibrary *self, - const GskGLGlyphKey *key, - const GskGLGlyphValue **out_value) -{ - GskGLTextureAtlasEntry *entry; - guint front_index = ((key->glyph << 2) | key->xshift) & 0xFF; - - if (memcmp (key, &self->front[front_index], sizeof *key) == 0) - { - *out_value = self->front[front_index].value; - } - else if (gsk_gl_texture_library_lookup ((GskGLTextureLibrary *)self, key, &entry)) - { - *out_value = (GskGLGlyphValue *)entry; - self->front[front_index].key = *key; - self->front[front_index].value = *out_value; - } - else - { - GskGLGlyphKey *k; - k = g_new (GskGLGlyphKey, 1); - memcpy (k, key, sizeof (GskGLGlyphKey)); - g_object_ref (k->font); - gsk_gl_glyph_library_add (self, k, out_value); - self->front[front_index].key = *key; - self->front[front_index].value = *out_value; - } - - return GSK_GL_TEXTURE_ATLAS_ENTRY_TEXTURE (*out_value); -} - -G_END_DECLS - diff --git a/gsk/gl/gskgliconlibrary.c b/gsk/gl/gskgliconlibrary.c deleted file mode 100644 index 63b25dea4b71d644da6052858df88ebf28e2214e..0000000000000000000000000000000000000000 --- a/gsk/gl/gskgliconlibrary.c +++ /dev/null @@ -1,212 +0,0 @@ -/* gskgliconlibrary.c - * - * Copyright 2020 Christian Hergert - * - * 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 . - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include "gskglcommandqueueprivate.h" -#include "gskgldriverprivate.h" -#include "gskgliconlibraryprivate.h" - -struct _GskGLIconLibrary -{ - GskGLTextureLibrary parent_instance; -}; - -G_DEFINE_TYPE (GskGLIconLibrary, gsk_gl_icon_library, GSK_TYPE_GL_TEXTURE_LIBRARY) - -GskGLIconLibrary * -gsk_gl_icon_library_new (GskGLDriver *driver) -{ - g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), NULL); - - return g_object_new (GSK_TYPE_GL_ICON_LIBRARY, - "driver", driver, - NULL); -} - -static void -gsk_gl_icon_data_free (gpointer data) -{ - GskGLIconData *icon_data = data; - - g_clear_object (&icon_data->source_texture); - g_free (icon_data); -} - -static void -gsk_gl_icon_library_class_init (GskGLIconLibraryClass *klass) -{ -} - -static void -gsk_gl_icon_library_init (GskGLIconLibrary *self) -{ - GskGLTextureLibrary *tl = (GskGLTextureLibrary *)self; - - tl->max_entry_size = 128; - gsk_gl_texture_library_set_funcs (tl, - NULL, NULL, NULL, - gsk_gl_icon_data_free); -} - -void -gsk_gl_icon_library_add (GskGLIconLibrary *self, - GdkTexture *key, - const GskGLIconData **out_value) -{ - GskGLTextureLibrary *tl = (GskGLTextureLibrary *)self; - G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME; - GskGLIconData *icon_data; - GdkTextureDownloader downloader; - guint8 *pixel_data; - guint gl_format; - guint gl_type; - guint packed_x; - guint packed_y; - int width; - int height; - guint texture_id; - - g_assert (GSK_IS_GL_ICON_LIBRARY (self)); - g_assert (GDK_IS_TEXTURE (key)); - g_assert (out_value != NULL); - - width = key->width; - height = key->height; - - icon_data = gsk_gl_texture_library_pack (tl, - key, - sizeof (GskGLIconData), - width, height, 1, - &packed_x, &packed_y); - icon_data->source_texture = g_object_ref (key); - - /* actually upload the texture */ - gdk_texture_downloader_init (&downloader, key); - gdk_gl_context_push_debug_group_printf (gdk_gl_context_get_current (), - "Uploading texture"); - - if (gdk_gl_context_get_use_es (gdk_gl_context_get_current ())) - { - gdk_texture_downloader_set_format (&downloader, GDK_MEMORY_R8G8B8A8_PREMULTIPLIED); - gl_format = GL_RGBA; - gl_type = GL_UNSIGNED_BYTE; - } - else - { - gdk_texture_downloader_set_format (&downloader, GDK_MEMORY_DEFAULT); - gl_format = GL_BGRA; - gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; - } - pixel_data = g_malloc (width * height * 4); - gdk_texture_downloader_download_into (&downloader, pixel_data, width * 4); - gdk_texture_downloader_finish (&downloader); - - texture_id = GSK_GL_TEXTURE_ATLAS_ENTRY_TEXTURE (icon_data); - - glBindTexture (GL_TEXTURE_2D, texture_id); - - glTexSubImage2D (GL_TEXTURE_2D, 0, - packed_x + 1, packed_y + 1, - width, height, - gl_format, gl_type, - pixel_data); - /* Padding top */ - glTexSubImage2D (GL_TEXTURE_2D, 0, - packed_x + 1, packed_y, - width, 1, - gl_format, gl_type, - pixel_data); - /* Padding left */ - glPixelStorei (GL_UNPACK_ROW_LENGTH, width); - glTexSubImage2D (GL_TEXTURE_2D, 0, - packed_x, packed_y + 1, - 1, height, - gl_format, gl_type, - pixel_data); - /* Padding top left */ - glTexSubImage2D (GL_TEXTURE_2D, 0, - packed_x, packed_y, - 1, 1, - gl_format, gl_type, - pixel_data); - - /* Padding right */ - glPixelStorei (GL_UNPACK_SKIP_PIXELS, width - 1); - glTexSubImage2D (GL_TEXTURE_2D, 0, - packed_x + width + 1, packed_y + 1, - 1, height, - gl_format, gl_type, - pixel_data); - /* Padding top right */ - glTexSubImage2D (GL_TEXTURE_2D, 0, - packed_x + width + 1, packed_y, - 1, 1, - gl_format, gl_type, - pixel_data); - /* Padding bottom */ - glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0); - glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); - glPixelStorei (GL_UNPACK_SKIP_ROWS, height - 1); - glTexSubImage2D (GL_TEXTURE_2D, 0, - packed_x + 1, packed_y + 1 + height, - width, 1, - gl_format, gl_type, - pixel_data); - /* Padding bottom left */ - glTexSubImage2D (GL_TEXTURE_2D, 0, - packed_x, packed_y + 1 + height, - 1, 1, - gl_format, gl_type, - pixel_data); - /* Padding bottom right */ - glPixelStorei (GL_UNPACK_ROW_LENGTH, width); - glPixelStorei (GL_UNPACK_SKIP_PIXELS, width - 1); - glTexSubImage2D (GL_TEXTURE_2D, 0, - packed_x + 1 + width, packed_y + 1 + height, - 1, 1, - gl_format, gl_type, - pixel_data); - /* Reset this */ - glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0); - glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); - glPixelStorei (GL_UNPACK_SKIP_ROWS, 0); - - gdk_gl_context_pop_debug_group (gdk_gl_context_get_current ()); - - *out_value = icon_data; - - g_free (pixel_data); - - tl->driver->command_queue->n_uploads++; - - if (gdk_profiler_is_running ()) - { - char message[64]; - g_snprintf (message, sizeof message, "Size %dx%d", width, height); - gdk_profiler_add_mark (start_time, GDK_PROFILER_CURRENT_TIME-start_time, "Upload icon", message); - } -} diff --git a/gsk/gl/gskgliconlibraryprivate.h b/gsk/gl/gskgliconlibraryprivate.h deleted file mode 100644 index dc99b546ce93c058b9c52e4a92be4b2c46efa7ad..0000000000000000000000000000000000000000 --- a/gsk/gl/gskgliconlibraryprivate.h +++ /dev/null @@ -1,58 +0,0 @@ -/* gskgliconlibraryprivate.h - * - * Copyright 2020 Christian Hergert - * - * 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 . - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#pragma once - -#include - -#include "gskgltexturelibraryprivate.h" - -G_BEGIN_DECLS - -#define GSK_TYPE_GL_ICON_LIBRARY (gsk_gl_icon_library_get_type()) - -typedef struct _GskGLIconData -{ - GskGLTextureAtlasEntry entry; - GdkTexture *source_texture; -} GskGLIconData; - -G_DECLARE_FINAL_TYPE (GskGLIconLibrary, gsk_gl_icon_library, GSK, GL_ICON_LIBRARY, GskGLTextureLibrary) - -GskGLIconLibrary *gsk_gl_icon_library_new (GskGLDriver *driver); -void gsk_gl_icon_library_add (GskGLIconLibrary *self, - GdkTexture *key, - const GskGLIconData **out_value); - -static inline void -gsk_gl_icon_library_lookup_or_add (GskGLIconLibrary *self, - GdkTexture *key, - const GskGLIconData **out_value) -{ - GskGLTextureAtlasEntry *entry; - - if G_LIKELY (gsk_gl_texture_library_lookup ((GskGLTextureLibrary *)self, key, &entry)) - *out_value = (GskGLIconData *)entry; - else - gsk_gl_icon_library_add (self, key, out_value); -} - -G_END_DECLS - diff --git a/gsk/gl/gskglprofiler.c b/gsk/gl/gskglprofiler.c deleted file mode 100644 index 6aff5ab0a50be5e633d135dcaa8cbb495f77bba8..0000000000000000000000000000000000000000 --- a/gsk/gl/gskglprofiler.c +++ /dev/null @@ -1,179 +0,0 @@ -#include "config.h" - -#include "gskglprofilerprivate.h" - -#include - -#define N_QUERIES 4 - -struct _GskGLProfiler -{ - GObject parent_instance; - - GdkGLContext *gl_context; - - /* Creating GL queries is kind of expensive, so we pay the - * price upfront and create a circular buffer of queries - */ - GLuint gl_queries[N_QUERIES]; - GLuint active_query; - - unsigned int has_queries : 1; - unsigned int has_timer : 1; - unsigned int first_frame : 1; -}; - -enum { - PROP_GL_CONTEXT = 1, - - N_PROPERTIES -}; - -static GParamSpec *gsk_gl_profiler_properties[N_PROPERTIES]; - -G_DEFINE_TYPE (GskGLProfiler, gsk_gl_profiler, G_TYPE_OBJECT) - -static void -gsk_gl_profiler_finalize (GObject *gobject) -{ - GskGLProfiler *self = GSK_GL_PROFILER (gobject); - - if (self->has_queries) - glDeleteQueries (N_QUERIES, self->gl_queries); - - g_clear_object (&self->gl_context); - - G_OBJECT_CLASS (gsk_gl_profiler_parent_class)->finalize (gobject); -} - -static void -gsk_gl_profiler_set_property (GObject *gobject, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GskGLProfiler *self = GSK_GL_PROFILER (gobject); - - switch (prop_id) - { - case PROP_GL_CONTEXT: - self->gl_context = g_value_dup_object (value); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); - } -} - -static void -gsk_gl_profiler_get_property (GObject *gobject, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GskGLProfiler *self = GSK_GL_PROFILER (gobject); - - switch (prop_id) - { - case PROP_GL_CONTEXT: - g_value_set_object (value, self->gl_context); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); - } -} - -static void -gsk_gl_profiler_class_init (GskGLProfilerClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->set_property = gsk_gl_profiler_set_property; - gobject_class->get_property = gsk_gl_profiler_get_property; - gobject_class->finalize = gsk_gl_profiler_finalize; - - gsk_gl_profiler_properties[PROP_GL_CONTEXT] = - g_param_spec_object ("gl-context", NULL, NULL, - GDK_TYPE_GL_CONTEXT, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties (gobject_class, N_PROPERTIES, gsk_gl_profiler_properties); -} - -static void -gsk_gl_profiler_init (GskGLProfiler *self) -{ - self->has_queries = epoxy_is_desktop_gl(); - self->has_timer = epoxy_is_desktop_gl() && (epoxy_gl_version () >= 33 || epoxy_has_gl_extension ("GL_ARB_timer_query")); - - if (!self->has_queries) - return; - - glGenQueries (N_QUERIES, self->gl_queries); - self->first_frame = TRUE; -} - -GskGLProfiler * -gsk_gl_profiler_new (GdkGLContext *context) -{ - g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL); - - return g_object_new (GSK_TYPE_GL_PROFILER, "gl-context", context, NULL); -} - -void -gsk_gl_profiler_begin_gpu_region (GskGLProfiler *profiler) -{ - GLuint query_id; - - g_return_if_fail (GSK_IS_GL_PROFILER (profiler)); - - if (!profiler->has_timer || !profiler->has_queries) - return; - - query_id = profiler->gl_queries[profiler->active_query]; - glBeginQuery (GL_TIME_ELAPSED, query_id); -} - -guint64 -gsk_gl_profiler_end_gpu_region (GskGLProfiler *profiler) -{ - GLuint last_query_id; - GLint res; - GLuint64 elapsed; - - g_return_val_if_fail (GSK_IS_GL_PROFILER (profiler), 0); - - if (!profiler->has_timer || !profiler->has_queries) - return 0; - - glEndQuery (GL_TIME_ELAPSED); - - if (profiler->active_query == 0) - last_query_id = N_QUERIES - 1; - else - last_query_id = profiler->active_query - 1; - - /* Advance iterator */ - profiler->active_query += 1; - if (profiler->active_query == N_QUERIES) - profiler->active_query = 0; - - /* If this is the first frame we already have a result */ - if (profiler->first_frame) - { - profiler->first_frame = FALSE; - return 0; - } - - glGetQueryObjectiv (profiler->gl_queries[last_query_id], GL_QUERY_RESULT_AVAILABLE, &res); - if (res == 1) - glGetQueryObjectui64v (profiler->gl_queries[last_query_id], GL_QUERY_RESULT, &elapsed); - else - elapsed = 0; - - return elapsed / 1000; /* Convert to usec to match other profiler APIs */ -} diff --git a/gsk/gl/gskglprofilerprivate.h b/gsk/gl/gskglprofilerprivate.h deleted file mode 100644 index 3aa0650c11768fe7dc7892892b00b778775911c3..0000000000000000000000000000000000000000 --- a/gsk/gl/gskglprofilerprivate.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include - -G_BEGIN_DECLS - -#define GSK_TYPE_GL_PROFILER (gsk_gl_profiler_get_type ()) -G_DECLARE_FINAL_TYPE (GskGLProfiler, gsk_gl_profiler, GSK, GL_PROFILER, GObject) - -GskGLProfiler * gsk_gl_profiler_new (GdkGLContext *context); - -void gsk_gl_profiler_begin_gpu_region (GskGLProfiler *profiler); -guint64 gsk_gl_profiler_end_gpu_region (GskGLProfiler *profiler); - -G_END_DECLS - diff --git a/gsk/gl/gskglprogram.c b/gsk/gl/gskglprogram.c deleted file mode 100644 index 728828459323ffc727a5e27e00cd015ce0307dc7..0000000000000000000000000000000000000000 --- a/gsk/gl/gskglprogram.c +++ /dev/null @@ -1,173 +0,0 @@ -/* gskglprogram.c - * - * Copyright 2020 Christian Hergert - * - * 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 . - * - * 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 have - * 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; -} diff --git a/gsk/gl/gskglprogramprivate.h b/gsk/gl/gskglprogramprivate.h deleted file mode 100644 index 6bfbe48f024cc0c615e0c9ace115d91aa5401331..0000000000000000000000000000000000000000 --- a/gsk/gl/gskglprogramprivate.h +++ /dev/null @@ -1,318 +0,0 @@ -/* gskglprogramprivate.h - * - * Copyright 2020 Christian Hergert - * - * 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 . - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#pragma once - -#include "gskgltypesprivate.h" - -#include "gskglattachmentstateprivate.h" -#include "gskglcommandqueueprivate.h" -#include "gskgldriverprivate.h" - -G_BEGIN_DECLS - -#define GSK_TYPE_GL_PROGRAM (gsk_gl_program_get_type()) -#define GSK_GL_PROGRAM_MAX_CUSTOM_TEXTURES 4 -#define GSK_GL_PROGRAM_MAX_CUSTOM_ARGS 8 - -G_DECLARE_FINAL_TYPE (GskGLProgram, gsk_gl_program, GSK, GL_PROGRAM, GObject) - -struct _GskGLProgram -{ - GObject parent_instance; - - int id; - char *name; - GskGLDriver *driver; - - /* Cached pointer to avoid lots of pointer chasing/lookups */ - GskGLUniformState *uniforms; - GskGLUniformProgram *program_info; - - /* Static array for key->location transforms */ - GskGLUniformMapping mappings[32]; - guint n_mappings; -}; - -GskGLProgram * gsk_gl_program_new (GskGLDriver *driver, - const char *name, - int program_id); -gboolean gsk_gl_program_add_uniform (GskGLProgram *self, - const char *name, - guint key); -void gsk_gl_program_uniforms_added (GskGLProgram *self, - gboolean has_attachments); -void gsk_gl_program_delete (GskGLProgram *self); - -static inline void -gsk_gl_program_set_uniform1fv (GskGLProgram *self, - guint key, - guint stamp, - guint count, - const float *values) -{ - gsk_gl_uniform_state_set1fv (self->uniforms, self->program_info, - key, - stamp, - count, - values); -} - -static inline void -gsk_gl_program_set_uniform2fv (GskGLProgram *self, - guint key, - guint stamp, - guint count, - const float *values) -{ - gsk_gl_uniform_state_set2fv (self->uniforms, self->program_info, - key, - stamp, - count, - values); -} - -static inline void -gsk_gl_program_set_uniform4fv (GskGLProgram *self, - guint key, - guint stamp, - guint count, - const float *values) -{ - gsk_gl_uniform_state_set4fv (self->uniforms, self->program_info, - key, - stamp, - count, - values); -} - -static inline void -gsk_gl_program_set_uniform_rounded_rect (GskGLProgram *self, - guint key, - guint stamp, - const GskRoundedRect *rounded_rect) -{ - gsk_gl_uniform_state_set_rounded_rect (self->uniforms, self->program_info, - key, - stamp, - rounded_rect); -} - -static inline void -gsk_gl_program_set_uniform1i (GskGLProgram *self, - guint key, - guint stamp, - int value0) -{ - gsk_gl_uniform_state_set1i (self->uniforms, - self->program_info, - key, - stamp, - value0); -} - -static inline void -gsk_gl_program_set_uniform2i (GskGLProgram *self, - guint key, - guint stamp, - int value0, - int value1) -{ - gsk_gl_uniform_state_set2i (self->uniforms, - self->program_info, - key, - stamp, - value0, value1); -} - -static inline void -gsk_gl_program_set_uniform3i (GskGLProgram *self, - guint key, - guint stamp, - int value0, - int value1, - int value2) -{ - gsk_gl_uniform_state_set3i (self->uniforms, - self->program_info, - key, - stamp, - value0, value1, value2); -} - -static inline void -gsk_gl_program_set_uniform4i (GskGLProgram *self, - guint key, - guint stamp, - int value0, - int value1, - int value2, - int value3) -{ - gsk_gl_uniform_state_set4i (self->uniforms, - self->program_info, - key, - stamp, - value0, value1, value2, value3); -} - -static inline void -gsk_gl_program_set_uniform1f (GskGLProgram *self, - guint key, - guint stamp, - float value0) -{ - gsk_gl_uniform_state_set1f (self->uniforms, - self->program_info, - key, - stamp, - value0); -} - -static inline void -gsk_gl_program_set_uniform2f (GskGLProgram *self, - guint key, - guint stamp, - float value0, - float value1) -{ - gsk_gl_uniform_state_set2f (self->uniforms, - self->program_info, - key, - stamp, - value0, value1); -} - -static inline void -gsk_gl_program_set_uniform3f (GskGLProgram *self, - guint key, - guint stamp, - float value0, - float value1, - float value2) -{ - gsk_gl_uniform_state_set3f (self->uniforms, - self->program_info, - key, - stamp, - value0, value1, value2); -} - -static inline void -gsk_gl_program_set_uniform4f (GskGLProgram *self, - guint key, - guint stamp, - float value0, - float value1, - float value2, - float value3) -{ - gsk_gl_uniform_state_set4f (self->uniforms, - self->program_info, - key, - stamp, - value0, value1, value2, value3); -} - -static inline void -gsk_gl_program_set_uniform_color (GskGLProgram *self, - guint key, - guint stamp, - const GdkRGBA *color) -{ - gsk_gl_uniform_state_set_color (self->uniforms, - self->program_info, - key, - stamp, - color); -} - -static inline void -gsk_gl_program_set_uniform_texture_with_filter (GskGLProgram *self, - guint key, - guint stamp, - GLenum texture_target, - GLenum texture_slot, - guint texture_id, - GLint min_filter, - GLint mag_filter) -{ - gsk_gl_attachment_state_bind_texture (self->driver->command_queue->attachments, - texture_target, - texture_slot, - texture_id, - min_filter, - mag_filter); - gsk_gl_uniform_state_set_texture (self->uniforms, - self->program_info, - key, - stamp, - texture_slot); -} - -static inline void -gsk_gl_program_set_uniform_texture (GskGLProgram *self, - guint key, - guint stamp, - GLenum texture_target, - GLenum texture_slot, - guint texture_id) -{ - gsk_gl_program_set_uniform_texture_with_filter (self, - key, - stamp, - texture_target, - texture_slot, - texture_id, - GL_LINEAR, - GL_LINEAR); -} - -static inline void -gsk_gl_program_set_uniform_texture_with_sync (GskGLProgram *self, - guint key, - guint stamp, - GLenum texture_target, - GLenum texture_slot, - guint texture_id, - GLint min_filter, - GLint max_filter, - gpointer sync) -{ - gsk_gl_program_set_uniform_texture_with_filter (self, key, stamp, texture_target, texture_slot, texture_id, - min_filter, max_filter); - gsk_gl_syncs_add_sync (&self->driver->command_queue->syncs, texture_id, sync); -} - -static inline void -gsk_gl_program_set_uniform_matrix (GskGLProgram *self, - guint key, - guint stamp, - const graphene_matrix_t *matrix) -{ - gsk_gl_uniform_state_set_matrix (self->uniforms, - self->program_info, - key, - stamp, - matrix); -} - -G_END_DECLS - diff --git a/gsk/gl/gskglprograms.defs b/gsk/gl/gskglprograms.defs deleted file mode 100644 index 0eabd8a9bd289eddfc4793088e282981a058d89b..0000000000000000000000000000000000000000 --- a/gsk/gl/gskglprograms.defs +++ /dev/null @@ -1,104 +0,0 @@ -GSK_GL_DEFINE_PROGRAM (blend, - GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("blend.glsl")), - GSK_GL_ADD_UNIFORM (1, BLEND_SOURCE2, u_source2) - GSK_GL_ADD_UNIFORM (2, BLEND_MODE, u_mode)) - -GSK_GL_DEFINE_PROGRAM (blit, - GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("blit.glsl")), - GSK_GL_NO_UNIFORMS) - -GSK_GL_DEFINE_PROGRAM (blur, - GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("blur.glsl")), - GSK_GL_ADD_UNIFORM (1, BLUR_RADIUS, u_blur_radius) - GSK_GL_ADD_UNIFORM (2, BLUR_SIZE, u_blur_size) - GSK_GL_ADD_UNIFORM (3, BLUR_DIR, u_blur_dir)) - -GSK_GL_DEFINE_PROGRAM (border, - GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("border.glsl")), - GSK_GL_ADD_UNIFORM (1, BORDER_WIDTHS, u_widths) - GSK_GL_ADD_UNIFORM (2, BORDER_OUTLINE_RECT, u_outline_rect)) - -GSK_GL_DEFINE_PROGRAM (color, - GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("color.glsl")), - GSK_GL_NO_UNIFORMS) - -GSK_GL_DEFINE_PROGRAM (coloring, - GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("coloring.glsl")), - GSK_GL_NO_UNIFORMS) - -GSK_GL_DEFINE_PROGRAM (color_matrix, - GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("color_matrix.glsl")), - GSK_GL_ADD_UNIFORM (1, COLOR_MATRIX_COLOR_MATRIX, u_color_matrix) - GSK_GL_ADD_UNIFORM (2, COLOR_MATRIX_COLOR_OFFSET, u_color_offset)) - -GSK_GL_DEFINE_PROGRAM (conic_gradient, - GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("conic_gradient.glsl")), - GSK_GL_ADD_UNIFORM (1, CONIC_GRADIENT_COLOR_STOPS, u_color_stops) - GSK_GL_ADD_UNIFORM (2, CONIC_GRADIENT_NUM_COLOR_STOPS, u_num_color_stops) - GSK_GL_ADD_UNIFORM (3, CONIC_GRADIENT_GEOMETRY, u_geometry)) - -GSK_GL_DEFINE_PROGRAM (cross_fade, - GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("cross_fade.glsl")), - GSK_GL_ADD_UNIFORM (1, CROSS_FADE_PROGRESS, u_progress) - GSK_GL_ADD_UNIFORM (2, CROSS_FADE_SOURCE2, u_source2)) - -GSK_GL_DEFINE_PROGRAM (filled_border, - GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("filled_border.glsl")), - GSK_GL_ADD_UNIFORM (1, FILLED_BORDER_WIDTHS, u_widths) - GSK_GL_ADD_UNIFORM (2, FILLED_BORDER_OUTLINE_RECT, u_outline_rect)) - -GSK_GL_DEFINE_PROGRAM (inset_shadow, - GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("inset_shadow.glsl")), - GSK_GL_ADD_UNIFORM (1, INSET_SHADOW_SPREAD, u_spread) - GSK_GL_ADD_UNIFORM (2, INSET_SHADOW_OFFSET, u_offset) - GSK_GL_ADD_UNIFORM (3, INSET_SHADOW_OUTLINE_RECT, u_outline_rect)) - -GSK_GL_DEFINE_PROGRAM (linear_gradient, - GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("linear_gradient.glsl")), - GSK_GL_ADD_UNIFORM (1, LINEAR_GRADIENT_COLOR_STOPS, u_color_stops) - GSK_GL_ADD_UNIFORM (2, LINEAR_GRADIENT_NUM_COLOR_STOPS, u_num_color_stops) - GSK_GL_ADD_UNIFORM (3, LINEAR_GRADIENT_POINTS, u_points) - GSK_GL_ADD_UNIFORM (4, LINEAR_GRADIENT_REPEAT, u_repeat)) - -GSK_GL_DEFINE_PROGRAM (mask, - GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("mask.glsl")), - GSK_GL_ADD_UNIFORM (1, MASK_SOURCE, u_mask) - GSK_GL_ADD_UNIFORM (2, MASK_MODE, u_mode)) - -GSK_GL_DEFINE_PROGRAM (outset_shadow, - GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("outset_shadow.glsl")), - GSK_GL_ADD_UNIFORM (1, OUTSET_SHADOW_OUTLINE_RECT, u_outline_rect)) - -GSK_GL_DEFINE_PROGRAM (radial_gradient, - GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("radial_gradient.glsl")), - GSK_GL_ADD_UNIFORM (1, RADIAL_GRADIENT_COLOR_STOPS, u_color_stops) - GSK_GL_ADD_UNIFORM (2, RADIAL_GRADIENT_NUM_COLOR_STOPS, u_num_color_stops) - GSK_GL_ADD_UNIFORM (3, RADIAL_GRADIENT_REPEAT, u_repeat) - GSK_GL_ADD_UNIFORM (4, RADIAL_GRADIENT_RANGE, u_range) - GSK_GL_ADD_UNIFORM (5, RADIAL_GRADIENT_GEOMETRY, u_geometry)) - -GSK_GL_DEFINE_PROGRAM (repeat, - GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("repeat.glsl")), - GSK_GL_ADD_UNIFORM (1, REPEAT_CHILD_BOUNDS, u_child_bounds) - GSK_GL_ADD_UNIFORM (2, REPEAT_TEXTURE_RECT, u_texture_rect)) - -GSK_GL_DEFINE_PROGRAM (unblurred_outset_shadow, - GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("unblurred_outset_shadow.glsl")), - GSK_GL_ADD_UNIFORM (1, UNBLURRED_OUTSET_SHADOW_SPREAD, u_spread) - GSK_GL_ADD_UNIFORM (2, UNBLURRED_OUTSET_SHADOW_OFFSET, u_offset) - GSK_GL_ADD_UNIFORM (3, UNBLURRED_OUTSET_SHADOW_OUTLINE_RECT, u_outline_rect)) - -/* Texture conversion shaders. - * - * Note: If you add new formats here, they need to be added - * to the list of supported formats in gdk/gdkdmabuftexture.c. - */ - -GSK_GL_DEFINE_PROGRAM_NO_CLIP (external, - GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("external.glsl")), - GSK_GL_ADD_UNIFORM (1, EXTERNAL_SOURCE, u_external_source) - GSK_GL_ADD_UNIFORM (2, PREMULTIPLY, u_premultiply)) - -GSK_GL_DEFINE_PROGRAM_NO_CLIP (premultiply, - GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("premultiply.glsl")), - GSK_GL_NO_UNIFORMS) diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c deleted file mode 100644 index c326286f0a893161b4acf53f3179e8e795af7341..0000000000000000000000000000000000000000 --- a/gsk/gl/gskglrenderer.c +++ /dev/null @@ -1,489 +0,0 @@ -/* gskglrenderer.c - * - * Copyright 2020 Christian Hergert - * - * This file 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 file 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 General Public License along - * with this program. If not, see . - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#include "config.h" - -#include "gskglrendererprivate.h" - -#include "gskglcommandqueueprivate.h" -#include "gskgldriverprivate.h" -#include "gskglprogramprivate.h" -#include "gskglrenderjobprivate.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * GskGLRenderer: - * - * A GL based renderer. - * - * See [class@Gsk.Renderer]. - * - * Since: 4.2 - */ -struct _GskGLRendererClass -{ - GskRendererClass parent_class; -}; - -struct _GskGLRenderer -{ - GskRenderer parent_instance; - - /* This context is used to swap buffers when we are rendering directly - * to a GDK surface. It is also used to locate the shared driver for - * the display that we use to drive the command queue. - */ - GdkGLContext *context; - - /* Our command queue is private to this renderer and talks to the GL - * context for our target surface. This ensure that framebuffer 0 matches - * the surface we care about. Since the context is shared with other - * contexts from other renderers on the display, texture atlases, - * programs, and other objects are available to them all. - */ - GskGLCommandQueue *command_queue; - - /* The driver manages our program state and command queues. It also - * deals with caching textures, shaders, shadows, glyph, and icon - * caches through various helpers. - */ - GskGLDriver *driver; -}; - -static gboolean -gsk_gl_renderer_dmabuf_downloader_supports (GdkDmabufDownloader *downloader, - GdkDmabufTexture *texture, - GError **error) -{ - GdkDisplay *display = gdk_dmabuf_texture_get_display (texture); - const GdkDmabuf *dmabuf = gdk_dmabuf_texture_get_dmabuf (texture); - - if (!gdk_dmabuf_formats_contains (display->egl_dmabuf_formats, dmabuf->fourcc, dmabuf->modifier)) - { - g_set_error (error, - GDK_DMABUF_ERROR, GDK_DMABUF_ERROR_UNSUPPORTED_FORMAT, - "Unsupported dmabuf format: %.4s:%#" G_GINT64_MODIFIER "x", - (char *) &dmabuf->fourcc, dmabuf->modifier); - return FALSE; - } - - return TRUE; -} - -static gboolean -gsk_gl_renderer_dmabuf_downloader_download (GdkDmabufDownloader *downloader_, - GdkDmabufTexture *texture, - GdkMemoryFormat format, - GdkColorState *color_state, - guchar *data, - gsize stride) -{ - GskRenderer *renderer = GSK_RENDERER (downloader_); - GdkGLContext *previous; - GdkTexture *native; - GdkTextureDownloader *downloader; - int width, height; - GskRenderNode *node; - - if (!gsk_gl_renderer_dmabuf_downloader_supports (downloader_, texture, NULL)) - return FALSE; - - previous = gdk_gl_context_get_current (); - if (previous) - g_object_ref (previous); - - width = gdk_texture_get_width (GDK_TEXTURE (texture)); - height = gdk_texture_get_height (GDK_TEXTURE (texture)); - - node = gsk_texture_node_new (GDK_TEXTURE (texture), &GRAPHENE_RECT_INIT (0, 0, width, height)); - native = gsk_renderer_render_texture (renderer, node, &GRAPHENE_RECT_INIT (0, 0, width, height)); - gsk_render_node_unref (node); - - downloader = gdk_texture_downloader_new (native); - gdk_texture_downloader_set_format (downloader, format); - gdk_texture_downloader_set_color_state (downloader, color_state); - gdk_texture_downloader_download_into (downloader, data, stride); - gdk_texture_downloader_free (downloader); - - g_object_unref (native); - - if (previous) - { - gdk_gl_context_make_current (previous); - g_object_unref (previous); - } - else - gdk_gl_context_clear_current (); - - return TRUE; -} - -static void -gsk_gl_renderer_dmabuf_downloader_close (GdkDmabufDownloader *downloader) -{ - gsk_renderer_unrealize (GSK_RENDERER (downloader)); -} - -static void -gsk_gl_renderer_dmabuf_downloader_init (GdkDmabufDownloaderInterface *iface) -{ - iface->close = gsk_gl_renderer_dmabuf_downloader_close; - iface->download = gsk_gl_renderer_dmabuf_downloader_download; -} - -G_DEFINE_TYPE_EXTENDED (GskGLRenderer, gsk_gl_renderer, GSK_TYPE_RENDERER, 0, - G_IMPLEMENT_INTERFACE (GDK_TYPE_DMABUF_DOWNLOADER, - gsk_gl_renderer_dmabuf_downloader_init)) - -/** - * gsk_gl_renderer_new: - * - * Creates a new `GskRenderer` using the new OpenGL renderer. - * - * Returns: a new GL renderer - * - * Since: 4.2 - */ -GskRenderer * -gsk_gl_renderer_new (void) -{ - return g_object_new (GSK_TYPE_GL_RENDERER, NULL); -} - -static gboolean -gsk_gl_renderer_realize (GskRenderer *renderer, - GdkDisplay *display, - GdkSurface *surface, - GError **error) -{ - G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME; - GskGLRenderer *self = (GskGLRenderer *)renderer; - GdkGLContext *context = NULL; - GskGLDriver *driver = NULL; - gboolean ret = FALSE; - gboolean debug_shaders = FALSE; - - if (self->context != NULL) - return TRUE; - - g_assert (self->driver == NULL); - g_assert (self->context == NULL); - g_assert (self->command_queue == NULL); - - if (!gdk_display_prepare_gl (display, error)) - goto failure; - - context = gdk_gl_context_new (display, surface, surface != NULL); - - if (!gdk_gl_context_realize (context, error)) - goto failure; - - if (GSK_RENDERER_DEBUG_CHECK (GSK_RENDERER (self), SHADERS)) - debug_shaders = TRUE; - - if (!(driver = gsk_gl_driver_for_display (display, debug_shaders, error))) - goto failure; - - self->command_queue = gsk_gl_driver_create_command_queue (driver, context); - self->context = g_steal_pointer (&context); - self->driver = g_steal_pointer (&driver); - - gsk_gl_command_queue_set_profiler (self->command_queue, - gsk_renderer_get_profiler (renderer)); - - ret = TRUE; - -failure: - g_clear_object (&driver); - g_clear_object (&context); - - gdk_profiler_end_mark (start_time, "realize GskGLRenderer", NULL); - - /* Assert either all or no state was set */ - g_assert ((ret && self->driver != NULL && self->context != NULL && self->command_queue != NULL) || - (!ret && self->driver == NULL && self->context == NULL && self->command_queue == NULL)); - - return ret; -} - -static void -gsk_gl_renderer_unrealize (GskRenderer *renderer) -{ - GskGLRenderer *self = (GskGLRenderer *)renderer; - - g_assert (GSK_IS_GL_RENDERER (renderer)); - - gdk_gl_context_make_current (self->context); - - g_clear_object (&self->driver); - g_clear_object (&self->command_queue); - g_clear_object (&self->context); - - gdk_gl_context_clear_current (); -} - -static cairo_region_t * -get_render_region (GdkSurface *surface, - GdkGLContext *context) -{ - const cairo_region_t *damage; - GdkRectangle whole_surface; - GdkRectangle extents; - - g_assert (GDK_IS_SURFACE (surface)); - g_assert (GDK_IS_GL_CONTEXT (context)); - - whole_surface.x = 0; - whole_surface.y = 0; - whole_surface.width = gdk_surface_get_width (surface); - whole_surface.height = gdk_surface_get_height (surface); - - /* Damage does not have scale factor applied so we can compare it to - * @whole_surface which also doesn't have the scale factor applied. - */ - damage = gdk_draw_context_get_frame_region (GDK_DRAW_CONTEXT (context)); - - if (cairo_region_contains_rectangle (damage, &whole_surface) == CAIRO_REGION_OVERLAP_IN) - return NULL; - - /* If the extents match the full-scene, do the same as above */ - cairo_region_get_extents (damage, &extents); - if (gdk_rectangle_equal (&extents, &whole_surface)) - return NULL; - - /* Draw clipped to the bounding-box of the region. */ - return cairo_region_create_rectangle (&extents); -} - -static void -gsk_gl_renderer_render (GskRenderer *renderer, - GskRenderNode *root, - const cairo_region_t *update_area) -{ - GskGLRenderer *self = (GskGLRenderer *)renderer; - cairo_region_t *render_region; - graphene_rect_t viewport; - GskGLRenderJob *job; - GdkSurface *surface; - graphene_rect_t opaque_tmp; - const graphene_rect_t *opaque; - float scale; - - g_assert (GSK_IS_GL_RENDERER (renderer)); - g_assert (root != NULL); - - surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (self->context)); - scale = gdk_gl_context_get_scale (self->context); - - if (cairo_region_is_empty (update_area)) - { - gdk_draw_context_empty_frame (GDK_DRAW_CONTEXT (self->context)); - return; - } - - viewport.origin.x = 0; - viewport.origin.y = 0; - viewport.size.width = gdk_surface_get_width (surface) * scale; - viewport.size.height = gdk_surface_get_height (surface) * scale; - - if (gsk_render_node_get_opaque_rect (root, &opaque_tmp)) - opaque = &opaque_tmp; - else - opaque = NULL; - gdk_draw_context_begin_frame_full (GDK_DRAW_CONTEXT (self->context), - gsk_render_node_get_preferred_depth (root), - update_area, - opaque); - - gdk_gl_context_make_current (self->context); - - /* Must be called *AFTER* gdk_draw_context_begin_frame() */ - render_region = get_render_region (surface, self->context); - - gsk_gl_driver_begin_frame (self->driver, self->command_queue); - job = gsk_gl_render_job_new (self->driver, &viewport, scale, render_region, 0, TRUE); - gsk_gl_render_job_render (job, root); - gsk_gl_driver_end_frame (self->driver); - gsk_gl_render_job_free (job); - - gdk_draw_context_end_frame_full (GDK_DRAW_CONTEXT (self->context)); - - gsk_gl_driver_after_frame (self->driver); - - cairo_region_destroy (render_region); -} - -static GdkTexture * -gsk_gl_renderer_render_texture (GskRenderer *renderer, - GskRenderNode *root, - const graphene_rect_t *viewport) -{ - GskGLRenderer *self = (GskGLRenderer *)renderer; - GskGLRenderTarget *render_target; - GskGLRenderJob *job; - GdkTexture *texture; - guint texture_id; - GdkMemoryFormat gdk_format; - int width, height, max_size; - int format; - - g_assert (GSK_IS_GL_RENDERER (renderer)); - g_assert (root != NULL); - - width = ceilf (viewport->size.width); - height = ceilf (viewport->size.height); - max_size = self->command_queue->max_texture_size; - if (width > max_size || height > max_size) - { - gsize x, y, size, stride; - GBytes *bytes; - guchar *data; - - stride = width * 4; - size = stride * height; - data = g_malloc_n (stride, height); - - for (y = 0; y < height; y += max_size) - { - for (x = 0; x < width; x += max_size) - { - texture = gsk_gl_renderer_render_texture (renderer, root, - &GRAPHENE_RECT_INIT (viewport->origin.x + x, - viewport->origin.y + y, - MIN (max_size, viewport->size.width - x), - MIN (max_size, viewport->size.height - y))); - gdk_texture_download (texture, - data + stride * y + x * 4, - stride); - g_object_unref (texture); - } - } - - bytes = g_bytes_new_take (data, size); - texture = gdk_memory_texture_new (width, height, GDK_MEMORY_DEFAULT, bytes, stride); - g_bytes_unref (bytes); - return texture; - } - - /* Don't use float textures for SRGB or node-editor turns on high - * depth unconditionally. */ - if (gsk_render_node_get_preferred_depth (root) != GDK_MEMORY_NONE && - gsk_render_node_get_preferred_depth (root) != GDK_MEMORY_U8 && - gsk_render_node_get_preferred_depth (root) != GDK_MEMORY_U8_SRGB && - gdk_gl_context_check_version (self->context, "3.0", "3.0")) - { - gdk_format = GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED; - format = GL_RGBA32F; - } - else - { - format = GL_RGBA8; - gdk_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; - } - - gdk_gl_context_make_current (self->context); - - if (gsk_gl_driver_create_render_target (self->driver, - width, height, - format, - &render_target)) - { - gsk_gl_driver_begin_frame (self->driver, self->command_queue); - job = gsk_gl_render_job_new (self->driver, viewport, 1, NULL, render_target->framebuffer_id, TRUE); - gsk_gl_render_job_render_flipped (job, root); - texture_id = gsk_gl_driver_release_render_target (self->driver, render_target, FALSE); - texture = gsk_gl_driver_create_gdk_texture (self->driver, texture_id, gdk_format); - gsk_gl_driver_end_frame (self->driver); - gsk_gl_render_job_free (job); - - gsk_gl_driver_after_frame (self->driver); - } - else - { - g_assert_not_reached (); - } - - return g_steal_pointer (&texture); -} - -static void -gsk_gl_renderer_dispose (GObject *object) -{ - GskGLRenderer *self = (GskGLRenderer *)object; - - if (self->driver != NULL) - g_critical ("Attempt to dispose %s without calling gsk_renderer_unrealize()", - G_OBJECT_TYPE_NAME (self)); - - G_OBJECT_CLASS (gsk_gl_renderer_parent_class)->dispose (object); -} - -static void -gsk_gl_renderer_class_init (GskGLRendererClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GskRendererClass *renderer_class = GSK_RENDERER_CLASS (klass); - - object_class->dispose = gsk_gl_renderer_dispose; - - renderer_class->supports_offload = TRUE; - - renderer_class->realize = gsk_gl_renderer_realize; - renderer_class->unrealize = gsk_gl_renderer_unrealize; - renderer_class->render = gsk_gl_renderer_render; - renderer_class->render_texture = gsk_gl_renderer_render_texture; -} - -static void -gsk_gl_renderer_init (GskGLRenderer *self) -{ -} - -G_GNUC_BEGIN_IGNORE_DEPRECATIONS - -gboolean -gsk_gl_renderer_try_compile_gl_shader (GskGLRenderer *renderer, - GskGLShader *shader, - GError **error) -{ - GskGLProgram *program; - - g_return_val_if_fail (GSK_IS_GL_RENDERER (renderer), FALSE); - g_return_val_if_fail (shader != NULL, FALSE); - - program = gsk_gl_driver_lookup_shader (renderer->driver, shader, error); - - return program != NULL; -} - -G_GNUC_END_IGNORE_DEPRECATIONS diff --git a/gsk/gl/gskglrenderer.h b/gsk/gl/gskglrenderer.h index 6d0095fe73ea9b031f453a0871da49fea513386b..e863b690cb05b357e1c558efa68e10a5e7a6bf26 100644 --- a/gsk/gl/gskglrenderer.h +++ b/gsk/gl/gskglrenderer.h @@ -20,35 +20,6 @@ #pragma once -#if !defined (__GSK_H_INSIDE__) && !defined (GTK_COMPILATION) -#include -#define GSK_INCLUDE_WARNING(x) GDK_DEPRECATED_IN_4_14_FOR("#include instead of to avoid this warning") -#else -#include -#define GSK_INCLUDE_WARNING(x) x -#endif - -G_BEGIN_DECLS - -#define GSK_TYPE_GL_RENDERER (gsk_gl_renderer_get_type()) - -#define GSK_GL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_GL_RENDERER, GskGLRenderer)) -#define GSK_IS_GL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_GL_RENDERER)) -#define GSK_GL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_GL_RENDERER, GskGLRendererClass)) -#define GSK_IS_GL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_GL_RENDERER)) -#define GSK_GL_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_GL_RENDERER, GskGLRendererClass)) - -typedef struct _GskGLRenderer GskGLRenderer; -typedef struct _GskGLRendererClass GskGLRendererClass; - -GSK_INCLUDE_WARNING(GDK_AVAILABLE_IN_4_2) -GType gsk_gl_renderer_get_type (void) G_GNUC_CONST; -GSK_INCLUDE_WARNING(GDK_AVAILABLE_IN_4_2) -GskRenderer *gsk_gl_renderer_new (void); - -GSK_INCLUDE_WARNING(GDK_AVAILABLE_IN_ALL) -GType gsk_ngl_renderer_get_type (void) G_GNUC_CONST; -GSK_INCLUDE_WARNING(GDK_AVAILABLE_IN_ALL) -GskRenderer *gsk_ngl_renderer_new (void); -G_END_DECLS +#warning "#include instead of to avoid this warning" +#include diff --git a/gsk/gl/gskglrendererprivate.h b/gsk/gl/gskglrendererprivate.h deleted file mode 100644 index 0bdb03efb2967ffd61e5b36d3b2634629c54dc8b..0000000000000000000000000000000000000000 --- a/gsk/gl/gskglrendererprivate.h +++ /dev/null @@ -1,38 +0,0 @@ -/* gskglrendererprivate.h - * - * Copyright 2021 Christian Hergert - * - * 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 . - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#pragma once - -#include "gskglrenderer.h" - -#include "gskglshader.h" - -G_BEGIN_DECLS - -G_GNUC_BEGIN_IGNORE_DEPRECATIONS - -gboolean gsk_gl_renderer_try_compile_gl_shader (GskGLRenderer *renderer, - GskGLShader *shader, - GError **error); - -G_GNUC_END_IGNORE_DEPRECATIONS - -G_END_DECLS - diff --git a/gsk/gl/gskglrenderjob.c b/gsk/gl/gskglrenderjob.c deleted file mode 100644 index 9c84c51fd5102bf4f7c6fab56221c6b637747ee3..0000000000000000000000000000000000000000 --- a/gsk/gl/gskglrenderjob.c +++ /dev/null @@ -1,4725 +0,0 @@ -/* gskglrenderjob.c - * - * Copyright 2017 Timm Bäder - * Copyright 2018 Matthias Clasen - * Copyright 2018 Alexander Larsson - * Copyright 2020 Christian Hergert - * - * 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 . - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gskglcommandqueueprivate.h" -#include "gskgldriverprivate.h" -#include "gskglglyphlibraryprivate.h" -#include "gskgliconlibraryprivate.h" -#include "gskglprogramprivate.h" -#include "gskglrenderjobprivate.h" -#include "gskglshadowlibraryprivate.h" -#include "gskdebugprivate.h" - -#include "ninesliceprivate.h" -#include "fp16private.h" - -#define ORTHO_NEAR_PLANE -10000 -#define ORTHO_FAR_PLANE 10000 -#define MAX_GRADIENT_STOPS 6 -#define SHADOW_EXTRA_SIZE 4 - -/* Make sure gradient stops fits in packed array_count */ -G_STATIC_ASSERT ((MAX_GRADIENT_STOPS * 5) < (1 << GSK_GL_UNIFORM_ARRAY_BITS)); - -#define ALPHA_IS_CLEAR(alpha) ((alpha) < ((float) 0x00ff / (float) 0xffff)) -#define RGBA_IS_CLEAR(rgba) ALPHA_IS_CLEAR((rgba)->alpha) - -typedef struct _GskGLRenderClip -{ - GskRoundedRect rect; - guint is_rectilinear : 1; - guint is_fully_contained : 1; -} GskGLRenderClip; - -#define GDK_ARRAY_NAME clips -#define GDK_ARRAY_TYPE_NAME Clips -#define GDK_ARRAY_ELEMENT_TYPE GskGLRenderClip -#define GDK_ARRAY_BY_VALUE 1 -#define GDK_ARRAY_PREALLOC 16 -#define GDK_ARRAY_NO_MEMSET -#include "gdk/gdkarrayimpl.c" - -typedef struct _GskGLRenderModelview -{ - GskTransform *transform; - float scale_x; - float scale_y; - float dx; - float dy; - float offset_x_before; - float offset_y_before; - graphene_matrix_t matrix; -} GskGLRenderModelview; - -#define GDK_ARRAY_NAME modelviews -#define GDK_ARRAY_TYPE_NAME Modelviews -#define GDK_ARRAY_ELEMENT_TYPE GskGLRenderModelview -#define GDK_ARRAY_BY_VALUE 1 -#define GDK_ARRAY_PREALLOC 16 -#define GDK_ARRAY_NO_MEMSET -#include "gdk/gdkarrayimpl.c" - -struct _GskGLRenderJob -{ - /* The context containing the framebuffer we are drawing to. Generally this - * is the context of the surface but may be a shared context if rendering to - * an offscreen texture such as gsk_gl_renderer_render_texture(). - */ - GdkGLContext *context; - - /* The driver to be used. This is shared among all the renderers on a given - * GdkDisplay and uses the shared GL context to send commands. - */ - GskGLDriver *driver; - - /* The command queue (which is just a faster pointer to the driver's - * command queue. - */ - GskGLCommandQueue *command_queue; - - /* The region that we are clipping. Normalized to a single rectangle region. */ - cairo_region_t *region; - - /* The framebuffer to draw to in the @context GL context. So 0 would be the - * default framebuffer of @context. This is important to note as many other - * operations could be done using objects shared from the command queues - * GL context. - */ - guint framebuffer; - guint default_framebuffer; - - /* The viewport we are using. This state is updated as we process render - * nodes in the specific visitor callbacks. - */ - graphene_rect_t viewport; - - /* The current projection, updated as we process nodes */ - graphene_matrix_t projection; - - /* An array of GskGLRenderModelview updated as nodes are processed. The - * current modelview is the last element. - */ - Modelviews modelview; - - /* An array of GskGLRenderClip updated as nodes are processed. The - * current clip is the last element. - */ - Clips clip; - - /* Our current alpha state as we process nodes */ - float alpha; - - /* Offset (delta x,y) as we process nodes. Occasionally this is merged into - * a transform that is referenced from child transform nodes. - */ - float offset_x; - float offset_y; - - /* The scale we are processing, possibly updated by transforms */ - float scale_x; - float scale_y; - - /* Cached pointers */ - const GskGLRenderClip *current_clip; - const GskGLRenderModelview *current_modelview; - GskGLProgram *current_program; - - guint source_is_glyph_atlas : 1; - - /* In some cases we might want to avoid clearing the framebuffer - * because we're going to render over the existing contents. - */ - guint clear_framebuffer : 1; - - /* Format we want to use for intermediate textures, determined by - * looking at the format of the framebuffer we are rendering on. - */ - int target_format; - - guint offscreen_count; /* if > 0, we're rendering to an offscreen */ -}; - -typedef struct _GskGLRenderOffscreen -{ - /* The bounds to render */ - const graphene_rect_t *bounds; - - /* Return location for texture coordinates */ - struct { - float x; - float y; - float x2; - float y2; - } area; - - /* Return location for texture ID */ - guint texture_id; - gpointer sync; - - /* Whether to force creating a new texture, even if the - * input already is a texture - */ - guint force_offscreen : 1; - guint reset_clip : 1; - guint do_not_cache : 1; - - /* Return location for whether we created a texture */ - guint was_offscreen : 1; - guint has_mipmap : 1; -} GskGLRenderOffscreen; - -static void gsk_gl_render_job_visit_node (GskGLRenderJob *job, - const GskRenderNode *node); -static gboolean gsk_gl_render_job_visit_node_with_offscreen (GskGLRenderJob *job, - const GskRenderNode *node, - GskGLRenderOffscreen *offscreen); -static void gsk_gl_render_job_upload_texture (GskGLRenderJob *job, - GdkTexture *texture, - gboolean ensure_mipmap, - GskGLRenderOffscreen *offscreen); - -static inline GskGLRenderClip * -clips_grow_one (Clips *clips) -{ - guint len = clips_get_size (clips); - clips_set_size (clips, len + 1); - return clips_get (clips, len); -} - -static inline GskGLRenderModelview * -modelviews_grow_one (Modelviews *modelviews) -{ - guint len = modelviews_get_size (modelviews); - modelviews_set_size (modelviews, len + 1); - return modelviews_get (modelviews, len); -} - -static inline int -get_target_format (GskGLRenderJob *job, - const GskRenderNode *node) -{ - if (gsk_render_node_get_preferred_depth (node) != GDK_MEMORY_U8) - return job->target_format; - - return GL_RGBA8; -} - -static inline void -init_full_texture_region (GskGLRenderOffscreen *offscreen) -{ - offscreen->area.x = 0; - offscreen->area.y = 0; - offscreen->area.x2 = 1; - offscreen->area.y2 = 1; -} - -static inline gboolean G_GNUC_PURE -node_is_invisible (const GskRenderNode *node) -{ - return node->bounds.size.width == 0.0f || - node->bounds.size.height == 0.0f; -} - -static inline gboolean G_GNUC_PURE -rounded_rect_equal (const GskRoundedRect *r1, - const GskRoundedRect *r2) -{ - return memcmp (r1, r2, sizeof (GskRoundedRect)) == 0; -} - -static inline void -gsk_rounded_rect_shrink_to_minimum (GskRoundedRect *self) -{ - self->bounds.size.width = MAX (self->corner[0].width + self->corner[1].width, - self->corner[3].width + self->corner[2].width); - self->bounds.size.height = MAX (self->corner[0].height + self->corner[3].height, - self->corner[1].height + self->corner[2].height); -} - -static inline gboolean G_GNUC_PURE -node_supports_2d_transform (const GskRenderNode *node) -{ - switch (GSK_RENDER_NODE_TYPE (node)) - { - case GSK_COLOR_NODE: - case GSK_OPACITY_NODE: - case GSK_COLOR_MATRIX_NODE: - case GSK_TEXTURE_NODE: - case GSK_TEXTURE_SCALE_NODE: - case GSK_CROSS_FADE_NODE: - case GSK_LINEAR_GRADIENT_NODE: - case GSK_REPEATING_LINEAR_GRADIENT_NODE: - case GSK_CONIC_GRADIENT_NODE: - case GSK_RADIAL_GRADIENT_NODE: - case GSK_REPEATING_RADIAL_GRADIENT_NODE: - case GSK_DEBUG_NODE: - case GSK_TEXT_NODE: - case GSK_CAIRO_NODE: - case GSK_BLEND_NODE: - case GSK_BLUR_NODE: - case GSK_MASK_NODE: - case GSK_FILL_NODE: - case GSK_STROKE_NODE: - case GSK_SUBSURFACE_NODE: - return TRUE; - - case GSK_SHADOW_NODE: - return node_supports_2d_transform (gsk_shadow_node_get_child (node)); - - case GSK_TRANSFORM_NODE: - return node_supports_2d_transform (gsk_transform_node_get_child (node)); - - case GSK_CONTAINER_NODE: - for (guint i = 0, p = gsk_container_node_get_n_children (node); i < p; i++) - { - if (!node_supports_2d_transform (gsk_container_node_get_child (node, i))) - return FALSE; - } - return TRUE; - - case GSK_BORDER_NODE: - case GSK_INSET_SHADOW_NODE: - case GSK_OUTSET_SHADOW_NODE: - case GSK_REPEAT_NODE: - case GSK_CLIP_NODE: - case GSK_ROUNDED_CLIP_NODE: - case GSK_GL_SHADER_NODE: - return FALSE; - - case GSK_NOT_A_RENDER_NODE: - default: - g_assert_not_reached (); - } -} - -static inline gboolean G_GNUC_PURE -node_supports_transform (const GskRenderNode *node) -{ - /* Some nodes can't handle non-trivial transforms without being - * rendered to a texture (e.g. rotated clips, etc.). Some however work - * just fine, mostly because they already draw their child to a - * texture and just render the texture manipulated in some way, think - * opacity or color matrix. - */ - - switch (GSK_RENDER_NODE_TYPE (node)) - { - case GSK_COLOR_NODE: - case GSK_OPACITY_NODE: - case GSK_COLOR_MATRIX_NODE: - case GSK_TEXTURE_NODE: - case GSK_CROSS_FADE_NODE: - case GSK_DEBUG_NODE: - case GSK_TEXT_NODE: - case GSK_CAIRO_NODE: - case GSK_BLEND_NODE: - case GSK_BLUR_NODE: - case GSK_MASK_NODE: - case GSK_FILL_NODE: - case GSK_STROKE_NODE: - case GSK_SUBSURFACE_NODE: - return TRUE; - - case GSK_SHADOW_NODE: - return node_supports_transform (gsk_shadow_node_get_child (node)); - - case GSK_TRANSFORM_NODE: - return node_supports_transform (gsk_transform_node_get_child (node)); - - case GSK_CONTAINER_NODE: - case GSK_LINEAR_GRADIENT_NODE: - case GSK_REPEATING_LINEAR_GRADIENT_NODE: - case GSK_RADIAL_GRADIENT_NODE: - case GSK_REPEATING_RADIAL_GRADIENT_NODE: - case GSK_CONIC_GRADIENT_NODE: - case GSK_BORDER_NODE: - case GSK_INSET_SHADOW_NODE: - case GSK_OUTSET_SHADOW_NODE: - case GSK_REPEAT_NODE: - case GSK_CLIP_NODE: - case GSK_ROUNDED_CLIP_NODE: - case GSK_GL_SHADER_NODE: - case GSK_TEXTURE_SCALE_NODE: - return FALSE; - - case GSK_NOT_A_RENDER_NODE: - default: - g_assert_not_reached (); - } -} - -static inline gboolean G_GNUC_PURE -color_matrix_modifies_alpha (const GskRenderNode *node) -{ - const graphene_matrix_t *matrix = gsk_color_matrix_node_get_color_matrix (node); - const graphene_vec4_t *offset = gsk_color_matrix_node_get_color_offset (node); - graphene_vec4_t row3; - - if (graphene_vec4_get_w (offset) != 0.0f) - return TRUE; - - graphene_matrix_get_row (matrix, 3, &row3); - - return !graphene_vec4_equal (graphene_vec4_w_axis (), &row3); -} - -static inline void -init_projection_matrix (graphene_matrix_t *projection, - const graphene_rect_t *viewport) -{ - graphene_matrix_init_ortho (projection, - viewport->origin.x, - viewport->origin.x + viewport->size.width, - viewport->origin.y, - viewport->origin.y + viewport->size.height, - ORTHO_NEAR_PLANE, - ORTHO_FAR_PLANE); - graphene_matrix_scale (projection, 1, -1, 1); -} - -static inline float -gsk_gl_render_job_set_alpha (GskGLRenderJob *job, - float alpha) -{ - if (job->alpha != alpha) - { - float ret = job->alpha; - job->alpha = alpha; - job->driver->stamps[UNIFORM_SHARED_ALPHA]++; - return ret; - } - - return alpha; -} - -static void -extract_matrix_metadata (GskGLRenderModelview *modelview) -{ - gsk_transform_to_matrix (modelview->transform, &modelview->matrix); - - switch (gsk_transform_get_category (modelview->transform)) - { - case GSK_TRANSFORM_CATEGORY_IDENTITY: - modelview->scale_x = 1; - modelview->scale_y = 1; - modelview->dx = 0; - modelview->dy = 0; - break; - - case GSK_TRANSFORM_CATEGORY_2D_TRANSLATE: - modelview->scale_x = 1; - modelview->scale_y = 1; - gsk_transform_to_translate (modelview->transform, - &modelview->dx, &modelview->dy); - break; - - case GSK_TRANSFORM_CATEGORY_2D_AFFINE: - gsk_transform_to_affine (modelview->transform, - &modelview->scale_x, &modelview->scale_y, - &modelview->dx, &modelview->dy); - break; - - case GSK_TRANSFORM_CATEGORY_2D: - { - float skew_x, skew_y, angle, dx, dy; - - gsk_transform_to_2d_components (modelview->transform, - &skew_x, &skew_y, - &modelview->scale_x, &modelview->scale_y, - &angle, &dx, &dy); - modelview->dx = 0; - modelview->dy = 0; - } - break; - - case GSK_TRANSFORM_CATEGORY_UNKNOWN: - case GSK_TRANSFORM_CATEGORY_ANY: - case GSK_TRANSFORM_CATEGORY_3D: - { - graphene_quaternion_t rotation; - graphene_vec4_t perspective; - graphene_vec3_t translation; - graphene_vec3_t scale; - graphene_vec3_t shear; - - graphene_matrix_decompose (&modelview->matrix, - &translation, - &scale, - &rotation, - &shear, - &perspective); - - modelview->scale_x = graphene_vec3_get_x (&scale); - modelview->scale_y = graphene_vec3_get_y (&scale); - modelview->dx = 0; - modelview->dy = 0; - } - break; - - default: - break; - } -} - -/* takes ownership of transform */ -static void -gsk_gl_render_job_set_modelview (GskGLRenderJob *job, - GskTransform *transform) -{ - GskGLRenderModelview *modelview; - - g_assert (job != NULL); - - job->driver->stamps[UNIFORM_SHARED_MODELVIEW]++; - - modelview = modelviews_grow_one (&job->modelview); - - modelview->transform = transform; - - modelview->offset_x_before = job->offset_x; - modelview->offset_y_before = job->offset_y; - - extract_matrix_metadata (modelview); - - job->offset_x = 0; - job->offset_y = 0; - job->scale_x = modelview->scale_x; - job->scale_y = modelview->scale_y; - - job->current_modelview = modelview; -} - -/* doesn't take ownership of transform */ -static void -gsk_gl_render_job_push_modelview (GskGLRenderJob *job, - GskTransform *transform) -{ - GskGLRenderModelview *modelview; - - g_assert (job != NULL); - g_assert (transform != NULL); - - job->driver->stamps[UNIFORM_SHARED_MODELVIEW]++; - - modelview = modelviews_grow_one (&job->modelview); - - if G_LIKELY (modelviews_get_size (&job->modelview) > 1) - { - GskGLRenderModelview *last = job->modelview.end - 2; - GskTransform *t = NULL; - - /* Multiply given matrix with our previous modelview */ - t = gsk_transform_translate (gsk_transform_ref (last->transform), - &(graphene_point_t) { - job->offset_x, - job->offset_y - }); - t = gsk_transform_transform (t, transform); - modelview->transform = t; - } - else - { - modelview->transform = gsk_transform_ref (transform); - } - - modelview->offset_x_before = job->offset_x; - modelview->offset_y_before = job->offset_y; - - extract_matrix_metadata (modelview); - - job->offset_x = 0; - job->offset_y = 0; - job->scale_x = modelview->scale_x; - job->scale_y = modelview->scale_y; - - job->current_modelview = modelview; -} - -static void -gsk_gl_render_job_pop_modelview (GskGLRenderJob *job) -{ - const GskGLRenderModelview *head; - - g_assert (job != NULL); - g_assert (modelviews_get_size (&job->modelview) > 0); - - job->driver->stamps[UNIFORM_SHARED_MODELVIEW]++; - - head = job->current_modelview; - - job->offset_x = head->offset_x_before; - job->offset_y = head->offset_y_before; - - gsk_transform_unref (head->transform); - - job->modelview.end--; - - if (modelviews_get_size (&job->modelview) >= 1) - { - head = job->modelview.end - 1; - - job->scale_x = head->scale_x; - job->scale_y = head->scale_y; - - job->current_modelview = head; - } - else - { - job->current_modelview = NULL; - } -} - -static void -gsk_gl_render_job_push_clip (GskGLRenderJob *job, - const GskRoundedRect *rect) -{ - GskGLRenderClip *clip; - - g_assert (job != NULL); - g_assert (rect != NULL); - - job->driver->stamps[UNIFORM_SHARED_CLIP_RECT]++; - - clip = clips_grow_one (&job->clip); - - memcpy (&clip->rect, rect, sizeof *rect); - clip->is_rectilinear = gsk_rounded_rect_is_rectilinear (rect); - clip->is_fully_contained = FALSE; - - job->current_clip = clip; -} - -static void -gsk_gl_render_job_push_contained_clip (GskGLRenderJob *job) -{ - GskGLRenderClip *clip; - GskGLRenderClip *old_clip; - - g_assert (job != NULL); - g_assert (clips_get_size (&job->clip) > 0); - - job->driver->stamps[UNIFORM_SHARED_CLIP_RECT]++; - - clip = clips_grow_one (&job->clip); - old_clip = clips_get (&job->clip, clips_get_size (&job->clip) - 2); - - memcpy (&clip->rect.bounds, &old_clip->rect.bounds, sizeof (graphene_rect_t)); - memset (clip->rect.corner, 0, sizeof clip->rect.corner); - clip->is_rectilinear = TRUE; - clip->is_fully_contained = TRUE; - - job->current_clip = clip; -} - -static void -gsk_gl_render_job_pop_clip (GskGLRenderJob *job) -{ - g_assert (job != NULL); - g_assert (clips_get_size (&job->clip) > 0); - - job->driver->stamps[UNIFORM_SHARED_CLIP_RECT]++; - job->current_clip--; - job->clip.end--; -} - -static inline void -gsk_gl_render_job_offset (GskGLRenderJob *job, - float offset_x, - float offset_y) -{ - if (offset_x || offset_y) - { - job->offset_x += offset_x; - job->offset_y += offset_y; - } -} - -static inline void -gsk_gl_render_job_set_projection (GskGLRenderJob *job, - const graphene_matrix_t *projection) -{ - memcpy (&job->projection, projection, sizeof job->projection); - job->driver->stamps[UNIFORM_SHARED_PROJECTION]++; -} - -static inline void -gsk_gl_render_job_set_projection_from_rect (GskGLRenderJob *job, - const graphene_rect_t *rect, - graphene_matrix_t *prev_projection) -{ - if (prev_projection) - memcpy (prev_projection, &job->projection, sizeof *prev_projection); - init_projection_matrix (&job->projection, rect); - job->driver->stamps[UNIFORM_SHARED_PROJECTION]++; -} - -static inline void -gsk_gl_render_job_set_projection_for_size (GskGLRenderJob *job, - float width, - float height, - graphene_matrix_t *prev_projection) -{ - if (prev_projection) - memcpy (prev_projection, &job->projection, sizeof *prev_projection); - graphene_matrix_init_ortho (&job->projection, 0, width, 0, height, ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE); - graphene_matrix_scale (&job->projection, 1, -1, 1); - job->driver->stamps[UNIFORM_SHARED_PROJECTION]++; -} - -static inline void -gsk_gl_render_job_set_viewport (GskGLRenderJob *job, - const graphene_rect_t *viewport, - graphene_rect_t *prev_viewport) -{ - if (prev_viewport) - memcpy (prev_viewport, &job->viewport, sizeof *prev_viewport); - memcpy (&job->viewport, viewport, sizeof job->viewport); - job->driver->stamps[UNIFORM_SHARED_VIEWPORT]++; -} - -static inline void -gsk_gl_render_job_set_viewport_for_size (GskGLRenderJob *job, - float width, - float height, - graphene_rect_t *prev_viewport) -{ - if (prev_viewport) - memcpy (prev_viewport, &job->viewport, sizeof *prev_viewport); - job->viewport.origin.x = 0; - job->viewport.origin.y = 0; - job->viewport.size.width = width; - job->viewport.size.height = height; - job->driver->stamps[UNIFORM_SHARED_VIEWPORT]++; -} - -static inline void -gsk_gl_render_job_transform_bounds (GskGLRenderJob *job, - const graphene_rect_t *rect, - graphene_rect_t *out_rect) -{ - GskTransform *transform; - GskTransformCategory category; - - g_assert (job != NULL); - g_assert (modelviews_get_size (&job->modelview) > 0); - g_assert (rect != NULL); - g_assert (out_rect != NULL); - - transform = job->current_modelview->transform; - category = gsk_transform_get_category (transform); - - /* Our most common transform is 2d-affine, so inline it. - * Both identity and 2d-translate are virtually unseen here. - */ - if G_LIKELY (category >= GSK_TRANSFORM_CATEGORY_2D_AFFINE) - { - float scale_x = job->current_modelview->scale_x; - float scale_y = job->current_modelview->scale_y; - float dx = job->current_modelview->dx; - float dy = job->current_modelview->dy; - - /* Init directly into out rect */ - out_rect->origin.x = ((rect->origin.x + job->offset_x) * scale_x) + dx; - out_rect->origin.y = ((rect->origin.y + job->offset_y) * scale_y) + dy; - out_rect->size.width = rect->size.width * scale_x; - out_rect->size.height = rect->size.height * scale_y; - - /* Normalize in place */ - if (out_rect->size.width < 0.f) - { - float size = fabsf (out_rect->size.width); - - out_rect->origin.x -= size; - out_rect->size.width = size; - } - - if (out_rect->size.height < 0.f) - { - float size = fabsf (out_rect->size.height); - - out_rect->origin.y -= size; - out_rect->size.height = size; - } - } - else - { - graphene_rect_t r; - - r.origin.x = rect->origin.x + job->offset_x; - r.origin.y = rect->origin.y + job->offset_y; - r.size.width = rect->size.width; - r.size.height = rect->size.height; - - gsk_transform_transform_bounds (transform, &r, out_rect); - } -} - -static inline void -gsk_gl_render_job_untransform_bounds (GskGLRenderJob *job, - const graphene_rect_t *rect, - graphene_rect_t *out_rect) -{ - GskTransform *transform; - - transform = gsk_transform_invert (gsk_transform_ref (job->current_modelview->transform)); - - gsk_transform_transform_bounds (transform, rect, out_rect); - - out_rect->origin.x -= job->offset_x; - out_rect->origin.y -= job->offset_y; - - gsk_transform_unref (transform); -} - -static inline void -gsk_gl_render_job_translate_rounded_rect (GskGLRenderJob *job, - const GskRoundedRect *rect, - GskRoundedRect *out_rect) - { - out_rect->bounds.origin.x = job->offset_x + rect->bounds.origin.x; - out_rect->bounds.origin.y = job->offset_y + rect->bounds.origin.y; - out_rect->bounds.size.width = rect->bounds.size.width; - out_rect->bounds.size.height = rect->bounds.size.height; - memcpy (out_rect->corner, rect->corner, sizeof rect->corner); -} - -static inline void -rounded_rect_scale_corners (const GskRoundedRect *rect, - GskRoundedRect *out_rect, - float scale_x, - float scale_y) -{ - for (guint i = 0; i < G_N_ELEMENTS (out_rect->corner); i++) - { - out_rect->corner[i].width = rect->corner[i].width * fabsf (scale_x); - out_rect->corner[i].height = rect->corner[i].height * fabsf (scale_y); - } - - if (scale_x < 0) - { - graphene_size_t p; - - p = out_rect->corner[GSK_CORNER_TOP_LEFT]; - out_rect->corner[GSK_CORNER_TOP_LEFT] = out_rect->corner[GSK_CORNER_TOP_RIGHT]; - out_rect->corner[GSK_CORNER_TOP_RIGHT] = p; - p = out_rect->corner[GSK_CORNER_BOTTOM_LEFT]; - out_rect->corner[GSK_CORNER_BOTTOM_LEFT] = out_rect->corner[GSK_CORNER_BOTTOM_RIGHT]; - out_rect->corner[GSK_CORNER_BOTTOM_RIGHT] = p; - } - - if (scale_y < 0) - { - graphene_size_t p; - - p = out_rect->corner[GSK_CORNER_TOP_LEFT]; - out_rect->corner[GSK_CORNER_TOP_LEFT] = out_rect->corner[GSK_CORNER_BOTTOM_LEFT]; - out_rect->corner[GSK_CORNER_BOTTOM_LEFT] = p; - p = out_rect->corner[GSK_CORNER_TOP_RIGHT]; - out_rect->corner[GSK_CORNER_TOP_RIGHT] = out_rect->corner[GSK_CORNER_BOTTOM_RIGHT]; - out_rect->corner[GSK_CORNER_BOTTOM_RIGHT] = p; - } -} - -static inline void -gsk_gl_render_job_transform_rounded_rect (GskGLRenderJob *job, - const GskRoundedRect *rect, - GskRoundedRect *out_rect) -{ - gsk_gl_render_job_transform_bounds (job, &rect->bounds, &out_rect->bounds); - rounded_rect_scale_corners (rect, out_rect, job->scale_x, job->scale_y); -} - -static inline void -rounded_rect_get_inner (const GskRoundedRect *rect, - graphene_rect_t *inner) -{ - float left = MAX (rect->corner[GSK_CORNER_TOP_LEFT].width, rect->corner[GSK_CORNER_BOTTOM_LEFT].width); - float right = MAX (rect->corner[GSK_CORNER_TOP_RIGHT].width, rect->corner[GSK_CORNER_BOTTOM_RIGHT].width); - float top = MAX (rect->corner[GSK_CORNER_TOP_LEFT].height, rect->corner[GSK_CORNER_TOP_RIGHT].height); - float bottom = MAX (rect->corner[GSK_CORNER_BOTTOM_LEFT].height, rect->corner[GSK_CORNER_BOTTOM_RIGHT].height); - - inner->origin.x = rect->bounds.origin.x + left; - inner->size.width = rect->bounds.size.width - (left + right); - - inner->origin.y = rect->bounds.origin.y + top; - inner->size.height = rect->bounds.size.height - (top + bottom); -} - -static inline gboolean -interval_contains (float p1, float w1, - float p2, float w2) -{ - if (p2 < p1) - return FALSE; - - if (p2 + w2 > p1 + w1) - return FALSE; - - return TRUE; -} - -static inline gboolean -gsk_gl_render_job_update_clip (GskGLRenderJob *job, - const graphene_rect_t *bounds, - gboolean *pushed_clip) -{ - graphene_rect_t transformed_bounds; - gboolean no_clip = FALSE; - gboolean rect_clip = FALSE; - - *pushed_clip = FALSE; - - if (job->current_clip->is_fully_contained) - { - /* Already fully contained - no further checks needed */ - return TRUE; - } - - gsk_gl_render_job_transform_bounds (job, bounds, &transformed_bounds); - - if (!gsk_rect_intersects (&job->current_clip->rect.bounds, &transformed_bounds)) - { - /* Completely clipped away */ - return FALSE; - } - - if (job->current_clip->is_rectilinear) - { - if (gsk_rect_contains_rect (&job->current_clip->rect.bounds, &transformed_bounds)) - no_clip = TRUE; - else - rect_clip = TRUE; - } - else if (gsk_rounded_rect_contains_rect (&job->current_clip->rect, &transformed_bounds)) - { - no_clip = TRUE; - } - else - { - graphene_rect_t inner; - - rounded_rect_get_inner (&job->current_clip->rect, &inner); - - if (interval_contains (inner.origin.x, inner.size.width, - transformed_bounds.origin.x, transformed_bounds.size.width) || - interval_contains (inner.origin.y, inner.size.height, - transformed_bounds.origin.y, transformed_bounds.size.height)) - rect_clip = TRUE; - } - - if (no_clip) - { - /* This node is completely contained inside the clip. - * Record this fact on the clip stack, so we don't do more work - * for child nodes. - */ - - gsk_gl_render_job_push_contained_clip (job); - - *pushed_clip = TRUE; - } - else if (rect_clip && !job->current_clip->is_rectilinear) - { - graphene_rect_t rect; - - /* The clip gets simpler for this node */ - - gsk_rect_intersection (&job->current_clip->rect.bounds, &transformed_bounds, &rect); - gsk_gl_render_job_push_clip (job, &GSK_ROUNDED_RECT_INIT_FROM_RECT (rect)); - - *pushed_clip = TRUE; - } - - return TRUE; -} - -static inline void -rgba_to_half (const GdkRGBA *rgba, - guint16 h[4]) -{ - float_to_half4 ((const float *)rgba, h); -} - -/* fill_vertex_data */ -static void -gsk_gl_render_job_draw_coords (GskGLRenderJob *job, - float min_x, - float min_y, - float max_x, - float max_y, - float min_u, - float min_v, - float max_u, - float max_v, - guint16 c[4]) -{ - GskGLDrawVertex *vertices = gsk_gl_command_queue_add_vertices (job->command_queue); - - vertices[0] = (GskGLDrawVertex) { .position = { min_x, min_y }, .uv = { min_u, min_v }, .color = { c[0], c[1], c[2], c[3] } }; - vertices[1] = (GskGLDrawVertex) { .position = { min_x, max_y }, .uv = { min_u, max_v }, .color = { c[0], c[1], c[2], c[3] } }; - vertices[2] = (GskGLDrawVertex) { .position = { max_x, min_y }, .uv = { max_u, min_v }, .color = { c[0], c[1], c[2], c[3] } }; - vertices[3] = (GskGLDrawVertex) { .position = { max_x, max_y }, .uv = { max_u, max_v }, .color = { c[0], c[1], c[2], c[3] } }; - vertices[4] = (GskGLDrawVertex) { .position = { min_x, max_y }, .uv = { min_u, max_v }, .color = { c[0], c[1], c[2], c[3] } }; - vertices[5] = (GskGLDrawVertex) { .position = { max_x, min_y }, .uv = { max_u, min_v }, .color = { c[0], c[1], c[2], c[3] } }; -} - -/* load_vertex_data_with_region */ -static inline void -gsk_gl_render_job_draw_offscreen_with_color (GskGLRenderJob *job, - const graphene_rect_t *bounds, - const GskGLRenderOffscreen *offscreen, - guint16 color[4]) -{ - float min_x = job->offset_x + bounds->origin.x; - float min_y = job->offset_y + bounds->origin.y; - float max_x = min_x + bounds->size.width; - float max_y = min_y + bounds->size.height; - float y1 = offscreen->was_offscreen ? offscreen->area.y2 : offscreen->area.y; - float y2 = offscreen->was_offscreen ? offscreen->area.y : offscreen->area.y2; - - gsk_gl_render_job_draw_coords (job, - min_x, min_y, max_x, max_y, - offscreen->area.x, y1, offscreen->area.x2, y2, - color); -} - -static inline void -gsk_gl_render_job_draw_offscreen (GskGLRenderJob *job, - const graphene_rect_t *bounds, - const GskGLRenderOffscreen *offscreen) -{ - gsk_gl_render_job_draw_offscreen_with_color (job, bounds, offscreen, - (guint16[]) { FP16_ZERO, FP16_ZERO, FP16_ZERO, FP16_ZERO }); -} - -/* load_float_vertex_data */ -static inline void -gsk_gl_render_job_draw_with_color (GskGLRenderJob *job, - float x, - float y, - float width, - float height, - guint16 color[4]) -{ - float min_x = job->offset_x + x; - float min_y = job->offset_y + y; - float max_x = min_x + width; - float max_y = min_y + height; - - gsk_gl_render_job_draw_coords (job, min_x, min_y, max_x, max_y, 0, 0, 1, 1, color); -} - -static inline void -gsk_gl_render_job_draw (GskGLRenderJob *job, - float x, - float y, - float width, - float height) -{ - gsk_gl_render_job_draw_with_color (job, x, y, width, height, - (guint16[]) { FP_ZERO, FP_ZERO, FP_ZERO, FP_ZERO }); -} - -/* load_vertex_data */ -static inline void -gsk_gl_render_job_draw_rect_with_color (GskGLRenderJob *job, - const graphene_rect_t *bounds, - guint16 color[4]) -{ - gsk_gl_render_job_draw_with_color (job, - bounds->origin.x, - bounds->origin.y, - bounds->size.width, - bounds->size.height, - color); -} -static inline void -gsk_gl_render_job_draw_rect (GskGLRenderJob *job, - const graphene_rect_t *bounds) -{ - gsk_gl_render_job_draw (job, - bounds->origin.x, - bounds->origin.y, - bounds->size.width, - bounds->size.height); -} - -/* load_offscreen_vertex_data */ -static inline void -gsk_gl_render_job_draw_offscreen_rect (GskGLRenderJob *job, - const graphene_rect_t *bounds) -{ - float min_x = job->offset_x + bounds->origin.x; - float min_y = job->offset_y + bounds->origin.y; - float max_x = min_x + bounds->size.width; - float max_y = min_y + bounds->size.height; - guint16 color[4] = { FP16_ZERO, FP16_ZERO, FP16_ZERO, FP16_ZERO }; - - gsk_gl_render_job_draw_coords (job, - min_x, min_y, max_x, max_y, - 0, 1, 1, 0, - color); -} - -static inline gboolean -gsk_gl_render_job_begin_draw (GskGLRenderJob *job, - GskGLProgram *program) -{ - job->current_program = program; - - if (!gsk_gl_command_queue_begin_draw (job->command_queue, - program->program_info, - job->viewport.size.width, - job->viewport.size.height)) - return FALSE; - - gsk_gl_uniform_state_set4fv (program->uniforms, - program->program_info, - UNIFORM_SHARED_VIEWPORT, - job->driver->stamps[UNIFORM_SHARED_VIEWPORT], - 1, - (const float *)&job->viewport); - - gsk_gl_uniform_state_set_matrix (program->uniforms, - program->program_info, - UNIFORM_SHARED_MODELVIEW, - job->driver->stamps[UNIFORM_SHARED_MODELVIEW], - &job->current_modelview->matrix); - - gsk_gl_uniform_state_set_matrix (program->uniforms, - program->program_info, - UNIFORM_SHARED_PROJECTION, - job->driver->stamps[UNIFORM_SHARED_PROJECTION], - &job->projection); - - gsk_gl_uniform_state_set_rounded_rect (program->uniforms, - program->program_info, - UNIFORM_SHARED_CLIP_RECT, - job->driver->stamps[UNIFORM_SHARED_CLIP_RECT], - &job->current_clip->rect); - - gsk_gl_uniform_state_set1f (program->uniforms, - program->program_info, - UNIFORM_SHARED_ALPHA, - job->driver->stamps[UNIFORM_SHARED_ALPHA], - job->alpha); - - return TRUE; -} - -#define CHOOSE_PROGRAM(job,name) \ - (job->current_clip->is_fully_contained \ - ? job->driver->name ## _no_clip \ - : (job->current_clip->is_rectilinear \ - ? job->driver->name ## _rect_clip \ - : job->driver->name)) - -static inline void -gsk_gl_render_job_split_draw (GskGLRenderJob *job) -{ - gsk_gl_command_queue_split_draw (job->command_queue); -} - -static inline void -gsk_gl_render_job_end_draw (GskGLRenderJob *job) -{ - gsk_gl_command_queue_end_draw (job->command_queue); - - job->current_program = NULL; -} - -static inline void -gsk_gl_render_job_visit_as_fallback (GskGLRenderJob *job, - const GskRenderNode *node) -{ - float scale_x = job->scale_x; - float scale_y = job->scale_y; - int surface_width = ceilf (node->bounds.size.width * fabsf (scale_x)); - int surface_height = ceilf (node->bounds.size.height * fabsf (scale_y)); - GdkTexture *texture; - cairo_surface_t *surface; - cairo_surface_t *rendered_surface; - cairo_t *cr; - int texture_id; - GskTextureKey key; - - if (surface_width <= 0 || surface_height <= 0) - return; - - key.pointer = node; - key.pointer_is_child = FALSE; - key.scale_x = scale_x; - key.scale_y = scale_y; - - texture_id = gsk_gl_driver_lookup_texture (job->driver, &key, NULL); - - if (texture_id != 0) - goto done; - - /* We first draw the recording surface on an image surface, - * just because the scaleY(-1) later otherwise screws up the - * rendering... */ - { - rendered_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, - surface_width, - surface_height); - - cairo_surface_set_device_scale (rendered_surface, fabsf (scale_x), fabsf (scale_y)); - cr = cairo_create (rendered_surface); - - cairo_save (cr); - cairo_translate (cr, - node->bounds.origin.x, - node->bounds.origin.y); - /* Render nodes don't modify state, so casting away the const is fine here */ - gsk_render_node_draw_fallback ((GskRenderNode *)node, cr); - cairo_restore (cr); - cairo_destroy (cr); - } - - surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, - surface_width, - surface_height); - cairo_surface_set_device_scale (surface, fabsf (scale_x), fabsf (scale_y)); - cr = cairo_create (surface); - - /* We draw upside down here, so it matches what GL does. */ - cairo_save (cr); - cairo_scale (cr, scale_x < 0 ? -1 : 1, scale_y < 0 ? 1 : -1); - cairo_translate (cr, scale_x < 0 ? - surface_width / fabsf (scale_x) : 0, - scale_y < 0 ? 0 : - surface_height / fabsf (scale_y)); - cairo_set_source_surface (cr, rendered_surface, 0, 0); - cairo_rectangle (cr, 0, 0, surface_width / fabsf (scale_x), surface_height / fabsf (scale_y)); - cairo_fill (cr); - cairo_restore (cr); - cairo_destroy (cr); - - /* Create texture to upload */ - texture = gdk_texture_new_for_surface (surface); - texture_id = gsk_gl_driver_load_texture (job->driver, texture, FALSE); - - if (gdk_gl_context_has_feature (job->command_queue->context, GDK_GL_FEATURE_DEBUG)) - gdk_gl_context_label_object_printf (job->command_queue->context, GL_TEXTURE, texture_id, - "Fallback %s %d", - g_type_name_from_instance ((GTypeInstance *) node), - texture_id); - - g_object_unref (texture); - cairo_surface_destroy (surface); - cairo_surface_destroy (rendered_surface); - - gsk_gl_driver_cache_texture (job->driver, &key, texture_id); - -done: - if (scale_x < 0 || scale_y < 0) - { - GskTransform *transform = gsk_transform_translate (gsk_transform_scale (NULL, scale_x < 0 ? -1 : 1, scale_y < 0 ? -1 : 1), - &GRAPHENE_POINT_INIT (scale_x < 0 ? - (node->bounds.size.width + 2 * node->bounds.origin.x) : 0, - scale_y < 0 ? - (node->bounds.size.height + 2 * node->bounds.origin.y) : 0)); - gsk_gl_render_job_push_modelview (job, transform); - gsk_transform_unref (transform); - } - - if (!gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit))) - goto out; - - gsk_gl_program_set_uniform_texture (job->current_program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, - GL_TEXTURE0, - texture_id); - job->source_is_glyph_atlas = FALSE; - gsk_gl_render_job_draw_offscreen_rect (job, &node->bounds); - gsk_gl_render_job_end_draw (job); - -out: - if (scale_x < 0 || scale_y < 0) - gsk_gl_render_job_pop_modelview (job); -} - -static guint -blur_offscreen (GskGLRenderJob *job, - GskGLRenderOffscreen *offscreen, - int texture_to_blur_width, - int texture_to_blur_height, - float blur_radius_x, - float blur_radius_y) -{ - const GskRoundedRect new_clip = GSK_ROUNDED_RECT_INIT (0, 0, texture_to_blur_width, texture_to_blur_height); - GskGLRenderTarget *pass1; - GskGLRenderTarget *pass2; - graphene_matrix_t prev_projection; - graphene_rect_t prev_viewport; - guint prev_fbo; - - g_assert (blur_radius_x > 0); - g_assert (blur_radius_y > 0); - g_assert (offscreen->texture_id > 0); - g_assert (offscreen->area.x2 > offscreen->area.x); - g_assert (offscreen->area.y2 > offscreen->area.y); - - if (!gsk_gl_driver_create_render_target (job->driver, - MAX (texture_to_blur_width, 1), - MAX (texture_to_blur_height, 1), - job->target_format, - &pass1)) - return 0; - - if (texture_to_blur_width <= 0 || texture_to_blur_height <= 0) - return gsk_gl_driver_release_render_target (job->driver, pass1, FALSE); - - if (!gsk_gl_driver_create_render_target (job->driver, - texture_to_blur_width, - texture_to_blur_height, - job->target_format, - &pass2)) - return gsk_gl_driver_release_render_target (job->driver, pass1, FALSE); - - gsk_gl_render_job_set_viewport (job, &new_clip.bounds, &prev_viewport); - gsk_gl_render_job_set_projection_from_rect (job, &new_clip.bounds, &prev_projection); - gsk_gl_render_job_set_modelview (job, NULL); - gsk_gl_render_job_push_clip (job, &new_clip); - - /* Bind new framebuffer and clear it */ - prev_fbo = gsk_gl_command_queue_bind_framebuffer (job->command_queue, pass1->framebuffer_id); - gsk_gl_command_queue_clear (job->command_queue, 0, &job->viewport); - - /* Begin drawing the first horizontal pass, using offscreen as the - * source texture for the program. - */ - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blur))) - { - gsk_gl_program_set_uniform_texture (job->current_program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, - GL_TEXTURE0, - offscreen->texture_id); - job->source_is_glyph_atlas = FALSE; - gsk_gl_program_set_uniform1f (job->current_program, - UNIFORM_BLUR_RADIUS, 0, - blur_radius_x); - gsk_gl_program_set_uniform2f (job->current_program, - UNIFORM_BLUR_SIZE, 0, - texture_to_blur_width, - texture_to_blur_height); - gsk_gl_program_set_uniform2f (job->current_program, - UNIFORM_BLUR_DIR, 0, - 1, 0); - gsk_gl_render_job_draw_coords (job, - 0, 0, texture_to_blur_width, texture_to_blur_height, - 0, 1, 1, 0, - (guint16[]) { FP16_ZERO, FP16_ZERO, FP16_ZERO, FP16_ZERO }); - gsk_gl_render_job_end_draw (job); - } - - /* Bind second pass framebuffer and clear it */ - gsk_gl_command_queue_bind_framebuffer (job->command_queue, pass2->framebuffer_id); - gsk_gl_command_queue_clear (job->command_queue, 0, &job->viewport); - - /* Draw using blur program with first pass as source texture */ - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blur))) - { - gsk_gl_program_set_uniform_texture (job->current_program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, - GL_TEXTURE0, - pass1->texture_id); - job->source_is_glyph_atlas = FALSE; - gsk_gl_program_set_uniform1f (job->current_program, - UNIFORM_BLUR_RADIUS, 0, - blur_radius_y); - gsk_gl_program_set_uniform2f (job->current_program, - UNIFORM_BLUR_SIZE, 0, - texture_to_blur_width, - texture_to_blur_height); - gsk_gl_program_set_uniform2f (job->current_program, - UNIFORM_BLUR_DIR, 0, - 0, 1); - gsk_gl_render_job_draw_coords (job, - 0, 0, texture_to_blur_width, texture_to_blur_height, - 0, 1, 1, 0, - (guint16[]) { FP16_ZERO, FP16_ZERO, FP16_ZERO, FP16_ZERO }); - gsk_gl_render_job_end_draw (job); - } - - gsk_gl_render_job_pop_modelview (job); - gsk_gl_render_job_pop_clip (job); - gsk_gl_render_job_set_viewport (job, &prev_viewport, NULL); - gsk_gl_render_job_set_projection (job, &prev_projection); - gsk_gl_command_queue_bind_framebuffer (job->command_queue, prev_fbo); - - gsk_gl_driver_release_render_target (job->driver, pass1, TRUE); - - return gsk_gl_driver_release_render_target (job->driver, pass2, FALSE); -} - -static void -blur_node (GskGLRenderJob *job, - GskGLRenderOffscreen *offscreen, - const GskRenderNode *node, - float blur_radius, - float *min_x, - float *max_x, - float *min_y, - float *max_y) -{ - const float blur_extra = blur_radius * 2.0; /* 2.0 = shader radius_multiplier */ - const float half_blur_extra = (blur_extra / 2.0); - float scale_x = job->scale_x; - float scale_y = job->scale_y; - float texture_width; - float texture_height; - - g_assert (blur_radius > 0); - - /* Increase texture size for the given blur radius and scale it */ - texture_width = ceilf ((node->bounds.size.width + blur_extra)); - texture_height = ceilf ((node->bounds.size.height + blur_extra)); - - /* Only blur this if the out region has no texture id yet */ - if (offscreen->texture_id == 0) - { - const graphene_rect_t bounds = GRAPHENE_RECT_INIT (node->bounds.origin.x - half_blur_extra, - node->bounds.origin.y - half_blur_extra, - texture_width, texture_height); - - offscreen->bounds = &bounds; - offscreen->reset_clip = TRUE; - offscreen->force_offscreen = TRUE; - - if (!gsk_gl_render_job_visit_node_with_offscreen (job, node, offscreen)) - g_assert_not_reached (); - - /* Ensure that we actually got a real texture_id */ - g_assert (offscreen->texture_id != 0); - - offscreen->texture_id = blur_offscreen (job, - offscreen, - texture_width * fabsf (scale_x), - texture_height * fabsf (scale_y), - blur_radius * fabsf (scale_x), - blur_radius * fabsf (scale_y)); - init_full_texture_region (offscreen); - } - - *min_x = job->offset_x + node->bounds.origin.x - half_blur_extra; - *max_x = job->offset_x + node->bounds.origin.x + node->bounds.size.width + half_blur_extra; - *min_y = job->offset_y + node->bounds.origin.y - half_blur_extra; - *max_y = job->offset_y + node->bounds.origin.y + node->bounds.size.height + half_blur_extra; -} - -#define ATLAS_SIZE 512 - -static void -get_color_node_color_as_srgb (const GskRenderNode *node, - GdkRGBA *rgba) -{ - const GdkColor *color = gsk_color_node_get_color2 (node); - gdk_color_to_float (color, GDK_COLOR_STATE_SRGB, (float *) rgba); -} - -static inline void -gsk_gl_render_job_visit_color_node (GskGLRenderJob *job, - const GskRenderNode *node) -{ - GdkRGBA rgba; - guint16 color[4]; - GskGLProgram *program; - GskGLCommandBatch *batch; - - get_color_node_color_as_srgb (node, &rgba); - if (RGBA_IS_CLEAR (&rgba)) - return; - - rgba_to_half (&rgba, color); - - /* Avoid switching away from the coloring program for - * rendering a solid color. - */ - program = CHOOSE_PROGRAM (job, coloring); - batch = gsk_gl_command_queue_get_batch (job->command_queue); - - /* Limit the size, or we end up with a coordinate overflow somewhere. */ - if (job->source_is_glyph_atlas && - node->bounds.size.width < 300 && - node->bounds.size.height < 300 && - batch->any.kind == GSK_GL_COMMAND_KIND_DRAW && - batch->any.program == program->id) - { - GskGLRenderOffscreen offscreen = {0}; - - if (gsk_gl_render_job_begin_draw (job, program)) - { - /* The top left few pixels in our atlases are always - * solid white, so we can use it here, without - * having to choose any particular atlas texture. - */ - offscreen.was_offscreen = FALSE; - offscreen.area.x = 1.f / ATLAS_SIZE; - offscreen.area.y = 1.f / ATLAS_SIZE; - offscreen.area.x2 = 2.f / ATLAS_SIZE; - offscreen.area.y2 = 2.f / ATLAS_SIZE; - - gsk_gl_render_job_draw_offscreen_with_color (job, - &node->bounds, - &offscreen, - color); - - gsk_gl_render_job_end_draw (job); - } - } - else - { - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, color))) - { - gsk_gl_render_job_draw_rect_with_color (job, &node->bounds, color); - gsk_gl_render_job_end_draw (job); - } - } -} - -static inline void -gsk_gl_render_job_visit_linear_gradient_node (GskGLRenderJob *job, - const GskRenderNode *node) -{ - const GskColorStop *stops = gsk_linear_gradient_node_get_color_stops (node, NULL); - const graphene_point_t *start = gsk_linear_gradient_node_get_start (node); - const graphene_point_t *end = gsk_linear_gradient_node_get_end (node); - int n_color_stops = gsk_linear_gradient_node_get_n_color_stops (node); - gboolean repeat = GSK_RENDER_NODE_TYPE (node) == GSK_REPEATING_LINEAR_GRADIENT_NODE; - float x1 = job->offset_x + start->x; - float x2 = job->offset_x + end->x; - float y1 = job->offset_y + start->y; - float y2 = job->offset_y + end->y; - - g_assert (n_color_stops < MAX_GRADIENT_STOPS); - - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, linear_gradient))) - { - gsk_gl_program_set_uniform1i (job->current_program, - UNIFORM_LINEAR_GRADIENT_NUM_COLOR_STOPS, 0, - n_color_stops); - gsk_gl_program_set_uniform1fv (job->current_program, - UNIFORM_LINEAR_GRADIENT_COLOR_STOPS, 0, - n_color_stops * 5, - (const float *)stops); - gsk_gl_program_set_uniform4f (job->current_program, - UNIFORM_LINEAR_GRADIENT_POINTS, 0, - x1, y1, x2 - x1, y2 - y1); - gsk_gl_program_set_uniform1i (job->current_program, - UNIFORM_LINEAR_GRADIENT_REPEAT, 0, - repeat); - gsk_gl_render_job_draw_rect (job, &node->bounds); - gsk_gl_render_job_end_draw (job); - } -} - -static inline void -gsk_gl_render_job_visit_conic_gradient_node (GskGLRenderJob *job, - const GskRenderNode *node) -{ - static const float scale = 0.5f * M_1_PI; - - const GskColorStop *stops = gsk_conic_gradient_node_get_color_stops (node, NULL); - const graphene_point_t *center = gsk_conic_gradient_node_get_center (node); - int n_color_stops = gsk_conic_gradient_node_get_n_color_stops (node); - float angle = gsk_conic_gradient_node_get_angle (node); - float bias = angle * scale + 2.0f; - - g_assert (n_color_stops < MAX_GRADIENT_STOPS); - - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, conic_gradient))) - { - gsk_gl_program_set_uniform1i (job->current_program, - UNIFORM_CONIC_GRADIENT_NUM_COLOR_STOPS, 0, - n_color_stops); - gsk_gl_program_set_uniform1fv (job->current_program, - UNIFORM_CONIC_GRADIENT_COLOR_STOPS, 0, - n_color_stops * 5, - (const float *)stops); - gsk_gl_program_set_uniform4f (job->current_program, - UNIFORM_CONIC_GRADIENT_GEOMETRY, 0, - job->offset_x + center->x, - job->offset_y + center->y, - scale, - bias); - gsk_gl_render_job_draw_rect (job, &node->bounds); - gsk_gl_render_job_end_draw (job); - } -} - -static inline void -gsk_gl_render_job_visit_radial_gradient_node (GskGLRenderJob *job, - const GskRenderNode *node) -{ - int n_color_stops = gsk_radial_gradient_node_get_n_color_stops (node); - const GskColorStop *stops = gsk_radial_gradient_node_get_color_stops (node, NULL); - const graphene_point_t *center = gsk_radial_gradient_node_get_center (node); - float start = gsk_radial_gradient_node_get_start (node); - float end = gsk_radial_gradient_node_get_end (node); - float hradius = gsk_radial_gradient_node_get_hradius (node); - float vradius = gsk_radial_gradient_node_get_vradius (node); - gboolean repeat = GSK_RENDER_NODE_TYPE (node) == GSK_REPEATING_RADIAL_GRADIENT_NODE; - float scale = 1.0f / (end - start); - float bias = -start * scale; - - g_assert (n_color_stops < MAX_GRADIENT_STOPS); - - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, radial_gradient))) - { - gsk_gl_program_set_uniform1i (job->current_program, - UNIFORM_RADIAL_GRADIENT_NUM_COLOR_STOPS, 0, - n_color_stops); - gsk_gl_program_set_uniform1fv (job->current_program, - UNIFORM_RADIAL_GRADIENT_COLOR_STOPS, 0, - n_color_stops * 5, - (const float *)stops); - gsk_gl_program_set_uniform1i (job->current_program, - UNIFORM_RADIAL_GRADIENT_REPEAT, 0, - repeat); - gsk_gl_program_set_uniform2f (job->current_program, - UNIFORM_RADIAL_GRADIENT_RANGE, 0, - scale, bias); - gsk_gl_program_set_uniform4f (job->current_program, - UNIFORM_RADIAL_GRADIENT_GEOMETRY, 0, - job->offset_x + center->x, - job->offset_y + center->y, - 1.0f / (hradius * job->scale_x), - 1.0f / (vradius * job->scale_y)); - gsk_gl_render_job_draw_rect (job, &node->bounds); - gsk_gl_render_job_end_draw (job); - } -} - -static inline void -gsk_gl_render_job_visit_clipped_child (GskGLRenderJob *job, - const GskRenderNode *child, - const graphene_rect_t *clip) -{ - graphene_rect_t transformed_clip; - GskRoundedRect intersection; - GskRoundedRectIntersection result; - - gsk_gl_render_job_transform_bounds (job, clip, &transformed_clip); - - if (job->current_clip->is_rectilinear) - { - memset (&intersection.corner, 0, sizeof intersection.corner); - gsk_rect_intersection (&transformed_clip, - &job->current_clip->rect.bounds, - &intersection.bounds); - - gsk_gl_render_job_push_clip (job, &intersection); - gsk_gl_render_job_visit_node (job, child); - gsk_gl_render_job_pop_clip (job); - return; - } - - result = gsk_rounded_rect_intersect_with_rect (&job->current_clip->rect, - &transformed_clip, - &intersection); - - if (result == GSK_INTERSECTION_EMPTY) - return; - - if (result == GSK_INTERSECTION_NONEMPTY) - { - gsk_gl_render_job_push_clip (job, &intersection); - gsk_gl_render_job_visit_node (job, child); - gsk_gl_render_job_pop_clip (job); - } - else - { - GskGLRenderOffscreen offscreen = {0}; - - offscreen.bounds = clip; - offscreen.force_offscreen = TRUE; - offscreen.reset_clip = TRUE; - offscreen.do_not_cache = TRUE; - - gsk_gl_render_job_visit_node_with_offscreen (job, child, &offscreen); - - g_assert (offscreen.texture_id); - - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit))) - { - gsk_gl_program_set_uniform_texture (job->current_program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, - GL_TEXTURE0, - offscreen.texture_id); - job->source_is_glyph_atlas = FALSE; - gsk_gl_render_job_draw_offscreen_rect (job, clip); - gsk_gl_render_job_end_draw (job); - } - } -} - -static inline void -gsk_gl_render_job_visit_clip_node (GskGLRenderJob *job, - const GskRenderNode *node) -{ - const graphene_rect_t *clip = gsk_clip_node_get_clip (node); - const GskRenderNode *child = gsk_clip_node_get_child (node); - - gsk_gl_render_job_visit_clipped_child (job, child, clip); -} - -static inline void -gsk_gl_render_job_visit_rounded_clip_node (GskGLRenderJob *job, - const GskRenderNode *node) -{ - const GskRenderNode *child = gsk_rounded_clip_node_get_child (node); - const GskRoundedRect *clip = gsk_rounded_clip_node_get_clip (node); - GskRoundedRect transformed_clip; - gboolean need_offscreen; - - if (node_is_invisible (child)) - return; - - gsk_gl_render_job_transform_rounded_rect (job, clip, &transformed_clip); - - if (job->current_clip->is_rectilinear) - { - GskRoundedRect intersected_clip; - GskRoundedRectIntersection result; - - result = gsk_rounded_rect_intersect_with_rect (&transformed_clip, - &job->current_clip->rect.bounds, - &intersected_clip); - - if (result == GSK_INTERSECTION_EMPTY) - return; - - if (result == GSK_INTERSECTION_NONEMPTY) - { - gsk_gl_render_job_push_clip (job, &intersected_clip); - gsk_gl_render_job_visit_node (job, child); - gsk_gl_render_job_pop_clip (job); - return; - } - } - - /* After this point we are really working with a new and a current clip - * which both have rounded corners. - */ - - if (clips_get_size (&job->clip) <= 1) - need_offscreen = FALSE; - else if (gsk_rounded_rect_contains_rect (&job->current_clip->rect, &transformed_clip.bounds)) - need_offscreen = FALSE; - else - need_offscreen = TRUE; - - if (!need_offscreen) - { - gsk_gl_render_job_push_clip (job, &transformed_clip); - gsk_gl_render_job_visit_node (job, child); - gsk_gl_render_job_pop_clip (job); - } - else - { - GskGLRenderOffscreen offscreen = {0}; - - offscreen.bounds = &node->bounds; - offscreen.force_offscreen = TRUE; - offscreen.reset_clip = FALSE; - - gsk_gl_render_job_push_clip (job, &transformed_clip); - if (!gsk_gl_render_job_visit_node_with_offscreen (job, child, &offscreen)) - g_assert_not_reached (); - gsk_gl_render_job_pop_clip (job); - - g_assert (offscreen.texture_id); - - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit))) - { - gsk_gl_program_set_uniform_texture (job->current_program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, - GL_TEXTURE0, - offscreen.texture_id); - job->source_is_glyph_atlas = FALSE; - gsk_gl_render_job_draw_offscreen (job, &node->bounds, &offscreen); - gsk_gl_render_job_end_draw (job); - } - } -} - -static inline void -gsk_gl_render_job_visit_rect_border_node (GskGLRenderJob *job, - const GskRenderNode *node) -{ - const GdkRGBA *colors = gsk_border_node_get_colors (node); - const float *widths = gsk_border_node_get_widths (node); - const graphene_point_t *origin = &node->bounds.origin; - const graphene_size_t *size = &node->bounds.size; - guint16 color[4]; - - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, color))) - { - if (widths[0] > 0) - { - rgba_to_half (&colors[0], color); - gsk_gl_render_job_draw_rect_with_color (job, - &GRAPHENE_RECT_INIT (origin->x, origin->y, size->width - widths[1], widths[0]), - color); - } - - if (widths[1] > 0) - { - rgba_to_half (&colors[1], color); - gsk_gl_render_job_draw_rect_with_color (job, - &GRAPHENE_RECT_INIT (origin->x + size->width - widths[1], origin->y, widths[1], size->height - widths[2]), - color); - } - - if (widths[2] > 0) - { - rgba_to_half (&colors[2], color); - gsk_gl_render_job_draw_rect_with_color (job, - &GRAPHENE_RECT_INIT (origin->x + widths[3], origin->y + size->height - widths[2], size->width - widths[3], widths[2]), - color); - } - - if (widths[3] > 0) - { - rgba_to_half (&colors[3], color); - gsk_gl_render_job_draw_rect_with_color (job, - &GRAPHENE_RECT_INIT (origin->x, origin->y + widths[0], widths[3], size->height - widths[0]), - color); - } - - gsk_gl_render_job_end_draw (job); - } -} - -static inline void -gsk_gl_render_job_visit_border_node (GskGLRenderJob *job, - const GskRenderNode *node) -{ - const GskRoundedRect *rounded_outline = gsk_border_node_get_outline (node); - const GdkRGBA *colors = gsk_border_node_get_colors (node); - const float *widths = gsk_border_node_get_widths (node); - struct { - float w; - float h; - } sizes[4]; - float min_x = job->offset_x + node->bounds.origin.x; - float min_y = job->offset_y + node->bounds.origin.y; - float max_x = min_x + node->bounds.size.width; - float max_y = min_y + node->bounds.size.height; - GskRoundedRect outline; - guint16 color[4]; - - memset (sizes, 0, sizeof sizes); - - if (widths[0] > 0) - { - sizes[0].h = MAX (widths[0], rounded_outline->corner[0].height); - sizes[1].h = MAX (widths[0], rounded_outline->corner[1].height); - } - - if (widths[1] > 0) - { - sizes[1].w = MAX (widths[1], rounded_outline->corner[1].width); - sizes[2].w = MAX (widths[1], rounded_outline->corner[2].width); - } - - if (widths[2] > 0) - { - sizes[2].h = MAX (widths[2], rounded_outline->corner[2].height); - sizes[3].h = MAX (widths[2], rounded_outline->corner[3].height); - } - - if (widths[3] > 0) - { - sizes[0].w = MAX (widths[3], rounded_outline->corner[0].width); - sizes[3].w = MAX (widths[3], rounded_outline->corner[3].width); - } - - gsk_gl_render_job_translate_rounded_rect (job, rounded_outline, &outline); - - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, border))) - { - gsk_gl_program_set_uniform4fv (job->current_program, - UNIFORM_BORDER_WIDTHS, 0, - 1, - widths); - gsk_gl_program_set_uniform_rounded_rect (job->current_program, - UNIFORM_BORDER_OUTLINE_RECT, 0, - &outline); - - if (widths[0] > 0) - { - GskGLDrawVertex *vertices = gsk_gl_command_queue_add_vertices (job->command_queue); - - rgba_to_half (&colors[0], color); - - vertices[0] = (GskGLDrawVertex) { .position = { min_x, min_y }, .uv = { 0, 1 }, .color = { color[0], color[1], color[2], color[3] } }; - vertices[1] = (GskGLDrawVertex) { .position = { min_x + sizes[0].w, min_y + sizes[0].h }, .uv = { 0, 0 }, .color = { color[0], color[1], color[2], color[3] } }; - vertices[2] = (GskGLDrawVertex) { .position = { max_x, min_y }, .uv = { 1, 1 }, .color = { color[0], color[1], color[2], color[3] } }; - - vertices[3] = (GskGLDrawVertex) { .position = { max_x - sizes[1].w, min_y + sizes[1].h }, .uv = { 1, 0 }, .color = { color[0], color[1], color[2], color[3] } }; - vertices[4] = (GskGLDrawVertex) { .position = { min_x + sizes[0].w, min_y + sizes[0].h }, .uv = { 0, 0 }, .color = { color[0], color[1], color[2], color[3] } }; - vertices[5] = (GskGLDrawVertex) { .position = { max_x, min_y }, .uv = { 1, 1 }, .color = { color[0], color[1], color[2], color[3] } }; - } - - if (widths[1] > 0) - { - GskGLDrawVertex *vertices = gsk_gl_command_queue_add_vertices (job->command_queue); - - rgba_to_half (&colors[1], color); - - vertices[0] = (GskGLDrawVertex) { .position = { max_x - sizes[1].w, min_y + sizes[1].h }, .uv = { 0, 1 }, .color = { color[0], color[1], color[2], color[3] } }; - vertices[1] = (GskGLDrawVertex) { .position = { max_x - sizes[2].w, max_y - sizes[2].h }, .uv = { 0, 0 }, .color = { color[0], color[1], color[2], color[3] } }; - vertices[2] = (GskGLDrawVertex) { .position = { max_x, min_y }, .uv = { 1, 1 }, .color = { color[0], color[1], color[2], color[3] } }; - - vertices[3] = (GskGLDrawVertex) { .position = { max_x, max_y }, .uv = { 1, 0 }, .color = { color[0], color[1], color[2], color[3] } }; - vertices[4] = (GskGLDrawVertex) { .position = { max_x - sizes[2].w, max_y - sizes[2].h }, .uv = { 0, 0 }, .color = { color[0], color[1], color[2], color[3] } }; - vertices[5] = (GskGLDrawVertex) { .position = { max_x, min_y }, .uv = { 1, 1 }, .color = { color[0], color[1], color[2], color[3] } }; - } - - if (widths[2] > 0) - { - GskGLDrawVertex *vertices = gsk_gl_command_queue_add_vertices (job->command_queue); - - rgba_to_half (&colors[2], color); - - vertices[0] = (GskGLDrawVertex) { .position = { min_x + sizes[3].w, max_y - sizes[3].h }, .uv = { 0, 1 }, .color = { color[0], color[1], color[2], color[3] } }; - vertices[1] = (GskGLDrawVertex) { .position = { min_x, max_y }, .uv = { 0, 0 }, .color = { color[0], color[1], color[2], color[3] } }; - vertices[2] = (GskGLDrawVertex) { .position = { max_x - sizes[2].w, max_y - sizes[2].h }, .uv = { 1, 1 }, .color = { color[0], color[1], color[2], color[3] } }; - - vertices[3] = (GskGLDrawVertex) { .position = { max_x, max_y }, .uv = { 1, 0 }, .color = { color[0], color[1], color[2], color[3] } }; - vertices[4] = (GskGLDrawVertex) { .position = { min_x , max_y }, .uv = { 0, 0 }, .color = { color[0], color[1], color[2], color[3] } }; - vertices[5] = (GskGLDrawVertex) { .position = { max_x - sizes[2].w, max_y - sizes[2].h }, .uv = { 1, 1 }, .color = { color[0], color[1], color[2], color[3] } }; - } - - if (widths[3] > 0) - { - GskGLDrawVertex *vertices = gsk_gl_command_queue_add_vertices (job->command_queue); - - rgba_to_half (&colors[3], color); - - vertices[0] = (GskGLDrawVertex) { .position = { min_x, min_y }, .uv = { 0, 1 }, .color = { color[0], color[1], color[2], color[3] } }; - vertices[1] = (GskGLDrawVertex) { .position = { min_x, max_y }, .uv = { 0, 0 }, .color = { color[0], color[1], color[2], color[3] } }; - vertices[2] = (GskGLDrawVertex) { .position = { min_x + sizes[0].w, min_y + sizes[0].h }, .uv = { 1, 1 }, .color = { color[0], color[1], color[2], color[3] } }; - - vertices[3] = (GskGLDrawVertex) { .position = { min_x + sizes[3].w, max_y - sizes[3].h }, .uv = { 1, 0 }, .color = { color[0], color[1], color[2], color[3] } }; - vertices[4] = (GskGLDrawVertex) { .position = { min_x, max_y }, .uv = { 0, 0 }, .color = { color[0], color[1], color[2], color[3] } }; - vertices[5] = (GskGLDrawVertex) { .position = { min_x + sizes[0].w, min_y + sizes[0].h }, .uv = { 1, 1 }, .color = { color[0], color[1], color[2], color[3] } }; - } - - gsk_gl_render_job_end_draw (job); - } -} - -/* A special case for a pattern that occurs frequently with CSS - * backgrounds: two sibling nodes, the first of which is a rounded - * clip node with a color node as child, and the second one is a - * border node, with the same outline as the clip node. We render - * this using the filled_border shader. - */ -static void -gsk_gl_render_job_visit_css_background (GskGLRenderJob *job, - const GskRenderNode *node, - const GskRenderNode *node2) -{ - const GskRenderNode *child = gsk_rounded_clip_node_get_child (node); - const GskRoundedRect *rounded_outline = gsk_border_node_get_outline (node2); - const float *widths = gsk_border_node_get_widths (node2); - float min_x = job->offset_x + node2->bounds.origin.x; - float min_y = job->offset_y + node2->bounds.origin.y; - float max_x = min_x + node2->bounds.size.width; - float max_y = min_y + node2->bounds.size.height; - GskRoundedRect outline; - GskGLDrawVertex *vertices; - guint16 color[4]; - guint16 color2[4]; - GdkRGBA rgba; - - if (node_is_invisible (node2)) - return; - - get_color_node_color_as_srgb (child, &rgba); - rgba_to_half (&gsk_border_node_get_colors (node2)[0], color); - rgba_to_half (&rgba, color2); - - gsk_gl_render_job_translate_rounded_rect (job, rounded_outline, &outline); - - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, filled_border))) - { - gsk_gl_program_set_uniform4fv (job->current_program, - UNIFORM_FILLED_BORDER_WIDTHS, 0, - 1, - widths); - gsk_gl_program_set_uniform_rounded_rect (job->current_program, - UNIFORM_FILLED_BORDER_OUTLINE_RECT, 0, - &outline); - - vertices = gsk_gl_command_queue_add_vertices (job->command_queue); - - vertices[0] = (GskGLDrawVertex) { .position = { min_x, min_y }, .color = { color[0], color[1], color[2], color[3] }, .color2 = { color2[0], color2[1], color2[2], color2[3] } }; - vertices[1] = (GskGLDrawVertex) { .position = { min_x, max_y }, .color = { color[0], color[1], color[2], color[3] }, .color2 = { color2[0], color2[1], color2[2], color2[3] } }; - vertices[2] = (GskGLDrawVertex) { .position = { max_x, min_y }, .color = { color[0], color[1], color[2], color[3] }, .color2 = { color2[0], color2[1], color2[2], color2[3] } }; - vertices[3] = (GskGLDrawVertex) { .position = { max_x, max_y }, .color = { color[0], color[1], color[2], color[3] }, .color2 = { color2[0], color2[1], color2[2], color2[3] } }; - vertices[4] = (GskGLDrawVertex) { .position = { min_x, max_y }, .color = { color[0], color[1], color[2], color[3] }, .color2 = { color2[0], color2[1], color2[2], color2[3] } }; - vertices[5] = (GskGLDrawVertex) { .position = { max_x, min_y }, .color = { color[0], color[1], color[2], color[3] }, .color2 = { color2[0], color2[1], color2[2], color2[3] } }; - - gsk_gl_render_job_end_draw (job); - } -} - -/* Returns TRUE if applying @transform to @bounds - * yields an axis-aligned rectangle - */ -static gboolean -result_is_axis_aligned (GskTransform *transform, - const graphene_rect_t *bounds) -{ - graphene_matrix_t m; - graphene_quad_t q; - graphene_rect_t b; - graphene_point_t b1, b2; - const graphene_point_t *p; - - gsk_transform_to_matrix (transform, &m); - gsk_matrix_transform_rect (&m, bounds, &q); - graphene_quad_bounds (&q, &b); - graphene_rect_get_top_left (&b, &b1); - graphene_rect_get_bottom_right (&b, &b2); - - for (guint i = 0; i < 4; i++) - { - p = graphene_quad_get_point (&q, i); - if (fabsf (p->x - b1.x) > FLT_EPSILON && fabsf (p->x - b2.x) > FLT_EPSILON) - return FALSE; - if (fabsf (p->y - b1.y) > FLT_EPSILON && fabsf (p->y - b2.y) > FLT_EPSILON) - return FALSE; - } - - return TRUE; -} - -static inline void -gsk_gl_render_job_visit_transform_node (GskGLRenderJob *job, - const GskRenderNode *node) -{ - GskTransform *transform = gsk_transform_node_get_transform (node); - const GskTransformCategory category = gsk_transform_get_category (transform); - const GskRenderNode *child = gsk_transform_node_get_child (node); - - switch (category) - { - case GSK_TRANSFORM_CATEGORY_IDENTITY: - gsk_gl_render_job_visit_node (job, child); - break; - - case GSK_TRANSFORM_CATEGORY_2D_TRANSLATE: - { - float dx, dy; - - gsk_transform_node_get_translate (node, &dx, &dy); - gsk_gl_render_job_offset (job, dx, dy); - gsk_gl_render_job_visit_node (job, child); - gsk_gl_render_job_offset (job, -dx, -dy); - } - break; - - case GSK_TRANSFORM_CATEGORY_2D_AFFINE: - { - gsk_gl_render_job_push_modelview (job, transform); - gsk_gl_render_job_visit_node (job, child); - gsk_gl_render_job_pop_modelview (job); - } - break; - - case GSK_TRANSFORM_CATEGORY_2D: - if (node_supports_2d_transform (child)) - { - gsk_gl_render_job_push_modelview (job, transform); - gsk_gl_render_job_visit_node (job, child); - gsk_gl_render_job_pop_modelview (job); - return; - } - G_GNUC_FALLTHROUGH; - case GSK_TRANSFORM_CATEGORY_3D: - case GSK_TRANSFORM_CATEGORY_ANY: - case GSK_TRANSFORM_CATEGORY_UNKNOWN: - if (node_supports_transform (child)) - { - gsk_gl_render_job_push_modelview (job, transform); - gsk_gl_render_job_visit_node (job, child); - gsk_gl_render_job_pop_modelview (job); - } - else - { - GskGLRenderOffscreen offscreen = {0}; - float sx = 1, sy = 1; - gboolean linear_filter = FALSE; - - offscreen.bounds = &child->bounds; - offscreen.force_offscreen = FALSE; - offscreen.reset_clip = TRUE; - - if (!result_is_axis_aligned (transform, &child->bounds)) - linear_filter = TRUE; - - if (category == GSK_TRANSFORM_CATEGORY_2D) - { - graphene_matrix_t m; - double a, b, c, d, tx, ty; - - g_assert (transform != NULL); - gsk_transform_to_matrix (transform, &m); - if (graphene_matrix_to_2d (&m, &a, &b, &c, &d, &tx, &ty)) - { - sx = sqrt (a * a + b * b); - sy = sqrt (c * c + d * d); - } - else - sx = sy = 1; - - if (sx != 1 || sy != 1) - { - GskTransform *scale; - - scale = gsk_transform_translate (gsk_transform_scale (NULL, sx, sy), &GRAPHENE_POINT_INIT (tx, ty)); - gsk_gl_render_job_push_modelview (job, scale); - transform = gsk_transform_transform (gsk_transform_invert (scale), transform); - } - } - - if (gsk_gl_render_job_visit_node_with_offscreen (job, child, &offscreen)) - { - /* For non-trivial transforms, we draw everything on a texture and then - * draw the texture transformed. - */ - if (transform) - gsk_gl_render_job_push_modelview (job, transform); - - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit))) - { - gsk_gl_program_set_uniform_texture_with_filter (job->current_program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, - GL_TEXTURE0, - offscreen.texture_id, - linear_filter ? GL_LINEAR : GL_NEAREST, - linear_filter ? GL_LINEAR : GL_NEAREST); - job->source_is_glyph_atlas = FALSE; - gsk_gl_render_job_draw_offscreen (job, &child->bounds, &offscreen); - gsk_gl_render_job_end_draw (job); - } - - if (transform) - gsk_gl_render_job_pop_modelview (job); - } - - if (category == GSK_TRANSFORM_CATEGORY_2D) - { - if (sx != 1 || sy != 1) - { - gsk_gl_render_job_pop_modelview (job); - gsk_transform_unref (transform); - } - } - } - break; - - default: - g_assert_not_reached (); - } -} - -static inline void -gsk_gl_render_job_visit_unblurred_inset_shadow_node (GskGLRenderJob *job, - const GskRenderNode *node) -{ - const GskRoundedRect *outline = gsk_inset_shadow_node_get_outline (node); - GskRoundedRect transformed_outline; - guint16 color[4]; - - gsk_gl_render_job_translate_rounded_rect (job, outline, &transformed_outline); - - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, inset_shadow))) - { - const GdkRGBA rgba; - - gdk_color_to_float (gsk_inset_shadow_node_get_color2 (node), GDK_COLOR_STATE_SRGB, (float *) &rgba); - - gsk_gl_program_set_uniform_rounded_rect (job->current_program, - UNIFORM_INSET_SHADOW_OUTLINE_RECT, 0, - &transformed_outline); - gsk_gl_program_set_uniform1f (job->current_program, - UNIFORM_INSET_SHADOW_SPREAD, 0, - gsk_inset_shadow_node_get_spread (node)); - gsk_gl_program_set_uniform2f (job->current_program, - UNIFORM_INSET_SHADOW_OFFSET, 0, - gsk_inset_shadow_node_get_dx (node), - gsk_inset_shadow_node_get_dy (node)); - rgba_to_half (&rgba, color); - gsk_gl_render_job_draw_rect_with_color (job, &node->bounds, color); - gsk_gl_render_job_end_draw (job); - } -} - -static inline void -gsk_gl_render_job_visit_blurred_inset_shadow_node (GskGLRenderJob *job, - const GskRenderNode *node) -{ - const GskRoundedRect *node_outline = gsk_inset_shadow_node_get_outline (node); - float blur_radius = gsk_inset_shadow_node_get_blur_radius (node); - float offset_x = gsk_inset_shadow_node_get_dx (node); - float offset_y = gsk_inset_shadow_node_get_dy (node); - float scale_x = job->scale_x; - float scale_y = job->scale_y; - float blur_extra = blur_radius * 2.0; /* 2.0 = shader radius_multiplier */ - float half_blur_extra = blur_radius; - float texture_width; - float texture_height; - int blurred_texture_id; - GskTextureKey key; - GskGLRenderOffscreen offscreen = {0}; - guint16 color[4]; - - g_assert (blur_radius > 0); - - texture_width = ceilf ((node_outline->bounds.size.width + blur_extra) * scale_x); - texture_height = ceilf ((node_outline->bounds.size.height + blur_extra) * scale_y); - - key.pointer = node; - key.pointer_is_child = FALSE; - key.scale_x = scale_x; - key.scale_y = scale_y; - - blurred_texture_id = gsk_gl_driver_lookup_texture (job->driver, &key, NULL); - - if (blurred_texture_id == 0) - { - float spread = gsk_inset_shadow_node_get_spread (node) + half_blur_extra; - GskRoundedRect transformed_outline; - GskRoundedRect outline_to_blur; - GskGLRenderTarget *render_target; - graphene_matrix_t prev_projection; - graphene_rect_t prev_viewport; - guint prev_fbo; - - /* TODO: In the following code, we have to be careful about where we apply the scale. - * We're manually scaling stuff (e.g. the outline) so we can later use texture_width - * and texture_height (which are already scaled) as the geometry and keep the modelview - * at a scale of 1. That's kinda complicated though... */ - - /* Outline of what we actually want to blur later. - * Spread grows inside, so we don't need to account for that. But the blur will need - * to read outside of the inset shadow, so we need to draw some color in there. */ - outline_to_blur = *node_outline; - gsk_rounded_rect_shrink (&outline_to_blur, - -half_blur_extra, - -half_blur_extra, - -half_blur_extra, - -half_blur_extra); - - /* Fit to our texture */ - outline_to_blur.bounds.origin.x = 0; - outline_to_blur.bounds.origin.y = 0; - outline_to_blur.bounds.size.width *= scale_x; - outline_to_blur.bounds.size.height *= scale_y; - - for (guint i = 0; i < 4; i ++) - { - outline_to_blur.corner[i].width *= scale_x; - outline_to_blur.corner[i].height *= scale_y; - } - - if (!gsk_gl_driver_create_render_target (job->driver, - texture_width, texture_height, - get_target_format (job, node), - &render_target)) - g_assert_not_reached (); - - gsk_gl_render_job_set_viewport_for_size (job, texture_width, texture_height, &prev_viewport); - gsk_gl_render_job_set_projection_for_size (job, texture_width, texture_height, &prev_projection); - gsk_gl_render_job_set_modelview (job, NULL); - gsk_gl_render_job_push_clip (job, &GSK_ROUNDED_RECT_INIT (0, 0, texture_width, texture_height)); - - prev_fbo = gsk_gl_command_queue_bind_framebuffer (job->command_queue, render_target->framebuffer_id); - gsk_gl_command_queue_clear (job->command_queue, 0, &job->viewport); - - gsk_gl_render_job_translate_rounded_rect (job, &outline_to_blur, &transformed_outline); - - /* Actual inset shadow outline drawing */ - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, inset_shadow))) - { - const GdkRGBA rgba; - - gdk_color_to_float (gsk_inset_shadow_node_get_color2 (node), GDK_COLOR_STATE_SRGB, (float *) &rgba); - - gsk_gl_program_set_uniform_rounded_rect (job->current_program, - UNIFORM_INSET_SHADOW_OUTLINE_RECT, 0, - &transformed_outline); - gsk_gl_program_set_uniform1f (job->current_program, - UNIFORM_INSET_SHADOW_SPREAD, 0, - spread * MAX (scale_x, scale_y)); - gsk_gl_program_set_uniform2f (job->current_program, - UNIFORM_INSET_SHADOW_OFFSET, 0, - offset_x * scale_x, - offset_y * scale_y); - rgba_to_half (&rgba, color); - gsk_gl_render_job_draw_with_color (job, - 0, 0, texture_width, texture_height, - color); - gsk_gl_render_job_end_draw (job); - } - - gsk_gl_render_job_pop_modelview (job); - gsk_gl_render_job_pop_clip (job); - gsk_gl_render_job_set_projection (job, &prev_projection); - gsk_gl_render_job_set_viewport (job, &prev_viewport, NULL); - gsk_gl_command_queue_bind_framebuffer (job->command_queue, prev_fbo); - - offscreen.texture_id = render_target->texture_id; - init_full_texture_region (&offscreen); - - blurred_texture_id = blur_offscreen (job, - &offscreen, - texture_width, - texture_height, - blur_radius * fabsf (scale_x), - blur_radius * fabsf (scale_y)); - - gsk_gl_driver_release_render_target (job->driver, render_target, TRUE); - - gsk_gl_driver_cache_texture (job->driver, &key, blurred_texture_id); - } - - g_assert (blurred_texture_id != 0); - - /* Blur the rendered unblurred inset shadow */ - /* Use a clip to cut away the unwanted parts outside of the original outline */ - { - const gboolean needs_clip = !gsk_rounded_rect_is_rectilinear (node_outline); - const float tx1 = half_blur_extra * scale_x / texture_width; - const float tx2 = 1.0 - tx1; - const float ty1 = half_blur_extra * scale_y / texture_height; - const float ty2 = 1.0 - ty1; - - if (needs_clip) - { - GskRoundedRect node_clip; - - gsk_gl_render_job_translate_rounded_rect (job, node_outline, &node_clip); - gsk_gl_render_job_push_clip (job, &node_clip); - } - - offscreen.was_offscreen = TRUE; - offscreen.area.x = tx1; - offscreen.area.y = ty1; - offscreen.area.x2 = tx2; - offscreen.area.y2 = ty2; - - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit))) - { - gsk_gl_program_set_uniform_texture (job->current_program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, - GL_TEXTURE0, - blurred_texture_id); - job->source_is_glyph_atlas = FALSE; - gsk_gl_render_job_draw_offscreen (job, &node->bounds, &offscreen); - gsk_gl_render_job_end_draw (job); - } - - if (needs_clip) - gsk_gl_render_job_pop_clip (job); - } -} - -static inline void -gsk_gl_render_job_visit_unblurred_outset_shadow_node (GskGLRenderJob *job, - const GskRenderNode *node) -{ - const GskRoundedRect *outline = gsk_outset_shadow_node_get_outline (node); - GskRoundedRect transformed_outline; - float x = node->bounds.origin.x; - float y = node->bounds.origin.y; - float w = node->bounds.size.width; - float h = node->bounds.size.height; - float spread = gsk_outset_shadow_node_get_spread (node); - float dx = gsk_outset_shadow_node_get_dx (node); - float dy = gsk_outset_shadow_node_get_dy (node); - GdkRGBA rgba; - guint16 color[4]; - const float edge_sizes[] = { // Top, right, bottom, left - spread - dy, spread + dx, spread + dy, spread - dx - }; - const float corner_sizes[][2] = { // top left, top right, bottom right, bottom left - { outline->corner[0].width + spread - dx, outline->corner[0].height + spread - dy }, - { outline->corner[1].width + spread + dx, outline->corner[1].height + spread - dy }, - { outline->corner[2].width + spread + dx, outline->corner[2].height + spread + dy }, - { outline->corner[3].width + spread - dx, outline->corner[3].height + spread + dy }, - }; - - gdk_color_to_float (gsk_outset_shadow_node_get_color2 (node), GDK_COLOR_STATE_SRGB, (float *) &rgba); - rgba_to_half (&rgba, color); - - gsk_gl_render_job_translate_rounded_rect (job, outline, &transformed_outline); - - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, unblurred_outset_shadow))) - { - gsk_gl_program_set_uniform_rounded_rect (job->current_program, - UNIFORM_UNBLURRED_OUTSET_SHADOW_OUTLINE_RECT, 0, - &transformed_outline); - gsk_gl_program_set_uniform1f (job->current_program, - UNIFORM_UNBLURRED_OUTSET_SHADOW_SPREAD, 0, - spread); - gsk_gl_program_set_uniform2f (job->current_program, - UNIFORM_UNBLURRED_OUTSET_SHADOW_OFFSET, 0, - dx, dy); - - /* Corners... */ - if (corner_sizes[0][0] > 0 && corner_sizes[0][1] > 0) /* Top left */ - gsk_gl_render_job_draw_with_color (job, - x, y, corner_sizes[0][0], corner_sizes[0][1], - color); - if (corner_sizes[1][0] > 0 && corner_sizes[1][1] > 0) /* Top right */ - gsk_gl_render_job_draw_with_color (job, - x + w - corner_sizes[1][0], y, - corner_sizes[1][0], corner_sizes[1][1], - color); - if (corner_sizes[2][0] > 0 && corner_sizes[2][1] > 0) /* Bottom right */ - gsk_gl_render_job_draw_with_color (job, - x + w - corner_sizes[2][0], y + h - corner_sizes[2][1], - corner_sizes[2][0], corner_sizes[2][1], - color); - if (corner_sizes[3][0] > 0 && corner_sizes[3][1] > 0) /* Bottom left */ - gsk_gl_render_job_draw_with_color (job, - x, y + h - corner_sizes[3][1], - corner_sizes[3][0], corner_sizes[3][1], - color); - /* Edges... */; - if (edge_sizes[0] > 0) /* Top */ - gsk_gl_render_job_draw_with_color (job, - x + corner_sizes[0][0], y, - w - corner_sizes[0][0] - corner_sizes[1][0], edge_sizes[0], - color); - if (edge_sizes[1] > 0) /* Right */ - gsk_gl_render_job_draw_with_color (job, - x + w - edge_sizes[1], y + corner_sizes[1][1], - edge_sizes[1], h - corner_sizes[1][1] - corner_sizes[2][1], - color); - if (edge_sizes[2] > 0) /* Bottom */ - gsk_gl_render_job_draw_with_color (job, - x + corner_sizes[3][0], y + h - edge_sizes[2], - w - corner_sizes[3][0] - corner_sizes[2][0], edge_sizes[2], - color); - if (edge_sizes[3] > 0) /* Left */ - gsk_gl_render_job_draw_with_color (job, - x, y + corner_sizes[0][1], - edge_sizes[3], h - corner_sizes[0][1] - corner_sizes[3][1], - color); - - gsk_gl_render_job_end_draw (job); - } -} - -static inline void -gsk_gl_render_job_visit_blurred_outset_shadow_node (GskGLRenderJob *job, - const GskRenderNode *node) -{ - const GskRoundedRect *outline = gsk_outset_shadow_node_get_outline (node); - float scale_x = fabsf (job->scale_x); - float scale_y = fabsf (job->scale_y); - float blur_radius = gsk_outset_shadow_node_get_blur_radius (node); - float blur_extra = blur_radius * 2.0f; /* 2.0 = shader radius_multiplier */ - float half_blur_extra = blur_extra / 2.0f; - int extra_blur_pixels_x = ceilf (half_blur_extra * scale_x); - int extra_blur_pixels_y = ceilf (half_blur_extra * scale_y); - float spread = gsk_outset_shadow_node_get_spread (node); - float dx = gsk_outset_shadow_node_get_dx (node); - float dy = gsk_outset_shadow_node_get_dy (node); - GskRoundedRect scaled_outline; - GskRoundedRect transformed_outline; - GskGLRenderOffscreen offscreen = {0}; - int texture_width, texture_height; - int blurred_texture_id; - int cached_tid; - gboolean do_slicing; - GdkRGBA rgba; - guint16 color[4]; - float half_width = outline->bounds.size.width / 2; - float half_height = outline->bounds.size.height / 2; - - gdk_color_to_float (gsk_outset_shadow_node_get_color2 (node), GDK_COLOR_STATE_SRGB, (float *) &rgba); - rgba_to_half (&rgba, color); - - /* scaled_outline is the minimal outline we need to draw the given drop shadow, - * enlarged by the spread and offset by the blur radius. */ - scaled_outline = *outline; - - if (outline->bounds.size.width < blur_extra || - outline->bounds.size.height < blur_extra || - outline->corner[0].width >= half_width || - outline->corner[1].width >= half_width || - outline->corner[2].width >= half_width || - outline->corner[3].width >= half_width || - outline->corner[0].height >= half_height || - outline->corner[1].height >= half_height || - outline->corner[2].height >= half_height || - outline->corner[3].height >= half_height) - { - do_slicing = FALSE; - gsk_rounded_rect_shrink (&scaled_outline, -spread, -spread, -spread, -spread); - } - else - { - /* Shrink our outline to the minimum size that can still hold all the border radii */ - gsk_rounded_rect_shrink_to_minimum (&scaled_outline); - /* Increase by the spread */ - gsk_rounded_rect_shrink (&scaled_outline, -spread, -spread, -spread, -spread); - /* Grow bounds but don't grow corners */ - graphene_rect_inset (&scaled_outline.bounds, - blur_extra / 2.0, - blur_extra / 2.0); - /* For the center part, we add a few pixels */ - scaled_outline.bounds.size.width += SHADOW_EXTRA_SIZE; - scaled_outline.bounds.size.height += SHADOW_EXTRA_SIZE; - - do_slicing = TRUE; - } - - texture_width = (int)ceilf ((scaled_outline.bounds.size.width + blur_extra) * scale_x); - texture_height = (int)ceilf ((scaled_outline.bounds.size.height + blur_extra) * scale_y); - - scaled_outline.bounds.origin.x = extra_blur_pixels_x; - scaled_outline.bounds.origin.y = extra_blur_pixels_y; - scaled_outline.bounds.size.width = texture_width - (extra_blur_pixels_x * 2); - scaled_outline.bounds.size.height = texture_height - (extra_blur_pixels_y * 2); - - for (guint i = 0; i < G_N_ELEMENTS (scaled_outline.corner); i++) - { - scaled_outline.corner[i].width *= scale_x; - scaled_outline.corner[i].height *= scale_y; - } - - cached_tid = gsk_gl_shadow_library_lookup (job->driver->shadows_library, - &scaled_outline, - blur_radius); - - if (cached_tid == 0) - { - GdkGLContext *context = job->command_queue->context; - GskGLRenderTarget *render_target; - graphene_matrix_t prev_projection; - graphene_rect_t prev_viewport; - guint prev_fbo; - - gsk_gl_driver_create_render_target (job->driver, - texture_width, texture_height, - get_target_format (job, node), - &render_target); - - if (gdk_gl_context_has_feature (context, GDK_GL_FEATURE_DEBUG)) - { - gdk_gl_context_label_object_printf (context, - GL_TEXTURE, - render_target->texture_id, - "Outset Shadow Temp %d", - render_target->texture_id); - gdk_gl_context_label_object_printf (context, - GL_FRAMEBUFFER, - render_target->framebuffer_id, - "Outset Shadow FB Temp %d", - render_target->framebuffer_id); - } - - /* Change state for offscreen */ - gsk_gl_render_job_set_projection_for_size (job, texture_width, texture_height, &prev_projection); - gsk_gl_render_job_set_viewport_for_size (job, texture_width, texture_height, &prev_viewport); - gsk_gl_render_job_set_modelview (job, NULL); - gsk_gl_render_job_push_clip (job, &scaled_outline); - - /* Bind render target and clear it */ - prev_fbo = gsk_gl_command_queue_bind_framebuffer (job->command_queue, render_target->framebuffer_id); - gsk_gl_command_queue_clear (job->command_queue, 0, &job->viewport); - - /* Draw the outline using color program */ - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, color))) - { - gsk_gl_render_job_draw_with_color (job, 0, 0, texture_width, texture_height, - (guint16[]){ FP16_ONE, FP16_ONE, FP16_ONE, FP16_ONE }); - gsk_gl_render_job_end_draw (job); - } - - /* Reset state from offscreen */ - gsk_gl_render_job_pop_clip (job); - gsk_gl_render_job_pop_modelview (job); - gsk_gl_render_job_set_viewport (job, &prev_viewport, NULL); - gsk_gl_render_job_set_projection (job, &prev_projection); - - /* Now blur the outline */ - init_full_texture_region (&offscreen); - offscreen.texture_id = gsk_gl_driver_release_render_target (job->driver, render_target, FALSE); - blurred_texture_id = blur_offscreen (job, - &offscreen, - texture_width, - texture_height, - blur_radius * scale_x, - blur_radius * scale_y); - - gsk_gl_shadow_library_insert (job->driver->shadows_library, - &scaled_outline, - blur_radius, - blurred_texture_id); - - gsk_gl_command_queue_bind_framebuffer (job->command_queue, prev_fbo); - } - else - { - blurred_texture_id = cached_tid; - } - - gsk_gl_render_job_translate_rounded_rect (job, outline, &transformed_outline); - - if (!do_slicing) - { - float min_x = floorf (outline->bounds.origin.x - spread - half_blur_extra + dx); - float min_y = floorf (outline->bounds.origin.y - spread - half_blur_extra + dy); - - offscreen.was_offscreen = TRUE; - offscreen.texture_id = blurred_texture_id; - init_full_texture_region (&offscreen); - - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, outset_shadow))) - { - gsk_gl_program_set_uniform_texture (job->current_program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, - GL_TEXTURE0, - blurred_texture_id); - job->source_is_glyph_atlas = FALSE; - gsk_gl_program_set_uniform_rounded_rect (job->current_program, - UNIFORM_OUTSET_SHADOW_OUTLINE_RECT, 0, - &transformed_outline); - gsk_gl_render_job_draw_offscreen_with_color (job, - &GRAPHENE_RECT_INIT (min_x, - min_y, - texture_width / scale_x, - texture_height / scale_y), - &offscreen, - color); - gsk_gl_render_job_end_draw (job); - } - - return; - } - - /* slicing */ - - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, outset_shadow))) - { - gsk_gl_program_set_uniform_texture (job->current_program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, - GL_TEXTURE0, - blurred_texture_id); - job->source_is_glyph_atlas = FALSE; - gsk_gl_program_set_uniform_rounded_rect (job->current_program, - UNIFORM_OUTSET_SHADOW_OUTLINE_RECT, 0, - &transformed_outline); - - { - float min_x = floorf (outline->bounds.origin.x - spread - half_blur_extra + dx); - float min_y = floorf (outline->bounds.origin.y - spread - half_blur_extra + dy); - float max_x = ceilf (outline->bounds.origin.x + outline->bounds.size.width + - half_blur_extra + dx + spread); - float max_y = ceilf (outline->bounds.origin.y + outline->bounds.size.height + - half_blur_extra + dy + spread); - const GskGLTextureNineSlice *slices; - float left_width, center_width, right_width; - float top_height, center_height, bottom_height; - GskGLTexture *texture; - - texture = gsk_gl_driver_get_texture_by_id (job->driver, blurred_texture_id); - slices = gsk_gl_texture_get_nine_slice (texture, &scaled_outline, extra_blur_pixels_x, extra_blur_pixels_y); - - offscreen.was_offscreen = TRUE; - - /* Our texture coordinates MUST be scaled, while the actual vertex coords - * MUST NOT be scaled. - */ - - left_width = slices[NINE_SLICE_TOP_LEFT].rect.width / scale_x; - right_width = slices[NINE_SLICE_TOP_RIGHT].rect.width / scale_x; - center_width = (max_x - min_x) - (left_width + right_width); - - top_height = slices[NINE_SLICE_TOP_LEFT].rect.height / scale_y; - bottom_height = slices[NINE_SLICE_BOTTOM_LEFT].rect.height / scale_y; - center_height = (max_y - min_y) - (top_height + bottom_height); - - /* Top left */ - if (nine_slice_is_visible (&slices[NINE_SLICE_TOP_LEFT])) - { - memcpy (&offscreen.area, &slices[NINE_SLICE_TOP_LEFT].area, sizeof offscreen.area); - gsk_gl_render_job_draw_offscreen_with_color (job, - &GRAPHENE_RECT_INIT (min_x, - min_y, - left_width, - top_height), - &offscreen, - color); - } - - /* Top center */ - if (nine_slice_is_visible (&slices[NINE_SLICE_TOP_CENTER])) - { - memcpy (&offscreen.area, &slices[NINE_SLICE_TOP_CENTER].area, sizeof offscreen.area); - gsk_gl_render_job_draw_offscreen_with_color (job, - &GRAPHENE_RECT_INIT (min_x + left_width, - min_y, - center_width, - top_height), - &offscreen, - color); - } - - /* Top right */ - if (nine_slice_is_visible (&slices[NINE_SLICE_TOP_RIGHT])) - { - memcpy (&offscreen.area, &slices[NINE_SLICE_TOP_RIGHT].area, sizeof offscreen.area); - gsk_gl_render_job_draw_offscreen_with_color (job, - &GRAPHENE_RECT_INIT (max_x - right_width, - min_y, - right_width, - top_height), - &offscreen, - color); - } - - /* Bottom right */ - if (nine_slice_is_visible (&slices[NINE_SLICE_BOTTOM_RIGHT])) - { - memcpy (&offscreen.area, &slices[NINE_SLICE_BOTTOM_RIGHT].area, sizeof offscreen.area); - gsk_gl_render_job_draw_offscreen_with_color (job, - &GRAPHENE_RECT_INIT (max_x - right_width, - max_y - bottom_height, - right_width, - bottom_height), - &offscreen, - color); - } - - /* Bottom left */ - if (nine_slice_is_visible (&slices[NINE_SLICE_BOTTOM_LEFT])) - { - memcpy (&offscreen.area, &slices[NINE_SLICE_BOTTOM_LEFT].area, sizeof offscreen.area); - gsk_gl_render_job_draw_offscreen_with_color (job, - &GRAPHENE_RECT_INIT (min_x, - max_y - bottom_height, - left_width, - bottom_height), - &offscreen, - color); - } - - /* Left side */ - if (nine_slice_is_visible (&slices[NINE_SLICE_LEFT_CENTER])) - { - memcpy (&offscreen.area, &slices[NINE_SLICE_LEFT_CENTER].area, sizeof offscreen.area); - gsk_gl_render_job_draw_offscreen_with_color (job, - &GRAPHENE_RECT_INIT (min_x, - min_y + top_height, - left_width, - center_height), - &offscreen, - color); - } - - /* Right side */ - if (nine_slice_is_visible (&slices[NINE_SLICE_RIGHT_CENTER])) - { - memcpy (&offscreen.area, &slices[NINE_SLICE_RIGHT_CENTER].area, sizeof offscreen.area); - gsk_gl_render_job_draw_offscreen_with_color (job, - &GRAPHENE_RECT_INIT (max_x - right_width, - min_y + top_height, - right_width, - center_height), - &offscreen, - color); - } - - /* Bottom side */ - if (nine_slice_is_visible (&slices[NINE_SLICE_BOTTOM_CENTER])) - { - memcpy (&offscreen.area, &slices[NINE_SLICE_BOTTOM_CENTER].area, sizeof offscreen.area); - gsk_gl_render_job_draw_offscreen_with_color (job, - &GRAPHENE_RECT_INIT (min_x + left_width, - max_y - bottom_height, - center_width, - bottom_height), - &offscreen, - color); - } - - /* Middle */ - if (nine_slice_is_visible (&slices[NINE_SLICE_CENTER])) - { - if (!gsk_rounded_rect_contains_rect (outline, &GRAPHENE_RECT_INIT (min_x + left_width, - min_y + top_height, - center_width, - center_height))) - { - memcpy (&offscreen.area, &slices[NINE_SLICE_CENTER].area, sizeof offscreen.area); - gsk_gl_render_job_draw_offscreen_with_color (job, - &GRAPHENE_RECT_INIT (min_x + left_width, - min_y + top_height, - center_width, - center_height), - &offscreen, - color); - } - } - } - - gsk_gl_render_job_end_draw (job); - } -} - -static inline gboolean G_GNUC_PURE -equal_texture_nodes (const GskRenderNode *node1, - const GskRenderNode *node2) -{ - if (GSK_RENDER_NODE_TYPE (node1) != GSK_TEXTURE_NODE || - GSK_RENDER_NODE_TYPE (node2) != GSK_TEXTURE_NODE) - return FALSE; - - if (gsk_texture_node_get_texture (node1) != - gsk_texture_node_get_texture (node2)) - return FALSE; - - return gsk_rect_equal (&node1->bounds, &node2->bounds); -} - -static inline void -gsk_gl_render_job_visit_cross_fade_node (GskGLRenderJob *job, - const GskRenderNode *node) -{ - const GskRenderNode *start_node = gsk_cross_fade_node_get_start_child (node); - const GskRenderNode *end_node = gsk_cross_fade_node_get_end_child (node); - float progress = gsk_cross_fade_node_get_progress (node); - GskGLRenderOffscreen offscreen_start = {0}; - GskGLRenderOffscreen offscreen_end = {0}; - - g_assert (progress > 0.0); - g_assert (progress < 1.0); - - offscreen_start.force_offscreen = TRUE; - offscreen_start.reset_clip = TRUE; - offscreen_start.bounds = &node->bounds; - - offscreen_end.force_offscreen = TRUE; - offscreen_end.reset_clip = TRUE; - offscreen_end.bounds = &node->bounds; - - gsk_gl_render_job_set_modelview (job, gsk_transform_scale (NULL, fabsf (job->scale_x), fabsf (job->scale_y))); - - if (!gsk_gl_render_job_visit_node_with_offscreen (job, start_node, &offscreen_start)) - { - gsk_gl_render_job_pop_modelview (job); - - gsk_gl_render_job_visit_node (job, end_node); - return; - } - - g_assert (offscreen_start.texture_id); - - if (!gsk_gl_render_job_visit_node_with_offscreen (job, end_node, &offscreen_end)) - { - float prev_alpha; - - gsk_gl_render_job_pop_modelview (job); - - prev_alpha = gsk_gl_render_job_set_alpha (job, job->alpha * progress); - gsk_gl_render_job_visit_node (job, start_node); - gsk_gl_render_job_set_alpha (job, prev_alpha); - return; - } - - gsk_gl_render_job_pop_modelview (job); - - g_assert (offscreen_end.texture_id); - - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, cross_fade))) - { - gsk_gl_program_set_uniform_texture (job->current_program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, - GL_TEXTURE0, - offscreen_start.texture_id); - gsk_gl_program_set_uniform_texture (job->current_program, - UNIFORM_CROSS_FADE_SOURCE2, 0, - GL_TEXTURE_2D, - GL_TEXTURE1, - offscreen_end.texture_id); - job->source_is_glyph_atlas = FALSE; - gsk_gl_program_set_uniform1f (job->current_program, - UNIFORM_CROSS_FADE_PROGRESS, 0, - progress); - gsk_gl_render_job_draw_offscreen (job, &node->bounds, &offscreen_end); - gsk_gl_render_job_end_draw (job); - } -} - -static inline void -gsk_gl_render_job_visit_opacity_node (GskGLRenderJob *job, - const GskRenderNode *node) -{ - const GskRenderNode *child = gsk_opacity_node_get_child (node); - float opacity = gsk_opacity_node_get_opacity (node); - float new_alpha = job->alpha * opacity; - - if (!ALPHA_IS_CLEAR (new_alpha)) - { - float prev_alpha = gsk_gl_render_job_set_alpha (job, new_alpha); - - if (!gsk_render_node_use_offscreen_for_opacity (child)) - { - gsk_gl_render_job_visit_node (job, child); - gsk_gl_render_job_set_alpha (job, prev_alpha); - } - else - { - GskGLRenderOffscreen offscreen = {0}; - - offscreen.bounds = &child->bounds; - offscreen.force_offscreen = TRUE; - offscreen.reset_clip = TRUE; - - /* Note: offscreen rendering resets alpha to 1.0 */ - if (!gsk_gl_render_job_visit_node_with_offscreen (job, child, &offscreen)) - return; - - g_assert (offscreen.texture_id); - - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit))) - { - gsk_gl_program_set_uniform_texture (job->current_program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, - GL_TEXTURE0, - offscreen.texture_id); - job->source_is_glyph_atlas = FALSE; - gsk_gl_render_job_draw_offscreen (job, &node->bounds, &offscreen); - gsk_gl_render_job_end_draw (job); - } - } - - gsk_gl_render_job_set_alpha (job, prev_alpha); - } -} - -static inline int -compute_phase_and_pos (float value, float *pos) -{ - float v; - - *pos = floorf (value); - - v = value - *pos; - - if (v < 0.125) - return 0; - else if (v < 0.375) - return 1; - else if (v < 0.625) - return 2; - else if (v < 0.875) - return 3; - else - { - *pos += 1; - return 0; - } -} - -static inline void -gsk_gl_render_job_visit_text_node (GskGLRenderJob *job, - const GskRenderNode *node, - const GdkRGBA *color, - gboolean force_color) -{ - const PangoFont *font = gsk_text_node_get_font (node); - const PangoGlyphInfo *glyphs = gsk_text_node_get_glyphs (node, NULL); - const graphene_point_t *offset = gsk_text_node_get_offset (node); - float text_scale = MAX (fabsf (job->scale_x), fabsf (job->scale_y)); /* TODO: Fix for uneven scales? */ - guint num_glyphs = gsk_text_node_get_num_glyphs (node); - float x = offset->x + job->offset_x; - float y = offset->y + job->offset_y; - GskGLGlyphLibrary *library = job->driver->glyphs_library; - GskGLCommandBatch *batch; - int x_position = 0; - GskGLGlyphKey lookup; - guint last_texture = 0; - GskGLDrawVertex *vertices; - guint used = 0; - guint16 nc[4] = { FP16_MINUS_ONE, FP16_MINUS_ONE, FP16_MINUS_ONE, FP16_MINUS_ONE }; - guint16 cc[4]; - const guint16 *c; - const PangoGlyphInfo *gi; - guint i; - int yshift; - float ypos; - - if (num_glyphs == 0) - return; - - if ((force_color || !gsk_text_node_has_color_glyphs (node)) && - RGBA_IS_CLEAR (color)) - return; - - rgba_to_half (color, cc); - - lookup.font = (PangoFont *)font; - lookup.scale = (guint) (text_scale * 1024); - - yshift = compute_phase_and_pos (y, &ypos); - - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, coloring))) - { - batch = gsk_gl_command_queue_get_batch (job->command_queue); - vertices = gsk_gl_command_queue_add_n_vertices (job->command_queue, num_glyphs); - - /* We use one quad per character */ - for (i = 0, gi = glyphs; i < num_glyphs; i++, gi++) - { - const GskGLGlyphValue *glyph; - float glyph_x, glyph_y, glyph_x2, glyph_y2; - float tx, ty, tx2, ty2; - float cx; - float cy; - guint texture_id; - - lookup.glyph = gi->glyph; - - /* If the glyph has color, we don't need to recolor anything. - * We tell the shader by setting the color to vec4(-1). - */ - if (!force_color && gi->attr.is_color) - c = nc; - else - c = cc; - - cx = (float)(x_position + gi->geometry.x_offset) / PANGO_SCALE; - lookup.xshift = compute_phase_and_pos (x + cx, &cx); - - if G_UNLIKELY (gi->geometry.y_offset != 0) - { - cy = (float)(gi->geometry.y_offset) / PANGO_SCALE; - lookup.yshift = compute_phase_and_pos (y + cy, &cy); - } - else - { - lookup.yshift = yshift; - cy = ypos; - } - - x_position += gi->geometry.width; - - texture_id = gsk_gl_glyph_library_lookup_or_add (library, &lookup, &glyph); - if G_UNLIKELY (texture_id == 0) - continue; - - if G_UNLIKELY (last_texture != texture_id || batch->draw.vbo_count + GSK_GL_N_VERTICES > 0xffff) - { - if G_LIKELY (last_texture != 0) - { - guint vbo_offset = batch->draw.vbo_offset + batch->draw.vbo_count; - - /* Since we have batched added our VBO vertices to avoid repeated - * calls to the buffer, we need to manually tweak the vbo offset - * of the new batch as otherwise it will point at the end of our - * vbo array. - */ - gsk_gl_render_job_split_draw (job); - batch = gsk_gl_command_queue_get_batch (job->command_queue); - batch->draw.vbo_offset = vbo_offset; - } - - gsk_gl_program_set_uniform_texture (job->current_program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, - GL_TEXTURE0, - texture_id); - job->source_is_glyph_atlas = TRUE; - last_texture = texture_id; - } - - tx = glyph->entry.area.x; - ty = glyph->entry.area.y; - tx2 = glyph->entry.area.x2; - ty2 = glyph->entry.area.y2; - - glyph_x = cx + glyph->ink_rect.x; - glyph_y = cy + glyph->ink_rect.y; - glyph_x2 = glyph_x + glyph->ink_rect.width; - glyph_y2 = glyph_y + glyph->ink_rect.height; - - *(vertices++) = (GskGLDrawVertex) { .position = { glyph_x, glyph_y }, .uv = { tx, ty }, .color = { c[0], c[1], c[2], c[3] } }; - *(vertices++) = (GskGLDrawVertex) { .position = { glyph_x, glyph_y2 }, .uv = { tx, ty2 }, .color = { c[0], c[1], c[2], c[3] } }; - *(vertices++) = (GskGLDrawVertex) { .position = { glyph_x2, glyph_y }, .uv = { tx2, ty }, .color = { c[0], c[1], c[2], c[3] } }; - - *(vertices++) = (GskGLDrawVertex) { .position = { glyph_x2, glyph_y2 }, .uv = { tx2, ty2 }, .color = { c[0], c[1], c[2], c[3] } }; - *(vertices++) = (GskGLDrawVertex) { .position = { glyph_x, glyph_y2 }, .uv = { tx, ty2 }, .color = { c[0], c[1], c[2], c[3] } }; - *(vertices++) = (GskGLDrawVertex) { .position = { glyph_x2, glyph_y }, .uv = { tx2, ty }, .color = { c[0], c[1], c[2], c[3] } }; - - batch->draw.vbo_count += GSK_GL_N_VERTICES; - used++; - } - - if (used != num_glyphs) - gsk_gl_command_queue_retract_n_vertices (job->command_queue, num_glyphs - used); - - gsk_gl_render_job_end_draw (job); - } -} - -static inline void -gsk_gl_render_job_visit_shadow_node (GskGLRenderJob *job, - const GskRenderNode *node) -{ - const gsize n_shadows = gsk_shadow_node_get_n_shadows (node); - const GskRenderNode *original_child = gsk_shadow_node_get_child (node); - const GskRenderNode *shadow_child = original_child; - - /* Shadow nodes recolor every pixel of the source texture, but leave the alpha in tact. - * If the child is a color matrix node that doesn't touch the alpha, we can throw that away. */ - if (GSK_RENDER_NODE_TYPE (shadow_child) == GSK_COLOR_MATRIX_NODE && - !color_matrix_modifies_alpha (shadow_child)) - shadow_child = gsk_color_matrix_node_get_child (shadow_child); - - for (guint i = 0; i < n_shadows; i++) - { - const GskShadow *shadow = gsk_shadow_node_get_shadow (node, i); - const float dx = shadow->dx; - const float dy = shadow->dy; - GskGLRenderOffscreen offscreen = {0}; - graphene_rect_t bounds; - guint16 color[4]; - - if (RGBA_IS_CLEAR (&shadow->color)) - continue; - - if (node_is_invisible (shadow_child)) - continue; - - if (shadow->radius == 0 && - GSK_RENDER_NODE_TYPE (shadow_child) == GSK_TEXT_NODE) - { - if (dx != 0 || dy != 0) - { - gsk_gl_render_job_offset (job, dx, dy); - gsk_gl_render_job_visit_text_node (job, shadow_child, &shadow->color, TRUE); - gsk_gl_render_job_offset (job, -dx, -dy); - } - continue; - } - - if (shadow->radius > 0) - { - float min_x; - float min_y; - float max_x; - float max_y; - - offscreen.do_not_cache = TRUE; - - blur_node (job, - &offscreen, - shadow_child, - shadow->radius, - &min_x, &max_x, - &min_y, &max_y); - - bounds.origin.x = min_x - job->offset_x; - bounds.origin.y = min_y - job->offset_y; - bounds.size.width = max_x - min_x; - bounds.size.height = max_y - min_y; - - offscreen.was_offscreen = TRUE; - } - else - { - offscreen.bounds = &shadow_child->bounds; - offscreen.reset_clip = TRUE; - offscreen.do_not_cache = TRUE; - - if (!gsk_gl_render_job_visit_node_with_offscreen (job, shadow_child, &offscreen)) - g_assert_not_reached (); - - bounds = shadow_child->bounds; - } - - gsk_gl_render_job_offset (job, dx, dy); - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, coloring))) - { - gsk_gl_program_set_uniform_texture (job->current_program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, - GL_TEXTURE0, - offscreen.texture_id); - job->source_is_glyph_atlas = FALSE; - rgba_to_half (&shadow->color, color); - gsk_gl_render_job_draw_offscreen_with_color (job, &bounds, &offscreen, color); - gsk_gl_render_job_end_draw (job); - } - gsk_gl_render_job_offset (job, -dx, -dy); - } - - /* Now draw the child normally */ - gsk_gl_render_job_visit_node (job, original_child); -} - -static inline void -gsk_gl_render_job_visit_blur_node (GskGLRenderJob *job, - const GskRenderNode *node) -{ - const GskRenderNode *child = gsk_blur_node_get_child (node); - float blur_radius = gsk_blur_node_get_radius (node); - GskGLRenderOffscreen offscreen = {0}; - GskTextureKey key; - gboolean cache_texture; - float min_x; - float max_x; - float min_y; - float max_y; - - g_assert (blur_radius > 0); - - if (node_is_invisible (child)) - return; - - key.pointer = node; - key.pointer_is_child = FALSE; - key.scale_x = job->scale_x; - key.scale_y = job->scale_y; - - offscreen.texture_id = gsk_gl_driver_lookup_texture (job->driver, &key, NULL); - cache_texture = offscreen.texture_id == 0; - - blur_node (job, - &offscreen, - child, - blur_radius, - &min_x, &max_x, &min_y, &max_y); - - g_assert (offscreen.texture_id != 0); - - if (cache_texture) - gsk_gl_driver_cache_texture (job->driver, &key, offscreen.texture_id); - - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit))) - { - gsk_gl_program_set_uniform_texture (job->current_program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, - GL_TEXTURE0, - offscreen.texture_id); - job->source_is_glyph_atlas = FALSE; - gsk_gl_render_job_draw_coords (job, - min_x, min_y, max_x, max_y, - 0, 1, 1, 0, - (guint16[]) { FP16_ZERO, FP16_ZERO, FP16_ZERO, FP16_ZERO } ); - gsk_gl_render_job_end_draw (job); - } -} - -static inline void -gsk_gl_render_job_visit_blend_node (GskGLRenderJob *job, - const GskRenderNode *node) -{ - const GskRenderNode *top_child = gsk_blend_node_get_top_child (node); - const GskRenderNode *bottom_child = gsk_blend_node_get_bottom_child (node); - GskGLRenderOffscreen top_offscreen = {0}; - GskGLRenderOffscreen bottom_offscreen = {0}; - - top_offscreen.bounds = &node->bounds; - top_offscreen.force_offscreen = TRUE; - top_offscreen.reset_clip = TRUE; - - bottom_offscreen.bounds = &node->bounds; - bottom_offscreen.force_offscreen = TRUE; - bottom_offscreen.reset_clip = TRUE; - - gsk_gl_render_job_set_modelview (job, gsk_transform_scale (NULL, fabsf (job->scale_x), fabsf (job->scale_y))); - - /* TODO: We create 2 textures here as big as the blend node, but both the - * start and the end node might be a lot smaller than that. */ - if (!gsk_gl_render_job_visit_node_with_offscreen (job, bottom_child, &bottom_offscreen)) - { - gsk_gl_render_job_pop_modelview (job); - - gsk_gl_render_job_visit_node (job, top_child); - return; - } - - g_assert (bottom_offscreen.was_offscreen); - - if (!gsk_gl_render_job_visit_node_with_offscreen (job, top_child, &top_offscreen)) - { - gsk_gl_render_job_pop_modelview (job); - - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit))) - { - gsk_gl_program_set_uniform_texture (job->current_program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, - GL_TEXTURE0, - bottom_offscreen.texture_id); - job->source_is_glyph_atlas = FALSE; - gsk_gl_render_job_draw_offscreen (job, &node->bounds, &bottom_offscreen); - gsk_gl_render_job_end_draw (job); - } - return; - } - - g_assert (top_offscreen.was_offscreen); - - gsk_gl_render_job_pop_modelview (job); - - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blend))) - { - gsk_gl_program_set_uniform_texture (job->current_program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, - GL_TEXTURE0, - bottom_offscreen.texture_id); - gsk_gl_program_set_uniform_texture (job->current_program, - UNIFORM_BLEND_SOURCE2, 0, - GL_TEXTURE_2D, - GL_TEXTURE1, - top_offscreen.texture_id); - job->source_is_glyph_atlas = FALSE; - gsk_gl_program_set_uniform1i (job->current_program, - UNIFORM_BLEND_MODE, 0, - gsk_blend_node_get_blend_mode (node)); - gsk_gl_render_job_draw_offscreen_rect (job, &node->bounds); - gsk_gl_render_job_end_draw (job); - } -} - -static gboolean -gsk_gl_render_job_texture_mask_for_color (GskGLRenderJob *job, - const GskRenderNode *mask, - const GskRenderNode *color, - const graphene_rect_t *bounds) -{ - int max_texture_size = job->command_queue->max_texture_size; - GdkTexture *texture = gsk_texture_node_get_texture (mask); - GdkRGBA rgba; - - get_color_node_color_as_srgb (color, &rgba); - if (RGBA_IS_CLEAR (&rgba)) - return TRUE; - - if G_LIKELY (texture->width <= max_texture_size && - texture->height <= max_texture_size && - gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, coloring))) - { - GskGLRenderOffscreen offscreen = {0}; - float scale_x = mask->bounds.size.width / texture->width; - float scale_y = mask->bounds.size.height / texture->height; - gboolean use_mipmap; - guint16 cc[4]; - - use_mipmap = (scale_x * fabsf (job->scale_x)) < 0.5 || - (scale_y * fabsf (job->scale_y)) < 0.5; - - rgba_to_half (&rgba, cc); - gsk_gl_render_job_upload_texture (job, texture, use_mipmap, &offscreen); - gsk_gl_program_set_uniform_texture_with_sync (job->current_program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, - GL_TEXTURE0, - offscreen.texture_id, - offscreen.has_mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR, - GL_LINEAR, - offscreen.sync); - job->source_is_glyph_atlas = FALSE; - gsk_gl_render_job_draw_offscreen_with_color (job, bounds, &offscreen, cc); - gsk_gl_render_job_end_draw (job); - - return TRUE; - } - - return FALSE; -} - -static inline void -gsk_gl_render_job_visit_mask_node (GskGLRenderJob *job, - const GskRenderNode *node) -{ - const GskRenderNode *source = gsk_mask_node_get_source (node); - const GskRenderNode *mask = gsk_mask_node_get_mask (node); - GskGLRenderOffscreen source_offscreen = {0}; - GskGLRenderOffscreen mask_offscreen = {0}; - - /* If the mask is a texture and the source is a color node - * then we can take a shortcut and avoid offscreens. - */ - if (GSK_RENDER_NODE_TYPE (mask) == GSK_TEXTURE_NODE && - GSK_RENDER_NODE_TYPE (source) == GSK_COLOR_NODE && - gsk_mask_node_get_mask_mode (node) == GSK_MASK_MODE_ALPHA) - { - if (gsk_gl_render_job_texture_mask_for_color (job, mask, source, &node->bounds)) - return; - } - - source_offscreen.bounds = &node->bounds; - source_offscreen.force_offscreen = TRUE; - source_offscreen.reset_clip = TRUE; - - mask_offscreen.bounds = &node->bounds; - mask_offscreen.force_offscreen = TRUE; - mask_offscreen.reset_clip = TRUE; - mask_offscreen.do_not_cache = TRUE; - - gsk_gl_render_job_set_modelview (job, gsk_transform_scale (NULL, fabsf (job->scale_x), fabsf (job->scale_y))); - - /* TODO: We create 2 textures here as big as the mask node, but both - * nodes might be a lot smaller than that. - */ - if (!gsk_gl_render_job_visit_node_with_offscreen (job, source, &source_offscreen)) - { - gsk_gl_render_job_pop_modelview (job); - gsk_gl_render_job_visit_node (job, source); - return; - } - - g_assert (source_offscreen.was_offscreen); - - if (!gsk_gl_render_job_visit_node_with_offscreen (job, mask, &mask_offscreen)) - { - gsk_gl_render_job_pop_modelview (job); - if (gsk_mask_node_get_mask_mode (node) == GSK_MASK_MODE_INVERTED_ALPHA) - gsk_gl_render_job_visit_node (job, source); - return; - } - - g_assert (mask_offscreen.was_offscreen); - - gsk_gl_render_job_pop_modelview (job); - - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, mask))) - { - gsk_gl_program_set_uniform_texture (job->current_program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, - GL_TEXTURE0, - source_offscreen.texture_id); - gsk_gl_program_set_uniform_texture (job->current_program, - UNIFORM_MASK_SOURCE, 0, - GL_TEXTURE_2D, - GL_TEXTURE1, - mask_offscreen.texture_id); - job->source_is_glyph_atlas = FALSE; - gsk_gl_program_set_uniform1i (job->current_program, - UNIFORM_MASK_MODE, 0, - gsk_mask_node_get_mask_mode (node)); - gsk_gl_render_job_draw_offscreen_rect (job, &node->bounds); - gsk_gl_render_job_end_draw (job); - } -} - -static inline void -gsk_gl_render_job_visit_color_matrix_node (GskGLRenderJob *job, - const GskRenderNode *node) -{ - const GskRenderNode *child = gsk_color_matrix_node_get_child (node); - GskGLRenderOffscreen offscreen = {0}; - float offset[4]; - - if (node_is_invisible (child)) - return; - - offscreen.bounds = &node->bounds; - offscreen.reset_clip = TRUE; - - if (!gsk_gl_render_job_visit_node_with_offscreen (job, child, &offscreen)) - g_assert_not_reached (); - - g_assert (offscreen.texture_id > 0); - - graphene_vec4_to_float (gsk_color_matrix_node_get_color_offset (node), offset); - - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, color_matrix))) - { - gsk_gl_program_set_uniform_texture (job->current_program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, - GL_TEXTURE0, - offscreen.texture_id); - job->source_is_glyph_atlas = FALSE; - gsk_gl_program_set_uniform_matrix (job->current_program, - UNIFORM_COLOR_MATRIX_COLOR_MATRIX, 0, - gsk_color_matrix_node_get_color_matrix (node)); - gsk_gl_program_set_uniform4fv (job->current_program, - UNIFORM_COLOR_MATRIX_COLOR_OFFSET, 0, - 1, - offset); - gsk_gl_render_job_draw_offscreen (job, &node->bounds, &offscreen); - gsk_gl_render_job_end_draw (job); - } -} - -static inline void -gsk_gl_render_job_visit_gl_shader_node_fallback (GskGLRenderJob *job, - const GskRenderNode *node) -{ - guint16 pink[4] = { 15360, 13975, 14758, 15360 }; /* 255 105 180 */ - - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, color))) - { - gsk_gl_render_job_draw_rect_with_color (job, &node->bounds, pink); - gsk_gl_render_job_end_draw (job); - } -} - -static inline void -gsk_gl_render_job_visit_gl_shader_node (GskGLRenderJob *job, - const GskRenderNode *node) -{ -G_GNUC_BEGIN_IGNORE_DEPRECATIONS - GError *error = NULL; - GskGLShader *shader; - GskGLProgram *program; - int n_children; - - shader = gsk_gl_shader_node_get_shader (node); - program = gsk_gl_driver_lookup_shader (job->driver, shader, &error); - n_children = gsk_gl_shader_node_get_n_children (node); - - if G_UNLIKELY (program == NULL) - { - if (g_object_get_data (G_OBJECT (shader), "gsk-did-warn") == NULL) - { - g_object_set_data (G_OBJECT (shader), "gsk-did-warn", GUINT_TO_POINTER (1)); - g_warning ("Failed to compile gl shader: %s", error->message); - } - gsk_gl_render_job_visit_gl_shader_node_fallback (job, node); - g_clear_error (&error); - } - else - { - GskGLRenderOffscreen offscreens[4] = {{0}}; - const GskGLUniform *uniforms; - const guint8 *base; - GBytes *args; - int n_uniforms; - - g_assert (n_children < G_N_ELEMENTS (offscreens)); - - for (guint i = 0; i < n_children; i++) - { - const GskRenderNode *child = gsk_gl_shader_node_get_child (node, i); - - offscreens[i].bounds = &node->bounds; - offscreens[i].force_offscreen = TRUE; - offscreens[i].reset_clip = TRUE; - - if (!gsk_gl_render_job_visit_node_with_offscreen (job, child, &offscreens[i])) - return; - } - - args = gsk_gl_shader_node_get_args (node); - base = g_bytes_get_data (args, NULL); - uniforms = gsk_gl_shader_get_uniforms (shader, &n_uniforms); - - if (gsk_gl_render_job_begin_draw (job, program)) - { - for (guint i = 0; i < n_children; i++) - gsk_gl_program_set_uniform_texture (program, - UNIFORM_CUSTOM_TEXTURE1 + i, 0, - GL_TEXTURE_2D, - GL_TEXTURE0 + i, - offscreens[i].texture_id); - job->source_is_glyph_atlas = FALSE; - gsk_gl_program_set_uniform2f (program, - UNIFORM_CUSTOM_SIZE, 0, - node->bounds.size.width, - node->bounds.size.height); - for (guint i = 0; i < n_uniforms; i++) - { - const GskGLUniform *u = &uniforms[i]; - const guint8 *data = base + u->offset; - - switch (u->type) - { - default: - case GSK_GL_UNIFORM_TYPE_NONE: - break; - case GSK_GL_UNIFORM_TYPE_FLOAT: - gsk_gl_uniform_state_set1fv (job->command_queue->uniforms, - program->program_info, - UNIFORM_CUSTOM_ARG0 + i, - 0, 1, (const float *)data); - break; - case GSK_GL_UNIFORM_TYPE_INT: - gsk_gl_uniform_state_set1i (job->command_queue->uniforms, - program->program_info, - UNIFORM_CUSTOM_ARG0 + i, - 0, *(const gint32 *)data); - break; - case GSK_GL_UNIFORM_TYPE_UINT: - case GSK_GL_UNIFORM_TYPE_BOOL: - gsk_gl_uniform_state_set1ui (job->command_queue->uniforms, - program->program_info, - UNIFORM_CUSTOM_ARG0 + i, - 0, *(const guint32 *)data); - break; - case GSK_GL_UNIFORM_TYPE_VEC2: - gsk_gl_uniform_state_set2fv (job->command_queue->uniforms, - program->program_info, - UNIFORM_CUSTOM_ARG0 + i, - 0, 1, (const float *)data); - break; - case GSK_GL_UNIFORM_TYPE_VEC3: - gsk_gl_uniform_state_set3fv (job->command_queue->uniforms, - program->program_info, - UNIFORM_CUSTOM_ARG0 + i, - 0, 1, (const float *)data); - break; - case GSK_GL_UNIFORM_TYPE_VEC4: - gsk_gl_uniform_state_set4fv (job->command_queue->uniforms, - program->program_info, - UNIFORM_CUSTOM_ARG0 + i, - 0, 1, (const float *)data); - break; - } - } - gsk_gl_render_job_draw_offscreen_rect (job, &node->bounds); - gsk_gl_render_job_end_draw (job); - } - } -G_GNUC_END_IGNORE_DEPRECATIONS -} - -static void -gsk_gl_render_job_upload_texture (GskGLRenderJob *job, - GdkTexture *texture, - gboolean ensure_mipmap, - GskGLRenderOffscreen *offscreen) -{ - /* Don't put GL or dmabuf textures into icon caches, they are already on the GPU side */ - if (!ensure_mipmap && - gsk_gl_texture_library_can_cache ((GskGLTextureLibrary *)job->driver->icons_library, - texture->width, - texture->height) && - !(GDK_IS_GL_TEXTURE (texture) || GDK_IS_DMABUF_TEXTURE (texture))) - { - const GskGLIconData *icon_data; - - gsk_gl_icon_library_lookup_or_add (job->driver->icons_library, texture, &icon_data); - offscreen->texture_id = GSK_GL_TEXTURE_ATLAS_ENTRY_TEXTURE (icon_data); - memcpy (&offscreen->area, &icon_data->entry.area, sizeof offscreen->area); - offscreen->has_mipmap = FALSE; - } - else - { - /* Only generate a mipmap if it does not make use reupload - * a GL texture which we could otherwise use directly. - */ - if (GDK_IS_GL_TEXTURE (texture) && - gdk_gl_context_is_shared (gdk_gl_texture_get_context (GDK_GL_TEXTURE (texture)), - job->command_queue->context)) - ensure_mipmap = gdk_gl_texture_has_mipmap (GDK_GL_TEXTURE (texture)); - else if (GDK_IS_DMABUF_TEXTURE (texture)) - ensure_mipmap = FALSE; - - offscreen->texture_id = gsk_gl_driver_load_texture (job->driver, texture, ensure_mipmap); - init_full_texture_region (offscreen); - offscreen->has_mipmap = ensure_mipmap; - - if (GDK_IS_GL_TEXTURE (texture) && - offscreen->texture_id == gdk_gl_texture_get_id (GDK_GL_TEXTURE (texture))) - offscreen->sync = gdk_gl_texture_get_sync (GDK_GL_TEXTURE (texture)); - } -} - -static inline void -gsk_gl_render_job_visit_texture (GskGLRenderJob *job, - GdkTexture *texture, - const graphene_rect_t *bounds) -{ - int max_texture_size = job->command_queue->max_texture_size; - float scale_x = bounds->size.width / texture->width; - float scale_y = bounds->size.height / texture->height; - gboolean use_mipmap; - - use_mipmap = (scale_x * fabsf (job->scale_x)) < 0.5 || - (scale_y * fabsf (job->scale_y)) < 0.5; - - if G_LIKELY (texture->width <= max_texture_size && - texture->height <= max_texture_size) - { - GskGLRenderOffscreen offscreen = {0}; - - gsk_gl_render_job_upload_texture (job, texture, use_mipmap, &offscreen); - - g_assert (offscreen.texture_id); - g_assert (offscreen.was_offscreen == FALSE); - - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit))) - { - gsk_gl_program_set_uniform_texture_with_sync (job->current_program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, - GL_TEXTURE0, - offscreen.texture_id, - offscreen.has_mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR, - GL_LINEAR, - offscreen.sync); - job->source_is_glyph_atlas = FALSE; - gsk_gl_render_job_draw_offscreen (job, bounds, &offscreen); - gsk_gl_render_job_end_draw (job); - } - } - else - { - float min_x = job->offset_x + bounds->origin.x; - float min_y = job->offset_y + bounds->origin.y; - GskGLTextureSlice *slices = NULL; - guint n_slices = 0; - - gsk_gl_driver_slice_texture (job->driver, texture, use_mipmap, &slices, &n_slices); - - g_assert (slices != NULL); - g_assert (n_slices > 0); - - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit))) - { - for (unsigned int i = 0; i < n_slices; i++) - { - const GskGLTextureSlice *slice = &slices[i]; - float x1, x2, y1, y2; - - x1 = min_x + (scale_x * slice->rect.x); - x2 = x1 + (slice->rect.width * scale_x); - y1 = min_y + (scale_y * slice->rect.y); - y2 = y1 + (slice->rect.height * scale_y); - - if (i > 0) - gsk_gl_render_job_split_draw (job); - gsk_gl_program_set_uniform_texture_with_filter (job->current_program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, - GL_TEXTURE0, - slice->texture_id, - use_mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR, - GL_LINEAR); - job->source_is_glyph_atlas = FALSE; - - gsk_gl_render_job_draw_coords (job, - x1, y1, x2, y2, - slice->area.x, slice->area.y, - slice->area.x2, slice->area.y2, - (guint16[]) { FP16_ZERO, FP16_ZERO, FP16_ZERO, FP16_ZERO }); - } - - gsk_gl_render_job_end_draw (job); - } - } -} - -static inline void -gsk_gl_render_job_visit_texture_node (GskGLRenderJob *job, - const GskRenderNode *node) -{ - GdkTexture *texture = gsk_texture_node_get_texture (node); - const graphene_rect_t *bounds = &node->bounds; - - gsk_gl_render_job_visit_texture (job, texture, bounds); -} - -static inline void -gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job, - const GskRenderNode *node) -{ - GdkTexture *texture = gsk_texture_scale_node_get_texture (node); - const graphene_rect_t *bounds = &node->bounds; - GskScalingFilter filter = gsk_texture_scale_node_get_filter (node); - int min_filters[] = { GL_LINEAR, GL_NEAREST, GL_LINEAR_MIPMAP_LINEAR }; - int mag_filters[] = { GL_LINEAR, GL_NEAREST, GL_LINEAR }; - int min_filter = min_filters[filter]; - int mag_filter = mag_filters[filter]; - int max_texture_size = job->command_queue->max_texture_size; - graphene_rect_t clip_rect; - GskGLRenderTarget *render_target; - graphene_rect_t viewport; - graphene_rect_t prev_viewport; - graphene_matrix_t prev_projection; - float prev_alpha; - guint prev_fbo; - float u0, u1, v0, v1; - GskTextureKey key; - guint texture_id; - gboolean need_mipmap; - gboolean has_mipmap; - - gsk_gl_render_job_untransform_bounds (job, &job->current_clip->rect.bounds, &clip_rect); - - if (!gsk_rect_intersection (bounds, &clip_rect, &clip_rect)) - return; - - key.pointer = node; - key.pointer_is_child = TRUE; - key.parent_rect = clip_rect; - key.scale_x = 1.; - key.scale_y = 1.; - - need_mipmap = (filter == GSK_SCALING_FILTER_TRILINEAR); - - texture_id = gsk_gl_driver_lookup_texture (job->driver, &key, &has_mipmap); - - if (texture_id != 0 && (!need_mipmap || has_mipmap)) - goto render_texture; - - viewport = GRAPHENE_RECT_INIT (0, 0, - clip_rect.size.width, - clip_rect.size.height); - - if (!gsk_gl_driver_create_render_target (job->driver, - (int) ceilf (clip_rect.size.width), - (int) ceilf (clip_rect.size.height), - get_target_format (job, node), - &render_target)) - { - gsk_gl_render_job_visit_texture (job, texture, bounds); - return; - } - - gsk_gl_render_job_set_viewport (job, &viewport, &prev_viewport); - gsk_gl_render_job_set_projection_from_rect (job, &viewport, &prev_projection); - gsk_gl_render_job_set_modelview (job, NULL); - prev_alpha = gsk_gl_render_job_set_alpha (job, 1.0f); - gsk_gl_render_job_push_clip (job, &GSK_ROUNDED_RECT_INIT_FROM_RECT (viewport)); - - prev_fbo = gsk_gl_command_queue_bind_framebuffer (job->command_queue, render_target->framebuffer_id); - gsk_gl_command_queue_clear (job->command_queue, 0, &viewport); - - if G_LIKELY (texture->width <= max_texture_size && - texture->height <= max_texture_size) - { - gpointer sync; - - texture_id = gsk_gl_driver_load_texture (job->driver, texture, need_mipmap); - - if (GDK_IS_GL_TEXTURE (texture) && texture_id == gdk_gl_texture_get_id (GDK_GL_TEXTURE (texture))) - sync = gdk_gl_texture_get_sync (GDK_GL_TEXTURE (texture)); - else - sync = NULL; - - u0 = (clip_rect.origin.x - bounds->origin.x) / bounds->size.width; - v0 = (clip_rect.origin.y - bounds->origin.y) / bounds->size.height; - u1 = (clip_rect.origin.x + clip_rect.size.width - bounds->origin.x) / bounds->size.width; - v1 = (clip_rect.origin.y + clip_rect.size.height - bounds->origin.y) / bounds->size.height; - - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit))) - { - gsk_gl_program_set_uniform_texture_with_sync (job->current_program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, - GL_TEXTURE0, - texture_id, - min_filter, - mag_filter, - sync); - job->source_is_glyph_atlas = FALSE; - gsk_gl_render_job_draw_coords (job, - 0, 0, clip_rect.size.width, clip_rect.size.height, - u0, v0, u1, v1, - (guint16[]) { FP16_ZERO, FP16_ZERO, FP16_ZERO, FP16_ZERO }); - gsk_gl_render_job_end_draw (job); - } - } - else - { - float scale_x = bounds->size.width / texture->width; - float scale_y = bounds->size.height / texture->height; - GskGLTextureSlice *slices = NULL; - guint n_slices = 0; - - gsk_gl_driver_slice_texture (job->driver, texture, need_mipmap, &slices, &n_slices); - - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit))) - { - for (guint i = 0; i < n_slices; i++) - { - const GskGLTextureSlice *slice = &slices[i]; - graphene_rect_t slice_bounds; - - slice_bounds.origin.x = bounds->origin.x - clip_rect.origin.x + slice->rect.x * scale_x; - slice_bounds.origin.y = bounds->origin.y - clip_rect.origin.y + slice->rect.y * scale_y; - slice_bounds.size.width = slice->rect.width * scale_x; - slice_bounds.size.height = slice->rect.height * scale_y; - - if (!gsk_rect_intersects (&slice_bounds, &viewport)) - continue; - - if (i > 0) - gsk_gl_render_job_split_draw (job); - - gsk_gl_program_set_uniform_texture_with_filter (job->current_program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, - GL_TEXTURE0, - slice->texture_id, - min_filter, - mag_filter); - job->source_is_glyph_atlas = FALSE; - gsk_gl_render_job_draw_coords (job, - slice_bounds.origin.x, - slice_bounds.origin.y, - slice_bounds.origin.x + slice_bounds.size.width, - slice_bounds.origin.y + slice_bounds.size.height, - slice->area.x, slice->area.y, - slice->area.x2, slice->area.y2, - (guint16[]){ FP16_ZERO, FP16_ZERO, FP16_ZERO, FP16_ZERO } ); - } - - gsk_gl_render_job_end_draw (job); - } - } - - gsk_gl_render_job_pop_clip (job); - gsk_gl_render_job_pop_modelview (job); - gsk_gl_render_job_set_viewport (job, &prev_viewport, NULL); - gsk_gl_render_job_set_projection (job, &prev_projection); - gsk_gl_render_job_set_alpha (job, prev_alpha); - gsk_gl_command_queue_bind_framebuffer (job->command_queue, prev_fbo); - - texture_id = gsk_gl_driver_release_render_target (job->driver, render_target, FALSE); - gsk_gl_driver_cache_texture (job->driver, &key, texture_id); - -render_texture: - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit))) - { - gsk_gl_program_set_uniform_texture (job->current_program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, - GL_TEXTURE0, - texture_id); - job->source_is_glyph_atlas = FALSE; - gsk_gl_render_job_draw_coords (job, - job->offset_x + clip_rect.origin.x, - job->offset_y + clip_rect.origin.y, - job->offset_x + clip_rect.origin.x + clip_rect.size.width, - job->offset_y + clip_rect.origin.y + clip_rect.size.height, - 0, clip_rect.size.width / ceilf (clip_rect.size.width), - clip_rect.size.height / ceilf (clip_rect.size.height), 0, - (guint16[]){ FP16_ZERO, FP16_ZERO, FP16_ZERO, FP16_ZERO } ); - gsk_gl_render_job_end_draw (job); - } -} - -static inline void -gsk_gl_render_job_visit_repeat_node (GskGLRenderJob *job, - const GskRenderNode *node) -{ - const GskRenderNode *child = gsk_repeat_node_get_child (node); - const graphene_rect_t *child_bounds = gsk_repeat_node_get_child_bounds (node); - GskGLRenderOffscreen offscreen = {0}; - - if (node_is_invisible (child)) - return; - - if (!gsk_rect_equal (child_bounds, &child->bounds)) - { - /* TODO: implement these repeat nodes. */ - gsk_gl_render_job_visit_as_fallback (job, node); - return; - } - - /* If the size of the repeat node is smaller than the size of the - * child node, we don't repeat at all and can just draw that part - * of the child texture... */ - if (gsk_rect_contains_rect (child_bounds, &node->bounds)) - { - gsk_gl_render_job_visit_clipped_child (job, child, &node->bounds); - return; - } - - offscreen.bounds = &child->bounds; - offscreen.reset_clip = TRUE; - - if (!gsk_gl_render_job_visit_node_with_offscreen (job, child, &offscreen)) - g_assert_not_reached (); - - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, repeat))) - { - gsk_gl_program_set_uniform_texture (job->current_program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, - GL_TEXTURE0, - offscreen.texture_id); - job->source_is_glyph_atlas = FALSE; - gsk_gl_program_set_uniform4f (job->current_program, - UNIFORM_REPEAT_CHILD_BOUNDS, 0, - (node->bounds.origin.x - child_bounds->origin.x) / child_bounds->size.width, - (node->bounds.origin.y - child_bounds->origin.y) / child_bounds->size.height, - node->bounds.size.width / child_bounds->size.width, - node->bounds.size.height / child_bounds->size.height); - gsk_gl_program_set_uniform4f (job->current_program, - UNIFORM_REPEAT_TEXTURE_RECT, 0, - offscreen.area.x, - offscreen.was_offscreen ? offscreen.area.y2 : offscreen.area.y, - offscreen.area.x2, - offscreen.was_offscreen ? offscreen.area.y : offscreen.area.y2); - gsk_gl_render_job_draw_offscreen (job, &node->bounds, &offscreen); - gsk_gl_render_job_end_draw (job); - } -} - -static inline void -gsk_gl_render_job_visit_subsurface_node (GskGLRenderJob *job, - const GskRenderNode *node) -{ - GdkSubsurface *subsurface; - - subsurface = (GdkSubsurface *) gsk_subsurface_node_get_subsurface (node); - - if (subsurface && - gdk_subsurface_get_texture (subsurface) && - gdk_subsurface_get_parent (subsurface) == gdk_gl_context_get_surface (job->command_queue->context)) - { - if (!gdk_subsurface_is_above_parent (subsurface)) - { - if (job->offscreen_count > 0) - { - GDK_DISPLAY_DEBUG (gdk_gl_context_get_display (job->command_queue->context), OFFLOAD, "Hiding subsurface %p in offscreen context", subsurface); - gdk_subsurface_detach (subsurface); - gsk_gl_render_job_visit_node (job, gsk_subsurface_node_get_child (node)); - } - else if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, color))) - { - /* Clear the area so we can see through */ - GskGLCommandBatch *batch; - guint16 color[4]; - rgba_to_half (&GDK_RGBA_TRANSPARENT, color); - - batch = gsk_gl_command_queue_get_batch (job->command_queue); - batch->draw.blend = 0; - gsk_gl_render_job_draw_rect_with_color (job, &node->bounds, color); - gsk_gl_render_job_end_draw (job); - } - } - } - else - { - gsk_gl_render_job_visit_node (job, gsk_subsurface_node_get_child (node)); - } -} - -static void -gsk_gl_render_job_visit_node (GskGLRenderJob *job, - const GskRenderNode *node) -{ - gboolean has_clip; - - g_assert (job != NULL); - g_assert (node != NULL); - g_assert (GSK_IS_GL_DRIVER (job->driver)); - g_assert (GSK_IS_GL_COMMAND_QUEUE (job->command_queue)); - - if (node_is_invisible (node)) - return; - - if (!gsk_gl_render_job_update_clip (job, &node->bounds, &has_clip)) - return; - - switch (GSK_RENDER_NODE_TYPE (node)) - { - case GSK_BLEND_NODE: - gsk_gl_render_job_visit_blend_node (job, node); - break; - - case GSK_BLUR_NODE: - if (gsk_blur_node_get_radius (node) > 0) - gsk_gl_render_job_visit_blur_node (job, node); - else - gsk_gl_render_job_visit_node (job, gsk_blur_node_get_child (node)); - break; - - case GSK_BORDER_NODE: - if (gsk_border_node_get_uniform_color (node) && - gsk_rounded_rect_is_rectilinear (gsk_border_node_get_outline (node))) - gsk_gl_render_job_visit_rect_border_node (job, node); - else - gsk_gl_render_job_visit_border_node (job, node); - break; - - case GSK_CLIP_NODE: - gsk_gl_render_job_visit_clip_node (job, node); - break; - - case GSK_COLOR_NODE: - gsk_gl_render_job_visit_color_node (job, node); - break; - - case GSK_COLOR_MATRIX_NODE: - gsk_gl_render_job_visit_color_matrix_node (job, node); - break; - - case GSK_CONIC_GRADIENT_NODE: - if (gsk_conic_gradient_node_get_n_color_stops (node) < MAX_GRADIENT_STOPS) - gsk_gl_render_job_visit_conic_gradient_node (job, node); - else - gsk_gl_render_job_visit_as_fallback (job, node); - break; - - case GSK_CONTAINER_NODE: - { - GskRenderNode **children; - guint n_children; - - children = gsk_container_node_get_children (node, &n_children); - - for (guint i = 0; i < n_children; i++) - { - const GskRenderNode *child = children[i]; - - if (i + 1 < n_children && - job->current_clip->is_fully_contained && - GSK_RENDER_NODE_TYPE (child) == GSK_ROUNDED_CLIP_NODE) - { - const GskRenderNode *grandchild = gsk_rounded_clip_node_get_child (child); - const GskRenderNode *child2 = children[i + 1]; - if (GSK_RENDER_NODE_TYPE (grandchild) == GSK_COLOR_NODE && - GSK_RENDER_NODE_TYPE (child2) == GSK_BORDER_NODE && - gsk_border_node_get_uniform_color (child2) && - rounded_rect_equal (gsk_rounded_clip_node_get_clip (child), - gsk_border_node_get_outline (child2))) - { - gsk_gl_render_job_visit_css_background (job, child, child2); - i++; /* skip the border node */ - continue; - } - } - - gsk_gl_render_job_visit_node (job, child); - } - } - break; - - case GSK_CROSS_FADE_NODE: - { - const GskRenderNode *start_node = gsk_cross_fade_node_get_start_child (node); - const GskRenderNode *end_node = gsk_cross_fade_node_get_end_child (node); - float progress = gsk_cross_fade_node_get_progress (node); - - if (progress <= 0.0f) - gsk_gl_render_job_visit_node (job, gsk_cross_fade_node_get_start_child (node)); - else if (progress >= 1.0f || equal_texture_nodes (start_node, end_node)) - gsk_gl_render_job_visit_node (job, gsk_cross_fade_node_get_end_child (node)); - else - gsk_gl_render_job_visit_cross_fade_node (job, node); - } - break; - - case GSK_DEBUG_NODE: - /* Debug nodes are ignored because draws get reordered anyway */ - gsk_gl_render_job_visit_node (job, gsk_debug_node_get_child (node)); - break; - - case GSK_GL_SHADER_NODE: - gsk_gl_render_job_visit_gl_shader_node (job, node); - break; - - case GSK_INSET_SHADOW_NODE: - if (gsk_inset_shadow_node_get_blur_radius (node) > 0) - gsk_gl_render_job_visit_blurred_inset_shadow_node (job, node); - else - gsk_gl_render_job_visit_unblurred_inset_shadow_node (job, node); - break; - - case GSK_LINEAR_GRADIENT_NODE: - case GSK_REPEATING_LINEAR_GRADIENT_NODE: - if (gsk_linear_gradient_node_get_n_color_stops (node) < MAX_GRADIENT_STOPS) - gsk_gl_render_job_visit_linear_gradient_node (job, node); - else - gsk_gl_render_job_visit_as_fallback (job, node); - break; - - case GSK_MASK_NODE: - gsk_gl_render_job_visit_mask_node (job, node); - break; - - case GSK_OPACITY_NODE: - gsk_gl_render_job_visit_opacity_node (job, node); - break; - - case GSK_OUTSET_SHADOW_NODE: - if (gsk_outset_shadow_node_get_blur_radius (node) > 0) - gsk_gl_render_job_visit_blurred_outset_shadow_node (job, node); - else - gsk_gl_render_job_visit_unblurred_outset_shadow_node (job, node); - break; - - case GSK_RADIAL_GRADIENT_NODE: - case GSK_REPEATING_RADIAL_GRADIENT_NODE: - if (gsk_radial_gradient_node_get_n_color_stops (node) < MAX_GRADIENT_STOPS) - gsk_gl_render_job_visit_radial_gradient_node (job, node); - else - gsk_gl_render_job_visit_as_fallback (job, node); - break; - - case GSK_REPEAT_NODE: - gsk_gl_render_job_visit_repeat_node (job, node); - break; - - case GSK_ROUNDED_CLIP_NODE: - gsk_gl_render_job_visit_rounded_clip_node (job, node); - break; - - case GSK_SHADOW_NODE: - gsk_gl_render_job_visit_shadow_node (job, node); - break; - - case GSK_TEXT_NODE: - { - GdkRGBA rgba; - - gdk_color_to_float (gsk_text_node_get_color2 (node), GDK_COLOR_STATE_SRGB, (float *) &rgba); - gsk_gl_render_job_visit_text_node (job, node, &rgba, FALSE); - } - break; - - case GSK_TEXTURE_NODE: - gsk_gl_render_job_visit_texture_node (job, node); - break; - - case GSK_TEXTURE_SCALE_NODE: - gsk_gl_render_job_visit_texture_scale_node (job, node); - break; - - case GSK_TRANSFORM_NODE: - gsk_gl_render_job_visit_transform_node (job, node); - break; - - case GSK_CAIRO_NODE: - gsk_gl_render_job_visit_as_fallback (job, node); - break; - - case GSK_FILL_NODE: - gsk_gl_render_job_visit_as_fallback (job, node); - break; - - case GSK_STROKE_NODE: - gsk_gl_render_job_visit_as_fallback (job, node); - break; - - case GSK_SUBSURFACE_NODE: - gsk_gl_render_job_visit_subsurface_node (job, node); - break; - - case GSK_NOT_A_RENDER_NODE: - default: - g_assert_not_reached (); - break; - } - - if (has_clip) - gsk_gl_render_job_pop_clip (job); -} - -static gboolean -gsk_gl_render_job_visit_node_with_offscreen (GskGLRenderJob *job, - const GskRenderNode *node, - GskGLRenderOffscreen *offscreen) -{ - GskTextureKey key; - guint cached_id; - - g_assert (job != NULL); - g_assert (node != NULL); - g_assert (offscreen != NULL); - g_assert (offscreen->texture_id == 0); - g_assert (offscreen->bounds != NULL); - - if (node_is_invisible (node)) - { - /* Just to be safe. */ - offscreen->texture_id = 0; - init_full_texture_region (offscreen); - offscreen->was_offscreen = FALSE; - return FALSE; - } - - if (GSK_RENDER_NODE_TYPE (node) == GSK_TEXTURE_NODE && - !offscreen->force_offscreen) - { - GdkTexture *texture = gsk_texture_node_get_texture (node); - gsk_gl_render_job_upload_texture (job, texture, FALSE, offscreen); - return TRUE; - } - - key.pointer = node; - key.pointer_is_child = TRUE; /* Don't conflict with the child using the cache too */ - key.parent_rect = *offscreen->bounds; - key.scale_x = job->scale_x; - key.scale_y = job->scale_y; - - float offset_x = job->offset_x; - float offset_y = job->offset_y; - gboolean flipped_x = job->scale_x < 0; - gboolean flipped_y = job->scale_y < 0; - graphene_rect_t viewport; - gboolean reset_clip = FALSE; - - if (flipped_x || flipped_y) - { - GskTransform *transform = gsk_transform_scale (NULL, - flipped_x ? -1 : 1, - flipped_y ? -1 : 1); - gsk_gl_render_job_push_modelview (job, transform); - gsk_transform_unref (transform); - } - - gsk_gl_render_job_transform_bounds (job, offscreen->bounds, &viewport); - - float aligned_x = floorf (viewport.origin.x); - float padding_left = viewport.origin.x - aligned_x; - float aligned_width = ceilf (viewport.size.width + padding_left); - float padding_right = aligned_width - viewport.size.width - padding_left; - - float aligned_y = floorf (viewport.origin.y); - float padding_top = viewport.origin.y - aligned_y; - float aligned_height = ceilf (viewport.size.height + padding_top); - float padding_bottom = aligned_height - viewport.size.height - padding_top; - - /* Tweak the scale factor so that the required texture doesn't - * exceed the max texture limit. This will render with a lower - * resolution, but this is better than clipping. - */ - - g_assert (job->command_queue->max_texture_size > 0); - - float downscale_x = 1; - float downscale_y = 1; - int texture_width; - int texture_height; - int max_texture_size = job->command_queue->max_texture_size; - - if (aligned_width > max_texture_size) - downscale_x = (float)max_texture_size / viewport.size.width; - - if (aligned_height > max_texture_size) - downscale_y = (float)max_texture_size / viewport.size.height; - - if (downscale_x != 1 || downscale_y != 1) - { - GskTransform *transform = gsk_transform_scale (NULL, downscale_x, downscale_y); - gsk_gl_render_job_push_modelview (job, transform); - gsk_transform_unref (transform); - gsk_gl_render_job_transform_bounds (job, offscreen->bounds, &viewport); - gsk_rect_scale (&viewport, downscale_x, downscale_y, &viewport); - } - - if (downscale_x == 1) - { - viewport.origin.x = aligned_x; - viewport.size.width = aligned_width; - offscreen->area.x = padding_left / aligned_width; - offscreen->area.x2 = 1.0f - (padding_right / aligned_width); - texture_width = aligned_width; - } - else - { - offscreen->area.x = 0; - offscreen->area.x2 = 1; - texture_width = max_texture_size; - } - - if (downscale_y == 1) - { - viewport.origin.y = aligned_y; - viewport.size.height = aligned_height; - offscreen->area.y = padding_bottom / aligned_height; - offscreen->area.y2 = 1.0f - padding_top / aligned_height; - texture_height = aligned_height; - } - else - { - offscreen->area.y = 0; - offscreen->area.y2 = 1; - texture_height = max_texture_size; - } - - /* Check if we've already cached the drawn texture. */ - cached_id = gsk_gl_driver_lookup_texture (job->driver, &key, NULL); - - if (cached_id != 0) - { - if (downscale_x != 1 || downscale_y != 1) - gsk_gl_render_job_pop_modelview (job); - if (flipped_x || flipped_y) - gsk_gl_render_job_pop_modelview (job); - offscreen->texture_id = cached_id; - /* We didn't render it offscreen, but hand out an offscreen texture id */ - offscreen->was_offscreen = TRUE; - return TRUE; - } - - GskGLRenderTarget *render_target; - graphene_matrix_t prev_projection; - graphene_rect_t prev_viewport; - float prev_alpha; - guint prev_fbo; - - if (!gsk_gl_driver_create_render_target (job->driver, - texture_width, texture_height, - get_target_format (job, node), - &render_target)) - g_assert_not_reached (); - - if (gdk_gl_context_has_feature (job->command_queue->context, GDK_GL_FEATURE_DEBUG)) - { - gdk_gl_context_label_object_printf (job->command_queue->context, - GL_TEXTURE, - render_target->texture_id, - "Offscreen<%s> %d", - g_type_name_from_instance ((GTypeInstance *) node), - render_target->texture_id); - gdk_gl_context_label_object_printf (job->command_queue->context, - GL_FRAMEBUFFER, - render_target->framebuffer_id, - "Offscreen<%s> FB %d", - g_type_name_from_instance ((GTypeInstance *) node), - render_target->framebuffer_id); - } - - gsk_gl_render_job_set_viewport (job, &viewport, &prev_viewport); - gsk_gl_render_job_set_projection_from_rect (job, &job->viewport, &prev_projection); - prev_alpha = gsk_gl_render_job_set_alpha (job, 1.0f); - - prev_fbo = gsk_gl_command_queue_bind_framebuffer (job->command_queue, render_target->framebuffer_id); - gsk_gl_command_queue_clear (job->command_queue, 0, &job->viewport); - - if (offscreen->reset_clip) - { - gsk_gl_render_job_push_clip (job, &GSK_ROUNDED_RECT_INIT_FROM_RECT (job->viewport)); - reset_clip = TRUE; - } - else if (flipped_x || flipped_y || downscale_x != 1 || downscale_y != 1) - { - GskRoundedRect new_clip; - float scale_x = flipped_x ? - downscale_x : downscale_x; - float scale_y = flipped_y ? - downscale_y : downscale_y; - - gsk_rect_scale (&job->current_clip->rect.bounds, scale_x, scale_y, &new_clip.bounds); - rounded_rect_scale_corners (&job->current_clip->rect, &new_clip, scale_x, scale_y); - gsk_gl_render_job_push_clip (job, &new_clip); - reset_clip = TRUE; - } - - job->offscreen_count++; - - gsk_gl_render_job_visit_node (job, node); - - job->offscreen_count--; - - if (reset_clip) - gsk_gl_render_job_pop_clip (job); - - if (downscale_x != 1 || downscale_y != 1) - gsk_gl_render_job_pop_modelview (job); - - if (flipped_x || flipped_y) - gsk_gl_render_job_pop_modelview (job); - - gsk_gl_render_job_set_viewport (job, &prev_viewport, NULL); - gsk_gl_render_job_set_projection (job, &prev_projection); - gsk_gl_render_job_set_alpha (job, prev_alpha); - gsk_gl_command_queue_bind_framebuffer (job->command_queue, prev_fbo); - - job->offset_x = offset_x; - job->offset_y = offset_y; - - offscreen->was_offscreen = TRUE; - offscreen->texture_id = gsk_gl_driver_release_render_target (job->driver, - render_target, - FALSE); - - if (!offscreen->do_not_cache) - gsk_gl_driver_cache_texture (job->driver, &key, offscreen->texture_id); - - return TRUE; -} - -void -gsk_gl_render_job_render_flipped (GskGLRenderJob *job, - GskRenderNode *root) -{ - graphene_matrix_t proj; - guint framebuffer_id; - guint texture_id; - guint surface_height; - - g_return_if_fail (job != NULL); - g_return_if_fail (root != NULL); - g_return_if_fail (GSK_IS_GL_DRIVER (job->driver)); - - surface_height = job->viewport.size.height; - - graphene_matrix_init_ortho (&proj, - job->viewport.origin.x, - job->viewport.origin.x + job->viewport.size.width, - job->viewport.origin.y, - job->viewport.origin.y + job->viewport.size.height, - ORTHO_NEAR_PLANE, - ORTHO_FAR_PLANE); - graphene_matrix_scale (&proj, 1, -1, 1); - - if (!gsk_gl_command_queue_create_render_target (job->command_queue, - MAX (1, job->viewport.size.width), - MAX (1, job->viewport.size.height), - job->target_format, - &framebuffer_id, &texture_id)) - return; - - /* Setup drawing to our offscreen texture/framebuffer which is flipped */ - gsk_gl_command_queue_bind_framebuffer (job->command_queue, framebuffer_id); - gsk_gl_command_queue_clear (job->command_queue, 0, &job->viewport); - - /* Visit all nodes creating batches */ - gdk_gl_context_push_debug_group (job->command_queue->context, "Building command queue"); - gsk_gl_render_job_visit_node (job, root); - gdk_gl_context_pop_debug_group (job->command_queue->context); - - /* Now draw to our real destination, but flipped */ - gsk_gl_render_job_set_alpha (job, 1.0f); - gsk_gl_command_queue_bind_framebuffer (job->command_queue, job->framebuffer); - gsk_gl_command_queue_clear (job->command_queue, 0, &job->viewport); - if (gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit))) - { - gsk_gl_program_set_uniform_texture (job->current_program, - UNIFORM_SHARED_SOURCE, 0, - GL_TEXTURE_2D, - GL_TEXTURE0, - texture_id); - job->source_is_glyph_atlas = FALSE; - gsk_gl_render_job_draw_rect (job, &job->viewport); - gsk_gl_render_job_end_draw (job); - } - - gdk_gl_context_push_debug_group (job->command_queue->context, "Executing command queue"); - gsk_gl_command_queue_execute (job->command_queue, surface_height, 1, NULL, job->default_framebuffer); - gdk_gl_context_pop_debug_group (job->command_queue->context); - - glDeleteFramebuffers (1, &framebuffer_id); - glDeleteTextures (1, &texture_id); -} - -void -gsk_gl_render_job_render (GskGLRenderJob *job, - GskRenderNode *root) -{ - G_GNUC_UNUSED gint64 start_time; - float scale; - guint surface_height; - - g_return_if_fail (job != NULL); - g_return_if_fail (root != NULL); - g_return_if_fail (GSK_IS_GL_DRIVER (job->driver)); - - scale = MAX (job->scale_x, job->scale_y); - surface_height = job->viewport.size.height; - - gsk_gl_command_queue_make_current (job->command_queue); - - /* Build the command queue using the shared GL context for all renderers - * on the same display. - */ - start_time = GDK_PROFILER_CURRENT_TIME; - gdk_gl_context_push_debug_group (job->command_queue->context, "Building command queue"); - gsk_gl_command_queue_bind_framebuffer (job->command_queue, job->framebuffer); - if (job->clear_framebuffer) - gsk_gl_command_queue_clear (job->command_queue, 0, &job->viewport); - gsk_gl_render_job_visit_node (job, root); - gdk_gl_context_pop_debug_group (job->command_queue->context); - - gdk_profiler_end_mark (start_time, "Build GL command queue", ""); - -#if 0 - /* At this point the atlases have uploaded content while we processed - * nodes but have not necessarily been used by the commands in the queue. - */ - gsk_gl_driver_save_atlases_to_png (job->driver, NULL); -#endif - - /* But now for executing the command queue, we want to use the context - * that was provided to us when creating the render job as framebuffer 0 - * is bound to that context. - */ - start_time = GDK_PROFILER_CURRENT_TIME; - gsk_gl_command_queue_make_current (job->command_queue); - gdk_gl_context_push_debug_group (job->command_queue->context, "Executing command queue"); - gsk_gl_command_queue_execute (job->command_queue, surface_height, scale, job->region, job->default_framebuffer); - gdk_gl_context_pop_debug_group (job->command_queue->context); - gdk_profiler_end_mark (start_time, "Execute GL command queue", ""); -} - -static int -get_framebuffer_format (GdkGLContext *context, - guint framebuffer) -{ - int size; - - if (!gdk_gl_context_check_version (context, NULL, "3.0")) - return GL_RGBA8; - - glBindFramebuffer (GL_FRAMEBUFFER, framebuffer); - glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER, - framebuffer ? GL_COLOR_ATTACHMENT0 - : gdk_gl_context_get_use_es (context) ? GL_BACK - : GL_BACK_LEFT, - GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE, &size); - - if (size > 16) - return GL_RGBA32F; - else if (size > 8) - return GL_RGBA16F; - else - return GL_RGBA8; -} - -GskGLRenderJob * -gsk_gl_render_job_new (GskGLDriver *driver, - const graphene_rect_t *viewport, - float scale, - const cairo_region_t *region, - guint framebuffer, - gboolean clear_framebuffer) -{ - const graphene_rect_t *clip_rect = viewport; - graphene_rect_t transformed_extents; - GskGLRenderJob *job; - GdkGLContext *context; - GLint default_framebuffer = 0; - - g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), NULL); - g_return_val_if_fail (viewport != NULL, NULL); - g_return_val_if_fail (scale > 0, NULL); - - /* Check for non-standard framebuffer binding as we might not be using - * the default framebuffer on systems like macOS where we've bound an - * IOSurface to a GL_TEXTURE_RECTANGLE. Otherwise, no scissor clip will - * be applied in the command queue causing overdrawing. - */ - context = driver->command_queue->context; - default_framebuffer = GDK_GL_CONTEXT_GET_CLASS (context)->get_default_framebuffer (context); - if (framebuffer == 0 && default_framebuffer != 0) - framebuffer = default_framebuffer; - - job = g_new0 (GskGLRenderJob, 1); - job->driver = g_object_ref (driver); - job->command_queue = job->driver->command_queue; - clips_init (&job->clip); - modelviews_init (&job->modelview); - job->framebuffer = framebuffer; - job->clear_framebuffer = !!clear_framebuffer; - job->default_framebuffer = default_framebuffer; - job->offset_x = 0; - job->offset_y = 0; - job->scale_x = scale; - job->scale_y = scale; - job->viewport = *viewport; - job->target_format = get_framebuffer_format (job->command_queue->context, framebuffer); - - gsk_gl_render_job_set_alpha (job, 1.0f); - gsk_gl_render_job_set_projection_from_rect (job, viewport, NULL); - gsk_gl_render_job_set_modelview (job, gsk_transform_scale (NULL, scale, scale)); - - /* Setup our initial clip. If region is NULL then we are drawing the - * whole viewport. Otherwise, we need to convert the region to a - * bounding box and clip based on that. - */ - - if (region != NULL) - { - cairo_rectangle_int_t extents; - - cairo_region_get_extents (region, &extents); - gsk_gl_render_job_transform_bounds (job, - &GRAPHENE_RECT_INIT (extents.x, - extents.y, - extents.width, - extents.height), - &transformed_extents); - clip_rect = &transformed_extents; - job->region = cairo_region_create_rectangle (&extents); - } - - gsk_gl_render_job_push_clip (job, - &GSK_ROUNDED_RECT_INIT (clip_rect->origin.x, - clip_rect->origin.y, - clip_rect->size.width, - clip_rect->size.height)); - - return job; -} - -void -gsk_gl_render_job_free (GskGLRenderJob *job) -{ - job->current_modelview = NULL; - job->current_clip = NULL; - - while (job->modelview.end > job->modelview.start) - { - GskGLRenderModelview *modelview = job->modelview.end-1; - g_clear_pointer (&modelview->transform, gsk_transform_unref); - job->modelview.end--; - } - - g_clear_object (&job->driver); - g_clear_pointer (&job->region, cairo_region_destroy); - modelviews_clear (&job->modelview); - clips_clear (&job->clip); - g_free (job); -} diff --git a/gsk/gl/gskglrenderjobprivate.h b/gsk/gl/gskglrenderjobprivate.h deleted file mode 100644 index 2e38b07a2e76b205ddff1a638458425527c62a75..0000000000000000000000000000000000000000 --- a/gsk/gl/gskglrenderjobprivate.h +++ /dev/null @@ -1,36 +0,0 @@ -/* gskglrenderjobprivate.h - * - * Copyright 2020 Christian Hergert - * - * 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 . - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#pragma once - -#include "gskgltypesprivate.h" - -GskGLRenderJob *gsk_gl_render_job_new (GskGLDriver *driver, - const graphene_rect_t *viewport, - float scale, - const cairo_region_t *region, - guint framebuffer, - gboolean clear_framebuffer); -void gsk_gl_render_job_free (GskGLRenderJob *job); -void gsk_gl_render_job_render (GskGLRenderJob *job, - GskRenderNode *root); -void gsk_gl_render_job_render_flipped (GskGLRenderJob *job, - GskRenderNode *root); - diff --git a/gsk/gl/gskglshadowlibrary.c b/gsk/gl/gskglshadowlibrary.c deleted file mode 100644 index d7c22c25880b10118ba0e26291f38fdd537a60d1..0000000000000000000000000000000000000000 --- a/gsk/gl/gskglshadowlibrary.c +++ /dev/null @@ -1,256 +0,0 @@ -/* gskglshadowlibrary.c - * - * Copyright 2020 Christian Hergert - * - * 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 . - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#include "config.h" - -#include - -#include "gskgldriverprivate.h" -#include "gskglshadowlibraryprivate.h" - -#define MAX_UNUSED_FRAMES (16 * 5) - -struct _GskGLShadowLibrary -{ - GObject parent_instance; - GskGLDriver *driver; - GArray *shadows; -}; - -typedef struct _Shadow -{ - GskRoundedRect outline; - float blur_radius; - guint texture_id; - gint64 last_used_in_frame; -} Shadow; - -G_DEFINE_TYPE (GskGLShadowLibrary, gsk_gl_shadow_library, G_TYPE_OBJECT) - -enum { - PROP_0, - PROP_DRIVER, - N_PROPS -}; - -static GParamSpec *properties [N_PROPS]; - -GskGLShadowLibrary * -gsk_gl_shadow_library_new (GskGLDriver *driver) -{ - g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), NULL); - - return g_object_new (GSK_TYPE_GL_SHADOW_LIBRARY, - "driver", driver, - NULL); -} - -static void -gsk_gl_shadow_library_dispose (GObject *object) -{ - GskGLShadowLibrary *self = (GskGLShadowLibrary *)object; - - for (guint i = 0; i < self->shadows->len; i++) - { - const Shadow *shadow = &g_array_index (self->shadows, Shadow, i); - gsk_gl_driver_release_texture_by_id (self->driver, shadow->texture_id); - } - - g_clear_pointer (&self->shadows, g_array_unref); - g_clear_object (&self->driver); - - G_OBJECT_CLASS (gsk_gl_shadow_library_parent_class)->dispose (object); -} - -static void -gsk_gl_shadow_library_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GskGLShadowLibrary *self = GSK_GL_SHADOW_LIBRARY (object); - - switch (prop_id) - { - case PROP_DRIVER: - g_value_set_object (value, self->driver); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -gsk_gl_shadow_library_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GskGLShadowLibrary *self = GSK_GL_SHADOW_LIBRARY (object); - - switch (prop_id) - { - case PROP_DRIVER: - self->driver = g_value_dup_object (value); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -gsk_gl_shadow_library_class_init (GskGLShadowLibraryClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->dispose = gsk_gl_shadow_library_dispose; - object_class->get_property = gsk_gl_shadow_library_get_property; - object_class->set_property = gsk_gl_shadow_library_set_property; - - properties [PROP_DRIVER] = - g_param_spec_object ("driver", NULL, NULL, - GSK_TYPE_GL_DRIVER, - (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_properties (object_class, N_PROPS, properties); -} - -static void -gsk_gl_shadow_library_init (GskGLShadowLibrary *self) -{ - self->shadows = g_array_new (FALSE, FALSE, sizeof (Shadow)); -} - -void -gsk_gl_shadow_library_insert (GskGLShadowLibrary *self, - const GskRoundedRect *outline, - float blur_radius, - guint texture_id) -{ - Shadow *shadow; - - g_assert (GSK_IS_GL_SHADOW_LIBRARY (self)); - g_assert (outline != NULL); - g_assert (texture_id != 0); - - gsk_gl_driver_mark_texture_permanent (self->driver, texture_id); - - g_array_set_size (self->shadows, self->shadows->len + 1); - - shadow = &g_array_index (self->shadows, Shadow, self->shadows->len - 1); - shadow->outline = *outline; - shadow->blur_radius = blur_radius; - shadow->texture_id = texture_id; - shadow->last_used_in_frame = self->driver->current_frame_id; -} - -guint -gsk_gl_shadow_library_lookup (GskGLShadowLibrary *self, - const GskRoundedRect *outline, - float blur_radius) -{ - Shadow *ret = NULL; - - g_assert (GSK_IS_GL_SHADOW_LIBRARY (self)); - g_assert (outline != NULL); - - /* Ensure GskRoundedRect is 12 packed floats without padding - * so that we can use memcmp instead of float comparisons. - */ - G_STATIC_ASSERT (sizeof *outline == (sizeof (float) * 12)); - - for (guint i = 0; i < self->shadows->len; i++) - { - Shadow *shadow = &g_array_index (self->shadows, Shadow, i); - - if (blur_radius == shadow->blur_radius && - memcmp (outline, &shadow->outline, sizeof *outline) == 0) - { - ret = shadow; - break; - } - } - - if (ret == NULL) - return 0; - - g_assert (ret->texture_id != 0); - - ret->last_used_in_frame = self->driver->current_frame_id; - - return ret->texture_id; -} - -#if 0 -static void -write_shadow_to_png (GskGLDriver *driver, - const Shadow *shadow) -{ - int width = shadow->outline.bounds.size.width + (shadow->outline.bounds.origin.x * 2); - int height = shadow->outline.bounds.size.height + (shadow->outline.bounds.origin.y * 2); - char *filename = g_strdup_printf ("shadow_cache_%d_%d_%d.png", - width, height, shadow->texture_id); - GdkTexture *texture; - - texture = gdk_gl_texture_new (gsk_gl_driver_get_context (driver), - shadow->texture_id, - width, height, - NULL, NULL); - gdk_texture_save_to_png (texture, filename); - - g_object_unref (texture); - g_free (filename); -} -#endif - -void -gsk_gl_shadow_library_begin_frame (GskGLShadowLibrary *self) -{ - gint64 watermark; - int i; - int p; - - g_return_if_fail (GSK_IS_GL_SHADOW_LIBRARY (self)); - -#if 0 - for (i = 0, p = self->shadows->len; i < p; i++) - { - const Shadow *shadow = &g_array_index (self->shadows, Shadow, i); - write_shadow_to_png (self->driver, shadow); - } -#endif - - watermark = self->driver->current_frame_id - MAX_UNUSED_FRAMES; - - for (i = 0, p = self->shadows->len; i < p; i++) - { - const Shadow *shadow = &g_array_index (self->shadows, Shadow, i); - - if (shadow->last_used_in_frame < watermark) - { - gsk_gl_driver_release_texture_by_id (self->driver, shadow->texture_id); - g_array_remove_index_fast (self->shadows, i); - p--; - i--; - } - } -} diff --git a/gsk/gl/gskglshadowlibraryprivate.h b/gsk/gl/gskglshadowlibraryprivate.h deleted file mode 100644 index 3c3c77c9e39e01c8ef329427e8019eb8331c3a65..0000000000000000000000000000000000000000 --- a/gsk/gl/gskglshadowlibraryprivate.h +++ /dev/null @@ -1,42 +0,0 @@ -/* gskglshadowlibraryprivate.h - * - * Copyright 2020 Christian Hergert - * - * 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 . - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#pragma once - -#include "gskgltexturelibraryprivate.h" - -G_BEGIN_DECLS - -#define GSK_TYPE_GL_SHADOW_LIBRARY (gsk_gl_shadow_library_get_type()) - -G_DECLARE_FINAL_TYPE (GskGLShadowLibrary, gsk_gl_shadow_library, GSK, GL_SHADOW_LIBRARY, GObject) - -GskGLShadowLibrary * gsk_gl_shadow_library_new (GskGLDriver *driver); -void gsk_gl_shadow_library_begin_frame (GskGLShadowLibrary *self); -guint gsk_gl_shadow_library_lookup (GskGLShadowLibrary *self, - const GskRoundedRect *outline, - float blur_radius); -void gsk_gl_shadow_library_insert (GskGLShadowLibrary *self, - const GskRoundedRect *outline, - float blur_radius, - guint texture_id); - -G_END_DECLS - diff --git a/gsk/gl/gskgltexture.c b/gsk/gl/gskgltexture.c deleted file mode 100644 index a578e80358501145ac2b576ec9b49f5364960c55..0000000000000000000000000000000000000000 --- a/gsk/gl/gskgltexture.c +++ /dev/null @@ -1,95 +0,0 @@ -/* gskgltexture.c - * - * Copyright 2020 Christian Hergert - * - * This file 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 file 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 General Public License along - * with this program. If not, see . - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#include "config.h" - -#include - -#include "gskgltextureprivate.h" -#include "ninesliceprivate.h" - -void -gsk_gl_texture_free (GskGLTexture *texture) -{ - if (texture != NULL) - { - g_assert (texture->link.prev == NULL); - g_assert (texture->link.next == NULL); - - if (texture->user) - g_clear_pointer (&texture->user, gdk_texture_clear_render_data); - - if (texture->texture_id != 0) - { - glDeleteTextures (1, &texture->texture_id); - texture->texture_id = 0; - } - - for (guint i = 0; i < texture->n_slices; i++) - { - glDeleteTextures (1, &texture->slices[i].texture_id); - texture->slices[i].texture_id = 0; - } - - g_clear_pointer (&texture->slices, g_free); - g_clear_pointer (&texture->nine_slice, g_free); - - g_free (texture); - } -} - -GskGLTexture * -gsk_gl_texture_new (guint texture_id, - int width, - int height, - gint64 frame_id) -{ - GskGLTexture *texture; - - texture = g_new0 (GskGLTexture, 1); - texture->texture_id = texture_id; - texture->link.data = texture; - texture->width = width; - texture->height = height; - texture->last_used_in_frame = frame_id; - - return texture; -} - -const GskGLTextureNineSlice * -gsk_gl_texture_get_nine_slice (GskGLTexture *texture, - const GskRoundedRect *outline, - float extra_pixels_x, - float extra_pixels_y) -{ - g_assert (texture != NULL); - g_assert (outline != NULL); - - if G_UNLIKELY (texture->nine_slice == NULL) - { - texture->nine_slice = g_new0 (GskGLTextureNineSlice, 9); - - nine_slice_rounded_rect (texture->nine_slice, outline); - nine_slice_grow (texture->nine_slice, extra_pixels_x, extra_pixels_y); - nine_slice_to_texture_coords (texture->nine_slice, texture->width, texture->height); - } - - return texture->nine_slice; -} diff --git a/gsk/gl/gskgltexturelibrary.c b/gsk/gl/gskgltexturelibrary.c deleted file mode 100644 index 772b3824776f4c0415c8586f0571a389ad4adace..0000000000000000000000000000000000000000 --- a/gsk/gl/gskgltexturelibrary.c +++ /dev/null @@ -1,583 +0,0 @@ -/* gskgltexturelibrary.c - * - * Copyright 2020 Christian Hergert - * - * 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 . - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#include "config.h" - -#include -#include - -#include "gskglcommandqueueprivate.h" -#include "gskgldriverprivate.h" -#include "gskgltexturelibraryprivate.h" - -#define DEFAULT_MAX_FRAME_AGE 60 -#define DEFAULT_ATLAS_WIDTH 512 -#define DEFAULT_ATLAS_HEIGHT 512 -#define MAX_OLD_RATIO 0.5 - -G_DEFINE_ABSTRACT_TYPE (GskGLTextureLibrary, gsk_gl_texture_library, G_TYPE_OBJECT) - -enum { - PROP_0, - PROP_DRIVER, - N_PROPS -}; - -static GParamSpec *properties [N_PROPS]; - -static void -gsk_gl_texture_atlas_free (GskGLTextureAtlas *atlas) -{ - if (atlas->texture_id != 0) - { - glDeleteTextures (1, &atlas->texture_id); - atlas->texture_id = 0; - } - - g_clear_pointer (&atlas->nodes, g_free); - g_free (atlas); -} - -static gboolean -gsk_gl_texture_library_real_compact (GskGLTextureLibrary *self, - gint64 frame_id) -{ - GPtrArray *removed = NULL; - gboolean ret = FALSE; - gboolean periodic_scan; - - g_assert (GSK_IS_GL_TEXTURE_LIBRARY (self)); - - periodic_scan = (self->max_frame_age > 0 && - (frame_id % self->max_frame_age) == 0); - - for (guint i = self->atlases->len; i > 0; i--) - { - GskGLTextureAtlas *atlas = g_ptr_array_index (self->atlases, i - 1); - - if (gsk_gl_texture_atlas_get_unused_ratio (atlas) > MAX_OLD_RATIO) - { - GSK_DEBUG (CACHE, - "Dropping atlas %d (%g.2%% old)", i, - 100.0 * gsk_gl_texture_atlas_get_unused_ratio (atlas)); - if (removed == NULL) - removed = g_ptr_array_new_with_free_func ((GDestroyNotify)gsk_gl_texture_atlas_free); - g_ptr_array_add (removed, g_ptr_array_steal_index (self->atlases, i - 1)); - } - } - - if (periodic_scan || removed != NULL) - { - GskGLTextureAtlasEntry *entry; - GHashTableIter iter; - guint dropped = 0; - G_GNUC_UNUSED guint atlased = 0; - - g_hash_table_iter_init (&iter, self->hash_table); - while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&entry)) - { - if (entry->is_atlased) - { - if (removed && g_ptr_array_find (removed, entry->atlas, NULL)) - { - g_hash_table_iter_remove (&iter); - dropped++; - } - else if (periodic_scan) - { - gsk_gl_texture_atlas_entry_mark_unused (entry); - entry->accessed = FALSE; - if (entry->is_atlased) - atlased++; - } - } - else - { - if (!entry->accessed) - { - if (entry->texture) - gsk_gl_driver_release_texture (self->driver, entry->texture); - g_hash_table_iter_remove (&iter); - dropped++; - } - else if (periodic_scan) - entry->accessed = FALSE; - } - } - - GSK_DEBUG (CACHE, "%s: Dropped %d individual items", - G_OBJECT_TYPE_NAME (self), - dropped); - GSK_DEBUG (CACHE, "%s: %d items cached (%d atlased, %d individually)", - G_OBJECT_TYPE_NAME (self), - g_hash_table_size (self->hash_table), - atlased, - g_hash_table_size (self->hash_table) - atlased); - - if (dropped > 0) - gsk_gl_texture_library_clear_cache (self); - - ret = TRUE; - - g_clear_pointer (&removed, g_ptr_array_unref); - } - - if (GSK_DEBUG_CHECK (CACHE)) - { - static gint64 last_message; - gint64 now = g_get_monotonic_time (); - if (now - last_message > G_USEC_PER_SEC) - { - last_message = now; - gdk_debug_message ("%s contains %d atlases", - G_OBJECT_TYPE_NAME (self), - self->atlases->len); - } - } - - return ret; -} - -static gboolean -gsk_gl_texture_library_real_allocate (GskGLTextureLibrary *self, - GskGLTextureAtlas *atlas, - int width, - int height, - int *out_x, - int *out_y) -{ - stbrp_rect rect; - - g_assert (GSK_IS_GL_TEXTURE_LIBRARY (self)); - g_assert (atlas != NULL); - g_assert (width > 0); - g_assert (height > 0); - g_assert (out_x != NULL); - g_assert (out_y != NULL); - - rect.w = width; - rect.h = height; - - stbrp_pack_rects (&atlas->context, &rect, 1); - - if (rect.was_packed) - { - *out_x = rect.x; - *out_y = rect.y; - } - - return rect.was_packed; -} - -static void -gsk_gl_texture_library_constructed (GObject *object) -{ - G_OBJECT_CLASS (gsk_gl_texture_library_parent_class)->constructed (object); - - g_assert (GSK_GL_TEXTURE_LIBRARY (object)->hash_table != NULL); -} - -static void -gsk_gl_texture_library_dispose (GObject *object) -{ - GskGLTextureLibrary *self = (GskGLTextureLibrary *)object; - - g_clear_pointer (&self->atlases, g_ptr_array_unref); - g_clear_object (&self->driver); - g_clear_pointer (&self->hash_table, g_hash_table_unref); - - G_OBJECT_CLASS (gsk_gl_texture_library_parent_class)->dispose (object); -} - -static void -gsk_gl_texture_library_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GskGLTextureLibrary *self = GSK_GL_TEXTURE_LIBRARY (object); - - switch (prop_id) - { - case PROP_DRIVER: - g_value_set_object (value, self->driver); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -gsk_gl_texture_library_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GskGLTextureLibrary *self = GSK_GL_TEXTURE_LIBRARY (object); - - switch (prop_id) - { - case PROP_DRIVER: - self->driver = g_value_dup_object (value); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -gsk_gl_texture_library_class_init (GskGLTextureLibraryClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->constructed = gsk_gl_texture_library_constructed; - object_class->dispose = gsk_gl_texture_library_dispose; - object_class->get_property = gsk_gl_texture_library_get_property; - object_class->set_property = gsk_gl_texture_library_set_property; - - klass->compact = gsk_gl_texture_library_real_compact; - klass->allocate = gsk_gl_texture_library_real_allocate; - - properties [PROP_DRIVER] = - g_param_spec_object ("driver", NULL, NULL, - GSK_TYPE_GL_DRIVER, - (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_properties (object_class, N_PROPS, properties); -} - -static void -gsk_gl_texture_library_init (GskGLTextureLibrary *self) -{ - self->max_frame_age = DEFAULT_MAX_FRAME_AGE; - self->atlas_width = DEFAULT_ATLAS_WIDTH; - self->atlas_height = DEFAULT_ATLAS_HEIGHT; - self->atlases = g_ptr_array_new_with_free_func ((GDestroyNotify)gsk_gl_texture_atlas_free); -} - -void -gsk_gl_texture_library_set_funcs (GskGLTextureLibrary *self, - GHashFunc hash_func, - GEqualFunc equal_func, - GDestroyNotify key_destroy, - GDestroyNotify value_destroy) -{ - g_return_if_fail (GSK_IS_GL_TEXTURE_LIBRARY (self)); - g_return_if_fail (self->hash_table == NULL); - - self->hash_table = g_hash_table_new_full (hash_func, equal_func, - key_destroy, value_destroy); -} - -void -gsk_gl_texture_library_begin_frame (GskGLTextureLibrary *self, - gint64 frame_id) -{ - g_return_if_fail (GSK_IS_GL_TEXTURE_LIBRARY (self)); - - gsk_gl_texture_library_compact (self, frame_id); - - if (GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->begin_frame) - GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->begin_frame (self, frame_id); -} - -static GskGLTexture * -gsk_gl_texture_library_pack_one (GskGLTextureLibrary *self, - guint width, - guint height) -{ - GskGLTexture *texture; - - g_assert (GSK_IS_GL_TEXTURE_LIBRARY (self)); - - if (width > self->driver->command_queue->max_texture_size || - height > self->driver->command_queue->max_texture_size) - { - g_warning ("Clipping requested texture of size %ux%u to maximum allowable size %u.", - width, height, self->driver->command_queue->max_texture_size); - width = MIN (width, self->driver->command_queue->max_texture_size); - height = MIN (height, self->driver->command_queue->max_texture_size); - } - - texture = gsk_gl_driver_create_texture (self->driver, width, height, GL_RGBA8); - texture->permanent = TRUE; - - return texture; -} - -static void -gsk_gl_texture_library_pack_any_atlas (GskGLTextureLibrary *self, - int width, - int height, - GskGLTextureAtlas **out_atlas, - int *out_x, - int *out_y) -{ - GskGLTextureAtlas *atlas = NULL; - int x, y; - - g_assert (GSK_IS_GL_TEXTURE_LIBRARY (self)); - g_assert (width > 0); - g_assert (height > 0); - g_assert (out_atlas != NULL); - g_assert (out_x != NULL); - g_assert (out_y != NULL); - - for (guint i = 0; i < self->atlases->len; i++) - { - atlas = g_ptr_array_index (self->atlases, i); - - if (gsk_gl_texture_library_allocate (self, atlas, width, height, &x, &y)) - break; - - atlas = NULL; - } - - if (atlas == NULL) - { - /* No atlas has enough space, so create a new one... */ - atlas = gsk_gl_texture_library_acquire_atlas (self); - - /* Pack it onto that one, which surely has enough space... */ - if (!gsk_gl_texture_library_allocate (self, atlas, width, height, &x, &y)) - g_assert_not_reached (); - } - - *out_atlas = atlas; - *out_x = x; - *out_y = y; -} - -gpointer -gsk_gl_texture_library_pack (GskGLTextureLibrary *self, - gpointer key, - gsize valuelen, - guint width, - guint height, - int padding, - guint *out_packed_x, - guint *out_packed_y) -{ - GskGLTextureAtlasEntry *entry; - GskGLTextureAtlas *atlas = NULL; - - g_assert (GSK_IS_GL_TEXTURE_LIBRARY (self)); - g_assert (key != NULL); - g_assert (valuelen > sizeof (GskGLTextureAtlasEntry)); - g_assert (out_packed_x != NULL); - g_assert (out_packed_y != NULL); - - entry = g_malloc0 (valuelen); - entry->n_pixels = width * height; - entry->accessed = TRUE; - entry->used = TRUE; - - /* If our size is invisible then we just want an entry in the - * cache for faster lookups, but do not actually spend any texture - * allocations on this entry. - */ - if (width <= 0 && height <= 0) - { - entry->is_atlased = FALSE; - entry->texture = NULL; - entry->area.x = 0.0f; - entry->area.y = 0.0f; - entry->area.x2 = 0.0f; - entry->area.y2 = 0.0f; - - *out_packed_x = 0; - *out_packed_y = 0; - } - else if (self->max_entry_size == 0 || - (width <= self->max_entry_size && - height <= self->max_entry_size)) - { - int packed_x; - int packed_y; - - gsk_gl_texture_library_pack_any_atlas (self, - padding + width + padding, - padding + height + padding, - &atlas, - &packed_x, - &packed_y); - - entry->atlas = atlas; - entry->is_atlased = TRUE; - entry->area.x = (packed_x + padding) / (float)atlas->width; - entry->area.y = (packed_y + padding) / (float)atlas->height; - entry->area.x2 = (packed_x + padding + width) / (float)atlas->width; - entry->area.y2 = (packed_y + padding + height) / (float)atlas->height; - - *out_packed_x = packed_x; - *out_packed_y = packed_y; - } - else - { - GskGLTexture *texture = gsk_gl_texture_library_pack_one (self, - padding + width + padding, - padding + height + padding); - - entry->texture = texture; - entry->is_atlased = FALSE; - entry->area.x = padding / (float) (padding + width + padding); - entry->area.y = padding / (float) (padding + height + padding); - entry->area.x2 = (padding + width) / (float) (padding + width + padding); - entry->area.y2 = (padding + height) / (float) (padding + height + padding); - - *out_packed_x = 0; - *out_packed_y = 0; - } - - g_hash_table_insert (self->hash_table, key, entry); - - return entry; -} - -/* - * gsk_gl_texture_library_clear_cache: - * - * Clear the front cache if the texture library is using one. For - * example the glyph cache would drop it's front cache to force - * next lookups to fall through to the GHashTable key lookup. - */ -void -gsk_gl_texture_library_clear_cache (GskGLTextureLibrary *self) -{ - g_return_if_fail (GSK_IS_GL_TEXTURE_LIBRARY (self)); - - if (GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->clear_cache) - GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->clear_cache (self); -} - -/* - * gsk_gl_texture_library_compact: - * - * Requests that the texture library compact it's altases. That - * generally means to traverse them to look for unused pixels over - * a certain threshold and release them if necessary. - * - * Returns: %TRUE if any compaction occurred. - */ -gboolean -gsk_gl_texture_library_compact (GskGLTextureLibrary *self, - gint64 frame_id) -{ - g_return_val_if_fail (GSK_IS_GL_TEXTURE_LIBRARY (self), FALSE); - - if (GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->compact) - return GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->compact (self, frame_id); - - return FALSE; -} - -void -gsk_gl_texture_library_reset (GskGLTextureLibrary *self) -{ - g_return_if_fail (GSK_IS_GL_TEXTURE_LIBRARY (self)); - - gsk_gl_texture_library_clear_cache (self); - - g_hash_table_remove_all (self->hash_table); - - if (self->atlases->len) - g_ptr_array_remove_range (self->atlases, 0, self->atlases->len); -} - -void -gsk_gl_texture_library_set_atlas_size (GskGLTextureLibrary *self, - int width, - int height) -{ - g_return_if_fail (GSK_IS_GL_TEXTURE_LIBRARY (self)); - - if (width <= 0) - width = DEFAULT_ATLAS_WIDTH; - - if (height <= 0) - height = DEFAULT_ATLAS_HEIGHT; - - self->atlas_height = height; - self->atlas_width = width; - - gsk_gl_texture_library_reset (self); -} - -/* - * gsk_gl_texture_library_acquire_atlas: - * - * Allocates a new texture atlas based on the current size - * and format requirements. - */ -GskGLTextureAtlas * -gsk_gl_texture_library_acquire_atlas (GskGLTextureLibrary *self) -{ - GskGLTextureAtlas *atlas; - - g_return_val_if_fail (GSK_IS_GL_TEXTURE_LIBRARY (self), NULL); - g_return_val_if_fail (GSK_IS_GL_DRIVER (self->driver), NULL); - g_return_val_if_fail (GSK_IS_GL_COMMAND_QUEUE (self->driver->command_queue), NULL); - g_return_val_if_fail (self->atlas_width > 0, NULL); - g_return_val_if_fail (self->atlas_height > 0, NULL); - - atlas = g_new0 (GskGLTextureAtlas, 1); - atlas->width = self->atlas_width; - atlas->height = self->atlas_height; - /* TODO: We might want to change the strategy about the amount of - * nodes here? stb_rect_pack.h says width is optimal. */ - atlas->nodes = g_malloc0_n (atlas->width, sizeof (struct stbrp_node)); - stbrp_init_target (&atlas->context, atlas->width, atlas->height, atlas->nodes, atlas->width); - atlas->texture_id = gsk_gl_command_queue_create_texture (self->driver->command_queue, - atlas->width, - atlas->height, - GL_RGBA8); - - gdk_gl_context_label_object_printf (gdk_gl_context_get_current (), - GL_TEXTURE, atlas->texture_id, - "Texture atlas %d", - atlas->texture_id); - - g_ptr_array_add (self->atlases, atlas); - - if (GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->init_atlas) - GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->init_atlas (self, atlas); - - return atlas; -} - -gboolean -gsk_gl_texture_library_allocate (GskGLTextureLibrary *self, - GskGLTextureAtlas *atlas, - int width, - int height, - int *out_x, - int *out_y) -{ - g_assert (GSK_IS_GL_TEXTURE_LIBRARY (self)); - g_assert (atlas != NULL); - g_assert (width > 0); - g_assert (height > 0); - g_assert (out_x != NULL); - g_assert (out_y != NULL); - - return GSK_GL_TEXTURE_LIBRARY_GET_CLASS (self)->allocate (self, atlas, width, height, out_x, out_y); -} diff --git a/gsk/gl/gskgltexturelibraryprivate.h b/gsk/gl/gskgltexturelibraryprivate.h deleted file mode 100644 index e2c3589fab4a2daf4c1a615d2b546fd928f43e7b..0000000000000000000000000000000000000000 --- a/gsk/gl/gskgltexturelibraryprivate.h +++ /dev/null @@ -1,232 +0,0 @@ -/* gskgltexturelibraryprivate.h - * - * Copyright 2020 Christian Hergert - * - * This file 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 file 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 General Public License along - * with this program. If not, see . - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#pragma once - -#include "gskgltypesprivate.h" -#include "gskgltextureprivate.h" - -#include "stb_rect_pack.h" - -G_BEGIN_DECLS - -#define GSK_TYPE_GL_TEXTURE_LIBRARY (gsk_gl_texture_library_get_type ()) -#define GSK_GL_TEXTURE_LIBRARY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_GL_TEXTURE_LIBRARY, GskGLTextureLibrary)) -#define GSK_IS_GL_TEXTURE_LIBRARY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_GL_TEXTURE_LIBRARY)) -#define GSK_GL_TEXTURE_LIBRARY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_GL_TEXTURE_LIBRARY, GskGLTextureLibraryClass)) -#define GSK_IS_GL_TEXTURE_LIBRARY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_GL_TEXTURE_LIBRARY)) -#define GSK_GL_TEXTURE_LIBRARY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_GL_TEXTURE_LIBRARY, GskGLTextureLibraryClass)) - -typedef struct _GskGLTextureAtlas -{ - struct stbrp_context context; - struct stbrp_node *nodes; - - int width; - int height; - - guint texture_id; - - /* Pixels of rects that have been used at some point, - * But are now unused. - */ - int unused_pixels; - -} GskGLTextureAtlas; - -typedef struct _GskGLTextureAtlasEntry -{ - /* A backreference to either the atlas or texture containing - * the contents of the atlas entry. For larger items, no atlas - * is used and instead a direct texture. - */ - union { - GskGLTextureAtlas *atlas; - GskGLTexture *texture; - }; - - /* The area within the atlas translated to 0..1 bounds */ - struct { - float x; - float y; - float x2; - float y2; - } area; - - /* Number of pixels in the entry, used to calculate usage - * of an atlas while processing. - */ - guint n_pixels : 29; - - /* If entry has marked pixels as used in the atlas this frame */ - guint used : 1; - - /* If entry was accessed this frame */ - guint accessed : 1; - - /* When true, backref is an atlas, otherwise texture */ - guint is_atlased : 1; -} GskGLTextureAtlasEntry; - -typedef struct _GskGLTextureLibrary -{ - GObject parent_instance; - GskGLDriver *driver; - GPtrArray *atlases; - GHashTable *hash_table; - guint max_entry_size; - guint max_frame_age; - guint atlas_width; - guint atlas_height; -} GskGLTextureLibrary; - -typedef struct _GskGLTextureLibraryClass -{ - GObjectClass parent_class; - - void (*begin_frame) (GskGLTextureLibrary *library, - gint64 frame_id); - gboolean (*compact) (GskGLTextureLibrary *library, - gint64 frame_id); - void (*clear_cache) (GskGLTextureLibrary *library); - void (*init_atlas) (GskGLTextureLibrary *library, - GskGLTextureAtlas *atlas); - gboolean (*allocate) (GskGLTextureLibrary *library, - GskGLTextureAtlas *atlas, - int width, - int height, - int *out_x, - int *out_y); -} GskGLTextureLibraryClass; - -G_DEFINE_AUTOPTR_CLEANUP_FUNC (GskGLTextureLibrary, g_object_unref) - -GType gsk_gl_texture_library_get_type (void) G_GNUC_CONST; -gboolean gsk_gl_texture_library_compact (GskGLTextureLibrary *self, - gint64 frame_id); -void gsk_gl_texture_library_clear_cache (GskGLTextureLibrary *self); -void gsk_gl_texture_library_reset (GskGLTextureLibrary *self); -void gsk_gl_texture_library_set_atlas_size (GskGLTextureLibrary *self, - int width, - int height); -GskGLTextureAtlas *gsk_gl_texture_library_acquire_atlas (GskGLTextureLibrary *self); -void gsk_gl_texture_library_set_funcs (GskGLTextureLibrary *self, - GHashFunc hash_func, - GEqualFunc equal_func, - GDestroyNotify key_destroy, - GDestroyNotify value_destroy); -void gsk_gl_texture_library_begin_frame (GskGLTextureLibrary *self, - gint64 frame_id); -gboolean gsk_gl_texture_library_allocate (GskGLTextureLibrary *self, - GskGLTextureAtlas *atlas, - int width, - int height, - int *out_x, - int *out_y); -gpointer gsk_gl_texture_library_pack (GskGLTextureLibrary *self, - gpointer key, - gsize valuelen, - guint width, - guint height, - int padding, - guint *out_packed_x, - guint *out_packed_y); - -static inline void -gsk_gl_texture_atlas_mark_unused (GskGLTextureAtlas *self, - int n_pixels) -{ - g_assert (n_pixels >= 0); - - self->unused_pixels += n_pixels; -} - -static inline void -gsk_gl_texture_atlas_entry_mark_used (GskGLTextureAtlasEntry *entry) -{ - if (entry->used == TRUE || entry->is_atlased == FALSE) - return; - - entry->atlas->unused_pixels -= entry->n_pixels; - entry->used = TRUE; -} - -static inline void -gsk_gl_texture_atlas_entry_mark_unused (GskGLTextureAtlasEntry *entry) -{ - if (entry->used == FALSE || entry->is_atlased == FALSE) - return; - - entry->atlas->unused_pixels += entry->n_pixels; - entry->used = FALSE; -} - -static inline gboolean -gsk_gl_texture_library_lookup (GskGLTextureLibrary *self, - gconstpointer key, - GskGLTextureAtlasEntry **out_entry) -{ - GskGLTextureAtlasEntry *entry = g_hash_table_lookup (self->hash_table, key); - - if G_LIKELY (entry != NULL && entry->accessed && entry->used) - { - *out_entry = entry; - return TRUE; - } - - if (entry != NULL) - { - gsk_gl_texture_atlas_entry_mark_used (entry); - entry->accessed = TRUE; - *out_entry = entry; - return TRUE; - } - - return FALSE; -} - -static inline guint -GSK_GL_TEXTURE_ATLAS_ENTRY_TEXTURE (gconstpointer d) -{ - const GskGLTextureAtlasEntry *e = d; - - return e->is_atlased ? e->atlas->texture_id - : e->texture ? e->texture->texture_id : 0; -} - -static inline double -gsk_gl_texture_atlas_get_unused_ratio (const GskGLTextureAtlas *self) -{ - if (self->unused_pixels > 0) - return (double)(self->unused_pixels) / (double)(self->width * self->height); - return 0.0; -} - -static inline gboolean -gsk_gl_texture_library_can_cache (GskGLTextureLibrary *self, - int width, - int height) -{ - g_assert (self->max_entry_size > 0); - return width <= self->max_entry_size && height <= self->max_entry_size; -} - -G_END_DECLS - diff --git a/gsk/gl/gskgltextureprivate.h b/gsk/gl/gskgltextureprivate.h deleted file mode 100644 index 620a9ed076530d17e446c2242555da347be66dea..0000000000000000000000000000000000000000 --- a/gsk/gl/gskgltextureprivate.h +++ /dev/null @@ -1,93 +0,0 @@ -/* gskgltextureprivate.h - * - * Copyright 2020 Christian Hergert - * - * This file 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 file 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 General Public License along - * with this program. If not, see . - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#pragma once - -#include "gskgltypesprivate.h" - -G_BEGIN_DECLS - -struct _GskGLTextureSlice -{ - cairo_rectangle_int_t rect; - struct { - float x; - float y; - float x2; - float y2; - } area; - guint texture_id; -}; - -struct _GskGLTextureNineSlice -{ - cairo_rectangle_int_t rect; - struct { - float x; - float y; - float x2; - float y2; - } area; -}; - -struct _GskGLTexture -{ - /* Used to insert into queue */ - GList link; - - /* Identifier of the frame that created it */ - gint64 last_used_in_frame; - - /* Backpointer to texture (can be cleared asynchronously) */ - GdkTexture *user; - - /* Only used by nine-slice textures */ - GskGLTextureNineSlice *nine_slice; - - /* Only used by sliced textures */ - GskGLTextureSlice *slices; - guint n_slices; - - /* The actual GL texture identifier in some shared context */ - guint texture_id; - - int width; - int height; - - /* Set when used by an atlas so we don't drop the texture */ - guint permanent : 1; - /* we are allowed to call glGenerateMipmap() for this texture */ - guint can_mipmap : 1; - /* we called glGenerateMipmap() for this texture */ - guint has_mipmap : 1; -}; - -GskGLTexture * gsk_gl_texture_new (guint texture_id, - int width, - int height, - gint64 frame_id); -const GskGLTextureNineSlice * gsk_gl_texture_get_nine_slice (GskGLTexture *texture, - const GskRoundedRect *outline, - float extra_pixels_x, - float extra_pixels_y); -void gsk_gl_texture_free (GskGLTexture *texture); - -G_END_DECLS - diff --git a/gsk/gl/gskgltypesprivate.h b/gsk/gl/gskgltypesprivate.h deleted file mode 100644 index 301a232bf13fce39dca368dd0633f5d519c966a2..0000000000000000000000000000000000000000 --- a/gsk/gl/gskgltypesprivate.h +++ /dev/null @@ -1,68 +0,0 @@ -/* gskgltypesprivate.h - * - * Copyright 2020 Christian Hergert - * - * 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 . - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#pragma once - -#include -#include -#ifdef GDK_WINDOWING_WIN32 -/* epoxy needs this, see https://github.com/anholt/libepoxy/issues/299 */ -#include -#endif -#include -#include - -G_BEGIN_DECLS - -#define GSK_GL_N_VERTICES 6 - -typedef struct _GskGLAttachmentState GskGLAttachmentState; -typedef struct _GskGLBuffer GskGLBuffer; -typedef struct _GskGLCommandQueue GskGLCommandQueue; -typedef struct _GskGLCompiler GskGLCompiler; -typedef struct _GskGLDrawVertex GskGLDrawVertex; -typedef struct _GskGLRenderTarget GskGLRenderTarget; -typedef struct _GskGLGlyphLibrary GskGLGlyphLibrary; -typedef struct _GskGLIconLibrary GskGLIconLibrary; -typedef struct _GskGLProgram GskGLProgram; -typedef struct _GskGLRenderJob GskGLRenderJob; -typedef struct _GskGLShadowLibrary GskGLShadowLibrary; -typedef struct _GskGLTexture GskGLTexture; -typedef struct _GskGLTextureSlice GskGLTextureSlice; -typedef struct _GskGLTextureAtlas GskGLTextureAtlas; -typedef struct _GskGLTextureLibrary GskGLTextureLibrary; -typedef struct _GskGLTextureNineSlice GskGLTextureNineSlice; -typedef struct _GskGLUniformInfo GskGLUniformInfo; -typedef struct _GskGLUniformProgram GskGLUniformProgram; -typedef struct _GskGLUniformState GskGLUniformState; -typedef struct _GskGLDriver GskGLDriver; - -struct _GskGLDrawVertex -{ - float position[2]; - union { - float uv[2]; - guint16 color2[4]; - }; - guint16 color[4]; -}; - -G_END_DECLS - diff --git a/gsk/gl/gskgluniformstate.c b/gsk/gl/gskgluniformstate.c deleted file mode 100644 index 77cd45a859515865a355b55f1ef6387740e61d9b..0000000000000000000000000000000000000000 --- a/gsk/gl/gskgluniformstate.c +++ /dev/null @@ -1,269 +0,0 @@ -/* gskgluniformstate.c - * - * Copyright 2020 Christian Hergert - * - * 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 . - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#include "config.h" - -#include -#include - -#include "gskgluniformstateprivate.h" - -static const guint8 uniform_sizes[] = { - 0, - - sizeof (Uniform1f), - sizeof (Uniform2f), - sizeof (Uniform3f), - sizeof (Uniform4f), - - sizeof (Uniform1f), - sizeof (Uniform2f), - sizeof (Uniform3f), - sizeof (Uniform4f), - - sizeof (Uniform1i), - sizeof (Uniform2i), - sizeof (Uniform3i), - sizeof (Uniform4i), - - sizeof (Uniform1ui), - - sizeof (guint), - - sizeof (graphene_matrix_t), - sizeof (GskRoundedRect), - sizeof (GdkRGBA), - - 0, -}; - -GskGLUniformState * -gsk_gl_uniform_state_new (void) -{ - GskGLUniformState *state; - - state = g_atomic_rc_box_new0 (GskGLUniformState); - state->programs = g_hash_table_new_full (NULL, NULL, NULL, g_free); - state->values_len = 4096; - state->values_pos = 0; - state->values_buf = g_malloc (4096); - - memset (state->apply_hash, 0, sizeof state->apply_hash); - - return g_steal_pointer (&state); -} - -GskGLUniformState * -gsk_gl_uniform_state_ref (GskGLUniformState *state) -{ - return g_atomic_rc_box_acquire (state); -} - -static void -gsk_gl_uniform_state_finalize (gpointer data) -{ - GskGLUniformState *state = data; - - g_clear_pointer (&state->programs, g_hash_table_unref); - g_clear_pointer (&state->values_buf, g_free); -} - -void -gsk_gl_uniform_state_unref (GskGLUniformState *state) -{ - g_atomic_rc_box_release_full (state, gsk_gl_uniform_state_finalize); -} - -gpointer -gsk_gl_uniform_state_init_value (GskGLUniformState *state, - GskGLUniformProgram *program, - GskGLUniformFormat format, - guint array_count, - guint key, - GskGLUniformMapping **infoptr) -{ - GskGLUniformMapping *mapping; - guint offset; - - g_assert (state != NULL); - g_assert (array_count < 32); - g_assert ((int)format >= 0 && format < GSK_GL_UNIFORM_FORMAT_LAST); - g_assert (format > 0); - g_assert (program != NULL); - g_assert (key < program->n_mappings); - - mapping = &program->mappings[key]; - - if (mapping->location == -1) - { - *infoptr = NULL; - return NULL; - } - - if G_LIKELY (format == mapping->info.format) - { - if G_LIKELY (array_count <= mapping->info.array_count) - { - *infoptr = mapping; - return GSK_GL_UNIFORM_VALUE (state->values_buf, mapping->info.offset); - } - - /* We found the uniform, but there is not enough space for the - * amount that was requested. Instead, allocate new space and - * set the value to "initial" so that the caller just writes - * over the previous value. - * - * This can happen when using dynamic array lengths like the - * "n_color_stops" in gradient shaders. - */ - goto setup_info; - } - else if (mapping->info.format == 0) - { - goto setup_info; - } - else - { - g_critical ("Attempt to access uniform with different type of value " - "than it was initialized with. Program %u Location %u. " - "Was %d now %d (array length %d now %d).", - program->program_id, key, mapping->info.format, format, - mapping->info.array_count, array_count); - *infoptr = NULL; - return NULL; - } - -setup_info: - - gsk_gl_uniform_state_realloc (state, - uniform_sizes[format] * MAX (1, array_count), - &offset); - - /* we have 21 bits for offset */ - g_assert (offset < (1 << GSK_GL_UNIFORM_OFFSET_BITS)); - - mapping->info.format = format; - mapping->info.offset = offset; - mapping->info.array_count = array_count; - mapping->info.initial = TRUE; - mapping->stamp = 0; - - *infoptr = mapping; - - return GSK_GL_UNIFORM_VALUE (state->values_buf, mapping->info.offset); -} - -void -gsk_gl_uniform_state_end_frame (GskGLUniformState *state) -{ - GHashTableIter iter; - GskGLUniformProgram *program; - guint allocator = 0; - - g_return_if_fail (state != NULL); - - /* After a frame finishes, we want to remove all our copies of uniform - * data that isn't needed any longer. Since we treat it as uninitialized - * after this frame (to reset it on first use next frame) we can just - * discard it but keep an allocation around to reuse. - */ - - g_hash_table_iter_init (&iter, state->programs); - while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&program)) - { - for (guint j = 0; j < program->n_mappings; j++) - { - GskGLUniformMapping *mapping = &program->mappings[j]; - guint size; - - /* Skip unused uniform mappings */ - if (mapping->info.format == 0 || mapping->location == -1) - continue; - - /* Calculate how much size is needed for the uniform, including arrays */ - size = uniform_sizes[mapping->info.format] * MAX (1, mapping->info.array_count); - - /* Adjust alignment for value */ - allocator += gsk_gl_uniform_state_align (allocator, size); - - /* Offset is in slots of 4 bytes */ - mapping->info.offset = allocator / 4; - mapping->info.initial = TRUE; - mapping->stamp = 0; - - /* Now advance for this items data */ - allocator += size; - } - } - - state->values_pos = allocator; - - /* It can happen that our space requirements grow due to - * difference in order increasing padding. As a pragmatic - * solution to this, just increase the allocation to cover - * the predefined mappins. - */ - if (allocator > state->values_len) - { - while (allocator > state->values_len) - state->values_len *= 2; - state->values_buf = g_realloc (state->values_buf, state->values_len); - } - - memset (state->apply_hash, 0, sizeof state->apply_hash); -} - -gsize -gsk_gl_uniform_format_size (GskGLUniformFormat format) -{ - g_assert (format > 0); - g_assert (format < GSK_GL_UNIFORM_FORMAT_LAST); - - return uniform_sizes[format]; -} - -GskGLUniformProgram * -gsk_gl_uniform_state_get_program (GskGLUniformState *state, - guint program, - const GskGLUniformMapping *mappings, - guint n_mappings) -{ - GskGLUniformProgram *ret; - - g_return_val_if_fail (state != NULL, NULL); - g_return_val_if_fail (program > 0, NULL); - g_return_val_if_fail (program < G_MAXUINT, NULL); - g_return_val_if_fail (n_mappings <= G_N_ELEMENTS (ret->mappings), NULL); - - ret = g_hash_table_lookup (state->programs, GUINT_TO_POINTER (program)); - - if (ret == NULL) - { - ret = g_new0 (GskGLUniformProgram, 1); - ret->program_id = program; - ret->n_mappings = n_mappings; - - memcpy (ret->mappings, mappings, n_mappings * sizeof *mappings); - - g_hash_table_insert (state->programs, GUINT_TO_POINTER (program), ret); - } - - return ret; -} diff --git a/gsk/gl/gskgluniformstateprivate.h b/gsk/gl/gskgluniformstateprivate.h deleted file mode 100644 index 3704be957ca8e90cc1a156518498749b90a969eb..0000000000000000000000000000000000000000 --- a/gsk/gl/gskgluniformstateprivate.h +++ /dev/null @@ -1,834 +0,0 @@ -/* gskgluniformstateprivate.h - * - * Copyright 2020 Christian Hergert - * - * 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 . - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#pragma once - -#include "gskgltypesprivate.h" - -G_BEGIN_DECLS - -typedef struct { float v0; } Uniform1f; -typedef struct { float v0; float v1; } Uniform2f; -typedef struct { float v0; float v1; float v2; } Uniform3f; -typedef struct { float v0; float v1; float v2; float v3; } Uniform4f; - -typedef struct { int v0; } Uniform1i; -typedef struct { int v0; int v1; } Uniform2i; -typedef struct { int v0; int v1; int v2; } Uniform3i; -typedef struct { int v0; int v1; int v2; int v3; } Uniform4i; - -typedef struct { guint v0; } Uniform1ui; - -#define GSK_GL_UNIFORM_ARRAY_BITS 5 -#define GSK_GL_UNIFORM_FORMAT_BITS 5 -#define GSK_GL_UNIFORM_OFFSET_BITS 21 - -typedef struct _GskGLUniformInfo -{ - guint initial : 1; - guint format : GSK_GL_UNIFORM_FORMAT_BITS; - guint array_count : GSK_GL_UNIFORM_ARRAY_BITS; - guint offset : GSK_GL_UNIFORM_OFFSET_BITS; -} GskGLUniformInfo; - -G_STATIC_ASSERT (sizeof (GskGLUniformInfo) == 4); - -typedef struct _GskGLUniformMapping -{ - const char *name; - GskGLUniformInfo info; - guint stamp; - int location; -} GskGLUniformMapping; - -typedef struct _GskGLUniformProgram -{ - guint program_id; - guint n_uniforms : 12; - guint has_attachments : 1; - guint n_mappings; - GskGLUniformMapping mappings[32]; -} GskGLUniformProgram; - -typedef struct _GskGLUniformState -{ - GHashTable *programs; - guint8 *values_buf; - guint values_pos; - guint values_len; - GskGLUniformInfo apply_hash[512]; -} GskGLUniformState; - -typedef enum _GskGLUniformKind -{ - GSK_GL_UNIFORM_FORMAT_1F = 1, - GSK_GL_UNIFORM_FORMAT_2F, - GSK_GL_UNIFORM_FORMAT_3F, - GSK_GL_UNIFORM_FORMAT_4F, - - GSK_GL_UNIFORM_FORMAT_1FV, - GSK_GL_UNIFORM_FORMAT_2FV, - GSK_GL_UNIFORM_FORMAT_3FV, - GSK_GL_UNIFORM_FORMAT_4FV, - - GSK_GL_UNIFORM_FORMAT_1I, - GSK_GL_UNIFORM_FORMAT_2I, - GSK_GL_UNIFORM_FORMAT_3I, - GSK_GL_UNIFORM_FORMAT_4I, - - GSK_GL_UNIFORM_FORMAT_1UI, - - GSK_GL_UNIFORM_FORMAT_TEXTURE, - - GSK_GL_UNIFORM_FORMAT_MATRIX, - GSK_GL_UNIFORM_FORMAT_ROUNDED_RECT, - GSK_GL_UNIFORM_FORMAT_COLOR, - - GSK_GL_UNIFORM_FORMAT_LAST -} GskGLUniformFormat; - -G_STATIC_ASSERT (GSK_GL_UNIFORM_FORMAT_LAST < (1 << GSK_GL_UNIFORM_FORMAT_BITS)); - -GskGLUniformState *gsk_gl_uniform_state_new (void); -GskGLUniformState *gsk_gl_uniform_state_ref (GskGLUniformState *state); -void gsk_gl_uniform_state_unref (GskGLUniformState *state); -GskGLUniformProgram *gsk_gl_uniform_state_get_program (GskGLUniformState *state, - guint program, - const GskGLUniformMapping *mappings, - guint n_mappings); -void gsk_gl_uniform_state_end_frame (GskGLUniformState *state); -gsize gsk_gl_uniform_format_size (GskGLUniformFormat format); -gpointer gsk_gl_uniform_state_init_value (GskGLUniformState *state, - GskGLUniformProgram *program, - GskGLUniformFormat format, - guint array_count, - guint key, - GskGLUniformMapping **out_mapping); - -#define GSK_GL_UNIFORM_VALUE(base, offset) ((gpointer)((base) + ((offset) * 4))) -#define gsk_gl_uniform_state_get_uniform_data(state,offset) GSK_GL_UNIFORM_VALUE((state)->values_buf, offset) - -static inline gpointer -gsk_gl_uniform_state_get_value (GskGLUniformState *state, - GskGLUniformProgram *program, - GskGLUniformFormat format, - guint array_count, - guint key, - guint stamp, - GskGLUniformMapping **out_mapping) -{ - GskGLUniformMapping *mapping; - - g_assert (key < G_N_ELEMENTS (program->mappings)); - g_assert (key < program->n_mappings); - - mapping = &program->mappings[key]; - - /* Short-circuit if the program optimized the uniform out */ - if (mapping->location == -1) - return NULL; - - /* If the stamp is the same, then we can ignore the request - * and short-circuit as early as possible. This requires the - * caller to increment their private stamp when they change - * internal state. - * - * This is generally used for the shared uniforms like projection, - * modelview, clip, etc to avoid so many comparisons which cost - * considerable CPU. - */ - if (stamp != 0 && stamp == mapping->stamp) - return NULL; - - if G_LIKELY (format == mapping->info.format && array_count <= mapping->info.array_count) - { - *out_mapping = mapping; - return GSK_GL_UNIFORM_VALUE (state->values_buf, mapping->info.offset); - } - - return gsk_gl_uniform_state_init_value (state, program, format, array_count, key, out_mapping); -} - -G_GNUC_PURE static inline guint -gsk_gl_uniform_state_align (guint current_pos, - guint size) -{ - guint align = size > 8 ? 16 : (size > 4 ? 8 : 4); - guint masked = current_pos & (align - 1); - - g_assert (size > 0); - g_assert (align == 4 || align == 8 || align == 16); - g_assert (masked < align); - - return align - masked; -} - -static inline gpointer -gsk_gl_uniform_state_realloc (GskGLUniformState *state, - guint size, - guint *offset) -{ - guint padding = gsk_gl_uniform_state_align (state->values_pos, size); - - if G_UNLIKELY (state->values_len - padding - size < state->values_pos) - { - state->values_len *= 2; - state->values_buf = g_realloc (state->values_buf, state->values_len); - } - - /* offsets are in slots of 4 to use fewer bits */ - g_assert ((state->values_pos + padding) % 4 == 0); - *offset = (state->values_pos + padding) / 4; - state->values_pos += padding + size; - - return GSK_GL_UNIFORM_VALUE (state->values_buf, *offset); -} - -#define GSK_GL_UNIFORM_STATE_REPLACE(info, u, type, count) \ - G_STMT_START { \ - if ((info)->info.initial && count == (info)->info.array_count) \ - { \ - u = GSK_GL_UNIFORM_VALUE (state->values_buf, (info)->info.offset); \ - } \ - else \ - { \ - guint offset; \ - u = gsk_gl_uniform_state_realloc (state, sizeof(type) * MAX (1, count), &offset); \ - g_assert (offset < (1 << GSK_GL_UNIFORM_OFFSET_BITS)); \ - (info)->info.offset = offset; \ - /* We might have increased array length */ \ - (info)->info.array_count = count; \ - } \ - } G_STMT_END - -static inline void -gsk_gl_uniform_info_changed (GskGLUniformMapping *info, - guint stamp) -{ - info->stamp = stamp; - info->info.initial = FALSE; -} - -static inline void -gsk_gl_uniform_state_set1f (GskGLUniformState *state, - GskGLUniformProgram *program, - guint key, - guint stamp, - float value0) -{ - Uniform1f *u; - GskGLUniformMapping *info; - - g_assert (state != NULL); - g_assert (program != 0); - - if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_1F, 1, key, stamp, &info))) - { - if (info->info.initial || u->v0 != value0) - { - GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform1f , 1); - u->v0 = value0; - gsk_gl_uniform_info_changed (info, stamp); - } - } -} - -static inline void -gsk_gl_uniform_state_set2f (GskGLUniformState *state, - GskGLUniformProgram *program, - guint key, - guint stamp, - float value0, - float value1) -{ - Uniform2f *u; - GskGLUniformMapping *info; - - g_assert (state != NULL); - g_assert (program != NULL); - - if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_2F, 1, key, stamp, &info))) - { - if (info->info.initial || u->v0 != value0 || u->v1 != value1) - { - GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform2f, 1); - u->v0 = value0; - u->v1 = value1; - gsk_gl_uniform_info_changed (info, stamp); - } - } -} - -static inline void -gsk_gl_uniform_state_set3f (GskGLUniformState *state, - GskGLUniformProgram *program, - guint key, - guint stamp, - float value0, - float value1, - float value2) -{ - Uniform3f *u; - GskGLUniformMapping *info; - - g_assert (state != NULL); - g_assert (program != NULL); - - if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_3F, 1, key, stamp, &info))) - { - if (info->info.initial || u->v0 != value0 || u->v1 != value1 || u->v2 != value2) - { - GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform3f, 1); - u->v0 = value0; - u->v1 = value1; - u->v2 = value2; - gsk_gl_uniform_info_changed (info, stamp); - } - } -} - -static inline void -gsk_gl_uniform_state_set4f (GskGLUniformState *state, - GskGLUniformProgram *program, - guint key, - guint stamp, - float value0, - float value1, - float value2, - float value3) -{ - Uniform4f *u; - GskGLUniformMapping *info; - - g_assert (state != NULL); - g_assert (program != NULL); - - if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_4F, 1, key, stamp, &info))) - { - if (info->info.initial || u->v0 != value0 || u->v1 != value1 || u->v2 != value2 || u->v3 != value3) - { - GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform4f, 1); - u->v0 = value0; - u->v1 = value1; - u->v2 = value2; - u->v3 = value3; - gsk_gl_uniform_info_changed (info, stamp); - } - } -} - -static inline void -gsk_gl_uniform_state_set1ui (GskGLUniformState *state, - GskGLUniformProgram *program, - guint key, - guint stamp, - guint value0) -{ - Uniform1ui *u; - GskGLUniformMapping *info; - - g_assert (state != NULL); - g_assert (program != NULL); - - if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_1UI, 1, key, stamp, &info))) - { - if (info->info.initial || u->v0 != value0) - { - GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform1ui, 1); - u->v0 = value0; - gsk_gl_uniform_info_changed (info, stamp); - } - } -} - -static inline void -gsk_gl_uniform_state_set1i (GskGLUniformState *state, - GskGLUniformProgram *program, - guint key, - guint stamp, - int value0) -{ - Uniform1i *u; - GskGLUniformMapping *info; - - g_assert (state != NULL); - g_assert (program != NULL); - - if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_1I, 1, key, stamp, &info))) - { - if (info->info.initial || u->v0 != value0) - { - GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform1i, 1); - u->v0 = value0; - gsk_gl_uniform_info_changed (info, stamp); - } - } -} - -static inline void -gsk_gl_uniform_state_set2i (GskGLUniformState *state, - GskGLUniformProgram *program, - guint key, - guint stamp, - int value0, - int value1) -{ - Uniform2i *u; - GskGLUniformMapping *info; - - g_assert (state != NULL); - g_assert (program != NULL); - - if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_2I, 1, key, stamp, &info))) - { - if (info->info.initial || u->v0 != value0 || u->v1 != value1) - { - GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform2i, 1); - u->v0 = value0; - u->v1 = value1; - gsk_gl_uniform_info_changed (info, stamp); - } - } -} - -static inline void -gsk_gl_uniform_state_set3i (GskGLUniformState *state, - GskGLUniformProgram *program, - guint key, - guint stamp, - int value0, - int value1, - int value2) -{ - Uniform3i *u; - GskGLUniformMapping *info; - - g_assert (state != NULL); - g_assert (program != NULL); - - if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_3I, 1, key, stamp, &info))) - { - if (info->info.initial || u->v0 != value0 || u->v1 != value1 || u->v2 != value2) - { - GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform3i, 1); - u->v0 = value0; - u->v1 = value1; - u->v2 = value2; - gsk_gl_uniform_info_changed (info, stamp); - } - } -} - -static inline void -gsk_gl_uniform_state_set4i (GskGLUniformState *state, - GskGLUniformProgram *program, - guint key, - guint stamp, - int value0, - int value1, - int value2, - int value3) -{ - Uniform4i *u; - GskGLUniformMapping *info; - - g_assert (state != NULL); - g_assert (program != NULL); - - if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_4I, 1, key, stamp, &info))) - { - if (info->info.initial || u->v0 != value0 || u->v1 != value1 || u->v2 != value2 || u->v3 != value3) - { - GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform4i, 1); - u->v0 = value0; - u->v1 = value1; - u->v2 = value2; - u->v3 = value3; - gsk_gl_uniform_info_changed (info, stamp); - } - } -} - -static inline void -gsk_gl_uniform_state_set_rounded_rect (GskGLUniformState *state, - GskGLUniformProgram *program, - guint key, - guint stamp, - const GskRoundedRect *rounded_rect) -{ - GskRoundedRect *u; - GskGLUniformMapping *info; - - g_assert (state != NULL); - g_assert (program != NULL); - g_assert (rounded_rect != NULL); - - if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_ROUNDED_RECT, 1, key, stamp, &info))) - { - if (info->info.initial || memcmp (u, rounded_rect, sizeof *u) != 0) - { - GSK_GL_UNIFORM_STATE_REPLACE (info, u, GskRoundedRect, 1); - memcpy (u, rounded_rect, sizeof *rounded_rect); - gsk_gl_uniform_info_changed (info, stamp); - } - } -} - -static inline void -gsk_gl_uniform_state_set_matrix (GskGLUniformState *state, - GskGLUniformProgram *program, - guint key, - guint stamp, - const graphene_matrix_t *matrix) -{ - graphene_matrix_t *u; - GskGLUniformMapping *info; - - g_assert (state != NULL); - g_assert (program != NULL); - g_assert (matrix != NULL); - - if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_MATRIX, 1, key, stamp, &info))) - { - if (info->info.initial || memcmp (u, matrix, sizeof *u) != 0) - { - GSK_GL_UNIFORM_STATE_REPLACE (info, u, graphene_matrix_t, 1); - memcpy (u, matrix, sizeof *matrix); - gsk_gl_uniform_info_changed (info, stamp); - } - } -} - -/** - * gsk_gl_uniform_state_set_texture: - * @state: a `GskGLUniformState` - * @program: the program id - * @location: the location of the texture - * @texture_slot: a texturing slot such as GL_TEXTURE0 - * - * Sets the uniform expecting a texture to @texture_slot. This API - * expects a texture slot such as GL_TEXTURE0 to reduce chances of - * miss-use by the caller. - * - * The value stored to the uniform is in the form of 0 for GL_TEXTURE0, - * 1 for GL_TEXTURE1, and so on. - */ -static inline void -gsk_gl_uniform_state_set_texture (GskGLUniformState *state, - GskGLUniformProgram *program, - guint key, - guint stamp, - guint texture_slot) -{ - GskGLUniformMapping *info; - guint *u; - - g_assert (texture_slot >= GL_TEXTURE0); - g_assert (texture_slot < GL_TEXTURE16); - - texture_slot -= GL_TEXTURE0; - - if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_TEXTURE, 1, key, stamp, &info))) - { - if (info->info.initial || *u != texture_slot) - { - GSK_GL_UNIFORM_STATE_REPLACE (info, u, guint, 1); - *u = texture_slot; - gsk_gl_uniform_info_changed (info, stamp); - } - } -} - -/** - * gsk_gl_uniform_state_set_color: - * @state: a `GskGLUniformState` - * @program: a program id > 0 - * @location: the uniform location - * @color: a color to set or %NULL for transparent - * - * Sets a uniform to the color described by @color. This is a convenience - * function to allow callers to avoid having to translate colors to floats - * in other portions of the renderer. - */ -static inline void -gsk_gl_uniform_state_set_color (GskGLUniformState *state, - GskGLUniformProgram *program, - guint key, - guint stamp, - const GdkRGBA *color) -{ - static const GdkRGBA transparent = {0}; - GskGLUniformMapping *info; - GdkRGBA *u; - - g_assert (state != NULL); - g_assert (program != NULL); - - if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_COLOR, 1, key, stamp, &info))) - { - if (color == NULL) - color = &transparent; - - if (info->info.initial || memcmp (color, u, sizeof *u) != 0) - { - GSK_GL_UNIFORM_STATE_REPLACE (info, u, GdkRGBA, 1); - memcpy (u, color, sizeof *color); - gsk_gl_uniform_info_changed (info, stamp); - } - } -} - -static inline void -gsk_gl_uniform_state_set1fv (GskGLUniformState *state, - GskGLUniformProgram *program, - guint key, - guint stamp, - guint count, - const float *value) -{ - Uniform1f *u; - GskGLUniformMapping *info; - - g_assert (state != NULL); - g_assert (program != NULL); - g_assert (count > 0); - - if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_1FV, count, key, stamp, &info))) - { - if (info->info.initial || count != info->info.array_count || memcmp (u, value, sizeof *u * count) != 0) - { - GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform1f, count); - memcpy (u, value, sizeof (Uniform1f) * count); - gsk_gl_uniform_info_changed (info, stamp); - } - } -} - -static inline void -gsk_gl_uniform_state_set2fv (GskGLUniformState *state, - GskGLUniformProgram *program, - guint key, - guint stamp, - guint count, - const float *value) -{ - Uniform2f *u; - GskGLUniformMapping *info; - - g_assert (state != NULL); - g_assert (program != NULL); - g_assert (count > 0); - - if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_2FV, count, key, stamp, &info))) - { - if (info->info.initial || count != info->info.array_count || memcmp (u, value, sizeof *u * count) != 0) - { - GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform2f, count); - memcpy (u, value, sizeof (Uniform2f) * count); - gsk_gl_uniform_info_changed (info, stamp); - } - } -} - -static inline void -gsk_gl_uniform_state_set3fv (GskGLUniformState *state, - GskGLUniformProgram *program, - guint key, - guint stamp, - guint count, - const float *value) -{ - Uniform3f *u; - GskGLUniformMapping *info; - - g_assert (state != NULL); - g_assert (program != NULL); - g_assert (count > 0); - - if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_3FV, count, key, stamp, &info))) - { - if (info->info.initial || count != info->info.array_count || memcmp (u, value, sizeof *u * count) != 0) - { - GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform3f, count); - memcpy (u, value, sizeof (Uniform3f) * count); - gsk_gl_uniform_info_changed (info, stamp); - } - } -} - -static inline void -gsk_gl_uniform_state_set4fv (GskGLUniformState *state, - GskGLUniformProgram *program, - guint key, - guint stamp, - guint count, - const float *value) -{ - Uniform4f *u; - GskGLUniformMapping *info; - - g_assert (state != NULL); - g_assert (program != NULL); - g_assert (count > 0); - - if ((u = gsk_gl_uniform_state_get_value (state, program, GSK_GL_UNIFORM_FORMAT_4FV, count, key, stamp, &info))) - { - if (info->info.initial || count != info->info.array_count || memcmp (u, value, sizeof *u * count) != 0) - { - GSK_GL_UNIFORM_STATE_REPLACE (info, u, Uniform4f, count); - memcpy (u, value, sizeof (Uniform4f) * count); - gsk_gl_uniform_info_changed (info, stamp); - } - } -} - -static inline guint -gsk_gl_uniform_state_fmix (guint program, - guint location) -{ - guint h = (program << 16) | location; - - h ^= h >> 16; - h *= 0x85ebca6b; - h ^= h >> 13; - h *= 0xc2b2ae35; - h ^= h >> 16; - - return h; -} - -/* - * gsk_gl_uniform_state_apply: - * @state: the uniform state - * @program: the program id - * @location: the location of the uniform - * @offset: the offset of the data within the buffer - * @info: the uniform info - * - * This function can be used to apply state that was previously recorded - * by the `GskGLUniformState`. - * - * It is specifically useful from the `GskGLCommandQueue` to execute uniform - * changes but only when they have changed from the current value. - */ -static inline void -gsk_gl_uniform_state_apply (GskGLUniformState *state, - guint program, - guint location, - GskGLUniformInfo info) -{ - guint index = gsk_gl_uniform_state_fmix (program, location) % G_N_ELEMENTS (state->apply_hash); - gconstpointer dataptr = GSK_GL_UNIFORM_VALUE (state->values_buf, info.offset); - - /* aligned, can treat as unsigned */ - if (*(guint *)&info == *(guint *)&state->apply_hash[index]) - return; - - state->apply_hash[index] = info; - - /* TODO: We could do additional comparisons here to make sure we are - * changing state. - */ - - switch (info.format) - { - case GSK_GL_UNIFORM_FORMAT_1F: - glUniform1fv (location, 1, dataptr); - break; - - case GSK_GL_UNIFORM_FORMAT_2F: - glUniform2fv (location, 1, dataptr); - break; - - case GSK_GL_UNIFORM_FORMAT_3F: - glUniform3fv (location, 1, dataptr); - break; - - case GSK_GL_UNIFORM_FORMAT_4F: - glUniform4fv (location, 1, dataptr); - break; - - case GSK_GL_UNIFORM_FORMAT_1FV: - glUniform1fv (location, info.array_count, dataptr); - break; - - case GSK_GL_UNIFORM_FORMAT_2FV: - glUniform2fv (location, info.array_count, dataptr); - break; - - case GSK_GL_UNIFORM_FORMAT_3FV: - glUniform3fv (location, info.array_count, dataptr); - break; - - case GSK_GL_UNIFORM_FORMAT_4FV: - glUniform4fv (location, info.array_count, dataptr); - break; - - case GSK_GL_UNIFORM_FORMAT_1I: - case GSK_GL_UNIFORM_FORMAT_TEXTURE: - glUniform1iv (location, 1, dataptr); - break; - - case GSK_GL_UNIFORM_FORMAT_2I: - glUniform2iv (location, 1, dataptr); - break; - - case GSK_GL_UNIFORM_FORMAT_3I: - glUniform3iv (location, 1, dataptr); - break; - - case GSK_GL_UNIFORM_FORMAT_4I: - glUniform4iv (location, 1, dataptr); - break; - - case GSK_GL_UNIFORM_FORMAT_1UI: - glUniform1uiv (location, 1, dataptr); - break; - - case GSK_GL_UNIFORM_FORMAT_MATRIX: { - float mat[16]; - graphene_matrix_to_float (dataptr, mat); - glUniformMatrix4fv (location, 1, GL_FALSE, mat); -#if 0 - /* TODO: If Graphene can give us a peek here on platforms - * where the format is float[16] (most/all x86_64?) then - * We can avoid the SIMD operation to convert the format. - */ - G_STATIC_ASSERT (sizeof (graphene_matrix_t) == 16*4); - glUniformMatrix4fv (location, 1, GL_FALSE, dataptr); -#endif - } - break; - - case GSK_GL_UNIFORM_FORMAT_COLOR: - glUniform4fv (location, 1, dataptr); - break; - - case GSK_GL_UNIFORM_FORMAT_ROUNDED_RECT: - glUniform4fv (location, 3, dataptr); - break; - - default: - g_assert_not_reached (); - } -} - -G_END_DECLS - diff --git a/gsk/gl/inlinearray.h b/gsk/gl/inlinearray.h deleted file mode 100644 index 204513d23c05d57866cb4fcce8fc07ed67381cab..0000000000000000000000000000000000000000 --- a/gsk/gl/inlinearray.h +++ /dev/null @@ -1,75 +0,0 @@ -#pragma once - -#define DEFINE_INLINE_ARRAY(Type, prefix, ElementType) \ - typedef struct _##Type { \ - gsize len; \ - gsize allocated; \ - ElementType *items; \ - } Type; \ - \ - static inline void \ - prefix##_init (Type *ar, \ - gsize initial_size) \ - { \ - ar->len = 0; \ - ar->allocated = initial_size ? initial_size : 16; \ - ar->items = g_new0 (ElementType, ar->allocated); \ - } \ - \ - static inline void \ - prefix##_clear (Type *ar) \ - { \ - ar->len = 0; \ - ar->allocated = 0; \ - g_clear_pointer (&ar->items, g_free); \ - } \ - \ - static inline ElementType * \ - prefix##_head (Type *ar) \ - { \ - return &ar->items[0]; \ - } \ - \ - static inline ElementType * \ - prefix##_tail (Type *ar) \ - { \ - return &ar->items[ar->len-1]; \ - } \ - \ - static inline ElementType * \ - prefix##_append (Type *ar) \ - { \ - if G_UNLIKELY (ar->len == ar->allocated) \ - { \ - ar->allocated *= 2; \ - ar->items = g_renew (ElementType, ar->items, ar->allocated);\ - } \ - \ - ar->len++; \ - \ - return prefix##_tail (ar); \ - } \ - \ - static inline ElementType * \ - prefix##_append_n (Type *ar, \ - gsize n) \ - { \ - if G_UNLIKELY ((ar->len + n) > ar->allocated) \ - { \ - while ((ar->len + n) > ar->allocated) \ - ar->allocated *= 2; \ - ar->items = g_renew (ElementType, ar->items, ar->allocated);\ - } \ - \ - ar->len += n; \ - \ - return &ar->items[ar->len-n]; \ - } \ - \ - static inline gsize \ - prefix##_index_of (Type *ar, \ - const ElementType *element) \ - { \ - return element - &ar->items[0]; \ - } - diff --git a/gsk/gl/ninesliceprivate.h b/gsk/gl/ninesliceprivate.h deleted file mode 100644 index 7191ec5f135e319610c54bfa4aa54fbd9445f8b9..0000000000000000000000000000000000000000 --- a/gsk/gl/ninesliceprivate.h +++ /dev/null @@ -1,308 +0,0 @@ -/* ninesliceprivate.h - * - * Copyright 2017 Timm Bäder - * Copyright 2021 Christian Hergert - * - * 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 . - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#pragma once - -#include "gskgltextureprivate.h" - -#if 0 -# define DEBUG_NINE_SLICE -#endif - -G_BEGIN_DECLS - -enum { - NINE_SLICE_TOP_LEFT = 0, - NINE_SLICE_TOP_CENTER = 1, - NINE_SLICE_TOP_RIGHT = 2, - NINE_SLICE_LEFT_CENTER = 3, - NINE_SLICE_CENTER = 4, - NINE_SLICE_RIGHT_CENTER = 5, - NINE_SLICE_BOTTOM_LEFT = 6, - NINE_SLICE_BOTTOM_CENTER = 7, - NINE_SLICE_BOTTOM_RIGHT = 8, -}; - -static inline bool G_GNUC_PURE -nine_slice_is_visible (const GskGLTextureNineSlice *slice) -{ - return slice->rect.width > 0 && slice->rect.height > 0; -} - -static inline void -nine_slice_rounded_rect (GskGLTextureNineSlice *slices, - const GskRoundedRect *rect) -{ - const graphene_point_t *origin = &rect->bounds.origin; - const graphene_size_t *size = &rect->bounds.size; - int top_height = ceilf (MAX (rect->corner[GSK_CORNER_TOP_LEFT].height, - rect->corner[GSK_CORNER_TOP_RIGHT].height)); - int bottom_height = ceilf (MAX (rect->corner[GSK_CORNER_BOTTOM_LEFT].height, - rect->corner[GSK_CORNER_BOTTOM_RIGHT].height)); - int right_width = ceilf (MAX (rect->corner[GSK_CORNER_TOP_RIGHT].width, - rect->corner[GSK_CORNER_BOTTOM_RIGHT].width)); - int left_width = ceilf (MAX (rect->corner[GSK_CORNER_TOP_LEFT].width, - rect->corner[GSK_CORNER_BOTTOM_LEFT].width)); - - /* Top left */ - slices[0].rect.x = origin->x; - slices[0].rect.y = origin->y; - slices[0].rect.width = left_width; - slices[0].rect.height = top_height; - - /* Top center */ - slices[1].rect.x = origin->x + size->width / 2.0 - 0.5; - slices[1].rect.y = origin->y; - slices[1].rect.width = 1; - slices[1].rect.height = top_height; - - /* Top right */ - slices[2].rect.x = origin->x + size->width - right_width; - slices[2].rect.y = origin->y; - slices[2].rect.width = right_width; - slices[2].rect.height = top_height; - - /* Left center */ - slices[3].rect.x = origin->x; - slices[3].rect.y = origin->y + size->height / 2; - slices[3].rect.width = left_width; - slices[3].rect.height = 1; - - /* center */ - slices[4].rect.x = origin->x + size->width / 2.0 - 0.5; - slices[4].rect.y = origin->y + size->height / 2.0 - 0.5; - slices[4].rect.width = 1; - slices[4].rect.height = 1; - - /* Right center */ - slices[5].rect.x = origin->x + size->width - right_width; - slices[5].rect.y = origin->y + (size->height / 2.0) - 0.5; - slices[5].rect.width = right_width; - slices[5].rect.height = 1; - - /* Bottom Left */ - slices[6].rect.x = origin->x; - slices[6].rect.y = origin->y + size->height - bottom_height; - slices[6].rect.width = left_width; - slices[6].rect.height = bottom_height; - - /* Bottom center */ - slices[7].rect.x = origin->x + (size->width / 2.0) - 0.5; - slices[7].rect.y = origin->y + size->height - bottom_height; - slices[7].rect.width = 1; - slices[7].rect.height = bottom_height; - - /* Bottom right */ - slices[8].rect.x = origin->x + size->width - right_width; - slices[8].rect.y = origin->y + size->height - bottom_height; - slices[8].rect.width = right_width; - slices[8].rect.height = bottom_height; - -#ifdef DEBUG_NINE_SLICE - /* These only hold true when the values from ceilf() above - * are greater than one. Otherwise they fail, like will happen - * with the node editor viewing the textures zoomed out. - */ - if (size->width > 1) - g_assert_cmpfloat (size->width, >=, left_width + right_width); - if (size->height > 1) - g_assert_cmpfloat (size->height, >=, top_height + bottom_height); -#endif -} - -static inline void -nine_slice_to_texture_coords (GskGLTextureNineSlice *slices, - int texture_width, - int texture_height) -{ - float fw = texture_width; - float fh = texture_height; - - for (guint i = 0; i < 9; i++) - { - GskGLTextureNineSlice *slice = &slices[i]; - - slice->area.x = slice->rect.x / fw; - slice->area.y = 1.0 - ((slice->rect.y + slice->rect.height) / fh); - slice->area.x2 = ((slice->rect.x + slice->rect.width) / fw); - slice->area.y2 = (1.0 - (slice->rect.y / fh)); - -#ifdef DEBUG_NINE_SLICE - g_assert_cmpfloat (slice->area.x, >=, 0); - g_assert_cmpfloat (slice->area.x, <=, 1); - g_assert_cmpfloat (slice->area.y, >=, 0); - g_assert_cmpfloat (slice->area.y, <=, 1); - g_assert_cmpfloat (slice->area.x2, >, slice->area.x); - g_assert_cmpfloat (slice->area.y2, >, slice->area.y); -#endif - } -} - -static inline void -nine_slice_grow (GskGLTextureNineSlice *slices, - int amount_x, - int amount_y) -{ - if (amount_x == 0 && amount_y == 0) - return; - - /* top left */ - slices[0].rect.x -= amount_x; - slices[0].rect.y -= amount_y; - if (amount_x > slices[0].rect.width) - slices[0].rect.width += amount_x * 2; - else - slices[0].rect.width += amount_x; - - if (amount_y > slices[0].rect.height) - slices[0].rect.height += amount_y * 2; - else - slices[0].rect.height += amount_y; - - - /* Top center */ - slices[1].rect.y -= amount_y; - if (amount_y > slices[1].rect.height) - slices[1].rect.height += amount_y * 2; - else - slices[1].rect.height += amount_y; - - /* top right */ - slices[2].rect.y -= amount_y; - if (amount_x > slices[2].rect.width) - { - slices[2].rect.x -= amount_x; - slices[2].rect.width += amount_x * 2; - } - else - { - slices[2].rect.width += amount_x; - } - - if (amount_y > slices[2].rect.height) - slices[2].rect.height += amount_y * 2; - else - slices[2].rect.height += amount_y; - - - - slices[3].rect.x -= amount_x; - if (amount_x > slices[3].rect.width) - slices[3].rect.width += amount_x * 2; - else - slices[3].rect.width += amount_x; - - /* Leave center alone */ - - if (amount_x > slices[5].rect.width) - { - slices[5].rect.x -= amount_x; - slices[5].rect.width += amount_x * 2; - } - else - { - slices[5].rect.width += amount_x; - } - - - /* Bottom left */ - slices[6].rect.x -= amount_x; - if (amount_x > slices[6].rect.width) - { - slices[6].rect.width += amount_x * 2; - } - else - { - slices[6].rect.width += amount_x; - } - - if (amount_y > slices[6].rect.height) - { - slices[6].rect.y -= amount_y; - slices[6].rect.height += amount_y * 2; - } - else - { - slices[6].rect.height += amount_y; - } - - - /* Bottom center */ - if (amount_y > slices[7].rect.height) - { - slices[7].rect.y -= amount_y; - slices[7].rect.height += amount_y * 2; - } - else - { - slices[7].rect.height += amount_y; - } - - if (amount_x > slices[8].rect.width) - { - slices[8].rect.x -= amount_x; - slices[8].rect.width += amount_x * 2; - } - else - { - slices[8].rect.width += amount_x; - } - - if (amount_y > slices[8].rect.height) - { - slices[8].rect.y -= amount_y; - slices[8].rect.height += amount_y * 2; - } - else - { - slices[8].rect.height += amount_y; - } - -#ifdef DEBUG_NINE_SLICE - /* These cannot be relied on in all cases right now, specifically - * when viewing data zoomed out. - */ - for (guint i = 0; i < 9; i ++) - { - g_assert_cmpint (slices[i].rect.x, >=, 0); - g_assert_cmpint (slices[i].rect.y, >=, 0); - g_assert_cmpint (slices[i].rect.width, >=, 0); - g_assert_cmpint (slices[i].rect.height, >=, 0); - } - - /* Rows don't overlap */ - for (guint i = 0; i < 3; i++) - { - int lhs = slices[i * 3 + 0].rect.x + slices[i * 3 + 0].rect.width; - int rhs = slices[i * 3 + 1].rect.x; - - /* Ignore the case where we are scaled out and the - * positioning is degenerate, such as from node-editor. - */ - if (rhs > 1) - g_assert_cmpint (lhs, <, rhs); - } -#endif - -} - -G_END_DECLS - diff --git a/gsk/gl/resources/blend.glsl b/gsk/gl/resources/blend.glsl deleted file mode 100644 index 41301c4a8b5756c1b3e2277ee2a84bd1256a65c3..0000000000000000000000000000000000000000 --- a/gsk/gl/resources/blend.glsl +++ /dev/null @@ -1,314 +0,0 @@ -// VERTEX_SHADER: -// blend.glsl - -void main() { - gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); - - vUv = vec2(aUv.x, aUv.y); -} - -// FRAGMENT_SHADER: -// blend.glsl - -uniform int u_mode; -uniform sampler2D u_source2; - -float -combine (float source, float backdrop) -{ - return source + backdrop * (1.0 - source); -} - -vec4 -composite (vec4 Cs, vec4 Cb, vec3 B) -{ - float ao = Cs.a + Cb.a * (1.0 - Cs.a); - vec3 Co = (Cs.a*(1.0 - Cb.a)*Cs.rgb + Cs.a*Cb.a*B + (1.0 - Cs.a)*Cb.a*Cb.rgb) / ao; - return vec4(Co, ao); -} - -vec4 -normal (vec4 Cs, vec4 Cb) -{ - return composite (Cs, Cb, Cs.rgb); -} - -vec4 -multiply (vec4 Cs, vec4 Cb) -{ - return composite (Cs, Cb, Cs.rgb * Cb.rgb); -} - -vec4 -difference (vec4 Cs, vec4 Cb) -{ - return composite (Cs, Cb, abs(Cs.rgb - Cb.rgb)); -} - -vec4 -screen (vec4 Cs, vec4 Cb) -{ - return composite (Cs, Cb, Cs.rgb + Cb.rgb - Cs.rgb * Cb.rgb); -} - -float -hard_light (float source, float backdrop) -{ - if (source <= 0.5) - return 2.0 * backdrop * source; - else - return 2.0 * (backdrop + source - backdrop * source) - 1.0; -} - -vec4 -hard_light (vec4 Cs, vec4 Cb) -{ - vec3 B = vec3 (hard_light (Cs.r, Cb.r), - hard_light (Cs.g, Cb.g), - hard_light (Cs.b, Cb.b)); - return composite (Cs, Cb, B); -} - -float -soft_light (float source, float backdrop) -{ - float db; - - if (backdrop <= 0.25) - db = ((16.0 * backdrop - 12.0) * backdrop + 4.0) * backdrop; - else - db = sqrt (backdrop); - - if (source <= 0.5) - return backdrop - (1.0 - 2.0 * source) * backdrop * (1.0 - backdrop); - else - return backdrop + (2.0 * source - 1.0) * (db - backdrop); -} - -vec4 -soft_light (vec4 Cs, vec4 Cb) -{ - vec3 B = vec3 (soft_light (Cs.r, Cb.r), - soft_light (Cs.g, Cb.g), - soft_light (Cs.b, Cb.b)); - return composite (Cs, Cb, B); -} - -vec4 -overlay (vec4 Cs, vec4 Cb) -{ - vec3 B = vec3 (hard_light (Cb.r, Cs.r), - hard_light (Cb.g, Cs.g), - hard_light (Cb.b, Cs.b)); - return composite (Cs, Cb, B); -} - -vec4 -darken (vec4 Cs, vec4 Cb) -{ - vec3 B = min (Cs.rgb, Cb.rgb); - return composite (Cs, Cb, B); -} - -vec4 -lighten (vec4 Cs, vec4 Cb) -{ - vec3 B = max (Cs.rgb, Cb.rgb); - return composite (Cs, Cb, B); -} - -float -color_dodge (float source, float backdrop) -{ - return (source == 1.0) ? source : min (backdrop / (1.0 - source), 1.0); -} - -vec4 -color_dodge (vec4 Cs, vec4 Cb) -{ - vec3 B = vec3 (color_dodge (Cs.r, Cb.r), - color_dodge (Cs.g, Cb.g), - color_dodge (Cs.b, Cb.b)); - return composite (Cs, Cb, B); -} - - -float -color_burn (float source, float backdrop) -{ - return (source == 0.0) ? source : max ((1.0 - ((1.0 - backdrop) / source)), 0.0); -} - -vec4 -color_burn (vec4 Cs, vec4 Cb) -{ - vec3 B = vec3 (color_burn (Cs.r, Cb.r), - color_burn (Cs.g, Cb.g), - color_burn (Cs.b, Cb.b)); - return composite (Cs, Cb, B); -} - -vec4 -exclusion (vec4 Cs, vec4 Cb) -{ - vec3 B = Cb.rgb + Cs.rgb - 2.0 * Cb.rgb * Cs.rgb; - return composite (Cs, Cb, B); -} - -float -lum (vec3 c) -{ - return 0.3 * c.r + 0.59 * c.g + 0.11 * c.b; -} - -vec3 -clip_color (vec3 c) -{ - float l = clamp (lum (c), 0.0, 1.0); - float n = min (c.r, min (c.g, c.b)); - float x = max (c.r, max (c.g, c.b)); - if (n < 0.0) c = l + (((c - l) * l) / (l - n)); - if (x > 1.0) c = l + (((c - l) * (1.0 - l)) / (x - l)); - return c; -} - -vec3 -set_lum (vec3 c, float l) -{ - float d = l - lum (c); - return clip_color (vec3 (c.r + d, c.g + d, c.b + d)); -} - -float -sat (vec3 c) -{ - return max (c.r, max (c.g, c.b)) - min (c.r, min (c.g, c.b)); -} - -vec3 -set_sat (vec3 c, float s) -{ - float cmin = min (c.r, min (c.g, c.b)); - float cmax = max (c.r, max (c.g, c.b)); - vec3 res; - - if (cmax == cmin) - res = vec3 (0, 0, 0); - else - { - if (c.r == cmax) - { - if (c.g == cmin) - { - res.b = ((c.b - cmin) * s) / (cmax - cmin); - res.g = 0.0; - } - else - { - res.g = ((c.g - cmin) * s) / (cmax - cmin); - res.b = 0.0; - } - res.r = s; - } - else if (c.g == cmax) - { - if (c.r == cmin) - { - res.b = ((c.b - cmin) * s) / (cmax - cmin); - res.r = 0.0; - } - else - { - res.r = ((c.r - cmin) * s) / (cmax - cmin); - res.b = 0.0; - } - res.g = s; - } - else - { - if (c.r == cmin) - { - res.g = ((c.g - cmin) * s) / (cmax - cmin); - res.r = 0.0; - } - else - { - res.r = ((c.r - cmin) * s) / (cmax - cmin); - res.g = 0.0; - } - res.b = s; - } - } - return res; -} - -vec4 -color (vec4 Cs, vec4 Cb) -{ - vec3 B = set_lum (Cs.rgb, lum (Cb.rgb)); - return composite (Cs, Cb, B); -} - -vec4 -hue (vec4 Cs, vec4 Cb) -{ - vec3 B = set_lum (set_sat (Cs.rgb, sat (Cb.rgb)), lum (Cb.rgb)); - return composite (Cs, Cb, B); -} - -vec4 -saturation (vec4 Cs, vec4 Cb) -{ - vec3 B = set_lum (set_sat (Cb.rgb, sat (Cs.rgb)), lum (Cb.rgb)); - return composite (Cs, Cb, B); -} - -vec4 -luminosity (vec4 Cs, vec4 Cb) -{ - vec3 B = set_lum (Cb.rgb, lum (Cs.rgb)); - return composite (Cs, Cb, B); -} - -void main() { - vec4 bottom_color = GskTexture(u_source, vUv); - vec4 top_color = GskTexture(u_source2, vUv); - - vec4 result; - if (u_mode == 0) - result = normal(top_color, bottom_color); - else if (u_mode == 1) - result = multiply(top_color, bottom_color); - else if (u_mode == 2) - result = screen(top_color, bottom_color); - else if (u_mode == 3) - result = overlay(top_color, bottom_color); - else if (u_mode == 4) - result = darken(top_color, bottom_color); - else if (u_mode == 5) - result = lighten(top_color, bottom_color); - else if (u_mode == 6) - result = color_dodge(top_color, bottom_color); - else if (u_mode == 7) - result = color_burn(top_color, bottom_color); - else if (u_mode == 8) - result = hard_light(top_color, bottom_color); - else if (u_mode == 9) - result = soft_light(top_color, bottom_color); - else if (u_mode == 10) - result = difference(top_color, bottom_color); - else if (u_mode == 11) - result = exclusion(top_color, bottom_color); - else if (u_mode == 12) - result = color(top_color, bottom_color); - else if (u_mode == 13) - result = hue(top_color, bottom_color); - else if (u_mode == 14) - result = saturation(top_color, bottom_color); - else if (u_mode == 15) - result = luminosity(top_color, bottom_color); - else - discard; - - gskSetScaledOutputColor(result, u_alpha); -} diff --git a/gsk/gl/resources/blit.glsl b/gsk/gl/resources/blit.glsl deleted file mode 100644 index ced047b9a985b9d7a149020a1ce1f2cadd6da8ad..0000000000000000000000000000000000000000 --- a/gsk/gl/resources/blit.glsl +++ /dev/null @@ -1,17 +0,0 @@ -// VERTEX_SHADER: -// blit.glsl - -void main() { - gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); - - vUv = vec2(aUv.x, aUv.y); -} - -// FRAGMENT_SHADER: -// blit.glsl - -void main() { - vec4 diffuse = GskTexture(u_source, vUv); - - gskSetScaledOutputColor(diffuse, u_alpha); -} diff --git a/gsk/gl/resources/blur.glsl b/gsk/gl/resources/blur.glsl deleted file mode 100644 index 7e7c1c251849bdfbd0c20f34355e9e2e905b16a5..0000000000000000000000000000000000000000 --- a/gsk/gl/resources/blur.glsl +++ /dev/null @@ -1,59 +0,0 @@ -// VERTEX_SHADER: -// blur.glsl - -uniform float u_blur_radius; -uniform vec2 u_blur_size; -uniform vec2 u_blur_dir; - -_OUT_ vec2 pixel_step; -_OUT_ float pixels_per_side; -_OUT_ vec3 initial_gaussian; - -const float PI = 3.14159265; -const float RADIUS_MULTIPLIER = 2.0; - -void main() { - gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); - - vUv = vec2(aUv.x, aUv.y); - - pixel_step = (vec2(1.0) / u_blur_size) * u_blur_dir; - pixels_per_side = floor(u_blur_radius * RADIUS_MULTIPLIER / 2.0); - - float sigma = u_blur_radius / 2.0; // *shrug* - initial_gaussian.x = 1.0 / (sqrt(2.0 * PI) * sigma); - initial_gaussian.y = exp(-0.5 / (sigma * sigma)); - initial_gaussian.z = initial_gaussian.y * initial_gaussian.y; -} - -// FRAGMENT_SHADER: -// blur.glsl - -_IN_ vec2 pixel_step; -_IN_ float pixels_per_side; -_IN_ vec3 initial_gaussian; - -// blur_radius 0 is NOT supported and MUST be caught before. - -// Partially from http://callumhay.blogspot.com/2010/09/gaussian-blur-shader-glsl.html -void main() { - vec3 incrementalGaussian = initial_gaussian; - - float coefficientSum = 0.0; - vec4 sum = GskTexture(u_source, vUv) * incrementalGaussian.x; - coefficientSum += incrementalGaussian.x; - incrementalGaussian.xy *= incrementalGaussian.yz; - - vec2 p = pixel_step; - for (int i = 1; i <= int(pixels_per_side); i++) { - sum += GskTexture(u_source, vUv - p) * incrementalGaussian.x; - sum += GskTexture(u_source, vUv + p) * incrementalGaussian.x; - - coefficientSum += 2.0 * incrementalGaussian.x; - incrementalGaussian.xy *= incrementalGaussian.yz; - - p += pixel_step; - } - - gskSetOutputColor(sum / coefficientSum); -} diff --git a/gsk/gl/resources/border.glsl b/gsk/gl/resources/border.glsl deleted file mode 100644 index 0fa3203887adfe8c106eb46c4d35ba87bd89f937..0000000000000000000000000000000000000000 --- a/gsk/gl/resources/border.glsl +++ /dev/null @@ -1,45 +0,0 @@ -// VERTEX_SHADER: -// border.glsl - -uniform vec4 u_widths; -uniform vec4[3] u_outline_rect; - -_OUT_ vec4 final_color; -_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; -_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; - -void main() { - gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); - - final_color = gsk_scaled_premultiply(aColor, u_alpha); - - GskRoundedRect outside = gsk_create_rect(u_outline_rect); - GskRoundedRect inside = gsk_rounded_rect_shrink (outside, u_widths); - - gsk_rounded_rect_transform(outside, u_modelview); - gsk_rounded_rect_transform(inside, u_modelview); - - gsk_rounded_rect_normalize(outside); - gsk_rounded_rect_normalize(inside); - - gsk_rounded_rect_encode(outside, transformed_outside_outline); - gsk_rounded_rect_encode(inside, transformed_inside_outline); -} - -// FRAGMENT_SHADER: -// border.glsl - -uniform vec4[3] u_outline_rect; - -_IN_ vec4 final_color; -_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; -_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; - -void main() { - vec2 frag = gsk_get_frag_coord(); - float outer_coverage = gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag); - float inner_coverage = gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag); - float alpha = clamp(outer_coverage - inner_coverage, 0.0, 1.0); - - gskSetScaledOutputColor(final_color, alpha); -} diff --git a/gsk/gl/resources/color.glsl b/gsk/gl/resources/color.glsl deleted file mode 100644 index ba98b1b170798f87009b3cd0f182ed945f8b857b..0000000000000000000000000000000000000000 --- a/gsk/gl/resources/color.glsl +++ /dev/null @@ -1,20 +0,0 @@ -// VERTEX_SHADER: -// color.glsl - -_OUT_ vec4 final_color; - -void main() { - gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); - - final_color = gsk_scaled_premultiply(aColor, u_alpha); -} - -// FRAGMENT_SHADER: -// color.glsl - -_IN_ vec4 final_color; - -void main() { - gskSetOutputColor(final_color); -} - diff --git a/gsk/gl/resources/color_matrix.glsl b/gsk/gl/resources/color_matrix.glsl deleted file mode 100644 index 51835f056fa9c919051ae98ad716db2ea72091d8..0000000000000000000000000000000000000000 --- a/gsk/gl/resources/color_matrix.glsl +++ /dev/null @@ -1,27 +0,0 @@ -// VERTEX_SHADER: -// color_matrix.glsl - -void main() { - gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); - - vUv = vec2(aUv.x, aUv.y); -} - -// FRAGMENT_SHADER: -// color_matrix.glsl - -uniform mat4 u_color_matrix; -uniform vec4 u_color_offset; - -void main() { - vec4 color = GskTexture(u_source, vUv); - - // Un-premultilpy - if (color.a != 0.0) - color.rgb /= color.a; - - color = u_color_matrix * color + u_color_offset; - color = clamp(color, 0.0, 1.0); - - gskSetOutputColor(gsk_scaled_premultiply(color, u_alpha)); -} diff --git a/gsk/gl/resources/coloring.glsl b/gsk/gl/resources/coloring.glsl deleted file mode 100644 index 0abe06ff05fc68b382390813c72965b0636e04fb..0000000000000000000000000000000000000000 --- a/gsk/gl/resources/coloring.glsl +++ /dev/null @@ -1,33 +0,0 @@ -// VERTEX_SHADER: -// coloring.glsl - -_OUT_ vec4 final_color; -_OUT_ float use_color; - -void main() { - gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); - - vUv = vec2(aUv.x, aUv.y); - - // We use this shader for both plain glyphs (used as mask) - // and color glyphs (used as source). The renderer sets - // aColor to vec4(-1) for color glyphs. - if (distance(aColor,vec4(-1)) < 0.1) - use_color = 0.0; - else - use_color = 1.0; - - final_color = gsk_scaled_premultiply(aColor, u_alpha); -} - -// FRAGMENT_SHADER: -// coloring.glsl - -_IN_ vec4 final_color; -_IN_ float use_color; - -void main() { - vec4 diffuse = GskTexture(u_source, vUv); - - gskSetOutputColor(mix(diffuse * u_alpha, final_color * diffuse.a, use_color)); -} diff --git a/gsk/gl/resources/conic_gradient.glsl b/gsk/gl/resources/conic_gradient.glsl deleted file mode 100644 index 9f5697843962864999e03842511636b0645ab12e..0000000000000000000000000000000000000000 --- a/gsk/gl/resources/conic_gradient.glsl +++ /dev/null @@ -1,85 +0,0 @@ -// VERTEX_SHADER -// conic_gradient.glsl - -uniform vec4 u_geometry; - -_OUT_ vec2 coord; - -void main() { - gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0)); - - vec2 mv0 = u_modelview[0].xy; - vec2 mv1 = u_modelview[1].xy; - vec2 offset = aPosition - u_geometry.xy; - - coord = vec2(dot(mv0, offset), dot(mv1, offset)); -} - -// FRAGMENT_SHADER: -// conic_gradient.glsl - -#define MAX_COLOR_STOPS 6 - -#ifdef GSK_LEGACY -uniform int u_num_color_stops; -#else -uniform highp int u_num_color_stops; // Why? Because it works like this. -#endif - -uniform vec4 u_geometry; -uniform float u_color_stops[MAX_COLOR_STOPS * 5]; - -_IN_ vec2 coord; - -float get_offset(int index) { - // u_color_stops[5 * index] makes Intel Windows driver crash. - // See https://gitlab.gnome.org/GNOME/gtk/-/issues/3783 - int base = 5 * index; - return u_color_stops[base]; -} - -vec4 get_color(int index) { - int base = 5 * index + 1; - - return vec4(u_color_stops[base], - u_color_stops[base + 1], - u_color_stops[base + 2], - u_color_stops[base + 3]); -} - -void main() { - // direction of point in range [-PI, PI] - vec2 pos = floor(coord); - float angle = atan(pos.y, pos.x); - - // fract() does the modulo here, so now we have progress - // into the current conic - float offset = fract(angle * u_geometry.z + u_geometry.w); - float curr_offset; - float next_offset; - - next_offset = get_offset(0); - if (offset < next_offset) { - gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha)); - return; - } - - if (offset >= get_offset(u_num_color_stops - 1)) { - gskSetOutputColor(gsk_scaled_premultiply(get_color(u_num_color_stops - 1), u_alpha)); - return; - } - - for (int i = 0; i < MAX_COLOR_STOPS; i++) { - curr_offset = next_offset; - next_offset = get_offset(i + 1); - - if (offset < next_offset) { - float f = (offset - curr_offset) / (next_offset - curr_offset); - vec4 curr_color = gsk_scaled_premultiply (get_color(i), u_alpha); - vec4 next_color = gsk_scaled_premultiply (get_color(i + 1), u_alpha); - vec4 color = mix(curr_color, next_color, f); - gskSetOutputColor(color); - return; - } - } -} diff --git a/gsk/gl/resources/cross_fade.glsl b/gsk/gl/resources/cross_fade.glsl deleted file mode 100644 index e61af597e91fdd12a3c7455806c36900d44fa135..0000000000000000000000000000000000000000 --- a/gsk/gl/resources/cross_fade.glsl +++ /dev/null @@ -1,24 +0,0 @@ -// VERTEX_SHADER: -// cross_fade.glsl - -void main() { - gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); - - vUv = vec2(aUv.x, aUv.y); -} - -// FRAGMENT_SHADER: -// cross_fade.glsl - -uniform float u_progress; -uniform sampler2D u_source2; - -void main() { - vec4 source1 = GskTexture(u_source, vUv); // start child - vec4 source2 = GskTexture(u_source2, vUv); // end child - - float p_start = (1.0 - u_progress) * u_alpha; - float p_end = u_progress * u_alpha; - vec4 color = (p_start * source1) + (p_end * source2); - gskSetOutputColor(color); -} diff --git a/gsk/gl/resources/custom.glsl b/gsk/gl/resources/custom.glsl deleted file mode 100644 index 6f91df6cf4f4230e8f49651c5b29405b60e3cfde..0000000000000000000000000000000000000000 --- a/gsk/gl/resources/custom.glsl +++ /dev/null @@ -1,25 +0,0 @@ -// VERTEX_SHADER: -// custom.glsl - -void main() { - gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); - vUv = vec2(aUv.x, aUv.y); -} - -// FRAGMENT_SHADER: -// custom.glsl - -// The shader supplies: -void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv); - -uniform vec2 u_size; -uniform sampler2D u_source2; -uniform sampler2D u_source3; -uniform sampler2D u_source4; - -void main() { - vec4 fragColor; - vec2 fragCoord = vec2(vUv.x * u_size.x, (1.0-vUv.y) * u_size.y); - mainImage(fragColor, fragCoord, u_size, vUv); - gskSetOutputColor(fragColor); -} diff --git a/gsk/gl/resources/external.glsl b/gsk/gl/resources/external.glsl deleted file mode 100644 index d2aaadd00371ec956e4874a02c5133b2cece5e33..0000000000000000000000000000000000000000 --- a/gsk/gl/resources/external.glsl +++ /dev/null @@ -1,34 +0,0 @@ -// VERTEX_SHADER: -// external.glsl - -void main() { - gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); - - vUv = vec2(aUv.x, aUv.y); -} - -// FRAGMENT_SHADER: -// external.glsl - -#if defined(GSK_GLES) || defined(GSK_GLES3) -uniform samplerExternalOES u_external_source; -#else -/* Just to make this compile, we won't use it without GLES */ -uniform sampler2D u_external_source; -#endif - -uniform int u_premultiply; - -void main() { -/* Open-code this here, since GskTexture() expects a sampler2D */ -#if defined(GSK_GLES) || defined(GSK_LEGACY) - vec4 color = texture2D(u_external_source, vUv); -#else - vec4 color = texture(u_external_source, vUv); -#endif - - if (u_premultiply == 1) - color.rgb *= color.a; - - gskSetOutputColor(color); -} diff --git a/gsk/gl/resources/filled_border.glsl b/gsk/gl/resources/filled_border.glsl deleted file mode 100644 index 23af3aa89c605f814019397f09da2a83745eea57..0000000000000000000000000000000000000000 --- a/gsk/gl/resources/filled_border.glsl +++ /dev/null @@ -1,50 +0,0 @@ -// VERTEX_SHADER: -// filled_border.glsl - -uniform vec4 u_widths; -uniform vec4[3] u_outline_rect; - -_OUT_ vec4 outer_color; -_OUT_ vec4 inner_color; -_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; -_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; - -void main() { - gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); - - outer_color = gsk_scaled_premultiply(aColor, u_alpha); - inner_color = gsk_scaled_premultiply(aColor2, u_alpha); - - GskRoundedRect outside = gsk_create_rect(u_outline_rect); - GskRoundedRect inside = gsk_rounded_rect_shrink (outside, u_widths); - - gsk_rounded_rect_transform(outside, u_modelview); - gsk_rounded_rect_transform(inside, u_modelview); - - gsk_rounded_rect_normalize(outside); - gsk_rounded_rect_normalize(inside); - - gsk_rounded_rect_encode(outside, transformed_outside_outline); - gsk_rounded_rect_encode(inside, transformed_inside_outline); -} - -// FRAGMENT_SHADER: -// filled_border.glsl - -uniform vec4[3] u_outline_rect; - -_IN_ vec4 outer_color; -_IN_ vec4 inner_color; -_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; -_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; - -void main() { - vec2 frag = gsk_get_frag_coord(); - float outer_coverage = gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag); - float inner_coverage = gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag); - - float alpha = clamp(outer_coverage - inner_coverage, 0.0, 1.0); - float alpha2 = clamp(inner_coverage, 0.0, 1.0); - - gskSetOutputColor((outer_color * alpha) + (inner_color * alpha2)); -} diff --git a/gsk/gl/resources/inset_shadow.glsl b/gsk/gl/resources/inset_shadow.glsl deleted file mode 100644 index 83d4287f130c7dab1af094299e7d30723a1eb139..0000000000000000000000000000000000000000 --- a/gsk/gl/resources/inset_shadow.glsl +++ /dev/null @@ -1,47 +0,0 @@ -// VERTEX_SHADER: -// inset_shadow.glsl - -uniform float u_spread; -uniform vec2 u_offset; -uniform vec4[3] u_outline_rect; - -_OUT_ vec4 final_color; -_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; -_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; - -void main() { - gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); - - final_color = gsk_scaled_premultiply(aColor, u_alpha); - - GskRoundedRect outside = gsk_create_rect(u_outline_rect); - GskRoundedRect inside = gsk_rounded_rect_shrink(outside, vec4(u_spread)); - - gsk_rounded_rect_offset(inside, u_offset); - - gsk_rounded_rect_transform(outside, u_modelview); - gsk_rounded_rect_transform(inside, u_modelview); - - gsk_rounded_rect_normalize(outside); - gsk_rounded_rect_normalize(inside); - - gsk_rounded_rect_encode(outside, transformed_outside_outline); - gsk_rounded_rect_encode(inside, transformed_inside_outline); -} - -// FRAGMENT_SHADER: -// inset_shadow.glsl - -_IN_ vec4 final_color; -_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; -_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; - -void main() { - vec2 frag = gsk_get_frag_coord(); - - float alpha = clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag) - - gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag), - 0.0, 1.0); - - gskSetScaledOutputColor(final_color, alpha); -} diff --git a/gsk/gl/resources/linear_gradient.glsl b/gsk/gl/resources/linear_gradient.glsl deleted file mode 100644 index d266cdbc79f3fa7b136599fc6a1659db9023c535..0000000000000000000000000000000000000000 --- a/gsk/gl/resources/linear_gradient.glsl +++ /dev/null @@ -1,107 +0,0 @@ -// VERTEX_SHADER -// linear_gradient.glsl -uniform vec4 u_points; - -_OUT_ vec4 info; - -void main() { - gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0)); - - vec2 mv0 = u_modelview[0].xy; - vec2 mv1 = u_modelview[1].xy; - vec2 offset = aPosition - u_points.xy; - vec2 coord = vec2(dot(mv0, offset), - dot(mv1, offset)); - - // Original equation: - // VS | maxDist = length(end - start); - // VS | gradient = end - start; - // VS | gradientLength = length(gradient); - // FS | pos = frag_coord - start - // FS | proj = (dot(gradient, pos) / (gradientLength * gradientLength)) * gradient - // FS | offset = length(proj) / maxDist - - // Simplified formula derivation: - // 1. Notice that maxDist = gradientLength: - // offset = length(proj) / gradientLength - // 2. Let gnorm = gradient / gradientLength, then: - // proj = (dot(gnorm * gradientLength, pos) / (gradientLength * gradientLength)) * (gnorm * gradientLength) = - // = dot(gnorm, pos) * gnorm - // 3. Since gnorm is unit length then: - // length(proj) = length(dot(gnorm, pos) * gnorm) = dot(gnorm, pos) - // 4. We can avoid the FS division by passing a scaled pos from the VS: - // offset = dot(gnorm, pos) / gradientLength = dot(gnorm, pos / gradientLength) - // 5. 1.0 / length(gradient) is inversesqrt(dot(gradient, gradient)) in GLSL - vec2 gradient = vec2(dot(mv0, u_points.zw), - dot(mv1, u_points.zw)); - float rcp_gradient_length = inversesqrt(dot(gradient, gradient)); - - info = rcp_gradient_length * vec4(coord, gradient); -} - -// FRAGMENT_SHADER: -// linear_gradient.glsl - -#define MAX_COLOR_STOPS 6 - -#ifdef GSK_LEGACY -uniform int u_num_color_stops; -#else -uniform highp int u_num_color_stops; // Why? Because it works like this. -#endif - -uniform float u_color_stops[MAX_COLOR_STOPS * 5]; -uniform bool u_repeat; - -_IN_ vec4 info; - -float get_offset(int index) { - // u_color_stops[5 * index] makes Intel Windows driver crash. - // See https://gitlab.gnome.org/GNOME/gtk/-/issues/3783 - int base = 5 * index; - return u_color_stops[base]; -} - -vec4 get_color(int index) { - int base = 5 * index + 1; - - return vec4(u_color_stops[base], - u_color_stops[base + 1], - u_color_stops[base + 2], - u_color_stops[base + 3]); -} - -void main() { - float offset = dot(info.xy, info.zw); - float curr_offset; - float next_offset; - - if (u_repeat) { - offset = fract(offset); - } - - next_offset = get_offset(0); - if (offset < next_offset) { - gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha)); - return; - } - - if (offset >= get_offset(u_num_color_stops - 1)) { - gskSetOutputColor(gsk_scaled_premultiply(get_color(u_num_color_stops - 1), u_alpha)); - return; - } - - for (int i = 0; i < MAX_COLOR_STOPS; i++) { - curr_offset = next_offset; - next_offset = get_offset(i + 1); - - if (offset < next_offset) { - float f = (offset - curr_offset) / (next_offset - curr_offset); - vec4 curr_color = gsk_scaled_premultiply (get_color(i), u_alpha); - vec4 next_color = gsk_scaled_premultiply (get_color(i + 1), u_alpha); - vec4 color = mix(curr_color, next_color, f); - gskSetOutputColor(color); - return; - } - } -} diff --git a/gsk/gl/resources/mask.glsl b/gsk/gl/resources/mask.glsl deleted file mode 100644 index 0c2814be9f132865c53bcc3a476473f8660993ee..0000000000000000000000000000000000000000 --- a/gsk/gl/resources/mask.glsl +++ /dev/null @@ -1,39 +0,0 @@ -// VERTEX_SHADER: -// mask.glsl - -void main() { - gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); - - vUv = vec2(aUv.x, aUv.y); -} - -// FRAGMENT_SHADER: -// mask.glsl - -uniform int u_mode; -uniform sampler2D u_mask; - -float -luminance (vec3 color) -{ - return dot (vec3 (0.2126, 0.7152, 0.0722), color); -} - -void main() { - vec4 source = GskTexture(u_source, vUv); - vec4 mask = GskTexture(u_mask, vUv); - float mask_value; - - if (u_mode == 0) - mask_value = mask.a; - else if (u_mode == 1) - mask_value = 1.0 - mask.a; - else if (u_mode == 2) - mask_value = luminance (mask.rgb); - else if (u_mode == 3) - mask_value = mask.a - luminance (mask.rgb); - else - mask_value = 0.0; - - gskSetOutputColor(vec4 (source * mask_value)); -} diff --git a/gsk/gl/resources/outset_shadow.glsl b/gsk/gl/resources/outset_shadow.glsl deleted file mode 100644 index fac86c0093c9ec49e0aa4bddbfca834ba640a205..0000000000000000000000000000000000000000 --- a/gsk/gl/resources/outset_shadow.glsl +++ /dev/null @@ -1,35 +0,0 @@ -// VERTEX_SHADER: -// outset_shadow.glsl - -uniform vec4[3] u_outline_rect; - -_OUT_ vec4 final_color; -_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outline; - -void main() { - gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); - - vUv = vec2(aUv.x, aUv.y); - - final_color = gsk_scaled_premultiply(aColor, u_alpha); - - GskRoundedRect outline = gsk_create_rect(u_outline_rect); - gsk_rounded_rect_transform(outline, u_modelview); - gsk_rounded_rect_normalize(outline); - gsk_rounded_rect_encode(outline, transformed_outline); -} - -// FRAGMENT_SHADER: -// outset_shadow.glsl - -_IN_ vec4 final_color; -_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outline; - -void main() { - vec2 frag = gsk_get_frag_coord(); - float alpha = GskTexture(u_source, vUv).a; - - alpha *= (1.0 - clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outline), frag), 0.0, 1.0)); - - gskSetScaledOutputColor(final_color, alpha); -} diff --git a/gsk/gl/resources/preamble.fs.glsl b/gsk/gl/resources/preamble.fs.glsl deleted file mode 100644 index 0c366bd8476ea01c909f0d52b0eb1f659b7d72cc..0000000000000000000000000000000000000000 --- a/gsk/gl/resources/preamble.fs.glsl +++ /dev/null @@ -1,166 +0,0 @@ -uniform sampler2D u_source; -uniform mat4 u_projection; -uniform mat4 u_modelview; -uniform float u_alpha; -uniform vec4 u_viewport; -uniform vec4[3] u_clip_rect; - -#if defined(GSK_LEGACY) -_OUT_ vec4 outputColor; -#elif !defined(GSK_GLES) -_OUT_ vec4 outputColor; -#endif - -_IN_ vec2 vUv; - - -GskRoundedRect gsk_decode_rect(_GSK_ROUNDED_RECT_UNIFORM_ r) -{ - GskRoundedRect rect; -#if defined(GSK_GLES) || defined(GSK_LEGACY) - rect = GskRoundedRect(r[0], r[1], r[2]); -#else - rect = r; -#endif - gsk_rounded_rect_normalize (rect); - - return rect; -} - -float -gsk_ellipsis_dist (vec2 p, vec2 radius) -{ - if (radius == vec2(0, 0)) - return 0.0; - - vec2 p0 = p / radius; - vec2 p1 = 2.0 * p0 / radius; - - return (dot(p0, p0) - 1.0) / length (p1); -} - -float -gsk_ellipsis_coverage (vec2 point, vec2 center, vec2 radius) -{ - float d = gsk_ellipsis_dist (point - center, radius); - return clamp (0.5 - d, 0.0, 1.0); -} - -float -gsk_rounded_rect_coverage (GskRoundedRect r, vec2 p) -{ - if (p.x < r.bounds.x || p.y < r.bounds.y || - p.x >= r.bounds.z || p.y >= r.bounds.w) - return 0.0; - - vec2 ref_tl = r.corner_points1.xy; - vec2 ref_tr = r.corner_points1.zw; - vec2 ref_br = r.corner_points2.xy; - vec2 ref_bl = r.corner_points2.zw; - - if (p.x >= ref_tl.x && p.x >= ref_bl.x && - p.x <= ref_tr.x && p.x <= ref_br.x) - return 1.0; - - if (p.y >= ref_tl.y && p.y >= ref_tr.y && - p.y <= ref_bl.y && p.y <= ref_br.y) - return 1.0; - - vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; - vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; - vec2 rad_br = r.corner_points2.xy - r.bounds.zw; - vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; - - float d_tl = gsk_ellipsis_coverage(p, ref_tl, rad_tl); - float d_tr = gsk_ellipsis_coverage(p, ref_tr, rad_tr); - float d_br = gsk_ellipsis_coverage(p, ref_br, rad_br); - float d_bl = gsk_ellipsis_coverage(p, ref_bl, rad_bl); - - vec4 corner_coverages = 1.0 - vec4(d_tl, d_tr, d_br, d_bl); - - bvec4 is_out = bvec4(p.x < ref_tl.x && p.y < ref_tl.y, - p.x > ref_tr.x && p.y < ref_tr.y, - p.x > ref_br.x && p.y > ref_br.y, - p.x < ref_bl.x && p.y > ref_bl.y); - - return 1.0 - dot(vec4(is_out), corner_coverages); -} - -float -gsk_rect_coverage (vec4 r, vec2 p) -{ - if (p.x < r.x || p.y < r.y || - p.x >= r.z || p.y >= r.w) - return 0.0; - - return 1.0; -} - -vec4 GskTexture(sampler2D sampler, vec2 texCoords) { -#if defined(GSK_GLES) || defined(GSK_LEGACY) - return texture2D(sampler, texCoords); -#else - return texture(sampler, texCoords); -#endif -} - -#ifdef GSK_GL3 -layout(origin_upper_left) in vec4 gl_FragCoord; -#endif - -vec2 gsk_get_frag_coord() { - vec2 fc = gl_FragCoord.xy; - -#ifdef GSK_GL3 - fc += u_viewport.xy; -#else - fc.x += u_viewport.x; - fc.y = (u_viewport.y + u_viewport.w) - fc.y; -#endif - - return fc; -} - -void gskSetOutputColor(vec4 color) { - vec4 result; - -#if defined(NO_CLIP) - result = color; -#elif defined(RECT_CLIP) - float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), - gsk_get_frag_coord()); - result = color * coverage; -#else - float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), - gsk_get_frag_coord()); - result = color * coverage; -#endif - -#if defined(GSK_GLES) || defined(GSK_LEGACY) - gl_FragColor = result; -#else - outputColor = result; -#endif -} - -void gskSetScaledOutputColor(vec4 color, float alpha) { - vec4 result; - -#if defined(NO_CLIP) - result = color * alpha; -#elif defined(RECT_CLIP) - float coverage = gsk_rect_coverage(gsk_get_bounds(u_clip_rect), - gsk_get_frag_coord()); - result = color * (alpha * coverage); -#else - float coverage = gsk_rounded_rect_coverage(gsk_create_rect(u_clip_rect), - gsk_get_frag_coord()); - result = color * (alpha * coverage); -#endif - -#if defined(GSK_GLES) || defined(GSK_LEGACY) - gl_FragColor = result; -#else - outputColor = result; -#endif -} diff --git a/gsk/gl/resources/preamble.glsl b/gsk/gl/resources/preamble.glsl deleted file mode 100644 index f37957947bed8ab8f340963ec6d4b0f63e56cd00..0000000000000000000000000000000000000000 --- a/gsk/gl/resources/preamble.glsl +++ /dev/null @@ -1,118 +0,0 @@ -#if defined(GSK_GLES3) -#extension GL_OES_EGL_image_external_essl3 : require -#elif defined (GSK_GLES) -#extension GL_OES_EGL_image_external : require -#endif - -#ifndef GSK_LEGACY -precision highp float; -#endif - -#if defined(GSK_GLES) || defined(GSK_LEGACY) -#define _OUT_ varying -#define _IN_ varying -#define _GSK_ROUNDED_RECT_UNIFORM_ vec4[3] -#else -#define _OUT_ out -#define _IN_ in -#define _GSK_ROUNDED_RECT_UNIFORM_ GskRoundedRect -#endif - - -struct GskRoundedRect -{ - vec4 bounds; // Top left and bottom right - // Look, arrays can't be in structs if you want to return the struct - // from a function in gles or whatever. Just kill me. - vec4 corner_points1; // xy = top left, zw = top right - vec4 corner_points2; // xy = bottom right, zw = bottom left -}; - -void gsk_rounded_rect_normalize(inout GskRoundedRect r) -{ - if (r.bounds.x > r.bounds.z) - { - float t = r.bounds.x; - r.bounds.x = r.bounds.z; - r.bounds.z = t; - - vec2 c = r.corner_points1.xy; - r.corner_points1.xy = r.corner_points1.zw; - r.corner_points1.zw = c; - - c = r.corner_points2.xy; - r.corner_points2.xy = r.corner_points2.zw; - r.corner_points2.zw = c; - } - - if (r.bounds.y > r.bounds.w) - { - float t = r.bounds.y; - r.bounds.y = r.bounds.w; - r.bounds.w = t; - - vec2 c = r.corner_points1.xy; - r.corner_points1.xy = r.corner_points2.xy; - r.corner_points2.xy = c; - - c = r.corner_points1.zw; - r.corner_points1.zw = r.corner_points2.zw; - r.corner_points2.zw = c; - } -} - -void gsk_bounds_normalize (inout vec4 bounds) -{ - if (bounds.x > bounds.z) - { - float t = bounds.x; - bounds.x = bounds.z; - bounds.z = t; - } - if (bounds.y > bounds.w) - { - float t = bounds.y; - bounds.y = bounds.w; - bounds.w = t; - } -} - -// Transform from a C GskRoundedRect to what we need. -GskRoundedRect -gsk_create_rect(vec4[3] data) -{ - vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); - - vec4 corner_points1 = vec4(bounds.xy + data[1].xy, - bounds.zy + vec2(data[1].zw * vec2(-1, 1))); - vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), - bounds.xw + vec2(data[2].zw * vec2(1, -1))); - - GskRoundedRect rect = GskRoundedRect(bounds, corner_points1, corner_points2); - - gsk_rounded_rect_normalize (rect); - - return rect; -} - -vec4 -gsk_get_bounds(vec4[3] data) -{ - vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); - - gsk_bounds_normalize (bounds); - - return bounds; -} - -vec4 gsk_premultiply(vec4 c) { - return vec4(c.rgb * c.a, c.a); -} - -vec4 gsk_scaled_premultiply(vec4 c, float s) { - // Fast version of gsk_premultiply(c) * s - // 4 muls instead of 7 - float a = s * c.a; - - return vec4(c.rgb * a, a); -} diff --git a/gsk/gl/resources/preamble.vs.glsl b/gsk/gl/resources/preamble.vs.glsl deleted file mode 100644 index ff3d5bb5a7265cdc8578cc87cb8db16a0b8e9e9b..0000000000000000000000000000000000000000 --- a/gsk/gl/resources/preamble.vs.glsl +++ /dev/null @@ -1,75 +0,0 @@ -uniform mat4 u_projection; -uniform mat4 u_modelview; -uniform float u_alpha; - -#if defined(GSK_GLES) || defined(GSK_LEGACY) -attribute vec2 aPosition; -attribute vec2 aUv; -attribute vec4 aColor; -attribute vec4 aColor2; -_OUT_ vec2 vUv; -#else -_IN_ vec2 aPosition; -_IN_ vec2 aUv; -_IN_ vec4 aColor; -_IN_ vec4 aColor2; -_OUT_ vec2 vUv; -#endif - -// amount is: top, right, bottom, left -GskRoundedRect -gsk_rounded_rect_shrink (GskRoundedRect r, vec4 amount) -{ - vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; - vec4 new_corner_points1 = r.corner_points1; - vec4 new_corner_points2 = r.corner_points2; - - if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; - if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; - if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; - if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; - new_corner_points1 = clamp (new_corner_points1, new_bounds.xyxy, new_bounds.zwzw); - new_corner_points2 = clamp (new_corner_points2, new_bounds.xyxy, new_bounds.zwzw); - - return GskRoundedRect (new_bounds, new_corner_points1, new_corner_points2); -} - -void -gsk_rounded_rect_offset(inout GskRoundedRect r, vec2 offset) -{ - r.bounds.xy += offset; - r.bounds.zw += offset; - r.corner_points1.xy += offset; - r.corner_points1.zw += offset; - r.corner_points2.xy += offset; - r.corner_points2.zw += offset; -} - -void gsk_rounded_rect_transform(inout GskRoundedRect r, mat4 mat) -{ - r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; - r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; - - r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; - r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; - - r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; - r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; -} - -#if defined(GSK_LEGACY) -// Can't have out or inout array parameters... -#define gsk_rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; -#else -void gsk_rounded_rect_encode(GskRoundedRect r, out _GSK_ROUNDED_RECT_UNIFORM_ out_r) -{ -#if defined(GSK_GLES) - out_r[0] = r.bounds; - out_r[1] = r.corner_points1; - out_r[2] = r.corner_points2; -#else - out_r = r; -#endif -} - -#endif diff --git a/gsk/gl/resources/premultiply.glsl b/gsk/gl/resources/premultiply.glsl deleted file mode 100644 index 892c2c445380ec9400d70f839b6931c2ac752c1d..0000000000000000000000000000000000000000 --- a/gsk/gl/resources/premultiply.glsl +++ /dev/null @@ -1,19 +0,0 @@ -// VERTEX_SHADER: -// premultiply.glsl - -void main() { - gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); - - vUv = vec2(aUv.x, aUv.y); -} - -// FRAGMENT_SHADER: -// premultiply.glsl - -void main() { - vec4 color = GskTexture(u_source, vUv); - - color.rgb *= color.a; - - gskSetOutputColor(color); -} diff --git a/gsk/gl/resources/radial_gradient.glsl b/gsk/gl/resources/radial_gradient.glsl deleted file mode 100644 index df955162375a783af91b968895ca37321240c2b7..0000000000000000000000000000000000000000 --- a/gsk/gl/resources/radial_gradient.glsl +++ /dev/null @@ -1,87 +0,0 @@ -// VERTEX_SHADER -// radial_gradient.glsl - -uniform vec4 u_geometry; - -_OUT_ vec2 coord; - -void main() { - gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0)); - - vec2 mv0 = u_modelview[0].xy; - vec2 mv1 = u_modelview[1].xy; - vec2 offset = aPosition - u_geometry.xy; - vec2 dir = vec2(dot(mv0, offset), - dot(mv1, offset)); - - coord = dir * u_geometry.zw; -} - -// FRAGMENT_SHADER: -// radial_gradient.glsl - -#define MAX_COLOR_STOPS 6 - -#ifdef GSK_LEGACY -uniform int u_num_color_stops; -#else -uniform highp int u_num_color_stops; -#endif - -uniform bool u_repeat; -uniform vec2 u_range; -uniform float u_color_stops[MAX_COLOR_STOPS * 5]; - -_IN_ vec2 coord; - -float get_offset(int index) { - // u_color_stops[5 * index] makes Intel Windows driver crash. - // See https://gitlab.gnome.org/GNOME/gtk/-/issues/3783 - int base = 5 * index; - return u_color_stops[base]; -} - -vec4 get_color(int index) { - int base = 5 * index + 1; - - return vec4(u_color_stops[base], - u_color_stops[base + 1], - u_color_stops[base + 2], - u_color_stops[base + 3]); -} - -void main() { - // Reverse scale - float offset = length(coord) * u_range.x + u_range.y; - float curr_offset; - float next_offset; - - if (u_repeat) { - offset = fract(offset); - } - - next_offset = get_offset(0); - if (offset < next_offset) { - gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha)); - return; - } - - if (offset >= get_offset(u_num_color_stops - 1)) { - gskSetOutputColor(gsk_scaled_premultiply(get_color(u_num_color_stops - 1), u_alpha)); - return; - } - - for (int i = 0; i < MAX_COLOR_STOPS; i++) { - curr_offset = next_offset; - next_offset = get_offset(i + 1); - - if (offset < next_offset) { - float f = (offset - curr_offset) / (next_offset - curr_offset); - vec4 curr_color = gsk_scaled_premultiply (get_color(i), u_alpha); - vec4 next_color = gsk_scaled_premultiply (get_color(i + 1), u_alpha); - vec4 color = mix(curr_color, next_color, f); - gskSetOutputColor(color); - return; - } - } -} diff --git a/gsk/gl/resources/repeat.glsl b/gsk/gl/resources/repeat.glsl deleted file mode 100644 index 1b811df2daa28e74b052d88f7a20c68c1dfc4afe..0000000000000000000000000000000000000000 --- a/gsk/gl/resources/repeat.glsl +++ /dev/null @@ -1,44 +0,0 @@ -// VERTEX_SHADER: -// repeat.glsl - -void main() { - gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); - - vUv = vec2(aUv.x, aUv.y); -} - -// FRAGMENT_SHADER: -// repeat.glsl - -uniform vec4 u_child_bounds; -uniform vec4 u_texture_rect; - -float wrap(float f, float wrap_for) { - return mod(f, wrap_for); -} - -/* We get the texture coordinates via vUv, - * but that might be on a texture atlas, so we need to do the - * wrapping ourselves. - */ -void main() { - - /* We map the texture coordinate to [1;0], then wrap it and scale the result again */ - - float tw = u_texture_rect.z - u_texture_rect.x; - float th = u_texture_rect.w - u_texture_rect.y; - - float mapped_x = (vUv.x - u_texture_rect.x) / tw; - float mapped_y = (vUv.y - u_texture_rect.y) / th; - - float wrapped_x = wrap(u_child_bounds.x + mapped_x * u_child_bounds.z, 1.0); - float wrapped_y = wrap(u_child_bounds.y + mapped_y * u_child_bounds.w, 1.0); - - vec2 tp; - tp.x = u_texture_rect.x + (wrapped_x * tw); - tp.y = u_texture_rect.y + (wrapped_y * th); - - vec4 diffuse = GskTexture(u_source, tp); - - gskSetScaledOutputColor(diffuse, u_alpha); -} diff --git a/gsk/gl/resources/unblurred_outset_shadow.glsl b/gsk/gl/resources/unblurred_outset_shadow.glsl deleted file mode 100644 index cd44212c933f2c29721b306d903cca2d93514a8e..0000000000000000000000000000000000000000 --- a/gsk/gl/resources/unblurred_outset_shadow.glsl +++ /dev/null @@ -1,44 +0,0 @@ -// VERTEX_SHADER: -// unblurred_outset_shadow.glsl - -uniform float u_spread; -uniform vec2 u_offset; -uniform vec4[3] u_outline_rect; - -_OUT_ vec4 final_color; -_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; -_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; - -void main() { - gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); - - final_color = gsk_premultiply(aColor) * u_alpha; - - GskRoundedRect inside = gsk_create_rect(u_outline_rect); - GskRoundedRect outside = gsk_rounded_rect_shrink(inside, vec4(- u_spread)); - - gsk_rounded_rect_offset(outside, u_offset); - - gsk_rounded_rect_transform(outside, u_modelview); - gsk_rounded_rect_transform(inside, u_modelview); - - gsk_rounded_rect_encode(outside, transformed_outside_outline); - gsk_rounded_rect_encode(inside, transformed_inside_outline); -} - -// FRAGMENT_SHADER: -// unblurred_outset_shadow.glsl -_IN_ vec4 final_color; -_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline; -_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline; - -void main() { - vec2 frag = gsk_get_frag_coord(); - - float alpha = clamp(gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag) - - gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag), - 0.0, 1.0); - - gskSetScaledOutputColor(final_color, alpha); -} - diff --git a/gsk/gl/stb_rect_pack.c b/gsk/gl/stb_rect_pack.c deleted file mode 100644 index 2ef31512b4dd60f9144d5b56f7298d9b6a477566..0000000000000000000000000000000000000000 --- a/gsk/gl/stb_rect_pack.c +++ /dev/null @@ -1,427 +0,0 @@ - -#include "stb_rect_pack.h" -#define STB_RECT_PACK_IMPLEMENTATION -////////////////////////////////////////////////////////////////////////////// -// -// IMPLEMENTATION SECTION -// - -#ifdef STB_RECT_PACK_IMPLEMENTATION -#ifndef STBRP_SORT -#include -#define STBRP_SORT qsort -#endif - -#ifndef STBRP_ASSERT -#include -#define STBRP_ASSERT assert -#endif - -#ifdef _MSC_VER -#define STBRP__NOTUSED(v) (void)(v) -#define STBRP__CDECL __cdecl -#else -#define STBRP__NOTUSED(v) (void)sizeof(v) -#define STBRP__CDECL -#endif - -enum -{ - STBRP__INIT_skyline = 1 -}; - -STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic) -{ - switch (context->init_mode) { - case STBRP__INIT_skyline: - STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight); - context->heuristic = heuristic; - break; - default: - STBRP_ASSERT(0); - } -} - -STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem) -{ - if (allow_out_of_mem) - // if it's ok to run out of memory, then don't bother aligning them; - // this gives better packing, but may fail due to OOM (even though - // the rectangles easily fit). @TODO a smarter approach would be to only - // quantize once we've hit OOM, then we could get rid of this parameter. - context->align = 1; - else { - // if it's not ok to run out of memory, then quantize the widths - // so that num_nodes is always enough nodes. - // - // I.e. num_nodes * align >= width - // align >= width / num_nodes - // align = ceil(width/num_nodes) - - context->align = (context->width + context->num_nodes-1) / context->num_nodes; - } -} - -STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes) -{ - int i; - - for (i=0; i < num_nodes-1; ++i) - nodes[i].next = &nodes[i+1]; - nodes[i].next = NULL; - context->init_mode = STBRP__INIT_skyline; - context->heuristic = STBRP_HEURISTIC_Skyline_default; - context->free_head = &nodes[0]; - context->active_head = &context->extra[0]; - context->width = width; - context->height = height; - context->num_nodes = num_nodes; - stbrp_setup_allow_out_of_mem(context, 0); - - // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly) - context->extra[0].x = 0; - context->extra[0].y = 0; - context->extra[0].next = &context->extra[1]; - context->extra[1].x = (stbrp_coord) width; - context->extra[1].y = (1<<30); - context->extra[1].next = NULL; -} - -// find minimum y position if it starts at x1 -static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste) -{ - stbrp_node *node = first; - int x1 = x0 + width; - int min_y, visited_width, waste_area; - - STBRP__NOTUSED(c); - - STBRP_ASSERT(first->x <= x0); - - #if 0 - // skip in case we're past the node - while (node->next->x <= x0) - ++node; - #else - STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency - #endif - - STBRP_ASSERT(node->x <= x0); - - min_y = 0; - waste_area = 0; - visited_width = 0; - while (node->x < x1) { - if (node->y > min_y) { - // raise min_y higher. - // we've accounted for all waste up to min_y, - // but we'll now add more waste for everything we've visited - waste_area += visited_width * (node->y - min_y); - min_y = node->y; - // the first time through, visited_width might be reduced - if (node->x < x0) - visited_width += node->next->x - x0; - else - visited_width += node->next->x - node->x; - } else { - // add waste area - int under_width = node->next->x - node->x; - if (under_width + visited_width > width) - under_width = width - visited_width; - waste_area += under_width * (min_y - node->y); - visited_width += under_width; - } - node = node->next; - } - - *pwaste = waste_area; - return min_y; -} - -typedef struct -{ - int x,y; - stbrp_node **prev_link; -} stbrp__findresult; - -static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height) -{ - int best_waste = (1<<30), best_x, best_y = (1 << 30); - stbrp__findresult fr; - stbrp_node **prev, *node, *tail, **best = NULL; - - // align to multiple of c->align - width = (width + c->align - 1); - width -= width % c->align; - STBRP_ASSERT(width % c->align == 0); - - // if it can't possibly fit, bail immediately - if (width > c->width || height > c->height) { - fr.prev_link = NULL; - fr.x = fr.y = 0; - return fr; - } - - node = c->active_head; - prev = &c->active_head; - while (node->x + width <= c->width) { - int y,waste; - y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste); - if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL - // bottom left - if (y < best_y) { - best_y = y; - best = prev; - } - } else { - // best-fit - if (y + height <= c->height) { - // can only use it if it first vertically - if (y < best_y || (y == best_y && waste < best_waste)) { - best_y = y; - best_waste = waste; - best = prev; - } - } - } - prev = &node->next; - node = node->next; - } - - best_x = (best == NULL) ? 0 : (*best)->x; - - // if doing best-fit (BF), we also have to try aligning right edge to each node position - // - // e.g, if fitting - // - // ____________________ - // |____________________| - // - // into - // - // | | - // | ____________| - // |____________| - // - // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned - // - // This makes BF take about 2x the time - - if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) { - tail = c->active_head; - node = c->active_head; - prev = &c->active_head; - // find first node that's admissible - while (tail->x < width) - tail = tail->next; - while (tail) { - int xpos = tail->x - width; - int y,waste; - STBRP_ASSERT(xpos >= 0); - // find the left position that matches this - while (node->next->x <= xpos) { - prev = &node->next; - node = node->next; - } - STBRP_ASSERT(node->next->x > xpos && node->x <= xpos); - y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste); - if (y + height <= c->height) { - if (y <= best_y) { - if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) { - best_x = xpos; - STBRP_ASSERT(y <= best_y); - best_y = y; - best_waste = waste; - best = prev; - } - } - } - tail = tail->next; - } - } - - fr.prev_link = best; - fr.x = best_x; - fr.y = best_y; - return fr; -} - -static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height) -{ - // find best position according to heuristic - stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height); - stbrp_node *node, *cur; - - // bail if: - // 1. it failed - // 2. the best node doesn't fit (we don't always check this) - // 3. we're out of memory - if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) { - res.prev_link = NULL; - return res; - } - - // on success, create new node - node = context->free_head; - node->x = (stbrp_coord) res.x; - node->y = (stbrp_coord) (res.y + height); - - context->free_head = node->next; - - // insert the new node into the right starting point, and - // let 'cur' point to the remaining nodes needing to be - // stiched back in - - cur = *res.prev_link; - if (cur->x < res.x) { - // preserve the existing one, so start testing with the next one - stbrp_node *next = cur->next; - cur->next = node; - cur = next; - } else { - *res.prev_link = node; - } - - // from here, traverse cur and free the nodes, until we get to one - // that shouldn't be freed - while (cur->next && cur->next->x <= res.x + width) { - stbrp_node *next = cur->next; - // move the current node to the free list - cur->next = context->free_head; - context->free_head = cur; - cur = next; - } - - // stitch the list back in - node->next = cur; - - if (cur->x < res.x + width) - cur->x = (stbrp_coord) (res.x + width); - -#ifdef _DEBUG - cur = context->active_head; - while (cur->x < context->width) { - STBRP_ASSERT(cur->x < cur->next->x); - cur = cur->next; - } - STBRP_ASSERT(cur->next == NULL); - - { - int count=0; - cur = context->active_head; - while (cur) { - cur = cur->next; - ++count; - } - cur = context->free_head; - while (cur) { - cur = cur->next; - ++count; - } - STBRP_ASSERT(count == context->num_nodes+2); - } -#endif - - return res; -} - -static int STBRP__CDECL rect_height_compare(const void *a, const void *b) -{ - const stbrp_rect *p = (const stbrp_rect *) a; - const stbrp_rect *q = (const stbrp_rect *) b; - if (p->h > q->h) - return -1; - if (p->h < q->h) - return 1; - return (p->w > q->w) ? -1 : (p->w < q->w); -} - -static int STBRP__CDECL rect_original_order(const void *a, const void *b) -{ - const stbrp_rect *p = (const stbrp_rect *) a; - const stbrp_rect *q = (const stbrp_rect *) b; - return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed); -} - -STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects) -{ - int i, all_rects_packed = 1; - - // we use the 'was_packed' field internally to allow sorting/unsorting - for (i=0; i < num_rects; ++i) { - rects[i].was_packed = i; - } - - // sort according to heuristic - STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare); - - for (i=0; i < num_rects; ++i) { - if (rects[i].w == 0 || rects[i].h == 0) { - rects[i].x = rects[i].y = 0; // empty rect needs no space - } else { - stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h); - if (fr.prev_link) { - rects[i].x = (stbrp_coord) fr.x; - rects[i].y = (stbrp_coord) fr.y; - } else { - rects[i].x = rects[i].y = STBRP__MAXVAL; - } - } - } - - // unsort - STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order); - - // set was_packed flags and all_rects_packed status - for (i=0; i < num_rects; ++i) { - rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL); - if (!rects[i].was_packed) - all_rects_packed = 0; - } - - // return the all_rects_packed status - return all_rects_packed; -} -#endif - -/* ------------------------------------------------------------------------------- -This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------- -ALTERNATIVE A - MIT License -Copyright (c) 2017 Sean Barrett -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ------------------------------------------------------------------------------- -ALTERNATIVE B - Public Domain (www.unlicense.org) -This is free and unencumbered software released into the public domain. -Anyone is free to copy, modify, publish, use, compile, sell, or distribute this -software, either in source code form or as a compiled binary, for any purpose, -commercial or non-commercial, and by any means. -In jurisdictions that recognize copyright laws, the author or authors of this -software dedicate any and all copyright interest in the software to the public -domain. We make this dedication for the benefit of the public at large and to -the detriment of our heirs and successors. We intend this dedication to be an -overt act of relinquishment in perpetuity of all present and future rights to -this software under copyright law. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------- -*/ diff --git a/gsk/gl/stb_rect_pack.h b/gsk/gl/stb_rect_pack.h deleted file mode 100644 index 2a3833ec80ddc30a0d353f0d6fb5b7a7ca34926f..0000000000000000000000000000000000000000 --- a/gsk/gl/stb_rect_pack.h +++ /dev/null @@ -1,197 +0,0 @@ -// stb_rect_pack.h - v1.01 - public domain - rectangle packing -// Sean Barrett 2014 -// -// Useful for e.g. packing rectangular textures into an atlas. -// Does not do rotation. -// -// Before #including, -// -// #define STB_RECT_PACK_IMPLEMENTATION -// -// in the file that you want to have the implementation. -// -// Not necessarily the awesomest packing method, but better than -// the totally naive one in stb_truetype (which is primarily what -// this is meant to replace). -// -// Has only had a few tests run, may have issues. -// -// More docs to come. -// -// No memory allocations; uses qsort() and assert() from stdlib. -// Can override those by defining STBRP_SORT and STBRP_ASSERT. -// -// This library currently uses the Skyline Bottom-Left algorithm. -// -// Please note: better rectangle packers are welcome! Please -// implement them to the same API, but with a different init -// function. -// -// Credits -// -// Library -// Sean Barrett -// Minor features -// Martins Mozeiko -// github:IntellectualKitty -// -// Bugfixes / warning fixes -// Jeremy Jaussaud -// Fabian Giesen -// -// Version history: -// -// 1.01 (2021-07-11) always use large rect mode, expose STBRP__MAXVAL in public section -// 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles -// 0.99 (2019-02-07) warning fixes -// 0.11 (2017-03-03) return packing success/fail result -// 0.10 (2016-10-25) remove cast-away-const to avoid warnings -// 0.09 (2016-08-27) fix compiler warnings -// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0) -// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0) -// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort -// 0.05: added STBRP_ASSERT to allow replacing assert -// 0.04: fixed minor bug in STBRP_LARGE_RECTS support -// 0.01: initial release -// -// LICENSE -// -// See end of file for license information. - -////////////////////////////////////////////////////////////////////////////// -// -// INCLUDE SECTION -// - -#pragma once - -#define STB_RECT_PACK_VERSION 1 - -#ifdef STBRP_STATIC -#define STBRP_DEF static -#else -#define STBRP_DEF extern -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct stbrp_context stbrp_context; -typedef struct stbrp_node stbrp_node; -typedef struct stbrp_rect stbrp_rect; - -typedef int stbrp_coord; - -#define STBRP__MAXVAL 0x7fffffff -// Mostly for internal use, but this is the maximum supported coordinate value. - -STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects); -// Assign packed locations to rectangles. The rectangles are of type -// 'stbrp_rect' defined below, stored in the array 'rects', and there -// are 'num_rects' many of them. -// -// Rectangles which are successfully packed have the 'was_packed' flag -// set to a non-zero value and 'x' and 'y' store the minimum location -// on each axis (i.e. bottom-left in cartesian coordinates, top-left -// if you imagine y increasing downwards). Rectangles which do not fit -// have the 'was_packed' flag set to 0. -// -// You should not try to access the 'rects' array from another thread -// while this function is running, as the function temporarily reorders -// the array while it executes. -// -// To pack into another rectangle, you need to call stbrp_init_target -// again. To continue packing into the same rectangle, you can call -// this function again. Calling this multiple times with multiple rect -// arrays will probably produce worse packing results than calling it -// a single time with the full rectangle array, but the option is -// available. -// -// The function returns 1 if all of the rectangles were successfully -// packed and 0 otherwise. - -struct stbrp_rect -{ - // reserved for your use: - int id; - - // input: - stbrp_coord w, h; - - // output: - stbrp_coord x, y; - int was_packed; // non-zero if valid packing - -}; // 16 bytes, nominally - - -STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes); -// Initialize a rectangle packer to: -// pack a rectangle that is 'width' by 'height' in dimensions -// using temporary storage provided by the array 'nodes', which is 'num_nodes' long -// -// You must call this function every time you start packing into a new target. -// -// There is no "shutdown" function. The 'nodes' memory must stay valid for -// the following stbrp_pack_rects() call (or calls), but can be freed after -// the call (or calls) finish. -// -// Note: to guarantee best results, either: -// 1. make sure 'num_nodes' >= 'width' -// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1' -// -// If you don't do either of the above things, widths will be quantized to multiples -// of small integers to guarantee the algorithm doesn't run out of temporary storage. -// -// If you do #2, then the non-quantized algorithm will be used, but the algorithm -// may run out of temporary storage and be unable to pack some rectangles. - -STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem); -// Optionally call this function after init but before doing any packing to -// change the handling of the out-of-temp-memory scenario, described above. -// If you call init again, this will be reset to the default (false). - - -STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic); -// Optionally select which packing heuristic the library should use. Different -// heuristics will produce better/worse results for different data sets. -// If you call init again, this will be reset to the default. - -enum -{ - STBRP_HEURISTIC_Skyline_default=0, - STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default, - STBRP_HEURISTIC_Skyline_BF_sortHeight -}; - - -////////////////////////////////////////////////////////////////////////////// -// -// the details of the following structures don't matter to you, but they must -// be visible so you can handle the memory allocations for them - -struct stbrp_node -{ - stbrp_coord x,y; - stbrp_node *next; -}; - -struct stbrp_context -{ - int width; - int height; - int align; - int init_mode; - int heuristic; - int num_nodes; - stbrp_node *active_head; - stbrp_node *free_head; - stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' -}; - -#ifdef __cplusplus -} -#endif - - diff --git a/gsk/gpu/gsknglrenderer.c b/gsk/gpu/gskglrenderer.c similarity index 54% rename from gsk/gpu/gsknglrenderer.c rename to gsk/gpu/gskglrenderer.c index 94d3e2b8f2164d45d521771fc30a0a08778147a7..1cdce228ce7444a694e40fc48881cbeeb8b343d5 100644 --- a/gsk/gpu/gsknglrenderer.c +++ b/gsk/gpu/gskglrenderer.c @@ -1,6 +1,6 @@ #include "config.h" -#include "gsknglrendererprivate.h" +#include "gskglrenderer.h" #include "gskgpuimageprivate.h" #include "gskgpurendererprivate.h" @@ -15,7 +15,7 @@ #include /** - * GskNglRenderer: + * GskGLRenderer: * * A GL based renderer. * @@ -23,26 +23,26 @@ * * Since: 4.2 */ -struct _GskNglRenderer +struct _GskGLRenderer { GskGpuRenderer parent_instance; GskGpuImage *backbuffer; }; -struct _GskNglRendererClass +struct _GskGLRendererClass { GskGpuRendererClass parent_class; }; -G_DEFINE_TYPE (GskNglRenderer, gsk_ngl_renderer, GSK_TYPE_GPU_RENDERER) +G_DEFINE_TYPE (GskGLRenderer, gsk_gl_renderer, GSK_TYPE_GPU_RENDERER) static GdkDrawContext * -gsk_ngl_renderer_create_context (GskGpuRenderer *renderer, - GdkDisplay *display, - GdkSurface *surface, - GskGpuOptimizations *supported, - GError **error) +gsk_gl_renderer_create_context (GskGpuRenderer *renderer, + GdkDisplay *display, + GdkSurface *surface, + GskGpuOptimizations *supported, + GError **error) { GdkGLContext *context; @@ -74,13 +74,13 @@ gsk_ngl_renderer_create_context (GskGpuRenderer *renderer, } static void -gsk_ngl_renderer_make_current (GskGpuRenderer *renderer) +gsk_gl_renderer_make_current (GskGpuRenderer *renderer) { gdk_gl_context_make_current (GDK_GL_CONTEXT (gsk_gpu_renderer_get_context (renderer))); } static gpointer -gsk_ngl_renderer_save_current (GskGpuRenderer *renderer) +gsk_gl_renderer_save_current (GskGpuRenderer *renderer) { GdkGLContext *current; @@ -92,8 +92,8 @@ gsk_ngl_renderer_save_current (GskGpuRenderer *renderer) } static void -gsk_ngl_renderer_restore_current (GskGpuRenderer *renderer, - gpointer current) +gsk_gl_renderer_restore_current (GskGpuRenderer *renderer, + gpointer current) { if (current) { @@ -105,15 +105,15 @@ gsk_ngl_renderer_restore_current (GskGpuRenderer *renderer, } static void -gsk_ngl_renderer_free_backbuffer (GskNglRenderer *self) +gsk_gl_renderer_free_backbuffer (GskGLRenderer *self) { g_clear_object (&self->backbuffer); } static GskGpuImage * -gsk_ngl_renderer_get_backbuffer (GskGpuRenderer *renderer) +gsk_gl_renderer_get_backbuffer (GskGpuRenderer *renderer) { - GskNglRenderer *self = GSK_NGL_RENDERER (renderer); + GskGLRenderer *self = GSK_GL_RENDERER (renderer); GdkDrawContext *context; GdkSurface *surface; double scale; @@ -127,7 +127,7 @@ gsk_ngl_renderer_get_backbuffer (GskGpuRenderer *renderer) gsk_gpu_image_get_width (self->backbuffer) != ceil (gdk_surface_get_width (surface) * scale) || gsk_gpu_image_get_height (self->backbuffer) != ceil (gdk_surface_get_height (surface) * scale)) { - gsk_ngl_renderer_free_backbuffer (self); + gsk_gl_renderer_free_backbuffer (self); self->backbuffer = gsk_gl_image_new_backbuffer (GSK_GL_DEVICE (gsk_gpu_renderer_get_device (renderer)), GDK_GL_CONTEXT (context), GDK_MEMORY_DEFAULT /* FIXME */, @@ -140,7 +140,7 @@ gsk_ngl_renderer_get_backbuffer (GskGpuRenderer *renderer) } static double -gsk_ngl_renderer_get_scale (GskGpuRenderer *self) +gsk_gl_renderer_get_scale (GskGpuRenderer *self) { GdkDrawContext *context = gsk_gpu_renderer_get_context (self); @@ -148,19 +148,19 @@ gsk_ngl_renderer_get_scale (GskGpuRenderer *self) } static void -gsk_ngl_renderer_unrealize (GskRenderer *renderer) +gsk_gl_renderer_unrealize (GskRenderer *renderer) { - GskNglRenderer *self = GSK_NGL_RENDERER (renderer); + GskGLRenderer *self = GSK_GL_RENDERER (renderer); - gsk_ngl_renderer_free_backbuffer (self); + gsk_gl_renderer_free_backbuffer (self); gdk_gl_context_clear_current (); - GSK_RENDERER_CLASS (gsk_ngl_renderer_parent_class)->unrealize (renderer); + GSK_RENDERER_CLASS (gsk_gl_renderer_parent_class)->unrealize (renderer); } static void -gsk_ngl_renderer_class_init (GskNglRendererClass *klass) +gsk_gl_renderer_class_init (GskGLRendererClass *klass) { GskGpuRendererClass *gpu_renderer_class = GSK_GPU_RENDERER_CLASS (klass); GskRendererClass *renderer_class = GSK_RENDERER_CLASS (klass); @@ -168,30 +168,80 @@ gsk_ngl_renderer_class_init (GskNglRendererClass *klass) gpu_renderer_class->frame_type = GSK_TYPE_GL_FRAME; gpu_renderer_class->get_device = gsk_gl_device_get_for_display; - gpu_renderer_class->create_context = gsk_ngl_renderer_create_context; - gpu_renderer_class->make_current = gsk_ngl_renderer_make_current; - gpu_renderer_class->save_current = gsk_ngl_renderer_save_current; - gpu_renderer_class->restore_current = gsk_ngl_renderer_restore_current; - gpu_renderer_class->get_backbuffer = gsk_ngl_renderer_get_backbuffer; - gpu_renderer_class->get_scale = gsk_ngl_renderer_get_scale; - - renderer_class->unrealize = gsk_ngl_renderer_unrealize; + gpu_renderer_class->create_context = gsk_gl_renderer_create_context; + gpu_renderer_class->make_current = gsk_gl_renderer_make_current; + gpu_renderer_class->save_current = gsk_gl_renderer_save_current; + gpu_renderer_class->restore_current = gsk_gl_renderer_restore_current; + gpu_renderer_class->get_backbuffer = gsk_gl_renderer_get_backbuffer; + gpu_renderer_class->get_scale = gsk_gl_renderer_get_scale; + + renderer_class->unrealize = gsk_gl_renderer_unrealize; } static void -gsk_ngl_renderer_init (GskNglRenderer *self) +gsk_gl_renderer_init (GskGLRenderer *self) { } +/** + * gsk_gl_renderer_new: + * + * Creates an instance of the GL renderer. + * + * Returns: (transfer full): a GL renderer + */ +GskRenderer * +gsk_gl_renderer_new (void) +{ + return g_object_new (GSK_TYPE_GL_RENDERER, NULL); +} + +typedef struct { + GskRenderer parent_instance; +} GskNglRenderer; + +typedef struct { + GskRendererClass parent_class; +} GskNglRendererClass; + +G_DEFINE_TYPE (GskNglRenderer, gsk_ngl_renderer, GSK_TYPE_RENDERER) + +static void +gsk_ngl_renderer_init (GskNglRenderer *renderer) +{ +} + +static gboolean +gsk_ngl_renderer_realize (GskRenderer *renderer, + GdkDisplay *display, + GdkSurface *surface, + GError **error) +{ + g_set_error_literal (error, + G_IO_ERROR, G_IO_ERROR_FAILED, + "Please use the GL renderer instead"); + return FALSE; +} + +static void +gsk_ngl_renderer_class_init (GskNglRendererClass *class) +{ + GSK_RENDERER_CLASS (class)->realize = gsk_ngl_renderer_realize; +} + /** * gsk_ngl_renderer_new: * - * Creates an instance of the new experimental GL renderer. + * Same as gsk_gl_renderer_new(). + * + * Returns: (transfer full): a GL renderer * - * Returns: (transfer full): a new GL renderer + * Deprecated: 4.18: Use gsk_gl_renderer_new() */ GskRenderer * gsk_ngl_renderer_new (void) { - return g_object_new (GSK_TYPE_NGL_RENDERER, NULL); +G_GNUC_BEGIN_IGNORE_DEPRECATIONS + return g_object_new (gsk_ngl_renderer_get_type (), NULL); +G_GNUC_END_IGNORE_DEPRECATIONS } diff --git a/gsk/gpu/gskglrenderer.h b/gsk/gpu/gskglrenderer.h new file mode 100644 index 0000000000000000000000000000000000000000..986c40d79b2183db2cd20a47bfd0a7736c236ba2 --- /dev/null +++ b/gsk/gpu/gskglrenderer.h @@ -0,0 +1,48 @@ +/* + * Copyright © 2024 Red Hat, Inc. + * + * 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 library. If not, see . + */ + +#pragma once + +#include +#include + +G_BEGIN_DECLS + +#define GSK_TYPE_GL_RENDERER (gsk_gl_renderer_get_type()) + +#define GSK_GL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_GL_RENDERER, GskGLRenderer)) +#define GSK_IS_GL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_GL_RENDERER)) +#define GSK_GL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_GL_RENDERER, GskGLRendererClass)) +#define GSK_IS_GL_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_GL_RENDERER)) +#define GSK_GL_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_GL_RENDERER, GskGLRendererClass)) + +typedef struct _GskGLRenderer GskGLRenderer; +typedef struct _GskGLRendererClass GskGLRendererClass; + +GDK_AVAILABLE_IN_ALL +GskRenderer *gsk_gl_renderer_new (void); + +GDK_AVAILABLE_IN_ALL +GType gsk_gl_renderer_get_type (void) G_GNUC_CONST; + +GDK_DEPRECATED_IN_4_18_FOR (gsk_gl_renderer_get_type) +GType gsk_ngl_renderer_get_type (void) G_GNUC_CONST; + +GDK_DEPRECATED_IN_4_18_FOR (gsk_gl_renderer_new) +GskRenderer *gsk_ngl_renderer_new (void); + +G_END_DECLS diff --git a/gsk/gpu/gsknglrendererprivate.h b/gsk/gpu/gsknglrendererprivate.h deleted file mode 100644 index ad520880ae3e3e524cb5684398686ea0c5166f28..0000000000000000000000000000000000000000 --- a/gsk/gpu/gsknglrendererprivate.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include "gskgpurendererprivate.h" - -G_BEGIN_DECLS - -#define GSK_TYPE_NGL_RENDERER (gsk_ngl_renderer_get_type ()) - -GDK_AVAILABLE_IN_ALL -G_DECLARE_FINAL_TYPE (GskNglRenderer, gsk_ngl_renderer, GSK, NGL_RENDERER, GskGpuRenderer) - -GDK_AVAILABLE_IN_ALL -GskRenderer *gsk_ngl_renderer_new (void); - -G_END_DECLS - diff --git a/gsk/gsk.h b/gsk/gsk.h index d118ef3c0a63ead39ae045062437192fc6840fb2..c95459171997ca8732cc179d3161bcbc139d8907 100644 --- a/gsk/gsk.h +++ b/gsk/gsk.h @@ -32,8 +32,8 @@ #include #include -#include #include +#include #include #include diff --git a/gsk/gskrenderer.c b/gsk/gskrenderer.c index f6c8f7c0115e85a646ae70efebcbab858f4308f4..1cd3cae7aae7fd2941ba2a62e62ed434c428dcdd 100644 --- a/gsk/gskrenderer.c +++ b/gsk/gskrenderer.c @@ -43,7 +43,7 @@ #include "gskenumtypes.h" -#include "gl/gskglrenderer.h" +#include "gpu/gskglrenderer.h" #include "gpu/gskvulkanrenderer.h" #include "gdk/gdkvulkancontextprivate.h" #include "gdk/gdkdisplayprivate.h" @@ -514,32 +514,39 @@ get_renderer_for_name (const char *renderer_name) #endif else if (g_ascii_strcasecmp (renderer_name, "cairo") == 0) return GSK_TYPE_CAIRO_RENDERER; - else if (g_ascii_strcasecmp (renderer_name, "opengl") == 0 || - g_ascii_strcasecmp (renderer_name, "gl") == 0) + else if (g_ascii_strcasecmp (renderer_name, "ngl") == 0 || + g_ascii_strcasecmp (renderer_name, "opengl") == 0) return GSK_TYPE_GL_RENDERER; - else if (g_ascii_strcasecmp (renderer_name, "ngl") == 0) - return gsk_ngl_renderer_get_type (); + else if (g_ascii_strcasecmp (renderer_name, "gl") == 0) + { + g_warning ("The old GL renderer has been removed. Try GSK_RENDERER=help"); + return GSK_TYPE_GL_RENDERER; + } #ifdef GDK_RENDERING_VULKAN else if (g_ascii_strcasecmp (renderer_name, "vulkan") == 0) return GSK_TYPE_VULKAN_RENDERER; #endif else if (g_ascii_strcasecmp (renderer_name, "help") == 0) { - g_print ("Supported arguments for GSK_RENDERER environment variable:\n"); + fprintf (stderr, "Supported arguments for GSK_RENDERER environment variable:\n"); #ifdef GDK_WINDOWING_BROADWAY - g_print (" broadway - Use the Broadway specific renderer\n"); + fprintf (stderr, " broadway - Use the Broadway specific renderer\n"); #else - g_print (" broadway - Disabled during GTK build\n"); + fprintf (stderr, " broadway - Disabled during GTK build\n"); #endif - g_print (" cairo - Use the Cairo fallback renderer\n"); - g_print (" ngl - Use the OpenGL renderer\n"); + fprintf (stderr, " cairo - Use the Cairo fallback renderer\n"); + fprintf (stderr, " opengl - Use the OpenGL renderer\n"); + fprintf (stderr, " ngl - Use the OpenGL renderer\n"); + fprintf (stderr, " gl - Use the OpenGL renderer\n"); #ifdef GDK_RENDERING_VULKAN - g_print (" vulkan - Use the Vulkan renderer\n"); + fprintf (stderr, " vulkan - Use the Vulkan renderer\n"); #else - g_print (" vulkan - Disabled during GTK build\n"); + fprintf (stderr, " vulkan - Disabled during GTK build\n"); #endif - g_print (" help - Print this help\n\n"); - g_print ("Other arguments will cause a warning and be ignored.\n"); + fprintf (stderr, " help - Print this help\n\n"); + fprintf (stderr, "The old OpenGL renderer has been removed in GTK 4.18, so using\n"); + fprintf (stderr, "GSK_RENDERER=gl will cause a warning and use the new OpenGL renderer.\n\n"); + fprintf (stderr, "Other arguments will cause a warning and be ignored.\n"); } else { @@ -626,19 +633,19 @@ gl_supported_platform (GdkSurface *surface, static GType get_renderer_for_gl (GdkSurface *surface) { - if (!gl_supported_platform (surface, gsk_ngl_renderer_get_type (), FALSE)) + if (!gl_supported_platform (surface, GSK_TYPE_GL_RENDERER, FALSE)) return G_TYPE_INVALID; - return gsk_ngl_renderer_get_type (); + return GSK_TYPE_GL_RENDERER; } static GType get_renderer_for_gl_fallback (GdkSurface *surface) { - if (!gl_supported_platform (surface, gsk_ngl_renderer_get_type (), TRUE)) + if (!gl_supported_platform (surface, GSK_TYPE_GL_RENDERER, TRUE)) return G_TYPE_INVALID; - return gsk_ngl_renderer_get_type (); + return GSK_TYPE_GL_RENDERER; } #ifdef GDK_RENDERING_VULKAN diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c index 6af196575ca2a67f488297f24938756a82c7e397..1369f12c42ee45fc24e6e51c192c65a711c90edf 100644 --- a/gsk/gskrendernodeimpl.c +++ b/gsk/gskrendernodeimpl.c @@ -24,7 +24,6 @@ #include "gskcairorenderer.h" #include "gskdebugprivate.h" #include "gskdiffprivate.h" -#include "gl/gskglrenderer.h" #include "gskpathprivate.h" #include "gskrectprivate.h" #include "gskrendererprivate.h" @@ -32,6 +31,7 @@ #include "gskstrokeprivate.h" #include "gsktransformprivate.h" #include "gskprivate.h" +#include "gpu/gskglrenderer.h" #include "gdk/gdkcairoprivate.h" #include "gdk/gdkcolorstateprivate.h" @@ -9010,7 +9010,7 @@ gsk_render_node_png_serializer (GdkContentSerializer *serializer) node = gsk_value_get_render_node (gdk_content_serializer_get_value (serializer)); - renderer = gsk_ngl_renderer_new (); + renderer = gsk_gl_renderer_new (); if (!gsk_renderer_realize (renderer, NULL, NULL)) { g_object_unref (renderer); diff --git a/gsk/meson.build b/gsk/meson.build index 0daa9fe72f23edf861f2a155e8de5926016736e4..69df4d81e713efec3a2286fd674b9c490baf7318 100644 --- a/gsk/meson.build +++ b/gsk/meson.build @@ -1,29 +1,3 @@ -gsk_private_gl_shaders = [ - 'gl/resources/preamble.glsl', - 'gl/resources/preamble.fs.glsl', - 'gl/resources/preamble.vs.glsl', - 'gl/resources/border.glsl', - 'gl/resources/blit.glsl', - 'gl/resources/coloring.glsl', - 'gl/resources/color.glsl', - 'gl/resources/linear_gradient.glsl', - 'gl/resources/radial_gradient.glsl', - 'gl/resources/conic_gradient.glsl', - 'gl/resources/color_matrix.glsl', - 'gl/resources/blur.glsl', - 'gl/resources/inset_shadow.glsl', - 'gl/resources/outset_shadow.glsl', - 'gl/resources/unblurred_outset_shadow.glsl', - 'gl/resources/cross_fade.glsl', - 'gl/resources/blend.glsl', - 'gl/resources/repeat.glsl', - 'gl/resources/custom.glsl', - 'gl/resources/filled_border.glsl', - 'gl/resources/mask.glsl', - 'gl/resources/external.glsl', - 'gl/resources/premultiply.glsl', -] - gsk_public_sources = files([ 'gskcairorenderer.c', 'gskdiff.c', @@ -41,8 +15,7 @@ gsk_public_sources = files([ 'gskroundedrect.c', 'gskstroke.c', 'gsktransform.c', - 'gl/gskglrenderer.c', - 'gpu/gsknglrenderer.c', + 'gpu/gskglrenderer.c', 'gpu/gskvulkanrenderer.c', ]) @@ -53,21 +26,6 @@ gsk_private_sources = files([ 'gskdebug.c', 'gskprivate.c', 'gskprofiler.c', - 'gl/gskglattachmentstate.c', - 'gl/gskglbuffer.c', - 'gl/gskglcommandqueue.c', - 'gl/gskglcompiler.c', - 'gl/gskgldriver.c', - 'gl/gskglglyphlibrary.c', - 'gl/gskgliconlibrary.c', - 'gl/gskglprogram.c', - 'gl/gskglrenderjob.c', - 'gl/gskglshadowlibrary.c', - 'gl/gskgltexturelibrary.c', - 'gl/gskgluniformstate.c', - 'gl/gskgltexture.c', - 'gl/gskglprofiler.c', - 'gl/stb_rect_pack.c', 'gl/fp16.c', 'gpu/gskglbuffer.c', 'gpu/gskgldevice.c', @@ -136,11 +94,10 @@ install_headers(gsk_public_headers, 'gsk.h', subdir: 'gtk-4.0/gsk') gsk_public_gl_headers = files([ 'gl/gskglrenderer.h', ]) -install_headers(gsk_public_gl_headers, subdir: 'gtk-4.0/gsk/gl') -gsk_public_headers += gsk_public_gl_headers gsk_public_gpu_headers = files([ - 'gpu/gskvulkanrenderer.h' + 'gpu/gskvulkanrenderer.h', + 'gpu/gskglrenderer.h' ]) install_headers(gsk_public_gpu_headers, subdir: 'gtk-4.0/gsk/gpu') gsk_public_headers += gsk_public_gpu_headers @@ -182,7 +139,6 @@ gsk_resources_xml = custom_target(output: 'gsk.resources.xml', command: [ find_program('gen-gsk-gresources-xml.py'), '@OUTPUT@', - gsk_private_gl_shaders, gsk_private_vulkan_compiled_shaders, gsk_private_vulkan_shaders, gsk_private_gpu_gl_shaders, diff --git a/po/POTFILES.in b/po/POTFILES.in index aa11a330fe338f996579937d952f9d78f793cc23..e8e7b0a0441bf8eb7b920c73cbb551be9a1cb54b 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -58,9 +58,8 @@ gdk/x11/gdkglcontext-x11.c gdk/x11/gdkmain-x11.c gdk/x11/gdkselectioninputstream-x11.c gdk/x11/gdktextlistconverter-x11.c -gsk/gl/gskglrenderer.c gsk/gpu/gskgldevice.c -gsk/gpu/gsknglrenderer.c +gsk/gpu/gskglrenderer.c gsk/gskrendernodeimpl.c gtk/a11y/gtkatspiaction.c gtk/a11y/gtkatspiroot.c diff --git a/testsuite/gdk/memorytexture.c b/testsuite/gdk/memorytexture.c index e9484f17fc0c6dbd249d07db17526c66b95c17c0..6ba38323d9578aafab416f69ca8f8d4868716e1d 100644 --- a/testsuite/gdk/memorytexture.c +++ b/testsuite/gdk/memorytexture.c @@ -685,7 +685,7 @@ main (int argc, char *argv[]) g_clear_object (&gl_context); } - gl_renderer = gsk_ngl_renderer_new (); + gl_renderer = gsk_gl_renderer_new (); if (!gsk_renderer_realize_for_display (gl_renderer, display, NULL)) { g_clear_object (&gl_renderer); diff --git a/testsuite/gdk/texture-threads.c b/testsuite/gdk/texture-threads.c index 677d0ba3230e9b085cdc3ed7989531a8035ceebf..b5a499305160b0c57b27135caa559cfc688aba5d 100644 --- a/testsuite/gdk/texture-threads.c +++ b/testsuite/gdk/texture-threads.c @@ -64,7 +64,7 @@ texture_threads (void) GError *error = NULL; /* 1. Get a GL renderer */ - gl_renderer = gsk_ngl_renderer_new (); + gl_renderer = gsk_gl_renderer_new (); if (!gsk_renderer_realize_for_display (gl_renderer, gdk_display_get_default (), &error)) { g_test_skip (error->message); diff --git a/testsuite/gsk/meson.build b/testsuite/gsk/meson.build index 97f606a1b521f9439b95fbde8da9416ce8046c26..29afa87c451a4fd7521ff8e160288623877597ef 100644 --- a/testsuite/gsk/meson.build +++ b/testsuite/gsk/meson.build @@ -219,7 +219,6 @@ informative_render_tests = [ ] renderers = [ - { 'name': 'gl' }, { 'name': 'broadway' }, { 'name': 'cairo' }, { 'name': 'ngl' }, diff --git a/testsuite/gsk/misc.c b/testsuite/gsk/misc.c index 2038b2cd28b97b54ee6e8c767e682e2a6b96d4e9..d8596ade02d600be9702bdfcea9349836acebe84 100644 --- a/testsuite/gsk/misc.c +++ b/testsuite/gsk/misc.c @@ -208,12 +208,12 @@ test_cairo_renderer (void) } static void -test_ngl_renderer (void) +test_gl_renderer (void) { #ifdef GDK_RENDERING_GL GskRenderer *renderer; - renderer = gsk_ngl_renderer_new (); + renderer = gsk_gl_renderer_new (); test_renderer (renderer); g_clear_object (&renderer); #else @@ -247,7 +247,7 @@ main (int argc, char *argv[]) g_test_add_func ("/rendernode/conic-gradient/angle", test_conic_gradient_angle); g_test_add_func ("/rendernode/container/disjoint", test_container_disjoint); g_test_add_func ("/renderer/cairo", test_cairo_renderer); - g_test_add_func ("/renderer/ngl", test_ngl_renderer); + g_test_add_func ("/renderer/gl", test_gl_renderer); g_test_add_func ("/renderer/vulkan", test_vulkan_renderer); return g_test_run (); diff --git a/testsuite/gsk/scaling.c b/testsuite/gsk/scaling.c index 04208cfdf8286e5f2bef1a751b98cc1e2a491ac1..23562d0ebb9169fea141238d99bed906dad3e026 100644 --- a/testsuite/gsk/scaling.c +++ b/testsuite/gsk/scaling.c @@ -10,13 +10,6 @@ struct { GskRenderer * (*create_func) (void); GskRenderer *renderer; } renderers[] = { -#if 0 - /* The GL renderer is broken, no idea why. It's suppsoed to work. */ - { - "gl", - gsk_gl_renderer_new, - }, -#endif { "cairo", gsk_cairo_renderer_new, @@ -26,8 +19,8 @@ struct { gsk_vulkan_renderer_new, }, { - "ngl", - gsk_ngl_renderer_new, + "gl", + gsk_gl_renderer_new, }, }; diff --git a/tools/gtk-rendernode-tool-benchmark.c b/tools/gtk-rendernode-tool-benchmark.c index fe4b88c81ca75b2f62c780633bb8b65e7276ef9e..884ae28357834c1439681070a907c991e376dea8 100644 --- a/tools/gtk-rendernode-tool-benchmark.c +++ b/tools/gtk-rendernode-tool-benchmark.c @@ -137,7 +137,7 @@ do_benchmark (int *argc, } if (renderers == NULL || renderers[0] == NULL) - renderers = g_strdupv ((char **) (const char *[]) { "gl", "ngl", "vulkan", "cairo", NULL }); + renderers = g_strdupv ((char **) (const char *[]) { "gl", "vulkan", "cairo", NULL }); node = load_node_file (filenames[0]); diff --git a/tools/gtk-rendernode-tool-utils.c b/tools/gtk-rendernode-tool-utils.c index deab3e36fcd59a9d0889bb6b874c88d14cd6bda8..26b0eef45983dcbbc840472f35718d0db2291cf0 100644 --- a/tools/gtk-rendernode-tool-utils.c +++ b/tools/gtk-rendernode-tool-utils.c @@ -89,11 +89,8 @@ get_renderer_for_name (const char *renderer_name) #endif else if (g_ascii_strcasecmp (renderer_name, "cairo") == 0) return gsk_cairo_renderer_new (); - else if (g_ascii_strcasecmp (renderer_name, "opengl") == 0 || - g_ascii_strcasecmp (renderer_name, "gl") == 0) + else if (g_ascii_strcasecmp (renderer_name, "gl") == 0) return gsk_gl_renderer_new (); - else if (g_ascii_strcasecmp (renderer_name, "ngl") == 0) - return gsk_ngl_renderer_new (); #ifdef GDK_RENDERING_VULKAN else if (g_ascii_strcasecmp (renderer_name, "vulkan") == 0) return gsk_vulkan_renderer_new ();