gimpcpuaccel.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /* The GIMP -- an image manipulation program
  2. * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17. */
  18. /*
  19. * CPU acceleration detection was taken from DirectFB but seems to be
  20. * originating from mpeg2dec with the following copyright:
  21. *
  22. * Copyright (C) 1999-2001 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
  23. */
  24. #include "config.h"
  25. #include <stdio.h>
  26. #include <signal.h>
  27. #include <setjmp.h>
  28. #include <glib.h>
  29. #include "cpu-accel.h"
  30. #ifdef ARCH_X86
  31. static guint32
  32. arch_accel (void)
  33. {
  34. guint32 eax, ebx, ecx, edx;
  35. gint AMD;
  36. guint32 caps = 0;
  37. #define cpuid(op,eax,ebx,ecx,edx) \
  38. asm ("pushl %%ebx\n\t" \
  39. "cpuid\n\t" \
  40. "movl %%ebx,%1\n\t" \
  41. "popl %%ebx" \
  42. : "=a" (eax), \
  43. "=r" (ebx), \
  44. "=c" (ecx), \
  45. "=d" (edx) \
  46. : "a" (op) \
  47. : "cc")
  48. asm ("pushfl\n\t"
  49. "pushfl\n\t"
  50. "popl %0\n\t"
  51. "movl %0,%1\n\t"
  52. "xorl $0x200000,%0\n\t"
  53. "pushl %0\n\t"
  54. "popfl\n\t"
  55. "pushfl\n\t"
  56. "popl %0\n\t"
  57. "popfl"
  58. : "=r" (eax),
  59. "=r" (ebx)
  60. :
  61. : "cc");
  62. if (eax == ebx) /* no cpuid */
  63. return 0;
  64. cpuid (0x00000000, eax, ebx, ecx, edx);
  65. if (!eax) /* vendor string only */
  66. return 0;
  67. AMD = (ebx == 0x68747541) && (ecx == 0x444d4163) && (edx == 0x69746e65);
  68. cpuid (0x00000001, eax, ebx, ecx, edx);
  69. if (! (edx & 0x00800000)) /* no MMX */
  70. return 0;
  71. #ifdef USE_MMX
  72. caps = CPU_ACCEL_X86_MMX;
  73. #ifdef USE_SSE
  74. if (edx & 0x02000000) /* SSE - identical to AMD MMX extensions */
  75. caps |= CPU_ACCEL_X86_SSE | CPU_ACCEL_X86_MMXEXT;
  76. if (edx & 0x04000000) /* SSE2 */
  77. caps |= CPU_ACCEL_X86_SSE2;
  78. cpuid (0x80000000, eax, ebx, ecx, edx);
  79. if (eax < 0x80000001) /* no extended capabilities */
  80. return caps;
  81. cpuid (0x80000001, eax, ebx, ecx, edx);
  82. if (edx & 0x80000000)
  83. caps |= CPU_ACCEL_X86_3DNOW;
  84. if (AMD && (edx & 0x00400000)) /* AMD MMX extensions */
  85. caps |= CPU_ACCEL_X86_MMXEXT;
  86. #endif /* USE_SSE */
  87. #endif /* USE_MMX */
  88. return caps;
  89. }
  90. static jmp_buf sigill_return;
  91. static void
  92. sigill_handler (gint n)
  93. {
  94. g_printerr ("OS lacks support for SSE instructions.\n");
  95. longjmp(sigill_return, 1);
  96. }
  97. #endif /* ARCH_X86 */
  98. #if defined (ARCH_PPC) && defined (USE_ALTIVEC)
  99. static sigjmp_buf jmpbuf;
  100. static volatile sig_atomic_t canjump = 0;
  101. static void
  102. sigill_handler (gint sig)
  103. {
  104. if (!canjump)
  105. {
  106. signal (sig, SIG_DFL);
  107. raise (sig);
  108. }
  109. canjump = 0;
  110. siglongjmp (jmpbuf, 1);
  111. }
  112. static guint32
  113. arch_accel (void)
  114. {
  115. signal (SIGILL, sigill_handler);
  116. if (sigsetjmp (jmpbuf, 1))
  117. {
  118. signal (SIGILL, SIG_DFL);
  119. return 0;
  120. }
  121. canjump = 1;
  122. asm volatile ("mtspr 256, %0\n\t"
  123. "vand %%v0, %%v0, %%v0"
  124. :
  125. : "r" (-1));
  126. signal (SIGILL, SIG_DFL);
  127. return CPU_ACCEL_PPC_ALTIVEC;
  128. }
  129. #endif /* ARCH_PPC */
  130. guint32
  131. cpu_accel (void)
  132. {
  133. #if defined (ARCH_X86) || (defined (ARCH_PPC) && defined (USE_ALTIVEC))
  134. static guint32 accel = ~0U;
  135. if (accel != ~0U)
  136. return accel;
  137. accel = arch_accel ();
  138. #ifdef USE_SSE
  139. /* test OS support for SSE */
  140. if (accel & CPU_ACCEL_X86_SSE)
  141. {
  142. if (setjmp (sigill_return))
  143. {
  144. accel &= ~(CPU_ACCEL_X86_SSE | CPU_ACCEL_X86_SSE2);
  145. }
  146. else
  147. {
  148. signal (SIGILL, sigill_handler);
  149. __asm __volatile ("xorps %xmm0, %xmm0");
  150. signal (SIGILL, SIG_DFL);
  151. }
  152. }
  153. #endif /* USE_SSE */
  154. return accel;
  155. #else /* !ARCH_X86 && !ARCH_PPC/USE_ALTIVEC */
  156. return 0;
  157. #endif
  158. }