[x11_egl] setup
commit
21888aa33e
|
|
@ -0,0 +1 @@
|
|||
build/*
|
||||
|
|
@ -0,0 +1,325 @@
|
|||
#if 0
|
||||
mkdir -p build
|
||||
clang -o build/demo -g x11_egl.c -lX11 -lEGL
|
||||
exit 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Reading From:
|
||||
** (1) xlib manual https://tronche.com/gui/x/xlib/
|
||||
** (2) EGL spec https://registry.khronos.org/EGL/sdk/docs/man/
|
||||
*/
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
#include <GL/glcorearb.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
// X(N:name,R:return,P:params)
|
||||
#define GL_FUNCS_XLIST(X)\
|
||||
X(glDrawBuffer, void, (GLenum buf)) \
|
||||
X(glViewport, void, (GLint x, GLint y, GLsizei w, GLsizei h)) \
|
||||
X(glClear, void, (GLbitfield mask)) \
|
||||
X(glClearColor, void, (GLfloat r, GLfloat g, GLfloat b, GLfloat a))
|
||||
|
||||
|
||||
#define X(N,R,P) R (*N)P = 0;
|
||||
GL_FUNCS_XLIST(X)
|
||||
#undef X
|
||||
|
||||
int main(int argc, char **argv){
|
||||
/*~ NOTE:
|
||||
**~ initialize X11 and EGL API's
|
||||
*/
|
||||
|
||||
/* (1) /display/opening.html
|
||||
** " The XOpenDisplay() function returns a Display structure that serves
|
||||
** as the connection to the X server and that contains all the
|
||||
** information about that X server. "
|
||||
*/
|
||||
Display *display = XOpenDisplay(0);
|
||||
if (display == 0){
|
||||
printf("XOpenDisplay failed\n");
|
||||
}
|
||||
|
||||
/* (2) eglGetPlatformDisplay
|
||||
** " eglGetPlatformDisplay obtains an EGL display connection "
|
||||
*/
|
||||
EGLDisplay *egl_display = 0;
|
||||
if (display != 0){
|
||||
egl_display = eglGetPlatformDisplay(EGL_PLATFORM_X11_KHR, display, 0);
|
||||
if (egl_display == 0){
|
||||
printf("eglGetPlatformDisplay failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* (2) eglInitialize
|
||||
** " initializes* the EGL display connection obtained with eglGetDisplay "
|
||||
*/
|
||||
int egl_init_success = 0;
|
||||
EGLint major = 0, minor = 0;
|
||||
if (egl_display != 0){
|
||||
egl_init_success = eglInitialize(egl_display, &major, &minor);
|
||||
if (!egl_init_success){
|
||||
printf("eglInitialize failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
// print version
|
||||
if (egl_init_success){
|
||||
printf("EGL version %d.%d\n", major, minor);
|
||||
if (major < 1 || (major == 1 && minor < 5)){
|
||||
printf("version 1.5 or higher\n");
|
||||
egl_init_success = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* (2) eglBindAPI
|
||||
** " defines the current rendering API for EGL in the thread it is
|
||||
** called from "
|
||||
*/
|
||||
EGLBoolean bind_api_success = 0;
|
||||
if (egl_init_success){
|
||||
bind_api_success = eglBindAPI(EGL_OPENGL_API);
|
||||
}
|
||||
|
||||
/*~ NOTE:
|
||||
**~ Create OpenGL context & link OpenGL procedures
|
||||
*/
|
||||
|
||||
/* (2) eglCreateContext
|
||||
** " creates an EGL rendering context for the current rendering API
|
||||
** (as set with eglBindAPI) and returns a handle to the context "
|
||||
*/
|
||||
EGLContext* context = 0;
|
||||
if (bind_api_success){
|
||||
EGLint attr[] = {
|
||||
EGL_CONTEXT_MAJOR_VERSION, 3,
|
||||
EGL_CONTEXT_MINOR_VERSION, 3,
|
||||
EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
|
||||
EGL_NONE,
|
||||
};
|
||||
context = eglCreateContext(egl_display, EGL_NO_CONFIG_KHR, EGL_NO_CONTEXT, attr);
|
||||
if (context == EGL_NO_CONTEXT){
|
||||
printf("eglCreateContext failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* (2) eglMakeCurrent
|
||||
** " binds context to the current rendering thread "
|
||||
*/
|
||||
EGLBoolean make_current_success = 0;
|
||||
if (context != 0){
|
||||
make_current_success = eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, context);
|
||||
if (!make_current_success){
|
||||
printf("eglMakeCurrent failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* (2) eglGetProcAddress
|
||||
** " returns the address of the client API or EGL function "
|
||||
*/
|
||||
int load_success = 0;
|
||||
if (make_current_success){
|
||||
load_success = 1;
|
||||
#define X(N,R,P) N = (R(*)P)(eglGetProcAddress(#N)); if (N == 0) load_success = 0;
|
||||
GL_FUNCS_XLIST(X)
|
||||
#undef X
|
||||
if (!load_success){
|
||||
printf("GL procedure loading failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* (1) /window-information/XInternAtom.html
|
||||
** " returns the atom identifier associated with the specified
|
||||
** atom_name string "
|
||||
*/
|
||||
Atom atom__WM_DELETE_WINDOW = XInternAtom(display, "WM_DELETE_WINDOW", False);
|
||||
|
||||
/*~ NOTE:
|
||||
**~ Create a window and a surface for it
|
||||
*/
|
||||
|
||||
/* (1) /window/XCreateWindow.html
|
||||
** " The XCreateWindow function creates an unmapped subwindow for a
|
||||
** specified parent window "
|
||||
*/
|
||||
Window window = 0;
|
||||
if (load_success){
|
||||
Window parent = DefaultRootWindow(display);
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int w = 640;
|
||||
int h = 480;
|
||||
int border_width = 0;
|
||||
int depth = CopyFromParent;
|
||||
unsigned int xclass = InputOutput;
|
||||
Visual *visual = CopyFromParent;
|
||||
unsigned long valuemask = CWEventMask;
|
||||
|
||||
XSetWindowAttributes attributes = {0};
|
||||
attributes.event_mask = StructureNotifyMask;
|
||||
|
||||
window = XCreateWindow(display, parent, x, y, w, h, border_width,
|
||||
depth, xclass, visual, valuemask,
|
||||
&attributes);
|
||||
|
||||
if (window == 0){
|
||||
printf("XCreateWindow failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
EGLSurface *surface = EGL_NO_SURFACE;
|
||||
{
|
||||
/* (2) eglChooseConfig
|
||||
** " returns in configs a list of all EGL frame buffer configurations
|
||||
** that match the attributes specified in attrib_list "
|
||||
*/
|
||||
EGLConfig configs[64];
|
||||
EGLint config_cap = sizeof(configs)/sizeof(*configs);
|
||||
EGLint config_count = 0;
|
||||
{
|
||||
EGLint attributes[] = {
|
||||
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
||||
EGL_CONFORMANT, EGL_OPENGL_BIT,
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
|
||||
EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER,
|
||||
EGL_RED_SIZE, 8,
|
||||
EGL_GREEN_SIZE, 8,
|
||||
EGL_BLUE_SIZE, 8,
|
||||
EGL_DEPTH_SIZE, 24,
|
||||
EGL_STENCIL_SIZE, 8,
|
||||
EGL_NONE,
|
||||
};
|
||||
if (!eglChooseConfig(egl_display, attributes, configs, config_cap, &config_count)){
|
||||
printf("eglChooseConfig failed\n");
|
||||
config_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* (2) eglCreatePlatformWindowSurface
|
||||
** " creates an on-screen EGL window surface and returns a handle to it "
|
||||
*/
|
||||
{
|
||||
EGLAttrib attributes[] = {
|
||||
EGL_RENDER_BUFFER, EGL_BACK_BUFFER,
|
||||
EGL_NONE,
|
||||
};
|
||||
for (EGLint i = 0; i < config_count; i += 1){
|
||||
surface = eglCreatePlatformWindowSurface(egl_display, configs[i], &window, attributes);
|
||||
if (surface != EGL_NO_SURFACE){
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (surface == EGL_NO_SURFACE){
|
||||
printf("eglCreatePlatformWindowSurface failed\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* (1) /ICC/client-to-window-manager/XStoreName.html
|
||||
** " assigns the name passed to window_name to the specified window "
|
||||
*/
|
||||
XStoreName(display, window, "Example Window");
|
||||
|
||||
/* (1) /window/XMapWindow.html
|
||||
** " maps the window and all of its subwindows that have had map requests "
|
||||
**~ NOTE: This makes the window visible on the screen.
|
||||
*/
|
||||
XMapWindow(display, window);
|
||||
|
||||
/* (2) eglMakeCurrent */
|
||||
EGLBoolean make_current_success2 = 0;
|
||||
if (surface != EGL_NO_SURFACE){
|
||||
make_current_success2 = eglMakeCurrent(egl_display, surface, surface, context);
|
||||
}
|
||||
|
||||
/* (2) eglSwapInterval
|
||||
** " Specifies the minimum number of video frames that are displayed before
|
||||
** a buffer swap will occur "
|
||||
*/
|
||||
EGLBoolean swap_interval_success = 0;
|
||||
if (make_current_success2){
|
||||
swap_interval_success = eglSwapInterval(egl_display, 1);
|
||||
}
|
||||
|
||||
/*~ NOTE: Main loop */
|
||||
int exit_loop = 0;
|
||||
for (;!exit_loop;){
|
||||
|
||||
/* (1) /event-handling/XPending.html
|
||||
** " returns the number of events that have been received from the X
|
||||
** server but have not been removed from the event queue "
|
||||
**~ NOTE: The docs say this returns the number of events, but in
|
||||
** since that number could grow as we process inputs, so it's more
|
||||
** usually used as a way to check if there is at least one input.
|
||||
*/
|
||||
for (;XPending(display) > 0;){
|
||||
/* (1) /event-handling/manipulating-event-queue/XNextEvent.html
|
||||
** " copies the first event from the event queue into the specified
|
||||
** XEvent structure and then removes it from the queue "
|
||||
*/
|
||||
XEvent event;
|
||||
XNextEvent(display, &event);
|
||||
|
||||
/* (1) /events/structures.html
|
||||
** " The XEvent structure is a union of the individual structures
|
||||
** declared for each event type. Depending on the type, you should
|
||||
** access members of each event by using the XEvent union. "
|
||||
*/
|
||||
switch (event.type){
|
||||
case ClientMessage: {
|
||||
Atom atom = event.xclient.data.l[0];
|
||||
if (atom == atom__WM_DELETE_WINDOW){
|
||||
exit_loop = 1;
|
||||
}
|
||||
}break;
|
||||
}
|
||||
}
|
||||
|
||||
/* (1) /window-information/XGetWindowAttributes.html
|
||||
** " returns the current attributes for the specified window "
|
||||
*/
|
||||
XWindowAttributes window_attr = {0};
|
||||
if (!XGetWindowAttributes(display, window, &window_attr)){
|
||||
printf("XGetWindowAttributes failed\n");
|
||||
}
|
||||
|
||||
if (window_attr.width > 0 && window_attr.height > 0){
|
||||
glDrawBuffer(GL_BACK);
|
||||
glViewport(0, 0, window_attr.width, window_attr.height);
|
||||
glClearColor(0.90f, 0.15f, 0.40f, 1.f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
/* (2) eglSwapBuffers
|
||||
** " back-buffered window surface, then the color buffer is copied
|
||||
** (posted) to the native window associated with that surface "
|
||||
*/
|
||||
EGLBoolean swap_success = eglSwapBuffers(egl_display, surface);
|
||||
if (!swap_success){
|
||||
printf("eglSwapBuffers failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*~ NOTE: Shutdown */
|
||||
|
||||
/* (1) /window/XDestroyWindow.html
|
||||
** " destroys the specified window as well as all of its subwindows "
|
||||
*/
|
||||
if (display != 0 && window != 0){
|
||||
XDestroyWindow(display, window);
|
||||
}
|
||||
|
||||
/* (1) /display/closing.html
|
||||
** " To close a display or disconnect from the X server, use
|
||||
** XCloseDisplay(). "
|
||||
*/
|
||||
if (display != 0){
|
||||
XCloseDisplay(display);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
Loading…
Reference in New Issue