OpenGL ES

O Android inclui suporte a gráficos 2D e 3D de alto desempenho com a Open Graphics Library (OpenGL®), especificamente, a API OpenGL ES. O OpenGL é uma API gráfica multiplataforma que especifica uma interface de software padrão para hardware de processamento de gráficos 3D. OpenGL ES é uma variação da especificação OpenGL destinada a dispositivos incorporados. O Android oferece suporte a várias versões da API OpenGL ES:

  • OpenGL ES 2.0 – esta especificação da API é compatível com o Android 2.2 (API de nível 8) e versões mais recentes.
  • OpenGL ES 3.0 – esta especificação da API é compatível com o Android 4.3 (API de nível 18) e versões mais recentes.
  • OpenGL ES 3.1: essa especificação da API é compatível com o Android 5.0 (nível 21 da API) e versões mais recentes.
  • OpenGL ES 3.2 – esta especificação da API é compatível com o Android 7.0 (nível 24 da API) e versões mais recentes.

Cuidado:independentemente da versão da plataforma Android, um dispositivo não é compatível com a API OpenGL ES 3.0, a menos que o fabricante forneça uma implementação desse pipeline de gráficos. Se você especificar no manifesto que o OpenGL ES 3.0 é necessário, poderá ter certeza de que essa versão estará presente no dispositivo. Se você especificar que uma versão de nível inferior é necessária, mas quiser usar os recursos 3.0, se estiverem disponíveis, verifique no ambiente de execução para saber qual versão do OpenGL o dispositivo oferece suporte. Para saber mais sobre como fazer isso, consulte Verificar a versão do OpenGL ES.

Observação:o Android inclui suporte ao OpenGL ES 1.0 e 1.1, mas essas versões da API foram descontinuadas e não podem ser usadas por aplicativos modernos.

Observação:a API específica fornecida pelo framework do Android é semelhante à API J2ME JSR239 OpenGL ES, mas não é idêntica. Se você conhece a especificação J2ME JSR239, fique atento a variações.

Consulte também

Noções básicas

O Android oferece suporte ao OpenGL tanto pela API de framework quanto pelo Native Development Kit (NDK). Este tópico têm como foco as interfaces do framework do Android. Para saber mais sobre o NDK, consulte Android NDK.

Há duas classes fundamentais no framework do Android que permitem criar e manipular gráficos com a API OpenGL ES: GLSurfaceView e GLSurfaceView.Renderer. Se o seu objetivo é usar o OpenGL no seu aplicativo Android, entender como implementar essas classes em uma atividade deve ser seu primeiro objetivo.

GLSurfaceView
Essa classe é uma View em que você pode desenhar e manipular objetos usando chamadas da API OpenGL e é semelhante em função a um SurfaceView. Para usar essa classe, crie uma instância da GLSurfaceView e adicione seu Renderer a ela. No entanto, se você quiser capturar eventos de tela touchscreen, estenda a classe GLSurfaceView para implementar listeners de toque, como mostrado na lição de treinamento do OpenGL, Como responder a eventos de toque.
GLSurfaceView.Renderer
Esta interface define os métodos necessários para desenhar gráficos em uma GLSurfaceView. Você precisa disponibilizar uma implementação dessa interface como uma classe separada e anexá-la à instância GLSurfaceView usando GLSurfaceView.setRenderer().

A interface GLSurfaceView.Renderer requer a implementação dos seguintes métodos:

  • onSurfaceCreated(): o sistema chama esse método uma vez ao criar o GLSurfaceView. Use esse método para realizar ações que precisam acontecer apenas uma vez, por exemplo, definir parâmetros de ambiente OpenGL ou inicializar objetos gráficos do OpenGL.
  • onDrawFrame(): o sistema chama esse método em cada novo desenho de GLSurfaceView. Use esse método como o ponto de execução principal para desenhar (e redesenhar) objetos gráficos.
  • onSurfaceChanged(): o sistema chama esse método quando a geometria GLSurfaceView é alterada, incluindo mudanças no tamanho do GLSurfaceView ou na orientação da tela do dispositivo. Por exemplo, o sistema chama esse método quando o dispositivo muda da orientação retrato para paisagem. Use esse método para responder a mudanças no contêiner GLSurfaceView.

