blob: 99896151b29e6a11d52f1c960a647f43d9d6a1cb [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qopenwfddevice.h"
#include "qopenwfdport.h"
#include "qopenwfdscreen.h"
#include <QtCore/QDebug>
#include <WF/wfdext.h>
#include <gbm.h>
QOpenWFDDevice::QOpenWFDDevice(QOpenWFDIntegration *integration, WFDint device_enumeration)
: mIntegration(integration)
, mDeviceEnum(device_enumeration)
, mCommitedDevice(false)
, mWaitingForBindSourceEvent(false)
{
mDevice = wfdCreateDevice(WFD_DEFAULT_DEVICE_ID,WFD_NONE);
if (mDevice == WFD_INVALID_HANDLE)
qDebug("failed to create device");
mEvent = wfdCreateEvent(mDevice,0);
if (mEvent == WFD_INVALID_HANDLE)
qDebug("failed to create event handle");
//initialize pipelines for device.
wfdEnumeratePipelines(mDevice,WFD_NONE,0,WFD_NONE);
initializeGbmAndEgl();
WFDint numberOfPorts = wfdEnumeratePorts(mDevice,0,0,0);
WFDint port_enumerations[numberOfPorts];
WFDint actualNumberOfPorts = wfdEnumeratePorts(mDevice,port_enumerations,numberOfPorts,WFD_NONE);
Q_ASSERT(actualNumberOfPorts == numberOfPorts);
for (int i = 0; i < actualNumberOfPorts; i++)
{
QOpenWFDPort *port = new QOpenWFDPort(this,port_enumerations[i]);
if (port->attached()) {
mPorts.append(port);
} else {
delete port;
}
}
int fd = wfdDeviceEventGetFD(mDevice,mEvent);
mEventSocketNotifier = new QSocketNotifier(fd,QSocketNotifier::Read,this);
connect(mEventSocketNotifier,SIGNAL(activated(QSocketDescriptor)),SLOT(readEvents()));
mCommitedDevice = true;
commit(WFD_COMMIT_ENTIRE_DEVICE, handle());
}
QOpenWFDDevice::~QOpenWFDDevice()
{
delete mEventSocketNotifier;
wfdDestroyEvent(mDevice,mEvent);
for (int i = 0; i < mPorts.size(); i++) {
//probably don't need to remove them from the list
QList <WFDint> keys = mUsedPipelines.keys(mPorts.at(i));
for (int keyIndex = 0; keyIndex < keys.size(); keyIndex++) {
mUsedPipelines.remove(keys.at(keyIndex));
}
//but we have to delete them :)
delete mPorts[i];
}
eglDestroyContext(mEglDisplay,mEglContext);
eglTerminate(mEglDisplay);
gbm_device_destroy(mGbmDevice);
wfdDestroyDevice(mDevice);
}
WFDDevice QOpenWFDDevice::handle() const
{
return mDevice;
}
QOpenWFDIntegration * QOpenWFDDevice::integration() const
{
return mIntegration;
}
bool QOpenWFDDevice::isPipelineUsed(WFDint pipelineId)
{
return mUsedPipelines.contains(pipelineId);
}
void QOpenWFDDevice::addToUsedPipelineSet(WFDint pipelineId,QOpenWFDPort *port)
{
mUsedPipelines.insert(pipelineId,port);
}
void QOpenWFDDevice::removeFromUsedPipelineSet(WFDint pipelineId)
{
mUsedPipelines.remove(pipelineId);
}
gbm_device * QOpenWFDDevice::gbmDevice() const
{
return mGbmDevice;
}
EGLDisplay QOpenWFDDevice::eglDisplay() const
{
return mEglDisplay;
}
EGLContext QOpenWFDDevice::eglContext() const
{
return mEglContext;
}
void QOpenWFDDevice::commit(WFDCommitType type, WFDHandle handle)
{
if (mCommitedDevice) {
wfdDeviceCommit(mDevice,type,handle);
}
}
void QOpenWFDDevice::waitForPipelineBindSourceCompleteEvent()
{
mWaitingForBindSourceEvent = true;
while (mWaitingForBindSourceEvent) {
readEvents(WFD_FOREVER);
}
}
void QOpenWFDDevice::readEvents(WFDtime wait)
{
WFDEventType type = wfdDeviceEventWait(mDevice,mEvent,wait);
if (type == WFD_EVENT_NONE || type == WFD_EVENT_DESTROYED) {
return;
}
switch (type) {
case WFD_EVENT_INVALID:
case WFD_EVENT_NONE:
return;
case WFD_EVENT_DESTROYED:
qDebug("Event or Device destoryed!");
return;
case WFD_EVENT_PORT_ATTACH_DETACH:
handlePortAttachDetach();
break;
case WFD_EVENT_PORT_PROTECTION_FAILURE:
qDebug("Port protection event handling not implemented");
break;
case WFD_EVENT_PIPELINE_BIND_SOURCE_COMPLETE:
handlePipelineBindSourceComplete();
break;
case WFD_EVENT_PIPELINE_BIND_MASK_COMPLETE:
qDebug("Pipeline bind mask event handling not implemented");
break;
default:
qDebug("Unrecognized event type: %lu", static_cast<long unsigned int>(type));
break;
}
}
void QOpenWFDDevice::initializeGbmAndEgl()
{
qDebug("initializing GBM and EGL");
int fd = wfdGetDeviceAttribi(mDevice,WFD_DEVICE_ID);
if (fd < 0) {
qDebug("failed to get WFD_DEVICE_ID");
}
mGbmDevice = gbm_create_device(fd);
setenv("EGL_PLATFORM", "drm",1);
mEglDisplay = eglGetDisplay(mGbmDevice);
EGLint minor, major;
if (!eglInitialize(mEglDisplay,&major,&minor)) {
qDebug("failed to initialize egl");
}
QByteArray eglExtensions = eglQueryString(mEglDisplay, EGL_EXTENSIONS);
if (!eglExtensions.contains("EGL_KHR_surfaceless_opengl")) {
qDebug("This egl implementation does not have the required EGL extension EGL_KHR_surfaceless_opengl");
}
eglBindAPI(EGL_OPENGL_ES_API);
EGLint contextAttribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
mEglContext = eglCreateContext(mEglDisplay,NULL,EGL_NO_CONTEXT,contextAttribs);
if (mEglContext == EGL_NO_CONTEXT) {
qDebug("Failed to create EGL context");
}
eglCreateImage = (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress("eglCreateImageKHR");
if (!eglCreateImage) {
qWarning("failed to load extension eglCreateImageKHR");
}
eglDestroyImage = (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress("eglDestroyImageKHR");
if (!eglDestroyImage) {
qWarning("failed to load extension eglDestoryImageKHR");
}
glEglImageTargetRenderBufferStorage = (PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) eglGetProcAddress("glEGLImageTargetRenderbufferStorageOES");
if (!glEglImageTargetRenderBufferStorage) {
qWarning("failed to load extension glEGLImageTargetRenderbufferStorageOES");
}
}
void QOpenWFDDevice::handlePortAttachDetach()
{
WFDint id = wfdGetEventAttribi(mDevice,mEvent,WFD_EVENT_PORT_ATTACH_PORT_ID);
if (id == WFD_INVALID_PORT_ID)
return;
WFDint attachState = wfdGetEventAttribi(mDevice,mEvent,WFD_EVENT_PORT_ATTACH_STATE);
if (attachState == WFD_TRUE) {
int indexToAdd = -1;
for (int i = 0; i < mPorts.size(); i++) {
if (mPorts.at(i)->portId() == id) {
indexToAdd = i;
qDebug("found index to attach");
break;
}
}
if (indexToAdd >= 0) {
mPorts[indexToAdd]->attach();
} else {
mPorts.append(new QOpenWFDPort(this,id));
}
} else {
int indexToDelete = -1;
for (int i = 0; i < mPorts.size(); i++) {
if (mPorts.at(i)->portId() == id) {
indexToDelete = i;
break;
}
}
if (indexToDelete >= 0) {
QOpenWFDPort *portToDelete = mPorts.at(indexToDelete);
mPorts.removeAt(indexToDelete);
delete portToDelete;
}
}
}
void QOpenWFDDevice::handlePipelineBindSourceComplete()
{
mWaitingForBindSourceEvent = false;
WFDint overflow = wfdGetEventAttribi(mDevice,mEvent, WFD_EVENT_PIPELINE_BIND_QUEUE_OVERFLOW);
if (overflow == WFD_TRUE) {
qDebug("PIPELINE_BIND_QUEUE_OVERFLOW event occurred");
}
WFDint pipelineId = wfdGetEventAttribi(mDevice,mEvent,WFD_EVENT_PIPELINE_BIND_PIPELINE_ID);
for (int i = 0; i < mPorts.size(); i++) {
if (pipelineId != WFD_INVALID_PIPELINE_ID && mUsedPipelines.contains(pipelineId)) {
QOpenWFDPort *port = mUsedPipelines.value(pipelineId);
port->screen()->pipelineBindSourceComplete();
break;
}
}
}