Source code of Windows XP (NT5)
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.

457 lines
16 KiB

  1. /*****************************************************************************\
  2. FILE: texture.cpp
  3. DESCRIPTION:
  4. Manage a texture for several instance for each monitor. Also manage keeping the
  5. ratio correct when it's not square when loaded.
  6. BryanSt 2/9/2000
  7. Copyright (C) Microsoft Corp 2000-2001. All rights reserved.
  8. \*****************************************************************************/
  9. #include "stdafx.h"
  10. #include "texture.h"
  11. #include "util.h"
  12. int g_nTotalTexturesLoaded = 0;
  13. int g_nTexturesRenderedInThisFrame = 0;
  14. CTexture::CTexture(CMSLogoDXScreenSaver * pMain, LPCTSTR pszPath, LPVOID pvBits, DWORD cbSize)
  15. {
  16. _Init(pMain);
  17. Str_SetPtr(&m_pszPath, pszPath);
  18. m_pvBits = pvBits;
  19. m_cbSize = cbSize;
  20. }
  21. CTexture::CTexture(CMSLogoDXScreenSaver * pMain, LPCTSTR pszPath, LPCTSTR pszResource, float fScale)
  22. {
  23. _Init(pMain);
  24. Str_SetPtr(&m_pszPath, pszPath);
  25. Str_SetPtr(&m_pszResource, pszResource);
  26. m_fScale = fScale;
  27. }
  28. CTexture::~CTexture()
  29. {
  30. Str_SetPtr(&m_pszResource, NULL);
  31. Str_SetPtr(&m_pszPath, NULL);
  32. if (m_pvBits)
  33. {
  34. LocalFree(m_pvBits);
  35. m_pvBits = NULL;
  36. m_cbSize = 0;
  37. }
  38. for (int nIndex = 0; nIndex < ARRAYSIZE(m_pTexture); nIndex++)
  39. {
  40. if (m_pTexture[nIndex])
  41. {
  42. SAFE_RELEASE(m_pTexture[nIndex]);
  43. g_nTotalTexturesLoaded--;
  44. }
  45. }
  46. m_pMain = NULL;
  47. }
  48. void CTexture::_Init(CMSLogoDXScreenSaver * pMain)
  49. {
  50. m_pszResource = NULL;
  51. m_fScale = 1.0f;
  52. m_pszPath = NULL;
  53. m_pvBits = NULL;
  54. m_cbSize = 0;
  55. m_dxImageInfo.Width = 0;
  56. m_dxImageInfo.Height = 0;
  57. m_dxImageInfo.Depth = 0;
  58. m_dxImageInfo.MipLevels = 0;
  59. m_dxImageInfo.Format = D3DFMT_UNKNOWN;
  60. for (int nIndex = 0; nIndex < ARRAYSIZE(m_pTexture); nIndex++)
  61. {
  62. m_pTexture[nIndex] = NULL;
  63. }
  64. m_cRef = 1;
  65. m_pMain = pMain;
  66. }
  67. BOOL CTexture::IsLoadedInAnyDevice(void)
  68. {
  69. BOOL fIsLoaded = FALSE;
  70. for (int nIndex = 0; nIndex < ARRAYSIZE(m_pTexture); nIndex++)
  71. {
  72. if (m_pTexture[nIndex])
  73. {
  74. fIsLoaded = TRUE;
  75. break;
  76. }
  77. }
  78. return fIsLoaded;
  79. }
  80. BOOL CTexture::IsLoadedForThisDevice(void)
  81. {
  82. BOOL fIsLoaded = FALSE;
  83. if (m_pMain)
  84. {
  85. int nCurrMonitor = m_pMain->GetCurrMonitorIndex();
  86. if (m_pTexture[nCurrMonitor])
  87. {
  88. fIsLoaded = TRUE;
  89. }
  90. }
  91. return fIsLoaded;
  92. }
  93. HRESULT CTexture::_GetPictureInfo(HRESULT hr, LPTSTR pszString, DWORD cchSize)
  94. {
  95. int nCurrMonitor = m_pMain->GetCurrMonitorIndex();
  96. StrCpyN(pszString, TEXT("<NoInfo>"), cchSize);
  97. if (SUCCEEDED(hr) && m_pTexture[nCurrMonitor] && m_pMain)
  98. {
  99. D3DSURFACE_DESC d3dSurfaceDesc;
  100. if (SUCCEEDED(m_pTexture[nCurrMonitor]->GetLevelDesc(0, &d3dSurfaceDesc)))
  101. {
  102. wnsprintf(pszString, cchSize, TEXT("Size Orig=<%d,%d> Now=<%d,%d>"),
  103. m_dxImageInfo.Width, m_dxImageInfo.Height, d3dSurfaceDesc.Width, d3dSurfaceDesc.Height);
  104. }
  105. }
  106. return S_OK;
  107. }
  108. BOOL CTexture::_DoesImageNeedClipping(int * pnNewWidth, int * pnNewHeight)
  109. {
  110. BOOL fClip = FALSE;
  111. *pnNewWidth = 512;
  112. *pnNewHeight = 512;
  113. if (m_pMain)
  114. {
  115. int nScreenWidth;
  116. int nScreenHeight;
  117. int nCurrMonitor = m_pMain->GetCurrMonitorIndex();
  118. D3DSURFACE_DESC d3dSurfaceDesc;
  119. if (FAILED(m_pMain->GetCurrentScreenSize(&nScreenWidth, &nScreenHeight)))
  120. {
  121. nScreenWidth = 800; // Fall back values
  122. nScreenHeight = 600;
  123. }
  124. if (!m_pTexture[nCurrMonitor] ||
  125. FAILED(m_pTexture[nCurrMonitor]->GetLevelDesc(0, &d3dSurfaceDesc)))
  126. {
  127. d3dSurfaceDesc.Width = 800; // default values
  128. d3dSurfaceDesc.Height = 800; // default values
  129. }
  130. int nCapWidth = 256;
  131. int nCapHeight = 256;
  132. if (d3dSurfaceDesc.Width > 256)
  133. {
  134. if (d3dSurfaceDesc.Width > 300)
  135. {
  136. nCapWidth = 512;
  137. if (d3dSurfaceDesc.Width > 512)
  138. {
  139. if (d3dSurfaceDesc.Width > 640) // 615 is 20% larger than 512
  140. {
  141. nCapWidth = 1024;
  142. if (d3dSurfaceDesc.Width > 1024) // 615 is 20% larger than 512
  143. {
  144. fClip = TRUE; // We don't want it any larger than this
  145. }
  146. }
  147. else
  148. {
  149. fClip = TRUE; // We are forcing it down to 512
  150. }
  151. }
  152. }
  153. else
  154. {
  155. fClip = TRUE; // We are forcing it down to 256
  156. }
  157. }
  158. if (d3dSurfaceDesc.Height > 256)
  159. {
  160. if (d3dSurfaceDesc.Height > 300)
  161. {
  162. nCapHeight = 512;
  163. if (d3dSurfaceDesc.Height > 512)
  164. {
  165. if (d3dSurfaceDesc.Height > 640) // 615 is 20% larger than 512
  166. {
  167. nCapHeight = 1024;
  168. if (d3dSurfaceDesc.Height > 1024) // 615 is 20% larger than 512
  169. {
  170. fClip = TRUE; // We don't want it any larger than this
  171. }
  172. }
  173. else
  174. {
  175. fClip = TRUE; // We are forcing it down to 512
  176. }
  177. }
  178. }
  179. else
  180. {
  181. fClip = TRUE; // We are forcing it down to 256
  182. }
  183. }
  184. if ((FALSE == fClip) && m_pMain->UseSmallImages())
  185. {
  186. // The caller wants to make sure we don't use anything larger than 512.
  187. if (512 < nCapHeight)
  188. {
  189. nCapHeight = 512;
  190. fClip = TRUE;
  191. }
  192. if (512 < nCapWidth)
  193. {
  194. nCapWidth = 512;
  195. fClip = TRUE;
  196. }
  197. }
  198. *pnNewWidth = nCapWidth;
  199. *pnNewHeight = nCapHeight;
  200. }
  201. return fClip;
  202. }
  203. IDirect3DTexture8 * CTexture::GetTexture(float * pfScale)
  204. {
  205. IDirect3DTexture8 * pTexture = NULL;
  206. HRESULT hr = E_FAIL;
  207. TCHAR szPictureInfo[MAX_PATH];
  208. if (pfScale)
  209. {
  210. *pfScale = m_fScale;
  211. }
  212. // PERF NOTES: Often the background thread will only spend 107ms to load the file (ReadFile)
  213. // but it will take the forground thread 694ms in D3DXCreateTextureFromFileInMemoryEx to
  214. // load and decode the file. This is because more memory is needed after the file is finished
  215. // being compressed and it takes a while to decompress. After this, if the image is too large,
  216. // it will need to call D3DXCreateTextureFromFileInMemoryEx in order to load it into a smaller
  217. // size, which will take 902ms.
  218. // TODO: How should we solve this?
  219. if (m_pMain)
  220. {
  221. int nCurrMonitor = m_pMain->GetCurrMonitorIndex();
  222. pTexture = m_pTexture[nCurrMonitor];
  223. if (!pTexture) // Cache is empty, so populate it.
  224. {
  225. if (m_pvBits)
  226. {
  227. DebugStartWatch();
  228. hr = D3DXCreateTextureFromFileInMemoryEx(m_pMain->GetD3DDevice(), m_pvBits, m_cbSize,
  229. D3DX_DEFAULT /* Size X*/, D3DX_DEFAULT /* Size Y*/, 5/*MIP Levels*/, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_FILTER_LINEAR,
  230. D3DX_FILTER_BOX, 0, &m_dxImageInfo, NULL,
  231. &(m_pTexture[nCurrMonitor]));
  232. _GetPictureInfo(hr, szPictureInfo, ARRAYSIZE(szPictureInfo));
  233. DXUtil_Trace(TEXT("PICTURE: It took %d ms for D3DXCreateTextureFromFileInMemoryEx(\"%ls\"). %s hr=%#08lx\n"), DebugStopWatch(), m_pszPath, szPictureInfo, hr);
  234. if (SUCCEEDED(hr))
  235. {
  236. int nNewWidth;
  237. int nNewHeight;
  238. g_nTotalTexturesLoaded++;
  239. // In order to save memory, we never want to load images over 800x600. If the render surface is small, we want to use
  240. // even smaller max sizes.
  241. if (_DoesImageNeedClipping(&nNewWidth, &nNewHeight))
  242. {
  243. SAFE_RELEASE(m_pTexture[nCurrMonitor]);
  244. g_nTotalTexturesLoaded--;
  245. DebugStartWatch();
  246. // Now we found that we want to re-render the image, but this time shrink it, then we do that now.
  247. hr = D3DXCreateTextureFromFileInMemoryEx(m_pMain->GetD3DDevice(), m_pvBits, m_cbSize,
  248. nNewWidth /* Size X*/, nNewHeight /* Size Y*/, 5/*MIP Levels*/, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_FILTER_LINEAR,
  249. D3DX_FILTER_BOX, 0, &m_dxImageInfo, NULL,
  250. &(m_pTexture[nCurrMonitor]));
  251. _GetPictureInfo(hr, szPictureInfo, ARRAYSIZE(szPictureInfo));
  252. DXUtil_Trace(TEXT("PICTURE: It took %d ms for D3DXCreateTextureFromFileInMemoryEx(\"%ls\") 2nd time. %s hr=%#08lx\n"), DebugStopWatch(), m_pszPath, szPictureInfo, hr);
  253. if (SUCCEEDED(hr))
  254. {
  255. g_nTotalTexturesLoaded++;
  256. }
  257. }
  258. }
  259. }
  260. else
  261. {
  262. // This will give people a chance to customize the images.
  263. if (m_pszPath && PathFileExists(m_pszPath))
  264. {
  265. int nOrigX;
  266. int nOrigY;
  267. DebugStartWatch();
  268. hr = D3DXCreateTextureFromFileEx(m_pMain->GetD3DDevice(), m_pszPath,
  269. D3DX_DEFAULT /* Size X*/, D3DX_DEFAULT /* Size Y*/, 5/*MIP Levels*/, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_FILTER_LINEAR,
  270. D3DX_FILTER_BOX, 0, &m_dxImageInfo, NULL,
  271. &(m_pTexture[nCurrMonitor]));
  272. _GetPictureInfo(hr, szPictureInfo, ARRAYSIZE(szPictureInfo));
  273. DXUtil_Trace(TEXT("PICTURE: It took %d ms for FromFileEx(\"%ls\"). %s hr=%#08lx\n"),
  274. DebugStopWatch(), (PathFindFileName(m_pszPath) ? PathFindFileName(m_pszPath) : m_pszPath), szPictureInfo, hr);
  275. if (SUCCEEDED(hr))
  276. {
  277. int nNewWidth;
  278. int nNewHeight;
  279. g_nTotalTexturesLoaded++;
  280. // In order to save memory, we never want to load images over 800x600. If the render surface is small, we want to use
  281. // even smaller max sizes.
  282. if (_DoesImageNeedClipping(&nNewWidth, &nNewHeight))
  283. {
  284. SAFE_RELEASE(m_pTexture[nCurrMonitor]);
  285. g_nTotalTexturesLoaded--;
  286. DebugStartWatch();
  287. // Now we found that we want to re-render the image, but this time shrink it, then we do that now.
  288. hr = D3DXCreateTextureFromFileEx(m_pMain->GetD3DDevice(), m_pszPath,
  289. nNewWidth /* Size X*/, nNewHeight /* Size Y*/, 5/*MIP Levels*/, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_FILTER_LINEAR,
  290. D3DX_FILTER_BOX, 0, &m_dxImageInfo, NULL,
  291. &(m_pTexture[nCurrMonitor]));
  292. _GetPictureInfo(hr, szPictureInfo, ARRAYSIZE(szPictureInfo));
  293. DXUtil_Trace(TEXT("PICTURE: It took %d ms for FromFileEx(\"%ls\") 2nd time. %s hr=%#08lx\n"),
  294. DebugStopWatch(), (PathFindFileName(m_pszPath) ? PathFindFileName(m_pszPath) : m_pszPath), szPictureInfo, hr);
  295. if (SUCCEEDED(hr))
  296. {
  297. g_nTotalTexturesLoaded++;
  298. }
  299. }
  300. }
  301. else
  302. {
  303. // We failed to load the picture, so it may be a type we don't support,
  304. // like .gif. So stop trying to load it.
  305. Str_SetPtr(&m_pszPath, NULL);
  306. }
  307. }
  308. if (FAILED(hr) && m_pszResource)
  309. {
  310. // Now, let's grab our standard value.
  311. int nMipLevels = 5;
  312. DebugStartWatch();
  313. hr = D3DXCreateTextureFromResourceEx(m_pMain->GetD3DDevice(), HINST_THISDLL, m_pszResource,
  314. D3DX_DEFAULT /* Size X*/, D3DX_DEFAULT /* Size Y*/, nMipLevels/*MIP Levels*/, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_FILTER_LINEAR,
  315. D3DX_FILTER_BOX, 0, &m_dxImageInfo, NULL,
  316. &(m_pTexture[nCurrMonitor]));
  317. _GetPictureInfo(hr, szPictureInfo, ARRAYSIZE(szPictureInfo));
  318. DXUtil_Trace(TEXT("PICTURE: It took %d ms for D3DXCreateTextureFromResourceEx(\"%ls\"). %s hr=%#08lx\n"), DebugStopWatch(), m_pszResource, szPictureInfo, hr);
  319. if (SUCCEEDED(hr))
  320. {
  321. int nNewWidth;
  322. int nNewHeight;
  323. g_nTotalTexturesLoaded++;
  324. // In order to save memory, we never want to load images over 800x600. If the render surface is small, we want to use
  325. // even smaller max sizes.
  326. if (_DoesImageNeedClipping(&nNewWidth, &nNewHeight))
  327. {
  328. SAFE_RELEASE(m_pTexture[nCurrMonitor]);
  329. g_nTotalTexturesLoaded--;
  330. DebugStartWatch();
  331. // Now we found that we want to re-render the image, but this time shrink it, then we do that now.
  332. hr = D3DXCreateTextureFromResourceEx(m_pMain->GetD3DDevice(), HINST_THISDLL, m_pszResource,
  333. nNewWidth /* Size X*/, nNewHeight /* Size Y*/, 5/*MIP Levels*/, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_FILTER_LINEAR,
  334. D3DX_FILTER_BOX, 0, &m_dxImageInfo, NULL,
  335. &(m_pTexture[nCurrMonitor]));
  336. _GetPictureInfo(hr, szPictureInfo, ARRAYSIZE(szPictureInfo));
  337. DXUtil_Trace(TEXT("PICTURE: It took %d ms for D3DXCreateTextureFromResourceEx(\"%ls\") 2nd time. %s hr=%#08lx\n"), DebugStopWatch(), m_pszResource, szPictureInfo, hr);
  338. if (SUCCEEDED(hr))
  339. {
  340. g_nTotalTexturesLoaded++;
  341. }
  342. }
  343. }
  344. else
  345. {
  346. // We failed to load the picture, so it may be a type we don't support,
  347. // like .gif. So stop trying to load it.
  348. Str_SetPtr(&m_pszPath, NULL);
  349. }
  350. }
  351. }
  352. pTexture = m_pTexture[nCurrMonitor];
  353. }
  354. }
  355. return pTexture;
  356. }
  357. //===========================
  358. // *** IUnknown Interface ***
  359. //===========================
  360. ULONG CTexture::AddRef()
  361. {
  362. return InterlockedIncrement(&m_cRef);
  363. }
  364. ULONG CTexture::Release()
  365. {
  366. if (InterlockedDecrement(&m_cRef))
  367. return m_cRef;
  368. delete this;
  369. return 0;
  370. }
  371. HRESULT CTexture::QueryInterface(REFIID riid, void **ppvObj)
  372. {
  373. static const QITAB qit[] =
  374. {
  375. QITABENT(CTexture, IUnknown),
  376. { 0 },
  377. };
  378. return QISearch(this, qit, riid, ppvObj);
  379. }