In my openGL game, I draw my scene normally using a GLSurfaceView.Renderer class in the onDrawFrame(). However, when I am displaying a loading screen I would like to force the screen to draw after each item of data is loaded so the loading bar can be displayed.
Is it possible to force a bufferswap during this draw call somehow? My only alternative is to stagger my loading across multiple frames which means a lot of rework..
I guess what I am trying to call is eglSwapBuffers() but I cannot find a way to access the egl context from the GLSurfaceView or GLSurfaceView.Renderer.
Thank you for your time.
You can add also this method to your GLSurfaceView.Renderer class:
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
public void swapBuffers()
{
EGL10 curEgl = (EGL10)EGLContext.getEGL();
EGLDisplay curDisplay = curEgl.eglGetCurrentDisplay();
if (curDisplay == EGL10.EGL_NO_DISPLAY) { Log.e("myApp","No default display"); return; }
EGLSurface curSurface = curEgl.eglGetCurrentSurface(EGL10.EGL_DRAW);
if (curSurface == EGL10.EGL_NO_SURFACE) { Log.e("myApp","No current surface"); return; }
curEgl.eglSwapBuffers(curDisplay, curSurface);
}
Much the same as OpenUserX03's answer, just in Java.
No you can't (or shouldn't) force swapping buffers in the onDraw method of your Renderer.
What you should do is to make the loading of your data in a separate Thread. Your onDraw method will still be called regularly, which will let you ask to the loading thread how many items were loadede to display a progress bar / message accordingly.
It's been awhile since the answer has been accepted but you can (and there is no reason you shouldn't) force swapping the buffers in the onDrawFrame() method of your Renderer.
I had the exact same problem in my OpenGL app - I needed to render a loading screen while data was being loaded. Here is my pseudo-code example of calling eglSwapBuffers() during a load (I use JNI):
public void onDrawFrame(GL10 gl)
{
MyJNILib.render();
}
MyJNILib native pseudo-code:
#include <EGL\egl.h>
...
void render()
{
...
while (loading)
{
// Do loading stuff
...
eglSwapBuffers( eglGetCurrentDisplay(), eglGetCurrentSurface( EGL_DRAW ) );
}
...
}
A solution by force is to make your custom version GLSurfaceView class based on the source code of Android.
In the source, you can find a method called swap:
/**
* Display the current render surface.
* #return the EGL error code from eglSwapBuffers.
*/
public int swap() {
if (! mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
return mEgl.eglGetError();
}
return EGL10.EGL_SUCCESS;
}
This should be what you want. Unfortunately, however, it is a method of private inner class called EglHelper.
/**
* An EGL helper class.
*/
private static class EglHelper {
So in your custom GLSurfaceView class (copied from Google's source), make this EglHelper class public and you can use EglHelper.swap method.
public static class EglHelper {
Related
I have a standard GLSurfaceView class:
public class TestSurfaceView extends GLSurfaceView {
public MainRenderer mRenderer;
public GStreamerSurfaceView(Context context) {
super(context);
setEGLContextClientVersion(2);
mRenderer = new MainRenderer(context);
setRenderer(mRenderer);
setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
}
}
I have a Renderer class that implements GLSurfaceView.Renderer:
public class MainRenderer implements GLSurfaceView.Renderer {
private int[] hTex;
private SurfaceTexture mSTexture;
private Context context;
MainRenderer(Context c) {
context = c;
}
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
}
public void onDrawFrame(GL10 unused) {
}
public void onSurfaceChanged(GL10 unused, int width, int height) {
}
public void onSurfaceCreated(GL10 arg0, javax.microedition.khronos.egl.EGLConfig arg1) {
}
}
In a separate JNI thread, I have some video data (YUV format) uploaded to an OpenGLES texture. I receive in Java the notification that a new texture is available and I have the corresponding texture id.
How can I display the content of this texture in the Renderer class with minimum performance impact?
For cases where the frames are coming from Camera or MediaCodec there are some very efficient solutions. It sounds like you're generating or decoding the video in software, though, which puts a mild spin on things (though you do have a SurfaceTexture declared in your code, which is odd). The trick is the "OpenGL ES texture" part, because the texture is associated with the EGL context, and the EGL context can only be active in one thread at a time.
Because you're using GLSurfaceView, rather than plain SurfaceView, you don't have control over the EGL context in the GLSurfaceView's renderer thread. The easiest way to work around this is to jump through some hoops to create a second EGL context that is shared with the first. Once you've done that, the texture created in the separate JNI thread will be available to the GLSurfaceView renderer thread.
You can find an example of this in Grafika's "show + capture camera" activity. If you look at the onDrawFrame() method in CameraCaptureActivity.java you can see it calling updateSharedContext(), which passes a message to the thread running TextureMovieEncoder to cause it to run handleUpdateSharedContext(), which (re-)creates the surface used to feed a video encoder.
If you use plain SurfaceView instead, and do your own EGL and thread management, the code will be less twisty. You can create both contexts at once, then just pass one to the thread that's producing images. You could also create a single context and use eglMakeCurrent() to shift it between threads, but that could be expensive on some platforms.
Update: the Grafika "show + capture camera" implementation has a race condition; see this bug report for details on the problem and solution. You have to perform some extra steps when creating a texture in one thread and using it in another. It's usually better to do everything in one context on one thread. The other activities in Grafika use a plain SurfaceView and do their own EGL context and thread management.
I am rendering a rajawali renderer object as
public void onCreate(Bundle savedInstanceState)
{
// initializing camera etc.
mSurfaceView.setZOrderMediaOverlay(true);
setGLBackgroundTransparent(true);
mRenderer = new Renderer(this);
mRenderer.setSurfaceView(mSurfaceView);
super.setRenderer(mRenderer);
mRenderer.setCameraPosition(0, 0, 20);
}
where mRenderer is an object of a class Renderer that extends rajawalirenderer
public class Renderer extends RajawaliRenderer
{
...// code for rendering a textured sphere
}
Now I want to stop the rendering of this 3d object(sphere) on some event handler, say button click. (And once the rendering is stopped, I again want to render a different 3d object on button click.)
How can I stop the rendering of 3d object sphere?
After searching a bit, I found the answer. There's a method named removeChild that-
Requests the removal of a child from the scene.
Parameters:
child Object3D child to be removed.
Returns:
boolean True if the child was successfully queued for removal.
Example..
getCurrentScene().removeChild(3d_Object);
where 3d_Object is the object which we don't want to render.
I have the following (simplified) rig so far:
MyActivity.java:
public class MyActivity extends Activity {
public GLSurfaceView myGLView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myGLView = new MyGLSurfaceView(this);
setContentView(myGLView);
}
}
MyGLSurfaceView.java:
public class MyGLSurfaceView extends GLSurfaceView {
private MyRenderer mMyRenderer = new MyRenderer();
private MyThread mMyThread = new MyThread();
public MyView(Context context) {
super(context);
setRenderer(mGameRenderer);
setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
mGameThread.setRunning(true);
}
}
MyRenderer.java:
public class GameRenderer implements GLSurfaceView.Renderer {
#Override
public void onDrawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
// ...
}
}
MyThread.java:
Here I'm doing all initializations, creating objects and so on.
public class MyThread extends Thread {
private MyObject mMyObject = new MyObject();
public MyThread {
// ...
mMyObject.setRot();
this.start();
}
public void run() {
// Fixed Timestep Loop goes here
mMyObject.getRot();
}
}
MyObject.java:
This is a sample object which holds different fileds and methods.
public class MyObject {
private double mRot;
// Getters & Setters
protected double getRot() { return mRot; }
protected void setRot() {
// ... Do calculations
}
public void draw() {
// OGL Instructions go here
gl.glRotatef(1.2f, 0, 0, setRot());
}
}
Now the problem I was running into is the following: (I guess, I missed something very basic and simple :) )
As stated above, I'm creating my object instances in the MyThread class. The Thread is created in the MyGLSurface class, same goes for the Renderer. Now, that I have that two threads I can't figure out, how to use that one instance and their methods in that two separate threads.
I tried different approaches, but nothing did work. So in my opinion I made a mistake in the class design. I mean, I don't just want to get it running (that'd be quite easy), but I want to know how to do it correctly.
The main problem is actually that I can't access the MyObject's instance and simply use the draw() method in the renderer - because I don't get it.
I thought, it would be possible to call the draw() method of MyObject within the rendering thread without the need of using a singleton and so on. So simply referencing the instance to it. But somehow that seemed weird and dirty (besides that it doesn't work for me).
I tried dozens of different approaches, but I really need a bump into the right direction. I'm quite familar with OOP, but here I might really miss something.
In that many samples I found on the web (stackoverflow, Replica Island, different tutorial sites, Google I/O, DevCentral, etc.) they either didn't use a multithreaded system or they split it directly (GL objects from regular objects).
Any hint into the right direction would be much appreciated!
Another example to peruse:
https://code.google.com/p/android-breakout/
The wiki and code comments discuss the threading issues inherent in using GLSurfaceView. In particular, the game does as much setup as it can before the Renderer thread starts; once it's running, as much work as possible is done on that thread. The game state objects are effectively "owned" by the renderer thread, and the Activity is owned by the UI thread, so any "off-thread" interactions are handled by sending messages rather than making direct method calls. For example, see the handling of touch events.
It's good that you're thinking about this -- you either need synchronization or careful object discipline to avoid nasty race conditions.
See also: android game loop vs updating in the rendering thread
The nice thing about GLSurfaceView is that it creates the OpenGL rendering thread for you, so you don't need to create one yourself. The main UI thread will call the OnDraw() method in your view class and that's all the threads you need. If you really want to create your own thread for OpenGL rendering, use TextureView instead of GLSurfaceView. Here is an article that I think will help:
http://software.intel.com/en-us/articles/porting-opengl-games-to-android-on-intel-atom-processors-part-1
I can get the scene from a layer, but I don't know how to have a Scene that manages layers. I can do this on iPhone, but on Android my code doesn't even get called.
This is in my start Activity:
CCDirector.sharedDirector().runWithScene(EditorScene.node());
This is my scene class:
public class EditorScene extends CCScene
{
public EditorScene()
{
CanvasBackgroundLayer canvasBackgroundLayer = (CanvasBackgroundLayer) CanvasBackgroundLayer.node();
CanvasEditorLayer canvasEditorLayer = (CanvasEditorLayer) CanvasEditorLayer.node();
addChild(canvasBackgroundLayer,0);
this.addChild(canvasEditorLayer);
}
}
My constructor here is never called. Any ideas on what to do?
Any subclasses of CCScene have to reimplement the static method node(). Have a look at the bottom of CCScene.h.
I am trying to create a context in opengl-es for android and I'm a bit confused about it. I have initialized my context in a completely separate class from my renderer and my launch activity like so.
import javax.microedition.khronos.egl.EGL11;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
import javax.microedition.khronos.opengles.GL11;
public class Context {
public static GL11 gl;
EGLConfig[] configs = new EGLConfig[1];
EGLConfig config = configs[0];
EGLDisplay dpy;
int attribList;
EGLSurface surf;
static EGLContext glContext;
public Context() {
int attribList [] =
{
EGL11.EGL_DEPTH_SIZE, 15, // z-buffer
EGL11.EGL_NONE
};
dpy = ((EGL11) gl).eglGetDisplay(EGL11.EGL_DEFAULT_DISPLAY);
EGLContext glContext = ((EGL11) gl).eglCreateContext(dpy, config, EGL11.EGL_NO_CONTEXT, attribList);
gl = (GL11)glContext.getGL();
}
}
My app is a simple thing that draws two squares to the screen on launch, one moves in a random direction while the other stays on the spot and spins. In theory the user should be able to touch the screen and the stationary square should move to the location touched on screen. But my app crashes when my UnProject method (which I need to translate coordinates) is called, possibly because my context
GL11 gl
(which is the argument for my UnProject class) returns null (NullPointerException is thrown when my app crashes).
Is my context initialized badly so that it returns null or do you think the problem is elsewhere?
I doubt that the Context constructor gets called anywhere in your code; if it did it would crash at that point:
You cast gl to an EGL11 type, while it doesn't implement that interface.
You use the config member in EGLContext glContext = ((EGL11) gl).eglCreateContext(dpy, config, EGL11.EGL_NO_CONTEXT, attribList);, while it's not initialized (it's null as the entries of your configs member are not constructed)
Where is gl assigned? From outside the Context class?
You use the gl member and then reassign it in gl = (GL11)glContext.getGL() ?
...
In short, I don't think gl was assigned a value in the first place, but it's hard to tell without the rest of the code.