Pacotes do OpenGL ES

Depois de estabelecer uma visualização de contêiner para o OpenGL ES usando GLSurfaceView e GLSurfaceView.Renderer, você pode começar a chamar APIs do OpenGL usando as seguintes classes:

  • Classe da API OpenGL ES 2.0
    • android.opengl.GLES20: este pacote fornece a interface para o OpenGL ES 2.0 e está disponível a partir do Android 2.2 (API de nível 8).
  • Pacotes da API OpenGL ES 3.0/3.1/3.2
    • android.opengl: este pacote fornece a interface para as classes do OpenGL ES 3.0/3.1. A versão 3.0 está disponível a partir do Android 4.3 (API nível 18). A versão 3.1 está disponível a partir do Android 5.0 (nível 21 da API). A versão 3.2 está disponível a partir do Android 7.0 (nível 24 da API).

Se você quiser começar a criar um app com o OpenGL ES imediatamente, siga a classe Como exibir gráficos com o OpenGL ES.

Declarar requisitos do OpenGL

Se o aplicativo usa recursos do OpenGL que não estão disponíveis em todos os dispositivos, você precisa incluir estes requisitos no arquivo AndroidManifest.xml. Estas são as declarações mais comuns de manifesto do OpenGL:

  • Requisitos de versão do OpenGL ES: se o aplicativo exige uma versão específica do OpenGL ES, é necessário declarar esse requisito adicionando as configurações abaixo ao manifesto, conforme mostrado abaixo.

    Para o OpenGL ES 2.0:

    <!-- Tell the system this app requires OpenGL ES 2.0. -->
    <uses-feature android:glEsVersion="0x00020000" android:required="true" />
    

    Adicionar essa declaração faz com que o Google Play restrinja a instalação do seu aplicativo em dispositivos sem suporte ao OpenGL ES 2.0. Se seu aplicativo for exclusivamente para dispositivos compatíveis com o OpenGL ES 3.0, você também poderá especificar isso no manifesto:

    Para o OpenGL ES 3.0:

    <!-- Tell the system this app requires OpenGL ES 3.0. -->
    <uses-feature android:glEsVersion="0x00030000" android:required="true" />
    

    Para o OpenGL ES 3.1:

    <!-- Tell the system this app requires OpenGL ES 3.1. -->
    <uses-feature android:glEsVersion="0x00030001" android:required="true" />
    

    Para o OpenGL ES 3.2:

    <!-- Tell the system this app requires OpenGL ES 3.2. -->
    <uses-feature android:glEsVersion="0x00030002" android:required="true" />
    

    Observação:a API OpenGL ES 3.x é compatível com versões anteriores da API 2.0. Isso significa que você pode ser mais flexível com a implementação do OpenGL ES no seu aplicativo. Ao declarar a API OpenGL ES 2.0 como um requisito no manifesto, você pode usar essa versão da API como padrão, verificar a disponibilidade da API 3.x no tempo de execução e usar os recursos do OpenGL ES 3.x se o dispositivo for compatível. Para saber mais sobre como verificar a versão do OpenGL ES compatível com um dispositivo, consulte Verificar a versão do OpenGL ES.

  • Requisitos de compactação de textura: se o aplicativo usa formatos de compactação de textura, é necessário declarar os formatos compatíveis no arquivo de manifesto usando <supports-gl-texture>. Para mais informações sobre os formatos de compactação de textura disponíveis, consulte Suporte à compactação de texturas.

    A declaração de requisitos de compactação de textura no manifesto oculta seu aplicativo dos usuários com dispositivos que não oferecem suporte a pelo menos um dos tipos de compactação declarados. Para saber mais sobre como a filtragem do Google Play funciona para compactações de textura, consulte a seção Google Play e a filtragem de compactação de textura da documentação de <supports-gl-texture>.

