@@ -263,116 +263,78 @@ bool Manager::IsValid() const {
263
263
return is_valid_;
264
264
}
265
265
266
- bool Manager::CreateSurface (HWND hwnd, EGLint width, EGLint height) {
266
+ bool Manager::CreateWindowSurface (HWND hwnd, size_t width, size_t height) {
267
+ FML_DCHECK (surface_ == nullptr || !surface_->IsValid ());
268
+
267
269
if (!hwnd || !is_valid_) {
268
270
return false ;
269
271
}
270
272
271
- EGLSurface surface = EGL_NO_SURFACE;
272
-
273
273
// Disable ANGLE's automatic surface resizing and provide an explicit size.
274
274
// The surface will need to be destroyed and re-created if the HWND is
275
275
// resized.
276
- const EGLint surface_attributes[] = {
277
- EGL_FIXED_SIZE_ANGLE, EGL_TRUE, EGL_WIDTH, width,
278
- EGL_HEIGHT, height, EGL_NONE};
279
-
280
- surface = ::eglCreateWindowSurface (display_, config_,
281
- static_cast <EGLNativeWindowType>(hwnd),
282
- surface_attributes);
276
+ const EGLint surface_attributes[] = {EGL_FIXED_SIZE_ANGLE,
277
+ EGL_TRUE,
278
+ EGL_WIDTH,
279
+ static_cast <EGLint>(width),
280
+ EGL_HEIGHT,
281
+ static_cast <EGLint>(height),
282
+ EGL_NONE};
283
+
284
+ auto const surface = ::eglCreateWindowSurface (
285
+ display_, config_, static_cast <EGLNativeWindowType>(hwnd),
286
+ surface_attributes);
283
287
if (surface == EGL_NO_SURFACE) {
284
288
LogEGLError (" Surface creation failed." );
285
289
return false ;
286
290
}
287
291
288
- surface_width_ = width;
289
- surface_height_ = height;
290
- surface_ = surface;
292
+ surface_ = std::make_unique<WindowSurface>(
293
+ display_, render_context_->GetHandle (), surface, width, height);
291
294
return true ;
292
295
}
293
296
294
- void Manager::ResizeSurface (HWND hwnd,
295
- EGLint width,
296
- EGLint height,
297
- bool vsync_enabled) {
298
- EGLint existing_width, existing_height;
299
- GetSurfaceDimensions (&existing_width, &existing_height);
300
- if (width != existing_width || height != existing_height) {
301
- surface_width_ = width;
302
- surface_height_ = height;
297
+ void Manager::ResizeWindowSurface (HWND hwnd, size_t width, size_t height) {
298
+ FML_CHECK (surface_ != nullptr );
303
299
300
+ auto const existing_width = surface_->width ();
301
+ auto const existing_height = surface_->height ();
302
+ auto const existing_vsync = surface_->vsync_enabled ();
303
+
304
+ if (width != existing_width || height != existing_height) {
304
305
// TODO: Destroying the surface and re-creating it is expensive.
305
306
// Ideally this would use ANGLE's automatic surface sizing instead.
306
307
// See: https://github.com/flutter/flutter/issues/79427
307
- render_context_->ClearCurrent ();
308
- DestroySurface ();
309
- if (!CreateSurface (hwnd, width, height)) {
310
- FML_LOG (ERROR) << " Manager::ResizeSurface failed to create surface" ;
308
+ if (!surface_->Destroy ()) {
309
+ FML_LOG (ERROR) << " Manager::ResizeSurface failed to destroy surface" ;
310
+ return ;
311
311
}
312
- }
313
312
314
- SetVSyncEnabled (vsync_enabled);
315
- }
316
-
317
- void Manager::GetSurfaceDimensions (EGLint* width, EGLint* height) {
318
- if (surface_ == EGL_NO_SURFACE || !is_valid_) {
319
- *width = 0 ;
320
- *height = 0 ;
321
- return ;
322
- }
323
-
324
- // This avoids eglQuerySurface as ideally surfaces would be automatically
325
- // sized by ANGLE to avoid expensive surface destroy & re-create. With
326
- // automatic sizing, ANGLE could resize the surface before Flutter asks it to,
327
- // which would break resize redraw synchronization.
328
- *width = surface_width_;
329
- *height = surface_height_;
330
- }
313
+ if (!CreateWindowSurface (hwnd, width, height)) {
314
+ FML_LOG (ERROR) << " Manager::ResizeSurface failed to create surface" ;
315
+ return ;
316
+ }
331
317
332
- void Manager::DestroySurface () {
333
- if (display_ != EGL_NO_DISPLAY && surface_ != EGL_NO_SURFACE) {
334
- ::eglDestroySurface (display_, surface_);
318
+ if (!surface_->SetVSyncEnabled (existing_vsync)) {
319
+ // Surfaces block until the v-blank by default.
320
+ // Failing to update the vsync might result in unnecessary blocking.
321
+ // This regresses performance but not correctness.
322
+ FML_LOG (ERROR) << " Manager::ResizeSurface failed to set vsync" ;
323
+ }
335
324
}
336
- surface_ = EGL_NO_SURFACE;
337
325
}
338
326
339
327
bool Manager::HasContextCurrent () {
340
328
return ::eglGetCurrentContext () != EGL_NO_CONTEXT;
341
329
}
342
330
343
- bool Manager::MakeCurrent () {
344
- return (::eglMakeCurrent (display_, surface_, surface_,
345
- render_context_->GetHandle ()) == EGL_TRUE);
346
- }
347
-
348
- bool Manager::SwapBuffers () {
349
- return (::eglSwapBuffers (display_, surface_));
350
- }
351
-
352
331
EGLSurface Manager::CreateSurfaceFromHandle (EGLenum handle_type,
353
332
EGLClientBuffer handle,
354
333
const EGLint* attributes) const {
355
334
return ::eglCreatePbufferFromClientBuffer (display_, handle_type, handle,
356
335
config_, attributes);
357
336
}
358
337
359
- void Manager::SetVSyncEnabled (bool enabled) {
360
- if (!MakeCurrent ()) {
361
- LogEGLError (" Unable to make surface current to update the swap interval" );
362
- return ;
363
- }
364
-
365
- // OpenGL swap intervals can be used to prevent screen tearing.
366
- // If enabled, the raster thread blocks until the v-blank.
367
- // This is unnecessary if DWM composition is enabled.
368
- // See: https://www.khronos.org/opengl/wiki/Swap_Interval
369
- // See: https://learn.microsoft.com/windows/win32/dwm/composition-ovw
370
- if (::eglSwapInterval (display_, enabled ? 1 : 0 ) != EGL_TRUE) {
371
- LogEGLError (" Unable to update the swap interval" );
372
- return ;
373
- }
374
- }
375
-
376
338
bool Manager::GetDevice (ID3D11Device** device) {
377
339
if (!resolved_device_) {
378
340
if (!InitializeDevice ()) {
@@ -392,5 +354,9 @@ Context* Manager::resource_context() const {
392
354
return resource_context_.get ();
393
355
}
394
356
357
+ WindowSurface* Manager::surface () const {
358
+ return surface_.get ();
359
+ }
360
+
395
361
} // namespace egl
396
362
} // namespace flutter
0 commit comments