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