1// Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "platformsurfacefilter_p.h"
5
6#include <Qt3DRender/private/abstractrenderer_p.h>
7
8#include <QMetaObject>
9#include <QPlatformSurfaceEvent>
10#include <QOffscreenSurface>
11#include <QtGui/qwindow.h>
12
13QT_BEGIN_NAMESPACE
14
15namespace Qt3DRender {
16namespace Render {
17
18QSemaphore PlatformSurfaceFilter::m_surfacesSemaphore(1);
19QHash<QSurface *, bool> PlatformSurfaceFilter::m_surfacesValidity;
20
21// Surface protection
22// The surface is accessible from multiple threads at 3 potential places
23// 1) In here (the frontend) when we receive an event
24// 2) In the RenderViewJobs
25// 3) In the Renderer for the submission
26// * We don't need any protection in 2) as we are just copying the pointer
27// but not performing any access to the texture as all the information
28// we need has been cached in the RenderSurfaceSelector element
29// * This leaves us with case 1 and 3. It is important that if the surface
30// is about to be destroyed that we let the time to the submission thread
31// to complete whatever it is doing with a surface before we have the time
32// to process the AboutToBeDestroyed event. For that we have lockSurface, releaseSurface
33// on the PlatformSurfaceFilter. But that's not enough, you need to be sure that
34// the surface is still valid. When locked, you can use isSurfaceValid to check
35// if a surface is still accessible.
36// A Surface is valid when it has been created and becomes invalid when AboutToBeDestroyed
37// has been called
38// SurfaceLocker is a convenience type to perform locking an surface validity check
39
40PlatformSurfaceFilter::PlatformSurfaceFilter(QObject *parent)
41 : QObject(parent)
42 , m_obj(nullptr)
43 , m_surface(nullptr)
44{
45 qRegisterMetaType<QSurface *>(typeName: "QSurface*");
46}
47
48PlatformSurfaceFilter::~PlatformSurfaceFilter()
49{
50 if (m_obj)
51 m_obj->removeEventFilter(obj: this);
52}
53
54bool PlatformSurfaceFilter::eventFilter(QObject *obj, QEvent *e)
55{
56 if (obj == m_obj && e->type() == QEvent::PlatformSurface) {
57 QPlatformSurfaceEvent *ev = static_cast<QPlatformSurfaceEvent *>(e);
58
59 switch (ev->surfaceEventType()) {
60 case QPlatformSurfaceEvent::SurfaceCreated:
61 // set validy to true
62 {
63 markSurfaceAsValid();
64 break;
65 }
66
67 case QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed:
68 // set validity to false
69 {
70 SurfaceLocker lock(m_surface);
71 // If we remove it, the call to isSurfaceValid will
72 // implicitely return false
73 PlatformSurfaceFilter::m_surfacesValidity.remove(key: m_surface);
74 break;
75 }
76
77 default:
78 qCritical(msg: "Unknown surface type");
79 Q_UNREACHABLE();
80 }
81 }
82
83 if (obj == m_obj && e->type() == QEvent::Expose) {
84 QExposeEvent *ev = static_cast<QExposeEvent *>(e);
85 Q_UNUSED(ev);
86 // We could use this to tell to ignore the RenderView
87 // at submission time since it's not exposed
88 }
89 return false;
90}
91
92void PlatformSurfaceFilter::lockSurface()
93{
94 PlatformSurfaceFilter::m_surfacesSemaphore.acquire(n: 1);
95}
96
97void PlatformSurfaceFilter::releaseSurface()
98{
99 PlatformSurfaceFilter::m_surfacesSemaphore.release(n: 1);
100}
101
102bool PlatformSurfaceFilter::isSurfaceValid(QSurface *surface)
103{
104 // Should be called only when the surface is locked
105 // with the semaphore
106 return m_surfacesValidity.value(key: surface, defaultValue: false);
107}
108
109void PlatformSurfaceFilter::markSurfaceAsValid()
110{
111 SurfaceLocker lock(m_surface);
112 PlatformSurfaceFilter::m_surfacesValidity.insert(key: m_surface, value: true);
113}
114
115SurfaceLocker::SurfaceLocker(QSurface *surface)
116 : m_surface(surface)
117{
118 PlatformSurfaceFilter::lockSurface();
119}
120
121SurfaceLocker::~SurfaceLocker()
122{
123 PlatformSurfaceFilter::releaseSurface();
124}
125
126bool SurfaceLocker::isSurfaceValid() const
127{
128 return PlatformSurfaceFilter::isSurfaceValid(surface: m_surface);
129}
130
131} // namespace Render
132} // namespace Qt3DRender
133
134QT_END_NAMESPACE
135
136#include "moc_platformsurfacefilter_p.cpp"
137

source code of qt3d/src/render/backend/platformsurfacefilter.cpp