Introducing QPlatformSharedGraphicsCache
Interface to provide cross-process caching mechanisms in a platform plugin. Can be used for shared glyph caches and icon caches etc. Change-Id: If0d89a0a50bbd6eee05daf908448262ff270fc5b Reviewed-by: Jiang Jiang <jiang.jiang@nokia.com>
This commit is contained in:
parent
47d5d349d8
commit
c274ea7cf5
@ -54,7 +54,8 @@ HEADERS += \
|
||||
kernel/qscreen_p.h \
|
||||
kernel/qstylehints.h \
|
||||
kernel/qtouchdevice.h \
|
||||
kernel/qtouchdevice_p.h
|
||||
kernel/qtouchdevice_p.h \
|
||||
kernel/qplatformsharedgraphicscache_qpa.h
|
||||
|
||||
SOURCES += \
|
||||
kernel/qclipboard_qpa.cpp \
|
||||
@ -96,6 +97,7 @@ SOURCES += \
|
||||
kernel/qscreen.cpp \
|
||||
kernel/qshortcutmap.cpp \
|
||||
kernel/qstylehints.cpp \
|
||||
kernel/qtouchdevice.cpp
|
||||
kernel/qtouchdevice.cpp \
|
||||
kernel/qplatformsharedgraphicscache_qpa.cpp
|
||||
|
||||
win32:HEADERS+=kernel/qwindowdefs_win.h
|
||||
|
@ -201,6 +201,17 @@ QPlatformOpenGLContext *QPlatformIntegration::createPlatformOpenGLContext(QOpenG
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
Factory function for QPlatformSharedGraphicsCache. This function will return 0 if the platform
|
||||
integration does not support any shared graphics cache mechanism for the given \a cacheId.
|
||||
*/
|
||||
QPlatformSharedGraphicsCache *QPlatformIntegration::createPlatformSharedGraphicsCache(const char *cacheId) const
|
||||
{
|
||||
qWarning("This plugin does not support createPlatformSharedGraphicsBuffer for cacheId: %s!",
|
||||
cacheId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the platforms input context.
|
||||
|
||||
|
@ -65,6 +65,8 @@ class QAbstractEventDispatcher;
|
||||
class QPlatformInputContext;
|
||||
class QPlatformAccessibility;
|
||||
class QPlatformTheme;
|
||||
class QPlatformDialogHelper;
|
||||
class QPlatformSharedGraphicsCache;
|
||||
|
||||
class Q_GUI_EXPORT QPlatformIntegration
|
||||
{
|
||||
@ -72,7 +74,8 @@ public:
|
||||
enum Capability {
|
||||
ThreadedPixmaps = 1,
|
||||
OpenGL = 2,
|
||||
ThreadedOpenGL = 3
|
||||
ThreadedOpenGL = 3,
|
||||
SharedGraphicsCache = 4
|
||||
};
|
||||
|
||||
virtual ~QPlatformIntegration() { }
|
||||
@ -83,6 +86,7 @@ public:
|
||||
virtual QPlatformWindow *createPlatformWindow(QWindow *window) const = 0;
|
||||
virtual QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const = 0;
|
||||
virtual QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const;
|
||||
virtual QPlatformSharedGraphicsCache *createPlatformSharedGraphicsCache(const char *cacheId) const;
|
||||
|
||||
// Event dispatcher:
|
||||
virtual QAbstractEventDispatcher *guiThreadEventDispatcher() const = 0;
|
||||
|
212
src/gui/kernel/qplatformsharedgraphicscache_qpa.cpp
Normal file
212
src/gui/kernel/qplatformsharedgraphicscache_qpa.cpp
Normal file
@ -0,0 +1,212 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the QtGui module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qplatformsharedgraphicscache_qpa.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
/*!
|
||||
\class QPlatformSharedGraphicsCache
|
||||
\since 5.0
|
||||
\internal
|
||||
\preliminary
|
||||
\ingroup qpa
|
||||
\brief The QPlatformSharedGraphicsCache is an abstraction of a cross-process graphics cache.
|
||||
|
||||
If supported, it is possible to retrieve a QPlatformSharedGraphicsCache object from the
|
||||
platform integration. This is typically used to store graphical items which should be shared
|
||||
between several processes.
|
||||
|
||||
Items are requested from the cache by calling requestItems(). If the cache contains the
|
||||
requested items in the requested cache, the itemsAvailable() signal is emitted with the ID of
|
||||
the graphical buffer and each item's coordinates inside the buffer. Before requesting items
|
||||
from a cache, the user must call ensureCacheInitialized() to set the correct parameters for
|
||||
the cache.
|
||||
|
||||
If the cache does not yet contain the requested items, it will emit a similar itemsMissing()
|
||||
signal. The client can then call updateItems() with rasterizations of the items and they will be
|
||||
entered into the shared cache. As the items are rendered into the cache, itemsAvailable() signals
|
||||
will be emitted for each of the items which have previously been requested and which have not
|
||||
yet been reported as ready.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\enum BufferType
|
||||
|
||||
Defines how the type of buffer required to contain a cache.
|
||||
|
||||
\value OpenGLTexture The buffer will be allocated in graphics memory, and an OpenGL texture
|
||||
for a buffer belonging to the cache can be requested using
|
||||
textureIdForBuffer().
|
||||
*/
|
||||
|
||||
/*!
|
||||
\enum PixelFormat
|
||||
|
||||
Defines the pixel format of a cache.
|
||||
|
||||
\value Alpha8 The cache will use 8 bits to represent the alpha value of each pixel. If an
|
||||
OpenGL texture is created for a buffer belong to the cache, it will have the
|
||||
pixel format GL_ALPHA.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void ensureCacheInitialized(const QByteArray &cacheId, BufferType bufferType, PixelFormat pixelFormat)
|
||||
|
||||
Initializes a cache named \a cacheId if it has not yet been initialized. The \a bufferType and
|
||||
\a pixelFormat gives the format of the buffers that will be used to contain the items in the
|
||||
cache. If a cache with the same \a cacheId has previously been initialized, the call will be
|
||||
ignored. The cache will keep its previously set buffer type and pixel format.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void QPlatformSharedGraphicsCache::requestItems(const QByteArray &cacheId, const QVector<quint32> &itemIds)
|
||||
|
||||
Requests all the items in \a itemIds from the cache with the name \a cacheId.
|
||||
|
||||
If any or all of the items are available in the cache, one or more itemsAvailable() signals will be
|
||||
emitted corresponding to the items. If the cache does not contain all of the items in question,
|
||||
then an itemsMissing() signal will be emitted corresponding to the missing items. The user
|
||||
is at this point expected to call insertItems() to insert the missing items into the cache. If
|
||||
the inserted items have previously been requested by the user, at which point an itemsAvailable()
|
||||
signal will be emitted corresponding to the items.
|
||||
|
||||
Before requesting items from a cache, the user must call ensureCacheInitialized() with the
|
||||
correct parameters for the cache.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void QPlatformSharedGraphicsCache::insertItems(const QByteArray &cacheId, const QVector<quint32> &itemIds, const QVector<QImage> &items)
|
||||
|
||||
Inserts the items in \a itemIds into the cache named \a cacheId. The appearance of
|
||||
each item is stored in \a items. The format of the QImage objects is expected to match the
|
||||
pixel format of the cache as it was initialized in ensureCacheInitialized().
|
||||
|
||||
When the items have been successfully entered into the cache, one or more itemsAvailable() signals
|
||||
will be emitted for the items.
|
||||
|
||||
If the cache already contains the items, the behavior is implementation-specific. The
|
||||
implementation may choose to ignore the items or it may overwrite the existing instances in
|
||||
the cache. Either way, itemsAvailable() signals corresponding to the inserted items will be
|
||||
emitted.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void QPlatformSharedGraphicsCache::releaseItems(const QByteArray &cacheId, const QVector<quint32> &itemIds)
|
||||
|
||||
Releases the reference to the items in \a itemIds from the cache named \a cacheId. This should
|
||||
only be called when all references to the items have been released by the user, and they are no
|
||||
longer needed.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void itemsMissing(const QByteArray &cacheId, const QVector<quint32> *itemIds)
|
||||
|
||||
This signal is emitted when requestItems() has been called for one or more items in the
|
||||
cache named \a cacheId which are not yet available in the cache. The user is then expected to
|
||||
call insertItems() to update the cache with the respective items, at which point they will
|
||||
become available to all clients of the shared cache.
|
||||
|
||||
The vector \a itemIds contains the IDs of the items that need to be inserted into the cache.
|
||||
|
||||
\sa itemsAvailable(), insertItems(), requestItems()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void itemsAvailable(const QByteArray &cacheId, void *bufferId, const QSize &bufferSize, const QVector<quint32> &itemIds, const QVector<QPoint> &positionsInBuffer)
|
||||
|
||||
This signal can be emitted at any time when either requestItems() or insertItems() has been
|
||||
called by the application for one or more items in the cache named \a cacheId, as long as
|
||||
releaseItems() has not subsequently been called for the same items. It instructs the application
|
||||
on where to find the items that have been entered into the cache. When the application receives
|
||||
a buffer, it is expected to reference it using referenceBuffer() on it if it keeps a reference
|
||||
to the buffer.
|
||||
|
||||
The \a bufferId is an ID for the buffer that contains the items. The \a bufferId can be
|
||||
converted to a format usable by the application depending on which format it was given at
|
||||
initialization. If it is a OpenGLTexture, its texture ID can be requested using the
|
||||
textureIdForBuffer() function. The dimensions of the buffer are given by \a bufferSize.
|
||||
|
||||
The items provided by the cache are identified in the \a itemIds vector. The
|
||||
\a positionsInBuffer vector contains the locations inside the buffer of each item. Each entry in
|
||||
\a positionsInBuffer corresponds to an item in \a itemIds.
|
||||
|
||||
The buffer and the items' locations within the buffer can be considered valid until an
|
||||
itemsInvalidated() signal has been emitted for the items, or until releaseItems() is called
|
||||
for the items.
|
||||
|
||||
\sa itemsMissing(), requestItems(), bufferType()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void itemsUpdated(const QByteArray &cacheId, void *bufferId, const QSize &bufferSize, const QVector<quint32> &itemIds, const QVector<QPoint> &positionsInBuffer)
|
||||
|
||||
This signal is similar in usage to the itemsAvailable() signal, but will be emitted when
|
||||
the location of a previously requested or inserted item has been updated. The application
|
||||
must update its data for the respective items and release any references to old buffers held
|
||||
by the items.
|
||||
|
||||
If the application no longer holds any references to previously referenced items in a given
|
||||
cache, it should call releaseItems() for these items, at which point it will no longer receive
|
||||
any itemsUpdated() signal for these items.
|
||||
|
||||
\sa requestItems(), insertItems(), itemsAvailable()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void itemsInvalidated(const QByteArray &cacheId, const QVector<quint32> &itemIds)
|
||||
|
||||
This signal is emitted when the items given by \a itemIds in the cache named \a cacheId have
|
||||
been removed from the cache and the previously reported information about them is considered
|
||||
invalid. It will only be emitted for items for which a buffer has previously been identified
|
||||
through the itemsAvailable() signal (either as response to a requestItems() call or an
|
||||
insertItems() call.)
|
||||
|
||||
The application is expected to throw away information about the items in the \a itemIds array
|
||||
and drop any references it might have to the memory held by the buffer. If the items are still
|
||||
required by the application, it can re-commit them to the cache using the insertItems() function.
|
||||
|
||||
If the application no longer holds any references to previously referenced items in a given
|
||||
cache, it should call releaseItems() for these items, at which point it will no longer receive
|
||||
any itemsInvalidated() signal for these items.
|
||||
*/
|
||||
|
||||
QT_END_NAMESPACE
|
97
src/gui/kernel/qplatformsharedgraphicscache_qpa.h
Normal file
97
src/gui/kernel/qplatformsharedgraphicscache_qpa.h
Normal file
@ -0,0 +1,97 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the QtGui module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QPLATFORMSHAREDGRAPHICSCACHE_QPA_H
|
||||
#define QPLATFORMSHAREDGRAPHICSCACHE_QPA_H
|
||||
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtGui/qimage.h>
|
||||
|
||||
QT_BEGIN_HEADER
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QT_MODULE(Gui)
|
||||
|
||||
class Q_GUI_EXPORT QPlatformSharedGraphicsCache: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum PixelFormat
|
||||
{
|
||||
Alpha8
|
||||
};
|
||||
|
||||
enum BufferType
|
||||
{
|
||||
OpenGLTexture
|
||||
};
|
||||
|
||||
QPlatformSharedGraphicsCache(QObject *parent = 0) : QObject(parent) {}
|
||||
|
||||
Q_INVOKABLE virtual void ensureCacheInitialized(const QByteArray &cacheId, BufferType bufferType,
|
||||
PixelFormat pixelFormat) = 0;
|
||||
|
||||
Q_INVOKABLE virtual void requestItems(const QByteArray &cacheId, const QVector<quint32> &itemIds) = 0;
|
||||
Q_INVOKABLE virtual void insertItems(const QByteArray &cacheId,
|
||||
const QVector<quint32> &itemIds,
|
||||
const QVector<QImage> &items) = 0;
|
||||
Q_INVOKABLE virtual void releaseItems(const QByteArray &cacheId, const QVector<quint32> &itemIds) = 0;
|
||||
|
||||
virtual void serializeBuffer(void *bufferId, QByteArray *serializedData, int *fileDescriptor) const = 0;
|
||||
virtual uint textureIdForBuffer(void *bufferId) = 0;
|
||||
virtual void referenceBuffer(void *bufferId) = 0;
|
||||
virtual bool dereferenceBuffer(void *bufferId) = 0;
|
||||
|
||||
Q_SIGNALS:
|
||||
void itemsMissing(const QByteArray &cacheId, const QVector<quint32> &itemIds);
|
||||
void itemsAvailable(const QByteArray &cacheId, void *bufferId, const QSize &bufferSize,
|
||||
const QVector<quint32> &itemIds, const QVector<QPoint> &positionsInBuffer);
|
||||
void itemsInvalidated(const QByteArray &cacheId, const QVector<quint32> &itemIds);
|
||||
void itemsUpdated(const QByteArray &cacheId, void *bufferId, const QSize &bufferSize,
|
||||
const QVector<quint32> &itemIds, const QVector<QPoint> &positionsInBuffer);
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
QT_END_HEADER
|
||||
|
||||
#endif // QPLATFORMSHAREDGRAPHICSCACHE_QPA_H
|
@ -47,6 +47,7 @@
|
||||
#include "qxcbnativeinterface.h"
|
||||
#include "qxcbclipboard.h"
|
||||
#include "qxcbdrag.h"
|
||||
#include "qxcbsharedgraphicscache.h"
|
||||
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
@ -107,6 +108,10 @@ QXcbIntegration::QXcbIntegration(const QStringList ¶meters)
|
||||
m_fontDatabase.reset(new QGenericUnixFontDatabase());
|
||||
m_inputContext.reset(QPlatformInputContextFactory::create());
|
||||
m_accessibility.reset(new QPlatformAccessibility());
|
||||
|
||||
#if defined(QT_USE_XCB_SHARED_GRAPHICS_CACHE)
|
||||
m_sharedGraphicsCache.reset(new QXcbSharedGraphicsCache);
|
||||
#endif
|
||||
}
|
||||
|
||||
QXcbIntegration::~QXcbIntegration()
|
||||
@ -186,6 +191,10 @@ QPlatformBackingStore *QXcbIntegration::createPlatformBackingStore(QWindow *wind
|
||||
bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const
|
||||
{
|
||||
switch (cap) {
|
||||
#if defined(QT_USE_XCB_SHARED_GRAPHICS_CACHE)
|
||||
case SharedGraphicsCache: return true;
|
||||
#endif
|
||||
|
||||
case ThreadedPixmaps: return true;
|
||||
case OpenGL: return true;
|
||||
case ThreadedOpenGL:
|
||||
@ -239,4 +248,24 @@ QPlatformAccessibility *QXcbIntegration::accessibility() const
|
||||
return m_accessibility.data();
|
||||
}
|
||||
|
||||
#if defined(QT_USE_XCB_SHARED_GRAPHICS_CACHE)
|
||||
static bool sharedGraphicsCacheDisabled()
|
||||
{
|
||||
static const char *environmentVariable = "QT_DISABLE_SHARED_CACHE";
|
||||
static bool cacheDisabled = !qgetenv(environmentVariable).isEmpty()
|
||||
&& qgetenv(environmentVariable).toInt() != 0;
|
||||
return cacheDisabled;
|
||||
}
|
||||
|
||||
QPlatformSharedGraphicsCache *QXcbIntegration::createPlatformSharedGraphicsCache(const char *cacheId) const
|
||||
{
|
||||
Q_UNUSED(cacheId);
|
||||
|
||||
if (sharedGraphicsCacheDisabled())
|
||||
return 0;
|
||||
|
||||
return m_sharedGraphicsCache.data();
|
||||
}
|
||||
#endif
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -77,6 +77,10 @@ public:
|
||||
|
||||
QPlatformAccessibility *accessibility() const;
|
||||
|
||||
#if defined(QT_USE_XCB_SHARED_GRAPHICS_CACHE)
|
||||
QPlatformSharedGraphicsCache *createPlatformSharedGraphicsCache(const char *cacheId) const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
QList<QXcbConnection *> m_connections;
|
||||
|
||||
@ -87,6 +91,10 @@ private:
|
||||
QAbstractEventDispatcher *m_eventDispatcher;
|
||||
|
||||
QScopedPointer<QPlatformAccessibility> m_accessibility;
|
||||
|
||||
#if defined(QT_USE_XCB_SHARED_GRAPHICS_CACHE)
|
||||
QScopedPointer<QPlatformSharedGraphicsCache> m_sharedGraphicsCache;
|
||||
#endif
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
640
src/plugins/platforms/xcb/qxcbsharedbuffermanager.cpp
Normal file
640
src/plugins/platforms/xcb/qxcbsharedbuffermanager.cpp
Normal file
@ -0,0 +1,640 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(QT_USE_XCB_SHARED_GRAPHICS_CACHE)
|
||||
|
||||
#include "qxcbsharedbuffermanager.h"
|
||||
|
||||
#include <QtCore/quuid.h>
|
||||
#include <QtGui/qimage.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if !defined(SHAREDGRAPHICSCACHE_MAX_MEMORY_USED)
|
||||
# define SHAREDGRAPHICSCACHE_MAX_MEMORY_USED 16 * 1024 * 1024 // 16 MB limit
|
||||
#endif
|
||||
|
||||
#if !defined(SHAREDGRAPHICSCACHE_MAX_TEXTURES_PER_CACHE)
|
||||
# define SHAREDGRAPHICSCACHE_MAX_TEXTURES_PER_CACHE 1
|
||||
#endif
|
||||
|
||||
#if !defined(SHAREDGRAPHICSCACHE_TEXTURE_SIZE)
|
||||
# define SHAREDGRAPHICSCACHE_TEXTURE_SIZE 2048
|
||||
#endif
|
||||
|
||||
#define SHAREDBUFFERMANAGER_DEBUG 1
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QXcbSharedBufferManager::QXcbSharedBufferManager()
|
||||
: m_memoryUsed(0)
|
||||
, m_mostRecentlyUsed(0)
|
||||
, m_leastRecentlyUsed(0)
|
||||
{
|
||||
}
|
||||
|
||||
QXcbSharedBufferManager::~QXcbSharedBufferManager()
|
||||
{
|
||||
{
|
||||
QHash<QByteArray, Buffer *>::const_iterator it = m_buffers.constBegin();
|
||||
while (it != m_buffers.constEnd()) {
|
||||
Buffer *buffer = it.value();
|
||||
delete buffer;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
QHash<QByteArray, Items *>::const_iterator it = m_items.constBegin();
|
||||
while (it != m_items.constEnd()) {
|
||||
Items *items = it.value();
|
||||
QHash<quint32, Item *>::const_iterator itemIt = items->items.constBegin();
|
||||
while (itemIt != items->items.constEnd()) {
|
||||
delete itemIt.value();
|
||||
++itemIt;
|
||||
}
|
||||
delete it.value();
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QXcbSharedBufferManager::getBufferForItem(const QByteArray &cacheId, quint32 itemId,
|
||||
Buffer **buffer, int *x, int *y) const
|
||||
{
|
||||
Q_ASSERT_X(m_currentCacheId.isEmpty(), Q_FUNC_INFO,
|
||||
"Call endSharedBufferAction before accessing data");
|
||||
|
||||
Q_ASSERT(buffer != 0);
|
||||
Q_ASSERT(x != 0);
|
||||
Q_ASSERT(y != 0);
|
||||
|
||||
Items *items = itemsForCache(cacheId);
|
||||
Item *item = items->items.value(itemId);
|
||||
if (item != 0) {
|
||||
*buffer = item->buffer;
|
||||
*x = item->x;
|
||||
*y = item->y;
|
||||
} else {
|
||||
*buffer = 0;
|
||||
*x = -1;
|
||||
*y = -1;
|
||||
}
|
||||
}
|
||||
|
||||
QPair<QByteArray, int> QXcbSharedBufferManager::serializeBuffer(QSharedMemory *buffer) const
|
||||
{
|
||||
Q_ASSERT_X(m_currentCacheId.isEmpty(), Q_FUNC_INFO,
|
||||
"Call endSharedBufferAction before accessing data");
|
||||
|
||||
return qMakePair(buffer->key().toLatin1(), 0);
|
||||
}
|
||||
|
||||
void QXcbSharedBufferManager::beginSharedBufferAction(const QByteArray &cacheId)
|
||||
{
|
||||
#if defined(SHAREDBUFFERMANAGER_DEBUG)
|
||||
qDebug("QXcbSharedBufferManager::beginSharedBufferAction() called for %s", cacheId.constData());
|
||||
#endif
|
||||
|
||||
Q_ASSERT(m_currentCacheId.isEmpty());
|
||||
Q_ASSERT(!cacheId.isEmpty());
|
||||
|
||||
m_pendingInvalidatedItems.clear();
|
||||
m_pendingReadyItems.clear();
|
||||
m_pendingMissingItems.clear();
|
||||
|
||||
m_currentCacheId = cacheId;
|
||||
}
|
||||
|
||||
void QXcbSharedBufferManager::requestItems(const QSet<quint32> &itemIds)
|
||||
{
|
||||
#if defined(SHAREDBUFFERMANAGER_DEBUG)
|
||||
qDebug("QXcbSharedBufferManager::requestItems for %d items", itemIds.size());
|
||||
#endif
|
||||
|
||||
Q_ASSERT_X(!m_currentCacheId.isEmpty(), Q_FUNC_INFO,
|
||||
"Call beginSharedBufferAction before requesting items");
|
||||
Items *items = itemsForCache(m_currentCacheId);
|
||||
|
||||
QSet<quint32>::const_iterator it = itemIds.constBegin();
|
||||
while (it != itemIds.constEnd()) {
|
||||
if (items->items.contains(*it))
|
||||
m_pendingReadyItems[m_currentCacheId].insert(*it);
|
||||
else
|
||||
m_pendingMissingItems[m_currentCacheId].insert(*it);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void QXcbSharedBufferManager::releaseItems(const QSet<quint32> &itemIds)
|
||||
{
|
||||
#if defined(SHAREDBUFFERMANAGER_DEBUG)
|
||||
qDebug("QXcbSharedBufferManager::releaseItems for %d items", itemIds.size());
|
||||
#endif
|
||||
|
||||
Items *items = itemsForCache(m_currentCacheId);
|
||||
|
||||
QSet<quint32>::const_iterator it;
|
||||
for (it = itemIds.constBegin(); it != itemIds.constEnd(); ++it) {
|
||||
Item *item = items->items.value(*it);
|
||||
if (item != 0)
|
||||
pushItemToBack(items, item);
|
||||
|
||||
m_pendingReadyItems[m_currentCacheId].remove(*it);
|
||||
m_pendingMissingItems[m_currentCacheId].remove(*it);
|
||||
}
|
||||
}
|
||||
|
||||
void QXcbSharedBufferManager::insertItem(quint32 itemId, uchar *data,
|
||||
int itemWidth, int itemHeight)
|
||||
{
|
||||
Q_ASSERT_X(!m_currentCacheId.isEmpty(), Q_FUNC_INFO,
|
||||
"Call beginSharedBufferAction before inserting items");
|
||||
Items *items = itemsForCache(m_currentCacheId);
|
||||
|
||||
if (!items->items.contains(itemId)) {
|
||||
Buffer *sharedBuffer = 0;
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
|
||||
findAvailableBuffer(itemWidth, itemHeight, &sharedBuffer, &x, &y);
|
||||
copyIntoBuffer(sharedBuffer, x, y, itemWidth, itemHeight, data);
|
||||
|
||||
// static int counter=0;
|
||||
// QString fileName = QString::fromLatin1("buffer%1.png").arg(counter++);
|
||||
// saveBuffer(sharedBuffer, fileName);
|
||||
|
||||
Item *item = new Item;
|
||||
item->itemId = itemId;
|
||||
item->buffer = sharedBuffer;
|
||||
item->x = x;
|
||||
item->y = y;
|
||||
|
||||
items->items[itemId] = item;
|
||||
|
||||
touchItem(items, item);
|
||||
}
|
||||
}
|
||||
|
||||
void QXcbSharedBufferManager::endSharedBufferAction()
|
||||
{
|
||||
#if defined(SHAREDBUFFERMANAGER_DEBUG)
|
||||
qDebug("QXcbSharedBufferManager::endSharedBufferAction() called for %s",
|
||||
m_currentCacheId.constData());
|
||||
#endif
|
||||
|
||||
Q_ASSERT(!m_currentCacheId.isEmpty());
|
||||
|
||||
// Do an extra validation pass on the invalidated items since they may have been re-inserted
|
||||
// after they were invalidated
|
||||
if (m_pendingInvalidatedItems.contains(m_currentCacheId)) {
|
||||
QSet<quint32> &invalidatedItems = m_pendingInvalidatedItems[m_currentCacheId];
|
||||
QSet<quint32>::iterator it = invalidatedItems.begin();
|
||||
while (it != invalidatedItems.end()) {
|
||||
Items *items = m_items.value(m_currentCacheId);
|
||||
|
||||
if (items->items.contains(*it)) {
|
||||
m_pendingReadyItems[m_currentCacheId].insert(*it);
|
||||
it = invalidatedItems.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_currentCacheId.clear();
|
||||
}
|
||||
|
||||
void QXcbSharedBufferManager::pushItemToBack(Items *items, Item *item)
|
||||
{
|
||||
if (items->leastRecentlyUsed == item)
|
||||
return;
|
||||
|
||||
if (item->next != 0)
|
||||
item->next->prev = item->prev;
|
||||
if (item->prev != 0)
|
||||
item->prev->next = item->next;
|
||||
|
||||
if (items->mostRecentlyUsed == item)
|
||||
items->mostRecentlyUsed = item->prev;
|
||||
|
||||
if (items->leastRecentlyUsed != 0)
|
||||
items->leastRecentlyUsed->prev = item;
|
||||
|
||||
item->prev = 0;
|
||||
item->next = items->leastRecentlyUsed;
|
||||
items->leastRecentlyUsed = item;
|
||||
if (items->mostRecentlyUsed == 0)
|
||||
items->mostRecentlyUsed = item;
|
||||
}
|
||||
|
||||
void QXcbSharedBufferManager::touchItem(Items *items, Item *item)
|
||||
{
|
||||
if (items->mostRecentlyUsed == item)
|
||||
return;
|
||||
|
||||
if (item->next != 0)
|
||||
item->next->prev = item->prev;
|
||||
if (item->prev != 0)
|
||||
item->prev->next = item->next;
|
||||
|
||||
if (items->leastRecentlyUsed == item)
|
||||
items->leastRecentlyUsed = item->next;
|
||||
|
||||
if (items->mostRecentlyUsed != 0)
|
||||
items->mostRecentlyUsed->next = item;
|
||||
|
||||
item->next = 0;
|
||||
item->prev = items->mostRecentlyUsed;
|
||||
items->mostRecentlyUsed = item;
|
||||
if (items->leastRecentlyUsed == 0)
|
||||
items->leastRecentlyUsed = item;
|
||||
}
|
||||
|
||||
void QXcbSharedBufferManager::deleteItem(Items *items, Item *item)
|
||||
{
|
||||
Q_ASSERT(items != 0);
|
||||
Q_ASSERT(item != 0);
|
||||
|
||||
if (items->mostRecentlyUsed == item)
|
||||
items->mostRecentlyUsed = item->prev;
|
||||
if (items->leastRecentlyUsed == item)
|
||||
items->leastRecentlyUsed = item->next;
|
||||
|
||||
if (item->next != 0)
|
||||
item->next->prev = item->prev;
|
||||
if (item->prev != 0)
|
||||
item->prev->next = item->next;
|
||||
|
||||
m_pendingInvalidatedItems[items->cacheId].insert(item->itemId);
|
||||
|
||||
{
|
||||
QHash<quint32, Item *>::iterator it = items->items.find(item->itemId);
|
||||
while (it != items->items.end() && it.value()->itemId == item->itemId)
|
||||
it = items->items.erase(it);
|
||||
}
|
||||
|
||||
delete item;
|
||||
}
|
||||
|
||||
void QXcbSharedBufferManager::recycleItem(Buffer **sharedBuffer, int *glyphX, int *glyphY)
|
||||
{
|
||||
#if defined(SHAREDBUFFERMANAGER_DEBUG)
|
||||
qDebug("QXcbSharedBufferManager::recycleItem() called for %s", m_currentCacheId.constData());
|
||||
#endif
|
||||
|
||||
Items *items = itemsForCache(m_currentCacheId);
|
||||
|
||||
Item *recycledItem = items->leastRecentlyUsed;
|
||||
Q_ASSERT(recycledItem != 0);
|
||||
|
||||
*sharedBuffer = recycledItem->buffer;
|
||||
*glyphX = recycledItem->x;
|
||||
*glyphY = recycledItem->y;
|
||||
|
||||
deleteItem(items, recycledItem);
|
||||
}
|
||||
|
||||
void QXcbSharedBufferManager::touchBuffer(Buffer *buffer)
|
||||
{
|
||||
#if defined(SHAREDBUFFERMANAGER_DEBUG)
|
||||
qDebug("QXcbSharedBufferManager::touchBuffer() called for %s", buffer->cacheId.constData());
|
||||
#endif
|
||||
|
||||
if (buffer == m_mostRecentlyUsed)
|
||||
return;
|
||||
|
||||
if (buffer->next != 0)
|
||||
buffer->next->prev = buffer->prev;
|
||||
if (buffer->prev != 0)
|
||||
buffer->prev->next = buffer->next;
|
||||
|
||||
if (m_leastRecentlyUsed == buffer)
|
||||
m_leastRecentlyUsed = buffer->next;
|
||||
|
||||
buffer->next = 0;
|
||||
buffer->prev = m_mostRecentlyUsed;
|
||||
if (m_mostRecentlyUsed != 0)
|
||||
m_mostRecentlyUsed->next = buffer;
|
||||
if (m_leastRecentlyUsed == 0)
|
||||
m_leastRecentlyUsed = buffer;
|
||||
m_mostRecentlyUsed = buffer;
|
||||
}
|
||||
|
||||
void QXcbSharedBufferManager::deleteLeastRecentlyUsed()
|
||||
{
|
||||
#if defined(SHAREDBUFFERMANAGER_DEBUG)
|
||||
qDebug("QXcbSharedBufferManager::deleteLeastRecentlyUsed() called");
|
||||
#endif
|
||||
|
||||
if (m_leastRecentlyUsed == 0)
|
||||
return;
|
||||
|
||||
Buffer *old = m_leastRecentlyUsed;
|
||||
m_leastRecentlyUsed = old->next;
|
||||
m_leastRecentlyUsed->prev = 0;
|
||||
|
||||
QByteArray cacheId = old->cacheId;
|
||||
Items *items = itemsForCache(cacheId);
|
||||
|
||||
QHash<quint32, Item *>::iterator it = items->items.begin();
|
||||
while (it != items->items.end()) {
|
||||
Item *item = it.value();
|
||||
if (item->buffer == old) {
|
||||
deleteItem(items, item);
|
||||
it = items->items.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
m_buffers.remove(cacheId, old);
|
||||
m_memoryUsed -= old->width * old->height * old->bytesPerPixel;
|
||||
|
||||
#if defined(SHAREDBUFFERMANAGER_DEBUG)
|
||||
qDebug("QXcbSharedBufferManager::deleteLeastRecentlyUsed: Memory used: %d / %d (%6.2f %%)",
|
||||
m_memoryUsed, SHAREDGRAPHICSCACHE_MAX_MEMORY_USED,
|
||||
100.0f * float(m_memoryUsed) / float(SHAREDGRAPHICSCACHE_MAX_MEMORY_USED));
|
||||
#endif
|
||||
|
||||
delete old;
|
||||
}
|
||||
|
||||
QXcbSharedBufferManager::Buffer *QXcbSharedBufferManager::createNewBuffer(const QByteArray &cacheId,
|
||||
int heightRequired)
|
||||
{
|
||||
#if defined(SHAREDBUFFERMANAGER_DEBUG)
|
||||
qDebug("QXcbSharedBufferManager::createNewBuffer() called for %s", cacheId.constData());
|
||||
#endif
|
||||
|
||||
// ###
|
||||
// if (bufferCount of cacheId == SHAREDGRAPHICACHE_MAX_TEXTURES_PER_CACHE)
|
||||
// deleteLeastRecentlyUsedBufferForCache(cacheId);
|
||||
|
||||
// ### Take pixel format into account
|
||||
while (m_memoryUsed + SHAREDGRAPHICSCACHE_TEXTURE_SIZE * heightRequired >= SHAREDGRAPHICSCACHE_MAX_MEMORY_USED)
|
||||
deleteLeastRecentlyUsed();
|
||||
|
||||
Buffer *buffer = allocateBuffer(SHAREDGRAPHICSCACHE_TEXTURE_SIZE, heightRequired);
|
||||
buffer->cacheId = cacheId;
|
||||
|
||||
buffer->currentLineMaxHeight = 0;
|
||||
m_buffers.insert(cacheId, buffer);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static inline int qt_next_power_of_two(int v)
|
||||
{
|
||||
v--;
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
++v;
|
||||
return v;
|
||||
}
|
||||
|
||||
QXcbSharedBufferManager::Buffer *QXcbSharedBufferManager::resizeBuffer(Buffer *oldBuffer, const QSize &newSize)
|
||||
{
|
||||
#if defined(SHAREDBUFFERMANAGER_DEBUG)
|
||||
qDebug("QXcbSharedBufferManager::resizeBuffer() called for %s (current size: %dx%d, new size: %dx%d)",
|
||||
oldBuffer->cacheId.constData(), oldBuffer->width, oldBuffer->height,
|
||||
newSize.width(), newSize.height());
|
||||
#endif
|
||||
|
||||
// Remove old buffer from lists to avoid deleting it under our feet
|
||||
if (m_leastRecentlyUsed == oldBuffer)
|
||||
m_leastRecentlyUsed = oldBuffer->next;
|
||||
if (m_mostRecentlyUsed == oldBuffer)
|
||||
m_mostRecentlyUsed = oldBuffer->prev;
|
||||
|
||||
if (oldBuffer->prev != 0)
|
||||
oldBuffer->prev->next = oldBuffer->next;
|
||||
if (oldBuffer->next != 0)
|
||||
oldBuffer->next->prev = oldBuffer->prev;
|
||||
|
||||
m_memoryUsed -= oldBuffer->width * oldBuffer->height * oldBuffer->bytesPerPixel;
|
||||
m_buffers.remove(oldBuffer->cacheId, oldBuffer);
|
||||
|
||||
#if defined(SHAREDBUFFERMANAGER_DEBUG)
|
||||
qDebug("QXcbSharedBufferManager::resizeBuffer: Memory used: %d / %d (%6.2f %%)",
|
||||
m_memoryUsed, SHAREDGRAPHICSCACHE_MAX_MEMORY_USED,
|
||||
100.0f * float(m_memoryUsed) / float(SHAREDGRAPHICSCACHE_MAX_MEMORY_USED));
|
||||
#endif
|
||||
|
||||
Buffer *resizedBuffer = createNewBuffer(oldBuffer->cacheId, newSize.height());
|
||||
copyIntoBuffer(resizedBuffer, 0, 0, oldBuffer->width, oldBuffer->height,
|
||||
reinterpret_cast<uchar *>(oldBuffer->buffer->data()));
|
||||
|
||||
resizedBuffer->currentLineMaxHeight = oldBuffer->currentLineMaxHeight;
|
||||
|
||||
Items *items = itemsForCache(oldBuffer->cacheId);
|
||||
QHash<quint32, Item *>::const_iterator it = items->items.constBegin();
|
||||
while (it != items->items.constEnd()) {
|
||||
Item *item = it.value();
|
||||
if (item->buffer == oldBuffer) {
|
||||
m_pendingReadyItems[oldBuffer->cacheId].insert(item->itemId);
|
||||
item->buffer = resizedBuffer;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
resizedBuffer->nextX = oldBuffer->nextX;
|
||||
resizedBuffer->nextY = oldBuffer->nextY;
|
||||
resizedBuffer->currentLineMaxHeight = oldBuffer->currentLineMaxHeight;
|
||||
|
||||
delete oldBuffer;
|
||||
return resizedBuffer;
|
||||
}
|
||||
|
||||
void QXcbSharedBufferManager::findAvailableBuffer(int itemWidth, int itemHeight,
|
||||
Buffer **sharedBuffer, int *glyphX, int *glyphY)
|
||||
{
|
||||
Q_ASSERT(sharedBuffer != 0);
|
||||
Q_ASSERT(glyphX != 0);
|
||||
Q_ASSERT(glyphY != 0);
|
||||
|
||||
QMultiHash<QByteArray, Buffer *>::iterator it = m_buffers.find(m_currentCacheId);
|
||||
|
||||
int bufferCount = 0;
|
||||
while (it != m_buffers.end() && it.key() == m_currentCacheId) {
|
||||
Buffer *buffer = it.value();
|
||||
|
||||
int x = buffer->nextX;
|
||||
int y = buffer->nextY;
|
||||
int width = buffer->width;
|
||||
int height = buffer->height;
|
||||
|
||||
if (x + itemWidth <= width && y + itemHeight <= height) {
|
||||
// There is space on the current line, put the item there
|
||||
buffer->currentLineMaxHeight = qMax(buffer->currentLineMaxHeight, itemHeight);
|
||||
*sharedBuffer = buffer;
|
||||
*glyphX = x;
|
||||
*glyphY = y;
|
||||
|
||||
buffer->nextX += itemWidth;
|
||||
|
||||
return;
|
||||
} else if (itemWidth <= width && y + buffer->currentLineMaxHeight + itemHeight <= height) {
|
||||
// There is space for a new line, put the item on the new line
|
||||
buffer->nextX = 0;
|
||||
buffer->nextY += buffer->currentLineMaxHeight;
|
||||
buffer->currentLineMaxHeight = 0;
|
||||
|
||||
*sharedBuffer = buffer;
|
||||
*glyphX = buffer->nextX;
|
||||
*glyphY = buffer->nextY;
|
||||
|
||||
buffer->nextX += itemWidth;
|
||||
|
||||
return;
|
||||
} else if (y + buffer->currentLineMaxHeight + itemHeight <= SHAREDGRAPHICSCACHE_TEXTURE_SIZE) {
|
||||
// There is space if we resize the buffer, so we do that
|
||||
int newHeight = qt_next_power_of_two(y + buffer->currentLineMaxHeight + itemHeight);
|
||||
buffer = resizeBuffer(buffer, QSize(width, newHeight));
|
||||
|
||||
buffer->nextX = 0;
|
||||
buffer->nextY += buffer->currentLineMaxHeight;
|
||||
buffer->currentLineMaxHeight = 0;
|
||||
|
||||
*sharedBuffer = buffer;
|
||||
*glyphX = buffer->nextX;
|
||||
*glyphY = buffer->nextY;
|
||||
|
||||
buffer->nextX += itemWidth;
|
||||
return;
|
||||
}
|
||||
|
||||
bufferCount++;
|
||||
++it;
|
||||
}
|
||||
|
||||
if (bufferCount == SHAREDGRAPHICSCACHE_MAX_TEXTURES_PER_CACHE) {
|
||||
// There is no space in any buffer, and there is no space for a new buffer
|
||||
// recycle an old item
|
||||
recycleItem(sharedBuffer, glyphX, glyphY);
|
||||
} else {
|
||||
// Create a new buffer for the item
|
||||
*sharedBuffer = createNewBuffer(m_currentCacheId, qt_next_power_of_two(itemHeight));
|
||||
if (*sharedBuffer == 0) {
|
||||
Q_ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
*glyphX = (*sharedBuffer)->nextX;
|
||||
*glyphY = (*sharedBuffer)->nextY;
|
||||
|
||||
(*sharedBuffer)->nextX += itemWidth;
|
||||
}
|
||||
}
|
||||
|
||||
QXcbSharedBufferManager::Buffer *QXcbSharedBufferManager::allocateBuffer(int width, int height)
|
||||
{
|
||||
Buffer *buffer = new Buffer;
|
||||
buffer->nextX = 0;
|
||||
buffer->nextY = 0;
|
||||
buffer->width = width;
|
||||
buffer->height = height;
|
||||
buffer->bytesPerPixel = 1; // ### Use pixel format here
|
||||
|
||||
buffer->buffer = new QSharedMemory(QUuid::createUuid().toString());
|
||||
bool ok = buffer->buffer->create(buffer->width * buffer->height * buffer->bytesPerPixel,
|
||||
QSharedMemory::ReadWrite);
|
||||
if (!ok) {
|
||||
qWarning("SharedBufferManager::findAvailableBuffer: Can't create new buffer (%s)",
|
||||
qPrintable(buffer->buffer->errorString()));
|
||||
delete buffer;
|
||||
return 0;
|
||||
}
|
||||
qMemSet(buffer->buffer->data(), 0, buffer->buffer->size());
|
||||
|
||||
m_memoryUsed += buffer->width * buffer->height * buffer->bytesPerPixel;
|
||||
|
||||
#if defined(SHAREDBUFFERMANAGER_DEBUG)
|
||||
qDebug("QXcbSharedBufferManager::allocateBuffer: Memory used: %d / %d (%6.2f %%)",
|
||||
int(m_memoryUsed), int(SHAREDGRAPHICSCACHE_MAX_MEMORY_USED),
|
||||
100.0f * float(m_memoryUsed) / float(SHAREDGRAPHICSCACHE_MAX_MEMORY_USED));
|
||||
#endif
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void QXcbSharedBufferManager::copyIntoBuffer(Buffer *buffer,
|
||||
int bufferX, int bufferY, int width, int height,
|
||||
uchar *data)
|
||||
{
|
||||
#if defined(SHAREDBUFFERMANAGER_DEBUG)
|
||||
qDebug("QXcbSharedBufferManager::copyIntoBuffer() called for %s (coords: %d, %d)",
|
||||
buffer->cacheId.constData(), bufferX, bufferY);
|
||||
#endif
|
||||
|
||||
Q_ASSERT(bufferX >= 0);
|
||||
Q_ASSERT(bufferX + width <= buffer->width);
|
||||
Q_ASSERT(bufferY >= 0);
|
||||
Q_ASSERT(bufferY + height <= buffer->height);
|
||||
|
||||
uchar *dest = reinterpret_cast<uchar *>(buffer->buffer->data());
|
||||
dest += bufferX + bufferY * buffer->width;
|
||||
for (int y=0; y<height; ++y) {
|
||||
qMemCopy(dest, data, width);
|
||||
|
||||
data += width;
|
||||
dest += buffer->width;
|
||||
}
|
||||
}
|
||||
|
||||
QXcbSharedBufferManager::Items *QXcbSharedBufferManager::itemsForCache(const QByteArray &cacheId) const
|
||||
{
|
||||
Items *items = m_items.value(cacheId);
|
||||
if (items == 0) {
|
||||
items = new Items;
|
||||
items->cacheId = cacheId;
|
||||
m_items[cacheId] = items;
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QT_USE_XCB_SHARED_GRAPHICS_CACHE
|
215
src/plugins/platforms/xcb/qxcbsharedbuffermanager.h
Normal file
215
src/plugins/platforms/xcb/qxcbsharedbuffermanager.h
Normal file
@ -0,0 +1,215 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef XCBSHAREDBUFFERMANAGER_H
|
||||
#define XCBSHAREDBUFFERMANAGER_H
|
||||
|
||||
#if defined(QT_USE_XCB_SHARED_GRAPHICS_CACHE)
|
||||
|
||||
#include <QtCore/qset.h>
|
||||
#include <QtCore/qhash.h>
|
||||
#include <QtCore/qsharedmemory.h>
|
||||
|
||||
#include <GLES2/gl2.h>
|
||||
|
||||
#include <EGL/egl.h>
|
||||
|
||||
#include <EGL/eglext.h>
|
||||
|
||||
class wl_resource;
|
||||
|
||||
QT_BEGIN_HEADER
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QXcbSharedBufferManager
|
||||
{
|
||||
public:
|
||||
struct Buffer {
|
||||
Buffer()
|
||||
: width(-1)
|
||||
, height(-1)
|
||||
, bytesPerPixel(1)
|
||||
, nextX(-1)
|
||||
, nextY(-1)
|
||||
, currentLineMaxHeight(0)
|
||||
, next(0)
|
||||
, prev(0)
|
||||
, buffer(0)
|
||||
, textureId(0)
|
||||
{
|
||||
}
|
||||
|
||||
~Buffer()
|
||||
{
|
||||
delete buffer;
|
||||
|
||||
if (textureId != 0)
|
||||
glDeleteTextures(1, &textureId);
|
||||
}
|
||||
|
||||
QByteArray cacheId;
|
||||
int width;
|
||||
int height;
|
||||
int bytesPerPixel;
|
||||
int nextX;
|
||||
int nextY;
|
||||
int currentLineMaxHeight;
|
||||
|
||||
Buffer *next;
|
||||
Buffer *prev;
|
||||
|
||||
QSharedMemory *buffer;
|
||||
|
||||
GLuint textureId;
|
||||
|
||||
QAtomicInt ref;
|
||||
};
|
||||
|
||||
typedef QHash<QByteArray, QSet<quint32> > PendingItemIds;
|
||||
|
||||
QXcbSharedBufferManager();
|
||||
~QXcbSharedBufferManager();
|
||||
|
||||
void beginSharedBufferAction(const QByteArray &cacheId);
|
||||
void insertItem(quint32 itemId, uchar *data, int itemWidth, int itemHeight);
|
||||
void requestItems(const QSet<quint32> &itemIds);
|
||||
void releaseItems(const QSet<quint32> &itemIds);
|
||||
void endSharedBufferAction();
|
||||
|
||||
void getBufferForItem(const QByteArray &cacheId, quint32 itemId, Buffer **buffer,
|
||||
int *x, int *y) const;
|
||||
QPair<QByteArray, int> serializeBuffer(QSharedMemory *buffer) const;
|
||||
|
||||
PendingItemIds pendingItemsInvalidated() const
|
||||
{
|
||||
Q_ASSERT_X(m_currentCacheId.isEmpty(), Q_FUNC_INFO,
|
||||
"Call endSharedBufferAction() before accessing data");
|
||||
return m_pendingInvalidatedItems;
|
||||
}
|
||||
|
||||
PendingItemIds pendingItemsReady() const
|
||||
{
|
||||
Q_ASSERT_X(m_currentCacheId.isEmpty(), Q_FUNC_INFO,
|
||||
"Call endSharedBufferAction() before accessing data");
|
||||
return m_pendingReadyItems;
|
||||
}
|
||||
|
||||
PendingItemIds pendingItemsMissing() const
|
||||
{
|
||||
Q_ASSERT_X(m_currentCacheId.isEmpty(), Q_FUNC_INFO,
|
||||
"Call endSharedBufferAction() before accessing data");
|
||||
return m_pendingMissingItems;
|
||||
}
|
||||
|
||||
private:
|
||||
struct Item {
|
||||
Item()
|
||||
: next(0)
|
||||
, prev(0)
|
||||
, buffer(0)
|
||||
, itemId(0)
|
||||
, x(-1)
|
||||
, y(-1)
|
||||
, width(-1)
|
||||
, height(-1)
|
||||
{
|
||||
}
|
||||
|
||||
Item *next;
|
||||
Item *prev;
|
||||
|
||||
Buffer *buffer;
|
||||
quint32 itemId;
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
struct Items
|
||||
{
|
||||
Items() : leastRecentlyUsed(0), mostRecentlyUsed(0) {}
|
||||
|
||||
Item *leastRecentlyUsed;
|
||||
Item *mostRecentlyUsed;
|
||||
|
||||
QByteArray cacheId;
|
||||
QHash<quint32, Item *> items;
|
||||
};
|
||||
|
||||
void findAvailableBuffer(int itemWidth, int itemHeight, Buffer **buffer, int *x, int *y);
|
||||
void recycleItem(Buffer **buffer, int *x, int *y);
|
||||
void copyIntoBuffer(Buffer *buffer, int x, int y, int itemWidth, int itemHeight, uchar *data);
|
||||
void touchBuffer(Buffer *buffer);
|
||||
void deleteLeastRecentlyUsed();
|
||||
|
||||
Buffer *createNewBuffer(const QByteArray &cacheId, int heightRequired);
|
||||
Buffer *resizeBuffer(Buffer *buffer, const QSize &newSize);
|
||||
Buffer *allocateBuffer(int width, int height);
|
||||
|
||||
Items *itemsForCache(const QByteArray &cacheId) const;
|
||||
void pushItemToBack(Items *items, Item *item);
|
||||
void touchItem(Items *items, Item *item);
|
||||
void deleteItem(Items *items, Item *item);
|
||||
void recycleItem(const QByteArray &cacheId, Buffer **sharedBuffer, int *glyphX, int *glyphY);
|
||||
|
||||
QByteArray m_currentCacheId;
|
||||
|
||||
quint32 m_memoryUsed;
|
||||
Buffer *m_mostRecentlyUsed;
|
||||
Buffer *m_leastRecentlyUsed;
|
||||
|
||||
mutable QHash<QByteArray, Items *> m_items;
|
||||
QMultiHash<QByteArray, Buffer *> m_buffers;
|
||||
|
||||
PendingItemIds m_pendingInvalidatedItems;
|
||||
PendingItemIds m_pendingReadyItems;
|
||||
PendingItemIds m_pendingMissingItems;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
QT_END_HEADER
|
||||
|
||||
#endif // QT_USE_XCB_SHARED_GRAPHICS_CACHE
|
||||
|
||||
#endif // XCBSHAREDBUFFERMANAGER_H
|
290
src/plugins/platforms/xcb/qxcbsharedgraphicscache.cpp
Normal file
290
src/plugins/platforms/xcb/qxcbsharedgraphicscache.cpp
Normal file
@ -0,0 +1,290 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(QT_USE_XCB_SHARED_GRAPHICS_CACHE)
|
||||
|
||||
#include "qxcbsharedgraphicscache.h"
|
||||
#include "qxcbsharedbuffermanager.h"
|
||||
|
||||
#include <QtCore/qsharedmemory.h>
|
||||
|
||||
#include <QtGui/qopenglcontext.h>
|
||||
#include <QtGui/qscreen.h>
|
||||
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include <GLES2/gl2ext.h>
|
||||
|
||||
#define SHAREDGRAPHICSCACHE_DEBUG 1
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QXcbSharedGraphicsCache::QXcbSharedGraphicsCache(QObject *parent)
|
||||
: QPlatformSharedGraphicsCache(parent)
|
||||
, m_bufferManager(new QXcbSharedBufferManager)
|
||||
{
|
||||
}
|
||||
|
||||
void QXcbSharedGraphicsCache::requestItems(const QByteArray &cacheId,
|
||||
const QVector<quint32> &itemIds)
|
||||
{
|
||||
m_bufferManager->beginSharedBufferAction(cacheId);
|
||||
|
||||
QSet<quint32> itemsForRequest;
|
||||
for (int i=0; i<itemIds.size(); ++i)
|
||||
itemsForRequest.insert(itemIds.at(i));
|
||||
|
||||
m_bufferManager->requestItems(itemsForRequest);
|
||||
m_bufferManager->endSharedBufferAction();
|
||||
|
||||
processPendingItems();
|
||||
}
|
||||
|
||||
void QXcbSharedGraphicsCache::insertItems(const QByteArray &cacheId,
|
||||
const QVector<quint32> &itemIds,
|
||||
const QVector<QImage> &items)
|
||||
{
|
||||
m_bufferManager->beginSharedBufferAction(cacheId);
|
||||
|
||||
QSet<quint32> itemsForRequest;
|
||||
for (int i=0; i<itemIds.size(); ++i) {
|
||||
QImage image = items.at(i);
|
||||
m_bufferManager->insertItem(itemIds.at(i), image.bits(), image.width(), image.height());
|
||||
itemsForRequest.insert(itemIds.at(i));
|
||||
}
|
||||
|
||||
// ### To avoid loops, we could check missing items here and notify the client
|
||||
m_bufferManager->requestItems(itemsForRequest);
|
||||
|
||||
m_bufferManager->endSharedBufferAction();
|
||||
|
||||
processPendingItems();
|
||||
}
|
||||
|
||||
void QXcbSharedGraphicsCache::ensureCacheInitialized(const QByteArray &cacheId,
|
||||
BufferType bufferType,
|
||||
PixelFormat pixelFormat)
|
||||
{
|
||||
Q_UNUSED(cacheId);
|
||||
Q_UNUSED(bufferType);
|
||||
Q_UNUSED(pixelFormat);
|
||||
}
|
||||
|
||||
|
||||
void QXcbSharedGraphicsCache::releaseItems(const QByteArray &cacheId,
|
||||
const QVector<quint32> &itemIds)
|
||||
{
|
||||
m_bufferManager->beginSharedBufferAction(cacheId);
|
||||
|
||||
QSet<quint32> itemsToRelease;
|
||||
for (int i=0; i<itemIds.size(); ++i)
|
||||
itemsToRelease.insert(itemIds.at(i));
|
||||
|
||||
m_bufferManager->releaseItems(itemsToRelease);
|
||||
|
||||
m_bufferManager->endSharedBufferAction();
|
||||
|
||||
processPendingItems();
|
||||
}
|
||||
|
||||
void QXcbSharedGraphicsCache::serializeBuffer(void *bufferId,
|
||||
QByteArray *serializedData,
|
||||
int *fileDescriptor) const
|
||||
{
|
||||
QXcbSharedBufferManager::Buffer *buffer =
|
||||
reinterpret_cast<QXcbSharedBufferManager::Buffer *>(bufferId);
|
||||
|
||||
QPair<QByteArray, int> bufferName = m_bufferManager->serializeBuffer(buffer->buffer);
|
||||
|
||||
*serializedData = bufferName.first;
|
||||
*fileDescriptor = bufferName.second;
|
||||
}
|
||||
|
||||
GLuint QXcbSharedGraphicsCache::textureIdForBuffer(void *bufferId)
|
||||
{
|
||||
# if defined(SHAREDGRAPHICSCACHE_DEBUG)
|
||||
qDebug("QXcbSharedGraphicsCache::textureIdForBuffer");
|
||||
# endif
|
||||
|
||||
QXcbSharedBufferManager::Buffer *buffer =
|
||||
reinterpret_cast<QXcbSharedBufferManager::Buffer *>(bufferId);
|
||||
|
||||
if (buffer->textureId == 0) {
|
||||
glGenTextures(1, &buffer->textureId);
|
||||
if (buffer->textureId == 0) {
|
||||
qWarning("QXcbSharedGraphicsCache::textureIdForBuffer: Failed to generate texture (gl error: 0x%x)",
|
||||
glGetError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, buffer->textureId);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, buffer->textureId);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, buffer->width, buffer->height, 0, GL_ALPHA,
|
||||
GL_UNSIGNED_BYTE, buffer->buffer->data());
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
return buffer->textureId;
|
||||
}
|
||||
|
||||
void QXcbSharedGraphicsCache::referenceBuffer(void *bufferId)
|
||||
{
|
||||
QXcbSharedBufferManager::Buffer *buffer =
|
||||
reinterpret_cast<QXcbSharedBufferManager::Buffer *>(bufferId);
|
||||
|
||||
buffer->ref.ref();
|
||||
}
|
||||
|
||||
bool QXcbSharedGraphicsCache::dereferenceBuffer(void *bufferId)
|
||||
{
|
||||
QXcbSharedBufferManager::Buffer *buffer =
|
||||
reinterpret_cast<QXcbSharedBufferManager::Buffer *>(bufferId);
|
||||
|
||||
if (buffer->ref.deref())
|
||||
return true;
|
||||
|
||||
if (buffer->textureId != 0) {
|
||||
glDeleteTextures(1, &buffer->textureId);
|
||||
buffer->textureId = 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void QXcbSharedGraphicsCache::processPendingItems()
|
||||
{
|
||||
# if defined(SHAREDGRAPHICSCACHE_DEBUG)
|
||||
qDebug("QXcbSharedGraphicsCache::processPendingItems");
|
||||
# endif
|
||||
|
||||
{
|
||||
QXcbSharedBufferManager::PendingItemIds pendingMissingItems = m_bufferManager->pendingItemsMissing();
|
||||
QXcbSharedBufferManager::PendingItemIds::const_iterator it;
|
||||
|
||||
|
||||
for (it = pendingMissingItems.constBegin(); it != pendingMissingItems.constEnd(); ++it) {
|
||||
QVector<quint32> missingItems;
|
||||
|
||||
const QSet<quint32> &items = it.value();
|
||||
QSet<quint32>::const_iterator itemIt;
|
||||
for (itemIt = items.constBegin(); itemIt != items.constEnd(); ++itemIt)
|
||||
missingItems.append(*itemIt);
|
||||
|
||||
# if defined(SHAREDGRAPHICSCACHE_DEBUG)
|
||||
qDebug("QXcbSharedGraphicsCache::processPendingItems: %d missing items",
|
||||
missingItems.size());
|
||||
# endif
|
||||
|
||||
if (!missingItems.isEmpty())
|
||||
emit itemsMissing(it.key(), missingItems);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
QXcbSharedBufferManager::PendingItemIds pendingInvalidatedItems = m_bufferManager->pendingItemsInvalidated();
|
||||
QXcbSharedBufferManager::PendingItemIds::const_iterator it;
|
||||
|
||||
for (it = pendingInvalidatedItems.constBegin(); it != pendingInvalidatedItems.constEnd(); ++it) {
|
||||
QVector<quint32> invalidatedItems;
|
||||
|
||||
const QSet<quint32> &items = it.value();
|
||||
QSet<quint32>::const_iterator itemIt;
|
||||
for (itemIt = items.constBegin(); itemIt != items.constEnd(); ++itemIt)
|
||||
invalidatedItems.append(*itemIt);
|
||||
|
||||
# if defined(SHAREDGRAPHICSCACHE_DEBUG)
|
||||
qDebug("QXcbSharedGraphicsCache::processPendingItems: %d invalidated items",
|
||||
invalidatedItems.size());
|
||||
# endif
|
||||
|
||||
if (!invalidatedItems.isEmpty())
|
||||
emit itemsInvalidated(it.key(), invalidatedItems);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
QXcbSharedBufferManager::PendingItemIds pendingReadyItems = m_bufferManager->pendingItemsReady();
|
||||
QXcbSharedBufferManager::PendingItemIds::const_iterator it;
|
||||
|
||||
for (it = pendingReadyItems.constBegin(); it != pendingReadyItems.constEnd(); ++it) {
|
||||
QHash<QXcbSharedBufferManager::Buffer *, ReadyItem> readyItemsForBuffer;
|
||||
const QSet<quint32> &items = it.value();
|
||||
|
||||
QByteArray cacheId = it.key();
|
||||
|
||||
QSet<quint32>::const_iterator itemIt;
|
||||
for (itemIt = items.constBegin(); itemIt != items.constEnd(); ++itemIt) {
|
||||
QXcbSharedBufferManager::Buffer *buffer;
|
||||
int x = -1;
|
||||
int y = -1;
|
||||
|
||||
m_bufferManager->getBufferForItem(cacheId, *itemIt, &buffer, &x, &y);
|
||||
|
||||
readyItemsForBuffer[buffer].itemIds.append(*itemIt);
|
||||
readyItemsForBuffer[buffer].positions.append(QPoint(x, y));
|
||||
}
|
||||
|
||||
QHash<QXcbSharedBufferManager::Buffer*, ReadyItem>::iterator readyItemIt
|
||||
= readyItemsForBuffer.begin();
|
||||
while (readyItemIt != readyItemsForBuffer.end()) {
|
||||
QXcbSharedBufferManager::Buffer *buffer = readyItemIt.key();
|
||||
if (!readyItemIt.value().itemIds.isEmpty()) {
|
||||
# if defined(SHAREDGRAPHICSCACHE_DEBUG)
|
||||
qDebug("QXcbSharedGraphicsCache::processPendingItems: %d ready items",
|
||||
readyItemIt.value().itemIds.size());
|
||||
# endif
|
||||
|
||||
emit itemsAvailable(cacheId, buffer, QSize(buffer->width, buffer->height),
|
||||
readyItemIt.value().itemIds, readyItemIt.value().positions);
|
||||
}
|
||||
++readyItemIt;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QT_USE_XCB_SHARED_GRAPHICS_CACHE
|
91
src/plugins/platforms/xcb/qxcbsharedgraphicscache.h
Normal file
91
src/plugins/platforms/xcb/qxcbsharedgraphicscache.h
Normal file
@ -0,0 +1,91 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QXCBSHAREDGRAPHICSCACHE
|
||||
#define QXCBSHAREDGRAPHICSCACHE
|
||||
|
||||
#if defined(QT_USE_XCB_SHARED_GRAPHICS_CACHE)
|
||||
|
||||
#include <QtGui/qplatformsharedgraphicscache_qpa.h>
|
||||
|
||||
QT_BEGIN_HEADER
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QXcbSharedBufferManager;
|
||||
class QXcbSharedGraphicsCache : public QPlatformSharedGraphicsCache
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QXcbSharedGraphicsCache(QObject *parent = 0);
|
||||
|
||||
virtual void ensureCacheInitialized(const QByteArray &cacheId, BufferType bufferType,
|
||||
PixelFormat pixelFormat);
|
||||
|
||||
virtual void requestItems(const QByteArray &cacheId, const QVector<quint32> &itemIds);
|
||||
virtual void insertItems(const QByteArray &cacheId,
|
||||
const QVector<quint32> &itemIds,
|
||||
const QVector<QImage> &items);
|
||||
virtual void releaseItems(const QByteArray &cacheId, const QVector<quint32> &itemIds);
|
||||
|
||||
virtual void serializeBuffer(void *bufferId, QByteArray *serializedData, int *fileDescriptor) const;
|
||||
virtual uint textureIdForBuffer(void *bufferId);
|
||||
virtual void referenceBuffer(void *bufferId);
|
||||
virtual bool dereferenceBuffer(void *bufferId);
|
||||
|
||||
private:
|
||||
struct ReadyItem {
|
||||
QVector<quint32> itemIds;
|
||||
QVector<QPoint> positions;
|
||||
};
|
||||
|
||||
void processPendingItems();
|
||||
|
||||
QXcbSharedBufferManager *m_bufferManager;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
QT_END_HEADER
|
||||
|
||||
#endif // QT_USE_XCB_SHARED_GRAPHICS_CACHE
|
||||
|
||||
#endif // QXCBSHAREDGRAPHICSCACHE
|
@ -5,6 +5,7 @@ QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/platforms
|
||||
|
||||
QT += core-private gui-private platformsupport-private
|
||||
|
||||
|
||||
SOURCES = \
|
||||
qxcbclipboard.cpp \
|
||||
qxcbconnection.cpp \
|
||||
@ -19,7 +20,9 @@ SOURCES = \
|
||||
main.cpp \
|
||||
qxcbnativeinterface.cpp \
|
||||
qxcbcursor.cpp \
|
||||
qxcbimage.cpp
|
||||
qxcbimage.cpp \
|
||||
qxcbsharedbuffermanager.cpp \
|
||||
qxcbsharedgraphicscache.cpp
|
||||
|
||||
HEADERS = \
|
||||
qxcbclipboard.h \
|
||||
@ -35,7 +38,9 @@ HEADERS = \
|
||||
qxcbwmsupport.h \
|
||||
qxcbnativeinterface.h \
|
||||
qxcbcursor.h \
|
||||
qxcbimage.h
|
||||
qxcbimage.h \
|
||||
qxcbsharedbuffermanager.h \
|
||||
qxcbsharedgraphicscache.h
|
||||
|
||||
contains(QT_CONFIG, xcb-poll-for-queued-event) {
|
||||
DEFINES += XCB_POLL_FOR_QUEUED_EVENT
|
||||
|
Loading…
Reference in New Issue
Block a user