MemoryTestFixture.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #include "MemoryTestFixture.h"
  2. #include "SpineEventMonitor.h"
  3. #include "spine/spine.h"
  4. #include "KMemory.h" // last include
  5. #define SPINEBOY_JSON "testdata/spineboy/spineboy.json"
  6. #define SPINEBOY_ATLAS "testdata/spineboy/spineboy.atlas"
  7. #define MAX_RUN_TIME 6000 // equal to about 100 seconds of execution
  8. MemoryTestFixture::~MemoryTestFixture()
  9. {
  10. finalize();
  11. }
  12. void MemoryTestFixture::initialize()
  13. {
  14. // on a Per- Fixture Basis, before Test execution
  15. }
  16. void MemoryTestFixture::finalize()
  17. {
  18. // on a Per- Fixture Basis, after all tests pass/fail
  19. }
  20. void MemoryTestFixture::setUp()
  21. {
  22. // Setup on Per-Test Basis
  23. }
  24. void MemoryTestFixture::tearDown()
  25. {
  26. // Tear Down on Per-Test Basis
  27. }
  28. //////////////////////////////////////////////////////////////////////////
  29. // Helper methods
  30. static spSkeletonData* readSkeletonJsonData(const char* filename, spAtlas* atlas) {
  31. spSkeletonJson* json = spSkeletonJson_create(atlas);
  32. ASSERT(json != nullptr);
  33. spSkeletonData* skeletonData = spSkeletonJson_readSkeletonDataFile(json, filename);
  34. ASSERT(skeletonData != nullptr);
  35. spSkeletonJson_dispose(json);
  36. return skeletonData;
  37. }
  38. static void LoadSpineboyExample(spAtlas* &atlas, spSkeletonData* &skeletonData, spAnimationStateData* &stateData, spSkeleton* &skeleton, spAnimationState* &state)
  39. {
  40. ///////////////////////////////////////////////////////////////////////////
  41. // Global Animation Information
  42. atlas = spAtlas_createFromFile(SPINEBOY_ATLAS, 0);
  43. ASSERT(atlas != nullptr);
  44. skeletonData = readSkeletonJsonData(SPINEBOY_JSON, atlas);
  45. ASSERT(skeletonData != nullptr);
  46. stateData = spAnimationStateData_create(skeletonData);
  47. ASSERT(stateData != nullptr);
  48. stateData->defaultMix = 0.4f; // force mixing
  49. ///////////////////////////////////////////////////////////////////////////
  50. // Animation Instance
  51. skeleton = spSkeleton_create(skeletonData);
  52. ASSERT(skeleton != nullptr);
  53. state = spAnimationState_create(stateData);
  54. ASSERT(state != nullptr);
  55. }
  56. static void DisposeAll(spSkeleton* skeleton, spAnimationState* state, spAnimationStateData* stateData, spSkeletonData* skeletonData, spAtlas* atlas)
  57. {
  58. ///////////////////////////////////////////////////////////////////////////
  59. // Dispose Instance
  60. spSkeleton_dispose(skeleton);
  61. spAnimationState_dispose(state);
  62. ///////////////////////////////////////////////////////////////////////////
  63. // Dispose Global
  64. spAnimationStateData_dispose(stateData);
  65. spSkeletonData_dispose(skeletonData);
  66. spAtlas_dispose(atlas);
  67. }
  68. //////////////////////////////////////////////////////////////////////////
  69. // Reproduce Memory leak as described in Issue #776
  70. // https://github.com/EsotericSoftware/spine-runtimes/issues/776
  71. void MemoryTestFixture::reproduceIssue_776()
  72. {
  73. spAtlas* atlas = nullptr;
  74. spSkeletonData* skeletonData = nullptr;
  75. spAnimationStateData* stateData = nullptr;
  76. spSkeleton* skeleton = nullptr;
  77. spAnimationState* state = nullptr;
  78. //////////////////////////////////////////////////////////////////////////
  79. // Initialize Animations
  80. LoadSpineboyExample(atlas, skeletonData, stateData, skeleton, state);
  81. ///////////////////////////////////////////////////////////////////////////
  82. // Run animation
  83. spSkeleton_setToSetupPose(skeleton);
  84. InterruptMonitor eventMonitor(state);
  85. //eventMonitor.SetDebugLogging(true);
  86. // Interrupt the animation on this specific sequence of spEventType(s)
  87. eventMonitor
  88. .AddInterruptEvent(SP_ANIMATION_INTERRUPT, "jump")
  89. .AddInterruptEvent(SP_ANIMATION_START);
  90. spAnimationState_setAnimationByName(state, 0, "walk", true);
  91. spAnimationState_addAnimationByName(state, 0, "jump", false, 0.0f);
  92. spAnimationState_addAnimationByName(state, 0, "run", true, 0.0f);
  93. spAnimationState_addAnimationByName(state, 0, "jump", false, 3.0f);
  94. spAnimationState_addAnimationByName(state, 0, "walk", true, 0.0f);
  95. spAnimationState_addAnimationByName(state, 0, "idle", false, 1.0f);
  96. for (int i = 0; i < MAX_RUN_TIME && eventMonitor.isAnimationPlaying(); ++i) {
  97. const float timeSlice = 1.0f / 60.0f;
  98. spSkeleton_update(skeleton, timeSlice);
  99. spAnimationState_update(state, timeSlice);
  100. spAnimationState_apply(state, skeleton);
  101. }
  102. //////////////////////////////////////////////////////////////////////////
  103. // Cleanup Animations
  104. DisposeAll(skeleton, state, stateData, skeletonData, atlas);
  105. }
  106. void MemoryTestFixture::reproduceIssue_777()
  107. {
  108. spAtlas* atlas = nullptr;
  109. spSkeletonData* skeletonData = nullptr;
  110. spAnimationStateData* stateData = nullptr;
  111. spSkeleton* skeleton = nullptr;
  112. spAnimationState* state = nullptr;
  113. //////////////////////////////////////////////////////////////////////////
  114. // Initialize Animations
  115. LoadSpineboyExample(atlas, skeletonData, stateData, skeleton, state);
  116. ///////////////////////////////////////////////////////////////////////////
  117. // Run animation
  118. spSkeleton_setToSetupPose(skeleton);
  119. SpineEventMonitor eventMonitor(state);
  120. //eventMonitor.SetDebugLogging(true);
  121. // Set Animation and Play for 5 frames
  122. spAnimationState_setAnimationByName(state, 0, "walk", true);
  123. for (int i = 0; i < 5; ++i) {
  124. const float timeSlice = 1.0f / 60.0f;
  125. spSkeleton_update(skeleton, timeSlice);
  126. spAnimationState_update(state, timeSlice);
  127. spAnimationState_apply(state, skeleton);
  128. }
  129. // Change animation twice in a row
  130. spAnimationState_setAnimationByName(state, 0, "walk", false);
  131. spAnimationState_setAnimationByName(state, 0, "run", false);
  132. // run normal update
  133. for (int i = 0; i < 5; ++i) {
  134. const float timeSlice = 1.0f / 60.0f;
  135. spSkeleton_update(skeleton, timeSlice);
  136. spAnimationState_update(state, timeSlice);
  137. spAnimationState_apply(state, skeleton);
  138. }
  139. // Now we'd lose mixingFrom (the first "walk" entry we set above) and should leak
  140. spAnimationState_setAnimationByName(state, 0, "run", false);
  141. //////////////////////////////////////////////////////////////////////////
  142. // Cleanup Animations
  143. DisposeAll(skeleton, state, stateData, skeletonData, atlas);
  144. }