
javachromiumembedded - issue #34
JCEF MainFrame sample app displays blank over remote deskop on Windows 7 in OSR mode
What steps will reproduce the problem? 1. Connect to a Windows box through remote desktop (e.g. Windows 7) 2. Start the JCEF MainFrame sample app from within that remote desktop session 3. App comes up but open gl area is rendered blank
What is the expected output? What do you see instead? Expect to see the web site rendered instead of blank
What version of the product are you using? On what operating system? jcef_binary_3.1650.1501.9_windows64_preview.7z
Please provide any additional information below.
I understand the remote desktop scenario isn't necessarily high on everyone's agenda. And the goal isn't to have super high performance rendering over a remote session anyway. But note that this pb doesn't affect the native CEF client app nor of course the standalone Chrome browser. It's related to a call JCEF uses from JOGL.
When creating the GL Canvas from within a remote desktop session, MSFT uses an open gl driver that uses software, not hardware support (gl2.getContext().isHardwareRasterizer() is false). This doesn’t support some Open GL 2.0 features, among them support for npot textures – non power of two textures. JCEF gets a buffer from the rendering engine and renders it as an open gl texture of size (width,height) with the call glTexImage2D inside CefRender.onPaint. That call fails when using the emulated open gl MSFT driver. Same issue for glTexSubImage2D.
Here's the code that fails: gl2.glTexImage2D(gl2.GL_TEXTURE_2D, 0, gl2.GL_RGBA, view_width_, view_height_, 0, gl2.GL_BGRA, gl2.GL_UNSIGNED_INT_8_8_8_8_REV, buffer);
You can find out by starting MainFrame.java with the flag -Djogl.debug.DebugGL
You'll get this kind of exception: javax.media.opengl.GLException: Thread[AWT-EventQueue-0,6,main] glGetError() returned the following error codes after a call to glTexImage2D(<int> 0xDE1, <int> 0x0, <int> 0x1907, <int> 0x310, <int> 0x201, <int> 0x0, <int> 0x1907, <int> 0x1401, <java.nio.Buffer> java.nio.DirectByteBuffer[pos=0 lim=1608768 cap=1608768]): GL_INVALID_VALUE ( 1281 0x501), at javax.media.opengl.DebugGL4bc.writeGLError(DebugGL4bc.java:29412) at javax.media.opengl.DebugGL4bc.glTexImage2D(DebugGL4bc.java:19877) at org.cef.CefRenderer.onPaint(CefRenderer.java:253) at org.cef.CefClient.onPaint(CefClient.java:259) at org.cef.CefContext.N_DoMessageLoopWork(Native Method) at org.cef.CefContext.doMessageLoopWork(CefContext.java:57) at org.cef.MainFrame$1$1.run(MainFrame.java:41) at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251) at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:733) at java.awt.EventQueue.access$200(EventQueue.java:103) at java.awt.EventQueue$3.run(EventQueue.java:694) at java.awt.EventQueue$3.run(EventQueue.java:692) at java.security.AccessController.doPrivileged(Native Method) at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76) at java.awt.EventQueue.dispatchEvent(EventQueue.java:703) at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242) at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138) at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)
This can be reproduced with a pure JOGL example (I can provide it if you wish). I've been searching about these open-gl texture calls and I wrote a horrible hack - turning the ByteBuffer RGBA received from onPaint into a new ByteBuffer RGB with 512x512 and got things to draw over remote desktop - albeit truncated of course.
I would appreciate any tip from a JCEF/CEF/JOGL/Open GL guru here :-)
Comment #1
Posted on Jan 24, 2014 by Massive RabbitI explored another workaround listed here. http://www.opengl.org/discussion_boards/showthread.php/164372-Remote-Desktop "You can do that with Mesa3D : current version is 7.2, and support OpenGL 2.1 in a complete software implementation. Compile or find a windows mesa .dll, and put it as opengl32.dll on your exe folder."
I got the mesa opengl32.dll (18MB...) and installed it into the folder that contains the java.exe. Then it displayed fine when started from a remote desktop session.
But copying things to the JDK/JRE folder isn't great. I was hoping MSFT would search for the current dir or entries in %PATH% before reaching to the system32, but that didn't work in my test. The only way it would use it would be after I remove MSFT's opengl32.dll from system32/.
Tips welcome, I'm interested in a friendly workaround - either by avoiding the calls not supported by MSFT opengl32.dll or by finding a way to tell jogl to use an alternative opengl32.dll in the current dir...
Comment #2
Posted on Jan 24, 2014 by Massive RabbitIn case anyone wants to test comment 1 above, here's a link to a binary of mesa opengl32.dll : http://hivelocity.dl.sourceforge.net/project/msys2/REPOS/MINGW/x86_64/mingw-w64-x86_64-mesa-10.0.1-2-any.pkg.tar.xz
Comment #3
Posted on Jan 27, 2014 by Massive RabbitThe following code renders the whole buffer with glDrawPixels when we detect hardware rendering isn't available. This works over MSFT Remote Desktop. What do you think? I suspect a CEF or OpenGL expert would have better alternatives to suggest?
CefRenderer.java
//Workaround for Windows Remote Desktop unable to deal with npot textures private boolean useDrawPixels = false;
protected void initialize(GL2 gl2) { if (initialized_) return;
if (!gl2.getContext().isHardwareRasterizer()) {
useDrawPixels = true;
System.out.println("opengl rendering may be slow as hardware rendering isn't available");
initialized_ = true;
return;
}
...
protected void render(GL2 gl2) { if (useDrawPixels) { return; } ...
protected void onPaint(GL2 gl2, boolean popup, Rectangle[] dirtyRects, ByteBuffer buffer, int width, int height) { if (!initialized_) initialize(gl2);
if (useDrawPixels) {
gl2.glRasterPos2f(-1,1);
gl2.glPixelZoom( 1, -1 );
gl2.glDrawPixels(width, height, GL2.GL_BGRA, GL2.GL_UNSIGNED_BYTE, buffer);
return;
}
...
Comment #4
Posted on Jan 27, 2014 by Quick HorseHow does the glDrawPixels approach behave from a performance standpoint (framerate, CPU/GPU usage) compared to the texture approach?
Other approaches include creating the view from a grid of tiled power-of-2 textures, or creating a single power-of-2 texture that is larger than the window size and only rendering to a portion of it.
To support the maximal number of devices it might be worthwhile to use only GLES2 interfaces (issue #19).
Comment #5
Posted on Jan 28, 2014 by Massive RabbitHow does the glDrawPixels approach behave from a performance standpoint (framerate, CPU/GPU usage) compared to the texture approach?
I pointed MainFrame.java to this site http://www.smashcat.org/av/canvas_test/ . If you have a preferred graphics benchmark, let me know and I'll re-run the tests.
To my surprise, there wasn't much difference between the 2 approaches in this particular case. The FPS wasn't affected and the GPU/CPU load didn't really differ.
1) Original (textures) FPS: ~ 160 GPU load: ~ 17% CPU load: ~ 5%
2) glDrawPixels FPS: ~ 160 GPU load: ~ 21% CPU load: ~ 6%
3) glDrawPixels over Remote Desktop (over a fast LAN) FPS: ~ 174 (not sure this is the effective RDP rate but it felt smooth anyway)
Comment #6
Posted on Jun 17, 2014 by Quick Horse(No comment was entered for this change.)
Comment #7
Posted on Jun 17, 2014 by Quick HorseThanks, added in revision 86. There's probably a better way to test if non-pot textures are supported (there might be some hardware that doesn't support it too), but I'm not sure what it is.
Status: Fixed
Labels:
Type-Defect
Priority-Medium