|
1 /* |
|
2 * Copyright © 2000 SuSE, Inc. |
|
3 * Copyright © 2007 Red Hat, Inc. |
|
4 * |
|
5 * Permission to use, copy, modify, distribute, and sell this software and its |
|
6 * documentation for any purpose is hereby granted without fee, provided that |
|
7 * the above copyright notice appear in all copies and that both that |
|
8 * copyright notice and this permission notice appear in supporting |
|
9 * documentation, and that the name of SuSE not be used in advertising or |
|
10 * publicity pertaining to distribution of the software without specific, |
|
11 * written prior permission. SuSE makes no representations about the |
|
12 * suitability of this software for any purpose. It is provided "as is" |
|
13 * without express or implied warranty. |
|
14 * |
|
15 * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL |
|
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE |
|
17 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
|
19 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
|
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|
21 */ |
|
22 #ifdef HAVE_CONFIG_H |
|
23 #include <config.h> |
|
24 #endif |
|
25 |
|
26 #include <string.h> |
|
27 #include <stdlib.h> |
|
28 |
|
29 #if defined(USE_ARM_SIMD) && defined(_MSC_VER) |
|
30 /* Needed for EXCEPTION_ILLEGAL_INSTRUCTION */ |
|
31 #include <windows.h> |
|
32 #endif |
|
33 |
|
34 #if defined(__APPLE__) |
|
35 #include "TargetConditionals.h" |
|
36 #endif |
|
37 |
|
38 #include "pixman-private.h" |
|
39 |
|
40 #ifdef USE_VMX |
|
41 |
|
42 /* The CPU detection code needs to be in a file not compiled with |
|
43 * "-maltivec -mabi=altivec", as gcc would try to save vector register |
|
44 * across function calls causing SIGILL on cpus without Altivec/vmx. |
|
45 */ |
|
46 static pixman_bool_t initialized = FALSE; |
|
47 static volatile pixman_bool_t have_vmx = TRUE; |
|
48 |
|
49 #ifdef __APPLE__ |
|
50 #include <sys/sysctl.h> |
|
51 |
|
52 static pixman_bool_t |
|
53 pixman_have_vmx (void) |
|
54 { |
|
55 if (!initialized) |
|
56 { |
|
57 size_t length = sizeof(have_vmx); |
|
58 int error = |
|
59 sysctlbyname ("hw.optional.altivec", &have_vmx, &length, NULL, 0); |
|
60 |
|
61 if (error) |
|
62 have_vmx = FALSE; |
|
63 |
|
64 initialized = TRUE; |
|
65 } |
|
66 return have_vmx; |
|
67 } |
|
68 |
|
69 #elif defined (__OpenBSD__) |
|
70 #include <sys/param.h> |
|
71 #include <sys/sysctl.h> |
|
72 #include <machine/cpu.h> |
|
73 |
|
74 static pixman_bool_t |
|
75 pixman_have_vmx (void) |
|
76 { |
|
77 if (!initialized) |
|
78 { |
|
79 int mib[2] = { CTL_MACHDEP, CPU_ALTIVEC }; |
|
80 size_t length = sizeof(have_vmx); |
|
81 int error = |
|
82 sysctl (mib, 2, &have_vmx, &length, NULL, 0); |
|
83 |
|
84 if (error != 0) |
|
85 have_vmx = FALSE; |
|
86 |
|
87 initialized = TRUE; |
|
88 } |
|
89 return have_vmx; |
|
90 } |
|
91 |
|
92 #elif defined (__linux__) |
|
93 #include <sys/types.h> |
|
94 #include <sys/stat.h> |
|
95 #include <fcntl.h> |
|
96 #include <unistd.h> |
|
97 #include <stdio.h> |
|
98 #include <linux/auxvec.h> |
|
99 #include <asm/cputable.h> |
|
100 |
|
101 static pixman_bool_t |
|
102 pixman_have_vmx (void) |
|
103 { |
|
104 if (!initialized) |
|
105 { |
|
106 char fname[64]; |
|
107 unsigned long buf[64]; |
|
108 ssize_t count = 0; |
|
109 pid_t pid; |
|
110 int fd, i; |
|
111 |
|
112 pid = getpid (); |
|
113 snprintf (fname, sizeof(fname) - 1, "/proc/%d/auxv", pid); |
|
114 |
|
115 fd = open (fname, O_RDONLY); |
|
116 if (fd >= 0) |
|
117 { |
|
118 for (i = 0; i <= (count / sizeof(unsigned long)); i += 2) |
|
119 { |
|
120 /* Read more if buf is empty... */ |
|
121 if (i == (count / sizeof(unsigned long))) |
|
122 { |
|
123 count = read (fd, buf, sizeof(buf)); |
|
124 if (count <= 0) |
|
125 break; |
|
126 i = 0; |
|
127 } |
|
128 |
|
129 if (buf[i] == AT_HWCAP) |
|
130 { |
|
131 have_vmx = !!(buf[i + 1] & PPC_FEATURE_HAS_ALTIVEC); |
|
132 initialized = TRUE; |
|
133 break; |
|
134 } |
|
135 else if (buf[i] == AT_NULL) |
|
136 { |
|
137 break; |
|
138 } |
|
139 } |
|
140 close (fd); |
|
141 } |
|
142 } |
|
143 if (!initialized) |
|
144 { |
|
145 /* Something went wrong. Assume 'no' rather than playing |
|
146 fragile tricks with catching SIGILL. */ |
|
147 have_vmx = FALSE; |
|
148 initialized = TRUE; |
|
149 } |
|
150 |
|
151 return have_vmx; |
|
152 } |
|
153 |
|
154 #else /* !__APPLE__ && !__OpenBSD__ && !__linux__ */ |
|
155 #include <signal.h> |
|
156 #include <setjmp.h> |
|
157 |
|
158 static jmp_buf jump_env; |
|
159 |
|
160 static void |
|
161 vmx_test (int sig, |
|
162 siginfo_t *si, |
|
163 void * unused) |
|
164 { |
|
165 longjmp (jump_env, 1); |
|
166 } |
|
167 |
|
168 static pixman_bool_t |
|
169 pixman_have_vmx (void) |
|
170 { |
|
171 struct sigaction sa, osa; |
|
172 int jmp_result; |
|
173 |
|
174 if (!initialized) |
|
175 { |
|
176 sa.sa_flags = SA_SIGINFO; |
|
177 sigemptyset (&sa.sa_mask); |
|
178 sa.sa_sigaction = vmx_test; |
|
179 sigaction (SIGILL, &sa, &osa); |
|
180 jmp_result = setjmp (jump_env); |
|
181 if (jmp_result == 0) |
|
182 { |
|
183 asm volatile ( "vor 0, 0, 0" ); |
|
184 } |
|
185 sigaction (SIGILL, &osa, NULL); |
|
186 have_vmx = (jmp_result == 0); |
|
187 initialized = TRUE; |
|
188 } |
|
189 return have_vmx; |
|
190 } |
|
191 |
|
192 #endif /* __APPLE__ */ |
|
193 #endif /* USE_VMX */ |
|
194 |
|
195 #if defined(USE_ARM_SIMD) || defined(USE_ARM_NEON) || defined(USE_ARM_IWMMXT) |
|
196 |
|
197 #if defined(_MSC_VER) |
|
198 |
|
199 #if defined(USE_ARM_SIMD) |
|
200 extern int pixman_msvc_try_arm_simd_op (); |
|
201 |
|
202 pixman_bool_t |
|
203 pixman_have_arm_simd (void) |
|
204 { |
|
205 static pixman_bool_t initialized = FALSE; |
|
206 static pixman_bool_t have_arm_simd = FALSE; |
|
207 |
|
208 if (!initialized) |
|
209 { |
|
210 __try { |
|
211 pixman_msvc_try_arm_simd_op (); |
|
212 have_arm_simd = TRUE; |
|
213 } __except (GetExceptionCode () == EXCEPTION_ILLEGAL_INSTRUCTION) { |
|
214 have_arm_simd = FALSE; |
|
215 } |
|
216 initialized = TRUE; |
|
217 } |
|
218 |
|
219 return have_arm_simd; |
|
220 } |
|
221 |
|
222 #endif /* USE_ARM_SIMD */ |
|
223 |
|
224 #if defined(USE_ARM_NEON) |
|
225 extern int pixman_msvc_try_arm_neon_op (); |
|
226 |
|
227 pixman_bool_t |
|
228 pixman_have_arm_neon (void) |
|
229 { |
|
230 static pixman_bool_t initialized = FALSE; |
|
231 static pixman_bool_t have_arm_neon = FALSE; |
|
232 |
|
233 if (!initialized) |
|
234 { |
|
235 __try |
|
236 { |
|
237 pixman_msvc_try_arm_neon_op (); |
|
238 have_arm_neon = TRUE; |
|
239 } |
|
240 __except (GetExceptionCode () == EXCEPTION_ILLEGAL_INSTRUCTION) |
|
241 { |
|
242 have_arm_neon = FALSE; |
|
243 } |
|
244 initialized = TRUE; |
|
245 } |
|
246 |
|
247 return have_arm_neon; |
|
248 } |
|
249 |
|
250 #endif /* USE_ARM_NEON */ |
|
251 |
|
252 #elif (defined (__APPLE__) && defined(TARGET_OS_IPHONE)) /* iOS (iPhone/iPad/iPod touch) */ |
|
253 |
|
254 /* Detection of ARM NEON on iOS is fairly simple because iOS binaries |
|
255 * contain separate executable images for each processor architecture. |
|
256 * So all we have to do is detect the armv7 architecture build. The |
|
257 * operating system automatically runs the armv7 binary for armv7 devices |
|
258 * and the armv6 binary for armv6 devices. |
|
259 */ |
|
260 |
|
261 pixman_bool_t |
|
262 pixman_have_arm_simd (void) |
|
263 { |
|
264 #if defined(USE_ARM_SIMD) |
|
265 return TRUE; |
|
266 #else |
|
267 return FALSE; |
|
268 #endif |
|
269 } |
|
270 |
|
271 pixman_bool_t |
|
272 pixman_have_arm_neon (void) |
|
273 { |
|
274 #if defined(USE_ARM_NEON) && defined(__ARM_NEON__) |
|
275 /* This is an armv7 cpu build */ |
|
276 return TRUE; |
|
277 #else |
|
278 /* This is an armv6 cpu build */ |
|
279 return FALSE; |
|
280 #endif |
|
281 } |
|
282 |
|
283 pixman_bool_t |
|
284 pixman_have_arm_iwmmxt (void) |
|
285 { |
|
286 #if defined(USE_ARM_IWMMXT) |
|
287 return FALSE; |
|
288 #else |
|
289 return FALSE; |
|
290 #endif |
|
291 } |
|
292 |
|
293 #elif defined (__linux__) || defined(__ANDROID__) || defined(ANDROID) /* linux ELF or ANDROID */ |
|
294 |
|
295 static pixman_bool_t arm_has_v7 = FALSE; |
|
296 static pixman_bool_t arm_has_v6 = FALSE; |
|
297 static pixman_bool_t arm_has_vfp = FALSE; |
|
298 static pixman_bool_t arm_has_neon = FALSE; |
|
299 static pixman_bool_t arm_has_iwmmxt = FALSE; |
|
300 static pixman_bool_t arm_tests_initialized = FALSE; |
|
301 |
|
302 #if defined(__ANDROID__) || defined(ANDROID) /* Android device support */ |
|
303 |
|
304 static void |
|
305 pixman_arm_read_auxv_or_cpu_features () |
|
306 { |
|
307 char buf[1024]; |
|
308 char* pos; |
|
309 const char* ver_token = "CPU architecture: "; |
|
310 FILE* f = fopen("/proc/cpuinfo", "r"); |
|
311 if (!f) { |
|
312 arm_tests_initialized = TRUE; |
|
313 return; |
|
314 } |
|
315 |
|
316 fread(buf, sizeof(char), sizeof(buf), f); |
|
317 fclose(f); |
|
318 pos = strstr(buf, ver_token); |
|
319 if (pos) { |
|
320 char vchar = *(pos + strlen(ver_token)); |
|
321 if (vchar >= '0' && vchar <= '9') { |
|
322 int ver = vchar - '0'; |
|
323 arm_has_v7 = ver >= 7; |
|
324 arm_has_v6 = ver >= 6; |
|
325 } |
|
326 } |
|
327 arm_has_neon = strstr(buf, "neon") != NULL; |
|
328 arm_has_vfp = strstr(buf, "vfp") != NULL; |
|
329 arm_has_iwmmxt = strstr(buf, "iwmmxt") != NULL; |
|
330 arm_tests_initialized = TRUE; |
|
331 } |
|
332 |
|
333 #elif defined (__linux__) /* linux ELF */ |
|
334 |
|
335 #include <unistd.h> |
|
336 #include <sys/types.h> |
|
337 #include <sys/stat.h> |
|
338 #include <sys/mman.h> |
|
339 #include <fcntl.h> |
|
340 #include <string.h> |
|
341 #include <elf.h> |
|
342 |
|
343 static void |
|
344 pixman_arm_read_auxv_or_cpu_features () |
|
345 { |
|
346 int fd; |
|
347 Elf32_auxv_t aux; |
|
348 |
|
349 fd = open ("/proc/self/auxv", O_RDONLY); |
|
350 if (fd >= 0) |
|
351 { |
|
352 while (read (fd, &aux, sizeof(Elf32_auxv_t)) == sizeof(Elf32_auxv_t)) |
|
353 { |
|
354 if (aux.a_type == AT_HWCAP) |
|
355 { |
|
356 uint32_t hwcap = aux.a_un.a_val; |
|
357 /* hardcode these values to avoid depending on specific |
|
358 * versions of the hwcap header, e.g. HWCAP_NEON |
|
359 */ |
|
360 arm_has_vfp = (hwcap & 64) != 0; |
|
361 arm_has_iwmmxt = (hwcap & 512) != 0; |
|
362 /* this flag is only present on kernel 2.6.29 */ |
|
363 arm_has_neon = (hwcap & 4096) != 0; |
|
364 } |
|
365 else if (aux.a_type == AT_PLATFORM) |
|
366 { |
|
367 const char *plat = (const char*) aux.a_un.a_val; |
|
368 if (strncmp (plat, "v7l", 3) == 0) |
|
369 { |
|
370 arm_has_v7 = TRUE; |
|
371 arm_has_v6 = TRUE; |
|
372 } |
|
373 else if (strncmp (plat, "v6l", 3) == 0) |
|
374 { |
|
375 arm_has_v6 = TRUE; |
|
376 } |
|
377 } |
|
378 } |
|
379 close (fd); |
|
380 } |
|
381 |
|
382 arm_tests_initialized = TRUE; |
|
383 } |
|
384 |
|
385 #endif /* Linux elf */ |
|
386 |
|
387 #if defined(USE_ARM_SIMD) |
|
388 pixman_bool_t |
|
389 pixman_have_arm_simd (void) |
|
390 { |
|
391 if (!arm_tests_initialized) |
|
392 pixman_arm_read_auxv_or_cpu_features (); |
|
393 |
|
394 return arm_has_v6; |
|
395 } |
|
396 |
|
397 #endif /* USE_ARM_SIMD */ |
|
398 |
|
399 #if defined(USE_ARM_NEON) |
|
400 pixman_bool_t |
|
401 pixman_have_arm_neon (void) |
|
402 { |
|
403 if (!arm_tests_initialized) |
|
404 pixman_arm_read_auxv_or_cpu_features (); |
|
405 |
|
406 return arm_has_neon; |
|
407 } |
|
408 |
|
409 #endif /* USE_ARM_NEON */ |
|
410 |
|
411 #if defined(USE_ARM_IWMMXT) |
|
412 pixman_bool_t |
|
413 pixman_have_arm_iwmmxt (void) |
|
414 { |
|
415 if (!arm_tests_initialized) |
|
416 pixman_arm_read_auxv_or_cpu_features (); |
|
417 |
|
418 return arm_has_iwmmxt; |
|
419 } |
|
420 |
|
421 #endif /* USE_ARM_IWMMXT */ |
|
422 |
|
423 #else /* !_MSC_VER && !Linux elf && !Android */ |
|
424 |
|
425 #define pixman_have_arm_simd() FALSE |
|
426 #define pixman_have_arm_neon() FALSE |
|
427 #define pixman_have_arm_iwmmxt() FALSE |
|
428 |
|
429 #endif |
|
430 |
|
431 #endif /* USE_ARM_SIMD || USE_ARM_NEON || USE_ARM_IWMMXT */ |
|
432 |
|
433 #if defined(USE_MIPS_DSPR2) |
|
434 |
|
435 #if defined (__linux__) /* linux ELF */ |
|
436 |
|
437 pixman_bool_t |
|
438 pixman_have_mips_dspr2 (void) |
|
439 { |
|
440 const char *search_string = "MIPS 74K"; |
|
441 const char *file_name = "/proc/cpuinfo"; |
|
442 /* Simple detection of MIPS DSP ASE (revision 2) at runtime for Linux. |
|
443 * It is based on /proc/cpuinfo, which reveals hardware configuration |
|
444 * to user-space applications. According to MIPS (early 2010), no similar |
|
445 * facility is universally available on the MIPS architectures, so it's up |
|
446 * to individual OSes to provide such. |
|
447 * |
|
448 * Only currently available MIPS core that supports DSPr2 is 74K. |
|
449 */ |
|
450 |
|
451 char cpuinfo_line[256]; |
|
452 |
|
453 FILE *f = NULL; |
|
454 |
|
455 if ((f = fopen (file_name, "r")) == NULL) |
|
456 return FALSE; |
|
457 |
|
458 while (fgets (cpuinfo_line, sizeof (cpuinfo_line), f) != NULL) |
|
459 { |
|
460 if (strstr (cpuinfo_line, search_string) != NULL) |
|
461 { |
|
462 fclose (f); |
|
463 return TRUE; |
|
464 } |
|
465 } |
|
466 |
|
467 fclose (f); |
|
468 |
|
469 /* Did not find string in the proc file. */ |
|
470 return FALSE; |
|
471 } |
|
472 |
|
473 #else /* linux ELF */ |
|
474 |
|
475 #define pixman_have_mips_dspr2() FALSE |
|
476 |
|
477 #endif /* linux ELF */ |
|
478 |
|
479 #endif /* USE_MIPS_DSPR2 */ |
|
480 |
|
481 #if defined(USE_X86_MMX) || defined(USE_SSE2) |
|
482 /* The CPU detection code needs to be in a file not compiled with |
|
483 * "-mmmx -msse", as gcc would generate CMOV instructions otherwise |
|
484 * that would lead to SIGILL instructions on old CPUs that don't have |
|
485 * it. |
|
486 */ |
|
487 #if !defined(__amd64__) && !defined(__x86_64__) && !defined(_M_AMD64) |
|
488 |
|
489 #ifdef HAVE_GETISAX |
|
490 #include <sys/auxv.h> |
|
491 #endif |
|
492 |
|
493 typedef enum |
|
494 { |
|
495 NO_FEATURES = 0, |
|
496 MMX = 0x1, |
|
497 MMX_EXTENSIONS = 0x2, |
|
498 SSE = 0x6, |
|
499 SSE2 = 0x8, |
|
500 CMOV = 0x10 |
|
501 } cpu_features_t; |
|
502 |
|
503 |
|
504 static unsigned int |
|
505 detect_cpu_features (void) |
|
506 { |
|
507 unsigned int features = 0; |
|
508 unsigned int result = 0; |
|
509 |
|
510 #ifdef HAVE_GETISAX |
|
511 if (getisax (&result, 1)) |
|
512 { |
|
513 if (result & AV_386_CMOV) |
|
514 features |= CMOV; |
|
515 if (result & AV_386_MMX) |
|
516 features |= MMX; |
|
517 if (result & AV_386_AMD_MMX) |
|
518 features |= MMX_EXTENSIONS; |
|
519 if (result & AV_386_SSE) |
|
520 features |= SSE; |
|
521 if (result & AV_386_SSE2) |
|
522 features |= SSE2; |
|
523 } |
|
524 #else |
|
525 char vendor[13]; |
|
526 #ifdef _MSC_VER |
|
527 int vendor0 = 0, vendor1, vendor2; |
|
528 #endif |
|
529 vendor[0] = 0; |
|
530 vendor[12] = 0; |
|
531 |
|
532 #ifdef __GNUC__ |
|
533 /* see p. 118 of amd64 instruction set manual Vol3 */ |
|
534 /* We need to be careful about the handling of %ebx and |
|
535 * %esp here. We can't declare either one as clobbered |
|
536 * since they are special registers (%ebx is the "PIC |
|
537 * register" holding an offset to global data, %esp the |
|
538 * stack pointer), so we need to make sure they have their |
|
539 * original values when we access the output operands. |
|
540 */ |
|
541 __asm__ ( |
|
542 "pushf\n" |
|
543 "pop %%eax\n" |
|
544 "mov %%eax, %%ecx\n" |
|
545 "xor $0x00200000, %%eax\n" |
|
546 "push %%eax\n" |
|
547 "popf\n" |
|
548 "pushf\n" |
|
549 "pop %%eax\n" |
|
550 "mov $0x0, %%edx\n" |
|
551 "xor %%ecx, %%eax\n" |
|
552 "jz 1f\n" |
|
553 |
|
554 "mov $0x00000000, %%eax\n" |
|
555 "push %%ebx\n" |
|
556 "cpuid\n" |
|
557 "mov %%ebx, %%eax\n" |
|
558 "pop %%ebx\n" |
|
559 "mov %%eax, %1\n" |
|
560 "mov %%edx, %2\n" |
|
561 "mov %%ecx, %3\n" |
|
562 "mov $0x00000001, %%eax\n" |
|
563 "push %%ebx\n" |
|
564 "cpuid\n" |
|
565 "pop %%ebx\n" |
|
566 "1:\n" |
|
567 "mov %%edx, %0\n" |
|
568 : "=r" (result), |
|
569 "=m" (vendor[0]), |
|
570 "=m" (vendor[4]), |
|
571 "=m" (vendor[8]) |
|
572 : |
|
573 : "%eax", "%ecx", "%edx" |
|
574 ); |
|
575 |
|
576 #elif defined (_MSC_VER) |
|
577 |
|
578 _asm { |
|
579 pushfd |
|
580 pop eax |
|
581 mov ecx, eax |
|
582 xor eax, 00200000h |
|
583 push eax |
|
584 popfd |
|
585 pushfd |
|
586 pop eax |
|
587 mov edx, 0 |
|
588 xor eax, ecx |
|
589 jz nocpuid |
|
590 |
|
591 mov eax, 0 |
|
592 push ebx |
|
593 cpuid |
|
594 mov eax, ebx |
|
595 pop ebx |
|
596 mov vendor0, eax |
|
597 mov vendor1, edx |
|
598 mov vendor2, ecx |
|
599 mov eax, 1 |
|
600 push ebx |
|
601 cpuid |
|
602 pop ebx |
|
603 nocpuid: |
|
604 mov result, edx |
|
605 } |
|
606 memmove (vendor + 0, &vendor0, 4); |
|
607 memmove (vendor + 4, &vendor1, 4); |
|
608 memmove (vendor + 8, &vendor2, 4); |
|
609 |
|
610 #else |
|
611 # error unsupported compiler |
|
612 #endif |
|
613 |
|
614 features = 0; |
|
615 if (result) |
|
616 { |
|
617 /* result now contains the standard feature bits */ |
|
618 if (result & (1 << 15)) |
|
619 features |= CMOV; |
|
620 if (result & (1 << 23)) |
|
621 features |= MMX; |
|
622 if (result & (1 << 25)) |
|
623 features |= SSE; |
|
624 if (result & (1 << 26)) |
|
625 features |= SSE2; |
|
626 if ((features & MMX) && !(features & SSE) && |
|
627 (strcmp (vendor, "AuthenticAMD") == 0 || |
|
628 strcmp (vendor, "Geode by NSC") == 0)) |
|
629 { |
|
630 /* check for AMD MMX extensions */ |
|
631 #ifdef __GNUC__ |
|
632 __asm__ ( |
|
633 " push %%ebx\n" |
|
634 " mov $0x80000000, %%eax\n" |
|
635 " cpuid\n" |
|
636 " xor %%edx, %%edx\n" |
|
637 " cmp $0x1, %%eax\n" |
|
638 " jge 2f\n" |
|
639 " mov $0x80000001, %%eax\n" |
|
640 " cpuid\n" |
|
641 "2:\n" |
|
642 " pop %%ebx\n" |
|
643 " mov %%edx, %0\n" |
|
644 : "=r" (result) |
|
645 : |
|
646 : "%eax", "%ecx", "%edx" |
|
647 ); |
|
648 #elif defined _MSC_VER |
|
649 _asm { |
|
650 push ebx |
|
651 mov eax, 80000000h |
|
652 cpuid |
|
653 xor edx, edx |
|
654 cmp eax, 1 |
|
655 jge notamd |
|
656 mov eax, 80000001h |
|
657 cpuid |
|
658 notamd: |
|
659 pop ebx |
|
660 mov result, edx |
|
661 } |
|
662 #endif |
|
663 if (result & (1 << 22)) |
|
664 features |= MMX_EXTENSIONS; |
|
665 } |
|
666 } |
|
667 #endif /* HAVE_GETISAX */ |
|
668 |
|
669 return features; |
|
670 } |
|
671 |
|
672 #ifdef USE_X86_MMX |
|
673 static pixman_bool_t |
|
674 pixman_have_mmx (void) |
|
675 { |
|
676 static pixman_bool_t initialized = FALSE; |
|
677 static pixman_bool_t mmx_present; |
|
678 |
|
679 if (!initialized) |
|
680 { |
|
681 unsigned int features = detect_cpu_features (); |
|
682 mmx_present = (features & (MMX | MMX_EXTENSIONS)) == (MMX | MMX_EXTENSIONS); |
|
683 initialized = TRUE; |
|
684 } |
|
685 |
|
686 return mmx_present; |
|
687 } |
|
688 #endif |
|
689 |
|
690 #ifdef USE_SSE2 |
|
691 static pixman_bool_t |
|
692 pixman_have_sse2 (void) |
|
693 { |
|
694 static pixman_bool_t initialized = FALSE; |
|
695 static pixman_bool_t sse2_present; |
|
696 |
|
697 if (!initialized) |
|
698 { |
|
699 unsigned int features = detect_cpu_features (); |
|
700 sse2_present = (features & (MMX | MMX_EXTENSIONS | SSE | SSE2)) == (MMX | MMX_EXTENSIONS | SSE | SSE2); |
|
701 initialized = TRUE; |
|
702 } |
|
703 |
|
704 return sse2_present; |
|
705 } |
|
706 |
|
707 #endif |
|
708 |
|
709 #else /* __amd64__ */ |
|
710 #ifdef USE_X86_MMX |
|
711 #define pixman_have_mmx() TRUE |
|
712 #endif |
|
713 #ifdef USE_SSE2 |
|
714 #define pixman_have_sse2() TRUE |
|
715 #endif |
|
716 #endif /* __amd64__ */ |
|
717 #endif |
|
718 |
|
719 static pixman_bool_t |
|
720 disabled (const char *name) |
|
721 { |
|
722 const char *env; |
|
723 |
|
724 if ((env = getenv ("PIXMAN_DISABLE"))) |
|
725 { |
|
726 do |
|
727 { |
|
728 const char *end; |
|
729 int len; |
|
730 |
|
731 if ((end = strchr (env, ' '))) |
|
732 len = end - env; |
|
733 else |
|
734 len = strlen (env); |
|
735 |
|
736 if (strlen (name) == len && strncmp (name, env, len) == 0) |
|
737 { |
|
738 printf ("pixman: Disabled %s implementation\n", name); |
|
739 return TRUE; |
|
740 } |
|
741 |
|
742 env += len; |
|
743 } |
|
744 while (*env++); |
|
745 } |
|
746 |
|
747 return FALSE; |
|
748 } |
|
749 |
|
750 pixman_implementation_t * |
|
751 _pixman_choose_implementation (void) |
|
752 { |
|
753 pixman_implementation_t *imp; |
|
754 |
|
755 imp = _pixman_implementation_create_general(); |
|
756 |
|
757 if (!disabled ("fast")) |
|
758 imp = _pixman_implementation_create_fast_path (imp); |
|
759 |
|
760 #ifdef USE_X86_MMX |
|
761 if (!disabled ("mmx") && pixman_have_mmx ()) |
|
762 imp = _pixman_implementation_create_mmx (imp); |
|
763 #endif |
|
764 |
|
765 #ifdef USE_SSE2 |
|
766 if (!disabled ("sse2") && pixman_have_sse2 ()) |
|
767 imp = _pixman_implementation_create_sse2 (imp); |
|
768 #endif |
|
769 |
|
770 #ifdef USE_ARM_SIMD |
|
771 if (!disabled ("arm-simd") && pixman_have_arm_simd ()) |
|
772 imp = _pixman_implementation_create_arm_simd (imp); |
|
773 #endif |
|
774 |
|
775 #ifdef USE_ARM_IWMMXT |
|
776 if (!disabled ("arm-iwmmxt") && pixman_have_arm_iwmmxt ()) |
|
777 imp = _pixman_implementation_create_mmx (imp); |
|
778 #endif |
|
779 |
|
780 #ifdef USE_ARM_NEON |
|
781 if (!disabled ("arm-neon") && pixman_have_arm_neon ()) |
|
782 imp = _pixman_implementation_create_arm_neon (imp); |
|
783 #endif |
|
784 |
|
785 #ifdef USE_MIPS_DSPR2 |
|
786 if (!disabled ("mips-dspr2") && pixman_have_mips_dspr2 ()) |
|
787 imp = _pixman_implementation_create_mips_dspr2 (imp); |
|
788 #endif |
|
789 |
|
790 #ifdef USE_VMX |
|
791 if (!disabled ("vmx") && pixman_have_vmx ()) |
|
792 imp = _pixman_implementation_create_vmx (imp); |
|
793 #endif |
|
794 |
|
795 imp = _pixman_implementation_create_noop (imp); |
|
796 |
|
797 return imp; |
|
798 } |
|
799 |