1 /**************************************************************************
3 * Copyright 2009 Younes Manton.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
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>
37 struct vl_screen base
;
40 dri_screen_t
*dri_screen
;
41 dri_framebuffer_t dri_framebuf
;
42 struct dri1_api
*api_hooks
;
48 struct vl_context base
;
52 dri_context_t
*dri_context
;
54 struct pipe_video_context
*vpipe
;
55 dri_drawable_t
*drawable
;
56 struct pipe_surface
*dri2_front
;
60 vl_dri_lock(void *priv
)
62 struct vl_dri_context
*vl_dri_ctx
= priv
;
63 drm_context_t hw_context
;
68 hw_context
= vl_dri_ctx
->dri_context
->drm_context
;
70 DRM_CAS(vl_dri_ctx
->lock
, hw_context
, DRM_LOCK_HELD
| hw_context
, ret
);
72 drmGetLock(vl_dri_ctx
->fd
, hw_context
, 0);
73 vl_dri_ctx
->lost_lock
= TRUE
;
75 vl_dri_ctx
->is_locked
= TRUE
;
79 vl_dri_unlock(void *priv
)
81 struct vl_dri_context
*vl_dri_ctx
= priv
;
82 drm_context_t hw_context
;
86 hw_context
= vl_dri_ctx
->dri_context
->drm_context
;
88 vl_dri_ctx
->is_locked
= FALSE
;
89 DRM_UNLOCK(vl_dri_ctx
->fd
, vl_dri_ctx
->lock
, hw_context
);
93 vl_dri_is_locked(void *priv
)
95 struct vl_dri_context
*vl_dri_ctx
= priv
;
99 return vl_dri_ctx
->is_locked
;
103 vl_dri_lost_lock(void *priv
)
105 struct vl_dri_context
*vl_dri_ctx
= priv
;
109 return vl_dri_ctx
->lost_lock
;
113 vl_dri_clear_lost_lock(void *priv
)
115 struct vl_dri_context
*vl_dri_ctx
= priv
;
119 vl_dri_ctx
->lost_lock
= FALSE
;
122 struct dri1_api_lock_funcs dri1_lf
=
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
132 vl_dri_copy_version(struct dri1_api_version
*dst
, dri_version_t
*src
)
136 dst
->major
= src
->major
;
137 dst
->minor
= src
->minor
;
138 dst
->patch_level
= src
->patch
;
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
)
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)
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)
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
)
180 struct pipe_video_context
*vpipe
;
181 struct drm_clip_rect clip
;
182 struct drm_clip_rect
*cur
;
190 vpipe
= vl_dri_ctx
->base
.vpipe
;
192 assert(vl_dri_ctx
->drawable
->cliprects
);
193 assert(vl_dri_ctx
->drawable
->num_cliprects
> 0);
195 cur
= vl_dri_ctx
->drawable
->cliprects
;
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
))
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
210 vl_dri_update_drawables_locked(struct vl_dri_context
*vl_dri_ctx
)
212 struct vl_dri_screen
*vl_dri_scrn
;
216 vl_dri_scrn
= (struct vl_dri_screen
*)vl_dri_ctx
->base
.vscreen
;
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
);
225 vl_dri_flush_frontbuffer(struct pipe_screen
*screen
,
226 struct pipe_surface
*surf
, void *context_private
)
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
;
235 assert(context_private
);
237 vl_dri_scrn
= (struct vl_dri_screen
*)vl_dri_ctx
->base
.vscreen
;
239 vl_dri_lock(vl_dri_ctx
);
241 save_lost_lock
= vl_dri_ctx
->lost_lock
;
243 vl_dri_update_drawables_locked(vl_dri_ctx
);
245 if (vl_dri_ctx
->drawable
->cliprects
) {
247 src_bbox
.x2
= vl_dri_ctx
->drawable
->w
;
249 src_bbox
.y2
= vl_dri_ctx
->drawable
->h
;
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*/);
260 if (vl_dri_scrn
->api_hooks
->front_srf_locked
) {
261 struct pipe_surface
*front
= vl_dri_scrn
->api_hooks
->front_srf_locked(screen
);
264 vl_clip_copy(vl_dri_ctx
, front
, surf
, &src_bbox
);
266 //st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, fence);
270 vl_dri_ctx
->lost_lock
= save_lost_lock
;
272 vl_dri_unlock(vl_dri_ctx
);
275 static struct pipe_surface
*
276 vl_dri2_get_front(struct vl_dri_screen
*vl_dri_scrn
, Drawable drawable
)
279 unsigned int attachments
[1] = {DRI_BUFFER_FRONT_LEFT
};
281 DRI2Buffer
*dri2_front
;
282 struct pipe_texture
template, *front_tex
;
283 struct pipe_surface
*front_surf
= NULL
;
287 dri2_front
= DRI2GetBuffers(vl_dri_scrn
->dri_screen
->display
,
288 drawable
, &w
, &h
, attachments
, 1, &count
);
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
);
293 front_surf
= vl_dri_scrn
->base
.pscreen
->get_tex_surface(vl_dri_scrn
->base
.pscreen
,
295 PIPE_BUFFER_USAGE_GPU_READ_WRITE
);
296 pipe_texture_reference(&front_tex
, NULL
);
303 vl_dri2_flush_frontbuffer(struct pipe_screen
*screen
,
304 struct pipe_surface
*surf
, void *context_private
)
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
;
312 assert(context_private
);
313 assert(vl_dri_ctx
->dri2_front
);
315 vl_dri_scrn
= (struct vl_dri_screen
*)vl_dri_ctx
->base
.vscreen
;
316 vpipe
= vl_dri_ctx
->base
.vpipe
;
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
);
321 //st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, fence);
326 vl_video_bind_drawable(struct vl_context
*vctx
, Drawable drawable
)
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
;
335 if (vl_dri_ctx
->drawable
)
336 old_drawable
= vl_dri_ctx
->drawable
->x_drawable
;
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
);
345 driCreateDrawable(vl_dri_scrn
->dri_screen
, drawable
, &dri_drawable
);
346 vl_dri_ctx
->drawable
= dri_drawable
;
354 vl_screen_create(Display
*display
, int screen
)
356 struct vl_dri_screen
*vl_dri_scrn
;
357 struct dri1_create_screen_arg arg
;
361 vl_dri_scrn
= CALLOC_STRUCT(vl_dri_screen
);
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
)) {
375 arg
.base
.mode
= DRM_CREATE_DRI1
;
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
);
384 vl_dri_scrn
->dri2
= FALSE
;
389 arg
.base
.mode
= DRM_CREATE_NORMAL
;
390 vl_dri_scrn
->dri2
= TRUE
;
393 vl_dri_scrn
->api
= drm_api_create();
394 if (!vl_dri_scrn
->api
) {
399 vl_dri_scrn
->base
.pscreen
= vl_dri_scrn
->api
->create_screen(vl_dri_scrn
->api
,
400 vl_dri_scrn
->dri_screen
->fd
,
403 if (!vl_dri_scrn
->base
.pscreen
) {
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
;
415 vl_dri_scrn
->base
.pscreen
->flush_frontbuffer
= vl_dri2_flush_frontbuffer
;
417 return &vl_dri_scrn
->base
;
420 void vl_screen_destroy(struct vl_screen
*vscreen
)
422 struct vl_dri_screen
*vl_dri_scrn
= (struct vl_dri_screen
*)vscreen
;
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
);
430 driDestroyScreen(vl_dri_scrn
->dri_screen
);
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
)
440 struct vl_dri_screen
*vl_dri_scrn
= (struct vl_dri_screen
*)vscreen
;
441 struct vl_dri_context
*vl_dri_ctx
;
443 vl_dri_ctx
= CALLOC_STRUCT(vl_dri_context
);
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
);
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
));
459 vl_dri_ctx
->base
.vpipe
= vscreen
->pscreen
->video_context_create(vscreen
->pscreen
,
460 profile
, chroma_format
,
462 vl_dri_ctx
->dri_context
);
464 if (!vl_dri_ctx
->base
.vpipe
) {
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
;
475 return &vl_dri_ctx
->base
;
478 void vl_video_destroy(struct vl_context
*vctx
)
480 struct vl_dri_context
*vl_dri_ctx
= (struct vl_dri_context
*)vctx
;
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
);