clients: add subsurfaces demo
Add a demo program with:
- a main surface (green)
- a Cairo-image sub-surface (red)
- a raw GLESv2 widget (triangle)
Sub-surface input region is set empty to avoid problems in toytoolkit.
If Cairo links to libGL, then we will end up with also libGLESv2 linked
to subsurfaces program, and both libs getting really used, which leads
to disaster.
Do not build subsurfaces demo, if Cairo links to libGL and cairo-egl is
usable.
The GL rendering loop is not tied to the toytoolkit or the widget, but
runs directly from its own frame callback. Therefore it runs
independent of the rest of the application. This also relies on one of
two things:
- eglSwapInterval(0) is implemented, and therefore eglSwapBuffers never
blocks indefinitely, or
- toytoolkit has a workaround, that guarantees that eglSwapBuffers will
return soon, when we force a repaint on resize.
Otherwise the demo will deadlock.
The code is separated into three sections:
1. The library component, using only EGL, GLESv2, and libwayland-client
APIs, and not aware of any toolkit details of the parent application.
This runs independently until the parent application tells otherwise.
2. The glue code: a toytoolkit application widget, who has its own
rendering machinery.
3. The application written in toytoolkit.
This patch also adds new toytoolkit interfaces:
- widget_get_wl_surface()
- widget_get_last_time()
- widget_input_region_add()
Toytoolkit applications have not had a possibility to change the input
region. The frame widget (decorations) set the input region on its own
when used, otherwise the default input region of everything has been
used. If a window does not have a frame widget, it can now use
widget_input_region_add() to set a custom input region.
These are not window methods, because a widget may lie on a different
wl_surface (sub-surface) than the window.
Changes in v3:
- replace set_commit_mode with set_sync and set_desync
Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
2013-04-25 14:57:50 +04:00
|
|
|
/*
|
|
|
|
* Copyright © 2010 Intel Corporation
|
|
|
|
* Copyright © 2011 Benjamin Franzke
|
|
|
|
* Copyright © 2012-2013 Collabora, Ltd.
|
|
|
|
*
|
2015-06-11 08:48:59 +03:00
|
|
|
* 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:
|
clients: add subsurfaces demo
Add a demo program with:
- a main surface (green)
- a Cairo-image sub-surface (red)
- a raw GLESv2 widget (triangle)
Sub-surface input region is set empty to avoid problems in toytoolkit.
If Cairo links to libGL, then we will end up with also libGLESv2 linked
to subsurfaces program, and both libs getting really used, which leads
to disaster.
Do not build subsurfaces demo, if Cairo links to libGL and cairo-egl is
usable.
The GL rendering loop is not tied to the toytoolkit or the widget, but
runs directly from its own frame callback. Therefore it runs
independent of the rest of the application. This also relies on one of
two things:
- eglSwapInterval(0) is implemented, and therefore eglSwapBuffers never
blocks indefinitely, or
- toytoolkit has a workaround, that guarantees that eglSwapBuffers will
return soon, when we force a repaint on resize.
Otherwise the demo will deadlock.
The code is separated into three sections:
1. The library component, using only EGL, GLESv2, and libwayland-client
APIs, and not aware of any toolkit details of the parent application.
This runs independently until the parent application tells otherwise.
2. The glue code: a toytoolkit application widget, who has its own
rendering machinery.
3. The application written in toytoolkit.
This patch also adds new toytoolkit interfaces:
- widget_get_wl_surface()
- widget_get_last_time()
- widget_input_region_add()
Toytoolkit applications have not had a possibility to change the input
region. The frame widget (decorations) set the input region on its own
when used, otherwise the default input region of everything has been
used. If a window does not have a frame widget, it can now use
widget_input_region_add() to set a custom input region.
These are not window methods, because a widget may lie on a different
wl_surface (sub-surface) than the window.
Changes in v3:
- replace set_commit_mode with set_sync and set_desync
Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
2013-04-25 14:57:50 +04:00
|
|
|
*
|
2015-06-11 08:48:59 +03:00
|
|
|
* 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.
|
clients: add subsurfaces demo
Add a demo program with:
- a main surface (green)
- a Cairo-image sub-surface (red)
- a raw GLESv2 widget (triangle)
Sub-surface input region is set empty to avoid problems in toytoolkit.
If Cairo links to libGL, then we will end up with also libGLESv2 linked
to subsurfaces program, and both libs getting really used, which leads
to disaster.
Do not build subsurfaces demo, if Cairo links to libGL and cairo-egl is
usable.
The GL rendering loop is not tied to the toytoolkit or the widget, but
runs directly from its own frame callback. Therefore it runs
independent of the rest of the application. This also relies on one of
two things:
- eglSwapInterval(0) is implemented, and therefore eglSwapBuffers never
blocks indefinitely, or
- toytoolkit has a workaround, that guarantees that eglSwapBuffers will
return soon, when we force a repaint on resize.
Otherwise the demo will deadlock.
The code is separated into three sections:
1. The library component, using only EGL, GLESv2, and libwayland-client
APIs, and not aware of any toolkit details of the parent application.
This runs independently until the parent application tells otherwise.
2. The glue code: a toytoolkit application widget, who has its own
rendering machinery.
3. The application written in toytoolkit.
This patch also adds new toytoolkit interfaces:
- widget_get_wl_surface()
- widget_get_last_time()
- widget_input_region_add()
Toytoolkit applications have not had a possibility to change the input
region. The frame widget (decorations) set the input region on its own
when used, otherwise the default input region of everything has been
used. If a window does not have a frame widget, it can now use
widget_input_region_add() to set a custom input region.
These are not window methods, because a widget may lie on a different
wl_surface (sub-surface) than the window.
Changes in v3:
- replace set_commit_mode with set_sync and set_desync
Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
2013-04-25 14:57:50 +04:00
|
|
|
*/
|
|
|
|
|
2014-04-07 15:40:35 +04:00
|
|
|
#include "config.h"
|
|
|
|
|
clients: add subsurfaces demo
Add a demo program with:
- a main surface (green)
- a Cairo-image sub-surface (red)
- a raw GLESv2 widget (triangle)
Sub-surface input region is set empty to avoid problems in toytoolkit.
If Cairo links to libGL, then we will end up with also libGLESv2 linked
to subsurfaces program, and both libs getting really used, which leads
to disaster.
Do not build subsurfaces demo, if Cairo links to libGL and cairo-egl is
usable.
The GL rendering loop is not tied to the toytoolkit or the widget, but
runs directly from its own frame callback. Therefore it runs
independent of the rest of the application. This also relies on one of
two things:
- eglSwapInterval(0) is implemented, and therefore eglSwapBuffers never
blocks indefinitely, or
- toytoolkit has a workaround, that guarantees that eglSwapBuffers will
return soon, when we force a repaint on resize.
Otherwise the demo will deadlock.
The code is separated into three sections:
1. The library component, using only EGL, GLESv2, and libwayland-client
APIs, and not aware of any toolkit details of the parent application.
This runs independently until the parent application tells otherwise.
2. The glue code: a toytoolkit application widget, who has its own
rendering machinery.
3. The application written in toytoolkit.
This patch also adds new toytoolkit interfaces:
- widget_get_wl_surface()
- widget_get_last_time()
- widget_input_region_add()
Toytoolkit applications have not had a possibility to change the input
region. The frame widget (decorations) set the input region on its own
when used, otherwise the default input region of everything has been
used. If a window does not have a frame widget, it can now use
widget_input_region_add() to set a custom input region.
These are not window methods, because a widget may lie on a different
wl_surface (sub-surface) than the window.
Changes in v3:
- replace set_commit_mode with set_sync and set_desync
Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
2013-04-25 14:57:50 +04:00
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <cairo.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#include <linux/input.h>
|
|
|
|
#include <wayland-client.h>
|
|
|
|
|
|
|
|
#include <wayland-egl.h>
|
|
|
|
#include <GLES2/gl2.h>
|
|
|
|
#include <EGL/egl.h>
|
2015-03-20 17:26:51 +03:00
|
|
|
#include <EGL/eglext.h>
|
clients: add subsurfaces demo
Add a demo program with:
- a main surface (green)
- a Cairo-image sub-surface (red)
- a raw GLESv2 widget (triangle)
Sub-surface input region is set empty to avoid problems in toytoolkit.
If Cairo links to libGL, then we will end up with also libGLESv2 linked
to subsurfaces program, and both libs getting really used, which leads
to disaster.
Do not build subsurfaces demo, if Cairo links to libGL and cairo-egl is
usable.
The GL rendering loop is not tied to the toytoolkit or the widget, but
runs directly from its own frame callback. Therefore it runs
independent of the rest of the application. This also relies on one of
two things:
- eglSwapInterval(0) is implemented, and therefore eglSwapBuffers never
blocks indefinitely, or
- toytoolkit has a workaround, that guarantees that eglSwapBuffers will
return soon, when we force a repaint on resize.
Otherwise the demo will deadlock.
The code is separated into three sections:
1. The library component, using only EGL, GLESv2, and libwayland-client
APIs, and not aware of any toolkit details of the parent application.
This runs independently until the parent application tells otherwise.
2. The glue code: a toytoolkit application widget, who has its own
rendering machinery.
3. The application written in toytoolkit.
This patch also adds new toytoolkit interfaces:
- widget_get_wl_surface()
- widget_get_last_time()
- widget_input_region_add()
Toytoolkit applications have not had a possibility to change the input
region. The frame widget (decorations) set the input region on its own
when used, otherwise the default input region of everything has been
used. If a window does not have a frame widget, it can now use
widget_input_region_add() to set a custom input region.
These are not window methods, because a widget may lie on a different
wl_surface (sub-surface) than the window.
Changes in v3:
- replace set_commit_mode with set_sync and set_desync
Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
2013-04-25 14:57:50 +04:00
|
|
|
|
2015-06-16 01:37:08 +03:00
|
|
|
#include "shared/helpers.h"
|
clients: add subsurfaces demo
Add a demo program with:
- a main surface (green)
- a Cairo-image sub-surface (red)
- a raw GLESv2 widget (triangle)
Sub-surface input region is set empty to avoid problems in toytoolkit.
If Cairo links to libGL, then we will end up with also libGLESv2 linked
to subsurfaces program, and both libs getting really used, which leads
to disaster.
Do not build subsurfaces demo, if Cairo links to libGL and cairo-egl is
usable.
The GL rendering loop is not tied to the toytoolkit or the widget, but
runs directly from its own frame callback. Therefore it runs
independent of the rest of the application. This also relies on one of
two things:
- eglSwapInterval(0) is implemented, and therefore eglSwapBuffers never
blocks indefinitely, or
- toytoolkit has a workaround, that guarantees that eglSwapBuffers will
return soon, when we force a repaint on resize.
Otherwise the demo will deadlock.
The code is separated into three sections:
1. The library component, using only EGL, GLESv2, and libwayland-client
APIs, and not aware of any toolkit details of the parent application.
This runs independently until the parent application tells otherwise.
2. The glue code: a toytoolkit application widget, who has its own
rendering machinery.
3. The application written in toytoolkit.
This patch also adds new toytoolkit interfaces:
- widget_get_wl_surface()
- widget_get_last_time()
- widget_input_region_add()
Toytoolkit applications have not had a possibility to change the input
region. The frame widget (decorations) set the input region on its own
when used, otherwise the default input region of everything has been
used. If a window does not have a frame widget, it can now use
widget_input_region_add() to set a custom input region.
These are not window methods, because a widget may lie on a different
wl_surface (sub-surface) than the window.
Changes in v3:
- replace set_commit_mode with set_sync and set_desync
Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
2013-04-25 14:57:50 +04:00
|
|
|
#include "window.h"
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
#define DBG(fmt, ...) \
|
|
|
|
fprintf(stderr, "%d:%s " fmt, __LINE__, __func__, ##__VA_ARGS__)
|
|
|
|
#else
|
|
|
|
#define DBG(...) do {} while (0)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int32_t option_red_mode;
|
|
|
|
static int32_t option_triangle_mode;
|
|
|
|
static int32_t option_no_triangle;
|
|
|
|
static int32_t option_help;
|
|
|
|
|
|
|
|
static const struct weston_option options[] = {
|
|
|
|
{ WESTON_OPTION_INTEGER, "red-mode", 'r', &option_red_mode },
|
|
|
|
{ WESTON_OPTION_INTEGER, "triangle-mode", 't', &option_triangle_mode },
|
|
|
|
{ WESTON_OPTION_BOOLEAN, "no-triangle", 'n', &option_no_triangle },
|
|
|
|
{ WESTON_OPTION_BOOLEAN, "help", 'h', &option_help },
|
|
|
|
};
|
|
|
|
|
|
|
|
static enum subsurface_mode
|
|
|
|
int_to_mode(int32_t i)
|
|
|
|
{
|
|
|
|
switch (i) {
|
|
|
|
case 0:
|
|
|
|
return SUBSURFACE_DESYNCHRONIZED;
|
|
|
|
case 1:
|
|
|
|
return SUBSURFACE_SYNCHRONIZED;
|
|
|
|
default:
|
|
|
|
fprintf(stderr, "error: %d is not a valid commit mode.\n", i);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char help_text[] =
|
|
|
|
"Usage: %s [options]\n"
|
|
|
|
"\n"
|
|
|
|
" -r, --red-mode=MODE\t\tthe commit mode for the red sub-surface (0)\n"
|
|
|
|
" -t, --triangle-mode=MODE\tthe commit mode for the GL sub-surface (0)\n"
|
|
|
|
" -n, --no-triangle\t\tDo not create the GL sub-surface.\n"
|
|
|
|
"\n"
|
|
|
|
"The MODE is the wl_subsurface commit mode used by default for the\n"
|
|
|
|
"given sub-surface. Valid values are the integers:\n"
|
|
|
|
" 0\tfor desynchronized, i.e. free-running\n"
|
|
|
|
" 1\tfor synchronized\n"
|
|
|
|
"\n"
|
|
|
|
"This program demonstrates sub-surfaces with the toytoolkit.\n"
|
|
|
|
"The main surface contains the decorations, a green canvas, and a\n"
|
|
|
|
"green spinner. One sub-surface is red with a red spinner. These\n"
|
|
|
|
"are rendered with Cairo. The other sub-surface contains a spinning\n"
|
|
|
|
"triangle rendered in EGL/GLESv2, without Cairo, i.e. it is a raw GL\n"
|
|
|
|
"widget.\n"
|
|
|
|
"\n"
|
|
|
|
"The GL widget animates on its own. The spinners follow wall clock\n"
|
|
|
|
"time and update only when their surface is repainted, so you see\n"
|
|
|
|
"which surfaces get redrawn. The red sub-surface animates on its own,\n"
|
|
|
|
"but can be toggled with the spacebar.\n"
|
|
|
|
"\n"
|
|
|
|
"Even though the sub-surfaces attempt to animate on their own, they\n"
|
|
|
|
"are subject to the commit mode. If commit mode is synchronized,\n"
|
|
|
|
"they will need a commit on the main surface to actually display.\n"
|
|
|
|
"You can trigger a main surface repaint, without a resize, by\n"
|
|
|
|
"hovering the pointer over the title bar buttons.\n"
|
|
|
|
"\n"
|
|
|
|
"Resizing will temporarily toggle the commit mode of all sub-surfaces\n"
|
|
|
|
"to guarantee synchronized rendering on size changes. It also forces\n"
|
|
|
|
"a repaint of all surfaces.\n"
|
|
|
|
"\n"
|
|
|
|
"Using -t1 -r1 is especially useful for trying to catch inconsistent\n"
|
|
|
|
"rendering and deadlocks, since free-running sub-surfaces would\n"
|
|
|
|
"immediately hide the problem.\n"
|
|
|
|
"\n"
|
|
|
|
"Key controls:\n"
|
|
|
|
" space - toggle red sub-surface animation loop\n"
|
|
|
|
" up - step window size shorter\n"
|
|
|
|
" down - step window size taller\n"
|
|
|
|
"\n";
|
|
|
|
|
|
|
|
struct egl_state {
|
|
|
|
EGLDisplay dpy;
|
|
|
|
EGLContext ctx;
|
|
|
|
EGLConfig conf;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct triangle_gl_state {
|
|
|
|
GLuint rotation_uniform;
|
|
|
|
GLuint pos;
|
|
|
|
GLuint col;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct triangle {
|
|
|
|
struct egl_state *egl;
|
|
|
|
|
|
|
|
struct wl_surface *wl_surface;
|
|
|
|
struct wl_egl_window *egl_window;
|
|
|
|
EGLSurface egl_surface;
|
|
|
|
int width;
|
|
|
|
int height;
|
|
|
|
|
|
|
|
struct triangle_gl_state gl;
|
|
|
|
|
|
|
|
struct widget *widget;
|
|
|
|
uint32_t time;
|
|
|
|
struct wl_callback *frame_cb;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******** Pure EGL/GLESv2/libwayland-client component: ***************/
|
|
|
|
|
|
|
|
static const char *vert_shader_text =
|
|
|
|
"uniform mat4 rotation;\n"
|
|
|
|
"attribute vec4 pos;\n"
|
|
|
|
"attribute vec4 color;\n"
|
|
|
|
"varying vec4 v_color;\n"
|
|
|
|
"void main() {\n"
|
|
|
|
" gl_Position = rotation * pos;\n"
|
|
|
|
" v_color = color;\n"
|
|
|
|
"}\n";
|
|
|
|
|
|
|
|
static const char *frag_shader_text =
|
|
|
|
"precision mediump float;\n"
|
|
|
|
"varying vec4 v_color;\n"
|
|
|
|
"void main() {\n"
|
|
|
|
" gl_FragColor = v_color;\n"
|
|
|
|
"}\n";
|
|
|
|
|
|
|
|
static void
|
|
|
|
egl_print_config_info(struct egl_state *egl)
|
|
|
|
{
|
|
|
|
EGLint r, g, b, a;
|
|
|
|
|
|
|
|
printf("Chosen EGL config details:\n");
|
|
|
|
|
|
|
|
printf("\tRGBA bits");
|
|
|
|
if (eglGetConfigAttrib(egl->dpy, egl->conf, EGL_RED_SIZE, &r) &&
|
|
|
|
eglGetConfigAttrib(egl->dpy, egl->conf, EGL_GREEN_SIZE, &g) &&
|
|
|
|
eglGetConfigAttrib(egl->dpy, egl->conf, EGL_BLUE_SIZE, &b) &&
|
|
|
|
eglGetConfigAttrib(egl->dpy, egl->conf, EGL_ALPHA_SIZE, &a))
|
|
|
|
printf(": %d %d %d %d\n", r, g, b, a);
|
|
|
|
else
|
|
|
|
printf(" unknown\n");
|
|
|
|
|
|
|
|
printf("\tswap interval range");
|
|
|
|
if (eglGetConfigAttrib(egl->dpy, egl->conf, EGL_MIN_SWAP_INTERVAL, &a) &&
|
|
|
|
eglGetConfigAttrib(egl->dpy, egl->conf, EGL_MAX_SWAP_INTERVAL, &b))
|
|
|
|
printf(": %d - %d\n", a, b);
|
|
|
|
else
|
|
|
|
printf(" unknown\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct egl_state *
|
|
|
|
egl_state_create(struct wl_display *display)
|
|
|
|
{
|
|
|
|
struct egl_state *egl;
|
|
|
|
|
|
|
|
static const EGLint context_attribs[] = {
|
|
|
|
EGL_CONTEXT_CLIENT_VERSION, 2,
|
|
|
|
EGL_NONE
|
|
|
|
};
|
|
|
|
|
|
|
|
EGLint config_attribs[] = {
|
|
|
|
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
|
|
|
EGL_RED_SIZE, 1,
|
|
|
|
EGL_GREEN_SIZE, 1,
|
|
|
|
EGL_BLUE_SIZE, 1,
|
|
|
|
EGL_ALPHA_SIZE, 1,
|
|
|
|
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
|
|
|
EGL_NONE
|
|
|
|
};
|
|
|
|
|
|
|
|
EGLint major, minor, n;
|
|
|
|
EGLBoolean ret;
|
|
|
|
|
|
|
|
egl = calloc(1, sizeof *egl);
|
|
|
|
assert(egl);
|
|
|
|
|
2015-03-20 17:26:51 +03:00
|
|
|
egl->dpy =
|
|
|
|
weston_platform_get_egl_display(EGL_PLATFORM_WAYLAND_KHR,
|
|
|
|
display, NULL);
|
clients: add subsurfaces demo
Add a demo program with:
- a main surface (green)
- a Cairo-image sub-surface (red)
- a raw GLESv2 widget (triangle)
Sub-surface input region is set empty to avoid problems in toytoolkit.
If Cairo links to libGL, then we will end up with also libGLESv2 linked
to subsurfaces program, and both libs getting really used, which leads
to disaster.
Do not build subsurfaces demo, if Cairo links to libGL and cairo-egl is
usable.
The GL rendering loop is not tied to the toytoolkit or the widget, but
runs directly from its own frame callback. Therefore it runs
independent of the rest of the application. This also relies on one of
two things:
- eglSwapInterval(0) is implemented, and therefore eglSwapBuffers never
blocks indefinitely, or
- toytoolkit has a workaround, that guarantees that eglSwapBuffers will
return soon, when we force a repaint on resize.
Otherwise the demo will deadlock.
The code is separated into three sections:
1. The library component, using only EGL, GLESv2, and libwayland-client
APIs, and not aware of any toolkit details of the parent application.
This runs independently until the parent application tells otherwise.
2. The glue code: a toytoolkit application widget, who has its own
rendering machinery.
3. The application written in toytoolkit.
This patch also adds new toytoolkit interfaces:
- widget_get_wl_surface()
- widget_get_last_time()
- widget_input_region_add()
Toytoolkit applications have not had a possibility to change the input
region. The frame widget (decorations) set the input region on its own
when used, otherwise the default input region of everything has been
used. If a window does not have a frame widget, it can now use
widget_input_region_add() to set a custom input region.
These are not window methods, because a widget may lie on a different
wl_surface (sub-surface) than the window.
Changes in v3:
- replace set_commit_mode with set_sync and set_desync
Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
2013-04-25 14:57:50 +04:00
|
|
|
assert(egl->dpy);
|
|
|
|
|
|
|
|
ret = eglInitialize(egl->dpy, &major, &minor);
|
|
|
|
assert(ret == EGL_TRUE);
|
|
|
|
ret = eglBindAPI(EGL_OPENGL_ES_API);
|
|
|
|
assert(ret == EGL_TRUE);
|
|
|
|
|
|
|
|
ret = eglChooseConfig(egl->dpy, config_attribs, &egl->conf, 1, &n);
|
|
|
|
assert(ret && n == 1);
|
|
|
|
|
|
|
|
egl->ctx = eglCreateContext(egl->dpy, egl->conf,
|
|
|
|
EGL_NO_CONTEXT, context_attribs);
|
|
|
|
assert(egl->ctx);
|
|
|
|
egl_print_config_info(egl);
|
|
|
|
|
|
|
|
return egl;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
egl_state_destroy(struct egl_state *egl)
|
|
|
|
{
|
|
|
|
/* Required, otherwise segfault in egl_dri2.c: dri2_make_current()
|
|
|
|
* on eglReleaseThread(). */
|
|
|
|
eglMakeCurrent(egl->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE,
|
|
|
|
EGL_NO_CONTEXT);
|
|
|
|
|
|
|
|
eglTerminate(egl->dpy);
|
|
|
|
eglReleaseThread();
|
|
|
|
free(egl);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
egl_make_swapbuffers_nonblock(struct egl_state *egl)
|
|
|
|
{
|
|
|
|
EGLint a = EGL_MIN_SWAP_INTERVAL;
|
|
|
|
EGLint b = EGL_MAX_SWAP_INTERVAL;
|
|
|
|
|
|
|
|
if (!eglGetConfigAttrib(egl->dpy, egl->conf, a, &a) ||
|
|
|
|
!eglGetConfigAttrib(egl->dpy, egl->conf, b, &b)) {
|
|
|
|
fprintf(stderr, "warning: swap interval range unknown\n");
|
2015-01-26 13:19:07 +03:00
|
|
|
} else if (a > 0) {
|
clients: add subsurfaces demo
Add a demo program with:
- a main surface (green)
- a Cairo-image sub-surface (red)
- a raw GLESv2 widget (triangle)
Sub-surface input region is set empty to avoid problems in toytoolkit.
If Cairo links to libGL, then we will end up with also libGLESv2 linked
to subsurfaces program, and both libs getting really used, which leads
to disaster.
Do not build subsurfaces demo, if Cairo links to libGL and cairo-egl is
usable.
The GL rendering loop is not tied to the toytoolkit or the widget, but
runs directly from its own frame callback. Therefore it runs
independent of the rest of the application. This also relies on one of
two things:
- eglSwapInterval(0) is implemented, and therefore eglSwapBuffers never
blocks indefinitely, or
- toytoolkit has a workaround, that guarantees that eglSwapBuffers will
return soon, when we force a repaint on resize.
Otherwise the demo will deadlock.
The code is separated into three sections:
1. The library component, using only EGL, GLESv2, and libwayland-client
APIs, and not aware of any toolkit details of the parent application.
This runs independently until the parent application tells otherwise.
2. The glue code: a toytoolkit application widget, who has its own
rendering machinery.
3. The application written in toytoolkit.
This patch also adds new toytoolkit interfaces:
- widget_get_wl_surface()
- widget_get_last_time()
- widget_input_region_add()
Toytoolkit applications have not had a possibility to change the input
region. The frame widget (decorations) set the input region on its own
when used, otherwise the default input region of everything has been
used. If a window does not have a frame widget, it can now use
widget_input_region_add() to set a custom input region.
These are not window methods, because a widget may lie on a different
wl_surface (sub-surface) than the window.
Changes in v3:
- replace set_commit_mode with set_sync and set_desync
Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
2013-04-25 14:57:50 +04:00
|
|
|
fprintf(stderr, "warning: minimum swap interval is %d, "
|
|
|
|
"while 0 is required to not deadlock on resize.\n", a);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We rely on the Wayland compositor to sync to vblank anyway.
|
|
|
|
* We just need to be able to call eglSwapBuffers() without the
|
|
|
|
* risk of waiting for a frame callback in it.
|
|
|
|
*/
|
|
|
|
if (!eglSwapInterval(egl->dpy, 0)) {
|
|
|
|
fprintf(stderr, "error: eglSwapInterval() failed.\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static GLuint
|
|
|
|
create_shader(const char *source, GLenum shader_type)
|
|
|
|
{
|
|
|
|
GLuint shader;
|
|
|
|
GLint status;
|
|
|
|
|
|
|
|
shader = glCreateShader(shader_type);
|
|
|
|
assert(shader != 0);
|
|
|
|
|
|
|
|
glShaderSource(shader, 1, (const char **) &source, NULL);
|
|
|
|
glCompileShader(shader);
|
|
|
|
|
|
|
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
|
|
|
|
if (!status) {
|
|
|
|
char log[1000];
|
|
|
|
GLsizei len;
|
|
|
|
glGetShaderInfoLog(shader, 1000, &len, log);
|
|
|
|
fprintf(stderr, "Error: compiling %s: %*s\n",
|
|
|
|
shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
|
|
|
|
len, log);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return shader;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
triangle_init_gl(struct triangle_gl_state *trigl)
|
|
|
|
{
|
|
|
|
GLuint frag, vert;
|
|
|
|
GLuint program;
|
|
|
|
GLint status;
|
|
|
|
|
|
|
|
frag = create_shader(frag_shader_text, GL_FRAGMENT_SHADER);
|
|
|
|
vert = create_shader(vert_shader_text, GL_VERTEX_SHADER);
|
|
|
|
|
|
|
|
program = glCreateProgram();
|
|
|
|
glAttachShader(program, frag);
|
|
|
|
glAttachShader(program, vert);
|
|
|
|
glLinkProgram(program);
|
|
|
|
|
|
|
|
glGetProgramiv(program, GL_LINK_STATUS, &status);
|
|
|
|
if (!status) {
|
|
|
|
char log[1000];
|
|
|
|
GLsizei len;
|
|
|
|
glGetProgramInfoLog(program, 1000, &len, log);
|
|
|
|
fprintf(stderr, "Error: linking:\n%*s\n", len, log);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
glUseProgram(program);
|
|
|
|
|
|
|
|
trigl->pos = 0;
|
|
|
|
trigl->col = 1;
|
|
|
|
|
|
|
|
glBindAttribLocation(program, trigl->pos, "pos");
|
|
|
|
glBindAttribLocation(program, trigl->col, "color");
|
|
|
|
glLinkProgram(program);
|
|
|
|
|
|
|
|
trigl->rotation_uniform = glGetUniformLocation(program, "rotation");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
triangle_draw(const struct triangle_gl_state *trigl, uint32_t time)
|
|
|
|
{
|
|
|
|
static const GLfloat verts[3][2] = {
|
|
|
|
{ -0.5, -0.5 },
|
|
|
|
{ 0.5, -0.5 },
|
|
|
|
{ 0, 0.5 }
|
|
|
|
};
|
|
|
|
static const GLfloat colors[3][3] = {
|
|
|
|
{ 1, 0, 0 },
|
|
|
|
{ 0, 1, 0 },
|
|
|
|
{ 0, 0, 1 }
|
|
|
|
};
|
|
|
|
GLfloat angle;
|
|
|
|
GLfloat rotation[4][4] = {
|
|
|
|
{ 1, 0, 0, 0 },
|
|
|
|
{ 0, 1, 0, 0 },
|
|
|
|
{ 0, 0, 1, 0 },
|
|
|
|
{ 0, 0, 0, 1 }
|
|
|
|
};
|
|
|
|
static const int32_t speed_div = 5;
|
|
|
|
|
|
|
|
angle = (time / speed_div) % 360 * M_PI / 180.0;
|
|
|
|
rotation[0][0] = cos(angle);
|
|
|
|
rotation[0][2] = sin(angle);
|
|
|
|
rotation[2][0] = -sin(angle);
|
|
|
|
rotation[2][2] = cos(angle);
|
|
|
|
|
|
|
|
glUniformMatrix4fv(trigl->rotation_uniform, 1, GL_FALSE,
|
|
|
|
(GLfloat *) rotation);
|
|
|
|
|
|
|
|
glClearColor(0.0, 0.0, 0.0, 0.5);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
|
|
|
|
glVertexAttribPointer(trigl->pos, 2, GL_FLOAT, GL_FALSE, 0, verts);
|
|
|
|
glVertexAttribPointer(trigl->col, 3, GL_FLOAT, GL_FALSE, 0, colors);
|
|
|
|
glEnableVertexAttribArray(trigl->pos);
|
|
|
|
glEnableVertexAttribArray(trigl->col);
|
|
|
|
|
|
|
|
glDrawArrays(GL_TRIANGLES, 0, 3);
|
|
|
|
|
|
|
|
glDisableVertexAttribArray(trigl->pos);
|
|
|
|
glDisableVertexAttribArray(trigl->col);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
triangle_frame_callback(void *data, struct wl_callback *callback,
|
|
|
|
uint32_t time);
|
|
|
|
|
|
|
|
static const struct wl_callback_listener triangle_frame_listener = {
|
|
|
|
triangle_frame_callback
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
triangle_frame_callback(void *data, struct wl_callback *callback,
|
|
|
|
uint32_t time)
|
|
|
|
{
|
|
|
|
struct triangle *tri = data;
|
|
|
|
|
|
|
|
DBG("%stime %u\n", callback ? "" : "artificial ", time);
|
|
|
|
assert(callback == tri->frame_cb);
|
|
|
|
tri->time = time;
|
|
|
|
|
|
|
|
if (callback)
|
|
|
|
wl_callback_destroy(callback);
|
|
|
|
|
2013-08-28 10:14:35 +04:00
|
|
|
eglMakeCurrent(tri->egl->dpy, tri->egl_surface,
|
|
|
|
tri->egl_surface, tri->egl->ctx);
|
|
|
|
|
clients: add subsurfaces demo
Add a demo program with:
- a main surface (green)
- a Cairo-image sub-surface (red)
- a raw GLESv2 widget (triangle)
Sub-surface input region is set empty to avoid problems in toytoolkit.
If Cairo links to libGL, then we will end up with also libGLESv2 linked
to subsurfaces program, and both libs getting really used, which leads
to disaster.
Do not build subsurfaces demo, if Cairo links to libGL and cairo-egl is
usable.
The GL rendering loop is not tied to the toytoolkit or the widget, but
runs directly from its own frame callback. Therefore it runs
independent of the rest of the application. This also relies on one of
two things:
- eglSwapInterval(0) is implemented, and therefore eglSwapBuffers never
blocks indefinitely, or
- toytoolkit has a workaround, that guarantees that eglSwapBuffers will
return soon, when we force a repaint on resize.
Otherwise the demo will deadlock.
The code is separated into three sections:
1. The library component, using only EGL, GLESv2, and libwayland-client
APIs, and not aware of any toolkit details of the parent application.
This runs independently until the parent application tells otherwise.
2. The glue code: a toytoolkit application widget, who has its own
rendering machinery.
3. The application written in toytoolkit.
This patch also adds new toytoolkit interfaces:
- widget_get_wl_surface()
- widget_get_last_time()
- widget_input_region_add()
Toytoolkit applications have not had a possibility to change the input
region. The frame widget (decorations) set the input region on its own
when used, otherwise the default input region of everything has been
used. If a window does not have a frame widget, it can now use
widget_input_region_add() to set a custom input region.
These are not window methods, because a widget may lie on a different
wl_surface (sub-surface) than the window.
Changes in v3:
- replace set_commit_mode with set_sync and set_desync
Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
2013-04-25 14:57:50 +04:00
|
|
|
glViewport(0, 0, tri->width, tri->height);
|
|
|
|
|
|
|
|
triangle_draw(&tri->gl, tri->time);
|
|
|
|
|
|
|
|
tri->frame_cb = wl_surface_frame(tri->wl_surface);
|
|
|
|
wl_callback_add_listener(tri->frame_cb, &triangle_frame_listener, tri);
|
|
|
|
|
|
|
|
eglSwapBuffers(tri->egl->dpy, tri->egl_surface);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
triangle_create_egl_surface(struct triangle *tri, int width, int height)
|
|
|
|
{
|
|
|
|
EGLBoolean ret;
|
|
|
|
|
|
|
|
tri->wl_surface = widget_get_wl_surface(tri->widget);
|
|
|
|
tri->egl_window = wl_egl_window_create(tri->wl_surface, width, height);
|
2015-03-24 15:12:09 +03:00
|
|
|
tri->egl_surface = weston_platform_create_egl_surface(tri->egl->dpy,
|
|
|
|
tri->egl->conf,
|
|
|
|
tri->egl_window, NULL);
|
clients: add subsurfaces demo
Add a demo program with:
- a main surface (green)
- a Cairo-image sub-surface (red)
- a raw GLESv2 widget (triangle)
Sub-surface input region is set empty to avoid problems in toytoolkit.
If Cairo links to libGL, then we will end up with also libGLESv2 linked
to subsurfaces program, and both libs getting really used, which leads
to disaster.
Do not build subsurfaces demo, if Cairo links to libGL and cairo-egl is
usable.
The GL rendering loop is not tied to the toytoolkit or the widget, but
runs directly from its own frame callback. Therefore it runs
independent of the rest of the application. This also relies on one of
two things:
- eglSwapInterval(0) is implemented, and therefore eglSwapBuffers never
blocks indefinitely, or
- toytoolkit has a workaround, that guarantees that eglSwapBuffers will
return soon, when we force a repaint on resize.
Otherwise the demo will deadlock.
The code is separated into three sections:
1. The library component, using only EGL, GLESv2, and libwayland-client
APIs, and not aware of any toolkit details of the parent application.
This runs independently until the parent application tells otherwise.
2. The glue code: a toytoolkit application widget, who has its own
rendering machinery.
3. The application written in toytoolkit.
This patch also adds new toytoolkit interfaces:
- widget_get_wl_surface()
- widget_get_last_time()
- widget_input_region_add()
Toytoolkit applications have not had a possibility to change the input
region. The frame widget (decorations) set the input region on its own
when used, otherwise the default input region of everything has been
used. If a window does not have a frame widget, it can now use
widget_input_region_add() to set a custom input region.
These are not window methods, because a widget may lie on a different
wl_surface (sub-surface) than the window.
Changes in v3:
- replace set_commit_mode with set_sync and set_desync
Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
2013-04-25 14:57:50 +04:00
|
|
|
|
|
|
|
ret = eglMakeCurrent(tri->egl->dpy, tri->egl_surface,
|
|
|
|
tri->egl_surface, tri->egl->ctx);
|
|
|
|
assert(ret == EGL_TRUE);
|
|
|
|
|
|
|
|
egl_make_swapbuffers_nonblock(tri->egl);
|
|
|
|
triangle_init_gl(&tri->gl);
|
|
|
|
}
|
|
|
|
|
|
|
|
/********* The widget code interfacing the toolkit agnostic code: **********/
|
|
|
|
|
|
|
|
static void
|
|
|
|
triangle_resize_handler(struct widget *widget,
|
|
|
|
int32_t width, int32_t height, void *data)
|
|
|
|
{
|
|
|
|
struct triangle *tri = data;
|
|
|
|
|
|
|
|
DBG("to %dx%d\n", width, height);
|
|
|
|
tri->width = width;
|
|
|
|
tri->height = height;
|
|
|
|
|
|
|
|
if (tri->egl_surface) {
|
|
|
|
wl_egl_window_resize(tri->egl_window, width, height, 0, 0);
|
|
|
|
} else {
|
|
|
|
triangle_create_egl_surface(tri, width, height);
|
|
|
|
triangle_frame_callback(tri, NULL, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
triangle_redraw_handler(struct widget *widget, void *data)
|
|
|
|
{
|
|
|
|
struct triangle *tri = data;
|
|
|
|
int w, h;
|
|
|
|
|
|
|
|
wl_egl_window_get_attached_size(tri->egl_window, &w, &h);
|
|
|
|
|
|
|
|
DBG("previous %dx%d, new %dx%d\n", w, h, tri->width, tri->height);
|
|
|
|
|
|
|
|
/* If size is not changing, do not redraw ahead of time.
|
|
|
|
* That would risk blocking in eglSwapbuffers().
|
|
|
|
*/
|
|
|
|
if (w == tri->width && h == tri->height)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (tri->frame_cb) {
|
|
|
|
wl_callback_destroy(tri->frame_cb);
|
|
|
|
tri->frame_cb = NULL;
|
|
|
|
}
|
|
|
|
triangle_frame_callback(tri, NULL, tri->time);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
set_empty_input_region(struct widget *widget, struct display *display)
|
|
|
|
{
|
|
|
|
struct wl_compositor *compositor;
|
|
|
|
struct wl_surface *surface;
|
|
|
|
struct wl_region *region;
|
|
|
|
|
|
|
|
compositor = display_get_compositor(display);
|
|
|
|
surface = widget_get_wl_surface(widget);
|
|
|
|
region = wl_compositor_create_region(compositor);
|
|
|
|
wl_surface_set_input_region(surface, region);
|
|
|
|
wl_region_destroy(region);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct triangle *
|
|
|
|
triangle_create(struct window *window, struct egl_state *egl)
|
|
|
|
{
|
|
|
|
struct triangle *tri;
|
|
|
|
|
2013-08-08 02:34:59 +04:00
|
|
|
tri = xmalloc(sizeof *tri);
|
|
|
|
memset(tri, 0, sizeof *tri);
|
clients: add subsurfaces demo
Add a demo program with:
- a main surface (green)
- a Cairo-image sub-surface (red)
- a raw GLESv2 widget (triangle)
Sub-surface input region is set empty to avoid problems in toytoolkit.
If Cairo links to libGL, then we will end up with also libGLESv2 linked
to subsurfaces program, and both libs getting really used, which leads
to disaster.
Do not build subsurfaces demo, if Cairo links to libGL and cairo-egl is
usable.
The GL rendering loop is not tied to the toytoolkit or the widget, but
runs directly from its own frame callback. Therefore it runs
independent of the rest of the application. This also relies on one of
two things:
- eglSwapInterval(0) is implemented, and therefore eglSwapBuffers never
blocks indefinitely, or
- toytoolkit has a workaround, that guarantees that eglSwapBuffers will
return soon, when we force a repaint on resize.
Otherwise the demo will deadlock.
The code is separated into three sections:
1. The library component, using only EGL, GLESv2, and libwayland-client
APIs, and not aware of any toolkit details of the parent application.
This runs independently until the parent application tells otherwise.
2. The glue code: a toytoolkit application widget, who has its own
rendering machinery.
3. The application written in toytoolkit.
This patch also adds new toytoolkit interfaces:
- widget_get_wl_surface()
- widget_get_last_time()
- widget_input_region_add()
Toytoolkit applications have not had a possibility to change the input
region. The frame widget (decorations) set the input region on its own
when used, otherwise the default input region of everything has been
used. If a window does not have a frame widget, it can now use
widget_input_region_add() to set a custom input region.
These are not window methods, because a widget may lie on a different
wl_surface (sub-surface) than the window.
Changes in v3:
- replace set_commit_mode with set_sync and set_desync
Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
2013-04-25 14:57:50 +04:00
|
|
|
|
|
|
|
tri->egl = egl;
|
|
|
|
tri->widget = window_add_subsurface(window, tri,
|
|
|
|
int_to_mode(option_triangle_mode));
|
2013-12-19 20:17:12 +04:00
|
|
|
widget_set_use_cairo(tri->widget, 0);
|
clients: add subsurfaces demo
Add a demo program with:
- a main surface (green)
- a Cairo-image sub-surface (red)
- a raw GLESv2 widget (triangle)
Sub-surface input region is set empty to avoid problems in toytoolkit.
If Cairo links to libGL, then we will end up with also libGLESv2 linked
to subsurfaces program, and both libs getting really used, which leads
to disaster.
Do not build subsurfaces demo, if Cairo links to libGL and cairo-egl is
usable.
The GL rendering loop is not tied to the toytoolkit or the widget, but
runs directly from its own frame callback. Therefore it runs
independent of the rest of the application. This also relies on one of
two things:
- eglSwapInterval(0) is implemented, and therefore eglSwapBuffers never
blocks indefinitely, or
- toytoolkit has a workaround, that guarantees that eglSwapBuffers will
return soon, when we force a repaint on resize.
Otherwise the demo will deadlock.
The code is separated into three sections:
1. The library component, using only EGL, GLESv2, and libwayland-client
APIs, and not aware of any toolkit details of the parent application.
This runs independently until the parent application tells otherwise.
2. The glue code: a toytoolkit application widget, who has its own
rendering machinery.
3. The application written in toytoolkit.
This patch also adds new toytoolkit interfaces:
- widget_get_wl_surface()
- widget_get_last_time()
- widget_input_region_add()
Toytoolkit applications have not had a possibility to change the input
region. The frame widget (decorations) set the input region on its own
when used, otherwise the default input region of everything has been
used. If a window does not have a frame widget, it can now use
widget_input_region_add() to set a custom input region.
These are not window methods, because a widget may lie on a different
wl_surface (sub-surface) than the window.
Changes in v3:
- replace set_commit_mode with set_sync and set_desync
Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
2013-04-25 14:57:50 +04:00
|
|
|
widget_set_resize_handler(tri->widget, triangle_resize_handler);
|
|
|
|
widget_set_redraw_handler(tri->widget, triangle_redraw_handler);
|
|
|
|
|
|
|
|
set_empty_input_region(tri->widget, window_get_display(window));
|
|
|
|
|
|
|
|
return tri;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
triangle_destroy(struct triangle *tri)
|
|
|
|
{
|
|
|
|
if (tri->egl_surface)
|
|
|
|
eglDestroySurface(tri->egl->dpy, tri->egl_surface);
|
|
|
|
|
|
|
|
if (tri->egl_window)
|
|
|
|
wl_egl_window_destroy(tri->egl_window);
|
|
|
|
|
|
|
|
widget_destroy(tri->widget);
|
|
|
|
free(tri);
|
|
|
|
}
|
|
|
|
|
|
|
|
/************** The toytoolkit application code: *********************/
|
|
|
|
|
|
|
|
struct demoapp {
|
|
|
|
struct display *display;
|
|
|
|
struct window *window;
|
|
|
|
struct widget *widget;
|
|
|
|
struct widget *subsurface;
|
|
|
|
|
|
|
|
struct egl_state *egl;
|
|
|
|
struct triangle *triangle;
|
|
|
|
|
|
|
|
int animate;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
draw_spinner(cairo_t *cr, const struct rectangle *rect, uint32_t time)
|
|
|
|
{
|
|
|
|
double cx, cy, r, angle;
|
|
|
|
unsigned t;
|
|
|
|
|
|
|
|
cx = rect->x + rect->width / 2;
|
|
|
|
cy = rect->y + rect->height / 2;
|
|
|
|
r = (rect->width < rect->height ? rect->width : rect->height) * 0.3;
|
|
|
|
t = time % 2000;
|
|
|
|
angle = t * (M_PI / 500.0);
|
|
|
|
|
|
|
|
cairo_set_line_width(cr, 4.0);
|
|
|
|
|
|
|
|
if (t < 1000)
|
|
|
|
cairo_arc(cr, cx, cy, r, 0.0, angle);
|
|
|
|
else
|
|
|
|
cairo_arc(cr, cx, cy, r, angle, 0.0);
|
|
|
|
|
|
|
|
cairo_stroke(cr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sub_redraw_handler(struct widget *widget, void *data)
|
|
|
|
{
|
|
|
|
struct demoapp *app = data;
|
|
|
|
cairo_t *cr;
|
|
|
|
struct rectangle allocation;
|
|
|
|
uint32_t time;
|
|
|
|
|
|
|
|
widget_get_allocation(app->subsurface, &allocation);
|
|
|
|
|
|
|
|
cr = widget_cairo_create(widget);
|
|
|
|
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
|
|
|
|
|
|
|
|
/* debug: paint whole surface magenta; no magenta should show */
|
|
|
|
cairo_set_source_rgba(cr, 0.9, 0.0, 0.9, 1.0);
|
|
|
|
cairo_paint(cr);
|
|
|
|
|
|
|
|
cairo_rectangle(cr,
|
|
|
|
allocation.x,
|
|
|
|
allocation.y,
|
|
|
|
allocation.width,
|
|
|
|
allocation.height);
|
|
|
|
cairo_clip(cr);
|
|
|
|
|
|
|
|
cairo_set_source_rgba(cr, 0.8, 0, 0, 0.8);
|
|
|
|
cairo_paint(cr);
|
|
|
|
|
|
|
|
time = widget_get_last_time(widget);
|
|
|
|
cairo_set_source_rgba(cr, 1.0, 0.5, 0.5, 1.0);
|
|
|
|
draw_spinner(cr, &allocation, time);
|
|
|
|
|
|
|
|
cairo_destroy(cr);
|
|
|
|
|
|
|
|
if (app->animate)
|
|
|
|
widget_schedule_redraw(app->subsurface);
|
|
|
|
DBG("%dx%d @ %d,%d, last time %u\n",
|
|
|
|
allocation.width, allocation.height,
|
|
|
|
allocation.x, allocation.y, time);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sub_resize_handler(struct widget *widget,
|
|
|
|
int32_t width, int32_t height, void *data)
|
|
|
|
{
|
|
|
|
DBG("%dx%d\n", width, height);
|
|
|
|
widget_input_region_add(widget, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
redraw_handler(struct widget *widget, void *data)
|
|
|
|
{
|
|
|
|
struct demoapp *app = data;
|
|
|
|
cairo_t *cr;
|
|
|
|
struct rectangle allocation;
|
|
|
|
uint32_t time;
|
|
|
|
|
|
|
|
widget_get_allocation(app->widget, &allocation);
|
|
|
|
|
|
|
|
cr = widget_cairo_create(widget);
|
|
|
|
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
|
|
|
|
cairo_rectangle(cr,
|
|
|
|
allocation.x,
|
|
|
|
allocation.y,
|
|
|
|
allocation.width,
|
|
|
|
allocation.height);
|
|
|
|
cairo_set_source_rgba(cr, 0, 0.8, 0, 0.8);
|
|
|
|
cairo_fill(cr);
|
|
|
|
|
|
|
|
time = widget_get_last_time(widget);
|
|
|
|
cairo_set_source_rgba(cr, 0.5, 1.0, 0.5, 1.0);
|
|
|
|
draw_spinner(cr, &allocation, time);
|
|
|
|
|
|
|
|
cairo_destroy(cr);
|
|
|
|
|
|
|
|
DBG("%dx%d @ %d,%d, last time %u\n",
|
|
|
|
allocation.width, allocation.height,
|
|
|
|
allocation.x, allocation.y, time);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
resize_handler(struct widget *widget,
|
|
|
|
int32_t width, int32_t height, void *data)
|
|
|
|
{
|
|
|
|
struct demoapp *app = data;
|
|
|
|
struct rectangle area;
|
|
|
|
int side, h;
|
|
|
|
|
|
|
|
widget_get_allocation(widget, &area);
|
|
|
|
|
|
|
|
side = area.width < area.height ? area.width / 2 : area.height / 2;
|
|
|
|
h = area.height - side;
|
|
|
|
|
|
|
|
widget_set_allocation(app->subsurface,
|
|
|
|
area.x + area.width - side,
|
|
|
|
area.y,
|
|
|
|
side, h);
|
|
|
|
|
|
|
|
if (app->triangle) {
|
|
|
|
widget_set_allocation(app->triangle->widget,
|
|
|
|
area.x + area.width - side,
|
|
|
|
area.y + h,
|
|
|
|
side, side);
|
|
|
|
}
|
|
|
|
|
|
|
|
DBG("green %dx%d, red %dx%d, GL %dx%d\n",
|
|
|
|
area.width, area.height, side, h, side, side);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
keyboard_focus_handler(struct window *window,
|
|
|
|
struct input *device, void *data)
|
|
|
|
{
|
|
|
|
struct demoapp *app = data;
|
|
|
|
|
|
|
|
window_schedule_redraw(app->window);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
key_handler(struct window *window, struct input *input, uint32_t time,
|
|
|
|
uint32_t key, uint32_t sym,
|
|
|
|
enum wl_keyboard_key_state state, void *data)
|
|
|
|
{
|
|
|
|
struct demoapp *app = data;
|
|
|
|
struct rectangle winrect;
|
|
|
|
|
|
|
|
if (state == WL_KEYBOARD_KEY_STATE_RELEASED)
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch (sym) {
|
|
|
|
case XKB_KEY_space:
|
|
|
|
app->animate = !app->animate;
|
|
|
|
window_schedule_redraw(window);
|
|
|
|
break;
|
|
|
|
case XKB_KEY_Up:
|
|
|
|
window_get_allocation(window, &winrect);
|
|
|
|
winrect.height -= 100;
|
|
|
|
if (winrect.height < 150)
|
|
|
|
winrect.height = 150;
|
|
|
|
window_schedule_resize(window, winrect.width, winrect.height);
|
|
|
|
break;
|
|
|
|
case XKB_KEY_Down:
|
|
|
|
window_get_allocation(window, &winrect);
|
|
|
|
winrect.height += 100;
|
|
|
|
if (winrect.height > 600)
|
|
|
|
winrect.height = 600;
|
|
|
|
window_schedule_resize(window, winrect.width, winrect.height);
|
|
|
|
break;
|
|
|
|
case XKB_KEY_Escape:
|
|
|
|
display_exit(app->display);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct demoapp *
|
|
|
|
demoapp_create(struct display *display)
|
|
|
|
{
|
|
|
|
struct demoapp *app;
|
|
|
|
|
2013-08-08 02:34:59 +04:00
|
|
|
app = xmalloc(sizeof *app);
|
|
|
|
memset(app, 0, sizeof *app);
|
clients: add subsurfaces demo
Add a demo program with:
- a main surface (green)
- a Cairo-image sub-surface (red)
- a raw GLESv2 widget (triangle)
Sub-surface input region is set empty to avoid problems in toytoolkit.
If Cairo links to libGL, then we will end up with also libGLESv2 linked
to subsurfaces program, and both libs getting really used, which leads
to disaster.
Do not build subsurfaces demo, if Cairo links to libGL and cairo-egl is
usable.
The GL rendering loop is not tied to the toytoolkit or the widget, but
runs directly from its own frame callback. Therefore it runs
independent of the rest of the application. This also relies on one of
two things:
- eglSwapInterval(0) is implemented, and therefore eglSwapBuffers never
blocks indefinitely, or
- toytoolkit has a workaround, that guarantees that eglSwapBuffers will
return soon, when we force a repaint on resize.
Otherwise the demo will deadlock.
The code is separated into three sections:
1. The library component, using only EGL, GLESv2, and libwayland-client
APIs, and not aware of any toolkit details of the parent application.
This runs independently until the parent application tells otherwise.
2. The glue code: a toytoolkit application widget, who has its own
rendering machinery.
3. The application written in toytoolkit.
This patch also adds new toytoolkit interfaces:
- widget_get_wl_surface()
- widget_get_last_time()
- widget_input_region_add()
Toytoolkit applications have not had a possibility to change the input
region. The frame widget (decorations) set the input region on its own
when used, otherwise the default input region of everything has been
used. If a window does not have a frame widget, it can now use
widget_input_region_add() to set a custom input region.
These are not window methods, because a widget may lie on a different
wl_surface (sub-surface) than the window.
Changes in v3:
- replace set_commit_mode with set_sync and set_desync
Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
2013-04-25 14:57:50 +04:00
|
|
|
|
|
|
|
app->egl = egl_state_create(display_get_display(display));
|
|
|
|
|
|
|
|
app->display = display;
|
|
|
|
display_set_user_data(app->display, app);
|
|
|
|
|
|
|
|
app->window = window_create(app->display);
|
2013-10-14 04:08:38 +04:00
|
|
|
app->widget = window_frame_create(app->window, app);
|
clients: add subsurfaces demo
Add a demo program with:
- a main surface (green)
- a Cairo-image sub-surface (red)
- a raw GLESv2 widget (triangle)
Sub-surface input region is set empty to avoid problems in toytoolkit.
If Cairo links to libGL, then we will end up with also libGLESv2 linked
to subsurfaces program, and both libs getting really used, which leads
to disaster.
Do not build subsurfaces demo, if Cairo links to libGL and cairo-egl is
usable.
The GL rendering loop is not tied to the toytoolkit or the widget, but
runs directly from its own frame callback. Therefore it runs
independent of the rest of the application. This also relies on one of
two things:
- eglSwapInterval(0) is implemented, and therefore eglSwapBuffers never
blocks indefinitely, or
- toytoolkit has a workaround, that guarantees that eglSwapBuffers will
return soon, when we force a repaint on resize.
Otherwise the demo will deadlock.
The code is separated into three sections:
1. The library component, using only EGL, GLESv2, and libwayland-client
APIs, and not aware of any toolkit details of the parent application.
This runs independently until the parent application tells otherwise.
2. The glue code: a toytoolkit application widget, who has its own
rendering machinery.
3. The application written in toytoolkit.
This patch also adds new toytoolkit interfaces:
- widget_get_wl_surface()
- widget_get_last_time()
- widget_input_region_add()
Toytoolkit applications have not had a possibility to change the input
region. The frame widget (decorations) set the input region on its own
when used, otherwise the default input region of everything has been
used. If a window does not have a frame widget, it can now use
widget_input_region_add() to set a custom input region.
These are not window methods, because a widget may lie on a different
wl_surface (sub-surface) than the window.
Changes in v3:
- replace set_commit_mode with set_sync and set_desync
Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
2013-04-25 14:57:50 +04:00
|
|
|
window_set_title(app->window, "Wayland Sub-surface Demo");
|
|
|
|
|
|
|
|
window_set_key_handler(app->window, key_handler);
|
|
|
|
window_set_user_data(app->window, app);
|
|
|
|
window_set_keyboard_focus_handler(app->window, keyboard_focus_handler);
|
|
|
|
|
|
|
|
widget_set_redraw_handler(app->widget, redraw_handler);
|
|
|
|
widget_set_resize_handler(app->widget, resize_handler);
|
|
|
|
|
|
|
|
app->subsurface = window_add_subsurface(app->window, app,
|
|
|
|
int_to_mode(option_red_mode));
|
|
|
|
widget_set_redraw_handler(app->subsurface, sub_redraw_handler);
|
|
|
|
widget_set_resize_handler(app->subsurface, sub_resize_handler);
|
|
|
|
|
|
|
|
if (app->egl && !option_no_triangle)
|
|
|
|
app->triangle = triangle_create(app->window, app->egl);
|
|
|
|
|
|
|
|
/* minimum size */
|
|
|
|
widget_schedule_resize(app->widget, 100, 100);
|
|
|
|
|
|
|
|
/* initial size */
|
|
|
|
widget_schedule_resize(app->widget, 400, 300);
|
|
|
|
|
|
|
|
app->animate = 1;
|
|
|
|
|
|
|
|
return app;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
demoapp_destroy(struct demoapp *app)
|
|
|
|
{
|
|
|
|
if (app->triangle)
|
|
|
|
triangle_destroy(app->triangle);
|
|
|
|
|
|
|
|
if (app->egl)
|
|
|
|
egl_state_destroy(app->egl);
|
|
|
|
|
|
|
|
widget_destroy(app->subsurface);
|
|
|
|
widget_destroy(app->widget);
|
|
|
|
window_destroy(app->window);
|
|
|
|
free(app);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
struct display *display;
|
|
|
|
struct demoapp *app;
|
|
|
|
|
2014-08-08 23:59:53 +04:00
|
|
|
if (parse_options(options, ARRAY_LENGTH(options), &argc, argv) > 1
|
|
|
|
|| option_help) {
|
clients: add subsurfaces demo
Add a demo program with:
- a main surface (green)
- a Cairo-image sub-surface (red)
- a raw GLESv2 widget (triangle)
Sub-surface input region is set empty to avoid problems in toytoolkit.
If Cairo links to libGL, then we will end up with also libGLESv2 linked
to subsurfaces program, and both libs getting really used, which leads
to disaster.
Do not build subsurfaces demo, if Cairo links to libGL and cairo-egl is
usable.
The GL rendering loop is not tied to the toytoolkit or the widget, but
runs directly from its own frame callback. Therefore it runs
independent of the rest of the application. This also relies on one of
two things:
- eglSwapInterval(0) is implemented, and therefore eglSwapBuffers never
blocks indefinitely, or
- toytoolkit has a workaround, that guarantees that eglSwapBuffers will
return soon, when we force a repaint on resize.
Otherwise the demo will deadlock.
The code is separated into three sections:
1. The library component, using only EGL, GLESv2, and libwayland-client
APIs, and not aware of any toolkit details of the parent application.
This runs independently until the parent application tells otherwise.
2. The glue code: a toytoolkit application widget, who has its own
rendering machinery.
3. The application written in toytoolkit.
This patch also adds new toytoolkit interfaces:
- widget_get_wl_surface()
- widget_get_last_time()
- widget_input_region_add()
Toytoolkit applications have not had a possibility to change the input
region. The frame widget (decorations) set the input region on its own
when used, otherwise the default input region of everything has been
used. If a window does not have a frame widget, it can now use
widget_input_region_add() to set a custom input region.
These are not window methods, because a widget may lie on a different
wl_surface (sub-surface) than the window.
Changes in v3:
- replace set_commit_mode with set_sync and set_desync
Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
2013-04-25 14:57:50 +04:00
|
|
|
printf(help_text, argv[0]);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
display = display_create(&argc, argv);
|
|
|
|
if (display == NULL) {
|
|
|
|
fprintf(stderr, "failed to create display: %m\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-08-15 22:54:03 +04:00
|
|
|
if (!display_has_subcompositor(display)) {
|
|
|
|
fprintf(stderr, "compositor does not support "
|
|
|
|
"the subcompositor extension\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
clients: add subsurfaces demo
Add a demo program with:
- a main surface (green)
- a Cairo-image sub-surface (red)
- a raw GLESv2 widget (triangle)
Sub-surface input region is set empty to avoid problems in toytoolkit.
If Cairo links to libGL, then we will end up with also libGLESv2 linked
to subsurfaces program, and both libs getting really used, which leads
to disaster.
Do not build subsurfaces demo, if Cairo links to libGL and cairo-egl is
usable.
The GL rendering loop is not tied to the toytoolkit or the widget, but
runs directly from its own frame callback. Therefore it runs
independent of the rest of the application. This also relies on one of
two things:
- eglSwapInterval(0) is implemented, and therefore eglSwapBuffers never
blocks indefinitely, or
- toytoolkit has a workaround, that guarantees that eglSwapBuffers will
return soon, when we force a repaint on resize.
Otherwise the demo will deadlock.
The code is separated into three sections:
1. The library component, using only EGL, GLESv2, and libwayland-client
APIs, and not aware of any toolkit details of the parent application.
This runs independently until the parent application tells otherwise.
2. The glue code: a toytoolkit application widget, who has its own
rendering machinery.
3. The application written in toytoolkit.
This patch also adds new toytoolkit interfaces:
- widget_get_wl_surface()
- widget_get_last_time()
- widget_input_region_add()
Toytoolkit applications have not had a possibility to change the input
region. The frame widget (decorations) set the input region on its own
when used, otherwise the default input region of everything has been
used. If a window does not have a frame widget, it can now use
widget_input_region_add() to set a custom input region.
These are not window methods, because a widget may lie on a different
wl_surface (sub-surface) than the window.
Changes in v3:
- replace set_commit_mode with set_sync and set_desync
Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
2013-04-25 14:57:50 +04:00
|
|
|
app = demoapp_create(display);
|
|
|
|
|
|
|
|
display_run(display);
|
|
|
|
|
|
|
|
demoapp_destroy(app);
|
|
|
|
display_destroy(display);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|