Flutter Windows Embedder
compositor_opengl_unittests.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 <memory>
6 #include <vector>
7 
8 #include "flutter/impeller/renderer/backend/gles/gles.h"
12 #include "flutter/shell/platform/windows/testing/egl/mock_context.h"
13 #include "flutter/shell/platform/windows/testing/egl/mock_manager.h"
14 #include "flutter/shell/platform/windows/testing/egl/mock_window_surface.h"
15 #include "flutter/shell/platform/windows/testing/engine_modifier.h"
16 #include "flutter/shell/platform/windows/testing/flutter_windows_engine_builder.h"
17 #include "flutter/shell/platform/windows/testing/mock_window_binding_handler.h"
18 #include "flutter/shell/platform/windows/testing/view_modifier.h"
19 #include "flutter/shell/platform/windows/testing/windows_test.h"
20 #include "gmock/gmock.h"
21 #include "gtest/gtest.h"
22 
23 namespace flutter {
24 namespace testing {
25 
26 namespace {
27 using ::testing::AnyNumber;
28 using ::testing::Return;
29 
30 void MockGetIntegerv(GLenum name, int* value) {
31  if (name == GL_NUM_EXTENSIONS) {
32  *value = 1;
33  } else {
34  *value = 0;
35  }
36 }
37 
38 const unsigned char* MockGetString(GLenum name) {
39  switch (name) {
40  case GL_VERSION:
41  case GL_SHADING_LANGUAGE_VERSION:
42  return reinterpret_cast<const unsigned char*>("3.0");
43  default:
44  return reinterpret_cast<const unsigned char*>("");
45  }
46 }
47 
48 const unsigned char* MockGetStringi(GLenum name, int index) {
49  if (name == GL_EXTENSIONS) {
50  return reinterpret_cast<const unsigned char*>("GL_ANGLE_framebuffer_blit");
51  } else {
52  return reinterpret_cast<const unsigned char*>("");
53  }
54 }
55 
56 GLenum MockGetError() {
57  return GL_NO_ERROR;
58 }
59 
60 void DoNothing() {}
61 
62 const impeller::ProcTableGLES::Resolver kMockResolver = [](const char* name) {
63  std::string function_name{name};
64 
65  if (function_name == "glGetString") {
66  return reinterpret_cast<void*>(&MockGetString);
67  } else if (function_name == "glGetStringi") {
68  return reinterpret_cast<void*>(&MockGetStringi);
69  } else if (function_name == "glGetIntegerv") {
70  return reinterpret_cast<void*>(&MockGetIntegerv);
71  } else if (function_name == "glGetError") {
72  return reinterpret_cast<void*>(&MockGetError);
73  } else {
74  return reinterpret_cast<void*>(&DoNothing);
75  }
76 };
77 
78 class CompositorOpenGLTest : public WindowsTest {
79  public:
80  CompositorOpenGLTest() = default;
81  virtual ~CompositorOpenGLTest() = default;
82 
83  protected:
84  FlutterWindowsEngine* engine() { return engine_.get(); }
85  FlutterWindowsView* view() { return view_.get(); }
86  egl::MockManager* egl_manager() { return egl_manager_; }
87  egl::MockContext* render_context() { return render_context_.get(); }
88  egl::MockWindowSurface* surface() { return surface_; }
89 
90  void UseHeadlessEngine() {
91  auto egl_manager = std::make_unique<egl::MockManager>();
92  render_context_ = std::make_unique<egl::MockContext>();
93  egl_manager_ = egl_manager.get();
94 
95  EXPECT_CALL(*egl_manager_, render_context)
96  .Times(AnyNumber())
97  .WillRepeatedly(Return(render_context_.get()));
98 
99  FlutterWindowsEngineBuilder builder{GetContext()};
100 
101  engine_ = builder.Build();
102  EngineModifier modifier{engine_.get()};
103  modifier.SetEGLManager(std::move(egl_manager));
104  }
105 
106  void UseEngineWithView(bool add_surface = true) {
107  UseHeadlessEngine();
108 
109  auto window = std::make_unique<MockWindowBindingHandler>();
110  EXPECT_CALL(*window.get(), SetView).Times(1);
111  EXPECT_CALL(*window.get(), GetWindowHandle).WillRepeatedly(Return(nullptr));
112 
113  view_ = std::make_unique<FlutterWindowsView>(kImplicitViewId, engine_.get(),
114  std::move(window));
115 
116  if (add_surface) {
117  auto surface = std::make_unique<egl::MockWindowSurface>();
118  surface_ = surface.get();
119 
120  EXPECT_CALL(*surface_, Destroy).Times(AnyNumber());
121 
122  ViewModifier modifier{view_.get()};
123  modifier.SetSurface(std::move(surface));
124  }
125  }
126 
127  private:
128  std::unique_ptr<FlutterWindowsEngine> engine_;
129  std::unique_ptr<FlutterWindowsView> view_;
130  std::unique_ptr<egl::MockContext> render_context_;
131  egl::MockWindowSurface* surface_;
132  egl::MockManager* egl_manager_;
133 
134  FML_DISALLOW_COPY_AND_ASSIGN(CompositorOpenGLTest);
135 };
136 
137 } // namespace
138 
139 TEST_F(CompositorOpenGLTest, CreateBackingStore) {
140  UseHeadlessEngine();
141 
142  auto compositor =
143  CompositorOpenGL{engine(), kMockResolver, /*enable_impeller=*/false};
144 
145  FlutterBackingStoreConfig config = {};
146  FlutterBackingStore backing_store = {};
147 
148  EXPECT_CALL(*render_context(), MakeCurrent).WillOnce(Return(true));
149  ASSERT_TRUE(compositor.CreateBackingStore(config, &backing_store));
150  ASSERT_TRUE(compositor.CollectBackingStore(&backing_store));
151 }
152 
153 TEST_F(CompositorOpenGLTest, CreateBackingStoreImpeller) {
154  UseHeadlessEngine();
155 
156  auto compositor =
157  CompositorOpenGL{engine(), kMockResolver, /*enable_impeller=*/true};
158 
159  FlutterBackingStoreConfig config = {};
160  FlutterBackingStore backing_store = {};
161 
162  EXPECT_CALL(*render_context(), MakeCurrent).WillOnce(Return(true));
163  ASSERT_TRUE(compositor.CreateBackingStore(config, &backing_store));
164  ASSERT_TRUE(compositor.CollectBackingStore(&backing_store));
165 }
166 
167 TEST_F(CompositorOpenGLTest, InitializationFailure) {
168  UseHeadlessEngine();
169 
170  auto compositor =
171  CompositorOpenGL{engine(), kMockResolver, /*enable_impeller=*/false};
172 
173  FlutterBackingStoreConfig config = {};
174  FlutterBackingStore backing_store = {};
175 
176  EXPECT_CALL(*render_context(), MakeCurrent).WillOnce(Return(false));
177  EXPECT_FALSE(compositor.CreateBackingStore(config, &backing_store));
178 }
179 
180 TEST_F(CompositorOpenGLTest, InitializationRequiresBlit) {
181  UseHeadlessEngine();
182 
183  const impeller::ProcTableGLES::Resolver resolver = [](const char* name) {
184  std::string function_name{name};
185 
186  if (function_name == "glBlitFramebuffer" ||
187  function_name == "glBlitFramebufferANGLE") {
188  return (void*)nullptr;
189  }
190 
191  return kMockResolver(name);
192  };
193 
194  auto compositor =
195  CompositorOpenGL{engine(), resolver, /*enable_impeller=*/false};
196 
197  FlutterBackingStoreConfig config = {};
198  FlutterBackingStore backing_store = {};
199 
200  EXPECT_CALL(*render_context(), MakeCurrent).WillOnce(Return(true));
201  ASSERT_FALSE(compositor.CreateBackingStore(config, &backing_store));
202 }
203 
204 TEST_F(CompositorOpenGLTest, Present) {
205  UseEngineWithView();
206 
207  auto compositor =
208  CompositorOpenGL{engine(), kMockResolver, /*enable_impeller=*/false};
209 
210  FlutterBackingStoreConfig config = {};
211  FlutterBackingStore backing_store = {};
212 
213  EXPECT_CALL(*render_context(), MakeCurrent).WillOnce(Return(true));
214  ASSERT_TRUE(compositor.CreateBackingStore(config, &backing_store));
215 
216  FlutterLayer layer = {};
217  layer.type = kFlutterLayerContentTypeBackingStore;
218  layer.backing_store = &backing_store;
219  const FlutterLayer* layer_ptr = &layer;
220 
221  EXPECT_CALL(*surface(), IsValid).WillRepeatedly(Return(true));
222  EXPECT_CALL(*surface(), MakeCurrent).WillOnce(Return(true));
223  EXPECT_CALL(*surface(), SwapBuffers).WillOnce(Return(true));
224  EXPECT_TRUE(compositor.Present(view(), &layer_ptr, 1));
225 
226  ASSERT_TRUE(compositor.CollectBackingStore(&backing_store));
227 }
228 
229 TEST_F(CompositorOpenGLTest, PresentEmpty) {
230  UseEngineWithView();
231 
232  auto compositor =
233  CompositorOpenGL{engine(), kMockResolver, /*enable_impeller=*/false};
234 
235  // The context will be bound twice: first to initialize the compositor, second
236  // to clear the surface.
237  EXPECT_CALL(*render_context(), MakeCurrent).WillOnce(Return(true));
238  EXPECT_CALL(*surface(), IsValid).WillRepeatedly(Return(true));
239  EXPECT_CALL(*surface(), MakeCurrent).WillOnce(Return(true));
240  EXPECT_CALL(*surface(), SwapBuffers).WillOnce(Return(true));
241  EXPECT_TRUE(compositor.Present(view(), nullptr, 0));
242 }
243 
244 TEST_F(CompositorOpenGLTest, NoSurfaceIgnored) {
245  UseEngineWithView(/*add_surface = */ false);
246 
247  auto compositor =
248  CompositorOpenGL{engine(), kMockResolver, /*enable_impeller=*/false};
249 
250  FlutterBackingStoreConfig config = {};
251  FlutterBackingStore backing_store = {};
252 
253  EXPECT_CALL(*render_context(), MakeCurrent).WillOnce(Return(true));
254  ASSERT_TRUE(compositor.CreateBackingStore(config, &backing_store));
255 
256  FlutterLayer layer = {};
257  layer.type = kFlutterLayerContentTypeBackingStore;
258  layer.backing_store = &backing_store;
259  const FlutterLayer* layer_ptr = &layer;
260 
261  EXPECT_FALSE(compositor.Present(view(), &layer_ptr, 1));
262 
263  ASSERT_TRUE(compositor.CollectBackingStore(&backing_store));
264 }
265 
266 TEST_F(CompositorOpenGLTest, PresentUsingANGLEBlitExtension) {
267  UseEngineWithView();
268 
269  bool resolved_ANGLE_blit = false;
270  const impeller::ProcTableGLES::Resolver resolver =
271  [&resolved_ANGLE_blit](const char* name) {
272  std::string function_name{name};
273 
274  if (function_name == "glBlitFramebuffer") {
275  return (void*)nullptr;
276  } else if (function_name == "glBlitFramebufferANGLE") {
277  resolved_ANGLE_blit = true;
278  return reinterpret_cast<void*>(&DoNothing);
279  }
280 
281  return kMockResolver(name);
282  };
283 
284  auto compositor =
285  CompositorOpenGL{engine(), resolver, /*enable_impeller=*/false};
286 
287  FlutterBackingStoreConfig config = {};
288  FlutterBackingStore backing_store = {};
289 
290  EXPECT_CALL(*render_context(), MakeCurrent).WillOnce(Return(true));
291  ASSERT_TRUE(compositor.CreateBackingStore(config, &backing_store));
292 
293  FlutterLayer layer = {};
294  layer.type = kFlutterLayerContentTypeBackingStore;
295  layer.backing_store = &backing_store;
296  const FlutterLayer* layer_ptr = &layer;
297 
298  EXPECT_CALL(*surface(), IsValid).WillRepeatedly(Return(true));
299  EXPECT_CALL(*surface(), MakeCurrent).WillOnce(Return(true));
300  EXPECT_CALL(*surface(), SwapBuffers).WillOnce(Return(true));
301  EXPECT_TRUE(compositor.Present(view(), &layer_ptr, 1));
302  EXPECT_TRUE(resolved_ANGLE_blit);
303 
304  ASSERT_TRUE(compositor.CollectBackingStore(&backing_store));
305 }
306 
307 } // namespace testing
308 } // namespace flutter
TEST_F(CompositorOpenGLTest, CreateBackingStore)
constexpr FlutterViewId kImplicitViewId