Move qt_cam_copy_register to QtCamera
[harmattan/cameraplus] / lib / qtcamviewfinderrenderermeego.cpp
index 95f8959..8b3efac 100644 (file)
@@ -1,7 +1,7 @@
 /*!
  * This file is part of CameraPlus.
  *
- * Copyright (C) 2012 Mohammed Sameer <msameer@foolab.org>
+ * Copyright (C) 2012-2013 Mohammed Sameer <msameer@foolab.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -25,7 +25,6 @@
 #include "qtcamconfig.h"
 #include <QX11Info>
 #include <QGLContext>
-#include <EGL/egl.h>
 #include <QGLShaderProgram>
 #include <gst/interfaces/meegovideotexture.h>
 
@@ -33,6 +32,14 @@ QT_CAM_VIEWFINDER_RENDERER(RENDERER_TYPE_MEEGO, QtCamViewfinderRendererMeeGo);
 
 #define GL_TEXTURE_EXTERNAL_OES                  0x8060
 
+typedef void *EGLSyncKHR;
+#define EGL_SYNC_FENCE_KHR                       0x30F9
+
+typedef EGLSyncKHR(EGLAPIENTRYP _PFNEGLCREATESYNCKHRPROC)(EGLDisplay dpy, EGLenum type,
+                                                         const EGLint *attrib_list);
+
+_PFNEGLCREATESYNCKHRPROC eglCreateSyncKHR = 0;
+
 static const QString FRAGMENT_SHADER = ""
     "#extension GL_OES_EGL_image_external: enable\n"
     "uniform samplerExternalOES texture0;"
@@ -56,7 +63,7 @@ static const QString VERTEX_SHADER = ""
   "";
 
 QtCamViewfinderRendererMeeGo::QtCamViewfinderRendererMeeGo(QtCamConfig *config,
-                                                              QObject *parent) :
+                                                          QObject *parent) :
   QtCamViewfinderRenderer(config, parent),
   m_conf(config),
   m_sink(0),
@@ -85,16 +92,27 @@ QtCamViewfinderRendererMeeGo::~QtCamViewfinderRendererMeeGo() {
   }
 }
 
-void QtCamViewfinderRendererMeeGo::paint(QPainter *painter) {
+bool QtCamViewfinderRendererMeeGo::needsNativePainting() {
+  return true;
+}
+
+void QtCamViewfinderRendererMeeGo::paint(const QMatrix4x4& matrix, const QRectF& viewport) {
   QMutexLocker locker(&m_frameMutex);
   if (m_frame == -1) {
     return;
   }
 
-  painter->beginNativePainting();
-
   if (m_needsInit) {
-    calculateProjectionMatrix(painter->viewport());
+    calculateProjectionMatrix(viewport);
+
+    if (!eglCreateSyncKHR && m_conf->viewfinderUseFence()) {
+      eglCreateSyncKHR = (_PFNEGLCREATESYNCKHRPROC)eglGetProcAddress("eglCreateSyncKHR");
+
+      if (!eglCreateSyncKHR) {
+       qWarning() << "eglCreateSyncKHR not found. Fences disabled";
+      }
+    }
+
     m_needsInit = false;
   }
 
@@ -104,9 +122,7 @@ void QtCamViewfinderRendererMeeGo::paint(QPainter *painter) {
     createProgram();
   }
 
-  paintFrame(painter, m_frame);
-
-  painter->endNativePainting();
+  paintFrame(matrix, m_frame);
 }
 
 void QtCamViewfinderRendererMeeGo::resize(const QSizeF& size) {
@@ -120,9 +136,11 @@ void QtCamViewfinderRendererMeeGo::resize(const QSizeF& size) {
 
   calculateCoords();
 
-  // TODO: this will destroy everything
+  // This will destroy everything
   // but we need a way to reset the viewport and the transformation matrix only.
   m_needsInit = true;
+
+  emit renderAreaChanged();
 }
 
 void QtCamViewfinderRendererMeeGo::reset() {
@@ -137,7 +155,7 @@ GstElement *QtCamViewfinderRendererMeeGo::sinkElement() {
   }
 
   if (!m_sink) {
-    m_sink = gst_element_factory_make(m_conf->viewfinderSink().toAscii().data(),
+    m_sink = gst_element_factory_make(m_conf->viewfinderSink().toLatin1().data(),
                                      "QtCamViewfinderRendererMeeGoSink");
     if (!m_sink) {
       qCritical() << "Failed to create" << m_conf->viewfinderSink();
@@ -147,16 +165,20 @@ GstElement *QtCamViewfinderRendererMeeGo::sinkElement() {
     g_object_add_toggle_ref(G_OBJECT(m_sink), (GToggleNotify)sink_notify, this);
   }
 
-  // Displa can be replaced with a null pointer.
-  // We all know that the sink used for Harmattan ignores the x-display property ;-)
-
   Display *d = QX11Info::display();
   g_object_set(G_OBJECT(m_sink), "x-display", d, "use-framebuffer-memory", TRUE, NULL);
 
-  EGLDisplay dpy = eglGetDisplay((EGLNativeDisplayType)d);
+  m_dpy = eglGetDisplay((EGLNativeDisplayType)d);
+  if (m_dpy == EGL_NO_DISPLAY) {
+    qCritical() << "Failed to obtain EGL Display";
+  }
+
   EGLContext context = eglGetCurrentContext();
+  if (context == EGL_NO_CONTEXT) {
+    qCritical() << "Failed to obtain EGL context";
+  }
 
-  g_object_set(G_OBJECT(m_sink), "egl-display", dpy, "egl-context", context, NULL);
+  g_object_set(G_OBJECT(m_sink), "egl-display", m_dpy, "egl-context", context, NULL);
 
   m_id = g_signal_connect(G_OBJECT(m_sink), "frame-ready", G_CALLBACK(frame_ready), this);
 
@@ -183,6 +205,8 @@ void QtCamViewfinderRendererMeeGo::frame_ready(GstElement *sink, int frame,
 void QtCamViewfinderRendererMeeGo::sink_notify(QtCamViewfinderRendererMeeGo *q,
                                               GObject *object, gboolean is_last_ref) {
 
+  Q_UNUSED(object);
+
   if (is_last_ref) {
     g_signal_handler_disconnect(q->m_sink, q->m_id);
     g_object_remove_toggle_ref(G_OBJECT(q->m_sink), (GToggleNotify)sink_notify, q);
@@ -196,7 +220,7 @@ void QtCamViewfinderRendererMeeGo::sink_caps_changed(GObject *obj, GParamSpec *p
   Q_UNUSED(pspec);
 
   int width, height;
-  if (obj && gst_video_get_size  (GST_PAD(obj), &width, &height)) {
+  if (obj && gst_video_get_size(GST_PAD(obj), &width, &height)) {
     QMetaObject::invokeMethod(q, "setVideoSize", Qt::QueuedConnection,
                              Q_ARG(QSizeF, QSizeF(width, height)));
   }
@@ -241,13 +265,13 @@ void QtCamViewfinderRendererMeeGo::createProgram() {
   m_program->release();
 }
 
-void QtCamViewfinderRendererMeeGo::paintFrame(QPainter *painter, int frame) {
+void QtCamViewfinderRendererMeeGo::paintFrame(const QMatrix4x4& matrix, int frame) {
+  EGLSyncKHR sync = 0;
+
   if (frame == -1) {
     return;
   }
 
-  // TODO: sometimes there is an assertion.
-
   MeegoGstVideoTexture *sink = MEEGO_GST_VIDEO_TEXTURE(m_sink);
   if (!meego_gst_video_texture_acquire_frame(sink, frame)) {
     qDebug() << "Failed to acquire frame";
@@ -257,7 +281,7 @@ void QtCamViewfinderRendererMeeGo::paintFrame(QPainter *painter, int frame) {
   m_program->bind();
 
   m_program->setUniformValue("matrix", m_projectionMatrix);
-  m_program->setUniformValue("matrixWorld", QMatrix4x4(painter->combinedTransform()));
+  m_program->setUniformValue("matrixWorld", matrix);
 
   if (!meego_gst_video_texture_bind_frame(sink, GL_TEXTURE_EXTERNAL_OES, frame)) {
     qDebug() << "Failed to bind frame";
@@ -282,9 +306,11 @@ void QtCamViewfinderRendererMeeGo::paintFrame(QPainter *painter, int frame) {
 
   m_program->release();
 
-  // We are not using fences.
-  // TODO: make it configurable.
-  meego_gst_video_texture_release_frame(sink, frame, 0);
+  if (eglCreateSyncKHR) {
+    sync = eglCreateSyncKHR(m_dpy, EGL_SYNC_FENCE_KHR, NULL);
+  }
+
+  meego_gst_video_texture_release_frame(sink, frame, sync);
 }
 
 void QtCamViewfinderRendererMeeGo::calculateCoords() {
@@ -327,6 +353,10 @@ QRectF QtCamViewfinderRendererMeeGo::renderArea() {
   return m_renderArea;
 }
 
+QSizeF QtCamViewfinderRendererMeeGo::videoResolution() {
+  return m_videoSize;
+}
+
 void QtCamViewfinderRendererMeeGo::setVideoSize(const QSizeF& size) {
   if (size == m_videoSize) {
     return;
@@ -339,4 +369,7 @@ void QtCamViewfinderRendererMeeGo::setVideoSize(const QSizeF& size) {
   calculateCoords();
 
   m_needsInit = true;
+
+  emit renderAreaChanged();
+  emit videoResolutionChanged();
 }