qmlgloverlay: make depth buffer optional

allow dropping depth/stencil buffer for
qmlgloverlay element. Shows considerable
drop in memory bandwidth consumption of
the element on windows platforms.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7677>
This commit is contained in:
Andreas Wittmann 2024-06-13 09:59:24 +02:00 committed by GStreamer Marge Bot
parent 5ef423fcaa
commit 41ad50fb48
9 changed files with 146 additions and 10 deletions

View file

@ -32,3 +32,4 @@
#include "buffers.h" #include "buffers.h"
#include "query.h" #include "query.h"
#include "buffer_storage.h" #include "buffer_storage.h"
#include "invalidate_subdata.h"

View file

@ -0,0 +1,66 @@
/*
* GStreamer
* Copyright (C) 2024 Andreas Wittmann <andreas.wittmann@zeiss.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
GST_GL_EXT_BEGIN (invalidate_subdata,
GST_GL_API_OPENGL3 |
GST_GL_API_GLES2,
4, 3,
3, 0,
"ARB:\0",
"invalidate_subdata\0")
GST_GL_EXT_FUNCTION (void, InvalidateFramebuffer,
(GLenum target,
GLsizei numAttachments,
const GLenum* attachments))
GST_GL_EXT_FUNCTION (void, InvalidateSubFramebuffer,
(GLenum target,
GLsizei numAttachments,
const GLenum* attachments,
GLint x,
GLint y,
GLsizei width,
GLsizei height))
GST_GL_EXT_END ()
GST_GL_EXT_BEGIN (invalidate_subdata_no_gles,
GST_GL_API_OPENGL3,
4, 3,
255, 255,
"ARB:\0",
"invalidate_subdata\0")
GST_GL_EXT_FUNCTION (void, InvalidateTexSubImage,
(GLuint texture,
GLint level,
GLint xoffset,
GLint yoffset,
GLint zoffset,
GLsizei width,
GLsizei height,
GLsizei depth))
GST_GL_EXT_FUNCTION (void, InvalidateTexImage,
(GLuint texture,
GLint level))
GST_GL_EXT_FUNCTION (void, InvalidateBufferSubData,
(GLuint buffer,
GLintptr offset,
GLsizeiptr length))
GST_GL_EXT_FUNCTION (void, InvalidateBufferData,
(GLuint buffer))
GST_GL_EXT_END ()

View file

@ -99,7 +99,7 @@ G_BEGIN_DECLS
struct _GstGLFuncs struct _GstGLFuncs
{ {
#include <gst/gl/glprototypes/all_functions.h> #include <gst/gl/glprototypes/all_functions.h>
gpointer padding[GST_PADDING_LARGE*6-2]; gpointer padding[GST_PADDING_LARGE*6-8];
}; };
#undef GST_GL_EXT_BEGIN #undef GST_GL_EXT_BEGIN

View file

@ -103,6 +103,7 @@ gl_prototype_headers = files([
'glprototypes/gles.h', 'glprototypes/gles.h',
'glprototypes/gstgl_compat.h', 'glprototypes/gstgl_compat.h',
'glprototypes/gstgl_gles2compat.h', 'glprototypes/gstgl_gles2compat.h',
'glprototypes/invalidate_subdata.h',
'glprototypes/opengl.h', 'glprototypes/opengl.h',
'glprototypes/query.h', 'glprototypes/query.h',
'glprototypes/shaders.h', 'glprototypes/shaders.h',

View file

@ -12450,6 +12450,18 @@
"type": "GstGLContext", "type": "GstGLContext",
"writable": false "writable": false
}, },
"depth-buffer": {
"blurb": "Use depth and stencil buffer for the rendering of the scene. Might corrupt the rendering when set to FALSE! Only set to FALSE after carefully checking the targeted QML scene.",
"conditionally-available": false,
"construct": false,
"construct-only": false,
"controllable": false,
"default": "true",
"mutable": "ready",
"readable": true,
"type": "gboolean",
"writable": true
},
"qml-scene": { "qml-scene": {
"blurb": "The contents of the QML scene", "blurb": "The contents of the QML scene",
"conditionally-available": false, "conditionally-available": false,

View file

@ -145,6 +145,7 @@ enum
PROP_WIDGET, PROP_WIDGET,
PROP_QML_SCENE, PROP_QML_SCENE,
PROP_ROOT_ITEM, PROP_ROOT_ITEM,
PROP_DEPTH_AND_STENCIL_BUFFER,
}; };
enum enum
@ -204,6 +205,23 @@ gst_qt_overlay_class_init (GstQtOverlayClass * klass)
"The root QQuickItem from the qml-scene used to render", "The root QQuickItem from the qml-scene used to render",
(GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS))); (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
/**
* GstQtOverlay:depth-buffer:
*
* Instructs QML to not use a depth or stencil buffer when rendering.
*
* WARNING: Disabling the depth and stencil buffer may cause QML to
* incorrectly render the provided scene.
*
* Since: 1.26
*/
g_object_class_install_property (gobject_class, PROP_DEPTH_AND_STENCIL_BUFFER,
g_param_spec_boolean ("depth-buffer", "Depth and Stencil Buffer",
"Use depth and stencil buffer for the rendering of the scene. "
"Might corrupt the rendering when set to FALSE! "
"Only set to FALSE after carefully checking the targeted QML scene.", TRUE,
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_MUTABLE_READY)));
/** /**
* GstQmlGLOverlay::qml-scene-initialized * GstQmlGLOverlay::qml-scene-initialized
* @element: the #GstQmlGLOverlay * @element: the #GstQmlGLOverlay
@ -243,6 +261,7 @@ static void
gst_qt_overlay_init (GstQtOverlay * qt_overlay) gst_qt_overlay_init (GstQtOverlay * qt_overlay)
{ {
qt_overlay->widget = QSharedPointer<QtGLVideoItemInterface>(); qt_overlay->widget = QSharedPointer<QtGLVideoItemInterface>();
qt_overlay->depth_buffer = TRUE;
qt_overlay->qml_scene = NULL; qt_overlay->qml_scene = NULL;
} }
@ -278,6 +297,9 @@ gst_qt_overlay_set_property (GObject * object, guint prop_id,
g_free (qt_overlay->qml_scene); g_free (qt_overlay->qml_scene);
qt_overlay->qml_scene = g_value_dup_string (value); qt_overlay->qml_scene = g_value_dup_string (value);
break; break;
case PROP_DEPTH_AND_STENCIL_BUFFER:
qt_overlay->depth_buffer = g_value_get_boolean (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -316,6 +338,9 @@ gst_qt_overlay_get_property (GObject * object, guint prop_id,
} }
GST_OBJECT_UNLOCK (qt_overlay); GST_OBJECT_UNLOCK (qt_overlay);
break; break;
case PROP_DEPTH_AND_STENCIL_BUFFER:
g_value_set_boolean(value, qt_overlay->depth_buffer);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -341,7 +366,7 @@ gst_qt_overlay_gl_start (GstGLBaseFilter * bfilter)
GST_OBJECT_LOCK (bfilter); GST_OBJECT_LOCK (bfilter);
qt_overlay->renderer = new GstQuickRenderer; qt_overlay->renderer = new GstQuickRenderer;
if (!qt_overlay->renderer->init (bfilter->context, &error)) { if (!qt_overlay->renderer->init (bfilter->context, qt_overlay->depth_buffer, &error)) {
GST_ELEMENT_ERROR (GST_ELEMENT (bfilter), RESOURCE, NOT_FOUND, GST_ELEMENT_ERROR (GST_ELEMENT (bfilter), RESOURCE, NOT_FOUND,
("%s", error->message), (NULL)); ("%s", error->message), (NULL));
delete qt_overlay->renderer; delete qt_overlay->renderer;

View file

@ -51,6 +51,8 @@ struct _GstQtOverlay
/* <private> */ /* <private> */
GstGLFilter parent; GstGLFilter parent;
gboolean depth_buffer;
gchar *qml_scene; gchar *qml_scene;
GstQuickRenderer *renderer; GstQuickRenderer *renderer;

