blob: 15749e0d2a6f0678bdc0bf85d8d8c4939499d97e [file] [log] [blame]
/*
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*
*/
#include <stdint.h>
#include "dl/api/omxtypes.h"
#include "dl/sp/api/omxSP.h"
#include "dl/sp/api/mipsSP.h"
static OMX_U16 SplitRadixPermutation(int i, int size, int inverse) {
int m;
if (size <= 2)
return (i & 1);
m = size >> 1;
if (!(i & m))
return SplitRadixPermutation(i, m, inverse) * 2;
m >>= 1;
if (inverse == !(i & m))
return SplitRadixPermutation(i, m, inverse) * 4 + 1;
return SplitRadixPermutation(i, m, inverse) * 4 - 1;
}
static void InitFFTOffsetsLUT(OMX_U16* offset_table,
int offset,
int size,
OMX_U32* index) {
if (size < 16) {
offset_table[*index] = (OMX_U16)(offset >> 2);
(*index)++;
} else {
InitFFTOffsetsLUT(offset_table, offset, size >> 1, index);
InitFFTOffsetsLUT(offset_table, offset + (size >> 1), size >> 2, index);
InitFFTOffsetsLUT(offset_table, offset + 3 * (size >> 2), size >> 2, index);
}
}
OMXResult omxSP_FFTInit_R_F32(OMXFFTSpec_R_F32* pFFTSpec, OMX_INT order) {
OMX_U32 n;
uint32_t fft_size;
OMX_U16* p_bit_rev;
OMX_U16* p_bit_rev_inv;
OMX_U16* p_offset;
OMX_F32* p_twiddle;
OMX_F32* p_buf;
OMX_U32 tmp;
MIPSFFTSpec_R_FC32* pFFTStruct = (MIPSFFTSpec_R_FC32*)pFFTSpec;
if (!pFFTSpec || (order < 1) || (order > TWIDDLE_TABLE_ORDER))
return OMX_Sts_BadArgErr;
/* For order larger than 4, compute Real FFT as Complex FFT of (order - 1). */
if (order > 4)
fft_size = 1 << (order - 1);
else
fft_size = 1 << order;
p_twiddle = mipsSP_FFT_F32TwiddleTable;
p_bit_rev = (OMX_U16*)((OMX_S8*)pFFTSpec + sizeof(MIPSFFTSpec_R_FC32));
/* Align to 32 byte boundary. */
tmp = ((uintptr_t)p_bit_rev) & 31;
if (tmp)
p_bit_rev = (OMX_U16*)((OMX_S8*)p_bit_rev + (32 - tmp));
p_bit_rev_inv = (OMX_U16*)((OMX_S8*)p_bit_rev + fft_size * sizeof(OMX_U16));
/* Align to 32 byte boundary. */
tmp = ((uintptr_t)p_bit_rev_inv) & 31;
if (tmp)
p_bit_rev_inv = (OMX_U16*)((OMX_S8*)p_bit_rev_inv + (32 - tmp));
p_offset = (OMX_U16*)((OMX_S8*)p_bit_rev_inv + fft_size * sizeof(OMX_U16));
/* Align to 32 byte boundary. */
tmp = ((uintptr_t)p_offset) & 31;
if (tmp)
p_offset = (OMX_U16*)((OMX_S8*)p_offset + (32 - tmp));
p_buf = (OMX_F32*)((OMX_S8*)p_offset +
((SUBTRANSFORM_CONST >> (16 - TWIDDLE_TABLE_ORDER)) | 1) *
sizeof(OMX_U16));
/* Align to 32 byte boundary. */
tmp = ((uintptr_t)p_buf) & 31;
if (tmp)
p_buf = (OMX_F32*)((OMX_S8*)p_buf + (32 - tmp));
/* Calculate BitRevInv indexes. */
for (uint32_t i = 0; i < fft_size; ++i)
p_bit_rev_inv[-SplitRadixPermutation(i, fft_size, 0) & (fft_size - 1)] = i;
/* Calculate BitRev indexes. */
for (uint32_t i = 0; i < fft_size; ++i)
p_bit_rev[p_bit_rev_inv[i]] = i;
/* Calculate Offsets. */
n = 0;
InitFFTOffsetsLUT(p_offset, 0, 1 << TWIDDLE_TABLE_ORDER, &n);
/*
* Double-check if the offset tables are initialized correctly.
* Note: the bit-reverse tables and the initialization algorithm for
* pFFTStruct->pOffset table are thoroughly tested, so this check is
* probabaly redundant. However, keeping this just to make sure the offsets
* will not exceed the buffer boundaries.
*/
if (order == 2) {
/* Only check the offsets for the p_bit_rev_inv table. */
for (uint32_t i = 0; i < fft_size; ++i) {
if (p_bit_rev_inv[i] >= fft_size)
return OMX_Sts_BadArgErr;
}
} else if (order < 5) {
/* Check for p_offset table. */
int shift = 2;
int over = 4;
int num_transforms = (SUBTRANSFORM_CONST >> (16 - order)) | 1;
for (uint32_t i = 2; i < order; ++i) {
for (uint32_t j = 0; j < num_transforms; ++j) {
if (((p_offset[j] << shift) + over - 1) >= fft_size)
return OMX_Sts_BadArgErr;
}
shift++;
over <<= 1;
num_transforms = (num_transforms >> 1) | 1;
}
/* Check for bit-reverse tables. */
for (uint32_t i = 0; i < fft_size; ++i) {
if ((p_bit_rev[i] >= fft_size) || (p_bit_rev_inv[i] >= fft_size))
return OMX_Sts_BadArgErr;
}
} else {
/* Check for p_offset table. */
int shift = 2;
int over = 4;
int num_transforms = (SUBTRANSFORM_CONST >> (17 - order)) | 1;
for (uint32_t i = 2; i < order; ++i) {
for (uint32_t j = 0; j < num_transforms; ++j) {
if (((p_offset[j] << shift) + over - 1) >= fft_size)
return OMX_Sts_BadArgErr;
}
shift++;
over <<= 1;
num_transforms = (num_transforms >> 1) | 1;
}
/* Check for bit-reverse tables. */
for (uint32_t i = 0; i < fft_size; ++i) {
if ((p_bit_rev[i] >= fft_size) || (p_bit_rev_inv[i] >= fft_size))
return OMX_Sts_BadArgErr;
}
}
pFFTStruct->order = order;
pFFTStruct->pBitRev = p_bit_rev;
pFFTStruct->pBitRevInv = p_bit_rev_inv;
pFFTStruct->pOffset = (const OMX_U16*)p_offset;
pFFTStruct->pTwiddle = p_twiddle;
pFFTStruct->pBuf = p_buf;
return OMX_Sts_NoErr;
}