1
0
Fork 0
mutter-performance-source/src/backends/native/meta-drm-buffer-dumb.c
Jonas Ådahl b3dffb43b3 drm-buffer: Don't always generate fb_id on construction
It might not be needed by the user of the buffer, so don't always
require it up front. Instead make sure that any user that needs it first
calls "meta_drm_buffer_ensure_fb_id()" to create the ID.

Only the plain gbm implementation creates the ID lazilly, the other
still does it on construction due to the objects used to create them
only existing during construction.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1854>
2021-10-18 17:33:33 +02:00

382 lines
10 KiB
C

/*
* Copyright (C) 2011 Intel Corporation.
* Copyright (C) 2016 Red Hat
* Copyright (C) 2018 DisplayLink (UK) Ltd.
* Copyright (C) 2018 Canonical Ltd.
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
*/
#include "config.h"
#include "backends/native/meta-drm-buffer-dumb.h"
#include <drm_fourcc.h>
#include <gio/gio.h>
#include <xf86drm.h>
#include <fcntl.h>
#include <sys/mman.h>
#include "backends/native/meta-device-pool.h"
struct _MetaDrmBufferDumb
{
MetaDrmBuffer parent;
uint32_t handle;
void *map;
uint64_t map_size;
int width;
int height;
int stride_bytes;
uint32_t drm_format;
int dmabuf_fd;
int offset;
};
G_DEFINE_TYPE (MetaDrmBufferDumb, meta_drm_buffer_dumb, META_TYPE_DRM_BUFFER)
static int
meta_drm_buffer_dumb_export_fd (MetaDrmBuffer *buffer,
GError **error)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
"Can't export fd for dumb buffer");
return -1;
}
static int
meta_drm_buffer_dumb_get_width (MetaDrmBuffer *buffer)
{
MetaDrmBufferDumb *buffer_dumb = META_DRM_BUFFER_DUMB (buffer);
return buffer_dumb->width;
}
static int
meta_drm_buffer_dumb_get_height (MetaDrmBuffer *buffer)
{
MetaDrmBufferDumb *buffer_dumb = META_DRM_BUFFER_DUMB (buffer);
return buffer_dumb->height;
}
static int
meta_drm_buffer_dumb_get_stride (MetaDrmBuffer *buffer)
{
MetaDrmBufferDumb *buffer_dumb = META_DRM_BUFFER_DUMB (buffer);
return buffer_dumb->stride_bytes;
}
static uint32_t
meta_drm_buffer_dumb_get_format (MetaDrmBuffer *buffer)
{
MetaDrmBufferDumb *buffer_dumb = META_DRM_BUFFER_DUMB (buffer);
return buffer_dumb->drm_format;
}
static int
meta_drm_buffer_dumb_get_bpp (MetaDrmBuffer *buffer)
{
MetaDrmBufferDumb *buffer_dumb = META_DRM_BUFFER_DUMB (buffer);
switch (buffer_dumb->drm_format)
{
case DRM_FORMAT_C8:
case DRM_FORMAT_R8:
case DRM_FORMAT_RGB332:
case DRM_FORMAT_BGR233:
return 8;
case DRM_FORMAT_GR88:
case DRM_FORMAT_XRGB4444:
case DRM_FORMAT_XBGR4444:
case DRM_FORMAT_RGBX4444:
case DRM_FORMAT_BGRX4444:
case DRM_FORMAT_ARGB4444:
case DRM_FORMAT_ABGR4444:
case DRM_FORMAT_RGBA4444:
case DRM_FORMAT_BGRA4444:
case DRM_FORMAT_XRGB1555:
case DRM_FORMAT_XBGR1555:
case DRM_FORMAT_RGBX5551:
case DRM_FORMAT_BGRX5551:
case DRM_FORMAT_ARGB1555:
case DRM_FORMAT_ABGR1555:
case DRM_FORMAT_RGBA5551:
case DRM_FORMAT_BGRA5551:
case DRM_FORMAT_RGB565:
case DRM_FORMAT_BGR565:
return 16;
case DRM_FORMAT_RGB888:
case DRM_FORMAT_BGR888:
return 24;
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_RGBX8888:
case DRM_FORMAT_BGRX8888:
case DRM_FORMAT_ARGB8888:
case DRM_FORMAT_ABGR8888:
case DRM_FORMAT_RGBA8888:
case DRM_FORMAT_BGRA8888:
case DRM_FORMAT_XRGB2101010:
case DRM_FORMAT_XBGR2101010:
case DRM_FORMAT_RGBX1010102:
case DRM_FORMAT_BGRX1010102:
case DRM_FORMAT_ARGB2101010:
case DRM_FORMAT_ABGR2101010:
case DRM_FORMAT_RGBA1010102:
case DRM_FORMAT_BGRA1010102:
return 32;
case DRM_FORMAT_XBGR16161616F:
case DRM_FORMAT_ABGR16161616F:
return 64;
default:
g_warn_if_reached ();
return 0;
}
}
static int
meta_drm_buffer_dumb_get_offset (MetaDrmBuffer *buffer,
int plane)
{
MetaDrmBufferDumb *buffer_dumb = META_DRM_BUFFER_DUMB (buffer);
g_warn_if_fail (plane == 0);
return buffer_dumb->offset;
}
static uint32_t
meta_drm_buffer_dumb_get_modifier (MetaDrmBuffer *buffer)
{
return DRM_FORMAT_MOD_LINEAR;
}
static int
handle_to_dmabuf_fd (MetaDrmBufferDumb *buffer_dumb,
GError **error)
{
MetaDrmBuffer *buffer = META_DRM_BUFFER (buffer_dumb);
MetaDeviceFile *device_file;
int fd;
int ret;
int dmabuf_fd;
device_file = meta_drm_buffer_get_device_file (buffer);
fd = meta_device_file_get_fd (device_file);
ret = drmPrimeHandleToFD (fd, buffer_dumb->handle, DRM_CLOEXEC,
&dmabuf_fd);
if (ret)
{
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ret),
"drmPrimeHandleToFd: %s", g_strerror (-ret));
return -1;
}
return dmabuf_fd;
}
int
meta_drm_buffer_dumb_ensure_dmabuf_fd (MetaDrmBufferDumb *buffer_dumb,
GError **error)
{
if (buffer_dumb->dmabuf_fd != -1)
return buffer_dumb->dmabuf_fd;
buffer_dumb->dmabuf_fd = handle_to_dmabuf_fd (buffer_dumb, error);
return buffer_dumb->dmabuf_fd;
}
void *
meta_drm_buffer_dumb_get_data (MetaDrmBufferDumb *buffer_dumb)
{
return buffer_dumb->map;
}
static gboolean
init_dumb_buffer (MetaDrmBufferDumb *buffer_dumb,
int width,
int height,
uint32_t format,
GError **error)
{
MetaDrmBuffer *buffer = META_DRM_BUFFER (buffer_dumb);
MetaDeviceFile *device_file;
int fd;
struct drm_mode_create_dumb create_arg;
struct drm_mode_destroy_dumb destroy_arg;
struct drm_mode_map_dumb map_arg;
void *map;
MetaDrmFbArgs fb_args;
device_file = meta_drm_buffer_get_device_file (buffer);
fd = meta_device_file_get_fd (device_file);
create_arg = (struct drm_mode_create_dumb) {
.bpp = 32, /* RGBX8888 */
.width = width,
.height = height
};
if (drmIoctl (fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg) != 0)
{
g_set_error (error, G_IO_ERROR,
G_IO_ERROR_FAILED,
"Failed to create dumb drm buffer: %s",
g_strerror (errno));
goto err_ioctl;
}
fb_args = (MetaDrmFbArgs) {
.width = width,
.height = height,
.format = format,
.handles = { create_arg.handle },
.strides = { create_arg.pitch },
};
if (!meta_drm_buffer_do_ensure_fb_id (buffer, &fb_args, error))
goto err_add_fb;
map_arg = (struct drm_mode_map_dumb) {
.handle = create_arg.handle
};
if (drmIoctl (fd, DRM_IOCTL_MODE_MAP_DUMB,
&map_arg) != 0)
{
g_set_error (error, G_IO_ERROR,
G_IO_ERROR_FAILED,
"Failed to map dumb drm buffer: %s",
g_strerror (errno));
goto err_map_dumb;
}
map = mmap (NULL, create_arg.size, PROT_WRITE, MAP_SHARED,
fd, map_arg.offset);
if (map == MAP_FAILED)
{
g_set_error (error, G_IO_ERROR,
G_IO_ERROR_FAILED,
"Failed to mmap dumb drm buffer memory: %s",
g_strerror (errno));
goto err_mmap;
}
buffer_dumb->handle = create_arg.handle;
buffer_dumb->map = map;
buffer_dumb->map_size = create_arg.size;
buffer_dumb->width = width;
buffer_dumb->height = height;
buffer_dumb->stride_bytes = create_arg.pitch;
buffer_dumb->drm_format = format;
buffer_dumb->offset = map_arg.offset;
return TRUE;
err_mmap:
err_map_dumb:
err_add_fb:
destroy_arg = (struct drm_mode_destroy_dumb) {
.handle = create_arg.handle
};
drmIoctl (fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
err_ioctl:
return FALSE;
}
MetaDrmBufferDumb *
meta_drm_buffer_dumb_new (MetaDeviceFile *device_file,
int width,
int height,
uint32_t format,
GError **error)
{
MetaDrmBufferDumb *buffer_dumb;
buffer_dumb = g_object_new (META_TYPE_DRM_BUFFER_DUMB,
"device-file", device_file,
"flags", META_DRM_BUFFER_FLAG_DISABLE_MODIFIERS,
NULL);
if (!init_dumb_buffer (buffer_dumb, width, height, format, error))
{
g_object_unref (buffer_dumb);
return NULL;
}
return buffer_dumb;
}
static void
destroy_dumb_buffer (MetaDrmBufferDumb *buffer_dumb)
{
MetaDrmBuffer *buffer = META_DRM_BUFFER (buffer_dumb);
MetaDeviceFile *device_file;
int fd;
struct drm_mode_destroy_dumb destroy_arg;
device_file = meta_drm_buffer_get_device_file (buffer);
fd = meta_device_file_get_fd (device_file);
munmap (buffer_dumb->map, buffer_dumb->map_size);
destroy_arg = (struct drm_mode_destroy_dumb) {
.handle = buffer_dumb->handle
};
drmIoctl (fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
if (buffer_dumb->dmabuf_fd != -1)
close (buffer_dumb->dmabuf_fd);
}
static void
meta_drm_buffer_dumb_finalize (GObject *object)
{
MetaDrmBufferDumb *buffer_dumb = META_DRM_BUFFER_DUMB (object);
if (buffer_dumb->handle)
destroy_dumb_buffer (buffer_dumb);
G_OBJECT_CLASS (meta_drm_buffer_dumb_parent_class)->finalize (object);
}
static void
meta_drm_buffer_dumb_init (MetaDrmBufferDumb *buffer_dumb)
{
buffer_dumb->dmabuf_fd = -1;
}
static void
meta_drm_buffer_dumb_class_init (MetaDrmBufferDumbClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
MetaDrmBufferClass *buffer_class = META_DRM_BUFFER_CLASS (klass);
object_class->finalize = meta_drm_buffer_dumb_finalize;
buffer_class->export_fd = meta_drm_buffer_dumb_export_fd;
buffer_class->get_width = meta_drm_buffer_dumb_get_width;
buffer_class->get_height = meta_drm_buffer_dumb_get_height;
buffer_class->get_stride = meta_drm_buffer_dumb_get_stride;
buffer_class->get_bpp = meta_drm_buffer_dumb_get_bpp;
buffer_class->get_format = meta_drm_buffer_dumb_get_format;
buffer_class->get_offset = meta_drm_buffer_dumb_get_offset;
buffer_class->get_modifier = meta_drm_buffer_dumb_get_modifier;
}