Fixed KMS y-invertedness.

Upgrade to new gbm_surface API which lets us use eglCreateWindowSurface.

Change-Id: I4af86d442375017ae3b4744e7b3bdebf3b496b6e
Reviewed-by: Andy Nichols <andy.nichols@nokia.com>
bb10
Samuel Rødal 2012-05-29 14:18:04 +02:00 committed by Qt by Nokia
parent 44f7df439f
commit ef204659b9
12 changed files with 175 additions and 445 deletions

View File

@ -17,7 +17,6 @@ SOURCES = main.cpp \
qkmswindow.cpp \
qkmscursor.cpp \
qkmsdevice.cpp \
qkmsbuffermanager.cpp \
qkmsbackingstore.cpp \
qkmsnativeinterface.cpp \
qkmsudevlistener.cpp \
@ -29,7 +28,6 @@ HEADERS = qkmsintegration.h \
qkmswindow.h \
qkmscursor.h \
qkmsdevice.h \
qkmsbuffermanager.h \
qkmsbackingstore.h \
qkmsnativeinterface.h \
qkmsudevlistener.h \

View File

@ -1,200 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** 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());
eglMakeCurrent(m_screen->device()->eglDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
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

View File

@ -1,105 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** 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 QKMSBUFFERMANAGER_H
#define QKMSBUFFERMANAGER_H
#include <QObject>
#include <QList>
#define EGL_EGLEXT_PROTOTYPES 1
#define GL_GLEXT_PROTOTYPES 1
extern "C" {
#include <gbm.h>
#include <xf86drmMode.h>
#include <xf86drm.h>
}
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
QT_BEGIN_NAMESPACE
class QKmsScreen;
class QKmsFramebuffer
{
public:
QKmsFramebuffer() : available(true) {}
gbm_bo *graphicsBufferObject;
GLuint renderBuffer;
EGLImageKHR eglImage;
quint32 framebufferId;
bool available;
};
class QKmsBufferManager
{
public:
explicit QKmsBufferManager(QKmsScreen *screen);
~QKmsBufferManager();
void setupBuffersForMode(const drmModeModeInfo &mode, int numBuffers = 3);
GLuint framebufferObject() const { return m_frameBufferObject; }
quint32 displayFramebufferId();
GLuint renderTargetBuffer();
bool nextBuffer();
private:
void clearBuffers();
QKmsScreen *m_screen;
QList<QKmsFramebuffer*> m_framebuffers;
GLuint m_frameBufferObject;
GLuint m_depthAndStencilBufferObject;
QKmsFramebuffer *m_renderTarget;
QKmsFramebuffer *m_displayCanidate;
QKmsFramebuffer *m_currentDisplay;
};
QT_END_NAMESPACE
#endif // QKMSBUFFERMANAGER_H

View File

@ -44,29 +44,56 @@
#include "qkmscontext.h"
#include "qkmswindow.h"
#include <QOpenGLContext>
#include <QtPlatformSupport/private/qeglconvenience_p.h>
QT_BEGIN_NAMESPACE
QKmsContext::QKmsContext(QKmsDevice *device)
: QPlatformOpenGLContext(),
m_device(device)
QKmsContext::QKmsContext(QOpenGLContext *context, QKmsDevice *device)
: QPlatformOpenGLContext()
, m_device(device)
{
EGLDisplay display = m_device->eglDisplay();
EGLConfig config = q_configFromGLFormat(display, QKmsScreen::tweakFormat(context->format()), true);
m_format = q_glFormatFromConfig(display, config);
//Initialize EGLContext
static EGLint contextAttribs[] = {
EGL_CONTEXT_CLIENT_VERSION, context->format().majorVersion(),
EGL_NONE
};
eglBindAPI(EGL_OPENGL_ES_API);
m_eglContext = eglCreateContext(display, config, 0, contextAttribs);
if (m_eglContext == EGL_NO_CONTEXT) {
qWarning("QKmsContext::QKmsContext(): eglError: %x, this: %p",
eglGetError(), this);
m_eglContext = 0;
}
}
bool QKmsContext::isValid() const
{
return m_eglContext != EGL_NO_CONTEXT;
}
bool QKmsContext::makeCurrent(QPlatformSurface *surface)
{
EGLDisplay display = m_device->eglDisplay();
EGLContext context = m_device->eglContext();
bool ok = eglMakeCurrent(display, EGL_NO_SURFACE,
EGL_NO_SURFACE, context);
if (!ok)
qWarning("QKmsContext::makeCurrent(): eglError: %d, this: %p",
eglGetError(), this);
QPlatformWindow *window = static_cast<QPlatformWindow *>(surface);
QKmsScreen *screen = static_cast<QKmsScreen *> (QPlatformScreen::platformScreenForWindow(window->window()));
screen->bindFramebuffer();
EGLSurface eglSurface = screen->eglSurface();
screen->waitForPageFlipComplete();
bool ok = eglMakeCurrent(display, eglSurface, eglSurface, m_eglContext);
if (!ok)
qWarning("QKmsContext::makeCurrent(): eglError: %x, this: %p",
eglGetError(), this);
return true;
}
@ -75,17 +102,13 @@ void QKmsContext::doneCurrent()
bool ok = eglMakeCurrent(m_device->eglDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE,
EGL_NO_CONTEXT);
if (!ok)
qWarning("QKmsContext::doneCurrent(): eglError: %d, this: %p",
qWarning("QKmsContext::doneCurrent(): eglError: %x, this: %p",
eglGetError(), this);
}
void QKmsContext::swapBuffers(QPlatformSurface *surface)
{
//After flush, the current render target should be moved to
//latest complete
glFlush();
//Cast context to a window surface and get the screen the context
//is on and call swapBuffers on that screen.
QPlatformWindow *window = static_cast<QPlatformWindow *>(surface);
@ -101,19 +124,12 @@ void (*QKmsContext::getProcAddress(const QByteArray &procName)) ()
EGLContext QKmsContext::eglContext() const
{
return m_device->eglContext();
return m_eglContext;
}
QSurfaceFormat QKmsContext::format() const
{
return QSurfaceFormat();
}
GLuint QKmsContext::defaultFramebufferObject(QPlatformSurface *surface) const
{
QPlatformWindow *window = static_cast<QPlatformWindow *>(surface);
QKmsScreen *screen = static_cast<QKmsScreen *> (QPlatformScreen::platformScreenForWindow(window->window()));
return screen->framebufferObject();
return m_format;
}
QT_END_NAMESPACE

View File

@ -54,20 +54,22 @@ class QKmsDevice;
class QKmsContext : public QPlatformOpenGLContext
{
public:
QKmsContext(QKmsDevice *device);
QKmsContext(QOpenGLContext *context, QKmsDevice *device);
bool makeCurrent(QPlatformSurface *surface);
void doneCurrent();
void swapBuffers(QPlatformSurface *surface);
void (*getProcAddress(const QByteArray &procName)) ();
bool isValid() const;
QSurfaceFormat format() const;
EGLContext eglContext() const;
GLuint defaultFramebufferObject(QPlatformSurface *surface) const;
private:
EGLContext m_eglContext;
QSurfaceFormat m_format;
QKmsDevice *m_device;
};

View File

@ -73,37 +73,14 @@ QKmsDevice::QKmsDevice(const QString &path, QKmsIntegration *parent) :
qFatal("EGL error");
}
QString extensions = eglQueryString(m_eglDisplay, EGL_EXTENSIONS);
if (!extensions.contains(QString::fromLatin1("EGL_KHR_surfaceless_opengl"))) {
qFatal("EGL_KHR_surfaceless_opengl extension not available");
}
//Initialize EGLContext
static EGLint contextAttribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
eglBindAPI(EGL_OPENGL_ES_API);
m_eglContext = eglCreateContext(m_eglDisplay, 0, 0, contextAttribs);
if (m_eglContext == EGL_NO_CONTEXT) {
qWarning("Could not create the EGL context.");
eglTerminate(m_eglDisplay);
qFatal("EGL error");
}
createScreens();
QSocketNotifier *notifier = new QSocketNotifier(m_fd, QSocketNotifier::Read, this);
connect(notifier, SIGNAL(activated(int)), this, SLOT(handlePageFlipCompleted()));
// QSocketNotifier *notifier = new QSocketNotifier(m_fd, QSocketNotifier::Read, this);
// connect(notifier, SIGNAL(activated(int)), this, SLOT(handlePageFlipCompleted()));
}
QKmsDevice::~QKmsDevice()
{
if (m_eglContext != EGL_NO_CONTEXT) {
eglDestroyContext(m_eglDisplay, m_eglContext);
m_eglContext = EGL_NO_CONTEXT;
}
}
void QKmsDevice::createScreens()
@ -127,7 +104,6 @@ void QKmsDevice::createScreens()
void QKmsDevice::handlePageFlipCompleted()
{
//qDebug() << "Display signal received";
drmEventContext eventContext;
memset(&eventContext, 0, sizeof eventContext);
@ -143,21 +119,9 @@ void QKmsDevice::pageFlipHandler(int fd, unsigned int frame, unsigned int sec, u
Q_UNUSED(frame)
Q_UNUSED(sec)
Q_UNUSED(usec)
static unsigned int previousTime = 0;
unsigned int currentTime = sec * 1000000 + usec;
unsigned int refreshTime = 0;
// qDebug() << "fd: " << fd << " frame: " << frame << " sec: "
// << sec << " usec: " << usec << " data: " << data
// << "msecs" << sec * 1000 + usec / 1000;
QKmsScreen *screen = static_cast<QKmsScreen *>(data);
if (previousTime == 0)
refreshTime = 16000;
else
refreshTime = currentTime - previousTime;
screen->setFlipReady(refreshTime);
screen->handlePageFlipped();
}
QT_END_NAMESPACE

View File

@ -65,7 +65,6 @@ public:
EGLDisplay eglDisplay() { return m_eglDisplay; }
gbm_device *gbmDevice() { return m_graphicsBufferManager; }
EGLContext eglContext() { return m_eglContext; }
int fd() const { return m_fd; }
static void pageFlipHandler(int fd, unsigned int frame, unsigned int sec,

View File

@ -95,6 +95,7 @@ bool QKmsIntegration::hasCapability(QPlatformIntegration::Capability cap) const
case ThreadedPixmaps: return true;
case OpenGL: return true;
case ThreadedOpenGL: return true;
case BufferQueueingOpenGL: return true;
default: return QPlatformIntegration::hasCapability(cap);
}
}
@ -102,7 +103,7 @@ bool QKmsIntegration::hasCapability(QPlatformIntegration::Capability cap) const
QPlatformOpenGLContext *QKmsIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
QKmsScreen *screen = static_cast<QKmsScreen *>(context->screen()->handle());
return new QKmsContext(screen->device());
return new QKmsContext(context, screen->device());
}
QPlatformWindow *QKmsIntegration::createPlatformWindow(QWindow *window) const

