• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***
2   This file is part of PulseAudio.
3 
4   Copyright 2004-2006 Lennart Poettering
5   Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6 
7   PulseAudio is free software; you can redistribute it and/or modify
8   it under the terms of the GNU Lesser General Public License as published
9   by the Free Software Foundation; either version 2.1 of the License,
10   or (at your option) any later version.
11 
12   PulseAudio is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   General Public License for more details.
16 
17   You should have received a copy of the GNU Lesser General Public License
18   along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
19 ***/
20 
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 
28 #include <pulsecore/macro.h>
29 #include <pulsecore/endianmacros.h>
30 
31 #include "cpu-x86.h"
32 #include "sconv.h"
33 
34 #if (!defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) && defined (__i386__)) || defined (__amd64__)
35 
36 static const PA_DECLARE_ALIGNED (16, float, scale[4]) = { 0x8000, 0x8000, 0x8000, 0x8000 };
37 
pa_sconv_s16le_from_f32ne_sse(unsigned n,const float * a,int16_t * b)38 static void pa_sconv_s16le_from_f32ne_sse(unsigned n, const float *a, int16_t *b) {
39     pa_reg_x86 temp, i;
40 
41     __asm__ __volatile__ (
42         " movaps %5, %%xmm5             \n\t"
43         " xor %0, %0                    \n\t"
44 
45         " mov %4, %1                    \n\t"
46         " sar $3, %1                    \n\t" /* 8 floats at a time */
47         " cmp $0, %1                    \n\t"
48         " je 2f                         \n\t"
49 
50         "1:                             \n\t"
51         " movups (%q2, %0, 2), %%xmm0   \n\t" /* read 8 floats */
52         " movups 16(%q2, %0, 2), %%xmm2 \n\t"
53         " mulps  %%xmm5, %%xmm0         \n\t" /* *= 0x8000 */
54         " mulps  %%xmm5, %%xmm2         \n\t"
55 
56         " cvtps2pi %%xmm0, %%mm0        \n\t" /* low part to int */
57         " cvtps2pi %%xmm2, %%mm2        \n\t"
58         " movhlps  %%xmm0, %%xmm0       \n\t" /* bring high part in position */
59         " movhlps  %%xmm2, %%xmm2       \n\t"
60         " cvtps2pi %%xmm0, %%mm1        \n\t" /* high part to int */
61         " cvtps2pi %%xmm2, %%mm3        \n\t"
62 
63         " packssdw %%mm1, %%mm0         \n\t" /* pack parts */
64         " packssdw %%mm3, %%mm2         \n\t"
65         " movq     %%mm0, (%q3, %0)     \n\t"
66         " movq     %%mm2, 8(%q3, %0)    \n\t"
67 
68         " add $16, %0                   \n\t"
69         " dec %1                        \n\t"
70         " jne 1b                        \n\t"
71 
72         "2:                             \n\t"
73         " mov %4, %1                    \n\t" /* prepare for leftovers */
74         " and $7, %1                    \n\t"
75         " je 5f                         \n\t"
76 
77         "3:                             \n\t"
78         " movss (%q2, %0, 2), %%xmm0    \n\t"
79         " mulss  %%xmm5, %%xmm0         \n\t"
80         " cvtss2si %%xmm0, %4           \n\t"
81         " add $0x8000, %4               \n\t" /* check for saturation */
82         " and $~0xffff, %4              \n\t"
83         " cvtss2si %%xmm0, %4           \n\t"
84         " je 4f                         \n\t"
85         " sar $31, %4                   \n\t"
86         " xor $0x7fff, %4               \n\t"
87 
88         "4:                             \n\t"
89         " movw  %w4, (%q3, %0)          \n\t" /* store leftover */
90         " add $2, %0                    \n\t"
91         " dec %1                        \n\t"
92         " jne 3b                        \n\t"
93 
94         "5:                             \n\t"
95         " emms                          \n\t"
96 
97         : "=&r" (i), "=&r" (temp)
98         : "r" (a), "r" (b), "r" ((pa_reg_x86)n), "m" (*scale)
99         : "cc", "memory"
100     );
101 }
102 
pa_sconv_s16le_from_f32ne_sse2(unsigned n,const float * a,int16_t * b)103 static void pa_sconv_s16le_from_f32ne_sse2(unsigned n, const float *a, int16_t *b) {
104     pa_reg_x86 temp, i;
105 
106     __asm__ __volatile__ (
107         " movaps %5, %%xmm5             \n\t"
108         " xor %0, %0                    \n\t"
109 
110         " mov %4, %1                    \n\t"
111         " sar $3, %1                    \n\t" /* 8 floats at a time */
112         " cmp $0, %1                    \n\t"
113         " je 2f                         \n\t"
114 
115         "1:                             \n\t"
116         " movups (%q2, %0, 2), %%xmm0   \n\t" /* read 8 floats */
117         " movups 16(%q2, %0, 2), %%xmm2 \n\t"
118         " mulps  %%xmm5, %%xmm0         \n\t" /* *= 0x8000 */
119         " mulps  %%xmm5, %%xmm2         \n\t"
120 
121         " cvtps2dq %%xmm0, %%xmm0       \n\t"
122         " cvtps2dq %%xmm2, %%xmm2       \n\t"
123 
124         " packssdw %%xmm2, %%xmm0       \n\t"
125         " movdqu   %%xmm0, (%q3, %0)    \n\t"
126 
127         " add $16, %0                   \n\t"
128         " dec %1                        \n\t"
129         " jne 1b                        \n\t"
130 
131         "2:                             \n\t"
132         " mov %4, %1                    \n\t" /* prepare for leftovers */
133         " and $7, %1                    \n\t"
134         " je 5f                         \n\t"
135 
136         "3:                             \n\t"
137         " movss (%q2, %0, 2), %%xmm0    \n\t"
138         " mulss  %%xmm5, %%xmm0         \n\t"
139         " cvtss2si %%xmm0, %4           \n\t"
140         " add $0x8000, %4               \n\t"
141         " and $~0xffff, %4              \n\t" /* check for saturation */
142         " cvtss2si %%xmm0, %4           \n\t"
143         " je 4f                         \n\t"
144         " sar $31, %4                   \n\t"
145         " xor $0x7fff, %4               \n\t"
146 
147         "4:                             \n\t"
148         " movw  %w4, (%q3, %0)          \n\t" /* store leftover */
149         " add $2, %0                    \n\t"
150         " dec %1                        \n\t"
151         " jne 3b                        \n\t"
152 
153         "5:                             \n\t"
154 
155         : "=&r" (i), "=&r" (temp)
156         : "r" (a), "r" (b), "r" ((pa_reg_x86)n), "m" (*scale)
157         : "cc", "memory"
158     );
159 }
160 
161 #endif /* defined (__i386__) || defined (__amd64__) */
162 
pa_convert_func_init_sse(pa_cpu_x86_flag_t flags)163 void pa_convert_func_init_sse(pa_cpu_x86_flag_t flags) {
164 #if (!defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) && defined (__i386__)) || defined (__amd64__)
165 
166     if (flags & PA_CPU_X86_SSE2) {
167         pa_log_info("Initialising SSE2 optimized conversions.");
168         pa_set_convert_from_float32ne_function(PA_SAMPLE_S16LE, (pa_convert_func_t) pa_sconv_s16le_from_f32ne_sse2);
169         pa_set_convert_to_s16ne_function(PA_SAMPLE_FLOAT32LE, (pa_convert_func_t) pa_sconv_s16le_from_f32ne_sse2);
170     } else if (flags & PA_CPU_X86_SSE) {
171         pa_log_info("Initialising SSE optimized conversions.");
172         pa_set_convert_from_float32ne_function(PA_SAMPLE_S16LE, (pa_convert_func_t) pa_sconv_s16le_from_f32ne_sse);
173         pa_set_convert_to_s16ne_function(PA_SAMPLE_FLOAT32LE, (pa_convert_func_t) pa_sconv_s16le_from_f32ne_sse);
174     }
175 
176 #endif /* defined (__i386__) || defined (__amd64__) */
177 }
178