BatchRender.cc 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 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 "BatchRender.h"
  23. #ifndef _SCENE_OBJECT_H_
  24. #include "2d/sceneobject/SceneObject.h"
  25. #endif
  26. // Debug Profiling.
  27. #include "debug/profiler.h"
  28. //-----------------------------------------------------------------------------
  29. BatchRender::BatchRender() :
  30. mTriangleCount( 0 ),
  31. mVertexCount( 0 ),
  32. mTextureCoordCount( 0 ),
  33. mIndexCount( 0 ),
  34. mColorCount( 0 ),
  35. NoColor( -1.0f, -1.0f, -1.0f ),
  36. mStrictOrderMode( false ),
  37. mpDebugStats( NULL ),
  38. mBlendMode( true ),
  39. mSrcBlendFactor( GL_SRC_ALPHA ),
  40. mDstBlendFactor( GL_ONE_MINUS_SRC_ALPHA ),
  41. mBlendColor( ColorF(1.0f,1.0f,1.0f,1.0f) ),
  42. mAlphaTestMode( -1.0f ),
  43. mWireframeMode( false ),
  44. mBatchEnabled( true )
  45. {
  46. }
  47. //-----------------------------------------------------------------------------
  48. BatchRender::~BatchRender()
  49. {
  50. // Destroy index vectors in texture batch map.
  51. for ( textureBatchType::iterator itr = mTextureBatchMap.begin(); itr != mTextureBatchMap.end(); ++itr )
  52. {
  53. delete itr->value;
  54. }
  55. mTextureBatchMap.clear();
  56. // Destroy index vectors in index vector pool.
  57. for ( VectorPtr< indexVectorType* >::iterator itr = mIndexVectorPool.begin(); itr != mIndexVectorPool.end(); ++itr )
  58. {
  59. delete (*itr);
  60. }
  61. mIndexVectorPool.clear();
  62. }
  63. //-----------------------------------------------------------------------------
  64. void BatchRender::setBlendMode( const SceneRenderRequest* pSceneRenderRequest )
  65. {
  66. // Are we blending?
  67. if ( pSceneRenderRequest->mBlendMode )
  68. {
  69. // Yes, so set blending to standard alpha-blending.
  70. setBlendMode(
  71. pSceneRenderRequest->mSrcBlendFactor,
  72. pSceneRenderRequest->mDstBlendFactor,
  73. pSceneRenderRequest->mBlendColor );
  74. }
  75. else
  76. {
  77. // No, so turn-off blending.
  78. setBlendOff();
  79. }
  80. }
  81. //-----------------------------------------------------------------------------
  82. void BatchRender::setAlphaTestMode( const SceneRenderRequest* pSceneRenderRequest )
  83. {
  84. // Set alpha-test mode.
  85. setAlphaTestMode( pSceneRenderRequest->mAlphaTest );
  86. }
  87. //-----------------------------------------------------------------------------
  88. void BatchRender::SubmitTriangles(
  89. const U32 vertexCount,
  90. const Vector2* pVertexArray,
  91. const Vector2* pTextureArray,
  92. TextureHandle& texture,
  93. const ColorF& color )
  94. {
  95. // Debug Profiling.
  96. PROFILE_SCOPE(BatchRender_SubmitTriangles);
  97. // Sanity!
  98. AssertFatal( mpDebugStats != NULL, "Debug stats have not been configured." );
  99. AssertFatal( vertexCount % 3 == 0, "BatchRender::SubmitTriangles() - Invalid vertex count, cannot represent whole triangles." );
  100. AssertFatal( vertexCount <= BATCHRENDER_BUFFERSIZE, "BatchRender::SubmitTriangles() - Invalid vertex count." );
  101. // Calculate triangle count.
  102. const U32 triangleCount = vertexCount / 3;
  103. // Would we exceed the triangle buffer size?
  104. if ( (mTriangleCount + triangleCount) > BATCHRENDER_MAXTRIANGLES )
  105. {
  106. // Yes, so flush.
  107. flush( mpDebugStats->batchBufferFullFlush );
  108. }
  109. // Do we have anything batched?
  110. else if ( mTriangleCount > 0 )
  111. {
  112. // Yes, so do we have any existing colors?
  113. if ( mColorCount == 0 )
  114. {
  115. // No, so flush if color is specified.
  116. if ( color != NoColor )
  117. flush( mpDebugStats->batchColorStateFlush );
  118. }
  119. else
  120. {
  121. // Yes, so flush if color is not specified.
  122. if ( color == NoColor )
  123. flush( mpDebugStats->batchColorStateFlush );
  124. }
  125. }
  126. // Strict order mode?
  127. if ( mStrictOrderMode )
  128. {
  129. // Yes, so is there a texture change?
  130. if ( texture != mStrictOrderTextureHandle && mTriangleCount > 0 )
  131. {
  132. // Yes, so flush.
  133. flush( mpDebugStats->batchTextureChangeFlush );
  134. }
  135. // Fetch vertex index.
  136. U16 vertexIndex = (U16)mVertexCount;
  137. // Add new indices.
  138. for( U32 n = 0; n < triangleCount; ++n )
  139. {
  140. mIndexBuffer[mIndexCount++] = vertexIndex++;
  141. mIndexBuffer[mIndexCount++] = vertexIndex++;
  142. mIndexBuffer[mIndexCount++] = vertexIndex++;
  143. }
  144. // Set strict order mode texture handle.
  145. mStrictOrderTextureHandle = texture;
  146. }
  147. else
  148. {
  149. // No, so add triangle run.
  150. findTextureBatch( texture )->push_back( TriangleRun( TriangleRun::TRIANGLE, triangleCount, mVertexCount ) );
  151. }
  152. // Is a color specified?
  153. if ( color != NoColor )
  154. {
  155. // Yes, so add colors.
  156. for( U32 n = 0; n < triangleCount; ++n )
  157. {
  158. mColorBuffer[mColorCount++] = color;
  159. mColorBuffer[mColorCount++] = color;
  160. mColorBuffer[mColorCount++] = color;
  161. }
  162. }
  163. // Add textured vertices.
  164. for( U32 n = 0; n < triangleCount; ++n )
  165. {
  166. mVertexBuffer[mVertexCount++] = *(pVertexArray++);
  167. mVertexBuffer[mVertexCount++] = *(pVertexArray++);
  168. mVertexBuffer[mVertexCount++] = *(pVertexArray++);
  169. mTextureBuffer[mTextureCoordCount++] = *(pTextureArray++);
  170. mTextureBuffer[mTextureCoordCount++] = *(pTextureArray++);
  171. mTextureBuffer[mTextureCoordCount++] = *(pTextureArray++);
  172. }
  173. // Stats.
  174. mpDebugStats->batchTrianglesSubmitted += triangleCount;
  175. // Increase triangle count.
  176. mTriangleCount += triangleCount;
  177. // Have we reached the buffer limit?
  178. if ( mTriangleCount == BATCHRENDER_MAXTRIANGLES )
  179. {
  180. // Yes, so flush.
  181. flush( mpDebugStats->batchBufferFullFlush );
  182. }
  183. // Is batching enabled?
  184. else if ( !mBatchEnabled )
  185. {
  186. // No, so flush immediately.
  187. // NOTE: Technically this is still batching but will still revert to using
  188. // more draw calls therefore can be used in comparison.
  189. flushInternal();
  190. }
  191. }
  192. //-----------------------------------------------------------------------------
  193. void BatchRender::SubmitQuad(
  194. const Vector2& vertexPos0,
  195. const Vector2& vertexPos1,
  196. const Vector2& vertexPos2,
  197. const Vector2& vertexPos3,
  198. const Vector2& texturePos0,
  199. const Vector2& texturePos1,
  200. const Vector2& texturePos2,
  201. const Vector2& texturePos3,
  202. TextureHandle& texture,
  203. const ColorF& color )
  204. {
  205. // Sanity!
  206. AssertFatal( mpDebugStats != NULL, "Debug stats have not been configured." );
  207. // Debug Profiling.
  208. PROFILE_SCOPE(BatchRender_SubmitQuad);
  209. // Would we exceed the triangle buffer size?
  210. if ( (mTriangleCount + 2) > BATCHRENDER_MAXTRIANGLES )
  211. {
  212. // Yes, so flush.
  213. flush( mpDebugStats->batchBufferFullFlush );
  214. }
  215. // Do we have anything batched?
  216. else if ( mTriangleCount > 0 )
  217. {
  218. // Yes, so do we have any existing colors?
  219. if ( mColorCount == 0 )
  220. {
  221. // No, so flush if color is specified.
  222. if ( color != NoColor )
  223. flush( mpDebugStats->batchColorStateFlush );
  224. }
  225. else
  226. {
  227. // Yes, so flush if color is not specified.
  228. if ( color == NoColor )
  229. flush( mpDebugStats->batchColorStateFlush );
  230. }
  231. }
  232. // Strict order mode?
  233. if ( mStrictOrderMode )
  234. {
  235. // Yes, so is there a texture change?
  236. if ( texture != mStrictOrderTextureHandle && mTriangleCount > 0 )
  237. {
  238. // Yes, so flush.
  239. flush( mpDebugStats->batchTextureChangeFlush );
  240. }
  241. // Add new indices.
  242. mIndexBuffer[mIndexCount++] = (U16)mVertexCount++;
  243. mIndexBuffer[mIndexCount++] = (U16)mVertexCount++;
  244. mIndexBuffer[mIndexCount++] = (U16)mVertexCount++;
  245. mIndexBuffer[mIndexCount++] = (U16)mVertexCount--;
  246. mIndexBuffer[mIndexCount++] = (U16)mVertexCount--;
  247. mIndexBuffer[mIndexCount++] = (U16)mVertexCount--;
  248. // Set strict order mode texture handle.
  249. mStrictOrderTextureHandle = texture;
  250. }
  251. else
  252. {
  253. // No, so add triangle run.
  254. findTextureBatch( texture )->push_back( TriangleRun( TriangleRun::QUAD, 1, mVertexCount ) );
  255. }
  256. // Is a color specified?
  257. if ( color != NoColor )
  258. {
  259. // Yes, so add colors.
  260. mColorBuffer[mColorCount++] = color;
  261. mColorBuffer[mColorCount++] = color;
  262. mColorBuffer[mColorCount++] = color;
  263. mColorBuffer[mColorCount++] = color;
  264. }
  265. // Add textured vertices.
  266. // NOTE: We swap #2/#3 here.
  267. mVertexBuffer[mVertexCount++] = vertexPos0;
  268. mVertexBuffer[mVertexCount++] = vertexPos1;
  269. mVertexBuffer[mVertexCount++] = vertexPos3;
  270. mVertexBuffer[mVertexCount++] = vertexPos2;
  271. mTextureBuffer[mTextureCoordCount++] = texturePos0;
  272. mTextureBuffer[mTextureCoordCount++] = texturePos1;
  273. mTextureBuffer[mTextureCoordCount++] = texturePos3;
  274. mTextureBuffer[mTextureCoordCount++] = texturePos2;
  275. // Stats.
  276. mpDebugStats->batchTrianglesSubmitted+=2;
  277. // Increase triangle count.
  278. mTriangleCount += 2;
  279. // Have we reached the buffer limit?
  280. if ( mTriangleCount == BATCHRENDER_MAXTRIANGLES )
  281. {
  282. // Yes, so flush.
  283. flush( mpDebugStats->batchBufferFullFlush );
  284. }
  285. // Is batching enabled?
  286. else if ( !mBatchEnabled )
  287. {
  288. // No, so flush immediately.
  289. // NOTE: Technically this is still batching but will still revert to using
  290. // more draw calls therefore can be used in comparison.
  291. flushInternal();
  292. }
  293. }
  294. //-----------------------------------------------------------------------------
  295. void BatchRender::flush( U32& reasonMetric )
  296. {
  297. // Finish if no triangles to flush.
  298. if ( mTriangleCount == 0 )
  299. return;
  300. // Increase reason metric.
  301. reasonMetric++;
  302. // Flush.
  303. flushInternal();
  304. }
  305. //-----------------------------------------------------------------------------
  306. void BatchRender::flush( void )
  307. {
  308. // Finish if no triangles to flush.
  309. if ( mTriangleCount == 0 )
  310. return;
  311. // Increase reason metric.
  312. mpDebugStats->batchAnonymousFlush++;
  313. // Flush.
  314. flushInternal();
  315. }
  316. //-----------------------------------------------------------------------------
  317. void BatchRender::flushInternal( void )
  318. {
  319. // Debug Profiling.
  320. PROFILE_SCOPE(T2D_BatchRender_flush);
  321. // Finish if no triangles to flush.
  322. if ( mTriangleCount == 0 )
  323. return;
  324. // Stats.
  325. mpDebugStats->batchFlushes++;
  326. if ( mWireframeMode )
  327. {
  328. // Disable texturing.
  329. glDisable( GL_TEXTURE_2D );
  330. // Set the polygon mode to line.
  331. glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
  332. }
  333. else
  334. {
  335. // Enable texturing.
  336. glEnable( GL_TEXTURE_2D );
  337. glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
  338. // Set the polygon mode to fill.
  339. glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
  340. }
  341. // Set blend mode.
  342. if ( mBlendMode )
  343. {
  344. glEnable( GL_BLEND );
  345. glBlendFunc( mSrcBlendFactor, mDstBlendFactor );
  346. glColor4f(mBlendColor.red, mBlendColor.green, mBlendColor.blue, mBlendColor.alpha );
  347. }
  348. else
  349. {
  350. glDisable( GL_BLEND );
  351. glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
  352. }
  353. // Set alpha-blend mode.
  354. if ( mAlphaTestMode >= 0.0f )
  355. {
  356. glEnable( GL_ALPHA_TEST );
  357. glAlphaFunc( GL_GREATER, mAlphaTestMode );
  358. }
  359. else
  360. {
  361. glDisable( GL_ALPHA_TEST );
  362. }
  363. // Enable vertex and texture arrays.
  364. glEnableClientState( GL_VERTEX_ARRAY );
  365. glVertexPointer( 2, GL_FLOAT, 0, mVertexBuffer );
  366. glTexCoordPointer( 2, GL_FLOAT, 0, mTextureBuffer );
  367. // Use the texture coordinates if not in wireframe mode.
  368. if ( !mWireframeMode )
  369. glEnableClientState( GL_TEXTURE_COORD_ARRAY );
  370. // Do we have any colors?
  371. if ( mColorCount > 0 )
  372. {
  373. // Yes, so enable color array.
  374. glEnableClientState( GL_COLOR_ARRAY );
  375. glColorPointer( 4, GL_FLOAT, 0, mColorBuffer );
  376. }
  377. // Strict order mode?
  378. if ( mStrictOrderMode )
  379. {
  380. // Bind the texture if not in wireframe mode.
  381. if ( !mWireframeMode )
  382. glBindTexture( GL_TEXTURE_2D, mStrictOrderTextureHandle.getGLName() );
  383. // Draw the triangles
  384. glDrawElements( GL_TRIANGLES, mIndexCount, GL_UNSIGNED_SHORT, mIndexBuffer );
  385. // Stats.
  386. mpDebugStats->batchDrawCallsStrict++;
  387. // Stats.
  388. const U32 trianglesDrawn = mIndexCount / 3;
  389. if ( trianglesDrawn > mpDebugStats->batchMaxTriangleDrawn )
  390. mpDebugStats->batchMaxTriangleDrawn = trianglesDrawn;
  391. // Stats.
  392. if ( mVertexCount > mpDebugStats->batchMaxVertexBuffer )
  393. mpDebugStats->batchMaxVertexBuffer = mVertexCount;
  394. }
  395. else
  396. {
  397. // No, so iterate texture batch map.
  398. for( textureBatchType::iterator batchItr = mTextureBatchMap.begin(); batchItr != mTextureBatchMap.end(); ++batchItr )
  399. {
  400. // Reset index count.
  401. mIndexCount = 0;
  402. // Fetch index vector.
  403. indexVectorType* pIndexVector = batchItr->value;
  404. // Iterate indexes.
  405. for( indexVectorType::iterator indexItr = pIndexVector->begin(); indexItr != pIndexVector->end(); ++indexItr )
  406. {
  407. // Fetch triangle run.
  408. const TriangleRun& triangleRun = *indexItr;
  409. // Fetch primitivecount.
  410. const U32 primitiveCount = triangleRun.mPrimitiveCount;
  411. // Fetch triangle index start.
  412. U16 triangleIndex = (U16)triangleRun.mStartIndex;
  413. // Fetch primitive mode.
  414. const TriangleRun::PrimitiveMode& primitiveMode = triangleRun.mPrimitiveMode;
  415. // Handle primitive mode.
  416. if ( primitiveMode == TriangleRun::QUAD )
  417. {
  418. // Add triangle run for quad.
  419. for( U32 n = 0; n < primitiveCount; ++n )
  420. {
  421. // Add new indices.
  422. mIndexBuffer[mIndexCount++] = triangleIndex++;
  423. mIndexBuffer[mIndexCount++] = triangleIndex++;
  424. mIndexBuffer[mIndexCount++] = triangleIndex++;
  425. mIndexBuffer[mIndexCount++] = triangleIndex--;
  426. mIndexBuffer[mIndexCount++] = triangleIndex--;
  427. mIndexBuffer[mIndexCount++] = triangleIndex--;
  428. }
  429. }
  430. else if ( primitiveMode == TriangleRun::TRIANGLE )
  431. {
  432. // Add triangle run for triangles.
  433. for( U32 n = 0; n < primitiveCount; ++n )
  434. {
  435. // Add new indices.
  436. mIndexBuffer[mIndexCount++] = triangleIndex++;
  437. mIndexBuffer[mIndexCount++] = triangleIndex++;
  438. mIndexBuffer[mIndexCount++] = triangleIndex++;
  439. }
  440. }
  441. else
  442. {
  443. // Sanity!
  444. AssertFatal( false, "BatchRender::flushInternal() - Unrecognized primitive mode encountered for triangle run." );
  445. }
  446. }
  447. // Sanity!
  448. AssertFatal( mIndexCount > 0, "No batching indexes are present." );
  449. // Bind the texture if not in wireframe mode.
  450. if ( !mWireframeMode )
  451. glBindTexture( GL_TEXTURE_2D, batchItr->key );
  452. // Draw the triangles.
  453. glDrawElements( GL_TRIANGLES, mIndexCount, GL_UNSIGNED_SHORT, mIndexBuffer );
  454. // Stats.
  455. mpDebugStats->batchDrawCallsSorted++;
  456. // Stats.
  457. if ( mVertexCount > mpDebugStats->batchMaxVertexBuffer )
  458. mpDebugStats->batchMaxVertexBuffer = mVertexCount;
  459. // Stats.
  460. const U32 trianglesDrawn = mIndexCount / 3;
  461. if ( trianglesDrawn > mpDebugStats->batchMaxTriangleDrawn )
  462. mpDebugStats->batchMaxTriangleDrawn = trianglesDrawn;
  463. // Return index vector to pool.
  464. pIndexVector->clear();
  465. mIndexVectorPool.push_back( pIndexVector );
  466. }
  467. // Clear texture batch map.
  468. mTextureBatchMap.clear();
  469. }
  470. // Reset common render state.
  471. glDisableClientState( GL_VERTEX_ARRAY );
  472. glDisableClientState( GL_TEXTURE_COORD_ARRAY );
  473. glDisableClientState( GL_COLOR_ARRAY );
  474. glDisable( GL_ALPHA_TEST );
  475. glDisable( GL_BLEND );
  476. glDisable( GL_TEXTURE_2D );
  477. glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
  478. // Reset batch state.
  479. mTriangleCount = 0;
  480. mVertexCount = 0;
  481. mTextureCoordCount = 0;
  482. mIndexCount = 0;
  483. mColorCount = 0;
  484. }
  485. //-----------------------------------------------------------------------------
  486. BatchRender::indexVectorType* BatchRender::findTextureBatch( TextureHandle& handle )
  487. {
  488. // Fetch texture binding.
  489. const U32 textureBinding = handle.getGLName();
  490. indexVectorType* pIndexVector = NULL;
  491. // Find texture binding.
  492. textureBatchType::iterator itr = mTextureBatchMap.find( textureBinding );
  493. // Did we find a texture binding?
  494. if ( itr == mTextureBatchMap.end() )
  495. {
  496. // No, so fetch index vector pool count.
  497. const U32 indexVectorPoolCount = mIndexVectorPool.size();
  498. // Do we have any in the index vector pool?
  499. if ( indexVectorPoolCount > 0 )
  500. {
  501. // Yes, so use it.
  502. pIndexVector = mIndexVectorPool[indexVectorPoolCount-1];
  503. mIndexVectorPool.pop_back();
  504. }
  505. else
  506. {
  507. // No, so generate one.
  508. pIndexVector = new indexVectorType( 6 * 6 );
  509. }
  510. // Insert into texture batch map.
  511. mTextureBatchMap.insert( textureBinding, pIndexVector );
  512. }
  513. else
  514. {
  515. // Yes, so fetch it.
  516. pIndexVector = itr->value;
  517. }
  518. return pIndexVector;
  519. }