Bug 239896 - Safari Tab freezes when creating too many webgl render calls without flushing
Summary: Safari Tab freezes when creating too many webgl render calls without flushing
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebGL (show other bugs)
Version: Safari 15
Hardware: iPhone / iPad iOS 15
: P2 Normal
Assignee: Nobody
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2022-04-29 05:19 PDT by Sebastian Dunkel
Modified: 2022-05-06 14:19 PDT (History)
5 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Sebastian Dunkel 2022-04-29 05:19:16 PDT
Hello,

We got reports from customers using Autodesk Forge Viewer that, since updating to IOS 15, very large models could not be loaded anymore and the browser tab completely freezes.
On IOS14 the same models load without problems. They also load fine when deactivating the Safari experimental flag "WebGL via Metal". 

The console on the device contains the following error messages when the tab freezes:
 // IOReturn IOGPUDevice::new_resource(IOGPUNewResourceArgs *, struct IOGPUNewResourceReturnData *, IOByteCount, uint32_t *): PID 44130 likely leaking IOGPUResource (count=44000)
 // ...
 // IOReturn IOGPUDevice::new_resource(IOGPUNewResourceArgs *, struct IOGPUNewResourceReturnData *, IOByteCount, uint32_t *): PID 44130 likely leaking IOGPUResource (count=60000)

The problem seems to occur in combination with multiple frame buffer objects, many geometry buffers and draw calls. 
Calling WebGLRenderingContext.flush() every couple thousand draw calls seems to prevent the issue.

We were not able to reproduce the issue using an IOS simulator, but only on physical devices. On some devices the tab reports a problem and reloads instead of freezing.


I created a minimal example application to show the issue:

// this version consistently fails after roughly 11.500.000 draw calls (Tested on IPhone 11, IPhone 13, IPhone 13 Pro Max, IPad Pro 11 2Gen with IOS/IpadOS 15.4)
https://sdunkel.github.io/IOS15TabFreeze/index.html

// this version does a flush in between and doesn't seem to fail
https://sdunkel.github.io/IOS15TabFreeze/index.html?flush

Depending on the amount of allocated/used resources the number of usable draw calls before the tab freezes varies significantly. So in our application this is already the case after a few ten thousand draw calls.

Thank you
Comment 1 Kenneth Russell 2022-04-29 11:31:03 PDT
I suspect this has already been addressed in top-of-tree WebKit with many other fixes that have been integrated.

Submitter, does this happen on macOS with M1 hardware? That would make it easier to diagnose and confirm whether it's been fixed with Safari Technology Preview.
Comment 2 Sebastian Dunkel 2022-05-02 00:39:21 PDT
On an M1 MacBook Pro (16-inch, 2021) with Safari 15.4 (17613.1.17.1.13) I can reach 33.500.000 draw calls in the test app and then the tab crashes and reloads. I can't reproduce the freezing behaviour on the Mac though, so I can't say for sure whether it is exactly the same problem. Turning off "WebGL via Metal" or flushing the GL context prevents the crashes on the Mac as well.

The console shows similar error messages:
 // IOReturn IOGPUDevice::new_resource(IOGPUNewResourceArgs *, struct IOGPUNewResourceReturnData *, IOByteCount, uint32_t *): PID 62576 likely leaking IOGPUResource (count=135000)
 // virtual bool IOGPUResource::map(uint64_t): failed to create mapping. resType=0x0
 // IOReturn IOGPUDevice::new_resource(IOGPUNewResourceArgs *, struct IOGPUNewResourceReturnData *, IOByteCount, uint32_t *): failed to create mapping.
 // static IOReturn IOGPUDeviceUserClient::s_new_resource(IOGPUDeviceUserClient *, void *, IOExternalMethodArguments *) failed to create resource

Same behaviour with Safari Tech Preview (15.4, WebKit 17614.1.7.7)
Comment 3 Radar WebKit Bug Importer 2022-05-06 05:20:12 PDT
<rdar://problem/92854716>
Comment 4 Kyle Piddington 2022-05-06 14:13:40 PDT
Looking at the code, it seems that we only flush when we exceed a resident resource count. Either this isn't being calculated right, or we need more flush conditions.

bool CommandBuffer::needsFlushForDrawCallLimits() const
{
    return mWorkingResourceSize > kMaximumResidentMemorySizeInBytes;
}



We might need to tweak this to a maximum number of drawArrays calls too. 10k, maybe?
Comment 5 Kenneth Russell 2022-05-06 14:19:35 PDT
That seems reasonable though I would:

1) Count all draw calls, not just drawArrays calls.
2) Make the limit higher so long as that mitigates this reported problem - like 100K draw calls.
3) Write a WebGL conformance test that tries to expose the freezing.

Please note that similar bugs were found in the past:
https://github.com/KhronosGroup/WebGL/blob/main/sdk/tests/conformance/rendering/many-draw-calls.html

and a reasonable place for any new test case could be:
https://github.com/KhronosGroup/WebGL/tree/main/sdk/tests/conformance2/rendering