summaryrefslogtreecommitdiffstats
path: root/src/plugins/qnx/common/windowgrabber.cpp
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2016-05-10 19:26:21 +0200
committerLiang Qi <liang.qi@qt.io>2016-05-10 19:26:21 +0200
commit08e13bfcdb23eabfbc47bca7499b0b8aadce0ac7 (patch)
tree406ffa7e3ae0a346a14175ccccb8ac7e596d8f8f /src/plugins/qnx/common/windowgrabber.cpp
parentfa9fe9ff8c3aba25fbae4f8f32588dd6477d6df8 (diff)
parentf0e0d5d901d4e28fff9f29caf86ada84906b3db4 (diff)
Merge remote-tracking branch 'origin/5.6' into 5.7
Conflicts: src/plugins/winrt/qwinrtcameracontrol.cpp Change-Id: I45d3042adf19577a72794610fa1c310cb22e26c4
Diffstat (limited to 'src/plugins/qnx/common/windowgrabber.cpp')
-rw-r--r--src/plugins/qnx/common/windowgrabber.cpp362
1 files changed, 178 insertions, 184 deletions
diff --git a/src/plugins/qnx/common/windowgrabber.cpp b/src/plugins/qnx/common/windowgrabber.cpp
index ce5b45298..ca7224a4f 100644
--- a/src/plugins/qnx/common/windowgrabber.cpp
+++ b/src/plugins/qnx/common/windowgrabber.cpp
@@ -43,47 +43,50 @@
#include <QDebug>
#include <QGuiApplication>
#include <QImage>
+#include <QThread>
#include <qpa/qplatformnativeinterface.h>
#include <QOpenGLContext>
#include <QOpenGLFunctions>
-#ifdef Q_OS_BLACKBERRY
-#include <bps/event.h>
-#include <bps/screen.h>
-#endif
#include <errno.h>
QT_BEGIN_NAMESPACE
+static PFNEGLCREATEIMAGEKHRPROC s_eglCreateImageKHR;
+static PFNEGLDESTROYIMAGEKHRPROC s_eglDestroyImageKHR;
+
WindowGrabber::WindowGrabber(QObject *parent)
: QObject(parent),
- m_screenBufferWidth(-1),
- m_screenBufferHeight(-1),
+ m_screenContext(0),
m_active(false),
- m_screenContextInitialized(false),
- m_screenPixmapBuffersInitialized(false),
m_currentFrame(0),
m_eglImageSupported(false),
- m_eglImagesInitialized(false),
m_eglImageCheck(false)
{
// grab the window frame with 60 frames per second
m_timer.setInterval(1000/60);
- connect(&m_timer, SIGNAL(timeout()), SLOT(grab()));
+ connect(&m_timer, SIGNAL(timeout()), SLOT(triggerUpdate()));
QCoreApplication::eventDispatcher()->installNativeEventFilter(this);
+
+ for ( int i = 0; i < 2; ++i )
+ m_images[i] = 0;
+
+ // Use of EGL images can be disabled by setting QQNX_MM_DISABLE_EGLIMAGE_SUPPORT to something
+ // non-zero. This is probably useful only to test that this path still works since it results
+ // in a high CPU load.
+ if (!s_eglCreateImageKHR && qgetenv("QQNX_MM_DISABLE_EGLIMAGE_SUPPORT").toInt() == 0) {
+ s_eglCreateImageKHR = reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(eglGetProcAddress("eglCreateImageKHR"));
+ s_eglDestroyImageKHR = reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>(eglGetProcAddress("eglDestroyImageKHR"));
+ }
}
WindowGrabber::~WindowGrabber()
{
QCoreApplication::eventDispatcher()->removeNativeEventFilter(this);
- if (eglImagesInitialized()) {
- glDeleteTextures(2, imgTextures);
- eglDestroyImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), img[0]);
- eglDestroyImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), img[1]);
- }
+ cleanup();
}
void WindowGrabber::setFrameRate(int frameRate)
@@ -91,36 +94,6 @@ void WindowGrabber::setFrameRate(int frameRate)
m_timer.setInterval(1000/frameRate);
}
-void WindowGrabber::createEglImages()
-{
- // Do nothing if either egl images are not supported, the screen context is not valid
- // or the images are already created
- if (!eglImageSupported() || !m_screenContextInitialized || eglImagesInitialized())
- return;
-
- glGenTextures(2, imgTextures);
- glBindTexture(GL_TEXTURE_2D, imgTextures[0]);
- img[0] = eglCreateImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), EGL_NO_CONTEXT,
- EGL_NATIVE_PIXMAP_KHR,
- m_screenPixmaps[0],
- 0);
- glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, img[0]);
-
- glBindTexture(GL_TEXTURE_2D, imgTextures[1]);
- img[1] = eglCreateImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), EGL_NO_CONTEXT,
- EGL_NATIVE_PIXMAP_KHR,
- m_screenPixmaps[1],
- 0);
-
- glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, img[1]);
-
- if (img[0] == 0 || img[1] == 0) {
- qWarning() << "Failed to create KHR images" << img[0] << img[1] << strerror(errno) << errno;
- m_eglImageSupported = false;
- } else {
- m_eglImagesInitialized = true;
- }
-}
void WindowGrabber::setWindowId(const QByteArray &windowId)
{
@@ -132,107 +105,14 @@ void WindowGrabber::start()
if (m_active)
return;
- int result = 0;
-
- result = screen_create_context(&m_screenContext, SCREEN_APPLICATION_CONTEXT);
- if (result != 0) {
- qWarning() << "WindowGrabber: cannot create screen context:" << strerror(errno);
- return;
- } else {
- m_screenContextInitialized = true;
- }
-
- result = screen_create_pixmap(&m_screenPixmaps[0], m_screenContext);
- result = screen_create_pixmap(&m_screenPixmaps[1], m_screenContext);
- if (result != 0) {
- cleanup();
- qWarning() << "WindowGrabber: cannot create pixmaps:" << strerror(errno);
- return;
- }
-
- const int usage = SCREEN_USAGE_NATIVE;
- result = screen_set_pixmap_property_iv(m_screenPixmaps[0], SCREEN_PROPERTY_USAGE, &usage);
- result |= screen_set_pixmap_property_iv(m_screenPixmaps[1], SCREEN_PROPERTY_USAGE, &usage);
-
- const int format = SCREEN_FORMAT_RGBX8888;
- screen_set_pixmap_property_iv(m_screenPixmaps[0], SCREEN_PROPERTY_FORMAT, &format);
- screen_set_pixmap_property_iv(m_screenPixmaps[1], SCREEN_PROPERTY_FORMAT, &format);
-
- int size[2] = { 0, 0 };
-
- result = screen_get_window_property_iv(m_window, SCREEN_PROPERTY_SOURCE_SIZE, size);
- if (result != 0) {
- cleanup();
- qWarning() << "WindowGrabber: cannot get window size:" << strerror(errno);
- return;
- }
-
- m_screenBufferWidth = size[0];
- m_screenBufferHeight = size[1];
-
- updateFrameSize();
+ if (!m_screenContext)
+ screen_get_window_property_pv(m_window, SCREEN_PROPERTY_CONTEXT, reinterpret_cast<void**>(&m_screenContext));
m_timer.start();
m_active = true;
}
-void WindowGrabber::updateFrameSize()
-{
- int size[2] = { m_screenBufferWidth, m_screenBufferHeight };
-
- screen_set_pixmap_property_iv(m_screenPixmaps[0], SCREEN_PROPERTY_BUFFER_SIZE, size);
- if (eglImageSupported())
- screen_set_pixmap_property_iv(m_screenPixmaps[1], SCREEN_PROPERTY_BUFFER_SIZE, size);
-
- int result = screen_create_pixmap_buffer(m_screenPixmaps[0]);
- if (eglImageSupported())
- result |= screen_create_pixmap_buffer(m_screenPixmaps[1]);
-
- if (result != 0) {
- cleanup();
- qWarning() << "WindowGrabber: cannot create pixmap buffer:" << strerror(errno);
- return;
- } else {
- m_screenPixmapBuffersInitialized = true;
- }
-
- result = screen_get_pixmap_property_pv(m_screenPixmaps[0], SCREEN_PROPERTY_RENDER_BUFFERS,
- (void**)&m_screenPixmapBuffers[0]);
- if (eglImageSupported()) {
- result |= screen_get_pixmap_property_pv(m_screenPixmaps[1], SCREEN_PROPERTY_RENDER_BUFFERS,
- (void**)&m_screenPixmapBuffers[1]);
- }
-
- if (result != 0) {
- cleanup();
- qWarning() << "WindowGrabber: cannot get pixmap buffer:" << strerror(errno);
- return;
- }
-
- result = screen_get_buffer_property_pv(m_screenPixmapBuffers[0], SCREEN_PROPERTY_POINTER,
- (void**)&m_screenBuffers[0]);
- if (eglImageSupported()) {
- result |= screen_get_buffer_property_pv(m_screenPixmapBuffers[1], SCREEN_PROPERTY_POINTER,
- (void**)&m_screenBuffers[1]);
- }
-
- if (result != 0) {
- cleanup();
- qWarning() << "WindowGrabber: cannot get pixmap buffer pointer:" << strerror(errno);
- return;
- }
-
- result = screen_get_buffer_property_iv(m_screenPixmapBuffers[0], SCREEN_PROPERTY_STRIDE,
- &m_screenBufferStride);
-
- if (result != 0) {
- cleanup();
- qWarning() << "WindowGrabber: cannot get pixmap buffer stride:" << strerror(errno);
- return;
- }
-}
-
void WindowGrabber::stop()
{
if (!m_active)
@@ -294,20 +174,10 @@ bool WindowGrabber::handleScreenEvent(screen_event_t screen_event)
bool WindowGrabber::nativeEventFilter(const QByteArray &eventType, void *message, long*)
{
-#ifdef Q_OS_BLACKBERRY
- Q_UNUSED(eventType)
- bps_event_t * const event = static_cast<bps_event_t *>(message);
-
- if (event && bps_event_get_domain(event) == screen_get_domain()) {
- const screen_event_t screen_event = screen_event_get_event(event);
- return handleScreenEvent(screen_event);
- }
-#else
if (eventType == "screen_event_t") {
const screen_event_t event = static_cast<screen_event_t>(message);
return handleScreenEvent(event);
}
-#endif
return false;
}
@@ -348,7 +218,8 @@ void WindowGrabber::checkForEglImageExtension()
QByteArray eglExtensions = QByteArray(eglQueryString(eglGetDisplay(EGL_DEFAULT_DISPLAY),
EGL_EXTENSIONS));
m_eglImageSupported = m_context->hasExtension(QByteArrayLiteral("GL_OES_EGL_image"))
- && eglExtensions.contains(QByteArrayLiteral("EGL_KHR_image"));
+ && eglExtensions.contains(QByteArrayLiteral("EGL_KHR_image"))
+ && s_eglCreateImageKHR && s_eglDestroyImageKHR;
if (strstr(reinterpret_cast<const char*>(glGetString(GL_VENDOR)), "VMware"))
m_eglImageSupported = false;
@@ -356,21 +227,11 @@ void WindowGrabber::checkForEglImageExtension()
m_eglImageCheck = true;
}
-bool WindowGrabber::eglImagesInitialized()
-{
- return m_eglImagesInitialized;
-}
-
-void WindowGrabber::grab()
+void WindowGrabber::triggerUpdate()
{
if (!m_eglImageCheck) // We did not check for egl images yet
return;
- if (eglImageSupported())
- m_currentFrame = (m_currentFrame + 1) % 2;
- else
- m_currentFrame = 0;
-
int size[2] = { 0, 0 };
int result = screen_get_window_property_iv(m_window, SCREEN_PROPERTY_SOURCE_SIZE, size);
@@ -380,40 +241,173 @@ void WindowGrabber::grab()
return;
}
- if (m_screenBufferWidth != size[0] || m_screenBufferHeight != size[1]) {
- // The source viewport size changed, so we have to adapt our buffers
+ if (m_size.width() != size[0] || m_size.height() != size[1])
+ m_size = QSize(size[0], size[1]);
- if (m_screenPixmapBuffersInitialized) {
- screen_destroy_pixmap_buffer(m_screenPixmaps[0]);
- if (eglImageSupported())
- screen_destroy_pixmap_buffer(m_screenPixmaps[1]);
- }
+ emit updateScene(m_size);
+}
- m_screenBufferWidth = size[0];
- m_screenBufferHeight = size[1];
+bool WindowGrabber::selectBuffer()
+{
+ // If we're using egl images we need to double buffer since the gpu may still be using the last
+ // video frame. If we're not, it doesn't matter since the data is immediately copied.
+ if (eglImageSupported())
+ m_currentFrame = (m_currentFrame + 1) % 2;
- updateFrameSize();
- m_eglImagesInitialized = false;
+ if (!m_images[m_currentFrame]) {
+ m_images[m_currentFrame] = new WindowGrabberImage();
+ if (!m_images[m_currentFrame]->initialize(m_screenContext)) {
+ delete m_images[m_currentFrame];
+ m_images[m_currentFrame] = 0;
+ return false;
+ }
}
+ return true;
+}
- const int rect[] = { 0, 0, m_screenBufferWidth, m_screenBufferHeight };
- result = screen_read_window(m_window, m_screenPixmapBuffers[m_currentFrame], 1, rect, 0);
- if (result != 0)
- return;
+int WindowGrabber::getNextTextureId()
+{
+ if (!selectBuffer())
+ return 0;
+ return m_images[m_currentFrame]->getTexture(m_window, m_size);
+}
- const QImage frame((unsigned char*)m_screenBuffers[m_currentFrame], m_screenBufferWidth,
- m_screenBufferHeight, m_screenBufferStride, QImage::Format_ARGB32);
+QImage WindowGrabber::getNextImage()
+{
+ if (!selectBuffer())
+ return QImage();
- emit frameGrabbed(frame, imgTextures[m_currentFrame]);
+ return m_images[m_currentFrame]->getImage(m_window, m_size);
}
void WindowGrabber::cleanup()
{
- //We only need to destroy the context as it frees all resources associated with it
- if (m_screenContextInitialized) {
- screen_destroy_context(m_screenContext);
- m_screenContextInitialized = false;
+ for ( int i = 0; i < 2; ++i ) {
+ if (m_images[i]) {
+ m_images[i]->destroy();
+ m_images[i] = 0;
+ }
+ }
+}
+
+
+WindowGrabberImage::WindowGrabberImage()
+ : m_pixmap(0), m_pixmapBuffer(0), m_eglImage(0), m_glTexture(0), m_bufferAddress(0), m_bufferStride(0)
+{
+}
+
+WindowGrabberImage::~WindowGrabberImage()
+{
+ if (m_glTexture)
+ glDeleteTextures(1, &m_glTexture);
+ if (m_eglImage)
+ s_eglDestroyImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), m_eglImage);
+ if (m_pixmap)
+ screen_destroy_pixmap(m_pixmap);
+}
+
+bool
+WindowGrabberImage::initialize(screen_context_t screenContext)
+{
+ if (screen_create_pixmap(&m_pixmap, screenContext) != 0) {
+ qWarning() << "WindowGrabber: cannot create pixmap:" << strerror(errno);
+ return false;
+ }
+ const int usage = SCREEN_USAGE_WRITE | SCREEN_USAGE_READ | SCREEN_USAGE_NATIVE;
+ screen_set_pixmap_property_iv(m_pixmap, SCREEN_PROPERTY_USAGE, &usage);
+
+ const int format = SCREEN_FORMAT_RGBX8888;
+ screen_set_pixmap_property_iv(m_pixmap, SCREEN_PROPERTY_FORMAT, &format);
+
+ return true;
+}
+
+void
+WindowGrabberImage::destroy()
+{
+ // We want to delete in the thread we were created in since we need the thread that
+ // has called eglMakeCurrent on the right EGL context. This doesn't actually guarantee
+ // this but that would be hard to achieve and in practice it works.
+ if (QThread::currentThread() == thread())
+ delete this;
+ else
+ deleteLater();
+}
+
+bool
+WindowGrabberImage::resize(const QSize &newSize)
+{
+ if (m_pixmapBuffer) {
+ screen_destroy_pixmap_buffer(m_pixmap);
+ m_pixmapBuffer = 0;
+ m_bufferAddress = 0;
+ m_bufferStride = 0;
+ }
+
+ int size[2] = { newSize.width(), newSize.height() };
+
+ screen_set_pixmap_property_iv(m_pixmap, SCREEN_PROPERTY_BUFFER_SIZE, size);
+
+ if (screen_create_pixmap_buffer(m_pixmap) == 0) {
+ screen_get_pixmap_property_pv(m_pixmap, SCREEN_PROPERTY_RENDER_BUFFERS,
+ reinterpret_cast<void**>(&m_pixmapBuffer));
+ screen_get_buffer_property_pv(m_pixmapBuffer, SCREEN_PROPERTY_POINTER,
+ reinterpret_cast<void**>(&m_bufferAddress));
+ screen_get_buffer_property_iv(m_pixmapBuffer, SCREEN_PROPERTY_STRIDE, &m_bufferStride);
+ m_size = newSize;
+
+ return true;
+ } else {
+ m_size = QSize();
+ return false;
}
}
+bool
+WindowGrabberImage::grab(screen_window_t window)
+{
+ const int rect[] = { 0, 0, m_size.width(), m_size.height() };
+ return screen_read_window(window, m_pixmapBuffer, 1, rect, 0) == 0;
+}
+
+QImage
+WindowGrabberImage::getImage(screen_window_t window, const QSize &size)
+{
+ if (size != m_size) {
+ if (!resize(size))
+ return QImage();
+ }
+ if (!m_bufferAddress || !grab(window))
+ return QImage();
+
+ return QImage(m_bufferAddress, m_size.width(), m_size.height(), m_bufferStride, QImage::Format_ARGB32);
+}
+
+GLuint
+WindowGrabberImage::getTexture(screen_window_t window, const QSize &size)
+{
+ if (size != m_size) {
+ if (!m_glTexture)
+ glGenTextures(1, &m_glTexture);
+ glBindTexture(GL_TEXTURE_2D, m_glTexture);
+ if (m_eglImage) {
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, 0);
+ s_eglDestroyImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), m_eglImage);
+ m_eglImage = 0;
+ }
+ if (!resize(size))
+ return 0;
+ m_eglImage = s_eglCreateImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), EGL_NO_CONTEXT,
+ EGL_NATIVE_PIXMAP_KHR, m_pixmap, 0);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_eglImage);
+ }
+
+ if (!m_pixmap || !grab(window))
+ return 0;
+
+ return m_glTexture;
+}
+
+
+
QT_END_NAMESPACE