1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtQml module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #include "qquickprofileradapter.h" |
41 | |
42 | #include <QCoreApplication> |
43 | #include <private/qqmldebugconnector_p.h> |
44 | #include <private/qversionedpacket_p.h> |
45 | #include <private/qqmldebugserviceinterfaces_p.h> |
46 | #include <private/qquickprofiler_p.h> |
47 | |
48 | QT_BEGIN_NAMESPACE |
49 | |
50 | using QQmlDebugPacket = QVersionedPacket<QQmlDebugConnector>; |
51 | |
52 | QQuickProfilerAdapter::QQuickProfilerAdapter(QObject *parent) : |
53 | QQmlAbstractProfilerAdapter(parent), next(0) |
54 | { |
55 | QQuickProfiler::initialize(parent: this); |
56 | |
57 | // We can always do DirectConnection here as all methods are protected by mutexes |
58 | connect(sender: this, signal: &QQmlAbstractProfilerAdapter::profilingEnabled, |
59 | receiver: QQuickProfiler::s_instance, slot: &QQuickProfiler::startProfilingImpl, type: Qt::DirectConnection); |
60 | connect(sender: this, signal: &QQmlAbstractProfilerAdapter::profilingEnabledWhileWaiting, |
61 | receiver: QQuickProfiler::s_instance, slot: &QQuickProfiler::startProfilingImpl, type: Qt::DirectConnection); |
62 | connect(sender: this, signal: &QQmlAbstractProfilerAdapter::referenceTimeKnown, |
63 | receiver: QQuickProfiler::s_instance, slot: &QQuickProfiler::setTimer, type: Qt::DirectConnection); |
64 | connect(sender: this, signal: &QQmlAbstractProfilerAdapter::profilingDisabled, |
65 | receiver: QQuickProfiler::s_instance, slot: &QQuickProfiler::stopProfilingImpl, type: Qt::DirectConnection); |
66 | connect(sender: this, signal: &QQmlAbstractProfilerAdapter::profilingDisabledWhileWaiting, |
67 | receiver: QQuickProfiler::s_instance, slot: &QQuickProfiler::stopProfilingImpl, type: Qt::DirectConnection); |
68 | connect(sender: this, signal: &QQmlAbstractProfilerAdapter::dataRequested, |
69 | receiver: QQuickProfiler::s_instance, slot: &QQuickProfiler::reportDataImpl, type: Qt::DirectConnection); |
70 | connect(sender: QQuickProfiler::s_instance, signal: &QQuickProfiler::dataReady, |
71 | receiver: this, slot: &QQuickProfilerAdapter::receiveData, type: Qt::DirectConnection); |
72 | } |
73 | |
74 | QQuickProfilerAdapter::~QQuickProfilerAdapter() |
75 | { |
76 | if (service) |
77 | service->removeGlobalProfiler(profiler: this); |
78 | } |
79 | |
80 | // convert to QByteArrays that can be sent to the debug client |
81 | static void qQuickProfilerDataToByteArrays(const QQuickProfilerData &data, |
82 | QList<QByteArray> &messages) |
83 | { |
84 | QQmlDebugPacket ds; |
85 | Q_ASSERT_X(((data.messageType | data.detailType) & (1 << 31)) == 0, Q_FUNC_INFO, |
86 | "You can use at most 31 message types and 31 detail types." ); |
87 | for (uint decodedMessageType = 0; (data.messageType >> decodedMessageType) != 0; |
88 | ++decodedMessageType) { |
89 | if ((data.messageType & (1 << decodedMessageType)) == 0) |
90 | continue; |
91 | |
92 | for (uint decodedDetailType = 0; (data.detailType >> decodedDetailType) != 0; |
93 | ++decodedDetailType) { |
94 | if ((data.detailType & (1 << decodedDetailType)) == 0) |
95 | continue; |
96 | |
97 | ds << data.time << decodedMessageType << decodedDetailType; |
98 | |
99 | switch (decodedMessageType) { |
100 | case QQuickProfiler::Event: |
101 | switch (decodedDetailType) { |
102 | case QQuickProfiler::AnimationFrame: |
103 | ds << data.framerate << data.count << data.threadId; |
104 | break; |
105 | case QQuickProfiler::Key: |
106 | case QQuickProfiler::Mouse: |
107 | ds << data.inputType << data.inputA << data.inputB; |
108 | break; |
109 | } |
110 | break; |
111 | case QQuickProfiler::PixmapCacheEvent: |
112 | ds << data.detailUrl.toString(); |
113 | switch (decodedDetailType) { |
114 | case QQuickProfiler::PixmapSizeKnown: ds << data.x << data.y; break; |
115 | case QQuickProfiler::PixmapReferenceCountChanged: ds << data.count; break; |
116 | case QQuickProfiler::PixmapCacheCountChanged: ds << data.count; break; |
117 | default: break; |
118 | } |
119 | break; |
120 | case QQuickProfiler::SceneGraphFrame: |
121 | switch (decodedDetailType) { |
122 | // RendererFrame: preprocessTime, updateTime, bindingTime, renderTime |
123 | case QQuickProfiler::SceneGraphRendererFrame: ds << data.subtime_1 << data.subtime_2 << data.subtime_3 << data.subtime_4; break; |
124 | // AdaptationLayerFrame: glyphCount (which is an integer), glyphRenderTime, glyphStoreTime |
125 | case QQuickProfiler::SceneGraphAdaptationLayerFrame: ds << data.subtime_3 << data.subtime_1 << data.subtime_2; break; |
126 | // ContextFrame: compiling material time |
127 | case QQuickProfiler::SceneGraphContextFrame: ds << data.subtime_1; break; |
128 | // RenderLoop: syncTime, renderTime, swapTime |
129 | case QQuickProfiler::SceneGraphRenderLoopFrame: ds << data.subtime_1 << data.subtime_2 << data.subtime_3; break; |
130 | // TexturePrepare: bind, convert, swizzle, upload, mipmap |
131 | case QQuickProfiler::SceneGraphTexturePrepare: ds << data.subtime_1 << data.subtime_2 << data.subtime_3 << data.subtime_4 << data.subtime_5; break; |
132 | // TextureDeletion: deletionTime |
133 | case QQuickProfiler::SceneGraphTextureDeletion: ds << data.subtime_1; break; |
134 | // PolishAndSync: polishTime, waitTime, syncTime, animationsTime, |
135 | case QQuickProfiler::SceneGraphPolishAndSync: ds << data.subtime_1 << data.subtime_2 << data.subtime_3 << data.subtime_4; break; |
136 | // WindowsRenderLoop: GL time, make current time, SceneGraph time |
137 | case QQuickProfiler::SceneGraphWindowsRenderShow: ds << data.subtime_1 << data.subtime_2 << data.subtime_3; break; |
138 | // WindowsAnimations: update time |
139 | case QQuickProfiler::SceneGraphWindowsAnimations: ds << data.subtime_1; break; |
140 | // non-threaded rendering: polish time |
141 | case QQuickProfiler::SceneGraphPolishFrame: ds << data.subtime_1; break; |
142 | default:break; |
143 | } |
144 | break; |
145 | default: |
146 | Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid message type." ); |
147 | break; |
148 | } |
149 | messages.append(t: ds.squeezedData()); |
150 | ds.clear(); |
151 | } |
152 | } |
153 | } |
154 | |
155 | qint64 QQuickProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages) |
156 | { |
157 | while (next < m_data.size()) { |
158 | if (m_data[next].time <= until && messages.length() <= s_numMessagesPerBatch) |
159 | qQuickProfilerDataToByteArrays(data: m_data[next++], messages); |
160 | else |
161 | return m_data[next].time; |
162 | } |
163 | m_data.clear(); |
164 | next = 0; |
165 | return -1; |
166 | } |
167 | |
168 | void QQuickProfilerAdapter::receiveData(const QVector<QQuickProfilerData> &new_data) |
169 | { |
170 | if (m_data.isEmpty()) |
171 | m_data = new_data; |
172 | else |
173 | m_data.append(l: new_data); |
174 | service->dataReady(profiler: this); |
175 | } |
176 | |
177 | QT_END_NAMESPACE |
178 | |