Merge remote-tracking branch 'upstream/development' into Atom/santorac/MaterialPropertyRenameInMaterialComponent

This commit is contained in:
santorac
2021-10-22 11:49:30 -07:00
62 changed files with 802 additions and 429 deletions
+3 -129
View File
@@ -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;
}
+5 -6
View File
@@ -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
View File
@@ -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;
@@ -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
@@ -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
)
@@ -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,
@@ -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);
@@ -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)
{
@@ -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);
@@ -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;
}
@@ -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;
@@ -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
@@ -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)
@@ -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;
};
+41 -50
View File
@@ -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;
};
}
+3 -3
View File
@@ -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;
@@ -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>;
@@ -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;
@@ -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);
}
}
@@ -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);
@@ -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;
@@ -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)
@@ -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)
;
}
}
@@ -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"
}
+1 -1
View File
@@ -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