Можно ли предотвратить разрушение артефактов при рисовании с использованием GDI в окне с композицией DWM?
Я рисую анимацию с использованием двойного буферизированного 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: normal Sleep
и спин-жду с высоким разрешением с использованием timeGetTime
.)
-
Используя DwmSetPresentParameters
, чтобы попытаться ограничить обновление с той же скоростью, на которую рисует код. (Вариации: много буферов (cBuffer = 8) (без видимого эффекта), указав скорость источника обновления монитора /1 и спящий режим с использованием вышеуказанного кода (так же, как и просто попытка спящего подхода), указав обновление на кадр 1, 10 и т.д. (Без видимого эффекта), изменение покрытия исходного кадра (отсутствие видимого эффекта.)
-
Используя DwmGetCompositionTimingInfo
различными способами:
-
- Пока
cFramesPending
> 0, spin;
-
- Получить
cFrame
(скомпонованный кадр) и открутить, пока это число не изменится;
-
- Получить
cFrameDisplayed
и открутить, пока это не изменится;
-
- Вычисление времени для спящего путем добавления
qpcVBlank + qpcRefreshPeriod
, а затем, пока QueryPerformanceCounter
возвращает время меньше этого, вращение
-
Все эти подходы были также изменены живописью, а затем спиннинг/сон, прежде чем снова рисовать; или наоборот: спать, а затем рисовать.
Немногие, похоже, имеют какой-либо видимый эффект, и какой эффект есть, трудно квалифицировать и может быть просто результатом более низкой частоты кадров. Ничего не мешает разрыву, т.е. Ни один из них не создает DWM для создания окна с "цельной" копией содержимого окна DC.
Совет оценил:)
Ответы
Ответ 1
Поскольку вы используете BitBlt
, убедитесь, что ваши DIB - это 4 байта/пиксель. С 3 байтами/пикселями GDI работает медленно, а DWM работает, что может стать источником вашего разрыва. Еще одна проблема BitBlt
, с которой я столкнулся, если ваш DIB несколько больше, чем вызов BitBlt
сделать неожиданно долгое время. Если вы разделите один вызов на более мелкие вызовы, а не нарисуете часть данных, это может помочь. Оба эти элемента помогли мне в моем случае, только потому, что сам BitBlt
работал слишком медленно, что приводило к видеоархиватам.