Comment limiter l'encrychage lors de l'utilisation de GLSurfaceView d'Android.RENDERMODE_CONTINUEMENT?

J'ai un jeu C ++ qui parcourt JNI dans Android. La fréquence d'images varie d'environ 20 à 45 fps en raison de la complexité de la scène. Tout ce qui dépasse 30 fps est stupide pour le jeu; C'est juste une batterie en feu. Je voudrais limiter la fréquence d'images à 30 fps.

  • Je pourrais passer à RENDERMODE_WHEN_DIRTY et utiliser une minuterie ou ScheduledThreadPoolExecutor pour demanderRender (). Mais cela ajoute tout un tas de pièces mobiles supplémentaires qui pourraient ou pourraient ne pas fonctionner de manière cohérente et correcte.
  • J'ai essayé d'injecter Thread.sleep () lorsque les choses fonctionnent rapidement, mais cela ne semble pas fonctionner du tout pour de petites valeurs temporelles. Et il se peut qu'il contienne quelques imprécisions par rapport à l'utilisation.

Existe-t-il une méthode capFramerate () qui se cache dans l'API? Une façon fiable de le faire?

  • Android: comment distribuer une application payante lorsque payé Google Play n'est pas disponible dans mon pays
  • RunOnUiThread dans le fragment
  • Android Volley - BasicNetwork.performRequest: code de réponse inattendu 400
  • Menu déroulant Styling ActionBar
  • Comment émettre par programme un événement de clic sur Android
  • Java.lang.IllegalStateException: commit déjà appelé dans le pager de vue avec Tablayout
  • Échec d'erreur après avoir ajouté un plugin Crosswalk à un projet Cordova Android
  • GetActionBar de Fragment avec AppCompatLibrary
  • Comment rendez-vous du texte dans un fichier xml de la liste de couches Android?
  • Comment lancer le service FCM ID après une activité particulière déclenchée?
  • Ouverture de la caméra dans un processus différent
  • Rafraîchissement de la vue de la liste Android
  • 5 Solutions collect form web for “Comment limiter l'encrychage lors de l'utilisation de GLSurfaceView d'Android.RENDERMODE_CONTINUEMENT?”

    La solution de Mark est presque bonne, mais pas tout à fait correcte. Le problème est que le swap lui-même prend beaucoup de temps (en particulier si le pilote vidéo contient des instructions de mise en cache). Par conséquent, vous devez en tenir compte ou vous finirez par une fréquence d'images inférieure à celle souhaitée. Donc, la chose devrait être:

    Quelque part au début (comme le constructeur):

    startTime = System.currentTimeMillis(); 

    Puis dans la boucle de rendu:

     public void onDrawFrame(GL10 gl) { endTime = System.currentTimeMillis(); dt = endTime - startTime; if (dt < 33) Thread.Sleep(33 - dt); startTime = System.currentTimeMillis(); UpdateGame(dt); RenderGame(gl); } 

    De cette façon, vous prendrez en compte le temps nécessaire pour échanger les tampons et le temps de dessiner le cadre.

    Lorsque vous utilisez GLSurfaceView, vous effectuez le dessin dans le OnDrawFrame de votre Renderer qui est traité dans un thread distinct par GLSurfaceView. Assurez-vous simplement que chaque appel à onDrawFrame prend (1000 / [cadres]) des millisecondes, dans votre cas, quelque chose comme 33 ms.

    Pour ce faire: (dans votre OnDrawFrame)

    1. Mesurez l'heure actuelle avant de commencer le dessin à l'aide de System.currentTimeMillis (appelons-le startTime)
    2. Effectuer le dessin
    3. Mesurez l'heure à nouveau (Appelons-le endTime)
    4. DeltaT = endTime – starTime
    5. Si deltaT <33, sommeil (33-deltaT)

    C'est tout.

    La réponse de Fili m'a paru géniale, malheureusement limité le FPS sur mon appareil Android à 25 FPS, même si j'ai demandé 30. J'ai compris que Thread.sleep() fonctionne pas assez précisément et peut durer plus longtemps qu'il ne le devrait.

    J'ai trouvé cette implémentation à partir du projet LWJGL pour effectuer le travail: https://github.com/LWJGL/lwjgl/blob/master/src/java/org/lwjgl/opengl/Sync.java

    La solution de Fili échoue pour certaines personnes, alors je soupçonne que ça dort jusqu'à immédiatement après la prochaine vsync au lieu de tout de suite. Je pense également que le fait de déplacer le sommeil jusqu'à la fin de la fonction donnerait de meilleurs résultats, car là, il peut effacer la trame actuelle avant le prochain vsync, au lieu d'essayer de compenser la précédente. Thread.sleep () est inexacte, mais heureusement, nous n'avons besoin que d'être précis à la période vsync la plus proche de 1 / 60s. Le code LWJGL tyrondis posté un lien semble trop compliqué pour cette situation, il est probablement conçu pour quand vsync est désactivé ou indisponible, ce qui ne devrait pas être le cas dans le contexte de cette question.

    J'essayerais quelque chose comme ça:

     private long lastTick = System.currentTimeMillis(); public void onDrawFrame(GL10 gl) { UpdateGame(dt); RenderGame(gl); // Subtract 10 from the desired period of 33ms to make generous // allowance for overhead and inaccuracy; vsync will take up the slack long nextTick = lastTick + 23; long now; while ((now = System.currentTimeMillis()) < nextTick) Thread.sleep(nextTick - now); lastTick = now; } 

    Vous pouvez également essayer de réduire la priorité du thread depuis OnSurfaceCreated ():

     Process.setThreadPriority(Process.THREAD_PRIORITY_LESS_FAVORABLE); 
    coAndroid est un fan Android de Google, tout sur les téléphones Android, Android Wear, Android Dev et Android Games Apps.