st/egl: Generalize wayland backend a bit

This commit is contained in:
Benjamin Franzke 2011-04-23 14:20:24 +02:00 committed by Kristian Høgsberg
parent aaa3c0d6de
commit 34fd282b27
3 changed files with 361 additions and 253 deletions

View File

@ -0,0 +1,303 @@
/*
* Mesa 3-D graphics library
* Version: 7.11
*
* Copyright (C) 2011 Benjamin Franzke <benjaminfranzke@googlemail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "util/u_memory.h"
#include "util/u_inlines.h"
#include "pipe/p_compiler.h"
#include "pipe/p_screen.h"
#include "pipe/p_context.h"
#include "pipe/p_state.h"
#include "state_tracker/drm_driver.h"
#include "egllog.h"
#include <errno.h>
#include "native_wayland.h"
/* see get_drm_screen_name */
#include <radeon_drm.h>
#include "radeon/drm/radeon_drm_public.h"
#include <wayland-client.h>
#include "wayland-drm-client-protocol.h"
#include "wayland-egl-priv.h"
#include <xf86drm.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
struct wayland_drm_display {
struct wayland_display base;
struct native_event_handler *event_handler;
struct wl_drm *wl_drm;
int fd;
char *device_name;
boolean authenticated;
};
static INLINE struct wayland_drm_display *
wayland_drm_display(const struct native_display *ndpy)
{
return (struct wayland_drm_display *) ndpy;
}
static void
sync_callback(void *data)
{
int *done = data;
*done = 1;
}
static void
force_roundtrip(struct wl_display *display)
{
int done = 0;
wl_display_sync_callback(display, sync_callback, &done);
wl_display_iterate(display, WL_DISPLAY_WRITABLE);
while (!done)
wl_display_iterate(display, WL_DISPLAY_READABLE);
}
static void
wayland_drm_display_destroy(struct native_display *ndpy)
{
struct wayland_drm_display *drmdpy = wayland_drm_display(ndpy);
if (drmdpy->fd)
close(drmdpy->fd);
if (drmdpy->wl_drm)
wl_drm_destroy(drmdpy->wl_drm);
if (drmdpy->device_name)
FREE(drmdpy->device_name);
if (drmdpy->base.config)
FREE(drmdpy->base.config);
ndpy_uninit(ndpy);
FREE(drmdpy);
}
static struct wl_buffer *
wayland_create_drm_buffer(struct wayland_display *display,
struct wayland_surface *surface,
enum native_attachment attachment)
{
struct wayland_drm_display *drmdpy = (struct wayland_drm_display *) display;
struct pipe_screen *screen = drmdpy->base.base.screen;
struct pipe_resource *resource;
struct winsys_handle wsh;
uint width, height;
struct wl_visual *visual;
resource = resource_surface_get_single_resource(surface->rsurf, attachment);
resource_surface_get_size(surface->rsurf, &width, &height);
wsh.type = DRM_API_HANDLE_TYPE_SHARED;
screen->resource_get_handle(screen, resource, &wsh);
pipe_resource_reference(&resource, NULL);
switch (surface->type) {
case WL_WINDOW_SURFACE:
visual = surface->win->visual;
break;
case WL_PIXMAP_SURFACE:
visual = surface->pix->visual;
break;
default:
return NULL;
}
return wl_drm_create_buffer(drmdpy->wl_drm, wsh.handle,
width, height, wsh.stride, visual);
}
static const char *
get_drm_screen_name(int fd, drmVersionPtr version)
{
const char *name = version->name;
if (name && !strcmp(name, "radeon")) {
int chip_id;
struct drm_radeon_info info;
memset(&info, 0, sizeof(info));
info.request = RADEON_INFO_DEVICE_ID;
info.value = pointer_to_intptr(&chip_id);
if (drmCommandWriteRead(fd, DRM_RADEON_INFO, &info, sizeof(info)) != 0)
return NULL;
name = is_r3xx(chip_id) ? "r300" : "r600";
}
return name;
}
static void
drm_handle_device(void *data, struct wl_drm *drm, const char *device)
{
struct wayland_drm_display *drmdpy = data;
drm_magic_t magic;
drmdpy->device_name = strdup(device);
if (!drmdpy->device_name)
return;
drmdpy->fd = open(drmdpy->device_name, O_RDWR);
if (drmdpy->fd == -1) {
_eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)",
drmdpy->device_name, strerror(errno));
return;
}
drmGetMagic(drmdpy->fd, &magic);
wl_drm_authenticate(drmdpy->wl_drm, magic);
}
static void
drm_handle_authenticated(void *data, struct wl_drm *drm)
{
struct wayland_drm_display *drmdpy = data;
drmdpy->authenticated = true;
}
static const struct wl_drm_listener drm_listener = {
drm_handle_device,
drm_handle_authenticated
};
static boolean
wayland_drm_display_init_screen(struct native_display *ndpy)
{
struct wayland_drm_display *drmdpy = wayland_drm_display(ndpy);
drmVersionPtr version;
const char *driver_name;
uint32_t id;
id = wl_display_get_global(drmdpy->base.dpy, "wl_drm", 1);
if (id == 0)
wl_display_iterate(drmdpy->base.dpy, WL_DISPLAY_READABLE);
id = wl_display_get_global(drmdpy->base.dpy, "wl_drm", 1);
if (id == 0)
return FALSE;
drmdpy->wl_drm = wl_drm_create(drmdpy->base.dpy, id, 1);
if (!drmdpy->wl_drm)
return FALSE;
wl_drm_add_listener(drmdpy->wl_drm, &drm_listener, drmdpy);
force_roundtrip(drmdpy->base.dpy);
if (drmdpy->fd == -1)
return FALSE;
force_roundtrip(drmdpy->base.dpy);
if (!drmdpy->authenticated)
return FALSE;
version = drmGetVersion(drmdpy->fd);
if (!version) {
_eglLog(_EGL_WARNING, "invalid fd %d", drmdpy->fd);
return FALSE;
}
/* FIXME: share this with native_drm or egl_dri2 */
driver_name = get_drm_screen_name(drmdpy->fd, version);
drmdpy->base.base.screen =
drmdpy->event_handler->new_drm_screen(&drmdpy->base.base,
driver_name, drmdpy->fd);
drmFreeVersion(version);
if (!drmdpy->base.base.screen) {
_eglLog(_EGL_WARNING, "failed to create DRM screen");
return FALSE;
}
return TRUE;
}
static struct pipe_resource *
wayland_drm_display_import_buffer(struct native_display *ndpy,
const struct pipe_resource *templ,
void *buf)
{
return ndpy->screen->resource_from_handle(ndpy->screen,
templ, (struct winsys_handle *) buf);
}
static boolean
wayland_drm_display_export_buffer(struct native_display *ndpy,
struct pipe_resource *res,
void *buf)
{
return ndpy->screen->resource_get_handle(ndpy->screen,
res, (struct winsys_handle *) buf);
}
static struct native_display_buffer wayland_drm_display_buffer = {
wayland_drm_display_import_buffer,
wayland_drm_display_export_buffer
};
struct wayland_display *
wayland_create_drm_display(struct wl_display *dpy,
struct native_event_handler *event_handler,
void *user_data)
{
struct wayland_drm_display *drmdpy;
drmdpy = CALLOC_STRUCT(wayland_drm_display);
if (!drmdpy)
return NULL;
drmdpy->event_handler = event_handler;
drmdpy->base.base.user_data = user_data;
drmdpy->base.dpy = dpy;
if (!drmdpy->base.dpy) {
wayland_drm_display_destroy(&drmdpy->base.base);
return NULL;
}
if (!wayland_drm_display_init_screen(&drmdpy->base.base)) {
wayland_drm_display_destroy(&drmdpy->base.base);
return NULL;
}
drmdpy->base.base.destroy = wayland_drm_display_destroy;
drmdpy->base.base.buffer = &wayland_drm_display_buffer;
drmdpy->base.create_buffer = wayland_create_drm_buffer;
return &drmdpy->base;
}
/* vim: set sw=3 ts=8 sts=3 expandtab: */

