Enable VSync (Fix bug 5296)
[dana/dcompmgr.git] / glxrender.c
1 #include "efence.h"
2
3 #include "render.h"
4 #include "screen.h"
5 #include "window.h"
6 #include "display.h"
7 #include "list.h"
8 #include <stdio.h>
9 #include <string.h>
10 #include <assert.h>
11 #include <stdlib.h>
12
13 #include <X11/Xmd.h>
14 #include <GL/glxproto.h>
15
16 #include <GL/gl.h>
17 #include <GL/glx.h>
18 #include <GL/glxtokens.h>
19 #include <GL/glext.h>
20 #include <GL/glxext.h>
21
22 #define MAX_DEPTH 32
23
24 static int plugin_id;
25
26 #define LEFT   0
27 #define TOP    1
28 #define RIGHT  2
29 #define BOTTOM 3
30
31 typedef void (*BindEXTFunc)(Display *, GLXDrawable, int, const int *);
32 typedef void (*ReleaseEXTFunc)(Display *, GLXDrawable, int);
33 typedef int (*SwapIntervalSGIFunc)(int);
34
35 typedef struct {
36     void (*screen_paint)(d_screen_t *sc);
37     void (*screen_root_pixmap_change)(d_screen_t *sc);
38     void (*window_show)(d_window_t *w);
39     void (*window_zombie_dead)(d_window_t *w);
40     void (*window_resize)(d_window_t *w);
41     void (*window_reshape)(d_window_t *w);
42
43     float shadowalpha;
44     int xshadowoff;
45     int yshadowoff;
46
47     GLXFBConfig fbconfig[MAX_DEPTH + 1];
48
49     GLXContext context;
50     GLuint root_texname;
51     GLXPixmap root_glpixmap;
52
53     BindEXTFunc bind_func;
54     ReleaseEXTFunc release_func;
55 } data_t;
56
57 typedef struct {
58     GLuint texname;
59     GLXPixmap glpixmap;
60
61     GLfloat *texcoords;
62     GLint *vertices;
63     int nrects;
64
65     xcb_xfixes_fetch_region_cookie_t ck_region;
66     int waiting_region;
67     int x_region;
68     int y_region;
69     int w_region;
70     int h_region;
71     int bw_region;
72 } window_data_t;
73
74 static gboolean glxrender_find_fb_config(d_screen_t *sc, data_t *d);
75
76 static void glxrender_paint(d_screen_t *sc);
77 static void glxrender_root_pixmap_change(d_screen_t *sc);
78 static void paint_root(d_screen_t *sc, data_t *d);
79 static void paint_window(d_window_t *window, data_t *d, window_data_t *wd,
80                          int x, int y, GLfloat z);
81 static void paint_shadow(data_t *d, window_data_t *wd, int x, int y,
82                          GLfloat z);
83 static void glxrender_update_window_pixmap(d_window_t *w, data_t *d,
84                                            window_data_t *wd);
85 static void glxrender_fetch_window_region(d_window_t *w, window_data_t *wd);
86 static void glxrender_update_window_region(d_window_t *w, window_data_t *wd);
87 static void glxrender_free_window_pixmap(d_window_t *w, data_t *d,
88                                          window_data_t *wd);
89 static void glxrender_free_window_region(window_data_t *wd);
90 static void glxrender_free_root_pixmap(d_screen_t *sc, data_t *d);
91 static void glxrender_update_root_pixmap(d_screen_t *sc, data_t *d);
92
93 static void glxrender_window_show(d_window_t *window);
94 static void glxrender_window_zombie_dead(d_window_t *window);
95 static void glxrender_window_resize(d_window_t *window);
96 static void glxrender_window_reshape(d_window_t *window);
97
98 void
99 glxrender_init(d_screen_t *sc, int id)
100 {
101     static int context_visual_config[] = {
102         GLX_DEPTH_SIZE, 1,
103         GLX_DOUBLEBUFFER,
104         GLX_RGBA,
105         XCB_NONE
106     };
107     XVisualInfo *vi;
108     data_t *d;
109
110     plugin_id = id;
111
112     d = malloc(sizeof(data_t));
113     d->screen_paint = sc->screen_paint;
114     d->screen_root_pixmap_change = sc->screen_root_pixmap_change;
115     d->window_show = sc->window_show;
116     d->window_zombie_dead = sc->window_zombie_dead;
117     d->window_resize = sc->window_resize;
118     d->window_reshape = sc->window_reshape;
119     screen_add_plugin_data(sc, plugin_id, d);
120
121     sc->screen_paint = glxrender_paint;
122     sc->screen_root_pixmap_change = glxrender_root_pixmap_change;
123     sc->window_show = glxrender_window_show;
124     sc->window_zombie_dead = glxrender_window_zombie_dead;
125     sc->window_resize = glxrender_window_resize;
126     sc->window_reshape = glxrender_window_reshape;
127
128     d->shadowalpha = 0.2f; /* 20% */
129     d->xshadowoff = 2;
130     d->yshadowoff = 2;
131
132     vi = glXChooseVisual(sc->dpy->xlib_dpy, sc->num, context_visual_config);
133     if (!vi) {
134         printf("unable to find a valid double buffered GL context to use\n");
135         exit(1);
136     }
137
138     if (!(glxrender_find_fb_config(sc, d))) {
139         printf("unable to find FB configs\n");
140         exit(1);
141     }
142
143     d->context = glXCreateContext(sc->dpy->xlib_dpy, vi, NULL, GL_TRUE);
144     glXMakeCurrent(sc->dpy->xlib_dpy, sc->overlay, d->context);
145
146     glViewport(0, 0, sc->super->width_in_pixels, sc->super->height_in_pixels);
147     glMatrixMode(GL_PROJECTION);
148     glLoadIdentity();
149     glOrtho(0, sc->super->width_in_pixels, sc->super->height_in_pixels, 0,
150             -100.0, 100.0);
151     glMatrixMode(GL_MODELVIEW);
152     glLoadIdentity();
153     glEnable(GL_TEXTURE_2D);
154     glEnable(GL_DEPTH_TEST);
155     //glEnable(GL_SCISSOR_TEST); ?? what is this, glxcompmgr enables it
156     //glEnable(GL_STENCIL_TEST); ?? what is this, glxcompmgr enables it
157
158     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
159     glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
160     glDisable(GL_BLEND);
161
162     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
163     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
164
165     glXSwapBuffers(sc->dpy->xlib_dpy, sc->overlay);
166
167     d->bind_func = (BindEXTFunc)
168         glXGetProcAddress((const guchar*)"glXBindTexImageEXT");
169     d->release_func = (ReleaseEXTFunc)
170         glXGetProcAddress((const guchar*)"glXReleaseTexImageEXT");
171
172     SwapIntervalSGIFunc swap_interval_func = (SwapIntervalSGIFunc)
173         glXGetProcAddress((const guchar*)"glXSwapIntervalSGI");
174     if(swap_interval_func)
175         swap_interval_func(1);
176
177     glGenTextures(1, &d->root_texname);
178     d->root_glpixmap = XCB_NONE;
179 }
180
181 static gboolean
182 glxrender_find_fb_config(d_screen_t *sc, data_t *d)
183 {
184     static const int drawable_tfp_attrs[] = {
185         GLX_CONFIG_CAVEAT, GLX_NONE,
186         GLX_DOUBLEBUFFER, FALSE,
187         GLX_DEPTH_SIZE, 0,
188         GLX_RED_SIZE, 1,
189         GLX_GREEN_SIZE, 1,
190         GLX_BLUE_SIZE, 1,
191         GLX_ALPHA_SIZE, 1,
192         GLX_RENDER_TYPE, GLX_RGBA_BIT,
193         GLX_BIND_TO_TEXTURE_RGBA_EXT, TRUE, /* For TextureFromPixmap */
194         XCB_NONE
195     };
196     int db, stencil, depth, numfb, i;
197     GLXFBConfig *fbcons;
198     XVisualInfo tvis, *visinfo;
199
200     fbcons = glXChooseFBConfig(sc->dpy->xlib_dpy, sc->num,
201                                drawable_tfp_attrs, &numfb);
202     if (!fbcons) return FALSE;
203
204     for (i = 0; i <= MAX_DEPTH; i++) {
205         int j, count, value;
206         VisualID vid;
207
208         vid = 0;
209         d->fbconfig[i] = 0;
210         db = 32767;
211         stencil = 32767;
212         depth = 32767;
213
214         //printf("looking for depth %d\n", i);
215
216         tvis.depth = i;
217         visinfo = XGetVisualInfo(sc->dpy->xlib_dpy, VisualDepthMask,
218                                  &tvis, &count);
219         /* pick the nicest visual for the depth */
220         for (j = 0; j < count; j++) {
221             glXGetConfig(sc->dpy->xlib_dpy, &visinfo[j], GLX_USE_GL, &value);
222             if (!value)
223                 continue;
224
225             glXGetConfig(sc->dpy->xlib_dpy, &visinfo[j], GLX_DOUBLEBUFFER,
226                          &value);
227             if (value > db)
228                 continue;
229             db = value;
230
231             glXGetConfig(sc->dpy->xlib_dpy, &visinfo[j], GLX_STENCIL_SIZE,
232                          &value);
233             if (value > stencil)
234                 continue;
235             stencil = value;
236
237             glXGetConfig(sc->dpy->xlib_dpy, &visinfo[j], GLX_DEPTH_SIZE,
238                          &value);
239             if (value > depth)
240                 continue;
241             depth = value;
242
243             /* use this visual */
244             vid = visinfo[j].visualid;
245         }
246
247         if (!vid) continue;
248
249         /* look for an fbconfig for this visual */
250         for (j = 0; j < numfb; ++j) {
251             glXGetFBConfigAttrib(sc->dpy->xlib_dpy, fbcons[j],
252                                  GLX_VISUAL_ID, &value);
253             if ((unsigned)value == vid) {
254                 d->fbconfig[i] = fbcons[j];
255
256                 printf("found visual 0x%x fbconfig 0x%x for depth %d\n",
257                        (uint32_t)vid, (uint32_t)fbcons[j], i);
258                 break;
259             }
260         }
261     }
262
263     XFree(fbcons);
264     return TRUE;
265 }
266
267 void
268 glxrender_free(d_screen_t *sc)
269 {
270     data_t *d = screen_find_plugin_data(sc, plugin_id);
271     if (d) {
272         glxrender_free_root_pixmap(sc, d);
273         glXDestroyContext(sc->dpy->xlib_dpy, d->context);
274         free(d);
275     }
276     screen_remove_plugin_data(sc, plugin_id);
277 }
278
279 int
280 glxrender_next_timeout(struct d_screen *sc, struct timeval *tv)
281 {
282     (void)sc;
283     (void)tv;
284     return FALSE;
285 }
286
287 void
288 glxrender_timeout(struct d_screen *sc, const struct timeval *now)
289 {
290     (void)sc; (void)now;
291 }
292
293 void
294 glxrender_window_free_data(d_window_t *w, data_t *d, window_data_t *wd)
295 {
296     glxrender_free_window_pixmap(w, d, wd);
297     glxrender_free_window_region(wd);
298     glDeleteTextures(1, &wd->texname);
299     free(wd);
300 }
301
302 static void
303 glxrender_window_show(d_window_t *w)
304 {
305     data_t *d;
306     window_data_t *wd;
307
308     d = screen_find_plugin_data(w->sc, plugin_id);
309
310     /* pass it on */
311     d->window_show(w);
312
313     wd = window_find_plugin_data(w, plugin_id);
314     if (wd) {
315         glxrender_window_free_data(w, d, wd);
316         window_remove_plugin_data(w, plugin_id);
317     }
318
319     wd = malloc(sizeof(window_data_t));
320     glGenTextures(1, &wd->texname);
321     wd->glpixmap = XCB_NONE;
322     wd->texcoords = NULL;
323     wd->vertices = NULL;
324     wd->nrects = 0;
325     wd->waiting_region = FALSE;
326
327     window_add_plugin_data(w, plugin_id, wd);
328
329     glxrender_fetch_window_region(w, wd);
330 }
331
332 static void
333 glxrender_window_zombie_dead(d_window_t *w)
334 {
335     data_t *d;
336     window_data_t *wd;
337
338     d = screen_find_plugin_data(w->sc, plugin_id);
339     wd = window_find_plugin_data(w, plugin_id);
340     if (wd) {
341         glxrender_window_free_data(w, d, wd);
342         window_remove_plugin_data(w, plugin_id);
343     }
344
345     /* pass it on */
346     d->window_zombie_dead(w);
347 }
348
349 static void
350 glxrender_free_window_pixmap(d_window_t *w, data_t *d, window_data_t *wd)
351 {
352     /* this might cause an error, oh well */
353     if (wd->glpixmap) {
354         glBindTexture(GL_TEXTURE_2D, wd->texname);
355         d->release_func(w->sc->dpy->xlib_dpy,
356                         wd->glpixmap, GLX_FRONT_LEFT_EXT);
357         glBindTexture(GL_TEXTURE_2D, 0);
358
359         glXDestroyPixmap(w->sc->dpy->xlib_dpy, wd->glpixmap);
360         wd->glpixmap = XCB_NONE;
361
362     }
363 }
364
365 static void
366 glxrender_free_window_region(window_data_t *wd)
367 {
368     if (wd->nrects) {
369         free(wd->texcoords);
370         free(wd->vertices);
371         wd->texcoords = NULL;
372         wd->vertices = NULL;
373         wd->nrects = 0;
374     }
375 }
376
377 static void
378 glxrender_free_root_pixmap(d_screen_t *sc, data_t *d)
379 {
380     /* this might cause an error, oh well */
381     if (d->root_glpixmap) {
382         glBindTexture(GL_TEXTURE_2D, d->root_texname);
383         d->release_func(sc->dpy->xlib_dpy,
384                         d->root_glpixmap, GLX_FRONT_LEFT_EXT);
385         glBindTexture(GL_TEXTURE_2D, 0);
386
387         glXDestroyPixmap(sc->dpy->xlib_dpy, d->root_glpixmap);
388         d->root_glpixmap = XCB_NONE;
389     }
390 }
391
392 static void
393 glxrender_update_window_pixmap(d_window_t *w, data_t *d, window_data_t *wd)
394 {
395     xcb_pixmap_t px;
396     uint8_t depth;
397
398     static int attrs[] = {
399         GLX_TEXTURE_FORMAT_EXT,
400         XCB_NONE,
401         XCB_NONE
402     };
403
404     px = window_get_pixmap(w);
405     depth = window_get_depth(w);
406
407     if (!px) return;
408
409     if (!d->fbconfig[depth]) {
410         printf("no GL visual for depth %d\n", depth);
411         return;
412     }
413
414     if (window_is_argb(w))
415         attrs[1] = GLX_TEXTURE_FORMAT_RGBA_EXT;
416     else
417         attrs[1] = GLX_TEXTURE_FORMAT_RGB_EXT;
418
419     wd->glpixmap = glXCreatePixmap(w->sc->dpy->xlib_dpy,
420                                    d->fbconfig[depth],
421                                    px, attrs);
422 #if 0
423     wd->glpixmap = xcb_generate_id(w->sc->dpy->conn);
424     int v;
425     glXGetFBConfigAttrib(w->sc->dpy->xlib_dpy, d->fbconfig[depth],
426                          GLX_FBCONFIG_ID, &v);
427     xcb_void_cookie_t ck =
428         xcb_glx_create_pixmap_checked(w->sc->dpy->conn, w->sc->num,
429                                       v,
430                                       px, wd->glpixmap,
431                                       2,
432                                       attrs);
433     xcb_generic_error_t *err = xcb_request_check(w->sc->dpy->conn, ck);
434     if (err) {
435         display_error(w->sc->dpy, err);
436         free(err);
437         wd->glpixmap = XCB_NONE;
438         return;
439     }
440 #endif
441
442     glBindTexture(GL_TEXTURE_2D, wd->texname);
443     d->bind_func(w->sc->dpy->xlib_dpy,
444                  wd->glpixmap, GLX_FRONT_LEFT_EXT, NULL);
445 #if 0
446     {
447         /*
448           BindTexImageEXT
449           1           CARD8                   opcode (X assigned)
450           1           16                      GLX opcode (glXVendorPrivate)
451           2           6+n                     request length
452           4           1330                    vendor specific opcode
453           4           CARD32                  context tag
454           4           GLX_DRAWABLE            drawable
455           4           INT32                   buffer
456           4           CARD32                  num_attributes
457           4*n         LISTofATTRIBUTE_PAIR    attribute, value pairs.
458         */
459         unsigned int len = 12;
460         uint32_t data[] = {
461             wd->glpixmap,
462             GLX_FRONT_LEFT_EXT,
463             0,
464         };
465         xcb_glx_vendor_private(w->sc->dpy->conn,
466                                X_GLXvop_BindTexImageEXT,
467                                1,
468                                len, (uint8_t*)data);
469     }
470 #endif
471
472     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
473     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
474
475     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
476     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
477
478     glBindTexture(GL_TEXTURE_2D, 0);
479 }
480
481 static void
482 glxrender_fetch_window_region(d_window_t *w, window_data_t *wd)
483 {
484     window_get_area(w, &wd->x_region, &wd->y_region,
485                     &wd->w_region, &wd->h_region, &wd->bw_region);
486
487     wd->ck_region =
488         xcb_xfixes_fetch_region_unchecked(w->sc->dpy->conn,
489                                           window_get_region(w));
490     wd->waiting_region = TRUE;
491     xcb_flush(w->sc->dpy->conn);
492 }
493
494 static void
495 glxrender_update_window_region(d_window_t *w, window_data_t *wd)
496 {
497     xcb_xfixes_fetch_region_reply_t *rep;
498     xcb_rectangle_t area, *rects;
499     int nrects, i, j;
500
501     if (!wd->waiting_region) return;
502
503     area.x = wd->x_region;
504     area.y = wd->y_region;
505     area.width = wd->w_region + wd->bw_region * 2;
506     area.height = wd->h_region + wd->bw_region * 2;
507
508     rep = xcb_xfixes_fetch_region_reply(w->sc->dpy->conn, wd->ck_region, NULL);
509     if (!rep) {
510         rects = &area;
511         nrects = 1;
512     }
513     else {
514         rects = xcb_xfixes_fetch_region_rectangles(rep);
515         nrects = xcb_xfixes_fetch_region_rectangles_length(rep);
516     }
517
518     wd->texcoords = (GLfloat*)realloc(wd->texcoords,
519                                       sizeof(GLfloat) * (nrects * 4));
520     wd->vertices = (GLint*)realloc(wd->vertices, sizeof(GLint) * (nrects * 4));
521     wd->nrects = nrects;
522
523     for (i = j = 0; i < nrects * 4; ++j, i += 4) {
524         wd->texcoords[i+LEFT] =
525             (GLfloat)(rects[j].x - area.x) / (GLfloat)area.width;
526         wd->texcoords[i+TOP] =
527             (GLfloat)(rects[j].y - area.y) / (GLfloat)area.height;
528         wd->texcoords[i+RIGHT] =
529             (GLfloat)(rects[j].x - area.x + rects[j].width) /
530             (GLfloat)area.width;
531         wd->texcoords[i+BOTTOM] =
532             (GLfloat)(rects[j].y - area.y + rects[j].height) /
533             (GLfloat)area.height;
534
535         wd->vertices[i+LEFT] = rects[j].x - area.x;
536         wd->vertices[i+TOP] = rects[j].y - area.y;
537         wd->vertices[i+RIGHT] = rects[j].x - area.x + rects[j].width;
538         wd->vertices[i+BOTTOM] = rects[j].y - area.y + rects[j].height;
539     }
540
541     if (rep)
542         free(rep);
543
544     wd->waiting_region = FALSE;
545 }
546
547 static void
548 glxrender_update_root_pixmap(d_screen_t *sc, data_t *d)
549 {
550     xcb_pixmap_t px;
551     static int attrs[] = {
552         GLX_TEXTURE_FORMAT_EXT,
553         GLX_TEXTURE_FORMAT_RGB_EXT,
554         XCB_NONE
555     };
556
557     px = screen_get_root_pixmap(sc);
558     if (!px) return;
559
560     if (!d->fbconfig[sc->super->root_depth]) {
561         printf("no GL visual for depth %d\n", sc->super->root_depth);
562         return;
563     }
564
565     d->root_glpixmap = glXCreatePixmap(sc->dpy->xlib_dpy,
566                                        d->fbconfig[sc->super->root_depth],
567                                        px, attrs);
568
569
570     glBindTexture(GL_TEXTURE_2D, d->root_texname);
571     d->bind_func(sc->dpy->xlib_dpy,
572                  d->root_glpixmap, GLX_FRONT_LEFT_EXT, NULL);
573
574     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
575     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
576
577     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
578     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
579
580     glBindTexture(GL_TEXTURE_2D, 0);
581 }
582
583 static void
584 glxrender_window_resize(d_window_t *w)
585 {
586     data_t *d;
587     window_data_t *wd;
588
589     d = screen_find_plugin_data(w->sc, plugin_id);
590     wd = window_find_plugin_data(w, plugin_id);
591
592     /* pass it on */
593     d->window_resize(w);
594
595     assert(wd != NULL);
596     glxrender_free_window_pixmap(w, d, wd);
597     glxrender_fetch_window_region(w, wd);
598 }
599
600 static void
601 glxrender_window_reshape(d_window_t *w)
602 {
603     data_t *d;
604     window_data_t *wd;
605
606     d = screen_find_plugin_data(w->sc, plugin_id);
607     wd = window_find_plugin_data(w, plugin_id);
608
609     /* pass it on */
610     d->window_reshape(w);
611
612     assert(wd != NULL);
613     //glxrender_free_window_pixmap(w, d, wd);
614     glxrender_fetch_window_region(w, wd);
615 }
616
617 static void
618 glxrender_root_pixmap_change(d_screen_t *sc)
619 {
620     data_t *d;
621
622     d = screen_find_plugin_data(sc, plugin_id);
623     glxrender_free_root_pixmap(sc, d);
624
625     /* pass it on */
626     d->screen_root_pixmap_change(sc);
627 }
628
629 static void
630 glxrender_paint(d_screen_t *sc)
631 {
632     data_t *d = screen_find_plugin_data(sc, plugin_id);
633     d_list_it_t *it;
634     GLfloat z;
635
636     //printf("painting\n");
637
638     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
639
640     /* add 0.1f to keep everything above the root */
641     z = list_length(sc->stacking) * 0.1f + 0.1f;
642     for (it = list_top(sc->stacking); it; it = it->next) {
643         d_window_t *w = it->data;
644
645         if (!window_is_input_only(w) &&
646             (window_is_mapped(w) || window_is_zombie(w)))
647         {
648             int x, y, width, height, bwidth;
649             gboolean opaque;
650             window_data_t *wd;
651
652             window_get_area(w, &x, &y, &width, &height, &bwidth);
653
654             if (!(x < sc->super->width_in_pixels &&
655                   y < sc->super->height_in_pixels &&
656                   (x + width > 0 || x + width + d->xshadowoff > 0) &&
657                   (y + height > 0 || y + height + d->yshadowoff > 0)))
658             {
659                 continue;
660             }
661
662             opaque = !window_is_argb(w) && window_get_opacity(w) == 0xffff;
663
664             if (opaque) {
665                 wd = window_find_plugin_data(w, plugin_id);
666
667                 //glPushMatrix();
668
669                 paint_window(w, d, wd, x, y, z - 0.05f);
670
671                 //glPopMatrix();
672             }
673
674             z -= 0.1f;
675         }
676     }
677
678     paint_root(sc, d);
679
680     glEnable(GL_BLEND);
681     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
682
683     for (it = list_bottom(sc->stacking); it; it = it->prev) {
684         d_window_t *w = it->data;
685
686         if (!window_is_input_only(w) &&
687             (window_is_mapped(w) || window_is_zombie(w)))
688         {
689             int x, y, width, height, bwidth;
690             gboolean opaque;
691             window_data_t *wd;
692             uint16_t opac;
693             GLfloat alpha;
694
695             window_get_area(w, &x, &y, &width, &height, &bwidth);
696
697             if (!(x < sc->super->width_in_pixels &&
698                   y < sc->super->height_in_pixels &&
699                   (x + width > 0 || x + width + d->xshadowoff > 0) &&
700                   (y + height > 0 || y + height + d->yshadowoff > 0)))
701             {
702                 continue;
703             }
704
705             opac = window_get_opacity(w);
706             opaque = !window_is_argb(w) && opac == 0xffff;
707
708             wd = window_find_plugin_data(w, plugin_id);
709
710             /* black shadow */
711             alpha = d->shadowalpha;
712             alpha *= opac;
713             alpha /= 0xffff;
714             if (alpha >= 0.01) {
715                 glColor4f(0.0f, 0.0f, 0.0f, alpha);
716                 paint_shadow(d, wd, x, y, z);
717             }
718
719             if (!opaque) {
720                 glColor4us(opac, opac, opac, opac);
721                 paint_window(w, d, wd, x, y, z + 0.05f);
722             }
723
724             z += 0.1f;
725         }
726     }
727
728     glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
729     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
730     glDisable(GL_BLEND);
731
732     glXSwapBuffers(sc->dpy->xlib_dpy, sc->overlay);
733
734     glFinish();
735
736     /* call the function we replaced in the chain */
737     d->screen_paint(sc);
738 }
739
740 static void
741 paint_root(d_screen_t *sc, data_t *d)
742 {
743     if (!d->root_glpixmap)
744         glxrender_update_root_pixmap(sc, d);
745
746     glBindTexture(GL_TEXTURE_2D, d->root_texname);
747     glBegin(GL_QUADS);
748     glTexCoord2f(0, 0);
749     glVertex3i(0, 0, 0);
750     glTexCoord2f(1, 0);
751     glVertex3i(sc->super->width_in_pixels, 0, 0);
752     glTexCoord2f(1, 1);
753     glVertex3i(sc->super->width_in_pixels, sc->super->height_in_pixels, 0);
754     glTexCoord2f(0, 1);
755     glVertex3i(0, sc->super->height_in_pixels, 0);
756     glEnd();
757
758     glBindTexture(GL_TEXTURE_2D, 0);
759 }
760
761 static void
762 paint_window(d_window_t *w, data_t *d, window_data_t *wd, int x, int y,
763              GLfloat z)
764 {
765     int i;
766
767     if (!wd->glpixmap)
768         glxrender_update_window_pixmap(w, d, wd);
769     if (wd->waiting_region)
770         glxrender_update_window_region(w, wd);
771
772     if (wd->nrects < 1) return;
773
774     glBindTexture(GL_TEXTURE_2D, wd->texname);
775
776     glBegin(GL_QUADS);
777     for (i = 0; i < wd->nrects * 4; i += 4) {
778         glTexCoord2f(wd->texcoords[i+LEFT], wd->texcoords[i+TOP]);
779         glVertex3f(x+wd->vertices[i+LEFT], y+wd->vertices[i+TOP], z);
780         glTexCoord2f(wd->texcoords[i+RIGHT], wd->texcoords[i+TOP]);
781         glVertex3f(x+wd->vertices[i+RIGHT], y+wd->vertices[i+TOP], z);
782         glTexCoord2f(wd->texcoords[i+RIGHT], wd->texcoords[i+BOTTOM]);
783         glVertex3f(x+wd->vertices[i+RIGHT], y+wd->vertices[i+BOTTOM], z);
784         glTexCoord2f(wd->texcoords[i+LEFT], wd->texcoords[i+BOTTOM]);
785         glVertex3f(x+wd->vertices[i+LEFT], y+wd->vertices[i+BOTTOM], z);
786     }
787     glEnd();
788
789     glBindTexture(GL_TEXTURE_2D, 0);
790 }
791
792 static void
793 paint_shadow(data_t *d, window_data_t *wd, int x, int y, GLfloat z)
794 {
795     int i;
796
797     if (wd->nrects < 1) return;
798
799     /* shape the shadow to the window */
800     glBindTexture(GL_TEXTURE_2D, wd->texname);
801
802     x += d->xshadowoff;
803     y += d->yshadowoff;
804
805     glBegin(GL_QUADS);
806     for (i = 0; i < wd->nrects * 4; i += 4) {
807         glTexCoord2f(wd->texcoords[i+LEFT], wd->texcoords[i+TOP]);
808         glVertex3f(x+wd->vertices[i+LEFT], y+wd->vertices[i+TOP], z);
809         glTexCoord2f(wd->texcoords[i+RIGHT], wd->texcoords[i+TOP]);
810         glVertex3f(x+wd->vertices[i+RIGHT], y+wd->vertices[i+TOP], z);
811         glTexCoord2f(wd->texcoords[i+RIGHT], wd->texcoords[i+BOTTOM]);
812         glVertex3f(x+wd->vertices[i+RIGHT], y+wd->vertices[i+BOTTOM], z);
813         glTexCoord2f(wd->texcoords[i+LEFT], wd->texcoords[i+BOTTOM]);
814         glVertex3f(x+wd->vertices[i+LEFT], y+wd->vertices[i+BOTTOM], z);
815     }
816     glEnd();
817
818     glBindTexture(GL_TEXTURE_2D, 0);
819 }