Оптимизация пользовательских вычислений IDCT - PullRequest
0 голосов
/ 12 января 2019

Для формата изображения я должен декодировать сжатие в формате JPEG. Шаги довольно стандартные, однако цветовое кодирование и полученные значения IDCT, кажется, немного отличаются (я думаю, я не эксперт). Вот почему, кажется, использование стандартной библиотеки JPEG дало неверные результаты, и мне пришлось реализовать ее самостоятельно.

Теперь я не очень доволен выступлением. После оптимизации наивного подхода путем выполнения некоторого кэширования данных, которое не изменяется, мне нужно ~ 150 мсек для декодирования изображения 1024x1024. Из этих 120 мс тратится на функцию idct, которая выглядит следующим образом:

float idctHelper(const int16_t *inBlock, int32_t u, int32_t v, int32_t blockWidth, int32_t blockHeight) {
    glm::vec<4, float, glm::packed_lowp> vec1{};
    glm::vec<4, float, glm::packed_lowp> vec2{};
    glm::vec<4, float, glm::packed_lowp> vec3{};

    float result = 0.0f;
    for (auto y = 0; y < blockHeight; ++y) {
        for (auto x = 0; x < blockWidth; x += 4) {
            const auto idx = (v * 8 + u) * 64 + y * 8 + x;
            vec1 = glm::vec<4, float, glm::packed_lowp>(inBlock[y * blockWidth + x], inBlock[y * blockWidth + x + 1], inBlock[y * blockWidth + x + 2], inBlock[y * blockWidth + x + 3]);
            vec2 = glm::vec<4, float, glm::packed_lowp>(idctLookup[idx], idctLookup[idx + 1], idctLookup[idx + 2], idctLookup[idx + 3]);
            vec3 = vec1 * vec2;
            result += vec3.x + vec3.y + vec3.z + vec3.w;
        }
    }

    return result;
}

template<typename T, typename U = T>
U clamp(T value, T min, T max) {
    return static_cast<U>(std::min<T>(std::max<T>(value, min), max));
}

void idct(int16_t *outBlock, int16_t *inBlock, bool isLuminance, int32_t blockWidth = 8, int32_t blockHeight = 8) {
    for (auto y = 0; y < blockHeight; ++y) {
        for (auto x = 0; x < blockWidth; ++x) {
            auto value = static_cast<int16_t>(std::round(
                    0.25f * idctHelper(inBlock, x, y, blockWidth, blockHeight)));
            if (isLuminance) {
                value = clamp<int16_t>(static_cast<int16_t>(value + 128), 0, 255);
            } else {
                value = clamp<int16_t>(value, -256, 255);
            }

            outBlock[y * blockWidth + x] = value;
        }
    }
}

Как вы можете видеть, я пытался использовать (потенциально) SIMD и операции с низкой точностью, чтобы ускорить idctHelper, но теперь я немного растерян, где я могу продолжать оптимизировать это. Буду очень признателен за любую идею или подсказку.

...