mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-28 06:21:14 +00:00
ef20b706e2
Carry an n_external_textures variable around when selecting programs and compile different programs for different amounts of external textures. For now, this code is unused, but dmabufs will need it.
299 lines
8.4 KiB
C
299 lines
8.4 KiB
C
#include "config.h"
|
|
|
|
#include "gskglimageprivate.h"
|
|
|
|
#include "gdk/gdkdisplayprivate.h"
|
|
#include "gdk/gdkglcontextprivate.h"
|
|
|
|
struct _GskGLImage
|
|
{
|
|
GskGpuImage parent_instance;
|
|
|
|
guint texture_id;
|
|
guint framebuffer_id;
|
|
|
|
GLint gl_internal_format;
|
|
GLenum gl_format;
|
|
GLenum gl_type;
|
|
|
|
guint owns_texture : 1;
|
|
};
|
|
|
|
struct _GskGLImageClass
|
|
{
|
|
GskGpuImageClass parent_class;
|
|
};
|
|
|
|
G_DEFINE_TYPE (GskGLImage, gsk_gl_image, GSK_TYPE_GPU_IMAGE)
|
|
|
|
static void
|
|
gsk_gl_image_get_projection_matrix (GskGpuImage *image,
|
|
graphene_matrix_t *out_projection)
|
|
{
|
|
GskGLImage *self = GSK_GL_IMAGE (image);
|
|
|
|
GSK_GPU_IMAGE_CLASS (gsk_gl_image_parent_class)->get_projection_matrix (image, out_projection);
|
|
|
|
if (self->texture_id == 0)
|
|
graphene_matrix_scale (out_projection, 1.f, -1.f, 1.f);
|
|
}
|
|
|
|
static void
|
|
gsk_gl_image_finalize (GObject *object)
|
|
{
|
|
GskGLImage *self = GSK_GL_IMAGE (object);
|
|
|
|
if (self->framebuffer_id)
|
|
glDeleteFramebuffers (1, &self->framebuffer_id);
|
|
|
|
if (self->owns_texture)
|
|
glDeleteTextures (1, &self->texture_id);
|
|
|
|
G_OBJECT_CLASS (gsk_gl_image_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
gsk_gl_image_class_init (GskGLImageClass *klass)
|
|
{
|
|
GskGpuImageClass *image_class = GSK_GPU_IMAGE_CLASS (klass);
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
image_class->get_projection_matrix = gsk_gl_image_get_projection_matrix;
|
|
|
|
object_class->finalize = gsk_gl_image_finalize;
|
|
}
|
|
|
|
static void
|
|
gsk_gl_image_init (GskGLImage *self)
|
|
{
|
|
}
|
|
|
|
GskGpuImage *
|
|
gsk_gl_image_new_backbuffer (GskGLDevice *device,
|
|
GdkMemoryFormat format,
|
|
gsize width,
|
|
gsize height)
|
|
{
|
|
GskGLImage *self;
|
|
GLint swizzle[4];
|
|
|
|
self = g_object_new (GSK_TYPE_GL_IMAGE, NULL);
|
|
|
|
/* We only do this so these variables get initialized */
|
|
gsk_gl_device_find_gl_format (device,
|
|
format,
|
|
&format,
|
|
&self->gl_internal_format,
|
|
&self->gl_format,
|
|
&self->gl_type,
|
|
swizzle);
|
|
|
|
gsk_gpu_image_setup (GSK_GPU_IMAGE (self), GSK_GPU_IMAGE_CAN_MIPMAP, format, width, height);
|
|
|
|
/* texture_id == 0 means backbuffer */
|
|
|
|
return GSK_GPU_IMAGE (self);
|
|
}
|
|
|
|
GskGpuImage *
|
|
gsk_gl_image_new (GskGLDevice *device,
|
|
GdkMemoryFormat format,
|
|
gsize width,
|
|
gsize height)
|
|
{
|
|
GskGLImage *self;
|
|
GLint swizzle[4];
|
|
gsize max_size;
|
|
|
|
max_size = gsk_gpu_device_get_max_image_size (GSK_GPU_DEVICE (device));
|
|
if (width > max_size || height > max_size)
|
|
return NULL;
|
|
|
|
self = g_object_new (GSK_TYPE_GL_IMAGE, NULL);
|
|
|
|
gsk_gl_device_find_gl_format (device,
|
|
format,
|
|
&format,
|
|
&self->gl_internal_format,
|
|
&self->gl_format,
|
|
&self->gl_type,
|
|
swizzle);
|
|
|
|
gsk_gpu_image_setup (GSK_GPU_IMAGE (self),
|
|
GSK_GPU_IMAGE_CAN_MIPMAP |
|
|
(gdk_memory_format_alpha (format) == GDK_MEMORY_ALPHA_STRAIGHT ? GSK_GPU_IMAGE_STRAIGHT_ALPHA : 0),
|
|
format,
|
|
width, height);
|
|
|
|
glGenTextures (1, &self->texture_id);
|
|
self->owns_texture = TRUE;
|
|
|
|
glActiveTexture (GL_TEXTURE0);
|
|
glBindTexture (GL_TEXTURE_2D, self->texture_id);
|
|
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
|
|
glTexImage2D (GL_TEXTURE_2D, 0, self->gl_internal_format, width, height, 0, self->gl_format, self->gl_type, NULL);
|
|
|
|
/* Only apply swizzle if really needed, might not even be
|
|
* supported if default values are set
|
|
*/
|
|
if (swizzle[0] != GL_RED || swizzle[1] != GL_GREEN || swizzle[2] != GL_BLUE || swizzle[3] != GL_ALPHA)
|
|
{
|
|
/* Set each channel independently since GLES 3.0 doesn't support the iv method */
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, swizzle[0]);
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, swizzle[1]);
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, swizzle[2]);
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, swizzle[3]);
|
|
}
|
|
|
|
return GSK_GPU_IMAGE (self);
|
|
}
|
|
|
|
GskGpuImage *
|
|
gsk_gl_image_new_for_texture (GskGLDevice *device,
|
|
GdkTexture *owner,
|
|
GLuint tex_id,
|
|
gboolean take_ownership,
|
|
GskGpuImageFlags extra_flags)
|
|
{
|
|
GdkMemoryFormat format;
|
|
GskGLImage *self;
|
|
GLint swizzle[4];
|
|
|
|
format = gdk_texture_get_format (owner);
|
|
|
|
self = g_object_new (GSK_TYPE_GL_IMAGE, NULL);
|
|
|
|
/* We only do this so these variables get initialized */
|
|
gsk_gl_device_find_gl_format (device,
|
|
format,
|
|
&format,
|
|
&self->gl_internal_format,
|
|
&self->gl_format,
|
|
&self->gl_type,
|
|
swizzle);
|
|
|
|
gsk_gpu_image_setup (GSK_GPU_IMAGE (self),
|
|
extra_flags |
|
|
(gdk_memory_format_alpha (format) == GDK_MEMORY_ALPHA_STRAIGHT ? GSK_GPU_IMAGE_STRAIGHT_ALPHA : 0),
|
|
format,
|
|
gdk_texture_get_width (owner),
|
|
gdk_texture_get_height (owner));
|
|
gsk_gpu_image_toggle_ref_texture (GSK_GPU_IMAGE (self), owner);
|
|
|
|
self->texture_id = tex_id;
|
|
self->owns_texture = take_ownership;
|
|
|
|
return GSK_GPU_IMAGE (self);
|
|
}
|
|
|
|
void
|
|
gsk_gl_image_bind_texture (GskGLImage *self)
|
|
{
|
|
if (gsk_gpu_image_get_flags (GSK_GPU_IMAGE (self)) & GSK_GPU_IMAGE_EXTERNAL)
|
|
glBindTexture (GL_TEXTURE_EXTERNAL_OES, self->texture_id);
|
|
else
|
|
glBindTexture (GL_TEXTURE_2D, self->texture_id);
|
|
}
|
|
|
|
void
|
|
gsk_gl_image_bind_framebuffer_target (GskGLImage *self,
|
|
GLenum target)
|
|
{
|
|
GLenum status;
|
|
|
|
if (self->framebuffer_id)
|
|
{
|
|
glBindFramebuffer (target, self->framebuffer_id);
|
|
return;
|
|
}
|
|
|
|
/* We're the renderbuffer */
|
|
if (self->texture_id == 0)
|
|
{
|
|
glBindFramebuffer (target, 0);
|
|
return;
|
|
}
|
|
|
|
glGenFramebuffers (1, &self->framebuffer_id);
|
|
glBindFramebuffer (target, self->framebuffer_id);
|
|
glFramebufferTexture2D (target, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->texture_id, 0);
|
|
status = glCheckFramebufferStatus (target);
|
|
|
|
switch (status)
|
|
{
|
|
case GL_FRAMEBUFFER_COMPLETE:
|
|
break;
|
|
|
|
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
|
g_critical ("glCheckFramebufferStatus() returned GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT. Expect broken rendering.");
|
|
break;
|
|
|
|
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
|
|
g_critical ("glCheckFramebufferStatus() returned GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS. Expect broken rendering.");
|
|
break;
|
|
|
|
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
|
|
g_critical ("glCheckFramebufferStatus() returned GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT. Expect broken rendering.");
|
|
break;
|
|
|
|
case GL_FRAMEBUFFER_UNSUPPORTED:
|
|
g_critical ("glCheckFramebufferStatus() returned GL_FRAMEBUFFER_UNSUPPORTED. Expect broken rendering.");
|
|
break;
|
|
|
|
default:
|
|
g_critical ("glCheckFramebufferStatus() returned %u (0x%x). Expect broken rendering.", status, status);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
gsk_gl_image_bind_framebuffer (GskGLImage *self)
|
|
{
|
|
gsk_gl_image_bind_framebuffer_target (self, GL_FRAMEBUFFER);
|
|
}
|
|
|
|
gboolean
|
|
gsk_gl_image_is_flipped (GskGLImage *self)
|
|
{
|
|
return self->texture_id == 0;
|
|
}
|
|
|
|
GLint
|
|
gsk_gl_image_get_gl_internal_format (GskGLImage *self)
|
|
{
|
|
return self->gl_internal_format;
|
|
}
|
|
|
|
GLenum
|
|
gsk_gl_image_get_gl_format (GskGLImage *self)
|
|
{
|
|
return self->gl_format;
|
|
}
|
|
|
|
GLenum
|
|
gsk_gl_image_get_gl_type (GskGLImage *self)
|
|
{
|
|
return self->gl_type;
|
|
}
|
|
|
|
GLuint
|
|
gsk_gl_image_steal_texture (GskGLImage *self)
|
|
{
|
|
g_assert (self->owns_texture);
|
|
|
|
if (self->framebuffer_id)
|
|
{
|
|
glDeleteFramebuffers (1, &self->framebuffer_id);
|
|
self->framebuffer_id = 0;
|
|
}
|
|
|
|
self->owns_texture = FALSE;
|
|
|
|
return self->texture_id;
|
|
}
|