Show EGL configuration debugging when fail to create surface/context (flutter/engine#19397)

This commit is contained in:
Robert Ancell 2020-07-02 09:35:00 +12:00 committed by GitHub
parent ebed95fb81
commit 4ffa68b795
7 changed files with 666 additions and 61 deletions

View File

@ -1214,6 +1214,9 @@ FILE: ../../../flutter/shell/platform/glfw/platform_handler.h
FILE: ../../../flutter/shell/platform/glfw/public/flutter_glfw.h
FILE: ../../../flutter/shell/platform/glfw/text_input_plugin.cc
FILE: ../../../flutter/shell/platform/glfw/text_input_plugin.h
FILE: ../../../flutter/shell/platform/linux/egl_utils.cc
FILE: ../../../flutter/shell/platform/linux/egl_utils.h
FILE: ../../../flutter/shell/platform/linux/egl_utils_test.cc
FILE: ../../../flutter/shell/platform/linux/fl_basic_message_channel.cc
FILE: ../../../flutter/shell/platform/linux/fl_basic_message_channel_test.cc
FILE: ../../../flutter/shell/platform/linux/fl_binary_codec.cc

View File

@ -76,6 +76,7 @@ source_set("flutter_linux_sources") {
configs += [ "//flutter/shell/platform/linux/config:gtk" ]
sources = [
"egl_utils.cc",
"fl_basic_message_channel.cc",
"fl_binary_codec.cc",
"fl_binary_messenger.cc",
@ -138,6 +139,7 @@ executable("flutter_linux_unittests") {
testonly = true
sources = [
"egl_utils_test.cc",
"fl_basic_message_channel_test.cc",
"fl_binary_codec_test.cc",
"fl_binary_messenger_test.cc",

View File

@ -0,0 +1,282 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "egl_utils.h"
#include <EGL/egl.h>
// Converts an EGL decimal value to a string.
static gchar* egl_decimal_to_string(EGLint value) {
return g_strdup_printf("%d", value);
}
// Converts an EGL hexadecimal value to a string.
static gchar* egl_hexadecimal_to_string(EGLint value) {
return g_strdup_printf("0x%x", value);
}
// Converts an EGL enumerated value to a string.
static gchar* egl_enum_to_string(EGLint value) {
if (value == EGL_FALSE)
return g_strdup("EGL_FALSE");
else if (value == EGL_LUMINANCE_BUFFER)
return g_strdup("EGL_LUMINANCE_BUFFER");
else if (value == EGL_NONE)
return g_strdup("EGL_NONE");
else if (value == EGL_NON_CONFORMANT_CONFIG)
return g_strdup("EGL_NON_CONFORMANT_CONFIG");
else if (value == EGL_RGB_BUFFER)
return g_strdup("EGL_RGB_BUFFER");
else if (value == EGL_SLOW_CONFIG)
return g_strdup("EGL_SLOW_CONFIG");
else if (value == EGL_TRANSPARENT_RGB)
return g_strdup("EGL_TRANSPARENT_RGB");
else if (value == EGL_TRUE)
return g_strdup("EGL_TRUE");
else
return nullptr;
}
// Ensures the given bit is not set in a bitfield. Returns TRUE if that bit was
// cleared.
static gboolean clear_bit(EGLint* field, EGLint bit) {
if ((*field & bit) == 0)
return FALSE;
*field ^= bit;
return TRUE;
}
// Converts an EGL renderable type bitfield to a string.
static gchar* egl_renderable_type_to_string(EGLint value) {
EGLint v = value;
g_autoptr(GPtrArray) strings = g_ptr_array_new_with_free_func(g_free);
if (clear_bit(&v, EGL_OPENGL_ES_BIT))
g_ptr_array_add(strings, g_strdup("EGL_OPENGL_ES_BIT"));
if (clear_bit(&v, EGL_OPENVG_BIT))
g_ptr_array_add(strings, g_strdup("EGL_OPENVG_BIT"));
if (clear_bit(&v, EGL_OPENGL_ES2_BIT))
g_ptr_array_add(strings, g_strdup("EGL_OPENGL_ES2_BIT"));
if (clear_bit(&v, EGL_OPENGL_BIT))
g_ptr_array_add(strings, g_strdup("EGL_OPENGL_BIT"));
if (clear_bit(&v, EGL_OPENGL_ES3_BIT))
g_ptr_array_add(strings, g_strdup("EGL_OPENGL_ES3_BIT"));
if (v != 0)
g_ptr_array_add(strings, egl_hexadecimal_to_string(v));
g_ptr_array_add(strings, nullptr);
return g_strjoinv("|", reinterpret_cast<gchar**>(strings->pdata));
}
// Converts an EGL surface type bitfield to a string.
static gchar* egl_surface_type_to_string(EGLint value) {
EGLint v = value;
g_autoptr(GPtrArray) strings = g_ptr_array_new_with_free_func(g_free);
if (clear_bit(&v, EGL_PBUFFER_BIT))
g_ptr_array_add(strings, g_strdup("EGL_PBUFFER_BIT"));
if (clear_bit(&v, EGL_PIXMAP_BIT))
g_ptr_array_add(strings, g_strdup("EGL_PIXMAP_BIT"));
if (clear_bit(&v, EGL_WINDOW_BIT))
g_ptr_array_add(strings, g_strdup("EGL_WINDOW_BIT"));
if (v != 0)
g_ptr_array_add(strings, egl_hexadecimal_to_string(v));
g_ptr_array_add(strings, nullptr);
return g_strjoinv("|", reinterpret_cast<gchar**>(strings->pdata));
}
const gchar* egl_error_to_string(EGLint error) {
switch (error) {
case EGL_SUCCESS:
return "Success";
case EGL_NOT_INITIALIZED:
return "Not Initialized";
case EGL_BAD_ACCESS:
return "Bad Access";
case EGL_BAD_ALLOC:
return "Bad Allocation";
case EGL_BAD_ATTRIBUTE:
return "Bad Attribute";
case EGL_BAD_CONTEXT:
return "Bad Context";
case EGL_BAD_CONFIG:
return "Bad Configuration";
case EGL_BAD_CURRENT_SURFACE:
return "Bad Current Surface";
case EGL_BAD_DISPLAY:
return "Bad Display";
case EGL_BAD_SURFACE:
return "Bad Surface";
case EGL_BAD_MATCH:
return "Bad Match";
case EGL_BAD_PARAMETER:
return "Bad Parameter";
case EGL_BAD_NATIVE_PIXMAP:
return "Bad Native Pixmap";
case EGL_BAD_NATIVE_WINDOW:
return "Bad Native Window";
case EGL_CONTEXT_LOST:
return "Context Lost";
default:
return "Unknown Error";
}
}
gchar* egl_config_to_string(EGLDisplay display, EGLConfig config) {
struct {
EGLint attribute;
const gchar* name;
gchar* (*to_string)(EGLint value);
} config_items[] = {{
EGL_CONFIG_ID,
"EGL_CONFIG_ID",
egl_decimal_to_string,
},
{
EGL_BUFFER_SIZE,
"EGL_BUFFER_SIZE",
egl_decimal_to_string,
},
{
EGL_COLOR_BUFFER_TYPE,
"EGL_COLOR_BUFFER_TYPE",
egl_enum_to_string,
},
{
EGL_TRANSPARENT_TYPE,
"EGL_TRANSPARENT_TYPE",
egl_enum_to_string,
},
{
EGL_LEVEL,
"EGL_LEVEL",
egl_decimal_to_string,
},
{
EGL_RED_SIZE,
"EGL_RED_SIZE",
egl_decimal_to_string,
},
{
EGL_GREEN_SIZE,
"EGL_GREEN_SIZE",
egl_decimal_to_string,
},
{
EGL_BLUE_SIZE,
"EGL_BLUE_SIZE",
egl_decimal_to_string,
},
{
EGL_ALPHA_SIZE,
"EGL_ALPHA_SIZE",
egl_decimal_to_string,
},
{
EGL_DEPTH_SIZE,
"EGL_DEPTH_SIZE",
egl_decimal_to_string,
},
{
EGL_STENCIL_SIZE,
"EGL_STENCIL_SIZE",
egl_decimal_to_string,
},
{
EGL_SAMPLES,
"EGL_SAMPLES",
egl_decimal_to_string,
},
{
EGL_SAMPLE_BUFFERS,
"EGL_SAMPLE_BUFFERS",
egl_decimal_to_string,
},
{
EGL_NATIVE_VISUAL_ID,
"EGL_NATIVE_VISUAL_ID",
egl_hexadecimal_to_string,
},
{
EGL_NATIVE_VISUAL_TYPE,
"EGL_NATIVE_VISUAL_TYPE",
egl_hexadecimal_to_string,
},
{
EGL_NATIVE_RENDERABLE,
"EGL_NATIVE_RENDERABLE",
egl_enum_to_string,
},
{
EGL_CONFIG_CAVEAT,
"EGL_CONFIG_CAVEAT",
egl_enum_to_string,
},
{
EGL_BIND_TO_TEXTURE_RGB,
"EGL_BIND_TO_TEXTURE_RGB",
egl_enum_to_string,
},
{
EGL_BIND_TO_TEXTURE_RGBA,
"EGL_BIND_TO_TEXTURE_RGBA",
egl_enum_to_string,
},
{
EGL_RENDERABLE_TYPE,
"EGL_RENDERABLE_TYPE",
egl_renderable_type_to_string,
},
{
EGL_CONFORMANT,
"EGL_CONFORMANT",
egl_renderable_type_to_string,
},
{
EGL_SURFACE_TYPE,
"EGL_SURFACE_TYPE",
egl_surface_type_to_string,
},
{
EGL_MAX_PBUFFER_WIDTH,
"EGL_MAX_PBUFFER_WIDTH",
egl_decimal_to_string,
},
{
EGL_MAX_PBUFFER_HEIGHT,
"EGL_MAX_PBUFFER_HEIGHT",
egl_decimal_to_string,
},
{
EGL_MAX_PBUFFER_PIXELS,
"EGL_MAX_PBUFFER_PIXELS",
egl_decimal_to_string,
},
{
EGL_MIN_SWAP_INTERVAL,
"EGL_MIN_SWAP_INTERVAL",
egl_decimal_to_string,
},
{
EGL_MAX_SWAP_INTERVAL,
"EGL_MAX_SWAP_INTERVAL",
egl_decimal_to_string,
},
{EGL_NONE, nullptr, nullptr}};
g_autoptr(GPtrArray) strings = g_ptr_array_new_with_free_func(g_free);
for (int i = 0; config_items[i].attribute != EGL_NONE; i++) {
EGLint value;
if (!eglGetConfigAttrib(display, config, config_items[i].attribute, &value))
continue;
g_autofree gchar* value_string = config_items[i].to_string(value);
if (value_string == nullptr)
value_string = egl_hexadecimal_to_string(value);
g_ptr_array_add(
strings, g_strdup_printf("%s=%s", config_items[i].name, value_string));
}
g_ptr_array_add(strings, nullptr);
return g_strjoinv(" ", reinterpret_cast<gchar**>(strings->pdata));
}

View File

@ -0,0 +1,38 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_LINUX_EGL_UTILS_H_
#define FLUTTER_SHELL_PLATFORM_LINUX_EGL_UTILS_H_
#include <EGL/egl.h>
#include <glib.h>
G_BEGIN_DECLS
/**
* egl_error_to_string:
* @error: an EGL error code.
*
* Converts an egl error code to a human readable string. e.g. "Bad Match".
*
* Returns: an error description.
*/
const gchar* egl_error_to_string(EGLint error);
/**
* egl_config_to_string:
* @display: an EGL display.
* @config: an EGL configuration.
*
* Converts an EGL configuration to a human readable string. e.g.
* "EGL_CONFIG_ID=1 EGL_RED_SIZE=8...".
*
* Returns: a configuration description.
*/
gchar* egl_config_to_string(EGLDisplay display, EGLConfig config);
G_END_DECLS
#endif // FLUTTER_SHELL_PLATFORM_LINUX_EGL_UTILS_H_

View File

@ -0,0 +1,58 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "gtest/gtest.h"
#include "flutter/shell/platform/linux/egl_utils.h"
TEST(EGLUtils, ErrorToString) {
const gchar* error_string = egl_error_to_string(EGL_SUCCESS);
EXPECT_STREQ(error_string, "Success");
}
TEST(EGLUtils, ErrorToStringUnknown) {
const gchar* error_string = egl_error_to_string(0xffffffff);
EXPECT_STREQ(error_string, "Unknown Error");
}
TEST(EGLUtils, ErrorToStringNegative) {
const gchar* error_string = egl_error_to_string(-1);
EXPECT_STREQ(error_string, "Unknown Error");
}
TEST(EGLUtils, ConfigToString) {
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, nullptr, nullptr);
EGLConfig config;
eglChooseConfig(display, nullptr, &config, 1, nullptr);
g_autofree gchar* config_string = egl_config_to_string(display, config);
EXPECT_STREQ(
config_string,
"EGL_CONFIG_ID=1 EGL_BUFFER_SIZE=32 EGL_COLOR_BUFFER_TYPE=EGL_RGB_BUFFER "
"EGL_TRANSPARENT_TYPE=EGL_NONE EGL_LEVEL=1 EGL_RED_SIZE=8 "
"EGL_GREEN_SIZE=8 EGL_BLUE_SIZE=8 EGL_ALPHA_SIZE=0 EGL_DEPTH_SIZE=0 "
"EGL_STENCIL_SIZE=0 EGL_SAMPLES=0 EGL_SAMPLE_BUFFERS=0 "
"EGL_NATIVE_VISUAL_ID=0x1 EGL_NATIVE_VISUAL_TYPE=0x0 "
"EGL_NATIVE_RENDERABLE=EGL_TRUE EGL_CONFIG_CAVEAT=EGL_NONE "
"EGL_BIND_TO_TEXTURE_RGB=EGL_TRUE EGL_BIND_TO_TEXTURE_RGBA=EGL_FALSE "
"EGL_RENDERABLE_TYPE=EGL_OPENGL_ES2_BIT "
"EGL_CONFORMANT=EGL_OPENGL_ES2_BIT "
"EGL_SURFACE_TYPE=EGL_PBUFFER_BIT|EGL_WINDOW_BIT "
"EGL_MAX_PBUFFER_WIDTH=1024 EGL_MAX_PBUFFER_HEIGHT=1024 "
"EGL_MAX_PBUFFER_PIXELS=1048576 EGL_MIN_SWAP_INTERVAL=0 "
"EGL_MAX_SWAP_INTERVAL=1000");
}
TEST(EGLUtils, ConfigToStringNullptr) {
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, nullptr, nullptr);
EGLConfig config;
eglChooseConfig(display, nullptr, &config, 1, nullptr);
g_autofree gchar* config_string1 = egl_config_to_string(nullptr, config);
EXPECT_STREQ(config_string1, "");
g_autofree gchar* config_string2 = egl_config_to_string(display, nullptr);
EXPECT_STREQ(config_string2, "");
g_autofree gchar* config_string3 = egl_config_to_string(nullptr, nullptr);
EXPECT_STREQ(config_string3, "");
}

View File

@ -5,6 +5,7 @@
#include "fl_renderer.h"
#include "flutter/shell/platform/embedder/embedder.h"
#include "flutter/shell/platform/linux/egl_utils.h"
G_DEFINE_QUARK(fl_renderer_error_quark, fl_renderer_error)
@ -19,45 +20,6 @@ typedef struct {
G_DEFINE_TYPE_WITH_PRIVATE(FlRenderer, fl_renderer, G_TYPE_OBJECT)
// Gets a string representation of the last EGL error.
static const gchar* get_egl_error() {
EGLint error = eglGetError();
switch (error) {
case EGL_SUCCESS:
return "Success";
case EGL_NOT_INITIALIZED:
return "Not Initialized";
case EGL_BAD_ACCESS:
return "Bad Access";
case EGL_BAD_ALLOC:
return "Bad Allocation";
case EGL_BAD_ATTRIBUTE:
return "Bad Attribute";
case EGL_BAD_CONTEXT:
return "Bad Context";
case EGL_BAD_CONFIG:
return "Bad Configuration";
case EGL_BAD_CURRENT_SURFACE:
return "Bad Current Surface";
case EGL_BAD_DISPLAY:
return "Bad Display";
case EGL_BAD_SURFACE:
return "Bad Surface";
case EGL_BAD_MATCH:
return "Bad Match";
case EGL_BAD_PARAMETER:
return "Bad Parameter";
case EGL_BAD_NATIVE_PIXMAP:
return "Bad Native Pixmap";
case EGL_BAD_NATIVE_WINDOW:
return "Bad Native Window";
case EGL_CONTEXT_LOST:
return "Context Lost";
default:
return "Unknown Error";
}
}
// Creates a resource surface.
static void create_resource_surface(FlRenderer* self, EGLConfig config) {
FlRendererPrivate* priv =
@ -69,14 +31,16 @@ static void create_resource_surface(FlRenderer* self, EGLConfig config) {
priv->resource_surface = eglCreatePbufferSurface(priv->egl_display, config,
resource_context_attribs);
if (priv->resource_surface == nullptr) {
g_warning("Failed to create EGL resource surface: %s", get_egl_error());
g_warning("Failed to create EGL resource surface: %s",
egl_error_to_string(eglGetError()));
return;
}
priv->resource_context = eglCreateContext(
priv->egl_display, config, priv->egl_context, context_attributes);
if (priv->resource_context == nullptr)
g_warning("Failed to create EGL resource context: %s", get_egl_error());
g_warning("Failed to create EGL resource context: %s",
egl_error_to_string(eglGetError()));
}
// Default implementation for the start virtual method.
@ -114,33 +78,44 @@ static gboolean fl_renderer_real_start(FlRenderer* self, GError** error) {
if (!eglChooseConfig(priv->egl_display, attributes, &egl_config, 1,
&n_config)) {
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to choose EGL config: %s", get_egl_error());
"Failed to choose EGL config: %s",
egl_error_to_string(eglGetError()));
return FALSE;
}
if (n_config == 0) {
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to find appropriate EGL config: %s", get_egl_error());
"Failed to find appropriate EGL config: %s",
egl_error_to_string(eglGetError()));
return FALSE;
}
if (!eglBindAPI(EGL_OPENGL_ES_API)) {
g_autofree gchar* config_string =
egl_config_to_string(priv->egl_display, egl_config);
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to bind EGL OpenGL ES API: %s", get_egl_error());
"Failed to bind EGL OpenGL ES API using configuration (%s): %s",
config_string, egl_error_to_string(eglGetError()));
return FALSE;
}
priv->egl_surface = FL_RENDERER_GET_CLASS(self)->create_surface(
self, priv->egl_display, egl_config);
if (priv->egl_surface == nullptr) {
g_autofree gchar* config_string =
egl_config_to_string(priv->egl_display, egl_config);
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to create EGL surface: %s", get_egl_error());
"Failed to create EGL surface using configuration (%s): %s",
config_string, egl_error_to_string(eglGetError()));
return FALSE;
}
EGLint context_attributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
priv->egl_context = eglCreateContext(priv->egl_display, egl_config,
EGL_NO_CONTEXT, context_attributes);
if (priv->egl_context == nullptr) {
g_autofree gchar* config_string =
egl_config_to_string(priv->egl_display, egl_config);
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to create EGL context: %s", get_egl_error());
"Failed to create EGL context using configuration (%s): %s",
config_string, egl_error_to_string(eglGetError()));
return FALSE;
}
@ -174,7 +149,8 @@ gboolean fl_renderer_make_current(FlRenderer* self, GError** error) {
if (!eglMakeCurrent(priv->egl_display, priv->egl_surface, priv->egl_surface,
priv->egl_context)) {
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to make EGL context current: %s", get_egl_error());
"Failed to make EGL context current: %s",
egl_error_to_string(eglGetError()));
return FALSE;
}
@ -191,7 +167,8 @@ gboolean fl_renderer_make_resource_current(FlRenderer* self, GError** error) {
if (!eglMakeCurrent(priv->egl_display, priv->resource_surface,
priv->resource_surface, priv->resource_context)) {
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to make EGL context current: %s", get_egl_error());
"Failed to make EGL context current: %s",
egl_error_to_string(eglGetError()));
return FALSE;
}
@ -205,7 +182,8 @@ gboolean fl_renderer_clear_current(FlRenderer* self, GError** error) {
if (!eglMakeCurrent(priv->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
EGL_NO_CONTEXT)) {
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to clear EGL context: %s", get_egl_error());
"Failed to clear EGL context: %s",
egl_error_to_string(eglGetError()));
return FALSE;
}
@ -223,7 +201,8 @@ gboolean fl_renderer_present(FlRenderer* self, GError** error) {
if (!eglSwapBuffers(priv->egl_display, priv->egl_surface)) {
g_set_error(error, fl_renderer_error_quark(), FL_RENDERER_ERROR_FAILED,
"Failed to swap EGL buffers: %s", get_egl_error());
"Failed to swap EGL buffers: %s",
egl_error_to_string(eglGetError()));
return FALSE;
}

View File

@ -4,72 +4,315 @@
#include <EGL/egl.h>
EGLBoolean eglBindAPI(EGLenum api) {
typedef struct {
EGLint config_id;
EGLint buffer_size;
EGLint color_buffer_type;
EGLint transparent_type;
EGLint level;
EGLint red_size;
EGLint green_size;
EGLint blue_size;
EGLint alpha_size;
EGLint depth_size;
EGLint stencil_size;
EGLint samples;
EGLint sample_buffers;
EGLint native_visual_id;
EGLint native_visual_type;
EGLint native_renderable;
EGLint config_caveat;
EGLint bind_to_texture_rgb;
EGLint bind_to_texture_rgba;
EGLint renderable_type;
EGLint conformant;
EGLint surface_type;
EGLint max_pbuffer_width;
EGLint max_pbuffer_height;
EGLint max_pbuffer_pixels;
EGLint min_swap_interval;
EGLint max_swap_interval;
} MockConfig;
typedef struct {
bool initialized;
MockConfig config;
} MockDisplay;
static MockDisplay mock_display;
static EGLint mock_error = EGL_SUCCESS;
static bool check_display(EGLDisplay dpy) {
if (dpy == nullptr) {
mock_error = EGL_BAD_DISPLAY;
return false;
}
MockDisplay* display = static_cast<MockDisplay*>(dpy);
if (!display->initialized) {
mock_error = EGL_NOT_INITIALIZED;
return false;
}
return true;
}
static bool check_config(EGLConfig config) {
if (config == nullptr) {
mock_error = EGL_BAD_CONFIG;
return false;
}
return true;
}
static EGLBoolean bool_success() {
mock_error = EGL_SUCCESS;
return EGL_TRUE;
}
static EGLBoolean bool_failure(EGLint error) {
mock_error = error;
return EGL_FALSE;
}
EGLBoolean eglBindAPI(EGLenum api) {
return bool_success();
}
EGLBoolean eglChooseConfig(EGLDisplay dpy,
const EGLint* attrib_list,
EGLConfig* configs,
EGLint config_size,
EGLint* num_config) {
return EGL_TRUE;
MockDisplay* display = static_cast<MockDisplay*>(dpy);
if (configs == nullptr) {
if (num_config != nullptr)
*num_config = 1;
return bool_success();
}
EGLint n_returned = 0;
if (config_size >= 1) {
configs[0] = &display->config;
}
if (num_config != nullptr)
*num_config = n_returned;
return bool_success();
}
EGLContext eglCreateContext(EGLDisplay dpy,
EGLConfig config,
EGLContext share_context,
const EGLint* attrib_list) {
return nullptr;
if (!check_display(dpy) || !check_config(config))
return EGL_NO_CONTEXT;
mock_error = EGL_SUCCESS;
return EGL_NO_CONTEXT;
}
EGLSurface eglCreatePbufferSurface(EGLDisplay dpy,
EGLConfig config,
const EGLint* attrib_list) {
return nullptr;
if (!check_display(dpy) || !check_config(config))
return EGL_NO_SURFACE;
mock_error = EGL_SUCCESS;
return EGL_NO_SURFACE;
}
EGLSurface eglCreateWindowSurface(EGLDisplay dpy,
EGLConfig config,
EGLNativeWindowType win,
const EGLint* attrib_list) {
return nullptr;
if (!check_display(dpy) || !check_config(config))
return EGL_NO_SURFACE;
mock_error = EGL_SUCCESS;
return EGL_NO_SURFACE;
}
EGLBoolean eglGetConfigAttrib(EGLDisplay dpy,
EGLConfig config,
EGLint attribute,
EGLint* value) {
if (!check_display(dpy) || !check_config(config))
return EGL_FALSE;
MockConfig* c = static_cast<MockConfig*>(config);
switch (attribute) {
case EGL_CONFIG_ID:
*value = c->config_id;
return bool_success();
case EGL_BUFFER_SIZE:
*value = c->buffer_size;
return bool_success();
case EGL_COLOR_BUFFER_TYPE:
*value = c->color_buffer_type;
return bool_success();
case EGL_TRANSPARENT_TYPE:
*value = c->transparent_type;
return bool_success();
case EGL_LEVEL:
*value = c->level;
return bool_success();
case EGL_RED_SIZE:
*value = c->red_size;
return bool_success();
case EGL_GREEN_SIZE:
*value = c->green_size;
return bool_success();
case EGL_BLUE_SIZE:
*value = c->blue_size;
return bool_success();
case EGL_ALPHA_SIZE:
*value = c->alpha_size;
return bool_success();
case EGL_DEPTH_SIZE:
*value = c->depth_size;
return bool_success();
case EGL_STENCIL_SIZE:
*value = c->stencil_size;
return bool_success();
case EGL_SAMPLES:
*value = c->samples;
return bool_success();
case EGL_SAMPLE_BUFFERS:
*value = c->sample_buffers;
return bool_success();
case EGL_NATIVE_VISUAL_ID:
*value = c->native_visual_id;
return bool_success();
case EGL_NATIVE_VISUAL_TYPE:
*value = c->native_visual_type;
return bool_success();
case EGL_NATIVE_RENDERABLE:
*value = c->native_renderable;
return bool_success();
case EGL_CONFIG_CAVEAT:
*value = c->config_caveat;
return bool_success();
case EGL_BIND_TO_TEXTURE_RGB:
*value = c->bind_to_texture_rgb;
return bool_success();
case EGL_BIND_TO_TEXTURE_RGBA:
*value = c->bind_to_texture_rgba;
return bool_success();
case EGL_RENDERABLE_TYPE:
*value = c->renderable_type;
return bool_success();
case EGL_CONFORMANT:
*value = c->conformant;
return bool_success();
case EGL_SURFACE_TYPE:
*value = c->surface_type;
return bool_success();
case EGL_MAX_PBUFFER_WIDTH:
*value = c->max_pbuffer_width;
return bool_success();
case EGL_MAX_PBUFFER_HEIGHT:
*value = c->max_pbuffer_height;
return bool_success();
case EGL_MAX_PBUFFER_PIXELS:
*value = c->max_pbuffer_pixels;
return bool_success();
case EGL_MIN_SWAP_INTERVAL:
*value = c->min_swap_interval;
return bool_success();
case EGL_MAX_SWAP_INTERVAL:
*value = c->max_swap_interval;
return bool_success();
default:
return bool_failure(EGL_BAD_ATTRIBUTE);
}
}
EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id) {
return nullptr;
return &mock_display;
}
EGLint eglGetError() {
return EGL_SUCCESS;
EGLint error = mock_error;
mock_error = EGL_SUCCESS;
return error;
}
void (*eglGetProcAddress(const char* procname))(void) {
mock_error = EGL_SUCCESS;
return nullptr;
}
EGLBoolean eglInitialize(EGLDisplay dpy, EGLint* major, EGLint* minor) {
MockDisplay* display = static_cast<MockDisplay*>(dpy);
if (!display->initialized) {
MockConfig* c = &display->config;
c->config_id = 1;
c->buffer_size = 32;
c->color_buffer_type = EGL_RGB_BUFFER;
c->transparent_type = EGL_NONE;
c->level = 1;
c->red_size = 8;
c->green_size = 8;
c->blue_size = 8;
c->alpha_size = 0;
c->depth_size = 0;
c->stencil_size = 0;
c->samples = 0;
c->sample_buffers = 0;
c->native_visual_id = 1;
c->native_visual_type = 0;
c->native_renderable = EGL_TRUE;
c->config_caveat = EGL_NONE;
c->bind_to_texture_rgb = EGL_TRUE;
c->bind_to_texture_rgba = EGL_FALSE;
c->renderable_type = EGL_OPENGL_ES2_BIT;
c->conformant = EGL_OPENGL_ES2_BIT;
c->surface_type = EGL_WINDOW_BIT | EGL_PBUFFER_BIT;
c->max_pbuffer_width = 1024;
c->max_pbuffer_height = 1024;
c->max_pbuffer_pixels = 1024 * 1024;
c->min_swap_interval = 0;
c->max_swap_interval = 1000;
display->initialized = true;
}
if (major != nullptr)
*major = 1;
if (minor != nullptr)
*major = 5;
return EGL_TRUE;
return bool_success();
}
EGLBoolean eglMakeCurrent(EGLDisplay dpy,
EGLSurface draw,
EGLSurface read,
EGLContext ctx) {
return EGL_TRUE;
if (!check_display(dpy))
return EGL_FALSE;
return bool_success();
}
EGLBoolean eglQueryContext(EGLDisplay dpy,
EGLContext ctx,
EGLint attribute,
EGLint* value) {
return EGL_TRUE;
if (!check_display(dpy))
return EGL_FALSE;
return bool_success();
}
EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) {
return EGL_TRUE;
if (!check_display(dpy))
return EGL_FALSE;
return bool_success();
}