64 бита не является хорошим кратным 12 битам.Чтобы исправить это, прочитайте группу из трех 64-битных значений (16 пикселей) за раз.Например:
uint64_t v1 = (uint64_t *)(&buffer[pos]);
uint64_t v2 = (uint64_t *)(&buffer[pos+8]);
uint64_t v3 = (uint64_t *)(&buffer[pos+16]);
Затем вы можете сделать всю маскировку сразу:
v1 &= 0x0F80F80F80F80F80ULL;
v2 &= 0x80F80F80F80F80F8ULL;
v3 &= 0xF80F80F80F80F80FULL;
Для первых 5 пикселей просто смещение для разделения значений отдельных пикселей (uint16_t MSBs = v1; v1 >>= 12;
повторение 5раз).Для 6-го пикселя вам нужно сделать помадку (MSBs = v2 << 4; v2 >>= 8;
), затем для следующих 4 пикселей он вернется к MSBs = v2; v2 >>= 12;
, повторяется 4 раза.Для пикселя после этого это немного больше выдумки (MSBs = v2 | (v3 << 8)
);затем просто MSBs = v3; v3 >>= 12;
повторяется 5 раз, чтобы закончить группу из 16 пикселей.
Обратите внимание, что это, вероятно, самый быстрый способ;потому что нет ветвей (и нет шансов на дорогостоящие неправильные прогнозы веток), потому что процессор может выполнять большинство операций параллельно (особенно если вы полностью расширяете извлечение пикселей, чтобы избавиться от сдвигов), и потому что «выборка и маска»фаза хорошо подходит для методов SIMD.