GLSurfaceView onDrawFrame清算行为 [英] GLSurfaceView onDrawFrame clearing behavior

查看:238
本文介绍了GLSurfaceView onDrawFrame清算行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我跑进与GLSurfaceView不同的行为。
AFAIK它是程序清除缓冲器(颜色和深度)每个帧的责任。这意味着,如果我不清除缓冲区我得到的最后一帧(或一前,对于双缓冲)的内容。

看来虽然好像缓冲区无论什么清除某些设备上。我跑了你好三角计划的以下修改从不同结果一些测试设备Addison Wesley出版OpenglES2.0编程指南:


  • 宏碁Iconia A500(4.0.3):不可以清除(预​​期的行为)

  • 索尼XPERIA围棋(4.0.4):清除

  • 银河S3(4.1.1):清除

  • LG擎天柱4X HD(4.0.3):不可以清除

  • 三星Galaxy Tab 20.1(4.0.4):不可以清除

  • 摩托罗拉Xoom(3.2):不可以清除

  • 银河S2(4.1.2 - 植根):清除

有没有办法来强制得到一个不变的缓冲区每次抽签回调?

与清除屏幕上的设备,结果如下:

该测试活动是这样的:

 包com.example.glcleartest;进口java.nio.Buffer中;
进口java.nio.ByteBuffer中;
进口java.nio.ByteOrder中;
进口java.nio.FloatBuffer中;进口javax.microedition.khronos.egl.EGLConfig;
进口javax.microedition.khronos.opengles.GL10;进口android.opengl.GLES20;
进口android.opengl.GLSurfaceView;
进口android.opengl.GLSurfaceView.Renderer;
进口android.os.Bundle;
进口android.app.Activity;
进口android.util.Log;公共类MainActivity延伸活动{受保护的静态最终诠释为num_vertices = 3;@覆盖
保护无效的onCreate(捆绑savedInstanceState){
    super.onCreate(savedInstanceState);
    的setContentView(R.layout.activity_main);    GLSurfaceView glview =(GLSurfaceView)findViewById(R.id.glview);
    glview.setEGLConfigChooser(假);
    glview.setEGLContextClientVersion(2);
    glview.setRenderer(新渲染器(){        私人诠释programObject;
        私人FloatBuffer vertexBuffer;        @覆盖
        公共无效onSurfaceCreated(GL10 GL,EGLConfig配置){
        }        @覆盖
        公共无效onSurfaceChanged(GL10 GL,诠释的宽度,高度INT){
            GLES20.glViewport(0,0,宽度,高度);
            在里面();
        }        @覆盖
        公共无效onDrawFrame(GL10 GL){
            浮动X = 0.1F *(浮点)Math.sin(System.currentTimeMillis的()/ 1000.0);
            浮动[] = vVertices新的浮动[] {X,0.5F,0.0,
                    的X 0.5F,-0.5f,0.0,
                    X + 0.5F,-0.5f,0.0};
            vertexBuffer.rewind();
            vertexBuffer.put(vVertices);
            vertexBuffer.rewind();
            //使用程序对象
            GLES20.glUseProgram(programObject);
            INT手柄= GLES20.glGetUniformLocation(programObjectuColor);
            浮动R =(浮点)(0.5F + Math.sin(System.currentTimeMillis的()/ 1000.0));
            浮G =(浮点)(0.5F + Math.sin(System.currentTimeMillis的()/ 300.0));
            GLES20.glUniform4f(手柄,R,G,0,1);            //加载顶点数据
            GLES20.glVertexAttribPointer(0,3,GLES20.GL_FLOAT,假,0,vertexBuffer);
            GLES20.glEnableVertexAttribArray(0);
            GLES20.glDrawArrays(GLES20.GL_TRIANGLES,0,3);
        }        私人无效错误(String s)将{
            Log.e(GLTEST,S);
        }        私人诠释loadShader(INT shaderType,弦乐源){
            如果(shaderType = GLES20.GL_FRAGMENT_SHADER和放大器;!&安培;!shaderType = GLES20.GL_VERTEX_SHADER){
                抛出新的RuntimeException(非法着色器类型);
            }            INT着色器= GLES20.glCreateShader(shaderType);
            如果(着色!= 0){
                GLES20.glShaderSource(着色器,源);
                GLES20.glCompileShader(着色器);
                INT []编译=新INT [1];
                GLES20.glGetShaderiv(着色,GLES20.GL_COMPILE_STATUS,编译,0);
                如果(编译[0] == 0){
                    错误(无法编译着色器:);
                    错误(GLES20.glGetShaderInfoLog(着色));
                    GLES20.glDeleteShader(着色器);
                    着色器= 0;
                    抛出新的RuntimeException(语法着色器/编译错误);
                }
            }
            返回着色器;
        }        私人无效的init(){
            字符串vShaderStr =属性vec4 vPosition; \\ n+
                                    无效的主要()\\ n+{\\ n+
                                    GL_POSITION = vPosition; \\ n+
                                    } \\ n;
            字符串fShaderStr =precision mediump浮动; \\ n+
                                        统一vec4 uColor; +
                                        无效的主要()\\ n+
                                        {\\ n+
                                        gl_FragColor = uColor; \\ n+
                                        } \\ n;            的ByteBuffer VBB = ByteBuffer.allocateDirect(为num_vertices * 3 * 4);
            vbb.order(ByteOrder.nativeOrder());
            vertexBuffer = vbb.asFloatBuffer();            INT vertexShader;
            INT fragmentShader;            //加载顶点/片段着色
            vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,vShaderStr);
            fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,fShaderStr);            //创建程序对象
            programObject = GLES20.glCreateProgram();
            如果(programObject == 0)
                返回;            GLES20.glAttachShader(programObject,vertexShader);
            GLES20.glAttachShader(programObject,fragmentShader);
            //绑定vPosition归因0
            GLES20.glBindAttribLocation(programObject,0,vPosition);
            //链接程序
            GLES20.glLinkProgram(programObject);
            INT [] linkStatus =新INT [1];
            GLES20.glGetProgramiv(programObject,GLES20.GL_LINK_STATUS,linkStatus,0);            如果(linkStatus [0]!= GLES20.GL_TRUE){
                错误(无法链接程序:);
                错误(GLES20.glGetProgramInfoLog(programObject));
                GLES20.glDeleteProgram(programObject);
                programObject = 0;
            }
        }
    });
}
}


