Add a global mutex to serialize PAGDecoder frame rendering across shared EGL contexts.#3565
Open
leiyue123 wants to merge 1 commit into
Open
Add a global mutex to serialize PAGDecoder frame rendering across shared EGL contexts.#3565leiyue123 wants to merge 1 commit into
leiyue123 wants to merge 1 commit into
Conversation
…red EGL contexts.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3565 +/- ##
=======================================
Coverage 81.32% 81.32%
=======================================
Files 653 653
Lines 77180 77181 +1
Branches 21913 21914 +1
=======================================
+ Hits 62763 62765 +2
+ Misses 9983 9980 -3
- Partials 4434 4436 +2 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
shlzxjp
reviewed
Jul 15, 2026
|
|
||
| namespace pag { | ||
|
|
||
| static std::mutex renderLocker = {}; |
Collaborator
There was a problem hiding this comment.
建议从根本上解决而非打补丁规避。真正的根因在于渲染引擎(tgfx)层:多个 PAGDecoder 各自 GLDevice::Make(sharedContext) 创建的 EGLContext 共享同一命名空间,缺乏对并发 GL 访问的保护,低端驱动才会错乱。
在 PAGDecoder 层加一把全局锁只是把并发压平为串行来规避问题,存在两个固有缺陷:
- 进程内所有 decoder 的首帧渲染被完全串行化,即使分属不相干的 context/业务,多视图首屏耗时线性叠加;
- 无法覆盖其他同样使用 GLDevice::Make(currentContext) 的并发 GL 路径(如 StillImage 等),本 PR 也未保护 reader 销毁(reader = nullptr)时的 GL 对象释放——它在锁作用域之外,仍与其他 decoder 的 renderFrame 并发。
根治方向:在 tgfx GLDevice 层对共享命名空间的并发访问做 per-context 锁 + makeCurrent 纪律,从渲染引擎层根除,让所有上层调用方自动受益,而非在每个调用点各自打补丁。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
问题
使用多个 PAGImageView 同时播放时,首次渲染(无缓存)会出现帧错乱。例如视图 A 渲染出视图 B 的某一帧,且错误帧被写入磁盘缓存后重启也无法恢复。
低端设备(小米 Note8 Pro、华为 P20)偶现,详见 #3540。
根因
多个 PAGDecoder 在创建时通过
GLDevice::CurrentNativeHandle()获取到同一个 EGLContext 作为 sharedContext。各自的BitmapDrawable又通过GLDevice::Make(sharedContext)创建了共享同一 EGL display 和 GL 对象命名空间的新 EGLContext。在 PAGAnimator 异步渲染模式下(
_isSync = false),tgfx::Task::Run()将不同 PAGImageView 的onAnimationUpdate回调分发到线程池的不同线程上执行,导致多个 Decoder 的renderFrame()在不同线程上并发执行 GL 命令。低端设备的 GPU 驱动无法正确处理共享 EGL 上下文的并发访问,导致渲染目标混乱。修复
在
PAGDecoder::readFrameInternal()中新增静态全局互斥锁renderLocker,包裹renderFrame()和writeFrame()调用。缓存命中时不进入锁区,仅首次 GPU 渲染时串行化,确保不同线程的 GL 命令不会交错执行。改动量:3 行代码,无公开 API 变更。