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
41 namespace WebCore {
42
TexturesGenerator(TilesManager * instance)43 TexturesGenerator::TexturesGenerator(TilesManager* instance)
44 : Thread(false)
45 , m_tilesManager(instance)
46 , m_deferredMode(false)
47 , m_renderer(0)
48 {
49 }
50
~TexturesGenerator()51 TexturesGenerator::~TexturesGenerator()
52 {
53 delete m_renderer;
54 }
55
tryUpdateOperationWithPainter(Tile * tile,TilePainter * painter)56 bool 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
scheduleOperation(QueuedOperation * operation)66 void 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
removeOperationsForFilter(OperationFilter * filter)84 void 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
readyToRun()102 status_t TexturesGenerator::readyToRun()
103 {
104 m_renderer = BaseRenderer::createRenderer();
105 return NO_ERROR;
106 }
107
108 // Must be called from within a lock!
popNext()109 QueuedOperation* 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
threadLoop()151 bool 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