суббота, 25 декабря 2010 г.

Что делает CS_SAVEBITS?

Это перевод What does CS_SAVEBITS do? Автор: Реймонд Чен.

Если вы указываете стиль класса CS_SAVEBITS, то оконный менеджер будет стараться сохранять биты, закрытые окном. Но настоящий вопрос здесь - почему. Т.к. ответ на этот вопрос позволит вам использовать эту силу для добра, а не зла.

Когда окно, чей класс содержит стиль CS_SAVEBITS, показывается, оконный менеджер делает снимок пикселей экрана, где будет показано окно. Сначала он просит видео-карту сохранять пиксели во внеэкранной видеопамяти (быстро). Если таковой памяти нет или недостаточно, то пиксели сохраняются в системной памяти RAM (медленнее). Если в промежутке сохранённые пиксели не были выброшены (см. ниже), то когда окно скрывается, сохранённые пиксели копируются назад на экран. Другими словами, не генерируются сообщения WM_PAINT.

Что может отменить сохранённые пиксели? Что угодно, что может привести к их рассинхронизации с тем, что должно быть на экране, когда окно уйдёт. Вот несколько примеров:
  • Если окно перемещается, то пиксели выбрасываются. Поскольку их восстановление на экран поместило бы их в неверную позицию.
  • Если нижележащее окно обновляет себя (обычно через InvalidateRect), то сохранённые пиксели также отбрасываются, потому что нижележащее окно указало, что оно хочет обновить свои пиксели.
  • Если любое окно под данным меняет свой Z-порядок, то сохранённые пиксели также отбрасываются.
  • Если под данным окном создаются или уничтожаются окна.
  • Если кто-то вызывает GetDC для нижележащего окна и начинает рисовать.
В общем, вы поняли. Если обратное копирование сохранённых пикселей на экран может привести к несогласованности, то сохранённые пиксели отбрасываются.

Так как вам использовать эту силу ради добра?

Первый момент для рассмотрения - регион окна должен быть невелик, потому что чем больше сохраняемое изображение, тем меньше шансов, что оно влезет во внеэкранную видеопамять, что означает большую вероятность для переноса данных из видеопамяти в системную память - кошмарный "vid-sys blt", с которым хорошо знакомы производители игр. В общей схеме копирования данных между видео- и системной памятью, "vid-vid" - быстрейший (поскольку видеокарты очень хороши в этой задаче), "sys-sys" - следующий наилучший (хотя это будет стоить вам места в кэше процессора), "sys-vid" на третьем месте, а "vid-sys" - наихудший: программы намного более часто пишут в видеопамять, чем читают из неё. Вот почему связь между видеокартой и системной памятью оптимизирована в сторону записи в видеопамять, а не чтения из неё.

Но основной момент здесь - убедиться, что оконный менеджер не будет заниматься всей этой работой только для того, чтобы выбросить в итоге эти пиксели. Поэтому окно, которое является хорошим кандидатом для стиля CS_SAVEBITS, не двигается, занимает относительно немного места на экране и видимо только короткий промежуток времени. То, что окно не должно двигаться, очевидно: если окно смещается, то пиксели выбрасываются. Второе и третье правила пытаются минимизировать шанс отмены пикселей.

Соответственно, лучшими кандидатами для CS_SAVEBITS являются меню, подсказки, небольшие диалоги - поскольку все они малы, обычно не двигаются по экрану и быстро пропадают.

(Некоторые люди ошибочно считают, что CS_SAVEBITS сохраняет биты самого окна. Я не знаю, откуда пошёл этот миф, поскольку простейший эксперимент показывает несостоятельность этой версии. Модель рисования в Windows следует принципу Не сохраняй ничего, что ты можешь пересчитать.)

2 комментария:

  1. И как тогда вытащить эти сохраненные данные под окном?

    ОтветитьУдалить

Можно использовать некоторые HTML-теги, например:

<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>

Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку (поддерживается OpenID).

Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.

Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.