diff options
Diffstat (limited to 'Source/WebCore')
7 files changed, 371 insertions, 16 deletions
diff --git a/Source/WebCore/Android.mk b/Source/WebCore/Android.mk index 4529f83..c0e6d91 100644 --- a/Source/WebCore/Android.mk +++ b/Source/WebCore/Android.mk @@ -647,6 +647,7 @@ LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ platform/graphics/android/TilesManager.cpp \ platform/graphics/android/TiledPage.cpp \ platform/graphics/android/VideoLayerAndroid.cpp \ + platform/graphics/android/VideoLayerManager.cpp \ platform/graphics/android/android_graphics.cpp \ ifeq ($(ENABLE_SVG), true) diff --git a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp index 8aa334f..cd19e55 100644 --- a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp @@ -352,6 +352,9 @@ bool BaseLayerAndroid::drawGL(LayerAndroid* compositedRoot, // the unnecessary ones to make space... TilesManager::instance()->cleanupLayersTextures(compositedRoot); } + // Clean up GL textures for video layer. + TilesManager::instance()->videoLayerManager()->deleteUnusedTextures(); + // Finally do another pass to create new textures and schedule // repaints if needed compositedRoot->createGLTextures(); diff --git a/Source/WebCore/platform/graphics/android/TilesManager.h b/Source/WebCore/platform/graphics/android/TilesManager.h index 6d49cca..e43afed 100644 --- a/Source/WebCore/platform/graphics/android/TilesManager.h +++ b/Source/WebCore/platform/graphics/android/TilesManager.h @@ -35,6 +35,7 @@ #include "ShaderProgram.h" #include "TexturesGenerator.h" #include "TiledPage.h" +#include "VideoLayerManager.h" #include <utils/threads.h> namespace WebCore { @@ -76,6 +77,7 @@ public: } ShaderProgram* shader() { return &m_shader; } + VideoLayerManager* videoLayerManager() { return &m_videoLayerManager; } BackedDoubleBufferedTexture* getAvailableTexture(BaseTile* owner); @@ -153,6 +155,7 @@ private: static TilesManager* gInstance; ShaderProgram m_shader; + VideoLayerManager m_videoLayerManager; SkBitmap* m_tilesBitmap; }; diff --git a/Source/WebCore/platform/graphics/android/VideoLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/VideoLayerAndroid.cpp index 32e518d..aee5ae0 100644 --- a/Source/WebCore/platform/graphics/android/VideoLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/VideoLayerAndroid.cpp @@ -75,9 +75,7 @@ void VideoLayerAndroid::init() { // m_surfaceTexture is only useful on UI thread, no need to copy. // And it will be set at setBaseLayer timeframe - m_playerState = INITIALIZED; - m_textureId = 0; } // We can use this function to set the Layer to point to surface texture. @@ -85,9 +83,8 @@ void VideoLayerAndroid::setSurfaceTexture(sp<SurfaceTexture> texture, int textureName, PlayerState playerState) { m_surfaceTexture = texture; - m_textureId = textureName; - m_playerState = playerState; + TilesManager::instance()->videoLayerManager()->registerTexture(uniqueId(), textureName); } GLuint VideoLayerAndroid::createSpinnerInnerTexture() @@ -199,18 +196,32 @@ bool VideoLayerAndroid::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix) // Show the real video. m_surfaceTexture->updateTexImage(); m_surfaceTexture->getTransformMatrix(surfaceMatrix); + GLuint textureId = + TilesManager::instance()->videoLayerManager()->getTextureId(uniqueId()); TilesManager::instance()->shader()->drawVideoLayerQuad(drawTransform(), surfaceMatrix, - rect, m_textureId); + rect, textureId); + TilesManager::instance()->videoLayerManager()->updateMatrix(uniqueId(), + surfaceMatrix); } else { - // Show the poster - TilesManager::instance()->shader()->drawLayerQuad(drawTransform(), rect, - m_backgroundTextureId, - 0.5, true); - - TilesManager::instance()->shader()->drawLayerQuad(drawTransform(), innerRect, - m_posterTextureId, - 1, true); + GLuint textureId = + TilesManager::instance()->videoLayerManager()->getTextureId(uniqueId()); + GLfloat* matrix = + TilesManager::instance()->videoLayerManager()->getMatrix(uniqueId()); + if (textureId && matrix) { + // Show the screen shot for each video. + TilesManager::instance()->shader()->drawVideoLayerQuad(drawTransform(), + matrix, + rect, textureId); + } else { + // Show the static poster b/c there is no screen shot available. + TilesManager::instance()->shader()->drawLayerQuad(drawTransform(), rect, + m_backgroundTextureId, + 0.5, true); + TilesManager::instance()->shader()->drawLayerQuad(drawTransform(), innerRect, + m_posterTextureId, + 1, true); + } } return drawChildrenGL(glWebViewState, matrix); diff --git a/Source/WebCore/platform/graphics/android/VideoLayerAndroid.h b/Source/WebCore/platform/graphics/android/VideoLayerAndroid.h index eac565e..0f3f007 100644 --- a/Source/WebCore/platform/graphics/android/VideoLayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/VideoLayerAndroid.h @@ -68,14 +68,11 @@ private: void init(); // Surface texture for showing the video is actually allocated in Java side // and passed into this native code. - GLuint m_textureId; sp<android::SurfaceTexture> m_surfaceTexture; PlayerState m_playerState; // Texture for showing the static image will be created at native side. - // TODO: instead using a shared texture, we could make a texture pool to - // show different screen shots for different videos static bool m_createdTexture; static GLuint m_backgroundTextureId; static GLuint m_posterTextureId; diff --git a/Source/WebCore/platform/graphics/android/VideoLayerManager.cpp b/Source/WebCore/platform/graphics/android/VideoLayerManager.cpp new file mode 100644 index 0000000..cec4d67 --- /dev/null +++ b/Source/WebCore/platform/graphics/android/VideoLayerManager.cpp @@ -0,0 +1,242 @@ +/* + * Copyright 2011 The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "VideoLayerManager.h" + +#if USE(ACCELERATED_COMPOSITING) + +#ifdef DEBUG +#include <cutils/log.h> +#include <wtf/text/CString.h> + +#undef XLOG +#define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "VideoLayerManager", __VA_ARGS__) + +#else + +#undef XLOG +#define XLOG(...) + +#endif // DEBUG + +// Define the max sum of all the video's sizes. +// Note that video_size = width * height. If there is no compression, then the +// maximum memory consumption could be 4 * video_size. +// Setting this to 2M, means that maximum memory consumption of all the +// screenshots would not be above 8M. +#define MAX_VIDEOSIZE_SUM 2097152 + +namespace WebCore { + +VideoLayerManager::VideoLayerManager() +{ + m_currentTimeStamp = 0; +} + +// Getting TextureId for GL draw call, in the UI thread. +GLuint VideoLayerManager::getTextureId(const int layerId) +{ + android::Mutex::Autolock lock(m_videoLayerInfoMapLock); + GLuint result = 0; + if (m_videoLayerInfoMap.contains(layerId)) + result = m_videoLayerInfoMap.get(layerId)->textureId; + return result; +} + +// Getting matrix for GL draw call, in the UI thread. +GLfloat* VideoLayerManager::getMatrix(const int layerId) +{ + android::Mutex::Autolock lock(m_videoLayerInfoMapLock); + GLfloat* result = 0; + if (m_videoLayerInfoMap.contains(layerId)) + result = m_videoLayerInfoMap.get(layerId)->surfaceMatrix; + return result; +} + +int VideoLayerManager::getTotalMemUsage() +{ + int sum = 0; + InfoIterator end = m_videoLayerInfoMap.end(); + for (InfoIterator it = m_videoLayerInfoMap.begin(); it != end; ++it) + sum += it->second->videoSize; + return sum; +} + +// When the video start, we know its texture info, so we register when we +// recieve the setSurfaceTexture call, this happens on UI thread. +void VideoLayerManager::registerTexture(const int layerId, const GLuint textureId) +{ + android::Mutex::Autolock lock(m_videoLayerInfoMapLock); + // If the texture has been registered, then early return. + if (m_videoLayerInfoMap.get(layerId)) { + GLuint oldTextureId = m_videoLayerInfoMap.get(layerId)->textureId; + if (oldTextureId != textureId) + removeLayerInternal(layerId); + else + return; + } + // The old info is deleted and now complete the new info and store it. + VideoLayerInfo* pInfo = new VideoLayerInfo(); + pInfo->textureId = textureId; + memset(pInfo->surfaceMatrix, 0, sizeof(pInfo->surfaceMatrix)); + pInfo->videoSize = 0; + m_currentTimeStamp++; + pInfo->timeStamp = m_currentTimeStamp; + + m_videoLayerInfoMap.add(layerId, pInfo); + XLOG("GL texture %d regisered for layerId %d", textureId, layerId); + + return; +} + +// Only when the video is prepared, we got the video size. So we should update +// the size for the video accordingly. +// This is called from webcore thread, from MediaPlayerPrivateAndroid. +void VideoLayerManager::updateVideoLayerSize(const int layerId, const int size ) +{ + android::Mutex::Autolock lock(m_videoLayerInfoMapLock); + if (m_videoLayerInfoMap.contains(layerId)) { + VideoLayerInfo* pInfo = m_videoLayerInfoMap.get(layerId); + if (pInfo) + pInfo->videoSize = size; + } + + // If the memory usage is out of bound, then just delete the oldest ones. + // Because we only recycle the texture before the current timestamp, the + // current video's texture will not be deleted. + while (getTotalMemUsage() > MAX_VIDEOSIZE_SUM) + if (!recycleTextureMem()) + break; + return; +} + +// This is called only from UI thread, at drawGL time. +void VideoLayerManager::updateMatrix(const int layerId, const GLfloat* matrix) +{ + android::Mutex::Autolock lock(m_videoLayerInfoMapLock); + if (m_videoLayerInfoMap.contains(layerId)) { + // If the existing video layer's matrix is matching the incoming one, + // then skip the update. + VideoLayerInfo* pInfo = m_videoLayerInfoMap.get(layerId); + ASSERT(matrix); + if (pInfo && !memcmp(matrix, pInfo->surfaceMatrix, sizeof(pInfo->surfaceMatrix))) + return; + memcpy(pInfo->surfaceMatrix, matrix, sizeof(pInfo->surfaceMatrix)); + } else { + XLOG("Error: should not reach here, the layerId %d should exist!", layerId); + ASSERT(false); + } + return; +} + +// This is called on the webcore thread, save the GL texture for recycle in +// the retired queue. They will be deleted in deleteUnusedTextures() in the UI +// thread. +// Return true when we found one texture to retire. +bool VideoLayerManager::recycleTextureMem() +{ + // Find the oldest texture int the m_videoLayerInfoMap, put it in m_retiredTextures + int oldestTimeStamp = m_currentTimeStamp; + int oldestLayerId = -1; + + InfoIterator end = m_videoLayerInfoMap.end(); +#ifdef DEBUG + XLOG("VideoLayerManager::recycleTextureMem m_videoLayerInfoMap contains"); + for (InfoIterator it = m_videoLayerInfoMap.begin(); it != end; ++it) + XLOG(" layerId %d, textureId %d, videoSize %d, timeStamp %d ", + it->first, it->second->textureId, it->second->videoSize, it->second->timeStamp); +#endif + for (InfoIterator it = m_videoLayerInfoMap.begin(); it != end; ++it) { + if (it->second->timeStamp < oldestTimeStamp) { + oldestTimeStamp = it->second->timeStamp; + oldestLayerId = it->first; + } + } + + bool foundTextureToRetire = (oldestLayerId != -1); + if (foundTextureToRetire) + removeLayerInternal(oldestLayerId); + + return foundTextureToRetire; +} + +// This is only called in the UI thread, b/c glDeleteTextures need to be called +// on the right context. +void VideoLayerManager::deleteUnusedTextures() +{ + m_retiredTexturesLock.lock(); + int size = m_retiredTextures.size(); + if (size > 0) { + GLuint* textureNames = new GLuint[size]; + int index = 0; + Vector<GLuint>::const_iterator end = m_retiredTextures.end(); + for (Vector<GLuint>::const_iterator it = m_retiredTextures.begin(); + it != end; ++it) { + GLuint textureName = *it; + if (textureName) { + textureNames[index] = textureName; + index++; + XLOG("GL texture %d will be deleted", textureName); + } + } + glDeleteTextures(size, textureNames); + delete textureNames; + m_retiredTextures.clear(); + } + m_retiredTexturesLock.unlock(); + return; +} + +// This can be called in the webcore thread in the media player's dtor. +void VideoLayerManager::removeLayer(const int layerId) +{ + android::Mutex::Autolock lock(m_videoLayerInfoMapLock); + removeLayerInternal(layerId); +} + +// This can be called on both UI and webcore thread. Since this is a private +// function, it is up to the public function to handle the lock for +// m_videoLayerInfoMap. +void VideoLayerManager::removeLayerInternal(const int layerId) +{ + // Delete the layerInfo corresponding to this layerId and remove from the map. + if (m_videoLayerInfoMap.contains(layerId)) { + GLuint textureId = m_videoLayerInfoMap.get(layerId)->textureId; + if (textureId) { + // Buffer up the retired textures in either UI or webcore thread, + // will be purged at deleteUnusedTextures in the UI thread. + m_retiredTexturesLock.lock(); + m_retiredTextures.append(textureId); + m_retiredTexturesLock.unlock(); + } + delete m_videoLayerInfoMap.get(layerId); + m_videoLayerInfoMap.remove(layerId); + } + return; +} + +} +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/android/VideoLayerManager.h b/Source/WebCore/platform/graphics/android/VideoLayerManager.h new file mode 100644 index 0000000..de2dafc --- /dev/null +++ b/Source/WebCore/platform/graphics/android/VideoLayerManager.h @@ -0,0 +1,98 @@ +/* + * Copyright 2011 The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef VideoLayerManager_h +#define VideoLayerManager_h + +#include "GLUtils.h" +#include <wtf/HashMap.h> +#include <wtf/Vector.h> + +#if USE(ACCELERATED_COMPOSITING) + +namespace WebCore { + +// Every video layer can use its uniqueId to query VideoLayerManager about such +// info globally. +struct VideoLayerInfo { + GLuint textureId; // GL texture bound with the surface texture. + int videoSize; // The size of the video. + int timeStamp; // Used to decide which VideoLayerInfo is the oldest one. + GLfloat surfaceMatrix[16]; +}; + + +class VideoLayerManager { + +public: + typedef HashMap<int, VideoLayerInfo*>::const_iterator InfoIterator; + + VideoLayerManager(); + + // Register the texture when we got setSurfaceTexture call. + void registerTexture(const int layerId, const GLuint textureId); + // Update the size when the video is prepared. + void updateVideoLayerSize(const int layerId, const int size); + // At draw time, update the matrix for every video frame update. + void updateMatrix(const int layerId, const GLfloat* matrix); + // Remove the layer info from the mapping. + void removeLayer(const int layerId); + + // Return the texture name corresponding to the layerId + GLuint getTextureId(const int layerId); + // Return the matrix for surface texture corresponding to the layerId + GLfloat* getMatrix(const int layerId); + + // Delete the GL textures + void deleteUnusedTextures(); + +private: + // Get the sum of all the video size stored in m_videoLayerInfoMap. + int getTotalMemUsage(); + // If the memory consumption is out of bound, recycle some textures. + bool recycleTextureMem(); + // The private function to remove layer. + void removeLayerInternal(const int layerId); + + // Indexed by each layer's uniqueId, this map contains the important info + // used for showing the video when playing or the screenshot when paused. + HashMap<int, VideoLayerInfo*> m_videoLayerInfoMap; + android::Mutex m_videoLayerInfoMapLock; + + // Everytime we add one item to the map, we update the timestamp. + int m_currentTimeStamp; + + // The retiredTextures is used to communicate between UI thread and webcore + // thread. Basically, GL textures are determined to retire in the webcore + // thread, and really get deleted in the UI thread. + Vector<GLuint> m_retiredTextures; + android::Mutex m_retiredTexturesLock; +}; + +} // namespace WebCore + +#endif // USE(ACCELERATED_COMPOSITING) + // +#endif // VideoLayerManager_h |