From 9a652ed802d5ec1114ba97ad86eca8d2f25c53d9 Mon Sep 17 00:00:00 2001 From: Andy Nichols Date: Tue, 2 Aug 2011 15:07:50 +0200 Subject: Initial support for Qt using Kernel Mode-setting (KMS) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This platform plugin supports fullscreen OpenGLES2 windows on devices that support Kernel Mode-setting. Change-Id: I7d4077319654c13851f0ff7ec0228b7b13936382 Reviewed-on: http://codereview.qt.nokia.com/2516 Reviewed-by: Qt Sanity Bot Reviewed-by: Jørgen Lind --- src/plugins/platforms/kms/qkmsbuffermanager.cpp | 198 ++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 src/plugins/platforms/kms/qkmsbuffermanager.cpp (limited to 'src/plugins/platforms/kms/qkmsbuffermanager.cpp') diff --git a/src/plugins/platforms/kms/qkmsbuffermanager.cpp b/src/plugins/platforms/kms/qkmsbuffermanager.cpp new file mode 100644 index 0000000000..0c2eec0f3b --- /dev/null +++ b/src/plugins/platforms/kms/qkmsbuffermanager.cpp @@ -0,0 +1,198 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#include "qkmsbuffermanager.h" +#include "qkmsscreen.h" +#include "qkmscontext.h" +#include "qkmsdevice.h" + +QT_BEGIN_NAMESPACE + +QKmsBufferManager::QKmsBufferManager(QKmsScreen *screen) : + m_screen(screen), + m_frameBufferObject(0), + m_renderTarget(0), + m_displayCanidate(0), + m_currentDisplay(0) +{ +} + +QKmsBufferManager::~QKmsBufferManager() +{ + clearBuffers(); + glDeleteFramebuffers(1, &m_frameBufferObject); +} + +void QKmsBufferManager::setupBuffersForMode(const drmModeModeInfo &mode, int numBuffers) +{ + eglMakeCurrent(m_screen->device()->eglDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, m_screen->device()->eglContext()); + m_screen->bindFramebuffer(); + + + if (m_frameBufferObject) { + clearBuffers(); + } else { + //Setup Framebuffer Object + glGenFramebuffers(1, &m_frameBufferObject); + glBindFramebuffer(GL_FRAMEBUFFER, m_frameBufferObject); + } + + //Setup shared Depth/Stencil buffer + glGenRenderbuffers(1, &m_depthAndStencilBufferObject); + glBindRenderbuffer(GL_RENDERBUFFER, m_depthAndStencilBufferObject); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, + mode.hdisplay, mode.vdisplay); + + //Setup "numBuffer" many rendering targets + for (int i = 0; i < numBuffers; i++) { + QKmsFramebuffer *buffer = new QKmsFramebuffer(); + + glGenRenderbuffers(1, &buffer->renderBuffer); + glBindRenderbuffer(GL_RENDERBUFFER, buffer->renderBuffer); + + buffer->graphicsBufferObject = gbm_bo_create(m_screen->device()->gbmDevice(), + mode.hdisplay, mode.vdisplay, + GBM_BO_FORMAT_XRGB8888, + GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); + buffer->eglImage = eglCreateImageKHR(m_screen->device()->eglDisplay(), 0, EGL_NATIVE_PIXMAP_KHR, + buffer->graphicsBufferObject, 0); + glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, buffer->eglImage); + + quint32 stride = gbm_bo_get_pitch(buffer->graphicsBufferObject); + quint32 handle = gbm_bo_get_handle(buffer->graphicsBufferObject).u32; + + int status = drmModeAddFB(m_screen->device()->fd(), mode.hdisplay, mode.vdisplay, + 32, 32, stride, handle, &buffer->framebufferId); + //Todo: IF this returns true, then this is one less buffer that we use + //Not so fatal, but not handled at the moment. + if (status) + qFatal("failed to add framebuffer"); + m_framebuffers.append(buffer); + } + //Attach the Depth and Stencil buffer + glFramebufferRenderbuffer(GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, + m_depthAndStencilBufferObject); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, + GL_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, + m_depthAndStencilBufferObject); + //Attach renderbuffer as Color Attachment. + glFramebufferRenderbuffer(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, + this->renderTargetBuffer()); +} + +void QKmsBufferManager::clearBuffers() +{ + //Make sure that the FBO is binded + glBindFramebuffer(GL_FRAMEBUFFER, m_frameBufferObject); + //Detach the Color/Depth/Stencil Attachments. + glFramebufferRenderbuffer(GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, + 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, + 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, + GL_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, + 0); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + //Delete the shared Depth/Stencil buffer + glDeleteRenderbuffers(1, &m_depthAndStencilBufferObject); + + //Delete each renderbuffer object + //Delete each EGLImage + //Remove each drm Framebuffer + foreach (QKmsFramebuffer *buffer, m_framebuffers) { + glDeleteRenderbuffers(1, &buffer->renderBuffer); + eglDestroyImageKHR(m_screen->device()->eglDisplay(), buffer->eglImage); + drmModeRmFB(m_screen->device()->fd(), buffer->framebufferId); + delete buffer; + } + m_framebuffers.clear(); +} + +GLuint QKmsBufferManager::renderTargetBuffer() +{ + //TODO: Handle more senarios than assuming at least 2 buffers + if (!m_renderTarget) { + m_renderTarget = m_framebuffers.at(1); + } + return m_renderTarget->renderBuffer; +} + +quint32 QKmsBufferManager::displayFramebufferId() +{ + if (!m_currentDisplay) { + m_currentDisplay = m_framebuffers.at(0); + m_currentDisplay->available = false; + return m_currentDisplay->framebufferId; + } + + if (!m_displayCanidate) + return m_currentDisplay->framebufferId; + + m_currentDisplay->available = true; + m_displayCanidate->available = false; + m_currentDisplay = m_displayCanidate; + return m_currentDisplay->framebufferId; + +} + +bool QKmsBufferManager::nextBuffer() +{ + m_displayCanidate = m_renderTarget; + foreach (QKmsFramebuffer *buffer, m_framebuffers) { + if (buffer->available && buffer != m_displayCanidate) { + m_renderTarget = buffer; + return true; + } + } + return false; +} + +QT_BEGIN_NAMESPACE -- cgit v1.2.3