renderImposterMgr.cpp 12 KB

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