/project/jni/sdl-1.3/src/video/SDL_stretch.c

https://github.com/aichunyu/FFPlayer · C · 363 lines · 287 code · 26 blank · 50 comment · 56 complexity · 06eb090072b77765bb570054c7ff6b9d MD5 · raw file

  1. /*
  2. Simple DirectMedia Layer
  3. Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any damages
  6. arising from the use of this software.
  7. Permission is granted to anyone to use this software for any purpose,
  8. including commercial applications, and to alter it and redistribute it
  9. freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you must not
  11. claim that you wrote the original software. If you use this software
  12. in a product, an acknowledgment in the product documentation would be
  13. appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and must not be
  15. misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. #include "SDL_config.h"
  19. /* This a stretch blit implementation based on ideas given to me by
  20. Tomasz Cejner - thanks! :)
  21. April 27, 2000 - Sam Lantinga
  22. */
  23. #include "SDL_video.h"
  24. #include "SDL_blit.h"
  25. /* This isn't ready for general consumption yet - it should be folded
  26. into the general blitting mechanism.
  27. */
  28. #if ((defined(_MFC_VER) && defined(_M_IX86)/* && !defined(_WIN32_WCE) still needed? */) || \
  29. defined(__WATCOMC__) || \
  30. (defined(__GNUC__) && defined(__i386__))) && SDL_ASSEMBLY_ROUTINES
  31. /* There's a bug with gcc 4.4.1 and -O2 where srcp doesn't get the correct
  32. * value after the first scanline. FIXME? */
  33. /*#define USE_ASM_STRETCH*/
  34. #endif
  35. #ifdef USE_ASM_STRETCH
  36. #ifdef HAVE_MPROTECT
  37. #include <sys/types.h>
  38. #include <sys/mman.h>
  39. #endif
  40. #ifdef __GNUC__
  41. #define PAGE_ALIGNED __attribute__((__aligned__(4096)))
  42. #else
  43. #define PAGE_ALIGNED
  44. #endif
  45. #if defined(_M_IX86) || defined(i386)
  46. #define PREFIX16 0x66
  47. #define STORE_BYTE 0xAA
  48. #define STORE_WORD 0xAB
  49. #define LOAD_BYTE 0xAC
  50. #define LOAD_WORD 0xAD
  51. #define RETURN 0xC3
  52. #else
  53. #error Need assembly opcodes for this architecture
  54. #endif
  55. static unsigned char copy_row[4096] PAGE_ALIGNED;
  56. static int
  57. generate_rowbytes(int src_w, int dst_w, int bpp)
  58. {
  59. static struct
  60. {
  61. int bpp;
  62. int src_w;
  63. int dst_w;
  64. int status;
  65. } last;
  66. int i;
  67. int pos, inc;
  68. unsigned char *eip, *fence;
  69. unsigned char load, store;
  70. /* See if we need to regenerate the copy buffer */
  71. if ((src_w == last.src_w) && (dst_w == last.dst_w) && (bpp == last.bpp)) {
  72. return (last.status);
  73. }
  74. last.bpp = bpp;
  75. last.src_w = src_w;
  76. last.dst_w = dst_w;
  77. last.status = -1;
  78. switch (bpp) {
  79. case 1:
  80. load = LOAD_BYTE;
  81. store = STORE_BYTE;
  82. break;
  83. case 2:
  84. case 4:
  85. load = LOAD_WORD;
  86. store = STORE_WORD;
  87. break;
  88. default:
  89. SDL_SetError("ASM stretch of %d bytes isn't supported\n", bpp);
  90. return (-1);
  91. }
  92. #ifdef HAVE_MPROTECT
  93. /* Make the code writeable */
  94. if (mprotect(copy_row, sizeof(copy_row), PROT_READ | PROT_WRITE) < 0) {
  95. SDL_SetError("Couldn't make copy buffer writeable");
  96. return (-1);
  97. }
  98. #endif
  99. pos = 0x10000;
  100. inc = (src_w << 16) / dst_w;
  101. eip = copy_row;
  102. fence = copy_row + sizeof(copy_row)-2;
  103. for (i = 0; i < dst_w; ++i) {
  104. while (pos >= 0x10000L) {
  105. if (eip == fence) {
  106. return -1;
  107. }
  108. if (bpp == 2) {
  109. *eip++ = PREFIX16;
  110. }
  111. *eip++ = load;
  112. pos -= 0x10000L;
  113. }
  114. if (eip == fence) {
  115. return -1;
  116. }
  117. if (bpp == 2) {
  118. *eip++ = PREFIX16;
  119. }
  120. *eip++ = store;
  121. pos += inc;
  122. }
  123. *eip++ = RETURN;
  124. #ifdef HAVE_MPROTECT
  125. /* Make the code executable but not writeable */
  126. if (mprotect(copy_row, sizeof(copy_row), PROT_READ | PROT_EXEC) < 0) {
  127. SDL_SetError("Couldn't make copy buffer executable");
  128. return (-1);
  129. }
  130. #endif
  131. last.status = 0;
  132. return (0);
  133. }
  134. #endif /* USE_ASM_STRETCH */
  135. #define DEFINE_COPY_ROW(name, type) \
  136. static void name(type *src, int src_w, type *dst, int dst_w) \
  137. { \
  138. int i; \
  139. int pos, inc; \
  140. type pixel = 0; \
  141. \
  142. pos = 0x10000; \
  143. inc = (src_w << 16) / dst_w; \
  144. for ( i=dst_w; i>0; --i ) { \
  145. while ( pos >= 0x10000L ) { \
  146. pixel = *src++; \
  147. pos -= 0x10000L; \
  148. } \
  149. *dst++ = pixel; \
  150. pos += inc; \
  151. } \
  152. }
  153. /* *INDENT-OFF* */
  154. DEFINE_COPY_ROW(copy_row1, Uint8)
  155. DEFINE_COPY_ROW(copy_row2, Uint16)
  156. DEFINE_COPY_ROW(copy_row4, Uint32)
  157. /* *INDENT-ON* */
  158. /* The ASM code doesn't handle 24-bpp stretch blits */
  159. static void
  160. copy_row3(Uint8 * src, int src_w, Uint8 * dst, int dst_w)
  161. {
  162. int i;
  163. int pos, inc;
  164. Uint8 pixel[3] = { 0, 0, 0 };
  165. pos = 0x10000;
  166. inc = (src_w << 16) / dst_w;
  167. for (i = dst_w; i > 0; --i) {
  168. while (pos >= 0x10000L) {
  169. pixel[0] = *src++;
  170. pixel[1] = *src++;
  171. pixel[2] = *src++;
  172. pos -= 0x10000L;
  173. }
  174. *dst++ = pixel[0];
  175. *dst++ = pixel[1];
  176. *dst++ = pixel[2];
  177. pos += inc;
  178. }
  179. }
  180. /* Perform a stretch blit between two surfaces of the same format.
  181. NOTE: This function is not safe to call from multiple threads!
  182. */
  183. int
  184. SDL_SoftStretch(SDL_Surface * src, const SDL_Rect * srcrect,
  185. SDL_Surface * dst, const SDL_Rect * dstrect)
  186. {
  187. int src_locked;
  188. int dst_locked;
  189. int pos, inc;
  190. int dst_width;
  191. int dst_maxrow;
  192. int src_row, dst_row;
  193. Uint8 *srcp = NULL;
  194. Uint8 *dstp;
  195. SDL_Rect full_src;
  196. SDL_Rect full_dst;
  197. #ifdef USE_ASM_STRETCH
  198. SDL_bool use_asm = SDL_TRUE;
  199. #ifdef __GNUC__
  200. int u1, u2;
  201. #endif
  202. #endif /* USE_ASM_STRETCH */
  203. const int bpp = dst->format->BytesPerPixel;
  204. if (src->format->BitsPerPixel != dst->format->BitsPerPixel) {
  205. SDL_SetError("Only works with same format surfaces");
  206. return (-1);
  207. }
  208. /* Verify the blit rectangles */
  209. if (srcrect) {
  210. if ((srcrect->x < 0) || (srcrect->y < 0) ||
  211. ((srcrect->x + srcrect->w) > src->w) ||
  212. ((srcrect->y + srcrect->h) > src->h)) {
  213. SDL_SetError("Invalid source blit rectangle");
  214. return (-1);
  215. }
  216. } else {
  217. full_src.x = 0;
  218. full_src.y = 0;
  219. full_src.w = src->w;
  220. full_src.h = src->h;
  221. srcrect = &full_src;
  222. }
  223. if (dstrect) {
  224. if ((dstrect->x < 0) || (dstrect->y < 0) ||
  225. ((dstrect->x + dstrect->w) > dst->w) ||
  226. ((dstrect->y + dstrect->h) > dst->h)) {
  227. SDL_SetError("Invalid destination blit rectangle");
  228. return (-1);
  229. }
  230. } else {
  231. full_dst.x = 0;
  232. full_dst.y = 0;
  233. full_dst.w = dst->w;
  234. full_dst.h = dst->h;
  235. dstrect = &full_dst;
  236. }
  237. /* Lock the destination if it's in hardware */
  238. dst_locked = 0;
  239. if (SDL_MUSTLOCK(dst)) {
  240. if (SDL_LockSurface(dst) < 0) {
  241. SDL_SetError("Unable to lock destination surface");
  242. return (-1);
  243. }
  244. dst_locked = 1;
  245. }
  246. /* Lock the source if it's in hardware */
  247. src_locked = 0;
  248. if (SDL_MUSTLOCK(src)) {
  249. if (SDL_LockSurface(src) < 0) {
  250. if (dst_locked) {
  251. SDL_UnlockSurface(dst);
  252. }
  253. SDL_SetError("Unable to lock source surface");
  254. return (-1);
  255. }
  256. src_locked = 1;
  257. }
  258. /* Set up the data... */
  259. pos = 0x10000;
  260. inc = (srcrect->h << 16) / dstrect->h;
  261. src_row = srcrect->y;
  262. dst_row = dstrect->y;
  263. dst_width = dstrect->w * bpp;
  264. #ifdef USE_ASM_STRETCH
  265. /* Write the opcodes for this stretch */
  266. if ((bpp == 3) || (generate_rowbytes(srcrect->w, dstrect->w, bpp) < 0)) {
  267. use_asm = SDL_FALSE;
  268. }
  269. #endif
  270. /* Perform the stretch blit */
  271. for (dst_maxrow = dst_row + dstrect->h; dst_row < dst_maxrow; ++dst_row) {
  272. dstp = (Uint8 *) dst->pixels + (dst_row * dst->pitch)
  273. + (dstrect->x * bpp);
  274. while (pos >= 0x10000L) {
  275. srcp = (Uint8 *) src->pixels + (src_row * src->pitch)
  276. + (srcrect->x * bpp);
  277. ++src_row;
  278. pos -= 0x10000L;
  279. }
  280. #ifdef USE_ASM_STRETCH
  281. if (use_asm) {
  282. #ifdef __GNUC__
  283. __asm__ __volatile__("call *%4":"=&D"(u1), "=&S"(u2)
  284. :"0"(dstp), "1"(srcp), "r"(copy_row)
  285. :"memory");
  286. #elif defined(_MSC_VER) || defined(__WATCOMC__)
  287. /* *INDENT-OFF* */
  288. {
  289. void *code = copy_row;
  290. __asm {
  291. push edi
  292. push esi
  293. mov edi, dstp
  294. mov esi, srcp
  295. call dword ptr code
  296. pop esi
  297. pop edi
  298. }
  299. }
  300. /* *INDENT-ON* */
  301. #else
  302. #error Need inline assembly for this compiler
  303. #endif
  304. } else
  305. #endif
  306. switch (bpp) {
  307. case 1:
  308. copy_row1(srcp, srcrect->w, dstp, dstrect->w);
  309. break;
  310. case 2:
  311. copy_row2((Uint16 *) srcp, srcrect->w,
  312. (Uint16 *) dstp, dstrect->w);
  313. break;
  314. case 3:
  315. copy_row3(srcp, srcrect->w, dstp, dstrect->w);
  316. break;
  317. case 4:
  318. copy_row4((Uint32 *) srcp, srcrect->w,
  319. (Uint32 *) dstp, dstrect->w);
  320. break;
  321. }
  322. pos += inc;
  323. }
  324. /* We need to unlock the surfaces if they're locked */
  325. if (dst_locked) {
  326. SDL_UnlockSurface(dst);
  327. }
  328. if (src_locked) {
  329. SDL_UnlockSurface(src);
  330. }
  331. return (0);
  332. }
  333. /* vi: set ts=4 sw=4 expandtab: */