Compare commits
4 Commits
wip/antoni
...
drop-gl-re
Author | SHA1 | Date | |
---|---|---|---|
|
6c5e8515b7 | ||
|
37c24ba186 | ||
|
0dcb35047e | ||
|
971ee42321 |
@@ -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 (),
|
||||
|
@@ -231,7 +231,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);
|
||||
@@ -275,7 +274,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))
|
||||
{
|
||||
|
@@ -1,116 +0,0 @@
|
||||
/* gskglattachmentstate.c
|
||||
*
|
||||
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
}
|
@@ -1,102 +0,0 @@
|
||||
/* gskglattachmentstateprivate.h
|
||||
*
|
||||
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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
|
||||
|
@@ -1,69 +0,0 @@
|
||||
/* gskglbufferprivate.h
|
||||
*
|
||||
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#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);
|
||||
}
|
@@ -1,80 +0,0 @@
|
||||
/* gskglbufferprivate.h
|
||||
*
|
||||
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,431 +0,0 @@
|
||||
/* gskglcommandqueueprivate.h
|
||||
*
|
||||
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gsk/gskprofilerprivate.h>
|
||||
|
||||
#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
|
||||
|
@@ -1,703 +0,0 @@
|
||||
/* gskglcompiler.c
|
||||
*
|
||||
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gsk/gskdebugprivate.h>
|
||||
#include <gio/gio.h>
|
||||
#include <string.h>
|
||||
|
||||
#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);
|
||||
}
|
@@ -1,68 +0,0 @@
|
||||
/* gskglcompilerprivate.h
|
||||
*
|
||||
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#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
|
||||
|
1867
gsk/gl/gskgldriver.c
1867
gsk/gl/gskgldriver.c
File diff suppressed because it is too large
Load Diff
@@ -1,261 +0,0 @@
|
||||
/* gskgldriverprivate.h
|
||||
*
|
||||
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gdk/gdkgltextureprivate.h>
|
||||
|
||||
#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
|
||||
|
@@ -1,439 +0,0 @@
|
||||
/* gskglglyphlibrary.c
|
||||
*
|
||||
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gdk/gdkglcontextprivate.h>
|
||||
#include <gdk/gdkmemoryformatprivate.h>
|
||||
#include <gdk/gdkprofilerprivate.h>
|
||||
|
||||
#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;
|
||||
}
|
@@ -1,103 +0,0 @@
|
||||
/* gskglglyphlibraryprivate.h
|
||||
*
|
||||
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <pango/pango.h>
|
||||
|
||||
#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
|
||||
|
@@ -1,212 +0,0 @@
|
||||
/* gskgliconlibrary.c
|
||||
*
|
||||
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gdk/gdkglcontextprivate.h>
|
||||
#include <gdk/gdkmemoryformatprivate.h>
|
||||
#include <gdk/gdkprofilerprivate.h>
|
||||
#include <gdk/gdktextureprivate.h>
|
||||
#include <gdk/gdktexturedownloaderprivate.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
}
|
@@ -1,58 +0,0 @@
|
||||
/* gskgliconlibraryprivate.h
|
||||
*
|
||||
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <pango/pango.h>
|
||||
|
||||
#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
|
||||
|
@@ -1,179 +0,0 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gskglprofilerprivate.h"
|
||||
|
||||
#include <epoxy/gl.h>
|
||||
|
||||
#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 */
|
||||
}
|
@@ -1,16 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gsk/gsktypes.h>
|
||||
|
||||
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
|
||||
|
@@ -1,173 +0,0 @@
|
||||
/* gskglprogram.c
|
||||
*
|
||||
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gskglcommandqueueprivate.h"
|
||||
#include "gskglprogramprivate.h"
|
||||
#include "gskgluniformstateprivate.h"
|
||||
|
||||
G_DEFINE_TYPE (GskGLProgram, gsk_gl_program, G_TYPE_OBJECT)
|
||||
|
||||
GskGLProgram *
|
||||
gsk_gl_program_new (GskGLDriver *driver,
|
||||
const char *name,
|
||||
int program_id)
|
||||
{
|
||||
GskGLProgram *self;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_GL_DRIVER (driver), NULL);
|
||||
g_return_val_if_fail (program_id >= -1, NULL);
|
||||
|
||||
self = g_object_new (GSK_TYPE_GL_PROGRAM, NULL);
|
||||
self->id = program_id;
|
||||
self->name = g_strdup (name);
|
||||
self->driver = g_object_ref (driver);
|
||||
self->n_mappings = 0;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_program_finalize (GObject *object)
|
||||
{
|
||||
GskGLProgram *self = (GskGLProgram *)object;
|
||||
|
||||
if (self->id >= 0)
|
||||
g_warning ("Leaking GLSL program %d (%s)",
|
||||
self->id,
|
||||
self->name ? self->name : "");
|
||||
|
||||
g_clear_pointer (&self->name, g_free);
|
||||
g_clear_object (&self->driver);
|
||||
|
||||
G_OBJECT_CLASS (gsk_gl_program_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_program_class_init (GskGLProgramClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = gsk_gl_program_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_program_init (GskGLProgram *self)
|
||||
{
|
||||
self->id = -1;
|
||||
|
||||
for (guint i = 0; i < G_N_ELEMENTS (self->mappings); i++)
|
||||
self->mappings[i].location = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_gl_program_add_uniform:
|
||||
* @self: a `GskGLProgram`
|
||||
* @name: the name of the uniform such as "u_source"
|
||||
* @key: the identifier to use for the uniform
|
||||
*
|
||||
* This method will create a mapping between @key and the location
|
||||
* of the uniform on the GPU. This simplifies calling code to not
|
||||
* need to know where the uniform location is and only register it
|
||||
* when creating the program.
|
||||
*
|
||||
* You might use this with an enum of all your uniforms for the
|
||||
* program and then register each of them like:
|
||||
*
|
||||
* ```
|
||||
* gsk_gl_program_add_uniform (program, "u_source", UNIFORM_SOURCE);
|
||||
* ```
|
||||
*
|
||||
* That allows you to set values for the program with something
|
||||
* like the following:
|
||||
*
|
||||
* ```
|
||||
* gsk_gl_program_set_uniform1i (program, UNIFORM_SOURCE, 1);
|
||||
* ```
|
||||
*
|
||||
* Returns: %TRUE if the uniform was found; otherwise %FALSE
|
||||
*/
|
||||
gboolean
|
||||
gsk_gl_program_add_uniform (GskGLProgram *self,
|
||||
const char *name,
|
||||
guint key)
|
||||
{
|
||||
GLint location;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_GL_PROGRAM (self), FALSE);
|
||||
g_return_val_if_fail (name != NULL, FALSE);
|
||||
g_return_val_if_fail (key < G_N_ELEMENTS (self->mappings), FALSE);
|
||||
|
||||
location = glGetUniformLocation (self->id, name);
|
||||
|
||||
/* Register the information even if unused */
|
||||
self->mappings[key].name = g_intern_string (name);
|
||||
self->mappings[key].location = location;
|
||||
if (key >= self->n_mappings)
|
||||
self->n_mappings = key + 1;
|
||||
|
||||
#if 0
|
||||
g_print ("program [%d] %s uniform %s [%u of %u] at location %d.\n",
|
||||
self->id, self->name, name, key, self->n_mappings, location);
|
||||
#endif
|
||||
|
||||
return location > -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_gl_program_delete:
|
||||
* @self: a `GskGLProgram`
|
||||
*
|
||||
* Deletes the GLSL program.
|
||||
*/
|
||||
void
|
||||
gsk_gl_program_delete (GskGLProgram *self)
|
||||
{
|
||||
g_return_if_fail (GSK_IS_GL_PROGRAM (self));
|
||||
g_return_if_fail (self->driver->command_queue != NULL);
|
||||
|
||||
gsk_gl_command_queue_delete_program (self->driver->command_queue, self->id);
|
||||
self->id = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_gl_program_uniforms_added:
|
||||
* @self: a `GskGLProgram`
|
||||
* @has_attachments: if any uniform is for a bind/texture attachment
|
||||
*
|
||||
* This function should be called after all of the uniforms 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;
|
||||
}
|
@@ -1,318 +0,0 @@
|
||||
/* gskglprogramprivate.h
|
||||
*
|
||||
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#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
|
||||
|
@@ -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)
|
@@ -1,489 +0,0 @@
|
||||
/* gskglrenderer.c
|
||||
*
|
||||
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 <gdk/gdkprofilerprivate.h>
|
||||
#include <gdk/gdkdisplayprivate.h>
|
||||
#include <gdk/gdkdmabufdownloaderprivate.h>
|
||||
#include <gdk/gdkdmabuftextureprivate.h>
|
||||
#include <gdk/gdkglcontextprivate.h>
|
||||
#include <gdk/gdksurfaceprivate.h>
|
||||
#include <gdk/gdksubsurfaceprivate.h>
|
||||
#include <glib/gi18n-lib.h>
|
||||
#include <gsk/gskdebugprivate.h>
|
||||
#include <gsk/gskrendererprivate.h>
|
||||
#include <gsk/gskrendernodeprivate.h>
|
||||
#include <gsk/gskroundedrectprivate.h>
|
||||
#include <gsk/gskrectprivate.h>
|
||||
|
||||
/**
|
||||
* 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
|
@@ -20,35 +20,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined (__GSK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#warning "#include <gsk/gsk.h> instead of <gsk/gl/gskglrenderer.h> to avoid this warning"
|
||||
|
||||
#include <gsk/gsk.h>
|
||||
#define GSK_INCLUDE_WARNING(x) GDK_DEPRECATED_IN_4_14_FOR("#include <gsk/gsk.h> instead of <gsk/gl/gskglrenderer.h> to avoid this warning")
|
||||
#else
|
||||
#include <gsk/gsktypes.h>
|
||||
#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
|
||||
|
||||
|
@@ -1,38 +0,0 @@
|
||||
/* gskglrendererprivate.h
|
||||
*
|
||||
* Copyright 2021 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#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
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,36 +0,0 @@
|
||||
/* gskglrenderjobprivate.h
|
||||
*
|
||||
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#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);
|
||||
|
@@ -1,256 +0,0 @@
|
||||
/* gskglshadowlibrary.c
|
||||
*
|
||||
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#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--;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,42 +0,0 @@
|
||||
/* gskglshadowlibraryprivate.h
|
||||
*
|
||||
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#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
|
||||
|
@@ -1,95 +0,0 @@
|
||||
/* gskgltexture.c
|
||||
*
|
||||
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gdk/gdktextureprivate.h>
|
||||
|
||||
#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;
|
||||
}
|
@@ -1,583 +0,0 @@
|
||||
/* gskgltexturelibrary.c
|
||||
*
|
||||
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gdk/gdkglcontextprivate.h>
|
||||
#include <gsk/gskdebugprivate.h>
|
||||
|
||||
#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);
|
||||
}
|
@@ -1,232 +0,0 @@
|
||||
/* gskgltexturelibraryprivate.h
|
||||
*
|
||||
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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
|
||||
|
@@ -1,93 +0,0 @@
|
||||
/* gskgltextureprivate.h
|
||||
*
|
||||
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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
|
||||
|
@@ -1,64 +0,0 @@
|
||||
/* gskgltypesprivate.h
|
||||
*
|
||||
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <epoxy/gl.h>
|
||||
#include <graphene.h>
|
||||
#include <gdk/gdk.h>
|
||||
#include <gsk/gsk.h>
|
||||
|
||||
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
|
||||
|
@@ -1,269 +0,0 @@
|
||||
/* gskgluniformstate.c
|
||||
*
|
||||
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gsk/gskroundedrectprivate.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
@@ -1,834 +0,0 @@
|
||||
/* gskgluniformstateprivate.h
|
||||
*
|
||||
* Copyright 2020 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#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
|
||||
|
@@ -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]; \
|
||||
}
|
||||
|
@@ -1,308 +0,0 @@
|
||||
/* ninesliceprivate.h
|
||||
*
|
||||
* Copyright 2017 Timm Bäder <mail@baedert.org>
|
||||
* Copyright 2021 Christian Hergert <chergert@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#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
|
||||
|
@@ -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 = lum (c);
|
||||
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);
|
||||
}
|
@@ -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);
|
||||
}
|
@@ -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);
|
||||
}
|
@@ -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);
|
||||
}
|
@@ -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);
|
||||
}
|
||||
|
@@ -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));
|
||||
}
|
@@ -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));
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
@@ -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);
|
||||
}
|
@@ -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);
|
||||
}
|
@@ -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));
|
||||
}
|
@@ -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);
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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));
|
||||
}
|
@@ -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);
|
||||
}
|
@@ -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
|
||||
}
|
@@ -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);
|
||||
}
|
@@ -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
|
@@ -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);
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
@@ -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);
|
||||
}
|
||||
|
@@ -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 <stdlib.h>
|
||||
#define STBRP_SORT qsort
|
||||
#endif
|
||||
|
||||
#ifndef STBRP_ASSERT
|
||||
#include <assert.h>
|
||||
#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.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
@@ -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
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gsknglrendererprivate.h"
|
||||
#include "gskglrenderer.h"
|
||||
|
||||
#include "gskgpuimageprivate.h"
|
||||
#include "gskgpurendererprivate.h"
|
||||
@@ -15,7 +15,7 @@
|
||||
#include <glib/gi18n-lib.h>
|
||||
|
||||
/**
|
||||
* 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;
|
||||
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_ngl_renderer_unrealize;
|
||||
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 new GL renderer
|
||||
* Returns: (transfer full): a 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
|
||||
}
|
49
gsk/gpu/gskglrenderer.h
Normal file
49
gsk/gpu/gskglrenderer.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gdk/gdk.h>
|
||||
#include <gsk/gsk.h>
|
||||
|
||||
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
|
||||
|
@@ -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
|
||||
|
@@ -32,8 +32,8 @@
|
||||
#include <gsk/gskglshader.h>
|
||||
|
||||
#include <gsk/gskcairorenderer.h>
|
||||
#include <gsk/gl/gskglrenderer.h>
|
||||
#include <gsk/gpu/gskvulkanrenderer.h>
|
||||
#include <gsk/gpu/gskglrenderer.h>
|
||||
|
||||
#include <gsk/gsktypes.h>
|
||||
#include <gsk/gskenumtypes.h>
|
||||
|
@@ -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"
|
||||
@@ -529,11 +529,8 @@ 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)
|
||||
return GSK_TYPE_GL_RENDERER;
|
||||
else if (g_ascii_strcasecmp (renderer_name, "ngl") == 0)
|
||||
return gsk_ngl_renderer_get_type ();
|
||||
return GSK_TYPE_GL_RENDERER;
|
||||
#ifdef GDK_RENDERING_VULKAN
|
||||
else if (g_ascii_strcasecmp (renderer_name, "vulkan") == 0)
|
||||
return GSK_TYPE_VULKAN_RENDERER;
|
||||
@@ -641,19 +638,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
|
||||
|
@@ -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"
|
||||
@@ -8160,7 +8160,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);
|
||||
|
@@ -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',
|
||||
@@ -135,11 +93,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
|
||||
@@ -181,7 +138,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,
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -215,7 +215,6 @@ informative_render_tests = [
|
||||
]
|
||||
|
||||
renderers = [
|
||||
{ 'name': 'gl' },
|
||||
{ 'name': 'broadway' },
|
||||
{ 'name': 'cairo' },
|
||||
{ 'name': 'ngl' },
|
||||
|
@@ -203,12 +203,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
|
||||
@@ -242,7 +242,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 ();
|
||||
|
@@ -6,7 +6,7 @@ static void
|
||||
test_normalize (GskRenderNode *node1,
|
||||
GskRenderNode *node2)
|
||||
{
|
||||
GskRenderer *renderer = gsk_ngl_renderer_new ();
|
||||
GskRenderer *renderer = gsk_gl_renderer_new ();
|
||||
graphene_rect_t bounds1, bounds2;
|
||||
GdkTexture *texture1, *texture2, *diff;
|
||||
GError *error = NULL;
|
||||
|
@@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
|
@@ -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]);
|
||||
|
||||
|
@@ -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 ();
|
||||
|
Reference in New Issue
Block a user