OpenGL'nin ekranı gerçekten güncellemesi ne kadar sürer?


9

C tuş girdisine yanıt olarak farklı şeyler çizen basit bir OpenGL test uygulamam var. (Mesa 8.0.4, Mesa-EGL ve GLFW, Ubuntu 12.04LTS ile NVIDIA GTX650 yüklü bir bilgisayarda çalıştı). Çekilişler oldukça basit / hızlı (dönen üçgen tipi şeyler). Test kodum kare hızını kasıtlı olarak herhangi bir şekilde sınırlamaz, sadece şöyle görünür:

while (true)
{
    draw();
    swap_buffers();
}

Bunu çok dikkatli bir şekilde zamanladım ve bir eglSwapBuffers()(veya glfwSwapBuffersaynı şey) çağrısından diğerine kadar geçen sürenin ~ 16.6 milisaniye olduğunu görüyorum . Bir çağrıdan eglSwapBuffers()sonraki bir sonraki çağrıya kadar geçen süre, çizilen şey çok basit olsa da, bundan biraz daha azdır. Takas arabelleklerinin çağrıldığı süre 1 ms'nin altındadır.

Bununla birlikte, uygulamadan tuşa basmakla çizdiklerini değiştiren , ekranda gösterilen değişikliğe kadar geçen süre> 150 ms'dir (yaklaşık 8-9 kare değerinde). Bu, 60fps'de ekranın ve klavyenin kamera kaydı ile ölçülür.

Bu nedenle, sorular:

  1. Arabellekleri değiştirmek için yapılan bir çağrı ile gerçekte ekranda gösterilmek üzere arabellekler nerede bulunur? Gecikme sebebi? Uygulama her zaman ekranın önünde birçok kare çiziyor gibi görünüyor.

  2. Bir OpenGL uygulaması derhal ekrana çekmek için ne yapabilir? (yani: tamponlama yok, sadece çizim tamamlanana kadar engelle; Yüksek verime ihtiyacım yok, düşük gecikmeye ihtiyacım var)

  3. Bir uygulama yukarıdaki acil çekilişi olabildiğince hızlı yapmak için ne yapabilir?

  4. Bir uygulama şu anda ekranda ne olduğunu nasıl bilebilir? (Ya da, geçerli arabelleğe alma gecikmesinin kaç kare / kaç kare olduğu?)


Klavyenin uygulamanızı bildirmesi için gereken süreyi bunu gerçekleştirmek için gereken süreye ayırabilir misiniz?
ThorinII

@ThorinII: Adil nokta. Muhtemelen uygulamanın gerçekte ne zaman tuşa basıldığının bir göstergesini almak için paralel bir bağlantı noktasında bir LED kullanarak hacky bir şey kurabilirim. Yine de, sadece fgetc (stdin), bu ne kadar yavaş olabilir? : /
Alex I

Tüm komutların hemen temizlenmesine neden olmak için glFlush'ın kullanıldığı izlenimi altındaydım.
Programmdude

1
@AlexI bu gamedev.stackexchange.com/questions/66543/… size yardımcı olabilir kontrol edin
concept3d

1
@ concept3d: Evet, temel olarak cevaplandı, sadece biraz daha fazla rep istediğinizi düşündüm :) Görünüşe göre bunu vermek için bir gün beklemek zorundayım.
Alex

Yanıtlar:


6

CPU'dan çağrılan herhangi bir çizim API işlevi, daha sonra GPU tarafından yürütülecek olan GPU komut halkası arabelleğine gönderilir. Bu, OpenGL işlevlerinin çoğunlukla engellemeyen işlevler olduğu anlamına gelir. Böylece CPU ve GPU paralel olarak çalışacaktır.

Dikkat edilmesi gereken en önemli şey, uygulamanızın CPU veya GPU'ya bağlı olabileceğidir. glFinish'i çağırdığınızda, CPU GPU'nun çizim komutlarını tamamlamasını beklemelidir, eğer GPU daha fazla zaman alıyorsa ve CPU'nun durmasına neden oluyorsa / uygulamalarınız GPU'ya bağlıdır. GPU komutları çizmeyi bitirirse ve CPU'nun glFinish için çok uzun sürmesi durumunda, uygulamanız CPU'ya bağlıdır.

Ve glFlushve arasında bir fark olduğunu unutmayın glFinish.

glFlush: daha önce GL'ye gönderilmiş olan tüm komutların sınırlı bir sürede tamamlanması gerektiğini belirtir.

glFinish: önceki tüm GL komutlarını tamamlamaya zorlar. GL istemcisi ve sunucu durumu ve çerçeve arabelleği üzerinde daha önce verilen komutlardan gelen tüm efektler tam olarak gerçekleşinceye kadar Finish geri dönmez. "

glXSwapBuffers , geri dönmeden önce örtük bir glFlush gerçekleştirir. Sonraki OpenGL komutları glXSwapBuffers çağrıldıktan hemen sonra verilebilir, ancak arabellek değişimi tamamlanana kadar yürütülmez.

Gerçek kare süresi büyük olasılıkla iki CPU / GPU'nun hangisinin çalışmasını tamamlamak için daha fazla zaman alacağına göre belirlenir.


Bu çok yardımcı. Bazı olası düzeltmeler: opengl.org/sdk/docs/man2/xhtml/glXSwapBuffers.xml "glXSwapBuffers dönmeden önce örtülü bir glFlush gerçekleştirir" bu aslında bir glFinish yapmaz, bu yüzden komut arabelleği oldukça fazla olabilir takas arabellekleri döndüğünde içindeki şeyler.
Alex I

