Enable DRI2 based on Dodji Seketeli's DRI work
[xephyr-with-gl-acceleration:xephyr-with-gl-acceleration.git] / xserver / hw / kdrive / ephyr / ephyrdri2ext.c
1 /*
2  * Xephyr - A kdrive X server thats runs in a host X window.
3  *          Authored by Matthew Allum <mallum@openedhand.com>
4  * 
5  * Copyright © 2007 OpenedHand Ltd 
6  *
7  * Permission to use, copy, modify, distribute, and sell this software and its
8  * documentation for any purpose is hereby granted without fee, provided that
9  * the above copyright notice appear in all copies and that both that
10  * copyright notice and this permission notice appear in supporting
11  * documentation, and that the name of OpenedHand Ltd not be used in
12  * advertising or publicity pertaining to distribution of the software without
13  * specific, written prior permission. OpenedHand Ltd makes no
14  * representations about the suitability of this software for any purpose.  It
15  * is provided "as is" without express or implied warranty.
16  *
17  * OpenedHand Ltd DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19  * EVENT SHALL OpenedHand Ltd BE LIABLE FOR ANY SPECIAL, INDIRECT OR
20  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
22  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
23  * PERFORMANCE OF THIS SOFTWARE.
24  *
25  * This file is heavily copied from hw/xfree86/dri/xf86dri.c
26  *
27  * Authors:
28  *    Haitao Feng <haitao.feng@intel.com>
29  */
30
31 #ifdef HAVE_CONFIG_H
32 #include <kdrive-config.h>
33 #endif
34
35 #include <string.h>
36
37 #define NEED_REPLIES
38 #define NEED_EVENTS
39 #include <X11/X.h>
40 #include <X11/Xproto.h>
41 #include "misc.h"
42 #include "privates.h"
43 #include "dixstruct.h"
44 #include "extnsionst.h"
45 #include "colormapst.h"
46 #include "cursorstr.h"
47 #include "scrnintstr.h"
48 #include "windowstr.h"
49 #include "servermd.h"
50 #include "swaprep.h"
51 #include "ephyrdri.h"
52 #include "ephyrdriext.h"
53 #include "hostx.h"
54 #define _HAVE_XALLOC_DECLS
55 #include "ephyrlog.h"
56
57 #include "ephyrdri2ext.h"
58
59 #include <X11/extensions/dri2proto.h>
60 #include "ephyrdri2.h"
61 #include <X11/extensions/xfixeswire.h>
62 #include <X11/Xlib.h>
63
64 extern RESTYPE  RegionResType;
65 extern int      XFixesErrorBase;
66 #define VERIFY_REGION(pRegion, rid, client, mode) { \
67     pRegion = SecurityLookupIDByType (client, rid, RegionResType, mode); \
68     if (!pRegion) { \
69         client->errorValue = rid; \
70         return XFixesErrorBase + BadRegion; \
71     } \
72 }
73 typedef struct {
74     int foo;
75 } EphyrDRI2WindowPrivRec;
76 typedef EphyrDRI2WindowPrivRec* EphyrDRI2WindowPrivPtr;
77
78 typedef struct {
79     CreateWindowProcPtr CreateWindow ;
80     DestroyWindowProcPtr DestroyWindow ;
81     MoveWindowProcPtr MoveWindow ;
82     PositionWindowProcPtr PositionWindow ;
83     ClipNotifyProcPtr ClipNotify ;
84 } EphyrDRI2ScreenPrivRec;
85 typedef EphyrDRI2ScreenPrivRec* EphyrDRI2ScreenPrivPtr;
86
87 static DISPATCH_PROC(ProcDRI2QueryVersion);
88 static DISPATCH_PROC(ProcDRI2Connect);
89 static DISPATCH_PROC(ProcDRI2Authenticate);
90 static DISPATCH_PROC(ProcDRI2CreateDrawable);
91 static DISPATCH_PROC(ProcDRI2DestroyDrawable);
92 static DISPATCH_PROC(ProcDRI2GetBuffers);
93 static DISPATCH_PROC(ProcDRI2GetBuffersWithFormat);
94 static DISPATCH_PROC(ProcDRI2CopyRegion);
95 static DISPATCH_PROC(ProcDRI2Dispatch);
96 static DISPATCH_PROC(SProcDRI2Connect);
97 static DISPATCH_PROC(SProcDRI2Dispatch);
98
99 static Bool ephyrDRI2ScreenInit (ScreenPtr a_screen) ;
100 static Bool ephyrDRI2CreateWindow (WindowPtr a_win) ;
101 static Bool ephyrDRI2DestroyWindow (WindowPtr a_win) ;
102 static void ephyrDRI2MoveWindow (WindowPtr a_win,
103                                 int a_x, int a_y,
104                                 WindowPtr a_siblings,
105                                 VTKind a_kind);
106 static Bool ephyrDRI2PositionWindow (WindowPtr a_win,
107                                     int x, int y) ;
108 static void ephyrDRI2ClipNotify (WindowPtr a_win,
109                                 int a_x, int a_y) ;
110
111 static Bool EphyrMirrorHostVisuals (ScreenPtr a_screen) ;
112 static Bool destroyHostPeerWindow (const WindowPtr a_win) ;
113 static Bool findWindowPairFromLocal (WindowPtr a_local,
114                                      EphyrDRI2WindowPair **a_pair);
115
116 static int ephyrDRI2WindowKeyIndex;
117 static DevPrivateKey ephyrDRI2WindowKey = &ephyrDRI2WindowKeyIndex;
118 static int ephyrDRI2ScreenKeyIndex;
119 static DevPrivateKey ephyrDRI2ScreenKey = &ephyrDRI2ScreenKeyIndex;
120
121 #define GET_EPHYR_DRI2_WINDOW_PRIV(win) ((EphyrDRI2WindowPrivPtr) \
122     dixLookupPrivate(&(win)->devPrivates, ephyrDRI2WindowKey))
123 #define GET_EPHYR_DRI2_SCREEN_PRIV(screen) ((EphyrDRI2ScreenPrivPtr) \
124     dixLookupPrivate(&(screen)->devPrivates, ephyrDRI2ScreenKey))
125
126 static ExtensionEntry   *dri2Extension;
127 static RESTYPE           dri2DrawableRes;
128
129 static int DRI2DrawableGone(pointer p, XID id)
130 {
131     DrawablePtr pDrawable = p;
132     WindowPtr window      = (WindowPtr)pDrawable;
133     EphyrDRI2WindowPair *pair = NULL;
134
135     memset (&pair, 0, sizeof (pair)) ;
136     if (!findWindowPairFromLocal (window, &pair) || !pair) {
137         EPHYR_LOG_ERROR ("failed to find remote peer drawable\n") ;
138         return BadMatch ;
139     }
140     ephyrDRI2DestroyDrawable(pair->remote);
141
142     return Success;
143 }
144
145 Bool
146 ephyrDRI2ExtensionInit (ScreenPtr a_screen)
147 {
148     Bool is_ok=FALSE ;
149     EphyrDRI2ScreenPrivPtr screen_priv=NULL ;
150
151     EPHYR_LOG ("enter\n") ;
152     if (!hostx_has_dri2 ()) {
153         EPHYR_LOG ("host does not have DRI2 extension\n") ;
154         goto out ;
155     }
156     EPHYR_LOG ("host X does have DRI2 extension\n") ;
157
158     if (!hostx_has_xshape ()) {
159         EPHYR_LOG ("host does not have XShape extension\n") ;
160         goto out ;
161     }
162     EPHYR_LOG ("host X does have XShape extension\n") ;
163
164     dri2Extension = AddExtension(DRI2_NAME,
165                                  DRI2NumberEvents,
166                                  DRI2NumberErrors,
167                                  ProcDRI2Dispatch,
168                                  SProcDRI2Dispatch,
169                                  NULL,
170                                  StandardMinorOpcode);
171
172     if (!dri2Extension){
173         EPHYR_LOG_ERROR ("failed to register DRI extension\n") ;
174         goto out;
175     }
176
177     dri2DrawableRes = CreateNewResourceType(DRI2DrawableGone);
178
179     screen_priv = xcalloc (1, sizeof (EphyrDRI2ScreenPrivRec)) ;
180     if (!screen_priv) {
181         EPHYR_LOG_ERROR ("failed to allocate screen_priv\n") ;
182         goto out ;
183     }
184     dixSetPrivate(&a_screen->devPrivates, ephyrDRI2ScreenKey, screen_priv);
185
186     if (!ephyrDRI2ScreenInit (a_screen)) {
187         EPHYR_LOG_ERROR ("ephyrDRI2ScreenInit() failed\n") ;
188         goto out ;
189     }
190     EphyrMirrorHostVisuals (a_screen) ;
191     is_ok=TRUE ;
192 out:
193     EPHYR_LOG ("leave\n") ;
194     return is_ok ;
195 }
196
197 static Bool
198 ephyrDRI2ScreenInit (ScreenPtr a_screen)
199 {
200     Bool is_ok=FALSE ;
201     EphyrDRI2ScreenPrivPtr screen_priv=NULL ;
202
203     EPHYR_RETURN_VAL_IF_FAIL (a_screen, FALSE) ;
204
205     screen_priv=GET_EPHYR_DRI2_SCREEN_PRIV (a_screen) ;
206     EPHYR_RETURN_VAL_IF_FAIL (screen_priv, FALSE) ;
207
208     screen_priv->CreateWindow = a_screen->CreateWindow ;
209     screen_priv->DestroyWindow = a_screen->DestroyWindow ;
210     screen_priv->MoveWindow = a_screen->MoveWindow ;
211     screen_priv->PositionWindow = a_screen->PositionWindow ;
212     screen_priv->ClipNotify = a_screen->ClipNotify ;
213
214     a_screen->CreateWindow = ephyrDRI2CreateWindow ;
215     a_screen->DestroyWindow = ephyrDRI2DestroyWindow ;
216     a_screen->MoveWindow = ephyrDRI2MoveWindow ;
217     a_screen->PositionWindow = ephyrDRI2PositionWindow ;
218     a_screen->ClipNotify = ephyrDRI2ClipNotify ;
219
220     is_ok = TRUE ;
221
222     return is_ok ;
223 }
224
225 static Bool
226 ephyrDRI2CreateWindow (WindowPtr a_win)
227 {
228     Bool is_ok=FALSE ;
229     ScreenPtr screen=NULL ;
230     EphyrDRI2ScreenPrivPtr screen_priv =NULL;
231
232     EPHYR_RETURN_VAL_IF_FAIL (a_win, FALSE) ;
233     screen = a_win->drawable.pScreen ;
234     EPHYR_RETURN_VAL_IF_FAIL (screen, FALSE) ;
235     screen_priv = GET_EPHYR_DRI2_SCREEN_PRIV (screen) ;
236     EPHYR_RETURN_VAL_IF_FAIL (screen_priv
237                               && screen_priv->CreateWindow,
238                               FALSE) ;
239
240     EPHYR_LOG ("enter. win:%p\n", a_win) ;
241
242     screen->CreateWindow = screen_priv->CreateWindow ;
243     is_ok = (*screen->CreateWindow) (a_win) ;
244     screen->CreateWindow = ephyrDRI2CreateWindow ;
245
246     if (is_ok) {
247         dixSetPrivate(&a_win->devPrivates, ephyrDRI2WindowKey, NULL);
248     }
249     return is_ok ;
250 }
251
252 static Bool
253 ephyrDRI2DestroyWindow (WindowPtr a_win)
254 {
255     Bool is_ok=FALSE ;
256     ScreenPtr screen=NULL ;
257     EphyrDRI2ScreenPrivPtr screen_priv =NULL;
258
259     EPHYR_RETURN_VAL_IF_FAIL (a_win, FALSE) ;
260     screen = a_win->drawable.pScreen ;
261     EPHYR_RETURN_VAL_IF_FAIL (screen, FALSE) ;
262     screen_priv = GET_EPHYR_DRI2_SCREEN_PRIV (screen) ;
263     EPHYR_RETURN_VAL_IF_FAIL (screen_priv
264                               && screen_priv->DestroyWindow,
265                               FALSE) ;
266
267     screen->DestroyWindow = screen_priv->DestroyWindow ;
268     if (screen->DestroyWindow) {
269         is_ok = (*screen->DestroyWindow) (a_win) ;
270     }
271     screen->DestroyWindow = ephyrDRI2DestroyWindow ;
272
273     if (is_ok) {
274         EphyrDRI2WindowPrivPtr win_priv=GET_EPHYR_DRI2_WINDOW_PRIV (a_win) ;
275         if (win_priv) {
276             destroyHostPeerWindow (a_win) ;
277             xfree (win_priv) ;
278             dixSetPrivate(&a_win->devPrivates, ephyrDRI2WindowKey, NULL);
279             EPHYR_LOG ("destroyed the remote peer window\n") ;
280         }
281     }
282     return is_ok ;
283 }
284
285 static void
286 ephyrDRI2MoveWindow (WindowPtr a_win,
287                     int a_x, int a_y,
288                     WindowPtr a_siblings,
289                     VTKind a_kind)
290 {
291     Bool is_ok=FALSE ;
292     ScreenPtr screen=NULL ;
293     EphyrDRI2ScreenPrivPtr screen_priv =NULL;
294     EphyrDRI2WindowPrivPtr win_priv=NULL ;
295     EphyrDRI2WindowPair *pair=NULL ;
296     EphyrBox geo;
297     int x=0,y=0;/*coords relative to parent window*/
298
299     EPHYR_RETURN_IF_FAIL (a_win) ;
300
301     EPHYR_LOG ("enter\n") ;
302     screen = a_win->drawable.pScreen ;
303     EPHYR_RETURN_IF_FAIL (screen) ;
304     screen_priv = GET_EPHYR_DRI2_SCREEN_PRIV (screen) ;
305     EPHYR_RETURN_IF_FAIL (screen_priv
306                           && screen_priv->MoveWindow) ;
307
308     screen->MoveWindow = screen_priv->MoveWindow ;
309     if (screen->MoveWindow) {
310         (*screen->MoveWindow) (a_win, a_x, a_y, a_siblings, a_kind) ;
311     }
312     screen->MoveWindow = ephyrDRI2MoveWindow ;
313
314     EPHYR_LOG ("window: %p\n", a_win) ;
315     if (!a_win->parent) {
316         EPHYR_LOG ("cannot move root window\n") ;
317         is_ok = TRUE ;
318         goto out ;
319     }
320     win_priv = GET_EPHYR_DRI2_WINDOW_PRIV (a_win) ;
321     if (!win_priv) {
322         EPHYR_LOG ("not a DRI peered window\n") ;
323         is_ok = TRUE ;
324         goto out ;
325     }
326     if (!findWindowPairFromLocal (a_win, &pair) || !pair) {
327         EPHYR_LOG_ERROR ("failed to get window pair\n") ;
328         goto out ;
329     }
330     /*compute position relative to parent window*/
331     x = a_win->drawable.x - a_win->parent->drawable.x ;
332     y = a_win->drawable.y - a_win->parent->drawable.y ;
333     /*set the geometry to pass to hostx_set_window_geometry*/
334     memset (&geo, 0, sizeof (geo)) ;
335     geo.x = x ;
336     geo.y = y ;
337     geo.width = a_win->drawable.width ;
338     geo.height = a_win->drawable.height ;
339     hostx_set_window_geometry (pair->remote, &geo) ;
340     is_ok = TRUE ;
341
342 out:
343     EPHYR_LOG ("leave. is_ok:%d\n", is_ok) ;
344     /*do cleanup here*/
345 }
346
347 static Bool
348 ephyrDRI2PositionWindow (WindowPtr a_win,
349                         int a_x, int a_y)
350 {
351     Bool is_ok=FALSE ;
352     ScreenPtr screen=NULL ;
353     EphyrDRI2ScreenPrivPtr screen_priv =NULL;
354     EphyrDRI2WindowPrivPtr win_priv=NULL ;
355     EphyrDRI2WindowPair *pair=NULL ;
356     EphyrBox geo;
357
358     EPHYR_RETURN_VAL_IF_FAIL (a_win, FALSE) ;
359
360     EPHYR_LOG ("enter\n") ;
361     screen = a_win->drawable.pScreen ;
362     EPHYR_RETURN_VAL_IF_FAIL (screen, FALSE) ;
363     screen_priv = GET_EPHYR_DRI2_SCREEN_PRIV (screen) ;
364     EPHYR_RETURN_VAL_IF_FAIL (screen_priv
365                               && screen_priv->PositionWindow,
366                               FALSE) ;
367
368     screen->PositionWindow = screen_priv->PositionWindow ;
369     if (screen->PositionWindow) {
370         (*screen->PositionWindow) (a_win, a_x, a_y) ;
371     }
372     screen->PositionWindow = ephyrDRI2PositionWindow ;
373
374     EPHYR_LOG ("window: %p\n", a_win) ;
375     win_priv = GET_EPHYR_DRI2_WINDOW_PRIV (a_win) ;
376     if (!win_priv) {
377         EPHYR_LOG ("not a DRI peered window\n") ;
378         is_ok = TRUE ;
379         goto out ;
380     }
381     if (!findWindowPairFromLocal (a_win, &pair) || !pair) {
382         EPHYR_LOG_ERROR ("failed to get window pair\n") ;
383         goto out ;
384     }
385     /*set the geometry to pass to hostx_set_window_geometry*/
386     memset (&geo, 0, sizeof (geo)) ;
387     geo.x = a_x ;
388     geo.y = a_y ;
389     geo.width = a_win->drawable.width ;
390     geo.height = a_win->drawable.height ;
391     hostx_set_window_geometry (pair->remote, &geo) ;
392     is_ok = TRUE ;
393
394 out:
395     EPHYR_LOG ("leave. is_ok:%d\n", is_ok) ;
396     /*do cleanup here*/
397     return is_ok ;
398 }
399
400 static void
401 ephyrDRI2ClipNotify (WindowPtr a_win,
402                     int a_x, int a_y)
403 {
404     Bool is_ok=FALSE ;
405     ScreenPtr screen=NULL ;
406     EphyrDRI2ScreenPrivPtr screen_priv =NULL;
407     EphyrDRI2WindowPrivPtr win_priv=NULL ;
408     EphyrDRI2WindowPair *pair=NULL ;
409     EphyrRect *rects=NULL;
410     int i=0 ;
411
412     EPHYR_RETURN_IF_FAIL (a_win) ;
413
414     EPHYR_LOG ("enter\n") ;
415     screen = a_win->drawable.pScreen ;
416     EPHYR_RETURN_IF_FAIL (screen) ;
417     screen_priv = GET_EPHYR_DRI2_SCREEN_PRIV (screen) ;
418     EPHYR_RETURN_IF_FAIL (screen_priv && screen_priv->ClipNotify) ;
419
420     screen->ClipNotify = screen_priv->ClipNotify ;
421     if (screen->ClipNotify) {
422         (*screen->ClipNotify) (a_win, a_x, a_y) ;
423     }
424     screen->ClipNotify = ephyrDRI2ClipNotify ;
425
426     EPHYR_LOG ("window: %p\n", a_win) ;
427     win_priv = GET_EPHYR_DRI2_WINDOW_PRIV (a_win) ;
428     if (!win_priv) {
429         EPHYR_LOG ("not a DRI peered window\n") ;
430         is_ok = TRUE ;
431         goto out ;
432     }
433     if (!findWindowPairFromLocal (a_win, &pair) || !pair) {
434         EPHYR_LOG_ERROR ("failed to get window pair\n") ;
435         goto out ;
436     }
437     rects = xcalloc (REGION_NUM_RECTS (&a_win->clipList),
438                      sizeof (EphyrRect)) ;
439     for (i=0; i < REGION_NUM_RECTS (&a_win->clipList); i++) {
440         memmove (&rects[i],
441                  &REGION_RECTS (&a_win->clipList)[i],
442                  sizeof (EphyrRect)) ;
443         rects[i].x1 -= a_win->drawable.x;
444         rects[i].x2 -= a_win->drawable.x;
445         rects[i].y1 -= a_win->drawable.y;
446         rects[i].y2 -= a_win->drawable.y;
447     }
448     /*
449      * push the clipping region of this window
450      * to the peer window in the host
451      */
452     is_ok = hostx_set_window_bounding_rectangles
453                                 (pair->remote,
454                                  rects,
455                                  REGION_NUM_RECTS (&a_win->clipList)) ;
456     is_ok = TRUE ;
457
458 out:
459     if (rects) {
460         xfree (rects) ;
461         rects = NULL ;
462     }
463     EPHYR_LOG ("leave. is_ok:%d\n", is_ok) ;
464     /*do cleanup here*/
465 }
466
467 /**
468  * Duplicates a visual of a_screen
469  * In screen a_screen, for depth a_depth, find a visual which
470  * bitsPerRGBValue and colormap size equal
471  * a_bits_per_rgb_values and a_colormap_entries.
472  * The ID of that duplicated visual is set to a_new_id.
473  * That duplicated visual is then added to the list of visuals
474  * of the screen.
475  */
476 static Bool
477 EphyrDuplicateVisual (unsigned int a_screen,
478                       short a_depth,
479                       short a_class,
480                       short a_bits_per_rgb_values,
481                       short a_colormap_entries,
482                       unsigned int a_red_mask,
483                       unsigned int a_green_mask,
484                       unsigned int a_blue_mask,
485                       unsigned int a_new_id)
486 {
487     Bool is_ok = FALSE, found_visual=FALSE, found_depth=FALSE ;
488     ScreenPtr screen=NULL ;
489     VisualRec new_visual, *new_visuals=NULL ;
490     int i=0 ;
491
492     EPHYR_LOG ("enter\n") ; 
493     if (a_screen > screenInfo.numScreens) {
494         EPHYR_LOG_ERROR ("bad screen number\n") ;
495         goto out;
496     }
497     memset (&new_visual, 0, sizeof (VisualRec)) ;
498
499     /*get the screen pointed to by a_screen*/
500     screen = screenInfo.screens[a_screen] ;
501     EPHYR_RETURN_VAL_IF_FAIL (screen, FALSE) ;
502
503     /*
504      * In that screen, first look for an existing visual that has the
505      * same characteristics as those passed in parameter
506      * to this function and copy it.
507      */
508     for (i=0; i < screen->numVisuals; i++) {
509         if (screen->visuals[i].bitsPerRGBValue == a_bits_per_rgb_values &&
510             screen->visuals[i].ColormapEntries == a_colormap_entries ) {
511             /*copy the visual found*/
512             memcpy (&new_visual, &screen->visuals[i], sizeof (new_visual)) ;
513             new_visual.vid = a_new_id ;
514             new_visual.class = a_class ;
515             new_visual.redMask = a_red_mask ;
516             new_visual.greenMask = a_green_mask ;
517             new_visual.blueMask = a_blue_mask ;
518             found_visual = TRUE ;
519             EPHYR_LOG ("found a visual that matches visual id: %d\n",
520                        a_new_id) ;
521             break;
522         }
523     }
524     if (!found_visual) {
525         EPHYR_LOG ("did not find any visual matching %d\n", a_new_id) ;
526         goto out ;
527     }
528     /*
529      * be prepare to extend screen->visuals to add new_visual to it
530      */
531     new_visuals = xcalloc (screen->numVisuals+1, sizeof (VisualRec)) ;
532     memmove (new_visuals,
533              screen->visuals,
534              screen->numVisuals*sizeof (VisualRec)) ;
535     memmove (&new_visuals[screen->numVisuals],
536              &new_visual,
537              sizeof (VisualRec)) ;
538     /*
539      * Now, in that same screen, update the screen->allowedDepths member.
540      * In that array, each element represents the visuals applicable to
541      * a given depth. So we need to add an entry matching the new visual
542      * that we are going to add to screen->visuals
543      */
544     for (i=0; i<screen->numDepths; i++) {
545         VisualID *vids=NULL;
546         DepthPtr cur_depth=NULL ;
547         /*find the entry matching a_depth*/
548         if (screen->allowedDepths[i].depth != a_depth)
549             continue ;
550         cur_depth = &screen->allowedDepths[i];
551         /*
552          * extend the list of visual IDs in that entry,
553          * so to add a_new_id in there.
554          */
555         vids = xrealloc (cur_depth->vids,
556                          (cur_depth->numVids+1)*sizeof (VisualID));
557         if (!vids) {
558             EPHYR_LOG_ERROR ("failed to realloc numids\n") ;
559             goto out ;
560         }
561         vids[cur_depth->numVids] = a_new_id ;
562         /*
563          * Okay now commit our change.
564          * Do really update screen->allowedDepths[i]
565          */
566         cur_depth->numVids++ ;
567         cur_depth->vids = vids ;
568         found_depth=TRUE;
569     }
570     if (!found_depth) {
571         EPHYR_LOG_ERROR ("failed to update screen[%d]->allowedDepth\n",
572                          a_screen) ;
573         goto out ;
574     }
575     /*
576      * Commit our change to screen->visuals
577      */
578     xfree (screen->visuals) ;
579     screen->visuals = new_visuals ;
580     screen->numVisuals++ ;
581     new_visuals = NULL ;
582
583     is_ok = TRUE ;
584 out:
585     if (new_visuals) {
586         xfree (new_visuals) ;
587         new_visuals = NULL ;
588     }
589     EPHYR_LOG ("leave\n") ; 
590     return is_ok ;
591 }
592
593 /**
594  * Duplicates the visuals of the host X server.
595  * This is necessary to have visuals that have the same
596  * ID as those of the host X. It is important to have that for
597  * GLX.
598  */
599 static Bool
600 EphyrMirrorHostVisuals (ScreenPtr a_screen)
601 {
602     Bool is_ok=FALSE;
603     EphyrHostVisualInfo  *visuals=NULL;
604     int nb_visuals=0, i=0;
605
606     EPHYR_LOG ("enter\n") ;
607     if (!hostx_get_visuals_info (&visuals, &nb_visuals)) {
608         EPHYR_LOG_ERROR ("failed to get host visuals\n") ;
609         goto out ;
610     }
611     for (i=0; i<nb_visuals; i++) {
612         if (!EphyrDuplicateVisual (a_screen->myNum,
613                                    visuals[i].depth,
614                                    visuals[i].class,
615                                    visuals[i].bits_per_rgb,
616                                    visuals[i].colormap_size,
617                                    visuals[i].red_mask,
618                                    visuals[i].green_mask,
619                                    visuals[i].blue_mask,
620                                    visuals[i].visualid)) {
621             EPHYR_LOG_ERROR ("failed to duplicate host visual %d\n",
622                              (int)visuals[i].visualid) ;
623         }
624     }
625
626     is_ok = TRUE ;
627 out:
628     EPHYR_LOG ("leave\n") ;
629     return is_ok;
630 }
631
632 static Bool
633 getWindowVisual (const WindowPtr a_win,
634                  VisualPtr *a_visual)
635 {
636     int i=0, visual_id=0 ;
637     EPHYR_RETURN_VAL_IF_FAIL (a_win
638                               && a_win->drawable.pScreen
639                               && a_win->drawable.pScreen->visuals,
640                               FALSE) ;
641
642     visual_id = wVisual (a_win) ;
643     for (i=0; i < a_win->drawable.pScreen->numVisuals; i++) {
644         if (a_win->drawable.pScreen->visuals[i].vid == visual_id) {
645             *a_visual = &a_win->drawable.pScreen->visuals[i] ;
646             return TRUE ;
647         }
648     }
649     return FALSE ;
650 }
651
652 #define NUM_WINDOW_PAIRS 256
653 static EphyrDRI2WindowPair window_pairs[NUM_WINDOW_PAIRS] ;
654
655 static Bool
656 appendWindowPairToList (WindowPtr a_local,
657                         int a_remote,
658                         int a_pixmap,
659                         void *gc)
660 {
661     int i=0 ;
662
663     EPHYR_RETURN_VAL_IF_FAIL (a_local, FALSE) ;
664
665     EPHYR_LOG ("(local,remote):(%p, %d)\n", a_local, a_remote) ;
666
667     for (i=0; i < NUM_WINDOW_PAIRS; i++) {
668         if (window_pairs[i].local == NULL) {
669             window_pairs[i].local = a_local ;
670             window_pairs[i].remote = a_remote ;
671             return TRUE ;
672         }
673     }
674     return FALSE ;
675 }
676
677 static Bool
678 findWindowPairFromLocal (WindowPtr a_local,
679                          EphyrDRI2WindowPair **a_pair)
680 {
681     int i=0 ;
682
683     EPHYR_RETURN_VAL_IF_FAIL (a_pair && a_local, FALSE) ;
684
685     for (i=0; i < NUM_WINDOW_PAIRS; i++) {
686         if (window_pairs[i].local == a_local) {
687             *a_pair = &window_pairs[i] ;
688 #if 0
689             EPHYR_LOG ("found (%p, %d)\n",
690                        (*a_pair)->local,
691                        (*a_pair)->remote) ;
692 #endif
693             return TRUE ;
694         }
695     }
696     return FALSE ;
697 }
698
699 Bool
700 findDRI2WindowPairFromRemote (int a_remote,
701                           EphyrDRI2WindowPair **a_pair)
702 {
703     int i=0 ;
704
705     EPHYR_RETURN_VAL_IF_FAIL (a_pair, FALSE) ;
706
707     for (i=0; i < NUM_WINDOW_PAIRS; i++) {
708         if (window_pairs[i].remote == a_remote) {
709             *a_pair = &window_pairs[i] ;
710 #if 0
711             EPHYR_LOG ("found (%p, %d)\n",
712                        (*a_pair)->local,
713                        (*a_pair)->remote) ;
714 #endif
715             return TRUE ;
716         }
717     }
718     return FALSE ;
719 }
720
721 static Bool
722 createHostPeerWindow (const WindowPtr a_win,
723                       int *a_peer_win,
724                       int *a_pixmap)
725 {
726     Bool is_ok=FALSE ;
727     VisualPtr visual=NULL;
728     EphyrBox geo ;
729     GC gc;
730     int redirect = 1;
731
732     EPHYR_RETURN_VAL_IF_FAIL (a_win && a_peer_win, FALSE) ;
733     EPHYR_RETURN_VAL_IF_FAIL (a_win->drawable.pScreen,
734                               FALSE) ;
735
736     EPHYR_LOG ("enter. a_win '%p'\n", a_win) ;
737
738     if (!getWindowVisual (a_win, &visual)) {
739         EPHYR_LOG_ERROR ("failed to get window visual\n") ;
740         goto out ;
741     }
742     if (!visual) {
743         EPHYR_LOG_ERROR ("failed to create visual\n") ;
744         goto out ;
745     }
746
747     memset (&geo, 0, sizeof (geo)) ;
748     geo.x = a_win->drawable.x ;
749     geo.y = a_win->drawable.y ;
750     geo.width = a_win->drawable.width ;
751     geo.height = a_win->drawable.height ;
752
753     if (!hostx_create_window (a_win->drawable.pScreen->myNum,
754                               &geo, visual->vid, a_peer_win)) {
755         EPHYR_LOG_ERROR ("failed to create host peer window\n") ;
756         goto out ;
757     }
758     if (!appendWindowPairToList (a_win, *a_peer_win, *a_pixmap, gc)) {
759         EPHYR_LOG_ERROR ("failed to append window to pair list\n") ;
760         goto out ;
761     }
762     is_ok = TRUE ;
763 out:
764     EPHYR_LOG ("leave:remote win%d\n", *a_peer_win) ;
765     return is_ok ;
766 }
767
768 static Bool
769 destroyHostPeerWindow (const WindowPtr a_win)
770 {
771     Bool is_ok = FALSE ;
772     EphyrDRI2WindowPair *pair=NULL ;
773     EPHYR_RETURN_VAL_IF_FAIL (a_win, FALSE) ;
774
775     EPHYR_LOG ("enter\n") ;
776
777     if (!findWindowPairFromLocal (a_win, &pair) || !pair) {
778         EPHYR_LOG_ERROR ("failed to find peer to local window\n") ;
779         goto out;
780     }
781     hostx_destroy_window (pair->remote) ;
782     is_ok = TRUE ;
783
784 out:
785     EPHYR_LOG ("leave\n") ;
786     return is_ok;
787 }
788
789 static Bool
790 validDrawable(ClientPtr client, XID drawable,
791               DrawablePtr *pDrawable, int *status)
792 {
793     *status = dixLookupDrawable(pDrawable, drawable, client, 0, DixReadAccess);
794     if (*status != Success) {
795         client->errorValue = drawable;
796         return FALSE;
797     }
798
799     return TRUE;
800 }
801
802 static int
803 ProcDRI2QueryVersion(ClientPtr client)
804 {
805     REQUEST(xDRI2QueryVersionReq);
806     xDRI2QueryVersionReply rep;
807     int n;
808
809     if (client->swapped)
810         swaps(&stuff->length, n);
811
812     REQUEST_SIZE_MATCH(xDRI2QueryVersionReq);
813     rep.type = X_Reply;
814     rep.length = 0;
815     rep.sequenceNumber = client->sequence;
816     rep.majorVersion = 1;
817     rep.minorVersion = 1;
818
819     if (client->swapped) {
820         swaps(&rep.sequenceNumber, n);
821         swapl(&rep.length, n);
822         swapl(&rep.majorVersion, n);
823         swapl(&rep.minorVersion, n);
824     }
825
826     WriteToClient(client, sizeof(xDRI2QueryVersionReply), &rep);
827
828     return client->noClientException;
829 }
830
831 static int
832 ProcDRI2Connect(ClientPtr client)
833 {
834     REQUEST(xDRI2ConnectReq);
835     xDRI2ConnectReply rep;
836     DrawablePtr pDraw;
837     int fd, status;
838     char *driverName;
839     char *deviceName;
840
841     REQUEST_SIZE_MATCH(xDRI2ConnectReq);
842     if (!validDrawable(client, stuff->window, &pDraw, &status))
843         return status;
844
845     rep.type = X_Reply;
846     rep.length = 0;
847     rep.sequenceNumber = client->sequence;
848     rep.driverNameLength = 0;
849     rep.deviceNameLength = 0;
850
851     if (!ephyrDRI2Connect(pDraw->pScreen,
852                      stuff->driverType, &fd, &driverName, &deviceName))
853         goto fail;
854
855     rep.driverNameLength = strlen(driverName);
856     rep.deviceNameLength = strlen(deviceName);
857     rep.length = (rep.driverNameLength + 3) / 4 +
858             (rep.deviceNameLength + 3) / 4;
859
860  fail:
861     WriteToClient(client, sizeof(xDRI2ConnectReply), &rep);
862     WriteToClient(client, rep.driverNameLength, driverName);
863     WriteToClient(client, rep.deviceNameLength, deviceName);
864
865     return client->noClientException;
866 }
867
868 static int
869 ProcDRI2Authenticate(ClientPtr client)
870 {
871     REQUEST(xDRI2AuthenticateReq);
872     xDRI2AuthenticateReply rep;
873     DrawablePtr pDraw;
874     int status;
875
876     REQUEST_SIZE_MATCH(xDRI2AuthenticateReq);
877     if (!validDrawable(client, stuff->window, &pDraw, &status))
878         return status;
879
880     rep.type = X_Reply;
881     rep.sequenceNumber = client->sequence;
882     rep.length = 0;
883     rep.authenticated = ephyrDRI2Authenticate(pDraw->pScreen, stuff->magic);
884     WriteToClient(client, sizeof(xDRI2AuthenticateReply), &rep);
885
886     return client->noClientException;
887 }
888
889 static int
890 ProcDRI2CreateDrawable(ClientPtr client)
891 {
892     REQUEST(xDRI2CreateDrawableReq);
893     DrawablePtr pDrawable;
894     int status;
895
896     int remote = 0;
897     int remote_win = 0;
898     int remote_pixmap = 0;
899     WindowPtr window = NULL;
900     PixmapPtr pixmap = NULL;
901     EphyrDRI2WindowPair *pair = NULL ;
902     EphyrDRI2WindowPrivPtr win_priv = NULL;
903
904     REQUEST_SIZE_MATCH(xDRI2CreateDrawableReq);
905
906     if (!validDrawable(client, stuff->drawable, &pDrawable, &status))
907         return status;
908
909     if (pDrawable->type == DRAWABLE_WINDOW) {
910         window = (WindowPtr)pDrawable;
911         if (findWindowPairFromLocal (window, &pair) && pair) {
912             remote_win = pair->remote;
913             //EPHYR_LOG ("found window '%p' paire with remote '%d'\n", window, remote_win) ;
914         } else if (!createHostPeerWindow (window, &remote_win, &remote_pixmap)) {
915             EPHYR_LOG_ERROR ("failed to create host peer window\n") ;
916             return BadAlloc ;
917         }
918         remote = remote_win;
919     }else if (pDrawable->type == DRAWABLE_PIXMAP) {
920         pixmap = (PixmapPtr)pDrawable;
921 #if 0
922         if (findPixmapPairFromLocal(pixmap, &pair) && pair) {
923             EPHYR_LOG_ERROR ("failed to create host peer window\n") ;
924                 remote_pixmap = pair->remote;
925         }else if (!createHostPeerWindow (window, &remote_win, &remote_pixmap)) {
926                 return BadAlloc;
927         }
928 #endif
929     }else {
930         EPHYR_LOG_ERROR ("non-drawable windows are not yet supported\n") ;
931         return BadImplementation ;
932     }
933
934     status = ephyrDRI2CreateDrawable(remote);
935     if (status != Success)
936         return status;
937
938     win_priv = GET_EPHYR_DRI2_WINDOW_PRIV (window) ;
939     if (!win_priv) {
940         win_priv = xcalloc (1, sizeof (EphyrDRI2WindowPrivRec)) ;
941         if (!win_priv) {
942             EPHYR_LOG_ERROR ("failed to allocate window private\n") ;
943             return BadAlloc ;
944         }
945         dixSetPrivate(&window->devPrivates, ephyrDRI2WindowKey, win_priv);
946         EPHYR_LOG ("paired window '%p' with remote '%d'\n",
947                    window, remote_win) ;
948     }
949
950     if (!AddResource(stuff->drawable, dri2DrawableRes, pDrawable)) {
951         DRI2DrawableGone(pDrawable, stuff->drawable);
952         return BadAlloc;
953     }
954
955     return client->noClientException;
956 }
957
958 static int
959 ProcDRI2DestroyDrawable(ClientPtr client)
960 {
961     REQUEST(xDRI2DestroyDrawableReq);
962     DrawablePtr pDrawable;
963     int status;
964
965     REQUEST_SIZE_MATCH(xDRI2DestroyDrawableReq);
966     if (!validDrawable(client, stuff->drawable, &pDrawable, &status))
967         return status;
968
969     FreeResourceByType(stuff->drawable, dri2DrawableRes, FALSE);
970
971     return client->noClientException;
972 }
973
974
975 static void
976 send_buffers_reply(ClientPtr client, DrawablePtr pDrawable,
977                    DRI2Buffer *buffers, int count, int width, int height)
978 {
979     xDRI2GetBuffersReply rep;
980     int skip = 0;
981     int i;
982
983     if (pDrawable->type == DRAWABLE_WINDOW) {
984         for (i = 0; i < count; i++) {
985             /* Do not send the real front buffer of a window to the client.
986              */
987             if (buffers[i].attachment == DRI2BufferFrontLeft) {
988                 skip++;
989                 continue;
990             }
991         }
992     }
993
994     rep.type = X_Reply;
995     rep.length = (count - skip) * sizeof(xDRI2Buffer) / 4;
996     rep.sequenceNumber = client->sequence;
997     rep.width = width;
998     rep.height = height;
999     rep.count = count - skip;
1000     WriteToClient(client, sizeof(xDRI2GetBuffersReply), &rep);
1001
1002     for (i = 0; i < count; i++) {
1003                 xDRI2Buffer buffer;
1004
1005                 /* Do not send the real front buffer of a window to the client.
1006                  */
1007                 if ((pDrawable->type == DRAWABLE_WINDOW)
1008                         && (buffers[i].attachment == DRI2BufferFrontLeft)) {
1009                         continue;
1010                 }
1011
1012                 buffer.attachment = buffers[i].attachment;
1013                 buffer.name = buffers[i].name;
1014                 buffer.pitch = buffers[i].pitch;
1015                 buffer.cpp = buffers[i].cpp;
1016                 buffer.flags = buffers[i].flags;
1017                 WriteToClient(client, sizeof(xDRI2Buffer), &buffer);
1018     }
1019 }
1020
1021
1022 static int
1023 ProcDRI2GetBuffers(ClientPtr client)
1024 {
1025     REQUEST(xDRI2GetBuffersReq);
1026     DrawablePtr pDrawable;
1027     DRI2Buffer *buffers;
1028     int status, width, height, count;
1029     unsigned int *attachments;
1030
1031     WindowPtr window=NULL;
1032     EphyrDRI2WindowPair *pair=NULL;
1033
1034     REQUEST_FIXED_SIZE(xDRI2GetBuffersReq, stuff->count * 4);
1035     if (!validDrawable(client, stuff->drawable, &pDrawable, &status))
1036         return status;
1037
1038     window = (WindowPtr)pDrawable ;
1039     memset (&pair, 0, sizeof (pair)) ;
1040     if (!findWindowPairFromLocal (window, &pair) || !pair) {
1041         EPHYR_LOG_ERROR ("failed to find remote peer drawable\n") ;
1042         return BadMatch ;
1043     }
1044
1045     attachments = (unsigned int *) &stuff[1];
1046     buffers = ephyrDRI2GetBuffers(pair->remote, &width, &height,
1047                              attachments, stuff->count, &count);
1048
1049
1050     send_buffers_reply(client, pDrawable, buffers, count, width, height);
1051
1052     return client->noClientException;
1053 }
1054
1055 static int
1056 ProcDRI2GetBuffersWithFormat(ClientPtr client)
1057 {
1058     REQUEST(xDRI2GetBuffersReq);
1059     DrawablePtr pDrawable;
1060     DRI2Buffer *buffers;
1061     int status, width, height, count;
1062     unsigned int *attachments;
1063
1064     WindowPtr window=NULL;
1065     EphyrDRI2WindowPair *pair=NULL;
1066
1067     REQUEST_FIXED_SIZE(xDRI2GetBuffersReq, stuff->count * (2 * 4));
1068     if (!validDrawable(client, stuff->drawable, &pDrawable, &status))
1069         return status;
1070
1071     window = (WindowPtr)pDrawable ;
1072     memset (&pair, 0, sizeof (pair)) ;
1073     if (!findWindowPairFromLocal (window, &pair) || !pair) {
1074         EPHYR_LOG_ERROR ("failed to find remote peer drawable\n") ;
1075         return BadMatch ;
1076     }
1077
1078     attachments = (unsigned int *) &stuff[1];
1079     buffers = ephyrDRI2GetBuffersWithFormat(pair->remote, &width, &height,
1080                                        attachments, stuff->count, &count);
1081
1082     send_buffers_reply(client, pDrawable, buffers, count, width, height);
1083
1084     return client->noClientException;
1085 }
1086
1087 static int
1088 ProcDRI2CopyRegion(ClientPtr client)
1089 {
1090     REQUEST(xDRI2CopyRegionReq);
1091     xDRI2CopyRegionReply rep;
1092     DrawablePtr pDrawable;
1093     int status;
1094     RegionPtr pRegion;
1095     XImage *img;
1096     ScreenPtr screen;
1097
1098     WindowPtr window=NULL;
1099     EphyrDRI2WindowPair *pair=NULL;
1100     Display *dpy = hostx_get_display ();
1101     struct EphyrHostScreen *host_screen;
1102
1103     REQUEST_SIZE_MATCH(xDRI2CopyRegionReq);
1104
1105     if (!validDrawable(client, stuff->drawable, &pDrawable, &status))
1106         return status;
1107
1108     window = (WindowPtr)pDrawable ;
1109     memset (&pair, 0, sizeof (pair)) ;
1110     if (!findWindowPairFromLocal (window, &pair) || !pair) {
1111         EPHYR_LOG_ERROR ("failed to find remote peer drawable\n") ;
1112         return BadMatch ;
1113     }
1114
1115     VERIFY_REGION(pRegion, stuff->region, client, DixReadAccess);
1116     status = ephyrDRI2CopyRegion(stuff->drawable, pair, pRegion, stuff->dest, stuff->src);
1117     if (status != Success)
1118         return status;
1119
1120     //hostx_copy_region(stuff->drawable, pair, pRegion, pDrawable->x, pDrawable->y);
1121
1122     /* CopyRegion needs to be a round trip to make sure the X server
1123      * queues the swap buffer rendering commands before the DRI client
1124      * continues rendering.  The reply has a bitmask to signal the
1125      * presense of optional return values as well, but we're not using
1126      * that yet.
1127      */
1128
1129     rep.type = X_Reply;
1130     rep.length = 0;
1131     rep.sequenceNumber = client->sequence;
1132
1133     WriteToClient(client, sizeof(xDRI2CopyRegionReply), &rep);
1134
1135     return client->noClientException;
1136 }
1137
1138 static int
1139 ProcDRI2Dispatch (ClientPtr client)
1140 {
1141     REQUEST(xReq);
1142
1143     switch (stuff->data) {
1144     case X_DRI2QueryVersion:
1145         return ProcDRI2QueryVersion(client);
1146     }
1147
1148     if (!LocalClient(client))
1149         return BadRequest;
1150
1151     switch (stuff->data) {
1152     case X_DRI2Connect:
1153         return ProcDRI2Connect(client);
1154     case X_DRI2Authenticate:
1155         return ProcDRI2Authenticate(client);
1156     case X_DRI2CreateDrawable:
1157         return ProcDRI2CreateDrawable(client);
1158     case X_DRI2DestroyDrawable:
1159         return ProcDRI2DestroyDrawable(client);
1160     case X_DRI2GetBuffers:
1161         return ProcDRI2GetBuffers(client);
1162     case X_DRI2CopyRegion:
1163         return ProcDRI2CopyRegion(client);
1164     case X_DRI2GetBuffersWithFormat:
1165         return ProcDRI2GetBuffersWithFormat(client);
1166     default:
1167                 {
1168                         fprintf(stderr, "Bad Request from client\n");
1169                         return BadRequest;
1170                 }
1171     }
1172 }
1173
1174 static int
1175 SProcDRI2Connect(ClientPtr client)
1176 {
1177     REQUEST(xDRI2ConnectReq);
1178     xDRI2ConnectReply rep;
1179     int n;
1180
1181     /* If the client is swapped, it's not local.  Talk to the hand. */
1182
1183     swaps(&stuff->length, n);
1184     if (sizeof(*stuff) / 4 != client->req_len)
1185         return BadLength;
1186
1187     rep.sequenceNumber = client->sequence;
1188     swaps(&rep.sequenceNumber, n);
1189     rep.length = 0;
1190     rep.driverNameLength = 0;
1191     rep.deviceNameLength = 0;
1192
1193     return client->noClientException;
1194 }
1195
1196 static int
1197 SProcDRI2Dispatch (ClientPtr client)
1198 {
1199     REQUEST(xReq);
1200
1201     /*
1202      * Only local clients are allowed DRI access, but remote clients
1203      * still need these requests to find out cleanly.
1204      */
1205     switch (stuff->data)
1206     {
1207     case X_DRI2QueryVersion:
1208         return ProcDRI2QueryVersion(client);
1209     case X_DRI2Connect:
1210         return SProcDRI2Connect(client);
1211     default:
1212         return BadRequest;
1213     }
1214 }