¿Es dependiente de GPU de desarrollo de OpenGL?

Estoy desarrollando una aplicación android en opengl ES2.0.En esta aplicación he utilizado para dibujar múltiples líneas y círculos por evento táctil en GL surfaceView.

Como opengl depende de la GPU, actualmente funciona bien en Google Nexus 7 (ULP GeForce).

En Samsung Galaxy Note 2 (MALI 400MP) Estoy tratando de dibujar más de una línea, pero borra la línea anterior y dibujar la línea actual como nueva.

En Sony Xperia Neo V (Adreno 205) Estoy tratando de dibujar una nueva línea, se bloquea la superficie como se muestra en la imagen de abajo. Introduzca aquí la descripción de la imagen

¿Es posible hacerlo funcionar en todos los dispositivos o necesito escribir código para la GPU individual?


Código fuente

MainActivity.java

//in OnCreate method of my activity, i set the glsurfaceview and renderer final ActivityManager activityManager = ( ActivityManager ) getSystemService( Context.ACTIVITY_SERVICE ); final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo( ); final boolean supportsEs2 = ( configurationInfo.reqGlEsVersion >= 0x20000 || Build.FINGERPRINT.startsWith( "generic" ) ); if( supportsEs2 ) { Log.i( "JO", "configurationInfo.reqGlEsVersion:" + configurationInfo.reqGlEsVersion + "supportsEs2:" + supportsEs2 ); // Request an OpenGL ES 2.0 compatible context. myGlsurfaceView.setEGLContextClientVersion( 2 ); final DisplayMetrics displayMetrics = new DisplayMetrics( ); getWindowManager( ).getDefaultDisplay( ).getMetrics( displayMetrics ); // Set the renderer to our demo renderer, defined below. myRenderer = new MyRenderer( this, myGlsurfaceView ); myGlsurfaceView.setRenderer( myRenderer, displayMetrics.density ); myGlsurfaceView.setRenderMode( GLSurfaceView.RENDERMODE_CONTINUOUSLY ); MyGLSurfaceView.java //in this im getting the coordinates of my touch on the glSurfaceView to draw the line and //passing those points to the renderer class public MyGLsurfaceview( Context context ) { super( context ); Log.i( "JO", "MyGLsurfaceview1" ); } public MyGLsurfaceview( Context context, AttributeSet attrs ) { super( context, attrs ); con = context; mActivity = new MainActivity( ); mActivity.myGlsurfaceView = this; Log.i( "JO", "MyGLsurfaceview2" ); } public void setRenderer( MyRenderer renderer, float density ) { Log.i( "JO", "setRenderer" ); myRenderer = renderer; myDensity = density; mGestureDetector = new GestureDetector( con, mGestureListener ); super.setRenderer( renderer ); setRenderMode( GLSurfaceView.RENDERMODE_CONTINUOUSLY ); } @Override public boolean onTouchEvent( MotionEvent ev ) { boolean retVal = mGestureDetector.onTouchEvent( ev ); if( myline ) { switch ( ev.getAction( ) ) { case MotionEvent.ACTION_DOWN: isLUp = false; if( count == 1 ) { dx = ev.getX( ); dy = ev.getY( ); dx = ( dx / ( getWidth( ) / 2 ) ) - 1; dy = 1 - ( dy / ( getHeight( ) / 2 ) ); firstX = dx; firstY = dy; } else if( count == 2 ) { ux = ev.getX( ); uy = ev.getY( ); ux = ( ux / ( getWidth( ) / 2 ) ) - 1; uy = 1 - ( uy / ( getHeight( ) / 2 ) ); secondX = ux; secondY = uy; myRenderer.dx = firstX; myRenderer.dy = firstY; myRenderer.ux = secondX; myRenderer.uy = secondY; midX = ( firstX + secondX ) / 2; midY = ( firstY + secondY ) / 2; Log.e( "JO", "Line:firstX" + firstX + "firstY" + firstY ); lp = new LinePoints( firstX, firstY, secondX, secondY, midX, midY ); lineArray.add( lp ); myRenderer.isNewClick = false; myRenderer.isEnteredAngle = false; myRenderer.myline = true; myRenderer.mycircle = false; myRenderer.mydashedline = false; myRenderer.eraseCircle = false; myRenderer.eraseLine = false; myRenderer.eraseSelCir = false; myRenderer.angle = angle; myRenderer.length = length; requestRender( ); count = 0; } count++; break; case MotionEvent.ACTION_MOVE: isLUp = true; break; case MotionEvent.ACTION_UP: if( isLUp ) { ux = ev.getX( ); uy = ev.getY( ); ux = ( ux / ( getWidth( ) / 2 ) ) - 1; uy = 1 - ( uy / ( getHeight( ) / 2 ) ); Log.i( "JO", "line2:" + ux + "," + uy ); secondX = ux; secondY = uy; myRenderer.dx = firstX; myRenderer.dy = firstY; myRenderer.ux = secondX; myRenderer.uy = secondY; midX = ( firstX + secondX ) / 2; midY = ( firstY + secondY ) / 2; Log.e( "JO", "Line:firstX" + firstX + "firstY" + firstY ); lp = new LinePoints( firstX, firstY, secondX, secondY, midX, midY ); lineArray.add( lp ); myRenderer.isNewClick = false; myRenderer.isEnteredAngle = false; myRenderer.myline = true; myRenderer.mycircle = false; myRenderer.mydashedline = false; myRenderer.mysnaptoedge = false; myRenderer.mysnaptoMiddle = false; myRenderer.eraseCircle = false; myRenderer.eraseLine = false; myRenderer.eraseSelCir = false; count = 1; requestRender( ); } break; } } } } 

