Merge remote-tracking branch 'upstream/development' into Atom/santorac/MaterialPropertyRenameInMaterialComponent
This commit is contained in:
@@ -16,18 +16,11 @@
|
||||
#include <QScopedValueRollback>
|
||||
#include <QToolBar>
|
||||
#include <QLoggingCategory>
|
||||
#if defined(AZ_PLATFORM_WINDOWS)
|
||||
#include <QtGui/qpa/qplatformnativeinterface.h>
|
||||
#include <QtGui/private/qhighdpiscaling_p.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include <AzCore/Component/ComponentApplication.h>
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
// AzFramework
|
||||
#if defined(AZ_PLATFORM_WINDOWS)
|
||||
# include <AzFramework/Input/Buses/Notifications/RawInputNotificationBus_Platform.h>
|
||||
#endif // defined(AZ_PLATFORM_WINDOWS)
|
||||
|
||||
// AzQtComponents
|
||||
#include <AzQtComponents/Components/GlobalEventFilter.h>
|
||||
@@ -39,7 +32,6 @@
|
||||
#include "Settings.h"
|
||||
#include "CryEdit.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
// in milliseconds
|
||||
@@ -241,7 +233,6 @@ namespace Editor
|
||||
|
||||
EditorQtApplication::EditorQtApplication(int& argc, char** argv)
|
||||
: AzQtApplication(argc, argv)
|
||||
, m_inWinEventFilter(false)
|
||||
, m_stylesheet(new AzQtComponents::O3DEStylesheet(this))
|
||||
, m_idleTimer(new QTimer(this))
|
||||
{
|
||||
@@ -368,86 +359,10 @@ namespace Editor
|
||||
UninstallEditorTranslators();
|
||||
}
|
||||
|
||||
#if defined(AZ_PLATFORM_WINDOWS)
|
||||
bool EditorQtApplication::nativeEventFilter([[maybe_unused]] const QByteArray& eventType, void* message, long* result)
|
||||
EditorQtApplication* EditorQtApplication::instance()
|
||||
{
|
||||
MSG* msg = (MSG*)message;
|
||||
|
||||
if (msg->message == WM_MOVING || msg->message == WM_SIZING)
|
||||
{
|
||||
m_isMovingOrResizing = true;
|
||||
}
|
||||
else if (msg->message == WM_EXITSIZEMOVE)
|
||||
{
|
||||
m_isMovingOrResizing = false;
|
||||
}
|
||||
|
||||
// Prevent the user from being able to move the window in game mode.
|
||||
// This is done during the hit test phase to bypass the native window move messages. If the window
|
||||
// decoration wrapper title bar contains the cursor, set the result to HTCLIENT instead of
|
||||
// HTCAPTION.
|
||||
if (msg->message == WM_NCHITTEST && GetIEditor()->IsInGameMode())
|
||||
{
|
||||
const LRESULT defWinProcResult = DefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam);
|
||||
if (defWinProcResult == 1)
|
||||
{
|
||||
if (QWidget* widget = QWidget::find((WId)msg->hwnd))
|
||||
{
|
||||
if (auto wrapper = qobject_cast<const AzQtComponents::WindowDecorationWrapper *>(widget))
|
||||
{
|
||||
AzQtComponents::TitleBar* titleBar = wrapper->titleBar();
|
||||
const short global_x = static_cast<short>(LOWORD(msg->lParam));
|
||||
const short global_y = static_cast<short>(HIWORD(msg->lParam));
|
||||
|
||||
const QPoint globalPos = QHighDpi::fromNativePixels(QPoint(global_x, global_y), widget->window()->windowHandle());
|
||||
const QPoint local = titleBar->mapFromGlobal(globalPos);
|
||||
if (titleBar->draggableRect().contains(local) && !titleBar->isTopResizeArea(globalPos))
|
||||
{
|
||||
*result = HTCLIENT;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that the Windows WM_INPUT messages get passed through to the AzFramework input system.
|
||||
// These events are only broadcast in game mode. In Editor mode, RenderViewportWidget creates synthetic
|
||||
// keyboard and mouse events via Qt.
|
||||
if (GetIEditor()->IsInGameMode())
|
||||
{
|
||||
if (msg->message == WM_INPUT)
|
||||
{
|
||||
UINT rawInputSize;
|
||||
const UINT rawInputHeaderSize = sizeof(RAWINPUTHEADER);
|
||||
GetRawInputData((HRAWINPUT)msg->lParam, RID_INPUT, nullptr, &rawInputSize, rawInputHeaderSize);
|
||||
|
||||
AZStd::array<BYTE, sizeof(RAWINPUT)> rawInputBytesArray;
|
||||
LPBYTE rawInputBytes = rawInputBytesArray.data();
|
||||
|
||||
[[maybe_unused]] const UINT bytesCopied = GetRawInputData((HRAWINPUT)msg->lParam, RID_INPUT, rawInputBytes, &rawInputSize, rawInputHeaderSize);
|
||||
CRY_ASSERT(bytesCopied == rawInputSize);
|
||||
|
||||
RAWINPUT* rawInput = (RAWINPUT*)rawInputBytes;
|
||||
CRY_ASSERT(rawInput);
|
||||
|
||||
AzFramework::RawInputNotificationBusWindows::Broadcast(&AzFramework::RawInputNotificationsWindows::OnRawInputEvent, *rawInput);
|
||||
|
||||
return false;
|
||||
}
|
||||
else if (msg->message == WM_DEVICECHANGE)
|
||||
{
|
||||
if (msg->wParam == 0x0007) // DBT_DEVNODES_CHANGED
|
||||
{
|
||||
AzFramework::RawInputNotificationBusWindows::Broadcast(&AzFramework::RawInputNotificationsWindows::OnRawInputDeviceChangeEvent);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return static_cast<EditorQtApplication*>(QApplication::instance());
|
||||
}
|
||||
#endif
|
||||
|
||||
void EditorQtApplication::OnEditorNotifyEvent(EEditorNotifyEvent event)
|
||||
{
|
||||
@@ -505,11 +420,6 @@ namespace Editor
|
||||
return m_stylesheet->GetColorByName(name);
|
||||
}
|
||||
|
||||
EditorQtApplication* EditorQtApplication::instance()
|
||||
{
|
||||
return static_cast<EditorQtApplication*>(QApplication::instance());
|
||||
}
|
||||
|
||||
bool EditorQtApplication::IsActive()
|
||||
{
|
||||
return applicationState() == Qt::ApplicationActive;
|
||||
@@ -613,42 +523,6 @@ namespace Editor
|
||||
case QEvent::KeyRelease:
|
||||
m_pressedKeys.remove(reinterpret_cast<QKeyEvent*>(event)->key());
|
||||
break;
|
||||
#ifdef AZ_PLATFORM_WINDOWS
|
||||
case QEvent::Leave:
|
||||
{
|
||||
// if we receive a leave event for a toolbar on Windows
|
||||
// check first whether we really left it. If we didn't: start checking
|
||||
// for the tool bar under the mouse by timer to check when we really left.
|
||||
// Synthesize a new leave event then. Workaround for LY-69788
|
||||
auto toolBarAt = [](const QPoint& pos) -> QToolBar* {
|
||||
QWidget* widget = qApp->widgetAt(pos);
|
||||
while (widget != nullptr)
|
||||
{
|
||||
if (QToolBar* tb = qobject_cast<QToolBar*>(widget))
|
||||
{
|
||||
return tb;
|
||||
}
|
||||
widget = widget->parentWidget();
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
if (object == toolBarAt(QCursor::pos()))
|
||||
{
|
||||
QTimer* t = new QTimer(object);
|
||||
t->start(100);
|
||||
connect(t, &QTimer::timeout, object, [t, object, toolBarAt]() {
|
||||
if (object != toolBarAt(QCursor::pos()))
|
||||
{
|
||||
QEvent event(QEvent::Leave);
|
||||
qApp->sendEvent(object, &event);
|
||||
t->deleteLater();
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -72,14 +72,12 @@ namespace Editor
|
||||
////
|
||||
|
||||
static EditorQtApplication* instance();
|
||||
static EditorQtApplication* newInstance(int& argc, char** argv);
|
||||
|
||||
static bool IsActive();
|
||||
|
||||
bool isMovingOrResizing() const;
|
||||
|
||||
// QAbstractNativeEventFilter:
|
||||
bool nativeEventFilter(const QByteArray& eventType, void* message, long* result) override;
|
||||
|
||||
// IEditorNotifyListener:
|
||||
void OnEditorNotifyEvent(EEditorNotifyEvent event) override;
|
||||
|
||||
@@ -100,6 +98,10 @@ namespace Editor
|
||||
signals:
|
||||
void skinChanged();
|
||||
|
||||
protected:
|
||||
|
||||
bool m_isMovingOrResizing = false;
|
||||
|
||||
private:
|
||||
enum TimerResetFlag
|
||||
{
|
||||
@@ -116,8 +118,6 @@ namespace Editor
|
||||
|
||||
AzQtComponents::O3DEStylesheet* m_stylesheet;
|
||||
|
||||
bool m_inWinEventFilter = false;
|
||||
|
||||
// Translators
|
||||
void InstallEditorTranslators();
|
||||
void UninstallEditorTranslators();
|
||||
@@ -127,7 +127,6 @@ namespace Editor
|
||||
QTranslator* m_editorTranslator = nullptr;
|
||||
QTranslator* m_assetBrowserTranslator = nullptr;
|
||||
QTimer* const m_idleTimer = nullptr;
|
||||
bool m_isMovingOrResizing = false;
|
||||
|
||||
AZ::UserSettingsProvider m_localUserSettings;
|
||||
|
||||
|
||||
+7
-10
@@ -4135,9 +4135,9 @@ extern "C" int AZ_DLL_EXPORT CryEditMain(int argc, char* argv[])
|
||||
Editor::EditorQtApplication::InstallQtLogHandler();
|
||||
|
||||
AzQtComponents::Utilities::HandleDpiAwareness(AzQtComponents::Utilities::SystemDpiAware);
|
||||
Editor::EditorQtApplication app(argc, argv);
|
||||
Editor::EditorQtApplication* app = Editor::EditorQtApplication::newInstance(argc, argv);
|
||||
|
||||
if (app.arguments().contains("-autotest_mode"))
|
||||
if (app->arguments().contains("-autotest_mode"))
|
||||
{
|
||||
// Nullroute all stdout to null for automated tests, this way we make sure
|
||||
// that the test result output is not polluted with unrelated output data.
|
||||
@@ -4173,12 +4173,7 @@ extern "C" int AZ_DLL_EXPORT CryEditMain(int argc, char* argv[])
|
||||
return -1;
|
||||
}
|
||||
|
||||
AzToolsFramework::EditorEvents::Bus::Broadcast(&AzToolsFramework::EditorEvents::NotifyQtApplicationAvailable, &app);
|
||||
|
||||
#if defined(AZ_PLATFORM_MAC)
|
||||
// Native menu bars do not work on macOS due to all the tool dialogs
|
||||
QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
|
||||
#endif
|
||||
AzToolsFramework::EditorEvents::Bus::Broadcast(&AzToolsFramework::EditorEvents::NotifyQtApplicationAvailable, app);
|
||||
|
||||
int exitCode = 0;
|
||||
|
||||
@@ -4189,9 +4184,9 @@ extern "C" int AZ_DLL_EXPORT CryEditMain(int argc, char* argv[])
|
||||
|
||||
if (didCryEditStart)
|
||||
{
|
||||
app.EnableOnIdle();
|
||||
app->EnableOnIdle();
|
||||
|
||||
ret = app.exec();
|
||||
ret = app->exec();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -4202,6 +4197,8 @@ extern "C" int AZ_DLL_EXPORT CryEditMain(int argc, char* argv[])
|
||||
|
||||
}
|
||||
|
||||
delete app;
|
||||
|
||||
gSettings.Disconnect();
|
||||
|
||||
return ret;
|
||||
|
||||
+11
-2
@@ -6,7 +6,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "QtEditorApplication.h"
|
||||
#include "QtEditorApplication_linux.h"
|
||||
|
||||
#ifdef PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
|
||||
#include <AzFramework/XcbEventHandler.h>
|
||||
@@ -14,7 +14,16 @@
|
||||
|
||||
namespace Editor
|
||||
{
|
||||
bool EditorQtApplication::nativeEventFilter([[maybe_unused]] const QByteArray& eventType, void* message, long*)
|
||||
EditorQtApplication* EditorQtApplication::newInstance(int& argc, char** argv)
|
||||
{
|
||||
#ifdef PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
|
||||
return new EditorQtApplicationXcb(argc, argv);
|
||||
#endif
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool EditorQtApplicationXcb::nativeEventFilter([[maybe_unused]] const QByteArray& eventType, void* message, long*)
|
||||
{
|
||||
if (GetIEditor()->IsInGameMode())
|
||||
{
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Editor/Core/QtEditorApplication.h>
|
||||
|
||||
namespace Editor
|
||||
{
|
||||
class EditorQtApplicationXcb : public EditorQtApplication
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
EditorQtApplicationXcb(int& argc, char** argv)
|
||||
: EditorQtApplication(argc, argv)
|
||||
{
|
||||
}
|
||||
|
||||
// QAbstractNativeEventFilter:
|
||||
bool nativeEventFilter(const QByteArray& eventType, void* message, long* result) override;
|
||||
};
|
||||
} // namespace Editor
|
||||
@@ -7,6 +7,6 @@
|
||||
#
|
||||
|
||||
set(FILES
|
||||
../../Core/QtEditorApplication_linux.cpp
|
||||
Editor/Core/QtEditorApplication_linux.cpp
|
||||
../Common/Unimplemented/Util/Mailer_Unimplemented.cpp
|
||||
)
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Editor/Core/QtEditorApplication.h>
|
||||
|
||||
namespace Editor
|
||||
{
|
||||
class EditorQtApplicationMac : public EditorQtApplication
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
EditorQtApplicationMac(int& argc, char** argv)
|
||||
: EditorQtApplication(argc, argv)
|
||||
{
|
||||
}
|
||||
|
||||
// QAbstractNativeEventFilter:
|
||||
bool nativeEventFilter(const QByteArray& eventType, void* message, long* result) override;
|
||||
};
|
||||
} // namespace Editor
|
||||
+8
-1
@@ -19,7 +19,14 @@
|
||||
|
||||
namespace Editor
|
||||
{
|
||||
bool EditorQtApplication::nativeEventFilter(const QByteArray& eventType, void* message, long* result)
|
||||
EditorQtApplication* EditorQtApplication::newInstance(int& argc, char** argv)
|
||||
{
|
||||
QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
|
||||
|
||||
return new EditorQtApplicationMac(argc, argv);
|
||||
}
|
||||
|
||||
bool EditorQtApplicationMac::nativeEventFilter(const QByteArray& eventType, void* message, long* result)
|
||||
{
|
||||
NSEvent* event = (NSEvent*)message;
|
||||
if (GetIEditor()->IsInGameMode())
|
||||
@@ -7,7 +7,7 @@
|
||||
#
|
||||
|
||||
set(FILES
|
||||
../../Core/QtEditorApplication_mac.mm
|
||||
Editor/Core/QtEditorApplication_mac.mm
|
||||
../../LogFile_mac.mm
|
||||
../../WindowObserver_mac.h
|
||||
../../WindowObserver_mac.mm
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "QtEditorApplication_windows.h"
|
||||
|
||||
// Qt
|
||||
#include <QAbstractEventDispatcher>
|
||||
#include <QScopedValueRollback>
|
||||
#include <QToolBar>
|
||||
#include <QLoggingCategory>
|
||||
#include <QTimer>
|
||||
|
||||
#include <QtGui/private/qhighdpiscaling_p.h>
|
||||
#include <QtGui/qpa/qplatformnativeinterface.h>
|
||||
|
||||
// AzQtComponents
|
||||
#include <AzQtComponents/Components/Titlebar.h>
|
||||
#include <AzQtComponents/Components/WindowDecorationWrapper.h>
|
||||
|
||||
// AzFramework
|
||||
#include <AzFramework/Input/Buses/Notifications/RawInputNotificationBus_Platform.h>
|
||||
|
||||
namespace Editor
|
||||
{
|
||||
EditorQtApplication* EditorQtApplication::newInstance(int& argc, char** argv)
|
||||
{
|
||||
return new EditorQtApplicationWindows(argc, argv);
|
||||
}
|
||||
|
||||
bool EditorQtApplicationWindows::nativeEventFilter([[maybe_unused]] const QByteArray& eventType, void* message, long* result)
|
||||
{
|
||||
MSG* msg = (MSG*)message;
|
||||
|
||||
if (msg->message == WM_MOVING || msg->message == WM_SIZING)
|
||||
{
|
||||
m_isMovingOrResizing = true;
|
||||
}
|
||||
else if (msg->message == WM_EXITSIZEMOVE)
|
||||
{
|
||||
m_isMovingOrResizing = false;
|
||||
}
|
||||
|
||||
// Prevent the user from being able to move the window in game mode.
|
||||
// This is done during the hit test phase to bypass the native window move messages. If the window
|
||||
// decoration wrapper title bar contains the cursor, set the result to HTCLIENT instead of
|
||||
// HTCAPTION.
|
||||
if (msg->message == WM_NCHITTEST && GetIEditor()->IsInGameMode())
|
||||
{
|
||||
const LRESULT defWinProcResult = DefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam);
|
||||
if (defWinProcResult == 1)
|
||||
{
|
||||
if (QWidget* widget = QWidget::find((WId)msg->hwnd))
|
||||
{
|
||||
if (auto wrapper = qobject_cast<const AzQtComponents::WindowDecorationWrapper*>(widget))
|
||||
{
|
||||
AzQtComponents::TitleBar* titleBar = wrapper->titleBar();
|
||||
const short global_x = static_cast<short>(LOWORD(msg->lParam));
|
||||
const short global_y = static_cast<short>(HIWORD(msg->lParam));
|
||||
|
||||
const QPoint globalPos = QHighDpi::fromNativePixels(QPoint(global_x, global_y), widget->window()->windowHandle());
|
||||
const QPoint local = titleBar->mapFromGlobal(globalPos);
|
||||
if (titleBar->draggableRect().contains(local) && !titleBar->isTopResizeArea(globalPos))
|
||||
{
|
||||
*result = HTCLIENT;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that the Windows WM_INPUT messages get passed through to the AzFramework input system.
|
||||
// These events are only broadcast in game mode. In Editor mode, RenderViewportWidget creates synthetic
|
||||
// keyboard and mouse events via Qt.
|
||||
if (GetIEditor()->IsInGameMode())
|
||||
{
|
||||
if (msg->message == WM_INPUT)
|
||||
{
|
||||
UINT rawInputSize;
|
||||
const UINT rawInputHeaderSize = sizeof(RAWINPUTHEADER);
|
||||
GetRawInputData((HRAWINPUT)msg->lParam, RID_INPUT, nullptr, &rawInputSize, rawInputHeaderSize);
|
||||
|
||||
AZStd::array<BYTE, sizeof(RAWINPUT)> rawInputBytesArray;
|
||||
LPBYTE rawInputBytes = rawInputBytesArray.data();
|
||||
|
||||
[[maybe_unused]] const UINT bytesCopied =
|
||||
GetRawInputData((HRAWINPUT)msg->lParam, RID_INPUT, rawInputBytes, &rawInputSize, rawInputHeaderSize);
|
||||
CRY_ASSERT(bytesCopied == rawInputSize);
|
||||
|
||||
RAWINPUT* rawInput = (RAWINPUT*)rawInputBytes;
|
||||
CRY_ASSERT(rawInput);
|
||||
|
||||
AzFramework::RawInputNotificationBusWindows::Broadcast(
|
||||
&AzFramework::RawInputNotificationsWindows::OnRawInputEvent, *rawInput);
|
||||
|
||||
return false;
|
||||
}
|
||||
else if (msg->message == WM_DEVICECHANGE)
|
||||
{
|
||||
if (msg->wParam == 0x0007) // DBT_DEVNODES_CHANGED
|
||||
{
|
||||
AzFramework::RawInputNotificationBusWindows::Broadcast(
|
||||
&AzFramework::RawInputNotificationsWindows::OnRawInputDeviceChangeEvent);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EditorQtApplicationWindows::eventFilter(QObject* object, QEvent* event)
|
||||
{
|
||||
switch (event->type())
|
||||
{
|
||||
case QEvent::Leave:
|
||||
{
|
||||
// if we receive a leave event for a toolbar on Windows
|
||||
// check first whether we really left it. If we didn't: start checking
|
||||
// for the tool bar under the mouse by timer to check when we really left.
|
||||
// Synthesize a new leave event then. Workaround for LY-69788
|
||||
auto toolBarAt = [](const QPoint& pos) -> QToolBar*
|
||||
{
|
||||
QWidget* widget = qApp->widgetAt(pos);
|
||||
while (widget != nullptr)
|
||||
{
|
||||
if (QToolBar* tb = qobject_cast<QToolBar*>(widget))
|
||||
{
|
||||
return tb;
|
||||
}
|
||||
widget = widget->parentWidget();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
if (object == toolBarAt(QCursor::pos()))
|
||||
{
|
||||
QTimer* t = new QTimer(object);
|
||||
t->start(100);
|
||||
connect(
|
||||
t, &QTimer::timeout, object,
|
||||
[t, object, toolBarAt]()
|
||||
{
|
||||
if (object != toolBarAt(QCursor::pos()))
|
||||
{
|
||||
QEvent event(QEvent::Leave);
|
||||
qApp->sendEvent(object, &event);
|
||||
t->deleteLater();
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return EditorQtApplication::eventFilter(object, event);
|
||||
}
|
||||
} // namespace Editor
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Editor/Core/QtEditorApplication.h>
|
||||
|
||||
namespace Editor
|
||||
{
|
||||
class EditorQtApplicationWindows : public EditorQtApplication
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
EditorQtApplicationWindows(int& argc, char** argv)
|
||||
: EditorQtApplication(argc, argv)
|
||||
{
|
||||
}
|
||||
|
||||
// QAbstractNativeEventFilter:
|
||||
bool nativeEventFilter(const QByteArray& eventType, void* message, long* result) override;
|
||||
|
||||
bool eventFilter(QObject* object, QEvent* event) override;
|
||||
};
|
||||
} // namespace Editor
|
||||
@@ -7,5 +7,6 @@
|
||||
#
|
||||
|
||||
set(FILES
|
||||
Editor/Core/QtEditorApplication_windows.cpp
|
||||
Util/Mailer_Windows.cpp
|
||||
)
|
||||
|
||||
+5
-15
@@ -80,14 +80,7 @@ namespace AzToolsFramework
|
||||
|
||||
// set up signals before we start thread.
|
||||
m_shutdownThreadSignal = false;
|
||||
|
||||
// Check to see if the 'p4' command is available at the command line
|
||||
int p4VersionExitCode = QProcess::execute("p4", QStringList{ "-V" });
|
||||
m_p4ApplicationDetected = (p4VersionExitCode == 0);
|
||||
if (m_p4ApplicationDetected)
|
||||
{
|
||||
m_WorkerThread = AZStd::thread(AZStd::bind(&PerforceComponent::ThreadWorker, this));
|
||||
}
|
||||
m_WorkerThread = AZStd::thread(AZStd::bind(&PerforceComponent::ThreadWorker, this));
|
||||
|
||||
SourceControlConnectionRequestBus::Handler::BusConnect();
|
||||
SourceControlCommandBus::Handler::BusConnect();
|
||||
@@ -98,13 +91,10 @@ namespace AzToolsFramework
|
||||
SourceControlCommandBus::Handler::BusDisconnect();
|
||||
SourceControlConnectionRequestBus::Handler::BusDisconnect();
|
||||
|
||||
if (m_p4ApplicationDetected)
|
||||
{
|
||||
m_shutdownThreadSignal = true; // tell the thread to die.
|
||||
m_WorkerSemaphore.release(1); // wake up the thread so that it sees the signal
|
||||
m_WorkerThread.join(); // wait for the thread to finish.
|
||||
m_WorkerThread = AZStd::thread();
|
||||
}
|
||||
m_shutdownThreadSignal = true; // tell the thread to die.
|
||||
m_WorkerSemaphore.release(1); // wake up the thread so that it sees the signal
|
||||
m_WorkerThread.join(); // wait for the thread to finish.
|
||||
m_WorkerThread = AZStd::thread();
|
||||
|
||||
SetConnection(nullptr);
|
||||
}
|
||||
|
||||
@@ -260,7 +260,5 @@ namespace AzToolsFramework
|
||||
AZStd::atomic_bool m_validConnection;
|
||||
|
||||
SourceControlState m_connectionState;
|
||||
|
||||
bool m_p4ApplicationDetected { false };
|
||||
};
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
@@ -523,6 +523,14 @@ QProgressBar::chunk {
|
||||
background-color: #444444;
|
||||
}
|
||||
|
||||
#gemCatalogMenuButton {
|
||||
qproperty-flat: true;
|
||||
max-width:36px;
|
||||
min-width:36px;
|
||||
max-height:24px;
|
||||
min-height:24px;
|
||||
}
|
||||
|
||||
#GemCatalogHeaderLabel {
|
||||
font-size: 12px;
|
||||
color: #FFFFFF;
|
||||
|
||||
@@ -8,14 +8,13 @@
|
||||
|
||||
#include <GemCatalog/GemCatalogHeaderWidget.h>
|
||||
#include <AzCore/std/functional.h>
|
||||
#include <TagWidget.h>
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QMouseEvent>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QMenu>
|
||||
#include <QProgressBar>
|
||||
#include <TagWidget.h>
|
||||
#include <QMenu>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
@@ -406,7 +405,6 @@ namespace O3DE::ProjectManager
|
||||
|
||||
CartButton* cartButton = new CartButton(gemModel, downloadController);
|
||||
hLayout->addWidget(cartButton);
|
||||
|
||||
hLayout->addSpacing(16);
|
||||
|
||||
// Separating line
|
||||
@@ -418,9 +416,9 @@ namespace O3DE::ProjectManager
|
||||
hLayout->addSpacing(16);
|
||||
|
||||
QMenu* gemMenu = new QMenu(this);
|
||||
m_openGemReposAction = gemMenu->addAction(tr("Show Gem Repos"));
|
||||
|
||||
connect(m_openGemReposAction, &QAction::triggered, this,[this](){ emit OpenGemsRepo(); });
|
||||
gemMenu->addAction( tr("Show Gem Repos"), [this]() { emit OpenGemsRepo(); });
|
||||
gemMenu->addSeparator();
|
||||
gemMenu->addAction( tr("Add Existing Gem"), [this]() { emit AddGem(); });
|
||||
|
||||
QPushButton* gemMenuButton = new QPushButton(this);
|
||||
gemMenuButton->setObjectName("gemCatalogMenuButton");
|
||||
|
||||
@@ -8,24 +8,23 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/function/function_fwd.h>
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/std/function/function_fwd.h>
|
||||
#include <AzQtComponents/Components/SearchLineEdit.h>
|
||||
#include <GemCatalog/GemModel.h>
|
||||
#include <GemCatalog/GemSortFilterProxyModel.h>
|
||||
#include <TagWidget.h>
|
||||
#include <DownloadController.h>
|
||||
|
||||
#include <QFrame>
|
||||
#include <QLabel>
|
||||
#include <QDialog>
|
||||
#include <QMoveEvent>
|
||||
#include <QHideEvent>
|
||||
#include <QVBoxLayout>
|
||||
#include <QAction>
|
||||
#include <DownloadController.h>
|
||||
#endif
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QPushButton)
|
||||
QT_FORWARD_DECLARE_CLASS(QLabel)
|
||||
QT_FORWARD_DECLARE_CLASS(QVBoxLayout)
|
||||
QT_FORWARD_DECLARE_CLASS(QHBoxLayout)
|
||||
QT_FORWARD_DECLARE_CLASS(QHideEvent)
|
||||
QT_FORWARD_DECLARE_CLASS(QMoveEvent)
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
class CartOverlayWidget
|
||||
@@ -87,12 +86,11 @@ namespace O3DE::ProjectManager
|
||||
void ReinitForProject();
|
||||
|
||||
signals:
|
||||
void AddGem();
|
||||
void OpenGemsRepo();
|
||||
|
||||
|
||||
private:
|
||||
AzQtComponents::SearchLineEdit* m_filterLineEdit = nullptr;
|
||||
inline constexpr static int s_height = 60;
|
||||
|
||||
QAction* m_openGemReposAction = nullptr;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
#include <QTimer>
|
||||
#include <PythonBindingsInterface.h>
|
||||
#include <QMessageBox>
|
||||
#include <QDir>
|
||||
#include <QStandardPaths>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
{
|
||||
@@ -74,6 +78,7 @@ namespace O3DE::ProjectManager
|
||||
void GemCatalogScreen::ReinitForProject(const QString& projectPath)
|
||||
{
|
||||
m_gemModel->clear();
|
||||
m_gemsToRegisterWithProject.clear();
|
||||
FillModel(projectPath);
|
||||
|
||||
if (m_filterWidget)
|
||||
@@ -90,6 +95,47 @@ namespace O3DE::ProjectManager
|
||||
|
||||
connect(m_gemModel, &GemModel::dataChanged, m_filterWidget, &GemFilterWidget::ResetGemStatusFilter);
|
||||
connect(m_gemModel, &GemModel::gemStatusChanged, this, &GemCatalogScreen::OnGemStatusChanged);
|
||||
connect(
|
||||
m_headerWidget, &GemCatalogHeaderWidget::AddGem,
|
||||
[&]()
|
||||
{
|
||||
EngineInfo engineInfo;
|
||||
QString defaultPath;
|
||||
|
||||
AZ::Outcome<EngineInfo> engineInfoResult = PythonBindingsInterface::Get()->GetEngineInfo();
|
||||
if (engineInfoResult.IsSuccess())
|
||||
{
|
||||
engineInfo = engineInfoResult.GetValue();
|
||||
defaultPath = engineInfo.m_defaultGemsFolder;
|
||||
}
|
||||
|
||||
if (defaultPath.isEmpty())
|
||||
{
|
||||
defaultPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
|
||||
}
|
||||
|
||||
QString directory = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(this, tr("Browse"), defaultPath));
|
||||
if (!directory.isEmpty())
|
||||
{
|
||||
// register the gem to the o3de_manifest.json and to the project after the user confirms
|
||||
// project creation/update
|
||||
auto registerResult = PythonBindingsInterface::Get()->RegisterGem(directory);
|
||||
if(!registerResult)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Failed to add gem"), registerResult.GetError().c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_gemsToRegisterWithProject.insert(directory);
|
||||
AZ::Outcome<GemInfo, void> gemInfoResult = PythonBindingsInterface::Get()->GetGemInfo(directory);
|
||||
if (gemInfoResult)
|
||||
{
|
||||
m_gemModel->AddGem(gemInfoResult.GetValue<GemInfo>());
|
||||
m_gemModel->UpdateGemDependencies();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Select the first entry after everything got correctly sized
|
||||
QTimer::singleShot(200, [=]{
|
||||
@@ -251,6 +297,12 @@ namespace O3DE::ProjectManager
|
||||
|
||||
return EnableDisableGemsResult::Failed;
|
||||
}
|
||||
|
||||
// register external gems that were added with relative paths
|
||||
if (m_gemsToRegisterWithProject.contains(gemPath))
|
||||
{
|
||||
pythonBindings->RegisterGem(QDir(projectPath).relativeFilePath(gemPath), projectPath);
|
||||
}
|
||||
}
|
||||
|
||||
for (const QModelIndex& modelIndex : toBeRemoved)
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include <GemCatalog/GemInspector.h>
|
||||
#include <GemCatalog/GemModel.h>
|
||||
#include <GemCatalog/GemSortFilterProxyModel.h>
|
||||
#include <QSet>
|
||||
#include <QString>
|
||||
#endif
|
||||
|
||||
namespace O3DE::ProjectManager
|
||||
@@ -70,5 +72,6 @@ namespace O3DE::ProjectManager
|
||||
GemFilterWidget* m_filterWidget = nullptr;
|
||||
DownloadController* m_downloadController = nullptr;
|
||||
bool m_notificationsEnabled = true;
|
||||
QSet<QString> m_gemsToRegisterWithProject;
|
||||
};
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -556,6 +556,47 @@ namespace O3DE::ProjectManager
|
||||
return AZ::Success(AZStd::move(gemNames));
|
||||
}
|
||||
|
||||
AZ::Outcome<void, AZStd::string> PythonBindings::RegisterGem(const QString& gemPath, const QString& projectPath)
|
||||
{
|
||||
bool registrationResult = false;
|
||||
auto result = ExecuteWithLockErrorHandling(
|
||||
[&]
|
||||
{
|
||||
auto externalProjectPath = projectPath.isEmpty() ? pybind11::none() : QString_To_Py_Path(projectPath);
|
||||
auto pythonRegistrationResult = m_register.attr("register")(
|
||||
pybind11::none(), // engine_path
|
||||
pybind11::none(), // project_path
|
||||
QString_To_Py_Path(gemPath), // gem folder
|
||||
pybind11::none(), // external subdirectory
|
||||
pybind11::none(), // template_path
|
||||
pybind11::none(), // restricted folder
|
||||
pybind11::none(), // repo uri
|
||||
pybind11::none(), // default_engines_folder
|
||||
pybind11::none(), // default_projects_folder
|
||||
pybind11::none(), // default_gems_folder
|
||||
pybind11::none(), // default_templates_folder
|
||||
pybind11::none(), // default_restricted_folder
|
||||
pybind11::none(), // default_third_party_folder
|
||||
pybind11::none(), // external_subdir_engine_path
|
||||
externalProjectPath // external_subdir_project_path
|
||||
);
|
||||
|
||||
// Returns an exit code so boolify it then invert result
|
||||
registrationResult = !pythonRegistrationResult.cast<bool>();
|
||||
});
|
||||
|
||||
if (!result.IsSuccess())
|
||||
{
|
||||
return AZ::Failure<AZStd::string>(result.GetError().c_str());
|
||||
}
|
||||
else if (!registrationResult)
|
||||
{
|
||||
return AZ::Failure<AZStd::string>(AZStd::string::format("Failed to register gem path %s", gemPath.toUtf8().constData()));
|
||||
}
|
||||
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
bool PythonBindings::AddProject(const QString& path)
|
||||
{
|
||||
bool registrationResult = false;
|
||||
|
||||
@@ -42,6 +42,7 @@ namespace O3DE::ProjectManager
|
||||
AZ::Outcome<QVector<GemInfo>, AZStd::string> GetEngineGemInfos() override;
|
||||
AZ::Outcome<QVector<GemInfo>, AZStd::string> GetAllGemInfos(const QString& projectPath) override;
|
||||
AZ::Outcome<QVector<AZStd::string>, AZStd::string> GetEnabledGemNames(const QString& projectPath) override;
|
||||
AZ::Outcome<void, AZStd::string> RegisterGem(const QString& gemPath, const QString& projectPath = {}) override;
|
||||
|
||||
// Project
|
||||
AZ::Outcome<ProjectInfo> CreateProject(const QString& projectTemplatePath, const ProjectInfo& projectInfo) override;
|
||||
|
||||
@@ -91,6 +91,14 @@ namespace O3DE::ProjectManager
|
||||
*/
|
||||
virtual AZ::Outcome<QVector<AZStd::string>, AZStd::string> GetEnabledGemNames(const QString& projectPath) = 0;
|
||||
|
||||
/**
|
||||
* Registers the gem to the specified project, or to the o3de_manifest.json if no project path is given
|
||||
* @param gemPath the path to the gem
|
||||
* @param projectPath the path to the project. If empty, will register the external path in o3de_manifest.json
|
||||
* @return An outcome with the success flag as well as an error message in case of a failure.
|
||||
*/
|
||||
virtual AZ::Outcome<void, AZStd::string> RegisterGem(const QString& gemPath, const QString& projectPath = {}) = 0;
|
||||
|
||||
|
||||
// Projects
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ VSOutput ShadowCatcherVS(VSInput IN)
|
||||
DirectionalLightShadow::GetShadowCoords(
|
||||
ViewSrg::m_shadowIndexDirectionalLight,
|
||||
worldPosition,
|
||||
OUT.m_worldNormal,
|
||||
OUT.m_shadowCoords);
|
||||
|
||||
return OUT;
|
||||
|
||||
@@ -112,13 +112,15 @@ VSOutput EnhancedPbr_ForwardPassVS(VSInput IN)
|
||||
|
||||
PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float depth)
|
||||
{
|
||||
const float3 vertexNormal = normalize(IN.m_normal);
|
||||
|
||||
// ------- Tangents & Bitangets -------
|
||||
float3 tangents[UvSetCount] = { IN.m_tangent.xyz, IN.m_tangent.xyz };
|
||||
float3 bitangents[UvSetCount] = { IN.m_bitangent.xyz, IN.m_bitangent.xyz };
|
||||
|
||||
if ((o_parallax_feature_enabled && !o_enableSubsurfaceScattering) || o_normal_useTexture || (o_clearCoat_enabled && o_clearCoat_normal_useTexture) || o_detail_normal_useTexture)
|
||||
{
|
||||
PrepareGeneratedTangent(IN.m_normal, IN.m_worldPosition, isFrontFace, IN.m_uv, UvSetCount, tangents, bitangents);
|
||||
PrepareGeneratedTangent(vertexNormal, IN.m_worldPosition, isFrontFace, IN.m_uv, UvSetCount, tangents, bitangents);
|
||||
}
|
||||
|
||||
// ------- Depth & Parallax -------
|
||||
@@ -137,7 +139,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
float3x3 uvMatrix = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3();
|
||||
float3x3 uvMatrixInverse = MaterialSrg::m_parallaxUvIndex == 0 ? MaterialSrg::m_uvMatrixInverse : CreateIdentity3x3();
|
||||
|
||||
GetParallaxInput(IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex], MaterialSrg::m_heightmapScale, MaterialSrg::m_heightmapOffset,
|
||||
GetParallaxInput(vertexNormal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex], MaterialSrg::m_heightmapScale, MaterialSrg::m_heightmapOffset,
|
||||
ObjectSrg::GetWorldMatrix(), uvMatrix, uvMatrixInverse,
|
||||
IN.m_uv[MaterialSrg::m_parallaxUvIndex], IN.m_worldPosition, depth, IN.m_position.w, displacementIsClipped);
|
||||
|
||||
@@ -150,7 +152,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
const uint shadowIndex = ViewSrg::m_shadowIndexDirectionalLight;
|
||||
if (o_enableShadows && shadowIndex < SceneSrg::m_directionalLightCount)
|
||||
{
|
||||
DirectionalLightShadow::GetShadowCoords(shadowIndex, IN.m_worldPosition, IN.m_shadowCoords);
|
||||
DirectionalLightShadow::GetShadowCoords(shadowIndex, IN.m_worldPosition, vertexNormal, IN.m_shadowCoords);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -185,7 +187,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
float2 normalUv = IN.m_uv[MaterialSrg::m_normalMapUvIndex];
|
||||
float3x3 uvMatrix = MaterialSrg::m_normalMapUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3(); // By design, only UV0 is allowed to apply transforms.
|
||||
float detailLayerNormalFactor = MaterialSrg::m_detail_normal_factor * detailLayerBlendFactor;
|
||||
surface.vertexNormal = normalize(IN.m_normal);
|
||||
surface.vertexNormal = vertexNormal;
|
||||
surface.normal = GetDetailedNormalInputWS(
|
||||
isFrontFace, IN.m_normal,
|
||||
tangents[MaterialSrg::m_normalMapUvIndex], bitangents[MaterialSrg::m_normalMapUvIndex], MaterialSrg::m_normalMap, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_normalFactor, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, uvMatrix, o_normal_useTexture,
|
||||
|
||||
+4
-3
@@ -302,6 +302,7 @@ ProcessedMaterialInputs ProcessStandardMaterialInputs(StandardMaterialInputs inp
|
||||
|
||||
PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float depthNDC)
|
||||
{
|
||||
const float3 vertexNormal = normalize(IN.m_normal);
|
||||
depthNDC = IN.m_position.z;
|
||||
|
||||
s_blendMaskFromVertexStream = IN.m_blendMask;
|
||||
@@ -321,7 +322,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
|| o_layer3_o_clearCoat_normal_useTexture
|
||||
)
|
||||
{
|
||||
PrepareGeneratedTangent(IN.m_normal, IN.m_worldPosition, isFrontFace, IN.m_uv, UvSetCount, tangents, bitangents);
|
||||
PrepareGeneratedTangent(vertexNormal, IN.m_worldPosition, isFrontFace, IN.m_uv, UvSetCount, tangents, bitangents);
|
||||
}
|
||||
|
||||
// ------- Debug Modes -------
|
||||
@@ -368,7 +369,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
const uint shadowIndex = ViewSrg::m_shadowIndexDirectionalLight;
|
||||
if (o_enableShadows && shadowIndex < SceneSrg::m_directionalLightCount)
|
||||
{
|
||||
DirectionalLightShadow::GetShadowCoords(shadowIndex, IN.m_worldPosition, IN.m_shadowCoords);
|
||||
DirectionalLightShadow::GetShadowCoords(shadowIndex, IN.m_worldPosition, vertexNormal, IN.m_shadowCoords);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -445,7 +446,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
normalTS = ReorientTangentSpaceNormal(normalTS, lightingInputLayer3.m_normalTS);
|
||||
}
|
||||
// [GFX TODO][ATOM-14591]: This will only work if the normal maps all use the same UV stream. We would need to add support for having them in different UV streams.
|
||||
surface.vertexNormal = normalize(IN.m_normal);
|
||||
surface.vertexNormal = vertexNormal;
|
||||
surface.normal = normalize(TangentSpaceToWorld(normalTS, IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex]));
|
||||
|
||||
// ------- Combine Albedo, roughness, specular, roughness ---------
|
||||
|
||||
@@ -98,6 +98,8 @@ VSOutput StandardPbr_ForwardPassVS(VSInput IN)
|
||||
|
||||
PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float depthNDC)
|
||||
{
|
||||
const float3 vertexNormal = normalize(IN.m_normal);
|
||||
|
||||
// ------- Tangents & Bitangets -------
|
||||
float3 tangents[UvSetCount] = { IN.m_tangent.xyz, IN.m_tangent.xyz };
|
||||
float3 bitangents[UvSetCount] = { IN.m_bitangent.xyz, IN.m_bitangent.xyz };
|
||||
@@ -128,7 +130,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
const uint shadowIndex = ViewSrg::m_shadowIndexDirectionalLight;
|
||||
if (o_enableShadows && shadowIndex < SceneSrg::m_directionalLightCount)
|
||||
{
|
||||
DirectionalLightShadow::GetShadowCoords(shadowIndex, IN.m_worldPosition, IN.m_shadowCoords);
|
||||
DirectionalLightShadow::GetShadowCoords(shadowIndex, IN.m_worldPosition, vertexNormal, IN.m_shadowCoords);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -146,7 +148,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
|
||||
|
||||
float2 normalUv = IN.m_uv[MaterialSrg::m_normalMapUvIndex];
|
||||
float3x3 uvMatrix = MaterialSrg::m_normalMapUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3(); // By design, only UV0 is allowed to apply transforms.
|
||||
surface.vertexNormal = normalize(IN.m_normal);
|
||||
surface.vertexNormal = vertexNormal;
|
||||
surface.normal = GetNormalInputWS(MaterialSrg::m_normalMap, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, isFrontFace, IN.m_normal,
|
||||
tangents[MaterialSrg::m_normalMapUvIndex], bitangents[MaterialSrg::m_normalMapUvIndex], uvMatrix, o_normal_useTexture, MaterialSrg::m_normalFactor);
|
||||
|
||||
|
||||
Vendored
-33
@@ -16,39 +16,6 @@
|
||||
// licensed and released under Creative Commons 3.0 Attribution
|
||||
// https://creativecommons.org/licenses/by/3.0/
|
||||
|
||||
float3 HueToRgb(float hue)
|
||||
{
|
||||
return saturate(float3(abs(hue * 6.0f - 3.0f) - 1.0f,
|
||||
2.0f - abs(hue * 6.0f - 2.0f),
|
||||
2.0f - abs(hue * 6.0f - 4.0f)));
|
||||
}
|
||||
|
||||
float3 RgbToHcv(float3 rgb)
|
||||
{
|
||||
// Based on work by Sam Hocevar and Emil Persson
|
||||
const float4 p = (rgb.g < rgb.b) ? float4(rgb.bg, -1.0f, 2.0f/3.0f) : float4(rgb.gb, 0.0f, -1.0f/3.0f);
|
||||
const float4 q1 = (rgb.r < p.x) ? float4(p.xyw, rgb.r) : float4(rgb.r, p.yzx);
|
||||
const float c = q1.x - min(q1.w, q1.y);
|
||||
const float h = abs((q1.w - q1.y) / (6.0f * c + 0.000001f ) + q1.z);
|
||||
return float3(h, c, q1.x);
|
||||
}
|
||||
|
||||
float3 RgbToHsl(float3 rgb)
|
||||
{
|
||||
rgb.xyz = max(rgb.xyz, 0.000001f);
|
||||
const float3 hcv = RgbToHcv(rgb);
|
||||
const float L = hcv.z - hcv.y * 0.5f;
|
||||
const float S = hcv.y / (1.0f - abs(L * 2.0f - 1.0f) + 0.000001f);
|
||||
return float3(hcv.x, S, L);
|
||||
}
|
||||
|
||||
float3 HslToRgb(float3 hsl)
|
||||
{
|
||||
const float3 rgb = HueToRgb(hsl.x);
|
||||
const float c = (1.0f - abs(2.0f * hsl.z - 1.0f)) * hsl.y;
|
||||
return (rgb - 0.5f) * c + hsl.z;
|
||||
}
|
||||
|
||||
// Color temperature
|
||||
float3 KelvinToRgb(float kelvin)
|
||||
{
|
||||
|
||||
+17
-4
@@ -66,12 +66,21 @@ float3 ColorGradeSaturation (float3 frameColor, float control)
|
||||
return (frameColor - vLuminance) * control + vLuminance;
|
||||
}
|
||||
|
||||
float3 ColorGradeKelvinColorTemp(float3 frameColor, float kelvin)
|
||||
float3 ColorGradeWhiteBalance(float3 frameColor, float kelvin, float tint, float luminancePreservation)
|
||||
{
|
||||
const float3 kColor = TransformColor(KelvinToRgb(kelvin), ColorSpaceId::LinearSRGB, ColorSpaceId::ACEScg);
|
||||
const float luminance = CalculateLuminance(frameColor, ColorSpaceId::ACEScg);
|
||||
const float3 resHsl = RgbToHsl(frameColor.rgb * kColor.rgb); // Apply Kelvin color and convert to HSL
|
||||
return HslToRgb(float3(resHsl.xy, luminance)); // Preserve luminance
|
||||
|
||||
// Apply Kelvin color and tint and calculate the new luminance
|
||||
float3 adjustedColor = frameColor.rgb * kColor.rgb;
|
||||
adjustedColor.g = max(0.0, adjustedColor.g + tint * 0.001);
|
||||
const float adjustedLuminance = CalculateLuminance(adjustedColor, ColorSpaceId::ACEScg);
|
||||
|
||||
// Adjust the color based on the difference in luminance.
|
||||
const float luminanceDifferenceRatio = luminance / adjustedLuminance;
|
||||
const float3 adjustedColorLumPreserved = adjustedColor * luminanceDifferenceRatio;
|
||||
|
||||
return lerp(adjustedColor, adjustedColorLumPreserved, luminancePreservation);
|
||||
}
|
||||
|
||||
// pow(f, e) won't work if f is negative, or may cause inf/NAN.
|
||||
@@ -132,7 +141,11 @@ float3 ColorGradeShadowsMidtonesHighlights (float3 frameColor, float shadowsStar
|
||||
float3 ColorGrade(float3 frameColor)
|
||||
{
|
||||
frameColor = lerp(frameColor, ColorGradePostExposure(frameColor, PassSrg::m_colorGradingExposure), PassSrg::m_colorAdjustmentWeight);
|
||||
frameColor = lerp(frameColor, ColorGradeKelvinColorTemp(frameColor, PassSrg::m_whiteBalanceKelvin), PassSrg::m_whiteBalanceWeight);
|
||||
frameColor = lerp(frameColor, ColorGradeWhiteBalance(
|
||||
frameColor, PassSrg::m_whiteBalanceKelvin,
|
||||
PassSrg::m_whiteBalanceTint,
|
||||
PassSrg::m_whiteBalanceLuminancePreservation),
|
||||
PassSrg::m_whiteBalanceWeight);
|
||||
frameColor = lerp(frameColor, ColorGradingContrast(frameColor, AcesCcMidGrey, PassSrg::m_colorGradingContrast), PassSrg::m_colorAdjustmentWeight);
|
||||
frameColor = lerp(frameColor, ColorGradeColorFilter(frameColor, PassSrg::m_colorFilterSwatch.rgb,
|
||||
PassSrg::m_colorFilterMultiply, PassSrg::m_colorFilterIntensity), PassSrg::m_colorAdjustmentWeight);
|
||||
|
||||
+12
-6
@@ -14,6 +14,7 @@
|
||||
#include "ShadowmapAtlasLib.azsli"
|
||||
#include "BicubicPcfFilters.azsli"
|
||||
#include "ReceiverPlaneDepthBias.azsli"
|
||||
#include "NormalOffsetShadows.azsli"
|
||||
|
||||
// Before including this azsli file, a PassSrg must be defined with the following members:
|
||||
// Texture2DArray<float> m_directionalLightShadowmap;
|
||||
@@ -45,6 +46,7 @@ class DirectionalLightShadow
|
||||
static void GetShadowCoords(
|
||||
uint lightIndex,
|
||||
float3 worldPosition,
|
||||
float3 worldNormal,
|
||||
out float3 shadowCoords[ViewSrg::MaxCascadeCount]);
|
||||
|
||||
//! This calculates visibility ratio of the surface from the light origin.
|
||||
@@ -109,18 +111,22 @@ class DirectionalLightShadow
|
||||
void DirectionalLightShadow::GetShadowCoords(
|
||||
uint lightIndex,
|
||||
float3 worldPosition,
|
||||
float3 worldNormal,
|
||||
out float3 shadowCoords[ViewSrg::MaxCascadeCount])
|
||||
{
|
||||
const uint cascadeCount = ViewSrg::m_directionalLightShadows[lightIndex].m_cascadeCount;
|
||||
const float shadowBias = ViewSrg::m_directionalLightShadows[lightIndex].m_shadowBias;
|
||||
|
||||
const float4x4 lightViewToShadowmapMatrices[ViewSrg::MaxCascadeCount] = ViewSrg::m_directionalLightShadows[lightIndex].m_lightViewToShadowmapMatrices;
|
||||
const float4x4 worldToLightViewMatrices[ViewSrg::MaxCascadeCount] = ViewSrg::m_directionalLightShadows[lightIndex].m_worldToLightViewMatrices;
|
||||
|
||||
for (uint index = 0; index < cascadeCount; ++index)
|
||||
{
|
||||
float4 lightSpacePos = mul(worldToLightViewMatrices[index], float4(worldPosition, 1.));
|
||||
lightSpacePos.z += shadowBias;
|
||||
|
||||
const uint cascadeCount = ViewSrg::m_directionalLightShadows[lightIndex].m_cascadeCount;
|
||||
const float3 shadowOffset = ComputeNormalShadowOffset(ViewSrg::m_directionalLightShadows[lightIndex].m_normalShadowBias, worldNormal, ViewSrg::m_directionalLightShadows[lightIndex].m_shadowmapSize);
|
||||
|
||||
for (uint index = 0; index < cascadeCount; ++index)
|
||||
{
|
||||
float4 lightSpacePos = mul(worldToLightViewMatrices[index], float4(worldPosition + shadowOffset, 1.));
|
||||
lightSpacePos.z += shadowBias;
|
||||
|
||||
const float4 clipSpacePos = mul(lightViewToShadowmapMatrices[index], lightSpacePos);
|
||||
shadowCoords[index] = clipSpacePos.xyz / clipSpacePos.w;
|
||||
}
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
// Helper functions for normal offset shadow mapping.
|
||||
// Normal Offset is an alternative to slope-scale depth bias.
|
||||
// We bias the shadow map lookup by transforming the world-position along the geometric normal before hand.
|
||||
// http://web.archive.org/web/20140810230446/https://www.dissidentlogic.com/old/#Normal%20Offset%20Shadows
|
||||
//
|
||||
|
||||
// Apply the following to the world position. Then use this modified world position to look up in the shadow map
|
||||
float3 ComputeNormalShadowOffset(const float normalOffsetBias, const float3 worldNormal, const float shadowMapDimension)
|
||||
{
|
||||
const float shadowmapSize = 2.0f / shadowMapDimension;
|
||||
return float3(worldNormal * normalOffsetBias * shadowmapSize);
|
||||
}
|
||||
@@ -47,6 +47,7 @@ void VertexHelper(in VSInput IN, inout VSOutput OUT, float3 worldPosition, bool
|
||||
DirectionalLightShadow::GetShadowCoords(
|
||||
shadowIndex,
|
||||
worldPosition,
|
||||
OUT.m_normal,
|
||||
OUT.m_shadowCoords);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,10 +81,10 @@ partial ShaderResourceGroup ViewSrg
|
||||
uint m_shadowmapArraySlice; // array slice who has shadowmap in the atlas.
|
||||
uint m_shadowFilterMethod;
|
||||
float m_boundaryScale;
|
||||
uint m_predictionSampleCount;
|
||||
uint m_filteringSampleCount;
|
||||
float2 m_unprojectConstants;
|
||||
float m_bias;
|
||||
float m_normalShadowBias;
|
||||
float m_esmExponent;
|
||||
float3 m_padding;
|
||||
};
|
||||
@@ -109,7 +109,7 @@ partial ShaderResourceGroup ViewSrg
|
||||
uint m_shadowmapSize; // width and height of shadowmap
|
||||
uint m_cascadeCount;
|
||||
float m_shadowBias;
|
||||
uint m_predictionSampleCount;
|
||||
float m_normalShadowBias;
|
||||
uint m_filteringSampleCount;
|
||||
uint m_debugFlags;
|
||||
uint m_shadowFilterMethod;
|
||||
|
||||
@@ -57,6 +57,7 @@ ShaderResourceGroup PassSrg : SRG_PerPass_WithFallback
|
||||
float m_whiteBalanceWeight;
|
||||
float m_whiteBalanceKelvin;
|
||||
float m_whiteBalanceTint;
|
||||
float m_whiteBalanceLuminancePreservation;
|
||||
|
||||
float m_splitToneBalance;
|
||||
float m_splitToneWeight;
|
||||
|
||||
@@ -40,6 +40,7 @@ ShaderResourceGroup PassSrg : SRG_PerPass_WithFallback
|
||||
float m_whiteBalanceWeight;
|
||||
float m_whiteBalanceKelvin;
|
||||
float m_whiteBalanceTint;
|
||||
float m_whiteBalanceLuminancePreservation;
|
||||
|
||||
float m_splitToneBalance;
|
||||
float m_splitToneWeight;
|
||||
|
||||
+3
@@ -160,6 +160,9 @@ namespace AZ
|
||||
|
||||
//! Reduces acne by applying a small amount of bias along shadow-space z.
|
||||
virtual void SetShadowBias(LightHandle handle, float bias) = 0;
|
||||
|
||||
//! Reduces acne by biasing the shadowmap lookup along the geometric normal.
|
||||
virtual void SetNormalShadowBias(LightHandle handle, float normalShadowBias) = 0;
|
||||
};
|
||||
} // namespace Render
|
||||
} // namespace AZ
|
||||
|
||||
+1
@@ -22,6 +22,7 @@ AZ_GFX_VEC3_PARAM(ColorFilterSwatch, m_colorFilterSwatch, AZ::Vector3(1.0f, 0.5f
|
||||
AZ_GFX_FLOAT_PARAM(WhiteBalanceWeight, m_whiteBalanceWeight, 0.0)
|
||||
AZ_GFX_FLOAT_PARAM(WhiteBalanceKelvin, m_whiteBalanceKelvin, 6600.0)
|
||||
AZ_GFX_FLOAT_PARAM(WhiteBalanceTint, m_whiteBalanceTint, 0.0)
|
||||
AZ_GFX_FLOAT_PARAM(WhiteBalanceLuminancePreservation, m_whiteBalanceLuminancePreservation, 1.0)
|
||||
|
||||
AZ_GFX_FLOAT_PARAM(SplitToneWeight, m_splitToneWeight, 0.0)
|
||||
AZ_GFX_FLOAT_PARAM(SplitToneBalance, m_splitToneBalance, 0.0)
|
||||
|
||||
+5
-3
@@ -48,11 +48,13 @@ namespace AZ::Render
|
||||
virtual void SetAspectRatio(ShadowId id, float aspectRatio) = 0;
|
||||
//! Sets the field of view for the shadow in radians in the Y direction.
|
||||
virtual void SetFieldOfViewY(ShadowId id, float fieldOfView) = 0;
|
||||
//! Sets the maximum resolution of the shadow map
|
||||
//! Sets the maximum resolution of the shadow map.
|
||||
virtual void SetShadowmapMaxResolution(ShadowId id, ShadowmapSize size) = 0;
|
||||
//! Sets the shadow bias
|
||||
//! Sets the shadow bias.
|
||||
virtual void SetShadowBias(ShadowId id, float bias) = 0;
|
||||
//! Sets the shadow filter method
|
||||
//! Sets the normal shadow bias.
|
||||
virtual void SetNormalShadowBias(ShadowId id, float normalShadowBias) = 0;
|
||||
//! Sets the shadow filter method.
|
||||
virtual void SetShadowFilterMethod(ShadowId id, ShadowFilterMethod method) = 0;
|
||||
//! Sets the sample count for filtering of the shadow boundary, max 64.
|
||||
virtual void SetFilteringSampleCount(ShadowId id, uint16_t count) = 0;
|
||||
|
||||
@@ -598,6 +598,15 @@ namespace AZ
|
||||
m_shadowBufferNeedsUpdate = true;
|
||||
}
|
||||
|
||||
void DirectionalLightFeatureProcessor::SetNormalShadowBias(LightHandle handle, float normalShadowBias)
|
||||
{
|
||||
for (auto& it : m_shadowData)
|
||||
{
|
||||
it.second.GetData(handle.GetIndex()).m_normalShadowBias = normalShadowBias;
|
||||
}
|
||||
m_shadowBufferNeedsUpdate = true;
|
||||
}
|
||||
|
||||
void DirectionalLightFeatureProcessor::OnRenderPipelineAdded(RPI::RenderPipelinePtr pipeline)
|
||||
{
|
||||
PrepareForChangingRenderPipelineAndCameraView();
|
||||
|
||||
@@ -92,8 +92,9 @@ namespace AZ
|
||||
uint32_t m_shadowmapSize = 1; // width and height of shadowmap
|
||||
uint32_t m_cascadeCount = 1;
|
||||
// Reduce acne by applying a small amount of bias to apply along shadow-space z.
|
||||
float m_shadowBias = 0.0f;
|
||||
uint32_t m_predictionSampleCount = 0;
|
||||
float m_shadowBias = 0.0f;
|
||||
// Reduces acne by biasing the shadowmap lookup along the geometric normal.
|
||||
float m_normalShadowBias;
|
||||
uint32_t m_filteringSampleCount = 0;
|
||||
uint32_t m_debugFlags = 0;
|
||||
uint32_t m_shadowFilterMethod = 0;
|
||||
@@ -101,6 +102,8 @@ namespace AZ
|
||||
float m_padding[3];
|
||||
};
|
||||
|
||||
static_assert(sizeof(DirectionalLightShadowData) % 16 == 0); // Structured buffers need alignment to be a multiple of 16 bytes.
|
||||
|
||||
class DirectionalLightFeatureProcessor final
|
||||
: public DirectionalLightFeatureProcessorInterface
|
||||
{
|
||||
@@ -216,6 +219,7 @@ namespace AZ
|
||||
void SetFilteringSampleCount(LightHandle handle, uint16_t count) override;
|
||||
void SetShadowReceiverPlaneBiasEnabled(LightHandle handle, bool enable) override;
|
||||
void SetShadowBias(LightHandle handle, float bias) override;
|
||||
void SetNormalShadowBias(LightHandle handle, float normalShadowBias) override;
|
||||
|
||||
const Data::Instance<RPI::Buffer> GetLightBuffer() const;
|
||||
uint32_t GetLightCount() const;
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
m_whiteBalanceWeightIndex.Reset();
|
||||
m_whiteBalanceKelvinIndex.Reset();
|
||||
m_whiteBalanceTintIndex.Reset();
|
||||
m_whiteBalanceLuminancePreservationIndex.Reset();
|
||||
|
||||
m_splitToneBalanceIndex.Reset();
|
||||
m_splitToneWeightIndex.Reset();
|
||||
@@ -96,7 +97,7 @@
|
||||
m_shaderResourceGroup->SetConstant(m_whiteBalanceWeightIndex, settings->GetWhiteBalanceWeight());
|
||||
m_shaderResourceGroup->SetConstant(m_whiteBalanceKelvinIndex, settings->GetWhiteBalanceKelvin());
|
||||
m_shaderResourceGroup->SetConstant(m_whiteBalanceTintIndex, settings->GetWhiteBalanceTint());
|
||||
|
||||
m_shaderResourceGroup->SetConstant(m_whiteBalanceLuminancePreservationIndex, settings->GetWhiteBalanceLuminancePreservation());
|
||||
m_shaderResourceGroup->SetConstant(m_splitToneBalanceIndex, settings->GetSplitToneBalance());
|
||||
m_shaderResourceGroup->SetConstant(m_splitToneWeightIndex, settings->GetSplitToneWeight());
|
||||
m_shaderResourceGroup->SetConstant(m_splitToneShadowsColorIndex, AZ::Vector4(settings->GetSplitToneShadowsColor()));
|
||||
|
||||
@@ -55,6 +55,7 @@ namespace AZ
|
||||
RHI::ShaderInputNameIndex m_whiteBalanceWeightIndex = "m_whiteBalanceWeight";
|
||||
RHI::ShaderInputNameIndex m_whiteBalanceKelvinIndex = "m_whiteBalanceKelvin";
|
||||
RHI::ShaderInputNameIndex m_whiteBalanceTintIndex = "m_whiteBalanceTint";
|
||||
RHI::ShaderInputNameIndex m_whiteBalanceLuminancePreservationIndex = "m_whiteBalanceLuminancePreservation";
|
||||
|
||||
RHI::ShaderInputNameIndex m_splitToneBalanceIndex = "m_splitToneBalance";
|
||||
RHI::ShaderInputNameIndex m_splitToneWeightIndex = "m_splitToneWeight";
|
||||
|
||||
@@ -151,6 +151,14 @@ namespace AZ::Render
|
||||
shadowProperty.m_bias = bias;
|
||||
}
|
||||
|
||||
void ProjectedShadowFeatureProcessor::SetNormalShadowBias(ShadowId id, float normalShadowBias)
|
||||
{
|
||||
AZ_Assert(id.IsValid(), "Invalid ShadowId passed to ProjectedShadowFeatureProcessor::SetNormalShadowBias().");
|
||||
|
||||
ShadowProperty& shadowProperty = GetShadowPropertyFromShadowId(id);
|
||||
shadowProperty.m_normalShadowBias = normalShadowBias;
|
||||
}
|
||||
|
||||
void ProjectedShadowFeatureProcessor::SetShadowmapMaxResolution(ShadowId id, ShadowmapSize size)
|
||||
{
|
||||
AZ_Assert(id.IsValid(), "Invalid ShadowId passed to ProjectedShadowFeatureProcessor::SetShadowmapMaxResolution().");
|
||||
|
||||
@@ -48,6 +48,7 @@ namespace AZ::Render
|
||||
void SetFieldOfViewY(ShadowId id, float fieldOfViewYRadians) override;
|
||||
void SetShadowmapMaxResolution(ShadowId id, ShadowmapSize size) override;
|
||||
void SetShadowBias(ShadowId id, float bias) override;
|
||||
void SetNormalShadowBias(ShadowId id, float normalShadowBias) override;
|
||||
void SetShadowFilterMethod(ShadowId id, ShadowFilterMethod method) override;
|
||||
void SetFilteringSampleCount(ShadowId id, uint16_t count) override;
|
||||
void SetShadowProperties(ShadowId id, const ProjectedShadowDescriptor& descriptor) override;
|
||||
@@ -64,10 +65,10 @@ namespace AZ::Render
|
||||
uint32_t m_shadowmapArraySlice = 0; // array slice who has shadowmap in the atlas.
|
||||
uint32_t m_shadowFilterMethod = 0; // filtering method of shadows.
|
||||
float m_boundaryScale = 0.f; // the half of boundary of lit/shadowed areas. (in degrees)
|
||||
uint32_t m_predictionSampleCount = 0; // sample count to judge whether it is on the shadow boundary or not.
|
||||
uint32_t m_filteringSampleCount = 0;
|
||||
AZStd::array<float, 2> m_unprojectConstants = { {0, 0} };
|
||||
float m_bias;
|
||||
float m_normalShadowBias;
|
||||
float m_esmExponent = 87.0f;
|
||||
float m_padding[3];
|
||||
};
|
||||
@@ -78,6 +79,7 @@ namespace AZ::Render
|
||||
ProjectedShadowDescriptor m_desc;
|
||||
RPI::ViewPtr m_shadowmapView;
|
||||
float m_bias = 0.1f;
|
||||
float m_normalShadowBias = 0.0f;
|
||||
ShadowId m_shadowId;
|
||||
};
|
||||
|
||||
|
||||
@@ -14,92 +14,86 @@ namespace AZ
|
||||
{
|
||||
namespace RHI
|
||||
{
|
||||
/**
|
||||
* The platform-independent swap chain base class. Swap chains contain a "chain" of images which
|
||||
* map to a platform-specific window, displayed on a physical monitor. The user is allowed
|
||||
* to adjust the swap chain outside of the current FrameScheduler frame. Doing so within a frame scheduler
|
||||
* frame results in undefined behavior.
|
||||
*
|
||||
* The frame scheduler controls presentation of the swap chain. The user may attach a swap chain to a scope
|
||||
* in order to render to the current image.
|
||||
*/
|
||||
//! The platform-independent swap chain base class. Swap chains contain a "chain" of images which
|
||||
//! map to a platform-specific window, displayed on a physical monitor. The user is allowed
|
||||
//! to adjust the swap chain outside of the current FrameScheduler frame. Doing so within a frame scheduler
|
||||
//! frame results in undefined behavior.
|
||||
//!
|
||||
//! The frame scheduler controls presentation of the swap chain. The user may attach a swap chain to a scope
|
||||
//! in order to render to the current image.
|
||||
class SwapChain
|
||||
: public ImagePoolBase
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(SwapChain, "{888B64A5-D956-406F-9C33-CF6A54FC41B0}", Object);
|
||||
|
||||
virtual ~SwapChain();
|
||||
|
||||
/// Initializes the swap chain, making it ready for attachment.
|
||||
//! Initializes the swap chain, making it ready for attachment.
|
||||
ResultCode Init(RHI::Device& device, const SwapChainDescriptor& descriptor);
|
||||
|
||||
/// Presents the swap chain to the display, and rotates the images.
|
||||
//! Presents the swap chain to the display, and rotates the images.
|
||||
void Present();
|
||||
|
||||
/**
|
||||
* Sets the vertical sync interval for the swap chain.
|
||||
* 0 - No vsync.
|
||||
* N - Sync to every N vertical refresh.
|
||||
*
|
||||
* A value of 1 syncs to the refresh rate of the monitor.
|
||||
*/
|
||||
//! Sets the vertical sync interval for the swap chain.
|
||||
//! 0 - No vsync.
|
||||
//! N - Sync to every N vertical refresh.
|
||||
//!
|
||||
//! A value of 1 syncs to the refresh rate of the monitor.
|
||||
void SetVerticalSyncInterval(uint32_t verticalSyncInterval);
|
||||
|
||||
/**
|
||||
* Resizes the display resolution of the swap chain. Ideally, this matches the platform window
|
||||
* resolution. Typically, the resize operation will occur in reaction to a platform window size
|
||||
* change. Takes effect immediately and results in a GPU pipeline flush.
|
||||
*/
|
||||
//! Resizes the display resolution of the swap chain. Ideally, this matches the platform window
|
||||
//! resolution. Typically, the resize operation will occur in reaction to a platform window size
|
||||
//! change. Takes effect immediately and results in a GPU pipeline flush.
|
||||
ResultCode Resize(const SwapChainDimensions& dimensions);
|
||||
|
||||
/// Returns the number of images in the swap chain.
|
||||
//! Returns the number of images in the swap chain.
|
||||
uint32_t GetImageCount() const;
|
||||
|
||||
/// Returns the current image index of the swap chain.
|
||||
//! Returns the current image index of the swap chain.
|
||||
uint32_t GetCurrentImageIndex() const;
|
||||
|
||||
/// Returns the current image of the swap chain.
|
||||
//! Returns the current image of the swap chain.
|
||||
Image* GetCurrentImage() const;
|
||||
|
||||
/// Returns the image associated with the provided index, where the total number of images
|
||||
/// is given by GetImageCount().
|
||||
//! Returns the image associated with the provided index, where the total number of images
|
||||
//! is given by GetImageCount().
|
||||
Image* GetImage(uint32_t index) const;
|
||||
|
||||
/// Returns the ID used for the SwapChain's attachment
|
||||
//! Returns the ID used for the SwapChain's attachment
|
||||
const AttachmentId& GetAttachmentId() const;
|
||||
|
||||
/// Returns the descriptor provided when initializing the swap chain.
|
||||
//! Returns the descriptor provided when initializing the swap chain.
|
||||
const RHI::SwapChainDescriptor& GetDescriptor() const override final;
|
||||
|
||||
//! \return True if the swap chain prefers to use exclusive full screen mode.
|
||||
//! Returns True if the swap chain prefers to use exclusive full screen mode.
|
||||
virtual bool IsExclusiveFullScreenPreferred() const { return false; }
|
||||
|
||||
//! \return True if the swap chain prefers exclusive full screen mode and it is currently true, false otherwise.
|
||||
//! Returns True if the swap chain prefers exclusive full screen mode and it is currently true, false otherwise.
|
||||
virtual bool GetExclusiveFullScreenState() const { return false; }
|
||||
|
||||
//! \return True if the swap chain prefers exclusive full screen mode and a transition happened, false otherwise.
|
||||
//! Return True if the swap chain prefers exclusive full screen mode and a transition happened, false otherwise.
|
||||
virtual bool SetExclusiveFullScreenState([[maybe_unused]]bool fullScreenState) { return false; }
|
||||
|
||||
AZ_RTTI(SwapChain, "{888B64A5-D956-406F-9C33-CF6A54FC41B0}", Object);
|
||||
|
||||
protected:
|
||||
SwapChain();
|
||||
|
||||
struct InitImageRequest
|
||||
{
|
||||
/// Pointer to the image to initialize.
|
||||
//! Pointer to the image to initialize.
|
||||
Image* m_image = nullptr;
|
||||
|
||||
/// Index of the image in the swap chain.
|
||||
//! Index of the image in the swap chain.
|
||||
uint32_t m_imageIndex = 0;
|
||||
|
||||
/// Descriptor for the image.
|
||||
//! Descriptor for the image.
|
||||
ImageDescriptor m_descriptor;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// ResourcePool Overrides
|
||||
|
||||
/// Called when the pool is shutting down.
|
||||
//! Called when the pool is shutting down.
|
||||
void ShutdownInternal() override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -111,32 +105,29 @@ namespace AZ
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Platform API
|
||||
|
||||
/// Called when the swap chain is initializing.
|
||||
//! Called when the swap chain is initializing.
|
||||
virtual ResultCode InitInternal(RHI::Device& device, const SwapChainDescriptor& descriptor, SwapChainDimensions* nativeDimensions) = 0;
|
||||
|
||||
/// called when the swap chain is initializing an image.
|
||||
//! called when the swap chain is initializing an image.
|
||||
virtual ResultCode InitImageInternal(const InitImageRequest& request) = 0;
|
||||
|
||||
/// Called when the swap chain is resizing.
|
||||
//! Called when the swap chain is resizing.
|
||||
virtual ResultCode ResizeInternal(const SwapChainDimensions& dimensions, SwapChainDimensions* nativeDimensions) = 0;
|
||||
|
||||
/// Called when the swap chain is presenting the currently swap image.
|
||||
/// Returns the index of the current image after the swap.
|
||||
//! Called when the swap chain is presenting the currently swap image.
|
||||
//! Returns the index of the current image after the swap.
|
||||
virtual uint32_t PresentInternal() = 0;
|
||||
|
||||
virtual void SetVerticalSyncIntervalInternal(uint32_t previousVerticalSyncInterval)
|
||||
{
|
||||
AZ_UNUSED(previousVerticalSyncInterval);
|
||||
}
|
||||
virtual void SetVerticalSyncIntervalInternal([[maybe_unused]]uint32_t previousVerticalSyncInterval) {}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SwapChainDescriptor m_descriptor;
|
||||
|
||||
/// Images corresponding to each image in the swap chain.
|
||||
//! Images corresponding to each image in the swap chain.
|
||||
AZStd::vector<Ptr<Image>> m_images;
|
||||
|
||||
/// The current image index.
|
||||
//! The current image index.
|
||||
uint32_t m_currentImageIndex = 0;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace AZ
|
||||
if (resultCode == ResultCode::Success)
|
||||
{
|
||||
m_descriptor = descriptor;
|
||||
// Ovewrite descriptor dimensions with the native ones (the ones assigned by the platform) returned by InitInternal.
|
||||
// Overwrite descriptor dimensions with the native ones (the ones assigned by the platform) returned by InitInternal.
|
||||
m_descriptor.m_dimensions = nativeDimensions;
|
||||
|
||||
m_images.reserve(m_descriptor.m_dimensions.m_imageCount);
|
||||
@@ -129,8 +129,8 @@ namespace AZ
|
||||
while (m_images.size() > static_cast<size_t>(m_descriptor.m_dimensions.m_imageCount))
|
||||
{
|
||||
m_images.pop_back();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
InitImageRequest request;
|
||||
|
||||
RHI::ImageDescriptor& imageDescriptor = request.m_descriptor;
|
||||
|
||||
@@ -61,13 +61,12 @@ namespace AZ
|
||||
|
||||
void SwapChain::SetVerticalSyncIntervalInternal(uint32_t previousVsyncInterval)
|
||||
{
|
||||
uint32_t verticalSyncInterval = GetDescriptor().m_verticalSyncInterval;
|
||||
if (verticalSyncInterval == 0 || previousVsyncInterval == 0)
|
||||
if (GetDescriptor().m_verticalSyncInterval == 0 || previousVsyncInterval == 0)
|
||||
{
|
||||
// The presentation mode may change when transitioning to or from a vsynced presentation mode
|
||||
// In this case, the swapchain must be recreated.
|
||||
InvalidateNativeSwapChain();
|
||||
BuildNativeSwapChain(GetDescriptor().m_dimensions, verticalSyncInterval);
|
||||
CreateSwapchain();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,46 +84,21 @@ namespace AZ
|
||||
RHI::DeviceObject::Init(baseDevice);
|
||||
|
||||
auto& device = static_cast<Device&>(GetDevice());
|
||||
RHI::SwapChainDimensions swapchainDimensions = descriptor.m_dimensions;
|
||||
m_dimensions = descriptor.m_dimensions;
|
||||
|
||||
result = BuildSurface(descriptor);
|
||||
RETURN_RESULT_IF_UNSUCCESSFUL(result);
|
||||
if (!ValidateSurfaceDimensions(swapchainDimensions))
|
||||
{
|
||||
swapchainDimensions.m_imageHeight = AZStd::clamp(swapchainDimensions.m_imageHeight, m_surfaceCapabilities.minImageExtent.height, m_surfaceCapabilities.maxImageExtent.height);
|
||||
swapchainDimensions.m_imageWidth = AZStd::clamp(swapchainDimensions.m_imageWidth, m_surfaceCapabilities.minImageExtent.width, m_surfaceCapabilities.maxImageExtent.width);
|
||||
AZ_Printf("Vulkan", "Resizing swapchain from (%d, %d) to (%d, %d).",
|
||||
static_cast<int>(descriptor.m_dimensions.m_imageWidth), static_cast<int>(descriptor.m_dimensions.m_imageHeight),
|
||||
static_cast<int>(swapchainDimensions.m_imageWidth), static_cast<int>(swapchainDimensions.m_imageHeight));
|
||||
}
|
||||
|
||||
auto& presentationQueue = device.GetCommandQueueContext().GetOrCreatePresentationCommandQueue(*this);
|
||||
m_presentationQueue = &presentationQueue;
|
||||
result = BuildNativeSwapChain(swapchainDimensions, descriptor.m_verticalSyncInterval);
|
||||
RETURN_RESULT_IF_UNSUCCESSFUL(result);
|
||||
uint32_t imageCount = 0;
|
||||
VkResult vkResult = vkGetSwapchainImagesKHR(device.GetNativeDevice(), m_nativeSwapChain, &imageCount, nullptr);
|
||||
AssertSuccess(vkResult);
|
||||
RETURN_RESULT_IF_UNSUCCESSFUL(ConvertResult(vkResult));
|
||||
|
||||
m_swapchainNativeImages.resize(imageCount);
|
||||
|
||||
// Retrieve the native images of the swapchain so they are
|
||||
// available when we init the Images in InitImageInternal
|
||||
vkResult = vkGetSwapchainImagesKHR(device.GetNativeDevice(), m_nativeSwapChain, &imageCount, m_swapchainNativeImages.data());
|
||||
AssertSuccess(vkResult);
|
||||
RETURN_RESULT_IF_UNSUCCESSFUL(ConvertResult(vkResult));
|
||||
|
||||
// Acquire the first image
|
||||
uint32_t imageIndex = 0;
|
||||
result = AcquireNewImage(&imageIndex);
|
||||
result = CreateSwapchain();
|
||||
RETURN_RESULT_IF_UNSUCCESSFUL(result);
|
||||
|
||||
if (nativeDimensions)
|
||||
{
|
||||
// Fill out the real swapchain dimensions to return
|
||||
nativeDimensions->m_imageCount = imageCount;
|
||||
nativeDimensions->m_imageHeight = swapchainDimensions.m_imageHeight;
|
||||
nativeDimensions->m_imageWidth = swapchainDimensions.m_imageWidth;
|
||||
*nativeDimensions = m_dimensions;
|
||||
nativeDimensions->m_imageFormat = ConvertFormat(m_surfaceFormat.format);
|
||||
}
|
||||
|
||||
@@ -165,51 +139,24 @@ namespace AZ
|
||||
RHI::ResultCode SwapChain::ResizeInternal(const RHI::SwapChainDimensions& dimensions, RHI::SwapChainDimensions* nativeDimensions)
|
||||
{
|
||||
auto& device = static_cast<Device&>(GetDevice());
|
||||
m_dimensions = dimensions;
|
||||
|
||||
InvalidateNativeSwapChain();
|
||||
InvalidateSurface();
|
||||
RHI::SwapChainDimensions resizeDimensions = dimensions;
|
||||
BuildSurface(GetDescriptor());
|
||||
if (!ValidateSurfaceDimensions(dimensions))
|
||||
{
|
||||
resizeDimensions.m_imageHeight = AZStd::clamp(dimensions.m_imageHeight, m_surfaceCapabilities.minImageExtent.height, m_surfaceCapabilities.maxImageExtent.height);
|
||||
resizeDimensions.m_imageWidth = AZStd::clamp(dimensions.m_imageWidth, m_surfaceCapabilities.minImageExtent.width, m_surfaceCapabilities.maxImageExtent.width);
|
||||
AZ_Printf("Vulkan", "Resizing swapchain from (%d, %d) to (%d, %d).",
|
||||
static_cast<int>(dimensions.m_imageWidth), static_cast<int>(dimensions.m_imageHeight),
|
||||
static_cast<int>(resizeDimensions.m_imageWidth), static_cast<int>(resizeDimensions.m_imageHeight));
|
||||
}
|
||||
|
||||
auto& presentationQueue = device.GetCommandQueueContext().GetOrCreatePresentationCommandQueue(*this);
|
||||
m_presentationQueue = &presentationQueue;
|
||||
BuildNativeSwapChain(resizeDimensions, GetDescriptor().m_verticalSyncInterval);
|
||||
|
||||
resizeDimensions.m_imageCount = 0;
|
||||
VkResult vkResult = vkGetSwapchainImagesKHR(device.GetNativeDevice(), m_nativeSwapChain, &resizeDimensions.m_imageCount, nullptr);
|
||||
RETURN_RESULT_IF_UNSUCCESSFUL(ConvertResult(vkResult));
|
||||
|
||||
m_swapchainNativeImages.resize(resizeDimensions.m_imageCount);
|
||||
|
||||
// Retrieve the native images of the swapchain so they are
|
||||
// available when we init the Images in InitImageInternal
|
||||
vkResult = vkGetSwapchainImagesKHR(device.GetNativeDevice(), m_nativeSwapChain, &resizeDimensions.m_imageCount, m_swapchainNativeImages.data());
|
||||
RETURN_RESULT_IF_UNSUCCESSFUL(ConvertResult(vkResult));
|
||||
|
||||
// Do not recycle the semaphore because they may not ever get signaled and since
|
||||
// we can't recycle Vulkan semaphores we just delete them.
|
||||
m_currentFrameContext.m_imageAvailableSemaphore->SetRecycleValue(false);
|
||||
m_currentFrameContext.m_presentableSemaphore->SetRecycleValue(false);
|
||||
|
||||
// Acquire the first image
|
||||
uint32_t imageIndex = 0;
|
||||
AcquireNewImage(&imageIndex);
|
||||
CreateSwapchain();
|
||||
|
||||
if (nativeDimensions)
|
||||
{
|
||||
*nativeDimensions = resizeDimensions;
|
||||
*nativeDimensions = m_dimensions;
|
||||
// [ATOM-4840] This is a workaround when the windows is minimized (0x0 size).
|
||||
// Add proper support to handle this case.
|
||||
nativeDimensions->m_imageHeight = AZStd::max(resizeDimensions.m_imageHeight, 1u);
|
||||
nativeDimensions->m_imageWidth = AZStd::max(resizeDimensions.m_imageWidth, 1u);
|
||||
nativeDimensions->m_imageHeight = AZStd::max(m_dimensions.m_imageHeight, 1u);
|
||||
nativeDimensions->m_imageWidth = AZStd::max(m_dimensions.m_imageWidth, 1u);
|
||||
|
||||
nativeDimensions->m_imageFormat = ConvertFormat(m_surfaceFormat.format);
|
||||
}
|
||||
|
||||
return RHI::ResultCode::Success;
|
||||
@@ -271,20 +218,48 @@ namespace AZ
|
||||
info.pImageIndices = &imageIndex;
|
||||
info.pResults = nullptr;
|
||||
|
||||
[[maybe_unused]] const VkResult result = vkQueuePresentKHR(vulkanQueue->GetNativeQueue(), &info);
|
||||
const VkResult result = vkQueuePresentKHR(vulkanQueue->GetNativeQueue(), &info);
|
||||
|
||||
// Resizing window cause recreation of SwapChain after calling this method,
|
||||
// so VK_SUBOPTIMAL_KHR or VK_ERROR_OUT_OF_DATE_KHR should not happen at this point.
|
||||
AZ_Assert(result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR, "Failed to present swapchain %s", GetName().GetCStr());
|
||||
AZ_Warning("Vulkan", result != VK_SUBOPTIMAL_KHR, "Suboptimal presentation of swapchain %s", GetName().GetCStr());
|
||||
// Vulkan's definition of the two types of errors.
|
||||
// VK_ERROR_OUT_OF_DATE_KHR: "A surface has changed in such a way that it is no longer compatible with the swapchain,
|
||||
// and further presentation requests using the swapchain will fail. Applications must query the new surface
|
||||
// properties and recreate their swapchain if they wish to continue presenting to the surface."
|
||||
// VK_SUBOPTIMAL_KHR: "A swapchain no longer matches the surface properties exactly, but can still be used to
|
||||
// present to the surface successfully."
|
||||
//
|
||||
// These result values may occur after resizing or some window operation. We should update the surface info and recreate the swapchain.
|
||||
// VK_SUBOPTIMAL_KHR is treated as success, but we better update the surface info as well.
|
||||
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR)
|
||||
{
|
||||
InvalidateNativeSwapChain();
|
||||
CreateSwapchain();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Other errors are:
|
||||
// VK_ERROR_OUT_OF_HOST_MEMORY
|
||||
// VK_ERROR_OUT_OF_DEVICE_MEMORY
|
||||
// VK_ERROR_DEVICE_LOST
|
||||
// VK_ERROR_SURFACE_LOST_KHR
|
||||
// VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT
|
||||
AZ_Assert(result == VK_SUCCESS, "Unhandled error for swapchain presentation.");
|
||||
}
|
||||
};
|
||||
|
||||
m_presentationQueue->QueueCommand(AZStd::move(presentCommand));
|
||||
|
||||
uint32_t acquiredImageIndex = GetCurrentImageIndex();
|
||||
AcquireNewImage(&acquiredImageIndex);
|
||||
|
||||
return acquiredImageIndex;
|
||||
RHI::ResultCode result = AcquireNewImage(&acquiredImageIndex);
|
||||
if (result == RHI::ResultCode::Fail)
|
||||
{
|
||||
InvalidateNativeSwapChain();
|
||||
CreateSwapchain();
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return acquiredImageIndex;
|
||||
}
|
||||
}
|
||||
|
||||
RHI::ResultCode SwapChain::BuildSurface(const RHI::SwapChainDescriptor& descriptor)
|
||||
@@ -293,15 +268,8 @@ namespace AZ
|
||||
surfaceDesc.m_windowHandle = descriptor.m_window;
|
||||
RHI::Ptr<WSISurface> surface = WSISurface::Create();
|
||||
const RHI::ResultCode result = surface->Init(surfaceDesc);
|
||||
if (result == RHI::ResultCode::Success)
|
||||
{
|
||||
m_surface = surface;
|
||||
auto& device = static_cast<Device&>(GetDevice());
|
||||
const auto& physicalDevice = static_cast<const PhysicalDevice&>(device.GetPhysicalDevice());
|
||||
VkResult vkResult = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice.GetNativePhysicalDevice(), m_surface->GetNativeSurface(), &m_surfaceCapabilities);
|
||||
AssertSuccess(vkResult);
|
||||
RETURN_RESULT_IF_UNSUCCESSFUL(ConvertResult(vkResult));
|
||||
}
|
||||
RETURN_RESULT_IF_UNSUCCESSFUL(result);
|
||||
m_surface = surface;
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -373,6 +341,21 @@ namespace AZ
|
||||
return supportedModes[0];
|
||||
}
|
||||
|
||||
VkSurfaceCapabilitiesKHR SwapChain::GetSurfaceCapabilities()
|
||||
{
|
||||
AZ_Assert(m_surface, "Surface has not been initialized.");
|
||||
|
||||
auto& device = static_cast<Device&>(GetDevice());
|
||||
const auto& physicalDevice = static_cast<const PhysicalDevice&>(device.GetPhysicalDevice());
|
||||
|
||||
VkSurfaceCapabilitiesKHR surfaceCapabilities;
|
||||
VkResult vkResult = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
|
||||
physicalDevice.GetNativePhysicalDevice(), m_surface->GetNativeSurface(), &surfaceCapabilities);
|
||||
AssertSuccess(vkResult);
|
||||
|
||||
return surfaceCapabilities;
|
||||
}
|
||||
|
||||
VkCompositeAlphaFlagBitsKHR SwapChain::GetSupportedCompositeAlpha() const
|
||||
{
|
||||
VkFlags supportedModesBits = m_surfaceCapabilities.supportedCompositeAlpha;
|
||||
@@ -394,15 +377,9 @@ namespace AZ
|
||||
return VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
}
|
||||
|
||||
RHI::ResultCode SwapChain::BuildNativeSwapChain(const RHI::SwapChainDimensions& dimensions, uint32_t verticalSyncInterval)
|
||||
RHI::ResultCode SwapChain::BuildNativeSwapChain(const RHI::SwapChainDimensions& dimensions)
|
||||
{
|
||||
AZ_Assert(m_nativeSwapChain == VK_NULL_HANDLE, "Vulkan's native SwapChain has been initialized already.");
|
||||
auto& device = static_cast<Device&>(GetDevice());
|
||||
auto& queueContext = device.GetCommandQueueContext();
|
||||
const VkExtent2D extent = {
|
||||
dimensions.m_imageWidth,
|
||||
dimensions.m_imageHeight
|
||||
};
|
||||
AZ_Assert(m_surface, "Surface is null.");
|
||||
|
||||
if (!ValidateSurfaceDimensions(dimensions))
|
||||
@@ -410,7 +387,11 @@ namespace AZ
|
||||
AZ_Assert(false, "Swapchain dimensions are not supported.");
|
||||
return RHI::ResultCode::InvalidArgument;
|
||||
}
|
||||
m_surfaceFormat = GetSupportedSurfaceFormat(dimensions.m_imageFormat);
|
||||
|
||||
auto& device = static_cast<Vulkan::Device&>(GetDevice());
|
||||
auto& queueContext = device.GetCommandQueueContext();
|
||||
const VkExtent2D extent = { dimensions.m_imageWidth, dimensions.m_imageHeight };
|
||||
|
||||
// If the graphic queue is the same as the presentation queue, then we will always acquire
|
||||
// 1 image at the same time. If it's another queue, we will have 2 at the same time (while the other queue
|
||||
// presents the image)
|
||||
@@ -441,11 +422,11 @@ namespace AZ
|
||||
createInfo.imageArrayLayers = 1; // non-stereoscopic
|
||||
createInfo.imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
createInfo.queueFamilyIndexCount = static_cast<uint32_t>(familyIndices.size());
|
||||
createInfo.queueFamilyIndexCount = aznumeric_cast<uint32_t>(familyIndices.size());
|
||||
createInfo.pQueueFamilyIndices = familyIndices.empty() ? nullptr : familyIndices.data();
|
||||
createInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
||||
createInfo.compositeAlpha = GetSupportedCompositeAlpha();
|
||||
createInfo.presentMode = GetSupportedPresentMode(verticalSyncInterval);
|
||||
createInfo.compositeAlpha = m_compositeAlphaFlagBits;
|
||||
createInfo.presentMode = m_presentMode;
|
||||
createInfo.clipped = VK_FALSE;
|
||||
createInfo.oldSwapchain = VK_NULL_HANDLE;
|
||||
|
||||
@@ -467,9 +448,6 @@ namespace AZ
|
||||
VK_NULL_HANDLE,
|
||||
acquiredImageIndex);
|
||||
|
||||
// Resizing window cause recreation of SwapChain before calling this method,
|
||||
// so VK_SUBOPTIMAL_KHR or VK_ERROR_OUT_OF_DATE_KHR should not happen.
|
||||
AssertSuccess(vkResult);
|
||||
RHI::ResultCode result = ConvertResult(vkResult);
|
||||
RETURN_RESULT_IF_UNSUCCESSFUL(result);
|
||||
|
||||
@@ -484,6 +462,7 @@ namespace AZ
|
||||
}
|
||||
m_currentFrameContext.m_imageAvailableSemaphore = imageAvailableSemaphore;
|
||||
m_currentFrameContext.m_presentableSemaphore = semaphoreAllocator.Allocate();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -502,5 +481,70 @@ namespace AZ
|
||||
m_nativeSwapChain = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
RHI::ResultCode SwapChain::CreateSwapchain()
|
||||
{
|
||||
auto& device = static_cast<Device&>(GetDevice());
|
||||
|
||||
m_surfaceCapabilities = GetSurfaceCapabilities();
|
||||
m_surfaceFormat = GetSupportedSurfaceFormat(GetDescriptor().m_dimensions.m_imageFormat);
|
||||
m_presentMode = GetSupportedPresentMode(GetDescriptor().m_verticalSyncInterval);
|
||||
m_compositeAlphaFlagBits = GetSupportedCompositeAlpha();
|
||||
|
||||
if (!ValidateSurfaceDimensions(m_dimensions))
|
||||
{
|
||||
uint32_t oldHeight = m_dimensions.m_imageHeight;
|
||||
uint32_t oldWidth = m_dimensions.m_imageWidth;
|
||||
m_dimensions.m_imageHeight = AZStd::clamp(
|
||||
m_dimensions.m_imageHeight,
|
||||
m_surfaceCapabilities.minImageExtent.height,
|
||||
m_surfaceCapabilities.maxImageExtent.height);
|
||||
m_dimensions.m_imageWidth = AZStd::clamp(
|
||||
m_dimensions.m_imageWidth,
|
||||
m_surfaceCapabilities.minImageExtent.width,
|
||||
m_surfaceCapabilities.maxImageExtent.width);
|
||||
AZ_Printf(
|
||||
"Vulkan", "Resizing swapchain from (%u, %u) to (%u, %u).",
|
||||
oldWidth, oldHeight, m_dimensions.m_imageWidth, m_dimensions.m_imageHeight);
|
||||
}
|
||||
|
||||
RHI::ResultCode result = BuildNativeSwapChain(m_dimensions);
|
||||
RETURN_RESULT_IF_UNSUCCESSFUL(result);
|
||||
AZ_TracePrintf("Swapchain", "Swapchain created. Width: %u, Height: %u.", m_dimensions.m_imageWidth, m_dimensions.m_imageHeight);
|
||||
|
||||
// Do not recycle the semaphore because they may not ever get signaled and since
|
||||
// we can't recycle Vulkan semaphores we just delete them.
|
||||
if (m_currentFrameContext.m_imageAvailableSemaphore)
|
||||
{
|
||||
m_currentFrameContext.m_imageAvailableSemaphore->SetRecycleValue(false);
|
||||
}
|
||||
if (m_currentFrameContext.m_presentableSemaphore)
|
||||
{
|
||||
m_currentFrameContext.m_presentableSemaphore->SetRecycleValue(false);
|
||||
}
|
||||
|
||||
m_dimensions.m_imageCount = 0;
|
||||
VkResult vkResult = vkGetSwapchainImagesKHR(device.GetNativeDevice(), m_nativeSwapChain, &m_dimensions.m_imageCount, nullptr);
|
||||
AssertSuccess(vkResult);
|
||||
RETURN_RESULT_IF_UNSUCCESSFUL(ConvertResult(vkResult));
|
||||
|
||||
m_swapchainNativeImages.resize(m_dimensions.m_imageCount);
|
||||
|
||||
// Retrieve the native images of the swapchain so they are
|
||||
// available when we init the images in InitImageInternal
|
||||
vkResult = vkGetSwapchainImagesKHR(
|
||||
device.GetNativeDevice(), m_nativeSwapChain, &m_dimensions.m_imageCount, m_swapchainNativeImages.data());
|
||||
AssertSuccess(vkResult);
|
||||
RETURN_RESULT_IF_UNSUCCESSFUL(ConvertResult(vkResult));
|
||||
AZ_TracePrintf("Swapchain", "Obtained presentable images.");
|
||||
|
||||
// Acquire the first image
|
||||
uint32_t imageIndex = 0;
|
||||
result = AcquireNewImage(&imageIndex);
|
||||
RETURN_RESULT_IF_UNSUCCESSFUL(result);
|
||||
AZ_TracePrintf("Swapchain", "Acquired the first image.");
|
||||
|
||||
return RHI::ResultCode::Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,24 +70,48 @@ namespace AZ
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
RHI::ResultCode BuildSurface(const RHI::SwapChainDescriptor& descriptor);
|
||||
|
||||
//! Returns true is the swapchain dimensions are supported by the current surface.
|
||||
bool ValidateSurfaceDimensions(const RHI::SwapChainDimensions& dimensions);
|
||||
//! Returns the corresponding Vulkan format that is supported by the surface.
|
||||
//! If such format is not found, return the first supported format from the surface.
|
||||
VkSurfaceFormatKHR GetSupportedSurfaceFormat(const RHI::Format format) const;
|
||||
//! Returns the correct presentation mode.
|
||||
//! If verticalSyncInterval is non-zero, returns VK_PRESENT_MODE_FIFO_KHR.
|
||||
//! Otherwise, choose preferred mode if they are supported.
|
||||
//! If not, the first supported present mode is returned.
|
||||
VkPresentModeKHR GetSupportedPresentMode(uint32_t verticalSyncInterval) const;
|
||||
//! Returns the preferred alpha compositing modes if they are supported.
|
||||
//! If not, error will be reported.
|
||||
VkCompositeAlphaFlagBitsKHR GetSupportedCompositeAlpha() const;
|
||||
RHI::ResultCode BuildNativeSwapChain(const RHI::SwapChainDimensions& dimensions, uint32_t verticalSyncInterval);
|
||||
//! Returns the current surface capabilities.
|
||||
VkSurfaceCapabilitiesKHR GetSurfaceCapabilities();
|
||||
//! Create the swapchain when initializing, or
|
||||
//! swapchain is no longer compatible or is sub-optimal with the surface.
|
||||
RHI::ResultCode CreateSwapchain();
|
||||
//! Build underlying Vulkan swapchain.
|
||||
RHI::ResultCode BuildNativeSwapChain(const RHI::SwapChainDimensions& dimensions);
|
||||
//! Retrieve the index of the next available presentable image.
|
||||
RHI::ResultCode AcquireNewImage(uint32_t* acquiredImageIndex);
|
||||
|
||||
//! Destroy the surface.
|
||||
void InvalidateSurface();
|
||||
//! Destroy the old swapchain.
|
||||
void InvalidateNativeSwapChain();
|
||||
|
||||
VkSwapchainKHR m_nativeSwapChain = VK_NULL_HANDLE;
|
||||
RHI::Ptr<WSISurface> m_surface;
|
||||
VkSwapchainKHR m_nativeSwapChain = VK_NULL_HANDLE;
|
||||
CommandQueue* m_presentationQueue = nullptr;
|
||||
VkSurfaceFormatKHR m_surfaceFormat = {};
|
||||
VkSurfaceCapabilitiesKHR m_surfaceCapabilities;
|
||||
|
||||
FrameContext m_currentFrameContext;
|
||||
|
||||
//! Swapchain data
|
||||
VkSurfaceFormatKHR m_surfaceFormat = {};
|
||||
VkSurfaceCapabilitiesKHR m_surfaceCapabilities = {};
|
||||
VkPresentModeKHR m_presentMode = {};
|
||||
VkCompositeAlphaFlagBitsKHR m_compositeAlphaFlagBits = {};
|
||||
AZStd::vector<VkImage> m_swapchainNativeImages;
|
||||
RHI::SwapChainDimensions m_dimensions;
|
||||
|
||||
struct SwapChainBarrier
|
||||
{
|
||||
VkPipelineStageFlags m_srcPipelineStages = 0;
|
||||
@@ -95,8 +119,6 @@ namespace AZ
|
||||
VkImageMemoryBarrier m_barrier = {};
|
||||
bool m_isValid = false;
|
||||
} m_swapChainBarrier;
|
||||
|
||||
AZStd::vector<VkImage> m_swapchainNativeImages;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
#include <AzToolsFramework/UI/UICore/QTreeViewStateSaver.hxx>
|
||||
#include <AzToolsFramework/UI/UICore/QWidgetSavedState.h>
|
||||
|
||||
#include "AtomToolsFramework_Traits_Platform.h"
|
||||
|
||||
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
|
||||
#include <QMessageBox>
|
||||
#include <QObject>
|
||||
@@ -217,7 +219,7 @@ namespace AtomToolsFramework
|
||||
AzFramework::AssetSystemRequestBus::Broadcast(&AzFramework::AssetSystem::AssetSystemRequests::StartDisconnectingAssetProcessor);
|
||||
|
||||
#if AZ_TRAIT_ATOMTOOLSFRAMEWORK_SKIP_APP_DESTROY
|
||||
_exit(0);
|
||||
::_exit(0);
|
||||
#else
|
||||
Base::Destroy();
|
||||
#endif
|
||||
|
||||
@@ -196,12 +196,8 @@ namespace AtomToolsFramework
|
||||
|
||||
bool RenderViewportWidget::event(QEvent* event)
|
||||
{
|
||||
// On some types of QEvents, a resize event is needed to make sure that the current viewport window
|
||||
// needs to be updated based on a potential new surface dimensions.
|
||||
switch (event->type())
|
||||
{
|
||||
case QEvent::ScreenChangeInternal:
|
||||
case QEvent::UpdateLater:
|
||||
case QEvent::Resize:
|
||||
SendWindowResizeEvent();
|
||||
break;
|
||||
|
||||
+8
@@ -176,6 +176,14 @@ namespace AZ
|
||||
//! Shadow bias reduces acne by applying a small amount of offset along shadow-space z.
|
||||
//! @param Sets the amount of bias to apply.
|
||||
virtual void SetShadowBias(float bias) = 0;
|
||||
|
||||
//! Reduces acne by biasing the shadowmap lookup along the geometric normal.
|
||||
//! @return Returns the amount of bias to apply.
|
||||
virtual float GetNormalShadowBias() const = 0;
|
||||
|
||||
//! Reduces acne by biasing the shadowmap lookup along the geometric normal.
|
||||
//! @param normalShadowBias Sets the amount of normal shadow bias to apply.
|
||||
virtual void SetNormalShadowBias(float normalShadowBias) = 0;
|
||||
};
|
||||
using DirectionalLightRequestBus = EBus<DirectionalLightRequests>;
|
||||
|
||||
|
||||
+3
@@ -101,6 +101,9 @@ namespace AZ
|
||||
//! Method of shadow's filtering.
|
||||
ShadowFilterMethod m_shadowFilterMethod = ShadowFilterMethod::None;
|
||||
|
||||
// Reduces acne by biasing the shadowmap lookup along the geometric normal.
|
||||
float m_normalShadowBias = 0.0f;
|
||||
|
||||
//! Sample Count for filtering (from 4 to 64)
|
||||
//! It is used only when the pixel is predicted as on the boundary.
|
||||
uint16_t m_filteringSampleCount = 32;
|
||||
|
||||
+2
-1
@@ -39,7 +39,8 @@ namespace AZ
|
||||
->Field("ShadowFilterMethod", &DirectionalLightComponentConfig::m_shadowFilterMethod)
|
||||
->Field("PcfFilteringSampleCount", &DirectionalLightComponentConfig::m_filteringSampleCount)
|
||||
->Field("ShadowReceiverPlaneBiasEnabled", &DirectionalLightComponentConfig::m_receiverPlaneBiasEnabled)
|
||||
->Field("Shadow Bias", &DirectionalLightComponentConfig::m_shadowBias);
|
||||
->Field("Shadow Bias", &DirectionalLightComponentConfig::m_shadowBias)
|
||||
->Field("Normal Shadow Bias", &DirectionalLightComponentConfig::m_normalShadowBias);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+19
-1
@@ -86,6 +86,8 @@ namespace AZ
|
||||
->Event("SetShadowReceiverPlaneBiasEnabled", &DirectionalLightRequestBus::Events::SetShadowReceiverPlaneBiasEnabled)
|
||||
->Event("GetShadowBias", &DirectionalLightRequestBus::Events::GetShadowBias)
|
||||
->Event("SetShadowBias", &DirectionalLightRequestBus::Events::SetShadowBias)
|
||||
->Event("GetNormalShadowBias", &DirectionalLightRequestBus::Events::GetNormalShadowBias)
|
||||
->Event("SetNormalShadowBias", &DirectionalLightRequestBus::Events::SetNormalShadowBias)
|
||||
->VirtualProperty("Color", "GetColor", "SetColor")
|
||||
->VirtualProperty("Intensity", "GetIntensity", "SetIntensity")
|
||||
->VirtualProperty("AngularDiameter", "GetAngularDiameter", "SetAngularDiameter")
|
||||
@@ -101,7 +103,8 @@ namespace AZ
|
||||
->VirtualProperty("ShadowFilterMethod", "GetShadowFilterMethod", "SetShadowFilterMethod")
|
||||
->VirtualProperty("FilteringSampleCount", "GetFilteringSampleCount", "SetFilteringSampleCount")
|
||||
->VirtualProperty("ShadowReceiverPlaneBiasEnabled", "GetShadowReceiverPlaneBiasEnabled", "SetShadowReceiverPlaneBiasEnabled")
|
||||
->VirtualProperty("ShadowBias", "GetShadowBias", "SetShadowBias");
|
||||
->VirtualProperty("ShadowBias", "GetShadowBias", "SetShadowBias")
|
||||
->VirtualProperty("NormalShadowBias", "GetNormalShadowBias", "SetNormalShadowBias");
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -423,6 +426,20 @@ namespace AZ
|
||||
return m_configuration.m_shadowBias;
|
||||
}
|
||||
|
||||
void DirectionalLightComponentController::SetNormalShadowBias(float bias)
|
||||
{
|
||||
m_configuration.m_normalShadowBias = bias;
|
||||
if (m_featureProcessor)
|
||||
{
|
||||
m_featureProcessor->SetNormalShadowBias(m_lightHandle, bias);
|
||||
}
|
||||
}
|
||||
|
||||
float DirectionalLightComponentController::GetNormalShadowBias() const
|
||||
{
|
||||
return m_configuration.m_normalShadowBias;
|
||||
}
|
||||
|
||||
void DirectionalLightComponentController::SetFilteringSampleCount(uint32_t count)
|
||||
{
|
||||
const uint16_t count16 = GetMin(Shadow::MaxPcfSamplingCount, aznumeric_cast<uint16_t>(count));
|
||||
@@ -517,6 +534,7 @@ namespace AZ
|
||||
SetDebugColoringEnabled(m_configuration.m_isDebugColoringEnabled);
|
||||
SetShadowFilterMethod(m_configuration.m_shadowFilterMethod);
|
||||
SetShadowBias(m_configuration.m_shadowBias);
|
||||
SetNormalShadowBias(m_configuration.m_normalShadowBias);
|
||||
SetFilteringSampleCount(m_configuration.m_filteringSampleCount);
|
||||
SetShadowReceiverPlaneBiasEnabled(m_configuration.m_receiverPlaneBiasEnabled);
|
||||
|
||||
|
||||
+3
-1
@@ -81,7 +81,9 @@ namespace AZ
|
||||
bool GetShadowReceiverPlaneBiasEnabled() const override;
|
||||
void SetShadowReceiverPlaneBiasEnabled(bool enable) override;
|
||||
float GetShadowBias() const override;
|
||||
void SetShadowBias(float width) override;
|
||||
void SetShadowBias(float bias) override;
|
||||
float GetNormalShadowBias() const override;
|
||||
void SetNormalShadowBias(float bias) override;
|
||||
|
||||
private:
|
||||
friend class EditorDirectionalLightComponent;
|
||||
|
||||
+1
-1
@@ -136,7 +136,7 @@ namespace AZ
|
||||
->Attribute(Edit::Attributes::Min, 0.0f)
|
||||
->Attribute(Edit::Attributes::Max, 100.0f)
|
||||
->Attribute(Edit::Attributes::SoftMin, 0.0f)
|
||||
->Attribute(Edit::Attributes::SoftMax, 1.0f)
|
||||
->Attribute(Edit::Attributes::SoftMax, 2.0f)
|
||||
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
|
||||
->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows)
|
||||
->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::ShadowsDisabled)
|
||||
|
||||
+8
-1
@@ -134,7 +134,7 @@ namespace AZ
|
||||
->EnumAttribute(ShadowFilterMethod::EsmPcf, "ESM+PCF")
|
||||
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
|
||||
->DataElement(Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_filteringSampleCount, "Filtering sample count\n",
|
||||
"This is used only when the pixel is predicted as on the boundary.\n"
|
||||
"This is used only when the pixel is predicted to be on the boundary.\n"
|
||||
"Specific to PCF and ESM+PCF.")
|
||||
->Attribute(Edit::Attributes::Min, 4)
|
||||
->Attribute(Edit::Attributes::Max, 64)
|
||||
@@ -154,6 +154,13 @@ namespace AZ
|
||||
->Attribute(Edit::Attributes::Min, 0.f)
|
||||
->Attribute(Edit::Attributes::Max, 0.2)
|
||||
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
|
||||
->DataElement(
|
||||
Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_normalShadowBias, "Normal Shadow Bias\n",
|
||||
"Reduces acne by biasing the shadowmap lookup along the geometric normal.\n"
|
||||
"If this is 0, no biasing is applied.")
|
||||
->Attribute(Edit::Attributes::Min, 0.f)
|
||||
->Attribute(Edit::Attributes::Max, 10.0f)
|
||||
->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -100,9 +100,13 @@ namespace AZ
|
||||
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_whiteBalanceKelvin, "Temperature", "Temperature in Kelvin")
|
||||
->Attribute(Edit::Attributes::Min, 1000.0f)
|
||||
->Attribute(Edit::Attributes::Max, 40000.0f)
|
||||
->Attribute(AZ::Edit::Attributes::SliderCurveMidpoint, 0.165f)
|
||||
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_whiteBalanceTint, "Tint", "Tint Value")
|
||||
->Attribute(Edit::Attributes::Min, -100.0f)
|
||||
->Attribute(Edit::Attributes::Max, 100.0f)
|
||||
->DataElement(AZ::Edit::UIHandlers::Slider, &HDRColorGradingComponentConfig::m_whiteBalanceLuminancePreservation, "Luminance Preservation", "Modulate the preservation of luminance")
|
||||
->Attribute(Edit::Attributes::Min, 0.0f)
|
||||
->Attribute(Edit::Attributes::Max, 1.0f)
|
||||
|
||||
->ClassElement(AZ::Edit::ClassElements::Group, "Split Toning")
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
|
||||
@@ -465,7 +465,7 @@ void ApplyLighting(inout Surface surface, inout LightingData lightingData)
|
||||
const uint shadowIndex = ViewSrg::m_shadowIndexDirectionalLight;
|
||||
if (o_enableShadows && shadowIndex < SceneSrg::m_directionalLightCount)
|
||||
{
|
||||
DirectionalLightShadow::GetShadowCoords(shadowIndex, surface.position, lightingData.shadowCoords);
|
||||
DirectionalLightShadow::GetShadowCoords(shadowIndex, surface.position, surface.vertexNormal, lightingData.shadowCoords);
|
||||
}
|
||||
|
||||
// Light loops application.
|
||||
|
||||
@@ -59,6 +59,7 @@ VSOutput TerrainPBR_MainPassVS(VertexInput IN)
|
||||
DirectionalLightShadow::GetShadowCoords(
|
||||
shadowIndex,
|
||||
worldPosition,
|
||||
OUT.m_normal,
|
||||
OUT.m_shadowCoords);
|
||||
}
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
"CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4",
|
||||
"CMAKE_LY_PROJECTS": "AutomatedTesting",
|
||||
"CMAKE_TARGET": "all",
|
||||
"CTEST_OPTIONS": "-E Gem::EMotionFX.Editor.Tests -LE (SUITE_sandbox|SUITE_awsi) -L FRAMEWORK_googletest",
|
||||
"CTEST_OPTIONS": "-E Gem::EMotionFX.Editor.Tests -LE (SUITE_sandbox|SUITE_awsi) -L FRAMEWORK_googletest --no-tests=error",
|
||||
"TEST_RESULTS": "True"
|
||||
}
|
||||
},
|
||||
@@ -96,7 +96,7 @@
|
||||
"CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=FALSE -DLY_PARALLEL_LINK_JOBS=4",
|
||||
"CMAKE_LY_PROJECTS": "AutomatedTesting",
|
||||
"CMAKE_TARGET": "all",
|
||||
"CTEST_OPTIONS": "-E Gem::EMotionFX.Editor.Tests -LE (SUITE_sandbox|SUITE_awsi) -L FRAMEWORK_googletest",
|
||||
"CTEST_OPTIONS": "-E Gem::EMotionFX.Editor.Tests -LE (SUITE_sandbox|SUITE_awsi) -L FRAMEWORK_googletest --no-tests=error",
|
||||
"TEST_RESULTS": "True"
|
||||
}
|
||||
},
|
||||
@@ -145,7 +145,7 @@
|
||||
"CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4",
|
||||
"CMAKE_LY_PROJECTS": "AutomatedTesting",
|
||||
"CMAKE_TARGET": "TEST_SUITE_periodic",
|
||||
"CTEST_OPTIONS": "-L (SUITE_periodic)",
|
||||
"CTEST_OPTIONS": "-L (SUITE_periodic) --no-tests=error",
|
||||
"TEST_RESULTS": "True"
|
||||
}
|
||||
},
|
||||
@@ -165,7 +165,7 @@
|
||||
"CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4 -DO3DE_HOME_PATH=\"${WORKSPACE}/home\" -DO3DE_REGISTER_ENGINE_PATH=\"${WORKSPACE}/o3de\" -DO3DE_REGISTER_THIS_ENGINE=TRUE",
|
||||
"CMAKE_LY_PROJECTS": "AutomatedTesting",
|
||||
"CMAKE_TARGET": "all",
|
||||
"CTEST_OPTIONS": "-L (SUITE_sandbox)"
|
||||
"CTEST_OPTIONS": "-L (SUITE_sandbox) --no-tests=error"
|
||||
}
|
||||
},
|
||||
"benchmark_test_profile": {
|
||||
@@ -181,7 +181,7 @@
|
||||
"CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -DLY_PARALLEL_LINK_JOBS=4",
|
||||
"CMAKE_LY_PROJECTS": "AutomatedTesting",
|
||||
"CMAKE_TARGET": "TEST_SUITE_benchmark",
|
||||
"CTEST_OPTIONS": "-L (SUITE_benchmark)",
|
||||
"CTEST_OPTIONS": "-L (SUITE_benchmark) --no-tests=error",
|
||||
"TEST_RESULTS": "True"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
"CMAKE_LY_PROJECTS": "AutomatedTesting",
|
||||
"CMAKE_TARGET": "TEST_SUITE_smoke TEST_SUITE_main",
|
||||
"CMAKE_NATIVE_BUILD_ARGS": "/m /nologo",
|
||||
"CTEST_OPTIONS": "-L \"(SUITE_smoke|SUITE_main)\" -LE \"(REQUIRES_gpu)\" -T Test",
|
||||
"CTEST_OPTIONS": "-L \"(SUITE_smoke|SUITE_main)\" -LE \"(REQUIRES_gpu)\" -T Test --no-tests=error",
|
||||
"TEST_METRICS": "True",
|
||||
"TEST_RESULTS": "True"
|
||||
}
|
||||
@@ -166,7 +166,7 @@
|
||||
"CMAKE_LY_PROJECTS": "AutomatedTesting",
|
||||
"CMAKE_TARGET": "TEST_SUITE_smoke TEST_SUITE_main",
|
||||
"CMAKE_NATIVE_BUILD_ARGS": "/m /nologo",
|
||||
"CTEST_OPTIONS": "-L \"(SUITE_smoke|SUITE_main)\" -LE \"(REQUIRES_gpu)\" -T Test",
|
||||
"CTEST_OPTIONS": "-L \"(SUITE_smoke|SUITE_main)\" -LE \"(REQUIRES_gpu)\" -T Test --no-tests=error",
|
||||
"TEST_METRICS": "True",
|
||||
"TEST_RESULTS": "True"
|
||||
}
|
||||
@@ -187,7 +187,7 @@
|
||||
"CMAKE_LY_PROJECTS": "AutomatedTesting",
|
||||
"CMAKE_TARGET": "TEST_SUITE_smoke TEST_SUITE_main",
|
||||
"CMAKE_NATIVE_BUILD_ARGS": "/m /nologo",
|
||||
"CTEST_OPTIONS": "-L \"(SUITE_smoke_REQUIRES_gpu|SUITE_main_REQUIRES_gpu)\" -T Test",
|
||||
"CTEST_OPTIONS": "-L \"(SUITE_smoke_REQUIRES_gpu|SUITE_main_REQUIRES_gpu)\" -T Test --no-tests=error",
|
||||
"TEST_METRICS": "True",
|
||||
"TEST_RESULTS": "True",
|
||||
"TEST_SCREENSHOTS": "True"
|
||||
@@ -238,7 +238,7 @@
|
||||
"CMAKE_LY_PROJECTS": "AutomatedTesting",
|
||||
"CMAKE_TARGET": "TEST_SUITE_awsi",
|
||||
"CMAKE_NATIVE_BUILD_ARGS": "/m /nologo",
|
||||
"CTEST_OPTIONS": "-L \"(SUITE_awsi)\" -T Test",
|
||||
"CTEST_OPTIONS": "-L \"(SUITE_awsi)\" -T Test --no-tests=error",
|
||||
"TEST_METRICS": "True",
|
||||
"TEST_RESULTS": "True"
|
||||
}
|
||||
@@ -257,7 +257,7 @@
|
||||
"CMAKE_LY_PROJECTS": "AutomatedTesting",
|
||||
"CMAKE_TARGET": "TEST_SUITE_periodic",
|
||||
"CMAKE_NATIVE_BUILD_ARGS": "/m /nologo",
|
||||
"CTEST_OPTIONS": "-L \"(SUITE_periodic)\" -T Test",
|
||||
"CTEST_OPTIONS": "-L \"(SUITE_periodic)\" -T Test --no-tests=error",
|
||||
"TEST_METRICS": "True",
|
||||
"TEST_RESULTS": "True"
|
||||
}
|
||||
@@ -279,7 +279,7 @@
|
||||
"CMAKE_LY_PROJECTS": "AutomatedTesting",
|
||||
"CMAKE_TARGET": "TEST_SUITE_sandbox",
|
||||
"CMAKE_NATIVE_BUILD_ARGS": "/m /nologo",
|
||||
"CTEST_OPTIONS": "-L \"(SUITE_sandbox)\" -T Test",
|
||||
"CTEST_OPTIONS": "-L \"(SUITE_sandbox)\" -T Test --no-tests=error",
|
||||
"TEST_METRICS": "True",
|
||||
"TEST_RESULTS": "True"
|
||||
}
|
||||
@@ -298,7 +298,7 @@
|
||||
"CMAKE_LY_PROJECTS": "AutomatedTesting",
|
||||
"CMAKE_TARGET": "TEST_SUITE_benchmark",
|
||||
"CMAKE_NATIVE_BUILD_ARGS": "/m /nologo",
|
||||
"CTEST_OPTIONS": "-L \"(SUITE_benchmark)\" -T Test",
|
||||
"CTEST_OPTIONS": "-L \"(SUITE_benchmark)\" -T Test --no-tests=error",
|
||||
"TEST_METRICS": "True",
|
||||
"TEST_RESULTS": "True"
|
||||
}
|
||||
|
||||
@@ -596,7 +596,7 @@ def register(engine_path: pathlib.Path = None,
|
||||
:param default_third_party_folder: default 3rd party cache folder
|
||||
:param external_subdir_engine_path: Path to the engine to use when registering an external subdirectory.
|
||||
The registration occurs in the engine.json file in this case
|
||||
:param external_subdir_engine_path: Path to the project to use when registering an external subdirectory.
|
||||
:param external_subdir_project_path: Path to the project to use when registering an external subdirectory.
|
||||
The registrations occurs in the project.json in this case
|
||||
:param remove: add/remove the entries
|
||||
:param force: force update of the engine_path for specified "engine_name" from the engine.json file
|
||||
|
||||
Reference in New Issue
Block a user