diff --git a/Assets/Editor/Icons/AssetBrowser/TreeBranch_First.svg b/Assets/Editor/Icons/AssetBrowser/TreeBranch_First.svg
new file mode 100644
index 0000000000..f1d36d3e41
--- /dev/null
+++ b/Assets/Editor/Icons/AssetBrowser/TreeBranch_First.svg
@@ -0,0 +1,7 @@
+
diff --git a/Assets/Editor/Icons/AssetBrowser/TreeBranch_Last.svg b/Assets/Editor/Icons/AssetBrowser/TreeBranch_Last.svg
new file mode 100644
index 0000000000..9fc9fe52c2
--- /dev/null
+++ b/Assets/Editor/Icons/AssetBrowser/TreeBranch_Last.svg
@@ -0,0 +1,5 @@
+
diff --git a/Assets/Editor/Icons/AssetBrowser/TreeBranch_Middle.svg b/Assets/Editor/Icons/AssetBrowser/TreeBranch_Middle.svg
new file mode 100644
index 0000000000..7a61db38e0
--- /dev/null
+++ b/Assets/Editor/Icons/AssetBrowser/TreeBranch_Middle.svg
@@ -0,0 +1,6 @@
+
diff --git a/Assets/Editor/Icons/AssetBrowser/TreeBranch_OneChild.svg b/Assets/Editor/Icons/AssetBrowser/TreeBranch_OneChild.svg
new file mode 100644
index 0000000000..c6fb977c52
--- /dev/null
+++ b/Assets/Editor/Icons/AssetBrowser/TreeBranch_OneChild.svg
@@ -0,0 +1,6 @@
+
diff --git a/Code/Editor/Core/QtEditorApplication_linux.cpp b/Code/Editor/Core/QtEditorApplication_linux.cpp
index 175bef0238..2fd4ef629e 100644
--- a/Code/Editor/Core/QtEditorApplication_linux.cpp
+++ b/Code/Editor/Core/QtEditorApplication_linux.cpp
@@ -9,7 +9,7 @@
#include "QtEditorApplication.h"
#ifdef PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
-#include
+#include
#endif
namespace Editor
@@ -19,7 +19,7 @@ namespace Editor
if (GetIEditor()->IsInGameMode())
{
#ifdef PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
- AzFramework::LinuxXcbEventHandlerBus::Broadcast(&AzFramework::LinuxXcbEventHandler::HandleXcbEvent, static_cast(message));
+ AzFramework::XcbEventHandlerBus::Broadcast(&AzFramework::XcbEventHandler::HandleXcbEvent, static_cast(message));
#endif
return true;
}
diff --git a/Code/Framework/AzFramework/AzFramework/Input/Channels/InputChannelId.cpp b/Code/Framework/AzFramework/AzFramework/Input/Channels/InputChannelId.cpp
index cc6154f20c..496d89d767 100644
--- a/Code/Framework/AzFramework/AzFramework/Input/Channels/InputChannelId.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Input/Channels/InputChannelId.cpp
@@ -28,34 +28,10 @@ namespace AzFramework
}
}
- ////////////////////////////////////////////////////////////////////////////////////////////////
- InputChannelId::InputChannelId(const char* name)
- : m_crc32(name)
- {
- memset(m_name, 0, AZ_ARRAY_SIZE(m_name));
- azstrncpy(m_name, NAME_BUFFER_SIZE, name, MAX_NAME_LENGTH);
- }
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- InputChannelId::InputChannelId(const InputChannelId& other)
- : m_crc32(other.m_crc32)
- {
- memset(m_name, 0, AZ_ARRAY_SIZE(m_name));
- azstrcpy(m_name, NAME_BUFFER_SIZE, other.m_name);
- }
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- InputChannelId& InputChannelId::operator=(const InputChannelId& other)
- {
- azstrcpy(m_name, NAME_BUFFER_SIZE, other.m_name);
- m_crc32 = other.m_crc32;
- return *this;
- }
-
////////////////////////////////////////////////////////////////////////////////////////////////
const char* InputChannelId::GetName() const
{
- return m_name;
+ return m_name.c_str();
}
////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/Code/Framework/AzFramework/AzFramework/Input/Channels/InputChannelId.h b/Code/Framework/AzFramework/AzFramework/Input/Channels/InputChannelId.h
index 5c1c58d6b1..a4d8ac83eb 100644
--- a/Code/Framework/AzFramework/AzFramework/Input/Channels/InputChannelId.h
+++ b/Code/Framework/AzFramework/AzFramework/Input/Channels/InputChannelId.h
@@ -11,6 +11,7 @@
#include
#include
#include
+#include
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace AzFramework
@@ -22,8 +23,7 @@ namespace AzFramework
public:
////////////////////////////////////////////////////////////////////////////////////////////
// Constants
- static const int NAME_BUFFER_SIZE = 64;
- static const int MAX_NAME_LENGTH = NAME_BUFFER_SIZE - 1;
+ static constexpr int MAX_NAME_LENGTH = 64;
////////////////////////////////////////////////////////////////////////////////////////////
// Allocator
@@ -39,21 +39,28 @@ namespace AzFramework
////////////////////////////////////////////////////////////////////////////////////////////
//! Constructor
- //! \param[in] name Name of the input channel (will be truncated if exceeds MAX_NAME_LENGTH)
- explicit InputChannelId(const char* name = "");
+ //! \param[in] name Name of the input channel (will be ignored if exceeds MAX_NAME_LENGTH)
+ explicit constexpr InputChannelId(AZStd::string_view name = "")
+ : m_name(name)
+ , m_crc32(name)
+ {
+ }
- ////////////////////////////////////////////////////////////////////////////////////////////
- //! Copy constructor
- //! \param[in] other Another instance of the class to copy from
- InputChannelId(const InputChannelId& other);
-
- ////////////////////////////////////////////////////////////////////////////////////////////
- //! Copy assignment operator
- //! \param[in] other Another instance of the class to copy from
- InputChannelId& operator=(const InputChannelId& other);
-
- ////////////////////////////////////////////////////////////////////////////////////////////
- //! Default destructor
+ constexpr InputChannelId(const InputChannelId& other) = default;
+ constexpr InputChannelId(InputChannelId&& other) = default;
+ constexpr InputChannelId& operator=(const InputChannelId& other)
+ {
+ m_name = other.m_name;
+ m_crc32 = other.m_crc32;
+ return *this;
+ }
+ constexpr InputChannelId& operator=(InputChannelId&& other)
+ {
+ m_name = AZStd::move(other.m_name);
+ m_crc32 = AZStd::move(other.m_crc32);
+ other.m_crc32 = 0;
+ return *this;
+ }
~InputChannelId() = default;
////////////////////////////////////////////////////////////////////////////////////////////
@@ -77,7 +84,7 @@ namespace AzFramework
private:
////////////////////////////////////////////////////////////////////////////////////////////
// Variables
- char m_name[NAME_BUFFER_SIZE]; //!< Name of the input channel
+ AZStd::fixed_string m_name; //!< Name of the input channel
AZ::Crc32 m_crc32; //!< Crc32 of the input channel
};
} // namespace AzFramework
diff --git a/Code/Framework/AzFramework/AzFramework/Input/Devices/Gamepad/InputDeviceGamepad.cpp b/Code/Framework/AzFramework/AzFramework/Input/Devices/Gamepad/InputDeviceGamepad.cpp
index 95886c6871..51aa008519 100644
--- a/Code/Framework/AzFramework/AzFramework/Input/Devices/Gamepad/InputDeviceGamepad.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Input/Devices/Gamepad/InputDeviceGamepad.cpp
@@ -28,91 +28,6 @@ namespace AzFramework
return (inputDeviceId.GetNameCrc32() == IdForIndex0.GetNameCrc32());
}
- ////////////////////////////////////////////////////////////////////////////////////////////////
- const InputChannelId InputDeviceGamepad::Button::A("gamepad_button_a");
- const InputChannelId InputDeviceGamepad::Button::B("gamepad_button_b");
- const InputChannelId InputDeviceGamepad::Button::X("gamepad_button_x");
- const InputChannelId InputDeviceGamepad::Button::Y("gamepad_button_y");
- const InputChannelId InputDeviceGamepad::Button::L1("gamepad_button_l1");
- const InputChannelId InputDeviceGamepad::Button::R1("gamepad_button_r1");
- const InputChannelId InputDeviceGamepad::Button::L3("gamepad_button_l3");
- const InputChannelId InputDeviceGamepad::Button::R3("gamepad_button_r3");
- const InputChannelId InputDeviceGamepad::Button::DU("gamepad_button_d_up");
- const InputChannelId InputDeviceGamepad::Button::DD("gamepad_button_d_down");
- const InputChannelId InputDeviceGamepad::Button::DL("gamepad_button_d_left");
- const InputChannelId InputDeviceGamepad::Button::DR("gamepad_button_d_right");
- const InputChannelId InputDeviceGamepad::Button::Start("gamepad_button_start");
- const InputChannelId InputDeviceGamepad::Button::Select("gamepad_button_select");
- const AZStd::array InputDeviceGamepad::Button::All =
- {{
- A,
- B,
- X,
- Y,
- L1,
- R1,
- L3,
- R3,
- DU,
- DD,
- DL,
- DR,
- Start,
- Select
- }};
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- const InputChannelId InputDeviceGamepad::Trigger::L2("gamepad_trigger_l2");
- const InputChannelId InputDeviceGamepad::Trigger::R2("gamepad_trigger_r2");
- const AZStd::array InputDeviceGamepad::Trigger::All =
- {{
- L2,
- R2
- }};
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- const InputChannelId InputDeviceGamepad::ThumbStickAxis2D::L("gamepad_thumbstick_l");
- const InputChannelId InputDeviceGamepad::ThumbStickAxis2D::R("gamepad_thumbstick_r");
- const AZStd::array InputDeviceGamepad::ThumbStickAxis2D::All =
- {{
- L,
- R
- }};
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- const InputChannelId InputDeviceGamepad::ThumbStickAxis1D::LX("gamepad_thumbstick_l_x");
- const InputChannelId InputDeviceGamepad::ThumbStickAxis1D::LY("gamepad_thumbstick_l_y");
- const InputChannelId InputDeviceGamepad::ThumbStickAxis1D::RX("gamepad_thumbstick_r_x");
- const InputChannelId InputDeviceGamepad::ThumbStickAxis1D::RY("gamepad_thumbstick_r_y");
- const AZStd::array InputDeviceGamepad::ThumbStickAxis1D::All =
- {{
- LX,
- LY,
- RX,
- RY
- }};
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- const InputChannelId InputDeviceGamepad::ThumbStickDirection::LU("gamepad_thumbstick_l_up");
- const InputChannelId InputDeviceGamepad::ThumbStickDirection::LD("gamepad_thumbstick_l_down");
- const InputChannelId InputDeviceGamepad::ThumbStickDirection::LL("gamepad_thumbstick_l_left");
- const InputChannelId InputDeviceGamepad::ThumbStickDirection::LR("gamepad_thumbstick_l_right");
- const InputChannelId InputDeviceGamepad::ThumbStickDirection::RU("gamepad_thumbstick_r_up");
- const InputChannelId InputDeviceGamepad::ThumbStickDirection::RD("gamepad_thumbstick_r_down");
- const InputChannelId InputDeviceGamepad::ThumbStickDirection::RL("gamepad_thumbstick_r_left");
- const InputChannelId InputDeviceGamepad::ThumbStickDirection::RR("gamepad_thumbstick_r_right");
- const AZStd::array InputDeviceGamepad::ThumbStickDirection::All =
- {{
- LU,
- LD,
- LL,
- LR,
- RU,
- RD,
- RL,
- RR
- }};
-
////////////////////////////////////////////////////////////////////////////////////////////////
void InputDeviceGamepad::Reflect(AZ::ReflectContext* context)
{
diff --git a/Code/Framework/AzFramework/AzFramework/Input/Devices/Gamepad/InputDeviceGamepad.h b/Code/Framework/AzFramework/AzFramework/Input/Devices/Gamepad/InputDeviceGamepad.h
index f4fddbb24e..286b4f0df3 100644
--- a/Code/Framework/AzFramework/AzFramework/Input/Devices/Gamepad/InputDeviceGamepad.h
+++ b/Code/Framework/AzFramework/AzFramework/Input/Devices/Gamepad/InputDeviceGamepad.h
@@ -59,75 +59,115 @@ namespace AzFramework
//! All the input channel ids that identify game-pad digital button input
struct Button
{
- static const InputChannelId A; //!< The bottom diamond face button
- static const InputChannelId B; //!< The right diamond face button
- static const InputChannelId X; //!< The left diamond face button
- static const InputChannelId Y; //!< The top diamond face button
- static const InputChannelId L1; //!< The top-left shoulder bumper button
- static const InputChannelId R1; //!< The top-right shoulder bumper button
- static const InputChannelId L3; //!< The left thumb-stick click button
- static const InputChannelId R3; //!< The right thumb-stick click button
- static const InputChannelId DU; //!< The up directional pad button
- static const InputChannelId DD; //!< The down directional pad button
- static const InputChannelId DL; //!< The left directional pad button
- static const InputChannelId DR; //!< The right directional pad button
- static const InputChannelId Start; //!< The start/pause/options button
- static const InputChannelId Select; //!< The select/back button
+ static constexpr inline InputChannelId A{"gamepad_button_a"}; //!< The bottom diamond face button
+ static constexpr inline InputChannelId B{"gamepad_button_b"}; //!< The right diamond face button
+ static constexpr inline InputChannelId X{"gamepad_button_x"}; //!< The left diamond face button
+ static constexpr inline InputChannelId Y{"gamepad_button_y"}; //!< The top diamond face button
+ static constexpr inline InputChannelId L1{"gamepad_button_l1"}; //!< The top-left shoulder bumper button
+ static constexpr inline InputChannelId R1{"gamepad_button_r1"}; //!< The top-right shoulder bumper button
+ static constexpr inline InputChannelId L3{"gamepad_button_l3"}; //!< The left thumb-stick click button
+ static constexpr inline InputChannelId R3{"gamepad_button_r3"}; //!< The right thumb-stick click button
+ static constexpr inline InputChannelId DU{"gamepad_button_d_up"}; //!< The up directional pad button
+ static constexpr inline InputChannelId DD{"gamepad_button_d_down"}; //!< The down directional pad button
+ static constexpr inline InputChannelId DL{"gamepad_button_d_left"}; //!< The left directional pad button
+ static constexpr inline InputChannelId DR{"gamepad_button_d_right"}; //!< The right directional pad button
+ static constexpr inline InputChannelId Start{"gamepad_button_start"}; //!< The start/pause/options button
+ static constexpr inline InputChannelId Select{"gamepad_button_select"}; //!< The select/back button
//!< All digital game-pad button ids
- static const AZStd::array All;
+ static constexpr inline AZStd::array All
+ {
+ A,
+ B,
+ X,
+ Y,
+ L1,
+ R1,
+ L3,
+ R3,
+ DU,
+ DD,
+ DL,
+ DR,
+ Start,
+ Select
+ };
};
////////////////////////////////////////////////////////////////////////////////////////////
//! All the input channel ids that identify game-pad analog trigger input
struct Trigger
{
- static const InputChannelId L2; //!< The bottom-left shoulder trigger
- static const InputChannelId R2; //!< The bottom-right shoulder trigger
+ static constexpr inline InputChannelId L2{"gamepad_trigger_l2"}; //!< The bottom-left shoulder trigger
+ static constexpr inline InputChannelId R2{"gamepad_trigger_r2"}; //!< The bottom-right shoulder trigger
//!< All analog game-pad trigger ids
- static const AZStd::array All;
+ static constexpr inline AZStd::array All
+ {
+ L2,
+ R2
+ };
};
////////////////////////////////////////////////////////////////////////////////////////////
//! All the input channel ids that identify game-pad thumb-stick 2D axis input
struct ThumbStickAxis2D
{
- static const InputChannelId L; //!< The left-hand thumb-stick
- static const InputChannelId R; //!< The right-hand thumb-stick
+ static constexpr inline InputChannelId L{"gamepad_thumbstick_l"}; //!< The left-hand thumb-stick
+ static constexpr inline InputChannelId R{"gamepad_thumbstick_r"}; //!< The right-hand thumb-stick
//!< All game-pad thumb-stick 2D axis input channel ids
- static const AZStd::array All;
+ static constexpr inline AZStd::array All
+ {
+ L,
+ R
+ };
};
////////////////////////////////////////////////////////////////////////////////////////////
//! All the input channel ids that identify game-pad thumb-stick 1D axis input
struct ThumbStickAxis1D
{
- static const InputChannelId LX; //!< X-axis of the left-hand thumb-stick
- static const InputChannelId LY; //!< Y-axis of the left-hand thumb-stick
- static const InputChannelId RX; //!< X-axis of the right-hand thumb-stick
- static const InputChannelId RY; //!< Y-axis of the right-hand thumb-stick
+ static constexpr inline InputChannelId LX{"gamepad_thumbstick_l_x"}; //!< X-axis of the left-hand thumb-stick
+ static constexpr inline InputChannelId LY{"gamepad_thumbstick_l_y"}; //!< Y-axis of the left-hand thumb-stick
+ static constexpr inline InputChannelId RX{"gamepad_thumbstick_r_x"}; //!< X-axis of the right-hand thumb-stick
+ static constexpr inline InputChannelId RY{"gamepad_thumbstick_r_y"}; //!< Y-axis of the right-hand thumb-stick
//!< All game-pad thumb-stick 1D axis input channel ids
- static const AZStd::array All;
+ static constexpr inline AZStd::array All
+ {
+ LX,
+ LY,
+ RX,
+ RY
+ };
};
////////////////////////////////////////////////////////////////////////////////////////////
//! All the input channel ids that identify game-pad thumb-stick directional input
struct ThumbStickDirection
{
- static const InputChannelId LU; //!< Up on the left-hand thumb-stick
- static const InputChannelId LD; //!< Down on the left-hand thumb-stick
- static const InputChannelId LL; //!< Left on the left-hand thumb-stick
- static const InputChannelId LR; //!< Right on the left-hand thumb-stick
- static const InputChannelId RU; //!< Up on the left-hand thumb-stick
- static const InputChannelId RD; //!< Down on the left-hand thumb-stick
- static const InputChannelId RL; //!< Left on the left-hand thumb-stick
- static const InputChannelId RR; //!< Right on the left-hand thumb-stick
+ static constexpr inline InputChannelId LU{"gamepad_thumbstick_l_up"}; //!< Up on the left-hand thumb-stick
+ static constexpr inline InputChannelId LD{"gamepad_thumbstick_l_down"}; //!< Down on the left-hand thumb-stick
+ static constexpr inline InputChannelId LL{"gamepad_thumbstick_l_left"}; //!< Left on the left-hand thumb-stick
+ static constexpr inline InputChannelId LR{"gamepad_thumbstick_l_right"}; //!< Right on the left-hand thumb-stick
+ static constexpr inline InputChannelId RU{"gamepad_thumbstick_r_up"}; //!< Up on the left-hand thumb-stick
+ static constexpr inline InputChannelId RD{"gamepad_thumbstick_r_down"}; //!< Down on the left-hand thumb-stick
+ static constexpr inline InputChannelId RL{"gamepad_thumbstick_r_left"}; //!< Left on the left-hand thumb-stick
+ static constexpr inline InputChannelId RR{"gamepad_thumbstick_r_right"}; //!< Right on the left-hand thumb-stick
//!< All game-pad thumb-stick directional input channel ids
- static const AZStd::array All;
+ static constexpr inline AZStd::array All
+ {
+ LU,
+ LD,
+ LL,
+ LR,
+ RU,
+ RD,
+ RL,
+ RR
+ };
};
////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/Code/Framework/AzFramework/AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.cpp b/Code/Framework/AzFramework/AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.cpp
index dd84fd9633..d1117ea895 100644
--- a/Code/Framework/AzFramework/AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.cpp
@@ -24,279 +24,6 @@ namespace AzFramework
return (inputDeviceId.GetNameCrc32() == Id.GetNameCrc32());
}
- ////////////////////////////////////////////////////////////////////////////////////////////////
- // Alphanumeric Keys
- const InputChannelId InputDeviceKeyboard::Key::Alphanumeric0("keyboard_key_alphanumeric_0");
- const InputChannelId InputDeviceKeyboard::Key::Alphanumeric1("keyboard_key_alphanumeric_1");
- const InputChannelId InputDeviceKeyboard::Key::Alphanumeric2("keyboard_key_alphanumeric_2");
- const InputChannelId InputDeviceKeyboard::Key::Alphanumeric3("keyboard_key_alphanumeric_3");
- const InputChannelId InputDeviceKeyboard::Key::Alphanumeric4("keyboard_key_alphanumeric_4");
- const InputChannelId InputDeviceKeyboard::Key::Alphanumeric5("keyboard_key_alphanumeric_5");
- const InputChannelId InputDeviceKeyboard::Key::Alphanumeric6("keyboard_key_alphanumeric_6");
- const InputChannelId InputDeviceKeyboard::Key::Alphanumeric7("keyboard_key_alphanumeric_7");
- const InputChannelId InputDeviceKeyboard::Key::Alphanumeric8("keyboard_key_alphanumeric_8");
- const InputChannelId InputDeviceKeyboard::Key::Alphanumeric9("keyboard_key_alphanumeric_9");
- const InputChannelId InputDeviceKeyboard::Key::AlphanumericA("keyboard_key_alphanumeric_A");
- const InputChannelId InputDeviceKeyboard::Key::AlphanumericB("keyboard_key_alphanumeric_B");
- const InputChannelId InputDeviceKeyboard::Key::AlphanumericC("keyboard_key_alphanumeric_C");
- const InputChannelId InputDeviceKeyboard::Key::AlphanumericD("keyboard_key_alphanumeric_D");
- const InputChannelId InputDeviceKeyboard::Key::AlphanumericE("keyboard_key_alphanumeric_E");
- const InputChannelId InputDeviceKeyboard::Key::AlphanumericF("keyboard_key_alphanumeric_F");
- const InputChannelId InputDeviceKeyboard::Key::AlphanumericG("keyboard_key_alphanumeric_G");
- const InputChannelId InputDeviceKeyboard::Key::AlphanumericH("keyboard_key_alphanumeric_H");
- const InputChannelId InputDeviceKeyboard::Key::AlphanumericI("keyboard_key_alphanumeric_I");
- const InputChannelId InputDeviceKeyboard::Key::AlphanumericJ("keyboard_key_alphanumeric_J");
- const InputChannelId InputDeviceKeyboard::Key::AlphanumericK("keyboard_key_alphanumeric_K");
- const InputChannelId InputDeviceKeyboard::Key::AlphanumericL("keyboard_key_alphanumeric_L");
- const InputChannelId InputDeviceKeyboard::Key::AlphanumericM("keyboard_key_alphanumeric_M");
- const InputChannelId InputDeviceKeyboard::Key::AlphanumericN("keyboard_key_alphanumeric_N");
- const InputChannelId InputDeviceKeyboard::Key::AlphanumericO("keyboard_key_alphanumeric_O");
- const InputChannelId InputDeviceKeyboard::Key::AlphanumericP("keyboard_key_alphanumeric_P");
- const InputChannelId InputDeviceKeyboard::Key::AlphanumericQ("keyboard_key_alphanumeric_Q");
- const InputChannelId InputDeviceKeyboard::Key::AlphanumericR("keyboard_key_alphanumeric_R");
- const InputChannelId InputDeviceKeyboard::Key::AlphanumericS("keyboard_key_alphanumeric_S");
- const InputChannelId InputDeviceKeyboard::Key::AlphanumericT("keyboard_key_alphanumeric_T");
- const InputChannelId InputDeviceKeyboard::Key::AlphanumericU("keyboard_key_alphanumeric_U");
- const InputChannelId InputDeviceKeyboard::Key::AlphanumericV("keyboard_key_alphanumeric_V");
- const InputChannelId InputDeviceKeyboard::Key::AlphanumericW("keyboard_key_alphanumeric_W");
- const InputChannelId InputDeviceKeyboard::Key::AlphanumericX("keyboard_key_alphanumeric_X");
- const InputChannelId InputDeviceKeyboard::Key::AlphanumericY("keyboard_key_alphanumeric_Y");
- const InputChannelId InputDeviceKeyboard::Key::AlphanumericZ("keyboard_key_alphanumeric_Z");
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- // Edit (and escape) Keys
- const InputChannelId InputDeviceKeyboard::Key::EditBackspace("keyboard_key_edit_backspace");
- const InputChannelId InputDeviceKeyboard::Key::EditCapsLock("keyboard_key_edit_capslock");
- const InputChannelId InputDeviceKeyboard::Key::EditEnter("keyboard_key_edit_enter");
- const InputChannelId InputDeviceKeyboard::Key::EditSpace("keyboard_key_edit_space");
- const InputChannelId InputDeviceKeyboard::Key::EditTab("keyboard_key_edit_tab");
- const InputChannelId InputDeviceKeyboard::Key::Escape("keyboard_key_escape");
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- // Function Keys
- const InputChannelId InputDeviceKeyboard::Key::Function01("keyboard_key_function_F01");
- const InputChannelId InputDeviceKeyboard::Key::Function02("keyboard_key_function_F02");
- const InputChannelId InputDeviceKeyboard::Key::Function03("keyboard_key_function_F03");
- const InputChannelId InputDeviceKeyboard::Key::Function04("keyboard_key_function_F04");
- const InputChannelId InputDeviceKeyboard::Key::Function05("keyboard_key_function_F05");
- const InputChannelId InputDeviceKeyboard::Key::Function06("keyboard_key_function_F06");
- const InputChannelId InputDeviceKeyboard::Key::Function07("keyboard_key_function_F07");
- const InputChannelId InputDeviceKeyboard::Key::Function08("keyboard_key_function_F08");
- const InputChannelId InputDeviceKeyboard::Key::Function09("keyboard_key_function_F09");
- const InputChannelId InputDeviceKeyboard::Key::Function10("keyboard_key_function_F10");
- const InputChannelId InputDeviceKeyboard::Key::Function11("keyboard_key_function_F11");
- const InputChannelId InputDeviceKeyboard::Key::Function12("keyboard_key_function_F12");
- const InputChannelId InputDeviceKeyboard::Key::Function13("keyboard_key_function_F13");
- const InputChannelId InputDeviceKeyboard::Key::Function14("keyboard_key_function_F14");
- const InputChannelId InputDeviceKeyboard::Key::Function15("keyboard_key_function_F15");
- const InputChannelId InputDeviceKeyboard::Key::Function16("keyboard_key_function_F16");
- const InputChannelId InputDeviceKeyboard::Key::Function17("keyboard_key_function_F17");
- const InputChannelId InputDeviceKeyboard::Key::Function18("keyboard_key_function_F18");
- const InputChannelId InputDeviceKeyboard::Key::Function19("keyboard_key_function_F19");
- const InputChannelId InputDeviceKeyboard::Key::Function20("keyboard_key_function_F20");
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- // Modifier Keys
- const InputChannelId InputDeviceKeyboard::Key::ModifierAltL("keyboard_key_modifier_alt_l");
- const InputChannelId InputDeviceKeyboard::Key::ModifierAltR("keyboard_key_modifier_alt_r");
- const InputChannelId InputDeviceKeyboard::Key::ModifierCtrlL("keyboard_key_modifier_ctrl_l");
- const InputChannelId InputDeviceKeyboard::Key::ModifierCtrlR("keyboard_key_modifier_ctrl_r");
- const InputChannelId InputDeviceKeyboard::Key::ModifierShiftL("keyboard_key_modifier_shift_l");
- const InputChannelId InputDeviceKeyboard::Key::ModifierShiftR("keyboard_key_modifier_shift_r");
- const InputChannelId InputDeviceKeyboard::Key::ModifierSuperL("keyboard_key_modifier_super_l");
- const InputChannelId InputDeviceKeyboard::Key::ModifierSuperR("keyboard_key_modifier_super_r");
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- // Navigation Keys
- const InputChannelId InputDeviceKeyboard::Key::NavigationArrowDown("keyboard_key_navigation_arrow_down");
- const InputChannelId InputDeviceKeyboard::Key::NavigationArrowLeft("keyboard_key_navigation_arrow_left");
- const InputChannelId InputDeviceKeyboard::Key::NavigationArrowRight("keyboard_key_navigation_arrow_right");
- const InputChannelId InputDeviceKeyboard::Key::NavigationArrowUp("keyboard_key_navigation_arrow_up");
- const InputChannelId InputDeviceKeyboard::Key::NavigationDelete("keyboard_key_navigation_delete");
- const InputChannelId InputDeviceKeyboard::Key::NavigationEnd("keyboard_key_navigation_end");
- const InputChannelId InputDeviceKeyboard::Key::NavigationHome("keyboard_key_navigation_home");
- const InputChannelId InputDeviceKeyboard::Key::NavigationInsert("keyboard_key_navigation_insert");
- const InputChannelId InputDeviceKeyboard::Key::NavigationPageDown("keyboard_key_navigation_page_down");
- const InputChannelId InputDeviceKeyboard::Key::NavigationPageUp("keyboard_key_navigation_page_up");
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- // Numpad Keys
- const InputChannelId InputDeviceKeyboard::Key::NumLock("keyboard_key_num_lock");
- const InputChannelId InputDeviceKeyboard::Key::NumPad0("keyboard_key_numpad_0");
- const InputChannelId InputDeviceKeyboard::Key::NumPad1("keyboard_key_numpad_1");
- const InputChannelId InputDeviceKeyboard::Key::NumPad2("keyboard_key_numpad_2");
- const InputChannelId InputDeviceKeyboard::Key::NumPad3("keyboard_key_numpad_3");
- const InputChannelId InputDeviceKeyboard::Key::NumPad4("keyboard_key_numpad_4");
- const InputChannelId InputDeviceKeyboard::Key::NumPad5("keyboard_key_numpad_5");
- const InputChannelId InputDeviceKeyboard::Key::NumPad6("keyboard_key_numpad_6");
- const InputChannelId InputDeviceKeyboard::Key::NumPad7("keyboard_key_numpad_7");
- const InputChannelId InputDeviceKeyboard::Key::NumPad8("keyboard_key_numpad_8");
- const InputChannelId InputDeviceKeyboard::Key::NumPad9("keyboard_key_numpad_9");
- const InputChannelId InputDeviceKeyboard::Key::NumPadAdd("keyboard_key_numpad_add");
- const InputChannelId InputDeviceKeyboard::Key::NumPadDecimal("keyboard_key_numpad_decimal");
- const InputChannelId InputDeviceKeyboard::Key::NumPadDivide("keyboard_key_numpad_divide");
- const InputChannelId InputDeviceKeyboard::Key::NumPadEnter("keyboard_key_numpad_enter");
- const InputChannelId InputDeviceKeyboard::Key::NumPadMultiply("keyboard_key_numpad_multiply");
- const InputChannelId InputDeviceKeyboard::Key::NumPadSubtract("keyboard_key_numpad_subtract");
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- // Punctuation Keys
- const InputChannelId InputDeviceKeyboard::Key::PunctuationApostrophe("keyboard_key_punctuation_apostrophe");
- const InputChannelId InputDeviceKeyboard::Key::PunctuationBackslash("keyboard_key_punctuation_backslash");
- const InputChannelId InputDeviceKeyboard::Key::PunctuationBracketL("keyboard_key_punctuation_bracket_l");
- const InputChannelId InputDeviceKeyboard::Key::PunctuationBracketR("keyboard_key_punctuation_bracket_r");
- const InputChannelId InputDeviceKeyboard::Key::PunctuationComma("keyboard_key_punctuation_comma");
- const InputChannelId InputDeviceKeyboard::Key::PunctuationEquals("keyboard_key_punctuation_equals");
- const InputChannelId InputDeviceKeyboard::Key::PunctuationHyphen("keyboard_key_punctuation_hyphen");
- const InputChannelId InputDeviceKeyboard::Key::PunctuationPeriod("keyboard_key_punctuation_period");
- const InputChannelId InputDeviceKeyboard::Key::PunctuationSemicolon("keyboard_key_punctuation_semicolon");
- const InputChannelId InputDeviceKeyboard::Key::PunctuationSlash("keyboard_key_punctuation_slash");
- const InputChannelId InputDeviceKeyboard::Key::PunctuationTilde("keyboard_key_punctuation_tilde");
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- // Supplementary ISO Key
- const InputChannelId InputDeviceKeyboard::Key::SupplementaryISO("keyboard_key_supplementary_iso");
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- // Windows System Keys
- const InputChannelId InputDeviceKeyboard::Key::WindowsSystemPause("keyboard_key_windows_system_pause");
- const InputChannelId InputDeviceKeyboard::Key::WindowsSystemPrint("keyboard_key_windows_system_print");
- const InputChannelId InputDeviceKeyboard::Key::WindowsSystemScrollLock("keyboard_key_windows_system_scroll_lock");
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- const AZStd::array InputDeviceKeyboard::Key::All =
- {{
- // Alphanumeric Keys
- Alphanumeric0,
- Alphanumeric1,
- Alphanumeric2,
- Alphanumeric3,
- Alphanumeric4,
- Alphanumeric5,
- Alphanumeric6,
- Alphanumeric7,
- Alphanumeric8,
- Alphanumeric9,
- AlphanumericA,
- AlphanumericB,
- AlphanumericC,
- AlphanumericD,
- AlphanumericE,
- AlphanumericF,
- AlphanumericG,
- AlphanumericH,
- AlphanumericI,
- AlphanumericJ,
- AlphanumericK,
- AlphanumericL,
- AlphanumericM,
- AlphanumericN,
- AlphanumericO,
- AlphanumericP,
- AlphanumericQ,
- AlphanumericR,
- AlphanumericS,
- AlphanumericT,
- AlphanumericU,
- AlphanumericV,
- AlphanumericW,
- AlphanumericX,
- AlphanumericY,
- AlphanumericZ,
-
- // Edit (and escape) Keys
- EditBackspace,
- EditCapsLock,
- EditEnter,
- EditSpace,
- EditTab,
- Escape,
-
- // Function Keys
- Function01,
- Function02,
- Function03,
- Function04,
- Function05,
- Function06,
- Function07,
- Function08,
- Function09,
- Function10,
- Function11,
- Function12,
- Function13,
- Function14,
- Function15,
- Function16,
- Function17,
- Function18,
- Function19,
- Function20,
-
- // Modifier Keys
- ModifierAltL,
- ModifierAltR,
- ModifierCtrlL,
- ModifierCtrlR,
- ModifierShiftL,
- ModifierShiftR,
- ModifierSuperL,
- ModifierSuperR,
-
- // Navigation Keys
- NavigationArrowDown,
- NavigationArrowLeft,
- NavigationArrowRight,
- NavigationArrowUp,
- NavigationDelete,
- NavigationEnd,
- NavigationHome,
- NavigationInsert,
- NavigationPageDown,
- NavigationPageUp,
-
- // Numpad Keys
- NumLock,
- NumPad0,
- NumPad1,
- NumPad2,
- NumPad3,
- NumPad4,
- NumPad5,
- NumPad6,
- NumPad7,
- NumPad8,
- NumPad9,
- NumPadAdd,
- NumPadDecimal,
- NumPadDivide,
- NumPadEnter,
- NumPadMultiply,
- NumPadSubtract,
-
- // Punctuation Keys
- PunctuationApostrophe,
- PunctuationBackslash,
- PunctuationBracketL,
- PunctuationBracketR,
- PunctuationComma,
- PunctuationEquals,
- PunctuationHyphen,
- PunctuationPeriod,
- PunctuationSemicolon,
- PunctuationSlash,
- PunctuationTilde,
-
- // Supplementary ISO Key
- SupplementaryISO,
-
- // Windows System Keys
- WindowsSystemPause,
- WindowsSystemPrint,
- WindowsSystemScrollLock
- }};
-
////////////////////////////////////////////////////////////////////////////////////////////////
ModifierKeyMask GetCorrespondingModifierKeyMask(const InputChannelId& channelId)
{
diff --git a/Code/Framework/AzFramework/AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h b/Code/Framework/AzFramework/AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h
index 5588f94d69..e3c21ec326 100644
--- a/Code/Framework/AzFramework/AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h
+++ b/Code/Framework/AzFramework/AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h
@@ -94,137 +94,268 @@ namespace AzFramework
struct Key
{
// Alphanumeric Keys
- static const InputChannelId Alphanumeric0; //!< The 0 key
- static const InputChannelId Alphanumeric1; //!< The 1 key
- static const InputChannelId Alphanumeric2; //!< The 2 key
- static const InputChannelId Alphanumeric3; //!< The 3 key
- static const InputChannelId Alphanumeric4; //!< The 4 key
- static const InputChannelId Alphanumeric5; //!< The 5 key
- static const InputChannelId Alphanumeric6; //!< The 6 key
- static const InputChannelId Alphanumeric7; //!< The 7 key
- static const InputChannelId Alphanumeric8; //!< The 8 key
- static const InputChannelId Alphanumeric9; //!< The 9 key
- static const InputChannelId AlphanumericA; //!< The A key
- static const InputChannelId AlphanumericB; //!< The B key
- static const InputChannelId AlphanumericC; //!< The C key
- static const InputChannelId AlphanumericD; //!< The D key
- static const InputChannelId AlphanumericE; //!< The E key
- static const InputChannelId AlphanumericF; //!< The F key
- static const InputChannelId AlphanumericG; //!< The G key
- static const InputChannelId AlphanumericH; //!< The H key
- static const InputChannelId AlphanumericI; //!< The I key
- static const InputChannelId AlphanumericJ; //!< The J key
- static const InputChannelId AlphanumericK; //!< The K key
- static const InputChannelId AlphanumericL; //!< The L key
- static const InputChannelId AlphanumericM; //!< The M key
- static const InputChannelId AlphanumericN; //!< The N key
- static const InputChannelId AlphanumericO; //!< The O key
- static const InputChannelId AlphanumericP; //!< The P key
- static const InputChannelId AlphanumericQ; //!< The Q key
- static const InputChannelId AlphanumericR; //!< The R key
- static const InputChannelId AlphanumericS; //!< The S key
- static const InputChannelId AlphanumericT; //!< The T key
- static const InputChannelId AlphanumericU; //!< The U key
- static const InputChannelId AlphanumericV; //!< The V key
- static const InputChannelId AlphanumericW; //!< The W key
- static const InputChannelId AlphanumericX; //!< The X key
- static const InputChannelId AlphanumericY; //!< The Y key
- static const InputChannelId AlphanumericZ; //!< The Z key
+ static constexpr inline InputChannelId Alphanumeric0{"keyboard_key_alphanumeric_0"}; //!< The 0 key
+ static constexpr inline InputChannelId Alphanumeric1{"keyboard_key_alphanumeric_1"}; //!< The 1 key
+ static constexpr inline InputChannelId Alphanumeric2{"keyboard_key_alphanumeric_2"}; //!< The 2 key
+ static constexpr inline InputChannelId Alphanumeric3{"keyboard_key_alphanumeric_3"}; //!< The 3 key
+ static constexpr inline InputChannelId Alphanumeric4{"keyboard_key_alphanumeric_4"}; //!< The 4 key
+ static constexpr inline InputChannelId Alphanumeric5{"keyboard_key_alphanumeric_5"}; //!< The 5 key
+ static constexpr inline InputChannelId Alphanumeric6{"keyboard_key_alphanumeric_6"}; //!< The 6 key
+ static constexpr inline InputChannelId Alphanumeric7{"keyboard_key_alphanumeric_7"}; //!< The 7 key
+ static constexpr inline InputChannelId Alphanumeric8{"keyboard_key_alphanumeric_8"}; //!< The 8 key
+ static constexpr inline InputChannelId Alphanumeric9{"keyboard_key_alphanumeric_9"}; //!< The 9 key
+ static constexpr inline InputChannelId AlphanumericA{"keyboard_key_alphanumeric_A"}; //!< The A key
+ static constexpr inline InputChannelId AlphanumericB{"keyboard_key_alphanumeric_B"}; //!< The B key
+ static constexpr inline InputChannelId AlphanumericC{"keyboard_key_alphanumeric_C"}; //!< The C key
+ static constexpr inline InputChannelId AlphanumericD{"keyboard_key_alphanumeric_D"}; //!< The D key
+ static constexpr inline InputChannelId AlphanumericE{"keyboard_key_alphanumeric_E"}; //!< The E key
+ static constexpr inline InputChannelId AlphanumericF{"keyboard_key_alphanumeric_F"}; //!< The F key
+ static constexpr inline InputChannelId AlphanumericG{"keyboard_key_alphanumeric_G"}; //!< The G key
+ static constexpr inline InputChannelId AlphanumericH{"keyboard_key_alphanumeric_H"}; //!< The H key
+ static constexpr inline InputChannelId AlphanumericI{"keyboard_key_alphanumeric_I"}; //!< The I key
+ static constexpr inline InputChannelId AlphanumericJ{"keyboard_key_alphanumeric_J"}; //!< The J key
+ static constexpr inline InputChannelId AlphanumericK{"keyboard_key_alphanumeric_K"}; //!< The K key
+ static constexpr inline InputChannelId AlphanumericL{"keyboard_key_alphanumeric_L"}; //!< The L key
+ static constexpr inline InputChannelId AlphanumericM{"keyboard_key_alphanumeric_M"}; //!< The M key
+ static constexpr inline InputChannelId AlphanumericN{"keyboard_key_alphanumeric_N"}; //!< The N key
+ static constexpr inline InputChannelId AlphanumericO{"keyboard_key_alphanumeric_O"}; //!< The O key
+ static constexpr inline InputChannelId AlphanumericP{"keyboard_key_alphanumeric_P"}; //!< The P key
+ static constexpr inline InputChannelId AlphanumericQ{"keyboard_key_alphanumeric_Q"}; //!< The Q key
+ static constexpr inline InputChannelId AlphanumericR{"keyboard_key_alphanumeric_R"}; //!< The R key
+ static constexpr inline InputChannelId AlphanumericS{"keyboard_key_alphanumeric_S"}; //!< The S key
+ static constexpr inline InputChannelId AlphanumericT{"keyboard_key_alphanumeric_T"}; //!< The T key
+ static constexpr inline InputChannelId AlphanumericU{"keyboard_key_alphanumeric_U"}; //!< The U key
+ static constexpr inline InputChannelId AlphanumericV{"keyboard_key_alphanumeric_V"}; //!< The V key
+ static constexpr inline InputChannelId AlphanumericW{"keyboard_key_alphanumeric_W"}; //!< The W key
+ static constexpr inline InputChannelId AlphanumericX{"keyboard_key_alphanumeric_X"}; //!< The X key
+ static constexpr inline InputChannelId AlphanumericY{"keyboard_key_alphanumeric_Y"}; //!< The Y key
+ static constexpr inline InputChannelId AlphanumericZ{"keyboard_key_alphanumeric_Z"}; //!< The Z key
- // Edit (and escape) Keys
- static const InputChannelId EditBackspace; //!< The backspace key
- static const InputChannelId EditCapsLock; //!< The caps lock key
- static const InputChannelId EditEnter; //!< The enter/return key
- static const InputChannelId EditSpace; //!< The spacebar key
- static const InputChannelId EditTab; //!< The tab key
- static const InputChannelId Escape; //!< The escape key
+ // Edit {and escape} Keys
+ static constexpr inline InputChannelId EditBackspace{"keyboard_key_edit_backspace"}; //!< The backspace key
+ static constexpr inline InputChannelId EditCapsLock{"keyboard_key_edit_capslock"}; //!< The caps lock key
+ static constexpr inline InputChannelId EditEnter{"keyboard_key_edit_enter"}; //!< The enter/return key
+ static constexpr inline InputChannelId EditSpace{"keyboard_key_edit_space"}; //!< The spacebar key
+ static constexpr inline InputChannelId EditTab{"keyboard_key_edit_tab"}; //!< The tab key
+ static constexpr inline InputChannelId Escape{"keyboard_key_escape"}; //!< The escape key
// Function Keys
- static const InputChannelId Function01; //!< The F1 key
- static const InputChannelId Function02; //!< The F2 key
- static const InputChannelId Function03; //!< The F3 key
- static const InputChannelId Function04; //!< The F4 key
- static const InputChannelId Function05; //!< The F5 key
- static const InputChannelId Function06; //!< The F6 key
- static const InputChannelId Function07; //!< The F7 key
- static const InputChannelId Function08; //!< The F8 key
- static const InputChannelId Function09; //!< The F9 key
- static const InputChannelId Function10; //!< The F10 key
- static const InputChannelId Function11; //!< The F11 key
- static const InputChannelId Function12; //!< The F12 key
- static const InputChannelId Function13; //!< The F13 key
- static const InputChannelId Function14; //!< The F14 key
- static const InputChannelId Function15; //!< The F15 key
- static const InputChannelId Function16; //!< The F16 key
- static const InputChannelId Function17; //!< The F17 key
- static const InputChannelId Function18; //!< The F18 key
- static const InputChannelId Function19; //!< The F19 key
- static const InputChannelId Function20; //!< The F20 key
+ static constexpr inline InputChannelId Function01{"keyboard_key_function_F01"}; //!< The F1 key
+ static constexpr inline InputChannelId Function02{"keyboard_key_function_F02"}; //!< The F2 key
+ static constexpr inline InputChannelId Function03{"keyboard_key_function_F03"}; //!< The F3 key
+ static constexpr inline InputChannelId Function04{"keyboard_key_function_F04"}; //!< The F4 key
+ static constexpr inline InputChannelId Function05{"keyboard_key_function_F05"}; //!< The F5 key
+ static constexpr inline InputChannelId Function06{"keyboard_key_function_F06"}; //!< The F6 key
+ static constexpr inline InputChannelId Function07{"keyboard_key_function_F07"}; //!< The F7 key
+ static constexpr inline InputChannelId Function08{"keyboard_key_function_F08"}; //!< The F8 key
+ static constexpr inline InputChannelId Function09{"keyboard_key_function_F09"}; //!< The F9 key
+ static constexpr inline InputChannelId Function10{"keyboard_key_function_F10"}; //!< The F10 key
+ static constexpr inline InputChannelId Function11{"keyboard_key_function_F11"}; //!< The F11 key
+ static constexpr inline InputChannelId Function12{"keyboard_key_function_F12"}; //!< The F12 key
+ static constexpr inline InputChannelId Function13{"keyboard_key_function_F13"}; //!< The F13 key
+ static constexpr inline InputChannelId Function14{"keyboard_key_function_F14"}; //!< The F14 key
+ static constexpr inline InputChannelId Function15{"keyboard_key_function_F15"}; //!< The F15 key
+ static constexpr inline InputChannelId Function16{"keyboard_key_function_F16"}; //!< The F16 key
+ static constexpr inline InputChannelId Function17{"keyboard_key_function_F17"}; //!< The F17 key
+ static constexpr inline InputChannelId Function18{"keyboard_key_function_F18"}; //!< The F18 key
+ static constexpr inline InputChannelId Function19{"keyboard_key_function_F19"}; //!< The F19 key
+ static constexpr inline InputChannelId Function20{"keyboard_key_function_F20"}; //!< The F20 key
// Modifier Keys
- static const InputChannelId ModifierAltL; //!< The left alt/option key
- static const InputChannelId ModifierAltR; //!< The right alt/option key
- static const InputChannelId ModifierCtrlL; //!< The left control key
- static const InputChannelId ModifierCtrlR; //!< The right control key
- static const InputChannelId ModifierShiftL; //!< The left shift key
- static const InputChannelId ModifierShiftR; //!< The right shift key
- static const InputChannelId ModifierSuperL; //!< The left super (windows or apple) key
- static const InputChannelId ModifierSuperR; //!< The right super (windows or apple) key
+ static constexpr inline InputChannelId ModifierAltL{"keyboard_key_modifier_alt_l"}; //!< The left alt/option key
+ static constexpr inline InputChannelId ModifierAltR{"keyboard_key_modifier_alt_r"}; //!< The right alt/option key
+ static constexpr inline InputChannelId ModifierCtrlL{"keyboard_key_modifier_ctrl_l"}; //!< The left control key
+ static constexpr inline InputChannelId ModifierCtrlR{"keyboard_key_modifier_ctrl_r"}; //!< The right control key
+ static constexpr inline InputChannelId ModifierShiftL{"keyboard_key_modifier_shift_l"}; //!< The left shift key
+ static constexpr inline InputChannelId ModifierShiftR{"keyboard_key_modifier_shift_r"}; //!< The right shift key
+ static constexpr inline InputChannelId ModifierSuperL{"keyboard_key_modifier_super_l"}; //!< The left super {windows or apple} key
+ static constexpr inline InputChannelId ModifierSuperR{"keyboard_key_modifier_super_r"}; //!< The right super {windows or apple} key
// Navigation Keys
- static const InputChannelId NavigationArrowDown; //!< The down arrow key
- static const InputChannelId NavigationArrowLeft; //!< The left arrow key
- static const InputChannelId NavigationArrowRight; //!< The right arrow key
- static const InputChannelId NavigationArrowUp; //!< The up arrow key
- static const InputChannelId NavigationDelete; //!< The delete key
- static const InputChannelId NavigationEnd; //!< The end key
- static const InputChannelId NavigationHome; //!< The home key
- static const InputChannelId NavigationInsert; //!< The insert key
- static const InputChannelId NavigationPageDown; //!< The page down key
- static const InputChannelId NavigationPageUp; //!< The page up key
+ static constexpr inline InputChannelId NavigationArrowDown{"keyboard_key_navigation_arrow_down"}; //!< The down arrow key
+ static constexpr inline InputChannelId NavigationArrowLeft{"keyboard_key_navigation_arrow_left"}; //!< The left arrow key
+ static constexpr inline InputChannelId NavigationArrowRight{"keyboard_key_navigation_arrow_right"}; //!< The right arrow key
+ static constexpr inline InputChannelId NavigationArrowUp{"keyboard_key_navigation_arrow_up"}; //!< The up arrow key
+ static constexpr inline InputChannelId NavigationDelete{"keyboard_key_navigation_delete"}; //!< The delete key
+ static constexpr inline InputChannelId NavigationEnd{"keyboard_key_navigation_end"}; //!< The end key
+ static constexpr inline InputChannelId NavigationHome{"keyboard_key_navigation_home"}; //!< The home key
+ static constexpr inline InputChannelId NavigationInsert{"keyboard_key_navigation_insert"}; //!< The insert key
+ static constexpr inline InputChannelId NavigationPageDown{"keyboard_key_navigation_page_down"}; //!< The page down key
+ static constexpr inline InputChannelId NavigationPageUp{"keyboard_key_navigation_page_up"}; //!< The page up key
// Numpad Keys
- static const InputChannelId NumLock; //!< The num lock key (the clear key on apple keyboards)
- static const InputChannelId NumPad0; //!< The numpad 0 key
- static const InputChannelId NumPad1; //!< The numpad 1 key
- static const InputChannelId NumPad2; //!< The numpad 2 key
- static const InputChannelId NumPad3; //!< The numpad 3 key
- static const InputChannelId NumPad4; //!< The numpad 4 key
- static const InputChannelId NumPad5; //!< The numpad 5 key
- static const InputChannelId NumPad6; //!< The numpad 6 key
- static const InputChannelId NumPad7; //!< The numpad 7 key
- static const InputChannelId NumPad8; //!< The numpad 8 key
- static const InputChannelId NumPad9; //!< The numpad 9 key
- static const InputChannelId NumPadAdd; //!< The numpad add key
- static const InputChannelId NumPadDecimal; //!< The numpad decimal key
- static const InputChannelId NumPadDivide; //!< The numpad divide key
- static const InputChannelId NumPadEnter; //!< The numpad enter key
- static const InputChannelId NumPadMultiply; //!< The numpad multiply key
- static const InputChannelId NumPadSubtract; //!< The numpad subtract key
+ static constexpr inline InputChannelId NumLock{"keyboard_key_num_lock"}; //!< The num lock key {the clear key on apple keyboards}
+ static constexpr inline InputChannelId NumPad0{"keyboard_key_numpad_0"}; //!< The numpad 0 key
+ static constexpr inline InputChannelId NumPad1{"keyboard_key_numpad_1"}; //!< The numpad 1 key
+ static constexpr inline InputChannelId NumPad2{"keyboard_key_numpad_2"}; //!< The numpad 2 key
+ static constexpr inline InputChannelId NumPad3{"keyboard_key_numpad_3"}; //!< The numpad 3 key
+ static constexpr inline InputChannelId NumPad4{"keyboard_key_numpad_4"}; //!< The numpad 4 key
+ static constexpr inline InputChannelId NumPad5{"keyboard_key_numpad_5"}; //!< The numpad 5 key
+ static constexpr inline InputChannelId NumPad6{"keyboard_key_numpad_6"}; //!< The numpad 6 key
+ static constexpr inline InputChannelId NumPad7{"keyboard_key_numpad_7"}; //!< The numpad 7 key
+ static constexpr inline InputChannelId NumPad8{"keyboard_key_numpad_8"}; //!< The numpad 8 key
+ static constexpr inline InputChannelId NumPad9{"keyboard_key_numpad_9"}; //!< The numpad 9 key
+ static constexpr inline InputChannelId NumPadAdd{"keyboard_key_numpad_add"}; //!< The numpad add key
+ static constexpr inline InputChannelId NumPadDecimal{"keyboard_key_numpad_decimal"}; //!< The numpad decimal key
+ static constexpr inline InputChannelId NumPadDivide{"keyboard_key_numpad_divide"}; //!< The numpad divide key
+ static constexpr inline InputChannelId NumPadEnter{"keyboard_key_numpad_enter"}; //!< The numpad enter key
+ static constexpr inline InputChannelId NumPadMultiply{"keyboard_key_numpad_multiply"}; //!< The numpad multiply key
+ static constexpr inline InputChannelId NumPadSubtract{"keyboard_key_numpad_subtract"}; //!< The numpad subtract key
// Punctuation Keys
- static const InputChannelId PunctuationApostrophe; //!< The apostrophe key
- static const InputChannelId PunctuationBackslash; //!< The backslash key
- static const InputChannelId PunctuationBracketL; //!< The left bracket key
- static const InputChannelId PunctuationBracketR; //!< The right bracket key
- static const InputChannelId PunctuationComma; //!< The comma key
- static const InputChannelId PunctuationEquals; //!< The equals key
- static const InputChannelId PunctuationHyphen; //!< The hyphen/underscore key
- static const InputChannelId PunctuationPeriod; //!< The period key
- static const InputChannelId PunctuationSemicolon; //!< The semicolon key
- static const InputChannelId PunctuationSlash; //!< The (forward) slash key
- static const InputChannelId PunctuationTilde; //!< The tilde/grave key
+ static constexpr inline InputChannelId PunctuationApostrophe{"keyboard_key_punctuation_apostrophe"}; //!< The apostrophe key
+ static constexpr inline InputChannelId PunctuationBackslash{"keyboard_key_punctuation_backslash"}; //!< The backslash key
+ static constexpr inline InputChannelId PunctuationBracketL{"keyboard_key_punctuation_bracket_l"}; //!< The left bracket key
+ static constexpr inline InputChannelId PunctuationBracketR{"keyboard_key_punctuation_bracket_r"}; //!< The right bracket key
+ static constexpr inline InputChannelId PunctuationComma{"keyboard_key_punctuation_comma"}; //!< The comma key
+ static constexpr inline InputChannelId PunctuationEquals{"keyboard_key_punctuation_equals"}; //!< The equals key
+ static constexpr inline InputChannelId PunctuationHyphen{"keyboard_key_punctuation_hyphen"}; //!< The hyphen/underscore key
+ static constexpr inline InputChannelId PunctuationPeriod{"keyboard_key_punctuation_period"}; //!< The period key
+ static constexpr inline InputChannelId PunctuationSemicolon{"keyboard_key_punctuation_semicolon"}; //!< The semicolon key
+ static constexpr inline InputChannelId PunctuationSlash{"keyboard_key_punctuation_slash"}; //!< The {forward} slash key
+ static constexpr inline InputChannelId PunctuationTilde{"keyboard_key_punctuation_tilde"}; //!< The tilde/grave key
// Supplementary ISO Key
- static const InputChannelId SupplementaryISO; //!< The supplementary ISO layout key
+ static constexpr inline InputChannelId SupplementaryISO{"keyboard_key_supplementary_iso"}; //!< The supplementary ISO layout key
// Windows System Keys
- static const InputChannelId WindowsSystemPause; //!< The windows pause key
- static const InputChannelId WindowsSystemPrint; //!< The windows print key
- static const InputChannelId WindowsSystemScrollLock; //!< The windows scroll lock key
+ static constexpr inline InputChannelId WindowsSystemPause{"keyboard_key_windows_system_pause"}; //!< The windows pause key
+ static constexpr inline InputChannelId WindowsSystemPrint{"keyboard_key_windows_system_print"}; //!< The windows print key
+ static constexpr inline InputChannelId WindowsSystemScrollLock{"keyboard_key_windows_system_scroll_lock"}; //!< The windows scroll lock key
//!< All keyboard key ids
- static const AZStd::array All;
+ static constexpr inline AZStd::array All
+ {
+ // Alphanumeric Keys
+ Alphanumeric0,
+ Alphanumeric1,
+ Alphanumeric2,
+ Alphanumeric3,
+ Alphanumeric4,
+ Alphanumeric5,
+ Alphanumeric6,
+ Alphanumeric7,
+ Alphanumeric8,
+ Alphanumeric9,
+ AlphanumericA,
+ AlphanumericB,
+ AlphanumericC,
+ AlphanumericD,
+ AlphanumericE,
+ AlphanumericF,
+ AlphanumericG,
+ AlphanumericH,
+ AlphanumericI,
+ AlphanumericJ,
+ AlphanumericK,
+ AlphanumericL,
+ AlphanumericM,
+ AlphanumericN,
+ AlphanumericO,
+ AlphanumericP,
+ AlphanumericQ,
+ AlphanumericR,
+ AlphanumericS,
+ AlphanumericT,
+ AlphanumericU,
+ AlphanumericV,
+ AlphanumericW,
+ AlphanumericX,
+ AlphanumericY,
+ AlphanumericZ,
+
+ // Edit (and escape) Keys
+ EditBackspace,
+ EditCapsLock,
+ EditEnter,
+ EditSpace,
+ EditTab,
+ Escape,
+
+ // Function Keys
+ Function01,
+ Function02,
+ Function03,
+ Function04,
+ Function05,
+ Function06,
+ Function07,
+ Function08,
+ Function09,
+ Function10,
+ Function11,
+ Function12,
+ Function13,
+ Function14,
+ Function15,
+ Function16,
+ Function17,
+ Function18,
+ Function19,
+ Function20,
+
+ // Modifier Keys
+ ModifierAltL,
+ ModifierAltR,
+ ModifierCtrlL,
+ ModifierCtrlR,
+ ModifierShiftL,
+ ModifierShiftR,
+ ModifierSuperL,
+ ModifierSuperR,
+
+ // Navigation Keys
+ NavigationArrowDown,
+ NavigationArrowLeft,
+ NavigationArrowRight,
+ NavigationArrowUp,
+ NavigationDelete,
+ NavigationEnd,
+ NavigationHome,
+ NavigationInsert,
+ NavigationPageDown,
+ NavigationPageUp,
+
+ // Numpad Keys
+ NumLock,
+ NumPad0,
+ NumPad1,
+ NumPad2,
+ NumPad3,
+ NumPad4,
+ NumPad5,
+ NumPad6,
+ NumPad7,
+ NumPad8,
+ NumPad9,
+ NumPadAdd,
+ NumPadDecimal,
+ NumPadDivide,
+ NumPadEnter,
+ NumPadMultiply,
+ NumPadSubtract,
+
+ // Punctuation Keys
+ PunctuationApostrophe,
+ PunctuationBackslash,
+ PunctuationBracketL,
+ PunctuationBracketR,
+ PunctuationComma,
+ PunctuationEquals,
+ PunctuationHyphen,
+ PunctuationPeriod,
+ PunctuationSemicolon,
+ PunctuationSlash,
+ PunctuationTilde,
+
+ // Supplementary ISO Key
+ SupplementaryISO,
+
+ // Windows System Keys
+ WindowsSystemPause,
+ WindowsSystemPrint,
+ WindowsSystemScrollLock
+ };
};
////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/Code/Framework/AzFramework/AzFramework/Input/Devices/Motion/InputDeviceMotion.cpp b/Code/Framework/AzFramework/AzFramework/Input/Devices/Motion/InputDeviceMotion.cpp
index 34c72f20d2..c144f63d2c 100644
--- a/Code/Framework/AzFramework/AzFramework/Input/Devices/Motion/InputDeviceMotion.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Input/Devices/Motion/InputDeviceMotion.cpp
@@ -23,44 +23,6 @@ namespace AzFramework
return (inputDeviceId.GetNameCrc32() == Id.GetNameCrc32());
}
- ////////////////////////////////////////////////////////////////////////////////////////////////
- const InputChannelId InputDeviceMotion::Acceleration::Gravity("motion_acceleration_gravity");
- const InputChannelId InputDeviceMotion::Acceleration::Raw("motion_acceleration_raw");
- const InputChannelId InputDeviceMotion::Acceleration::User("motion_acceleration_user");
- const AZStd::array InputDeviceMotion::Acceleration::All =
- {{
- Gravity,
- Raw,
- User
- }};
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- const InputChannelId InputDeviceMotion::RotationRate::Raw("motion_rotation_rate_raw");
- const InputChannelId InputDeviceMotion::RotationRate::Unbiased("motion_rotation_rate_unbiased");
- const AZStd::array InputDeviceMotion::RotationRate::All =
- {{
- Raw,
- Unbiased
- }};
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- const InputChannelId InputDeviceMotion::MagneticField::North("motion_magnetic_field_north");
- const InputChannelId InputDeviceMotion::MagneticField::Raw("motion_magnetic_field_raw");
- const InputChannelId InputDeviceMotion::MagneticField::Unbiased("motion_magnetic_field_unbiased");
- const AZStd::array InputDeviceMotion::MagneticField::All =
- {{
- North,
- Raw,
- Unbiased
- }};
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- const InputChannelId InputDeviceMotion::Orientation::Current("motion_orientation_current");
- const AZStd::array InputDeviceMotion::Orientation::All =
- {{
- Current
- }};
-
////////////////////////////////////////////////////////////////////////////////////////////////
void InputDeviceMotion::Reflect(AZ::ReflectContext* context)
{
diff --git a/Code/Framework/AzFramework/AzFramework/Input/Devices/Motion/InputDeviceMotion.h b/Code/Framework/AzFramework/AzFramework/Input/Devices/Motion/InputDeviceMotion.h
index 1e020a6e02..872bd1cfa0 100644
--- a/Code/Framework/AzFramework/AzFramework/Input/Devices/Motion/InputDeviceMotion.h
+++ b/Code/Framework/AzFramework/AzFramework/Input/Devices/Motion/InputDeviceMotion.h
@@ -44,12 +44,17 @@ namespace AzFramework
//! - InputMotionSensorRequests::SetInputChannelEnabled
struct Acceleration
{
- static const InputChannelId Gravity;
- static const InputChannelId Raw;
- static const InputChannelId User;
+ static constexpr inline InputChannelId Gravity{"motion_acceleration_gravity"};
+ static constexpr inline InputChannelId Raw{"motion_acceleration_raw"};
+ static constexpr inline InputChannelId User{"motion_acceleration_user"};
//!< All acceleration input channel ids
- static const AZStd::array All;
+ static constexpr inline AZStd::array All
+ {
+ Gravity,
+ Raw,
+ User
+ };
};
////////////////////////////////////////////////////////////////////////////////////////////
@@ -60,11 +65,15 @@ namespace AzFramework
//! - InputMotionSensorRequests::SetInputChannelEnabled
struct RotationRate
{
- static const InputChannelId Raw;
- static const InputChannelId Unbiased;
+ static constexpr inline InputChannelId Raw{"motion_rotation_rate_raw"};
+ static constexpr inline InputChannelId Unbiased{"motion_rotation_rate_unbiased"};
//!< All rotation rate input channel ids
- static const AZStd::array All;
+ static constexpr inline AZStd::array All
+ {
+ Raw,
+ Unbiased
+ };
};
////////////////////////////////////////////////////////////////////////////////////////////
@@ -75,12 +84,17 @@ namespace AzFramework
//! - InputMotionSensorRequests::SetInputChannelEnabled
struct MagneticField
{
- static const InputChannelId North;
- static const InputChannelId Raw;
- static const InputChannelId Unbiased;
+ static constexpr inline InputChannelId North{"motion_magnetic_field_north"};
+ static constexpr inline InputChannelId Raw{"motion_magnetic_field_raw"};
+ static constexpr inline InputChannelId Unbiased{"motion_magnetic_field_unbiased"};
//!< All magnetic field input channel ids
- static const AZStd::array All;
+ static constexpr inline AZStd::array All
+ {
+ North,
+ Raw,
+ Unbiased
+ };
};
////////////////////////////////////////////////////////////////////////////////////////////
@@ -91,10 +105,13 @@ namespace AzFramework
//! - InputMotionSensorRequests::SetInputChannelEnabled
struct Orientation
{
- static const InputChannelId Current;
+ static constexpr inline InputChannelId Current{"motion_orientation_current"};
//!< All orientation input channel ids
- static const AZStd::array All;
+ static constexpr inline AZStd::array All
+ {
+ Current
+ };
};
////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/Code/Framework/AzFramework/AzFramework/Input/Devices/Mouse/InputDeviceMouse.cpp b/Code/Framework/AzFramework/AzFramework/Input/Devices/Mouse/InputDeviceMouse.cpp
index 2cc4573bce..e9af4cc4ce 100644
--- a/Code/Framework/AzFramework/AzFramework/Input/Devices/Mouse/InputDeviceMouse.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Input/Devices/Mouse/InputDeviceMouse.cpp
@@ -33,35 +33,6 @@ namespace AzFramework
return (inputDeviceId.GetNameCrc32() == Id.GetNameCrc32());
}
- ////////////////////////////////////////////////////////////////////////////////////////////////
- const InputChannelId InputDeviceMouse::Button::Left("mouse_button_left");
- const InputChannelId InputDeviceMouse::Button::Right("mouse_button_right");
- const InputChannelId InputDeviceMouse::Button::Middle("mouse_button_middle");
- const InputChannelId InputDeviceMouse::Button::Other1("mouse_button_other1");
- const InputChannelId InputDeviceMouse::Button::Other2("mouse_button_other2");
- const AZStd::array InputDeviceMouse::Button::All =
- {{
- Left,
- Right,
- Middle,
- Other1,
- Other2
- }};
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- const InputChannelId InputDeviceMouse::Movement::X("mouse_delta_x");
- const InputChannelId InputDeviceMouse::Movement::Y("mouse_delta_y");
- const InputChannelId InputDeviceMouse::Movement::Z("mouse_delta_z");
- const AZStd::array InputDeviceMouse::Movement::All =
- {{
- X,
- Y,
- Z
- }};
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- const InputChannelId InputDeviceMouse::SystemCursorPosition("mouse_system_cursor_position");
-
////////////////////////////////////////////////////////////////////////////////////////////////
void InputDeviceMouse::Reflect(AZ::ReflectContext* context)
{
diff --git a/Code/Framework/AzFramework/AzFramework/Input/Devices/Mouse/InputDeviceMouse.h b/Code/Framework/AzFramework/AzFramework/Input/Devices/Mouse/InputDeviceMouse.h
index 99fe5b820c..3b35e03f1b 100644
--- a/Code/Framework/AzFramework/AzFramework/Input/Devices/Mouse/InputDeviceMouse.h
+++ b/Code/Framework/AzFramework/AzFramework/Input/Devices/Mouse/InputDeviceMouse.h
@@ -66,14 +66,21 @@ namespace AzFramework
//! been implemented for windows simply to provide for backwards compatibility with CryInput.
struct Button
{
- static const InputChannelId Left; //!< The left mouse button
- static const InputChannelId Right; //!< The right mouse button
- static const InputChannelId Middle; //!< The middle mouse button
- static const InputChannelId Other1; //!< DEPRECATED: the x1 mouse button
- static const InputChannelId Other2; //!< DEPRECATED: the x2 mouse button
+ static constexpr inline InputChannelId Left{"mouse_button_left"}; //!< The left mouse button
+ static constexpr inline InputChannelId Right{"mouse_button_right"}; //!< The right mouse button
+ static constexpr inline InputChannelId Middle{"mouse_button_middle"}; //!< The middle mouse button
+ static constexpr inline InputChannelId Other1{"mouse_button_other1"}; //!< DEPRECATED: the x1 mouse button
+ static constexpr inline InputChannelId Other2{"mouse_button_other2"}; //!< DEPRECATED: the x2 mouse button
//!< All mouse button ids
- static const AZStd::array All;
+ static constexpr inline AZStd::array All
+ {
+ Left,
+ Right,
+ Middle,
+ Other1,
+ Other2
+ };
};
////////////////////////////////////////////////////////////////////////////////////////////
@@ -82,12 +89,17 @@ namespace AzFramework
//! directly correlate to the mouse position (which is queried directly from the system).
struct Movement
{
- static const InputChannelId X; //!< Raw horizontal mouse movement over the last frame
- static const InputChannelId Y; //!< Raw vertical mouse movement over the last frame
- static const InputChannelId Z; //!< Raw mouse wheel movement over the last frame
+ static constexpr inline InputChannelId X{"mouse_delta_x"}; //!< Raw horizontal mouse movement over the last frame
+ static constexpr inline InputChannelId Y{"mouse_delta_y"}; //!< Raw vertical mouse movement over the last frame
+ static constexpr inline InputChannelId Z{"mouse_delta_z"}; //!< Raw mouse wheel movement over the last frame
//!< All mouse movement ids
- static const AZStd::array All;
+ static constexpr inline AZStd::array All
+ {
+ X,
+ Y,
+ Z
+ };
};
////////////////////////////////////////////////////////////////////////////////////////////
@@ -96,7 +108,7 @@ namespace AzFramework
//! the system cursor is hidden or visible. When the system cursor has been constrained to
//! the active window values will be in the [0.0, 1.0] range, but not when unconstrained.
//! See also InputSystemCursorRequests::SetSystemCursorState and GetSystemCursorState.
- static const InputChannelId SystemCursorPosition;
+ static constexpr inline InputChannelId SystemCursorPosition{"mouse_system_cursor_position"};
////////////////////////////////////////////////////////////////////////////////////////////
// Allocator
diff --git a/Code/Framework/AzFramework/AzFramework/Input/Devices/Touch/InputDeviceTouch.cpp b/Code/Framework/AzFramework/AzFramework/Input/Devices/Touch/InputDeviceTouch.cpp
index 07d10090a3..be850e9289 100644
--- a/Code/Framework/AzFramework/AzFramework/Input/Devices/Touch/InputDeviceTouch.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Input/Devices/Touch/InputDeviceTouch.cpp
@@ -24,31 +24,6 @@ namespace AzFramework
return (inputDeviceId.GetNameCrc32() == Id.GetNameCrc32());
}
- ////////////////////////////////////////////////////////////////////////////////////////////////
- const InputChannelId InputDeviceTouch::Touch::Index0("touch_index_0");
- const InputChannelId InputDeviceTouch::Touch::Index1("touch_index_1");
- const InputChannelId InputDeviceTouch::Touch::Index2("touch_index_2");
- const InputChannelId InputDeviceTouch::Touch::Index3("touch_index_3");
- const InputChannelId InputDeviceTouch::Touch::Index4("touch_index_4");
- const InputChannelId InputDeviceTouch::Touch::Index5("touch_index_5");
- const InputChannelId InputDeviceTouch::Touch::Index6("touch_index_6");
- const InputChannelId InputDeviceTouch::Touch::Index7("touch_index_7");
- const InputChannelId InputDeviceTouch::Touch::Index8("touch_index_8");
- const InputChannelId InputDeviceTouch::Touch::Index9("touch_index_9");
- const AZStd::array InputDeviceTouch::Touch::All =
- {{
- Index0,
- Index1,
- Index2,
- Index3,
- Index4,
- Index5,
- Index6,
- Index7,
- Index8,
- Index9
- }};
-
////////////////////////////////////////////////////////////////////////////////////////////////
void InputDeviceTouch::Reflect(AZ::ReflectContext* context)
{
diff --git a/Code/Framework/AzFramework/AzFramework/Input/Devices/Touch/InputDeviceTouch.h b/Code/Framework/AzFramework/AzFramework/Input/Devices/Touch/InputDeviceTouch.h
index 6e069c44ba..d21834c22a 100644
--- a/Code/Framework/AzFramework/AzFramework/Input/Devices/Touch/InputDeviceTouch.h
+++ b/Code/Framework/AzFramework/AzFramework/Input/Devices/Touch/InputDeviceTouch.h
@@ -38,19 +38,31 @@ namespace AzFramework
//! track is arbitrary, but ten seems to be more than sufficient for most game applications.
struct Touch
{
- static const InputChannelId Index0; //!< Touch index 0
- static const InputChannelId Index1; //!< Touch index 1
- static const InputChannelId Index2; //!< Touch index 2
- static const InputChannelId Index3; //!< Touch index 3
- static const InputChannelId Index4; //!< Touch index 4
- static const InputChannelId Index5; //!< Touch index 5
- static const InputChannelId Index6; //!< Touch index 6
- static const InputChannelId Index7; //!< Touch index 7
- static const InputChannelId Index8; //!< Touch index 8
- static const InputChannelId Index9; //!< Touch index 9
+ static constexpr inline InputChannelId Index0{"touch_index_0"}; //!< Touch index 0
+ static constexpr inline InputChannelId Index1{"touch_index_1"}; //!< Touch index 1
+ static constexpr inline InputChannelId Index2{"touch_index_2"}; //!< Touch index 2
+ static constexpr inline InputChannelId Index3{"touch_index_3"}; //!< Touch index 3
+ static constexpr inline InputChannelId Index4{"touch_index_4"}; //!< Touch index 4
+ static constexpr inline InputChannelId Index5{"touch_index_5"}; //!< Touch index 5
+ static constexpr inline InputChannelId Index6{"touch_index_6"}; //!< Touch index 6
+ static constexpr inline InputChannelId Index7{"touch_index_7"}; //!< Touch index 7
+ static constexpr inline InputChannelId Index8{"touch_index_8"}; //!< Touch index 8
+ static constexpr inline InputChannelId Index9{"touch_index_9"}; //!< Touch index 9
//!< All touch input channel ids
- static const AZStd::array All;
+ static constexpr inline AZStd::array All
+ {
+ Index0,
+ Index1,
+ Index2,
+ Index3,
+ Index4,
+ Index5,
+ Index6,
+ Index7,
+ Index8,
+ Index9
+ };
};
////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/Code/Framework/AzFramework/AzFramework/Input/Devices/VirtualKeyboard/InputDeviceVirtualKeyboard.cpp b/Code/Framework/AzFramework/AzFramework/Input/Devices/VirtualKeyboard/InputDeviceVirtualKeyboard.cpp
index bc23826ebc..f3024f11ab 100644
--- a/Code/Framework/AzFramework/AzFramework/Input/Devices/VirtualKeyboard/InputDeviceVirtualKeyboard.cpp
+++ b/Code/Framework/AzFramework/AzFramework/Input/Devices/VirtualKeyboard/InputDeviceVirtualKeyboard.cpp
@@ -23,17 +23,6 @@ namespace AzFramework
return (inputDeviceId.GetNameCrc32() == Id.GetNameCrc32());
}
- ////////////////////////////////////////////////////////////////////////////////////////////////
- const InputChannelId InputDeviceVirtualKeyboard::Command::EditEnter("virtual_keyboard_edit_enter");
- const InputChannelId InputDeviceVirtualKeyboard::Command::EditClear("virtual_keyboard_edit_clear");
- const InputChannelId InputDeviceVirtualKeyboard::Command::NavigationBack("virtual_keyboard_navigation_back");
- const AZStd::array InputDeviceVirtualKeyboard::Command::All =
- {{
- EditClear,
- EditEnter,
- NavigationBack
- }};
-
////////////////////////////////////////////////////////////////////////////////////////////////
void InputDeviceVirtualKeyboard::Reflect(AZ::ReflectContext* context)
{
diff --git a/Code/Framework/AzFramework/AzFramework/Input/Devices/VirtualKeyboard/InputDeviceVirtualKeyboard.h b/Code/Framework/AzFramework/AzFramework/Input/Devices/VirtualKeyboard/InputDeviceVirtualKeyboard.h
index 43e2815875..6f62c3ec61 100644
--- a/Code/Framework/AzFramework/AzFramework/Input/Devices/VirtualKeyboard/InputDeviceVirtualKeyboard.h
+++ b/Code/Framework/AzFramework/AzFramework/Input/Devices/VirtualKeyboard/InputDeviceVirtualKeyboard.h
@@ -39,17 +39,22 @@ namespace AzFramework
struct Command
{
//!< The clear command used to indicate the user wants to clear the active text field
- static const InputChannelId EditClear;
+ static constexpr inline InputChannelId EditClear{"virtual_keyboard_edit_enter"};
//!< The enter/return/close command used to indicate the user has finished text editing
- static const InputChannelId EditEnter;
+ static constexpr inline InputChannelId EditEnter{"virtual_keyboard_edit_clear"};
//!< The back command used to indicate the user wants to navigate 'backwards'.
//!< This is specific to android devices, and does not have an ios equivalent.
- static const InputChannelId NavigationBack;
+ static constexpr inline InputChannelId NavigationBack{"virtual_keyboard_navigation_back"};
//!< All virtual keyboard command ids
- static const AZStd::array All;
+ static constexpr inline AZStd::array All
+ {
+ EditClear,
+ EditEnter,
+ NavigationBack
+ };
};
////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/Code/Framework/AzFramework/CMakeLists.txt b/Code/Framework/AzFramework/CMakeLists.txt
index 6f6e47855e..f6851f0ab8 100644
--- a/Code/Framework/AzFramework/CMakeLists.txt
+++ b/Code/Framework/AzFramework/CMakeLists.txt
@@ -95,4 +95,4 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
endif()
-endif()
\ No newline at end of file
+endif()
diff --git a/Code/Framework/AzFramework/Platform/Linux/AzFramework/Application/Application_Linux_xcb.cpp b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbApplication.cpp
similarity index 54%
rename from Code/Framework/AzFramework/Platform/Linux/AzFramework/Application/Application_Linux_xcb.cpp
rename to Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbApplication.cpp
index aaab67b2a1..7cbd9ae0e2 100644
--- a/Code/Framework/AzFramework/Platform/Linux/AzFramework/Application/Application_Linux_xcb.cpp
+++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbApplication.cpp
@@ -6,29 +6,26 @@
*
*/
-#include
-#include
-#include "Application_Linux_xcb.h"
+#include
+#include
-////////////////////////////////////////////////////////////////////////////////////////////////////
namespace AzFramework
{
-#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
////////////////////////////////////////////////////////////////////////////////////////////////
- class LinuxXcbConnectionManagerImpl
- : public LinuxXcbConnectionManagerBus::Handler
+ class XcbConnectionManagerImpl
+ : public XcbConnectionManagerBus::Handler
{
public:
- LinuxXcbConnectionManagerImpl()
+ XcbConnectionManagerImpl()
{
m_xcbConnection = xcb_connect(nullptr, nullptr);
- AZ_Error("ApplicationLinux", m_xcbConnection != nullptr, "Unable to connect to X11 Server.");
- LinuxXcbConnectionManagerBus::Handler::BusConnect();
+ AZ_Error("Application", m_xcbConnection != nullptr, "Unable to connect to X11 Server.");
+ XcbConnectionManagerBus::Handler::BusConnect();
}
- ~LinuxXcbConnectionManagerImpl()
+ ~XcbConnectionManagerImpl() override
{
- LinuxXcbConnectionManagerBus::Handler::BusDisconnect();
+ XcbConnectionManagerBus::Handler::BusDisconnect();
xcb_disconnect(m_xcbConnection);
}
@@ -42,53 +39,51 @@ namespace AzFramework
};
////////////////////////////////////////////////////////////////////////////////////////////////
- ApplicationLinux_xcb::ApplicationLinux_xcb()
+ XcbApplication::XcbApplication()
{
LinuxLifecycleEvents::Bus::Handler::BusConnect();
- m_xcbConnectionManager = AZStd::make_unique();
- if (LinuxXcbConnectionManagerInterface::Get() == nullptr)
+ m_xcbConnectionManager = AZStd::make_unique();
+ if (XcbConnectionManagerInterface::Get() == nullptr)
{
- LinuxXcbConnectionManagerInterface::Register(m_xcbConnectionManager.get());
+ XcbConnectionManagerInterface::Register(m_xcbConnectionManager.get());
}
}
////////////////////////////////////////////////////////////////////////////////////////////////
- ApplicationLinux_xcb::~ApplicationLinux_xcb()
+ XcbApplication::~XcbApplication()
{
- if (LinuxXcbConnectionManagerInterface::Get() == m_xcbConnectionManager.get())
+ if (XcbConnectionManagerInterface::Get() == m_xcbConnectionManager.get())
{
- LinuxXcbConnectionManagerInterface::Unregister(m_xcbConnectionManager.get());
+ XcbConnectionManagerInterface::Unregister(m_xcbConnectionManager.get());
}
m_xcbConnectionManager.reset();
LinuxLifecycleEvents::Bus::Handler::BusDisconnect();
}
////////////////////////////////////////////////////////////////////////////////////////////////
- void ApplicationLinux_xcb::PumpSystemEventLoopOnce()
+ void XcbApplication::PumpSystemEventLoopOnce()
{
if (xcb_connection_t* xcbConnection = m_xcbConnectionManager->GetXcbConnection())
{
if (xcb_generic_event_t* event = xcb_poll_for_event(xcbConnection))
{
- LinuxXcbEventHandlerBus::Broadcast(&LinuxXcbEventHandlerBus::Events::HandleXcbEvent, event);
+ XcbEventHandlerBus::Broadcast(&XcbEventHandlerBus::Events::HandleXcbEvent, event);
free(event);
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////
- void ApplicationLinux_xcb::PumpSystemEventLoopUntilEmpty()
+ void XcbApplication::PumpSystemEventLoopUntilEmpty()
{
if (xcb_connection_t* xcbConnection = m_xcbConnectionManager->GetXcbConnection())
{
while (xcb_generic_event_t* event = xcb_poll_for_event(xcbConnection))
{
- LinuxXcbEventHandlerBus::Broadcast(&LinuxXcbEventHandlerBus::Events::HandleXcbEvent, event);
+ XcbEventHandlerBus::Broadcast(&XcbEventHandlerBus::Events::HandleXcbEvent, event);
free(event);
}
}
}
-#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
-
} // namespace AzFramework
diff --git a/Code/Framework/AzFramework/Platform/Linux/AzFramework/Application/Application_Linux_xcb.h b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbApplication.h
similarity index 61%
rename from Code/Framework/AzFramework/Platform/Linux/AzFramework/Application/Application_Linux_xcb.h
rename to Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbApplication.h
index fbd7f165d3..f27b5dd680 100644
--- a/Code/Framework/AzFramework/Platform/Linux/AzFramework/Application/Application_Linux_xcb.h
+++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbApplication.h
@@ -5,27 +5,24 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
+
#pragma once
#include
#include
+#include
-////////////////////////////////////////////////////////////////////////////////////////////////////
namespace AzFramework
{
-
-#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- class ApplicationLinux_xcb
+ class XcbApplication
: public Application::Implementation
, public LinuxLifecycleEvents::Bus::Handler
{
public:
////////////////////////////////////////////////////////////////////////////////////////////
- AZ_CLASS_ALLOCATOR(ApplicationLinux_xcb, AZ::SystemAllocator, 0);
- ApplicationLinux_xcb();
- ~ApplicationLinux_xcb() override;
+ AZ_CLASS_ALLOCATOR(XcbApplication, AZ::SystemAllocator, 0);
+ XcbApplication();
+ ~XcbApplication() override;
////////////////////////////////////////////////////////////////////////////////////////////
// Application::Implementation
@@ -33,9 +30,6 @@ namespace AzFramework
void PumpSystemEventLoopUntilEmpty() override;
private:
- AZStd::unique_ptr m_xcbConnectionManager;
+ AZStd::unique_ptr m_xcbConnectionManager;
};
-
-#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
-
} // namespace AzFramework
diff --git a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbConnectionManager.h b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbConnectionManager.h
new file mode 100644
index 0000000000..daa5bf35af
--- /dev/null
+++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbConnectionManager.h
@@ -0,0 +1,42 @@
+/*
+ * 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
+
+#include
+#include
+#include
+
+#include
+
+namespace AzFramework
+{
+ class XcbConnectionManager
+ {
+ public:
+ AZ_RTTI(XcbConnectionManager, "{1F756E14-8D74-42FD-843C-4863307710DB}");
+
+ virtual ~XcbConnectionManager() = default;
+
+ virtual xcb_connection_t* GetXcbConnection() const = 0;
+ };
+
+ class XcbConnectionManagerBusTraits
+ : public AZ::EBusTraits
+ {
+ public:
+ //////////////////////////////////////////////////////////////////////////
+ // EBusTraits overrides
+ static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
+ static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
+ //////////////////////////////////////////////////////////////////////////
+ };
+
+ using XcbConnectionManagerBus = AZ::EBus;
+ using XcbConnectionManagerInterface = AZ::Interface;
+} // namespace AzFramework
diff --git a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbEventHandler.h b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbEventHandler.h
new file mode 100644
index 0000000000..c6307755a7
--- /dev/null
+++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbEventHandler.h
@@ -0,0 +1,40 @@
+/*
+ * 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
+
+#include
+#include
+
+#include
+
+namespace AzFramework
+{
+ class XcbEventHandler
+ {
+ public:
+ AZ_RTTI(XcbEventHandler, "{3F756E14-8D74-42FD-843C-4863307710DB}");
+
+ virtual ~XcbEventHandler() = default;
+
+ virtual void HandleXcbEvent(xcb_generic_event_t* event) = 0;
+ };
+
+ class XcbEventHandlerBusTraits
+ : public AZ::EBusTraits
+ {
+ public:
+ //////////////////////////////////////////////////////////////////////////
+ // EBusTraits overrides
+ static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
+ static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
+ //////////////////////////////////////////////////////////////////////////
+ };
+
+ using XcbEventHandlerBus = AZ::EBus;
+} // namespace AzFramework
diff --git a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.cpp b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.cpp
new file mode 100644
index 0000000000..c971c3b793
--- /dev/null
+++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.cpp
@@ -0,0 +1,271 @@
+/*
+ * 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
+#include
+#include
+#include
+
+#define explicit ExplicitIsACXXKeyword
+#include
+#undef explicit
+#include
+#include
+#include
+
+namespace AzFramework
+{
+ XcbInputDeviceKeyboard::XcbInputDeviceKeyboard(InputDeviceKeyboard& inputDevice)
+ : InputDeviceKeyboard::Implementation(inputDevice)
+ {
+ XcbEventHandlerBus::Handler::BusConnect();
+
+ auto* interface = AzFramework::XcbConnectionManagerInterface::Get();
+ if (!interface)
+ {
+ AZ_Warning("ApplicationLinux", false, "XCB interface not available");
+ return;
+ }
+
+ auto* connection = interface->GetXcbConnection();
+ if (!connection)
+ {
+ AZ_Warning("ApplicationLinux", false, "XCB connection not available");
+ return;
+ }
+
+ XcbStdFreePtr xkbUseExtensionReply{
+ xcb_xkb_use_extension_reply(connection, xcb_xkb_use_extension(connection, 1, 0), nullptr)
+ };
+ if (!xkbUseExtensionReply)
+ {
+ AZ_Warning("ApplicationLinux", false, "Failed to initialize the xkb extension");
+ return;
+ }
+ if (!xkbUseExtensionReply->supported)
+ {
+ AZ_Warning("ApplicationLinux", false, "The X server does not support the xkb extension");
+ return;
+ }
+
+ m_coreDeviceId = xkb_x11_get_core_keyboard_device_id(connection);
+
+ m_xkbContext.reset(xkb_context_new(XKB_CONTEXT_NO_FLAGS));
+ m_xkbKeymap.reset(xkb_x11_keymap_new_from_device(m_xkbContext.get(), connection, m_coreDeviceId, XKB_KEYMAP_COMPILE_NO_FLAGS));
+ m_xkbState.reset(xkb_x11_state_new_from_device(m_xkbKeymap.get(), connection, m_coreDeviceId));
+
+ m_initialized = true;
+ }
+
+ bool XcbInputDeviceKeyboard::IsConnected() const
+ {
+ auto* connection = AzFramework::XcbConnectionManagerInterface::Get()->GetXcbConnection();
+ return connection && !xcb_connection_has_error(connection);
+ }
+
+ bool XcbInputDeviceKeyboard::HasTextEntryStarted() const
+ {
+ return false;
+ }
+
+ void XcbInputDeviceKeyboard::TextEntryStart(const InputDeviceKeyboard::VirtualKeyboardOptions& options)
+ {
+ }
+
+ void XcbInputDeviceKeyboard::TextEntryStop()
+ {
+ }
+
+ void XcbInputDeviceKeyboard::TickInputDevice()
+ {
+ ProcessRawEventQueues();
+ }
+
+ void XcbInputDeviceKeyboard::HandleXcbEvent(xcb_generic_event_t* event)
+ {
+ if (!m_initialized)
+ {
+ return;
+ }
+
+ switch (event->response_type & ~0x80)
+ {
+ case XCB_KEY_PRESS:
+ {
+ auto* keyPress = reinterpret_cast(event);
+
+ const InputChannelId* key = InputChannelFromKeyEvent(keyPress->detail);
+ if (key)
+ {
+ QueueRawKeyEvent(*key, true);
+ }
+ break;
+ }
+ case XCB_KEY_RELEASE:
+ {
+ auto* keyRelease = reinterpret_cast(event);
+
+ const InputChannelId* key = InputChannelFromKeyEvent(keyRelease->detail);
+ if (key)
+ {
+ QueueRawKeyEvent(*key, false);
+ }
+ break;
+ }
+ }
+ }
+
+ [[nodiscard]] const InputChannelId* XcbInputDeviceKeyboard::InputChannelFromKeyEvent(xcb_keycode_t code) const
+ {
+ const xcb_keysym_t keysym = xkb_state_key_get_one_sym(m_xkbState.get(), code);
+
+ switch(keysym)
+ {
+ case XKB_KEY_0: return &InputDeviceKeyboard::Key::Alphanumeric0;
+ case XKB_KEY_1: return &InputDeviceKeyboard::Key::Alphanumeric1;
+ case XKB_KEY_2: return &InputDeviceKeyboard::Key::Alphanumeric2;
+ case XKB_KEY_3: return &InputDeviceKeyboard::Key::Alphanumeric3;
+ case XKB_KEY_4: return &InputDeviceKeyboard::Key::Alphanumeric4;
+ case XKB_KEY_5: return &InputDeviceKeyboard::Key::Alphanumeric5;
+ case XKB_KEY_6: return &InputDeviceKeyboard::Key::Alphanumeric6;
+ case XKB_KEY_7: return &InputDeviceKeyboard::Key::Alphanumeric7;
+ case XKB_KEY_8: return &InputDeviceKeyboard::Key::Alphanumeric8;
+ case XKB_KEY_9: return &InputDeviceKeyboard::Key::Alphanumeric9;
+ case XKB_KEY_A:
+ case XKB_KEY_a: return &InputDeviceKeyboard::Key::AlphanumericA;
+ case XKB_KEY_B:
+ case XKB_KEY_b: return &InputDeviceKeyboard::Key::AlphanumericB;
+ case XKB_KEY_C:
+ case XKB_KEY_c: return &InputDeviceKeyboard::Key::AlphanumericC;
+ case XKB_KEY_D:
+ case XKB_KEY_d: return &InputDeviceKeyboard::Key::AlphanumericD;
+ case XKB_KEY_E:
+ case XKB_KEY_e: return &InputDeviceKeyboard::Key::AlphanumericE;
+ case XKB_KEY_F:
+ case XKB_KEY_f: return &InputDeviceKeyboard::Key::AlphanumericF;
+ case XKB_KEY_G:
+ case XKB_KEY_g: return &InputDeviceKeyboard::Key::AlphanumericG;
+ case XKB_KEY_H:
+ case XKB_KEY_h: return &InputDeviceKeyboard::Key::AlphanumericH;
+ case XKB_KEY_I:
+ case XKB_KEY_i: return &InputDeviceKeyboard::Key::AlphanumericI;
+ case XKB_KEY_J:
+ case XKB_KEY_j: return &InputDeviceKeyboard::Key::AlphanumericJ;
+ case XKB_KEY_K:
+ case XKB_KEY_k: return &InputDeviceKeyboard::Key::AlphanumericK;
+ case XKB_KEY_L:
+ case XKB_KEY_l: return &InputDeviceKeyboard::Key::AlphanumericL;
+ case XKB_KEY_M:
+ case XKB_KEY_m: return &InputDeviceKeyboard::Key::AlphanumericM;
+ case XKB_KEY_N:
+ case XKB_KEY_n: return &InputDeviceKeyboard::Key::AlphanumericN;
+ case XKB_KEY_O:
+ case XKB_KEY_o: return &InputDeviceKeyboard::Key::AlphanumericO;
+ case XKB_KEY_P:
+ case XKB_KEY_p: return &InputDeviceKeyboard::Key::AlphanumericP;
+ case XKB_KEY_Q:
+ case XKB_KEY_q: return &InputDeviceKeyboard::Key::AlphanumericQ;
+ case XKB_KEY_R:
+ case XKB_KEY_r: return &InputDeviceKeyboard::Key::AlphanumericR;
+ case XKB_KEY_S:
+ case XKB_KEY_s: return &InputDeviceKeyboard::Key::AlphanumericS;
+ case XKB_KEY_T:
+ case XKB_KEY_t: return &InputDeviceKeyboard::Key::AlphanumericT;
+ case XKB_KEY_U:
+ case XKB_KEY_u: return &InputDeviceKeyboard::Key::AlphanumericU;
+ case XKB_KEY_V:
+ case XKB_KEY_v: return &InputDeviceKeyboard::Key::AlphanumericV;
+ case XKB_KEY_W:
+ case XKB_KEY_w: return &InputDeviceKeyboard::Key::AlphanumericW;
+ case XKB_KEY_X:
+ case XKB_KEY_x: return &InputDeviceKeyboard::Key::AlphanumericX;
+ case XKB_KEY_Y:
+ case XKB_KEY_y: return &InputDeviceKeyboard::Key::AlphanumericY;
+ case XKB_KEY_Z:
+ case XKB_KEY_z: return &InputDeviceKeyboard::Key::AlphanumericZ;
+ case XKB_KEY_BackSpace: return &InputDeviceKeyboard::Key::EditBackspace;
+ case XKB_KEY_Caps_Lock: return &InputDeviceKeyboard::Key::EditCapsLock;
+ case XKB_KEY_Return: return &InputDeviceKeyboard::Key::EditEnter;
+ case XKB_KEY_space: return &InputDeviceKeyboard::Key::EditSpace;
+ case XKB_KEY_Tab: return &InputDeviceKeyboard::Key::EditTab;
+ case XKB_KEY_Escape: return &InputDeviceKeyboard::Key::Escape;
+ case XKB_KEY_F1: return &InputDeviceKeyboard::Key::Function01;
+ case XKB_KEY_F2: return &InputDeviceKeyboard::Key::Function02;
+ case XKB_KEY_F3: return &InputDeviceKeyboard::Key::Function03;
+ case XKB_KEY_F4: return &InputDeviceKeyboard::Key::Function04;
+ case XKB_KEY_F5: return &InputDeviceKeyboard::Key::Function05;
+ case XKB_KEY_F6: return &InputDeviceKeyboard::Key::Function06;
+ case XKB_KEY_F7: return &InputDeviceKeyboard::Key::Function07;
+ case XKB_KEY_F8: return &InputDeviceKeyboard::Key::Function08;
+ case XKB_KEY_F9: return &InputDeviceKeyboard::Key::Function09;
+ case XKB_KEY_F10: return &InputDeviceKeyboard::Key::Function10;
+ case XKB_KEY_F11: return &InputDeviceKeyboard::Key::Function11;
+ case XKB_KEY_F12: return &InputDeviceKeyboard::Key::Function12;
+ case XKB_KEY_F13: return &InputDeviceKeyboard::Key::Function13;
+ case XKB_KEY_F14: return &InputDeviceKeyboard::Key::Function14;
+ case XKB_KEY_F15: return &InputDeviceKeyboard::Key::Function15;
+ case XKB_KEY_F16: return &InputDeviceKeyboard::Key::Function16;
+ case XKB_KEY_F17: return &InputDeviceKeyboard::Key::Function17;
+ case XKB_KEY_F18: return &InputDeviceKeyboard::Key::Function18;
+ case XKB_KEY_F19: return &InputDeviceKeyboard::Key::Function19;
+ case XKB_KEY_F20: return &InputDeviceKeyboard::Key::Function20;
+ case XKB_KEY_Alt_L: return &InputDeviceKeyboard::Key::ModifierAltL;
+ case XKB_KEY_Alt_R: return &InputDeviceKeyboard::Key::ModifierAltR;
+ case XKB_KEY_Control_L: return &InputDeviceKeyboard::Key::ModifierCtrlL;
+ case XKB_KEY_Control_R: return &InputDeviceKeyboard::Key::ModifierCtrlR;
+ case XKB_KEY_Shift_L: return &InputDeviceKeyboard::Key::ModifierShiftL;
+ case XKB_KEY_Shift_R: return &InputDeviceKeyboard::Key::ModifierShiftR;
+ case XKB_KEY_Super_L: return &InputDeviceKeyboard::Key::ModifierSuperL;
+ case XKB_KEY_Super_R: return &InputDeviceKeyboard::Key::ModifierSuperR;
+ case XKB_KEY_Down: return &InputDeviceKeyboard::Key::NavigationArrowDown;
+ case XKB_KEY_Left: return &InputDeviceKeyboard::Key::NavigationArrowLeft;
+ case XKB_KEY_Right: return &InputDeviceKeyboard::Key::NavigationArrowRight;
+ case XKB_KEY_Up: return &InputDeviceKeyboard::Key::NavigationArrowUp;
+ case XKB_KEY_Delete: return &InputDeviceKeyboard::Key::NavigationDelete;
+ case XKB_KEY_End: return &InputDeviceKeyboard::Key::NavigationEnd;
+ case XKB_KEY_Home: return &InputDeviceKeyboard::Key::NavigationHome;
+ case XKB_KEY_Insert: return &InputDeviceKeyboard::Key::NavigationInsert;
+ case XKB_KEY_Page_Down: return &InputDeviceKeyboard::Key::NavigationPageDown;
+ case XKB_KEY_Page_Up: return &InputDeviceKeyboard::Key::NavigationPageUp;
+ case XKB_KEY_Num_Lock: return &InputDeviceKeyboard::Key::NumLock;
+ case XKB_KEY_KP_0: return &InputDeviceKeyboard::Key::NumPad0;
+ case XKB_KEY_KP_1: return &InputDeviceKeyboard::Key::NumPad1;
+ case XKB_KEY_KP_2: return &InputDeviceKeyboard::Key::NumPad2;
+ case XKB_KEY_KP_3: return &InputDeviceKeyboard::Key::NumPad3;
+ case XKB_KEY_KP_4: return &InputDeviceKeyboard::Key::NumPad4;
+ case XKB_KEY_KP_5: return &InputDeviceKeyboard::Key::NumPad5;
+ case XKB_KEY_KP_6: return &InputDeviceKeyboard::Key::NumPad6;
+ case XKB_KEY_KP_7: return &InputDeviceKeyboard::Key::NumPad7;
+ case XKB_KEY_KP_8: return &InputDeviceKeyboard::Key::NumPad8;
+ case XKB_KEY_KP_9: return &InputDeviceKeyboard::Key::NumPad9;
+ case XKB_KEY_KP_Add: return &InputDeviceKeyboard::Key::NumPadAdd;
+ case XKB_KEY_KP_Decimal: return &InputDeviceKeyboard::Key::NumPadDecimal;
+ case XKB_KEY_KP_Divide: return &InputDeviceKeyboard::Key::NumPadDivide;
+ case XKB_KEY_KP_Enter: return &InputDeviceKeyboard::Key::NumPadEnter;
+ case XKB_KEY_KP_Multiply: return &InputDeviceKeyboard::Key::NumPadMultiply;
+ case XKB_KEY_KP_Subtract: return &InputDeviceKeyboard::Key::NumPadSubtract;
+ case XKB_KEY_apostrophe: return &InputDeviceKeyboard::Key::PunctuationApostrophe;
+ case XKB_KEY_backslash: return &InputDeviceKeyboard::Key::PunctuationBackslash;
+ case XKB_KEY_bracketleft: return &InputDeviceKeyboard::Key::PunctuationBracketL;
+ case XKB_KEY_bracketright: return &InputDeviceKeyboard::Key::PunctuationBracketR;
+ case XKB_KEY_comma: return &InputDeviceKeyboard::Key::PunctuationComma;
+ case XKB_KEY_equal: return &InputDeviceKeyboard::Key::PunctuationEquals;
+ case XKB_KEY_hyphen: return &InputDeviceKeyboard::Key::PunctuationHyphen;
+ case XKB_KEY_period: return &InputDeviceKeyboard::Key::PunctuationPeriod;
+ case XKB_KEY_semicolon: return &InputDeviceKeyboard::Key::PunctuationSemicolon;
+ case XKB_KEY_slash: return &InputDeviceKeyboard::Key::PunctuationSlash;
+ case XKB_KEY_grave:
+ case XKB_KEY_asciitilde: return &InputDeviceKeyboard::Key::PunctuationTilde;
+ case XKB_KEY_ISO_Group_Shift: return &InputDeviceKeyboard::Key::SupplementaryISO;
+ case XKB_KEY_Pause: return &InputDeviceKeyboard::Key::WindowsSystemPause;
+ case XKB_KEY_Print: return &InputDeviceKeyboard::Key::WindowsSystemPrint;
+ case XKB_KEY_Scroll_Lock: return &InputDeviceKeyboard::Key::WindowsSystemScrollLock;
+ default: return nullptr;
+ }
+ }
+} // namespace AzFramework
diff --git a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.h b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.h
new file mode 100644
index 0000000000..de65941a67
--- /dev/null
+++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInputDeviceKeyboard.h
@@ -0,0 +1,46 @@
+/*
+ * 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
+#include
+#include
+
+#include
+#include
+
+namespace AzFramework
+{
+ class XcbInputDeviceKeyboard
+ : public InputDeviceKeyboard::Implementation
+ , public XcbEventHandlerBus::Handler
+ {
+ public:
+ AZ_CLASS_ALLOCATOR(XcbInputDeviceKeyboard, AZ::SystemAllocator, 0);
+
+ using InputDeviceKeyboard::Implementation::Implementation;
+ XcbInputDeviceKeyboard(InputDeviceKeyboard& inputDevice);
+
+ bool IsConnected() const override;
+
+ bool HasTextEntryStarted() const override;
+ void TextEntryStart(const InputDeviceKeyboard::VirtualKeyboardOptions& options) override;
+ void TextEntryStop() override;
+ void TickInputDevice() override;
+
+ void HandleXcbEvent(xcb_generic_event_t* event) override;
+
+ private:
+ [[nodiscard]] const InputChannelId* InputChannelFromKeyEvent(xcb_keycode_t code) const;
+
+ XcbUniquePtr m_xkbContext;
+ XcbUniquePtr m_xkbKeymap;
+ XcbUniquePtr m_xkbState;
+ int m_coreDeviceId{-1};
+ bool m_initialized{false};
+ };
+} // namespace AzFramework
diff --git a/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInterface.h b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInterface.h
new file mode 100644
index 0000000000..838048b174
--- /dev/null
+++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbInterface.h
@@ -0,0 +1,38 @@
+/*
+ * 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
+
+#include
+
+#include
+
+namespace AzFramework
+{
+ // @brief Wrap a function pointer in a type
+ // This serves as a convenient way to wrap a function pointer in a given
+ // type. That type can then be used in a `unique_ptr` or `shared_ptr`.
+ // Using a type instead of a function pointer by value prevents the need to
+ // copy the pointer when copying the smart poiner.
+ template
+ struct XcbDeleterFreeFunctionWrapper
+ {
+ using value_type = decltype(Callable);
+ static constexpr value_type s_value = Callable;
+ constexpr operator value_type() const noexcept
+ {
+ return s_value;
+ }
+ };
+
+ template
+ using XcbUniquePtr = AZStd::unique_ptr>;
+
+ template
+ using XcbStdFreePtr = XcbUniquePtr;
+} // namespace AzFramework
diff --git a/Code/Framework/AzFramework/Platform/Linux/AzFramework/Windowing/NativeWindow_Linux_xcb.cpp b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.cpp
similarity index 85%
rename from Code/Framework/AzFramework/Platform/Linux/AzFramework/Windowing/NativeWindow_Linux_xcb.cpp
rename to Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.cpp
index cfc0222214..6ab97fd616 100644
--- a/Code/Framework/AzFramework/Platform/Linux/AzFramework/Windowing/NativeWindow_Linux_xcb.cpp
+++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.cpp
@@ -6,41 +6,37 @@
*
*/
-#include
#include
#include
-#include
+#include
+#include
-#include "NativeWindow_Linux_xcb.h"
+#include
namespace AzFramework
{
-#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
-
- [[maybe_unused]] const char LinuxXcbErrorWindow[] = "NativeWindow_Linux_xcb";
+ [[maybe_unused]] const char XcbErrorWindow[] = "XcbNativeWindow";
static constexpr uint8_t s_XcbFormatDataSize = 32; // Format indicator for xcb for client messages
static constexpr uint16_t s_DefaultXcbWindowBorderWidth = 4; // The default border with in pixels if a border was specified
static constexpr uint8_t s_XcbResponseTypeMask = 0x7f; // Mask to extract the specific event type from an xcb event
////////////////////////////////////////////////////////////////////////////////////////////////
- NativeWindowImpl_Linux_xcb::NativeWindowImpl_Linux_xcb()
+ XcbNativeWindow::XcbNativeWindow()
: NativeWindow::Implementation()
{
- if (auto xcbConnectionManager = AzFramework::LinuxXcbConnectionManagerInterface::Get();
+ if (auto xcbConnectionManager = AzFramework::XcbConnectionManagerInterface::Get();
xcbConnectionManager != nullptr)
{
m_xcbConnection = xcbConnectionManager->GetXcbConnection();
}
- AZ_Error(LinuxXcbErrorWindow, m_xcbConnection != nullptr, "Unable to get XCB Connection");
+ AZ_Error(XcbErrorWindow, m_xcbConnection != nullptr, "Unable to get XCB Connection");
}
////////////////////////////////////////////////////////////////////////////////////////////////
- NativeWindowImpl_Linux_xcb::~NativeWindowImpl_Linux_xcb()
- {
- }
+ XcbNativeWindow::~XcbNativeWindow() = default;
////////////////////////////////////////////////////////////////////////////////////////////////
- void NativeWindowImpl_Linux_xcb::InitWindow(const AZStd::string& title,
+ void XcbNativeWindow::InitWindow(const AZStd::string& title,
const WindowGeometry& geometry,
const WindowStyleMasks& styleMasks)
{
@@ -98,13 +94,13 @@ namespace AzFramework
xcb_intern_atom_cookie_t cookieProtocol = xcb_intern_atom(m_xcbConnection, 1, strlen(wmProtocolString), wmProtocolString);
xcb_intern_atom_reply_t* replyProtocol = xcb_intern_atom_reply(m_xcbConnection, cookieProtocol, nullptr);
- AZ_Error(LinuxXcbErrorWindow, replyProtocol != nullptr, "Unable to query xcb '%s' atom", wmProtocolString);
+ AZ_Error(XcbErrorWindow, replyProtocol != nullptr, "Unable to query xcb '%s' atom", wmProtocolString);
m_xcbAtomProtocols = replyProtocol->atom;
const static char* wmDeleteWindowString = "WM_DELETE_WINDOW";
xcb_intern_atom_cookie_t cookieDeleteWindow = xcb_intern_atom(m_xcbConnection, 0, strlen(wmDeleteWindowString), wmDeleteWindowString);
xcb_intern_atom_reply_t* replyDeleteWindow = xcb_intern_atom_reply(m_xcbConnection, cookieDeleteWindow, nullptr);
- AZ_Error(LinuxXcbErrorWindow, replyDeleteWindow != nullptr, "Unable to query xcb '%s' atom", wmDeleteWindowString);
+ AZ_Error(XcbErrorWindow, replyDeleteWindow != nullptr, "Unable to query xcb '%s' atom", wmDeleteWindowString);
m_xcbAtomDeleteWindow = replyDeleteWindow->atom;
xcbCheckResult = xcb_change_property_checked(m_xcbConnection,
@@ -123,9 +119,9 @@ namespace AzFramework
}
////////////////////////////////////////////////////////////////////////////////////////////////
- void NativeWindowImpl_Linux_xcb::Activate()
+ void XcbNativeWindow::Activate()
{
- LinuxXcbEventHandlerBus::Handler::BusConnect();
+ XcbEventHandlerBus::Handler::BusConnect();
if (!m_activated) // nothing to do if window was already activated
{
@@ -137,7 +133,7 @@ namespace AzFramework
}
////////////////////////////////////////////////////////////////////////////////////////////////
- void NativeWindowImpl_Linux_xcb::Deactivate()
+ void XcbNativeWindow::Deactivate()
{
if (m_activated) // nothing to do if window was already deactivated
{
@@ -148,17 +144,17 @@ namespace AzFramework
xcb_unmap_window(m_xcbConnection, m_xcbWindow);
xcb_flush(m_xcbConnection);
}
- LinuxXcbEventHandlerBus::Handler::BusDisconnect();
+ XcbEventHandlerBus::Handler::BusDisconnect();
}
////////////////////////////////////////////////////////////////////////////////////////////////
- NativeWindowHandle NativeWindowImpl_Linux_xcb::GetWindowHandle() const
+ NativeWindowHandle XcbNativeWindow::GetWindowHandle() const
{
return reinterpret_cast(m_xcbWindow);
}
////////////////////////////////////////////////////////////////////////////////////////////////
- void NativeWindowImpl_Linux_xcb::SetWindowTitle(const AZStd::string& title)
+ void XcbNativeWindow::SetWindowTitle(const AZStd::string& title)
{
xcb_void_cookie_t xcbCheckResult;
xcbCheckResult = xcb_change_property(m_xcbConnection,
@@ -173,7 +169,7 @@ namespace AzFramework
}
////////////////////////////////////////////////////////////////////////////////////////////////
- void NativeWindowImpl_Linux_xcb::ResizeClientArea(WindowSize clientAreaSize)
+ void XcbNativeWindow::ResizeClientArea(WindowSize clientAreaSize)
{
const uint32_t values[] = { clientAreaSize.m_width, clientAreaSize.m_height };
@@ -184,7 +180,7 @@ namespace AzFramework
}
////////////////////////////////////////////////////////////////////////////////////////////////
- uint32_t NativeWindowImpl_Linux_xcb::GetDisplayRefreshRate() const
+ uint32_t XcbNativeWindow::GetDisplayRefreshRate() const
{
// [GFX TODO][GHI - 2678]
// Using 60 for now until proper support is added
@@ -192,7 +188,7 @@ namespace AzFramework
}
////////////////////////////////////////////////////////////////////////////////////////////////
- bool NativeWindowImpl_Linux_xcb::ValidateXcbResult(xcb_void_cookie_t cookie)
+ bool XcbNativeWindow::ValidateXcbResult(xcb_void_cookie_t cookie)
{
bool result = true;
if (xcb_generic_error_t* error = xcb_request_check(m_xcbConnection, cookie))
@@ -204,7 +200,7 @@ namespace AzFramework
}
////////////////////////////////////////////////////////////////////////////////////////////////
- void NativeWindowImpl_Linux_xcb::HandleXcbEvent(xcb_generic_event_t* event)
+ void XcbNativeWindow::HandleXcbEvent(xcb_generic_event_t* event)
{
switch (event->response_type & s_XcbResponseTypeMask)
{
@@ -233,7 +229,7 @@ namespace AzFramework
}
////////////////////////////////////////////////////////////////////////////////////////////////
- void NativeWindowImpl_Linux_xcb::WindowSizeChanged(const uint32_t width, const uint32_t height)
+ void XcbNativeWindow::WindowSizeChanged(const uint32_t width, const uint32_t height)
{
if (m_width != width || m_height != height)
{
@@ -246,7 +242,4 @@ namespace AzFramework
}
}
}
-
-#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
-
} // namespace AzFramework
diff --git a/Code/Framework/AzFramework/Platform/Linux/AzFramework/Windowing/NativeWindow_Linux_xcb.h b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.h
similarity index 78%
rename from Code/Framework/AzFramework/Platform/Linux/AzFramework/Windowing/NativeWindow_Linux_xcb.h
rename to Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.h
index 40181395e4..36737e24e8 100644
--- a/Code/Framework/AzFramework/Platform/Linux/AzFramework/Windowing/NativeWindow_Linux_xcb.h
+++ b/Code/Framework/AzFramework/Platform/Common/Xcb/AzFramework/XcbNativeWindow.h
@@ -5,24 +5,25 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
+
#pragma once
-#include
#include
#include
+#include
+
#include
namespace AzFramework
{
-#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
- class NativeWindowImpl_Linux_xcb final
+ class XcbNativeWindow final
: public NativeWindow::Implementation
- , public LinuxXcbEventHandlerBus::Handler
+ , public XcbEventHandlerBus::Handler
{
public:
- AZ_CLASS_ALLOCATOR(NativeWindowImpl_Linux_xcb, AZ::SystemAllocator, 0);
- NativeWindowImpl_Linux_xcb();
- ~NativeWindowImpl_Linux_xcb() override;
+ AZ_CLASS_ALLOCATOR(XcbNativeWindow, AZ::SystemAllocator, 0);
+ XcbNativeWindow();
+ ~XcbNativeWindow() override;
////////////////////////////////////////////////////////////////////////////////////////////
// NativeWindow::Implementation
@@ -37,7 +38,7 @@ namespace AzFramework
uint32_t GetDisplayRefreshRate() const override;
////////////////////////////////////////////////////////////////////////////////////////////
- // LinuxXcbEventHandlerBus::Handler
+ // XcbEventHandlerBus::Handler
void HandleXcbEvent(xcb_generic_event_t* event) override;
private:
@@ -49,6 +50,4 @@ namespace AzFramework
xcb_atom_t m_xcbAtomProtocols;
xcb_atom_t m_xcbAtomDeleteWindow;
};
-#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
-
} // namespace AzFramework
diff --git a/Code/Framework/AzFramework/Platform/Common/Xcb/azframework_xcb_files.cmake b/Code/Framework/AzFramework/Platform/Common/Xcb/azframework_xcb_files.cmake
new file mode 100644
index 0000000000..68de710fa1
--- /dev/null
+++ b/Code/Framework/AzFramework/Platform/Common/Xcb/azframework_xcb_files.cmake
@@ -0,0 +1,18 @@
+#
+# 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
+#
+#
+
+set(FILES
+ AzFramework/XcbApplication.cpp
+ AzFramework/XcbApplication.h
+ AzFramework/XcbConnectionManager.h
+ AzFramework/XcbInputDeviceKeyboard.cpp
+ AzFramework/XcbInputDeviceKeyboard.h
+ AzFramework/XcbInterface.h
+ AzFramework/XcbNativeWindow.cpp
+ AzFramework/XcbNativeWindow.h
+)
diff --git a/Code/Framework/AzFramework/Platform/Linux/AzFramework/API/ApplicationAPI_Linux.h b/Code/Framework/AzFramework/Platform/Linux/AzFramework/API/ApplicationAPI_Linux.h
index 833f4019f8..adf3ee0bdd 100644
--- a/Code/Framework/AzFramework/Platform/Linux/AzFramework/API/ApplicationAPI_Linux.h
+++ b/Code/Framework/AzFramework/Platform/Linux/AzFramework/API/ApplicationAPI_Linux.h
@@ -12,10 +12,6 @@
#include
#include
-#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
-#include
-#endif // LY_COMPILE_DEFINITIONS
-
namespace AzFramework
{
class LinuxLifecycleEvents
@@ -30,54 +26,4 @@ namespace AzFramework
using Bus = AZ::EBus;
};
-
-#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
- class LinuxXcbConnectionManager
- {
- public:
- AZ_RTTI(LinuxXcbConnectionManager, "{1F756E14-8D74-42FD-843C-4863307710DB}");
-
- virtual ~LinuxXcbConnectionManager() = default;
-
- virtual xcb_connection_t* GetXcbConnection() const = 0;
- };
-
- class LinuxXcbConnectionManagerBusTraits
- : public AZ::EBusTraits
- {
- public:
- //////////////////////////////////////////////////////////////////////////
- // EBusTraits overrides
- static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
- static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
- //////////////////////////////////////////////////////////////////////////
- };
-
- using LinuxXcbConnectionManagerBus = AZ::EBus;
- using LinuxXcbConnectionManagerInterface = AZ::Interface;
-
- class LinuxXcbEventHandler
- {
- public:
- AZ_RTTI(LinuxXcbEventHandler, "{3F756E14-8D74-42FD-843C-4863307710DB}");
-
- virtual ~LinuxXcbEventHandler() = default;
-
- virtual void HandleXcbEvent(xcb_generic_event_t* event) = 0;
- };
-
- class LinuxXcbEventHandlerBusTraits
- : public AZ::EBusTraits
- {
- public:
- //////////////////////////////////////////////////////////////////////////
- // EBusTraits overrides
- static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
- static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
- //////////////////////////////////////////////////////////////////////////
- };
-
- using LinuxXcbEventHandlerBus = AZ::EBus;
-
-#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
} // namespace AzFramework
diff --git a/Code/Framework/AzFramework/Platform/Linux/AzFramework/Application/Application_Linux.cpp b/Code/Framework/AzFramework/Platform/Linux/AzFramework/Application/Application_Linux.cpp
index 59602fe788..158240210e 100644
--- a/Code/Framework/AzFramework/Platform/Linux/AzFramework/Application/Application_Linux.cpp
+++ b/Code/Framework/AzFramework/Platform/Linux/AzFramework/Application/Application_Linux.cpp
@@ -8,7 +8,9 @@
#include
-#include "Application_Linux_xcb.h"
+#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
+#include
+#endif
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace AzFramework
@@ -17,7 +19,7 @@ namespace AzFramework
Application::Implementation* Application::Implementation::Create()
{
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
- return aznew ApplicationLinux_xcb();
+ return aznew XcbApplication();
#elif PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND
#error "Linux Window Manager Wayland not supported."
return nullptr;
diff --git a/Code/Framework/AzFramework/Platform/Linux/AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard_Linux.cpp b/Code/Framework/AzFramework/Platform/Linux/AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard_Linux.cpp
new file mode 100644
index 0000000000..d1f90c3052
--- /dev/null
+++ b/Code/Framework/AzFramework/Platform/Linux/AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard_Linux.cpp
@@ -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
+ *
+ */
+
+#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
+#include
+#endif
+
+namespace AzFramework
+{
+ InputDeviceKeyboard::Implementation* InputDeviceKeyboard::Implementation::Create(InputDeviceKeyboard& inputDevice)
+ {
+#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
+ return aznew XcbInputDeviceKeyboard(inputDevice);
+#elif PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND
+ #error "Linux Window Manager Wayland not supported."
+ return nullptr;
+#else
+ #error "Linux Window Manager not recognized."
+ return nullptr;
+#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
+ }
+} // namespace AzFramework
diff --git a/Code/Framework/AzFramework/Platform/Linux/AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard_xcb.cpp b/Code/Framework/AzFramework/Platform/Linux/AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard_xcb.cpp
deleted file mode 100644
index 8ff4c72d42..0000000000
--- a/Code/Framework/AzFramework/Platform/Linux/AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard_xcb.cpp
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * 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
-#include
-#include
-
-#define explicit ExplicitIsACXXKeyword
-#include
-#undef explicit
-#include
-#include
-#include
-
-namespace AzFramework
-{
- class InputDeviceKeyboardXcb
- : public InputDeviceKeyboard::Implementation
- , public LinuxXcbEventHandlerBus::Handler
- {
- public:
- AZ_CLASS_ALLOCATOR(InputDeviceKeyboardXcb, AZ::SystemAllocator, 0);
-
- using InputDeviceKeyboard::Implementation::Implementation;
- InputDeviceKeyboardXcb(InputDeviceKeyboard& inputDevice)
- : InputDeviceKeyboard::Implementation(inputDevice)
- {
- LinuxXcbEventHandlerBus::Handler::BusConnect();
-
- auto* interface = AzFramework::LinuxXcbConnectionManagerInterface::Get();
- if (!interface)
- {
- AZ_Warning("ApplicationLinux", false, "XCB interface not available");
- return;
- }
-
- auto* connection = AzFramework::LinuxXcbConnectionManagerInterface::Get()->GetXcbConnection();
- if (!connection)
- {
- AZ_Warning("ApplicationLinux", false, "XCB connection not available");
- return;
- }
-
- AZStd::unique_ptr> xkbUseExtensionReply{
- xcb_xkb_use_extension_reply(connection, xcb_xkb_use_extension(connection, 1, 0), nullptr)
- };
- if (!xkbUseExtensionReply)
- {
- AZ_Warning("ApplicationLinux", false, "Failed to initialize the xkb extension");
- return;
- }
- if (!xkbUseExtensionReply->supported)
- {
- AZ_Warning("ApplicationLinux", false, "The X server does not support the xkb extension");
- return;
- }
-
- m_coreDeviceId = xkb_x11_get_core_keyboard_device_id(connection);
-
- m_xkbContext.reset(xkb_context_new(XKB_CONTEXT_NO_FLAGS));
- m_xkbKeymap.reset(xkb_x11_keymap_new_from_device(m_xkbContext.get(), connection, m_coreDeviceId, XKB_KEYMAP_COMPILE_NO_FLAGS));
- m_xkbState.reset(xkb_x11_state_new_from_device(m_xkbKeymap.get(), connection, m_coreDeviceId));
-
- m_initialized = true;
- }
-
- bool IsConnected() const override
- {
- return m_initialized;
- }
-
- bool HasTextEntryStarted() const override
- {
- return false;
- }
-
- void TextEntryStart(const InputDeviceKeyboard::VirtualKeyboardOptions& options) override
- {
- }
-
- void TextEntryStop() override
- {
- }
-
- void TickInputDevice() override
- {
- ProcessRawEventQueues();
- }
-
- void HandleXcbEvent(xcb_generic_event_t* event) override
- {
- if (!IsConnected())
- {
- return;
- }
-
- switch (event->response_type & ~0x80)
- {
- case XCB_KEY_PRESS:
- {
- auto* keyPress = reinterpret_cast(event);
-
- const InputChannelId* key = InputChannelFromKeyEvent(keyPress->detail);
- if (key)
- {
- QueueRawKeyEvent(*key, true);
- }
- break;
- }
- case XCB_KEY_RELEASE:
- {
- auto* keyRelease = reinterpret_cast(event);
-
- const InputChannelId* key = InputChannelFromKeyEvent(keyRelease->detail);
- if (key)
- {
- QueueRawKeyEvent(*key, false);
- }
- break;
- }
- }
- }
-
- private:
- [[nodiscard]] const InputChannelId* InputChannelFromKeyEvent(xcb_keycode_t code) const
- {
- const xcb_keysym_t keysym = xkb_state_key_get_one_sym(m_xkbState.get(), code);
-
- switch(keysym)
- {
- case XKB_KEY_0: return &InputDeviceKeyboard::Key::Alphanumeric0;
- case XKB_KEY_1: return &InputDeviceKeyboard::Key::Alphanumeric1;
- case XKB_KEY_2: return &InputDeviceKeyboard::Key::Alphanumeric2;
- case XKB_KEY_3: return &InputDeviceKeyboard::Key::Alphanumeric3;
- case XKB_KEY_4: return &InputDeviceKeyboard::Key::Alphanumeric4;
- case XKB_KEY_5: return &InputDeviceKeyboard::Key::Alphanumeric5;
- case XKB_KEY_6: return &InputDeviceKeyboard::Key::Alphanumeric6;
- case XKB_KEY_7: return &InputDeviceKeyboard::Key::Alphanumeric7;
- case XKB_KEY_8: return &InputDeviceKeyboard::Key::Alphanumeric8;
- case XKB_KEY_9: return &InputDeviceKeyboard::Key::Alphanumeric9;
- case XKB_KEY_A:
- case XKB_KEY_a: return &InputDeviceKeyboard::Key::AlphanumericA;
- case XKB_KEY_B:
- case XKB_KEY_b: return &InputDeviceKeyboard::Key::AlphanumericB;
- case XKB_KEY_C:
- case XKB_KEY_c: return &InputDeviceKeyboard::Key::AlphanumericC;
- case XKB_KEY_D:
- case XKB_KEY_d: return &InputDeviceKeyboard::Key::AlphanumericD;
- case XKB_KEY_E:
- case XKB_KEY_e: return &InputDeviceKeyboard::Key::AlphanumericE;
- case XKB_KEY_F:
- case XKB_KEY_f: return &InputDeviceKeyboard::Key::AlphanumericF;
- case XKB_KEY_G:
- case XKB_KEY_g: return &InputDeviceKeyboard::Key::AlphanumericG;
- case XKB_KEY_H:
- case XKB_KEY_h: return &InputDeviceKeyboard::Key::AlphanumericH;
- case XKB_KEY_I:
- case XKB_KEY_i: return &InputDeviceKeyboard::Key::AlphanumericI;
- case XKB_KEY_J:
- case XKB_KEY_j: return &InputDeviceKeyboard::Key::AlphanumericJ;
- case XKB_KEY_K:
- case XKB_KEY_k: return &InputDeviceKeyboard::Key::AlphanumericK;
- case XKB_KEY_L:
- case XKB_KEY_l: return &InputDeviceKeyboard::Key::AlphanumericL;
- case XKB_KEY_M:
- case XKB_KEY_m: return &InputDeviceKeyboard::Key::AlphanumericM;
- case XKB_KEY_N:
- case XKB_KEY_n: return &InputDeviceKeyboard::Key::AlphanumericN;
- case XKB_KEY_O:
- case XKB_KEY_o: return &InputDeviceKeyboard::Key::AlphanumericO;
- case XKB_KEY_P:
- case XKB_KEY_p: return &InputDeviceKeyboard::Key::AlphanumericP;
- case XKB_KEY_Q:
- case XKB_KEY_q: return &InputDeviceKeyboard::Key::AlphanumericQ;
- case XKB_KEY_R:
- case XKB_KEY_r: return &InputDeviceKeyboard::Key::AlphanumericR;
- case XKB_KEY_S:
- case XKB_KEY_s: return &InputDeviceKeyboard::Key::AlphanumericS;
- case XKB_KEY_T:
- case XKB_KEY_t: return &InputDeviceKeyboard::Key::AlphanumericT;
- case XKB_KEY_U:
- case XKB_KEY_u: return &InputDeviceKeyboard::Key::AlphanumericU;
- case XKB_KEY_V:
- case XKB_KEY_v: return &InputDeviceKeyboard::Key::AlphanumericV;
- case XKB_KEY_W:
- case XKB_KEY_w: return &InputDeviceKeyboard::Key::AlphanumericW;
- case XKB_KEY_X:
- case XKB_KEY_x: return &InputDeviceKeyboard::Key::AlphanumericX;
- case XKB_KEY_Y:
- case XKB_KEY_y: return &InputDeviceKeyboard::Key::AlphanumericY;
- case XKB_KEY_Z:
- case XKB_KEY_z: return &InputDeviceKeyboard::Key::AlphanumericZ;
- case XKB_KEY_BackSpace: return &InputDeviceKeyboard::Key::EditBackspace;
- case XKB_KEY_Caps_Lock: return &InputDeviceKeyboard::Key::EditCapsLock;
- case XKB_KEY_Return: return &InputDeviceKeyboard::Key::EditEnter;
- case XKB_KEY_space: return &InputDeviceKeyboard::Key::EditSpace;
- case XKB_KEY_Tab: return &InputDeviceKeyboard::Key::EditTab;
- case XKB_KEY_Escape: return &InputDeviceKeyboard::Key::Escape;
- case XKB_KEY_F1: return &InputDeviceKeyboard::Key::Function01;
- case XKB_KEY_F2: return &InputDeviceKeyboard::Key::Function02;
- case XKB_KEY_F3: return &InputDeviceKeyboard::Key::Function03;
- case XKB_KEY_F4: return &InputDeviceKeyboard::Key::Function04;
- case XKB_KEY_F5: return &InputDeviceKeyboard::Key::Function05;
- case XKB_KEY_F6: return &InputDeviceKeyboard::Key::Function06;
- case XKB_KEY_F7: return &InputDeviceKeyboard::Key::Function07;
- case XKB_KEY_F8: return &InputDeviceKeyboard::Key::Function08;
- case XKB_KEY_F9: return &InputDeviceKeyboard::Key::Function09;
- case XKB_KEY_F10: return &InputDeviceKeyboard::Key::Function10;
- case XKB_KEY_F11: return &InputDeviceKeyboard::Key::Function11;
- case XKB_KEY_F12: return &InputDeviceKeyboard::Key::Function12;
- case XKB_KEY_F13: return &InputDeviceKeyboard::Key::Function13;
- case XKB_KEY_F14: return &InputDeviceKeyboard::Key::Function14;
- case XKB_KEY_F15: return &InputDeviceKeyboard::Key::Function15;
- case XKB_KEY_F16: return &InputDeviceKeyboard::Key::Function16;
- case XKB_KEY_F17: return &InputDeviceKeyboard::Key::Function17;
- case XKB_KEY_F18: return &InputDeviceKeyboard::Key::Function18;
- case XKB_KEY_F19: return &InputDeviceKeyboard::Key::Function19;
- case XKB_KEY_F20: return &InputDeviceKeyboard::Key::Function20;
- case XKB_KEY_Alt_L: return &InputDeviceKeyboard::Key::ModifierAltL;
- case XKB_KEY_Alt_R: return &InputDeviceKeyboard::Key::ModifierAltR;
- case XKB_KEY_Control_L: return &InputDeviceKeyboard::Key::ModifierCtrlL;
- case XKB_KEY_Control_R: return &InputDeviceKeyboard::Key::ModifierCtrlR;
- case XKB_KEY_Shift_L: return &InputDeviceKeyboard::Key::ModifierShiftL;
- case XKB_KEY_Shift_R: return &InputDeviceKeyboard::Key::ModifierShiftR;
- case XKB_KEY_Super_L: return &InputDeviceKeyboard::Key::ModifierSuperL;
- case XKB_KEY_Super_R: return &InputDeviceKeyboard::Key::ModifierSuperR;
- case XKB_KEY_Down: return &InputDeviceKeyboard::Key::NavigationArrowDown;
- case XKB_KEY_Left: return &InputDeviceKeyboard::Key::NavigationArrowLeft;
- case XKB_KEY_Right: return &InputDeviceKeyboard::Key::NavigationArrowRight;
- case XKB_KEY_Up: return &InputDeviceKeyboard::Key::NavigationArrowUp;
- case XKB_KEY_Delete: return &InputDeviceKeyboard::Key::NavigationDelete;
- case XKB_KEY_End: return &InputDeviceKeyboard::Key::NavigationEnd;
- case XKB_KEY_Home: return &InputDeviceKeyboard::Key::NavigationHome;
- case XKB_KEY_Insert: return &InputDeviceKeyboard::Key::NavigationInsert;
- case XKB_KEY_Page_Down: return &InputDeviceKeyboard::Key::NavigationPageDown;
- case XKB_KEY_Page_Up: return &InputDeviceKeyboard::Key::NavigationPageUp;
- case XKB_KEY_Num_Lock: return &InputDeviceKeyboard::Key::NumLock;
- case XKB_KEY_KP_0: return &InputDeviceKeyboard::Key::NumPad0;
- case XKB_KEY_KP_1: return &InputDeviceKeyboard::Key::NumPad1;
- case XKB_KEY_KP_2: return &InputDeviceKeyboard::Key::NumPad2;
- case XKB_KEY_KP_3: return &InputDeviceKeyboard::Key::NumPad3;
- case XKB_KEY_KP_4: return &InputDeviceKeyboard::Key::NumPad4;
- case XKB_KEY_KP_5: return &InputDeviceKeyboard::Key::NumPad5;
- case XKB_KEY_KP_6: return &InputDeviceKeyboard::Key::NumPad6;
- case XKB_KEY_KP_7: return &InputDeviceKeyboard::Key::NumPad7;
- case XKB_KEY_KP_8: return &InputDeviceKeyboard::Key::NumPad8;
- case XKB_KEY_KP_9: return &InputDeviceKeyboard::Key::NumPad9;
- case XKB_KEY_KP_Add: return &InputDeviceKeyboard::Key::NumPadAdd;
- case XKB_KEY_KP_Decimal: return &InputDeviceKeyboard::Key::NumPadDecimal;
- case XKB_KEY_KP_Divide: return &InputDeviceKeyboard::Key::NumPadDivide;
- case XKB_KEY_KP_Enter: return &InputDeviceKeyboard::Key::NumPadEnter;
- case XKB_KEY_KP_Multiply: return &InputDeviceKeyboard::Key::NumPadMultiply;
- case XKB_KEY_KP_Subtract: return &InputDeviceKeyboard::Key::NumPadSubtract;
- case XKB_KEY_apostrophe: return &InputDeviceKeyboard::Key::PunctuationApostrophe;
- case XKB_KEY_backslash: return &InputDeviceKeyboard::Key::PunctuationBackslash;
- case XKB_KEY_bracketleft: return &InputDeviceKeyboard::Key::PunctuationBracketL;
- case XKB_KEY_bracketright: return &InputDeviceKeyboard::Key::PunctuationBracketR;
- case XKB_KEY_comma: return &InputDeviceKeyboard::Key::PunctuationComma;
- case XKB_KEY_equal: return &InputDeviceKeyboard::Key::PunctuationEquals;
- case XKB_KEY_hyphen: return &InputDeviceKeyboard::Key::PunctuationHyphen;
- case XKB_KEY_period: return &InputDeviceKeyboard::Key::PunctuationPeriod;
- case XKB_KEY_semicolon: return &InputDeviceKeyboard::Key::PunctuationSemicolon;
- case XKB_KEY_slash: return &InputDeviceKeyboard::Key::PunctuationSlash;
- case XKB_KEY_grave:
- case XKB_KEY_asciitilde: return &InputDeviceKeyboard::Key::PunctuationTilde;
- case XKB_KEY_ISO_Group_Shift: return &InputDeviceKeyboard::Key::SupplementaryISO;
- case XKB_KEY_Pause: return &InputDeviceKeyboard::Key::WindowsSystemPause;
- case XKB_KEY_Print: return &InputDeviceKeyboard::Key::WindowsSystemPrint;
- case XKB_KEY_Scroll_Lock: return &InputDeviceKeyboard::Key::WindowsSystemScrollLock;
- default: return nullptr;
- }
- }
-
- template
- using DeleterForFreeFn = AZStd::integral_constant;
-
- AZStd::unique_ptr> m_xkbContext;
- AZStd::unique_ptr> m_xkbKeymap;
- AZStd::unique_ptr> m_xkbState;
- int m_coreDeviceId{-1};
- bool m_initialized{false};
- };
-
- InputDeviceKeyboard::Implementation* InputDeviceKeyboard::Implementation::Create(InputDeviceKeyboard& inputDevice)
- {
- return aznew InputDeviceKeyboardXcb(inputDevice);
- }
-} // namespace AzFramework
diff --git a/Code/Framework/AzFramework/Platform/Linux/AzFramework/Windowing/NativeWindow_Linux.cpp b/Code/Framework/AzFramework/Platform/Linux/AzFramework/Windowing/NativeWindow_Linux.cpp
index 2950f8dcfc..ba3e761974 100644
--- a/Code/Framework/AzFramework/Platform/Linux/AzFramework/Windowing/NativeWindow_Linux.cpp
+++ b/Code/Framework/AzFramework/Platform/Linux/AzFramework/Windowing/NativeWindow_Linux.cpp
@@ -6,14 +6,16 @@
*
*/
-#include "NativeWindow_Linux_xcb.h"
+#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
+#include
+#endif
namespace AzFramework
{
NativeWindow::Implementation* NativeWindow::Implementation::Create()
{
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
- return aznew NativeWindowImpl_Linux_xcb();
+ return aznew XcbNativeWindow();
#elif PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND
#error "Linux Window Manager Wayland not supported."
return nullptr;
@@ -22,5 +24,4 @@ namespace AzFramework
return nullptr;
#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
}
-
} // namespace AzFramework
diff --git a/Code/Framework/AzFramework/Platform/Linux/platform_linux.cmake b/Code/Framework/AzFramework/Platform/Linux/platform_linux.cmake
index 5c8ca8392f..b08c3b310d 100644
--- a/Code/Framework/AzFramework/Platform/Linux/platform_linux.cmake
+++ b/Code/Framework/AzFramework/Platform/Linux/platform_linux.cmake
@@ -10,6 +10,14 @@
# Only 'xcb' and 'wayland' are recognized
if (${PAL_TRAIT_LINUX_WINDOW_MANAGER} STREQUAL "xcb")
+ set(LY_COMPILE_DEFINITIONS PUBLIC PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB)
+ set(LY_INCLUDE_DIRECTORIES
+ PUBLIC
+ Platform/Common/Xcb
+ )
+ set(LY_FILES_CMAKE
+ Platform/Common/Xcb/azframework_xcb_files.cmake
+ )
set(LY_BUILD_DEPENDENCIES
PRIVATE
3rdParty::X11::xcb
@@ -18,8 +26,6 @@ if (${PAL_TRAIT_LINUX_WINDOW_MANAGER} STREQUAL "xcb")
3rdParty::X11::xkbcommon_X11
)
- set(LY_COMPILE_DEFINITIONS PUBLIC PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB)
-
elseif(PAL_TRAIT_LINUX_WINDOW_MANAGER STREQUAL "wayland")
set(LY_COMPILE_DEFINITIONS PUBLIC PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND)
diff --git a/Code/Framework/AzFramework/Platform/Linux/platform_linux_files.cmake b/Code/Framework/AzFramework/Platform/Linux/platform_linux_files.cmake
index 93767322b2..4f06aa5c57 100644
--- a/Code/Framework/AzFramework/Platform/Linux/platform_linux_files.cmake
+++ b/Code/Framework/AzFramework/Platform/Linux/platform_linux_files.cmake
@@ -12,8 +12,6 @@ set(FILES
AzFramework/API/ApplicationAPI_Platform.h
AzFramework/API/ApplicationAPI_Linux.h
AzFramework/Application/Application_Linux.cpp
- AzFramework/Application/Application_Linux_xcb.h
- AzFramework/Application/Application_Linux_xcb.cpp
AzFramework/Asset/AssetSystemComponentHelper_Linux.cpp
AzFramework/Process/ProcessWatcher_Linux.cpp
AzFramework/Process/ProcessCommon.h
@@ -22,10 +20,8 @@ set(FILES
../Common/Unimplemented/AzFramework/StreamingInstall/StreamingInstall_Unimplemented.cpp
../Common/Default/AzFramework/TargetManagement/TargetManagementComponent_Default.cpp
AzFramework/Windowing/NativeWindow_Linux.cpp
- AzFramework/Windowing/NativeWindow_Linux_xcb.h
- AzFramework/Windowing/NativeWindow_Linux_xcb.cpp
../Common/Unimplemented/AzFramework/Input/Devices/Gamepad/InputDeviceGamepad_Unimplemented.cpp
- AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard_xcb.cpp
+ AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard_Linux.cpp
../Common/Unimplemented/AzFramework/Input/Devices/Motion/InputDeviceMotion_Unimplemented.cpp
../Common/Unimplemented/AzFramework/Input/Devices/Mouse/InputDeviceMouse_Unimplemented.cpp
../Common/Unimplemented/AzFramework/Input/Devices/Touch/InputDeviceTouch_Unimplemented.cpp
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserTableModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserTableModel.cpp
index 469a235b9f..ec709aef8a 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserTableModel.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserTableModel.cpp
@@ -138,7 +138,13 @@ namespace AzToolsFramework
m_indexMap[row] = index;
m_rowMap[index] = row;
++row;
- ++m_displayedItemsCounter;
+
+ // We only want to increase the displayed counter if it is a parent (Source)
+ // so we don't cut children entries.
+ if (entry->GetEntryType() == AssetBrowserEntry::AssetEntryType::Source)
+ {
+ ++m_displayedItemsCounter;
+ }
}
if (model->hasChildren(index))
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/AssetBrowserTableView.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/AssetBrowserTableView.cpp
index 37091c11e2..217e282a37 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/AssetBrowserTableView.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/AssetBrowserTableView.cpp
@@ -29,20 +29,20 @@ namespace AzToolsFramework
{
AssetBrowserTableView::AssetBrowserTableView(QWidget* parent)
: AzQtComponents::TableView(parent)
- , m_delegate(new EntryDelegate(this))
+ , m_delegate(new SearchEntryDelegate(this))
{
- setSortingEnabled(true);
+ setSortingEnabled(false);
setItemDelegate(m_delegate);
setRootIsDecorated(false);
//Styling the header aligning text to the left and using a bold font.
header()->setDefaultAlignment(Qt::AlignLeft);
- header()->setStyleSheet("QHeaderView { font-weight: bold; }");
+ header()->setStyleSheet("QHeaderView { font-weight: bold; };");
+
setContextMenuPolicy(Qt::CustomContextMenu);
setMouseTracking(true);
- setSortingEnabled(false);
setSelectionMode(QAbstractItemView::SingleSelection);
connect(this, &AzQtComponents::TableView::customContextMenuRequested, this, &AssetBrowserTableView::OnContextMenu);
@@ -67,6 +67,8 @@ namespace AzToolsFramework
header()->setSectionResizeMode(0, QHeaderView::ResizeMode::Stretch);
header()->setSectionResizeMode(1, QHeaderView::ResizeMode::Stretch);
+ header()->setSortIndicatorShown(false);
+ header()->setSectionsClickable(false);
}
void AssetBrowserTableView::SetName(const QString& name)
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/AssetBrowserTableView.h b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/AssetBrowserTableView.h
index 94e9bdc4e4..b4eca59cef 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/AssetBrowserTableView.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/AssetBrowserTableView.h
@@ -26,7 +26,7 @@ namespace AzToolsFramework
class AssetBrowserEntry;
class AssetBrowserTableModel;
class AssetBrowserFilterModel;
- class EntryDelegate;
+ class SearchEntryDelegate;
class AssetBrowserTableView //! Table view that displays the asset browser entries in a list.
: public AzQtComponents::TableView
@@ -67,9 +67,9 @@ namespace AzToolsFramework
private:
QString m_name;
- QPointer m_tableModel = nullptr;
- QPointer m_sourceFilterModel = nullptr;
- EntryDelegate* m_delegate = nullptr;
+ QPointer m_tableModel;
+ QPointer m_sourceFilterModel;
+ SearchEntryDelegate* m_delegate = nullptr;
private Q_SLOTS:
void OnContextMenu(const QPoint& point);
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp
index 29324c612c..755c59b55b 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.cpp
@@ -11,12 +11,13 @@
#include
#include
#include
-
+#include
#include
#include
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // 4251: class 'QScopedPointer' needs to have dll-interface to be used by clients of class 'QBrush'
// 4800: 'uint': forcing value to bool 'true' or 'false' (performance warning)
+#include
#include
AZ_POP_DISABLE_WARNING
@@ -24,8 +25,13 @@ namespace AzToolsFramework
{
namespace AssetBrowser
{
- const int ENTRY_SPACING_LEFT_PIXELS = 8;
- const int ENTRY_ICON_MARGIN_LEFT_PIXELS = 2;
+ static constexpr const char* TreeIconPathFirst = "Assets/Editor/Icons/AssetBrowser/TreeBranch_First.svg";
+ static constexpr const char* TreeIconPathMiddle = "Assets/Editor/Icons/AssetBrowser/TreeBranch_Middle.svg";
+ static constexpr const char* TreeIconPathLast = "Assets/Editor/Icons/AssetBrowser/TreeBranch_Last.svg";
+ static constexpr const char* TreeIconPathOneChild = "Assets/Editor/Icons/AssetBrowser/TreeBranch_OneChild.svg";
+
+ const int EntrySpacingLeftPixels = 8;
+ const int EntryIconMarginLeftPixels = 2;
EntryDelegate::EntryDelegate(QWidget* parent)
: QStyledItemDelegate(parent)
@@ -62,7 +68,7 @@ namespace AzToolsFramework
// Draw main entry thumbnail.
QRect remainingRect(option.rect);
- remainingRect.adjust(ENTRY_ICON_MARGIN_LEFT_PIXELS, 0, 0, 0); // bump it rightwards to give some margin to the icon.
+ remainingRect.adjust(EntryIconMarginLeftPixels, 0, 0, 0); // bump it rightwards to give some margin to the icon.
QSize iconSize(m_iconSize, m_iconSize);
// Note that the thumbnail might actually be smaller than the row if theres a lot of padding or font size
@@ -89,7 +95,7 @@ namespace AzToolsFramework
}
remainingRect.adjust(thumbX, 0, 0, 0); // bump it to the right by the size of the thumbnail
- remainingRect.adjust(ENTRY_SPACING_LEFT_PIXELS, 0, 0, 0); // bump it to the right by the spacing.
+ remainingRect.adjust(EntrySpacingLeftPixels, 0, 0, 0); // bump it to the right by the spacing.
}
QString displayString = index.column() == aznumeric_cast(AssetBrowserEntry::Column::Name)
? qvariant_cast(entry->data(aznumeric_cast(AssetBrowserEntry::Column::Name)))
@@ -148,7 +154,162 @@ namespace AzToolsFramework
return m_iconSize;
}
- } // namespace Thumbnailer
+ SearchEntryDelegate::SearchEntryDelegate(QWidget* parent)
+ : EntryDelegate(parent)
+ {
+ LoadBranchPixMaps();
+ }
+
+ void SearchEntryDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
+ {
+ auto data = index.data(AssetBrowserModel::Roles::EntryRole);
+ if (data.canConvert())
+ {
+ bool isEnabled = (option.state & QStyle::State_Enabled) != 0;
+ bool isSelected = (option.state & QStyle::State_Selected) != 0;
+
+ QStyle* style = option.widget ? option.widget->style() : QApplication::style();
+
+ // draw the background
+ style->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, option.widget);
+
+ // Draw main entry thumbnail.
+ QRect remainingRect(option.rect);
+
+ QSize iconSize(m_iconSize, m_iconSize);
+ // Note that the thumbnail might actually be smaller than the row if theres a lot of padding or font size
+ // so it needs to center vertically with padding in that case:
+ QPoint iconTopLeft;
+ QPoint branchIconTopLeft = QPoint();
+
+ auto entry = qvariant_cast(data);
+ auto sourceEntry = azrtti_cast(entry);
+
+ //If it is a SourceEntry or it is not the column name we don't want to add space for the branch Icon
+ if (sourceEntry || index.column() != aznumeric_cast(AssetBrowserEntry::Column::Name))
+ {
+ remainingRect.adjust(EntryIconMarginLeftPixels, 0, 0, 0); // bump it rightwards to give some margin to the icon.
+ iconTopLeft = QPoint(remainingRect.x(), remainingRect.y() + (remainingRect.height() / 2) - (m_iconSize / 2));
+ }
+ else
+ {
+ remainingRect.adjust(EntryIconMarginLeftPixels + m_iconSize, 0, 0, 0); // bump it rightwards to give some margin to the icon.
+ iconTopLeft = QPoint(remainingRect.x() / 2 + m_iconSize, remainingRect.y() + (remainingRect.height() / 2) - (m_iconSize / 2));
+ branchIconTopLeft = QPoint((remainingRect.x() / 2) - 2, remainingRect.y() + (remainingRect.height() / 2) - (m_iconSize / 2));
+ }
+
+ QPalette actualPalette(option.palette);
+
+ if (index.column() == aznumeric_cast(AssetBrowserEntry::Column::Name))
+ {
+ int thumbX = DrawThumbnail(painter, iconTopLeft, iconSize, entry->GetThumbnailKey());
+ if (sourceEntry)
+ {
+ if (m_showSourceControl)
+ {
+ DrawThumbnail(painter, iconTopLeft, iconSize, sourceEntry->GetSourceControlThumbnailKey());
+ }
+ // sources with no children should be greyed out.
+ if (sourceEntry->GetChildCount() == 0)
+ {
+ isEnabled = false; // draw in disabled style.
+ actualPalette.setCurrentColorGroup(QPalette::Disabled);
+ }
+ }
+ else
+ {
+ //Get the indexes above and below our entry to see what type are they.
+ QAbstractItemView* view = qobject_cast(option.styleObject);
+ const QAbstractItemModel* viewModel = view->model();
+
+ const QModelIndex indexBelow = viewModel->index(index.row() + 1, index.column());
+ const QModelIndex indexAbove = viewModel->index(index.row() - 1, index.column());
+
+ auto aboveEntry = qvariant_cast(indexBelow.data(AssetBrowserModel::Roles::EntryRole));
+ auto belowEntry = qvariant_cast(indexAbove.data(AssetBrowserModel::Roles::EntryRole));
+
+ auto aboveSourceEntry = azrtti_cast(aboveEntry);
+ auto belowSourceEntry = azrtti_cast(belowEntry);
+
+ // if current index is the last entry in the view
+ // or the index above it is a Source Entry and
+ // the index below is invalid or is valid but it is also a source entry
+ // then the current index is the only child.
+ if (index.row() == viewModel->rowCount() - 1 ||
+ (indexBelow.isValid() && aboveSourceEntry &&
+ (!indexAbove.isValid() || (indexAbove.isValid() && belowSourceEntry))))
+ {
+ DrawBranchPixMap(EntryBranchType::OneChild, painter, branchIconTopLeft, iconSize); // Draw One Child Icon
+ }
+ else if (indexBelow.isValid() && aboveSourceEntry) // The index above is a source entry
+ {
+ DrawBranchPixMap(EntryBranchType::Last, painter, branchIconTopLeft, iconSize); // Draw First child Icon
+ }
+ else if (indexAbove.isValid() && belowSourceEntry) // The index below is a source entry
+ {
+ DrawBranchPixMap(EntryBranchType::First, painter, branchIconTopLeft, iconSize); // Draw Last Child Icon
+ }
+ else //the index above and below are also child entries
+ {
+ DrawBranchPixMap(EntryBranchType::Middle, painter, branchIconTopLeft, iconSize); // Draw Default child Icon.
+ }
+ }
+
+ remainingRect.adjust(thumbX, 0, 0, 0); // bump it to the right by the size of the thumbnail
+ remainingRect.adjust(EntrySpacingLeftPixels, 0, 0, 0); // bump it to the right by the spacing.
+ }
+ QString displayString = index.column() == aznumeric_cast(AssetBrowserEntry::Column::Name)
+ ? qvariant_cast(entry->data(aznumeric_cast(AssetBrowserEntry::Column::Name)))
+ : qvariant_cast(entry->data(aznumeric_cast(AssetBrowserEntry::Column::Path)));
+
+ style->drawItemText(
+ painter, remainingRect, option.displayAlignment, actualPalette, isEnabled, displayString,
+ isSelected ? QPalette::HighlightedText : QPalette::Text);
+ }
+ }
+
+ void SearchEntryDelegate::LoadBranchPixMaps()
+ {
+ AZ::IO::BasicPath absoluteIconPath;
+ for (int branchType = EntryBranchType::First; branchType != EntryBranchType::Count; ++branchType)
+ {
+ QPixmap pixmap;
+ switch (branchType)
+ {
+ case AzToolsFramework::AssetBrowser::EntryBranchType::First:
+ absoluteIconPath = AZ::IO::FixedMaxPath(AZ::Utils::GetEnginePath()) / TreeIconPathFirst;
+ break;
+ case AzToolsFramework::AssetBrowser::EntryBranchType::Middle:
+ absoluteIconPath = AZ::IO::FixedMaxPath(AZ::Utils::GetEnginePath()) / TreeIconPathMiddle;
+ break;
+ case AzToolsFramework::AssetBrowser::EntryBranchType::Last:
+ absoluteIconPath = AZ::IO::FixedMaxPath(AZ::Utils::GetEnginePath()) / TreeIconPathLast;
+ break;
+ case AzToolsFramework::AssetBrowser::EntryBranchType::OneChild:
+ default:
+ absoluteIconPath = AZ::IO::FixedMaxPath(AZ::Utils::GetEnginePath()) / TreeIconPathOneChild;
+ break;
+ }
+ bool pixmapLoadedSuccess = pixmap.load(absoluteIconPath.c_str());
+ AZ_Assert(pixmapLoadedSuccess, "Error loading Branch Icons in SearchEntryDelegate");
+
+ m_branchIcons[static_cast(branchType)] = pixmap;
+
+ }
+ }
+
+ void SearchEntryDelegate::DrawBranchPixMap(
+ EntryBranchType branchType, QPainter* painter, const QPoint& point, const QSize& size) const
+ {
+ const QPixmap& pixmap = m_branchIcons[branchType];
+
+ pixmap.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
+ const QSize sizeDelta = size - pixmap.size();
+ const QPoint pointDelta = QPoint(sizeDelta.width() / 2, sizeDelta.height() / 2);
+ painter->drawPixmap(point + pointDelta, pixmap);
+ }
+
+ } // namespace AssetBrowser
} // namespace AzToolsFramework
#include "AssetBrowser/Views/moc_EntryDelegate.cpp"
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.h b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.h
index 643bedec7c..ac68c19248 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/EntryDelegate.h
@@ -27,9 +27,19 @@ namespace AzToolsFramework
{
namespace AssetBrowser
{
+ //! Type of branch icon the delegate should paint.
+ enum EntryBranchType
+ {
+ First,
+ Middle,
+ Last,
+ OneChild,
+ Count
+ };
+
class AssetBrowserFilterModel;
- //! EntryDelegate draws a single item in AssetBrowser
+ //! EntryDelegate draws a single item in AssetBrowser.
class EntryDelegate
: public QStyledItemDelegate
{
@@ -52,5 +62,23 @@ namespace AzToolsFramework
//! Draw a thumbnail and return its width
int DrawThumbnail(QPainter* painter, const QPoint& point, const QSize& size, Thumbnailer::SharedThumbnailKey thumbnailKey) const;
};
+
+ //! SearchEntryDelegate draws a single item in AssetBrowserTableView.
+ class SearchEntryDelegate
+ : public EntryDelegate
+ {
+ Q_OBJECT
+ public:
+ explicit SearchEntryDelegate(QWidget* parent = nullptr);
+
+ void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
+
+ private:
+ void LoadBranchPixMaps();
+ void DrawBranchPixMap(EntryBranchType branchType, QPainter* painter, const QPoint& point, const QSize& size) const;
+
+ private:
+ QMap m_branchIcons;
+ };
} // namespace AssetBrowser
} // namespace AzToolsFramework
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeInterface.h
index 6d3a7599de..a4b90f95b7 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeInterface.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeInterface.h
@@ -33,7 +33,7 @@ namespace AzToolsFramework
virtual AZ::EntityId GetFocusRoot() = 0;
//! Returns whether the entity id provided is part of the focused sub-tree.
- virtual bool IsInFocusSubTree(AZ::EntityId entityId) = 0;
+ virtual bool IsInFocusSubTree(AZ::EntityId entityId) const = 0;
};
} // namespace AzToolsFramework
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp
index 817006413d..f6afc3bff5 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.cpp
@@ -86,7 +86,7 @@ namespace AzToolsFramework
return m_focusRoot;
}
- bool FocusModeSystemComponent::IsInFocusSubTree(AZ::EntityId entityId)
+ bool FocusModeSystemComponent::IsInFocusSubTree(AZ::EntityId entityId) const
{
if (m_focusRoot == AZ::EntityId())
{
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.h
index 697a4ff998..27ddebe1ed 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/FocusMode/FocusModeSystemComponent.h
@@ -42,7 +42,7 @@ namespace AzToolsFramework
void SetFocusRoot(AZ::EntityId entityId) override;
void ClearFocusRoot() override;
AZ::EntityId GetFocusRoot() override;
- bool IsInFocusSubTree(AZ::EntityId entityId) override;
+ bool IsInFocusSubTree(AZ::EntityId entityId) const override;
private:
AZ::EntityId m_focusRoot;
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp
index 6135f35df5..c17b58486a 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp
@@ -39,7 +39,7 @@ namespace AzToolsFramework::Prefab
{
InstanceOptionalReference focusedInstance;
- if (entityId == AZ::EntityId())
+ if (!entityId.IsValid())
{
PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface =
AZ::Interface::Get();
@@ -121,7 +121,7 @@ namespace AzToolsFramework::Prefab
return false;
}
- if (entityId == AZ::EntityId())
+ if (!entityId.IsValid())
{
return false;
}
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutliner.qss b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutliner.qss
index 15ff8b1b67..b3c5882334 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutliner.qss
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutliner.qss
@@ -18,18 +18,19 @@ AzToolsFramework--EntityOutlinerWidget QTreeView
selection-background-color: transparent;
}
+
+/*
+ * Entity Outliner handles hover and selected state of items via code,
+ * so we need to override the AzQtComponents::Treeview style.
+ */
AzToolsFramework--EntityOutlinerWidget QTreeView::branch:hover
, AzToolsFramework--EntityOutlinerWidget QTreeView::item:hover
-{
- background: rgba(255, 255, 255, 30);
-}
-
-AzToolsFramework--EntityOutlinerWidget QTreeView::branch:selected
+, AzToolsFramework--EntityOutlinerWidget QTreeView::branch:selected
, AzToolsFramework--EntityOutlinerWidget QTreeView::item:selected
, AzToolsFramework--EntityOutlinerWidget QTreeView::branch:selected:active
, AzToolsFramework--EntityOutlinerWidget QTreeView::item:selected:active
{
- background: rgba(255, 255, 255, 45);
+ background: transparent;
}
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp
index d9f3ff8bb8..90f8e1d121 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.cpp
@@ -44,6 +44,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -102,10 +103,14 @@ namespace AzToolsFramework
EntityCompositionNotificationBus::Handler::BusConnect();
AZ::EntitySystemBus::Handler::BusConnect();
- m_editorEntityFrameworkInterface = AZ::Interface::Get();
+ m_editorEntityUiInterface = AZ::Interface::Get();
+ AZ_Assert(m_editorEntityUiInterface != nullptr,
+ "EntityOutlinerListModel requires a EditorEntityUiInterface instance on Initialize.");
- AZ_Assert(m_editorEntityFrameworkInterface != nullptr,
- "EntityOutlinerListModel requires a EditorEntityFrameworkInterface instance on Initialize.");
+ m_focusModeInterface = AZ::Interface::Get();
+ AZ_Assert(
+ m_focusModeInterface != nullptr,
+ "EntityOutlinerListModel requires a FocusModeInterface instance on Initialize.");
}
int EntityOutlinerListModel::rowCount(const QModelIndex& parent) const
@@ -279,7 +284,7 @@ namespace AzToolsFramework
QVariant EntityOutlinerListModel::GetEntityIcon(const AZ::EntityId& id) const
{
- auto entityUiHandler = m_editorEntityFrameworkInterface->GetHandler(id);
+ auto entityUiHandler = m_editorEntityUiInterface->GetHandler(id);
QIcon icon;
// Retrieve the icon from the handler
@@ -316,7 +321,7 @@ namespace AzToolsFramework
QVariant EntityOutlinerListModel::GetEntityTooltip(const AZ::EntityId& id) const
{
- auto entityUiHandler = m_editorEntityFrameworkInterface->GetHandler(id);
+ auto entityUiHandler = m_editorEntityUiInterface->GetHandler(id);
QString tooltip;
// Retrieve the tooltip from the handler
@@ -349,7 +354,7 @@ namespace AzToolsFramework
QVariant EntityOutlinerListModel::dataForVisibility(const QModelIndex& index, int role) const
{
auto entityId = GetEntityFromIndex(index);
- auto entityUiHandler = m_editorEntityFrameworkInterface->GetHandler(entityId);
+ auto entityUiHandler = m_editorEntityUiInterface->GetHandler(entityId);
if (!entityUiHandler || entityUiHandler->CanToggleLockVisibility(entityId))
{
@@ -377,7 +382,7 @@ namespace AzToolsFramework
QVariant EntityOutlinerListModel::dataForLock(const QModelIndex& index, int role) const
{
auto entityId = GetEntityFromIndex(index);
- auto entityUiHandler = m_editorEntityFrameworkInterface->GetHandler(entityId);
+ auto entityUiHandler = m_editorEntityUiInterface->GetHandler(entityId);
if (!entityUiHandler || entityUiHandler->CanToggleLockVisibility(entityId))
{
@@ -436,7 +441,7 @@ namespace AzToolsFramework
if (value.canConvert())
{
const auto entityId = GetEntityFromIndex(index);
- auto entityUiHandler = m_editorEntityFrameworkInterface->GetHandler(entityId);
+ auto entityUiHandler = m_editorEntityUiInterface->GetHandler(entityId);
if (!entityUiHandler || entityUiHandler->CanToggleLockVisibility(entityId))
{
@@ -532,6 +537,11 @@ namespace AzToolsFramework
break;
}
+ if (AZ::EntityId entityId = GetEntityFromIndex(index); !m_focusModeInterface->IsInFocusSubTree(entityId))
+ {
+ itemFlags &= !Qt::ItemIsEnabled;
+ }
+
return itemFlags;
}
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx
index 25e4276dd4..4b13aa6d27 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerListModel.hxx
@@ -36,6 +36,7 @@
namespace AzToolsFramework
{
class EditorEntityUiInterface;
+ class FocusModeInterface;
namespace EntityOutliner
{
@@ -273,7 +274,8 @@ namespace AzToolsFramework
QVariant GetEntityIcon(const AZ::EntityId& id) const;
QVariant GetEntityTooltip(const AZ::EntityId& id) const;
- EditorEntityUiInterface* m_editorEntityFrameworkInterface = nullptr;
+ EditorEntityUiInterface* m_editorEntityUiInterface = nullptr;
+ FocusModeInterface* m_focusModeInterface = nullptr;
};
class EntityOutlinerCheckBox
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.cpp
index 73276973bb..6a40b3be3a 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.cpp
@@ -40,6 +40,8 @@ namespace AzToolsFramework
"EntityOutlinerTreeView requires a EditorEntityFrameworkInterface instance on Construction.");
FocusModeNotificationBus::Handler::BusConnect();
+
+ viewport()->setMouseTracking(true);
}
EntityOutlinerTreeView::~EntityOutlinerTreeView()
@@ -63,6 +65,11 @@ namespace AzToolsFramework
}
}
+ void EntityOutlinerTreeView::leaveEvent([[maybe_unused]] QEvent* event)
+ {
+ m_mousePosition = QPoint();
+ }
+
void EntityOutlinerTreeView::mousePressEvent(QMouseEvent* event)
{
//postponing normal mouse pressed logic until mouse is released or dragged
@@ -116,6 +123,8 @@ namespace AzToolsFramework
setSelectionMode(selectionModeBefore);
}
+ m_mousePosition = event->pos();
+
//process mouse movement as normal, potentially triggering drag and drop
QTreeView::mouseMoveEvent(event);
}
@@ -176,12 +185,45 @@ namespace AzToolsFramework
void EntityOutlinerTreeView::drawBranches(QPainter* painter, const QRect& rect, const QModelIndex& index) const
{
+ const bool isEnabled = (this->model()->flags(index) & Qt::ItemIsEnabled);
+
+ const bool isSelected = selectionModel()->isSelected(index);
+ const bool isHovered = (index == indexAt(m_mousePosition)) && isEnabled;
+
+ // Paint the branch Selection/Hover Rect
+ PaintBranchSelectionHoverRect(painter, rect, isSelected, isHovered);
+
// Paint the branch background as defined by the entity's handler, or its closes ancestor's.
PaintBranchBackground(painter, rect, index);
QTreeView::drawBranches(painter, rect, index);
}
+ void EntityOutlinerTreeView::PaintBranchSelectionHoverRect(
+ QPainter* painter, const QRect& rect, bool isSelected, bool isHovered) const
+ {
+ painter->save();
+ painter->setRenderHint(QPainter::Antialiasing, false);
+
+ if (isSelected || isHovered)
+ {
+ QPainterPath backgroundPath;
+ QRect backgroundRect(rect);
+
+ backgroundPath.addRect(backgroundRect);
+
+ QColor backgroundColor = m_hoverColor;
+ if (isSelected)
+ {
+ backgroundColor = m_selectedColor;
+ }
+
+ painter->fillPath(backgroundPath, backgroundColor);
+ }
+
+ painter->restore();
+ }
+
void EntityOutlinerTreeView::PaintBranchBackground(QPainter* painter, const QRect& rect, const QModelIndex& index) const
{
// Go through ancestors and add them to the stack
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.hxx
index 8d71b3ed31..2ddbaaafa9 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.hxx
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.hxx
@@ -61,6 +61,7 @@ namespace AzToolsFramework
void startDrag(Qt::DropActions supportedActions) override;
void dragMoveEvent(QDragMoveEvent* event) override;
void dropEvent(QDropEvent* event) override;
+ void leaveEvent(QEvent* event) override;
// FocusModeNotificationBus overrides ...
void OnEditorFocusChanged(AZ::EntityId entityId) override;
@@ -77,8 +78,10 @@ namespace AzToolsFramework
void StartCustomDrag(const QModelIndexList& indexList, Qt::DropActions supportedActions) override;
void PaintBranchBackground(QPainter* painter, const QRect& rect, const QModelIndex& index) const;
+ void PaintBranchSelectionHoverRect(QPainter* painter, const QRect& rect, bool isSelected, bool isHovered) const;
QMouseEvent* m_queuedMouseEvent;
+ QPoint m_mousePosition;
bool m_draggingUnselectedItem; // This is set when an item is dragged outside its bounding box.
int m_expandOnlyDelay = -1;
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp
index 25b10463dc..57e6c9ff7a 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp
@@ -13,6 +13,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -112,6 +113,17 @@ namespace AzToolsFramework
}
}
+ EditorHelpers::EditorHelpers(const EditorVisibleEntityDataCache* entityDataCache)
+ : m_entityDataCache(entityDataCache)
+ {
+ m_focusModeInterface = AZ::Interface::Get();
+ AZ_Assert(
+ m_focusModeInterface,
+ "EditorHelpers - "
+ "Focus Mode Interface could not be found. "
+ "Check that it is being correctly initialized.");
+ }
+
AZ::EntityId EditorHelpers::HandleMouseInteraction(
const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteractionEvent& mouseInteraction)
{
@@ -173,6 +185,12 @@ namespace AzToolsFramework
}
}
+ // Verify if the entity Id corresponds to an entity that is focused; if not, halt selection.
+ if (!m_focusModeInterface->IsInFocusSubTree(entityIdUnderCursor))
+ {
+ return AZ::EntityId();
+ }
+
return entityIdUnderCursor;
}
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.h
index 0dbb1d0f6c..a6a78a4e61 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.h
@@ -22,6 +22,7 @@ namespace AzFramework
namespace AzToolsFramework
{
class EditorVisibleEntityDataCache;
+ class FocusModeInterface;
namespace ViewportInteraction
{
@@ -38,10 +39,7 @@ namespace AzToolsFramework
//! An EditorVisibleEntityDataCache must be passed to EditorHelpers to allow it to
//! efficiently read entity data without resorting to EBus calls.
- explicit EditorHelpers(const EditorVisibleEntityDataCache* entityDataCache)
- : m_entityDataCache(entityDataCache)
- {
- }
+ explicit EditorHelpers(const EditorVisibleEntityDataCache* entityDataCache);
EditorHelpers(const EditorHelpers&) = delete;
EditorHelpers& operator=(const EditorHelpers&) = delete;
~EditorHelpers() = default;
@@ -62,5 +60,6 @@ namespace AzToolsFramework
private:
const EditorVisibleEntityDataCache* m_entityDataCache = nullptr; //!< Entity Data queried by the EditorHelpers.
+ const FocusModeInterface* m_focusModeInterface = nullptr;
};
} // namespace AzToolsFramework
diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp
new file mode 100644
index 0000000000..5972da58a7
--- /dev/null
+++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp
@@ -0,0 +1,128 @@
+/*
+ * 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
+#include
+#include
+#include
+#include
+
+namespace AzToolsFramework
+{
+ class EditorFocusModeTests
+ : public ::testing::Test
+ {
+ protected:
+ void SetUp() override
+ {
+ m_app.Start(m_descriptor);
+
+ // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
+ // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash
+ // in the unit tests.
+ AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
+
+ GenerateTestHierarchy();
+ }
+
+ void GenerateTestHierarchy()
+ {
+ /*
+ * City
+ * |_ Street
+ * |_ Car
+ * | |_ Passenger
+ * |_ SportsCar
+ * |_ Passenger
+ */
+
+ m_entityMap["cityId"] = CreateEditorEntity("City", AZ::EntityId());
+ m_entityMap["streetId"] = CreateEditorEntity("Street", m_entityMap["cityId"]);
+ m_entityMap["carId"] = CreateEditorEntity("Car", m_entityMap["streetId"]);
+ m_entityMap["passengerId1"] = CreateEditorEntity("Passenger", m_entityMap["carId"]);
+ m_entityMap["sportsCarId"] = CreateEditorEntity("SportsCar", m_entityMap["streetId"]);
+ m_entityMap["passengerId2"] = CreateEditorEntity("Passenger", m_entityMap["sportsCarId"]);
+ }
+
+ AZ::EntityId CreateEditorEntity(const char* name, AZ::EntityId parentId)
+ {
+ AZ::Entity* entity = nullptr;
+ UnitTest::CreateDefaultEditorEntity(name, &entity);
+
+ // Parent
+ AZ::TransformBus::Event(entity->GetId(), &AZ::TransformInterface::SetParent, parentId);
+
+ return entity->GetId();
+ }
+
+ void TearDown() override
+ {
+ m_app.Stop();
+ }
+
+ UnitTest::ToolsTestApplication m_app{ "EditorFocusModeTests" };
+ AZ::ComponentApplication::Descriptor m_descriptor;
+ AZStd::unordered_map m_entityMap;
+ };
+
+ TEST_F(EditorFocusModeTests, EditorFocusModeTests_SetFocus)
+ {
+ FocusModeInterface* focusModeInterface = AZ::Interface::Get();
+ EXPECT_TRUE(focusModeInterface != nullptr);
+
+ focusModeInterface->SetFocusRoot(m_entityMap["carId"]);
+ EXPECT_EQ(focusModeInterface->GetFocusRoot(), m_entityMap["carId"]);
+
+ focusModeInterface->ClearFocusRoot();
+ EXPECT_EQ(focusModeInterface->GetFocusRoot(), AZ::EntityId());
+ }
+
+ TEST_F(EditorFocusModeTests, EditorFocusModeTests_IsInFocusSubTree)
+ {
+ FocusModeInterface* focusModeInterface = AZ::Interface::Get();
+ EXPECT_TRUE(focusModeInterface != nullptr);
+
+ focusModeInterface->ClearFocusRoot();
+
+ EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["cityId"]), true);
+ EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["streetId"]), true);
+ EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["carId"]), true);
+ EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId1"]), true);
+ EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["sportsCarId"]), true);
+ EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId2"]), true);
+
+ focusModeInterface->SetFocusRoot(m_entityMap["streetId"]);
+
+ EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["cityId"]), false);
+ EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["streetId"]), true);
+ EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["carId"]), true);
+ EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId1"]), true);
+ EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["sportsCarId"]), true);
+ EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId2"]), true);
+
+ focusModeInterface->SetFocusRoot(m_entityMap["carId"]);
+
+ EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["cityId"]), false);
+ EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["streetId"]), false);
+ EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["carId"]), true);
+ EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId1"]), true);
+ EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["sportsCarId"]), false);
+ EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId2"]), false);
+
+ focusModeInterface->SetFocusRoot(m_entityMap["passengerId2"]);
+
+ EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["cityId"]), false);
+ EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["streetId"]), false);
+ EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["carId"]), false);
+ EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId1"]), false);
+ EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["sportsCarId"]), false);
+ EXPECT_EQ(focusModeInterface->IsInFocusSubTree(m_entityMap["passengerId2"]), true);
+
+ focusModeInterface->ClearFocusRoot();
+ }
+}
diff --git a/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp
new file mode 100644
index 0000000000..ffd6cd2a44
--- /dev/null
+++ b/Code/Framework/AzToolsFramework/Tests/Prefab/PrefabFocus/PrefabFocusTests.cpp
@@ -0,0 +1,173 @@
+/*
+ * 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
+#include
+#include
+#include
+#include
+
+namespace UnitTest
+{
+ class PrefabFocusTests
+ : public PrefabTestFixture
+ {
+ protected:
+ void GenerateTestHierarchy()
+ {
+ /*
+ * City (Prefab Container)
+ * |_ City
+ * |_ Street (Prefab Container)
+ * |_ Car (Prefab Container)
+ * | |_ Passenger
+ * |_ SportsCar (Prefab Container)
+ * |_ Passenger
+ */
+
+ m_entityMap["passenger1"] = CreateEntity("Passenger1");
+ m_entityMap["passenger2"] = CreateEntity("Passenger2");
+ m_entityMap["city"] = CreateEntity("City");
+
+ AzToolsFramework::EditorEntityContextRequestBus::Broadcast(
+ &AzToolsFramework::EditorEntityContextRequests::HandleEntitiesAdded,
+ AzToolsFramework::EntityList{ m_entityMap["passenger1"], m_entityMap["passenger2"], m_entityMap["city"] });
+
+ AZStd::unique_ptr carInstance =
+ m_prefabSystemComponent->CreatePrefab({ m_entityMap["passenger1"] }, {}, "test/car");
+ ASSERT_TRUE(carInstance);
+ m_instanceMap["car"] = carInstance.get();
+
+ AZStd::unique_ptr sportsCarInstance =
+ m_prefabSystemComponent->CreatePrefab({ m_entityMap["passenger2"] }, {}, "test/sportsCar");
+ ASSERT_TRUE(sportsCarInstance);
+ m_instanceMap["sportsCar"] = sportsCarInstance.get();
+
+ AZStd::unique_ptr streetInstance =
+ m_prefabSystemComponent->CreatePrefab({}, MakeInstanceList( AZStd::move(carInstance), AZStd::move(sportsCarInstance) ), "test/street");
+ ASSERT_TRUE(streetInstance);
+ m_instanceMap["street"] = streetInstance.get();
+
+ m_rootInstance =
+ m_prefabSystemComponent->CreatePrefab({ m_entityMap["city"] }, MakeInstanceList(AZStd::move(streetInstance)), "test/city");
+ ASSERT_TRUE(m_rootInstance);
+ m_instanceMap["city"] = m_rootInstance.get();
+ }
+
+ AZStd::unordered_map m_entityMap;
+ AZStd::unordered_map m_instanceMap;
+
+ AZStd::unique_ptr m_rootInstance;
+ };
+
+ TEST_F(PrefabFocusTests, PrefabFocus_FocusOnOwningPrefab)
+ {
+ GenerateTestHierarchy();
+
+ PrefabFocusInterface* prefabFocusInterface = AZ::Interface::Get();
+ EXPECT_TRUE(prefabFocusInterface != nullptr);
+
+ // Verify FocusOnOwningPrefab works when passing the container entity of the root prefab.
+ {
+ prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["city"]->GetContainerEntityId());
+ EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap["city"]->GetTemplateId());
+
+ auto instance = prefabFocusInterface->GetFocusedPrefabInstance();
+ EXPECT_TRUE(instance.has_value());
+ EXPECT_EQ(&instance->get(), m_instanceMap["city"]);
+ }
+
+ // Verify FocusOnOwningPrefab works when passing a nested entity of the root prefab.
+ {
+ prefabFocusInterface->FocusOnOwningPrefab(m_entityMap["city"]->GetId());
+ EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap["city"]->GetTemplateId());
+
+ auto instance = prefabFocusInterface->GetFocusedPrefabInstance();
+ EXPECT_TRUE(instance.has_value());
+ EXPECT_EQ(&instance->get(), m_instanceMap["city"]);
+ }
+
+ // Verify FocusOnOwningPrefab works when passing the container entity of a nested prefab.
+ {
+ prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["car"]->GetContainerEntityId());
+ EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap["car"]->GetTemplateId());
+
+ auto instance = prefabFocusInterface->GetFocusedPrefabInstance();
+ EXPECT_TRUE(instance.has_value());
+ EXPECT_EQ(&instance->get(), m_instanceMap["car"]);
+ }
+
+ // Verify FocusOnOwningPrefab works when passing a nested entity of the a nested prefab.
+ {
+ prefabFocusInterface->FocusOnOwningPrefab(m_entityMap["passenger1"]->GetId());
+ EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), m_instanceMap["car"]->GetTemplateId());
+
+ auto instance = prefabFocusInterface->GetFocusedPrefabInstance();
+ EXPECT_TRUE(instance.has_value());
+ EXPECT_EQ(&instance->get(), m_instanceMap["car"]);
+ }
+
+ // Verify FocusOnOwningPrefab points to the root prefab when the focus is cleared.
+ {
+ AzToolsFramework::PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface =
+ AZ::Interface::Get();
+ AzToolsFramework::Prefab::InstanceOptionalReference rootPrefabInstance =
+ prefabEditorEntityOwnershipInterface->GetRootPrefabInstance();
+ EXPECT_TRUE(rootPrefabInstance.has_value());
+
+ prefabFocusInterface->FocusOnOwningPrefab(AZ::EntityId());
+ EXPECT_EQ(prefabFocusInterface->GetFocusedPrefabTemplateId(), rootPrefabInstance->get().GetTemplateId());
+
+ auto instance = prefabFocusInterface->GetFocusedPrefabInstance();
+ EXPECT_TRUE(instance.has_value());
+ EXPECT_EQ(&instance->get(), &rootPrefabInstance->get());
+ }
+
+ m_rootInstance.release();
+ }
+
+ TEST_F(PrefabFocusTests, PrefabFocus_IsOwningPrefabBeingFocused)
+ {
+ GenerateTestHierarchy();
+
+ PrefabFocusInterface* prefabFocusInterface = AZ::Interface::Get();
+ EXPECT_TRUE(prefabFocusInterface != nullptr);
+
+ // Verify IsOwningPrefabBeingFocused returns true for all entities in a focused prefab (container/nested)
+ {
+ prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["city"]->GetContainerEntityId());
+
+ EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["city"]->GetContainerEntityId()));
+ EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["city"]->GetId()));
+ }
+
+ // Verify IsOwningPrefabBeingFocused returns false for all entities not in a focused prefab (ancestors/descendants)
+ {
+ prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["street"]->GetContainerEntityId());
+
+ EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["street"]->GetContainerEntityId()));
+ EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["city"]->GetContainerEntityId()));
+ EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["city"]->GetId()));
+ EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["car"]->GetContainerEntityId()));
+ EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["passenger1"]->GetId()));
+ }
+
+ // Verify IsOwningPrefabBeingFocused returns false for all entities not in a focused prefab (siblings)
+ {
+ prefabFocusInterface->FocusOnOwningPrefab(m_instanceMap["sportsCar"]->GetContainerEntityId());
+
+ EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["sportsCar"]->GetContainerEntityId()));
+ EXPECT_TRUE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["passenger2"]->GetId()));
+ EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_instanceMap["car"]->GetContainerEntityId()));
+ EXPECT_FALSE(prefabFocusInterface->IsOwningPrefabBeingFocused(m_entityMap["passenger1"]->GetId()));
+ }
+
+ m_rootInstance.release();
+ }
+
+}
diff --git a/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake b/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake
index 764afce266..ecc7d17ccc 100644
--- a/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake
+++ b/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake
@@ -34,6 +34,7 @@ set(FILES
EntityTestbed.h
FileFunc.cpp
FingerprintingTests.cpp
+ FocusMode/EditorFocusModeTests.cpp
GenericComponentWrapperTest.cpp
InstanceDataHierarchy.cpp
IntegerPrimtitiveTestConfig.h
@@ -50,6 +51,7 @@ set(FILES
Prefab/Benchmark/PrefabLoadBenchmarks.cpp
Prefab/Benchmark/PrefabUpdateInstancesBenchmarks.cpp
Prefab/Benchmark/SpawnableCreateBenchmarks.cpp
+ Prefab/PrefabFocus/PrefabFocusTests.cpp
Prefab/MockPrefabFileIOActionValidator.cpp
Prefab/MockPrefabFileIOActionValidator.h
Prefab/PrefabDuplicateTests.cpp
diff --git a/Gems/AWSMetrics/cdk/aws_metrics/batch_analytics.py b/Gems/AWSMetrics/cdk/aws_metrics/batch_analytics.py
index eb36d8a5da..709335f9ce 100755
--- a/Gems/AWSMetrics/cdk/aws_metrics/batch_analytics.py
+++ b/Gems/AWSMetrics/cdk/aws_metrics/batch_analytics.py
@@ -122,6 +122,9 @@ class BatchAnalytics:
)
]
+ for named_query in self._named_queries:
+ named_query.node.add_dependency(self._athena_work_group)
+
@property
def athena_work_group_name(self) -> athena.CfnWorkGroup.name:
return self._athena_work_group.name
diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp
index 82568126df..3fcda71998 100644
--- a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp
@@ -85,7 +85,6 @@ namespace AZ
{
const auto jobLambda = [&]() -> void
{
- AZ_PROFILE_SCOPE(AzRender, "MeshFP::Simulate() Lambda");
for (auto meshDataIter = iteratorRange.first; meshDataIter != iteratorRange.second; ++meshDataIter)
{
if (!meshDataIter->m_model)
diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/MemoryUsage.h b/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/MemoryUsage.h
index 36511ebccf..b6f6e0df11 100644
--- a/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/MemoryUsage.h
+++ b/Gems/Atom/RHI/Code/Include/Atom/RHI.Reflect/MemoryUsage.h
@@ -28,25 +28,19 @@ namespace AZ
size_t m_accumulatedInBytes = 0;
};
- /**
- * Tracks memory usage for a specific heap in the system. The data is expected to adhere to the following constraints:
- *
- * 1) Reserved <= Budget (unless the budget is 0).
- * 2) Resident <= Reserved.
- */
+ //! Tracks memory usage for a specific heap in the system. The data is expected to adhere to the following constraints:
+ //! 1) Reserved <= Budget (unless the budget is 0).
+ //! 2) Resident <= Reserved.
struct HeapMemoryUsage
{
HeapMemoryUsage() = default;
HeapMemoryUsage(const HeapMemoryUsage&);
HeapMemoryUsage& operator=(const HeapMemoryUsage&);
- /**
- * This helper reserves memory in a thread-safe fashion. If the result exceeds the budget, the reservation is safely
- * reverted and false is returned. otherwise, true is returned. Only m_reservedInBytes is affected.
- *
- * @param sizeInBytes The amount of bytes to reserve.
- * @return Whether the reservation was successful.
- */
+ //! This helper reserves memory in a thread-safe fashion. If the result exceeds the budget, the reservation is safely
+ //! reverted and false is returned. otherwise, true is returned. Only m_reservedInBytes is affected.
+ //! @param sizeInBytes The amount of bytes to reserve.
+ //! @return Whether the reservation was successful.
bool TryReserveMemory(size_t sizeInBytes)
{
const size_t reservationInBytes = (m_reservedInBytes += sizeInBytes);
@@ -60,45 +54,41 @@ namespace AZ
return true;
}
- /**
- * Helper function to validate sizes
- */
+ //! Helper function to validate sizes
void Validate()
{
if (Validation::IsEnabled())
{
- AZ_Assert(m_budgetInBytes >= m_reservedInBytes, "Reserved memory is larger than memory budget");
- AZ_Assert(m_reservedInBytes >= m_residentInBytes, "Resident memory is larger than reserved memory");
+ AZ_Assert(
+ m_budgetInBytes >= m_reservedInBytes,
+ "Reserved memory is larger than memory budget. Memory budget %zu Reserved %zu", m_budgetInBytes, m_reservedInBytes.load());
+ AZ_Assert(
+ m_reservedInBytes >= m_residentInBytes,
+ "Resident memory is larger than reserved memory. Reserved Memory %zu Resident memory %zu", m_reservedInBytes.load(),
+ m_residentInBytes.load());
}
}
- /**
- * The budget for the heap in bytes. A non-zero budget means the pool will reject reservation requests
- * once the budget is exceeded. A zero budget effectively disables this check. On certain platforms,
- * it may be unnecessary to budget certain heaps. Other platforms may require a non-zero budget for certain
- * heaps.
- */
+ // The budget for the heap in bytes. A non-zero budget means the pool will reject reservation requests
+ // once the budget is exceeded. A zero budget effectively disables this check. On certain platforms,
+ // it may be unnecessary to budget certain heaps. Other platforms may require a non-zero budget for certain
+ // heaps.
size_t m_budgetInBytes = 0;
- /**
- * Number of bytes reserved on the heap for allocations. This value represents the allocation capacity for
- * the platform. It is validated against the budget and may not exceed it.
- */
+ // Number of bytes reserved on the heap for allocations. This value represents the allocation capacity for
+ // the platform. It is validated against the budget and may not exceed it.
AZStd::atomic_size_t m_reservedInBytes{ 0 };
- /**
- * Number of bytes physically allocated on the heap. This may not exceed the reservation. Certain platforms
- * may choose to transfer memory down the heap level hierarchy in response to memory trim events from the driver.
- */
+ // Number of bytes physically allocated on the heap. This may not exceed the reservation. Certain platforms
+ // may choose to transfer memory down the heap level hierarchy in response to memory trim events from the driver.
AZStd::atomic_size_t m_residentInBytes{ 0 };
};
- /**
- * Describes memory usage metrics of a resource pool. Resource pools *can* associate with a single
- * device memory heap (i.e. a single GPU) and the host memory heap. Certain pools on specific platforms
- * may not require one or the other. In this case, the memory usage / budget will report empty values for
- * that heap type.
- */
+ //!
+ //! Describes memory usage metrics of a resource pool. Resource pools *can* associate with a single
+ //! device memory heap (i.e. a single GPU) and the host memory heap. Certain pools on specific platforms
+ //! may not require one or the other. In this case, the memory usage / budget will report empty values for
+ //! that heap type.
struct PoolMemoryUsage
{
PoolMemoryUsage() = default;
diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/Allocator.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/Allocator.h
index 0bd0056a0b..dc95078f80 100644
--- a/Gems/Atom/RHI/Code/Include/Atom/RHI/Allocator.h
+++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/Allocator.h
@@ -13,13 +13,12 @@ namespace AZ
{
namespace RHI
{
- /**
- * A virtual address which may be relative to a base resource. This means
- * 0 might be a valid address (dependent on the Allocator::Descriptor::m_addressBase value).
- * To account for this, VirtualAddress::Null is used instead. Check validity of the address
- * using IsValid or IsNull instead of checking for 0. VirtualAddress is initialized
- * to Null, so returning the default constructor is sufficient to represent an invalid address.
- */
+
+ //! A virtual address which may be relative to a base resource. This means
+ //! 0 might be a valid address (dependent on the Allocator::Descriptor::m_addressBase value).
+ //! To account for this, VirtualAddress::Null is used instead. Check validity of the address
+ //! using IsValid or IsNull instead of checking for 0. VirtualAddress is initialized
+ //! to Null, so returning the default constructor is sufficient to represent an invalid address.
class VirtualAddress
{
static const VirtualAddress Null;
@@ -29,13 +28,13 @@ namespace AZ
static VirtualAddress CreateNull();
- /// Creates a valid address with a zero offset.
+ //! Creates a valid address with a zero offset.
static VirtualAddress CreateZero();
- /// Creates an address from a pointer.
+ //! Creates an address from a pointer.
static VirtualAddress CreateFromPointer(void* ptr);
- /// Creates an address from an offset from a base pointer.
+ //! Creates an address from an offset from a base pointer.
static VirtualAddress CreateFromOffset(uint64_t offset);
inline bool IsValid() const
@@ -51,15 +50,13 @@ namespace AZ
uintptr_t m_ptr;
};
- /**
- * An allocator interface used for external GPU allocations. The allocator
- * does not manage the host memory. Instead, the user specifies a base address
- * (which may be 0, in order to allocate offsets from a base resource). The allocator
- * interface also provides an API for garbage collection. If used to manage GPU resources,
- * these are often deferred-released after N frames. The user may provide a garbage collection
- * latency, which controls the number of GarbageCollect calls that must occur before an allocation
- * is actually reclaimed. The intended use case is to garbage collect at the end of each frame.
- */
+ //! An allocator interface used for external GPU allocations. The allocator
+ //! does not manage the host memory. Instead, the user specifies a base address
+ //! (which may be 0, in order to allocate offsets from a base resource). The allocator
+ //! interface also provides an API for garbage collection. If used to manage GPU resources,
+ //! these are often deferred-released after N frames. The user may provide a garbage collection
+ //! latency, which controls the number of GarbageCollect calls that must occur before an allocation
+ //! is actually reclaimed. The intended use case is to garbage collect at the end of each frame.
class Allocator
{
public:
@@ -86,44 +83,42 @@ namespace AZ
virtual void Shutdown() = 0;
- /**
- * Allocates a virtual address relative to the base address provided at initialization time.
- * @param byteCount The number of bytes to allocate.
- * @param byteAlignement The alignment used to align the allocation.
- */
+ //! Allocates a virtual address relative to the base address provided at initialization time.
+ //! @param byteCount The number of bytes to allocate.
+ //! @param byteAlignement The alignment used to align the allocation.
virtual VirtualAddress Allocate(size_t byteCount, size_t byteAlignment) = 0;
- /**
- * Deallocates an allocation. The memory is not reclaimed until garbage collect is called.
- * Depending on the garbage collection latency, it may take several garbage collection cycles
- * before the memory is reclaimed.
- */
+ //! Deallocates an allocation. The memory is not reclaimed until garbage collect is called.
+ //! Depending on the garbage collection latency, it may take several garbage collection cycles
+ //! before the memory is reclaimed.
virtual void DeAllocate(VirtualAddress offset) = 0;
- /// Allocations are deferred-released until a specific number of GC cycles have occurred. This
- /// is useful for allocations actively being consumed by the GPU.
+ //! Allocations are deferred-released until a specific number of GC cycles have occurred. This
+ //! is useful for allocations actively being consumed by the GPU.
virtual void GarbageCollect() = 0;
- /// Forces garbage collection of all allocations, regardless of the GC latency.
+ //! Forces garbage collection of all allocations, regardless of the GC latency.
virtual void GarbageCollectForce() = 0;
- /**
- * Returns the number of allocations active for this allocator. This includes
- * allocations that are pending garbage collection.
- */
+ //! Returns the number of allocations active for this allocator. This includes
+ //! allocations that are pending garbage collection.
virtual size_t GetAllocationCount() const { return 0; }
- /**
- * Returns the number of bytes used by the allocator. This includes
- * allocations that are pending garbage collection.
- */
+ //! Returns the number of bytes used by the allocator. This includes
+ //! allocations that are pending garbage collection.
virtual size_t GetAllocatedByteCount() const { return 0; }
- /// Returns the descriptor used to initialize the allocator.
+ //! Returns the descriptor used to initialize the allocator.
virtual const Descriptor& GetDescriptor() const = 0;
- /// Helper for converting agnostic VirtualAddress type to pointer type. Will convert
- /// VirtualAddress::Null to nullptr.
+ //! Clone the current allocator to the new allocator passed in
+ virtual void Clone([[maybe_unused]] RHI::Allocator* newAllocator)
+ {
+ AZ_Assert(false, "Not Implemented");
+ };
+
+ //! Helper for converting agnostic VirtualAddress type to pointer type. Will convert
+ //! VirtualAddress::Null to nullptr.
template
T* AllocateAs(size_t byteCount, size_t byteAlignment)
{
diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/Device.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/Device.h
index f9df29cf74..fb4082bb25 100644
--- a/Gems/Atom/RHI/Code/Include/Atom/RHI/Device.h
+++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/Device.h
@@ -139,6 +139,12 @@ namespace AZ
//! Notifies after all objects currently in the platform release queue are released
virtual void ObjectCollectionNotify(RHI::ObjectCollectorNotifyFunction notifyFunction) = 0;
+ //! Allows the back-ends to compact SRG related memory if applicable
+ virtual RHI::ResultCode CompactSRGMemory()
+ {
+ return RHI::ResultCode::Success;
+ };
+
protected:
DeviceFeatures m_features;
DeviceLimits m_limits;
diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/Factory.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/Factory.h
index 992cc0e79a..71f9f1605b 100644
--- a/Gems/Atom/RHI/Code/Include/Atom/RHI/Factory.h
+++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/Factory.h
@@ -112,6 +112,9 @@ namespace AZ
//! Returns true if Pix dll is loaded
static bool IsPixModuleLoaded();
+ //! Returns true if Warp is enabled
+ static bool UsingWarpDevice();
+
//! Returns the name of the Factory.
virtual Name GetName() = 0;
diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/FreeListAllocator.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/FreeListAllocator.h
index ee1cb7c7f4..ce20f9cbe5 100644
--- a/Gems/Atom/RHI/Code/Include/Atom/RHI/FreeListAllocator.h
+++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/FreeListAllocator.h
@@ -55,6 +55,7 @@ namespace AZ
size_t GetAllocationCount() const override;
size_t GetAllocatedByteCount() const override;
const Descriptor& GetDescriptor() const override;
+ void Clone(RHI::Allocator* newAllocator) override;
//////////////////////////////////////////////////////////////////////////
private:
diff --git a/Gems/Atom/RHI/Code/Source/RHI.Edit/ShaderCompilerArguments.cpp b/Gems/Atom/RHI/Code/Source/RHI.Edit/ShaderCompilerArguments.cpp
index ab45d2239b..ef330e7902 100644
--- a/Gems/Atom/RHI/Code/Source/RHI.Edit/ShaderCompilerArguments.cpp
+++ b/Gems/Atom/RHI/Code/Source/RHI.Edit/ShaderCompilerArguments.cpp
@@ -155,11 +155,6 @@ namespace AZ
{
arguments += " -Zpr";
}
- if (m_dxcGenerateDebugInfo)
- {
- arguments += " -Zi"; // Generate debug information
- arguments += " -Zss"; // Compute Shader Hash considering source information
- }
// strip spaces at both sides
AZStd::string dxcAdditionalFreeArguments = m_dxcAdditionalFreeArguments;
AzFramework::StringFunc::TrimWhiteSpace(dxcAdditionalFreeArguments, true, true);
diff --git a/Gems/Atom/RHI/Code/Source/RHI/Factory.cpp b/Gems/Atom/RHI/Code/Source/RHI/Factory.cpp
index 48b64c17c0..82b0a13c86 100644
--- a/Gems/Atom/RHI/Code/Source/RHI/Factory.cpp
+++ b/Gems/Atom/RHI/Code/Source/RHI/Factory.cpp
@@ -8,12 +8,12 @@
#include
#include
+#include
#include
#include
#if defined(USE_RENDERDOC) || defined(USE_PIX)
#include
-#include
#include
#endif
@@ -28,6 +28,8 @@ static AZStd::unique_ptr s_pixModule;
static bool s_isPixGpuCaptureDllLoaded = false;
#endif
+static bool s_usingWarpDevice = false;
+
namespace AZ
{
namespace RHI
@@ -55,6 +57,8 @@ namespace AZ
Factory::Factory()
{
+ AZStd::string preferredUserAdapterName = RHI::GetCommandLineValue("forceAdapter");
+ s_usingWarpDevice = preferredUserAdapterName == "Microsoft Basic Render Driver";
#if defined(USE_RENDERDOC)
// If RenderDoc is requested, we need to load the library as early as possible (before device queries/factories are made)
bool enableRenderDoc = RHI::QueryCommandLineOption("enableRenderDoc");
@@ -197,5 +201,10 @@ namespace AZ
return false;
#endif
}
+
+ bool Factory::UsingWarpDevice()
+ {
+ return s_usingWarpDevice;
+ }
}
}
diff --git a/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp b/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp
index df887379fe..5d2feb1e34 100644
--- a/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp
+++ b/Gems/Atom/RHI/Code/Source/RHI/FrameScheduler.cpp
@@ -314,6 +314,11 @@ namespace AZ
resourcePoolDatabase.ForEachShaderResourceGroupPool(compileAllLambda);
}
+
+ //It is possible for certain back ends to run out of SRG memory (due to fragmentation) in which case
+ //we try to compact and re-compile SRGs.
+ RHI::ResultCode resultCode = m_device->CompactSRGMemory();
+ AZ_Assert(resultCode == RHI::ResultCode::Success, "SRG compaction failed and this can lead to a gpu crash.");
}
void FrameScheduler::BuildRayTracingShaderTables()
diff --git a/Gems/Atom/RHI/Code/Source/RHI/FreeListAllocator.cpp b/Gems/Atom/RHI/Code/Source/RHI/FreeListAllocator.cpp
index c646700495..77877b0020 100644
--- a/Gems/Atom/RHI/Code/Source/RHI/FreeListAllocator.cpp
+++ b/Gems/Atom/RHI/Code/Source/RHI/FreeListAllocator.cpp
@@ -344,5 +344,17 @@ namespace AZ
handle = node.m_nextFree;
}
}
+
+ void FreeListAllocator::Clone(RHI::Allocator* newAllocator)
+ {
+ FreeListAllocator* newFreeListAllocator = static_cast(newAllocator);
+ newFreeListAllocator->m_headHandle = m_headHandle;
+ newFreeListAllocator->m_nodeFreeList = m_nodeFreeList;
+ newFreeListAllocator->m_nodes = m_nodes;
+ newFreeListAllocator->m_allocations = m_allocations;
+ newFreeListAllocator->m_garbage = m_garbage;
+ newFreeListAllocator->m_garbageCollectCycle = m_garbageCollectCycle;
+ newFreeListAllocator->m_byteCountTotal = m_byteCountTotal;
+ }
}
}
diff --git a/Gems/Atom/RHI/DX12/Code/Include/Atom/RHI.Reflect/DX12/PlatformLimitsDescriptor.h b/Gems/Atom/RHI/DX12/Code/Include/Atom/RHI.Reflect/DX12/PlatformLimitsDescriptor.h
index 1f22599b38..63c2d69ea2 100644
--- a/Gems/Atom/RHI/DX12/Code/Include/Atom/RHI.Reflect/DX12/PlatformLimitsDescriptor.h
+++ b/Gems/Atom/RHI/DX12/Code/Include/Atom/RHI.Reflect/DX12/PlatformLimitsDescriptor.h
@@ -64,6 +64,12 @@ namespace AZ
//! int array: Max count for descriptors
AZStd::unordered_map> m_descriptorHeapLimits;
+ // Number of max static handles for shader visible srv/uav/cbv views
+ uint32_t m_numShaderVisibleCbvSrvUavStaticHandles = 2000;
+
+ //Bool to indicate allowing compaction of shader visible srv/uav/cbv heap in case of fragmentation
+ bool m_allowDescriptorHeapCompaction = false;
+
FrameGraphExecuterData m_frameGraphExecuterData;
void LoadPlatformLimitsDescriptor(const char* rhiName) override;
diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI.Builders/ShaderPlatformInterface.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI.Builders/ShaderPlatformInterface.cpp
index 89ae3ede46..f30fc72ace 100644
--- a/Gems/Atom/RHI/DX12/Code/Source/RHI.Builders/ShaderPlatformInterface.cpp
+++ b/Gems/Atom/RHI/DX12/Code/Source/RHI.Builders/ShaderPlatformInterface.cpp
@@ -255,6 +255,11 @@ namespace AZ
// Compilation parameters
AZStd::string params = shaderCompilerArguments.MakeAdditionalDxcCommandLineString();
+ if (BuildHasDebugInfo(shaderCompilerArguments))
+ {
+ params += " -Zi"; // Generate debug information
+ params += " -Zss"; // Compute Shader Hash considering source information
+ }
// Enable half precision types when shader model >= 6.2
int shaderModelMajor = 0;
@@ -281,12 +286,11 @@ namespace AZ
AZStd::string symbolDatabaseFileCliArgument{" "}; // when not debug: still insert a space between 5.dxil and 7.hlsl-in
if (BuildHasDebugInfo(shaderCompilerArguments))
{
- // prepare .ldd filename:
+ // prepare .pdb filename:
AZStd::string md5hex = RHI::ByteToHexString(md5);
AZStd::string symbolDatabaseFilePath = dxcInputFile.c_str(); // mutate from source
- AZStd::string lldFileName = md5hex // lld is like pdb but it's the default symbol database extension in dxc
- + "-" + profileIt->second; // concatenate the shader profile to disambiguate vs/ps...
- AzFramework::StringFunc::Path::ReplaceFullName(symbolDatabaseFilePath, lldFileName.c_str(), "lld");
+ AZStd::string pdbFileName = md5hex + "-" + profileIt->second; // concatenate the shader profile to disambiguate vs/ps...
+ AzFramework::StringFunc::Path::ReplaceFullName(symbolDatabaseFilePath, pdbFileName.c_str(), "pdb");
// it is possible that another activated platform/profile, already exported that file. (since it's hashed on the source file)
// dxc returns an error in such case. we get less surprising effets by just not mentionning an -Fd argument
if (AZ::IO::SystemFile::Exists(symbolDatabaseFilePath.c_str()))
diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI.Reflect/PlatformLimitsDescriptor.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI.Reflect/PlatformLimitsDescriptor.cpp
index 77b41d6ffc..fd9ad84511 100644
--- a/Gems/Atom/RHI/DX12/Code/Source/RHI.Reflect/PlatformLimitsDescriptor.cpp
+++ b/Gems/Atom/RHI/DX12/Code/Source/RHI.Reflect/PlatformLimitsDescriptor.cpp
@@ -19,8 +19,10 @@ namespace AZ
if (SerializeContext* serializeContext = azrtti_cast(context))
{
serializeContext->Class()
- ->Version(0)
+ ->Version(1)
->Field("DescriptorHeapLimits", &PlatformLimitsDescriptor::m_descriptorHeapLimits)
+ ->Field("NumShaderVisibleCbvSrvUavStaticHandles", &PlatformLimitsDescriptor::m_numShaderVisibleCbvSrvUavStaticHandles)
+ ->Field("AllowDescriptorHeapCompaction", &PlatformLimitsDescriptor::m_allowDescriptorHeapCompaction)
->Field("FrameGraphExecuterData", &PlatformLimitsDescriptor::m_frameGraphExecuterData)
;
}
@@ -54,7 +56,7 @@ namespace AZ
// Map default value must be initialized after attempting to serialize (and result in failure).
// Otherwise, serialization won't overwrite the default values.
m_descriptorHeapLimits = AZStd::unordered_map>({
- { AZStd::string("DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV"), { 1000000, 1000000 } },
+ { AZStd::string("DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV"), { 100000, 1000000 } },
{ AZStd::string("DESCRIPTOR_HEAP_TYPE_SAMPLER"), { 2048, 2048 } },
{ AZStd::string("DESCRIPTOR_HEAP_TYPE_RTV"), { 2048, 0 } },
{ AZStd::string("DESCRIPTOR_HEAP_TYPE_DSV"), { 2048, 0 } }
diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandList.h b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandList.h
index 443ab3e73a..1472cdc80e 100644
--- a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandList.h
+++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandList.h
@@ -438,7 +438,7 @@ namespace AZ
switch (pipelineType)
{
case RHI::PipelineStateType::Draw:
- if (binding.m_resourceTable.IsValid())
+ if (binding.m_resourceTable.IsValid() && compiledData.m_gpuViewsDescriptorHandle.ptr)
{
GetCommandList()->SetGraphicsRootDescriptorTable(binding.m_resourceTable.GetIndex(), compiledData.m_gpuViewsDescriptorHandle);
}
@@ -448,14 +448,15 @@ namespace AZ
GetCommandList()->SetGraphicsRootConstantBufferView(binding.m_constantBuffer.GetIndex(), compiledData.m_gpuConstantAddress);
}
- if (binding.m_samplerTable.IsValid())
+ if (binding.m_samplerTable.IsValid() && compiledData.m_gpuSamplersDescriptorHandle.ptr)
{
GetCommandList()->SetGraphicsRootDescriptorTable(binding.m_samplerTable.GetIndex(), compiledData.m_gpuSamplersDescriptorHandle);
}
for (uint32_t unboundedArrayIndex = 0; unboundedArrayIndex < ShaderResourceGroupCompiledData::MaxUnboundedArrays; ++unboundedArrayIndex)
{
- if (binding.m_unboundedArrayResourceTables[unboundedArrayIndex].IsValid())
+ if (binding.m_unboundedArrayResourceTables[unboundedArrayIndex].IsValid() &&
+ compiledData.m_gpuUnboundedArraysDescriptorHandles[unboundedArrayIndex].ptr)
{
GetCommandList()->SetGraphicsRootDescriptorTable(
binding.m_unboundedArrayResourceTables[unboundedArrayIndex].GetIndex(),
@@ -465,7 +466,7 @@ namespace AZ
break;
case RHI::PipelineStateType::Dispatch:
- if (binding.m_resourceTable.IsValid())
+ if (binding.m_resourceTable.IsValid() && compiledData.m_gpuViewsDescriptorHandle.ptr)
{
GetCommandList()->SetComputeRootDescriptorTable(binding.m_resourceTable.GetIndex(), compiledData.m_gpuViewsDescriptorHandle);
}
@@ -475,14 +476,15 @@ namespace AZ
GetCommandList()->SetComputeRootConstantBufferView(binding.m_constantBuffer.GetIndex(), compiledData.m_gpuConstantAddress);
}
- if (binding.m_samplerTable.IsValid())
+ if (binding.m_samplerTable.IsValid() && compiledData.m_gpuSamplersDescriptorHandle.ptr)
{
GetCommandList()->SetComputeRootDescriptorTable(binding.m_samplerTable.GetIndex(), compiledData.m_gpuSamplersDescriptorHandle);
}
for (uint32_t unboundedArrayIndex = 0; unboundedArrayIndex < ShaderResourceGroupCompiledData::MaxUnboundedArrays; ++unboundedArrayIndex)
{
- if (binding.m_unboundedArrayResourceTables[unboundedArrayIndex].IsValid())
+ if (binding.m_unboundedArrayResourceTables[unboundedArrayIndex].IsValid() &&
+ compiledData.m_gpuUnboundedArraysDescriptorHandles[unboundedArrayIndex].ptr)
{
GetCommandList()->SetComputeRootDescriptorTable(
binding.m_unboundedArrayResourceTables[unboundedArrayIndex].GetIndex(),
diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandListBase.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandListBase.cpp
index efa9518ee1..9733045179 100644
--- a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandListBase.cpp
+++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandListBase.cpp
@@ -50,7 +50,7 @@ namespace AZ
void CommandListBase::SetNameInternal(const AZStd::string_view& name)
{
- AZStd::wstring wname;
+ AZStd::fixed_wstring<256> wname;
AZStd::to_wstring(wname, name.data());
GetCommandList()->SetName(wname.data());
}
diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueueContext.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueueContext.cpp
index 9bf25d8bc6..012784d3fc 100644
--- a/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueueContext.cpp
+++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/CommandQueueContext.cpp
@@ -39,7 +39,7 @@ namespace AZ
{
Device& device = static_cast(deviceBase);
m_currentFrameIndex = 0;
- m_frameFences.resize(RHI::Limits::Device::FrameCountMax - 1);
+ m_frameFences.resize(RHI::Limits::Device::FrameCountMax);
for (FenceSet& fences : m_frameFences)
{
fences.Init(device.GetDevice(), RHI::FenceState::Signaled);
diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/DescriptorContext.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/DescriptorContext.cpp
index 635c66f1cd..1b0df5846c 100644
--- a/Gems/Atom/RHI/DX12/Code/Source/RHI/DescriptorContext.cpp
+++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/DescriptorContext.cpp
@@ -10,7 +10,9 @@
#include
#include
#include
+#include
#include
+#include
namespace AZ
{
@@ -40,7 +42,7 @@ namespace AZ
for (D3D12_SRV_DIMENSION dimension : validSRVDimensions)
{
- DescriptorHandle srvDescriptorHandle = Allocate(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, 1).GetOffset();
+ DescriptorHandle srvDescriptorHandle = AllocateHandle(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, 1);
D3D12_SHADER_RESOURCE_VIEW_DESC desc = {};
desc.Format = DXGI_FORMAT_R32_UINT;
@@ -62,7 +64,7 @@ namespace AZ
for (D3D12_UAV_DIMENSION dimension : UAVDimensions)
{
- DescriptorHandle uavDescriptorHandle = Allocate(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, 1).GetOffset();
+ DescriptorHandle uavDescriptorHandle = AllocateHandle(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, 1);
D3D12_UNORDERED_ACCESS_VIEW_DESC desc = {};
desc.Format = DXGI_FORMAT_R32_UINT;
@@ -75,14 +77,14 @@ namespace AZ
void DescriptorContext::CreateNullDescriptorsCBV()
{
D3D12_CONSTANT_BUFFER_VIEW_DESC constantBufferDesc = {};
- DescriptorHandle cbvDescriptorHandle = Allocate(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, 1).GetOffset();
+ DescriptorHandle cbvDescriptorHandle = AllocateHandle(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, 1);
m_device->CreateConstantBufferView(&constantBufferDesc, GetCpuPlatformHandle(cbvDescriptorHandle));
m_nullDescriptorCBV = cbvDescriptorHandle;
}
void DescriptorContext::CreateNullDescriptorsSampler()
{
- m_nullSamplerDescriptor = Allocate(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, 1).GetOffset();
+ m_nullSamplerDescriptor = AllocateHandle(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, 1);
D3D12_SAMPLER_DESC samplerDesc = {};
samplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
@@ -102,7 +104,7 @@ namespace AZ
AZ_Assert(platformLimitsDescriptor.get(), "Platform limits information is missing");
m_platformLimitsDescriptor = platformLimitsDescriptor;
-
+ m_allowDescriptorHeapCompaction = m_platformLimitsDescriptor->m_allowDescriptorHeapCompaction;
for (const auto& itr : platformLimitsDescriptor->m_descriptorHeapLimits)
{
for (uint32_t shaderVisibleIdx = 0; shaderVisibleIdx < PlatformLimitsDescriptor::NumHeapFlags; ++shaderVisibleIdx)
@@ -114,11 +116,33 @@ namespace AZ
if (descriptorCountMax)
{
- GetPool(static_cast(heapTypeIdx.value()), shaderVisibleIdx).Init(m_device.get(), type, flags, descriptorCountMax);
+ if (m_allowDescriptorHeapCompaction && IsShaderVisibleCbvSrvUavHeap(type, flags))
+ {
+ //Init the two heaps to help support compaction after fragmentation
+ m_shaderVisibleCbvSrvUavPools[0].Init(
+ m_device.get(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE,
+ descriptorCountMax, platformLimitsDescriptor->m_numShaderVisibleCbvSrvUavStaticHandles);
+
+ m_shaderVisibleCbvSrvUavPools[1].Init(
+ m_device.get(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE,
+ descriptorCountMax, platformLimitsDescriptor->m_numShaderVisibleCbvSrvUavStaticHandles);
+ }
+ else
+ {
+ GetPool(static_cast(heapTypeIdx.value()), shaderVisibleIdx).Init(m_device.get(), type, flags, descriptorCountMax, descriptorCountMax);
+ }
}
}
}
-
+
+ if (m_allowDescriptorHeapCompaction)
+ {
+ m_backupStaticHandles.Init(
+ m_device.get(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE,
+ platformLimitsDescriptor->m_numShaderVisibleCbvSrvUavStaticHandles,
+ platformLimitsDescriptor->m_numShaderVisibleCbvSrvUavStaticHandles);
+ }
+
CreateNullDescriptors();
}
@@ -129,7 +153,7 @@ namespace AZ
{
if (constantBufferView.IsNull())
{
- constantBufferView = Allocate(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, 1).GetOffset();
+ constantBufferView = AllocateHandle(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, 1);
}
D3D12_CPU_DESCRIPTOR_HANDLE descriptorHandle = GetCpuPlatformHandle(constantBufferView);
@@ -145,7 +169,7 @@ namespace AZ
{
if (shaderResourceView.IsNull())
{
- shaderResourceView = Allocate(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, 1).GetOffset();
+ shaderResourceView = AllocateHandle(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, 1);
}
D3D12_CPU_DESCRIPTOR_HANDLE descriptorHandle = GetCpuPlatformHandle(shaderResourceView);
@@ -165,7 +189,7 @@ namespace AZ
{
if (unorderedAccessView.IsNull())
{
- unorderedAccessView = Allocate(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, 1).GetOffset();
+ unorderedAccessView = AllocateHandle(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, 1);
}
D3D12_CPU_DESCRIPTOR_HANDLE unorderedAccessDescriptor = GetCpuPlatformHandle(unorderedAccessView);
@@ -176,7 +200,24 @@ namespace AZ
// Copy the UAV descriptor into the GPU-visible version for clearing.
if (unorderedAccessViewClear.IsNull())
{
- unorderedAccessViewClear = Allocate(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, 1).GetOffset();
+ unorderedAccessViewClear = AllocateHandle(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, 1);
+
+ if (unorderedAccessViewClear.IsNull())
+ {
+ AZ_Assert(
+ false,
+ "Descriptor heap ran out of memory for static handles. Please consider increasing the value of NumShaderVisibleCbvSrvUavStaticHandles"
+ "within platformlimits.azasset file for dx12.");
+ return;
+ }
+
+ if (m_allowDescriptorHeapCompaction)
+ {
+ //We make a copy of static handles in case we need to compact and recreate the shader visible heap
+ m_device->CopyDescriptorsSimple(
+ 1, m_backupStaticHandles.GetCpuPlatformHandle(unorderedAccessViewClear), unorderedAccessDescriptor,
+ unorderedAccessViewClear.m_type);
+ }
}
CopyDescriptor(unorderedAccessViewClear, unorderedAccessView);
}
@@ -188,7 +229,7 @@ namespace AZ
{
if (shaderResourceView.IsNull())
{
- shaderResourceView = Allocate(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, 1).GetOffset();
+ shaderResourceView = AllocateHandle(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, 1);
}
D3D12_CPU_DESCRIPTOR_HANDLE descriptorHandle = GetCpuPlatformHandle(shaderResourceView);
@@ -205,7 +246,7 @@ namespace AZ
{
if (unorderedAccessView.IsNull())
{
- unorderedAccessView = Allocate(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, 1).GetOffset();
+ unorderedAccessView = AllocateHandle(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, 1);
}
D3D12_CPU_DESCRIPTOR_HANDLE unorderedAccessDescriptor = GetCpuPlatformHandle(unorderedAccessView);
@@ -216,7 +257,24 @@ namespace AZ
// Copy the UAV descriptor into the GPU-visible version for clearing.
if (unorderedAccessViewClear.IsNull())
{
- unorderedAccessViewClear = Allocate(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, 1).GetOffset();
+ unorderedAccessViewClear = AllocateHandle(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, 1);
+
+ if (unorderedAccessViewClear.IsNull())
+ {
+ AZ_Assert(
+ false,
+ "Descriptor heap ran out of memory for static handles. Please consider increasing the value of "
+ "NumShaderVisibleCbvSrvUavStaticHandles within platformlimits.azasset file for dx12.");
+ return;
+ }
+
+ if (m_allowDescriptorHeapCompaction)
+ {
+ // We make a copy of static handles in case we need to compact and recreate the shader visible heap
+ m_device->CopyDescriptorsSimple(
+ 1, m_backupStaticHandles.GetCpuPlatformHandle(unorderedAccessViewClear), unorderedAccessDescriptor,
+ unorderedAccessViewClear.m_type);
+ }
}
CopyDescriptor(unorderedAccessViewClear, unorderedAccessView);
}
@@ -228,7 +286,7 @@ namespace AZ
{
if (renderTargetView.IsNull())
{
- renderTargetView = Allocate(D3D12_DESCRIPTOR_HEAP_TYPE_RTV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, 1).GetOffset();
+ renderTargetView = AllocateHandle(D3D12_DESCRIPTOR_HEAP_TYPE_RTV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, 1);
}
D3D12_CPU_DESCRIPTOR_HANDLE renderTargetDescriptor = GetCpuPlatformHandle(renderTargetView);
@@ -245,13 +303,13 @@ namespace AZ
{
if (depthStencilView.IsNull())
{
- depthStencilView = Allocate(D3D12_DESCRIPTOR_HEAP_TYPE_DSV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, 1).GetOffset();
+ depthStencilView = AllocateHandle(D3D12_DESCRIPTOR_HEAP_TYPE_DSV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, 1);
}
D3D12_CPU_DESCRIPTOR_HANDLE depthStencilDescriptor = GetCpuPlatformHandle(depthStencilView);
if (depthStencilReadView.IsNull())
{
- depthStencilReadView = Allocate(D3D12_DESCRIPTOR_HEAP_TYPE_DSV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, 1).GetOffset();
+ depthStencilReadView = AllocateHandle(D3D12_DESCRIPTOR_HEAP_TYPE_DSV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, 1);
}
D3D12_CPU_DESCRIPTOR_HANDLE depthStencilReadDescriptor = GetCpuPlatformHandle(depthStencilReadView);
@@ -274,7 +332,7 @@ namespace AZ
{
if (samplerHandle.IsNull())
{
- samplerHandle = Allocate(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, 1).GetOffset();
+ samplerHandle = AllocateHandle(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, 1);
}
D3D12_SAMPLER_DESC samplerDesc;
@@ -286,17 +344,49 @@ namespace AZ
{
if (!descriptorHandle.IsNull())
{
- ReleaseDescriptorTable(DescriptorTable(descriptorHandle, 1));
+ GetPool(descriptorHandle.m_type, descriptorHandle.m_flags).ReleaseHandle(descriptorHandle);
}
}
DescriptorTable DescriptorContext::CreateDescriptorTable(
- D3D12_DESCRIPTOR_HEAP_TYPE descriptorHeapType,
- uint32_t descriptorCount)
+ D3D12_DESCRIPTOR_HEAP_TYPE descriptorHeapType, uint32_t descriptorCount, ShaderResourceGroup* srg)
{
- return Allocate(descriptorHeapType, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, descriptorCount);
+ if (m_allowDescriptorHeapCompaction && !m_compactionInProgress)
+ {
+ // Track active SRGs in case we need to compact the shader visible cbv_srv_uav heap
+ AZStd::scoped_lock lock{ m_srgMapMutex };
+ auto iter = m_srgAllocations.find(srg);
+ if (iter == m_srgAllocations.end())
+ {
+ m_srgAllocations.emplace(srg, 1);
+ }
+ else
+ {
+ m_srgAllocations[srg]++;
+ }
+ }
+
+ return GetPool(descriptorHeapType, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE).AllocateTable(descriptorCount);
}
+ void DescriptorContext::ReleaseDescriptorTable(DescriptorTable table, ShaderResourceGroup* srg)
+ {
+ if (m_allowDescriptorHeapCompaction && !m_compactionInProgress)
+ {
+ //Track active SRGs in case we need to compact the shader visible cbv_srv_uav heap
+ AZStd::scoped_lock lock{ m_srgMapMutex };
+ auto iter = m_srgAllocations.find(srg);
+ AZ_Assert(iter != m_srgAllocations.end(), "Srg entry not found");
+ m_srgAllocations[srg]--;
+ if (m_srgAllocations[srg] == 0)
+ {
+ m_srgAllocations.erase(srg);
+ }
+ }
+
+ GetPool(table.GetType(), table.GetFlags()).ReleaseTable(table);
+ }
+
void DescriptorContext::UpdateDescriptorTableRange(
DescriptorTable gpuDestinationTable,
const DescriptorHandle* cpuSourceDescriptors,
@@ -313,14 +403,12 @@ namespace AZ
}
// Resolve destination descriptor to platform handle.
- D3D12_CPU_DESCRIPTOR_HANDLE gpuDestinationHandle = GetCpuPlatformHandle(gpuDestinationTable.GetOffset());
+ D3D12_CPU_DESCRIPTOR_HANDLE gpuDestinationHandle = GetCpuPlatformHandleForTable(gpuDestinationTable);
// An array of descriptor sizes for each range. We just want N ranges with 1 descriptor each.
AZStd::vector rangeCounts(DescriptorCount, 1);
- /**
- * We are gathering N source descriptors into a contiguous destination table.
- */
+ //We are gathering N source descriptors into a contiguous destination table.
m_device->CopyDescriptors(
1, // Number of destination ranges.
&gpuDestinationHandle, // Destination range array.
@@ -353,19 +441,24 @@ namespace AZ
}
}
}
+
+ if (m_allowDescriptorHeapCompaction)
+ {
+ m_backupStaticHandles.GarbageCollect();
+ }
}
- DescriptorTable DescriptorContext::Allocate(
+ DescriptorTable DescriptorContext::AllocateTable(
D3D12_DESCRIPTOR_HEAP_TYPE type,
D3D12_DESCRIPTOR_HEAP_FLAGS flags,
uint32_t count)
{
- return GetPool(type, flags).Allocate(count);
+ return GetPool(type, flags).AllocateTable(count);
}
- void DescriptorContext::ReleaseDescriptorTable(DescriptorTable table)
+ DescriptorHandle DescriptorContext::AllocateHandle(D3D12_DESCRIPTOR_HEAP_TYPE type, D3D12_DESCRIPTOR_HEAP_FLAGS flags, uint32_t count)
{
- GetPool(table.GetType(), table.GetFlags()).Release(table);
+ return GetPool(type, flags).AllocateHandle(count);
}
D3D12_CPU_DESCRIPTOR_HANDLE DescriptorContext::GetCpuPlatformHandle(DescriptorHandle handle) const
@@ -378,6 +471,16 @@ namespace AZ
return GetPool(handle.m_type, handle.m_flags).GetGpuPlatformHandle(handle);
}
+ D3D12_CPU_DESCRIPTOR_HANDLE DescriptorContext::GetCpuPlatformHandleForTable(DescriptorTable descTable) const
+ {
+ return GetPool(descTable.GetOffset().m_type, descTable.GetOffset().m_flags).GetCpuPlatformHandleForTable(descTable);
+ }
+
+ D3D12_GPU_DESCRIPTOR_HANDLE DescriptorContext::GetGpuPlatformHandleForTable(DescriptorTable descTable) const
+ {
+ return GetPool(descTable.GetOffset().m_type, descTable.GetOffset().m_flags).GetGpuPlatformHandleForTable(descTable);
+ }
+
DescriptorHandle DescriptorContext::GetNullHandleSRV(D3D12_SRV_DIMENSION dimension) const
{
auto iter = m_nullDescriptorsSRV.find(dimension);
@@ -431,14 +534,88 @@ namespace AZ
{
AZ_Assert(type < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES, "Trying to get pool with invalid type: [%d]", type);
AZ_Assert(flag < NumHeapFlags, "Trying to get pool with invalid flag: [%d]", flag);
- return m_pools[type][flag];
+
+ if (m_allowDescriptorHeapCompaction && IsShaderVisibleCbvSrvUavHeap(type, flag))
+ {
+ return m_shaderVisibleCbvSrvUavPools[m_currentHeapIndex];
+ }
+ else
+ {
+ return m_pools[type][flag];
+ }
}
const DescriptorPool& DescriptorContext::GetPool(uint32_t type, uint32_t flag) const
{
AZ_Assert(type < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES, "Trying to get pool with invalid type: [%d]", type);
AZ_Assert(flag < NumHeapFlags, "Trying to get pool with invalid flag: [%d]", flag);
- return m_pools[type][flag];
+ if (m_allowDescriptorHeapCompaction && IsShaderVisibleCbvSrvUavHeap(type, flag))
+ {
+ return m_shaderVisibleCbvSrvUavPools[m_currentHeapIndex];
+ }
+ else
+ {
+ return m_pools[type][flag];
+ }
+ }
+
+ RHI::ResultCode DescriptorContext::CompactDescriptorHeap()
+ {
+ //Check if heap compaction is enabled by the user. Since there is an overhead associated with heap compaction it is not enabled by default
+ if(!m_allowDescriptorHeapCompaction)
+ {
+ AZ_Assert(
+ false,
+ "Descriptor heap Compaction not allowed. Please consider increasing number of handles allowed for the second value"
+ "of DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV or enabling AllowDescriptorHeapCompaction within platformlimits.azasset file for dx12.");
+ return RHI::ResultCode::OutOfMemory;
+ }
+
+ //We need to ping-pong between two heaps as we cannot compact the active heap without updating it and that is not allowed as
+ //we need to keep that gpu memory untouched until GPU is finished consuming which can take up to 3 frames.
+ m_compactionInProgress = true;
+ DescriptorPool& srcPool = GetPool(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE);
+
+ //Update the currently active heap index
+ m_currentHeapIndex = !m_currentHeapIndex;
+ DescriptorPool& destPool = GetPool(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE);
+
+ //Copy over all the static handles first
+ for (size_t i = 0; i < m_platformLimitsDescriptor->m_numShaderVisibleCbvSrvUavStaticHandles; i++)
+ {
+ DescriptorHandle srcHandle(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, static_cast(i));
+ DescriptorHandle destHandle(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, static_cast(i));
+ m_device->CopyDescriptorsSimple(1, destPool.GetCpuPlatformHandle(destHandle), m_backupStaticHandles.GetCpuPlatformHandle(srcHandle), destHandle.m_type);
+ }
+
+ //Clone the allocator of the source pool into the destination pool
+ srcPool.CloneAllocator(destPool.GetAllocator());
+
+ {
+ //The mutex is here 'just in case' Compaction is called from more than one thread.
+ AZStd::scoped_lock lock{ m_srgMapMutex };
+ //Re-update all the descriptor tables associated with active SRGs
+ for (const auto& [srg, numAllocations] : m_srgAllocations)
+ {
+ RHI::ResultCode resultCode = static_cast(srg->GetPool())->UpdateDescriptorTableAfterCompaction(*srg, srg->GetData());
+ if (resultCode != RHI::ResultCode::Success)
+ {
+ return resultCode;
+ }
+ }
+ }
+
+ //Clear the allocator of the source pool
+ srcPool.ClearAllocator();
+
+ m_compactionInProgress = false;
+
+ return RHI::ResultCode::Success;
+ }
+
+ bool DescriptorContext::IsShaderVisibleCbvSrvUavHeap(uint32_t type, uint32_t flag) const
+ {
+ return type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV && flag == D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
}
}
}
diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/DescriptorContext.h b/Gems/Atom/RHI/DX12/Code/Source/RHI/DescriptorContext.h
index d4b6479fb2..88d2781329 100644
--- a/Gems/Atom/RHI/DX12/Code/Source/RHI/DescriptorContext.h
+++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/DescriptorContext.h
@@ -15,6 +15,8 @@
#include
#include
#include
+#include
+#include
namespace AZ
{
@@ -82,12 +84,14 @@ namespace AZ
//! Creates a GPU-visible descriptor table.
//! @param descriptorHeapType The descriptor heap to allocate from.
//! @param descriptorCount The number of descriptors to allocate.
+ //! @param srg Shader resource group with which the descriptor table is associated with
DescriptorTable CreateDescriptorTable(
- D3D12_DESCRIPTOR_HEAP_TYPE descriptorHeapType,
- uint32_t descriptorCount);
-
- void ReleaseDescriptorTable(DescriptorTable descriptorTable);
+ D3D12_DESCRIPTOR_HEAP_TYPE descriptorHeapType, uint32_t descriptorCount, ShaderResourceGroup* srg);
+ //! Releases a GPU-visible descriptor table.
+ //! @param descriptorHeapType The descriptor heap to allocate from.
+ //! @param srg Shader resource group with which the descriptor table is associated with
+ void ReleaseDescriptorTable(DescriptorTable descriptorTable, ShaderResourceGroup* srg);
//! Performs a gather of disjoint CPU-side descriptors and copies to a contiguous GPU-side descriptor table.
//! @param gpuDestinationTable The destination descriptor table that the descriptors will be uploaded to.
@@ -110,6 +114,8 @@ namespace AZ
D3D12_CPU_DESCRIPTOR_HANDLE GetCpuPlatformHandle(DescriptorHandle handle) const;
D3D12_GPU_DESCRIPTOR_HANDLE GetGpuPlatformHandle(DescriptorHandle handle) const;
+ D3D12_CPU_DESCRIPTOR_HANDLE GetCpuPlatformHandleForTable(DescriptorTable descTable) const;
+ D3D12_GPU_DESCRIPTOR_HANDLE GetGpuPlatformHandleForTable(DescriptorTable descTable) const;
void SetDescriptorHeaps(ID3D12GraphicsCommandList* commandList) const;
@@ -117,6 +123,12 @@ namespace AZ
ID3D12DeviceX* GetDevice();
+ //! Since we are only allowed one shader visible CbvSrvUav heap of a limited size in certain hardware, it is possible that
+ //! it can get fragmented by constant alloc/de-alloc of descriptor tables related to direct views or unbounded resource views within a SRG. We use two
+ //! heaps to ping pong during compaction as fragmentation can occur many times. It copies static handles directly and for all the
+ //! dynamic handles we re-update the new heap by copying over the handles from the 'non-shader visible' heap.
+ RHI::ResultCode CompactDescriptorHeap();
+
private:
void CopyDescriptor(DescriptorHandle dst, DescriptorHandle src);
@@ -129,10 +141,13 @@ namespace AZ
DescriptorPool& GetPool(uint32_t type, uint32_t flag);
const DescriptorPool& GetPool(uint32_t type, uint32_t flag) const;
- DescriptorTable Allocate(
- D3D12_DESCRIPTOR_HEAP_TYPE type,
- D3D12_DESCRIPTOR_HEAP_FLAGS flags,
- uint32_t count);
+ //! Allocates a Descriptor table which describes a contiguous range of descriptor handles
+ DescriptorTable AllocateTable(D3D12_DESCRIPTOR_HEAP_TYPE type, D3D12_DESCRIPTOR_HEAP_FLAGS flags, uint32_t count);
+
+ //! Allocates a single descriptor handle
+ DescriptorHandle AllocateHandle(D3D12_DESCRIPTOR_HEAP_TYPE type, D3D12_DESCRIPTOR_HEAP_FLAGS flags, uint32_t count);
+
+ bool IsShaderVisibleCbvSrvUavHeap(uint32_t type, uint32_t flag) const;
static const uint32_t NumHeapFlags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE + 1;
static const uint32_t s_descriptorCountMax[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES][NumHeapFlags];
@@ -147,6 +162,25 @@ namespace AZ
DescriptorHandle m_nullSamplerDescriptor;
RHI::ConstPtr m_platformLimitsDescriptor;
+
+ // Use 2 heaps below in order to ping-pong between shader visible CbvSrvUav heap when one of them fragments and run out of memory.
+ static const uint32_t MaxShaderVisibleCbvSrvUavHeaps = 2;
+ DescriptorPoolShaderVisibleCbvSrvUav m_shaderVisibleCbvSrvUavPools[MaxShaderVisibleCbvSrvUavHeaps];
+ //This pool stores a copy of static handles that can later be used to recreate the compacted shader visible CbvSrvUav heap.
+ DescriptorPool m_backupStaticHandles;
+
+ //Boolean to dictate when compaction was in progress
+ bool m_compactionInProgress = false;
+
+ //Boolean to dictate if we should support compaction for shader visible CbvSrvUav heap
+ bool m_allowDescriptorHeapCompaction = false;
+
+ //Map to store active SRGs and the number of associated descriptor tables. This is used to recreate the new compacted heap when we switch heaps
+ AZStd::unordered_map m_srgAllocations;
+ AZStd::mutex m_srgMapMutex;
+
+ //Index that holds the currently active shader visible CbvSrvUav heap
+ uint32_t m_currentHeapIndex = 0;
};
}
}
diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/DescriptorPool.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/DescriptorPool.cpp
index 7a6d96a519..96a3979f41 100644
--- a/Gems/Atom/RHI/DX12/Code/Source/RHI/DescriptorPool.cpp
+++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/DescriptorPool.cpp
@@ -18,34 +18,38 @@ namespace AZ
ID3D12DeviceX* device,
D3D12_DESCRIPTOR_HEAP_TYPE type,
D3D12_DESCRIPTOR_HEAP_FLAGS flags,
- uint32_t descriptorCount)
+ uint32_t descriptorCountForHeap,
+ uint32_t descriptorCountForAllocator)
{
- m_Desc.Type = type;
- m_Desc.Flags = flags;
- m_Desc.NumDescriptors = descriptorCount;
- m_Desc.NodeMask = 1;
+ m_desc.Type = type;
+ m_desc.Flags = flags;
+ m_desc.NumDescriptors = descriptorCountForHeap;
+ m_desc.NodeMask = 1;
ID3D12DescriptorHeap* heap;
- DX12::AssertSuccess(device->CreateDescriptorHeap(&m_Desc, IID_GRAPHICS_PPV_ARGS(&heap)));
+ DX12::AssertSuccess(device->CreateDescriptorHeap(&m_desc, IID_GRAPHICS_PPV_ARGS(&heap)));
heap->SetName(L"DescriptorHeap");
- m_DescriptorHeap.Attach(heap);
- m_Stride = device->GetDescriptorHandleIncrementSize(m_Desc.Type);
+ m_descriptorHeap.Attach(heap);
+ m_stride = device->GetDescriptorHandleIncrementSize(m_desc.Type);
- m_CpuStart = heap->GetCPUDescriptorHandleForHeapStart();
- m_GpuStart = {};
-
- if (RHI::CheckBitsAny(flags, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE))
- {
- m_GpuStart = heap->GetGPUDescriptorHandleForHeapStart();
- }
+ m_cpuStart = heap->GetCPUDescriptorHandleForHeapStart();
+ m_gpuStart = {};
const bool isGpuVisible = RHI::CheckBitsAll(flags, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE);
+ if (isGpuVisible)
+ {
+ m_gpuStart = heap->GetGPUDescriptorHandleForHeapStart();
+ }
+
if (isGpuVisible)
{
RHI::FreeListAllocator::Descriptor descriptor;
descriptor.m_alignmentInBytes = 1;
- descriptor.m_capacityInBytes = descriptorCount;
+
+ //It is possible for descriptorCountForAllocator to not match descriptorCountForHeap for DescriptorPoolShaderVisibleCbvSrvUav
+ //heaps in which case descriptorCountForAllocator defines the number of static handles
+ descriptor.m_capacityInBytes = aznumeric_cast(descriptorCountForAllocator);
descriptor.m_garbageCollectLatency = RHI::Limits::Device::FrameCountMax;
RHI::FreeListAllocator* allocator = aznew RHI::FreeListAllocator();
@@ -56,10 +60,11 @@ namespace AZ
{
// Non-shader-visible heaps don't require contiguous descriptors. Therefore, we can allocate
// them using a block allocator.
+
RHI::PoolAllocator::Descriptor descriptor;
descriptor.m_alignmentInBytes = 1;
descriptor.m_elementSize = 1;
- descriptor.m_capacityInBytes = descriptorCount;
+ descriptor.m_capacityInBytes = aznumeric_cast(descriptorCountForAllocator);
descriptor.m_garbageCollectLatency = 0;
RHI::PoolAllocator* allocator = aznew RHI::PoolAllocator();
@@ -68,7 +73,7 @@ namespace AZ
}
}
- DescriptorTable DescriptorPool::Allocate(uint32_t count)
+ DescriptorHandle DescriptorPool::AllocateHandle(uint32_t count)
{
RHI::VirtualAddress address;
{
@@ -78,24 +83,34 @@ namespace AZ
if (address.IsValid())
{
- DescriptorHandle handle(m_Desc.Type, m_Desc.Flags, static_cast(address.m_ptr));
- return DescriptorTable(handle, static_cast(count));
+ DescriptorHandle handle(m_desc.Type, m_desc.Flags, static_cast(address.m_ptr));
+ return handle;
}
else
{
- return DescriptorTable{};
+ return DescriptorHandle{};
}
}
- void DescriptorPool::Release(DescriptorTable table)
+ void DescriptorPool::ReleaseHandle(DescriptorHandle handle)
{
- if (table.IsNull())
+ if (handle.IsNull())
{
return;
}
AZStd::lock_guard lock(m_mutex);
- m_allocator->DeAllocate(RHI::VirtualAddress::CreateFromOffset(table.GetOffset().m_index));
+ m_allocator->DeAllocate(RHI::VirtualAddress::CreateFromOffset(handle.m_index));
+ }
+
+ DescriptorTable DescriptorPool::AllocateTable(uint32_t count)
+ {
+ return DescriptorTable(AllocateHandle(count), static_cast(count));
+ }
+
+ void DescriptorPool::ReleaseTable(DescriptorTable table)
+ {
+ ReleaseHandle(table.GetOffset());
}
void DescriptorPool::GarbageCollect()
@@ -106,20 +121,134 @@ namespace AZ
ID3D12DescriptorHeap* DescriptorPool::GetPlatformHeap() const
{
- return m_DescriptorHeap.Get();
+ return m_descriptorHeap.Get();
}
D3D12_CPU_DESCRIPTOR_HANDLE DescriptorPool::GetCpuPlatformHandle(DescriptorHandle handle) const
{
AZ_Assert(handle.m_index != DescriptorHandle::NullIndex, "Index is invalid");
- return D3D12_CPU_DESCRIPTOR_HANDLE{ m_CpuStart.ptr + handle.m_index * m_Stride };
+ return D3D12_CPU_DESCRIPTOR_HANDLE{ m_cpuStart.ptr + handle.m_index * m_stride };
}
D3D12_GPU_DESCRIPTOR_HANDLE DescriptorPool::GetGpuPlatformHandle(DescriptorHandle handle) const
{
AZ_Assert(handle.IsShaderVisible(), "Handle is not shader visible");
AZ_Assert(handle.m_index != DescriptorHandle::NullIndex, "Index is invalid");
- return D3D12_GPU_DESCRIPTOR_HANDLE{ m_GpuStart.ptr + handle.m_index * m_Stride };
+ return D3D12_GPU_DESCRIPTOR_HANDLE{ m_gpuStart.ptr + (handle.m_index * m_stride) };
+ }
+
+ D3D12_CPU_DESCRIPTOR_HANDLE DescriptorPool::GetCpuPlatformHandleForTable(DescriptorTable descTable) const
+ {
+ DescriptorHandle handle = descTable.GetOffset();
+ AZ_Assert(handle.m_index != DescriptorHandle::NullIndex, "Index is invalid");
+ return D3D12_CPU_DESCRIPTOR_HANDLE{ m_cpuStart.ptr + handle.m_index * m_stride };
+ }
+
+ D3D12_GPU_DESCRIPTOR_HANDLE DescriptorPool::GetGpuPlatformHandleForTable(DescriptorTable descTable) const
+ {
+ DescriptorHandle handle = descTable.GetOffset();
+ AZ_Assert(handle.IsShaderVisible(), "Handle is not shader visible");
+ AZ_Assert(handle.m_index != DescriptorHandle::NullIndex, "Index is invalid");
+ return D3D12_GPU_DESCRIPTOR_HANDLE{ m_gpuStart.ptr + (handle.m_index * m_stride) };
+ }
+
+ void DescriptorPool::CloneAllocator(RHI::Allocator* newAllocator)
+ {
+ m_allocator->Clone(newAllocator);
+ }
+
+ void DescriptorPool::ClearAllocator()
+ {
+ AZ_Assert(m_gpuStart.ptr, "Clearing the allocator is only supported for the gpu visible heap as only this heap can be compacted");
+ static_cast(m_allocator.get())
+ ->Init(static_cast(m_allocator.get())->GetDescriptor());
+ }
+
+ RHI::Allocator* DescriptorPool::GetAllocator() const
+ {
+ return m_allocator.get();
+ }
+
+ void DescriptorPoolShaderVisibleCbvSrvUav::Init(
+ ID3D12DeviceX* device,
+ D3D12_DESCRIPTOR_HEAP_TYPE type,
+ D3D12_DESCRIPTOR_HEAP_FLAGS flags,
+ uint32_t descriptorCount,
+ uint32_t staticHandlesCount)
+ {
+ //This pool manages two allocators. The allocator in the base class manages static handles
+ Base::Init(device, type, flags, descriptorCount, staticHandlesCount);
+
+ //This allocator manages dynamic handles associated with descriptor tables. This allows us to
+ //reconstruct the full heap in a compact manner if it ever fragments.
+ RHI::FreeListAllocator::Descriptor descriptor;
+ descriptor.m_alignmentInBytes = 1;
+ descriptor.m_capacityInBytes = aznumeric_cast(descriptorCount - staticHandlesCount);
+ descriptor.m_garbageCollectLatency = RHI::Limits::Device::FrameCountMax;
+
+ RHI::FreeListAllocator* allocator = aznew RHI::FreeListAllocator();
+ allocator->Init(descriptor);
+ m_unboundedArrayAllocator.reset(allocator);
+
+ //Cache the starting point of the dynamic section of the heap
+ m_startingHandleIndex = staticHandlesCount;
+ }
+
+ DescriptorTable DescriptorPoolShaderVisibleCbvSrvUav::AllocateTable(uint32_t count)
+ {
+ RHI::VirtualAddress address;
+ {
+ AZStd::lock_guard lock(m_mutex);
+ address = m_unboundedArrayAllocator->Allocate(count, 1);
+ }
+
+ if (address.IsValid())
+ {
+ DescriptorHandle handle(m_desc.Type, m_desc.Flags, static_cast(address.m_ptr));
+ return DescriptorTable(handle, static_cast(count));
+ }
+ else
+ {
+ return DescriptorTable{};
+ }
+ }
+
+ void DescriptorPoolShaderVisibleCbvSrvUav::ReleaseTable(DescriptorTable table)
+ {
+ if (table.IsNull())
+ {
+ return;
+ }
+
+ AZStd::lock_guard lock(m_mutex);
+ m_unboundedArrayAllocator->DeAllocate(RHI::VirtualAddress::CreateFromOffset(table.GetOffset().m_index));
+ }
+
+ void DescriptorPoolShaderVisibleCbvSrvUav::GarbageCollect()
+ {
+ Base::GarbageCollect();
+ m_unboundedArrayAllocator->GarbageCollect();
+ }
+
+ D3D12_CPU_DESCRIPTOR_HANDLE DescriptorPoolShaderVisibleCbvSrvUav::GetCpuPlatformHandleForTable(DescriptorTable descTable) const
+ {
+ DescriptorHandle handle = descTable.GetOffset();
+ AZ_Assert(handle.m_index != DescriptorHandle::NullIndex, "Index is invalid");
+ return D3D12_CPU_DESCRIPTOR_HANDLE{ m_cpuStart.ptr + (m_startingHandleIndex * m_stride) + (handle.m_index * m_stride) };
+ }
+
+ D3D12_GPU_DESCRIPTOR_HANDLE DescriptorPoolShaderVisibleCbvSrvUav::GetGpuPlatformHandleForTable(DescriptorTable descTable) const
+ {
+ DescriptorHandle handle = descTable.GetOffset();
+ AZ_Assert(handle.IsShaderVisible(), "Handle is not shader visible");
+ AZ_Assert(handle.m_index != DescriptorHandle::NullIndex, "Index is invalid");
+ return D3D12_GPU_DESCRIPTOR_HANDLE{ m_gpuStart.ptr + (m_startingHandleIndex * m_stride) + (handle.m_index * m_stride) };
+ }
+
+ void DescriptorPoolShaderVisibleCbvSrvUav::ClearAllocator()
+ {
+ Base::ClearAllocator();
+ static_cast(m_unboundedArrayAllocator.get())->Init(static_cast(m_unboundedArrayAllocator.get())->GetDescriptor());
}
}
}
diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/DescriptorPool.h b/Gems/Atom/RHI/DX12/Code/Source/RHI/DescriptorPool.h
index cd90d1aba3..2237841ea7 100644
--- a/Gems/Atom/RHI/DX12/Code/Source/RHI/DescriptorPool.h
+++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/DescriptorPool.h
@@ -18,37 +18,91 @@ namespace AZ
{
namespace DX12
{
+ //! This class defines a Descriptor pool which manages all the descriptors used for binding resources
class DescriptorPool
{
public:
DescriptorPool() = default;
+ virtual ~DescriptorPool() = default;
- void Init(
+ //! Initialize the native heap as well as init the allocators tracking the memory for descriptor handles
+ virtual void Init(
ID3D12DeviceX* device,
D3D12_DESCRIPTOR_HEAP_TYPE type,
D3D12_DESCRIPTOR_HEAP_FLAGS flags,
- uint32_t descriptorCount);
+ uint32_t descriptorCountForHeap,
+ uint32_t descriptorCountForAllocator);
ID3D12DescriptorHeap* GetPlatformHeap() const;
- DescriptorTable Allocate(uint32_t count = 1);
+ //! Allocate a Descriptor handles
+ DescriptorHandle AllocateHandle(uint32_t count = 1);
+ //! Release a descriptor handle
+ void ReleaseHandle(DescriptorHandle table);
+ //! Allocate a range contiguous handles (i.e Descriptor table)
+ virtual DescriptorTable AllocateTable(uint32_t count = 1);
+ //! Release a range contiguous handles (i.e Descriptor table)
+ virtual void ReleaseTable(DescriptorTable table);
+ //! Garbage collection for freed handles or tables
+ virtual void GarbageCollect();
+ //Get native pointers from the heap
+ virtual D3D12_CPU_DESCRIPTOR_HANDLE GetCpuPlatformHandleForTable(DescriptorTable handle) const;
+ virtual D3D12_GPU_DESCRIPTOR_HANDLE GetGpuPlatformHandleForTable(DescriptorTable handle) const;
+ //Clear the tracking allocator
+ virtual void ClearAllocator();
- void Release(DescriptorTable table);
-
- void GarbageCollect();
D3D12_CPU_DESCRIPTOR_HANDLE GetCpuPlatformHandle(DescriptorHandle handle) const;
D3D12_GPU_DESCRIPTOR_HANDLE GetGpuPlatformHandle(DescriptorHandle handle) const;
- private:
- D3D12_CPU_DESCRIPTOR_HANDLE m_CpuStart = {};
- D3D12_GPU_DESCRIPTOR_HANDLE m_GpuStart = {};
- D3D12_CPU_DESCRIPTOR_HANDLE m_NullDescriptor = {};
- uint32_t m_Stride = 0;
- D3D12_DESCRIPTOR_HEAP_DESC m_Desc;
- Microsoft::WRL::ComPtr m_DescriptorHeap;
+ //Clone the tracking allocator
+ void CloneAllocator(RHI::Allocator* newAllocator);
+ RHI::Allocator* GetAllocator() const;
+
+ protected:
+ D3D12_DESCRIPTOR_HEAP_DESC m_desc;
AZStd::mutex m_mutex;
+ D3D12_CPU_DESCRIPTOR_HANDLE m_cpuStart = {};
+ D3D12_GPU_DESCRIPTOR_HANDLE m_gpuStart = {};
+ uint32_t m_stride = 0;
+ private:
+
+ // Native heap
+ Microsoft::WRL::ComPtr m_descriptorHeap;
+
+ // Allocator used to manage the whole native heap. In the case of DescriptorPoolShaderVisibleCbvSrvUav this allocator
+ // is used to manage the part of the heap that only manages static handles.
AZStd::unique_ptr m_allocator;
};
+
+ //! A specialized pool that specifically handles Descriptor tables for Cbv/Srv/Uav views and allows for Compaction
+ //! Specifically this pool handles the dynamic part of the heap
+ class DescriptorPoolShaderVisibleCbvSrvUav : public DescriptorPool
+ {
+ using Base = DescriptorPool;
+
+ public:
+ void Init(
+ ID3D12DeviceX* device,
+ D3D12_DESCRIPTOR_HEAP_TYPE type,
+ D3D12_DESCRIPTOR_HEAP_FLAGS flags,
+ uint32_t descriptorCount,
+ uint32_t staticHandlesCount);
+
+ DescriptorTable AllocateTable(uint32_t count = 1) override;
+ void ReleaseTable(DescriptorTable table) override;
+ void GarbageCollect() override;
+
+ D3D12_CPU_DESCRIPTOR_HANDLE GetCpuPlatformHandleForTable(DescriptorTable handle) const override;
+ D3D12_GPU_DESCRIPTOR_HANDLE GetGpuPlatformHandleForTable(DescriptorTable handle) const override;
+ void ClearAllocator() override;
+
+ private:
+
+ // A separate allocator that handles descriptor tables which are dynamic in nature and may fragment and require compaction
+ AZStd::unique_ptr