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
scheduleOperation(QueuedOperation * operation)54 void TexturesGenerator::scheduleOperation(QueuedOperation* operation)
55 {
56 {
57 android::Mutex::Autolock lock(mRequestedOperationsLock);
58 mRequestedOperations.append(operation);
59 }
60 mRequestedOperationsCond.signal();
61 }
62
removeOperationsForPage(TiledPage * page)63 void TexturesGenerator::removeOperationsForPage(TiledPage* page)
64 {
65 removeOperationsForFilter(new PageFilter(page));
66 }
67
removePaintOperationsForPage(TiledPage * page,bool waitForRunning)68 void TexturesGenerator::removePaintOperationsForPage(TiledPage* page, bool waitForRunning)
69 {
70 removeOperationsForFilter(new PagePaintFilter(page), waitForRunning);
71 }
72
removeOperationsForFilter(OperationFilter * filter)73 void TexturesGenerator::removeOperationsForFilter(OperationFilter* filter)
74 {
75 removeOperationsForFilter(filter, true);
76 }
77
removeOperationsForFilter(OperationFilter * filter,bool waitForRunning)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
readyToRun()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!
popNext()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
threadLoop()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 mRequestedOperationsLock.lock();
188 if (m_currentOperation) {
189 delete m_currentOperation;
190 m_currentOperation = 0;
191 }
192 if (!mRequestedOperations.size())
193 stop = true;
194 if (m_waitForCompletion) {
195 m_waitForCompletion = false;
196 TilesManager::instance()->transferQueue()->interruptTransferQueue(false);
197 mRequestedOperationsCond.signal();
198 }
199 mRequestedOperationsLock.unlock();
200
201 }
202 XLOG("threadLoop empty");
203
204 return true;
205 }
206
207 } // namespace WebCore
208
209 #endif // USE(ACCELERATED_COMPOSITING)
210