Подтвердить что ты не робот

Растровые шаблоны оптимизации производительности

Я нашел несколько шаблонов для оптимизации обработки битмапов в WPF. Однако я не понимаю, когда использовать каждый образец. Поскольку я думаю, что это распространенная проблема, я подытожил то, что я понимаю, и что я думаю, и прошу вас о помощи. Если вы можете добавить шаблоны, объясните , как они отличаются, объясните, используют ли они ЦП или графический процессор, и научите , когда использовать каждый и , как их объединить, это будет огромная помощь!

Контекст - Сценарий "Сетка" изображений:

Мое приложение должно отображать много растровых изображений. Изображения отображаются на экране в сетчатой ​​структуре строк и столбцов (не обязательно в классах Grid или UniformGrid, думайте о просмотре Album Media Players Album). Изображения могут перемещаться между различными ячейками сетки. Некоторые изображения в произвольных ячейках могут быть заменены другими. Изображения должны быть интерактивными, содержать контекстное меню, выбирать, перетаскивать и т.д. Другими словами, "объединить маленьких искателей в один большой битмап" не применимо, по крайней мере, не наивно.

Образец 0: Хак

Соедините маленьких искателей с растровым рисунком (как рисовать контекст?) и используйте это как фон. Наложите это на изображение с пустым содержимым, которое будет обрабатывать хиты, контекстные меню, события и т.д.

Преимущество состоит в том, что мы говорим только о двух растровых изображениях здесь: в настоящее время отображается один и тот, который должен его заменить. Это должно быть очень быстро. Однако мой многолетний опыт повышает красный флаг опасности. Ваши комментарии?

Шаблон 1: Уменьшить размер изображения

Это неудобно, когда вы заранее знаете размер изображения для изменения размера и когда вы готовы потерять детали (цвет) для производительности:

  • Уменьшить размер растрового изображения с помощью BitmapImage.DecodePixelWidth
  • Уменьшить информацию о цвете с помощью FormatConvertedBitmap.DestinationFormat
  • Задайте настройку поведения масштабирования элементов управления. Image.Stretch to Stretch.None
  • Установите SetBitmapScalingMode для изображения в LowQuality.
  • Заморозить bugger

Смотрите код здесь.

Шаблон 2: предварительная выборка фона

Этот шаблон применим, если вы считаете, что можете воспользоваться преимуществами пользователя, смотрящего на изображения на экране, и подготовьте вперед следующие изображения для отображения. Недостатки вашего проекта в дополнение к издержкам на память заключаются в том, что он должен поддерживать цель .Net Framework 4, а не только профиль клиента, поэтому может потребоваться установка на клиентах. Вам самому придется страдать от асинхронной боли программирования.

В этом шаблоне вы создаете точно необходимое количество элементов управления Image. Когда необходимо добавить, перемещать или удалять растровые изображения, вы изменяете только BitmapSource элементов управления Image. Задача BackgroundWorker отвечает за предварительную выборку BitmapSource (ов) (возможно, используя шаблон "Уменьшить размер изображения" выше) и вставляя их в MemoryCache.

Для этого вам нужно установить BitmapImages CacheOption в OnLoad, чтобы работа была загружена фоновым рабочим.

Рисунок 3: Контекст рисования

Это было предложено Шелдоном Цяо из Microsoft Support на форуме MSDN WPF здесь. См. Стр. 494, глава 15 "2D-графика" в Adam Nathans WPF 4 Развязано для описания DrawingContext. Я не могу сказать, что понимаю. В соответствии с ответом здесь, я бы предположил, что это улучшит обработку чертежей геометрии, а не растровых изображений. Затем я не думаю, что это будет поддерживать требования к фокусу и событиям для изображений (мое плохое для того, чтобы лучше не объяснять требования на форуме). Кроме того, Im обеспокоен предложением книги: "Обратите внимание, что использование DrawingContext не меняет факт что вы работаете в системе с сохраненным режимом. Указанный рисунок не происходит сразу, команды сохраняются WPF до тех пор, пока они не понадобятся". Это означает, что после нашего четного обработчика мы не можем воспользоваться parallelism, как в "Предварительной выборке фона".