... Ayrıca, en ilginç nokta benim çok basit test uygulaması ne CPU GPU sınırlı değil - ne burada yapacak çok iş var - ama başka bir şey, bir şekilde her iki düşük framerate (monitör ile aynı yenileme hızı ??) ve yüksek gecikme (komut tamponu nedeniyle, aslında bu kısmı oldukça iyi açıkladınız).
Alex

@AlexI both low framerate (exactly same as monitor refresh rate??no açıkça VSync kullanmadığınız sürece.
concept3d

@AlexI Ayrıca kare süresinin FPS'den farklı olduğunu belirtmek istiyorum, doğrusal olduğu için uygulamanızı profillemek için kare zamanını kullanın. Öte yandan FPS, doğrusal olmayan zayıf bir ölçümdür.
concept3d

Açıkça vsync kullanmıyorum. Varsayılan vsync ayarlarını değiştirmek için hiçbir şey yapmıyorum, OpenGL'deki ayarları nerede değiştireceğimi bile bilmiyorum. Tam olarak 60 fps alıyorum (yüzde içinde).
Alex I

4

OpenGL hiçbir zaman ekranı teknik olarak güncellemez.

Bunu yapan GL'den ayrı bir pencere sistemi API'si vardır (örn. GLX, WGL, CGL, EGL). Bu API'leri kullanan arabellek değişimleri genellikle örtük olarak çağrılır, glFlush (...)ancak bazı uygulamalarda (örn. Windows'ta GDI rasterizer) bir tam yapar glFinish (...):

 

    * Sol tarafta, ICD (donanım) yolu vardır SwapBuffers (...). Sağ tarafta, GDI (yazılım) yolu.

VSYNC'yi etkinleştirdiyseniz ve çift arabelleğe aldıysanız, bekleyen bir takas gerçekleşmeden önce arka arabelleği değiştirecek herhangi bir komutun takas haline gelene kadar durması gerekir . Komut kuyruğunda sınırlı bir derinlik vardır, bu nedenle bu durdurulmuş komut sonunda boru hattında trafik sıkışıklığına neden olur. Bu SwapBuffers (...), uygulamanızın engellenmesi yerine, VBLANK yuvarlanana kadar ilgisiz bazı GL komutlarını engellediği anlamına gelebilir . Gerçekten kaynar olan şey, takas zincirinizde kaç tane arka tampon bulunduğudur.

Tüm arka tamponlar henüz öne taşınmamış bitmiş çerçevelerle dolu olduğu sürece, takas tamponları dolaylı olarak engellemeye neden olur. Ne yazık ki, çoğu GL pencere sistemi API'si tarafından kullanılan arka tamponların sayısını açıkça kontrol etmenin bir yolu yoktur ( 0 tek tamponlu veya 1 çift ​​tamponlu dışında). Sürücü isterse 2 arka tampon kullanmakta serbesttir (üçlü tamponlama), ancak bunu GLX veya WGL gibi bir şey kullanarak uygulama düzeyinde talep edemezsiniz.


Andon: İyi bilgi, teşekkürler. Ben ne görüyorum kısmen çift tamponlama olduğunu düşünüyorum, ama: "takas oluşmadan önce arka tampon değiştirme girişimi engellemek gerekir" - neden? takas dahil her şey komut arabelleğine gönderilebilir gibi görünüyor :)
Alex I

"çoğu GL pencere sistemi API'si tarafından kullanılan arka tamponların sayısını açıkça kontrol edin (0 tek tamponlu veya 1 çift tamponlu dışında)" Biri tek / çift tamponlu nasıl kontrol edilir?
Alex

@AlexI: Komutun neden engellemeye yol açabileceğine dair dili açıkladım. Diğer API'lerde oluşturma komutu olarak bilinen ve etkili bir şekilde komut kuyruğunun derinliği olan bir kavram vardır. Tek / çift arabelleğe alınmış denetime gelince, bu, oluşturma bağlamınızı oluştururken seçtiğiniz piksel biçimiyle denetlenir. WGL'de, tek veya çift arabelleğe alınmış seçebilirsiniz, ancak çift arabelleğe alınmış seçeneğini belirlerseniz, kullanıcı sürücüsünü bunu yapmak için ayarladığında sürücü aslında 2 arka tampon oluşturabilir (böylece çift arabelleğe alma üçlü arabelleğe alma haline gelir).
Andon M. Coleman

Aslında çok fazla kare oluşturmak istemezsiniz, çünkü bu engellemeyi azaltırken gecikmeyi de artırır. Gecikmeyi en aza indirmenin en iyi yolu, glFinish (...)arabellekleri değiştirdikten hemen sonra çağırmaktır . Bu, komut kuyruğunu temizler, ancak aynı zamanda GPU ve CPU'nun senkronize edileceği anlamına gelir (GPU'nun her zaman çalışmasını sağlamak istiyorsanız iyi değildir).
Andon

1

Bu deneye aşina olduğunu varsayıyorum ?

Esasen John Carmack benzer bir şey yapıyordu, ekranı kaydediyor ve ekrana gönderilen zamanlama piksellerini kaydediyordu. Ekrandan gecikmenin büyük bir kısmının geldiğini buldu. Diğer faktörler klavyeden giriş gecikmesi, video sürücüleri ve / veya programın kendisinin yürütülmesiydi.

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.