2016-09-16 2 views
1

Problem.
Ich habe ein Problem mit bestimmten Android-Geräten. Ich verwende die native C++ - Bibliothek, um Dinge in meiner App zu zeichnen. Die von mir verwendete Lösung funktionierte lange Zeit auf verschiedenen Geräten, bis ich vom Samsung Galaxy S4-Nutzer (GT-I9500, Android 4.4.2, Exynos 5410) eine negative Rückmeldung erhielt. Das Ergebnis meiner OpenGL-Zeichnung war beschädigt. Die Textur, die in diesem Fall normalerweise Vollbild zeichnet, wurde auf ein Viertel des Bildschirmbereichs verkleinert und auf die obere rechte Ecke ausgerichtet. Der mit glClearColor gezeichnete Hintergrund füllte den ganzen Bildschirm.
Ich konnte auf drei anderen S4s überprüfen - von insgesamt vier Handys meiner App ist die Zeichnung nur auf Exynos-Geräten beschädigt. Die anderen beiden hatten Snapdragon und es gab keine Probleme mit ihnen.
Android: OpenGL Zeichnung nur auf einem Viertel des Bildschirms auf Exynos Geräten

Code.
Ich habe den Code ein wenig vereinfacht, damit ich es hier zeigen kann. Die Aufgabe ist einfach: Zeichnen Sie roten Hintergrund und schwarzes Vollbild-Rechteck darüber.
Unten können Sie meine Zeichnungsmethode sehen. Daten, die ich an die Shader übergebe, haben in diesem vereinfachten Fall keine Auswirkungen.

// Use program 
glUseProgram(_shaderProgram); 
ERROR_STATUS 
//bind quad mesh buffer 
glBindBuffer(GL_ARRAY_BUFFER, _vbo); 
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ibo); 
ERROR_STATUS 

//set attribs 
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0); 
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *) (2 * sizeof(float))); 
glEnableVertexAttribArray(0); 
glEnableVertexAttribArray(1); 
ERROR_STATUS 

// Clear background to red 
glClear(GL_COLOR_BUFFER_BIT); 
glClearColor(1, 0, 0, 1); 

glUniform2fv(_scaleUniform, 1, _eyes[0].scale.data); 
glUniform1f(_offsetUniform, _eyes[0].offset); 
glUniform1f(_offsetYUniform, _eyes[0].offsetY); 

BindTextures(TEX); 

// Draw 
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, NULL); 
ERROR_STATUS 

glDisableVertexAttribArray(0); 
glDisableVertexAttribArray(1); 
ERROR_STATUS 


Und hier ist mein ConfigChooser (grafika war eine große Hilfe hier).