Рисунок 4: Записываемые растровые изображения

Документация MSDN здесь описывает его как двойную буферную систему: ваш поток пользовательского интерфейса обновляет буфер; WPFs render thread перемещает это в видеопамять.

Предполагаемое использование (см. здесь) для растровых изображений, которые сильно меняются в видеоролике, таком как дисплей. Я не уверен, но возможно, что это можно взломать и объединить с фоном Pre-fetch pattern и использовать в сценарии сетки.

Шаблон 5: Кэшированный растровый рисунок

Немного информации о MSDN (здесь). В архиве форума WPF (здесь) объясняется, что "BitmapCache API предназначен для кэширования вашего содержимого (при рендеринге в аппаратном обеспечении) в видеопамяти, что означает, что он остается на вашем GPU, что экономит вам стоимость повторного рендеринга этого контента при его рисовании на экране". Это кажется отличной идеей. Я не уверен, однако, каковы подводные камни и способы их использования.

Шаблон 6: RenderTargetBitmap

RenderTargetBitmap преобразует Visual в растровое изображение. Я не уверен, если это имеет значение здесь. См. здесь.

Изменить. Что касается вопроса Павла Хонекека: я написал, что "Мое приложение должно отображать множество битмапов". Я не заметил, что мне нужно отображать около 800 изображений одновременно.

Можно прочитать о проблемах производительности, связанных с моими вопросами SO WPF Bitmap performance и Как сделать отображение изображений на WPF более "мгновенный" ?

Я изменил описание шаблона 1, чтобы подчеркнуть концепцию, что элементы управления изображением не создаются и не удаляются (если мы не хотим отображать большую или меньшую сетку). Только их источники установлены в разные, новые или нулевые источники Bitmap.

Изменить: Этот вопрос опубликован на форуме поддержки WPF с некоторыми ответами персонала MS.

4b9b3361

Ответ 1

Я не могу найти конкретный вопрос в вашем сообщении, кроме как просить комментарии о подходах ниже. Я не буду требовать знать все выше, но я расскажу вам, что я знаю, работая некоторое время, разрабатывая высокопроизводительные пользовательские интерфейсы, используя WPF и Silverlight.

Образец 0: Хак. Объединение всех в одно изображение

Я бы избегал этого, если это было возможно. Похоже, вы хотите отобразить большую панель с тысячами небольших изображений. Поэтому каждое изображение является миниатюрой (так как вы не можете отображать сразу 1000 больших изображений). В результате я защищал кеширование/изменение размера по сравнению с комбинацией.

Шаблон 1: Уменьшить размер изображения

Если вы одновременно показываете 1000 изображений на экране, рассмотрите доступную экранную недвижимость. Средний монитор - 1280x1024 пикселей или чуть более 1,3MPixels. 1000 изображений показывают, что вы получите максимальный размер 1300 пикселей на изображение или 36 * 36. Допустим, ваши изображения имеют размер 32 * 32. Вы должны создать миниатюру этого размера изображения для рендеринга на экране, а затем щелкнуть (или другое действие) показать изображение полного размера.

Также рассмотрите не только накладные расходы на изменение размера большого изображения, но и отправку большого изображения на GPU для изменения размера. Для этих данных требуется пропускная способность для отправки. Большое изображение может быть в несколько мегабайт, тогда как миниатюра размером 32 * 32 может составлять несколько килобайт.

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

Шаблон 2: предварительная выборка фона

Это техника, о которой я не слышал, однако она кажется правдоподобной. Каковы накладные расходы в вашем приложении? это обновление свойства Image.Source или создание нового изображения, тесселяции, выполнение макета и отправка информации для рендеринга на GPU?

Все вышеперечисленное происходит на процессоре, за исключением окончательного рендеринга. Уменьшая накладные расходы на стороне процессора и обновляя источник, вы можете что-то сказать. Объедините это с WriteableBitmap в качестве источника, и вы можете дополнительно улучшить производительность (см. Ниже).

Рисунок 3: Контекст рисования