Coordenadas de mapeamento para objetos desenhados

Um dos problemas básicos na exibição de gráficos em dispositivos Android é que as telas podem variar em tamanho e forma. O OpenGL pressupõe um sistema de coordenadas quadrado e uniforme e, por padrão, desenha essas coordenadas em uma tela normalmente não quadrada, como se ela fosse perfeitamente quadrada.

Figura 1. Sistema de coordenadas padrão do OpenGL (à esquerda) mapeado para uma tela típica de dispositivo Android (à direita).

A ilustração acima mostra o sistema de coordenadas uniforme presumido para um frame OpenGL à esquerda e como essas coordenadas são mapeadas para uma tela típica de dispositivo na orientação paisagem à direita. Para resolver esse problema, aplique os modos de projeção do OpenGL e as visualizações de câmera para transformar as coordenadas, fazendo com que seus objetos gráficos tenham as proporções corretas em qualquer tela.

Para aplicar projeção e visualizações de câmera, crie uma matriz de projeção e uma matriz de visualização de câmera e aplique-as ao pipeline de renderização do OpenGL. A matriz de projeção recalcula as coordenadas dos gráficos para que sejam mapeadas corretamente nas telas de dispositivos Android. A matriz de visualização da câmera cria uma transformação que renderiza objetos de uma posição específica dos olhos.

Projeção e visualização de câmera no OpenGL ES 2.0 e versões posteriores

