cocos2d / cocos2d-x

Cocos2d-x is a suite of open-source, cross-platform, game-development tools utilized by millions of developers across the globe. Its core has evolved to serve as the foundation for Cocos Creator 1.x & 2.x.
https://www.cocos.com/en/cocos2d-x
18.28k stars 7.05k forks source link

UI clipping problem when reload Android openGL context #19022

Open pbs0512 opened 6 years ago

pbs0512 commented 6 years ago

Steps to Reproduce:

  1. The test has clippingListView in the previous scene when multiple scenes are nested.
  2. Continuing to click on the Android power button will recreate the opengl context.
  3. Then move to the previous scene (there is a clipping Listview).
  4. There is a bug where Listview childrens are not visible.

error log

OpenGL error 0x0502 in D:/test/frameworks/runtime-src/proj.android/app/jni/…/…/…/…/cocos2d-x/cocos/2d/CCDrawNode.cpp onDraw 362

ggggamer commented 6 years ago

What's your device? I want to fix a crash that need monitor opengl context recreate situation, but it's too difficult to reproduce.

pbs0512 commented 6 years ago

@ggggamer thank you for reply. my device is samsung galaxy 9. but it also happens on other devices.

---Cause of error

  1. Create a scene and add clipping ui.
  2. Push another scene.
  3. At this time, an onExit occurs on the drawnode.
  4. This will cause the EVENT_RENDERER_RECREATED event (https://github.com/cocos2d/cocos2d-x/blob/v3/cocos/2d/CCDrawNode.cpp#L286) to pause.
  5. android reload gl context, the EVENT_RENDERER_RECREATED event of drawNode will not happen.
ggggamer commented 6 years ago

I can't reproduce "opengl context reload", how did you monitor this?

For your crash, Did you use TransitionScene?

pbs0512 commented 6 years ago

Turn the screen off, then on, and repeat with the device power button.

ggggamer commented 6 years ago

TransitionScene::onEnter will disable EventDispatcher so EVENT_RENDERER_RECREATED event can't emit. You can change cocos\platform\android\javaactivity-android.cpp https://github.com/cocos2d/cocos2d-x/blob/c99611589c11c09edce4b1266bf211e42af6ffe4/cocos/platform/android/javaactivity-android.cpp#L106-L107 to

cocos2d::EventCustom recreatedEvent(EVENT_RENDERER_RECREATED);
if (director->getEventDispatcher()->isEnabled())
{
    director->getEventDispatcher()->dispatchEvent(&recreatedEvent);
}
else
{
    director->getEventDispatcher()->setEnabled(true);
    director->getEventDispatcher()->dispatchEvent(&recreatedEvent);
    director->getEventDispatcher()->setEnabled(false);
}
pbs0512 commented 6 years ago

I don't use TransitionScene. use CCScene.cpp and UIListView.cpp. I solved the problem.

https://github.com/cocos2d/cocos2d-x/blob/c99611589c11c09edce4b1266bf211e42af6ffe4/cocos/2d/CCDrawNode.cpp#L286-L294

to

#if CC_ENABLE_CACHE_TEXTURE_DATA
    if (_eventRendererRecreate == nullptr)
    {
        // Need to listen the event only when not use batchnode, because it will use VBO
        _eventRendererRecreate = EventListenerCustom::create(EVENT_RENDERER_RECREATED, [this](EventCustom* event) {
            /** listen the event that renderer was recreated on Android/WP8 */
            this->init();
        });
        _eventDispatcher->addEventListenerWithFixedPriority(_eventRendererRecreate, 1);
    }
#endif

This way, it works regardless of the node's pause (onExit) and resume (onEnter).

ggggamer commented 6 years ago

Congratulations!