Flutter Windows Embedder
compositor_opengl.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 
6 
7 #include "GLES3/gl3.h"
10 
11 namespace flutter {
12 
13 namespace {
14 
15 constexpr uint32_t kWindowFrameBufferId = 0;
16 
17 // The metadata for an OpenGL framebuffer backing store.
18 struct FramebufferBackingStore {
19  uint32_t framebuffer_id;
20  uint32_t texture_id;
21 };
22 
23 typedef const impeller::GLProc<decltype(glBlitFramebuffer)> BlitFramebufferProc;
24 
25 const BlitFramebufferProc& GetBlitFramebufferProc(
26  const impeller::ProcTableGLES& gl) {
27  if (gl.BlitFramebuffer.IsAvailable()) {
28  return gl.BlitFramebuffer;
29  } else if (gl.BlitFramebufferANGLE.IsAvailable()) {
30  return gl.BlitFramebufferANGLE;
31  }
32 
33  // CompositorOpenGL::Initialize verifies that a blit procedure is available.
34  FML_UNREACHABLE();
35 }
36 
37 } // namespace
38 
40  impeller::ProcTableGLES::Resolver resolver,
41  bool enable_impeller)
42  : engine_(engine), resolver_(resolver), enable_impeller_(enable_impeller) {}
43 
45  const FlutterBackingStoreConfig& config,
46  FlutterBackingStore* result) {
47  if (!is_initialized_ && !Initialize()) {
48  return false;
49  }
50 
51  auto store = std::make_unique<FramebufferBackingStore>();
52 
53  gl_->GenTextures(1, &store->texture_id);
54  gl_->GenFramebuffers(1, &store->framebuffer_id);
55 
56  gl_->BindFramebuffer(GL_FRAMEBUFFER, store->framebuffer_id);
57 
58  gl_->BindTexture(GL_TEXTURE_2D, store->texture_id);
59  gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
60  gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
61  gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
62  gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
63  gl_->TexImage2D(GL_TEXTURE_2D, 0, format_.general_format, config.size.width,
64  config.size.height, 0, format_.general_format,
65  GL_UNSIGNED_BYTE, nullptr);
66  gl_->BindTexture(GL_TEXTURE_2D, 0);
67 
68  if (enable_impeller_) {
69  // Impeller requries that its onscreen surface is Multisampled and already
70  // has depth/stencil attached in order for anti-aliasing to work.
71  gl_->FramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER,
72  GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
73  store->texture_id, 0, 4);
74 
75  // Set up depth/stencil attachment for impeller renderer.
76  GLuint depth_stencil;
77  gl_->GenRenderbuffers(1, &depth_stencil);
78  gl_->BindRenderbuffer(GL_RENDERBUFFER, depth_stencil);
79  gl_->RenderbufferStorageMultisampleEXT(
80  GL_RENDERBUFFER, // target
81  4, // samples
82  GL_DEPTH24_STENCIL8, // internal format
83  config.size.width, // width
84  config.size.height // height
85  );
86  gl_->FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
87  GL_RENDERBUFFER, depth_stencil);
88  gl_->FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
89  GL_RENDERBUFFER, depth_stencil);
90 
91  } else {
92  gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
93  GL_TEXTURE_2D, store->texture_id, 0);
94  }
95 
96  result->type = kFlutterBackingStoreTypeOpenGL;
97  result->open_gl.type = kFlutterOpenGLTargetTypeFramebuffer;
98  result->open_gl.framebuffer.name = store->framebuffer_id;
99  result->open_gl.framebuffer.target = format_.sized_format;
100  result->open_gl.framebuffer.user_data = store.release();
101  result->open_gl.framebuffer.destruction_callback = [](void* user_data) {
102  // Backing store destroyed in `CompositorOpenGL::CollectBackingStore`, set
103  // on FlutterCompositor.collect_backing_store_callback during engine start.
104  };
105  return true;
106 }
107 
108 bool CompositorOpenGL::CollectBackingStore(const FlutterBackingStore* store) {
109  FML_DCHECK(is_initialized_);
110  FML_DCHECK(store->type == kFlutterBackingStoreTypeOpenGL);
111  FML_DCHECK(store->open_gl.type == kFlutterOpenGLTargetTypeFramebuffer);
112 
113  auto user_data = static_cast<FramebufferBackingStore*>(
114  store->open_gl.framebuffer.user_data);
115 
116  gl_->DeleteFramebuffers(1, &user_data->framebuffer_id);
117  gl_->DeleteTextures(1, &user_data->texture_id);
118 
119  delete user_data;
120  return true;
121 }
122 
124  const FlutterLayer** layers,
125  size_t layers_count) {
126  FML_DCHECK(view != nullptr);
127 
128  // Clear the view if there are no layers to present.
129  if (layers_count == 0) {
130  // Normally the compositor is initialized when the first backing store is
131  // created. However, on an empty frame no backing stores are created and
132  // the present needs to initialize the compositor.
133  if (!is_initialized_ && !Initialize()) {
134  return false;
135  }
136 
137  return Clear(view);
138  }
139 
140  // TODO: Support compositing layers and platform views.
141  // See: https://github.com/flutter/flutter/issues/31713
142  FML_DCHECK(is_initialized_);
143  FML_DCHECK(layers_count == 1);
144  FML_DCHECK(layers[0]->offset.x == 0 && layers[0]->offset.y == 0);
145  FML_DCHECK(layers[0]->type == kFlutterLayerContentTypeBackingStore);
146  FML_DCHECK(layers[0]->backing_store->type == kFlutterBackingStoreTypeOpenGL);
147  FML_DCHECK(layers[0]->backing_store->open_gl.type ==
148  kFlutterOpenGLTargetTypeFramebuffer);
149 
150  auto width = layers[0]->size.width;
151  auto height = layers[0]->size.height;
152 
153  // Check if this frame can be presented. This resizes the surface if a resize
154  // is pending and |width| and |height| match the target size.
155  if (!view->OnFrameGenerated(width, height)) {
156  return false;
157  }
158 
159  // |OnFrameGenerated| should return false if the surface isn't valid.
160  FML_DCHECK(view->surface() != nullptr);
161  FML_DCHECK(view->surface()->IsValid());
162 
163  egl::WindowSurface* surface = view->surface();
164  if (!surface->MakeCurrent()) {
165  return false;
166  }
167 
168  auto source_id = layers[0]->backing_store->open_gl.framebuffer.name;
169 
170  // Disable the scissor test as it can affect blit operations.
171  // Prevents regressions like: https://github.com/flutter/flutter/issues/140828
172  // See OpenGL specification version 4.6, section 18.3.1.
173  gl_->Disable(GL_SCISSOR_TEST);
174  gl_->BindFramebuffer(GL_READ_FRAMEBUFFER, source_id);
175  gl_->BindFramebuffer(GL_DRAW_FRAMEBUFFER, kWindowFrameBufferId);
176 
177  auto blitFramebuffer = GetBlitFramebufferProc(*gl_);
178  blitFramebuffer(0, // srcX0
179  0, // srcY0
180  width, // srcX1
181  height, // srcY1
182  0, // dstX0
183  0, // dstY0
184  width, // dstX1
185  height, // dstY1
186  GL_COLOR_BUFFER_BIT, // mask
187  GL_NEAREST // filter
188  );
189 
190  if (!surface->SwapBuffers()) {
191  return false;
192  }
193 
194  view->OnFramePresented();
195  return true;
196 }
197 
198 bool CompositorOpenGL::Initialize() {
199  FML_DCHECK(!is_initialized_);
200 
201  egl::Manager* manager = engine_->egl_manager();
202  if (!manager) {
203  return false;
204  }
205 
206  if (!manager->render_context()->MakeCurrent()) {
207  return false;
208  }
209 
210  gl_ = std::make_unique<impeller::ProcTableGLES>(resolver_);
211  if (!gl_->IsValid()) {
212  gl_.reset();
213  return false;
214  }
215 
216  if (gl_->GetDescription()->HasExtension("GL_EXT_texture_format_BGRA8888")) {
217  format_.sized_format = GL_BGRA8_EXT;
218  format_.general_format = GL_BGRA_EXT;
219  } else {
220  format_.sized_format = GL_RGBA8;
221  format_.general_format = GL_RGBA;
222  }
223 
224  if (!gl_->BlitFramebuffer.IsAvailable() &&
225  !gl_->BlitFramebufferANGLE.IsAvailable()) {
226  FML_LOG(ERROR) << "Unable to find OpenGL blit framebuffer procedure.";
227  return false;
228  }
229 
230  is_initialized_ = true;
231  return true;
232 }
233 
234 bool CompositorOpenGL::Clear(FlutterWindowsView* view) {
235  FML_DCHECK(is_initialized_);
236 
237  // Check if this frame can be presented. This resizes the surface if needed.
238  if (!view->OnEmptyFrameGenerated()) {
239  return false;
240  }
241 
242  // |OnEmptyFrameGenerated| should return false if the surface isn't valid.
243  FML_DCHECK(view->surface() != nullptr);
244  FML_DCHECK(view->surface()->IsValid());
245 
246  egl::WindowSurface* surface = view->surface();
247  if (!surface->MakeCurrent()) {
248  return false;
249  }
250 
251  gl_->ClearColor(0.0f, 0.0f, 0.0f, 0.0f);
252  gl_->Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
253 
254  if (!surface->SwapBuffers()) {
255  return false;
256  }
257 
258  view->OnFramePresented();
259  return true;
260 }
261 
262 } // namespace flutter
bool Present(FlutterWindowsView *view, const FlutterLayer **layers, size_t layers_count) override
|Compositor|
bool CreateBackingStore(const FlutterBackingStoreConfig &config, FlutterBackingStore *result) override
|Compositor|
bool CollectBackingStore(const FlutterBackingStore *store) override
|Compositor|
CompositorOpenGL(FlutterWindowsEngine *engine, impeller::ProcTableGLES::Resolver resolver, bool enable_impeller)
egl::WindowSurface * surface() const
bool OnFrameGenerated(size_t width, size_t height)
virtual bool MakeCurrent() const
Definition: context.cc:29
virtual Context * render_context() const
Definition: manager.cc:328
virtual bool SwapBuffers() const
Definition: surface.cc:59
virtual bool IsValid() const
Definition: surface.cc:19
virtual bool MakeCurrent() const
Definition: surface.cc:50
uint32_t texture_id
uint32_t framebuffer_id
enum flutter::testing::@88::KeyboardChange::Type type