Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
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
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";
30 FlutterProjectBundle project(properties);
31 auto engine = std::make_unique<FlutterWindowsEngine>(project);
32
33 EngineModifier modifier(engine.get());
34 modifier.embedder_api().RegisterExternalTexture =
35 MOCK_ENGINE_PROC(RegisterExternalTexture,
36 ([](auto engine, auto texture_id) { return kSuccess; }));
37
38 return engine;
39}
40
41// Creates a ID3D11Texture2D with the specified size.
42ComPtr<ID3D11Texture2D> CreateD3dTexture(FlutterWindowsEngine* engine,
43 UINT width,
44 UINT height) {
45 ComPtr<ID3D11Device> d3d_device;
46 ComPtr<ID3D11Texture2D> d3d_texture;
47 if (engine->egl_manager()->GetDevice(d3d_device.GetAddressOf())) {
48 D3D11_TEXTURE2D_DESC texture_description = {};
49 texture_description.MipLevels = 1;
50 texture_description.SampleDesc.Count = 1;
51 texture_description.BindFlags = D3D11_BIND_RENDER_TARGET;
52 texture_description.Usage = D3D11_USAGE_DEFAULT;
53 texture_description.CPUAccessFlags = 0;
54 texture_description.ArraySize = 1;
55 texture_description.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
56 texture_description.Height = width;
57 texture_description.Width = height;
58 texture_description.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
59
60 d3d_device->CreateTexture2D(&texture_description, nullptr,
61 d3d_texture.GetAddressOf());
62 }
63 return d3d_texture;
64}
65
66} // namespace
67
68TEST(FlutterWindowsTextureRegistrarTest, CreateDestroy) {
69 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
70 auto gl = std::make_shared<egl::MockProcTable>();
71 FlutterWindowsTextureRegistrar registrar(engine.get(), gl);
72
73 EXPECT_TRUE(true);
74}
75
76TEST(FlutterWindowsTextureRegistrarTest, RegisterUnregisterTexture) {
77 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
78 EngineModifier modifier(engine.get());
79 auto gl = std::make_shared<egl::MockProcTable>();
80
81 FlutterWindowsTextureRegistrar registrar(engine.get(), gl);
82
83 FlutterDesktopTextureInfo texture_info = {};
85 texture_info.pixel_buffer_config.callback =
86 [](size_t width, size_t height,
87 void* user_data) -> const FlutterDesktopPixelBuffer* {
88 return nullptr;
89 };
90
91 int64_t registered_texture_id = 0;
92 bool register_called = false;
94 RegisterExternalTexture, ([&register_called, &registered_texture_id](
95 auto engine, auto texture_id) {
96 register_called = true;
97 registered_texture_id = texture_id;
98 return kSuccess;
99 }));
100
101 bool unregister_called = false;
103 UnregisterExternalTexture, ([&unregister_called, &registered_texture_id](
104 auto engine, auto texture_id) {
105 unregister_called = true;
106 EXPECT_EQ(registered_texture_id, texture_id);
107 return kSuccess;
108 }));
109
110 bool mark_frame_available_called = false;
112 MOCK_ENGINE_PROC(MarkExternalTextureFrameAvailable,
113 ([&mark_frame_available_called, &registered_texture_id](
114 auto engine, auto texture_id) {
115 mark_frame_available_called = true;
116 EXPECT_EQ(registered_texture_id, texture_id);
117 return kSuccess;
118 }));
119
121 MOCK_ENGINE_PROC(PostRenderThreadTask,
122 [](auto engine, auto callback, void* callback_data) {
123 callback(callback_data);
124 return kSuccess;
125 });
126
127 auto texture_id = registrar.RegisterTexture(&texture_info);
128 EXPECT_TRUE(register_called);
129 EXPECT_NE(texture_id, -1);
130 EXPECT_EQ(texture_id, registered_texture_id);
131
132 EXPECT_TRUE(registrar.MarkTextureFrameAvailable(texture_id));
133 EXPECT_TRUE(mark_frame_available_called);
134
136 registrar.UnregisterTexture(texture_id, [&]() { latch.Signal(); });
137 latch.Wait();
138 ASSERT_TRUE(unregister_called);
139}
140
141TEST(FlutterWindowsTextureRegistrarTest, RegisterUnknownTextureType) {
142 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
143 auto gl = std::make_shared<egl::MockProcTable>();
144
145 FlutterWindowsTextureRegistrar registrar(engine.get(), gl);
146
147 FlutterDesktopTextureInfo texture_info = {};
148 texture_info.type = static_cast<FlutterDesktopTextureType>(1234);
149
150 auto texture_id = registrar.RegisterTexture(&texture_info);
151
152 EXPECT_EQ(texture_id, -1);
153}
154
155TEST(FlutterWindowsTextureRegistrarTest, PopulatePixelBufferTexture) {
156 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
157 auto gl = std::make_shared<egl::MockProcTable>();
158
159 FlutterWindowsTextureRegistrar registrar(engine.get(), gl);
160
161 bool release_callback_called = false;
162 size_t width = 100;
163 size_t height = 100;
164 std::unique_ptr<uint8_t[]> pixels =
165 std::make_unique<uint8_t[]>(width * height * 4);
166 FlutterDesktopPixelBuffer pixel_buffer = {};
167 pixel_buffer.width = width;
168 pixel_buffer.height = height;
169 pixel_buffer.buffer = pixels.get();
170 pixel_buffer.release_context = &release_callback_called;
171 pixel_buffer.release_callback = [](void* release_context) {
172 bool* called = reinterpret_cast<bool*>(release_context);
173 *called = true;
174 };
175
176 FlutterDesktopTextureInfo texture_info = {};
178 texture_info.pixel_buffer_config.user_data = &pixel_buffer;
179 texture_info.pixel_buffer_config.callback =
180 [](size_t width, size_t height,
181 void* user_data) -> const FlutterDesktopPixelBuffer* {
182 return reinterpret_cast<const FlutterDesktopPixelBuffer*>(user_data);
183 };
184
185 FlutterOpenGLTexture flutter_texture = {};
186 auto texture_id = registrar.RegisterTexture(&texture_info);
187 EXPECT_NE(texture_id, -1);
188
189 EXPECT_CALL(*gl.get(), GenTextures(1, _))
190 .Times(1)
191 .WillOnce([](GLsizei n, GLuint* textures) { textures[0] = 1; });
192 EXPECT_CALL(*gl.get(), BindTexture).Times(1);
193 EXPECT_CALL(*gl.get(), TexParameteri).Times(AtLeast(1));
194 EXPECT_CALL(*gl.get(), TexImage2D).Times(1);
195 EXPECT_CALL(*gl.get(), DeleteTextures(1, _)).Times(1);
196
197 auto result =
198 registrar.PopulateTexture(texture_id, 640, 480, &flutter_texture);
199 EXPECT_TRUE(result);
200 EXPECT_EQ(flutter_texture.width, width);
201 EXPECT_EQ(flutter_texture.height, height);
202 EXPECT_EQ(flutter_texture.target, GL_TEXTURE_2D);
203 EXPECT_TRUE(release_callback_called);
204}
205
206TEST(FlutterWindowsTextureRegistrarTest, PopulateD3dTextureWithHandle) {
207 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
208 auto gl = std::make_shared<egl::MockProcTable>();
209 FlutterWindowsTextureRegistrar registrar(engine.get(), gl);
210
211 UINT width = 100;
212 UINT height = 100;
213 auto d3d_texture = CreateD3dTexture(engine.get(), width, height);
214 EXPECT_TRUE(d3d_texture);
215
216 ComPtr<IDXGIResource> shared_resource;
217 EXPECT_TRUE(SUCCEEDED(d3d_texture.As(&shared_resource)));
218
219 HANDLE shared_handle;
220 EXPECT_TRUE(SUCCEEDED(shared_resource->GetSharedHandle(&shared_handle)));
221
222 bool release_callback_called = false;
223 FlutterDesktopGpuSurfaceDescriptor surface_descriptor = {};
224 surface_descriptor.struct_size = sizeof(FlutterDesktopGpuSurfaceDescriptor);
225 surface_descriptor.handle = shared_handle;
226 surface_descriptor.width = surface_descriptor.visible_width = width;
227 surface_descriptor.height = surface_descriptor.visible_height = height;
228 surface_descriptor.release_context = &release_callback_called;
229 surface_descriptor.release_callback = [](void* release_context) {
230 bool* called = reinterpret_cast<bool*>(release_context);
231 *called = true;
232 };
233
234 FlutterDesktopTextureInfo texture_info = {};
236 texture_info.gpu_surface_config.struct_size =
238 texture_info.gpu_surface_config.type =
240 texture_info.gpu_surface_config.user_data = &surface_descriptor;
241 texture_info.gpu_surface_config.callback =
242 [](size_t width, size_t height,
244 return reinterpret_cast<const FlutterDesktopGpuSurfaceDescriptor*>(
245 user_data);
246 };
247
248 FlutterOpenGLTexture flutter_texture = {};
249 auto texture_id = registrar.RegisterTexture(&texture_info);
250 EXPECT_NE(texture_id, -1);
251
252 EXPECT_CALL(*gl.get(), GenTextures(1, _))
253 .Times(1)
254 .WillOnce([](GLsizei n, GLuint* textures) { textures[0] = 1; });
255 EXPECT_CALL(*gl.get(), BindTexture).Times(1);
256 EXPECT_CALL(*gl.get(), TexParameteri).Times(AtLeast(1));
257 EXPECT_CALL(*gl.get(), DeleteTextures(1, _)).Times(1);
258
259 auto result =
260 registrar.PopulateTexture(texture_id, 640, 480, &flutter_texture);
261 EXPECT_TRUE(result);
262 EXPECT_EQ(flutter_texture.width, width);
263 EXPECT_EQ(flutter_texture.height, height);
264 EXPECT_EQ(flutter_texture.target, GL_TEXTURE_2D);
265 EXPECT_TRUE(release_callback_called);
266}
267
268TEST(FlutterWindowsTextureRegistrarTest, PopulateD3dTexture) {
269 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
270 auto gl = std::make_shared<egl::MockProcTable>();
271 FlutterWindowsTextureRegistrar registrar(engine.get(), gl);
272
273 UINT width = 100;
274 UINT height = 100;
275 auto d3d_texture = CreateD3dTexture(engine.get(), width, height);
276 EXPECT_TRUE(d3d_texture);
277
278 bool release_callback_called = false;
279 FlutterDesktopGpuSurfaceDescriptor surface_descriptor = {};
280 surface_descriptor.struct_size = sizeof(FlutterDesktopGpuSurfaceDescriptor);
281 surface_descriptor.handle = d3d_texture.Get();
282 surface_descriptor.width = surface_descriptor.visible_width = width;
283 surface_descriptor.height = surface_descriptor.visible_height = height;
284 surface_descriptor.release_context = &release_callback_called;
285 surface_descriptor.release_callback = [](void* release_context) {
286 bool* called = reinterpret_cast<bool*>(release_context);
287 *called = true;
288 };
289
290 FlutterDesktopTextureInfo texture_info = {};
292 texture_info.gpu_surface_config.struct_size =
294 texture_info.gpu_surface_config.type =
296 texture_info.gpu_surface_config.user_data = &surface_descriptor;
297 texture_info.gpu_surface_config.callback =
298 [](size_t width, size_t height,
300 return reinterpret_cast<const FlutterDesktopGpuSurfaceDescriptor*>(
301 user_data);
302 };
303
304 FlutterOpenGLTexture flutter_texture = {};
305 auto texture_id = registrar.RegisterTexture(&texture_info);
306 EXPECT_NE(texture_id, -1);
307
308 EXPECT_CALL(*gl.get(), GenTextures(1, _))
309 .Times(1)
310 .WillOnce([](GLsizei n, GLuint* textures) { textures[0] = 1; });
311 EXPECT_CALL(*gl.get(), BindTexture).Times(1);
312 EXPECT_CALL(*gl.get(), TexParameteri).Times(AtLeast(1));
313 EXPECT_CALL(*gl.get(), DeleteTextures(1, _)).Times(1);
314
315 auto result =
316 registrar.PopulateTexture(texture_id, 640, 480, &flutter_texture);
317 EXPECT_TRUE(result);
318 EXPECT_EQ(flutter_texture.width, width);
319 EXPECT_EQ(flutter_texture.height, height);
320 EXPECT_EQ(flutter_texture.target, GL_TEXTURE_2D);
321 EXPECT_TRUE(release_callback_called);
322}
323
324TEST(FlutterWindowsTextureRegistrarTest, PopulateInvalidTexture) {
325 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
326 auto gl = std::make_shared<egl::MockProcTable>();
327
328 FlutterWindowsTextureRegistrar registrar(engine.get(), gl);
329
330 auto result = registrar.PopulateTexture(1, 640, 480, nullptr);
331 EXPECT_FALSE(result);
332}
333
334TEST(FlutterWindowsTextureRegistrarTest,
335 UnregisterTextureWithEngineDownInvokesCallback) {
336 std::unique_ptr<FlutterWindowsEngine> engine = GetTestEngine();
337 auto gl = std::make_shared<egl::MockProcTable>();
338
339 FlutterWindowsTextureRegistrar registrar(engine.get(), gl);
340
342 registrar.UnregisterTexture(1234, [&]() { latch.Signal(); });
343 latch.Wait();
344}
345
346} // namespace testing
347} // 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)
FlutterEngine engine
Definition main.cc:84
@ kFlutterDesktopGpuSurfaceTypeDxgiSharedHandle
@ kFlutterDesktopGpuSurfaceTypeD3d11Texture2D
@ kFlutterDesktopGpuSurfaceTexture
@ kFlutterDesktopPixelBufferTexture
@ DefaultImpeller
FlutterDesktopBinaryReply callback
TEST(NativeAssetsManagerTest, NoAvailableAssets)
#define MOCK_ENGINE_PROC(proc, mock_impl)
int32_t height
int32_t width
FlutterDesktopImpellerSwitch impeller_switch
void(* release_callback)(void *release_context)
FlutterDesktopGpuSurfaceTextureCallback callback
void(* release_callback)(void *release_context)
FlutterDesktopPixelBufferTextureCallback callback
FlutterDesktopGpuSurfaceTextureConfig gpu_surface_config
FlutterDesktopPixelBufferTextureConfig pixel_buffer_config
FlutterEngineRegisterExternalTextureFnPtr RegisterExternalTexture
Definition embedder.h:3783
FlutterEngineUnregisterExternalTextureFnPtr UnregisterExternalTexture
Definition embedder.h:3784
FlutterEngineMarkExternalTextureFrameAvailableFnPtr MarkExternalTextureFrameAvailable
Definition embedder.h:3786
FlutterEnginePostRenderThreadTaskFnPtr PostRenderThreadTask
Definition embedder.h:3795
size_t height
Height of the texture.
Definition embedder.h:536
int64_t texture_id
#define SUCCEEDED(hr)
unsigned int UINT
void * HANDLE