mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
[Fix] (Espryt): swap a pbuffer without damage rectangles
This commit is contained in:
@@ -18159,21 +18159,26 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
//
|
||||
// The damage is the client's, from the present record (CurrentPresentDamage): GL window
|
||||
// coordinates, which is what the native call takes. Whole surface = no rectangles.
|
||||
const EGLSurface drawSurface = ActiveNativeSession().Draw;
|
||||
//
|
||||
// ONLY A WINDOW SURFACE TAKES RECTANGLES: the platform's swap-with-damage hands them to the
|
||||
// surface's native window, and a pbuffer has none (Android's dereferences it regardless).
|
||||
NativeSessionState& session = ActiveNativeSession(); // before the lock: it takes it too
|
||||
const EGLSurface drawSurface = session.Draw;
|
||||
Bool windowSurface = false;
|
||||
if (drawSurface != EGL_NO_SURFACE) {
|
||||
const std::lock_guard<std::mutex> lock(g_nativeRegistryMutex);
|
||||
if (const auto* entry = FindSessionSurfaceLocked(session, drawSurface))
|
||||
windowSurface = entry->Window != static_cast<NativeWindowType>(0);
|
||||
}
|
||||
if (g_EGLFuncs.eglSwapBuffersWithDamageEXT != nullptr) {
|
||||
const MG_Util::Damage::Region& damage = MG_Backend::CurrentPresentDamage();
|
||||
EGLint rects[MG_Util::Damage::kMaxRects * 4] = {};
|
||||
EGLint count = 0;
|
||||
if (!damage.IsFull() && !damage.IsEmpty()) {
|
||||
count = static_cast<EGLint>(MG_Util::Damage::PackRects(damage, rects, MG_Util::Damage::kMaxRects));
|
||||
}
|
||||
const EGLint count = static_cast<EGLint>(MG_Util::Damage::NativeSwapRects(windowSurface, damage, rects));
|
||||
g_EGLFuncs.eglSwapBuffersWithDamageEXT(g_Display, drawSurface, count > 0 ? rects : nullptr, count);
|
||||
} else {
|
||||
g_EGLFuncs.eglSwapBuffers(g_Display, drawSurface);
|
||||
}
|
||||
if (drawSurface != EGL_NO_SURFACE) {
|
||||
// Resolved before the lock: ActiveNativeSession takes it too.
|
||||
NativeSessionState& session = ActiveNativeSession();
|
||||
const std::lock_guard<std::mutex> lock(g_nativeRegistryMutex);
|
||||
if (auto* entry = FindSessionSurfaceLocked(session, drawSurface)) ++entry->Presents;
|
||||
}
|
||||
|
||||
@@ -137,6 +137,21 @@ TEST(Damage, PackedRectsRoundTripThroughARecord) {
|
||||
EXPECT_EQ(Region::FromEglRects(out, 1), Of({{1, 2, 56, 66}}));
|
||||
}
|
||||
|
||||
// The native swap gets rectangles only for a window surface: Android's swap-with-damage on a
|
||||
// pbuffer (a client window's drawable) dereferences the native window it does not have.
|
||||
TEST(Damage, OnlyAWindowSurfaceSwapsWithRectangles) {
|
||||
Int32 out[kMaxRects * 4] = {};
|
||||
const Region partial = Of({{10, 20, 30, 40}});
|
||||
EXPECT_EQ(NativeSwapRects(false, partial, out), 0u) << "a pbuffer swaps plainly";
|
||||
EXPECT_EQ(NativeSwapRects(true, Region::Full(), out), 0u);
|
||||
EXPECT_EQ(NativeSwapRects(true, Region(), out), 0u) << "nothing damaged has no rectangle spelling";
|
||||
ASSERT_EQ(NativeSwapRects(true, partial, out), 1u);
|
||||
EXPECT_EQ(out[0], 10);
|
||||
EXPECT_EQ(out[1], 20);
|
||||
EXPECT_EQ(out[2], 30);
|
||||
EXPECT_EQ(out[3], 40);
|
||||
}
|
||||
|
||||
// Three shared images rotate; each write must bring over what that image missed.
|
||||
TEST(Damage, EachBufferCopiesTheDamageItMissedSinceItsLastWrite) {
|
||||
constexpr Int32 W = 200, H = 100;
|
||||
|
||||
@@ -266,6 +266,15 @@ namespace MobileGL::MG_Util::Damage {
|
||||
return static_cast<Uint32>(rects.size());
|
||||
}
|
||||
|
||||
// The rectangles a native swap-with-damage gets for `damage` (into `out`, room for kMaxRects),
|
||||
// and their count; 0 = a plain swap. Only a window surface takes any: the platform hands them to
|
||||
// the surface's native window, and a pbuffer has none (Android's EGL dereferences it anyway).
|
||||
// An empty damage has no spelling (no rectangles means the whole surface), so it swaps plainly.
|
||||
inline Uint32 NativeSwapRects(Bool windowSurface, const Region& damage, Int32* out) {
|
||||
if (!windowSurface || damage.IsFull() || damage.IsEmpty()) return 0;
|
||||
return PackRects(damage, out, kMaxRects);
|
||||
}
|
||||
|
||||
// Per buffer of a rotating set: the damage each has missed since it was last written.
|
||||
class BufferDamageTracker {
|
||||
public:
|
||||
|
||||
Reference in New Issue
Block a user