1/*
2 Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB.  If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
18 */
19
20#include "config.h"
21#include "TextureMapper.h"
22
23#include "FilterOperations.h"
24#include "GraphicsLayer.h"
25#include "TextureMapperImageBuffer.h"
26#include "Timer.h"
27#include <wtf/CurrentTime.h>
28
29#if USE(TEXTURE_MAPPER)
30
31namespace WebCore {
32
33struct BitmapTexturePoolEntry {
34    explicit BitmapTexturePoolEntry(PassRefPtr<BitmapTexture> texture)
35        : m_texture(texture)
36    { }
37    inline void markUsed() { m_timeLastUsed = monotonicallyIncreasingTime(); }
38    static bool compareTimeLastUsed(const BitmapTexturePoolEntry& a, const BitmapTexturePoolEntry& b)
39    {
40        return a.m_timeLastUsed - b.m_timeLastUsed > 0;
41    }
42
43    RefPtr<BitmapTexture> m_texture;
44    double m_timeLastUsed;
45};
46
47class BitmapTexturePool {
48    WTF_MAKE_NONCOPYABLE(BitmapTexturePool);
49    WTF_MAKE_FAST_ALLOCATED;
50public:
51    BitmapTexturePool();
52
53    PassRefPtr<BitmapTexture> acquireTexture(const IntSize&, TextureMapper*);
54
55private:
56    void scheduleReleaseUnusedTextures();
57    void releaseUnusedTexturesTimerFired(Timer<BitmapTexturePool>*);
58
59    Vector<BitmapTexturePoolEntry> m_textures;
60    Timer<BitmapTexturePool> m_releaseUnusedTexturesTimer;
61
62    static const double s_releaseUnusedSecondsTolerance;
63    static const double s_releaseUnusedTexturesTimerInterval;
64};
65
66const double BitmapTexturePool::s_releaseUnusedSecondsTolerance = 3;
67const double BitmapTexturePool::s_releaseUnusedTexturesTimerInterval = 0.5;
68
69BitmapTexturePool::BitmapTexturePool()
70    : m_releaseUnusedTexturesTimer(this, &BitmapTexturePool::releaseUnusedTexturesTimerFired)
71{ }
72
73void BitmapTexturePool::scheduleReleaseUnusedTextures()
74{
75    if (m_releaseUnusedTexturesTimer.isActive())
76        m_releaseUnusedTexturesTimer.stop();
77
78    m_releaseUnusedTexturesTimer.startOneShot(s_releaseUnusedTexturesTimerInterval);
79}
80
81void BitmapTexturePool::releaseUnusedTexturesTimerFired(Timer<BitmapTexturePool>*)
82{
83    if (m_textures.isEmpty())
84        return;
85
86    // Delete entries, which have been unused in s_releaseUnusedSecondsTolerance.
87    std::sort(m_textures.begin(), m_textures.end(), BitmapTexturePoolEntry::compareTimeLastUsed);
88
89    double minUsedTime = monotonicallyIncreasingTime() - s_releaseUnusedSecondsTolerance;
90    for (size_t i = 0; i < m_textures.size(); ++i) {
91        if (m_textures[i].m_timeLastUsed < minUsedTime) {
92            m_textures.remove(i, m_textures.size() - i);
93            break;
94        }
95    }
96}
97
98PassRefPtr<BitmapTexture> BitmapTexturePool::acquireTexture(const IntSize& size, TextureMapper* textureMapper)
99{
100    BitmapTexturePoolEntry* selectedEntry = 0;
101    for (size_t i = 0; i < m_textures.size(); ++i) {
102        BitmapTexturePoolEntry* entry = &m_textures[i];
103
104        // If the surface has only one reference (the one in m_textures), we can safely reuse it.
105        if (entry->m_texture->refCount() > 1)
106            continue;
107
108        if (entry->m_texture->canReuseWith(size)) {
109            selectedEntry = entry;
110            break;
111        }
112    }
113
114    if (!selectedEntry) {
115        m_textures.append(BitmapTexturePoolEntry(textureMapper->createTexture()));
116        selectedEntry = &m_textures.last();
117    }
118
119    scheduleReleaseUnusedTextures();
120    selectedEntry->markUsed();
121    return selectedEntry->m_texture;
122}
123
124PassRefPtr<BitmapTexture> TextureMapper::acquireTextureFromPool(const IntSize& size, const BitmapTexture::Flags flags)
125{
126    RefPtr<BitmapTexture> selectedTexture = m_texturePool->acquireTexture(size, this);
127    selectedTexture->reset(size, flags);
128    return selectedTexture;
129}
130
131std::unique_ptr<TextureMapper> TextureMapper::create(AccelerationMode mode)
132{
133    if (mode == SoftwareMode)
134        return std::make_unique<TextureMapperImageBuffer>();
135    return platformCreateAccelerated();
136}
137
138TextureMapper::TextureMapper(AccelerationMode accelerationMode)
139    : m_context(0)
140    , m_interpolationQuality(InterpolationDefault)
141    , m_textDrawingMode(TextModeFill)
142    , m_texturePool(std::make_unique<BitmapTexturePool>())
143    , m_accelerationMode(accelerationMode)
144    , m_isMaskMode(false)
145    , m_wrapMode(StretchWrap)
146{ }
147
148TextureMapper::~TextureMapper()
149{ }
150
151void BitmapTexture::updateContents(TextureMapper* textureMapper, GraphicsLayer* sourceLayer, const IntRect& targetRect, const IntPoint& offset, UpdateContentsFlag updateContentsFlag)
152{
153    std::unique_ptr<ImageBuffer> imageBuffer = ImageBuffer::create(targetRect.size());
154    GraphicsContext* context = imageBuffer->context();
155    context->setImageInterpolationQuality(textureMapper->imageInterpolationQuality());
156    context->setTextDrawingMode(textureMapper->textDrawingMode());
157
158    IntRect sourceRect(targetRect);
159    sourceRect.setLocation(offset);
160    context->translate(-offset.x(), -offset.y());
161    sourceLayer->paintGraphicsLayerContents(*context, sourceRect);
162
163    RefPtr<Image> image = imageBuffer->copyImage(DontCopyBackingStore);
164
165    updateContents(image.get(), targetRect, IntPoint(), updateContentsFlag);
166}
167
168} // namespace
169
170#endif
171