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

1990 lines
63 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. // TOGL CODE LICENSE
  3. //
  4. // Copyright 2011-2014 Valve Corporation
  5. // All Rights Reserved.
  6. //
  7. // Permission is hereby granted, free of charge, to any person obtaining a copy
  8. // of this software and associated documentation files (the "Software"), to deal
  9. // in the Software without restriction, including without limitation the rights
  10. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. // copies of the Software, and to permit persons to whom the Software is
  12. // furnished to do so, subject to the following conditions:
  13. //
  14. // The above copyright notice and this permission notice shall be included in
  15. // all copies or substantial portions of the Software.
  16. //
  17. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. // THE SOFTWARE.
  24. //
  25. // cglmtex.cpp
  26. //
  27. //===============================================================================
  28. #include "togl/rendermechanism.h"
  29. #include "tier0/icommandline.h"
  30. #include "glmtexinlines.h"
  31. // memdbgon -must- be the last include file in a .cpp file.
  32. #include "tier0/memdbgon.h"
  33. #if defined(OSX)
  34. #include "appframework/ilaunchermgr.h"
  35. extern ILauncherMgr *g_pLauncherMgr;
  36. #endif
  37. //===============================================================================
  38. #if GLMDEBUG
  39. CGLMTex *g_pFirstCGMLTex;
  40. #endif
  41. ConVar gl_pow2_tempmem( "gl_pow2_tempmem", "0", FCVAR_INTERNAL_USE,
  42. "If set, use power-of-two allocations for temporary texture memory during uploads. "
  43. "May help with fragmentation on certain systems caused by heavy churn of large allocations." );
  44. #define TEXSPACE_LOGGING 0
  45. // encoding layout to an index where the bits read
  46. // 4 : 1 if compressed
  47. // 2 : 1 if not power of two
  48. // 1 : 1 if mipmapped
  49. bool pwroftwo (int val )
  50. {
  51. return (val & (val-1)) == 0;
  52. }
  53. int sEncodeLayoutAsIndex( GLMTexLayoutKey *key )
  54. {
  55. int index = 0;
  56. if (key->m_texFlags & kGLMTexMipped)
  57. {
  58. index |= 1;
  59. }
  60. if ( ! ( pwroftwo(key->m_xSize) && pwroftwo(key->m_ySize) && pwroftwo(key->m_zSize) ) )
  61. {
  62. // if not all power of two
  63. index |= 2;
  64. }
  65. if (GetFormatDesc( key->m_texFormat )->m_chunkSize >1 )
  66. {
  67. index |= 4;
  68. }
  69. return index;
  70. }
  71. static unsigned long g_texGlobalBytes[8];
  72. //===============================================================================
  73. const GLMTexFormatDesc g_formatDescTable[] =
  74. {
  75. // not yet handled by this table:
  76. // D3DFMT_INDEX16, D3DFMT_VERTEXDATA // D3DFMT_INDEX32,
  77. // WTF { D3DFMT_R5G6R5 ???, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 1, 2 },
  78. // WTF { D3DFMT_A ???, GL_ALPHA8, GL_ALPHA, GL_UNSIGNED_BYTE, 1, 1 },
  79. // ??? D3DFMT_V8U8,
  80. // ??? D3DFMT_Q8W8V8U8,
  81. // ??? D3DFMT_X8L8V8U8,
  82. // ??? D3DFMT_R32F,
  83. // ??? D3DFMT_D24X4S4 unsure how to handle or if it is ever used..
  84. // ??? D3DFMT_D15S1 ever used ?
  85. // ??? D3DFMT_D24X8 ever used?
  86. // summ-name d3d-format gl-int-format gl-int-format-srgb gl-data-format gl-data-type chunksize, bytes-per-sqchunk
  87. { "_D16", D3DFMT_D16, GL_DEPTH_COMPONENT16, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, 1, 2 },
  88. { "_D24X8", D3DFMT_D24X8, GL_DEPTH_COMPONENT24, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, 1, 4 }, // ??? unsure on this one
  89. { "_D24S8", D3DFMT_D24S8, GL_DEPTH24_STENCIL8_EXT, 0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, 1, 4 },
  90. { "_A8R8G8B8", D3DFMT_A8R8G8B8, GL_RGBA8, GL_SRGB8_ALPHA8_EXT, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 1, 4 },
  91. { "_A4R4G4B4", D3DFMT_A4R4G4B4, GL_RGBA4, 0, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV, 1, 2 },
  92. { "_X8R8G8B8", D3DFMT_X8R8G8B8, GL_RGB8, GL_SRGB8_EXT, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 1, 4 },
  93. { "_X1R5G5B5", D3DFMT_X1R5G5B5, GL_RGB5, 0, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 1, 2 },
  94. { "_A1R5G5B5", D3DFMT_A1R5G5B5, GL_RGB5_A1, 0, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 1, 2 },
  95. { "_L8", D3DFMT_L8, GL_LUMINANCE8, GL_SLUMINANCE8_EXT, GL_LUMINANCE, GL_UNSIGNED_BYTE, 1, 1 },
  96. { "_A8L8", D3DFMT_A8L8, GL_LUMINANCE8_ALPHA8, GL_SLUMINANCE8_ALPHA8_EXT, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, 1, 2 },
  97. { "_DXT1", D3DFMT_DXT1, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_BYTE, 4, 8 },
  98. { "_DXT3", D3DFMT_DXT3, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_BYTE, 4, 16 },
  99. { "_DXT5", D3DFMT_DXT5, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_BYTE, 4, 16 },
  100. { "_A16B16G16R16F", D3DFMT_A16B16G16R16F, GL_RGBA16F_ARB, 0, GL_RGBA, GL_HALF_FLOAT_ARB, 1, 8 },
  101. { "_A16B16G16R16", D3DFMT_A16B16G16R16, GL_RGBA16, 0, GL_RGBA, GL_UNSIGNED_SHORT, 1, 8 }, // 16bpc integer tex
  102. { "_A32B32G32R32F", D3DFMT_A32B32G32R32F, GL_RGBA32F_ARB, 0, GL_RGBA, GL_FLOAT, 1, 16 },
  103. { "_R8G8B8", D3DFMT_R8G8B8, GL_RGB8, GL_SRGB8_EXT, GL_BGR, GL_UNSIGNED_BYTE, 1, 3 },
  104. { "_A8", D3DFMT_A8, GL_ALPHA8, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 1, 1 },
  105. { "_R5G6B5", D3DFMT_R5G6B5, GL_RGB, GL_SRGB_EXT, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 1, 2 },
  106. // fakey tex formats: the stated GL format and the memory layout may not agree (U8V8 for example)
  107. // _Q8W8V8U8 we just pass through as RGBA bytes. Shader does scale/bias fix
  108. { "_Q8W8V8U8", D3DFMT_Q8W8V8U8, GL_RGBA8, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 1, 4 }, // straight ripoff of D3DFMT_A8R8G8B8
  109. // U8V8 is exposed to the client as 2-bytes per texel, but we download it as 3-byte RGB.
  110. // WriteTexels needs to do that conversion from rg8 to rgb8 in order to be able to download it correctly
  111. { "_V8U8", D3DFMT_V8U8, GL_RGB8, 0, GL_RG, GL_BYTE, 1, 2 },
  112. { "_R32F", D3DFMT_R32F, GL_R32F, GL_R32F, GL_RED, GL_FLOAT, 1, 4 },
  113. //$ TODO: Need to merge bitmap changes over from Dota to get these formats.
  114. #if 0
  115. { "_A2R10G10B10", D3DFMT_A2R10G10B10, GL_RGB10_A2, GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_10_10_10_2, 1, 4 },
  116. { "_A2B10G10R10", D3DFMT_A2B10G10R10, GL_RGB10_A2, GL_RGB10_A2, GL_BGRA, GL_UNSIGNED_INT_10_10_10_2, 1, 4 },
  117. #endif
  118. /*
  119. // NV shadow depth tex
  120. D3DFMT_NV_INTZ = 0x5a544e49, // MAKEFOURCC('I','N','T','Z')
  121. D3DFMT_NV_RAWZ = 0x5a574152, // MAKEFOURCC('R','A','W','Z')
  122. // NV null tex
  123. D3DFMT_NV_NULL = 0x4c4c554e, // MAKEFOURCC('N','U','L','L')
  124. // ATI shadow depth tex
  125. D3DFMT_ATI_D16 = 0x36314644, // MAKEFOURCC('D','F','1','6')
  126. D3DFMT_ATI_D24S8 = 0x34324644, // MAKEFOURCC('D','F','2','4')
  127. // ATI 1N and 2N compressed tex
  128. D3DFMT_ATI_2N = 0x32495441, // MAKEFOURCC('A', 'T', 'I', '2')
  129. D3DFMT_ATI_1N = 0x31495441, // MAKEFOURCC('A', 'T', 'I', '1')
  130. */
  131. };
  132. int g_formatDescTableCount = sizeof(g_formatDescTable) / sizeof( g_formatDescTable[0] );
  133. const GLMTexFormatDesc *GetFormatDesc( D3DFORMAT format )
  134. {
  135. for( int i=0; i<g_formatDescTableCount; i++)
  136. {
  137. if (g_formatDescTable[i].m_d3dFormat == format)
  138. {
  139. return &g_formatDescTable[i];
  140. }
  141. }
  142. return (const GLMTexFormatDesc *)NULL; // not found
  143. }
  144. //===============================================================================
  145. void InsertTexelComponentFixed( float value, int width, unsigned long *valuebuf )
  146. {
  147. unsigned long range = (1<<width);
  148. unsigned long scaled = (value * (float) range) * (range-1) / (range);
  149. if (scaled >= range) DebuggerBreak();
  150. *valuebuf = (*valuebuf << width) | scaled;
  151. }
  152. // return true if successful
  153. bool GLMGenTexels( GLMGenTexelParams *params )
  154. {
  155. unsigned char chunkbuf[256]; // can't think of any chunk this big..
  156. const GLMTexFormatDesc *format = GetFormatDesc( params->m_format );
  157. if (!format)
  158. {
  159. return FALSE; // fail
  160. }
  161. // this section just generates one square chunk in the desired format
  162. unsigned long *temp32 = (unsigned long*)chunkbuf;
  163. unsigned int chunksize = 0; // we can sanity check against the format table with this
  164. switch( params->m_format )
  165. {
  166. // comment shows byte order in RAM
  167. // lowercase is bit arrangement in a byte
  168. case D3DFMT_A8R8G8B8: // B G R A
  169. InsertTexelComponentFixed( params->a, 8, temp32 ); // A is inserted first and winds up at most significant bits after insertions follow
  170. InsertTexelComponentFixed( params->r, 8, temp32 );
  171. InsertTexelComponentFixed( params->g, 8, temp32 );
  172. InsertTexelComponentFixed( params->b, 8, temp32 );
  173. chunksize = 4;
  174. break;
  175. case D3DFMT_A4R4G4B4: // [ggggbbbb] [aaaarrrr] RA (nibbles)
  176. InsertTexelComponentFixed( params->a, 4, temp32 );
  177. InsertTexelComponentFixed( params->r, 4, temp32 );
  178. InsertTexelComponentFixed( params->g, 4, temp32 );
  179. InsertTexelComponentFixed( params->b, 4, temp32 );
  180. chunksize = 2;
  181. break;
  182. case D3DFMT_X8R8G8B8: // B G R X
  183. InsertTexelComponentFixed( 0.0, 8, temp32 );
  184. InsertTexelComponentFixed( params->r, 8, temp32 );
  185. InsertTexelComponentFixed( params->g, 8, temp32 );
  186. InsertTexelComponentFixed( params->b, 8, temp32 );
  187. chunksize = 4;
  188. break;
  189. case D3DFMT_X1R5G5B5: // [gggbbbbb] [xrrrrrgg]
  190. InsertTexelComponentFixed( 0.0, 1, temp32 );
  191. InsertTexelComponentFixed( params->r, 5, temp32 );
  192. InsertTexelComponentFixed( params->g, 5, temp32 );
  193. InsertTexelComponentFixed( params->b, 5, temp32 );
  194. chunksize = 2;
  195. break;
  196. case D3DFMT_A1R5G5B5: // [gggbbbbb] [arrrrrgg]
  197. InsertTexelComponentFixed( params->a, 1, temp32 );
  198. InsertTexelComponentFixed( params->r, 5, temp32 );
  199. InsertTexelComponentFixed( params->g, 5, temp32 );
  200. InsertTexelComponentFixed( params->b, 5, temp32 );
  201. chunksize = 2;
  202. break;
  203. case D3DFMT_L8: // L // caller, use R for L
  204. InsertTexelComponentFixed( params->r, 8, temp32 );
  205. chunksize = 1;
  206. break;
  207. case D3DFMT_A8L8: // L A // caller, use R for L and A for A
  208. InsertTexelComponentFixed( params->a, 8, temp32 );
  209. InsertTexelComponentFixed( params->r, 8, temp32 );
  210. chunksize = 2;
  211. break;
  212. case D3DFMT_R8G8B8: // B G R
  213. InsertTexelComponentFixed( params->r, 8, temp32 );
  214. InsertTexelComponentFixed( params->g, 8, temp32 );
  215. InsertTexelComponentFixed( params->b, 8, temp32 );
  216. chunksize = 3;
  217. break;
  218. case D3DFMT_A8: // A
  219. InsertTexelComponentFixed( params->a, 8, temp32 );
  220. chunksize = 1;
  221. break;
  222. case D3DFMT_R5G6B5: // [gggbbbbb] [rrrrrggg]
  223. InsertTexelComponentFixed( params->r, 5, temp32 );
  224. InsertTexelComponentFixed( params->g, 6, temp32 );
  225. InsertTexelComponentFixed( params->b, 5, temp32 );
  226. chunksize = 2;
  227. break;
  228. case D3DFMT_DXT1:
  229. {
  230. memset( temp32, 0, 8 ); // zap 8 bytes
  231. // two 565 RGB words followed by 32 bits of 2-bit interp values for a 4x4 block
  232. // we write the same color to both slots and all zeroes for the mask (one color total)
  233. unsigned long dxt1_color = 0;
  234. // generate one such word and clone it
  235. InsertTexelComponentFixed( params->r, 5, &dxt1_color );
  236. InsertTexelComponentFixed( params->g, 6, &dxt1_color );
  237. InsertTexelComponentFixed( params->b, 5, &dxt1_color );
  238. // dupe
  239. dxt1_color = dxt1_color | (dxt1_color<<16);
  240. // write into chunkbuf
  241. *(unsigned long*)&chunkbuf[0] = dxt1_color;
  242. // color mask bits after that are already set to all zeroes. chunk is done.
  243. chunksize = 8;
  244. }
  245. break;
  246. case D3DFMT_DXT3:
  247. {
  248. memset( temp32, 0, 16 ); // zap 16 bytes
  249. // eight bytes of alpha (16 4-bit alpha nibbles)
  250. // followed by a DXT1 block
  251. unsigned long dxt3_alpha = 0;
  252. for( int i=0; i<8; i++)
  253. {
  254. // splat same alpha through block
  255. InsertTexelComponentFixed( params->a, 4, &dxt3_alpha );
  256. }
  257. unsigned long dxt3_color = 0;
  258. // generate one such word and clone it
  259. InsertTexelComponentFixed( params->r, 5, &dxt3_color );
  260. InsertTexelComponentFixed( params->g, 6, &dxt3_color );
  261. InsertTexelComponentFixed( params->b, 5, &dxt3_color );
  262. // dupe
  263. dxt3_color = dxt3_color | (dxt3_color<<16);
  264. // write into chunkbuf
  265. *(unsigned long*)&chunkbuf[0] = dxt3_alpha;
  266. *(unsigned long*)&chunkbuf[4] = dxt3_alpha;
  267. *(unsigned long*)&chunkbuf[8] = dxt3_color;
  268. *(unsigned long*)&chunkbuf[12] = dxt3_color;
  269. chunksize = 16;
  270. }
  271. break;
  272. case D3DFMT_DXT5:
  273. {
  274. memset( temp32, 0, 16 ); // zap 16 bytes
  275. // DXT5 has 8 bytes of compressed alpha, then 8 bytes of compressed RGB like DXT1.
  276. // the 8 alpha bytes are 2 bytes of endpoint alpha values, then 16x3 bits of interpolants.
  277. // so to write a single alpha value, just figure out the value, store it in both the first two bytes then store zeroes.
  278. InsertTexelComponentFixed( params->a, 8, (unsigned long*)&chunkbuf[0] );
  279. InsertTexelComponentFixed( params->a, 8, (unsigned long*)&chunkbuf[0] );
  280. // rest of the alpha mask was already zeroed.
  281. // now do colors
  282. unsigned long dxt5_color = 0;
  283. // generate one such word and clone it
  284. InsertTexelComponentFixed( params->r, 5, &dxt5_color );
  285. InsertTexelComponentFixed( params->g, 6, &dxt5_color );
  286. InsertTexelComponentFixed( params->b, 5, &dxt5_color );
  287. // dupe
  288. dxt5_color = dxt5_color | (dxt5_color<<16);
  289. // write into chunkbuf
  290. *(unsigned long*)&chunkbuf[8] = dxt5_color;
  291. *(unsigned long*)&chunkbuf[12] = dxt5_color;
  292. chunksize = 16;
  293. }
  294. break;
  295. case D3DFMT_A32B32G32R32F:
  296. {
  297. *(float*)&chunkbuf[0] = params->r;
  298. *(float*)&chunkbuf[4] = params->g;
  299. *(float*)&chunkbuf[8] = params->b;
  300. *(float*)&chunkbuf[12] = params->a;
  301. chunksize = 16;
  302. }
  303. break;
  304. case D3DFMT_A16B16G16R16:
  305. memset( chunkbuf, 0, 8 );
  306. // R and G wind up in the first 32 bits
  307. // B and A wind up in the second 32 bits
  308. InsertTexelComponentFixed( params->a, 16, (unsigned long*)&chunkbuf[4] ); // winds up as MSW of second word (note [4]) - thus last in RAM
  309. InsertTexelComponentFixed( params->b, 16, (unsigned long*)&chunkbuf[4] );
  310. InsertTexelComponentFixed( params->g, 16, (unsigned long*)&chunkbuf[0] );
  311. InsertTexelComponentFixed( params->r, 16, (unsigned long*)&chunkbuf[0] ); // winds up as LSW of first word, thus first in RAM
  312. chunksize = 8;
  313. break;
  314. // not done yet
  315. //case D3DFMT_D16:
  316. //case D3DFMT_D24X8:
  317. //case D3DFMT_D24S8:
  318. //case D3DFMT_A16B16G16R16F:
  319. default:
  320. return FALSE; // fail
  321. break;
  322. }
  323. // once the chunk buffer is filled..
  324. // sanity check the reported chunk size.
  325. if (static_cast<int>(chunksize) != format->m_bytesPerSquareChunk)
  326. {
  327. DebuggerBreak();
  328. return FALSE;
  329. }
  330. // verify that the amount you want to write will not exceed the limit byte count
  331. unsigned long destByteCount = chunksize * params->m_chunkCount;
  332. if (static_cast<int>(destByteCount) > params->m_byteCountLimit)
  333. {
  334. DebuggerBreak();
  335. return FALSE;
  336. }
  337. // write the bytes.
  338. unsigned char *destP = (unsigned char*)params->m_dest;
  339. for( int chunk=0; chunk < params->m_chunkCount; chunk++)
  340. {
  341. for( uint byteindex = 0; byteindex < chunksize; byteindex++)
  342. {
  343. *destP++ = chunkbuf[byteindex];
  344. }
  345. }
  346. params->m_bytesWritten = destP - (unsigned char*)params->m_dest;
  347. return TRUE;
  348. }
  349. //===============================================================================
  350. bool LessFunc_GLMTexLayoutKey( const GLMTexLayoutKey &a, const GLMTexLayoutKey &b )
  351. {
  352. #define DO_LESS(fff) if (a.fff != b.fff) { return (a.fff< b.fff); }
  353. DO_LESS(m_texGLTarget);
  354. DO_LESS(m_texFormat);
  355. DO_LESS(m_texFlags);
  356. DO_LESS(m_texSamples);
  357. DO_LESS(m_xSize);
  358. DO_LESS(m_ySize)
  359. DO_LESS(m_zSize);
  360. #undef DO_LESS
  361. return false; // they are equal
  362. }
  363. CGLMTexLayoutTable::CGLMTexLayoutTable()
  364. {
  365. m_layoutMap.SetLessFunc( LessFunc_GLMTexLayoutKey );
  366. }
  367. GLMTexLayout *CGLMTexLayoutTable::NewLayoutRef( GLMTexLayoutKey *pDesiredKey )
  368. {
  369. GLMTexLayoutKey tempKey;
  370. GLMTexLayoutKey *key = pDesiredKey;
  371. // look up 'key' in the map and see if it's a hit, if so, bump the refcount and return
  372. // if not, generate a completed layout based on the key, add to map, set refcount to 1, return that
  373. const GLMTexFormatDesc *formatDesc = GetFormatDesc( key->m_texFormat );
  374. //bool compression = (formatDesc->m_chunkSize > 1) != 0;
  375. if (!formatDesc)
  376. {
  377. GLMStop(); // bad news
  378. }
  379. if ( gGL->m_bHave_GL_EXT_texture_sRGB_decode )
  380. {
  381. if ( ( formatDesc->m_glIntFormatSRGB != 0 ) && ( ( key->m_texFlags & kGLMTexSRGB ) == 0 ) )
  382. {
  383. tempKey = *pDesiredKey;
  384. key = &tempKey;
  385. // Slam on SRGB texture flag, and we'll use GL_EXT_texture_sRGB_decode to selectively turn it off in the samplers
  386. key->m_texFlags |= kGLMTexSRGB;
  387. }
  388. }
  389. unsigned short index = m_layoutMap.Find( *key );
  390. if (index != m_layoutMap.InvalidIndex())
  391. {
  392. // found it
  393. //printf(" -hit- ");
  394. GLMTexLayout *layout = m_layoutMap[ index ];
  395. // bump ref count
  396. layout->m_refCount ++;
  397. return layout;
  398. }
  399. else
  400. {
  401. //printf(" -miss- ");
  402. // need to make a new one
  403. // to allocate it, we need to know how big to make it (slice count)
  404. // figure out how many mip levels are in play
  405. int mipCount = 1;
  406. if (key->m_texFlags & kGLMTexMipped)
  407. {
  408. int largestAxis = key->m_xSize;
  409. if (key->m_ySize > largestAxis)
  410. largestAxis = key->m_ySize;
  411. if (key->m_zSize > largestAxis)
  412. largestAxis = key->m_zSize;
  413. mipCount = 0;
  414. while( largestAxis > 0 )
  415. {
  416. mipCount ++;
  417. largestAxis >>= 1;
  418. }
  419. }
  420. int faceCount = 1;
  421. if (key->m_texGLTarget == GL_TEXTURE_CUBE_MAP)
  422. {
  423. faceCount = 6;
  424. }
  425. int sliceCount = mipCount * faceCount;
  426. if (key->m_texFlags & kGLMTexMultisampled)
  427. {
  428. Assert( (key->m_texGLTarget == GL_TEXTURE_2D) );
  429. Assert( sliceCount == 1 );
  430. // assume non mipped
  431. Assert( (key->m_texFlags & kGLMTexMipped) == 0 );
  432. Assert( (key->m_texFlags & kGLMTexMippedAuto) == 0 );
  433. // assume renderable and srgb
  434. Assert( (key->m_texFlags & kGLMTexRenderable) !=0 );
  435. //Assert( (key->m_texFlags & kGLMTexSRGB) !=0 ); //FIXME don't assert on making depthstencil surfaces which are non srgb
  436. // double check sample count (FIXME need real limit check here against device/driver)
  437. Assert( (key->m_texSamples==2) || (key->m_texSamples==4) || (key->m_texSamples==6) || (key->m_texSamples==8) );
  438. }
  439. // now we know enough to allocate and populate the new tex layout.
  440. // malloc the new layout
  441. int layoutSize = sizeof( GLMTexLayout ) + (sliceCount * sizeof( GLMTexLayoutSlice ));
  442. GLMTexLayout *layout = (GLMTexLayout *)malloc( layoutSize );
  443. memset( layout, 0, layoutSize );
  444. // clone the key in there
  445. memset( &layout->m_key, 0x00, sizeof(layout->m_key) );
  446. layout->m_key = *key;
  447. // set refcount
  448. layout->m_refCount = 1;
  449. // save the format desc
  450. layout->m_format = (GLMTexFormatDesc *)formatDesc;
  451. // we know the mipcount from before
  452. layout->m_mipCount = mipCount;
  453. // we know the face count too
  454. layout->m_faceCount = faceCount;
  455. // slice count is the product
  456. layout->m_sliceCount = mipCount * faceCount;
  457. // we can now fill in the slices.
  458. GLMTexLayoutSlice *slicePtr = &layout->m_slices[0];
  459. int storageOffset = 0;
  460. //bool compressed = (formatDesc->m_chunkSize > 1); // true if DXT
  461. for( int mip = 0; mip < mipCount; mip ++ )
  462. {
  463. for( int face = 0; face < faceCount; face++ )
  464. {
  465. // note application of chunk size which is 1 for uncompressed, and 4 for compressed tex (DXT)
  466. // note also that the *dimensions* must scale down to 1
  467. // but that the *storage* cannot go below 4x4.
  468. // we introduce the "storage sizes" which are clamped, to compute the storage footprint.
  469. int storage_x,storage_y,storage_z;
  470. slicePtr->m_xSize = layout->m_key.m_xSize >> mip;
  471. slicePtr->m_xSize = MAX( slicePtr->m_xSize, 1 ); // dimension can't go to zero
  472. storage_x = MAX( slicePtr->m_xSize, formatDesc->m_chunkSize ); // storage extent can't go below chunk size
  473. slicePtr->m_ySize = layout->m_key.m_ySize >> mip;
  474. slicePtr->m_ySize = MAX( slicePtr->m_ySize, 1 ); // dimension can't go to zero
  475. storage_y = MAX( slicePtr->m_ySize, formatDesc->m_chunkSize ); // storage extent can't go below chunk size
  476. slicePtr->m_zSize = layout->m_key.m_zSize >> mip;
  477. slicePtr->m_zSize = MAX( slicePtr->m_zSize, 1 ); // dimension can't go to zero
  478. storage_z = MAX( slicePtr->m_zSize, 1); // storage extent for Z cannot go below '1'.
  479. //if (compressed) NO NO NO do not lie about the dimensionality, just fudge the storage.
  480. //{
  481. // // round up to multiple of 4 in X and Y axes
  482. // slicePtr->m_xSize = (slicePtr->m_xSize+3) & (~3);
  483. // slicePtr->m_ySize = (slicePtr->m_ySize+3) & (~3);
  484. //}
  485. int xchunks = (storage_x / formatDesc->m_chunkSize );
  486. int ychunks = (storage_y / formatDesc->m_chunkSize );
  487. slicePtr->m_storageSize = (xchunks * ychunks * formatDesc->m_bytesPerSquareChunk) * storage_z;
  488. slicePtr->m_storageOffset = storageOffset;
  489. storageOffset += slicePtr->m_storageSize;
  490. storageOffset = ( (storageOffset+0x0F) & (~0x0F)); // keep each MIP starting on a 16 byte boundary.
  491. slicePtr++;
  492. }
  493. }
  494. layout->m_storageTotalSize = storageOffset;
  495. //printf("\n size %08x for key (x=%d y=%d z=%d, fmt=%08x, bpsc=%d)", layout->m_storageTotalSize, key->m_xSize, key->m_ySize, key->m_zSize, key->m_texFormat, formatDesc->m_bytesPerSquareChunk );
  496. // generate summary
  497. // "target, format, +/- mips, base size"
  498. char scratch[1024];
  499. char *targetname = "?";
  500. switch( key->m_texGLTarget )
  501. {
  502. case GL_TEXTURE_2D: targetname = "2D "; break;
  503. case GL_TEXTURE_3D: targetname = "3D "; break;
  504. case GL_TEXTURE_CUBE_MAP: targetname = "CUBE"; break;
  505. }
  506. sprintf( scratch, "[%s %s %dx%dx%d mips=%d slices=%d flags=%02lX%s]",
  507. targetname,
  508. formatDesc->m_formatSummary,
  509. layout->m_key.m_xSize, layout->m_key.m_ySize, layout->m_key.m_zSize,
  510. mipCount,
  511. sliceCount,
  512. layout->m_key.m_texFlags,
  513. (layout->m_key.m_texFlags & kGLMTexSRGB) ? " SRGB" : ""
  514. );
  515. layout->m_layoutSummary = strdup( scratch );
  516. //GLMPRINTF(("-D- new tex layout [ %s ]", scratch ));
  517. // then insert into map. disregard returned index.
  518. m_layoutMap.Insert( layout->m_key, layout );
  519. return layout;
  520. }
  521. }
  522. void CGLMTexLayoutTable::DelLayoutRef( GLMTexLayout *layout )
  523. {
  524. // locate layout in hash, drop refcount
  525. // (some GC step later on will harvest expired layouts - not like it's any big challenge to re-generate them)
  526. unsigned short index = m_layoutMap.Find( layout->m_key );
  527. if (index != m_layoutMap.InvalidIndex())
  528. {
  529. // found it
  530. GLMTexLayout *layout = m_layoutMap[ index ];
  531. // drop ref count
  532. layout->m_refCount --;
  533. //assert( layout->m_refCount >= 0 );
  534. }
  535. else
  536. {
  537. // that's bad
  538. GLMStop();
  539. }
  540. }
  541. void CGLMTexLayoutTable::DumpStats( )
  542. {
  543. for (uint i=0; i<m_layoutMap.Count(); i++ )
  544. {
  545. GLMTexLayout *layout = m_layoutMap[ i ];
  546. // print it out
  547. printf("\n%05d instances %08d bytes %08d totbytes %s", layout->m_refCount, layout->m_storageTotalSize, (layout->m_refCount*layout->m_storageTotalSize), layout->m_layoutSummary );
  548. }
  549. }
  550. ConVar gl_texmsaalog ( "gl_texmsaalog", "0");
  551. ConVar gl_rt_forcergba ( "gl_rt_forcergba", "1" ); // on teximage of a renderable tex, pass GL_RGBA in place of GL_BGRA
  552. ConVar gl_minimize_rt_tex ( "gl_minimize_rt_tex", "0" ); // if 1, set the GL_TEXTURE_MINIMIZE_STORAGE_APPLE texture parameter to cut off mipmaps for RT's
  553. ConVar gl_minimize_all_tex ( "gl_minimize_all_tex", "1" ); // if 1, set the GL_TEXTURE_MINIMIZE_STORAGE_APPLE texture parameter to cut off mipmaps for textures which are unmipped
  554. ConVar gl_minimize_tex_log ( "gl_minimize_tex_log", "0" ); // if 1, printf the names of the tex that got minimized
  555. CGLMTex::CGLMTex( GLMContext *ctx, GLMTexLayout *layout, uint levels, const char *debugLabel )
  556. {
  557. #if GLMDEBUG
  558. m_pPrevTex = NULL;
  559. m_pNextTex = g_pFirstCGMLTex;
  560. if ( m_pNextTex )
  561. {
  562. Assert( m_pNextTex->m_pPrevTex == NULL );
  563. m_pNextTex->m_pPrevTex = this;
  564. }
  565. g_pFirstCGMLTex = this;
  566. #endif
  567. // caller has responsibility to make 'ctx' current, but we check to be sure.
  568. ctx->CheckCurrent();
  569. m_nLastResolvedBatchCounter = ctx->m_nBatchCounter;
  570. // note layout requested
  571. m_layout = layout;
  572. m_texGLTarget = m_layout->m_key.m_texGLTarget;
  573. m_nSamplerType = SAMPLER_TYPE_UNUSED;
  574. switch ( m_texGLTarget )
  575. {
  576. case GL_TEXTURE_CUBE_MAP: m_nSamplerType = SAMPLER_TYPE_CUBE; break;
  577. case GL_TEXTURE_2D: m_nSamplerType = SAMPLER_TYPE_2D; break;
  578. case GL_TEXTURE_3D: m_nSamplerType = SAMPLER_TYPE_3D; break;
  579. default:
  580. Assert( 0 );
  581. break;
  582. }
  583. m_maxActiveMip = -1; //index of highest mip that has been written - increase as each mip arrives
  584. m_minActiveMip = 999; //index of lowest mip that has been written - lower it as each mip arrives
  585. // note context owner
  586. m_ctx = ctx;
  587. // clear the bind point flags
  588. //m_bindPoints.ClearAll();
  589. // clear the RT attach count
  590. m_rtAttachCount = 0;
  591. // come up with a GL name for this texture.
  592. m_texName = ctx->CreateTex( m_texGLTarget, m_layout->m_format->m_glIntFormat );
  593. m_pBlitSrcFBO = NULL;
  594. m_pBlitDstFBO = NULL;
  595. // Sense whether to try and apply client storage upon teximage/subimage.
  596. // This should only be true if we're running on OSX 10.6 or it was explicitly
  597. // enabled with -gl_texclientstorage on the command line.
  598. m_texClientStorage = ctx->m_bTexClientStorage;
  599. // flag that we have not yet been explicitly kicked into VRAM..
  600. m_texPreloaded = false;
  601. // clone the debug label if there is one.
  602. m_debugLabel = debugLabel ? strdup(debugLabel) : NULL;
  603. // if tex is MSAA renderable, make an RBO, else zero the RBO name and dirty bit
  604. if (layout->m_key.m_texFlags & kGLMTexMultisampled)
  605. {
  606. gGL->glGenRenderbuffersEXT( 1, &m_rboName );
  607. // so we have enough info to go ahead and bind the RBO and put storage on it?
  608. // try it.
  609. gGL->glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, m_rboName );
  610. // quietly clamp if sample count exceeds known limit for the device
  611. int sampleCount = layout->m_key.m_texSamples;
  612. if (sampleCount > ctx->Caps().m_maxSamples)
  613. {
  614. sampleCount = ctx->Caps().m_maxSamples; // clamp
  615. }
  616. GLenum msaaFormat = (layout->m_key.m_texFlags & kGLMTexSRGB) ? layout->m_format->m_glIntFormatSRGB : layout->m_format->m_glIntFormat;
  617. gGL->glRenderbufferStorageMultisampleEXT( GL_RENDERBUFFER_EXT,
  618. sampleCount, // not "layout->m_key.m_texSamples"
  619. msaaFormat,
  620. layout->m_key.m_xSize,
  621. layout->m_key.m_ySize );
  622. if (gl_texmsaalog.GetInt())
  623. {
  624. printf( "\n == MSAA Tex %p %s : MSAA RBO is intformat %s (%x)", this, m_debugLabel?m_debugLabel:"", GLMDecode( eGL_ENUM, msaaFormat ), msaaFormat );
  625. }
  626. gGL->glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
  627. }
  628. else
  629. {
  630. m_rboName = 0;
  631. }
  632. // at this point we have the complete description of the texture, and a name for it, but no data and no actual GL object.
  633. // we know this name has bever seen duty before, so we're going to hard-bind it to TMU 0, displacing any other tex that might have been bound there.
  634. // any previously bound tex will be unbound and appropriately marked as a result.
  635. // the active TMU will be set as a side effect.
  636. CGLMTex *pPrevTex = ctx->m_samplers[0].m_pBoundTex;
  637. ctx->BindTexToTMU( this, 0 );
  638. m_SamplingParams.SetToDefaults();
  639. m_SamplingParams.SetToTarget( m_texGLTarget );
  640. // OK, our texture now exists and is bound on the active TMU. Not drawable yet though.
  641. // Create backing storage and fill it
  642. if ( !(layout->m_key.m_texFlags & kGLMTexRenderable) && m_texClientStorage )
  643. {
  644. m_backing = (char *)malloc( m_layout->m_storageTotalSize );
  645. memset( m_backing, 0, m_layout->m_storageTotalSize );
  646. // track bytes allocated for non-RT's
  647. int formindex = sEncodeLayoutAsIndex( &layout->m_key );
  648. g_texGlobalBytes[ formindex ] += m_layout->m_storageTotalSize;
  649. #if TEXSPACE_LOGGING
  650. printf( "\n Tex %s added %d bytes in form %d which is now %d bytes", m_debugLabel ? m_debugLabel : "-", m_layout->m_storageTotalSize, formindex, g_texGlobalBytes[ formindex ] );
  651. printf( "\n\t\t[ %d %d %d %d %d %d %d %d ]",
  652. g_texGlobalBytes[ 0 ],g_texGlobalBytes[ 1 ],g_texGlobalBytes[ 2 ],g_texGlobalBytes[ 3 ],
  653. g_texGlobalBytes[ 4 ],g_texGlobalBytes[ 5 ],g_texGlobalBytes[ 6 ],g_texGlobalBytes[ 7 ]
  654. );
  655. #endif
  656. }
  657. else
  658. {
  659. m_backing = NULL;
  660. m_texClientStorage = false;
  661. }
  662. // init lock count
  663. // lock reqs are tracked by the owning context
  664. m_lockCount = 0;
  665. m_sliceFlags.SetCount( m_layout->m_sliceCount );
  666. for( int i=0; i< m_layout->m_sliceCount; i++)
  667. {
  668. m_sliceFlags[i] = 0;
  669. // kSliceValid = false (we have not teximaged each slice yet)
  670. // kSliceStorageValid = false (the storage allocated does not reflect what is in the tex)
  671. // kSliceLocked = false (the slices are not locked)
  672. // kSliceFullyDirty = false (this does not come true til first lock)
  673. }
  674. // texture minimize parameter keeps driver from allocing mips when it should not, by being explicit about the ones that have no mips.
  675. bool setMinimizeParameter = false;
  676. bool minimize_rt = (gl_minimize_rt_tex.GetInt()!=0);
  677. bool minimize_all = (gl_minimize_all_tex.GetInt()!=0);
  678. if (layout->m_key.m_texFlags & kGLMTexRenderable)
  679. {
  680. // it's an RT. if mips were not explicitly requested, and "gl_minimize_rt_tex" is true, set the minimize parameter.
  681. if ( (minimize_rt || minimize_all) && ( !(layout->m_key.m_texFlags & kGLMTexMipped) ) )
  682. {
  683. setMinimizeParameter = true;
  684. }
  685. }
  686. else
  687. {
  688. // not an RT. if mips were not requested, and "gl_minimize_all_tex" is true, set the minimize parameter.
  689. if ( minimize_all && ( !(layout->m_key.m_texFlags & kGLMTexMipped) ) )
  690. {
  691. setMinimizeParameter = true;
  692. }
  693. }
  694. if (setMinimizeParameter)
  695. {
  696. if (gl_minimize_tex_log.GetInt())
  697. {
  698. printf("\n minimizing storage for tex '%s' [%s] ", m_debugLabel?m_debugLabel:"-", m_layout->m_layoutSummary );
  699. }
  700. if (gGL->m_bHave_GL_APPLE_texture_range)
  701. gGL->glTexParameteri( m_layout->m_key.m_texGLTarget, GL_TEXTURE_MINIMIZE_STORAGE_APPLE, 1 );
  702. }
  703. // after a lot of pain with texture completeness...
  704. // always push black into all slices of all newly created textures.
  705. #if 0
  706. bool pushRenderableSlices = (m_layout->m_key.m_texFlags & kGLMTexRenderable) != 0;
  707. bool pushTexSlices = true; // just do it everywhere (m_layout->m_mipCount>1) && (m_layout->m_format->m_chunkSize !=1) ;
  708. if (pushTexSlices)
  709. {
  710. // fill storage with mostly-opaque purple
  711. GLMGenTexelParams genp;
  712. memset( &genp, 0, sizeof(genp) );
  713. genp.m_format = m_layout->m_format->m_d3dFormat;
  714. const GLMTexFormatDesc *format = GetFormatDesc( genp.m_format );
  715. genp.m_dest = m_backing; // dest addr
  716. genp.m_chunkCount = m_layout->m_storageTotalSize / format->m_bytesPerSquareChunk; // fill the whole slab
  717. genp.m_byteCountLimit = m_layout->m_storageTotalSize; // limit writes to this amount
  718. genp.r = 1.0;
  719. genp.g = 0.0;
  720. genp.b = 1.0;
  721. genp.a = 0.75;
  722. GLMGenTexels( &genp );
  723. }
  724. #endif
  725. //if (pushRenderableSlices || pushTexSlices)
  726. if ( !( ( layout->m_key.m_texFlags & kGLMTexMipped ) && ( levels == ( unsigned ) m_layout->m_mipCount ) ) )
  727. {
  728. for( int face=0; face <m_layout->m_faceCount; face++)
  729. {
  730. for( int mip=0; mip <m_layout->m_mipCount; mip++)
  731. {
  732. // we're not really going to lock, we're just going to write the blank data from the backing store we just made
  733. GLMTexLockDesc desc;
  734. desc.m_req.m_tex = this;
  735. desc.m_req.m_face = face;
  736. desc.m_req.m_mip = mip;
  737. desc.m_sliceIndex = CalcSliceIndex( face, mip );
  738. GLMTexLayoutSlice *slice = &m_layout->m_slices[ desc.m_sliceIndex ];
  739. desc.m_req.m_region.xmin = desc.m_req.m_region.ymin = desc.m_req.m_region.zmin = 0;
  740. desc.m_req.m_region.xmax = slice->m_xSize;
  741. desc.m_req.m_region.ymax = slice->m_ySize;
  742. desc.m_req.m_region.zmax = slice->m_zSize;
  743. desc.m_sliceBaseOffset = slice->m_storageOffset; // doesn't really matter... we're just pushing zeroes..
  744. desc.m_sliceRegionOffset = 0;
  745. WriteTexels( &desc, true, (layout->m_key.m_texFlags & kGLMTexRenderable)!=0 ); // write whole slice - but disable data source if it's an RT, as there's no backing
  746. }
  747. }
  748. }
  749. GLMPRINTF(("-A- -**TEXNEW '%-60s' name=%06d size=%09d storage=%08x label=%s ", m_layout->m_layoutSummary, m_texName, m_layout->m_storageTotalSize, m_backing, m_debugLabel ? m_debugLabel : "-" ));
  750. ctx->BindTexToTMU( pPrevTex, 0 );
  751. }
  752. CGLMTex::~CGLMTex( )
  753. {
  754. #if GLMDEBUG
  755. if ( m_pPrevTex )
  756. {
  757. Assert( m_pPrevTex->m_pNextTex == this );
  758. m_pPrevTex->m_pNextTex = m_pNextTex;
  759. }
  760. else
  761. {
  762. Assert( g_pFirstCGMLTex == this );
  763. g_pFirstCGMLTex = m_pNextTex;
  764. }
  765. if ( m_pNextTex )
  766. {
  767. Assert( m_pNextTex->m_pPrevTex == this );
  768. m_pNextTex->m_pPrevTex = m_pPrevTex;
  769. }
  770. m_pNextTex = m_pPrevTex = NULL;
  771. #endif
  772. if ( !(m_layout->m_key.m_texFlags & kGLMTexRenderable) )
  773. {
  774. int formindex = sEncodeLayoutAsIndex( &m_layout->m_key );
  775. g_texGlobalBytes[ formindex ] -= m_layout->m_storageTotalSize;
  776. #if TEXSPACE_LOGGING
  777. printf( "\n Tex %s freed %d bytes in form %d which is now %d bytes", m_debugLabel ? m_debugLabel : "-", m_layout->m_storageTotalSize, formindex, g_texGlobalBytes[ formindex ] );
  778. printf( "\n\t\t[ %d %d %d %d %d %d %d %d ]",
  779. g_texGlobalBytes[ 0 ],g_texGlobalBytes[ 1 ],g_texGlobalBytes[ 2 ],g_texGlobalBytes[ 3 ],
  780. g_texGlobalBytes[ 4 ],g_texGlobalBytes[ 5 ],g_texGlobalBytes[ 6 ],g_texGlobalBytes[ 7 ]
  781. );
  782. #endif
  783. }
  784. GLMPRINTF(("-A- -**TEXDEL '%-60s' name=%06d size=%09d storage=%08x label=%s ", m_layout->m_layoutSummary, m_texName, m_layout->m_storageTotalSize, m_backing, m_debugLabel ? m_debugLabel : "-" ));
  785. // check first to see if we were still bound anywhere or locked... these should be failures.
  786. if ( m_pBlitSrcFBO )
  787. {
  788. m_ctx->DelFBO( m_pBlitSrcFBO );
  789. m_pBlitSrcFBO = NULL;
  790. }
  791. if ( m_pBlitDstFBO )
  792. {
  793. m_ctx->DelFBO( m_pBlitDstFBO );
  794. m_pBlitDstFBO = NULL;
  795. }
  796. if ( m_rboName )
  797. {
  798. gGL->glDeleteRenderbuffersEXT( 1, &m_rboName );
  799. m_rboName = 0;
  800. }
  801. // if all that is OK, then delete the underlying tex
  802. if ( m_texName )
  803. {
  804. m_ctx->DestroyTex( m_texGLTarget, m_layout, m_texName );
  805. m_texName = 0;
  806. }
  807. // release our usage of the layout
  808. m_ctx->m_texLayoutTable->DelLayoutRef( m_layout );
  809. m_layout = NULL;
  810. if (m_backing)
  811. {
  812. free( m_backing );
  813. m_backing = NULL;
  814. }
  815. if (m_debugLabel)
  816. {
  817. free( m_debugLabel );
  818. m_debugLabel = NULL;
  819. }
  820. m_ctx = NULL;
  821. }
  822. int CGLMTex::CalcSliceIndex( int face, int mip )
  823. {
  824. // faces of the same mip level are adjacent. "face major" storage
  825. int index = (mip * m_layout->m_faceCount) + face;
  826. return index;
  827. }
  828. void CGLMTex::CalcTexelDataOffsetAndStrides( int sliceIndex, int x, int y, int z, int *offsetOut, int *yStrideOut, int *zStrideOut )
  829. {
  830. int offset = 0;
  831. int yStride = 0;
  832. int zStride = 0;
  833. GLMTexFormatDesc *format = m_layout->m_format;
  834. if (format->m_chunkSize==1)
  835. {
  836. // figure out row stride and layer stride
  837. yStride = format->m_bytesPerSquareChunk * m_layout->m_slices[sliceIndex].m_xSize; // bytes per texel row (y stride)
  838. zStride = yStride * m_layout->m_slices[sliceIndex].m_ySize; // bytes per texel layer (if 3D tex)
  839. offset = x * format->m_bytesPerSquareChunk; // lateral offset
  840. offset += (y * yStride); // scanline offset
  841. offset += (z * zStride); // should be zero for 2D tex
  842. }
  843. else
  844. {
  845. yStride = format->m_bytesPerSquareChunk * (m_layout->m_slices[sliceIndex].m_xSize / format->m_chunkSize);
  846. zStride = yStride * (m_layout->m_slices[sliceIndex].m_ySize / format->m_chunkSize);
  847. // compressed format. scale the x,y,z values into chunks.
  848. // assert if any of them are not multiples of a chunk.
  849. int chunkx = x / format->m_chunkSize;
  850. int chunky = y / format->m_chunkSize;
  851. int chunkz = z / format->m_chunkSize;
  852. if ( (chunkx * format->m_chunkSize) != x)
  853. {
  854. GLMStop();
  855. }
  856. if ( (chunky * format->m_chunkSize) != y)
  857. {
  858. GLMStop();
  859. }
  860. if ( (chunkz * format->m_chunkSize) != z)
  861. {
  862. GLMStop();
  863. }
  864. offset = chunkx * format->m_bytesPerSquareChunk; // lateral offset
  865. offset += (chunky * yStride); // chunk row offset
  866. offset += (chunkz * zStride); // should be zero for 2D tex
  867. }
  868. *offsetOut = offset;
  869. *yStrideOut = yStride;
  870. *zStrideOut = zStride;
  871. }
  872. void CGLMTex::ReadTexels( GLMTexLockDesc *desc, bool readWholeSlice )
  873. {
  874. GLMRegion readBox;
  875. if (readWholeSlice)
  876. {
  877. readBox.xmin = readBox.ymin = readBox.zmin = 0;
  878. readBox.xmax = m_layout->m_slices[ desc->m_sliceIndex ].m_xSize;
  879. readBox.ymax = m_layout->m_slices[ desc->m_sliceIndex ].m_ySize;
  880. readBox.zmax = m_layout->m_slices[ desc->m_sliceIndex ].m_zSize;
  881. }
  882. else
  883. {
  884. readBox = desc->m_req.m_region;
  885. }
  886. CGLMTex *pPrevTex = m_ctx->m_samplers[0].m_pBoundTex;
  887. m_ctx->BindTexToTMU( this, 0 ); // SelectTMU(n) is a side effect
  888. if (readWholeSlice)
  889. {
  890. // make this work first.... then write the partial path
  891. // (Hmmmm, I don't think we will ever actually need a partial path -
  892. // since we have no notion of a partially valid slice of storage
  893. GLMTexFormatDesc *format = m_layout->m_format;
  894. GLenum target = m_layout->m_key.m_texGLTarget;
  895. void *sliceAddress = m_backing + m_layout->m_slices[ desc->m_sliceIndex ].m_storageOffset; // this would change for PBO
  896. //int sliceSize = m_layout->m_slices[ desc->m_sliceIndex ].m_storageSize;
  897. // interestingly enough, we can use the same path for both 2D and 3D fetch
  898. switch( target )
  899. {
  900. case GL_TEXTURE_CUBE_MAP:
  901. // adjust target to steer to the proper face, then fall through to the 2D texture path.
  902. target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + desc->m_req.m_face;
  903. case GL_TEXTURE_2D:
  904. case GL_TEXTURE_3D:
  905. {
  906. // check compressed or not
  907. if (format->m_chunkSize != 1)
  908. {
  909. // compressed path
  910. // http://www.opengl.org/sdk/docs/man/xhtml/glGetCompressedTexImage.xml
  911. gGL->glGetCompressedTexImage( target, // target
  912. desc->m_req.m_mip, // level
  913. sliceAddress ); // destination
  914. }
  915. else
  916. {
  917. // uncompressed path
  918. // http://www.opengl.org/sdk/docs/man/xhtml/glGetTexImage.xml
  919. gGL->glGetTexImage( target, // target
  920. desc->m_req.m_mip, // level
  921. format->m_glDataFormat, // dataformat
  922. format->m_glDataType, // datatype
  923. sliceAddress ); // destination
  924. }
  925. }
  926. break;
  927. }
  928. }
  929. else
  930. {
  931. GLMStop();
  932. }
  933. m_ctx->BindTexToTMU( pPrevTex, 0 );
  934. }
  935. // TexSubImage should work properly on every driver stack and GPU--enabling by default.
  936. ConVar gl_enabletexsubimage( "gl_enabletexsubimage", "1" );
  937. void CGLMTex::WriteTexels( GLMTexLockDesc *desc, bool writeWholeSlice, bool noDataWrite )
  938. {
  939. //if ( m_nBindlessHashNumEntries )
  940. // return;
  941. GLMRegion writeBox;
  942. bool needsExpand = false;
  943. char *expandTemp = NULL;
  944. switch( m_layout->m_format->m_d3dFormat)
  945. {
  946. case D3DFMT_V8U8:
  947. {
  948. needsExpand = true;
  949. writeWholeSlice = true;
  950. // shoot down client storage if we have to generate a new flavor of the data
  951. m_texClientStorage = false;
  952. }
  953. break;
  954. }
  955. if (writeWholeSlice)
  956. {
  957. writeBox.xmin = writeBox.ymin = writeBox.zmin = 0;
  958. writeBox.xmax = m_layout->m_slices[ desc->m_sliceIndex ].m_xSize;
  959. writeBox.ymax = m_layout->m_slices[ desc->m_sliceIndex ].m_ySize;
  960. writeBox.zmax = m_layout->m_slices[ desc->m_sliceIndex ].m_zSize;
  961. }
  962. else
  963. {
  964. writeBox = desc->m_req.m_region;
  965. }
  966. // first thing is to get the GL texture bound to a TMU, or just select one if already bound
  967. // to get this running we will just always slam TMU 0 and let the draw time code fix it back
  968. // a later optimization would be to hoist the bind call to the caller, do it exactly once
  969. CGLMTex *pPrevTex = m_ctx->m_samplers[0].m_pBoundTex;
  970. m_ctx->BindTexToTMU( this, 0 ); // SelectTMU(n) is a side effect
  971. GLMTexFormatDesc *format = m_layout->m_format;
  972. GLenum target = m_layout->m_key.m_texGLTarget;
  973. GLenum glDataFormat = format->m_glDataFormat; // this could change if expansion kicks in
  974. GLenum glDataType = format->m_glDataType;
  975. GLMTexLayoutSlice *slice = &m_layout->m_slices[ desc->m_sliceIndex ];
  976. void *sliceAddress = m_backing ? (m_backing + slice->m_storageOffset) : NULL; // this would change for PBO
  977. // allow use of subimage if the target is texture2D and it has already been teximage'd
  978. bool mayUseSubImage = false;
  979. if ( (target==GL_TEXTURE_2D) && (m_sliceFlags[ desc->m_sliceIndex ] & kSliceValid) )
  980. {
  981. mayUseSubImage = gl_enabletexsubimage.GetInt() != 0;
  982. }
  983. // check flavor, 2D, 3D, or cube map
  984. // we also have the choice to use subimage if this is a tex already created. (open question as to benefit)
  985. // SRGB select. At this level (writetexels) we firmly obey the m_texFlags.
  986. // (mechanism not policy)
  987. GLenum intformat = (m_layout->m_key.m_texFlags & kGLMTexSRGB) ? format->m_glIntFormatSRGB : format->m_glIntFormat;
  988. if (CommandLine()->FindParm("-disable_srgbtex"))
  989. {
  990. // force non srgb flavor - experiment to make ATI r600 happy on 10.5.8 (maybe x1600 too!)
  991. intformat = format->m_glIntFormat;
  992. }
  993. Assert( intformat != 0 );
  994. if (m_layout->m_key.m_texFlags & kGLMTexSRGB)
  995. {
  996. Assert( m_layout->m_format->m_glDataFormat != GL_DEPTH_COMPONENT );
  997. Assert( m_layout->m_format->m_glDataFormat != GL_DEPTH_STENCIL_EXT );
  998. Assert( m_layout->m_format->m_glDataFormat != GL_ALPHA );
  999. }
  1000. // adjust min and max mip written
  1001. if (desc->m_req.m_mip > m_maxActiveMip)
  1002. {
  1003. m_maxActiveMip = desc->m_req.m_mip;
  1004. gGL->glTexParameteri( target, GL_TEXTURE_MAX_LEVEL, desc->m_req.m_mip);
  1005. }
  1006. if (desc->m_req.m_mip < m_minActiveMip)
  1007. {
  1008. m_minActiveMip = desc->m_req.m_mip;
  1009. gGL->glTexParameteri( target, GL_TEXTURE_BASE_LEVEL, desc->m_req.m_mip);
  1010. }
  1011. if (needsExpand)
  1012. {
  1013. int expandSize = 0;
  1014. switch( m_layout->m_format->m_d3dFormat)
  1015. {
  1016. case D3DFMT_V8U8:
  1017. {
  1018. // figure out new size based on 3byte RGB format
  1019. // easy, just take the two byte size and grow it by 50%
  1020. expandSize = (slice->m_storageSize * 3) / 2;
  1021. expandTemp = (char*)malloc( expandSize );
  1022. char *src = (char*)sliceAddress;
  1023. char *dst = expandTemp;
  1024. // transfer RG's to RGB's
  1025. while(expandSize>0)
  1026. {
  1027. *dst = *src++; // move first byte
  1028. *dst = *src++; // move second byte
  1029. *reinterpret_cast<uint8*>(dst) = 0xBB; // pad third byte
  1030. expandSize -= 3;
  1031. }
  1032. // move the slice pointer
  1033. sliceAddress = expandTemp;
  1034. // change the data format we tell GL about
  1035. glDataFormat = GL_RGB;
  1036. }
  1037. break;
  1038. default: Assert(!"Don't know how to expand that format..");
  1039. }
  1040. }
  1041. // set up the client storage now, one way or another
  1042. // If this extension isn't supported, we just end up with two copies of the texture, one in the GL and one in app memory.
  1043. // So it's safe to just go on as if this extension existed and hold the possibly-unnecessary extra RAM.
  1044. if (gGL->m_bHave_GL_APPLE_client_storage)
  1045. {
  1046. gGL->glPixelStorei( GL_UNPACK_CLIENT_STORAGE_APPLE, m_texClientStorage );
  1047. }
  1048. switch( target )
  1049. {
  1050. case GL_TEXTURE_CUBE_MAP:
  1051. // adjust target to steer to the proper face, then fall through to the 2D texture path.
  1052. target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + desc->m_req.m_face;
  1053. case GL_TEXTURE_2D:
  1054. {
  1055. // check compressed or not
  1056. if (format->m_chunkSize != 1)
  1057. {
  1058. Assert( writeWholeSlice ); //subimage not implemented in this path yet
  1059. // compressed path
  1060. // http://www.opengl.org/sdk/docs/man/xhtml/glCompressedTexImage2D.xml
  1061. gGL->glCompressedTexImage2D( target, // target
  1062. desc->m_req.m_mip, // level
  1063. intformat, // internalformat - don't use format->m_glIntFormat because we have the SRGB select going on above
  1064. slice->m_xSize, // width
  1065. slice->m_ySize, // height
  1066. 0, // border
  1067. slice->m_storageSize, // imageSize
  1068. sliceAddress ); // data
  1069. }
  1070. else
  1071. {
  1072. if (mayUseSubImage)
  1073. {
  1074. // go subimage2D if it's a replacement, not a creation
  1075. gGL->glPixelStorei( GL_UNPACK_ROW_LENGTH, slice->m_xSize ); // in pixels
  1076. gGL->glPixelStorei( GL_UNPACK_SKIP_PIXELS, writeBox.xmin ); // in pixels
  1077. gGL->glPixelStorei( GL_UNPACK_SKIP_ROWS, writeBox.ymin ); // in pixels
  1078. gGL->glTexSubImage2D( target,
  1079. desc->m_req.m_mip, // level
  1080. writeBox.xmin, // xoffset into dest
  1081. writeBox.ymin, // yoffset into dest
  1082. writeBox.xmax - writeBox.xmin, // width (was slice->m_xSize)
  1083. writeBox.ymax - writeBox.ymin, // height (was slice->m_ySize)
  1084. glDataFormat, // format
  1085. glDataType, // type
  1086. sliceAddress // data (will be offsetted by the SKIP_PIXELS and SKIP_ROWS - let GL do the math to find the first source texel)
  1087. );
  1088. gGL->glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
  1089. gGL->glPixelStorei( GL_UNPACK_SKIP_PIXELS, 0 );
  1090. gGL->glPixelStorei( GL_UNPACK_SKIP_ROWS, 0 );
  1091. /*
  1092. //http://www.opengl.org/sdk/docs/man/xhtml/glTexSubImage2D.xml
  1093. glTexSubImage2D( target,
  1094. desc->m_req.m_mip, // level
  1095. 0, // xoffset
  1096. 0, // yoffset
  1097. slice->m_xSize, // width
  1098. slice->m_ySize, // height
  1099. glDataFormat, // format
  1100. glDataType, // type
  1101. sliceAddress // data
  1102. );
  1103. */
  1104. }
  1105. else
  1106. {
  1107. if (m_layout->m_key.m_texFlags & kGLMTexRenderable)
  1108. {
  1109. if (gl_rt_forcergba.GetInt())
  1110. {
  1111. if (glDataFormat == GL_BGRA)
  1112. {
  1113. // change it
  1114. glDataFormat = GL_RGBA;
  1115. }
  1116. }
  1117. }
  1118. // uncompressed path
  1119. // http://www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/teximage2d.html
  1120. gGL->glTexImage2D( target, // target
  1121. desc->m_req.m_mip, // level
  1122. intformat, // internalformat - don't use format->m_glIntFormat because we have the SRGB select going on above
  1123. slice->m_xSize, // width
  1124. slice->m_ySize, // height
  1125. 0, // border
  1126. glDataFormat, // dataformat
  1127. glDataType, // datatype
  1128. noDataWrite ? NULL : sliceAddress ); // data (optionally suppressed in case ResetSRGB desires)
  1129. if (m_layout->m_key.m_texFlags & kGLMTexMultisampled)
  1130. {
  1131. if (gl_texmsaalog.GetInt())
  1132. {
  1133. printf( "\n == MSAA Tex %p %s : glTexImage2D for flat tex using intformat %s (%x)", this, m_debugLabel?m_debugLabel:"", GLMDecode( eGL_ENUM, intformat ), intformat );
  1134. printf( "\n" );
  1135. }
  1136. }
  1137. m_sliceFlags[ desc->m_sliceIndex ] |= kSliceValid; // for next time, we can subimage..
  1138. }
  1139. }
  1140. }
  1141. break;
  1142. case GL_TEXTURE_3D:
  1143. {
  1144. // check compressed or not
  1145. if (format->m_chunkSize != 1)
  1146. {
  1147. // compressed path
  1148. // http://www.opengl.org/sdk/docs/man/xhtml/glCompressedTexImage3D.xml
  1149. gGL->glCompressedTexImage3D( target, // target
  1150. desc->m_req.m_mip, // level
  1151. intformat, // internalformat
  1152. slice->m_xSize, // width
  1153. slice->m_ySize, // height
  1154. slice->m_zSize, // depth
  1155. 0, // border
  1156. slice->m_storageSize, // imageSize
  1157. sliceAddress ); // data
  1158. }
  1159. else
  1160. {
  1161. // uncompressed path
  1162. // http://www.opengl.org/sdk/docs/man/xhtml/glTexImage3D.xml
  1163. gGL->glTexImage3D( target, // target
  1164. desc->m_req.m_mip, // level
  1165. intformat, // internalformat
  1166. slice->m_xSize, // width
  1167. slice->m_ySize, // height
  1168. slice->m_zSize, // depth
  1169. 0, // border
  1170. glDataFormat, // dataformat
  1171. glDataType, // datatype
  1172. noDataWrite ? NULL : sliceAddress ); // data (optionally suppressed in case ResetSRGB desires)
  1173. }
  1174. }
  1175. break;
  1176. }
  1177. if (gGL->m_bHave_GL_APPLE_client_storage)
  1178. {
  1179. gGL->glPixelStorei( GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE );
  1180. }
  1181. if ( expandTemp )
  1182. {
  1183. free( expandTemp );
  1184. }
  1185. m_ctx->BindTexToTMU( pPrevTex, 0 );
  1186. }
  1187. void CGLMTex::Lock( GLMTexLockParams *params, char** addressOut, int* yStrideOut, int *zStrideOut )
  1188. {
  1189. #if GL_TELEMETRY_GPU_ZONES
  1190. CScopedGLMPIXEvent glmPIXEvent( "CGLMTex::Lock" );
  1191. g_TelemetryGPUStats.m_nTotalTexLocksAndUnlocks++;
  1192. #endif
  1193. // locate appropriate slice in layout record
  1194. int sliceIndex = CalcSliceIndex( params->m_face, params->m_mip );
  1195. GLMTexLayoutSlice *slice = &m_layout->m_slices[sliceIndex];
  1196. // obtain offset
  1197. //int sliceBaseOffset = slice->m_storageOffset;
  1198. // cross check region req against slice bounds - figure out if it matches, exceeds, or is less than the whole slice.
  1199. char exceed = (params->m_region.xmin < 0) || (params->m_region.xmax > slice->m_xSize) ||
  1200. (params->m_region.ymin < 0) || (params->m_region.ymax > slice->m_ySize) ||
  1201. (params->m_region.zmin < 0) || (params->m_region.zmax > slice->m_zSize);
  1202. char partial = (params->m_region.xmin > 0) || (params->m_region.xmax < slice->m_xSize) ||
  1203. (params->m_region.ymin > 0) || (params->m_region.ymax < slice->m_ySize) ||
  1204. (params->m_region.zmin > 0) || (params->m_region.zmax < slice->m_zSize);
  1205. bool copyout = false; // set if a readback of the texture slice from GL is needed
  1206. if (exceed)
  1207. {
  1208. // illegal rect, out of bounds
  1209. GLMStop();
  1210. }
  1211. // on return, these things need to be true
  1212. // a - there needs to be storage allocated, which we will return an address within
  1213. // b - the region corresponding to the slice being locked, will have valid data there for the whole slice.
  1214. // c - the slice is marked as locked
  1215. // d - the params of the lock request have been saved in the lock table (in the context)
  1216. // so step 1 is unambiguous. If there's no backing storage, make some.
  1217. if (!m_backing)
  1218. {
  1219. if ( gl_pow2_tempmem.GetBool() )
  1220. {
  1221. uint32_t unStoragePow2 = m_layout->m_storageTotalSize;
  1222. // Round up to next power of 2
  1223. unStoragePow2--;
  1224. unStoragePow2 |= unStoragePow2 >> 1;
  1225. unStoragePow2 |= unStoragePow2 >> 2;
  1226. unStoragePow2 |= unStoragePow2 >> 4;
  1227. unStoragePow2 |= unStoragePow2 >> 8;
  1228. unStoragePow2 |= unStoragePow2 >> 16;
  1229. unStoragePow2++;
  1230. m_backing = (char *)calloc( unStoragePow2, 1 );
  1231. }
  1232. else
  1233. {
  1234. m_backing = (char *)calloc( m_layout->m_storageTotalSize, 1 );
  1235. }
  1236. // clear the kSliceStorageValid bit on all slices
  1237. for( int i=0; i<m_layout->m_sliceCount; i++)
  1238. {
  1239. m_sliceFlags[i] &= ~kSliceStorageValid;
  1240. }
  1241. }
  1242. // work on this slice now
  1243. // storage is known to exist at this point, but we need to check if its contents are valid for this slice.
  1244. // this is tracked per-slice so we don't hoist all the texels back out of GL across all slices if caller only
  1245. // wanted to lock some of them.
  1246. // (i.e. if we just alloced it, it's blank)
  1247. // if storage is invalid, but the texture itself is valid, hoist the texels back to the storage and mark it valid.
  1248. // if storage is invalid, and texture itself is also invalid, go ahead and mark storage as valid and fully dirty... to force teximage.
  1249. // ???????????? we need to go over this more carefully re "slice valid" (it has been teximaged) vs "storage valid" (it has been copied out).
  1250. unsigned char *sliceFlags = &m_sliceFlags[ sliceIndex ];
  1251. if (params->m_readback)
  1252. {
  1253. // caller is letting us know that it wants to readback the real texels.
  1254. *sliceFlags |= kSliceStorageValid;
  1255. *sliceFlags |= kSliceValid;
  1256. *sliceFlags &= ~(kSliceFullyDirty);
  1257. copyout = true;
  1258. }
  1259. else
  1260. {
  1261. // caller is pushing texels.
  1262. if (! (*sliceFlags & kSliceStorageValid) )
  1263. {
  1264. // storage is invalid. check texture state
  1265. if ( *sliceFlags & kSliceValid )
  1266. {
  1267. // kSliceValid set: the texture itself has a valid slice, but we don't have it in our backing copy, so copy it out.
  1268. copyout = true;
  1269. }
  1270. else
  1271. {
  1272. // kSliceValid not set: the texture does not have a valid slice to copy out - it hasn't been teximage'd yet.
  1273. // set the "full dirty" bit to make sure we teximage the whole thing on unlock.
  1274. *sliceFlags |= kSliceFullyDirty;
  1275. // assert if they did not ask to lock the full slice size on this go-round
  1276. if (partial)
  1277. {
  1278. // choice here -
  1279. // 1 - stop cold, we don't know how to subimage yet.
  1280. // 2 - grin and bear it, mark whole slice dirty (ah, we already did... so, do nothing).
  1281. // choice 2: // GLMStop();
  1282. }
  1283. }
  1284. // one way or another, upon reaching here the slice storage is valid for read.
  1285. *sliceFlags |= kSliceStorageValid;
  1286. }
  1287. }
  1288. // when we arrive here, there is storage, and the content of the storage for this slice is valid
  1289. // (or zeroes if it's the first lock)
  1290. // log the lock request in the context.
  1291. int newdesc = m_ctx->m_texLocks.AddToTail();
  1292. GLMTexLockDesc *desc = &m_ctx->m_texLocks[newdesc];
  1293. desc->m_req = *params;
  1294. desc->m_active = true;
  1295. desc->m_sliceIndex = sliceIndex;
  1296. desc->m_sliceBaseOffset = m_layout->m_slices[sliceIndex].m_storageOffset;
  1297. // to calculate the additional offset we need to look at the rect's min corner
  1298. // combined with the per-texel size and Y/Z stride
  1299. // also cross check it for 4x multiple if there is compression in play
  1300. int offsetInSlice = 0;
  1301. int yStride = 0;
  1302. int zStride = 0;
  1303. CalcTexelDataOffsetAndStrides( sliceIndex, params->m_region.xmin, params->m_region.ymin, params->m_region.zmin, &offsetInSlice, &yStride, &zStride );
  1304. // for compressed case...
  1305. // since there is presently no way to texsubimage a DXT when the rect does not cover the whole width,
  1306. // we will probably need to inflate the dirty rect in the recorded lock req so that the entire span is
  1307. // pushed across at unlock time.
  1308. desc->m_sliceRegionOffset = offsetInSlice + desc->m_sliceBaseOffset;
  1309. if (copyout)
  1310. {
  1311. // read the whole slice
  1312. // (odds are we'll never request anything but a whole slice to be read..)
  1313. ReadTexels( desc, true );
  1314. } // this would be a good place to fill with scrub value if in debug...
  1315. *addressOut = m_backing + desc->m_sliceRegionOffset;
  1316. *yStrideOut = yStride;
  1317. *zStrideOut = zStride;
  1318. m_lockCount++;
  1319. }
  1320. void CGLMTex::Unlock( GLMTexLockParams *params )
  1321. {
  1322. #if GL_TELEMETRY_GPU_ZONES
  1323. CScopedGLMPIXEvent glmPIXEvent( "CGLMTex::Unlock" );
  1324. g_TelemetryGPUStats.m_nTotalTexLocksAndUnlocks++;
  1325. #endif
  1326. // look for an active lock request on this face and mip (doesn't necessarily matter which one, if more than one)
  1327. // and mark it inactive.
  1328. // --> if you can't find one, fail. first line of defense against mismatched locks/unlocks..
  1329. int i=0;
  1330. bool found = false;
  1331. while( !found && (i<m_ctx->m_texLocks.Count()) )
  1332. {
  1333. GLMTexLockDesc *desc = &m_ctx->m_texLocks[i];
  1334. // is lock at index 'i' targeted at the texture/face/mip in question?
  1335. if ( (desc->m_req.m_tex == this) && (desc->m_req.m_face == params->m_face) & (desc->m_req.m_mip == params->m_mip) && (desc->m_active) )
  1336. {
  1337. // matched and active, so retire it
  1338. desc->m_active = false;
  1339. // stop searching
  1340. found = true;
  1341. }
  1342. i++;
  1343. }
  1344. if (!found)
  1345. {
  1346. GLMStop(); // bad news
  1347. }
  1348. // found - so drop lock count
  1349. m_lockCount--;
  1350. if (m_lockCount <0)
  1351. {
  1352. GLMStop(); // bad news
  1353. }
  1354. if (m_lockCount==0)
  1355. {
  1356. // there should not be any active locks remaining on this texture.
  1357. // motivation to defer all texel pushing til *all* open locks are closed out -
  1358. // if/when we back the texture with a PBO, we will need to unmap that PBO before teximaging from it;
  1359. // by waiting for all the locks to clear this gives us an unambiguous signal to act on.
  1360. // scan through all the retired locks for this texture and push the texels for each one.
  1361. // after each one is dispatched, remove it from the pile.
  1362. int j=0;
  1363. while( j<m_ctx->m_texLocks.Count() )
  1364. {
  1365. GLMTexLockDesc *desc = &m_ctx->m_texLocks[j];
  1366. if ( desc->m_req.m_tex == this )
  1367. {
  1368. // if it's active, something is wrong
  1369. if (desc->m_active)
  1370. {
  1371. GLMStop();
  1372. }
  1373. // write the texels
  1374. bool fullyDirty = false;
  1375. fullyDirty |= ((m_sliceFlags[ desc->m_sliceIndex ] & kSliceFullyDirty) != 0);
  1376. // this is not optimal and will result in full downloads on any dirty.
  1377. // we're papering over the fact that subimage isn't done yet.
  1378. // but this is safe if the slice of storage is all valid.
  1379. // at some point we'll need to actually compare the lock box against the slice bounds.
  1380. // fullyDirty |= (m_sliceFlags[ desc->m_sliceIndex ] & kSliceStorageValid);
  1381. WriteTexels( desc, fullyDirty );
  1382. // logical place to trigger preloading
  1383. // only do it for an RT tex, if it is not yet attached to any FBO.
  1384. // also, only do it if the slice number is the last slice in the tex.
  1385. if ( desc->m_sliceIndex == (m_layout->m_sliceCount-1) )
  1386. {
  1387. if ( !(m_layout->m_key.m_texFlags & kGLMTexRenderable) || (m_rtAttachCount==0) )
  1388. {
  1389. m_ctx->PreloadTex( this );
  1390. // printf("( slice %d of %d )", desc->m_sliceIndex, m_layout->m_sliceCount );
  1391. }
  1392. }
  1393. m_ctx->m_texLocks.FastRemove( j ); // remove from the pile, don't advance index
  1394. }
  1395. else
  1396. {
  1397. j++; // move on to next one
  1398. }
  1399. }
  1400. // clear the locked and full-dirty flags for all slices
  1401. for( int slice=0; slice < m_layout->m_sliceCount; slice++)
  1402. {
  1403. m_sliceFlags[slice] &= ~( kSliceLocked | kSliceFullyDirty );
  1404. }
  1405. // The 3D texture upload code seems to rely on the host copy, probably
  1406. // because it reuploads the whole thing each slice; we only use 3D textures
  1407. // for the 32x32x32 colorpsace conversion lookups and debugging the problem
  1408. // would not save any more memory.
  1409. if ( !m_texClientStorage && ( m_texGLTarget == GL_TEXTURE_2D ) )
  1410. {
  1411. free(m_backing);
  1412. m_backing = NULL;
  1413. }
  1414. }
  1415. }
  1416. #if defined( OSX )
  1417. void CGLMTex::HandleSRGBMismatch( bool srgb, int &srgbFlipCount )
  1418. {
  1419. bool srgbCapableTex = false; // not yet known
  1420. bool renderableTex = false; // not yet known.
  1421. srgbCapableTex = m_layout->m_format->m_glIntFormatSRGB != 0;
  1422. renderableTex = ( m_layout->m_key.m_texFlags & kGLMTexRenderable ) != 0;
  1423. // we can fix it if it's not a renderable, and an sRGB enabled format variation is available.
  1424. if ( srgbCapableTex && !renderableTex )
  1425. {
  1426. char *texname = m_debugLabel;
  1427. if (!texname) texname = "-";
  1428. m_srgbFlipCount++;
  1429. #if GLMDEBUG
  1430. //policy: print the ones that have flipped 1 or N times
  1431. static bool print_allflips = CommandLine()->FindParm("-glmspewallsrgbflips");
  1432. static bool print_firstflips = CommandLine()->FindParm("-glmspewfirstsrgbflips");
  1433. static bool print_freqflips = CommandLine()->FindParm("-glmspewfreqsrgbflips");
  1434. static bool print_crawls = CommandLine()->FindParm("-glmspewsrgbcrawls");
  1435. static bool print_maxcrawls = CommandLine()->FindParm("-glmspewsrgbmaxcrawls");
  1436. bool print_it = false;
  1437. if (print_allflips)
  1438. {
  1439. print_it = true;
  1440. }
  1441. if (print_firstflips) // report on first flip
  1442. {
  1443. print_it |= m_srgbFlipCount==1;
  1444. }
  1445. if (print_freqflips) // report on 50th flip
  1446. {
  1447. print_it |= m_srgbFlipCount==50;
  1448. }
  1449. if ( print_it )
  1450. {
  1451. char *formatStr;
  1452. formatStr = "srgb change (samp=%d): tex '%-30s' %08x %s (srgb=%d, %d times)";
  1453. if (strlen(texname) >= 30)
  1454. {
  1455. formatStr = "srgb change (samp=%d): tex '%s' %08x %s (srgb=%d, %d times)";
  1456. }
  1457. printf( "\n" );
  1458. printf( formatStr, index, texname, m_layout->m_layoutSummary, (int)srgb, m_srgbFlipCount );
  1459. #ifdef POSIX
  1460. if (print_crawls)
  1461. {
  1462. static char *interesting_crawl_substrs[] = { "CShader::OnDrawElements", NULL }; // add more as needed
  1463. CStackCrawlParams cp;
  1464. memset( &cp, 0, sizeof(cp) );
  1465. cp.m_frameLimit = 20;
  1466. g_pLauncherMgr->GetStackCrawl(&cp);
  1467. for( int i=0; i< cp.m_frameCount; i++)
  1468. {
  1469. // for each row of crawl, decide if name is interesting
  1470. bool hit = print_maxcrawls;
  1471. for( char **match = interesting_crawl_substrs; (!hit) && (*match != NULL); match++)
  1472. {
  1473. if (strstr(cp.m_crawlNames[i], *match))
  1474. {
  1475. hit = true;
  1476. }
  1477. }
  1478. if (hit)
  1479. {
  1480. printf( "\n\t%s", cp.m_crawlNames[i] );
  1481. }
  1482. }
  1483. printf( "\n");
  1484. }
  1485. #endif
  1486. }
  1487. #endif // GLMDEBUG
  1488. #if GLMDEBUG && 0
  1489. //"toi" = texture of interest
  1490. static char s_toi[256] = "colorcorrection";
  1491. if (strstr( texname, s_toi ))
  1492. {
  1493. // breakpoint on this if you like
  1494. GLMPRINTF(( "srgb change %d for %s", m_srgbFlipCount, texname ));
  1495. }
  1496. #endif
  1497. // re-submit the tex unless we're stifling it
  1498. static bool s_nosrgbflips = CommandLine()->FindParm( "-glmnosrgbflips" );
  1499. if ( !s_nosrgbflips )
  1500. {
  1501. ResetSRGB( srgb, false );
  1502. }
  1503. }
  1504. else
  1505. {
  1506. //GLMPRINTF(("-Z- srgb sampling conflict: NOT fixing tex %08x [%s] (srgb req: %d) because (tex-srgb-capable=%d tex-renderable=%d)", m_textures[index], m_textures[index]->m_tex->m_layout->m_layoutSummary, (int)glsamp->m_srgb, (int)srgbCapableTex, (int)renderableTex ));
  1507. // we just leave the sampler state where it is, and that's life
  1508. }
  1509. }
  1510. void CGLMTex::ResetSRGB( bool srgb, bool noDataWrite )
  1511. {
  1512. // see if requested SRGB state differs from the known one
  1513. bool wasSRGB = (m_layout->m_key.m_texFlags & kGLMTexSRGB);
  1514. GLMTexLayout *oldLayout = m_layout; // need to m_ctx->m_texLayoutTable->DelLayoutRef on this one if we flip
  1515. if (srgb != wasSRGB)
  1516. {
  1517. // we're going to need a new layout (though the storage size should be the same - check it)
  1518. GLMTexLayoutKey newKey = m_layout->m_key;
  1519. newKey.m_texFlags &= (~kGLMTexSRGB); // turn off that bit
  1520. newKey.m_texFlags |= srgb ? kGLMTexSRGB : 0; // turn on that bit if it should be so
  1521. // get new layout
  1522. GLMTexLayout *newLayout = m_ctx->m_texLayoutTable->NewLayoutRef( &newKey );
  1523. // if SRGB requested, verify that the layout we just got can do it.
  1524. // if it can't, delete the new layout ref and bail.
  1525. if (srgb && (newLayout->m_format->m_glIntFormatSRGB == 0))
  1526. {
  1527. Assert( !"Can't enable SRGB mode on this format" );
  1528. m_ctx->m_texLayoutTable->DelLayoutRef( newLayout );
  1529. return;
  1530. }
  1531. // check sizes and fail if no match
  1532. if( newLayout->m_storageTotalSize != oldLayout->m_storageTotalSize )
  1533. {
  1534. Assert( !"Bug: layout sizes don't match on SRGB change" );
  1535. m_ctx->m_texLayoutTable->DelLayoutRef( newLayout );
  1536. return;
  1537. }
  1538. // commit to new layout
  1539. m_layout = newLayout;
  1540. m_texGLTarget = m_layout->m_key.m_texGLTarget;
  1541. // check same size
  1542. Assert( m_layout->m_storageTotalSize == oldLayout->m_storageTotalSize );
  1543. Assert( newLayout != oldLayout );
  1544. // release old
  1545. m_ctx->m_texLayoutTable->DelLayoutRef( oldLayout );
  1546. oldLayout = NULL;
  1547. // force texel re-DL
  1548. // note this messes with TMU 0 as side effect of WriteTexels
  1549. // so we save and restore the TMU 0 binding first
  1550. // since we're likely to be called in dxabstract when it is syncing sampler state, we can't go trampling the bindings.
  1551. // a refinement would be to have each texture make a note of which TMU they're bound on, and just use that active TMU for DL instead of 0.
  1552. CGLMTex *tmu0save = m_ctx->m_samplers[0].m_pBoundTex;
  1553. for( int face=0; face <m_layout->m_faceCount; face++)
  1554. {
  1555. for( int mip=0; mip <m_layout->m_mipCount; mip++)
  1556. {
  1557. // we're not really going to lock, we're just going to rewrite the orig data
  1558. GLMTexLockDesc desc;
  1559. desc.m_req.m_tex = this;
  1560. desc.m_req.m_face = face;
  1561. desc.m_req.m_mip = mip;
  1562. desc.m_sliceIndex = CalcSliceIndex( face, mip );
  1563. GLMTexLayoutSlice *slice = &m_layout->m_slices[ desc.m_sliceIndex ];
  1564. desc.m_req.m_region.xmin = desc.m_req.m_region.ymin = desc.m_req.m_region.zmin = 0;
  1565. desc.m_req.m_region.xmax = slice->m_xSize;
  1566. desc.m_req.m_region.ymax = slice->m_ySize;
  1567. desc.m_req.m_region.zmax = slice->m_zSize;
  1568. desc.m_sliceBaseOffset = slice->m_storageOffset; // doesn't really matter... we're just pushing zeroes..
  1569. desc.m_sliceRegionOffset = 0;
  1570. WriteTexels( &desc, true, noDataWrite ); // write whole slice. and avoid pushing real bits if the caller requests (RT's)
  1571. }
  1572. }
  1573. // put it back
  1574. m_ctx->BindTexToTMU( tmu0save, 0 );
  1575. }
  1576. }
  1577. #endif
  1578. bool CGLMTex::IsRBODirty() const
  1579. {
  1580. return m_nLastResolvedBatchCounter != m_ctx->m_nBatchCounter;
  1581. }
  1582. void CGLMTex::ForceRBONonDirty()
  1583. {
  1584. m_nLastResolvedBatchCounter = m_ctx->m_nBatchCounter;
  1585. }
  1586. void CGLMTex::ForceRBODirty()
  1587. {
  1588. m_nLastResolvedBatchCounter = m_ctx->m_nBatchCounter - 1;
  1589. }