Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

6092 lines
166 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. // TOGL CODE LICENSE
  3. //
  4. // Copyright 2011-2014 Valve Corporation
  5. // All Rights Reserved.
  6. //
  7. // Permission is hereby granted, free of charge, to any person obtaining a copy
  8. // of this software and associated documentation files (the "Software"), to deal
  9. // in the Software without restriction, including without limitation the rights
  10. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. // copies of the Software, and to permit persons to whom the Software is
  12. // furnished to do so, subject to the following conditions:
  13. //
  14. // The above copyright notice and this permission notice shall be included in
  15. // all copies or substantial portions of the Software.
  16. //
  17. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. // THE SOFTWARE.
  24. //
  25. // glmgr.cpp
  26. //
  27. //===============================================================================
  28. #include "togl/rendermechanism.h"
  29. #include "tier0/icommandline.h"
  30. #include "tier0/vprof.h"
  31. #include "glmtexinlines.h"
  32. #include "materialsystem/IShader.h"
  33. #include "appframework/ilaunchermgr.h"
  34. #include "convar.h"
  35. #include "glmgr_flush.inl"
  36. #ifdef OSX
  37. #include <OpenGL/OpenGL.h>
  38. #include "intelglmallocworkaround.h"
  39. #endif
  40. // memdbgon -must- be the last include file in a .cpp file.
  41. #include "tier0/memdbgon.h"
  42. // Whether the code should use gl_arb_debug_output. This causes error messages to be streamed, via callback, to the application.
  43. // It is much friendlier to the MTGL driver.
  44. // NOTE: This can be turned off after launch, but it cannot be turned on after launch--it implies a context-creation-time
  45. // behavior.
  46. ConVar gl_debug_output( "gl_debug_output", "1" );
  47. // Whether or not we should batch up our creation and deletion behavior.
  48. ConVar gl_batch_tex_creates( "gl_batch_tex_creates", "0" );
  49. ConVar gl_batch_tex_destroys( "gl_batch_tex_destroys", "0" );
  50. //===============================================================================
  51. // g_nTotalDrawsOrClears is reset to 0 in Present()
  52. uint g_nTotalDrawsOrClears, g_nTotalVBLockBytes, g_nTotalIBLockBytes;
  53. #if GL_TELEMETRY_GPU_ZONES
  54. TelemetryGPUStats_t g_TelemetryGPUStats;
  55. #endif
  56. const int kGLMInitialTexCount = 4096;
  57. const int kGLMReUpTexCount = 1024;
  58. const int kGLMHighWaterUndeleted = 2048;
  59. const int kDeletedTextureDim = 4;
  60. const uint32 g_garbageTextureBits[ 4 * kDeletedTextureDim * kDeletedTextureDim ] = { 0 };
  61. char g_nullFragmentProgramText [] =
  62. {
  63. "!!ARBfp1.0 \n"
  64. "PARAM black = { 0.0, 0.0, 0.0, 1.0 }; \n" // opaque black
  65. "MOV result.color, black; \n"
  66. "END \n\n\n"
  67. "//GLSLfp\n"
  68. "void main()\n"
  69. "{\n"
  70. "gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n"
  71. "}\n"
  72. };
  73. // make dummy programs for doing texture preload via dummy draw
  74. char g_preloadTexVertexProgramText[] =
  75. {
  76. "//GLSLvp \n"
  77. "#version 120 \n"
  78. "varying vec4 otex; \n"
  79. "void main() \n"
  80. "{ \n"
  81. "vec4 pos = ftransform(); // vec4( 0.1, 0.1, 0.1, 0.1 ); \n"
  82. "vec4 tex = vec4( 0.0, 0.0, 0.0, 0.0 ); \n"
  83. " \n"
  84. "gl_Position = pos; \n"
  85. "otex = tex; \n"
  86. "} \n"
  87. };
  88. char g_preload2DTexFragmentProgramText[] =
  89. {
  90. "//GLSLfp \n"
  91. "#version 120 \n"
  92. "varying vec4 otex; \n"
  93. "//SAMPLERMASK-8000 // may not be needed \n"
  94. "//HIGHWATER-30 // may not be needed \n"
  95. " \n"
  96. "uniform vec4 pc[31]; \n"
  97. "uniform sampler2D sampler15; \n"
  98. " \n"
  99. "void main() \n"
  100. "{ \n"
  101. "vec4 r0; \n"
  102. "r0 = texture2D( sampler15, otex.xy ); \n"
  103. "gl_FragColor = r0; //discard; \n"
  104. "} \n"
  105. };
  106. char g_preload3DTexFragmentProgramText[] =
  107. {
  108. "//GLSLfp \n"
  109. "#version 120 \n"
  110. "varying vec4 otex; \n"
  111. "//SAMPLERMASK-8000 // may not be needed \n"
  112. "//HIGHWATER-30 // may not be needed \n"
  113. " \n"
  114. "uniform vec4 pc[31]; \n"
  115. "uniform sampler3D sampler15; \n"
  116. " \n"
  117. "void main() \n"
  118. "{ \n"
  119. "vec4 r0; \n"
  120. "r0 = texture3D( sampler15, otex.xyz ); \n"
  121. "gl_FragColor = r0; //discard; \n"
  122. "} \n"
  123. };
  124. char g_preloadCubeTexFragmentProgramText[] =
  125. {
  126. "//GLSLfp \n"
  127. "#version 120 \n"
  128. "varying vec4 otex; \n"
  129. "//SAMPLERMASK-8000 // may not be needed \n"
  130. "//HIGHWATER-30 // may not be needed \n"
  131. " \n"
  132. "uniform vec4 pc[31]; \n"
  133. "uniform samplerCube sampler15; \n"
  134. " \n"
  135. "void main() \n"
  136. "{ \n"
  137. "vec4 r0; \n"
  138. "r0 = textureCube( sampler15, otex.xyz ); \n"
  139. "gl_FragColor = r0; //discard; \n"
  140. "} \n"
  141. };
  142. const char* glSourceToString(GLenum source)
  143. {
  144. switch (source)
  145. {
  146. case GL_DEBUG_SOURCE_API_ARB: return "API";
  147. case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB: return "WINDOW_SYSTEM";
  148. case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB: return "SHADER_COMPILER";
  149. case GL_DEBUG_SOURCE_THIRD_PARTY_ARB: return "THIRD_PARTY";
  150. case GL_DEBUG_SOURCE_APPLICATION_ARB: return "APPLICATION";
  151. case GL_DEBUG_SOURCE_OTHER_ARB: return "OTHER";
  152. default: break;
  153. }
  154. return "UNKNOWN";
  155. }
  156. const char* glTypeToString(GLenum type)
  157. {
  158. switch (type)
  159. {
  160. case GL_DEBUG_TYPE_ERROR_ARB: return "ERROR";
  161. case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB: return "DEPRECATION";
  162. case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB: return "UNDEFINED_BEHAVIOR";
  163. case GL_DEBUG_TYPE_PORTABILITY_ARB: return "PORTABILITY";
  164. case GL_DEBUG_TYPE_PERFORMANCE_ARB: return "PERFORMANCE";
  165. case GL_DEBUG_TYPE_OTHER_ARB: return "OTHER";
  166. default: break;
  167. }
  168. return "UNKNOWN";
  169. }
  170. const char* glSeverityToString(GLenum severity)
  171. {
  172. switch (severity)
  173. {
  174. case GL_DEBUG_SEVERITY_HIGH_ARB: return "HIGH";
  175. case GL_DEBUG_SEVERITY_MEDIUM_ARB: return "MEDIUM";
  176. case GL_DEBUG_SEVERITY_LOW_ARB: return "LOW";
  177. default: break;
  178. }
  179. return "UNKNOWN";
  180. }
  181. bool g_bDebugOutputBreakpoints = true;
  182. void APIENTRY GL_Debug_Output_Callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, GLvoid* userParam)
  183. {
  184. const char *sSource = glSourceToString(source),
  185. *sType = glTypeToString(type),
  186. *sSeverity = glSeverityToString(severity);
  187. // According to NVidia, this error is a bug in the driver and not really an error (it's a warning in newer drivers): "Texture X is base level inconsistent. Check texture size"
  188. if ( ( type == GL_DEBUG_TYPE_ERROR_ARB ) && strstr( message, "base level inconsistent" ) )
  189. {
  190. return;
  191. }
  192. if ( gl_debug_output.GetBool() || type == GL_DEBUG_TYPE_ERROR_ARB )
  193. {
  194. Msg( "GL: [%s][%s][%s][%d]: %s\n", sSource, sType, sSeverity, id, message );
  195. }
  196. #ifdef WIN32
  197. OutputDebugStringA( message );
  198. #endif
  199. if ( ( type == GL_DEBUG_TYPE_ERROR_ARB ) && ( g_bDebugOutputBreakpoints ) )
  200. {
  201. DebuggerBreak();
  202. }
  203. }
  204. void GLMDebugPrintf( const char *pMsg, ... )
  205. {
  206. //$ TODO: Should this call Warning()?
  207. //$ TODO: Should replace call these calls with Warning() / Msg() / DevMsg()?
  208. va_list args;
  209. va_start( args, pMsg );
  210. vprintf( pMsg, args );
  211. va_end( args );
  212. }
  213. //===============================================================================
  214. // functions that are dependant on g_pLauncherMgr
  215. inline bool MakeContextCurrent( PseudoGLContextPtr hContext )
  216. {
  217. return g_pLauncherMgr->MakeContextCurrent( hContext );
  218. }
  219. inline PseudoGLContextPtr GetMainContext()
  220. {
  221. return g_pLauncherMgr->GetMainContext();
  222. }
  223. inline PseudoGLContextPtr GetGLContextForWindow( void* windowref )
  224. {
  225. return g_pLauncherMgr->GetGLContextForWindow( windowref );
  226. }
  227. inline void IncrementWindowRefCount()
  228. {
  229. g_pLauncherMgr->IncWindowRefCount();
  230. }
  231. inline void DecrementWindowRefCount()
  232. {
  233. g_pLauncherMgr->DecWindowRefCount();
  234. }
  235. inline void ShowPixels( CShowPixelsParams *params )
  236. {
  237. g_pLauncherMgr->ShowPixels(params);
  238. }
  239. inline void DisplayedSize( uint &width, uint &height )
  240. {
  241. g_pLauncherMgr->DisplayedSize( width, height );
  242. }
  243. inline void GetDesiredPixelFormatAttribsAndRendererInfo( uint **ptrOut, uint *countOut, GLMRendererInfoFields *rendInfoOut )
  244. {
  245. g_pLauncherMgr->GetDesiredPixelFormatAttribsAndRendererInfo( ptrOut, countOut, rendInfoOut );
  246. }
  247. inline void GetStackCrawl( CStackCrawlParams *params )
  248. {
  249. g_pLauncherMgr->GetStackCrawl(params);
  250. }
  251. #if GLMDEBUG
  252. inline void PumpWindowsMessageLoop()
  253. {
  254. g_pLauncherMgr->PumpWindowsMessageLoop();
  255. }
  256. inline int GetEvents( CCocoaEvent *pEvents, int nMaxEventsToReturn, bool debugEvents = false )
  257. {
  258. return g_pLauncherMgr->GetEvents( pEvents, nMaxEventsToReturn, debugEvents );
  259. }
  260. #endif
  261. //===============================================================================
  262. // helper routines for debug
  263. static bool hasnonzeros( float *values, int count )
  264. {
  265. for( int i=0; i<count; i++)
  266. {
  267. if (values[i] != 0.0)
  268. {
  269. return true;
  270. }
  271. }
  272. return false;
  273. }
  274. static void printmat( char *label, int baseSlotNumber, int slots, float *m00 )
  275. {
  276. // print label..
  277. // fetch 4 from row, print as a row
  278. // fetch 4 from column, print as a row
  279. float row[4];
  280. float col[4];
  281. if (hasnonzeros( m00, slots*4) )
  282. {
  283. GLMPRINTF(("-D- %s", label ));
  284. for( int islot=0; islot<4; islot++ ) // we always run this loop til 4, but we special case the printing if there are only 3 submitted
  285. {
  286. // extract row and column floats
  287. for( int slotcol=0; slotcol<4; slotcol++)
  288. {
  289. //copy
  290. row[slotcol] = m00[(islot*4)+slotcol];
  291. // transpose
  292. col[slotcol] = m00[(slotcol*4)+islot];
  293. }
  294. if (slots==4)
  295. {
  296. GLMPRINTF(( "-D- %03d: [ %10.5f %10.5f %10.5f %10.5f ] T=> [ %10.5f %10.5f %10.5f %10.5f ]",
  297. baseSlotNumber+islot,
  298. row[0],row[1],row[2],row[3],
  299. col[0],col[1],col[2],col[3]
  300. ));
  301. }
  302. else
  303. {
  304. if (islot<3)
  305. {
  306. GLMPRINTF(( "-D- %03d: [ %10.5f %10.5f %10.5f %10.5f ] T=> [ %10.5f %10.5f %10.5f ]",
  307. baseSlotNumber+islot,
  308. row[0],row[1],row[2],row[3],
  309. col[0],col[1],col[2]
  310. ));
  311. }
  312. else
  313. {
  314. GLMPRINTF(( "-D- %03d: T=> [ %10.5f %10.5f %10.5f ]",
  315. baseSlotNumber+islot,
  316. col[0],col[1],col[2]
  317. ));
  318. }
  319. }
  320. }
  321. GLMPRINTSTR(("-D-"));
  322. }
  323. else
  324. {
  325. GLMPRINTF(("-D- %s - (all 0.0)", label ));
  326. }
  327. }
  328. static void transform_dp4( float *in4, float *m00, int slots, float *out4 )
  329. {
  330. // m00 points to a column.
  331. // each DP is one column of the matrix ( m00[4*n]
  332. // if we are passed a three slot matrix, this is three columns, the source W plays into all three columns, but we must set the final output W to 1 ?
  333. for( int n=0; n<slots; n++)
  334. {
  335. float col4[4];
  336. col4[0] = m00[(4*n)+0];
  337. col4[1] = m00[(4*n)+1];
  338. col4[2] = m00[(4*n)+2];
  339. col4[3] = m00[(4*n)+3];
  340. out4[n] = 0.0;
  341. for( int inner = 0; inner < 4; inner++ )
  342. {
  343. out4[n] += in4[inner] * col4[inner];
  344. }
  345. }
  346. if (slots==3)
  347. {
  348. out4[3] = 1.0;
  349. }
  350. }
  351. //===============================================================================
  352. //===============================================================================
  353. // GLMgr static methods
  354. GLMgr *g_glmgr = NULL;
  355. void GLMgr::NewGLMgr( void )
  356. {
  357. if (!g_glmgr)
  358. {
  359. #if GLMDEBUG
  360. // check debug mode early in program lifetime
  361. GLMDebugInitialize( true );
  362. #endif
  363. g_glmgr = new GLMgr;
  364. }
  365. }
  366. GLMgr *GLMgr::aGLMgr( void )
  367. {
  368. assert( g_glmgr != NULL);
  369. return g_glmgr;
  370. }
  371. void GLMgr::DelGLMgr( void )
  372. {
  373. if (g_glmgr)
  374. {
  375. delete g_glmgr;
  376. g_glmgr = NULL;
  377. }
  378. }
  379. // GLMgr class methods
  380. GLMgr::GLMgr()
  381. {
  382. }
  383. GLMgr::~GLMgr()
  384. {
  385. }
  386. //===============================================================================
  387. GLMContext *GLMgr::NewContext( IDirect3DDevice9 *pDevice, GLMDisplayParams *params )
  388. {
  389. // this now becomes really simple. We just pass through the params.
  390. return new GLMContext( pDevice, params );
  391. }
  392. void GLMgr::DelContext( GLMContext *context )
  393. {
  394. delete context;
  395. }
  396. void GLMgr::SetCurrentContext( GLMContext *context )
  397. {
  398. #if defined( USE_SDL )
  399. context->m_nCurOwnerThreadId = ThreadGetCurrentId();
  400. if ( !MakeContextCurrent( context->m_ctx ) )
  401. {
  402. // give up
  403. GLMStop();
  404. }
  405. Assert( 0 );
  406. #endif
  407. }
  408. GLMContext *GLMgr::GetCurrentContext( void )
  409. {
  410. #if defined( USE_SDL )
  411. PseudoGLContextPtr context = GetMainContext();
  412. return (GLMContext*) context;
  413. #else
  414. Assert( 0 );
  415. return NULL;
  416. #endif
  417. }
  418. // #define CHECK_THREAD_USAGE 1
  419. //===============================================================================
  420. // GLMContext public methods
  421. void GLMContext::MakeCurrent( bool bRenderThread )
  422. {
  423. tmZone( TELEMETRY_LEVEL0, 0, "GLMContext::MakeCurrent" );
  424. Assert( m_nCurOwnerThreadId == 0 || m_nCurOwnerThreadId == ThreadGetCurrentId() );
  425. #if defined( USE_SDL )
  426. #ifndef CHECK_THREAD_USAGE
  427. if ( bRenderThread )
  428. {
  429. // Msg( "******************************************** %08x Acquiring Context\n", ThreadGetCurrentId() );
  430. m_nCurOwnerThreadId = ThreadGetCurrentId();
  431. bool bSuccess = MakeContextCurrent( m_ctx );
  432. if ( !bSuccess )
  433. {
  434. Assert( 0 );
  435. }
  436. }
  437. #else
  438. uint32 dwThreadId = ThreadGetCurrentId();
  439. if ( bRenderThread || dwThreadId == m_dwRenderThreadId )
  440. {
  441. m_nCurOwnerThreadId = ThreadGetCurrentId();
  442. m_dwRenderThreadId = dwThreadId;
  443. MakeContextCurrent( m_ctx );
  444. m_bIsThreading = true;
  445. }
  446. else if ( !m_bIsThreading )
  447. {
  448. m_nCurOwnerThreadId = ThreadGetCurrentId();
  449. MakeContextCurrent( m_ctx );
  450. }
  451. else
  452. {
  453. Assert( 0 );
  454. }
  455. #endif
  456. #else
  457. Assert( 0 );
  458. #endif
  459. }
  460. void GLMContext::ReleaseCurrent( bool bRenderThread )
  461. {
  462. tmZone( TELEMETRY_LEVEL0, 0, "GLMContext::ReleaseCurrent" );
  463. Assert( m_nCurOwnerThreadId == ThreadGetCurrentId() );
  464. #if defined( USE_SDL )
  465. #ifndef CHECK_THREAD_USAGE
  466. if ( bRenderThread )
  467. {
  468. // Msg( "******************************************** %08x Releasing Context\n", ThreadGetCurrentId() );
  469. m_nCurOwnerThreadId = 0;
  470. m_nThreadOwnershipReleaseCounter++;
  471. MakeContextCurrent( NULL );
  472. }
  473. #else
  474. m_nCurOwnerThreadId = 0;
  475. m_nThreadOwnershipReleaseCounter++;
  476. MakeContextCurrent( NULL );
  477. if ( bRenderThread )
  478. {
  479. m_bIsThreading = false;
  480. }
  481. #endif
  482. #else
  483. Assert( 0 );
  484. #endif
  485. }
  486. // This function forces all GL state to be re-sent to the context. Some state will only be set on the next batch flush.
  487. void GLMContext::ForceFlushStates()
  488. {
  489. // Flush various render states
  490. m_AlphaTestEnable.Flush();
  491. m_AlphaTestFunc.Flush();
  492. m_DepthBias.Flush();
  493. m_ScissorEnable.Flush();
  494. m_ScissorBox.Flush();
  495. m_ViewportBox.Flush();
  496. m_ViewportDepthRange.Flush();
  497. m_ColorMaskSingle.Flush();
  498. m_BlendEnable.Flush();
  499. m_BlendFactor.Flush();
  500. m_BlendEnableSRGB.Flush();
  501. m_DepthTestEnable.Flush();
  502. m_DepthFunc.Flush();
  503. m_DepthMask.Flush();
  504. m_StencilTestEnable.Flush();
  505. m_StencilFunc.Flush();
  506. m_StencilOp.Flush();
  507. m_StencilWriteMask.Flush();
  508. m_ClearColor.Flush();
  509. m_ClearDepth.Flush();
  510. m_ClearStencil.Flush();
  511. m_ClipPlaneEnable.Flush(); // always push clip state
  512. m_ClipPlaneEquation.Flush();
  513. m_CullFaceEnable.Flush();
  514. m_CullFrontFace.Flush();
  515. m_PolygonMode.Flush();
  516. m_AlphaToCoverageEnable.Flush();
  517. m_ColorMaskMultiple.Flush();
  518. m_BlendEquation.Flush();
  519. m_BlendColor.Flush();
  520. // Reset various things so they get reset on the next batch flush
  521. m_activeTexture = -1;
  522. for ( int i = 0; i < GLM_SAMPLER_COUNT; i++ )
  523. {
  524. SetSamplerTex( i, m_samplers[i].m_pBoundTex );
  525. SetSamplerDirty( i );
  526. }
  527. // Attributes/vertex attribs
  528. ClearCurAttribs();
  529. m_lastKnownVertexAttribMask = 0;
  530. m_nNumSetVertexAttributes = 16;
  531. memset( &m_boundVertexAttribs[0], 0xFF, sizeof( m_boundVertexAttribs ) );
  532. for( int index=0; index < kGLMVertexAttributeIndexMax; index++ )
  533. gGL->glDisableVertexAttribArray( index );
  534. // Program
  535. NullProgram();
  536. // FBO
  537. BindFBOToCtx( m_boundReadFBO, GL_READ_FRAMEBUFFER_EXT );
  538. BindFBOToCtx( m_boundDrawFBO, GL_DRAW_FRAMEBUFFER_EXT );
  539. // Current VB/IB/pinned memory buffers
  540. gGL->glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, m_nBoundGLBuffer[ kGLMIndexBuffer] );
  541. gGL->glBindBufferARB( GL_ARRAY_BUFFER_ARB, m_nBoundGLBuffer[ kGLMVertexBuffer] );
  542. #ifndef OSX
  543. if ( gGL->m_bHave_GL_AMD_pinned_memory )
  544. {
  545. gGL->glBindBufferARB( GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, m_PinnedMemoryBuffers[m_nCurPinnedMemoryBuffer].GetHandle() );
  546. }
  547. #endif
  548. }
  549. const GLMRendererInfoFields& GLMContext::Caps( void )
  550. {
  551. return m_caps;
  552. }
  553. void GLMContext::DumpCaps( void )
  554. {
  555. /*
  556. #define dumpfield( fff ) printf( "\n "#fff" : %d", (int) m_caps.fff )
  557. #define dumpfield_hex( fff ) printf( "\n "#fff" : 0x%08x", (int) m_caps.fff )
  558. #define dumpfield_str( fff ) printf( "\n "#fff" : %s", m_caps.fff )
  559. */
  560. #define dumpfield( fff ) printf( "\n %-30s : %d", #fff, (int) m_caps.fff )
  561. #define dumpfield_hex( fff ) printf( "\n %-30s : 0x%08x", #fff, (int) m_caps.fff )
  562. #define dumpfield_str( fff ) printf( "\n %-30s : %s", #fff, m_caps.fff )
  563. printf("\n-------------------------------- context caps for context %08x", (uint)this);
  564. dumpfield( m_fullscreen );
  565. dumpfield( m_accelerated );
  566. dumpfield( m_windowed );
  567. dumpfield_hex( m_rendererID );
  568. dumpfield( m_displayMask );
  569. dumpfield( m_bufferModes );
  570. dumpfield( m_colorModes );
  571. dumpfield( m_accumModes );
  572. dumpfield( m_depthModes );
  573. dumpfield( m_stencilModes );
  574. dumpfield( m_maxAuxBuffers );
  575. dumpfield( m_maxSampleBuffers );
  576. dumpfield( m_maxSamples );
  577. dumpfield( m_sampleModes );
  578. dumpfield( m_sampleAlpha );
  579. dumpfield_hex( m_vidMemory );
  580. dumpfield_hex( m_texMemory );
  581. dumpfield_hex( m_pciVendorID );
  582. dumpfield_hex( m_pciDeviceID );
  583. dumpfield_str( m_pciModelString );
  584. dumpfield_str( m_driverInfoString );
  585. printf( "\n m_osComboVersion: 0x%08x (%d.%d.%d)", m_caps.m_osComboVersion, (m_caps.m_osComboVersion>>16)&0xFF, (m_caps.m_osComboVersion>>8)&0xFF, (m_caps.m_osComboVersion)&0xFF );
  586. dumpfield( m_ati );
  587. if (m_caps.m_ati)
  588. {
  589. dumpfield( m_atiR5xx );
  590. dumpfield( m_atiR6xx );
  591. dumpfield( m_atiR7xx );
  592. dumpfield( m_atiR8xx );
  593. dumpfield( m_atiNewer );
  594. }
  595. dumpfield( m_intel );
  596. if (m_caps.m_intel)
  597. {
  598. dumpfield( m_intel95x );
  599. dumpfield( m_intel3100 );
  600. dumpfield( m_intelHD4000 );
  601. }
  602. dumpfield( m_nv );
  603. if (m_caps.m_nv)
  604. {
  605. //dumpfield( m_nvG7x );
  606. dumpfield( m_nvG8x );
  607. dumpfield( m_nvNewer );
  608. }
  609. dumpfield( m_hasGammaWrites );
  610. dumpfield( m_hasMixedAttachmentSizes );
  611. dumpfield( m_hasBGRA );
  612. dumpfield( m_hasNewFullscreenMode );
  613. dumpfield( m_hasNativeClipVertexMode );
  614. dumpfield( m_maxAniso );
  615. dumpfield( m_hasBindableUniforms );
  616. dumpfield( m_maxVertexBindableUniforms );
  617. dumpfield( m_maxFragmentBindableUniforms );
  618. dumpfield( m_maxBindableUniformSize );
  619. dumpfield( m_hasUniformBuffers );
  620. dumpfield( m_hasPerfPackage1 );
  621. dumpfield( m_cantBlitReliably );
  622. dumpfield( m_cantAttachSRGB );
  623. dumpfield( m_cantResolveFlipped );
  624. dumpfield( m_cantResolveScaled );
  625. dumpfield( m_costlyGammaFlips );
  626. dumpfield( m_badDriver1064NV );
  627. dumpfield( m_badDriver108Intel );
  628. printf("\n--------------------------------");
  629. #undef dumpfield
  630. #undef dumpfield_hex
  631. #undef dumpfield_str
  632. }
  633. CGLMTex *GLMContext::NewTex( GLMTexLayoutKey *key, uint levels, const char *debugLabel )
  634. {
  635. // get a layout based on the key
  636. GLMTexLayout *layout = m_texLayoutTable->NewLayoutRef( key );
  637. CGLMTex *tex = new CGLMTex( this, layout, levels, debugLabel );
  638. return tex;
  639. }
  640. void GLMContext::DelTex( CGLMTex * tex )
  641. {
  642. //Queue the texture for deletion in ProcessTextureDeletes
  643. //when we are sure we will hold the context.
  644. m_DeleteTextureQueue.PushItem(tex);
  645. }
  646. void GLMContext::ProcessTextureDeletes()
  647. {
  648. #if GL_TELEMETRY_GPU_ZONES
  649. CScopedGLMPIXEvent glmEvent( "GLMContext::ProcessTextureDeletes" );
  650. #endif
  651. CGLMTex* tex = nullptr;
  652. while ( m_DeleteTextureQueue.PopItem( &tex ) )
  653. {
  654. for( int i = 0; i < GLM_SAMPLER_COUNT; i++)
  655. {
  656. if ( m_samplers[i].m_pBoundTex == tex )
  657. {
  658. BindTexToTMU( NULL, i );
  659. }
  660. }
  661. if ( tex->m_rtAttachCount != 0 )
  662. {
  663. // RG - huh? wtf? TODO: fix this code which seems to be purposely leaking
  664. // leak it and complain - we may have to implement a deferred-delete system for tex like these
  665. GLMDebugPrintf("GLMContext::DelTex: Leaking tex %08x [ %s ] - was attached for drawing at time of delete",tex, tex->m_layout->m_layoutSummary );
  666. #if 0
  667. // can't actually do this yet as the draw calls will tank
  668. FOR_EACH_VEC( m_fboTable, i )
  669. {
  670. CGLMFBO *fbo = m_fboTable[i];
  671. fbo->TexScrub( tex );
  672. }
  673. tex->m_rtAttachCount = 0;
  674. #endif
  675. }
  676. else
  677. {
  678. delete tex;
  679. }
  680. }
  681. }
  682. // push and pop attrib when blit has mixed srgb source and dest?
  683. ConVar gl_radar7954721_workaround_mixed ( "gl_radar7954721_workaround_mixed", "1" );
  684. // push and pop attrib on any blit?
  685. ConVar gl_radar7954721_workaround_all ( "gl_radar7954721_workaround_all", "0" );
  686. // what attrib mask to use ?
  687. ConVar gl_radar7954721_workaround_maskval ( "gl_radar7954721_workaround_maskval", "0" );
  688. enum eBlitFormatClass
  689. {
  690. eColor,
  691. eDepth, // may not get used. not sure..
  692. eDepthStencil
  693. };
  694. uint glAttachFromClass[ 3 ] = { GL_COLOR_ATTACHMENT0_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_DEPTH_STENCIL_ATTACHMENT_EXT };
  695. void glScrubFBO ( GLenum target )
  696. {
  697. gGL->glFramebufferRenderbufferEXT ( target, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, 0);
  698. gGL->glFramebufferRenderbufferEXT ( target, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
  699. gGL->glFramebufferRenderbufferEXT ( target, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
  700. gGL->glFramebufferTexture2DEXT ( target, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 0, 0 );
  701. gGL->glFramebufferTexture2DEXT ( target, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0 );
  702. gGL->glFramebufferTexture2DEXT ( target, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0 );
  703. }
  704. void glAttachRBOtoFBO ( GLenum target, eBlitFormatClass formatClass, uint rboName )
  705. {
  706. switch( formatClass )
  707. {
  708. case eColor:
  709. gGL->glFramebufferRenderbufferEXT ( target, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, rboName);
  710. break;
  711. case eDepth:
  712. gGL->glFramebufferRenderbufferEXT ( target, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, rboName);
  713. break;
  714. case eDepthStencil:
  715. gGL->glFramebufferRenderbufferEXT ( target, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, rboName);
  716. gGL->glFramebufferRenderbufferEXT ( target, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, rboName);
  717. break;
  718. }
  719. }
  720. void glAttachTex2DtoFBO ( GLenum target, eBlitFormatClass formatClass, uint texName, uint texMip )
  721. {
  722. switch( formatClass )
  723. {
  724. case eColor:
  725. gGL->glFramebufferTexture2DEXT ( target, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texName, texMip );
  726. break;
  727. case eDepth:
  728. gGL->glFramebufferTexture2DEXT ( target, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, texName, texMip );
  729. break;
  730. case eDepthStencil:
  731. gGL->glFramebufferTexture2DEXT ( target, GL_DEPTH_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, texName, texMip );
  732. break;
  733. }
  734. }
  735. ConVar gl_can_resolve_flipped("gl_can_resolve_flipped", "0" );
  736. ConVar gl_cannot_resolve_flipped("gl_cannot_resolve_flipped", "0" );
  737. // these are only consulted if the m_cant_resolve_scaled cap bool is false.
  738. ConVar gl_minify_resolve_mode("gl_minify_resolve_mode", "1" ); // if scaled resolve available, for downscaled resolve blits only (i.e. internal blits)
  739. ConVar gl_magnify_resolve_mode("gl_magnify_resolve_mode", "2" ); // if scaled resolve available, for upscaled resolve blits only
  740. // 0 == old style, two steps
  741. // 1 == faster, one step blit aka XGL_SCALED_RESOLVE_FASTEST_EXT - if available.
  742. // 2 == faster, one step blit aka XGL_SCALED_RESOLVE_NICEST_EXT - if available.
  743. void GLMContext::SaveColorMaskAndSetToDefault()
  744. {
  745. // NVidia's driver doesn't ignore the colormask during blitframebuffer calls, so we need to save/restore it:
  746. // “The bug here is that our driver fails to ignore colormask for BlitFramebuffer calls. This was unclear in the original spec, but we resolved it in Khronos last year (https://cvs.khronos.org/bugzilla/show_bug.cgi?id=7969).”
  747. m_ColorMaskSingle.Read( &m_SavedColorMask, 0 );
  748. GLColorMaskSingle_t newColorMask;
  749. newColorMask.r = newColorMask.g = newColorMask.b = newColorMask.a = -1;
  750. m_ColorMaskSingle.Write( &newColorMask );
  751. }
  752. void GLMContext::RestoreSavedColorMask()
  753. {
  754. m_ColorMaskSingle.Write( &m_SavedColorMask );
  755. }
  756. void GLMContext::Blit2( CGLMTex *srcTex, GLMRect *srcRect, int srcFace, int srcMip, CGLMTex *dstTex, GLMRect *dstRect, int dstFace, int dstMip, uint filter )
  757. {
  758. #if GL_TELEMETRY_GPU_ZONES
  759. CScopedGLMPIXEvent glmPIXEvent( "Blit2" );
  760. g_TelemetryGPUStats.m_nTotalBlit2++;
  761. #endif
  762. SaveColorMaskAndSetToDefault();
  763. Assert( srcFace == 0 );
  764. Assert( dstFace == 0 );
  765. //----------------------------------------------------------------- format assessment
  766. eBlitFormatClass formatClass = eColor;
  767. uint blitMask= 0;
  768. switch( srcTex->m_layout->m_format->m_glDataFormat )
  769. {
  770. case GL_RED: case GL_BGRA: case GL_RGB: case GL_RGBA: case GL_ALPHA: case GL_LUMINANCE: case GL_LUMINANCE_ALPHA:
  771. formatClass = eColor;
  772. blitMask = GL_COLOR_BUFFER_BIT;
  773. break;
  774. case GL_DEPTH_COMPONENT:
  775. formatClass = eDepth;
  776. blitMask = GL_DEPTH_BUFFER_BIT;
  777. break;
  778. case GL_DEPTH_STENCIL_EXT:
  779. formatClass = eDepthStencil;
  780. blitMask = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
  781. break;
  782. default:
  783. Assert(!"Unsupported format for blit" );
  784. GLMStop();
  785. break;
  786. }
  787. //----------------------------------------------------------------- blit assessment
  788. bool blitResolves = srcTex->m_rboName != 0;
  789. bool blitScales = ((srcRect->xmax - srcRect->xmin) != (dstRect->xmax - dstRect->xmin)) || ((srcRect->ymax - srcRect->ymin) != (dstRect->ymax - dstRect->ymin));
  790. bool blitToBack = (dstTex == NULL);
  791. bool blitFlips = blitToBack; // implicit y-flip upon blit to GL_BACK supplied
  792. //should we support blitFromBack ?
  793. bool srcGamma = srcTex && ((srcTex->m_layout->m_key.m_texFlags & kGLMTexSRGB) != 0);
  794. bool dstGamma = dstTex && ((dstTex->m_layout->m_key.m_texFlags & kGLMTexSRGB) != 0);
  795. bool doPushPop = (srcGamma != dstGamma) && gl_radar7954721_workaround_mixed.GetInt() && m_caps.m_nv; // workaround for cross gamma blit problems on NV
  796. // ^^ need to re-check this on some post-10.6.3 build on NV to see if it was fixed
  797. if (doPushPop)
  798. {
  799. gGL->glPushAttrib( 0 );
  800. }
  801. //----------------------------------------------------------------- figure out the plan
  802. bool blitTwoStep = false; // think positive
  803. // each subsequent segment here can only set blitTwoStep, not clear it.
  804. // the common case where these get hit is resolve out to presentation
  805. // there may be GL extensions or driver revisions which start doing these safely.
  806. // ideally many blits internally resolve without scaling and can thus go direct without using the scratch tex.
  807. if (blitResolves && (blitFlips||blitToBack)) // flips, blit to back, same thing (for now)
  808. {
  809. if( gl_cannot_resolve_flipped.GetInt() )
  810. {
  811. blitTwoStep = true;
  812. }
  813. else if (!gl_can_resolve_flipped.GetInt())
  814. {
  815. blitTwoStep = blitTwoStep || m_caps.m_cantResolveFlipped; // if neither convar renders an opinion, fall back to the caps to decide if we have to two-step.
  816. }
  817. }
  818. // only consider trying to use the scaling resolve filter,
  819. // if we are confident we are not headed for two step mode already.
  820. if (!blitTwoStep)
  821. {
  822. if (blitResolves && blitScales)
  823. {
  824. if (m_caps.m_cantResolveScaled)
  825. {
  826. // filter is unchanged, two step mode switches on
  827. blitTwoStep = true;
  828. }
  829. else
  830. {
  831. bool blitScalesDown = ((srcRect->xmax - srcRect->xmin) > (dstRect->xmax - dstRect->xmin)) || ((srcRect->ymax - srcRect->ymin) > (dstRect->ymax - dstRect->ymin));
  832. int mode = (blitScalesDown) ? gl_minify_resolve_mode.GetInt() : gl_magnify_resolve_mode.GetInt();
  833. // roughly speaking, resolve blits that minify represent setup for special effects ("copy framebuffer to me")
  834. // resolve blits that magnify are almost always on the final present in the case where remder size < display size
  835. switch( mode )
  836. {
  837. case 0:
  838. default:
  839. // filter is unchanged, two step mode
  840. blitTwoStep = true;
  841. break;
  842. case 1:
  843. // filter goes to fastest, one step mode
  844. blitTwoStep = false;
  845. filter = XGL_SCALED_RESOLVE_FASTEST_EXT;
  846. break;
  847. case 2:
  848. // filter goes to nicest, one step mode
  849. blitTwoStep = false;
  850. filter = XGL_SCALED_RESOLVE_NICEST_EXT;
  851. break;
  852. }
  853. }
  854. }
  855. }
  856. //----------------------------------------------------------------- save old scissor state and disable scissor
  857. GLScissorEnable_t oldsciss,newsciss;
  858. m_ScissorEnable.Read( &oldsciss, 0 );
  859. if (oldsciss.enable)
  860. {
  861. // turn off scissor
  862. newsciss.enable = false;
  863. m_ScissorEnable.Write( &newsciss );
  864. }
  865. //----------------------------------------------------------------- fork in the road, depending on two-step or not
  866. if (blitTwoStep)
  867. {
  868. // a resolve that can't be done directly due to constraints on scaling or flipping.
  869. // bind scratch FBO0 to read, scrub it, attach RBO
  870. BindFBOToCtx ( m_scratchFBO[0], GL_READ_FRAMEBUFFER_EXT );
  871. glScrubFBO ( GL_READ_FRAMEBUFFER_EXT );
  872. glAttachRBOtoFBO ( GL_READ_FRAMEBUFFER_EXT, formatClass, srcTex->m_rboName );
  873. // bind scratch FBO1 to write, scrub it, attach scratch tex
  874. BindFBOToCtx ( m_scratchFBO[1], GL_DRAW_FRAMEBUFFER_EXT );
  875. glScrubFBO ( GL_DRAW_FRAMEBUFFER_EXT );
  876. glAttachTex2DtoFBO ( GL_DRAW_FRAMEBUFFER_EXT, formatClass, srcTex->m_texName, 0 );
  877. // set read and draw buffers appropriately
  878. gGL->glReadBuffer ( glAttachFromClass[formatClass] );
  879. gGL->glDrawBuffer ( glAttachFromClass[formatClass] );
  880. // blit#1 - to resolve to scratch
  881. // implicitly means no scaling, thus will be done with NEAREST sampling
  882. GLenum resolveFilter = GL_NEAREST;
  883. gGL->glBlitFramebufferEXT( 0, 0, srcTex->m_layout->m_key.m_xSize, srcTex->m_layout->m_key.m_ySize,
  884. 0, 0, srcTex->m_layout->m_key.m_xSize, srcTex->m_layout->m_key.m_ySize, // same source and dest rect, whole surface
  885. blitMask, resolveFilter );
  886. // FBO1 now holds the interesting content.
  887. // scrub FBO0, bind FBO1 to READ, fall through to next stage of blit where 1 goes onto 0 (or BACK)
  888. glScrubFBO ( GL_READ_FRAMEBUFFER_EXT ); // zap FBO0
  889. BindFBOToCtx ( m_scratchFBO[1], GL_READ_FRAMEBUFFER_EXT );
  890. srcTex->ForceRBONonDirty();
  891. }
  892. else
  893. {
  894. #if 1
  895. if (srcTex->m_pBlitSrcFBO == NULL)
  896. {
  897. srcTex->m_pBlitSrcFBO = NewFBO();
  898. BindFBOToCtx( srcTex->m_pBlitSrcFBO, GL_READ_FRAMEBUFFER_EXT );
  899. if (blitResolves)
  900. {
  901. glAttachRBOtoFBO( GL_READ_FRAMEBUFFER_EXT, formatClass, srcTex->m_rboName );
  902. }
  903. else
  904. {
  905. glAttachTex2DtoFBO( GL_READ_FRAMEBUFFER_EXT, formatClass, srcTex->m_texName, srcMip );
  906. }
  907. }
  908. else
  909. {
  910. BindFBOToCtx ( srcTex->m_pBlitSrcFBO, GL_READ_FRAMEBUFFER_EXT );
  911. // GLMCheckError();
  912. }
  913. #else
  914. // arrange source surface on FBO1 for blit directly to dest (which could be FBO0 or BACK)
  915. BindFBOToCtx( m_scratchFBO[1], GL_READ_FRAMEBUFFER_EXT );
  916. glScrubFBO( GL_READ_FRAMEBUFFER_EXT );
  917. GLMCheckError();
  918. if (blitResolves)
  919. {
  920. glAttachRBOtoFBO( GL_READ_FRAMEBUFFER_EXT, formatClass, srcTex->m_rboName );
  921. }
  922. else
  923. {
  924. glAttachTex2DtoFBO( GL_READ_FRAMEBUFFER_EXT, formatClass, srcTex->m_texName, srcMip );
  925. }
  926. #endif
  927. gGL->glReadBuffer( glAttachFromClass[formatClass] );
  928. }
  929. //----------------------------------------------------------------- zero or one blits may have happened above, whichever took place, FBO1 is now on read
  930. bool yflip = false;
  931. if (blitToBack)
  932. {
  933. // backbuffer is special - FBO0 is left out (either scrubbed already, or not used)
  934. BindFBOToCtx ( NULL, GL_DRAW_FRAMEBUFFER_EXT );
  935. gGL->glDrawBuffer ( GL_BACK );
  936. yflip = true;
  937. }
  938. else
  939. {
  940. // not going to GL_BACK - use FBO0. set up dest tex or RBO on it. i.e. it's OK to blit from MSAA to MSAA if needed, though unlikely.
  941. Assert( dstTex != NULL );
  942. #if 1
  943. if (dstTex->m_pBlitDstFBO == NULL)
  944. {
  945. dstTex->m_pBlitDstFBO = NewFBO();
  946. BindFBOToCtx( dstTex->m_pBlitDstFBO, GL_DRAW_FRAMEBUFFER_EXT );
  947. if (dstTex->m_rboName)
  948. {
  949. glAttachRBOtoFBO( GL_DRAW_FRAMEBUFFER_EXT, formatClass, dstTex->m_rboName );
  950. }
  951. else
  952. {
  953. glAttachTex2DtoFBO( GL_DRAW_FRAMEBUFFER_EXT, formatClass, dstTex->m_texName, dstMip );
  954. }
  955. }
  956. else
  957. {
  958. BindFBOToCtx( dstTex->m_pBlitDstFBO, GL_DRAW_FRAMEBUFFER_EXT );
  959. }
  960. #else
  961. BindFBOToCtx( m_scratchFBO[0], GL_DRAW_FRAMEBUFFER_EXT ); GLMCheckError();
  962. glScrubFBO( GL_DRAW_FRAMEBUFFER_EXT );
  963. if (dstTex->m_rboName)
  964. {
  965. glAttachRBOtoFBO( GL_DRAW_FRAMEBUFFER_EXT, formatClass, dstTex->m_rboName );
  966. }
  967. else
  968. {
  969. glAttachTex2DtoFBO( GL_DRAW_FRAMEBUFFER_EXT, formatClass, dstTex->m_texName, dstMip );
  970. }
  971. gGL->glDrawBuffer ( glAttachFromClass[formatClass] ); GLMCheckError();
  972. #endif
  973. }
  974. // final blit
  975. // i think in general, if we are blitting same size, gl_nearest is the right filter to pass.
  976. // this re-steering won't kick in if there is scaling or a special scaled resolve going on.
  977. if (!blitScales)
  978. {
  979. // steer it
  980. filter = GL_NEAREST;
  981. }
  982. // this is blit #1 or #2 depending on what took place above.
  983. if (yflip)
  984. {
  985. gGL->glBlitFramebufferEXT( srcRect->xmin, srcRect->ymin, srcRect->xmax, srcRect->ymax,
  986. dstRect->xmin, dstRect->ymax, dstRect->xmax, dstRect->ymin, // note dest Y's are flipped
  987. blitMask, filter );
  988. }
  989. else
  990. {
  991. gGL->glBlitFramebufferEXT( srcRect->xmin, srcRect->ymin, srcRect->xmax, srcRect->ymax,
  992. dstRect->xmin, dstRect->ymin, dstRect->xmax, dstRect->ymax,
  993. blitMask, filter );
  994. }
  995. //----------------------------------------------------------------- scrub READ and maybe DRAW FBO, and unbind
  996. // glScrubFBO ( GL_READ_FRAMEBUFFER_EXT );
  997. BindFBOToCtx ( NULL, GL_READ_FRAMEBUFFER_EXT );
  998. if (!blitToBack)
  999. {
  1000. // glScrubFBO ( GL_DRAW_FRAMEBUFFER_EXT );
  1001. BindFBOToCtx ( NULL, GL_DRAW_FRAMEBUFFER_EXT );
  1002. }
  1003. //----------------------------------------------------------------- restore GLM's drawing FBO
  1004. // restore GLM drawing FBO
  1005. BindFBOToCtx( m_drawingFBO, GL_FRAMEBUFFER_EXT );
  1006. if (doPushPop)
  1007. {
  1008. gGL->glPopAttrib( );
  1009. }
  1010. //----------------------------------------------------------------- restore old scissor state
  1011. if (oldsciss.enable)
  1012. {
  1013. m_ScissorEnable.Write( &oldsciss );
  1014. }
  1015. RestoreSavedColorMask();
  1016. }
  1017. void GLMContext::BlitTex( CGLMTex *srcTex, GLMRect *srcRect, int srcFace, int srcMip, CGLMTex *dstTex, GLMRect *dstRect, int dstFace, int dstMip, GLenum filter, bool useBlitFB )
  1018. {
  1019. // This path doesn't work anymore (or did it ever work in the L4D2 Linux branch?)
  1020. DXABSTRACT_BREAK_ON_ERROR();
  1021. return;
  1022. SaveColorMaskAndSetToDefault();
  1023. switch( srcTex->m_layout->m_format->m_glDataFormat )
  1024. {
  1025. case GL_BGRA:
  1026. case GL_RGB:
  1027. case GL_RGBA:
  1028. case GL_ALPHA:
  1029. case GL_LUMINANCE:
  1030. case GL_LUMINANCE_ALPHA:
  1031. #if 0
  1032. if (GLMKnob("caps-key",NULL) > 0.0)
  1033. {
  1034. useBlitFB = false;
  1035. }
  1036. #endif
  1037. if ( m_caps.m_cantBlitReliably ) // this is referring to a problem with the x3100..
  1038. {
  1039. useBlitFB = false;
  1040. }
  1041. break;
  1042. }
  1043. if (0)
  1044. {
  1045. GLMPRINTF(("-D- Blit from %d %d %d %d to %d %d %d %d",
  1046. srcRect->xmin, srcRect->ymin, srcRect->xmax, srcRect->ymax,
  1047. dstRect->xmin, dstRect->ymin, dstRect->xmax, dstRect->ymax
  1048. ));
  1049. GLMPRINTF(( "-D- src tex layout is %s", srcTex->m_layout->m_layoutSummary ));
  1050. GLMPRINTF(( "-D- dst tex layout is %s", dstTex->m_layout->m_layoutSummary ));
  1051. }
  1052. int pushed = 0;
  1053. uint pushmask = gl_radar7954721_workaround_maskval.GetInt();
  1054. //GL_COLOR_BUFFER_BIT
  1055. //| GL_CURRENT_BIT
  1056. //| GL_ENABLE_BIT
  1057. //| GL_FOG_BIT
  1058. //| GL_PIXEL_MODE_BIT
  1059. //| GL_SCISSOR_BIT
  1060. //| GL_STENCIL_BUFFER_BIT
  1061. //| GL_TEXTURE_BIT
  1062. //GL_VIEWPORT_BIT
  1063. //;
  1064. if (gl_radar7954721_workaround_all.GetInt()!=0)
  1065. {
  1066. gGL->glPushAttrib( pushmask );
  1067. pushed++;
  1068. }
  1069. else
  1070. {
  1071. bool srcGamma = (srcTex->m_layout->m_key.m_texFlags & kGLMTexSRGB) != 0;
  1072. bool dstGamma = (dstTex->m_layout->m_key.m_texFlags & kGLMTexSRGB) != 0;
  1073. if (srcGamma != dstGamma)
  1074. {
  1075. if (gl_radar7954721_workaround_mixed.GetInt())
  1076. {
  1077. gGL->glPushAttrib( pushmask );
  1078. pushed++;
  1079. }
  1080. }
  1081. }
  1082. if (useBlitFB)
  1083. {
  1084. // state we need to save
  1085. // current setting of scissor
  1086. // current setting of the drawing fbo (no explicit save, it's in the context)
  1087. GLScissorEnable_t oldsciss,newsciss;
  1088. m_ScissorEnable.Read( &oldsciss, 0 );
  1089. // remember to restore m_drawingFBO at end of effort
  1090. // setup
  1091. // turn off scissor
  1092. newsciss.enable = false;
  1093. m_ScissorEnable.Write( &newsciss );
  1094. // select which attachment enum we're going to use for the blit
  1095. // default to color0, unless it's a depth or stencil flava
  1096. Assert( srcTex->m_layout->m_format->m_glDataFormat == dstTex->m_layout->m_format->m_glDataFormat );
  1097. EGLMFBOAttachment attachIndex = (EGLMFBOAttachment)0;
  1098. GLenum attachIndexGL = 0;
  1099. GLuint blitMask = 0;
  1100. switch( srcTex->m_layout->m_format->m_glDataFormat )
  1101. {
  1102. case GL_BGRA:
  1103. case GL_RGB:
  1104. case GL_RGBA:
  1105. case GL_ALPHA:
  1106. case GL_LUMINANCE:
  1107. case GL_LUMINANCE_ALPHA:
  1108. attachIndex = kAttColor0;
  1109. attachIndexGL = GL_COLOR_ATTACHMENT0_EXT;
  1110. blitMask = GL_COLOR_BUFFER_BIT;
  1111. break;
  1112. case GL_DEPTH_COMPONENT:
  1113. attachIndex = kAttDepth;
  1114. attachIndexGL = GL_DEPTH_ATTACHMENT_EXT;
  1115. blitMask = GL_DEPTH_BUFFER_BIT;
  1116. break;
  1117. case GL_DEPTH_STENCIL_EXT:
  1118. attachIndex = kAttDepthStencil;
  1119. attachIndexGL = GL_DEPTH_STENCIL_ATTACHMENT_EXT;
  1120. blitMask = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
  1121. break;
  1122. default:
  1123. Assert(0);
  1124. break;
  1125. }
  1126. // set the read fb, attach read tex at appropriate attach point, set read buffer
  1127. BindFBOToCtx( m_blitReadFBO, GL_READ_FRAMEBUFFER_EXT );
  1128. GLMFBOTexAttachParams attparams;
  1129. attparams.m_tex = srcTex;
  1130. attparams.m_face = srcFace;
  1131. attparams.m_mip = srcMip;
  1132. attparams.m_zslice = 0;
  1133. m_blitReadFBO->TexAttach( &attparams, attachIndex, GL_READ_FRAMEBUFFER_EXT );
  1134. gGL->glReadBuffer( attachIndexGL );
  1135. // set the write fb and buffer, and attach write tex
  1136. BindFBOToCtx( m_blitDrawFBO, GL_DRAW_FRAMEBUFFER_EXT );
  1137. attparams.m_tex = dstTex;
  1138. attparams.m_face = dstFace;
  1139. attparams.m_mip = dstMip;
  1140. attparams.m_zslice = 0;
  1141. m_blitDrawFBO->TexAttach( &attparams, attachIndex, GL_DRAW_FRAMEBUFFER_EXT );
  1142. gGL->glDrawBuffer( attachIndexGL );
  1143. // do the blit
  1144. gGL->glBlitFramebufferEXT( srcRect->xmin, srcRect->ymin, srcRect->xmax, srcRect->ymax,
  1145. dstRect->xmin, dstRect->ymin, dstRect->xmax, dstRect->ymax,
  1146. blitMask, filter );
  1147. // cleanup
  1148. // unset the read fb and buffer, detach read tex
  1149. // unset the write fb and buffer, detach write tex
  1150. m_blitReadFBO->TexDetach( attachIndex, GL_READ_FRAMEBUFFER_EXT );
  1151. m_blitDrawFBO->TexDetach( attachIndex, GL_DRAW_FRAMEBUFFER_EXT );
  1152. // put the original FB back in place (both read and draw)
  1153. // this bind will hit both read and draw bindings
  1154. BindFBOToCtx( m_drawingFBO, GL_FRAMEBUFFER_EXT );
  1155. // set the read and write buffers back to... what ? does it matter for anything but copies ? don't worry about it
  1156. // restore the scissor state
  1157. m_ScissorEnable.Write( &oldsciss );
  1158. }
  1159. else
  1160. {
  1161. // textured quad style
  1162. // we must attach the dest tex as the color buffer on the blit draw FBO
  1163. // so that means we need to re-set the drawing FBO on exit
  1164. EGLMFBOAttachment attachIndex = (EGLMFBOAttachment)0;
  1165. GLenum attachIndexGL = 0;
  1166. switch( srcTex->m_layout->m_format->m_glDataFormat )
  1167. {
  1168. case GL_BGRA:
  1169. case GL_RGB:
  1170. case GL_RGBA:
  1171. case GL_ALPHA:
  1172. case GL_LUMINANCE:
  1173. case GL_LUMINANCE_ALPHA:
  1174. attachIndex = kAttColor0;
  1175. attachIndexGL = GL_COLOR_ATTACHMENT0_EXT;
  1176. break;
  1177. default:
  1178. Assert(!"Can't blit that format");
  1179. break;
  1180. }
  1181. BindFBOToCtx( m_blitDrawFBO, GL_DRAW_FRAMEBUFFER_EXT );
  1182. GLMFBOTexAttachParams attparams;
  1183. attparams.m_tex = dstTex;
  1184. attparams.m_face = dstFace;
  1185. attparams.m_mip = dstMip;
  1186. attparams.m_zslice = 0;
  1187. m_blitDrawFBO->TexAttach( &attparams, attachIndex, GL_DRAW_FRAMEBUFFER_EXT );
  1188. gGL->glDrawBuffer( attachIndexGL );
  1189. // attempt to just set states directly the way we want them, then use the latched states to repair them afterward.
  1190. NullProgram(); // out of program mode
  1191. gGL->glDisable ( GL_ALPHA_TEST );
  1192. gGL->glDisable ( GL_CULL_FACE );
  1193. gGL->glDisable ( GL_POLYGON_OFFSET_FILL );
  1194. gGL->glDisable ( GL_SCISSOR_TEST );
  1195. gGL->glDisable ( GL_CLIP_PLANE0 );
  1196. gGL->glDisable ( GL_CLIP_PLANE1 );
  1197. gGL->glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
  1198. gGL->glDisable ( GL_BLEND );
  1199. gGL->glDepthMask ( GL_FALSE );
  1200. gGL->glDisable ( GL_DEPTH_TEST );
  1201. gGL->glDisable ( GL_STENCIL_TEST );
  1202. gGL->glStencilMask ( GL_FALSE );
  1203. // now do the unlit textured quad...
  1204. gGL->glActiveTexture( GL_TEXTURE0 );
  1205. gGL->glBindTexture( GL_TEXTURE_2D, srcTex->m_texName );
  1206. gGL->glEnable(GL_TEXTURE_2D);
  1207. // immediate mode is fine
  1208. float topv = 1.0;
  1209. float botv = 0.0;
  1210. gGL->glBegin(GL_QUADS);
  1211. gGL->glTexCoord2f ( 0.0, botv );
  1212. gGL->glVertex3f ( -1.0, -1.0, 0.0 );
  1213. gGL->glTexCoord2f ( 1.0, botv );
  1214. gGL->glVertex3f ( 1.0, -1.0, 0.0 );
  1215. gGL->glTexCoord2f ( 1.0, topv );
  1216. gGL->glVertex3f ( 1.0, 1.0, 0.0 );
  1217. gGL->glTexCoord2f ( 0.0, topv );
  1218. gGL->glVertex3f ( -1.0, 1.0, 0.0 );
  1219. gGL->glEnd();
  1220. gGL->glBindTexture( GL_TEXTURE_2D, 0 );
  1221. gGL->glDisable(GL_TEXTURE_2D);
  1222. BindTexToTMU( m_samplers[0].m_pBoundTex, 0 );
  1223. // leave active program empty - flush draw states will fix
  1224. // then restore states using the scoreboard
  1225. m_AlphaTestEnable.Flush();
  1226. m_AlphaToCoverageEnable.Flush();
  1227. m_CullFaceEnable.Flush();
  1228. m_DepthBias.Flush();
  1229. m_ScissorEnable.Flush();
  1230. m_ClipPlaneEnable.FlushIndex( 0 );
  1231. m_ClipPlaneEnable.FlushIndex( 1 );
  1232. m_ColorMaskSingle.Flush();
  1233. m_BlendEnable.Flush();
  1234. m_DepthMask.Flush();
  1235. m_DepthTestEnable.Flush();
  1236. m_StencilWriteMask.Flush();
  1237. m_StencilTestEnable.Flush();
  1238. // unset the write fb and buffer, detach write tex
  1239. m_blitDrawFBO->TexDetach( attachIndex, GL_DRAW_FRAMEBUFFER_EXT );
  1240. // put the original FB back in place (both read and draw)
  1241. BindFBOToCtx( m_drawingFBO, GL_FRAMEBUFFER_EXT );
  1242. }
  1243. while(pushed)
  1244. {
  1245. gGL->glPopAttrib();
  1246. pushed--;
  1247. }
  1248. RestoreSavedColorMask();
  1249. }
  1250. void GLMContext::ResolveTex( CGLMTex *tex, bool forceDirty )
  1251. {
  1252. #if GL_TELEMETRY_GPU_ZONES
  1253. CScopedGLMPIXEvent glmPIXEvent( "ResolveTex" );
  1254. g_TelemetryGPUStats.m_nTotalResolveTex++;
  1255. #endif
  1256. // only run resolve if it's (a) possible and (b) dirty or force-dirtied
  1257. if ( ( tex->m_rboName ) && ( tex->IsRBODirty() || forceDirty ) )
  1258. {
  1259. // state we need to save
  1260. // current setting of scissor
  1261. // current setting of the drawing fbo (no explicit save, it's in the context)
  1262. GLScissorEnable_t oldsciss,newsciss;
  1263. m_ScissorEnable.Read( &oldsciss, 0 );
  1264. // remember to restore m_drawingFBO at end of effort
  1265. // setup
  1266. // turn off scissor
  1267. newsciss.enable = false;
  1268. m_ScissorEnable.Write( &newsciss );
  1269. // select which attachment enum we're going to use for the blit
  1270. // default to color0, unless it's a depth or stencil flava
  1271. // for resolve, only handle a modest subset of the possible formats
  1272. EGLMFBOAttachment attachIndex = (EGLMFBOAttachment)0;
  1273. GLenum attachIndexGL = 0;
  1274. GLuint blitMask = 0;
  1275. switch( tex->m_layout->m_format->m_glDataFormat )
  1276. {
  1277. case GL_BGRA:
  1278. case GL_RGB:
  1279. case GL_RGBA:
  1280. // case GL_ALPHA:
  1281. // case GL_LUMINANCE:
  1282. // case GL_LUMINANCE_ALPHA:
  1283. attachIndex = kAttColor0;
  1284. attachIndexGL = GL_COLOR_ATTACHMENT0_EXT;
  1285. blitMask = GL_COLOR_BUFFER_BIT;
  1286. break;
  1287. // case GL_DEPTH_COMPONENT:
  1288. // attachIndex = kAttDepth;
  1289. // attachIndexGL = GL_DEPTH_ATTACHMENT_EXT;
  1290. // blitMask = GL_DEPTH_BUFFER_BIT;
  1291. // break;
  1292. case GL_DEPTH_STENCIL_EXT:
  1293. attachIndex = kAttDepthStencil;
  1294. attachIndexGL = GL_DEPTH_STENCIL_ATTACHMENT_EXT;
  1295. blitMask = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
  1296. break;
  1297. default:
  1298. Assert(!"Unsupported format for MSAA resolve" );
  1299. break;
  1300. }
  1301. // set the read fb, attach read RBO at appropriate attach point, set read buffer
  1302. BindFBOToCtx( m_blitReadFBO, GL_READ_FRAMEBUFFER_EXT );
  1303. // going to avoid the TexAttach / TexDetach calls due to potential confusion, implement it directly here
  1304. //-----------------------------------------------------------------------------------
  1305. // put tex->m_rboName on the read FB's attachment
  1306. if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT_EXT)
  1307. {
  1308. // you have to attach it both places...
  1309. // http://www.opengl.org/wiki/GL_EXT_framebuffer_object
  1310. // bind the RBO to the GL_RENDERBUFFER_EXT target - is this extraneous ?
  1311. //glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, tex->m_rboName );
  1312. // attach the GL_RENDERBUFFER_EXT target to the depth and stencil attach points
  1313. gGL->glFramebufferRenderbufferEXT( GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, tex->m_rboName);
  1314. gGL->glFramebufferRenderbufferEXT( GL_READ_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, tex->m_rboName);
  1315. // no need to leave the RBO hanging on
  1316. //glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
  1317. }
  1318. else
  1319. {
  1320. //glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, tex->m_rboName );
  1321. gGL->glFramebufferRenderbufferEXT( GL_READ_FRAMEBUFFER_EXT, attachIndexGL, GL_RENDERBUFFER_EXT, tex->m_rboName);
  1322. //glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
  1323. }
  1324. gGL->glReadBuffer( attachIndexGL );
  1325. //-----------------------------------------------------------------------------------
  1326. // put tex->m_texName on the draw FBO attachment
  1327. // set the write fb and buffer, and attach write tex
  1328. BindFBOToCtx( m_blitDrawFBO, GL_DRAW_FRAMEBUFFER_EXT );
  1329. // regular path - attaching a texture2d
  1330. if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT_EXT)
  1331. {
  1332. gGL->glFramebufferTexture2DEXT( GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, tex->m_texName, 0 );
  1333. gGL->glFramebufferTexture2DEXT( GL_DRAW_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, tex->m_texName, 0 );
  1334. }
  1335. else
  1336. {
  1337. gGL->glFramebufferTexture2DEXT( GL_DRAW_FRAMEBUFFER_EXT, attachIndexGL, GL_TEXTURE_2D, tex->m_texName, 0 );
  1338. }
  1339. gGL->glDrawBuffer( attachIndexGL );
  1340. //-----------------------------------------------------------------------------------
  1341. // blit
  1342. gGL->glBlitFramebufferEXT( 0, 0, tex->m_layout->m_key.m_xSize, tex->m_layout->m_key.m_ySize,
  1343. 0, 0, tex->m_layout->m_key.m_xSize, tex->m_layout->m_key.m_ySize,
  1344. blitMask, GL_NEAREST );
  1345. // or should it be GL_LINEAR? does it matter ?
  1346. //-----------------------------------------------------------------------------------
  1347. // cleanup
  1348. //-----------------------------------------------------------------------------------
  1349. // unset the read fb and buffer, detach read RBO
  1350. //glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
  1351. if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT_EXT)
  1352. {
  1353. // detach the GL_RENDERBUFFER_EXT target from the depth and stencil attach points
  1354. gGL->glFramebufferRenderbufferEXT( GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
  1355. gGL->glFramebufferRenderbufferEXT( GL_READ_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
  1356. }
  1357. else
  1358. {
  1359. gGL->glFramebufferRenderbufferEXT( GL_READ_FRAMEBUFFER_EXT, attachIndexGL, GL_RENDERBUFFER_EXT, 0);
  1360. }
  1361. //-----------------------------------------------------------------------------------
  1362. // unset the write fb and buffer, detach write tex
  1363. if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT_EXT)
  1364. {
  1365. gGL->glFramebufferTexture2DEXT( GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0 );
  1366. gGL->glFramebufferTexture2DEXT( GL_DRAW_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0 );
  1367. }
  1368. else
  1369. {
  1370. gGL->glFramebufferTexture2DEXT( GL_DRAW_FRAMEBUFFER_EXT, attachIndexGL, GL_TEXTURE_2D, 0, 0 );
  1371. }
  1372. // put the original FB back in place (both read and draw)
  1373. // this bind will hit both read and draw bindings
  1374. BindFBOToCtx( m_drawingFBO, GL_FRAMEBUFFER_EXT );
  1375. // set the read and write buffers back to... what ? does it matter for anything but copies ? don't worry about it
  1376. // restore the scissor state
  1377. m_ScissorEnable.Write( &oldsciss );
  1378. // mark the RBO clean on the resolved tex
  1379. tex->ForceRBONonDirty();
  1380. }
  1381. }
  1382. void GLMContext::PreloadTex( CGLMTex *tex, bool force )
  1383. {
  1384. // if conditions allow (i.e. a drawing surface is active)
  1385. // bind the texture on TMU 15
  1386. // set up a dummy program to sample it but not write (use 'discard')
  1387. // draw a teeny little triangle that won't generate a lot of fragments
  1388. if (!m_pairCache)
  1389. return;
  1390. if (!m_drawingFBO)
  1391. return;
  1392. if (tex->m_texPreloaded && !force) // only do one preload unless forced to re-do
  1393. {
  1394. //printf("\nnot-preloading %s", tex->m_debugLabel ? tex->m_debugLabel : "(unknown)");
  1395. return;
  1396. }
  1397. //printf("\npreloading %s", tex->m_debugLabel ? tex->m_debugLabel : "(unknown)");
  1398. CGLMProgram *vp = m_preloadTexVertexProgram;
  1399. CGLMProgram *fp = NULL;
  1400. switch(tex->m_layout->m_key.m_texGLTarget)
  1401. {
  1402. case GL_TEXTURE_2D: fp = m_preload2DTexFragmentProgram;
  1403. break;
  1404. case GL_TEXTURE_3D: fp = m_preload3DTexFragmentProgram;
  1405. break;
  1406. case GL_TEXTURE_CUBE_MAP: fp = m_preloadCubeTexFragmentProgram;
  1407. break;
  1408. }
  1409. if (!fp)
  1410. return;
  1411. CGLMShaderPair *preloadPair = m_pairCache->SelectShaderPair( vp, fp, 0 );
  1412. if (!preloadPair)
  1413. return;
  1414. if ( !preloadPair->m_valid )
  1415. {
  1416. if ( !preloadPair->ValidateProgramPair() )
  1417. {
  1418. return;
  1419. }
  1420. }
  1421. gGL->glUseProgram( (GLuint)preloadPair->m_program );
  1422. m_pBoundPair = preloadPair;
  1423. m_bDirtyPrograms = true;
  1424. // almost ready to draw...
  1425. //int tmuForPreload = 15;
  1426. // shut down all the generic attribute arrays on the detention level - next real draw will activate them again
  1427. m_lastKnownVertexAttribMask = 0;
  1428. m_nNumSetVertexAttributes = 16;
  1429. memset( &m_boundVertexAttribs[0], 0xFF, sizeof( m_boundVertexAttribs ) );
  1430. // Force the next flush to reset the attributes.
  1431. ClearCurAttribs();
  1432. for( int index=0; index < kGLMVertexAttributeIndexMax; index++ )
  1433. {
  1434. gGL->glDisableVertexAttribArray( index );
  1435. }
  1436. // bind texture and sampling params
  1437. CGLMTex *pPrevTex = m_samplers[15].m_pBoundTex;
  1438. #ifndef OSX // 10.6
  1439. if ( m_bUseSamplerObjects )
  1440. {
  1441. gGL->glBindSampler( 15, 0 );
  1442. }
  1443. #endif // !OSX
  1444. BindTexToTMU( tex, 15 );
  1445. // unbind vertex/index buffers
  1446. BindBufferToCtx( kGLMVertexBuffer, NULL );
  1447. BindBufferToCtx( kGLMIndexBuffer, NULL );
  1448. // draw
  1449. static float posns[] = { 0.0f, 0.0f, 0.0f,
  1450. 0.0f, 0.0f, 0.0f,
  1451. 0.0f, 0.0f, 0.0f };
  1452. static int indices[] = { 0, 1, 2 };
  1453. gGL->glEnableVertexAttribArray( 0 );
  1454. gGL->glVertexAttribPointer( 0, 3, GL_FLOAT, 0, 0, posns );
  1455. gGL->glDrawRangeElements( GL_TRIANGLES, 0, 3, 3, GL_UNSIGNED_INT, indices);
  1456. gGL->glDisableVertexAttribArray( 0 );
  1457. SetSamplerDirty( 15 );
  1458. BindTexToTMU( pPrevTex, 15 );
  1459. tex->m_texPreloaded = true;
  1460. }
  1461. CGLMFBO *GLMContext::NewFBO( void )
  1462. {
  1463. GLM_FUNC;
  1464. CGLMFBO *fbo = new CGLMFBO( this );
  1465. m_fboTable.AddToTail( fbo );
  1466. return fbo;
  1467. }
  1468. void GLMContext::DelFBO( CGLMFBO *fbo )
  1469. {
  1470. GLM_FUNC;
  1471. if (m_drawingFBO == fbo)
  1472. {
  1473. m_drawingFBO = NULL; //poof!
  1474. }
  1475. if (m_boundReadFBO == fbo )
  1476. {
  1477. BindFBOToCtx( NULL, GL_READ_FRAMEBUFFER_EXT );
  1478. m_boundReadFBO = NULL;
  1479. }
  1480. if (m_boundDrawFBO == fbo )
  1481. {
  1482. BindFBOToCtx( NULL, GL_DRAW_FRAMEBUFFER_EXT );
  1483. m_boundDrawFBO = NULL;
  1484. }
  1485. int idx = m_fboTable.Find( fbo );
  1486. Assert( idx >= 0 );
  1487. if ( idx >= 0 )
  1488. {
  1489. m_fboTable.FastRemove( idx );
  1490. }
  1491. delete fbo;
  1492. }
  1493. //===============================================================================
  1494. CGLMProgram *GLMContext::NewProgram( EGLMProgramType type, char *progString, const char *pShaderName )
  1495. {
  1496. //hushed GLM_FUNC;
  1497. CGLMProgram *prog = new CGLMProgram( this, type );
  1498. prog->SetProgramText( progString );
  1499. prog->SetShaderName( pShaderName );
  1500. prog->CompileActiveSources();
  1501. return prog;
  1502. }
  1503. void GLMContext::DelProgram( CGLMProgram *pProg )
  1504. {
  1505. GLM_FUNC;
  1506. if ( m_drawingProgram[ pProg->m_type ] == pProg )
  1507. {
  1508. SetProgram( pProg->m_type, ( pProg->m_type == kGLMFragmentProgram ) ? m_pNullFragmentProgram : NULL );
  1509. }
  1510. // make sure to eliminate any cached pairs using this shader
  1511. bool purgeResult = m_pairCache->PurgePairsWithShader( pProg );
  1512. (void)purgeResult;
  1513. Assert( !purgeResult ); // very unlikely to trigger
  1514. NullProgram();
  1515. delete pProg;
  1516. }
  1517. void GLMContext::NullProgram( void )
  1518. {
  1519. gGL->glUseProgram( 0 );
  1520. m_pBoundPair = NULL;
  1521. m_bDirtyPrograms = true;
  1522. }
  1523. void GLMContext::SetDrawingLang( EGLMProgramLang lang, bool immediate )
  1524. {
  1525. if ( !m_caps.m_hasDualShaders ) return; // ignore attempts to change language when -glmdualshaders is not engaged
  1526. m_drawingLangAtFrameStart = lang;
  1527. if (immediate)
  1528. {
  1529. NullProgram();
  1530. m_drawingLang = m_drawingLangAtFrameStart;
  1531. }
  1532. }
  1533. void GLMContext::LinkShaderPair( CGLMProgram *vp, CGLMProgram *fp )
  1534. {
  1535. if ( (m_pairCache) && (m_drawingLang==kGLMGLSL) && (vp) && (fp) )
  1536. {
  1537. CGLMShaderPair *pair = m_pairCache->SelectShaderPair( vp, fp, 0 );
  1538. (void)pair;
  1539. Assert( pair != NULL );
  1540. NullProgram(); // clear out any binds that were done - next draw will set it right
  1541. }
  1542. }
  1543. void GLMContext::ValidateShaderPair( CGLMProgram *vp, CGLMProgram *fp )
  1544. {
  1545. if ((m_pairCache) && (m_drawingLang == kGLMGLSL) && (vp) && (fp))
  1546. {
  1547. CGLMShaderPair *pair = m_pairCache->SelectShaderPair( vp, fp, 0 );
  1548. Assert( pair != NULL );
  1549. pair->ValidateProgramPair();
  1550. NullProgram(); // clear out any binds that were done - next draw will set it right
  1551. }
  1552. }
  1553. void GLMContext::ClearShaderPairCache( void )
  1554. {
  1555. if (m_pairCache)
  1556. {
  1557. NullProgram();
  1558. m_pairCache->Purge(); // bye bye all linked pairs
  1559. NullProgram();
  1560. }
  1561. }
  1562. void GLMContext::QueryShaderPair( int index, GLMShaderPairInfo *infoOut )
  1563. {
  1564. if (m_pairCache)
  1565. {
  1566. m_pairCache->QueryShaderPair( index, infoOut );
  1567. }
  1568. else
  1569. {
  1570. memset( infoOut, 0, sizeof( *infoOut ) );
  1571. infoOut->m_status = -1;
  1572. }
  1573. }
  1574. CGLMBuffer *GLMContext::NewBuffer( EGLMBufferType type, uint size, uint options )
  1575. {
  1576. //hushed GLM_FUNC;
  1577. CGLMBuffer *prog = new CGLMBuffer( this, type, size, options );
  1578. return prog;
  1579. }
  1580. void GLMContext::DelBuffer( CGLMBuffer *buff )
  1581. {
  1582. GLM_FUNC;
  1583. for( int index = 0; index < kGLMVertexAttributeIndexMax; index++ )
  1584. {
  1585. if ( m_drawVertexSetup.m_attrs[index].m_pBuffer == buff )
  1586. {
  1587. // just clear the enable mask - this will force all the attrs to get re-sent on next sync
  1588. m_drawVertexSetup.m_attrMask = 0;
  1589. }
  1590. }
  1591. BindGLBufferToCtx( buff->m_buffGLTarget, NULL, false );
  1592. delete buff;
  1593. }
  1594. GLMVertexSetup g_blank_setup;
  1595. void GLMContext::Clear( bool color, unsigned long colorValue, bool depth, float depthValue, bool stencil, unsigned int stencilValue, GLScissorBox_t *box )
  1596. {
  1597. GLM_FUNC;
  1598. ++m_nBatchCounter;
  1599. #if GLMDEBUG
  1600. GLMDebugHookInfo info;
  1601. memset( &info, 0, sizeof(info) );
  1602. info.m_caller = eClear;
  1603. do
  1604. {
  1605. #endif
  1606. uint mask = 0;
  1607. GLClearColor_t clearcol;
  1608. GLClearDepth_t cleardep = { depthValue };
  1609. GLClearStencil_t clearsten = { (GLint)stencilValue };
  1610. // depth write mask must be saved&restored
  1611. GLDepthMask_t olddepthmask;
  1612. GLDepthMask_t newdepthmask = { true };
  1613. // stencil write mask must be saved and restored
  1614. GLStencilWriteMask_t oldstenmask;
  1615. GLStencilWriteMask_t newstenmask = { (GLint)0xFFFFFFFF };
  1616. GLColorMaskSingle_t oldcolormask;
  1617. GLColorMaskSingle_t newcolormask = { -1,-1,-1,-1 }; // D3D clears do not honor color mask, so force it
  1618. if (color)
  1619. {
  1620. // #define D3DCOLOR_ARGB(a,r,g,b) ((D3DCOLOR)((((a)&0xff)<<24)|(((r)&0xff)<<16)|(((g)&0xff)<<8)|((b)&0xff)))
  1621. clearcol.r = ((colorValue >> 16) & 0xFF) / 255.0f; //R
  1622. clearcol.g = ((colorValue >> 8) & 0xFF) / 255.0f; //G
  1623. clearcol.b = ((colorValue ) & 0xFF) / 255.0f; //B
  1624. clearcol.a = ((colorValue >> 24) & 0xFF) / 255.0f; //A
  1625. m_ClearColor.Write( &clearcol ); // no check, no wait
  1626. mask |= GL_COLOR_BUFFER_BIT;
  1627. // save and set color mask
  1628. m_ColorMaskSingle.Read( &oldcolormask, 0 );
  1629. m_ColorMaskSingle.Write( &newcolormask );
  1630. }
  1631. if (depth)
  1632. {
  1633. // get old depth write mask
  1634. m_DepthMask.Read( &olddepthmask, 0 );
  1635. m_DepthMask.Write( &newdepthmask );
  1636. m_ClearDepth.Write( &cleardep ); // no check, no wait
  1637. mask |= GL_DEPTH_BUFFER_BIT;
  1638. }
  1639. if (stencil)
  1640. {
  1641. m_ClearStencil.Write( &clearsten ); // no check, no wait
  1642. mask |= GL_STENCIL_BUFFER_BIT;
  1643. // save and set sten mask
  1644. m_StencilWriteMask.Read( &oldstenmask, 0 );
  1645. m_StencilWriteMask.Write( &newstenmask );
  1646. }
  1647. bool subrect = (box != NULL);
  1648. GLScissorEnable_t scissorEnableSave;
  1649. GLScissorEnable_t scissorEnableNew = { true };
  1650. GLScissorBox_t scissorBoxSave;
  1651. GLScissorBox_t scissorBoxNew;
  1652. if (subrect)
  1653. {
  1654. // save current scissorbox and enable
  1655. m_ScissorEnable.Read( &scissorEnableSave, 0 );
  1656. m_ScissorBox.Read( &scissorBoxSave, 0 );
  1657. if(0)
  1658. {
  1659. // calc new scissorbox as intersection against *box
  1660. // max of the mins
  1661. scissorBoxNew.x = MAX(scissorBoxSave.x, box->x);
  1662. scissorBoxNew.y = MAX(scissorBoxSave.y, box->y);
  1663. // min of the maxes
  1664. scissorBoxNew.width = ( MIN(scissorBoxSave.x+scissorBoxSave.width, box->x+box->width)) - scissorBoxNew.x;
  1665. // height is just min of the max y's, minus the new base Y
  1666. scissorBoxNew.height = ( MIN(scissorBoxSave.y+scissorBoxSave.height, box->y+box->height)) - scissorBoxNew.y;
  1667. }
  1668. else
  1669. {
  1670. // ignore old scissor box completely.
  1671. scissorBoxNew = *box;
  1672. }
  1673. // set new box and enable
  1674. m_ScissorEnable.Write( &scissorEnableNew );
  1675. m_ScissorBox.Write( &scissorBoxNew );
  1676. }
  1677. gGL->glClear( mask );
  1678. if (subrect)
  1679. {
  1680. // put old scissor box and enable back
  1681. m_ScissorEnable.Write( &scissorEnableSave );
  1682. m_ScissorBox.Write( &scissorBoxSave );
  1683. }
  1684. if (depth)
  1685. {
  1686. // put old depth write mask
  1687. m_DepthMask.Write( &olddepthmask );
  1688. }
  1689. if (color)
  1690. {
  1691. // put old color write mask
  1692. m_ColorMaskSingle.Write( &oldcolormask );
  1693. }
  1694. if (stencil)
  1695. {
  1696. // put old sten mask
  1697. m_StencilWriteMask.Write( &oldstenmask );
  1698. }
  1699. #if GLMDEBUG
  1700. DebugHook( &info );
  1701. } while (info.m_loop);
  1702. #endif
  1703. }
  1704. // stolen from glmgrbasics.cpp
  1705. extern "C" uint GetCurrentKeyModifiers( void );
  1706. enum ECarbonModKeyIndex
  1707. {
  1708. EcmdKeyBit = 8, /* command key down?*/
  1709. EshiftKeyBit = 9, /* shift key down?*/
  1710. EalphaLockBit = 10, /* alpha lock down?*/
  1711. EoptionKeyBit = 11, /* option key down?*/
  1712. EcontrolKeyBit = 12 /* control key down?*/
  1713. };
  1714. enum ECarbonModKeyMask
  1715. {
  1716. EcmdKey = 1 << EcmdKeyBit,
  1717. EshiftKey = 1 << EshiftKeyBit,
  1718. EalphaLock = 1 << EalphaLockBit,
  1719. EoptionKey = 1 << EoptionKeyBit,
  1720. EcontrolKey = 1 << EcontrolKeyBit
  1721. };
  1722. static ConVar gl_flushpaircache ("gl_flushpaircache", "0");
  1723. static ConVar gl_paircachestats ("gl_paircachestats", "0");
  1724. static ConVar gl_mtglflush_at_tof ("gl_mtglflush_at_tof", "0");
  1725. static ConVar gl_texlayoutstats ("gl_texlayoutstats", "0" );
  1726. void GLMContext::BeginFrame( void )
  1727. {
  1728. GLM_FUNC;
  1729. m_debugFrameIndex++;
  1730. // check for lang change at TOF
  1731. if (m_caps.m_hasDualShaders)
  1732. {
  1733. if (m_drawingLang != m_drawingLangAtFrameStart)
  1734. {
  1735. // language change. unbind everything..
  1736. NullProgram();
  1737. m_drawingLang = m_drawingLangAtFrameStart;
  1738. }
  1739. }
  1740. // scrub some critical shock absorbers
  1741. for( int i=0; i< 16; i++)
  1742. {
  1743. gGL->glDisableVertexAttribArray( i ); // enable GLSL attribute- this is just client state - will be turned back off
  1744. }
  1745. m_lastKnownVertexAttribMask = 0;
  1746. m_nNumSetVertexAttributes = 0;
  1747. //FIXME should we also zap the m_lastKnownAttribs array ? (worst case it just sets them all again on first batch)
  1748. BindBufferToCtx( kGLMVertexBuffer, NULL, true );
  1749. BindBufferToCtx( kGLMIndexBuffer, NULL, true );
  1750. if (gl_flushpaircache.GetInt())
  1751. {
  1752. // do the flush and then set back to zero
  1753. ClearShaderPairCache();
  1754. printf("\n\n##### shader pair cache cleared\n\n");
  1755. gl_flushpaircache.SetValue( 0 );
  1756. }
  1757. if (gl_paircachestats.GetInt())
  1758. {
  1759. // do the flush and then set back to zero
  1760. m_pairCache->DumpStats();
  1761. gl_paircachestats.SetValue( 0 );
  1762. }
  1763. if (gl_texlayoutstats.GetInt())
  1764. {
  1765. m_texLayoutTable->DumpStats();
  1766. gl_texlayoutstats.SetValue( 0 );
  1767. }
  1768. if (gl_mtglflush_at_tof.GetInt())
  1769. {
  1770. gGL->glFlush(); // TOF flush - skip this if benchmarking, enable it if human playing (smoothness)
  1771. }
  1772. #if GLMDEBUG
  1773. // init debug hook information
  1774. GLMDebugHookInfo info;
  1775. memset( &info, 0, sizeof(info) );
  1776. info.m_caller = eBeginFrame;
  1777. do
  1778. {
  1779. DebugHook( &info );
  1780. } while (info.m_loop);
  1781. #endif
  1782. }
  1783. void GLMContext::EndFrame( void )
  1784. {
  1785. GLM_FUNC;
  1786. #if GLMDEBUG
  1787. // init debug hook information
  1788. GLMDebugHookInfo info;
  1789. memset( &info, 0, sizeof(info) );
  1790. info.m_caller = eEndFrame;
  1791. do
  1792. {
  1793. DebugHook( &info );
  1794. } while (info.m_loop);
  1795. #endif
  1796. }
  1797. //===============================================================================
  1798. CGLMQuery *GLMContext::NewQuery( GLMQueryParams *params )
  1799. {
  1800. CGLMQuery *query = new CGLMQuery( this, params );
  1801. return query;
  1802. }
  1803. void GLMContext::DelQuery( CGLMQuery *query )
  1804. {
  1805. // may want to do some finish/
  1806. delete query;
  1807. }
  1808. static ConVar mat_vsync( "mat_vsync", "0", 0, "Force sync to vertical retrace", true, 0.0, true, 1.0 );
  1809. //===============================================================================
  1810. ConVar glm_nullrefresh_capslock( "glm_nullrefresh_capslock", "0" );
  1811. ConVar glm_literefresh_capslock( "glm_literefresh_capslock", "0" );
  1812. extern ConVar gl_blitmode;
  1813. void GLMContext::Present( CGLMTex *tex )
  1814. {
  1815. GLM_FUNC;
  1816. {
  1817. #if GL_TELEMETRY_GPU_ZONES
  1818. CScopedGLMPIXEvent glmPIXEvent( "GLMContext::Present" );
  1819. g_TelemetryGPUStats.m_nTotalPresent++;
  1820. #endif
  1821. ProcessTextureDeletes();
  1822. #ifdef HAVE_GL_ARB_SYNC
  1823. if ( gGL->m_bHave_GL_AMD_pinned_memory )
  1824. {
  1825. m_PinnedMemoryBuffers[m_nCurPinnedMemoryBuffer].InsertFence();
  1826. m_nCurPinnedMemoryBuffer = ( m_nCurPinnedMemoryBuffer + 1 ) % cNumPinnedMemoryBuffers;
  1827. m_PinnedMemoryBuffers[m_nCurPinnedMemoryBuffer].BlockUntilNotBusy();
  1828. gGL->glBindBufferARB( GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, m_PinnedMemoryBuffers[m_nCurPinnedMemoryBuffer].GetHandle() );
  1829. }
  1830. if ( gGL->m_bHave_GL_ARB_buffer_storage )
  1831. {
  1832. for (uint lpType = 0; lpType < kGLMNumBufferTypes; ++lpType)
  1833. {
  1834. m_persistentBuffer[m_nCurPersistentBuffer][lpType].InsertFence();
  1835. }
  1836. m_nCurPersistentBuffer = ( m_nCurPersistentBuffer + 1 ) % cNumPersistentBuffers;
  1837. for (uint lpType = 0; lpType < kGLMNumBufferTypes; ++lpType)
  1838. {
  1839. m_persistentBuffer[m_nCurPersistentBuffer][lpType].BlockUntilNotBusy();
  1840. }
  1841. }
  1842. #endif // HAVE_GL_ARB_SYNC
  1843. bool newRefreshMode = false;
  1844. // two ways to go:
  1845. // old school, do the resolve, had the tex down to cocoamgr to actually blit.
  1846. // that way is required if you are not in one-context mode (10.5.8)
  1847. if ( (gl_blitmode.GetInt() != 0) )
  1848. {
  1849. newRefreshMode = true;
  1850. }
  1851. // this is the path whether full screen or windowed... we always blit.
  1852. CShowPixelsParams showparams;
  1853. memset( &showparams, 0, sizeof(showparams) );
  1854. showparams.m_srcTexName = tex->m_texName;
  1855. showparams.m_width = tex->m_layout->m_key.m_xSize;
  1856. showparams.m_height = tex->m_layout->m_key.m_ySize;
  1857. showparams.m_vsyncEnable = m_displayParams.m_vsyncEnable = mat_vsync.GetBool();
  1858. showparams.m_fsEnable = m_displayParams.m_fsEnable;
  1859. showparams.m_useBlit = m_caps.m_hasFramebufferBlit;
  1860. // we call showpixels once with the "only sync view" arg set, so we know what the latest surface size is, before trying to do our own blit !
  1861. showparams.m_onlySyncView = true;
  1862. ShowPixels(&showparams); // doesn't actually show anything, just syncs window/fs state (would make a useful separate call)
  1863. showparams.m_onlySyncView = false;
  1864. bool refresh = true;
  1865. #ifdef OSX
  1866. if ( (glm_nullrefresh_capslock.GetInt()) && (GetCurrentKeyModifiers() & EalphaLock) )
  1867. {
  1868. refresh = false;
  1869. }
  1870. #endif
  1871. static int counter;
  1872. counter ++;
  1873. #ifdef OSX
  1874. if ( (glm_literefresh_capslock.GetInt()) && (GetCurrentKeyModifiers() & EalphaLock) && (counter & 127) )
  1875. {
  1876. // just show every 128th frame
  1877. refresh = false;
  1878. }
  1879. #endif
  1880. if (refresh)
  1881. {
  1882. if (newRefreshMode)
  1883. {
  1884. // blit to GL_BACK done here, not in CocoaMgr, this lets us do resolve directly if conditions are right
  1885. GLMRect srcRect, dstRect;
  1886. uint dstWidth,dstHeight;
  1887. DisplayedSize( dstWidth,dstHeight );
  1888. srcRect.xmin = 0;
  1889. srcRect.ymin = 0;
  1890. srcRect.xmax = showparams.m_width;
  1891. srcRect.ymax = showparams.m_height;
  1892. dstRect.xmin = 0;
  1893. dstRect.ymin = 0;
  1894. dstRect.xmax = dstWidth;
  1895. dstRect.ymax = dstHeight;
  1896. // do not ask for LINEAR if blit is unscaled
  1897. // NULL means targeting GL_BACK. Blit2 will break it down into two steps if needed, and will handle resolve, scale, flip.
  1898. bool blitScales = (showparams.m_width != static_cast<int>(dstWidth)) || (showparams.m_height != static_cast<int>(dstHeight));
  1899. Blit2( tex, &srcRect, 0,0,
  1900. NULL, &dstRect, 0,0,
  1901. blitScales ? GL_LINEAR : GL_NEAREST );
  1902. // we set showparams.m_noBlit, and just let CocoaMgr handle the swap (flushbuffer / page flip)
  1903. showparams.m_noBlit = true;
  1904. BindFBOToCtx( NULL, GL_FRAMEBUFFER_EXT );
  1905. }
  1906. else
  1907. {
  1908. ResolveTex( tex, true ); // dxabstract used to do this unconditionally.we still do if new refresh mode doesn't engage.
  1909. BindFBOToCtx( NULL, GL_FRAMEBUFFER_EXT );
  1910. // showparams.m_noBlit is left set to 0. CocoaMgr does the blit.
  1911. }
  1912. ShowPixels(&showparams);
  1913. }
  1914. // put the original FB back in place (both read and draw)
  1915. // this bind will hit both read and draw bindings
  1916. BindFBOToCtx( m_drawingFBO, GL_FRAMEBUFFER_EXT );
  1917. // put em back !!
  1918. m_ScissorEnable.Flush();
  1919. m_ScissorBox.Flush();
  1920. m_ViewportBox.Flush();
  1921. }
  1922. m_nCurFrame++;
  1923. #if GL_BATCH_PERF_ANALYSIS
  1924. tmMessage( TELEMETRY_LEVEL2, TMMF_ICON_EXCLAMATION, "VS Uniform Calls: %u, VS Uniforms: %u|VS Uniform Bone Calls: %u, VS Bone Uniforms: %u|PS Uniform Calls: %u, PS Uniforms: %u", m_nTotalVSUniformCalls, m_nTotalVSUniformsSet, m_nTotalVSUniformBoneCalls, m_nTotalVSUniformsBoneSet, m_nTotalPSUniformCalls, m_nTotalPSUniformsSet );
  1925. m_nTotalVSUniformCalls = 0, m_nTotalVSUniformBoneCalls = 0, m_nTotalVSUniformsSet = 0, m_nTotalVSUniformsBoneSet = 0, m_nTotalPSUniformCalls = 0, m_nTotalPSUniformsSet = 0;
  1926. #endif
  1927. #ifndef OSX
  1928. GLMGPUTimestampManagerTick();
  1929. #endif
  1930. }
  1931. //===============================================================================
  1932. // GLMContext protected methods
  1933. // a naive implementation of this would just clear-drawable on the context at entry,
  1934. // and then capture and set fullscreen if requested.
  1935. // however that would glitch thescreen every time the user changed resolution while staying in full screen.
  1936. // but in windowed mode there's really not much to do in here. Yeah, this routine centers around obtaining
  1937. // drawables for fullscreen mode, and/or dropping those drawables if we're going back to windowed.
  1938. // um, are we expected to re-make the standard surfaces (color, depthstencil) if the res changes? is that now this routine's job ?
  1939. // so, kick it off with an assessment of whather we were FS previously or not.
  1940. // if there was no prior display params latched, then it wasn't.
  1941. // changes in here take place immediately. If you want to defer display changes then that's going to be a different method.
  1942. // common assumption is that there will be two places that call this: context create and the implementation of the DX9 Reset method.
  1943. // in either case the client code is aware of what it signed up for.
  1944. bool GLMContext::SetDisplayParams( GLMDisplayParams *params )
  1945. {
  1946. m_displayParams = *params; // latch em
  1947. m_displayParamsValid = true;
  1948. return true;
  1949. }
  1950. ConVar gl_can_query_fast("gl_can_query_fast", "0");
  1951. static uint gPersistentBufferSize[kGLMNumBufferTypes] =
  1952. {
  1953. 2 * 1024 * 1024, // kGLMVertexBuffer
  1954. 1 * 1024 * 1024, // kGLMIndexBuffer
  1955. 0, // kGLMUniformBuffer
  1956. 0, // kGLMPixelBuffer
  1957. };
  1958. GLMContext::GLMContext( IDirect3DDevice9 *pDevice, GLMDisplayParams *params )
  1959. {
  1960. // m_bUseSamplerObjects = true;
  1961. //
  1962. // // On most AMD drivers (like the current latest, 12.10 Windows), the PCF depth comparison mode doesn't work on sampler objects, so just punt them.
  1963. // if ( gGL->m_nDriverProvider == cGLDriverProviderAMD )
  1964. // {
  1965. // m_bUseSamplerObjects = false;
  1966. // }
  1967. // if ( CommandLine()->CheckParm( "-gl_disablesamplerobjects" ) )
  1968. // {
  1969. // Disable sampler object usage for now since ScaleForm isn't aware of them
  1970. // and doesn't know how to push/pop their binding state. It seems we don't
  1971. // really use them in this codebase anyhow, except to preload textures.
  1972. m_bUseSamplerObjects = false;
  1973. if ( CommandLine()->CheckParm( "-gl_enablesamplerobjects" ) )
  1974. m_bUseSamplerObjects = true;
  1975. // Try to get some more free memory by relying on driver host copies instead of ours.
  1976. // In some cases the driver will be able to discard their own host copy and rely on GPU
  1977. // memory, reducing memory usage.
  1978. // Sadly, we have to enable tex client storage for srgb decoding. This should only happen
  1979. // on Macs w/ OSX 10.6.
  1980. m_bTexClientStorage = !gGL->m_bHave_GL_EXT_texture_sRGB_decode;
  1981. if ( CommandLine()->CheckParm( "-gl_texclientstorage" ) )
  1982. m_bTexClientStorage = true;
  1983. GLMDebugPrintf( "GL sampler object usage: %s\n", m_bUseSamplerObjects ? "ENABLED" : "DISABLED" );
  1984. m_nCurOwnerThreadId = ThreadGetCurrentId();
  1985. m_nThreadOwnershipReleaseCounter = 0;
  1986. m_pDevice = pDevice;
  1987. m_nCurFrame = 0;
  1988. m_nBatchCounter = 0;
  1989. ClearCurAttribs();
  1990. #ifndef OSX
  1991. m_nCurPinnedMemoryBuffer = 0;
  1992. if ( gGL->m_bHave_GL_AMD_pinned_memory )
  1993. {
  1994. for ( uint t = 0; t < cNumPinnedMemoryBuffers; t++ )
  1995. {
  1996. m_PinnedMemoryBuffers[t].Init( GLMGR_PINNED_MEMORY_BUFFER_SIZE );
  1997. }
  1998. gGL->glBindBufferARB( GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, m_PinnedMemoryBuffers[m_nCurPinnedMemoryBuffer].GetHandle() );
  1999. }
  2000. #endif // OSX
  2001. m_nCurPersistentBuffer = 0;
  2002. if ( gGL->m_bHave_GL_ARB_buffer_storage )
  2003. {
  2004. for ( uint lpType = 0; lpType < kGLMNumBufferTypes; ++lpType )
  2005. {
  2006. for ( uint lpNum = 0; lpNum < cNumPersistentBuffers; ++lpNum )
  2007. {
  2008. m_persistentBuffer[lpNum][lpType].Init( (EGLMBufferType)lpType, gPersistentBufferSize[lpType] );
  2009. }
  2010. }
  2011. }
  2012. m_bUseBoneUniformBuffers = true;
  2013. if (CommandLine()->CheckParm("-disableboneuniformbuffers"))
  2014. {
  2015. m_bUseBoneUniformBuffers = false;
  2016. }
  2017. m_nMaxUsedVertexProgramConstantsHint = 256;
  2018. // flag our copy of display params as blank
  2019. m_displayParamsValid = false;
  2020. // peek at any CLI options
  2021. m_slowAssertEnable = CommandLine()->FindParm("-glmassertslow") != 0;
  2022. m_slowSpewEnable = CommandLine()->FindParm("-glmspewslow") != 0;
  2023. m_checkglErrorsAfterEveryBatch = CommandLine()->FindParm("-glcheckerrors") != 0;
  2024. m_slowCheckEnable = m_slowAssertEnable || m_slowSpewEnable || m_checkglErrorsAfterEveryBatch;
  2025. m_drawingLangAtFrameStart = m_drawingLang = kGLMGLSL; // default to GLSL
  2026. // this affects FlushDrawStates which will route program bindings, uniform delivery, sampler setup, and enables accordingly.
  2027. if ( CommandLine()->FindParm("-glslmode") )
  2028. {
  2029. m_drawingLangAtFrameStart = m_drawingLang = kGLMGLSL;
  2030. }
  2031. if ( CommandLine()->FindParm("-arbmode") && !CommandLine()->FindParm("-glslcontrolflow") )
  2032. {
  2033. m_drawingLangAtFrameStart = m_drawingLang = kGLMARB;
  2034. }
  2035. // proceed with rest of init
  2036. m_dwRenderThreadId = 0;
  2037. m_bIsThreading = false;
  2038. m_nsctx = NULL;
  2039. m_ctx = NULL;
  2040. int *selAttribs = NULL;
  2041. uint selWords = 0;
  2042. memset( &m_caps, 0, sizeof( m_caps ) );
  2043. GetDesiredPixelFormatAttribsAndRendererInfo( (uint**)&selAttribs, &selWords, &m_caps );
  2044. uint selBytes = selWords * sizeof( uint ); selBytes;
  2045. #if defined( USE_SDL )
  2046. m_ctx = (SDL_GLContext)GetGLContextForWindow( params ? (void*)params->m_focusWindow : NULL );
  2047. MakeCurrent( true );
  2048. #else
  2049. #error
  2050. #endif
  2051. IncrementWindowRefCount();
  2052. // If we're using GL_ARB_debug_output, go ahead and setup the callback here.
  2053. if ( gGL->m_bHave_GL_ARB_debug_output && CommandLine()->FindParm( "-gl_debug" ) )
  2054. {
  2055. #if GLMDEBUG
  2056. // Turning this on is a perf loss, but it ensures that you can (at least) swap to the other
  2057. // threads to see what call is currently being made.
  2058. // Note that if the driver is in multithreaded mode, you can put it back into singlethreaded mode
  2059. // and get a real stack for the offending gl call.
  2060. gGL->glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
  2061. #ifdef WIN32
  2062. // This happens early enough during init that DevMsg() does nothing.
  2063. OutputDebugStringA( "GLMContext::GLMContext: GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB enabled!\n" );
  2064. #else
  2065. printf( "GLMContext::GLMContext: GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB enabled!\n" );
  2066. #endif
  2067. #endif
  2068. // This should be there if we get in here--make sure.
  2069. Assert(gGL->glDebugMessageControlARB);
  2070. gGL->glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, (const GLuint *)NULL, GL_TRUE);
  2071. // Gonna filter these out, they're "chatty".
  2072. gGL->glDebugMessageControlARB(GL_DEBUG_SOURCE_API_ARB, GL_DEBUG_TYPE_OTHER_ARB, GL_DEBUG_SEVERITY_LOW_ARB, 0, (const GLuint *)NULL, GL_FALSE);
  2073. gGL->glDebugMessageCallbackARB(GL_Debug_Output_Callback, (void*)NULL);
  2074. GLMDebugPrintf( "GLMContext::GLMContext: Debug output (gl_arb_debug_output) enabled!\n" );
  2075. }
  2076. if (CommandLine()->FindParm("-glmspewcaps"))
  2077. {
  2078. DumpCaps();
  2079. }
  2080. SetDisplayParams( params );
  2081. m_texLayoutTable = new CGLMTexLayoutTable;
  2082. #ifndef OSX
  2083. if ( m_bUseSamplerObjects )
  2084. {
  2085. memset( m_samplerObjectHash, 0, sizeof( m_samplerObjectHash ) );
  2086. m_nSamplerObjectHashNumEntries = 0;
  2087. for ( uint i = 0; i < cSamplerObjectHashSize; ++i )
  2088. {
  2089. gGL->glGenSamplers( 1, &m_samplerObjectHash[i].m_samplerObject );
  2090. }
  2091. }
  2092. #endif // !OSX
  2093. memset( m_samplers, 0, sizeof( m_samplers ) );
  2094. for( int i=0; i< GLM_SAMPLER_COUNT; i++)
  2095. {
  2096. GLMTexSamplingParams &params = m_samplers[i].m_samp;
  2097. params.m_packed.m_addressU = D3DTADDRESS_WRAP;
  2098. params.m_packed.m_addressV = D3DTADDRESS_WRAP;
  2099. params.m_packed.m_addressW = D3DTADDRESS_WRAP;
  2100. params.m_packed.m_minFilter = D3DTEXF_POINT;
  2101. params.m_packed.m_magFilter = D3DTEXF_POINT;
  2102. params.m_packed.m_mipFilter = D3DTEXF_NONE;
  2103. params.m_packed.m_maxAniso = 1;
  2104. params.m_packed.m_isValid = true;
  2105. params.m_packed.m_compareMode = 0;
  2106. }
  2107. MarkAllSamplersDirty();
  2108. m_activeTexture = -1;
  2109. m_texLocks.EnsureCapacity( 16 ); // should be sufficient
  2110. // FIXME need a texture tracking table so we can reliably delete CGLMTex objects at context teardown
  2111. m_boundReadFBO = NULL;
  2112. m_boundDrawFBO = NULL;
  2113. m_drawingFBO = NULL;
  2114. memset( m_drawingProgram, 0, sizeof( m_drawingProgram ) );
  2115. m_bDirtyPrograms = true;
  2116. memset( m_programParamsF , 0, sizeof( m_programParamsF ) );
  2117. memset( m_programParamsB , 0, sizeof( m_programParamsB ) );
  2118. memset( m_programParamsI , 0, sizeof( m_programParamsI ) );
  2119. for (uint i = 0; i < ARRAYSIZE(m_programParamsF); i++)
  2120. {
  2121. m_programParamsF[i].m_firstDirtySlotNonBone = 256;
  2122. m_programParamsF[i].m_dirtySlotHighWaterNonBone = 0;
  2123. m_programParamsF[i].m_dirtySlotHighWaterBone = 0;
  2124. }
  2125. m_paramWriteMode = eParamWriteDirtySlotRange; // default to fastest mode
  2126. if (CommandLine()->FindParm("-glmwriteallslots")) m_paramWriteMode = eParamWriteAllSlots;
  2127. if (CommandLine()->FindParm("-glmwriteshaderslots")) m_paramWriteMode = eParamWriteShaderSlots;
  2128. if (CommandLine()->FindParm("-glmwriteshaderslotsoptional")) m_paramWriteMode = eParamWriteShaderSlotsOptional;
  2129. if (CommandLine()->FindParm("-glmwritedirtyslotrange")) m_paramWriteMode = eParamWriteDirtySlotRange;
  2130. m_attribWriteMode = eAttribWriteDirty;
  2131. if (CommandLine()->FindParm("-glmwriteallattribs")) m_attribWriteMode = eAttribWriteAll;
  2132. if (CommandLine()->FindParm("-glmwritedirtyattribs")) m_attribWriteMode = eAttribWriteDirty;
  2133. m_pairCache = new CGLMShaderPairCache( this );
  2134. m_pBoundPair = NULL;
  2135. m_fragDataMask = 0;
  2136. memset( m_nBoundGLBuffer, 0xFF, sizeof( m_nBoundGLBuffer ) );
  2137. memset( m_boundVertexAttribs, 0xFF, sizeof(m_boundVertexAttribs) );
  2138. m_lastKnownVertexAttribMask = 0;
  2139. m_nNumSetVertexAttributes = 16;
  2140. // make a null program for use when client asks for NULL FP
  2141. m_pNullFragmentProgram = NewProgram(kGLMFragmentProgram, g_nullFragmentProgramText, "null" );
  2142. SetProgram( kGLMFragmentProgram, m_pNullFragmentProgram );
  2143. // make dummy programs for doing texture preload via dummy draw
  2144. m_preloadTexVertexProgram = NewProgram(kGLMVertexProgram, g_preloadTexVertexProgramText, "preloadTex" );
  2145. m_preload2DTexFragmentProgram = NewProgram(kGLMFragmentProgram, g_preload2DTexFragmentProgramText, "preload2DTex" );
  2146. m_preload3DTexFragmentProgram = NewProgram(kGLMFragmentProgram, g_preload3DTexFragmentProgramText, "preload3DTex" );
  2147. m_preloadCubeTexFragmentProgram = NewProgram(kGLMFragmentProgram, g_preloadCubeTexFragmentProgramText, "preloadCube" );
  2148. //memset( &m_drawVertexSetup, 0, sizeof(m_drawVertexSetup) );
  2149. SetVertexAttributes( NULL ); // will set up all the entries in m_drawVertexSetup
  2150. m_debugFontTex = NULL;
  2151. // debug state
  2152. m_debugFrameIndex = -1;
  2153. #if GLMDEBUG
  2154. // #######################################################################################
  2155. // DebugHook state - we could set these to more interesting values in response to a CLI arg like "startpaused" or something if desired
  2156. //m_paused = false;
  2157. m_holdFrameBegin = -1;
  2158. m_holdFrameEnd = -1;
  2159. m_holdBatch = m_holdBatchFrame = -1;
  2160. m_debugDelayEnable = false;
  2161. m_debugDelay = 1<<19; // ~0.5 sec delay
  2162. m_autoClearColor = m_autoClearDepth = m_autoClearStencil = false;
  2163. m_autoClearColorValues[0] = 0.0; //red
  2164. m_autoClearColorValues[1] = 1.0; //green
  2165. m_autoClearColorValues[2] = 0.0; //blue
  2166. m_autoClearColorValues[3] = 1.0; //alpha
  2167. m_selKnobIndex = 0;
  2168. m_selKnobMinValue = -10.0f;
  2169. m_selKnobMaxValue = 10.0f;
  2170. m_selKnobIncrement = 1/256.0f;
  2171. // #######################################################################################
  2172. #endif
  2173. // make two scratch FBO's for blit purposes
  2174. m_blitReadFBO = NewFBO();
  2175. m_blitDrawFBO = NewFBO();
  2176. for( int i=0; i<kGLMScratchFBOCount; i++)
  2177. {
  2178. m_scratchFBO[i] = NewFBO();
  2179. }
  2180. // Create a PBO that we can use to fill textures with bogus data asyncronously.
  2181. m_nBoundGLBuffer[ kGLMPixelBuffer ] = 0;
  2182. gGL->glGenBuffersARB( 1, &m_destroyPBO );
  2183. gGL->glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, m_destroyPBO );
  2184. gGL->glBufferDataARB( GL_PIXEL_UNPACK_BUFFER_ARB, sizeof( g_garbageTextureBits ), g_garbageTextureBits, GL_STATIC_DRAW );
  2185. gGL->glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, m_nBoundGLBuffer[ kGLMPixelBuffer ] );
  2186. // Create a bunch of texture names for us to use forever and ever ramen.
  2187. FillTexCache( false, kGLMInitialTexCount );
  2188. #ifdef OSX
  2189. bool new_mtgl = m_caps.m_hasPerfPackage1; // i.e. 10.6.4 plus new driver
  2190. if ( CommandLine()->FindParm("-glmenablemtgl2") )
  2191. {
  2192. new_mtgl = true;
  2193. }
  2194. if ( CommandLine()->FindParm("-glmdisablemtgl2") )
  2195. {
  2196. new_mtgl = false;
  2197. }
  2198. bool mtgl_on = params->m_mtgl;
  2199. if (CommandLine()->FindParm("-glmenablemtgl"))
  2200. {
  2201. mtgl_on = true;
  2202. }
  2203. if (CommandLine()->FindParm("-glmdisablemtgl"))
  2204. {
  2205. mtgl_on = false;
  2206. }
  2207. CGLError result = (CGLError)0;
  2208. if (mtgl_on)
  2209. {
  2210. bool ready = false;
  2211. CGLContextObj context = GetCGLContextFromNSGL(m_ctx);
  2212. if (new_mtgl)
  2213. {
  2214. // afterburner
  2215. CGLContextEnable kCGLCPGCDMPEngine = ((CGLContextEnable)1314);
  2216. result = CGLEnable( context, kCGLCPGCDMPEngine );
  2217. if (!result)
  2218. {
  2219. ready = true; // succeeded - no need to try non-MTGL
  2220. printf("\nMTGL detected.\n");
  2221. }
  2222. else
  2223. {
  2224. printf("\nMTGL *not* detected, falling back.\n");
  2225. }
  2226. }
  2227. if (!ready)
  2228. {
  2229. // try old MTGL
  2230. result = CGLEnable( context, kCGLCEMPEngine );
  2231. if (!result)
  2232. {
  2233. printf("\nMTGL has been detected.\n");
  2234. ready = true; // succeeded - no need to try non-MTGL
  2235. }
  2236. }
  2237. }
  2238. if ( m_caps.m_badDriver108Intel )
  2239. {
  2240. // this way we have something to look for in terminal spew if users report issues related to this in the future.
  2241. printf( "\nEnabling GLSL compiler `malloc' workaround.\n" );
  2242. if ( !IntelGLMallocWorkaround::Get()->Enable() )
  2243. {
  2244. Warning( "Unable to enable OSX 10.8 / Intel HD4000 workaround, there might be crashes.\n" );
  2245. }
  2246. }
  2247. #endif
  2248. // also, set the remote convar "gl_can_query_fast" to 1 if perf package present, else 0.
  2249. gl_can_query_fast.SetValue( m_caps.m_hasPerfPackage1?1:0 );
  2250. #if GL_BATCH_PERF_ANALYSIS
  2251. m_nTotalVSUniformCalls = 0;
  2252. m_nTotalVSUniformBoneCalls = 0;
  2253. m_nTotalVSUniformsSet = 0;
  2254. m_nTotalVSUniformsBoneSet = 0;
  2255. m_nTotalPSUniformCalls = 0;
  2256. m_nTotalPSUniformsSet = 0;
  2257. #endif
  2258. // See g_D3DRS_INFO_packed in dxabstract.cpp; dithering is a non-managed
  2259. // piece of state that we consider off by default. However it is actually
  2260. // enabled by default in the GL spec, so account for that here.
  2261. // See: https://bugs.freedesktop.org/show_bug.cgi?id=74700
  2262. gGL->glDisable( GL_DITHER );
  2263. }
  2264. void GLMContext::Reset()
  2265. {
  2266. }
  2267. GLMContext::~GLMContext ()
  2268. {
  2269. #ifndef OSX
  2270. GLMGPUTimestampManagerDeinit();
  2271. for ( uint t = 0; t < cNumPinnedMemoryBuffers; t++ )
  2272. {
  2273. m_PinnedMemoryBuffers[t].Deinit();
  2274. }
  2275. if (gGL->m_bHave_GL_ARB_buffer_storage)
  2276. {
  2277. for (uint lpType = 0; lpType < kGLMNumBufferTypes; ++lpType)
  2278. {
  2279. for (uint lpNum = 0; lpNum < cNumPersistentBuffers; ++lpNum)
  2280. {
  2281. m_persistentBuffer[lpNum][lpType].Deinit();
  2282. }
  2283. }
  2284. }
  2285. if ( m_bUseSamplerObjects )
  2286. {
  2287. for( int i=0; i< GLM_SAMPLER_COUNT; i++)
  2288. {
  2289. gGL->glBindSampler( i, 0 );
  2290. }
  2291. for( int i=0; i< cSamplerObjectHashSize; i++)
  2292. {
  2293. gGL->glDeleteSamplers( 1, &m_samplerObjectHash[i].m_samplerObject );
  2294. m_samplerObjectHash[i].m_samplerObject = 0;
  2295. }
  2296. }
  2297. #endif // !OSX
  2298. if (m_debugFontTex)
  2299. {
  2300. DelTex( m_debugFontTex );
  2301. m_debugFontTex = NULL;
  2302. }
  2303. ProcessTextureDeletes();
  2304. if ( m_pNullFragmentProgram )
  2305. {
  2306. DelProgram( m_pNullFragmentProgram );
  2307. m_pNullFragmentProgram = NULL;
  2308. }
  2309. // walk m_fboTable and free them up..
  2310. FOR_EACH_VEC( m_fboTable, i )
  2311. {
  2312. CGLMFBO *fbo = m_fboTable[i];
  2313. DelFBO( fbo );
  2314. }
  2315. m_fboTable.SetSize( 0 );
  2316. if (m_pairCache)
  2317. {
  2318. delete m_pairCache;
  2319. m_pairCache = NULL;
  2320. }
  2321. // we need a m_texTable I think..
  2322. // m_texLayoutTable can be scrubbed once we know that all the tex are freed
  2323. gGL->glDeleteBuffersARB( 1, &m_destroyPBO );
  2324. PurgeTexCache();
  2325. DecrementWindowRefCount();
  2326. }
  2327. // This method must call SelectTMU()/glActiveTexture() (it's expected as a side effect).
  2328. // This method is no longer called from any performance sensitive code paths.
  2329. void GLMContext::BindTexToTMU( CGLMTex *pTex, int tmu )
  2330. {
  2331. #if GLMDEBUG
  2332. GLM_FUNC;
  2333. #endif
  2334. GLMPRINTF(("--- GLMContext::BindTexToTMU tex %p GL name %d -> TMU %d ", pTex, pTex ? pTex->m_texName : -1, tmu ));
  2335. CheckCurrent();
  2336. SelectTMU( tmu );
  2337. if ( !pTex )
  2338. {
  2339. gGL->glBindTexture( GL_TEXTURE_1D, 0 );
  2340. gGL->glBindTexture( GL_TEXTURE_2D, 0 );
  2341. gGL->glBindTexture( GL_TEXTURE_3D, 0 );
  2342. gGL->glBindTexture( GL_TEXTURE_CUBE_MAP, 0 );
  2343. }
  2344. else
  2345. {
  2346. const GLenum texGLTarget = pTex->m_texGLTarget;
  2347. if ( texGLTarget != GL_TEXTURE_1D ) gGL->glBindTexture( GL_TEXTURE_1D, 0 );
  2348. if ( texGLTarget != GL_TEXTURE_2D ) gGL->glBindTexture( GL_TEXTURE_2D, 0 );
  2349. if ( texGLTarget != GL_TEXTURE_3D ) gGL->glBindTexture( GL_TEXTURE_3D, 0 );
  2350. if ( texGLTarget != GL_TEXTURE_CUBE_MAP ) gGL->glBindTexture( GL_TEXTURE_CUBE_MAP, 0 );
  2351. gGL->glBindTexture( texGLTarget, pTex->m_texName );
  2352. }
  2353. m_samplers[tmu].m_pBoundTex = pTex;
  2354. }
  2355. void GLMContext::BindFBOToCtx( CGLMFBO *fbo, GLenum bindPoint )
  2356. {
  2357. #if GLMDEBUG
  2358. GLM_FUNC;
  2359. #endif
  2360. GLMPRINTF(( "--- GLMContext::BindFBOToCtx fbo %p, GL name %d", fbo, (fbo) ? fbo->m_name : -1 ));
  2361. CheckCurrent();
  2362. if ( bindPoint == GL_FRAMEBUFFER_EXT )
  2363. {
  2364. gGL->glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, fbo ? fbo->m_name : 0 );
  2365. m_boundReadFBO = fbo;
  2366. m_boundDrawFBO = fbo;
  2367. return;
  2368. }
  2369. bool targetRead = (bindPoint==GL_READ_FRAMEBUFFER_EXT);
  2370. bool targetDraw = (bindPoint==GL_DRAW_FRAMEBUFFER_EXT);
  2371. if (targetRead)
  2372. {
  2373. if (fbo) // you can pass NULL to go back to no-FBO
  2374. {
  2375. gGL->glBindFramebufferEXT( GL_READ_FRAMEBUFFER_EXT, fbo->m_name );
  2376. m_boundReadFBO = fbo;
  2377. //dontcare fbo->m_bound = true;
  2378. }
  2379. else
  2380. {
  2381. gGL->glBindFramebufferEXT( GL_READ_FRAMEBUFFER_EXT, 0 );
  2382. m_boundReadFBO = NULL;
  2383. }
  2384. }
  2385. if (targetDraw)
  2386. {
  2387. if (fbo) // you can pass NULL to go back to no-FBO
  2388. {
  2389. gGL->glBindFramebufferEXT( GL_DRAW_FRAMEBUFFER_EXT, fbo->m_name );
  2390. m_boundDrawFBO = fbo;
  2391. //dontcare fbo->m_bound = true;
  2392. }
  2393. else
  2394. {
  2395. gGL->glBindFramebufferEXT( GL_DRAW_FRAMEBUFFER_EXT, 0 );
  2396. m_boundDrawFBO = NULL;
  2397. }
  2398. }
  2399. }
  2400. void GLMContext::BindBufferToCtx( EGLMBufferType type, CGLMBuffer *pBuff, bool bForce )
  2401. {
  2402. #if GLMDEBUG
  2403. GLM_FUNC;
  2404. #endif
  2405. GLMPRINTF(( "--- GLMContext::BindBufferToCtx buff %p, GL name %d", pBuff, (pBuff) ? pBuff->m_nHandle : -1 ));
  2406. CheckCurrent();
  2407. GLuint nGLName = pBuff ? pBuff->GetHandle() : 0;
  2408. if ( !bForce )
  2409. {
  2410. if ( m_nBoundGLBuffer[type] == nGLName )
  2411. return;
  2412. }
  2413. GLenum target = 0;
  2414. switch( type )
  2415. {
  2416. case kGLMVertexBuffer: target = GL_ARRAY_BUFFER_ARB; break;
  2417. case kGLMIndexBuffer: target = GL_ELEMENT_ARRAY_BUFFER_ARB; break;
  2418. case kGLMUniformBuffer: target = GL_UNIFORM_BUFFER_EXT; break;
  2419. case kGLMPixelBuffer: target = GL_PIXEL_UNPACK_BUFFER_ARB; break;
  2420. default: Assert(!"Unknown buffer type" );
  2421. }
  2422. Assert( !pBuff || ( pBuff->m_buffGLTarget == target ) );
  2423. m_nBoundGLBuffer[type] = nGLName;
  2424. gGL->glBindBufferARB( target, nGLName );
  2425. }
  2426. GLuint GLMContext::CreateTex( GLenum texBind, GLenum internalFormat )
  2427. {
  2428. GLM_FUNC;
  2429. // If we're not doing batch create, just return one here.
  2430. if ( !gl_batch_tex_creates.GetBool() )
  2431. {
  2432. GLuint tex = 0;
  2433. gGL->glGenTextures( 1, &tex );
  2434. return tex;
  2435. }
  2436. FOR_EACH_VEC( m_availableTextures, i )
  2437. {
  2438. TextureEntry_t& tex = m_availableTextures[ i ];
  2439. if ( ( tex.m_nTexBind == GL_NONE || tex.m_nTexBind == texBind )
  2440. && ( tex.m_nInternalFormat == GL_NONE || tex.m_nInternalFormat == internalFormat ) )
  2441. {
  2442. // Hit!
  2443. GLuint retVal = tex.m_nTexName;
  2444. m_availableTextures.Remove( i );
  2445. return retVal;
  2446. }
  2447. }
  2448. if ( m_availableTextures.Count() >= kGLMHighWaterUndeleted )
  2449. {
  2450. PurgeTexCache();
  2451. }
  2452. return FillTexCache( true, kGLMReUpTexCount );
  2453. }
  2454. void GLMContext::CleanupTex( GLenum texBind, GLMTexLayout* pLayout, GLuint tex )
  2455. {
  2456. // If the total
  2457. if ( pLayout->m_storageTotalSize <= ( kDeletedTextureDim * kDeletedTextureDim * sizeof( uint32 ) ) )
  2458. return;
  2459. const GLuint oldPBO = m_nBoundGLBuffer[ kGLMPixelBuffer ];
  2460. const GLuint oldTex = ( m_samplers[ m_activeTexture ].m_pBoundTex != NULL ) ? m_samplers[ m_activeTexture ].m_pBoundTex->GetTexName() : 0;
  2461. gGL->glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, m_destroyPBO );
  2462. gGL->glBindTexture( texBind, tex );
  2463. // Clear out old data.
  2464. for ( int i = 0; i < pLayout->m_mipCount; ++i )
  2465. {
  2466. int mipDim = ( i == 0 ) ? kDeletedTextureDim : 0;
  2467. if ( pLayout->m_format->m_chunkSize != 1 )
  2468. {
  2469. const int chunks = ( mipDim + ( pLayout->m_format->m_chunkSize - 1 ) ) / pLayout->m_format->m_chunkSize;
  2470. const int dataSize = ( chunks * chunks ) * pLayout->m_format->m_bytesPerSquareChunk;
  2471. Assert( dataSize <= ( sizeof( uint32) * ARRAYSIZE( g_garbageTextureBits ) ) );
  2472. gGL->glCompressedTexImage2D( texBind, i, pLayout->m_format->m_glIntFormat, mipDim, mipDim, 0, dataSize, 0 );
  2473. }
  2474. else
  2475. {
  2476. gGL->glTexImage2D( texBind, i, pLayout->m_format->m_glIntFormat, mipDim, mipDim, 0, pLayout->m_format->m_glDataFormat, pLayout->m_format->m_glDataType, 0 );
  2477. }
  2478. }
  2479. gGL->glBindTexture( texBind, oldTex );
  2480. gGL->glBindBufferARB( GL_PIXEL_UNPACK_BUFFER_ARB, oldPBO );
  2481. }
  2482. void GLMContext::DestroyTex( GLenum texBind, GLMTexLayout* pLayout, GLuint tex )
  2483. {
  2484. GLM_FUNC;
  2485. // Code only handles 2D for now.
  2486. if ( texBind != GL_TEXTURE_2D || !gl_batch_tex_destroys.GetBool() )
  2487. {
  2488. gGL->glDeleteTextures( 1, &tex );
  2489. return;
  2490. }
  2491. CleanupTex( texBind, pLayout, tex );
  2492. TextureEntry_t entry;
  2493. entry.m_nTexBind = texBind;
  2494. entry.m_nInternalFormat = pLayout->m_format->m_glIntFormat;
  2495. entry.m_nTexName = tex;
  2496. m_availableTextures.AddToTail( entry );
  2497. }
  2498. GLuint GLMContext::FillTexCache( bool holdOne, int newTextures )
  2499. {
  2500. // If we aren't doing batch creates, then don't fill the cache.
  2501. if ( !gl_batch_tex_creates.GetBool() )
  2502. return 0;
  2503. // If we have to hit the name table, might as well hit it a bunch because this causes
  2504. // serialization either way--at least we can do it less often.
  2505. GLuint* textures = (GLuint*) stackalloc( newTextures * sizeof( GLuint ) );
  2506. gGL->glGenTextures( newTextures, textures );
  2507. Assert( textures[ 0 ] );
  2508. TextureEntry_t entry;
  2509. entry.m_nTexBind = GL_NONE;
  2510. entry.m_nInternalFormat = GL_NONE;
  2511. // We may return 0, so skip adding it here.
  2512. for ( int i = 1; i < newTextures; ++i )
  2513. {
  2514. Assert( textures[ i ] );
  2515. if ( textures[ i ] )
  2516. {
  2517. // We still add these to the tail because we'd prefer to reuse old textures (rather
  2518. // than these new ones).
  2519. entry.m_nTexName = textures[ i ];
  2520. m_availableTextures.AddToTail( entry );
  2521. }
  2522. }
  2523. if ( holdOne )
  2524. return textures[ 0 ];
  2525. // If not, stick that last one in the list and return 0.
  2526. entry.m_nTexName = textures[ 0 ];
  2527. m_availableTextures.AddToTail( entry );
  2528. return 0;
  2529. }
  2530. void GLMContext::PurgeTexCache()
  2531. {
  2532. GLM_FUNC;
  2533. int textureCount = m_availableTextures.Count();
  2534. if ( textureCount == 0 )
  2535. return;
  2536. GLuint* textures = (GLuint*) stackalloc( textureCount * sizeof( GLuint ) );
  2537. FOR_EACH_VEC( m_availableTextures, i )
  2538. {
  2539. TextureEntry_t& tex = m_availableTextures[ i ];
  2540. textures[ i ] = tex.m_nTexName;
  2541. }
  2542. gGL->glDeleteTextures( textureCount, textures );
  2543. m_availableTextures.RemoveAll();
  2544. }
  2545. #ifdef OSX
  2546. // As far as I can tell this stuff is only useful under OSX.
  2547. ConVar gl_can_mix_shader_gammas( "gl_can_mix_shader_gammas", 0 );
  2548. ConVar gl_cannot_mix_shader_gammas( "gl_cannot_mix_shader_gammas", 0 );
  2549. #endif
  2550. // ConVar param_write_mode("param_write_mode", "0");
  2551. void GLMContext::MarkAllSamplersDirty()
  2552. {
  2553. m_nNumDirtySamplers = GLM_SAMPLER_COUNT;
  2554. for (uint i = 0; i < GLM_SAMPLER_COUNT; i++)
  2555. {
  2556. m_nDirtySamplerFlags[i] = 0;
  2557. m_nDirtySamplers[i] = (uint8)i;
  2558. }
  2559. }
  2560. void GLMContext::FlushDrawStatesNoShaders( )
  2561. {
  2562. Assert( ( m_drawingFBO == m_boundDrawFBO ) && ( m_drawingFBO == m_boundReadFBO ) ); // this check MUST succeed
  2563. GLM_FUNC;
  2564. GL_BATCH_PERF( m_FlushStats.m_nTotalBatchFlushes++; )
  2565. NullProgram();
  2566. }
  2567. #if GLMDEBUG
  2568. enum EGLMDebugDumpOptions
  2569. {
  2570. eDumpBatchInfo,
  2571. eDumpSurfaceInfo,
  2572. eDumpStackCrawl,
  2573. eDumpShaderLinks,
  2574. // eDumpShaderText, // we never use this one
  2575. eDumpShaderParameters,
  2576. eDumpTextureSetup,
  2577. eDumpVertexAttribSetup,
  2578. eDumpVertexData,
  2579. eOpenShadersForEdit
  2580. };
  2581. enum EGLMVertDumpMode
  2582. {
  2583. // options that affect eDumpVertexData above
  2584. eDumpVertsNoTransformDump,
  2585. eDumpVertsTransformedByViewProj,
  2586. eDumpVertsTransformedByModelViewProj,
  2587. eDumpVertsTransformedByBoneZeroThenViewProj,
  2588. eDumpVertsTransformedByBonesThenViewProj,
  2589. eLastDumpVertsMode
  2590. };
  2591. char *g_vertDumpModeNames[] =
  2592. {
  2593. "noTransformDump",
  2594. "transformedByViewProj",
  2595. "transformedByModelViewProj",
  2596. "transformedByBoneZeroThenViewProj",
  2597. "transformedByBonesThenViewProj"
  2598. };
  2599. static void CopyTilEOL( char *dst, char *src, int dstSize )
  2600. {
  2601. dstSize--;
  2602. int i=0;
  2603. while ( (i<dstSize) && (src[i] != 0) && (src[i] != '\n') && (src[i] != '\r') )
  2604. {
  2605. dst[i] = src[i];
  2606. i++;
  2607. }
  2608. dst[i] = 0;
  2609. }
  2610. static uint g_maxVertsToDumpLog2 = 4;
  2611. static uint g_maxFramesToCrawl = 20; // usually enough. Not enough? change it..
  2612. extern char sg_pPIXName[128];
  2613. // min is eDumpVertsNormal, max is the one before eLastDumpVertsMode
  2614. static enum EGLMVertDumpMode g_vertDumpMode = eDumpVertsNoTransformDump;
  2615. void GLMContext::DebugDump( GLMDebugHookInfo *info, uint options, uint vertDumpMode )
  2616. {
  2617. int oldIndent = GLMGetIndent();
  2618. GLMSetIndent(0);
  2619. CGLMProgram *vp = m_drawingProgram[kGLMVertexProgram];
  2620. CGLMProgram *fp = m_drawingProgram[kGLMFragmentProgram];
  2621. bool is_draw = (info->m_caller==eDrawElements);
  2622. const char *batchtype = is_draw ? "draw" : "clear";
  2623. if (options & (1<<eDumpBatchInfo))
  2624. {
  2625. GLMPRINTF(("-D- %s === %s %d ======================================================== %s %d frame %d", sg_pPIXName, batchtype, m_nBatchCounter, batchtype, m_nBatchCounter, m_debugFrameIndex ));
  2626. }
  2627. if (options & (1<<eDumpSurfaceInfo))
  2628. {
  2629. GLMPRINTF(("-D-" ));
  2630. GLMPRINTF(("-D- surface info:"));
  2631. GLMPRINTF(("-D- drawing FBO: %8x bound draw-FBO: %8x (%s)", m_drawingFBO, m_boundDrawFBO, (m_drawingFBO==m_boundDrawFBO) ? "in sync" : "desync!" ));
  2632. CGLMFBO *fbo = m_boundDrawFBO;
  2633. for( int i=0; i<kAttCount; i++)
  2634. {
  2635. CGLMTex *tex = fbo->m_attach[i].m_tex;
  2636. if (tex)
  2637. {
  2638. GLMPRINTF(("-D- bound FBO (%8x) attachment %d = tex %8x (GL %d) (%s)", fbo, i, tex, tex->m_texName, tex->m_layout->m_layoutSummary ));
  2639. }
  2640. else
  2641. {
  2642. // warning if no depthstencil attachment
  2643. switch(i)
  2644. {
  2645. case kAttDepth:
  2646. case kAttStencil:
  2647. case kAttDepthStencil:
  2648. GLMPRINTF(("-D- bound FBO (%8x) attachment %d = NULL, warning!", fbo, i ));
  2649. break;
  2650. }
  2651. }
  2652. }
  2653. }
  2654. if (options & (1<<eDumpStackCrawl))
  2655. {
  2656. CStackCrawlParams cp;
  2657. memset( &cp, 0, sizeof(cp) );
  2658. cp.m_frameLimit = g_maxFramesToCrawl;
  2659. GetStackCrawl(&cp);
  2660. GLMPRINTF(("-D-" ));
  2661. GLMPRINTF(("-D- stack crawl"));
  2662. for( uint i=0; i< cp.m_frameCount; i++)
  2663. {
  2664. GLMPRINTF(("-D-\t%s", cp.m_crawlNames[i] ));
  2665. }
  2666. }
  2667. if ( (options & (1<<eDumpShaderLinks)) && is_draw)
  2668. {
  2669. // we want to print out - GL name, pathname to disk copy if editable, extra credit would include the summary translation line
  2670. // so grep for "#// trans#"
  2671. char attribtemp[1000];
  2672. char transtemp[1000];
  2673. if (vp)
  2674. {
  2675. char *attribmap = strstr(vp->m_text, "#//ATTRIBMAP");
  2676. if (attribmap)
  2677. {
  2678. CopyTilEOL( attribtemp, attribmap, sizeof(attribtemp) );
  2679. }
  2680. else
  2681. {
  2682. strcpy( attribtemp, "no attrib map" );
  2683. }
  2684. char *trans = strstr(vp->m_text, "#// trans#");
  2685. if (trans)
  2686. {
  2687. CopyTilEOL( transtemp, trans, sizeof(transtemp) );
  2688. }
  2689. else
  2690. {
  2691. strcpy( transtemp, "no translation info" );
  2692. }
  2693. char *linkpath = "no file link";
  2694. #if GLMDEBUG
  2695. linkpath = vp->m_editable->m_mirror->m_path;
  2696. #endif
  2697. GLMPRINTF(("-D-"));
  2698. GLMPRINTF(("-D- ARBVP || GL %d || Path %s ", vp->m_descs[kGLMARB].m_object.arb, linkpath ));
  2699. GLMPRINTF(("-D- Attribs %s", attribtemp ));
  2700. GLMPRINTF(("-D- Trans %s", transtemp ));
  2701. /*
  2702. if ( (options & (1<<eDumpShaderText)) && is_draw )
  2703. {
  2704. GLMPRINTF(("-D-"));
  2705. GLMPRINTF(("-D- VP text " ));
  2706. GLMPRINTTEXT(vp->m_string, eDebugDump ));
  2707. }
  2708. */
  2709. }
  2710. else
  2711. {
  2712. GLMPRINTF(("-D- VP (none)" ));
  2713. }
  2714. if (fp)
  2715. {
  2716. char *trans = strstr(fp->m_text, "#// trans#");
  2717. if (trans)
  2718. {
  2719. CopyTilEOL( transtemp, trans, sizeof(transtemp) );
  2720. }
  2721. else
  2722. {
  2723. strcpy( transtemp, "no translation info" );
  2724. }
  2725. char *linkpath = "no file link";
  2726. #if GLMDEBUG
  2727. linkpath = fp->m_editable->m_mirror->m_path;
  2728. #endif
  2729. GLMPRINTF(("-D-"));
  2730. GLMPRINTF(("-D- FP || GL %d || Path %s ", fp->m_descs[kGLMARB].m_object.arb, linkpath ));
  2731. GLMPRINTF(("-D- Trans %s", transtemp ));
  2732. /*
  2733. if ( (options & (1<<eDumpShaderText)) && is_draw )
  2734. {
  2735. GLMPRINTF(("-D-"));
  2736. GLMPRINTF(("-D- FP text " ));
  2737. GLMPRINTTEXT((fp->m_string, eDebugDump));
  2738. }
  2739. */
  2740. }
  2741. else
  2742. {
  2743. GLMPRINTF(("-D- FP (none)" ));
  2744. }
  2745. }
  2746. if ( (options & (1<<eDumpShaderParameters)) && is_draw )
  2747. {
  2748. GLMPRINTF(("-D-"));
  2749. GLMPRINTF(("-D- VP parameters" ));
  2750. char *label = "";
  2751. //int labelcounter = 0;
  2752. static int vmaskranges[] = { /*18,47,*/ -1,-1 };
  2753. //float transposeTemp; // row, column for printing
  2754. int slotIndex = 0;
  2755. int upperSlotLimit = 61;
  2756. // take a peek at the vertex attrib setup. If it has an attribute for bone weights, then raise the shader param dump limit to 256.
  2757. bool usesSkinning = false;
  2758. GLMVertexSetup *pSetup = &m_drawVertexSetup;
  2759. for( int index=0; index < kGLMVertexAttributeIndexMax; index++ )
  2760. {
  2761. usesSkinning |= (pSetup->m_attrMask & (1<<index)) && ((pSetup->m_vtxAttribMap[index]>>4)== D3DDECLUSAGE_BLENDWEIGHT);
  2762. }
  2763. if (usesSkinning)
  2764. {
  2765. upperSlotLimit = 256;
  2766. }
  2767. while( slotIndex < upperSlotLimit )
  2768. {
  2769. // if slot index is in a masked range, skip it
  2770. // if slot index is the start of a matrix, label it, print it, skip ahead 4 slots
  2771. for( int maski=0; vmaskranges[maski] >=0; maski+=2)
  2772. {
  2773. if ( (slotIndex >= vmaskranges[maski]) && (slotIndex <= vmaskranges[maski+1]) )
  2774. {
  2775. // that index is masked. set to one past end of range, print a blank line for clarity
  2776. slotIndex = vmaskranges[maski+1]+1;
  2777. GLMPrintStr("-D- .....");
  2778. }
  2779. }
  2780. if (slotIndex < upperSlotLimit)
  2781. {
  2782. float *values = &m_programParamsF[ kGLMVertexProgram ].m_values[slotIndex][0];
  2783. switch( slotIndex )
  2784. {
  2785. case 4:
  2786. printmat( "MODELVIEWPROJ", slotIndex, 4, values );
  2787. slotIndex += 4;
  2788. break;
  2789. case 8:
  2790. printmat( "VIEWPROJ", slotIndex, 4, values );
  2791. slotIndex += 4;
  2792. break;
  2793. default:
  2794. if (slotIndex>=58)
  2795. {
  2796. // bone
  2797. char bonelabel[100];
  2798. sprintf(bonelabel, "MODEL_BONE%-2d", (slotIndex-58)/3 );
  2799. printmat( bonelabel, slotIndex, 3, values );
  2800. slotIndex += 3;
  2801. }
  2802. else
  2803. {
  2804. // just print the one slot
  2805. GLMPRINTF(("-D- %03d: [ %10.5f %10.5f %10.5f %10.5f ] %s", slotIndex, values[0], values[1], values[2], values[3], label ));
  2806. slotIndex++;
  2807. }
  2808. break;
  2809. }
  2810. }
  2811. }
  2812. // VP stage still, if in GLSL mode, find the bound pair and see if it has live i0, b0-b3 uniforms
  2813. if (m_pBoundPair) // should only be non-NULL in GLSL mode
  2814. {
  2815. #if 0
  2816. if (m_pBoundPair->m_locVertexBool0>=0)
  2817. {
  2818. GLMPRINTF(("-D- GLSL 'b0': %d", m_programParamsB[kGLMVertexProgram].m_values[0] ));
  2819. }
  2820. if (m_pBoundPair->m_locVertexBool1>=0)
  2821. {
  2822. GLMPRINTF(("-D- GLSL 'b1': %d", m_programParamsB[kGLMVertexProgram].m_values[1] ));
  2823. }
  2824. if (m_pBoundPair->m_locVertexBool2>=0)
  2825. {
  2826. GLMPRINTF(("-D- GLSL 'b2': %d", m_programParamsB[kGLMVertexProgram].m_values[2] ));
  2827. }
  2828. if (m_pBoundPair->m_locVertexBool3>=0)
  2829. {
  2830. GLMPRINTF(("-D- GLSL 'b3': %d", m_programParamsB[kGLMVertexProgram].m_values[3] ));
  2831. }
  2832. if (m_pBoundPair->m_locVertexInteger0>=0)
  2833. {
  2834. GLMPRINTF(("-D- GLSL 'i0': %d", m_programParamsI[kGLMVertexProgram].m_values[0][0] ));
  2835. }
  2836. #endif
  2837. }
  2838. GLMPRINTF(("-D-"));
  2839. GLMPRINTF(("-D- FP parameters " ));
  2840. static int fmaskranges[] = { 40,41, -1,-1 };
  2841. slotIndex = 0;
  2842. label = "";
  2843. while(slotIndex < 40)
  2844. {
  2845. // if slot index is in a masked range, skip it
  2846. // if slot index is the start of a matrix, label it, print it, skip ahead 4 slots
  2847. for( int maski=0; fmaskranges[maski] >=0; maski+=2)
  2848. {
  2849. if ( (slotIndex >= fmaskranges[maski]) && (slotIndex <= fmaskranges[maski+1]) )
  2850. {
  2851. // that index is masked. set to one past end of range, print a blank line for clarity
  2852. slotIndex = fmaskranges[maski+1]+1;
  2853. GLMPrintStr("-D- .....");
  2854. }
  2855. }
  2856. if (slotIndex < 40)
  2857. {
  2858. float *values = &m_programParamsF[ kGLMFragmentProgram ].m_values[slotIndex][0];
  2859. switch( slotIndex )
  2860. {
  2861. case 0: label = "g_EnvmapTint"; break;
  2862. case 1: label = "g_DiffuseModulation"; break;
  2863. case 2: label = "g_EnvmapContrast_ShadowTweaks"; break;
  2864. case 3: label = "g_EnvmapSaturation_SelfIllumMask (xyz, and w)"; break;
  2865. case 4: label = "g_SelfIllumTint_and_BlendFactor (xyz, and w)"; break;
  2866. case 12: label = "g_ShaderControls"; break;
  2867. case 13: label = "g_DepthFeatheringConstants"; break;
  2868. case 20: label = "g_EyePos"; break;
  2869. case 21: label = "g_FogParams"; break;
  2870. case 22: label = "g_FlashlightAttenuationFactors"; break;
  2871. case 23: label = "g_FlashlightPos"; break;
  2872. case 24: label = "g_FlashlightWorldToTexture"; break;
  2873. case 28: label = "cFlashlightColor"; break;
  2874. case 29: label = "g_LinearFogColor"; break;
  2875. case 30: label = "cLightScale"; break;
  2876. case 31: label = "cFlashlightScreenScale"; break;
  2877. default:
  2878. label = "";
  2879. break;
  2880. }
  2881. GLMPRINTF(("-D- %03d: [ %10.5f %10.5f %10.5f %10.5f ] %s", slotIndex, values[0], values[1], values[2], values[3], label ));
  2882. slotIndex ++;
  2883. }
  2884. }
  2885. if (m_pBoundPair->m_locFragmentFakeSRGBEnable)
  2886. {
  2887. GLMPRINTF(("-D- GLSL 'flEnableSRGBWrite': %f", m_pBoundPair->m_fakeSRGBEnableValue ));
  2888. }
  2889. }
  2890. if ( (options & (1<<eDumpTextureSetup)) && is_draw )
  2891. {
  2892. GLMPRINTF(( "-D-" ));
  2893. GLMPRINTF(( "-D- Texture / Sampler setup" ));
  2894. GLMPRINTF(( "-D- TODO" ));
  2895. #if 0
  2896. for( int i=0; i<GLM_SAMPLER_COUNT; i++ )
  2897. {
  2898. if (m_samplers[i].m_pBoundTex)
  2899. {
  2900. GLMTexSamplingParams *samp = &m_samplers[i].m_samp;
  2901. GLMPRINTF(( "-D-" ));
  2902. GLMPRINTF(("-D- Sampler %-2d tex %08x layout %s", i, m_samplers[i].m_pBoundTex, m_samplers[i].m_pBoundTex->m_layout->m_layoutSummary ));
  2903. GLMPRINTF(("-D- addressMode[ %s %s %s ]",
  2904. GLMDecode( eGL_ENUM, samp->m_addressModes[0] ),
  2905. GLMDecode( eGL_ENUM, samp->m_addressModes[1] ),
  2906. GLMDecode( eGL_ENUM, samp->m_addressModes[2] )
  2907. ));
  2908. GLMPRINTF(("-D- magFilter [ %s ]", GLMDecode( eGL_ENUM, samp->m_magFilter ) ));
  2909. GLMPRINTF(("-D- minFilter [ %s ]", GLMDecode( eGL_ENUM, samp->m_minFilter ) ));
  2910. GLMPRINTF(("-D- srgb [ %s ]", samp->m_srgb ? "T" : "F" ));
  2911. GLMPRINTF(("-D- shadowFilter [ %s ]", samp->m_compareMode == GL_COMPARE_R_TO_TEXTURE_ARB ? "T" : "F" ));
  2912. // add more as needed later..
  2913. }
  2914. }
  2915. #endif
  2916. }
  2917. if ( (options & (1<<eDumpVertexAttribSetup)) && is_draw )
  2918. {
  2919. GLMVertexSetup *pSetup = &m_drawVertexSetup;
  2920. uint nRelevantMask = pSetup->m_attrMask;
  2921. for( int index=0; index < kGLMVertexAttributeIndexMax; index++ )
  2922. {
  2923. uint mask = 1<<index;
  2924. if (nRelevantMask & mask)
  2925. {
  2926. GLMVertexAttributeDesc *setdesc = &pSetup->m_attrs[index];
  2927. char sizestr[100];
  2928. if (setdesc->m_nCompCount < 32)
  2929. {
  2930. sprintf( sizestr, "%d", setdesc->m_nCompCount);
  2931. }
  2932. else
  2933. {
  2934. strcpy( sizestr, GLMDecode( eGL_ENUM, setdesc->m_nCompCount ) );
  2935. }
  2936. if (pSetup->m_vtxAttribMap[index] != 0xBB)
  2937. {
  2938. GLMPRINTF(("-D- attr=%-2d decl=$%s%1d stride=%-2d offset=%-3d buf=%08x size=%s type=%s normalized=%s ",
  2939. index,
  2940. GLMDecode(eD3D_VTXDECLUSAGE, pSetup->m_vtxAttribMap[index]>>4 ),
  2941. pSetup->m_vtxAttribMap[index]&0x0F,
  2942. setdesc->m_stride,
  2943. setdesc->m_offset,
  2944. setdesc->m_pBuffer,
  2945. sizestr,
  2946. GLMDecode( eGL_ENUM, setdesc->m_datatype),
  2947. setdesc->m_normalized?"Y":"N"
  2948. ));
  2949. }
  2950. else
  2951. {
  2952. // the attrib map is referencing an attribute that is not wired up in the vertex setup...
  2953. DebuggerBreak();
  2954. }
  2955. }
  2956. }
  2957. }
  2958. if ( (options & (1<<eDumpVertexData)) && is_draw )
  2959. {
  2960. GLMVertexSetup *pSetup = &m_drawVertexSetup;
  2961. int start = info->m_drawStart;
  2962. int end = info->m_drawEnd;
  2963. int endLimit = start + (1<<g_maxVertsToDumpLog2);
  2964. int realEnd = MIN( end, endLimit );
  2965. // vertex data
  2966. GLMPRINTF(("-D-"));
  2967. GLMPRINTF(("-D- Vertex Data : %d of %d verts (index %d through %d)", realEnd-start, end-start, start, realEnd-1));
  2968. for( int vtxIndex=-1; vtxIndex < realEnd; vtxIndex++ ) // vtxIndex will jump from -1 to start after first spin, not necessarily to 0
  2969. {
  2970. char buf[64000];
  2971. char *mark = buf;
  2972. // index -1 is the first run through the loop, we just print a header
  2973. // iterate attrs
  2974. if (vtxIndex>=0)
  2975. {
  2976. mark += sprintf(mark, "-D- %04d: ", vtxIndex );
  2977. }
  2978. // for transform dumping, we latch values as we spot them
  2979. float vtxPos[4];
  2980. int vtxBoneIndices[4]; // only three get used
  2981. float vtxBoneWeights[4]; // only three get used and index 2 is synthesized from 0 and 1
  2982. vtxPos[0] = vtxPos[1] = vtxPos[2] = 0.0;
  2983. vtxPos[3] = 1.0;
  2984. vtxBoneIndices[0] = vtxBoneIndices[1] = vtxBoneIndices[2] = vtxBoneIndices[3] = 0;
  2985. vtxBoneWeights[0] = vtxBoneWeights[1] = vtxBoneWeights[2] = vtxBoneWeights[3] = 0.0;
  2986. for( int attr = 0; attr < kGLMVertexAttributeIndexMax; attr++ )
  2987. {
  2988. if (pSetup->m_attrMask & (1<<attr) )
  2989. {
  2990. GLMVertexAttributeDesc *desc = &pSetup->m_attrs[ attr ];
  2991. // print that attribute.
  2992. // on OSX, VB's never move unless resized. You can peek at them when unmapped. Safe enough for debug..
  2993. char *bufferBase = (char*)desc->m_pBuffer->m_pLastMappedAddress;
  2994. uint stride = desc->m_stride;
  2995. uint fieldoffset = desc->m_offset;
  2996. uint baseoffset = vtxIndex * stride;
  2997. char *attrBase = bufferBase + baseoffset + fieldoffset;
  2998. uint usage = pSetup->m_vtxAttribMap[attr]>>4;
  2999. uint usageindex = pSetup->m_vtxAttribMap[attr]&0x0F;
  3000. if (vtxIndex <0)
  3001. {
  3002. mark += sprintf(mark, "[%s%1d @ offs=%04d / strd %03d] ", GLMDecode(eD3D_VTXDECLUSAGE, usage ), usageindex, fieldoffset, stride );
  3003. }
  3004. else
  3005. {
  3006. mark += sprintf(mark, "[%s%1d ", GLMDecode(eD3D_VTXDECLUSAGE, usage ), usageindex );
  3007. if (desc->m_nCompCount<32)
  3008. {
  3009. for( uint which = 0; which < desc->m_nCompCount; which++ )
  3010. {
  3011. static char *fieldname = "xyzw";
  3012. switch( desc->m_datatype )
  3013. {
  3014. case GL_FLOAT:
  3015. {
  3016. float *floatbase = (float*)attrBase;
  3017. mark += sprintf(mark, (usage != D3DDECLUSAGE_TEXCOORD) ? "%c%7.3f " : "%c%.3f", fieldname[which], floatbase[which] );
  3018. if (usage==D3DDECLUSAGE_POSITION)
  3019. {
  3020. if (which<4)
  3021. {
  3022. // latch pos
  3023. vtxPos[which] = floatbase[which];
  3024. }
  3025. }
  3026. if (usage==D3DDECLUSAGE_BLENDWEIGHT)
  3027. {
  3028. if (which<4)
  3029. {
  3030. // latch weight
  3031. vtxBoneWeights[which] = floatbase[which];
  3032. }
  3033. }
  3034. }
  3035. break;
  3036. case GL_UNSIGNED_BYTE:
  3037. {
  3038. unsigned char *unchbase = (unsigned char*)attrBase;
  3039. mark += sprintf(mark, "%c$%02X ", fieldname[which], unchbase[which] );
  3040. }
  3041. break;
  3042. default:
  3043. // hold off on other formats for now
  3044. mark += sprintf(mark, "%c????? ", fieldname[which] );
  3045. break;
  3046. }
  3047. }
  3048. }
  3049. else // special path for BGRA bytes which are expressed in GL by setting the *size* to GL_BGRA (gross large enum)
  3050. {
  3051. switch(desc->m_nCompCount)
  3052. {
  3053. case GL_BGRA: // byte reversed color
  3054. {
  3055. for( int which = 0; which < 4; which++ )
  3056. {
  3057. static const char *fieldname = "BGRA";
  3058. switch( desc->m_datatype )
  3059. {
  3060. case GL_UNSIGNED_BYTE:
  3061. {
  3062. unsigned char *unchbase = (unsigned char*)attrBase;
  3063. mark += sprintf(mark, "%c$%02X ", fieldname[which], unchbase[which] );
  3064. if (usage==D3DDECLUSAGE_BLENDINDICES)
  3065. {
  3066. if (which<4)
  3067. {
  3068. // latch index
  3069. vtxBoneIndices[which] = unchbase[which]; // ignoring the component reverse which BGRA would inflict, but we also ignore it below so it matches up.
  3070. }
  3071. }
  3072. }
  3073. break;
  3074. default:
  3075. DebuggerBreak();
  3076. break;
  3077. }
  3078. }
  3079. }
  3080. break;
  3081. }
  3082. }
  3083. mark += sprintf(mark, "] " );
  3084. }
  3085. }
  3086. }
  3087. GLMPrintStr( buf, eDebugDump );
  3088. if (vtxIndex >=0)
  3089. {
  3090. // if transform dumping requested, and we've reached the actual vert dump phase, do it
  3091. float vtxout[4];
  3092. char *translabel = NULL; // NULL means no print...
  3093. switch( g_vertDumpMode )
  3094. {
  3095. case eDumpVertsNoTransformDump: break;
  3096. case eDumpVertsTransformedByViewProj: // viewproj is slot 8
  3097. {
  3098. float *viewproj = &m_programParamsF[ kGLMVertexProgram ].m_values[8][0];
  3099. transform_dp4( vtxPos, viewproj, 4, vtxout );
  3100. translabel = "post-viewproj";
  3101. }
  3102. break;
  3103. case eDumpVertsTransformedByModelViewProj: // modelviewproj is slot 4
  3104. {
  3105. float *modelviewproj = &m_programParamsF[ kGLMVertexProgram ].m_values[4][0];
  3106. transform_dp4( vtxPos, modelviewproj, 4, vtxout );
  3107. translabel = "post-modelviewproj";
  3108. }
  3109. break;
  3110. case eDumpVertsTransformedByBoneZeroThenViewProj:
  3111. {
  3112. float postbone[4];
  3113. postbone[3] = 1.0;
  3114. float *bonemat = &m_programParamsF[ kGLMVertexProgram ].m_values[58][0];
  3115. transform_dp4( vtxPos, bonemat, 3, postbone );
  3116. float *viewproj = &m_programParamsF[ kGLMVertexProgram ].m_values[8][0]; // viewproj is slot 8
  3117. transform_dp4( postbone, viewproj, 4, vtxout );
  3118. translabel = "post-bone0-viewproj";
  3119. }
  3120. break;
  3121. case eDumpVertsTransformedByBonesThenViewProj:
  3122. {
  3123. //float bone[4][4]; // [bone index][bone member] // members are adjacent
  3124. vtxout[0] = vtxout[1] = vtxout[2] = vtxout[3] = 0;
  3125. // unpack the third weight
  3126. vtxBoneWeights[2] = 1.0 - (vtxBoneWeights[0] + vtxBoneWeights[1]);
  3127. for( int ibone=0; ibone<3; ibone++ )
  3128. {
  3129. int boneindex = vtxBoneIndices[ ibone ];
  3130. float *bonemat = &m_programParamsF[ kGLMVertexProgram ].m_values[58+(boneindex*3)][0];
  3131. float boneweight = vtxBoneWeights[ibone];
  3132. float postbonevtx[4];
  3133. transform_dp4( vtxPos, bonemat, 3, postbonevtx );
  3134. // add weighted sum into output
  3135. for( int which=0; which<4; which++ )
  3136. {
  3137. vtxout[which] += boneweight * postbonevtx[which];
  3138. }
  3139. }
  3140. // fix W ? do we care ? check shaders to see what they do...
  3141. translabel = "post-skin3bone-viewproj";
  3142. }
  3143. break;
  3144. }
  3145. if(translabel)
  3146. {
  3147. // for extra credit, do the perspective divide and viewport
  3148. GLMPRINTF(("-D- %-24s: [ %7.4f %7.4f %7.4f %7.4f ]", translabel, vtxout[0],vtxout[1],vtxout[2],vtxout[3] ));
  3149. GLMPRINTF(("-D-" ));
  3150. }
  3151. }
  3152. if (vtxIndex<0)
  3153. {
  3154. vtxIndex = start-1; // for printing of the data (note it will be incremented at bottom of loop, so bias down by 1)
  3155. }
  3156. else
  3157. { // no more < and > around vert dump lines
  3158. //mark += sprintf(mark, "" );
  3159. }
  3160. }
  3161. }
  3162. if (options & (1<<eOpenShadersForEdit) )
  3163. {
  3164. #if GLMDEBUG
  3165. if (m_drawingProgram[ kGLMVertexProgram ])
  3166. {
  3167. m_drawingProgram[ kGLMVertexProgram ]->m_editable->OpenInEditor();
  3168. }
  3169. if (m_drawingProgram[ kGLMFragmentProgram ])
  3170. {
  3171. m_drawingProgram[ kGLMFragmentProgram ]->m_editable->OpenInEditor();
  3172. }
  3173. #endif
  3174. }
  3175. /*
  3176. if (options & (1<<))
  3177. {
  3178. }
  3179. */
  3180. // trailer line
  3181. GLMPRINTF(("-D- ===================================================================================== end %s %d frame %d", batchtype, m_nBatchCounter, m_debugFrameIndex ));
  3182. GLMSetIndent(oldIndent);
  3183. }
  3184. // here is the table that binds knob numbers to names. change at will.
  3185. char *g_knobnames[] =
  3186. {
  3187. /*0*/ "dummy",
  3188. /*1*/ "FB-SRGB",
  3189. #if 0
  3190. /*1*/ "tex-U0-bias", // src left
  3191. /*2*/ "tex-V0-bias", // src upper
  3192. /*3*/ "tex-U1-bias", // src right
  3193. /*4*/ "tex-V1-bias", // src bottom
  3194. /*5*/ "pos-X0-bias", // dst left
  3195. /*6*/ "pos-Y0-bias", // dst upper
  3196. /*7*/ "pos-X1-bias", // dst right
  3197. /*8*/ "pos-Y1-bias", // dst bottom
  3198. #endif
  3199. };
  3200. int g_knobcount = sizeof( g_knobnames ) / sizeof( g_knobnames[0] );
  3201. void GLMContext::DebugHook( GLMDebugHookInfo *info )
  3202. {
  3203. // FIXME: This has seriously bitrotted.
  3204. return;
  3205. bool debughook = false;
  3206. // debug hook is called after an action has taken place.
  3207. // that would be the initial action, or a repeat.
  3208. // if paused, we stay inside this function until return.
  3209. // when returning, we inform the caller if it should repeat its last action or continue.
  3210. // there is no global pause state. The rest of the app runs at the best speed it can.
  3211. // initial stuff we do unconditionally
  3212. // increment iteration
  3213. info->m_iteration++; // can be thought of as "number of times the caller's action has now occurred - starting at 1"
  3214. // now set initial state guess for the info block (outcome may change below)
  3215. info->m_loop = false;
  3216. // check prior hold-conditions to see if any of them hit.
  3217. // note we disarm each trigger once the hold has occurred (one-shot style)
  3218. switch( info->m_caller )
  3219. {
  3220. case eBeginFrame:
  3221. if (debughook) GLMPRINTF(("-D- Caller: BeginFrame" ));
  3222. if ( (m_holdFrameBegin>=0) && (m_holdFrameBegin==m_debugFrameIndex) ) // did we hit a frame breakpoint?
  3223. {
  3224. if (debughook) GLMPRINTF(("-D- BeginFrame trigger match, clearing m_holdFrameBegin, hold=true" ));
  3225. m_holdFrameBegin = -1;
  3226. info->m_holding = true;
  3227. }
  3228. break;
  3229. case eClear:
  3230. if (debughook) GLMPRINTF(("-D- Caller: Clear" ));
  3231. if ( (m_holdBatch>=0) && (m_holdBatchFrame>=0) && ((int)m_holdBatch==(int)m_nBatchCounter) && ((int)m_holdBatchFrame==(int)m_debugFrameIndex) )
  3232. {
  3233. if (debughook) GLMPRINTF(("-D- Clear trigger match, clearing m_holdBatch&Frame, hold=true" ));
  3234. m_holdBatch = m_holdBatchFrame = -1;
  3235. info->m_holding = true;
  3236. }
  3237. break;
  3238. case eDrawElements:
  3239. if (debughook) GLMPRINTF(( (info->m_caller==eClear) ? "-D- Caller: Clear" : "-D- Caller: Draw" ));
  3240. if ( (m_holdBatch>=0) && (m_holdBatchFrame>=0) && ((int)m_holdBatch==(int)m_nBatchCounter) && ((int)m_holdBatchFrame==(int)m_debugFrameIndex) )
  3241. {
  3242. if (debughook) GLMPRINTF(("-D- Draw trigger match, clearing m_holdBatch&Frame, hold=true" ));
  3243. m_holdBatch = m_holdBatchFrame = -1;
  3244. info->m_holding = true;
  3245. }
  3246. break;
  3247. case eEndFrame:
  3248. if (debughook) GLMPRINTF(("-D- Caller: EndFrame" ));
  3249. // check for any expired batch hold req
  3250. if ( (m_holdBatch>=0) && (m_holdBatchFrame>=0) && (m_holdBatchFrame==m_debugFrameIndex) )
  3251. {
  3252. // you tried to say 'next batch', but there wasn't one in this frame.
  3253. // target first batch of next frame instead
  3254. if (debughook) GLMPRINTF(("-D- EndFrame noticed an expired draw hold trigger, rolling to next frame, hold=false"));
  3255. m_holdBatch = 0;
  3256. m_holdBatchFrame++;
  3257. info->m_holding = false;
  3258. }
  3259. // now check for an explicit hold on end of this frame..
  3260. if ( (m_holdFrameEnd>=0) && (m_holdFrameEnd==m_debugFrameIndex) )
  3261. {
  3262. if (debughook) GLMPRINTF(("-D- EndFrame trigger match, clearing m_holdFrameEnd, hold=true" ));
  3263. m_holdFrameEnd = -1;
  3264. info->m_holding = true;
  3265. }
  3266. break;
  3267. }
  3268. // spin until event queue is empty *and* hold is false
  3269. int evtcount=0;
  3270. bool refresh = info->m_holding || m_debugDelayEnable; // only refresh once per initial visit (if paused!) or follow up event input
  3271. int breakToDebugger = 0;
  3272. // 1 = break to GDB
  3273. // 2 = break to OpenGL Profiler if attached
  3274. do
  3275. {
  3276. if (refresh)
  3277. {
  3278. if (debughook) GLMPRINTF(("-D- pushing pixels" ));
  3279. DebugPresent(); // show pixels
  3280. uint minidumpOptions = (1<<eDumpBatchInfo) /* | (1<<eDumpSurfaceInfo) */;
  3281. DebugDump( info, minidumpOptions, g_vertDumpMode );
  3282. ThreadSleep( 10000 / 1000 ); // lil sleep
  3283. refresh = false;
  3284. }
  3285. bool eventCheck = true; // event pull will be skipped if we detect a shader edit being done
  3286. // keep editable shaders in sync
  3287. #if GLMDEBUG
  3288. bool redrawBatch = false;
  3289. if (m_drawingProgram[ kGLMVertexProgram ])
  3290. {
  3291. if( m_drawingProgram[ kGLMVertexProgram ]->SyncWithEditable() )
  3292. {
  3293. redrawBatch = true;
  3294. }
  3295. }
  3296. if (m_drawingProgram[ kGLMFragmentProgram ])
  3297. {
  3298. if( m_drawingProgram[ kGLMFragmentProgram ]->SyncWithEditable() )
  3299. {
  3300. redrawBatch = true;
  3301. }
  3302. }
  3303. if (redrawBatch)
  3304. {
  3305. // act as if user pressed the option-\ key
  3306. if (m_drawingLang == kGLMGLSL)
  3307. {
  3308. // if GLSL mode, force relink - and refresh the pair cache as needed
  3309. if (m_pBoundPair)
  3310. {
  3311. // fix it in place
  3312. m_pBoundPair->RefreshProgramPair();
  3313. }
  3314. }
  3315. // TODO - need to retest this whole path
  3316. FlushDrawStates( 0, 0, 0 ); // this is key, because the linked shader pair may have changed (note call to PurgePairsWithShader in cglmprogram.cpp)
  3317. GLMPRINTF(("-- Shader changed, re-running batch" ));
  3318. m_holdBatch = m_nBatchCounter;
  3319. m_holdBatchFrame = m_debugFrameIndex;
  3320. m_debugDelayEnable = false;
  3321. info->m_holding = false;
  3322. info->m_loop = true;
  3323. eventCheck = false;
  3324. }
  3325. #endif
  3326. if(eventCheck)
  3327. {
  3328. PumpWindowsMessageLoop();
  3329. CCocoaEvent evt;
  3330. evtcount = GetEvents( &evt, 1, true ); // asking for debug events only.
  3331. if (evtcount)
  3332. {
  3333. // print it
  3334. if (debughook) GLMPRINTF(("-D- Received debug key '%c' with modifiers %x", evt.m_UnicodeKeyUnmodified, evt.m_ModifierKeyMask ));
  3335. // flag for refresh if we spin again
  3336. refresh = 1;
  3337. switch(evt.m_UnicodeKeyUnmodified)
  3338. {
  3339. case ' ': // toggle pause
  3340. // clear all the holds to be sure
  3341. m_holdFrameBegin = m_holdFrameEnd = m_holdBatch = m_holdBatchFrame = -1;
  3342. info->m_holding = !info->m_holding;
  3343. if (!info->m_holding)
  3344. {
  3345. m_debugDelayEnable = false; // coming out of pause means no slow mo
  3346. }
  3347. GLMPRINTF((info->m_holding ? "-D- Paused." : "-D- Unpaused." ));
  3348. break;
  3349. case 'f': // frame advance
  3350. GLMPRINTF(("-D- Command: next frame" ));
  3351. m_holdFrameBegin = m_debugFrameIndex+1; // stop at top of next numbered frame
  3352. m_debugDelayEnable = false; // get there fast
  3353. info->m_holding = false;
  3354. break;
  3355. case ']': // ahead 1 batch
  3356. case '}': // ahead ten batches
  3357. {
  3358. int delta = evt.m_UnicodeKeyUnmodified == ']' ? 1 : 10;
  3359. m_holdBatch = m_nBatchCounter+delta;
  3360. m_holdBatchFrame = m_debugFrameIndex;
  3361. m_debugDelayEnable = false; // get there fast
  3362. info->m_holding = false;
  3363. GLMPRINTF(("-D- Command: advance %d batches to %d", delta, m_holdBatch ));
  3364. }
  3365. break;
  3366. case '[': // back one batch
  3367. case '{': // back 10 batches
  3368. {
  3369. int delta = evt.m_UnicodeKeyUnmodified == '[' ? -1 : -10;
  3370. m_holdBatch = m_nBatchCounter + delta;
  3371. if (m_holdBatch<0)
  3372. {
  3373. m_holdBatch = 0;
  3374. }
  3375. m_holdBatchFrame = m_debugFrameIndex+1; // next frame, but prev batch #
  3376. m_debugDelayEnable = false; // get there fast
  3377. info->m_holding = false;
  3378. GLMPRINTF(("-D- Command: rewind %d batches to %d", delta, m_holdBatch ));
  3379. }
  3380. break;
  3381. case '\\': // batch rerun
  3382. m_holdBatch = m_nBatchCounter;
  3383. m_holdBatchFrame = m_debugFrameIndex;
  3384. m_debugDelayEnable = false;
  3385. info->m_holding = false;
  3386. info->m_loop = true;
  3387. GLMPRINTF(("-D- Command: re-run batch %d", m_holdBatch ));
  3388. break;
  3389. case 'c': // toggle auto color clear
  3390. m_autoClearColor = !m_autoClearColor;
  3391. GLMPRINTF((m_autoClearColor ? "-D- Auto color clear ON" : "-D- Auto color clear OFF" ));
  3392. break;
  3393. case 's': // toggle auto stencil clear
  3394. m_autoClearStencil = !m_autoClearStencil;
  3395. GLMPRINTF((m_autoClearStencil ? "-D- Auto stencil clear ON" : "-D- Auto stencil clear OFF" ));
  3396. break;
  3397. case 'd': // toggle auto depth clear
  3398. m_autoClearDepth = !m_autoClearDepth;
  3399. GLMPRINTF((m_autoClearDepth ? "-D- Auto depth clear ON" : "-D- Auto depth clear OFF" ));
  3400. break;
  3401. case '.': // break to debugger or insta-quit
  3402. if (evt.m_ModifierKeyMask & (1<<eControlKey))
  3403. {
  3404. GLMPRINTF(( "-D- INSTA QUIT! (TM) (PAT PEND)" ));
  3405. abort();
  3406. }
  3407. else
  3408. {
  3409. GLMPRINTF(( "-D- Breaking to debugger" ));
  3410. breakToDebugger = 1;
  3411. info->m_holding = true;
  3412. info->m_loop = true; // so when you come back from debugger, you get another spin (i.e. you enter paused mode)
  3413. }
  3414. break;
  3415. case 'g': // break to OGLP and enable OGLP logging of spew
  3416. if (GLMDetectOGLP()) // if this comes back true, there will be a breakpoint set on glColor4sv.
  3417. {
  3418. uint channelMask = GLMDetectAvailableChannels(); // will re-assert whether spew goes to OGLP log
  3419. if (channelMask & (1<<eGLProfiler))
  3420. {
  3421. GLMDebugChannelMask(&channelMask);
  3422. breakToDebugger = 2;
  3423. info->m_holding = true;
  3424. info->m_loop = true; // so when you come back from debugger, you get another spin (i.e. you enter paused mode)
  3425. }
  3426. }
  3427. break;
  3428. case '_': // toggle slow mo
  3429. m_debugDelayEnable = !m_debugDelayEnable;
  3430. break;
  3431. case '-': // go slower
  3432. if (m_debugDelayEnable)
  3433. {
  3434. // already in slow mo, so lower speed
  3435. m_debugDelay <<= 1; // double delay
  3436. if (m_debugDelay > (1<<24))
  3437. {
  3438. m_debugDelay = (1<<24);
  3439. }
  3440. }
  3441. else
  3442. {
  3443. // enter slow mo
  3444. m_debugDelayEnable = true;
  3445. }
  3446. break;
  3447. case '=': // go faster
  3448. if (m_debugDelayEnable)
  3449. {
  3450. // already in slow mo, so raise speed
  3451. m_debugDelay >>= 1; // halve delay
  3452. if (m_debugDelay < (1<<17))
  3453. {
  3454. m_debugDelay = (1<<17);
  3455. }
  3456. }
  3457. else
  3458. {
  3459. // enter slow mo
  3460. m_debugDelayEnable = true;
  3461. }
  3462. break;
  3463. case 'v':
  3464. // open vs in editor (foreground pop)
  3465. #if GLMDEBUG
  3466. if (m_drawingProgram[ kGLMVertexProgram ])
  3467. {
  3468. m_drawingProgram[ kGLMVertexProgram ]->m_editable->OpenInEditor( true );
  3469. }
  3470. #endif
  3471. break;
  3472. case 'p':
  3473. // open fs/ps in editor (foreground pop)
  3474. #if GLMDEBUG
  3475. if (m_drawingProgram[ kGLMFragmentProgram ])
  3476. {
  3477. m_drawingProgram[ kGLMFragmentProgram ]->m_editable->OpenInEditor( true );
  3478. }
  3479. #endif
  3480. break;
  3481. case '<': // dump fewer verts
  3482. case '>': // dump more verts
  3483. {
  3484. int delta = (evt.m_UnicodeKeyUnmodified=='>') ? 1 : -1;
  3485. g_maxVertsToDumpLog2 = MIN( MAX( g_maxVertsToDumpLog2+delta, 0 ), 16 );
  3486. // just re-dump the verts
  3487. DebugDump( info, 1<<eDumpVertexData, g_vertDumpMode );
  3488. }
  3489. break;
  3490. case 'x': // adjust transform dump mode
  3491. {
  3492. int newmode = g_vertDumpMode+1;
  3493. if (newmode >= eLastDumpVertsMode)
  3494. {
  3495. // wrap
  3496. newmode = eDumpVertsNoTransformDump;
  3497. }
  3498. g_vertDumpMode = (EGLMVertDumpMode)newmode;
  3499. GLMPRINTF(("-D- New vert dump mode is %s", g_vertDumpModeNames[g_vertDumpMode] ));
  3500. }
  3501. break;
  3502. case 'u': // more crawl
  3503. {
  3504. CStackCrawlParams cp;
  3505. memset( &cp, 0, sizeof(cp) );
  3506. cp.m_frameLimit = kMaxCrawlFrames;
  3507. GetStackCrawl(&cp);
  3508. GLMPRINTF(("-D-" ));
  3509. GLMPRINTF(("-D- extended stack crawl:"));
  3510. for( uint i=0; i< cp.m_frameCount; i++)
  3511. {
  3512. GLMPRINTF(("-D-\t%s", cp.m_crawlNames[i] ));
  3513. }
  3514. }
  3515. break;
  3516. case 'q':
  3517. DebugDump( info, 0xFFFFFFFF, g_vertDumpMode );
  3518. break;
  3519. case 'H':
  3520. case 'h':
  3521. {
  3522. // toggle drawing language. hold down shift key to do it immediately.
  3523. if (m_caps.m_hasDualShaders)
  3524. {
  3525. bool immediate;
  3526. immediate = evt.m_UnicodeKeyUnmodified == 'H'; // (evt.m_ModifierKeyMask & (1<<eShiftKey)) != 0;
  3527. if (m_drawingLang==kGLMARB)
  3528. {
  3529. GLMPRINTF(( "-D- Setting GLSL language mode %s.", immediate ? "immediately" : "for next frame start" ));
  3530. SetDrawingLang( kGLMGLSL, immediate );
  3531. }
  3532. else
  3533. {
  3534. GLMPRINTF(( "-D- Setting ARB language mode %s.", immediate ? "immediately" : "for next frame start" ));
  3535. SetDrawingLang( kGLMARB, immediate );
  3536. }
  3537. refresh = immediate;
  3538. }
  3539. else
  3540. {
  3541. GLMPRINTF(("You can't change shader languages unless you launch with -glmdualshaders enabled"));
  3542. }
  3543. }
  3544. break;
  3545. // ======================================================== debug knobs. change these as needed to troubleshoot stuff
  3546. // keys to select a knob
  3547. // or, toggle a debug flavor, if control is being held down
  3548. case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
  3549. {
  3550. if (evt.m_ModifierKeyMask & (1<<eControlKey))
  3551. {
  3552. // '0' toggles the all-channels on or off
  3553. int flavorSelect = evt.m_UnicodeKeyUnmodified - '0';
  3554. if ( (flavorSelect >=0) && (flavorSelect<eFlavorCount) )
  3555. {
  3556. uint mask = GLMDebugFlavorMask();
  3557. mask ^= (1<<flavorSelect);
  3558. GLMDebugFlavorMask(&mask);
  3559. }
  3560. }
  3561. else
  3562. {
  3563. // knob selection
  3564. m_selKnobIndex = evt.m_UnicodeKeyUnmodified - '0';
  3565. GLMPRINTF(("-D- Knob # %d (%s) selected.", m_selKnobIndex, g_knobnames[ m_selKnobIndex ] ));
  3566. m_selKnobIncrement = (m_selKnobIndex<5) ? (1.0f / 2048.0f) : (1.0 / 256.0f);
  3567. ThreadSleep( 500000 / 1000 );
  3568. }
  3569. refresh = false;
  3570. }
  3571. break;
  3572. // keys to adjust or zero a knob
  3573. case 't': // toggle
  3574. {
  3575. if (m_selKnobIndex < g_knobcount)
  3576. {
  3577. GLMKnobToggle( g_knobnames[ m_selKnobIndex ] );
  3578. }
  3579. }
  3580. break;
  3581. case 'l': // less
  3582. case 'm': // more
  3583. case 'z': // zero
  3584. {
  3585. if (m_selKnobIndex < g_knobcount)
  3586. {
  3587. float val = GLMKnob( g_knobnames[ m_selKnobIndex ], NULL );
  3588. if (evt.m_UnicodeKeyUnmodified == 'l')
  3589. {
  3590. // minus (less)
  3591. val -= m_selKnobIncrement;
  3592. if (val < m_selKnobMinValue)
  3593. {
  3594. val = m_selKnobMinValue;
  3595. }
  3596. // send new value back to the knob
  3597. GLMKnob( g_knobnames[ m_selKnobIndex ], &val );
  3598. }
  3599. if (evt.m_UnicodeKeyUnmodified == 'm')
  3600. {
  3601. // plus (more)
  3602. val += m_selKnobIncrement;
  3603. if (val > m_selKnobMaxValue)
  3604. {
  3605. val = m_selKnobMaxValue;
  3606. }
  3607. // send new value back to the knob
  3608. GLMKnob( g_knobnames[ m_selKnobIndex ], &val );
  3609. }
  3610. if (evt.m_UnicodeKeyUnmodified == 'z')
  3611. {
  3612. // zero
  3613. val = 0.0f;
  3614. // send new value back to the knob
  3615. GLMKnob( g_knobnames[ m_selKnobIndex ], &val );
  3616. }
  3617. GLMPRINTF(("-D- Knob # %d (%s) set to %f (%f/1024.0)", m_selKnobIndex, g_knobnames[ m_selKnobIndex ], val, val * 1024.0 ));
  3618. ThreadSleep( 500000 / 1000 );
  3619. refresh = false;
  3620. }
  3621. }
  3622. break;
  3623. }
  3624. }
  3625. }
  3626. } while( ((evtcount>0) || info->m_holding) && (!breakToDebugger) );
  3627. if (m_debugDelayEnable)
  3628. {
  3629. ThreadSleep( m_debugDelay / 1000 );
  3630. }
  3631. if (breakToDebugger)
  3632. {
  3633. switch (breakToDebugger)
  3634. {
  3635. case 1:
  3636. DebuggerBreak();
  3637. break;
  3638. case 2:
  3639. short fakecolor[4] = { 0, 0, 0, 0 };
  3640. gGL->glColor4sv( fakecolor ); // break to OGLP
  3641. break;
  3642. }
  3643. // re-flush all GLM states so you can fiddle with them in the debugger. then run the batch again and spin..
  3644. ForceFlushStates();
  3645. }
  3646. }
  3647. void GLMContext::DebugPresent( void )
  3648. {
  3649. CGLMTex *drawBufferTex = m_drawingFBO->m_attach[kAttColor0].m_tex;
  3650. gGL->glFinish();
  3651. Present( drawBufferTex );
  3652. }
  3653. void GLMContext::DebugClear( void )
  3654. {
  3655. // get old clear color
  3656. GLClearColor_t clearcol_orig;
  3657. m_ClearColor.Read( &clearcol_orig,0 );
  3658. // new clear color
  3659. GLClearColor_t clearcol;
  3660. clearcol.r = m_autoClearColorValues[0];
  3661. clearcol.g = m_autoClearColorValues[1];
  3662. clearcol.b = m_autoClearColorValues[2];
  3663. clearcol.a = m_autoClearColorValues[3];
  3664. m_ClearColor.Write( &clearcol ); // don't check, don't defer
  3665. uint mask = 0;
  3666. if (m_autoClearColor) mask |= GL_COLOR_BUFFER_BIT;
  3667. if (m_autoClearDepth) mask |= GL_DEPTH_BUFFER_BIT;
  3668. if (m_autoClearStencil) mask |= GL_STENCIL_BUFFER_BIT;
  3669. gGL->glClear( mask );
  3670. gGL->glFinish();
  3671. // put old color back
  3672. m_ClearColor.Write( &clearcol_orig ); // don't check, don't defer
  3673. }
  3674. #endif
  3675. void GLMContext::CheckNative( void )
  3676. {
  3677. // note that this is available in release. We don't use GLMPRINTF for that reason.
  3678. // note we do not get called unless either slow-batch asserting or logging is enabled.
  3679. #ifdef OSX
  3680. bool gpuProcessing;
  3681. GLint fragmentGPUProcessing, vertexGPUProcessing;
  3682. CGLGetParameter (CGLGetCurrentContext(), kCGLCPGPUFragmentProcessing, &fragmentGPUProcessing);
  3683. CGLGetParameter(CGLGetCurrentContext(), kCGLCPGPUVertexProcessing, &vertexGPUProcessing);
  3684. // spews then asserts.
  3685. // that way you can enable both, get log output on a pair if it's slow, and then the debugger will pop.
  3686. if(m_slowSpewEnable)
  3687. {
  3688. if ( !vertexGPUProcessing )
  3689. {
  3690. m_drawingProgram[ kGLMVertexProgram ]->LogSlow( m_drawingLang );
  3691. }
  3692. if ( !fragmentGPUProcessing )
  3693. {
  3694. m_drawingProgram[ kGLMFragmentProgram ]->LogSlow( m_drawingLang );
  3695. }
  3696. }
  3697. if(m_slowAssertEnable)
  3698. {
  3699. if ( !vertexGPUProcessing || !fragmentGPUProcessing)
  3700. {
  3701. Assert( !"slow batch" );
  3702. }
  3703. }
  3704. #else
  3705. //Assert( !"impl GLMContext::CheckNative()" );
  3706. if (m_checkglErrorsAfterEveryBatch)
  3707. {
  3708. // This is slow, and somewhat redundant (-gldebugoutput uses the GL_ARB_debug_output extension, which can be at least asynchronous), but having a straightforward backup can be useful.
  3709. // This is useful for callstack purposes - GL_ARB_debug_output may break in a different thread that the thread triggering the GL error.
  3710. //gGL->glFlush();
  3711. GLenum errorcode = (GLenum)gGL->glGetError();
  3712. if ( errorcode != GL_NO_ERROR )
  3713. {
  3714. const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
  3715. char buf[512];
  3716. V_snprintf( buf, sizeof( buf), "\nGL ERROR! %08x = '%s'\n", errorcode, decodedStr );
  3717. // Make sure the dev sees something, because these errors can happen early enough that DevMsg() does nothing.
  3718. #ifdef WIN32
  3719. OutputDebugStringA( buf );
  3720. #else
  3721. printf( "%s", buf );
  3722. #endif
  3723. }
  3724. }
  3725. #endif
  3726. }
  3727. // debug font
  3728. void GLMContext::GenDebugFontTex( void )
  3729. {
  3730. if(!m_debugFontTex)
  3731. {
  3732. // make a 128x128 RGBA texture
  3733. GLMTexLayoutKey key;
  3734. memset( &key, 0, sizeof(key) );
  3735. key.m_texGLTarget = GL_TEXTURE_2D;
  3736. key.m_xSize = 128;
  3737. key.m_ySize = 128;
  3738. key.m_zSize = 1;
  3739. key.m_texFormat = D3DFMT_A8R8G8B8;
  3740. key.m_texFlags = 0;
  3741. m_debugFontTex = NewTex( &key, 1, "GLM debug font" );
  3742. //-----------------------------------------------------
  3743. GLMTexLockParams lockreq;
  3744. lockreq.m_tex = m_debugFontTex;
  3745. lockreq.m_face = 0;
  3746. lockreq.m_mip = 0;
  3747. GLMTexLayoutSlice *slice = &m_debugFontTex->m_layout->m_slices[ lockreq.m_tex->CalcSliceIndex( lockreq.m_face, lockreq.m_mip ) ];
  3748. lockreq.m_region.xmin = lockreq.m_region.ymin = lockreq.m_region.zmin = 0;
  3749. lockreq.m_region.xmax = slice->m_xSize;
  3750. lockreq.m_region.ymax = slice->m_ySize;
  3751. lockreq.m_region.zmax = slice->m_zSize;
  3752. lockreq.m_readback = false;
  3753. char *lockAddress;
  3754. int yStride;
  3755. int zStride;
  3756. m_debugFontTex->Lock( &lockreq, &lockAddress, &yStride, &zStride );
  3757. //-----------------------------------------------------
  3758. // fetch elements of font data and make texels... we're doing the whole slab so we don't really need the stride info
  3759. unsigned long *destTexelPtr = (unsigned long *)lockAddress;
  3760. for( int index = 0; index < 16384; index++ )
  3761. {
  3762. if (g_glmDebugFontMap[index] == ' ')
  3763. {
  3764. // clear
  3765. *destTexelPtr = 0x00000000;
  3766. }
  3767. else
  3768. {
  3769. // opaque white (drawing code can modulate if desired)
  3770. *destTexelPtr = 0xFFFFFFFF;
  3771. }
  3772. destTexelPtr++;
  3773. }
  3774. //-----------------------------------------------------
  3775. GLMTexLockParams unlockreq;
  3776. unlockreq.m_tex = m_debugFontTex;
  3777. unlockreq.m_face = 0;
  3778. unlockreq.m_mip = 0;
  3779. // region need not matter for unlocks
  3780. unlockreq.m_region.xmin = unlockreq.m_region.ymin = unlockreq.m_region.zmin = 0;
  3781. unlockreq.m_region.xmax = unlockreq.m_region.ymax = unlockreq.m_region.zmax = 0;
  3782. unlockreq.m_readback = false;
  3783. m_debugFontTex->Unlock( &unlockreq );
  3784. //-----------------------------------------------------
  3785. // change up the tex sampling on this texture to be "nearest" not linear
  3786. //-----------------------------------------------------
  3787. // don't leave texture bound on the TMU
  3788. BindTexToTMU( NULL, 0 );
  3789. // also make the index and vertex buffers for use - up to 1K indices and 1K verts
  3790. uint indexBufferSize = 1024*2;
  3791. m_debugFontIndices = NewBuffer(kGLMIndexBuffer, indexBufferSize, 0); // two byte indices
  3792. // we go ahead and lock it now, and fill it with indices 0-1023.
  3793. char *indices = NULL;
  3794. GLMBuffLockParams idxLock;
  3795. idxLock.m_nOffset = 0;
  3796. idxLock.m_nSize = indexBufferSize;
  3797. idxLock.m_bNoOverwrite = false;
  3798. idxLock.m_bDiscard = true;
  3799. m_debugFontIndices->Lock( &idxLock, &indices );
  3800. for( int i=0; i<1024; i++)
  3801. {
  3802. unsigned short *idxPtr = &((unsigned short*)indices)[i];
  3803. *idxPtr = i;
  3804. }
  3805. m_debugFontIndices->Unlock();
  3806. m_debugFontVertices = NewBuffer(kGLMVertexBuffer, 1024 * 128, 0); // up to 128 bytes per vert
  3807. }
  3808. }
  3809. #define MAX_DEBUG_CHARS 256
  3810. struct GLMDebugTextVertex
  3811. {
  3812. float x,y,z;
  3813. float u,v;
  3814. char rgba[4];
  3815. };
  3816. void GLMContext::DrawDebugText( float x, float y, float z, float drawCharWidth, float drawCharHeight, char *string )
  3817. {
  3818. if (!m_debugFontTex)
  3819. {
  3820. GenDebugFontTex();
  3821. }
  3822. // setup needed to draw text
  3823. // we're assuming that +x goes left to right on screen, no billboarding math in here
  3824. // and that +y goes bottom up
  3825. // caller knows projection / rectangle so it gets to decide vertex spacing
  3826. // debug font must be bound to TMU 0
  3827. // texturing enabled
  3828. // alpha blending enabled
  3829. // generate a quad per character
  3830. // characters are 6px wide by 11 px high.
  3831. // upper left character in tex is 0x20
  3832. // y axis will need to be flipped for display
  3833. // for any character in 0x20 - 0x7F - here are the needed UV's
  3834. // leftU = ((character % 16) * 6.0f / 128.0f)
  3835. // rightU = lowU + (6.0 / 128.0);
  3836. // topV = ((character - 0x20) * 11.0f / 128.0f)
  3837. // bottomV = lowV + (11.0f / 128.0f)
  3838. int stringlen = strlen( string );
  3839. if (stringlen > MAX_DEBUG_CHARS)
  3840. {
  3841. stringlen = MAX_DEBUG_CHARS;
  3842. }
  3843. // lock
  3844. char *vertices = NULL;
  3845. GLMBuffLockParams vtxLock;
  3846. vtxLock.m_nOffset = 0;
  3847. vtxLock.m_nSize = 1024 * stringlen;
  3848. vtxLock.m_bNoOverwrite = false;
  3849. vtxLock.m_bDiscard = false;
  3850. m_debugFontVertices->Lock( &vtxLock, &vertices );
  3851. GLMDebugTextVertex *vtx = (GLMDebugTextVertex*)vertices;
  3852. GLMDebugTextVertex *vtxOutPtr = vtx;
  3853. for( int charindex = 0; charindex < stringlen; charindex++ )
  3854. {
  3855. float leftU,rightU,topV,bottomV;
  3856. int character = (int)string[charindex];
  3857. character -= 0x20;
  3858. if ( (character<0) || (character > 0x7F) )
  3859. {
  3860. character = '*' - 0x20;
  3861. }
  3862. leftU = ((character & 0x0F) * 6.0f ) / 128.0f;
  3863. rightU = leftU + (6.0f / 128.0f);
  3864. topV = ((character >> 4) * 11.0f ) / 128.0f;
  3865. bottomV = topV + (11.0f / 128.0f);
  3866. float posx,posy,posz;
  3867. posx = x + (drawCharWidth * (float)charindex);
  3868. posy = y;
  3869. posz = z;
  3870. // generate four verts
  3871. // first vert will be upper left of displayed quad (low X, high Y) then we go clockwise
  3872. for( int quadvert = 0; quadvert < 4; quadvert++ )
  3873. {
  3874. bool isTop = (quadvert <2); // verts 0 and 1
  3875. bool isLeft = (quadvert & 1) == (quadvert >> 1); // verts 0 and 3
  3876. vtxOutPtr->x = posx + (isLeft ? 0.0f : drawCharWidth);
  3877. vtxOutPtr->y = posy + (isTop ? drawCharHeight : 0.0f);
  3878. vtxOutPtr->z = posz;
  3879. vtxOutPtr->u = isLeft ? leftU : rightU;
  3880. vtxOutPtr->v = isTop ? topV : bottomV;
  3881. vtxOutPtr++;
  3882. }
  3883. }
  3884. // verts are done.
  3885. // unlock...
  3886. m_debugFontVertices->Unlock();
  3887. // make a vertex setup
  3888. GLMVertexSetup vertSetup;
  3889. // position, color, tc = 0, 3, 8
  3890. vertSetup.m_attrMask = (1<<kGLMGenericAttr00) | (1<<kGLMGenericAttr03) | (1<<kGLMGenericAttr08);
  3891. vertSetup.m_attrs[kGLMGenericAttr00].m_pBuffer = m_debugFontVertices;
  3892. vertSetup.m_attrs[kGLMGenericAttr00].m_nCompCount = 3; // 3 floats
  3893. vertSetup.m_attrs[kGLMGenericAttr00].m_datatype = GL_FLOAT;
  3894. vertSetup.m_attrs[kGLMGenericAttr00].m_stride = sizeof(GLMDebugTextVertex);
  3895. vertSetup.m_attrs[kGLMGenericAttr00].m_offset = offsetof(GLMDebugTextVertex, x);
  3896. vertSetup.m_attrs[kGLMGenericAttr00].m_normalized= false;
  3897. vertSetup.m_attrs[kGLMGenericAttr03].m_pBuffer = m_debugFontVertices;
  3898. vertSetup.m_attrs[kGLMGenericAttr03].m_nCompCount = 4; // four bytes
  3899. vertSetup.m_attrs[kGLMGenericAttr03].m_datatype = GL_UNSIGNED_BYTE;
  3900. vertSetup.m_attrs[kGLMGenericAttr03].m_stride = sizeof(GLMDebugTextVertex);
  3901. vertSetup.m_attrs[kGLMGenericAttr03].m_offset = offsetof(GLMDebugTextVertex, rgba);
  3902. vertSetup.m_attrs[kGLMGenericAttr03].m_normalized= true;
  3903. vertSetup.m_attrs[kGLMGenericAttr08].m_pBuffer = m_debugFontVertices;
  3904. vertSetup.m_attrs[kGLMGenericAttr08].m_nCompCount = 2; // 2 floats
  3905. vertSetup.m_attrs[kGLMGenericAttr08].m_datatype = GL_FLOAT;
  3906. vertSetup.m_attrs[kGLMGenericAttr08].m_stride = sizeof(GLMDebugTextVertex);
  3907. vertSetup.m_attrs[kGLMGenericAttr08].m_offset = offsetof(GLMDebugTextVertex, u);
  3908. vertSetup.m_attrs[kGLMGenericAttr03].m_normalized= false;
  3909. // bind texture and draw it..
  3910. CGLMTex *pPrevTex = m_samplers[0].m_pBoundTex;
  3911. BindTexToTMU( m_debugFontTex, 0 );
  3912. SelectTMU(0); // somewhat redundant
  3913. gGL->glDisable( GL_DEPTH_TEST );
  3914. gGL->glEnable(GL_TEXTURE_2D);
  3915. if (0)
  3916. {
  3917. gGL->glEnableClientState(GL_VERTEX_ARRAY);
  3918. gGL->glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  3919. gGL->glVertexPointer( 3, GL_FLOAT, sizeof( vtx[0] ), &vtx[0].x );
  3920. gGL->glClientActiveTexture(GL_TEXTURE0);
  3921. gGL->glTexCoordPointer( 2, GL_FLOAT, sizeof( vtx[0] ), &vtx[0].u );
  3922. }
  3923. else
  3924. {
  3925. SetVertexAttributes( &vertSetup );
  3926. }
  3927. gGL->glDrawArrays( GL_QUADS, 0, stringlen * 4 );
  3928. // disable all the input streams
  3929. if (0)
  3930. {
  3931. gGL->glDisableClientState(GL_VERTEX_ARRAY);
  3932. gGL->glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  3933. }
  3934. else
  3935. {
  3936. SetVertexAttributes( NULL );
  3937. }
  3938. gGL->glDisable(GL_TEXTURE_2D);
  3939. BindTexToTMU( pPrevTex, 0 );
  3940. }
  3941. //===============================================================================
  3942. void GLMgrSelfTests( void )
  3943. {
  3944. return; // until such time as the tests are revised or axed
  3945. GLMDisplayParams glmParams;
  3946. glmParams.m_fsEnable = false;
  3947. glmParams.m_vsyncEnable = false; // "The runtime updates the window client area immediately and might do so more
  3948. glmParams.m_backBufferWidth = 1024;
  3949. glmParams.m_backBufferHeight = 768;
  3950. glmParams.m_backBufferFormat = D3DFMT_A8R8G8B8;
  3951. glmParams.m_multiSampleCount = 2;
  3952. glmParams.m_enableAutoDepthStencil = true;
  3953. glmParams.m_autoDepthStencilFormat = D3DFMT_D24S8;
  3954. glmParams.m_fsRefreshHz = 60;
  3955. glmParams.m_mtgl = true;
  3956. glmParams.m_focusWindow = 0;
  3957. // make a new context on renderer 0.
  3958. GLMContext *ctx = GLMgr::aGLMgr()->NewContext( NULL, &glmParams ); ////FIXME you can't make contexts this way any more.
  3959. if (!ctx)
  3960. {
  3961. DebuggerBreak(); // no go
  3962. return;
  3963. }
  3964. // make a test object based on that context.
  3965. //int alltests[] = {0,1,2,3, -1};
  3966. //int newtests[] = {3, -1};
  3967. int twotests[] = {2, -1};
  3968. //int notests[] = {-1};
  3969. int *testlist = twotests;
  3970. GLMTestParams params;
  3971. memset( &params, 0, sizeof(params) );
  3972. params.m_ctx = ctx;
  3973. params.m_testList = testlist;
  3974. params.m_glErrToDebugger = true;
  3975. params.m_glErrToConsole = true;
  3976. params.m_intlErrToDebugger = true;
  3977. params.m_intlErrToConsole = true;
  3978. params.m_frameCount = 1000;
  3979. GLMTester testobj( &params );
  3980. testobj.RunTests( );
  3981. GLMgr::aGLMgr()->DelContext( ctx );
  3982. }
  3983. void GLMContext::SetDefaultStates( void )
  3984. {
  3985. GLM_FUNC;
  3986. CheckCurrent();
  3987. m_AlphaTestEnable.Default();
  3988. m_AlphaTestFunc.Default();
  3989. m_AlphaToCoverageEnable.Default();
  3990. m_CullFaceEnable.Default();
  3991. m_CullFrontFace.Default();
  3992. m_PolygonMode.Default();
  3993. m_DepthBias.Default();
  3994. m_ClipPlaneEnable.Default();
  3995. m_ClipPlaneEquation.Default();
  3996. m_ScissorEnable.Default();
  3997. m_ScissorBox.Default();
  3998. m_ViewportBox.Default();
  3999. m_ViewportDepthRange.Default();
  4000. m_ColorMaskSingle.Default();
  4001. m_ColorMaskMultiple.Default();
  4002. m_BlendEnable.Default();
  4003. m_BlendFactor.Default();
  4004. m_BlendEquation.Default();
  4005. m_BlendColor.Default();
  4006. //m_BlendEnableSRGB.Default(); // this isn't useful until there is an FBO bound - in fact it will trip a GL error.
  4007. m_DepthTestEnable.Default();
  4008. m_DepthFunc.Default();
  4009. m_DepthMask.Default();
  4010. m_StencilTestEnable.Default();
  4011. m_StencilFunc.Default();
  4012. m_StencilOp.Default();
  4013. m_StencilWriteMask.Default();
  4014. m_ClearColor.Default();
  4015. m_ClearDepth.Default();
  4016. m_ClearStencil.Default();
  4017. }
  4018. void GLMContext::VerifyStates ( void )
  4019. {
  4020. GLM_FUNC;
  4021. CheckCurrent();
  4022. // bare bones sanity check, head over to the debugger if our sense of the current context state is not correct
  4023. // we should only want to call this after a flush or the checks will flunk.
  4024. if( m_AlphaTestEnable.Check() ) GLMStop();
  4025. if( m_AlphaTestFunc.Check() ) GLMStop();
  4026. if( m_AlphaToCoverageEnable.Check() ) GLMStop();
  4027. if( m_CullFaceEnable.Check() ) GLMStop();
  4028. if( m_CullFrontFace.Check() ) GLMStop();
  4029. if( m_PolygonMode.Check() ) GLMStop();
  4030. if( m_DepthBias.Check() ) GLMStop();
  4031. if( m_ClipPlaneEnable.Check() ) GLMStop();
  4032. //if( m_ClipPlaneEquation.Check() ) GLMStop();
  4033. if( m_ScissorEnable.Check() ) GLMStop();
  4034. if( m_ScissorBox.Check() ) GLMStop();
  4035. if( m_ViewportBox.Check() ) GLMStop();
  4036. if( m_ViewportDepthRange.Check() ) GLMStop();
  4037. if( m_ColorMaskSingle.Check() ) GLMStop();
  4038. if( m_ColorMaskMultiple.Check() ) GLMStop();
  4039. if( m_BlendEnable.Check() ) GLMStop();
  4040. if( m_BlendFactor.Check() ) GLMStop();
  4041. if( m_BlendEquation.Check() ) GLMStop();
  4042. if( m_BlendColor.Check() ) GLMStop();
  4043. // only do this as caps permit
  4044. if (m_caps.m_hasGammaWrites)
  4045. {
  4046. if( m_BlendEnableSRGB.Check() ) GLMStop();
  4047. }
  4048. if( m_DepthTestEnable.Check() ) GLMStop();
  4049. if( m_DepthFunc.Check() ) GLMStop();
  4050. if( m_DepthMask.Check() ) GLMStop();
  4051. if( m_StencilTestEnable.Check() ) GLMStop();
  4052. if( m_StencilFunc.Check() ) GLMStop();
  4053. if( m_StencilOp.Check() ) GLMStop();
  4054. if( m_StencilWriteMask.Check() ) GLMStop();
  4055. if( m_ClearColor.Check() ) GLMStop();
  4056. if( m_ClearDepth.Check() ) GLMStop();
  4057. if( m_ClearStencil.Check() ) GLMStop();
  4058. }
  4059. static inline uint GetDataTypeSizeInBytes( GLenum dataType )
  4060. {
  4061. switch ( dataType )
  4062. {
  4063. case GL_BYTE:
  4064. case GL_UNSIGNED_BYTE:
  4065. return 1;
  4066. case GL_SHORT:
  4067. case GL_UNSIGNED_SHORT:
  4068. case GL_HALF_FLOAT:
  4069. return 2;
  4070. case GL_INT:
  4071. case GL_FLOAT:
  4072. return 4;
  4073. default:
  4074. Assert( 0 );
  4075. break;
  4076. }
  4077. return 0;
  4078. }
  4079. #ifndef OSX
  4080. void GLMContext::DrawRangeElementsNonInline( GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, uint baseVertex, CGLMBuffer *pIndexBuf )
  4081. {
  4082. #if GLMDEBUG
  4083. GLM_FUNC;
  4084. #else
  4085. //tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s %d-%d count:%d mode:%d type:%d", __FUNCTION__, start, end, count, mode, type );
  4086. #endif
  4087. ++m_nBatchCounter;
  4088. SetIndexBuffer( pIndexBuf );
  4089. void *indicesActual = (void*)indices;
  4090. if ( pIndexBuf->m_bPseudo )
  4091. {
  4092. // you have to pass actual address, not offset
  4093. indicesActual = (void*)( (int)indicesActual + (int)pIndexBuf->m_pPseudoBuf );
  4094. }
  4095. if (pIndexBuf->m_bUsingPersistentBuffer)
  4096. {
  4097. indicesActual = (void*)( (int)indicesActual + (int)pIndexBuf->m_nPersistentBufferStartOffset );
  4098. }
  4099. #if GL_ENABLE_INDEX_VERIFICATION
  4100. // Obviously only for debugging.
  4101. if ( !pIndexBuf->IsSpanValid( (uint)indices, count * GetDataTypeSizeInBytes( type ) ) )
  4102. {
  4103. // The consumption range crosses more than one lock span, or the lock is trying to consume a bad IB range.
  4104. DXABSTRACT_BREAK_ON_ERROR();
  4105. }
  4106. if ( ( type == GL_UNSIGNED_SHORT ) && ( pIndexBuf->m_bPseudo ) )
  4107. {
  4108. Assert( start <= end );
  4109. for ( int i = 0; i < count; i++)
  4110. {
  4111. uint n = ((const uint16*)indicesActual)[i];
  4112. if ( ( n < start ) || ( n > end ) )
  4113. {
  4114. DXABSTRACT_BREAK_ON_ERROR();
  4115. }
  4116. }
  4117. unsigned char *pVertexShaderAttribMap = m_pDevice->m_vertexShader->m_vtxAttribMap;
  4118. const int nMaxVertexAttributesToCheck = m_drawingProgram[ kGLMVertexProgram ]->m_maxVertexAttrs;
  4119. IDirect3DVertexDeclaration9 *pVertDecl = m_pDevice->m_pVertDecl;
  4120. const uint8 *pVertexAttribDescToStreamIndex = pVertDecl->m_VertexAttribDescToStreamIndex;
  4121. // FIXME: Having to duplicate all this flush logic is terrible here
  4122. for( int nMask = 1, nIndex = 0; nIndex < nMaxVertexAttributesToCheck; ++nIndex, nMask <<= 1 )
  4123. {
  4124. uint8 vertexShaderAttrib = pVertexShaderAttribMap[ nIndex ];
  4125. uint nDeclIndex = pVertexAttribDescToStreamIndex[vertexShaderAttrib];
  4126. if ( nDeclIndex == 0xFF )
  4127. continue;
  4128. D3DVERTEXELEMENT9_GL *pDeclElem = &pVertDecl->m_elements[nDeclIndex];
  4129. Assert( ( ( vertexShaderAttrib >> 4 ) == pDeclElem->m_dxdecl.Usage ) && ( ( vertexShaderAttrib & 0x0F ) == pDeclElem->m_dxdecl.UsageIndex) );
  4130. const uint nStreamIndex = pDeclElem->m_dxdecl.Stream;
  4131. const D3DStreamDesc *pStream = &m_pDevice->m_streams[ nStreamIndex ];
  4132. CGLMBuffer *pBuf = m_pDevice->m_vtx_buffers[ nStreamIndex ];
  4133. if ( pBuf == m_pDevice->m_pDummy_vtx_buffer )
  4134. continue;
  4135. Assert( pStream->m_vtxBuffer->m_vtxBuffer == pBuf );
  4136. int nBufOffset = pDeclElem->m_gldecl.m_offset + pStream->m_offset;
  4137. Assert( nBufOffset >= 0 );
  4138. Assert( nBufOffset < (int)pBuf->m_nSize );
  4139. uint nBufSize = pStream->m_vtxBuffer->m_vtxBuffer->m_nSize;
  4140. uint nDataTypeSize = GetDataTypeSizeInBytes( pDeclElem->m_gldecl.m_datatype );
  4141. uint nActualStride = pStream->m_stride ? pStream->m_stride : nDataTypeSize;
  4142. uint nStart = nBufOffset + ( start + baseVertex ) * nActualStride;
  4143. uint nEnd = nBufOffset + ( end + baseVertex ) * nActualStride + nDataTypeSize;
  4144. if ( nEnd > nBufSize )
  4145. {
  4146. DXABSTRACT_BREAK_ON_ERROR();
  4147. }
  4148. if ( !pStream->m_vtxBuffer->m_vtxBuffer->IsSpanValid( nStart, nEnd - nStart ) )
  4149. {
  4150. // The draw is trying to consume a range of the bound VB that hasn't been set to valid data!
  4151. DXABSTRACT_BREAK_ON_ERROR();
  4152. }
  4153. }
  4154. }
  4155. #endif
  4156. Assert( m_drawingLang == kGLMGLSL );
  4157. if ( m_pBoundPair )
  4158. {
  4159. gGL->glDrawRangeElementsBaseVertex( mode, start, end, count, type, indicesActual, baseVertex );
  4160. #if GLMDEBUG
  4161. if ( m_slowCheckEnable )
  4162. {
  4163. CheckNative();
  4164. }
  4165. #endif
  4166. }
  4167. }
  4168. #else
  4169. // support for OSX 10.6 (no support for glDrawRangeElementsBaseVertex)
  4170. void GLMContext::DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, CGLMBuffer *pIndexBuf)
  4171. {
  4172. GLM_FUNC;
  4173. // CheckCurrent();
  4174. ++m_nBatchCounter; // batch index increments unconditionally on entry
  4175. SetIndexBuffer( pIndexBuf );
  4176. void *indicesActual = (void*)indices;
  4177. if ( pIndexBuf->m_bPseudo )
  4178. {
  4179. // you have to pass actual address, not offset
  4180. indicesActual = (void*)( (int)indicesActual + (int)pIndexBuf->m_pPseudoBuf );
  4181. }
  4182. if (pIndexBuf->m_bUsingPersistentBuffer)
  4183. {
  4184. indicesActual = (void*)( (int)indicesActual + (int)pIndexBuf->m_nPersistentBufferStartOffset );
  4185. }
  4186. #if GLMDEBUG
  4187. // init debug hook information
  4188. GLMDebugHookInfo info;
  4189. memset(&info, 0, sizeof(info));
  4190. info.m_caller = eDrawElements;
  4191. // relay parameters we're operating under
  4192. info.m_drawMode = mode;
  4193. info.m_drawStart = start;
  4194. info.m_drawEnd = end;
  4195. info.m_drawCount = count;
  4196. info.m_drawType = type;
  4197. info.m_drawIndices = indices;
  4198. do
  4199. {
  4200. // obey global options re pre-draw clear
  4201. if (m_autoClearColor || m_autoClearDepth || m_autoClearStencil)
  4202. {
  4203. GLMPRINTF(("-- DrawRangeElements auto clear"));
  4204. this->DebugClear();
  4205. }
  4206. // always sync with editable shader text prior to draw
  4207. #if GLMDEBUG
  4208. // TODO - fixup OSX 10.6 m_boundProg not used in this version togl (m_pBoundPair)
  4209. //FIXME disengage this path if context is in GLSL mode..
  4210. // it will need fixes to get the shader pair re-linked etc if edits happen anyway.
  4211. if (m_boundProgram[kGLMVertexProgram])
  4212. {
  4213. m_boundProgram[kGLMVertexProgram]->SyncWithEditable();
  4214. }
  4215. else
  4216. {
  4217. AssertOnce(!"drawing with no vertex program bound");
  4218. }
  4219. if (m_boundProgram[kGLMFragmentProgram])
  4220. {
  4221. m_boundProgram[kGLMFragmentProgram]->SyncWithEditable();
  4222. }
  4223. else
  4224. {
  4225. AssertOnce(!"drawing with no fragment program bound");
  4226. }
  4227. #endif
  4228. // do the drawing
  4229. if ( m_pBoundPair )
  4230. {
  4231. gGL->glDrawRangeElements(mode, start, end, count, type, indicesActual);
  4232. // GLMCheckError();
  4233. if (m_slowCheckEnable)
  4234. {
  4235. CheckNative();
  4236. }
  4237. }
  4238. this->DebugHook(&info);
  4239. } while (info.m_loop);
  4240. #else
  4241. if ( m_pBoundPair )
  4242. {
  4243. gGL->glDrawRangeElements(mode, start, end, count, type, indicesActual);
  4244. #if GLMDEBUG
  4245. if ( m_slowCheckEnable )
  4246. {
  4247. CheckNative();
  4248. }
  4249. #endif
  4250. }
  4251. #endif
  4252. }
  4253. #endif // !OSX
  4254. #if 0
  4255. // helper function to do enable or disable in one step
  4256. void glSetEnable( GLenum which, bool enable )
  4257. {
  4258. if (enable)
  4259. gGL->glEnable(which);
  4260. else
  4261. gGL->glDisable(which);
  4262. }
  4263. // helper function for int vs enum clarity
  4264. void glGetEnumv( GLenum which, GLenum *dst )
  4265. {
  4266. gGL->glGetIntegerv( which, (int*)dst );
  4267. }
  4268. #endif
  4269. //===============================================================================
  4270. GLMTester::GLMTester(GLMTestParams *params)
  4271. {
  4272. m_params = *params;
  4273. m_drawFBO = NULL;
  4274. m_drawColorTex = NULL;
  4275. m_drawDepthTex = NULL;
  4276. }
  4277. GLMTester::~GLMTester()
  4278. {
  4279. }
  4280. void GLMTester::StdSetup( void )
  4281. {
  4282. GLMContext *ctx = m_params.m_ctx;
  4283. m_drawWidth = 1024;
  4284. m_drawHeight = 768;
  4285. // make an FBO to draw into and activate it. no depth buffer yet
  4286. m_drawFBO = ctx->NewFBO();
  4287. // make color buffer texture
  4288. GLMTexLayoutKey colorkey;
  4289. //CGLMTex *colortex;
  4290. memset( &colorkey, 0, sizeof(colorkey) );
  4291. colorkey.m_texGLTarget = GL_TEXTURE_2D;
  4292. colorkey.m_xSize = m_drawWidth;
  4293. colorkey.m_ySize = m_drawHeight;
  4294. colorkey.m_zSize = 1;
  4295. colorkey.m_texFormat = D3DFMT_A8R8G8B8;
  4296. colorkey.m_texFlags = kGLMTexRenderable;
  4297. m_drawColorTex = ctx->NewTex( &colorkey );
  4298. // do not leave that texture bound on the TMU
  4299. ctx->BindTexToTMU(NULL, 0 );
  4300. // attach color to FBO
  4301. GLMFBOTexAttachParams colorParams;
  4302. memset( &colorParams, 0, sizeof(colorParams) );
  4303. colorParams.m_tex = m_drawColorTex;
  4304. colorParams.m_face = 0;
  4305. colorParams.m_mip = 0;
  4306. colorParams.m_zslice= 0; // for clarity..
  4307. m_drawFBO->TexAttach( &colorParams, kAttColor0 );
  4308. // check it.
  4309. bool ready = m_drawFBO->IsReady();
  4310. InternalError( !ready, "drawing FBO no go");
  4311. // bind it
  4312. ctx->BindFBOToCtx( m_drawFBO, GL_FRAMEBUFFER_EXT );
  4313. gGL->glViewport(0, 0, (GLsizei) m_drawWidth, (GLsizei) m_drawHeight );
  4314. CheckGLError("stdsetup viewport");
  4315. gGL->glScissor( 0,0, (GLsizei) m_drawWidth, (GLsizei) m_drawHeight );
  4316. CheckGLError("stdsetup scissor");
  4317. gGL->glOrtho( -1,1, -1,1, -1,1 );
  4318. CheckGLError("stdsetup ortho");
  4319. // activate debug font
  4320. ctx->GenDebugFontTex();
  4321. }
  4322. void GLMTester::StdCleanup( void )
  4323. {
  4324. GLMContext *ctx = m_params.m_ctx;
  4325. // unbind
  4326. ctx->BindFBOToCtx( NULL, GL_FRAMEBUFFER_EXT );
  4327. // del FBO
  4328. if (m_drawFBO)
  4329. {
  4330. ctx->DelFBO( m_drawFBO );
  4331. m_drawFBO = NULL;
  4332. }
  4333. // del tex
  4334. if (m_drawColorTex)
  4335. {
  4336. ctx->DelTex( m_drawColorTex );
  4337. m_drawColorTex = NULL;
  4338. }
  4339. if (m_drawDepthTex)
  4340. {
  4341. ctx->DelTex( m_drawDepthTex );
  4342. m_drawDepthTex = NULL;
  4343. }
  4344. }
  4345. void GLMTester::Clear( void )
  4346. {
  4347. GLMContext *ctx = m_params.m_ctx;
  4348. ctx->MakeCurrent();
  4349. gGL->glViewport(0, 0, (GLsizei) m_drawWidth, (GLsizei) m_drawHeight );
  4350. gGL->glScissor( 0,0, (GLsizei) m_drawWidth, (GLsizei) m_drawHeight );
  4351. gGL->glOrtho( -1,1, -1,1, -1,1 );
  4352. CheckGLError("clearing viewport");
  4353. // clear to black
  4354. gGL->glClearColor(0.0f, 0.0f, 0.0, 1.0f);
  4355. CheckGLError("clearing color");
  4356. gGL->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  4357. CheckGLError("clearing");
  4358. //glFinish();
  4359. //CheckGLError("clear finish");
  4360. }
  4361. void GLMTester::Present( int seed )
  4362. {
  4363. GLMContext *ctx = m_params.m_ctx;
  4364. ctx->Present( m_drawColorTex );
  4365. }
  4366. void GLMTester::CheckGLError( const char *comment )
  4367. {
  4368. return;
  4369. char errbuf[1024];
  4370. //borrowed from GLMCheckError.. slightly different
  4371. if (!comment)
  4372. {
  4373. comment = "";
  4374. }
  4375. GLenum errorcode = (GLenum)gGL->glGetError();
  4376. GLenum errorcode2 = 0;
  4377. if ( errorcode != GL_NO_ERROR )
  4378. {
  4379. const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
  4380. const char *decodedStr2 = "";
  4381. if ( errorcode == GL_INVALID_FRAMEBUFFER_OPERATION_EXT )
  4382. {
  4383. // dig up the more detailed FBO status
  4384. errorcode2 = gGL->glCheckFramebufferStatusEXT( GL_FRAMEBUFFER_EXT );
  4385. decodedStr2 = GLMDecode( eGL_ERROR, errorcode2 );
  4386. sprintf( errbuf, "\n%s - GL Error %08x/%08x = '%s / %s'\n", comment, errorcode, errorcode2, decodedStr, decodedStr2 );
  4387. }
  4388. else
  4389. {
  4390. sprintf( errbuf, "\n%s - GL Error %08x = '%s'\n", comment, errorcode, decodedStr );
  4391. }
  4392. if ( m_params.m_glErrToConsole )
  4393. {
  4394. printf("%s", errbuf );
  4395. }
  4396. if ( m_params.m_glErrToDebugger )
  4397. {
  4398. DebuggerBreak();
  4399. }
  4400. }
  4401. }
  4402. void GLMTester::InternalError( int errcode, char *comment )
  4403. {
  4404. if (errcode)
  4405. {
  4406. if (m_params.m_intlErrToConsole)
  4407. {
  4408. printf("%s - error %d\n", comment, errcode );
  4409. }
  4410. if (m_params.m_intlErrToDebugger)
  4411. {
  4412. DebuggerBreak();
  4413. }
  4414. }
  4415. }
  4416. void GLMTester::RunTests( void )
  4417. {
  4418. int *testList = m_params.m_testList;
  4419. while( (*testList >=0) && (*testList < 20) )
  4420. {
  4421. RunOneTest( *testList++ );
  4422. }
  4423. }
  4424. void GLMTester::RunOneTest( int testindex )
  4425. {
  4426. // this might be better with 'ptmf' style
  4427. switch(testindex)
  4428. {
  4429. case 0: Test0(); break;
  4430. case 1: Test1(); break;
  4431. case 2: Test2(); break;
  4432. case 3: Test3(); break;
  4433. default:
  4434. DebuggerBreak(); // unrecognized
  4435. }
  4436. }
  4437. // #####################################################################################################################
  4438. // some fixed lists which may be useful to all tests
  4439. D3DFORMAT g_drawTexFormatsGLMT[] = // -1 terminated
  4440. {
  4441. D3DFMT_A8R8G8B8,
  4442. D3DFMT_A4R4G4B4,
  4443. D3DFMT_X8R8G8B8,
  4444. D3DFMT_X1R5G5B5,
  4445. D3DFMT_A1R5G5B5,
  4446. D3DFMT_L8,
  4447. D3DFMT_A8L8,
  4448. D3DFMT_R8G8B8,
  4449. D3DFMT_A8,
  4450. D3DFMT_R5G6B5,
  4451. D3DFMT_DXT1,
  4452. D3DFMT_DXT3,
  4453. D3DFMT_DXT5,
  4454. D3DFMT_A32B32G32R32F,
  4455. D3DFMT_A16B16G16R16,
  4456. (D3DFORMAT)-1
  4457. };
  4458. D3DFORMAT g_fboColorTexFormatsGLMT[] = // -1 terminated
  4459. {
  4460. D3DFMT_A8R8G8B8,
  4461. //D3DFMT_A4R4G4B4, //unsupported
  4462. D3DFMT_X8R8G8B8,
  4463. D3DFMT_X1R5G5B5,
  4464. //D3DFMT_A1R5G5B5, //unsupported
  4465. D3DFMT_A16B16G16R16F,
  4466. D3DFMT_A32B32G32R32F,
  4467. D3DFMT_R5G6B5,
  4468. (D3DFORMAT)-1
  4469. };
  4470. D3DFORMAT g_fboDepthTexFormatsGLMT[] = // -1 terminated, but note 0 for "no depth" mode
  4471. {
  4472. (D3DFORMAT)0,
  4473. D3DFMT_D16,
  4474. D3DFMT_D24X8,
  4475. D3DFMT_D24S8,
  4476. (D3DFORMAT)-1
  4477. };
  4478. // #####################################################################################################################
  4479. void GLMTester::Test0( void )
  4480. {
  4481. // make and delete a bunch of textures.
  4482. // lock and unlock them.
  4483. // use various combos of -
  4484. // √texel format
  4485. // √2D | 3D | cube map
  4486. // √mipped / not
  4487. // √POT / NPOT
  4488. // large / small / square / rect
  4489. // square / rect
  4490. GLMContext *ctx = m_params.m_ctx;
  4491. ctx->MakeCurrent();
  4492. CUtlVector< CGLMTex* > testTextures; // will hold all the built textures
  4493. // test stage loop
  4494. // 0 is creation
  4495. // 1 is lock/unlock
  4496. // 2 is deletion
  4497. for( int teststage = 0; teststage < 3; teststage++)
  4498. {
  4499. int innerindex = 0; // increment at stage switch
  4500. // format loop
  4501. for( D3DFORMAT *fmtPtr = g_drawTexFormatsGLMT; *fmtPtr != ((D3DFORMAT)-1); fmtPtr++ )
  4502. {
  4503. // form loop
  4504. GLenum forms[] = { GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP, (GLenum)-1 };
  4505. for( GLenum *formPtr = forms; *formPtr != ((GLenum)-1); formPtr++ )
  4506. {
  4507. // mip loop
  4508. for( int mipped = 0; mipped < 2; mipped++ )
  4509. {
  4510. // large / square / pot loop
  4511. // &4 == large &2 == square &1 == POT
  4512. // NOTE you *have to be square* for cube maps.
  4513. for( int aspect = 0; aspect < 8; aspect++ )
  4514. {
  4515. switch( teststage )
  4516. {
  4517. case 0:
  4518. {
  4519. GLMTexLayoutKey key;
  4520. memset( &key, 0, sizeof(key) );
  4521. key.m_texGLTarget = *formPtr;
  4522. key.m_texFormat = *fmtPtr;
  4523. if (mipped)
  4524. key.m_texFlags |= kGLMTexMipped;
  4525. // assume big, square, POT, and 3D, then adjust as needed
  4526. key.m_xSize = key.m_ySize = key.m_zSize = 256;
  4527. if ( !(aspect&4) ) // big or little ?
  4528. {
  4529. // little
  4530. key.m_xSize >>= 2;
  4531. key.m_ySize >>= 2;
  4532. key.m_zSize >>= 2;
  4533. }
  4534. if ( key.m_texGLTarget != GL_TEXTURE_CUBE_MAP )
  4535. {
  4536. if ( !(aspect & 2) ) // square or rect?
  4537. {
  4538. // rect
  4539. key.m_ySize >>= 1;
  4540. key.m_zSize >>= 2;
  4541. }
  4542. }
  4543. if ( !(aspect&1) ) // POT or NPOT?
  4544. {
  4545. // NPOT
  4546. key.m_xSize += 56;
  4547. key.m_ySize += 56;
  4548. key.m_zSize += 56;
  4549. }
  4550. // 2D, 3D, cube map ?
  4551. if (key.m_texGLTarget!=GL_TEXTURE_3D)
  4552. {
  4553. // 2D or cube map: flatten Z extent to one texel
  4554. key.m_zSize = 1;
  4555. }
  4556. else
  4557. {
  4558. // 3D: knock down Z quite a bit so our test case does not run out of RAM
  4559. key.m_zSize >>= 3;
  4560. if (!key.m_zSize)
  4561. {
  4562. key.m_zSize = 1;
  4563. }
  4564. }
  4565. CGLMTex *newtex = ctx->NewTex( &key );
  4566. CheckGLError( "tex create test");
  4567. InternalError( newtex==NULL, "tex create test" );
  4568. testTextures.AddToTail( newtex );
  4569. printf("\n[%5d] created tex %s",innerindex,newtex->m_layout->m_layoutSummary );
  4570. }
  4571. break;
  4572. case 1:
  4573. {
  4574. CGLMTex *ptex = testTextures[innerindex];
  4575. for( int face=0; face <ptex->m_layout->m_faceCount; face++)
  4576. {
  4577. for( int mip=0; mip <ptex->m_layout->m_mipCount; mip++)
  4578. {
  4579. GLMTexLockParams lockreq;
  4580. lockreq.m_tex = ptex;
  4581. lockreq.m_face = face;
  4582. lockreq.m_mip = mip;
  4583. GLMTexLayoutSlice *slice = &ptex->m_layout->m_slices[ ptex->CalcSliceIndex( face, mip ) ];
  4584. lockreq.m_region.xmin = lockreq.m_region.ymin = lockreq.m_region.zmin = 0;
  4585. lockreq.m_region.xmax = slice->m_xSize;
  4586. lockreq.m_region.ymax = slice->m_ySize;
  4587. lockreq.m_region.zmax = slice->m_zSize;
  4588. char *lockAddress;
  4589. int yStride;
  4590. int zStride;
  4591. ptex->Lock( &lockreq, &lockAddress, &yStride, &zStride );
  4592. CheckGLError( "tex lock test");
  4593. InternalError( lockAddress==NULL, "null lock address");
  4594. // write some texels of this flavor:
  4595. // red 75% green 40% blue 15% alpha 80%
  4596. GLMGenTexelParams gtp;
  4597. gtp.m_format = ptex->m_layout->m_format->m_d3dFormat;
  4598. gtp.m_dest = lockAddress;
  4599. gtp.m_chunkCount = (slice->m_xSize * slice->m_ySize * slice->m_zSize) / (ptex->m_layout->m_format->m_chunkSize * ptex->m_layout->m_format->m_chunkSize);
  4600. gtp.m_byteCountLimit = slice->m_storageSize;
  4601. gtp.r = 0.75;
  4602. gtp.g = 0.40;
  4603. gtp.b = 0.15;
  4604. gtp.a = 0.80;
  4605. GLMGenTexels( &gtp );
  4606. InternalError( gtp.m_bytesWritten != gtp.m_byteCountLimit, "byte count mismatch from GLMGenTexels" );
  4607. }
  4608. }
  4609. for( int face=0; face <ptex->m_layout->m_faceCount; face++)
  4610. {
  4611. for( int mip=0; mip <ptex->m_layout->m_mipCount; mip++)
  4612. {
  4613. GLMTexLockParams unlockreq;
  4614. unlockreq.m_tex = ptex;
  4615. unlockreq.m_face = face;
  4616. unlockreq.m_mip = mip;
  4617. // region need not matter for unlocks
  4618. unlockreq.m_region.xmin = unlockreq.m_region.ymin = unlockreq.m_region.zmin = 0;
  4619. unlockreq.m_region.xmax = unlockreq.m_region.ymax = unlockreq.m_region.zmax = 0;
  4620. //char *lockAddress;
  4621. //int yStride;
  4622. //int zStride;
  4623. ptex->Unlock( &unlockreq );
  4624. CheckGLError( "tex unlock test");
  4625. }
  4626. }
  4627. printf("\n[%5d] locked/wrote/unlocked tex %s",innerindex, ptex->m_layout->m_layoutSummary );
  4628. }
  4629. break;
  4630. case 2:
  4631. {
  4632. CGLMTex *dtex = testTextures[innerindex];
  4633. printf("\n[%5d] deleting tex %s",innerindex, dtex->m_layout->m_layoutSummary );
  4634. ctx->DelTex( dtex );
  4635. CheckGLError( "tex delete test");
  4636. }
  4637. break;
  4638. } // end stage switch
  4639. innerindex++;
  4640. } // end aspect loop
  4641. } // end mip loop
  4642. } // end form loop
  4643. } // end format loop
  4644. } // end stage loop
  4645. }
  4646. // #####################################################################################################################
  4647. void GLMTester::Test1( void )
  4648. {
  4649. // FBO exercises
  4650. GLMContext *ctx = m_params.m_ctx;
  4651. ctx->MakeCurrent();
  4652. // FBO color format loop
  4653. for( D3DFORMAT *colorFmtPtr = g_fboColorTexFormatsGLMT; *colorFmtPtr != ((D3DFORMAT)-1); colorFmtPtr++ )
  4654. {
  4655. // FBO depth format loop
  4656. for( D3DFORMAT *depthFmtPtr = g_fboDepthTexFormatsGLMT; *depthFmtPtr != ((D3DFORMAT)-1); depthFmtPtr++ )
  4657. {
  4658. // mip loop
  4659. for( int mipped = 0; mipped < 2; mipped++ )
  4660. {
  4661. GLenum forms[] = { GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP, (GLenum)-1 };
  4662. // form loop
  4663. for( GLenum *formPtr = forms; *formPtr != ((GLenum)-1); formPtr++ )
  4664. {
  4665. //=============================================== make an FBO
  4666. CGLMFBO *fbo = ctx->NewFBO();
  4667. //=============================================== make a color texture
  4668. GLMTexLayoutKey colorkey;
  4669. memset( &colorkey, 0, sizeof(colorkey) );
  4670. switch(*formPtr)
  4671. {
  4672. case GL_TEXTURE_2D:
  4673. colorkey.m_texGLTarget = GL_TEXTURE_2D;
  4674. colorkey.m_xSize = 800;
  4675. colorkey.m_ySize = 600;
  4676. colorkey.m_zSize = 1;
  4677. break;
  4678. case GL_TEXTURE_3D:
  4679. colorkey.m_texGLTarget = GL_TEXTURE_3D;
  4680. colorkey.m_xSize = 800;
  4681. colorkey.m_ySize = 600;
  4682. colorkey.m_zSize = 32;
  4683. break;
  4684. case GL_TEXTURE_CUBE_MAP:
  4685. colorkey.m_texGLTarget = GL_TEXTURE_CUBE_MAP;
  4686. colorkey.m_xSize = 800;
  4687. colorkey.m_ySize = 800; // heh, cube maps have to have square sides...
  4688. colorkey.m_zSize = 1;
  4689. break;
  4690. }
  4691. colorkey.m_texFormat = *colorFmtPtr;
  4692. colorkey.m_texFlags = kGLMTexRenderable;
  4693. // decide if we want mips
  4694. if (mipped)
  4695. {
  4696. colorkey.m_texFlags |= kGLMTexMipped;
  4697. }
  4698. CGLMTex *colorTex = ctx->NewTex( &colorkey );
  4699. // Note that GLM will notice the renderable flag, and force texels to be written
  4700. // so the FBO will be complete
  4701. //=============================================== attach color
  4702. GLMFBOTexAttachParams colorParams;
  4703. memset( &colorParams, 0, sizeof(colorParams) );
  4704. colorParams.m_tex = colorTex;
  4705. colorParams.m_face = (colorkey.m_texGLTarget == GL_TEXTURE_CUBE_MAP) ? 2 : 0; // just steer to an alternate face as a test
  4706. colorParams.m_mip = (colorkey.m_texFlags & kGLMTexMipped) ? 2 : 0; // pick non-base mip slice
  4707. colorParams.m_zslice= (colorkey.m_texGLTarget == GL_TEXTURE_3D) ? 3 : 0; // just steer to an alternate slice as a test;
  4708. fbo->TexAttach( &colorParams, kAttColor0 );
  4709. //=============================================== optional depth tex
  4710. CGLMTex *depthTex = NULL;
  4711. if (*depthFmtPtr > 0 )
  4712. {
  4713. GLMTexLayoutKey depthkey;
  4714. memset( &depthkey, 0, sizeof(depthkey) );
  4715. depthkey.m_texGLTarget = GL_TEXTURE_2D;
  4716. depthkey.m_xSize = colorkey.m_xSize >> colorParams.m_mip; // scale depth tex to match color tex
  4717. depthkey.m_ySize = colorkey.m_ySize >> colorParams.m_mip;
  4718. depthkey.m_zSize = 1;
  4719. depthkey.m_texFormat = *depthFmtPtr;
  4720. depthkey.m_texFlags = kGLMTexRenderable | kGLMTexIsDepth; // no mips.
  4721. if (depthkey.m_texFormat==D3DFMT_D24S8)
  4722. {
  4723. depthkey.m_texFlags |= kGLMTexIsStencil;
  4724. }
  4725. depthTex = ctx->NewTex( &depthkey );
  4726. //=============================================== attach depth
  4727. GLMFBOTexAttachParams depthParams;
  4728. memset( &depthParams, 0, sizeof(depthParams) );
  4729. depthParams.m_tex = depthTex;
  4730. depthParams.m_face = 0;
  4731. depthParams.m_mip = 0;
  4732. depthParams.m_zslice= 0;
  4733. EGLMFBOAttachment depthAttachIndex = (depthkey.m_texFlags & kGLMTexIsStencil) ? kAttDepthStencil : kAttDepth;
  4734. fbo->TexAttach( &depthParams, depthAttachIndex );
  4735. }
  4736. printf("\n FBO:\n color tex %s\n depth tex %s",
  4737. colorTex->m_layout->m_layoutSummary,
  4738. depthTex ? depthTex->m_layout->m_layoutSummary : "none"
  4739. );
  4740. // see if FBO is happy
  4741. bool ready = fbo->IsReady();
  4742. printf("\n -> %s\n", ready ? "pass" : "fail" );
  4743. // unbind
  4744. ctx->BindFBOToCtx( NULL, GL_FRAMEBUFFER_EXT );
  4745. // del FBO
  4746. ctx->DelFBO(fbo);
  4747. // del texes
  4748. ctx->DelTex( colorTex );
  4749. if (depthTex) ctx->DelTex( depthTex );
  4750. } // end form loop
  4751. } // end mip loop
  4752. } // end depth loop
  4753. } // end color loop
  4754. }
  4755. // #####################################################################################################################
  4756. static int selftest2_seed = 0; // inc this every run to force main thread to teardown/reset display view
  4757. void GLMTester::Test2( void )
  4758. {
  4759. GLMContext *ctx = m_params.m_ctx;
  4760. ctx->MakeCurrent();
  4761. StdSetup(); // default test case drawing setup
  4762. // draw stuff (loop...)
  4763. for( int i=0; i<m_params.m_frameCount; i++)
  4764. {
  4765. // ramping shades of blue...
  4766. GLfloat clear_color[4] = { 0.50f, 0.05f, ((float)(i%100)) / 100.0f, 1.0f };
  4767. gGL->glClearColor(clear_color[0], clear_color[1], clear_color[2], clear_color[3]);
  4768. CheckGLError("test2 clear color");
  4769. gGL->glClear(GL_COLOR_BUFFER_BIT+GL_DEPTH_BUFFER_BIT+GL_STENCIL_BUFFER_BIT);
  4770. CheckGLError("test2 clearing");
  4771. // try out debug text
  4772. for( int j=0; j<16; j++)
  4773. {
  4774. char text[256];
  4775. sprintf(text, "The quick brown fox jumped over the lazy dog %d times", i );
  4776. float theta = ( (i*0.10f) + (j * 6.28f) ) / 16.0f;
  4777. float posx = cos(theta) * 0.5;
  4778. float posy = sin(theta) * 0.5;
  4779. float charwidth = 6.0 * (2.0 / 1024.0);
  4780. float charheight = 11.0 * (2.0 / 768.0);
  4781. ctx->DrawDebugText( posx, posy, 0.0f, charwidth, charheight, text );
  4782. }
  4783. gGL->glFinish();
  4784. CheckGLError("test2 finish");
  4785. Present( selftest2_seed );
  4786. }
  4787. StdCleanup();
  4788. selftest2_seed++;
  4789. }
  4790. // #####################################################################################################################
  4791. static char g_testVertexProgram01 [] =
  4792. {
  4793. "!!ARBvp1.0 \n"
  4794. "TEMP vertexClip; \n"
  4795. "DP4 vertexClip.x, state.matrix.mvp.row[0], vertex.position; \n"
  4796. "DP4 vertexClip.y, state.matrix.mvp.row[1], vertex.position; \n"
  4797. "DP4 vertexClip.z, state.matrix.mvp.row[2], vertex.position; \n"
  4798. "DP4 vertexClip.w, state.matrix.mvp.row[3], vertex.position; \n"
  4799. "ADD vertexClip.y, vertexClip.x, vertexClip.y; \n"
  4800. "MOV result.position, vertexClip; \n"
  4801. "MOV result.color, vertex.color; \n"
  4802. "MOV result.texcoord[0], vertex.texcoord; \n"
  4803. "END \n"
  4804. };
  4805. static char g_testFragmentProgram01 [] =
  4806. {
  4807. "!!ARBfp1.0 \n"
  4808. "TEMP color; \n"
  4809. "MUL color, fragment.texcoord[0].y, 2.0; \n"
  4810. "ADD color, 1.0, -color; \n"
  4811. "ABS color, color; \n"
  4812. "ADD result.color, 1.0, -color; \n"
  4813. "MOV result.color.a, 1.0; \n"
  4814. "END \n"
  4815. };
  4816. // generic attrib versions..
  4817. static char g_testVertexProgram01_GA [] =
  4818. {
  4819. "!!ARBvp1.0 \n"
  4820. "TEMP vertexClip; \n"
  4821. "DP4 vertexClip.x, state.matrix.mvp.row[0], vertex.attrib[0]; \n"
  4822. "DP4 vertexClip.y, state.matrix.mvp.row[1], vertex.attrib[0]; \n"
  4823. "DP4 vertexClip.z, state.matrix.mvp.row[2], vertex.attrib[0]; \n"
  4824. "DP4 vertexClip.w, state.matrix.mvp.row[3], vertex.attrib[0]; \n"
  4825. "ADD vertexClip.y, vertexClip.x, vertexClip.y; \n"
  4826. "MOV result.position, vertexClip; \n"
  4827. "MOV result.color, vertex.attrib[3]; \n"
  4828. "MOV result.texcoord[0], vertex.attrib[8]; \n"
  4829. "END \n"
  4830. };
  4831. static char g_testFragmentProgram01_GA [] =
  4832. {
  4833. "!!ARBfp1.0 \n"
  4834. "TEMP color; \n"
  4835. "TEX color, fragment.texcoord[0], texture[0], 2D;"
  4836. //"MUL color, fragment.texcoord[0].y, 2.0; \n"
  4837. //"ADD color, 1.0, -color; \n"
  4838. //"ABS color, color; \n"
  4839. //"ADD result.color, 1.0, -color; \n"
  4840. //"MOV result.color.a, 1.0; \n"
  4841. "MOV result.color, color; \n"
  4842. "END \n"
  4843. };
  4844. void GLMTester::Test3( void )
  4845. {
  4846. /**************************
  4847. XXXXXXXXXXXXXXXXXXXXXX stale test code until we revise the program interface
  4848. GLMContext *ctx = m_params.m_ctx;
  4849. ctx->MakeCurrent();
  4850. StdSetup(); // default test case drawing setup
  4851. // make vertex&pixel shader
  4852. CGLMProgram *vprog = ctx->NewProgram( kGLMVertexProgram, g_testVertexProgram01_GA );
  4853. ctx->BindProgramToCtx( kGLMVertexProgram, vprog );
  4854. CGLMProgram *fprog = ctx->NewProgram( kGLMFragmentProgram, g_testFragmentProgram01_GA );
  4855. ctx->BindProgramToCtx( kGLMFragmentProgram, fprog );
  4856. // draw stuff (loop...)
  4857. for( int i=0; i<m_params.m_frameCount; i++)
  4858. {
  4859. // ramping shades of blue...
  4860. GLfloat clear_color[4] = { 0.50f, 0.05f, ((float)(i%100)) / 100.0, 1.0f };
  4861. glClearColor(clear_color[0], clear_color[1], clear_color[2], clear_color[3]);
  4862. CheckGLError("test3 clear color");
  4863. glClear(GL_COLOR_BUFFER_BIT+GL_DEPTH_BUFFER_BIT+GL_STENCIL_BUFFER_BIT);
  4864. CheckGLError("test3 clearing");
  4865. // try out debug text
  4866. for( int j=0; j<16; j++)
  4867. {
  4868. char text[256];
  4869. sprintf(text, "This here is running through a trivial vertex shader");
  4870. float theta = ( (i*0.10f) + (j * 6.28f) ) / 16.0f;
  4871. float posx = cos(theta) * 0.5;
  4872. float posy = sin(theta) * 0.5;
  4873. float charwidth = 6.0 * (2.0 / 800.0);
  4874. float charheight = 11.0 * (2.0 / 640.0);
  4875. ctx->DrawDebugText( posx, posy, 0.0f, charwidth, charheight, text );
  4876. }
  4877. glFinish();
  4878. CheckGLError("test3 finish");
  4879. Present( 3333 );
  4880. }
  4881. StdCleanup();
  4882. *****************************/
  4883. }
  4884. #if GLMDEBUG
  4885. void GLMTriggerDebuggerBreak()
  4886. {
  4887. // we call an obscure GL function which we know has been breakpointed in the OGLP function list
  4888. static signed short nada[] = { -1,-1,-1,-1 };
  4889. gGL->glColor4sv( nada );
  4890. }
  4891. #endif