native_drm.c revision dc520d4fefa6a92b3a8f2eed3c5a1044dfccb3ff
1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)/*
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Mesa 3-D graphics library
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Version:  7.11
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Copyright (C) 2011 Benjamin Franzke <benjaminfranzke@googlemail.com>
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Permission is hereby granted, free of charge, to any person obtaining a
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * copy of this software and associated documentation files (the "Software"),
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * to deal in the Software without restriction, including without limitation
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the rights to use, copy, modify, merge, publish, distribute, sublicense,
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * and/or sell copies of the Software, and to permit persons to whom the
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * Software is furnished to do so, subject to the following conditions:
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
1423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) * The above copyright notice and this permission notice shall be included
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * in all copies or substantial portions of the Software.
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * DEALINGS IN THE SOFTWARE.
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "util/u_memory.h"
27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "util/u_inlines.h"
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "pipe/p_compiler.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "pipe/p_screen.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "pipe/p_context.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "pipe/p_state.h"
331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "state_tracker/drm_driver.h"
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "egllog.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h>
371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "native_wayland.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* see get_drm_screen_name */
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <radeon_drm.h>
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "radeon/drm/radeon_drm_public.h"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <wayland-client.h>
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "wayland-drm-client-protocol.h"
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "wayland-egl-priv.h"
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <xf86drm.h>
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/types.h>
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/stat.h>
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <fcntl.h>
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)struct wayland_drm_display {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   struct wayland_display base;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   struct native_event_handler *event_handler;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   struct wl_drm *wl_drm;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   int fd;
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   char *device_name;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   boolean authenticated;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static INLINE struct wayland_drm_display *
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)wayland_drm_display(const struct native_display *ndpy)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   return (struct wayland_drm_display *) ndpy;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)sync_callback(void *data)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   int *done = data;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   *done = 1;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void
791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)force_roundtrip(struct wl_display *display)
80d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles){
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   int done = 0;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   wl_display_sync_callback(display, sync_callback, &done);
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   wl_display_iterate(display, WL_DISPLAY_WRITABLE);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   while (!done)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      wl_display_iterate(display, WL_DISPLAY_READABLE);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)wayland_drm_display_destroy(struct native_display *ndpy)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   struct wayland_drm_display *drmdpy = wayland_drm_display(ndpy);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   if (drmdpy->fd)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      close(drmdpy->fd);
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   if (drmdpy->wl_drm)
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      wl_drm_destroy(drmdpy->wl_drm);
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   if (drmdpy->device_name)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FREE(drmdpy->device_name);
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   if (drmdpy->base.config)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FREE(drmdpy->base.config);
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   ndpy_uninit(ndpy);
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   FREE(drmdpy);
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static struct wl_buffer *
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)wayland_create_drm_buffer(struct wayland_display *display,
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          struct wayland_surface *surface,
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          enum native_attachment attachment)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   struct wayland_drm_display *drmdpy = (struct wayland_drm_display *) display;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   struct pipe_screen *screen = drmdpy->base.base.screen;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   struct pipe_resource *resource;
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   struct winsys_handle wsh;
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   uint width, height;
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)   struct wl_visual *visual;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   resource = resource_surface_get_single_resource(surface->rsurf, attachment);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   resource_surface_get_size(surface->rsurf, &width, &height);
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   wsh.type = DRM_API_HANDLE_TYPE_SHARED;
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   screen->resource_get_handle(screen, resource, &wsh);
125d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   pipe_resource_reference(&resource, NULL);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   switch (surface->type) {
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   case WL_WINDOW_SURFACE:
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      visual = surface->win->visual;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   case WL_PIXMAP_SURFACE:
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      visual = surface->pix->visual;
134868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      break;
135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)   default:
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return NULL;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   }
138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)   return wl_drm_create_buffer(drmdpy->wl_drm, wsh.handle,
140                               width, height, wsh.stride, visual);
141}
142
143static const char *
144get_drm_screen_name(int fd, drmVersionPtr version)
145{
146   const char *name = version->name;
147
148   if (name && !strcmp(name, "radeon")) {
149      int chip_id;
150      struct drm_radeon_info info;
151
152      memset(&info, 0, sizeof(info));
153      info.request = RADEON_INFO_DEVICE_ID;
154      info.value = pointer_to_intptr(&chip_id);
155      if (drmCommandWriteRead(fd, DRM_RADEON_INFO, &info, sizeof(info)) != 0)
156         return NULL;
157
158      name = is_r3xx(chip_id) ? "r300" : "r600";
159   }
160
161   return name;
162}
163
164static void
165drm_handle_device(void *data, struct wl_drm *drm, const char *device)
166{
167   struct wayland_drm_display *drmdpy = data;
168   drm_magic_t magic;
169
170   drmdpy->device_name = strdup(device);
171   if (!drmdpy->device_name)
172      return;
173
174   drmdpy->fd = open(drmdpy->device_name, O_RDWR);
175   if (drmdpy->fd == -1) {
176      _eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)",
177              drmdpy->device_name, strerror(errno));
178      return;
179   }
180
181   drmGetMagic(drmdpy->fd, &magic);
182   wl_drm_authenticate(drmdpy->wl_drm, magic);
183}
184
185static void
186drm_handle_authenticated(void *data, struct wl_drm *drm)
187{
188   struct wayland_drm_display *drmdpy = data;
189
190   drmdpy->authenticated = true;
191}
192
193static const struct wl_drm_listener drm_listener = {
194   drm_handle_device,
195   drm_handle_authenticated
196};
197
198static boolean
199wayland_drm_display_init_screen(struct native_display *ndpy)
200{
201   struct wayland_drm_display *drmdpy = wayland_drm_display(ndpy);
202   drmVersionPtr version;
203   const char *driver_name;
204   uint32_t id;
205
206   id = wl_display_get_global(drmdpy->base.dpy, "wl_drm", 1);
207   if (id == 0)
208      force_roundtrip(drmdpy->base.dpy);
209   id = wl_display_get_global(drmdpy->base.dpy, "wl_drm", 1);
210   if (id == 0)
211      return FALSE;
212
213   drmdpy->wl_drm = wl_drm_create(drmdpy->base.dpy, id, 1);
214   if (!drmdpy->wl_drm)
215      return FALSE;
216
217   wl_drm_add_listener(drmdpy->wl_drm, &drm_listener, drmdpy);
218   force_roundtrip(drmdpy->base.dpy);
219   if (drmdpy->fd == -1)
220      return FALSE;
221
222   force_roundtrip(drmdpy->base.dpy);
223   if (!drmdpy->authenticated)
224      return FALSE;
225
226   version = drmGetVersion(drmdpy->fd);
227   if (!version) {
228      _eglLog(_EGL_WARNING, "invalid fd %d", drmdpy->fd);
229      return FALSE;
230   }
231
232   /* FIXME: share this with native_drm or egl_dri2 */
233   driver_name = get_drm_screen_name(drmdpy->fd, version);
234
235   drmdpy->base.base.screen =
236      drmdpy->event_handler->new_drm_screen(&drmdpy->base.base,
237                                            driver_name, drmdpy->fd);
238   drmFreeVersion(version);
239
240   if (!drmdpy->base.base.screen) {
241      _eglLog(_EGL_WARNING, "failed to create DRM screen");
242      return FALSE;
243   }
244
245   return TRUE;
246}
247
248static struct pipe_resource *
249wayland_drm_display_import_buffer(struct native_display *ndpy,
250                                  const struct pipe_resource *templ,
251                                  void *buf)
252{
253   return ndpy->screen->resource_from_handle(ndpy->screen,
254                                             templ, (struct winsys_handle *) buf);
255}
256
257static boolean
258wayland_drm_display_export_buffer(struct native_display *ndpy,
259                                  struct pipe_resource *res,
260                                  void *buf)
261{
262   return ndpy->screen->resource_get_handle(ndpy->screen,
263                                            res, (struct winsys_handle *) buf);
264}
265
266static struct native_display_buffer wayland_drm_display_buffer = {
267   wayland_drm_display_import_buffer,
268   wayland_drm_display_export_buffer
269};
270
271struct wayland_display *
272wayland_create_drm_display(struct wl_display *dpy,
273                           struct native_event_handler *event_handler,
274                           void *user_data)
275{
276   struct wayland_drm_display *drmdpy;
277
278   drmdpy = CALLOC_STRUCT(wayland_drm_display);
279   if (!drmdpy)
280      return NULL;
281
282   drmdpy->event_handler = event_handler;
283   drmdpy->base.base.user_data = user_data;
284
285   drmdpy->base.dpy = dpy;
286   if (!drmdpy->base.dpy) {
287      wayland_drm_display_destroy(&drmdpy->base.base);
288      return NULL;
289   }
290
291   if (!wayland_drm_display_init_screen(&drmdpy->base.base)) {
292      wayland_drm_display_destroy(&drmdpy->base.base);
293      return NULL;
294   }
295   drmdpy->base.base.destroy = wayland_drm_display_destroy;
296   drmdpy->base.base.buffer = &wayland_drm_display_buffer;
297
298   drmdpy->base.create_buffer = wayland_create_drm_buffer;
299
300   return &drmdpy->base;
301}
302
303/* vim: set sw=3 ts=8 sts=3 expandtab: */
304