/**************************************************************************** ** ** 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 #include #include 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(int)),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 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(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; } } }