native_drm.c revision 93a96abe16068fa3ca8a1eb8d1c34195bffdc470
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.11 4 * 5 * Copyright (C) 2011 Benjamin Franzke <benjaminfranzke@googlemail.com> 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 * DEALINGS IN THE SOFTWARE. 24 */ 25 26#include "util/u_memory.h" 27#include "util/u_inlines.h" 28 29#include "pipe/p_compiler.h" 30#include "pipe/p_screen.h" 31#include "pipe/p_context.h" 32#include "pipe/p_state.h" 33#include "state_tracker/drm_driver.h" 34 35#include "egllog.h" 36#include <errno.h> 37 38#include "native_wayland.h" 39 40#include <wayland-client.h> 41#include "wayland-drm-client-protocol.h" 42#include "wayland-egl-priv.h" 43 44#include "common/native_wayland_drm_bufmgr_helper.h" 45 46#include <xf86drm.h> 47#include <sys/types.h> 48#include <sys/stat.h> 49#include <fcntl.h> 50 51struct wayland_drm_display { 52 struct wayland_display base; 53 54 const struct native_event_handler *event_handler; 55 56 struct wl_drm *wl_drm; 57 struct wl_drm *wl_server_drm; /* for EGL_WL_bind_wayland_display */ 58 int fd; 59 char *device_name; 60 boolean authenticated; 61 62 /* supported formats */ 63 boolean argb32; 64 boolean argb32_pre; 65 boolean xrgb32; 66}; 67 68static INLINE struct wayland_drm_display * 69wayland_drm_display(const struct native_display *ndpy) 70{ 71 return (struct wayland_drm_display *) ndpy; 72} 73 74static void 75wayland_drm_display_destroy(struct native_display *ndpy) 76{ 77 struct wayland_drm_display *drmdpy = wayland_drm_display(ndpy); 78 79 if (drmdpy->fd) 80 close(drmdpy->fd); 81 if (drmdpy->wl_drm) 82 wl_drm_destroy(drmdpy->wl_drm); 83 if (drmdpy->device_name) 84 FREE(drmdpy->device_name); 85 if (drmdpy->base.configs) 86 FREE(drmdpy->base.configs); 87 if (drmdpy->base.own_dpy) 88 wl_display_destroy(drmdpy->base.dpy); 89 90 ndpy_uninit(ndpy); 91 92 FREE(drmdpy); 93} 94 95static struct wl_buffer * 96wayland_create_drm_buffer(struct wayland_display *display, 97 struct wayland_surface *surface, 98 enum native_attachment attachment) 99{ 100 struct wayland_drm_display *drmdpy = (struct wayland_drm_display *) display; 101 struct pipe_screen *screen = drmdpy->base.base.screen; 102 struct pipe_resource *resource; 103 struct winsys_handle wsh; 104 uint width, height; 105 uint32_t format; 106 107 resource = resource_surface_get_single_resource(surface->rsurf, attachment); 108 resource_surface_get_size(surface->rsurf, &width, &height); 109 110 wsh.type = DRM_API_HANDLE_TYPE_SHARED; 111 screen->resource_get_handle(screen, resource, &wsh); 112 113 pipe_resource_reference(&resource, NULL); 114 115 switch (surface->color_format) { 116 case PIPE_FORMAT_B8G8R8A8_UNORM: 117 /* assume premultiplied */ 118 format = WL_DRM_FORMAT_PREMULTIPLIED_ARGB32; 119 break; 120 case PIPE_FORMAT_B8G8R8X8_UNORM: 121 format = WL_DRM_FORMAT_XRGB32; 122 break; 123 default: 124 return NULL; 125 break; 126 } 127 128 return wl_drm_create_buffer(drmdpy->wl_drm, wsh.handle, 129 width, height, wsh.stride, format); 130} 131 132static boolean 133wayland_drm_display_add_configs(struct wayland_drm_display *drmdpy) 134{ 135 struct wayland_config *configs; 136 enum pipe_format formats[2]; 137 int i, num_formats = 0; 138 139 /* 140 * Only argb32 counts here. If we make (!argbb32 && argb32_pre) count, we 141 * will not be able to support the case where 142 * native_present_control::premultiplied_alpha is FALSE. 143 */ 144 if (drmdpy->argb32) 145 formats[num_formats++] = PIPE_FORMAT_B8G8R8A8_UNORM; 146 147 if (drmdpy->xrgb32) 148 formats[num_formats++] = PIPE_FORMAT_B8G8R8X8_UNORM; 149 150 if (!num_formats) 151 return FALSE; 152 153 configs = CALLOC(num_formats, sizeof(*configs)); 154 if (!configs) 155 return FALSE; 156 157 for (i = 0; i < num_formats; i++) { 158 struct native_config *nconf = &configs[i].base; 159 160 nconf->buffer_mask = 161 (1 << NATIVE_ATTACHMENT_FRONT_LEFT) | 162 (1 << NATIVE_ATTACHMENT_BACK_LEFT); 163 164 nconf->color_format = formats[i]; 165 166 nconf->window_bit = TRUE; 167 nconf->pixmap_bit = TRUE; 168 } 169 170 drmdpy->base.configs = configs; 171 drmdpy->base.num_configs = num_formats; 172 173 return TRUE; 174} 175 176static void 177drm_handle_device(void *data, struct wl_drm *drm, const char *device) 178{ 179 struct wayland_drm_display *drmdpy = data; 180 drm_magic_t magic; 181 182 drmdpy->device_name = strdup(device); 183 if (!drmdpy->device_name) 184 return; 185 186 drmdpy->fd = open(drmdpy->device_name, O_RDWR); 187 if (drmdpy->fd == -1) { 188 _eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)", 189 drmdpy->device_name, strerror(errno)); 190 return; 191 } 192 193 drmGetMagic(drmdpy->fd, &magic); 194 wl_drm_authenticate(drmdpy->wl_drm, magic); 195} 196 197static void 198drm_handle_format(void *data, struct wl_drm *drm, uint32_t format) 199{ 200 struct wayland_drm_display *drmdpy = data; 201 202 switch (format) { 203 case WL_DRM_FORMAT_ARGB32: 204 drmdpy->argb32 = TRUE; 205 break; 206 case WL_DRM_FORMAT_PREMULTIPLIED_ARGB32: 207 drmdpy->argb32_pre = TRUE; 208 break; 209 case WL_DRM_FORMAT_XRGB32: 210 drmdpy->xrgb32 = TRUE; 211 break; 212 } 213} 214 215static void 216drm_handle_authenticated(void *data, struct wl_drm *drm) 217{ 218 struct wayland_drm_display *drmdpy = data; 219 220 drmdpy->authenticated = true; 221} 222 223static const struct wl_drm_listener drm_listener = { 224 drm_handle_device, 225 drm_handle_format, 226 drm_handle_authenticated 227}; 228 229static boolean 230wayland_drm_display_init_screen(struct native_display *ndpy) 231{ 232 struct wayland_drm_display *drmdpy = wayland_drm_display(ndpy); 233 uint32_t id; 234 235 id = wl_display_get_global(drmdpy->base.dpy, "wl_drm", 1); 236 if (id == 0) 237 wl_display_roundtrip(drmdpy->base.dpy); 238 id = wl_display_get_global(drmdpy->base.dpy, "wl_drm", 1); 239 if (id == 0) 240 return FALSE; 241 242 drmdpy->wl_drm = wl_display_bind(drmdpy->base.dpy, id, &wl_drm_interface); 243 if (!drmdpy->wl_drm) 244 return FALSE; 245 246 wl_drm_add_listener(drmdpy->wl_drm, &drm_listener, drmdpy); 247 wl_display_roundtrip(drmdpy->base.dpy); 248 if (drmdpy->fd == -1) 249 return FALSE; 250 251 wl_display_roundtrip(drmdpy->base.dpy); 252 if (!drmdpy->authenticated) 253 return FALSE; 254 255 if (!wayland_drm_display_add_configs(drmdpy)) 256 return FALSE; 257 258 drmdpy->base.base.screen = 259 drmdpy->event_handler->new_drm_screen(&drmdpy->base.base, 260 NULL, drmdpy->fd); 261 if (!drmdpy->base.base.screen) { 262 _eglLog(_EGL_WARNING, "failed to create DRM screen"); 263 return FALSE; 264 } 265 266 return TRUE; 267} 268 269static struct native_display_buffer wayland_drm_display_buffer = { 270 /* use the helpers */ 271 drm_display_import_native_buffer, 272 drm_display_export_native_buffer 273}; 274 275static int 276wayland_drm_display_authenticate(void *user_data, uint32_t magic) 277{ 278 struct native_display *ndpy = user_data; 279 struct wayland_drm_display *drmdpy = wayland_drm_display(ndpy); 280 boolean current_authenticate, authenticated; 281 282 current_authenticate = drmdpy->authenticated; 283 284 wl_drm_authenticate(drmdpy->wl_drm, magic); 285 wl_display_roundtrip(drmdpy->base.dpy); 286 authenticated = drmdpy->authenticated; 287 288 drmdpy->authenticated = current_authenticate; 289 290 return authenticated ? 0 : -1; 291} 292 293static struct wayland_drm_callbacks wl_drm_callbacks = { 294 wayland_drm_display_authenticate, 295 egl_g3d_wl_drm_helper_reference_buffer, 296 egl_g3d_wl_drm_helper_unreference_buffer 297}; 298 299static boolean 300wayland_drm_display_bind_wayland_display(struct native_display *ndpy, 301 struct wl_display *wl_dpy) 302{ 303 struct wayland_drm_display *drmdpy = wayland_drm_display(ndpy); 304 305 if (drmdpy->wl_server_drm) 306 return FALSE; 307 308 drmdpy->wl_server_drm = 309 wayland_drm_init(wl_dpy, drmdpy->device_name, 310 &wl_drm_callbacks, ndpy); 311 312 if (!drmdpy->wl_server_drm) 313 return FALSE; 314 315 return TRUE; 316} 317 318static boolean 319wayland_drm_display_unbind_wayland_display(struct native_display *ndpy, 320 struct wl_display *wl_dpy) 321{ 322 struct wayland_drm_display *drmdpy = wayland_drm_display(ndpy); 323 324 if (!drmdpy->wl_server_drm) 325 return FALSE; 326 327 wayland_drm_uninit(drmdpy->wl_server_drm); 328 drmdpy->wl_server_drm = NULL; 329 330 return TRUE; 331} 332 333static struct native_display_wayland_bufmgr wayland_drm_display_wayland_bufmgr = { 334 wayland_drm_display_bind_wayland_display, 335 wayland_drm_display_unbind_wayland_display, 336 egl_g3d_wl_drm_common_wl_buffer_get_resource 337}; 338 339 340struct wayland_display * 341wayland_create_drm_display(struct wl_display *dpy, 342 const struct native_event_handler *event_handler) 343{ 344 struct wayland_drm_display *drmdpy; 345 346 drmdpy = CALLOC_STRUCT(wayland_drm_display); 347 if (!drmdpy) 348 return NULL; 349 350 drmdpy->event_handler = event_handler; 351 352 drmdpy->base.dpy = dpy; 353 if (!drmdpy->base.dpy) { 354 wayland_drm_display_destroy(&drmdpy->base.base); 355 return NULL; 356 } 357 358 drmdpy->base.base.init_screen = wayland_drm_display_init_screen; 359 drmdpy->base.base.destroy = wayland_drm_display_destroy; 360 drmdpy->base.base.buffer = &wayland_drm_display_buffer; 361 drmdpy->base.base.wayland_bufmgr = &wayland_drm_display_wayland_bufmgr; 362 363 drmdpy->base.create_buffer = wayland_create_drm_buffer; 364 365 return &drmdpy->base; 366} 367 368/* vim: set sw=3 ts=8 sts=3 expandtab: */ 369