testautomation_blit.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /**
  2. * SDL_BlitSurface bit-perfect rendering test suite written by Isaac Aronson
  3. */
  4. /* Suppress C4996 VS compiler warnings for unlink() */
  5. #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
  6. #define _CRT_SECURE_NO_DEPRECATE
  7. #endif
  8. #if defined(_MSC_VER) && !defined(_CRT_NONSTDC_NO_DEPRECATE)
  9. #define _CRT_NONSTDC_NO_DEPRECATE
  10. #endif
  11. #include <stdio.h>
  12. #ifndef _MSC_VER
  13. #include <unistd.h>
  14. #else
  15. /* Suppress uint64 to uint32 conversion warning within the PRNG engine */
  16. #pragma warning( disable : 4244 )
  17. #endif
  18. #include <sys/stat.h>
  19. #include <SDL3/SDL.h>
  20. #include <SDL3/SDL_test.h>
  21. #include "testautomation_images.h"
  22. /* ====== xoroshiro128+ PRNG engine for deterministic blit input ===== */
  23. Uint64 rotl(Uint64 x, int k) { return (x << k) | (x >> (-k & 63)); }
  24. Uint64 next(Uint64 state[2]) {
  25. Uint64 s0 = state[0], s1 = state[1];
  26. Uint64 result = rotl((s0 + s1) * 9, 29) + s0;
  27. state[0] = s0 ^ rotl(s1, 29);
  28. state[1] = s0 ^ s1 << 9;
  29. return result;
  30. }
  31. static Uint64 rngState[2] = {1, 2};
  32. Uint32 getRandomUint32(void) {
  33. return (Uint32)next(rngState);
  34. }
  35. /* ================= Test Case Helper Functions ================== */
  36. /*
  37. * Resets PRNG state to initialize tests using PRNG
  38. */
  39. void SDLCALL blitSetUp(void **arg) {
  40. rngState[0] = 1;
  41. rngState[1] = 2;
  42. }
  43. /*
  44. * Fill buffer with stream of PRNG pixel data given size
  45. */
  46. static Uint32 *fillNextRandomBuffer(Uint32 *buf, const int width, const int height) {
  47. int i;
  48. for (i = 0; i < width * height; i++) {
  49. buf[i] = getRandomUint32();
  50. }
  51. return buf;
  52. }
  53. /*
  54. * Generates a stream of PRNG pixel data given length
  55. */
  56. static Uint32 *getNextRandomBuffer(const int width, const int height) {
  57. Uint32* buf = SDL_malloc(sizeof(Uint32) * width * height);
  58. fillNextRandomBuffer(buf, width, height);
  59. return buf;
  60. }
  61. /*
  62. * Generates a 800 x 600 surface of PRNG pixel data
  63. */
  64. SDL_Surface* getRandomSVGASurface(Uint32 *pixels, SDL_PixelFormat format) {
  65. return SDL_CreateSurfaceFrom(800, 600, format, pixels, 800 * 4);
  66. }
  67. /*
  68. * Calculates the FNV-1a hash of input pixel data
  69. */
  70. Uint32 FNVHash(Uint32* buf, int length) {
  71. const Uint32 fnv_prime = 0x811C9DC5;
  72. Uint32 hash = 0;
  73. int i;
  74. for (i = 0; i < length; buf++, i++)
  75. {
  76. hash *= fnv_prime;
  77. hash ^= (*buf);
  78. }
  79. return hash;
  80. }
  81. /*
  82. * Wraps the FNV-1a hash for an input surface's pixels
  83. */
  84. Uint32 hashSurfacePixels(SDL_Surface * surface) {
  85. int buffer_size = surface->w * surface->h;
  86. if (buffer_size < 0) {
  87. return 0;
  88. }
  89. return FNVHash(surface->pixels, buffer_size);
  90. }
  91. /* ================= Test Case Implementation ================== */
  92. /**
  93. * Tests rendering a rainbow gradient background onto a blank surface, then rendering a sprite with complex geometry and
  94. * transparency on top of said surface, and comparing the result to known accurate renders with a hash.
  95. */
  96. static int SDLCALL blit_testExampleApplicationRender(void *arg) {
  97. const int width = 32;
  98. const int height = 32;
  99. const Uint32 correct_hash = 0xe345d7a7;
  100. SDL_Surface* dest_surface = SDL_CreateSurface(width, height, SDL_PIXELFORMAT_ARGB8888);
  101. SDL_Surface* rainbow_background = SDLTest_ImageBlendingBackground();
  102. SDL_Surface* gearbrain_sprite = SDLTest_ImageBlendingSprite();
  103. // Blit background into "screen"
  104. SDL_BlitSurface(rainbow_background, NULL, dest_surface, NULL);
  105. // Blit example game sprite onto "screen"
  106. SDL_BlitSurface(gearbrain_sprite, NULL, dest_surface, NULL);
  107. // Check result
  108. const Uint32 hash = hashSurfacePixels(dest_surface);
  109. SDLTest_AssertCheck(hash == correct_hash,
  110. "Should render identically, expected hash 0x%" SDL_PRIx32 ", got 0x%" SDL_PRIx32,
  111. correct_hash, hash);
  112. // Clean up
  113. SDL_DestroySurface(rainbow_background);
  114. SDL_DestroySurface(gearbrain_sprite);
  115. SDL_DestroySurface(dest_surface);
  116. return TEST_COMPLETED;
  117. }
  118. /**
  119. * Tests rendering PRNG noise onto a surface of PRNG noise, while also testing color shift operations between the
  120. * different source and destination pixel formats, without an alpha shuffle, at SVGA resolution. Compares to known
  121. * accurate renders with a hash.
  122. */
  123. static int SDLCALL blit_testRandomToRandomSVGA(void *arg) {
  124. const int width = 800;
  125. const int height = 600;
  126. const Uint32 correct_hash = 0x42140c5f;
  127. // Allocate random buffers
  128. Uint32 *dest_pixels = getNextRandomBuffer(width, height);
  129. Uint32 *src_pixels = getNextRandomBuffer(width, height);
  130. // Create surfaces of different pixel formats
  131. SDL_Surface* dest_surface = getRandomSVGASurface(dest_pixels, SDL_PIXELFORMAT_BGRA8888);
  132. SDL_Surface* src_surface = getRandomSVGASurface(src_pixels, SDL_PIXELFORMAT_RGBA8888);
  133. // Blit surfaces
  134. SDL_BlitSurface(src_surface, NULL, dest_surface, NULL);
  135. // Check result
  136. const Uint32 hash = hashSurfacePixels(dest_surface);
  137. SDLTest_AssertCheck(hash == correct_hash,
  138. "Should render identically, expected hash 0x%" SDL_PRIx32 ", got 0x%" SDL_PRIx32,
  139. correct_hash, hash);
  140. // Clean up
  141. SDL_DestroySurface(dest_surface);
  142. SDL_DestroySurface(src_surface);
  143. SDL_free(dest_pixels);
  144. SDL_free(src_pixels);
  145. return TEST_COMPLETED;
  146. }
  147. /**
  148. * Tests rendering small chunks of 15 by 15px PRNG noise onto an initially blank SVGA surface, while also testing color
  149. * shift operations between the different source and destination pixel formats, including an alpha shuffle. Compares to
  150. * known accurate renders with a hash.
  151. */
  152. static int SDLCALL blit_testRandomToRandomSVGAMultipleIterations(void *arg) {
  153. const int width = 800;
  154. const int height = 600;
  155. const int blit_width = 15;
  156. const int blit_height = 15;
  157. int i;
  158. const Uint32 correct_hash = 0x5d26be78;
  159. Uint32 *buf = SDL_malloc(blit_width * blit_height * sizeof(Uint32));
  160. // Create blank source surface
  161. SDL_Surface *sourceSurface = SDL_CreateSurface(blit_width, blit_height, SDL_PIXELFORMAT_RGBA8888);
  162. // Create blank destination surface
  163. SDL_Surface* dest_surface = SDL_CreateSurface(width, height, SDL_PIXELFORMAT_ABGR8888);
  164. // Perform 250k random blits into random areas of the blank surface
  165. for (i = 0; i < 250000; i++) {
  166. fillNextRandomBuffer(buf, blit_width, blit_height);
  167. SDL_LockSurface(sourceSurface);
  168. SDL_memcpy(sourceSurface->pixels, buf, blit_width * blit_height * sizeof(Uint32));
  169. SDL_UnlockSurface(sourceSurface);
  170. SDL_Rect dest_rect;
  171. int location = (int)getRandomUint32();
  172. dest_rect.x = location % (width - 15 - 1);
  173. dest_rect.y = location % (height - 15 - 1);
  174. SDL_BlitSurface(sourceSurface, NULL, dest_surface, &dest_rect);
  175. }
  176. // Check result
  177. const Uint32 hash = hashSurfacePixels(dest_surface);
  178. // Clean up
  179. SDL_DestroySurface(dest_surface);
  180. SDLTest_AssertCheck(hash == correct_hash,
  181. "Should render identically, expected hash 0x%" SDL_PRIx32 ", got 0x%" SDL_PRIx32,
  182. correct_hash, hash);
  183. SDL_DestroySurface(sourceSurface);
  184. SDL_free(buf);
  185. return TEST_COMPLETED;
  186. }
  187. static const SDLTest_TestCaseReference blitTest1 = {
  188. blit_testExampleApplicationRender, "blit_testExampleApplicationRender",
  189. "Test example application render.", TEST_ENABLED
  190. };
  191. static const SDLTest_TestCaseReference blitTest2 = {
  192. blit_testRandomToRandomSVGA, "blit_testRandomToRandomSVGA",
  193. "Test SVGA noise render.", TEST_ENABLED
  194. };
  195. static const SDLTest_TestCaseReference blitTest3 = {
  196. blit_testRandomToRandomSVGAMultipleIterations, "blit_testRandomToRandomSVGAMultipleIterations",
  197. "Test SVGA noise render (250k iterations).", TEST_ENABLED
  198. };
  199. static const SDLTest_TestCaseReference *blitTests[] = {
  200. &blitTest1, &blitTest2, &blitTest3, NULL
  201. };
  202. SDLTest_TestSuiteReference blitTestSuite = {
  203. "Blending",
  204. blitSetUp,
  205. blitTests,
  206. NULL
  207. };