@@ -236,6 +236,153 @@ namespace ojph {
236236 }
237237 }
238238
239+ // ////////////////////////////////////////////////////////////////////////
240+ void avx2_irv_convert_to_integer_nlt_type3 (const line_buf *src_line,
241+ line_buf *dst_line, ui32 dst_line_offset,
242+ ui32 bit_depth, bool is_signed, ui32 width)
243+ {
244+ assert ((src_line->flags & line_buf::LFT_32BIT) &&
245+ (src_line->flags & line_buf::LFT_INTEGER) == 0 &&
246+ (dst_line->flags & line_buf::LFT_32BIT) &&
247+ (dst_line->flags & line_buf::LFT_INTEGER));
248+
249+ const float * sp = src_line->f32 ;
250+ si32* dp = dst_line->i32 + dst_line_offset;
251+ if (bit_depth <= 30 )
252+ {
253+ // We are leaving two bit overhead -- here, we are assuming that after
254+ // multiplications, the resulting number can still be represented
255+ // using 32 bit integer
256+ __m256 mul = _mm256_set1_ps ((float )(1 << bit_depth));
257+ __m256i upper_limit = _mm256_set1_epi32 (INT_MAX >> (32 - bit_depth));
258+ __m256i lower_limit = _mm256_set1_epi32 (INT_MIN >> (32 - bit_depth));
259+
260+ if (is_signed)
261+ {
262+ __m256i zero = _mm256_setzero_si256 ();
263+ __m256i bias = _mm256_set1_epi32 (-((1 << (bit_depth - 1 )) + 1 ));
264+ for (ui32 i = width; i > 0 ; i -= 8 , sp += 8 , dp += 8 )
265+ {
266+ __m256 t = _mm256_loadu_ps (sp);
267+ t = _mm256_mul_ps (t, mul);
268+ t = _mm256_round_ps (t,
269+ _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC);
270+ __m256i u = _mm256_cvtps_epi32 (t);
271+ u = _mm256_max_epi32 (u, lower_limit);
272+ u = _mm256_min_epi32 (u, upper_limit);
273+
274+ __m256i c = _mm256_cmpgt_epi32 (zero, u); // 0xFFFFFFFF for -ve value
275+ __m256i neg = _mm256_sub_epi32 (bias, u); // -bias -value
276+ neg = _mm256_and_si256 (c, neg); // keep only - bias - value
277+ __m256i v = _mm256_andnot_si256 (c, u); // keep only +ve or 0
278+ v = _mm256_or_si256 (neg, v); // combine
279+ _mm256_storeu_si256 ((__m256i*)dp, v);
280+ }
281+ }
282+ else
283+ {
284+ __m256i half = _mm256_set1_epi32 (-(1 << (bit_depth - 1 )));
285+ for (ui32 i = width; i > 0 ; i -= 8 , sp += 8 , dp += 8 ) {
286+ __m256 t = _mm256_loadu_ps (sp);
287+ t = _mm256_mul_ps (t, mul);
288+ t = _mm256_round_ps (t,
289+ _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC);
290+ __m256i u = _mm256_cvtps_epi32 (t);
291+ u = _mm256_max_epi32 (u, lower_limit);
292+ u = _mm256_min_epi32 (u, upper_limit);
293+ u = _mm256_add_epi32 (u, half);
294+ _mm256_storeu_si256 ((__m256i*)dp, u);
295+ }
296+ }
297+ }
298+ else
299+ {
300+ // There is the possibility that converting to integer will
301+ // exceed the dynamic range of 32bit integer; therefore, we need
302+ // to use 64 bit. One may think, why not limit the floats to the
303+ // range of [-0.5f, 0.5f)?
304+ // Notice the half closed range -- we need a value just below 0.5f.
305+ // While getting this number is possible, after multiplication, the
306+ // resulting number will not be exactly the maximum that the integer
307+ // can achieve. All this is academic, because here are talking
308+ // about a number which has all the exponent bits set, meaning
309+ // it is either infinity, -infinity, qNan or sNan.
310+ float mul = (float )(1ull << bit_depth);
311+ const si64 upper_limit = (si64)LLONG_MAX >> (64 - bit_depth);
312+ const si64 lower_limit = (si64)LLONG_MIN >> (64 - bit_depth);
313+
314+ if (is_signed)
315+ {
316+ const si32 bias = (1 << (bit_depth - 1 )) + 1 ;
317+ for (ui32 i = width; i > 0 ; --i) {
318+ si64 t = ojph_round64 (*sp++ * mul);
319+ t = ojph_max (t, lower_limit);
320+ t = ojph_min (t, upper_limit);
321+ si32 v = (si32)t;
322+ v = (v >= 0 ) ? v : (- v - bias);
323+ *dp++ = v;
324+ }
325+ }
326+ else
327+ {
328+ const si32 half = (1 << (bit_depth - 1 ));
329+ for (ui32 i = width; i > 0 ; --i) {
330+ si64 t = ojph_round64 (*sp++ * mul);
331+ t = ojph_max (t, lower_limit);
332+ t = ojph_min (t, upper_limit);
333+ si32 v = (si32)t;
334+ *dp++ = v + half;
335+ }
336+ }
337+ }
338+ }
339+
340+ // ////////////////////////////////////////////////////////////////////////
341+ void avx2_irv_convert_to_float_nlt_type3 (const line_buf *src_line,
342+ ui32 src_line_offset, line_buf *dst_line,
343+ ui32 bit_depth, bool is_signed, ui32 width)
344+ {
345+ assert ((src_line->flags & line_buf::LFT_32BIT) &&
346+ (src_line->flags & line_buf::LFT_INTEGER) &&
347+ (dst_line->flags & line_buf::LFT_32BIT) &&
348+ (dst_line->flags & line_buf::LFT_INTEGER) == 0 );
349+
350+ __m256 mul = _mm256_set1_ps ((float )(1.0 / 65536.0 / 65536.0 ));
351+
352+ const si32* sp = src_line->i32 + src_line_offset;
353+ float * dp = dst_line->f32 ;
354+ si32 shift = 32 - (si32)bit_depth;
355+ if (is_signed)
356+ {
357+ __m256i zero = _mm256_setzero_si256 ();
358+ __m256i bias = _mm256_set1_epi32 (-(si32)((ui32)INT_MIN + 1 ));
359+ for (ui32 i = width; i > 0 ; i -= 8 , sp += 8 , dp += 8 ) {
360+ __m256i t = _mm256_loadu_si256 ((__m256i*)sp);
361+ __m256i u = _mm256_slli_epi32 (t, shift);
362+ __m256i c = _mm256_cmpgt_epi32 (zero, u); // 0xFFFFFFFF for -ve value
363+ __m256i neg = _mm256_sub_epi32 (bias, u); // - bias - value
364+ neg = _mm256_and_si256 (c, neg); // keep only - bias - value
365+ t = _mm256_andnot_si256 (c, u); // keep only +ve or 0
366+ u = _mm256_or_si256 (neg, t); // combine
367+ __m256 v = _mm256_cvtepi32_ps (u);
368+ v = _mm256_mul_ps (v, mul);
369+ _mm256_storeu_ps (dp, v);
370+ }
371+ }
372+ else
373+ {
374+ __m256 half = _mm256_set1_ps (0 .5f );
375+ for (ui32 i = width; i > 0 ; i -= 8 , sp += 8 , dp += 8 ) {
376+ __m256i t = _mm256_loadu_si256 ((__m256i*)sp);
377+ __m256i u = _mm256_slli_epi32 (t, shift);
378+ __m256 v = _mm256_cvtepi32_ps (u);
379+ v = _mm256_mul_ps (v, mul);
380+ v = _mm256_add_ps (v, half);
381+ _mm256_storeu_ps (dp, v);
382+ }
383+ }
384+ }
385+
239386 // ////////////////////////////////////////////////////////////////////////
240387 void avx2_rct_forward (const line_buf *r,
241388 const line_buf *g,
0 commit comments