解决方案

如果你想让你的后备缓冲区的内容交换后,你必须设置的 EGL_SWAP_BEHAVIOR 属性您互换表面 EGL_BUFFER_ preSERVED ,由的 EGL API 。的确意识到尽管这在大多数平台上,这将是一个相当的的性能损失。你刚才关闭重绘在大多数情况下框架要好得多。

对于一些历史:见 http://www.khronos.org /registry/egl/specs/EGLTechNote0001.html

I ran into different behaviors with the GLSurfaceView. AFAIK it is the responsibility of the program to clear the buffer (color and depth ) each frame. Which means that if I don't clear the buffer I get the content of the last frame ( or the one before that for double buffering ).

It seems though as if the buffer is cleared no matter what on some devices. I ran the following modification of the "Hello Triangle" program from the Addison Wesley OpenglES2.0 Programming Guide on some test devices with different results:

  • Acer Iconia A500 (4.0.3): not cleared (expected behavior)
  • Sony XPERIA Go (4.0.4): cleared
  • Galaxy S3 (4.1.1): cleared
  • LG Optimus 4x HD (4.0.3): not cleared
  • Samsung Galaxy Tab 20.1 (4.0.4): not cleared
  • Motorola Xoom ( 3.2): not cleared
  • Galaxy S2 (4.1.2 - rooted): cleared

Is there a way to force getting an unchanged buffer with each draw callback?

The result for the devices with cleared screen looks like this:

The test activity looks like this:

package com.example.glcleartest;

import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.GLSurfaceView.Renderer;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;

