Android: improve texture rendering on API level >= 16.
Android API level 16 added SurfaceTexture::attachToGLContext(). This allows to create the OpenGL texture when the first video frame is available, rather than at initialization. This means we can do without the ugly hack that makes the render thread call us back through some custom property. Additionally, it allows to recreate a new OpenGL texture every time the SurfaceTexture is reset. Task-number: QTBUG-51911 Change-Id: I17b04524d426c42ef8aa0288b0731597bc9eba62 Reviewed-by: Christian Stromme <christian.stromme@qt.io>
This commit is contained in:
@@ -42,6 +42,7 @@
|
|||||||
#include <qopenglfunctions.h>
|
#include <qopenglfunctions.h>
|
||||||
#include <qopenglshaderprogram.h>
|
#include <qopenglshaderprogram.h>
|
||||||
#include <qopenglframebufferobject.h>
|
#include <qopenglframebufferobject.h>
|
||||||
|
#include <QtCore/private/qjnihelpers_p.h>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
@@ -159,6 +160,7 @@ QAndroidTextureVideoOutput::QAndroidTextureVideoOutput(QObject *parent)
|
|||||||
, m_fbo(0)
|
, m_fbo(0)
|
||||||
, m_program(0)
|
, m_program(0)
|
||||||
, m_glDeleter(0)
|
, m_glDeleter(0)
|
||||||
|
, m_surfaceTextureCanAttachToContext(QtAndroidPrivate::androidSdkVersion() >= 16)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -184,12 +186,14 @@ void QAndroidTextureVideoOutput::setSurface(QAbstractVideoSurface *surface)
|
|||||||
if (m_surface) {
|
if (m_surface) {
|
||||||
if (m_surface->isActive())
|
if (m_surface->isActive())
|
||||||
m_surface->stop();
|
m_surface->stop();
|
||||||
m_surface->setProperty("_q_GLThreadCallback", QVariant());
|
|
||||||
|
if (!m_surfaceTextureCanAttachToContext)
|
||||||
|
m_surface->setProperty("_q_GLThreadCallback", QVariant());
|
||||||
}
|
}
|
||||||
|
|
||||||
m_surface = surface;
|
m_surface = surface;
|
||||||
|
|
||||||
if (m_surface) {
|
if (m_surface && !m_surfaceTextureCanAttachToContext) {
|
||||||
m_surface->setProperty("_q_GLThreadCallback",
|
m_surface->setProperty("_q_GLThreadCallback",
|
||||||
QVariant::fromValue<QObject*>(this));
|
QVariant::fromValue<QObject*>(this));
|
||||||
}
|
}
|
||||||
@@ -197,7 +201,7 @@ void QAndroidTextureVideoOutput::setSurface(QAbstractVideoSurface *surface)
|
|||||||
|
|
||||||
bool QAndroidTextureVideoOutput::isReady()
|
bool QAndroidTextureVideoOutput::isReady()
|
||||||
{
|
{
|
||||||
return QOpenGLContext::currentContext() || m_externalTex;
|
return m_surfaceTextureCanAttachToContext || QOpenGLContext::currentContext() || m_externalTex;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QAndroidTextureVideoOutput::initSurfaceTexture()
|
bool QAndroidTextureVideoOutput::initSurfaceTexture()
|
||||||
@@ -208,14 +212,16 @@ bool QAndroidTextureVideoOutput::initSurfaceTexture()
|
|||||||
if (!m_surface)
|
if (!m_surface)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// if we have an OpenGL context in the current thread, create a texture. Otherwise, wait
|
if (!m_surfaceTextureCanAttachToContext) {
|
||||||
// for the GL render thread to call us back to do it.
|
// if we have an OpenGL context in the current thread, create a texture. Otherwise, wait
|
||||||
if (QOpenGLContext::currentContext()) {
|
// for the GL render thread to call us back to do it.
|
||||||
glGenTextures(1, &m_externalTex);
|
if (QOpenGLContext::currentContext()) {
|
||||||
m_glDeleter = new OpenGLResourcesDeleter;
|
glGenTextures(1, &m_externalTex);
|
||||||
m_glDeleter->setTexture(m_externalTex);
|
m_glDeleter = new OpenGLResourcesDeleter;
|
||||||
} else if (!m_externalTex) {
|
m_glDeleter->setTexture(m_externalTex);
|
||||||
return false;
|
} else if (!m_externalTex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QMutexLocker locker(&m_mutex);
|
QMutexLocker locker(&m_mutex);
|
||||||
@@ -227,7 +233,8 @@ bool QAndroidTextureVideoOutput::initSurfaceTexture()
|
|||||||
} else {
|
} else {
|
||||||
delete m_surfaceTexture;
|
delete m_surfaceTexture;
|
||||||
m_surfaceTexture = 0;
|
m_surfaceTexture = 0;
|
||||||
m_glDeleter->deleteLater();
|
if (m_glDeleter)
|
||||||
|
m_glDeleter->deleteLater();
|
||||||
m_externalTex = 0;
|
m_externalTex = 0;
|
||||||
m_glDeleter = 0;
|
m_glDeleter = 0;
|
||||||
}
|
}
|
||||||
@@ -242,6 +249,10 @@ void QAndroidTextureVideoOutput::clearSurfaceTexture()
|
|||||||
delete m_surfaceTexture;
|
delete m_surfaceTexture;
|
||||||
m_surfaceTexture = 0;
|
m_surfaceTexture = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Also reset the attached OpenGL texture
|
||||||
|
if (m_surfaceTextureCanAttachToContext)
|
||||||
|
m_externalTex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
AndroidSurfaceTexture *QAndroidTextureVideoOutput::surfaceTexture()
|
AndroidSurfaceTexture *QAndroidTextureVideoOutput::surfaceTexture()
|
||||||
@@ -364,6 +375,18 @@ void QAndroidTextureVideoOutput::renderFrameToFbo()
|
|||||||
|
|
||||||
void QAndroidTextureVideoOutput::createGLResources()
|
void QAndroidTextureVideoOutput::createGLResources()
|
||||||
{
|
{
|
||||||
|
Q_ASSERT(QOpenGLContext::currentContext() != NULL);
|
||||||
|
|
||||||
|
if (!m_glDeleter)
|
||||||
|
m_glDeleter = new OpenGLResourcesDeleter;
|
||||||
|
|
||||||
|
if (m_surfaceTextureCanAttachToContext && !m_externalTex) {
|
||||||
|
m_surfaceTexture->detachFromGLContext();
|
||||||
|
glGenTextures(1, &m_externalTex);
|
||||||
|
m_surfaceTexture->attachToGLContext(m_externalTex);
|
||||||
|
m_glDeleter->setTexture(m_externalTex);
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_fbo || m_fbo->size() != m_nativeSize) {
|
if (!m_fbo || m_fbo->size() != m_nativeSize) {
|
||||||
delete m_fbo;
|
delete m_fbo;
|
||||||
m_fbo = new QOpenGLFramebufferObject(m_nativeSize);
|
m_fbo = new QOpenGLFramebufferObject(m_nativeSize);
|
||||||
@@ -407,7 +430,7 @@ void QAndroidTextureVideoOutput::customEvent(QEvent *e)
|
|||||||
{
|
{
|
||||||
if (e->type() == QEvent::User) {
|
if (e->type() == QEvent::User) {
|
||||||
// This is running in the render thread (OpenGL enabled)
|
// This is running in the render thread (OpenGL enabled)
|
||||||
if (!m_externalTex) {
|
if (!m_surfaceTextureCanAttachToContext && !m_externalTex) {
|
||||||
glGenTextures(1, &m_externalTex);
|
glGenTextures(1, &m_externalTex);
|
||||||
m_glDeleter = new OpenGLResourcesDeleter; // will cleanup GL resources in the correct thread
|
m_glDeleter = new OpenGLResourcesDeleter; // will cleanup GL resources in the correct thread
|
||||||
m_glDeleter->setTexture(m_externalTex);
|
m_glDeleter->setTexture(m_externalTex);
|
||||||
|
|||||||
@@ -110,6 +110,8 @@ private:
|
|||||||
QOpenGLShaderProgram *m_program;
|
QOpenGLShaderProgram *m_program;
|
||||||
OpenGLResourcesDeleter *m_glDeleter;
|
OpenGLResourcesDeleter *m_glDeleter;
|
||||||
|
|
||||||
|
bool m_surfaceTextureCanAttachToContext;
|
||||||
|
|
||||||
friend class AndroidTextureVideoBuffer;
|
friend class AndroidTextureVideoBuffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -146,6 +146,22 @@ jobject AndroidSurfaceTexture::surfaceHolder()
|
|||||||
return m_surfaceHolder.object();
|
return m_surfaceHolder.object();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AndroidSurfaceTexture::attachToGLContext(int texName)
|
||||||
|
{
|
||||||
|
if (QtAndroidPrivate::androidSdkVersion() < 16 || !m_surfaceTexture.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_surfaceTexture.callMethod<void>("attachToGLContext", "(I)V", texName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidSurfaceTexture::detachFromGLContext()
|
||||||
|
{
|
||||||
|
if (QtAndroidPrivate::androidSdkVersion() < 16 || !m_surfaceTexture.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_surfaceTexture.callMethod<void>("detachFromGLContext");
|
||||||
|
}
|
||||||
|
|
||||||
bool AndroidSurfaceTexture::initJNI(JNIEnv *env)
|
bool AndroidSurfaceTexture::initJNI(JNIEnv *env)
|
||||||
{
|
{
|
||||||
// SurfaceTexture is available since API 11.
|
// SurfaceTexture is available since API 11.
|
||||||
|
|||||||
@@ -58,6 +58,9 @@ public:
|
|||||||
void release(); // API level 14
|
void release(); // API level 14
|
||||||
void updateTexImage();
|
void updateTexImage();
|
||||||
|
|
||||||
|
void attachToGLContext(int texName); // API level 16
|
||||||
|
void detachFromGLContext(); // API level 16
|
||||||
|
|
||||||
static bool initJNI(JNIEnv *env);
|
static bool initJNI(JNIEnv *env);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
|
|||||||
Reference in New Issue
Block a user