Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 4 additions & 29 deletions shell/platform/linux/fl_framebuffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ static void fl_framebuffer_class_init(FlFramebufferClass* klass) {

static void fl_framebuffer_init(FlFramebuffer* self) {}

FlFramebuffer* fl_framebuffer_new(size_t width, size_t height) {
FlFramebuffer* fl_framebuffer_new(GLint format, size_t width, size_t height) {
FlFramebuffer* provider =
FL_FRAMEBUFFER(g_object_new(fl_framebuffer_get_type(), nullptr));

Expand All @@ -56,12 +56,12 @@ FlFramebuffer* fl_framebuffer_new(size_t width, size_t height) {
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA,
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format,
GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);

glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
GL_TEXTURE_2D, provider->texture_id, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
provider->texture_id, 0);

return provider;
}
Expand All @@ -78,31 +78,6 @@ GLenum fl_framebuffer_get_target(FlFramebuffer* self) {
return GL_TEXTURE_2D;
}

GLenum fl_framebuffer_get_format(FlFramebuffer* self) {
// Flutter defines SK_R32_SHIFT=16, so SK_PMCOLOR_BYTE_ORDER should be BGRA.
// In Linux kN32_SkColorType is assumed to be kBGRA_8888_SkColorType.
// So we must choose a valid gl format to be compatible with surface format
// BGRA8.
// Following logic is copied from Skia GrGLCaps.cpp:
// https://github.com/google/skia/blob/4738ed711e03212aceec3cd502a4adb545f38e63/src/gpu/ganesh/gl/GrGLCaps.cpp#L1963-L2116

if (epoxy_is_desktop_gl()) {
// For OpenGL.
if (epoxy_gl_version() >= 12 || epoxy_has_gl_extension("GL_EXT_bgra")) {
return GL_RGBA8;
}
} else {
// For OpenGL ES.
if (epoxy_has_gl_extension("GL_EXT_texture_format_BGRA8888") ||
(epoxy_has_gl_extension("GL_APPLE_texture_format_BGRA8888") &&
epoxy_gl_version() >= 30)) {
return GL_BGRA8_EXT;
}
}
g_critical("Failed to determine valid GL format for Flutter rendering");
return GL_RGBA8;
}

size_t fl_framebuffer_get_width(FlFramebuffer* self) {
return self->width;
}
Expand Down
13 changes: 2 additions & 11 deletions shell/platform/linux/fl_framebuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@ G_DECLARE_FINAL_TYPE(FlFramebuffer, fl_framebuffer, FL, FRAMEBUFFER, GObject)

/**
* fl_framebuffer_new:
* @format: format, e.g. GL_RGB, GL_BGR
* @width: width of texture.
* @height: height of texture.
*
* Creates a new frame buffer. Requires a valid OpenGL context to create.
*
* Returns: a new #FlFramebuffer.
*/
FlFramebuffer* fl_framebuffer_new(size_t width, size_t height);
FlFramebuffer* fl_framebuffer_new(GLint format, size_t width, size_t height);

/**
* fl_framebuffer_get_id:
Expand Down Expand Up @@ -60,16 +61,6 @@ GLuint fl_framebuffer_get_texture_id(FlFramebuffer* framebuffer);
*/
GLenum fl_framebuffer_get_target(FlFramebuffer* framebuffer);

/**
* fl_framebuffer_get_format:
* @framebuffer: an #FlFramebuffer.
*
* Gets format of texture backing the framebuffer (example GL_RGBA8).
*
* Returns: texture format.
*/
GLenum fl_framebuffer_get_format(FlFramebuffer* framebuffer);

/**
* fl_framebuffer_get_width:
* @framebuffer: an #FlFramebuffer.
Expand Down
44 changes: 38 additions & 6 deletions shell/platform/linux/fl_renderer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ typedef struct {
// Engine we are rendering.
GWeakRef engine;

// Flag to track lazy initialization.
gboolean initialized;

// The pixel format passed to the engine.
GLint sized_format;

// The format used to create textures.
GLint general_format;

// Views being rendered.
GHashTable* views;

Expand Down Expand Up @@ -105,6 +114,25 @@ static GLfloat pixels_to_gl_coords(GLfloat position, GLfloat pixels) {
return (2.0 * position / pixels) - 1.0;
}

// Perform single run OpenGL initialization.
static void initialize(FlRenderer* self) {
FlRendererPrivate* priv = reinterpret_cast<FlRendererPrivate*>(
fl_renderer_get_instance_private(self));

if (priv->initialized) {
return;
}
priv->initialized = TRUE;

if (epoxy_has_gl_extension("GL_EXT_texture_format_BGRA8888")) {
priv->sized_format = GL_BGRA8_EXT;
priv->general_format = GL_BGRA_EXT;
} else {
priv->sized_format = GL_RGBA8;
priv->general_format = GL_RGBA;
}
}

static void fl_renderer_unblock_main_thread(FlRenderer* self) {
FlRendererPrivate* priv = reinterpret_cast<FlRendererPrivate*>(
fl_renderer_get_instance_private(self));
Expand Down Expand Up @@ -328,13 +356,18 @@ guint32 fl_renderer_get_fbo(FlRenderer* self) {
}

gboolean fl_renderer_create_backing_store(
FlRenderer* renderer,
FlRenderer* self,
const FlutterBackingStoreConfig* config,
FlutterBackingStore* backing_store_out) {
fl_renderer_make_current(renderer);
FlRendererPrivate* priv = reinterpret_cast<FlRendererPrivate*>(
fl_renderer_get_instance_private(self));

fl_renderer_make_current(self);

initialize(self);

FlFramebuffer* framebuffer =
fl_framebuffer_new(config->size.width, config->size.height);
FlFramebuffer* framebuffer = fl_framebuffer_new(
priv->general_format, config->size.width, config->size.height);
if (!framebuffer) {
g_warning("Failed to create backing store");
return FALSE;
Expand All @@ -345,8 +378,7 @@ gboolean fl_renderer_create_backing_store(
backing_store_out->open_gl.framebuffer.user_data = framebuffer;
backing_store_out->open_gl.framebuffer.name =
fl_framebuffer_get_id(framebuffer);
backing_store_out->open_gl.framebuffer.target =
fl_framebuffer_get_format(framebuffer);
backing_store_out->open_gl.framebuffer.target = priv->sized_format;
backing_store_out->open_gl.framebuffer.destruction_callback = [](void* p) {
// Backing store destroyed in fl_renderer_collect_backing_store(), set
// on FlutterCompositor.collect_backing_store_callback during engine start.
Expand Down
5 changes: 4 additions & 1 deletion shell/platform/linux/fl_renderer_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ TEST(FlRendererTest, RestoresGLState) {
g_autoptr(FlDartProject) project = fl_dart_project_new();
g_autoptr(FlView) view = fl_view_new(project);
g_autoptr(FlMockRenderer) renderer = fl_mock_renderer_new();
g_autoptr(FlFramebuffer) framebuffer = fl_framebuffer_new(kWidth, kHeight);
g_autoptr(FlFramebuffer) framebuffer =
fl_framebuffer_new(GL_RGB, kWidth, kHeight);

fl_renderer_add_view(FL_RENDERER(renderer), 0, view);
fl_renderer_wait_for_frame(FL_RENDERER(renderer), kWidth, kHeight);
Expand Down Expand Up @@ -144,6 +145,8 @@ TEST(FlRendererTest, BlitFramebufferExtension) {
::testing::Return(reinterpret_cast<const GLubyte*>("Intel")));
ON_CALL(epoxy, epoxy_is_desktop_gl).WillByDefault(::testing::Return(true));
EXPECT_CALL(epoxy, epoxy_gl_version).WillRepeatedly(::testing::Return(20));
EXPECT_CALL(epoxy, epoxy_has_gl_extension(::testing::_))
.WillRepeatedly(::testing::Return(false));
EXPECT_CALL(epoxy, epoxy_has_gl_extension(
::testing::StrEq("GL_EXT_framebuffer_blit")))
.WillRepeatedly(::testing::Return(true));
Expand Down