Flutter Linux Embedder
fl_framebuffer.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "fl_framebuffer.h"
6 
7 #include <epoxy/egl.h>
8 #include <epoxy/gl.h>
9 
11  GObject parent_instance;
12 
13  // Width of framebuffer in pixels.
14  size_t width;
15 
16  // Height of framebuffer in pixels.
17  size_t height;
18 
19  // Framebuffer ID.
21 
22  // Texture backing framebuffer.
23  GLuint texture_id;
24 
25  // Stencil buffer associated with this framebuffer.
26  GLuint depth_stencil;
27 
28  // EGL image for this texture.
29  EGLImage image;
30 };
31 
32 G_DEFINE_TYPE(FlFramebuffer, fl_framebuffer, G_TYPE_OBJECT)
33 
34 static EGLImage create_egl_image(GLuint texture_id) {
35  EGLDisplay egl_display = eglGetCurrentDisplay();
36  if (egl_display == EGL_NO_DISPLAY) {
37  g_warning("Failed to create EGL image: Failed to get current EGL display");
38  return nullptr;
39  }
40 
41  EGLContext egl_context = eglGetCurrentContext();
42  if (egl_context == EGL_NO_CONTEXT) {
43  g_warning("Failed to create EGL image: Failed to get current EGL context");
44  return nullptr;
45  }
46 
47  return eglCreateImage(
48  egl_display, egl_context, EGL_GL_TEXTURE_2D,
49  reinterpret_cast<EGLClientBuffer>(static_cast<intptr_t>(texture_id)),
50  nullptr);
51 }
52 
53 static void fl_framebuffer_dispose(GObject* object) {
54  FlFramebuffer* self = FL_FRAMEBUFFER(object);
55 
56  glDeleteFramebuffers(1, &self->framebuffer_id);
57  glDeleteTextures(1, &self->texture_id);
58  glDeleteRenderbuffers(1, &self->depth_stencil);
59 
60  G_OBJECT_CLASS(fl_framebuffer_parent_class)->dispose(object);
61 }
62 
63 static void fl_framebuffer_class_init(FlFramebufferClass* klass) {
64  G_OBJECT_CLASS(klass)->dispose = fl_framebuffer_dispose;
65 }
66 
67 static void fl_framebuffer_init(FlFramebuffer* self) {}
68 
69 FlFramebuffer* fl_framebuffer_new(GLint format,
70  size_t width,
71  size_t height,
72  gboolean shareable) {
73  FlFramebuffer* self =
74  FL_FRAMEBUFFER(g_object_new(fl_framebuffer_get_type(), nullptr));
75 
76  self->width = width;
77  self->height = height;
78 
79  glGenTextures(1, &self->texture_id);
80  glGenFramebuffers(1, &self->framebuffer_id);
81 
82  glBindFramebuffer(GL_FRAMEBUFFER, self->framebuffer_id);
83 
84  glBindTexture(GL_TEXTURE_2D, self->texture_id);
85  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
86  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
87  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
88  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
89  glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format,
90  GL_UNSIGNED_BYTE, NULL);
91  glBindTexture(GL_TEXTURE_2D, 0);
92 
93  if (shareable) {
94  self->image = create_egl_image(self->texture_id);
95  }
96 
97  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
98  self->texture_id, 0);
99 
100  glGenRenderbuffers(1, &self->depth_stencil);
101  glBindRenderbuffer(GL_RENDERBUFFER, self->depth_stencil);
102  glRenderbufferStorage(GL_RENDERBUFFER, // target
103  GL_DEPTH24_STENCIL8, // internal format
104  width, // width
105  height // height
106  );
107  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
108  GL_RENDERBUFFER, self->depth_stencil);
109  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
110  GL_RENDERBUFFER, self->depth_stencil);
111 
112  return self;
113 }
114 
115 gboolean fl_framebuffer_get_shareable(FlFramebuffer* self) {
116  g_return_val_if_fail(FL_IS_FRAMEBUFFER(self), FALSE);
117  return self->image != nullptr;
118 }
119 
120 FlFramebuffer* fl_framebuffer_create_sibling(FlFramebuffer* self) {
121  g_return_val_if_fail(FL_IS_FRAMEBUFFER(self), nullptr);
122  g_return_val_if_fail(self->image != nullptr, nullptr);
123 
124  FlFramebuffer* sibling =
125  FL_FRAMEBUFFER(g_object_new(fl_framebuffer_get_type(), nullptr));
126 
127  sibling->width = self->width;
128  sibling->height = self->height;
129  sibling->image = self->image;
130 
131  // Make texture from existing image.
132  glGenTextures(1, &sibling->texture_id);
133  glBindTexture(GL_TEXTURE_2D, sibling->texture_id);
134  glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, self->image);
135 
136  // Make framebuffer that uses this texture.
137  glGenFramebuffers(1, &sibling->framebuffer_id);
138  GLint saved_framebuffer_binding;
139  glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &saved_framebuffer_binding);
140  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, sibling->framebuffer_id);
141  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
142  sibling->texture_id, 0);
143  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, saved_framebuffer_binding);
144 
145  return sibling;
146 }
147 
148 GLuint fl_framebuffer_get_id(FlFramebuffer* self) {
149  return self->framebuffer_id;
150 }
151 
152 GLuint fl_framebuffer_get_texture_id(FlFramebuffer* self) {
153  return self->texture_id;
154 }
155 
156 size_t fl_framebuffer_get_width(FlFramebuffer* self) {
157  return self->width;
158 }
159 
160 size_t fl_framebuffer_get_height(FlFramebuffer* self) {
161  return self->height;
162 }
G_DEFINE_TYPE(FlBasicMessageChannelResponseHandle, fl_basic_message_channel_response_handle, G_TYPE_OBJECT) static void fl_basic_message_channel_response_handle_dispose(GObject *object)
G_BEGIN_DECLS FlOpenGLManager gboolean shareable
self height
self width
static EGLImage create_egl_image(GLuint texture_id)
size_t fl_framebuffer_get_height(FlFramebuffer *self)
static void fl_framebuffer_init(FlFramebuffer *self)
GLuint fl_framebuffer_get_id(FlFramebuffer *self)
static void fl_framebuffer_class_init(FlFramebufferClass *klass)
static void fl_framebuffer_dispose(GObject *object)
gboolean fl_framebuffer_get_shareable(FlFramebuffer *self)
size_t fl_framebuffer_get_width(FlFramebuffer *self)
GLuint fl_framebuffer_get_texture_id(FlFramebuffer *self)
FlFramebuffer * fl_framebuffer_create_sibling(FlFramebuffer *self)
FlFramebuffer * fl_framebuffer_new(GLint format, size_t width, size_t height, gboolean shareable)
uint32_t uint32_t * format
GObject parent_instance
int64_t texture_id