Я рисую анимацию с использованием двойного буферизированного GDI в окне, в системе, где включен состав DWM, и видя наглядно видимый tearing на экране. Есть ли способ предотвратить это?
Подробнее
Анимация принимает одно и то же изображение и перемещает ее справа налево по экрану; количество пикселей в поперечнике определяется разницей между текущим временем и временем начала анимации и временем до конца, чтобы получить полную донную часть, которая применяется ко всей ширине окна, используя timeGetTime с разрешением 1 мс. Анимация рисует в цикле без обработки сообщений приложения; он вызывает метод (VCL library) Repaint, который внутренне отменяет действие, а затем вызывает UpdateWindow для окна, непосредственно вызывающего процедуру сообщения с помощью WM_PAINT. В реализации VCL обработчика краски используется BeginBufferedPaint. Картина сама по себе является двойной буферизацией.
Целью этого является максимально возможная частота кадров, чтобы получить гладкую анимацию по экрану. (Чертеж использует двойную буферизацию для удаления мерцания и для обеспечения того, чтобы все изображение или кадр были на экране в любой момент времени. Он недействителен и обновляется напрямую, вызывая процедуру сообщения, не выполняя другую обработку сообщений. Живопись выполняется с использованием современных методов ( например BeginBufferedPaint) для композиции Aero.) В этом случае живопись выполняется в нескольких битовых вызовах (одна для левой стороны анимации, то есть перемещение за кадром, и одна для правой части анимации, то есть движущаяся на экране. )
При просмотре анимации отчетливо видна tearing. Это происходит в Windows Vista, 7 и 8.1 на нескольких системах с различные видеокарты.
Мой подход к обработке заключается в уменьшении скорости его рисования или попытке дождаться VSync до рисования снова. Это может быть неправильный подход, поэтому ответ на этот вопрос может быть "Сделать что-то еще полностью: X". Если да, то отлично:)
(Мне бы очень хотелось, чтобы попросить DWM составить/использовать только полностью раскрашенные кадры для этого конкретного окна.)
Я пробовал следующие подходы, ни один из которых не удаляет все видимые разрывы. Поэтому возникает вопрос: возможно ли избежать разрыва при использовании состава DWM, и если да, то как?
Подходы:
-
Получение частоты обновления монитора с помощью
GetDeviceCaps(Application.MainForm.Handle, VREFRESH); сон за 1/частота обновления миллисекунд. Немного улучшена окраска как можно быстрее, но может быть желаемое за действительное. Восприимчивость немного менее плавная. (Tweaks: normalSleepи спин-жду с высоким разрешением с использованиемtimeGetTime.) -
Используя
DwmSetPresentParameters, чтобы попытаться ограничить обновление с той же скоростью, на которую рисует код. (Вариации: много буферов (cBuffer = 8) (без видимого эффекта), указав скорость источника обновления монитора /1 и спящий режим с использованием вышеуказанного кода (так же, как и просто попытка спящего подхода), указав обновление на кадр 1, 10 и т.д. (Без видимого эффекта), изменение покрытия исходного кадра (отсутствие видимого эффекта.) -
Используя
DwmGetCompositionTimingInfoразличными способами:-
- Пока
cFramesPending> 0, spin;
- Пока
-
- Получить
cFrame(скомпонованный кадр) и открутить, пока это число не изменится;
- Получить
-
- Получить
cFrameDisplayedи открутить, пока это не изменится;
- Получить
-
- Вычисление времени для спящего путем добавления
qpcVBlank + qpcRefreshPeriod, а затем, покаQueryPerformanceCounterвозвращает время меньше этого, вращение
- Вычисление времени для спящего путем добавления
-
-
Все эти подходы были также изменены живописью, а затем спиннинг/сон, прежде чем снова рисовать; или наоборот: спать, а затем рисовать.
Немногие, похоже, имеют какой-либо видимый эффект, и какой эффект есть, трудно квалифицировать и может быть просто результатом более низкой частоты кадров. Ничего не мешает разрыву, т.е. Ни один из них не создает DWM для создания окна с "цельной" копией содержимого окна DC.
Совет оценил:)