Statistics
| Branch: | Revision:

ffmpeg / libavcodec / x86 / cpuid.c @ b1c32fb5

History | View | Annotate | Download (4.69 KB)

1
/*
2
 * CPU detection code, extracted from mmx.h
3
 * (c)1997-99 by H. Dietz and R. Fisher
4
 * Converted to C and improved by Fabrice Bellard.
5
 *
6
 * This file is part of FFmpeg.
7
 *
8
 * FFmpeg is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public
10
 * License as published by the Free Software Foundation; either
11
 * version 2.1 of the License, or (at your option) any later version.
12
 *
13
 * FFmpeg is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public
19
 * License along with FFmpeg; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
 */
22

    
23
#include <stdlib.h>
24
#include "libavutil/x86_cpu.h"
25
#include "libavcodec/dsputil.h"
26

    
27
#undef printf
28

    
29
/* ebx saving is necessary for PIC. gcc seems unable to see it alone */
30
#define cpuid(index,eax,ebx,ecx,edx)\
31
    __asm__ volatile\
32
        ("mov %%"REG_b", %%"REG_S"\n\t"\
33
         "cpuid\n\t"\
34
         "xchg %%"REG_b", %%"REG_S\
35
         : "=a" (eax), "=S" (ebx),\
36
           "=c" (ecx), "=d" (edx)\
37
         : "0" (index));
38

    
39
/* Function to test if multimedia instructions are supported...  */
40
int mm_support(void)
41
{
42
    int rval = 0;
43
    int eax, ebx, ecx, edx;
44
    int max_std_level, max_ext_level, std_caps=0, ext_caps=0;
45
    int family=0, model=0;
46
    union { int i[3]; char c[12]; } vendor;
47

    
48
#if ARCH_X86_32
49
    x86_reg a, c;
50
    __asm__ volatile (
51
        /* See if CPUID instruction is supported ... */
52
        /* ... Get copies of EFLAGS into eax and ecx */
53
        "pushfl\n\t"
54
        "pop %0\n\t"
55
        "mov %0, %1\n\t"
56

    
57
        /* ... Toggle the ID bit in one copy and store */
58
        /*     to the EFLAGS reg */
59
        "xor $0x200000, %0\n\t"
60
        "push %0\n\t"
61
        "popfl\n\t"
62

    
63
        /* ... Get the (hopefully modified) EFLAGS */
64
        "pushfl\n\t"
65
        "pop %0\n\t"
66
        : "=a" (a), "=c" (c)
67
        :
68
        : "cc"
69
        );
70

    
71
    if (a == c)
72
        return 0; /* CPUID not supported */
73
#endif
74

    
75
    cpuid(0, max_std_level, vendor.i[0], vendor.i[2], vendor.i[1]);
76

    
77
    if(max_std_level >= 1){
78
        cpuid(1, eax, ebx, ecx, std_caps);
79
        family = ((eax>>8)&0xf) + ((eax>>20)&0xff);
80
        model  = ((eax>>4)&0xf) + ((eax>>12)&0xf0);
81
        if (std_caps & (1<<23))
82
            rval |= AV_CPU_FLAG_MMX;
83
        if (std_caps & (1<<25))
84
            rval |= AV_CPU_FLAG_MMX2
85
#if HAVE_SSE
86
                  | AV_CPU_FLAG_SSE;
87
        if (std_caps & (1<<26))
88
            rval |= AV_CPU_FLAG_SSE2;
89
        if (ecx & 1)
90
            rval |= AV_CPU_FLAG_SSE3;
91
        if (ecx & 0x00000200 )
92
            rval |= AV_CPU_FLAG_SSSE3;
93
        if (ecx & 0x00080000 )
94
            rval |= AV_CPU_FLAG_SSE4;
95
        if (ecx & 0x00100000 )
96
            rval |= AV_CPU_FLAG_SSE42;
97
#endif
98
                  ;
99
    }
100

    
101
    cpuid(0x80000000, max_ext_level, ebx, ecx, edx);
102

    
103
    if(max_ext_level >= 0x80000001){
104
        cpuid(0x80000001, eax, ebx, ecx, ext_caps);
105
        if (ext_caps & (1<<31))
106
            rval |= AV_CPU_FLAG_3DNOW;
107
        if (ext_caps & (1<<30))
108
            rval |= AV_CPU_FLAG_3DNOWEXT;
109
        if (ext_caps & (1<<23))
110
            rval |= AV_CPU_FLAG_MMX;
111
        if (ext_caps & (1<<22))
112
            rval |= AV_CPU_FLAG_MMX2;
113
    }
114

    
115
    if (!strncmp(vendor.c, "GenuineIntel", 12) &&
116
        family == 6 && (model == 9 || model == 13 || model == 14)) {
117
        /* 6/9 (pentium-m "banias"), 6/13 (pentium-m "dothan"), and 6/14 (core1 "yonah")
118
         * theoretically support sse2, but it's usually slower than mmx,
119
         * so let's just pretend they don't. */
120
        if (rval & AV_CPU_FLAG_SSE2) rval ^= AV_CPU_FLAG_SSE2SLOW|AV_CPU_FLAG_SSE2;
121
        if (rval & AV_CPU_FLAG_SSE3) rval ^= AV_CPU_FLAG_SSE3SLOW|AV_CPU_FLAG_SSE3;
122
    }
123

    
124
#if 0
125
    av_log(NULL, AV_LOG_DEBUG, "%s%s%s%s%s%s%s%s%s%s%s%s\n",
126
        (rval&AV_CPU_FLAG_MMX) ? "MMX ":"",
127
        (rval&AV_CPU_FLAG_MMX2) ? "MMX2 ":"",
128
        (rval&AV_CPU_FLAG_SSE) ? "SSE ":"",
129
        (rval&AV_CPU_FLAG_SSE2) ? "SSE2 ":"",
130
        (rval&AV_CPU_FLAG_SSE2SLOW) ? "SSE2(slow) ":"",
131
        (rval&AV_CPU_FLAG_SSE3) ? "SSE3 ":"",
132
        (rval&AV_CPU_FLAG_SSE3SLOW) ? "SSE3(slow) ":"",
133
        (rval&AV_CPU_FLAG_SSSE3) ? "SSSE3 ":"",
134
        (rval&AV_CPU_FLAG_SSE4) ? "SSE4.1 ":"",
135
        (rval&AV_CPU_FLAG_SSE42) ? "SSE4.2 ":"",
136
        (rval&AV_CPU_FLAG_3DNOW) ? "3DNow ":"",
137
        (rval&AV_CPU_FLAG_3DNOWEXT) ? "3DNowExt ":"");
138
#endif
139
    return rval;
140
}
141

    
142
#ifdef TEST
143
int main ( void )
144
{
145
    int mm_flags;
146
    mm_flags = mm_support();
147
    printf("mm_support = 0x%08X\n",mm_flags);
148
    return 0;
149
}
150
#endif