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