testautomation_blit.c 7.6 KB

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