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.

7035 lines
197 KiB

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