renderImposterMgr.cpp
Engine/source/renderInstance/renderImposterMgr.cpp
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