Commit fecc57dd authored by Daniel van Vugt's avatar Daniel van Vugt Committed by Jonas Ådahl
Browse files

renderer-native: Reference count front buffers

Start reference counting front buffers instead of assuming we know
their (scanout) lifetimes.

Functionally, this should not change anything.

!119
parent 0d7a929b
Pipeline #83253 passed with stages
in 3 minutes and 57 seconds
/*
* 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.
*
* Author: Daniel van Vugt <daniel.van.vugt@canonical.com>
*/
#include "backends/native/meta-kms-buffer.h"
#include "config.h"
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <drm_fourcc.h>
#include <errno.h>
#define INVALID_FB_ID 0U
typedef enum _MetaKmsBufferType
{
META_KMS_BUFFER_TYPE_GBM,
META_KMS_BUFFER_TYPE_WRAPPED_DUMB
} MetaKmsBufferType;
struct _MetaKmsBuffer
{
GObject parent;
MetaKmsBufferType type;
union
{
uint32_t fb_id;
struct
{
uint32_t fb_id;
struct gbm_surface *surface;
struct gbm_bo *bo;
MetaGpuKms *gpu_kms;
} gbm;
struct
{
uint32_t fb_id;
} wrapped_dumb;
};
};
G_DEFINE_TYPE (MetaKmsBuffer, meta_kms_buffer, G_TYPE_OBJECT)
static gboolean
meta_kms_buffer_acquire_swapped_buffer (MetaKmsBuffer *kms_buffer,
gboolean use_modifiers,
GError **error)
{
uint32_t handles[4] = {0, 0, 0, 0};
uint32_t strides[4] = {0, 0, 0, 0};
uint32_t offsets[4] = {0, 0, 0, 0};
uint64_t modifiers[4] = {0, 0, 0, 0};
uint32_t width, height, format;
struct gbm_bo *bo;
int i;
int drm_fd;
g_return_val_if_fail (META_IS_KMS_BUFFER (kms_buffer), FALSE);
g_return_val_if_fail (kms_buffer->type == META_KMS_BUFFER_TYPE_GBM, FALSE);
g_return_val_if_fail (kms_buffer->gbm.bo == NULL, FALSE);
g_return_val_if_fail (kms_buffer->gbm.surface != NULL, FALSE);
g_return_val_if_fail (kms_buffer->gbm.gpu_kms != NULL, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
drm_fd = meta_gpu_kms_get_fd (kms_buffer->gbm.gpu_kms);
g_return_val_if_fail (drm_fd >= 0, FALSE);
bo = gbm_surface_lock_front_buffer (kms_buffer->gbm.surface);
if (!bo)
{
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_FAILED,
"gbm_surface_lock_front_buffer failed");
return FALSE;
}
if (gbm_bo_get_handle_for_plane (bo, 0).s32 == -1)
{
/* Failed to fetch handle to plane, falling back to old method */
strides[0] = gbm_bo_get_stride (bo);
handles[0] = gbm_bo_get_handle (bo).u32;
offsets[0] = 0;
modifiers[0] = DRM_FORMAT_MOD_INVALID;
}
else
{
for (i = 0; i < gbm_bo_get_plane_count (bo); i++)
{
strides[i] = gbm_bo_get_stride_for_plane (bo, i);
handles[i] = gbm_bo_get_handle_for_plane (bo, i).u32;
offsets[i] = gbm_bo_get_offset (bo, i);
modifiers[i] = gbm_bo_get_modifier (bo);
}
}
width = gbm_bo_get_width (bo);
height = gbm_bo_get_height (bo);
format = gbm_bo_get_format (bo);
if (use_modifiers && modifiers[0] != DRM_FORMAT_MOD_INVALID)
{
if (drmModeAddFB2WithModifiers (drm_fd,
width,
height,
format,
handles,
strides,
offsets,
modifiers,
&kms_buffer->fb_id,
DRM_MODE_FB_MODIFIERS))
{
g_set_error (error,
G_IO_ERROR,
g_io_error_from_errno (errno),
"drmModeAddFB2WithModifiers failed: %s",
g_strerror (errno));
gbm_surface_release_buffer (kms_buffer->gbm.surface, bo);
return FALSE;
}
}
else if (drmModeAddFB2 (drm_fd,
width,
height,
format,
handles,
strides,
offsets,
&kms_buffer->fb_id,
0))
{
if (format != DRM_FORMAT_XRGB8888)
{
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_FAILED,
"drmModeAddFB does not support format 0x%x",
format);
gbm_surface_release_buffer (kms_buffer->gbm.surface, bo);
return FALSE;
}
if (drmModeAddFB (drm_fd,
width,
height,
24,
32,
strides[0],
handles[0],
&kms_buffer->fb_id))
{
g_set_error (error,
G_IO_ERROR,
g_io_error_from_errno (errno),
"drmModeAddFB failed: %s",
g_strerror (errno));
gbm_surface_release_buffer (kms_buffer->gbm.surface, bo);
return FALSE;
}
}
kms_buffer->gbm.bo = bo;
return TRUE;
}
static void
meta_kms_buffer_init (MetaKmsBuffer *kms_buffer)
{
}
static void
meta_kms_buffer_finalize (GObject *object)
{
MetaKmsBuffer *kms_buffer = META_KMS_BUFFER (object);
if (kms_buffer->type == META_KMS_BUFFER_TYPE_GBM)
{
if (kms_buffer->gbm.gpu_kms != NULL &&
kms_buffer->gbm.fb_id != INVALID_FB_ID)
{
int drm_fd = meta_gpu_kms_get_fd (kms_buffer->gbm.gpu_kms);
drmModeRmFB (drm_fd, kms_buffer->fb_id);
kms_buffer->fb_id = INVALID_FB_ID;
}
if (kms_buffer->gbm.surface &&
kms_buffer->gbm.bo)
{
gbm_surface_release_buffer (kms_buffer->gbm.surface,
kms_buffer->gbm.bo);
}
}
G_OBJECT_CLASS (meta_kms_buffer_parent_class)->finalize (object);
}
static void
meta_kms_buffer_class_init (MetaKmsBufferClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_kms_buffer_finalize;
}
MetaKmsBuffer *
meta_kms_buffer_new_from_gbm (MetaGpuKms *gpu_kms,
struct gbm_surface *gbm_surface,
gboolean use_modifiers,
GError **error)
{
MetaKmsBuffer *kms_buffer;
g_return_val_if_fail (META_IS_GPU_KMS (gpu_kms), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
kms_buffer = g_object_new (META_TYPE_KMS_BUFFER, NULL);
kms_buffer->type = META_KMS_BUFFER_TYPE_GBM;
kms_buffer->gbm.gpu_kms = gpu_kms;
kms_buffer->gbm.surface = gbm_surface;
if (!meta_kms_buffer_acquire_swapped_buffer (kms_buffer,
use_modifiers,
error))
{
g_object_unref (kms_buffer);
return NULL;
}
return kms_buffer;
}
MetaKmsBuffer *
meta_kms_buffer_new_from_dumb (uint32_t dumb_fb_id)
{
MetaKmsBuffer *kms_buffer;
kms_buffer = g_object_new (META_TYPE_KMS_BUFFER, NULL);
kms_buffer->type = META_KMS_BUFFER_TYPE_WRAPPED_DUMB;
kms_buffer->wrapped_dumb.fb_id = dumb_fb_id;
return kms_buffer;
}
uint32_t
meta_kms_buffer_get_fb_id (const MetaKmsBuffer *kms_buffer)
{
g_return_val_if_fail (kms_buffer != NULL, INVALID_FB_ID);
return kms_buffer->fb_id;
}
struct gbm_bo *
meta_kms_buffer_get_bo (const MetaKmsBuffer *kms_buffer)
{
g_return_val_if_fail (kms_buffer != NULL, NULL);
g_return_val_if_fail (kms_buffer->type == META_KMS_BUFFER_TYPE_GBM, NULL);
return kms_buffer->gbm.bo;
}
/*
* 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.
*
* Author: Daniel van Vugt <daniel.van.vugt@canonical.com>
*/
#ifndef META_KMS_BUFFER_H
#define META_KMS_BUFFER_H
#include <gbm.h>
#include <glib-object.h>
#include "backends/native/meta-gpu-kms.h"
#define META_TYPE_KMS_BUFFER (meta_kms_buffer_get_type ())
G_DECLARE_FINAL_TYPE (MetaKmsBuffer,
meta_kms_buffer,
META,
KMS_BUFFER,
GObject)
MetaKmsBuffer *
meta_kms_buffer_new_from_gbm (MetaGpuKms *gpu_kms,
struct gbm_surface *gbm_surface,
gboolean use_modifiers,
GError **error);
MetaKmsBuffer *
meta_kms_buffer_new_from_dumb (uint32_t dumb_fb_id);
uint32_t meta_kms_buffer_get_fb_id (const MetaKmsBuffer *kms_buffer);
struct gbm_bo *meta_kms_buffer_get_bo (const MetaKmsBuffer *kms_buffer);
#endif /* META_KMS_BUFFER_H */
......@@ -59,6 +59,7 @@
#include "backends/meta-renderer-view.h"
#include "backends/native/meta-crtc-kms.h"
#include "backends/native/meta-gpu-kms.h"
#include "backends/native/meta-kms-buffer.h"
#include "backends/native/meta-monitor-manager-kms.h"
#include "backends/native/meta-renderer-native-gles3.h"
#include "backends/native/meta-renderer-native.h"
......@@ -144,10 +145,8 @@ typedef struct _MetaOnscreenNativeSecondaryGpuState
struct {
struct gbm_surface *surface;
uint32_t current_fb_id;
uint32_t next_fb_id;
struct gbm_bo *current_bo;
struct gbm_bo *next_bo;
MetaKmsBuffer *current_fb;
MetaKmsBuffer *next_fb;
} gbm;
struct {
......@@ -168,10 +167,8 @@ typedef struct _MetaOnscreenNative
struct {
struct gbm_surface *surface;
uint32_t current_fb_id;
uint32_t next_fb_id;
struct gbm_bo *current_bo;
struct gbm_bo *next_bo;
MetaKmsBuffer *current_fb;
MetaKmsBuffer *next_fb;
} gbm;
#ifdef HAVE_EGL_DEVICE
......@@ -971,25 +968,12 @@ free_current_secondary_bo (MetaGpuKms *gpu_kms,
MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state)
{
MetaRendererNativeGpuData *renderer_gpu_data;
int kms_fd;
kms_fd = meta_gpu_kms_get_fd (gpu_kms);
renderer_gpu_data = secondary_gpu_state->renderer_gpu_data;
switch (renderer_gpu_data->secondary.copy_mode)
{
case META_SHARED_FRAMEBUFFER_COPY_MODE_GPU:
if (secondary_gpu_state->gbm.current_fb_id)
{
drmModeRmFB (kms_fd, secondary_gpu_state->gbm.current_fb_id);
secondary_gpu_state->gbm.current_fb_id = 0;
}
if (secondary_gpu_state->gbm.current_bo)
{
gbm_surface_release_buffer (secondary_gpu_state->gbm.surface,
secondary_gpu_state->gbm.current_bo);
secondary_gpu_state->gbm.current_bo = NULL;
}
g_clear_object (&secondary_gpu_state->gbm.current_fb);
break;
case META_SHARED_FRAMEBUFFER_COPY_MODE_CPU:
break;
......@@ -1001,22 +985,8 @@ free_current_bo (CoglOnscreen *onscreen)
{
CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
MetaGpuKms *render_gpu = onscreen_native->render_gpu;
int kms_fd;
kms_fd = meta_gpu_kms_get_fd (render_gpu);
if (onscreen_native->gbm.current_fb_id)
{
drmModeRmFB (kms_fd, onscreen_native->gbm.current_fb_id);
onscreen_native->gbm.current_fb_id = 0;
}
if (onscreen_native->gbm.current_bo)
{
gbm_surface_release_buffer (onscreen_native->gbm.surface,
onscreen_native->gbm.current_bo);
onscreen_native->gbm.current_bo = NULL;
}
g_clear_object (&onscreen_native->gbm.current_fb);
g_hash_table_foreach (onscreen_native->secondary_gpu_states,
(GHFunc) free_current_secondary_bo,
......@@ -1310,11 +1280,9 @@ static void
swap_secondary_drm_fb (MetaGpuKms *gpu_kms,
MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state)
{
secondary_gpu_state->gbm.current_fb_id = secondary_gpu_state->gbm.next_fb_id;
secondary_gpu_state->gbm.next_fb_id = 0;
secondary_gpu_state->gbm.current_bo = secondary_gpu_state->gbm.next_bo;
secondary_gpu_state->gbm.next_bo = NULL;
g_set_object (&secondary_gpu_state->gbm.current_fb,
secondary_gpu_state->gbm.next_fb);
g_clear_object (&secondary_gpu_state->gbm.next_fb);
}
static void
......@@ -1325,11 +1293,8 @@ meta_onscreen_native_swap_drm_fb (CoglOnscreen *onscreen)
free_current_bo (onscreen);
onscreen_native->gbm.current_fb_id = onscreen_native->gbm.next_fb_id;
onscreen_native->gbm.next_fb_id = 0;
onscreen_native->gbm.current_bo = onscreen_native->gbm.next_bo;
onscreen_native->gbm.next_bo = NULL;
g_set_object (&onscreen_native->gbm.current_fb, onscreen_native->gbm.next_fb);
g_clear_object (&onscreen_native->gbm.next_fb);
g_hash_table_foreach (onscreen_native->secondary_gpu_states,
(GHFunc) swap_secondary_drm_fb,
......@@ -1413,17 +1378,7 @@ free_next_secondary_bo (MetaGpuKms *gpu_kms,
switch (renderer_gpu_data->secondary.copy_mode)
{
case META_SHARED_FRAMEBUFFER_COPY_MODE_GPU:
if (secondary_gpu_state->gbm.next_fb_id)
{
int kms_fd;
kms_fd = meta_gpu_kms_get_fd (gpu_kms);
drmModeRmFB (kms_fd, secondary_gpu_state->gbm.next_fb_id);
gbm_surface_release_buffer (secondary_gpu_state->gbm.surface,
secondary_gpu_state->gbm.next_bo);
secondary_gpu_state->gbm.next_fb_id = 0;
secondary_gpu_state->gbm.next_bo = NULL;
}
g_clear_object (&secondary_gpu_state->gbm.next_fb);
break;
case META_SHARED_FRAMEBUFFER_COPY_MODE_CPU:
break;
......@@ -1448,17 +1403,7 @@ flip_closure_destroyed (MetaRendererView *view)
switch (renderer_gpu_data->mode)
{
case META_RENDERER_NATIVE_MODE_GBM:
if (onscreen_native->gbm.next_fb_id)
{
int kms_fd;
kms_fd = meta_gpu_kms_get_fd (render_gpu);
drmModeRmFB (kms_fd, onscreen_native->gbm.next_fb_id);
gbm_surface_release_buffer (onscreen_native->gbm.surface,
onscreen_native->gbm.next_bo);
onscreen_native->gbm.next_bo = NULL;
onscreen_native->gbm.next_fb_id = 0;
}
g_clear_object (&onscreen_native->gbm.next_fb);
g_hash_table_foreach (onscreen_native->secondary_gpu_states,
(GHFunc) free_next_secondary_bo,
......@@ -1808,12 +1753,12 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen,
case META_RENDERER_NATIVE_MODE_GBM:
if (gpu_kms == render_gpu)
{
fb_id = onscreen_native->gbm.next_fb_id;
fb_id = meta_kms_buffer_get_fb_id (onscreen_native->gbm.next_fb);
}
else
{
secondary_gpu_state = get_secondary_gpu_state (onscreen, gpu_kms);
fb_id = secondary_gpu_state->gbm.next_fb_id;
fb_id = meta_kms_buffer_get_fb_id (secondary_gpu_state->gbm.next_fb);
}
if (!meta_gpu_kms_flip_crtc (gpu_kms,
......@@ -1879,7 +1824,7 @@ set_crtc_fb (CoglOnscreen *onscreen,
if (!secondary_gpu_state)
return;
fb_id = secondary_gpu_state->gbm.next_fb_id;
fb_id = meta_kms_buffer_get_fb_id (secondary_gpu_state->gbm.next_fb);
}
x = crtc->rect.x - logical_monitor->rect.x;
......@@ -1922,7 +1867,7 @@ meta_onscreen_native_set_crtc_modes (CoglOnscreen *onscreen)
switch (renderer_gpu_data->mode)
{
case META_RENDERER_NATIVE_MODE_GBM:
fb_id = onscreen_native->gbm.next_fb_id;
fb_id = meta_kms_buffer_get_fb_id (onscreen_native->gbm.next_fb);
break;
#ifdef HAVE_EGL_DEVICE
case META_RENDERER_NATIVE_MODE_EGL_DEVICE:
......@@ -1990,7 +1935,7 @@ crtc_mode_set_fallback (CoglOnscreen *onscreen,
return FALSE;
}
fb_id = onscreen_native->gbm.next_fb_id;
fb_id = meta_kms_buffer_get_fb_id (onscreen_native->gbm.next_fb);
set_crtc_fb (onscreen, logical_monitor, crtc, fb_id);
return TRUE;
}
......@@ -2090,101 +2035,6 @@ meta_onscreen_native_flip_crtcs (CoglOnscreen *onscreen)
g_closure_unref (flip_closure);
}
static gboolean
gbm_get_next_fb_id (MetaGpuKms *gpu_kms,
struct gbm_surface *gbm_surface,
struct gbm_bo **out_next_bo,
uint32_t *out_next_fb_id)
{
MetaRendererNative *renderer_native = meta_renderer_native_from_gpu (gpu_kms);
struct gbm_bo *next_bo;
uint32_t next_fb_id;
int kms_fd;
uint32_t handles[4] = { 0, };
uint32_t strides[4] = { 0, };
uint32_t offsets[4] = { 0, };
uint64_t modifiers[4] = { 0, };
int i;
/* Now we need to set the CRTC to whatever is the front buffer */
next_bo = gbm_surface_lock_front_buffer (gbm_surface);
if (!next_bo)
{
g_error ("Impossible to lock surface front buffer: %m");
return FALSE;
}
if (gbm_bo_get_handle_for_plane (next_bo, 0).s32 == -1)
{
/* Failed to fetch handle to plane, falling back to old method */
strides[0] = gbm_bo_get_stride (next_bo);
handles[0] = gbm_bo_get_handle (next_bo).u32;
offsets[0] = 0;
modifiers[0] = DRM_FORMAT_MOD_INVALID;
}
else
{
for (i = 0; i < gbm_bo_get_plane_count (next_bo); i++)
{
strides[i] = gbm_bo_get_stride_for_plane (next_bo, i);
handles[i] = gbm_bo_get_handle_for_plane (next_bo, i).u32;
offsets[i] = gbm_bo_get_offset (next_bo, i);
modifiers[i] = gbm_bo_get_modifier (next_bo);
}
}
kms_fd = meta_gpu_kms_get_fd (gpu_kms);
if (renderer_native->use_modifiers &&
modifiers[0] != DRM_FORMAT_MOD_INVALID)
{
if (drmModeAddFB2WithModifiers (kms_fd,
gbm_bo_get_width (next_bo),
gbm_bo_get_height (next_bo),
gbm_bo_get_format (next_bo),
handles,
strides,
offsets,
modifiers,
&next_fb_id,
DRM_MODE_FB_MODIFIERS))
{
g_warning ("Failed to create new back buffer handle: %m");
gbm_surface_release_buffer (gbm_surface, next_bo);
return FALSE;
}
}
else if (drmModeAddFB2 (kms_fd,
gbm_bo_get_width (next_bo),
gbm_bo_get_height (next_bo),
gbm_bo_get_format (next_bo),
handles,
strides,
offsets,
&next_fb_id,
0))
{
if (drmModeAddFB (kms_fd,
gbm_bo_get_width (next_bo),
gbm_bo_get_height (next_bo),
24, /* depth */
32, /* bpp */
strides[0],
handles[0],