Nas APIs ES 2.0 e 3.0, aplique a projeção e a visualização de câmera adicionando primeiro um membro de matriz aos sombreadores de vértice dos objetos gráficos. Com esse membro de matriz adicionado, é possível gerar e aplicar matrizes de projeção e de visualização de câmera aos seus objetos.

  1. Adicionar matriz aos sombreadores de vértice: crie uma variável para a matriz de projeção de visualização e a inclua como um multiplicador da posição do sombreador. No exemplo de código do sombreador de vértice a seguir, o membro uMVPMatrix incluído permite aplicar matrizes de projeção e de visualização de câmera às coordenadas de objetos que usam esse sombreador.

    Kotlin

    private val vertexShaderCode =
    
        // This matrix member variable provides a hook to manipulate
        // the coordinates of objects that use this vertex shader.
        "uniform mat4 uMVPMatrix;   \n" +
    
        "attribute vec4 vPosition;  \n" +
        "void main(){               \n" +
        // The matrix must be included as part of gl_Position
        // Note that the uMVPMatrix factor *must be first* in order
        // for the matrix multiplication product to be correct.
        " gl_Position = uMVPMatrix * vPosition; \n" +
    
        "}  \n"
    

    Java

    private final String vertexShaderCode =
    
        // This matrix member variable provides a hook to manipulate
        // the coordinates of objects that use this vertex shader.
        "uniform mat4 uMVPMatrix;   \n" +
    
        "attribute vec4 vPosition;  \n" +
        "void main(){               \n" +
        // The matrix must be included as part of gl_Position
        // Note that the uMVPMatrix factor *must be first* in order
        // for the matrix multiplication product to be correct.
        " gl_Position = uMVPMatrix * vPosition; \n" +
    
        "}  \n";
    

    Observação:o exemplo acima define um único membro da matriz de transformação no sombreador de vértice em que você aplica uma matriz de projeção combinada e uma matriz de visualização de câmera. Dependendo dos requisitos do seu aplicativo, convém definir uma matriz de projeção e membros da matriz de visualização de câmera separados nos sombreadores de vértice para que possam ser alterados de forma independente.

  2. Acessar a matriz de sombreador: depois de criar um hook nos sombreadores de vértice para aplicar projeção e visualização de câmera, é possível acessar essa variável para aplicar matrizes de projeção e de visualização de câmera. O código a seguir mostra como modificar o método onSurfaceCreated() de uma implementação de GLSurfaceView.Renderer para acessar a variável de matriz definida no sombreador de vértice acima.

    Kotlin

    override fun onSurfaceCreated(gl: GL10, config: EGLConfig) {
        ...
        muMVPMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix")
        ...
    }
    

    Java

    public void onSurfaceCreated(GL10 unused, EGLConfig config) {
        ...
        muMVPMatrixHandle = GLES20.glGetUniformLocation(program, "uMVPMatrix");
        ...
    }
    
  3. Criar matrizes de projeção e de visualização de câmera: gere as matrizes de projeção e visualização a serem aplicadas aos objetos gráficos. O código de exemplo abaixo mostra como modificar os métodos onSurfaceCreated() e onSurfaceChanged() de uma implementação de GLSurfaceView.Renderer para criar uma matriz de visualização de câmera e uma de projeção com base na proporção da tela do dispositivo.

    Kotlin

    override fun onSurfaceCreated(gl: GL10, config: EGLConfig) {
        ...
        // Create a camera view matrix
        Matrix.setLookAtM(vMatrix, 0, 0f, 0f, -3f, 0f, 0f, 0f, 0f, 1.0f, 0.0f)
    }
    
    override fun onSurfaceChanged(gl: GL10, width: Int, height: Int) {
        GLES20.glViewport(0, 0, width, height)
    
        val ratio: Float = width.toFloat() / height.toFloat()
    
        // create a projection matrix from device screen geometry
        Matrix.frustumM(projMatrix, 0, -ratio, ratio, -1f, 1f, 3f, 7f)
    }
    

    Java

    public void onSurfaceCreated(GL10 unused, EGLConfig config) {
        ...
        // Create a camera view matrix
        Matrix.setLookAtM(vMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
    }
    
    public void onSurfaceChanged(GL10 unused, int width, int height) {
        GLES20.glViewport(0, 0, width, height);
    
        float ratio = (float) width / height;
    
        // create a projection matrix from device screen geometry
        Matrix.frustumM(projMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
    }
    
  4. Aplicar matrizes de projeção e de visualização de câmera: para aplicar as transformações de projeção e visualização de câmera, multiplique as matrizes e defina-as no sombreador de vértice. O código de exemplo abaixo mostra como modificar o método onDrawFrame() de uma implementação de GLSurfaceView.Renderer para combinar a matriz de projeção e a visualização da câmera criadas no código acima e, em seguida, aplicá-los aos objetos gráficos que serão renderizados pelo OpenGL.

    Kotlin

    override fun onDrawFrame(gl: GL10) {
        ...
        // Combine the projection and camera view matrices
        Matrix.multiplyMM(vPMatrix, 0, projMatrix, 0, vMatrix, 0)
    
        // Apply the combined projection and camera view transformations
        GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, vPMatrix, 0)
    
        // Draw objects
        ...
    }
    

    Java

    public void onDrawFrame(GL10 unused) {
        ...
        // Combine the projection and camera view matrices
        Matrix.multiplyMM(vPMatrix, 0, projMatrix, 0, vMatrix, 0);
    
        // Apply the combined projection and camera view transformations
        GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, vPMatrix, 0);
    
        // Draw objects
        ...
    }
    

Para ver um exemplo completo de como aplicar projeção e visualização de câmera com o OpenGL ES 2.0, consulte a classe Como exibir gráficos com o OpenGL ES.

Faces e enrolamento de formas

No OpenGL, a face de uma forma é uma superfície definida por três ou mais pontos no espaço tridimensional. Um conjunto de três ou mais pontos tridimensionais (chamados de vértices no OpenGL) tem uma face frontal e uma face traseira. Como saber qual é a face frontal e qual é a traseira? Boa pergunta. A resposta tem a ver com o enrolamento, ou seja, a direção em que você define os pontos de uma forma.

Coordenadas nos
vértices de um triângulo

Figura 1. Ilustração de uma lista de coordenadas que é convertida em uma ordem de desenho no sentido anti-horário.