View file

@ -21,6 +21,14 @@
#define GST_CAT_DEFAULT gst_qt_gl_renderer_debug #define GST_CAT_DEFAULT gst_qt_gl_renderer_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
// from GL_EXT_discard_framebuffer
#ifndef GL_DEPTH_EXT
#define GL_DEPTH_EXT 0x1801
#endif
#ifndef GL_STENCIL_EXT
#define GL_STENCIL_EXT 0x1802
#endif
static void static void
init_debug (void) init_debug (void)
{ {
@ -217,6 +225,7 @@ GstQuickRenderer::GstQuickRenderer()
gl_allocator(NULL), gl_allocator(NULL),
gl_params(NULL), gl_params(NULL),
gl_mem(NULL), gl_mem(NULL),
m_useDepthBuffer(TRUE),
m_sharedRenderData(NULL) m_sharedRenderData(NULL)
{ {
init_debug (); init_debug ();
@ -292,7 +301,7 @@ bool CreateSurfaceWorker::event(QEvent * ev)
return QObject::event(ev); return QObject::event(ev);
} }
bool GstQuickRenderer::init (GstGLContext * context, GError ** error) bool GstQuickRenderer::init (GstGLContext * context, const gboolean use_depth_buffer, GError ** error)
{ {
g_return_val_if_fail (GST_IS_GL_CONTEXT (context), false); g_return_val_if_fail (GST_IS_GL_CONTEXT (context), false);
g_return_val_if_fail (gst_gl_context_get_current () == context, false); g_return_val_if_fail (gst_gl_context_get_current () == context, false);
@ -306,6 +315,9 @@ bool GstQuickRenderer::init (GstGLContext * context, GError ** error)
return false; return false;
} }
m_useDepthBuffer = use_depth_buffer;
GST_DEBUG ("%s", m_useDepthBuffer ? "Use depth and stencil buffer" : "Discard depth and stencil buffer");
struct SharedRenderData *render_data = NULL, *old_render_data; struct SharedRenderData *render_data = NULL, *old_render_data;
do { do {
if (render_data) if (render_data)
@ -551,7 +563,8 @@ void GstQuickRenderer::ensureFbo()
if (!m_fbo) { if (!m_fbo) {
m_fbo = new QOpenGLFramebufferObject(m_sharedRenderData->m_surface->size(), m_fbo = new QOpenGLFramebufferObject(m_sharedRenderData->m_surface->size(),
QOpenGLFramebufferObject::CombinedDepthStencil); m_useDepthBuffer ? QOpenGLFramebufferObject::CombinedDepthStencil :
QOpenGLFramebufferObject::NoAttachment);
m_quickWindow->setRenderTarget(m_fbo); m_quickWindow->setRenderTarget(m_fbo);
GST_DEBUG ("%p new framebuffer created with size %ix%i", this, GST_DEBUG ("%p new framebuffer created with size %ix%i", this,
m_fbo->size().width(), m_fbo->size().height()); m_fbo->size().width(), m_fbo->size().height());
@ -584,6 +597,23 @@ GstQuickRenderer::renderGstGL ()
/* Meanwhile on this thread continue with the actual rendering. */ /* Meanwhile on this thread continue with the actual rendering. */
m_renderControl->render(); m_renderControl->render();
{
GLint currentFbo = -1;
gl->GetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &currentFbo);
if ((GLuint)currentFbo == m_fbo->handle()) {
if (gl->InvalidateFramebuffer) {
const GLenum attachments[] = { GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT };
gl->InvalidateFramebuffer(GL_FRAMEBUFFER, sizeof(attachments) / sizeof(*attachments), attachments);
} else if (gl->DiscardFramebuffer) {
const GLenum attachments[] = { GL_DEPTH_EXT, GL_STENCIL_EXT };
gl->DiscardFramebuffer(GL_FRAMEBUFFER, sizeof(attachments) / sizeof(*attachments), attachments);
} else {
GST_DEBUG ("Context lacks both - GL_ARB_invalidate_subdata and GL_EXT_discard_framebuffer, cannot discard");
}
}
}
GST_DEBUG ("wrapping Qfbo %p with texture %u", m_fbo, m_fbo->texture()); GST_DEBUG ("wrapping Qfbo %p with texture %u", m_fbo, m_fbo->texture());
struct FBOUserData *data = g_new0 (struct FBOUserData, 1); struct FBOUserData *data = g_new0 (struct FBOUserData, 1);
data->context = (GstGLContext *) gst_object_ref (gl_context); data->context = (GstGLContext *) gst_object_ref (gl_context);

View file

@ -44,11 +44,10 @@ public:
GstQuickRenderer(); GstQuickRenderer();
~GstQuickRenderer(); ~GstQuickRenderer();
/* initialize the GStreamer/Qt integration. On failure returns false /* initialize the GStreamer/Qt integration and determine wether to attach depth/stencil buffer to fbo. On failure
* and fills @error. * returns false and fills @error. Must be called with @context not wrapped and current in the current thread
* Must be called with @context not wrapped and current in the current */
* thread */ bool init (GstGLContext * context, const gboolean use_depth_buffer, GError ** error);
bool init (GstGLContext * context, GError ** error);
/* set the qml scene. returns false and fills @error on failure */ /* set the qml scene. returns false and fills @error on failure */
bool setQmlScene (const gchar * scene, GError ** error); bool setQmlScene (const gchar * scene, GError ** error);
@ -101,7 +100,7 @@ private:
GstGLAllocationParams *gl_params; GstGLAllocationParams *gl_params;
GstVideoInfo v_info; GstVideoInfo v_info;
GstGLMemory *gl_mem; GstGLMemory *gl_mem;
gboolean m_useDepthBuffer;
QString m_errorString; QString m_errorString;
struct SharedRenderData *m_sharedRenderData; struct SharedRenderData *m_sharedRenderData;
}; };