View File

@ -31,25 +31,10 @@
#include "pipe/p_context.h"
#include "pipe/p_state.h"
#include "state_tracker/drm_driver.h"
#include "egllog.h"
#include <errno.h>
#include "native_wayland.h"
/* see get_drm_screen_name */
#include <radeon_drm.h>
#include "radeon/drm/radeon_drm_public.h"
#include <wayland-client.h>
#include "wayland-drm-client-protocol.h"
#include "wayland-egl-priv.h"
#include <xf86drm.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
static struct native_event_handler *wayland_event_handler;
static void
@ -113,12 +98,12 @@ wayland_display_get_param(struct native_display *ndpy,
int val;
switch (param) {
case NATIVE_PARAM_USE_NATIVE_BUFFER:
case NATIVE_PARAM_PRESERVE_BUFFER:
case NATIVE_PARAM_MAX_SWAP_INTERVAL:
default:
val = 0;
break;
case NATIVE_PARAM_USE_NATIVE_BUFFER:
case NATIVE_PARAM_PRESERVE_BUFFER:
case NATIVE_PARAM_MAX_SWAP_INTERVAL:
default:
val = 0;
break;
}
return val;
@ -134,48 +119,6 @@ wayland_display_is_pixmap_supported(struct native_display *ndpy,
return TRUE;
}
static void
wayland_display_destroy(struct native_display *ndpy)
{
struct wayland_display *display = wayland_display(ndpy);
if (display->fd)
close(display->fd);
if (display->wl_drm)
wl_drm_destroy(display->wl_drm);
if (display->device_name)
FREE(display->device_name);
if (display->config)
FREE(display->config);
ndpy_uninit(ndpy);
FREE(display);
}
static struct wl_buffer *
wayland_create_buffer(struct wayland_surface *surface,
enum native_attachment attachment)
{
struct wayland_display *display = surface->display;
struct pipe_resource *resource;
struct winsys_handle wsh;
uint width, height;
resource = resource_surface_get_single_resource(surface->rsurf, attachment);
resource_surface_get_size(surface->rsurf, &width, &height);
wsh.type = DRM_API_HANDLE_TYPE_SHARED;
display->base.screen->resource_get_handle(display->base.screen, resource, &wsh);
pipe_resource_reference(&resource, NULL);
return wl_drm_create_buffer(display->wl_drm, wsh.handle,
width, height,
wsh.stride, surface->win->visual);
}
static void
wayland_pixmap_destroy(struct wl_egl_pixmap *egl_pixmap)
{
@ -188,7 +131,7 @@ wayland_pixmap_destroy(struct wl_egl_pixmap *egl_pixmap)
wl_buffer_destroy(egl_pixmap->buffer);
egl_pixmap->buffer = NULL;
}
egl_pixmap->driver_private = NULL;
egl_pixmap->destroy = NULL;
}
@ -196,26 +139,16 @@ wayland_pixmap_destroy(struct wl_egl_pixmap *egl_pixmap)
static void
wayland_pixmap_surface_initialize(struct wayland_surface *surface)
{
struct native_display *ndpy = &surface->display->base;
struct pipe_resource *resource;
struct winsys_handle wsh;
struct wayland_display *display = wayland_display(&surface->display->base);
const enum native_attachment front_natt = NATIVE_ATTACHMENT_FRONT_LEFT;
if (surface->pix->buffer != NULL)
return;
resource = resource_surface_get_single_resource(surface->rsurf, front_natt);
wsh.type = DRM_API_HANDLE_TYPE_SHARED;
ndpy->screen->resource_get_handle(ndpy->screen, resource, &wsh);
surface->pix->buffer =
wl_drm_create_buffer(surface->display->wl_drm, wsh.handle,
surface->pix->width, surface->pix->height,
wsh.stride, surface->pix->visual);
surface->pix->destroy = wayland_pixmap_destroy;
surface->pix->driver_private = resource;
surface->pix->buffer = display->create_buffer(display, surface, front_natt);
surface->pix->destroy = wayland_pixmap_destroy;
surface->pix->driver_private =
resource_surface_get_single_resource(surface->rsurf, front_natt);
}
static void
@ -237,11 +170,11 @@ wayland_window_surface_handle_resize(struct wayland_surface *surface)
struct pipe_resource *front_resource;
const enum native_attachment front_natt = NATIVE_ATTACHMENT_FRONT_LEFT;
int i;
front_resource = resource_surface_get_single_resource(surface->rsurf,
front_natt);
if (resource_surface_set_size(surface->rsurf,
surface->win->width, surface->win->height)) {
surface->win->width, surface->win->height)) {
if (surface->pending_resource)
force_roundtrip(display->dpy);
@ -328,17 +261,19 @@ wayland_surface_swap_buffers(struct native_surface *nsurf)
if (surface->type == WL_WINDOW_SURFACE) {
resource_surface_swap_buffers(surface->rsurf,
NATIVE_ATTACHMENT_FRONT_LEFT, NATIVE_ATTACHMENT_BACK_LEFT, FALSE);
NATIVE_ATTACHMENT_FRONT_LEFT,
NATIVE_ATTACHMENT_BACK_LEFT, FALSE);
wayland_buffers_swap(surface->buffer, WL_BUFFER_FRONT, WL_BUFFER_BACK);
if (surface->buffer[WL_BUFFER_FRONT] == NULL)
surface->buffer[WL_BUFFER_FRONT] =
wayland_create_buffer(surface, NATIVE_ATTACHMENT_FRONT_LEFT);
display->create_buffer(display, surface,
NATIVE_ATTACHMENT_FRONT_LEFT);
wl_surface_attach(surface->win->surface, surface->buffer[WL_BUFFER_FRONT],
surface->dx, surface->dy);
resource_surface_get_size(surface->rsurf,
(uint *) &surface->win->attached_width,
(uint *) &surface->win->attached_height);
@ -348,7 +283,8 @@ wayland_surface_swap_buffers(struct native_surface *nsurf)
surface->sequence_number++;
wayland_event_handler->invalid_surface(&display->base,
&surface->base, surface->sequence_number);
&surface->base,
surface->sequence_number);
return TRUE;
}
@ -408,6 +344,8 @@ wayland_surface_destroy(struct native_surface *nsurf)
FREE(surface);
}
static struct native_surface *
wayland_create_pixmap_surface(struct native_display *ndpy,
EGLNativePixmapType pix,
@ -417,6 +355,8 @@ wayland_create_pixmap_surface(struct native_display *ndpy,
struct wayland_surface *surface;
struct wl_egl_pixmap *egl_pixmap = (struct wl_egl_pixmap *) pix;
enum native_attachment natt = NATIVE_ATTACHMENT_FRONT_LEFT;
uint bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW |
PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SCANOUT;
surface = CALLOC_STRUCT(wayland_surface);
if (!surface)
@ -434,15 +374,13 @@ wayland_create_pixmap_surface(struct native_display *ndpy,
surface->color_format = PIPE_FORMAT_B8G8R8A8_UNORM;
surface->attachment_mask = (1 << NATIVE_ATTACHMENT_FRONT_LEFT);
surface->rsurf = resource_surface_create(display->base.screen,
surface->color_format,
PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW |
PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SCANOUT);
surface->color_format, bind);
if (!surface->rsurf) {
FREE(surface);
return NULL;
FREE(surface);
return NULL;
}
resource_surface_set_size(surface->rsurf,
@ -461,6 +399,7 @@ wayland_create_pixmap_surface(struct native_display *ndpy,
return &surface->base;
}
static struct native_surface *
wayland_create_window_surface(struct native_display *ndpy,
EGLNativeWindowType win,
@ -469,6 +408,8 @@ wayland_create_window_surface(struct native_display *ndpy,
struct wayland_display *display = wayland_display(ndpy);
struct wayland_config *config = wayland_config(nconf);
struct wayland_surface *surface;
uint bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW |
PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SCANOUT;
surface = CALLOC_STRUCT(wayland_surface);
if (!surface)
@ -486,16 +427,14 @@ wayland_create_window_surface(struct native_display *ndpy,
surface->buffer[WL_BUFFER_FRONT] = NULL;
surface->buffer[WL_BUFFER_BACK] = NULL;
surface->attachment_mask = (1 << NATIVE_ATTACHMENT_FRONT_LEFT) |
(1 << NATIVE_ATTACHMENT_BACK_LEFT);
(1 << NATIVE_ATTACHMENT_BACK_LEFT);
surface->rsurf = resource_surface_create(display->base.screen,
surface->color_format,
PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW |
PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SCANOUT);
surface->color_format, bind);
if (!surface->rsurf) {
FREE(surface);
return NULL;
FREE(surface);
return NULL;
}
surface->base.destroy = wayland_surface_destroy;
@ -506,178 +445,36 @@ wayland_create_window_surface(struct native_display *ndpy,
return &surface->base;
}
static const char *
get_drm_screen_name(int fd, drmVersionPtr version)
{
const char *name = version->name;
if (name && !strcmp(name, "radeon")) {
int chip_id;
struct drm_radeon_info info;
memset(&info, 0, sizeof(info));
info.request = RADEON_INFO_DEVICE_ID;
info.value = pointer_to_intptr(&chip_id);
if (drmCommandWriteRead(fd, DRM_RADEON_INFO, &info, sizeof(info)) != 0)
return NULL;
name = is_r3xx(chip_id) ? "r300" : "r600";
}
return name;
}
static void
drm_handle_device(void *data, struct wl_drm *drm, const char *device)
{
struct wayland_display *display = data;
drm_magic_t magic;
display->device_name = strdup(device);
if (!display->device_name)
return;
display->fd = open(display->device_name, O_RDWR);
if (display->fd == -1) {
_eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)",
display->device_name, strerror(errno));
return;
}
drmGetMagic(display->fd, &magic);
wl_drm_authenticate(display->wl_drm, magic);
}
static void
drm_handle_authenticated(void *data, struct wl_drm *drm)
{
struct wayland_display *display = data;
display->authenticated = true;
}
static const struct wl_drm_listener drm_listener = {
drm_handle_device,
drm_handle_authenticated
};
static boolean
wayland_display_init_screen(struct native_display *ndpy)
{
struct wayland_display *display = wayland_display(ndpy);
drmVersionPtr version;
const char *driver_name;
uint32_t id;
id = wl_display_get_global(display->dpy, "wl_drm", 1);
if (id == 0)
wl_display_iterate(display->dpy, WL_DISPLAY_READABLE);
id = wl_display_get_global(display->dpy, "wl_drm", 1);
if (id == 0)
return FALSE;
display->wl_drm = wl_drm_create(display->dpy, id, 1);
if (!display->wl_drm)
return FALSE;
wl_drm_add_listener(display->wl_drm, &drm_listener, display);
force_roundtrip(display->dpy);
if (display->fd == -1)
return FALSE;
force_roundtrip(display->dpy);
if (!display->authenticated)
return FALSE;
version = drmGetVersion(display->fd);
if (!version) {
_eglLog(_EGL_WARNING, "invalid fd %d", display->fd);
return FALSE;
}
/* FIXME: share this with native_drm or egl_dri2 */
driver_name = get_drm_screen_name(display->fd, version);
display->base.screen =
wayland_event_handler->new_drm_screen(&display->base,
driver_name, display->fd);
drmFreeVersion(version);
if (!display->base.screen) {
_eglLog(_EGL_WARNING, "failed to create DRM screen");
return FALSE;
}
return TRUE;
}
static void
wayland_set_event_handler(struct native_event_handler *event_handler)
native_set_event_handler(struct native_event_handler *event_handler)
{
wayland_event_handler = event_handler;
}
static struct pipe_resource *
wayland_display_import_buffer(struct native_display *ndpy,
const struct pipe_resource *templ,
void *buf)
{
return ndpy->screen->resource_from_handle(ndpy->screen,
templ, (struct winsys_handle *) buf);
}
static boolean
wayland_display_export_buffer(struct native_display *ndpy,
struct pipe_resource *res,
void *buf)
{
return ndpy->screen->resource_get_handle(ndpy->screen,
res, (struct winsys_handle *) buf);
}
static struct native_display_buffer wayland_display_buffer = {
wayland_display_import_buffer,
wayland_display_export_buffer
};
static struct native_display *
wayland_display_create(void *dpy, boolean use_sw, void *user_data)
native_create_display(void *dpy, boolean use_sw, void *user_data)
{
struct wayland_display *display;
struct wayland_display *display = NULL;
display = CALLOC_STRUCT(wayland_display);
display = wayland_create_drm_display((struct wl_display *) dpy,
wayland_event_handler,
user_data);
if (!display)
return NULL;
display->base.user_data = user_data;
display->dpy = dpy;
if (!display->dpy) {
wayland_display_destroy(&display->base);
return NULL;
}
if (!wayland_display_init_screen(&display->base)) {
wayland_display_destroy(&display->base);
return NULL;
}
display->base.destroy = wayland_display_destroy;
display->base.get_param = wayland_display_get_param;
display->base.get_configs = wayland_display_get_configs;
display->base.is_pixmap_supported = wayland_display_is_pixmap_supported;
display->base.create_window_surface = wayland_create_window_surface;
display->base.create_pixmap_surface = wayland_create_pixmap_surface;
display->base.buffer = &wayland_display_buffer;
return &display->base;
}
static const struct native_platform wayland_platform = {
"wayland", /* name */
wayland_set_event_handler,
wayland_display_create
native_set_event_handler,
native_create_display
};
const struct native_platform *
@ -685,3 +482,5 @@ native_get_wayland_platform(void)
{
return &wayland_platform;
}
/* vim: set sw=3 ts=8 sts=3 expandtab: */

View File

@ -33,17 +33,18 @@
#include "common/native_helper.h"
#include "wayland-egl-priv.h"
#include "wayland-drm-client-protocol.h"
struct wayland_surface;
struct wayland_display {
struct native_display base;
struct wayland_config *config;
struct wl_display *dpy;
struct wl_drm *wl_drm;
int fd;
char *device_name;
boolean authenticated;
struct wl_buffer *(*create_buffer)(struct wayland_display *display,
struct wayland_surface *surface,
enum native_attachment attachment);
};
enum wayland_buffer_type {
@ -78,7 +79,7 @@ struct wayland_surface {
};
struct wayland_config {
struct native_config base;
struct native_config base;
};
static INLINE struct wayland_display *
@ -99,4 +100,9 @@ wayland_config(const struct native_config *nconf)
return (struct wayland_config *) nconf;
}
struct wayland_display *
wayland_create_drm_display(struct wl_display *display,
struct native_event_handler *event_handler,
void *user_data);
#endif /* _NATIVE_WAYLAND_H_ */