Skip to content

Instantly share code, notes, and snippets.

@Miouyouyou
Created December 15, 2016 07:55
Show Gist options
  • Save Miouyouyou/ca15af1c7f2696f66b0e013058f110b4 to your computer and use it in GitHub Desktop.
Save Miouyouyou/ca15af1c7f2696f66b0e013058f110b4 to your computer and use it in GitHub Desktop.
A very ugly Wayland EGL OpenGL example
// gcc -o test init_window.c -I. -lwayland-client -lwayland-server -lwayland-client-protocol -lwayland-egl -lEGL -lGLESv2
#include <wayland-client.h>
#include <wayland-server.h>
#include <wayland-client-protocol.h>
#include <wayland-egl.h> // Wayland EGL MUST be included before EGL headers
#include "init_window.h"
#include "log.h"
#include <string.h>
#include <stdlib.h>
#include <GLES2/gl2.h>
struct wl_compositor *compositor = NULL;
struct wl_surface *surface;
struct wl_egl_window *egl_window;
struct wl_region *region;
struct wl_shell *shell;
struct wl_shell_surface *shell_surface;
struct _escontext ESContext = {
.native_display = NULL,
.window_width = 0,
.window_height = 0,
.native_window = 0,
.display = NULL,
.context = NULL,
.surface = NULL
};
#define TRUE 1
#define FALSE 0
#define WINDOW_WIDTH 1280
#define WINDOW_HEIGHT 720
void CreateNativeWindow(char *title, int width, int height) {
region = wl_compositor_create_region(compositor);
wl_region_add(region, 0, 0, width, height);
wl_surface_set_opaque_region(surface, region);
struct wl_egl_window *egl_window =
wl_egl_window_create(surface, width, height);
if (egl_window == EGL_NO_SURFACE) {
LOG("No window !?\n");
exit(1);
}
else LOG("Window created !\n");
ESContext.window_width = width;
ESContext.window_height = height;
ESContext.native_window = egl_window;
}
EGLBoolean CreateEGLContext ()
{
EGLint numConfigs;
EGLint majorVersion;
EGLint minorVersion;
EGLContext context;
EGLSurface surface;
EGLConfig config;
EGLint fbAttribs[] =
{
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_NONE
};
EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE, EGL_NONE };
EGLDisplay display = eglGetDisplay( ESContext.native_display );
if ( display == EGL_NO_DISPLAY )
{
LOG("No EGL Display...\n");
return EGL_FALSE;
}
// Initialize EGL
if ( !eglInitialize(display, &majorVersion, &minorVersion) )
{
LOG("No Initialisation...\n");
return EGL_FALSE;
}
// Get configs
if ( (eglGetConfigs(display, NULL, 0, &numConfigs) != EGL_TRUE) || (numConfigs == 0))
{
LOG("No configuration...\n");
return EGL_FALSE;
}
// Choose config
if ( (eglChooseConfig(display, fbAttribs, &config, 1, &numConfigs) != EGL_TRUE) || (numConfigs != 1))
{
LOG("No configuration...\n");
return EGL_FALSE;
}
// Create a surface
surface = eglCreateWindowSurface(display, config, ESContext.native_window, NULL);
if ( surface == EGL_NO_SURFACE )
{
LOG("No surface...\n");
return EGL_FALSE;
}
// Create a GL context
context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs );
if ( context == EGL_NO_CONTEXT )
{
LOG("No context...\n");
return EGL_FALSE;
}
// Make the context current
if ( !eglMakeCurrent(display, surface, surface, context) )
{
LOG("Could not make the current window current !\n");
return EGL_FALSE;
}
ESContext.display = display;
ESContext.surface = surface;
ESContext.context = context;
return EGL_TRUE;
}
void shell_surface_ping
(void *data, struct wl_shell_surface *shell_surface, uint32_t serial) {
wl_shell_surface_pong(shell_surface, serial);
}
void shell_surface_configure
(void *data, struct wl_shell_surface *shell_surface, uint32_t edges,
int32_t width, int32_t height) {
struct window *window = data;
wl_egl_window_resize(ESContext.native_window, width, height, 0, 0);
}
void shell_surface_popup_done(void *data, struct wl_shell_surface *shell_surface) {
}
static struct wl_shell_surface_listener shell_surface_listener = {
&shell_surface_ping,
&shell_surface_configure,
&shell_surface_popup_done
};
EGLBoolean CreateWindowWithEGLContext(char *title, int width, int height) {
CreateNativeWindow(title, width, height);
return CreateEGLContext();
}
void draw() {
glClearColor(0.5, 0.3, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
}
unsigned long last_click = 0;
void RefreshWindow() { eglSwapBuffers(ESContext.display, ESContext.surface); }
static void global_registry_handler
(void *data, struct wl_registry *registry, uint32_t id,
const char *interface, uint32_t version) {
LOG("Got a registry event for %s id %d\n", interface, id);
if (strcmp(interface, "wl_compositor") == 0)
compositor =
wl_registry_bind(registry, id, &wl_compositor_interface, 1);
else if (strcmp(interface, "wl_shell") == 0)
shell = wl_registry_bind(registry, id, &wl_shell_interface, 1);
}
static void global_registry_remover
(void *data, struct wl_registry *registry, uint32_t id) {
LOG("Got a registry losing event for %d\n", id);
}
const struct wl_registry_listener listener = {
global_registry_handler,
global_registry_remover
};
static void
get_server_references() {
struct wl_display * display = wl_display_connect(NULL);
if (display == NULL) {
LOG("Can't connect to wayland display !?\n");
exit(1);
}
LOG("Got a display !");
struct wl_registry *wl_registry =
wl_display_get_registry(display);
wl_registry_add_listener(wl_registry, &listener, NULL);
// This call the attached listener global_registry_handler
wl_display_dispatch(display);
wl_display_roundtrip(display);
// If at this point, global_registry_handler didn't set the
// compositor, nor the shell, bailout !
if (compositor == NULL || shell == NULL) {
LOG("No compositor !? No Shell !! There's NOTHING in here !\n");
exit(1);
}
else {
LOG("Okay, we got a compositor and a shell... That's something !\n");
ESContext.native_display = display;
}
}
void destroy_window() {
eglDestroySurface(ESContext.display, ESContext.surface);
wl_egl_window_destroy(ESContext.native_window);
wl_shell_surface_destroy(shell_surface);
wl_surface_destroy(surface);
eglDestroyContext(ESContext.display, ESContext.context);
}
int main() {
get_server_references();
surface = wl_compositor_create_surface(compositor);
if (surface == NULL) {
LOG("No Compositor surface ! Yay....\n");
exit(1);
}
else LOG("Got a compositor surface !\n");
shell_surface = wl_shell_get_shell_surface(shell, surface);
wl_shell_surface_set_toplevel(shell_surface);
CreateWindowWithEGLContext("Nya", 1280, 720);
while (1) {
wl_display_dispatch_pending(ESContext.native_display);
draw();
RefreshWindow();
}
wl_display_disconnect(ESContext.native_display);
LOG("Display disconnected !\n");
exit(0);
}
#ifndef INIT_WINDOW_INCLUDED
#define INIT_WINDOW_INCLUDED 1
#include <stdint.h>
#include <EGL/egl.h>
#include <EGL/eglplatform.h>
struct _escontext
{
/// Native System informations
EGLNativeDisplayType native_display;
EGLNativeWindowType native_window;
uint16_t window_width, window_height;
/// EGL display
EGLDisplay display;
/// EGL context
EGLContext context;
/// EGL surface
EGLSurface surface;
};
void CreateNativeWindow(char* title, int width, int height);
EGLBoolean CreateEGLContext();
EGLBoolean CreateWindowWithEGLContext(char *title, int width, int height);
void RefreshWindow();
#endif
#ifndef MYY_LOG_H
#define MYY_LOG_H 1
#include <string.h>
#if defined(DEBUG)
#if defined(__ANDROID__)
#include <android/log.h>
#define LOG(...) ((void)__android_log_print(ANDROID_LOG_WARN, "native-insanity", __VA_ARGS__))
#define LOG_ERRNO(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "native-insanity", "Error : %s\n", strerror(errno))); ((void)__android_log_print(ANDROID_LOG_ERROR, "native-insanity", __VA_ARGS__)
#else
#include <stdio.h>
#define LOG(...) fprintf(stderr, __VA_ARGS__)
#define LOG_ERRNO(...) fprintf(stderr, "Error : %s\n", strerror(errno)); fprintf(stderr, __VA_ARGS__)
#endif
#else // DEBUG
#define LOG(...)
#define LOG_ERRNO(...)
#endif // DEBUG
#endif
@md-sami
Copy link

md-sami commented Nov 7, 2023

Thanks for the code.
how to compile this on ubuntu 22.04? I got below error when I run the following command.

gcc -o test init_window.c xdg-shell-client-protocol.c -I. -lwayland-client -lwayland-server -lwayland-client-protocol -lwayland-egl -lEGL -lGLESv2 

/usr/bin/ld: cannot find -lwayland-client-protocol: No such file or directory

collect2: error: ld returned 1 exit status

I tried installing sudo apt-get install libwayland-dev but that didn't help

@rmader
Copy link

rmader commented Nov 7, 2023

I tried installing sudo apt-get install libwayland-dev but that didn't help

Probably you're missing wayland-protocols (https://packages.ubuntu.com/jammy/wayland-protocols)?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment