Я рисую анимацию с использованием двойного буферизированного GDI в окне, в системе, где включена компоновка DWM, и видя хорошо видимый tearing на экране. Есть ли способ предотвратить это?Возможно ли предотвратить разрушение артефактов при рисовании с использованием GDI в окне с композицией DWM?
Подробности
анимация занимает такое же изображение, и перемещает его справа налево по экрану; количество пикселей в поперечнике определяется разницей между текущим временем и временем начала анимации и временем до конца, чтобы получить полную фракцию, которая применяется ко всей ширине окна, используя timeGetTime
с 1ms resolution. Анимация рисует в цикле без обработки сообщений приложения; он вызывает метод (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: нормальныйSleep
и высокое разрешение спин-подождите использованиеtimeGetTime
.)Использование
DwmSetPresentParameters
, чтобы попытаться ограничить обновление до той же скорости, при которой код втягивает. (Вариации: много буферов (cBuffer = 8) (без видимого эффекта), указав скорость источника обновления монитора/1 и спящий режим с использованием вышеуказанного кода (так же, как и просто попытка спящего подхода), указав обновление на кадр 1, 10 и т. Д. (Без видимого эффекта), изменение покрытия исходного кадра (отсутствие видимого эффекта.)Использование
DwmGetCompositionTimingInfo
в различных формах:-
- Хотя
cFramesPending
> 0, спина;
- Хотя
-
- Получить
cFrame
(кадр состоит) и спин в то время как это число не меняется;
- Получить
-
- Получить
cFrameDisplayed
и спина в то время как это не меняет;
- Получить
-
- Расчет времени для сна, чтобы путем добавления
qpcVBlank + qpcRefreshPeriod
, а затем в то время какQueryPerformanceCounter
возвращает время меньше, чем это, спина
- Расчет времени для сна, чтобы путем добавления
-
Все эти подходы также варьировалась от живописи , затем спиннинг/сон, прежде чем снова рисовать; или наоборот: спать, а затем рисовать.
Немногие, похоже, имеют какой-либо видимый эффект и какой эффект есть, трудно квалифицировать и может быть просто результатом более низкой частоты кадров. Ничего не мешает разрыву, т. Е. Ни один из них не делает DWM составляющим окно с «цельной» копией содержимого DC окна.
Совет оценил :)
GDI - старый и хрустящий, а не гладкая анимация. Может быть, попробовать Direct2D? –
@JonathanPotter Хорошая точка. Одним из ограничений, с которыми я столкнулся, является не использование DX любого типа - одна из причин - количество платформ и отсутствие требований, конечный код должен работать. (Не все являются современными Windows.) Возможно, вспомогательный DX-код, только когда Aero существует ...? Тем не менее, он должен будет легко переключаться на и из GDI/DX без видимых сбоев, поскольку он включает/выключает анимацию. Это возможно? –
Возможно, вы могли бы написать класс вспомогательного чертежа, который использует DX, если он доступен, и в противном случае возвращается обратно в GDI. Было бы довольно редко найти систему, которая не поддерживала Direct3D, хотя и не D2D. –