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
13 changes: 11 additions & 2 deletions shell/platform/linux/fl_renderer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,9 @@ static void render_with_textures(FlRenderer* self, int width, int height) {
GLint saved_array_buffer_binding;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &saved_array_buffer_binding);

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

glUseProgram(priv->program);

for (guint i = 0; i < priv->framebuffers->len; i++) {
Expand Down Expand Up @@ -236,6 +239,8 @@ static void render_with_textures(FlRenderer* self, int width, int height) {
glDeleteBuffers(1, &vertex_buffer);
}

glDisable(GL_BLEND);

glBindTexture(GL_TEXTURE_2D, saved_texture_binding);
glBindVertexArray(saved_vao_binding);
glBindBuffer(GL_ARRAY_BUFFER, saved_array_buffer_binding);
Expand Down Expand Up @@ -443,13 +448,17 @@ void fl_renderer_setup(FlRenderer* self) {
}
}

void fl_renderer_render(FlRenderer* self, int width, int height) {
void fl_renderer_render(FlRenderer* self,
int width,
int height,
const GdkRGBA* background_color) {
FlRendererPrivate* priv = reinterpret_cast<FlRendererPrivate*>(
fl_renderer_get_instance_private(self));

g_return_if_fail(FL_IS_RENDERER(self));

glClearColor(0.0, 0.0, 0.0, 1.0);
glClearColor(background_color->red, background_color->green,
background_color->blue, background_color->alpha);
glClear(GL_COLOR_BUFFER_BIT);

if (priv->has_gl_framebuffer_blit) {
Expand Down
6 changes: 5 additions & 1 deletion shell/platform/linux/fl_renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,14 @@ void fl_renderer_setup(FlRenderer* renderer);
* @renderer: an #FlRenderer.
* @width: width of the window in pixels.
* @height: height of the window in pixels.
* @background_color: color to use for background.
*
* Performs OpenGL commands to render current Flutter view.
*/
void fl_renderer_render(FlRenderer* renderer, int width, int height);
void fl_renderer_render(FlRenderer* renderer,
int width,
int height,
const GdkRGBA* background_color);

/**
* fl_renderer_cleanup:
Expand Down
62 changes: 49 additions & 13 deletions shell/platform/linux/fl_renderer_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,36 @@

#include <epoxy/egl.h>

TEST(FlRendererTest, BackgroundColor) {
::testing::NiceMock<flutter::testing::MockEpoxy> epoxy;

ON_CALL(epoxy, epoxy_is_desktop_gl).WillByDefault(::testing::Return(true));
EXPECT_CALL(epoxy, epoxy_gl_version).WillRepeatedly(::testing::Return(30));
ON_CALL(epoxy, glGetString(GL_VENDOR))
.WillByDefault(
::testing::Return(reinterpret_cast<const GLubyte*>("Intel")));
EXPECT_CALL(epoxy, glClearColor(0.2, 0.3, 0.4, 0.5));

g_autoptr(FlMockRenderer) renderer = fl_mock_renderer_new();
fl_renderer_setup(FL_RENDERER(renderer));
fl_renderer_wait_for_frame(FL_RENDERER(renderer), 1024, 1024);
FlutterBackingStoreConfig config = {
.struct_size = sizeof(FlutterBackingStoreConfig),
.size = {.width = 1024, .height = 1024}};
FlutterBackingStore backing_store;
fl_renderer_create_backing_store(FL_RENDERER(renderer), &config,
&backing_store);
const FlutterLayer layer0 = {.struct_size = sizeof(FlutterLayer),
.type = kFlutterLayerContentTypeBackingStore,
.backing_store = &backing_store,
.size = {.width = 1024, .height = 1024}};
const FlutterLayer* layers[] = {&layer0};
fl_renderer_present_layers(FL_RENDERER(renderer), 0, layers, 1);
GdkRGBA background_color = {
.red = 0.2, .green = 0.3, .blue = 0.4, .alpha = 0.5};
fl_renderer_render(FL_RENDERER(renderer), 1024, 1024, &background_color);
}

TEST(FlRendererTest, RestoresGLState) {
::testing::NiceMock<flutter::testing::MockEpoxy> epoxy;

Expand Down Expand Up @@ -44,7 +74,9 @@ TEST(FlRendererTest, RestoresGLState) {

fl_renderer_present_layers(FL_RENDERER(renderer), 0, layers.data(),
layers.size());
fl_renderer_render(FL_RENDERER(renderer), kWidth, kHeight);
GdkRGBA background_color = {
.red = 0.0, .green = 0.0, .blue = 0.0, .alpha = 1.0};
fl_renderer_render(FL_RENDERER(renderer), kWidth, kHeight, &background_color);

GLuint texture_2d_binding;
glGetIntegerv(GL_TEXTURE_BINDING_2D,
Expand Down Expand Up @@ -82,8 +114,7 @@ TEST(FlRendererTest, BlitFramebuffer) {

EXPECT_CALL(epoxy, glBlitFramebuffer);

g_autoptr(FlMockRenderer) renderer =
fl_mock_renderer_new(&renderer_get_refresh_rate);
g_autoptr(FlMockRenderer) renderer = fl_mock_renderer_new();
fl_renderer_setup(FL_RENDERER(renderer));
fl_renderer_wait_for_frame(FL_RENDERER(renderer), 1024, 1024);
FlutterBackingStoreConfig config = {
Expand All @@ -98,7 +129,9 @@ TEST(FlRendererTest, BlitFramebuffer) {
.size = {.width = 1024, .height = 1024}};
const FlutterLayer* layers[] = {&layer0};
fl_renderer_present_layers(FL_RENDERER(renderer), 0, layers, 1);
fl_renderer_render(FL_RENDERER(renderer), 1024, 1024);
GdkRGBA background_color = {
.red = 0.0, .green = 0.0, .blue = 0.0, .alpha = 1.0};
fl_renderer_render(FL_RENDERER(renderer), 1024, 1024, &background_color);
}

TEST(FlRendererTest, BlitFramebufferExtension) {
Expand All @@ -116,8 +149,7 @@ TEST(FlRendererTest, BlitFramebufferExtension) {

EXPECT_CALL(epoxy, glBlitFramebuffer);

g_autoptr(FlMockRenderer) renderer =
fl_mock_renderer_new(&renderer_get_refresh_rate);
g_autoptr(FlMockRenderer) renderer = fl_mock_renderer_new();
fl_renderer_setup(FL_RENDERER(renderer));
fl_renderer_wait_for_frame(FL_RENDERER(renderer), 1024, 1024);
FlutterBackingStoreConfig config = {
Expand All @@ -132,7 +164,9 @@ TEST(FlRendererTest, BlitFramebufferExtension) {
.size = {.width = 1024, .height = 1024}};
const FlutterLayer* layers[] = {&layer0};
fl_renderer_present_layers(FL_RENDERER(renderer), 0, layers, 1);
fl_renderer_render(FL_RENDERER(renderer), 1024, 1024);
GdkRGBA background_color = {
.red = 0.0, .green = 0.0, .blue = 0.0, .alpha = 1.0};
fl_renderer_render(FL_RENDERER(renderer), 1024, 1024, &background_color);
}

TEST(FlRendererTest, NoBlitFramebuffer) {
Expand All @@ -145,8 +179,7 @@ TEST(FlRendererTest, NoBlitFramebuffer) {
ON_CALL(epoxy, epoxy_is_desktop_gl).WillByDefault(::testing::Return(true));
EXPECT_CALL(epoxy, epoxy_gl_version).WillRepeatedly(::testing::Return(20));

g_autoptr(FlMockRenderer) renderer =
fl_mock_renderer_new(&renderer_get_refresh_rate);
g_autoptr(FlMockRenderer) renderer = fl_mock_renderer_new();
fl_renderer_setup(FL_RENDERER(renderer));
fl_renderer_wait_for_frame(FL_RENDERER(renderer), 1024, 1024);
FlutterBackingStoreConfig config = {
Expand All @@ -161,7 +194,9 @@ TEST(FlRendererTest, NoBlitFramebuffer) {
.size = {.width = 1024, .height = 1024}};
const FlutterLayer* layers[] = {&layer0};
fl_renderer_present_layers(FL_RENDERER(renderer), 0, layers, 1);
fl_renderer_render(FL_RENDERER(renderer), 1024, 1024);
GdkRGBA background_color = {
.red = 0.0, .green = 0.0, .blue = 0.0, .alpha = 1.0};
fl_renderer_render(FL_RENDERER(renderer), 1024, 1024, &background_color);
}

TEST(FlRendererTest, BlitFramebufferNvidia) {
Expand All @@ -175,8 +210,7 @@ TEST(FlRendererTest, BlitFramebufferNvidia) {
ON_CALL(epoxy, epoxy_is_desktop_gl).WillByDefault(::testing::Return(true));
EXPECT_CALL(epoxy, epoxy_gl_version).WillRepeatedly(::testing::Return(30));

g_autoptr(FlMockRenderer) renderer =
fl_mock_renderer_new(&renderer_get_refresh_rate);
g_autoptr(FlMockRenderer) renderer = fl_mock_renderer_new();
fl_renderer_setup(FL_RENDERER(renderer));
fl_renderer_wait_for_frame(FL_RENDERER(renderer), 1024, 1024);
FlutterBackingStoreConfig config = {
Expand All @@ -191,5 +225,7 @@ TEST(FlRendererTest, BlitFramebufferNvidia) {
.size = {.width = 1024, .height = 1024}};
const FlutterLayer* layers[] = {&layer0};
fl_renderer_present_layers(FL_RENDERER(renderer), 0, layers, 1);
fl_renderer_render(FL_RENDERER(renderer), 1024, 1024);
GdkRGBA background_color = {
.red = 0.0, .green = 0.0, .blue = 0.0, .alpha = 1.0};
fl_renderer_render(FL_RENDERER(renderer), 1024, 1024, &background_color);
}
18 changes: 17 additions & 1 deletion shell/platform/linux/fl_view.cc
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ struct _FlView {
// Rendering output.
FlRendererGdk* renderer;

// Background color.
GdkRGBA* background_color;

// Pointer button state recorded for sending status updates.
int64_t button_state;

Expand Down Expand Up @@ -607,7 +610,7 @@ static gboolean render_cb(FlView* self, GdkGLContext* context) {
int height = gtk_widget_get_allocated_height(GTK_WIDGET(self->gl_area));
gint scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(self->gl_area));
fl_renderer_render(FL_RENDERER(self->renderer), width * scale_factor,
height * scale_factor);
height * scale_factor, self->background_color);

return TRUE;
}
Expand Down Expand Up @@ -654,6 +657,7 @@ static void fl_view_dispose(GObject* object) {

g_clear_object(&self->engine);
g_clear_object(&self->renderer);
g_clear_pointer(&self->background_color, gdk_rgba_free);
g_clear_object(&self->window_state_monitor);
g_clear_object(&self->scrolling_manager);
g_clear_object(&self->keyboard_handler);
Expand Down Expand Up @@ -706,6 +710,10 @@ static void fl_view_init(FlView* self) {
// https://github.com/flutter/flutter/issues/138178
self->view_id = flutter::kFlutterImplicitViewId;

GdkRGBA default_background = {
.red = 0.0, .green = 0.0, .blue = 0.0, .alpha = 1.0};
self->background_color = gdk_rgba_copy(&default_background);

self->event_box = gtk_event_box_new();
gtk_widget_set_hexpand(self->event_box, TRUE);
gtk_widget_set_vexpand(self->event_box, TRUE);
Expand Down Expand Up @@ -743,6 +751,7 @@ static void fl_view_init(FlView* self) {
self);

self->gl_area = GTK_GL_AREA(gtk_gl_area_new());
gtk_gl_area_set_has_alpha(self->gl_area, TRUE);
gtk_widget_show(GTK_WIDGET(self->gl_area));
gtk_container_add(GTK_CONTAINER(self->event_box), GTK_WIDGET(self->gl_area));

Expand Down Expand Up @@ -785,6 +794,13 @@ G_MODULE_EXPORT FlEngine* fl_view_get_engine(FlView* self) {
return self->engine;
}

G_MODULE_EXPORT void fl_view_set_background_color(FlView* self,
const GdkRGBA* color) {
g_return_if_fail(FL_IS_VIEW(self));
gdk_rgba_free(self->background_color);
self->background_color = gdk_rgba_copy(color);
}

void fl_view_redraw(FlView* self) {
g_return_if_fail(FL_IS_VIEW(self));
gtk_widget_queue_draw(GTK_WIDGET(self->gl_area));
Expand Down
9 changes: 9 additions & 0 deletions shell/platform/linux/public/flutter_linux/fl_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,15 @@ FlView* fl_view_new_for_engine(FlEngine* engine);
*/
FlEngine* fl_view_get_engine(FlView* view);

/**
* fl_view_set_background_color:
* @view: an #FlView.
* @color: a background color.
*
* Set the background color for Flutter (defaults to black).
*/
void fl_view_set_background_color(FlView* view, const GdkRGBA* color);

G_END_DECLS

#endif // FLUTTER_SHELL_PLATFORM_LINUX_PUBLIC_FLUTTER_LINUX_FL_VIEW_H_
5 changes: 5 additions & 0 deletions shell/platform/linux/testing/mock_epoxy.cc
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,10 @@ GLuint _glCreateProgram() {

void _glCompileShader(GLuint shader) {}

void _glClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
mock->glClearColor(r, g, b, a);
}

GLuint _glCreateShader(GLenum shaderType) {
return 0;
}
Expand Down Expand Up @@ -594,6 +598,7 @@ static void library_init() {
epoxy_glBindTexture = _glBindTexture;
epoxy_glBlitFramebuffer = _glBlitFramebuffer;
epoxy_glCompileShader = _glCompileShader;
epoxy_glClearColor = _glClearColor;
epoxy_glCreateProgram = _glCreateProgram;
epoxy_glCreateShader = _glCreateShader;
epoxy_glDeleteFramebuffers = _glDeleteFramebuffers;
Expand Down
1 change: 1 addition & 0 deletions shell/platform/linux/testing/mock_epoxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class MockEpoxy {
MOCK_METHOD(bool, epoxy_has_gl_extension, (const char* extension));
MOCK_METHOD(bool, epoxy_is_desktop_gl, ());
MOCK_METHOD(int, epoxy_gl_version, ());
MOCK_METHOD(void, glClearColor, (GLfloat r, GLfloat g, GLfloat b, GLfloat a));
MOCK_METHOD(void,
glBlitFramebuffer,
(GLint srcX0,
Expand Down