mirror of
https://github.com/brl/mutter.git
synced 2025-02-21 23:44:10 +00:00

Dropped obsolete Free Software Foundation address pointing to the FSF website instead as suggested by https://www.gnu.org/licenses/gpl-howto.html keeping intact the important part of the historical notice as requested by the license. Resolving rpmlint reported issue E: incorrect-fsf-address. Signed-off-by: Sandro Bonazzola <sbonazzo@redhat.com> Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3155>
412 lines
12 KiB
C
412 lines
12 KiB
C
/*
|
|
* Copyright (C) 2021 Red Hat Inc.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program 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
|
|
* 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/>.
|
|
*
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "backends/native/meta-render-device-private.h"
|
|
|
|
#include "backends/meta-backend-private.h"
|
|
#include "backends/meta-egl.h"
|
|
#include "backends/native/meta-backend-native-types.h"
|
|
#include "backends/native/meta-drm-buffer-dumb.h"
|
|
|
|
enum
|
|
{
|
|
PROP_0,
|
|
|
|
PROP_BACKEND,
|
|
PROP_DEVICE_FILE,
|
|
|
|
N_PROPS
|
|
};
|
|
|
|
static GParamSpec *obj_props[N_PROPS];
|
|
|
|
typedef struct _MetaRenderDevicePrivate
|
|
{
|
|
MetaBackend *backend;
|
|
|
|
MetaDeviceFile *device_file;
|
|
|
|
EGLDisplay egl_display;
|
|
EGLConfig egl_config;
|
|
|
|
gboolean is_hardware_rendering;
|
|
} MetaRenderDevicePrivate;
|
|
|
|
static void
|
|
initable_iface_init (GInitableIface *initable_iface);
|
|
|
|
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MetaRenderDevice, meta_render_device,
|
|
G_TYPE_OBJECT,
|
|
G_ADD_PRIVATE (MetaRenderDevice)
|
|
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
|
|
initable_iface_init))
|
|
|
|
static EGLDisplay
|
|
meta_render_device_create_egl_display (MetaRenderDevice *render_device,
|
|
GError **error)
|
|
{
|
|
MetaRenderDeviceClass *klass = META_RENDER_DEVICE_GET_CLASS (render_device);
|
|
|
|
return klass->create_egl_display (render_device, error);
|
|
}
|
|
|
|
static void
|
|
detect_hardware_rendering (MetaRenderDevice *render_device)
|
|
{
|
|
MetaRenderDevicePrivate *priv =
|
|
meta_render_device_get_instance_private (render_device);
|
|
MetaEgl *egl = meta_backend_get_egl (priv->backend);
|
|
g_autoptr (GError) error = NULL;
|
|
EGLint *attributes;
|
|
EGLContext egl_context;
|
|
const char *renderer_str;
|
|
|
|
attributes = (EGLint[]) {
|
|
EGL_CONTEXT_CLIENT_VERSION, 2,
|
|
EGL_NONE
|
|
};
|
|
egl_context = meta_egl_create_context (egl,
|
|
priv->egl_display,
|
|
EGL_NO_CONFIG_KHR,
|
|
EGL_NO_CONTEXT,
|
|
attributes,
|
|
&error);
|
|
if (egl_context == EGL_NO_CONTEXT)
|
|
{
|
|
meta_topic (META_DEBUG_RENDER, "Failed to create EGLContext for %s: %s",
|
|
meta_device_file_get_path (priv->device_file),
|
|
error->message);
|
|
return;
|
|
}
|
|
|
|
if (!meta_egl_make_current (egl,
|
|
priv->egl_display,
|
|
EGL_NO_SURFACE,
|
|
EGL_NO_SURFACE,
|
|
egl_context,
|
|
&error))
|
|
{
|
|
g_warning ("Failed to detect hardware rendering: eglMakeCurrent(): %s",
|
|
error->message);
|
|
goto out_has_context;
|
|
}
|
|
|
|
renderer_str = (const char *) glGetString (GL_RENDERER);
|
|
if (g_str_has_prefix (renderer_str, "llvmpipe") ||
|
|
g_str_has_prefix (renderer_str, "softpipe") ||
|
|
g_str_has_prefix (renderer_str, "swrast"))
|
|
goto out_current_context;
|
|
|
|
priv->is_hardware_rendering = TRUE;
|
|
|
|
out_current_context:
|
|
meta_egl_make_current (egl, priv->egl_display,
|
|
EGL_NO_SURFACE, EGL_NO_SURFACE,
|
|
EGL_NO_CONTEXT, NULL);
|
|
|
|
out_has_context:
|
|
meta_egl_destroy_context (egl, priv->egl_display, egl_context, NULL);
|
|
}
|
|
|
|
static void
|
|
init_egl (MetaRenderDevice *render_device)
|
|
{
|
|
MetaRenderDevicePrivate *priv =
|
|
meta_render_device_get_instance_private (render_device);
|
|
MetaEgl *egl = meta_backend_get_egl (priv->backend);
|
|
g_autoptr (GError) error = NULL;
|
|
EGLDisplay egl_display;
|
|
|
|
meta_egl_bind_api (egl, EGL_OPENGL_ES_API, NULL);
|
|
|
|
egl_display = meta_render_device_create_egl_display (render_device, &error);
|
|
if (egl_display == EGL_NO_DISPLAY)
|
|
{
|
|
meta_topic (META_DEBUG_RENDER, "Failed to create EGLDisplay for %s: %s",
|
|
meta_device_file_get_path (priv->device_file),
|
|
error->message);
|
|
return;
|
|
}
|
|
|
|
priv->egl_display = egl_display;
|
|
detect_hardware_rendering (render_device);
|
|
}
|
|
|
|
static gboolean
|
|
meta_render_device_initable_init (GInitable *initable,
|
|
GCancellable *cancellable,
|
|
GError **error)
|
|
{
|
|
MetaRenderDevice *render_device = META_RENDER_DEVICE (initable);
|
|
|
|
init_egl (render_device);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
initable_iface_init (GInitableIface *initable_iface)
|
|
{
|
|
initable_iface->init = meta_render_device_initable_init;
|
|
}
|
|
|
|
static void
|
|
meta_render_device_get_property (GObject *object,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
MetaRenderDevice *render_device = META_RENDER_DEVICE (object);
|
|
MetaRenderDevicePrivate *priv =
|
|
meta_render_device_get_instance_private (render_device);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_BACKEND:
|
|
g_value_set_object (value, priv->backend);
|
|
break;
|
|
case PROP_DEVICE_FILE:
|
|
g_value_set_pointer (value, priv->device_file);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
meta_render_device_set_property (GObject *object,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
MetaRenderDevice *render_device = META_RENDER_DEVICE (object);
|
|
MetaRenderDevicePrivate *priv =
|
|
meta_render_device_get_instance_private (render_device);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_BACKEND:
|
|
priv->backend = g_value_get_object (value);
|
|
break;
|
|
case PROP_DEVICE_FILE:
|
|
priv->device_file = g_value_get_pointer (value);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
meta_render_device_dispose (GObject *object)
|
|
{
|
|
MetaRenderDevice *render_device = META_RENDER_DEVICE (object);
|
|
MetaRenderDevicePrivate *priv =
|
|
meta_render_device_get_instance_private (render_device);
|
|
MetaEgl *egl = meta_backend_get_egl (priv->backend);
|
|
|
|
if (priv->egl_display != EGL_NO_DISPLAY)
|
|
{
|
|
meta_egl_terminate (egl, priv->egl_display, NULL);
|
|
priv->egl_display = EGL_NO_DISPLAY;
|
|
}
|
|
|
|
G_OBJECT_CLASS (meta_render_device_parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
meta_render_device_finalize (GObject *object)
|
|
{
|
|
MetaRenderDevice *render_device = META_RENDER_DEVICE (object);
|
|
MetaRenderDevicePrivate *priv =
|
|
meta_render_device_get_instance_private (render_device);
|
|
|
|
g_clear_pointer (&priv->device_file, meta_device_file_release);
|
|
|
|
G_OBJECT_CLASS (meta_render_device_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
meta_render_device_constructed (GObject *object)
|
|
{
|
|
MetaRenderDevice *render_device = META_RENDER_DEVICE (object);
|
|
MetaRenderDevicePrivate *priv =
|
|
meta_render_device_get_instance_private (render_device);
|
|
|
|
if (priv->device_file)
|
|
meta_device_file_acquire (priv->device_file);
|
|
|
|
G_OBJECT_CLASS (meta_render_device_parent_class)->constructed (object);
|
|
}
|
|
|
|
static void
|
|
meta_render_device_class_init (MetaRenderDeviceClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
object_class->get_property = meta_render_device_get_property;
|
|
object_class->set_property = meta_render_device_set_property;
|
|
object_class->constructed = meta_render_device_constructed;
|
|
object_class->dispose = meta_render_device_dispose;
|
|
object_class->finalize = meta_render_device_finalize;
|
|
|
|
obj_props[PROP_BACKEND] =
|
|
g_param_spec_object ("backend", NULL, NULL,
|
|
META_TYPE_BACKEND,
|
|
G_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
G_PARAM_STATIC_STRINGS);
|
|
obj_props[PROP_DEVICE_FILE] =
|
|
g_param_spec_pointer ("device-file", NULL, NULL,
|
|
G_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
G_PARAM_STATIC_STRINGS);
|
|
g_object_class_install_properties (object_class, N_PROPS, obj_props);
|
|
}
|
|
|
|
static void
|
|
meta_render_device_init (MetaRenderDevice *render_device)
|
|
{
|
|
MetaRenderDevicePrivate *priv =
|
|
meta_render_device_get_instance_private (render_device);
|
|
|
|
priv->egl_display = EGL_NO_DISPLAY;
|
|
priv->egl_config = EGL_NO_CONFIG_KHR;
|
|
}
|
|
|
|
MetaBackend *
|
|
meta_render_device_get_backend (MetaRenderDevice *render_device)
|
|
{
|
|
MetaRenderDevicePrivate *priv =
|
|
meta_render_device_get_instance_private (render_device);
|
|
|
|
return priv->backend;
|
|
}
|
|
|
|
MetaDeviceFile *
|
|
meta_render_device_get_device_file (MetaRenderDevice *render_device)
|
|
{
|
|
MetaRenderDevicePrivate *priv =
|
|
meta_render_device_get_instance_private (render_device);
|
|
|
|
return priv->device_file;
|
|
}
|
|
|
|
EGLDisplay
|
|
meta_render_device_get_egl_display (MetaRenderDevice *render_device)
|
|
{
|
|
MetaRenderDevicePrivate *priv =
|
|
meta_render_device_get_instance_private (render_device);
|
|
|
|
return priv->egl_display;
|
|
}
|
|
|
|
gboolean
|
|
meta_render_device_is_hardware_accelerated (MetaRenderDevice *render_device)
|
|
{
|
|
MetaRenderDevicePrivate *priv =
|
|
meta_render_device_get_instance_private (render_device);
|
|
|
|
return priv->is_hardware_rendering;
|
|
}
|
|
|
|
const char *
|
|
meta_render_device_get_name (MetaRenderDevice *render_device)
|
|
{
|
|
MetaRenderDevicePrivate *priv =
|
|
meta_render_device_get_instance_private (render_device);
|
|
|
|
if (priv->device_file)
|
|
return meta_device_file_get_path (priv->device_file);
|
|
else
|
|
return "(device-less)";
|
|
}
|
|
|
|
MetaDrmBuffer *
|
|
meta_render_device_allocate_dma_buf (MetaRenderDevice *render_device,
|
|
int width,
|
|
int height,
|
|
uint32_t format,
|
|
MetaDrmBufferFlags flags,
|
|
GError **error)
|
|
{
|
|
MetaRenderDeviceClass *klass = META_RENDER_DEVICE_GET_CLASS (render_device);
|
|
|
|
if (klass->allocate_dma_buf)
|
|
{
|
|
return klass->allocate_dma_buf (render_device,
|
|
width, height, format,
|
|
flags,
|
|
error);
|
|
}
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
"Render device '%s' doesn't support allocating DMA buffers",
|
|
meta_render_device_get_name (render_device));
|
|
|
|
return NULL;
|
|
}
|
|
|
|
MetaDrmBuffer *
|
|
meta_render_device_import_dma_buf (MetaRenderDevice *render_device,
|
|
MetaDrmBuffer *buffer,
|
|
GError **error)
|
|
{
|
|
MetaRenderDeviceClass *klass = META_RENDER_DEVICE_GET_CLASS (render_device);
|
|
|
|
if (klass->import_dma_buf)
|
|
return klass->import_dma_buf (render_device, buffer, error);
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
"Render device '%s' doesn't importing DMA buffers",
|
|
meta_render_device_get_name (render_device));
|
|
|
|
return NULL;
|
|
}
|
|
|
|
MetaDrmBuffer *
|
|
meta_render_device_allocate_dumb_buf (MetaRenderDevice *render_device,
|
|
int width,
|
|
int height,
|
|
uint32_t format,
|
|
GError **error)
|
|
{
|
|
MetaRenderDevicePrivate *priv =
|
|
meta_render_device_get_instance_private (render_device);
|
|
MetaDrmBufferDumb *buffer_dumb;
|
|
|
|
if (!priv->device_file)
|
|
{
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
|
"No device file to allocate from");
|
|
return NULL;
|
|
}
|
|
|
|
buffer_dumb = meta_drm_buffer_dumb_new (priv->device_file,
|
|
width, height,
|
|
format,
|
|
error);
|
|
if (!buffer_dumb)
|
|
return NULL;
|
|
|
|
return META_DRM_BUFFER (buffer_dumb);
|
|
}
|