Update tile partially
[framework/web/webkit-efl.git] / Source / WebKit2 / WebProcess / WebPage / efl / tizen / PlatformSurfacePoolTizen.cpp
1 /*
2  * Copyright (C) 2012 Samsung Electronics. All rights reserved.
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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. 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 AND CONTRIBUTORS
14  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
15  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
16  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
17  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY 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
28 #if ENABLE(TIZEN_WEBKIT2_TILED_AC_SHARED_PLATFORM_SURFACE)
29 #include "PlatformSurfacePoolTizen.h"
30 #include <WebCore/Logging.h>
31 #include <wtf/HashMap.h>
32 #include "WebProcess.h"
33 #include "WebProcessProxyMessages.h"
34
35 using namespace WebCore;
36
37 namespace WebKit {
38 static const int MB = 1024 * 1024;
39
40 static inline bool reachLowPoolUtilization(int usedSize, int totalSize)
41 {
42     // lowPoolUtilization threshold is 70%.
43     return (usedSize < static_cast<int>(static_cast<float>(totalSize) * 0.7));
44
45 }
46 static inline bool reachHighPoolUtilization(int usedSize, int totalSize)
47 {
48     // highPoolUtilization threshold is 90%.
49     return (usedSize > static_cast<int>(static_cast<float>(totalSize) * 0.9));
50 }
51
52 PlatformSurfacePoolTizen::PlatformSurfaceInfo::PlatformSurfaceInfo(const IntSize& size)
53     : m_used(false)
54     , m_willBeRemoved(false)
55     , m_age(0)
56     , m_tileID(0)
57 {
58     m_SharedPlatformSurfaceTizen =  WebCore::SharedPlatformSurfaceTizen::create(size, true);
59 }
60
61 PlatformSurfacePoolTizen::PlatformSurfacePoolTizen()
62     : m_sizeInByte(0)
63     , m_maxSizeInByte(128 * MB)  // 128 MB
64     , m_usedSizeInByte(0)
65     , m_usedSizeInCount(0)
66     , m_removePlaformSurfaceTimer(this, &PlatformSurfacePoolTizen::removePlaformSurfaceTimerFired)
67 {
68     // FIXME : Create this workqueue and a pixmap temporarily to avoid a crash issue.
69     // The crash occur in cairo gl used by 2dCanvas. It will be removed if the issue is fixed.
70     RefPtr<PlatformSurfaceInfo> newPlatformSurfaceInfo;
71     newPlatformSurfaceInfo = createPlatformSurface(IntSize(384,384));
72 }
73
74 PlatformSurfacePoolTizen::~PlatformSurfacePoolTizen()
75 {
76     m_platformSurfacesToFree.clear();
77
78     PlatformSurfaceMap::iterator end = m_platformSurfaces.end();
79     for (PlatformSurfaceMap::iterator iter = m_platformSurfaces.begin(); iter != end; ++iter) {
80         iter->second->m_SharedPlatformSurfaceTizen.release();
81         iter->second.release();
82     }
83     m_platformSurfaces.clear();
84 }
85
86 SharedPlatformSurfaceTizen* PlatformSurfacePoolTizen::acquirePlatformSurface(const IntSize& size, int tileID)
87 {
88     freePlatformSurfacesIfNeeded();
89     removePlatformSurfacesIfNeeded();
90     PlatformSurfaceMap::iterator end = m_platformSurfaces.end();
91     for (PlatformSurfaceMap::iterator iter = m_platformSurfaces.begin(); iter != end; ++iter) {
92         RefPtr<PlatformSurfaceInfo> platformSurfaceInfo = iter->second;
93         if (platformSurfaceInfo->m_used || platformSurfaceInfo->m_willBeRemoved)
94             continue;
95
96         if (platformSurfaceInfo->size() != size)
97             platformSurfaceInfo->m_age++;
98         else {
99             platformSurfaceInfo->m_used = true;
100             platformSurfaceInfo->m_age = 0;
101             platformSurfaceInfo->m_tileID = tileID;
102
103             // update statistics
104             m_usedSizeInByte += platformSurfaceInfo->sizeInByte();
105             m_usedSizeInCount++;
106
107             LOG(TiledAC, "XPlatformSurface pool size : %u MB (%u tiles) used : %u MB (%u tiles) at [%s]",
108                 m_sizeInByte/MB, m_platformSurfaces.size(), m_usedSizeInByte/MB, m_usedSizeInCount, "PlatformSurfacePoolTizen::acquirePlatformSurface");
109             return platformSurfaceInfo->m_SharedPlatformSurfaceTizen.get();
110         }
111     }
112
113     if (canCreatePlatformSurface()) {
114         RefPtr<PlatformSurfaceInfo> newPlatformSurfaceInfo = createPlatformSurface(size);
115         if (!newPlatformSurfaceInfo) {
116             LOG(TiledAC, "can't create new platformSurface(%dx%d) at [%s]", size.width(), size.height(), "PlatformSurfacePoolTizen::acquirePlatformSurface");
117             return 0;
118         }
119         newPlatformSurfaceInfo->m_used = true;
120         newPlatformSurfaceInfo->m_tileID = tileID;
121
122         m_usedSizeInCount++;
123         m_usedSizeInByte += newPlatformSurfaceInfo->sizeInByte();
124
125         LOG(TiledAC, "acquire platformSurface(%dx%d) XPlatformSurface pool size : %u MB (%u tiles) used : %u MB (%u tiles) at [%s]",
126             size.width(), size.height(), m_sizeInByte/MB, m_platformSurfaces.size(), m_usedSizeInByte/MB, m_usedSizeInCount, "PlatformSurfacePoolTizen::acquirePlatformSurface");
127
128         return newPlatformSurfaceInfo->m_SharedPlatformSurfaceTizen.get();
129     }
130
131     LOG(TiledAC, "No more platformSurface allowed: can't acquire platformSurface(%dx%d) at [%s]", size.width(), size.height(), "PlatformSurfacePoolTizen::acquirePlatformSurface");
132     return 0;
133 }
134
135 SharedPlatformSurfaceTizen* PlatformSurfacePoolTizen::acquirePlatformSurfaceByID(int platformSurfaceId)
136 {
137     PlatformSurfaceMap::iterator foundSurface = m_platformSurfaces.find(platformSurfaceId);
138     if (foundSurface == m_platformSurfaces.end())
139         return 0;
140     return foundSurface->second->m_SharedPlatformSurfaceTizen.get();
141 }
142
143 void PlatformSurfacePoolTizen::freePlatformSurfaceByTileID(int tileID)
144 {
145     int platformSurfaceId = 0;
146     PlatformSurfaceMap::iterator end = m_platformSurfaces.end();
147     for (PlatformSurfaceMap::iterator iter = m_platformSurfaces.begin(); iter != end; ++iter) {
148         RefPtr<PlatformSurfaceInfo> platformSurfaceInfo = iter->second;
149         if (platformSurfaceInfo->m_tileID == tileID) {
150             platformSurfaceId = platformSurfaceInfo->m_SharedPlatformSurfaceTizen->id();
151             break;
152         }
153     }
154     if (platformSurfaceId)
155         freePlatformSurface(platformSurfaceId);
156 }
157
158 void PlatformSurfacePoolTizen::freePlatformSurface(int platformSurfaceId)
159 {
160     RefPtr<PlatformSurfaceInfo> platformSurfaceInfo = m_platformSurfaces.get(platformSurfaceId);
161     if (platformSurfaceInfo && platformSurfaceInfo->m_used)
162         m_platformSurfacesToFree.append(platformSurfaceInfo);
163     else
164         LOG(TiledAC, "WARNING: no matching or freed PlatformSurfaceInfo for %d at [%s]", platformSurfaceId, __PRETTY_FUNCTION__);
165 }
166
167 void PlatformSurfacePoolTizen::freePlatformSurfacesIfNeeded()
168 {
169     if (m_platformSurfacesToFree.isEmpty())
170         return;
171
172     for (size_t index = 0; index < m_platformSurfacesToFree.size(); index++) {
173         RefPtr<PlatformSurfaceInfo> platformSurfaceInfo = m_platformSurfacesToFree[index];
174         platformSurfaceInfo->m_SharedPlatformSurfaceTizen->lockSurface();
175         platformSurfaceInfo->m_SharedPlatformSurfaceTizen->unlockSurface();
176         platformSurfaceInfo->m_tileID = 0;
177         platformSurfaceInfo->m_used = false;
178         m_usedSizeInByte -= platformSurfaceInfo->sizeInByte();
179         m_usedSizeInCount--;
180         // update statistics
181         LOG(TiledAC, "free platformSurface(%dx%d) XPlatformSurface pool size : %u MB (%u tiles) used : %u MB (%u tiles) at [%s]",
182                platformSurfaceInfo->m_SharedPlatformSurfaceTizen->size().width(),platformSurfaceInfo->m_SharedPlatformSurfaceTizen->size().height(),
183                m_sizeInByte/MB, m_platformSurfaces.size(), m_usedSizeInByte/MB, m_usedSizeInCount, __PRETTY_FUNCTION__);
184     }
185
186     m_platformSurfacesToFree.clear();
187
188     if (reachLowPoolUtilization(m_usedSizeInByte, m_sizeInByte))
189         shrink();
190 }
191
192 void PlatformSurfacePoolTizen::removePlatformSurface(int platformSurfaceId)
193 {
194     /*FIXME : platformSurfaceId must not be zero.
195        But sometimes zero id was added to platformSurfaceMap.
196        If this problem is fixed, it will be removed.*/
197     if (!platformSurfaceId)
198         return;
199
200     PlatformSurfaceMap::iterator foundSurface = m_platformSurfaces.find(platformSurfaceId);
201     if (foundSurface == m_platformSurfaces.end())
202         return;
203
204     if (foundSurface->second->m_used) {
205         m_platformSurfacesIdToRemove.append(platformSurfaceId);
206         foundSurface->second->m_willBeRemoved = true;
207         startRemovePlaformSurfaceTimer();
208         return;
209     }
210
211     int width = foundSurface->second->m_SharedPlatformSurfaceTizen->size().width();
212     int height = foundSurface->second->m_SharedPlatformSurfaceTizen->size().height();
213
214     // update statistics
215     m_sizeInByte -= foundSurface->second->sizeInByte();
216     m_platformSurfaces.remove(foundSurface);
217
218     LOG(TiledAC, "remove platformSurface(%dx%d) XPlatformSurface pool size : %u MB (%u tiles) used : %u MB (%u tiles) at [%s]",
219        width,  height, m_sizeInByte/MB, m_platformSurfaces.size(), m_usedSizeInByte/MB, m_usedSizeInCount, "PlatformSurfacePoolTizen::removePlatformSurface");
220 }
221
222 void PlatformSurfacePoolTizen::willRemovePlatformSurface(int platformSurfaceId)
223 {
224     WebProcess::shared().connection()->send(Messages::WebProcessProxy::RemovePlatformSurfaceTextureFromPool(platformSurfaceId), 0);
225 }
226
227 bool PlatformSurfacePoolTizen::canCreatePlatformSurface()
228 {
229     if (m_sizeInByte >= m_maxSizeInByte)
230         shrink();
231
232     return m_sizeInByte < m_maxSizeInByte;
233 }
234
235 RefPtr<PlatformSurfacePoolTizen::PlatformSurfaceInfo> PlatformSurfacePoolTizen::createPlatformSurface(const IntSize& size)
236 {
237     RefPtr<PlatformSurfaceInfo> newPlatformSurface = adoptRef(new PlatformSurfaceInfo(size));
238     if (!newPlatformSurface->m_SharedPlatformSurfaceTizen)
239         return 0;
240
241     m_platformSurfaces.add(newPlatformSurface->m_SharedPlatformSurfaceTizen->id(), newPlatformSurface);
242     m_sizeInByte += newPlatformSurface->sizeInByte();
243
244     return newPlatformSurface.get();
245 }
246
247 void PlatformSurfacePoolTizen::shrink()
248 {
249     Vector<int> platformSurfacesToRemove;
250     {
251         size_t sizeInByte = m_sizeInByte;
252         PlatformSurfaceMap::iterator end = m_platformSurfaces.end();
253         for (PlatformSurfaceMap::iterator iter = m_platformSurfaces.begin(); iter != end; ++iter) {
254             RefPtr<PlatformSurfaceInfo> platformSurfaceInfo = iter->second;
255
256             if (!platformSurfaceInfo->m_used && ++platformSurfaceInfo->m_age > 3) {
257                 platformSurfacesToRemove.append(platformSurfaceInfo->m_SharedPlatformSurfaceTizen->id());
258                 sizeInByte -= platformSurfaceInfo->sizeInByte();
259             }
260
261             if (reachLowPoolUtilization(m_usedSizeInByte, m_sizeInByte)
262                 && reachLowPoolUtilization(sizeInByte, m_sizeInByte))
263                 break;
264         }
265     }
266
267     if (platformSurfacesToRemove.size())
268         LOG(TiledAC, "remove %d platformSurfaces @PlatformSurfacePoolTizen::shrink", platformSurfacesToRemove.size());
269
270     for (size_t index = 0; index < platformSurfacesToRemove.size(); index++) {
271         // FIXME: we should send willRemovePlatformSurface to UIProcess before destroying xplatformSurface itself
272         // to make sure UIProcess release corresponding texture first.
273         // But currently there's no harm to destroying xplatformSurface first, because UIProcess will not use
274         // corresponding texture any longer and will successfully release the texture.
275         // Without removing platformSurfaces immediately here, we will encounter starvation of xplatformSurface too often.
276         removePlatformSurface(platformSurfacesToRemove[index]);
277         willRemovePlatformSurface(platformSurfacesToRemove[index]);
278     }
279 }
280
281 void PlatformSurfacePoolTizen::startRemovePlaformSurfaceTimer()
282 {
283     if (m_removePlaformSurfaceTimer.isActive())
284         return;
285     m_removePlaformSurfaceTimer.startOneShot(0.01);
286 }
287
288 void PlatformSurfacePoolTizen::removePlaformSurfaceTimerFired(Timer<PlatformSurfacePoolTizen>*)
289 {
290     freePlatformSurfacesIfNeeded();
291     removePlatformSurfacesIfNeeded();
292 }
293
294 void PlatformSurfacePoolTizen::removePlatformSurfacesIfNeeded()
295 {
296     Vector<int> platformSurfacesIdToRemove = m_platformSurfacesIdToRemove;
297     m_platformSurfacesIdToRemove.clear();
298
299     for (Vector<int>::iterator iter = platformSurfacesIdToRemove.begin(); iter != platformSurfacesIdToRemove.end(); ++iter)
300         removePlatformSurface(*iter);
301 }
302
303 }
304 #endif
305