MyRenderer.java

 //renderer class to render the line to the glsurfaceview Lines line; public MyRenderer( MainActivity mainActivity, MyGLsurfaceview myGlsurfaceView ) { Log.i( "JO", "MyRenderer" ); this.main = mainActivity; myGlsurface = myGlsurfaceView; } public void onDrawFrame( GL10 gl ) { line.draw( dx, dy, ux, uy ); } @Override public void onSurfaceCreated( GL10 gl, EGLConfig config ) { Log.i( "JO", "onSurfaceCreated" ); // Set the background frame color GLES20.glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); // Create the GLText glText = new GLText( main.getAssets( ) ); // Load the font from file (set size + padding), creates the texture // NOTE: after a successful call to this the font is ready for // rendering! glText.load( "Roboto-Regular.ttf", 14, 2, 2 ); // Create Font (Height: 14 // Pixels / X+Y Padding // 2 Pixels) // enable texture + alpha blending GLES20.glEnable( GLES20.GL_BLEND ); GLES20.glBlendFunc( GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA ); } @Override public void onSurfaceChanged( GL10 gl, int width, int height ) { // Adjust the viewport based on geometry changes, // such as screen rotation GLES20.glViewport( 0, 0, width, height ); ratio = ( float ) width / height; width_surface = width; height_surface = height; /* * // this projection matrix is applied to object coordinates // in the * onDrawFrame() method Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, * -1, 1, 3, 7); */ // Take into account device orientation if( width > height ) { Matrix.frustumM( mProjMatrix, 0, -ratio, ratio, -1, 1, 1, 10 ); } else { Matrix.frustumM( mProjMatrix, 0, -1, 1, -1 / ratio, 1 / ratio, 1, 10 ); } // Save width and height this.width = width; // Save Current Width this.height = height; // Save Current Height int useForOrtho = Math.min( width, height ); // TODO: Is this wrong? Matrix.orthoM( mVMatrix, 0, -useForOrtho / 2, useForOrtho / 2, -useForOrtho / 2, useForOrtho / 2, 0.1f, 100f ); } 

