| // 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 "fl_backing_store_provider.h" |
| |
| #include <epoxy/gl.h> |
| |
| struct _FlBackingStoreProvider { |
| GObject parent_instance; |
| |
| uint32_t framebuffer_id; |
| uint32_t texture_id; |
| GdkRectangle geometry; |
| }; |
| |
| G_DEFINE_TYPE(FlBackingStoreProvider, fl_backing_store_provider, G_TYPE_OBJECT) |
| |
| static void fl_backing_store_provider_dispose(GObject* object) { |
| FlBackingStoreProvider* self = FL_BACKING_STORE_PROVIDER(object); |
| |
| glDeleteFramebuffers(1, &self->framebuffer_id); |
| glDeleteTextures(1, &self->texture_id); |
| |
| G_OBJECT_CLASS(fl_backing_store_provider_parent_class)->dispose(object); |
| } |
| |
| static void fl_backing_store_provider_class_init( |
| FlBackingStoreProviderClass* klass) { |
| G_OBJECT_CLASS(klass)->dispose = fl_backing_store_provider_dispose; |
| } |
| |
| static void fl_backing_store_provider_init(FlBackingStoreProvider* self) {} |
| |
| FlBackingStoreProvider* fl_backing_store_provider_new(int width, int height) { |
| FlBackingStoreProvider* provider = FL_BACKING_STORE_PROVIDER( |
| g_object_new(fl_backing_store_provider_get_type(), nullptr)); |
| |
| provider->geometry = { |
| .x = 0, |
| .y = 0, |
| .width = width, |
| .height = height, |
| }; |
| |
| glGenTextures(1, &provider->texture_id); |
| glGenFramebuffers(1, &provider->framebuffer_id); |
| |
| glBindFramebuffer(GL_FRAMEBUFFER, provider->framebuffer_id); |
| |
| glBindTexture(GL_TEXTURE_2D, provider->texture_id); |
| glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| 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, |
| GL_UNSIGNED_BYTE, NULL); |
| glBindTexture(GL_TEXTURE_2D, 0); |
| |
| glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, |
| GL_TEXTURE_2D, provider->texture_id, 0); |
| |
| return provider; |
| } |
| |
| uint32_t fl_backing_store_provider_get_gl_framebuffer_id( |
| FlBackingStoreProvider* self) { |
| return self->framebuffer_id; |
| } |
| |
| uint32_t fl_backing_store_provider_get_gl_texture_id( |
| FlBackingStoreProvider* self) { |
| return self->texture_id; |
| } |
| |
| uint32_t fl_backing_store_provider_get_gl_target(FlBackingStoreProvider* self) { |
| return GL_TEXTURE_2D; |
| } |
| |
| uint32_t fl_backing_store_provider_get_gl_format(FlBackingStoreProvider* 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 logics are copied from Skia GrGLCaps.cpp. |
| |
| 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; |
| } |
| |
| GdkRectangle fl_backing_store_provider_get_geometry( |
| FlBackingStoreProvider* self) { |
| return self->geometry; |
| } |