diff options
author | Nicolas Roard <nicolasroard@google.com> | 2011-12-01 07:43:52 -0800 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2011-12-01 07:43:52 -0800 |
commit | 931e90d171935ef706b6906c5867a51fc491a83d (patch) | |
tree | 4321841ab956b65cfe508bc824e7d0fc6eaaff15 /Source/WebCore | |
parent | 6dd76bd83b84be93653706342d235c4377b40e62 (diff) | |
parent | f1a221194f2b0d5fd82d2e98ced94f0553c45986 (diff) | |
download | external_webkit-931e90d171935ef706b6906c5867a51fc491a83d.zip external_webkit-931e90d171935ef706b6906c5867a51fc491a83d.tar.gz external_webkit-931e90d171935ef706b6906c5867a51fc491a83d.tar.bz2 |
am f1a22119: Merge "Fix image layer codepath" into ics-mr1
* commit 'f1a221194f2b0d5fd82d2e98ced94f0553c45986':
Fix image layer codepath
Diffstat (limited to 'Source/WebCore')
19 files changed, 421 insertions, 203 deletions
diff --git a/Source/WebCore/platform/graphics/android/BaseTile.cpp b/Source/WebCore/platform/graphics/android/BaseTile.cpp index a331dfc..df96657 100644 --- a/Source/WebCore/platform/graphics/android/BaseTile.cpp +++ b/Source/WebCore/platform/graphics/android/BaseTile.cpp @@ -268,7 +268,7 @@ void BaseTile::draw(float transparency, SkRect& rect, float scale) } if (m_frontTexture->readyFor(this)) { - if (isLayerTile()) + if (isLayerTile() && m_painter && m_painter->transform()) TilesManager::instance()->shader()->drawLayerQuad(*m_painter->transform(), rect, m_frontTexture->m_ownTextureId, transparency, true); diff --git a/Source/WebCore/platform/graphics/android/ClassTracker.cpp b/Source/WebCore/platform/graphics/android/ClassTracker.cpp index 92d406c..eb810a8 100644 --- a/Source/WebCore/platform/graphics/android/ClassTracker.cpp +++ b/Source/WebCore/platform/graphics/android/ClassTracker.cpp @@ -27,6 +27,7 @@ #include "ClassTracker.h" #include "LayerAndroid.h" +#include "TilesManager.h" #include <cutils/log.h> #include <wtf/CurrentTime.h> @@ -35,6 +36,9 @@ #undef XLOG #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "ClassTracker", __VA_ARGS__) +#define DEBUG_LAYERS +#undef DEBUG_LAYERS + namespace WebCore { ClassTracker* ClassTracker::instance() @@ -66,7 +70,6 @@ void ClassTracker::decrement(String name) m_classes.set(name, value - 1); } - void ClassTracker::add(LayerAndroid* layer) { android::Mutex::Autolock lock(m_lock); @@ -88,6 +91,21 @@ void ClassTracker::show() iter->first.latin1().data(), iter->second); } XLOG("*** %d Layers ***", m_layers.size()); + int nbTextures = 0; + int nbAllocatedTextures = 0; + int nbLayerTextures = 0; + int nbAllocatedLayerTextures = 0; + float textureSize = 256 * 256 * 4 / 1024.0 / 1024.0; + TilesManager::instance()->gatherTexturesNumbers(&nbTextures, &nbAllocatedTextures, + &nbLayerTextures, &nbAllocatedLayerTextures); + XLOG("*** textures: %d/%d (%.2f Mb), layer textures: %d/%d (%.2f Mb) : total used %.2f Mb", + nbAllocatedTextures, nbTextures, + nbAllocatedTextures * textureSize, + nbAllocatedLayerTextures, nbLayerTextures, + nbAllocatedLayerTextures * textureSize, + (nbAllocatedTextures + nbAllocatedLayerTextures) * textureSize); + +#ifdef DEBUG_LAYERS for (unsigned int i = 0; i < m_layers.size(); i++) { LayerAndroid* layer = m_layers[i]; XLOG("[%d/%d] layer %x (%.2f, %.2f) of type %d, refcount(%d) has texture %x has image ref %x (%x) root: %x parent: %x", @@ -98,6 +116,7 @@ void ClassTracker::show() layer->imageTexture(), (LayerAndroid*) layer->getRootLayer(), (LayerAndroid*) layer->getParent()); } +#endif } } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp index 4820120..cf91c00 100644 --- a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp +++ b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp @@ -479,7 +479,7 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, // Upload any pending ImageTexture // Return true if we still have some images to upload. // TODO: upload as many textures as possible within a certain time limit - bool ret = ImagesManager::instance()->uploadTextures(); + bool ret = ImagesManager::instance()->prepareTextures(this); if (scale < MIN_SCALE_WARNING || scale > MAX_SCALE_WARNING) { XLOGC("WARNING, scale seems corrupted after update: %e", scale); @@ -501,6 +501,13 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, if (!ret) resetFrameworkInval(); + int nbTexturesForImages = ImagesManager::instance()->nbTextures(); + XLOG("*** We have %d textures for images, %d full, %d clipped, total %d / %d", + nbTexturesForImages, nbTexturesNeeded.full, nbTexturesNeeded.clipped, + nbTexturesNeeded.full + nbTexturesForImages, + nbTexturesNeeded.clipped + nbTexturesForImages); + nbTexturesNeeded.full += nbTexturesForImages; + nbTexturesNeeded.clipped += nbTexturesForImages; ret |= setLayersRenderingMode(nbTexturesNeeded); FloatRect extrasclip(0, 0, rect.width(), rect.height()); diff --git a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp index 44c9a2d..de9fcae 100644 --- a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp @@ -119,8 +119,8 @@ GraphicsLayerAndroid::GraphicsLayerAndroid(GraphicsLayerClient* client) : m_needsRepaint(false), m_needsNotifyClient(false), m_haveContents(false), - m_haveImage(false), m_newImage(false), + m_image(0), m_foregroundLayer(0), m_foregroundClipLayer(0) { @@ -132,6 +132,9 @@ GraphicsLayerAndroid::GraphicsLayerAndroid(GraphicsLayerClient* client) : GraphicsLayerAndroid::~GraphicsLayerAndroid() { + if (m_image) + m_image->deref(); + m_contentLayer->unref(); SkSafeUnref(m_foregroundLayer); SkSafeUnref(m_foregroundClipLayer); @@ -557,7 +560,7 @@ bool GraphicsLayerAndroid::repaint() LOG("(%x) repaint(), gPaused(%d) m_needsRepaint(%d) m_haveContents(%d) ", this, gPaused, m_needsRepaint, m_haveContents); - if (!gPaused && m_haveContents && m_needsRepaint && !m_haveImage) { + if (!gPaused && m_haveContents && m_needsRepaint && !m_image) { // with SkPicture, we request the entire layer's content. IntRect layerBounds(0, 0, m_size.width(), m_size.height()); @@ -639,7 +642,7 @@ bool GraphicsLayerAndroid::repaint() return true; } - if (m_needsRepaint && m_haveImage && m_newImage) { + if (m_needsRepaint && m_image && m_newImage) { // We need to tell the GL thread that we will need to repaint the // texture. Only do so if we effectively have a new image! m_contentLayer->markAsDirty(m_dirtyRegion); @@ -672,7 +675,7 @@ void GraphicsLayerAndroid::setNeedsDisplayInRect(const FloatRect& rect) { // rect is in the render object coordinates - if (!m_haveImage && !drawsContent()) { + if (!m_image && !drawsContent()) { LOG("(%x) setNeedsDisplay(%.2f,%.2f,%.2f,%.2f) doesn't have content, bypass...", this, rect.x(), rect.y(), rect.width(), rect.height()); return; @@ -836,14 +839,23 @@ void GraphicsLayerAndroid::resumeAnimations() void GraphicsLayerAndroid::setContentsToImage(Image* image) { TLOG("(%x) setContentsToImage", this, image); - if (image) { + if (image && image != m_image) { + image->ref(); + if (m_image) + m_image->deref(); + m_image = image; + + SkBitmapRef* bitmap = image->nativeImageForCurrentFrame(); + m_contentLayer->setContentsImage(bitmap); + m_haveContents = true; - m_haveImage = true; m_newImage = true; - m_contentLayer->setContentsImage(image->nativeImageForCurrentFrame()); } - if (m_haveImage && !image) + if (!image && m_image) { m_contentLayer->setContentsImage(0); + m_image->deref(); + m_image = 0; + } setNeedsDisplay(); askForSync(); diff --git a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h index af8d7ce..358f674 100644 --- a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h @@ -145,8 +145,8 @@ private: bool m_needsNotifyClient; bool m_haveContents; - bool m_haveImage; bool m_newImage; + Image* m_image; SkRegion m_dirtyRegion; diff --git a/Source/WebCore/platform/graphics/android/ImageTexture.cpp b/Source/WebCore/platform/graphics/android/ImageTexture.cpp index 96f7713..23e3899 100644 --- a/Source/WebCore/platform/graphics/android/ImageTexture.cpp +++ b/Source/WebCore/platform/graphics/android/ImageTexture.cpp @@ -27,8 +27,11 @@ #include "ImageTexture.h" #include "ImagesManager.h" +#include "LayerAndroid.h" #include "SkDevice.h" +#include "SkPicture.h" #include "TilesManager.h" +#include "TiledTexture.h" #include <cutils/log.h> #include <wtf/CurrentTime.h> @@ -51,96 +54,201 @@ namespace WebCore { -ImageTexture::ImageTexture(SkBitmapRef* img) - : m_imageRef(img) - , m_image(0) - , m_textureId(0) - , m_refCount(0) +// CRC computation adapted from Tools/DumpRenderTree/CyclicRedundancyCheck.cpp +static void makeCrcTable(unsigned crcTable[256]) +{ + for (unsigned i = 0; i < 256; i++) { + unsigned c = i; + for (int k = 0; k < 8; k++) { + if (c & 1) + c = -306674912 ^ ((c >> 1) & 0x7fffffff); + else + c = c >> 1; + } + crcTable[i] = c; + } +} + +unsigned computeCrc(uint8_t* buffer, size_t size) +{ + static unsigned crcTable[256]; + static bool crcTableComputed = false; + if (!crcTableComputed) { + makeCrcTable(crcTable); + crcTableComputed = true; + } + + unsigned crc = 0xffffffffL; + for (size_t i = 0; i < size; ++i) + crc = crcTable[(crc ^ buffer[i]) & 0xff] ^ ((crc >> 8) & 0x00ffffffL); + return crc ^ 0xffffffffL; +} + +ImageTexture::ImageTexture(SkBitmap* bmp, unsigned crc) + : m_image(bmp) + , m_texture(0) + , m_layer(0) + , m_picture(0) + , m_crc(crc) { #ifdef DEBUG_COUNT ClassTracker::instance()->increment("ImageTexture"); #endif - if (!m_imageRef) + if (!m_image) return; - SkBitmap* bitmap = &m_imageRef->bitmap(); - m_image = new SkBitmap(); + // NOTE: This constructor is called on the webcore thread + + // Create a picture containing the image (needed for TiledTexture) + m_picture = new SkPicture(); + SkCanvas* pcanvas = m_picture->beginRecording(m_image->width(), m_image->height()); + pcanvas->clear(SkColorSetARGBInline(0, 0, 0, 0)); + pcanvas->drawBitmap(*m_image, 0, 0); + m_picture->endRecording(); +} + +ImageTexture::~ImageTexture() +{ +#ifdef DEBUG_COUNT + ClassTracker::instance()->decrement("ImageTexture"); +#endif + delete m_image; + delete m_texture; + SkSafeUnref(m_picture); +} + +SkBitmap* ImageTexture::convertBitmap(SkBitmap* bitmap) +{ + SkBitmap* img = new SkBitmap(); int w = bitmap->width(); int h = bitmap->height(); - m_image->setConfig(SkBitmap::kARGB_8888_Config, w, h); - m_image->allocPixels(); - SkDevice* device = new SkDevice(NULL, *m_image, false); + + // Create a copy of the image + img->setConfig(SkBitmap::kARGB_8888_Config, w, h); + img->allocPixels(); + SkDevice* device = new SkDevice(NULL, *img, false); SkCanvas canvas; canvas.setDevice(device); device->unref(); SkRect dest; dest.set(0, 0, w, h); - m_image->setIsOpaque(false); - m_image->eraseARGB(0, 0, 0, 0); + img->setIsOpaque(false); + img->eraseARGB(0, 0, 0, 0); canvas.drawBitmapRect(*bitmap, 0, dest); + + return img; } -ImageTexture::~ImageTexture() +unsigned ImageTexture::computeCRC(const SkBitmap* bitmap) { -#ifdef DEBUG_COUNT - ClassTracker::instance()->decrement("ImageTexture"); -#endif - delete m_image; + if (!bitmap) + return 0; + bitmap->lockPixels(); + uint8_t* img = static_cast<uint8_t*>(bitmap->getPixels()); + unsigned crc = computeCrc(img, bitmap->getSize()); + bitmap->unlockPixels(); + return crc; } -void ImageTexture::prepareGL() +bool ImageTexture::equalsCRC(unsigned crc) { - if (m_textureId) - return; - - ImagesManager::instance()->scheduleTextureUpload(this); + return m_crc == crc; } -void ImageTexture::uploadGLTexture() +int ImageTexture::nbTextures() { - if (m_textureId) - return; - - glGenTextures(1, &m_textureId); - GLUtils::createTextureWithBitmap(m_textureId, *m_image); + if (!hasContentToShow()) + return 0; + if (!m_texture) + return 0; + + // TODO: take in account the visible clip (need to maintain + // a list of the clients layer, etc.) + IntRect visibleArea(0, 0, m_image->width(), m_image->height()); + int nbTextures = m_texture->nbTextures(visibleArea, 1.0); + XLOG("ImageTexture %p, %d x %d needs %d textures", + this, m_image->width(), m_image->height(), + nbTextures); + return nbTextures; } -void ImageTexture::drawGL(LayerAndroid* layer) +bool ImageTexture::hasContentToShow() { - if (!layer) - return; - if (!m_textureId) - return; + // Don't display 1x1 image -- no need to allocate a full texture for this if (!m_image) - return; + return false; + if (m_image->width() == 1 && m_image->height() == 1) + return false; + return true; +} - SkRect rect; - rect.fLeft = 0; - rect.fTop = 0; - rect.fRight = layer->getSize().width(); - rect.fBottom = layer->getSize().height(); - TilesManager::instance()->shader()->drawLayerQuad(*layer->drawTransform(), - rect, m_textureId, - layer->drawOpacity(), true); +bool ImageTexture::prepareGL(GLWebViewState* state) +{ + if (!hasContentToShow()) + return false; + + if (!m_texture && m_picture) { + m_texture = new TiledTexture(this); + SkRegion region; + region.setRect(0, 0, m_image->width(), m_image->height()); + m_texture->update(region, m_picture); + } + + if (!m_texture) + return false; + + IntRect visibleArea(0, 0, m_image->width(), m_image->height()); + m_texture->prepare(state, 1.0, true, true, visibleArea); + if (m_texture->ready()) { + m_texture->swapTiles(); + return false; + } + return true; } -void ImageTexture::drawCanvas(SkCanvas* canvas, SkRect& rect) +const TransformationMatrix* ImageTexture::transform() { - canvas->drawBitmapRect(*m_image, 0, rect); + if (!m_layer) + return 0; + + FloatPoint p(0, 0); + p = m_layer->drawTransform()->mapPoint(p); + IntRect layerArea = m_layer->unclippedArea(); + float scaleW = static_cast<float>(layerArea.width()) / static_cast<float>(m_image->width()); + float scaleH = static_cast<float>(layerArea.height()) / static_cast<float>(m_image->height()); + TransformationMatrix d = *(m_layer->drawTransform()); + TransformationMatrix m; + m.scaleNonUniform(scaleW, scaleH); + m_layerMatrix = d.multiply(m); + return &m_layerMatrix; } -void ImageTexture::release() +float ImageTexture::opacity() { - if (m_refCount >= 1) - m_refCount--; - if (!m_refCount) - deleteTexture(); + if (!m_layer) + return 1.0; + return m_layer->drawOpacity(); } -void ImageTexture::deleteTexture() +void ImageTexture::drawGL(LayerAndroid* layer) +{ + if (!layer) + return; + if (!hasContentToShow()) + return; + + // TiledTexture::draw() will call us back to know the + // transform and opacity, so we need to set m_layer + m_layer = layer; + if (m_texture) + m_texture->draw(); + m_layer = 0; +} + +void ImageTexture::drawCanvas(SkCanvas* canvas, SkRect& rect) { - if (m_textureId) - glDeleteTextures(1, &m_textureId); + if (canvas && m_image) + canvas->drawBitmapRect(*m_image, 0, rect); } } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/ImageTexture.h b/Source/WebCore/platform/graphics/android/ImageTexture.h index cea79c3..6c6a075 100644 --- a/Source/WebCore/platform/graphics/android/ImageTexture.h +++ b/Source/WebCore/platform/graphics/android/ImageTexture.h @@ -29,57 +29,78 @@ #include "GLUtils.h" #include "SkBitmap.h" #include "SkBitmapRef.h" +#include "SkPicture.h" #include "SkRefCnt.h" #include "LayerAndroid.h" namespace WebCore { class LayerAndroid; +class TexturesResult; +class TiledTexture; ///////////////////////////////////////////////////////////////////////////////// // Image sharing codepath for layers ///////////////////////////////////////////////////////////////////////////////// // -// We receive an SkBitmapRef on the webcore thread; from this we create -// an ImageTexture instance and keep it in TilesManager in a hashmap -// (see TilesManager::addImage()) +// Layers containing only an image take a slightly different codepath; +// GraphicsLayer::setContentsToImage() is called on the webcore thread, +// passing an Image instance. We get the native image (an SkBitmap) and create +// an ImageTexture instance with it (or increment the refcount of an existing +// instance if the SkBitmap is similar to one already stored in ImagesManager, +// i.e. if two GraphicsLayer share the same image). // -// The ImageTexture will recopy the pointed SkBitmap locally (so we can safely -// use it on the texture generation thread), and just use the SkBitmapRef as a -// key. +// To detect if an image is similar, we compute and use a CRC. Each ImageTexture +// is stored in ImagesManager using its CRC as a hash key. +// Simply comparing the address is not enough -- different image could end up +// at the same address (i.e. the image is deallocated then a new one is +// reallocated at the old address) // -// Layers on the shared image path will ask TilesManager for the corresponding -// ImageTexture, instead of using a PaintedSurface+TiledTexture. -// When the ImageTexture is prepared for the first time, we directly upload -// the bitmap to a texture. +// Each ImageTexture's CRC being unique, LayerAndroid instances simply store that +// and retain/release the corresponding ImageTexture (so that +// queued painting request will work correctly and not crash...). +// LayerAndroid running on the UI thread will get the corresponding +// ImageTexture at draw time. // -// TODO: limit how many ImageTextures can be uploaded in one draw cycle -// TODO: limit the size of ImageTextures (use a TiledTexture when needed) +// ImageTexture recopy the original SkBitmap so that they can safely be used +// on a different thread; it uses TiledTexture to allocate and paint the image, +// so that we can share the same textures and limits as the rest of the layers. // ///////////////////////////////////////////////////////////////////////////////// -class ImageTexture { +class ImageTexture : public SurfacePainter { public: - ImageTexture(SkBitmapRef* img); + ImageTexture(SkBitmap* bmp, unsigned crc); virtual ~ImageTexture(); - void prepareGL(); - void uploadGLTexture(); + bool prepareGL(GLWebViewState*); void drawGL(LayerAndroid* painter); void drawCanvas(SkCanvas*, SkRect&); - void retain() { m_refCount++; } - void release(); - unsigned int refCount() { return m_refCount; } - SkBitmapRef* imageRef() { return m_imageRef; } + bool hasContentToShow(); SkBitmap* bitmap() { return m_image; } + unsigned imageCRC() { return m_crc; } -private: + static SkBitmap* convertBitmap(SkBitmap* bitmap); + + static unsigned computeCRC(const SkBitmap* bitmap); + bool equalsCRC(unsigned crc); + + // methods used by TiledTexture + virtual const TransformationMatrix* transform(); + virtual float opacity(); - void deleteTexture(); + int nbTextures(); + + virtual SurfaceType type() { return SurfacePainter::ImageSurface; } + +private: SkBitmapRef* m_imageRef; SkBitmap* m_image; - GLuint m_textureId; - unsigned int m_refCount; + TiledTexture* m_texture; + LayerAndroid* m_layer; + SkPicture* m_picture; + TransformationMatrix m_layerMatrix; + unsigned m_crc; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/ImagesManager.cpp b/Source/WebCore/platform/graphics/android/ImagesManager.cpp index 21f9fe9..65c41d1 100644 --- a/Source/WebCore/platform/graphics/android/ImagesManager.cpp +++ b/Source/WebCore/platform/graphics/android/ImagesManager.cpp @@ -26,6 +26,9 @@ #include "config.h" #include "ImagesManager.h" +#include "SkCanvas.h" +#include "SkDevice.h" +#include "SkRefCnt.h" #include "ImageTexture.h" #include <cutils/log.h> @@ -59,71 +62,88 @@ ImagesManager* ImagesManager::instance() ImagesManager* ImagesManager::gInstance = 0; -void ImagesManager::addImage(SkBitmapRef* imgRef) +ImageTexture* ImagesManager::setImage(SkBitmapRef* imgRef) { if (!imgRef) - return; + return 0; + + SkBitmap* bitmap = &imgRef->bitmap(); + ImageTexture* image = 0; + SkBitmap* img = 0; + unsigned crc = 0; + + img = ImageTexture::convertBitmap(bitmap); + crc = ImageTexture::computeCRC(img); + + { + android::Mutex::Autolock lock(m_imagesLock); + if (m_images.contains(crc)) { + image = m_images.get(crc); + SkSafeRef(image); + return image; + } + } + + // the image is not in the map, we add it + + image = new ImageTexture(img, crc); android::Mutex::Autolock lock(m_imagesLock); - if (!m_images.contains(imgRef)) - m_images.set(imgRef, new ImageTexture(imgRef)); + m_images.set(crc, image); + + return image; } -void ImagesManager::removeImage(SkBitmapRef* imgRef) +ImageTexture* ImagesManager::retainImage(unsigned imgCRC) { + if (!imgCRC) + return 0; + android::Mutex::Autolock lock(m_imagesLock); - if (!m_images.contains(imgRef)) - return; + ImageTexture* image = 0; + if (m_images.contains(imgCRC)) { + image = m_images.get(imgCRC); + SkSafeRef(image); + } + return image; +} - ImageTexture* image = m_images.get(imgRef); - image->release(); +void ImagesManager::releaseImage(unsigned imgCRC) +{ + if (!imgCRC) + return; - if (!image->refCount()) { - m_images.remove(imgRef); - delete image; + android::Mutex::Autolock lock(m_imagesLock); + if (m_images.contains(imgCRC)) { + ImageTexture* image = m_images.get(imgCRC); + if (image->getRefCnt() == 1) + m_images.remove(imgCRC); + SkSafeUnref(image); } } -void ImagesManager::showImages() +int ImagesManager::nbTextures() { - XLOGC("We have %d images", m_images.size()); - HashMap<SkBitmapRef*, ImageTexture*>::iterator end = m_images.end(); + android::Mutex::Autolock lock(m_imagesLock); + HashMap<unsigned, ImageTexture*>::iterator end = m_images.end(); int i = 0; - for (HashMap<SkBitmapRef*, ImageTexture*>::iterator it = m_images.begin(); it != end; ++it) { - XLOGC("Image %x (%d/%d) has %d references", it->first, i, - m_images.size(), it->second->refCount()); + int nb = 0; + for (HashMap<unsigned, ImageTexture*>::iterator it = m_images.begin(); it != end; ++it) { + nb += it->second->nbTextures(); i++; } + return nb; } -ImageTexture* ImagesManager::getTextureForImage(SkBitmapRef* img, bool retain) +bool ImagesManager::prepareTextures(GLWebViewState* state) { + bool ret = false; android::Mutex::Autolock lock(m_imagesLock); - ImageTexture* image = m_images.get(img); - if (retain && image) - image->retain(); - return image; -} - -void ImagesManager::scheduleTextureUpload(ImageTexture* texture) -{ - if (m_imagesToUpload.contains(texture)) - return; - - texture->retain(); - m_imagesToUpload.append(texture); -} - -bool ImagesManager::uploadTextures() -{ - // scheduleUpload and uploadTextures are called on the same thread - if (!m_imagesToUpload.size()) - return false; - ImageTexture* texture = m_imagesToUpload.last(); - texture->uploadGLTexture(); - m_imagesToUpload.removeLast(); - removeImage(texture->imageRef()); - return m_imagesToUpload.size(); + HashMap<unsigned, ImageTexture*>::iterator end = m_images.end(); + for (HashMap<unsigned, ImageTexture*>::iterator it = m_images.begin(); it != end; ++it) { + ret |= it->second->prepareGL(state); + } + return ret; } } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/ImagesManager.h b/Source/WebCore/platform/graphics/android/ImagesManager.h index 2fcb9fd..a3ea859 100644 --- a/Source/WebCore/platform/graphics/android/ImagesManager.h +++ b/Source/WebCore/platform/graphics/android/ImagesManager.h @@ -35,17 +35,18 @@ namespace WebCore { class ImageTexture; +class GLWebViewState; class ImagesManager { public: static ImagesManager* instance(); - void addImage(SkBitmapRef* img); - void removeImage(SkBitmapRef* img); - ImageTexture* getTextureForImage(SkBitmapRef* img, bool retain = true); - void showImages(); - void scheduleTextureUpload(ImageTexture* texture); - bool uploadTextures(); + ImageTexture* setImage(SkBitmapRef* imgRef); + ImageTexture* retainImage(unsigned imgCRC); + void releaseImage(unsigned imgCRC); + + bool prepareTextures(GLWebViewState*); + int nbTextures(); private: ImagesManager() {} @@ -53,8 +54,7 @@ private: static ImagesManager* gInstance; android::Mutex m_imagesLock; - HashMap<SkBitmapRef*, ImageTexture*> m_images; - Vector<ImageTexture*> m_imagesToUpload; + HashMap<unsigned, ImageTexture*> m_images; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp index 86991d5..1cd2b1a 100644 --- a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp @@ -149,8 +149,7 @@ LayerAndroid::LayerAndroid(RenderLayer* owner) : Layer(), m_recordingPicture(0), m_uniqueId(++gUniqueId), m_texture(0), - m_imageRef(0), - m_imageTexture(0), + m_imageCRC(0), m_pictureUsed(0), m_scale(1), m_lastComputeTextureSize(0), @@ -174,15 +173,15 @@ LayerAndroid::LayerAndroid(const LayerAndroid& layer) : Layer(layer), m_isIframe(layer.m_isIframe), m_uniqueId(layer.m_uniqueId), m_texture(0), - m_imageTexture(0), m_owningLayer(layer.m_owningLayer), m_type(LayerAndroid::UILayer), m_hasText(true) { m_isFixed = layer.m_isFixed; - m_imageRef = layer.m_imageRef; - if (m_imageRef) - ImagesManager::instance()->addImage(m_imageRef); + m_imageCRC = layer.m_imageCRC; + if (m_imageCRC) + ImagesManager::instance()->retainImage(m_imageCRC); + m_renderLayerPos = layer.m_renderLayerPos; m_transform = layer.m_transform; m_backfaceVisibility = layer.m_backfaceVisibility; @@ -223,7 +222,7 @@ LayerAndroid::LayerAndroid(const LayerAndroid& layer) : Layer(layer), m_hasText = layer.m_hasText; #ifdef DEBUG_COUNT - ClassTracker::instance()->increment("LayerAndroid - recopy (UI?)"); + ClassTracker::instance()->increment("LayerAndroid - recopy (UI)"); ClassTracker::instance()->add(this); #endif } @@ -252,8 +251,7 @@ LayerAndroid::LayerAndroid(SkPicture* picture) : Layer(), m_recordingPicture(picture), m_uniqueId(++gUniqueId), m_texture(0), - m_imageRef(0), - m_imageTexture(0), + m_imageCRC(0), m_scale(1), m_lastComputeTextureSize(0), m_owningLayer(0), @@ -272,8 +270,9 @@ LayerAndroid::LayerAndroid(SkPicture* picture) : Layer(), LayerAndroid::~LayerAndroid() { - if (m_imageTexture) - ImagesManager::instance()->removeImage(m_imageTexture->imageRef()); + if (m_imageCRC) + ImagesManager::instance()->releaseImage(m_imageCRC); + SkSafeUnref(m_recordingPicture); m_animations.clear(); #ifdef DEBUG_COUNT @@ -761,16 +760,14 @@ void LayerAndroid::updateGLPositionsAndScale(const TransformationMatrix& parentM void LayerAndroid::setContentsImage(SkBitmapRef* img) { - m_imageRef = img; - if (!img) - return; - - ImagesManager::instance()->addImage(img); + ImageTexture* image = ImagesManager::instance()->setImage(img); + ImagesManager::instance()->releaseImage(m_imageCRC); + m_imageCRC = image ? image->imageCRC() : 0; } bool LayerAndroid::needsTexture() { - return m_imageRef || (m_recordingPicture + return m_imageCRC || (m_recordingPicture && m_recordingPicture->width() && m_recordingPicture->height()); } @@ -841,10 +838,11 @@ void LayerAndroid::showLayer(int indent) IntRect visible = visibleArea(); IntRect clip(m_clippingRect.x(), m_clippingRect.y(), m_clippingRect.width(), m_clippingRect.height()); - XLOGC("%s [%d:0x%x] - %s - area (%d, %d, %d, %d) - visible (%d, %d, %d, %d) " + XLOGC("%s [%d:0x%x] - %s %s - area (%d, %d, %d, %d) - visible (%d, %d, %d, %d) " "clip (%d, %d, %d, %d) %s %s prepareContext(%x), pic w: %d h: %d", spaces, uniqueId(), m_owningLayer, needsTexture() ? "needs a texture" : "no texture", + m_imageCRC ? "has an image" : "no image", tr.x(), tr.y(), tr.width(), tr.height(), visible.x(), visible.y(), visible.width(), visible.height(), clip.x(), clip.y(), clip.width(), clip.height(), @@ -983,11 +981,11 @@ bool LayerAndroid::updateWithLayer(LayerAndroid* layer) m_opacity = layer->m_opacity; m_transform = layer->m_transform; - if (m_imageRef != layer->m_imageRef) + if (m_imageCRC != layer->m_imageCRC) m_visible = false; if ((m_recordingPicture != layer->m_recordingPicture) - || (m_imageRef != layer->m_imageRef)) + || (m_imageCRC != layer->m_imageCRC)) return true; return false; @@ -998,11 +996,7 @@ void LayerAndroid::obtainTextureForPainting(LayerAndroid* drawingLayer) if (!needsTexture()) return; - if (m_imageRef) { - if (!m_imageTexture) { - m_imageTexture = ImagesManager::instance()->getTextureForImage(m_imageRef); - m_dirtyRegion.setEmpty(); - } + if (m_imageCRC) { if (m_texture) { m_texture->setDrawingLayer(0); m_texture->clearPaintingLayer(); @@ -1019,8 +1013,8 @@ void LayerAndroid::obtainTextureForPainting(LayerAndroid* drawingLayer) // pass the invalidated regions to the PaintedSurface m_texture->setPaintingLayer(this, m_dirtyRegion); - m_dirtyRegion.setEmpty(); } + m_dirtyRegion.setEmpty(); } @@ -1062,9 +1056,6 @@ void LayerAndroid::prepare() if (m_texture) m_texture->prepare(m_state); - - if (m_imageTexture) - m_imageTexture->prepareGL(); } IntRect LayerAndroid::unclippedArea() @@ -1148,9 +1139,12 @@ bool LayerAndroid::drawGL() if (m_state->layersRenderingMode() < GLWebViewState::kScrollableAndFixedLayers) { if (m_texture) askScreenUpdate |= m_texture->draw(); - - if (m_imageTexture) - m_imageTexture->drawGL(this); + if (m_imageCRC) { + ImageTexture* imageTexture = ImagesManager::instance()->retainImage(m_imageCRC); + if (imageTexture) + imageTexture->drawGL(this); + ImagesManager::instance()->releaseImage(m_imageCRC); + } } // When the layer is dirty, the UI thread should be notified to redraw. @@ -1248,16 +1242,15 @@ void LayerAndroid::onDraw(SkCanvas* canvas, SkScalar opacity) if (canvasOpacity < 255) canvas->setDrawFilter(new OpacityDrawFilter(canvasOpacity)); - if (m_imageRef) { - if (!m_imageTexture) { - m_imageTexture = ImagesManager::instance()->getTextureForImage(m_imageRef); - m_dirtyRegion.setEmpty(); - } - if (m_imageTexture) { + if (m_imageCRC) { + ImageTexture* imageTexture = ImagesManager::instance()->retainImage(m_imageCRC); + m_dirtyRegion.setEmpty(); + if (imageTexture) { SkRect dest; dest.set(0, 0, getSize().width(), getSize().height()); - m_imageTexture->drawCanvas(canvas, dest); + imageTexture->drawCanvas(canvas, dest); } + ImagesManager::instance()->releaseImage(m_imageCRC); } contentDraw(canvas); } diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.h b/Source/WebCore/platform/graphics/android/LayerAndroid.h index 8b82b27..cc96fae 100644 --- a/Source/WebCore/platform/graphics/android/LayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/LayerAndroid.h @@ -260,7 +260,7 @@ public: /** This sets a content image -- calling it means we will use the image directly when drawing the layer instead of using the content painted by WebKit. - Images are handled in TilesManager, as they can be shared + Images are handled in ImagesManager, as they can be shared between layers. */ void setContentsImage(SkBitmapRef* img); @@ -298,8 +298,6 @@ public: bool updateWithTree(LayerAndroid*); virtual bool updateWithLayer(LayerAndroid*); - SkBitmapRef* imageRef() { return m_imageRef; } - ImageTexture* imageTexture() { return m_imageTexture; } int type() { return m_type; } bool hasText() { return m_hasText; } @@ -387,8 +385,7 @@ private: int m_uniqueId; PaintedSurface* m_texture; - SkBitmapRef* m_imageRef; - ImageTexture* m_imageTexture; + unsigned m_imageCRC; unsigned int m_pictureUsed; diff --git a/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp b/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp index 5d06ea3..2d69706 100644 --- a/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp +++ b/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp @@ -25,12 +25,14 @@ #include "config.h" #include "PaintTileOperation.h" +#include "ImageTexture.h" +#include "ImagesManager.h" #include "LayerAndroid.h" #include "PaintedSurface.h" namespace WebCore { -PaintTileOperation::PaintTileOperation(BaseTile* tile, PaintedSurface* surface) +PaintTileOperation::PaintTileOperation(BaseTile* tile, SurfacePainter* surface) : QueuedOperation(QueuedOperation::PaintTile, tile->page()) , m_tile(tile) , m_surface(surface) @@ -46,7 +48,13 @@ PaintTileOperation::~PaintTileOperation() m_tile->setRepaintPending(false); m_tile = 0; } - SkSafeUnref(m_surface); + + if (m_surface && m_surface->type() == SurfacePainter::ImageSurface) { + ImageTexture* image = static_cast<ImageTexture*>(m_surface); + ImagesManager::instance()->releaseImage(image->imageCRC()); + } else { + SkSafeUnref(m_surface); + } } bool PaintTileOperation::operator==(const QueuedOperation* operation) diff --git a/Source/WebCore/platform/graphics/android/PaintTileOperation.h b/Source/WebCore/platform/graphics/android/PaintTileOperation.h index fabc2f7..bc74d03 100644 --- a/Source/WebCore/platform/graphics/android/PaintTileOperation.h +++ b/Source/WebCore/platform/graphics/android/PaintTileOperation.h @@ -28,15 +28,17 @@ #include "BaseTile.h" #include "QueuedOperation.h" +#include "SkRefCnt.h" namespace WebCore { class LayerAndroid; -class PaintedSurface; +class SurfacePainter; +class ImageTexture; class PaintTileOperation : public QueuedOperation { public: - PaintTileOperation(BaseTile* tile, PaintedSurface* surface = 0); + PaintTileOperation(BaseTile* tile, SurfacePainter* surface = 0); virtual ~PaintTileOperation(); virtual bool operator==(const QueuedOperation* operation); virtual void run(); @@ -47,7 +49,7 @@ public: private: BaseTile* m_tile; - PaintedSurface* m_surface; + SurfacePainter* m_surface; }; class ScaleFilter : public OperationFilter { diff --git a/Source/WebCore/platform/graphics/android/PaintedSurface.h b/Source/WebCore/platform/graphics/android/PaintedSurface.h index b438111..b8ab7b8 100644 --- a/Source/WebCore/platform/graphics/android/PaintedSurface.h +++ b/Source/WebCore/platform/graphics/android/PaintedSurface.h @@ -43,7 +43,7 @@ namespace WebCore { class DualTiledTexture; -class PaintedSurface : public SkRefCnt { +class PaintedSurface : public SurfacePainter { public: PaintedSurface(); virtual ~PaintedSurface(); @@ -71,10 +71,10 @@ public: // TilePainter methods for TiledTexture virtual const TransformationMatrix* transform(); + virtual float opacity(); // used by TiledTexture float scale() { return m_scale; } - float opacity(); unsigned int pictureUsed() { return m_pictureUsed; } private: diff --git a/Source/WebCore/platform/graphics/android/TilePainter.h b/Source/WebCore/platform/graphics/android/TilePainter.h index 91030cb..4d0f5dc 100644 --- a/Source/WebCore/platform/graphics/android/TilePainter.h +++ b/Source/WebCore/platform/graphics/android/TilePainter.h @@ -27,6 +27,7 @@ #define TilePainter_h #include "TransformationMatrix.h" +#include "SkRefCnt.h" class SkCanvas; @@ -41,6 +42,15 @@ public: virtual const TransformationMatrix* transform() { return 0; } }; +class SurfacePainter : public SkRefCnt { +public: + virtual ~SurfacePainter() { } + virtual const TransformationMatrix* transform() { return 0; } + virtual float opacity() { return 1.0; } + enum SurfaceType { PaintedSurface, ImageSurface }; + virtual SurfaceType type() { return PaintedSurface; } +}; + } #endif // TilePainter_h diff --git a/Source/WebCore/platform/graphics/android/TiledTexture.cpp b/Source/WebCore/platform/graphics/android/TiledTexture.cpp index 91d6897..6711527 100644 --- a/Source/WebCore/platform/graphics/android/TiledTexture.cpp +++ b/Source/WebCore/platform/graphics/android/TiledTexture.cpp @@ -204,6 +204,7 @@ void TiledTexture::prepareTile(bool repaint, int x, int y) if (tile->isDirty() || !tile->frontTexture()) tile->reserveTexture(); + bool hasPicture = m_paintingPicture != 0; // safely read on UI thread, since only UI thread writes if (tile->backTexture() && tile->isDirty() && !tile->isRepaintPending() && hasPicture) { PaintTileOperation *operation = new PaintTileOperation(tile, m_surface); @@ -229,6 +230,9 @@ int TiledTexture::nbTextures(IntRect& area, float scale) bool TiledTexture::draw() { + if (!m_surface) + return true; + XLOG("TT %p draw", this); #ifdef DEBUG @@ -257,8 +261,8 @@ bool TiledTexture::draw() rect.fTop = tile->y() * tileHeight; rect.fRight = rect.fLeft + tileWidth; rect.fBottom = rect.fTop + tileHeight; - XLOG("- [%d], { painter %x vs %x }, tile %x %d,%d at scale %.2f vs %.2f [ready: %d] dirty: %d", - i, this, tile->painter(), tile, tile->x(), tile->y(), + XLOG("- [%d], { painter %x vs %x }, tile %x (layer tile: %d) %d,%d at scale %.2f vs %.2f [ready: %d] dirty: %d", + i, this, tile->painter(), tile, tile->isLayerTile(), tile->x(), tile->y(), tile->scale(), m_scale, tile->isTileReady(), tile->isDirty()); tile->draw(m_surface->opacity(), rect, m_scale); #ifdef DEBUG @@ -283,7 +287,7 @@ bool TiledTexture::paint(BaseTile* tile, SkCanvas* canvas, unsigned int* picture return false; } - XLOG("TT %p painting with picture %p", this, picture); + XLOG("TT %p painting tile %d, %d with picture %p", this, tile->x(), tile->y(), picture); canvas->drawPicture(*picture); @@ -294,6 +298,8 @@ bool TiledTexture::paint(BaseTile* tile, SkCanvas* canvas, unsigned int* picture const TransformationMatrix* TiledTexture::transform() { + if (!m_surface) + return 0; return m_surface->transform(); } @@ -323,7 +329,7 @@ bool TiledTexture::owns(BaseTileTexture* texture) return false; } -DualTiledTexture::DualTiledTexture(PaintedSurface* surface) +DualTiledTexture::DualTiledTexture(SurfacePainter* surface) { m_textureA = new TiledTexture(surface); m_textureB = new TiledTexture(surface); diff --git a/Source/WebCore/platform/graphics/android/TiledTexture.h b/Source/WebCore/platform/graphics/android/TiledTexture.h index b761880..444ab14 100644 --- a/Source/WebCore/platform/graphics/android/TiledTexture.h +++ b/Source/WebCore/platform/graphics/android/TiledTexture.h @@ -39,11 +39,9 @@ class SkCanvas; namespace WebCore { -class PaintedSurface; - class TiledTexture : public TilePainter { public: - TiledTexture(PaintedSurface* surface) + TiledTexture(SurfacePainter* surface) : m_paintingPicture(0) , m_surface(surface) , m_prevTileX(0) @@ -82,8 +80,6 @@ public: float scale() { return m_scale; } bool ready(); - PaintedSurface* surface() { return m_surface; } - int nbTextures(IntRect& area, float scale); private: @@ -95,7 +91,7 @@ private: android::Mutex m_paintingPictureSync; SkPicture* m_paintingPicture; - PaintedSurface* m_surface; + SurfacePainter* m_surface; Vector<BaseTile*> m_tiles; // tile coordinates in viewport, set in prepare() @@ -112,7 +108,7 @@ private: class DualTiledTexture { public: - DualTiledTexture(PaintedSurface* surface); + DualTiledTexture(SurfacePainter* surface); ~DualTiledTexture(); void prepare(GLWebViewState* state, float scale, bool repaint, bool startFastSwap, IntRect& area); diff --git a/Source/WebCore/platform/graphics/android/TilesManager.cpp b/Source/WebCore/platform/graphics/android/TilesManager.cpp index 219435d..30bd8d0 100644 --- a/Source/WebCore/platform/graphics/android/TilesManager.cpp +++ b/Source/WebCore/platform/graphics/android/TilesManager.cpp @@ -189,6 +189,23 @@ void TilesManager::deallocateTexturesVector(unsigned long long sparedDrawCount, dealloc, max, maxLayer); } +void TilesManager::gatherTexturesNumbers(int* nbTextures, int* nbAllocatedTextures, + int* nbLayerTextures, int* nbAllocatedLayerTextures) +{ + *nbTextures = m_textures.size(); + for (unsigned int i = 0; i < m_textures.size(); i++) { + BaseTileTexture* texture = m_textures[i]; + if (texture->m_ownTextureId) + *nbAllocatedTextures += 1; + } + *nbLayerTextures = m_tilesTextures.size(); + for (unsigned int i = 0; i < m_tilesTextures.size(); i++) { + BaseTileTexture* texture = m_tilesTextures[i]; + if (texture->m_ownTextureId) + *nbAllocatedLayerTextures += 1; + } +} + void TilesManager::printTextures() { #ifdef DEBUG diff --git a/Source/WebCore/platform/graphics/android/TilesManager.h b/Source/WebCore/platform/graphics/android/TilesManager.h index 0c3e900..9782fbb 100644 --- a/Source/WebCore/platform/graphics/android/TilesManager.h +++ b/Source/WebCore/platform/graphics/android/TilesManager.h @@ -88,6 +88,8 @@ public: void gatherLayerTextures(); void gatherTextures(); bool layerTexturesRemain() { return m_layerTexturesRemain; } + void gatherTexturesNumbers(int* nbTextures, int* nbAllocatedTextures, + int* nbLayerTextures, int* nbAllocatedLayerTextures); BaseTileTexture* getAvailableTexture(BaseTile* owner); |