Skip to content

fix-3.13.9-crash-windows-angle-context-frameBuffer

Choose a tag to compare

MixinNetwork/flutter-plugins#283

Crash description

  1. SuerfaceFrame::Submit() requires framebuffer to be not nullptr.
    Framebuffer *framebuffer = state.getDrawFramebuffer();
    ASSERT(framebuffer);

    if (context->getLimitations().noSeparateStencilRefsAndMasks ||
        extensions.webglCompatibilityANGLE)
    {
        ASSERT(framebuffer);
        const FramebufferAttachment *dsAttachment =
            framebuffer->getStencilOrDepthStencilAttachment();
        const GLuint stencilBits = dsAttachment ? dsAttachment->getStencilSize() : 0;
        ASSERT(stencilBits <= 8);
...
  1. FlutterViewController will reset frameBuffer by calling State::setDrawFramebufferBinding()

Crash case

SurfaceFrame::Submit() -> OpsTask::onExecute() -> [ renderPass->begin(); chain.head()->execute(flushState, chain.bounds()); ]

renderPass->begin(); will prepare the framebuffer, then chain.head()->execute(flushState, chain.bounds()); will execute with no error.

But there's no guarantee that no other threads call State::setDrawFramebufferBinding() between the two calls.

No crash case

If State::setDrawFramebufferBinding() is not executed between renderPass->begin(); and chain.head()->execute(flushState, chain.bounds());

                             Thread 1                     |                                   Thread2
-------------------------------------------------------------------------------------------------------------------------
        OpsTask::onExecute()                              |
                                                          |
        renderPass->begin();                              |
                                                          |
 chain.head()->execute(flushState, chain.bounds());       |
                                                          |
                                                          |     State::setDrawFramebufferBinding()  from FlutterViewController()

Crash case

                             Thread 1                     |                                   Thread2
-------------------------------------------------------------------------------------------------------------------------
        OpsTask::onExecute()                              |
                                                          |
        renderPass->begin();                              |
                                                          |
                                                          |     State::setDrawFramebufferBinding()  from FlutterViewController()
                                                          |
 chain.head()->execute(flushState, chain.bounds());       |
                                                          |
                                                       Crash
https://github.com/google/angle/blob/eebf069c1d98952c9cde6f4e5f81383736b10163/src/libANGLE/validationES.cpp#L4124

Callstacks

Crash callstack

See the image attached in MixinNetwork/flutter-plugins#283.

Reset frameBuffer

Creating FlutterViewController will cause the global render context to reset the framebuffer by calling EGL_MakeCurrent then ANGLE_TRY(unsetDefaultFramebuffer());

State::setDrawFramebufferBinding 15424, 000001EA9A854AB0, framebuffer: 0000000000000000
[0] gl::State::setDrawFramebufferBinding
[1] gl::Context::unsetDefaultFramebuffer
[2] gl::Context::unMakeCurrent
[3] egl::Display::makeCurrent
[4] egl::MakeCurrent
[5] EGL_MakeCurrent
[6] flutter::AngleSurfaceManager::SetVSyncEnabled
[7] flutter::AngleSurfaceManager::CreateSurface
[8] flutter::FlutterWindowsView::CreateRenderSurface
[9] FlutterDesktopViewControllerCreate
[10] DesktopMultiWindowSetWindowCreatedCallback
[11] DesktopMultiWindowPluginRegisterWithRegistrar
[12] DesktopMultiWindowPluginRegisterWithRegistrar
[13] DesktopMultiWindowPluginRegisterWithRegistrar
[14] DesktopMultiWindowPluginRegisterWithRegistrar
[15] DesktopMultiWindowPluginRegisterWithRegistrar
[16] DesktopMultiWindowPluginRegisterWithRegistrar
[17] DesktopMultiWindowSetWindowCreatedCallback
[18] flutter::IncomingMessageDispatcher::HandleMessage
[19] flutter::FlutterWindowsEngine::HandlePlatformMessage
[20] std::_Func_impl_no_alloc<`lambda at ../../flutter/shell/platform/embedder/embedder.cc:1874:9',void,std::unique_ptr<flutter::PlatformMessage,std::default_delete<flutter::PlatformMessage> > >::_Do_call
[21] std::_Func_class<void,std::unique_ptr<flutter::PlatformMessage,std::default_delete<flutter::PlatformMessage> > >::operator()
[22] flutter::PlatformViewEmbedder::HandlePlatformMessage
[23] fml::internal::CopyableLambda<`lambda at ../../flutter/shell/platform/embedder/platform_view_embedder.cc:24:9'>::operator()<>
[24] flutter::EmbedderTaskRunner::PostTask
[25] flutter::EmbedderThreadHost::PostTask
[26] FlutterEngineRunTask
[27] std::_Func_impl_no_alloc<`lambda at ../../flutter/shell/platform/windows/flutter_windows_engine.cc:171:41',void,const FlutterTask *>::_Do_call
[28] flutter::TaskRunner::ProcessTasks
[29] flutter::TaskRunnerWindow::ProcessTasks
[30] flutter::TaskRunnerWindow::HandleMessage
[31] CallWindowProcW
[32] DispatchMessageW
[33] DispatchMessageW
[34] DispatchMessageW
[35] BaseThreadInitThunk
[36] RtlUserThreadStart