Line.java

 //Line class to draw line public class Lines { final String vertexShaderCode = "attribute vec4 vPosition;" + "void main() {" + " gl_Position = vPosition;" + "}"; final String fragmentShaderCode = "precision mediump float;" + "uniform vec4 vColor;" + "void main() {" + " gl_FragColor = vColor;" + "}"; final FloatBuffer vertexBuffer; final int mProgram; int mPositionHandle; int mColorHandle; // number of coordinates per vertex in this array final int COORDS_PER_VERTEX = 3; float lineCoords[] = new float[6]; final int vertexCount = lineCoords.length / COORDS_PER_VERTEX; final int vertexStride = COORDS_PER_VERTEX * 4; // bytes per vertex // Set color with red, green, blue and alpha (opacity) values float lcolor[] = { 1.0f, 1.0f, 1.0f, 1.0f }; public Lines( ) { // initialize vertex byte buffer for shape coordinates ByteBuffer bb = ByteBuffer.allocateDirect( // (number of coordinate values * 4 bytes per float) lineCoords. length * 4 ); // use the device hardware's native byte order bb.order( ByteOrder.nativeOrder( ) ); // create a floating point buffer from the ByteBuffer vertexBuffer = bb.asFloatBuffer( ); // prepare shaders and OpenGL program int vertexShader = MyRenderer.loadShader( GLES20.GL_VERTEX_SHADER, vertexShaderCode ); int fragmentShader = MyRenderer.loadShader( GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode ); mProgram = GLES20.glCreateProgram( ); // create empty OpenGL Program GLES20.glAttachShader( mProgram, vertexShader ); // add the vertex shader // to program GLES20.glAttachShader( mProgram, fragmentShader ); // add the fragment // shader to program GLES20.glLinkProgram( mProgram ); // create OpenGL program executables } public void draw( float dX, float dY, float uX, float uY ) { lineCoords[0] = dX; lineCoords[1] = dY; lineCoords[2] = 0.0f; lineCoords[3] = uX; lineCoords[4] = uY; lineCoords[5] = 0.0f; Log.i( "JO", "lineCoords:" + lineCoords[0] + "," + lineCoords[1] + "," + lineCoords[3] + "," + lineCoords[4] ); vertexBuffer.put( lineCoords ); vertexBuffer.position( 0 ); // Add program to OpenGL environment GLES20.glUseProgram( mProgram ); // get handle to vertex shader's vPosition member mPositionHandle = GLES20.glGetAttribLocation( mProgram, "vPosition" ); // Enable a handle to the triangle vertices GLES20.glEnableVertexAttribArray( mPositionHandle ); // Prepare the triangle coordinate data GLES20.glVertexAttribPointer( mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer ); // get handle to fragment shader's vColor member mColorHandle = GLES20.glGetUniformLocation( mProgram, "vColor" ); // Set color for drawing the triangle GLES20.glUniform4fv( mColorHandle, 1, lcolor, 0 ); GLES20.glLineWidth( 3 ); // Draw the triangle GLES20.glDrawArrays( GLES20.GL_LINES, 0, vertexCount ); // Disable vertex array GLES20.glDisableVertexAttribArray( mPositionHandle ); } } 

Bueno, aquí va de nuevo: ^ 1

OpenGL no es un gráfico de escena. OpenGL no mantiene una escena, sabe sobre objetos o mantiene pistas de geometría. OpenGL es una API de dibujo . Usted le da un lienzo (en forma de una ventana o un PBuffer) y ordenarlo para dibujar puntos, líneas o triángulos y OpenGL hace exactamente eso. Una vez que se ha dibujado un primitivo (= punto, línea, triángulo), OpenGL no tiene ningún recuerdo de ello. Si algo cambia, tienes que volver a dibujarlo todo.

