ShadowMap.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. /* Copyright (c) 2002-2012 Croteam Ltd.
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of version 2 of the GNU General Public License as published by
  4. the Free Software Foundation
  5. This program is distributed in the hope that it will be useful,
  6. but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License along
  10. with this program; if not, write to the Free Software Foundation, Inc.,
  11. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
  12. #include "stdh.h"
  13. #include <Engine/Graphics/ShadowMap.h>
  14. #include <Engine/Base/Console.h>
  15. #include <Engine/Base/Memory.h>
  16. #include <Engine/Base/Stream.h>
  17. #include <Engine/Math/Functions.h>
  18. #include <Engine/Graphics/GfxLibrary.h>
  19. #include <Engine/Graphics/Color.h>
  20. #include <Engine/Graphics/Texture.h>
  21. #include <Engine/Graphics/GfxProfile.h>
  22. #include <Engine/Brushes/Brush.h>
  23. #include <Engine/Base/Statistics_internal.h>
  24. #define SHADOWMAXBYTES (256*256*4*4/3)
  25. extern INDEX shd_iStaticSize;
  26. extern INDEX shd_iDynamicSize;
  27. extern INDEX shd_bFineQuality;
  28. extern INDEX shd_iDithering;
  29. extern INDEX shd_bDynamicMipmaps;
  30. extern INDEX gap_bAllowSingleMipmap;
  31. extern FLOAT gfx_tmProbeDecay;
  32. extern BOOL _bShadowsUpdated;
  33. extern BOOL _bMultiPlayer;
  34. /*
  35. * Routines that manipulates with shadow cluster map class
  36. */
  37. CShadowMap::CShadowMap()
  38. {
  39. sm_pulCachedShadowMap = NULL;
  40. sm_pulDynamicShadowMap = NULL;
  41. sm_slMemoryUsed = 0;
  42. sm_ulObject = NONE;
  43. sm_ulProbeObject = NONE;
  44. sm_ulInternalFormat = NONE;
  45. sm_iRenderFrame = -1;
  46. sm_ulFlags = NONE;
  47. Clear();
  48. }
  49. CShadowMap::~CShadowMap()
  50. {
  51. Clear();
  52. }
  53. // report shadowmap memory usage (in bytes)
  54. ULONG CShadowMap::GetShadowSize(void)
  55. {
  56. CBrushPolygon *pbpo=((CBrushShadowMap *)this)->GetBrushPolygon();
  57. ULONG ulFlags=pbpo->bpo_ulFlags;
  58. BOOL bIsTransparent = (ulFlags&BPOF_PORTAL) && !(ulFlags&(BPOF_TRANSLUCENT|BPOF_TRANSPARENT));
  59. BOOL bTakesShadow = !(ulFlags&BPOF_FULLBRIGHT);
  60. BOOL bIsFlat = sm_pulCachedShadowMap==&sm_colFlat;
  61. if( bIsTransparent || !bTakesShadow || bIsFlat) return 0; // not influenced
  62. const PIX pixSizeU = sm_mexWidth >>sm_iFirstMipLevel;
  63. const PIX pixSizeV = sm_mexHeight>>sm_iFirstMipLevel;
  64. return pixSizeU*pixSizeV *BYTES_PER_TEXEL;
  65. }
  66. // cache the shadow map
  67. void CShadowMap::Cache( INDEX iWantedMipLevel)
  68. {
  69. _pfGfxProfile.StartTimer( CGfxProfile::PTI_CACHESHADOW);
  70. _bShadowsUpdated = TRUE;
  71. // level must be in valid range and caching has to be needed
  72. ASSERT( iWantedMipLevel>=sm_iFirstMipLevel && iWantedMipLevel<=sm_iLastMipLevel);
  73. ASSERT( sm_pulCachedShadowMap==NULL || iWantedMipLevel<sm_iFirstCachedMipLevel);
  74. // dynamic layers are invalid when shadowmap is cached
  75. sm_ulFlags |= SMF_DYNAMICINVALID;
  76. if( sm_pulDynamicShadowMap!=NULL) {
  77. FreeMemory( sm_pulDynamicShadowMap);
  78. sm_pulDynamicShadowMap = NULL;
  79. }
  80. // calculate (new) amount of memory
  81. const PIX pixSizeU = sm_mexWidth >>iWantedMipLevel;
  82. const PIX pixSizeV = sm_mexHeight>>iWantedMipLevel;
  83. const SLONG slSize = GetMipmapOffset( 15, pixSizeU, pixSizeV) *BYTES_PER_TEXEL;
  84. const BOOL bWasFlat = sm_pulCachedShadowMap==&sm_colFlat;
  85. const BOOL bCached = sm_pulCachedShadowMap!=NULL;
  86. // determine whether shadowmap is all flat (once flat - always flat!)
  87. if( IsShadowFlat(sm_colFlat)) {
  88. // release memory if allocated
  89. if( bCached) {
  90. ASSERT( sm_slMemoryUsed>0 && sm_slMemoryUsed<=SHADOWMAXBYTES);
  91. if( !bWasFlat) FreeMemory( sm_pulCachedShadowMap);
  92. }
  93. sm_pulCachedShadowMap = &sm_colFlat;
  94. sm_iFirstCachedMipLevel = iWantedMipLevel;
  95. sm_slMemoryUsed = slSize;
  96. // add it to shadow list
  97. if( !sm_lnInGfx.IsLinked()) _pGfx->gl_lhCachedShadows.AddTail(sm_lnInGfx);
  98. _pfGfxProfile.StopTimer( CGfxProfile::PTI_CACHESHADOW);
  99. return;
  100. }
  101. // if not yet allocated
  102. if( !bCached || bWasFlat)
  103. {
  104. // allocate the memory
  105. sm_pulCachedShadowMap = (ULONG*)AllocMemory(slSize);
  106. sm_slMemoryUsed = slSize;
  107. ASSERT( sm_slMemoryUsed>0 && sm_slMemoryUsed<=SHADOWMAXBYTES);
  108. }
  109. // if already allocated, but too small
  110. else if( iWantedMipLevel<sm_iFirstCachedMipLevel)
  111. {
  112. // allocate new block
  113. ULONG *pulNew = (ULONG*)AllocMemory(slSize);
  114. ASSERT( sm_slMemoryUsed>0 && sm_slMemoryUsed<=SHADOWMAXBYTES);
  115. if( slSize>sm_slMemoryUsed && !bWasFlat) {
  116. // copy old shadow map at the end of buffer
  117. memcpy( pulNew + (slSize-sm_slMemoryUsed)/BYTES_PER_TEXEL, sm_pulCachedShadowMap, sm_slMemoryUsed);
  118. } // free old block if needed and use the new one
  119. if( !bWasFlat) FreeMemory( sm_pulCachedShadowMap);
  120. sm_pulCachedShadowMap = pulNew;
  121. sm_slMemoryUsed = slSize;
  122. ASSERT( sm_slMemoryUsed>0 && sm_slMemoryUsed<=SHADOWMAXBYTES);
  123. } else {
  124. // WHAT?
  125. ASSERTALWAYS( "Trying to cache shadowmap again in the same mipmap!");
  126. }
  127. // let the higher level driver mix its layers
  128. INDEX iLastMipLevelToCache = Min( sm_iLastMipLevel, sm_iFirstCachedMipLevel-1L);
  129. sm_iFirstCachedMipLevel = iWantedMipLevel;
  130. ASSERT( iWantedMipLevel <= iLastMipLevelToCache);
  131. // colorize shadowmap?
  132. extern INDEX shd_bColorize;
  133. if( _bMultiPlayer) shd_bColorize = FALSE; // don't allow in multiplayer mode!
  134. if( shd_bColorize) {
  135. #define GSIZE 4.0f
  136. #define RSIZE 8.0f
  137. FLOAT fLogSize = Log2((sm_mexWidth>>sm_iFirstCachedMipLevel) * (sm_mexHeight>>sm_iFirstCachedMipLevel)) /2;
  138. fLogSize = Max(fLogSize,GSIZE) -GSIZE;
  139. FLOAT fR = fLogSize / (RSIZE-GSIZE);
  140. COLOR colSize;
  141. if( fR>0.5f) colSize = LerpColor( C_dYELLOW, C_dRED, (fR-0.5f)*2);
  142. else colSize = LerpColor( C_dGREEN, C_dYELLOW, fR*2);
  143. // fill!
  144. for( INDEX iPix=0; iPix<sm_slMemoryUsed/4; iPix++) sm_pulCachedShadowMap[iPix] = ByteSwap(colSize);
  145. }
  146. // no colorization - just mix the layers in
  147. else MixLayers( iWantedMipLevel, iLastMipLevelToCache);
  148. // add it to shadow list
  149. if( !sm_lnInGfx.IsLinked()) _pGfx->gl_lhCachedShadows.AddTail( sm_lnInGfx);
  150. _pfGfxProfile.StopTimer( CGfxProfile::PTI_CACHESHADOW);
  151. }
  152. // update dynamic layers of the shadow map
  153. // (returns mip in which shadow needs to be uploaded)
  154. ULONG CShadowMap::UpdateDynamicLayers(void)
  155. {
  156. // call this only if needed
  157. ASSERT( sm_ulFlags&SMF_DYNAMICINVALID);
  158. sm_ulFlags &= ~SMF_DYNAMICINVALID;
  159. // if there are no dynamic layers
  160. if( !HasDynamicLayers()) {
  161. // free dynamic shadows if allocated
  162. if( sm_pulDynamicShadowMap!=NULL) {
  163. _bShadowsUpdated = TRUE;
  164. ASSERT( sm_slMemoryUsed>0 && sm_slMemoryUsed<=SHADOWMAXBYTES);
  165. FreeMemory( sm_pulDynamicShadowMap);
  166. sm_pulDynamicShadowMap = NULL;
  167. return sm_iFirstCachedMipLevel;
  168. } else return 31;
  169. }
  170. _pfGfxProfile.StartTimer( CGfxProfile::PTI_CACHESHADOW);
  171. // allocate the memory if not yet allocated
  172. if( sm_pulDynamicShadowMap==NULL) {
  173. ASSERT( sm_slMemoryUsed>0 && sm_slMemoryUsed<=SHADOWMAXBYTES);
  174. sm_pulDynamicShadowMap = (ULONG*)AllocMemory(sm_slMemoryUsed);
  175. }
  176. // determine and clamp to max allowed dynamic shadow dimension
  177. const INDEX iMinSize = Max( shd_iStaticSize-2L, 5L);
  178. shd_iDynamicSize = Clamp( shd_iDynamicSize, iMinSize, shd_iStaticSize);
  179. PIX pixClampAreaSize = 1L<<(shd_iDynamicSize*2);
  180. INDEX iFinestMipLevel = sm_iFirstCachedMipLevel +
  181. ClampTextureSize( pixClampAreaSize, _pGfx->gl_pixMaxTextureDimension,
  182. sm_mexWidth>>sm_iFirstCachedMipLevel, sm_mexHeight>>sm_iFirstCachedMipLevel);
  183. // check if need to generate only one mip-map
  184. INDEX iLastMipLevel = sm_iLastMipLevel;
  185. if( !shd_bDynamicMipmaps && gap_bAllowSingleMipmap) iLastMipLevel = iFinestMipLevel;
  186. // let the higher level driver mix its layers
  187. MixLayers( iFinestMipLevel, iLastMipLevel, TRUE);
  188. _pfGfxProfile.StopTimer( CGfxProfile::PTI_CACHESHADOW);
  189. // skip if there was nothing to mix-in
  190. if( sm_ulFlags&SMF_DYNAMICBLACK) return 31;
  191. _bShadowsUpdated = TRUE;
  192. return iFinestMipLevel;
  193. }
  194. // invalidate the shadow map
  195. void CShadowMap::Invalidate( BOOL bDynamicOnly/*=FALSE*/)
  196. {
  197. // if only dynamic layers are to be uncached
  198. if( bDynamicOnly) {
  199. // just mark that they are not valid any more
  200. sm_ulFlags |= SMF_DYNAMICINVALID;
  201. // if static layers are to be uncached
  202. } else {
  203. // mark that no mipmaps are cached
  204. sm_iFirstCachedMipLevel = 31;
  205. }
  206. }
  207. // mark that shadow has been drawn
  208. void CShadowMap::MarkDrawn(void)
  209. {
  210. // remove from list
  211. ASSERT( sm_lnInGfx.IsLinked());
  212. sm_lnInGfx.Remove();
  213. // set time stamp
  214. sm_tvLastDrawn = _pTimer->GetHighPrecisionTimer();
  215. // put at the end of the list
  216. _pGfx->gl_lhCachedShadows.AddTail(sm_lnInGfx);
  217. }
  218. // uncache the shadow map (returns total ammount of memory that has been freed)
  219. SLONG CShadowMap::Uncache( void)
  220. {
  221. _bShadowsUpdated = TRUE;
  222. // discard uploaded portion
  223. if( sm_ulObject!=NONE) {
  224. gfxDeleteTexture(sm_ulObject);
  225. gfxDeleteTexture(sm_ulProbeObject);
  226. sm_ulInternalFormat = NONE;
  227. }
  228. SLONG slFreed = 0;
  229. // if dynamic allocated, release memory
  230. if( sm_pulDynamicShadowMap != NULL) {
  231. FreeMemory( sm_pulDynamicShadowMap);
  232. sm_pulDynamicShadowMap = NULL;
  233. ASSERT( sm_slMemoryUsed>0 && sm_slMemoryUsed<=SHADOWMAXBYTES);
  234. slFreed += sm_slMemoryUsed;
  235. }
  236. // if static non-flat has been allocated
  237. if( sm_pulCachedShadowMap!=NULL) {
  238. // release memory
  239. ASSERT( sm_slMemoryUsed>0 && sm_slMemoryUsed<=SHADOWMAXBYTES);
  240. if( sm_pulCachedShadowMap!=&sm_colFlat) {
  241. FreeMemory( sm_pulCachedShadowMap);
  242. slFreed += sm_slMemoryUsed;
  243. } else slFreed += sizeof(sm_colFlat);
  244. }
  245. // reset params
  246. sm_iFirstCachedMipLevel = 31;
  247. sm_pulCachedShadowMap = NULL;
  248. sm_slMemoryUsed = 0;
  249. sm_tvLastDrawn = 0I64;
  250. sm_iRenderFrame = -1;
  251. sm_ulFlags = NONE;
  252. sm_tpLocal.Clear();
  253. // if added to list of all shadows, remove from there
  254. if( sm_lnInGfx.IsLinked()) sm_lnInGfx.Remove();
  255. return slFreed;
  256. }
  257. // clear the object
  258. void CShadowMap::Clear()
  259. {
  260. // uncache the shadow map
  261. Uncache();
  262. // reset structure members
  263. sm_pulCachedShadowMap = NULL;
  264. sm_pulDynamicShadowMap = NULL;
  265. sm_iFirstMipLevel = 0;
  266. sm_slMemoryUsed = 0;
  267. sm_tvLastDrawn = 0I64;
  268. sm_mexOffsetX = 0;
  269. sm_mexOffsetY = 0;
  270. sm_mexWidth = 0;
  271. sm_mexHeight = 0;
  272. sm_ulFlags = NONE;
  273. }
  274. // initialize the shadow map
  275. void CShadowMap::Initialize( INDEX iMipLevel, MEX mexOffsetX, MEX mexOffsetY, MEX mexWidth, MEX mexHeight)
  276. {
  277. // clear old shadow
  278. Clear();
  279. // just remember new values
  280. sm_iFirstMipLevel = iMipLevel;
  281. sm_mexOffsetX = mexOffsetX;
  282. sm_mexOffsetY = mexOffsetY;
  283. sm_mexWidth = mexWidth;
  284. sm_mexHeight = mexHeight;
  285. sm_iLastMipLevel = FastLog2( Min(mexWidth, mexHeight));
  286. ASSERT( (mexWidth >>sm_iLastMipLevel)>=1);
  287. ASSERT( (mexHeight>>sm_iLastMipLevel)>=1);
  288. }
  289. // skip old shadows saved in stream
  290. void CShadowMap::Read_old_t(CTStream *pstrm) // throw char *
  291. {
  292. Clear();
  293. // read shadow map header
  294. // pstrm->ExpectID_t( CChunkID("CTSM")); // read in Read_t()
  295. if( pstrm->GetSize_t() != 5*4) throw( TRANS("Invalid shadow cluster map file."));
  296. *pstrm >> (INDEX)sm_iFirstMipLevel;
  297. INDEX iNoOfMipmaps;
  298. *pstrm >> (INDEX)iNoOfMipmaps;
  299. *pstrm >> (MEX)sm_mexOffsetX;
  300. *pstrm >> (MEX)sm_mexOffsetY;
  301. *pstrm >> (MEX)sm_mexWidth;
  302. *pstrm >> (MEX)sm_mexHeight;
  303. BOOL bStaticImagePresent, bAnimatingImagePresent;
  304. *pstrm >> (INDEX&)bStaticImagePresent;
  305. *pstrm >> (INDEX&)bAnimatingImagePresent;
  306. // skip mip-map offsets
  307. pstrm->Seek_t( MAX_MEX_LOG2*4, CTStream::SD_CUR);
  308. // skip the shadow map data
  309. if( bStaticImagePresent) {
  310. pstrm->ExpectID_t("SMSI");
  311. SLONG slSize;
  312. *pstrm>>slSize;
  313. pstrm->Seek_t(slSize, CTStream::SD_CUR);
  314. }
  315. if( bAnimatingImagePresent) {
  316. pstrm->ExpectID_t("SMAI");
  317. SLONG slSize;
  318. *pstrm>>slSize;
  319. pstrm->Seek_t(slSize, CTStream::SD_CUR);
  320. }
  321. }
  322. // reads image info raw format from file
  323. void CShadowMap::Read_t( CTStream *pstrm) // throw char *
  324. {
  325. Clear();
  326. // read the header chunk ID
  327. CChunkID cidHeader = pstrm->GetID_t();
  328. // if it is the old shadow format
  329. if (cidHeader==CChunkID("CTSM")) {
  330. // read shadows in old format
  331. Read_old_t(pstrm);
  332. return;
  333. // if it is not the new shadow format
  334. } else if (!(cidHeader==CChunkID("LSHM"))) { // layered shadow map
  335. // error
  336. FatalError(TRANS("Error loading shadow map! Wrong header chunk."));
  337. }
  338. // load the shadow map data
  339. *pstrm >> sm_ulFlags;
  340. *pstrm >> sm_iFirstMipLevel;
  341. *pstrm >> sm_mexOffsetX;
  342. *pstrm >> sm_mexOffsetY;
  343. *pstrm >> sm_mexWidth;
  344. *pstrm >> sm_mexHeight;
  345. sm_iLastMipLevel = FastLog2( Min(sm_mexWidth, sm_mexHeight));
  346. ASSERT((sm_mexWidth >>sm_iLastMipLevel)>=1);
  347. ASSERT((sm_mexHeight>>sm_iLastMipLevel)>=1);
  348. // read the layers of the shadow
  349. ReadLayers_t(pstrm);
  350. }
  351. // writes shadow cluster map format to file
  352. void CShadowMap::Write_t( CTStream *pstrm) // throw char *
  353. {
  354. pstrm->WriteID_t("LSHM"); // layered shadow map
  355. // load the shadow map data
  356. *pstrm << sm_ulFlags;
  357. *pstrm << sm_iFirstMipLevel;
  358. *pstrm << sm_mexOffsetX;
  359. *pstrm << sm_mexOffsetY;
  360. *pstrm << sm_mexWidth;
  361. *pstrm << sm_mexHeight;
  362. // write the layers of the shadow
  363. WriteLayers_t(pstrm);
  364. }
  365. // mix all layers into cached shadow map
  366. void CShadowMap::MixLayers( INDEX iFirstMip, INDEX iLastMip, BOOL bDynamic/*=FALSE*/)
  367. {
  368. // base function is used only for testing
  369. (void)iFirstMip;
  370. (void)iLastMip;
  371. // just fill with white
  372. ULONG ulValue = ByteSwap(C_WHITE);
  373. ASSERT( sm_pulCachedShadowMap!=NULL);
  374. if( sm_pulCachedShadowMap==NULL || sm_pulCachedShadowMap==&sm_colFlat) return;
  375. for( INDEX i=0; i<(sm_mexWidth>>sm_iFirstMipLevel)*(sm_mexHeight>>sm_iFirstMipLevel); i++) {
  376. sm_pulCachedShadowMap[i] = ulValue;
  377. }
  378. }
  379. // check if all layers are up to date
  380. void CShadowMap::CheckLayersUpToDate(void)
  381. {
  382. NOTHING;
  383. }
  384. // test if there is any dynamic layer
  385. BOOL CShadowMap::HasDynamicLayers(void)
  386. {
  387. return FALSE;
  388. }
  389. void CShadowMap::ReadLayers_t( CTStream *pstrm) // throw char *
  390. {
  391. }
  392. void CShadowMap::WriteLayers_t( CTStream *pstrm) // throw char *
  393. {
  394. }
  395. // prepare shadow map for upload and bind (returns whether the shadowmap is flat or not)
  396. void CShadowMap::Prepare(void)
  397. {
  398. // determine probing
  399. ASSERT(this!=NULL);
  400. extern BOOL ProbeMode( CTimerValue tvLast);
  401. BOOL bUseProbe = ProbeMode(sm_tvLastDrawn);
  402. // determine and clamp to max allowed shadow dimension
  403. shd_iStaticSize = Clamp( shd_iStaticSize, 5L, 8L);
  404. PIX pixClampAreaSize = 1L<<(shd_iStaticSize*2);
  405. // determine largest allowed mip level
  406. INDEX iFinestMipLevel = sm_iFirstMipLevel +
  407. ClampTextureSize( pixClampAreaSize, _pGfx->gl_pixMaxTextureDimension,
  408. sm_mexWidth>>sm_iFirstMipLevel, sm_mexHeight>>sm_iFirstMipLevel);
  409. // make sure we didn't run out of range
  410. INDEX iWantedMipLevel = ClampUp( iFinestMipLevel, sm_iLastMipLevel);
  411. sm_iFirstUploadMipLevel = 31;
  412. const PIX pixShadowSize = (sm_mexWidth>>iFinestMipLevel) * (sm_mexHeight>>iFinestMipLevel);
  413. // see if shadowmap can be pulled out of probe mode
  414. if( pixShadowSize<=16*16*4 || ((sm_ulFlags&SMF_PROBED) && _pGfx->gl_slAllowedUploadBurst>=0)) bUseProbe = FALSE;
  415. if( bUseProbe) {
  416. // adjust mip-level for probing
  417. ULONG *pulDummy = NULL;
  418. PIX pixProbeWidth = sm_mexWidth >>iFinestMipLevel;
  419. PIX pixProbeHeight = sm_mexHeight>>iFinestMipLevel;
  420. INDEX iMipOffset = GetMipmapOfSize( 16*16, pulDummy, pixProbeWidth, pixProbeHeight);
  421. if( iMipOffset<2) bUseProbe = FALSE;
  422. else iWantedMipLevel += iMipOffset;
  423. }
  424. // cache if it is not cached at all of not in this mip level
  425. if( sm_pulCachedShadowMap==NULL || iWantedMipLevel<sm_iFirstCachedMipLevel) {
  426. Cache( iWantedMipLevel);
  427. ASSERT( sm_iFirstCachedMipLevel<31);
  428. sm_iFirstUploadMipLevel = sm_iFirstCachedMipLevel;
  429. }
  430. // update the dynamic layers if they're invalid
  431. if( sm_ulFlags&SMF_DYNAMICINVALID) {
  432. INDEX iRet = UpdateDynamicLayers();
  433. if( iRet<31) sm_iFirstUploadMipLevel = iRet;
  434. }
  435. // update statistics if not updated already for this frame
  436. if( sm_iRenderFrame != _pGfx->gl_iFrameNumber) {
  437. sm_iRenderFrame = _pGfx->gl_iFrameNumber;
  438. // determine size and update
  439. SLONG slBytes = pixShadowSize * gfxGetFormatPixRatio(sm_ulInternalFormat);
  440. if( !sm_tpLocal.tp_bSingleMipmap) slBytes = slBytes *4/3;
  441. _sfStats.IncrementCounter( CStatForm::SCI_SHADOWBINDS, 1);
  442. _sfStats.IncrementCounter( CStatForm::SCI_SHADOWBINDBYTES, slBytes);
  443. }
  444. // reduce allowed burst value if upload is required in non-probe mode
  445. if( !bUseProbe && sm_iFirstUploadMipLevel<31) {
  446. const PIX pixWidth = sm_mexWidth >>sm_iFirstUploadMipLevel;
  447. const PIX pixHeight = sm_mexHeight >>sm_iFirstUploadMipLevel;
  448. const INDEX iPixSize = shd_bFineQuality ? 4 : 2;
  449. SLONG slSize = pixWidth*pixHeight *iPixSize;
  450. _pGfx->gl_slAllowedUploadBurst -= slSize;
  451. }
  452. // update probe requirements
  453. if( bUseProbe) sm_ulFlags |= SMF_WANTSPROBE;
  454. else sm_ulFlags &=~SMF_WANTSPROBE;
  455. }
  456. // provide the data for uploading
  457. void CShadowMap::SetAsCurrent(void)
  458. {
  459. ASSERT( sm_pulCachedShadowMap!=NULL && sm_iFirstCachedMipLevel<31);
  460. // eventually re-adjust LOD bias
  461. extern FLOAT _fCurrentLODBias;
  462. extern void UpdateLODBias( const FLOAT fLODBias);
  463. if( _fCurrentLODBias != _pGfx->gl_fTextureLODBias) UpdateLODBias( _pGfx->gl_fTextureLODBias);
  464. // determine actual need for upload and eventaully colorize shadowmaps
  465. const BOOL bFlat = IsFlat();
  466. // done here if flat and non-dynamic
  467. if( bFlat) {
  468. // bind flat texture
  469. _ptdFlat->SetAsCurrent();
  470. MarkDrawn();
  471. return;
  472. }
  473. // init use probe flag
  474. BOOL bUseProbe = (sm_ulFlags & SMF_WANTSPROBE);
  475. // if needs to be uploaded
  476. if( sm_iFirstUploadMipLevel<31 || ((sm_ulFlags&SMF_DYNAMICUPLOADED) && (sm_ulFlags&SMF_DYNAMICBLACK)))
  477. {
  478. // generate bind number(s) if needed
  479. if( sm_ulObject==NONE) {
  480. gfxGenerateTexture( sm_ulObject);
  481. sm_pixUploadWidth = sm_pixUploadHeight = 0;
  482. sm_ulInternalFormat = NONE;
  483. }
  484. // determine shadow map pointer (static or dynamic shadow)
  485. ULONG *pulShadowMap = sm_pulCachedShadowMap;
  486. BOOL bSingleMipmap = FALSE;
  487. sm_ulFlags &= ~SMF_DYNAMICUPLOADED;
  488. if( sm_pulDynamicShadowMap!=NULL && !(sm_ulFlags&SMF_DYNAMICBLACK)) {
  489. pulShadowMap = sm_pulDynamicShadowMap;
  490. if( !shd_bDynamicMipmaps && gap_bAllowSingleMipmap) bSingleMipmap = TRUE;
  491. sm_ulFlags |= SMF_DYNAMICUPLOADED;
  492. bUseProbe = FALSE; // don't probe dynamic shadowmaps
  493. }
  494. // reset mapping parameters if needed
  495. if( sm_tpLocal.tp_bSingleMipmap != bSingleMipmap) {
  496. sm_tpLocal.Clear();
  497. sm_tpLocal.tp_bSingleMipmap = bSingleMipmap;
  498. sm_pixUploadWidth = sm_pixUploadHeight = 0; // will not use subimage
  499. }
  500. // determine corresponding shadowmap's texture internal format, memory offset and flatness
  501. if( sm_iFirstUploadMipLevel>30) sm_iFirstUploadMipLevel = sm_iFirstCachedMipLevel;
  502. PIX pixWidth=1, pixHeight=1;
  503. pixWidth = sm_mexWidth >>sm_iFirstUploadMipLevel;
  504. pixHeight = sm_mexHeight >>sm_iFirstUploadMipLevel;
  505. pulShadowMap += sm_slMemoryUsed/BYTES_PER_TEXEL - GetMipmapOffset( 15, pixWidth, pixHeight);
  506. // paranoid
  507. ASSERT( pixWidth>0 && pixHeight>0);
  508. // determine internal shadow texture format and usage of faster glTexSubImage function instead of slow glTexImage
  509. BOOL bUseSubImage = TRUE;
  510. ULONG ulInternalFormat = TS.ts_tfRGB5;
  511. if( !(_pGfx->gl_ulFlags&GLF_32BITTEXTURES)) shd_bFineQuality = FALSE;
  512. if( shd_bFineQuality) ulInternalFormat = TS.ts_tfRGB8;
  513. if( _slShdSaturation<4) ulInternalFormat = TS.ts_tfL8; // better quality for grayscale shadow mode
  514. // eventually re-adjust uploading parameters
  515. if( sm_pixUploadWidth!=pixWidth || sm_pixUploadHeight!=pixHeight || sm_ulInternalFormat!=ulInternalFormat) {
  516. sm_pixUploadWidth = pixWidth;
  517. sm_pixUploadHeight = pixHeight;
  518. sm_ulInternalFormat = ulInternalFormat;
  519. bUseSubImage = FALSE;
  520. }
  521. // upload probe (if needed)
  522. if( bUseProbe) {
  523. sm_ulFlags |= SMF_PROBED;
  524. if( sm_ulProbeObject==NONE) gfxGenerateTexture( sm_ulProbeObject);
  525. CTexParams tpTmp = sm_tpLocal;
  526. gfxSetTexture( sm_ulProbeObject, tpTmp);
  527. gfxUploadTexture( pulShadowMap, pixWidth, pixHeight, TS.ts_tfRGB5, FALSE);
  528. } else {
  529. // upload shadow in required format and size
  530. if( sm_ulFlags&SMF_PROBED) { // cannot subimage shadowmap that has been probed
  531. bUseSubImage = FALSE;
  532. sm_ulFlags &= ~SMF_PROBED;
  533. }
  534. // colorize mipmaps if needed
  535. extern INDEX tex_bColorizeMipmaps;
  536. if( tex_bColorizeMipmaps && pixWidth>1 && pixHeight>1) ColorizeMipmaps( 1, pulShadowMap, pixWidth, pixHeight);
  537. MarkDrawn(); // mark that shadowmap has been referenced
  538. gfxSetTexture( sm_ulObject, sm_tpLocal);
  539. gfxUploadTexture( pulShadowMap, pixWidth, pixHeight, ulInternalFormat, bUseSubImage);
  540. }
  541. // paranoid android
  542. ASSERT( sm_iFirstCachedMipLevel<31 && sm_pulCachedShadowMap!=NULL);
  543. return;
  544. }
  545. // set corresponding probe or texture frame as current
  546. if( bUseProbe && sm_ulProbeObject!=NONE && (_pGfx->gl_slAllowedUploadBurst<0 || (sm_ulFlags&SMF_PROBED))) {
  547. CTexParams tpTmp = sm_tpLocal;
  548. gfxSetTexture( sm_ulProbeObject, tpTmp);
  549. return;
  550. }
  551. // set non-probe shadowmap and mark that this shadowmap has been drawn
  552. gfxSetTexture( sm_ulObject, sm_tpLocal);
  553. MarkDrawn();
  554. }
  555. // returns used memory - static, dynamic and uploaded size separately, slack space ratio (0-1 float)
  556. // and whether the shadowmap is flat or not
  557. BOOL CShadowMap::GetUsedMemory( SLONG &slStaticSize, SLONG &slDynamicSize, SLONG &slUploadSize, FLOAT &fSlackRatio)
  558. {
  559. const BOOL bFlat = (sm_pulCachedShadowMap==&sm_colFlat);
  560. // determine static portion size
  561. slStaticSize = 0;
  562. if( sm_pulCachedShadowMap!=NULL) slStaticSize = sm_slMemoryUsed;
  563. // determine dynamic portion size
  564. slDynamicSize = 0;
  565. if( sm_pulDynamicShadowMap!=NULL) slDynamicSize = sm_slMemoryUsed;
  566. // determine uploaded portion size
  567. slUploadSize = 0;
  568. const PIX pixMemoryUsed = Max(slStaticSize,slDynamicSize)/BYTES_PER_TEXEL;
  569. if( pixMemoryUsed==0) return bFlat; // done if no memory is used
  570. if( sm_ulObject!=NONE) {
  571. slUploadSize = gfxGetTexturePixRatio(sm_ulObject);
  572. if( !bFlat || slDynamicSize!=0) slUploadSize *= pixMemoryUsed;
  573. }
  574. // determine slack space
  575. const FLOAT fPolySize = sm_pixPolygonSizeU*sm_pixPolygonSizeV;
  576. fSlackRatio = 1.0f - ClampUp( fPolySize*4/3/pixMemoryUsed, 1.0f);
  577. return bFlat;
  578. }