Flutter Engine
The Flutter Engine
flutter_windows_texture_registrar_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 "flutter/fml/synchronization/waitable_event.h"
6#include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
7#include "flutter/shell/platform/windows/egl/proc_table.h"
8#include "flutter/shell/platform/windows/flutter_windows_engine.h"
9#include "flutter/shell/platform/windows/flutter_windows_texture_registrar.h"
10#include "flutter/shell/platform/windows/testing/egl/mock_proc_table.h"
11#include "flutter/shell/platform/windows/testing/engine_modifier.h"
12#include "gtest/gtest.h"
13
14namespace flutter {
15namespace testing {
16
17using ::testing::_;
18using ::testing::AtLeast;
19
20using Microsoft::WRL::ComPtr;
21
22namespace {
23// Returns an engine instance configured with dummy project path values.
24std::unique_ptr<FlutterWindowsEngine> GetTestEngine() {
25 FlutterDesktopEngineProperties properties = {};
26 properties.assets_path = L"C:\\foo\\flutter_assets";
27 properties.icu_data_path = L"C:\\foo\\icudtl.dat";
28 properties.aot_library_path = L"C:\\foo\\aot.so";
29 FlutterProjectBundle project(properties);
30 auto engine = std::make_unique<FlutterWindowsEngine>(project);
31
32 EngineModifier modifier(engine.get());
33 modifier.embedder_api().RegisterExternalTexture =
34 MOCK_ENGINE_PROC(RegisterExternalTexture,
35 ([](auto engine, auto texture_id) { return kSuccess; }));
36
37 return engine;
38}
39
40// Creates a ID3D11Texture2D with the specified size.
41ComPtr<ID3D11Texture2D> CreateD3dTexture(FlutterWindowsEngine* engine,
42 UINT width,
43 UINT height) {
44 ComPtr<ID3D11Device> d3d_device;
45 ComPtr<ID3D11Texture2D> d3d_texture;
46 if (engine->egl_manager()->GetDevice(d3d_device.GetAddressOf())) {
47 D3D11_TEXTURE2D_DESC texture_description = {};
48 texture_description.MipLevels = 1;
49 texture_description.SampleDesc.Count = 1;
50 texture_description.BindFlags = D3D11_BIND_RENDER_TARGET;
51 texture_description.Usage = D3D11_USAGE_DEFAULT;
52 texture_description.CPUAccessFlags = 0;
53 texture_description.ArraySize = 1;
54 texture_description.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
55 texture_description.Height = width;
56 texture_description.Width = height;
57 texture_description.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
58
59 d3d_device->CreateTexture2D(&texture_description, nullptr,
60 d3d_texture.GetAddressOf());
61 }
62 return d3d_texture;
63}
64
65} // namespace
66
67TEST(FlutterWindowsTextureRegistrarTest, CreateDestroy) {
68 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
69 auto gl = std::make_shared<egl::MockProcTable>();
71
72 EXPECT_TRUE(true);
73}
74
75TEST(FlutterWindowsTextureRegistrarTest, RegisterUnregisterTexture) {
76 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
77 EngineModifier modifier(engine.get());
78 auto gl = std::make_shared<egl::MockProcTable>();
79
81
82 FlutterDesktopTextureInfo texture_info = {};
84 texture_info.pixel_buffer_config.callback =
85 [](size_t width, size_t height,
86 void* user_data) -> const FlutterDesktopPixelBuffer* {
87 return nullptr;
88 };
89
90 int64_t registered_texture_id = 0;
91 bool register_called = false;
93 RegisterExternalTexture, ([&register_called, &registered_texture_id](
94 auto engine, auto texture_id) {
95 register_called = true;
96 registered_texture_id = texture_id;
97 return kSuccess;
98 }));
99
100 bool unregister_called = false;
102 UnregisterExternalTexture, ([&unregister_called, &registered_texture_id](
103 auto engine, auto texture_id) {
104 unregister_called = true;
105 EXPECT_EQ(registered_texture_id, texture_id);
106 return kSuccess;
107 }));
108
109 bool mark_frame_available_called = false;
111 MOCK_ENGINE_PROC(MarkExternalTextureFrameAvailable,
112 ([&mark_frame_available_called, &registered_texture_id](
113 auto engine, auto texture_id) {
114 mark_frame_available_called = true;
115 EXPECT_EQ(registered_texture_id, texture_id);
116 return kSuccess;
117 }));
118
120 MOCK_ENGINE_PROC(PostRenderThreadTask,
121 [](auto engine, auto callback, void* callback_data) {
122 callback(callback_data);
123 return kSuccess;
124 });
125
126 auto texture_id = registrar.RegisterTexture(&texture_info);
127 EXPECT_TRUE(register_called);
128 EXPECT_NE(texture_id, -1);
129 EXPECT_EQ(texture_id, registered_texture_id);
130
132 EXPECT_TRUE(mark_frame_available_called);
133
135 registrar.UnregisterTexture(texture_id, [&]() { latch.Signal(); });
136 latch.Wait();
137 ASSERT_TRUE(unregister_called);
138}
139
140TEST(FlutterWindowsTextureRegistrarTest, RegisterUnknownTextureType) {
141 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
142 auto gl = std::make_shared<egl::MockProcTable>();
143
144 FlutterWindowsTextureRegistrar registrar(engine.get(), gl);
145
146 FlutterDesktopTextureInfo texture_info = {};
147 texture_info.type = static_cast<FlutterDesktopTextureType>(1234);
148
149 auto texture_id = registrar.RegisterTexture(&texture_info);
150
151 EXPECT_EQ(texture_id, -1);
152}
153
154TEST(FlutterWindowsTextureRegistrarTest, PopulatePixelBufferTexture) {
155 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
156 auto gl = std::make_shared<egl::MockProcTable>();
157
158 FlutterWindowsTextureRegistrar registrar(engine.get(), gl);
159
160 bool release_callback_called = false;
161 size_t width = 100;
162 size_t height = 100;
163 std::unique_ptr<uint8_t[]> pixels =
164 std::make_unique<uint8_t[]>(width * height * 4);
165 FlutterDesktopPixelBuffer pixel_buffer = {};
166 pixel_buffer.width = width;
167 pixel_buffer.height = height;
168 pixel_buffer.buffer = pixels.get();
169 pixel_buffer.release_context = &release_callback_called;
170 pixel_buffer.release_callback = [](void* release_context) {
171 bool* called = reinterpret_cast<bool*>(release_context);
172 *called = true;
173 };
174
175 FlutterDesktopTextureInfo texture_info = {};
177 texture_info.pixel_buffer_config.user_data = &pixel_buffer;
178 texture_info.pixel_buffer_config.callback =
179 [](size_t width, size_t height,
180 void* user_data) -> const FlutterDesktopPixelBuffer* {
181 return reinterpret_cast<const FlutterDesktopPixelBuffer*>(user_data);
182 };
183
184 FlutterOpenGLTexture flutter_texture = {};
185 auto texture_id = registrar.RegisterTexture(&texture_info);
186 EXPECT_NE(texture_id, -1);
187
188 EXPECT_CALL(*gl.get(), GenTextures(1, _))
189 .Times(1)
190 .WillOnce([](GLsizei n, GLuint* textures) { textures[0] = 1; });
191 EXPECT_CALL(*gl.get(), BindTexture).Times(1);
192 EXPECT_CALL(*gl.get(), TexParameteri).Times(AtLeast(1));
193 EXPECT_CALL(*gl.get(), TexImage2D).Times(1);
194 EXPECT_CALL(*gl.get(), DeleteTextures(1, _)).Times(1);
195
196 auto result =
197 registrar.PopulateTexture(texture_id, 640, 480, &flutter_texture);
199 EXPECT_EQ(flutter_texture.width, width);
200 EXPECT_EQ(flutter_texture.height, height);
201 EXPECT_EQ(flutter_texture.target, GL_TEXTURE_2D);
202 EXPECT_TRUE(release_callback_called);
203}
204
205TEST(FlutterWindowsTextureRegistrarTest, PopulateD3dTextureWithHandle) {
206 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
207 auto gl = std::make_shared<egl::MockProcTable>();
208 FlutterWindowsTextureRegistrar registrar(engine.get(), gl);
209
210 UINT width = 100;
211 UINT height = 100;
212 auto d3d_texture = CreateD3dTexture(engine.get(), width, height);
213 EXPECT_TRUE(d3d_texture);
214
215 ComPtr<IDXGIResource> shared_resource;
216 EXPECT_TRUE(SUCCEEDED(d3d_texture.As(&shared_resource)));
217
218 HANDLE shared_handle;
219 EXPECT_TRUE(SUCCEEDED(shared_resource->GetSharedHandle(&shared_handle)));
220
221 bool release_callback_called = false;
222 FlutterDesktopGpuSurfaceDescriptor surface_descriptor = {};
223 surface_descriptor.struct_size = sizeof(FlutterDesktopGpuSurfaceDescriptor);
224 surface_descriptor.handle = shared_handle;
225 surface_descriptor.width = surface_descriptor.visible_width = width;
226 surface_descriptor.height = surface_descriptor.visible_height = height;
227 surface_descriptor.release_context = &release_callback_called;
228 surface_descriptor.release_callback = [](void* release_context) {
229 bool* called = reinterpret_cast<bool*>(release_context);
230 *called = true;
231 };
232
233 FlutterDesktopTextureInfo texture_info = {};
235 texture_info.gpu_surface_config.struct_size =
237 texture_info.gpu_surface_config.type =
239 texture_info.gpu_surface_config.user_data = &surface_descriptor;
240 texture_info.gpu_surface_config.callback =
241 [](size_t width, size_t height,
243 return reinterpret_cast<const FlutterDesktopGpuSurfaceDescriptor*>(
244 user_data);
245 };
246
247 FlutterOpenGLTexture flutter_texture = {};
248 auto texture_id = registrar.RegisterTexture(&texture_info);
249 EXPECT_NE(texture_id, -1);
250
251 EXPECT_CALL(*gl.get(), GenTextures(1, _))
252 .Times(1)
253 .WillOnce([](GLsizei n, GLuint* textures) { textures[0] = 1; });
254 EXPECT_CALL(*gl.get(), BindTexture).Times(1);
255 EXPECT_CALL(*gl.get(), TexParameteri).Times(AtLeast(1));
256 EXPECT_CALL(*gl.get(), DeleteTextures(1, _)).Times(1);
257
258 auto result =
259 registrar.PopulateTexture(texture_id, 640, 480, &flutter_texture);
261 EXPECT_EQ(flutter_texture.width, width);
262 EXPECT_EQ(flutter_texture.height, height);
263 EXPECT_EQ(flutter_texture.target, GL_TEXTURE_2D);
264 EXPECT_TRUE(release_callback_called);
265}
266
267TEST(FlutterWindowsTextureRegistrarTest, PopulateD3dTexture) {
268 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
269 auto gl = std::make_shared<egl::MockProcTable>();
270 FlutterWindowsTextureRegistrar registrar(engine.get(), gl);
271
272 UINT width = 100;
273 UINT height = 100;
274 auto d3d_texture = CreateD3dTexture(engine.get(), width, height);
275 EXPECT_TRUE(d3d_texture);
276
277 bool release_callback_called = false;
278 FlutterDesktopGpuSurfaceDescriptor surface_descriptor = {};
279 surface_descriptor.struct_size = sizeof(FlutterDesktopGpuSurfaceDescriptor);
280 surface_descriptor.handle = d3d_texture.Get();
281 surface_descriptor.width = surface_descriptor.visible_width = width;
282 surface_descriptor.height = surface_descriptor.visible_height = height;
283 surface_descriptor.release_context = &release_callback_called;
284 surface_descriptor.release_callback = [](void* release_context) {
285 bool* called = reinterpret_cast<bool*>(release_context);
286 *called = true;
287 };
288
289 FlutterDesktopTextureInfo texture_info = {};
291 texture_info.gpu_surface_config.struct_size =
293 texture_info.gpu_surface_config.type =
295 texture_info.gpu_surface_config.user_data = &surface_descriptor;
296 texture_info.gpu_surface_config.callback =
297 [](size_t width, size_t height,
299 return reinterpret_cast<const FlutterDesktopGpuSurfaceDescriptor*>(
300 user_data);
301 };
302
303 FlutterOpenGLTexture flutter_texture = {};
304 auto texture_id = registrar.RegisterTexture(&texture_info);
305 EXPECT_NE(texture_id, -1);
306
307 EXPECT_CALL(*gl.get(), GenTextures(1, _))
308 .Times(1)
309 .WillOnce([](GLsizei n, GLuint* textures) { textures[0] = 1; });
310 EXPECT_CALL(*gl.get(), BindTexture).Times(1);
311 EXPECT_CALL(*gl.get(), TexParameteri).Times(AtLeast(1));
312 EXPECT_CALL(*gl.get(), DeleteTextures(1, _)).Times(1);
313
314 auto result =
315 registrar.PopulateTexture(texture_id, 640, 480, &flutter_texture);
317 EXPECT_EQ(flutter_texture.width, width);
318 EXPECT_EQ(flutter_texture.height, height);
319 EXPECT_EQ(flutter_texture.target, GL_TEXTURE_2D);
320 EXPECT_TRUE(release_callback_called);
321}
322
323TEST(FlutterWindowsTextureRegistrarTest, PopulateInvalidTexture) {
324 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
325 auto gl = std::make_shared<egl::MockProcTable>();
326
327 FlutterWindowsTextureRegistrar registrar(engine.get(), gl);
328
329 auto result = registrar.PopulateTexture(1, 640, 480, nullptr);
330 EXPECT_FALSE(result);
331}
332
333TEST(FlutterWindowsTextureRegistrarTest,
334 UnregisterTextureWithEngineDownInvokesCallback) {
335 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
336 auto gl = std::make_shared<egl::MockProcTable>();
337
338 FlutterWindowsTextureRegistrar registrar(engine.get(), gl);
339
341 registrar.UnregisterTexture(1234, [&]() { latch.Signal(); });
342 latch.Wait();
343}
344
345} // namespace testing
346} // namespace flutter
FlutterEngineProcTable & embedder_api()
bool PopulateTexture(int64_t texture_id, size_t width, size_t height, FlutterOpenGLTexture *texture)
int64_t RegisterTexture(const FlutterDesktopTextureInfo *texture_info)
void UnregisterTexture(int64_t texture_id, fml::closure callback=nullptr)
@ kSuccess
Definition: embedder.h:73
FlutterEngine engine
Definition: main.cc:68
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
GAsyncResult * result
@ kFlutterDesktopGpuSurfaceTypeDxgiSharedHandle
@ kFlutterDesktopGpuSurfaceTypeD3d11Texture2D
FlutterDesktopTextureType
@ kFlutterDesktopGpuSurfaceTexture
@ kFlutterDesktopPixelBufferTexture
TEST(DisplayListComplexity, EmptyDisplayList)
gl
Definition: malisc.py:41
#define MOCK_ENGINE_PROC(proc, mock_impl)
int32_t height
int32_t width
void(* release_callback)(void *release_context)
FlutterDesktopGpuSurfaceTextureCallback callback
FlutterDesktopPixelBufferTextureCallback callback
void(* release_callback)(void *release_context)
FlutterDesktopGpuSurfaceTextureConfig gpu_surface_config
FlutterDesktopTextureType type
FlutterDesktopPixelBufferTextureConfig pixel_buffer_config
FlutterEngineRegisterExternalTextureFnPtr RegisterExternalTexture
Definition: embedder.h:3339
FlutterEngineUnregisterExternalTextureFnPtr UnregisterExternalTexture
Definition: embedder.h:3340
FlutterEngineMarkExternalTextureFrameAvailableFnPtr MarkExternalTextureFrameAvailable
Definition: embedder.h:3342
FlutterEnginePostRenderThreadTaskFnPtr PostRenderThreadTask
Definition: embedder.h:3351
size_t height
Height of the texture.
Definition: embedder.h:386
void * user_data
int64_t texture_id
#define EXPECT_TRUE(handle)
Definition: unit_test.h:678
#define SUCCEEDED(hr)
unsigned int UINT
Definition: windows_types.h:32
void * HANDLE
Definition: windows_types.h:36