mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Show EGL configuration debugging when fail to create surface/context (flutter/engine#19397)
This commit is contained in:
parent
ebed95fb81
commit
4ffa68b795
@ -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
|
||||
|
||||
@ -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",
|
||||
|
||||
282
engine/src/flutter/shell/platform/linux/egl_utils.cc
Normal file
282
engine/src/flutter/shell/platform/linux/egl_utils.cc
Normal 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));
|
||||
}
|
||||
38
engine/src/flutter/shell/platform/linux/egl_utils.h
Normal file
38
engine/src/flutter/shell/platform/linux/egl_utils.h
Normal 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_
|
||||
58
engine/src/flutter/shell/platform/linux/egl_utils_test.cc
Normal file
58
engine/src/flutter/shell/platform/linux/egl_utils_test.cc
Normal 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, "");
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user