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