private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser { 

    public ConfigChooser(int r, int g, int b, int a, int depth, int stencil) { 
     mRedSize = r; 
     mGreenSize = g; 
     mBlueSize = b; 
     mAlphaSize = a; 
     mDepthSize = depth; 
     mStencilSize = stencil; 
    } 

    /* This EGL config specification is used to specify 2.0 rendering. 
    * We use a minimum size of 4 bits for red/green/blue, but will 
    * perform actual matching in chooseConfig() below. 
    */ 
    private static int EGL_OPENGL_ES2_BIT = 4; 
    private static int[] s_configAttribs2 = 
    { 
     EGL10.EGL_RED_SIZE, 4, 
     EGL10.EGL_GREEN_SIZE, 4, 
     EGL10.EGL_BLUE_SIZE, 4, 
     EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 
     EGL10.EGL_NONE 
    }; 

    public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { 

     /* Get the number of minimally matching EGL configurations 
     */ 
     int[] num_config = new int[1]; 
     egl.eglChooseConfig(display, s_configAttribs2, null, 0, num_config); 

     int numConfigs = num_config[0]; 

     if (numConfigs <= 0) { 
      throw new IllegalArgumentException("No configs match configSpec"); 
     } 

     /* Allocate then read the array of minimally matching EGL configs 
     */ 
     EGLConfig[] configs = new EGLConfig[numConfigs]; 
     egl.eglChooseConfig(display, s_configAttribs2, configs, numConfigs, num_config); 

     if (DEBUG) { 
      printConfigs(egl, display, configs); 
     } 
     /* Now return the "best" one 
     */ 
     return chooseConfig(egl, display, configs); 
    } 

    public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, 
      EGLConfig[] configs) { 
     for(EGLConfig config : configs) { 
      int d = findConfigAttrib(egl, display, config, 
        EGL10.EGL_DEPTH_SIZE, 0); 
      int s = findConfigAttrib(egl, display, config, 
        EGL10.EGL_STENCIL_SIZE, 0); 

      // We need at least mDepthSize and mStencilSize bits 
      if (d < mDepthSize || s < mStencilSize) 
       continue; 

      // We want an *exact* match for red/green/blue/alpha 
      int r = findConfigAttrib(egl, display, config, 
        EGL10.EGL_RED_SIZE, 0); 
      int g = findConfigAttrib(egl, display, config, 
         EGL10.EGL_GREEN_SIZE, 0); 
      int b = findConfigAttrib(egl, display, config, 
         EGL10.EGL_BLUE_SIZE, 0); 
      int a = findConfigAttrib(egl, display, config, 
        EGL10.EGL_ALPHA_SIZE, 0); 

      if (r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize) 
       return config; 
     } 
     return null; 
    } 

    private int findConfigAttrib(EGL10 egl, EGLDisplay display, 
      EGLConfig config, int attribute, int defaultValue) { 

     if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) { 
      return mValue[0]; 
     } 
     return defaultValue; 
    } 

    private void printConfigs(EGL10 egl, EGLDisplay display, 
     EGLConfig[] configs) { 
     int numConfigs = configs.length; 
     Log.w(TAG, String.format("%d configurations", numConfigs)); 
     for (int i = 0; i < numConfigs; i++) { 
      Log.w(TAG, String.format("Configuration %d:\n", i)); 
      printConfig(egl, display, configs[i]); 
     } 
    } 

    private void printConfig(EGL10 egl, EGLDisplay display, 
      EGLConfig config) { 
     int[] attributes = { 
       EGL10.EGL_BUFFER_SIZE, 
       EGL10.EGL_ALPHA_SIZE, 
       EGL10.EGL_BLUE_SIZE, 
       EGL10.EGL_GREEN_SIZE, 
       EGL10.EGL_RED_SIZE, 
       EGL10.EGL_DEPTH_SIZE, 
       EGL10.EGL_STENCIL_SIZE, 
       EGL10.EGL_CONFIG_CAVEAT, 
       EGL10.EGL_CONFIG_ID, 
       EGL10.EGL_LEVEL, 
       EGL10.EGL_MAX_PBUFFER_HEIGHT, 
       EGL10.EGL_MAX_PBUFFER_PIXELS, 
       EGL10.EGL_MAX_PBUFFER_WIDTH, 
       EGL10.EGL_NATIVE_RENDERABLE, 
       EGL10.EGL_NATIVE_VISUAL_ID, 
       EGL10.EGL_NATIVE_VISUAL_TYPE, 
       0x3030, // EGL10.EGL_PRESERVED_RESOURCES, 
       EGL10.EGL_SAMPLES, 
       EGL10.EGL_SAMPLE_BUFFERS, 
       EGL10.EGL_SURFACE_TYPE, 
       EGL10.EGL_TRANSPARENT_TYPE, 
       EGL10.EGL_TRANSPARENT_RED_VALUE, 
       EGL10.EGL_TRANSPARENT_GREEN_VALUE, 
       EGL10.EGL_TRANSPARENT_BLUE_VALUE, 
       0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB, 
       0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA, 
       0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL, 
       0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL, 
       EGL10.EGL_LUMINANCE_SIZE, 
       EGL10.EGL_ALPHA_MASK_SIZE, 
       EGL10.EGL_COLOR_BUFFER_TYPE, 
       EGL10.EGL_RENDERABLE_TYPE, 
       0x3042 // EGL10.EGL_CONFORMANT 
     }; 
     String[] names = { 
       "EGL_BUFFER_SIZE", 
       "EGL_ALPHA_SIZE", 
       "EGL_BLUE_SIZE", 
       "EGL_GREEN_SIZE", 
       "EGL_RED_SIZE", 
       "EGL_DEPTH_SIZE", 
       "EGL_STENCIL_SIZE", 
       "EGL_CONFIG_CAVEAT", 
       "EGL_CONFIG_ID", 
       "EGL_LEVEL", 
       "EGL_MAX_PBUFFER_HEIGHT", 
       "EGL_MAX_PBUFFER_PIXELS", 
       "EGL_MAX_PBUFFER_WIDTH", 
       "EGL_NATIVE_RENDERABLE", 
       "EGL_NATIVE_VISUAL_ID", 
       "EGL_NATIVE_VISUAL_TYPE", 
       "EGL_PRESERVED_RESOURCES", 
       "EGL_SAMPLES", 
       "EGL_SAMPLE_BUFFERS", 
       "EGL_SURFACE_TYPE", 
       "EGL_TRANSPARENT_TYPE", 
       "EGL_TRANSPARENT_RED_VALUE", 
       "EGL_TRANSPARENT_GREEN_VALUE", 
       "EGL_TRANSPARENT_BLUE_VALUE", 
       "EGL_BIND_TO_TEXTURE_RGB", 
       "EGL_BIND_TO_TEXTURE_RGBA", 
       "EGL_MIN_SWAP_INTERVAL", 
       "EGL_MAX_SWAP_INTERVAL", 
       "EGL_LUMINANCE_SIZE", 
       "EGL_ALPHA_MASK_SIZE", 
       "EGL_COLOR_BUFFER_TYPE", 
       "EGL_RENDERABLE_TYPE", 
       "EGL_CONFORMANT" 
     }; 
     int[] value = new int[1]; 
     for (int i = 0; i < attributes.length; i++) { 
      int attribute = attributes[i]; 
      String name = names[i]; 
      if (egl.eglGetConfigAttrib(display, config, attribute, value)) { 
       Log.w(TAG, String.format(" %s: %d\n", name, value[0])); 
      } else { 
       // Log.w(TAG, String.format(" %s: failed\n", name)); 
       while (egl.eglGetError() != EGL10.EGL_SUCCESS); 
      } 
     } 
    } 

    // Subclasses can adjust these values: 
    protected int mRedSize; 
    protected int mGreenSize; 
    protected int mBlueSize; 
    protected int mAlphaSize; 
    protected int mDepthSize; 
    protected int mStencilSize; 
    private int[] mValue = new int[1]; 
} 