Neste exemplo, os pontos do triângulo são definidos na ordem em que são desenhados no sentido anti-horário. A ordem em que essas coordenadas são desenhadas define a direção de enrolamento da forma. Por padrão, no OpenGL, a face desenhada no sentido anti-horário é a frontal. O triângulo mostrado na Figura 1 é definido para que você esteja olhando para a face frontal da forma (conforme interpretado pelo OpenGL) e o outro lado é a face traseira.

Por que é importante saber qual face de uma forma é a frontal? A resposta tem a ver com um recurso do OpenGL usado com frequência, chamado seleção facial. A seleção facial é uma opção para o ambiente OpenGL que permite que o pipeline de renderização ignore (não calcule nem desenhe) a face traseira de uma forma, economizando tempo, memória e ciclos de processamento:

Kotlin

gl.apply {
    // enable face culling feature
    glEnable(GL10.GL_CULL_FACE)
    // specify which faces to not draw
    glCullFace(GL10.GL_BACK)
}

Java

// enable face culling feature
gl.glEnable(GL10.GL_CULL_FACE);
// specify which faces to not draw
gl.glCullFace(GL10.GL_BACK);

Se você tentar usar o recurso de seleção de rostos sem saber quais lados das formas são a frente e o traseiro, os gráficos OpenGL vão parecer um pouco finos ou não aparecer. Portanto, sempre defina as coordenadas das formas do OpenGL em um sentido de desenho anti-horário.

Observação:é possível definir um ambiente OpenGL para tratar o sentido no sentido horário como a face frontal, mas isso exige mais código e pode confundir desenvolvedores com OpenGL experientes quando você pedir ajuda. Então, não faça isso.

Versões do OpenGL e compatibilidade com dispositivos

As especificações da API OpenGL ES 1.0 e 1.1 são compatíveis a partir do Android 1.0. A programação gráfica com a API OpenGL ES 1.0/1.1 é significativamente diferente de usar as versões 2.0 e mais recentes. O OpenGL ES 2.0 oferece suporte a todos os dispositivos Android a partir da versão 2.2 (nível 8 da API) e é a versão mais antiga recomendada para novos aplicativos desenvolvidos com o OpenGL ES. O OpenGL ES 3.0 oferece suporte ao Android 4.3 (nível 18 da API) e versões mais recentes em dispositivos que oferecem uma implementação da API OpenGL ES 3.0. Para saber mais sobre o número relativo de dispositivos Android que oferecem suporte a uma determinada versão do OpenGL ES, consulte o painel de versões do OpenGL ES.

Considere cuidadosamente os requisitos gráficos e escolha a versão da API que funciona melhor para seu aplicativo. Para saber mais, consulte Escolher uma versão da API OpenGL.

A API OpenGL ES 3.0 oferece mais recursos e desempenho melhor do que a API 2.0 e também é compatível com versões anteriores. Isso significa que você pode programar seu aplicativo segmentando OpenGL ES 2.0 e incluir condicionalmente os recursos gráficos do OpenGL ES 3.0, se eles estiverem disponíveis. Para mais informações sobre como verificar a disponibilidade da API 3.0, consulte Verificar a versão do OpenGL ES

Compatibilidade com compactação de textura

A compactação de textura pode aumentar significativamente o desempenho do seu aplicativo OpenGL, reduzindo os requisitos de memória e usando a largura de banda da memória de forma mais eficiente. O framework do Android oferece suporte ao formato de compactação ETC1 como um recurso padrão, incluindo uma classe de utilitário ETC1Util e a ferramenta de compactação etc1tool (localizada no SDK do Android em <sdk>/tools/). Para conferir um exemplo de app Android que usa compactação de textura, consulte o exemplo de código CompressedTextureActivity no SDK do Android (<sdk>/samples/<version>/ApiDemos/src/com/example/android/apis/graphics/).

O formato ETC1 oferece suporte a todos os dispositivos Android compatíveis com o OpenGL ES 2.0 ou versões mais recentes.