public class MainActivity extends Activity {

protected static final int NUM_VERTICES = 3;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    GLSurfaceView glview = (GLSurfaceView) findViewById(R.id.glview);
    glview.setEGLConfigChooser(false);
    glview.setEGLContextClientVersion(2);
    glview.setRenderer(new Renderer() {

        private int programObject;
        private FloatBuffer vertexBuffer;

        @Override
        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        }

        @Override
        public void onSurfaceChanged(GL10 gl, int width, int height) {
            GLES20.glViewport(0, 0, width, height);
            init();
        }

        @Override
        public void onDrawFrame(GL10 gl) {
            float x = 0.1f*(float) Math.sin(System.currentTimeMillis()/1000.0);
            float[] vVertices = new float[]{x, 0.5f, 0.0f,
                    x-0.5f, -0.5f, 0.0f,
                    x+0.5f, -0.5f, 0.0f};
            vertexBuffer.rewind();
            vertexBuffer.put(vVertices);
            vertexBuffer.rewind();


            // Use the program object
            GLES20.glUseProgram(programObject);
            int handle = GLES20.glGetUniformLocation(programObject, "uColor");
            float r = (float) (0.5f+Math.sin(System.currentTimeMillis()/1000.0));
            float g = (float) (0.5f+Math.sin(System.currentTimeMillis()/300.0));
            GLES20.glUniform4f(handle, r, g,0,1);

            // Load the vertex data
            GLES20.glVertexAttribPointer(0, 3, GLES20.GL_FLOAT, false, 0, vertexBuffer);
            GLES20.glEnableVertexAttribArray(0);
            GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);             
        }

        private void error(String s) {
            Log.e("GLTEST", s);
        }

        private int loadShader(int shaderType, String source) {
            if (shaderType != GLES20.GL_FRAGMENT_SHADER && shaderType != GLES20.GL_VERTEX_SHADER) {
                throw new RuntimeException("Illegal shader type");
            }

            int shader = GLES20.glCreateShader(shaderType);
            if (shader != 0) {
                GLES20.glShaderSource(shader, source);
                GLES20.glCompileShader(shader);
                int[] compiled = new int[1];
                GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
                if (compiled[0] == 0) {
                    error("Could not compile shader :");
                    error(GLES20.glGetShaderInfoLog(shader));
                    GLES20.glDeleteShader(shader);
                    shader = 0;
                    throw new RuntimeException("Shader Syntax / compilation error");
                }
            }
            return shader;
        }

        private void init() {
            String vShaderStr = "attribute vec4 vPosition; \n" + 
                                    "void main() \n" + "{ \n" + 
                                    " gl_Position = vPosition; \n" + 
                                    "} \n";
            String fShaderStr = "precision mediump float; \n" +
                                        "uniform vec4 uColor;" +
                                        "void main() \n" + 
                                        "{ \n" + 
                                        " gl_FragColor = uColor; \n" + 
                                        "} \n";

            ByteBuffer vbb = ByteBuffer.allocateDirect(NUM_VERTICES*3*4);
            vbb.order(ByteOrder.nativeOrder());
            vertexBuffer = vbb.asFloatBuffer();

            int vertexShader;
            int fragmentShader;

            // Load the vertex/fragment shaders
            vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vShaderStr);
            fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fShaderStr);

            // Create the program object
            programObject = GLES20.glCreateProgram();
            if (programObject == 0)
                return;

            GLES20.glAttachShader(programObject, vertexShader);
            GLES20.glAttachShader(programObject, fragmentShader);
            // Bind vPosition to attribute 0
            GLES20.glBindAttribLocation(programObject, 0, "vPosition");
            // Link the program
            GLES20.glLinkProgram(programObject);
            int[] linkStatus = new int[1];
            GLES20.glGetProgramiv(programObject, GLES20.GL_LINK_STATUS, linkStatus, 0);

            if (linkStatus[0] != GLES20.GL_TRUE) {
                error("Could not link program: ");
                error(GLES20.glGetProgramInfoLog(programObject));
                GLES20.glDeleteProgram(programObject);
                programObject = 0;
            }
        }
    });
}
}

解决方案

If you want to keep your backbuffer contents after swapping, you have to set the EGL_SWAP_BEHAVIOR attribute of your swap surface to EGL_BUFFER_PRESERVED, as documented by the EGL API. Do realize though that on most platforms, this will be a fairly large performance hit. You're much better off just redrawing the frame in most cases.

For a bit of history: see http://www.khronos.org/registry/egl/specs/EGLTechNote0001.html

这篇关于GLSurfaceView onDrawFrame清算行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