Ich lege es mit setEGLConfigChooser(new ConfigChooser(5, 6, 5, 0, 0, 0)).
Kontext Fabrik:

private static class ContextFactory implements GLSurfaceView.EGLContextFactory { 
    private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098; 
    public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) { 
     Log.w(TAG, "creating OpenGL ES 2.0 context"); 
     checkEglError("Before eglCreateContext", egl); 
     int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE }; 
     EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); 
     checkEglError("After eglCreateContext", egl); 
     return context; 
    } 

    public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) { 
     egl.eglDestroyContext(display, context); 
    } 
} 

ich andere Teile meines Code bei Bedarf zur Verfügung stellen kann.

Ergebnisse.
Während die üblichen, gültiges Ergebnis nur schwarzer Bildschirm (die schwarze, leere Textur der roten Hintergrund überlappend), auf S4 Exynos sieht der Bildschirm wie folgt (der Pfeil auf der rechten Seite ist nur System-Taste):

enter image description here

Also hier ist die Frage. Wie behebt man das Problem, so dass die App das gleiche zeigt verschiedene Geräte?

+0

@RawN Erledigt. Das C++ - Tag wurde vorgeschlagen, deshalb habe ich es ausgewählt. –

+1

Könnte eine Anzahl von Dingen sein, wahrscheinlich in Code, der hier nicht gezeigt wird. Stellen Sie beispielsweise sicher, dass die Scheitelpunktattribute wirklich an den Positionen 0 und 1 liegen? –

+0

@RetoKoradi Danke!Das war das Problem - den Speicherort der Attribute zu speichern und sie anstelle der fixierten zu verwenden. Entschuldigung für verspätete Antwort, ich konnte es bis heute nicht überprüfen. –

Antwort

0

Ich konnte meinen Code dank RetoKoradi Vorschlag beheben.
Das Problem war, dass ich feste Standorte von Uniformen in Shadern (0 und 1) verwendet habe. Ich bin mir nicht sicher, warum das bei den meisten Geräten funktioniert und bei manchen nicht.

Anstatt also Anrufe wie:

glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0); 
glEnableVertexAttribArray(0); 

ich jetzt bin mit:

_posAttribLocation = glGetAttribLocation(_shaderProgram, "a_position"); 

Lage einheitlicher zu speichern, nachdem Shader-Programm bereit ist und es statt Fixe mit:

glVertexAttribPointer(_posAttribLocation, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0); 
glEnableVertexAttribArray(_posAttribLocation);