renderImposterMgr.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  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/renderDeferredMgr.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. RenderDeferredMgr::getRenderSignal().notify( this, &RenderImposterMgr::_renderDeferred );
  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. RenderDeferredMgr::getRenderSignal().remove( this, &RenderImposterMgr::_renderDeferred );
  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::_renderDeferred( const SceneRenderState *state, RenderDeferredMgr *deferredBin, bool startDeferred )
  100. {
  101. PROFILE_SCOPE( RenderImposterMgr_RenderDeferred );
  102. if ( !mElementList.size() || !startDeferred )
  103. return;
  104. GFXDEBUGEVENT_SCOPE( RenderImposterMgr_RenderDeferred, ColorI::RED );
  105. _innerRender( state, deferredBin );
  106. }
  107. void RenderImposterMgr::_innerRender( const SceneRenderState *state, RenderDeferredMgr *deferredBin )
  108. {
  109. if (deferredBin == NULL) return;
  110. PROFILE_SCOPE( RenderImposterMgr_InnerRender );
  111. // Capture the GFX stats for this render.
  112. GFXDeviceStatistics stats;
  113. stats.start( GFX->getDeviceStatistics() );
  114. GFXTransformSaver saver;
  115. // Restore transforms
  116. MatrixSet &matrixSet = getRenderPass()->getMatrixSet();
  117. matrixSet.restoreSceneViewProjection();
  118. matrixSet.setWorld( MatrixF::Identity );
  119. // Setup the large static index buffer for rendering the imposters.
  120. if ( !mIB.isValid() )
  121. {
  122. // Setup a static index buffer for rendering.
  123. mIB.set( GFX, smImposterBatchSize * 6, 0, GFXBufferTypeStatic );
  124. U16 *idxBuff;
  125. mIB.lock(&idxBuff, NULL, 0, 0);
  126. for ( U32 i=0; i < smImposterBatchSize; i++ )
  127. {
  128. //
  129. // The vertex pattern in the VB for each
  130. // imposter is as follows...
  131. //
  132. // 0----1
  133. // |\ |
  134. // | \ |
  135. // | \ |
  136. // | \|
  137. // 3----2
  138. //
  139. // We setup the index order below to ensure
  140. // sequental, cache friendly, access.
  141. //
  142. U32 offset = i * 4;
  143. idxBuff[i*6+0] = 0 + offset;
  144. idxBuff[i*6+1] = 1 + offset;
  145. idxBuff[i*6+2] = 2 + offset;
  146. idxBuff[i*6+3] = 2 + offset;
  147. idxBuff[i*6+4] = 3 + offset;
  148. idxBuff[i*6+5] = 0 + offset;
  149. }
  150. mIB.unlock();
  151. }
  152. /*
  153. if ( !mCornerVB.isValid() )
  154. {
  155. // Setup a static vertex buffer for the corner index for each imposter state.
  156. mCornerVB.set( GFX, smImposterBatchSize * 4, GFXBufferTypeStatic );
  157. ImposterCorner *corner = mCornerVB.lock( 0 );
  158. for ( U32 i=0; i < smImposterBatchSize; i++ )
  159. {
  160. corner->corner = 0; corner++;
  161. corner->corner = 1; corner++;
  162. corner->corner = 2; corner++;
  163. corner->corner = 3; corner++;
  164. }
  165. mCornerVB.unlock();
  166. }
  167. */
  168. // Set the buffers here once.
  169. GFX->setPrimitiveBuffer( mIB );
  170. // Batch up the imposters into the buffer. These
  171. // are already sorted by texture, to minimize switches
  172. // so just batch them up and render as they come.
  173. ImposterState* statePtr = NULL;
  174. U32 stateCount;
  175. ImposterBaseRenderInst *ri;
  176. ImposterRenderInst *imposter;
  177. ImposterBatchRenderInst *batch;
  178. const U32 binSize = mElementList.size();
  179. BaseMatInstance *setupMat, *currMat;
  180. GFXVertexBufferHandle<ImposterState> vb;
  181. // TODO: We could maybe do better with lights when forward
  182. // rendering the imposters. Just pass a light list with it
  183. // and do some simple tests to break the batch when the light
  184. // list changes.
  185. SceneData sgData;
  186. sgData.init( state, deferredBin ? SceneData::DeferredBin : SceneData::RegularBin );
  187. sgData.lights[0] = LIGHTMGR->getDefaultLight();
  188. // TODO: I should rework this loop to generate the VB first then
  189. // do all the material passes... should be easier to read and faster.
  190. //
  191. // Also consider making this store two element lists... one for
  192. // batches and one for individual imposters.
  193. //
  194. for ( U32 i=0; i < binSize; )
  195. {
  196. currMat = static_cast<ImposterBaseRenderInst*>( mElementList[i].inst )->mat;
  197. setupMat = deferredBin ? deferredBin->getDeferredMaterial( currMat ) : currMat;
  198. // TODO: Fix MatInstance to take a const SceneRenderState!
  199. while ( setupMat->setupPass( (SceneRenderState*)state, sgData ) )
  200. {
  201. setupMat->setSceneInfo( (SceneRenderState*)state, sgData );
  202. setupMat->setTransforms( matrixSet, (SceneRenderState*)state );
  203. for ( ; i < binSize; )
  204. {
  205. ri = static_cast<ImposterBaseRenderInst*>( mElementList[i].inst );
  206. // NOTE: Its safe to compare matinstances here instead of
  207. // the state hint because imposters all share the same
  208. // material instances.... if this changes revise.
  209. if ( ri->mat != currMat )
  210. break;
  211. // Ok if this is a batch then we can just fire off the draw now.
  212. if ( ri->type == RIT_ImposterBatch )
  213. {
  214. batch = static_cast<ImposterBatchRenderInst*>( ri );
  215. GFX->setVertexBuffer( batch->vertBuff->getPointer() );
  216. GFX->drawPrimitive( GFXTriangleList, 0, batch->vertBuff->getPointer()->mNumVerts / 3 );
  217. i++;
  218. continue;
  219. }
  220. // This wasn't a batch so build up all the single imposters into
  221. // a dynamic batch and render it.
  222. statePtr = mBuffer;
  223. stateCount = 0;
  224. // Loop for each individual imposter.
  225. for ( ; i < binSize; i++ )
  226. {
  227. if ( mElementList[i].inst->type == RIT_ImposterBatch )
  228. break;
  229. imposter = static_cast<ImposterRenderInst*>( mElementList[i].inst );
  230. // Stop the loop if the material changed.
  231. if ( imposter->mat != currMat )
  232. break;
  233. ++smRendered;
  234. // If we're out of vb space then draw what we got.
  235. if ( stateCount + 1 >= smImposterBatchSize )
  236. {
  237. smBatches++;
  238. vb.set( GFX, stateCount*4, GFXBufferTypeVolatile );
  239. ImposterState *buf = vb.lock();
  240. if(buf)
  241. {
  242. dMemcpy( buf, mBuffer, stateCount * 4 * sizeof( ImposterState ) );
  243. vb.unlock();
  244. }
  245. //GFX->setVertexBuffer( mCornerVB, 0, stateCount * 4 );
  246. GFX->setVertexBuffer( vb );
  247. ///GFX->setVertexFormat( &mImposterVertDecl );
  248. GFX->drawIndexedPrimitive( GFXTriangleList, 0, 0, stateCount * 4, 0, stateCount * 2 );
  249. statePtr = mBuffer;
  250. stateCount = 0;
  251. }
  252. // Setup the imposter state.
  253. *statePtr = imposter->state;
  254. statePtr->corner = 0;
  255. statePtr++;
  256. *statePtr = imposter->state;
  257. statePtr->corner = 1;
  258. statePtr++;
  259. *statePtr = imposter->state;
  260. statePtr->corner = 2;
  261. statePtr++;
  262. *statePtr = imposter->state;
  263. statePtr->corner = 3;
  264. statePtr++;
  265. stateCount++;
  266. } // for ( ; i < binSize; i++ )
  267. // Any remainder to dump?
  268. if ( stateCount > 0 )
  269. {
  270. smBatches++;
  271. vb.set( GFX, stateCount*4, GFXBufferTypeVolatile );
  272. ImposterState *buf = vb.lock();
  273. if(buf)
  274. {
  275. dMemcpy( buf, mBuffer, stateCount * 4 * sizeof( ImposterState ) );
  276. vb.unlock();
  277. }
  278. //GFX->setVertexBuffer( mCornerVB, 0, stateCount * 4 );
  279. GFX->setVertexBuffer( vb );
  280. ///GFX->setVertexFormat( &mImposterVertDecl );
  281. GFX->drawIndexedPrimitive( GFXTriangleList, 0, 0, stateCount * 4, 0, stateCount * 2 );
  282. }
  283. } // for( U32 i=0; i < binSize; )
  284. } // while ( currMat->setupPass( (SceneRenderState*)state, sgData ) )
  285. } // for ( U32 i=0; i < binSize; )
  286. // Capture the GFX stats for this render.
  287. stats.end( GFX->getDeviceStatistics() );
  288. smDrawCalls += stats.mDrawCalls;
  289. smPolyCount += stats.mPolyCount;
  290. smRTChanges += stats.mRenderTargetChanges;
  291. }