I have a program running in vivoX7 device(Android 5.1.1, OpenGL ES 3.1, Adreno ™ 510,4G RAM). According to my observation, when the return value of glGenBuffers over 33279,the next value returned
by glGenBuffers will be 0. Then I remove some assets in the scene, the value can be up to 69778, but finally end up with 0 value.Is there anyone can tell me the reason and how to resolve it?
Best guess: At some point, the implementation is running out of some type of internal resource and so is failing to generate new buffer object handles (0 is of course not a valid buffer object handle). It may be triggering GL errors as well. You might check for those and see if they lead you closer to the source of the problem.
I checked the value after glMapBufferRange with 1285, which implys out of memory. But I use some Profiler finding the memory used by the app is 1.1G and the total memory used is 2.4G, so I am not sure about the reason of out of memory. So I make a test: I make glGenBuffers 100 times instead of one time called, the app crashed soon even the UI is not show up. Then I decrease glGenBuffers 10 times every time called, the UI is displayed normally but the scene (another scene, not the bad scene) which is fine before, is also not working. The last return value of glGenBuffers for all the tests is 0. One Special test I met is a little different, the last values of glGenBuffers are 0->normal values->0->normal Values->0.
As glGenBuffers won’t allocate any memory, so is there possible that the number of buffer object handles exist simultaneously (I mean not deleted yet) are limited?
I am not sure about the problem is related with asset resources or internal system resources, and witch type of internal resources.
Your vivo X7 cell phone uses a Qualcomm Adreno 510 GPU. This is a mobile (embedded) GPU that shares use of the same DRAM memory that’s used by the ARM CPU cores.
So max system+app CPU+GPU memory consumption is limited to 4GB. But likely a much lower limit is imposed on your application’s CPU and GPU usage by the Android OS. It could be some low internal limit like the dalvik heap limit.
Qualcomm has this to say about this GL error w.r.t. Adreno GPUs and drivers:
Since OpenGL ES presents a deferred execution model, keep in mind that you don’t necessarily receive a GL_OUT_OF_MEMORY right after the command that triggered it. It could have been triggered by a command issued many commands previous (even 1 or 2 frames ago).
Pure OpenGL ES doesn’t provide you visibility into the use of driver and GPU memory. So you’ll need to consult Android or Qualcomm-specific tools to gain more insight into where driver CPU and GPU memory is being consumed, and potentially what internal limit is being hit.
For textures and buffer objects, you can estimate best-case GPU memory usage. However, keep in mind that naive OpenGL ES usage can balloon your worst case GPU usage many times over this estimate for driver-internal reasons (e.g ghosting, aka resource renaming).
As you said, glGenBuffers() does not allocate buffer objects, but merely allocate buffer object handles. Should be pretty light-weight. If you’re seeing this behavior with glGenBuffers() on a fresh, clean GL context before you’ve even started allocating textures or buffer objects, then I’d get to the bottom of that first. That’s a big problem.
On the other hand, if at this point in execution you’ve already triggered some GL errors, especially GL_OUT_OF_MEMORY errors, then this test is invalid. I’d retry this on top of a fresh, clean GL context prior to any allocations to ensure valid results.
I would check the Android system log for more clues (see the logcat command; for instance adb logcat Adreno-GSL:* *:S). My guess you’ll at least see something like this in there in response to the GL_OUT_OF_MEMORY error.
But there may be other clues as well as to what internal limit the driver is hitting. Note that in the logs, KGSL = the Adreno kernel graphics driver (Kernel Graphics Support Layer) which talks to the usermode graphics driver linked into your app. GSL is likely the usermode graphics driver (Graphics Support Layer).
Once you establish that your setup is stable, I would recommend avoiding use of map buffer. Even on desktop, this can cause implicit synchronization and slowdowns unless you’re very careful. It’s typically much worse on mobile GPUs, as this can cause a full app CPU block and/or GPU pipeline flush, which besides being very bad for performance, can generate rendering artifacts on mobile. This from the Adreno OpenGL ES Developer’s Guide:
So by contrast, here it says that buffer object updates may ghost (duplicate) the resource on-update (bloating your app’s current memory consumption, potentially instigating GL_OUT_OF_MEMORY conditions), rather than trigger a full block + pipeline flush. Neither is good, so this usage pattern needs to be avoided.
Buffer object updates at render-time are tricky to make fast, especially on mobile GPUs. Consult the Qualcomm Adreno OpenGL ES Programming Guide for tips here.
Thank you for your advices! It applys me a lot ideas and methods to locate my problem. I will try these methods step by step!
And I have another question, last year I also met glerror with 1285 after glMapBufferRangein in another vivoX7 device(android 5.1.1 api level 22, OpenGLES 3.1, Adreno ™ 510), but I didn’t log the handles, so i am not sure if they are the same problem. The point is that when I updated the Android OS version, then the glerror with 1285 disappeared. I don’t know this information is helpful or not, but if you have more idea about it please tell me!
I checked the log, some of these handle are reused, but most of these are deleted without reusing. The new handle value generated by glGenBuffers seems increasing automatically. And I checked logs in other mobile(like Huawei Meta 40),where the scene works fine, the handle can up to 39000. Maybe designing a pool to manage handles can release the problem in vivoX7, but I want to locate the problem is handle limits related first. I am not sure about the problem exactly at this time.
If you’re saying you’re allocating (and deleting) a number of buffer objects on the order of 33,000+, then I’d absolutely agree with Alfonse. Stop doing this. You could easily be fragmenting GPU memory so badly that allocations are failing (e.g. GL_OUT_OF_MEMORY) even if sufficient available GPU memory exists.
Another way to look at it: Even if you could allocate all 4GB of system RAM to your GPU buffer object memory allocations (you can’t, but just for a best case…), then spreading that 4GB across 32768 allocations gives you only 128KB per buffer object. That’s tiny. Moreover, you’ve probably only got 1GB of mem partitioned to the GPU, so that’s ~32KB per object. Pool the vertex data for your draw calls into a few shared buffer objects, preallocate these on startup, and never allocate buffer objects after that (at draw time). This simple change will very likely clear up your GL_OUT_OF_MEMORY problem.
However, even if it doesn’t, with this approach you know very clearly exactly how much GPU memory you’re consuming with your few buffer object allocations and you can compare it against how much GPU mem your app is permitted to use on that system. Moreover, you’re not misusing the GL API, so you’re much less likely to fall victim of unusual GPU driver internal behavior.
Totally different GPU vendor, GPU (Mali-G78), GPU driver, and amount of system RAM (8GB instead of 4GB). The latter likely explains why you’re not blowing out the GPU memory on the Huawei phone with your pathological GL usage but you are on the vivoX7 / Adreno.