Renderer Targets.cpp 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************
  5. RT : Width , Height , Type , Samples , Comments
  6. _main : D. resW(), D. resH(), IMAGERT_RGBA, 1 , COLOR RGB, Opacity
  7. _main_ds : D. resW(), D. resH(), IMAGERT_RGBA, 1 , this is the Main DepthStencil buffer to be used together with '_main' RT, on OpenGL (except iOS) it is provided by the system
  8. _ds : D.renderW(), D.renderW(), IMAGERT_DS , D.samples()
  9. _ds_1s : D.renderW(), D.renderW(), IMAGERT_DS , 1 , if '_ds' is Multi-Sampled then this is created as a standalone 1-sampled depth buffer, otherwise it's a duplicate of '_ds'
  10. _col : D.renderW(), D.renderH(), D.highPrecColRT() ? IMAGERT_RGBA_P : IMAGERT_RGBA, D.samples(), COLOR RGB, GLOW
  11. _nrm : D.renderW(), D.renderH(), D.signedNrmRT() ? .. : D.highPrecNrmRT() ? IMAGERT_RGBA_P : IMAGERT_RGBA, D.samples(), NRM XYZ, SPEC
  12. _vel : D.renderW(), D.renderH(), D.signedVelRT() ? IMAGERT_RGB_S : IMAGERT_RGB , D.samples(), VEL XYZ
  13. _pos : D.renderW(), D.renderH(), IMAGERT_F32 , 1 , Linearized depth
  14. _lum : D.renderW(), D.renderH(), D.highPrecLumRT() ? IMAGERT_RGBA_H : IMAGERT_RGBA, D.samples(), LIGHT RGB, LIGHT SPEC
  15. _lum_1s : D.renderW(), D.renderH(), D.highPrecLumRT() ? IMAGERT_RGBA_H : IMAGERT_RGBA, 1 , LIGHT RGB, LIGHT SPEC. if '_lum' is Multi-Sampled then this is created as a standalone 1-sampled depth buffer, otherwise it's a duplicate of '_lum'
  16. _water_col: D.renderW(), D.renderH(), IMAGERT_RGBA, 1 , COLOR RGB, UNUSED
  17. _water_nrm: D.renderW(), D.renderH(), D.signedNrmRT() ? IMAGERT_RGBA_S : IMAGERT_RGBA , 1 , NRM XYZ, SPEC. High precision is not needed because we just use better UnpackNormal in the shader
  18. _water_ds : D.renderW(), D.renderH(), IMAGERT_DS , 1 , Water Depth
  19. _water_lum: D.renderW(), D.renderH(), IMAGERT_RGBA, 1 , LIGHT RGB, LIGHT SPEC
  20. '_gui' is set to '_main', unless stereoscopic rendering is enabled then it's set to VR RT
  21. If '_ds' is multi-sampled on DX10+ then:
  22. In Deferred Renderer:
  23. -'_ds_1s' is set to down-sampled copy of '_ds'
  24. -both '_ds' and '_ds_1s' have STENCIL_REF_MSAA set
  25. In Non-Deferred Renderer:
  26. -if 'slowCombine' then '_ds_1s' has STENCIL_REF_MSAA set
  27. -if "Fog.draw || Sky.isActual" then '_ds' has STENCIL_REF_MSAA set
  28. In OpenGL (except iOS):
  29. '_main' and '_main_ds' don't have _rb and _txtr set, because they're provided by the system and not created by the engine.
  30. This means that when setting '_main' it's always paired with '_main_ds' depth buffer, and '_main_ds' can't be read as a depth texture.
  31. In OpenGL:
  32. '_main' and '_main_ds' are flipped vertically when compared to other render targets.
  33. /******************************************************************************/
  34. void RendererClass::createShadowMap()
  35. {
  36. SyncLocker locker(D._lock);
  37. // shadow maps
  38. D._shd_map_size_actual=Max(0, Min(D.shadowMapSize()*3, D.maxTexSize())/3);
  39. Int shd_map_w=D.shadowMapSizeActual()*2,
  40. shd_map_h=D.shadowMapSizeActual()*3;
  41. #if DX9
  42. _shd_map_null.del();
  43. if(!_shd_map.createTryEx(shd_map_w, shd_map_h, 1, IMAGE_D32 , IMAGE_SHADOW_MAP, 1)) // on GeForce 650m this is not available, but try anyway
  44. if(!_shd_map.createTryEx(shd_map_w, shd_map_h, 1, IMAGE_D24X8, IMAGE_SHADOW_MAP, 1)) // we don't need stencil so avoid it in case it causes performance penalty
  45. _shd_map.createTryEx(shd_map_w, shd_map_h, 1, IMAGE_D24S8, IMAGE_SHADOW_MAP, 1);
  46. if( _shd_map.is())
  47. if(!_shd_map_null.createTryEx(_shd_map.w(), _shd_map.h(), 1, IMAGE_NULL, IMAGE_RT, 1, 1, IMAGE_B8G8R8A8))_shd_map.del();
  48. #else
  49. if(!_shd_map.createTryEx(shd_map_w, shd_map_h, 1, IMAGE_D32 , IMAGE_SHADOW_MAP, 1)) // D32 shadow maps have no performance penalty (tested on GeForce 650m) so use them if possible
  50. if(!_shd_map.createTryEx(shd_map_w, shd_map_h, 1, IMAGE_D24X8, IMAGE_SHADOW_MAP, 1)) // we don't need stencil so avoid it in case it causes performance penalty
  51. if(!_shd_map.createTryEx(shd_map_w, shd_map_h, 1, IMAGE_D24S8, IMAGE_SHADOW_MAP, 1))
  52. if(!_shd_map.createTryEx(shd_map_w, shd_map_h, 1, IMAGE_D16 , IMAGE_SHADOW_MAP, 1)){}
  53. #endif
  54. if(!_shd_map.is())D._shd_map_size_actual=0;
  55. // cloud shadow maps
  56. #if DX9
  57. if(!_cld_map.createTryEx(D.cloudsMapSize()*2, D.cloudsMapSize()*3, 1, IMAGE_A8 , IMAGE_RT, 1, 1, IMAGE_L8A8 ))
  58. _cld_map.createTryEx(D.cloudsMapSize()*2, D.cloudsMapSize()*3, 1, IMAGE_B8G8R8A8, IMAGE_RT, 1, 1, IMAGE_R8G8B8A8);
  59. #else
  60. if(!_cld_map.createTryEx(D.cloudsMapSize()*2, D.cloudsMapSize()*3, 1, IMAGE_R8 , IMAGE_RT, 1, 1, IMAGE_R8G8))
  61. _cld_map.createTry (D.cloudsMapSize()*2, D.cloudsMapSize()*3, 1, IMAGE_R8G8B8A8, IMAGE_RT, 1);
  62. #endif
  63. Sh.connectRT();
  64. D.shadowJitterSet();
  65. }
  66. void RendererClass::rtClear()
  67. {
  68. _h0 .clear();
  69. _h1 .clear();
  70. _q0 .clear();
  71. _q1 .clear();
  72. _col .clear();
  73. _nrm .clear();
  74. _vel .clear();
  75. _lum .clear();
  76. _lum_1s .clear();
  77. _shd_1s .clear();
  78. _shd_ms .clear();
  79. _ds .clear();
  80. _ds_1s .clear();
  81. _water_col .clear();
  82. _water_nrm .clear();
  83. _water_ds .clear();
  84. _water_lum .clear();
  85. _vol .clear();
  86. _ao .clear();
  87. _mirror_rt .clear();
  88. _outline_rt .clear();
  89. _sky_coverage.clear();
  90. _final .clear();
  91. // don't clear '_back' and '_back_ds' here in case they are used
  92. }
  93. void RendererClass::rtClean()
  94. {
  95. SyncLocker locker(D._lock);
  96. rtClear();
  97. REPA(_rts)if(_rts[i].available())_rts.removeValid(i);
  98. }
  99. void RendererClass::rtDel()
  100. {
  101. SyncLocker locker(D._lock);
  102. #if GL
  103. if(FBO) // detach all render targets
  104. {
  105. D.fbo(FBO); // set custom frame buffer
  106. glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , 0, 0);
  107. glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1 , GL_TEXTURE_2D , 0, 0);
  108. glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2 , GL_TEXTURE_2D , 0, 0);
  109. glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3 , GL_TEXTURE_2D , 0, 0);
  110. glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT , GL_TEXTURE_2D , 0, 0);
  111. glFramebufferTexture2D (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D , 0, 0);
  112. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT , GL_RENDERBUFFER, 0 );
  113. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0 );
  114. #if !IOS
  115. //D.fbo(0); // set default frame buffer (iOS doesn't have it) !! Don't do this, because we clear all attachments and '_cur' to null, we assume that no RT's are set, however that's possible only in a custom FBO, so we need to keep it, so that the next 'set' RT change will be able to properly detect the change !!
  116. #endif
  117. }
  118. #endif
  119. rtClear();
  120. D.clearFade(); // _fade.clear(); this is already cleared in 'clearFade'
  121. _back .clear();
  122. _back_ds.clear();
  123. _gui =_cur_main =&_main;
  124. _gui_ds=_cur_main_ds=&_main_ds;
  125. unmapMain();
  126. #if DX9 || DX11 || IOS // only on these platforms we're creating custom '_main_ds', on other platforms the system creates it, so we're not deleting (to keep the info about IMAGE_TYPE and samples)
  127. _main_ds.del();
  128. #endif
  129. _cld_map .del();
  130. _shd_map .del();
  131. _shd_map_null.del();
  132. REPAO(_eye_adapt_scale).del();
  133. _rts.clear();
  134. REPAO(_cur )=null; _cur_ds =null;
  135. REPAO(_cur_id )=NULL; _cur_ds_id=NULL;
  136. REPAO(_cur_ds_ids)=NULL;
  137. }
  138. Bool RendererClass::rtCreate()
  139. {
  140. if(LogInit)LogN("RendererClass.rtCreate");
  141. SyncLocker locker(D._lock);
  142. rtDel();
  143. ResetImageTypeCreateResult();
  144. if(!D.canDraw())return true; // don't bother with render targets if the device can't draw (can happen when using 'APP_ALLOW_NO_GPU')
  145. if(!mapMain())return false;
  146. // depth
  147. #if DX9
  148. if(!_main_ds.createTryEx(_main.w(), _main.h(), 1, IMAGE_INTZ , IMAGE_DS_RT, 1, _main.samples()))
  149. //if(!_main_ds.createTryEx(_main.w(), _main.h(), 1, IMAGE_RAWZ , IMAGE_DS_RT, 1, _main.samples())) disable for now because all shader depth reads use standard depth format while RAWZ requires a special shader, enabling would require converting to IMAGE_F32 that mimics standard depth buffer, however that would destroy stencil and we would have to use 2 separate Images
  150. if(!_main_ds.createTryEx(_main.w(), _main.h(), 1, IMAGE_DF24 , IMAGE_DS_RT, 1, _main.samples()))
  151. if(!_main_ds.createTryEx(_main.w(), _main.h(), 1, IMAGE_D24S8, IMAGE_DS , 1, _main.samples()))
  152. if(!_main_ds.createTryEx(_main.w(), _main.h(), 1, IMAGE_D24X8, IMAGE_DS , 1, _main.samples()))return false;
  153. #elif DX11
  154. if(!_main_ds.createTryEx(_main.w(), _main.h(), 1, IMAGE_D24S8, IMAGE_DS_RT, 1, _main.samples()))return false;
  155. #elif IOS // on iOS we have access to '_main' so let's keep '_main_ds' the same
  156. if(!_main_ds.createTryEx(_main.w(), _main.h(), 1, IMAGE_D24S8, IMAGE_DS_RT, 1, _main.samples()))
  157. if(!_main_ds.createTryEx(_main.w(), _main.h(), 1, IMAGE_D32 , IMAGE_DS_RT, 1, _main.samples()))
  158. if(!_main_ds.createTryEx(_main.w(), _main.h(), 1, IMAGE_D24X8, IMAGE_DS_RT, 1, _main.samples()))
  159. if(!_main_ds.createTryEx(_main.w(), _main.h(), 1, IMAGE_D16 , IMAGE_DS_RT, 1, _main.samples()))
  160. if(!_main_ds.createTryEx(_main.w(), _main.h(), 1, IMAGE_D24S8, IMAGE_DS , 1, _main.samples()))
  161. if(!_main_ds.createTryEx(_main.w(), _main.h(), 1, IMAGE_D32 , IMAGE_DS , 1, _main.samples()))
  162. if(!_main_ds.createTryEx(_main.w(), _main.h(), 1, IMAGE_D24X8, IMAGE_DS , 1, _main.samples()))
  163. if(!_main_ds.createTryEx(_main.w(), _main.h(), 1, IMAGE_D16 , IMAGE_DS , 1, _main.samples()))return false;
  164. #else // other platforms have '_main_ds' linked with '_main' provided by the system
  165. _main_ds.forceInfo(_main.w(), _main.h(), 1, _main_ds.type() ? _main_ds.type() : IMAGE_D24S8, IMAGE_DS)._samples=_main.samples(); // if we know the type then use it, otherwise assume the default IMAGE_D24S8
  166. #endif
  167. createShadowMap();
  168. // eye adaptation
  169. _eye_adapt_scale_cur=0; if(!_eye_adapt_scale[0].createTryEx(1, 1, 1, IMAGE_F32, IMAGE_RT, 1, 1, IMAGE_F16)
  170. || !_eye_adapt_scale[1].createTryEx(1, 1, 1, IMAGE_F32, IMAGE_RT, 1, 1, IMAGE_F16))REPAO(_eye_adapt_scale).del();
  171. setMain();
  172. Sh.connectRT();
  173. return true;
  174. }
  175. /******************************************************************************/
  176. void RendererClass::update()
  177. {
  178. if(_t_measure)
  179. {
  180. Dbl t=Time.curTime();
  181. if( t>_t_last_measure+1)
  182. {
  183. Flt mul=1.0f/_t_measures[0];
  184. _t_reflection [0]=_t_reflection [1]*mul; _t_reflection [1]=0;
  185. _t_prepare [0]=_t_prepare [1]*mul; _t_prepare [1]=0;
  186. _t_solid [0]=_t_solid [1]*mul; _t_solid [1]=0;
  187. _t_overlay [0]=_t_overlay [1]*mul; _t_overlay [1]=0;
  188. _t_water [0]=_t_water [1]*mul; _t_water [1]=0;
  189. _t_light [0]=_t_light [1]*mul; _t_light [1]=0;
  190. _t_sky [0]=_t_sky [1]*mul; _t_sky [1]=0;
  191. _t_blend [0]=_t_blend [1]*mul; _t_blend [1]=0;
  192. _t_palette [0]=_t_palette [1]*mul; _t_palette [1]=0;
  193. _t_behind [0]=_t_behind [1]*mul; _t_behind [1]=0;
  194. _t_rays [0]=_t_rays [1]*mul; _t_rays [1]=0;
  195. _t_refract [0]=_t_refract [1]*mul; _t_refract [1]=0;
  196. _t_volumetric [0]=_t_volumetric [1]*mul; _t_volumetric [1]=0;
  197. _t_post_process[0]=_t_post_process[1]*mul; _t_post_process[1]=0;
  198. _t_gpu_wait [0]=_t_gpu_wait [1]/_t_measures[1]; _t_gpu_wait [1]=0; // '_t_gpu_wait' has it's own counter (_t_measures[1]) because it's called once per frame, while others can be called multiple times per frame
  199. _t_last_measure=t;
  200. _t_measures[0]=0;
  201. _t_measures[1]=0;
  202. }
  203. }
  204. }
  205. /******************************************************************************/
  206. void RendererClass::setMain() // !! requires 'D._lock' !! this is called after RT creation, and when VR GuiTexture is created/deleted/changed, and at the end of frame drawing for stereo mode (to advance to the next VR frame)
  207. {
  208. #if DX12
  209. map needs to be called for all images, cache the values, and call setMain in every frame
  210. #endif
  211. if(VR.active() && (_gui=VR.getNewGui()))
  212. {
  213. _gui_ds.getDS(_gui->w(), _gui->h());
  214. }else
  215. {
  216. _gui =&_main;
  217. _gui_ds=&_main_ds;
  218. }
  219. _cur_main =_gui .rc();
  220. _cur_main_ds=_gui_ds.rc();
  221. set(_cur_main, _cur_main_ds, false);
  222. }
  223. Bool RendererClass::mapMain()
  224. {
  225. return _main.map();
  226. }
  227. void RendererClass::unmapMain()
  228. {
  229. _main.unmap();
  230. _cur [0]=null;
  231. _cur_id[0]=NULL;
  232. }
  233. /******************************************************************************/
  234. Rect RendererClass::colClamp(C VecI2 &size)
  235. {
  236. Rect r((D.viewRect().min.x+D.w())*size.x/D.w2(), (D.h()-D.viewRect().max.y)*size.y/D.h2(),
  237. (D.viewRect().max.x+D.w())*size.x/D.w2(), (D.h()-D.viewRect().min.y)*size.y/D.h2());
  238. RectI ri=RoundGPU(r);
  239. r.min=(ri.min+0.5f)/size; // yes +0.5 is needed
  240. r.max=(ri.max-0.5f)/size; // yes -0.5 is needed
  241. return r;
  242. }
  243. Rect RendererClass::screenToPixel(C Rect &screen)
  244. {
  245. return Rect((screen.min.x+D.w())*Renderer.resW()/D.w2(), (D.h()-screen.max.y)*Renderer.resH()/D.h2(),
  246. (screen.max.x+D.w())*Renderer.resW()/D.w2(), (D.h()-screen.min.y)*Renderer.resH()/D.h2());
  247. }
  248. RectI RendererClass::screenToPixelI(C Rect &screen)
  249. {
  250. return RoundGPU(screenToPixel(screen));
  251. }
  252. Rect RendererClass::pixelToScreen(C RectI &pixel)
  253. {
  254. return Rect(pixel.min.x*D.w2()/Renderer.resW()-D.w(), D.h()-pixel.max.y*D.h2()/Renderer.resH(),
  255. pixel.max.x*D.w2()/Renderer.resW()-D.w(), D.h()-pixel.min.y*D.h2()/Renderer.resH());
  256. }
  257. Vec2 RendererClass::pixelToScreenSize(Flt pixel)
  258. {
  259. return Vec2(pixel*D.w2()/Renderer.resW(),
  260. pixel*D.h2()/Renderer.resH());
  261. }
  262. Vec2 RendererClass::screenToPixelSize(C Vec2 &screen)
  263. {
  264. return Vec2(screen.x*Renderer.resW()/D.w2(),
  265. screen.y*Renderer.resH()/D.h2());
  266. }
  267. /******************************************************************************/
  268. #if GL
  269. static void SwitchedFBO()
  270. {
  271. // update settings that depend on main FBO being active
  272. D.cullGL (); // adjust culling according to Y axis
  273. SetProjMatrix(); // flip Y 3D coords when Rendering To Texture
  274. }
  275. static inline Bool EqualRT(C Image *a, C Image *b)
  276. {
  277. UInt a_txtr, a_rb; if(a){a_txtr=a->_txtr; a_rb=a->_rb;}else a_txtr=a_rb=0;
  278. UInt b_txtr, b_rb; if(b){b_txtr=b->_txtr; b_rb=b->_rb;}else b_txtr=b_rb=0;
  279. return a_txtr==b_txtr && a_rb==b_rb;
  280. }
  281. static inline Bool EqualDS(C Image *a, C Image *b, UInt a_txtr)
  282. {
  283. UInt a_rb; if(a){ a_rb=a->_rb;}else a_rb=0;
  284. UInt b_txtr, b_rb; if(b){b_txtr=b->_txtr; b_rb=b->_rb;}else b_txtr=b_rb=0;
  285. return a_txtr==b_txtr && a_rb==b_rb;
  286. }
  287. static Bool EqualTxtr(C Image *a, C Image *b) {return (a ? a->_txtr : 0)==(b ? b->_txtr : 0);} // simpler version that checks texture ID's only, this can be used for #1+ RT's which never use RenderBuffers but only textures
  288. #endif
  289. #if DX9
  290. void RendererClass::setCube(Image &cube, Image *ds, DIR_ENUM dir)
  291. {
  292. if(cube._cube)
  293. {
  294. #if GL
  295. Bool was_main_fbo=D.mainFBO();
  296. #endif
  297. D3DCUBEMAP_FACES cf;
  298. switch(dir)
  299. {
  300. case DIR_LEFT : cf=D3DCUBEMAP_FACE_NEGATIVE_X; break;
  301. case DIR_RIGHT: cf=D3DCUBEMAP_FACE_POSITIVE_X; break;
  302. case DIR_DOWN : cf=D3DCUBEMAP_FACE_NEGATIVE_Y; break;
  303. case DIR_UP : cf=D3DCUBEMAP_FACE_POSITIVE_Y; break;
  304. case DIR_BACK : cf=D3DCUBEMAP_FACE_NEGATIVE_Z; break;
  305. default : cf=D3DCUBEMAP_FACE_POSITIVE_Z; break;
  306. }
  307. IDirect3DSurface9 *surf=null; cube._cube->GetCubeMapSurface(cf, 0, &surf);
  308. _cur [0]=&cube;
  309. _cur_id[0]= surf;
  310. D3D->SetRenderTarget(0, surf);
  311. RELEASE(surf);
  312. IDirect3DSurface9 *ids=(ds ? ds->_surf : null);
  313. if(_cur_ds_id!=ids){_cur_ds=ds; D3D->SetDepthStencilSurface(_cur_ds_id=ids);}
  314. _res.set(cube.w(), cube.h());
  315. if(Sh.h_RTSizeI)Sh.h_RTSizeI->set(Vec2(_res));
  316. #if DX9
  317. D.viewportForce(RectI(0, 0, resW(), resH())); // DX9 automatically sets full viewport on RT change, force current viewport values
  318. #elif GL
  319. if(was_main_fbo!=D.mainFBO())SwitchedFBO();
  320. #endif
  321. D._view_active.setRect(RectI(0, 0, resW(), resH())).setViewport(); // set full viewport
  322. D.clipAllow(_cur[0]==_cur_main);
  323. }
  324. }
  325. #endif
  326. #define R Renderer
  327. #if DX11
  328. void RendererClass::setDSLookup()
  329. {
  330. if(R._cur_ds)
  331. {
  332. R._cur_ds_ids[ NO_DEPTH_READ]=R._cur_ds-> _dsv;
  333. R._cur_ds_ids[NEED_DEPTH_READ]=R._cur_ds->_rdsv;
  334. R._cur_ds_ids[WANT_DEPTH_READ]=R._cur_ds_ids[R._cur_ds_ids[NEED_DEPTH_READ] ? NEED_DEPTH_READ : NO_DEPTH_READ]; // use RDSV if available, if not then DSV
  335. }else
  336. {
  337. R._cur_ds_ids[ NO_DEPTH_READ]=null;
  338. R._cur_ds_ids[WANT_DEPTH_READ]=null;
  339. R._cur_ds_ids[NEED_DEPTH_READ]=null;
  340. }
  341. }
  342. void RendererClass::setDS(ID3D11DepthStencilView *dsv)
  343. {
  344. if(R._cur_ds_id!=dsv)
  345. {
  346. if(dsv==R._cur_ds_ids[NO_DEPTH_READ])D.texClear(R._cur_ds->_srv); // if we're writing to depth then we need to unbind it from reading (because DirectX will do it)
  347. D3DC->OMSetRenderTargets(Elms(R._cur_id), R._cur_id, R._cur_ds_id=dsv);
  348. }
  349. }
  350. void RendererClass::needDepthTest() {if(D._depth_write || !R._cur_ds_id)setDS(R._cur_ds_ids[ NO_DEPTH_READ]);}
  351. void RendererClass::wantDepthRead() { setDS(R._cur_ds_ids[WANT_DEPTH_READ]);}
  352. void RendererClass::needDepthRead() { setDS(R._cur_ds_ids[NEED_DEPTH_READ]);}
  353. #elif WEB
  354. void RendererClass::setDSLookup()
  355. {
  356. /*R._cur_ds_ids[WANT_DEPTH_READ]=*/R._cur_ds_ids[NO_DEPTH_READ]=(R._cur_ds ? R._cur_ds->_txtr : 0); // WANT_DEPTH_READ will always be the same as NO_DEPTH_READ so never use it
  357. //R._cur_ds_ids[NEED_DEPTH_READ]=NULL; this will always be null so no need to change it, this is already cleared at startup, besides it's never accessed anyway
  358. }
  359. void RendererClass::setDS(UInt ds_txtr_id)
  360. {
  361. if(R._cur_ds_id!=ds_txtr_id)
  362. {
  363. R._cur_ds_id=ds_txtr_id;
  364. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT , GL_TEXTURE_2D, ds_txtr_id, 0);
  365. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, ds_txtr_id, 0); // this could fail if Image doesn't have stencil component
  366. }
  367. }
  368. void RendererClass::needDepthTest() {setDS(R._cur_ds_ids[NO_DEPTH_READ]);}
  369. #endif
  370. #undef R
  371. void RendererClass::set(Image *t0, Image *t1, Image *t2, Image *t3, Image *ds, Bool custom_viewport, DEPTH_READ_MODE depth_read_mode)
  372. {
  373. Int changed=0;
  374. #if DX9
  375. enum
  376. {
  377. RT0=0x1,
  378. RTN=0x2,
  379. DS =0x4,
  380. };
  381. IDirect3DSurface9 *id0=(t0 ? t0->_surf : null),
  382. *id1=(t1 ? t1->_surf : null),
  383. *id2=(t2 ? t2->_surf : null),
  384. *id3=(t3 ? t3->_surf : null),
  385. *ids=(ds ? ds->_surf : null);
  386. // a render target can't be attached to multiple slots, so that's why 1-2-3 slots need first to be detached
  387. if(_cur_id[1]!=id1 || _cur_id[2]!=id2 || _cur_id[3]!=id3)
  388. {
  389. if(_cur_id[3]){_cur[3]=null; changed|=RTN; D3D->SetRenderTarget(3, _cur_id[3]=null);}
  390. if(_cur_id[2]){_cur[2]=null; changed|=RTN; D3D->SetRenderTarget(2, _cur_id[2]=null);}
  391. if(_cur_id[1]){_cur[1]=null; changed|=RTN; D3D->SetRenderTarget(1, _cur_id[1]=null);}
  392. }
  393. if(_cur_id[0]!=id0){_cur[0]=t0; changed|=RT0; D3D->SetRenderTarget (0, _cur_id[0]=id0);}
  394. if(_cur_id[1]!=id1){_cur[1]=t1; changed|=RTN; D3D->SetRenderTarget (1, _cur_id[1]=id1);}
  395. if(_cur_id[2]!=id2){_cur[2]=t2; changed|=RTN; D3D->SetRenderTarget (2, _cur_id[2]=id2);}
  396. if(_cur_id[3]!=id3){_cur[3]=t3; changed|=RTN; D3D->SetRenderTarget (3, _cur_id[3]=id3);}
  397. if(_cur_ds_id!=ids){_cur_ds=ds; changed|=DS ; D3D->SetDepthStencilSurface( _cur_ds_id=ids);}
  398. #elif DX11
  399. ID3D11RenderTargetView *id0=(t0 ? t0->_rtv : null),
  400. *id1=(t1 ? t1->_rtv : null),
  401. *id2=(t2 ? t2->_rtv : null),
  402. *id3=(t3 ? t3->_rtv : null);
  403. ID3D11DepthStencilView *ids=(ds ? (depth_read_mode==NEED_DEPTH_READ
  404. || depth_read_mode==WANT_DEPTH_READ && ds->_rdsv) ? ds->_rdsv : ds->_dsv : null);
  405. if(_cur_id[0]!=id0 || _cur_id[1]!=id1 || _cur_id[2]!=id2 || _cur_id[3]!=id3 || _cur_ds_id!=ids)
  406. {
  407. if(id0 && _cur_id[0]!=id0)D.texClear(t0->_srv);
  408. if(id1 && _cur_id[1]!=id1)D.texClear(t1->_srv);
  409. if(id2 && _cur_id[2]!=id2)D.texClear(t2->_srv);
  410. if(id3 && _cur_id[3]!=id3)D.texClear(t3->_srv);
  411. if(ids && ids==ds->_dsv && _cur_ds_id!=ids)D.texClear(ds->_srv); // if we're writing to depth then we need to unbind it from reading (because DirectX will do it)
  412. changed=true;
  413. _cur[0]=t0; _cur_id[0]=id0;
  414. _cur[1]=t1; _cur_id[1]=id1;
  415. _cur[2]=t2; _cur_id[2]=id2;
  416. _cur[3]=t3; _cur_id[3]=id3;
  417. _cur_ds=ds; _cur_ds_id=ids;
  418. D3DC->OMSetRenderTargets(Elms(_cur_id), _cur_id, _cur_ds_id); ASSERT(ELMS(_cur_id)<=D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT);
  419. }else
  420. if(_cur_ds!=ds) // even if we're not changing RenderTargetView it's still possible we're changing RenderTarget Image, this can happen on DX10 when using NEED_DEPTH_READ, '_rdsv' null and last '_cur_ds_id' also null
  421. {
  422. changed=true;
  423. _cur_ds =ds;
  424. }
  425. #elif GL
  426. // !! '_cur_id' is not set for GL, only '_cur_ds_id' is !!
  427. Image *set_ds =((WEB && depth_read_mode==NEED_DEPTH_READ) ? null : ds); // if we require reading from the depth buffer, then we can't set it
  428. Bool was_main_fbo=D.mainFBO(),
  429. main_fbo=(t0==&_main || ds==&_main_ds), // check 'ds' and not 'set_ds' !!
  430. change_0, change_ds;
  431. if(main_fbo)
  432. {
  433. change_0 =((_cur[0]==&_main )!=(t0==&_main ));
  434. change_ds=((_cur_ds==&_main_ds)!=(ds==&_main_ds)); // check 'ds' and not 'set_ds' !!
  435. }else
  436. {
  437. change_0 =!EqualRT(_cur[0], t0);
  438. change_ds=!EqualDS(_cur_ds, set_ds, _cur_ds_id);
  439. }
  440. if(main_fbo!=was_main_fbo || change_0 || change_ds || !EqualTxtr(_cur[1], t1) || !EqualTxtr(_cur[2], t2) || !EqualTxtr(_cur[3], t3))
  441. {
  442. #if !IOS // there is no default frame buffer on iOS
  443. D.colWriteAllow((main_fbo && t0!=&_main) ? 0 : COL_WRITE_RGBA); // on desktop OpenGL and OpenGL ES (except iOS) '_main' is always linked with '_main_ds', when setting null RT and '_main_ds' DS, '_main' is set either way but with color writes disabled
  444. D. depthAllow(!main_fbo || ds==&_main_ds); // check 'ds' and not 'set_ds' !!
  445. if(main_fbo)
  446. {
  447. D.fbo(0); // set default frame buffer
  448. _cur_ds_id=0; // main FBO always has 0 depth txtr ID
  449. #if GL_ES // do this only on GLES, because on desktop it requires GL 4.3 TODO:
  450. if(D.notShaderModelGLES2()) // this check is needed because on GLES2 we don't have 'glInvalidateFramebuffer'
  451. {
  452. // discard, for main FBO we need to setup different values - https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glInvalidateFramebuffer.xhtml
  453. GLenum attachment[3]; GLsizei attachments=0; // RT0+Depth+Stencil
  454. if(_main ._discard){_main ._discard=false; attachment[attachments++]=GL_COLOR;}
  455. if(_main_ds._discard){_main_ds._discard=false; attachment[attachments++]=GL_DEPTH; if(ImageTI[_main_ds.hwType()].s)attachment[attachments++]=GL_STENCIL;}
  456. if(attachments)glInvalidateFramebuffer(GL_FRAMEBUFFER, attachments, attachment);
  457. }
  458. #endif
  459. }else
  460. #endif
  461. {
  462. #if !IOS // on iOS there's only one FBO and nothing else, so it is set during creation and not here
  463. D.fbo(FBO); // set custom frame buffer
  464. #endif
  465. #if IOS // on iOS there's only one FBO, so we can safely apply only changed RT's, otherwise we need to always set all of them
  466. if(change_ds)
  467. #endif
  468. {
  469. if(!set_ds)
  470. {
  471. _cur_ds_id=0;
  472. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT , GL_RENDERBUFFER, 0);
  473. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
  474. }else
  475. if(_cur_ds_id=set_ds->_txtr)
  476. {
  477. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT , GL_TEXTURE_2D, _cur_ds_id , 0);
  478. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, ImageTI[set_ds->hwType()].s ? _cur_ds_id : 0, 0);
  479. }else
  480. {
  481. //_cur_ds_id=0; already set above
  482. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT , GL_RENDERBUFFER, set_ds->_rb );
  483. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, ImageTI[set_ds->hwType()].s ? set_ds->_rb : 0);
  484. }
  485. }
  486. #if IOS // on iOS there's only one FBO, so we can safely apply only changed RT's, otherwise we need to always set all of them
  487. if(change_0)
  488. #endif
  489. {
  490. if(!t0 )glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, 0);else
  491. if( t0->_txtr)glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D , t0->_txtr, 0);else
  492. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, t0->_rb );
  493. }
  494. if(D.notShaderModelGLES2()) // this check is needed because on GLES2 we don't have MRT, and there's no 'glInvalidateFramebuffer'
  495. {
  496. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, t1 ? t1->_txtr : 0, 0);
  497. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, t2 ? t2->_txtr : 0, 0);
  498. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, t3 ? t3->_txtr : 0, 0);
  499. GLenum buffers[]={GLenum(t0 ? GL_COLOR_ATTACHMENT0 : GL_NONE),
  500. GLenum(t1 ? GL_COLOR_ATTACHMENT1 : GL_NONE),
  501. GLenum(t2 ? GL_COLOR_ATTACHMENT2 : GL_NONE),
  502. GLenum(t3 ? GL_COLOR_ATTACHMENT3 : GL_NONE)};
  503. glDrawBuffers(Elms(buffers), buffers);
  504. glReadBuffer (buffers[0]);
  505. // discard
  506. #if GL_ES // do this only on GLES, because on desktop it requires GL 4.3 TODO:
  507. GLenum attachment[ELMS(_cur)+1]; GLsizei attachments=0; // RT's+DS
  508. if(t0 && t0->_discard){ t0->_discard=false; attachment[attachments++]=GL_COLOR_ATTACHMENT0;}
  509. if(t1 && t1->_discard){ t1->_discard=false; attachment[attachments++]=GL_COLOR_ATTACHMENT1;}
  510. if(t2 && t2->_discard){ t2->_discard=false; attachment[attachments++]=GL_COLOR_ATTACHMENT2;}
  511. if(t3 && t3->_discard){ t3->_discard=false; attachment[attachments++]=GL_COLOR_ATTACHMENT3;}
  512. if(set_ds && set_ds->_discard){set_ds->_discard=false; attachment[attachments++]=(ImageTI[set_ds->hwType()].s ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT);}
  513. if(attachments)glInvalidateFramebuffer(GL_FRAMEBUFFER, attachments, attachment);
  514. #endif
  515. }
  516. #if DEBUG
  517. GLenum error =glCheckFramebufferStatus(GL_FRAMEBUFFER);
  518. if( error!=GL_FRAMEBUFFER_COMPLETE)
  519. {
  520. LogN(S+"Invalid OpenGL FramebufferStatus: "+error+", frame:"+Time.frame()+", t0:"+(t0 ? t0->w() : 0)+", ds:"+(ds ? ds->w() : 0));
  521. Break();
  522. switch(error)
  523. {
  524. case GL_FRAMEBUFFER_UNSUPPORTED : error=0; break;
  525. case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT : error=0; break;
  526. case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: error=0; break;
  527. #if GL_ES
  528. case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS : error=0; break;
  529. #else
  530. case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER : error=0; break;
  531. case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER : error=0; break;
  532. #endif
  533. }
  534. }
  535. #endif
  536. }
  537. _cur[0] =t0;
  538. _cur[1] =t1;
  539. _cur[2] =t2;
  540. _cur[3] =t3;
  541. _cur_ds =ds;
  542. changed=true;
  543. }else
  544. if(_cur_ds!=ds) // check this in case 'set_ds' was cleared to null
  545. {
  546. _cur_ds =ds;
  547. changed=true;
  548. #if !IOS // there is no default frame buffer on iOS
  549. D.depthAllow(!main_fbo || ds==&_main_ds); // check 'ds' and not 'set_ds' !!
  550. #endif
  551. }
  552. #endif
  553. if(changed)
  554. {
  555. if(Image *main=(t0 ? t0 : ds))
  556. {
  557. _res=main->size();
  558. if(Sh.h_RTSizeI)Sh.h_RTSizeI->setConditional(_res);
  559. }
  560. #if DX9
  561. if(changed&RT0) // DX9 automatically performs some changes on RT #0 change (but not on the others, this was tested)
  562. {
  563. RectI full(0, 0, resW(), resH());
  564. D.viewportForce(full); // DX9 automatically sets full viewport, so we need to adjust cached viewport values to math those of the DX9
  565. D. clipForce(full); // DX9 automatically sets full clipping (scissor rect)
  566. }
  567. #elif GL
  568. if(was_main_fbo!=main_fbo)SwitchedFBO();
  569. #endif
  570. D._view_active.setRect(custom_viewport ? screenToPixelI(D.viewRect()) : RectI(0, 0, resW(), resH())).setViewport();
  571. D.clipAllow(_cur[0]==_cur_main);
  572. D.validateCoords(); // viewport was changed, also for DX9 (pixel offset) and OpenGL (flip Y 2D coords when Rendering To Texture)
  573. }else // render targets weren't changed, so set viewport only
  574. {
  575. RectI rect(custom_viewport ? screenToPixelI(D.viewRect()) : RectI(0, 0, resW(), resH()));
  576. if( rect!=D._view_active.recti) // over here we can do a quick != check first, because the Render Targets haven't changed (Renderer.resW(), resH() is the same, and that affects 'setRect')
  577. {
  578. D._view_active.setRect(rect).setViewport();
  579. D.validateCoords(); // viewport was changed, also for DX9 (pixel offset) and OpenGL (flip Y 2D coords when Rendering To Texture)
  580. }
  581. }
  582. }
  583. /******************************************************************************/
  584. void RendererClass::setMainViewport()
  585. {
  586. if(_stereo)
  587. {
  588. D._view_active.setRect(Renderer.screenToPixelI(D._view_rect)).setViewport(false).setShader();
  589. SetProjMatrix();
  590. SetCam(ActiveCam.matrix, false);
  591. D.validateCoords();
  592. D.setViewFovTan();
  593. }
  594. }
  595. void RendererClass::setEyeViewport()
  596. {
  597. if(_stereo)
  598. {
  599. D._view_active.setRect(Renderer.screenToPixelI(D._view_eye_rect[_eye])).setViewport(false).setShader(&ProjMatrixEyeOffset[_eye]); // 'setShader' needed for 'PosToScreen' and 'fur'
  600. SetProjMatrix(ProjMatrixEyeOffset[_eye]);
  601. SetCam(EyeMatrix[_eye], false);
  602. D.validateCoords(_eye);
  603. D.setViewFovTan();
  604. }
  605. }
  606. Rect* RendererClass::setEyeParams()
  607. {
  608. if(_stereo)
  609. {
  610. RectI rect=D._view_active.recti;
  611. D._view_active.setRect(Renderer.screenToPixelI(D._view_eye_rect[_eye])).setShader(&ProjMatrixEyeOffset[_eye]).setRect(rect);
  612. return &D._view_eye_rect[_eye];
  613. }
  614. return &D._view_rect;
  615. }
  616. /******************************************************************************/
  617. void RendererClass:: hasGlow() {_has_glow=true;}
  618. void RendererClass::finalizeGlow()
  619. {
  620. if(!ImageTI[_col->type()].a || !D.glowAllow() || !D.bloomAllow() || fastCombine())_has_glow=false; // glow can be done only if we have Alpha Channel in the RT, if we're allowing bloom processing (because it'd done together in the same shader), if we're allowing glow, and if 'fastCombine' is not active
  621. }
  622. /******************************************************************************/
  623. Bool RendererClass::capture(Image &image, Int w, Int h, Int type, Int mode, Int mip_maps, Bool alpha)
  624. {
  625. if(image.capture(_main))
  626. {
  627. if(type<=0)type=image.type();else MIN(type, IMAGE_TYPES);
  628. if(!_ds_1s)alpha=false;
  629. if(ImageTI[type].a && ImageTI[image.type()].a && !alpha && image.lock()) // dest has alpha and src has alpha, and don't want to manually set alpha
  630. {
  631. REPD(y, image.h())
  632. REPD(x, image.w())
  633. {
  634. Color color=image.color(x, y); color.a=255; // force full alpha
  635. image.color(x, y, color);
  636. }
  637. image.unlock();
  638. }
  639. if(image.copyTry(image, w, h, 1, type, mode, mip_maps))
  640. {
  641. if(alpha && ImageTI[image.type()].a && image.lock()) // set alpha from depth
  642. {
  643. Image depth; if(depth.capture(*_ds_1s) && depth.lockRead())
  644. {
  645. Image alpha(depth.w(), depth.h(), 1, IMAGE_A8, IMAGE_SOFT, 1);
  646. REPD(y, depth.h())
  647. REPD(x, depth.w())
  648. {
  649. Flt w=depth.pixelF(x, y);
  650. #if REVERSE_DEPTH
  651. alpha.pixB(x, y)=((w>0.0f) ? 0xFF : 0);
  652. #else
  653. alpha.pixB(x, y)=((w<1.0f) ? 0xFF : 0);
  654. #endif
  655. }
  656. depth.unlock();
  657. alpha.resize(image.w(), image.h(), FILTER_LINEAR);
  658. REPD(y, image.h())
  659. REPD(x, image.w())
  660. {
  661. Color color=image.color(x, y); color.a=alpha.pixB(x, y);
  662. image.color(x, y, color);
  663. }
  664. }else
  665. {
  666. REPD(y, image.h())
  667. REPD(x, image.w())
  668. {
  669. Color color=image.color(x, y); color.a=255; // force full alpha
  670. image.color(x, y, color);
  671. }
  672. }
  673. image.unlock().updateMipMaps();
  674. }
  675. return true;
  676. }
  677. }
  678. image.del(); return false;
  679. }
  680. Bool RendererClass::screenShot(C Str &name, Bool alpha)
  681. {
  682. FCreateDirs(GetPath(name));
  683. Image temp;
  684. if(alpha) // with alpha
  685. {
  686. if(capture(temp, -1, -1, IMAGE_DEFAULT, IMAGE_SOFT, 1, true))return temp.Export(name);
  687. }else
  688. if(temp.capture(_main)) // no alpha
  689. {
  690. if(ImageTI[temp.type()].a)temp.copyTry(temp, -1, -1, -1, IMAGE_R8G8B8, IMAGE_SOFT, 1); // if captured image has alpha channel then let's remove it
  691. return temp.Export(name);
  692. }
  693. return false;
  694. }
  695. Bool RendererClass::screenShots(C Str &name, C Str &ext, Bool alpha)
  696. {
  697. Str n=FFirst(name, ext);
  698. return n.is() ? screenShot(n, alpha) : false;
  699. }
  700. /******************************************************************************/
  701. void RendererClass::timeMeasure(Bool on)
  702. {
  703. if(_t_measure!=on)
  704. {
  705. _t_measure=on;
  706. _t_last_measure=Time.curTime();
  707. }
  708. }
  709. /******************************************************************************/
  710. }
  711. /******************************************************************************/