TextureLoader.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  1. //--------------------------------------------------------------------------------------
  2. // File: WICTextureLoader.cpp
  3. //
  4. // Function for loading a WIC image and creating a Direct3D 11 runtime texture for it
  5. // (auto-generating mipmaps if possible)
  6. //
  7. // Note: Assumes application has already called CoInitializeEx
  8. //
  9. // Warning: CreateWICTexture* functions are not thread-safe if given a d3dContext instance for
  10. // auto-gen mipmap support.
  11. //
  12. // Note these functions are useful for images created as simple 2D textures. For
  13. // more complex resources, DDSTextureLoader is an excellent light-weight runtime loader.
  14. // For a full-featured DDS file reader, writer, and texture processing pipeline see
  15. // the 'Texconv' sample and the 'DirectXTex' library.
  16. //
  17. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  18. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  19. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  20. // PARTICULAR PURPOSE.
  21. //
  22. // Copyright (c) Microsoft Corporation. All rights reserved.
  23. //
  24. // http://go.microsoft.com/fwlink/?LinkId=248926
  25. // http://go.microsoft.com/fwlink/?LinkId=248929
  26. //--------------------------------------------------------------------------------------
  27. // We could load multi-frame images (TIFF/GIF) into a texture array.
  28. // For now, we just load the first frame (note: DirectXTex supports multi-frame images)
  29. #include <dxgiformat.h>
  30. #include <assert.h>
  31. #ifdef _MSC_VER
  32. #pragma warning(push)
  33. #pragma warning(disable : 4005)
  34. #endif // _MSC_VER
  35. #include <wincodec.h>
  36. #ifdef _MSC_VER
  37. #pragma warning(pop)
  38. #endif // _MSC_VER
  39. #include <memory>
  40. #include "TextureLoader.h"
  41. #if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/) && !defined(DXGI_1_2_FORMATS)
  42. #define DXGI_1_2_FORMATS
  43. #endif
  44. //---------------------------------------------------------------------------------
  45. template<class T> class ScopedObject
  46. {
  47. public:
  48. explicit ScopedObject(T *p = 0) : _pointer(p) {}
  49. ~ScopedObject()
  50. {
  51. if (_pointer)
  52. {
  53. _pointer->Release();
  54. _pointer = nullptr;
  55. }
  56. }
  57. bool IsNull() const { return (!_pointer); }
  58. T& operator*() { return *_pointer; }
  59. T* operator->() { return _pointer; }
  60. T** operator&() { return &_pointer; }
  61. void Reset(T *p = 0) { if (_pointer) { _pointer->Release(); } _pointer = p; }
  62. T* Get() const { return _pointer; }
  63. private:
  64. ScopedObject(const ScopedObject&);
  65. ScopedObject& operator=(const ScopedObject&);
  66. T* _pointer;
  67. };
  68. //-------------------------------------------------------------------------------------
  69. // WIC Pixel Format Translation Data
  70. //-------------------------------------------------------------------------------------
  71. struct WICTranslate
  72. {
  73. GUID wic;
  74. DXGI_FORMAT format;
  75. };
  76. static WICTranslate g_WICFormats[] =
  77. {
  78. { GUID_WICPixelFormat128bppRGBAFloat, DXGI_FORMAT_R32G32B32A32_FLOAT },
  79. { GUID_WICPixelFormat64bppRGBAHalf, DXGI_FORMAT_R16G16B16A16_FLOAT },
  80. { GUID_WICPixelFormat64bppRGBA, DXGI_FORMAT_R16G16B16A16_UNORM },
  81. { GUID_WICPixelFormat32bppRGBA, DXGI_FORMAT_R8G8B8A8_UNORM },
  82. { GUID_WICPixelFormat32bppBGRA, DXGI_FORMAT_B8G8R8A8_UNORM }, // DXGI 1.1
  83. { GUID_WICPixelFormat32bppBGR, DXGI_FORMAT_B8G8R8X8_UNORM }, // DXGI 1.1
  84. { GUID_WICPixelFormat32bppRGBA1010102XR, DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM }, // DXGI 1.1
  85. { GUID_WICPixelFormat32bppRGBA1010102, DXGI_FORMAT_R10G10B10A2_UNORM },
  86. { GUID_WICPixelFormat32bppRGBE, DXGI_FORMAT_R9G9B9E5_SHAREDEXP },
  87. #ifdef DXGI_1_2_FORMATS
  88. { GUID_WICPixelFormat16bppBGRA5551, DXGI_FORMAT_B5G5R5A1_UNORM },
  89. { GUID_WICPixelFormat16bppBGR565, DXGI_FORMAT_B5G6R5_UNORM },
  90. #endif // DXGI_1_2_FORMATS
  91. { GUID_WICPixelFormat32bppGrayFloat, DXGI_FORMAT_R32_FLOAT },
  92. { GUID_WICPixelFormat16bppGrayHalf, DXGI_FORMAT_R16_FLOAT },
  93. { GUID_WICPixelFormat16bppGray, DXGI_FORMAT_R16_UNORM },
  94. { GUID_WICPixelFormat8bppGray, DXGI_FORMAT_R8_UNORM },
  95. { GUID_WICPixelFormat8bppAlpha, DXGI_FORMAT_A8_UNORM },
  96. #if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/)
  97. { GUID_WICPixelFormat96bppRGBFloat, DXGI_FORMAT_R32G32B32_FLOAT },
  98. #endif
  99. };
  100. //-------------------------------------------------------------------------------------
  101. // WIC Pixel Format nearest conversion table
  102. //-------------------------------------------------------------------------------------
  103. struct WICConvert
  104. {
  105. GUID source;
  106. GUID target;
  107. };
  108. static WICConvert g_WICConvert[] =
  109. {
  110. // Note target GUID in this conversion table must be one of those directly supported formats (above).
  111. { GUID_WICPixelFormatBlackWhite, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM
  112. { GUID_WICPixelFormat1bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
  113. { GUID_WICPixelFormat2bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
  114. { GUID_WICPixelFormat4bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
  115. { GUID_WICPixelFormat8bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
  116. { GUID_WICPixelFormat2bppGray, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM
  117. { GUID_WICPixelFormat4bppGray, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM
  118. { GUID_WICPixelFormat16bppGrayFixedPoint, GUID_WICPixelFormat16bppGrayHalf }, // DXGI_FORMAT_R16_FLOAT
  119. { GUID_WICPixelFormat32bppGrayFixedPoint, GUID_WICPixelFormat32bppGrayFloat }, // DXGI_FORMAT_R32_FLOAT
  120. #ifdef DXGI_1_2_FORMATS
  121. { GUID_WICPixelFormat16bppBGR555, GUID_WICPixelFormat16bppBGRA5551 }, // DXGI_FORMAT_B5G5R5A1_UNORM
  122. #else
  123. { GUID_WICPixelFormat16bppBGR555, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
  124. { GUID_WICPixelFormat16bppBGRA5551, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
  125. { GUID_WICPixelFormat16bppBGR565, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
  126. #endif // DXGI_1_2_FORMATS
  127. { GUID_WICPixelFormat32bppBGR101010, GUID_WICPixelFormat32bppRGBA1010102 }, // DXGI_FORMAT_R10G10B10A2_UNORM
  128. { GUID_WICPixelFormat24bppBGR, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
  129. { GUID_WICPixelFormat24bppRGB, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
  130. { GUID_WICPixelFormat32bppPBGRA, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
  131. { GUID_WICPixelFormat32bppPRGBA, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
  132. { GUID_WICPixelFormat48bppRGB, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
  133. { GUID_WICPixelFormat48bppBGR, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
  134. { GUID_WICPixelFormat64bppBGRA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
  135. { GUID_WICPixelFormat64bppPRGBA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
  136. { GUID_WICPixelFormat64bppPBGRA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
  137. { GUID_WICPixelFormat48bppRGBFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
  138. { GUID_WICPixelFormat48bppBGRFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
  139. { GUID_WICPixelFormat64bppRGBAFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
  140. { GUID_WICPixelFormat64bppBGRAFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
  141. { GUID_WICPixelFormat64bppRGBFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
  142. { GUID_WICPixelFormat64bppRGBHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
  143. { GUID_WICPixelFormat48bppRGBHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
  144. { GUID_WICPixelFormat96bppRGBFixedPoint, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT
  145. { GUID_WICPixelFormat128bppPRGBAFloat, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT
  146. { GUID_WICPixelFormat128bppRGBFloat, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT
  147. { GUID_WICPixelFormat128bppRGBAFixedPoint, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT
  148. { GUID_WICPixelFormat128bppRGBFixedPoint, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT
  149. { GUID_WICPixelFormat32bppCMYK, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
  150. { GUID_WICPixelFormat64bppCMYK, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
  151. { GUID_WICPixelFormat40bppCMYKAlpha, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
  152. { GUID_WICPixelFormat80bppCMYKAlpha, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
  153. #if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/)
  154. { GUID_WICPixelFormat32bppRGB, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM
  155. { GUID_WICPixelFormat64bppRGB, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM
  156. { GUID_WICPixelFormat64bppPRGBAHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT
  157. #endif
  158. // We don't support n-channel formats
  159. };
  160. //--------------------------------------------------------------------------------------
  161. static IWICImagingFactory* _GetWIC()
  162. {
  163. static IWICImagingFactory* s_Factory = nullptr;
  164. if (s_Factory)
  165. return s_Factory;
  166. HRESULT hr = CoCreateInstance(
  167. CLSID_WICImagingFactory,
  168. nullptr,
  169. CLSCTX_INPROC_SERVER,
  170. __uuidof(IWICImagingFactory),
  171. (LPVOID*)&s_Factory
  172. );
  173. if (FAILED(hr))
  174. {
  175. s_Factory = nullptr;
  176. return nullptr;
  177. }
  178. return s_Factory;
  179. }
  180. //---------------------------------------------------------------------------------
  181. static DXGI_FORMAT _WICToDXGI(const GUID& guid)
  182. {
  183. for (size_t i = 0; i < _countof(g_WICFormats); ++i)
  184. {
  185. if (memcmp(&g_WICFormats[i].wic, &guid, sizeof(GUID)) == 0)
  186. return g_WICFormats[i].format;
  187. }
  188. return DXGI_FORMAT_UNKNOWN;
  189. }
  190. //---------------------------------------------------------------------------------
  191. static size_t _WICBitsPerPixel(REFGUID targetGuid)
  192. {
  193. IWICImagingFactory* pWIC = _GetWIC();
  194. if (!pWIC)
  195. return 0;
  196. ScopedObject<IWICComponentInfo> cinfo;
  197. if (FAILED(pWIC->CreateComponentInfo(targetGuid, &cinfo)))
  198. return 0;
  199. WICComponentType type;
  200. if (FAILED(cinfo->GetComponentType(&type)))
  201. return 0;
  202. if (type != WICPixelFormat)
  203. return 0;
  204. ScopedObject<IWICPixelFormatInfo> pfinfo;
  205. if (FAILED(cinfo->QueryInterface(__uuidof(IWICPixelFormatInfo), reinterpret_cast<void**>(&pfinfo))))
  206. return 0;
  207. UINT bpp;
  208. if (FAILED(pfinfo->GetBitsPerPixel(&bpp)))
  209. return 0;
  210. return bpp;
  211. }
  212. //---------------------------------------------------------------------------------
  213. static HRESULT CreateTextureFromWIC(_In_ ID3D11Device* d3dDevice,
  214. _In_opt_ ID3D11DeviceContext* d3dContext,
  215. _In_ IWICBitmapFrameDecode *frame,
  216. _Out_opt_ ID3D11Resource** texture,
  217. _Out_opt_ ID3D11ShaderResourceView** textureView,
  218. _In_ size_t maxsize)
  219. {
  220. UINT width, height;
  221. HRESULT hr = frame->GetSize(&width, &height);
  222. if (FAILED(hr))
  223. return hr;
  224. assert(width > 0 && height > 0);
  225. if (!maxsize)
  226. {
  227. // This is a bit conservative because the hardware could support larger textures than
  228. // the Feature Level defined minimums, but doing it this way is much easier and more
  229. // performant for WIC than the 'fail and retry' model used by DDSTextureLoader
  230. switch (d3dDevice->GetFeatureLevel())
  231. {
  232. case D3D_FEATURE_LEVEL_9_1:
  233. case D3D_FEATURE_LEVEL_9_2:
  234. maxsize = 2048 /*D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION*/;
  235. break;
  236. case D3D_FEATURE_LEVEL_9_3:
  237. maxsize = 4096 /*D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION*/;
  238. break;
  239. case D3D_FEATURE_LEVEL_10_0:
  240. case D3D_FEATURE_LEVEL_10_1:
  241. maxsize = 8192 /*D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION*/;
  242. break;
  243. default:
  244. maxsize = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
  245. break;
  246. }
  247. }
  248. assert(maxsize > 0);
  249. UINT twidth, theight;
  250. if (width > maxsize || height > maxsize)
  251. {
  252. float ar = static_cast<float>(height) / static_cast<float>(width);
  253. if (width > height)
  254. {
  255. twidth = static_cast<UINT>(maxsize);
  256. theight = static_cast<UINT>(static_cast<float>(maxsize) * ar);
  257. }
  258. else
  259. {
  260. theight = static_cast<UINT>(maxsize);
  261. twidth = static_cast<UINT>(static_cast<float>(maxsize) / ar);
  262. }
  263. assert(twidth <= maxsize && theight <= maxsize);
  264. }
  265. else
  266. {
  267. twidth = width;
  268. theight = height;
  269. }
  270. // Determine format
  271. WICPixelFormatGUID pixelFormat;
  272. hr = frame->GetPixelFormat(&pixelFormat);
  273. if (FAILED(hr))
  274. return hr;
  275. WICPixelFormatGUID convertGUID;
  276. memcpy(&convertGUID, &pixelFormat, sizeof(WICPixelFormatGUID));
  277. size_t bpp = 0;
  278. DXGI_FORMAT format = _WICToDXGI(pixelFormat);
  279. if (format == DXGI_FORMAT_UNKNOWN)
  280. {
  281. for (size_t i = 0; i < _countof(g_WICConvert); ++i)
  282. {
  283. if (memcmp(&g_WICConvert[i].source, &pixelFormat, sizeof(WICPixelFormatGUID)) == 0)
  284. {
  285. memcpy(&convertGUID, &g_WICConvert[i].target, sizeof(WICPixelFormatGUID));
  286. format = _WICToDXGI(g_WICConvert[i].target);
  287. assert(format != DXGI_FORMAT_UNKNOWN);
  288. bpp = _WICBitsPerPixel(convertGUID);
  289. break;
  290. }
  291. }
  292. if (format == DXGI_FORMAT_UNKNOWN)
  293. return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
  294. }
  295. else
  296. {
  297. bpp = _WICBitsPerPixel(pixelFormat);
  298. }
  299. if (!bpp)
  300. return E_FAIL;
  301. // Verify our target format is supported by the current device
  302. // (handles WDDM 1.0 or WDDM 1.1 device driver cases as well as DirectX 11.0 Runtime without 16bpp format support)
  303. UINT support = 0;
  304. hr = d3dDevice->CheckFormatSupport(format, &support);
  305. if (FAILED(hr) || !(support & D3D11_FORMAT_SUPPORT_TEXTURE2D))
  306. {
  307. // Fallback to RGBA 32-bit format which is supported by all devices
  308. memcpy(&convertGUID, &GUID_WICPixelFormat32bppRGBA, sizeof(WICPixelFormatGUID));
  309. format = DXGI_FORMAT_R8G8B8A8_UNORM;
  310. bpp = 32;
  311. }
  312. // Allocate temporary memory for image
  313. size_t rowPitch = (twidth * bpp + 7) / 8;
  314. size_t imageSize = rowPitch * theight;
  315. std::unique_ptr<uint8_t[]> temp(new uint8_t[imageSize]);
  316. // Load image data
  317. if (memcmp(&convertGUID, &pixelFormat, sizeof(GUID)) == 0
  318. && twidth == width
  319. && theight == height)
  320. {
  321. // No format conversion or resize needed
  322. hr = frame->CopyPixels(0, static_cast<UINT>(rowPitch), static_cast<UINT>(imageSize), temp.get());
  323. if (FAILED(hr))
  324. return hr;
  325. }
  326. else if (twidth != width || theight != height)
  327. {
  328. // Resize
  329. IWICImagingFactory* pWIC = _GetWIC();
  330. if (!pWIC)
  331. return E_NOINTERFACE;
  332. ScopedObject<IWICBitmapScaler> scaler;
  333. hr = pWIC->CreateBitmapScaler(&scaler);
  334. if (FAILED(hr))
  335. return hr;
  336. hr = scaler->Initialize(frame, twidth, theight, WICBitmapInterpolationModeFant);
  337. if (FAILED(hr))
  338. return hr;
  339. WICPixelFormatGUID pfScaler;
  340. hr = scaler->GetPixelFormat(&pfScaler);
  341. if (FAILED(hr))
  342. return hr;
  343. if (memcmp(&convertGUID, &pfScaler, sizeof(GUID)) == 0)
  344. {
  345. // No format conversion needed
  346. hr = scaler->CopyPixels(0, static_cast<UINT>(rowPitch), static_cast<UINT>(imageSize), temp.get());
  347. if (FAILED(hr))
  348. return hr;
  349. }
  350. else
  351. {
  352. ScopedObject<IWICFormatConverter> FC;
  353. hr = pWIC->CreateFormatConverter(&FC);
  354. if (FAILED(hr))
  355. return hr;
  356. hr = FC->Initialize(scaler.Get(), convertGUID, WICBitmapDitherTypeErrorDiffusion, 0, 0, WICBitmapPaletteTypeCustom);
  357. if (FAILED(hr))
  358. return hr;
  359. hr = FC->CopyPixels(0, static_cast<UINT>(rowPitch), static_cast<UINT>(imageSize), temp.get());
  360. if (FAILED(hr))
  361. return hr;
  362. }
  363. }
  364. else
  365. {
  366. // Format conversion but no resize
  367. IWICImagingFactory* pWIC = _GetWIC();
  368. if (!pWIC)
  369. return E_NOINTERFACE;
  370. ScopedObject<IWICFormatConverter> FC;
  371. hr = pWIC->CreateFormatConverter(&FC);
  372. if (FAILED(hr))
  373. return hr;
  374. hr = FC->Initialize(frame, convertGUID, WICBitmapDitherTypeErrorDiffusion, 0, 0, WICBitmapPaletteTypeCustom);
  375. if (FAILED(hr))
  376. return hr;
  377. hr = FC->CopyPixels(0, static_cast<UINT>(rowPitch), static_cast<UINT>(imageSize), temp.get());
  378. if (FAILED(hr))
  379. return hr;
  380. }
  381. // See if format is supported for auto-gen mipmaps (varies by feature level)
  382. bool autogen = false;
  383. if (d3dContext != 0 && textureView != 0) // Must have context and shader-view to auto generate mipmaps
  384. {
  385. UINT fmtSupport = 0;
  386. hr = d3dDevice->CheckFormatSupport(format, &fmtSupport);
  387. if (SUCCEEDED(hr) && (fmtSupport & D3D11_FORMAT_SUPPORT_MIP_AUTOGEN))
  388. {
  389. autogen = true;
  390. }
  391. }
  392. // Create texture
  393. D3D11_TEXTURE2D_DESC desc;
  394. desc.Width = twidth;
  395. desc.Height = theight;
  396. desc.MipLevels = (autogen) ? 0 : 1;
  397. desc.ArraySize = 1;
  398. desc.Format = format;
  399. desc.SampleDesc.Count = 1;
  400. desc.SampleDesc.Quality = 0;
  401. desc.Usage = D3D11_USAGE_DEFAULT;
  402. desc.BindFlags = (autogen) ? (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET) : (D3D11_BIND_SHADER_RESOURCE);
  403. desc.CPUAccessFlags = 0;
  404. desc.MiscFlags = (autogen) ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0;
  405. D3D11_SUBRESOURCE_DATA initData;
  406. initData.pSysMem = temp.get();
  407. initData.SysMemPitch = static_cast<UINT>(rowPitch);
  408. initData.SysMemSlicePitch = static_cast<UINT>(imageSize);
  409. ID3D11Texture2D* tex = nullptr;
  410. hr = d3dDevice->CreateTexture2D(&desc, (autogen) ? nullptr : &initData, &tex);
  411. if (SUCCEEDED(hr) && tex != 0)
  412. {
  413. if (textureView != 0)
  414. {
  415. D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc;
  416. memset(&SRVDesc, 0, sizeof(SRVDesc));
  417. SRVDesc.Format = format;
  418. SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
  419. SRVDesc.Texture2D.MipLevels = (autogen) ? -1 : 1;
  420. hr = d3dDevice->CreateShaderResourceView(tex, &SRVDesc, textureView);
  421. if (FAILED(hr))
  422. {
  423. tex->Release();
  424. return hr;
  425. }
  426. if (autogen)
  427. {
  428. assert(d3dContext != 0);
  429. d3dContext->UpdateSubresource(tex, 0, nullptr, temp.get(), static_cast<UINT>(rowPitch), static_cast<UINT>(imageSize));
  430. d3dContext->GenerateMips(*textureView);
  431. }
  432. }
  433. if (texture != 0)
  434. {
  435. *texture = tex;
  436. }
  437. else
  438. {
  439. #if defined(_DEBUG) || defined(PROFILE)
  440. tex->SetPrivateData(WKPDID_D3DDebugObjectName,
  441. sizeof("WICTextureLoader") - 1,
  442. "WICTextureLoader"
  443. );
  444. #endif
  445. tex->Release();
  446. }
  447. }
  448. return hr;
  449. }
  450. //--------------------------------------------------------------------------------------
  451. HRESULT CreateWICTextureFromMemory(_In_ ID3D11Device* d3dDevice,
  452. _In_opt_ ID3D11DeviceContext* d3dContext,
  453. _In_bytecount_(wicDataSize) const uint8_t* wicData,
  454. _In_ size_t wicDataSize,
  455. _Out_opt_ ID3D11Resource** texture,
  456. _Out_opt_ ID3D11ShaderResourceView** textureView,
  457. _In_ size_t maxsize
  458. )
  459. {
  460. if (!d3dDevice || !wicData || (!texture && !textureView))
  461. {
  462. return E_INVALIDARG;
  463. }
  464. if (!wicDataSize)
  465. {
  466. return E_FAIL;
  467. }
  468. #ifdef _M_AMD64
  469. if (wicDataSize > 0xFFFFFFFF)
  470. return HRESULT_FROM_WIN32(ERROR_FILE_TOO_LARGE);
  471. #endif
  472. IWICImagingFactory* pWIC = _GetWIC();
  473. if (!pWIC)
  474. return E_NOINTERFACE;
  475. // Create input stream for memory
  476. ScopedObject<IWICStream> stream;
  477. HRESULT hr = pWIC->CreateStream(&stream);
  478. if (FAILED(hr))
  479. return hr;
  480. hr = stream->InitializeFromMemory(const_cast<uint8_t*>(wicData), static_cast<DWORD>(wicDataSize));
  481. if (FAILED(hr))
  482. return hr;
  483. // Initialize WIC
  484. ScopedObject<IWICBitmapDecoder> decoder;
  485. hr = pWIC->CreateDecoderFromStream(stream.Get(), 0, WICDecodeMetadataCacheOnDemand, &decoder);
  486. if (FAILED(hr))
  487. return hr;
  488. ScopedObject<IWICBitmapFrameDecode> frame;
  489. hr = decoder->GetFrame(0, &frame);
  490. if (FAILED(hr))
  491. return hr;
  492. hr = CreateTextureFromWIC(d3dDevice, d3dContext, frame.Get(), texture, textureView, maxsize);
  493. if (FAILED(hr))
  494. return hr;
  495. #if defined(_DEBUG) || defined(PROFILE)
  496. if (texture != 0 && *texture != 0)
  497. {
  498. (*texture)->SetPrivateData(WKPDID_D3DDebugObjectName,
  499. sizeof("WICTextureLoader") - 1,
  500. "WICTextureLoader"
  501. );
  502. }
  503. if (textureView != 0 && *textureView != 0)
  504. {
  505. (*textureView)->SetPrivateData(WKPDID_D3DDebugObjectName,
  506. sizeof("WICTextureLoader") - 1,
  507. "WICTextureLoader"
  508. );
  509. }
  510. #endif
  511. return hr;
  512. }
  513. //--------------------------------------------------------------------------------------
  514. HRESULT CreateWICTextureFromFile(_In_ ID3D11Device* d3dDevice,
  515. _In_opt_ ID3D11DeviceContext* d3dContext,
  516. _In_z_ const wchar_t* fileName,
  517. _Out_opt_ ID3D11Resource** texture,
  518. _Out_opt_ ID3D11ShaderResourceView** textureView,
  519. _In_ size_t maxsize)
  520. {
  521. if (!d3dDevice || !fileName || (!texture && !textureView))
  522. {
  523. return E_INVALIDARG;
  524. }
  525. IWICImagingFactory* pWIC = _GetWIC();
  526. if (!pWIC)
  527. return E_NOINTERFACE;
  528. // Initialize WIC
  529. ScopedObject<IWICBitmapDecoder> decoder;
  530. HRESULT hr = pWIC->CreateDecoderFromFilename(fileName, 0, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &decoder);
  531. if (FAILED(hr))
  532. return hr;
  533. ScopedObject<IWICBitmapFrameDecode> frame;
  534. hr = decoder->GetFrame(0, &frame);
  535. if (FAILED(hr))
  536. return hr;
  537. hr = CreateTextureFromWIC(d3dDevice, d3dContext, frame.Get(), texture, textureView, maxsize);
  538. if (FAILED(hr))
  539. return hr;
  540. #if defined(_DEBUG) || defined(PROFILE)
  541. if (texture != 0 || textureView != 0)
  542. {
  543. CHAR strFileA[MAX_PATH];
  544. WideCharToMultiByte(CP_ACP,
  545. WC_NO_BEST_FIT_CHARS,
  546. fileName,
  547. -1,
  548. strFileA,
  549. MAX_PATH,
  550. nullptr,
  551. FALSE
  552. );
  553. const CHAR* pstrName = strrchr(strFileA, '\\');
  554. if (!pstrName)
  555. {
  556. pstrName = strFileA;
  557. }
  558. else
  559. {
  560. pstrName++;
  561. }
  562. if (texture != 0 && *texture != 0)
  563. {
  564. (*texture)->SetPrivateData(WKPDID_D3DDebugObjectName,
  565. static_cast<UINT>(strnlen_s(pstrName, MAX_PATH)),
  566. pstrName
  567. );
  568. }
  569. if (textureView != 0 && *textureView != 0)
  570. {
  571. (*textureView)->SetPrivateData(WKPDID_D3DDebugObjectName,
  572. static_cast<UINT>(strnlen_s(pstrName, MAX_PATH)),
  573. pstrName
  574. );
  575. }
  576. }
  577. #endif
  578. return hr;
  579. }