Observação:o formato de compactação de textura ETC1 não oferece suporte a texturas com transparência (canal Alfa). Caso seu aplicativo exija texturas com transparência, investigue outros formatos de compactação de textura disponíveis nos dispositivos de destino. Um método para renderizar texturas do canal Alfa usando o ETC1 é vincular dois objetos de textura de ETC1: o primeiro com dados de cores, o segundo com os dados do canal Alfa e depois combinar os valores das duas texturas no sombreador de fragmento.

Os formatos de compactação de textura ETC2/EAC têm garantia de disponibilidade ao usar a API OpenGL ES 3.0. Esse formato de textura oferece excelentes taxas de compactação com alta qualidade visual, e o formato também oferece suporte à transparência (canal alfa).

Além dos formatos ETC, os dispositivos Android oferecem suporte variado à compactação de textura com base nos chipsets de GPU e implementações do OpenGL. Investigue o suporte à compactação de textura nos dispositivos de destino para determinar com quais tipos de compactação seu aplicativo pode oferecer suporte. Para determinar quais formatos de textura podem ser usados em um dispositivo, é necessário consultar o dispositivo e revisar os nomes das extensões OpenGL, que identificam quais formatos de compactação de textura e outros recursos do OpenGL oferecem suporte ao dispositivo. Alguns dos formatos de compactação de textura mais comuns são:

  • Compactação de textura escalonável adaptável (ASTC, na sigla em inglês): um formato de compactação de textura criado para substituir formatos anteriores. Mais flexível do que os formatos anteriores devido ao suporte a vários tamanhos de bloco.
    • GL_KHR_texture_compression_astc_ldr
    • GL_KHR_texture_compression_astc_hdr(alto alcance dinâmico)
  • S3TC (DXTn/DXTC): a compactação de textura S3 (S3TC) tem diversas variações de formato (DXT1 a DXT5) e está disponível de forma menos ampla. O formato é compatível com texturas RGB com canais Alfa de 4 ou 8 bits. Esses formatos são representados pelo seguinte nome de extensão do OpenGL:
    • GL_EXT_texture_compression_s3tc
    Alguns dispositivos oferecem suporte apenas à variação do formato DXT1. Esse suporte limitado é representado pelo seguinte nome de extensão do OpenGL:
    • GL_EXT_texture_compression_dxt1

Os formatos de compactação de textura abaixo são considerados legados e não são recomendados para uso em novos aplicativos:

  • ATITC (ATC): a compactação de textura ATI (ATITC ou ATC) está disponível em vários dispositivos e oferece suporte à compactação de taxa fixa para texturas RGB com e sem um canal Alfa. Esse formato pode ser representado por vários nomes de extensão do OpenGL, por exemplo:
    • GL_AMD_compressed_ATC_texture
    • GL_ATI_texture_compression_atitc
  • PVRTC: a compactação de textura PowerVR (PVRTC) está disponível em vários dispositivos e oferece suporte a texturas de 2 e 4 bits por pixel com ou sem um canal Alfa. Esse formato é representado pelo seguinte nome de extensão do OpenGL:
    • GL_IMG_texture_compression_pvrtc
  • 3DC: a compactação de textura 3DC é um formato menos disponível que oferece suporte a texturas RGB com um canal Alfa. Esse formato é representado pelo seguinte nome da extensão OpenGL:
    • GL_AMD_compressed_3DC_texture

Aviso:esses formatos de compactação de textura não têm suporte em todos os dispositivos. A compatibilidade com esses formatos pode variar de acordo com o fabricante e o dispositivo. Para saber mais sobre como determinar quais formatos de compactação de textura estão em um dispositivo específico, consulte a próxima seção.

Observação:depois de decidir para quais formatos de compactação de textura seu aplicativo vai oferecer suporte, declare-os no manifesto usando <supports-gl-texture> . O uso dessa declaração permite o filtro por serviços externos, como o Google Play, para que o app seja instalado somente em dispositivos com suporte aos formatos exigidos. Para mais detalhes, consulte as declarações do manifesto do OpenGL.

