Update GFXTextureManager and GBitmap

GBitmap Changes:
Added all other formats to gbitmap that we support
gbitmap now supports cubemaps
added converters for all these other formats
added stb_image_resize for extrudemips so we can extrude mipmaps for all other formats

GFXTextureManager
Can now directly make cubemaps and texture arrays based on the GFXTextureProfile
API implementations for all functions that cubemaps and arrays needed
This commit is contained in:
marauder2k7 2025-12-22 10:29:01 +00:00
parent 975fc924cc
commit 3aef90a6bc
66 changed files with 4235 additions and 2590 deletions

View file

@ -38,6 +38,7 @@ GFXD3D11TextureTarget::GFXD3D11TextureTarget(bool genMips)
mResolveTargets[i] = NULL;
mTargetViews[i] = NULL;
mTargetSRViews[i] = NULL;
mTargetArrayIdx[i] = 0;
}
mGenMips = genMips;
@ -57,9 +58,9 @@ GFXD3D11TextureTarget::~GFXD3D11TextureTarget()
zombify();
}
void GFXD3D11TextureTarget::attachTexture( RenderSlot slot, GFXTextureObject *tex, U32 mipLevel/*=0*/, U32 zOffset /*= 0*/ )
void GFXD3D11TextureTarget::attachTexture(RenderSlot slot, GFXTextureObject* tex, U32 mipLevel /*= 0*/, U32 zOffset /*= 0*/, U32 faceIndex /*= 0*/)
{
GFXDEBUGEVENT_SCOPE( GFXPCD3D11TextureTarget_attachTexture, ColorI::RED );
GFXDEBUGEVENT_SCOPE(GFXPCD3D11TextureTarget_attachTexture, ColorI::RED);
AssertFatal(slot < MaxRenderSlotId, "GFXD3D11TextureTarget::attachTexture - out of range slot.");
@ -76,17 +77,17 @@ void GFXD3D11TextureTarget::attachTexture( RenderSlot slot, GFXTextureObject *te
SAFE_RELEASE(mTargetViews[slot]);
SAFE_RELEASE(mTargets[slot]);
SAFE_RELEASE(mTargetSRViews[slot]);
mResolveTargets[slot] = NULL;
mTargetArrayIdx[slot] = 0;
if(slot == Color0)
if (slot == Color0)
{
mTargetSize = Point2I::Zero;
mTargetFormat = GFXFormatR8G8B8A8;
}
// Are we clearing?
if(!tex)
if (!tex)
{
// Yup - just exit, it'll stay NULL.
return;
@ -96,7 +97,7 @@ void GFXD3D11TextureTarget::attachTexture( RenderSlot slot, GFXTextureObject *te
mTargetSRViews[slot] = NULL;
// Take care of default targets
if( tex == GFXTextureTarget::sDefaultDepthStencil )
if (tex == GFXTextureTarget::sDefaultDepthStencil)
{
mTargets[slot] = D3D11->mDeviceDepthStencil;
mTargetViews[slot] = D3D11->mDeviceDepthStencilView;
@ -108,81 +109,100 @@ void GFXD3D11TextureTarget::attachTexture( RenderSlot slot, GFXTextureObject *te
// Cast the texture object to D3D...
AssertFatal(dynamic_cast<GFXD3D11TextureObject*>(tex), "GFXD3D11TextureTarget::attachTexture - invalid texture object.");
GFXD3D11TextureObject *d3dto = dynamic_cast<GFXD3D11TextureObject*>(tex);
GFXD3D11TextureObject* d3dto = dynamic_cast<GFXD3D11TextureObject*>(tex);
bool isCube = d3dto->isCubeMap();
// Grab the surface level.
if( slot == DepthStencil )
{
if (slot == DepthStencil)
{
mTargets[slot] = d3dto->getSurface();
if ( mTargets[slot] )
if (mTargets[slot])
mTargets[slot]->AddRef();
mTargetViews[slot] = d3dto->getDSView();
if( mTargetViews[slot])
mTargetViews[slot]->AddRef();
if (mTargetViews[slot])
mTargetViews[slot]->AddRef();
}
else
{
// getSurface will almost always return NULL. It will only return non-NULL
// if the surface that it needs to render to is different than the mip level
// in the actual texture. This will happen with MSAA.
if( d3dto->getSurface() == NULL )
{
if (!isCube)
{
mTargets[slot] = d3dto->get2DTex();
mTargets[slot]->AddRef();
mTargetViews[slot] = d3dto->getRTView();
mTargetViews[slot]->AddRef();
}
else
{
mTargets[slot] = d3dto->getSurface();
mTargets[slot]->AddRef();
mTargetViews[slot]->AddRef();
mResolveTargets[slot] = d3dto;
if ( tex && slot == Color0 )
if (d3dto->getSurface() == NULL)
{
mTargetSize.set( tex->getSize().x, tex->getSize().y );
mTargetFormat = tex->getFormat();
mTargets[slot] = d3dto->get2DTex();
mTargets[slot]->AddRef();
mTargetViews[slot] = d3dto->getRTView();
mTargetViews[slot]->AddRef();
}
else
{
mTargets[slot] = d3dto->getSurface();
mTargets[slot]->AddRef();
mTargetViews[slot] = d3dto->getRTView();
mTargetViews[slot]->AddRef();
mResolveTargets[slot] = d3dto;
}
}
else
{
// Cubemap render target face
mGenMips = false;
AssertFatal(faceIndex < 6, "Invalid cubemap face index!");
ID3D11RenderTargetView* faceRTV = d3dto->getCubeFaceRTView(faceIndex);
AssertFatal(faceRTV, "Cubemap face RTV is null!");
mTargetArrayIdx[slot] = faceIndex;
if (d3dto->getSurface() == NULL)
{
mTargets[slot] = d3dto->get2DTex();
mTargets[slot]->AddRef();
mTargetViews[slot] = faceRTV;
mTargetViews[slot]->AddRef();
}
else
{
mTargets[slot] = d3dto->getSurface();
mTargets[slot]->AddRef();
mTargetViews[slot] = faceRTV;
mTargetViews[slot]->AddRef();
mResolveTargets[slot] = d3dto;
}
}
// For mip generation
if (mGenMips)
{
mTargetSRViews[slot] = d3dto->getSRView();
mTargetSRViews[slot]->AddRef();
if (mTargetSRViews[slot])
mTargetSRViews[slot]->AddRef();
}
}
// Update surface size
if(slot == Color0)
// Update color target info
if (slot == Color0)
{
ID3D11Texture2D *surface = mTargets[Color0];
if ( surface )
ID3D11Texture2D* surface = mTargets[Color0];
if (surface)
{
D3D11_TEXTURE2D_DESC sd;
surface->GetDesc(&sd);
mTargetSize = Point2I(sd.Width, sd.Height);
S32 format = sd.Format;
if (format == DXGI_FORMAT_R8G8B8A8_TYPELESS || format == DXGI_FORMAT_B8G8R8A8_TYPELESS)
{
mTargetFormat = GFXFormatR8G8B8A8;
return;
else
{
GFXREVERSE_LOOKUP(GFXD3D11TextureFormat, GFXFormat, format);
mTargetFormat = (GFXFormat)format;
}
GFXREVERSE_LOOKUP( GFXD3D11TextureFormat, GFXFormat, format );
mTargetFormat = (GFXFormat)format;
}
}
}
}
void GFXD3D11TextureTarget::attachTexture( RenderSlot slot, GFXCubemap *tex, U32 face, U32 mipLevel/*=0*/ )
{
GFXDEBUGEVENT_SCOPE( GFXPCD3D11TextureTarget_attachTexture_Cubemap, ColorI::RED );
@ -316,7 +336,9 @@ void GFXD3D11TextureTarget::resolveTo( GFXTextureObject *tex )
D3D11_TEXTURE2D_DESC desc;
mTargets[Color0]->GetDesc(&desc);
D3D11DEVICECONTEXT->CopySubresourceRegion(((GFXD3D11TextureObject*)(tex))->get2DTex(), 0, 0, 0, 0, mTargets[Color0], 0, NULL);
UINT mipLevels = desc.MipLevels ? desc.MipLevels : 1;
UINT subResource = D3D11CalcSubresource(0, mTargetArrayIdx[Color0], mipLevels);
D3D11DEVICECONTEXT->CopySubresourceRegion(((GFXD3D11TextureObject*)(tex))->get2DTex(), 0, 0, 0, 0, mTargets[Color0], subResource, NULL);
}

View file

@ -49,6 +49,8 @@ class GFXD3D11TextureTarget : public GFXTextureTarget
GFXFormat mTargetFormat;
U32 mTargetArrayIdx[MaxRenderSlotId];
public:
GFXD3D11TextureTarget(bool genMips);
@ -57,7 +59,7 @@ public:
// Public interface.
const Point2I getSize() override { return mTargetSize; }
GFXFormat getFormat() override { return mTargetFormat; }
void attachTexture(RenderSlot slot, GFXTextureObject *tex, U32 mipLevel=0, U32 zOffset = 0) override;
void attachTexture(RenderSlot slot, GFXTextureObject* tex, U32 mipLevel = 0, U32 zOffset = 0, U32 faceIndex = 0) override;
void attachTexture(RenderSlot slot, GFXCubemap *tex, U32 face, U32 mipLevel=0) override;
void resolve() override;

View file

@ -52,7 +52,8 @@ void GFXD3D11TextureManager::_innerCreateTexture( GFXD3D11TextureObject *retTex,
GFXTextureProfile *profile,
U32 numMipLevels,
bool forceMips,
S32 antialiasLevel)
S32 antialiasLevel,
U32 arraySize)
{
U32 usage = 0;
U32 bindFlags = 0;
@ -67,6 +68,9 @@ void GFXD3D11TextureManager::_innerCreateTexture( GFXD3D11TextureObject *retTex,
retTex->isManaged = false;
DXGI_FORMAT d3dTextureFormat = GFXD3D11TextureFormat[format];
if (retTex->isCubeMap())
miscFlags |= D3D11_RESOURCE_MISC_TEXTURECUBE;
if( retTex->mProfile->isDynamic() )
{
usage = D3D11_USAGE_DYNAMIC;
@ -199,7 +203,7 @@ void GFXD3D11TextureManager::_innerCreateTexture( GFXD3D11TextureObject *retTex,
D3D11_TEXTURE2D_DESC desc;
ZeroMemory(&desc, sizeof(D3D11_TEXTURE2D_DESC));
desc.ArraySize = 1;
desc.ArraySize = arraySize * (retTex->isCubeMap() ? 6 : 1);
desc.BindFlags = bindFlags;
desc.CPUAccessFlags = cpuFlags;
desc.Format = d3dTextureFormat;
@ -219,6 +223,7 @@ void GFXD3D11TextureManager::_innerCreateTexture( GFXD3D11TextureObject *retTex,
retTex->get2DTex()->GetDesc(&desc);
retTex->mMipLevels = desc.MipLevels;
retTex->mArraySize = arraySize;
}
// start creating the resource views...
@ -267,6 +272,7 @@ GFXTextureObject *GFXD3D11TextureManager::_createTextureObject( U32 height,
U32 numMipLevels,
bool forceMips,
S32 antialiasLevel,
U32 arraySize,
GFXTextureObject *inTex )
{
GFXD3D11TextureObject *retTex;
@ -278,11 +284,11 @@ GFXTextureObject *GFXD3D11TextureManager::_createTextureObject( U32 height,
}
else
{
retTex = new GFXD3D11TextureObject(GFX, profile);
retTex = new GFXD3D11TextureObject(GFX, profile, arraySize);
retTex->registerResourceWithDevice(GFX);
}
_innerCreateTexture(retTex, height, width, depth, format, profile, numMipLevels, forceMips, antialiasLevel);
_innerCreateTexture(retTex, height, width, depth, format, profile, numMipLevels, forceMips, antialiasLevel, arraySize);
return retTex;
}
@ -295,7 +301,9 @@ bool GFXD3D11TextureManager::_loadTexture(GFXTextureObject *aTexture, GBitmap *p
// Check with profiler to see if we can do automatic mipmap generation.
const bool supportsAutoMips = GFX->getCardProfiler()->queryProfile("autoMipMapLevel", true);
const bool isCube = texture->isCubeMap() && pDL->getNumFaces() > 1;
const U32 numFaces = isCube ? 6 : 1;
// Helper bool
const bool isCompressedTexFmt = ImageUtil::isCompressedFormat(aTexture->mFormat);
@ -312,98 +320,101 @@ bool GFXD3D11TextureManager::_loadTexture(GFXTextureObject *aTexture, GBitmap *p
bool isDynamic = texture->mProfile->isDynamic();
// Fill the texture...
for( U32 i = 0; i < maxDownloadMip; i++ )
for (U32 face = 0; face < numFaces; ++face)
{
U32 subResource = D3D11CalcSubresource(i, 0, aTexture->mMipLevels);
for (U32 i = 0; i < maxDownloadMip; i++)
{
U32 subResource = D3D11CalcSubresource(i, face, aTexture->mMipLevels);
if(!isDynamic)
{
U8* copyBuffer = NULL;
if (!isDynamic)
{
U8* copyBuffer = NULL;
switch(texture->mFormat)
{
switch (texture->mFormat)
{
case GFXFormatR8G8B8:
case GFXFormatR8G8B8_SRGB:
{
PROFILE_SCOPE(Swizzle24_Upload);
{
PROFILE_SCOPE(Swizzle24_Upload);
U8* Bits = new U8[pDL->getWidth(i) * pDL->getHeight(i) * 4];
dMemcpy(Bits, pDL->getBits(i), pDL->getWidth(i) * pDL->getHeight(i) * 3);
bitmapConvertRGB_to_RGBX(&Bits, pDL->getWidth(i) * pDL->getHeight(i));
copyBuffer = new U8[pDL->getWidth(i) * pDL->getHeight(i) * 4];
dev->getDeviceSwizzle32()->ToBuffer(copyBuffer, Bits, pDL->getWidth(i) * pDL->getHeight(i) * 4);
dev->getDeviceContext()->UpdateSubresource(texture->get2DTex(), subResource, NULL, copyBuffer, pDL->getWidth() * 4, pDL->getHeight() *4);
U8* Bits = new U8[pDL->getWidth(i) * pDL->getHeight(i) * 4];
dMemcpy(Bits, pDL->getBits(i, face), pDL->getWidth(i) * pDL->getHeight(i) * 3);
bitmapConvertRGB_to_RGBX(&Bits, pDL->getWidth(i) * pDL->getHeight(i));
copyBuffer = new U8[pDL->getWidth(i) * pDL->getHeight(i) * 4];
dev->getDeviceSwizzle32()->ToBuffer(copyBuffer, Bits, pDL->getWidth(i) * pDL->getHeight(i) * 4);
dev->getDeviceContext()->UpdateSubresource(texture->get2DTex(), subResource, NULL, copyBuffer, pDL->getWidth() * 4, pDL->getHeight() * 4);
SAFE_DELETE_ARRAY(Bits);
break;
}
case GFXFormatR8G8B8A8:
case GFXFormatR8G8B8X8:
case GFXFormatR8G8B8A8_SRGB:
{
PROFILE_SCOPE(Swizzle32_Upload);
copyBuffer = new U8[pDL->getWidth(i) * pDL->getHeight(i) * pDL->getBytesPerPixel()];
dev->getDeviceSwizzle32()->ToBuffer(copyBuffer, pDL->getBits(i), pDL->getWidth(i) * pDL->getHeight(i) * pDL->getBytesPerPixel());
dev->getDeviceContext()->UpdateSubresource(texture->get2DTex(), subResource, NULL, copyBuffer, pDL->getWidth() * pDL->getBytesPerPixel(), pDL->getHeight() *pDL->getBytesPerPixel());
break;
}
default:
{
// Just copy the bits in no swizzle or padding
PROFILE_SCOPE(SwizzleNull_Upload);
AssertFatal( pDL->getFormat() == texture->mFormat, "Format mismatch");
dev->getDeviceContext()->UpdateSubresource(texture->get2DTex(), subResource, NULL, pDL->getBits(i), pDL->getWidth() *pDL->getBytesPerPixel(), pDL->getHeight() *pDL->getBytesPerPixel());
}
}
SAFE_DELETE_ARRAY(copyBuffer);
}
else
{
D3D11_MAPPED_SUBRESOURCE mapping;
HRESULT res = dev->getDeviceContext()->Map(texture->get2DTex(), subResource, D3D11_MAP_WRITE, 0, &mapping);
AssertFatal(res, "tex2d map call failure");
switch( texture->mFormat )
{
case GFXFormatR8G8B8:
case GFXFormatR8G8B8_SRGB:
{
PROFILE_SCOPE(Swizzle24_Upload);
U8* Bits = new U8[pDL->getWidth(i) * pDL->getHeight(i) * 4];
dMemcpy(Bits, pDL->getBits(i), pDL->getWidth(i) * pDL->getHeight(i) * 3);
bitmapConvertRGB_to_RGBX(&Bits, pDL->getWidth(i) * pDL->getHeight(i));
dev->getDeviceSwizzle32()->ToBuffer(mapping.pData, Bits, pDL->getWidth(i) * pDL->getHeight(i) * 4);
SAFE_DELETE_ARRAY(Bits);
}
break;
break;
}
case GFXFormatR8G8B8A8:
case GFXFormatR8G8B8X8:
case GFXFormatR8G8B8A8_SRGB:
{
PROFILE_SCOPE(Swizzle32_Upload);
dev->getDeviceSwizzle32()->ToBuffer(mapping.pData, pDL->getBits(i), pDL->getWidth(i) * pDL->getHeight(i) * pDL->getBytesPerPixel());
copyBuffer = new U8[pDL->getWidth(i) * pDL->getHeight(i) * pDL->getBytesPerPixel()];
dev->getDeviceSwizzle32()->ToBuffer(copyBuffer, pDL->getBits(i, face), pDL->getWidth(i) * pDL->getHeight(i) * pDL->getBytesPerPixel());
dev->getDeviceContext()->UpdateSubresource(texture->get2DTex(), subResource, NULL, copyBuffer, pDL->getWidth() * pDL->getBytesPerPixel(), pDL->getHeight() * pDL->getBytesPerPixel());
break;
}
break;
default:
{
default:
{
// Just copy the bits in no swizzle or padding
PROFILE_SCOPE(SwizzleNull_Upload);
AssertFatal( pDL->getFormat() == texture->mFormat, "Format mismatch");
dMemcpy(mapping.pData, pDL->getBits(i), pDL->getWidth(i) * pDL->getHeight(i) * pDL->getBytesPerPixel());
}
}
AssertFatal(pDL->getFormat() == texture->mFormat, "Format mismatch");
dev->getDeviceContext()->UpdateSubresource(texture->get2DTex(), subResource, NULL, pDL->getBits(i, face), pDL->getWidth() * pDL->getBytesPerPixel(), pDL->getHeight() * pDL->getBytesPerPixel());
}
}
dev->getDeviceContext()->Unmap(texture->get2DTex(), subResource);
}
SAFE_DELETE_ARRAY(copyBuffer);
}
else
{
D3D11_MAPPED_SUBRESOURCE mapping;
HRESULT res = dev->getDeviceContext()->Map(texture->get2DTex(), subResource, D3D11_MAP_WRITE, 0, &mapping);
AssertFatal(res, "tex2d map call failure");
switch (texture->mFormat)
{
case GFXFormatR8G8B8:
case GFXFormatR8G8B8_SRGB:
{
PROFILE_SCOPE(Swizzle24_Upload);
U8* Bits = new U8[pDL->getWidth(i) * pDL->getHeight(i) * 4];
dMemcpy(Bits, pDL->getBits(i, face), pDL->getWidth(i) * pDL->getHeight(i) * 3);
bitmapConvertRGB_to_RGBX(&Bits, pDL->getWidth(i) * pDL->getHeight(i));
dev->getDeviceSwizzle32()->ToBuffer(mapping.pData, Bits, pDL->getWidth(i) * pDL->getHeight(i) * 4);
SAFE_DELETE_ARRAY(Bits);
}
break;
case GFXFormatR8G8B8A8:
case GFXFormatR8G8B8X8:
case GFXFormatR8G8B8A8_SRGB:
{
PROFILE_SCOPE(Swizzle32_Upload);
dev->getDeviceSwizzle32()->ToBuffer(mapping.pData, pDL->getBits(i, face), pDL->getWidth(i) * pDL->getHeight(i) * pDL->getBytesPerPixel());
}
break;
default:
{
// Just copy the bits in no swizzle or padding
PROFILE_SCOPE(SwizzleNull_Upload);
AssertFatal(pDL->getFormat() == texture->mFormat, "Format mismatch");
dMemcpy(mapping.pData, pDL->getBits(i, face), pDL->getWidth(i) * pDL->getHeight(i) * pDL->getBytesPerPixel());
}
}
dev->getDeviceContext()->Unmap(texture->get2DTex(), subResource);
}
}
}
D3D11_TEXTURE2D_DESC desc;
@ -487,7 +498,7 @@ bool GFXD3D11TextureManager::_refreshTexture(GFXTextureObject *texture)
if(texture->mProfile->isRenderTarget() || texture->mProfile->isDynamic() || texture->mProfile->isZTarget())
{
realTex->release();
_innerCreateTexture(realTex, texture->getHeight(), texture->getWidth(), texture->getDepth(), texture->mFormat, texture->mProfile, texture->mMipLevels, false, texture->mAntialiasLevel);
_innerCreateTexture(realTex, texture->getHeight(), texture->getWidth(), texture->getDepth(), texture->mFormat, texture->mProfile, texture->mMipLevels, false, texture->mAntialiasLevel, texture->mArraySize);
usedStrategies++;
}
@ -519,14 +530,31 @@ bool GFXD3D11TextureManager::_loadTexture(GFXTextureObject *aTexture, DDSFile *d
GFXD3D11TextureObject *texture = static_cast<GFXD3D11TextureObject*>(aTexture);
GFXD3D11Device* dev = static_cast<GFXD3D11Device *>(GFX);
// Fill the texture...
for( U32 i = 0; i < aTexture->mMipLevels; i++ )
const bool isCube = texture->isCubeMap() && dds->isCubemap();
const U32 numFaces = isCube ? 6 : 1;
// Loop over faces and mips
for (U32 face = 0; face < numFaces; ++face)
{
PROFILE_SCOPE(GFXD3DTexMan_loadSurface);
for (U32 mip = 0; mip < aTexture->mMipLevels; ++mip)
{
PROFILE_SCOPE(GFXD3DTexMan_loadSurface);
AssertFatal( dds->mSurfaces.size() > 0, "Assumption failed. DDSFile has no surfaces." );
// DDSFile must have data for each face
AssertFatal(dds->mSurfaces.size() > face, "DDSFile missing cubemap face data.");
AssertFatal(dds->mSurfaces[face]->mMips.size() > mip, "DDSFile missing mip level.");
U32 subresource = D3D11CalcSubresource(i, 0, aTexture->mMipLevels);
dev->getDeviceContext()->UpdateSubresource(texture->get2DTex(), subresource, 0, dds->mSurfaces[0]->mMips[i], dds->getSurfacePitch(i), 0);
const U32 subresource = D3D11CalcSubresource(mip, face, aTexture->mMipLevels);
dev->getDeviceContext()->UpdateSubresource(
texture->get2DTex(), // resource
subresource, // subresource index
nullptr, // box (nullptr for full subresource)
dds->mSurfaces[face]->mMips[mip], // source data pointer
dds->getSurfacePitch(mip), // row pitch
0 // depth pitch
);
}
}
D3D11_TEXTURE2D_DESC desc;
@ -541,14 +569,14 @@ bool GFXD3D11TextureManager::_loadTexture(GFXTextureObject *aTexture, DDSFile *d
void GFXD3D11TextureManager::createResourceView(U32 height, U32 width, U32 depth, DXGI_FORMAT format, U32 numMipLevels,U32 usageFlags, GFXTextureObject *inTex)
{
GFXD3D11TextureObject *tex = static_cast<GFXD3D11TextureObject*>(inTex);
ID3D11Resource* resource = NULL;
if(tex->get2DTex())
resource = tex->get2DTex();
else if(tex->getSurface())
resource = tex->getSurface();
else
resource = tex->get3DTex();
ID3D11Resource* resource;
if (tex->get2DTex())
resource = tex->get2DTex();
else if (tex->getSurface())
resource = tex->getSurface();
else
resource = tex->get3DTex();
HRESULT hr;
//TODO: add MSAA support later.
@ -567,11 +595,40 @@ void GFXD3D11TextureManager::createResourceView(U32 height, U32 width, U32 depth
desc.Texture3D.MipLevels = -1;
desc.Texture3D.MostDetailedMip = 0;
}
else
else if (tex->isCubeMap())
{
if (tex->getArraySize() == 1)
{
desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
desc.TextureCube.MipLevels = -1;
desc.TextureCube.MostDetailedMip = 0;
}
else
{
desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBEARRAY;
desc.TextureCubeArray.MostDetailedMip = 0;
desc.TextureCubeArray.MipLevels = -1;
desc.TextureCubeArray.First2DArrayFace = 0;
desc.TextureCubeArray.NumCubes = tex->getArraySize();
}
}
else
{
desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
desc.Texture2D.MipLevels = -1;
desc.Texture2D.MostDetailedMip = 0;
if (tex->getArraySize() == 1)
{
desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
desc.Texture2D.MipLevels = -1;
desc.Texture2D.MostDetailedMip = 0;
}
else
{
desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
desc.Texture2DArray.MipLevels = -1;
desc.Texture2DArray.MostDetailedMip = 0;
desc.Texture2DArray.FirstArraySlice = 0;
desc.Texture2DArray.ArraySize = tex->getArraySize();
}
}
hr = D3D11DEVICE->CreateShaderResourceView(resource,&desc, tex->getSRViewPtr());
@ -580,12 +637,29 @@ void GFXD3D11TextureManager::createResourceView(U32 height, U32 width, U32 depth
if(usageFlags & D3D11_BIND_RENDER_TARGET)
{
D3D11_RENDER_TARGET_VIEW_DESC desc;
desc.Format = format;
desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
desc.Texture2D.MipSlice = 0;
hr = D3D11DEVICE->CreateRenderTargetView(resource, &desc, tex->getRTViewPtr());
AssertFatal(SUCCEEDED(hr), "CreateRenderTargetView:: failed to create view!");
if (tex->isCubeMap())
{
for (U32 face = 0; face < 6; face++)
{
D3D11_RENDER_TARGET_VIEW_DESC desc;
desc.Format = format;
desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
desc.Texture2DArray.ArraySize = 1;
desc.Texture2DArray.FirstArraySlice = face;
desc.Texture2DArray.MipSlice = 0;
hr = D3D11DEVICE->CreateRenderTargetView(resource, &desc, tex->getCubeFaceRTViewPtr(face));
AssertFatal(SUCCEEDED(hr), "CreateRenderTargetView:: failed to create view!");
}
}
else
{
D3D11_RENDER_TARGET_VIEW_DESC desc;
desc.Format = format;
desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
desc.Texture2D.MipSlice = 0;
hr = D3D11DEVICE->CreateRenderTargetView(resource, &desc, tex->getRTViewPtr());
AssertFatal(SUCCEEDED(hr), "CreateRenderTargetView:: failed to create view!");
}
}
if(usageFlags & D3D11_BIND_DEPTH_STENCIL)

View file

@ -45,6 +45,7 @@ protected:
U32 numMipLevels,
bool forceMips = false,
S32 antialiasLevel = 0,
U32 arraySize = 1,
GFXTextureObject *inTex = NULL ) override;
bool _loadTexture(GFXTextureObject *texture, DDSFile *dds) override;
@ -56,7 +57,7 @@ protected:
private:
U32 mCurTexSet[GFX_TEXTURE_STAGE_COUNT];
void _innerCreateTexture(GFXD3D11TextureObject *obj, U32 height, U32 width, U32 depth, GFXFormat format, GFXTextureProfile *profile, U32 numMipLevels, bool forceMips = false, S32 antialiasLevel = 0);
void _innerCreateTexture(GFXD3D11TextureObject *obj, U32 height, U32 width, U32 depth, GFXFormat format, GFXTextureProfile *profile, U32 numMipLevels, bool forceMips = false, S32 antialiasLevel = 0, U32 arraySize = 1);
};
#endif

View file

@ -33,26 +33,16 @@ U32 GFXD3D11TextureObject::mTexCount = 0;
// 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 )
GFXD3D11TextureObject::GFXD3D11TextureObject( GFXDevice * d, GFXTextureProfile *profile, const U32 arraySize) : GFXTextureObject( d, profile )
{
#ifdef D3D11_DEBUG_SPEW
mTexCount++;
Con::printf("+ texMake %d %x", mTexCount, this);
#endif
mD3DTexture = NULL;
mLocked = false;
mD3DSurface = NULL;
isManaged = false;
dMemset(&mLockRect, 0, sizeof(mLockRect));
dMemset(&mLockBox, 0, sizeof(mLockBox));
mLockedSubresource = 0;
mDSView = NULL;
mRTView = NULL;
mSRView = NULL;
isManaged = false;
mArraySize = arraySize;
}
GFXD3D11TextureObject::~GFXD3D11TextureObject()
@ -64,53 +54,76 @@ GFXD3D11TextureObject::~GFXD3D11TextureObject()
#endif
}
GFXLockedRect *GFXD3D11TextureObject::lock(U32 mipLevel /*= 0*/, RectI *inRect /*= NULL*/)
ID3D11Texture2D* GFXD3D11TextureObject::get2DTex() const
{
AssertFatal( !mLocked, "GFXD3D11TextureObject::lock - The texture is already locked!" );
ComPtr<ID3D11Texture2D> tex2D;
if (mD3DTexture) mD3DTexture.As(&tex2D);
return tex2D.Get();
}
if( !mStagingTex ||
ID3D11Texture3D* GFXD3D11TextureObject::get3DTex() const
{
ComPtr<ID3D11Texture3D> tex3D;
if (mD3DTexture) mD3DTexture.As(&tex3D);
return tex3D.Get();
}
ID3D11Texture2D** GFXD3D11TextureObject::get2DTexPtr()
{
return reinterpret_cast<ID3D11Texture2D**>(mD3DTexture.GetAddressOf());
}
ID3D11Texture3D** GFXD3D11TextureObject::get3DTexPtr()
{
return reinterpret_cast<ID3D11Texture3D**>(mD3DTexture.GetAddressOf());
}
ID3D11RenderTargetView** GFXD3D11TextureObject::getCubeFaceRTViewPtr(U32 face)
{
AssertFatal(isCubeMap(), "Not a cubemap texture!");
AssertFatal(face < 6, "Invalid cubemap face index!");
return mCubeRTV[face].GetAddressOf();
}
GFXLockedRect* GFXD3D11TextureObject::lock(U32 mipLevel /*= 0*/, RectI* inRect /*= NULL*/, U32 faceIndex /*= 0*/)
{
AssertFatal(!mLocked, "GFXD3D11TextureObject::lock - Texture is already locked!");
AssertFatal(faceIndex < 6 || !isCubeMap(), "Invalid cubemap face index!");
// Ensure staging texture exists and matches size
if (!mStagingTex.isValid() ||
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__));
}
mStagingTex.set(getWidth(), getHeight(), mFormat, &GFXSystemMemTextureProfile,
avar("%s() - stagingTex", __FUNCTION__));
}
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);
mLockedSubresource = D3D11CalcSubresource(mipLevel, faceIndex, getMipLevels());
GFXD3D11TextureObject* staging = (GFXD3D11TextureObject*)&(*mStagingTex);
HRESULT hr = D3D11DEVICECONTEXT->Map(staging->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;
U32 offset = 0;
//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!");
AssertFatal(inRect->point.x + inRect->extent.x <= width, "GFXD3D11TextureObject::lock - Invalid lock rect width!");
AssertFatal(inRect->point.y + inRect->extent.y <= height, "GFXD3D11TextureObject::lock - Invalid lock rect height!");
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.bottom = inRect->point.y + inRect->extent.y;
mLockBox.back = depth;
mLockBox.front = 0;
@ -121,49 +134,57 @@ GFXLockedRect *GFXD3D11TextureObject::lock(U32 mipLevel /*= 0*/, RectI *inRect /
{
mLockBox.top = 0;
mLockBox.left = 0;
mLockBox.bottom = height;
mLockBox.right = width;
mLockBox.bottom = height;
mLockBox.back = depth;
mLockBox.front = 0;
}
mLocked = true;
mLockRect.pBits = static_cast<U8*>(mapInfo.pData) + offset;
mLockRect.Pitch = mapInfo.RowPitch;
return (GFXLockedRect*)&mLockRect;
return reinterpret_cast<GFXLockedRect*>(&mLockRect);
}
void GFXD3D11TextureObject::unlock(U32 mipLevel)
void GFXD3D11TextureObject::unlock(U32 mipLevel /*= 0*/, U32 faceIndex /*= 0*/)
{
AssertFatal( mLocked, "GFXD3D11TextureObject::unlock - Attempting to unlock a surface that has not been locked" );
AssertFatal(mLocked, "GFXD3D11TextureObject::unlock - Texture is not locked!");
AssertFatal(faceIndex < 6 || !isCubeMap(), "Invalid cubemap face index!");
//profile in the unlock function because all the heavy lifting is done here
PROFILE_START(GFXD3D11TextureObject_lockRT);
PROFILE_START(GFXD3D11TextureObject_unlock);
ID3D11DeviceContext* pContext = D3D11DEVICECONTEXT;
GFXD3D11TextureObject* pD3DStagingTex = (GFXD3D11TextureObject*)&(*mStagingTex);
ID3D11Resource* pStagingResource = pD3DStagingTex->getResource();
const bool is3D = mStagingTex->getDepth() != 0;
GFXD3D11TextureObject* staging = (GFXD3D11TextureObject*)&(*mStagingTex);
//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);
D3D11DEVICECONTEXT->Unmap(staging->getResource(), mLockedSubresource);
PROFILE_END();
// Copy from staging back to GPU texture
D3D11DEVICECONTEXT->CopySubresourceRegion(
mD3DTexture.Get(),
mLockedSubresource,
0, 0, 0,
staging->getResource(),
mLockedSubresource,
&mLockBox
);
mLockedSubresource = 0;
mLocked = false;
PROFILE_END();
}
void GFXD3D11TextureObject::release()
{
SAFE_RELEASE(mSRView);
SAFE_RELEASE(mRTView);
SAFE_RELEASE(mDSView);
SAFE_RELEASE(mD3DTexture);
SAFE_RELEASE(mD3DSurface);
mSRView.Reset();
mRTView.Reset();
mDSView.Reset();
mD3DTexture.Reset();
mD3DSurface.Reset();
for (auto& faceRTV : mCubeRTV)
faceRTV.Reset();
}
void GFXD3D11TextureObject::zombify()
@ -189,149 +210,206 @@ 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;
AssertFatal(mFormat == GFXFormatR16G16B16A16F || mFormat == GFXFormatR8G8B8A8 ||
mFormat == GFXFormatR8G8B8A8_LINEAR_FORCE || mFormat == GFXFormatR8G8B8A8_SRGB ||
mFormat == GFXFormatR8G8B8,
"GFXD3D11TextureObject::copyToBmp - Unsupported source format.");
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();
AssertFatal(bmp->getWidth() == getWidth(), "Width mismatch between texture and bitmap.");
AssertFatal(bmp->getHeight() == getHeight(), "Height mismatch between texture and bitmap.");
const U32 mipLevels = getMipLevels();
bmp->setHasTransparency(mHasTransparency);
// set some constants
U32 sourceBytesPerPixel = 4;
U32 destBytesPerPixel = 0;
// Figure out bytes per pixel
const bool isFP16 = (bmp->getFormat() == GFXFormatR16G16B16A16F);
const U32 destBpp = (bmp->getFormat() == GFXFormatR8G8B8 ? 3 :
bmp->getFormat() == GFXFormatR16G16B16A16F ? 8 : 4);
const U32 srcBpp = (mFormat == GFXFormatR16G16B16A16F ? 8 : 4);
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);
// --- Create staging texture ---
D3D11_TEXTURE2D_DESC desc = {};
reinterpret_cast<ID3D11Texture2D*>(mD3DTexture.Get())->GetDesc(&desc);
desc.BindFlags = 0;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.Usage = D3D11_USAGE_STAGING;
desc.MiscFlags = 0;
ID3D11Texture2D* pStagingTexture = NULL;
HRESULT hr = D3D11DEVICE->CreateTexture2D(&desc, NULL, &pStagingTexture);
ComPtr<ID3D11Texture2D> stagingTex;
HRESULT hr = D3D11DEVICE->CreateTexture2D(&desc, nullptr, stagingTex.GetAddressOf());
if (FAILED(hr))
{
Con::errorf("GFXD3D11TextureObject::copyToBmp - Failed to create staging texture");
Con::errorf("GFXD3D11TextureObject::copyToBmp - Failed to create staging texture (0x%X)", hr);
return false;
}
//copy the classes texture to the staging texture
D3D11DEVICECONTEXT->CopyResource(pStagingTexture, mD3DTexture);
// --- Copy texture (handle cubemap or 2D) ---
const U32 faceCount = isCubeMap() && bmp->getNumFaces() == 6 ? 6 : 1;
for (U32 mip = 0; mip < mipLevels; mip++)
for (U32 face = 0; face < faceCount; ++face)
{
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))
for (U32 mip = 0; mip < mipLevels; ++mip)
{
//cleanup
SAFE_RELEASE(pStagingTexture);
Con::errorf("GFXD3D11TextureObject::copyToBmp - Failed to map staging texture");
return false;
}
const U32 srcSubRes = D3D11CalcSubresource(mip, face, mipLevels);
// Always map mip-level 0..mipLevels-1 on *slice 0* of the staging texture
const U32 dstSubRes = D3D11CalcSubresource(mip, face, mipLevels);
// set pointers
const U8* srcPtr = (U8*)mappedRes.pData;
U8* destPtr = bmp->getWritableBits(mip);
D3D11DEVICECONTEXT->CopySubresourceRegion(
stagingTex.Get(), dstSubRes, 0, 0, 0,
mD3DTexture.Get(), srcSubRes, nullptr);
// 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)
D3D11_MAPPED_SUBRESOURCE mapped = {};
hr = D3D11DEVICECONTEXT->Map(stagingTex.Get(), dstSubRes, D3D11_MAP_READ, 0, &mapped);
if (FAILED(hr))
{
//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;
Con::errorf("GFXD3D11TextureObject::copyToBmp - Failed to map staging texture (0x%X)", hr);
return false;
}
// skip past the cache data for this row (if any)
srcPtr += sourceCacheSize;
const U8* src = static_cast<const U8*>(mapped.pData);
U8* dst = bmp->getWritableBits(mip, face);
const U32 width = bmp->getWidth(mip);
const U32 height = bmp->getHeight(mip);
for (U32 y = 0; y < height; ++y)
{
const U8* srcRow = src;
U8* dstRow = dst;
for (U32 x = 0; x < width; ++x)
{
if (isFP16)
{
dMemcpy(dstRow, srcRow, sizeof(U16) * 4);
}
else
{
// Convert BGRA → RGB(A)
dstRow[0] = srcRow[2];
dstRow[1] = srcRow[1];
dstRow[2] = srcRow[0];
if (destBpp == 4)
dstRow[3] = srcRow[3];
}
srcRow += srcBpp;
dstRow += destBpp;
}
src += mapped.RowPitch;
dst += width * destBpp;
}
D3D11DEVICECONTEXT->Unmap(stagingTex.Get(), dstSubRes);
}
// 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()
void GFXD3D11TextureObject::generateMipMaps()
{
return mSRView;
}
ID3D11RenderTargetView* GFXD3D11TextureObject::getRTView()
{
return mRTView;
}
ID3D11DepthStencilView* GFXD3D11TextureObject::getDSView()
{
return mDSView;
//Generate mips
D3D11DEVICECONTEXT->GenerateMips(mSRView.Get());
//get mip level count
D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc;
mSRView->GetDesc(&viewDesc);
mMipLevels = viewDesc.TextureCube.MipLevels;
}
ID3D11ShaderResourceView** GFXD3D11TextureObject::getSRViewPtr()
void GFXD3D11TextureObject::updateTextureSlot(const GFXTexHandle& texHandle, const U32 slot, const S32 faceIdx /*=-1*/)
{
return &mSRView;
}
ID3D11RenderTargetView** GFXD3D11TextureObject::getRTViewPtr()
{
return &mRTView;
AssertFatal(slot < getArraySize(), "updateTextureSlot - destination slot out of bounds");
AssertFatal(mFormat == texHandle->getFormat(), "updateTextureSlot - format mismatch");
AssertFatal(getMipLevels() == texHandle->getMipLevels(), "updateTextureSlot - mip level mismatch");
GFXD3D11TextureObject* srcTex = static_cast<GFXD3D11TextureObject*>(texHandle.getPointer());
ID3D11Resource* dstRes = get2DTex();
ID3D11Resource* srcRes = srcTex->get2DTex();
const UINT mipLevels = getMipLevels();
const bool dstIsCube = isCubeMap();
const bool srcIsCube = srcTex->isCubeMap();
const UINT dstArraySize = getArraySize();
const UINT srcArraySize = srcTex->getArraySize();
// Determine number of faces to copy
const UINT faceCount = srcIsCube ? 6 : 1;
const UINT startFace = (faceIdx >= 0) ? faceIdx : 0;
const UINT endFace = (faceIdx >= 0) ? faceIdx + 1 : faceCount;
for (UINT face = startFace; face < endFace; ++face)
{
// Compute source slice
const UINT srcSlice = srcIsCube
? (srcArraySize > 1 ? face + slot * 6 : face) // only add slot*6 if it's a cubemap array
: (srcArraySize > 1 ? face + slot : 0); // otherwise, single 2D texture or 2D array
const UINT dstSlice = dstIsCube
? (dstArraySize > 1 ? face + slot * 6 : face) // only add slot*6 if it's a cubemap array
: (dstArraySize > 1 ? face + slot : 0); // otherwise, single 2D texture or 2D array
for (UINT mip = 0; mip < mipLevels; ++mip)
{
const UINT srcSubresource = D3D11CalcSubresource(mip, srcSlice, mipLevels);
const UINT dstSubresource = D3D11CalcSubresource(mip, dstSlice, mipLevels);
D3D11DEVICECONTEXT->CopySubresourceRegion(dstRes, dstSubresource, 0, 0, 0, srcRes, srcSubresource, nullptr);
}
}
}
ID3D11DepthStencilView** GFXD3D11TextureObject::getDSViewPtr()
void GFXD3D11TextureObject::copyTo(GFXTextureObject* dstTex)
{
return &mDSView;
AssertFatal(dstTex, "GFXD3D11TextureObject::copyTo - destination is null");
GFXD3D11TextureObject* pDstTex = static_cast<GFXD3D11TextureObject*>(dstTex);
ID3D11Texture2D* srcTex = (ID3D11Texture2D*)mD3DTexture.Get();
ID3D11Texture2D* dstTex2D = pDstTex->get2DTex();
D3D11_TEXTURE2D_DESC srcDesc, dstDesc;
srcTex->GetDesc(&srcDesc);
dstTex2D->GetDesc(&dstDesc);
// Sanity check sizes and formats must match for a full copy.
AssertFatal(srcDesc.Width == dstDesc.Width && srcDesc.Height == dstDesc.Height,
"GFXD3D11TextureObject::copyTo - Mismatched texture dimensions");
AssertFatal(srcDesc.Format == dstDesc.Format,
"GFXD3D11TextureObject::copyTo - Mismatched formats");
UINT srcMipLevels = srcDesc.MipLevels ? srcDesc.MipLevels : 1;
UINT dstMipLevels = dstDesc.MipLevels ? dstDesc.MipLevels : 1;
UINT mipLevels = getMin(srcMipLevels, dstMipLevels);
UINT srcArraySize = srcDesc.ArraySize;
UINT dstArraySize = dstDesc.ArraySize;
UINT arraySize = getMin(srcArraySize, dstArraySize);
// Handle cube maps and cube map arrays
bool isCubeSrc = (srcDesc.MiscFlags & D3D11_RESOURCE_MISC_TEXTURECUBE) != 0;
// In cubemaps, ArraySize is always 6 * numCubes
if (isCubeSrc) arraySize = srcArraySize; // 6 or 6*nCubes
for (UINT arraySlice = 0; arraySlice < arraySize; ++arraySlice)
{
for (UINT mip = 0; mip < mipLevels; ++mip)
{
UINT srcSubresource = D3D11CalcSubresource(mip, arraySlice, srcMipLevels);
UINT dstSubresource = D3D11CalcSubresource(mip, arraySlice, dstMipLevels);
D3D11DEVICECONTEXT->CopySubresourceRegion(
dstTex2D, dstSubresource,
0, 0, 0,
srcTex, srcSubresource,
nullptr);
}
}
}

View file

@ -27,55 +27,77 @@
#include "gfx/gfxTextureHandle.h"
#include "gfx/gfxTextureManager.h"
#include <wrl/client.h>
using Microsoft::WRL::ComPtr;
class GFXD3D11TextureObject : public GFXTextureObject
{
protected:
static U32 mTexCount;
GFXTexHandle mStagingTex;
DXGI_MAPPED_RECT mLockRect;
D3D11_BOX mLockBox;
bool mLocked;
bool mLocked = false;
U32 mLockedSubresource;
ID3D11Resource *mD3DTexture;
U32 mLockedSubresource = 0;
// used for z buffers...
ID3D11Texture2D *mD3DSurface;
// Main GPU texture resource (2D / 3D / Cubemap)
ComPtr<ID3D11Resource> mD3DTexture;
ID3D11ShaderResourceView* mSRView; // for shader resource input
ID3D11RenderTargetView* mRTView; // for render targets
ID3D11DepthStencilView* mDSView; //render target view for depth stencil
// Used for Z-targets
ComPtr<ID3D11Texture2D> mD3DSurface;
// Views
ComPtr<ID3D11ShaderResourceView> mSRView; // Shader resource
ComPtr<ID3D11RenderTargetView> mRTView; // Render target
ComPtr<ID3D11DepthStencilView> mDSView; // Depth stencil
// Cubemap face render target views (optional)
ComPtr<ID3D11RenderTargetView> mCubeRTV[6];
public:
GFXD3D11TextureObject( GFXDevice * d, GFXTextureProfile *profile);
GFXD3D11TextureObject( GFXDevice * d, GFXTextureProfile *profile, const U32 arraySize = 1);
~GFXD3D11TextureObject();
ID3D11Resource* getResource(){ return mD3DTexture; }
ID3D11Texture2D* get2DTex(){ return (ID3D11Texture2D*) mD3DTexture; }
ID3D11Texture2D** get2DTexPtr(){ return (ID3D11Texture2D**) &mD3DTexture; }
ID3D11Texture3D* get3DTex(){ return (ID3D11Texture3D*) mD3DTexture; }
ID3D11Texture3D** get3DTexPtr(){ return (ID3D11Texture3D**) &mD3DTexture; }
ID3D11ShaderResourceView* getSRView();
ID3D11RenderTargetView* getRTView();
ID3D11DepthStencilView* getDSView();
// Accessors
ID3D11Resource* getResource() const { return mD3DTexture.Get(); }
ID3D11Texture2D* get2DTex() const;
ID3D11Texture3D* get3DTex() const;
ID3D11Texture2D** get2DTexPtr();
ID3D11Texture3D** get3DTexPtr();
ID3D11ShaderResourceView** getSRViewPtr();
ID3D11RenderTargetView** getRTViewPtr();
ID3D11DepthStencilView** getDSViewPtr();
ID3D11ShaderResourceView* getSRView() const { return mSRView.Get(); }
ID3D11RenderTargetView* getRTView() const { return mRTView.Get(); }
ID3D11DepthStencilView* getDSView() const { return mDSView.Get(); }
ID3D11ShaderResourceView** getSRViewPtr() { return mSRView.GetAddressOf(); }
ID3D11RenderTargetView** getRTViewPtr() { return mRTView.GetAddressOf(); }
ID3D11DepthStencilView** getDSViewPtr() { return mDSView.GetAddressOf(); }
// Cubemap face RTV access (for render-to-cubemap)
ID3D11RenderTargetView* getCubeFaceRTView(U32 face) const
{
AssertFatal(isCubeMap(), "Not a cubemap texture!");
AssertFatal(face < 6, "Invalid cubemap face index!");
return mCubeRTV[face].Get();
}
ID3D11RenderTargetView** getCubeFaceRTViewPtr(U32 face);
void release();
bool isManaged; //setting to true tells this texture not to be released from being zombify
GFXLockedRect * lock(U32 mipLevel = 0, RectI *inRect = NULL) override;
void unlock(U32 mipLevel = 0 ) override;
GFXLockedRect* lock(U32 mipLevel = 0, RectI* inRect = NULL, U32 faceIndex = 0) override;
void unlock(U32 mipLevel = 0, U32 faceIndex = 0) override;
bool copyToBmp(GBitmap* bmp) override;
ID3D11Texture2D* getSurface() {return mD3DSurface;}
ID3D11Texture2D** getSurfacePtr() {return &mD3DSurface;}
void generateMipMaps() override;
void updateTextureSlot(const GFXTexHandle& texHandle, const U32 slot, const S32 face = -1) override;
void copyTo(GFXTextureObject* dstTex) override;
ID3D11Texture2D* getSurface() {return mD3DSurface.Get();}
ID3D11Texture2D** getSurfacePtr() {return mD3DSurface.GetAddressOf();}
// GFXResource
void zombify() override;