[Refactoring] Move PlatformSurfacePoolEfl to PlatformSurfacePoolTizen
[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 void PlatformSurfacePoolTizen::freePlatformSurfaceByTileID(int tileID)
136 {
137     int platformSurfaceId = 0;
138     PlatformSurfaceMap::iterator end = m_platformSurfaces.end();
139     for (PlatformSurfaceMap::iterator iter = m_platformSurfaces.begin(); iter != end; ++iter) {
140         RefPtr<PlatformSurfaceInfo> platformSurfaceInfo = iter->second;
141         if (platformSurfaceInfo->m_tileID == tileID) {
142             platformSurfaceId = platformSurfaceInfo->m_SharedPlatformSurfaceTizen->id();
143             break;
144         }
145     }
146     if (platformSurfaceId)
147         freePlatformSurface(platformSurfaceId);
148 }
149
150 void PlatformSurfacePoolTizen::freePlatformSurface(int platformSurfaceId)
151 {
152     RefPtr<PlatformSurfaceInfo> platformSurfaceInfo = m_platformSurfaces.get(platformSurfaceId);
153     if (platformSurfaceInfo && platformSurfaceInfo->m_used)
154         m_platformSurfacesToFree.append(platformSurfaceInfo);
155     else
156         LOG(TiledAC, "WARNING: no matching or freed PlatformSurfaceInfo for %d at [%s]", platformSurfaceId, __PRETTY_FUNCTION__);
157 }
158
159 void PlatformSurfacePoolTizen::freePlatformSurfacesIfNeeded()
160 {
161     if (m_platformSurfacesToFree.isEmpty())
162         return;
163
164     for (size_t index = 0; index < m_platformSurfacesToFree.size(); index++) {
165         RefPtr<PlatformSurfaceInfo> platformSurfaceInfo = m_platformSurfacesToFree[index];
166         platformSurfaceInfo->m_SharedPlatformSurfaceTizen->lockSurface();
167         platformSurfaceInfo->m_SharedPlatformSurfaceTizen->unlockSurface();
168         platformSurfaceInfo->m_tileID = 0;
169         platformSurfaceInfo->m_used = false;
170         m_usedSizeInByte -= platformSurfaceInfo->sizeInByte();
171         m_usedSizeInCount--;
172         // update statistics
173         LOG(TiledAC, "free platformSurface(%dx%d) XPlatformSurface pool size : %u MB (%u tiles) used : %u MB (%u tiles) at [%s]",
174                platformSurfaceInfo->m_SharedPlatformSurfaceTizen->size().width(),platformSurfaceInfo->m_SharedPlatformSurfaceTizen->size().height(),
175                m_sizeInByte/MB, m_platformSurfaces.size(), m_usedSizeInByte/MB, m_usedSizeInCount, __PRETTY_FUNCTION__);
176     }
177
178     m_platformSurfacesToFree.clear();
179
180     if (reachLowPoolUtilization(m_usedSizeInByte, m_sizeInByte))
181         shrink();
182 }
183
184 void PlatformSurfacePoolTizen::removePlatformSurface(int platformSurfaceId)
185 {
186     /*FIXME : platformSurfaceId must not be zero.
187        But sometimes zero id was added to platformSurfaceMap.
188        If this problem is fixed, it will be removed.*/
189     if (!platformSurfaceId)
190         return;
191
192     PlatformSurfaceMap::iterator foundSurface = m_platformSurfaces.find(platformSurfaceId);
193     if (foundSurface == m_platformSurfaces.end())
194         return;
195
196     if (foundSurface->second->m_used) {
197         m_platformSurfacesIdToRemove.append(platformSurfaceId);
198         foundSurface->second->m_willBeRemoved = true;
199         startRemovePlaformSurfaceTimer();
200         return;
201     }
202
203     int width = foundSurface->second->m_SharedPlatformSurfaceTizen->size().width();
204     int height = foundSurface->second->m_SharedPlatformSurfaceTizen->size().height();
205
206     // update statistics
207     m_sizeInByte -= foundSurface->second->sizeInByte();
208     m_platformSurfaces.remove(foundSurface);
209
210     LOG(TiledAC, "remove platformSurface(%dx%d) XPlatformSurface pool size : %u MB (%u tiles) used : %u MB (%u tiles) at [%s]",
211        width,  height, m_sizeInByte/MB, m_platformSurfaces.size(), m_usedSizeInByte/MB, m_usedSizeInCount, "PlatformSurfacePoolTizen::removePlatformSurface");
212 }
213
214 void PlatformSurfacePoolTizen::willRemovePlatformSurface(int platformSurfaceId)
215 {
216     WebProcess::shared().connection()->send(Messages::WebProcessProxy::RemovePlatformSurfaceTextureFromPool(platformSurfaceId), 0);
217 }
218
219 bool PlatformSurfacePoolTizen::canCreatePlatformSurface()
220 {
221     if (m_sizeInByte >= m_maxSizeInByte)
222         shrink();
223
224     return m_sizeInByte < m_maxSizeInByte;
225 }
226
227 RefPtr<PlatformSurfacePoolTizen::PlatformSurfaceInfo> PlatformSurfacePoolTizen::createPlatformSurface(const IntSize& size)
228 {
229     RefPtr<PlatformSurfaceInfo> newPlatformSurface = adoptRef(new PlatformSurfaceInfo(size));
230     if (!newPlatformSurface->m_SharedPlatformSurfaceTizen)
231         return 0;
232
233     m_platformSurfaces.add(newPlatformSurface->m_SharedPlatformSurfaceTizen->id(), newPlatformSurface);
234     m_sizeInByte += newPlatformSurface->sizeInByte();
235
236     return newPlatformSurface.get();
237 }
238
239 void PlatformSurfacePoolTizen::shrink()
240 {
241     Vector<int> platformSurfacesToRemove;
242     {
243         size_t sizeInByte = m_sizeInByte;
244         PlatformSurfaceMap::iterator end = m_platformSurfaces.end();
245         for (PlatformSurfaceMap::iterator iter = m_platformSurfaces.begin(); iter != end; ++iter) {
246             RefPtr<PlatformSurfaceInfo> platformSurfaceInfo = iter->second;
247
248             if (!platformSurfaceInfo->m_used && ++platformSurfaceInfo->m_age > 3) {
249                 platformSurfacesToRemove.append(platformSurfaceInfo->m_SharedPlatformSurfaceTizen->id());
250                 sizeInByte -= platformSurfaceInfo->sizeInByte();
251             }
252
253             if (reachLowPoolUtilization(m_usedSizeInByte, m_sizeInByte)
254                 && reachLowPoolUtilization(sizeInByte, m_sizeInByte))
255                 break;
256         }
257     }
258
259     if (platformSurfacesToRemove.size())
260         LOG(TiledAC, "remove %d platformSurfaces @PlatformSurfacePoolTizen::shrink", platformSurfacesToRemove.size());
261
262     for (size_t index = 0; index < platformSurfacesToRemove.size(); index++) {
263         // FIXME: we should send willRemovePlatformSurface to UIProcess before destroying xplatformSurface itself
264         // to make sure UIProcess release corresponding texture first.
265         // But currently there's no harm to destroying xplatformSurface first, because UIProcess will not use
266         // corresponding texture any longer and will successfully release the texture.
267         // Without removing platformSurfaces immediately here, we will encounter starvation of xplatformSurface too often.
268         removePlatformSurface(platformSurfacesToRemove[index]);
269         willRemovePlatformSurface(platformSurfacesToRemove[index]);
270     }
271 }
272
273 void PlatformSurfacePoolTizen::startRemovePlaformSurfaceTimer()
274 {
275     if (m_removePlaformSurfaceTimer.isActive())
276         return;
277     m_removePlaformSurfaceTimer.startOneShot(0.01);
278 }
279
280 void PlatformSurfacePoolTizen::removePlaformSurfaceTimerFired(Timer<PlatformSurfacePoolTizen>*)
281 {
282     freePlatformSurfacesIfNeeded();
283     removePlatformSurfacesIfNeeded();
284 }
285
286 void PlatformSurfacePoolTizen::removePlatformSurfacesIfNeeded()
287 {
288     Vector<int> platformSurfacesIdToRemove = m_platformSurfacesIdToRemove;
289     m_platformSurfacesIdToRemove.clear();
290
291     for (Vector<int>::iterator iter = platformSurfacesIdToRemove.begin(); iter != platformSurfacesIdToRemove.end(); ++iter)
292         removePlatformSurface(*iter);
293 }
294
295 }
296 #endif
297