blob: 2afb265c9f679866fbacdc8433659c92c3046242 [file] [log] [blame]
// 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