• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1Name
2
3    EXT_platform_xcb
4
5Name Strings
6
7    EGL_EXT_platform_xcb
8
9Contributors
10
11    Yuxuan Shui <yshuiv7@gmail.com>
12
13Contacts
14
15    Yuxuan Shui <yshuiv7@gmail.com>
16
17Status
18
19    Complete
20
21Version
22
23    Version 1, 2020-08-28
24
25Number
26
27    EGL Extension #141
28
29Extension Type
30
31    EGL client extension
32
33Dependencies
34
35    Requires EGL_EXT_client_extensions to query its existence without
36    a display.
37
38    Requires EGL_EXT_platform_base.
39
40    This extension is written against the wording of version 9 of the
41    EGL_EXT_platform_base specification.
42
43Overview
44
45    This extension defines how to create EGL resources from native X11
46    resources using the functions defined by EGL_EXT_platform_base.
47
48    The native X11 resources required by this extension are xcb resources.
49    All X11 types discussed here are defined by the header `xcb.h`.
50
51New Types
52
53    None
54
55New Procedures and Functions
56
57    None
58
59New Tokens
60
61    Accepted as the <platform> argument of eglGetPlatformDisplayEXT:
62
63        EGL_PLATFORM_XCB_EXT                    0x31DC
64
65    Accepted as an attribute name in the <attrib_list> argument of
66    eglGetPlatformDisplayEXT:
67
68        EGL_PLATFORM_XCB_SCREEN_EXT             0x31DE
69
70Additions to the EGL Specification
71
72    None.
73
74New Behavior
75
76    To determine if the EGL implementation supports this extension, clients
77    should query the EGL_EXTENSIONS string of EGL_NO_DISPLAY.
78
79    This extension defines the same set of behaviors as EGL_EXT_platform_x11,
80    except Xlib types are replaced with xcb types.
81
82    To obtain an EGLDisplay backed by an X11 screen, call
83    eglGetPlatformDisplayEXT with <platform> set to EGL_PLATFORM_XCB_EXT. The
84    <native_display> parameter specifies the X11 display connection to use, and
85    must point to a valid xcb `xcb_connection_t` or be EGL_DEFAULT_DISPLAY.  If
86    <native_display> is EGL_DEFAULT_DISPLAY, then EGL will create [1] a
87    connection to the default X11 display. The environment variable DISPLAY
88    determines the default X11 display, and, unless overridden by the
89    EGL_PLATFORM_XCB_SCREEN_EXT attribute, the default X11 screen - as
90    described in the documentation of `xcb_connect`.  If the environment
91    variable DISPLAY is not present in this case, the result is undefined. The
92    value of attribute EGL_PLATFORM_XCB_SCREEN_EXT specifies the X11 screen to
93    use. If the attribute is omitted from <attrib_list>, and <native_display>
94    is not EGL_DEFAULT_DISPLAY, then screen 0 will be used. Otherwise, the
95    attribute's value must be a valid screen on the display connection. If the
96    attribute's value is not a valid screen, then an EGL_BAD_ATTRIBUTE error is
97    generated.
98
99    [fn1] The method by which EGL creates a connection to the default X11
100    display is an internal implementation detail. The implementation may use
101    xcb_connect, or any other method.
102
103    To obtain an on-screen rendering surface from an X11 Window, call
104    eglCreatePlatformWindowSurfaceEXT with a <dpy> that belongs to X11 and
105    a <native_window> that points to an xcb_window_t.
106
107    To obtain an offscreen rendering surface from an X11 Pixmap, call
108    eglCreatePlatformPixmapSurfaceEXT with a <dpy> that belongs to X11 and
109    a <native_pixmap> that points to an xcb_pixmap_t.
110
111Issues
112
113    1. As xcb_connection_t doesn't carry a screen number, how should a screen be
114       selected in eglGetPlatformDisplayEXT()?
115
116       RESOLVED. The screen will be chosen with the following logic:
117
118         * If EGL_PLATFORM_XCB_SCREEN_EXT is specified, it will always take
119           precedence. Whether <native_display> is EGL_DEFAULT_DISPLAY or not.
120
121         * Otherwise, if <native_display> is not EGL_DEFAULT_DISPLAY, then
122           screen 0 will be used.
123
124         * Otherwise, which is to say <native_display> is EGL_DEFAULT_DISPLAY.
125           Then the DISPLAY environment variable will be used to determine the
126           screen number. If DISPLAY contains a screen number, that will be
127           used; if not, then 0 will be used.
128
129         * If the DISPLAY environment variable is not present when
130           <native_display> is EGL_DEFAULT_DISPLAY, the result will be undefined.
131
132Example Code
133
134    // This example program creates two EGL surfaces: one from an X11 Window
135    // and the other from an X11 Pixmap.
136    //
137    // Compile with `cc example.c -lxcb -lEGL`.
138
139    #include <stddef.h>
140    #include <stdlib.h>
141    #include <string.h>
142
143    #include <EGL/egl.h>
144    #include <EGL/eglext.h>
145    #include <xcb/xcb.h>
146
147    struct my_display {
148        xcb_connection_t *x11;
149        int screen;
150        int root_of_screen;
151        EGLDisplay egl;
152    };
153
154    struct my_config {
155        struct my_display dpy;
156        xcb_colormap_t colormap;
157        xcb_visualid_t visualid;
158        int depth;
159        EGLConfig egl;
160    };
161
162    struct my_window {
163        struct my_config config;
164        xcb_window_t x11;
165        EGLSurface egl;
166    };
167
168    struct my_pixmap {
169        struct my_config config;
170        xcb_pixmap_t x11;
171        EGLSurface egl;
172    };
173
174    static void check_extensions(void) {
175        const char *client_extensions =
176            eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
177
178        if (!client_extensions) {
179            // EGL_EXT_client_extensions is unsupported.
180            abort();
181        }
182        if (!strstr(client_extensions, "EGL_EXT_platform_xcb")) {
183            abort();
184        }
185    }
186
187    xcb_screen_t *get_screen(xcb_connection_t *c, int screen) {
188        xcb_screen_iterator_t iter;
189
190        iter = xcb_setup_roots_iterator(xcb_get_setup(c));
191        for (; iter.rem; --screen, xcb_screen_next(&iter))
192            if (screen == 0)
193                return iter.data;
194
195        return NULL;
196    }
197
198    int get_visual_depth(xcb_connection_t *c, xcb_visualid_t visual) {
199        const xcb_setup_t *setup = xcb_get_setup(c);
200        for (xcb_screen_iterator_t i = xcb_setup_roots_iterator(setup); i.rem;
201             xcb_screen_next(&i)) {
202            for (xcb_depth_iterator_t j =
203                     xcb_screen_allowed_depths_iterator(i.data);
204                 j.rem; xcb_depth_next(&j)) {
205                const int len = xcb_depth_visuals_length(j.data);
206                const xcb_visualtype_t *visuals = xcb_depth_visuals(j.data);
207                for (int k = 0; k < len; k++) {
208                    if (visual == visuals[k].visual_id) {
209                        return j.data->depth;
210                    }
211                }
212            }
213        }
214        abort();
215    }
216
217    static struct my_display get_display(void) {
218        struct my_display dpy;
219
220        dpy.x11 = xcb_connect(NULL, &dpy.screen);
221        if (!dpy.x11) {
222            abort();
223        }
224
225        dpy.egl = eglGetPlatformDisplayEXT(EGL_PLATFORM_XCB_EXT, dpy.x11,
226                                           (const EGLint[]){
227                                               EGL_PLATFORM_XCB_SCREEN_EXT,
228                                               dpy.screen,
229                                               EGL_NONE,
230                                           });
231
232        if (dpy.egl == EGL_NO_DISPLAY) {
233            abort();
234        }
235
236        EGLint major, minor;
237        if (!eglInitialize(dpy.egl, &major, &minor)) {
238            abort();
239        }
240
241        xcb_screen_t *screen = get_screen(dpy.x11, dpy.screen);
242        dpy.root_of_screen = screen->root;
243
244        return dpy;
245    }
246
247    static struct my_config get_config(struct my_display dpy) {
248        struct my_config config = {
249            .dpy = dpy,
250        };
251
252        EGLint egl_config_attribs[] = {
253            EGL_BUFFER_SIZE,
254            32,
255            EGL_RED_SIZE,
256            8,
257            EGL_GREEN_SIZE,
258            8,
259            EGL_BLUE_SIZE,
260            8,
261            EGL_ALPHA_SIZE,
262            8,
263
264            EGL_DEPTH_SIZE,
265            EGL_DONT_CARE,
266            EGL_STENCIL_SIZE,
267            EGL_DONT_CARE,
268
269            EGL_RENDERABLE_TYPE,
270            EGL_OPENGL_ES2_BIT,
271            EGL_SURFACE_TYPE,
272            EGL_WINDOW_BIT | EGL_PIXMAP_BIT,
273            EGL_NONE,
274        };
275
276        EGLint num_configs;
277        if (!eglChooseConfig(dpy.egl, egl_config_attribs, &config.egl, 1,
278                             &num_configs)) {
279            abort();
280        }
281        if (num_configs == 0) {
282            abort();
283        }
284
285        if (!eglGetConfigAttrib(dpy.egl, config.egl, EGL_NATIVE_VISUAL_ID,
286                                (EGLint *)&config.visualid)) {
287            abort();
288        }
289
290        config.colormap = xcb_generate_id(dpy.x11);
291        if (xcb_request_check(dpy.x11,
292                              xcb_create_colormap_checked(
293                                  dpy.x11, XCB_COLORMAP_ALLOC_NONE, config.colormap,
294                                  dpy.root_of_screen, config.visualid))) {
295            abort();
296        }
297
298        config.depth = get_visual_depth(dpy.x11, config.visualid);
299
300        return config;
301    }
302
303    static struct my_window get_window(struct my_config config) {
304        xcb_generic_error_t *e;
305
306        struct my_window window = {
307            .config = config,
308        };
309
310        window.x11 = xcb_generate_id(config.dpy.x11);
311        e = xcb_request_check(
312            config.dpy.x11,
313            xcb_create_window_checked(config.dpy.x11,            // connection
314                                      XCB_COPY_FROM_PARENT,      // depth
315                                      window.x11,                // window id
316                                      config.dpy.root_of_screen, // root
317                                      0, 0,                      // x, y
318                                      256, 256,                  // width, height
319                                      0,                         // border_width
320                                      XCB_WINDOW_CLASS_INPUT_OUTPUT, // class
321                                      config.visualid,               // visual
322                                      XCB_CW_COLORMAP,               // mask
323                                      (const int[]){
324                                          config.colormap,
325                                          XCB_NONE,
326                                      }));
327        if (e) {
328            abort();
329        }
330
331        window.egl = eglCreatePlatformWindowSurfaceEXT(config.dpy.egl, config.egl,
332                                                       &window.x11, NULL);
333
334        if (window.egl == EGL_NO_SURFACE) {
335            abort();
336        }
337
338        return window;
339    }
340
341    static struct my_pixmap get_pixmap(struct my_config config) {
342        struct my_pixmap pixmap = {
343            .config = config,
344        };
345
346        pixmap.x11 = xcb_generate_id(config.dpy.x11);
347        if (xcb_request_check(
348                config.dpy.x11,
349                xcb_create_pixmap(config.dpy.x11, config.depth, pixmap.x11,
350                                  config.dpy.root_of_screen, 256, 256))) {
351            abort();
352        }
353
354        pixmap.egl = eglCreatePlatformPixmapSurfaceEXT(config.dpy.egl, config.egl,
355                                                       &pixmap.x11, NULL);
356
357        if (pixmap.egl == EGL_NO_SURFACE) {
358            abort();
359        }
360
361        return pixmap;
362    }
363
364    int main(void) {
365        check_extensions();
366
367        struct my_display dpy = get_display();
368        struct my_config config = get_config(dpy);
369        struct my_window window = get_window(config);
370        struct my_pixmap pixmap = get_pixmap(config);
371
372        return 0;
373    }
374
375Revision History
376
377    Version 2, 2020.10.13 (Yuxuan Shui)
378        - Some wording changes
379        - Address the question about screen selection
380
381    Version 1, 2020.08.28 (Yuxuan Shui)
382        - First draft
383