Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1366 lines
43 KiB

  1. >//===== Copyright � 1996-2006, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: The thread which performs lighting preview
  4. //
  5. //===========================================================================//
  6. #include "stdafx.h"
  7. #include "lpreview_thread.h"
  8. #define HAMMER_RAYTRACE
  9. #include "raytrace.h"
  10. #include "hammer.h"
  11. #include "mainfrm.h"
  12. #include "lprvwindow.h"
  13. #include "threadtools.h"
  14. #include "vstdlib/jobthread.h"
  15. #include "mathlib/halton.h"
  16. // memdbgon must be the last include file in a .cpp file!!!
  17. #include <tier0/memdbgon.h>
  18. #define LPREVIEW_MULTITHREAD 1
  19. CInterlockedInt n_gbufs_queued;
  20. CInterlockedInt n_result_bms_queued;
  21. #define NUMBER_OF_LINES_TO_CALCULATE_PER_STEP 8
  22. // the current lighting preview output, if we have one
  23. Bitmap_t * g_pLPreviewOutputBitmap;
  24. IThreadPool *s_pThreadPool;
  25. static class CLightingPreviewThread *s_pThis;
  26. static int s_nNumThreads;
  27. enum IncrementalLightState
  28. {
  29. INCR_STATE_NO_RESULTS = 0, // we threw away the results for this light
  30. INCR_STATE_PARTIAL_RESULTS = 1, // have done some but not all
  31. INCR_STATE_NEW = 2, // we know nothing about this light
  32. INCR_STATE_HAVE_FULL_RESULTS = 3, // we are done
  33. };
  34. class CLightingPreviewThread;
  35. #define MAX_IMAGE_HEIGHT 1024
  36. // attributes for result soa containers
  37. #define RSLT_ATTR_DIFFUSE_RGB 0
  38. #define RSLT_BUFFER_RSLT_RGB 3
  39. #define GBUFFER_ATTR_POSITION 0
  40. #define GBUFFER_ATTR_ALBEDO 1
  41. #define GBUFFER_ATTR_NORMAL 2
  42. class CIncrementalLightInfo
  43. {
  44. public:
  45. CIncrementalLightInfo * m_pNext;
  46. CLightingPreviewLightDescription * m_pLight;
  47. // incremental lighting tracking information
  48. int m_nObjectID;
  49. int m_nNumLinesCalculated;
  50. IncrementalLightState m_eIncrState;
  51. CSOAContainer m_CalculatedContribution;
  52. float m_fTotalContribution; // current magnitude of light effect
  53. float m_flLastContribution; // the last amount added
  54. int m_nBitmapGenerationCounter; // set on receive of new data from master
  55. float m_fDistanceToEye;
  56. int m_nMostRecentNonZeroContributionTimeStamp;
  57. uint8 m_nCalculationLevel[MAX_IMAGE_HEIGHT]; // 0 = not calculated, 1 = calculated at 1:1, etc.
  58. int m_nMaxCalculatedLine;
  59. int m_nFirstCalculatedLine;
  60. bool m_bCreatedIndirectLights;
  61. bool m_bDisabled;
  62. CIncrementalLightInfo( void )
  63. {
  64. m_bDisabled = false;
  65. m_bCreatedIndirectLights = false;
  66. m_nObjectID = - 1;
  67. m_pNext = NULL;
  68. m_eIncrState = INCR_STATE_NEW;
  69. m_fTotalContribution = 0.;
  70. m_flLastContribution = 0.;
  71. m_nNumLinesCalculated = 0;
  72. m_nMostRecentNonZeroContributionTimeStamp = 0;
  73. m_nMaxCalculatedLine = -1;
  74. m_nFirstCalculatedLine = INT_MAX;
  75. memset( m_nCalculationLevel, 0, sizeof( m_nCalculationLevel ) );
  76. }
  77. float PredictedContribution( void ) const;
  78. void SetContributionSize( int nWidth, int nHeight )
  79. {
  80. if ( ( m_CalculatedContribution.NumCols() != nWidth ) || ( m_CalculatedContribution.NumRows() != nHeight ) )
  81. {
  82. m_CalculatedContribution.Purge();
  83. if ( nWidth && nHeight )
  84. {
  85. m_CalculatedContribution.SetAttributeType( RSLT_ATTR_DIFFUSE_RGB, ATTRDATATYPE_4V );
  86. m_CalculatedContribution.AllocateData( nWidth, nHeight );
  87. }
  88. }
  89. }
  90. void DiscardResults( void )
  91. {
  92. m_bDisabled = false;
  93. m_CalculatedContribution.Purge();
  94. memset( m_nCalculationLevel, 0, sizeof( m_nCalculationLevel ) );
  95. m_nMaxCalculatedLine = -1;
  96. m_nFirstCalculatedLine = INT_MAX;
  97. if ( m_eIncrState != INCR_STATE_NEW )
  98. m_eIncrState = INCR_STATE_NO_RESULTS;
  99. m_nNumLinesCalculated = 0;
  100. }
  101. void ClearIncremental( void )
  102. {
  103. m_eIncrState = INCR_STATE_NEW;
  104. // free calculated lighting matrix
  105. DiscardResults();
  106. }
  107. bool HasWorkToDo( void ) const
  108. {
  109. if ( m_bDisabled )
  110. return false;
  111. return ( m_eIncrState != INCR_STATE_HAVE_FULL_RESULTS );
  112. }
  113. bool IsLowerPriorityThan( CLightingPreviewThread * pLPV,
  114. CIncrementalLightInfo const & other ) const;
  115. bool IsHighPriority( CLightingPreviewThread * pLPV ) const;
  116. };
  117. #define N_INCREMENTAL_STEPS 32
  118. class CLightingPreviewThread
  119. {
  120. public:
  121. CUtlIntrusiveList< CLightingPreviewLightDescription > m_LightList;
  122. CSOAContainer m_GBuffer;
  123. CSOAContainer m_GBufferLowRes;
  124. RayTracingEnvironment * m_pRtEnv;
  125. CIncrementalLightInfo * m_pIncrementalLightInfoList;
  126. bool m_bAccStructureBuilt;
  127. Vector m_LastEyePosition;
  128. bool m_bResultChangedSinceLastSend;
  129. float m_fLastSendTime;
  130. int m_nBitmapGenerationCounter;
  131. int m_nContributionCounter;
  132. // bounidng box of the rendered scene+ the eye
  133. Vector m_MinViewCoords;
  134. Vector m_MaxViewCoords;
  135. // sets that we are doing the first update since a discard and should do more lights per pass
  136. bool m_bFirstWork;
  137. CLightingPreviewThread( void )
  138. {
  139. m_nBitmapGenerationCounter = - 1;
  140. m_pRtEnv = NULL;
  141. m_bAccStructureBuilt = false;
  142. m_pIncrementalLightInfoList = NULL;
  143. m_fLastSendTime = - 1.0e6;
  144. m_bResultChangedSinceLastSend = false;
  145. m_nContributionCounter = 1000000;
  146. m_bFirstWork = true;
  147. }
  148. ~CLightingPreviewThread( void )
  149. {
  150. m_LightList.Purge();
  151. while ( m_pIncrementalLightInfoList )
  152. {
  153. CIncrementalLightInfo * n = m_pIncrementalLightInfoList->m_pNext;
  154. delete m_pIncrementalLightInfoList;
  155. m_pIncrementalLightInfoList = n;
  156. }
  157. }
  158. // check if the master has new work for us to do, meaning we should abort rendering
  159. bool ShouldAbort( void )
  160. {
  161. return g_HammerToLPreviewMsgQueue.MessageWaiting();
  162. }
  163. // main loop
  164. void Run( void );
  165. // handle new g-buffers from master
  166. void HandleGBuffersMessage( MessageToLPreview & msg_in );
  167. // accept triangle list from master
  168. void HandleGeomMessage( MessageToLPreview & msg_in );
  169. // send one of our output images back
  170. void SendResultRendering( CSOAContainer &rsltBuffer );
  171. // calculate m_MinViewCoords, m_MaxViewCoords - the bounding box of the rendered pixels+the eye
  172. void CalculateSceneBounds( void );
  173. // inner lighting loop. meant to be multithreaded on dual-core (or more)
  174. void CalculateForLightTask( int nLineStart, int nLineEnd,
  175. CLightingPreviewLightDescription *l,
  176. float * fContributionOut,
  177. CIncrementalLightInfo *pInfremental );
  178. void CalculateForLight( CLightingPreviewLightDescription *l );
  179. // send our current output back
  180. void SendResult( void );
  181. void UpdateIncrementalForNewLightList( void );
  182. void DiscardResults( void )
  183. {
  184. // Warning(" invalidate\n" );
  185. // invalidate all per light result data
  186. for( CIncrementalLightInfo * i = m_pIncrementalLightInfoList; i; i = i->m_pNext )
  187. {
  188. i->DiscardResults();
  189. }
  190. // bump time stamp
  191. m_nContributionCounter++;
  192. // update distances to lights
  193. for( CLightingPreviewLightDescription *l = m_LightList.Head(); l; l = l->m_pNext )
  194. {
  195. CIncrementalLightInfo * l_info = l->m_pIncrementalInfo;
  196. if ( l->m_Type == MATERIAL_LIGHT_DIRECTIONAL )
  197. l_info->m_fDistanceToEye = 0; // high priority
  198. else
  199. l_info->m_fDistanceToEye = m_LastEyePosition.DistTo( l->m_Position );
  200. }
  201. m_bResultChangedSinceLastSend = true;
  202. m_fLastSendTime = Plat_FloatTime() - 12; // force send
  203. m_bFirstWork = true;
  204. }
  205. // handle a message. returns true if the thread shuold exit
  206. bool HandleAMessage( void );
  207. // returns whether or not there is useful work to do
  208. bool AnyUsefulWorkToDo( void );
  209. // do some work, like a rendering for one light
  210. void DoWork( void );
  211. Vector EstimatedUnshotAmbient( void )
  212. {
  213. // return Vector( 1,1,1 );
  214. float sum_weights = 0.0001;
  215. Vector sum_colors( sum_weights, sum_weights, sum_weights );
  216. // calculate an ambient color based on light calculcated so far
  217. for( CLightingPreviewLightDescription *l = m_LightList.Head(); l; l = l->m_pNext )
  218. {
  219. CIncrementalLightInfo * l_info = l->m_pIncrementalInfo;
  220. if ( l_info &&
  221. ( l_info->m_eIncrState == INCR_STATE_HAVE_FULL_RESULTS ) ||
  222. ( l_info->m_eIncrState == INCR_STATE_PARTIAL_RESULTS ) )
  223. {
  224. float flPredictedContribution = l_info->PredictedContribution();
  225. sum_weights += flPredictedContribution;
  226. sum_colors.x += flPredictedContribution * l->m_Color.x;
  227. sum_colors.y += flPredictedContribution * l->m_Color.y;
  228. sum_colors.z += flPredictedContribution * l->m_Color.z;
  229. }
  230. }
  231. sum_colors.NormalizeInPlace();
  232. sum_colors *= 0.05;
  233. return sum_colors;
  234. }
  235. void AccumulateOuput( int nLineMask, CSOAContainer *pResult, CSOAContainer *pLowresResule );
  236. void AddLowresResultToHires( CSOAContainer &lowres, CSOAContainer &hires );
  237. };
  238. bool CIncrementalLightInfo::IsHighPriority( CLightingPreviewThread * pLPV ) const
  239. {
  240. // is this lighjt prioirty-boosted in some way?
  241. if ( m_eIncrState == INCR_STATE_NEW )
  242. {
  243. // uncalculated lights within the view range are highest priority
  244. if ( m_pLight->m_Position.WithinAABox( pLPV->m_MinViewCoords,
  245. pLPV->m_MaxViewCoords ) )
  246. return true;
  247. }
  248. return false;
  249. }
  250. bool CIncrementalLightInfo::IsLowerPriorityThan( CLightingPreviewThread * pLPV,
  251. CIncrementalLightInfo const & other ) const
  252. {
  253. // a NEW light within the view volume is highest priority
  254. bool highpriority = IsHighPriority( pLPV );
  255. bool other_highpriority = other.IsHighPriority( pLPV );
  256. if ( highpriority && ( ! other_highpriority ) )
  257. return false;
  258. if ( other_highpriority && ( ! highpriority ) )
  259. return true;
  260. int state_combo = m_eIncrState + 16 * other.m_eIncrState;
  261. switch ( state_combo )
  262. {
  263. case INCR_STATE_NEW + 16 * INCR_STATE_NEW:
  264. {
  265. // if both are new, closest to eye is best
  266. return ( m_fDistanceToEye > other.m_fDistanceToEye );
  267. }
  268. case INCR_STATE_NEW + 16 * INCR_STATE_NO_RESULTS:
  269. {
  270. // new loses to something we know is probably going to contribute light
  271. return ( other.m_fTotalContribution > 0 );
  272. }
  273. case INCR_STATE_NEW + 16 * INCR_STATE_PARTIAL_RESULTS:
  274. {
  275. return false;
  276. }
  277. case INCR_STATE_PARTIAL_RESULTS + 16 * INCR_STATE_NEW:
  278. {
  279. return true;
  280. }
  281. case INCR_STATE_NO_RESULTS + 16 * INCR_STATE_NEW:
  282. {
  283. // partial or discarded with no brightness loses to new
  284. return ( m_fTotalContribution == 0 );
  285. }
  286. case INCR_STATE_PARTIAL_RESULTS + 16 * INCR_STATE_PARTIAL_RESULTS:
  287. {
  288. // if incrmental vs incremental, and no light from either, do most recently lit one
  289. if ( ( m_fTotalContribution == 0.0 ) && ( other.m_fTotalContribution == 0.0 ) &&
  290. ( other.m_nMostRecentNonZeroContributionTimeStamp > m_nMostRecentNonZeroContributionTimeStamp ) )
  291. return true;
  292. int nMaxLines = max( m_nNumLinesCalculated, other.m_nNumLinesCalculated );
  293. int nMinLines = min( m_nNumLinesCalculated, other.m_nNumLinesCalculated );
  294. // if other is black, and ratios aren't extremely far off, keep this one
  295. if ( nMaxLines <= 16 * nMinLines )
  296. {
  297. if ( ( other.m_fTotalContribution == 0.0 ) && ( m_fTotalContribution > 0 ) )
  298. return false;
  299. if ( ( m_fTotalContribution == 0.0 ) && ( other.m_fTotalContribution > 0 ) )
  300. return true;
  301. }
  302. // if incremental states are close, do brightest
  303. if ( nMaxLines <= 2 * nMinLines )
  304. return ( PredictedContribution() < other.PredictedContribution() );
  305. // else do least refined
  306. return ( m_nNumLinesCalculated > other.m_nNumLinesCalculated );
  307. }
  308. case INCR_STATE_PARTIAL_RESULTS + 16 * INCR_STATE_NO_RESULTS:
  309. {
  310. if ( other.m_fTotalContribution )
  311. return true;
  312. if ( ( m_fTotalContribution == 0.0 ) && ( other.m_fTotalContribution == 0.0 ) )
  313. return ( other.m_nMostRecentNonZeroContributionTimeStamp > m_nMostRecentNonZeroContributionTimeStamp );
  314. return ( PredictedContribution() < other.PredictedContribution() );
  315. }
  316. case INCR_STATE_NO_RESULTS + 16 * INCR_STATE_PARTIAL_RESULTS:
  317. {
  318. if ( m_fTotalContribution )
  319. return false;
  320. if ( ( m_fTotalContribution == 0.0 ) && ( other.m_fTotalContribution == 0.0 ) )
  321. return ( other.m_nMostRecentNonZeroContributionTimeStamp > m_nMostRecentNonZeroContributionTimeStamp );
  322. return ( PredictedContribution() < other.PredictedContribution() );
  323. }
  324. case INCR_STATE_NO_RESULTS * 16 + INCR_STATE_NO_RESULTS:
  325. {
  326. // if incrmental vs discarded, brightest or most recently bright wins
  327. if ( ( m_fTotalContribution == 0.0 ) && ( other.m_fTotalContribution == 0.0 ) )
  328. return ( other.m_nMostRecentNonZeroContributionTimeStamp > m_nMostRecentNonZeroContributionTimeStamp );
  329. return ( PredictedContribution() < other.PredictedContribution() );
  330. }
  331. }
  332. return false;
  333. }
  334. float cg[3]={ 1, 0, 0};
  335. float cr[3]={ 0, 1, 0 };
  336. float cb[3]={ 0, 0, 1 };
  337. void CLightingPreviewThread::HandleGeomMessage( MessageToLPreview & msg_in )
  338. {
  339. if ( m_pRtEnv )
  340. {
  341. delete m_pRtEnv;
  342. m_pRtEnv = NULL;
  343. }
  344. CUtlVector < Vector > & tris = * ( msg_in.m_pShadowTriangleList );
  345. if ( tris.Count() )
  346. {
  347. // FILE *fp = fopen( "c:\\gl.out", "w" );
  348. m_pRtEnv = new RayTracingEnvironment;
  349. for( int i = 0; i < tris.Count(); i += 3 )
  350. {
  351. // fprintf(fp,"3\n");
  352. // for(int j=0;j<3;j++)
  353. // fprintf( fp,"%f %f %f %f %f %f\n", tris[j+i].x,tris[j+i].y,tris[j+i].z, cr[j],cg[j],cb[j] );
  354. m_pRtEnv->AddTriangle( i, tris[i], tris[1 + i], tris[2 + i], Vector( .5, .5, .5 ) );
  355. }
  356. // fclose( fp );
  357. }
  358. delete msg_in.m_pShadowTriangleList;
  359. m_bAccStructureBuilt = false;
  360. DiscardResults();
  361. }
  362. float CIncrementalLightInfo::PredictedContribution( void ) const
  363. {
  364. if ( ( m_fTotalContribution == 0 ) || ( ! m_nNumLinesCalculated ) )
  365. return 0.;
  366. else
  367. return m_fTotalContribution * ( m_CalculatedContribution.NumRows() * ( 1.0 / m_nNumLinesCalculated ) );
  368. }
  369. void CLightingPreviewThread::CalculateSceneBounds( void )
  370. {
  371. FourVectors minbound, maxbound;
  372. minbound.DuplicateVector( m_LastEyePosition );
  373. maxbound.DuplicateVector( m_LastEyePosition );
  374. for( int y = 0; y < m_GBuffer.NumRows(); y++ )
  375. {
  376. FourVectors const *cptr = m_GBuffer.RowPtr<FourVectors>( GBUFFER_ATTR_POSITION, y );
  377. for( int x = 0; x < m_GBuffer.NumQuadsPerRow(); x++ )
  378. {
  379. minbound.x = MinSIMD( cptr->x, minbound.x );
  380. minbound.y = MinSIMD( cptr->y, minbound.y );
  381. minbound.z = MinSIMD( cptr->z, minbound.z );
  382. maxbound.x = MaxSIMD( cptr->x, maxbound.x );
  383. maxbound.y = MaxSIMD( cptr->y, maxbound.y );
  384. maxbound.z = MaxSIMD( cptr->z, maxbound.z );
  385. cptr++;
  386. }
  387. }
  388. m_MinViewCoords = minbound.Vec( 0 );
  389. m_MaxViewCoords = maxbound.Vec( 0 );
  390. for( int v = 1; v < 4; v++ )
  391. {
  392. m_MinViewCoords = m_MinViewCoords.Min( minbound.Vec( v ) );
  393. m_MaxViewCoords = m_MaxViewCoords.Max( maxbound.Vec( v ) );
  394. }
  395. }
  396. void CLightingPreviewThread::UpdateIncrementalForNewLightList( void )
  397. {
  398. for( CLightingPreviewLightDescription *l = m_LightList.Head(); l; l = l->m_pNext )
  399. {
  400. // see if we know about this light
  401. for( CIncrementalLightInfo * i = m_pIncrementalLightInfoList; i; i = i->m_pNext )
  402. {
  403. if ( i->m_nObjectID == l->m_nObjectID )
  404. {
  405. // found it!
  406. l->m_pIncrementalInfo = i;
  407. i->m_pLight = l;
  408. break;
  409. }
  410. }
  411. if ( ! l->m_pIncrementalInfo )
  412. {
  413. l->m_pIncrementalInfo = new CIncrementalLightInfo;
  414. l->m_pIncrementalInfo->m_nObjectID = l->m_nObjectID;
  415. l->m_pIncrementalInfo->m_pLight = l;
  416. // add to list
  417. l->m_pIncrementalInfo->m_pNext = m_pIncrementalLightInfoList;
  418. m_pIncrementalLightInfoList = l->m_pIncrementalInfo;
  419. }
  420. }
  421. }
  422. void CLightingPreviewThread::Run( void )
  423. {
  424. bool should_quit = false;
  425. while( ! should_quit )
  426. {
  427. while (
  428. ( ! should_quit ) &&
  429. ( ( ! AnyUsefulWorkToDo() ) || ( g_HammerToLPreviewMsgQueue.MessageWaiting() ) ) )
  430. should_quit |= HandleAMessage();
  431. if ( ( ! should_quit ) && ( AnyUsefulWorkToDo() ) )
  432. DoWork();
  433. if ( m_bResultChangedSinceLastSend )
  434. {
  435. float newtime = Plat_FloatTime();
  436. if ( ( newtime - m_fLastSendTime > 2.0 ) || ( ! AnyUsefulWorkToDo() ) )
  437. {
  438. SendResult();
  439. }
  440. }
  441. }
  442. }
  443. bool CLightingPreviewThread::HandleAMessage( void )
  444. {
  445. MessageToLPreview msg_in;
  446. g_HammerToLPreviewMsgQueue.WaitMessage( & msg_in );
  447. switch( msg_in.m_MsgType )
  448. {
  449. case LPREVIEW_MSG_EXIT:
  450. return true; // return from thread
  451. case LPREVIEW_MSG_LIGHT_DATA:
  452. {
  453. m_LightList.Purge();
  454. m_LightList = msg_in.m_LightList;
  455. m_LastEyePosition = msg_in.m_EyePosition;
  456. UpdateIncrementalForNewLightList();
  457. DiscardResults();
  458. }
  459. break;
  460. case LPREVIEW_MSG_GEOM_DATA:
  461. HandleGeomMessage( msg_in );
  462. DiscardResults();
  463. break;
  464. case LPREVIEW_MSG_G_BUFFERS:
  465. HandleGBuffersMessage( msg_in );
  466. DiscardResults();
  467. break;
  468. }
  469. return false;
  470. }
  471. bool CLightingPreviewThread::AnyUsefulWorkToDo( void )
  472. {
  473. if ( m_GBuffer.NumRows() )
  474. {
  475. for( CLightingPreviewLightDescription *l = m_LightList.Head(); l; l = l->m_pNext )
  476. {
  477. CIncrementalLightInfo *l_info = l->m_pIncrementalInfo;
  478. if ( l_info->HasWorkToDo() )
  479. return true;
  480. }
  481. }
  482. return false;
  483. }
  484. static void s_CalculateForLight( CLightingPreviewLightDescription * &pLight )
  485. {
  486. s_pThis->CalculateForLight( pLight );
  487. }
  488. void CLightingPreviewThread::DoWork( void )
  489. {
  490. if ( m_pRtEnv && ( ! m_bAccStructureBuilt ) )
  491. {
  492. m_bAccStructureBuilt = true;
  493. m_pRtEnv->SetupAccelerationStructure();
  494. }
  495. CLightingPreviewLightDescription *pLightsToRun[8];
  496. int nNumLightJobs = 0;
  497. int nJobsToDo = s_nNumThreads + 1;
  498. if ( m_bFirstWork )
  499. {
  500. nJobsToDo *= 2;
  501. m_bFirstWork = false;
  502. }
  503. #if LPREVIEW_MULTITHREAD == 0
  504. nJobsToDo = 1;
  505. #endif
  506. for( int i = 0; i < nJobsToDo; i++ )
  507. {
  508. CLightingPreviewLightDescription *best_l = NULL;
  509. CIncrementalLightInfo * best_l_info = NULL;
  510. for( CLightingPreviewLightDescription *l = m_LightList.Head(); l; l = l->m_pNext )
  511. {
  512. CIncrementalLightInfo * l_info = l->m_pIncrementalInfo;
  513. // check if light could influence scene
  514. if ( l_info->m_bDisabled )
  515. continue; // this light can't effect the visible scene
  516. if ( l->m_Type != MATERIAL_LIGHT_DIRECTIONAL )
  517. {
  518. float lrad = l->DistanceAtWhichBrightnessIsLessThan( 1.0 / 500.0 );
  519. if ( ! l->m_Position.WithinAABox( m_MinViewCoords - ReplicateToVector( lrad ),
  520. m_MaxViewCoords + ReplicateToVector( lrad ) ) )
  521. {
  522. l_info->m_bDisabled = true;
  523. }
  524. }
  525. if ( l_info->m_bDisabled )
  526. continue; // this light can't effect the visible scene
  527. // check that we don't have it
  528. bool bHaveit = false;
  529. for( int j = 0; j < nNumLightJobs; j++ )
  530. if ( pLightsToRun[j] == l )
  531. bHaveit = true;
  532. if ( (! bHaveit) && ( l_info->HasWorkToDo() ) )
  533. {
  534. if ( ( ! best_l ) ||
  535. ( best_l->m_pIncrementalInfo->IsLowerPriorityThan( this, *l_info ) ) )
  536. {
  537. best_l_info = l_info;
  538. best_l = l;
  539. }
  540. }
  541. }
  542. if ( best_l )
  543. {
  544. pLightsToRun[nNumLightJobs++] = best_l;
  545. }
  546. }
  547. // now, process in parallel
  548. if ( nNumLightJobs )
  549. {
  550. #if LPREVIEW_MULTITHREAD
  551. ParallelProcess( s_pThreadPool, pLightsToRun, nNumLightJobs, s_CalculateForLight );
  552. #else
  553. for( int i = 0; i < nNumLightJobs; i++ )
  554. {
  555. Warning( "process light %p lnum=%d contribution = %f predicted = %f\n", pLightsToRun[i], pLightsToRun[i]->m_pIncrementalInfo->m_nNumLinesCalculated, pLightsToRun[i]->m_pIncrementalInfo->m_fTotalContribution, pLightsToRun[i]->m_pIncrementalInfo->PredictedContribution() );
  556. s_CalculateForLight( pLightsToRun[i] );
  557. }
  558. #endif
  559. // now, some lights may have created lights for indirect light. We must move these to the global list.
  560. // we could not do this while creating them, because of thread-safety.
  561. for( int i = 0; i < nNumLightJobs; i++ )
  562. {
  563. if ( pLightsToRun[i]->m_pIncrementalInfo->m_flLastContribution )
  564. {
  565. m_bResultChangedSinceLastSend = true;
  566. }
  567. for( int j = 0; j < pLightsToRun[i]->m_TempChildren.Count(); j++ )
  568. {
  569. CLightingPreviewLightDescription *pNew = pLightsToRun[i]->m_TempChildren[j];
  570. pNew->m_pIncrementalInfo = new CIncrementalLightInfo;
  571. pNew->m_pIncrementalInfo->m_nObjectID = pNew->m_nObjectID;
  572. pNew->m_pIncrementalInfo->m_pLight = pNew;
  573. pNew->m_pIncrementalInfo->m_pNext = m_pIncrementalLightInfoList;
  574. m_pIncrementalLightInfoList = pNew->m_pIncrementalInfo;
  575. m_LightList.AddToTail( pNew );
  576. }
  577. pLightsToRun[i]->m_TempChildren.Purge();
  578. pLightsToRun[i]->m_bDidIndirect = true;
  579. }
  580. }
  581. }
  582. void CLightingPreviewThread::HandleGBuffersMessage( MessageToLPreview & msg_in )
  583. {
  584. m_GBuffer.Purge();
  585. m_GBuffer.SetAttributeType( GBUFFER_ATTR_POSITION, ATTRDATATYPE_4V );
  586. m_GBuffer.SetAttributeType( GBUFFER_ATTR_ALBEDO, ATTRDATATYPE_4V );
  587. m_GBuffer.SetAttributeType( GBUFFER_ATTR_NORMAL, ATTRDATATYPE_4V );
  588. m_GBuffer.AllocateData( msg_in.m_pDefferedRenderingBMs[0]->NumCols(),
  589. msg_in.m_pDefferedRenderingBMs[0]->NumRows() );
  590. m_GBuffer.PackScalarAttributesToVectorAttribute( msg_in.m_pDefferedRenderingBMs[0],
  591. GBUFFER_ATTR_ALBEDO,
  592. FBM_ATTR_RED, FBM_ATTR_GREEN, FBM_ATTR_BLUE );
  593. m_GBuffer.PackScalarAttributesToVectorAttribute( msg_in.m_pDefferedRenderingBMs[1],
  594. GBUFFER_ATTR_NORMAL,
  595. FBM_ATTR_RED, FBM_ATTR_GREEN, FBM_ATTR_BLUE );
  596. m_GBuffer.PackScalarAttributesToVectorAttribute( msg_in.m_pDefferedRenderingBMs[2],
  597. GBUFFER_ATTR_POSITION,
  598. FBM_ATTR_RED, FBM_ATTR_GREEN, FBM_ATTR_BLUE );
  599. m_GBufferLowRes.Purge();
  600. m_GBufferLowRes.SetAttributeType( GBUFFER_ATTR_POSITION, ATTRDATATYPE_4V );
  601. m_GBufferLowRes.SetAttributeType( GBUFFER_ATTR_ALBEDO, ATTRDATATYPE_4V );
  602. m_GBufferLowRes.SetAttributeType( GBUFFER_ATTR_NORMAL, ATTRDATATYPE_4V );
  603. m_GBufferLowRes.AllocateData( msg_in.m_pDefferedRenderingBMs[0]->NumCols() / 4,
  604. msg_in.m_pDefferedRenderingBMs[0]->NumRows() / 4 );
  605. // now, downsample
  606. m_GBufferLowRes.ResampleAttribute( m_GBuffer, GBUFFER_ATTR_POSITION );
  607. m_GBufferLowRes.ResampleAttribute( m_GBuffer, GBUFFER_ATTR_ALBEDO );
  608. m_GBufferLowRes.ResampleAttribute( m_GBuffer, GBUFFER_ATTR_NORMAL );
  609. m_LastEyePosition = msg_in.m_EyePosition;
  610. for( int i = 0;i < ARRAYSIZE( msg_in.m_pDefferedRenderingBMs ); i++ )
  611. delete msg_in.m_pDefferedRenderingBMs[i];
  612. n_gbufs_queued--;
  613. m_nBitmapGenerationCounter = msg_in.m_nBitmapGenerationCounter;
  614. CalculateSceneBounds();
  615. }
  616. void CLightingPreviewThread::AccumulateOuput( int nLineMask, CSOAContainer *rslt, CSOAContainer *rslt1 )
  617. {
  618. for( CLightingPreviewLightDescription *l = m_LightList.Head(); l; l = l->m_pNext )
  619. {
  620. CSOAContainer *pRslt = rslt;
  621. CSOAContainer *pGB = &m_GBuffer;
  622. if ( l->m_bLowRes )
  623. {
  624. pGB = &m_GBufferLowRes;
  625. pRslt = rslt1;
  626. }
  627. CIncrementalLightInfo * l_info = l->m_pIncrementalInfo;
  628. if ( ( l_info->m_fTotalContribution > 0.0 ) &&
  629. ( l_info->m_eIncrState >= INCR_STATE_PARTIAL_RESULTS ) )
  630. {
  631. // need to add partials, replicated to handle undone lines
  632. CSOAContainer &src = l_info->m_CalculatedContribution;
  633. int nY0 = l_info->m_nFirstCalculatedLine;
  634. int nY1 = nY0;
  635. // scan forward to find the next calculated line, if any
  636. while ( nY1 < l_info->m_nMaxCalculatedLine )
  637. {
  638. nY1++;
  639. if ( l_info->m_nCalculationLevel[nY1] )
  640. break;
  641. }
  642. fltx4 fl4NormalFactorScale = ReplicateX4( 4.0f );
  643. fltx4 fl4NormalBias = ReplicateX4( 0.0f ); //1.01 ); // prevent 0.
  644. for( int y = 0; y < pGB->NumRows(); y++ )
  645. {
  646. if ( nLineMask & ( 1 << ( y & 31 ) ) )
  647. {
  648. fltx4 fl4Weights[2];
  649. if ( ( y < nY0 ) || ( nY0 == nY1 ) )
  650. {
  651. fl4Weights[0] = Four_Ones;
  652. fl4Weights[1] = Four_Zeros;
  653. }
  654. else
  655. {
  656. fl4Weights[1] = ReplicateX4( ( y - nY0 ) * ( 1.0 / ( nY1 - nY0 ) ) );
  657. fl4Weights[0] = SubSIMD( Four_Ones, fl4Weights[1] );
  658. }
  659. FourVectors *pRslts[2];
  660. pRslts[0] = src.RowPtr<FourVectors>( RSLT_ATTR_DIFFUSE_RGB, nY0 );
  661. pRslts[1] = src.RowPtr<FourVectors>( RSLT_ATTR_DIFFUSE_RGB, nY1 );
  662. FourVectors *dest = pRslt->RowPtr<FourVectors>( RSLT_BUFFER_RSLT_RGB, y);
  663. FourVectors const * pNormal = pGB->RowPtr<FourVectors>( GBUFFER_ATTR_NORMAL, y );
  664. FourVectors const * pRsltNormals[2];
  665. pRsltNormals[0] = pGB->RowPtr<FourVectors>( GBUFFER_ATTR_NORMAL, nY0 );
  666. pRsltNormals[1] = pGB->RowPtr<FourVectors>( GBUFFER_ATTR_NORMAL, nY1 );
  667. FourVectors const * pCoord = pGB->RowPtr<FourVectors>( GBUFFER_ATTR_POSITION, y );
  668. FourVectors const * pCoords[2];
  669. pCoords[0] = pGB->RowPtr<FourVectors>( GBUFFER_ATTR_POSITION, nY0 );
  670. pCoords[1] = pGB->RowPtr<FourVectors>( GBUFFER_ATTR_POSITION, nY1 );
  671. fltx4 fl4DistanceScale = ReplicateX4( 1.0 / 36.0 );
  672. for( int x = 0; x < pGB->NumQuadsPerRow(); x++ )
  673. {
  674. FourVectors l1 = *( pRslts[1]++ );
  675. fltx4 fl4Dot = ( *pRsltNormals[1]++ ) * ( *pNormal );
  676. fl4Dot = MaxSIMD( Four_Epsilons,
  677. MulSIMD( fl4NormalFactorScale, AddSIMD( fl4NormalBias, fl4Dot ) ) );
  678. FourVectors fl4Delta = *( pCoords[1]++ );
  679. fl4Delta -= *pCoord;
  680. fltx4 fl4Distance = fl4Delta.length();
  681. fl4Distance = ReciprocalEstSIMD( AddSIMD( Four_Ones, MulSIMD( fl4Distance, fl4DistanceScale ) ) );
  682. fltx4 fl4SumWeights = MulSIMD( fl4Distance, MulSIMD( fl4Weights[1], fl4Dot ) );
  683. l1 *= fl4SumWeights;
  684. fl4Dot = ( *pRsltNormals[0]++ ) * ( *pNormal++ );
  685. fl4Dot = MaxSIMD( Four_Epsilons,
  686. MulSIMD( fl4NormalFactorScale, AddSIMD( fl4NormalBias, fl4Dot ) ) );
  687. fl4Delta = *( pCoords[0]++ );
  688. fl4Delta -= *pCoord;
  689. fl4Distance = fl4Delta.length();
  690. pCoord++;
  691. fl4Distance = ReciprocalEstSIMD( AddSIMD( Four_Ones, MulSIMD( fl4Distance, fl4DistanceScale ) ) );
  692. FourVectors l2 = *( pRslts[0]++ );
  693. fltx4 w0 = MulSIMD( fl4Distance, MulSIMD( fl4Dot, fl4Weights[0] ) );
  694. l2 *= w0;
  695. l1 += l2;
  696. fl4SumWeights = AddSIMD( fl4SumWeights, w0 );
  697. l1 *= ReciprocalSIMD( fl4SumWeights );
  698. * ( dest++ ) += l1;
  699. }
  700. }
  701. // now, update line indices
  702. if ( y >= nY1 )
  703. {
  704. nY0 = nY1;
  705. while ( nY1 < l_info->m_nMaxCalculatedLine )
  706. {
  707. nY1++;
  708. if ( l_info->m_nCalculationLevel[nY1] )
  709. break;
  710. }
  711. }
  712. }
  713. }
  714. }
  715. }
  716. static CSOAContainer *s_pResultBuffer;
  717. static CSOAContainer *s_pResultBuffer1;
  718. void s_AccumulateOutput( int &nLineMask )
  719. {
  720. s_pThis->AccumulateOuput( nLineMask, s_pResultBuffer, s_pResultBuffer1 );
  721. }
  722. #define GRAB4PIXELS( base ) \
  723. base##AAAA.x = SplatXSIMD( base##ShiftRegister0.x ); \
  724. base##AAAA.y = SplatXSIMD( base##ShiftRegister0.y ); \
  725. base##AAAA.z = SplatXSIMD( base##ShiftRegister0.z ); \
  726. base##BBBB.x = SplatYSIMD( base##ShiftRegister0.x ); \
  727. base##BBBB.y = SplatYSIMD( base##ShiftRegister0.y ); \
  728. base##BBBB.z = SplatYSIMD( base##ShiftRegister0.z ); \
  729. RotateLeftDoubleSIMD( base##ShiftRegister0.x, base##ShiftRegister0a.x ); \
  730. RotateLeftDoubleSIMD( base##ShiftRegister0.y, base##ShiftRegister0a.y ); \
  731. RotateLeftDoubleSIMD( base##ShiftRegister0.z, base##ShiftRegister0a.z ); \
  732. base##EEEE.x = SplatXSIMD( base##ShiftRegister1.x ); \
  733. base##EEEE.y = SplatXSIMD( base##ShiftRegister1.y ); \
  734. base##EEEE.z = SplatXSIMD( base##ShiftRegister1.z ); \
  735. base##FFFF.x = SplatYSIMD( base##ShiftRegister1.x ); \
  736. base##FFFF.y = SplatYSIMD( base##ShiftRegister1.y ); \
  737. base##FFFF.z = SplatYSIMD( base##ShiftRegister1.z ); \
  738. RotateLeftDoubleSIMD( base##ShiftRegister1.x, base##ShiftRegister1a.x ); \
  739. RotateLeftDoubleSIMD( base##ShiftRegister1.y, base##ShiftRegister1a.y ); \
  740. RotateLeftDoubleSIMD( base##ShiftRegister1.z, base##ShiftRegister1a.z );
  741. void CLightingPreviewThread::AddLowresResultToHires( CSOAContainer &lores, CSOAContainer &hires )
  742. {
  743. // we will bilaterally upsample lowres and add it to hires. This is coded for the specific case of a 4x4 downsamping
  744. fltx4 fl4NormalFactorScale = ReplicateX4( 4.0f );
  745. fltx4 fl4NormalBias = ReplicateX4( 0.0f ); //1.01 ); // prevent 0.
  746. fltx4 fl4DistanceScale = ReplicateX4( 1.0 / 36.0 );
  747. Assert( lores.NumRows() == m_GBufferLowRes.NumRows() );
  748. Assert( lores.NumCols() == m_GBufferLowRes.NumCols() );
  749. for( int y = 0; y < hires.NumRows(); y++ )
  750. {
  751. int ysrc0 = min( ( y >> 2 ), lores.NumRows() -1 );
  752. int ysrc1 = min( ysrc0 + 1, lores.NumRows() - 1 );
  753. int nIterations = hires.NumQuadsPerRow();
  754. int numFetches = lores.NumQuadsPerRow();
  755. FourVectors *pSrc0 = lores.RowPtr<FourVectors>( RSLT_BUFFER_RSLT_RGB, ysrc0 );
  756. FourVectors *pSrc1 = lores.RowPtr<FourVectors>( RSLT_BUFFER_RSLT_RGB, ysrc1 );
  757. FourVectors rsltShiftRegister0 = *( pSrc0++ );
  758. FourVectors rsltShiftRegister0a;
  759. FourVectors rsltShiftRegister1 = *( pSrc1++ );
  760. FourVectors rsltShiftRegister1a;
  761. FourVectors *pSrcNormal0 = m_GBufferLowRes.RowPtr<FourVectors>( GBUFFER_ATTR_NORMAL, ysrc0 );
  762. FourVectors *pSrcNormal1 = m_GBufferLowRes.RowPtr<FourVectors>( GBUFFER_ATTR_NORMAL, ysrc1 );
  763. FourVectors normShiftRegister0 = *( pSrcNormal0++ );
  764. FourVectors normShiftRegister0a;
  765. FourVectors normShiftRegister1 = *( pSrcNormal1++ );
  766. FourVectors normShiftRegister1a;
  767. FourVectors *pSrcPos0 = m_GBufferLowRes.RowPtr<FourVectors>( GBUFFER_ATTR_POSITION, ysrc0 );
  768. FourVectors *pSrcPos1 = m_GBufferLowRes.RowPtr<FourVectors>( GBUFFER_ATTR_POSITION, ysrc1 );
  769. FourVectors posShiftRegister0 = *( pSrcPos0++ );
  770. FourVectors posShiftRegister0a;
  771. FourVectors posShiftRegister1 = *( pSrcPos1++ );
  772. FourVectors posShiftRegister1a;
  773. FourVectors *pDest = hires.RowPtr<FourVectors>( RSLT_BUFFER_RSLT_RGB, y );
  774. FourVectors *pDestNormal = m_GBuffer.RowPtr<FourVectors>( GBUFFER_ATTR_NORMAL, y );
  775. FourVectors *pDestPos = m_GBuffer.RowPtr<FourVectors>( GBUFFER_ATTR_POSITION, y );
  776. numFetches--;
  777. for( int x = 0; x < nIterations; x++ )
  778. {
  779. if ( ( ( x & 3 ) == 0 ) && numFetches ) // need to fetch new data every 4 outputs
  780. {
  781. numFetches--;
  782. rsltShiftRegister0a = *( pSrc0++ );
  783. rsltShiftRegister1a = *( pSrc1++ );
  784. normShiftRegister0a = *( pSrcNormal0++ );
  785. normShiftRegister1a = *( pSrcNormal1++ );
  786. posShiftRegister0a = *( pSrcPos0++ );
  787. posShiftRegister1a = *( pSrcPos1++ );
  788. }
  789. FourVectors rsltAAAA, rsltBBBB, rsltEEEE, rsltFFFF;
  790. GRAB4PIXELS( rslt );
  791. FourVectors normAAAA, normBBBB, normEEEE, normFFFF;
  792. GRAB4PIXELS( norm );
  793. FourVectors posAAAA, posBBBB, posEEEE, posFFFF;
  794. GRAB4PIXELS( pos );
  795. // we should now be ready to filter. We will take the 4 pixels we have, and produce 4 output pixels
  796. FourVectors dNorm = *( pDestNormal++ );
  797. fltx4 fl4ADot = MaxSIMD( Four_Epsilons, MulSIMD( fl4NormalFactorScale, AddSIMD( fl4NormalBias, dNorm * normAAAA ) ) );
  798. fltx4 fl4BDot = MaxSIMD( Four_Epsilons, MulSIMD( fl4NormalFactorScale, AddSIMD( fl4NormalBias, dNorm * normBBBB ) ) );
  799. fltx4 fl4EDot = MaxSIMD( Four_Epsilons, MulSIMD( fl4NormalFactorScale, AddSIMD( fl4NormalBias, dNorm * normEEEE ) ) );
  800. fltx4 fl4FDot = MaxSIMD( Four_Epsilons, MulSIMD( fl4NormalFactorScale, AddSIMD( fl4NormalBias, dNorm * normFFFF ) ) );
  801. FourVectors fl4Pos = *( pDestPos++ );
  802. FourVectors v4Delta = posAAAA;
  803. v4Delta -= fl4Pos;
  804. fltx4 fl4WA =
  805. MulSIMD( fl4ADot, ReciprocalEstSIMD( AddSIMD( Four_Ones, MulSIMD( v4Delta.length(), fl4DistanceScale ) ) ) );
  806. v4Delta = posBBBB;
  807. v4Delta -= fl4Pos;
  808. fltx4 fl4WB =
  809. MulSIMD( fl4BDot, ReciprocalEstSIMD( AddSIMD( Four_Ones, MulSIMD( v4Delta.length(), fl4DistanceScale ) ) ) );
  810. v4Delta = posEEEE;
  811. v4Delta -= fl4Pos;
  812. fltx4 fl4WE =
  813. MulSIMD( fl4EDot, ReciprocalEstSIMD( AddSIMD( Four_Ones, MulSIMD( v4Delta.length(), fl4DistanceScale ) ) ) );
  814. v4Delta = posFFFF;
  815. v4Delta -= fl4Pos;
  816. fltx4 fl4WF =
  817. MulSIMD( fl4FDot, ReciprocalEstSIMD( AddSIMD( Four_Ones, MulSIMD( v4Delta.length(), fl4DistanceScale ) ) ) );
  818. fltx4 fl4OOSumWeights = ReciprocalSIMD( AddSIMD( AddSIMD( fl4WA, fl4WB ), AddSIMD( fl4WE, fl4WF ) ) );
  819. // now, calculate the output color
  820. FourVectors out = rsltAAAA;
  821. out *= fl4WA;
  822. FourVectors out1 = rsltBBBB;
  823. out1 *= fl4WB;
  824. out += out1;
  825. out1 = rsltEEEE;
  826. out1 *= fl4WE;
  827. out += out1;
  828. out1 = rsltFFFF;
  829. out1 *= fl4WF;
  830. out += out1;
  831. out *= fl4OOSumWeights;
  832. *( pDest++ ) += out;
  833. }
  834. }
  835. }
  836. void CLightingPreviewThread::SendResult( void )
  837. {
  838. if ( m_GBuffer.NumRows() && m_GBuffer.NumCols() )
  839. {
  840. // Warning("send\n");
  841. CSOAContainer rsltBuffer;
  842. rsltBuffer.SetAttributeType( RSLT_BUFFER_RSLT_RGB, ATTRDATATYPE_4V );
  843. rsltBuffer.AllocateData( m_GBuffer.NumCols(), m_GBuffer.NumRows() );
  844. rsltBuffer.FillAttr( RSLT_BUFFER_RSLT_RGB, EstimatedUnshotAmbient() );
  845. s_pResultBuffer = &rsltBuffer;
  846. bool bDidLoRes = false;
  847. for( CLightingPreviewLightDescription *l = m_LightList.Head(); l; l = l->m_pNext )
  848. {
  849. if ( l->m_bLowRes )
  850. bDidLoRes = true;
  851. }
  852. CSOAContainer rsltBuffer1;
  853. rsltBuffer1.SetAttributeType( RSLT_BUFFER_RSLT_RGB, ATTRDATATYPE_4V );
  854. rsltBuffer1.AllocateData( m_GBufferLowRes.NumCols(), m_GBufferLowRes.NumRows() );
  855. if ( bDidLoRes )
  856. {
  857. rsltBuffer1.FillAttr( RSLT_BUFFER_RSLT_RGB, Vector( 0, 0, 0 ) );
  858. }
  859. s_pResultBuffer1 = &rsltBuffer1;
  860. int nProcessMasks[32];
  861. for( int i = 0; i < 32; i++ )
  862. nProcessMasks[i] = ( 1 << i );
  863. ParallelProcess( s_pThreadPool, nProcessMasks, 32, s_AccumulateOutput );
  864. if ( bDidLoRes )
  865. AddLowresResultToHires( rsltBuffer1, rsltBuffer );
  866. // now, multiply by albedo
  867. rsltBuffer.MulAttr( m_GBuffer, GBUFFER_ATTR_ALBEDO, RSLT_BUFFER_RSLT_RGB );
  868. SendResultRendering( rsltBuffer );
  869. m_fLastSendTime = Plat_FloatTime();
  870. m_bResultChangedSinceLastSend = false;
  871. }
  872. }
  873. void CLightingPreviewThread::CalculateForLightTask( int nLineStart, int nLineEnd,
  874. CLightingPreviewLightDescription *l,
  875. float *fContributionOut,
  876. CIncrementalLightInfo *pLInfo )
  877. {
  878. FourVectors zero_vector;
  879. zero_vector.x = Four_Zeros;
  880. zero_vector.y = Four_Zeros;
  881. zero_vector.z = Four_Zeros;
  882. FourVectors total_light = zero_vector;
  883. CIncrementalLightInfo * l_info = l->m_pIncrementalInfo;
  884. CSOAContainer &rslt = l_info->m_CalculatedContribution;
  885. // figure out what lines to do
  886. fltx4 ThresholdBrightness = ReplicateX4( 0.1 / 1024.0 );
  887. FourVectors LastLinesTotalLight = zero_vector;
  888. // calculate jitter stuff
  889. fltx4 fl4RandRange = ReplicateX4( l->m_flJitterAmount );
  890. bool bJitter = l->m_flJitterAmount > 0.0;
  891. int nCtx = GetSIMDRandContext();
  892. CSOAContainer *pGB = ( l->m_bLowRes ) ? &m_GBufferLowRes : &m_GBuffer;
  893. for( int idx = nLineStart; idx <= nLineEnd; idx++ )
  894. {
  895. int y = InsideOut( rslt.NumRows(), idx );
  896. FourVectors ThisLinesTotalLight = zero_vector;
  897. FourVectors *pDataOut = rslt.RowPtr<FourVectors>( RSLT_ATTR_DIFFUSE_RGB, y );
  898. FourVectors *pAlbedo = pGB->RowPtr<FourVectors>( GBUFFER_ATTR_ALBEDO, y );
  899. FourVectors *pPos = pGB->RowPtr<FourVectors>( GBUFFER_ATTR_POSITION, y );
  900. FourVectors *pNormal = pGB->RowPtr<FourVectors>( GBUFFER_ATTR_NORMAL, y );
  901. for( int x = 0; x < rslt.NumQuadsPerRow(); x++ )
  902. {
  903. // shadow check
  904. FourVectors pos = *( pPos++ );
  905. FourVectors normal = *( pNormal++ );
  906. FourVectors l_add = zero_vector;
  907. l->ComputeLightAtPoints( pos, normal, l_add, false );
  908. fltx4 v_or = OrSIMD( l_add.x, OrSIMD( l_add.y, l_add.z ) );
  909. if ( ! IsAllZeros( v_or ) )
  910. {
  911. FourVectors lpos;
  912. lpos.DuplicateVector( l->m_Position );
  913. // jitter light position
  914. if ( bJitter )
  915. {
  916. lpos.x =
  917. AddSIMD( lpos.x, MulSIMD( fl4RandRange, SubSIMD( MulSIMD( Four_Twos, RandSIMD( nCtx ) ), Four_Ones ) ) );
  918. lpos.y =
  919. AddSIMD( lpos.y, MulSIMD( fl4RandRange, SubSIMD( MulSIMD( Four_Twos, RandSIMD( nCtx ) ), Four_Ones ) ) );
  920. lpos.z =
  921. AddSIMD( lpos.z, MulSIMD( fl4RandRange, SubSIMD( MulSIMD( Four_Twos, RandSIMD( nCtx ) ), Four_Ones ) ) );
  922. }
  923. FourRays myray;
  924. myray.direction = lpos;
  925. myray.direction -= pos;
  926. fltx4 len = myray.direction.length();
  927. myray.direction *= ReciprocalSIMD( len );
  928. // slide towards light to avoid self-intersection
  929. myray.origin = myray.direction;
  930. myray.origin *= 0.02;
  931. myray.origin += pos;
  932. RayTracingResult r_rslt;
  933. m_pRtEnv->Trace4Rays( myray, Four_Zeros, ReplicateX4( 1.0e9 ), & r_rslt );
  934. for( int c = 0; c < 4; c++ ) // !!speed!! use sse logic ops here
  935. {
  936. if ( ( r_rslt.HitIds[c] != - 1 ) &&
  937. ( r_rslt.HitDistance.m128_f32[c] < len.m128_f32[c] ) )
  938. {
  939. l_add.x.m128_f32[c]= 0.0;
  940. l_add.y.m128_f32[c]= 0.0;
  941. l_add.z.m128_f32[c]= 0.0;
  942. }
  943. }
  944. *( pDataOut ) = l_add;
  945. l_add *= *(pAlbedo );
  946. // now, supress brightness < threshold so as to not falsely think
  947. // far away lights are interesting
  948. l_add.x = AndSIMD( l_add.x, CmpGtSIMD( l_add.x, ThresholdBrightness ) );
  949. l_add.y = AndSIMD( l_add.y, CmpGtSIMD( l_add.y, ThresholdBrightness ) );
  950. l_add.z = AndSIMD( l_add.z, CmpGtSIMD( l_add.z, ThresholdBrightness ) );
  951. ThisLinesTotalLight += l_add;
  952. }
  953. else
  954. *( pDataOut ) = l_add;
  955. pDataOut++;
  956. pAlbedo++;
  957. }
  958. pLInfo->m_nCalculationLevel[y] = 1;
  959. pLInfo->m_nMaxCalculatedLine = max( y, pLInfo->m_nMaxCalculatedLine );
  960. pLInfo->m_nFirstCalculatedLine = min( y, pLInfo->m_nFirstCalculatedLine );
  961. total_light += ThisLinesTotalLight;
  962. }
  963. ReleaseSIMDRandContext( nCtx );
  964. fltx4 lmag = total_light.length();
  965. * ( fContributionOut ) = lmag.m128_f32[0]+ lmag.m128_f32[1]+ lmag.m128_f32[2]+ lmag.m128_f32[3];
  966. }
  967. #define N_FAKE_LIGHTS_FOR_INDIRECT 50
  968. void CLightingPreviewThread::CalculateForLight( CLightingPreviewLightDescription *l )
  969. {
  970. if ( ! l->m_bDidIndirect )
  971. {
  972. // create a bunch of pseudo lights for this light
  973. float lrad = l->DistanceAtWhichBrightnessIsLessThan( 1.0 / 500.0 );
  974. RayTracingSingleResult rslts[N_FAKE_LIGHTS_FOR_INDIRECT];
  975. Vector rayDirs[N_FAKE_LIGHTS_FOR_INDIRECT];
  976. DirectionalSampler_t sampler;
  977. RayStream myStream;
  978. Vector rayStart = l->m_Position;
  979. for( int i = 0; i < N_FAKE_LIGHTS_FOR_INDIRECT; i++ )
  980. {
  981. rayDirs[i] = sampler.NextValue();
  982. m_pRtEnv->AddToRayStream( myStream, rayStart, rayStart + lrad * rayDirs[i], rslts + i );
  983. }
  984. m_pRtEnv->FinishRayStream( myStream);
  985. // now, we have a bunch of raytracing results
  986. for( int i = 0; i < N_FAKE_LIGHTS_FOR_INDIRECT; i++ )
  987. {
  988. if ( rslts[i].HitID != -1 ) // hit something
  989. {
  990. Vector vecHitPos = rayStart + rslts[i].HitDistance * rayDirs[i];
  991. FourVectors v4Pnt;
  992. v4Pnt.DuplicateVector( vecHitPos );
  993. FourVectors v4Normal;
  994. v4Normal.DuplicateVector( rslts[i].surface_normal );
  995. FourVectors v4Color;
  996. l->ComputeLightAtPoints( v4Pnt, v4Normal, v4Color );
  997. Vector vecColorToShoot = v4Color.Vec( 0 ) * 0.25 / N_FAKE_LIGHTS_FOR_INDIRECT;
  998. if ( vecColorToShoot.Length() > 1/255.0 )
  999. {
  1000. CLightingPreviewLightDescription *pNew = new CLightingPreviewLightDescription;
  1001. pNew->Init( 0xf0000000 );
  1002. pNew->m_Position = vecHitPos + rslts[i].surface_normal * 2;
  1003. pNew->m_Type = MATERIAL_LIGHT_SPOT;
  1004. pNew->m_Color = vecColorToShoot;
  1005. pNew->m_Direction = rslts[i].surface_normal;
  1006. pNew->m_Theta = 0;
  1007. pNew->m_Phi = M_PI;
  1008. pNew->RecalculateDerivedValues();
  1009. pNew->m_Falloff = 5.0;
  1010. pNew->m_Range = 0.;
  1011. pNew->m_Attenuation0 = 0;
  1012. pNew->m_Attenuation1 = 0;
  1013. pNew->m_Attenuation2 = 1;
  1014. pNew->m_bDidIndirect = true;
  1015. l->m_TempChildren.AddToTail( pNew );
  1016. }
  1017. }
  1018. }
  1019. l->m_bDidIndirect = true;
  1020. }
  1021. CIncrementalLightInfo * l_info = l->m_pIncrementalInfo;
  1022. CSOAContainer *pGB = &m_GBuffer;
  1023. if ( l->m_bLowRes )
  1024. pGB = &m_GBufferLowRes;
  1025. l_info->SetContributionSize( pGB->NumCols(), pGB->NumRows() );
  1026. // figure out which lines need to be calculated
  1027. int nStartIteration = l_info->m_nNumLinesCalculated;
  1028. int nEndIteration =
  1029. min( l_info->m_nNumLinesCalculated + NUMBER_OF_LINES_TO_CALCULATE_PER_STEP, pGB->NumRows() - 1 );
  1030. float total_light;
  1031. CalculateForLightTask( nStartIteration, nEndIteration, l, &total_light, l_info );
  1032. l_info->m_flLastContribution = total_light;
  1033. l_info->m_fTotalContribution += total_light;
  1034. // throw away light array if no contribution ?????
  1035. if ( l_info->m_fTotalContribution == 0.0 )
  1036. l_info->m_CalculatedContribution.Purge();
  1037. else
  1038. {
  1039. l_info->m_nMostRecentNonZeroContributionTimeStamp = m_nContributionCounter;
  1040. }
  1041. l_info->m_nNumLinesCalculated = nEndIteration + 1;
  1042. if ( nEndIteration == pGB->NumRows() - 1 )
  1043. l_info->m_eIncrState = INCR_STATE_HAVE_FULL_RESULTS;
  1044. else
  1045. l_info->m_eIncrState = INCR_STATE_PARTIAL_RESULTS;
  1046. }
  1047. void CLightingPreviewThread::SendResultRendering( CSOAContainer &rsltBuffer )
  1048. {
  1049. Bitmap_t *ret_bm = new Bitmap_t;
  1050. #if 0
  1051. ret_bm->Init( m_GBuffer.NumCols(), m_GBuffer.NumRows(), IMAGE_FORMAT_RGBA8888 );
  1052. // lets copy into the output bitmap
  1053. for( int y = 0; y < ret_bm->m_nHeight; y++ )
  1054. {
  1055. float const *pRGBData = m_GBuffer.RowPtr<float>( GBUFFER_ATTR_NORMAL, y );
  1056. for( int x = 0; x < ret_bm->m_nWidth; x++ )
  1057. {
  1058. Vector color;
  1059. color.Init( 0.5 + 0.5 * pRGBData[0] , 0.5 + 0.5 * pRGBData[4], 0.5 + 0.5 * pRGBData[8] );
  1060. * ( ret_bm->GetPixel( x, y ) + 0 ) = ( uint8 ) min( 255, ( 255.0 * pow( color.z, ( float ) ( 1 / 2.2 ) ) ) );
  1061. * ( ret_bm->GetPixel( x, y ) + 1 ) = ( uint8 ) min( 255, ( 255.0 * pow( color.y, ( float ) ( 1 / 2.2 ) ) ) );
  1062. * ( ret_bm->GetPixel( x, y ) + 2 ) = ( uint8 ) min( 255, ( 255.0 * pow( color.x, ( float ) ( 1 / 2.2 ) ) ) );
  1063. * ( ret_bm->GetPixel( x, y ) + 3 ) = 0;
  1064. pRGBData++;
  1065. if ( ( x & 3 ) == 3 )
  1066. pRGBData += 8;
  1067. }
  1068. }
  1069. #else
  1070. ret_bm->Init( rsltBuffer.NumCols(), rsltBuffer.NumRows(), IMAGE_FORMAT_RGBA8888 );
  1071. // lets copy into the output bitmap
  1072. for( int y = 0; y < ret_bm->Height(); y++ )
  1073. {
  1074. float const *pRGBData = rsltBuffer.RowPtr<float>( RSLT_BUFFER_RSLT_RGB, y );
  1075. for( int x = 0; x < ret_bm->Width(); x++ )
  1076. {
  1077. Vector color;
  1078. color.Init( pRGBData[0], pRGBData[4], pRGBData[8] );
  1079. * ( ret_bm->GetPixel( x, y ) + 0 ) = ( uint8 ) min( 255, ( 255.0 * pow( color.z, ( float ) ( 1 / 2.2 ) ) ) );
  1080. * ( ret_bm->GetPixel( x, y ) + 1 ) = ( uint8 ) min( 255, ( 255.0 * pow( color.y, ( float ) ( 1 / 2.2 ) ) ) );
  1081. * ( ret_bm->GetPixel( x, y ) + 2 ) = ( uint8 ) min( 255, ( 255.0 * pow( color.x, ( float ) ( 1 / 2.2 ) ) ) );
  1082. * ( ret_bm->GetPixel( x, y ) + 3 ) = 0;
  1083. pRGBData++;
  1084. if ( ( x & 3 ) == 3 )
  1085. pRGBData += 8;
  1086. }
  1087. }
  1088. #endif
  1089. MessageFromLPreview ret_msg( LPREVIEW_MSG_DISPLAY_RESULT );
  1090. // n_result_bms_queued++;
  1091. ret_msg.m_pBitmapToDisplay = ret_bm;
  1092. ret_msg.m_nBitmapGenerationCounter = m_nBitmapGenerationCounter;
  1093. g_LPreviewToHammerMsgQueue.QueueMessage( ret_msg );
  1094. }
  1095. // master side of lighting preview
  1096. unsigned LightingPreviewThreadFN( void * thread_start_arg )
  1097. {
  1098. CLightingPreviewThread LPreviewObject;
  1099. s_pThis = &LPreviewObject;
  1100. ThreadSetPriority( -2 ); // low
  1101. s_pThreadPool = CreateNewThreadPool();
  1102. CPUInformation pCPUInfo = GetCPUInformation();
  1103. ThreadPoolStartParams_t startParams;
  1104. startParams.nThreads = pCPUInfo.m_nPhysicalProcessors - 1;
  1105. s_nNumThreads = startParams.nThreads;
  1106. startParams.nStackSize = 1024*1024;
  1107. startParams.fDistribute = TRS_TRUE;
  1108. startParams.iThreadPriority = -2;
  1109. s_pThreadPool->Start( startParams );
  1110. LPreviewObject.Run();
  1111. return 0;
  1112. }
  1113. void HandleLightingPreview( void )
  1114. {
  1115. if ( GetMainWnd()->m_pLightingPreviewOutputWindow && !GetMainWnd()->m_bLightingPreviewOutputWindowShowing )
  1116. {
  1117. delete GetMainWnd()->m_pLightingPreviewOutputWindow;
  1118. GetMainWnd()->m_pLightingPreviewOutputWindow = NULL;
  1119. }
  1120. // called during main loop
  1121. while ( g_LPreviewToHammerMsgQueue.MessageWaiting() )
  1122. {
  1123. MessageFromLPreview msg;
  1124. g_LPreviewToHammerMsgQueue.WaitMessage( & msg );
  1125. switch( msg.m_MsgType )
  1126. {
  1127. case LPREVIEW_MSG_DISPLAY_RESULT:
  1128. {
  1129. n_result_bms_queued--;
  1130. if ( g_pLPreviewOutputBitmap )
  1131. delete g_pLPreviewOutputBitmap;
  1132. g_pLPreviewOutputBitmap = NULL;
  1133. // if ( msg.m_nBitmapGenerationCounter == g_nBitmapGenerationCounter )
  1134. {
  1135. g_pLPreviewOutputBitmap = msg.m_pBitmapToDisplay;
  1136. if ( g_pLPreviewOutputBitmap && ( g_pLPreviewOutputBitmap->Width() > 10 ) )
  1137. {
  1138. SignalUpdate( EVTYPE_BITMAP_RECEIVED_FROM_LPREVIEW );
  1139. CLightingPreviewResultsWindow *w=GetMainWnd()->m_pLightingPreviewOutputWindow;
  1140. if ( !GetMainWnd()->m_bLightingPreviewOutputWindowShowing )
  1141. {
  1142. w = new CLightingPreviewResultsWindow;
  1143. GetMainWnd()->m_pLightingPreviewOutputWindow = w;
  1144. w->Create( GetMainWnd() );
  1145. GetMainWnd()->m_bLightingPreviewOutputWindowShowing = true;
  1146. }
  1147. if ( ! w->IsWindowVisible() )
  1148. w->ShowWindow( SW_SHOW );
  1149. RECT existing_rect;
  1150. w->GetClientRect( & existing_rect );
  1151. if (
  1152. ( existing_rect.right != g_pLPreviewOutputBitmap->Width() - 1 ) ||
  1153. ( existing_rect.bottom != g_pLPreviewOutputBitmap->Height() - 1 ) )
  1154. {
  1155. CRect myRect;
  1156. myRect.top = 0;
  1157. myRect.left = 0;
  1158. myRect.right = g_pLPreviewOutputBitmap->Width() - 1;
  1159. myRect.bottom = g_pLPreviewOutputBitmap->Height() - 1;
  1160. w->CalcWindowRect( & myRect );
  1161. w->SetWindowPos(
  1162. NULL, 0, 0,
  1163. myRect.Width(), myRect.Height(),
  1164. SWP_NOMOVE | SWP_NOZORDER );
  1165. }
  1166. w->Invalidate( false );
  1167. w->UpdateWindow();
  1168. }
  1169. }
  1170. // else
  1171. // delete msg.m_pBitmapToDisplay; // its old
  1172. break;
  1173. }
  1174. }
  1175. }
  1176. }