24

When Android 4.0 (Ice Cream Sandwich) was released, a new view was introduced into the sdk. This View is the TextureView. In the documentation, it says that the TextureView can be used to display content for an OpenGL scene.

When you look up how to do this, you'll find this link to one example.

https://groups.google.com/forum/?fromgroups=#!topic/android-developers/U5RXFGpAHPE

However I wanted to just replace GLSurfaceView with TextureView, and keep the rest of my code the same, and just receive the advantages of the TextureView.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
William Goodale
  • 611
  • 1
  • 5
  • 6
  • 3
    FWIW, http://source.android.com/devices/graphics/architecture.html describes how GLSurfaceView and TextureView compare at a system level, and the tradeoffs between them. – fadden May 20 '14 at 20:08

4 Answers4

36

Answer:

1) Start with the source code of the GLSurfaceView, name the file GLTextureView.java

2) Change the header to: GLTextureView extends TextureView implements SurfaceTextureListener

3) Rename constructors to GLTextureView. Remove code from init() method.

4) Organize imports. Always choose the non-GLSurfaceView option.

5) Find every instance of SurfaceHolder and change it to a SurfaceTexture

6) Add Unimplemented methods for the SurfaceTextureListener, each method should be as follows:

  • onSurfaceTextureAvailable - surfaceCreated(surface)
  • onSurfaceTextureDestroyed - surfaceDestroyed(surface), (return true)
  • onSurfaceTextureSizeChanged - surfaceChanged(surface, 0, width, height)
  • onSurfaceTextureUpdated - requestRender()

7) There should be one line where there is a call being made to getHolder(), change that to getSurfaceTexture()

8) In the init() method, put the following line setSurfaceTextureListener(this)

Then add an OnLayoutChangeListener and have it call surfaceChanged(getSurfaceTexture(), 0, right - left, bottom - top).

With that you should be able to replace your GLSurfaceView code with GLTextureView and receive the benefits of GLTextureView. Also make sure your app supports Hardware Acceleration and that your Renderer extends GLTextureView.Renderer.

Rajesh Loganathan
  • 11,129
  • 4
  • 78
  • 90
William Goodale
  • 611
  • 1
  • 5
  • 6
  • Adding to Robin and William's answers: This method works all the cases when you want to convert a SurfaceView to TextureView. – Edison Apr 22 '13 at 17:09
  • 2
    Is it possible to post an example of this? I have found this: https://github.com/eaglesakura/gltextureview/blob/master/GLTextureView/src/com/eaglesakura/view/GLTextureView.java Does this resemble the method your describing? – Martijn Mellens Aug 14 '13 at 15:15
  • 2
    Note that while this answer does work, you don't want to do last step of point 5 ie `onSurfaceTextureUpdated - requestRender()`. With this line, onDrawFrame is called continuously even if rendermode is set to RENDERMODE_WHEN_DIRTY. Without it, RENDERMODE_WHEN_DIRTY behaves as it should. – iTwenty Nov 07 '14 at 10:06
  • @William Goodalte Can you please take a look at this thread? http://stackoverflow.com/questions/32482565/replace-glsurfaceview-with-textureview-android – Kaidul Sep 09 '15 at 14:40
  • On some Android versions this will draw as fast as possible -- >1000fps! To limit the framerate, use RENDERMODE_DIRTY and use a Choreographer to call requestRender(). – Learn OpenGL ES Nov 25 '15 at 18:50
  • "5) Find every instance of SurfaceHolder and change it to a SurfaceTexture" - I don't get this stage. For example, I have an extended SurfaceView which is using for stream and it has plenty of settings for surfaceholder. How can I apply them to SurfaceTexture? – Eugene Alexeev Jan 27 '16 at 15:29
14

Brilliant!

A minor addition to Mr. Goodale's brilliant answer:

The 4.1.1 version of GLSurfaceView seems to have been modified to avoid rendering on a zero-width/height surface, I think. And there doesn't seem to be a gratuitous onSurfaceTextureChanged notification immediately following onSurfaceTextureAvailable.

If you start with the 4.1.1 sources, onSurfaceTextureAvailable needs to read as follows:

public void onSurfaceTextureAvailable(SurfaceTexture surface, int width,
        int height) 
{
    this.surfaceCreated(surface);
    this.surfaceChanged(surface, 0,width,height);
}

Other than that, I was up and running in about five minutes flat! Thanks.

Robin Davies
  • 7,547
  • 1
  • 35
  • 50
5

Thanks Mr. Goodale's and Mr. Davies for answers!

I have some extra about conversion GLSurfaceView to GLTextureView. The first is about render mode. As described there just remove the requestRender() call in onSurfaceTextureUpdated.

The second is about
mGLESVersion = SystemProperties.getInt("ro.opengles.version", ConfigurationInfo.GL_ES_VERSION_UNDEFINED); Just use link, but you need Context to do context.getClassLoader(); You can call reflection version of getInt from init() and save result in static field sGLESVersion = getInt(getContext(), "ro.opengles.version",ConfigurationInfo.GL_ES_VERSION_UNDEFINED);

And the last easiest change is about EGLLogWrapper.getErrorString(error); Just copy getErrorString from EGLLogWrapper sources.

See the final version of my conversion GLSurfaceView to GLTextureView on GitHub Gist

Community
  • 1
  • 1
AndreyICE
  • 3,574
  • 29
  • 27
  • I tried this on Android 5.0 ( with `compileSdkVersion 21` ). This crashed if I tried to make the GLTextureView transparent - I called `setEGLConfigChooser(8, 8, 8, 8, 16, 0); and setOpaque(false)`. Should I try your gist with any particular `compileSdkVersion` in gradle ? – kiranpradeep Mar 04 '15 at 17:04
  • It's probably worth noting that you can do this without the reflection with the following: `final ActivityManager activityManager = (ActivityManager) c.getSystemService(Context.ACTIVITY_SERVICE); final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo(); sGLESVersion = configurationInfo.reqGlEsVersion;` – Cara Esten Hurtle Mar 04 '15 at 22:54
  • I think it's just because config was not found. Try setEGLConfigChooser(8, 8, 8, 8, 24, 0); – AndreyICE Mar 05 '15 at 07:48
4

If you want to copy/paste a ready-made class, I wrote one here:

GLTextureView

You can call setRenderer(GLSurfaceView.Renderer), like with a GLSurfaceView.

Yervant
  • 225
  • 2
  • 8