chiark / gitweb /
New option: movres.ignore_transience.
[e16] / src / eglx.c
1 /*
2  * Copyright (C) 2007 Kim Woelders
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to
6  * deal in the Software without restriction, including without limitation the
7  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8  * sell copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies of the Software, its documentation and marketing & publicity
13  * materials, and acknowledgment shall be given in the documentation, materials
14  * and software packages that this Software was used.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 #define GLX_GLXEXT_PROTOTYPES 1
24 #include "E.h"
25 #include "eglx.h"
26 #include "eimage.h"
27 #include <GL/gl.h>
28 #include <GL/glu.h>
29 #include <GL/glx.h>
30 #include <X11/extensions/Xcomposite.h>
31 #include <X11/extensions/Xrender.h>
32
33 #define ENABLE_DEBUG   1
34 #if ENABLE_DEBUG
35 #define Dprintf(fmt...)  do { if(EDebug(EDBUG_TYPE_GLX))Eprintf(fmt); } while(0)
36 #define D2printf(fmt...) do { if(EDebug(EDBUG_TYPE_GLX)>1)Eprintf(fmt); } while(0)
37 #else
38 #define Dprintf(fmt...)
39 #define D2printf(fmt...)
40 #endif /* ENABLE_DEBUG */
41
42 #define ETEX_TYPE_IMAGE      1
43 #define ETEX_TYPE_PIXMAP     2
44
45 #if 1
46 #define TEXTURE_TARGET GL_TEXTURE_2D
47 #else
48 #define TEXTURE_TARGET GLX_TEXTURE_RECTANGLE_EXT
49 #endif
50
51 #ifdef HAVE_GLX_glXBindTexImageEXT
52
53 #define _glXBindTexImageEXT    glXBindTexImageEXT
54 #define _glXReleaseTexImageEXT glXReleaseTexImageEXT
55
56 #else
57
58 #include <dlfcn.h>
59
60 /* GL functions and helper */
61 typedef void        (*glXBindTexImageEXT_func) (Display * dpy,
62                                                 GLXDrawable drawable,
63                                                 int buffer,
64                                                 const int *attrib_list);
65 typedef void        (*glXReleaseTexImageEXT_func) (Display * dpy,
66                                                    GLXDrawable drawable,
67                                                    int buffer);
68 typedef void        (*glXFuncPtr) (void);
69 typedef             glXFuncPtr(*glXGetProcAddress_func) (const GLubyte *);
70
71 static glXBindTexImageEXT_func _glXBindTexImageEXT;
72 static glXReleaseTexImageEXT_func _glXReleaseTexImageEXT;
73 static glXGetProcAddress_func glx_get_proc_address;
74
75 static              glXFuncPtr
76 get_func_addr(const char *name)
77 {
78    glXFuncPtr          ret = NULL;
79
80    if (glx_get_proc_address)
81       ret = glx_get_proc_address((const GLubyte *)name);
82    if (!ret)
83       ret = (glXFuncPtr) dlsym(RTLD_DEFAULT, name);
84
85    return ret;
86 }
87
88 static int
89 glx_funcs_init(void)
90 {
91    glx_get_proc_address = (glXGetProcAddress_func)
92       get_func_addr("glXGetProcAddress");
93    if (!glx_get_proc_address)
94       glx_get_proc_address = (glXGetProcAddress_func)
95          get_func_addr("glXGetProcAddressARB");
96
97    _glXBindTexImageEXT = (glXBindTexImageEXT_func)
98       get_func_addr("glXBindTexImageEXT");
99
100    _glXReleaseTexImageEXT = (glXReleaseTexImageEXT_func)
101       get_func_addr("glXReleaseTexImageEXT");
102
103    return !_glXBindTexImageEXT || !_glXReleaseTexImageEXT;
104 }
105
106 #endif /* HAVE_GLX_glXBindTexImageEXT */
107
108 static void         EobjTexturesFree(void);
109
110 typedef struct {
111    XVisualInfo        *vi;
112    GLXContext          ctx;
113    GLXFBConfig         fbc;
114    unsigned            ctx_initialised:1;
115 } EGlContext;
116
117 static EGlContext   egl;
118
119 #define FBCATTR(fbc, attr, want) _EGlFbcAttrib(fbc, #attr, attr, want)
120 static int
121 _EGlFbcAttrib(GLXFBConfig fbc, const char *name, int attr, int want)
122 {
123    int                 err, value;
124
125    value = 0xabbabeef;
126    err = glXGetFBConfigAttrib(disp, fbc, attr, &value);
127    if (err)
128       Eprintf("  %s *** Error %d ***\n", name, err);
129    else if (want > 0)
130       D2printf("  %s=%#x (want %#x)\n", name, value, want);
131    else
132       D2printf("  %s=%#x\n", name, value);
133
134    return value;
135 }
136
137 int
138 EGlInit(void)
139 {
140 /* From NV's README.txt (AddARGBGLXVisuals) */
141    static const int    attrs[] = {
142       GLX_VISUAL_CAVEAT_EXT, GLX_NONE_EXT,
143       GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT | GLX_PIXMAP_BIT,
144       GLX_RENDER_TYPE, GLX_RGBA_BIT,
145       GLX_RED_SIZE, 1,
146       GLX_GREEN_SIZE, 1,
147       GLX_BLUE_SIZE, 1,
148       GLX_ALPHA_SIZE, 1,
149       GLX_DOUBLEBUFFER, True,
150       GLX_DEPTH_SIZE, 1,
151       0
152    };
153    XVisualInfo        *vi;
154    GLXFBConfig        *fbc;
155    int                 i, ix, num;
156    int                 value;
157    char               *s;
158    XID                 vid = None;
159    XRenderPictFormat  *pictFormat;
160
161    Dprintf("EGlInit\n");
162
163    memset(&egl, 0, sizeof(EGlContext));
164
165    s = getenv("EVISUAL");
166    if (s)
167      {
168         vid = strtoul(s, NULL, 0);
169         Eprintf("Want Visual Id=%#lx\n", vid);
170      }
171
172    /* Create a GLX context */
173    fbc = glXChooseFBConfig(disp, DefaultScreen(disp), attrs, &num);
174    if (!fbc)
175      {
176         Eprintf("No FB configs\n");
177         return -1;
178      }
179
180    D2printf("Visuals found: %d\n", num);
181    ix = -1;
182    for (i = 0; i < num; i++)
183      {
184         vi = glXGetVisualFromFBConfig(disp, fbc[i]);
185         if (!vi)
186            continue;
187
188         D2printf("Checking Visual ID=%#lx depth=%d\n", vi->visualid, vi->depth);
189         if (vid && vi->visualid != vid)
190            continue;
191
192 #if 1
193         value = FBCATTR(fbc[i], GLX_FBCONFIG_ID, -1);
194         value = FBCATTR(fbc[i], GLX_CONFIG_CAVEAT, GLX_NONE);
195         value = FBCATTR(fbc[i], GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT);
196         value = FBCATTR(fbc[i], GLX_RENDER_TYPE, -1);
197         value = FBCATTR(fbc[i], GLX_X_VISUAL_TYPE, -1);
198         value = FBCATTR(fbc[i], GLX_X_RENDERABLE, -1);
199         value = FBCATTR(fbc[i], GLX_BUFFER_SIZE, -1);
200         value = FBCATTR(fbc[i], GLX_LEVEL, -1);
201         value = FBCATTR(fbc[i], GLX_TRANSPARENT_TYPE, -1);
202 #endif
203
204 #if 1
205         value = FBCATTR(fbc[i], GLX_BIND_TO_TEXTURE_RGBA_EXT, 1);
206         value = FBCATTR(fbc[i], GLX_BIND_TO_TEXTURE_RGB_EXT, 1);
207         if (!value)
208            continue;
209         value = FBCATTR(fbc[i], GLX_BIND_TO_MIPMAP_TEXTURE_EXT, -1);
210         value = FBCATTR(fbc[i], GLX_BIND_TO_TEXTURE_TARGETS_EXT,
211                         GLX_TEXTURE_2D_BIT_EXT);
212 #if 0
213         if (!(value & GLX_TEXTURE_2D_BIT_EXT))
214            continue;
215 #endif
216         value = FBCATTR(fbc[i], GLX_Y_INVERTED_EXT, -1);
217 #endif
218
219 #if 1
220         /* We want an ARGB visual */
221         pictFormat = XRenderFindVisualFormat(disp, vi->visual);
222         if (!pictFormat)
223            continue;
224         if (pictFormat->direct.alphaMask == 0)
225            continue;
226 #endif
227
228         D2printf(" - passed\n");
229         if (ix < 0)
230            ix = i;
231
232         XFree(vi);
233      }
234
235    if (ix >= 0)
236       egl.fbc = fbc[ix];
237    XFree(fbc);
238
239    if (ix < 0)
240      {
241         Eprintf("No FB config match\n");
242         return -1;
243      }
244
245 #ifndef HAVE_GLX_glXBindTexImageEXT
246    if (glx_funcs_init())
247      {
248         Eprintf("glXBindTexImageEXT or glXReleaseTexImageEXT not available\n");
249         return -1;
250      }
251 #endif
252
253    egl.vi = glXGetVisualFromFBConfig(disp, egl.fbc);
254
255    egl.ctx = glXCreateNewContext(disp, egl.fbc, GLX_RGBA_TYPE, NULL, True);
256
257    Dprintf("Direct Rendering %s\n",
258            glXIsDirect(disp, egl.ctx) ? "enabled" : "not available");
259    Dprintf("Visual ID=%#lx  depth %d\n", egl.vi->visualid, egl.vi->depth);
260
261    return 0;
262 }
263
264 void
265 EGlExit(void)
266 {
267    Dprintf("EGlExit\n");
268
269    EobjTexturesFree();
270
271    if (egl.vi)
272      {
273         XFree(egl.vi);
274         egl.vi = NULL;
275      }
276
277    if (egl.ctx)
278      {
279         EGlWindowDisconnect();
280         glXDestroyContext(disp, egl.ctx);
281         egl.ctx = NULL;
282      }
283 }
284
285 Visual             *
286 EGlGetVisual(void)
287 {
288    if (!egl.vi)
289       EGlInit();
290    return (egl.vi) ? egl.vi->visual : NULL;
291 }
292
293 unsigned int
294 EGlGetDepth(void)
295 {
296    if (!egl.vi)
297       EGlInit();
298    return (egl.vi) ? egl.vi->depth : 0;
299 }
300
301 #if 0
302 Win
303 EGlWindowCreate(Win parent, int x, int y, unsigned int width,
304                 unsigned int height)
305 {
306    return ECreateWindowVD(parent, x, y, width, height, egl.vi->visual,
307                           egl.vi->depth);
308 }
309 #endif
310
311 void
312 EGlWindowConnect(Window xwin)
313 {
314    glXMakeContextCurrent(disp, xwin, xwin, egl.ctx);
315
316    if (egl.ctx_initialised)
317       return;
318
319    /* First time */
320    glEnable(TEXTURE_TARGET);
321
322    glShadeModel(GL_SMOOTH);
323    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
324    glClearDepth(1.0f);
325    glEnable(GL_DEPTH_TEST);
326    glDepthFunc(GL_LEQUAL);
327    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
328
329    egl.ctx_initialised = 1;
330 }
331
332 void
333 EGlWindowDisconnect(void)
334 {
335    if (!glXMakeContextCurrent(disp, None, None, NULL))
336      {
337         Eprintf("Failed to release GL context.\n");
338      }
339 }
340
341 ETexture           *
342 EGlTextureFromImage(EImage * im, int mode)
343 {
344    ETexture           *et;
345    int                 w, h;
346    unsigned char      *data;
347
348    if (!im)
349       return NULL;
350
351    et = Ecalloc(1, sizeof(ETexture));
352    if (!et)
353       return NULL;
354
355    et->type = ETEX_TYPE_IMAGE;
356    et->target = TEXTURE_TARGET;
357    glGenTextures(1, &et->texture);
358    glBindTexture(et->target, et->texture);
359
360    EImageGetSize(im, &w, &h);
361    data = EImageGetData(im);
362
363    switch (mode)
364      {
365      case 0:                    /* No filtering */
366         glTexImage2D(et->target, 0, GL_RGB8, w, h, 0, GL_BGRA,
367                      GL_UNSIGNED_BYTE, data);
368         glTexParameteri(et->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
369         glTexParameteri(et->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
370         break;
371      case 1:                    /* Linear filtering */
372         glTexImage2D(et->target, 0, GL_RGB8, w, h, 0, GL_BGRA,
373                      GL_UNSIGNED_BYTE, data);
374         glTexParameteri(et->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
375         glTexParameteri(et->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
376         break;
377      case 2:                    /* Mipmapping */
378         gluBuild2DMipmaps(et->target, GL_RGB8, w, h, GL_BGRA,
379                           GL_UNSIGNED_BYTE, data);
380         glTexParameteri(et->target, GL_TEXTURE_MIN_FILTER,
381                         GL_LINEAR_MIPMAP_NEAREST);
382         glTexParameteri(et->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
383         break;
384      }
385
386    return et;
387 }
388
389 static              GLXPixmap
390 GetGlPixmap(Window xwin, Drawable draw)
391 {
392    static const int    attrs[] = {
393       GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT,
394       0
395    };
396    Pixmap              pixmap;
397    GLXPixmap           glxpixmap;
398
399    if (xwin == None && draw == None)
400       return 0;
401
402    pixmap = (draw) ? draw : XCompositeNameWindowPixmap(disp, xwin);
403    glxpixmap = glXCreatePixmap(disp, egl.fbc, pixmap, attrs);
404    Dprintf("GetGlPixmap: Window=%#lx Drawable=%#lx glxpixmap=%#lx\n",
405            xwin, draw, glxpixmap);
406
407    return glxpixmap;
408 }
409
410 static void
411 _EGlTextureFromDrawable(ETexture * et, Drawable draw, int mode)
412 {
413    if (!et || draw == None)
414       return;
415
416    glBindTexture(et->target, et->texture);
417    et->glxpmap = GetGlPixmap(draw, (mode & 0x100) ? None : draw);
418    if (et->glxpmap == None)
419       return;
420
421    _glXBindTexImageEXT(disp, et->glxpmap, GLX_FRONT_LEFT_EXT, NULL);
422 #if 0                           /* No! */
423    glXDestroyPixmap(disp, et->glxpmap);
424 #endif
425 }
426
427 ETexture           *
428 EGlTextureFromDrawable(Drawable draw, int mode)
429 {
430    ETexture           *et;
431
432    if (draw == None)
433       return NULL;
434
435    et = Ecalloc(1, sizeof(ETexture));
436    if (!et)
437       return NULL;
438
439    et->type = ETEX_TYPE_PIXMAP;
440    et->target = TEXTURE_TARGET;
441    glGenTextures(1, &et->texture);
442    glBindTexture(et->target, et->texture);
443
444    _EGlTextureFromDrawable(et, draw, mode);
445
446    return et;
447 }
448
449 void
450 EGlTextureDestroy(ETexture * et)
451 {
452    if (!et)
453       return;
454
455    Dprintf("EGlTextureDestroy %d type=%u pmap=%#x\n", et->texture, et->type,
456            et->glxpmap);
457
458    EGlTextureInvalidate(et);
459    glDeleteTextures(1, &et->texture);
460    Efree(et);
461 }
462
463 void
464 EGlTextureInvalidate(ETexture * et)
465 {
466    if (!et)
467       return;
468
469    Dprintf("EGlTextureInvalidate %d type=%u pmap=%#x\n", et->texture, et->type,
470            et->glxpmap);
471
472    switch (et->type)
473      {
474      case ETEX_TYPE_IMAGE:
475         break;
476      case ETEX_TYPE_PIXMAP:
477         if (!et->glxpmap)
478            break;
479         _glXReleaseTexImageEXT(disp, et->glxpmap, GLX_FRONT_LEFT_EXT);
480         glXDestroyPixmap(disp, et->glxpmap);
481         et->glxpmap = None;
482         break;
483      }
484 }
485
486 #include "eobj.h"
487
488 static void
489 EobjTexturesFree(void)
490 {
491    int                 i, num;
492    EObj               *const *eol;
493
494    eol = EobjListStackGet(&num);
495    for (i = 0; i < num; i++)
496       EobjTextureDestroy(eol[i]);
497 }
498
499 ETexture           *
500 EobjGetTexture(EObj * eo)
501 {
502    if (eo->glhook)
503      {
504         if (eo->glhook->glxpmap)
505            return eo->glhook;
506
507         _EGlTextureFromDrawable(eo->glhook, EobjGetPixmap(eo), 0);
508         return eo->glhook;
509      }
510
511    return EobjTextureCreate(eo);
512 }
513
514 ETexture           *
515 EobjTextureCreate(EObj * eo)
516 {
517    Pixmap              pmap;
518
519    pmap = EobjGetPixmap(eo);
520    if (pmap == None)
521       return NULL;
522
523    eo->glhook = EGlTextureFromDrawable(pmap, 0);
524
525    return eo->glhook;
526 }
527
528 void
529 EobjTextureDestroy(EObj * eo)
530 {
531    EGlTextureDestroy(eo->glhook);
532    eo->glhook = NULL;
533 }
534
535 void
536 EobjTextureInvalidate(EObj * eo)
537 {
538    EGlTextureInvalidate(eo->glhook);
539 }