Project
Loading...
Searching...
No Matches
GPUDisplayFrontendX11.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
14
15// Now the other headers
19#include "GPULogging.h"
20#include <cstdio>
21#include <cstdlib>
22#include <cstring>
23#include <stdexcept>
24
25#include <unistd.h>
26#include <X11/Xatom.h>
27#include <X11/Xresource.h>
28
29#ifdef GPUCA_BUILD_EVENT_DISPLAY_VULKAN
30#include <vulkan/vulkan.h>
31#include <vulkan/vulkan_xlib.h>
32#endif
33
34typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int32_t*);
35
36using namespace o2::gpu;
37
43
44int32_t GPUDisplayFrontendX11::GetKey(int32_t key)
45{
46 if (key == 65453) {
47 return ('-');
48 }
49 if (key == 65451) {
50 return ('+');
51 }
52 if (key == 65505 || key == 65506) {
53 return (KEY_SHIFT);
54 }
55 if (key == 65513 || key == 65511) {
56 return (KEY_ALT);
57 }
58 if (key == 65027) {
59 return (KEY_RALT);
60 }
61 if (key == 65507) {
62 return (KEY_CTRL);
63 }
64 if (key == 65508) {
65 return (KEY_RCTRL);
66 }
67 if (key == 65362) {
68 return (KEY_UP);
69 }
70 if (key == 65364) {
71 return (KEY_DOWN);
72 }
73 if (key == 65361) {
74 return (KEY_LEFT);
75 }
76 if (key == 65363) {
77 return (KEY_RIGHT);
78 }
79 if (key == 65365) {
80 return (KEY_PAGEUP);
81 }
82 if (key == 65366) {
83 return (KEY_PAGEDOWN);
84 }
85 if (key == 65307) {
86 return (KEY_ESCAPE);
87 }
88 if (key == 65293) {
89 return (KEY_ENTER);
90 }
91 if (key == 65367) {
92 return (KEY_END);
93 }
94 if (key == 65360) {
95 return (KEY_HOME);
96 }
97 if (key == 65379) {
98 return (KEY_INSERT);
99 }
100 if (key == 65470) {
101 return (KEY_F1);
102 }
103 if (key == 65471) {
104 return (KEY_F2);
105 }
106 if (key == 65472) {
107 return (KEY_F3);
108 }
109 if (key == 65473) {
110 return (KEY_F4);
111 }
112 if (key == 65474) {
113 return (KEY_F5);
114 }
115 if (key == 65475) {
116 return (KEY_F6);
117 }
118 if (key == 65476) {
119 return (KEY_F7);
120 }
121 if (key == 65477) {
122 return (KEY_F8);
123 }
124 if (key == 65478) {
125 return (KEY_F9);
126 }
127 if (key == 65479) {
128 return (KEY_F10);
129 }
130 if (key == 65480) {
131 return (KEY_F11);
132 }
133 if (key == 65481) {
134 return (KEY_F12);
135 }
136 if (key == 32) {
137 return (KEY_SPACE);
138 }
139 if (key > 255) {
140 return (0);
141 }
142 return 0;
143}
144
145void GPUDisplayFrontendX11::GetKey(XEvent& event, int32_t& keyOut, int32_t& keyPressOut)
146{
147 char tmpString[9];
148 KeySym sym;
149 if (XLookupString(&event.xkey, tmpString, 8, &sym, nullptr) == 0) {
150 tmpString[0] = 0;
151 }
152 int32_t specialKey = GetKey(sym);
153 int32_t localeKey = (uint8_t)tmpString[0];
154 // GPUInfo("Key: keycode %d -> sym %d (%c) key %d (%c) special %d (%c)", (int32_t)event.xkey.keycode, (int32_t)sym, (char)sym, (int32_t)localeKey, (char)localeKey, (int32_t)specialKey, (char)specialKey);
155
156 if (specialKey) {
157 keyOut = keyPressOut = specialKey;
158 } else {
159 keyOut = keyPressOut = localeKey;
160 if (keyPressOut >= 'a' && keyPressOut <= 'z') {
161 keyPressOut += 'A' - 'a';
162 }
163 }
164}
165
166void GPUDisplayFrontendX11::OpenGLPrint(const char* s, float x, float y, float r, float g, float b, float a, bool fromBotton)
167{
168#ifndef GPUCA_DISPLAY_OPENGL_CORE
169 if (backend()->backendType() == GPUDisplayBackend::TYPE_OPENGL) {
170 if (!fromBotton) {
171 y = mDisplayHeight - y;
172 }
173 glColor4f(r, g, b, a);
174 glRasterPos2f(x, y);
175 if (!glIsList(mFontBase)) {
176 GPUError("print string: Bad display list.");
177 exit(1);
178 } else if (s && strlen(s)) {
179 glPushAttrib(GL_LIST_BIT);
180 glListBase(mFontBase);
181 glCallLists(strlen(s), GL_UNSIGNED_BYTE, (GLubyte*)s);
182 glPopAttrib();
183 }
184 }
185#endif
186}
187
188int32_t GPUDisplayFrontendX11::FrontendMain()
189{
190 XSetWindowAttributes windowAttributes;
191 XVisualInfo* visualInfo = nullptr;
192 XEvent event;
193 Colormap colorMap;
194 GLXContext glxContext = nullptr;
195 int32_t errorBase;
196 int32_t eventBase;
197
198 // Open a connection to the X server
199 mXDisplay = XOpenDisplay(nullptr);
200
201 if (mXDisplay == nullptr) {
202 GPUError("could not open display");
203 return (-1);
204 }
205
206 XrmInitialize();
207 if (const char* resources = XResourceManagerString(mXDisplay)) {
208 XrmDatabase db = XrmGetStringDatabase(resources);
209 char* type = nullptr;
210 XrmValue value;
211 if (db && XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value) && value.addr && atof(value.addr) > 0) {
212 mScale = atof(value.addr) / 96.;
213 }
214 if (db) {
215 XrmDestroyDatabase(db);
216 }
217 }
218
219 // Make sure OpenGL's GLX extension supported
220 if (!glXQueryExtension(mXDisplay, &errorBase, &eventBase)) {
221 GPUError("X server has no OpenGL GLX extension");
222 return (-1);
223 }
224
225 const char* glxExt = glXQueryExtensionsString(mXDisplay, DefaultScreen(mXDisplay));
226 if (strstr(glxExt, "GLX_EXT_swap_control") == nullptr) {
227 if (backend()->backendType() == GPUDisplayBackend::TYPE_OPENGL) {
228 GPUError("GLX_EXT_swap_control not available, cannot change VSync");
229 }
230 vsync_supported = false;
231 } else {
232 vsync_supported = true;
233 }
234
235 // Require MSAA, double buffering, and Depth buffer
236 int32_t attribs[] = {GLX_X_RENDERABLE, True, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_ALPHA_SIZE, 8, GLX_DEPTH_SIZE, 24, GLX_STENCIL_SIZE, 8, GLX_DOUBLEBUFFER, True,
237 // GLX_SAMPLE_BUFFERS , 1, //Disable MSAA here, we do it by rendering to offscreenbuffer
238 // GLX_SAMPLES , MSAA_SAMPLES,
239 None};
240
241 GLXFBConfig fbconfig = nullptr;
242 int32_t fbcount;
243 GLXFBConfig* fbc = glXChooseFBConfig(mXDisplay, DefaultScreen(mXDisplay), attribs, &fbcount);
244 if (fbc == nullptr || fbcount == 0) {
245 GPUError("Failed to get MSAA GLXFBConfig");
246 return (-1);
247 }
248 fbconfig = fbc[0];
249 XFree(fbc);
250 visualInfo = glXGetVisualFromFBConfig(mXDisplay, fbconfig);
251
252 if (visualInfo == nullptr) {
253 GPUError("no RGB visual with depth buffer");
254 return (-1);
255 }
256
257 if (backend()->backendType() == GPUDisplayBackend::TYPE_OPENGL) {
258 // Create an OpenGL rendering context
259 glXCreateContextAttribsARBProc glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)glXGetProcAddressARB((const GLubyte*)"glXCreateContextAttribsARB");
260 if (glXCreateContextAttribsARB) {
261 int32_t context_attribs[] = {
262 GLX_CONTEXT_MAJOR_VERSION_ARB, GL_MIN_VERSION_MAJOR,
263 GLX_CONTEXT_MINOR_VERSION_ARB, GL_MIN_VERSION_MINOR,
264 GLX_CONTEXT_PROFILE_MASK_ARB, mBackend->CoreProfile() ? GLX_CONTEXT_CORE_PROFILE_BIT_ARB : GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
265 None};
266 glxContext = glXCreateContextAttribsARB(mXDisplay, fbconfig, nullptr, GL_TRUE, context_attribs);
267 } else {
268 glxContext = glXCreateContext(mXDisplay, visualInfo, nullptr, GL_TRUE);
269 }
270 if (glxContext == nullptr) {
271 GPUError("could not create rendering context");
272 return (-1);
273 }
274 }
275
276 Window win = RootWindow(mXDisplay, visualInfo->screen);
277 colorMap = XCreateColormap(mXDisplay, win, visualInfo->visual, AllocNone);
278 windowAttributes.colormap = colorMap;
279 windowAttributes.border_pixel = 0;
280 windowAttributes.event_mask = ExposureMask | VisibilityChangeMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | SubstructureNotifyMask | FocusChangeMask | PropertyChangeMask;
281
282 // Create an X window with the selected visual
283 mWindow = XCreateWindow(mXDisplay, win, 50, 50, INIT_WIDTH * mScale, INIT_HEIGHT * mScale, // Position / Width and height of window
284 0, visualInfo->depth, InputOutput, visualInfo->visual, CWBorderPixel | CWColormap | CWEventMask, &windowAttributes);
285 XSetStandardProperties(mXDisplay, mWindow, DISPLAY_WINDOW_NAME, DISPLAY_WINDOW_NAME, None, nullptr, 0, nullptr);
286 XSizeHints sizeHints{};
287 sizeHints.flags = PMinSize;
288 sizeHints.min_width = MIN_WIDTH * mScale;
289 sizeHints.min_height = MIN_HEIGHT * mScale;
290 XSetWMNormalHints(mXDisplay, mWindow, &sizeHints);
291 if (backend()->backendType() == GPUDisplayBackend::TYPE_OPENGL) {
292 glXMakeCurrent(mXDisplay, mWindow, glxContext);
293 }
294 XMapWindow(mXDisplay, mWindow);
295
296 XEvent mapEvent; // Maximize only after the window manager placed the window (on the active monitor), so that it restores to this position when un-maximized
297 XPeekIfEvent(mXDisplay, &mapEvent, [](Display*, XEvent* ev, XPointer window) -> Bool { return ev->type == MapNotify && ev->xmap.window == *(Window*)window; }, (XPointer)&mWindow);
299
300 // Receive signal when window closed
301 Atom WM_DELETE_WINDOW = XInternAtom(mXDisplay, "WM_DELETE_WINDOW", False);
302 XSetWMProtocols(mXDisplay, mWindow, &WM_DELETE_WINDOW, 1);
303#ifndef GPUCA_DISPLAY_OPENGL_CORE
304 XFontStruct* font_info = nullptr;
305 if (backend()->backendType() == GPUDisplayBackend::TYPE_OPENGL) {
306 // Prepare fonts
307 mFontBase = glGenLists(256);
308 if (!glIsList(mFontBase)) {
309 GPUError("Out of display lists.");
310 return (-1);
311 }
312 const char* f = "fixed";
313 font_info = XLoadQueryFont(mXDisplay, f);
314 if (!font_info) {
315 GPUError("XLoadQueryFont failed.");
316 return (-1);
317 } else {
318 int32_t first = font_info->min_char_or_byte2;
319 int32_t last = font_info->max_char_or_byte2;
320 glXUseXFont(font_info->fid, first, last - first + 1, mFontBase + first);
321 }
322 }
323 mCanDrawText = 1;
324 if (drawTextFontSize() == 0) {
325 drawTextFontSize() = 12;
326 }
327#endif
328
329 if (mBackend->ExtInit()) {
330 fprintf(stderr, "Error initializing backend\n");
331 return (-1);
332 }
333
334 XMapWindow(mXDisplay, mWindow);
335 XFlush(mXDisplay);
336
337 // Enable vsync
338 if (backend()->backendType() == GPUDisplayBackend::TYPE_OPENGL && vsync_supported) {
339 mGlXSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddressARB((const GLubyte*)"glXSwapIntervalEXT");
340 if (mGlXSwapIntervalEXT == nullptr) {
341 GPUError("Cannot enable vsync");
342 return (-1);
343 }
344 mGlXSwapIntervalEXT(mXDisplay, glXGetCurrentDrawable(), vsyncEnabled());
345 }
346
347 if (InitDisplay()) {
348 return (1);
349 }
350
351 {
352 std::lock_guard lock(mExitStateMutex);
353 mDisplayRunning = true;
354 }
355
356 while (1) {
357 do {
358 if (mDisplayControl == 2) {
359 break;
360 }
361 if (!XPending(mXDisplay)) {
362 event.type = Expose;
363 } else {
364 XNextEvent(mXDisplay, &event);
365 }
366 switch (event.type) {
367 case ButtonPress: {
368 if (event.xbutton.button == 4) {
369 mMouseWheel += 100;
370 } else if (event.xbutton.button == 5) {
371 mMouseWheel -= 100;
372 } else {
373 if (event.xbutton.button == 1) {
374 mMouseDn = true;
375 } else if (event.xbutton.button == 2) {
376 mMouseDnM = true;
377 } else {
378 mMouseDnR = true;
379 }
380 mMouseDnX = event.xmotion.x;
381 mMouseDnY = event.xmotion.y;
382 }
383 break;
384 }
385
386 case ButtonRelease: {
387 if (event.xbutton.button != 4 && event.xbutton.button != 5) {
388 if (event.xbutton.button == 1) {
389 mMouseDn = false;
390 } else if (event.xbutton.button == 2) {
391 mMouseDnM = false;
392 } else {
393 mMouseDnR = false;
394 }
395 }
396 break;
397 }
398
399 case KeyPress: {
400 int32_t handleKey = 0, keyPress = 0;
401 GetKey(event, handleKey, keyPress);
402 mKeysShift[keyPress] = mKeys[KEY_SHIFT];
403 mKeys[keyPress] = true;
404 HandleKey(handleKey);
405 break;
406 }
407
408 case KeyRelease: {
409 int32_t handleKey = 0, keyPress = 0;
410 GetKey(event, handleKey, keyPress);
411 mKeys[keyPress] = false;
412 mKeysShift[keyPress] = false;
413 break;
414 }
415
416 case MotionNotify: {
417 mMouseMvX = event.xmotion.x;
418 mMouseMvY = event.xmotion.y;
419 break;
420 }
421
422 case FocusOut: {
423 focusLost();
424 break;
425 }
426
427 case PropertyNotify: {
428 if (event.xproperty.atom == XInternAtom(mXDisplay, "_NET_WM_STATE", False)) {
429 updateWindowState();
430 }
431 break;
432 }
433
434 case Expose: {
435 break;
436 }
437
438 case ConfigureNotify: {
439 ResizeScene(event.xconfigure.width, event.xconfigure.height);
440 break;
441 }
442
443 case ClientMessage: {
444 if (event.xclient.message_type == XInternAtom(mXDisplay, "_NET_WM_STATE", False)) {
445 XFlush(mXDisplay);
446 } else {
447 mDisplayControl = 2;
448 }
449 break;
450 }
451 }
452 } while (XPending(mXDisplay)); // Loop to compress events
453 if (mDisplayControl == 2) {
454 break;
455 }
456
458 DrawGLScene();
459 if (backend()->backendType() == GPUDisplayBackend::TYPE_OPENGL) {
460 glXSwapBuffers(mXDisplay, mWindow);
461 }
463 }
464
465#ifndef GPUCA_DISPLAY_OPENGL_CORE
466 if (backend()->backendType() == GPUDisplayBackend::TYPE_OPENGL) {
467 glDeleteLists(mFontBase, 256);
468 XUnloadFont(mXDisplay, font_info->fid);
469 }
470#endif
471 ExitDisplay();
472 if (backend()->backendType() == GPUDisplayBackend::TYPE_OPENGL) {
473 glXDestroyContext(mXDisplay, glxContext);
474 }
475 XFree(visualInfo);
476 XDestroyWindow(mXDisplay, mWindow);
477 XCloseDisplay(mXDisplay);
478
479 {
480 std::lock_guard lock(mExitStateMutex);
481 mDisplayRunning = false;
482 }
483
484 return (0);
485}
486
487void GPUDisplayFrontendX11::updateWindowState()
488{
489 Atom type;
490 int32_t format;
491 unsigned long nItems, bytesAfter;
492 unsigned char* data = nullptr;
493 if (XGetWindowProperty(mXDisplay, mWindow, XInternAtom(mXDisplay, "_NET_WM_STATE", False), 0, 1024, False, XA_ATOM, &type, &format, &nItems, &bytesAfter, &data) != Success || data == nullptr) {
494 return;
495 }
496 const Atom fullScreen = XInternAtom(mXDisplay, "_NET_WM_STATE_FULLSCREEN", False), maxHorz = XInternAtom(mXDisplay, "_NET_WM_STATE_MAXIMIZED_HORZ", False), maxVert = XInternAtom(mXDisplay, "_NET_WM_STATE_MAXIMIZED_VERT", False);
497 bool isFullScreen = false, isMaxHorz = false, isMaxVert = false;
498 for (unsigned long i = 0; i < nItems; i++) {
499 const Atom a = ((Atom*)data)[i];
500 isFullScreen |= a == fullScreen;
501 isMaxHorz |= a == maxHorz;
502 isMaxVert |= a == maxVert;
503 }
504 XFree(data);
505 setWindowState(isFullScreen, isMaxHorz && isMaxVert);
506}
507
509{
510 XEvent xev;
511 memset(&xev, 0, sizeof(xev));
512 xev.type = ClientMessage;
513 xev.xclient.window = mWindow;
514 xev.xclient.message_type = XInternAtom(mXDisplay, "_NET_WM_STATE", False);
515 xev.xclient.format = 32;
516 xev.xclient.data.l[0] = 2; // _NET_WM_STATE_TOGGLE
517 xev.xclient.data.l[1] = XInternAtom(mXDisplay, "_NET_WM_STATE_FULLSCREEN", True);
518 xev.xclient.data.l[2] = 0;
519 XSendEvent(mXDisplay, DefaultRootWindow(mXDisplay), False, SubstructureNotifyMask, &xev);
520}
521
523{
524 XEvent xev;
525 memset(&xev, 0, sizeof(xev));
526 xev.type = ClientMessage;
527 xev.xclient.window = mWindow;
528 xev.xclient.message_type = XInternAtom(mXDisplay, "_NET_WM_STATE", False);
529 xev.xclient.format = 32;
530 xev.xclient.data.l[0] = set ? 1 : 0; // _NET_WM_STATE_ADD / _NET_WM_STATE_REMOVE
531 xev.xclient.data.l[1] = XInternAtom(mXDisplay, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
532 xev.xclient.data.l[2] = XInternAtom(mXDisplay, "_NET_WM_STATE_MAXIMIZED_VERT", False);
533 XSendEvent(mXDisplay, DefaultRootWindow(mXDisplay), False, SubstructureNotifyMask, &xev);
534}
535
537{
538 if (backend()->backendType() == GPUDisplayBackend::TYPE_OPENGL && vsync_supported) {
539 mGlXSwapIntervalEXT(mXDisplay, glXGetCurrentDrawable(), (int32_t)enable);
540 }
541}
542
544{
545 Window root_return;
546 int32_t x_return, y_return;
547 uint32_t width_return, height_return, border_width_return, depth_return;
548 if (XGetGeometry(mXDisplay, mWindow, &root_return, &x_return, &y_return, &width_return, &height_return, &border_width_return, &depth_return) == 0) {
549 throw std::runtime_error("Cannot query X11 window geometry");
550 }
551 width = width_return;
552 height = height_return;
553}
554
556{
557#ifdef GPUCA_BUILD_EVENT_DISPLAY_VULKAN
558 VkXlibSurfaceCreateInfoKHR info{};
559 info.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
560 info.flags = 0;
561 info.dpy = mXDisplay;
562 info.window = mWindow;
563 return vkCreateXlibSurfaceKHR(*(VkInstance*)instance, &info, nullptr, (VkSurfaceKHR*)surface) != VK_SUCCESS;
564#else
565 return 1;
566#endif
567}
568
570{
571 static const char* exts[] = {"VK_KHR_surface", "VK_KHR_xlib_surface"};
572 p = exts;
573 return 2;
574}
int32_t i
GLXContext(* glXCreateContextAttribsARBProc)(Display *, GLXFBConfig, GLXContext, Bool, const int32_t *)
const Acts::Surface * surface
StringRef key
void getSize(int32_t &width, int32_t &height) override
int32_t getVulkanSurface(void *instance, void *surface) override
void OpenGLPrint(const char *s, float x, float y, float r, float g, float b, float a, bool fromBotton=true) override
uint32_t getReqVulkanExtensions(const char **&p) override
void SetVSync(bool enable) override
static constexpr int32_t KEY_F9
static constexpr int32_t KEY_F2
static constexpr int32_t KEY_ALT
static constexpr int32_t KEY_F12
static constexpr int32_t KEY_F7
static constexpr int32_t KEY_END
static constexpr int32_t KEY_PAGEDOWN
static constexpr int32_t KEY_RALT
static constexpr int32_t KEY_F10
static constexpr int32_t KEY_F4
static constexpr int32_t KEY_LEFT
static constexpr int32_t KEY_ENTER
static constexpr int32_t KEY_F6
static constexpr int32_t KEY_CTRL
static constexpr int32_t KEY_F1
void ResizeScene(int32_t width, int32_t height)
static constexpr const char * DISPLAY_WINDOW_NAME
static constexpr int32_t INIT_WIDTH
static constexpr int32_t GL_MIN_VERSION_MAJOR
static constexpr int32_t KEY_SHIFT
static constexpr int32_t KEY_F3
static constexpr int32_t KEY_INSERT
static constexpr int32_t KEY_F11
void setWindowState(bool fullScreen, bool maximized)
static constexpr int32_t KEY_SPACE
static constexpr int32_t KEY_F5
static constexpr int32_t KEY_PAGEUP
static constexpr int32_t KEY_HOME
static constexpr int32_t GL_MIN_VERSION_MINOR
int32_t InitDisplay(bool initFailure=false)
static constexpr int32_t KEY_UP
static constexpr int32_t KEY_DOWN
static constexpr int32_t KEY_F8
static constexpr int32_t MIN_WIDTH
static constexpr int32_t INIT_HEIGHT
static constexpr int32_t KEY_RIGHT
static constexpr int32_t KEY_RCTRL
static constexpr int32_t MIN_HEIGHT
static constexpr int32_t KEY_ESCAPE
struct _cl_event * event
Definition glcorearb.h:2982
#define GL_TRUE
Definition glcorearb.h:95
GLint GLenum GLint x
Definition glcorearb.h:403
khronos_uint8_t GLubyte
Definition glcorearb.h:90
GLint GLsizei GLsizei height
Definition glcorearb.h:270
GLint first
Definition glcorearb.h:399
GLint GLsizei width
Definition glcorearb.h:270
GLdouble f
Definition glcorearb.h:310
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLint y
Definition glcorearb.h:270
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLint GLint GLsizei GLint GLenum GLenum type
Definition glcorearb.h:275
#define GL_UNSIGNED_BYTE
Definition glcorearb.h:206
GLboolean * data
Definition glcorearb.h:298
GLboolean GLboolean g
Definition glcorearb.h:1233
GLboolean enable
Definition glcorearb.h:3991
GLboolean r
Definition glcorearb.h:1233
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
GLint GLint GLsizei GLint GLenum format
Definition glcorearb.h:275
uint8_t itsSharedClusterMap uint8_t
Marks an empty item in the context.