Кросспост из
блога автора. Комментировать лучше
там, но можно и тут
Практика вот к
этой презентации:
Берем 36Mpix файлик с D800, распаковываем егонный RAW в 16-битный однокомпонентный битмеп, дальше начинаем процессить.
Процессим без "интерполяции", т.е. 4 пикселя исходного байера образуют один выходной пиксель (режим half_size у LibRaw/dcraw). Получаем такие вот времена:
- LibRaw::dcraw_process() плюс формирование RGBA-битмепа: 420ms.
- Перепишем этот самый dcraw_process() на SSE3, процессить будем в плавучке (с эмуляцией особенностей dcraw), выдаем такой же 8-битный RGBA: 110ms (и более-менее понятно где еще выиграть миллисекунд 20).
- Добавим в предыдущий суп еще: подсчет RAW-гистограммы и сохранение исходного float-битмепа нетронутым (и без дублирования по памяти), т.е. баланс белого и конверсию цвета делаем два раза, один раз для подсчета гистограммы результирующего файла, а второй раз - прямо на вывод. 180ms.
Это все был один поток. Распараллелим его:
- "распараллеленный dcraw_process": 130ms (так в RawDigger сделано, тамошний RGB render устроен именно так, но гистограммы и статистика в эти 130ms не входят, равно как и битмеп для показа там готовится иначе и потому дольше).
- "распаралеленный ассемблерный dcraw_process": не делал, ожидаю <50ms (потому что вариант с двойным вычислением, как следующий, но без гистограмм - 57ms).
- параллельная ассемблерная версия с гистограммами, сохранением float RAW: 75ms
Сравнивая последний вариант с последовательным C-шным, нужно понимать, что в C-шном варианте еще где-то 200ms придется на гистограммы и еще 200 на конверсию int16 - float. То есть реальное ускорение от SSE и параллельной обработки - раз в 10 (75ms против 800). И это оптимизированный C-шный, в LibRaw это место заметно пооптимизировано в сравнении с исходным dcraw.
Минусы: потрачено изрядно времени (несколько дней), окончательного кода 25кб, а промежуточных вариантов было в разы больше. Ну и две баги ловились достаточно мучительно.