2014-10-02 7 views
14

Rysuję animację, korzystając z podwójnie buforowanego interfejsu GDI w oknie, w systemie, w którym włączono kompozycję DWM, i wyświetlając wyraźnie widoczne na ekranie tearing. Czy istnieje sposób, aby temu zapobiec?Czy można zapobiec powstawaniu artefaktów podczas rysowania za pomocą interfejsu GDI w oknie z kompozycją DWM?

Szczegóły

Animacja trwa ten sam obraz, i przenosi go od prawej do lewej na ekranie; liczba pikseli w pikselach jest określona na podstawie różnicy między bieżącym czasem i czasem rozpoczęcia animacji a czasem zakończenia, aby uzyskać ułamek kompletny, który zostanie zastosowany do szerokości całego okna, przy użyciu timeGetTime z 1ms resolution. Animacja rysuje w pętli bez przetwarzania komunikatów aplikacji; wywołuje metodę (biblioteki VCL), która wewnętrznie unieważnia, a następnie wywołuje UpdateWindow dla danego okna, wywołując bezpośrednio w procedurze wiadomości z numerem WM_PAINT. Implementacja VLC programu obsługi farb używa BeginBufferedPaint. Malowanie samo w sobie jest podwójnie buforowane.

Celem tego jest uzyskanie jak największej liczby klatek na sekundę, aby uzyskać płynną animację na ekranie. (Rysunek korzysta z podwójnego buforowania, aby usunąć migotanie i zapewnić, że cały obraz lub ramka jest jednocześnie wyświetlany na ekranie.Nie powoduje to anulowania i aktualizacji bezpośrednio przez wywoływanie w procedurze wiadomości, bez wykonywania innych procesów przetwarzania wiadomości. np. BeginBufferedPaint) dla kompozycji Aero.) W tym przypadku malowanie odbywa się w kilku wywołaniach BitBlt (jeden po lewej stronie animacji, tj. co się porusza poza ekranem, a drugi po prawej stronie animacji, czyli co się porusza na ekranie.)

Podczas oglądania animacji wyraźnie widać tearing. Ta sytuacja występuje w systemach Windows Vista, 7 i 8.1 w wielu systemach z różnymi kartami graficznymi.

Moje podejście do tego problemu polegało na zmniejszeniu tempa rysowania lub próbie oczekiwania na VSync przed ponownym malowaniem. To może być niewłaściwe podejście, więc odpowiedź na to pytanie brzmi: "Zrób coś zupełnie innego: X". Jeśli tak, to świetnie :)

(Co ja naprawdę chciałbym jest sposobem, aby zapytać DWM komponować/używać tylko w pełni pomalowanych klatek dla tego konkretnego okna.)

Próbowałem następujące metody , z których żaden nie usuwa widocznych łez. Dlatego pytanie brzmi, Czy można uniknąć łzawienia podczas używania kompozycji DWM, a jeśli tak, to w jaki sposób?

Podejścia próbowałem:

  • Pierwsze częstotliwość odświeżania monitora poprzez GetDeviceCaps(Application.MainForm.Handle, VREFRESH); spanie dla 1/częstości odświeżania milisekund. Nieznacznie poprawiłem malowanie tak szybko, jak to możliwe, ale może to być pobożne życzenie. Perceptualnie nieco mniej płynna szybkość animacji. (Wariacje: normalny Sleep i wysokiej rozdzielczości spin-czekać użyciu timeGetTime).

  • Korzystanie DwmSetPresentParameters spróbować ograniczyć aktualizację do tej samej szybkości, z jaką kod rysuje. (Wariacje: wiele buforów (cBuffer = 8) (brak widocznego efektu), określanie źródła częstotliwości odświeżania monitora/1 i spanie przy użyciu powyższego kodu (tak samo, jak po prostu próbowanie metody spania), określenie odświeżania na klatkę 1, 10 itd. (Brak widocznego efektu), zmiana zasięgu ramki źródłowej (brak widocznego efektu).)

  • Korzystanie DwmGetCompositionTimingInfo w różny sposób:

      • Podczas cFramesPending> 0, wirowania;
      • Get cFrame (rama składa) i spin natomiast liczba ta nie ulega zmianie;
      • Get cFrameDisplayed i korkociąg natomiast nie zmienia;
      • Obliczanie czasu na sen, aby dodając qpcVBlank + qpcRefreshPeriod, a następnie podczas QueryPerformanceCounter zwraca czas mniejszy niż ten, spin
  • Wszystkie te podejścia zostały również zmieniać poprzez malowanie , następnie wirując/śpiąc przed ponownym malowaniem; lub odwrotnie: spanie, a następnie malowanie.

Kilka wydaje się mieć jakikolwiek widoczny efekt, a efekt, który trudno jest zakwalifikować, może wynikać z mniejszej liczby klatek na sekundę. Żaden nie zapobiega rozdzieraniu, tzn. Nie powoduje, że DWM tworzy okno z "pełną" kopią zawartości DC okna.

Porady ceniona :)

+1

GDI jest stary i chrupiący, a nie do płynnej animacji. Może wypróbujesz Direct2D? –

+1

@ JonathanPotter Dobry punkt. Jednym z ograniczeń, którym jestem nie jest korzystanie z DX jakiegokolwiek rodzaju - jednym z powodów jest liczba platform i brak wymagań, na końcu potrzebny jest końcowy kod. (Nie wszystkie są nowoczesnymi systemami Windows.) Być może pomocny kod DX tylko wtedy, gdy Aero istnieje ...? Musiałby jednak płynnie przełączać się do iz GDI/DX bez widocznych zakłóceń, ponieważ włącza/wyłącza animację. Czy to jest możliwe? –

+0

Może mógłbyś napisać klasę pomocniczą rysunku, która używa DX, jeśli jest dostępna i w przeciwnym razie wraca do GDI. Byłoby dość rzadkie, aby znaleźć system, który nie obsługuje Direct3D, chociaż nawet jeśli nie D2D. –

Odpowiedz

2

Ponieważ używasz BitBlt, upewnij się, że forsa są 4 bajty/pixel. Z 3 bajtami/piksel, GDI jest strasznie wolny podczas działania DWM, które może być źródłem twojego łzawienia. Kolejny problem, na który natknąłem się, jeśli twój DIB jest nieco większy, niż wywołanie BitBlt, zajmuje nieoczekiwanie długi czas. Jeśli podzielisz jedno połączenie na mniejsze, a nie tylko narysujesz część danych, może to pomóc. Oba te elementy pomogły mi w mojej sprawie, tylko dlatego, że sama usługa BitBlt działała zbyt wolno, co prowadziło do artefaktów wideo.

+0

Na wszelki wypadek: nie zapomnij zaktualizować tylko dirty rect (GetUpdateRect) zamiast całego okna ... – Jurlie

Powiązane problemy