Commit | Line | Data |
---|---|---|
25072f02 AW |
1 | ;;; figl |
2 | ;;; Copyright (C) 2013 Andy Wingo <wingo@pobox.com> | |
3 | ;;; | |
4 | ;;; Figl is free software: you can redistribute it and/or modify it | |
5 | ;;; under the terms of the GNU Lesser General Public License as | |
6 | ;;; published by the Free Software Foundation, either version 3 of the | |
7 | ;;; License, or (at your option) any later version. | |
8 | ;;; | |
9 | ;;; Figl is distributed in the hope that it will be useful, but WITHOUT | |
10 | ;;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
11 | ;;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General | |
12 | ;;; Public License for more details. | |
13 | ;;; | |
14 | ;;; You should have received a copy of the GNU Lesser General Public | |
15 | ;;; License along with this program. If not, see | |
16 | ;;; <http://www.gnu.org/licenses/>. | |
17 | ||
18 | ;;; Commentary: | |
19 | ;; | |
20 | ;; figl is the Foreign Interface to GL. | |
21 | ;; | |
22 | ;;; Code: | |
23 | ||
24 | (define-module (figl gl runtime) | |
25 | #:use-module (system foreign) | |
26 | #:use-module (figl runtime) | |
27 | #:export (current-gl-resolver | |
28 | current-gl-get-dynamic-object | |
29 | define-gl-procedure | |
30 | define-gl-procedures)) | |
31 | ||
32 | (module-use! (module-public-interface (current-module)) | |
33 | (resolve-interface '(figl runtime))) | |
34 | ||
35 | ;; | |
36 | ;; OpenGL and loading. What a mess. So, in the beginning, when | |
37 | ;; Microsoft added support for OpenGL to Windows, they did so via a | |
38 | ;; trampoline DLL. This DLL had a fixed number of entry points, and it | |
39 | ;; was independent of the driver that the graphics card provided. It | |
40 | ;; also provided an extension interface, wglGetProcAddress, which could | |
41 | ;; return additional GL procedures by name. Microsoft was unwilling to | |
42 | ;; extend their trampoline DLL for whatever reason, and so on Windows | |
43 | ;; you always needed to wglGetProcAddress for almost any OpenGL | |
44 | ;; function. | |
45 | ;; | |
46 | ;; Time passed and GLX and other GL implementations started to want | |
47 | ;; extensions too. This let application vendors ship applications that | |
48 | ;; could take advantage of the capabilities of users's graphics cards | |
49 | ;; without requiring that they be present. | |
50 | ;; | |
51 | ;; There are a couple of differences between WGL and GLX, however. | |
52 | ;; Chiefly, wglGetProcAddress can only be called once you have a | |
53 | ;; context, and the resulting function can only be used in that context. | |
54 | ;; In practice it seems that it can be used also in other contexts that | |
55 | ;; end up referring to that same driver and GPU. GLX on the other hand | |
56 | ;; is context-independent, but presence of a function does not mean that | |
57 | ;; the corresponding functionality is actually available. In theory | |
58 | ;; users have to check for the presence of the GL extension or check the | |
59 | ;; core GL version, depending on whether the interface is an extension | |
60 | ;; or in GL core. | |
61 | ;; | |
62 | ;; Because of this difference between the GLX and WGL semantics, there | |
63 | ;; is no core "glGetProcAddress" function. It's terrible: each | |
64 | ;; windowing system is responsible for providing their own | |
65 | ;; function-loader interface. | |
66 | ;; | |
67 | ;; Finally, Guile needs to load up at least some interfaces using | |
68 | ;; dynamic-link / dynamic-pointer in order to be able to talk to the | |
69 | ;; library at all (and to open a context in the case of Windows), and it | |
70 | ;; happens that these interfaces also work fine for getting some of the | |
71 | ;; GL functionality! | |
72 | ;; | |
73 | ;; All of this mess really has very little place in the world of free | |
74 | ;; software, where dynamic linking is entirely sufficient to deal with | |
75 | ;; this issue, but it is how things have evolved. | |
76 | ;; | |
77 | ;; In light of all of this, we need to make some simplifications. | |
78 | ;; | |
79 | ;; One is that each low-level function will have just one foreign | |
80 | ;; function wrapper. This means that a minority of Windows | |
81 | ;; configurations won't work. Oh well. | |
82 | ;; | |
83 | ;; Another is that if dynamic-link returns a result, that it is assumed | |
84 | ;; that glXGetProcAddress (or the equivalent) would return the same | |
85 | ;; value. So we can try dynamic-link first, and only dispatch to e.g | |
86 | ;; glXGetProcAddress if that fails. | |
87 | ;; | |
88 | ;; Finally, we assume that all GL symbols may be resolved by | |
89 | ;; dynamic-pointer by looking in one library, regardless of whether they | |
90 | ;; come from the lower GL level or from the window-system-specific | |
91 | ;; level. | |
92 | ;; | |
93 | ||
94 | ;; Parameterize this with glXGetProcAddress, eglGetProcAddress, etc. | |
95 | (define current-gl-resolver | |
96 | (make-parameter (lambda (name) %null-pointer))) | |
97 | ||
98 | ;; Parameterize this with a procedure that returns a dynamic object we | |
99 | ;; can use to get libGL bindings. | |
100 | (define current-gl-get-dynamic-object | |
101 | (make-parameter (lambda () (dynamic-link)))) | |
102 | ||
103 | (define (resolve name) | |
104 | (let ((ptr ((current-gl-resolver) (symbol->string name)))) | |
105 | (if (null-pointer? ptr) | |
106 | (dynamic-pointer (symbol->string name) | |
107 | ((current-gl-get-dynamic-object))) | |
108 | ptr))) | |
109 | ||
110 | (define-syntax define-gl-procedure | |
111 | (syntax-rules (->) | |
112 | ((define-gl-procedure (name (pname ptype) ... -> type) | |
113 | docstring) | |
114 | (define-foreign-procedure (name (pname ptype) ... -> type) | |
115 | (resolve 'name) | |
116 | docstring)))) | |
117 | ||
118 | (define-syntax define-gl-procedures | |
119 | (syntax-rules () | |
120 | ((define-gl-procedures ((name prototype ...) ...) | |
121 | docstring) | |
122 | (begin | |
123 | (define-gl-procedure (name prototype ...) | |
124 | docstring) | |
125 | ...)))) |