Los pasos apropiados para redibujar una escena son:

  1. Deshabilite la prueba de la plantilla, de modo que el siguiente paso opere en toda la ventana.

  2. Borrar el framebuffer usando glClear(bits) , donde bits es una máscara de bits que especifica qué partes del lienzo para borrar. Al representar un nuevo marco que desea borrar todo lo que los bits = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT bits = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT bits = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ;

  3. Establecer la ventana gráfica, crear una matriz de proyección apropiada

  4. Para cada objeto de la escena cargar la matriz de modelo de vista derecha, establecer uniformes, seleccionar los arrays de vértices y realizar la llamada de dibujo.

  5. Termine la representación mediante el lavado de la tubería. Si utiliza una única ventana de búfer glFinish() , si utiliza una ventana de búfer doble llamada SwapBuffers . En el caso de marcos de nivel superior esto puede ser realizado por el marco.

Importante Una vez que el dibujo se haya terminado en una ventana de doble búfer, no debe continuar enviando operaciones de dibujo, ya que realizando el intercambio de búfer, el contenido del búfer de fondo que está dibujando está indefinido. Por lo tanto, debe iniciar el dibujo de nuevo, comenzando por borrar el framebuffer (pasos 1 y 2).

Lo que pierde su código son exactamente esos dos pasos. También tengo la impresión de que está realizando llamadas de dibujo OpenGL en reacción directa a los eventos de entrada, posiblemente en los handlers de eventos de entrada por sí mismo. ¡No lo hagas! . En su lugar, utilice los eventos de entrada para agregar a una lista de primitivas (líneas en su caso) para dibujar y, a continuación, enviar un evento de redibujo, lo que hace que el marco de llamar a la función de dibujo. En la función de dibujo itera sobre esa lista para dibujar las líneas deseadas.

Redibujar toda la escena es canónico en OpenGL!


[1] (geesh, me estoy cansando de tener que escribir esto cada 3 ª pregunta o menos …)

Tomando un punt aquí, pero ¿estás realmente limpiar la pantalla? Los tipos de comportamiento que está viendo sugieren que no lo son, y que en diferentes escenarios están viendo diferentes errores: memoria no inicializada, reutilización de un antiguo buffer, borrado implícito, etc.

GL requiere que sea específico acerca de lo que quiere, por lo que necesita borrar explícitamente.

OpenGL es sólo un estándar. La implementación real de la API es hasta el fabricante de la tarjeta gráfica. Así que sí, el desarrollo de OpenGL puede ser dependiente de la GPU a veces. Sin embargo, todas las implementaciones deben proporcionar el mismo resultado (lo que sucede detrás de las escenas puede ser realmente diferente). Si su código da un resultado diferente con diferentes GPUs, es probable que haya una diferencia de versión en la implementación de OpenGL.

