Skip to content

Instantly share code, notes, and snippets.

@sahib
Last active July 5, 2019 07:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sahib/320c2fdfce983ffaf2a931940bd68318 to your computer and use it in GitHub Desktop.
Save sahib/320c2fdfce983ffaf2a931940bd68318 to your computer and use it in GitHub Desktop.
cairo-pango-gles2 bug report (start reading surface.c -> main; the headers are from wayland weston and probably not relevant)
all:
gcc surface.c -o surface ${CFLAGS} ${LDFLAGS} $(shell pkg-config --libs --cflags cairo wayland-client wayland-server wayland-egl pango pangocairo) -lEGL -Wall -Wextra
/*
* Copyright © 2015 Collabora, Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef WESTON_PLATFORM_H
#define WESTON_PLATFORM_H
#include <stdbool.h>
#include <string.h>
#ifdef ENABLE_EGL
#include <wayland-egl.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include "weston-egl-ext.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifdef ENABLE_EGL
static bool
weston_check_egl_extension(const char *extensions, const char *extension)
{
size_t extlen = strlen(extension);
const char *end = extensions + strlen(extensions);
while (extensions < end) {
size_t n = 0;
/* Skip whitespaces, if any */
if (*extensions == ' ') {
extensions++;
continue;
}
n = strcspn(extensions, " ");
/* Compare strings */
if (n == extlen && strncmp(extension, extensions, n) == 0)
return true; /* Found */
extensions += n;
}
/* Not found */
return false;
}
static inline void *
weston_platform_get_egl_proc_address(const char *address)
{
const char *extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
if (extensions &&
(weston_check_egl_extension(extensions, "EGL_EXT_platform_wayland") ||
weston_check_egl_extension(extensions, "EGL_KHR_platform_wayland"))) {
return (void *) eglGetProcAddress(address);
}
return NULL;
}
static inline EGLDisplay
weston_platform_get_egl_display(EGLenum platform, void *native_display,
const EGLint *attrib_list)
{
static PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display = NULL;
if (!get_platform_display) {
get_platform_display = (PFNEGLGETPLATFORMDISPLAYEXTPROC)
weston_platform_get_egl_proc_address(
"eglGetPlatformDisplayEXT");
}
if (get_platform_display)
return get_platform_display(platform,
native_display, attrib_list);
return eglGetDisplay((EGLNativeDisplayType) native_display);
}
static inline EGLSurface
weston_platform_create_egl_surface(EGLDisplay dpy, EGLConfig config,
void *native_window,
const EGLint *attrib_list)
{
static PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC
create_platform_window = NULL;
if (!create_platform_window) {
create_platform_window = (PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC)
weston_platform_get_egl_proc_address(
"eglCreatePlatformWindowSurfaceEXT");
}
if (create_platform_window)
return create_platform_window(dpy, config,
native_window,
attrib_list);
return eglCreateWindowSurface(dpy, config,
(EGLNativeWindowType) native_window,
attrib_list);
}
static inline EGLBoolean
weston_platform_destroy_egl_surface(EGLDisplay display,
EGLSurface surface)
{
return eglDestroySurface(display, surface);
}
#else /* ENABLE_EGL */
static inline void *
weston_platform_get_egl_display(void *platform, void *native_display,
const int *attrib_list)
{
return NULL;
}
static inline void *
weston_platform_create_egl_surface(void *dpy, void *config,
void *native_window,
const int *attrib_list)
{
return NULL;
}
static inline unsigned int
weston_platform_destroy_egl_surface(void *display,
void *surface)
{
return 1;
}
#endif /* ENABLE_EGL */
#ifdef __cplusplus
}
#endif
#endif /* WESTON_PLATFORM_H */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <stdbool.h>
#include <cairo/cairo.h>
#include <time.h>
#include <wayland-client.h>
#include <wayland-server.h>
#include <wayland-client-protocol.h>
#include <wayland-egl.h>
#include <EGL/egl.h>
#ifndef USE_PANGO
# define USE_PANGO 0
#endif
#include <cairo/cairo-gl.h>
#if USE_PANGO
#include <pango/pango.h>
#include <pango/pangocairo.h>
#endif
// Define needed to make platform.h actually define weston_platform_create_egl_surface()
#define ENABLE_EGL 1
#include "platform.h"
typedef struct Surface {
struct wl_display *display;
struct wl_compositor *compositor;
struct wl_surface *surface;
struct wl_egl_window *egl_window;
struct wl_region *region;
struct wl_shell *shell;
struct wl_shell_surface *shell_surface;
EGLDisplay egl_display;
EGLConfig egl_conf;
EGLSurface egl_surface;
EGLContext egl_context;
cairo_surface_t *cairo_surface;
cairo_device_t *cairo_device;
cairo_t *ctx;
} Surface;
static const char *create_window(Surface *srf, uint32_t width, uint32_t height) {
printf("creating window with width=%d and height=%d\n", width, height);
srf->egl_window = wl_egl_window_create(srf->surface, width, height);
if(srf->egl_window == EGL_NO_SURFACE) {
return "can't create egl window";
}
printf("created egl window\n");
srf->egl_surface = weston_platform_create_egl_surface(srf->egl_display, srf->egl_conf, srf->egl_window, NULL);
srf->cairo_surface = cairo_gl_surface_create_for_egl(srf->cairo_device, srf->egl_surface, width, height);
if(srf->cairo_surface == NULL) {
return "can't create Cairo surface";
}
srf->ctx = cairo_create(srf->cairo_surface);
if(cairo_status(srf->ctx) != CAIRO_STATUS_SUCCESS) {
return "cairo error on create";
}
return NULL;
}
static const char *init_egl(Surface *srf) {
EGLint major, minor, count, n, size;
EGLConfig *configs;
EGLint config_attribs[] = {
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
};
static const EGLint context_attribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
int i;
srf->egl_display = eglGetDisplay((EGLNativeDisplayType) srf->display);
if(srf->egl_display == EGL_NO_DISPLAY) {
return "can't create egl display";
}
if(eglInitialize(srf->egl_display, &major, &minor) != EGL_TRUE) {
return "can't initialise egl display";
}
fprintf(stderr, "EGL major: %d, minor %d\n", major, minor);
if(!eglBindAPI(EGL_OPENGL_API)) {
return "failed to bind EGL client API";
}
eglGetConfigs(srf->egl_display, NULL, 0, &count);
configs = calloc(count, sizeof *configs);
eglChooseConfig(srf->egl_display, config_attribs, configs, count, &n);
for(i = 0; i < n; i++) {
eglGetConfigAttrib(srf->egl_display, configs[i], EGL_BUFFER_SIZE, &size);
printf("buffer size for config %d is %d\n", i, size);
eglGetConfigAttrib(srf->egl_display, configs[i], EGL_RED_SIZE, &size);
printf("red size for config %d is %d\n", i, size);
// just choose the first one
srf->egl_conf = configs[i];
break;
}
srf->egl_context = eglCreateContext(srf->egl_display, srf->egl_conf, EGL_NO_CONTEXT, context_attribs);
if(srf->egl_context == NULL) {
return "can't create context";
}
srf->cairo_device = cairo_egl_device_create(srf->egl_display, srf->egl_context);
if(cairo_device_status(srf->cairo_device) != CAIRO_STATUS_SUCCESS) {
return "failed to get cairo EGL device";
}
return NULL;
}
/////////////////
static void global_registry_handler(void *data, struct wl_registry *registry, uint32_t id, const char *interface, uint32_t version) {
(void) version;
Surface *srf = (Surface *)data;
if(strcmp(interface, "wl_compositor") == 0) {
srf->compositor = wl_registry_bind(registry, id, &wl_compositor_interface, 1);
} else if (strcmp(interface, "wl_shell") == 0) {
srf->shell = wl_registry_bind(registry, id, &wl_shell_interface, 1);
}
}
static void global_registry_remover(void *data, struct wl_registry *registry, uint32_t id) {
(void) data;
(void) registry;
(void) id;
}
static const struct wl_registry_listener registry_listener = {
global_registry_handler,
global_registry_remover
};
static const char * get_server_references(Surface *srf) {
srf->display = wl_display_connect(NULL);
if(srf->display == NULL) {
return "can't connect to display";
}
struct wl_registry *registry = wl_display_get_registry(srf->display);
wl_registry_add_listener(registry, &registry_listener, srf);
wl_display_dispatch(srf->display);
wl_display_roundtrip(srf->display);
if(srf->compositor == NULL || srf->shell == NULL) {
return "can't find compositor or shell";
}
return NULL;
}
/////////////
static Surface * ui_surface_create(uint32_t width, uint32_t height, const char **out_err) {
Surface *srf = calloc(1, sizeof(Surface));
const char *err = get_server_references(srf);
if(err != NULL) {
*out_err = err;
free(srf);
return NULL;
}
srf->surface = wl_compositor_create_surface(srf->compositor);
if(srf->surface == NULL) {
*out_err = "can't create surface";
free(srf);
return NULL;
}
srf->shell_surface = wl_shell_get_shell_surface(srf->shell, srf->surface);
wl_shell_surface_set_toplevel(srf->shell_surface);
if((err = init_egl(srf)) != NULL) {
*out_err = err;
free(srf);
return NULL;
}
if((err = create_window(srf, width, height)) != NULL) {
*out_err = err;
free(srf);
return NULL;
}
return srf;
}
static void ui_surface_free(void *vsrf) {
Surface *srf = vsrf;
wl_display_disconnect(srf->display);
free(srf);
}
static cairo_t *ui_surface_get_context(void *vsrf) {
Surface *srf = vsrf;
return srf->ctx;
}
static void ui_surface_swap_buffers(void *vsrf) {
Surface *srf = vsrf;
cairo_gl_surface_swapbuffers(srf->cairo_surface);
}
int main(void) {
const char *err = NULL;
const int width = 340;
const int height = 480;
Surface *srf = ui_surface_create(width, height, &err);
if(srf == NULL) {
fprintf(stderr, "failed to create surface: %s\n", err);
return EXIT_FAILURE;
}
cairo_t * ctx = ui_surface_get_context(srf);
#if USE_PANGO
PangoFontDescription *desc = pango_font_description_from_string("Sans 20");
#else
cairo_select_font_face(ctx, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(ctx, 20);
#endif
float value = 0;
float direction = +0.01;
while(1) {
cairo_set_source_rgb(ctx, 1-value, 1-value, 1-value);
cairo_paint(ctx);
cairo_set_source_rgb(ctx, value, value, value);
if(cairo_status(ctx) != CAIRO_STATUS_SUCCESS) {
printf("drawing failed before text: %s\n", cairo_status_to_string(cairo_status(ctx)));
return EXIT_FAILURE;
}
#if USE_PANGO
PangoLayout *lay = pango_cairo_create_layout(ctx);
pango_layout_set_text(lay, "Hello from Pango!", -1);
pango_layout_set_font_description(lay, desc);
int tw = 0, th = 0;
pango_layout_get_size(lay, &tw, &th);
tw /= PANGO_SCALE;
th /= PANGO_SCALE;
cairo_move_to(ctx, width/2-tw/2, height/2-th/2);
pango_cairo_show_layout(ctx, lay);
#else
cairo_text_extents_t extents;
cairo_text_extents(ctx, "Hello from Cairo!", &extents);
cairo_move_to(ctx, width/2-extents.width/2, height/2-extents.height/2);
cairo_show_text(ctx, "Hello from Cairo!");
#endif
// It fails here (both for cairo_show_text and pango):
if(cairo_status(ctx) != CAIRO_STATUS_SUCCESS) {
printf("drawing text failed: %s\n", cairo_status_to_string(cairo_status(ctx)));
return EXIT_FAILURE;
}
ui_surface_swap_buffers(srf);
value += direction;
if(value > 1.0) {
direction *= -1;
}
if(value < 0.0) {
direction *= -1;
}
}
#if USE_PANGO
pango_font_description_free(desc);
#endif
ui_surface_free(srf);
return EXIT_SUCCESS;
}
/**************************************************************************
*
* Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
/* Extensions used by Weston, copied from Mesa's eglmesaext.h, */
#ifndef WESTON_EGL_EXT_H
#define WESTON_EGL_EXT_H
#ifndef EGL_WL_bind_wayland_display
#define EGL_WL_bind_wayland_display 1
#define EGL_WAYLAND_BUFFER_WL 0x31D5 /* eglCreateImageKHR target */
#define EGL_WAYLAND_PLANE_WL 0x31D6 /* eglCreateImageKHR target */
#define EGL_TEXTURE_Y_U_V_WL 0x31D7
#define EGL_TEXTURE_Y_UV_WL 0x31D8
#define EGL_TEXTURE_Y_XUXV_WL 0x31D9
#define EGL_TEXTURE_EXTERNAL_WL 0x31DA
struct wl_display;
struct wl_buffer;
#ifdef EGL_EGLEXT_PROTOTYPES
EGLAPI EGLBoolean EGLAPIENTRY eglBindWaylandDisplayWL(EGLDisplay dpy, struct wl_display *display);
EGLAPI EGLBoolean EGLAPIENTRY eglUnbindWaylandDisplayWL(EGLDisplay dpy, struct wl_display *display);
EGLAPI EGLBoolean EGLAPIENTRY eglQueryWaylandBufferWL(EGLDisplay dpy, struct wl_buffer *buffer, EGLint attribute, EGLint *value);
#endif
typedef EGLBoolean (EGLAPIENTRYP PFNEGLBINDWAYLANDDISPLAYWL) (EGLDisplay dpy, struct wl_display *display);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNBINDWAYLANDDISPLAYWL) (EGLDisplay dpy, struct wl_display *display);
typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYWAYLANDBUFFERWL) (EGLDisplay dpy, struct wl_buffer *buffer, EGLint attribute, EGLint *value);
#endif
#ifndef EGL_TEXTURE_EXTERNAL_WL
#define EGL_TEXTURE_EXTERNAL_WL 0x31DA
#endif
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment