2012-02-16 3 views
35

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

Контекст - образы «Сетка» Сценарий:

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

Pattern 0: The Hack

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

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

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

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

  1. Уменьшение размера растрового изображения с помощью BitmapImage.DecodePixelWidth
  2. уменьшить цветовую информацию, используя FormatConvertedBitmap.DestinationFormat
  3. Установить поведение масштабирования элемента управления с etting Image.Stretch to Stretch.None
  4. Установите SetBitmapScalingMode для изображения в LowQuality.
  5. замораживать мудак

См код here.

Pattern 2: Фон упреждающего

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

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

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

Узор 3: Рисунок Контекст

Это было предложено Шелдон Ziao от поддержки Microsoft на форуме MSDN WPF here. См. Стр. 494, глава 15 «2D-графика» в WPF 4 Адама Натана. Развязано для описания DrawingContext. Я не могу сказать, что понимаю. Согласно ответу here, я предполагаю, что это улучшит обработку чертежей геометрии, а не растровых изображений. Затем я не думаю, что это будет поддерживать требования к фокусу и событиям для изображений (мое плохое для того, чтобы не объяснять требования лучше на форуме). Кроме того, меня беспокоит сводное предложение книги: «Обратите внимание, что использование DrawingContext не изменяет тот факт, что вы работаете в системе с сохраненным режимом. Указанный рисунок не выполняется немедленно; команды сохраняются WPF до тех пор, пока они не понадобятся ». Это означает, что после нашего четного обработчика мы не можем использовать параллелизм, как в« Предварительной выборке фона ».

Узор 4: Writeable Bitmaps

В документации MSDN here описывает это как двойной буферной системы: Ваш UI поток обновляет буфер; поток рендеринга WPF перемещает это в видеопамять.

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

Pattern 5: Сохраненная Bitmap

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

шаблон 6: RenderTargetBitmap

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

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

можно прочитать о проблемах производительности, участвующих в моих С.О. вопросы WPF Bitmap performance и How can I make displaying images on WPF more “snappy”?

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

Редактировать: This question as posted on the WPF support forum, с некоторыми ответами персонала MS.

+1

Сколько изображений вы ожидаете? Я сделал приложение, которое показывает сетку тысяч изображений раньше. Мы использовали список виртуального режима; по мере того, как пользователь прокручивается вниз, изображения загружаются в фоновый поток, застывают и устанавливаются на источник изображения. Ясно, что вы много думали об этом ... но, возможно, знать больше о том, чего вы хотите добиться, было бы лучше. Например, какие проблемы у вас возникли, чтобы оптимизировать такой приоритет? –

+0

@PaulHoenecke Привет, Пол, благодарю вас за ответ. Виртуальные коллекции помогают вам, когда вы хотите отобразить небольшое количество элементов из большой коллекции. Здесь я хочу отображать около 1K элементов одновременно. Кроме того, я не уверен, что существует виртуализованная сетка. Наконец, шаблон 1 по существу виртуализуется - я добавлю en edit. – Avi

+0

Ави, ваш вопрос выглядит неуместным для описанной проблемы. По какой-то причине вы можете улучшить коэффициент сжатия, но тогда вам нужно точно знать, какие изображения вы показываете. Или, с другой стороны, вы можете захотеть дать пользователю представление обо всех доступных изображениях, тогда вы можете определить некоторые наборы и отобразить миниатюры или аналогичные. Но обе вещи не обязательно связаны друг с другом. Может быть, вы хотите что-то похожее на метрику сходства для определения наборов похожих изображений? –

ответ

17

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

Узор 0: Взлом. Объединение всех в одно изображение

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

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

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

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

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

Pattern 2: Фон упреждающего

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

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

Узор 3: Рисунок Контекст

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

Узор 4: Writeable Bitmaps

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

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

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

шаблон 5: Сохраненная Растровые

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

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

Pattern 6: RenderTargetBitmap

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

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

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

Удачи вам!

+0

Спасибо за ваш ответ! История древней еврейской Пасхи описывает четырех сыновей: Мудрый, злой, наивный и тот, который даже не знает, какие вопросы задавать. Я чувствую, что мне так не хватает фона, я даже не способен задавать правильные вопросы: «тесселлирование»? Знаете ли вы о какой-либо книге или статье, описывающей (2D) графику «конвейер» в WPF? Каковы действия, что делает процессор, что делает GPU? – Avi

+1

Да, я делаю! См. Эту статью: http://jeremiahmorrill.com/2011/02/14/a-critical-deep-dive-into-the-wpf-rendering-system/ Это довольно эзотерический материал, не чувствуйте себя плохо. Большинство из вас расскажут вам «Просто переопределить OnRender» для производительности, или «WPF использует GPU», но это неправильный ответ. Когда вы понимаете, что WPF выполняет большую часть своей работы на стороне процессора (lame !!), тогда вы можете начать оптимизировать производительность. –

+0

Пройдя по тропе, на которую вы меня отправили, я начинаю чувствовать, что WPF по своей сути медленный, и что нужно ждать Direct2D или WinRT ... – Avi

Смежные вопросы