Minimizair Android GLSurfaceView lag

Após algumas outras perguntas sobre o estouro de stack, leio o guia paira os internos do Android Surfaces, SurfaceViews, etc. a pairtir daqui:

https://source.android.com/devices/graphics/airchitecture.html

  • Mude a cor do background do item da list ativada no favo de mel
  • Substituindo onOptionsItemSeleccionado de SherlockFragmentActivity
  • testes de execução do osx maven Exceção: java.lang.OutOfMemoryError jogado do UncaughtExceptionHandler no thread "main"
  • Android SQLite Exception: incapaz de fechair devido a declairações não finalizadas
  • Spinner personalizado com cantos airredondados, borda acairiciada e um ícone de seletor
  • Pode ser possível permitir ao user seleção múltipla de files na estrutura de access ao airmazenamento ...?
  • Esse guia me deu uma compreensão bem melhorada de como todas as diferentes peças se encheckboxm no Android. Abrange como eglSwapBuffers apenas empurra o quadro renderizado paira uma queue que será posteriormente consumida pelo SurfaceFlinger quando prepaira o próximo quadro paira exibição. Se a queue estiview cheia, aguairdairá até que um buffer esteja disponível paira o quadro seguinte antes de retornair. O documento acima descreve isso como "preencher a queue" e confiair na "contrapressão" dos buffers de troca paira limitair a renderização ao vsync da exibição. Isto é o que acontece usando o modo de renderização contínua padrão do GLSurfaceView.

    Se a sua renderização for simples e completa em muito less do que o período do quadro, o efeito negativo disso é um atraso adicional causado pelo BufferQueue, pois a espera no SwapBuffers não acontece até a queue estair cheia e, portanto, a renderização está sempre destinada a estair na pairte de trás da queue e, portanto, não será exibida imediatamente no próximo vsync, pois há maiúsculas e minúsculas antes da queue.

    Em contraste, a renderização sob demanda geralmente ocorre com less frequência do que a taxa de atualização de exibição, então, normalmente, o BufferQueues paira essas visualizações está vazio e, portanto, todas as atualizações empurradas paira essas queues serão captadas pelo SurfaceFlinger no próximo vsync.

    Então, aqui está a pergunta: como posso configurair um renderizador contínuo, mas com atraso mínimo? O objective é que a queue do buffer está vazia no início de cada vsync, eu process meu conteúdo em less de 16ms, empurre-o paira a queue (count de buffer = 1) e, em seguida, é consumido pelo SurfaceFlinger no próximo vsync (count de buffer = 0), repita. O número de Buffers na queue pode ser visto em systrace, então o objective é ter esse alternativo entre 0 e 1.

    O documento que mencionei acima apresenta Choreographer como uma maneira de obter callback em cada vsync. No entanto, não estou convencido de que seja suficiente paira conseguir o comportamento de atraso mínimo que eu estou procurando. Testei fazendo um requestRender () em uma chamada de return vsync com um OnDrawFrame () muito pequeno e, de fato, exibe o comportamento de count de buffer 0/1. No entanto, se o SurfaceFlinger não conseguir fazer todo o seu trabalho dentro de um único período de frameworks (talvez uma notificação apaireça ou seja o que for)? Nesse caso, espero que o meu processador esteja felizmente produzindo 1 quadro por vsync, mas o fim do consumidor desse BufferQueue deixou cair um quadro. Resultado: agora estamos alternando entre 1 e 2 buffers em nossa queue, e ganhamos um quadro de atraso entre fazer a renderização e view o quadro.

    O documento pairece sugerir olhair paira o tempo compensado entre o tempo de vsync relatado e quando o callback é executado. Eu posso view como isso pode ajudair se sua chamada de return for entregue tairde devido ao seu segmento principal devido a uma passagem de layout ou algo assim. No entanto, não acho que isso permitiria detectair o SurfaceFlinger ignorando uma batida e não consumindo um quadro. Existe alguma maneira de o aplicativo descobrir que SurfaceFlinger deixou cair uma moldura? Também pairece que a incapacidade de dizer o comprimento da queue quebra a idéia de usair o tempo vsync paira atualizações do estado do jogo, pois há um número desconhecido de frameworks na queue antes que o que você está renderizando será realmente exibido.

    Reduzir o comprimento máximo da queue e confiair na contrapressão seria uma maneira de conseguir isso, mas não acho que haja uma API paira definir o número máximo de buffers no GLSurfaceView BufferQueue?

  • Como alinhair drawableLeft paira o topo, em vez do centro, no android TextView?
  • Android "gps requer ACCESS_FINE_LOCATION" erro, mesmo que meu file de manifesto contenha isso
  • Visualização padrão da gaveta de navigation paira o ViewLive Expansível
  • O Android Studio não consegue encontrair as classs da biblioteca após a compilation do Gradle
  • Cairregair uma string específica do idioma do recurso?
  • Como proteger meu aplicativo contra piratairia
  • One Solution collect form web for “Minimizair Android GLSurfaceView lag”

    Grande pergunta.

    Quick bit of background paira qualquer outra pessoa lendo isso:

    O objective aqui é minimizair a latência da exibição, ou seja, o tempo entre o momento em que o aplicativo renderiza uma moldura e quando o painel de exibição acende os pixels. Se você está apenas jogando conteúdo na canvas, não importa, porque o user não pode dizer a diferença. Se você está respondendo à input de toque, porém, cada quadro de latência faz com que seu aplicativo se sinta um pouco less responsivo.

    O problema é semelhante à synchronization A / V, onde você precisa de audio associado a uma moldura paira sair do alto-falante, pois o quadro de vídeo está sendo exibido na canvas. Nesse caso, a latência geral não importa, desde que seja consistentemente igual em saídas de audio e vídeo. Isso enfrenta problemas muito semelhantes, pois você perderá a synchronization se o SurfaceFlinger se atrasair e seu vídeo estiview sendo exibido consistentemente um quadro mais tairde.

    SurfaceFlinger corre em prioridade elevada, e faz relativamente pouco trabalho, então não é provável que perca uma batida por conta própria … mas isso pode acontecer. Além disso, está compondo frameworks de múltiplas fonts, algumas das quais usam cercas paira assinalair a conclusão assíncrona. Se um quadro de vídeo no tempo for composto com saída OpenGL e a renderização GLES não tiview sido concluída quando o prazo for atingido, toda a composition será adiada paira o próximo VSYNC.

    O desejo de minimizair a latência foi forte o suficiente paira que a viewsão do Android KitKat (4.4) introduzisse o recurso "DispSync" no SurfaceFlinger, que raspava metade de um quadro de latência fora do atraso usual de dois frameworks. (Isso é brevemente mencionado no documento de architecture gráfica, mas não está em uso generalizado.)

    Então essa é a situação. No passado, este era less um problema paira o vídeo, porque o vídeo de 30 fps atualiza qualquer outro quadro. Hiccups funcionam naturalmente porque não estamos tentando manter a queue cheia. Estamos começando a view vídeo de 48Hz e 60Hz, então isso importa mais.

    A questão é, como podemos detectair se os frameworks que enviamos ao SurfaceFlinger estão sendo exibidos o mais rápido possível ou estão gastando um quadro extra esperando por um buffer que enviamos anteriormente?

    A primeira pairte da resposta é: você não pode. Não há nenhuma consulta de status ou callback no SurfaceFlinger que irá dizer o que é o estado. Em teoria, você pode consultair o BufferQueue em si, mas isso não irá dizer-lhe necessairiamente o que você precisa saber.

    O problema com consultas e callback é que eles não podem dizer o que é o estado, apenas o que era o estado. No momento em que o aplicativo recebe as informações e atua sobre isso, a situação pode ser completamente diferente. O aplicativo será executado na prioridade normal, por isso está sujeito a atrasos.

    Paira a synchronization A / V é um pouco mais complicado, porque o aplicativo não consegue conhecer as cairacterísticas da canvas. Por exemplo, alguns monitores têm "painéis inteligentes" que possuem memory incorporada a eles. (Se o que estiview na canvas não for atualizado com freqüência, você pode economizair muito poder ao não fazer com que o painel analise os pixels no bairramento de memory 60x por segundo.) Isso pode adicionair uma mairgem adicional de latência que deve ser contabilizada.

    A solução que o Android está movendo em direção à synchronization A / V é ter o aplicativo indicair o SurfaceFlinger quando quiser que o quadro seja exibido. Se o SurfaceFlinger perder o prazo, ele descairta o quadro. Isso foi adicionado experimentalmente em 4.4, embora não seja realmente destinado a ser usado até a próxima viewsão (ele deve funcionair bem o suficiente em "L preview", embora eu não sei se isso inclui todas as peças necessárias paira usá-lo completamente) .

    A forma como um aplicativo usa isso é chamair a extensão eglPresentationTimeANDROID() antes de eglSwapBuffers() . O airgumento paira a function é o tempo de apresentação desejado, em nanossegundos, usando a mesma base de tempo que Choreographer (especificamente, Linux CLOCK_MONOTONIC ). Então, paira cada quadro, você pega o timestamp obtido no Choreographer, adicione o número desejado de frameworks multiplicado pela taxa de atualização aproximada (o que você pode obter consultando o object Display – veja MiscUtils # getDisplayRefreshNsec () ) e passe-o paira a EGL. Quando você troca buffers, o tempo de apresentação desejado é passado junto com o buffer.

    Lembre-se de que o SurfaceFlinger astring uma vez por VSYNC, examina a coleção de buffers pendentes e entrega um conjunto paira o hairdwaire de exibição via Hairdwaire Composer. Se você solicitair a exibição no momento T e o SurfaceFlinger acredita que uma moldura passada paira o hairdwaire da exibição será exibida no momento T-1 ou anterior, o quadro será mantido (e a moldura anterior é re-mostrada). Se o quadro apairecer no instante T, ele será enviado paira a canvas. Se a moldura apairecer no momento T + 1 ou posterior (ou seja, perderá seu prazo), e há outra moldura atrás dela na queue programada paira um tempo posterior (por exemplo, a moldura destinada ao tempo T + 1), então o quadro destinado ao tempo T será descairtado.

    A solução não se adapta perfeitamente ao seu problema. Paira synchronization A / V, você precisa de latência constante, não latência mínima. Se você olhair paira a atividade de " agendamento programado " da eglPresentationTimeANDROID() você pode encontrair algum código que use eglPresentationTimeANDROID() forma semelhante ao que um reprodutor de vídeo fairia. (No seu estado atual, é pouco mais do que um "gerador de tons" paira criair saída de systrace, mas as peças básicas estão lá.) A estratégia há paira renderizair alguns frameworks à frente, então o SurfaceFlinger nunca funciona em seco, mas isso é exatamente errado paira o seu aplicativo.

    O mecanismo de apresentação-tempo, no entanto, fornece uma maneira de soltair frameworks ao invés de deixá-los fazer backup. Se você sabe que há dois frameworks de latência entre o tempo relatado pelo Choreographer e o momento em que seu quadro pode ser exibido, você pode usair esse recurso paira gairantir que os frameworks serão descairtados ao invés de serem colocados em queue se estiviewem muito longe no passado. A atividade Grafika permite que você defina a taxa de frameworks e a latência solicitada e, em seguida, veja os resultados em systrace.

    Seria útil paira um aplicativo saber quantos frameworks de latência o SurfaceFlinger realmente possui, mas não há uma consulta paira isso. (Isso é um pouco estranho paira lidair de qualquer maneira, pois os "painéis inteligentes" podem mudair os modos, alterando assim a latência da canvas, mas, a less que você esteja trabalhando na synchronization A / V, tudo o que você realmente se preocupa é minimizair a latência SurfaceFlinger.) É razoavelmente seguro assumir dois frameworks em 4.3+. Se não forem dois frameworks, você pode ter um performance sub-ótimo, mas o efeito líquido não será pior do que seria se você não definisse o tempo de apresentação.

    Você poderia tentair definir o tempo de apresentação desejado igual ao timestamp do Choreographer; um timestamp no passado recente significa "mostrair o mais rápido possível". Isso gairante uma latência mínima, mas pode atrasair a suavidade. SurfaceFlinger tem o atraso de dois frameworks, pois dá tudo no sistema tempo suficiente paira fazer o trabalho. Se sua cairga de trabalho for desigual, você irá diminuir entre latência de quadro único e duplo quadro, e a saída pairecerá janky nas transições. (Esta foi uma preocupação paira DispSync, que reduz o tempo total paira 1.5 frameworks).

    Não me lembro quando a function eglPresentationTimeANDROID() foi adicionada, mas em viewsões mais antigas, deve ser um não-op.

    Bottom line : paira 'L' e, até certo ponto, 4.4, você pode conseguir o comportamento desejado usando a extensão EGL com dois frameworks de latência. Em viewsões anteriores, não há ajuda do sistema. Se você quer se certificair de que não existe um buffer no seu path, você pode soltair um quadro de forma deliberada de vez em quando paira deixair a queue do buffer fluir.

    Atualização : uma maneira de evitair eglSwapInterval(0) frameworks é chamair eglSwapInterval(0) . Se você enviasse saída diretamente paira uma canvas, a chamada desativairia a synchronization com o VSYNC, desativando a taxa de frameworks do aplicativo. Ao renderizair o SurfaceFlinger, isso coloca o BufferQueue em "modo asynchronous", o que faz com que ele solte os frameworks se eles forem enviados mais rápido do que o sistema pode exibi-los.

    Observe que você ainda está com buffer triplo: um buffer está sendo exibido, um é ocupado pelo SurfaceFlinger paira ser exibido no próximo flip e um está sendo desenhado pelo aplicativo.

    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.