Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions shell/common/shell_test_platform_view_gl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,7 @@ bool ShellTestPlatformViewGL::GLContextClearCurrent() {
}

// |GPUSurfaceGLDelegate|
bool ShellTestPlatformViewGL::GLContextPresent(
uint32_t fbo_id,
const std::optional<SkIRect>& damage) {
bool ShellTestPlatformViewGL::GLContextPresent(uint32_t fbo_id) {
return gl_surface_.Present();
}

Expand Down
3 changes: 1 addition & 2 deletions shell/common/shell_test_platform_view_gl.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@ class ShellTestPlatformViewGL : public ShellTestPlatformView,
bool GLContextClearCurrent() override;

// |GPUSurfaceGLDelegate|
bool GLContextPresent(uint32_t fbo_id,
const std::optional<SkIRect>& damage) override;
bool GLContextPresent(uint32_t fbo_id) override;

// |GPUSurfaceGLDelegate|
intptr_t GLContextFBO(GLFrameInfo frame_info) const override;
Expand Down
8 changes: 3 additions & 5 deletions shell/gpu/gpu_surface_gl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceGL::AcquireFrame(const SkISize& size) {
SurfaceFrame::SubmitCallback submit_callback =
[weak = weak_factory_.GetWeakPtr()](const SurfaceFrame& surface_frame,
SkCanvas* canvas) {
return weak ? weak->PresentSurface(surface_frame, canvas) : false;
return weak ? weak->PresentSurface(canvas) : false;
};

framebuffer_info = delegate_->GLContextFramebufferInfo();
Expand All @@ -251,19 +251,17 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceGL::AcquireFrame(const SkISize& size) {
std::move(context_switch));
}

bool GPUSurfaceGL::PresentSurface(const SurfaceFrame& frame, SkCanvas* canvas) {
bool GPUSurfaceGL::PresentSurface(SkCanvas* canvas) {
if (delegate_ == nullptr || canvas == nullptr || context_ == nullptr) {
return false;
}

delegate_->GLContextSetDamageRegion(frame.submit_info().buffer_damage);

{
TRACE_EVENT0("flutter", "SkCanvas::Flush");
onscreen_surface_->getCanvas()->flush();
}

if (!delegate_->GLContextPresent(fbo_id_, frame.submit_info().frame_damage)) {
if (!delegate_->GLContextPresent(fbo_id_)) {
return false;
}

Expand Down
2 changes: 1 addition & 1 deletion shell/gpu/gpu_surface_gl.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class GPUSurfaceGL : public Surface {
const SkISize& untransformed_size,
const SkMatrix& root_surface_transformation);

bool PresentSurface(const SurfaceFrame& frame, SkCanvas* canvas);
bool PresentSurface(SkCanvas* canvas);

GPUSurfaceGLDelegate* delegate_;
sk_sp<GrDirectContext> context_;
Expand Down
12 changes: 1 addition & 11 deletions shell/gpu/gpu_surface_gl_delegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
#ifndef FLUTTER_SHELL_GPU_GPU_SURFACE_GL_DELEGATE_H_
#define FLUTTER_SHELL_GPU_GPU_SURFACE_GL_DELEGATE_H_

#include <optional>

#include "flutter/common/graphics/gl_context_switch.h"
#include "flutter/flow/embedded_views.h"
#include "flutter/fml/macros.h"
Expand All @@ -33,17 +31,9 @@ class GPUSurfaceGLDelegate {
// either the GPU or IO threads.
virtual bool GLContextClearCurrent() = 0;

// Inform the GL Context that there's going to be no writing beyond
// the specified region
virtual void GLContextSetDamageRegion(const std::optional<SkIRect>& region) {}

// Called to present the main GL surface. This is only called for the main GL
// context and not any of the contexts dedicated for IO.
//
// Damage is a hint to compositor telling it which parts of front buffer
// need to be updated
virtual bool GLContextPresent(uint32_t fbo_id,
const std::optional<SkIRect>& damage) = 0;
virtual bool GLContextPresent(uint32_t fbo_id) = 0;

// The ID of the main window bound framebuffer. Typically FBO0.
virtual intptr_t GLContextFBO(GLFrameInfo frame_info) const = 0;
Expand Down
149 changes: 3 additions & 146 deletions shell/platform/android/android_context_gl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,8 @@

#include <EGL/eglext.h>

#include <list>
#include <utility>

// required to get API level
#include <sys/system_properties.h>

#include "flutter/fml/trace_event.h"

namespace flutter {
Expand Down Expand Up @@ -109,135 +105,10 @@ static bool TeardownContext(EGLDisplay display, EGLContext context) {
return true;
}

class AndroidEGLSurfaceDamage {
public:
void init(EGLDisplay display, EGLContext context) {
if (GetAPILevel() < 28) {
// Disable partial repaint for devices older than Android 9. There
// are old devices that have extensions below available but the
// implementation causes glitches (i.e. Xperia Z3 with Android 6).
partial_redraw_supported_ = false;
return;
}

const char* extensions = eglQueryString(display, EGL_EXTENSIONS);

if (HasExtension(extensions, "EGL_KHR_partial_update")) {
set_damage_region_ = reinterpret_cast<PFNEGLSETDAMAGEREGIONKHRPROC>(
eglGetProcAddress("eglSetDamageRegionKHR"));
}

if (HasExtension(extensions, "EGL_EXT_swap_buffers_with_damage")) {
swap_buffers_with_damage_ =
reinterpret_cast<PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC>(
eglGetProcAddress("eglSwapBuffersWithDamageEXT"));
} else if (HasExtension(extensions, "EGL_KHR_swap_buffers_with_damage")) {
swap_buffers_with_damage_ =
reinterpret_cast<PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC>(
eglGetProcAddress("eglSwapBuffersWithDamageKHR"));
}

partial_redraw_supported_ =
set_damage_region_ != nullptr && swap_buffers_with_damage_ != nullptr;
}

static int GetAPILevel() {
char sdk_version_string[PROP_VALUE_MAX];
if (__system_property_get("ro.build.version.sdk", sdk_version_string)) {
return atoi(sdk_version_string);
} else {
return -1;
}
}

void SetDamageRegion(EGLDisplay display,
EGLSurface surface,
const std::optional<SkIRect>& region) {
if (set_damage_region_ && region) {
auto rects = RectToInts(display, surface, *region);
set_damage_region_(display, surface, rects.data(), 1);
}
}

// Maximum damage history - for triple buffering we need to store damage for
// last two frames; Some Android devices (Pixel 4) use quad buffering.
static const int kMaxHistorySize = 10;

bool SupportsPartialRepaint() const { return partial_redraw_supported_; }

std::optional<SkIRect> InitialDamage(EGLDisplay display, EGLSurface surface) {
if (!partial_redraw_supported_) {
return std::nullopt;
}

EGLint age;
eglQuerySurface(display, surface, EGL_BUFFER_AGE_EXT, &age);

if (age == 0) { // full repaint
return std::nullopt;
} else {
// join up to (age - 1) last rects from damage history
--age;
auto res = SkIRect::MakeEmpty();
for (auto i = damage_history_.rbegin();
i != damage_history_.rend() && age > 0; ++i, --age) {
res.join(*i);
}
return res;
}
}

bool SwapBuffersWithDamage(EGLDisplay display,
EGLSurface surface,
const std::optional<SkIRect>& damage) {
if (swap_buffers_with_damage_ && damage) {
damage_history_.push_back(*damage);
if (damage_history_.size() > kMaxHistorySize) {
damage_history_.pop_front();
}
auto rects = RectToInts(display, surface, *damage);
return swap_buffers_with_damage_(display, surface, rects.data(), 1);
} else {
return eglSwapBuffers(display, surface);
}
}

private:
std::array<EGLint, 4> static RectToInts(EGLDisplay display,
EGLSurface surface,
const SkIRect& rect) {
EGLint height;
eglQuerySurface(display, surface, EGL_HEIGHT, &height);

std::array<EGLint, 4> res{rect.left(), height - rect.bottom(), rect.width(),
rect.height()};
return res;
}

PFNEGLSETDAMAGEREGIONKHRPROC set_damage_region_ = nullptr;
PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage_ = nullptr;

bool partial_redraw_supported_;

bool HasExtension(const char* extensions, const char* name) {
const char* r = strstr(extensions, name);
auto len = strlen(name);
// check that the extension name is terminated by space or null terminator
return r != nullptr && (r[len] == ' ' || r[len] == 0);
}

std::list<SkIRect> damage_history_;
};

AndroidEGLSurface::AndroidEGLSurface(EGLSurface surface,
EGLDisplay display,
EGLContext context)
: surface_(surface),
display_(display),
context_(context),
damage_(std::make_unique<AndroidEGLSurfaceDamage>()) {
damage_->init(display_, context);
}
: surface_(surface), display_(display), context_(context) {}

AndroidEGLSurface::~AndroidEGLSurface() {
[[maybe_unused]] auto result = eglDestroySurface(display_, surface_);
Expand All @@ -257,23 +128,9 @@ bool AndroidEGLSurface::MakeCurrent() const {
return true;
}

void AndroidEGLSurface::SetDamageRegion(
const std::optional<SkIRect>& buffer_damage) {
damage_->SetDamageRegion(display_, surface_, buffer_damage);
}

bool AndroidEGLSurface::SwapBuffers(
const std::optional<SkIRect>& surface_damage) {
bool AndroidEGLSurface::SwapBuffers() {
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_);
return eglSwapBuffers(display_, surface_);
}

SkISize AndroidEGLSurface::GetSize() const {
Expand Down
27 changes: 1 addition & 26 deletions shell/platform/android/android_context_gl.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ namespace flutter {
/// This can be used in conjunction to unique_ptr to provide better guarantees
/// about the lifespan of the `EGLSurface` object.
///
class AndroidEGLSurfaceDamage;

class AndroidEGLSurface {
public:
AndroidEGLSurface(EGLSurface surface, EGLDisplay display, EGLContext context);
Expand All @@ -45,35 +43,13 @@ class AndroidEGLSurface {
///
bool MakeCurrent() const;

//----------------------------------------------------------------------------
///
/// @return Whether target surface supports partial repaint.
///
bool SupportsPartialRepaint() const;

//----------------------------------------------------------------------------
/// @brief This is the minimal area that needs to be repainted to get
/// correct result.
///
/// With double or triple buffering this buffer content may lag behind
/// current front buffer and the rect accounts for accumulated damage.
///
/// @return The area of current surface where it is behind front buffer.
///
std::optional<SkIRect> InitialDamage();

//----------------------------------------------------------------------------
/// @brief Sets the damage region for current surface. Corresponds to
// eglSetDamageRegionKHR
void SetDamageRegion(const std::optional<SkIRect>& buffer_damage);

//----------------------------------------------------------------------------
/// @brief This only applies to on-screen surfaces such as those created
/// by `AndroidContextGL::CreateOnscreenSurface`.
///
/// @return Whether the EGL surface color buffer was swapped.
///
bool SwapBuffers(const std::optional<SkIRect>& surface_damage);
bool SwapBuffers();

//----------------------------------------------------------------------------
/// @return The size of an `EGLSurface`.
Expand All @@ -84,7 +60,6 @@ class AndroidEGLSurface {
const EGLSurface surface_;
const EGLDisplay display_;
const EGLContext context_;
std::unique_ptr<AndroidEGLSurfaceDamage> damage_;
};

//------------------------------------------------------------------------------
Expand Down
21 changes: 2 additions & 19 deletions shell/platform/android/android_surface_gl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -126,27 +126,10 @@ bool AndroidSurfaceGL::GLContextClearCurrent() {
return GLContextPtr()->ClearCurrent();
}

SurfaceFrame::FramebufferInfo AndroidSurfaceGL::GLContextFramebufferInfo()
const {
FML_DCHECK(IsValid());
SurfaceFrame::FramebufferInfo res;
res.supports_readback = true;
res.supports_partial_repaint = onscreen_surface_->SupportsPartialRepaint();
res.existing_damage = onscreen_surface_->InitialDamage();
return res;
}

void AndroidSurfaceGL::GLContextSetDamageRegion(
const std::optional<SkIRect>& region) {
FML_DCHECK(IsValid());
onscreen_surface_->SetDamageRegion(region);
}

bool AndroidSurfaceGL::GLContextPresent(uint32_t fbo_id,
const std::optional<SkIRect>& damage) {
bool AndroidSurfaceGL::GLContextPresent(uint32_t fbo_id) {
FML_DCHECK(IsValid());
FML_DCHECK(onscreen_surface_);
return onscreen_surface_->SwapBuffers(damage);
return onscreen_surface_->SwapBuffers();
}

intptr_t AndroidSurfaceGL::GLContextFBO(GLFrameInfo frame_info) const {
Expand Down
9 changes: 1 addition & 8 deletions shell/platform/android/android_surface_gl.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,7 @@ class AndroidSurfaceGL final : public GPUSurfaceGLDelegate,
bool GLContextClearCurrent() override;

// |GPUSurfaceGLDelegate|
SurfaceFrame::FramebufferInfo GLContextFramebufferInfo() const override;

// |GPUSurfaceGLDelegate|
void GLContextSetDamageRegion(const std::optional<SkIRect>& region) override;

// |GPUSurfaceGLDelegate|
bool GLContextPresent(uint32_t fbo_id,
const std::optional<SkIRect>& damage) override;
bool GLContextPresent(uint32_t fbo_id) override;

// |GPUSurfaceGLDelegate|
intptr_t GLContextFBO(GLFrameInfo frame_info) const override;
Expand Down
4 changes: 1 addition & 3 deletions shell/platform/android/surface/android_surface_mock.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ bool AndroidSurfaceMock::GLContextClearCurrent() {
return true;
}

bool AndroidSurfaceMock::GLContextPresent(
uint32_t fbo_id,
const std::optional<SkIRect>& damage) {
bool AndroidSurfaceMock::GLContextPresent(uint32_t fbo_id) {
return true;
}

Expand Down
3 changes: 1 addition & 2 deletions shell/platform/android/surface/android_surface_mock.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,7 @@ class AndroidSurfaceMock final : public GPUSurfaceGLDelegate,
bool GLContextClearCurrent() override;

// |GPUSurfaceGLDelegate|
bool GLContextPresent(uint32_t fbo_id,
const std::optional<SkIRect>& damage) override;
bool GLContextPresent(uint32_t fbo_id) override;

// |GPUSurfaceGLDelegate|
intptr_t GLContextFBO(GLFrameInfo frame_info) const override;
Expand Down
2 changes: 1 addition & 1 deletion shell/platform/darwin/ios/ios_surface_gl.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class IOSSurfaceGL final : public IOSSurface, public GPUSurfaceGLDelegate {
bool GLContextClearCurrent() override;

// |GPUSurfaceGLDelegate|
bool GLContextPresent(uint32_t fbo_id, const std::optional<SkIRect>& damage) override;
bool GLContextPresent(uint32_t fbo_id) override;

// |GPUSurfaceGLDelegate|
intptr_t GLContextFBO(GLFrameInfo frame_info) const override;
Expand Down
Loading