Низкая производительность с DrawText на Win7 x64 - PullRequest
8 голосов
/ 25 ноября 2010

Я заметил, что в приложении MFC, которое я разрабатываю, при перетаскивании полосы прокрутки для плавной прокрутки вниз по документу частота кадров падает до прерывистых уровней, когда блок, содержащий около абзаца текста, отображается на экране, но шелковисто, когдазакадровый.Исследуя представление, я обнаружил один CDC::DrawText призыв к параграфу текста.Это оптимизированная сборка релиза.

Я использовал QueryPerformanceCounter для получения измерения высокого разрешения просто вызова DrawText, например:

QueryPerformanceCounter(...);
pDC->DrawText(some_cstring, some_crect, DT_WORDBREAK);
QueryPerformanceCounter(...);

Текст представляет собой Unicode, заполнитель в стиле lorem-ipsum, 865 символов в длину и переносится по 7-битовым строкам с учетом прямоугольника и шрифта (пользовательский интерфейс Segoe, lfHeight = -12, стандартный размер основного текста).По моим измерениям, этот вызов в одиночку занимает в среднем 7,5 мс с нечетным пиком в 21 мс.(Обратите внимание, что при работе с монитором с частотой 60 Гц вы получаете около 16 мс для рендеринга каждого обновления.)

Я попытался внести некоторые изменения, чтобы улучшить производительность:

  • Удаление DT_WORDBREAK улучшаетпроизводительность примерно до 1 мс (примерно в 7 раз быстрее), но с учетом того, что только одна строка текста выводит его на экран, и было более 7 строк с разрывом слов, это, как мне кажется, указывает на узкое место в другом месте.
  • Я рисовал текст в прозрачном режиме (SetBkMode(TRANSPARENT)).Поэтому я попробовал непрозрачный режим со сплошной фоновой заливкой.Без улучшений.
  • Я думал, что виноват рендеринг ClearType.Я изменил шрифт lfQuality с CLEARTYPE_QUALITY на NONANTIALIASED_QUALITY.Это выглядело как дерьмо с острыми краями и все, без каких-либо улучшений.
  • Согласно предложению комментария, я использовал CMemDC, но я избавился от него и сделал прямое рисование.Он мерцал как сумасшедший, и никаких улучшений.

Это работает на 64-разрядном ноутбуке с Windows 7 с Intel Core 2 Duo P8400 @ 2,26 ГГц и 4 ГБ оперативной памяти - я не думаю, что этосчитается медленной системой.

Я вызываю DrawText () каждый раз, когда он рисует, и это явно снижает производительность при такой медленной функции, особенно если несколько из этих текстовых блоков видны одновременно.Этого достаточно, чтобы опыт ощущался вялым.Тем не менее, Firefox может отображать страницу, подобную этой, в ClearType с гораздо большим количеством текста, и, кажется, справляется просто отлично.Что я делаю неправильно?Как я могу обойти плохую производительность реального вызова DrawText?

Ответы [ 5 ]

7 голосов
/ 29 ноября 2010

Рисование текста при каждом обновлении расточительно. Используйте двойную буферизацию , то есть нарисуйте закадровое растровое изображение и просто перетащите его на экран. Затем, для прокрутки, просто скопируйте большую часть растрового изображения вверх или вниз или вбок по мере необходимости, затем нарисуйте только недействительную область (перед тем, как выбросить результат на экран).

Если даже это оказывается слишком медленным, сохраняйте также нарисованный текст в закадровом растровом изображении, и вместо отображения используйте блики.

Приветствия и hth.,

2 голосов
/ 26 ноября 2010

Пользователи не могут читать текст в 7 строк за 7 миллисекунд, поэтому сам вызов достаточно быстр.

Частота обновления монитора 60 Гц совершенно не имеет значения. Вам не нужно повторно отображать один и тот же текст для каждого кадра. Видеокарта с радостью снова отправит те же пиксели на экран.

Итак, я думаю, у вас есть еще одна проблема. Возможно, вам интересно прокручивать текст? Пожалуйста, спросите о проблеме, которая у вас действительно есть, вместо того, чтобы считать, что виновником является DrawText.

2 голосов
/ 26 ноября 2010

Согласно этому немецкому посту блога , проблема связана с поддержкой азиатских языковых шрифтов. Если вы включите их в XP, вы получите тот же самый хит перф. В Vista / 7 они включены по умолчанию, и вы не можете их отключить.

РЕДАКТИРОВАТЬ: Просто может быть, использование другого шрифта может помочь .. (тот, который не содержит азиатских символов).

1 голос
/ 27 ноября 2010

Чтобы разбить текст на разрывы слов, DrawText должен многократно пытаться определить ширину блока текста, чтобы увидеть, подходит ли он, затем взять оставшуюся часть и повторить. Это нужно будет делать при каждом звонке. Если ваш текст неизменен, это лишние накладные расходы. В качестве обходного пути вы можете измерить текст самостоятельно, вставить временные разрывы строк и удалить флаг DT_WORDBREAK.

0 голосов
/ 30 ноября 2010

Рассматривали ли вы Direct2D / DirectWrite?

В любом случае, все должно работать лучше, если вы просто нарисуете текст один раз на свой собственный мем-DC и добавите его к тому постоянному току, на котором вы хотите, чтобы он рисовал на каждой итерации.

...