States.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************/
  5. // this cannot be done on OpenGL (on Windows it was tested, even with 'glFlush' significant stuttering occured, like previous frames were rendered sometimes)
  6. #define MT_FLIP (DX9 || DX11 || DX12) // if use Multi-Threaded flipping which performs 'D.flip' on the secondary thread, allowing the CPU 'Update' to run while flipping is still executing, this will improve performance only if the 'Update' is time consuming, however the performance benefit will not be full if the user tries to modify the GPU data (by using 'D._lock', which will have to wait until flip has finished)
  7. #define MT_SPIN 0 // spin is ~2x faster (0.000015s vs 0.000030s), however may cause slow downs if other threads catch sync lock before 'DisplayFlipThread' does
  8. /******************************************************************************/
  9. static Bool DisplayFlipOk=true;
  10. #if MT_FLIP
  11. #if MT_SPIN
  12. static Bool DisplayFlipLocked;
  13. #else
  14. static SyncEvent DisplayFlipLocked;
  15. #endif
  16. static SyncEvent DisplayFlipDo;
  17. static Thread DisplayFlipThread;
  18. static Bool DisplayFlipFunc(Thread &thread)
  19. {
  20. for(; DisplayFlipDo.wait() && !DisplayFlipThread.wantStop(); )
  21. {
  22. SyncLocker locker(D._lock);
  23. #if MT_SPIN
  24. DisplayFlipLocked=true;
  25. #else
  26. DisplayFlipLocked.on();
  27. #endif
  28. #if GL
  29. //ThreadMayUseGPUData(); glFlush(); didn't help
  30. //glFinish(); didn't help
  31. #endif
  32. DisplayFlipOk=D.flip();
  33. #if GL
  34. //glFlush(); didn't help
  35. //glFinish(); didn't help
  36. #endif
  37. }
  38. return false;
  39. }
  40. #endif
  41. /******************************************************************************/
  42. State StateExit(null, null);
  43. /******************************************************************************/
  44. State StateMain(Update, Draw),
  45. *StateActive,
  46. *StateNext=&StateMain;
  47. /******************************************************************************/
  48. void State::set()
  49. {
  50. StateNext=this;
  51. }
  52. void State::set(Flt fade_time, Bool fade_previous_frame)
  53. {
  54. if(StateNext!=this)
  55. {
  56. set();
  57. D.setFade(fade_time, fade_previous_frame);
  58. }
  59. }
  60. /******************************************************************************/
  61. State::State(Bool (*update)(), void (*draw)(), Bool (*init)(), void (*shut)())
  62. {
  63. T.update=update;
  64. T.draw =draw ;
  65. T.init =init ;
  66. T.shut =shut ;
  67. }
  68. /******************************************************************************/
  69. // MAIN
  70. /******************************************************************************/
  71. void InitState()
  72. {
  73. #if MT_FLIP
  74. DisplayFlipThread.create(DisplayFlipFunc, null, 3, false, "EE.Display.flip");
  75. #endif
  76. }
  77. void ShutState()
  78. {
  79. if(StateActive){StateActive->shutDo(); StateActive=null;}
  80. #if MT_FLIP
  81. DisplayFlipThread.stop(); DisplayFlipDo.on();
  82. DisplayFlipThread.del ();
  83. #endif
  84. }
  85. Bool UpdateState()
  86. {
  87. // change states
  88. if(StateNext!=StateActive)
  89. {
  90. if( StateActive) StateActive->shutDo(); StateActive=StateNext;
  91. if(!StateActive || !StateActive->initDo())return false;
  92. Time._st=0;
  93. Time.skipUpdate();
  94. D .resetEyeAdaptation();
  95. }
  96. // update state & draw
  97. if(StateActive && StateActive->update)
  98. {
  99. // update caches (process in order from parents to base elements)
  100. DelayRemoveUpdate();
  101. Environments.update();
  102. Objects .update();
  103. Meshes .update();
  104. PhysBodies .update();
  105. WaterMtrls .update();
  106. Materials .update();
  107. GuiSkins .update();
  108. Panels .update();
  109. PanelImages .update();
  110. TextStyles .update();
  111. Fonts .update();
  112. ImageAtlases.update();
  113. Images .update();
  114. Physics.step(); // try step, since we're after 'DrawState' any stepping could already be called, so possible lack of synchronization is inevitable
  115. Dbl t=Time.curTime() ; Bool update=StateActive->update(); UpdateSound(); UpdateThreads(); // enable sound update event immediately after state update has finished so latest sounds can be played and changes can be applied
  116. Time._state_update=Time.curTime()-t; return update;
  117. }
  118. return false;
  119. }
  120. Bool DrawState()
  121. {
  122. if(App.minimized() || (D.full() && !App.active()) || !D.canDraw())return true;
  123. if(StateActive && StateActive->draw)
  124. {
  125. // draw
  126. Dbl start_time, flip_time;
  127. {
  128. SyncLockerEx locker(D._lock);
  129. if(Renderer._t_measure)D.finish(); start_time=Time.curTime();
  130. Renderer._cur_main ->discard();
  131. Renderer._cur_main_ds->discard();
  132. D._view_main.setViewport(); // user may have called 'D.viewRect' during 'Update', in which setting the viewport can be ignored, so force it always here
  133. StateActive->draw();
  134. Physics.step(); // step after all drawing completed (in case it used current state of physics)
  135. D .fadeDraw();
  136. Gui.dragDraw();
  137. Ms . draw();
  138. VR . draw();
  139. Renderer._cur_main_ds->discard();
  140. if(VR.active())
  141. {
  142. const Bool ds=false; // no need for depth buffer because we will only copy VR results
  143. Renderer._gui =&Renderer._main ; Renderer._cur_main =Renderer._gui .rc();
  144. Renderer._gui_ds=&Renderer._main_ds; Renderer._cur_main_ds=Renderer._gui_ds.rc();
  145. Renderer.set(Renderer._cur_main, ds ? Renderer._cur_main_ds : null, false);
  146. Renderer._cur_main ->discard();
  147. if(ds)Renderer._cur_main_ds->discard();
  148. D._allow_stereo=false; D.aspectRatioEx(true, true); Frustum.set(); // !! call in this order !!
  149. //D.viewRect(null); // reset viewport, not needed since we've reset this already above in 'Renderer.set'
  150. VR.drawMain();
  151. if(ds)Renderer._cur_main_ds->discard();
  152. Renderer.setMain(); // restore the main RT (that includes advancing to the next VR texture)
  153. D._allow_stereo=true; D.aspectRatioEx(true, true); Frustum.set(); // !! call in this order !!
  154. }
  155. // flip
  156. if(Renderer._t_measure){D.finish(); flip_time=Time.curTime();}
  157. #if MT_FLIP
  158. if(DisplayFlipOk) // flip only if there was no error before
  159. if(DisplayFlipThread.active()
  160. #if WINDOWS_OLD && DX11
  161. && SwapChainDesc.Windowed // on DX10+ we can't do this when in full screen (only in windowed), because Alt+Tab will freeze the app, http://msdn.microsoft.com/en-us/library/windows/desktop/bb205075(v=vs.85).aspx#Multithread_Considerations
  162. #endif
  163. )
  164. {
  165. #if GL
  166. glFlush();
  167. #endif
  168. locker.off(); // release lock
  169. DisplayFlipDo.on(); // enable flip
  170. // wait for flip to enter lock
  171. #if MT_SPIN
  172. for(; !DisplayFlipLocked; )_mm_pause(); DisplayFlipLocked=false;
  173. #else
  174. DisplayFlipLocked.wait();
  175. #endif
  176. }else
  177. #endif
  178. {
  179. DisplayFlipOk=D.flip();
  180. if(Renderer._t_measure)D.finish();
  181. }
  182. if(!DisplayFlipOk)
  183. {
  184. DisplayFlipOk=true;
  185. #if DX9
  186. D.Reset();
  187. #endif
  188. }
  189. }
  190. Dbl cur_time=Time.curTime();
  191. Time._state_draw=cur_time-start_time; if(Renderer._t_measure){Renderer._t_measures[1]++; Renderer._t_gpu_wait[1]+=cur_time-flip_time;}
  192. Physics.step(); // flipping could take some time, so try stepping again
  193. return true;
  194. }
  195. return false;
  196. }
  197. /******************************************************************************/
  198. }
  199. /******************************************************************************/