Hi!I'm trying to get working multisampled FBO on Samsung Galaxy S10+ with Mali-G76 (Android 10).Minimal example from spec fails with GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT (8D56) for me.Tried it with 256x256, 1024x768, 4 samples, GL_MAX_SAMPLES_EXT is 4.I'm building app with gl2.h and gl2ext.h and ndk-r19c.
OpenGL version: OpenGL ES 3.2 v1.r19p0-01rel0.###other-sha0123456789ABCDEF0### Compatibility profileMy desired setup is:- bind texture to COLOR_ATTACHMENT_0 (with glFramebufferTexture2DMultisampleEXT)
- bind d24s8 multisampled renderbuffer to both DEPTH_ATTACHMENT and STENCIL_ATTACHMENT (create with glRenderBufferStorageMultisample, bind with glFramebufferRenderBuffer)
Is there any detail I missed about using this extension?
Thank you!I've tried with GL_UNSIGNED_SHORT_4_4_4_4 when trying to do copy-paste from spec and GL_UNSIGNED_BYTE before that for our regular rgba8888 case.Anothing thing that came to my mind: I'm using EGL with EGL_SAMPLES, 4 for main backbuffer which maybe also uses this extension.If copy-pasted example from spec works fine for you - that will be very interesting to find out the truth! :)
I've tested the spec example on a few devices and drivers now, including a S10 with R19, but so far not been able to hit any problems (glCheckFramebufferStatus return GL_FRAMEBUFFER_COMPLETE). Is it possible to share a reproducer APK for this? Happy to have a look to try to debug what goes wrong.
Just for reference, here's a patch on top of the gles3jni example from https://github.com/android/ndk-samples (the same type of code works for the hello-gl2 sample as well) demonstrating how to load the right function pointers, plus how using the non-EXT glRenderbufferStorageMultisample can result in this error (see the #if for good vs non-working code):
diff --git a/gles3jni/app/src/main/cpp/RendererES3.cpp b/gles3jni/app/src/main/cpp/RendererES3.cpp index df71a85..c7366a5 100644 --- a/gles3jni/app/src/main/cpp/RendererES3.cpp +++ b/gles3jni/app/src/main/cpp/RendererES3.cpp @@ -15,6 +15,8 @@ */ #include "gles3jni.h" +#include <GLES2/gl2ext.h> #include <EGL/egl.h> #define STR(s) #s @@ -117,6 +119,55 @@ bool RendererES3::init() { glVertexAttribPointer(OFFSET_ATTRIB, 2, GL_FLOAT, GL_FALSE, 2*sizeof(float), 0); glEnableVertexAttribArray(OFFSET_ATTRIB); glVertexAttribDivisor(OFFSET_ATTRIB, 1); +#if 1 + GLsizei width = 256; + GLsizei height = 256; + GLint samples; + glGetIntegerv(GL_MAX_SAMPLES_EXT, &samples); + + PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)eglGetProcAddress("glRenderbufferStorageMultisampleEXT"); + PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC glFramebufferTexture2DMultisampleEXT =(PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC)eglGetProcAddress("glFramebufferTexture2DMultisampleEXT"); + + /* Create multisampled depth renderbuffer */ + GLuint depthbuffer; + glGenRenderbuffers(1, &depthbuffer); + glBindRenderbuffer(GL_RENDERBUFFER, depthbuffer); +#if 0 // OK + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples, + GL_DEPTH_COMPONENT16, width, height); +#else // Fails + glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, + GL_DEPTH_COMPONENT16, width, height); +#endif + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + /* Create RGBA texture with single mipmap level */ + GLuint texture; + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, + GL_UNSIGNED_SHORT_4_4_4_4, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glBindTexture(GL_TEXTURE_2D, 0); + + /* Create framebuffer object, attach texture and depth renderbuffer */ + GLuint framebuffer; + glGenFramebuffers(1, &framebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, depthbuffer); + glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0, samples); + + /* handle unsupported cases */ + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != + GL_FRAMEBUFFER_COMPLETE) + { + ALOGE("FBO incomplete: %x", glCheckFramebufferStatus(GL_FRAMEBUFFER)); + } else ALOGE("FBO OK"); + + checkGlError("FBO"); +#endif ALOGV("Using OpenGL ES 3.0 renderer"); return true;
It might be good to double-check any function pointer loader you might be using isn't grabbing the wrong function.
I'll check it and answer tomorrow.Thank you a lot!
Hello.I copy-pasted retrieving glRenderbufferStorageMultisampleEXT pointer as PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC into example and it fixes my issue.The problem was in our engine macro GET_GL_FUNC(func_name, extSuffix) which first looks up function without suffix and only when it is not found looks up EXT version.Thank you for help!
Super, thanks for confirming this was the issue! :)