Commit 6982260b by Austin Kinross Committed by Jamie Madill

Reduce CPU texture usage in D3D11 where possible

Change-Id: I3186d78fa0a5c676611806c6f553c5c7ad06f56a Reviewed-on: https://chromium-review.googlesource.com/212118Tested-by: 's avatarAustin Kinross <aukinros@microsoft.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 71117e2c
......@@ -219,12 +219,15 @@ TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
TextureD3D_2D::~TextureD3D_2D()
{
SafeDelete(mTexStorage);
// Delete the Images before the TextureStorage.
// Images might be relying on the TextureStorage for some of their data.
// If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images.
for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
{
delete mImageArray[i];
}
SafeDelete(mTexStorage);
}
Image *TextureD3D_2D::getImage(int level, int layer) const
......@@ -762,8 +765,9 @@ TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
TextureD3D_Cube::~TextureD3D_Cube()
{
SafeDelete(mTexStorage);
// Delete the Images before the TextureStorage.
// Images might be relying on the TextureStorage for some of their data.
// If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images.
for (int i = 0; i < 6; i++)
{
for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
......@@ -771,6 +775,8 @@ TextureD3D_Cube::~TextureD3D_Cube()
SafeDelete(mImageArray[i][j]);
}
}
SafeDelete(mTexStorage);
}
Image *TextureD3D_Cube::getImage(int level, int layer) const
......@@ -1283,12 +1289,15 @@ TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
TextureD3D_3D::~TextureD3D_3D()
{
SafeDelete(mTexStorage);
// Delete the Images before the TextureStorage.
// Images might be relying on the TextureStorage for some of their data.
// If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images.
for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
{
delete mImageArray[i];
}
SafeDelete(mTexStorage);
}
Image *TextureD3D_3D::getImage(int level, int layer) const
......@@ -1798,9 +1807,11 @@ TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
TextureD3D_2DArray::~TextureD3D_2DArray()
{
SafeDelete(mTexStorage);
// Delete the Images before the TextureStorage.
// Images might be relying on the TextureStorage for some of their data.
// If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images.
deleteImages();
SafeDelete(mTexStorage);
}
Image *TextureD3D_2DArray::getImage(int level, int layer) const
......
......@@ -27,11 +27,17 @@ Image11::Image11()
mStagingTexture = NULL;
mRenderer = NULL;
mDXGIFormat = DXGI_FORMAT_UNKNOWN;
mRecoverFromStorage = false;
mAssociatedStorage = NULL;
mAssociatedStorageLevel = 0;
mAssociatedStorageLayerTarget = 0;
mRecoveredFromStorageCount = 0;
}
Image11::~Image11()
{
SafeRelease(mStagingTexture);
disassociateStorage();
releaseStagingTexture();
}
Image11 *Image11::makeImage11(Image *img)
......@@ -82,33 +88,117 @@ void Image11::generateMipmap(Image11 *dest, Image11 *src)
bool Image11::isDirty() const
{
// Make sure that this image is marked as dirty even if the staging texture hasn't been created yet
// if initialization is required before use.
return (mDirty && (mStagingTexture || d3d11::GetTextureFormatInfo(mInternalFormat).dataInitializerFunction != NULL));
// If mDirty is true
// AND mStagingTexture doesn't exist AND mStagingTexture doesn't need to be recovered from TextureStorage
// AND the texture doesn't require init data (i.e. a blank new texture will suffice)
// then isDirty should still return false.
if (mDirty && !mStagingTexture && !mRecoverFromStorage && !(d3d11::GetTextureFormatInfo(mInternalFormat).dataInitializerFunction != NULL))
{
return false;
}
return mDirty;
}
bool Image11::copyToStorage(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
{
TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage->getStorageInstance());
return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, 0, xoffset, yoffset, 0, width, height, 1);
return copyToStorageImpl(storage11, level, 0, xoffset, yoffset, width, height);
}
bool Image11::copyToStorage(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
{
TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage->getStorageInstance());
return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, face, xoffset, yoffset, 0, width, height, 1);
return copyToStorageImpl(storage11, level, face, xoffset, yoffset, width, height);
}
bool Image11::copyToStorage(TextureStorageInterface3D *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
{
TextureStorage11_3D *storage11 = TextureStorage11_3D::makeTextureStorage11_3D(storage->getStorageInstance());
return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, 0, xoffset, yoffset, zoffset, width, height, depth);
return copyToStorageImpl(storage11, level, 0, xoffset, yoffset, width, height);
}
bool Image11::copyToStorage(TextureStorageInterface2DArray *storage, int level, GLint xoffset, GLint yoffset, GLint arrayLayer, GLsizei width, GLsizei height)
{
TextureStorage11_2DArray *storage11 = TextureStorage11_2DArray::makeTextureStorage11_2DArray(storage->getStorageInstance());
return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, arrayLayer, xoffset, yoffset, 0, width, height, 1);
return copyToStorageImpl(storage11, level, arrayLayer, xoffset, yoffset, width, height);
}
bool Image11::copyToStorageImpl(TextureStorage11 *storage11, int level, int layerTarget, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
{
// If an app's behavior results in an Image11 copying its data to/from to a TextureStorage multiple times,
// then we should just keep the staging texture around to prevent the copying from impacting perf.
// We allow the Image11 to copy its data to/from TextureStorage once.
// This accounts for an app making a late call to glGenerateMipmap.
bool attemptToReleaseStagingTexture = (mRecoveredFromStorageCount < 2);
if (attemptToReleaseStagingTexture)
{
// If another image is relying on this Storage for its data, then we must let it recover its data before we overwrite it.
storage11->releaseAssociatedImage(level, layerTarget, this);
}
bool updateSubresourceSuccess = storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, layerTarget, xoffset, yoffset, 0, width, height, 1);
// Once the image data has been copied into the Storage, we can release it locally.
if (attemptToReleaseStagingTexture && updateSubresourceSuccess)
{
storage11->associateImage(this, level, layerTarget);
releaseStagingTexture();
mRecoverFromStorage = true;
mAssociatedStorage = storage11;
mAssociatedStorageLevel = level;
mAssociatedStorageLayerTarget = layerTarget;
}
return updateSubresourceSuccess;
}
bool Image11::isAssociatedStorageValid(TextureStorage11* textureStorage) const
{
return (mAssociatedStorage == textureStorage);
}
bool Image11::recoverFromAssociatedStorage()
{
if (mRecoverFromStorage)
{
createStagingTexture();
bool textureStorageCorrect = mAssociatedStorage->isAssociatedImageValid(mAssociatedStorageLevel, mAssociatedStorageLayerTarget, this);
// This means that the cached TextureStorage has been modified after this Image11 released its copy of its data.
// This should not have happened. The TextureStorage should have told this Image11 to recover its data before it was overwritten.
ASSERT(textureStorageCorrect);
if (textureStorageCorrect)
{
// CopySubResource from the Storage to the Staging texture
mAssociatedStorage->copySubresourceLevel(mStagingTexture, mStagingSubresource, mAssociatedStorageLevel, mAssociatedStorageLayerTarget, 0, 0, 0, mWidth, mHeight, mDepth);
mRecoveredFromStorageCount += 1;
}
// Reset all the recovery parameters, even if the texture storage association is broken.
disassociateStorage();
return textureStorageCorrect;
}
return false;
}
void Image11::disassociateStorage()
{
if (mRecoverFromStorage)
{
// Make the texturestorage release the Image11 too
mAssociatedStorage->disassociateImage(mAssociatedStorageLevel, mAssociatedStorageLayerTarget, this);
mRecoverFromStorage = false;
mAssociatedStorage = NULL;
mAssociatedStorageLevel = 0;
mAssociatedStorageLayerTarget = 0;
}
}
bool Image11::redefine(Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease)
......@@ -118,6 +208,11 @@ bool Image11::redefine(Renderer *renderer, GLenum target, GLenum internalformat,
mInternalFormat != internalformat ||
forceRelease)
{
// End the association with the TextureStorage, since that data will be out of date.
// Also reset mRecoveredFromStorageCount since this Image is getting completely redefined.
disassociateStorage();
mRecoveredFromStorageCount = 0;
mRenderer = Renderer11::makeRenderer11(renderer);
mWidth = width;
......@@ -313,6 +408,11 @@ ID3D11Resource *Image11::getStagingTexture()
return mStagingTexture;
}
void Image11::releaseStagingTexture()
{
SafeRelease(mStagingTexture);
}
unsigned int Image11::getStagingSubresource()
{
createStagingTexture();
......@@ -434,6 +534,9 @@ HRESULT Image11::map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map)
{
createStagingTexture();
// We must recover from the TextureStorage if necessary, even for D3D11_MAP_WRITE.
recoverFromAssociatedStorage();
HRESULT result = E_FAIL;
if (mStagingTexture)
......
......@@ -25,6 +25,7 @@ class Renderer;
class Renderer11;
class TextureStorageInterface2D;
class TextureStorageInterfaceCube;
class TextureStorage11;
class Image11 : public ImageD3D
{
......@@ -54,6 +55,10 @@ class Image11 : public ImageD3D
virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source);
bool recoverFromAssociatedStorage();
bool isAssociatedStorageValid(TextureStorage11* textureStorage) const;
void disassociateStorage();
protected:
HRESULT map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map);
void unmap();
......@@ -61,15 +66,24 @@ class Image11 : public ImageD3D
private:
DISALLOW_COPY_AND_ASSIGN(Image11);
bool copyToStorageImpl(TextureStorage11 *storage11, int level, int layerTarget, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height);
ID3D11Resource *getStagingTexture();
unsigned int getStagingSubresource();
void createStagingTexture();
void releaseStagingTexture();
Renderer11 *mRenderer;
DXGI_FORMAT mDXGIFormat;
ID3D11Resource *mStagingTexture;
unsigned int mStagingSubresource;
bool mRecoverFromStorage;
TextureStorage11 *mAssociatedStorage;
int mAssociatedStorageLevel;
int mAssociatedStorageLayerTarget;
unsigned int mRecoveredFromStorageCount;
};
}
......
......@@ -20,6 +20,7 @@ class RenderTarget11;
class Renderer;
class Renderer11;
class SwapChain11;
class Image11;
class TextureStorage11 : public TextureStorage
{
......@@ -55,6 +56,15 @@ class TextureStorage11 : public TextureStorage
int layerTarget, GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLsizei depth);
bool copySubresourceLevel(ID3D11Resource* dstTexture, unsigned int dstSubresource, int level,
int layerTarget, GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLsizei depth);
virtual void associateImage(Image11* image, int level, int layerTarget) = 0;
virtual void disassociateImage(int level, int layerTarget, Image11* expectedImage) = 0;
virtual bool isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage) = 0;
virtual void releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage) = 0;
protected:
TextureStorage11(Renderer *renderer, UINT bindFlags);
void generateMipmapLayer(RenderTarget11 *source, RenderTarget11 *dest);
......@@ -152,6 +162,11 @@ class TextureStorage11_2D : public TextureStorage11
virtual void generateMipmap(int level);
virtual void associateImage(Image11* image, int level, int layerTarget);
virtual void disassociateImage(int level, int layerTarget, Image11* expectedImage);
virtual bool isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage);
virtual void releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage);
protected:
virtual ID3D11Resource *getSwizzleTexture();
virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel);
......@@ -168,6 +183,8 @@ class TextureStorage11_2D : public TextureStorage11
ID3D11Texture2D *mSwizzleTexture;
ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
Image11 *mAssociatedImages[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
};
class TextureStorage11_Cube : public TextureStorage11
......@@ -183,6 +200,11 @@ class TextureStorage11_Cube : public TextureStorage11
virtual void generateMipmap(int faceIndex, int level);
virtual void associateImage(Image11* image, int level, int layerTarget);
virtual void disassociateImage(int level, int layerTarget, Image11* expectedImage);
virtual bool isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage);
virtual void releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage);
protected:
virtual ID3D11Resource *getSwizzleTexture();
virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel);
......@@ -199,6 +221,8 @@ class TextureStorage11_Cube : public TextureStorage11
ID3D11Texture2D *mSwizzleTexture;
ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
Image11 *mAssociatedImages[6][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
};
class TextureStorage11_3D : public TextureStorage11
......@@ -216,6 +240,11 @@ class TextureStorage11_3D : public TextureStorage11
virtual void generateMipmap(int level);
virtual void associateImage(Image11* image, int level, int layerTarget);
virtual void disassociateImage(int level, int layerTarget, Image11* expectedImage);
virtual bool isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage);
virtual void releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage);
protected:
virtual ID3D11Resource *getSwizzleTexture();
virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel);
......@@ -236,6 +265,8 @@ class TextureStorage11_3D : public TextureStorage11
ID3D11Texture3D *mTexture;
ID3D11Texture3D *mSwizzleTexture;
ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
Image11 *mAssociatedImages[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
};
class TextureStorage11_2DArray : public TextureStorage11
......@@ -252,6 +283,11 @@ class TextureStorage11_2DArray : public TextureStorage11
virtual void generateMipmap(int level);
virtual void associateImage(Image11* image, int level, int layerTarget);
virtual void disassociateImage(int level, int layerTarget, Image11* expectedImage);
virtual bool isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage);
virtual void releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage);
protected:
virtual ID3D11Resource *getSwizzleTexture();
virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel);
......@@ -271,6 +307,9 @@ class TextureStorage11_2DArray : public TextureStorage11
ID3D11Texture2D *mSwizzleTexture;
ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
typedef std::map<LevelLayerKey, Image11*> ImageMap;
ImageMap mAssociatedImages;
};
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment