Compare commits
8 Commits
ebassi/css
...
dmabug-tex
Author | SHA1 | Date | |
---|---|---|---|
|
b27592c6d1 | ||
|
c362840b3f | ||
|
ea98ea1217 | ||
|
e6b11c8668 | ||
|
2a3fdf78d7 | ||
|
a8a0292f20 | ||
|
e83dcc4cab | ||
|
4957bed573 |
@@ -43,6 +43,11 @@
|
||||
#ifdef HAVE_EGL
|
||||
#include <epoxy/egl.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LINUX_DMA_BUF_H
|
||||
#include <drm/drm_fourcc.h>
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -1769,6 +1774,8 @@ gdk_display_init_egl (GdkDisplay *self,
|
||||
epoxy_has_egl_extension (priv->egl_display, "EGL_KHR_no_config_context");
|
||||
self->have_egl_pixel_format_float =
|
||||
epoxy_has_egl_extension (priv->egl_display, "EGL_EXT_pixel_format_float");
|
||||
self->have_egl_dma_buf_import =
|
||||
epoxy_has_egl_extension (priv->egl_display, "EGL_EXT_image_dma_buf_import_modifiers");
|
||||
|
||||
if (self->have_egl_no_config_context)
|
||||
priv->egl_config_high_depth = gdk_display_create_egl_config (self,
|
||||
@@ -1856,17 +1863,77 @@ gdk_display_get_egl_display (GdkDisplay *self)
|
||||
static void
|
||||
init_dmabuf_formats (GdkDisplay *display)
|
||||
{
|
||||
GdkDmabufFormat *formats;
|
||||
gsize n_formats;
|
||||
GdkDisplayPrivate *priv = gdk_display_get_instance_private (display);
|
||||
|
||||
if (display->dmabuf_formats != NULL)
|
||||
return;
|
||||
|
||||
gdk_display_prepare_gl (display, NULL);
|
||||
|
||||
formats = gdk_dmabuf_texture_get_supported_formats (&n_formats);
|
||||
display->dmabuf_formats = gdk_dmabuf_formats_new (formats, n_formats);
|
||||
g_free (formats);
|
||||
gdk_gl_context_make_current (priv->gl_context);
|
||||
|
||||
#ifdef HAVE_EGL
|
||||
if (priv->egl_display != EGL_NO_DISPLAY &&
|
||||
display->have_egl_dma_buf_import)
|
||||
{
|
||||
int num_formats;
|
||||
int *formats;
|
||||
GArray *array;
|
||||
|
||||
eglQueryDmaBufFormatsEXT (priv->egl_display, 0, NULL, &num_formats);
|
||||
formats = g_new (int, num_formats);
|
||||
eglQueryDmaBufFormatsEXT (priv->egl_display, num_formats, formats, &num_formats);
|
||||
|
||||
array = g_array_new (FALSE, FALSE, sizeof (GdkDmabufFormat));
|
||||
|
||||
for (int i = 0; i < num_formats; i++)
|
||||
{
|
||||
int num_modifiers;
|
||||
uint64_t *modifiers;
|
||||
unsigned int *external_only;
|
||||
|
||||
// if (!gdk_dmabuf_texture_may_support ((unsigned int)formats[i]))
|
||||
// continue;
|
||||
|
||||
eglQueryDmaBufModifiersEXT (priv->egl_display, formats[i], 0, NULL, NULL, &num_modifiers);
|
||||
modifiers = g_new (uint64_t, num_modifiers);
|
||||
external_only = g_new (unsigned int, num_modifiers);
|
||||
eglQueryDmaBufModifiersEXT (priv->egl_display, formats[i], num_modifiers, modifiers, external_only, &num_modifiers);
|
||||
|
||||
for (int j = 0; j < num_modifiers; j++)
|
||||
{
|
||||
if (1 || !external_only[j])
|
||||
{
|
||||
GDK_DEBUG (MISC, "supported EGL dmabuf format %c%c%c%c:%#lx %s",
|
||||
formats[i] & 0xff,
|
||||
(formats[i] >> 8) & 0xff,
|
||||
(formats[i] >> 16) & 0xff,
|
||||
(formats[i] >> 24) & 0xff,
|
||||
modifiers[j],
|
||||
external_only[j] ? "EXT" : "");
|
||||
g_array_append_val (array, ((GdkDmabufFormat){ formats[i], modifiers[j] }));
|
||||
}
|
||||
}
|
||||
g_array_append_val (array, ((GdkDmabufFormat){ formats[i], DRM_FORMAT_MOD_INVALID }));
|
||||
|
||||
g_free (modifiers);
|
||||
}
|
||||
|
||||
g_free (formats);
|
||||
|
||||
display->dmabuf_formats = gdk_dmabuf_formats_new ((GdkDmabufFormat *)array->data, array->len);
|
||||
g_array_free (array, TRUE);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
GdkDmabufFormat *formats;
|
||||
gsize n_formats;
|
||||
|
||||
formats = gdk_dmabuf_texture_get_supported_formats (&n_formats);
|
||||
display->dmabuf_formats = gdk_dmabuf_formats_new (formats, n_formats);
|
||||
g_free (formats);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -114,6 +114,7 @@ struct _GdkDisplay
|
||||
guint have_egl_buffer_age : 1;
|
||||
guint have_egl_no_config_context : 1;
|
||||
guint have_egl_pixel_format_float : 1;
|
||||
guint have_egl_dma_buf_import : 1;
|
||||
|
||||
GdkDmabufFormats *dmabuf_formats;
|
||||
};
|
||||
|
@@ -35,6 +35,15 @@
|
||||
#include <epoxy/egl.h>
|
||||
#endif
|
||||
|
||||
/* We don't include gsk/gsk.h here to avoid a build order problem
|
||||
* with the generated header gskenumtypes.h
|
||||
*/
|
||||
#include <gsk/gskenums.h>
|
||||
#include <gsk/gsktypes.h>
|
||||
#include <gsk/gskrenderer.h>
|
||||
#include <gsk/gskrendernode.h>
|
||||
#include <gsk/gl/gskglrenderer.h>
|
||||
|
||||
/**
|
||||
* GdkDmabufTexture:
|
||||
*
|
||||
@@ -150,15 +159,16 @@ struct _GdkDrmFormatInfo
|
||||
guint32 fourcc;
|
||||
GdkMemoryFormat premultiplied_memory_format;
|
||||
GdkMemoryFormat unpremultiplied_memory_format;
|
||||
gboolean requires_gl;
|
||||
};
|
||||
|
||||
static GdkDrmFormatInfo supported_formats[] = {
|
||||
{ DRM_FORMAT_ARGB8888, GDK_MEMORY_A8R8G8B8_PREMULTIPLIED, GDK_MEMORY_A8R8G8B8 },
|
||||
{ DRM_FORMAT_RGBA8888, GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, GDK_MEMORY_R8G8B8A8 },
|
||||
{ DRM_FORMAT_BGRA8888, GDK_MEMORY_B8G8R8A8_PREMULTIPLIED, GDK_MEMORY_B8G8R8A8 },
|
||||
{ DRM_FORMAT_ABGR16161616F, GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED, GDK_MEMORY_R16G16B16A16_FLOAT },
|
||||
{ DRM_FORMAT_RGB888, GDK_MEMORY_R8G8B8, GDK_MEMORY_R8G8B8 },
|
||||
{ DRM_FORMAT_BGR888, GDK_MEMORY_B8G8R8, GDK_MEMORY_B8G8R8 },
|
||||
{ DRM_FORMAT_ARGB8888, GDK_MEMORY_A8R8G8B8_PREMULTIPLIED, GDK_MEMORY_A8R8G8B8, FALSE },
|
||||
{ DRM_FORMAT_RGBA8888, GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, GDK_MEMORY_R8G8B8A8, FALSE },
|
||||
{ DRM_FORMAT_BGRA8888, GDK_MEMORY_B8G8R8A8_PREMULTIPLIED, GDK_MEMORY_B8G8R8A8, FALSE },
|
||||
{ DRM_FORMAT_ABGR16161616F, GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED, GDK_MEMORY_R16G16B16A16_FLOAT, FALSE },
|
||||
{ DRM_FORMAT_RGB888, GDK_MEMORY_R8G8B8, GDK_MEMORY_R8G8B8, FALSE },
|
||||
{ DRM_FORMAT_BGR888, GDK_MEMORY_B8G8R8, GDK_MEMORY_B8G8R8, FALSE },
|
||||
};
|
||||
|
||||
static GdkDrmFormatInfo *
|
||||
@@ -173,6 +183,53 @@ get_drm_format_info (guint32 fourcc)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
do_indirect_download (GdkDmabufTexture *self,
|
||||
GdkMemoryFormat format,
|
||||
guchar *data,
|
||||
gsize stride)
|
||||
{
|
||||
GskRenderer *renderer;
|
||||
int width, height;
|
||||
GskRenderNode *node;
|
||||
GdkTexture *gl_texture;
|
||||
GdkTextureDownloader *downloader;
|
||||
GError *error = NULL;
|
||||
|
||||
GDK_DEBUG (MISC, "Using gsk_renderer_render_texture import for downloading a dmabuf");
|
||||
|
||||
g_assert (GDK_IS_DISPLAY (self->display));
|
||||
g_assert (GDK_IS_GL_CONTEXT (gdk_display_get_gl_context (self->display)));
|
||||
|
||||
renderer = gsk_gl_renderer_new ();
|
||||
if (!gsk_renderer_realize (renderer, NULL, &error))
|
||||
{
|
||||
g_warning ("Failed to realize GL renderer: %s", error->message);
|
||||
g_error_free (error);
|
||||
g_object_unref (renderer);
|
||||
return;
|
||||
}
|
||||
|
||||
width = gdk_texture_get_width (GDK_TEXTURE (self));
|
||||
height = gdk_texture_get_height (GDK_TEXTURE (self));
|
||||
|
||||
node = gsk_texture_node_new (GDK_TEXTURE (self), &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
gl_texture = gsk_renderer_render_texture (renderer, node, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
gsk_render_node_unref (node);
|
||||
|
||||
gsk_renderer_unrealize (renderer);
|
||||
g_object_unref (renderer);
|
||||
|
||||
downloader = gdk_texture_downloader_new (gl_texture);
|
||||
|
||||
gdk_texture_downloader_set_format (downloader, format);
|
||||
|
||||
gdk_texture_downloader_download_into (downloader, data, stride);
|
||||
|
||||
gdk_texture_downloader_free (downloader);
|
||||
g_object_unref (gl_texture);
|
||||
}
|
||||
|
||||
static void
|
||||
do_direct_download (GdkDmabufTexture *self,
|
||||
guchar *data,
|
||||
@@ -239,6 +296,22 @@ gdk_dmabuf_texture_get_supported_formats (gsize *n_formats)
|
||||
#endif
|
||||
}
|
||||
|
||||
gboolean
|
||||
gdk_dmabuf_texture_may_support (guint32 fourcc)
|
||||
{
|
||||
#ifdef HAVE_LINUX_DMA_BUF_H
|
||||
|
||||
for (gsize i = 0; i < G_N_ELEMENTS (supported_formats); i++)
|
||||
{
|
||||
if (supported_formats[i].fourcc == fourcc)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_dmabuf_texture_download (GdkTexture *texture,
|
||||
GdkMemoryFormat format,
|
||||
@@ -248,8 +321,15 @@ gdk_dmabuf_texture_download (GdkTexture *texture,
|
||||
#ifdef HAVE_LINUX_DMA_BUF_H
|
||||
GdkDmabufTexture *self = GDK_DMABUF_TEXTURE (texture);
|
||||
GdkMemoryFormat src_format = gdk_texture_get_format (texture);
|
||||
GdkDrmFormatInfo *info;
|
||||
|
||||
if (format == src_format)
|
||||
info = get_drm_format_info (self->fourcc);
|
||||
|
||||
g_assert (info != NULL);
|
||||
|
||||
if (info->requires_gl || self->n_planes > 1 || self->modifier != DRM_FORMAT_MOD_LINEAR)
|
||||
do_indirect_download (self, format, data, stride);
|
||||
else if (format == src_format)
|
||||
do_direct_download (self, data, stride);
|
||||
else
|
||||
{
|
||||
@@ -274,6 +354,21 @@ gdk_dmabuf_texture_download (GdkTexture *texture,
|
||||
#endif /* HAVE_LINUX_DMA_BUF_H */
|
||||
}
|
||||
|
||||
static gboolean
|
||||
display_supports_format (GdkDisplay *display,
|
||||
guint32 fourcc,
|
||||
guint64 modifier)
|
||||
{
|
||||
GdkDmabufFormats *formats;
|
||||
|
||||
if (!display)
|
||||
return FALSE;
|
||||
|
||||
formats = gdk_display_get_dmabuf_formats (display);
|
||||
|
||||
return gdk_dmabuf_formats_contains (formats, fourcc, modifier);
|
||||
}
|
||||
|
||||
GdkTexture *
|
||||
gdk_dmabuf_texture_new_from_builder (GdkDmabufTextureBuilder *builder,
|
||||
GDestroyNotify destroy,
|
||||
@@ -291,7 +386,7 @@ gdk_dmabuf_texture_new_from_builder (GdkDmabufTextureBuilder *builder,
|
||||
|
||||
info = get_drm_format_info (fourcc);
|
||||
|
||||
if (!info || modifier != DRM_FORMAT_MOD_LINEAR || n_planes > 1)
|
||||
if ((!info || info->requires_gl || n_planes > 1 || modifier != DRM_FORMAT_MOD_LINEAR) && !display_supports_format (display, fourcc, modifier))
|
||||
{
|
||||
g_warning ("Unsupported dmabuf format %c%c%c%c:%#lx",
|
||||
fourcc & 0xff, (fourcc >> 8) & 0xff, (fourcc >> 16) & 0xff, (fourcc >> 24) & 0xff, modifier);
|
||||
@@ -309,8 +404,11 @@ gdk_dmabuf_texture_new_from_builder (GdkDmabufTextureBuilder *builder,
|
||||
self->destroy = destroy;
|
||||
self->data = data;
|
||||
|
||||
GDK_TEXTURE (self)->format = premultiplied ? info->premultiplied_memory_format
|
||||
: info->unpremultiplied_memory_format;
|
||||
if (info)
|
||||
GDK_TEXTURE (self)->format = premultiplied ? info->premultiplied_memory_format
|
||||
: info->unpremultiplied_memory_format;
|
||||
else
|
||||
GDK_TEXTURE (self)->format = premultiplied ? GDK_MEMORY_A8R8G8B8_PREMULTIPLIED : GDK_MEMORY_A8R8G8B8;
|
||||
|
||||
g_set_object (&self->display, display);
|
||||
|
||||
|
@@ -26,7 +26,8 @@ int * gdk_dmabuf_texture_get_fds (GdkDmabufTexture *textu
|
||||
unsigned int * gdk_dmabuf_texture_get_offsets (GdkDmabufTexture *texture);
|
||||
unsigned int * gdk_dmabuf_texture_get_strides (GdkDmabufTexture *texture);
|
||||
|
||||
GdkDmabufFormat * gdk_dmabuf_texture_get_supported_formats (gsize *n_formats);
|
||||
GdkDmabufFormat * gdk_dmabuf_texture_get_supported_formats (gsize *n_formats);
|
||||
gboolean gdk_dmabuf_texture_may_support (guint32 fourcc);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
@@ -76,7 +76,8 @@ gsk_gl_attachment_state_bind_texture (GskGLAttachmentState *self,
|
||||
g_assert (self != NULL);
|
||||
g_assert (target == GL_TEXTURE_1D ||
|
||||
target == GL_TEXTURE_2D ||
|
||||
target == GL_TEXTURE_3D);
|
||||
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));
|
||||
|
||||
|
@@ -282,7 +282,10 @@ snapshot_attachments (const GskGLAttachmentState *state,
|
||||
{
|
||||
bind[count].id = state->textures[i].id;
|
||||
bind[count].texture = state->textures[i].texture;
|
||||
bind[count].sampler = state->textures[i].sampler;
|
||||
if (state->textures[i].target == GL_TEXTURE_EXTERNAL_OES)
|
||||
bind[count].sampler = 15;
|
||||
else
|
||||
bind[count].sampler = state->textures[i].sampler;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
@@ -1190,12 +1193,23 @@ gsk_gl_command_queue_execute (GskGLCommandQueue *self,
|
||||
s->sync = NULL;
|
||||
}
|
||||
|
||||
glBindTexture (GL_TEXTURE_2D, bind->id);
|
||||
if (bind->sampler == 15)
|
||||
glBindTexture (GL_TEXTURE_EXTERNAL_OES, bind->id);
|
||||
else
|
||||
glBindTexture (GL_TEXTURE_2D, bind->id);
|
||||
textures[bind->texture] = bind->id;
|
||||
if (!self->has_samplers)
|
||||
{
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter_from_index (bind->sampler / GSK_GL_N_FILTERS));
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter_from_index (bind->sampler % GSK_GL_N_FILTERS));
|
||||
if (bind->sampler == 15)
|
||||
{
|
||||
glTexParameteri (GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri (GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter_from_index (bind->sampler / GSK_GL_N_FILTERS));
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter_from_index (bind->sampler % GSK_GL_N_FILTERS));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1205,8 +1219,16 @@ gsk_gl_command_queue_execute (GskGLCommandQueue *self,
|
||||
glBindSampler (bind->texture, self->samplers[bind->sampler]);
|
||||
else
|
||||
{
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter_from_index (bind->sampler / GSK_GL_N_FILTERS));
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter_from_index (bind->sampler % GSK_GL_N_FILTERS));
|
||||
if (bind->sampler == 15)
|
||||
{
|
||||
glTexParameteri (GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri (GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter_from_index (bind->sampler / GSK_GL_N_FILTERS));
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter_from_index (bind->sampler % GSK_GL_N_FILTERS));
|
||||
}
|
||||
}
|
||||
samplers[bind->texture] = bind->sampler;
|
||||
}
|
||||
@@ -1324,7 +1346,7 @@ gsk_gl_command_queue_end_frame (GskGLCommandQueue *self)
|
||||
if (self->attachments->textures[i].id != 0)
|
||||
{
|
||||
glActiveTexture (GL_TEXTURE0 + i);
|
||||
glBindTexture (GL_TEXTURE_2D, 0);
|
||||
glBindTexture (self->attachments->textures[i].target, 0);
|
||||
|
||||
self->attachments->textures[i].id = 0;
|
||||
self->attachments->textures[i].changed = FALSE;
|
||||
@@ -1401,7 +1423,7 @@ gsk_gl_command_queue_create_texture (GskGLCommandQueue *self,
|
||||
|
||||
glActiveTexture (GL_TEXTURE0);
|
||||
glBindTexture (GL_TEXTURE_2D, texture_id);
|
||||
|
||||
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
@@ -1429,8 +1451,10 @@ gsk_gl_command_queue_create_texture (GskGLCommandQueue *self,
|
||||
}
|
||||
|
||||
/* Restore the previous texture if it was set */
|
||||
if (self->attachments->textures[0].id != 0)
|
||||
glBindTexture (GL_TEXTURE_2D, self->attachments->textures[0].id);
|
||||
if (self->attachments->textures[0].id != 0 &&
|
||||
self->attachments->textures[0].target == GL_TEXTURE_2D)
|
||||
glBindTexture (self->attachments->textures[0].target,
|
||||
self->attachments->textures[0].id);
|
||||
|
||||
return (int)texture_id;
|
||||
}
|
||||
|
@@ -54,6 +54,7 @@ typedef struct _GskGLCommandBind
|
||||
*/
|
||||
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(). */
|
||||
|
@@ -56,6 +56,7 @@ struct _GskGLCompiler
|
||||
guint gles : 1;
|
||||
guint legacy : 1;
|
||||
guint debug_shaders : 1;
|
||||
guint use_preamble : 1;
|
||||
};
|
||||
|
||||
typedef struct _GskGLProgramAttrib
|
||||
@@ -108,6 +109,7 @@ gsk_gl_compiler_init (GskGLCompiler *self)
|
||||
self->vertex_suffix = g_bytes_ref (empty_bytes);
|
||||
self->fragment_source = g_bytes_ref (empty_bytes);
|
||||
self->fragment_suffix = g_bytes_ref (empty_bytes);
|
||||
self->use_preamble = 1;
|
||||
}
|
||||
|
||||
GskGLCompiler *
|
||||
@@ -422,6 +424,13 @@ gsk_gl_compiler_set_suffix_from_resource (GskGLCompiler *self,
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gl_compiler_set_use_preamble (GskGLCompiler *self,
|
||||
gboolean use_preamble)
|
||||
{
|
||||
self->use_preamble = use_preamble ? 1 : 0;
|
||||
}
|
||||
|
||||
static void
|
||||
prepend_line_numbers (char *code,
|
||||
GString *s)
|
||||
@@ -573,28 +582,40 @@ gsk_gl_compiler_compile (GskGLCompiler *self,
|
||||
gl3 = "#define GSK_GL3 1\n";
|
||||
|
||||
vertex_id = glCreateShader (GL_VERTEX_SHADER);
|
||||
glShaderSource (vertex_id,
|
||||
10,
|
||||
(const char *[]) {
|
||||
version, debug, legacy, gl3, gles,
|
||||
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 (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),
|
||||
});
|
||||
if (self->use_preamble)
|
||||
glShaderSource (vertex_id,
|
||||
10,
|
||||
(const char *[]) {
|
||||
version, debug, legacy, gl3, gles,
|
||||
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 (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),
|
||||
});
|
||||
else
|
||||
glShaderSource (vertex_id,
|
||||
2,
|
||||
(const char *[]) {
|
||||
get_shader_string (self->vertex_source),
|
||||
get_shader_string (self->vertex_suffix),
|
||||
},
|
||||
(int[]) {
|
||||
g_bytes_get_size (self->vertex_source),
|
||||
g_bytes_get_size (self->vertex_suffix),
|
||||
});
|
||||
glCompileShader (vertex_id);
|
||||
|
||||
if (!check_shader_error (vertex_id, error))
|
||||
@@ -606,28 +627,40 @@ gsk_gl_compiler_compile (GskGLCompiler *self,
|
||||
print_shader_info ("Vertex shader", vertex_id, name);
|
||||
|
||||
fragment_id = glCreateShader (GL_FRAGMENT_SHADER);
|
||||
glShaderSource (fragment_id,
|
||||
10,
|
||||
(const char *[]) {
|
||||
version, debug, legacy, gl3, gles,
|
||||
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 (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),
|
||||
});
|
||||
if (self->use_preamble)
|
||||
glShaderSource (fragment_id,
|
||||
10,
|
||||
(const char *[]) {
|
||||
version, debug, legacy, gl3, gles,
|
||||
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 (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),
|
||||
});
|
||||
else
|
||||
glShaderSource (fragment_id,
|
||||
2,
|
||||
(const char *[]) {
|
||||
get_shader_string (self->fragment_source),
|
||||
get_shader_string (self->fragment_suffix),
|
||||
},
|
||||
(int[]) {
|
||||
g_bytes_get_size (self->fragment_source),
|
||||
g_bytes_get_size (self->fragment_suffix),
|
||||
});
|
||||
glCompileShader (fragment_id);
|
||||
|
||||
if (!check_shader_error (fragment_id, error))
|
||||
|
@@ -43,6 +43,8 @@ void gsk_gl_compiler_set_preamble (GskGLCompiler *
|
||||
void gsk_gl_compiler_set_preamble_from_resource (GskGLCompiler *self,
|
||||
GskGLCompilerKind kind,
|
||||
const char *resource_path);
|
||||
void gsk_gl_compiler_set_use_preamble (GskGLCompiler *self,
|
||||
gboolean use_preamble);
|
||||
void gsk_gl_compiler_set_source (GskGLCompiler *self,
|
||||
GskGLCompilerKind kind,
|
||||
GBytes *source_bytes);
|
||||
|
@@ -42,9 +42,16 @@
|
||||
#include <gdk/gdkmemorytextureprivate.h>
|
||||
#include <gdk/gdkprofilerprivate.h>
|
||||
#include <gdk/gdktextureprivate.h>
|
||||
|
||||
#include <gdk/gdkdmabuftextureprivate.h>
|
||||
#include <gdk/gdkmemoryformatprivate.h>
|
||||
|
||||
#ifdef HAVE_EGL
|
||||
#include <epoxy/egl.h>
|
||||
#endif
|
||||
#ifdef HAVE_LINUX_DMA_BUF_H
|
||||
#include <drm/drm_fourcc.h>
|
||||
#endif
|
||||
|
||||
G_DEFINE_TYPE (GskGLDriver, gsk_gl_driver, G_TYPE_OBJECT)
|
||||
|
||||
static guint
|
||||
@@ -224,6 +231,8 @@ gsk_gl_driver_dispose (GObject *object)
|
||||
GSK_GL_DELETE_PROGRAM(name); \
|
||||
GSK_GL_DELETE_PROGRAM(name ## _no_clip); \
|
||||
GSK_GL_DELETE_PROGRAM(name ## _rect_clip);
|
||||
#define GSK_GL_DEFINE_PROGRAM_NO_CLIP(name, resource, uniforms) \
|
||||
GSK_GL_DELETE_PROGRAM(name);
|
||||
#define GSK_GL_DELETE_PROGRAM(name) \
|
||||
G_STMT_START { \
|
||||
if (self->name) \
|
||||
@@ -238,6 +247,7 @@ gsk_gl_driver_dispose (GObject *object)
|
||||
#undef GSK_GL_SHADER_JOINED
|
||||
#undef GSK_GL_ADD_UNIFORM
|
||||
#undef GSK_GL_DEFINE_PROGRAM
|
||||
#undef GSK_GL_DEFINE_PROGRAM_NO_CLIP
|
||||
|
||||
if (self->shader_cache != NULL)
|
||||
{
|
||||
@@ -367,12 +377,19 @@ gsk_gl_driver_load_programs (GskGLDriver *self,
|
||||
#define GSK_GL_ADD_UNIFORM(pos, KEY, name) \
|
||||
gsk_gl_program_add_uniform (program, #name, UNIFORM_##KEY);
|
||||
#define GSK_GL_DEFINE_PROGRAM(name, sources, uniforms) \
|
||||
gsk_gl_compiler_set_use_preamble (compiler, TRUE); \
|
||||
gsk_gl_compiler_set_source (compiler, GSK_GL_COMPILER_VERTEX, NULL); \
|
||||
gsk_gl_compiler_set_source (compiler, GSK_GL_COMPILER_FRAGMENT, NULL); \
|
||||
sources \
|
||||
GSK_GL_COMPILE_PROGRAM(name ## _no_clip, uniforms, "#define NO_CLIP 1\n"); \
|
||||
GSK_GL_COMPILE_PROGRAM(name ## _rect_clip, uniforms, "#define RECT_CLIP 1\n"); \
|
||||
GSK_GL_COMPILE_PROGRAM(name, uniforms, "");
|
||||
#define GSK_GL_DEFINE_PROGRAM_NO_CLIP(name, sources, uniforms) \
|
||||
gsk_gl_compiler_set_use_preamble (compiler, FALSE); \
|
||||
gsk_gl_compiler_set_source (compiler, GSK_GL_COMPILER_VERTEX, NULL); \
|
||||
gsk_gl_compiler_set_source (compiler, GSK_GL_COMPILER_FRAGMENT, NULL); \
|
||||
sources \
|
||||
GSK_GL_COMPILE_PROGRAM(name, uniforms, "#define NO_CLIP 1\n");
|
||||
#define GSK_GL_COMPILE_PROGRAM(name, uniforms, clip) \
|
||||
G_STMT_START { \
|
||||
GskGLProgram *program; \
|
||||
@@ -399,8 +416,8 @@ gsk_gl_driver_load_programs (GskGLDriver *self,
|
||||
g_steal_pointer (&program); \
|
||||
} G_STMT_END;
|
||||
# include "gskglprograms.defs"
|
||||
#undef GSK_GL_DEFINE_PROGRAM_CLIP
|
||||
#undef GSK_GL_DEFINE_PROGRAM
|
||||
#undef GSK_GL_DEFINE_PROGRAM_NO_CLIP
|
||||
#undef GSK_GL_ADD_UNIFORM
|
||||
#undef GSK_GL_SHADER_SINGLE
|
||||
#undef GSK_GL_SHADER_JOINED
|
||||
@@ -703,6 +720,308 @@ gsk_gl_driver_cache_texture (GskGLDriver *self,
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(HAVE_EGL) && defined(HAVE_LINUX_DMA_BUF_H)
|
||||
static EGLImage
|
||||
egl_create_dmabuf_image (EGLDisplay display,
|
||||
int width,
|
||||
int height,
|
||||
unsigned int fourcc,
|
||||
guint64 modifier,
|
||||
unsigned int n_planes,
|
||||
int *fds,
|
||||
unsigned int *strides,
|
||||
unsigned int *offsets)
|
||||
{
|
||||
EGLint attribs[64];
|
||||
int i;
|
||||
|
||||
g_assert (1 <= n_planes && n_planes <= 4);
|
||||
|
||||
GSK_DEBUG (OPENGL,
|
||||
"Importing dma-buf into GL via EGLImage. Format %c%c%c%c:%#lx",
|
||||
fourcc & 0xff, (fourcc >> 8) & 0xff, (fourcc >> 16) & 0xff, (fourcc >> 24) & 0xff, modifier);
|
||||
|
||||
i = 0;
|
||||
attribs[i++] = EGL_IMAGE_PRESERVED_KHR;
|
||||
attribs[i++] = EGL_TRUE;
|
||||
attribs[i++] = EGL_WIDTH;
|
||||
attribs[i++] = width;
|
||||
attribs[i++] = EGL_HEIGHT;
|
||||
attribs[i++] = height;
|
||||
attribs[i++] = EGL_LINUX_DRM_FOURCC_EXT;
|
||||
attribs[i++] = fourcc;
|
||||
|
||||
#define ADD_PLANE(plane) \
|
||||
{ \
|
||||
if (modifier != DRM_FORMAT_MOD_INVALID) \
|
||||
{ \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE## plane ##_MODIFIER_LO_EXT; \
|
||||
attribs[i++] = modifier & 0xFFFFFFFF; \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE## plane ## _MODIFIER_HI_EXT; \
|
||||
attribs[i++] = modifier >> 32; \
|
||||
} \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE## plane ##_FD_EXT; \
|
||||
attribs[i++] = fds[plane]; \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE## plane ##_PITCH_EXT; \
|
||||
attribs[i++] = strides[plane]; \
|
||||
attribs[i++] = EGL_DMA_BUF_PLANE## plane ##_OFFSET_EXT; \
|
||||
attribs[i++] = offsets[plane]; \
|
||||
}
|
||||
|
||||
ADD_PLANE (0);
|
||||
|
||||
if (n_planes > 1) ADD_PLANE (1);
|
||||
if (n_planes > 2) ADD_PLANE (2);
|
||||
if (n_planes > 3) ADD_PLANE (3);
|
||||
|
||||
attribs[i++] = EGL_NONE;
|
||||
|
||||
return eglCreateImageKHR (display,
|
||||
EGL_NO_CONTEXT,
|
||||
EGL_LINUX_DMA_BUF_EXT,
|
||||
(EGLClientBuffer)NULL,
|
||||
attribs);
|
||||
}
|
||||
|
||||
static guint
|
||||
egl_import_image (EGLImage image,
|
||||
int target)
|
||||
{
|
||||
guint texture_id;
|
||||
|
||||
glGenTextures (1, &texture_id);
|
||||
glBindTexture (target, texture_id);
|
||||
g_assert (glGetError() == GL_NO_ERROR);
|
||||
glEGLImageTargetTexture2DOES (target, image);
|
||||
g_assert (glGetError() == GL_NO_ERROR);
|
||||
glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
g_assert (glGetError() == GL_NO_ERROR);
|
||||
glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
g_assert (glGetError() == GL_NO_ERROR);
|
||||
|
||||
return texture_id;
|
||||
}
|
||||
|
||||
static void
|
||||
egl_destroy_image (EGLDisplay display,
|
||||
EGLImage image)
|
||||
{
|
||||
eglDestroyImageKHR (display, image);
|
||||
}
|
||||
|
||||
static int
|
||||
import_dmabuf_planes (EGLDisplay display,
|
||||
int width,
|
||||
int height,
|
||||
unsigned int fourcc,
|
||||
guint64 modifier,
|
||||
unsigned int n_planes,
|
||||
int *fds,
|
||||
unsigned int *strides,
|
||||
unsigned int *offsets,
|
||||
int target)
|
||||
{
|
||||
EGLImage image;
|
||||
int texture_id;
|
||||
|
||||
image = egl_create_dmabuf_image (display, width, height, fourcc, modifier, n_planes,fds, strides, offsets);
|
||||
|
||||
if (image == EGL_NO_IMAGE)
|
||||
{
|
||||
g_warning ("Failed to create EGL image: %#x\n", eglGetError ());
|
||||
return 0;
|
||||
}
|
||||
|
||||
texture_id = egl_import_image (image, target);
|
||||
|
||||
egl_destroy_image (display, image);
|
||||
|
||||
return texture_id;
|
||||
}
|
||||
|
||||
static void
|
||||
set_viewport_for_size (GskGLDriver *self,
|
||||
GskGLProgram *program,
|
||||
float width,
|
||||
float height)
|
||||
{
|
||||
float viewport[4] = { 0, 0, width, height };
|
||||
|
||||
gsk_gl_uniform_state_set4fv (program->uniforms,
|
||||
program->program_info,
|
||||
UNIFORM_SHARED_VIEWPORT, 0,
|
||||
1,
|
||||
(const float *)&viewport);
|
||||
self->stamps[UNIFORM_SHARED_VIEWPORT]++;
|
||||
}
|
||||
|
||||
#define ORTHO_NEAR_PLANE -10000
|
||||
#define ORTHO_FAR_PLANE 10000
|
||||
|
||||
static void
|
||||
set_projection_for_size (GskGLDriver *self,
|
||||
GskGLProgram *program,
|
||||
float width,
|
||||
float height)
|
||||
{
|
||||
graphene_matrix_t projection;
|
||||
|
||||
graphene_matrix_init_ortho (&projection, 0, width, 0, height, ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE);
|
||||
graphene_matrix_scale (&projection, 1, -1, 1);
|
||||
|
||||
gsk_gl_uniform_state_set_matrix (program->uniforms,
|
||||
program->program_info,
|
||||
UNIFORM_SHARED_PROJECTION, 0,
|
||||
&projection);
|
||||
self->stamps[UNIFORM_SHARED_PROJECTION]++;
|
||||
}
|
||||
|
||||
static void
|
||||
reset_modelview (GskGLDriver *self,
|
||||
GskGLProgram *program)
|
||||
{
|
||||
graphene_matrix_t modelview;
|
||||
|
||||
graphene_matrix_init_identity (&modelview);
|
||||
|
||||
gsk_gl_uniform_state_set_matrix (program->uniforms,
|
||||
program->program_info,
|
||||
UNIFORM_SHARED_MODELVIEW, 0,
|
||||
&modelview);
|
||||
self->stamps[UNIFORM_SHARED_MODELVIEW]++;
|
||||
}
|
||||
|
||||
static void
|
||||
draw_rect (GskGLCommandQueue *command_queue,
|
||||
float min_x,
|
||||
float min_y,
|
||||
float max_x,
|
||||
float max_y)
|
||||
{
|
||||
GskGLDrawVertex *vertices = gsk_gl_command_queue_add_vertices (command_queue);
|
||||
float min_u = 0;
|
||||
float max_u = 1;
|
||||
float min_v = 1;
|
||||
float max_v = 0;
|
||||
guint16 c = FP16_ZERO;
|
||||
|
||||
vertices[0] = (GskGLDrawVertex) { .position = { min_x, min_y }, .uv = { min_u, min_v }, .color = { c, c, c, c } };
|
||||
vertices[1] = (GskGLDrawVertex) { .position = { min_x, max_y }, .uv = { min_u, max_v }, .color = { c, c, c, c } };
|
||||
vertices[2] = (GskGLDrawVertex) { .position = { max_x, min_y }, .uv = { max_u, min_v }, .color = { c, c, c, c } };
|
||||
vertices[3] = (GskGLDrawVertex) { .position = { max_x, max_y }, .uv = { max_u, max_v }, .color = { c, c, c, c } };
|
||||
vertices[4] = (GskGLDrawVertex) { .position = { min_x, max_y }, .uv = { min_u, max_v }, .color = { c, c, c, c } };
|
||||
vertices[5] = (GskGLDrawVertex) { .position = { max_x, min_y }, .uv = { max_u, min_v }, .color = { c, c, c, c } };
|
||||
}
|
||||
|
||||
static unsigned int release_render_target (GskGLDriver *self,
|
||||
GskGLRenderTarget *render_target,
|
||||
gboolean release_texture,
|
||||
gboolean cache_texture);
|
||||
|
||||
static unsigned int
|
||||
gsk_gl_driver_import_dmabuf_texture (GskGLDriver *self,
|
||||
GdkDmabufTexture *texture)
|
||||
{
|
||||
GdkGLContext *context = self->command_queue->context;
|
||||
GdkDisplay *display = gdk_gl_context_get_display (context);
|
||||
EGLDisplay egl_display;
|
||||
int width, height;
|
||||
guint32 fourcc;
|
||||
guint64 modifier;
|
||||
GskGLProgram *program;
|
||||
GskGLRenderTarget *render_target;
|
||||
guint prev_fbo;
|
||||
|
||||
egl_display = gdk_display_get_egl_display (display);
|
||||
if (egl_display == NULL)
|
||||
{
|
||||
g_warning ("Can't import dmabufs when not using EGL");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!display->have_egl_dma_buf_import)
|
||||
{
|
||||
g_warning ("EGL does ont support importing dmabufs");
|
||||
return 0;
|
||||
}
|
||||
|
||||
gdk_gl_context_make_current (context);
|
||||
|
||||
width = gdk_texture_get_width (GDK_TEXTURE (texture));
|
||||
height = gdk_texture_get_height (GDK_TEXTURE (texture));
|
||||
fourcc = gdk_dmabuf_texture_get_fourcc (texture);
|
||||
modifier = gdk_dmabuf_texture_get_modifier (texture);
|
||||
|
||||
GSK_DEBUG (OPENGL,
|
||||
"DMA-buf Format %c%c%c%c:%#lx",
|
||||
fourcc & 0xff, (fourcc >> 8) & 0xff, (fourcc >> 16) & 0xff, (fourcc >> 24) & 0xff, modifier);
|
||||
|
||||
if (gdk_gl_context_get_api (context) == GDK_GL_API_GLES)
|
||||
{
|
||||
program = self->external;
|
||||
}
|
||||
else
|
||||
{
|
||||
return import_dmabuf_planes (egl_display,
|
||||
gdk_texture_get_width (GDK_TEXTURE (texture)),
|
||||
gdk_texture_get_height (GDK_TEXTURE (texture)),
|
||||
gdk_dmabuf_texture_get_fourcc (texture),
|
||||
gdk_dmabuf_texture_get_modifier (texture),
|
||||
gdk_dmabuf_texture_get_n_planes (texture),
|
||||
gdk_dmabuf_texture_get_fds (texture),
|
||||
gdk_dmabuf_texture_get_strides (texture),
|
||||
gdk_dmabuf_texture_get_offsets (texture),
|
||||
GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
gsk_gl_driver_create_render_target (self, width, height, GL_RGBA8, &render_target);
|
||||
|
||||
prev_fbo = gsk_gl_command_queue_bind_framebuffer (self->command_queue, render_target->framebuffer_id);
|
||||
gsk_gl_command_queue_clear (self->command_queue, 0, &GRAPHENE_RECT_INIT (0, 0, width, height));
|
||||
|
||||
gsk_gl_command_queue_begin_draw (self->command_queue, program->program_info, width, height);
|
||||
|
||||
set_projection_for_size (self, program, width, height);
|
||||
set_viewport_for_size (self, program, width, height);
|
||||
reset_modelview (self, program);
|
||||
|
||||
if (gdk_gl_context_get_api (context) == GDK_GL_API_GLES)
|
||||
{
|
||||
int texture_id = import_dmabuf_planes (egl_display,
|
||||
gdk_texture_get_width (GDK_TEXTURE (texture)),
|
||||
gdk_texture_get_height (GDK_TEXTURE (texture)),
|
||||
gdk_dmabuf_texture_get_fourcc (texture),
|
||||
gdk_dmabuf_texture_get_modifier (texture),
|
||||
gdk_dmabuf_texture_get_n_planes (texture),
|
||||
gdk_dmabuf_texture_get_fds (texture),
|
||||
gdk_dmabuf_texture_get_strides (texture),
|
||||
gdk_dmabuf_texture_get_offsets (texture),
|
||||
GL_TEXTURE_EXTERNAL_OES);
|
||||
|
||||
gsk_gl_program_set_uniform_texture (program,
|
||||
UNIFORM_EXTERNAL_SOURCE, 0,
|
||||
GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE0, texture_id);
|
||||
|
||||
gsk_gl_driver_autorelease_texture (self, texture_id);
|
||||
}
|
||||
|
||||
draw_rect (self->command_queue, 0, 0, width, height);
|
||||
|
||||
gsk_gl_command_queue_end_draw (self->command_queue);
|
||||
|
||||
gsk_gl_command_queue_bind_framebuffer (self->command_queue, prev_fbo);
|
||||
|
||||
return release_render_target (self, render_target, FALSE, FALSE);
|
||||
}
|
||||
#else
|
||||
static unsigned int
|
||||
gsk_gl_driver_import_dmabuf_texture (GskGLDriver *self,
|
||||
GdkDmabufTexture *texture)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* HAVE_EGL && HAVE_LINUX_DMA_BUF_H */
|
||||
|
||||
/**
|
||||
* gsk_gl_driver_load_texture:
|
||||
* @self: a `GdkTexture`
|
||||
@@ -759,7 +1078,11 @@ gsk_gl_driver_load_texture (GskGLDriver *self,
|
||||
return t->texture_id;
|
||||
}
|
||||
|
||||
if (GDK_IS_GL_TEXTURE (texture))
|
||||
if (GDK_IS_DMABUF_TEXTURE (texture))
|
||||
{
|
||||
texture_id = gsk_gl_driver_import_dmabuf_texture (self, GDK_DMABUF_TEXTURE (texture));
|
||||
}
|
||||
else if (GDK_IS_GL_TEXTURE (texture))
|
||||
{
|
||||
GdkGLTexture *gl_texture = (GdkGLTexture *) texture;
|
||||
GdkGLContext *texture_context = gdk_gl_texture_get_context (gl_texture);
|
||||
@@ -788,9 +1111,8 @@ gsk_gl_driver_load_texture (GskGLDriver *self,
|
||||
width = gdk_texture_get_width (texture);
|
||||
height = gdk_texture_get_height (texture);
|
||||
|
||||
t = gsk_gl_texture_new (texture_id,
|
||||
width, height,
|
||||
self->current_frame_id);
|
||||
t = gsk_gl_texture_new (texture_id, width, height, self->current_frame_id);
|
||||
|
||||
if (ensure_mipmap)
|
||||
{
|
||||
glBindTexture (GL_TEXTURE_2D, t->texture_id);
|
||||
@@ -962,6 +1284,47 @@ gsk_gl_driver_create_render_target (GskGLDriver *self,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
release_render_target (GskGLDriver *self,
|
||||
GskGLRenderTarget *render_target,
|
||||
gboolean release_texture,
|
||||
gboolean cache_texture)
|
||||
{
|
||||
guint texture_id;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_GL_DRIVER (self), 0);
|
||||
g_return_val_if_fail (render_target != NULL, 0);
|
||||
|
||||
if (release_texture)
|
||||
{
|
||||
texture_id = 0;
|
||||
g_ptr_array_add (self->render_targets, render_target);
|
||||
}
|
||||
else
|
||||
{
|
||||
texture_id = render_target->texture_id;
|
||||
|
||||
if (cache_texture)
|
||||
{
|
||||
GskGLTexture *texture;
|
||||
|
||||
texture = gsk_gl_texture_new (render_target->texture_id,
|
||||
render_target->width,
|
||||
render_target->height,
|
||||
self->current_frame_id);
|
||||
g_hash_table_insert (self->textures,
|
||||
GUINT_TO_POINTER (texture_id),
|
||||
g_steal_pointer (&texture));
|
||||
}
|
||||
|
||||
gsk_gl_driver_autorelease_framebuffer (self, render_target->framebuffer_id);
|
||||
g_free (render_target);
|
||||
|
||||
}
|
||||
|
||||
return texture_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_gl_driver_release_render_target:
|
||||
* @self: a `GskGLDriver`
|
||||
@@ -987,36 +1350,7 @@ gsk_gl_driver_release_render_target (GskGLDriver *self,
|
||||
GskGLRenderTarget *render_target,
|
||||
gboolean release_texture)
|
||||
{
|
||||
guint texture_id;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_GL_DRIVER (self), 0);
|
||||
g_return_val_if_fail (render_target != NULL, 0);
|
||||
|
||||
if (release_texture)
|
||||
{
|
||||
texture_id = 0;
|
||||
g_ptr_array_add (self->render_targets, render_target);
|
||||
}
|
||||
else
|
||||
{
|
||||
GskGLTexture *texture;
|
||||
|
||||
texture_id = render_target->texture_id;
|
||||
|
||||
texture = gsk_gl_texture_new (render_target->texture_id,
|
||||
render_target->width,
|
||||
render_target->height,
|
||||
self->current_frame_id);
|
||||
g_hash_table_insert (self->textures,
|
||||
GUINT_TO_POINTER (texture_id),
|
||||
g_steal_pointer (&texture));
|
||||
|
||||
gsk_gl_driver_autorelease_framebuffer (self, render_target->framebuffer_id);
|
||||
g_free (render_target);
|
||||
|
||||
}
|
||||
|
||||
return texture_id;
|
||||
return release_render_target (self, render_target, release_texture, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -69,7 +69,9 @@ typedef struct {
|
||||
#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
|
||||
@@ -116,10 +118,13 @@ struct _GskGLDriver
|
||||
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;
|
||||
|
||||
|
@@ -87,3 +87,13 @@ GSK_GL_DEFINE_PROGRAM (unblurred_outset_shadow,
|
||||
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))
|
||||
|
@@ -30,6 +30,8 @@
|
||||
#include <gsk/gskglshaderprivate.h>
|
||||
#include <gdk/gdktextureprivate.h>
|
||||
#include <gdk/gdkmemorytextureprivate.h>
|
||||
#include <gdk/gdkdmabuftextureprivate.h>
|
||||
#include <gdk/gdkdisplayprivate.h>
|
||||
#include <gsk/gsktransformprivate.h>
|
||||
#include <gsk/gskroundedrectprivate.h>
|
||||
#include <gsk/gskrectprivate.h>
|
||||
@@ -43,10 +45,15 @@
|
||||
#include "gskglprogramprivate.h"
|
||||
#include "gskglrenderjobprivate.h"
|
||||
#include "gskglshadowlibraryprivate.h"
|
||||
#include "gskdebugprivate.h"
|
||||
|
||||
#include "ninesliceprivate.h"
|
||||
#include "fp16private.h"
|
||||
|
||||
#include <epoxy/egl.h>
|
||||
|
||||
#include <drm/drm_fourcc.h>
|
||||
|
||||
#define ORTHO_NEAR_PLANE -10000
|
||||
#define ORTHO_FAR_PLANE 10000
|
||||
#define MAX_GRADIENT_STOPS 6
|
||||
@@ -3630,16 +3637,11 @@ gsk_gl_render_job_upload_texture (GskGLRenderJob *job,
|
||||
gboolean ensure_mipmap,
|
||||
GskGLRenderOffscreen *offscreen)
|
||||
{
|
||||
GdkGLTexture *gl_texture = NULL;
|
||||
|
||||
if (GDK_IS_GL_TEXTURE (texture))
|
||||
gl_texture = GDK_GL_TEXTURE (texture);
|
||||
|
||||
if (!ensure_mipmap &&
|
||||
gsk_gl_texture_library_can_cache ((GskGLTextureLibrary *)job->driver->icons_library,
|
||||
texture->width,
|
||||
texture->height) &&
|
||||
!gl_texture)
|
||||
!(GDK_IS_GL_TEXTURE (texture) || GDK_IS_DMABUF_TEXTURE (texture)))
|
||||
{
|
||||
const GskGLIconData *icon_data;
|
||||
|
||||
@@ -3653,16 +3655,18 @@ gsk_gl_render_job_upload_texture (GskGLRenderJob *job,
|
||||
/* Only generate a mipmap if it does not make use reupload
|
||||
* a GL texture which we could otherwise use directly.
|
||||
*/
|
||||
if (gl_texture &&
|
||||
gdk_gl_context_is_shared (gdk_gl_texture_get_context (gl_texture), job->command_queue->context))
|
||||
ensure_mipmap = gdk_gl_texture_has_mipmap (gl_texture);
|
||||
if (GDK_IS_GL_TEXTURE (texture) &&
|
||||
gdk_gl_context_is_shared (gdk_gl_texture_get_context (GDK_GL_TEXTURE (texture)),
|
||||
job->command_queue->context))
|
||||
ensure_mipmap = gdk_gl_texture_has_mipmap (GDK_GL_TEXTURE (texture));
|
||||
|
||||
offscreen->texture_id = gsk_gl_driver_load_texture (job->driver, texture, ensure_mipmap);
|
||||
init_full_texture_region (offscreen);
|
||||
offscreen->has_mipmap = ensure_mipmap;
|
||||
|
||||
if (gl_texture && offscreen->texture_id == gdk_gl_texture_get_id (gl_texture))
|
||||
offscreen->sync = gdk_gl_texture_get_sync (gl_texture);
|
||||
if (GDK_IS_GL_TEXTURE (texture) &&
|
||||
offscreen->texture_id == gdk_gl_texture_get_id (GDK_GL_TEXTURE (texture)))
|
||||
offscreen->sync = gdk_gl_texture_get_sync (GDK_GL_TEXTURE (texture));
|
||||
}
|
||||
}
|
||||
|
||||
|
37
gsk/gl/resources/external.glsl
Normal file
37
gsk/gl/resources/external.glsl
Normal file
@@ -0,0 +1,37 @@
|
||||
// VERTEX_SHADER:
|
||||
// external.glsl
|
||||
|
||||
#version 300 es
|
||||
|
||||
precision highp float;
|
||||
|
||||
in vec2 aPosition;
|
||||
in vec2 aUv;
|
||||
out vec2 vUv;
|
||||
uniform mat4 u_projection;
|
||||
uniform mat4 u_modelview;
|
||||
|
||||
void main() {
|
||||
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
|
||||
|
||||
vUv = vec2(aUv.x, aUv.y);
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
// external.glsl
|
||||
|
||||
#version 300 es
|
||||
#extension GL_OES_EGL_image_external_essl3 : require
|
||||
|
||||
precision highp float;
|
||||
|
||||
uniform samplerExternalOES u_external_source;
|
||||
|
||||
in vec2 vUv;
|
||||
|
||||
out vec4 outputColor;
|
||||
|
||||
void main() {
|
||||
vec4 color = texture(u_external_source, vUv);
|
||||
outputColor = color;
|
||||
}
|
@@ -1,3 +1,7 @@
|
||||
#ifdef GSK_GLES
|
||||
#extension GL_OES_EGL_image_external : require
|
||||
#endif
|
||||
|
||||
#ifndef GSK_LEGACY
|
||||
precision highp float;
|
||||
#endif
|
||||
|
@@ -20,6 +20,7 @@ gsk_private_gl_shaders = [
|
||||
'gl/resources/custom.glsl',
|
||||
'gl/resources/filled_border.glsl',
|
||||
'gl/resources/mask.glsl',
|
||||
'gl/resources/external.glsl',
|
||||
]
|
||||
|
||||
gsk_public_sources = files([
|
||||
|
@@ -1,5 +1,6 @@
|
||||
gtk_tests = [
|
||||
# testname, optional extra sources
|
||||
['testdmabuf'],
|
||||
['testsections'],
|
||||
['testfilelauncher'],
|
||||
['input'],
|
||||
|
440
tests/testdmabuf.c
Normal file
440
tests/testdmabuf.c
Normal file
@@ -0,0 +1,440 @@
|
||||
#include <gtk/gtk.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/dma-heap.h>
|
||||
#include <drm/drm_fourcc.h>
|
||||
|
||||
/* For this to work, you may need to give /dev/dma_heap/system
|
||||
* lax permissions.
|
||||
*/
|
||||
|
||||
static int
|
||||
allocate_dma_buf (gsize size)
|
||||
{
|
||||
static int fd = -1;
|
||||
struct dma_heap_allocation_data heap_data;
|
||||
int ret;
|
||||
|
||||
if (fd == -1)
|
||||
{
|
||||
fd = open ("/dev/dma_heap/system", O_RDONLY | O_CLOEXEC);
|
||||
if (fd == -1)
|
||||
g_error ("Failed to open /dev/dma_heap/system");
|
||||
}
|
||||
|
||||
heap_data.len = size;
|
||||
heap_data.fd = 0;
|
||||
heap_data.fd_flags = O_RDWR | O_CLOEXEC;
|
||||
heap_data.heap_flags = 0;
|
||||
|
||||
ret = ioctl (fd, DMA_HEAP_IOCTL_ALLOC, &heap_data);
|
||||
if (ret)
|
||||
g_error ("dma-buf allocation failed");
|
||||
|
||||
return heap_data.fd;
|
||||
}
|
||||
|
||||
static void
|
||||
populate_dma_buf (int fd,
|
||||
guchar *data,
|
||||
gsize size)
|
||||
{
|
||||
guchar *buf;
|
||||
|
||||
buf = mmap (NULL, size, PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
memcpy (buf, data, size);
|
||||
munmap (buf, size);
|
||||
}
|
||||
|
||||
|
||||
/* The YUV conversion code is adapted from weston/tests/yuv-buffer-test.c */
|
||||
|
||||
/*
|
||||
* Based on Rec. ITU-R BT.601-7
|
||||
*
|
||||
* This is intended to be obvious and accurate, not fast.
|
||||
*/
|
||||
static void
|
||||
x8r8g8b8_to_ycbcr8_bt601 (guint32 xrgb,
|
||||
guchar *y_out,
|
||||
guchar *cb_out,
|
||||
guchar *cr_out)
|
||||
{
|
||||
double y, cb, cr;
|
||||
double r = (xrgb >> 16) & 0xff;
|
||||
double g = (xrgb >> 8) & 0xff;
|
||||
double b = (xrgb >> 0) & 0xff;
|
||||
|
||||
/* normalize to [0.0, 1.0] */
|
||||
r /= 255.0;
|
||||
g /= 255.0;
|
||||
b /= 255.0;
|
||||
|
||||
/* Y normalized to [0.0, 1.0], Cb and Cr [-0.5, 0.5] */
|
||||
y = 0.299 * r + 0.587 * g + 0.114 * b;
|
||||
cr = (r - y) / 1.402;
|
||||
cb = (b - y) / 1.772;
|
||||
|
||||
/* limited range quantization to 8 bit */
|
||||
*y_out = round(219.0 * y + 16.0);
|
||||
if (cr_out)
|
||||
*cr_out = round(224.0 * cr + 128.0);
|
||||
if (cb_out)
|
||||
*cb_out = round(224.0 * cb + 128.0);
|
||||
}
|
||||
|
||||
/*
|
||||
* 3 plane YCbCr
|
||||
* plane 0: Y plane, [7:0] Y
|
||||
* plane 1: Cb plane, [7:0] Cb
|
||||
* plane 2: Cr plane, [7:0] Cr
|
||||
* YUV420: 2x2 subsampled Cb (1) and Cr (2) planes
|
||||
* YUV444: no subsampling
|
||||
*/
|
||||
static guchar *
|
||||
y_u_v_create_buffer (uint32_t drm_format,
|
||||
guchar *rgb_data,
|
||||
int rgb_width,
|
||||
int rgb_height,
|
||||
int *size,
|
||||
int *u_offset,
|
||||
int *v_offset)
|
||||
{
|
||||
gsize bytes;
|
||||
int x, y;
|
||||
guint32 *rgb_row;
|
||||
guchar *y_base;
|
||||
guchar *u_base;
|
||||
guchar *v_base;
|
||||
guchar *y_row;
|
||||
guchar *u_row;
|
||||
guchar *v_row;
|
||||
guint32 argb;
|
||||
int sub = (drm_format == DRM_FORMAT_YUV420) ? 2 : 1;
|
||||
guchar *buf;
|
||||
|
||||
g_assert (drm_format == DRM_FORMAT_YUV420 ||
|
||||
drm_format == DRM_FORMAT_YUV444);
|
||||
|
||||
/* Full size Y plus quarter U and V */
|
||||
bytes = rgb_width * rgb_height +
|
||||
(rgb_width / sub) * (rgb_height / sub) * 2;
|
||||
|
||||
buf = g_new (guchar, bytes);
|
||||
|
||||
*size = bytes;
|
||||
*u_offset = rgb_width * rgb_height;
|
||||
*v_offset = *u_offset + (rgb_width / sub) * (rgb_height / sub);
|
||||
|
||||
y_base = buf;
|
||||
u_base = y_base + rgb_width * rgb_height;
|
||||
v_base = u_base + (rgb_width / sub) * (rgb_height / sub);
|
||||
|
||||
for (y = 0; y < rgb_height; y++)
|
||||
{
|
||||
rgb_row = (guint32 *) (rgb_data + y * 4 * rgb_width);
|
||||
y_row = y_base + y * rgb_width;
|
||||
u_row = u_base + (y / sub) * (rgb_width / sub);
|
||||
v_row = v_base + (y / sub) * (rgb_width / sub);
|
||||
|
||||
for (x = 0; x < rgb_width; x++)
|
||||
{
|
||||
/*
|
||||
* Sub-sample the source image instead, so that U and V
|
||||
* sub-sampling does not require proper
|
||||
* filtering/averaging/siting.
|
||||
*/
|
||||
argb = *(rgb_row + x / 2 * 2);
|
||||
|
||||
/*
|
||||
* A stupid way of "sub-sampling" chroma. This does not
|
||||
* do the necessary filtering/averaging/siting or
|
||||
* alternate Cb/Cr rows.
|
||||
*/
|
||||
if ((y & (sub - 1)) == 0 && (x & (sub - 1)) == 0)
|
||||
x8r8g8b8_to_ycbcr8_bt601 (argb, y_row + x, u_row + x / sub, v_row + x / sub);
|
||||
else
|
||||
x8r8g8b8_to_ycbcr8_bt601 (argb, y_row + x, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
* 2 plane YCbCr
|
||||
* plane 0 = Y plane, [7:0] Y
|
||||
* plane 1 = Cr:Cb plane, [15:0] Cr:Cb little endian
|
||||
* 2x2 subsampled Cr:Cb plane
|
||||
*/
|
||||
static guchar *
|
||||
nv12_create_buffer (uint32_t drm_format,
|
||||
guchar *rgb_data,
|
||||
int rgb_width,
|
||||
int rgb_height,
|
||||
int *size,
|
||||
int *uv_offset)
|
||||
{
|
||||
size_t bytes;
|
||||
int x, y;
|
||||
uint32_t *rgb_row;
|
||||
uint8_t *y_base;
|
||||
uint16_t *uv_base;
|
||||
uint8_t *y_row;
|
||||
uint16_t *uv_row;
|
||||
uint32_t argb;
|
||||
uint8_t cr;
|
||||
uint8_t cb;
|
||||
guchar *buf;
|
||||
|
||||
g_assert (drm_format == DRM_FORMAT_NV12);
|
||||
|
||||
/* Full size Y, quarter UV */
|
||||
bytes = rgb_width * rgb_height +
|
||||
(rgb_width / 2) * (rgb_height / 2) * sizeof (uint16_t);
|
||||
|
||||
buf = g_new0 (guchar, bytes);
|
||||
|
||||
*uv_offset = rgb_width * rgb_height;
|
||||
y_base = buf;
|
||||
uv_base = (uint16_t *)(y_base + rgb_width * rgb_height);
|
||||
|
||||
for (y = 0; y < rgb_height; y++)
|
||||
{
|
||||
rgb_row = (uint32_t *) (rgb_data + y * 4 * rgb_width);
|
||||
y_row = y_base + y * rgb_width;
|
||||
uv_row = (uint16_t *) (uv_base + (y / 2) * (rgb_width / 2));
|
||||
|
||||
for (x = 0; x < rgb_width; x++)
|
||||
{
|
||||
/*
|
||||
* Sub-sample the source image instead, so that U and V
|
||||
* sub-sampling does not require proper
|
||||
* filtering/averaging/siting.
|
||||
*/
|
||||
argb = *(rgb_row + x / 2 * 2);
|
||||
|
||||
/*
|
||||
* A stupid way of "sub-sampling" chroma. This does not
|
||||
* do the necessary filtering/averaging/siting.
|
||||
*/
|
||||
if ((y & 1) == 0 && (x & 1) == 0)
|
||||
{
|
||||
x8r8g8b8_to_ycbcr8_bt601(argb, y_row + x, &cb, &cr);
|
||||
*(uv_row + x / 2) = ((uint16_t)cr << 8) | cb;
|
||||
}
|
||||
else
|
||||
{
|
||||
x8r8g8b8_to_ycbcr8_bt601(argb, y_row + x, NULL, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static GdkTexture *
|
||||
make_dmabuf_texture (const char *filename,
|
||||
guint32 format)
|
||||
{
|
||||
GdkTexture *texture;
|
||||
int width, height;
|
||||
gsize rgb_stride, rgb_size;
|
||||
guchar *rgb_data;
|
||||
int fd;
|
||||
GdkDmabufTextureBuilder *builder;
|
||||
GError *error = NULL;
|
||||
|
||||
texture = gdk_texture_new_from_filename (filename, NULL);
|
||||
|
||||
width = gdk_texture_get_width (texture);
|
||||
height = gdk_texture_get_height (texture);
|
||||
rgb_stride = 4 * width;
|
||||
rgb_size = rgb_stride * height;
|
||||
|
||||
rgb_data = g_new0 (guchar, rgb_size);
|
||||
|
||||
gdk_texture_download (texture, rgb_data, rgb_stride);
|
||||
|
||||
g_object_unref (texture);
|
||||
|
||||
builder = gdk_dmabuf_texture_builder_new ();
|
||||
|
||||
gdk_dmabuf_texture_builder_set_display (builder, gdk_display_get_default ());
|
||||
gdk_dmabuf_texture_builder_set_width (builder, width);
|
||||
gdk_dmabuf_texture_builder_set_height (builder, height);
|
||||
gdk_dmabuf_texture_builder_set_fourcc (builder, format);
|
||||
gdk_dmabuf_texture_builder_set_modifier (builder, DRM_FORMAT_MOD_LINEAR);
|
||||
|
||||
if (format == DRM_FORMAT_XRGB8888)
|
||||
{
|
||||
gdk_dmabuf_texture_builder_set_n_planes (builder, 1);
|
||||
|
||||
fd = allocate_dma_buf (rgb_size);
|
||||
populate_dma_buf (fd, rgb_data, rgb_size);
|
||||
|
||||
gdk_dmabuf_texture_builder_set_fd (builder, 0, fd);
|
||||
gdk_dmabuf_texture_builder_set_stride (builder, 0, rgb_stride);
|
||||
}
|
||||
else if (format == DRM_FORMAT_YUV420)
|
||||
{
|
||||
guchar *buf;
|
||||
int size, u_offset, v_offset;
|
||||
|
||||
gdk_dmabuf_texture_builder_set_n_planes (builder, 3);
|
||||
|
||||
buf = y_u_v_create_buffer (format, rgb_data, width, height, &size, &u_offset, &v_offset);
|
||||
|
||||
fd = allocate_dma_buf (width * height);
|
||||
populate_dma_buf (fd, buf, width * height);
|
||||
|
||||
gdk_dmabuf_texture_builder_set_fd (builder, 0, fd);
|
||||
gdk_dmabuf_texture_builder_set_stride (builder, 0, width);
|
||||
gdk_dmabuf_texture_builder_set_offset (builder, 0, 0);
|
||||
|
||||
fd = allocate_dma_buf ((width / 2) * (height / 2));
|
||||
populate_dma_buf (fd, buf + u_offset, (width / 2) * (height / 2));
|
||||
|
||||
gdk_dmabuf_texture_builder_set_fd (builder, 1, fd);
|
||||
gdk_dmabuf_texture_builder_set_stride (builder, 1, width / 2);
|
||||
gdk_dmabuf_texture_builder_set_offset (builder, 1, 0);
|
||||
|
||||
fd = allocate_dma_buf ((width / 2) * (height / 2));
|
||||
populate_dma_buf (fd, buf + v_offset, (width / 2) * (height / 2));
|
||||
|
||||
gdk_dmabuf_texture_builder_set_fd (builder, 2, fd);
|
||||
gdk_dmabuf_texture_builder_set_stride (builder, 2, width / 2);
|
||||
gdk_dmabuf_texture_builder_set_offset (builder, 2, 0);
|
||||
|
||||
g_free (buf);
|
||||
}
|
||||
else if (format == DRM_FORMAT_NV12)
|
||||
{
|
||||
guchar *buf;
|
||||
int size, uv_offset;
|
||||
|
||||
gdk_dmabuf_texture_builder_set_n_planes (builder, 2);
|
||||
|
||||
buf = nv12_create_buffer (format, rgb_data, width, height, &size, &uv_offset);
|
||||
|
||||
fd = allocate_dma_buf (width * height);
|
||||
populate_dma_buf (fd, buf, width * height);
|
||||
|
||||
gdk_dmabuf_texture_builder_set_fd (builder, 0, fd);
|
||||
gdk_dmabuf_texture_builder_set_stride (builder, 0, width);
|
||||
gdk_dmabuf_texture_builder_set_offset (builder, 0, 0);
|
||||
|
||||
fd = allocate_dma_buf ((width / 2) * (height / 2) * sizeof (uint16_t));
|
||||
populate_dma_buf (fd, buf + uv_offset, (width / 2) * (height / 2) * sizeof (uint16_t));
|
||||
|
||||
gdk_dmabuf_texture_builder_set_fd (builder, 1, fd);
|
||||
gdk_dmabuf_texture_builder_set_stride (builder, 1, width);
|
||||
gdk_dmabuf_texture_builder_set_offset (builder, 1, 0);
|
||||
|
||||
g_free (buf);
|
||||
}
|
||||
|
||||
g_free (rgb_data);
|
||||
|
||||
texture = gdk_dmabuf_texture_builder_build (builder, NULL, NULL);
|
||||
if (!texture)
|
||||
g_error ("Failed to create dmabuf texture: %s", error->message);
|
||||
|
||||
g_object_unref (builder);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
static guint32 supported_formats[] = {
|
||||
DRM_FORMAT_XRGB8888,
|
||||
DRM_FORMAT_YUV420,
|
||||
DRM_FORMAT_NV12,
|
||||
};
|
||||
|
||||
static gboolean
|
||||
format_is_supported (guint32 fmt)
|
||||
{
|
||||
for (int i = 0; i < G_N_ELEMENTS (supported_formats); i++)
|
||||
{
|
||||
if (supported_formats[i] == fmt)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static char *
|
||||
supported_formats_to_string (void)
|
||||
{
|
||||
GString *s;
|
||||
|
||||
s = g_string_new ("");
|
||||
for (int i = 0; i < G_N_ELEMENTS (supported_formats); i++)
|
||||
{
|
||||
if (s->len)
|
||||
g_string_append (s, ", ");
|
||||
g_string_append_printf (s, "%.4s", (char *)&supported_formats[i]);
|
||||
}
|
||||
|
||||
return g_string_free (s, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
usage (void)
|
||||
{
|
||||
char *formats = supported_formats_to_string ();
|
||||
g_print ("Usage: testdmabuf FORMAT FILE\n"
|
||||
"Supported formats: %s\n", formats);
|
||||
g_free (formats);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
static guint32
|
||||
parse_format (const char *a)
|
||||
{
|
||||
if (strlen (a) == 4)
|
||||
{
|
||||
guint32 format = fourcc_code (a[0], a[1], a[2], a[3]);
|
||||
if (format_is_supported (format))
|
||||
return format;
|
||||
}
|
||||
|
||||
usage ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
GdkTexture *texture;
|
||||
GtkWidget *window, *picture;
|
||||
char *filename;
|
||||
guint32 format;
|
||||
|
||||
if (argc != 3)
|
||||
g_assert (argc == 3);
|
||||
|
||||
format = parse_format (argv[1]);
|
||||
filename = argv[2];
|
||||
|
||||
gtk_init ();
|
||||
|
||||
/* Get the list of supported formats with GDK_DEBUG=opengl */
|
||||
gdk_display_get_dmabuf_formats (gdk_display_get_default ());
|
||||
|
||||
texture = make_dmabuf_texture (filename, format);
|
||||
|
||||
window = gtk_window_new ();
|
||||
|
||||
picture = gtk_picture_new_for_paintable (GDK_PAINTABLE (texture));
|
||||
|
||||
gtk_window_set_child (GTK_WINDOW (window), picture);
|
||||
|
||||
gtk_window_present (GTK_WINDOW (window));
|
||||
|
||||
while (g_list_model_get_n_items (gtk_window_get_toplevels ()) > 0)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user