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 VMWARE 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 /* directly referenced from target Makefile, because of X dependencies */
30 #include <sys/types.h>
33 #include <X11/Xlib-xcb.h>
34 #include <X11/extensions/dri2tokens.h>
41 #include "pipe/p_screen.h"
42 #include "pipe/p_context.h"
43 #include "pipe/p_state.h"
44 #include "pipe-loader/pipe_loader.h"
45 #include "frontend/drm_driver.h"
47 #include "util/u_memory.h"
48 #include "util/crc32.h"
49 #include "util/u_hash_table.h"
50 #include "util/u_inlines.h"
52 #include "vl/vl_compositor.h"
53 #include "vl/vl_winsys.h"
57 struct vl_screen base
;
58 xcb_connection_t
*conn
;
59 xcb_drawable_t drawable
;
61 unsigned width
, height
;
64 uint32_t buffer_names
[2];
65 struct u_rect dirty_areas
[2];
68 xcb_dri2_swap_buffers_cookie_t swap_cookie
;
69 xcb_dri2_wait_sbc_cookie_t wait_cookie
;
70 xcb_dri2_get_buffers_cookie_t buffers_cookie
;
72 int64_t last_ust
, ns_frame
, last_msc
, next_msc
;
75 static const unsigned attachments
[1] = { XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT
};
77 static void vl_dri2_screen_destroy(struct vl_screen
*vscreen
);
80 vl_dri2_handle_stamps(struct vl_dri_screen
*scrn
,
81 uint32_t ust_hi
, uint32_t ust_lo
,
82 uint32_t msc_hi
, uint32_t msc_lo
)
84 int64_t ust
= ((((uint64_t)ust_hi
) << 32) | ust_lo
) * 1000;
85 int64_t msc
= (((uint64_t)msc_hi
) << 32) | msc_lo
;
87 if (scrn
->last_ust
&& (ust
> scrn
->last_ust
) &&
88 scrn
->last_msc
&& (msc
> scrn
->last_msc
))
89 scrn
->ns_frame
= (ust
- scrn
->last_ust
) / (msc
- scrn
->last_msc
);
95 static xcb_dri2_get_buffers_reply_t
*
96 vl_dri2_get_flush_reply(struct vl_dri_screen
*scrn
)
98 xcb_dri2_wait_sbc_reply_t
*wait_sbc_reply
;
105 scrn
->flushed
= false;
107 free(xcb_dri2_swap_buffers_reply(scrn
->conn
, scrn
->swap_cookie
, NULL
));
109 wait_sbc_reply
= xcb_dri2_wait_sbc_reply(scrn
->conn
, scrn
->wait_cookie
, NULL
);
112 vl_dri2_handle_stamps(scrn
, wait_sbc_reply
->ust_hi
, wait_sbc_reply
->ust_lo
,
113 wait_sbc_reply
->msc_hi
, wait_sbc_reply
->msc_lo
);
114 free(wait_sbc_reply
);
116 return xcb_dri2_get_buffers_reply(scrn
->conn
, scrn
->buffers_cookie
, NULL
);
120 vl_dri2_flush_frontbuffer(struct pipe_screen
*screen
,
121 struct pipe_resource
*resource
,
122 unsigned level
, unsigned layer
,
123 void *context_private
, struct pipe_box
*sub_box
)
125 struct vl_dri_screen
*scrn
= (struct vl_dri_screen
*)context_private
;
126 uint32_t msc_hi
, msc_lo
;
130 assert(context_private
);
132 free(vl_dri2_get_flush_reply(scrn
));
134 msc_hi
= scrn
->next_msc
>> 32;
135 msc_lo
= scrn
->next_msc
& 0xFFFFFFFF;
137 scrn
->swap_cookie
= xcb_dri2_swap_buffers_unchecked(scrn
->conn
, scrn
->drawable
,
138 msc_hi
, msc_lo
, 0, 0, 0, 0);
139 scrn
->wait_cookie
= xcb_dri2_wait_sbc_unchecked(scrn
->conn
, scrn
->drawable
, 0, 0);
140 scrn
->buffers_cookie
= xcb_dri2_get_buffers_unchecked(scrn
->conn
, scrn
->drawable
,
143 scrn
->flushed
= true;
144 scrn
->current_buffer
= !scrn
->current_buffer
;
148 vl_dri2_destroy_drawable(struct vl_dri_screen
*scrn
)
150 xcb_void_cookie_t destroy_cookie
;
151 if (scrn
->drawable
) {
152 free(vl_dri2_get_flush_reply(scrn
));
153 destroy_cookie
= xcb_dri2_destroy_drawable_checked(scrn
->conn
, scrn
->drawable
);
154 /* ignore any error here, since the drawable can be destroyed long ago */
155 free(xcb_request_check(scrn
->conn
, destroy_cookie
));
160 vl_dri2_set_drawable(struct vl_dri_screen
*scrn
, Drawable drawable
)
165 if (scrn
->drawable
== drawable
)
168 vl_dri2_destroy_drawable(scrn
);
170 xcb_dri2_create_drawable(scrn
->conn
, drawable
);
171 scrn
->current_buffer
= false;
172 vl_compositor_reset_dirty_area(&scrn
->dirty_areas
[0]);
173 vl_compositor_reset_dirty_area(&scrn
->dirty_areas
[1]);
174 scrn
->drawable
= drawable
;
177 static struct pipe_resource
*
178 vl_dri2_screen_texture_from_drawable(struct vl_screen
*vscreen
, void *drawable
)
180 struct vl_dri_screen
*scrn
= (struct vl_dri_screen
*)vscreen
;
182 struct winsys_handle dri2_handle
;
183 struct pipe_resource templ
, *tex
;
185 xcb_dri2_get_buffers_reply_t
*reply
;
186 xcb_dri2_dri2_buffer_t
*buffers
, *back_left
;
188 unsigned depth
= ((xcb_screen_t
*)(vscreen
->xcb_screen
))->root_depth
;
193 vl_dri2_set_drawable(scrn
, (Drawable
)drawable
);
194 reply
= vl_dri2_get_flush_reply(scrn
);
196 xcb_dri2_get_buffers_cookie_t cookie
;
197 cookie
= xcb_dri2_get_buffers_unchecked(scrn
->conn
, (Drawable
)drawable
,
199 reply
= xcb_dri2_get_buffers_reply(scrn
->conn
, cookie
, NULL
);
204 buffers
= xcb_dri2_get_buffers_buffers(reply
);
210 for (i
= 0; i
< reply
->count
; ++i
) {
211 if (buffers
[i
].attachment
== XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT
) {
212 back_left
= &buffers
[i
];
217 if (i
== reply
->count
) {
222 if (reply
->width
!= scrn
->width
|| reply
->height
!= scrn
->height
) {
223 vl_compositor_reset_dirty_area(&scrn
->dirty_areas
[0]);
224 vl_compositor_reset_dirty_area(&scrn
->dirty_areas
[1]);
225 scrn
->width
= reply
->width
;
226 scrn
->height
= reply
->height
;
228 } else if (back_left
->name
!= scrn
->buffer_names
[scrn
->current_buffer
]) {
229 vl_compositor_reset_dirty_area(&scrn
->dirty_areas
[scrn
->current_buffer
]);
230 scrn
->buffer_names
[scrn
->current_buffer
] = back_left
->name
;
233 memset(&dri2_handle
, 0, sizeof(dri2_handle
));
234 dri2_handle
.type
= WINSYS_HANDLE_TYPE_SHARED
;
235 dri2_handle
.handle
= back_left
->name
;
236 dri2_handle
.stride
= back_left
->pitch
;
238 memset(&templ
, 0, sizeof(templ
));
239 templ
.target
= PIPE_TEXTURE_2D
;
240 templ
.format
= vl_dri2_format_for_depth(vscreen
, depth
);
241 templ
.last_level
= 0;
242 templ
.width0
= reply
->width
;
243 templ
.height0
= reply
->height
;
245 templ
.array_size
= 1;
246 templ
.usage
= PIPE_USAGE_DEFAULT
;
247 templ
.bind
= PIPE_BIND_RENDER_TARGET
;
250 tex
= scrn
->base
.pscreen
->resource_from_handle(scrn
->base
.pscreen
, &templ
,
252 PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE
);
258 static struct u_rect
*
259 vl_dri2_screen_get_dirty_area(struct vl_screen
*vscreen
)
261 struct vl_dri_screen
*scrn
= (struct vl_dri_screen
*)vscreen
;
263 return &scrn
->dirty_areas
[scrn
->current_buffer
];
267 vl_dri2_screen_get_timestamp(struct vl_screen
*vscreen
, void *drawable
)
269 struct vl_dri_screen
*scrn
= (struct vl_dri_screen
*)vscreen
;
270 xcb_dri2_get_msc_cookie_t cookie
;
271 xcb_dri2_get_msc_reply_t
*reply
;
275 vl_dri2_set_drawable(scrn
, (Drawable
)drawable
);
276 if (!scrn
->last_ust
) {
277 cookie
= xcb_dri2_get_msc_unchecked(scrn
->conn
, (Drawable
)drawable
);
278 reply
= xcb_dri2_get_msc_reply(scrn
->conn
, cookie
, NULL
);
281 vl_dri2_handle_stamps(scrn
, reply
->ust_hi
, reply
->ust_lo
,
282 reply
->msc_hi
, reply
->msc_lo
);
286 return scrn
->last_ust
;
290 vl_dri2_screen_set_next_timestamp(struct vl_screen
*vscreen
, uint64_t stamp
)
292 struct vl_dri_screen
*scrn
= (struct vl_dri_screen
*)vscreen
;
294 if (stamp
&& scrn
->last_ust
&& scrn
->ns_frame
&& scrn
->last_msc
)
295 scrn
->next_msc
= ((int64_t)stamp
- scrn
->last_ust
+ scrn
->ns_frame
/2) /
296 scrn
->ns_frame
+ scrn
->last_msc
;
302 vl_dri2_screen_get_private(struct vl_screen
*vscreen
)
307 static xcb_screen_t
*
308 get_xcb_screen(xcb_screen_iterator_t iter
, int screen
)
310 for (; iter
.rem
; --screen
, xcb_screen_next(&iter
))
317 static xcb_visualtype_t
*
318 get_xcb_visualtype_for_depth(struct vl_screen
*vscreen
, int depth
)
320 xcb_visualtype_iterator_t visual_iter
;
321 xcb_screen_t
*screen
= vscreen
->xcb_screen
;
322 xcb_depth_iterator_t depth_iter
;
327 depth_iter
= xcb_screen_allowed_depths_iterator(screen
);
328 for (; depth_iter
.rem
; xcb_depth_next(&depth_iter
)) {
329 if (depth_iter
.data
->depth
!= depth
)
332 visual_iter
= xcb_depth_visuals_iterator(depth_iter
.data
);
334 return visual_iter
.data
;
341 get_red_mask_for_depth(struct vl_screen
*vscreen
, int depth
)
343 xcb_visualtype_t
*visual
= get_xcb_visualtype_for_depth(vscreen
, depth
);
346 return visual
->red_mask
;
353 vl_dri2_format_for_depth(struct vl_screen
*vscreen
, int depth
)
357 return PIPE_FORMAT_B8G8R8X8_UNORM
;
359 /* Different preferred formats for different hw */
360 if (get_red_mask_for_depth(vscreen
, 30) == 0x3ff)
361 return PIPE_FORMAT_R10G10B10X2_UNORM
;
363 return PIPE_FORMAT_B10G10R10X2_UNORM
;
365 return PIPE_FORMAT_NONE
;
370 vl_dri2_screen_create(Display
*display
, int screen
)
372 struct vl_dri_screen
*scrn
;
373 const xcb_query_extension_reply_t
*extension
;
374 xcb_dri2_query_version_cookie_t dri2_query_cookie
;
375 xcb_dri2_query_version_reply_t
*dri2_query
= NULL
;
376 xcb_dri2_connect_cookie_t connect_cookie
;
377 xcb_dri2_connect_reply_t
*connect
= NULL
;
378 xcb_dri2_authenticate_cookie_t authenticate_cookie
;
379 xcb_dri2_authenticate_reply_t
*authenticate
= NULL
;
380 xcb_screen_iterator_t s
;
381 xcb_generic_error_t
*error
= NULL
;
383 int fd
, device_name_length
;
390 scrn
= CALLOC_STRUCT(vl_dri_screen
);
394 scrn
->conn
= XGetXCBConnection(display
);
398 xcb_prefetch_extension_data(scrn
->conn
, &xcb_dri2_id
);
400 extension
= xcb_get_extension_data(scrn
->conn
, &xcb_dri2_id
);
401 if (!(extension
&& extension
->present
))
404 dri2_query_cookie
= xcb_dri2_query_version (scrn
->conn
,
405 XCB_DRI2_MAJOR_VERSION
,
406 XCB_DRI2_MINOR_VERSION
);
407 dri2_query
= xcb_dri2_query_version_reply (scrn
->conn
, dri2_query_cookie
, &error
);
408 if (dri2_query
== NULL
|| error
!= NULL
|| dri2_query
->minor_version
< 2)
411 s
= xcb_setup_roots_iterator(xcb_get_setup(scrn
->conn
));
412 scrn
->base
.xcb_screen
= get_xcb_screen(s
, screen
);
413 if (!scrn
->base
.xcb_screen
)
416 driverType
= XCB_DRI2_DRIVER_TYPE_DRI
;
418 char *prime
= getenv("DRI_PRIME");
422 primeid
= strtoul(prime
, NULL
, 0);
425 ((primeid
& DRI2DriverPrimeMask
) << DRI2DriverPrimeShift
);
429 connect_cookie
= xcb_dri2_connect_unchecked(
430 scrn
->conn
, ((xcb_screen_t
*)(scrn
->base
.xcb_screen
))->root
, driverType
);
431 connect
= xcb_dri2_connect_reply(scrn
->conn
, connect_cookie
, NULL
);
432 if (connect
== NULL
||
433 connect
->driver_name_length
+ connect
->device_name_length
== 0)
436 device_name_length
= xcb_dri2_connect_device_name_length(connect
);
437 device_name
= CALLOC(1, device_name_length
+ 1);
440 memcpy(device_name
, xcb_dri2_connect_device_name(connect
), device_name_length
);
441 fd
= loader_open_device(device_name
);
447 if (drmGetMagic(fd
, &magic
))
450 authenticate_cookie
= xcb_dri2_authenticate_unchecked(
451 scrn
->conn
, ((xcb_screen_t
*)(scrn
->base
.xcb_screen
))->root
, magic
);
452 authenticate
= xcb_dri2_authenticate_reply(scrn
->conn
, authenticate_cookie
, NULL
);
454 if (authenticate
== NULL
|| !authenticate
->authenticated
)
455 goto free_authenticate
;
457 if (pipe_loader_drm_probe_fd(&scrn
->base
.dev
, fd
))
458 scrn
->base
.pscreen
= pipe_loader_create_screen(scrn
->base
.dev
);
460 if (!scrn
->base
.pscreen
)
463 scrn
->base
.destroy
= vl_dri2_screen_destroy
;
464 scrn
->base
.texture_from_drawable
= vl_dri2_screen_texture_from_drawable
;
465 scrn
->base
.get_dirty_area
= vl_dri2_screen_get_dirty_area
;
466 scrn
->base
.get_timestamp
= vl_dri2_screen_get_timestamp
;
467 scrn
->base
.set_next_timestamp
= vl_dri2_screen_set_next_timestamp
;
468 scrn
->base
.get_private
= vl_dri2_screen_get_private
;
469 scrn
->base
.pscreen
->flush_frontbuffer
= vl_dri2_flush_frontbuffer
;
470 vl_compositor_reset_dirty_area(&scrn
->dirty_areas
[0]);
471 vl_compositor_reset_dirty_area(&scrn
->dirty_areas
[1]);
473 /* The pipe loader duplicates the fd */
484 pipe_loader_release(&scrn
->base
.dev
, 1);
501 vl_dri2_screen_destroy(struct vl_screen
*vscreen
)
503 struct vl_dri_screen
*scrn
= (struct vl_dri_screen
*)vscreen
;
508 free(xcb_dri2_swap_buffers_reply(scrn
->conn
, scrn
->swap_cookie
, NULL
));
509 free(xcb_dri2_wait_sbc_reply(scrn
->conn
, scrn
->wait_cookie
, NULL
));
510 free(xcb_dri2_get_buffers_reply(scrn
->conn
, scrn
->buffers_cookie
, NULL
));
513 vl_dri2_destroy_drawable(scrn
);
514 scrn
->base
.pscreen
->destroy(scrn
->base
.pscreen
);
515 pipe_loader_release(&scrn
->base
.dev
, 1);
516 /* There is no user provided fd */