0,0 → 1,904 |
/* |
optimize: get a grip on the different optimizations |
|
copyright 2006-9 by the mpg123 project - free software under the terms of the LGPL 2.1 |
see COPYING and AUTHORS files in distribution or http://mpg123.org |
initially written by Thomas Orgis, inspired by 3DNow stuff in mpg123.[hc] |
|
Currently, this file contains the struct and function to choose an optimization variant and works only when OPT_MULTI is in effect. |
*/ |
|
#include "mpg123lib_intern.h" /* includes optimize.h */ |
#include "debug.h" |
|
/* Must match the enum dectype! */ |
|
/* |
It SUCKS having to define these names that way, but compile-time intialization of string arrays is a bitch. |
GCC doesn't see constant stuff when it's wiggling in front of it! |
Anyhow: Have a script for that: |
names="generic generic_dither i386 i486 i586 i586_dither MMX 3DNow 3DNowExt AltiVec SSE x86-64" |
for i in $names; do echo "##define dn_${i/-/_} \"$i\""; done |
echo -n "static const char* decname[] = |
{ |
\"auto\" |
" |
for i in $names; do echo -n ", dn_${i/-/_}"; done |
echo " |
, \"nodec\" |
};" |
*/ |
#define dn_generic "generic" |
#define dn_generic_dither "generic_dither" |
#define dn_i386 "i386" |
#define dn_i486 "i486" |
#define dn_i586 "i586" |
#define dn_i586_dither "i586_dither" |
#define dn_MMX "MMX" |
#define dn_3DNow "3DNow" |
#define dn_3DNowExt "3DNowExt" |
#define dn_AltiVec "AltiVec" |
#define dn_SSE "SSE" |
#define dn_x86_64 "x86-64" |
#define dn_ARM "ARM" |
static const char* decname[] = |
{ |
"auto" |
, dn_generic, dn_generic_dither, dn_i386, dn_i486, dn_i586, dn_i586_dither, dn_MMX, dn_3DNow, dn_3DNowExt, dn_AltiVec, dn_SSE, dn_x86_64, dn_ARM |
, "nodec" |
}; |
|
#if (defined OPT_X86) && (defined OPT_MULTI) |
#include "getcpuflags.h" |
struct cpuflags cpu_flags; |
#else |
/* Faking stuff for non-multi builds. The same code for synth function choice is used. |
Just no runtime dependency of result... */ |
char cpu_flags; |
#define cpu_i586(s) 1 |
#define cpu_fpu(s) 1 |
#define cpu_mmx(s) 1 |
#define cpu_3dnow(s) 1 |
#define cpu_3dnowext(s) 1 |
#define cpu_sse(s) 1 |
#define cpu_sse2(s) 1 |
#define cpu_sse3(s) 1 |
#endif |
|
/* Ugly macros to build conditional synth function array values. */ |
|
#ifndef NO_8BIT |
#define IF8(synth) synth, |
#else |
#define IF8(synth) |
#endif |
|
#ifndef NO_REAL |
#define IFREAL(synth) synth, |
#else |
#define IFREAL(synth) |
#endif |
|
#ifndef NO_32BIT |
#define IF32(synth) synth |
#else |
#define IF32(synth) |
#endif |
|
#ifndef NO_16BIT |
# define OUT_SYNTHS(synth_16, synth_8, synth_real, synth_32) { synth_16, IF8(synth_8) IFREAL(synth_real) IF32(synth_32) } |
#else |
# define OUT_SYNTHS(synth_16, synth_8, synth_real, synth_32) { IF8(synth_8) IFREAL(synth_real) IF32(synth_32) } |
#endif |
|
const struct synth_s synth_base = |
{ |
{ /* plain */ |
OUT_SYNTHS(synth_1to1, synth_1to1_8bit, synth_1to1_real, synth_1to1_s32) |
# ifndef NO_DOWNSAMPLE |
,OUT_SYNTHS(synth_2to1, synth_2to1_8bit, synth_2to1_real, synth_2to1_s32) |
,OUT_SYNTHS(synth_4to1, synth_4to1_8bit, synth_4to1_real, synth_4to1_s32) |
# endif |
# ifndef NO_NTOM |
,OUT_SYNTHS(synth_ntom, synth_ntom_8bit, synth_ntom_real, synth_ntom_s32) |
# endif |
}, |
{ /* stereo, by default only wrappers over plain synth */ |
OUT_SYNTHS(synth_stereo_wrap, synth_stereo_wrap, synth_stereo_wrap, synth_stereo_wrap) |
# ifndef NO_DOWNSAMPLE |
,OUT_SYNTHS(synth_stereo_wrap, synth_stereo_wrap, synth_stereo_wrap, synth_stereo_wrap) |
,OUT_SYNTHS(synth_stereo_wrap, synth_stereo_wrap, synth_stereo_wrap, synth_stereo_wrap) |
# endif |
# ifndef NO_NTOM |
,OUT_SYNTHS(synth_stereo_wrap, synth_stereo_wrap, synth_stereo_wrap, synth_stereo_wrap) |
# endif |
}, |
{ /* mono2stereo */ |
OUT_SYNTHS(synth_1to1_mono2stereo, synth_1to1_8bit_mono2stereo, synth_1to1_real_mono2stereo, synth_1to1_s32_mono2stereo) |
# ifndef NO_DOWNSAMPLE |
,OUT_SYNTHS(synth_2to1_mono2stereo, synth_2to1_8bit_mono2stereo, synth_2to1_real_mono2stereo, synth_2to1_s32_mono2stereo) |
,OUT_SYNTHS(synth_4to1_mono2stereo, synth_4to1_8bit_mono2stereo, synth_4to1_real_mono2stereo, synth_4to1_s32_mono2stereo) |
# endif |
# ifndef NO_NTOM |
,OUT_SYNTHS(synth_ntom_mono2stereo, synth_ntom_8bit_mono2stereo, synth_ntom_real_mono2stereo, synth_ntom_s32_mono2stereo) |
# endif |
}, |
{ /* mono*/ |
OUT_SYNTHS(synth_1to1_mono, synth_1to1_8bit_mono, synth_1to1_real_mono, synth_1to1_s32_mono) |
# ifndef NO_DOWNSAMPLE |
,OUT_SYNTHS(synth_2to1_mono, synth_2to1_8bit_mono, synth_2to1_real_mono, synth_2to1_s32_mono) |
,OUT_SYNTHS(synth_4to1_mono, synth_4to1_8bit_mono, synth_4to1_real_mono, synth_4to1_s32_mono) |
# endif |
# ifndef NO_NTOM |
,OUT_SYNTHS(synth_ntom_mono, synth_ntom_8bit_mono, synth_ntom_real_mono, synth_ntom_s32_mono) |
#endif |
} |
}; |
|
#ifdef OPT_X86 |
/* More plain synths for i386 */ |
const func_synth plain_i386[r_limit][f_limit] = |
{ /* plain */ |
OUT_SYNTHS(synth_1to1_i386, synth_1to1_8bit_i386, synth_1to1_real_i386, synth_1to1_s32_i386) |
# ifndef NO_DOWNSAMPLE |
,OUT_SYNTHS(synth_2to1_i386, synth_2to1_8bit_i386, synth_2to1_real_i386, synth_2to1_s32_i386) |
,OUT_SYNTHS(synth_4to1_i386, synth_4to1_8bit_i386, synth_4to1_real_i386, synth_4to1_s32_i386) |
# endif |
# ifndef NO_NTOM |
,OUT_SYNTHS(synth_ntom, synth_ntom_8bit, synth_ntom_real, synth_ntom_s32) |
# endif |
}; |
#endif |
|
|
enum optdec defdec(void){ return defopt; } |
|
enum optcla decclass(const enum optdec type) |
{ |
return (type == mmx || type == sse || type == dreidnowext || type == x86_64 ) ? mmxsse : normal; |
} |
|
|
static int find_synth(func_synth synth, const func_synth synths[r_limit][f_limit]) |
{ |
enum synth_resample ri; |
enum synth_format fi; |
for(ri=0; ri<r_limit; ++ri) |
for(fi=0; fi<f_limit; ++fi) |
if(synth == synths[ri][fi]) |
return TRUE; |
|
return FALSE; |
} |
|
/* Determine what kind of decoder is actually active |
This depends on runtime choices which may cause fallback to i386 or generic code. */ |
static int find_dectype(mpg123_handle *fr) |
{ |
enum optdec type = nodec; |
/* Direct and indirect usage, 1to1 stereo decoding. |
Concentrating on the plain stereo synth should be fine, mono stuff is derived. */ |
func_synth basic_synth = fr->synth; |
#ifndef NO_8BIT |
#ifndef NO_16BIT |
if(basic_synth == synth_1to1_8bit_wrap) |
basic_synth = fr->synths.plain[r_1to1][f_16]; /* That is what's really below the surface. */ |
#endif |
#endif |
|
if(FALSE) ; /* Just to initialize the else if ladder. */ |
#ifndef NO_16BIT |
#ifdef OPT_3DNOWEXT |
else if(basic_synth == synth_1to1_3dnowext) type = dreidnowext; |
#endif |
#ifdef OPT_SSE |
else if(basic_synth == synth_1to1_sse) type = sse; |
#endif |
#ifdef OPT_3DNOW |
else if(basic_synth == synth_1to1_3dnow) type = dreidnow; |
#endif |
#ifdef OPT_MMX |
else if(basic_synth == synth_1to1_mmx) type = mmx; |
#endif |
#ifdef OPT_I586_DITHER |
else if(basic_synth == synth_1to1_i586_dither) type = ifuenf_dither; |
#endif |
#ifdef OPT_I586 |
else if(basic_synth == synth_1to1_i586) type = ifuenf; |
#endif |
#ifdef OPT_ALTIVEC |
else if(basic_synth == synth_1to1_altivec) type = altivec; |
#endif |
#ifdef OPT_X86_64 |
else if(basic_synth == synth_1to1_x86_64) type = x86_64; |
#endif |
#ifdef OPT_ARM |
else if(basic_synth == synth_1to1_arm) type = arm; |
#endif |
#ifdef OPT_GENERIC_DITHER |
else if(basic_synth == synth_1to1_dither) type = generic_dither; |
#endif |
#ifdef OPT_DITHER /* either i586 or generic! */ |
#ifndef NO_DOWNSAMPLE |
else if |
( |
basic_synth == synth_2to1_dither |
|| basic_synth == synth_4to1_dither |
) type = generic_dither; |
#endif |
#endif |
#endif /* 16bit */ |
|
#ifndef NO_REAL |
#ifdef OPT_SSE |
else if(basic_synth == synth_1to1_real_sse) type = sse; |
#endif |
#ifdef OPT_X86_64 |
else if(basic_synth == synth_1to1_real_x86_64) type = x86_64; |
#endif |
#ifdef OPT_ALTIVEC |
else if(basic_synth == synth_1to1_real_altivec) type = altivec; |
#endif |
|
#endif /* real */ |
|
#ifndef NO_32BIT |
#ifdef OPT_SSE |
else if(basic_synth == synth_1to1_s32_sse) type = sse; |
#endif |
#ifdef OPT_X86_64 |
else if(basic_synth == synth_1to1_s32_x86_64) type = x86_64; |
#endif |
#ifdef OPT_ALTIVEC |
else if(basic_synth == synth_1to1_s32_altivec) type = altivec; |
#endif |
#endif /* 32bit */ |
|
#ifdef OPT_X86 |
else if(find_synth(basic_synth, plain_i386)) |
type = idrei; |
#endif |
|
else if(find_synth(basic_synth, synth_base.plain)) |
type = generic; |
|
|
|
#ifdef OPT_I486 |
/* i486 is special ... the specific code is in use for 16bit 1to1 stereo |
otherwise we have i386 active... but still, the distinction doesn't matter*/ |
type = ivier; |
#endif |
|
if(type != nodec) |
{ |
fr->cpu_opts.type = type; |
fr->cpu_opts.class = decclass(type); |
|
debug3("determined active decoder type %i (%s) of class %i", type, decname[type], fr->cpu_opts.class); |
return MPG123_OK; |
} |
else |
{ |
if(NOQUIET) error("Unable to determine active decoder type -- this is SERIOUS b0rkage!"); |
|
fr->err = MPG123_BAD_DECODER_SETUP; |
return MPG123_ERR; |
} |
} |
|
/* set synth functions for current frame, optimizations handled by opt_* macros */ |
int set_synth_functions(mpg123_handle *fr) |
{ |
enum synth_resample resample = r_none; |
enum synth_format basic_format = f_none; /* Default is always 16bit, or whatever. */ |
|
/* Select the basic output format, different from 16bit: 8bit, real. */ |
if(FALSE){} |
#ifndef NO_16BIT |
else if(fr->af.encoding & MPG123_ENC_16) |
basic_format = f_16; |
#endif |
#ifndef NO_8BIT |
else if(fr->af.encoding & MPG123_ENC_8) |
basic_format = f_8; |
#endif |
#ifndef NO_REAL |
else if(fr->af.encoding & MPG123_ENC_FLOAT) |
basic_format = f_real; |
#endif |
#ifndef NO_32BIT |
else if(fr->af.encoding & MPG123_ENC_32) |
basic_format = f_32; |
#endif |
|
/* Make sure the chosen format is compiled into this lib. */ |
if(basic_format == f_none) |
{ |
if(NOQUIET) error("set_synth_functions: This output format is disabled in this build!"); |
|
return -1; |
} |
|
/* Be explicit about downsampling variant. */ |
switch(fr->down_sample) |
{ |
case 0: resample = r_1to1; break; |
#ifndef NO_DOWNSAMPLE |
case 1: resample = r_2to1; break; |
case 2: resample = r_4to1; break; |
#endif |
#ifndef NO_NTOM |
case 3: resample = r_ntom; break; |
#endif |
} |
|
if(resample == r_none) |
{ |
if(NOQUIET) error("set_synth_functions: This resampling mode is not supported in this build!"); |
|
return -1; |
} |
|
debug2("selecting synth: resample=%i format=%i", resample, basic_format); |
/* Finally selecting the synth functions for stereo / mono. */ |
fr->synth = fr->synths.plain[resample][basic_format]; |
fr->synth_stereo = fr->synths.stereo[resample][basic_format]; |
fr->synth_mono = fr->af.channels==2 |
? fr->synths.mono2stereo[resample][basic_format] /* Mono MPEG file decoded to stereo. */ |
: fr->synths.mono[resample][basic_format]; /* Mono MPEG file decoded to mono. */ |
|
if(find_dectype(fr) != MPG123_OK) /* Actually determine the currently active decoder breed. */ |
{ |
fr->err = MPG123_BAD_DECODER_SETUP; |
return MPG123_ERR; |
} |
|
if(frame_buffers(fr) != 0) |
{ |
fr->err = MPG123_NO_BUFFERS; |
if(NOQUIET) error("Failed to set up decoder buffers!"); |
|
return MPG123_ERR; |
} |
|
#ifndef NO_8BIT |
if(basic_format == f_8) |
{ |
if(make_conv16to8_table(fr) != 0) |
{ |
if(NOQUIET) error("Failed to set up conv16to8 table!"); |
/* it's a bit more work to get proper error propagation up */ |
return -1; |
} |
} |
#endif |
|
#ifdef OPT_MMXORSSE |
/* Special treatment for MMX, SSE and 3DNowExt stuff. |
The real-decoding SSE for x86-64 uses normal tables! */ |
if(fr->cpu_opts.class == mmxsse |
# ifndef NO_REAL |
&& basic_format != f_real |
# endif |
# ifndef NO_32BIT |
&& basic_format != f_32 |
# endif |
# ifdef ACCURATE_ROUNDING |
&& fr->cpu_opts.type != sse |
&& fr->cpu_opts.type != x86_64 |
# endif |
) |
{ |
#ifndef NO_LAYER3 |
init_layer3_stuff(fr, init_layer3_gainpow2_mmx); |
#endif |
#ifndef NO_LAYER12 |
init_layer12_stuff(fr, init_layer12_table_mmx); |
#endif |
fr->make_decode_tables = make_decode_tables_mmx; |
} |
else |
#endif |
{ |
#ifndef NO_LAYER3 |
init_layer3_stuff(fr, init_layer3_gainpow2); |
#endif |
#ifndef NO_LAYER12 |
init_layer12_stuff(fr, init_layer12_table); |
#endif |
fr->make_decode_tables = make_decode_tables; |
} |
|
/* We allocated the table buffers just now, so (re)create the tables. */ |
fr->make_decode_tables(fr); |
|
return 0; |
} |
|
int frame_cpu_opt(mpg123_handle *fr, const char* cpu) |
{ |
const char* chosen = ""; /* the chosen decoder opt as string */ |
enum optdec want_dec = nodec; |
int done = 0; |
int auto_choose = 0; |
#ifdef OPT_DITHER |
int dithered = FALSE; /* If some dithered decoder is chosen. */ |
#endif |
|
want_dec = dectype(cpu); |
auto_choose = want_dec == autodec; |
/* Fill whole array of synth functions with generic code first. */ |
fr->synths = synth_base; |
|
#ifndef OPT_MULTI |
{ |
if(!auto_choose && want_dec != defopt) |
{ |
if(NOQUIET) error2("you wanted decoder type %i, I only have %i", want_dec, defopt); |
} |
auto_choose = TRUE; /* There will be only one choice anyway. */ |
} |
#endif |
|
fr->cpu_opts.type = nodec; |
/* covers any i386+ cpu; they actually differ only in the synth_1to1 function, mostly... */ |
#ifdef OPT_X86 |
|
#ifndef NO_LAYER3 |
#if (defined OPT_3DNOW || defined OPT_3DNOWEXT) |
fr->cpu_opts.dct36 = dct36; |
#endif |
#endif |
|
if(cpu_i586(cpu_flags)) |
{ |
# ifdef OPT_MULTI |
debug2("standard flags: 0x%08x\textended flags: 0x%08x", cpu_flags.std, cpu_flags.ext); |
# endif |
#ifdef OPT_SSE |
if( !done && (auto_choose || want_dec == sse) |
&& cpu_sse(cpu_flags) && cpu_mmx(cpu_flags) ) |
{ |
chosen = "SSE"; |
fr->cpu_opts.type = sse; |
# ifndef NO_16BIT |
fr->synths.plain[r_1to1][f_16] = synth_1to1_sse; |
# ifdef ACCURATE_ROUNDING |
fr->synths.stereo[r_1to1][f_16] = synth_1to1_stereo_sse; |
# endif |
# endif |
# ifndef NO_REAL |
fr->synths.plain[r_1to1][f_real] = synth_1to1_real_sse; |
fr->synths.stereo[r_1to1][f_real] = synth_1to1_real_stereo_sse; |
# endif |
# ifndef NO_32BIT |
fr->synths.plain[r_1to1][f_32] = synth_1to1_s32_sse; |
fr->synths.stereo[r_1to1][f_32] = synth_1to1_s32_stereo_sse; |
# endif |
done = 1; |
} |
#endif |
# ifdef OPT_3DNOWEXT |
if( !done && (auto_choose || want_dec == dreidnowext ) |
&& cpu_3dnow(cpu_flags) |
&& cpu_3dnowext(cpu_flags) |
&& cpu_mmx(cpu_flags) ) |
{ |
chosen = "3DNowExt"; |
fr->cpu_opts.type = dreidnowext; |
# ifndef NO_LAYER3 |
fr->cpu_opts.dct36 = dct36_3dnowext; |
# endif |
# ifndef NO_16BIT |
fr->synths.plain[r_1to1][f_16] = synth_1to1_3dnowext; |
# endif |
done = 1; |
} |
#endif |
#ifdef OPT_3DNOW |
if( !done && (auto_choose || want_dec == dreidnow) |
&& cpu_3dnow(cpu_flags) && cpu_mmx(cpu_flags) ) |
{ |
chosen = "3DNow"; |
fr->cpu_opts.type = dreidnow; |
# ifndef NO_LAYER3 |
fr->cpu_opts.dct36 = dct36_3dnow; |
# endif |
# ifndef NO_16BIT |
fr->synths.plain[r_1to1][f_16] = synth_1to1_3dnow; |
# endif |
done = 1; |
} |
#endif |
#ifdef OPT_MMX |
if( !done && (auto_choose || want_dec == mmx) |
&& cpu_mmx(cpu_flags) ) |
{ |
chosen = "MMX"; |
fr->cpu_opts.type = mmx; |
# ifndef NO_16BIT |
fr->synths.plain[r_1to1][f_16] = synth_1to1_mmx; |
# endif |
done = 1; |
} |
#endif |
#ifdef OPT_I586 |
if(!done && (auto_choose || want_dec == ifuenf)) |
{ |
chosen = "i586/pentium"; |
fr->cpu_opts.type = ifuenf; |
# ifndef NO_16BIT |
fr->synths.plain[r_1to1][f_16] = synth_1to1_i586; |
# endif |
done = 1; |
} |
#endif |
#ifdef OPT_I586_DITHER |
if(!done && (auto_choose || want_dec == ifuenf_dither)) |
{ |
chosen = "dithered i586/pentium"; |
fr->cpu_opts.type = ifuenf_dither; |
dithered = TRUE; |
# ifndef NO_16BIT |
fr->synths.plain[r_1to1][f_16] = synth_1to1_i586_dither; |
# ifndef NO_DOWNSAMPLE |
fr->synths.plain[r_2to1][f_16] = synth_2to1_dither; |
fr->synths.plain[r_4to1][f_16] = synth_4to1_dither; |
# endif |
# endif |
done = 1; |
} |
#endif |
} |
#ifdef OPT_I486 |
/* That won't cooperate in multi opt mode - forcing i486 in layer3.c |
But still... here it is... maybe for real use in future. */ |
if(!done && (auto_choose || want_dec == ivier)) |
{ |
chosen = "i486"; |
fr->cpu_opts.type = ivier; |
done = 1; |
} |
#endif |
#ifdef OPT_I386 |
if(!done && (auto_choose || want_dec == idrei)) |
{ |
chosen = "i386"; |
fr->cpu_opts.type = idrei; |
done = 1; |
} |
#endif |
|
if(done) |
{ |
/* |
We have chosen some x86 decoder... fillup some i386 stuff. |
There is an open question about using dithered synth_1to1 for 8bit wrappers. |
For quality it won't make sense, but wrapped i586_dither wrapped may still be faster... |
*/ |
enum synth_resample ri; |
enum synth_format fi; |
# ifndef NO_8BIT |
# ifndef NO_16BIT /* possibility to use a 16->8 wrapper... */ |
if(fr->synths.plain[r_1to1][f_16] != synth_base.plain[r_1to1][f_16]) |
{ |
fr->synths.plain[r_1to1][f_8] = synth_1to1_8bit_wrap; |
fr->synths.mono[r_1to1][f_8] = synth_1to1_8bit_wrap_mono; |
fr->synths.mono2stereo[r_1to1][f_8] = synth_1to1_8bit_wrap_mono2stereo; |
} |
# endif |
# endif |
for(ri=0; ri<r_limit; ++ri) |
for(fi=0; fi<f_limit; ++fi) |
{ |
if(fr->synths.plain[ri][fi] == synth_base.plain[ri][fi]) |
fr->synths.plain[ri][fi] = plain_i386[ri][fi]; |
} |
} |
|
#endif /* OPT_X86 */ |
|
#ifdef OPT_X86_64 |
if(!done && (auto_choose || want_dec == x86_64)) |
{ |
chosen = "x86-64 (SSE)"; |
fr->cpu_opts.type = x86_64; |
# ifndef NO_16BIT |
fr->synths.plain[r_1to1][f_16] = synth_1to1_x86_64; |
fr->synths.stereo[r_1to1][f_16] = synth_1to1_stereo_x86_64; |
# endif |
# ifndef NO_REAL |
fr->synths.plain[r_1to1][f_real] = synth_1to1_real_x86_64; |
fr->synths.stereo[r_1to1][f_real] = synth_1to1_real_stereo_x86_64; |
# endif |
# ifndef NO_32BIT |
fr->synths.plain[r_1to1][f_32] = synth_1to1_s32_x86_64; |
fr->synths.stereo[r_1to1][f_32] = synth_1to1_s32_stereo_x86_64; |
# endif |
done = 1; |
} |
#endif |
|
#ifdef OPT_GENERIC_DITHER |
if(!done && (auto_choose || want_dec == generic_dither)) |
{ |
chosen = "dithered generic"; |
fr->cpu_opts.type = generic_dither; |
dithered = TRUE; |
# ifndef NO_16BIT |
fr->synths.plain[r_1to1][f_16] = synth_1to1_dither; |
# ifndef NO_DOWNSAMPLE |
fr->synths.plain[r_2to1][f_16] = synth_2to1_dither; |
fr->synths.plain[r_4to1][f_16] = synth_4to1_dither; |
# endif |
# endif |
done = 1; |
} |
#endif |
|
# ifdef OPT_ALTIVEC |
if(!done && (auto_choose || want_dec == altivec)) |
{ |
chosen = "AltiVec"; |
fr->cpu_opts.type = altivec; |
# ifndef NO_16BIT |
fr->synths.plain[r_1to1][f_16] = synth_1to1_altivec; |
fr->synths.stereo[r_1to1][f_16] = synth_1to1_stereo_altivec; |
# endif |
# ifndef NO_REAL |
fr->synths.plain[r_1to1][f_real] = synth_1to1_real_altivec; |
fr->synths.stereo[r_1to1][f_real] = synth_1to1_real_stereo_altivec; |
# endif |
# ifndef NO_32BIT |
fr->synths.plain[r_1to1][f_32] = synth_1to1_s32_altivec; |
fr->synths.stereo[r_1to1][f_32] = synth_1to1_s32_stereo_altivec; |
# endif |
done = 1; |
} |
# endif |
|
# ifdef OPT_ARM |
if(!done && (auto_choose || want_dec == arm)) |
{ |
chosen = "ARM"; |
fr->cpu_opts.type = arm; |
# ifndef NO_16BIT |
fr->synths.plain[r_1to1][f_16] = synth_1to1_arm; |
# endif |
done = 1; |
} |
# endif |
|
# ifdef OPT_GENERIC |
if(!done && (auto_choose || want_dec == generic)) |
{ |
chosen = "generic"; |
fr->cpu_opts.type = generic; |
done = 1; |
} |
# endif |
|
fr->cpu_opts.class = decclass(fr->cpu_opts.type); |
|
# ifndef NO_8BIT |
# ifndef NO_16BIT /* possibility to use a 16->8 wrapper... */ |
/* Last chance to use some optimized routine via generic wrappers (for 8bit). */ |
if( fr->cpu_opts.type != ifuenf_dither |
&& fr->cpu_opts.type != generic_dither |
&& fr->synths.plain[r_1to1][f_16] != synth_base.plain[r_1to1][f_16] ) |
{ |
fr->synths.plain[r_1to1][f_8] = synth_1to1_8bit_wrap; |
fr->synths.mono[r_1to1][f_8] = synth_1to1_8bit_wrap_mono; |
fr->synths.mono2stereo[r_1to1][f_8] = synth_1to1_8bit_wrap_mono2stereo; |
} |
# endif |
# endif |
|
#ifdef OPT_DITHER |
if(done && dithered) |
{ |
/* run-time dither noise table generation */ |
if(!frame_dither_init(fr)) |
{ |
if(NOQUIET) error("Dither noise setup failed!"); |
return 0; |
} |
} |
#endif |
|
if(done) |
{ |
if(VERBOSE) fprintf(stderr, "Decoder: %s\n", chosen); |
return 1; |
} |
else |
{ |
if(NOQUIET) error("Could not set optimization!"); |
return 0; |
} |
} |
|
enum optdec dectype(const char* decoder) |
{ |
enum optdec dt; |
if( (decoder == NULL) |
|| (decoder[0] == 0) ) |
return autodec; |
|
for(dt=autodec; dt<nodec; ++dt) |
if(!strcasecmp(decoder, decname[dt])) return dt; |
|
return nodec; /* If we found nothing... */ |
} |
|
#ifdef OPT_MULTI |
|
/* same number of entries as full list, but empty at beginning */ |
static const char *mpg123_supported_decoder_list[] = |
{ |
#ifdef OPT_SSE |
NULL, |
#endif |
#ifdef OPT_3DNOWEXT |
NULL, |
#endif |
#ifdef OPT_3DNOW |
NULL, |
#endif |
#ifdef OPT_MMX |
NULL, |
#endif |
#ifdef OPT_I586 |
NULL, |
#endif |
#ifdef OPT_I586_DITHER |
NULL, |
#endif |
#ifdef OPT_I486 |
NULL, |
#endif |
#ifdef OPT_I386 |
NULL, |
#endif |
#ifdef OPT_ALTIVEC |
NULL, |
#endif |
#ifdef OPT_X86_64 |
NULL, |
#endif |
#ifdef OPT_ARM |
NULL, |
#endif |
#ifdef OPT_GENERIC_FLOAT |
NULL, |
#endif |
# ifdef OPT_GENERIC |
NULL, |
# endif |
# ifdef OPT_GENERIC_DITHER |
NULL, |
# endif |
NULL |
}; |
#endif |
|
static const char *mpg123_decoder_list[] = |
{ |
#ifdef OPT_SSE |
dn_SSE, |
#endif |
#ifdef OPT_3DNOWEXT |
dn_3DNowExt, |
#endif |
#ifdef OPT_3DNOW |
dn_3DNow, |
#endif |
#ifdef OPT_MMX |
dn_MMX, |
#endif |
#ifdef OPT_I586 |
dn_i586, |
#endif |
#ifdef OPT_I586_DITHER |
dn_i586_dither, |
#endif |
#ifdef OPT_I486 |
dn_i486, |
#endif |
#ifdef OPT_I386 |
dn_i386, |
#endif |
#ifdef OPT_ALTIVEC |
dn_AltiVec, |
#endif |
#ifdef OPT_X86_64 |
dn_x86_64, |
#endif |
#ifdef OPT_ARM |
dn_ARM, |
#endif |
#ifdef OPT_GENERIC |
dn_generic, |
#endif |
#ifdef OPT_GENERIC_DITHER |
dn_generic_dither, |
#endif |
NULL |
}; |
|
void check_decoders(void ) |
{ |
#ifndef OPT_MULTI |
/* In non-multi mode, only the full list (one entry) is used. */ |
return; |
#else |
const char **d = mpg123_supported_decoder_list; |
#ifdef OPT_X86 |
getcpuflags(&cpu_flags); |
if(cpu_i586(cpu_flags)) |
{ |
/* not yet: if(cpu_sse2(cpu_flags)) printf(" SSE2"); |
if(cpu_sse3(cpu_flags)) printf(" SSE3"); */ |
#ifdef OPT_SSE |
if(cpu_sse(cpu_flags)) *(d++) = decname[sse]; |
#endif |
#ifdef OPT_3DNOWEXT |
if(cpu_3dnowext(cpu_flags)) *(d++) = decname[dreidnowext]; |
#endif |
#ifdef OPT_3DNOW |
if(cpu_3dnow(cpu_flags)) *(d++) = decname[dreidnow]; |
#endif |
#ifdef OPT_MMX |
if(cpu_mmx(cpu_flags)) *(d++) = decname[mmx]; |
#endif |
#ifdef OPT_I586 |
*(d++) = decname[ifuenf]; |
#endif |
#ifdef OPT_I586_DITHER |
*(d++) = decname[ifuenf_dither]; |
#endif |
} |
#endif |
/* just assume that the i486 built is run on a i486 cpu... */ |
#ifdef OPT_I486 |
*(d++) = decname[ivier]; |
#endif |
#ifdef OPT_ALTIVEC |
*(d++) = decname[altivec]; |
#endif |
/* every supported x86 can do i386, any cpu can do generic */ |
#ifdef OPT_I386 |
*(d++) = decname[idrei]; |
#endif |
#ifdef OPT_X86_64 |
*(d++) = decname[x86_64]; |
#endif |
#ifdef OPT_ARM |
*(d++) = decname[arm]; |
#endif |
#ifdef OPT_GENERIC |
*(d++) = decname[generic]; |
#endif |
#ifdef OPT_GENERIC_DITHER |
*(d++) = decname[generic_dither]; |
#endif |
#endif /* ndef OPT_MULTI */ |
} |
|
const char* attribute_align_arg mpg123_current_decoder(mpg123_handle *mh) |
{ |
if(mh == NULL) return NULL; |
|
return decname[mh->cpu_opts.type]; |
} |
|
const char attribute_align_arg **mpg123_decoders(){ return mpg123_decoder_list; } |
const char attribute_align_arg **mpg123_supported_decoders() |
{ |
#ifdef OPT_MULTI |
return mpg123_supported_decoder_list; |
#else |
return mpg123_decoder_list; |
#endif |
} |