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#define LOG_TAG "TexturesGenerator" 27#define LOG_NDEBUG 1 28 29#include "config.h" 30#include "TexturesGenerator.h" 31 32#if USE(ACCELERATED_COMPOSITING) 33 34#include "AndroidLog.h" 35#include "BaseRenderer.h" 36#include "GLUtils.h" 37#include "PaintTileOperation.h" 38#include "TilesManager.h" 39#include "TransferQueue.h" 40 41namespace WebCore { 42 43TexturesGenerator::TexturesGenerator(TilesManager* instance) 44 : Thread(false) 45 , m_tilesManager(instance) 46 , m_deferredMode(false) 47 , m_renderer(0) 48{ 49} 50 51TexturesGenerator::~TexturesGenerator() 52{ 53 delete m_renderer; 54} 55 56bool TexturesGenerator::tryUpdateOperationWithPainter(Tile* tile, TilePainter* painter) 57{ 58 android::Mutex::Autolock lock(mRequestedOperationsLock); 59 if (!mRequestedOperationsHash.contains(tile)) 60 return false; 61 62 static_cast<PaintTileOperation*>(mRequestedOperationsHash.get(tile))->updatePainter(painter); 63 return true; 64} 65 66void TexturesGenerator::scheduleOperation(QueuedOperation* operation) 67{ 68 bool signal = false; 69 { 70 android::Mutex::Autolock lock(mRequestedOperationsLock); 71 mRequestedOperations.append(operation); 72 mRequestedOperationsHash.set(operation->uniquePtr(), operation); 73 74 bool deferrable = operation->priority() >= gDeferPriorityCutoff; 75 m_deferredMode &= deferrable; 76 77 // signal if we weren't in deferred mode, or if we can no longer defer 78 signal = !m_deferredMode || !deferrable; 79 } 80 if (signal) 81 mRequestedOperationsCond.signal(); 82} 83 84void TexturesGenerator::removeOperationsForFilter(OperationFilter* filter) 85{ 86 if (!filter) 87 return; 88 89 android::Mutex::Autolock lock(mRequestedOperationsLock); 90 for (unsigned int i = 0; i < mRequestedOperations.size();) { 91 QueuedOperation* operation = mRequestedOperations[i]; 92 if (filter->check(operation)) { 93 mRequestedOperations.remove(i); 94 mRequestedOperationsHash.remove(operation->uniquePtr()); 95 delete operation; 96 } else { 97 i++; 98 } 99 } 100} 101 102status_t TexturesGenerator::readyToRun() 103{ 104 m_renderer = BaseRenderer::createRenderer(); 105 return NO_ERROR; 106} 107 108// Must be called from within a lock! 109QueuedOperation* TexturesGenerator::popNext() 110{ 111 // Priority can change between when it was added and now 112 // Hence why the entire queue is rescanned 113 QueuedOperation* current = mRequestedOperations.last(); 114 int currentPriority = current->priority(); 115 if (currentPriority < 0) { 116 mRequestedOperations.removeLast(); 117 mRequestedOperationsHash.remove(current->uniquePtr()); 118 return current; 119 } 120 int currentIndex = mRequestedOperations.size() - 1; 121 // Scan from the back to make removing faster (less items to copy) 122 for (int i = mRequestedOperations.size() - 2; i >= 0; i--) { 123 QueuedOperation *next = mRequestedOperations[i]; 124 int nextPriority = next->priority(); 125 if (nextPriority < 0) { 126 // Found a very high priority item, go ahead and just handle it now 127 mRequestedOperations.remove(i); 128 mRequestedOperationsHash.remove(next->uniquePtr()); 129 return next; 130 } 131 // pick items preferrably by priority, or if equal, by order of 132 // insertion (as we add items at the back of the queue) 133 if (nextPriority <= currentPriority) { 134 current = next; 135 currentPriority = nextPriority; 136 currentIndex = i; 137 } 138 } 139 140 if (!m_deferredMode && currentPriority >= gDeferPriorityCutoff) { 141 // finished with non-deferred rendering, enter deferred mode to wait 142 m_deferredMode = true; 143 return 0; 144 } 145 146 mRequestedOperations.remove(currentIndex); 147 mRequestedOperationsHash.remove(current->uniquePtr()); 148 return current; 149} 150 151bool TexturesGenerator::threadLoop() 152{ 153 // Check if we have any pending operations. 154 mRequestedOperationsLock.lock(); 155 156 if (!m_deferredMode) { 157 // if we aren't currently deferring work, wait for new work to arrive 158 while (!mRequestedOperations.size()) 159 mRequestedOperationsCond.wait(mRequestedOperationsLock); 160 } else { 161 // if we only have deferred work, wait for better work, or a timeout 162 mRequestedOperationsCond.waitRelative(mRequestedOperationsLock, gDeferNsecs); 163 } 164 165 mRequestedOperationsLock.unlock(); 166 167 bool stop = false; 168 while (!stop) { 169 QueuedOperation* currentOperation = 0; 170 171 mRequestedOperationsLock.lock(); 172 ALOGV("threadLoop, %d operations in the queue", mRequestedOperations.size()); 173 174 if (mRequestedOperations.size()) 175 currentOperation = popNext(); 176 mRequestedOperationsLock.unlock(); 177 178 if (currentOperation) { 179 ALOGV("threadLoop, painting the request with priority %d", 180 currentOperation->priority()); 181 // swap out the renderer if necessary 182 BaseRenderer::swapRendererIfNeeded(m_renderer); 183 currentOperation->run(m_renderer); 184 } 185 186 mRequestedOperationsLock.lock(); 187 if (m_deferredMode && !currentOperation) 188 stop = true; 189 if (!mRequestedOperations.size()) { 190 m_deferredMode = false; 191 stop = true; 192 } 193 mRequestedOperationsLock.unlock(); 194 195 if (currentOperation) 196 delete currentOperation; // delete outside lock 197 } 198 ALOGV("threadLoop empty"); 199 200 return true; 201} 202 203} // namespace WebCore 204 205#endif // USE(ACCELERATED_COMPOSITING) 206