// Copyright 2013 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "flutter/shell/platform/windows/angle_surface_manager.h" namespace flutter { AngleSurfaceManager::AngleSurfaceManager() : egl_config_(nullptr), egl_display_(EGL_NO_DISPLAY), egl_context_(EGL_NO_CONTEXT) { initialize_succeeded_ = Initialize(); } AngleSurfaceManager::~AngleSurfaceManager() { CleanUp(); } bool AngleSurfaceManager::Initialize() { const EGLint configAttributes[] = {EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_DEPTH_SIZE, 8, EGL_STENCIL_SIZE, 8, EGL_NONE}; const EGLint display_context_attributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; const EGLint default_display_attributes[] = { // These are prefered display attributes and request ANGLE's D3D11 // renderer. eglInitialize will only succeed with these attributes if the // hardware supports D3D11 Feature Level 10_0+. EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, // EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE is an option that will // enable ANGLE to automatically call the IDXGIDevice3::Trim method on // behalf of the application when it gets suspended. EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE, EGL_NONE, }; const EGLint fl9_3_display_attributes[] = { // These are used to request ANGLE's D3D11 renderer, with D3D11 Feature // Level 9_3. EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, 9, EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, 3, EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE, EGL_NONE, }; const EGLint warp_display_attributes[] = { // These attributes request D3D11 WARP (software rendering fallback) as a // last resort. EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE, EGL_TRUE, EGL_NONE, }; PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = reinterpret_cast( eglGetProcAddress("eglGetPlatformDisplayEXT")); if (!eglGetPlatformDisplayEXT) { OutputDebugString(L"EGL: Failed to get a compatible EGLdisplay"); return false; } // Try to initialize EGL to D3D11 Feature Level 10_0+. egl_display_ = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, default_display_attributes); if (egl_display_ == EGL_NO_DISPLAY) { OutputDebugString(L"EGL: Failed to get a compatible EGLdisplay"); return false; } if (eglInitialize(egl_display_, nullptr, nullptr) == EGL_FALSE) { // If above failed, try to initialize EGL to D3D11 Feature Level 9_3, if // 10_0+ is unavailable. egl_display_ = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, fl9_3_display_attributes); if (egl_display_ == EGL_NO_DISPLAY) { OutputDebugString(L"EGL: Failed to get a compatible EGLdisplay"); return false; } if (eglInitialize(egl_display_, nullptr, nullptr) == EGL_FALSE) { // If all else fails, attempt D3D11 Feature Level 11_0 on WARP as a last // resort egl_display_ = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, EGL_DEFAULT_DISPLAY, warp_display_attributes); if (egl_display_ == EGL_NO_DISPLAY) { OutputDebugString(L"EGL: Failed to get a compatible EGLdisplay"); return false; } if (eglInitialize(egl_display_, nullptr, nullptr) == EGL_FALSE) { OutputDebugString(L"EGL: Failed to initialize EGL"); return false; } } } EGLint numConfigs = 0; if ((eglChooseConfig(egl_display_, configAttributes, &egl_config_, 1, &numConfigs) == EGL_FALSE) || (numConfigs == 0)) { OutputDebugString(L"EGL: Failed to choose first context"); return false; } egl_context_ = eglCreateContext(egl_display_, egl_config_, EGL_NO_CONTEXT, display_context_attributes); if (egl_context_ == EGL_NO_CONTEXT) { OutputDebugString(L"EGL: Failed to create EGL context"); return false; } return true; } void AngleSurfaceManager::CleanUp() { if (egl_display_ != EGL_NO_DISPLAY && egl_context_ != EGL_NO_CONTEXT) { eglDestroyContext(egl_display_, egl_context_); egl_context_ = EGL_NO_CONTEXT; } if (egl_display_ != EGL_NO_DISPLAY) { eglTerminate(egl_display_); egl_display_ = EGL_NO_DISPLAY; } } EGLSurface AngleSurfaceManager::CreateSurface(HWND window) { if (!window || !initialize_succeeded_) { return EGL_NO_SURFACE; } EGLSurface surface = EGL_NO_SURFACE; const EGLint surfaceAttributes[] = {EGL_NONE}; surface = eglCreateWindowSurface(egl_display_, egl_config_, static_cast(window), surfaceAttributes); return surface; } void AngleSurfaceManager::GetSurfaceDimensions(const EGLSurface surface, EGLint* width, EGLint* height) { if (surface == EGL_NO_SURFACE || !initialize_succeeded_) { width = 0; height = 0; return; } eglQuerySurface(egl_display_, surface, EGL_WIDTH, width); eglQuerySurface(egl_display_, surface, EGL_HEIGHT, height); } void AngleSurfaceManager::DestroySurface(const EGLSurface surface) { if (egl_display_ != EGL_NO_DISPLAY && surface != EGL_NO_SURFACE) { eglDestroySurface(egl_display_, surface); } } bool AngleSurfaceManager::MakeCurrent(const EGLSurface surface) { return (eglMakeCurrent(egl_display_, surface, surface, egl_context_) == EGL_TRUE); } EGLBoolean AngleSurfaceManager::SwapBuffers(const EGLSurface surface) { return (eglSwapBuffers(egl_display_, surface)); } } // namespace flutter