View File

@ -87,15 +87,9 @@ void *QKmsNativeInterface::eglDisplayForWindow(QWindow *window)
return device->eglDisplay();
}
void *QKmsNativeInterface::eglContextForWindow(QWindow *window)
void *QKmsNativeInterface::eglContextForWindow(QWindow *)
{
QKmsScreen *screen = qPlatformScreenForWindow(window);
if (!screen)
return 0;
QKmsDevice *device = screen->device();
if (!device)
return 0;
return device->eglContext();
return 0;
}
QKmsScreen *QKmsNativeInterface::qPlatformScreenForWindow(QWindow *window)

View File

@ -39,11 +39,16 @@
**
****************************************************************************/
//#include <QDebug>
#include "qkmscursor.h"
#include "qkmsscreen.h"
#include "qkmscursor.h"
#include "qkmsdevice.h"
#include "qkmscontext.h"
#include "qkmsbuffermanager.h"
#include <QtPlatformSupport/private/qeglconvenience_p.h>
#include <QCoreApplication>
#include <QtDebug>
QT_BEGIN_NAMESPACE
@ -60,12 +65,13 @@ static drmModeModeInfo builtin_1024x768 = {
QKmsScreen::QKmsScreen(QKmsDevice *device, int connectorId)
: m_device(device),
m_flipReady(true),
m_current_bo(0),
m_next_bo(0),
m_connectorId(connectorId),
m_depth(32),
m_format(QImage::Format_Invalid),
m_bufferManager(this),
m_refreshTime(16000)
m_refreshTime(16000),
m_modeSet(false)
{
m_cursor = new QKmsCursor(this);
initializeScreenMode();
@ -101,11 +107,6 @@ QPlatformCursor *QKmsScreen::cursor() const
return m_cursor;
}
GLuint QKmsScreen::framebufferObject() const
{
return m_bufferManager.framebufferObject();
}
void QKmsScreen::initializeScreenMode()
{
//Determine optimal mode for screen
@ -132,71 +133,100 @@ void QKmsScreen::initializeScreenMode()
if (i == resources->count_crtcs)
qFatal("No usable crtc for encoder.");
m_oldCrtc = drmModeGetCrtc(m_device->fd(), encoder->crtc_id);
m_crtcId = resources->crtcs[i];
m_mode = *mode;
m_geometry = QRect(0, 0, m_mode.hdisplay, m_mode.vdisplay);
qDebug() << "kms initialized with geometry" << m_geometry;
m_depth = 32;
m_format = QImage::Format_RGB32;
m_physicalSize = QSizeF(connector->mmWidth, connector->mmHeight);
//Setup three buffers for current mode
m_bufferManager.setupBuffersForMode(m_mode, 3);
//Set the Mode of the screen.
int ret = drmModeSetCrtc(m_device->fd(), m_crtcId, m_bufferManager.displayFramebufferId(),
0, 0, &m_connectorId, 1, &m_mode);
if (ret)
qFatal("failed to set mode");
m_gbmSurface = gbm_surface_create(m_device->gbmDevice(),
m_mode.hdisplay, m_mode.vdisplay,
GBM_BO_FORMAT_XRGB8888,
GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
qDebug() << "created gbm surface" << m_gbmSurface << m_mode.hdisplay << m_mode.vdisplay;
//Cleanup
drmModeFreeEncoder(encoder);
drmModeFreeConnector(connector);
drmModeFreeResources(resources);
}
void QKmsScreen::bindFramebuffer()
QSurfaceFormat QKmsScreen::tweakFormat(const QSurfaceFormat &format)
{
if (m_bufferManager.framebufferObject()) {
glBindFramebuffer(GL_FRAMEBUFFER, m_bufferManager.framebufferObject());
QSurfaceFormat fmt = format;
fmt.setRedBufferSize(8);
fmt.setGreenBufferSize(8);
fmt.setBlueBufferSize(8);
if (fmt.alphaBufferSize() != -1)
fmt.setAlphaBufferSize(8);
return fmt;
}
glFramebufferRenderbuffer(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER,
m_bufferManager.renderTargetBuffer());
}
void QKmsScreen::initializeWithFormat(const QSurfaceFormat &format)
{
EGLDisplay display = m_device->eglDisplay();
EGLConfig config = q_configFromGLFormat(display, tweakFormat(format), true);
m_eglWindowSurface = eglCreateWindowSurface(display, config, (EGLNativeWindowType)m_gbmSurface, NULL);
qDebug() << "created window surface";
}
void QKmsScreen::swapBuffers()
{
waitForPageFlipComplete();
eglSwapBuffers(m_device->eglDisplay(), m_eglWindowSurface);
if ( m_flipReady )
performPageFlip();
//TODO: Do something with return value here
m_bufferManager.nextBuffer();
//qDebug() << "swapBuffers now rendering to " << m_bufferManager.renderTargetBuffer();
bindFramebuffer();
m_next_bo = gbm_surface_lock_front_buffer(m_gbmSurface);
if (!m_next_bo)
qFatal("kms: Failed to lock front buffer");
performPageFlip();
}
void QKmsScreen::performPageFlip()
{
quint32 displayFramebufferId = m_bufferManager.displayFramebufferId();
//qDebug() << "Flipping to framebuffer: " << displayFramebufferId;
if (!m_next_bo)
return;
uint32_t width = gbm_bo_get_width(m_next_bo);
uint32_t height = gbm_bo_get_height(m_next_bo);
uint32_t stride = gbm_bo_get_pitch(m_next_bo);
uint32_t handle = gbm_bo_get_handle(m_next_bo).u32;
uint32_t fb_id;
int ret = drmModeAddFB(m_device->fd(), width, height, 24, 32,
stride, handle, &fb_id);
if (ret) {
qFatal("kms: Failed to create fb: fd %d, w %d, h %d, stride %d, handle %d, ret %d",
m_device->fd(), width, height, stride, handle, ret);
}
if (!m_modeSet) {
//Set the Mode of the screen.
int ret = drmModeSetCrtc(m_device->fd(), m_crtcId, fb_id,
0, 0, &m_connectorId, 1, &m_mode);
if (ret)
qFatal("failed to set mode");
m_modeSet = true;
}
int pageFlipStatus = drmModePageFlip(m_device->fd(), m_crtcId,
displayFramebufferId,
fb_id,
DRM_MODE_PAGE_FLIP_EVENT, this);
if (pageFlipStatus)
qWarning("Pageflip status: %d", pageFlipStatus);
m_flipReady = false;
}
void QKmsScreen::setFlipReady(unsigned int time)
void QKmsScreen::handlePageFlipped()
{
m_flipReady = true;
m_refreshTime = time;
performPageFlip();
if (m_current_bo)
gbm_surface_release_buffer(m_gbmSurface, m_current_bo);
m_current_bo = m_next_bo;
m_next_bo = 0;
}
QKmsDevice * QKmsScreen::device() const
@ -206,23 +236,25 @@ QKmsDevice * QKmsScreen::device() const
void QKmsScreen::waitForPageFlipComplete()
{
//Check manually if there is something to be read on the device
//as there are senarios where the signal is not received (starvation)
fd_set fdSet;
timeval timeValue;
int returnValue;
while (m_next_bo) {
#if 0
//Check manually if there is something to be read on the device
//as there are senarios where the signal is not received (starvation)
fd_set fdSet;
timeval timeValue;
int returnValue;
FD_ZERO(&fdSet);
FD_SET(m_device->fd(), &fdSet);
timeValue.tv_sec = 0;
timeValue.tv_usec = m_refreshTime;
FD_ZERO(&fdSet);
FD_SET(m_device->fd(), &fdSet);
timeValue.tv_sec = 0;
timeValue.tv_usec = 1000;
returnValue = select(1, &fdSet, 0, 0, &timeValue);
returnValue = select(1, &fdSet, 0, 0, &timeValue);
printf("select returns %d\n", returnValue);
#endif
if (returnValue) {
m_device->handlePageFlipCompleted();
}
}

View File

@ -42,8 +42,23 @@
#ifndef QKMSSCREEN_H
#define QKMSSCREEN_H
#include <stddef.h>
#define EGL_EGLEXT_PROTOTYPES 1
#define GL_GLEXT_PROTOTYPES 1
extern "C" {
#include <gbm.h>
#include <xf86drmMode.h>
#include <xf86drm.h>
}
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <qpa/qplatformscreen.h>
#include "qkmsbuffermanager.h"
QT_BEGIN_NAMESPACE
@ -63,22 +78,28 @@ public:
QSizeF physicalSize() const;
QPlatformCursor *cursor() const;
GLuint framebufferObject() const;
quint32 crtcId() const { return m_crtcId; }
QKmsDevice *device() const;
void initializeWithFormat(const QSurfaceFormat &format);
//Called by context for each screen
void bindFramebuffer();
void swapBuffers();
void setFlipReady(unsigned int time);
void handlePageFlipped();
EGLSurface eglSurface() const { return m_eglWindowSurface; }
void waitForPageFlipComplete();
static QSurfaceFormat tweakFormat(const QSurfaceFormat &format);
private:
void performPageFlip();
void initializeScreenMode();
void waitForPageFlipComplete();
QKmsDevice *m_device;
bool m_flipReady;
gbm_bo *m_current_bo;
gbm_bo *m_next_bo;
quint32 m_connectorId;
quint32 m_crtcId;
@ -88,9 +109,15 @@ private:
int m_depth;
QImage::Format m_format;
drmModeCrtcPtr m_oldCrtc;
QKmsCursor *m_cursor;
QKmsBufferManager m_bufferManager;
unsigned int m_refreshTime;
gbm_surface *m_gbmSurface;
EGLSurface m_eglWindowSurface;
bool m_modeSet;
};
QT_END_NAMESPACE

View File

@ -49,6 +49,8 @@ QKmsWindow::QKmsWindow(QWindow *window)
: QPlatformWindow(window)
{
m_screen = QPlatformScreen::platformScreenForWindow(window);
static_cast<QKmsScreen *>(m_screen)->initializeWithFormat(window->requestedFormat());
}
void QKmsWindow::setGeometry(const QRect &rect)