Комментарии 11
Может быть добавить этой функции несколько опций альфакомпозитинга? Для близкого к photoshop и для «скоростного»?
0
Однотипные операции над компонентами цвета наводят на мысли о применении того же SSE. Не пробовали с ним? Что-нибудь вида:
- грузим src
- src*coeff1
- грузим dst
- dst*coeff2 + 0x800
- сложить значения на вершине стека
- удвоить значение на вершине стека
- shr 8
- сложить значения на вершине стека
- shr 12
- заменить в результате «a» значение на (outa + 0x7) >> 4
+2
Очень поздно я наткнулся на эту статью, конечно (ссылка в другой теме привела сюда), но в свое время я, решая задачу смешивания двух цветов с коэффициентом от 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-битным.
К сожалению, точных цифр прироста сказать не могу (тогда не было цели посчитать, насколько же именно быстрее стало, главным на тот момент было хоть как-то убрать тормоза), но выигрыш был очень заметный.
Смысл решения заключается в том, чтобы заменить выражение 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-битным.
К сожалению, точных цифр прироста сказать не могу (тогда не было цели посчитать, насколько же именно быстрее стало, главным на тот момент было хоть как-то убрать тормоза), но выигрыш был очень заметный.
0
Случайно пришел сюда из другой статьи, хотя понимаю что дело было давно, и уже не так актуально. Так вот, у вас в выражении делается 2 умножения. Нужно раскрыть скобки и сделать преобразование: a * coeff + b * (1-coeff) = a * coeff + b — b * coeff = (a — b) * coeff + b
Обращение к массиву по индексу — это все равно 1 операция умножения и 1 операция сложения. Так что, да, вы сэкономили 1 умножение по сравнению с начальной формулой, но если бы вы провели преобразование — вы бы точно так же сэкономили умножение.
Кроме того, для 16-ти мегабайтной таблицы — это постоянные кешмиссы, а в случае с преобразованной формулой — этого нет.
Обращение к массиву по индексу — это все равно 1 операция умножения и 1 операция сложения. Так что, да, вы сэкономили 1 умножение по сравнению с начальной формулой, но если бы вы провели преобразование — вы бы точно так же сэкономили умножение.
Кроме того, для 16-ти мегабайтной таблицы — это постоянные кешмиссы, а в случае с преобразованной формулой — этого нет.
0
Да, разумеется, я использовал оптимизированную формулу с одним умножением, просто в комментарии для наглядности проще было написать a * coeff + b * (1-coeff).
Что касается умножений при обращении к массиву по адресу [a][b][coeff], то из-за природы значений самих индексов их можно легко заменить на побитовые сдвиги (что и было сделано). А вот про промахи кэша полностью согласен, конечно.
Что касается умножений при обращении к массиву по адресу [a][b][coeff], то из-за природы значений самих индексов их можно легко заменить на побитовые сдвиги (что и было сделано). А вот про промахи кэша полностью согласен, конечно.
0
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
История оптимизации alpha_composite в Pillow 2.0