Home | History | Annotate | Download | only in android
      1 /*
      2  * Copyright 2010, The Android Open Source Project
      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  *  * Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  *  * 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 THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "TexturesGenerator.h"
     28 
     29 #if USE(ACCELERATED_COMPOSITING)
     30 
     31 #include "BaseLayerAndroid.h"
     32 #include "GLUtils.h"
     33 #include "PaintTileOperation.h"
     34 #include "TilesManager.h"
     35 
     36 #ifdef DEBUG
     37 
     38 #include <cutils/log.h>
     39 #include <wtf/CurrentTime.h>
     40 #include <wtf/text/CString.h>
     41 
     42 #undef XLOG
     43 #define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "TexturesGenerator", __VA_ARGS__)
     44 
     45 #else
     46 
     47 #undef XLOG
     48 #define XLOG(...)
     49 
     50 #endif // DEBUG
     51 
     52 namespace WebCore {
     53 
     54 void TexturesGenerator::scheduleOperation(QueuedOperation* operation)
     55 {
     56     {
     57         android::Mutex::Autolock lock(mRequestedOperationsLock);
     58         mRequestedOperations.append(operation);
     59     }
     60     mRequestedOperationsCond.signal();
     61 }
     62 
     63 void TexturesGenerator::removeOperationsForPage(TiledPage* page)
     64 {
     65     removeOperationsForFilter(new PageFilter(page));
     66 }
     67 
     68 void TexturesGenerator::removePaintOperationsForPage(TiledPage* page, bool waitForRunning)
     69 {
     70     removeOperationsForFilter(new PagePaintFilter(page), waitForRunning);
     71 }
     72 
     73 void TexturesGenerator::removeOperationsForFilter(OperationFilter* filter)
     74 {
     75     removeOperationsForFilter(filter, true);
     76 }
     77 
     78 void TexturesGenerator::removeOperationsForFilter(OperationFilter* filter, bool waitForRunning)
     79 {
     80     if (!filter)
     81         return;
     82 
     83     android::Mutex::Autolock lock(mRequestedOperationsLock);
     84     for (unsigned int i = 0; i < mRequestedOperations.size();) {
     85         QueuedOperation* operation = mRequestedOperations[i];
     86         if (filter->check(operation)) {
     87             mRequestedOperations.remove(i);
     88             delete operation;
     89         } else {
     90             i++;
     91         }
     92     }
     93 
     94     if (waitForRunning && m_currentOperation) {
     95         QueuedOperation* operation = m_currentOperation;
     96 
     97         if (operation && filter->check(operation)) {
     98             m_waitForCompletion = true;
     99             // The reason we are signaling the transferQueue is :
    100             // TransferQueue may be waiting a slot to work on, but now UI
    101             // thread is waiting for Tex Gen thread to finish first before the
    102             // UI thread can free a slot for the transferQueue.
    103             // Therefore, it could be a deadlock.
    104             // The solution is use this as a flag to tell Tex Gen thread that
    105             // UI thread is waiting now, Tex Gen thread should not wait for the
    106             // queue any more.
    107             TilesManager::instance()->transferQueue()->interruptTransferQueue(true);
    108         }
    109 
    110         delete filter;
    111 
    112         // At this point, it means that we are currently executing an operation that
    113         // we want to be removed -- we should wait until it is done, so that
    114         // when we return our caller can be sure that there is no more operations
    115         // in the queue matching the given filter.
    116         while (m_waitForCompletion)
    117             mRequestedOperationsCond.wait(mRequestedOperationsLock);
    118     } else {
    119         delete filter;
    120     }
    121 }
    122 
    123 status_t TexturesGenerator::readyToRun()
    124 {
    125     TilesManager::instance()->markGeneratorAsReady();
    126     XLOG("Thread ready to run");
    127     return NO_ERROR;
    128 }
    129 
    130 // Must be called from within a lock!
    131 QueuedOperation* TexturesGenerator::popNext()
    132 {
    133     // Priority can change between when it was added and now
    134     // Hence why the entire queue is rescanned
    135     QueuedOperation* current = mRequestedOperations.last();
    136     int currentPriority = current->priority();
    137     if (currentPriority < 0) {
    138         mRequestedOperations.removeLast();
    139         return current;
    140     }
    141     int currentIndex = mRequestedOperations.size() - 1;
    142     // Scan from the back to make removing faster (less items to copy)
    143     for (int i = mRequestedOperations.size() - 2; i >= 0; i--) {
    144         QueuedOperation *next = mRequestedOperations[i];
    145         int nextPriority = next->priority();
    146         if (nextPriority < 0) {
    147             // Found a very high priority item, go ahead and just handle it now
    148             mRequestedOperations.remove(i);
    149             return next;
    150         }
    151         // pick items preferrably by priority, or if equal, by order of
    152         // insertion (as we add items at the back of the queue)
    153         if (nextPriority <= currentPriority) {
    154             current = next;
    155             currentPriority = nextPriority;
    156             currentIndex = i;
    157         }
    158     }
    159     mRequestedOperations.remove(currentIndex);
    160     return current;
    161 }
    162 
    163 bool TexturesGenerator::threadLoop()
    164 {
    165     // Check if we have any pending operations.
    166     mRequestedOperationsLock.lock();
    167     while (!mRequestedOperations.size())
    168         mRequestedOperationsCond.wait(mRequestedOperationsLock);
    169 
    170     XLOG("threadLoop, got signal");
    171     mRequestedOperationsLock.unlock();
    172 
    173     m_currentOperation = 0;
    174     bool stop = false;
    175     while (!stop) {
    176         mRequestedOperationsLock.lock();
    177         XLOG("threadLoop, %d operations in the queue", mRequestedOperations.size());
    178         if (mRequestedOperations.size())
    179             m_currentOperation = popNext();
    180         mRequestedOperationsLock.unlock();
    181 
    182         if (m_currentOperation) {
    183             XLOG("threadLoop, painting the request with priority %d", m_currentOperation->priority());
    184             m_currentOperation->run();
    185         }
    186 
    187         QueuedOperation* oldOperation = m_currentOperation;
    188         mRequestedOperationsLock.lock();
    189         if (m_currentOperation)
    190             m_currentOperation = 0;
    191         if (!mRequestedOperations.size())
    192             stop = true;
    193         if (m_waitForCompletion) {
    194             m_waitForCompletion = false;
    195             TilesManager::instance()->transferQueue()->interruptTransferQueue(false);
    196             mRequestedOperationsCond.signal();
    197         }
    198         mRequestedOperationsLock.unlock();
    199         if (oldOperation)
    200             delete oldOperation; // delete outside lock
    201     }
    202     XLOG("threadLoop empty");
    203 
    204     return true;
    205 }
    206 
    207 } // namespace WebCore
    208 
    209 #endif // USE(ACCELERATED_COMPOSITING)
    210