123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "platform/platform.h"
- #include "renderInstance/renderImposterMgr.h"
- #include "scene/sceneManager.h"
- #include "T3D/gameBase/gameConnection.h"
- #include "materials/shaderData.h"
- #include "lighting/lightManager.h"
- #include "lighting/lightInfo.h"
- #include "scene/sceneRenderState.h"
- #include "gfx/gfxDebugEvent.h"
- #include "renderInstance/renderDeferredMgr.h"
- #include "gfx/gfxTransformSaver.h"
- #include "console/consoleTypes.h"
- #include "gfx/util/screenspace.h"
- #include "math/util/matrixSet.h"
- #include "materials/materialManager.h"
- #include "materials/materialFeatureTypes.h"
- /*
- GFXImplementVertexFormat( ImposterCorner )
- {
- addElement( "ImposterCorner", GFXDeclType_Float, 4 );
- };
- */
- const RenderInstType RenderImposterMgr::RIT_Imposter( "Imposter" );
- const RenderInstType RenderImposterMgr::RIT_ImposterBatch( "ImposterBatch" );
- U32 RenderImposterMgr::smRendered = 0.0f;
- U32 RenderImposterMgr::smBatches = 0.0f;
- U32 RenderImposterMgr::smDrawCalls = 0.0f;
- U32 RenderImposterMgr::smPolyCount = 0.0f;
- U32 RenderImposterMgr::smRTChanges = 0.0f;
- IMPLEMENT_CONOBJECT(RenderImposterMgr);
- ConsoleDocClass( RenderImposterMgr,
- "@brief A render bin for batch rendering imposters.\n\n"
- "This render bin gathers imposter render instances and renders them in large "
- "batches.\n\n"
- "You can type 'metrics( imposter )' in the console to see rendering statistics.\n\n"
- "@ingroup RenderBin\n" );
- RenderImposterMgr::RenderImposterMgr( F32 renderOrder, F32 processAddOrder )
- : RenderBinManager( RIT_Imposter, renderOrder, processAddOrder )
- {
- notifyType( RIT_ImposterBatch );
- RenderDeferredMgr::getRenderSignal().notify( this, &RenderImposterMgr::_renderDeferred );
- }
- void RenderImposterMgr::initPersistFields()
- {
- docsURL;
- GFXDevice::getDeviceEventSignal().notify( &RenderImposterMgr::_clearStats );
- Con::addVariable( "$ImposterStats::rendered", TypeS32, &smRendered, "@internal" );
- Con::addVariable( "$ImposterStats::batches", TypeS32, &smBatches, "@internal" );
- Con::addVariable( "$ImposterStats::drawCalls", TypeS32, &smDrawCalls, "@internal" );
- Con::addVariable( "$ImposterStats::polyCount", TypeS32, &smPolyCount, "@internal" );
- Con::addVariable( "$ImposterStats::rtChanges", TypeS32, &smRTChanges, "@internal" );
- Parent::initPersistFields();
- }
- RenderImposterMgr::~RenderImposterMgr()
- {
- RenderDeferredMgr::getRenderSignal().remove( this, &RenderImposterMgr::_renderDeferred );
- mIB = NULL;
- }
- void RenderImposterMgr::render( SceneRenderState *state )
- {
- PROFILE_SCOPE( RenderImposterMgr_Render );
- if ( !mElementList.size() )
- return;
- GFXDEBUGEVENT_SCOPE( RenderImposterMgr_Render, ColorI::RED );
- _innerRender( state, NULL );
- }
- bool RenderImposterMgr::_clearStats( GFXDevice::GFXDeviceEventType type )
- {
- if ( type == GFXDevice::deStartOfFrame )
- {
- smRendered = 0.0f;
- smBatches = 0.0f;
- smDrawCalls = 0.0f;
- smPolyCount = 0.0f;
- smRTChanges = 0.0f;
- }
- return true;
- }
- void RenderImposterMgr::_renderDeferred( const SceneRenderState *state, RenderDeferredMgr *deferredBin, bool startDeferred )
- {
- PROFILE_SCOPE( RenderImposterMgr_RenderDeferred );
- if ( !mElementList.size() || !startDeferred )
- return;
- GFXDEBUGEVENT_SCOPE( RenderImposterMgr_RenderDeferred, ColorI::RED );
- _innerRender( state, deferredBin );
- }
- void RenderImposterMgr::_innerRender( const SceneRenderState *state, RenderDeferredMgr *deferredBin )
- {
- if (deferredBin == NULL) return;
- PROFILE_SCOPE( RenderImposterMgr_InnerRender );
- // Capture the GFX stats for this render.
- GFXDeviceStatistics stats;
- stats.start( GFX->getDeviceStatistics() );
- GFXTransformSaver saver;
- // Restore transforms
- MatrixSet &matrixSet = getRenderPass()->getMatrixSet();
- matrixSet.restoreSceneViewProjection();
- matrixSet.setWorld( MatrixF::Identity );
- // Setup the large static index buffer for rendering the imposters.
- if ( !mIB.isValid() )
- {
- // Setup a static index buffer for rendering.
- mIB.set( GFX, smImposterBatchSize * 6, 0, GFXBufferTypeStatic );
- U16 *idxBuff;
- mIB.lock(&idxBuff, NULL, 0, 0);
- for ( U32 i=0; i < smImposterBatchSize; i++ )
- {
- //
- // The vertex pattern in the VB for each
- // imposter is as follows...
- //
- // 0----1
- // |\ |
- // | \ |
- // | \ |
- // | \|
- // 3----2
- //
- // We setup the index order below to ensure
- // sequental, cache friendly, access.
- //
- U32 offset = i * 4;
- idxBuff[i*6+0] = 0 + offset;
- idxBuff[i*6+1] = 1 + offset;
- idxBuff[i*6+2] = 2 + offset;
- idxBuff[i*6+3] = 2 + offset;
- idxBuff[i*6+4] = 3 + offset;
- idxBuff[i*6+5] = 0 + offset;
- }
- mIB.unlock();
- }
- /*
- if ( !mCornerVB.isValid() )
- {
- // Setup a static vertex buffer for the corner index for each imposter state.
- mCornerVB.set( GFX, smImposterBatchSize * 4, GFXBufferTypeStatic );
- ImposterCorner *corner = mCornerVB.lock( 0 );
- for ( U32 i=0; i < smImposterBatchSize; i++ )
- {
- corner->corner = 0; corner++;
- corner->corner = 1; corner++;
- corner->corner = 2; corner++;
- corner->corner = 3; corner++;
- }
- mCornerVB.unlock();
- }
- */
- // Set the buffers here once.
- GFX->setPrimitiveBuffer( mIB );
- // Batch up the imposters into the buffer. These
- // are already sorted by texture, to minimize switches
- // so just batch them up and render as they come.
- ImposterState* statePtr = NULL;
- U32 stateCount;
- ImposterBaseRenderInst *ri;
- ImposterRenderInst *imposter;
- ImposterBatchRenderInst *batch;
- const U32 binSize = mElementList.size();
- BaseMatInstance *setupMat, *currMat;
- GFXVertexBufferHandle<ImposterState> vb;
- // TODO: We could maybe do better with lights when forward
- // rendering the imposters. Just pass a light list with it
- // and do some simple tests to break the batch when the light
- // list changes.
- SceneData sgData;
- sgData.init( state, deferredBin ? SceneData::DeferredBin : SceneData::RegularBin );
- sgData.lights[0] = LIGHTMGR->getDefaultLight();
- // TODO: I should rework this loop to generate the VB first then
- // do all the material passes... should be easier to read and faster.
- //
- // Also consider making this store two element lists... one for
- // batches and one for individual imposters.
- //
-
- for ( U32 i=0; i < binSize; )
- {
- currMat = static_cast<ImposterBaseRenderInst*>( mElementList[i].inst )->mat;
- setupMat = deferredBin ? deferredBin->getDeferredMaterial( currMat ) : currMat;
- // TODO: Fix MatInstance to take a const SceneRenderState!
- while ( setupMat->setupPass( (SceneRenderState*)state, sgData ) )
- {
- setupMat->setSceneInfo( (SceneRenderState*)state, sgData );
- setupMat->setTransforms( matrixSet, (SceneRenderState*)state );
- for ( ; i < binSize; )
- {
- ri = static_cast<ImposterBaseRenderInst*>( mElementList[i].inst );
-
- // NOTE: Its safe to compare matinstances here instead of
- // the state hint because imposters all share the same
- // material instances.... if this changes revise.
- if ( ri->mat != currMat )
- break;
- // Ok if this is a batch then we can just fire off the draw now.
- if ( ri->type == RIT_ImposterBatch )
- {
- batch = static_cast<ImposterBatchRenderInst*>( ri );
- GFX->setVertexBuffer( batch->vertBuff->getPointer() );
- GFX->drawPrimitive( GFXTriangleList, 0, batch->vertBuff->getPointer()->mNumVerts / 3 );
-
- i++;
- continue;
- }
- // This wasn't a batch so build up all the single imposters into
- // a dynamic batch and render it.
- statePtr = mBuffer;
- stateCount = 0;
- // Loop for each individual imposter.
- for ( ; i < binSize; i++ )
- {
- if ( mElementList[i].inst->type == RIT_ImposterBatch )
- break;
- imposter = static_cast<ImposterRenderInst*>( mElementList[i].inst );
- // Stop the loop if the material changed.
- if ( imposter->mat != currMat )
- break;
- ++smRendered;
- // If we're out of vb space then draw what we got.
- if ( stateCount + 1 >= smImposterBatchSize )
- {
- smBatches++;
-
- vb.set( GFX, stateCount*4, GFXBufferTypeVolatile );
- ImposterState *buf = vb.lock();
- if(buf)
- {
- dMemcpy( buf, mBuffer, stateCount * 4 * sizeof( ImposterState ) );
- vb.unlock();
- }
-
- //GFX->setVertexBuffer( mCornerVB, 0, stateCount * 4 );
- GFX->setVertexBuffer( vb );
- ///GFX->setVertexFormat( &mImposterVertDecl );
- GFX->drawIndexedPrimitive( GFXTriangleList, 0, 0, stateCount * 4, 0, stateCount * 2 );
- statePtr = mBuffer;
- stateCount = 0;
- }
- // Setup the imposter state.
- *statePtr = imposter->state;
- statePtr->corner = 0;
- statePtr++;
- *statePtr = imposter->state;
- statePtr->corner = 1;
- statePtr++;
- *statePtr = imposter->state;
- statePtr->corner = 2;
- statePtr++;
- *statePtr = imposter->state;
- statePtr->corner = 3;
- statePtr++;
- stateCount++;
- } // for ( ; i < binSize; i++ )
- // Any remainder to dump?
- if ( stateCount > 0 )
- {
- smBatches++;
- vb.set( GFX, stateCount*4, GFXBufferTypeVolatile );
- ImposterState *buf = vb.lock();
- if(buf)
- {
- dMemcpy( buf, mBuffer, stateCount * 4 * sizeof( ImposterState ) );
- vb.unlock();
- }
-
- //GFX->setVertexBuffer( mCornerVB, 0, stateCount * 4 );
- GFX->setVertexBuffer( vb );
- ///GFX->setVertexFormat( &mImposterVertDecl );
- GFX->drawIndexedPrimitive( GFXTriangleList, 0, 0, stateCount * 4, 0, stateCount * 2 );
- }
- } // for( U32 i=0; i < binSize; )
- } // while ( currMat->setupPass( (SceneRenderState*)state, sgData ) )
- } // for ( U32 i=0; i < binSize; )
- // Capture the GFX stats for this render.
- stats.end( GFX->getDeviceStatistics() );
- smDrawCalls += stats.mDrawCalls;
- smPolyCount += stats.mPolyCount;
- smRTChanges += stats.mRenderTargetChanges;
- }
|