Hi Romain,

I am wondering about the Thread.sleep() call in the rendering thread's run 
loop. Is that technically necessary? If so, may I ask why? And if so, then 
how would one implement a high-framerate OpenGL game (for instance) using 
TextureView?

What prompted these questions is that I have run into a few devices where 
this code 'crashes' with (randomly) one of the two following errors. Are 
you able to comment on this?


   1. queueBuffer: slot 2 is current! 
   2. dequeueBuffer: buffer 0 is both FREE and current! 
   


Many thanks,
-Nathan Morse


On Wednesday, November 23, 2011 9:17:28 AM UTC-8, Romain Guy (Google) wrote:
>
> GLSurfaceView handles GL setup for you, which TextureView will not do. A 
> TextureView can be used as the native window when you create an EGL 
> surface. Here is an example (the interesting part is the call 
> to eglCreateWindowSurface()):
>
>     @Override
>     public void onSurfaceTextureAvailable(SurfaceTexture surface, int 
> width, int height) {
>         mRenderThread = new RenderThread(getResources(), surface);
>         mRenderThread.start();
>     }
>
>     private static class RenderThread extends Thread {
>         private static final String LOG_TAG = "GLTextureView";
>  
>         static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
>         static final int EGL_OPENGL_ES2_BIT = 4;
>
>         private volatile boolean mFinished;
>
>         private final Resources mResources;
>         private final SurfaceTexture mSurface;
>         
>         private EGL10 mEgl;
>         private EGLDisplay mEglDisplay;
>         private EGLConfig mEglConfig;
>         private EGLContext mEglContext;
>         private EGLSurface mEglSurface;
>         private GL mGL;
>
>         RenderThread(Resources resources, SurfaceTexture surface) {
>             mResources = resources;
>             mSurface = surface;
>         }
>
>         private static final String sSimpleVS =
>                 "attribute vec4 position;\n" +
>                 "attribute vec2 texCoords;\n" +
>                 "varying vec2 outTexCoords;\n" +
>                 "\nvoid main(void) {\n" +
>                 "    outTexCoords = texCoords;\n" +
>                 "    gl_Position = position;\n" +
>                 "}\n\n";
>         private static final String sSimpleFS =
>                 "precision mediump float;\n\n" +
>                 "varying vec2 outTexCoords;\n" +
>                 "uniform sampler2D texture;\n" +
>                 "\nvoid main(void) {\n" +
>                 "    gl_FragColor = texture2D(texture, outTexCoords);\n" +
>                 "}\n\n";
>
>         private static final int FLOAT_SIZE_BYTES = 4;
>         private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * 
> FLOAT_SIZE_BYTES;
>         private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0;
>         private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
>         private final float[] mTriangleVerticesData = {
>                 // X, Y, Z, U, V
>                 -1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
>                  1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
>                 -1.0f,  1.0f, 0.0f, 0.0f, 1.0f,
>                  1.0f,  1.0f, 0.0f, 1.0f, 1.0f,
>         };
>
>         @Override
>         public void run() {
>             initGL();
>             
>             FloatBuffer triangleVertices = 
> ByteBuffer.allocateDirect(mTriangleVerticesData.length
>                     * 
> FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer();
>             triangleVertices.put(mTriangleVerticesData).position(0);
>
>             int texture = loadTexture(R.drawable.large_photo);
>             int program = buildProgram(sSimpleVS, sSimpleFS);
>
>             int attribPosition = glGetAttribLocation(program, "position");
>             checkGlError();
>  
>             int attribTexCoords = glGetAttribLocation(program, 
> "texCoords");
>             checkGlError();
>
>             int uniformTexture = glGetUniformLocation(program, "texture");
>             checkGlError();
>
>             glBindTexture(GL_TEXTURE_2D, texture);
>             checkGlError();
>
>             glUseProgram(program);
>             checkGlError();
>
>             glEnableVertexAttribArray(attribPosition);
>             checkGlError();
>
>             glEnableVertexAttribArray(attribTexCoords);
>             checkGlError();
>
>             glUniform1i(uniformTexture, texture);
>             checkGlError();
>             
>             while (!mFinished) {
>                 checkCurrent();
>
>                 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
>                 checkGlError();
>
>                 glClear(GL_COLOR_BUFFER_BIT);
>                 checkGlError();
>
>                 // drawQuad
>                 
> triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
>                 glVertexAttribPointer(attribPosition, 3, GL_FLOAT, false,
>                         TRIANGLE_VERTICES_DATA_STRIDE_BYTES, 
> triangleVertices);
>
>                 
> triangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
>                 glVertexAttribPointer(attribTexCoords, 3, GL_FLOAT, false,
>                         TRIANGLE_VERTICES_DATA_STRIDE_BYTES, 
> triangleVertices);
>
>                 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
>
>                 if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
>                     throw new RuntimeException("Cannot swap buffers");
>                 }
>                 checkEglError();
>
>                 try {
>                     Thread.sleep(2000);
>                 } catch (InterruptedException e) {
>                     // Ignore
>                 }
>             }
>
>             finishGL();
>         }
>
>         private int loadTexture(int resource) {
>             int[] textures = new int[1];
>
>             glActiveTexture(GL_TEXTURE0);
>             glGenTextures(1, textures, 0);
>             checkGlError();
>
>             int texture = textures[0];
>             glBindTexture(GL_TEXTURE_2D, texture);
>             checkGlError();
>             
>             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 
> GL_LINEAR);
>             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, 
> GL_LINEAR);
>
>             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, 
> GL_CLAMP_TO_EDGE);
>             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 
> GL_CLAMP_TO_EDGE);
>
>             Bitmap bitmap = BitmapFactory.decodeResource(mResources, 
> resource);
>
>             GLUtils.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap, 
> GL_UNSIGNED_BYTE, 0);
>             checkGlError();
>
>             bitmap.recycle();
>
>             return texture;
>         }
>         
>         private int buildProgram(String vertex, String fragment) {
>             int vertexShader = buildShader(vertex, GL_VERTEX_SHADER);
>             if (vertexShader == 0) return 0;
>
>             int fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER);
>             if (fragmentShader == 0) return 0;
>
>             int program = glCreateProgram();
>             glAttachShader(program, vertexShader);
>             checkGlError();
>
>             glAttachShader(program, fragmentShader);
>             checkGlError();
>
>             glLinkProgram(program);
>             checkGlError();
>
>             int[] status = new int[1];
>             glGetProgramiv(program, GL_LINK_STATUS, status, 0);
>             if (status[0] != GL_TRUE) {
>                 String error = glGetProgramInfoLog(program);
>                 Log.d(LOG_TAG, "Error while linking program:\n" + error);
>                 glDeleteShader(vertexShader);
>                 glDeleteShader(fragmentShader);
>                 glDeleteProgram(program);
>                 return 0;
>             }
>
>             return program;
>         }
>         
>         private int buildShader(String source, int type) {
>             int shader = glCreateShader(type);
>
>             glShaderSource(shader, source);
>             checkGlError();
>
>             glCompileShader(shader);
>             checkGlError();
>
>             int[] status = new int[1];
>             glGetShaderiv(shader, GL_COMPILE_STATUS, status, 0);
>             if (status[0] != GL_TRUE) {
>                 String error = glGetShaderInfoLog(shader);
>                 Log.d(LOG_TAG, "Error while compiling shader:\n" + error);
>                 glDeleteShader(shader);
>                 return 0;
>             }
>             
>             return shader;
>         }
>
>         private void checkEglError() {
>             int error = mEgl.eglGetError();
>             if (error != EGL10.EGL_SUCCESS) {
>                 Log.w(LOG_TAG, "EGL error = 0x" + 
> Integer.toHexString(error));
>             }
>         }
>
>         private void checkGlError() {
>             int error = glGetError();
>             if (error != GL_NO_ERROR) {
>                 Log.w(LOG_TAG, "GL error = 0x" + 
> Integer.toHexString(error));
>             }
>          }
>
>         private void finishGL() {
>             mEgl.eglDestroyContext(mEglDisplay, mEglContext);
>             mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
>         }
>
>         private void checkCurrent() {
>             if (!mEglContext.equals(mEgl.eglGetCurrentContext()) ||
>                     
> !mEglSurface.equals(mEgl.eglGetCurrentSurface(EGL10.EGL_DRAW))) {
>                 if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, 
> mEglSurface, mEglContext)) {
>                     throw new RuntimeException("eglMakeCurrent failed "
>                             + 
> GLUtils.getEGLErrorString(mEgl.eglGetError()));
>                 }
>             }
>         }
>         
>         private void initGL() {
>             mEgl = (EGL10) EGLContext.getEGL();
>
>             mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
>             if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
>                 throw new RuntimeException("eglGetDisplay failed "
>                         + GLUtils.getEGLErrorString(mEgl.eglGetError()));
>             }
>             
>             int[] version = new int[2];
>             if (!mEgl.eglInitialize(mEglDisplay, version)) {
>                 throw new RuntimeException("eglInitialize failed " +
>                         GLUtils.getEGLErrorString(mEgl.eglGetError()));
>             }
>
>             mEglConfig = chooseEglConfig();
>             if (mEglConfig == null) {
>                 throw new RuntimeException("eglConfig not initialized");
>             }
>             
>             mEglContext = createContext(mEgl, mEglDisplay, mEglConfig);
>
>             mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, 
> mEglConfig, mSurface, null);
>
>             if (mEglSurface == null || mEglSurface == 
> EGL10.EGL_NO_SURFACE) {
>                 int error = mEgl.eglGetError();
>                 if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
>                     Log.e(LOG_TAG, "createWindowSurface returned 
> EGL_BAD_NATIVE_WINDOW.");
>                     return;
>                 }
>                 throw new RuntimeException("createWindowSurface failed "
>                         + GLUtils.getEGLErrorString(error));
>             }
>
>             if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, 
> mEglSurface, mEglContext)) {
>                 throw new RuntimeException("eglMakeCurrent failed "
>                         + GLUtils.getEGLErrorString(mEgl.eglGetError()));
>             }
>
>             mGL = mEglContext.getGL();
>         }
>         
>
>          EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, 
> EGLConfig eglConfig) {
>             int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2, 
> EGL10.EGL_NONE };
>             return egl.eglCreateContext(eglDisplay, eglConfig, 
> EGL10.EGL_NO_CONTEXT, attrib_list);            
>         }
>
>         private EGLConfig chooseEglConfig() {
>             int[] configsCount = new int[1];
>             EGLConfig[] configs = new EGLConfig[1];
>             int[] configSpec = getConfig();
>             if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, 
> configsCount)) {
>                 throw new IllegalArgumentException("eglChooseConfig failed 
> " +
>                         GLUtils.getEGLErrorString(mEgl.eglGetError()));
>             } else if (configsCount[0] > 0) {
>                 return configs[0];
>             }
>             return null;
>         }
>         
>         private int[] getConfig() {
>             return new int[] {
>                     EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
>                     EGL10.EGL_RED_SIZE, 8,
>                     EGL10.EGL_GREEN_SIZE, 8,
>                     EGL10.EGL_BLUE_SIZE, 8,
>                     EGL10.EGL_ALPHA_SIZE, 8,
>                     EGL10.EGL_DEPTH_SIZE, 0,
>                     EGL10.EGL_STENCIL_SIZE, 0,
>                     EGL10.EGL_NONE
>             };
>         }
>
>         void finish() {
>             mFinished = true;
>         }
>     }
>
> On Wed, Nov 23, 2011 at 8:54 AM, plafayette <pierre.lafaye...@gmail.com>wrote:
>
>> The TextureView documentation states that it can be used to render
>> OpenGL content.
>>
>> In the blog post announcing TextureView, it states:
>>
>> A TextureView can just as easily be used to embed an OpenGL scene in
>> your application. As of Android 4.0, eglCreateWindowSurface() can be
>> used to render into a SurfaceTexture object.
>>
>> Which seems to imply that to use TextureView instead of GLSurfaceView,
>> one would have to do all the EGL setup themselves and manage the
>> EGLContext and the threading (since GLSurfaceView maintains a
>> GLThread). There doesn't seem to be any sample code in the Android 4.0
>> SDK that demonstrates how the "TextureView can just as easily be used
>> to embed an OpenGL scene". TextureView seems to plug in more cleanly
>> to the Camera preview (setPreviewTexture) and MediaPlayer
>> (setSurface).
>>
>> Is it possible to use GLSurfaceView in conjunction with TextureView by
>> using GLSurfaceView.setEGLWindowSurfaceFactory to make it render to
>> the TextureView's SurfaceTexture?
>>
>> Again, it would be nice if there were some sample code.
>>
>> p.s. Posted on stackoverflow.com as well. Feel free to answer:
>>
>> http://stackoverflow.com/questions/8231978/how-to-replace-glsurfaceview-with-textureview-in-android-ice-cream-sandwich
>>
>> --
>> You received this message because you are subscribed to the Google
>> Groups "Android Developers" group.
>> To post to this group, send email to android-developers@googlegroups.com
>> To unsubscribe from this group, send email to
>> android-developers+unsubscr...@googlegroups.com
>> For more options, visit this group at
>> http://groups.google.com/group/android-developers?hl=en
>>
>
>
>
> -- 
> Romain Guy
> Android framework engineer
> romain...@android.com
>
>  

-- 
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to android-developers@googlegroups.com
To unsubscribe from this group, send email to
android-developers+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en

Reply via email to