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.

1831 lines
60 KiB

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