vl: WIP DRI2 support in the winsys.
[mesa.git] / src / gallium / winsys / g3dvl / dri / dri_winsys.c
1 /**************************************************************************
2 *
3 * Copyright 2009 Younes Manton.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 #include <vl_winsys.h>
29 #include <driclient.h>
30 #include <state_tracker/dri1_api.h>
31 #include <pipe/p_video_context.h>
32 #include <pipe/p_state.h>
33 #include <util/u_memory.h>
34
35 struct vl_dri_screen
36 {
37 struct vl_screen base;
38 Visual *visual;
39 struct drm_api *api;
40 dri_screen_t *dri_screen;
41 dri_framebuffer_t dri_framebuf;
42 struct dri1_api *api_hooks;
43 boolean dri2;
44 };
45
46 struct vl_dri_context
47 {
48 struct vl_context base;
49 boolean is_locked;
50 boolean lost_lock;
51 drmLock *lock;
52 dri_context_t *dri_context;
53 int fd;
54 struct pipe_video_context *vpipe;
55 dri_drawable_t *drawable;
56 struct pipe_surface *dri2_front;
57 };
58
59 static void
60 vl_dri_lock(void *priv)
61 {
62 struct vl_dri_context *vl_dri_ctx = priv;
63 drm_context_t hw_context;
64 char ret = 0;
65
66 assert(priv);
67
68 hw_context = vl_dri_ctx->dri_context->drm_context;
69
70 DRM_CAS(vl_dri_ctx->lock, hw_context, DRM_LOCK_HELD | hw_context, ret);
71 if (ret) {
72 drmGetLock(vl_dri_ctx->fd, hw_context, 0);
73 vl_dri_ctx->lost_lock = TRUE;
74 }
75 vl_dri_ctx->is_locked = TRUE;
76 }
77
78 static void
79 vl_dri_unlock(void *priv)
80 {
81 struct vl_dri_context *vl_dri_ctx = priv;
82 drm_context_t hw_context;
83
84 assert(priv);
85
86 hw_context = vl_dri_ctx->dri_context->drm_context;
87
88 vl_dri_ctx->is_locked = FALSE;
89 DRM_UNLOCK(vl_dri_ctx->fd, vl_dri_ctx->lock, hw_context);
90 }
91
92 static boolean
93 vl_dri_is_locked(void *priv)
94 {
95 struct vl_dri_context *vl_dri_ctx = priv;
96
97 assert(priv);
98
99 return vl_dri_ctx->is_locked;
100 }
101
102 static boolean
103 vl_dri_lost_lock(void *priv)
104 {
105 struct vl_dri_context *vl_dri_ctx = priv;
106
107 assert(priv);
108
109 return vl_dri_ctx->lost_lock;
110 }
111
112 static void
113 vl_dri_clear_lost_lock(void *priv)
114 {
115 struct vl_dri_context *vl_dri_ctx = priv;
116
117 assert(priv);
118
119 vl_dri_ctx->lost_lock = FALSE;
120 }
121
122 struct dri1_api_lock_funcs dri1_lf =
123 {
124 .lock = vl_dri_lock,
125 .unlock = vl_dri_unlock,
126 .is_locked = vl_dri_is_locked,
127 .is_lock_lost = vl_dri_lost_lock,
128 .clear_lost_lock = vl_dri_clear_lost_lock
129 };
130
131 static void
132 vl_dri_copy_version(struct dri1_api_version *dst, dri_version_t *src)
133 {
134 assert(src);
135 assert(dst);
136 dst->major = src->major;
137 dst->minor = src->minor;
138 dst->patch_level = src->patch;
139 }
140
141 static boolean
142 vl_dri_intersect_src_bbox(struct drm_clip_rect *dst, int dst_x, int dst_y,
143 const struct drm_clip_rect *src, const struct drm_clip_rect *bbox)
144 {
145 int xy1;
146 int xy2;
147
148 assert(dst);
149 assert(src);
150 assert(bbox);
151
152 xy1 = ((int)src->x1 > (int)bbox->x1 + dst_x) ? src->x1 :
153 (int)bbox->x1 + dst_x;
154 xy2 = ((int)src->x2 < (int)bbox->x2 + dst_x) ? src->x2 :
155 (int)bbox->x2 + dst_x;
156 if (xy1 >= xy2 || xy1 < 0)
157 return FALSE;
158
159 dst->x1 = xy1;
160 dst->x2 = xy2;
161
162 xy1 = ((int)src->y1 > (int)bbox->y1 + dst_y) ? src->y1 :
163 (int)bbox->y1 + dst_y;
164 xy2 = ((int)src->y2 < (int)bbox->y2 + dst_y) ? src->y2 :
165 (int)bbox->y2 + dst_y;
166 if (xy1 >= xy2 || xy1 < 0)
167 return FALSE;
168
169 dst->y1 = xy1;
170 dst->y2 = xy2;
171 return TRUE;
172 }
173
174 static void
175 vl_clip_copy(struct vl_dri_context *vl_dri_ctx,
176 struct pipe_surface *dst,
177 struct pipe_surface *src,
178 const struct drm_clip_rect *src_bbox)
179 {
180 struct pipe_video_context *vpipe;
181 struct drm_clip_rect clip;
182 struct drm_clip_rect *cur;
183 int i;
184
185 assert(vl_dri_ctx);
186 assert(dst);
187 assert(src);
188 assert(src_bbox);
189
190 vpipe = vl_dri_ctx->base.vpipe;
191
192 assert(vl_dri_ctx->drawable->cliprects);
193 assert(vl_dri_ctx->drawable->num_cliprects > 0);
194
195 cur = vl_dri_ctx->drawable->cliprects;
196
197 for (i = 0; i < vl_dri_ctx->drawable->num_cliprects; ++i) {
198 if (vl_dri_intersect_src_bbox(&clip, vl_dri_ctx->drawable->x, vl_dri_ctx->drawable->y, cur++, src_bbox))
199 vpipe->surface_copy
200 (
201 vpipe, dst, clip.x1, clip.y1, src,
202 (int)clip.x1 - vl_dri_ctx->drawable->x,
203 (int)clip.y1 - vl_dri_ctx->drawable->y,
204 clip.x2 - clip.x1, clip.y2 - clip.y1
205 );
206 }
207 }
208
209 static void
210 vl_dri_update_drawables_locked(struct vl_dri_context *vl_dri_ctx)
211 {
212 struct vl_dri_screen *vl_dri_scrn;
213
214 assert(vl_dri_ctx);
215
216 vl_dri_scrn = (struct vl_dri_screen*)vl_dri_ctx->base.vscreen;
217
218 if (vl_dri_ctx->lost_lock) {
219 vl_dri_ctx->lost_lock = FALSE;
220 DRI_VALIDATE_DRAWABLE_INFO(vl_dri_scrn->dri_screen, vl_dri_ctx->drawable);
221 }
222 }
223
224 static void
225 vl_dri_flush_frontbuffer(struct pipe_screen *screen,
226 struct pipe_surface *surf, void *context_private)
227 {
228 struct vl_dri_context *vl_dri_ctx = (struct vl_dri_context*)context_private;
229 struct vl_dri_screen *vl_dri_scrn;
230 struct drm_clip_rect src_bbox;
231 boolean save_lost_lock = FALSE;
232
233 assert(screen);
234 assert(surf);
235 assert(context_private);
236
237 vl_dri_scrn = (struct vl_dri_screen*)vl_dri_ctx->base.vscreen;
238
239 vl_dri_lock(vl_dri_ctx);
240
241 save_lost_lock = vl_dri_ctx->lost_lock;
242
243 vl_dri_update_drawables_locked(vl_dri_ctx);
244
245 if (vl_dri_ctx->drawable->cliprects) {
246 src_bbox.x1 = 0;
247 src_bbox.x2 = vl_dri_ctx->drawable->w;
248 src_bbox.y1 = 0;
249 src_bbox.y2 = vl_dri_ctx->drawable->h;
250
251 #if 0
252 if (vl_dri_scrn->_api_hooks->present_locked)
253 vl_dri_scrn->api_hooks->present_locked(pipe, surf,
254 vl_dri_ctx->drawable->cliprects,
255 vl_dri_ctx->drawable->num_cliprects,
256 vl_dri_ctx->drawable->x, vl_dri_drawable->y,
257 &bbox, NULL /*fence*/);
258 else
259 #endif
260 if (vl_dri_scrn->api_hooks->front_srf_locked) {
261 struct pipe_surface *front = vl_dri_scrn->api_hooks->front_srf_locked(screen);
262
263 if (front)
264 vl_clip_copy(vl_dri_ctx, front, surf, &src_bbox);
265
266 //st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, fence);
267 }
268 }
269
270 vl_dri_ctx->lost_lock = save_lost_lock;
271
272 vl_dri_unlock(vl_dri_ctx);
273 }
274
275 static struct pipe_surface*
276 vl_dri2_get_front(struct vl_dri_screen *vl_dri_scrn, Drawable drawable)
277 {
278 int w, h;
279 unsigned int attachments[1] = {DRI_BUFFER_FRONT_LEFT};
280 int count;
281 DRI2Buffer *dri2_front;
282 struct pipe_texture template, *front_tex;
283 struct pipe_surface *front_surf = NULL;
284
285 assert(vl_dri_scrn);
286
287 dri2_front = DRI2GetBuffers(vl_dri_scrn->dri_screen->display,
288 drawable, &w, &h, attachments, 1, &count);
289 if (dri2_front) {
290 front_tex = vl_dri_scrn->api->texture_from_shared_handle(vl_dri_scrn->api, vl_dri_scrn->base.pscreen,
291 &template, "", dri2_front->pitch, dri2_front->name);
292 if (front_tex)
293 front_surf = vl_dri_scrn->base.pscreen->get_tex_surface(vl_dri_scrn->base.pscreen,
294 front_tex, 0, 0, 0,
295 PIPE_BUFFER_USAGE_GPU_READ_WRITE);
296 pipe_texture_reference(&front_tex, NULL);
297 }
298
299 return front_surf;
300 }
301
302 static void
303 vl_dri2_flush_frontbuffer(struct pipe_screen *screen,
304 struct pipe_surface *surf, void *context_private)
305 {
306 struct vl_dri_context *vl_dri_ctx = (struct vl_dri_context*)context_private;
307 struct vl_dri_screen *vl_dri_scrn;
308 struct pipe_video_context *vpipe;
309
310 assert(screen);
311 assert(surf);
312 assert(context_private);
313 assert(vl_dri_ctx->dri2_front);
314
315 vl_dri_scrn = (struct vl_dri_screen*)vl_dri_ctx->base.vscreen;
316 vpipe = vl_dri_ctx->base.vpipe;
317
318 /* XXX: Why not just render to fake front? */
319 vpipe->surface_copy(vpipe, vl_dri_ctx->dri2_front, 0, 0, surf, 0, 0, surf->width, surf->height);
320
321 //st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, fence);
322 }
323
324
325 Drawable
326 vl_video_bind_drawable(struct vl_context *vctx, Drawable drawable)
327 {
328 struct vl_dri_context *vl_dri_ctx = (struct vl_dri_context*)vctx;
329 struct vl_dri_screen *vl_dri_scrn;
330 dri_drawable_t *dri_drawable;
331 Drawable old_drawable = None;
332
333 assert(vctx);
334
335 if (vl_dri_ctx->drawable)
336 old_drawable = vl_dri_ctx->drawable->x_drawable;
337
338 if (drawable != old_drawable) {
339 vl_dri_scrn = (struct vl_dri_screen*)vl_dri_ctx->base.vscreen;
340 if (vl_dri_scrn->dri2) {
341 /* XXX: Need dri2CreateDrawable()? */
342 vl_dri_ctx->dri2_front = vl_dri2_get_front(vl_dri_scrn, drawable);
343 }
344 else {
345 driCreateDrawable(vl_dri_scrn->dri_screen, drawable, &dri_drawable);
346 vl_dri_ctx->drawable = dri_drawable;
347 }
348 }
349
350 return old_drawable;
351 }
352
353 struct vl_screen*
354 vl_screen_create(Display *display, int screen)
355 {
356 struct vl_dri_screen *vl_dri_scrn;
357 struct dri1_create_screen_arg arg;
358
359 assert(display);
360
361 vl_dri_scrn = CALLOC_STRUCT(vl_dri_screen);
362 if (!vl_dri_scrn)
363 return NULL;
364
365 /* Try DRI2 first */
366 if (dri2CreateScreen(display, screen, &vl_dri_scrn->dri_screen)) {
367 /* If not, try DRI */
368 if (driCreateScreen(display, screen, &vl_dri_scrn->dri_screen, &vl_dri_scrn->dri_framebuf)) {
369 /* Now what? */
370 FREE(vl_dri_scrn);
371 return NULL;
372 }
373 else {
374 /* Got DRI */
375 arg.base.mode = DRM_CREATE_DRI1;
376 arg.lf = &dri1_lf;
377 arg.ddx_info = vl_dri_scrn->dri_framebuf.private;
378 arg.ddx_info_size = vl_dri_scrn->dri_framebuf.private_size;
379 arg.sarea = vl_dri_scrn->dri_screen->sarea;
380 vl_dri_copy_version(&arg.ddx_version, &vl_dri_scrn->dri_screen->ddx);
381 vl_dri_copy_version(&arg.dri_version, &vl_dri_scrn->dri_screen->dri);
382 vl_dri_copy_version(&arg.drm_version, &vl_dri_scrn->dri_screen->drm);
383 arg.api = NULL;
384 vl_dri_scrn->dri2 = FALSE;
385 }
386 }
387 else {
388 /* Got DRI2 */
389 arg.base.mode = DRM_CREATE_NORMAL;
390 vl_dri_scrn->dri2 = TRUE;
391 }
392
393 vl_dri_scrn->api = drm_api_create();
394 if (!vl_dri_scrn->api) {
395 FREE(vl_dri_scrn);
396 return NULL;
397 }
398
399 vl_dri_scrn->base.pscreen = vl_dri_scrn->api->create_screen(vl_dri_scrn->api,
400 vl_dri_scrn->dri_screen->fd,
401 &arg.base);
402
403 if (!vl_dri_scrn->base.pscreen) {
404 FREE(vl_dri_scrn);
405 return NULL;
406 }
407
408 if (!vl_dri_scrn->dri2) {
409 vl_dri_scrn->visual = XDefaultVisual(display, screen);
410 vl_dri_scrn->api_hooks = arg.api;
411 vl_dri_scrn->base.format = vl_dri_scrn->api_hooks->front_srf_locked(vl_dri_scrn->base.pscreen)->format;
412 vl_dri_scrn->base.pscreen->flush_frontbuffer = vl_dri_flush_frontbuffer;
413 }
414 else
415 vl_dri_scrn->base.pscreen->flush_frontbuffer = vl_dri2_flush_frontbuffer;
416
417 return &vl_dri_scrn->base;
418 }
419
420 void vl_screen_destroy(struct vl_screen *vscreen)
421 {
422 struct vl_dri_screen *vl_dri_scrn = (struct vl_dri_screen*)vscreen;
423
424 assert(vscreen);
425
426 vl_dri_scrn->base.pscreen->destroy(vl_dri_scrn->base.pscreen);
427 if (vl_dri_scrn->dri2)
428 dri2DestroyScreen(vl_dri_scrn->dri_screen);
429 else
430 driDestroyScreen(vl_dri_scrn->dri_screen);
431 FREE(vl_dri_scrn);
432 }
433
434 struct vl_context*
435 vl_video_create(struct vl_screen *vscreen,
436 enum pipe_video_profile profile,
437 enum pipe_video_chroma_format chroma_format,
438 unsigned width, unsigned height)
439 {
440 struct vl_dri_screen *vl_dri_scrn = (struct vl_dri_screen*)vscreen;
441 struct vl_dri_context *vl_dri_ctx;
442
443 vl_dri_ctx = CALLOC_STRUCT(vl_dri_context);
444 if (!vl_dri_ctx)
445 return NULL;
446
447 /* XXX: Is default visual correct/sufficient here? */
448 if (!vl_dri_scrn->dri2)
449 driCreateContext(vl_dri_scrn->dri_screen, vl_dri_scrn->visual, &vl_dri_ctx->dri_context);
450
451 if (!vscreen->pscreen->video_context_create) {
452 debug_printf("[G3DVL] No video support found on %s/%s.\n",
453 vscreen->pscreen->get_vendor(vscreen->pscreen),
454 vscreen->pscreen->get_name(vscreen->pscreen));
455 FREE(vl_dri_ctx);
456 return NULL;
457 }
458
459 vl_dri_ctx->base.vpipe = vscreen->pscreen->video_context_create(vscreen->pscreen,
460 profile, chroma_format,
461 width, height,
462 vl_dri_ctx->dri_context);
463
464 if (!vl_dri_ctx->base.vpipe) {
465 FREE(vl_dri_ctx);
466 return NULL;
467 }
468
469 vl_dri_ctx->base.vpipe->priv = vl_dri_ctx;
470 vl_dri_ctx->base.vscreen = vscreen;
471 vl_dri_ctx->fd = vl_dri_scrn->dri_screen->fd;
472 if (!vl_dri_scrn->dri2)
473 vl_dri_ctx->lock = (drmLock*)&vl_dri_scrn->dri_screen->sarea->lock;
474
475 return &vl_dri_ctx->base;
476 }
477
478 void vl_video_destroy(struct vl_context *vctx)
479 {
480 struct vl_dri_context *vl_dri_ctx = (struct vl_dri_context*)vctx;
481
482 assert(vctx);
483
484 vl_dri_ctx->base.vpipe->destroy(vl_dri_ctx->base.vpipe);
485 if (!((struct vl_dri_screen *)vctx->vscreen)->dri2)
486 driDestroyContext(vl_dri_ctx->dri_context);
487 FREE(vl_dri_ctx);
488 }