egl/x11/sw: Implement shm support

Reviewed-by: Adam Jackson <ajax@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/29910>
This commit is contained in:
Lucas Fryzek
2024-06-21 07:54:18 +01:00
committed by Marge Bot
parent 71a97b2047
commit ba1a6a7e38
2 changed files with 172 additions and 5 deletions

View File

@@ -37,6 +37,7 @@
#include <unistd.h>
/* clang-format off */
#include <xcb/xcb.h>
#include <xcb/shm.h>
#include <vulkan/vulkan_core.h>
#include <vulkan/vulkan_xcb.h>
/* clang-format on */
@@ -46,6 +47,7 @@
#include "util/bitscan.h"
#include "util/macros.h"
#include "util/u_debug.h"
#include "util/log.h"
#include <sys/stat.h>
#include <sys/types.h>
@@ -224,8 +226,9 @@ swrastPutImage(__DRIdrawable *draw, int op, int x, int y, int w, int h,
}
static void
swrastGetImage(__DRIdrawable *read, int x, int y, int w, int h, char *data,
void *loaderPrivate)
swrastGetImage2(__DRIdrawable * read,
int x, int y, int w, int h, int stride,
char *data, void *loaderPrivate)
{
struct dri2_egl_surface *dri2_surf = loaderPrivate;
struct dri2_egl_display *dri2_dpy =
@@ -247,11 +250,120 @@ swrastGetImage(__DRIdrawable *read, int x, int y, int w, int h, char *data,
} else {
uint32_t bytes = xcb_get_image_data_length(reply);
uint8_t *idata = xcb_get_image_data(reply);
memcpy(data, idata, bytes);
int stride_b = w * dri2_surf->bytes_per_pixel;
/* Only copy line by line if we have a different stride */
if (stride != stride_b) {
for (int i = 0; i < h; i++) {
memcpy(data, idata, stride_b);
data += stride;
idata += stride_b;
}
} else {
memcpy(data, idata, bytes);
}
}
free(reply);
}
static void
swrastGetImage(__DRIdrawable *read, int x, int y, int w, int h, char *data,
void *loaderPrivate)
{
struct dri2_egl_surface *dri2_surf = loaderPrivate;
int stride_b = w * dri2_surf->bytes_per_pixel;
swrastGetImage2(read, x, y, w, h, stride_b, data, loaderPrivate);
}
static void
swrastPutImageShm(__DRIdrawable * draw, int op,
int x, int y, int w, int h, int stride,
int shmid, char *shmaddr, unsigned offset,
void *loaderPrivate)
{
struct dri2_egl_surface *dri2_surf = loaderPrivate;
struct dri2_egl_display *dri2_dpy =
dri2_egl_display(dri2_surf->base.Resource.Display);
xcb_generic_error_t *error = NULL;
xcb_shm_seg_t shm_seg = xcb_generate_id(dri2_dpy->conn);
error = xcb_request_check(dri2_dpy->conn,
xcb_shm_attach_checked(dri2_dpy->conn,
shm_seg, shmid, 0));
if (error) {
mesa_loge("Failed to attach to x11 shm");
_eglError(EGL_BAD_SURFACE, "xcb_shm_attach_checked");
free(error);
return;
}
xcb_gcontext_t gc;
xcb_void_cookie_t cookie;
switch (op) {
case __DRI_SWRAST_IMAGE_OP_DRAW:
gc = dri2_surf->gc;
break;
case __DRI_SWRAST_IMAGE_OP_SWAP:
gc = dri2_surf->swapgc;
break;
default:
return;
}
cookie = xcb_shm_put_image(dri2_dpy->conn,
dri2_surf->drawable,
gc,
stride / dri2_surf->bytes_per_pixel, h,
x, 0,
w, h,
x, y,
dri2_surf->depth,
XCB_IMAGE_FORMAT_Z_PIXMAP,
0, shm_seg, stride * y);
xcb_discard_reply(dri2_dpy->conn, cookie.sequence);
xcb_flush(dri2_dpy->conn);
xcb_shm_detach(dri2_dpy->conn, shm_seg);
}
static void
swrastGetImageShm(__DRIdrawable * read,
int x, int y, int w, int h,
int shmid, void *loaderPrivate)
{
struct dri2_egl_surface *dri2_surf = loaderPrivate;
struct dri2_egl_display *dri2_dpy =
dri2_egl_display(dri2_surf->base.Resource.Display);
xcb_generic_error_t *error = NULL;
xcb_shm_seg_t shm_seg = xcb_generate_id(dri2_dpy->conn);
error = xcb_request_check(dri2_dpy->conn,
xcb_shm_attach_checked(dri2_dpy->conn,
shm_seg, shmid, 0));
if (error) {
mesa_loge("Failed to attach to x11 shm");
_eglError(EGL_BAD_SURFACE, "xcb_shm_attach_checked");
free(error);
return;
}
xcb_shm_get_image_cookie_t cookie;
xcb_shm_get_image_reply_t *reply;
cookie = xcb_shm_get_image(dri2_dpy->conn,
dri2_surf->drawable,
x, y,
w, h,
~0, XCB_IMAGE_FORMAT_Z_PIXMAP,
shm_seg, 0);
reply = xcb_shm_get_image_reply(dri2_dpy->conn, cookie, NULL);
if (reply == NULL)
_eglLog(_EGL_WARNING, "error in xcb_shm_get_image");
else
free(reply);
xcb_shm_detach(dri2_dpy->conn, shm_seg);
}
static xcb_screen_t *
get_xcb_screen(xcb_screen_iterator_t iter, int screen)
{
@@ -1475,6 +1587,18 @@ static const __DRIswrastLoaderExtension swrast_loader_extension = {
.getImage = swrastGetImage,
};
static const __DRIswrastLoaderExtension swrast_loader_shm_extension = {
.base = {__DRI_SWRAST_LOADER, 4},
.getDrawableInfo = swrastGetDrawableInfo,
.putImage = swrastPutImage,
.putImage2 = swrastPutImage2,
.putImageShm = swrastPutImageShm,
.getImage = swrastGetImage,
.getImage2 = swrastGetImage2,
.getImageShm = swrastGetImageShm,
};
static_assert(sizeof(struct kopper_vk_surface_create_storage) >=
sizeof(VkXcbSurfaceCreateInfoKHR),
"");
@@ -1511,6 +1635,13 @@ static const __DRIextension *swrast_loader_extensions[] = {
NULL,
};
static const __DRIextension *swrast_loader_shm_extensions[] = {
&swrast_loader_shm_extension.base,
&image_lookup_extension.base,
&kopper_loader_extension.base,
NULL,
};
static int
dri2_find_screen_for_display(const _EGLDisplay *disp, int fallback_screen)
{
@@ -1595,6 +1726,38 @@ dri2_x11_setup_swap_interval(_EGLDisplay *disp)
dri2_setup_swap_interval(disp, arbitrary_max_interval);
}
static bool
check_xshm(struct dri2_egl_display *dri2_dpy)
{
xcb_void_cookie_t cookie;
xcb_generic_error_t *error;
int ret = true;
xcb_query_extension_cookie_t shm_cookie;
xcb_query_extension_reply_t *shm_reply;
bool has_mit_shm;
shm_cookie = xcb_query_extension(dri2_dpy->conn, 7, "MIT-SHM");
shm_reply = xcb_query_extension_reply(dri2_dpy->conn, shm_cookie, NULL);
has_mit_shm = shm_reply->present;
free(shm_reply);
if (!has_mit_shm)
return false;
cookie = xcb_shm_detach_checked(dri2_dpy->conn, 0);
if ((error = xcb_request_check(dri2_dpy->conn, cookie))) {
/* BadRequest means we're a remote client. If we were local we'd
* expect BadValue since 'info' has an invalid segment name.
*/
if (error->error_code == BadRequest)
ret = false;
free(error);
}
return ret;
}
static EGLBoolean
dri2_initialize_x11_swrast(_EGLDisplay *disp)
{
@@ -1619,7 +1782,11 @@ dri2_initialize_x11_swrast(_EGLDisplay *disp)
if (!dri2_load_driver_swrast(disp))
goto cleanup;
dri2_dpy->loader_extensions = swrast_loader_extensions;
if (check_xshm(dri2_dpy)) {
dri2_dpy->loader_extensions = swrast_loader_shm_extensions;
} else {
dri2_dpy->loader_extensions = swrast_loader_extensions;
}
if (!dri2_create_screen(disp))
goto cleanup;

View File

@@ -99,7 +99,7 @@ if with_dri2
files_egl += files('drivers/dri2/platform_x11_dri3.c')
link_for_egl += libloader_dri3_helper
endif
deps_for_egl += [dep_x11_xcb, dep_xcb_dri2, dep_xcb_xrandr, dep_xcb_xfixes]
deps_for_egl += [dep_x11_xcb, dep_xcb_dri2, dep_xcb_xrandr, dep_xcb_xfixes, dep_xcb_shm]
endif
if with_gbm and not with_platform_android
files_egl += files('drivers/dri2/platform_drm.c')