aboutsummaryrefslogtreecommitdiff
path: root/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libGLESv2/renderer/d3d/d3d11/Image11.cpp')
-rw-r--r--src/libGLESv2/renderer/d3d/d3d11/Image11.cpp144
1 files changed, 123 insertions, 21 deletions
diff --git a/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp b/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp
index 08b16ee7..7536713a 100644
--- a/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp
+++ b/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp
@@ -1,4 +1,3 @@
-#include "precompiled.h"
//
// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
@@ -11,13 +10,13 @@
#include "libGLESv2/renderer/d3d/d3d11/Renderer11.h"
#include "libGLESv2/renderer/d3d/d3d11/Image11.h"
#include "libGLESv2/renderer/d3d/d3d11/TextureStorage11.h"
+#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h"
+#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h"
#include "libGLESv2/Framebuffer.h"
#include "libGLESv2/FramebufferAttachment.h"
-
#include "libGLESv2/main.h"
+
#include "common/utilities.h"
-#include "libGLESv2/renderer/d3d/d3d11/formatutils11.h"
-#include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h"
namespace rx
{
@@ -27,11 +26,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 +87,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::copyToStorage2D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
+{
+ TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage);
+ return copyToStorageImpl(storage11, level, 0, xoffset, yoffset, width, height);
}
-bool Image11::copyToStorage(TextureStorageInterface2D *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
+bool Image11::copyToStorageCube(TextureStorage *storage, int face, 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);
+ TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage);
+ return copyToStorageImpl(storage11, level, face, xoffset, yoffset, width, height);
+}
+
+bool Image11::copyToStorage3D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
+{
+ TextureStorage11_3D *storage11 = TextureStorage11_3D::makeTextureStorage11_3D(storage);
+ return copyToStorageImpl(storage11, level, 0, xoffset, yoffset, width, height);
+}
+
+bool Image11::copyToStorage2DArray(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint arrayLayer, GLsizei width, GLsizei height)
+{
+ TextureStorage11_2DArray *storage11 = TextureStorage11_2DArray::makeTextureStorage11_2DArray(storage);
+ 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::copyToStorage(TextureStorageInterfaceCube *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
+bool Image11::isAssociatedStorageValid(TextureStorage11* textureStorage) const
{
- TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage->getStorageInstance());
- return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, face, xoffset, yoffset, 0, width, height, 1);
+ return (mAssociatedStorage == textureStorage);
}
-bool Image11::copyToStorage(TextureStorageInterface3D *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
+bool Image11::recoverFromAssociatedStorage()
{
- TextureStorage11_3D *storage11 = TextureStorage11_3D::makeTextureStorage11_3D(storage->getStorageInstance());
- return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, 0, xoffset, yoffset, zoffset, width, height, depth);
+ 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;
}
-bool Image11::copyToStorage(TextureStorageInterface2DArray *storage, int level, GLint xoffset, GLint yoffset, GLint arrayLayer, GLsizei width, GLsizei height)
+void Image11::disassociateStorage()
{
- TextureStorage11_2DArray *storage11 = TextureStorage11_2DArray::makeTextureStorage11_2DArray(storage->getStorageInstance());
- return storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, arrayLayer, xoffset, yoffset, 0, width, height, 1);
+ 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 +207,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;
@@ -296,7 +390,7 @@ void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y
// determine the offset coordinate into the destination buffer
GLsizei rowOffset = gl::GetInternalFormatInfo(mActualFormat).pixelBytes * xoffset;
- void *dataOffset = static_cast<unsigned char*>(mappedImage.pData) + mappedImage.RowPitch * yoffset + rowOffset + zoffset * mappedImage.DepthPitch;
+ uint8_t *dataOffset = static_cast<uint8_t*>(mappedImage.pData) + mappedImage.RowPitch * yoffset + rowOffset + zoffset * mappedImage.DepthPitch;
const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat);
@@ -313,6 +407,11 @@ ID3D11Resource *Image11::getStagingTexture()
return mStagingTexture;
}
+void Image11::releaseStagingTexture()
+{
+ SafeRelease(mStagingTexture);
+}
+
unsigned int Image11::getStagingSubresource()
{
createStagingTexture();
@@ -434,6 +533,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)