BatchRender.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  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. mQuadCount( 0 ),
  31. mVertexCount( 0 ),
  32. mTextureResidentCount( 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::SubmitQuad(
  89. const Vector2& vertexPos0,
  90. const Vector2& vertexPos1,
  91. const Vector2& vertexPos2,
  92. const Vector2& vertexPos3,
  93. const Vector2& texturePos0,
  94. const Vector2& texturePos1,
  95. const Vector2& texturePos2,
  96. const Vector2& texturePos3,
  97. TextureHandle& texture,
  98. const ColorF& color )
  99. {
  100. // Sanity!
  101. AssertFatal( mpDebugStats != NULL, "Debug stats have not been configured." );
  102. PROFILE_START(BatchRender_SubmitQuad);
  103. // Do we have anything batched?
  104. if ( mQuadCount > 0 )
  105. {
  106. // Yes, so do we have any existing colors?
  107. if ( mColorCount == 0 )
  108. {
  109. // No, so flush if color is specified.
  110. if ( color != NoColor )
  111. flush( mpDebugStats->batchColorStateFlush );
  112. }
  113. else
  114. {
  115. // Yes, so flush if color is not specified.
  116. if ( color == NoColor )
  117. flush( mpDebugStats->batchColorStateFlush );
  118. }
  119. }
  120. // Is a color specified?
  121. if ( color != NoColor )
  122. {
  123. // Yes, so add colors.
  124. mColorBuffer[mColorCount++] = color;
  125. mColorBuffer[mColorCount++] = color;
  126. mColorBuffer[mColorCount++] = color;
  127. mColorBuffer[mColorCount++] = color;
  128. }
  129. // Strict order mode?
  130. if ( mStrictOrderMode )
  131. {
  132. // Is there is a texture change.
  133. if ( texture != mStrictOrderTextureHandle )
  134. {
  135. // Yes, so flush.
  136. flush( mpDebugStats->batchTextureChangeFlush );
  137. }
  138. // Add new indices.
  139. mIndexBuffer[mIndexCount++] = (U16)mVertexCount++;
  140. mIndexBuffer[mIndexCount++] = (U16)mVertexCount++;
  141. mIndexBuffer[mIndexCount++] = (U16)mVertexCount++;
  142. mIndexBuffer[mIndexCount++] = (U16)mVertexCount--;
  143. mIndexBuffer[mIndexCount++] = (U16)mVertexCount--;
  144. mIndexBuffer[mIndexCount++] = (U16)mVertexCount--;
  145. // Set strict order mode texture handle.
  146. mStrictOrderTextureHandle = texture;
  147. }
  148. else
  149. {
  150. // No, so fetch texture binding.
  151. const U32 textureBinding = texture.getGLName();
  152. indexVectorType* pIndexVector = NULL;
  153. // Find texture binding.
  154. textureBatchType::iterator itr = mTextureBatchMap.find( textureBinding );
  155. // Did we find a texture binding?
  156. if ( itr == mTextureBatchMap.end() )
  157. {
  158. // No, so fetch index vector pool count.
  159. const U32 indexVectorPoolCount = mIndexVectorPool.size();
  160. // Do we have any in the index vector pool?
  161. if ( indexVectorPoolCount > 0 )
  162. {
  163. // Yes, so use it.
  164. pIndexVector = mIndexVectorPool[indexVectorPoolCount-1];
  165. mIndexVectorPool.pop_back();
  166. }
  167. else
  168. {
  169. // No, so generate one.
  170. pIndexVector = new indexVectorType( 6 * 6 );
  171. }
  172. // Insert into texture batch map.
  173. mTextureBatchMap.insert( textureBinding, pIndexVector );
  174. }
  175. else
  176. {
  177. // Yes, so fetch it.
  178. pIndexVector = itr->value;
  179. }
  180. // Add vertex start.
  181. pIndexVector->push_back( mVertexCount );
  182. }
  183. // Add textured vertices.
  184. // NOTE: We swap #2/#3 here.
  185. mVertexBuffer[mVertexCount++] = vertexPos0;
  186. mVertexBuffer[mVertexCount++] = vertexPos1;
  187. mVertexBuffer[mVertexCount++] = vertexPos3;
  188. mVertexBuffer[mVertexCount++] = vertexPos2;
  189. mTextureBuffer[mTextureResidentCount++] = texturePos0;
  190. mTextureBuffer[mTextureResidentCount++] = texturePos1;
  191. mTextureBuffer[mTextureResidentCount++] = texturePos3;
  192. mTextureBuffer[mTextureResidentCount++] = texturePos2;
  193. // Stats.
  194. mpDebugStats->batchTrianglesSubmitted+=2;
  195. // Increase quad count.
  196. mQuadCount++;
  197. // Have we reached the buffer limit?
  198. if ( mQuadCount == BATCHRENDER_MAXQUADS )
  199. {
  200. // Yes, so flush.
  201. flush( mpDebugStats->batchBufferFullFlush );
  202. }
  203. // Is batching enabled?
  204. if ( !mBatchEnabled )
  205. {
  206. // No, so flush immediately.
  207. // NOTE: Technically this is still batching but will still revert to using
  208. // more draw calls therefore can be used in comparison.
  209. flushInternal();
  210. }
  211. PROFILE_END(); // BatchRender_SubmitQuad
  212. }
  213. //-----------------------------------------------------------------------------
  214. void BatchRender::flush( U32& reasonMetric )
  215. {
  216. // Finish if no quads to flush.
  217. if ( mQuadCount == 0 )
  218. return;
  219. // Increase reason metric.
  220. reasonMetric++;
  221. // Flush.
  222. flushInternal();
  223. }
  224. //-----------------------------------------------------------------------------
  225. void BatchRender::flush( void )
  226. {
  227. // Finish if no quads to flush.
  228. if ( mQuadCount == 0 )
  229. return;
  230. // Increase reason metric.
  231. mpDebugStats->batchAnonymousFlush++;
  232. // Flush.
  233. flushInternal();
  234. }
  235. //-----------------------------------------------------------------------------
  236. void BatchRender::flushInternal( void )
  237. {
  238. // Finish if no quads to flush.
  239. if ( mQuadCount == 0 )
  240. return;
  241. PROFILE_START(T2D_BatchRender_flush);
  242. // Stats.
  243. mpDebugStats->batchFlushes++;
  244. if ( mWireframeMode )
  245. {
  246. // Disable texturing.
  247. glDisable( GL_TEXTURE_2D );
  248. // Set the polygon mode to line.
  249. glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
  250. }
  251. else
  252. {
  253. // Enable texturing.
  254. glEnable( GL_TEXTURE_2D );
  255. glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
  256. // Set the polygon mode to fill.
  257. glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
  258. }
  259. // Set blend mode.
  260. if ( mBlendMode )
  261. {
  262. glEnable( GL_BLEND );
  263. glBlendFunc( mSrcBlendFactor, mDstBlendFactor );
  264. glColor4f(mBlendColor.red, mBlendColor.green, mBlendColor.blue, mBlendColor.alpha );
  265. }
  266. else
  267. {
  268. glDisable( GL_BLEND );
  269. glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
  270. }
  271. // Set alpha-blend mode.
  272. if ( mAlphaTestMode >= 0.0f )
  273. {
  274. glEnable( GL_ALPHA_TEST );
  275. glAlphaFunc( GL_GREATER, mAlphaTestMode );
  276. }
  277. else
  278. {
  279. glDisable( GL_ALPHA_TEST );
  280. }
  281. // Enable vertex and texture arrays.
  282. glEnableClientState( GL_VERTEX_ARRAY );
  283. glVertexPointer( 2, GL_FLOAT, 0, mVertexBuffer );
  284. glTexCoordPointer( 2, GL_FLOAT, 0, mTextureBuffer );
  285. // Use the texture coordinates if not in wireframe mode.
  286. if ( !mWireframeMode )
  287. glEnableClientState( GL_TEXTURE_COORD_ARRAY );
  288. // Do we have any colors?
  289. if ( mColorCount > 0 )
  290. {
  291. // Yes, so enable color array.
  292. glEnableClientState( GL_COLOR_ARRAY );
  293. glColorPointer( 4, GL_FLOAT, 0, mColorBuffer );
  294. }
  295. // Strict order mode?
  296. if ( mStrictOrderMode )
  297. {
  298. // Bind the texture if not in wireframe mode.
  299. if ( !mWireframeMode )
  300. glBindTexture( GL_TEXTURE_2D, mStrictOrderTextureHandle.getGLName() );
  301. // Yes, so do we have a single quad?
  302. if ( mQuadCount == 1 )
  303. {
  304. // Yes, so draw the quad using a triangle-strip with indexes.
  305. glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
  306. // Stats.
  307. mpDebugStats->batchDrawCallsStrictSingle++;
  308. // Stats.
  309. if ( mpDebugStats->batchMaxTriangleDrawn < 2 )
  310. mpDebugStats->batchMaxTriangleDrawn = 2;
  311. }
  312. else
  313. {
  314. // Draw the quads using triangles with indexes.
  315. glDrawElements( GL_TRIANGLES, mIndexCount, GL_UNSIGNED_SHORT, mIndexBuffer );
  316. // Stats.
  317. mpDebugStats->batchDrawCallsStrictMultiple++;
  318. // Stats.
  319. const U32 trianglesDrawn = mIndexCount / 3;
  320. if ( trianglesDrawn > mpDebugStats->batchMaxTriangleDrawn )
  321. mpDebugStats->batchMaxTriangleDrawn = trianglesDrawn;
  322. }
  323. // Stats.
  324. if ( mVertexCount > mpDebugStats->batchMaxVertexBuffer )
  325. mpDebugStats->batchMaxVertexBuffer = mVertexCount;
  326. }
  327. else
  328. {
  329. // No, so iterate texture batch map.
  330. for( textureBatchType::iterator batchItr = mTextureBatchMap.begin(); batchItr != mTextureBatchMap.end(); ++batchItr )
  331. {
  332. // Fetch texture binding.
  333. const U32 textureBinding = batchItr->key;
  334. // Fetch index vector.
  335. indexVectorType* pIndexVector = batchItr->value;
  336. // Reset index count.
  337. mIndexCount = 0;
  338. // Iterate indexes.
  339. for( indexVectorType::iterator indexItr = pIndexVector->begin(); indexItr != pIndexVector->end(); ++indexItr )
  340. {
  341. // Fetch quad index.
  342. U32 quadIndex = (*indexItr);
  343. // Add new indices.
  344. mIndexBuffer[mIndexCount++] = (U16)quadIndex++;
  345. mIndexBuffer[mIndexCount++] = (U16)quadIndex++;
  346. mIndexBuffer[mIndexCount++] = (U16)quadIndex++;
  347. mIndexBuffer[mIndexCount++] = (U16)quadIndex--;
  348. mIndexBuffer[mIndexCount++] = (U16)quadIndex--;
  349. mIndexBuffer[mIndexCount++] = (U16)quadIndex;
  350. }
  351. // Sanity!
  352. AssertFatal( mIndexCount > 0, "No batching indexes are present." );
  353. // Bind the texture if not in wireframe mode.
  354. if ( !mWireframeMode )
  355. glBindTexture( GL_TEXTURE_2D, textureBinding );
  356. // Draw the quads using triangles with indexes.
  357. glDrawElements( GL_TRIANGLES, mIndexCount, GL_UNSIGNED_SHORT, mIndexBuffer );
  358. // Stats.
  359. mpDebugStats->batchDrawCallsSorted++;
  360. // Stats.
  361. if ( mVertexCount > mpDebugStats->batchMaxVertexBuffer )
  362. mpDebugStats->batchMaxVertexBuffer = mVertexCount;
  363. // Stats.
  364. const U32 trianglesDrawn = mIndexCount / 3;
  365. if ( trianglesDrawn > mpDebugStats->batchMaxTriangleDrawn )
  366. mpDebugStats->batchMaxTriangleDrawn = trianglesDrawn;
  367. // Return index vector to pool.
  368. pIndexVector->clear();
  369. mIndexVectorPool.push_back( pIndexVector );
  370. }
  371. // Clear texture batch map.
  372. mTextureBatchMap.clear();
  373. }
  374. // Reset common render state.
  375. glDisableClientState( GL_VERTEX_ARRAY );
  376. glDisableClientState( GL_TEXTURE_COORD_ARRAY );
  377. glDisableClientState( GL_COLOR_ARRAY );
  378. glDisable( GL_ALPHA_TEST );
  379. glDisable( GL_BLEND );
  380. glDisable( GL_TEXTURE_2D );
  381. glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
  382. // Reset batch state.
  383. mQuadCount = 0;
  384. mVertexCount = 0;
  385. mTextureResidentCount = 0;
  386. mIndexCount = 0;
  387. mColorCount = 0;
  388. PROFILE_END(); // T2D_BatchRender_flush
  389. }
  390. //-----------------------------------------------------------------------------
  391. void BatchRender::RenderQuad(
  392. const Vector2& vertexPos0,
  393. const Vector2& vertexPos1,
  394. const Vector2& vertexPos2,
  395. const Vector2& vertexPos3,
  396. const Vector2& texturePos0,
  397. const Vector2& texturePos1,
  398. const Vector2& texturePos2,
  399. const Vector2& texturePos3 )
  400. {
  401. glBegin( GL_TRIANGLE_STRIP );
  402. glTexCoord2f( texturePos0.x, texturePos0.y );
  403. glVertex2f( vertexPos0.x, vertexPos0.y );
  404. glTexCoord2f( texturePos1.x, texturePos1.y );
  405. glVertex2f( vertexPos1.x, vertexPos1.y );
  406. glTexCoord2f( texturePos3.x, texturePos3.y );
  407. glVertex2f( vertexPos3.x, vertexPos3.y );
  408. glTexCoord2f( texturePos2.x, texturePos2.y );
  409. glVertex2f( vertexPos2.x, vertexPos2.y );
  410. glEnd();
  411. }