Determinar extensões do OpenGL

As implementações do OpenGL variam de acordo com o dispositivo Android no que diz respeito às extensões compatíveis com a API OpenGL ES. Essas extensões incluem compactações de textura, mas normalmente também incluem outras extensões para o conjunto de recursos do OpenGL.

Para determinar quais formatos de compactação de textura e outras extensões do OpenGL podem ser usados em um dispositivo específico, faça o seguinte:

  1. Execute o código abaixo nos dispositivos de destino para determinar quais formatos de compactação de textura têm suporte:

    Kotlin

    var extensions = gl.glGetString(GL10.GL_EXTENSIONS)
    

    Java

    String extensions = gl.glGetString(GL10.GL_EXTENSIONS);
    

    Alerta: os resultados dessa chamada variam de acordo com o modelo do dispositivo. Execute essa chamada em vários dispositivos de destino para determinar quais tipos de compactação são mais compatíveis.

  2. Analise a saída desse método para determinar quais extensões OpenGL têm suporte no dispositivo.

Pacote de extensões para Android (AEP, na sigla em inglês)

O AEP garante que o aplicativo ofereça suporte a um conjunto padronizado de extensões do OpenGL acima e além do conjunto principal descrito na especificação do OpenGL 3.1. O empacotamento dessas extensões incentiva um conjunto consistente de funcionalidades em vários dispositivos, permitindo que os desenvolvedores aproveitem ao máximo a série mais recente de dispositivos móveis de GPU.

O AEP também melhora o suporte a imagens, buffers de armazenamento de sombreador e contadores atômicos em sombreadores de fragmento.

Para que seu app possa usar o AEP, o manifesto precisa declarar que o AEP é necessário. Além disso, a versão da plataforma precisa ser compatível com o pacote.

Todos os recursos adicionais especificados no AEP estão incluídos na especificação básica do OpenGL ES 3.2. Se seu aplicativo exige o OpenGL ES 3.2, você não precisa do AEP.

Declare o requisito de AEP no manifesto da seguinte forma:

<uses-feature android:name="android.hardware.opengles.aep"
              android:required="true" />

Para verificar se a versão da plataforma é compatível com o AEP, use o método hasSystemFeature(String), transmitindo FEATURE_OPENGLES_EXTENSION_PACK como argumento. O snippet de código abaixo mostra um exemplo de como fazer isso:

Kotlin

var deviceSupportsAEP: Boolean =
        packageManager.hasSystemFeature(PackageManager.FEATURE_OPENGLES_EXTENSION_PACK)

Java

boolean deviceSupportsAEP = getPackageManager().hasSystemFeature
     (PackageManager.FEATURE_OPENGLES_EXTENSION_PACK);

Se o método retornar verdadeiro, o AEP será compatível.

Para saber mais sobre o AEP, visite a página dele no Registro do Khronos OpenGL ES.

Verificar a versão do OpenGL ES

Existem várias versões do OpenGL ES disponíveis em dispositivos Android. Você pode especificar a versão mínima da API exigida pelo aplicativo no manifesto, mas também pode aproveitar os recursos de uma API mais recente ao mesmo tempo. Por exemplo, a API OpenGL ES 3.0 é compatível com a versão 2.0 da API.Por isso, escreva o aplicativo para que ele use os recursos do OpenGL ES 3.0, mas use a API 2.0 se ela não estiver disponível.

Antes de usar os recursos do OpenGL ES de uma versão mais recente que a mínima exigida no manifesto do aplicativo, é necessário verificar a versão da API disponível no dispositivo. Isso pode ser feito de duas maneiras:

  1. Tente criar o contexto do OpenGL ES de nível superior (EGLContext) e verifique o resultado.
  2. Crie um contexto do OpenGL ES mínimo compatível e verifique o valor da versão.

O código de exemplo abaixo demonstra como verificar a versão do OpenGL ES disponível criando uma EGLContext e verificando o resultado. Este exemplo mostra como verificar a versão do OpenGL ES 3.0:

