Android durakladığında OpenGL içeriğini kaybetmek için geçici çözüm?


40

Android belgelerinde diyor ki:

EGL oluşturma içeriğinin kaybedileceği durumlar vardır. Bu genellikle cihaz uyuduktan sonra uyandığında meydana gelir. EGL içeriği kaybolduğunda, o bağlamla ilişkilendirilmiş tüm OpenGL kaynakları (dokular gibi) otomatik olarak silinir. Oluşturmayı doğru tutmak için bir oluşturucunun hala ihtiyacı olan kaybolan kaynakları yeniden oluşturması gerekir. OnCurfaceCreated (GL10, EGLConfig) yöntemi, bunu yapmak için uygun bir yerdir.

Ancak, OpenGL bağlamındaki tüm dokuları yeniden yüklemek zorunda kalmak hem bir acıdır hem de bir duraklamadan sonra uygulamayı yeniden girerken kullanıcı için oyun deneyimine zarar verir. "Angry Birds" in bir şekilde bundan kaçındığını biliyorum, aynı şeyi nasıl gerçekleştireceğine dair öneriler arıyorum.

Android NDK r5 (CrystaX sürümü.) İle çalışıyorum. Sorunun olası bu hackünü buldum ama özel bir SDK sürümü oluşturmaktan kaçınmaya çalışıyorum.


Uykuya dalma ve uyanma cihaza atıfta bulunur, bu nedenle kullanıcı oyununuzu duraklatırken veya işlemlerinizi değiştirirken EGL bağlamından herhangi birini kaybetmelidir.
Ali1S232

Yanıtlar:


22

Replica Island, bu sorunla ilgilenen GLSurfaceView'ın değiştirilmiş bir sürümüne sahiptir (ve daha önceki Android sürümleriyle çalışır). Chris Pruett'e göre :

Temel olarak, çok spesifik bir problemi çözmek için orijinal GLSurfaceView'ü kapattım: Tüm OpenGL durumumu atmadan, uygulamamdaki farklı Aktivitelere gitmek istedim. En büyük değişiklik EGLSurface’i EGLContext’ten ayırmak ve eski olanı Pause () ’a atmaktı, fakat ikincisi bağlam açıkça kaybolana kadar korudu. GLSurfaceView'ın varsayılan uygulaması (bu arada yazmadım), etkinlik duraklatıldığında tüm GL durumlarını atar ve devam ettirildiğinde SurCurted () ifadesini çağırır. Bu, oyunumda bir iletişim kutusu açıldığında, tüm dokuların yeniden yüklenmesi gerektiğinden, kapanışta gecikme yaşandığı anlamına geliyordu.

Varsayılan GLSurfaceView kullanmalısınız. Madende aynı işleve sahip olmanız gerekiyorsa, benimkine bakabilirsiniz. Ancak yaptığım şeyi yapmak bazı ahizelerde her türlü korkunç sürücü hatasını açığa çıkardı (bu dosyanın sonundaki çok uzun yorumu görün) ve yalnızca varsayılan olanı kullanarak tüm bu karışıklıkları önleyebilirsiniz.

Düzenleme: Ben zaten benzer bir hack için bağlantı yayınladığını fark ettim. Petekten önce herhangi bir yerleşik çözüm olduğunu sanmıyorum. Replica Island, birçok cihaz üzerinde çalışan popüler bir oyundur ve Chris'in uygulamasını ve yorumlarını faydalı bulabilirsin.


1
Bunu atlatmaya yönelik çeşitli yaklaşımları denedikten sonra, en iyi çözümün sadece içeriği yeniden oluşturmak için uygulamayı yeniden kodlamak olduğuna karar verdim. Bu çok israf edici bir yaklaşım ama iyi bir çözüm yok gibi görünmüyor code.google.com/p/android/issues/detail?id=12774
Nick Gotch

9

Chris Pruett (Replica Island, Wind-Up Knight, vb.) Tarafından bir veya iki yıl önce bana iletilen buna başka bir cevap daha eklemek istiyorum. SetPreserveEglContextOnPause (true) 4.3'te işe yaramadığı için 2013'te özellikle faydalıdır. (Bu konuda yanılmış olabilirim ama 2011'de en son dokunulan oyun kodunu güncellerken şu anda bana öyle geliyor.)

Temel olarak, hile GLSurfaceView'ınızı Aktivite'in onPause () görünümündeki hiyerarşisinden ayırmaktır. OnPause () çalıştırma noktasındaki hiyerarşi görünümünde olmadığı için, içerik asla bozulmaz.

Dolayısıyla, Aktivitenizin onPause () yöntemi şunun gibi görünmeli:

@Override
public void onPause() {
    view.setVisibility(View.GONE);
    super.onPause();
    ...
}

Ve GLSurfaceView'ınızı onResume () 'dan değil onWindowFocusChanged ()' den hiyerarşiye geri yüklersiniz :

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    if (hasFocus && view.getVisibility() == View.GONE) {
         view.setVisibility(View.VISIBLE);
    }
    ...
}

