modesetting: Add infrastructure for creating and mapping gbm bo's

Signed-off-by: stefan11111 <stefan11111@shitposting.expert>
This commit is contained in:
stefan11111
2026-02-06 16:20:17 +02:00
committed by Enrico Weigelt
parent 55eba2385c
commit a1872f51fb
5 changed files with 400 additions and 25 deletions

View File

@@ -0,0 +1,332 @@
/* SPDX-License-Identifier: MIT OR X11
*
* Copyright © 2026 stefan11111 <stefan11111@shitposting.expert>
*/
#include <stddef.h>
#include <stdint.h>
#include "dix-config.h"
#include "dix.h" /* ARRAY_SIZE() */
#include "dix/dix_priv.h"
#include <drm_fourcc.h>
#include <drm_mode.h>
#include <xf86drm.h>
#include "xf86Crtc.h"
#include "driver.h"
#include "drmmode_bo.h"
typedef struct {
void* map_data; /* Opaque ptr for the mapped region */
void* map_addr; /* Address of the map, what we actually want to use */
Bool used_modifiers;
} bo_priv_t;
#ifndef GBM_BO_USE_LINEAR
#define GBM_BO_USE_LINEAR 0
#endif
#ifndef GBM_BO_USE_FRONT_RENDERING
#define GBM_BO_USE_FRONT_RENDERING 0
#endif
/**
* Thin wrapper around gbm_bo_{create,map,unmap}
* that creates and maps (if necessary) the "best"
* buffer of a certain type that we can create.
*
* Any needed mapping is done when creating the buffer,
* and unmapping is handeled automatically by the gbm
* loader through the destroy_user_data callback.
*/
#define TRY_CREATE(proc, data, do_map, ...) \
do { \
struct gbm_bo *ret = (proc)(__VA_ARGS__); \
if (ret && (!(do_map) || gbm_bo_map_or_free(ret, (data)))) { \
return ret; \
} \
} while (0);
static inline uint32_t
get_opaque_format(uint32_t format)
{
switch (format) {
case DRM_FORMAT_ARGB8888:
return DRM_FORMAT_XRGB8888;
case DRM_FORMAT_ARGB2101010:
return DRM_FORMAT_XRGB2101010;
default:
return format;
}
}
static void
destroy_user_data(struct gbm_bo *bo, void* _data)
{
bo_priv_t *data = _data;
if (!data) {
return;
}
if (data->map_data) {
gbm_bo_unmap(bo, data->map_data);
}
free(data);
}
void*
gbm_bo_get_map(struct gbm_bo *bo)
{
bo_priv_t *data = gbm_bo_get_user_data(bo);
return data ? data->map_addr : NULL;
}
Bool
gbm_bo_get_used_modifiers(struct gbm_bo *bo)
{
bo_priv_t *data = gbm_bo_get_user_data(bo);
return data ? data->used_modifiers : FALSE;
}
static inline Bool
gbm_bo_map_all(struct gbm_bo *bo, bo_priv_t *data)
{
uint32_t stride = 0;
if (!bo || !data) {
return FALSE;
}
if (data->map_addr) {
return TRUE;
}
uint32_t width = gbm_bo_get_width(bo);
uint32_t height = gbm_bo_get_height(bo);
/* must be NULL before the map call */
data->map_data = NULL;
/* While reading from gpu memory is often very slow, we do allow it */
data->map_addr = gbm_bo_map(bo, 0, 0, width, height,
GBM_BO_TRANSFER_READ_WRITE,
&stride, &data->map_data);
return !!data->map_addr;
}
static inline Bool
gbm_bo_map_or_free(struct gbm_bo *bo, bo_priv_t *data)
{
if (gbm_bo_map_all(bo, data)) {
return TRUE;
}
if (bo) {
gbm_bo_destroy(bo);
}
return FALSE;
}
static inline struct gbm_bo*
gbm_bo_create_and_map(struct gbm_device *gbm,
bo_priv_t *data,
Bool do_map,
uint32_t width, uint32_t height,
uint32_t format,
const uint64_t *modifiers,
const unsigned int count,
uint32_t flags)
{
if (!data) {
return NULL;
}
#ifdef GBM_BO_WITH_MODIFIERS
if (count && modifiers) {
data->used_modifiers = TRUE;
#ifdef GBM_BO_WITH_MODIFIERS2
TRY_CREATE(gbm_bo_create_with_modifiers2, data, do_map,
gbm, width, height, format, modifiers, count, flags);
#endif
TRY_CREATE(gbm_bo_create_with_modifiers, data, do_map,
gbm, width, height, format, modifiers, count);
}
#endif
data->used_modifiers = FALSE;
TRY_CREATE(gbm_bo_create, data, do_map,
gbm, width, height, format, flags);
return NULL;
}
static inline struct gbm_bo*
gbm_bo_create_and_map_with_flag_list(struct gbm_device *gbm,
bo_priv_t *data,
Bool do_map,
uint32_t width, uint32_t height,
uint32_t format,
const uint64_t *modifiers,
const unsigned int count,
const uint32_t *flag_list,
unsigned int flag_count)
{
struct gbm_bo *ret = NULL;
for (unsigned int i = 0; i < flag_count && !ret; i++) {
ret = gbm_bo_create_and_map(gbm, data, do_map,
width, height, format,
modifiers, count,
flag_list[i]);
}
return ret;
}
static inline struct gbm_bo*
gbm_create_front_bo(drmmode_ptr drmmode, Bool do_map,
bo_priv_t *data,
unsigned width, unsigned height)
{
uint32_t format = drmmode_gbm_format_for_depth(drmmode->scrn->depth);
uint32_t num_modifiers = 0;
uint64_t *modifiers = NULL;
static const uint32_t front_flag_list[] = { /* best flags */
GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT |
GBM_BO_USE_FRONT_RENDERING,
/* if front_rendering is unsupported */
GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT,
/* linear buffers */
GBM_BO_USE_LINEAR | GBM_BO_USE_SCANOUT |
GBM_BO_USE_FRONT_RENDERING,
GBM_BO_USE_WRITE | GBM_BO_USE_SCANOUT,
};
#ifdef GBM_BO_WITH_MODIFIERS
num_modifiers = get_modifiers_set(drmmode->scrn, format, &modifiers,
FALSE, TRUE, TRUE);
#endif
return gbm_bo_create_and_map_with_flag_list(drmmode->gbm,
data,
do_map,
width, height,
format,
modifiers, num_modifiers,
front_flag_list,
ARRAY_SIZE(front_flag_list));
}
static inline struct gbm_bo*
gbm_create_cursor_bo(drmmode_ptr drmmode, Bool do_map,
bo_priv_t *data,
uint32_t width, uint32_t height)
{
static const uint32_t cursor_flag_list[] = { /* best flags */
GBM_BO_USE_CURSOR,
#if 0 /* Use these ones too if we ever need to */
GBM_BO_USE_CURSOR | GBM_BO_USE_LINEAR,
GBM_BO_USE_LINEAR,
#endif
/* For older mesa */
GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE,
};
/* Assume whatever bpp we have for the primary plane, we also have for the cursor plane */
int bpp = drmmode->kbpp;
/**
* Assume the depth for the cursor is the same as the bpp,
* even if this is not true for the primary plane (e.g., even if bpp is 32, but drmmode->scrn->depth is 24).
*/
uint32_t format = drmmode_gbm_format_for_depth(bpp);
return gbm_bo_create_and_map_with_flag_list(drmmode->gbm,
data,
do_map,
width, height,
format,
NULL, 0,
cursor_flag_list,
ARRAY_SIZE(cursor_flag_list));
}
struct gbm_bo*
gbm_create_best_bo(drmmode_ptr drmmode, Bool do_map,
uint32_t width, uint32_t height,
int type)
{
struct gbm_bo *ret = NULL;
bo_priv_t* data = calloc(1, sizeof(*data));
if (!data) {
return NULL;
}
switch (type) {
case DRMMODE_FRONT_BO:
ret = gbm_create_front_bo(drmmode, do_map, data, width, height);
break;
case DRMMODE_CURSOR_BO:
ret = gbm_create_cursor_bo(drmmode, do_map, data, width, height);
break;
}
if (!ret) {
free(data);
return NULL;
}
gbm_bo_set_user_data(ret, data, destroy_user_data);
return ret;
}
/* dmabuf import */
struct gbm_bo*
gbm_back_bo_from_fd(drmmode_ptr drmmode, Bool do_map, int fd_handle, uint32_t pitch, uint32_t size)
{
/* pitch == width * cpp */
int width = pitch / drmmode->cpp;
/* size == pitch * height */
int height = size / pitch;
int depth = drmmode->scrn->depth > 0 ?
drmmode->scrn->depth : drmmode->kbpp;
uint32_t format = drmmode_gbm_format_for_depth(depth);
struct gbm_import_fd_data import_data = {.fd = fd_handle,
.width = width,
.height = height,
.stride = pitch,
.format = format,
};
bo_priv_t* data = calloc(1, sizeof(*data));
if (!data) {
return NULL;
}
data->used_modifiers = FALSE;
TRY_CREATE(gbm_bo_import, data, do_map,
drmmode->gbm, GBM_BO_IMPORT_FD, &import_data,
GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT);
TRY_CREATE(gbm_bo_import, data, do_map,
drmmode->gbm, GBM_BO_IMPORT_FD, &import_data,
GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT | GBM_BO_USE_WRITE);
return NULL;
}

