2014-08-20 13:29:38 +00:00
|
|
|
/********************************************************************
|
|
|
|
KWin - the KDE window manager
|
|
|
|
This file is part of the KDE project.
|
|
|
|
|
|
|
|
Copyright (C) 2013 Martin Gräßlin <mgraesslin@kde.org>
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*********************************************************************/
|
|
|
|
#include "shm_pool.h"
|
|
|
|
#include "buffer.h"
|
|
|
|
// Qt
|
|
|
|
#include <QDebug>
|
|
|
|
#include <QImage>
|
|
|
|
#include <QTemporaryFile>
|
|
|
|
// system
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
|
|
|
|
namespace KWin
|
|
|
|
{
|
|
|
|
namespace Wayland
|
|
|
|
{
|
|
|
|
|
2014-08-21 05:54:16 +00:00
|
|
|
ShmPool::ShmPool(QObject *parent)
|
|
|
|
: QObject(parent)
|
|
|
|
, m_shm(nullptr)
|
2014-08-20 13:29:38 +00:00
|
|
|
, m_pool(nullptr)
|
|
|
|
, m_poolData(nullptr)
|
|
|
|
, m_size(1024)
|
|
|
|
, m_tmpFile(new QTemporaryFile())
|
2014-08-21 05:54:16 +00:00
|
|
|
, m_valid(false)
|
2014-08-20 13:29:38 +00:00
|
|
|
, m_offset(0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
ShmPool::~ShmPool()
|
2014-08-21 05:54:16 +00:00
|
|
|
{
|
|
|
|
release();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShmPool::release()
|
2014-08-20 13:29:38 +00:00
|
|
|
{
|
|
|
|
qDeleteAll(m_buffers);
|
2014-08-21 05:54:16 +00:00
|
|
|
m_buffers.clear();
|
2014-08-20 13:29:38 +00:00
|
|
|
if (m_poolData) {
|
|
|
|
munmap(m_poolData, m_size);
|
2014-08-21 05:54:16 +00:00
|
|
|
m_poolData = nullptr;
|
2014-08-20 13:29:38 +00:00
|
|
|
}
|
|
|
|
if (m_pool) {
|
|
|
|
wl_shm_pool_destroy(m_pool);
|
2014-08-21 05:54:16 +00:00
|
|
|
m_pool = nullptr;
|
2014-08-20 13:29:38 +00:00
|
|
|
}
|
|
|
|
if (m_shm) {
|
|
|
|
wl_shm_destroy(m_shm);
|
2014-08-21 05:54:16 +00:00
|
|
|
m_shm = nullptr;
|
|
|
|
}
|
|
|
|
m_tmpFile->close();
|
|
|
|
m_valid = false;
|
|
|
|
m_offset = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShmPool::destroy()
|
|
|
|
{
|
|
|
|
qDeleteAll(m_buffers);
|
|
|
|
m_buffers.clear();
|
|
|
|
if (m_poolData) {
|
|
|
|
munmap(m_poolData, m_size);
|
|
|
|
m_poolData = nullptr;
|
|
|
|
}
|
|
|
|
if (m_pool) {
|
|
|
|
free(m_pool);
|
|
|
|
m_pool = nullptr;
|
|
|
|
}
|
|
|
|
if (m_shm) {
|
|
|
|
free(m_shm);
|
|
|
|
m_shm = nullptr;
|
2014-08-20 13:29:38 +00:00
|
|
|
}
|
|
|
|
m_tmpFile->close();
|
2014-08-21 05:54:16 +00:00
|
|
|
m_valid = false;
|
|
|
|
m_offset = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShmPool::setup(wl_shm *shm)
|
|
|
|
{
|
|
|
|
Q_ASSERT(shm);
|
|
|
|
Q_ASSERT(!m_shm);
|
|
|
|
m_shm = shm;
|
|
|
|
m_valid = createPool();
|
2014-08-20 13:29:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ShmPool::createPool()
|
|
|
|
{
|
|
|
|
if (!m_tmpFile->open()) {
|
|
|
|
qDebug() << "Could not open temporary file for Shm pool";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (ftruncate(m_tmpFile->handle(), m_size) < 0) {
|
|
|
|
qDebug() << "Could not set size for Shm pool file";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
m_poolData = mmap(NULL, m_size, PROT_READ | PROT_WRITE, MAP_SHARED, m_tmpFile->handle(), 0);
|
|
|
|
m_pool = wl_shm_create_pool(m_shm, m_tmpFile->handle(), m_size);
|
|
|
|
|
|
|
|
if (!m_poolData || !m_pool) {
|
|
|
|
qDebug() << "Creating Shm pool failed";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ShmPool::resizePool(int32_t newSize)
|
|
|
|
{
|
|
|
|
if (ftruncate(m_tmpFile->handle(), newSize) < 0) {
|
|
|
|
qDebug() << "Could not set new size for Shm pool file";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
wl_shm_pool_resize(m_pool, newSize);
|
|
|
|
munmap(m_poolData, m_size);
|
|
|
|
m_poolData = mmap(NULL, newSize, PROT_READ | PROT_WRITE, MAP_SHARED, m_tmpFile->handle(), 0);
|
|
|
|
m_size = newSize;
|
|
|
|
if (!m_poolData) {
|
|
|
|
qDebug() << "Resizing Shm pool failed";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
emit poolResized();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
wl_buffer *ShmPool::createBuffer(const QImage& image)
|
|
|
|
{
|
|
|
|
if (image.isNull() || !m_valid) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
Buffer *buffer = getBuffer(image.size(), image.bytesPerLine());
|
|
|
|
if (!buffer) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
buffer->copy(image.bits());
|
|
|
|
return buffer->buffer();
|
|
|
|
}
|
|
|
|
|
|
|
|
wl_buffer *ShmPool::createBuffer(const QSize &size, int32_t stride, const void *src)
|
|
|
|
{
|
|
|
|
if (size.isNull() || !m_valid) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
Buffer *buffer = getBuffer(size, stride);
|
|
|
|
if (!buffer) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
buffer->copy(src);
|
|
|
|
return buffer->buffer();
|
|
|
|
}
|
|
|
|
|
|
|
|
Buffer *ShmPool::getBuffer(const QSize &size, int32_t stride)
|
|
|
|
{
|
|
|
|
Q_FOREACH (Buffer *buffer, m_buffers) {
|
|
|
|
if (!buffer->isReleased() || buffer->isUsed()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (buffer->size() != size || buffer->stride() != stride) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
buffer->setReleased(false);
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
const int32_t byteCount = size.height() * stride;
|
|
|
|
if (m_offset + byteCount > m_size) {
|
|
|
|
if (!resizePool(m_size + byteCount)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// we don't have a buffer which we could reuse - need to create a new one
|
|
|
|
wl_buffer *native = wl_shm_pool_create_buffer(m_pool, m_offset, size.width(), size.height(),
|
|
|
|
stride, WL_SHM_FORMAT_ARGB8888);
|
|
|
|
if (!native) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
Buffer *buffer = new Buffer(this, native, size, stride, m_offset);
|
|
|
|
m_offset += byteCount;
|
|
|
|
m_buffers.append(buffer);
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|