Asla GLSurfaceView's'ın onPause () ve onResume () kodlarını çağırmayacağınızı ve bunun resmi SDK GLSurfaceView olduğunu, hiçbir kesilmiş alternatif versiyonun gerekli olmadığını unutmayın.


Aslında bu yaklaşım işe yaramadı. Chris Pruett, Unity ile birlikte kullandı, bu geçici çözümün yerel projelerde çalışmaması mümkün mü? Ama sadece GLView.onPause () 'u çağırmamak işe yarıyor! Bunu onaylayabilecek başkaları var mı?
sjkm

Android 2.2 OpenGl ES 2 hedefli benim için çalıştı. Diğer cihazlarda nasıl performans gösterdiğinden emin değil. Bir LG G2 D802 telefonum var. Bunun genel bir çözüm olup olmadığını bilen var mı?
Piksel

7

<Rant> Ben birçok farklı çözümler çalıştı, bu problem üzerinde zaman büyük miktarda geçirdi ve bugün, bu ben bile görülen en korkunç tasarım kararı biri olduğunu düşünüyorum dek hiçbiri çalıştı, ama değilim, Android ekibi gelen gerçekten şaşırdım. </ rant>

Dolayısıyla, çözüm eglContext üyesini yukarı doğru hareket ettirmek ve onu statik (global) yapmaktır, böylece imha edilmeyecektir, o zaman tekrar oluşturmadan önce boş olup olmadığını kontrol etmeniz gerekir.

Şimdiye dek bu çözüm bizim için işe yarıyor gibi görünüyor ve 2005 cihazlarını kırıp bozmadığı umrumda değil.


4

Petek API kullanın. OGL içeriğinizi korumak için bir seçenek var. Aksi takdirde, içeriğinizi yeniden yüklemeniz gerekir. Zor ya da acı verici değil.

İki vaka olduğunu anlamanız gerekir (Android 2.1):

  • Ekran Duraklat: uygulamanız her zaman en ön sıradadır => hack kullanılabilir
  • Uygulama Duraklatma: başka bir ön uygulama daha var => Çözüm yok

Not: Eski android gpus çoklu bağlamı desteklemiyor. Bu nedenle, başka bir uygulamaya geçtiğinizde opengl bağlamı kaybolur => çözüm yok (bağlam duraklatmayı ekran duraklatması ile koruyabilirsiniz).

Not 2: HoneyComb işlevi setPreserveEGLContextOnPause


1
İçeriği kolayca yeniden yüklemek için tasarlanmamış olan Android NDK'ya bir C ++ oyunu taşıyorum, bu yüzden en azından benim için biraz zor. Bir kenara bırakmanın zorlukları, dokuların yeniden yüklenmesi diğer cihazlarımızda bulunmayan bir gecikmeye neden olacak (iPhone, PSP, DS, vb.) Petek düzeltmelerini duyduğuma sevindim ama ne yazık ki 2.1+ desteklememiz gerek
Nick Gotch

1
Bu onun sorusuna hiç cevap vermiyor.
48'de notlesh

1
Eğer anlamıyorsan, yapamazsın.
Ellis,

2

Buradaki cevapların bazıları Android'de OpenGL ES'nin erken kullanımları için uygundur. İlk GLES cihazları sadece tek bir içeriği destekledi, bu yüzden GLSurfaceView durumu agresif bir şekilde atmak için tasarlandı. GLSurfaceView'ı başka türlü yapmaya ikna etmek kolay değildir.

Daha yeni Android sürümleri için (muhtemelen GLES 2.x kullanan herhangi bir şey), en iyi yanıt düz bir SurfaceView kullanmak ve kendi EGL ve iş parçacığı yönetiminizi yapmaktır. Sen gles birden örnekler düz SurfaceView ile kullanılabilir bulabilirsiniz Grafika EGL bağlamlar yaratılarak ve öldürmeye yarayan basit sınıfların bir kütüphane de dahil olmak üzere.

Bir uygulama arka plana girdiğinde durumu boşaltmak yine de iyi bir uygulamadır, ancak örneğin Chris Pruett'ten - uygulamanın hala ön planda olduğu, ancak GLSurfaceView'ı barındıran Etkinlik'in uzak olduğu - yırtılmanın hiçbir değeri yok bağlamda aşağı.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.