Detecting RGB format support

Hello,



I am starting to develop a game using augmented reallity using the qcar library (qualcom augmented reallity) and jme3. Qcar initializes the camera by itself and I pass the data through a bytebuffer from native code to java.



By default qcar camera data is formatted in RGB565, but if I try to use it as is, in some devices the image is not renderered (it renders black) and I need to “translate” it to RGB888. I’d like to avoid the translation step when unneeded (it lasts too long, 9ms native code in my SGS).



Is there any way in jme3 to check if RGB565 is supported?



Thanks

[java]renderer.getCaps() ?[/java]



You may want to check the JavaDoc about this method :

http://hub.jmonkeyengine.org/javadoc/com/jme3/renderer/Caps.html

@ozonegrif, Thanks for your answer. I’ve checked your link, but Caps class doesn’t have information about RGB formats related with my problem, only floating point… Any other ideas?

RGB565 support is required by the OpenGL ES 2.0 specification, it must be supported by all vendors otherwise they break the spec.

Perhaps the issue is elsewhere?

I’ve made a test case to check the RGB565 vs RGB888 problem I’m facing and ran it on some android devices. The test just creates two images (one RGB565 and other RGB888) with different colors and renders both images half the screen…



Here is the code for the main class:



[java]

package mygame;



import com.jme3.app.SimpleApplication;

import com.jme3.material.Material;

import com.jme3.math.ColorRGBA;

import com.jme3.math.Vector3f;

import com.jme3.renderer.RenderManager;

import com.jme3.scene.Geometry;

import com.jme3.scene.shape.Box;

import com.jme3.texture.Image;

import com.jme3.texture.Texture2D;

import com.jme3.ui.Picture;

import java.nio.ByteBuffer;



public class Main extends SimpleApplication

{

// Left stands for RGB565

private ByteBuffer leftBuffer=null;

private Image leftImage=null;

private Texture2D leftTexture=null;

private Picture leftPic;



// Right stands for RGB888

private ByteBuffer rightBuffer=null;

private Image rightImage=null;

private Texture2D rightTexture=null;

private Picture rightPic;





public static void main(String args)

{

Main app = new Main();

app.start();

}



@Override

public void simpleInitApp()

{

//Create two images of different formats (565 and 888)

//Each image will be covering half the screen

int width=settings.getWidth();

int halfWidth=width/2;

int height=settings.getHeight();

int pxSize=halfWidthheight;





leftBuffer=ByteBuffer.allocateDirect(pxSize
2);//Size2 because of RGB565 format

//White image (each pixel is FFFF (16bit)

leftBuffer.rewind();

for(int i=0; i<pxSize;++i)

{

leftBuffer.put((byte)255);

leftBuffer.put((byte)255);

}



leftImage=new Image(Image.Format.RGB565, halfWidth, height, leftBuffer);

leftTexture=new Texture2D();

leftTexture.setImage(leftImage);



leftPic=new Picture("left");

leftPic.setTexture(assetManager, leftTexture, false);

leftPic.setWidth(halfWidth);

leftPic.setHeight(height);

leftPic.setPosition(0, 0 );



guiNode.attachChild(leftPic);



rightBuffer=ByteBuffer.allocateDirect(pxSize
3);//Size*3 because of RGB888 format

//Green image (each pixel is 00FF00 (24bit)

rightBuffer.rewind();

for(int i=0; i<pxSize;++i)

{

rightBuffer.put((byte)0); //r

rightBuffer.put((byte)255); //g

rightBuffer.put((byte)0); //b

}



rightImage=new Image(Image.Format.RGB8, halfWidth, height, rightBuffer);

rightTexture=new Texture2D();

rightTexture.setImage(rightImage);



rightPic=new Picture("right");

rightPic.setTexture(assetManager, rightTexture, false);

rightPic.setWidth(halfWidth);

rightPic.setHeight(height);

rightPic.setPosition(halfWidth, 0);



guiNode.attachChild(rightPic);



guiNode.updateGeometricState();

guiNode.updateLogicalState(0);

}



@Override

public void simpleUpdate(float tpf) {

//TODO: add update code

}



@Override

public void simpleRender(RenderManager rm) {

//TODO: add render code

}

}

[/java]



The Activity class is the default one created automatically when added the mobile configuration to the project.



I’ve run the program in some devices having the following results (Bad stands for rendered black):



Galaxy S → 565 OK, 888 OK

HTC desire → 565 Bad, 888 OK

Galaxy Tab - 565 OK, 888 OK

Sony tablet S - 565 Bad, 888 OK

Galaxy S2 - 565 Bad, 888 OK



It seems that all tested devices render correctly RGB888 but only some of them are capable to render RGB565 (just the powerVR based devices). There is no related output in the logcat when running the test.



Also I tried to run this code on the PC getting the following exception:



GRAVE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]
java.lang.UnsupportedOperationException: Unrecognized format: RGB565
at com.jme3.renderer.lwjgl.TextureUtil.uploadTexture(TextureUtil.java:395)
at com.jme3.renderer.lwjgl.LwjglRenderer.updateTexImageData(LwjglRenderer.java:1865)
at com.jme3.renderer.lwjgl.LwjglRenderer.setTexture(LwjglRenderer.java:1887)
at com.jme3.material.MatParamTexture.apply(MatParamTexture.java:46)
at com.jme3.material.Material.render(Material.java:1009)
at com.jme3.renderer.RenderManager.renderGeometry(RenderManager.java:649)
at com.jme3.renderer.queue.RenderQueue.renderGeometryList(RenderQueue.java:299)
at com.jme3.renderer.queue.RenderQueue.renderQueue(RenderQueue.java:348)
at com.jme3.renderer.RenderManager.renderViewPortQueues(RenderManager.java:911)
at com.jme3.renderer.RenderManager.flushQueue(RenderManager.java:842)
at com.jme3.renderer.RenderManager.renderViewPort(RenderManager.java:1118)
at com.jme3.renderer.RenderManager.render(RenderManager.java:1166)
at com.jme3.app.SimpleApplication.update(SimpleApplication.java:266)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:149)
at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:182)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:223)
at java.lang.Thread.run(Thread.java:662)

This link should give you more of an insight of what some phones are actually capable of doing



Link

@techsonic thanks for the link. I’ve read it, but I can’t find any GL extension or information regarding which hardware supports RGB565 correctly or not there… :? Any other ideas?

The RGB565 natively shows that it uses FrameBuffer Objects. You might want to ask @Momoko_Fan about the FrameBuffer part.



http://i.imgur.com/b5a6R.jpg

Looking at the OpenGL 2.0 specification, it seems that the RGB565 format is not supported, thus the correct behavior is exhibited on the PC.

@techsonic was referring to the OpenGL ES 2.0 specification, which does indeed support RGB565, although some mobile GPU vendors fail to support it thus breaking the spec.

@Momoko_Fan said:
...was referring to the OpenGL ES 2.0 specification, which does indeed support RGB565, although some mobile GPU vendors fail to support it thus breaking the spec.


Acording to my tests, the only GPUs correctly following the spec are powerVR... So finally, and until I get a better way to do it, I'm just checking the renderer name and if it's PowerVR hardware I use RGB565 otherwise I use RGB888. This way my app works on all hardware I've been able to try. :P