Merge branch 'master' into pipe-video
[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 };
44
45 struct vl_dri_context
46 {
47 struct vl_context base;
48 boolean is_locked;
49 boolean lost_lock;
50 drmLock *lock;
51 dri_context_t *dri_context;
52 int fd;
53 struct pipe_video_context *vpipe;
54 dri_drawable_t *drawable;
55 };
56
57 static void
58 vl_dri_lock(void *priv)
59 {
60 struct vl_dri_context *vl_dri_ctx = priv;
61 drm_context_t hw_context;
62 char ret = 0;
63
64 assert(priv);
65
66 hw_context = vl_dri_ctx->dri_context->drm_context;
67
68 DRM_CAS(vl_dri_ctx->lock, hw_context, DRM_LOCK_HELD | hw_context, ret);
69 if (ret) {
70 drmGetLock(vl_dri_ctx->fd, hw_context, 0);
71 vl_dri_ctx->lost_lock = TRUE;
72 }
73 vl_dri_ctx->is_locked = TRUE;
74 }
75
76 static void
77 vl_dri_unlock(void *priv)
78 {
79 struct vl_dri_context *vl_dri_ctx = priv;
80 drm_context_t hw_context;
81
82 assert(priv);
83
84 hw_context = vl_dri_ctx->dri_context->drm_context;
85
86 vl_dri_ctx->is_locked = FALSE;
87 DRM_UNLOCK(vl_dri_ctx->fd, vl_dri_ctx->lock, hw_context);
88 }
89
90 static boolean
91 vl_dri_is_locked(void *priv)
92 {
93 struct vl_dri_context *vl_dri_ctx = priv;
94
95 assert(priv);
96
97 return vl_dri_ctx->is_locked;
98 }
99
100 static boolean
101 vl_dri_lost_lock(void *priv)
102 {
103 struct vl_dri_context *vl_dri_ctx = priv;
104
105 assert(priv);
106
107 return vl_dri_ctx->lost_lock;
108 }
109
110 static void
111 vl_dri_clear_lost_lock(void *priv)
112 {
113 struct vl_dri_context *vl_dri_ctx = priv;
114
115 assert(priv);
116
117 vl_dri_ctx->lost_lock = FALSE;
118 }
119
120 struct dri1_api_lock_funcs dri1_lf =
121 {
122 .lock = vl_dri_lock,
123 .unlock = vl_dri_unlock,
124 .is_locked = vl_dri_is_locked,
125 .is_lock_lost = vl_dri_lost_lock,
126 .clear_lost_lock = vl_dri_clear_lost_lock
127 };
128
129 static void
130 vl_dri_copy_version(struct dri1_api_version *dst, dri_version_t *src)
131 {
132 assert(src);
133 assert(dst);
134 dst->major = src->major;
135 dst->minor = src->minor;
136 dst->patch_level = src->patch;
137 }
138
139 static boolean
140 vl_dri_intersect_src_bbox(struct drm_clip_rect *dst, int dst_x, int dst_y,
141 const struct drm_clip_rect *src, const struct drm_clip_rect *bbox)
142 {
143 int xy1;
144 int xy2;
145
146 assert(dst);
147 assert(src);
148 assert(bbox);
149
150 xy1 = ((int)src->x1 > (int)bbox->x1 + dst_x) ? src->x1 :
151 (int)bbox->x1 + dst_x;
152 xy2 = ((int)src->x2 < (int)bbox->x2 + dst_x) ? src->x2 :
153 (int)bbox->x2 + dst_x;
154 if (xy1 >= xy2 || xy1 < 0)
155 return FALSE;
156
157 dst->x1 = xy1;
158 dst->x2 = xy2;
159
160 xy1 = ((int)src->y1 > (int)bbox->y1 + dst_y) ? src->y1 :
161 (int)bbox->y1 + dst_y;
162 xy2 = ((int)src->y2 < (int)bbox->y2 + dst_y) ? src->y2 :
163 (int)bbox->y2 + dst_y;
164 if (xy1 >= xy2 || xy1 < 0)
165 return FALSE;
166
167 dst->y1 = xy1;
168 dst->y2 = xy2;
169 return TRUE;
170 }
171
172 static void
173 vl_clip_copy(struct vl_dri_context *vl_dri_ctx,
174 struct pipe_surface *dst,
175 struct pipe_surface *src,
176 const struct drm_clip_rect *src_bbox)
177 {
178 struct pipe_video_context *vpipe = vl_dri_ctx->base.vpipe;
179 struct drm_clip_rect clip;
180 struct drm_clip_rect *cur;
181 int i;
182
183 assert(vl_dri_ctx);
184 assert(dst);
185 assert(src);
186 assert(src_bbox);
187
188 assert(vl_dri_ctx->drawable->cliprects);
189 assert(vl_dri_ctx->drawable->num_cliprects > 0);
190
191 cur = vl_dri_ctx->drawable->cliprects;
192
193 for (i = 0; i < vl_dri_ctx->drawable->num_cliprects; ++i) {
194 if (vl_dri_intersect_src_bbox(&clip, vl_dri_ctx->drawable->x, vl_dri_ctx->drawable->y, cur++, src_bbox))
195 vpipe->surface_copy
196 (
197 vpipe, dst, clip.x1, clip.y1, src,
198 (int)clip.x1 - vl_dri_ctx->drawable->x,
199 (int)clip.y1 - vl_dri_ctx->drawable->y,
200 clip.x2 - clip.x1, clip.y2 - clip.y1
201 );
202 }
203 }
204
205 static void
206 vl_dri_update_drawables_locked(struct vl_dri_context *vl_dri_ctx)
207 {
208 struct vl_dri_screen *vl_dri_scrn;
209
210 assert(vl_dri_ctx);
211
212 vl_dri_scrn = (struct vl_dri_screen*)vl_dri_ctx->base.vscreen;
213
214 if (vl_dri_ctx->lost_lock) {
215 vl_dri_ctx->lost_lock = FALSE;
216 DRI_VALIDATE_DRAWABLE_INFO(vl_dri_scrn->dri_screen, vl_dri_ctx->drawable);
217 }
218 }
219
220 static void
221 vl_dri_flush_frontbuffer(struct pipe_screen *screen,
222 struct pipe_surface *surf, void *context_private)
223 {
224 struct vl_dri_context *vl_dri_ctx = (struct vl_dri_context*)context_private;
225 struct vl_dri_screen *vl_dri_scrn;
226 struct drm_clip_rect src_bbox;
227 boolean save_lost_lock = FALSE;
228
229 assert(screen);
230 assert(surf);
231 assert(context_private);
232
233 vl_dri_scrn = (struct vl_dri_screen*)vl_dri_ctx->base.vscreen;
234
235 vl_dri_lock(vl_dri_ctx);
236
237 save_lost_lock = vl_dri_ctx->lost_lock;
238
239 vl_dri_update_drawables_locked(vl_dri_ctx);
240
241 if (vl_dri_ctx->drawable->cliprects) {
242 src_bbox.x1 = 0;
243 src_bbox.x2 = vl_dri_ctx->drawable->w;
244 src_bbox.y1 = 0;
245 src_bbox.y2 = vl_dri_ctx->drawable->h;
246
247 #if 0
248 if (vl_dri_scrn->_api_hooks->present_locked)
249 vl_dri_scrn->api_hooks->present_locked(pipe, surf,
250 vl_dri_ctx->drawable->cliprects,
251 vl_dri_ctx->drawable->num_cliprects,
252 vl_dri_ctx->drawable->x, vl_dri_drawable->y,
253 &bbox, NULL /*fence*/);
254 else
255 #endif
256 if (vl_dri_scrn->api_hooks->front_srf_locked) {
257 struct pipe_surface *front = vl_dri_scrn->api_hooks->front_srf_locked(screen);
258
259 if (front)
260 vl_clip_copy(vl_dri_ctx, front, surf, &src_bbox);
261
262 //st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, fence);
263 }
264 }
265
266 vl_dri_ctx->lost_lock = save_lost_lock;
267
268 vl_dri_unlock(vl_dri_ctx);
269 }
270
271 Drawable
272 vl_video_bind_drawable(struct vl_context *vctx, Drawable drawable)
273 {
274 struct vl_dri_context *vl_dri_ctx = (struct vl_dri_context*)vctx;
275 struct vl_dri_screen *vl_dri_scrn;
276 dri_drawable_t *dri_drawable;
277 Drawable old_drawable = None;
278
279 assert(vctx);
280
281 if (vl_dri_ctx->drawable)
282 old_drawable = vl_dri_ctx->drawable->x_drawable;
283
284 vl_dri_scrn = (struct vl_dri_screen*)vl_dri_ctx->base.vscreen;
285 driCreateDrawable(vl_dri_scrn->dri_screen, drawable, &dri_drawable);
286 vl_dri_ctx->drawable = dri_drawable;
287
288 return old_drawable;
289 }
290
291 struct vl_screen*
292 vl_screen_create(Display *display, int screen)
293 {
294 struct vl_dri_screen *vl_dri_scrn;
295 struct dri1_create_screen_arg arg;
296
297 assert(display);
298
299 vl_dri_scrn = CALLOC_STRUCT(vl_dri_screen);
300 if (!vl_dri_scrn)
301 return NULL;
302
303 driCreateScreen(display, screen, &vl_dri_scrn->dri_screen, &vl_dri_scrn->dri_framebuf);
304 vl_dri_scrn->api = drm_api_create();
305
306 arg.base.mode = DRM_CREATE_DRI1;
307 arg.lf = &dri1_lf;
308 arg.ddx_info = vl_dri_scrn->dri_framebuf.private;
309 arg.ddx_info_size = vl_dri_scrn->dri_framebuf.private_size;
310 arg.sarea = vl_dri_scrn->dri_screen->sarea;
311 vl_dri_copy_version(&arg.ddx_version, &vl_dri_scrn->dri_screen->ddx);
312 vl_dri_copy_version(&arg.dri_version, &vl_dri_scrn->dri_screen->dri);
313 vl_dri_copy_version(&arg.drm_version, &vl_dri_scrn->dri_screen->drm);
314 arg.api = NULL;
315
316 vl_dri_scrn->base.pscreen = vl_dri_scrn->api->create_screen(vl_dri_scrn->api,
317 vl_dri_scrn->dri_screen->fd,
318 &arg.base);
319
320 if (!vl_dri_scrn->base.pscreen) {
321 FREE(vl_dri_scrn);
322 return NULL;
323 }
324
325 vl_dri_scrn->visual = XDefaultVisual(display, screen);
326 vl_dri_scrn->api_hooks = arg.api;
327 vl_dri_scrn->base.pscreen->flush_frontbuffer = vl_dri_flush_frontbuffer;
328 /* XXX: Safe to call this while unlocked? */
329 vl_dri_scrn->base.format = vl_dri_scrn->api_hooks->front_srf_locked(vl_dri_scrn->base.pscreen)->format;
330
331 return &vl_dri_scrn->base;
332 }
333
334 void vl_screen_destroy(struct vl_screen *vscreen)
335 {
336 struct vl_dri_screen *vl_dri_scrn = (struct vl_dri_screen*)vscreen;
337
338 assert(vscreen);
339
340 vl_dri_scrn->base.pscreen->destroy(vl_dri_scrn->base.pscreen);
341 driDestroyScreen(vl_dri_scrn->dri_screen);
342 FREE(vl_dri_scrn);
343 }
344
345 struct vl_context*
346 vl_video_create(struct vl_screen *vscreen,
347 enum pipe_video_profile profile,
348 enum pipe_video_chroma_format chroma_format,
349 unsigned width, unsigned height)
350 {
351 struct vl_dri_screen *vl_dri_scrn = (struct vl_dri_screen*)vscreen;
352 struct vl_dri_context *vl_dri_ctx;
353
354 vl_dri_ctx = CALLOC_STRUCT(vl_dri_context);
355 if (!vl_dri_ctx)
356 return NULL;
357
358 /* XXX: Is default visual correct/sufficient here? */
359 driCreateContext(vl_dri_scrn->dri_screen, vl_dri_scrn->visual, &vl_dri_ctx->dri_context);
360
361 if (!vl_dri_scrn->api->create_video_context) {
362 debug_printf("[G3DVL] No video support found on %s/%s.\n",
363 vl_dri_scrn->base.pscreen->get_vendor(vl_dri_scrn->base.pscreen),
364 vl_dri_scrn->base.pscreen->get_name(vl_dri_scrn->base.pscreen));
365 FREE(vl_dri_ctx);
366 return NULL;
367 }
368
369 vl_dri_ctx->base.vpipe = vl_dri_scrn->api->create_video_context(vl_dri_scrn->api,
370 vscreen->pscreen,
371 profile, chroma_format,
372 width, height);
373
374 if (!vl_dri_ctx->base.vpipe) {
375 FREE(vl_dri_ctx);
376 return NULL;
377 }
378
379 vl_dri_ctx->base.vpipe->priv = vl_dri_ctx;
380 vl_dri_ctx->base.vscreen = vscreen;
381 vl_dri_ctx->fd = vl_dri_scrn->dri_screen->fd;
382 vl_dri_ctx->lock = (drmLock*)&vl_dri_scrn->dri_screen->sarea->lock;
383
384 return &vl_dri_ctx->base;
385 }
386
387 void vl_video_destroy(struct vl_context *vctx)
388 {
389 struct vl_dri_context *vl_dri_ctx = (struct vl_dri_context*)vctx;
390
391 assert(vctx);
392
393 vl_dri_ctx->base.vpipe->destroy(vl_dri_ctx->base.vpipe);
394 FREE(vl_dri_ctx);
395 }