d2cdb511d0
Previously, with no level loaded in the main editor, and no assets loaded
in the EMotionFX editor, the AnimGraph viewport would only update at 15fps,
even on a 64 core machine.
Digging into this with Pix, I found that EMotionFX's UI would only get
updated for every other call to the ComponentApplication tick.
The Editor's QApplication instance controls how the
`ComponentApplication::OnTick` method is called. This is done in the
`maybeProcessIdle()` method. Generally, I found callstacks like this:
```
EditorQtApplication::maybeProcessIdle()
CCryEditApp::OnIdle()
CCryEditApp::IdleProcessing()
CGameEngine::Update() # ~2.2ms
PhysX::Update() # ~1.8ms
EMotionFX::Update() # ~0.2ms
calls QWidget::update() on all the widgets that change per
frame, only puts update events on the event queue, doesn't
paint anything
AZ::ComponentApplication::TickSystem() # ~25ms
renders the frame with Atom # ~24ms
```
The `maybeProcessIdle()` method is invoked by a QTimer, with a timeout
that changes depending on the application state. If the Editor is in
game mode, it used a timeout of 0, which essentially forced the game to
run at as high an fps as possible. If the Editor application has focus,
it used a timeout of 1ms, asking for the idle processing to happen at
1000 fps. Otherwise, it used a timeout of 10ms, asking for idle
processing at 100 fps.
Those fps targets are not realistic. What happened in this case is that
while the PhysX system was being updated, while the previous
`maybeProcessIdle()` call was still processing, the idle processing
timer would timeout again, and place a timer event on Qt's event queue,
before anything else had a chance to do anything. Only afterward would
EMotionFX's MainWindow::OnTick would be invoked, placing paint events on
Qt's event queue.
The fix for this is to use a single shot timer at the end of each
`maybeProcessIdle()` call. This ensures that any events that are
enqueued during the `maybeProcessIdle()` call are processed prior to the
next call to `maybeProcessIdle()`.
Signed-off-by: Chris Burel <burelc@amazon.com>
131 lines
4.1 KiB
C++
131 lines
4.1 KiB
C++
/*
|
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
*
|
|
*/
|
|
#pragma once
|
|
|
|
#if !defined(Q_MOC_RUN)
|
|
#include <QAbstractNativeEventFilter>
|
|
#include <QColor>
|
|
#include <QMap>
|
|
#include <QTranslator>
|
|
#include <QSet>
|
|
#include <unordered_map>
|
|
|
|
#include <AzCore/PlatformDef.h>
|
|
#include <AzCore/UserSettings/UserSettingsProvider.h>
|
|
#include <IEditor.h>
|
|
#include <AzQtComponents/Application/AzQtApplication.h>
|
|
#endif
|
|
|
|
class QFileInfo;
|
|
typedef QList<QFileInfo> QFileInfoList;
|
|
class QByteArray;
|
|
|
|
namespace AzQtComponents
|
|
{
|
|
class O3DEStylesheet;
|
|
}
|
|
|
|
enum EEditorNotifyEvent;
|
|
|
|
// This contains the main "QApplication"-derived class for the editor itself.
|
|
// it performs the message hooking and other functions to allow CryEdit to function.
|
|
|
|
namespace Editor
|
|
{
|
|
typedef void(* ScanDirectoriesUpdateCallBack)(void);
|
|
/*!
|
|
\param directoryList A list of directories to search. ScanDirectories will also search the subdirectories of each of these.
|
|
\param filters A list of filename filters. Supports * and ? wildcards. The filters will not apply to the directory names.
|
|
\param files Any file that is found and matches any of the filters will be added to files.
|
|
\param updateCallback An optional callback function that will be called once for every directory and subdirectory that is scanned.
|
|
*/
|
|
void ScanDirectories(QFileInfoList& directoryList, const QStringList& filters, QFileInfoList& files, ScanDirectoriesUpdateCallBack updateCallback = nullptr);
|
|
|
|
class EditorQtApplication
|
|
: public AzQtComponents::AzQtApplication
|
|
, public QAbstractNativeEventFilter
|
|
, public IEditorNotifyListener
|
|
, public AZ::UserSettingsOwnerRequestBus::Handler
|
|
{
|
|
Q_OBJECT
|
|
Q_PROPERTY(QSet<int> pressedKeys READ pressedKeys)
|
|
Q_PROPERTY(int pressedMouseButtons READ pressedMouseButtons)
|
|
public:
|
|
// Call this before creating this object:
|
|
static void InstallQtLogHandler();
|
|
|
|
EditorQtApplication(int& argc, char** argv);
|
|
virtual ~EditorQtApplication();
|
|
void Initialize();
|
|
|
|
void LoadSettings();
|
|
void UnloadSettings();
|
|
|
|
// AZ::UserSettingsOwnerRequestBus::Handler
|
|
void SaveSettings() override;
|
|
////
|
|
|
|
static EditorQtApplication* instance();
|
|
static EditorQtApplication* newInstance(int& argc, char** argv);
|
|
|
|
static bool IsActive();
|
|
|
|
bool isMovingOrResizing() const;
|
|
|
|
// IEditorNotifyListener:
|
|
void OnEditorNotifyEvent(EEditorNotifyEvent event) override;
|
|
|
|
const QColor& GetColorByName(const QString& colorName);
|
|
|
|
void EnableOnIdle(bool enable = true);
|
|
bool OnIdleEnabled() const;
|
|
|
|
bool eventFilter(QObject* object, QEvent* event) override;
|
|
|
|
QSet<int> pressedKeys() const { return m_pressedKeys; }
|
|
int pressedMouseButtons() const { return m_pressedButtons; }
|
|
|
|
public Q_SLOTS:
|
|
|
|
void setIsMovingOrResizing(bool isMovingOrResizing);
|
|
|
|
signals:
|
|
void skinChanged();
|
|
|
|
protected:
|
|
|
|
bool m_isMovingOrResizing = false;
|
|
|
|
private:
|
|
static QColor InterpolateColors(QColor a, QColor b, float factor);
|
|
void RefreshStyleSheet();
|
|
void InstallFilters();
|
|
void UninstallFilters();
|
|
void maybeProcessIdle();
|
|
|
|
AzQtComponents::O3DEStylesheet* m_stylesheet;
|
|
|
|
// Translators
|
|
void InstallEditorTranslators();
|
|
void UninstallEditorTranslators();
|
|
QTranslator* CreateAndInitializeTranslator(const QString& filename, const QString& directory);
|
|
void DeleteTranslator(QTranslator*& translator);
|
|
|
|
QTranslator* m_editorTranslator = nullptr;
|
|
QTranslator* m_assetBrowserTranslator = nullptr;
|
|
|
|
AZ::UserSettingsProvider m_localUserSettings;
|
|
|
|
Qt::MouseButtons m_pressedButtons = Qt::NoButton;
|
|
QSet<int> m_pressedKeys;
|
|
|
|
bool m_activatedLocalUserSettings = false;
|
|
bool m_applicationActive = false;
|
|
};
|
|
} // namespace editor
|