View File

@@ -0,0 +1,58 @@
/* SPDX-License-Identifier: MIT OR X11
*
* Copyright © 2026 stefan11111 <stefan11111@shitposting.expert>
*/
#ifndef DRMMODE_BO_H
#define DRMMODE_BO_H
#include <gbm.h>
#include "drmmode_display.h"
enum {
DRMMODE_FRONT_BO = 1 << 0,
DRMMODE_CURSOR_BO = 1 << 1,
DRMMODE_SHADOW_BO = 1 << 2,
};
void*
gbm_bo_get_map(struct gbm_bo *bo);
Bool
gbm_bo_get_used_modifiers(struct gbm_bo *bo);
/* Create the best gbm bo of a given type */
struct gbm_bo*
gbm_create_best_bo(drmmode_ptr drmmode, Bool do_map,
uint32_t width, uint32_t height,
int type);
/* dmabuf import */
struct gbm_bo*
gbm_back_bo_from_fd(drmmode_ptr drmmode, Bool do_map,
int fd_handle, uint32_t pitch, uint32_t size);
static inline uint32_t
drmmode_gbm_format_for_depth(int depth)
{
switch (depth) {
case 8:
return GBM_FORMAT_R8;
case 15:
return GBM_FORMAT_ARGB1555;
case 16:
return GBM_FORMAT_RGB565;
case 24:
return GBM_FORMAT_XRGB8888;
case 30:
/* XXX Is this format right? https://github.com/X11Libre/xserver/pull/1396/files#r2523698616 XXX */
return GBM_FORMAT_ARGB2101010;
case 32:
return GBM_FORMAT_ARGB8888;
}
/* Unsupported depth */
return GBM_FORMAT_ARGB8888;
}
#endif /* DRMMODE_BO_H */

