Можно ли предотвратить разрушение артефактов при рисовании с использованием 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 работал слишком медленно, что приводило к видеоархиватам.