Kotlin

private const val EGL_CONTEXT_CLIENT_VERSION = 0x3098
private const val glVersion = 3.0
private class ContextFactory : GLSurfaceView.EGLContextFactory {

    override fun createContext(egl: EGL10, display: EGLDisplay, eglConfig: EGLConfig): EGLContext {

        Log.w(TAG, "creating OpenGL ES $glVersion context")
        return egl.eglCreateContext(
                display,
                eglConfig,
                EGL10.EGL_NO_CONTEXT,
                intArrayOf(EGL_CONTEXT_CLIENT_VERSION, glVersion.toInt(), EGL10.EGL_NONE)
        ) // returns null if 3.0 is not supported
    }
}

Java

private static double glVersion = 3.0;

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 " + glVersion + " context");
      int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, (int) glVersion,
              EGL10.EGL_NONE };
      // attempt to create a OpenGL ES 3.0 context
      EGLContext context = egl.eglCreateContext(
              display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
      return context; // returns null if 3.0 is not supported;
  }
}

Se o método createContext() mostrado acima retornar nulo, seu código precisará criar um contexto do OpenGL ES 2.0 e voltar a usar apenas essa API.

O exemplo de código abaixo demonstra como verificar a versão do OpenGL ES criando um contexto mínimo compatível primeiro e, em seguida, verificando a string da versão:

Kotlin

// Create a minimum supported OpenGL ES context, then check:
gl.glGetString(GL10.GL_VERSION).also {
    Log.w(TAG, "Version: $it")
}
 // The version format is displayed as: "OpenGL ES <major>.<minor>"
 // followed by optional content provided by the implementation.

Java

// Create a minimum supported OpenGL ES context, then check:
String version = gl.glGetString(GL10.GL_VERSION);
Log.w(TAG, "Version: " + version );
// The version format is displayed as: "OpenGL ES <major>.<minor>"
// followed by optional content provided by the implementation.

Com essa abordagem, se você descobrir que o dispositivo oferece suporte a uma versão de API de nível superior, será necessário destruir o contexto mínimo do OpenGL ES e criar um novo contexto com a versão mais recente disponível da API.

Escolher uma versão da API OpenGL

As versões 2.0 e 3.0 do OpenGL ES oferecem interfaces gráficas de alto desempenho para criar jogos, visualizações e interfaces do usuário em 3D. A programação de gráficos para OpenGL ES 2.0 e 3.0 é muito semelhante, com a versão 3.0 representando um superconjunto da API 2.0 com outros recursos. A programação da API OpenGL ES 1.0/1.1 em comparação com o OpenGL ES 2.0 e 3.0 é muito diferente e não é recomendada para novos aplicativos. Os desenvolvedores precisam considerar cuidadosamente os seguintes fatores antes de iniciar o desenvolvimento com essas APIs:

  • Compatibilidade do dispositivo: os desenvolvedores precisam considerar os tipos de dispositivos, as versões do Android e as versões do OpenGL ES disponíveis para os clientes. Para saber mais sobre a compatibilidade do OpenGL nos dispositivos, consulte a seção Versões do OpenGL e compatibilidade com dispositivos.
  • Suporte a textura: a API OpenGL ES 3.0 oferece o melhor suporte à compactação de textura, porque ela garante a disponibilidade do formato de compactação ETC2, que oferece suporte à transparência. As implementações da API 2.0 incluem suporte para ETC1, no entanto, esse formato de textura não tem suporte à transparência. Para implementar a transparência com texturas compactadas, é necessário usar duas texturas ETC1 (divididas entre cor e Alfa) ou fornecer recursos em outros formatos de compactação com suporte aos dispositivos de destino. Para mais informações, consulte Suporte à compactação de textura.

Embora a compatibilidade e a compatibilidade com a textura possam influenciar sua decisão, escolha uma versão da API OpenGL com base no que você acha que oferece a melhor experiência para os usuários.