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"
8 #include "flutter/fml/logging.h"
11 
12 namespace flutter {
13 
14 namespace {
15 
16 constexpr uint32_t kWindowFrameBufferId = 0;
17 
18 // The metadata for an OpenGL framebuffer backing store.
19 struct FramebufferBackingStore {
20  uint32_t framebuffer_id = 0;
21  uint32_t texture_id = 0;
22  uint32_t color_renderbuffer_id = 0;
23  uint32_t depth_stencil_id = 0;
24 };
25 
26 typedef const impeller::GLProc<decltype(glBlitFramebuffer)> BlitFramebufferProc;
27 
28 const BlitFramebufferProc& GetBlitFramebufferProc(
29  const impeller::ProcTableGLES& gl) {
30  if (gl.BlitFramebuffer.IsAvailable()) {
31  return gl.BlitFramebuffer;
32  } else if (gl.BlitFramebufferANGLE.IsAvailable()) {
33  return gl.BlitFramebufferANGLE;
34  }
35 
36  // CompositorOpenGL::Initialize verifies that a blit procedure is available.
37  FML_UNREACHABLE();
38 }
39 
40 } // namespace
41 
43  impeller::ProcTableGLES::Resolver resolver,
44  bool enable_impeller)
45  : engine_(engine), resolver_(resolver), enable_impeller_(enable_impeller) {}
46 
48  const FlutterBackingStoreConfig& config,
49  FlutterBackingStore* result) {
50  if (!is_initialized_ && !Initialize()) {
51  return false;
52  }
53 
54  auto store = std::make_unique<FramebufferBackingStore>();
55 
56  gl_->GenFramebuffers(1, &store->framebuffer_id);
57  gl_->BindFramebuffer(GL_FRAMEBUFFER, store->framebuffer_id);
58 
59  if (enable_impeller_) {
60  if (supports_implicit_msaa_) {
61  gl_->GenTextures(1, &store->texture_id);
62  gl_->BindTexture(GL_TEXTURE_2D, store->texture_id);
63  gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
64  gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
65  gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
66  gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
67  gl_->TexImage2D(GL_TEXTURE_2D, 0, format_.sized_format, config.size.width,
68  config.size.height, 0, format_.general_format,
69  GL_UNSIGNED_BYTE, nullptr);
70  gl_->BindTexture(GL_TEXTURE_2D, 0);
71 
72  // MSAA color attachment
73  gl_->FramebufferTexture2DMultisampleEXT(
74  GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
75  store->texture_id, 0, 4);
76 
77  // Impeller always requires depth/stencil attachment.
78  gl_->GenRenderbuffers(1, &store->depth_stencil_id);
79  gl_->BindRenderbuffer(GL_RENDERBUFFER, store->depth_stencil_id);
80  gl_->RenderbufferStorageMultisampleEXT(
81  GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, config.size.width,
82  config.size.height);
83  gl_->FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
84  GL_RENDERBUFFER, store->depth_stencil_id);
85  gl_->FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
86  GL_RENDERBUFFER, store->depth_stencil_id);
87  } else if (supports_offscreen_msaa_) {
88  // MSAA color renderbuffer attachment
89  gl_->GenRenderbuffers(1, &store->color_renderbuffer_id);
90  gl_->BindRenderbuffer(GL_RENDERBUFFER, store->color_renderbuffer_id);
91  gl_->RenderbufferStorageMultisample(
92  GL_RENDERBUFFER, 4, format_.sized_format, config.size.width,
93  config.size.height);
94  gl_->FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
95  GL_RENDERBUFFER,
96  store->color_renderbuffer_id);
97 
98  // MSAA depth/stencil attachment
99  gl_->GenRenderbuffers(1, &store->depth_stencil_id);
100  gl_->BindRenderbuffer(GL_RENDERBUFFER, store->depth_stencil_id);
101  gl_->RenderbufferStorageMultisample(
102  GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, config.size.width,
103  config.size.height);
104  gl_->FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
105  GL_RENDERBUFFER, store->depth_stencil_id);
106  gl_->FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
107  GL_RENDERBUFFER, store->depth_stencil_id);
108  } else {
109  gl_->GenTextures(1, &store->texture_id);
110  gl_->BindTexture(GL_TEXTURE_2D, store->texture_id);
111  gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
112  gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
113  gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
114  gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
115  gl_->TexImage2D(GL_TEXTURE_2D, 0, format_.sized_format, config.size.width,
116  config.size.height, 0, format_.general_format,
117  GL_UNSIGNED_BYTE, nullptr);
118  gl_->BindTexture(GL_TEXTURE_2D, 0);
119 
120  gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
121  GL_TEXTURE_2D, store->texture_id, 0);
122 
123  gl_->GenRenderbuffers(1, &store->depth_stencil_id);
124  gl_->BindRenderbuffer(GL_RENDERBUFFER, store->depth_stencil_id);
125  gl_->RenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8,
126  config.size.width, config.size.height);
127  gl_->FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
128  GL_RENDERBUFFER, store->depth_stencil_id);
129  gl_->FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
130  GL_RENDERBUFFER, store->depth_stencil_id);
131  }
132  } else {
133  gl_->GenTextures(1, &store->texture_id);
134  gl_->BindTexture(GL_TEXTURE_2D, store->texture_id);
135  gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
136  gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
137  gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
138  gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
139  gl_->TexImage2D(GL_TEXTURE_2D, 0, format_.sized_format, config.size.width,
140  config.size.height, 0, format_.general_format,
141  GL_UNSIGNED_BYTE, nullptr);
142  gl_->BindTexture(GL_TEXTURE_2D, 0);
143 
144  gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
145  GL_TEXTURE_2D, store->texture_id, 0);
146  }
147 
148  result->type = kFlutterBackingStoreTypeOpenGL;
149  result->open_gl.type = kFlutterOpenGLTargetTypeFramebuffer;
150  result->open_gl.framebuffer.name = store->framebuffer_id;
151  result->open_gl.framebuffer.target = format_.sized_format;
152  result->open_gl.framebuffer.user_data = store.release();
153  result->open_gl.framebuffer.destruction_callback = [](void* user_data) {
154  // Backing store destroyed in `CompositorOpenGL::CollectBackingStore`, set
155  // on FlutterCompositor.collect_backing_store_callback during engine start.
156  };
157  return true;
158 }
159 
160 bool CompositorOpenGL::CollectBackingStore(const FlutterBackingStore* store) {
161  FML_DCHECK(is_initialized_);
162  FML_DCHECK(store->type == kFlutterBackingStoreTypeOpenGL);
163  FML_DCHECK(store->open_gl.type == kFlutterOpenGLTargetTypeFramebuffer);
164 
165  auto user_data = static_cast<FramebufferBackingStore*>(
166  store->open_gl.framebuffer.user_data);
167 
168  gl_->DeleteFramebuffers(1, &user_data->framebuffer_id);
169  if (user_data->texture_id != 0) {
170  gl_->DeleteTextures(1, &user_data->texture_id);
171  }
172  if (user_data->color_renderbuffer_id != 0) {
173  gl_->DeleteRenderbuffers(1, &user_data->color_renderbuffer_id);
174  }
175  if (user_data->depth_stencil_id != 0) {
176  gl_->DeleteRenderbuffers(1, &user_data->depth_stencil_id);
177  }
178 
179  delete user_data;
180  return true;
181 }
182 
184  const FlutterLayer** layers,
185  size_t layers_count) {
186  FML_DCHECK(view != nullptr);
187 
188  // Clear the view if there are no layers to present.
189  if (layers_count == 0) {
190  // Normally the compositor is initialized when the first backing store is
191  // created. However, on an empty frame no backing stores are created and
192  // the present needs to initialize the compositor.
193  if (!is_initialized_ && !Initialize()) {
194  return false;
195  }
196 
197  return Clear(view);
198  }
199 
200  // TODO: Support compositing layers and platform views.
201  // See: https://github.com/flutter/flutter/issues/31713
202  FML_DCHECK(is_initialized_);
203  FML_DCHECK(layers_count == 1);
204  FML_DCHECK(layers[0]->offset.x == 0 && layers[0]->offset.y == 0);
205  FML_DCHECK(layers[0]->type == kFlutterLayerContentTypeBackingStore);
206  FML_DCHECK(layers[0]->backing_store->type == kFlutterBackingStoreTypeOpenGL);
207  FML_DCHECK(layers[0]->backing_store->open_gl.type ==
208  kFlutterOpenGLTargetTypeFramebuffer);
209 
210  auto width = layers[0]->size.width;
211  auto height = layers[0]->size.height;
212 
213  // Check if this frame can be presented. This resizes the surface if a resize
214  // is pending and |width| and |height| match the target size.
215  if (!view->OnFrameGenerated(width, height)) {
216  return false;
217  }
218 
219  // |OnFrameGenerated| should return false if the surface isn't valid.
220  FML_DCHECK(view->surface() != nullptr);
221  FML_DCHECK(view->surface()->IsValid());
222 
223  egl::WindowSurface* surface = view->surface();
224  if (!surface->MakeCurrent()) {
225  return false;
226  }
227 
228  auto source_id = layers[0]->backing_store->open_gl.framebuffer.name;
229 
230  // Disable the scissor test as it can affect blit operations.
231  // Prevents regressions like: https://github.com/flutter/flutter/issues/140828
232  // See OpenGL specification version 4.6, section 18.3.1.
233  gl_->Disable(GL_SCISSOR_TEST);
234  gl_->BindFramebuffer(GL_READ_FRAMEBUFFER, source_id);
235  gl_->BindFramebuffer(GL_DRAW_FRAMEBUFFER, kWindowFrameBufferId);
236 
237  auto blitFramebuffer = GetBlitFramebufferProc(*gl_);
238  blitFramebuffer(0, // srcX0
239  0, // srcY0
240  width, // srcX1
241  height, // srcY1
242  0, // dstX0
243  0, // dstY0
244  width, // dstX1
245  height, // dstY1
246  GL_COLOR_BUFFER_BIT, // mask
247  GL_NEAREST // filter
248  );
249 
250  if (!surface->SwapBuffers()) {
251  return false;
252  }
253 
254  view->OnFramePresented();
255  return true;
256 }
257 
258 bool CompositorOpenGL::Initialize() {
259  FML_DCHECK(!is_initialized_);
260 
261  egl::Manager* manager = engine_->egl_manager();
262  if (!manager) {
263  return false;
264  }
265 
266  if (!manager->render_context()->MakeCurrent()) {
267  return false;
268  }
269 
270  gl_ = std::make_unique<impeller::ProcTableGLES>(resolver_);
271  if (!gl_->IsValid()) {
272  gl_.reset();
273  return false;
274  }
275 
276  if (gl_->GetDescription()->HasExtension("GL_EXT_texture_format_BGRA8888")) {
277  format_.sized_format = GL_BGRA8_EXT;
278  format_.general_format = GL_BGRA_EXT;
279  } else {
280  format_.sized_format = GL_RGBA8;
281  format_.general_format = GL_RGBA;
282  }
283 
284  if (!gl_->BlitFramebuffer.IsAvailable() &&
285  !gl_->BlitFramebufferANGLE.IsAvailable()) {
286  FML_LOG(ERROR) << "Unable to find OpenGL blit framebuffer procedure.";
287  return false;
288  }
289 
290  supports_implicit_msaa_ =
291  gl_->GetCapabilities()->SupportsImplicitResolvingMSAA();
292  supports_offscreen_msaa_ = gl_->GetCapabilities()->SupportsOffscreenMSAA();
293 
294  if (enable_impeller_ && !supports_implicit_msaa_ &&
295  !supports_offscreen_msaa_) {
296  // TODO(190362): I suspect this branch is never taken since ANGLE will
297  // support offscreen MSAA. We should investigate removing this branch and
298  // the implicit MSAA branch in the rendering functions.
299  FML_LOG(WARNING) << "Rendering without MSAA.";
300  }
301 
302  is_initialized_ = true;
303  return true;
304 }
305 
306 bool CompositorOpenGL::Clear(FlutterWindowsView* view) {
307  FML_DCHECK(is_initialized_);
308 
309  // Check if this frame can be presented. This resizes the surface if needed.
310  if (!view->OnEmptyFrameGenerated()) {
311  return false;
312  }
313 
314  // |OnEmptyFrameGenerated| should return false if the surface isn't valid.
315  FML_DCHECK(view->surface() != nullptr);
316  FML_DCHECK(view->surface()->IsValid());
317 
318  egl::WindowSurface* surface = view->surface();
319  if (!surface->MakeCurrent()) {
320  return false;
321  }
322 
323  gl_->ClearColor(0.0f, 0.0f, 0.0f, 0.0f);
324  gl_->Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
325 
326  if (!surface->SwapBuffers()) {
327  return false;
328  }
329 
330  view->OnFramePresented();
331  return true;
332 }
333 
334 } // 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:335
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 color_renderbuffer_id
uint32_t framebuffer_id
uint32_t depth_stencil_id
enum flutter::testing::@104::KeyboardChange::Type type