Как стать автором
Обновить

Комментарии 11

Может быть добавить этой функции несколько опций альфакомпозитинга? Для близкого к photoshop и для «скоростного»?
Дак последний вариант и так самый быстрый и близкий к фотошопу.
Смотреть большой апдейт.
Однотипные операции над компонентами цвета наводят на мысли о применении того же SSE. Не пробовали с ним? Что-нибудь вида:

  1. грузим src
  2. src*coeff1
  3. грузим dst
  4. dst*coeff2 + 0x800
  5. сложить значения на вершине стека
  6. удвоить значение на вершине стека
  7. shr 8
  8. сложить значения на вершине стека
  9. shr 12
  10. заменить в результате «a» значение на (outa + 0x7) >> 4

об этом должен думать компилятор.
Насколько я понимаю, это все-таки mmx, а не sse. Нет, намеренно не применял, использовал ли его компилятор, не проверял.
В SSE тоже есть подходящие целочисленные команды. Просто интересно, даст ли это хоть какое-то ускорение.
Очень поздно я наткнулся на эту статью, конечно (ссылка в другой теме привела сюда), но в свое время я, решая задачу смешивания двух цветов с коэффициентом от 0 до 255, прибегнул к помощи таблиц поиска, полностью заменив ими умножения.

Смысл решения заключается в том, чтобы заменить выражение a * coeff + b * (1-coeff) обращением к массиву в памяти по адресу [a][b][coeff]. Разумеется, при 32-битном цвете размер такой таблицы будет 17 млрд ТБ, но достаточно хранить такую таблицу только для 8-битного «цвета» (0-255) и вызывать обращение к массиву отдельно для каждого компонента (result->r = a->r * coeff + b->r * (1-coeff) заменяется на result->r = table[a->r][b->r][coeff]). Получается всего 16 МБ. Если и это много, можно «проредить» coeff, сделать его не 8-битным, а, скажем, 4-битным или даже 2-битным.

К сожалению, точных цифр прироста сказать не могу (тогда не было цели посчитать, насколько же именно быстрее стало, главным на тот момент было хоть как-то убрать тормоза), но выигрыш был очень заметный.
Случайно пришел сюда из другой статьи, хотя понимаю что дело было давно, и уже не так актуально. Так вот, у вас в выражении делается 2 умножения. Нужно раскрыть скобки и сделать преобразование: a * coeff + b * (1-coeff) = a * coeff + b — b * coeff = (a — b) * coeff + b
Обращение к массиву по индексу — это все равно 1 операция умножения и 1 операция сложения. Так что, да, вы сэкономили 1 умножение по сравнению с начальной формулой, но если бы вы провели преобразование — вы бы точно так же сэкономили умножение.
Кроме того, для 16-ти мегабайтной таблицы — это постоянные кешмиссы, а в случае с преобразованной формулой — этого нет.
Да, разумеется, я использовал оптимизированную формулу с одним умножением, просто в комментарии для наглядности проще было написать a * coeff + b * (1-coeff).

Что касается умножений при обращении к массиву по адресу [a][b][coeff], то из-за природы значений самих индексов их можно легко заменить на побитовые сдвиги (что и было сделано). А вот про промахи кэша полностью согласен, конечно.
Что то мне как-то сомнительно, что (a — b) * coeff + b выполняется медленнее, чем 3 разиндексации массива (даже через сдвиги) + чтение памяти с частыми кешмиссами. По крайней мере на современном железе. А вы на каком железе это делали?
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации