| // 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 "impeller/toolkit/egl/display.h" |
| |
| #include <vector> |
| |
| #include "impeller/toolkit/egl/context.h" |
| #include "impeller/toolkit/egl/surface.h" |
| |
| namespace impeller { |
| namespace egl { |
| |
| Display::Display() { |
| EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); |
| |
| if (::eglInitialize(display, nullptr, nullptr) != EGL_TRUE) { |
| IMPELLER_LOG_EGL_ERROR; |
| return; |
| } |
| display_ = display; |
| } |
| |
| Display::~Display() { |
| if (display_ != EGL_NO_DISPLAY) { |
| if (::eglTerminate(display_) != EGL_TRUE) { |
| IMPELLER_LOG_EGL_ERROR; |
| } |
| } |
| } |
| |
| bool Display::IsValid() const { |
| return display_ != EGL_NO_DISPLAY; |
| } |
| |
| std::unique_ptr<Context> Display::CreateContext(const Config& config, |
| const Context* share_context) { |
| const auto& desc = config.GetDescriptor(); |
| |
| std::vector<EGLint> attributes; |
| switch (desc.api) { |
| case API::kOpenGL: |
| break; |
| case API::kOpenGLES2: |
| attributes.push_back(EGL_CONTEXT_CLIENT_VERSION); |
| attributes.push_back(2); |
| break; |
| case API::kOpenGLES3: |
| attributes.push_back(EGL_CONTEXT_CLIENT_VERSION); |
| attributes.push_back(3); |
| break; |
| } |
| // Termination sentinel must be present. |
| attributes.push_back(EGL_NONE); |
| |
| auto context = ::eglCreateContext( |
| display_, // display |
| config.GetHandle(), // config |
| share_context != nullptr ? share_context->GetHandle() : nullptr, // share |
| attributes.data() // attributes |
| ); |
| |
| if (context == EGL_NO_CONTEXT) { |
| IMPELLER_LOG_EGL_ERROR; |
| return nullptr; |
| } |
| |
| return std::make_unique<Context>(display_, context); |
| } |
| |
| std::unique_ptr<Config> Display::ChooseConfig(ConfigDescriptor config) const { |
| if (!display_) { |
| return nullptr; |
| } |
| |
| std::vector<EGLint> attributes; |
| |
| { |
| attributes.push_back(EGL_RENDERABLE_TYPE); |
| switch (config.api) { |
| case API::kOpenGL: |
| attributes.push_back(EGL_OPENGL_BIT); |
| break; |
| case API::kOpenGLES2: |
| attributes.push_back(EGL_OPENGL_ES2_BIT); |
| break; |
| case API::kOpenGLES3: |
| attributes.push_back(EGL_OPENGL_ES3_BIT); |
| break; |
| } |
| } |
| |
| { |
| attributes.push_back(EGL_SURFACE_TYPE); |
| switch (config.surface_type) { |
| case SurfaceType::kWindow: |
| attributes.push_back(EGL_WINDOW_BIT); |
| break; |
| case SurfaceType::kPBuffer: |
| attributes.push_back(EGL_PBUFFER_BIT); |
| break; |
| } |
| } |
| |
| { |
| switch (config.color_format) { |
| case ColorFormat::kRGBA8888: |
| attributes.push_back(EGL_RED_SIZE); |
| attributes.push_back(8); |
| attributes.push_back(EGL_GREEN_SIZE); |
| attributes.push_back(8); |
| attributes.push_back(EGL_BLUE_SIZE); |
| attributes.push_back(8); |
| attributes.push_back(EGL_ALPHA_SIZE); |
| attributes.push_back(8); |
| break; |
| case ColorFormat::kRGB565: |
| attributes.push_back(EGL_RED_SIZE); |
| attributes.push_back(5); |
| attributes.push_back(EGL_GREEN_SIZE); |
| attributes.push_back(6); |
| attributes.push_back(EGL_BLUE_SIZE); |
| attributes.push_back(5); |
| break; |
| } |
| } |
| |
| { |
| attributes.push_back(EGL_DEPTH_SIZE); |
| attributes.push_back(static_cast<EGLint>(config.depth_bits)); |
| } |
| |
| { |
| attributes.push_back(EGL_STENCIL_SIZE); |
| attributes.push_back(static_cast<EGLint>(config.stencil_bits)); |
| } |
| |
| { |
| const auto sample_count = static_cast<EGLint>(config.samples); |
| if (sample_count > 1) { |
| attributes.push_back(EGL_SAMPLE_BUFFERS); |
| attributes.push_back(1); |
| } |
| attributes.push_back(EGL_SAMPLES); |
| attributes.push_back(sample_count); |
| } |
| |
| // termination sentinel must be present. |
| attributes.push_back(EGL_NONE); |
| |
| EGLConfig config_out = nullptr; |
| EGLint config_count_out = 0; |
| if (::eglChooseConfig(display_, // display |
| attributes.data(), // attributes (null terminated) |
| &config_out, // matched configs |
| 1, // configs array size |
| &config_count_out // match configs count |
| ) != EGL_TRUE) { |
| IMPELLER_LOG_EGL_ERROR; |
| return nullptr; |
| } |
| |
| if (config_count_out != 1u) { |
| IMPELLER_LOG_EGL_ERROR; |
| return nullptr; |
| } |
| |
| return std::make_unique<Config>(std::move(config), config_out); |
| } |
| |
| std::unique_ptr<Surface> Display::CreateWindowSurface( |
| const Config& config, |
| EGLNativeWindowType window) { |
| const EGLint attribs[] = {EGL_NONE}; |
| auto surface = ::eglCreateWindowSurface(display_, // display |
| config.GetHandle(), // config |
| window, // window |
| attribs // attrib_list |
| ); |
| if (surface == EGL_NO_SURFACE) { |
| IMPELLER_LOG_EGL_ERROR; |
| return nullptr; |
| } |
| return std::make_unique<Surface>(display_, surface); |
| } |
| |
| std::unique_ptr<Surface> Display::CreatePixelBufferSurface(const Config& config, |
| size_t width, |
| size_t height) { |
| // clang-format off |
| const EGLint attribs[] = { |
| EGL_WIDTH, static_cast<EGLint>(width), |
| EGL_HEIGHT, static_cast<EGLint>(height), |
| EGL_NONE |
| }; |
| // clang-format on |
| auto surface = ::eglCreatePbufferSurface(display_, // display |
| config.GetHandle(), // config |
| attribs // attrib_list |
| ); |
| if (surface == EGL_NO_SURFACE) { |
| IMPELLER_LOG_EGL_ERROR; |
| return nullptr; |
| } |
| return std::make_unique<Surface>(display_, surface); |
| } |
| |
| } // namespace egl |
| } // namespace impeller |