View File

@@ -51,7 +51,7 @@
#include <xf86drm.h>
#include "xf86Crtc.h"
#include "drmmode_display.h"
#include "drmmode_bo.h"
#include <cursorstr.h>
@@ -183,7 +183,7 @@ drmmode_is_format_supported(ScrnInfoPtr scrn, uint32_t format,
}
#ifdef GBM_BO_WITH_MODIFIERS
static uint32_t
uint32_t
get_modifiers_set(ScrnInfoPtr scrn, uint32_t format, uint64_t **modifiers,
Bool enabled_crtc_only, Bool exclude_multiplane, Bool async_flip)
{
@@ -1162,29 +1162,6 @@ drmmode_bo_import(drmmode_ptr drmmode, drmmode_bo *bo,
drmmode_bo_get_handle(bo), fb_id);
}
#ifdef GLAMOR_HAS_GBM
/* formats taken from glamor/glamor_egl.c */
static inline uint32_t
drmmode_gbm_format_for_depth(int depth)
{
switch (depth) {
case 8:
return GBM_FORMAT_R8;
case 15:
return GBM_FORMAT_ARGB1555;
case 16:
return GBM_FORMAT_RGB565;
case 24:
return GBM_FORMAT_XRGB8888;
case 30:
/* XXX Is this format right? https://github.com/X11Libre/xserver/pull/1396/files#r2523698616 XXX */
return GBM_FORMAT_ARGB2101010;
default:
return GBM_FORMAT_ARGB8888;
}
}
#endif
static Bool
drmmode_create_front_bo(drmmode_ptr drmmode, drmmode_bo *bo,
unsigned width, unsigned height, unsigned bpp)

View File

@@ -373,4 +373,11 @@ Bool drmmode_crtc_get_fb_id(xf86CrtcPtr crtc, uint32_t *fb_id, int *x, int *y);
void drmmode_set_dpms(ScrnInfoPtr scrn, int PowerManagementMode, int flags);
void drmmode_crtc_set_vrr(xf86CrtcPtr crtc, Bool enabled);
#ifdef GBM_BO_WITH_MODIFIERS
uint32_t
get_modifiers_set(ScrnInfoPtr scrn, uint32_t format, uint64_t **modifiers,
Bool enabled_crtc_only, Bool exclude_multiplane, Bool async_flip);
#endif
#endif

View File

@@ -1,6 +1,7 @@
modesetting_srcs = [
'dri2.c',
'driver.c',
'drmmode_bo.c',
'drmmode_display.c',
'dumb_bo.c',
'pageflip.c',