Image RT.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************/
  5. enum IMAGE_TYPE_CREATE_RESULT : Byte
  6. {
  7. UNKNOWN,
  8. FAILED ,
  9. SUCCESS,
  10. };
  11. static IMAGE_TYPE_CREATE_RESULT ImageTypeCreateResult[2][IMAGE_ALL_TYPES]; // [MultiSample][IMAGE_TYPE]
  12. struct ImageRTType
  13. {
  14. IMAGE_TYPE types[6]; // 6 is max IMAGE_TYPE elms per ImageRTType
  15. };
  16. static const ImageRTType ImageRTTypes[]=
  17. {
  18. {IMAGE_DEFAULT }, // 0 IMAGERT_RGBA
  19. {IMAGE_R10G10B10A2 , IMAGE_DEFAULT }, // 1 IMAGERT_RGB
  20. {IMAGE_R10G10B10A2 , IMAGE_F16_3, IMAGE_F16_4, IMAGE_DEFAULT }, // 2 IMAGERT_RGB_P
  21. {IMAGE_F16_4 , IMAGE_DEFAULT }, // 3 IMAGERT_RGBA_H
  22. {IMAGE_F16_3 , IMAGE_F16_4, IMAGE_R10G10B10A2, IMAGE_DEFAULT }, // 4 IMAGERT_RGB_H
  23. {IMAGE_F32_4 , IMAGE_F16_4, IMAGE_DEFAULT }, // 5 IMAGERT_RGBA_F
  24. {IMAGE_F32_3 , IMAGE_F32_4, IMAGE_F16_3, IMAGE_F16_4, IMAGE_R10G10B10A2, IMAGE_DEFAULT}, // 6 IMAGERT_RGB_F
  25. {IMAGE_R8G8B8A8_SIGN, IMAGE_F16_4 }, // 7 IMAGERT_RGBA_S
  26. {IMAGE_F32 , IMAGE_F16 }, // 8 IMAGERT_F32
  27. {IMAGE_F16 , IMAGE_F32 }, // 9 IMAGERT_F16
  28. {
  29. #if DX9
  30. IMAGE_A8, IMAGE_L8A8,
  31. #else
  32. IMAGE_R8, IMAGE_R8G8,
  33. #endif
  34. IMAGE_DEFAULT}, // 10 IMAGERT_ONE
  35. {
  36. #if !DX9
  37. IMAGE_R8_SIGN, IMAGE_R8G8_SIGN,
  38. #endif
  39. IMAGE_F16,
  40. #if !DX9
  41. IMAGE_R8G8B8A8_SIGN,
  42. #endif
  43. IMAGE_F32}, // 11 IMAGERT_ONE_S
  44. {
  45. #if !DX9
  46. IMAGE_R8G8,
  47. #endif
  48. IMAGE_DEFAULT}, // 12 IMAGERT_TWO
  49. {
  50. #if !DX9
  51. IMAGE_R8G8_SIGN, IMAGE_R8G8B8A8_SIGN,
  52. #endif
  53. IMAGE_F16_2}, // 13 IMAGERT_TWO_S
  54. {
  55. #if DX9
  56. IMAGE_INTZ, /*IMAGE_RAWZ, */IMAGE_DF24, // read why IMAGE_RAWZ is disabled in 'RendererClass::rtCreate()'
  57. #endif
  58. IMAGE_D24S8, IMAGE_D24X8, IMAGE_D32, IMAGE_D16}, // 14 IMAGERT_DS
  59. }; ASSERT(IMAGERT_RGBA==0 && IMAGERT_RGB==1 && IMAGERT_RGB_P==2 && IMAGERT_RGBA_H==3 && IMAGERT_RGB_H==4 && IMAGERT_RGBA_F==5 && IMAGERT_RGB_F==6 && IMAGERT_RGBA_S==7 && IMAGERT_F32==8 && IMAGERT_F16==9 && IMAGERT_ONE==10 && IMAGERT_ONE_S==11 && IMAGERT_TWO==12 && IMAGERT_TWO_S==13 && IMAGERT_DS==14 && IMAGERT_NUM==15);
  60. static ImageRTType ImageRTTypesOK[2][Elms(ImageRTTypes)]; // [MultiSample][IMAGERT_NUM], this keeps info about result of creating different IMAGE_TYPE for 1-sample and multi-sample, this is because some formats may fail to create multi-sampled but succeed with 1-sample (for simplication this assumes that there will be only one type of multi-sample, like only 4x, but not 4x and 8x)
  61. static CChar8 *ImageRTName[]=
  62. {
  63. "RGBA" , // 0
  64. "RGB" , // 1
  65. "RGB_P" , // 2
  66. "RGBA_H", // 3
  67. "RGB_H" , // 4
  68. "RGBA_F", // 5
  69. "RGB_F" , // 6
  70. "RGBA_S", // 7
  71. "F32" , // 8
  72. "F16" , // 9
  73. "ONE" , // 10
  74. "ONE_S" , // 11
  75. "TWO" , // 12
  76. "TWO_S" , // 13
  77. "DS" , // 14
  78. }; ASSERT(IMAGERT_RGBA==0 && IMAGERT_RGB==1 && IMAGERT_RGB_P==2 && IMAGERT_RGBA_H==3 && IMAGERT_RGB_H==4 && IMAGERT_RGBA_F==5 && IMAGERT_RGB_F==6 && IMAGERT_RGBA_S==7 && IMAGERT_F32==8 && IMAGERT_F16==9 && IMAGERT_ONE==10 && IMAGERT_ONE_S==11 && IMAGERT_TWO==12 && IMAGERT_TWO_S==13 && IMAGERT_DS==14 && IMAGERT_NUM==15);
  79. /******************************************************************************/
  80. static const IMAGERT_TYPE GetImageRTTypeLookup[IMAGE_PRECISION_NUM][2]= // [precision][alpha]
  81. {
  82. // no alpha , alpha
  83. {IMAGERT_RGB , IMAGERT_RGBA }, // 0 IMAGE_PRECISION_8
  84. {IMAGERT_RGB_P, IMAGERT_RGBA_P}, // 1 IMAGE_PRECISION_10
  85. {IMAGERT_RGB_H, IMAGERT_RGBA_H}, // 2 IMAGE_PRECISION_16
  86. {IMAGERT_RGB_F, IMAGERT_RGBA_F}, // 3 IMAGE_PRECISION_24
  87. {IMAGERT_RGB_F, IMAGERT_RGBA_F}, // 4 IMAGE_PRECISION_32
  88. {IMAGERT_RGB_F, IMAGERT_RGBA_F}, // 5 IMAGE_PRECISION_64
  89. }; ASSERT(IMAGE_PRECISION_8==0 && IMAGE_PRECISION_10==1 && IMAGE_PRECISION_16==2 && IMAGE_PRECISION_24==3 && IMAGE_PRECISION_32==4 && IMAGE_PRECISION_64==5 && IMAGE_PRECISION_NUM==6);
  90. IMAGERT_TYPE GetImageRTType( Bool alpha, IMAGE_PRECISION precision) {return GetImageRTTypeLookup[precision][alpha];}
  91. IMAGERT_TYPE GetImageRTType(IMAGE_TYPE type, Bool allow_alpha, IMAGE_PRECISION max_precision)
  92. {
  93. if(type==IMAGE_R10G10B10A2)return IMAGERT_RGB; // because the implementation operates on Bool alpha (yes/no) and not how many alpha bits we want, then as result we may actually increase precision when operating on 'IMAGE_R10G10B10A2' with 'allow_alpha'=true, so treat this as a special case and always return IMAGERT_RGB
  94. C ImageTypeInfo &ti=ImageTI[type]; return GetImageRTType(ti.a && allow_alpha, Min(ti.precision, max_precision));
  95. }
  96. IMAGERT_TYPE GetImageRTType(IMAGE_TYPE type, Bool allow_alpha)
  97. {
  98. if(type==IMAGE_R10G10B10A2)return IMAGERT_RGB; // because the implementation operates on Bool alpha (yes/no) and not how many alpha bits we want, then as result we may actually increase precision when operating on 'IMAGE_R10G10B10A2' with 'allow_alpha'=true, so treat this as a special case and always return IMAGERT_RGB
  99. C ImageTypeInfo &ti=ImageTI[type]; return GetImageRTType(ti.a && allow_alpha, ti.precision);
  100. }
  101. IMAGERT_TYPE GetImageRTType(IMAGE_TYPE type)
  102. {
  103. if(type==IMAGE_R10G10B10A2)return IMAGERT_RGB; // because the implementation operates on Bool alpha (yes/no) and not how many alpha bits we want, then as result we may actually increase precision when operating on 'IMAGE_R10G10B10A2', so treat this as a special case and always return IMAGERT_RGB
  104. C ImageTypeInfo &ti=ImageTI[type]; return GetImageRTType(ti.a>0, ti.precision);
  105. }
  106. /******************************************************************************/
  107. void ResetImageTypeCreateResult()
  108. {
  109. Zero(ImageTypeCreateResult); ASSERT(UNKNOWN==0); // assume that all are UNKNOWN (zero)
  110. CopyFast(ImageRTTypesOK[0], ImageRTTypes);
  111. CopyFast(ImageRTTypesOK[1], ImageRTTypes);
  112. }
  113. static Int CompareDesc(C ImageRC &image, C ImageRTDesc &desc)
  114. {
  115. if(Int c=Compare(image.w (), desc.size.x ))return c;
  116. if(Int c=Compare(image.h (), desc.size.y ))return c;
  117. if(Int c=Compare(image.type (), desc._type ))return c;
  118. if(Int c=Compare(image.samples(), desc.samples))return c;
  119. return 0;
  120. }
  121. static inline Bool ImageRTCreate(ImageRC &image, C ImageRTDesc &desc)
  122. {
  123. Bool ok;
  124. if(ImageTI[desc._type].d) // if this is a depth buffer
  125. {
  126. ok=image.createTryEx(desc.size.x, desc.size.y, 1, desc._type, IMAGE_DS_RT, 1, desc.samples); // try first as a render target
  127. #if DX9 || GL // for DX10+ IMAGE_DS_RT is the same as IMAGE_DS so don't bother checking it again
  128. if(!ok)ok=image.createTryEx(desc.size.x, desc.size.y, 1, desc._type, IMAGE_DS , 1, desc.samples);
  129. #endif
  130. }else
  131. {
  132. ok=image.createTryEx(desc.size.x, desc.size.y, 1, desc._type, IMAGE_RT, 1, desc.samples);
  133. }
  134. if(ok)Time.skipUpdate();
  135. return ok;
  136. }
  137. static inline void Set(ImageRTPtr &p, ImageRC &rt) // this is called only when "_ptr_num==0"
  138. {
  139. rt._ptr_num++; p._data=&rt; rt.discard();
  140. }
  141. ImageRTPtr& ImageRTPtr::clear()
  142. {
  143. if(_data)
  144. {
  145. DEBUG_ASSERT(_data->_ptr_num, "ImageRC._ptr_num should be >0");
  146. _data->_ptr_num--;
  147. if(!_data->_ptr_num)_data->discard();
  148. _data=null;
  149. }
  150. return T;
  151. }
  152. ImageRTPtr& ImageRTPtr::operator=(C ImageRTPtr &p)
  153. {
  154. if(T!=p)
  155. {
  156. clear();
  157. if(T._data=p._data){T._data->_ptr_num++; T._last_index=p._last_index;} // assign to new
  158. }
  159. return T;
  160. }
  161. ImageRTPtr& ImageRTPtr::operator=(ImageRC *p)
  162. {
  163. if(T!=p)
  164. {
  165. clear();
  166. if(T._data=p)T._data->_ptr_num++; // assign to new
  167. }
  168. return T;
  169. }
  170. ImageRTPtr::ImageRTPtr(C ImageRTPtr &p)
  171. {
  172. if(T._data=p._data){T._data->_ptr_num++; T._last_index=p._last_index;}else T._last_index=-1;
  173. }
  174. ImageRTPtr::ImageRTPtr(ImageRC *p)
  175. {
  176. if(T._data=p)T._data->_ptr_num++;else T._last_index=-1;
  177. }
  178. /******************************************************************************/
  179. Bool ImageRTPtr::find(C ImageRTDesc &desc)
  180. {
  181. clear(); // clear first so we can find the same Image if possible
  182. Bool multi_sample =(desc.samples>1);
  183. IMAGE_TYPE_CREATE_RESULT (&itcr)[IMAGE_ALL_TYPES]=ImageTypeCreateResult[multi_sample];
  184. ImageRTType &types =ImageRTTypesOK [multi_sample][desc.rt_type];
  185. again:
  186. ConstCast(desc._type)=types.types[0];
  187. Bool found; if(InRange(_last_index, Renderer._rts) && !CompareDesc(Renderer._rts[_last_index], desc))found=true; // in range and matches ("!CompareDesc" -> match)
  188. else found=Renderer._rts.binarySearch(desc, _last_index, CompareDesc);
  189. if(found)
  190. {
  191. // check '_last_index' first
  192. ImageRC &rt=Renderer._rts[_last_index];
  193. if(rt.available()){Set(T, rt); return true;}
  194. // check all neighbors with the same desc
  195. for(Int i=_last_index-1; i>=0 ; i--) {ImageRC &rt=Renderer._rts[i]; if(CompareDesc(rt, desc))break; if(rt.available()){Set(T, rt); T._last_index=i; return true;}}
  196. for(Int i=_last_index+1; InRange(i, Renderer._rts); i++) {ImageRC &rt=Renderer._rts[i]; if(CompareDesc(rt, desc))break; if(rt.available()){Set(T, rt); T._last_index=i; return true;}}
  197. }
  198. switch(itcr[desc._type])
  199. {
  200. case UNKNOWN:
  201. {
  202. ImageRC temp; Bool ok=ImageRTCreate(temp, desc); // try to create first as a standalone variable (not in 'Renderer._rts') in case it fails so we don't have to remove it
  203. itcr[desc._type]=(ok ? SUCCESS : FAILED);
  204. if(ok){ImageRC &rt=Renderer._rts.NewAt(_last_index); Swap(rt, temp); Set(T, rt); return true;}
  205. // fail
  206. if(desc._type!=IMAGE_NONE)
  207. {
  208. MoveFastN(&types.types[0], &types.types[1], ELMS(types.types)-1); // move all elements from index 1 and right, to the left by 1, to index 0..
  209. types.types[ELMS(types.types)-1]=IMAGE_NONE; // set last type as none
  210. if(types.types[0]!=IMAGE_NONE)goto again; // try the new type
  211. }
  212. }break;
  213. case SUCCESS:
  214. {
  215. ImageRC &rt=Renderer._rts.NewAt(_last_index); if(!ImageRTCreate(rt, desc))Exit(S+"Can't create Render Target "+desc.size.x+'x'+desc.size.y); // Exit because SUCCESS always assumes to succeed
  216. Set(T, rt); return true;
  217. }break;
  218. }
  219. return false;
  220. }
  221. /******************************************************************************/
  222. ImageRTPtr& ImageRTPtr::get(C ImageRTDesc &desc)
  223. {
  224. if(!find(desc))Exit(S+"Can't create Render Target "+desc.size.x+'x'+desc.size.y+' '+ImageRTName[desc.rt_type]+", samples:"+desc.samples);
  225. return T;
  226. }
  227. ImageRTPtr& ImageRTPtr::getDS(Int w, Int h, Byte samples, Bool reuse_main)
  228. {
  229. clear(); // clear first so we can find the same Image if possible
  230. if(reuse_main)
  231. {
  232. ImageRC &ds=Renderer._main_ds, *cur_ds=Renderer._cur_main_ds;
  233. #if GL
  234. // on OpenGL we can't reuse '_main_ds' because it has different flipping orientation as it is always paired with '_main' in the main FBO
  235. // <- here don't check for 'ds'
  236. if(cur_ds==&ds)cur_ds=null; // if 'cur_ds' is 'ds' then don't check it either
  237. #else
  238. if( /*ds .available() && */ ds .accessible() && ds .w()==w && ds .h()==h && ds .samples()==samples){T= &ds; return T;} // if ds is not used (actually don't check this because '_gui_ds' can be set to it at the start of each frame), accessible and compatible then we can use it
  239. #endif
  240. if(cur_ds && /*cur_ds->available() && */cur_ds->accessible() && cur_ds->w()==w && cur_ds->h()==h && cur_ds->samples()==samples){T=cur_ds; return T;} // if ds is not used (actually don't check this because '_gui_ds' can be set to it at the start of each frame), accessible and compatible then we can use it
  241. }
  242. get(ImageRTDesc(w, h, IMAGERT_DS, samples)); return T;
  243. }
  244. /******************************************************************************/
  245. Bool ImageRTPtr::find(Int w, Int h, IMAGERT_TYPE rt_type, Byte samples) {return find(ImageRTDesc(w, h, rt_type, samples));}
  246. ImageRTPtr& ImageRTPtr:: get(Int w, Int h, IMAGERT_TYPE rt_type, Byte samples) {return get(ImageRTDesc(w, h, rt_type, samples));}
  247. /******************************************************************************/
  248. }
  249. /******************************************************************************/