blob: d4f3fc648eead4cb781c4d72b307d43c5b14a39a [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 "flutter/shell/platform/android/android_egl_surface.h"
#include <EGL/eglext.h>
#include <sys/system_properties.h>
#include <array>
#include <list>
#include "flutter/fml/trace_event.h"
namespace flutter {
void LogLastEGLError() {
struct EGLNameErrorPair {
const char* name;
EGLint code;
};
#define _EGL_ERROR_DESC(a) \
{ #a, a }
const EGLNameErrorPair pairs[] = {
_EGL_ERROR_DESC(EGL_SUCCESS),
_EGL_ERROR_DESC(EGL_NOT_INITIALIZED),
_EGL_ERROR_DESC(EGL_BAD_ACCESS),
_EGL_ERROR_DESC(EGL_BAD_ALLOC),
_EGL_ERROR_DESC(EGL_BAD_ATTRIBUTE),
_EGL_ERROR_DESC(EGL_BAD_CONTEXT),
_EGL_ERROR_DESC(EGL_BAD_CONFIG),
_EGL_ERROR_DESC(EGL_BAD_CURRENT_SURFACE),
_EGL_ERROR_DESC(EGL_BAD_DISPLAY),
_EGL_ERROR_DESC(EGL_BAD_SURFACE),
_EGL_ERROR_DESC(EGL_BAD_MATCH),
_EGL_ERROR_DESC(EGL_BAD_PARAMETER),
_EGL_ERROR_DESC(EGL_BAD_NATIVE_PIXMAP),
_EGL_ERROR_DESC(EGL_BAD_NATIVE_WINDOW),
_EGL_ERROR_DESC(EGL_CONTEXT_LOST),
};
#undef _EGL_ERROR_DESC
const auto count = sizeof(pairs) / sizeof(EGLNameErrorPair);
EGLint last_error = eglGetError();
for (size_t i = 0; i < count; i++) {
if (last_error == pairs[i].code) {
FML_LOG(ERROR) << "EGL Error: " << pairs[i].name << " (" << pairs[i].code
<< ")";
return;
}
}
FML_LOG(ERROR) << "Unknown EGL Error";
}
class AndroidEGLSurfaceDamage {
public:
void init(EGLDisplay display, EGLContext context) {}
void SetDamageRegion(EGLDisplay display,
EGLSurface surface,
const std::optional<SkIRect>& region) {}
/// This was disabled after discussion in
/// https://github.com/flutter/flutter/issues/123353
bool SupportsPartialRepaint() const { return false; }
std::optional<SkIRect> InitialDamage(EGLDisplay display, EGLSurface surface) {
return std::nullopt;
}
bool SwapBuffersWithDamage(EGLDisplay display,
EGLSurface surface,
const std::optional<SkIRect>& damage) {
return eglSwapBuffers(display, surface);
}
};
AndroidEGLSurface::AndroidEGLSurface(EGLSurface surface,
EGLDisplay display,
EGLContext context)
: surface_(surface),
display_(display),
context_(context),
damage_(std::make_unique<AndroidEGLSurfaceDamage>()) {
damage_->init(display_, context);
}
AndroidEGLSurface::~AndroidEGLSurface() {
[[maybe_unused]] auto result = eglDestroySurface(display_, surface_);
FML_DCHECK(result == EGL_TRUE);
}
bool AndroidEGLSurface::IsValid() const {
return surface_ != EGL_NO_SURFACE;
}
bool AndroidEGLSurface::IsContextCurrent() const {
EGLContext current_egl_context = eglGetCurrentContext();
if (context_ != current_egl_context) {
return false;
}
EGLDisplay current_egl_display = eglGetCurrentDisplay();
if (display_ != current_egl_display) {
return false;
}
EGLSurface draw_surface = eglGetCurrentSurface(EGL_DRAW);
if (draw_surface != surface_) {
return false;
}
EGLSurface read_surface = eglGetCurrentSurface(EGL_READ);
if (read_surface != surface_) {
return false;
}
return true;
}
AndroidEGLSurfaceMakeCurrentStatus AndroidEGLSurface::MakeCurrent() const {
if (IsContextCurrent()) {
return AndroidEGLSurfaceMakeCurrentStatus::kSuccessAlreadyCurrent;
}
if (eglMakeCurrent(display_, surface_, surface_, context_) != EGL_TRUE) {
FML_LOG(ERROR) << "Could not make the context current";
LogLastEGLError();
return AndroidEGLSurfaceMakeCurrentStatus::kFailure;
}
return AndroidEGLSurfaceMakeCurrentStatus::kSuccessMadeCurrent;
}
void AndroidEGLSurface::SetDamageRegion(
const std::optional<SkIRect>& buffer_damage) {
damage_->SetDamageRegion(display_, surface_, buffer_damage);
}
bool AndroidEGLSurface::SetPresentationTime(
const fml::TimePoint& presentation_time) {
if (presentation_time_proc_) {
const auto time_ns = presentation_time.ToEpochDelta().ToNanoseconds();
return presentation_time_proc_(display_, surface_, time_ns);
} else {
return false;
}
}
bool AndroidEGLSurface::SwapBuffers(
const std::optional<SkIRect>& surface_damage) {
TRACE_EVENT0("flutter", "AndroidContextGL::SwapBuffers");
return damage_->SwapBuffersWithDamage(display_, surface_, surface_damage);
}
bool AndroidEGLSurface::SupportsPartialRepaint() const {
return damage_->SupportsPartialRepaint();
}
std::optional<SkIRect> AndroidEGLSurface::InitialDamage() {
return damage_->InitialDamage(display_, surface_);
}
SkISize AndroidEGLSurface::GetSize() const {
EGLint width = 0;
EGLint height = 0;
if (!eglQuerySurface(display_, surface_, EGL_WIDTH, &width) ||
!eglQuerySurface(display_, surface_, EGL_HEIGHT, &height)) {
FML_LOG(ERROR) << "Unable to query EGL surface size";
LogLastEGLError();
return SkISize::Make(0, 0);
}
return SkISize::Make(width, height);
}
} // namespace flutter