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) ...@@ -219,12 +219,15 @@ TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
TextureD3D_2D::~TextureD3D_2D() 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) for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
{ {
delete mImageArray[i]; delete mImageArray[i];
} }
SafeDelete(mTexStorage);
} }
Image *TextureD3D_2D::getImage(int level, int layer) const Image *TextureD3D_2D::getImage(int level, int layer) const
...@@ -762,8 +765,9 @@ TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer) ...@@ -762,8 +765,9 @@ TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
TextureD3D_Cube::~TextureD3D_Cube() 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 i = 0; i < 6; i++)
{ {
for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j) for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
...@@ -771,6 +775,8 @@ TextureD3D_Cube::~TextureD3D_Cube() ...@@ -771,6 +775,8 @@ TextureD3D_Cube::~TextureD3D_Cube()
SafeDelete(mImageArray[i][j]); SafeDelete(mImageArray[i][j]);
} }
} }
SafeDelete(mTexStorage);
} }
Image *TextureD3D_Cube::getImage(int level, int layer) const Image *TextureD3D_Cube::getImage(int level, int layer) const
...@@ -1283,12 +1289,15 @@ TextureD3D_3D::TextureD3D_3D(Renderer *renderer) ...@@ -1283,12 +1289,15 @@ TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
TextureD3D_3D::~TextureD3D_3D() 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) for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
{ {
delete mImageArray[i]; delete mImageArray[i];
} }
SafeDelete(mTexStorage);
} }
Image *TextureD3D_3D::getImage(int level, int layer) const Image *TextureD3D_3D::getImage(int level, int layer) const
...@@ -1798,9 +1807,11 @@ TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer) ...@@ -1798,9 +1807,11 @@ TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
TextureD3D_2DArray::~TextureD3D_2DArray() 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(); deleteImages();
SafeDelete(mTexStorage);
} }
Image *TextureD3D_2DArray::getImage(int level, int layer) const Image *TextureD3D_2DArray::getImage(int level, int layer) const
......
...@@ -27,11 +27,17 @@ Image11::Image11() ...@@ -27,11 +27,17 @@ Image11::Image11()
mStagingTexture = NULL; mStagingTexture = NULL;
mRenderer = NULL; mRenderer = NULL;
mDXGIFormat = DXGI_FORMAT_UNKNOWN; mDXGIFormat = DXGI_FORMAT_UNKNOWN;
mRecoverFromStorage = false;
mAssociatedStorage = NULL;
mAssociatedStorageLevel = 0;
mAssociatedStorageLayerTarget = 0;
mRecoveredFromStorageCount = 0;
} }
Image11::~Image11() Image11::~Image11()
{ {
SafeRelease(mStagingTexture); disassociateStorage();
releaseStagingTexture();
} }
Image11 *Image11::makeImage11(Image *img) Image11 *Image11::makeImage11(Image *img)
...@@ -82,33 +88,117 @@ void Image11::generateMipmap(Image11 *dest, Image11 *src) ...@@ -82,33 +88,117 @@ void Image11::generateMipmap(Image11 *dest, Image11 *src)
bool Image11::isDirty() const bool Image11::isDirty() const
{ {
// Make sure that this image is marked as dirty even if the staging texture hasn't been created yet // If mDirty is true
// if initialization is required before use. // AND mStagingTexture doesn't exist AND mStagingTexture doesn't need to be recovered from TextureStorage
return (mDirty && (mStagingTexture || d3d11::GetTextureFormatInfo(mInternalFormat).dataInitializerFunction != NULL)); // 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) bool Image11::copyToStorage(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
{ {
TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage->getStorageInstance()); 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) 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()); 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) 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()); 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) 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()); 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) 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, ...@@ -118,6 +208,11 @@ bool Image11::redefine(Renderer *renderer, GLenum target, GLenum internalformat,
mInternalFormat != internalformat || mInternalFormat != internalformat ||
forceRelease) 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); mRenderer = Renderer11::makeRenderer11(renderer);
mWidth = width; mWidth = width;
...@@ -313,6 +408,11 @@ ID3D11Resource *Image11::getStagingTexture() ...@@ -313,6 +408,11 @@ ID3D11Resource *Image11::getStagingTexture()
return mStagingTexture; return mStagingTexture;
} }
void Image11::releaseStagingTexture()
{
SafeRelease(mStagingTexture);
}
unsigned int Image11::getStagingSubresource() unsigned int Image11::getStagingSubresource()
{ {
createStagingTexture(); createStagingTexture();
...@@ -434,6 +534,9 @@ HRESULT Image11::map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map) ...@@ -434,6 +534,9 @@ HRESULT Image11::map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map)
{ {
createStagingTexture(); createStagingTexture();
// We must recover from the TextureStorage if necessary, even for D3D11_MAP_WRITE.
recoverFromAssociatedStorage();
HRESULT result = E_FAIL; HRESULT result = E_FAIL;
if (mStagingTexture) if (mStagingTexture)
......
...@@ -25,6 +25,7 @@ class Renderer; ...@@ -25,6 +25,7 @@ class Renderer;
class Renderer11; class Renderer11;
class TextureStorageInterface2D; class TextureStorageInterface2D;
class TextureStorageInterfaceCube; class TextureStorageInterfaceCube;
class TextureStorage11;
class Image11 : public ImageD3D class Image11 : public ImageD3D
{ {
...@@ -54,6 +55,10 @@ 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); 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: protected:
HRESULT map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map); HRESULT map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map);
void unmap(); void unmap();
...@@ -61,15 +66,24 @@ class Image11 : public ImageD3D ...@@ -61,15 +66,24 @@ class Image11 : public ImageD3D
private: private:
DISALLOW_COPY_AND_ASSIGN(Image11); DISALLOW_COPY_AND_ASSIGN(Image11);
bool copyToStorageImpl(TextureStorage11 *storage11, int level, int layerTarget, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height);
ID3D11Resource *getStagingTexture(); ID3D11Resource *getStagingTexture();
unsigned int getStagingSubresource(); unsigned int getStagingSubresource();
void createStagingTexture(); void createStagingTexture();
void releaseStagingTexture();
Renderer11 *mRenderer; Renderer11 *mRenderer;
DXGI_FORMAT mDXGIFormat; DXGI_FORMAT mDXGIFormat;
ID3D11Resource *mStagingTexture; ID3D11Resource *mStagingTexture;
unsigned int mStagingSubresource; unsigned int mStagingSubresource;
bool mRecoverFromStorage;
TextureStorage11 *mAssociatedStorage;
int mAssociatedStorageLevel;
int mAssociatedStorageLayerTarget;
unsigned int mRecoveredFromStorageCount;
}; };
} }
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h" #include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h"
#include "libGLESv2/renderer/d3d/d3d11/Blit11.h" #include "libGLESv2/renderer/d3d/d3d11/Blit11.h"
#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h" #include "libGLESv2/renderer/d3d/d3d11/formatutils11.h"
#include "libGLESv2/renderer/d3d/d3d11/Image11.h"
#include "common/utilities.h" #include "common/utilities.h"
#include "libGLESv2/main.h" #include "libGLESv2/main.h"
...@@ -342,6 +343,27 @@ bool TextureStorage11::updateSubresourceLevel(ID3D11Resource *srcTexture, unsign ...@@ -342,6 +343,27 @@ bool TextureStorage11::updateSubresourceLevel(ID3D11Resource *srcTexture, unsign
return false; return false;
} }
bool TextureStorage11::copySubresourceLevel(ID3D11Resource* dstTexture, unsigned int dstSubresource,
int level, int layerTarget, GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLsizei depth)
{
if (dstTexture)
{
ID3D11Resource *srcTexture = getResource();
unsigned int srcSubresource = getSubresourceIndex(level + mTopLevel, layerTarget);
ASSERT(srcTexture);
ID3D11DeviceContext *context = mRenderer->getDeviceContext();
context->CopySubresourceRegion(dstTexture, dstSubresource, xoffset, yoffset, zoffset,
srcTexture, srcSubresource, NULL);
return true;
}
return false;
}
void TextureStorage11::generateMipmapLayer(RenderTarget11 *source, RenderTarget11 *dest) void TextureStorage11::generateMipmapLayer(RenderTarget11 *source, RenderTarget11 *dest)
{ {
if (source && dest) if (source && dest)
...@@ -383,6 +405,7 @@ TextureStorage11_2D::TextureStorage11_2D(Renderer *renderer, SwapChain11 *swapch ...@@ -383,6 +405,7 @@ TextureStorage11_2D::TextureStorage11_2D(Renderer *renderer, SwapChain11 *swapch
for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
{ {
mAssociatedImages[i] = NULL;
mRenderTarget[i] = NULL; mRenderTarget[i] = NULL;
mSwizzleRenderTargets[i] = NULL; mSwizzleRenderTargets[i] = NULL;
} }
...@@ -422,6 +445,7 @@ TextureStorage11_2D::TextureStorage11_2D(Renderer *renderer, GLenum internalform ...@@ -422,6 +445,7 @@ TextureStorage11_2D::TextureStorage11_2D(Renderer *renderer, GLenum internalform
for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
{ {
mAssociatedImages[i] = NULL;
mRenderTarget[i] = NULL; mRenderTarget[i] = NULL;
mSwizzleRenderTargets[i] = NULL; mSwizzleRenderTargets[i] = NULL;
} }
...@@ -484,6 +508,21 @@ TextureStorage11_2D::TextureStorage11_2D(Renderer *renderer, GLenum internalform ...@@ -484,6 +508,21 @@ TextureStorage11_2D::TextureStorage11_2D(Renderer *renderer, GLenum internalform
TextureStorage11_2D::~TextureStorage11_2D() TextureStorage11_2D::~TextureStorage11_2D()
{ {
for (unsigned i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
{
if (mAssociatedImages[i] != NULL)
{
bool imageAssociationCorrect = mAssociatedImages[i]->isAssociatedStorageValid(this);
ASSERT(imageAssociationCorrect);
if (imageAssociationCorrect)
{
// We must let the Images recover their data before we delete it from the TextureStorage.
mAssociatedImages[i]->recoverFromAssociatedStorage();
}
}
}
SafeRelease(mTexture); SafeRelease(mTexture);
SafeRelease(mSwizzleTexture); SafeRelease(mSwizzleTexture);
...@@ -500,6 +539,69 @@ TextureStorage11_2D *TextureStorage11_2D::makeTextureStorage11_2D(TextureStorage ...@@ -500,6 +539,69 @@ TextureStorage11_2D *TextureStorage11_2D::makeTextureStorage11_2D(TextureStorage
return static_cast<TextureStorage11_2D*>(storage); return static_cast<TextureStorage11_2D*>(storage);
} }
void TextureStorage11_2D::associateImage(Image11* image, int level, int layerTarget)
{
ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
{
mAssociatedImages[level] = image;
}
}
bool TextureStorage11_2D::isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage)
{
if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
{
// This validation check should never return false. It means the Image/TextureStorage association is broken.
bool retValue = (mAssociatedImages[level] == expectedImage);
ASSERT(retValue);
return retValue;
}
return false;
}
// disassociateImage allows an Image to end its association with a Storage.
void TextureStorage11_2D::disassociateImage(int level, int layerTarget, Image11* expectedImage)
{
ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
{
ASSERT(mAssociatedImages[level] == expectedImage);
if (mAssociatedImages[level] == expectedImage)
{
mAssociatedImages[level] = NULL;
}
}
}
// releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association.
void TextureStorage11_2D::releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage)
{
ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
{
// No need to let the old Image recover its data, if it is also the incoming Image.
if (mAssociatedImages[level] != NULL && mAssociatedImages[level] != incomingImage)
{
// Ensure that the Image is still associated with this TextureStorage. This should be true.
bool imageAssociationCorrect = mAssociatedImages[level]->isAssociatedStorageValid(this);
ASSERT(imageAssociationCorrect);
if (imageAssociationCorrect)
{
// Force the image to recover from storage before its data is overwritten.
// This will reset mAssociatedImages[level] to NULL too.
mAssociatedImages[level]->recoverFromAssociatedStorage();
}
}
}
}
ID3D11Resource *TextureStorage11_2D::getResource() const ID3D11Resource *TextureStorage11_2D::getResource() const
{ {
return mTexture; return mTexture;
...@@ -693,6 +795,7 @@ TextureStorage11_Cube::TextureStorage11_Cube(Renderer *renderer, GLenum internal ...@@ -693,6 +795,7 @@ TextureStorage11_Cube::TextureStorage11_Cube(Renderer *renderer, GLenum internal
mSwizzleRenderTargets[level] = NULL; mSwizzleRenderTargets[level] = NULL;
for (unsigned int face = 0; face < 6; face++) for (unsigned int face = 0; face < 6; face++)
{ {
mAssociatedImages[face][level] = NULL;
mRenderTarget[face][level] = NULL; mRenderTarget[face][level] = NULL;
} }
} }
...@@ -750,6 +853,24 @@ TextureStorage11_Cube::TextureStorage11_Cube(Renderer *renderer, GLenum internal ...@@ -750,6 +853,24 @@ TextureStorage11_Cube::TextureStorage11_Cube(Renderer *renderer, GLenum internal
TextureStorage11_Cube::~TextureStorage11_Cube() TextureStorage11_Cube::~TextureStorage11_Cube()
{ {
for (unsigned int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
{
for (unsigned int face = 0; face < 6; face++)
{
if (mAssociatedImages[face][level] != NULL)
{
bool imageAssociationCorrect = mAssociatedImages[face][level]->isAssociatedStorageValid(this);
ASSERT(imageAssociationCorrect);
if (imageAssociationCorrect)
{
// We must let the Images recover their data before we delete it from the TextureStorage.
mAssociatedImages[face][level]->recoverFromAssociatedStorage();
}
}
}
}
SafeRelease(mTexture); SafeRelease(mTexture);
SafeRelease(mSwizzleTexture); SafeRelease(mSwizzleTexture);
...@@ -769,6 +890,84 @@ TextureStorage11_Cube *TextureStorage11_Cube::makeTextureStorage11_Cube(TextureS ...@@ -769,6 +890,84 @@ TextureStorage11_Cube *TextureStorage11_Cube::makeTextureStorage11_Cube(TextureS
return static_cast<TextureStorage11_Cube*>(storage); return static_cast<TextureStorage11_Cube*>(storage);
} }
void TextureStorage11_Cube::associateImage(Image11* image, int level, int layerTarget)
{
ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
ASSERT(0 <= layerTarget && layerTarget < 6);
if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
{
if (0 <= layerTarget && layerTarget < 6)
{
mAssociatedImages[layerTarget][level] = image;
}
}
}
bool TextureStorage11_Cube::isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage)
{
if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
{
if (0 <= layerTarget && layerTarget < 6)
{
// This validation check should never return false. It means the Image/TextureStorage association is broken.
bool retValue = (mAssociatedImages[layerTarget][level] == expectedImage);
ASSERT(retValue);
return retValue;
}
}
return false;
}
// disassociateImage allows an Image to end its association with a Storage.
void TextureStorage11_Cube::disassociateImage(int level, int layerTarget, Image11* expectedImage)
{
ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
ASSERT(0 <= layerTarget && layerTarget < 6);
if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
{
if (0 <= layerTarget && layerTarget < 6)
{
ASSERT(mAssociatedImages[layerTarget][level] == expectedImage);
if (mAssociatedImages[layerTarget][level] == expectedImage)
{
mAssociatedImages[layerTarget][level] = NULL;
}
}
}
}
// releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association.
void TextureStorage11_Cube::releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage)
{
ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
ASSERT(0 <= layerTarget && layerTarget < 6);
if ((0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
{
if (0 <= layerTarget && layerTarget < 6)
{
// No need to let the old Image recover its data, if it is also the incoming Image.
if (mAssociatedImages[layerTarget][level] != NULL && mAssociatedImages[layerTarget][level] != incomingImage)
{
// Ensure that the Image is still associated with this TextureStorage. This should be true.
bool imageAssociationCorrect = mAssociatedImages[layerTarget][level]->isAssociatedStorageValid(this);
ASSERT(imageAssociationCorrect);
if (imageAssociationCorrect)
{
// Force the image to recover from storage before its data is overwritten.
// This will reset mAssociatedImages[level] to NULL too.
mAssociatedImages[layerTarget][level]->recoverFromAssociatedStorage();
}
}
}
}
}
ID3D11Resource *TextureStorage11_Cube::getResource() const ID3D11Resource *TextureStorage11_Cube::getResource() const
{ {
return mTexture; return mTexture;
...@@ -995,6 +1194,7 @@ TextureStorage11_3D::TextureStorage11_3D(Renderer *renderer, GLenum internalform ...@@ -995,6 +1194,7 @@ TextureStorage11_3D::TextureStorage11_3D(Renderer *renderer, GLenum internalform
for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++) for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
{ {
mAssociatedImages[i] = NULL;
mLevelRenderTargets[i] = NULL; mLevelRenderTargets[i] = NULL;
mSwizzleRenderTargets[i] = NULL; mSwizzleRenderTargets[i] = NULL;
} }
...@@ -1055,6 +1255,21 @@ TextureStorage11_3D::TextureStorage11_3D(Renderer *renderer, GLenum internalform ...@@ -1055,6 +1255,21 @@ TextureStorage11_3D::TextureStorage11_3D(Renderer *renderer, GLenum internalform
TextureStorage11_3D::~TextureStorage11_3D() TextureStorage11_3D::~TextureStorage11_3D()
{ {
for (unsigned i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
{
if (mAssociatedImages[i] != NULL)
{
bool imageAssociationCorrect = mAssociatedImages[i]->isAssociatedStorageValid(this);
ASSERT(imageAssociationCorrect);
if (imageAssociationCorrect)
{
// We must let the Images recover their data before we delete it from the TextureStorage.
mAssociatedImages[i]->recoverFromAssociatedStorage();
}
}
}
SafeRelease(mTexture); SafeRelease(mTexture);
SafeRelease(mSwizzleTexture); SafeRelease(mSwizzleTexture);
...@@ -1077,6 +1292,69 @@ TextureStorage11_3D *TextureStorage11_3D::makeTextureStorage11_3D(TextureStorage ...@@ -1077,6 +1292,69 @@ TextureStorage11_3D *TextureStorage11_3D::makeTextureStorage11_3D(TextureStorage
return static_cast<TextureStorage11_3D*>(storage); return static_cast<TextureStorage11_3D*>(storage);
} }
void TextureStorage11_3D::associateImage(Image11* image, int level, int layerTarget)
{
ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
{
mAssociatedImages[level] = image;
}
}
bool TextureStorage11_3D::isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage)
{
if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
{
// This validation check should never return false. It means the Image/TextureStorage association is broken.
bool retValue = (mAssociatedImages[level] == expectedImage);
ASSERT(retValue);
return retValue;
}
return false;
}
// disassociateImage allows an Image to end its association with a Storage.
void TextureStorage11_3D::disassociateImage(int level, int layerTarget, Image11* expectedImage)
{
ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
{
ASSERT(mAssociatedImages[level] == expectedImage);
if (mAssociatedImages[level] == expectedImage)
{
mAssociatedImages[level] = NULL;
}
}
}
// releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association.
void TextureStorage11_3D::releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage)
{
ASSERT((0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS));
if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
{
// No need to let the old Image recover its data, if it is also the incoming Image.
if (mAssociatedImages[level] != NULL && mAssociatedImages[level] != incomingImage)
{
// Ensure that the Image is still associated with this TextureStorage. This should be true.
bool imageAssociationCorrect = mAssociatedImages[level]->isAssociatedStorageValid(this);
ASSERT(imageAssociationCorrect);
if (imageAssociationCorrect)
{
// Force the image to recover from storage before its data is overwritten.
// This will reset mAssociatedImages[level] to NULL too.
mAssociatedImages[level]->recoverFromAssociatedStorage();
}
}
}
}
ID3D11Resource *TextureStorage11_3D::getResource() const ID3D11Resource *TextureStorage11_3D::getResource() const
{ {
return mTexture; return mTexture;
...@@ -1361,6 +1639,19 @@ TextureStorage11_2DArray::TextureStorage11_2DArray(Renderer *renderer, GLenum in ...@@ -1361,6 +1639,19 @@ TextureStorage11_2DArray::TextureStorage11_2DArray(Renderer *renderer, GLenum in
TextureStorage11_2DArray::~TextureStorage11_2DArray() TextureStorage11_2DArray::~TextureStorage11_2DArray()
{ {
for (ImageMap::iterator i = mAssociatedImages.begin(); i != mAssociatedImages.end(); i++)
{
bool imageAssociationCorrect = i->second->isAssociatedStorageValid(this);
ASSERT(imageAssociationCorrect);
if (imageAssociationCorrect)
{
// We must let the Images recover their data before we delete it from the TextureStorage.
i->second->recoverFromAssociatedStorage();
}
}
mAssociatedImages.clear();
SafeRelease(mTexture); SafeRelease(mTexture);
SafeRelease(mSwizzleTexture); SafeRelease(mSwizzleTexture);
...@@ -1382,6 +1673,66 @@ TextureStorage11_2DArray *TextureStorage11_2DArray::makeTextureStorage11_2DArray ...@@ -1382,6 +1673,66 @@ TextureStorage11_2DArray *TextureStorage11_2DArray::makeTextureStorage11_2DArray
return static_cast<TextureStorage11_2DArray*>(storage); return static_cast<TextureStorage11_2DArray*>(storage);
} }
void TextureStorage11_2DArray::associateImage(Image11* image, int level, int layerTarget)
{
ASSERT(0 <= level && level < getLevelCount());
if (0 <= level && level < getLevelCount())
{
LevelLayerKey key(level, layerTarget);
mAssociatedImages[key] = image;
}
}
bool TextureStorage11_2DArray::isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage)
{
LevelLayerKey key(level, layerTarget);
// This validation check should never return false. It means the Image/TextureStorage association is broken.
bool retValue = (mAssociatedImages.find(key) != mAssociatedImages.end() && (mAssociatedImages[key] == expectedImage));
ASSERT(retValue);
return retValue;
}
// disassociateImage allows an Image to end its association with a Storage.
void TextureStorage11_2DArray::disassociateImage(int level, int layerTarget, Image11* expectedImage)
{
LevelLayerKey key(level, layerTarget);
bool imageAssociationCorrect = (mAssociatedImages.find(key) != mAssociatedImages.end() && (mAssociatedImages[key] == expectedImage));
ASSERT(imageAssociationCorrect);
if (imageAssociationCorrect)
{
mAssociatedImages[key] = NULL;
}
}
// releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association.
void TextureStorage11_2DArray::releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage)
{
LevelLayerKey key(level, layerTarget);
ASSERT(mAssociatedImages.find(key) != mAssociatedImages.end());
if (mAssociatedImages.find(key) != mAssociatedImages.end())
{
if (mAssociatedImages[key] != NULL && mAssociatedImages[key] != incomingImage)
{
// Ensure that the Image is still associated with this TextureStorage. This should be true.
bool imageAssociationCorrect = mAssociatedImages[key]->isAssociatedStorageValid(this);
ASSERT(imageAssociationCorrect);
if (imageAssociationCorrect)
{
// Force the image to recover from storage before its data is overwritten.
// This will reset mAssociatedImages[level] to NULL too.
mAssociatedImages[key]->recoverFromAssociatedStorage();
}
}
}
}
ID3D11Resource *TextureStorage11_2DArray::getResource() const ID3D11Resource *TextureStorage11_2DArray::getResource() const
{ {
return mTexture; return mTexture;
......
...@@ -20,6 +20,7 @@ class RenderTarget11; ...@@ -20,6 +20,7 @@ class RenderTarget11;
class Renderer; class Renderer;
class Renderer11; class Renderer11;
class SwapChain11; class SwapChain11;
class Image11;
class TextureStorage11 : public TextureStorage class TextureStorage11 : public TextureStorage
{ {
...@@ -55,6 +56,15 @@ class TextureStorage11 : public TextureStorage ...@@ -55,6 +56,15 @@ class TextureStorage11 : public TextureStorage
int layerTarget, GLint xoffset, GLint yoffset, GLint zoffset, int layerTarget, GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLsizei depth); 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: protected:
TextureStorage11(Renderer *renderer, UINT bindFlags); TextureStorage11(Renderer *renderer, UINT bindFlags);
void generateMipmapLayer(RenderTarget11 *source, RenderTarget11 *dest); void generateMipmapLayer(RenderTarget11 *source, RenderTarget11 *dest);
...@@ -152,6 +162,11 @@ class TextureStorage11_2D : public TextureStorage11 ...@@ -152,6 +162,11 @@ class TextureStorage11_2D : public TextureStorage11
virtual void generateMipmap(int level); 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: protected:
virtual ID3D11Resource *getSwizzleTexture(); virtual ID3D11Resource *getSwizzleTexture();
virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel); virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel);
...@@ -168,6 +183,8 @@ class TextureStorage11_2D : public TextureStorage11 ...@@ -168,6 +183,8 @@ class TextureStorage11_2D : public TextureStorage11
ID3D11Texture2D *mSwizzleTexture; ID3D11Texture2D *mSwizzleTexture;
ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
Image11 *mAssociatedImages[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
}; };
class TextureStorage11_Cube : public TextureStorage11 class TextureStorage11_Cube : public TextureStorage11
...@@ -183,6 +200,11 @@ class TextureStorage11_Cube : public TextureStorage11 ...@@ -183,6 +200,11 @@ class TextureStorage11_Cube : public TextureStorage11
virtual void generateMipmap(int faceIndex, int level); 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: protected:
virtual ID3D11Resource *getSwizzleTexture(); virtual ID3D11Resource *getSwizzleTexture();
virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel); virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel);
...@@ -199,6 +221,8 @@ class TextureStorage11_Cube : public TextureStorage11 ...@@ -199,6 +221,8 @@ class TextureStorage11_Cube : public TextureStorage11
ID3D11Texture2D *mSwizzleTexture; ID3D11Texture2D *mSwizzleTexture;
ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
Image11 *mAssociatedImages[6][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
}; };
class TextureStorage11_3D : public TextureStorage11 class TextureStorage11_3D : public TextureStorage11
...@@ -216,6 +240,11 @@ class TextureStorage11_3D : public TextureStorage11 ...@@ -216,6 +240,11 @@ class TextureStorage11_3D : public TextureStorage11
virtual void generateMipmap(int level); 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: protected:
virtual ID3D11Resource *getSwizzleTexture(); virtual ID3D11Resource *getSwizzleTexture();
virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel); virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel);
...@@ -236,6 +265,8 @@ class TextureStorage11_3D : public TextureStorage11 ...@@ -236,6 +265,8 @@ class TextureStorage11_3D : public TextureStorage11
ID3D11Texture3D *mTexture; ID3D11Texture3D *mTexture;
ID3D11Texture3D *mSwizzleTexture; ID3D11Texture3D *mSwizzleTexture;
ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
Image11 *mAssociatedImages[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
}; };
class TextureStorage11_2DArray : public TextureStorage11 class TextureStorage11_2DArray : public TextureStorage11
...@@ -252,6 +283,11 @@ class TextureStorage11_2DArray : public TextureStorage11 ...@@ -252,6 +283,11 @@ class TextureStorage11_2DArray : public TextureStorage11
virtual void generateMipmap(int level); 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: protected:
virtual ID3D11Resource *getSwizzleTexture(); virtual ID3D11Resource *getSwizzleTexture();
virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel); virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel);
...@@ -271,6 +307,9 @@ class TextureStorage11_2DArray : public TextureStorage11 ...@@ -271,6 +307,9 @@ class TextureStorage11_2DArray : public TextureStorage11
ID3D11Texture2D *mSwizzleTexture; ID3D11Texture2D *mSwizzleTexture;
ID3D11RenderTargetView *mSwizzleRenderTargets[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS]; 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