I have a graphical glitch related to blending in my OpenGL application using Android NDK.
The strange thing is that when I take a screenshot through adb screencap command, the problem completely disappears and the result looks okay.
My question is:
Is there a way to know what is happening behind the scenes of making screenshots? Is there eglChooseConfig called with some specific values for the entire frame for example? Or maybe is there some specific initial GL state forced?
Some background:
My device is using Qualcomm Adreno 320.
The glich occurs when I call glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) for some of the geometry.
I have also found that setting glColorMask(1, 1, 1, 0) results in a black screen on my device (and only on this device), whereas taking a screenshot results in a complete, correct game frame.
The application outputs no glitches on several other Android devices, and other applications work well, even ones that use blending extensively.
Generally speaking, devices don't have a framebuffer full of pixels that you can copy out of when capturing the screen. The "screen capture" functions are actually "redraw the screen into a buffer" functions. It's possible for the screen capture to be slightly different, deliberately so if a "secure" layer or DRM content is on screen.
Is this a single, fully opaque Surface? Or is it being blended with another layer above or below?
The most common reason for differences is bugs in the Hardware Composer, but it sounds like you're seeing issues rendering on a single surface, so that is less likely. If you have a rooted device, you can turn HWC composition on and off using the commands shown here: adb shell service call SurfaceFlinger 1008 i32 1 will disable overlays and force GLES composition. (If none of that made any sense, read through the graphics architecture doc.)
Are you able to post images of the correct and glitched images? (One via screenshot, one by taking a picture of the device with a second device.)
Do you see similar issues if you record the screen with adb shell screenrecord?
The problem disappeared once I commented out EGL_ALPHA_SIZE setting:
const EGLint attribs[] = {
EGL_BLUE_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_RED_SIZE, 8,
//EGL_ALPHA_SIZE, 8,
EGL_NONE
};
It looks like with alpha set to 8 bits, eglChooseConfig returned a problematic configuration object.
Funnily enough, the "correct" EGLConfig specifies 0 bits for EGL_ALPHA_SIZE, so at first I would expect it to not work at all. Other devices don't really care about the value and they are doing well provided only RGB channels' depths.
I have learned a lesson: if there are graphical glitches on your device, always check all possible EGL configurations!
So my conclusion is: yes, probably there is a custom EGLConfig set inside adb screencap.
Related
I've been looking a lot around, and can't find much of anything clear. The context is I have a stylus-enabled e-ink tablet that I program on for fun, and I'd love to use a native library to read the pen events, and draw directly on the framebuffer. The vendor provides one, secret (a .so JNI lib that you can call with just a size parameter).
I suppose this is intended to activate a direct draw on the frame buffer, eventually with a refresh. But I can't grasp how it's supposed to compose with SurfaceFlinger and Android...
Anyone has experience with generic eink tricks to display from JNI via IOCTL that could explain me why I don't see the pixels changing unless I draw myself in java (I can change the update mode and draw quite fast, but... I want the fastest) ?
How could I verify writes on the FB ? Can an android app be "overlayed" by pixels written directly on the framebuffer ?
I figured it out in the end. Using strace to catch calls to fb0 via ioctl + lsof + remote debugging of the official drawing applications showed me that I was wrong.
This particular tablet's vendor software, unlike the remarkable, does NOT draw on the framebuffer directly via magic ioctl commands. All it does is register an area of the screen to be non refreshable by Android normal display primitives. That allows them not to configure each and every view in the hierarchy to be in Direct Update eink mode, while using the android framework with as little custom code as possible.
I could see the command passed that way:
[pid 3997] openat(AT_FDCWD, "/dev/graphics/fb0", O_RDWR|O_LARGEFILE) = 30
[pid 3997] ioctl(30, _IOC(0, 0x6d, 0x25, 0x00), 0x1) = 0
[pid 3997] close(30)
This simply puts the screen on lockdown and stop all android refreshes.
This means they could be much faster.
I suggest you write a basic pixel plotting program in C for framebuffer. Execute it normally and then create a JNI call for the same. The speed difference is negligible to notice.
Recently, I have started using dumpsys SurfaceFlinger to gather some information about android graphics. I currently work on a development board called Odroid-XU3. The display is a Dell monitor which is connected to the board through HDMI cable.
In the very last few lines of the output of the above command, I have two displays, while I only expect to have one. One of them is Display[0] and the other one is Display[1]. The type column of each of the displays could be HWC or GLES. Some times they are both HWC or GLES and some other times one is HWC and the other one is GLES.
What is the difference between Display[0] and Display[1]?
I have tried to find a documentation to understand how to interpret the output of the aforementioned command, but I have not found anything useful.
It would help to have the dumpsys output in your question, but I can make a couple of general observations.
display[0] is the device's built-in display. display[1] is an "external" display, in your case HDMI. These two indices are hard-wired. (Well, they were as of KitKat; I don't know if they've since un-hard-wired things.) Virtual displays start at index 2.
The chunk of text below the display is the hardware composer dump. It displays the layers on the screen, with a bunch of information about the position, rotation, and format of each layer.
The closest thing to documentation can be found in the HWC section of the graphics architecture doc. Given the level of the system you're working with, I would recommend you read the entire document. Beyond that, you can try to discern the meaning from the source code.
The arch doc does explain the difference between "HWC" and "GLES" in the output: "HWC" means the surface lives on a display overlay, while "GLES" means the surface is being composed with the GPU instead.
I'm using my own GLSurfaceView and have been struggling with crashes related to the EGL config chooser for a while.
It seems as though requesting RGB_565 by calling setEGLConfigChooser(5, 6, 5, 0, 16, 0) should be the most supported. However, running this code on the emulator using host GPU I still get a crash, seemingly because my graphics card does not natively support RGB_565. Setting to RGBA_8888 by calling setEGLConfigChooser(8, 8, 8, 8, 16, 0) seems to run fine on my emulator and HTC Rezound device, but I'm seeing a small number of crash reports in the market still.
My guess is that most phones support RGBA_8888 natively now but a small number of my users have phones which are only compatible with RGB_565, which prevents my config chooser from getting a config.
Seeing as how I don't need the alpha channel, is there a right way to try RGBA_8888 first and then fall back to RGB_565? Is there a cleaner way to just ask for any ol' config without caring about the alpha value?
I saw a possible solution to determine ahead of time what the default display config was and request that specifically here: https://stackoverflow.com/a/20918779/234256. Unfortunately, it looks like the suggested getPixelFormat function is deprecated as of API level 17.
From my experience I do not think setEGLConfigChooser() actually works correctly, i.e. it has a bug in its implementation. Across a number of devices I have seen crashes where setEGLConfigChooser() fails to select a valid context even if the underlying surface is of the correct type.
I have found the only reliable way to choose an EGL context is with a custom EGLConfigChooser. This also has the added benefit of choosing a config based on your own rules, e.g. surface must have depth and preferably RGB888 but can settle for RGB565. This is actually pretty straightforward to use eglChooseConfig() to get a list of possible configurations and then return one of them that matches your selection criteria.
This gsoc code sample is for enabling MSAA. But it also contains code to select configurations, checking if they are available.
https://code.google.com/p/gdc2011-android-opengl/source/browse/trunk/src/com/example/gdc11/MultisampleConfigChooser.java#90
in some android test devices, when rendering in opengl 2.0 ES, the screen flashes.
I was able to track the problem to the GLSurfaceView class at the point the "eglSwapBuffers" is called, so the flashing is produced on each iteration, on one the screen becomes black and the next has the image I've drawn. So it seams that eglSwapBuffers is not preserving the back buffer on each call producing this flashing behaviour.
Is there anyway to preserve the back buffer? I've found around that maybe I could use the EGL_SWAP_BEHAVIOR_PRESERVED_BIT flag but I can't figure it out how to put it in android, and neither how to use it in old API's such as gingerbread.
Thanks
You should not need to modify GLSurfaceView. It's much more likely that your problem is caused by the drivers or configuration of your system. I would try a different test device with different graphics drivers. What happens when you run it on an AVD?
It could be that your test device is not making enough memory available to the underlying linux framebuffer device to get the normal triple buffering. Most systems will fall back to single buffering in that case. I recommend that you check these fb device parameters. The virtual_size should be large enough for 2 or 3 buffers for the display mode you are using:
cat /sys/class/graphics/fb0/mode
U:1024x768p-60
cat /sys/class/graphics/fb0/virtual_size
800,1440
I have a cross-platform code base (iOS and Android) that uses a standard render-to-texture setup. Each frame (after initialization), the following sequence occurs:
glBindFramebuffer of a framebuffer with a texture color attachment
Render some stuff
*
glBindFramebuffer of the default framebuffer (0 on Android, usually 2 on iOS)
glBindTexture of the texture that was the color attachment to the first framebuffer
Render using the bound texture
On iOS and some Android devices (including the emulator), this works fine and as expected. On other devices (currently sitting in front of a Samsung Galaxy Note running 4.0.4), the second-phase rendering that uses the texture looks "jumpy". Other animations continue to run at 60 fps on the same screen as the "jumpy" bits; my conclusion is that the changes to the target texture are not always visible in the second rendering pass.
To test this theory, I insert a glFinish() at the step marked with a * above. On all devices, now, this has the correct behavior. Interestingly, glFlush() does NOT fix the problem. But glFinish() is expensive, and I haven't seen any documentation that suggests that this should be necessary.
So, here's my question: What must I do when finished rendering to a texture to make sure that the most-recently-drawn texture is available in later rendering passes?
The code you describe should be fine.
As long as you are using a single context, and not opting in to any extensions that relax synchronization behavior (such as EXT_map_buffer_range), then every command must appear to execute as if it had executed in exactly the same order specified in the API, and in your API usage you're rendering to the texture before reading from it.
Given that, you are probably encountering driver bugs on those devices. Can you list which devices are encountering the issue? You'll probably find common hardware or drivers.