From b3401b13ad7a02f2b753af6ae9c6b3e8d74de1ee Mon Sep 17 00:00:00 2001 From: Phireh Date: Sun, 17 Nov 2024 17:19:46 +0100 Subject: [PATCH] Initial commit --- .gitignore | 1 + Makefile | 4 ++ gitignore | 0 notes.org | 6 ++ wayland.c | 207 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 218 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 gitignore create mode 100644 notes.org create mode 100644 wayland.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0cf8f40 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +wayland diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..da91960 --- /dev/null +++ b/Makefile @@ -0,0 +1,4 @@ +CFLAGS=-Wall -Wextra -Og -ggdb3 +LIBS=-lwayland-client -lwayland-egl -lEGL -lOpenGL +wayland: wayland.c + gcc $(CFLAGS) $(LIBS) wayland.c -o wayland diff --git a/gitignore b/gitignore new file mode 100644 index 0000000..e69de29 diff --git a/notes.org b/notes.org new file mode 100644 index 0000000..55f2ecd --- /dev/null +++ b/notes.org @@ -0,0 +1,6 @@ +There are four ways (it would seem) to render pixels to a wayland surface: + +1. *wl_shm* using shared memory, aka directly telling wayland the color of each pixel to draw using software rendering. +2. Using a *wl_shell_interface* to create a *wl_shell_surface*, then use the *wl_egl_* functions to draw pixels. +3. Using a *wl_surface* directly? Apparently not all compositors implement the *wl_shell_interface* protocol, and checking the source code from SDL's repository they do not even look for it. +4. Using extensions like *wl_egl_window_create* to hook a wayland window to a OGL rendering context. This link seems to agree with me: https://www.gfxstrand.net/faith/projects/wayland/wayland-android/ diff --git a/wayland.c b/wayland.c new file mode 100644 index 0000000..7dede93 --- /dev/null +++ b/wayland.c @@ -0,0 +1,207 @@ +#include +#include +#include +#include +#include +#include +#include + +struct wl_compositor *compositor = NULL; +struct wl_registry *registry = NULL; +struct wl_shell *shell = NULL; +struct wl_surface *surface = NULL; +struct wl_shm *shm = NULL; +EGLBoolean errcode = 0; + +void registry_handle_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) +{ + printf("Wayland interface: '%s', version: %d, name: %d\n", + interface, version, name); + if (!strcmp(interface, wl_compositor_interface.name)) + { + fprintf(stdout, "Registering compositor...\n"); + compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 1); + } + + if (!strcmp(interface, wl_shell_interface.name)) + { + fprintf(stdout, "Getting shell interface...\n"); + shell = wl_registry_bind(registry, name, &wl_shell_interface, 1); + } +} + + +void registry_handle_global_remove(void *data, struct wl_registry *registry, + uint32_t name) +{ + // This space deliberately left blank +} + +static const struct wl_registry_listener +registry_listener = { + .global = registry_handle_global, + .global_remove = registry_handle_global_remove, +}; + +int main() +{ + fprintf(stdout, "Starting platform layer...\n"); + struct wl_display *display = wl_display_connect(NULL); + if (!display) + { + fprintf(stdout, "Cannot retrieve wayland display!\n"); + } + + registry = wl_display_get_registry(display); + if (!registry) + { + fprintf(stderr, "Cannot retrieve wayland registry!\n"); + } + + fprintf(stdout, "Linking registry listener...\n"); + wl_registry_add_listener(registry, ®istry_listener, NULL); + + wl_display_dispatch(display); + wl_display_roundtrip(display); + + surface = wl_compositor_create_surface(compositor); + if (!surface) + { + fprintf(stderr, "Can't create surface!\n"); + } + + /* WL EGL initialization */ + struct wl_egl_window *window = wl_egl_window_create(surface, 480, 460); + + EGLDisplay egl_display = eglGetDisplay((EGLNativeDisplayType) display); + if (egl_display == EGL_NO_DISPLAY) + { + fprintf(stderr, "Could not retrieve EGL display from wayland display\n"); + } + errcode = eglInitialize(egl_display, NULL, NULL); + switch (errcode) + { + case EGL_FALSE: + case EGL_BAD_DISPLAY: + case EGL_NOT_INITIALIZED: + fprintf(stderr, "Could not initialize EGL display\n"); + break; + case EGL_TRUE: + ; + break; + } + + int config_count; + errcode = eglGetConfigs(egl_display, NULL, 0, &config_count); + switch (errcode) + { + case EGL_FALSE: + case EGL_BAD_DISPLAY: + case EGL_NOT_INITIALIZED: + case EGL_BAD_PARAMETER: + fprintf(stderr, "Could not retrieve EGL config number\n"); + break; + case EGL_TRUE: + ; + break; + } + + EGLConfig *configs = calloc(config_count, sizeof(EGLConfig)); + + EGLint attr_list[] = { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_NONE + }; + int chosen_config_count; + + errcode = eglChooseConfig(egl_display, attr_list, configs, config_count * sizeof(EGLConfig), &chosen_config_count); + switch (errcode) + { + case EGL_FALSE: + case EGL_BAD_DISPLAY: + case EGL_NOT_INITIALIZED: + case EGL_BAD_PARAMETER: + fprintf(stderr, "Could not choose EGL config parameters\n"); + break; + case EGL_TRUE: + ; + break; + } + + EGLSurface egl_surface = eglCreateWindowSurface(egl_display, configs[0], (EGLNativeWindowType)window, NULL); + + switch ((intptr_t)egl_surface) + { + case (intptr_t)EGL_NO_SURFACE: + case EGL_BAD_DISPLAY: + case EGL_NOT_INITIALIZED: + case EGL_BAD_CONFIG: + case EGL_BAD_NATIVE_WINDOW: + case EGL_BAD_ATTRIBUTE: + case EGL_BAD_ALLOC: + case EGL_BAD_MATCH: + fprintf(stderr, "Could not choose EGL config parameters\n"); + break; + case EGL_TRUE: + ; + break; + } + + static const EGLint context_attribs[] = { + EGL_CONTEXT_MAJOR_VERSION, 3, + EGL_CONTEXT_MINOR_VERSION, 2, + EGL_CONTEXT_OPENGL_DEBUG, EGL_TRUE, + EGL_NONE + }; + + /* Change from OpenGL ES to regular OpenGL */ + errcode = eglBindAPI(EGL_OPENGL_API); + switch (errcode) + { + case EGL_FALSE: + case EGL_BAD_PARAMETER: + fprintf(stderr, "Could not bind OpenGL API to EGL\n"); + break; + } + + EGLContext egl_context = eglCreateContext(egl_display, configs[0], EGL_NO_CONTEXT, context_attribs); + + errcode = eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context); + switch (errcode) + { + case EGL_BAD_CONTEXT: + case EGL_BAD_SURFACE: + case EGL_BAD_MATCH: + case EGL_BAD_NATIVE_WINDOW: + case EGL_BAD_CURRENT_SURFACE: + case EGL_BAD_ALLOC: + case EGL_CONTEXT_LOST: + case EGL_NOT_INITIALIZED: + case EGL_BAD_DISPLAY: + fprintf(stderr, "Could not make EGL context current\n"); + break; + } + + struct wl_region *region = wl_compositor_create_region(compositor); + wl_region_add(region, 0, 0, 480, 360); + wl_surface_set_opaque_region(surface, region); + + // Main event loop + while (1) + { + //wl_display_dispatch_pending(display); + fprintf(stdout, "Dispatching event...\n"); + glClearColor(0.5, 0.3, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + glFlush(); + eglSwapBuffers(egl_display, egl_surface); + } + + wl_display_disconnect(display); + return 0; +}