/*! \reimp Connects to QNX's io-display based device based on the \a displaySpec parameters from the \c{QWS_DISPLAY} environment variable. See the QQnxScreen class documentation for possible parameters. \sa QQnxScreen */ bool QQnxScreen::connect(const QString &displaySpec) { const QStringList params = displaySpec.split(QLatin1Char(':'), QString::SkipEmptyParts); bool isOk = false; QRegExp deviceRegExp(QLatin1String("^device=(.+)$")); if (params.indexOf(deviceRegExp) != -1) { isOk = attachDevice(d, deviceRegExp.cap(1).toLocal8Bit().constData()); } else { // no device specified - attach to device 0 (the default) isOk = attachDevice(d, GF_DEVICE_INDEX(0)); } if (!isOk) return false; qDebug("QQnxScreen: Attached to Device, number of displays: %d", d->deviceInfo.ndisplays); // default to display 0 int displayIndex = 0; QRegExp displayRegexp(QLatin1String("^display=(\\d+)$")); if (params.indexOf(displayRegexp) != -1) { displayIndex = displayRegexp.cap(1).toInt(); } if (!attachDisplay(d, displayIndex)) return false; qDebug("QQnxScreen: Attached to Display %d, resolution %dx%d, refresh %d Hz", displayIndex, d->displayInfo.xres, d->displayInfo.yres, d->displayInfo.refresh); // default to main_layer_index from the displayInfo struct int layerIndex = 0; QRegExp layerRegexp(QLatin1String("^layer=(\\d+)$")); if (params.indexOf(layerRegexp) != -1) { layerIndex = layerRegexp.cap(1).toInt(); } else { layerIndex = d->displayInfo.main_layer_index; } if (!attachLayer(d, layerIndex)) return false; // tell QWSDisplay the width and height of the display w = dw = d->displayInfo.xres; h = dh = d->displayInfo.yres; // we only support 32 bit displays for now. QScreen::d = 32; // assume 72 dpi as default, to calculate the physical dimensions if not specified const int defaultDpi = 72; // Handle display physical size spec. QRegExp mmWidthRegexp(QLatin1String("^mmWidth=(\\d+)$")); if (params.indexOf(mmWidthRegexp) == -1) { physWidth = qRound(dw * 25.4 / defaultDpi); } else { physWidth = mmWidthRegexp.cap(1).toInt(); } QRegExp mmHeightRegexp(QLatin1String("^mmHeight=(\\d+)$")); if (params.indexOf(mmHeightRegexp) == -1) { physHeight = qRound(dh * 25.4 / defaultDpi); } else { physHeight = mmHeightRegexp.cap(1).toInt(); } // create a hardware surface with our dimensions. In the old days, it was possible // to get a pointer directly to the hw surface, so we could blit directly. Now, we // have to use one indirection more, because it's not guaranteed that the hw surface // is mappable into our process. if (!createHwSurface(d, w, h)) return false; // create an in-memory linear surface that is used by QWS. QWS will blit directly in here. if (!createMemSurface(d, w, h)) return false; // set the address of the in-memory buffer that QWS is blitting to data = d->memSurfaceInfo.vaddr; // set the line stepping lstep = d->memSurfaceInfo.stride; // the overall size of the in-memory buffer is linestep * height size = mapsize = lstep * h; // create a QNX drawing context if (!createContext(d)) return false; // we're always using a software cursor for now. Initialize it here. QScreenCursor::initSoftwareCursor(); // done, the driver should be connected to the display now. return true; }
VkBool32 VKTS_APIENTRY engineRun() { if (g_engineState != VKTS_ENGINE_INIT_STATE) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Not in initialize state."); return VK_FALSE; } if (engineGetNumberUpdateThreads() < VKTS_MIN_UPDATE_THREADS || engineGetNumberUpdateThreads() > VKTS_MAX_UPDATE_THREADS) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Number of update threads not correct."); return VK_FALSE; } // // Main thread gets all displays and windows attached. // const auto& displayList = _visualGetActiveDisplays(); for (size_t i = 0; i < displayList.size(); i++) { engineAttachDisplayToUpdateThread(displayList[i], g_allUpdateThreads[g_allUpdateThreads.size() - 1]); } const auto& windowList = _visualGetActiveWindows(); for (size_t i = 0; i < windowList.size(); i++) { engineAttachWindowToUpdateThread(windowList[i], g_allUpdateThreads[g_allUpdateThreads.size() - 1]); } // g_engineState = VKTS_ENGINE_UPDATE_STATE; logPrint(VKTS_LOG_INFO, "Engine: Started."); // Task queue creation. TaskQueueSP sendTaskQueue; TaskQueueSP executedTaskQueue; if (g_taskExecutorCount > 0) { sendTaskQueue = TaskQueueSP(new TaskQueue); if (!sendTaskQueue.get()) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create task queue."); return VK_FALSE; } executedTaskQueue = TaskQueueSP(new TaskQueue); if (!executedTaskQueue.get()) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create task queue."); return VK_FALSE; } } // Message dispatcher creation. MessageDispatcherSP messageDispatcher = MessageDispatcherSP(new MessageDispatcher()); if (!messageDispatcher.get()) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create message dispatcher."); return VK_FALSE; } // Object, needed for synchronizing the executors. ExecutorSync executorSync; // // Task executor creation and launching, // SmartPointerVector<TaskExecutorSP> realTaskExecutors; SmartPointerVector<ThreadSP> realTaskThreads; for (uint32_t i = 0; i < g_taskExecutorCount; i++) { auto currentTaskExecutor = TaskExecutorSP(new TaskExecutor(i, executorSync, sendTaskQueue, executedTaskQueue)); if (!currentTaskExecutor.get()) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create current task executor."); return VK_FALSE; } auto currentRealThread = ThreadSP(new std::thread(&TaskExecutor::run, currentTaskExecutor)); if (!currentRealThread.get()) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create current real thread."); return VK_FALSE; } // realTaskExecutors.append(currentTaskExecutor); realTaskThreads.append(currentRealThread); logPrint(VKTS_LOG_INFO, "Engine: Task %d started.", currentTaskExecutor->getIndex()); } // // Update Thread creation and launching. // UpdateThreadExecutorSP mainUpdateThreadExecutor; SmartPointerVector<UpdateThreadExecutorSP> realUpdateThreadExecutors; SmartPointerVector<ThreadSP> realUpdateThreads; int32_t index = 0; for (size_t updateThreadIndex = 0; updateThreadIndex < g_allUpdateThreads.size(); updateThreadIndex++) { const auto& currentUpdateThread = g_allUpdateThreads[updateThreadIndex]; // const auto currentMessageDispatcher = (index == engineGetNumberUpdateThreads() - 1) ? messageDispatcher : MessageDispatcherSP(); // auto currentUpdateThreadContext = UpdateThreadContextSP(new UpdateThreadContext((int32_t) updateThreadIndex, (int32_t) g_allUpdateThreads.size(), g_tickTime, sendTaskQueue, executedTaskQueue)); if (!currentUpdateThreadContext.get()) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create update thread context."); return VK_FALSE; } // for (auto currentDisplayWalker = g_allAttachedDisplays.lower_bound(currentUpdateThread); currentDisplayWalker != g_allAttachedDisplays.upper_bound(currentUpdateThread); currentDisplayWalker++) { currentUpdateThreadContext->attachDisplay(currentDisplayWalker->second); } // for (auto currentWindowWalker = g_allAttachedWindows.lower_bound(currentUpdateThread); currentWindowWalker != g_allAttachedWindows.upper_bound(currentUpdateThread); currentWindowWalker++) { currentUpdateThreadContext->attachWindow(currentWindowWalker->second); } // if (index == engineGetNumberUpdateThreads() - 1) { // Last thread is the main thread. mainUpdateThreadExecutor = UpdateThreadExecutorSP(new UpdateThreadExecutor(index, executorSync, currentUpdateThread, currentUpdateThreadContext, currentMessageDispatcher)); if (!mainUpdateThreadExecutor.get()) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create main update thread executor."); return VK_FALSE; } } else { // Receive queue is the threads send queue. auto currentUpdateThreadExecutor = UpdateThreadExecutorSP(new UpdateThreadExecutor(index, executorSync, currentUpdateThread, currentUpdateThreadContext, currentMessageDispatcher)); if (!currentUpdateThreadExecutor.get()) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create current update thread executor."); return VK_FALSE; } realUpdateThreadExecutors.append(currentUpdateThreadExecutor); logPrint(VKTS_LOG_INFO, "Engine: Thread %d started.", currentUpdateThreadExecutor->getIndex()); auto currentRealThread = ThreadSP(new std::thread(&UpdateThreadExecutor::run, currentUpdateThreadExecutor)); if (!currentRealThread.get()) { logPrint(VKTS_LOG_ERROR, "Engine: Run failed! Could not create current real thread."); return VK_FALSE; } realUpdateThreads.append(currentRealThread); } index++; } // Run last thread and loop. logPrint(VKTS_LOG_INFO, "Engine: Thread %d started.", mainUpdateThreadExecutor->getIndex()); mainUpdateThreadExecutor->run(); // // Stopping everything. // logPrint(VKTS_LOG_INFO, "Engine: Thread %d stopped.", mainUpdateThreadExecutor->getIndex()); // Wait for all threads to finish in the reverse order they were created. for (auto reverseIndex = static_cast<int32_t>(realUpdateThreads.size()) - 1; reverseIndex >= 0; reverseIndex--) { const auto& currentRealThread = realUpdateThreads[reverseIndex]; currentRealThread->join(); logPrint(VKTS_LOG_INFO, "Engine: Thread %d stopped.", reverseIndex); } realUpdateThreadExecutors.clear(); realUpdateThreads.clear(); // if (sendTaskQueue.get()) { // Empty the queue. // As no update thread can feed the queue anymore, it is save to call reset. sendTaskQueue->reset(); // ITaskSP stopTask; logPrint(VKTS_LOG_SEVERE, "Engine: Disabling task queue."); for (uint32_t i = 0; i < g_taskExecutorCount; i++) { // Send an empty task to the queue, to exit the thread. sendTaskQueue->addTask(stopTask); } } // Wait for all tasks to finish in the reverse order they were created. for (auto reverseIndex = static_cast<int32_t>(realTaskThreads.size()) - 1; reverseIndex >= 0; reverseIndex--) { const auto& currentRealThread = realTaskThreads[reverseIndex]; currentRealThread->join(); logPrint(VKTS_LOG_INFO, "Engine: Task %d stopped.", reverseIndex); } realTaskExecutors.clear(); realTaskThreads.clear(); // g_engineState = VKTS_ENGINE_INIT_STATE; logPrint(VKTS_LOG_INFO, "Engine: Stopped."); return VK_TRUE; }
/*! \reimp Connects to QNX's io-display based device based on the \a displaySpec parameters from the \c{QWS_DISPLAY} environment variable. See the QQnxScreen class documentation for possible parameters. \sa QQnxScreen */ bool QQnxScreen::connect(const QString &displaySpec) { const QStringList params = displaySpec.split(QLatin1Char(':'), QString::SkipEmptyParts); // default to device 0 int deviceIndex = 0; if (!params.isEmpty()) { QRegExp deviceRegExp(QLatin1String("^device=(.+)$")); if (params.indexOf(deviceRegExp) != -1) deviceIndex = deviceRegExp.cap(1).toInt(); } if (!attachDevice(d, GF_DEVICE_INDEX(deviceIndex))) return false; qDebug("QQnxScreen: Attached to Device, number of displays: %d", d->deviceInfo.ndisplays); // default to display id passed to constructor int displayIndex = displayId; if (!params.isEmpty()) { QRegExp displayRegexp(QLatin1String("^display=(\\d+)$")); if (params.indexOf(displayRegexp) != -1) displayIndex = displayRegexp.cap(1).toInt(); } if (!attachDisplay(d, displayIndex)) return false; qDebug("QQnxScreen: Attached to Display %d, resolution %dx%d, refresh %d Hz", displayIndex, d->displayInfo.xres, d->displayInfo.yres, d->displayInfo.refresh); // default to main_layer_index from the displayInfo struct int layerIndex = d->displayInfo.main_layer_index; if (!params.isEmpty()) { QRegExp layerRegexp(QLatin1String("^layer=(\\d+)$")); if (params.indexOf(layerRegexp) != -1) layerIndex = layerRegexp.cap(1).toInt(); } if (!attachLayer(d, layerIndex)) return false; // determine the pixel format and the pixel type switch (d->displayInfo.format) { #if defined(QT_QWS_DEPTH_32) || defined(QT_QWS_DEPTH_GENERIC) case GF_FORMAT_ARGB8888: pixeltype = QScreen::BGRPixel; // fall through case GF_FORMAT_BGRA8888: setPixelFormat(QImage::Format_ARGB32); break; #endif #if defined(QT_QWS_DEPTH_24) case GF_FORMAT_BGR888: pixeltype = QScreen::BGRPixel; setPixelFormat(QImage::Format_RGB888); break; #endif #if defined(QT_QWS_DEPTH_16) || defined(QT_QWS_DEPTH_GENERIC) case GF_FORMAT_PACK_RGB565: case GF_FORMAT_PKLE_RGB565: case GF_FORMAT_PKBE_RGB565: #if Q_BYTE_ORDER == Q_BIG_ENDIAN setFrameBufferLittleEndian((d->displayInfo.format & GF_FORMAT_PKLE) == GF_FORMAT_PKLE); #endif setPixelFormat(QImage::Format_RGB16); break; #endif default: return false; } // tell QWSDisplay the width and height of the display w = dw = d->displayInfo.xres; h = dh = d->displayInfo.yres; QScreen::d = (d->displayInfo.format & GF_FORMAT_BPP); // colour depth // assume 72 dpi as default, to calculate the physical dimensions if not specified const int defaultDpi = 72; // Handle display physical size physWidth = qRound(dw * 25.4 / defaultDpi); physHeight = qRound(dh * 25.4 / defaultDpi); if (!params.isEmpty()) { QRegExp mmWidthRegexp(QLatin1String("^mmWidth=(\\d+)$")); if (params.indexOf(mmWidthRegexp) != -1) physWidth = mmWidthRegexp.cap(1).toInt(); QRegExp mmHeightRegexp(QLatin1String("^mmHeight=(\\d+)$")); if (params.indexOf(mmHeightRegexp) != -1) physHeight = mmHeightRegexp.cap(1).toInt(); } if (QApplication::type() == QApplication::GuiServer) { // create a hardware surface with our dimensions. In the old days, it was possible // to get a pointer directly to the hw surface, so we could blit directly. Now, we // have to use one indirection more, because it's not guaranteed that the hw surface // is mappable into our process. if (!createHwSurface(d, w, h)) return false; } // create an in-memory linear surface that is used by QWS. QWS will blit directly in here. if (!createMemSurface(d, w, h)) return false; // set the address of the in-memory buffer that QWS is blitting to data = d->memSurfaceInfo.vaddr; // set the line stepping lstep = d->memSurfaceInfo.stride; // the overall size of the in-memory buffer is linestep * height size = mapsize = lstep * h; // done, the driver should be connected to the display now. return true; }