2012-05-08 31 views
9

Dikey senkronize edilmiş işlemler yapmaya çalışıyorum, böylece herhangi bir kareyi atlamadan veya yinelemeden, dikey senkronizasyon başına tam olarak bir işlem yapılır. Ben (gelecekte) Windows'u Windows 7 altında çalışacak ve bu gerekir 8. Temelde orijinal görüntülerden bir piksel 1 eşleşecek şekilde ekrana uyabilecek QUADS dizisi çizim oluşacakDikey eşitlemede her tam olarak nasıl bir işlem yapılır (tekrarlama yok, atlama yok)?

: 1 bir Ekrandaki piksel. İşleme parçası, OpenGL veya DirectX ile bir sorun değildir. Sorun doğru senkronizasyon.

daha önce çekilmesi ve daha sonra) bir glFlush (birlikte bu iki talimatları tüm kombinasyonlarını ve permütasyon güvenilir

SwapBuffers(g_hDC); 
glFinish(); 

arayarak, WGL_EXT_swap_control uzantılı, OpenGL kullanarak güvenilir ve güvenilir değildir.

Sonra çekilmesi ve daha sonra g_pSwapChain bir IDXGISwapChain* ve pOutput bu SwapChain bağlantılı IDXGIOutput* olduğu

g_pSwapChain->Present(1, 0); 
pOutput->WaitForVBlank(); 

arayarak, Direct3D 10 çalıştı.

Her iki sürümde, OpenGL ve Direct3D, sonuçta ortaya çıkar: 60 karelik ilk dizi, ne gerekiyorsa dayanmaz (60hz'de yaklaşık 1000ms yerine, 1030 veya 1050 ms gibi bir şey sürer), Aşağıdakiler iyi çalışıyor (yaklaşık 1000.40 ms), ama her şimdi ve sonra bir kare atlamak gibi görünüyor. Ölçümü QueryPerformanceCounter ile yapıyorum.

Direct3D'de, yalnızca WaitForVBlank'ın bir döngüsünü denerken, 1000 yineleme süresi tutarlı bir şekilde 1000.40 küçük bir değişkedir.

Buradaki sorun, tam olarak geri dönüş adı verilen işlevlerin ne zaman olduğunu ve takasın dikey senkronizasyon sırasında (daha önce değil, yırtılmayı önlemek için) yapılıp yapılmadığını bilmemektedir.

İdeal olarak (eğer yanılmadıysam), istediğimi elde etmek için, bir render gerçekleştirmek, senkronizasyon başlatana kadar beklemek, senkronizasyon sırasında takaslamak ve ardından senkronizasyon tamamlanana kadar beklemek olacaktır. OpenGL veya DirectX ile nasıl yapılır?

Düzenleme: sadece WaitForVSync 60x bir deney döngü 1000.30ms gelen 1000.50ms tutarlı sürer. Present(1,0) ile aynı döngüde, başka hiçbir şey olmadan, görüntü oluşturma işlemi aynı zamanda gerçekleşmez, ancak bazen bir çerçeve tekrarlanıyormuş gibi 1017 ms alır ve başarısız olur. Görüntü yok, burada yanlış bir şeyler var.

cevap

0

Bir Direct3D aygıtı oluştururken, D3DPRESENT_PARAMETERS yapısının PresentationInterval parametresini D3DPRESENT_INTERVAL_DEFAULT olarak ayarlayın.

+0

Bu DX10'da da var mı? Aygıtı, D3D10CreateDeviceAndSwapChain' ile oluşturduğumda, herhangi bir Mevcut Parametre bulunmadığını söyleyebilirim. – slazaro

+0

Korkarım ki DX10 bu seçeneğe sahip değil. Üzgünüm, DX10'a pek değmem. – miloszmaki

+1

Aslında bunu da ayarlamak istiyoruz: D3DPRESENT_INTERVAL_ONE ... ve D3D10, şu anki yöntemi 'swapChain-> Present (vSync, 0); – zezba9000

2

daha önce çekilmesi ve daha sonra çağrı

SwapBuffers(g_hDC); 
glFinish(); 

O glFinish() veya glFlush gereksiz göre, WGL_EXT_swap_control uzantılı, OpenGL kullanarak çalıştı. SwapBuffers bir glFinish anlamına gelir.

Grafik sürücüsü ayarlarınızda "V-Blank/V-Sync kapalı" seçeneğini ayarlamanız mümkün mü?

+0

Her uygulama her ne seçerse ayarlanır. Yaptığım işlemler dikey boşluk için daha fazla veya daha az senkronizasyon yapıyor, ancak sorun, çoğunlukla (çoğunlukla) boş işleyicilerle tutarlı olmamasıdır. – slazaro

+0

@slazaro: Bunu nasıl ölçüyorsun? Boş bir render ile kullanabileceğinin göstergesi yok. Sistem zamanlayıcısını kullanıyorsanız, bunun her zaman V-Senkronizasyon aralığının etrafında titremesinin farkında olmalısınız, hiçbir zaman tam olarak vurmuyor – datenwolf

+0

Sadece bir WaitForVBlank döngüsüne sahip olduğumda, DirectX ile sürekli olarak işaretler. Aynı zaman, küçük bir varyasyon ile, 1 ms'den az. Öte yandan, vsync aktif hale getirilmiş bir render ve swapbuffer ile, her render iki kare (~ 33.3ms) almak dışında, yaklaşık 16.6ms alır. Bu uzun renderlemeyi (vsync olmadan 60x'lik bir döngü 30ms gibi alır) harcadığımda, bazı güvenilmezlik var ve bence zamanlayıcıların hassasiyetine göre daha fazla suçlanabilir. – slazaro

3

DX11'de aynı sorunu yaşıyorum. Birden çok arabelleğe alma gecikmesini önlemek için çerçeve oluşturma kodumun monitör yenileme hızının tam bir katını almasını garanti ediyorum.

Sadece pSwapChain->present(1,0) numaralı telefonu aramak yetmez. Bu, tam ekran modunda yırtılmasını önler, ancak vblank'ın gerçekleşmesini beklemez. Mevcut çağrı eşzamansızdır ve doldurulması gereken çerçeve arabellekleri varsa hemen döner. Dolayısıyla render kodunuz çok hızlı bir şekilde yeni bir çerçeve üretiyorsa (herşeyi işlemek için 10ms deyin) ve kullanıcı sürücünün "Önceden oluşturulmuş maksimum çerçeveleri" 4 olarak ayarladıysa, kullanıcının gördüğü şeyden dört kare oluşturacaksınız. Bu, fare eylemi ile ekran yanıtı arasında kabul edilemez olan 4 * 16,7 = 67 ms gecikme anlamına gelir. Sürücünün ayarlarının kazanacağına dikkat edin - uygulamanızın pOutput->setMaximumFrameLatency(1) numaralı telefonunu sorsa bile, 4 çerçeveden bağımsız olarak faydalanabilirsiniz. Böylece, sürücü ayarından bağımsız olarak fare gecikmesini garanti etmenin tek yolu, render döngüsünüzün bir sonraki dikey yenileme aralığına kadar gönüllü olarak beklemesidir, böylece bu ekstra frameBuffer'ları asla kullanmazsınız. Bu amaç için tasarlanmıştır. Ama bu çalışmıyor! Ben

<render something in ~10ms> 
pSwapChain->present(1,0); 
pOutput->waitForVBlank(); 

aşağıdaki arayıp waitForVBlank() çağrı dönmek için gereken süreyi ölçmek, ben kabaca, o 6ms ve 22MS arasındaki alternatif görüyorum.

Bu nasıl olabilir? waitForVBlank()'un tamamlanması 16.7 ms'den daha uzun sürebilir mi? DX9'da, kendi sorunumuz olan waitForVBlank'ın kendi versiyonunu uygulamak için getRasterState() kullanarak bu problemi çözdük. Ancak bu çağrı DX11'de kullanımdan kaldırıldı.

Çerçevemin monitörün yenileme hızıyla tam olarak hizalanmasını garanti etmenin başka bir yolu var mı? Mevcut tarama hattını getRasterState gibi yapmak için kullanılan başka bir yol var mı?

-1

Çekirdek modunda veya ring-0'da çalışıyorsanız, VGA input register (03bah, 03dah) öğesinden bit 3'ü okumayı deneyebilirsiniz. Bilgi oldukça eskidir ancak bitin konumu değişmiş olabilir veya Windows 2000 ve sonraki sürümlerinde kaldırılmış olabilir hinted here olmasına rağmen, aslında bu konuda şüpheliyim. İkinci bağlantıda, eski Windows sürümleri için vblank sinyalini açığa çıkarmaya çalışan çok eski bir kaynak kodu vardır. Artık çalışmıyor, ancak teoride en son Windows SDK ile bunu yeniden kurmanız gerekiyor.

Zor kısmı, bu bilgileri güvenilir bir şekilde gösteren ve ardından uygulamanızdan getirilen bir aygıt sürücüsü oluşturmak ve kaydetmek.

1

Şu anda DX9 kullanıyoruz ve DX11'e geçmek istiyoruz. Ekrana manuel olarak senkronize etmek için şu anda GetRasterState() kullanıyoruz. Bu DX11'de gider, ancak DirectDraw7 cihazının DX11'i bozmadığını görüyorum. Yani bunu sadece kodunuza ekleyin ve tarama pozisyonunu almanız gerekir. Windows 8.1'de ve Windows 10 üzerinde

IDirectDraw7* ddraw = nullptr; 
DirectDrawCreateEx(NULL, reinterpret_cast<LPVOID*>(&ddraw), IID_IDirectDraw7, NULL); 
DWORD scanline = -1; 
ddraw->GetScanLine(&scanline); 
1

, sen DXGI 1.3 DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT yararlanabilirler. Bakınız MSDN. Buradaki örnek, Windows 8 Store uygulamaları içindir, ancak sınıf Win32 windows swapchains'e de uyarlanabilir olmalıdır.

Bu video'u da yararlı bulabilirsiniz.