Torque3D Documentation / _generateds / renderImposterMgr.cpp

renderImposterMgr.cpp

Engine/source/renderInstance/renderImposterMgr.cpp

More...

Public Functions

ConsoleDocClass(RenderImposterMgr , "@brief A <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> bin <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> batch rendering <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">imposters.\n\n</a>" "This <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> bin gathers imposter <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> instances and renders them in large " "<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">batches.\n\n</a>" "You can type 'metrics( imposter )' in the console <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> see rendering <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">statistics.\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">RenderBin\n</a>" )

Detailed Description

Public Functions

ConsoleDocClass(RenderImposterMgr , "@brief A <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> bin <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> batch rendering <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">imposters.\n\n</a>" "This <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> bin gathers imposter <a href="/coding/file/editortool_8cpp/#editortool_8cpp_1a4cb041169a32ea3d4cacadbb955e06b4">render</a> instances and renders them in large " "<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">batches.\n\n</a>" "You can type 'metrics( imposter )' in the console <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> see rendering <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">statistics.\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">RenderBin\n</a>" )

IMPLEMENT_CONOBJECT(RenderImposterMgr )

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