Home | History | Annotate | Download | only in chromium
      1 /*
      2 Copyright (C) 2012 Google Inc. All rights reserved.
      3 
      4 Redistribution and use in source and binary forms, with or without
      5 modification, are permitted provided that the following conditions
      6 are met:
      7 1.  Redistributions of source code must retain the above copyright
      8     notice, this list of conditions and the following disclaimer.
      9 2.  Redistributions in binary form must reproduce the above copyright
     10     notice, this list of conditions and the following disclaimer in the
     11     documentation and/or other materials provided with the distribution.
     12 
     13 THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
     14 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     15 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     16 DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     17 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     18 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     19 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     20 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     21 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     22 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     23 */
     24 #include "config.h"
     25 
     26 #include "core/platform/graphics/chromium/Canvas2DLayerManager.h"
     27 
     28 #include "public/platform/Platform.h"
     29 #include "wtf/StdLibExtras.h"
     30 
     31 using WebKit::WebThread;
     32 
     33 namespace {
     34 enum {
     35     DefaultMaxBytesAllocated = 64*1024*1024,
     36     DefaultTargetBytesAllocated = 16*1024*1024,
     37 };
     38 }
     39 
     40 namespace WebCore {
     41 
     42 Canvas2DLayerManager::Canvas2DLayerManager()
     43     : m_bytesAllocated(0)
     44     , m_maxBytesAllocated(DefaultMaxBytesAllocated)
     45     , m_targetBytesAllocated(DefaultTargetBytesAllocated)
     46     , m_taskObserverActive(false)
     47 {
     48 }
     49 
     50 Canvas2DLayerManager::~Canvas2DLayerManager()
     51 {
     52     ASSERT(!m_bytesAllocated);
     53     ASSERT(!m_layerList.head());
     54     ASSERT(!m_taskObserverActive);
     55 }
     56 
     57 void Canvas2DLayerManager::init(size_t maxBytesAllocated, size_t targetBytesAllocated)
     58 {
     59     ASSERT(maxBytesAllocated >= targetBytesAllocated);
     60     m_maxBytesAllocated = maxBytesAllocated;
     61     m_targetBytesAllocated = targetBytesAllocated;
     62     if (m_taskObserverActive) {
     63         WebKit::Platform::current()->currentThread()->removeTaskObserver(this);
     64         m_taskObserverActive = false;
     65     }
     66 }
     67 
     68 Canvas2DLayerManager& Canvas2DLayerManager::get()
     69 {
     70     DEFINE_STATIC_LOCAL(Canvas2DLayerManager, manager, ());
     71     return manager;
     72 }
     73 
     74 void Canvas2DLayerManager::willProcessTask()
     75 {
     76 }
     77 
     78 void Canvas2DLayerManager::didProcessTask()
     79 {
     80     // Called after the script action for the current frame has been processed.
     81     ASSERT(m_taskObserverActive);
     82     WebKit::Platform::current()->currentThread()->removeTaskObserver(this);
     83     m_taskObserverActive = false;
     84     for (Canvas2DLayerBridge* layer = m_layerList.head(); layer; layer = layer->next())
     85         layer->limitPendingFrames();
     86 }
     87 
     88 void Canvas2DLayerManager::layerDidDraw(Canvas2DLayerBridge* layer)
     89 {
     90     if (isInList(layer)) {
     91         if (layer != m_layerList.head()) {
     92             m_layerList.remove(layer);
     93             m_layerList.push(layer); // Set as MRU
     94         }
     95     } else
     96         addLayerToList(layer);
     97 
     98     if (!m_taskObserverActive) {
     99         m_taskObserverActive = true;
    100         // Schedule a call to didProcessTask() after completion of the current script task.
    101         WebKit::Platform::current()->currentThread()->addTaskObserver(this);
    102     }
    103 }
    104 
    105 void Canvas2DLayerManager::addLayerToList(Canvas2DLayerBridge* layer)
    106 {
    107     ASSERT(!isInList(layer));
    108     m_bytesAllocated += layer->bytesAllocated();
    109     m_layerList.push(layer); // Set as MRU
    110 }
    111 
    112 void Canvas2DLayerManager::layerAllocatedStorageChanged(Canvas2DLayerBridge* layer, intptr_t deltaBytes)
    113 {
    114     if (!isInList(layer))
    115         addLayerToList(layer);
    116     else {
    117         ASSERT((intptr_t)m_bytesAllocated + deltaBytes >= 0);
    118         m_bytesAllocated = (intptr_t)m_bytesAllocated + deltaBytes;
    119     }
    120     if (deltaBytes > 0)
    121         freeMemoryIfNecessary();
    122 }
    123 
    124 void Canvas2DLayerManager::layerToBeDestroyed(Canvas2DLayerBridge* layer)
    125 {
    126     if (isInList(layer))
    127         removeLayerFromList(layer);
    128 }
    129 
    130 void Canvas2DLayerManager::freeMemoryIfNecessary()
    131 {
    132     if (m_bytesAllocated > m_maxBytesAllocated) {
    133         // Pass 1: Free memory from caches
    134         Canvas2DLayerBridge* layer = m_layerList.tail(); // LRU
    135         while (m_bytesAllocated > m_targetBytesAllocated && layer) {
    136             layer->freeMemoryIfPossible(m_bytesAllocated - m_targetBytesAllocated);
    137             layer = layer->prev();
    138         }
    139 
    140         // Pass 2: Flush canvases
    141         Canvas2DLayerBridge* leastRecentlyUsedLayer = m_layerList.tail();
    142         while (m_bytesAllocated > m_targetBytesAllocated && leastRecentlyUsedLayer) {
    143             leastRecentlyUsedLayer->flush();
    144             leastRecentlyUsedLayer->freeMemoryIfPossible(~0);
    145             removeLayerFromList(leastRecentlyUsedLayer);
    146             leastRecentlyUsedLayer = m_layerList.tail();
    147         }
    148     }
    149 }
    150 
    151 void Canvas2DLayerManager::removeLayerFromList(Canvas2DLayerBridge* layer)
    152 {
    153     ASSERT(isInList(layer));
    154     m_bytesAllocated -= layer->bytesAllocated();
    155     m_layerList.remove(layer);
    156     layer->setNext(0);
    157     layer->setPrev(0);
    158 }
    159 
    160 bool Canvas2DLayerManager::isInList(Canvas2DLayerBridge* layer)
    161 {
    162     return layer->prev() || m_layerList.head() == layer;
    163 }
    164 
    165 }
    166 
    167