renderImposterMgr.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "renderInstance/renderImposterMgr.h"
  24. #include "scene/sceneManager.h"
  25. #include "T3D/gameBase/gameConnection.h"
  26. #include "materials/shaderData.h"
  27. #include "lighting/lightManager.h"
  28. #include "lighting/lightInfo.h"
  29. #include "scene/sceneRenderState.h"
  30. #include "gfx/gfxDebugEvent.h"
  31. #include "renderInstance/renderPrePassMgr.h"
  32. #include "gfx/gfxTransformSaver.h"
  33. #include "console/consoleTypes.h"
  34. #include "gfx/util/screenspace.h"
  35. #include "math/util/matrixSet.h"
  36. #include "materials/materialManager.h"
  37. #include "materials/materialFeatureTypes.h"
  38. /*
  39. GFXImplementVertexFormat( ImposterCorner )
  40. {
  41. addElement( "ImposterCorner", GFXDeclType_Float, 4 );
  42. };
  43. */
  44. const RenderInstType RenderImposterMgr::RIT_Imposter( "Imposter" );
  45. const RenderInstType RenderImposterMgr::RIT_ImposterBatch( "ImposterBatch" );
  46. U32 RenderImposterMgr::smRendered = 0.0f;
  47. U32 RenderImposterMgr::smBatches = 0.0f;
  48. U32 RenderImposterMgr::smDrawCalls = 0.0f;
  49. U32 RenderImposterMgr::smPolyCount = 0.0f;
  50. U32 RenderImposterMgr::smRTChanges = 0.0f;
  51. IMPLEMENT_CONOBJECT(RenderImposterMgr);
  52. ConsoleDocClass( RenderImposterMgr,
  53. "@brief A render bin for batch rendering imposters.\n\n"
  54. "This render bin gathers imposter render instances and renders them in large "
  55. "batches.\n\n"
  56. "You can type 'metrics( imposter )' in the console to see rendering statistics.\n\n"
  57. "@ingroup RenderBin\n" );
  58. RenderImposterMgr::RenderImposterMgr( F32 renderOrder, F32 processAddOrder )
  59. : RenderBinManager( RIT_Imposter, renderOrder, processAddOrder )
  60. {
  61. notifyType( RIT_ImposterBatch );
  62. RenderPrePassMgr::getRenderSignal().notify( this, &RenderImposterMgr::_renderPrePass );
  63. }
  64. void RenderImposterMgr::initPersistFields()
  65. {
  66. GFXDevice::getDeviceEventSignal().notify( &RenderImposterMgr::_clearStats );
  67. Con::addVariable( "$ImposterStats::rendered", TypeS32, &smRendered, "@internal" );
  68. Con::addVariable( "$ImposterStats::batches", TypeS32, &smBatches, "@internal" );
  69. Con::addVariable( "$ImposterStats::drawCalls", TypeS32, &smDrawCalls, "@internal" );
  70. Con::addVariable( "$ImposterStats::polyCount", TypeS32, &smPolyCount, "@internal" );
  71. Con::addVariable( "$ImposterStats::rtChanges", TypeS32, &smRTChanges, "@internal" );
  72. Parent::initPersistFields();
  73. }
  74. RenderImposterMgr::~RenderImposterMgr()
  75. {
  76. RenderPrePassMgr::getRenderSignal().remove( this, &RenderImposterMgr::_renderPrePass );
  77. mIB = NULL;
  78. }
  79. void RenderImposterMgr::render( SceneRenderState *state )
  80. {
  81. PROFILE_SCOPE( RenderImposterMgr_Render );
  82. if ( !mElementList.size() )
  83. return;
  84. GFXDEBUGEVENT_SCOPE( RenderImposterMgr_Render, ColorI::RED );
  85. _innerRender( state, NULL );
  86. }
  87. bool RenderImposterMgr::_clearStats( GFXDevice::GFXDeviceEventType type )
  88. {
  89. if ( type == GFXDevice::deStartOfFrame )
  90. {
  91. smRendered = 0.0f;
  92. smBatches = 0.0f;
  93. smDrawCalls = 0.0f;
  94. smPolyCount = 0.0f;
  95. smRTChanges = 0.0f;
  96. }
  97. return true;
  98. }
  99. void RenderImposterMgr::_renderPrePass( const SceneRenderState *state, RenderPrePassMgr *prePassBin, bool startPrePass )
  100. {
  101. PROFILE_SCOPE( RenderImposterMgr_RenderPrePass );
  102. if ( !mElementList.size() || !startPrePass )
  103. return;
  104. GFXDEBUGEVENT_SCOPE( RenderImposterMgr_RenderPrePass, ColorI::RED );
  105. _innerRender( state, prePassBin );
  106. }
  107. void RenderImposterMgr::_innerRender( const SceneRenderState *state, RenderPrePassMgr *prePassBin )
  108. {
  109. PROFILE_SCOPE( RenderImposterMgr_InnerRender );
  110. // Capture the GFX stats for this render.
  111. GFXDeviceStatistics stats;
  112. stats.start( GFX->getDeviceStatistics() );
  113. GFXTransformSaver saver;
  114. // Restore transforms
  115. MatrixSet &matrixSet = getRenderPass()->getMatrixSet();
  116. matrixSet.restoreSceneViewProjection();
  117. matrixSet.setWorld( MatrixF::Identity );
  118. // Setup the large static index buffer for rendering the imposters.
  119. if ( !mIB.isValid() )
  120. {
  121. // Setup a static index buffer for rendering.
  122. mIB.set( GFX, smImposterBatchSize * 6, 0, GFXBufferTypeStatic );
  123. U16 *idxBuff;
  124. mIB.lock(&idxBuff, NULL, NULL, NULL);
  125. for ( U32 i=0; i < smImposterBatchSize; i++ )
  126. {
  127. //
  128. // The vertex pattern in the VB for each
  129. // imposter is as follows...
  130. //
  131. // 0----1
  132. // |\ |
  133. // | \ |
  134. // | \ |
  135. // | \|
  136. // 3----2
  137. //
  138. // We setup the index order below to ensure
  139. // sequental, cache friendly, access.
  140. //
  141. U32 offset = i * 4;
  142. idxBuff[i*6+0] = 0 + offset;
  143. idxBuff[i*6+1] = 1 + offset;
  144. idxBuff[i*6+2] = 2 + offset;
  145. idxBuff[i*6+3] = 2 + offset;
  146. idxBuff[i*6+4] = 3 + offset;
  147. idxBuff[i*6+5] = 0 + offset;
  148. }
  149. mIB.unlock();
  150. }
  151. /*
  152. if ( !mCornerVB.isValid() )
  153. {
  154. // Setup a static vertex buffer for the corner index for each imposter state.
  155. mCornerVB.set( GFX, smImposterBatchSize * 4, GFXBufferTypeStatic );
  156. ImposterCorner *corner = mCornerVB.lock( 0 );
  157. for ( U32 i=0; i < smImposterBatchSize; i++ )
  158. {
  159. corner->corner = 0; corner++;
  160. corner->corner = 1; corner++;
  161. corner->corner = 2; corner++;
  162. corner->corner = 3; corner++;
  163. }
  164. mCornerVB.unlock();
  165. }
  166. */
  167. // Set the buffers here once.
  168. GFX->setPrimitiveBuffer( mIB );
  169. // Batch up the imposters into the buffer. These
  170. // are already sorted by texture, to minimize switches
  171. // so just batch them up and render as they come.
  172. ImposterState* statePtr = NULL;
  173. U32 stateCount;
  174. ImposterBaseRenderInst *ri;
  175. ImposterRenderInst *imposter;
  176. ImposterBatchRenderInst *batch;
  177. const U32 binSize = mElementList.size();
  178. BaseMatInstance *setupMat, *currMat;
  179. GFXVertexBufferHandle<ImposterState> vb;
  180. // TODO: We could maybe do better with lights when forward
  181. // rendering the imposters. Just pass a light list with it
  182. // and do some simple tests to break the batch when the light
  183. // list changes.
  184. SceneData sgData;
  185. sgData.init( state, prePassBin ? SceneData::PrePassBin : SceneData::RegularBin );
  186. sgData.lights[0] = LIGHTMGR->getDefaultLight();
  187. // TODO: I should rework this loop to generate the VB first then
  188. // do all the material passes... should be easier to read and faster.
  189. //
  190. // Also consider making this store two element lists... one for
  191. // batches and one for individual imposters.
  192. //
  193. for ( U32 i=0; i < binSize; )
  194. {
  195. currMat = static_cast<ImposterBaseRenderInst*>( mElementList[i].inst )->mat;
  196. setupMat = prePassBin ? prePassBin->getPrePassMaterial( currMat ) : currMat;
  197. // TODO: Fix MatInstance to take a const SceneRenderState!
  198. while ( setupMat->setupPass( (SceneRenderState*)state, sgData ) )
  199. {
  200. setupMat->setSceneInfo( (SceneRenderState*)state, sgData );
  201. setupMat->setTransforms( matrixSet, (SceneRenderState*)state );
  202. for ( ; i < binSize; )
  203. {
  204. ri = static_cast<ImposterBaseRenderInst*>( mElementList[i].inst );
  205. // NOTE: Its safe to compare matinstances here instead of
  206. // the state hint because imposters all share the same
  207. // material instances.... if this changes revise.
  208. if ( ri->mat != currMat )
  209. break;
  210. // Ok if this is a batch then we can just fire off the draw now.
  211. if ( ri->type == RIT_ImposterBatch )
  212. {
  213. batch = static_cast<ImposterBatchRenderInst*>( ri );
  214. GFX->setVertexBuffer( batch->vertBuff->getPointer() );
  215. GFX->drawPrimitive( GFXTriangleList, 0, batch->vertBuff->getPointer()->mNumVerts / 3 );
  216. i++;
  217. continue;
  218. }
  219. // This wasn't a batch so build up all the single imposters into
  220. // a dynamic batch and render it.
  221. statePtr = mBuffer;
  222. stateCount = 0;
  223. // Loop for each individual imposter.
  224. for ( ; i < binSize; i++ )
  225. {
  226. if ( mElementList[i].inst->type == RIT_ImposterBatch )
  227. break;
  228. imposter = static_cast<ImposterRenderInst*>( mElementList[i].inst );
  229. // Stop the loop if the material changed.
  230. if ( imposter->mat != currMat )
  231. break;
  232. ++smRendered;
  233. // If we're out of vb space then draw what we got.
  234. if ( stateCount + 1 >= smImposterBatchSize )
  235. {
  236. smBatches++;
  237. vb.set( GFX, stateCount*4, GFXBufferTypeVolatile );
  238. ImposterState *buf = vb.lock();
  239. if(buf)
  240. {
  241. dMemcpy( buf, mBuffer, stateCount * 4 * sizeof( ImposterState ) );
  242. vb.unlock();
  243. }
  244. //GFX->setVertexBuffer( mCornerVB, 0, stateCount * 4 );
  245. GFX->setVertexBuffer( vb );
  246. ///GFX->setVertexFormat( &mImposterVertDecl );
  247. GFX->drawIndexedPrimitive( GFXTriangleList, 0, 0, stateCount * 4, 0, stateCount * 2 );
  248. statePtr = mBuffer;
  249. stateCount = 0;
  250. }
  251. // Setup the imposter state.
  252. *statePtr = imposter->state;
  253. statePtr->corner = 0;
  254. statePtr++;
  255. *statePtr = imposter->state;
  256. statePtr->corner = 1;
  257. statePtr++;
  258. *statePtr = imposter->state;
  259. statePtr->corner = 2;
  260. statePtr++;
  261. *statePtr = imposter->state;
  262. statePtr->corner = 3;
  263. statePtr++;
  264. stateCount++;
  265. } // for ( ; i < binSize; i++ )
  266. // Any remainder to dump?
  267. if ( stateCount > 0 )
  268. {
  269. smBatches++;
  270. vb.set( GFX, stateCount*4, GFXBufferTypeVolatile );
  271. ImposterState *buf = vb.lock();
  272. if(buf)
  273. {
  274. dMemcpy( buf, mBuffer, stateCount * 4 * sizeof( ImposterState ) );
  275. vb.unlock();
  276. }
  277. //GFX->setVertexBuffer( mCornerVB, 0, stateCount * 4 );
  278. GFX->setVertexBuffer( vb );
  279. ///GFX->setVertexFormat( &mImposterVertDecl );
  280. GFX->drawIndexedPrimitive( GFXTriangleList, 0, 0, stateCount * 4, 0, stateCount * 2 );
  281. }
  282. } // for( U32 i=0; i < binSize; )
  283. } // while ( currMat->setupPass( (SceneRenderState*)state, sgData ) )
  284. } // for ( U32 i=0; i < binSize; )
  285. // Capture the GFX stats for this render.
  286. stats.end( GFX->getDeviceStatistics() );
  287. smDrawCalls += stats.mDrawCalls;
  288. smPolyCount += stats.mPolyCount;
  289. smRTChanges += stats.mRenderTargetChanges;
  290. }