gfxD3D11TextureObject.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2015 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "gfx/D3D11/gfxD3D11Device.h"
  23. #include "gfx/D3D11/gfxD3D11TextureObject.h"
  24. #include "platform/profiler.h"
  25. #include "console/console.h"
  26. #ifdef TORQUE_DEBUG
  27. U32 GFXD3D11TextureObject::mTexCount = 0;
  28. #endif
  29. // GFXFormatR8G8B8 has now the same behaviour as GFXFormatR8G8B8X8.
  30. // This is because 24 bit format are now deprecated by microsoft, for data alignment reason there's no changes beetween 24 and 32 bit formats.
  31. // DirectX 10-11 both have 24 bit format no longer.
  32. GFXD3D11TextureObject::GFXD3D11TextureObject( GFXDevice * d, GFXTextureProfile *profile) : GFXTextureObject( d, profile )
  33. {
  34. #ifdef D3D11_DEBUG_SPEW
  35. mTexCount++;
  36. Con::printf("+ texMake %d %x", mTexCount, this);
  37. #endif
  38. mD3DTexture = NULL;
  39. mLocked = false;
  40. mD3DSurface = NULL;
  41. dMemset(&mLockRect, 0, sizeof(mLockRect));
  42. dMemset(&mLockBox, 0, sizeof(mLockBox));
  43. mLockedSubresource = 0;
  44. mDSView = NULL;
  45. mRTView = NULL;
  46. mSRView = NULL;
  47. isManaged = false;
  48. }
  49. GFXD3D11TextureObject::~GFXD3D11TextureObject()
  50. {
  51. kill();
  52. #ifdef D3D11_DEBUG_SPEW
  53. mTexCount--;
  54. Con::printf("+ texkill %d %x", mTexCount, this);
  55. #endif
  56. }
  57. GFXLockedRect *GFXD3D11TextureObject::lock(U32 mipLevel /*= 0*/, RectI *inRect /*= NULL*/)
  58. {
  59. AssertFatal( !mLocked, "GFXD3D11TextureObject::lock - The texture is already locked!" );
  60. if( !mStagingTex ||
  61. mStagingTex->getWidth() != getWidth() ||
  62. mStagingTex->getHeight() != getHeight() ||
  63. mStagingTex->getDepth() != getDepth())
  64. {
  65. if (getDepth() != 0)
  66. {
  67. mStagingTex.set(getWidth(), getHeight(), getDepth(), mFormat, &GFXSystemMemTextureProfile, avar("%s() - mLockTex (line %d)", __FUNCTION__, __LINE__, 0));
  68. }
  69. else
  70. {
  71. mStagingTex.set(getWidth(), getHeight(), mFormat, &GFXSystemMemTextureProfile, avar("%s() - mLockTex (line %d)", __FUNCTION__, __LINE__));
  72. }
  73. }
  74. ID3D11DeviceContext* pContext = D3D11DEVICECONTEXT;
  75. D3D11_MAPPED_SUBRESOURCE mapInfo;
  76. U32 offset = 0;
  77. mLockedSubresource = D3D11CalcSubresource(mipLevel, 0, getMipLevels());
  78. GFXD3D11TextureObject* pD3DStagingTex = (GFXD3D11TextureObject*)&(*mStagingTex);
  79. //map staging texture
  80. HRESULT hr;
  81. bool is3D = mStagingTex->getDepth() != 0;
  82. if (is3D) //3d texture
  83. hr = pContext->Map(pD3DStagingTex->get3DTex(), mLockedSubresource, D3D11_MAP_READ, 0, &mapInfo);
  84. else
  85. hr = pContext->Map(pD3DStagingTex->get2DTex(), mLockedSubresource, D3D11_MAP_READ, 0, &mapInfo);
  86. if (FAILED(hr))
  87. AssertFatal(false, "GFXD3D11TextureObject:lock - failed to map render target resource!");
  88. const U32 width = mTextureSize.x >> mipLevel;
  89. const U32 height = mTextureSize.y >> mipLevel;
  90. const U32 depth = is3D ? mTextureSize.z >> mipLevel : 1;
  91. //calculate locked box region and offset
  92. if (inRect)
  93. {
  94. if ((inRect->point.x + inRect->extent.x > width) || (inRect->point.y + inRect->extent.y > height))
  95. AssertFatal(false, "GFXD3D11TextureObject::lock - Rectangle too big!");
  96. mLockBox.top = inRect->point.y;
  97. mLockBox.left = inRect->point.x;
  98. mLockBox.bottom = inRect->point.y + inRect->extent.y;
  99. mLockBox.right = inRect->point.x + inRect->extent.x;
  100. mLockBox.back = depth;
  101. mLockBox.front = 0;
  102. //calculate offset
  103. offset = inRect->point.x * getFormatByteSize() + inRect->point.y * mapInfo.RowPitch;
  104. }
  105. else
  106. {
  107. mLockBox.top = 0;
  108. mLockBox.left = 0;
  109. mLockBox.bottom = height;
  110. mLockBox.right = width;
  111. mLockBox.back = depth;
  112. mLockBox.front = 0;
  113. }
  114. mLocked = true;
  115. mLockRect.pBits = static_cast<U8*>(mapInfo.pData) + offset;
  116. mLockRect.Pitch = mapInfo.RowPitch;
  117. return (GFXLockedRect*)&mLockRect;
  118. }
  119. void GFXD3D11TextureObject::unlock(U32 mipLevel)
  120. {
  121. AssertFatal( mLocked, "GFXD3D11TextureObject::unlock - Attempting to unlock a surface that has not been locked" );
  122. //profile in the unlock function because all the heavy lifting is done here
  123. PROFILE_START(GFXD3D11TextureObject_lockRT);
  124. ID3D11DeviceContext* pContext = D3D11DEVICECONTEXT;
  125. GFXD3D11TextureObject* pD3DStagingTex = (GFXD3D11TextureObject*)&(*mStagingTex);
  126. bool is3D = mStagingTex->getDepth() != 0;
  127. if (is3D)
  128. {
  129. ID3D11Texture3D* pStagingTex = pD3DStagingTex->get3DTex();
  130. //unmap staging texture
  131. pContext->Unmap(pStagingTex, mLockedSubresource);
  132. //copy lock box region from the staging texture to our regular texture
  133. pContext->CopySubresourceRegion(mD3DTexture, mLockedSubresource, mLockBox.left, mLockBox.top, mLockBox.front, pStagingTex, mLockedSubresource, &mLockBox);
  134. }
  135. else
  136. {
  137. ID3D11Texture2D* pStagingTex = pD3DStagingTex->get2DTex();
  138. //unmap staging texture
  139. pContext->Unmap(pStagingTex, mLockedSubresource);
  140. //copy lock box region from the staging texture to our regular texture
  141. pContext->CopySubresourceRegion(mD3DTexture, mLockedSubresource, mLockBox.left, mLockBox.top, 0, pStagingTex, mLockedSubresource, &mLockBox);
  142. }
  143. PROFILE_END();
  144. mLockedSubresource = 0;
  145. mLocked = false;
  146. }
  147. void GFXD3D11TextureObject::release()
  148. {
  149. SAFE_RELEASE(mSRView);
  150. SAFE_RELEASE(mRTView);
  151. SAFE_RELEASE(mDSView);
  152. SAFE_RELEASE(mD3DTexture);
  153. SAFE_RELEASE(mD3DSurface);
  154. }
  155. void GFXD3D11TextureObject::zombify()
  156. {
  157. // Managed textures are managed by D3D
  158. AssertFatal(!mLocked, "GFXD3D11TextureObject::zombify - Cannot zombify a locked texture!");
  159. if(isManaged)
  160. return;
  161. release();
  162. }
  163. void GFXD3D11TextureObject::resurrect()
  164. {
  165. // Managed textures are managed by D3D
  166. if(isManaged)
  167. return;
  168. static_cast<GFXD3D11TextureManager*>(TEXMGR)->refreshTexture(this);
  169. }
  170. bool GFXD3D11TextureObject::copyToBmp(GBitmap* bmp)
  171. {
  172. if (!bmp)
  173. return false;
  174. // check format limitations
  175. // at the moment we only support RGBA for the source (other 4 byte formats should
  176. // be easy to add though)
  177. AssertFatal(mFormat == GFXFormatR16G16B16A16F || mFormat == GFXFormatR8G8B8A8 || mFormat == GFXFormatR8G8B8A8_LINEAR_FORCE || mFormat == GFXFormatR8G8B8A8_SRGB, "copyToBmp: invalid format");
  178. if (mFormat != GFXFormatR16G16B16A16F && mFormat != GFXFormatR8G8B8A8 && mFormat != GFXFormatR8G8B8A8_LINEAR_FORCE && mFormat != GFXFormatR8G8B8A8_SRGB)
  179. return false;
  180. PROFILE_START(GFXD3D11TextureObject_copyToBmp);
  181. AssertFatal(bmp->getWidth() == getWidth(), "GFXD3D11TextureObject::copyToBmp - source/dest width does not match");
  182. AssertFatal(bmp->getHeight() == getHeight(), "GFXD3D11TextureObject::copyToBmp - source/dest height does not match");
  183. const U32 mipLevels = getMipLevels();
  184. bmp->setHasTransparency(mHasTransparency);
  185. // set some constants
  186. U32 sourceBytesPerPixel = 4;
  187. U32 destBytesPerPixel = 0;
  188. const GFXFormat fmt = bmp->getFormat();
  189. bool fp16 = false;//is rgba16f format?
  190. if (fmt == GFXFormatR16G16B16A16F)
  191. {
  192. destBytesPerPixel = 8;
  193. sourceBytesPerPixel = 8;
  194. fp16 = true;
  195. }
  196. else if (fmt == GFXFormatR8G8B8A8 || fmt == GFXFormatR8G8B8A8_LINEAR_FORCE || fmt == GFXFormatR8G8B8A8_SRGB)
  197. destBytesPerPixel = 4;
  198. else if(bmp->getFormat() == GFXFormatR8G8B8)
  199. destBytesPerPixel = 3;
  200. else
  201. // unsupported
  202. AssertFatal(false, "GFXD3D11TextureObject::copyToBmp - unsupported bitmap format");
  203. //create temp staging texture
  204. D3D11_TEXTURE2D_DESC desc;
  205. static_cast<ID3D11Texture2D*>(mD3DTexture)->GetDesc(&desc);
  206. desc.BindFlags = 0;
  207. desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
  208. desc.Usage = D3D11_USAGE_STAGING;
  209. ID3D11Texture2D* pStagingTexture = NULL;
  210. HRESULT hr = D3D11DEVICE->CreateTexture2D(&desc, NULL, &pStagingTexture);
  211. if (FAILED(hr))
  212. {
  213. Con::errorf("GFXD3D11TextureObject::copyToBmp - Failed to create staging texture");
  214. return false;
  215. }
  216. //copy the classes texture to the staging texture
  217. D3D11DEVICECONTEXT->CopyResource(pStagingTexture, mD3DTexture);
  218. for (U32 mip = 0; mip < mipLevels; mip++)
  219. {
  220. const U32 width = bmp->getWidth(mip);
  221. const U32 height = bmp->getHeight(mip);
  222. //map the staging resource
  223. D3D11_MAPPED_SUBRESOURCE mappedRes;
  224. const U32 subResource = D3D11CalcSubresource(mip, 0, mipLevels);
  225. hr = D3D11DEVICECONTEXT->Map(pStagingTexture, subResource, D3D11_MAP_READ, 0, &mappedRes);
  226. if (FAILED(hr))
  227. {
  228. //cleanup
  229. SAFE_RELEASE(pStagingTexture);
  230. Con::errorf("GFXD3D11TextureObject::copyToBmp - Failed to map staging texture");
  231. return false;
  232. }
  233. // set pointers
  234. const U8* srcPtr = (U8*)mappedRes.pData;
  235. U8* destPtr = bmp->getWritableBits(mip);
  236. // we will want to skip over any D3D cache data in the source texture
  237. const S32 sourceCacheSize = mappedRes.RowPitch - width * sourceBytesPerPixel;
  238. AssertFatal(sourceCacheSize >= 0, "GFXD3D11TextureObject::copyToBmp - cache size is less than zero?");
  239. // copy data into bitmap
  240. for (U32 row = 0; row < height; ++row)
  241. {
  242. for (U32 col = 0; col < width; ++col)
  243. {
  244. //we can just copy data straight in with RGBA16F format
  245. if (fp16)
  246. {
  247. dMemcpy(destPtr, srcPtr, sizeof(U16) * 4);
  248. }
  249. else
  250. {
  251. destPtr[0] = srcPtr[2]; // red
  252. destPtr[1] = srcPtr[1]; // green
  253. destPtr[2] = srcPtr[0]; // blue
  254. if (destBytesPerPixel == 4)
  255. destPtr[3] = srcPtr[3]; // alpha
  256. }
  257. // go to next pixel in src
  258. srcPtr += sourceBytesPerPixel;
  259. // go to next pixel in dest
  260. destPtr += destBytesPerPixel;
  261. }
  262. // skip past the cache data for this row (if any)
  263. srcPtr += sourceCacheSize;
  264. }
  265. // assert if we stomped or underran memory
  266. AssertFatal(U32(destPtr - bmp->getWritableBits(mip)) == width * height * destBytesPerPixel, "GFXD3D11TextureObject::copyToBmp - memory error");
  267. AssertFatal(U32(srcPtr - (U8*)mappedRes.pData) == height * mappedRes.RowPitch, "GFXD3D11TextureObject::copyToBmp - memory error");
  268. D3D11DEVICECONTEXT->Unmap(pStagingTexture, subResource);
  269. }
  270. SAFE_RELEASE(pStagingTexture);
  271. PROFILE_END();
  272. return true;
  273. }
  274. ID3D11ShaderResourceView* GFXD3D11TextureObject::getSRView()
  275. {
  276. return mSRView;
  277. }
  278. ID3D11RenderTargetView* GFXD3D11TextureObject::getRTView()
  279. {
  280. return mRTView;
  281. }
  282. ID3D11DepthStencilView* GFXD3D11TextureObject::getDSView()
  283. {
  284. return mDSView;
  285. }
  286. ID3D11ShaderResourceView** GFXD3D11TextureObject::getSRViewPtr()
  287. {
  288. return &mSRView;
  289. }
  290. ID3D11RenderTargetView** GFXD3D11TextureObject::getRTViewPtr()
  291. {
  292. return &mRTView;
  293. }
  294. ID3D11DepthStencilView** GFXD3D11TextureObject::getDSViewPtr()
  295. {
  296. return &mDSView;
  297. }