BatchRender.cc 20 KB

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