Counter Strike : Global Offensive Source Code
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.

6175 lines
168 KiB

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