Хорошо, все это позволяет вам выстраивать очереди в режиме ожидания с использованием синтаксиса стиля "OnPaint", который не похож на старый GDI OnPaint. По моему опыту, OnRender не улучшает производительность, но это обеспечивает гибкую гибкость над тем, что нарисовано и когда. OnRender предоставляет вам контекст, который имеет функцию DrawImage, позволяя BitmapSource рисоваться в конвейере рендеринга без необходимости управления изображением. Это хорошо, поскольку он устраняет некоторые накладные расходы, однако вводит проблемы, подобные тем, которые наблюдаются в Pattern0 (вы потеряете макет и должны вычислить положение всех ваших изображений). Если вы это сделаете, вы можете также вызвать шаблон 0, о котором я посоветовал.

Рисунок 4: Записываемые растровые изображения

WriteableBitmaps - это малоиспользуемая и чрезвычайно мощная подсистема в WPF. Я использую их для создания диаграммного компонента, способного отображать большие объемы данных в реальном времени. Я бы посоветовал проверить проект WriteableBitmapEx codeplex Раскрытие информации, я внес свой вклад в этот раз и посмотреть, можете ли вы объединить его с другими шаблонами. В частности, функция Blit, которая позволит вам записать кэшированное растровое изображение в источник растрового изображения на изображении.

Например, хорошей техникой может быть шаблон 1 + 2 + 4.

У вас может быть сетка из N элементов управления изображением на экране в заданных местах в элементе управления сеткой. Каждый из них является статичным и не получает прокрутки вне поля зрения, поэтому никаких творений и исключений не происходит. Теперь, помимо этого, измените размер изображения и напишите в WriteableBitmap, который устанавливается как свойство Source для каждого изображения. Когда вы прокручиваете, получите следующие/предыдущие эскизы и обновите источники, используя WriteableBitmapEx.Blit. Pow! виртуализированную, кэшированную, многопоточную визуализацию.

Рисунок 5: Кэшированное растровое изображение

Это попытка microsoft сделать 1 + 2 + 4, как я уже говорил выше. То, что он пытается сделать, это после компоновки (процессорная сторона), тесселяции (процессорная сторона), отправки команд рендеринга сохраненного режима на процессорную плату (GPU) и рендеринг (сторона GPU), которая кэширует растровое изображение визуализируемого элемента, используется для следующего прохождения рендеринга. Да, малоизвестный факт о WPF заключается в том, что замечательный двигатель с графическим процессором очень медленный, так как он выполняет большую часть своей работы с CPU: P

Я бы экспериментировал с BitmapCache и видел, как он работает. Есть предостережения, и они таковы, что при обновлении UIElement он должен воссоздать кеш, поэтому статические элементы будут работать намного лучше, чем динамические. Кроме того, я не видел существенного улучшения производительности от использования этого, тогда как методы стиля WriteableBitmap могут дать порядок улучшения.

Образец 6: RenderTargetBitmap

Этот окончательный метод позволяет отображать UIElement в растровом изображении - вы знаете это, но интересно, что это может выполнять генератор миниатюр с низким разрешением (или изменение размера). Например, установите изображение с BitmapSource вашего полноразмерного изображения. Теперь установите размер элемента управления Image на 32 * 32 и сделайте растровое изображение. Вуаля! У вас есть миниатюра BitmapSource для использования в сочетании с некоторыми подкачками (шаблон 2) и/или записываемыми растровыми изображениями.

Хорошо, наконец, просто хотел сказать, что ваше требование будет подталкивать WPF до предела, однако есть способы заставить его выполнить. Как я уже сказал, у меня есть системы построения, которые отображали тысячи или миллионы элементов на экране сразу, используя замечательный обходной путь, который является WriteableBitmap. Переход по стандартным маршрутам WPF приведет к производительности ад, поэтому вам придется сделать что-то экзотическое, чтобы решить эту проблему.

Как я уже сказал, моя рекомендация 1 + 2 + 4. Вы должны изменить размер миниатюры, и я не сомневаюсь. Идея создания статической сетки элементов управления Image и обновления источников очень хороша. Идея использования WriteableBitmap (в частности, функция Blit-функции WriteableBitmapEx) для обновления источников также заслуживает изучения.

Удачи!