Puede utilizar estas funciones para obtener la versión compatible de OpenGL:

 glGetIntegerv​(GL_MAJOR_VERSION​, *); //version 3.0+ glGetIntegerv​(GL_MINOR_VERSION​, *); //version 3.0+ glGetString​(GL_VERSION​); //all versions 
  1. ¿Por qué no proporciona un ejemplo de trabajo , para que la gente realmente pueda ayudar?

  2. De tu código: ¿No puedo ver dónde creas tu línea? Algo como:

     @Override public void onSurfaceCreated(GL10 gl, EGLConfig config){ ... mLine = new Lines(); ... } 
  3. Como ya se ha mencionado, en onDrawFrame siempre borre el búfer:

     public void onDrawFrame(GL10 gl ) { // Erase CL_COLOR_BUFFER GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 
  4. Ajuste la cámara:

     // Set the camera position (View matrix) Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 3, 0f, 0f, 0f, 0f, 1.0f, 0.0f); // // Calculate the projection and view transformation Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mViewMatrix, 0); 
  5. Dibujar:

     line.draw( dx, dy, ux, uy ); 

Crossposted de mi respuesta a una pregunta similar ¿ Por qué mi salida opengl difiere para varios dispositivos? :

¿Deberíamos tener en cuenta la GPU mientras codifica? De ninguna manera, la API de OpenGL es una capa entre su aplicación y el hardware.

Esto es en gran medida correcto para gráficos de escritorio ya que todas las GPUs son renderizadores inmediatos, sin embargo, esto NO es el caso en los gráficos para móviles.

Las GPUs de Mali usan renderizado de modo inmediato basado en azulejos. Para este tipo de renderizado, el framebuffer se divide en fichas de tamaño 16 por 16 píxeles. El Generador de listas de polígonos (PLB) organiza los datos de entrada de la aplicación en listas de polígonos. Hay una lista de polígonos para cada mosaico. Cuando una primitiva cubre parte de un mosaico, se agrega una entrada, llamada un comando de lista de polígonos, a la lista de polígonos del mosaico. El procesador de píxeles toma la lista de polígonos de una baldosa y calcula los valores de todos los píxeles de esa baldosa antes de comenzar a trabajar en la baldosa siguiente. Debido a que este enfoque basado en azulejos utiliza un buffer de mosaico rápido en el chip, la GPU sólo escribe el contenido del buffer de mosaico en el framebuffer de la memoria principal al final de cada mosaico. Los procesadores de modo inmediato no basados ​​en mosaicos generalmente requieren muchos más accesos framebuffer. Por lo tanto, el método basado en azulejos consume menos ancho de banda de memoria y soporta operaciones como pruebas de profundidad, mezcla y anti-aliasing de manera eficiente.

Otra diferencia es el tratamiento de los búferes renderizados. Los renderizadores inmediatos "guardarán" el contenido de su búfer, permitiéndole efectivamente dibujar solamente diferencias en la escena rendida encima de qué había existido previamente. Esto está disponible en Malí, sin embargo, no está habilitado de forma predeterminada ya que puede causar efectos no deseados si se usa incorrectamente.

Hay un ejemplo de Mali GLES2 SDK sobre cómo usar "EGL Preserve" correctamente disponible en el SDK de GLES2 aquí

La razón por la que el nexo 7 de Geforce basado en la ULP funciona como se pretende es que, como renderizador de base inmediata, prefiere conservar los búferes, mientras que Malí no lo hace.

De la especificación Khronos EGL:

EGL_SWAP_BEHAVIOR

Especifica el efecto en el búfer de color de publicar una superficie con eglSwapBuffers. Un valor de EGL_BUFFER_PRESERVED indica que el contenido del buffer de color no se ve afectado, mientras que EGL_BUFFER_DESTROYED indica que el contenido del buffer de color puede ser destruido o modificado por la operación.

El valor inicial de EGL_SWAP_BEHAVIOR es elegido por la implementación.

El valor predeterminado para EGL_SWAP_BEHAVIOUR en la plataforma de Mali es EGL_BUFFER_DESTROYED. Esto se debe al rendimiento de golpe asociado con tener que buscar el buffer anterior de la memoria antes de renderizar el nuevo marco, y almacenarlo al final, así como el consumo de ancho de banda (que también es increíblemente malo para la vida de la batería en los dispositivos móviles). No puedo comentar con certeza en cuanto al comportamiento por defecto de los SoCs de Tegra sin embargo, me parece que su defecto es EGL_BUFFER_PRESERVED.

Para aclarar la posición de Malí con respecto a las especificaciones de Glos de Khronos – Malí es completamente obediente.

  • ¿Cómo aprender y usar OpenGL ES 2.0? Simplemente no lo entiendo - Qn serio.
  • ¿Es posible renderizar / sombrear diferido con OpenGL ES 2.0?
  • GLSurfaceView que muestra negro en Nexus 7 con Android 4.2
  • Cómo salvar SurfaceTexture como bitmap
  • Point sprite desaparece en el borde de la pantalla en mi Galaxy S4 (no en el Nexus 7)
  • La textura de OpenGL no sigue la geometría
  • Pasando varias texturas a shader en LibGDX
  • Bucle liso del juego del androide
  • Escena de OpenGL con fondo transparente + widgets nativos por debajo y por encima
  • Cómo utilizar la cámara con Android OpenGL ES para trabajar?
  • Android OpenGL ES Soporte en todas partes?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.