Torque3D/Engine/source/gfx/D3D11/gfxD3D11TextureObject.cpp
AzaezelX 0527865462 set cubemapsaver profile to one that preserves sizes
also aug size mismatches for the popup so they're reported
2021-11-21 14:28:51 -06:00

338 lines
11 KiB
C++

//-----------------------------------------------------------------------------
// Copyright (c) 2015 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "gfx/D3D11/gfxD3D11Device.h"
#include "gfx/D3D11/gfxD3D11TextureObject.h"
#include "platform/profiler.h"
#include "console/console.h"
#ifdef TORQUE_DEBUG
U32 GFXD3D11TextureObject::mTexCount = 0;
#endif
// GFXFormatR8G8B8 has now the same behaviour as GFXFormatR8G8B8X8.
// 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.
// DirectX 10-11 both have 24 bit format no longer.
GFXD3D11TextureObject::GFXD3D11TextureObject( GFXDevice * d, GFXTextureProfile *profile) : GFXTextureObject( d, profile )
{
#ifdef D3D11_DEBUG_SPEW
mTexCount++;
Con::printf("+ texMake %d %x", mTexCount, this);
#endif
mD3DTexture = NULL;
mLocked = false;
mD3DSurface = NULL;
dMemset(&mLockRect, 0, sizeof(mLockRect));
dMemset(&mLockBox, 0, sizeof(mLockBox));
mLockedSubresource = 0;
mDSView = NULL;
mRTView = NULL;
mSRView = NULL;
isManaged = false;
}
GFXD3D11TextureObject::~GFXD3D11TextureObject()
{
kill();
#ifdef D3D11_DEBUG_SPEW
mTexCount--;
Con::printf("+ texkill %d %x", mTexCount, this);
#endif
}
GFXLockedRect *GFXD3D11TextureObject::lock(U32 mipLevel /*= 0*/, RectI *inRect /*= NULL*/)
{
AssertFatal( !mLocked, "GFXD3D11TextureObject::lock - The texture is already locked!" );
if( !mStagingTex ||
mStagingTex->getWidth() != getWidth() ||
mStagingTex->getHeight() != getHeight() ||
mStagingTex->getDepth() != getDepth())
{
if (getDepth() != 0)
{
mStagingTex.set(getWidth(), getHeight(), getDepth(), mFormat, &GFXSystemMemTextureProfile, avar("%s() - mLockTex (line %d)", __FUNCTION__, __LINE__, 0));
}
else
{
mStagingTex.set(getWidth(), getHeight(), mFormat, &GFXSystemMemTextureProfile, avar("%s() - mLockTex (line %d)", __FUNCTION__, __LINE__));
}
}
ID3D11DeviceContext* pContext = D3D11DEVICECONTEXT;
D3D11_MAPPED_SUBRESOURCE mapInfo;
U32 offset = 0;
mLockedSubresource = D3D11CalcSubresource(mipLevel, 0, getMipLevels());
GFXD3D11TextureObject* pD3DStagingTex = (GFXD3D11TextureObject*)&(*mStagingTex);
//map staging texture
HRESULT hr = pContext->Map(pD3DStagingTex->getResource(), mLockedSubresource, D3D11_MAP_WRITE, 0, &mapInfo);
if (FAILED(hr))
AssertFatal(false, "GFXD3D11TextureObject:lock - failed to map render target resource!");
const bool is3D = mStagingTex->getDepth() != 0;
const U32 width = mTextureSize.x >> mipLevel;
const U32 height = mTextureSize.y >> mipLevel;
const U32 depth = is3D ? mTextureSize.z >> mipLevel : 1;
//calculate locked box region and offset
if (inRect)
{
if ((inRect->point.x + inRect->extent.x > width) || (inRect->point.y + inRect->extent.y > height))
AssertFatal(false, "GFXD3D11TextureObject::lock - Rectangle too big!");
mLockBox.top = inRect->point.y;
mLockBox.left = inRect->point.x;
mLockBox.bottom = inRect->point.y + inRect->extent.y;
mLockBox.right = inRect->point.x + inRect->extent.x;
mLockBox.back = depth;
mLockBox.front = 0;
//calculate offset
offset = inRect->point.x * getFormatByteSize() + inRect->point.y * mapInfo.RowPitch;
}
else
{
mLockBox.top = 0;
mLockBox.left = 0;
mLockBox.bottom = height;
mLockBox.right = width;
mLockBox.back = depth;
mLockBox.front = 0;
}
mLocked = true;
mLockRect.pBits = static_cast<U8*>(mapInfo.pData) + offset;
mLockRect.Pitch = mapInfo.RowPitch;
return (GFXLockedRect*)&mLockRect;
}
void GFXD3D11TextureObject::unlock(U32 mipLevel)
{
AssertFatal( mLocked, "GFXD3D11TextureObject::unlock - Attempting to unlock a surface that has not been locked" );
//profile in the unlock function because all the heavy lifting is done here
PROFILE_START(GFXD3D11TextureObject_lockRT);
ID3D11DeviceContext* pContext = D3D11DEVICECONTEXT;
GFXD3D11TextureObject* pD3DStagingTex = (GFXD3D11TextureObject*)&(*mStagingTex);
ID3D11Resource* pStagingResource = pD3DStagingTex->getResource();
const bool is3D = mStagingTex->getDepth() != 0;
//unmap staging texture
pContext->Unmap(pStagingResource, mLockedSubresource);
//copy lock box region from the staging texture to our regular texture
pContext->CopySubresourceRegion(mD3DTexture, mLockedSubresource, mLockBox.left, mLockBox.top, is3D ? mLockBox.back : 0, pStagingResource, mLockedSubresource, &mLockBox);
PROFILE_END();
mLockedSubresource = 0;
mLocked = false;
}
void GFXD3D11TextureObject::release()
{
SAFE_RELEASE(mSRView);
SAFE_RELEASE(mRTView);
SAFE_RELEASE(mDSView);
SAFE_RELEASE(mD3DTexture);
SAFE_RELEASE(mD3DSurface);
}
void GFXD3D11TextureObject::zombify()
{
// Managed textures are managed by D3D
AssertFatal(!mLocked, "GFXD3D11TextureObject::zombify - Cannot zombify a locked texture!");
if(isManaged)
return;
release();
}
void GFXD3D11TextureObject::resurrect()
{
// Managed textures are managed by D3D
if(isManaged)
return;
static_cast<GFXD3D11TextureManager*>(TEXMGR)->refreshTexture(this);
}
bool GFXD3D11TextureObject::copyToBmp(GBitmap* bmp)
{
if (!bmp)
return false;
// check format limitations
// at the moment we only support RGBA for the source (other 4 byte formats should
// be easy to add though)
AssertFatal(mFormat == GFXFormatR16G16B16A16F || mFormat == GFXFormatR8G8B8A8 || mFormat == GFXFormatR8G8B8A8_LINEAR_FORCE || mFormat == GFXFormatR8G8B8A8_SRGB || mFormat == GFXFormatR8G8B8, "copyToBmp: invalid format");
if (mFormat != GFXFormatR16G16B16A16F && mFormat != GFXFormatR8G8B8A8 && mFormat != GFXFormatR8G8B8A8_LINEAR_FORCE && mFormat != GFXFormatR8G8B8A8_SRGB && mFormat != GFXFormatR8G8B8)
return false;
PROFILE_START(GFXD3D11TextureObject_copyToBmp);
AssertFatal(bmp->getWidth() == getWidth(), avar("GFXGLTextureObject::copyToBmp - Width mismatch: %i vs %i", bmp->getWidth(), getWidth()));
AssertFatal(bmp->getHeight() == getHeight(), avar("GFXGLTextureObject::copyToBmp - Height mismatch: %i vs %i", bmp->getHeight(), getHeight()));
const U32 mipLevels = getMipLevels();
bmp->setHasTransparency(mHasTransparency);
// set some constants
U32 sourceBytesPerPixel = 4;
U32 destBytesPerPixel = 0;
const GFXFormat fmt = bmp->getFormat();
bool fp16 = false;//is rgba16f format?
if (fmt == GFXFormatR16G16B16A16F)
{
destBytesPerPixel = 8;
sourceBytesPerPixel = 8;
fp16 = true;
}
else if (fmt == GFXFormatR8G8B8A8 || fmt == GFXFormatR8G8B8A8_LINEAR_FORCE || fmt == GFXFormatR8G8B8A8_SRGB)
destBytesPerPixel = 4;
else if(bmp->getFormat() == GFXFormatR8G8B8)
destBytesPerPixel = 3;
else
// unsupported
AssertFatal(false, "GFXD3D11TextureObject::copyToBmp - unsupported bitmap format");
//create temp staging texture
D3D11_TEXTURE2D_DESC desc;
static_cast<ID3D11Texture2D*>(mD3DTexture)->GetDesc(&desc);
desc.BindFlags = 0;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
desc.Usage = D3D11_USAGE_STAGING;
desc.MiscFlags = 0;
ID3D11Texture2D* pStagingTexture = NULL;
HRESULT hr = D3D11DEVICE->CreateTexture2D(&desc, NULL, &pStagingTexture);
if (FAILED(hr))
{
Con::errorf("GFXD3D11TextureObject::copyToBmp - Failed to create staging texture");
return false;
}
//copy the classes texture to the staging texture
D3D11DEVICECONTEXT->CopyResource(pStagingTexture, mD3DTexture);
for (U32 mip = 0; mip < mipLevels; mip++)
{
const U32 width = bmp->getWidth(mip);
const U32 height = bmp->getHeight(mip);
//map the staging resource
D3D11_MAPPED_SUBRESOURCE mappedRes;
const U32 subResource = D3D11CalcSubresource(mip, 0, mipLevels);
hr = D3D11DEVICECONTEXT->Map(pStagingTexture, subResource, D3D11_MAP_READ, 0, &mappedRes);
if (FAILED(hr))
{
//cleanup
SAFE_RELEASE(pStagingTexture);
Con::errorf("GFXD3D11TextureObject::copyToBmp - Failed to map staging texture");
return false;
}
// set pointers
const U8* srcPtr = (U8*)mappedRes.pData;
U8* destPtr = bmp->getWritableBits(mip);
// we will want to skip over any D3D cache data in the source texture
const S32 sourceCacheSize = mappedRes.RowPitch - width * sourceBytesPerPixel;
AssertFatal(sourceCacheSize >= 0, "GFXD3D11TextureObject::copyToBmp - cache size is less than zero?");
// copy data into bitmap
for (U32 row = 0; row < height; ++row)
{
for (U32 col = 0; col < width; ++col)
{
//we can just copy data straight in with RGBA16F format
if (fp16)
{
dMemcpy(destPtr, srcPtr, sizeof(U16) * 4);
}
else
{
destPtr[0] = srcPtr[2]; // red
destPtr[1] = srcPtr[1]; // green
destPtr[2] = srcPtr[0]; // blue
if (destBytesPerPixel == 4)
destPtr[3] = srcPtr[3]; // alpha
}
// go to next pixel in src
srcPtr += sourceBytesPerPixel;
// go to next pixel in dest
destPtr += destBytesPerPixel;
}
// skip past the cache data for this row (if any)
srcPtr += sourceCacheSize;
}
// assert if we stomped or underran memory
AssertFatal(U32(destPtr - bmp->getWritableBits(mip)) == width * height * destBytesPerPixel, "GFXD3D11TextureObject::copyToBmp - memory error");
AssertFatal(U32(srcPtr - (U8*)mappedRes.pData) == height * mappedRes.RowPitch, "GFXD3D11TextureObject::copyToBmp - memory error");
D3D11DEVICECONTEXT->Unmap(pStagingTexture, subResource);
}
SAFE_RELEASE(pStagingTexture);
PROFILE_END();
return true;
}
ID3D11ShaderResourceView* GFXD3D11TextureObject::getSRView()
{
return mSRView;
}
ID3D11RenderTargetView* GFXD3D11TextureObject::getRTView()
{
return mRTView;
}
ID3D11DepthStencilView* GFXD3D11TextureObject::getDSView()
{
return mDSView;
}
ID3D11ShaderResourceView** GFXD3D11TextureObject::getSRViewPtr()
{
return &mSRView;
}
ID3D11RenderTargetView** GFXD3D11TextureObject::getRTViewPtr()
{
return &mRTView;
}
ID3D11DepthStencilView** GFXD3D11TextureObject::getDSViewPtr()
{
return &mDSView;
}