mirror of
https://github.com/brl/mutter.git
synced 2024-11-25 01:20:42 -05:00
cogl/winsys/egl: Move out onscreen code to own file
As a preparation turning it into its own type, move the code related to CoglOnscreen to its own file. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1514>
This commit is contained in:
parent
d4dbcf3983
commit
b24d5ce1dd
@ -399,6 +399,8 @@ if have_egl
|
|||||||
]
|
]
|
||||||
cogl_sources += [
|
cogl_sources += [
|
||||||
'cogl-egl-private.h',
|
'cogl-egl-private.h',
|
||||||
|
'winsys/cogl-onscreen-egl.c',
|
||||||
|
'winsys/cogl-onscreen-egl.h',
|
||||||
'winsys/cogl-winsys-egl.c',
|
'winsys/cogl-winsys-egl.c',
|
||||||
'winsys/cogl-winsys-egl-feature-functions.h',
|
'winsys/cogl-winsys-egl-feature-functions.h',
|
||||||
'winsys/cogl-winsys-egl-private.h',
|
'winsys/cogl-winsys-egl-private.h',
|
||||||
|
309
cogl/cogl/winsys/cogl-onscreen-egl.c
Normal file
309
cogl/cogl/winsys/cogl-onscreen-egl.c
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2007,2008,2009,2010,2011,2013 Intel Corporation.
|
||||||
|
* Copyright (C) 2020 Red Hat
|
||||||
|
*
|
||||||
|
* 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 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "cogl-config.h"
|
||||||
|
|
||||||
|
#include "winsys/cogl-onscreen-egl.h"
|
||||||
|
|
||||||
|
#include "cogl-context-private.h"
|
||||||
|
#include "cogl-renderer-private.h"
|
||||||
|
#include "cogl-trace.h"
|
||||||
|
#include "winsys/cogl-winsys-egl-private.h"
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
_cogl_winsys_onscreen_egl_init (CoglOnscreen *onscreen,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
||||||
|
CoglContext *context = cogl_framebuffer_get_context (framebuffer);
|
||||||
|
CoglDisplay *display = context->display;
|
||||||
|
CoglDisplayEGL *egl_display = display->winsys;
|
||||||
|
CoglRenderer *renderer = display->renderer;
|
||||||
|
CoglRendererEGL *egl_renderer = renderer->winsys;
|
||||||
|
const CoglFramebufferConfig *config;
|
||||||
|
EGLint attributes[MAX_EGL_CONFIG_ATTRIBS];
|
||||||
|
EGLConfig egl_config;
|
||||||
|
EGLint config_count = 0;
|
||||||
|
EGLBoolean status;
|
||||||
|
CoglOnscreenEGL *winsys;
|
||||||
|
|
||||||
|
g_return_val_if_fail (egl_display->egl_context, FALSE);
|
||||||
|
|
||||||
|
config = cogl_framebuffer_get_config (framebuffer);
|
||||||
|
cogl_display_egl_determine_attributes (display, config, attributes);
|
||||||
|
|
||||||
|
status = eglChooseConfig (egl_renderer->edpy,
|
||||||
|
attributes,
|
||||||
|
&egl_config, 1,
|
||||||
|
&config_count);
|
||||||
|
if (status != EGL_TRUE || config_count == 0)
|
||||||
|
{
|
||||||
|
g_set_error (error, COGL_WINSYS_ERROR,
|
||||||
|
COGL_WINSYS_ERROR_CREATE_ONSCREEN,
|
||||||
|
"Failed to find a suitable EGL configuration");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update the real number of samples_per_pixel now that we have
|
||||||
|
* found an egl_config... */
|
||||||
|
if (config->samples_per_pixel)
|
||||||
|
{
|
||||||
|
EGLint samples;
|
||||||
|
status = eglGetConfigAttrib (egl_renderer->edpy,
|
||||||
|
egl_config,
|
||||||
|
EGL_SAMPLES, &samples);
|
||||||
|
g_return_val_if_fail (status == EGL_TRUE, TRUE);
|
||||||
|
cogl_framebuffer_update_samples_per_pixel (framebuffer, samples);
|
||||||
|
}
|
||||||
|
|
||||||
|
winsys = g_slice_new0 (CoglOnscreenEGL);
|
||||||
|
cogl_onscreen_set_winsys (onscreen, winsys);
|
||||||
|
|
||||||
|
if (egl_renderer->platform_vtable->onscreen_init &&
|
||||||
|
!egl_renderer->platform_vtable->onscreen_init (onscreen,
|
||||||
|
egl_config,
|
||||||
|
error))
|
||||||
|
{
|
||||||
|
g_slice_free (CoglOnscreenEGL, winsys);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_winsys_onscreen_egl_deinit (CoglOnscreen *onscreen)
|
||||||
|
{
|
||||||
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
||||||
|
CoglContext *context = cogl_framebuffer_get_context (framebuffer);
|
||||||
|
CoglDisplayEGL *egl_display = context->display->winsys;
|
||||||
|
CoglRenderer *renderer = context->display->renderer;
|
||||||
|
CoglRendererEGL *egl_renderer = renderer->winsys;
|
||||||
|
CoglOnscreenEGL *egl_onscreen = cogl_onscreen_get_winsys (onscreen);
|
||||||
|
|
||||||
|
/* If we never successfully allocated then there's nothing to do */
|
||||||
|
if (egl_onscreen == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (egl_onscreen->egl_surface != EGL_NO_SURFACE)
|
||||||
|
{
|
||||||
|
/* Cogl always needs a valid context bound to something so if we
|
||||||
|
* are destroying the onscreen that is currently bound we'll
|
||||||
|
* switch back to the dummy drawable. */
|
||||||
|
if ((egl_display->dummy_surface != EGL_NO_SURFACE ||
|
||||||
|
(egl_renderer->private_features &
|
||||||
|
COGL_EGL_WINSYS_FEATURE_SURFACELESS_CONTEXT) != 0) &&
|
||||||
|
(egl_display->current_draw_surface == egl_onscreen->egl_surface ||
|
||||||
|
egl_display->current_read_surface == egl_onscreen->egl_surface))
|
||||||
|
{
|
||||||
|
_cogl_winsys_egl_make_current (context->display,
|
||||||
|
egl_display->dummy_surface,
|
||||||
|
egl_display->dummy_surface,
|
||||||
|
egl_display->current_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eglDestroySurface (egl_renderer->edpy, egl_onscreen->egl_surface)
|
||||||
|
== EGL_FALSE)
|
||||||
|
g_warning ("Failed to destroy EGL surface");
|
||||||
|
egl_onscreen->egl_surface = EGL_NO_SURFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (egl_renderer->platform_vtable->onscreen_deinit)
|
||||||
|
egl_renderer->platform_vtable->onscreen_deinit (onscreen);
|
||||||
|
|
||||||
|
g_slice_free (CoglOnscreenEGL, cogl_onscreen_get_winsys (onscreen));
|
||||||
|
cogl_onscreen_set_winsys (onscreen, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
bind_onscreen_with_context (CoglOnscreen *onscreen,
|
||||||
|
EGLContext egl_context)
|
||||||
|
{
|
||||||
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
||||||
|
CoglContext *context = cogl_framebuffer_get_context (framebuffer);
|
||||||
|
CoglOnscreenEGL *egl_onscreen = cogl_onscreen_get_winsys (onscreen);
|
||||||
|
|
||||||
|
gboolean status = _cogl_winsys_egl_make_current (context->display,
|
||||||
|
egl_onscreen->egl_surface,
|
||||||
|
egl_onscreen->egl_surface,
|
||||||
|
egl_context);
|
||||||
|
if (status)
|
||||||
|
{
|
||||||
|
CoglRenderer *renderer = context->display->renderer;
|
||||||
|
CoglRendererEGL *egl_renderer = renderer->winsys;
|
||||||
|
|
||||||
|
eglSwapInterval (egl_renderer->edpy, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
bind_onscreen (CoglOnscreen *onscreen)
|
||||||
|
{
|
||||||
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
||||||
|
CoglContext *context = cogl_framebuffer_get_context (framebuffer);
|
||||||
|
CoglDisplayEGL *egl_display = context->display->winsys;
|
||||||
|
|
||||||
|
return bind_onscreen_with_context (onscreen, egl_display->egl_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_winsys_onscreen_egl_bind (CoglOnscreen *onscreen)
|
||||||
|
{
|
||||||
|
bind_onscreen (onscreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef EGL_BUFFER_AGE_EXT
|
||||||
|
#define EGL_BUFFER_AGE_EXT 0x313D
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int
|
||||||
|
_cogl_winsys_onscreen_egl_get_buffer_age (CoglOnscreen *onscreen)
|
||||||
|
{
|
||||||
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
||||||
|
CoglContext *context = cogl_framebuffer_get_context (framebuffer);
|
||||||
|
CoglRenderer *renderer = context->display->renderer;
|
||||||
|
CoglRendererEGL *egl_renderer = renderer->winsys;
|
||||||
|
CoglOnscreenEGL *egl_onscreen = cogl_onscreen_get_winsys (onscreen);
|
||||||
|
CoglDisplayEGL *egl_display = context->display->winsys;
|
||||||
|
EGLSurface surface = egl_onscreen->egl_surface;
|
||||||
|
static gboolean warned = FALSE;
|
||||||
|
int age = 0;
|
||||||
|
|
||||||
|
if (!(egl_renderer->private_features & COGL_EGL_WINSYS_FEATURE_BUFFER_AGE))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!_cogl_winsys_egl_make_current (context->display,
|
||||||
|
surface, surface,
|
||||||
|
egl_display->egl_context))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!eglQuerySurface (egl_renderer->edpy, surface, EGL_BUFFER_AGE_EXT, &age))
|
||||||
|
{
|
||||||
|
if (!warned)
|
||||||
|
g_critical ("Failed to query buffer age, got error %x", eglGetError ());
|
||||||
|
warned = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
warned = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return age;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_winsys_onscreen_egl_swap_region (CoglOnscreen *onscreen,
|
||||||
|
const int *user_rectangles,
|
||||||
|
int n_rectangles,
|
||||||
|
CoglFrameInfo *info,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
||||||
|
CoglContext *context = cogl_framebuffer_get_context (framebuffer);
|
||||||
|
CoglRenderer *renderer = context->display->renderer;
|
||||||
|
CoglRendererEGL *egl_renderer = renderer->winsys;
|
||||||
|
CoglOnscreenEGL *egl_onscreen = cogl_onscreen_get_winsys (onscreen);
|
||||||
|
int framebuffer_height = cogl_framebuffer_get_height (framebuffer);
|
||||||
|
int *rectangles = g_alloca (sizeof (int) * n_rectangles * 4);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* eglSwapBuffersRegion expects rectangles relative to the
|
||||||
|
* bottom left corner but we are given rectangles relative to
|
||||||
|
* the top left so we need to flip them... */
|
||||||
|
memcpy (rectangles, user_rectangles, sizeof (int) * n_rectangles * 4);
|
||||||
|
for (i = 0; i < n_rectangles; i++)
|
||||||
|
{
|
||||||
|
int *rect = &rectangles[4 * i];
|
||||||
|
rect[1] = framebuffer_height - rect[1] - rect[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* At least for eglSwapBuffers the EGL spec says that the surface to
|
||||||
|
swap must be bound to the current context. It looks like Mesa
|
||||||
|
also validates that this is the case for eglSwapBuffersRegion so
|
||||||
|
we must bind here too */
|
||||||
|
_cogl_framebuffer_flush_state (COGL_FRAMEBUFFER (onscreen),
|
||||||
|
COGL_FRAMEBUFFER (onscreen),
|
||||||
|
COGL_FRAMEBUFFER_STATE_BIND);
|
||||||
|
|
||||||
|
if (egl_renderer->pf_eglSwapBuffersRegion (egl_renderer->edpy,
|
||||||
|
egl_onscreen->egl_surface,
|
||||||
|
n_rectangles,
|
||||||
|
rectangles) == EGL_FALSE)
|
||||||
|
g_warning ("Error reported by eglSwapBuffersRegion");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_winsys_onscreen_egl_swap_buffers_with_damage (CoglOnscreen *onscreen,
|
||||||
|
const int *rectangles,
|
||||||
|
int n_rectangles,
|
||||||
|
CoglFrameInfo *info,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
||||||
|
CoglContext *context = cogl_framebuffer_get_context (framebuffer);
|
||||||
|
CoglRenderer *renderer = context->display->renderer;
|
||||||
|
CoglRendererEGL *egl_renderer = renderer->winsys;
|
||||||
|
CoglOnscreenEGL *egl_onscreen = cogl_onscreen_get_winsys (onscreen);
|
||||||
|
|
||||||
|
COGL_TRACE_BEGIN_SCOPED (CoglOnscreenEGLSwapBuffersWithDamage,
|
||||||
|
"Onscreen (eglSwapBuffers)");
|
||||||
|
|
||||||
|
/* The specification for EGL (at least in 1.4) says that the surface
|
||||||
|
needs to be bound to the current context for the swap to work
|
||||||
|
although it may change in future. Mesa explicitly checks for this
|
||||||
|
and just returns an error if this is not the case so we can't
|
||||||
|
just pretend this isn't in the spec. */
|
||||||
|
_cogl_framebuffer_flush_state (COGL_FRAMEBUFFER (onscreen),
|
||||||
|
COGL_FRAMEBUFFER (onscreen),
|
||||||
|
COGL_FRAMEBUFFER_STATE_BIND);
|
||||||
|
|
||||||
|
if (n_rectangles && egl_renderer->pf_eglSwapBuffersWithDamage)
|
||||||
|
{
|
||||||
|
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
||||||
|
size_t size = n_rectangles * sizeof (int) * 4;
|
||||||
|
int *flipped = alloca (size);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
memcpy (flipped, rectangles, size);
|
||||||
|
for (i = 0; i < n_rectangles; i++)
|
||||||
|
{
|
||||||
|
const int *rect = rectangles + 4 * i;
|
||||||
|
int *flip_rect = flipped + 4 * i;
|
||||||
|
|
||||||
|
flip_rect[1] =
|
||||||
|
cogl_framebuffer_get_height (framebuffer) - rect[1] - rect[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (egl_renderer->pf_eglSwapBuffersWithDamage (egl_renderer->edpy,
|
||||||
|
egl_onscreen->egl_surface,
|
||||||
|
flipped,
|
||||||
|
n_rectangles) == EGL_FALSE)
|
||||||
|
g_warning ("Error reported by eglSwapBuffersWithDamage");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
eglSwapBuffers (egl_renderer->edpy, egl_onscreen->egl_surface);
|
||||||
|
}
|
58
cogl/cogl/winsys/cogl-onscreen-egl.h
Normal file
58
cogl/cogl/winsys/cogl-onscreen-egl.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2007,2008,2009,2010,2011,2013 Intel Corporation.
|
||||||
|
* Copyright (C) 2020 Red Hat
|
||||||
|
*
|
||||||
|
* 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 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 COGL_ONSCREEN_EGL_H
|
||||||
|
#define COGL_ONSCREEN_EGL_H
|
||||||
|
|
||||||
|
#include "cogl-onscreen.h"
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
_cogl_winsys_onscreen_egl_init (CoglOnscreen *onscreen,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_winsys_onscreen_egl_deinit (CoglOnscreen *onscreen);
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_winsys_onscreen_egl_bind (CoglOnscreen *onscreen);
|
||||||
|
|
||||||
|
int
|
||||||
|
_cogl_winsys_onscreen_egl_get_buffer_age (CoglOnscreen *onscreen);
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_winsys_onscreen_egl_swap_region (CoglOnscreen *onscreen,
|
||||||
|
const int *user_rectangles,
|
||||||
|
int n_rectangles,
|
||||||
|
CoglFrameInfo *info,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
void
|
||||||
|
_cogl_winsys_onscreen_egl_swap_buffers_with_damage (CoglOnscreen *onscreen,
|
||||||
|
const int *rectangles,
|
||||||
|
int n_rectangles,
|
||||||
|
CoglFrameInfo *info,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
#endif /* COGL_ONSCREEN_EGL_H */
|
@ -97,6 +97,8 @@ typedef struct _CoglWinsysEGLVtable
|
|||||||
GError **error);
|
GError **error);
|
||||||
} CoglWinsysEGLVtable;
|
} CoglWinsysEGLVtable;
|
||||||
|
|
||||||
|
#define MAX_EGL_CONFIG_ATTRIBS 30
|
||||||
|
|
||||||
typedef enum _CoglEGLWinsysFeature
|
typedef enum _CoglEGLWinsysFeature
|
||||||
{
|
{
|
||||||
COGL_EGL_WINSYS_FEATURE_SWAP_REGION =1L<<0,
|
COGL_EGL_WINSYS_FEATURE_SWAP_REGION =1L<<0,
|
||||||
@ -209,4 +211,9 @@ COGL_EXPORT gboolean
|
|||||||
_cogl_winsys_egl_renderer_connect_common (CoglRenderer *renderer,
|
_cogl_winsys_egl_renderer_connect_common (CoglRenderer *renderer,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
|
void
|
||||||
|
cogl_display_egl_determine_attributes (CoglDisplay *display,
|
||||||
|
const CoglFramebufferConfig *config,
|
||||||
|
EGLint *attributes);
|
||||||
|
|
||||||
#endif /* __COGL_WINSYS_EGL_PRIVATE_H */
|
#endif /* __COGL_WINSYS_EGL_PRIVATE_H */
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
#include "cogl-trace.h"
|
#include "cogl-trace.h"
|
||||||
#include "winsys/cogl-winsys-egl-private.h"
|
#include "winsys/cogl-winsys-egl-private.h"
|
||||||
#include "winsys/cogl-winsys-private.h"
|
#include "winsys/cogl-winsys-private.h"
|
||||||
|
#include "winsys/cogl-onscreen-egl.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -77,8 +78,6 @@
|
|||||||
#define EGL_CONTEXT_PRIORITY_LOW_IMG 0x3103
|
#define EGL_CONTEXT_PRIORITY_LOW_IMG 0x3103
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MAX_EGL_CONFIG_ATTRIBS 30
|
|
||||||
|
|
||||||
/* Define a set of arrays containing the functions required from GL
|
/* Define a set of arrays containing the functions required from GL
|
||||||
for each winsys feature */
|
for each winsys feature */
|
||||||
#define COGL_WINSYS_FEATURE_BEGIN(name, namespaces, extension_names, \
|
#define COGL_WINSYS_FEATURE_BEGIN(name, namespaces, extension_names, \
|
||||||
@ -194,8 +193,8 @@ _cogl_winsys_renderer_connect (CoglRenderer *renderer,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
egl_attributes_from_framebuffer_config (CoglDisplay *display,
|
cogl_display_egl_determine_attributes (CoglDisplay *display,
|
||||||
const CoglFramebufferConfig *config,
|
const CoglFramebufferConfig *config,
|
||||||
EGLint *attributes)
|
EGLint *attributes)
|
||||||
{
|
{
|
||||||
@ -371,7 +370,7 @@ try_create_context (CoglDisplay *display,
|
|||||||
else if (renderer->driver == COGL_DRIVER_GLES2)
|
else if (renderer->driver == COGL_DRIVER_GLES2)
|
||||||
eglBindAPI (EGL_OPENGL_ES_API);
|
eglBindAPI (EGL_OPENGL_ES_API);
|
||||||
|
|
||||||
egl_attributes_from_framebuffer_config (display,
|
cogl_display_egl_determine_attributes (display,
|
||||||
&display->onscreen_template->config,
|
&display->onscreen_template->config,
|
||||||
cfg_attribs);
|
cfg_attribs);
|
||||||
|
|
||||||
@ -584,282 +583,6 @@ _cogl_winsys_context_deinit (CoglContext *context)
|
|||||||
g_free (context->winsys);
|
g_free (context->winsys);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
_cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
|
||||||
CoglContext *context = cogl_framebuffer_get_context (framebuffer);
|
|
||||||
CoglDisplay *display = context->display;
|
|
||||||
CoglDisplayEGL *egl_display = display->winsys;
|
|
||||||
CoglRenderer *renderer = display->renderer;
|
|
||||||
CoglRendererEGL *egl_renderer = renderer->winsys;
|
|
||||||
const CoglFramebufferConfig *config;
|
|
||||||
EGLint attributes[MAX_EGL_CONFIG_ATTRIBS];
|
|
||||||
EGLConfig egl_config;
|
|
||||||
EGLint config_count = 0;
|
|
||||||
EGLBoolean status;
|
|
||||||
CoglOnscreenEGL *winsys;
|
|
||||||
|
|
||||||
g_return_val_if_fail (egl_display->egl_context, FALSE);
|
|
||||||
|
|
||||||
config = cogl_framebuffer_get_config (framebuffer);
|
|
||||||
egl_attributes_from_framebuffer_config (display, config, attributes);
|
|
||||||
|
|
||||||
status = eglChooseConfig (egl_renderer->edpy,
|
|
||||||
attributes,
|
|
||||||
&egl_config, 1,
|
|
||||||
&config_count);
|
|
||||||
if (status != EGL_TRUE || config_count == 0)
|
|
||||||
{
|
|
||||||
g_set_error (error, COGL_WINSYS_ERROR,
|
|
||||||
COGL_WINSYS_ERROR_CREATE_ONSCREEN,
|
|
||||||
"Failed to find a suitable EGL configuration");
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update the real number of samples_per_pixel now that we have
|
|
||||||
* found an egl_config... */
|
|
||||||
if (config->samples_per_pixel)
|
|
||||||
{
|
|
||||||
EGLint samples;
|
|
||||||
status = eglGetConfigAttrib (egl_renderer->edpy,
|
|
||||||
egl_config,
|
|
||||||
EGL_SAMPLES, &samples);
|
|
||||||
g_return_val_if_fail (status == EGL_TRUE, TRUE);
|
|
||||||
cogl_framebuffer_update_samples_per_pixel (framebuffer, samples);
|
|
||||||
}
|
|
||||||
|
|
||||||
winsys = g_slice_new0 (CoglOnscreenEGL);
|
|
||||||
cogl_onscreen_set_winsys (onscreen, winsys);
|
|
||||||
|
|
||||||
if (egl_renderer->platform_vtable->onscreen_init &&
|
|
||||||
!egl_renderer->platform_vtable->onscreen_init (onscreen,
|
|
||||||
egl_config,
|
|
||||||
error))
|
|
||||||
{
|
|
||||||
g_slice_free (CoglOnscreenEGL, winsys);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
_cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen)
|
|
||||||
{
|
|
||||||
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
|
||||||
CoglContext *context = cogl_framebuffer_get_context (framebuffer);
|
|
||||||
CoglDisplayEGL *egl_display = context->display->winsys;
|
|
||||||
CoglRenderer *renderer = context->display->renderer;
|
|
||||||
CoglRendererEGL *egl_renderer = renderer->winsys;
|
|
||||||
CoglOnscreenEGL *egl_onscreen = cogl_onscreen_get_winsys (onscreen);
|
|
||||||
|
|
||||||
/* If we never successfully allocated then there's nothing to do */
|
|
||||||
if (egl_onscreen == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (egl_onscreen->egl_surface != EGL_NO_SURFACE)
|
|
||||||
{
|
|
||||||
/* Cogl always needs a valid context bound to something so if we
|
|
||||||
* are destroying the onscreen that is currently bound we'll
|
|
||||||
* switch back to the dummy drawable. */
|
|
||||||
if ((egl_display->dummy_surface != EGL_NO_SURFACE ||
|
|
||||||
(egl_renderer->private_features &
|
|
||||||
COGL_EGL_WINSYS_FEATURE_SURFACELESS_CONTEXT) != 0) &&
|
|
||||||
(egl_display->current_draw_surface == egl_onscreen->egl_surface ||
|
|
||||||
egl_display->current_read_surface == egl_onscreen->egl_surface))
|
|
||||||
{
|
|
||||||
_cogl_winsys_egl_make_current (context->display,
|
|
||||||
egl_display->dummy_surface,
|
|
||||||
egl_display->dummy_surface,
|
|
||||||
egl_display->current_context);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eglDestroySurface (egl_renderer->edpy, egl_onscreen->egl_surface)
|
|
||||||
== EGL_FALSE)
|
|
||||||
g_warning ("Failed to destroy EGL surface");
|
|
||||||
egl_onscreen->egl_surface = EGL_NO_SURFACE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (egl_renderer->platform_vtable->onscreen_deinit)
|
|
||||||
egl_renderer->platform_vtable->onscreen_deinit (onscreen);
|
|
||||||
|
|
||||||
g_slice_free (CoglOnscreenEGL, cogl_onscreen_get_winsys (onscreen));
|
|
||||||
cogl_onscreen_set_winsys (onscreen, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
bind_onscreen_with_context (CoglOnscreen *onscreen,
|
|
||||||
EGLContext egl_context)
|
|
||||||
{
|
|
||||||
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
|
||||||
CoglContext *context = cogl_framebuffer_get_context (framebuffer);
|
|
||||||
CoglOnscreenEGL *egl_onscreen = cogl_onscreen_get_winsys (onscreen);
|
|
||||||
|
|
||||||
gboolean status = _cogl_winsys_egl_make_current (context->display,
|
|
||||||
egl_onscreen->egl_surface,
|
|
||||||
egl_onscreen->egl_surface,
|
|
||||||
egl_context);
|
|
||||||
if (status)
|
|
||||||
{
|
|
||||||
CoglRenderer *renderer = context->display->renderer;
|
|
||||||
CoglRendererEGL *egl_renderer = renderer->winsys;
|
|
||||||
|
|
||||||
eglSwapInterval (egl_renderer->edpy, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
bind_onscreen (CoglOnscreen *onscreen)
|
|
||||||
{
|
|
||||||
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
|
||||||
CoglContext *context = cogl_framebuffer_get_context (framebuffer);
|
|
||||||
CoglDisplayEGL *egl_display = context->display->winsys;
|
|
||||||
|
|
||||||
return bind_onscreen_with_context (onscreen, egl_display->egl_context);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
_cogl_winsys_onscreen_bind (CoglOnscreen *onscreen)
|
|
||||||
{
|
|
||||||
bind_onscreen (onscreen);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef EGL_BUFFER_AGE_EXT
|
|
||||||
#define EGL_BUFFER_AGE_EXT 0x313D
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int
|
|
||||||
_cogl_winsys_onscreen_get_buffer_age (CoglOnscreen *onscreen)
|
|
||||||
{
|
|
||||||
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
|
||||||
CoglContext *context = cogl_framebuffer_get_context (framebuffer);
|
|
||||||
CoglRenderer *renderer = context->display->renderer;
|
|
||||||
CoglRendererEGL *egl_renderer = renderer->winsys;
|
|
||||||
CoglOnscreenEGL *egl_onscreen = cogl_onscreen_get_winsys (onscreen);
|
|
||||||
CoglDisplayEGL *egl_display = context->display->winsys;
|
|
||||||
EGLSurface surface = egl_onscreen->egl_surface;
|
|
||||||
static gboolean warned = FALSE;
|
|
||||||
int age = 0;
|
|
||||||
|
|
||||||
if (!(egl_renderer->private_features & COGL_EGL_WINSYS_FEATURE_BUFFER_AGE))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!_cogl_winsys_egl_make_current (context->display,
|
|
||||||
surface, surface,
|
|
||||||
egl_display->egl_context))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!eglQuerySurface (egl_renderer->edpy, surface, EGL_BUFFER_AGE_EXT, &age))
|
|
||||||
{
|
|
||||||
if (!warned)
|
|
||||||
g_critical ("Failed to query buffer age, got error %x", eglGetError ());
|
|
||||||
warned = TRUE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
warned = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return age;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
_cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen,
|
|
||||||
const int *user_rectangles,
|
|
||||||
int n_rectangles,
|
|
||||||
CoglFrameInfo *info,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
|
||||||
CoglContext *context = cogl_framebuffer_get_context (framebuffer);
|
|
||||||
CoglRenderer *renderer = context->display->renderer;
|
|
||||||
CoglRendererEGL *egl_renderer = renderer->winsys;
|
|
||||||
CoglOnscreenEGL *egl_onscreen = cogl_onscreen_get_winsys (onscreen);
|
|
||||||
int framebuffer_height = cogl_framebuffer_get_height (framebuffer);
|
|
||||||
int *rectangles = g_alloca (sizeof (int) * n_rectangles * 4);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* eglSwapBuffersRegion expects rectangles relative to the
|
|
||||||
* bottom left corner but we are given rectangles relative to
|
|
||||||
* the top left so we need to flip them... */
|
|
||||||
memcpy (rectangles, user_rectangles, sizeof (int) * n_rectangles * 4);
|
|
||||||
for (i = 0; i < n_rectangles; i++)
|
|
||||||
{
|
|
||||||
int *rect = &rectangles[4 * i];
|
|
||||||
rect[1] = framebuffer_height - rect[1] - rect[3];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* At least for eglSwapBuffers the EGL spec says that the surface to
|
|
||||||
swap must be bound to the current context. It looks like Mesa
|
|
||||||
also validates that this is the case for eglSwapBuffersRegion so
|
|
||||||
we must bind here too */
|
|
||||||
_cogl_framebuffer_flush_state (COGL_FRAMEBUFFER (onscreen),
|
|
||||||
COGL_FRAMEBUFFER (onscreen),
|
|
||||||
COGL_FRAMEBUFFER_STATE_BIND);
|
|
||||||
|
|
||||||
if (egl_renderer->pf_eglSwapBuffersRegion (egl_renderer->edpy,
|
|
||||||
egl_onscreen->egl_surface,
|
|
||||||
n_rectangles,
|
|
||||||
rectangles) == EGL_FALSE)
|
|
||||||
g_warning ("Error reported by eglSwapBuffersRegion");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
_cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen,
|
|
||||||
const int *rectangles,
|
|
||||||
int n_rectangles,
|
|
||||||
CoglFrameInfo *info,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
|
||||||
CoglContext *context = cogl_framebuffer_get_context (framebuffer);
|
|
||||||
CoglRenderer *renderer = context->display->renderer;
|
|
||||||
CoglRendererEGL *egl_renderer = renderer->winsys;
|
|
||||||
CoglOnscreenEGL *egl_onscreen = cogl_onscreen_get_winsys (onscreen);
|
|
||||||
|
|
||||||
COGL_TRACE_BEGIN_SCOPED (CoglOnscreenEGLSwapBuffersWithDamage,
|
|
||||||
"Onscreen (eglSwapBuffers)");
|
|
||||||
|
|
||||||
/* The specification for EGL (at least in 1.4) says that the surface
|
|
||||||
needs to be bound to the current context for the swap to work
|
|
||||||
although it may change in future. Mesa explicitly checks for this
|
|
||||||
and just returns an error if this is not the case so we can't
|
|
||||||
just pretend this isn't in the spec. */
|
|
||||||
_cogl_framebuffer_flush_state (COGL_FRAMEBUFFER (onscreen),
|
|
||||||
COGL_FRAMEBUFFER (onscreen),
|
|
||||||
COGL_FRAMEBUFFER_STATE_BIND);
|
|
||||||
|
|
||||||
if (n_rectangles && egl_renderer->pf_eglSwapBuffersWithDamage)
|
|
||||||
{
|
|
||||||
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
|
|
||||||
size_t size = n_rectangles * sizeof (int) * 4;
|
|
||||||
int *flipped = alloca (size);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
memcpy (flipped, rectangles, size);
|
|
||||||
for (i = 0; i < n_rectangles; i++)
|
|
||||||
{
|
|
||||||
const int *rect = rectangles + 4 * i;
|
|
||||||
int *flip_rect = flipped + 4 * i;
|
|
||||||
|
|
||||||
flip_rect[1] =
|
|
||||||
cogl_framebuffer_get_height (framebuffer) - rect[1] - rect[3];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (egl_renderer->pf_eglSwapBuffersWithDamage (egl_renderer->edpy,
|
|
||||||
egl_onscreen->egl_surface,
|
|
||||||
flipped,
|
|
||||||
n_rectangles) == EGL_FALSE)
|
|
||||||
g_warning ("Error reported by eglSwapBuffersWithDamage");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
eglSwapBuffers (egl_renderer->edpy, egl_onscreen->egl_surface);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(EGL_KHR_fence_sync) || defined(EGL_KHR_reusable_sync)
|
#if defined(EGL_KHR_fence_sync) || defined(EGL_KHR_reusable_sync)
|
||||||
static void *
|
static void *
|
||||||
_cogl_winsys_fence_add (CoglContext *context)
|
_cogl_winsys_fence_add (CoglContext *context)
|
||||||
@ -913,13 +636,13 @@ static CoglWinsysVtable _cogl_winsys_vtable =
|
|||||||
.display_destroy = _cogl_winsys_display_destroy,
|
.display_destroy = _cogl_winsys_display_destroy,
|
||||||
.context_init = _cogl_winsys_context_init,
|
.context_init = _cogl_winsys_context_init,
|
||||||
.context_deinit = _cogl_winsys_context_deinit,
|
.context_deinit = _cogl_winsys_context_deinit,
|
||||||
.onscreen_init = _cogl_winsys_onscreen_init,
|
.onscreen_init = _cogl_winsys_onscreen_egl_init,
|
||||||
.onscreen_deinit = _cogl_winsys_onscreen_deinit,
|
.onscreen_deinit = _cogl_winsys_onscreen_egl_deinit,
|
||||||
.onscreen_bind = _cogl_winsys_onscreen_bind,
|
.onscreen_bind = _cogl_winsys_onscreen_egl_bind,
|
||||||
.onscreen_swap_buffers_with_damage =
|
.onscreen_swap_buffers_with_damage =
|
||||||
_cogl_winsys_onscreen_swap_buffers_with_damage,
|
_cogl_winsys_onscreen_egl_swap_buffers_with_damage,
|
||||||
.onscreen_swap_region = _cogl_winsys_onscreen_swap_region,
|
.onscreen_swap_region = _cogl_winsys_onscreen_egl_swap_region,
|
||||||
.onscreen_get_buffer_age = _cogl_winsys_onscreen_get_buffer_age,
|
.onscreen_get_buffer_age = _cogl_winsys_onscreen_egl_get_buffer_age,
|
||||||
|
|
||||||
#if defined(EGL_KHR_fence_sync) || defined(EGL_KHR_reusable_sync)
|
#if defined(EGL_KHR_fence_sync) || defined(EGL_KHR_reusable_sync)
|
||||||
.fence_add = _cogl_winsys_fence_add,
|
.fence_add = _cogl_winsys_fence_add,
|
||||||
|
Loading…
Reference in New Issue
Block a user