66
77#include < EGL/eglext.h>
88
9+ #include < list>
910#include < utility>
1011
1112#include " android_environment_gl.h"
@@ -106,11 +107,120 @@ static bool TeardownContext(EGLDisplay display, EGLContext context) {
106107 return true ;
107108}
108109
110+ class AndroidEGLSurfaceDamage {
111+ public:
112+ void init (EGLDisplay display, EGLContext context) {
113+ const char * extensions = eglQueryString (display, EGL_EXTENSIONS);
114+
115+ if (HasExtension (extensions, " EGL_KHR_partial_update" )) {
116+ set_damage_region = reinterpret_cast <PFNEGLSETDAMAGEREGIONKHRPROC>(
117+ eglGetProcAddress (" eglSetDamageRegionKHR" ));
118+ }
119+
120+ if (HasExtension (extensions, " EGL_EXT_swap_buffers_with_damage" )) {
121+ swap_buffers_with_damage =
122+ reinterpret_cast <PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC>(
123+ eglGetProcAddress (" eglSwapBuffersWithDamageEXT" ));
124+ } else if (HasExtension (extensions, " EGL_KHR_swap_buffers_with_damage" )) {
125+ swap_buffers_with_damage =
126+ reinterpret_cast <PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC>(
127+ eglGetProcAddress (" eglSwapBuffersWithDamageKHR" ));
128+ }
129+
130+ _partial_redraw_supported =
131+ set_damage_region != nullptr && swap_buffers_with_damage != nullptr ;
132+ }
133+
134+ void SetDamageRegion (EGLDisplay display,
135+ EGLSurface surface,
136+ const std::optional<SkIRect>& region) {
137+ if (set_damage_region && region) {
138+ auto rects = RectToInts (display, surface, *region);
139+ set_damage_region (display, surface, rects.data (), 1 );
140+ }
141+ }
142+
143+ std::optional<SkIRect> InitialDamage (EGLDisplay display, EGLSurface surface) {
144+ if (!_partial_redraw_supported) {
145+ return std::nullopt ;
146+ }
147+
148+ EGLint age;
149+ eglQuerySurface (display, surface, EGL_BUFFER_AGE_EXT, &age);
150+
151+ if (age == 0 ) { // full repaint
152+ return std::nullopt ;
153+ } else if (age == 1 ) {
154+ // no initial damage
155+ return SkIRect::MakeEmpty ();
156+ } else {
157+ age -= 2 ;
158+ SkIRect res;
159+ for (auto i = damage_history_.begin ();
160+ i != damage_history_.end () && age >= 0 ; ++i, --age) {
161+ res.join (*i);
162+ }
163+ return res;
164+ }
165+ }
166+
167+ bool SwapBuffersWithDamage (EGLDisplay display,
168+ EGLSurface surface,
169+ const std::optional<SkIRect>& damage) {
170+ if (swap_buffers_with_damage && damage) {
171+ damage_history_.push_back (*damage);
172+ if (damage_history_.size () > 2 ) {
173+ damage_history_.pop_front ();
174+ }
175+ auto rects = RectToInts (display, surface, *damage);
176+ return swap_buffers_with_damage (display, surface, rects.data (), 1 );
177+
178+ } else {
179+ return eglSwapBuffers (display, surface);
180+ }
181+ }
182+
183+ private:
184+ std::vector<EGLint> RectToInts (EGLDisplay display,
185+ EGLSurface surface,
186+ const SkIRect& rect) {
187+ std::vector<EGLint> res;
188+ EGLint height;
189+ eglQuerySurface (display, surface, EGL_HEIGHT, &height);
190+
191+ res.push_back (rect.left ());
192+ res.push_back (height - rect.bottom ());
193+ res.push_back (rect.width ());
194+ res.push_back (rect.height ());
195+
196+ return res;
197+ }
198+
199+ PFNEGLSETDAMAGEREGIONKHRPROC set_damage_region = nullptr ;
200+ PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage = nullptr ;
201+
202+ bool _partial_redraw_supported;
203+
204+ bool HasExtension (const char * extensions, const char * name) {
205+ const char * r = strstr (extensions, name);
206+ auto len = strlen (name);
207+ // check that the extension name is terminated by space or null terminator
208+ return r != nullptr && (r[len] == ' ' || r[len] == 0 );
209+ }
210+
211+ std::list<SkIRect> damage_history_;
212+ };
213+
109214AndroidEGLSurface::AndroidEGLSurface (
110215 EGLSurface surface,
111216 fml::RefPtr<AndroidEnvironmentGL> environment,
112217 EGLContext context)
113- : surface_(surface), environment_(environment), context_(context) {}
218+ : surface_(surface),
219+ environment_ (environment),
220+ context_(context),
221+ damage_(std::make_unique<AndroidEGLSurfaceDamage>()) {
222+ damage_->init (environment->Display (), context);
223+ }
114224
115225AndroidEGLSurface::~AndroidEGLSurface () {
116226 auto result = eglDestroySurface (environment_->Display (), surface_);
@@ -131,10 +241,22 @@ bool AndroidEGLSurface::MakeCurrent() const {
131241 return true ;
132242}
133243
134- bool AndroidEGLSurface::SwapBuffers (fml::TimePoint target_time) {
244+ void AndroidEGLSurface::SetDamageRegion (
245+ const std::optional<SkIRect>& buffer_damage) {
246+ damage_->SetDamageRegion (environment_->Display (), surface_, buffer_damage);
247+ }
248+
249+ bool AndroidEGLSurface::SwapBuffers (
250+ fml::TimePoint target_time,
251+ const std::optional<SkIRect>& surface_damage) {
135252 TRACE_EVENT0 (" flutter" , " AndroidContextGL::SwapBuffers" );
136253 environment_->SetPresentationTime (surface_, target_time);
137- return eglSwapBuffers (environment_->Display (), surface_);
254+ return damage_->SwapBuffersWithDamage (environment_->Display (), surface_,
255+ surface_damage);
256+ }
257+
258+ std::optional<SkIRect> AndroidEGLSurface::InitialDamage () {
259+ return damage_->InitialDamage (environment_->Display (), surface_);
138260}
139261
140262SkISize AndroidEGLSurface::GetSize () const {
0 commit comments