Texture2D.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2011 Lasse Öörni
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. #include "Precompiled.h"
  24. #include "Log.h"
  25. #include "Profiler.h"
  26. #include "Renderer.h"
  27. #include "RendererImpl.h"
  28. #include "ResourceCache.h"
  29. #include "Texture2D.h"
  30. #include "DebugNew.h"
  31. Texture2D::Texture2D(Renderer* renderer, TextureUsage usage, const std::string& name) :
  32. Texture(renderer, name),
  33. mLockedLevel(-1),
  34. mFollowWindowSize(false)
  35. {
  36. mUsage = 0;
  37. if ((usage == TEXTURE_RENDERTARGET) || (usage == TEXTURE_DEPTHSTENCIL))
  38. {
  39. mRenderSurface = new RenderSurface(this);
  40. if (usage == TEXTURE_RENDERTARGET)
  41. mUsage |= D3DUSAGE_RENDERTARGET;
  42. else
  43. mUsage |= D3DUSAGE_DEPTHSTENCIL;
  44. mPool = D3DPOOL_DEFAULT;
  45. // Clamp mode addressing by default, nearest filtering, and mipmaps disabled
  46. mAddressMode[COORD_U] = ADDRESS_CLAMP;
  47. mAddressMode[COORD_V] = ADDRESS_CLAMP;
  48. mFilterMode = FILTER_NEAREST;
  49. mRequestedLevels = 1;
  50. }
  51. else if (usage == TEXTURE_DYNAMIC)
  52. {
  53. mUsage |= D3DUSAGE_DYNAMIC;
  54. mPool = D3DPOOL_DEFAULT;
  55. }
  56. else
  57. mPool = D3DPOOL_MANAGED;
  58. }
  59. Texture2D::~Texture2D()
  60. {
  61. release();
  62. }
  63. void Texture2D::load(Deserializer& source, ResourceCache* cache)
  64. {
  65. if (!mRenderer)
  66. return;
  67. PROFILE(Texture2D_Load);
  68. // If over the texture budget, see if materials can be freed to allow textures to be freed
  69. checkTextureBudget(getTypeStatic(), cache);
  70. SharedPtr<Image> image(new Image());
  71. image->load(source, cache);
  72. // Before actually loading the texture, get optional parameters from an XML description file
  73. loadParameters(cache);
  74. load(image);
  75. }
  76. void Texture2D::onDeviceLost()
  77. {
  78. if ((mPool == D3DPOOL_DEFAULT) || (mFollowWindowSize))
  79. release();
  80. }
  81. void Texture2D::onDeviceReset()
  82. {
  83. if ((mPool == D3DPOOL_DEFAULT) || (mFollowWindowSize))
  84. {
  85. create();
  86. mDataLost = true;
  87. }
  88. }
  89. void Texture2D::setSize(int width, int height, unsigned format)
  90. {
  91. if ((width <= 0) || (height <= 0))
  92. mFollowWindowSize = true;
  93. else
  94. {
  95. mWidth = width;
  96. mHeight = height;
  97. mFollowWindowSize = false;
  98. }
  99. mFormat = format;
  100. create();
  101. }
  102. void Texture2D::load(SharedPtr<Image> image)
  103. {
  104. if (!image)
  105. EXCEPTION("Null image for Texture2D");
  106. unsigned memoryUse = 0;
  107. if (!image->isCompressed())
  108. {
  109. unsigned char* levelData = image->getData();
  110. int levelWidth = image->getWidth();
  111. int levelHeight = image->getHeight();
  112. unsigned components = image->getComponents();
  113. D3DFORMAT format = D3DFMT_UNKNOWN;
  114. // Discard unnecessary mip levels
  115. for (unsigned i = 0; i < mMipsToSkip[sQuality]; ++i)
  116. {
  117. image = image->getNextLevel();
  118. levelData = image->getData();
  119. levelWidth = image->getWidth();
  120. levelHeight = image->getHeight();
  121. }
  122. switch (components)
  123. {
  124. case 1:
  125. format = D3DFMT_L8;
  126. break;
  127. case 2:
  128. format = D3DFMT_A8L8;
  129. break;
  130. case 3:
  131. format = D3DFMT_X8R8G8B8;
  132. break;
  133. case 4:
  134. format = D3DFMT_A8R8G8B8;
  135. break;
  136. }
  137. setSize(levelWidth, levelHeight, format);
  138. // Make sure manual mip creation is never attempted for D3DPOOL_DEFAULT resources
  139. unsigned manualLevels = (mPool == D3DPOOL_DEFAULT) ? 1 : mLevels;
  140. for (unsigned i = 0; i < manualLevels; ++i)
  141. {
  142. D3DLOCKED_RECT hwRect;
  143. lock(i, 0, &hwRect);
  144. memoryUse += levelWidth * levelHeight * components;
  145. for (int y = 0; y < levelHeight; ++y)
  146. {
  147. unsigned char* dest = (unsigned char*)hwRect.pBits + hwRect.Pitch * y;
  148. unsigned char* src = levelData + components * levelWidth * y;
  149. switch (components)
  150. {
  151. case 1:
  152. case 2:
  153. memcpy(dest, src, components * levelWidth);
  154. break;
  155. case 3:
  156. for (int x = 0; x < levelWidth; ++x)
  157. {
  158. *dest++ = src[2]; *dest++ = src[1]; *dest++ = src[0]; *dest++ = 255;
  159. src += 3;
  160. }
  161. break;
  162. case 4:
  163. for (int x = 0; x < levelWidth; ++x)
  164. {
  165. *dest++ = src[2]; *dest++ = src[1]; *dest++ = src[0]; *dest++ = src[3];
  166. src += 4;
  167. }
  168. break;
  169. }
  170. }
  171. if (i < manualLevels - 1)
  172. {
  173. image = image->getNextLevel();
  174. levelData = image->getData();
  175. levelWidth = image->getWidth();
  176. levelHeight = image->getHeight();
  177. }
  178. unlock();
  179. }
  180. }
  181. else
  182. {
  183. int width = image->getWidth();
  184. int height = image->getHeight();
  185. unsigned levels = image->getNumCompressedLevels();
  186. D3DFORMAT format = (D3DFORMAT)getCompressedD3DFormat(image->getCompressedFormat());
  187. unsigned mipsToSkip = mMipsToSkip[sQuality];
  188. if (mipsToSkip >= levels)
  189. mipsToSkip = levels - 1;
  190. while ((mipsToSkip) && ((width / (1 << mipsToSkip) < 4) || (height / (1 << mipsToSkip) < 4)))
  191. --mipsToSkip;
  192. width /= (1 << mipsToSkip);
  193. height /= (1 << mipsToSkip);
  194. setNumLevels(max((int)(levels - mipsToSkip), 1));
  195. setSize(width, height, format);
  196. for (unsigned i = 0; (i < mLevels) && (i < levels - mipsToSkip); ++i)
  197. {
  198. CompressedLevel level = image->getCompressedLevel(i + mipsToSkip);
  199. memoryUse += level.mRows * level.mRowSize;
  200. D3DLOCKED_RECT hwRect;
  201. lock(i, 0, &hwRect);
  202. for (unsigned j = 0; j < level.mRows; ++j)
  203. {
  204. unsigned char* dest = (unsigned char*)hwRect.pBits + hwRect.Pitch * j;
  205. unsigned char* src = level.mData + level.mRowSize * j;
  206. memcpy(dest, src, level.mRowSize);
  207. }
  208. unlock();
  209. }
  210. }
  211. setMemoryUse(memoryUse);
  212. }
  213. void Texture2D::lock(unsigned level, void* rect, void* hwRect)
  214. {
  215. D3DLOCKED_RECT* lockedRect = (D3DLOCKED_RECT*)hwRect;
  216. if (!lockedRect)
  217. EXCEPTION("Null locked rect structure");
  218. if (!mObject)
  219. EXCEPTION("No texture created, can not lock");
  220. if (mLockedLevel != -1)
  221. EXCEPTION("Texture already locked");
  222. DWORD flags = 0;
  223. if ((!rect) && (mPool == D3DPOOL_DEFAULT))
  224. flags |= D3DLOCK_DISCARD;
  225. if (FAILED(((IDirect3DTexture9*)mObject)->LockRect(level, lockedRect, (RECT*)rect, flags)))
  226. EXCEPTION("Could not lock texture");
  227. mLockedLevel = level;
  228. }
  229. void Texture2D::unlock()
  230. {
  231. if (mLockedLevel != -1)
  232. {
  233. ((IDirect3DTexture9*)mObject)->UnlockRect(mLockedLevel);
  234. mLockedLevel = -1;
  235. }
  236. }
  237. void Texture2D::create()
  238. {
  239. release();
  240. if (!mRenderer)
  241. return;
  242. if (mFollowWindowSize)
  243. {
  244. mWidth = mRenderer->getWidth();
  245. mHeight = mRenderer->getHeight();
  246. }
  247. if ((!mWidth) || (!mHeight))
  248. return;
  249. // If using a default pool texture, must generate mipmaps automatically
  250. if ((mPool == D3DPOOL_DEFAULT) && (mRequestedLevels != 1))
  251. mUsage |= D3DUSAGE_AUTOGENMIPMAP;
  252. else
  253. mUsage &= ~D3DUSAGE_AUTOGENMIPMAP;
  254. // If creating a depth stencil texture, and it is not supported, create a depth stencil surface instead
  255. if ((mUsage & D3DUSAGE_DEPTHSTENCIL) && (!mRenderer->getImpl()->checkFormatSupport((D3DFORMAT)mFormat, mUsage, D3DRTYPE_TEXTURE)))
  256. {
  257. if (FAILED(mRenderer->getImpl()->getDevice()->CreateDepthStencilSurface(
  258. mWidth,
  259. mHeight,
  260. (D3DFORMAT)mFormat,
  261. D3DMULTISAMPLE_NONE,
  262. 0,
  263. FALSE,
  264. (IDirect3DSurface9**)&mRenderSurface->mSurface,
  265. 0)))
  266. EXCEPTION("Could not create depth stencil surface");
  267. mLevels = 1;
  268. }
  269. else
  270. {
  271. if (FAILED(mRenderer->getImpl()->getDevice()->CreateTexture(
  272. mWidth,
  273. mHeight,
  274. mRequestedLevels,
  275. mUsage,
  276. (D3DFORMAT)mFormat,
  277. (D3DPOOL)mPool,
  278. (IDirect3DTexture9**)&mObject,
  279. 0)))
  280. EXCEPTION("Could not create texture");
  281. mLevels = ((IDirect3DTexture9*)mObject)->GetLevelCount();
  282. if (mUsage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL))
  283. ((IDirect3DTexture9*)mObject)->GetSurfaceLevel(0, (IDirect3DSurface9**)&mRenderSurface->mSurface);
  284. }
  285. }
  286. void Texture2D::release()
  287. {
  288. if (mObject)
  289. {
  290. if (!mRenderer)
  291. {
  292. LOGWARNING("Renderer has expired, skipping release of Texture2D");
  293. return;
  294. }
  295. unlock();
  296. for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
  297. {
  298. if (mRenderer->getTexture(i) == this)
  299. mRenderer->setTexture(i, 0);
  300. }
  301. if (mRenderSurface)
  302. mRenderSurface->release();
  303. ((IDirect3DTexture9*)mObject)->Release();
  304. mObject = 0;
  305. }
  306. else
  307. {
  308. if (mRenderSurface)
  309. mRenderSurface->release();
  310. }
  311. }