summaryrefslogtreecommitdiffstats
path: root/WebCore
diff options
context:
space:
mode:
authorDerek Sollenberger <djsollen@google.com>2011-03-23 11:19:05 -0400
committerDerek Sollenberger <djsollen@google.com>2011-03-23 14:55:43 -0400
commitf32b2ce68c45663b1193cfe45a10d2889fd61c81 (patch)
tree4667dd2b39c9f9ce8e9bda96420707802bb05157 /WebCore
parentef25442f9f65d5f8283b2a5c2b90e63bf875c694 (diff)
downloadexternal_webkit-f32b2ce68c45663b1193cfe45a10d2889fd61c81.zip
external_webkit-f32b2ce68c45663b1193cfe45a10d2889fd61c81.tar.gz
external_webkit-f32b2ce68c45663b1193cfe45a10d2889fd61c81.tar.bz2
Fix GPU leak where plugin textures in the WebKit thread were not being deleted.
bug: 4165067 Change-Id: I2f50f600133300cec712b0177ead1a7afbbee2c3
Diffstat (limited to 'WebCore')
-rw-r--r--WebCore/platform/graphics/android/DoubleBufferedTexture.cpp12
-rw-r--r--WebCore/platform/graphics/android/DoubleBufferedTexture.h1
-rw-r--r--WebCore/platform/graphics/android/MediaLayer.cpp18
-rw-r--r--WebCore/platform/graphics/android/MediaLayer.h1
-rw-r--r--WebCore/platform/graphics/android/MediaTexture.cpp79
-rw-r--r--WebCore/platform/graphics/android/MediaTexture.h18
-rw-r--r--WebCore/platform/graphics/android/SharedTexture.cpp21
-rw-r--r--WebCore/platform/graphics/android/SharedTexture.h1
8 files changed, 143 insertions, 8 deletions
diff --git a/WebCore/platform/graphics/android/DoubleBufferedTexture.cpp b/WebCore/platform/graphics/android/DoubleBufferedTexture.cpp
index 7dcd1bc..cf640e8 100644
--- a/WebCore/platform/graphics/android/DoubleBufferedTexture.cpp
+++ b/WebCore/platform/graphics/android/DoubleBufferedTexture.cpp
@@ -102,6 +102,18 @@ EGLContext DoubleBufferedTexture::producerAcquireContext()
return context;
}
+void DoubleBufferedTexture::producerDeleteTextures()
+{
+ m_textureA.lock();
+ m_textureB.lock();
+ LOGV("Deleting Producer Textures A/B (%d:%d)", m_textureA.getSourceTextureId(),
+ m_textureB.getSourceTextureId());
+ m_textureA.deleteSourceTexture();
+ m_textureB.deleteSourceTexture();
+ m_textureA.unlock();
+ m_textureB.unlock();
+}
+
TextureInfo* DoubleBufferedTexture::producerLock()
{
SharedTexture* sharedTex = getWriteableTexture();
diff --git a/WebCore/platform/graphics/android/DoubleBufferedTexture.h b/WebCore/platform/graphics/android/DoubleBufferedTexture.h
index 5016332..8a9d81e 100644
--- a/WebCore/platform/graphics/android/DoubleBufferedTexture.h
+++ b/WebCore/platform/graphics/android/DoubleBufferedTexture.h
@@ -42,6 +42,7 @@ public:
virtual void producerRelease();
virtual void producerReleaseAndSwap();
EGLContext producerAcquireContext();
+ void producerDeleteTextures();
// consumer thread functions
TextureInfo* consumerLock();
diff --git a/WebCore/platform/graphics/android/MediaLayer.cpp b/WebCore/platform/graphics/android/MediaLayer.cpp
index 40a0f11..1ba6d46 100644
--- a/WebCore/platform/graphics/android/MediaLayer.cpp
+++ b/WebCore/platform/graphics/android/MediaLayer.cpp
@@ -43,33 +43,45 @@ namespace WebCore {
MediaLayer::MediaLayer(jobject weakWebViewRef) : LayerAndroid((RenderLayer*) NULL)
{
m_bufferedTexture = new MediaTexture(EGL_NO_CONTEXT);
- m_bufferedTexture->incStrong(this);
+ m_bufferedTexture->producerInc();
m_videoTexture = new VideoTexture(weakWebViewRef);
m_videoTexture->incStrong(this);
+ m_isCopy = false;
m_currentTextureInfo = 0;
m_isContentInverted = false;
m_outlineSize = 0;
XLOG("Creating Media Layer %p", this);
+ XLOG("producer: %d consumer: %d", m_bufferedTexture->getProducerCount(),
+ m_bufferedTexture->getConsumerCount());
}
MediaLayer::MediaLayer(const MediaLayer& layer) : LayerAndroid(layer)
{
m_bufferedTexture = layer.getTexture();
- m_bufferedTexture->incStrong(this);
+ m_bufferedTexture->consumerInc();
m_videoTexture = layer.m_videoTexture;
m_videoTexture->incStrong(this);
+ m_isCopy = true;
m_currentTextureInfo = 0;
m_isContentInverted = layer.m_isContentInverted;
m_outlineSize = layer.m_outlineSize;
XLOG("Creating Media Layer Copy %p -> %p", &layer, this);
+ XLOG("producer: %d consumer: %d COPY", m_bufferedTexture->getProducerCount(),
+ m_bufferedTexture->getConsumerCount());
}
MediaLayer::~MediaLayer()
{
XLOG("Deleting Media Layer");
- m_bufferedTexture->decStrong(this);
+ XLOG("producer: %d consumer: %d %s", m_bufferedTexture->getProducerCount(),
+ m_bufferedTexture->getConsumerCount(), (m_isCopy) ? "COPY" : "");
+
+ if (m_isCopy)
+ m_bufferedTexture->consumerDec();
+ else
+ m_bufferedTexture->producerDec();
m_videoTexture->decStrong(this);
}
diff --git a/WebCore/platform/graphics/android/MediaLayer.h b/WebCore/platform/graphics/android/MediaLayer.h
index 46789cb..8a07134 100644
--- a/WebCore/platform/graphics/android/MediaLayer.h
+++ b/WebCore/platform/graphics/android/MediaLayer.h
@@ -57,6 +57,7 @@ public:
void releaseNativeWindowForVideo(ANativeWindow* window);
private:
+ bool m_isCopy;
// Primary GL texture variables
MediaTexture* m_bufferedTexture;
diff --git a/WebCore/platform/graphics/android/MediaTexture.cpp b/WebCore/platform/graphics/android/MediaTexture.cpp
index 9836a01..9821065 100644
--- a/WebCore/platform/graphics/android/MediaTexture.cpp
+++ b/WebCore/platform/graphics/android/MediaTexture.cpp
@@ -48,6 +48,85 @@
namespace WebCore {
+MediaTexture::MediaTexture(EGLContext sharedContext) : DoubleBufferedTexture(sharedContext)
+{
+ m_producerRefCount = 0;
+ m_consumerRefCount = 0;
+}
+
+/* Increment the number of objects in the producer's thread that hold a reference
+ * to this object. In practice, there is often only one producer reference for
+ * the lifetime of the object.
+ */
+void MediaTexture::producerInc()
+{
+ android::Mutex::Autolock lock(m_mediaLock);
+ m_producerRefCount++;
+}
+
+/* Decrement the number of objects in the producer's thread that are holding a
+ * reference to this object. When removing the last reference we must cleanup
+ * all GL objects that are associated with the producer's thread. There may not
+ * be a consumer reference as the object may not have synced to the UI thread,
+ * in which case the producer needs to handle the deletion of the object.
+ */
+void MediaTexture::producerDec()
+{
+ bool needsDeleted = false;
+
+ m_mediaLock.lock();
+ m_producerRefCount--;
+ if (m_producerRefCount == 0) {
+ producerDeleteTextures();
+ if (m_consumerRefCount < 1) {
+ XLOG("INFO: This texture has not been synced to the UI thread");
+ needsDeleted = true;
+ }
+ }
+ m_mediaLock.unlock();
+
+ if (needsDeleted) {
+ XLOG("Deleting MediaTexture Object");
+ delete this;
+ }
+}
+
+/* Increment the number of objects in the consumer's thread that hold a reference
+ * to this object. In practice, there can be multiple producer references as the
+ * consumer (i.e. UI) thread may have multiple copies of the layer tree.
+ */
+void MediaTexture::consumerInc()
+{
+ android::Mutex::Autolock lock(m_mediaLock);
+ m_consumerRefCount++;
+}
+
+/* Decrement the number of objects in the consumer's thread that are holding a
+ * reference to this object. When removing the last reference we must delete
+ * this object and by extension cleanup all GL objects that are associated with
+ * the consumer's thread. At the time of deletion there should be no remaining
+ * producer references.
+ */
+void MediaTexture::consumerDec()
+{
+ bool needsDeleted = false;
+
+ m_mediaLock.lock();
+ m_consumerRefCount--;
+ if (m_consumerRefCount == 0) {
+ needsDeleted = true;
+ if (m_producerRefCount != 0) {
+ XLOG("ERROR: We should not delete the consumer before the producer is finished");
+ }
+ }
+ m_mediaLock.unlock();
+
+ if (needsDeleted) {
+ XLOG("Deleting MediaTexture Object");
+ delete this;
+ }
+}
+
VideoTexture::VideoTexture(jobject weakWebViewRef) : android::LightRefBase<VideoTexture>()
{
m_weakWebViewRef = weakWebViewRef;
diff --git a/WebCore/platform/graphics/android/MediaTexture.h b/WebCore/platform/graphics/android/MediaTexture.h
index b0c04a6..722afd8 100644
--- a/WebCore/platform/graphics/android/MediaTexture.h
+++ b/WebCore/platform/graphics/android/MediaTexture.h
@@ -33,11 +33,23 @@ namespace WebCore {
class VideoListener;
-class MediaTexture : public DoubleBufferedTexture,
- public android::LightRefBase<MediaTexture> {
+class MediaTexture : public DoubleBufferedTexture {
public:
- MediaTexture(EGLContext sharedContext) : DoubleBufferedTexture(sharedContext) { };
+ MediaTexture(EGLContext sharedContext);
+
+ void producerInc();
+ void producerDec();
+ void consumerInc();
+ void consumerDec();
+
+ int getProducerCount() { android::Mutex::Autolock lock(m_mediaLock); return m_producerRefCount; }
+ int getConsumerCount() { android::Mutex::Autolock lock(m_mediaLock); return m_consumerRefCount; }
+
+private:
+ android::Mutex m_mediaLock;
+ int m_producerRefCount;
+ int m_consumerRefCount;
};
class VideoTexture : public android::LightRefBase<VideoTexture> {
diff --git a/WebCore/platform/graphics/android/SharedTexture.cpp b/WebCore/platform/graphics/android/SharedTexture.cpp
index f2da663..8c703d4 100644
--- a/WebCore/platform/graphics/android/SharedTexture.cpp
+++ b/WebCore/platform/graphics/android/SharedTexture.cpp
@@ -77,8 +77,7 @@ SharedTexture::SharedTexture()
// called by the consumer when it no longer wants to consume and after it has
// terminated all providers. If EGLImages are used, the deletion of the
-// source texture and EGLImage is the responsibility of the caller. In the case
-// of double buffered textures this is handled in the onDestroy(...) method.
+// source texture and EGLImage is the responsibility of the caller.
SharedTexture::~SharedTexture()
{
if (m_supportsEGLImage)
@@ -103,6 +102,24 @@ void SharedTexture::initSourceTexture()
glGenTextures(1, &m_sourceTexture.m_textureId);
}
+
+void SharedTexture::deleteSourceTexture()
+{
+ // We need to delete the source texture and EGLImage in the thread in which
+ // it was created. In theory we should be able to delete the EGLImage
+ // from either thread, but it currently throws an error if not deleted
+ // in the same EGLContext from which it was created.
+ if (m_supportsEGLImage) {
+ GLUtils::deleteTexture(&m_sourceTexture.m_textureId);
+ if (m_eglImage != EGL_NO_IMAGE_KHR) {
+ eglDestroyImageKHR(eglGetCurrentDisplay(), m_eglImage);
+ m_eglImage = EGL_NO_IMAGE_KHR;
+ m_isNewImage = true;
+ }
+ LOGI("Deleted Source Texture and EGLImage");
+ }
+}
+
TextureInfo* SharedTexture::lockSource()
{
m_lock.lock();
diff --git a/WebCore/platform/graphics/android/SharedTexture.h b/WebCore/platform/graphics/android/SharedTexture.h
index e654c5c..731aa5c 100644
--- a/WebCore/platform/graphics/android/SharedTexture.h
+++ b/WebCore/platform/graphics/android/SharedTexture.h
@@ -80,6 +80,7 @@ public:
void unlock() { m_lock.unlock(); }
void initSourceTexture(); // producer thread only
+ void deleteSourceTexture(); // producer thread only
GLuint getSourceTextureId() { return m_sourceTexture.m_textureId; }
GLuint getTargetTextureId() { return m_targetTexture.m_textureId; }
EGLImageKHR getEGLImage() { return m_eglImage; }