1bf215546Sopenharmony_ci/**************************************************************************
2bf215546Sopenharmony_ci *
3bf215546Sopenharmony_ci * Copyright 2009 Younes Manton.
4bf215546Sopenharmony_ci * All Rights Reserved.
5bf215546Sopenharmony_ci *
6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the
8bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
9bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
10bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
11bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
12bf215546Sopenharmony_ci * the following conditions:
13bf215546Sopenharmony_ci *
14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the
15bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
16bf215546Sopenharmony_ci * of the Software.
17bf215546Sopenharmony_ci *
18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21bf215546Sopenharmony_ci * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25bf215546Sopenharmony_ci *
26bf215546Sopenharmony_ci **************************************************************************/
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci/* directly referenced from target Makefile, because of X dependencies */
29bf215546Sopenharmony_ci
30bf215546Sopenharmony_ci#include <sys/types.h>
31bf215546Sopenharmony_ci#include <sys/stat.h>
32bf215546Sopenharmony_ci
33bf215546Sopenharmony_ci#include <X11/Xlib-xcb.h>
34bf215546Sopenharmony_ci#include <X11/extensions/dri2tokens.h>
35bf215546Sopenharmony_ci#include <xcb/dri2.h>
36bf215546Sopenharmony_ci#include <xf86drm.h>
37bf215546Sopenharmony_ci#include <errno.h>
38bf215546Sopenharmony_ci
39bf215546Sopenharmony_ci#include "loader.h"
40bf215546Sopenharmony_ci
41bf215546Sopenharmony_ci#include "pipe/p_screen.h"
42bf215546Sopenharmony_ci#include "pipe/p_context.h"
43bf215546Sopenharmony_ci#include "pipe/p_state.h"
44bf215546Sopenharmony_ci#include "pipe-loader/pipe_loader.h"
45bf215546Sopenharmony_ci#include "frontend/drm_driver.h"
46bf215546Sopenharmony_ci
47bf215546Sopenharmony_ci#include "util/u_memory.h"
48bf215546Sopenharmony_ci#include "util/crc32.h"
49bf215546Sopenharmony_ci#include "util/u_hash_table.h"
50bf215546Sopenharmony_ci#include "util/u_inlines.h"
51bf215546Sopenharmony_ci
52bf215546Sopenharmony_ci#include "vl/vl_compositor.h"
53bf215546Sopenharmony_ci#include "vl/vl_winsys.h"
54bf215546Sopenharmony_ci
55bf215546Sopenharmony_ci#include "drm-uapi/drm_fourcc.h"
56bf215546Sopenharmony_ci
57bf215546Sopenharmony_cistruct vl_dri_screen
58bf215546Sopenharmony_ci{
59bf215546Sopenharmony_ci   struct vl_screen base;
60bf215546Sopenharmony_ci   xcb_connection_t *conn;
61bf215546Sopenharmony_ci   xcb_drawable_t drawable;
62bf215546Sopenharmony_ci
63bf215546Sopenharmony_ci   unsigned width, height;
64bf215546Sopenharmony_ci
65bf215546Sopenharmony_ci   bool current_buffer;
66bf215546Sopenharmony_ci   uint32_t buffer_names[2];
67bf215546Sopenharmony_ci   struct u_rect dirty_areas[2];
68bf215546Sopenharmony_ci
69bf215546Sopenharmony_ci   bool flushed;
70bf215546Sopenharmony_ci   xcb_dri2_swap_buffers_cookie_t swap_cookie;
71bf215546Sopenharmony_ci   xcb_dri2_wait_sbc_cookie_t wait_cookie;
72bf215546Sopenharmony_ci   xcb_dri2_get_buffers_cookie_t buffers_cookie;
73bf215546Sopenharmony_ci
74bf215546Sopenharmony_ci   int64_t last_ust, ns_frame, last_msc, next_msc;
75bf215546Sopenharmony_ci};
76bf215546Sopenharmony_ci
77bf215546Sopenharmony_cistatic const unsigned attachments[1] = { XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT };
78bf215546Sopenharmony_ci
79bf215546Sopenharmony_cistatic void vl_dri2_screen_destroy(struct vl_screen *vscreen);
80bf215546Sopenharmony_ci
81bf215546Sopenharmony_cistatic void
82bf215546Sopenharmony_civl_dri2_handle_stamps(struct vl_dri_screen *scrn,
83bf215546Sopenharmony_ci                      uint32_t ust_hi, uint32_t ust_lo,
84bf215546Sopenharmony_ci                      uint32_t msc_hi, uint32_t msc_lo)
85bf215546Sopenharmony_ci{
86bf215546Sopenharmony_ci   int64_t ust = ((((uint64_t)ust_hi) << 32) | ust_lo) * 1000;
87bf215546Sopenharmony_ci   int64_t msc = (((uint64_t)msc_hi) << 32) | msc_lo;
88bf215546Sopenharmony_ci
89bf215546Sopenharmony_ci   if (scrn->last_ust && (ust > scrn->last_ust) &&
90bf215546Sopenharmony_ci       scrn->last_msc && (msc > scrn->last_msc))
91bf215546Sopenharmony_ci      scrn->ns_frame = (ust - scrn->last_ust) / (msc - scrn->last_msc);
92bf215546Sopenharmony_ci
93bf215546Sopenharmony_ci   scrn->last_ust = ust;
94bf215546Sopenharmony_ci   scrn->last_msc = msc;
95bf215546Sopenharmony_ci}
96bf215546Sopenharmony_ci
97bf215546Sopenharmony_cistatic xcb_dri2_get_buffers_reply_t *
98bf215546Sopenharmony_civl_dri2_get_flush_reply(struct vl_dri_screen *scrn)
99bf215546Sopenharmony_ci{
100bf215546Sopenharmony_ci   xcb_dri2_wait_sbc_reply_t *wait_sbc_reply;
101bf215546Sopenharmony_ci
102bf215546Sopenharmony_ci   assert(scrn);
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_ci   if (!scrn->flushed)
105bf215546Sopenharmony_ci      return NULL;
106bf215546Sopenharmony_ci
107bf215546Sopenharmony_ci   scrn->flushed = false;
108bf215546Sopenharmony_ci
109bf215546Sopenharmony_ci   free(xcb_dri2_swap_buffers_reply(scrn->conn, scrn->swap_cookie, NULL));
110bf215546Sopenharmony_ci
111bf215546Sopenharmony_ci   wait_sbc_reply = xcb_dri2_wait_sbc_reply(scrn->conn, scrn->wait_cookie, NULL);
112bf215546Sopenharmony_ci   if (!wait_sbc_reply)
113bf215546Sopenharmony_ci      return NULL;
114bf215546Sopenharmony_ci   vl_dri2_handle_stamps(scrn, wait_sbc_reply->ust_hi, wait_sbc_reply->ust_lo,
115bf215546Sopenharmony_ci                         wait_sbc_reply->msc_hi, wait_sbc_reply->msc_lo);
116bf215546Sopenharmony_ci   free(wait_sbc_reply);
117bf215546Sopenharmony_ci
118bf215546Sopenharmony_ci   return xcb_dri2_get_buffers_reply(scrn->conn, scrn->buffers_cookie, NULL);
119bf215546Sopenharmony_ci}
120bf215546Sopenharmony_ci
121bf215546Sopenharmony_cistatic void
122bf215546Sopenharmony_civl_dri2_flush_frontbuffer(struct pipe_screen *screen,
123bf215546Sopenharmony_ci                          struct pipe_context *pipe,
124bf215546Sopenharmony_ci                          struct pipe_resource *resource,
125bf215546Sopenharmony_ci                          unsigned level, unsigned layer,
126bf215546Sopenharmony_ci                          void *context_private, struct pipe_box *sub_box)
127bf215546Sopenharmony_ci{
128bf215546Sopenharmony_ci   struct vl_dri_screen *scrn = (struct vl_dri_screen *)context_private;
129bf215546Sopenharmony_ci   uint32_t msc_hi, msc_lo;
130bf215546Sopenharmony_ci
131bf215546Sopenharmony_ci   assert(screen);
132bf215546Sopenharmony_ci   assert(resource);
133bf215546Sopenharmony_ci   assert(context_private);
134bf215546Sopenharmony_ci
135bf215546Sopenharmony_ci   free(vl_dri2_get_flush_reply(scrn));
136bf215546Sopenharmony_ci
137bf215546Sopenharmony_ci   msc_hi = scrn->next_msc >> 32;
138bf215546Sopenharmony_ci   msc_lo = scrn->next_msc & 0xFFFFFFFF;
139bf215546Sopenharmony_ci
140bf215546Sopenharmony_ci   scrn->swap_cookie = xcb_dri2_swap_buffers_unchecked(scrn->conn, scrn->drawable,
141bf215546Sopenharmony_ci                                                       msc_hi, msc_lo, 0, 0, 0, 0);
142bf215546Sopenharmony_ci   scrn->wait_cookie = xcb_dri2_wait_sbc_unchecked(scrn->conn, scrn->drawable, 0, 0);
143bf215546Sopenharmony_ci   scrn->buffers_cookie = xcb_dri2_get_buffers_unchecked(scrn->conn, scrn->drawable,
144bf215546Sopenharmony_ci                                                         1, 1, attachments);
145bf215546Sopenharmony_ci
146bf215546Sopenharmony_ci   scrn->flushed = true;
147bf215546Sopenharmony_ci   scrn->current_buffer = !scrn->current_buffer;
148bf215546Sopenharmony_ci}
149bf215546Sopenharmony_ci
150bf215546Sopenharmony_cistatic void
151bf215546Sopenharmony_civl_dri2_destroy_drawable(struct vl_dri_screen *scrn)
152bf215546Sopenharmony_ci{
153bf215546Sopenharmony_ci   xcb_void_cookie_t destroy_cookie;
154bf215546Sopenharmony_ci   if (scrn->drawable) {
155bf215546Sopenharmony_ci      free(vl_dri2_get_flush_reply(scrn));
156bf215546Sopenharmony_ci      destroy_cookie = xcb_dri2_destroy_drawable_checked(scrn->conn, scrn->drawable);
157bf215546Sopenharmony_ci      /* ignore any error here, since the drawable can be destroyed long ago */
158bf215546Sopenharmony_ci      free(xcb_request_check(scrn->conn, destroy_cookie));
159bf215546Sopenharmony_ci   }
160bf215546Sopenharmony_ci}
161bf215546Sopenharmony_ci
162bf215546Sopenharmony_cistatic void
163bf215546Sopenharmony_civl_dri2_set_drawable(struct vl_dri_screen *scrn, Drawable drawable)
164bf215546Sopenharmony_ci{
165bf215546Sopenharmony_ci   assert(scrn);
166bf215546Sopenharmony_ci   assert(drawable);
167bf215546Sopenharmony_ci
168bf215546Sopenharmony_ci   if (scrn->drawable == drawable)
169bf215546Sopenharmony_ci      return;
170bf215546Sopenharmony_ci
171bf215546Sopenharmony_ci   vl_dri2_destroy_drawable(scrn);
172bf215546Sopenharmony_ci
173bf215546Sopenharmony_ci   xcb_dri2_create_drawable(scrn->conn, drawable);
174bf215546Sopenharmony_ci   scrn->current_buffer = false;
175bf215546Sopenharmony_ci   vl_compositor_reset_dirty_area(&scrn->dirty_areas[0]);
176bf215546Sopenharmony_ci   vl_compositor_reset_dirty_area(&scrn->dirty_areas[1]);
177bf215546Sopenharmony_ci   scrn->drawable = drawable;
178bf215546Sopenharmony_ci}
179bf215546Sopenharmony_ci
180bf215546Sopenharmony_cistatic struct pipe_resource *
181bf215546Sopenharmony_civl_dri2_screen_texture_from_drawable(struct vl_screen *vscreen, void *drawable)
182bf215546Sopenharmony_ci{
183bf215546Sopenharmony_ci   struct vl_dri_screen *scrn = (struct vl_dri_screen *)vscreen;
184bf215546Sopenharmony_ci
185bf215546Sopenharmony_ci   struct winsys_handle dri2_handle;
186bf215546Sopenharmony_ci   struct pipe_resource templ, *tex;
187bf215546Sopenharmony_ci
188bf215546Sopenharmony_ci   xcb_dri2_get_buffers_reply_t *reply;
189bf215546Sopenharmony_ci   xcb_dri2_dri2_buffer_t *buffers, *back_left = NULL;
190bf215546Sopenharmony_ci
191bf215546Sopenharmony_ci   unsigned depth = ((xcb_screen_t *)(vscreen->xcb_screen))->root_depth;
192bf215546Sopenharmony_ci   unsigned i;
193bf215546Sopenharmony_ci
194bf215546Sopenharmony_ci   assert(scrn);
195bf215546Sopenharmony_ci
196bf215546Sopenharmony_ci   vl_dri2_set_drawable(scrn, (Drawable)drawable);
197bf215546Sopenharmony_ci   reply = vl_dri2_get_flush_reply(scrn);
198bf215546Sopenharmony_ci   if (!reply) {
199bf215546Sopenharmony_ci      xcb_dri2_get_buffers_cookie_t cookie;
200bf215546Sopenharmony_ci      cookie = xcb_dri2_get_buffers_unchecked(scrn->conn, (Drawable)drawable,
201bf215546Sopenharmony_ci                                              1, 1, attachments);
202bf215546Sopenharmony_ci      reply = xcb_dri2_get_buffers_reply(scrn->conn, cookie, NULL);
203bf215546Sopenharmony_ci   }
204bf215546Sopenharmony_ci   if (!reply)
205bf215546Sopenharmony_ci      return NULL;
206bf215546Sopenharmony_ci
207bf215546Sopenharmony_ci   buffers = xcb_dri2_get_buffers_buffers(reply);
208bf215546Sopenharmony_ci   if (!buffers)  {
209bf215546Sopenharmony_ci      free(reply);
210bf215546Sopenharmony_ci      return NULL;
211bf215546Sopenharmony_ci   }
212bf215546Sopenharmony_ci
213bf215546Sopenharmony_ci   for (i = 0; i < reply->count; ++i) {
214bf215546Sopenharmony_ci      if (buffers[i].attachment == XCB_DRI2_ATTACHMENT_BUFFER_BACK_LEFT) {
215bf215546Sopenharmony_ci         back_left = &buffers[i];
216bf215546Sopenharmony_ci         break;
217bf215546Sopenharmony_ci      }
218bf215546Sopenharmony_ci   }
219bf215546Sopenharmony_ci
220bf215546Sopenharmony_ci   if (i == reply->count || !back_left) {
221bf215546Sopenharmony_ci      free(reply);
222bf215546Sopenharmony_ci      return NULL;
223bf215546Sopenharmony_ci   }
224bf215546Sopenharmony_ci
225bf215546Sopenharmony_ci   if (reply->width != scrn->width || reply->height != scrn->height) {
226bf215546Sopenharmony_ci      vl_compositor_reset_dirty_area(&scrn->dirty_areas[0]);
227bf215546Sopenharmony_ci      vl_compositor_reset_dirty_area(&scrn->dirty_areas[1]);
228bf215546Sopenharmony_ci      scrn->width = reply->width;
229bf215546Sopenharmony_ci      scrn->height = reply->height;
230bf215546Sopenharmony_ci
231bf215546Sopenharmony_ci   } else if (back_left->name != scrn->buffer_names[scrn->current_buffer]) {
232bf215546Sopenharmony_ci      vl_compositor_reset_dirty_area(&scrn->dirty_areas[scrn->current_buffer]);
233bf215546Sopenharmony_ci      scrn->buffer_names[scrn->current_buffer] = back_left->name;
234bf215546Sopenharmony_ci   }
235bf215546Sopenharmony_ci
236bf215546Sopenharmony_ci   memset(&dri2_handle, 0, sizeof(dri2_handle));
237bf215546Sopenharmony_ci   dri2_handle.type = WINSYS_HANDLE_TYPE_SHARED;
238bf215546Sopenharmony_ci   dri2_handle.handle = back_left->name;
239bf215546Sopenharmony_ci   dri2_handle.stride = back_left->pitch;
240bf215546Sopenharmony_ci   dri2_handle.modifier = DRM_FORMAT_MOD_INVALID;
241bf215546Sopenharmony_ci
242bf215546Sopenharmony_ci   memset(&templ, 0, sizeof(templ));
243bf215546Sopenharmony_ci   templ.target = PIPE_TEXTURE_2D;
244bf215546Sopenharmony_ci   templ.format = vl_dri2_format_for_depth(vscreen, depth);
245bf215546Sopenharmony_ci   templ.last_level = 0;
246bf215546Sopenharmony_ci   templ.width0 = reply->width;
247bf215546Sopenharmony_ci   templ.height0 = reply->height;
248bf215546Sopenharmony_ci   templ.depth0 = 1;
249bf215546Sopenharmony_ci   templ.array_size = 1;
250bf215546Sopenharmony_ci   templ.usage = PIPE_USAGE_DEFAULT;
251bf215546Sopenharmony_ci   templ.bind = PIPE_BIND_RENDER_TARGET;
252bf215546Sopenharmony_ci   templ.flags = 0;
253bf215546Sopenharmony_ci
254bf215546Sopenharmony_ci   tex = scrn->base.pscreen->resource_from_handle(scrn->base.pscreen, &templ,
255bf215546Sopenharmony_ci                                                  &dri2_handle,
256bf215546Sopenharmony_ci                                                  PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE);
257bf215546Sopenharmony_ci   free(reply);
258bf215546Sopenharmony_ci
259bf215546Sopenharmony_ci   return tex;
260bf215546Sopenharmony_ci}
261bf215546Sopenharmony_ci
262bf215546Sopenharmony_cistatic struct u_rect *
263bf215546Sopenharmony_civl_dri2_screen_get_dirty_area(struct vl_screen *vscreen)
264bf215546Sopenharmony_ci{
265bf215546Sopenharmony_ci   struct vl_dri_screen *scrn = (struct vl_dri_screen *)vscreen;
266bf215546Sopenharmony_ci   assert(scrn);
267bf215546Sopenharmony_ci   return &scrn->dirty_areas[scrn->current_buffer];
268bf215546Sopenharmony_ci}
269bf215546Sopenharmony_ci
270bf215546Sopenharmony_cistatic uint64_t
271bf215546Sopenharmony_civl_dri2_screen_get_timestamp(struct vl_screen *vscreen, void *drawable)
272bf215546Sopenharmony_ci{
273bf215546Sopenharmony_ci   struct vl_dri_screen *scrn = (struct vl_dri_screen *)vscreen;
274bf215546Sopenharmony_ci   xcb_dri2_get_msc_cookie_t cookie;
275bf215546Sopenharmony_ci   xcb_dri2_get_msc_reply_t *reply;
276bf215546Sopenharmony_ci
277bf215546Sopenharmony_ci   assert(scrn);
278bf215546Sopenharmony_ci
279bf215546Sopenharmony_ci   vl_dri2_set_drawable(scrn, (Drawable)drawable);
280bf215546Sopenharmony_ci   if (!scrn->last_ust) {
281bf215546Sopenharmony_ci      cookie = xcb_dri2_get_msc_unchecked(scrn->conn, (Drawable)drawable);
282bf215546Sopenharmony_ci      reply = xcb_dri2_get_msc_reply(scrn->conn, cookie, NULL);
283bf215546Sopenharmony_ci
284bf215546Sopenharmony_ci      if (reply) {
285bf215546Sopenharmony_ci         vl_dri2_handle_stamps(scrn, reply->ust_hi, reply->ust_lo,
286bf215546Sopenharmony_ci                               reply->msc_hi, reply->msc_lo);
287bf215546Sopenharmony_ci         free(reply);
288bf215546Sopenharmony_ci      }
289bf215546Sopenharmony_ci   }
290bf215546Sopenharmony_ci   return scrn->last_ust;
291bf215546Sopenharmony_ci}
292bf215546Sopenharmony_ci
293bf215546Sopenharmony_cistatic void
294bf215546Sopenharmony_civl_dri2_screen_set_next_timestamp(struct vl_screen *vscreen, uint64_t stamp)
295bf215546Sopenharmony_ci{
296bf215546Sopenharmony_ci   struct vl_dri_screen *scrn = (struct vl_dri_screen *)vscreen;
297bf215546Sopenharmony_ci   assert(scrn);
298bf215546Sopenharmony_ci   if (stamp && scrn->last_ust && scrn->ns_frame && scrn->last_msc)
299bf215546Sopenharmony_ci      scrn->next_msc = ((int64_t)stamp - scrn->last_ust + scrn->ns_frame/2) /
300bf215546Sopenharmony_ci                       scrn->ns_frame + scrn->last_msc;
301bf215546Sopenharmony_ci   else
302bf215546Sopenharmony_ci      scrn->next_msc = 0;
303bf215546Sopenharmony_ci}
304bf215546Sopenharmony_ci
305bf215546Sopenharmony_cistatic void *
306bf215546Sopenharmony_civl_dri2_screen_get_private(struct vl_screen *vscreen)
307bf215546Sopenharmony_ci{
308bf215546Sopenharmony_ci   return vscreen;
309bf215546Sopenharmony_ci}
310bf215546Sopenharmony_ci
311bf215546Sopenharmony_cistatic xcb_screen_t *
312bf215546Sopenharmony_ciget_xcb_screen(xcb_screen_iterator_t iter, int screen)
313bf215546Sopenharmony_ci{
314bf215546Sopenharmony_ci    for (; iter.rem; --screen, xcb_screen_next(&iter))
315bf215546Sopenharmony_ci        if (screen == 0)
316bf215546Sopenharmony_ci            return iter.data;
317bf215546Sopenharmony_ci
318bf215546Sopenharmony_ci    return NULL;
319bf215546Sopenharmony_ci}
320bf215546Sopenharmony_ci
321bf215546Sopenharmony_cistatic xcb_visualtype_t *
322bf215546Sopenharmony_ciget_xcb_visualtype_for_depth(struct vl_screen *vscreen, int depth)
323bf215546Sopenharmony_ci{
324bf215546Sopenharmony_ci   xcb_visualtype_iterator_t visual_iter;
325bf215546Sopenharmony_ci   xcb_screen_t *screen = vscreen->xcb_screen;
326bf215546Sopenharmony_ci   xcb_depth_iterator_t depth_iter;
327bf215546Sopenharmony_ci
328bf215546Sopenharmony_ci   if (!screen)
329bf215546Sopenharmony_ci      return NULL;
330bf215546Sopenharmony_ci
331bf215546Sopenharmony_ci   depth_iter = xcb_screen_allowed_depths_iterator(screen);
332bf215546Sopenharmony_ci   for (; depth_iter.rem; xcb_depth_next(&depth_iter)) {
333bf215546Sopenharmony_ci      if (depth_iter.data->depth != depth)
334bf215546Sopenharmony_ci         continue;
335bf215546Sopenharmony_ci
336bf215546Sopenharmony_ci      visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
337bf215546Sopenharmony_ci      if (visual_iter.rem)
338bf215546Sopenharmony_ci         return visual_iter.data;
339bf215546Sopenharmony_ci   }
340bf215546Sopenharmony_ci
341bf215546Sopenharmony_ci   return NULL;
342bf215546Sopenharmony_ci}
343bf215546Sopenharmony_ci
344bf215546Sopenharmony_cistatic uint32_t
345bf215546Sopenharmony_ciget_red_mask_for_depth(struct vl_screen *vscreen, int depth)
346bf215546Sopenharmony_ci{
347bf215546Sopenharmony_ci   xcb_visualtype_t *visual = get_xcb_visualtype_for_depth(vscreen, depth);
348bf215546Sopenharmony_ci
349bf215546Sopenharmony_ci   if (visual) {
350bf215546Sopenharmony_ci      return visual->red_mask;
351bf215546Sopenharmony_ci   }
352bf215546Sopenharmony_ci
353bf215546Sopenharmony_ci   return 0;
354bf215546Sopenharmony_ci}
355bf215546Sopenharmony_ci
356bf215546Sopenharmony_ciuint32_t
357bf215546Sopenharmony_civl_dri2_format_for_depth(struct vl_screen *vscreen, int depth)
358bf215546Sopenharmony_ci{
359bf215546Sopenharmony_ci   switch (depth) {
360bf215546Sopenharmony_ci   case 24:
361bf215546Sopenharmony_ci      return PIPE_FORMAT_B8G8R8X8_UNORM;
362bf215546Sopenharmony_ci   case 30:
363bf215546Sopenharmony_ci      /* Different preferred formats for different hw */
364bf215546Sopenharmony_ci      if (get_red_mask_for_depth(vscreen, 30) == 0x3ff)
365bf215546Sopenharmony_ci         return PIPE_FORMAT_R10G10B10X2_UNORM;
366bf215546Sopenharmony_ci      else
367bf215546Sopenharmony_ci         return PIPE_FORMAT_B10G10R10X2_UNORM;
368bf215546Sopenharmony_ci   default:
369bf215546Sopenharmony_ci      return PIPE_FORMAT_NONE;
370bf215546Sopenharmony_ci   }
371bf215546Sopenharmony_ci}
372bf215546Sopenharmony_ci
373bf215546Sopenharmony_cistruct vl_screen *
374bf215546Sopenharmony_civl_dri2_screen_create(Display *display, int screen)
375bf215546Sopenharmony_ci{
376bf215546Sopenharmony_ci   struct vl_dri_screen *scrn;
377bf215546Sopenharmony_ci   const xcb_query_extension_reply_t *extension;
378bf215546Sopenharmony_ci   xcb_dri2_query_version_cookie_t dri2_query_cookie;
379bf215546Sopenharmony_ci   xcb_dri2_query_version_reply_t *dri2_query = NULL;
380bf215546Sopenharmony_ci   xcb_dri2_connect_cookie_t connect_cookie;
381bf215546Sopenharmony_ci   xcb_dri2_connect_reply_t *connect = NULL;
382bf215546Sopenharmony_ci   xcb_dri2_authenticate_cookie_t authenticate_cookie;
383bf215546Sopenharmony_ci   xcb_dri2_authenticate_reply_t *authenticate = NULL;
384bf215546Sopenharmony_ci   xcb_screen_iterator_t s;
385bf215546Sopenharmony_ci   xcb_generic_error_t *error = NULL;
386bf215546Sopenharmony_ci   char *device_name;
387bf215546Sopenharmony_ci   int fd, device_name_length;
388bf215546Sopenharmony_ci   unsigned driverType;
389bf215546Sopenharmony_ci
390bf215546Sopenharmony_ci   drm_magic_t magic;
391bf215546Sopenharmony_ci
392bf215546Sopenharmony_ci   assert(display);
393bf215546Sopenharmony_ci
394bf215546Sopenharmony_ci   scrn = CALLOC_STRUCT(vl_dri_screen);
395bf215546Sopenharmony_ci   if (!scrn)
396bf215546Sopenharmony_ci      return NULL;
397bf215546Sopenharmony_ci
398bf215546Sopenharmony_ci   scrn->conn = XGetXCBConnection(display);
399bf215546Sopenharmony_ci   if (!scrn->conn)
400bf215546Sopenharmony_ci      goto free_screen;
401bf215546Sopenharmony_ci
402bf215546Sopenharmony_ci   xcb_prefetch_extension_data(scrn->conn, &xcb_dri2_id);
403bf215546Sopenharmony_ci
404bf215546Sopenharmony_ci   extension = xcb_get_extension_data(scrn->conn, &xcb_dri2_id);
405bf215546Sopenharmony_ci   if (!(extension && extension->present))
406bf215546Sopenharmony_ci      goto free_screen;
407bf215546Sopenharmony_ci
408bf215546Sopenharmony_ci   dri2_query_cookie = xcb_dri2_query_version (scrn->conn,
409bf215546Sopenharmony_ci                                               XCB_DRI2_MAJOR_VERSION,
410bf215546Sopenharmony_ci                                               XCB_DRI2_MINOR_VERSION);
411bf215546Sopenharmony_ci   dri2_query = xcb_dri2_query_version_reply (scrn->conn, dri2_query_cookie, &error);
412bf215546Sopenharmony_ci   if (dri2_query == NULL || error != NULL || dri2_query->minor_version < 2)
413bf215546Sopenharmony_ci      goto free_query;
414bf215546Sopenharmony_ci
415bf215546Sopenharmony_ci   s = xcb_setup_roots_iterator(xcb_get_setup(scrn->conn));
416bf215546Sopenharmony_ci   scrn->base.xcb_screen = get_xcb_screen(s, screen);
417bf215546Sopenharmony_ci   if (!scrn->base.xcb_screen)
418bf215546Sopenharmony_ci      goto free_query;
419bf215546Sopenharmony_ci
420bf215546Sopenharmony_ci   driverType = XCB_DRI2_DRIVER_TYPE_DRI;
421bf215546Sopenharmony_ci   {
422bf215546Sopenharmony_ci      char *prime = getenv("DRI_PRIME");
423bf215546Sopenharmony_ci      if (prime) {
424bf215546Sopenharmony_ci         unsigned primeid;
425bf215546Sopenharmony_ci         errno = 0;
426bf215546Sopenharmony_ci         primeid = strtoul(prime, NULL, 0);
427bf215546Sopenharmony_ci         if (errno == 0)
428bf215546Sopenharmony_ci            driverType |=
429bf215546Sopenharmony_ci               ((primeid & DRI2DriverPrimeMask) << DRI2DriverPrimeShift);
430bf215546Sopenharmony_ci      }
431bf215546Sopenharmony_ci   }
432bf215546Sopenharmony_ci
433bf215546Sopenharmony_ci   connect_cookie = xcb_dri2_connect_unchecked(
434bf215546Sopenharmony_ci      scrn->conn, ((xcb_screen_t *)(scrn->base.xcb_screen))->root, driverType);
435bf215546Sopenharmony_ci   connect = xcb_dri2_connect_reply(scrn->conn, connect_cookie, NULL);
436bf215546Sopenharmony_ci   if (connect == NULL ||
437bf215546Sopenharmony_ci       connect->driver_name_length + connect->device_name_length == 0)
438bf215546Sopenharmony_ci      goto free_connect;
439bf215546Sopenharmony_ci
440bf215546Sopenharmony_ci   device_name_length = xcb_dri2_connect_device_name_length(connect);
441bf215546Sopenharmony_ci   device_name = CALLOC(1, device_name_length + 1);
442bf215546Sopenharmony_ci   if (!device_name)
443bf215546Sopenharmony_ci      goto free_connect;
444bf215546Sopenharmony_ci   memcpy(device_name, xcb_dri2_connect_device_name(connect), device_name_length);
445bf215546Sopenharmony_ci   fd = loader_open_device(device_name);
446bf215546Sopenharmony_ci   free(device_name);
447bf215546Sopenharmony_ci
448bf215546Sopenharmony_ci   if (fd < 0)
449bf215546Sopenharmony_ci      goto free_connect;
450bf215546Sopenharmony_ci
451bf215546Sopenharmony_ci   if (drmGetMagic(fd, &magic))
452bf215546Sopenharmony_ci      goto close_fd;
453bf215546Sopenharmony_ci
454bf215546Sopenharmony_ci   authenticate_cookie = xcb_dri2_authenticate_unchecked(
455bf215546Sopenharmony_ci      scrn->conn, ((xcb_screen_t *)(scrn->base.xcb_screen))->root, magic);
456bf215546Sopenharmony_ci   authenticate = xcb_dri2_authenticate_reply(scrn->conn, authenticate_cookie, NULL);
457bf215546Sopenharmony_ci
458bf215546Sopenharmony_ci   if (authenticate == NULL || !authenticate->authenticated)
459bf215546Sopenharmony_ci      goto free_authenticate;
460bf215546Sopenharmony_ci
461bf215546Sopenharmony_ci   if (pipe_loader_drm_probe_fd(&scrn->base.dev, fd))
462bf215546Sopenharmony_ci      scrn->base.pscreen = pipe_loader_create_screen(scrn->base.dev);
463bf215546Sopenharmony_ci
464bf215546Sopenharmony_ci   if (!scrn->base.pscreen)
465bf215546Sopenharmony_ci      goto release_pipe;
466bf215546Sopenharmony_ci
467bf215546Sopenharmony_ci   scrn->base.destroy = vl_dri2_screen_destroy;
468bf215546Sopenharmony_ci   scrn->base.texture_from_drawable = vl_dri2_screen_texture_from_drawable;
469bf215546Sopenharmony_ci   scrn->base.get_dirty_area = vl_dri2_screen_get_dirty_area;
470bf215546Sopenharmony_ci   scrn->base.get_timestamp = vl_dri2_screen_get_timestamp;
471bf215546Sopenharmony_ci   scrn->base.set_next_timestamp = vl_dri2_screen_set_next_timestamp;
472bf215546Sopenharmony_ci   scrn->base.get_private = vl_dri2_screen_get_private;
473bf215546Sopenharmony_ci   scrn->base.pscreen->flush_frontbuffer = vl_dri2_flush_frontbuffer;
474bf215546Sopenharmony_ci   vl_compositor_reset_dirty_area(&scrn->dirty_areas[0]);
475bf215546Sopenharmony_ci   vl_compositor_reset_dirty_area(&scrn->dirty_areas[1]);
476bf215546Sopenharmony_ci
477bf215546Sopenharmony_ci   /* The pipe loader duplicates the fd */
478bf215546Sopenharmony_ci   close(fd);
479bf215546Sopenharmony_ci   free(authenticate);
480bf215546Sopenharmony_ci   free(connect);
481bf215546Sopenharmony_ci   free(dri2_query);
482bf215546Sopenharmony_ci   free(error);
483bf215546Sopenharmony_ci
484bf215546Sopenharmony_ci   return &scrn->base;
485bf215546Sopenharmony_ci
486bf215546Sopenharmony_cirelease_pipe:
487bf215546Sopenharmony_ci   if (scrn->base.dev)
488bf215546Sopenharmony_ci      pipe_loader_release(&scrn->base.dev, 1);
489bf215546Sopenharmony_cifree_authenticate:
490bf215546Sopenharmony_ci   free(authenticate);
491bf215546Sopenharmony_ciclose_fd:
492bf215546Sopenharmony_ci   close(fd);
493bf215546Sopenharmony_cifree_connect:
494bf215546Sopenharmony_ci   free(connect);
495bf215546Sopenharmony_cifree_query:
496bf215546Sopenharmony_ci   free(dri2_query);
497bf215546Sopenharmony_ci   free(error);
498bf215546Sopenharmony_ci
499bf215546Sopenharmony_cifree_screen:
500bf215546Sopenharmony_ci   FREE(scrn);
501bf215546Sopenharmony_ci   return NULL;
502bf215546Sopenharmony_ci}
503bf215546Sopenharmony_ci
504bf215546Sopenharmony_cistatic void
505bf215546Sopenharmony_civl_dri2_screen_destroy(struct vl_screen *vscreen)
506bf215546Sopenharmony_ci{
507bf215546Sopenharmony_ci   struct vl_dri_screen *scrn = (struct vl_dri_screen *)vscreen;
508bf215546Sopenharmony_ci
509bf215546Sopenharmony_ci   assert(vscreen);
510bf215546Sopenharmony_ci
511bf215546Sopenharmony_ci   if (scrn->flushed) {
512bf215546Sopenharmony_ci      free(xcb_dri2_swap_buffers_reply(scrn->conn, scrn->swap_cookie, NULL));
513bf215546Sopenharmony_ci      free(xcb_dri2_wait_sbc_reply(scrn->conn, scrn->wait_cookie, NULL));
514bf215546Sopenharmony_ci      free(xcb_dri2_get_buffers_reply(scrn->conn, scrn->buffers_cookie, NULL));
515bf215546Sopenharmony_ci   }
516bf215546Sopenharmony_ci
517bf215546Sopenharmony_ci   vl_dri2_destroy_drawable(scrn);
518bf215546Sopenharmony_ci   scrn->base.pscreen->destroy(scrn->base.pscreen);
519bf215546Sopenharmony_ci   pipe_loader_release(&scrn->base.dev, 1);
520bf215546Sopenharmony_ci   /* There is no user provided fd */
521bf215546Sopenharmony_ci   FREE(scrn);
522bf215546Sopenharmony_ci}
523