Merge branch 'development' of https://github.com/o3de/o3de into daimini/FocusMode/breadcrumbs

Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com>

# Conflicts:
#	Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerTreeView.cpp
This commit is contained in:
Danilo Aimini
2021-09-27 21:23:38 -07:00
110 changed files with 3299 additions and 1637 deletions
@@ -0,0 +1,7 @@
<svg width="24" height="33" viewBox="0 0 24 33" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="5" y="7" width="2" height="12" fill="#808080"/>
<rect x="5" y="19" width="2" height="14" fill="#808080"/>
<rect x="17" y="16" width="2" height="12" transform="rotate(90 17 16)" fill="#808080"/>
<circle cx="6" cy="6" r="2" fill="#808080"/>
<circle cx="18" cy="17" r="2" fill="#808080"/>
</svg>

After

Width:  |  Height:  |  Size: 398 B

@@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="5" width="2" height="12" fill="grey"/>
<rect x="17" y="12" width="2" height="12" transform="rotate(90 17 12)" fill="grey"/>
<circle cx="18" cy="13" r="2" fill="grey"/>
</svg>

After

Width:  |  Height:  |  Size: 280 B

@@ -0,0 +1,6 @@
<svg width="24" height="26" viewBox="0 0 24 26" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="5" width="2" height="12" fill="grey"/>
<rect x="5" y="14" width="2" height="12" fill="grey"/>
<rect x="17" y="12" width="2" height="12" transform="rotate(90 17 12)" fill="grey"/>
<circle cx="18" cy="13" r="2" fill="grey"/>
</svg>

After

Width:  |  Height:  |  Size: 335 B

@@ -0,0 +1,6 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="5" y="7" width="2" height="7" fill="#808080"/>
<rect x="17" y="12" width="2" height="12" transform="rotate(90 17 12)" fill="#808080"/>
<circle cx="6" cy="6" r="2" fill="#808080"/>
<circle cx="18" cy="13" r="2" fill="#808080"/>
</svg>

After

Width:  |  Height:  |  Size: 339 B

@@ -9,7 +9,7 @@
#include "QtEditorApplication.h" #include "QtEditorApplication.h"
#ifdef PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB #ifdef PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
#include <AzFramework/API/ApplicationAPI_Linux.h> #include <AzFramework/XcbEventHandler.h>
#endif #endif
namespace Editor namespace Editor
@@ -19,7 +19,7 @@ namespace Editor
if (GetIEditor()->IsInGameMode()) if (GetIEditor()->IsInGameMode())
{ {
#ifdef PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB #ifdef PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
AzFramework::LinuxXcbEventHandlerBus::Broadcast(&AzFramework::LinuxXcbEventHandler::HandleXcbEvent, static_cast<xcb_generic_event_t*>(message)); AzFramework::XcbEventHandlerBus::Broadcast(&AzFramework::XcbEventHandler::HandleXcbEvent, static_cast<xcb_generic_event_t*>(message));
#endif #endif
return true; return true;
} }
@@ -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 const char* InputChannelId::GetName() const
{ {
return m_name; return m_name.c_str();
} }
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
@@ -11,6 +11,7 @@
#include <AzCore/Math/Crc.h> #include <AzCore/Math/Crc.h>
#include <AzCore/RTTI/ReflectContext.h> #include <AzCore/RTTI/ReflectContext.h>
#include <AzCore/std/hash.h> #include <AzCore/std/hash.h>
#include <AzCore/std/string/fixed_string.h>
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
namespace AzFramework namespace AzFramework
@@ -22,8 +23,7 @@ namespace AzFramework
public: public:
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
// Constants // Constants
static const int NAME_BUFFER_SIZE = 64; static constexpr int MAX_NAME_LENGTH = 64;
static const int MAX_NAME_LENGTH = NAME_BUFFER_SIZE - 1;
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
// Allocator // Allocator
@@ -39,21 +39,28 @@ namespace AzFramework
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
//! Constructor //! Constructor
//! \param[in] name Name of the input channel (will be truncated if exceeds MAX_NAME_LENGTH) //! \param[in] name Name of the input channel (will be ignored if exceeds MAX_NAME_LENGTH)
explicit InputChannelId(const char* name = ""); explicit constexpr InputChannelId(AZStd::string_view name = "")
: m_name(name)
, m_crc32(name)
{
}
//////////////////////////////////////////////////////////////////////////////////////////// constexpr InputChannelId(const InputChannelId& other) = default;
//! Copy constructor constexpr InputChannelId(InputChannelId&& other) = default;
//! \param[in] other Another instance of the class to copy from constexpr InputChannelId& operator=(const InputChannelId& other)
InputChannelId(const InputChannelId& other); {
m_name = other.m_name;
//////////////////////////////////////////////////////////////////////////////////////////// m_crc32 = other.m_crc32;
//! Copy assignment operator return *this;
//! \param[in] other Another instance of the class to copy from }
InputChannelId& operator=(const InputChannelId& other); constexpr InputChannelId& operator=(InputChannelId&& other)
{
//////////////////////////////////////////////////////////////////////////////////////////// m_name = AZStd::move(other.m_name);
//! Default destructor m_crc32 = AZStd::move(other.m_crc32);
other.m_crc32 = 0;
return *this;
}
~InputChannelId() = default; ~InputChannelId() = default;
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
@@ -77,7 +84,7 @@ namespace AzFramework
private: private:
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
// Variables // Variables
char m_name[NAME_BUFFER_SIZE]; //!< Name of the input channel AZStd::fixed_string<MAX_NAME_LENGTH> m_name; //!< Name of the input channel
AZ::Crc32 m_crc32; //!< Crc32 of the input channel AZ::Crc32 m_crc32; //!< Crc32 of the input channel
}; };
} // namespace AzFramework } // namespace AzFramework
@@ -28,91 +28,6 @@ namespace AzFramework
return (inputDeviceId.GetNameCrc32() == IdForIndex0.GetNameCrc32()); 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<InputChannelId, 14> 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<InputChannelId, 2> InputDeviceGamepad::Trigger::All =
{{
L2,
R2
}};
////////////////////////////////////////////////////////////////////////////////////////////////
const InputChannelId InputDeviceGamepad::ThumbStickAxis2D::L("gamepad_thumbstick_l");
const InputChannelId InputDeviceGamepad::ThumbStickAxis2D::R("gamepad_thumbstick_r");
const AZStd::array<InputChannelId, 2> 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<InputChannelId, 4> 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<InputChannelId, 8> InputDeviceGamepad::ThumbStickDirection::All =
{{
LU,
LD,
LL,
LR,
RU,
RD,
RL,
RR
}};
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
void InputDeviceGamepad::Reflect(AZ::ReflectContext* context) void InputDeviceGamepad::Reflect(AZ::ReflectContext* context)
{ {
@@ -59,75 +59,115 @@ namespace AzFramework
//! All the input channel ids that identify game-pad digital button input //! All the input channel ids that identify game-pad digital button input
struct Button struct Button
{ {
static const InputChannelId A; //!< The bottom diamond face button static constexpr inline InputChannelId A{"gamepad_button_a"}; //!< The bottom diamond face button
static const InputChannelId B; //!< The right diamond face button static constexpr inline InputChannelId B{"gamepad_button_b"}; //!< The right diamond face button
static const InputChannelId X; //!< The left diamond face button static constexpr inline InputChannelId X{"gamepad_button_x"}; //!< The left diamond face button
static const InputChannelId Y; //!< The top diamond face button static constexpr inline InputChannelId Y{"gamepad_button_y"}; //!< The top diamond face button
static const InputChannelId L1; //!< The top-left shoulder bumper button static constexpr inline InputChannelId L1{"gamepad_button_l1"}; //!< The top-left shoulder bumper button
static const InputChannelId R1; //!< The top-right shoulder bumper button static constexpr inline InputChannelId R1{"gamepad_button_r1"}; //!< The top-right shoulder bumper button
static const InputChannelId L3; //!< The left thumb-stick click button static constexpr inline InputChannelId L3{"gamepad_button_l3"}; //!< The left thumb-stick click button
static const InputChannelId R3; //!< The right thumb-stick click button static constexpr inline InputChannelId R3{"gamepad_button_r3"}; //!< The right thumb-stick click button
static const InputChannelId DU; //!< The up directional pad button static constexpr inline InputChannelId DU{"gamepad_button_d_up"}; //!< The up directional pad button
static const InputChannelId DD; //!< The down directional pad button static constexpr inline InputChannelId DD{"gamepad_button_d_down"}; //!< The down directional pad button
static const InputChannelId DL; //!< The left directional pad button static constexpr inline InputChannelId DL{"gamepad_button_d_left"}; //!< The left directional pad button
static const InputChannelId DR; //!< The right directional pad button static constexpr inline InputChannelId DR{"gamepad_button_d_right"}; //!< The right directional pad button
static const InputChannelId Start; //!< The start/pause/options button static constexpr inline InputChannelId Start{"gamepad_button_start"}; //!< The start/pause/options button
static const InputChannelId Select; //!< The select/back button static constexpr inline InputChannelId Select{"gamepad_button_select"}; //!< The select/back button
//!< All digital game-pad button ids //!< All digital game-pad button ids
static const AZStd::array<InputChannelId, 14> 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 //! All the input channel ids that identify game-pad analog trigger input
struct Trigger struct Trigger
{ {
static const InputChannelId L2; //!< The bottom-left shoulder trigger static constexpr inline InputChannelId L2{"gamepad_trigger_l2"}; //!< The bottom-left shoulder trigger
static const InputChannelId R2; //!< The bottom-right shoulder trigger static constexpr inline InputChannelId R2{"gamepad_trigger_r2"}; //!< The bottom-right shoulder trigger
//!< All analog game-pad trigger ids //!< All analog game-pad trigger ids
static const AZStd::array<InputChannelId, 2> All; static constexpr inline AZStd::array All
{
L2,
R2
};
}; };
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
//! All the input channel ids that identify game-pad thumb-stick 2D axis input //! All the input channel ids that identify game-pad thumb-stick 2D axis input
struct ThumbStickAxis2D struct ThumbStickAxis2D
{ {
static const InputChannelId L; //!< The left-hand thumb-stick static constexpr inline InputChannelId L{"gamepad_thumbstick_l"}; //!< The left-hand thumb-stick
static const InputChannelId R; //!< The right-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 //!< All game-pad thumb-stick 2D axis input channel ids
static const AZStd::array<InputChannelId, 2> All; static constexpr inline AZStd::array All
{
L,
R
};
}; };
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
//! All the input channel ids that identify game-pad thumb-stick 1D axis input //! All the input channel ids that identify game-pad thumb-stick 1D axis input
struct ThumbStickAxis1D struct ThumbStickAxis1D
{ {
static const InputChannelId LX; //!< X-axis of the left-hand thumb-stick static constexpr inline InputChannelId LX{"gamepad_thumbstick_l_x"}; //!< X-axis of the left-hand thumb-stick
static const InputChannelId LY; //!< Y-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 const InputChannelId RX; //!< X-axis of the right-hand thumb-stick static constexpr inline InputChannelId RX{"gamepad_thumbstick_r_x"}; //!< X-axis of the right-hand thumb-stick
static const InputChannelId RY; //!< Y-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 //!< All game-pad thumb-stick 1D axis input channel ids
static const AZStd::array<InputChannelId, 4> All; static constexpr inline AZStd::array All
{
LX,
LY,
RX,
RY
};
}; };
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
//! All the input channel ids that identify game-pad thumb-stick directional input //! All the input channel ids that identify game-pad thumb-stick directional input
struct ThumbStickDirection struct ThumbStickDirection
{ {
static const InputChannelId LU; //!< Up on the left-hand thumb-stick static constexpr inline InputChannelId LU{"gamepad_thumbstick_l_up"}; //!< Up on the left-hand thumb-stick
static const InputChannelId LD; //!< Down on the left-hand thumb-stick static constexpr inline InputChannelId LD{"gamepad_thumbstick_l_down"}; //!< Down on the left-hand thumb-stick
static const InputChannelId LL; //!< Left on the left-hand thumb-stick static constexpr inline InputChannelId LL{"gamepad_thumbstick_l_left"}; //!< Left on the left-hand thumb-stick
static const InputChannelId LR; //!< Right on the left-hand thumb-stick static constexpr inline InputChannelId LR{"gamepad_thumbstick_l_right"}; //!< Right on the left-hand thumb-stick
static const InputChannelId RU; //!< Up on the left-hand thumb-stick static constexpr inline InputChannelId RU{"gamepad_thumbstick_r_up"}; //!< Up on the left-hand thumb-stick
static const InputChannelId RD; //!< Down on the left-hand thumb-stick static constexpr inline InputChannelId RD{"gamepad_thumbstick_r_down"}; //!< Down on the left-hand thumb-stick
static const InputChannelId RL; //!< Left on the left-hand thumb-stick static constexpr inline InputChannelId RL{"gamepad_thumbstick_r_left"}; //!< Left on the left-hand thumb-stick
static const InputChannelId RR; //!< Right 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 //!< All game-pad thumb-stick directional input channel ids
static const AZStd::array<InputChannelId, 8> All; static constexpr inline AZStd::array All
{
LU,
LD,
LL,
LR,
RU,
RD,
RL,
RR
};
}; };
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
@@ -24,279 +24,6 @@ namespace AzFramework
return (inputDeviceId.GetNameCrc32() == Id.GetNameCrc32()); 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<InputChannelId, 112> 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) ModifierKeyMask GetCorrespondingModifierKeyMask(const InputChannelId& channelId)
{ {
@@ -94,137 +94,268 @@ namespace AzFramework
struct Key struct Key
{ {
// Alphanumeric Keys // Alphanumeric Keys
static const InputChannelId Alphanumeric0; //!< The 0 key static constexpr inline InputChannelId Alphanumeric0{"keyboard_key_alphanumeric_0"}; //!< The 0 key
static const InputChannelId Alphanumeric1; //!< The 1 key static constexpr inline InputChannelId Alphanumeric1{"keyboard_key_alphanumeric_1"}; //!< The 1 key
static const InputChannelId Alphanumeric2; //!< The 2 key static constexpr inline InputChannelId Alphanumeric2{"keyboard_key_alphanumeric_2"}; //!< The 2 key
static const InputChannelId Alphanumeric3; //!< The 3 key static constexpr inline InputChannelId Alphanumeric3{"keyboard_key_alphanumeric_3"}; //!< The 3 key
static const InputChannelId Alphanumeric4; //!< The 4 key static constexpr inline InputChannelId Alphanumeric4{"keyboard_key_alphanumeric_4"}; //!< The 4 key
static const InputChannelId Alphanumeric5; //!< The 5 key static constexpr inline InputChannelId Alphanumeric5{"keyboard_key_alphanumeric_5"}; //!< The 5 key
static const InputChannelId Alphanumeric6; //!< The 6 key static constexpr inline InputChannelId Alphanumeric6{"keyboard_key_alphanumeric_6"}; //!< The 6 key
static const InputChannelId Alphanumeric7; //!< The 7 key static constexpr inline InputChannelId Alphanumeric7{"keyboard_key_alphanumeric_7"}; //!< The 7 key
static const InputChannelId Alphanumeric8; //!< The 8 key static constexpr inline InputChannelId Alphanumeric8{"keyboard_key_alphanumeric_8"}; //!< The 8 key
static const InputChannelId Alphanumeric9; //!< The 9 key static constexpr inline InputChannelId Alphanumeric9{"keyboard_key_alphanumeric_9"}; //!< The 9 key
static const InputChannelId AlphanumericA; //!< The A key static constexpr inline InputChannelId AlphanumericA{"keyboard_key_alphanumeric_A"}; //!< The A key
static const InputChannelId AlphanumericB; //!< The B key static constexpr inline InputChannelId AlphanumericB{"keyboard_key_alphanumeric_B"}; //!< The B key
static const InputChannelId AlphanumericC; //!< The C key static constexpr inline InputChannelId AlphanumericC{"keyboard_key_alphanumeric_C"}; //!< The C key
static const InputChannelId AlphanumericD; //!< The D key static constexpr inline InputChannelId AlphanumericD{"keyboard_key_alphanumeric_D"}; //!< The D key
static const InputChannelId AlphanumericE; //!< The E key static constexpr inline InputChannelId AlphanumericE{"keyboard_key_alphanumeric_E"}; //!< The E key
static const InputChannelId AlphanumericF; //!< The F key static constexpr inline InputChannelId AlphanumericF{"keyboard_key_alphanumeric_F"}; //!< The F key
static const InputChannelId AlphanumericG; //!< The G key static constexpr inline InputChannelId AlphanumericG{"keyboard_key_alphanumeric_G"}; //!< The G key
static const InputChannelId AlphanumericH; //!< The H key static constexpr inline InputChannelId AlphanumericH{"keyboard_key_alphanumeric_H"}; //!< The H key
static const InputChannelId AlphanumericI; //!< The I key static constexpr inline InputChannelId AlphanumericI{"keyboard_key_alphanumeric_I"}; //!< The I key
static const InputChannelId AlphanumericJ; //!< The J key static constexpr inline InputChannelId AlphanumericJ{"keyboard_key_alphanumeric_J"}; //!< The J key
static const InputChannelId AlphanumericK; //!< The K key static constexpr inline InputChannelId AlphanumericK{"keyboard_key_alphanumeric_K"}; //!< The K key
static const InputChannelId AlphanumericL; //!< The L key static constexpr inline InputChannelId AlphanumericL{"keyboard_key_alphanumeric_L"}; //!< The L key
static const InputChannelId AlphanumericM; //!< The M key static constexpr inline InputChannelId AlphanumericM{"keyboard_key_alphanumeric_M"}; //!< The M key
static const InputChannelId AlphanumericN; //!< The N key static constexpr inline InputChannelId AlphanumericN{"keyboard_key_alphanumeric_N"}; //!< The N key
static const InputChannelId AlphanumericO; //!< The O key static constexpr inline InputChannelId AlphanumericO{"keyboard_key_alphanumeric_O"}; //!< The O key
static const InputChannelId AlphanumericP; //!< The P key static constexpr inline InputChannelId AlphanumericP{"keyboard_key_alphanumeric_P"}; //!< The P key
static const InputChannelId AlphanumericQ; //!< The Q key static constexpr inline InputChannelId AlphanumericQ{"keyboard_key_alphanumeric_Q"}; //!< The Q key
static const InputChannelId AlphanumericR; //!< The R key static constexpr inline InputChannelId AlphanumericR{"keyboard_key_alphanumeric_R"}; //!< The R key
static const InputChannelId AlphanumericS; //!< The S key static constexpr inline InputChannelId AlphanumericS{"keyboard_key_alphanumeric_S"}; //!< The S key
static const InputChannelId AlphanumericT; //!< The T key static constexpr inline InputChannelId AlphanumericT{"keyboard_key_alphanumeric_T"}; //!< The T key
static const InputChannelId AlphanumericU; //!< The U key static constexpr inline InputChannelId AlphanumericU{"keyboard_key_alphanumeric_U"}; //!< The U key
static const InputChannelId AlphanumericV; //!< The V key static constexpr inline InputChannelId AlphanumericV{"keyboard_key_alphanumeric_V"}; //!< The V key
static const InputChannelId AlphanumericW; //!< The W key static constexpr inline InputChannelId AlphanumericW{"keyboard_key_alphanumeric_W"}; //!< The W key
static const InputChannelId AlphanumericX; //!< The X key static constexpr inline InputChannelId AlphanumericX{"keyboard_key_alphanumeric_X"}; //!< The X key
static const InputChannelId AlphanumericY; //!< The Y key static constexpr inline InputChannelId AlphanumericY{"keyboard_key_alphanumeric_Y"}; //!< The Y key
static const InputChannelId AlphanumericZ; //!< The Z key static constexpr inline InputChannelId AlphanumericZ{"keyboard_key_alphanumeric_Z"}; //!< The Z key
// Edit (and escape) Keys // Edit {and escape} Keys
static const InputChannelId EditBackspace; //!< The backspace key static constexpr inline InputChannelId EditBackspace{"keyboard_key_edit_backspace"}; //!< The backspace key
static const InputChannelId EditCapsLock; //!< The caps lock key static constexpr inline InputChannelId EditCapsLock{"keyboard_key_edit_capslock"}; //!< The caps lock key
static const InputChannelId EditEnter; //!< The enter/return key static constexpr inline InputChannelId EditEnter{"keyboard_key_edit_enter"}; //!< The enter/return key
static const InputChannelId EditSpace; //!< The spacebar key static constexpr inline InputChannelId EditSpace{"keyboard_key_edit_space"}; //!< The spacebar key
static const InputChannelId EditTab; //!< The tab key static constexpr inline InputChannelId EditTab{"keyboard_key_edit_tab"}; //!< The tab key
static const InputChannelId Escape; //!< The escape key static constexpr inline InputChannelId Escape{"keyboard_key_escape"}; //!< The escape key
// Function Keys // Function Keys
static const InputChannelId Function01; //!< The F1 key static constexpr inline InputChannelId Function01{"keyboard_key_function_F01"}; //!< The F1 key
static const InputChannelId Function02; //!< The F2 key static constexpr inline InputChannelId Function02{"keyboard_key_function_F02"}; //!< The F2 key
static const InputChannelId Function03; //!< The F3 key static constexpr inline InputChannelId Function03{"keyboard_key_function_F03"}; //!< The F3 key
static const InputChannelId Function04; //!< The F4 key static constexpr inline InputChannelId Function04{"keyboard_key_function_F04"}; //!< The F4 key
static const InputChannelId Function05; //!< The F5 key static constexpr inline InputChannelId Function05{"keyboard_key_function_F05"}; //!< The F5 key
static const InputChannelId Function06; //!< The F6 key static constexpr inline InputChannelId Function06{"keyboard_key_function_F06"}; //!< The F6 key
static const InputChannelId Function07; //!< The F7 key static constexpr inline InputChannelId Function07{"keyboard_key_function_F07"}; //!< The F7 key
static const InputChannelId Function08; //!< The F8 key static constexpr inline InputChannelId Function08{"keyboard_key_function_F08"}; //!< The F8 key
static const InputChannelId Function09; //!< The F9 key static constexpr inline InputChannelId Function09{"keyboard_key_function_F09"}; //!< The F9 key
static const InputChannelId Function10; //!< The F10 key static constexpr inline InputChannelId Function10{"keyboard_key_function_F10"}; //!< The F10 key
static const InputChannelId Function11; //!< The F11 key static constexpr inline InputChannelId Function11{"keyboard_key_function_F11"}; //!< The F11 key
static const InputChannelId Function12; //!< The F12 key static constexpr inline InputChannelId Function12{"keyboard_key_function_F12"}; //!< The F12 key
static const InputChannelId Function13; //!< The F13 key static constexpr inline InputChannelId Function13{"keyboard_key_function_F13"}; //!< The F13 key
static const InputChannelId Function14; //!< The F14 key static constexpr inline InputChannelId Function14{"keyboard_key_function_F14"}; //!< The F14 key
static const InputChannelId Function15; //!< The F15 key static constexpr inline InputChannelId Function15{"keyboard_key_function_F15"}; //!< The F15 key
static const InputChannelId Function16; //!< The F16 key static constexpr inline InputChannelId Function16{"keyboard_key_function_F16"}; //!< The F16 key
static const InputChannelId Function17; //!< The F17 key static constexpr inline InputChannelId Function17{"keyboard_key_function_F17"}; //!< The F17 key
static const InputChannelId Function18; //!< The F18 key static constexpr inline InputChannelId Function18{"keyboard_key_function_F18"}; //!< The F18 key
static const InputChannelId Function19; //!< The F19 key static constexpr inline InputChannelId Function19{"keyboard_key_function_F19"}; //!< The F19 key
static const InputChannelId Function20; //!< The F20 key static constexpr inline InputChannelId Function20{"keyboard_key_function_F20"}; //!< The F20 key
// Modifier Keys // Modifier Keys
static const InputChannelId ModifierAltL; //!< The left alt/option key static constexpr inline InputChannelId ModifierAltL{"keyboard_key_modifier_alt_l"}; //!< The left alt/option key
static const InputChannelId ModifierAltR; //!< The right alt/option key static constexpr inline InputChannelId ModifierAltR{"keyboard_key_modifier_alt_r"}; //!< The right alt/option key
static const InputChannelId ModifierCtrlL; //!< The left control key static constexpr inline InputChannelId ModifierCtrlL{"keyboard_key_modifier_ctrl_l"}; //!< The left control key
static const InputChannelId ModifierCtrlR; //!< The right control key static constexpr inline InputChannelId ModifierCtrlR{"keyboard_key_modifier_ctrl_r"}; //!< The right control key
static const InputChannelId ModifierShiftL; //!< The left shift key static constexpr inline InputChannelId ModifierShiftL{"keyboard_key_modifier_shift_l"}; //!< The left shift key
static const InputChannelId ModifierShiftR; //!< The right shift key static constexpr inline InputChannelId ModifierShiftR{"keyboard_key_modifier_shift_r"}; //!< The right shift key
static const InputChannelId ModifierSuperL; //!< The left super (windows or apple) key static constexpr inline InputChannelId ModifierSuperL{"keyboard_key_modifier_super_l"}; //!< The left super {windows or apple} key
static const InputChannelId ModifierSuperR; //!< The right super (windows or apple) key static constexpr inline InputChannelId ModifierSuperR{"keyboard_key_modifier_super_r"}; //!< The right super {windows or apple} key
// Navigation Keys // Navigation Keys
static const InputChannelId NavigationArrowDown; //!< The down arrow key static constexpr inline InputChannelId NavigationArrowDown{"keyboard_key_navigation_arrow_down"}; //!< The down arrow key
static const InputChannelId NavigationArrowLeft; //!< The left arrow key static constexpr inline InputChannelId NavigationArrowLeft{"keyboard_key_navigation_arrow_left"}; //!< The left arrow key
static const InputChannelId NavigationArrowRight; //!< The right arrow key static constexpr inline InputChannelId NavigationArrowRight{"keyboard_key_navigation_arrow_right"}; //!< The right arrow key
static const InputChannelId NavigationArrowUp; //!< The up arrow key static constexpr inline InputChannelId NavigationArrowUp{"keyboard_key_navigation_arrow_up"}; //!< The up arrow key
static const InputChannelId NavigationDelete; //!< The delete key static constexpr inline InputChannelId NavigationDelete{"keyboard_key_navigation_delete"}; //!< The delete key
static const InputChannelId NavigationEnd; //!< The end key static constexpr inline InputChannelId NavigationEnd{"keyboard_key_navigation_end"}; //!< The end key
static const InputChannelId NavigationHome; //!< The home key static constexpr inline InputChannelId NavigationHome{"keyboard_key_navigation_home"}; //!< The home key
static const InputChannelId NavigationInsert; //!< The insert key static constexpr inline InputChannelId NavigationInsert{"keyboard_key_navigation_insert"}; //!< The insert key
static const InputChannelId NavigationPageDown; //!< The page down key static constexpr inline InputChannelId NavigationPageDown{"keyboard_key_navigation_page_down"}; //!< The page down key
static const InputChannelId NavigationPageUp; //!< The page up key static constexpr inline InputChannelId NavigationPageUp{"keyboard_key_navigation_page_up"}; //!< The page up key
// Numpad Keys // Numpad Keys
static const InputChannelId NumLock; //!< The num lock key (the clear key on apple keyboards) static constexpr inline InputChannelId NumLock{"keyboard_key_num_lock"}; //!< The num lock key {the clear key on apple keyboards}
static const InputChannelId NumPad0; //!< The numpad 0 key static constexpr inline InputChannelId NumPad0{"keyboard_key_numpad_0"}; //!< The numpad 0 key
static const InputChannelId NumPad1; //!< The numpad 1 key static constexpr inline InputChannelId NumPad1{"keyboard_key_numpad_1"}; //!< The numpad 1 key
static const InputChannelId NumPad2; //!< The numpad 2 key static constexpr inline InputChannelId NumPad2{"keyboard_key_numpad_2"}; //!< The numpad 2 key
static const InputChannelId NumPad3; //!< The numpad 3 key static constexpr inline InputChannelId NumPad3{"keyboard_key_numpad_3"}; //!< The numpad 3 key
static const InputChannelId NumPad4; //!< The numpad 4 key static constexpr inline InputChannelId NumPad4{"keyboard_key_numpad_4"}; //!< The numpad 4 key
static const InputChannelId NumPad5; //!< The numpad 5 key static constexpr inline InputChannelId NumPad5{"keyboard_key_numpad_5"}; //!< The numpad 5 key
static const InputChannelId NumPad6; //!< The numpad 6 key static constexpr inline InputChannelId NumPad6{"keyboard_key_numpad_6"}; //!< The numpad 6 key
static const InputChannelId NumPad7; //!< The numpad 7 key static constexpr inline InputChannelId NumPad7{"keyboard_key_numpad_7"}; //!< The numpad 7 key
static const InputChannelId NumPad8; //!< The numpad 8 key static constexpr inline InputChannelId NumPad8{"keyboard_key_numpad_8"}; //!< The numpad 8 key
static const InputChannelId NumPad9; //!< The numpad 9 key static constexpr inline InputChannelId NumPad9{"keyboard_key_numpad_9"}; //!< The numpad 9 key
static const InputChannelId NumPadAdd; //!< The numpad add key static constexpr inline InputChannelId NumPadAdd{"keyboard_key_numpad_add"}; //!< The numpad add key
static const InputChannelId NumPadDecimal; //!< The numpad decimal key static constexpr inline InputChannelId NumPadDecimal{"keyboard_key_numpad_decimal"}; //!< The numpad decimal key
static const InputChannelId NumPadDivide; //!< The numpad divide key static constexpr inline InputChannelId NumPadDivide{"keyboard_key_numpad_divide"}; //!< The numpad divide key
static const InputChannelId NumPadEnter; //!< The numpad enter key static constexpr inline InputChannelId NumPadEnter{"keyboard_key_numpad_enter"}; //!< The numpad enter key
static const InputChannelId NumPadMultiply; //!< The numpad multiply key static constexpr inline InputChannelId NumPadMultiply{"keyboard_key_numpad_multiply"}; //!< The numpad multiply key
static const InputChannelId NumPadSubtract; //!< The numpad subtract key static constexpr inline InputChannelId NumPadSubtract{"keyboard_key_numpad_subtract"}; //!< The numpad subtract key
// Punctuation Keys // Punctuation Keys
static const InputChannelId PunctuationApostrophe; //!< The apostrophe key static constexpr inline InputChannelId PunctuationApostrophe{"keyboard_key_punctuation_apostrophe"}; //!< The apostrophe key
static const InputChannelId PunctuationBackslash; //!< The backslash key static constexpr inline InputChannelId PunctuationBackslash{"keyboard_key_punctuation_backslash"}; //!< The backslash key
static const InputChannelId PunctuationBracketL; //!< The left bracket key static constexpr inline InputChannelId PunctuationBracketL{"keyboard_key_punctuation_bracket_l"}; //!< The left bracket key
static const InputChannelId PunctuationBracketR; //!< The right bracket key static constexpr inline InputChannelId PunctuationBracketR{"keyboard_key_punctuation_bracket_r"}; //!< The right bracket key
static const InputChannelId PunctuationComma; //!< The comma key static constexpr inline InputChannelId PunctuationComma{"keyboard_key_punctuation_comma"}; //!< The comma key
static const InputChannelId PunctuationEquals; //!< The equals key static constexpr inline InputChannelId PunctuationEquals{"keyboard_key_punctuation_equals"}; //!< The equals key
static const InputChannelId PunctuationHyphen; //!< The hyphen/underscore key static constexpr inline InputChannelId PunctuationHyphen{"keyboard_key_punctuation_hyphen"}; //!< The hyphen/underscore key
static const InputChannelId PunctuationPeriod; //!< The period key static constexpr inline InputChannelId PunctuationPeriod{"keyboard_key_punctuation_period"}; //!< The period key
static const InputChannelId PunctuationSemicolon; //!< The semicolon key static constexpr inline InputChannelId PunctuationSemicolon{"keyboard_key_punctuation_semicolon"}; //!< The semicolon key
static const InputChannelId PunctuationSlash; //!< The (forward) slash key static constexpr inline InputChannelId PunctuationSlash{"keyboard_key_punctuation_slash"}; //!< The {forward} slash key
static const InputChannelId PunctuationTilde; //!< The tilde/grave key static constexpr inline InputChannelId PunctuationTilde{"keyboard_key_punctuation_tilde"}; //!< The tilde/grave key
// Supplementary ISO 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 // Windows System Keys
static const InputChannelId WindowsSystemPause; //!< The windows pause key static constexpr inline InputChannelId WindowsSystemPause{"keyboard_key_windows_system_pause"}; //!< The windows pause key
static const InputChannelId WindowsSystemPrint; //!< The windows print key static constexpr inline InputChannelId WindowsSystemPrint{"keyboard_key_windows_system_print"}; //!< The windows print key
static const InputChannelId WindowsSystemScrollLock; //!< The windows scroll lock key static constexpr inline InputChannelId WindowsSystemScrollLock{"keyboard_key_windows_system_scroll_lock"}; //!< The windows scroll lock key
//!< All keyboard key ids //!< All keyboard key ids
static const AZStd::array<InputChannelId, 112> 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
};
}; };
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
@@ -23,44 +23,6 @@ namespace AzFramework
return (inputDeviceId.GetNameCrc32() == Id.GetNameCrc32()); 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<InputChannelId, 3> 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<InputChannelId, 2> 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<InputChannelId, 3> InputDeviceMotion::MagneticField::All =
{{
North,
Raw,
Unbiased
}};
////////////////////////////////////////////////////////////////////////////////////////////////
const InputChannelId InputDeviceMotion::Orientation::Current("motion_orientation_current");
const AZStd::array<InputChannelId, 1> InputDeviceMotion::Orientation::All =
{{
Current
}};
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
void InputDeviceMotion::Reflect(AZ::ReflectContext* context) void InputDeviceMotion::Reflect(AZ::ReflectContext* context)
{ {
@@ -44,12 +44,17 @@ namespace AzFramework
//! - InputMotionSensorRequests::SetInputChannelEnabled //! - InputMotionSensorRequests::SetInputChannelEnabled
struct Acceleration struct Acceleration
{ {
static const InputChannelId Gravity; static constexpr inline InputChannelId Gravity{"motion_acceleration_gravity"};
static const InputChannelId Raw; static constexpr inline InputChannelId Raw{"motion_acceleration_raw"};
static const InputChannelId User; static constexpr inline InputChannelId User{"motion_acceleration_user"};
//!< All acceleration input channel ids //!< All acceleration input channel ids
static const AZStd::array<InputChannelId, 3> All; static constexpr inline AZStd::array All
{
Gravity,
Raw,
User
};
}; };
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
@@ -60,11 +65,15 @@ namespace AzFramework
//! - InputMotionSensorRequests::SetInputChannelEnabled //! - InputMotionSensorRequests::SetInputChannelEnabled
struct RotationRate struct RotationRate
{ {
static const InputChannelId Raw; static constexpr inline InputChannelId Raw{"motion_rotation_rate_raw"};
static const InputChannelId Unbiased; static constexpr inline InputChannelId Unbiased{"motion_rotation_rate_unbiased"};
//!< All rotation rate input channel ids //!< All rotation rate input channel ids
static const AZStd::array<InputChannelId, 2> All; static constexpr inline AZStd::array All
{
Raw,
Unbiased
};
}; };
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
@@ -75,12 +84,17 @@ namespace AzFramework
//! - InputMotionSensorRequests::SetInputChannelEnabled //! - InputMotionSensorRequests::SetInputChannelEnabled
struct MagneticField struct MagneticField
{ {
static const InputChannelId North; static constexpr inline InputChannelId North{"motion_magnetic_field_north"};
static const InputChannelId Raw; static constexpr inline InputChannelId Raw{"motion_magnetic_field_raw"};
static const InputChannelId Unbiased; static constexpr inline InputChannelId Unbiased{"motion_magnetic_field_unbiased"};
//!< All magnetic field input channel ids //!< All magnetic field input channel ids
static const AZStd::array<InputChannelId, 3> All; static constexpr inline AZStd::array All
{
North,
Raw,
Unbiased
};
}; };
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
@@ -91,10 +105,13 @@ namespace AzFramework
//! - InputMotionSensorRequests::SetInputChannelEnabled //! - InputMotionSensorRequests::SetInputChannelEnabled
struct Orientation struct Orientation
{ {
static const InputChannelId Current; static constexpr inline InputChannelId Current{"motion_orientation_current"};
//!< All orientation input channel ids //!< All orientation input channel ids
static const AZStd::array<InputChannelId, 1> All; static constexpr inline AZStd::array All
{
Current
};
}; };
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
@@ -33,35 +33,6 @@ namespace AzFramework
return (inputDeviceId.GetNameCrc32() == Id.GetNameCrc32()); 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<InputChannelId, 5> 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<InputChannelId, 3> InputDeviceMouse::Movement::All =
{{
X,
Y,
Z
}};
////////////////////////////////////////////////////////////////////////////////////////////////
const InputChannelId InputDeviceMouse::SystemCursorPosition("mouse_system_cursor_position");
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
void InputDeviceMouse::Reflect(AZ::ReflectContext* context) void InputDeviceMouse::Reflect(AZ::ReflectContext* context)
{ {
@@ -66,14 +66,21 @@ namespace AzFramework
//! been implemented for windows simply to provide for backwards compatibility with CryInput. //! been implemented for windows simply to provide for backwards compatibility with CryInput.
struct Button struct Button
{ {
static const InputChannelId Left; //!< The left mouse button static constexpr inline InputChannelId Left{"mouse_button_left"}; //!< The left mouse button
static const InputChannelId Right; //!< The right mouse button static constexpr inline InputChannelId Right{"mouse_button_right"}; //!< The right mouse button
static const InputChannelId Middle; //!< The middle mouse button static constexpr inline InputChannelId Middle{"mouse_button_middle"}; //!< The middle mouse button
static const InputChannelId Other1; //!< DEPRECATED: the x1 mouse button static constexpr inline InputChannelId Other1{"mouse_button_other1"}; //!< DEPRECATED: the x1 mouse button
static const InputChannelId Other2; //!< DEPRECATED: the x2 mouse button static constexpr inline InputChannelId Other2{"mouse_button_other2"}; //!< DEPRECATED: the x2 mouse button
//!< All mouse button ids //!< All mouse button ids
static const AZStd::array<InputChannelId, 5> 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). //! directly correlate to the mouse position (which is queried directly from the system).
struct Movement struct Movement
{ {
static const InputChannelId X; //!< Raw horizontal mouse movement over the last frame static constexpr inline InputChannelId X{"mouse_delta_x"}; //!< Raw horizontal mouse movement over the last frame
static const InputChannelId Y; //!< Raw vertical mouse movement over the last frame static constexpr inline InputChannelId Y{"mouse_delta_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 Z{"mouse_delta_z"}; //!< Raw mouse wheel movement over the last frame
//!< All mouse movement ids //!< All mouse movement ids
static const AZStd::array<InputChannelId, 3> 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 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. //! the active window values will be in the [0.0, 1.0] range, but not when unconstrained.
//! See also InputSystemCursorRequests::SetSystemCursorState and GetSystemCursorState. //! See also InputSystemCursorRequests::SetSystemCursorState and GetSystemCursorState.
static const InputChannelId SystemCursorPosition; static constexpr inline InputChannelId SystemCursorPosition{"mouse_system_cursor_position"};
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
// Allocator // Allocator
@@ -24,31 +24,6 @@ namespace AzFramework
return (inputDeviceId.GetNameCrc32() == Id.GetNameCrc32()); 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<InputChannelId, 10> InputDeviceTouch::Touch::All =
{{
Index0,
Index1,
Index2,
Index3,
Index4,
Index5,
Index6,
Index7,
Index8,
Index9
}};
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
void InputDeviceTouch::Reflect(AZ::ReflectContext* context) void InputDeviceTouch::Reflect(AZ::ReflectContext* context)
{ {
@@ -38,19 +38,31 @@ namespace AzFramework
//! track is arbitrary, but ten seems to be more than sufficient for most game applications. //! track is arbitrary, but ten seems to be more than sufficient for most game applications.
struct Touch struct Touch
{ {
static const InputChannelId Index0; //!< Touch index 0 static constexpr inline InputChannelId Index0{"touch_index_0"}; //!< Touch index 0
static const InputChannelId Index1; //!< Touch index 1 static constexpr inline InputChannelId Index1{"touch_index_1"}; //!< Touch index 1
static const InputChannelId Index2; //!< Touch index 2 static constexpr inline InputChannelId Index2{"touch_index_2"}; //!< Touch index 2
static const InputChannelId Index3; //!< Touch index 3 static constexpr inline InputChannelId Index3{"touch_index_3"}; //!< Touch index 3
static const InputChannelId Index4; //!< Touch index 4 static constexpr inline InputChannelId Index4{"touch_index_4"}; //!< Touch index 4
static const InputChannelId Index5; //!< Touch index 5 static constexpr inline InputChannelId Index5{"touch_index_5"}; //!< Touch index 5
static const InputChannelId Index6; //!< Touch index 6 static constexpr inline InputChannelId Index6{"touch_index_6"}; //!< Touch index 6
static const InputChannelId Index7; //!< Touch index 7 static constexpr inline InputChannelId Index7{"touch_index_7"}; //!< Touch index 7
static const InputChannelId Index8; //!< Touch index 8 static constexpr inline InputChannelId Index8{"touch_index_8"}; //!< Touch index 8
static const InputChannelId Index9; //!< Touch index 9 static constexpr inline InputChannelId Index9{"touch_index_9"}; //!< Touch index 9
//!< All touch input channel ids //!< All touch input channel ids
static const AZStd::array<InputChannelId, 10> All; static constexpr inline AZStd::array All
{
Index0,
Index1,
Index2,
Index3,
Index4,
Index5,
Index6,
Index7,
Index8,
Index9
};
}; };
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
@@ -23,17 +23,6 @@ namespace AzFramework
return (inputDeviceId.GetNameCrc32() == Id.GetNameCrc32()); 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<InputChannelId, 3> InputDeviceVirtualKeyboard::Command::All =
{{
EditClear,
EditEnter,
NavigationBack
}};
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
void InputDeviceVirtualKeyboard::Reflect(AZ::ReflectContext* context) void InputDeviceVirtualKeyboard::Reflect(AZ::ReflectContext* context)
{ {
@@ -39,17 +39,22 @@ namespace AzFramework
struct Command struct Command
{ {
//!< The clear command used to indicate the user wants to clear the active text field //!< 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 //!< 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'. //!< 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. //!< 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 //!< All virtual keyboard command ids
static const AZStd::array<InputChannelId, 3> All; static constexpr inline AZStd::array All
{
EditClear,
EditEnter,
NavigationBack
};
}; };
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
+1 -1
View File
@@ -95,4 +95,4 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
endif() endif()
endif() endif()
@@ -6,29 +6,26 @@
* *
*/ */
#include <AzFramework/API/ApplicationAPI_Platform.h> #include <AzFramework/XcbApplication.h>
#include <AzFramework/Application/Application.h> #include <AzFramework/XcbEventHandler.h>
#include "Application_Linux_xcb.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace AzFramework namespace AzFramework
{ {
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
class LinuxXcbConnectionManagerImpl class XcbConnectionManagerImpl
: public LinuxXcbConnectionManagerBus::Handler : public XcbConnectionManagerBus::Handler
{ {
public: public:
LinuxXcbConnectionManagerImpl() XcbConnectionManagerImpl()
{ {
m_xcbConnection = xcb_connect(nullptr, nullptr); m_xcbConnection = xcb_connect(nullptr, nullptr);
AZ_Error("ApplicationLinux", m_xcbConnection != nullptr, "Unable to connect to X11 Server."); AZ_Error("Application", m_xcbConnection != nullptr, "Unable to connect to X11 Server.");
LinuxXcbConnectionManagerBus::Handler::BusConnect(); XcbConnectionManagerBus::Handler::BusConnect();
} }
~LinuxXcbConnectionManagerImpl() ~XcbConnectionManagerImpl() override
{ {
LinuxXcbConnectionManagerBus::Handler::BusDisconnect(); XcbConnectionManagerBus::Handler::BusDisconnect();
xcb_disconnect(m_xcbConnection); xcb_disconnect(m_xcbConnection);
} }
@@ -42,53 +39,51 @@ namespace AzFramework
}; };
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
ApplicationLinux_xcb::ApplicationLinux_xcb() XcbApplication::XcbApplication()
{ {
LinuxLifecycleEvents::Bus::Handler::BusConnect(); LinuxLifecycleEvents::Bus::Handler::BusConnect();
m_xcbConnectionManager = AZStd::make_unique<LinuxXcbConnectionManagerImpl>(); m_xcbConnectionManager = AZStd::make_unique<XcbConnectionManagerImpl>();
if (LinuxXcbConnectionManagerInterface::Get() == nullptr) 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(); m_xcbConnectionManager.reset();
LinuxLifecycleEvents::Bus::Handler::BusDisconnect(); LinuxLifecycleEvents::Bus::Handler::BusDisconnect();
} }
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
void ApplicationLinux_xcb::PumpSystemEventLoopOnce() void XcbApplication::PumpSystemEventLoopOnce()
{ {
if (xcb_connection_t* xcbConnection = m_xcbConnectionManager->GetXcbConnection()) if (xcb_connection_t* xcbConnection = m_xcbConnectionManager->GetXcbConnection())
{ {
if (xcb_generic_event_t* event = xcb_poll_for_event(xcbConnection)) 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); free(event);
} }
} }
} }
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
void ApplicationLinux_xcb::PumpSystemEventLoopUntilEmpty() void XcbApplication::PumpSystemEventLoopUntilEmpty()
{ {
if (xcb_connection_t* xcbConnection = m_xcbConnectionManager->GetXcbConnection()) if (xcb_connection_t* xcbConnection = m_xcbConnectionManager->GetXcbConnection())
{ {
while (xcb_generic_event_t* event = xcb_poll_for_event(xcbConnection)) 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); free(event);
} }
} }
} }
#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
} // namespace AzFramework } // namespace AzFramework
@@ -5,27 +5,24 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT * SPDX-License-Identifier: Apache-2.0 OR MIT
* *
*/ */
#pragma once #pragma once
#include <AzFramework/API/ApplicationAPI_Platform.h> #include <AzFramework/API/ApplicationAPI_Platform.h>
#include <AzFramework/Application/Application.h> #include <AzFramework/Application/Application.h>
#include <AzFramework/XcbConnectionManager.h>
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace AzFramework namespace AzFramework
{ {
class XcbApplication
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
////////////////////////////////////////////////////////////////////////////////////////////////
class ApplicationLinux_xcb
: public Application::Implementation : public Application::Implementation
, public LinuxLifecycleEvents::Bus::Handler , public LinuxLifecycleEvents::Bus::Handler
{ {
public: public:
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
AZ_CLASS_ALLOCATOR(ApplicationLinux_xcb, AZ::SystemAllocator, 0); AZ_CLASS_ALLOCATOR(XcbApplication, AZ::SystemAllocator, 0);
ApplicationLinux_xcb(); XcbApplication();
~ApplicationLinux_xcb() override; ~XcbApplication() override;
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
// Application::Implementation // Application::Implementation
@@ -33,9 +30,6 @@ namespace AzFramework
void PumpSystemEventLoopUntilEmpty() override; void PumpSystemEventLoopUntilEmpty() override;
private: private:
AZStd::unique_ptr<LinuxXcbConnectionManager> m_xcbConnectionManager; AZStd::unique_ptr<XcbConnectionManager> m_xcbConnectionManager;
}; };
#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
} // namespace AzFramework } // namespace AzFramework
@@ -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 <AzCore/EBus/EBus.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/RTTI/RTTI.h>
#include <xcb/xcb.h>
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<XcbConnectionManager, XcbConnectionManagerBusTraits>;
using XcbConnectionManagerInterface = AZ::Interface<XcbConnectionManager>;
} // namespace AzFramework
@@ -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 <AzCore/EBus/EBus.h>
#include <AzCore/RTTI/RTTI.h>
#include <xcb/xcb.h>
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<XcbEventHandler, XcbEventHandlerBusTraits>;
} // namespace AzFramework
@@ -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 <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
#include <AzFramework/XcbEventHandler.h>
#include <AzFramework/XcbConnectionManager.h>
#include <AzFramework/XcbInputDeviceKeyboard.h>
#define explicit ExplicitIsACXXKeyword
#include <xcb/xkb.h>
#undef explicit
#include <xkbcommon/xkbcommon-keysyms.h>
#include <xkbcommon/xkbcommon.h>
#include <xkbcommon/xkbcommon-x11.h>
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<xcb_xkb_use_extension_reply_t> 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<xcb_key_press_event_t*>(event);
const InputChannelId* key = InputChannelFromKeyEvent(keyPress->detail);
if (key)
{
QueueRawKeyEvent(*key, true);
}
break;
}
case XCB_KEY_RELEASE:
{
auto* keyRelease = reinterpret_cast<xcb_key_release_event_t*>(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
@@ -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 <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
#include <AzFramework/XcbEventHandler.h>
#include <AzFramework/XcbInterface.h>
#include <xcb/xcb.h>
#include <xkbcommon/xkbcommon.h>
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<xkb_context, xkb_context_unref> m_xkbContext;
XcbUniquePtr<xkb_keymap, xkb_keymap_unref> m_xkbKeymap;
XcbUniquePtr<xkb_state, xkb_state_unref> m_xkbState;
int m_coreDeviceId{-1};
bool m_initialized{false};
};
} // namespace AzFramework
@@ -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 <xcb/xcb.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
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<auto Callable>
struct XcbDeleterFreeFunctionWrapper
{
using value_type = decltype(Callable);
static constexpr value_type s_value = Callable;
constexpr operator value_type() const noexcept
{
return s_value;
}
};
template<typename T, auto fn>
using XcbUniquePtr = AZStd::unique_ptr<T, XcbDeleterFreeFunctionWrapper<fn>>;
template<typename T>
using XcbStdFreePtr = XcbUniquePtr<T, ::free>;
} // namespace AzFramework
@@ -6,41 +6,37 @@
* *
*/ */
#include <AzFramework/API/ApplicationAPI_Platform.h>
#include <AzFramework/Application/Application.h> #include <AzFramework/Application/Application.h>
#include <AzFramework/Windowing/NativeWindow.h> #include <AzFramework/Windowing/NativeWindow.h>
#include <xcb/xcb.h> #include <AzFramework/XcbNativeWindow.h>
#include <AzFramework/XcbConnectionManager.h>
#include "NativeWindow_Linux_xcb.h" #include <xcb/xcb.h>
namespace AzFramework namespace AzFramework
{ {
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB [[maybe_unused]] const char XcbErrorWindow[] = "XcbNativeWindow";
[[maybe_unused]] const char LinuxXcbErrorWindow[] = "NativeWindow_Linux_xcb";
static constexpr uint8_t s_XcbFormatDataSize = 32; // Format indicator for xcb for client messages 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 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 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() : NativeWindow::Implementation()
{ {
if (auto xcbConnectionManager = AzFramework::LinuxXcbConnectionManagerInterface::Get(); if (auto xcbConnectionManager = AzFramework::XcbConnectionManagerInterface::Get();
xcbConnectionManager != nullptr) xcbConnectionManager != nullptr)
{ {
m_xcbConnection = xcbConnectionManager->GetXcbConnection(); 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 WindowGeometry& geometry,
const WindowStyleMasks& styleMasks) 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_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); 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; m_xcbAtomProtocols = replyProtocol->atom;
const static char* wmDeleteWindowString = "WM_DELETE_WINDOW"; 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_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); 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; m_xcbAtomDeleteWindow = replyDeleteWindow->atom;
xcbCheckResult = xcb_change_property_checked(m_xcbConnection, 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 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 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_unmap_window(m_xcbConnection, m_xcbWindow);
xcb_flush(m_xcbConnection); xcb_flush(m_xcbConnection);
} }
LinuxXcbEventHandlerBus::Handler::BusDisconnect(); XcbEventHandlerBus::Handler::BusDisconnect();
} }
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
NativeWindowHandle NativeWindowImpl_Linux_xcb::GetWindowHandle() const NativeWindowHandle XcbNativeWindow::GetWindowHandle() const
{ {
return reinterpret_cast<NativeWindowHandle>(m_xcbWindow); return reinterpret_cast<NativeWindowHandle>(m_xcbWindow);
} }
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////
void NativeWindowImpl_Linux_xcb::SetWindowTitle(const AZStd::string& title) void XcbNativeWindow::SetWindowTitle(const AZStd::string& title)
{ {
xcb_void_cookie_t xcbCheckResult; xcb_void_cookie_t xcbCheckResult;
xcbCheckResult = xcb_change_property(m_xcbConnection, 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 }; 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] // [GFX TODO][GHI - 2678]
// Using 60 for now until proper support is added // 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; bool result = true;
if (xcb_generic_error_t* error = xcb_request_check(m_xcbConnection, cookie)) 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) 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) if (m_width != width || m_height != height)
{ {
@@ -246,7 +242,4 @@ namespace AzFramework
} }
} }
} }
#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
} // namespace AzFramework } // namespace AzFramework
@@ -5,24 +5,25 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT * SPDX-License-Identifier: Apache-2.0 OR MIT
* *
*/ */
#pragma once #pragma once
#include <AzFramework/API/ApplicationAPI_Platform.h>
#include <AzFramework/Application/Application.h> #include <AzFramework/Application/Application.h>
#include <AzFramework/Windowing/NativeWindow.h> #include <AzFramework/Windowing/NativeWindow.h>
#include <AzFramework/XcbEventHandler.h>
#include <xcb/xcb.h> #include <xcb/xcb.h>
namespace AzFramework namespace AzFramework
{ {
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB class XcbNativeWindow final
class NativeWindowImpl_Linux_xcb final
: public NativeWindow::Implementation : public NativeWindow::Implementation
, public LinuxXcbEventHandlerBus::Handler , public XcbEventHandlerBus::Handler
{ {
public: public:
AZ_CLASS_ALLOCATOR(NativeWindowImpl_Linux_xcb, AZ::SystemAllocator, 0); AZ_CLASS_ALLOCATOR(XcbNativeWindow, AZ::SystemAllocator, 0);
NativeWindowImpl_Linux_xcb(); XcbNativeWindow();
~NativeWindowImpl_Linux_xcb() override; ~XcbNativeWindow() override;
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
// NativeWindow::Implementation // NativeWindow::Implementation
@@ -37,7 +38,7 @@ namespace AzFramework
uint32_t GetDisplayRefreshRate() const override; uint32_t GetDisplayRefreshRate() const override;
//////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////
// LinuxXcbEventHandlerBus::Handler // XcbEventHandlerBus::Handler
void HandleXcbEvent(xcb_generic_event_t* event) override; void HandleXcbEvent(xcb_generic_event_t* event) override;
private: private:
@@ -49,6 +50,4 @@ namespace AzFramework
xcb_atom_t m_xcbAtomProtocols; xcb_atom_t m_xcbAtomProtocols;
xcb_atom_t m_xcbAtomDeleteWindow; xcb_atom_t m_xcbAtomDeleteWindow;
}; };
#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
} // namespace AzFramework } // namespace AzFramework
@@ -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
)
@@ -12,10 +12,6 @@
#include <AzCore/Interface/Interface.h> #include <AzCore/Interface/Interface.h>
#include <AzCore/EBus/EBus.h> #include <AzCore/EBus/EBus.h>
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
#include <xcb/xcb.h>
#endif // LY_COMPILE_DEFINITIONS
namespace AzFramework namespace AzFramework
{ {
class LinuxLifecycleEvents class LinuxLifecycleEvents
@@ -30,54 +26,4 @@ namespace AzFramework
using Bus = AZ::EBus<LinuxLifecycleEvents>; using Bus = AZ::EBus<LinuxLifecycleEvents>;
}; };
#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<LinuxXcbConnectionManager, LinuxXcbConnectionManagerBusTraits>;
using LinuxXcbConnectionManagerInterface = AZ::Interface<LinuxXcbConnectionManager>;
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<LinuxXcbEventHandler, LinuxXcbEventHandlerBusTraits>;
#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
} // namespace AzFramework } // namespace AzFramework
@@ -8,7 +8,9 @@
#include <AzFramework/Application/Application.h> #include <AzFramework/Application/Application.h>
#include "Application_Linux_xcb.h" #if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
#include <AzFramework/XcbApplication.h>
#endif
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
namespace AzFramework namespace AzFramework
@@ -17,7 +19,7 @@ namespace AzFramework
Application::Implementation* Application::Implementation::Create() Application::Implementation* Application::Implementation::Create()
{ {
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB #if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
return aznew ApplicationLinux_xcb(); return aznew XcbApplication();
#elif PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND #elif PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND
#error "Linux Window Manager Wayland not supported." #error "Linux Window Manager Wayland not supported."
return nullptr; return nullptr;
@@ -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 <AzFramework/XcbInputDeviceKeyboard.h>
#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
@@ -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 <AzCore/std/typetraits/integral_constant.h>
#include <AzFramework/API/ApplicationAPI_Linux.h>
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
#define explicit ExplicitIsACXXKeyword
#include <xcb/xkb.h>
#undef explicit
#include <xkbcommon/xkbcommon-keysyms.h>
#include <xkbcommon/xkbcommon.h>
#include <xkbcommon/xkbcommon-x11.h>
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<xcb_xkb_use_extension_reply_t, DeleterForFreeFn<::std::free>> 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<xcb_key_press_event_t*>(event);
const InputChannelId* key = InputChannelFromKeyEvent(keyPress->detail);
if (key)
{
QueueRawKeyEvent(*key, true);
}
break;
}
case XCB_KEY_RELEASE:
{
auto* keyRelease = reinterpret_cast<xcb_key_release_event_t*>(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<auto freeFn>
using DeleterForFreeFn = AZStd::integral_constant<decltype(freeFn), freeFn>;
AZStd::unique_ptr<xkb_context, DeleterForFreeFn<xkb_context_unref>> m_xkbContext;
AZStd::unique_ptr<xkb_keymap, DeleterForFreeFn<xkb_keymap_unref>> m_xkbKeymap;
AZStd::unique_ptr<xkb_state, DeleterForFreeFn<xkb_state_unref>> m_xkbState;
int m_coreDeviceId{-1};
bool m_initialized{false};
};
InputDeviceKeyboard::Implementation* InputDeviceKeyboard::Implementation::Create(InputDeviceKeyboard& inputDevice)
{
return aznew InputDeviceKeyboardXcb(inputDevice);
}
} // namespace AzFramework
@@ -6,14 +6,16 @@
* *
*/ */
#include "NativeWindow_Linux_xcb.h" #if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
#include <AzFramework/XcbNativeWindow.h>
#endif
namespace AzFramework namespace AzFramework
{ {
NativeWindow::Implementation* NativeWindow::Implementation::Create() NativeWindow::Implementation* NativeWindow::Implementation::Create()
{ {
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB #if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
return aznew NativeWindowImpl_Linux_xcb(); return aznew XcbNativeWindow();
#elif PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND #elif PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND
#error "Linux Window Manager Wayland not supported." #error "Linux Window Manager Wayland not supported."
return nullptr; return nullptr;
@@ -22,5 +24,4 @@ namespace AzFramework
return nullptr; return nullptr;
#endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB #endif // PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
} }
} // namespace AzFramework } // namespace AzFramework
@@ -10,6 +10,14 @@
# Only 'xcb' and 'wayland' are recognized # Only 'xcb' and 'wayland' are recognized
if (${PAL_TRAIT_LINUX_WINDOW_MANAGER} STREQUAL "xcb") 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 set(LY_BUILD_DEPENDENCIES
PRIVATE PRIVATE
3rdParty::X11::xcb 3rdParty::X11::xcb
@@ -18,8 +26,6 @@ if (${PAL_TRAIT_LINUX_WINDOW_MANAGER} STREQUAL "xcb")
3rdParty::X11::xkbcommon_X11 3rdParty::X11::xkbcommon_X11
) )
set(LY_COMPILE_DEFINITIONS PUBLIC PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB)
elseif(PAL_TRAIT_LINUX_WINDOW_MANAGER STREQUAL "wayland") elseif(PAL_TRAIT_LINUX_WINDOW_MANAGER STREQUAL "wayland")
set(LY_COMPILE_DEFINITIONS PUBLIC PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND) set(LY_COMPILE_DEFINITIONS PUBLIC PAL_TRAIT_LINUX_WINDOW_MANAGER_WAYLAND)
@@ -12,8 +12,6 @@ set(FILES
AzFramework/API/ApplicationAPI_Platform.h AzFramework/API/ApplicationAPI_Platform.h
AzFramework/API/ApplicationAPI_Linux.h AzFramework/API/ApplicationAPI_Linux.h
AzFramework/Application/Application_Linux.cpp AzFramework/Application/Application_Linux.cpp
AzFramework/Application/Application_Linux_xcb.h
AzFramework/Application/Application_Linux_xcb.cpp
AzFramework/Asset/AssetSystemComponentHelper_Linux.cpp AzFramework/Asset/AssetSystemComponentHelper_Linux.cpp
AzFramework/Process/ProcessWatcher_Linux.cpp AzFramework/Process/ProcessWatcher_Linux.cpp
AzFramework/Process/ProcessCommon.h AzFramework/Process/ProcessCommon.h
@@ -22,10 +20,8 @@ set(FILES
../Common/Unimplemented/AzFramework/StreamingInstall/StreamingInstall_Unimplemented.cpp ../Common/Unimplemented/AzFramework/StreamingInstall/StreamingInstall_Unimplemented.cpp
../Common/Default/AzFramework/TargetManagement/TargetManagementComponent_Default.cpp ../Common/Default/AzFramework/TargetManagement/TargetManagementComponent_Default.cpp
AzFramework/Windowing/NativeWindow_Linux.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 ../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/Motion/InputDeviceMotion_Unimplemented.cpp
../Common/Unimplemented/AzFramework/Input/Devices/Mouse/InputDeviceMouse_Unimplemented.cpp ../Common/Unimplemented/AzFramework/Input/Devices/Mouse/InputDeviceMouse_Unimplemented.cpp
../Common/Unimplemented/AzFramework/Input/Devices/Touch/InputDeviceTouch_Unimplemented.cpp ../Common/Unimplemented/AzFramework/Input/Devices/Touch/InputDeviceTouch_Unimplemented.cpp
@@ -138,7 +138,13 @@ namespace AzToolsFramework
m_indexMap[row] = index; m_indexMap[row] = index;
m_rowMap[index] = row; m_rowMap[index] = row;
++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)) if (model->hasChildren(index))
@@ -29,20 +29,20 @@ namespace AzToolsFramework
{ {
AssetBrowserTableView::AssetBrowserTableView(QWidget* parent) AssetBrowserTableView::AssetBrowserTableView(QWidget* parent)
: AzQtComponents::TableView(parent) : AzQtComponents::TableView(parent)
, m_delegate(new EntryDelegate(this)) , m_delegate(new SearchEntryDelegate(this))
{ {
setSortingEnabled(true); setSortingEnabled(false);
setItemDelegate(m_delegate); setItemDelegate(m_delegate);
setRootIsDecorated(false); setRootIsDecorated(false);
//Styling the header aligning text to the left and using a bold font. //Styling the header aligning text to the left and using a bold font.
header()->setDefaultAlignment(Qt::AlignLeft); header()->setDefaultAlignment(Qt::AlignLeft);
header()->setStyleSheet("QHeaderView { font-weight: bold; }"); header()->setStyleSheet("QHeaderView { font-weight: bold; };");
setContextMenuPolicy(Qt::CustomContextMenu); setContextMenuPolicy(Qt::CustomContextMenu);
setMouseTracking(true); setMouseTracking(true);
setSortingEnabled(false);
setSelectionMode(QAbstractItemView::SingleSelection); setSelectionMode(QAbstractItemView::SingleSelection);
connect(this, &AzQtComponents::TableView::customContextMenuRequested, this, &AssetBrowserTableView::OnContextMenu); connect(this, &AzQtComponents::TableView::customContextMenuRequested, this, &AssetBrowserTableView::OnContextMenu);
@@ -67,6 +67,8 @@ namespace AzToolsFramework
header()->setSectionResizeMode(0, QHeaderView::ResizeMode::Stretch); header()->setSectionResizeMode(0, QHeaderView::ResizeMode::Stretch);
header()->setSectionResizeMode(1, QHeaderView::ResizeMode::Stretch); header()->setSectionResizeMode(1, QHeaderView::ResizeMode::Stretch);
header()->setSortIndicatorShown(false);
header()->setSectionsClickable(false);
} }
void AssetBrowserTableView::SetName(const QString& name) void AssetBrowserTableView::SetName(const QString& name)
@@ -26,7 +26,7 @@ namespace AzToolsFramework
class AssetBrowserEntry; class AssetBrowserEntry;
class AssetBrowserTableModel; class AssetBrowserTableModel;
class AssetBrowserFilterModel; class AssetBrowserFilterModel;
class EntryDelegate; class SearchEntryDelegate;
class AssetBrowserTableView //! Table view that displays the asset browser entries in a list. class AssetBrowserTableView //! Table view that displays the asset browser entries in a list.
: public AzQtComponents::TableView : public AzQtComponents::TableView
@@ -67,9 +67,9 @@ namespace AzToolsFramework
private: private:
QString m_name; QString m_name;
QPointer<AssetBrowserTableModel> m_tableModel = nullptr; QPointer<AssetBrowserTableModel> m_tableModel;
QPointer<AssetBrowserFilterModel> m_sourceFilterModel = nullptr; QPointer<AssetBrowserFilterModel> m_sourceFilterModel;
EntryDelegate* m_delegate = nullptr; SearchEntryDelegate* m_delegate = nullptr;
private Q_SLOTS: private Q_SLOTS:
void OnContextMenu(const QPoint& point); void OnContextMenu(const QPoint& point);
@@ -11,12 +11,13 @@
#include <AzToolsFramework/AssetBrowser/AssetBrowserModel.h> #include <AzToolsFramework/AssetBrowser/AssetBrowserModel.h>
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h> #include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
#include <AzToolsFramework/AssetBrowser/Views/EntryDelegate.h> #include <AzToolsFramework/AssetBrowser/Views/EntryDelegate.h>
#include <AzCore/Utils/Utils.h>
#include <AzQtComponents/Components/StyledBusyLabel.h> #include <AzQtComponents/Components/StyledBusyLabel.h>
#include <QApplication> #include <QApplication>
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // 4251: class 'QScopedPointer<QBrushData,QBrushDataPointerDeleter>' needs to have dll-interface to be used by clients of class 'QBrush' AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // 4251: class 'QScopedPointer<QBrushData,QBrushDataPointerDeleter>' needs to have dll-interface to be used by clients of class 'QBrush'
// 4800: 'uint': forcing value to bool 'true' or 'false' (performance warning) // 4800: 'uint': forcing value to bool 'true' or 'false' (performance warning)
#include <QAbstractItemView>
#include <QPainter> #include <QPainter>
AZ_POP_DISABLE_WARNING AZ_POP_DISABLE_WARNING
@@ -24,8 +25,13 @@ namespace AzToolsFramework
{ {
namespace AssetBrowser namespace AssetBrowser
{ {
const int ENTRY_SPACING_LEFT_PIXELS = 8; static constexpr const char* TreeIconPathFirst = "Assets/Editor/Icons/AssetBrowser/TreeBranch_First.svg";
const int ENTRY_ICON_MARGIN_LEFT_PIXELS = 2; 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) EntryDelegate::EntryDelegate(QWidget* parent)
: QStyledItemDelegate(parent) : QStyledItemDelegate(parent)
@@ -62,7 +68,7 @@ namespace AzToolsFramework
// Draw main entry thumbnail. // Draw main entry thumbnail.
QRect remainingRect(option.rect); 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); 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 // 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(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<int>(AssetBrowserEntry::Column::Name) QString displayString = index.column() == aznumeric_cast<int>(AssetBrowserEntry::Column::Name)
? qvariant_cast<QString>(entry->data(aznumeric_cast<int>(AssetBrowserEntry::Column::Name))) ? qvariant_cast<QString>(entry->data(aznumeric_cast<int>(AssetBrowserEntry::Column::Name)))
@@ -148,7 +154,162 @@ namespace AzToolsFramework
return m_iconSize; 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<const AssetBrowserEntry*>())
{
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<const AssetBrowserEntry*>(data);
auto sourceEntry = azrtti_cast<const SourceAssetBrowserEntry*>(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<int>(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<int>(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<QAbstractItemView*>(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<const AssetBrowserEntry*>(indexBelow.data(AssetBrowserModel::Roles::EntryRole));
auto belowEntry = qvariant_cast<const AssetBrowserEntry*>(indexAbove.data(AssetBrowserModel::Roles::EntryRole));
auto aboveSourceEntry = azrtti_cast<const SourceAssetBrowserEntry*>(aboveEntry);
auto belowSourceEntry = azrtti_cast<const SourceAssetBrowserEntry*>(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<int>(AssetBrowserEntry::Column::Name)
? qvariant_cast<QString>(entry->data(aznumeric_cast<int>(AssetBrowserEntry::Column::Name)))
: qvariant_cast<QString>(entry->data(aznumeric_cast<int>(AssetBrowserEntry::Column::Path)));
style->drawItemText(
painter, remainingRect, option.displayAlignment, actualPalette, isEnabled, displayString,
isSelected ? QPalette::HighlightedText : QPalette::Text);
}
}
void SearchEntryDelegate::LoadBranchPixMaps()
{
AZ::IO::BasicPath<AZ::IO::FixedMaxPathString> 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<EntryBranchType>(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 } // namespace AzToolsFramework
#include "AssetBrowser/Views/moc_EntryDelegate.cpp" #include "AssetBrowser/Views/moc_EntryDelegate.cpp"
@@ -27,9 +27,19 @@ namespace AzToolsFramework
{ {
namespace AssetBrowser namespace AssetBrowser
{ {
//! Type of branch icon the delegate should paint.
enum EntryBranchType
{
First,
Middle,
Last,
OneChild,
Count
};
class AssetBrowserFilterModel; class AssetBrowserFilterModel;
//! EntryDelegate draws a single item in AssetBrowser //! EntryDelegate draws a single item in AssetBrowser.
class EntryDelegate class EntryDelegate
: public QStyledItemDelegate : public QStyledItemDelegate
{ {
@@ -52,5 +62,23 @@ namespace AzToolsFramework
//! Draw a thumbnail and return its width //! Draw a thumbnail and return its width
int DrawThumbnail(QPainter* painter, const QPoint& point, const QSize& size, Thumbnailer::SharedThumbnailKey thumbnailKey) const; 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<EntryBranchType, QPixmap> m_branchIcons;
};
} // namespace AssetBrowser } // namespace AssetBrowser
} // namespace AzToolsFramework } // namespace AzToolsFramework
@@ -33,7 +33,7 @@ namespace AzToolsFramework
virtual AZ::EntityId GetFocusRoot() = 0; virtual AZ::EntityId GetFocusRoot() = 0;
//! Returns whether the entity id provided is part of the focused sub-tree. //! 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 } // namespace AzToolsFramework
@@ -86,7 +86,7 @@ namespace AzToolsFramework
return m_focusRoot; return m_focusRoot;
} }
bool FocusModeSystemComponent::IsInFocusSubTree(AZ::EntityId entityId) bool FocusModeSystemComponent::IsInFocusSubTree(AZ::EntityId entityId) const
{ {
if (m_focusRoot == AZ::EntityId()) if (m_focusRoot == AZ::EntityId())
{ {
@@ -42,7 +42,7 @@ namespace AzToolsFramework
void SetFocusRoot(AZ::EntityId entityId) override; void SetFocusRoot(AZ::EntityId entityId) override;
void ClearFocusRoot() override; void ClearFocusRoot() override;
AZ::EntityId GetFocusRoot() override; AZ::EntityId GetFocusRoot() override;
bool IsInFocusSubTree(AZ::EntityId entityId) override; bool IsInFocusSubTree(AZ::EntityId entityId) const override;
private: private:
AZ::EntityId m_focusRoot; AZ::EntityId m_focusRoot;
@@ -39,7 +39,7 @@ namespace AzToolsFramework::Prefab
{ {
InstanceOptionalReference focusedInstance; InstanceOptionalReference focusedInstance;
if (entityId == AZ::EntityId()) if (!entityId.IsValid())
{ {
PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface = PrefabEditorEntityOwnershipInterface* prefabEditorEntityOwnershipInterface =
AZ::Interface<PrefabEditorEntityOwnershipInterface>::Get(); AZ::Interface<PrefabEditorEntityOwnershipInterface>::Get();
@@ -121,7 +121,7 @@ namespace AzToolsFramework::Prefab
return false; return false;
} }
if (entityId == AZ::EntityId()) if (!entityId.IsValid())
{ {
return false; return false;
} }
@@ -18,18 +18,19 @@ AzToolsFramework--EntityOutlinerWidget QTreeView
selection-background-color: transparent; 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::branch:hover
, AzToolsFramework--EntityOutlinerWidget QTreeView::item:hover , AzToolsFramework--EntityOutlinerWidget QTreeView::item:hover
{ , AzToolsFramework--EntityOutlinerWidget QTreeView::branch:selected
background: rgba(255, 255, 255, 30);
}
AzToolsFramework--EntityOutlinerWidget QTreeView::branch:selected
, AzToolsFramework--EntityOutlinerWidget QTreeView::item:selected , AzToolsFramework--EntityOutlinerWidget QTreeView::item:selected
, AzToolsFramework--EntityOutlinerWidget QTreeView::branch:selected:active , AzToolsFramework--EntityOutlinerWidget QTreeView::branch:selected:active
, AzToolsFramework--EntityOutlinerWidget QTreeView::item:selected:active , AzToolsFramework--EntityOutlinerWidget QTreeView::item:selected:active
{ {
background: rgba(255, 255, 255, 45); background: transparent;
} }
@@ -44,6 +44,7 @@
#include <AzToolsFramework/Entity/EditorEntityContextBus.h> #include <AzToolsFramework/Entity/EditorEntityContextBus.h>
#include <AzToolsFramework/Entity/EditorEntityHelpers.h> #include <AzToolsFramework/Entity/EditorEntityHelpers.h>
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h> #include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
#include <AzToolsFramework/FocusMode/FocusModeInterface.h>
#include <AzToolsFramework/ToolsComponents/ComponentAssetMimeDataContainer.h> #include <AzToolsFramework/ToolsComponents/ComponentAssetMimeDataContainer.h>
#include <AzToolsFramework/ToolsComponents/ComponentMimeData.h> #include <AzToolsFramework/ToolsComponents/ComponentMimeData.h>
#include <AzToolsFramework/ToolsComponents/EditorEntityIdContainer.h> #include <AzToolsFramework/ToolsComponents/EditorEntityIdContainer.h>
@@ -102,10 +103,14 @@ namespace AzToolsFramework
EntityCompositionNotificationBus::Handler::BusConnect(); EntityCompositionNotificationBus::Handler::BusConnect();
AZ::EntitySystemBus::Handler::BusConnect(); AZ::EntitySystemBus::Handler::BusConnect();
m_editorEntityFrameworkInterface = AZ::Interface<AzToolsFramework::EditorEntityUiInterface>::Get(); m_editorEntityUiInterface = AZ::Interface<AzToolsFramework::EditorEntityUiInterface>::Get();
AZ_Assert(m_editorEntityUiInterface != nullptr,
"EntityOutlinerListModel requires a EditorEntityUiInterface instance on Initialize.");
AZ_Assert(m_editorEntityFrameworkInterface != nullptr, m_focusModeInterface = AZ::Interface<FocusModeInterface>::Get();
"EntityOutlinerListModel requires a EditorEntityFrameworkInterface instance on Initialize."); AZ_Assert(
m_focusModeInterface != nullptr,
"EntityOutlinerListModel requires a FocusModeInterface instance on Initialize.");
} }
int EntityOutlinerListModel::rowCount(const QModelIndex& parent) const int EntityOutlinerListModel::rowCount(const QModelIndex& parent) const
@@ -279,7 +284,7 @@ namespace AzToolsFramework
QVariant EntityOutlinerListModel::GetEntityIcon(const AZ::EntityId& id) const QVariant EntityOutlinerListModel::GetEntityIcon(const AZ::EntityId& id) const
{ {
auto entityUiHandler = m_editorEntityFrameworkInterface->GetHandler(id); auto entityUiHandler = m_editorEntityUiInterface->GetHandler(id);
QIcon icon; QIcon icon;
// Retrieve the icon from the handler // Retrieve the icon from the handler
@@ -316,7 +321,7 @@ namespace AzToolsFramework
QVariant EntityOutlinerListModel::GetEntityTooltip(const AZ::EntityId& id) const QVariant EntityOutlinerListModel::GetEntityTooltip(const AZ::EntityId& id) const
{ {
auto entityUiHandler = m_editorEntityFrameworkInterface->GetHandler(id); auto entityUiHandler = m_editorEntityUiInterface->GetHandler(id);
QString tooltip; QString tooltip;
// Retrieve the tooltip from the handler // Retrieve the tooltip from the handler
@@ -349,7 +354,7 @@ namespace AzToolsFramework
QVariant EntityOutlinerListModel::dataForVisibility(const QModelIndex& index, int role) const QVariant EntityOutlinerListModel::dataForVisibility(const QModelIndex& index, int role) const
{ {
auto entityId = GetEntityFromIndex(index); auto entityId = GetEntityFromIndex(index);
auto entityUiHandler = m_editorEntityFrameworkInterface->GetHandler(entityId); auto entityUiHandler = m_editorEntityUiInterface->GetHandler(entityId);
if (!entityUiHandler || entityUiHandler->CanToggleLockVisibility(entityId)) if (!entityUiHandler || entityUiHandler->CanToggleLockVisibility(entityId))
{ {
@@ -377,7 +382,7 @@ namespace AzToolsFramework
QVariant EntityOutlinerListModel::dataForLock(const QModelIndex& index, int role) const QVariant EntityOutlinerListModel::dataForLock(const QModelIndex& index, int role) const
{ {
auto entityId = GetEntityFromIndex(index); auto entityId = GetEntityFromIndex(index);
auto entityUiHandler = m_editorEntityFrameworkInterface->GetHandler(entityId); auto entityUiHandler = m_editorEntityUiInterface->GetHandler(entityId);
if (!entityUiHandler || entityUiHandler->CanToggleLockVisibility(entityId)) if (!entityUiHandler || entityUiHandler->CanToggleLockVisibility(entityId))
{ {
@@ -436,7 +441,7 @@ namespace AzToolsFramework
if (value.canConvert<Qt::CheckState>()) if (value.canConvert<Qt::CheckState>())
{ {
const auto entityId = GetEntityFromIndex(index); const auto entityId = GetEntityFromIndex(index);
auto entityUiHandler = m_editorEntityFrameworkInterface->GetHandler(entityId); auto entityUiHandler = m_editorEntityUiInterface->GetHandler(entityId);
if (!entityUiHandler || entityUiHandler->CanToggleLockVisibility(entityId)) if (!entityUiHandler || entityUiHandler->CanToggleLockVisibility(entityId))
{ {
@@ -532,6 +537,11 @@ namespace AzToolsFramework
break; break;
} }
if (AZ::EntityId entityId = GetEntityFromIndex(index); !m_focusModeInterface->IsInFocusSubTree(entityId))
{
itemFlags &= !Qt::ItemIsEnabled;
}
return itemFlags; return itemFlags;
} }
@@ -36,6 +36,7 @@
namespace AzToolsFramework namespace AzToolsFramework
{ {
class EditorEntityUiInterface; class EditorEntityUiInterface;
class FocusModeInterface;
namespace EntityOutliner namespace EntityOutliner
{ {
@@ -273,7 +274,8 @@ namespace AzToolsFramework
QVariant GetEntityIcon(const AZ::EntityId& id) const; QVariant GetEntityIcon(const AZ::EntityId& id) const;
QVariant GetEntityTooltip(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 class EntityOutlinerCheckBox
@@ -40,6 +40,8 @@ namespace AzToolsFramework
"EntityOutlinerTreeView requires a EditorEntityFrameworkInterface instance on Construction."); "EntityOutlinerTreeView requires a EditorEntityFrameworkInterface instance on Construction.");
FocusModeNotificationBus::Handler::BusConnect(); FocusModeNotificationBus::Handler::BusConnect();
viewport()->setMouseTracking(true);
} }
EntityOutlinerTreeView::~EntityOutlinerTreeView() EntityOutlinerTreeView::~EntityOutlinerTreeView()
@@ -63,6 +65,11 @@ namespace AzToolsFramework
} }
} }
void EntityOutlinerTreeView::leaveEvent([[maybe_unused]] QEvent* event)
{
m_mousePosition = QPoint();
}
void EntityOutlinerTreeView::mousePressEvent(QMouseEvent* event) void EntityOutlinerTreeView::mousePressEvent(QMouseEvent* event)
{ {
//postponing normal mouse pressed logic until mouse is released or dragged //postponing normal mouse pressed logic until mouse is released or dragged
@@ -116,6 +123,8 @@ namespace AzToolsFramework
setSelectionMode(selectionModeBefore); setSelectionMode(selectionModeBefore);
} }
m_mousePosition = event->pos();
//process mouse movement as normal, potentially triggering drag and drop //process mouse movement as normal, potentially triggering drag and drop
QTreeView::mouseMoveEvent(event); QTreeView::mouseMoveEvent(event);
} }
@@ -176,12 +185,45 @@ namespace AzToolsFramework
void EntityOutlinerTreeView::drawBranches(QPainter* painter, const QRect& rect, const QModelIndex& index) const 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. // Paint the branch background as defined by the entity's handler, or its closes ancestor's.
PaintBranchBackground(painter, rect, index); PaintBranchBackground(painter, rect, index);
QTreeView::drawBranches(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 void EntityOutlinerTreeView::PaintBranchBackground(QPainter* painter, const QRect& rect, const QModelIndex& index) const
{ {
// Go through ancestors and add them to the stack // Go through ancestors and add them to the stack
@@ -61,6 +61,7 @@ namespace AzToolsFramework
void startDrag(Qt::DropActions supportedActions) override; void startDrag(Qt::DropActions supportedActions) override;
void dragMoveEvent(QDragMoveEvent* event) override; void dragMoveEvent(QDragMoveEvent* event) override;
void dropEvent(QDropEvent* event) override; void dropEvent(QDropEvent* event) override;
void leaveEvent(QEvent* event) override;
// FocusModeNotificationBus overrides ... // FocusModeNotificationBus overrides ...
void OnEditorFocusChanged(AZ::EntityId entityId) override; void OnEditorFocusChanged(AZ::EntityId entityId) override;
@@ -77,8 +78,10 @@ namespace AzToolsFramework
void StartCustomDrag(const QModelIndexList& indexList, Qt::DropActions supportedActions) override; void StartCustomDrag(const QModelIndexList& indexList, Qt::DropActions supportedActions) override;
void PaintBranchBackground(QPainter* painter, const QRect& rect, const QModelIndex& index) const; 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; QMouseEvent* m_queuedMouseEvent;
QPoint m_mousePosition;
bool m_draggingUnselectedItem; // This is set when an item is dragged outside its bounding box. bool m_draggingUnselectedItem; // This is set when an item is dragged outside its bounding box.
int m_expandOnlyDelay = -1; int m_expandOnlyDelay = -1;
@@ -13,6 +13,7 @@
#include <AzFramework/Viewport/CameraState.h> #include <AzFramework/Viewport/CameraState.h>
#include <AzFramework/Viewport/ViewportScreen.h> #include <AzFramework/Viewport/ViewportScreen.h>
#include <AzFramework/Visibility/BoundsBus.h> #include <AzFramework/Visibility/BoundsBus.h>
#include <AzToolsFramework/FocusMode/FocusModeInterface.h>
#include <AzToolsFramework/API/EditorViewportIconDisplayInterface.h> #include <AzToolsFramework/API/EditorViewportIconDisplayInterface.h>
#include <AzToolsFramework/ToolsComponents/EditorEntityIconComponentBus.h> #include <AzToolsFramework/ToolsComponents/EditorEntityIconComponentBus.h>
#include <AzToolsFramework/Viewport/ViewportMessages.h> #include <AzToolsFramework/Viewport/ViewportMessages.h>
@@ -112,6 +113,17 @@ namespace AzToolsFramework
} }
} }
EditorHelpers::EditorHelpers(const EditorVisibleEntityDataCache* entityDataCache)
: m_entityDataCache(entityDataCache)
{
m_focusModeInterface = AZ::Interface<FocusModeInterface>::Get();
AZ_Assert(
m_focusModeInterface,
"EditorHelpers - "
"Focus Mode Interface could not be found. "
"Check that it is being correctly initialized.");
}
AZ::EntityId EditorHelpers::HandleMouseInteraction( AZ::EntityId EditorHelpers::HandleMouseInteraction(
const AzFramework::CameraState& cameraState, const ViewportInteraction::MouseInteractionEvent& mouseInteraction) 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; return entityIdUnderCursor;
} }
@@ -22,6 +22,7 @@ namespace AzFramework
namespace AzToolsFramework namespace AzToolsFramework
{ {
class EditorVisibleEntityDataCache; class EditorVisibleEntityDataCache;
class FocusModeInterface;
namespace ViewportInteraction namespace ViewportInteraction
{ {
@@ -38,10 +39,7 @@ namespace AzToolsFramework
//! An EditorVisibleEntityDataCache must be passed to EditorHelpers to allow it to //! An EditorVisibleEntityDataCache must be passed to EditorHelpers to allow it to
//! efficiently read entity data without resorting to EBus calls. //! efficiently read entity data without resorting to EBus calls.
explicit EditorHelpers(const EditorVisibleEntityDataCache* entityDataCache) explicit EditorHelpers(const EditorVisibleEntityDataCache* entityDataCache);
: m_entityDataCache(entityDataCache)
{
}
EditorHelpers(const EditorHelpers&) = delete; EditorHelpers(const EditorHelpers&) = delete;
EditorHelpers& operator=(const EditorHelpers&) = delete; EditorHelpers& operator=(const EditorHelpers&) = delete;
~EditorHelpers() = default; ~EditorHelpers() = default;
@@ -62,5 +60,6 @@ namespace AzToolsFramework
private: private:
const EditorVisibleEntityDataCache* m_entityDataCache = nullptr; //!< Entity Data queried by the EditorHelpers. const EditorVisibleEntityDataCache* m_entityDataCache = nullptr; //!< Entity Data queried by the EditorHelpers.
const FocusModeInterface* m_focusModeInterface = nullptr;
}; };
} // namespace AzToolsFramework } // namespace AzToolsFramework
@@ -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 <AzTest/AzTest.h>
#include <AzCore/UserSettings/UserSettingsComponent.h>
#include <AzCore/Component/TransformBus.h>
#include <AzToolsFramework/FocusMode/FocusModeInterface.h>
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
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<AZStd::string, AZ::EntityId> m_entityMap;
};
TEST_F(EditorFocusModeTests, EditorFocusModeTests_SetFocus)
{
FocusModeInterface* focusModeInterface = AZ::Interface<FocusModeInterface>::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<FocusModeInterface>::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();
}
}
@@ -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 <AzCore/Component/EntityId.h>
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
#include <AzToolsFramework/Entity/PrefabEditorEntityOwnershipInterface.h>
#include <AzToolsFramework/Prefab/PrefabFocusInterface.h>
#include <Prefab/PrefabTestFixture.h>
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<AzToolsFramework::Prefab::Instance> carInstance =
m_prefabSystemComponent->CreatePrefab({ m_entityMap["passenger1"] }, {}, "test/car");
ASSERT_TRUE(carInstance);
m_instanceMap["car"] = carInstance.get();
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> sportsCarInstance =
m_prefabSystemComponent->CreatePrefab({ m_entityMap["passenger2"] }, {}, "test/sportsCar");
ASSERT_TRUE(sportsCarInstance);
m_instanceMap["sportsCar"] = sportsCarInstance.get();
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> 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<AZStd::string, AZ::Entity*> m_entityMap;
AZStd::unordered_map<AZStd::string, Instance*> m_instanceMap;
AZStd::unique_ptr<AzToolsFramework::Prefab::Instance> m_rootInstance;
};
TEST_F(PrefabFocusTests, PrefabFocus_FocusOnOwningPrefab)
{
GenerateTestHierarchy();
PrefabFocusInterface* prefabFocusInterface = AZ::Interface<PrefabFocusInterface>::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<AzToolsFramework::PrefabEditorEntityOwnershipInterface>::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<PrefabFocusInterface>::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();
}
}
@@ -34,6 +34,7 @@ set(FILES
EntityTestbed.h EntityTestbed.h
FileFunc.cpp FileFunc.cpp
FingerprintingTests.cpp FingerprintingTests.cpp
FocusMode/EditorFocusModeTests.cpp
GenericComponentWrapperTest.cpp GenericComponentWrapperTest.cpp
InstanceDataHierarchy.cpp InstanceDataHierarchy.cpp
IntegerPrimtitiveTestConfig.h IntegerPrimtitiveTestConfig.h
@@ -50,6 +51,7 @@ set(FILES
Prefab/Benchmark/PrefabLoadBenchmarks.cpp Prefab/Benchmark/PrefabLoadBenchmarks.cpp
Prefab/Benchmark/PrefabUpdateInstancesBenchmarks.cpp Prefab/Benchmark/PrefabUpdateInstancesBenchmarks.cpp
Prefab/Benchmark/SpawnableCreateBenchmarks.cpp Prefab/Benchmark/SpawnableCreateBenchmarks.cpp
Prefab/PrefabFocus/PrefabFocusTests.cpp
Prefab/MockPrefabFileIOActionValidator.cpp Prefab/MockPrefabFileIOActionValidator.cpp
Prefab/MockPrefabFileIOActionValidator.h Prefab/MockPrefabFileIOActionValidator.h
Prefab/PrefabDuplicateTests.cpp Prefab/PrefabDuplicateTests.cpp
@@ -122,6 +122,9 @@ class BatchAnalytics:
) )
] ]
for named_query in self._named_queries:
named_query.node.add_dependency(self._athena_work_group)
@property @property
def athena_work_group_name(self) -> athena.CfnWorkGroup.name: def athena_work_group_name(self) -> athena.CfnWorkGroup.name:
return self._athena_work_group.name return self._athena_work_group.name
@@ -85,7 +85,6 @@ namespace AZ
{ {
const auto jobLambda = [&]() -> void const auto jobLambda = [&]() -> void
{ {
AZ_PROFILE_SCOPE(AzRender, "MeshFP::Simulate() Lambda");
for (auto meshDataIter = iteratorRange.first; meshDataIter != iteratorRange.second; ++meshDataIter) for (auto meshDataIter = iteratorRange.first; meshDataIter != iteratorRange.second; ++meshDataIter)
{ {
if (!meshDataIter->m_model) if (!meshDataIter->m_model)
@@ -28,25 +28,19 @@ namespace AZ
size_t m_accumulatedInBytes = 0; 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:
* 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.
* 1) Reserved <= Budget (unless the budget is 0).
* 2) Resident <= Reserved.
*/
struct HeapMemoryUsage struct HeapMemoryUsage
{ {
HeapMemoryUsage() = default; HeapMemoryUsage() = default;
HeapMemoryUsage(const HeapMemoryUsage&); HeapMemoryUsage(const HeapMemoryUsage&);
HeapMemoryUsage& operator=(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
* 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.
* 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.
* @param sizeInBytes The amount of bytes to reserve.
* @return Whether the reservation was successful.
*/
bool TryReserveMemory(size_t sizeInBytes) bool TryReserveMemory(size_t sizeInBytes)
{ {
const size_t reservationInBytes = (m_reservedInBytes += sizeInBytes); const size_t reservationInBytes = (m_reservedInBytes += sizeInBytes);
@@ -60,45 +54,41 @@ namespace AZ
return true; return true;
} }
/** //! Helper function to validate sizes
* Helper function to validate sizes
*/
void Validate() void Validate()
{ {
if (Validation::IsEnabled()) if (Validation::IsEnabled())
{ {
AZ_Assert(m_budgetInBytes >= m_reservedInBytes, "Reserved memory is larger than memory budget"); AZ_Assert(
AZ_Assert(m_reservedInBytes >= m_residentInBytes, "Resident memory is larger than reserved memory"); 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
* 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,
* 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
* it may be unnecessary to budget certain heaps. Other platforms may require a non-zero budget for certain // heaps.
* heaps.
*/
size_t m_budgetInBytes = 0; size_t m_budgetInBytes = 0;
/** // Number of bytes reserved on the heap for allocations. This value represents the allocation capacity for
* 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.
* the platform. It is validated against the budget and may not exceed it.
*/
AZStd::atomic_size_t m_reservedInBytes{ 0 }; AZStd::atomic_size_t m_reservedInBytes{ 0 };
/** // Number of bytes physically allocated on the heap. This may not exceed the reservation. Certain platforms
* 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.
* 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 }; AZStd::atomic_size_t m_residentInBytes{ 0 };
}; };
/** //!
* Describes memory usage metrics of a resource pool. Resource pools *can* associate with a single //! 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 //! 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 //! may not require one or the other. In this case, the memory usage / budget will report empty values for
* that heap type. //! that heap type.
*/
struct PoolMemoryUsage struct PoolMemoryUsage
{ {
PoolMemoryUsage() = default; PoolMemoryUsage() = default;
+38 -43
View File
@@ -13,13 +13,12 @@ namespace AZ
{ {
namespace RHI namespace RHI
{ {
/**
* A virtual address which may be relative to a base resource. This means //! 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). //! 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 //! 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 //! 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. //! to Null, so returning the default constructor is sufficient to represent an invalid address.
*/
class VirtualAddress class VirtualAddress
{ {
static const VirtualAddress Null; static const VirtualAddress Null;
@@ -29,13 +28,13 @@ namespace AZ
static VirtualAddress CreateNull(); static VirtualAddress CreateNull();
/// Creates a valid address with a zero offset. //! Creates a valid address with a zero offset.
static VirtualAddress CreateZero(); static VirtualAddress CreateZero();
/// Creates an address from a pointer. //! Creates an address from a pointer.
static VirtualAddress CreateFromPointer(void* ptr); 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); static VirtualAddress CreateFromOffset(uint64_t offset);
inline bool IsValid() const inline bool IsValid() const
@@ -51,15 +50,13 @@ namespace AZ
uintptr_t m_ptr; uintptr_t m_ptr;
}; };
/** //! An allocator interface used for external GPU allocations. The allocator
* An allocator interface used for external GPU allocations. The allocator //! does not manage the host memory. Instead, the user specifies a base address
* 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
* (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,
* 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
* 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
* 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.
* is actually reclaimed. The intended use case is to garbage collect at the end of each frame.
*/
class Allocator class Allocator
{ {
public: public:
@@ -86,44 +83,42 @@ namespace AZ
virtual void Shutdown() = 0; virtual void Shutdown() = 0;
/** //! Allocates a virtual address relative to the base address provided at initialization time.
* Allocates a virtual address relative to the base address provided at initialization time. //! @param byteCount The number of bytes to allocate.
* @param byteCount The number of bytes to allocate. //! @param byteAlignement The alignment used to align the allocation.
* @param byteAlignement The alignment used to align the allocation.
*/
virtual VirtualAddress Allocate(size_t byteCount, size_t byteAlignment) = 0; virtual VirtualAddress Allocate(size_t byteCount, size_t byteAlignment) = 0;
/** //! Deallocates an allocation. The memory is not reclaimed until garbage collect is called.
* 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
* Depending on the garbage collection latency, it may take several garbage collection cycles //! before the memory is reclaimed.
* before the memory is reclaimed.
*/
virtual void DeAllocate(VirtualAddress offset) = 0; virtual void DeAllocate(VirtualAddress offset) = 0;
/// Allocations are deferred-released until a specific number of GC cycles have occurred. This //! Allocations are deferred-released until a specific number of GC cycles have occurred. This
/// is useful for allocations actively being consumed by the GPU. //! is useful for allocations actively being consumed by the GPU.
virtual void GarbageCollect() = 0; 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; virtual void GarbageCollectForce() = 0;
/** //! Returns the number of allocations active for this allocator. This includes
* Returns the number of allocations active for this allocator. This includes //! allocations that are pending garbage collection.
* allocations that are pending garbage collection.
*/
virtual size_t GetAllocationCount() const { return 0; } virtual size_t GetAllocationCount() const { return 0; }
/** //! Returns the number of bytes used by the allocator. This includes
* Returns the number of bytes used by the allocator. This includes //! allocations that are pending garbage collection.
* allocations that are pending garbage collection.
*/
virtual size_t GetAllocatedByteCount() const { return 0; } 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; virtual const Descriptor& GetDescriptor() const = 0;
/// Helper for converting agnostic VirtualAddress type to pointer type. Will convert //! Clone the current allocator to the new allocator passed in
/// VirtualAddress::Null to nullptr. 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 <typename T> template <typename T>
T* AllocateAs(size_t byteCount, size_t byteAlignment) T* AllocateAs(size_t byteCount, size_t byteAlignment)
{ {
@@ -139,6 +139,12 @@ namespace AZ
//! Notifies after all objects currently in the platform release queue are released //! Notifies after all objects currently in the platform release queue are released
virtual void ObjectCollectionNotify(RHI::ObjectCollectorNotifyFunction notifyFunction) = 0; 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: protected:
DeviceFeatures m_features; DeviceFeatures m_features;
DeviceLimits m_limits; DeviceLimits m_limits;
@@ -112,6 +112,9 @@ namespace AZ
//! Returns true if Pix dll is loaded //! Returns true if Pix dll is loaded
static bool IsPixModuleLoaded(); static bool IsPixModuleLoaded();
//! Returns true if Warp is enabled
static bool UsingWarpDevice();
//! Returns the name of the Factory. //! Returns the name of the Factory.
virtual Name GetName() = 0; virtual Name GetName() = 0;
@@ -55,6 +55,7 @@ namespace AZ
size_t GetAllocationCount() const override; size_t GetAllocationCount() const override;
size_t GetAllocatedByteCount() const override; size_t GetAllocatedByteCount() const override;
const Descriptor& GetDescriptor() const override; const Descriptor& GetDescriptor() const override;
void Clone(RHI::Allocator* newAllocator) override;
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
private: private:
@@ -155,11 +155,6 @@ namespace AZ
{ {
arguments += " -Zpr"; arguments += " -Zpr";
} }
if (m_dxcGenerateDebugInfo)
{
arguments += " -Zi"; // Generate debug information
arguments += " -Zss"; // Compute Shader Hash considering source information
}
// strip spaces at both sides // strip spaces at both sides
AZStd::string dxcAdditionalFreeArguments = m_dxcAdditionalFreeArguments; AZStd::string dxcAdditionalFreeArguments = m_dxcAdditionalFreeArguments;
AzFramework::StringFunc::TrimWhiteSpace(dxcAdditionalFreeArguments, true, true); AzFramework::StringFunc::TrimWhiteSpace(dxcAdditionalFreeArguments, true, true);
+10 -1
View File
@@ -8,12 +8,12 @@
#include <Atom/RHI/Factory.h> #include <Atom/RHI/Factory.h>
#include <Atom/RHI/ResourceInvalidateBus.h> #include <Atom/RHI/ResourceInvalidateBus.h>
#include <Atom/RHI/RHIUtils.h>
#include <AzCore/Interface/Interface.h> #include <AzCore/Interface/Interface.h>
#include <AzCore/Component/TickBus.h> #include <AzCore/Component/TickBus.h>
#if defined(USE_RENDERDOC) || defined(USE_PIX) #if defined(USE_RENDERDOC) || defined(USE_PIX)
#include <AzCore/Module/DynamicModuleHandle.h> #include <AzCore/Module/DynamicModuleHandle.h>
#include <Atom/RHI/RHIUtils.h>
#include <Atom_RHI_Traits_Platform.h> #include <Atom_RHI_Traits_Platform.h>
#endif #endif
@@ -28,6 +28,8 @@ static AZStd::unique_ptr<AZ::DynamicModuleHandle> s_pixModule;
static bool s_isPixGpuCaptureDllLoaded = false; static bool s_isPixGpuCaptureDllLoaded = false;
#endif #endif
static bool s_usingWarpDevice = false;
namespace AZ namespace AZ
{ {
namespace RHI namespace RHI
@@ -55,6 +57,8 @@ namespace AZ
Factory::Factory() Factory::Factory()
{ {
AZStd::string preferredUserAdapterName = RHI::GetCommandLineValue("forceAdapter");
s_usingWarpDevice = preferredUserAdapterName == "Microsoft Basic Render Driver";
#if defined(USE_RENDERDOC) #if defined(USE_RENDERDOC)
// If RenderDoc is requested, we need to load the library as early as possible (before device queries/factories are made) // 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"); bool enableRenderDoc = RHI::QueryCommandLineOption("enableRenderDoc");
@@ -197,5 +201,10 @@ namespace AZ
return false; return false;
#endif #endif
} }
bool Factory::UsingWarpDevice()
{
return s_usingWarpDevice;
}
} }
} }
@@ -314,6 +314,11 @@ namespace AZ
resourcePoolDatabase.ForEachShaderResourceGroupPool<decltype(compileAllLambda)>(compileAllLambda); resourcePoolDatabase.ForEachShaderResourceGroupPool<decltype(compileAllLambda)>(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() void FrameScheduler::BuildRayTracingShaderTables()
@@ -344,5 +344,17 @@ namespace AZ
handle = node.m_nextFree; handle = node.m_nextFree;
} }
} }
void FreeListAllocator::Clone(RHI::Allocator* newAllocator)
{
FreeListAllocator* newFreeListAllocator = static_cast<FreeListAllocator*>(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;
}
} }
} }
@@ -64,6 +64,12 @@ namespace AZ
//! int array: Max count for descriptors //! int array: Max count for descriptors
AZStd::unordered_map<AZStd::string, AZStd::array<uint32_t, NumHeapFlags>> m_descriptorHeapLimits; AZStd::unordered_map<AZStd::string, AZStd::array<uint32_t, NumHeapFlags>> 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; FrameGraphExecuterData m_frameGraphExecuterData;
void LoadPlatformLimitsDescriptor(const char* rhiName) override; void LoadPlatformLimitsDescriptor(const char* rhiName) override;
@@ -255,6 +255,11 @@ namespace AZ
// Compilation parameters // Compilation parameters
AZStd::string params = shaderCompilerArguments.MakeAdditionalDxcCommandLineString(); 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 // Enable half precision types when shader model >= 6.2
int shaderModelMajor = 0; 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 AZStd::string symbolDatabaseFileCliArgument{" "}; // when not debug: still insert a space between 5.dxil and 7.hlsl-in
if (BuildHasDebugInfo(shaderCompilerArguments)) if (BuildHasDebugInfo(shaderCompilerArguments))
{ {
// prepare .ldd filename: // prepare .pdb filename:
AZStd::string md5hex = RHI::ByteToHexString(md5); AZStd::string md5hex = RHI::ByteToHexString(md5);
AZStd::string symbolDatabaseFilePath = dxcInputFile.c_str(); // mutate from source 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 AZStd::string pdbFileName = md5hex + "-" + profileIt->second; // concatenate the shader profile to disambiguate vs/ps...
+ "-" + profileIt->second; // concatenate the shader profile to disambiguate vs/ps... AzFramework::StringFunc::Path::ReplaceFullName(symbolDatabaseFilePath, pdbFileName.c_str(), "pdb");
AzFramework::StringFunc::Path::ReplaceFullName(symbolDatabaseFilePath, lldFileName.c_str(), "lld");
// it is possible that another activated platform/profile, already exported that file. (since it's hashed on the source file) // 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 // 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())) if (AZ::IO::SystemFile::Exists(symbolDatabaseFilePath.c_str()))
@@ -19,8 +19,10 @@ namespace AZ
if (SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context)) if (SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context))
{ {
serializeContext->Class<PlatformLimitsDescriptor, Base>() serializeContext->Class<PlatformLimitsDescriptor, Base>()
->Version(0) ->Version(1)
->Field("DescriptorHeapLimits", &PlatformLimitsDescriptor::m_descriptorHeapLimits) ->Field("DescriptorHeapLimits", &PlatformLimitsDescriptor::m_descriptorHeapLimits)
->Field("NumShaderVisibleCbvSrvUavStaticHandles", &PlatformLimitsDescriptor::m_numShaderVisibleCbvSrvUavStaticHandles)
->Field("AllowDescriptorHeapCompaction", &PlatformLimitsDescriptor::m_allowDescriptorHeapCompaction)
->Field("FrameGraphExecuterData", &PlatformLimitsDescriptor::m_frameGraphExecuterData) ->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). // Map default value must be initialized after attempting to serialize (and result in failure).
// Otherwise, serialization won't overwrite the default values. // Otherwise, serialization won't overwrite the default values.
m_descriptorHeapLimits = AZStd::unordered_map<AZStd::string, AZStd::array<uint32_t, NumHeapFlags>>({ m_descriptorHeapLimits = AZStd::unordered_map<AZStd::string, AZStd::array<uint32_t, NumHeapFlags>>({
{ 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_SAMPLER"), { 2048, 2048 } },
{ AZStd::string("DESCRIPTOR_HEAP_TYPE_RTV"), { 2048, 0 } }, { AZStd::string("DESCRIPTOR_HEAP_TYPE_RTV"), { 2048, 0 } },
{ AZStd::string("DESCRIPTOR_HEAP_TYPE_DSV"), { 2048, 0 } } { AZStd::string("DESCRIPTOR_HEAP_TYPE_DSV"), { 2048, 0 } }
@@ -438,7 +438,7 @@ namespace AZ
switch (pipelineType) switch (pipelineType)
{ {
case RHI::PipelineStateType::Draw: 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); GetCommandList()->SetGraphicsRootDescriptorTable(binding.m_resourceTable.GetIndex(), compiledData.m_gpuViewsDescriptorHandle);
} }
@@ -448,14 +448,15 @@ namespace AZ
GetCommandList()->SetGraphicsRootConstantBufferView(binding.m_constantBuffer.GetIndex(), compiledData.m_gpuConstantAddress); 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); GetCommandList()->SetGraphicsRootDescriptorTable(binding.m_samplerTable.GetIndex(), compiledData.m_gpuSamplersDescriptorHandle);
} }
for (uint32_t unboundedArrayIndex = 0; unboundedArrayIndex < ShaderResourceGroupCompiledData::MaxUnboundedArrays; ++unboundedArrayIndex) 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( GetCommandList()->SetGraphicsRootDescriptorTable(
binding.m_unboundedArrayResourceTables[unboundedArrayIndex].GetIndex(), binding.m_unboundedArrayResourceTables[unboundedArrayIndex].GetIndex(),
@@ -465,7 +466,7 @@ namespace AZ
break; break;
case RHI::PipelineStateType::Dispatch: 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); GetCommandList()->SetComputeRootDescriptorTable(binding.m_resourceTable.GetIndex(), compiledData.m_gpuViewsDescriptorHandle);
} }
@@ -475,14 +476,15 @@ namespace AZ
GetCommandList()->SetComputeRootConstantBufferView(binding.m_constantBuffer.GetIndex(), compiledData.m_gpuConstantAddress); 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); GetCommandList()->SetComputeRootDescriptorTable(binding.m_samplerTable.GetIndex(), compiledData.m_gpuSamplersDescriptorHandle);
} }
for (uint32_t unboundedArrayIndex = 0; unboundedArrayIndex < ShaderResourceGroupCompiledData::MaxUnboundedArrays; ++unboundedArrayIndex) 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( GetCommandList()->SetComputeRootDescriptorTable(
binding.m_unboundedArrayResourceTables[unboundedArrayIndex].GetIndex(), binding.m_unboundedArrayResourceTables[unboundedArrayIndex].GetIndex(),
@@ -50,7 +50,7 @@ namespace AZ
void CommandListBase::SetNameInternal(const AZStd::string_view& name) void CommandListBase::SetNameInternal(const AZStd::string_view& name)
{ {
AZStd::wstring wname; AZStd::fixed_wstring<256> wname;
AZStd::to_wstring(wname, name.data()); AZStd::to_wstring(wname, name.data());
GetCommandList()->SetName(wname.data()); GetCommandList()->SetName(wname.data());
} }
@@ -39,7 +39,7 @@ namespace AZ
{ {
Device& device = static_cast<Device&>(deviceBase); Device& device = static_cast<Device&>(deviceBase);
m_currentFrameIndex = 0; m_currentFrameIndex = 0;
m_frameFences.resize(RHI::Limits::Device::FrameCountMax - 1); m_frameFences.resize(RHI::Limits::Device::FrameCountMax);
for (FenceSet& fences : m_frameFences) for (FenceSet& fences : m_frameFences)
{ {
fences.Init(device.GetDevice(), RHI::FenceState::Signaled); fences.Init(device.GetDevice(), RHI::FenceState::Signaled);
@@ -10,7 +10,9 @@
#include <RHI/Conversions.h> #include <RHI/Conversions.h>
#include <RHI/Device.h> #include <RHI/Device.h>
#include <RHI/Image.h> #include <RHI/Image.h>
#include <RHI/ShaderResourceGroupPool.h>
#include <Atom/RHI.Reflect/DX12/PlatformLimitsDescriptor.h> #include <Atom/RHI.Reflect/DX12/PlatformLimitsDescriptor.h>
#include <Atom/RHI/ShaderResourceGroupPool.h>
namespace AZ namespace AZ
{ {
@@ -40,7 +42,7 @@ namespace AZ
for (D3D12_SRV_DIMENSION dimension : validSRVDimensions) 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 = {}; D3D12_SHADER_RESOURCE_VIEW_DESC desc = {};
desc.Format = DXGI_FORMAT_R32_UINT; desc.Format = DXGI_FORMAT_R32_UINT;
@@ -62,7 +64,7 @@ namespace AZ
for (D3D12_UAV_DIMENSION dimension : UAVDimensions) 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 = {}; D3D12_UNORDERED_ACCESS_VIEW_DESC desc = {};
desc.Format = DXGI_FORMAT_R32_UINT; desc.Format = DXGI_FORMAT_R32_UINT;
@@ -75,14 +77,14 @@ namespace AZ
void DescriptorContext::CreateNullDescriptorsCBV() void DescriptorContext::CreateNullDescriptorsCBV()
{ {
D3D12_CONSTANT_BUFFER_VIEW_DESC constantBufferDesc = {}; 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_device->CreateConstantBufferView(&constantBufferDesc, GetCpuPlatformHandle(cbvDescriptorHandle));
m_nullDescriptorCBV = cbvDescriptorHandle; m_nullDescriptorCBV = cbvDescriptorHandle;
} }
void DescriptorContext::CreateNullDescriptorsSampler() 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 = {}; D3D12_SAMPLER_DESC samplerDesc = {};
samplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR; samplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP; samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
@@ -102,7 +104,7 @@ namespace AZ
AZ_Assert(platformLimitsDescriptor.get(), "Platform limits information is missing"); AZ_Assert(platformLimitsDescriptor.get(), "Platform limits information is missing");
m_platformLimitsDescriptor = platformLimitsDescriptor; m_platformLimitsDescriptor = platformLimitsDescriptor;
m_allowDescriptorHeapCompaction = m_platformLimitsDescriptor->m_allowDescriptorHeapCompaction;
for (const auto& itr : platformLimitsDescriptor->m_descriptorHeapLimits) for (const auto& itr : platformLimitsDescriptor->m_descriptorHeapLimits)
{ {
for (uint32_t shaderVisibleIdx = 0; shaderVisibleIdx < PlatformLimitsDescriptor::NumHeapFlags; ++shaderVisibleIdx) for (uint32_t shaderVisibleIdx = 0; shaderVisibleIdx < PlatformLimitsDescriptor::NumHeapFlags; ++shaderVisibleIdx)
@@ -114,11 +116,33 @@ namespace AZ
if (descriptorCountMax) if (descriptorCountMax)
{ {
GetPool(static_cast<uint32_t>(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<uint32_t>(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(); CreateNullDescriptors();
} }
@@ -129,7 +153,7 @@ namespace AZ
{ {
if (constantBufferView.IsNull()) 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); D3D12_CPU_DESCRIPTOR_HANDLE descriptorHandle = GetCpuPlatformHandle(constantBufferView);
@@ -145,7 +169,7 @@ namespace AZ
{ {
if (shaderResourceView.IsNull()) 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); D3D12_CPU_DESCRIPTOR_HANDLE descriptorHandle = GetCpuPlatformHandle(shaderResourceView);
@@ -165,7 +189,7 @@ namespace AZ
{ {
if (unorderedAccessView.IsNull()) 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); D3D12_CPU_DESCRIPTOR_HANDLE unorderedAccessDescriptor = GetCpuPlatformHandle(unorderedAccessView);
@@ -176,7 +200,24 @@ namespace AZ
// Copy the UAV descriptor into the GPU-visible version for clearing. // Copy the UAV descriptor into the GPU-visible version for clearing.
if (unorderedAccessViewClear.IsNull()) 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); CopyDescriptor(unorderedAccessViewClear, unorderedAccessView);
} }
@@ -188,7 +229,7 @@ namespace AZ
{ {
if (shaderResourceView.IsNull()) 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); D3D12_CPU_DESCRIPTOR_HANDLE descriptorHandle = GetCpuPlatformHandle(shaderResourceView);
@@ -205,7 +246,7 @@ namespace AZ
{ {
if (unorderedAccessView.IsNull()) 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); D3D12_CPU_DESCRIPTOR_HANDLE unorderedAccessDescriptor = GetCpuPlatformHandle(unorderedAccessView);
@@ -216,7 +257,24 @@ namespace AZ
// Copy the UAV descriptor into the GPU-visible version for clearing. // Copy the UAV descriptor into the GPU-visible version for clearing.
if (unorderedAccessViewClear.IsNull()) 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); CopyDescriptor(unorderedAccessViewClear, unorderedAccessView);
} }
@@ -228,7 +286,7 @@ namespace AZ
{ {
if (renderTargetView.IsNull()) 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); D3D12_CPU_DESCRIPTOR_HANDLE renderTargetDescriptor = GetCpuPlatformHandle(renderTargetView);
@@ -245,13 +303,13 @@ namespace AZ
{ {
if (depthStencilView.IsNull()) 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); D3D12_CPU_DESCRIPTOR_HANDLE depthStencilDescriptor = GetCpuPlatformHandle(depthStencilView);
if (depthStencilReadView.IsNull()) 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); D3D12_CPU_DESCRIPTOR_HANDLE depthStencilReadDescriptor = GetCpuPlatformHandle(depthStencilReadView);
@@ -274,7 +332,7 @@ namespace AZ
{ {
if (samplerHandle.IsNull()) 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; D3D12_SAMPLER_DESC samplerDesc;
@@ -286,17 +344,49 @@ namespace AZ
{ {
if (!descriptorHandle.IsNull()) if (!descriptorHandle.IsNull())
{ {
ReleaseDescriptorTable(DescriptorTable(descriptorHandle, 1)); GetPool(descriptorHandle.m_type, descriptorHandle.m_flags).ReleaseHandle(descriptorHandle);
} }
} }
DescriptorTable DescriptorContext::CreateDescriptorTable( DescriptorTable DescriptorContext::CreateDescriptorTable(
D3D12_DESCRIPTOR_HEAP_TYPE descriptorHeapType, D3D12_DESCRIPTOR_HEAP_TYPE descriptorHeapType, uint32_t descriptorCount, ShaderResourceGroup* srg)
uint32_t descriptorCount)
{ {
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( void DescriptorContext::UpdateDescriptorTableRange(
DescriptorTable gpuDestinationTable, DescriptorTable gpuDestinationTable,
const DescriptorHandle* cpuSourceDescriptors, const DescriptorHandle* cpuSourceDescriptors,
@@ -313,14 +403,12 @@ namespace AZ
} }
// Resolve destination descriptor to platform handle. // 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. // An array of descriptor sizes for each range. We just want N ranges with 1 descriptor each.
AZStd::vector<uint32_t> rangeCounts(DescriptorCount, 1); AZStd::vector<uint32_t> 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( m_device->CopyDescriptors(
1, // Number of destination ranges. 1, // Number of destination ranges.
&gpuDestinationHandle, // Destination range array. &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_TYPE type,
D3D12_DESCRIPTOR_HEAP_FLAGS flags, D3D12_DESCRIPTOR_HEAP_FLAGS flags,
uint32_t count) 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 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); 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 DescriptorHandle DescriptorContext::GetNullHandleSRV(D3D12_SRV_DIMENSION dimension) const
{ {
auto iter = m_nullDescriptorsSRV.find(dimension); 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(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); 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 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(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); 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<uint32_t>(i));
DescriptorHandle destHandle(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE, static_cast<uint32_t>(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<ShaderResourceGroupPool*>(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;
} }
} }
} }
@@ -15,6 +15,8 @@
#include <Atom/RHI.Reflect/SamplerState.h> #include <Atom/RHI.Reflect/SamplerState.h>
#include <Atom/RHI/Buffer.h> #include <Atom/RHI/Buffer.h>
#include <Atom/RHI/Image.h> #include <Atom/RHI/Image.h>
#include <AzCore/std/containers/unordered_map.h>
#include <RHI/ShaderResourceGroup.h>
namespace AZ namespace AZ
{ {
@@ -82,12 +84,14 @@ namespace AZ
//! Creates a GPU-visible descriptor table. //! Creates a GPU-visible descriptor table.
//! @param descriptorHeapType The descriptor heap to allocate from. //! @param descriptorHeapType The descriptor heap to allocate from.
//! @param descriptorCount The number of descriptors to allocate. //! @param descriptorCount The number of descriptors to allocate.
//! @param srg Shader resource group with which the descriptor table is associated with
DescriptorTable CreateDescriptorTable( DescriptorTable CreateDescriptorTable(
D3D12_DESCRIPTOR_HEAP_TYPE descriptorHeapType, D3D12_DESCRIPTOR_HEAP_TYPE descriptorHeapType, uint32_t descriptorCount, ShaderResourceGroup* srg);
uint32_t descriptorCount);
void ReleaseDescriptorTable(DescriptorTable descriptorTable);
//! 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. //! 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. //! @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_CPU_DESCRIPTOR_HANDLE GetCpuPlatformHandle(DescriptorHandle handle) const;
D3D12_GPU_DESCRIPTOR_HANDLE GetGpuPlatformHandle(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; void SetDescriptorHeaps(ID3D12GraphicsCommandList* commandList) const;
@@ -117,6 +123,12 @@ namespace AZ
ID3D12DeviceX* GetDevice(); 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: private:
void CopyDescriptor(DescriptorHandle dst, DescriptorHandle src); void CopyDescriptor(DescriptorHandle dst, DescriptorHandle src);
@@ -129,10 +141,13 @@ namespace AZ
DescriptorPool& GetPool(uint32_t type, uint32_t flag); DescriptorPool& GetPool(uint32_t type, uint32_t flag);
const DescriptorPool& GetPool(uint32_t type, uint32_t flag) const; const DescriptorPool& GetPool(uint32_t type, uint32_t flag) const;
DescriptorTable Allocate( //! Allocates a Descriptor table which describes a contiguous range of descriptor handles
D3D12_DESCRIPTOR_HEAP_TYPE type, DescriptorTable AllocateTable(D3D12_DESCRIPTOR_HEAP_TYPE type, D3D12_DESCRIPTOR_HEAP_FLAGS flags, uint32_t count);
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 NumHeapFlags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE + 1;
static const uint32_t s_descriptorCountMax[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES][NumHeapFlags]; static const uint32_t s_descriptorCountMax[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES][NumHeapFlags];
@@ -147,6 +162,25 @@ namespace AZ
DescriptorHandle m_nullSamplerDescriptor; DescriptorHandle m_nullSamplerDescriptor;
RHI::ConstPtr<PlatformLimitsDescriptor> m_platformLimitsDescriptor; RHI::ConstPtr<PlatformLimitsDescriptor> 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<ShaderResourceGroup*, uint32_t> m_srgAllocations;
AZStd::mutex m_srgMapMutex;
//Index that holds the currently active shader visible CbvSrvUav heap
uint32_t m_currentHeapIndex = 0;
}; };
} }
} }
@@ -18,34 +18,38 @@ namespace AZ
ID3D12DeviceX* device, ID3D12DeviceX* device,
D3D12_DESCRIPTOR_HEAP_TYPE type, D3D12_DESCRIPTOR_HEAP_TYPE type,
D3D12_DESCRIPTOR_HEAP_FLAGS flags, D3D12_DESCRIPTOR_HEAP_FLAGS flags,
uint32_t descriptorCount) uint32_t descriptorCountForHeap,
uint32_t descriptorCountForAllocator)
{ {
m_Desc.Type = type; m_desc.Type = type;
m_Desc.Flags = flags; m_desc.Flags = flags;
m_Desc.NumDescriptors = descriptorCount; m_desc.NumDescriptors = descriptorCountForHeap;
m_Desc.NodeMask = 1; m_desc.NodeMask = 1;
ID3D12DescriptorHeap* heap; 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"); heap->SetName(L"DescriptorHeap");
m_DescriptorHeap.Attach(heap); m_descriptorHeap.Attach(heap);
m_Stride = device->GetDescriptorHandleIncrementSize(m_Desc.Type); m_stride = device->GetDescriptorHandleIncrementSize(m_desc.Type);
m_CpuStart = heap->GetCPUDescriptorHandleForHeapStart(); m_cpuStart = heap->GetCPUDescriptorHandleForHeapStart();
m_GpuStart = {}; m_gpuStart = {};
if (RHI::CheckBitsAny(flags, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE))
{
m_GpuStart = heap->GetGPUDescriptorHandleForHeapStart();
}
const bool isGpuVisible = RHI::CheckBitsAll(flags, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE); const bool isGpuVisible = RHI::CheckBitsAll(flags, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE);
if (isGpuVisible)
{
m_gpuStart = heap->GetGPUDescriptorHandleForHeapStart();
}
if (isGpuVisible) if (isGpuVisible)
{ {
RHI::FreeListAllocator::Descriptor descriptor; RHI::FreeListAllocator::Descriptor descriptor;
descriptor.m_alignmentInBytes = 1; 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<uint32_t>(descriptorCountForAllocator);
descriptor.m_garbageCollectLatency = RHI::Limits::Device::FrameCountMax; descriptor.m_garbageCollectLatency = RHI::Limits::Device::FrameCountMax;
RHI::FreeListAllocator* allocator = aznew RHI::FreeListAllocator(); 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 // Non-shader-visible heaps don't require contiguous descriptors. Therefore, we can allocate
// them using a block allocator. // them using a block allocator.
RHI::PoolAllocator::Descriptor descriptor; RHI::PoolAllocator::Descriptor descriptor;
descriptor.m_alignmentInBytes = 1; descriptor.m_alignmentInBytes = 1;
descriptor.m_elementSize = 1; descriptor.m_elementSize = 1;
descriptor.m_capacityInBytes = descriptorCount; descriptor.m_capacityInBytes = aznumeric_cast<uint32_t>(descriptorCountForAllocator);
descriptor.m_garbageCollectLatency = 0; descriptor.m_garbageCollectLatency = 0;
RHI::PoolAllocator* allocator = aznew RHI::PoolAllocator(); 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; RHI::VirtualAddress address;
{ {
@@ -78,24 +83,34 @@ namespace AZ
if (address.IsValid()) if (address.IsValid())
{ {
DescriptorHandle handle(m_Desc.Type, m_Desc.Flags, static_cast<uint32_t>(address.m_ptr)); DescriptorHandle handle(m_desc.Type, m_desc.Flags, static_cast<uint32_t>(address.m_ptr));
return DescriptorTable(handle, static_cast<uint16_t>(count)); return handle;
} }
else else
{ {
return DescriptorTable{}; return DescriptorHandle{};
} }
} }
void DescriptorPool::Release(DescriptorTable table) void DescriptorPool::ReleaseHandle(DescriptorHandle handle)
{ {
if (table.IsNull()) if (handle.IsNull())
{ {
return; return;
} }
AZStd::lock_guard<AZStd::mutex> lock(m_mutex); AZStd::lock_guard<AZStd::mutex> 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<uint16_t>(count));
}
void DescriptorPool::ReleaseTable(DescriptorTable table)
{
ReleaseHandle(table.GetOffset());
} }
void DescriptorPool::GarbageCollect() void DescriptorPool::GarbageCollect()
@@ -106,20 +121,134 @@ namespace AZ
ID3D12DescriptorHeap* DescriptorPool::GetPlatformHeap() const ID3D12DescriptorHeap* DescriptorPool::GetPlatformHeap() const
{ {
return m_DescriptorHeap.Get(); return m_descriptorHeap.Get();
} }
D3D12_CPU_DESCRIPTOR_HANDLE DescriptorPool::GetCpuPlatformHandle(DescriptorHandle handle) const D3D12_CPU_DESCRIPTOR_HANDLE DescriptorPool::GetCpuPlatformHandle(DescriptorHandle handle) const
{ {
AZ_Assert(handle.m_index != DescriptorHandle::NullIndex, "Index is invalid"); 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 D3D12_GPU_DESCRIPTOR_HANDLE DescriptorPool::GetGpuPlatformHandle(DescriptorHandle handle) const
{ {
AZ_Assert(handle.IsShaderVisible(), "Handle is not shader visible"); AZ_Assert(handle.IsShaderVisible(), "Handle is not shader visible");
AZ_Assert(handle.m_index != DescriptorHandle::NullIndex, "Index is invalid"); 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<RHI::FreeListAllocator*>(m_allocator.get())
->Init(static_cast<RHI::FreeListAllocator*>(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<uint32_t>(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<AZStd::mutex> lock(m_mutex);
address = m_unboundedArrayAllocator->Allocate(count, 1);
}
if (address.IsValid())
{
DescriptorHandle handle(m_desc.Type, m_desc.Flags, static_cast<uint32_t>(address.m_ptr));
return DescriptorTable(handle, static_cast<uint16_t>(count));
}
else
{
return DescriptorTable{};
}
}
void DescriptorPoolShaderVisibleCbvSrvUav::ReleaseTable(DescriptorTable table)
{
if (table.IsNull())
{
return;
}
AZStd::lock_guard<AZStd::mutex> 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<RHI::FreeListAllocator*>(m_unboundedArrayAllocator.get())->Init(static_cast<RHI::FreeListAllocator*>(m_unboundedArrayAllocator.get())->GetDescriptor());
} }
} }
} }
@@ -18,37 +18,91 @@ namespace AZ
{ {
namespace DX12 namespace DX12
{ {
//! This class defines a Descriptor pool which manages all the descriptors used for binding resources
class DescriptorPool class DescriptorPool
{ {
public: public:
DescriptorPool() = default; 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, ID3D12DeviceX* device,
D3D12_DESCRIPTOR_HEAP_TYPE type, D3D12_DESCRIPTOR_HEAP_TYPE type,
D3D12_DESCRIPTOR_HEAP_FLAGS flags, D3D12_DESCRIPTOR_HEAP_FLAGS flags,
uint32_t descriptorCount); uint32_t descriptorCountForHeap,
uint32_t descriptorCountForAllocator);
ID3D12DescriptorHeap* GetPlatformHeap() const; 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_CPU_DESCRIPTOR_HANDLE GetCpuPlatformHandle(DescriptorHandle handle) const;
D3D12_GPU_DESCRIPTOR_HANDLE GetGpuPlatformHandle(DescriptorHandle handle) const; D3D12_GPU_DESCRIPTOR_HANDLE GetGpuPlatformHandle(DescriptorHandle handle) const;
private: //Clone the tracking allocator
D3D12_CPU_DESCRIPTOR_HANDLE m_CpuStart = {}; void CloneAllocator(RHI::Allocator* newAllocator);
D3D12_GPU_DESCRIPTOR_HANDLE m_GpuStart = {}; RHI::Allocator* GetAllocator() const;
D3D12_CPU_DESCRIPTOR_HANDLE m_NullDescriptor = {};
uint32_t m_Stride = 0; protected:
D3D12_DESCRIPTOR_HEAP_DESC m_Desc; D3D12_DESCRIPTOR_HEAP_DESC m_desc;
Microsoft::WRL::ComPtr<ID3D12DescriptorHeap> m_DescriptorHeap;
AZStd::mutex m_mutex; 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<ID3D12DescriptorHeap> 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<RHI::Allocator> m_allocator; AZStd::unique_ptr<RHI::Allocator> 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<RHI::Allocator> m_unboundedArrayAllocator;
//Starting index of the dynamic part of the heap
uint32_t m_startingHandleIndex = 0;
};
} }
} }
@@ -625,5 +625,20 @@ namespace AZ
{ {
return m_isAftermathInitialized; return m_isAftermathInitialized;
} }
RHI::ResultCode Device::CompactSRGMemory()
{
if (m_isDescriptorHeapCompactionNeeded)
{
m_isDescriptorHeapCompactionNeeded = false;
return m_descriptorContext->CompactDescriptorHeap();
}
return RHI::ResultCode::Success;
}
void Device::DescriptorHeapCompactionNeeded()
{
m_isDescriptorHeapCompactionNeeded = true;
}
} }
} }
+19 -23
View File
@@ -98,39 +98,27 @@ namespace AZ
D3D12_RESOURCE_STATES initialState, D3D12_RESOURCE_STATES initialState,
ImageTileLayout& imageTilingInfo); ImageTileLayout& imageTilingInfo);
/** //! Queues a DX12 COM object for release (by taking a reference) after the current frame has flushed
* Queues a DX12 COM object for release (by taking a reference) after the current frame has flushed //! through the GPU.
* through the GPU.
*/
void QueueForRelease(RHI::Ptr<ID3D12Object> dx12Object); void QueueForRelease(RHI::Ptr<ID3D12Object> dx12Object);
/** //! Queues the backing Memory instance of a MemoryView for release (by taking a reference) after the
* Queues the backing Memory instance of a MemoryView for release (by taking a reference) after the //! current frame has flushed through the GPU. The reference on the MemoryView itself is not released.
* current frame has flushed through the GPU. The reference on the MemoryView itself is not released.
*/
void QueueForRelease(const MemoryView& memoryView); void QueueForRelease(const MemoryView& memoryView);
/** //! Allocates host memory from the internal frame allocator that is suitable for staging
* Allocates host memory from the internal frame allocator that is suitable for staging //! uploads to the GPU for the current frame. The memory is valid for the lifetime of
* uploads to the GPU for the current frame. The memory is valid for the lifetime of //! the frame and is automatically reclaimed after the frame has completed on the GPU.
* the frame and is automatically reclaimed after the frame has completed on the GPU.
*/
MemoryView AcquireStagingMemory(size_t size, size_t alignment); MemoryView AcquireStagingMemory(size_t size, size_t alignment);
/** //! Acquires a pipeline layout from the internal cache.
* Acquires a pipeline layout from the internal cache.
*/
RHI::ConstPtr<PipelineLayout> AcquirePipelineLayout(const RHI::PipelineLayoutDescriptor& descriptor); RHI::ConstPtr<PipelineLayout> AcquirePipelineLayout(const RHI::PipelineLayoutDescriptor& descriptor);
/** //! Acquires a new command list for the frame given the hardware queue class. The command list is
* Acquires a new command list for the frame given the hardware queue class. The command list is //! automatically reclaimed after the current frame has flushed through the GPU.
* automatically reclaimed after the current frame has flushed through the GPU.
*/
CommandList* AcquireCommandList(RHI::HardwareQueueClass hardwareQueueClass); CommandList* AcquireCommandList(RHI::HardwareQueueClass hardwareQueueClass);
/** //! Acquires a sampler from the internal cache.
* Acquires a sampler from the internal cache.
*/
RHI::ConstPtr<Sampler> AcquireSampler(const RHI::SamplerState& state); RHI::ConstPtr<Sampler> AcquireSampler(const RHI::SamplerState& state);
const PhysicalDevice& GetPhysicalDevice() const; const PhysicalDevice& GetPhysicalDevice() const;
@@ -146,6 +134,10 @@ namespace AZ
AsyncUploadQueue& GetAsyncUploadQueue(); AsyncUploadQueue& GetAsyncUploadQueue();
bool IsAftermathInitialized() const; bool IsAftermathInitialized() const;
//! Indicate that we need to compact the shader visible srv/uav/cbv shader visible heap.
void DescriptorHeapCompactionNeeded();
private: private:
Device(); Device();
@@ -167,6 +159,7 @@ namespace AZ
RHI::ResourceMemoryRequirements GetResourceMemoryRequirements(const RHI::ImageDescriptor & descriptor) override; RHI::ResourceMemoryRequirements GetResourceMemoryRequirements(const RHI::ImageDescriptor & descriptor) override;
RHI::ResourceMemoryRequirements GetResourceMemoryRequirements(const RHI::BufferDescriptor & descriptor) override; RHI::ResourceMemoryRequirements GetResourceMemoryRequirements(const RHI::BufferDescriptor & descriptor) override;
void ObjectCollectionNotify(RHI::ObjectCollectorNotifyFunction notifyFunction) override; void ObjectCollectionNotify(RHI::ObjectCollectorNotifyFunction notifyFunction) override;
RHI::ResultCode CompactSRGMemory() override;
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
RHI::ResultCode InitSubPlatform(RHI::PhysicalDevice& physicalDevice); RHI::ResultCode InitSubPlatform(RHI::PhysicalDevice& physicalDevice);
@@ -198,6 +191,9 @@ namespace AZ
AZStd::mutex m_samplerCacheMutex; AZStd::mutex m_samplerCacheMutex;
bool m_isAftermathInitialized = false; bool m_isAftermathInitialized = false;
// Boolean used to compact the view specific shader visible heap
bool m_isDescriptorHeapCompactionNeeded = false;
}; };
} }
} }
@@ -49,9 +49,11 @@ namespace AZ
AZStd::array_view<uint8_t> bytes; AZStd::array_view<uint8_t> bytes;
bool shouldCreateLibFromSerializedData = true; bool shouldCreateLibFromSerializedData = true;
if (RHI::Factory::Get().IsRenderDocModuleLoaded() || RHI::Factory::Get().IsPixModuleLoaded()) if (RHI::Factory::Get().IsRenderDocModuleLoaded() ||
RHI::Factory::Get().IsPixModuleLoaded() ||
RHI::Factory::Get().UsingWarpDevice())
{ {
// CreatePipelineLibrary api does not function properly if Renderdoc or Pix is enabled // CreatePipelineLibrary api does not function properly if Renderdoc, Pix or Warp is enabled
shouldCreateLibFromSerializedData = false; shouldCreateLibFromSerializedData = false;
} }
@@ -215,9 +217,11 @@ namespace AZ
RHI::ResultCode PipelineLibrary::MergeIntoInternal([[maybe_unused]] AZStd::array_view<const RHI::PipelineLibrary*> pipelineLibraries) RHI::ResultCode PipelineLibrary::MergeIntoInternal([[maybe_unused]] AZStd::array_view<const RHI::PipelineLibrary*> pipelineLibraries)
{ {
if (RHI::Factory::Get().IsRenderDocModuleLoaded() || RHI::Factory::Get().IsPixModuleLoaded()) if (RHI::Factory::Get().IsRenderDocModuleLoaded() ||
RHI::Factory::Get().IsPixModuleLoaded() ||
RHI::Factory::Get().UsingWarpDevice())
{ {
// StorePipeline api does not function properly if RenderDoc or Pix is enabled // StorePipeline api does not function properly if RenderDoc, Pix or Warp is enabled
return RHI::ResultCode::Fail; return RHI::ResultCode::Fail;
} }
@@ -51,6 +51,7 @@ namespace AZ
ShaderResourceGroup() = default; ShaderResourceGroup() = default;
friend class ShaderResourceGroupPool; friend class ShaderResourceGroupPool;
friend class DescriptorContext;
/// The current index into the compiled data array. /// The current index into the compiled data array.
uint32_t m_compiledDataIndex = 0; uint32_t m_compiledDataIndex = 0;
@@ -132,33 +132,17 @@ namespace AZ
compiledData.m_cpuConstantAddress = cpuAddress + m_constantBufferSize * i; compiledData.m_cpuConstantAddress = cpuAddress + m_constantBufferSize * i;
} }
} }
if (m_viewsDescriptorTableSize)
{
group.m_viewsDescriptorTable = m_descriptorContext->CreateDescriptorTable(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_viewsDescriptorTableRingSize);
if (!group.m_viewsDescriptorTable.IsValid())
{
AZ_Error("ShaderResourceGroupPool", false, "Descriptor context failed to allocate view descriptor table. Try increasing the limits specified in platformlimits.azasset file for dx12");
return RHI::ResultCode::OutOfMemory;
}
for (uint32_t i = 0; i < copyCount; ++i)
{
const DescriptorHandle descriptorHandle = group.m_viewsDescriptorTable.GetOffset() + m_viewsDescriptorTableSize * i;
ShaderResourceGroupCompiledData& compiledData = group.m_compiledData[i];
compiledData.m_gpuViewsDescriptorHandle = m_descriptorContext->GetGpuPlatformHandle(descriptorHandle);
}
}
if (m_samplersDescriptorTableSize) if (m_samplersDescriptorTableSize)
{ {
group.m_samplersDescriptorTable = m_descriptorContext->CreateDescriptorTable(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, m_samplersDescriptorTableRingSize); group.m_samplersDescriptorTable = m_descriptorContext->CreateDescriptorTable(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, m_samplersDescriptorTableRingSize, &group);
if (!group.m_samplersDescriptorTable.IsValid()) if (!group.m_samplersDescriptorTable.IsValid())
{ {
AZ_Error("ShaderResourceGroupPool", false, "Descriptor context failed to allocate sampler descriptor table. Try increasing the limits specified in platformlimits.azasset file for dx12."); AZ_Error(
"ShaderResourceGroupPool", false,
"Descriptor context failed to allocate sampler descriptor table. Please consider increasing number of handles "
"allowed for the second value of DESCRIPTOR_HEAP_TYPE_SAMPLER within platformlimits.azasset file for dx12.");
return RHI::ResultCode::OutOfMemory; return RHI::ResultCode::OutOfMemory;
} }
@@ -167,7 +151,7 @@ namespace AZ
const DescriptorHandle descriptorHandle = group.m_samplersDescriptorTable.GetOffset() + m_samplersDescriptorTableSize * i; const DescriptorHandle descriptorHandle = group.m_samplersDescriptorTable.GetOffset() + m_samplersDescriptorTableSize * i;
ShaderResourceGroupCompiledData& compiledData = group.m_compiledData[i]; ShaderResourceGroupCompiledData& compiledData = group.m_compiledData[i];
compiledData.m_gpuSamplersDescriptorHandle = m_descriptorContext->GetGpuPlatformHandle(descriptorHandle); compiledData.m_gpuSamplersDescriptorHandle = m_descriptorContext->GetGpuPlatformHandleForTable(DescriptorTable(descriptorHandle, static_cast<uint16_t>(m_samplersDescriptorTableSize)));
} }
} }
@@ -186,19 +170,25 @@ namespace AZ
if (m_viewsDescriptorTableSize) if (m_viewsDescriptorTableSize)
{ {
m_descriptorContext->ReleaseDescriptorTable(group.m_viewsDescriptorTable); if (group.m_viewsDescriptorTable.IsValid())
{
m_descriptorContext->ReleaseDescriptorTable(group.m_viewsDescriptorTable, &group);
}
} }
if (m_samplersDescriptorTableSize) if (m_samplersDescriptorTableSize)
{ {
m_descriptorContext->ReleaseDescriptorTable(group.m_samplersDescriptorTable); if (group.m_viewsDescriptorTable.IsValid())
{
m_descriptorContext->ReleaseDescriptorTable(group.m_samplersDescriptorTable, &group);
}
} }
for (uint32_t unboundedArrayindex = 0; unboundedArrayindex < (ShaderResourceGroupCompiledData::MaxUnboundedArrays * RHI::Limits::Device::FrameCountMax); ++unboundedArrayindex) for (uint32_t unboundedArrayindex = 0; unboundedArrayindex < (ShaderResourceGroupCompiledData::MaxUnboundedArrays * RHI::Limits::Device::FrameCountMax); ++unboundedArrayindex)
{ {
if (group.m_unboundedDescriptorTables[unboundedArrayindex].IsValid()) if (group.m_unboundedDescriptorTables[unboundedArrayindex].IsValid())
{ {
m_descriptorContext->ReleaseDescriptorTable(group.m_unboundedDescriptorTables[unboundedArrayindex]); m_descriptorContext->ReleaseDescriptorTable(group.m_unboundedDescriptorTables[unboundedArrayindex], &group);
} }
} }
@@ -213,6 +203,7 @@ namespace AZ
const RHI::ShaderResourceGroupData& groupData) const RHI::ShaderResourceGroupData& groupData)
{ {
ShaderResourceGroup& group = static_cast<ShaderResourceGroup&>(groupBase); ShaderResourceGroup& group = static_cast<ShaderResourceGroup&>(groupBase);
auto& device = static_cast<Device&>(GetDevice());
group.m_compiledDataIndex = (group.m_compiledDataIndex + 1) % RHI::Limits::Device::FrameCountMax; group.m_compiledDataIndex = (group.m_compiledDataIndex + 1) % RHI::Limits::Device::FrameCountMax;
if (m_constantBufferSize) if (m_constantBufferSize)
@@ -222,6 +213,22 @@ namespace AZ
if (m_viewsDescriptorTableSize) if (m_viewsDescriptorTableSize)
{ {
//Lazy initialization for cbv/srv/uav Descriptor Tables
if (!group.m_viewsDescriptorTable.IsValid())
{
group.m_viewsDescriptorTable = m_descriptorContext->CreateDescriptorTable(
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_viewsDescriptorTableRingSize, &group);
if (!group.m_viewsDescriptorTable.IsValid())
{
//We have support for compacting D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV (if applicable) so try that.
device.DescriptorHeapCompactionNeeded();
return RHI::ResultCode::Success;
}
CacheGpuHandlesForViews(group);
}
const DescriptorTable descriptorTable( const DescriptorTable descriptorTable(
group.m_viewsDescriptorTable.GetOffset() + group.m_compiledDataIndex * m_viewsDescriptorTableSize, group.m_viewsDescriptorTable.GetOffset() + group.m_compiledDataIndex * m_viewsDescriptorTableSize,
static_cast<uint16_t>(m_viewsDescriptorTableSize)); static_cast<uint16_t>(m_viewsDescriptorTableSize));
@@ -246,6 +253,18 @@ namespace AZ
return RHI::ResultCode::Success; return RHI::ResultCode::Success;
} }
void ShaderResourceGroupPool::CacheGpuHandlesForViews(ShaderResourceGroup& group)
{
for (uint32_t i = 0; i < RHI::Limits::Device::FrameCountMax; ++i)
{
const DescriptorHandle descriptorHandle = group.m_viewsDescriptorTable.GetOffset() + m_viewsDescriptorTableSize * i;
ShaderResourceGroupCompiledData& compiledData = group.m_compiledData[i];
compiledData.m_gpuViewsDescriptorHandle = m_descriptorContext->GetGpuPlatformHandleForTable(
DescriptorTable(descriptorHandle, static_cast<uint16_t>(m_viewsDescriptorTableSize)));
}
}
void ShaderResourceGroupPool::UpdateViewsDescriptorTable(DescriptorTable descriptorTable, const RHI::ShaderResourceGroupData& groupData) void ShaderResourceGroupPool::UpdateViewsDescriptorTable(DescriptorTable descriptorTable, const RHI::ShaderResourceGroupData& groupData)
{ {
const RHI::ShaderResourceGroupLayout& groupLayout = *groupData.GetLayout(); const RHI::ShaderResourceGroupLayout& groupLayout = *groupData.GetLayout();
@@ -261,27 +280,27 @@ namespace AZ
AZStd::vector<DescriptorHandle> descriptorHandles; AZStd::vector<DescriptorHandle> descriptorHandles;
switch (descriptorRangeType) switch (descriptorRangeType)
{ {
case D3D12_DESCRIPTOR_RANGE_TYPE_SRV: case D3D12_DESCRIPTOR_RANGE_TYPE_SRV:
{ {
descriptorHandles = GetSRVsFromImageViews< RHI::BufferView, BufferView> (bufferViews, D3D12_SRV_DIMENSION_BUFFER); descriptorHandles = GetSRVsFromImageViews< RHI::BufferView, BufferView> (bufferViews, D3D12_SRV_DIMENSION_BUFFER);
break; break;
}
case D3D12_DESCRIPTOR_RANGE_TYPE_UAV:
{
descriptorHandles = GetUAVsFromImageViews<RHI::BufferView, BufferView>(bufferViews, D3D12_UAV_DIMENSION_BUFFER);
break;
}
case D3D12_DESCRIPTOR_RANGE_TYPE_CBV:
{
descriptorHandles = GetCBVsFromBufferViews(bufferViews);
break;
}
default:
AZ_Assert(false, "Unhandled D3D12_DESCRIPTOR_RANGE_TYPE enumeration");
break;
} }
case D3D12_DESCRIPTOR_RANGE_TYPE_UAV:
{
descriptorHandles = GetUAVsFromImageViews<RHI::BufferView, BufferView>(bufferViews, D3D12_UAV_DIMENSION_BUFFER);
break;
}
case D3D12_DESCRIPTOR_RANGE_TYPE_CBV:
{
descriptorHandles = GetCBVsFromBufferViews(bufferViews);
break;
}
default:
AZ_Assert(false, "Unhandled D3D12_DESCRIPTOR_RANGE_TYPE enumeration");
break;
}
UpdateDescriptorTableRange(descriptorTable, descriptorHandles, bufferInputIndex);
UpdateDescriptorTableRange(descriptorTable, descriptorHandles, bufferInputIndex);
++shaderInputIndex; ++shaderInputIndex;
} }
@@ -297,23 +316,24 @@ namespace AZ
AZStd::vector<DescriptorHandle> descriptorHandles; AZStd::vector<DescriptorHandle> descriptorHandles;
switch (descriptorRangeType) switch (descriptorRangeType)
{ {
case D3D12_DESCRIPTOR_RANGE_TYPE_SRV: case D3D12_DESCRIPTOR_RANGE_TYPE_SRV:
{ {
descriptorHandles = GetSRVsFromImageViews<RHI::ImageView, ImageView>(imageViews, ConvertSRVDimension(shaderInputImage.m_type)); descriptorHandles =
break; GetSRVsFromImageViews<RHI::ImageView, ImageView>(imageViews, ConvertSRVDimension(shaderInputImage.m_type));
} break;
case D3D12_DESCRIPTOR_RANGE_TYPE_UAV: }
{ case D3D12_DESCRIPTOR_RANGE_TYPE_UAV:
descriptorHandles = GetUAVsFromImageViews<RHI::ImageView, ImageView>(imageViews, ConvertUAVDimension(shaderInputImage.m_type)); {
break; descriptorHandles =
} GetUAVsFromImageViews<RHI::ImageView, ImageView>(imageViews, ConvertUAVDimension(shaderInputImage.m_type));
default: break;
}
default:
AZ_Assert(false, "Unhandled D3D12_DESCRIPTOR_RANGE_TYPE enumeration"); AZ_Assert(false, "Unhandled D3D12_DESCRIPTOR_RANGE_TYPE enumeration");
break; break;
} }
UpdateDescriptorTableRange(descriptorTable, descriptorHandles, imageInputIndex); UpdateDescriptorTableRange(descriptorTable, descriptorHandles, imageInputIndex);
++shaderInputIndex; ++shaderInputIndex;
} }
} }
@@ -334,7 +354,7 @@ namespace AZ
void ShaderResourceGroupPool::UpdateUnboundedArrayDescriptorTables(ShaderResourceGroup& group, const RHI::ShaderResourceGroupData& groupData) void ShaderResourceGroupPool::UpdateUnboundedArrayDescriptorTables(ShaderResourceGroup& group, const RHI::ShaderResourceGroupData& groupData)
{ {
const RHI::ShaderResourceGroupLayout& groupLayout = *groupData.GetLayout(); const RHI::ShaderResourceGroupLayout& groupLayout = *groupData.GetLayout();
auto& device = static_cast<Device&>(GetDevice());
uint32_t shaderInputIndex = 0; uint32_t shaderInputIndex = 0;
// process buffer unbounded arrays // process buffer unbounded arrays
@@ -350,50 +370,30 @@ namespace AZ
{ {
if (group.m_unboundedDescriptorTables[tableIndex].IsValid()) if (group.m_unboundedDescriptorTables[tableIndex].IsValid())
{ {
m_descriptorContext->ReleaseDescriptorTable(group.m_unboundedDescriptorTables[tableIndex]); m_descriptorContext->ReleaseDescriptorTable(group.m_unboundedDescriptorTables[tableIndex], &group);
group.m_unboundedDescriptorTables[tableIndex] = DescriptorTable{}; group.m_unboundedDescriptorTables[tableIndex] = DescriptorTable{};
} }
if (!bufferViews.empty()) if (!bufferViews.empty())
{ {
group.m_unboundedDescriptorTables[tableIndex] = m_descriptorContext->CreateDescriptorTable(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, static_cast<uint32_t>(bufferViews.size())); group.m_unboundedDescriptorTables[tableIndex] = m_descriptorContext->CreateDescriptorTable(
AZ_Assert(group.m_unboundedDescriptorTables[tableIndex].IsValid(), "Descriptor context failed to allocate unbounded array descriptor table, most likely out of memory."); D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, static_cast<uint32_t>(bufferViews.size()), &group);
if (!group.m_unboundedDescriptorTables[tableIndex].IsValid())
{
// We have support for compacting D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV (if applicable) so try that.
device.DescriptorHeapCompactionNeeded();
return;
}
ShaderResourceGroupCompiledData& compiledData = group.m_compiledData[group.m_compiledDataIndex]; ShaderResourceGroupCompiledData& compiledData = group.m_compiledData[group.m_compiledDataIndex];
compiledData.m_gpuUnboundedArraysDescriptorHandles[shaderInputIndex] = m_descriptorContext->GetGpuPlatformHandle(group.m_unboundedDescriptorTables[tableIndex].GetOffset()); compiledData.m_gpuUnboundedArraysDescriptorHandles[shaderInputIndex] = m_descriptorContext->GetGpuPlatformHandleForTable(group.m_unboundedDescriptorTables[tableIndex]);
} }
} }
++shaderInputIndex;
if (bufferViews.empty())
{
// we don't need to update descriptors since the buffer list is empty
continue;
}
D3D12_DESCRIPTOR_RANGE_TYPE descriptorRangeType = ConvertShaderInputBufferAccess(shaderInputBufferUnboundedArray.m_access);
AZStd::vector<DescriptorHandle> descriptorHandles;
switch (descriptorRangeType)
{
case D3D12_DESCRIPTOR_RANGE_TYPE_SRV:
{
descriptorHandles = GetSRVsFromImageViews<RHI::BufferView, BufferView>(bufferViews, D3D12_SRV_DIMENSION_BUFFER);
break;
}
case D3D12_DESCRIPTOR_RANGE_TYPE_UAV:
{
descriptorHandles = GetUAVsFromImageViews<RHI::BufferView, BufferView>(bufferViews, D3D12_UAV_DIMENSION_BUFFER);
break;
}
default:
AZ_Assert(false, "Unhandled D3D12_DESCRIPTOR_RANGE_TYPE enumeration");
break;
}
const DescriptorTable descriptorTable(group.m_unboundedDescriptorTables[tableIndex].GetOffset(), static_cast<uint16_t>(bufferViews.size())); const DescriptorTable descriptorTable(group.m_unboundedDescriptorTables[tableIndex].GetOffset(), static_cast<uint16_t>(bufferViews.size()));
m_descriptorContext->UpdateDescriptorTableRange(descriptorTable, descriptorHandles.data(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); UpdateUnboundedBuffersDescTable(descriptorTable, groupData, shaderInputIndex, shaderInputBufferUnboundedArray.m_access);
++shaderInputIndex;
} }
// process image unbounded arrays // process image unbounded arrays
@@ -407,55 +407,223 @@ namespace AZ
// resize the descriptor table allocation if necessary // resize the descriptor table allocation if necessary
if (group.m_unboundedDescriptorTables[tableIndex].GetSize() != imageViews.size()) if (group.m_unboundedDescriptorTables[tableIndex].GetSize() != imageViews.size())
{ {
if (group.m_unboundedDescriptorTables[tableIndex].IsValid()) if (group.m_unboundedDescriptorTables[tableIndex].IsValid())
{ {
m_descriptorContext->ReleaseDescriptorTable(group.m_unboundedDescriptorTables[tableIndex]); m_descriptorContext->ReleaseDescriptorTable(group.m_unboundedDescriptorTables[tableIndex], &group);
group.m_unboundedDescriptorTables[tableIndex] = DescriptorTable{}; group.m_unboundedDescriptorTables[tableIndex] = DescriptorTable{};
} }
if (!imageViews.empty()) if (!imageViews.empty())
{ {
group.m_unboundedDescriptorTables[tableIndex] = m_descriptorContext->CreateDescriptorTable(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, static_cast<uint32_t>(imageViews.size())); group.m_unboundedDescriptorTables[tableIndex] = m_descriptorContext->CreateDescriptorTable(
AZ_Assert(group.m_unboundedDescriptorTables[tableIndex].IsValid(), "Descriptor context failed to allocate unbounded array descriptor table, most likely out of memory."); D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, static_cast<uint32_t>(imageViews.size()), &group);
if (!group.m_unboundedDescriptorTables[tableIndex].IsValid())
{
// We have support for compacting D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV (if applicable) so try that
device.DescriptorHeapCompactionNeeded();
return;
}
ShaderResourceGroupCompiledData& compiledData = group.m_compiledData[group.m_compiledDataIndex]; ShaderResourceGroupCompiledData& compiledData = group.m_compiledData[group.m_compiledDataIndex];
compiledData.m_gpuUnboundedArraysDescriptorHandles[shaderInputIndex] = m_descriptorContext->GetGpuPlatformHandle(group.m_unboundedDescriptorTables[tableIndex].GetOffset()); compiledData.m_gpuUnboundedArraysDescriptorHandles[shaderInputIndex] = m_descriptorContext->GetGpuPlatformHandleForTable(group.m_unboundedDescriptorTables[tableIndex]);
} }
} }
++shaderInputIndex;
if (imageViews.empty())
{
// we don't need to update descriptors since the image list is empty
continue;
}
D3D12_DESCRIPTOR_RANGE_TYPE descriptorRangeType = ConvertShaderInputImageAccess(shaderInputImageUnboundedArray.m_access);
AZStd::vector<DescriptorHandle> descriptorHandles;
switch (descriptorRangeType)
{
case D3D12_DESCRIPTOR_RANGE_TYPE_SRV:
{
descriptorHandles = GetSRVsFromImageViews<RHI::ImageView, ImageView>(imageViews, ConvertSRVDimension(shaderInputImageUnboundedArray.m_type));
break;
}
case D3D12_DESCRIPTOR_RANGE_TYPE_UAV:
{
descriptorHandles = GetUAVsFromImageViews<RHI::ImageView, ImageView>(imageViews, ConvertUAVDimension(shaderInputImageUnboundedArray.m_type));
break;
}
default:
AZ_Assert(false, "Unhandled D3D12_DESCRIPTOR_RANGE_TYPE enumeration");
break;
}
const DescriptorTable descriptorTable(group.m_unboundedDescriptorTables[tableIndex].GetOffset(), static_cast<uint16_t>(imageViews.size())); const DescriptorTable descriptorTable(group.m_unboundedDescriptorTables[tableIndex].GetOffset(), static_cast<uint16_t>(imageViews.size()));
m_descriptorContext->UpdateDescriptorTableRange(descriptorTable, descriptorHandles.data(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); UpdateUnboundedImagesDescTable(descriptorTable, groupData, shaderInputIndex, shaderInputImageUnboundedArray.m_access, shaderInputImageUnboundedArray.m_type);
++shaderInputIndex;
} }
} }
void ShaderResourceGroupPool::UpdateUnboundedBuffersDescTable(
DescriptorTable descriptorTable,
const RHI::ShaderResourceGroupData& groupData,
uint32_t shaderInputIndex,
RHI::ShaderInputBufferAccess bufferAccess)
{
const RHI::ShaderInputBufferUnboundedArrayIndex bufferUnboundedArrayInputIndex(shaderInputIndex);
AZStd::array_view<RHI::ConstPtr<RHI::BufferView>> bufferViews =
groupData.GetBufferViewUnboundedArray(bufferUnboundedArrayInputIndex);
if (bufferViews.empty())
{
// we don't need to update descriptors since the buffer list is empty
return;
}
D3D12_DESCRIPTOR_RANGE_TYPE descriptorRangeType = ConvertShaderInputBufferAccess(bufferAccess);
AZStd::vector<DescriptorHandle> descriptorHandles;
switch (descriptorRangeType)
{
case D3D12_DESCRIPTOR_RANGE_TYPE_SRV:
{
descriptorHandles = GetSRVsFromImageViews<RHI::BufferView, BufferView>(bufferViews, D3D12_SRV_DIMENSION_BUFFER);
break;
}
case D3D12_DESCRIPTOR_RANGE_TYPE_UAV:
{
descriptorHandles = GetUAVsFromImageViews<RHI::BufferView, BufferView>(bufferViews, D3D12_UAV_DIMENSION_BUFFER);
break;
}
default:
AZ_Assert(false, "Unhandled D3D12_DESCRIPTOR_RANGE_TYPE enumeration");
break;
}
m_descriptorContext->UpdateDescriptorTableRange(
descriptorTable, descriptorHandles.data(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
}
void ShaderResourceGroupPool::UpdateUnboundedImagesDescTable(
DescriptorTable descriptorTable,
const RHI::ShaderResourceGroupData& groupData,
uint32_t shaderInputIndex,
RHI::ShaderInputImageAccess imageAccess,
RHI::ShaderInputImageType imageType)
{
const RHI::ShaderInputImageUnboundedArrayIndex imageUnboundedArrayInputIndex(shaderInputIndex);
AZStd::array_view<RHI::ConstPtr<RHI::ImageView>> imageViews =
groupData.GetImageViewUnboundedArray(imageUnboundedArrayInputIndex);
if (imageViews.empty())
{
// we don't need to update descriptors since the image list is empty
return;
}
D3D12_DESCRIPTOR_RANGE_TYPE descriptorRangeType = ConvertShaderInputImageAccess(imageAccess);
AZStd::vector<DescriptorHandle> descriptorHandles;
switch (descriptorRangeType)
{
case D3D12_DESCRIPTOR_RANGE_TYPE_SRV:
{
descriptorHandles = GetSRVsFromImageViews<RHI::ImageView, ImageView>(imageViews, ConvertSRVDimension(imageType));
break;
}
case D3D12_DESCRIPTOR_RANGE_TYPE_UAV:
{
descriptorHandles = GetUAVsFromImageViews<RHI::ImageView, ImageView>(imageViews, ConvertUAVDimension(imageType));
break;
}
default:
AZ_Assert(false, "Unhandled D3D12_DESCRIPTOR_RANGE_TYPE enumeration");
break;
}
m_descriptorContext->UpdateDescriptorTableRange(
descriptorTable, descriptorHandles.data(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
}
RHI::ResultCode ShaderResourceGroupPool::UpdateDescriptorTableAfterCompaction(
RHI::ShaderResourceGroup& groupBase, const RHI::ShaderResourceGroupData& groupData)
{
// Since we are trying to compact we will re-create all the descriptor tables and re-update them all
ShaderResourceGroup& group = static_cast<ShaderResourceGroup&>(groupBase);
if (m_viewsDescriptorTableSize)
{
group.m_viewsDescriptorTable = m_descriptorContext->CreateDescriptorTable(
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_viewsDescriptorTableRingSize, &group);
if (!group.m_viewsDescriptorTable.IsValid())
{
AZ_Assert(
false,
"Descriptor heap ran out of memory. Please consider increasing number of handles allowed for the second value"
"of DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV within platformlimits.azasset file for dx12.");
return RHI::ResultCode::OutOfMemory;
}
CacheGpuHandlesForViews(group);
const DescriptorTable descriptorTable(
group.m_viewsDescriptorTable.GetOffset() + group.m_compiledDataIndex * m_viewsDescriptorTableSize,
static_cast<uint16_t>(m_viewsDescriptorTableSize));
UpdateViewsDescriptorTable(descriptorTable, groupData);
}
if (m_unboundedArrayCount)
{
//Reset all the old descriptor tables as the previous heap is gone.
for (uint32_t unboundedArrayindex = 0; unboundedArrayindex < (ShaderResourceGroupCompiledData::MaxUnboundedArrays * RHI::Limits::Device::FrameCountMax); ++unboundedArrayindex)
{
group.m_unboundedDescriptorTables[unboundedArrayindex] = DescriptorTable{};
}
const RHI::ShaderResourceGroupLayout& groupLayout = *groupData.GetLayout();
uint32_t shaderInputIndex = 0;
// process buffer unbounded arrays
for (const RHI::ShaderInputBufferUnboundedArrayDescriptor& shaderInputBufferUnboundedArray : groupLayout.GetShaderInputListForBufferUnboundedArrays())
{
const RHI::ShaderInputBufferUnboundedArrayIndex bufferUnboundedArrayInputIndex(shaderInputIndex);
AZStd::array_view<RHI::ConstPtr<RHI::BufferView>> bufferViews = groupData.GetBufferViewUnboundedArray(bufferUnboundedArrayInputIndex);
uint32_t tableIndex = shaderInputIndex * RHI::Limits::Device::FrameCountMax + group.m_compiledDataIndex;
if (!bufferViews.empty())
{
group.m_unboundedDescriptorTables[tableIndex] = m_descriptorContext->CreateDescriptorTable(
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, static_cast<uint32_t>(bufferViews.size()), &group);
if (!group.m_unboundedDescriptorTables[tableIndex].IsValid())
{
AZ_Assert(
false,
"Descriptor heap ran out of memory. Please consider increasing number of handles allowed for the second value"
"of DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV within platformlimits.azasset file for dx12.");
return RHI::ResultCode::OutOfMemory;
}
ShaderResourceGroupCompiledData& compiledData = group.m_compiledData[group.m_compiledDataIndex];
compiledData.m_gpuUnboundedArraysDescriptorHandles[shaderInputIndex] = m_descriptorContext->GetGpuPlatformHandleForTable(group.m_unboundedDescriptorTables[tableIndex]);
const DescriptorTable descriptorTable(
group.m_unboundedDescriptorTables[tableIndex].GetOffset(), static_cast<uint16_t>(bufferViews.size()));
UpdateUnboundedBuffersDescTable(descriptorTable, groupData, shaderInputIndex, shaderInputBufferUnboundedArray.m_access);
}
shaderInputIndex++;
}
// process image unbounded arrays
for (const RHI::ShaderInputImageUnboundedArrayDescriptor& shaderInputImageUnboundedArray :
groupLayout.GetShaderInputListForImageUnboundedArrays())
{
const RHI::ShaderInputImageUnboundedArrayIndex imageUnboundedArrayInputIndex(shaderInputIndex);
AZStd::array_view<RHI::ConstPtr<RHI::ImageView>> imageViews =
groupData.GetImageViewUnboundedArray(imageUnboundedArrayInputIndex);
uint32_t tableIndex = shaderInputIndex * RHI::Limits::Device::FrameCountMax + group.m_compiledDataIndex;
if (!imageViews.empty())
{
group.m_unboundedDescriptorTables[tableIndex] = m_descriptorContext->CreateDescriptorTable(
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, static_cast<uint32_t>(imageViews.size()), &group);
if (!group.m_unboundedDescriptorTables[tableIndex].IsValid())
{
AZ_Assert(
false,
"Descriptor heap ran out of memory. Please consider increasing number of handles allowed for the second value"
"of DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV within platformlimits.azasset file for dx12.");
return RHI::ResultCode::OutOfMemory;
}
ShaderResourceGroupCompiledData& compiledData = group.m_compiledData[group.m_compiledDataIndex];
compiledData.m_gpuUnboundedArraysDescriptorHandles[shaderInputIndex] = m_descriptorContext->GetGpuPlatformHandleForTable(group.m_unboundedDescriptorTables[tableIndex]);
const DescriptorTable descriptorTable(group.m_unboundedDescriptorTables[tableIndex].GetOffset(), static_cast<uint16_t>(imageViews.size()));
UpdateUnboundedImagesDescTable(descriptorTable, groupData, shaderInputIndex, shaderInputImageUnboundedArray.m_access, shaderInputImageUnboundedArray.m_type);
}
shaderInputIndex++;
}
}
return RHI::ResultCode::Success;
}
void ShaderResourceGroupPool::OnFrameEnd() void ShaderResourceGroupPool::OnFrameEnd()
{ {
m_constantAllocator.GarbageCollect(); m_constantAllocator.GarbageCollect();
@@ -30,6 +30,9 @@ namespace AZ
static RHI::Ptr<ShaderResourceGroupPool> Create(); static RHI::Ptr<ShaderResourceGroupPool> Create();
//! Re-Update the descriptor tables for all the cbv/srv/uav views (direct and via unbounded array)
RHI::ResultCode UpdateDescriptorTableAfterCompaction(RHI::ShaderResourceGroup& groupBase, const RHI::ShaderResourceGroupData& groupData);
private: private:
ShaderResourceGroupPool() = default; ShaderResourceGroupPool() = default;
@@ -51,6 +54,21 @@ namespace AZ
void UpdateSamplersDescriptorTable(DescriptorTable descriptorTable, const RHI::ShaderResourceGroupData& groupData); void UpdateSamplersDescriptorTable(DescriptorTable descriptorTable, const RHI::ShaderResourceGroupData& groupData);
void UpdateUnboundedArrayDescriptorTables(ShaderResourceGroup& group, const RHI::ShaderResourceGroupData& groupData); void UpdateUnboundedArrayDescriptorTables(ShaderResourceGroup& group, const RHI::ShaderResourceGroupData& groupData);
//! Update all the buffer views for the unbounded array
void UpdateUnboundedBuffersDescTable(
DescriptorTable descriptorTable,
const RHI::ShaderResourceGroupData& groupData,
uint32_t shaderInputIndex,
RHI::ShaderInputBufferAccess bufferAccess);
//! Update all the image views for the unbounded array
void UpdateUnboundedImagesDescTable(
DescriptorTable descriptorTable,
const RHI::ShaderResourceGroupData& groupData,
uint32_t shaderInputIndex,
RHI::ShaderInputImageAccess imageAccess,
RHI::ShaderInputImageType imageType);
void UpdateDescriptorTableRange( void UpdateDescriptorTableRange(
DescriptorTable descriptorTable, DescriptorTable descriptorTable,
const AZStd::vector<DescriptorHandle>& descriptors, const AZStd::vector<DescriptorHandle>& descriptors,
@@ -66,6 +84,9 @@ namespace AZ
RHI::ShaderInputSamplerIndex samplerIndex, RHI::ShaderInputSamplerIndex samplerIndex,
AZStd::array_view<RHI::SamplerState> samplerStates); AZStd::array_view<RHI::SamplerState> samplerStates);
//Cache all the gpu handles for the Descriptor tables related to all the views
void CacheGpuHandlesForViews(ShaderResourceGroup& group);
DescriptorTable GetBufferTable(DescriptorTable descriptorTable, RHI::ShaderInputBufferIndex bufferIndex) const; DescriptorTable GetBufferTable(DescriptorTable descriptorTable, RHI::ShaderInputBufferIndex bufferIndex) const;
DescriptorTable GetBufferTableUnbounded(DescriptorTable descriptorTable, RHI::ShaderInputBufferIndex bufferIndex) const; DescriptorTable GetBufferTableUnbounded(DescriptorTable descriptorTable, RHI::ShaderInputBufferIndex bufferIndex) const;
DescriptorTable GetImageTable(DescriptorTable descriptorTable, RHI::ShaderInputImageIndex imageIndex) const; DescriptorTable GetImageTable(DescriptorTable descriptorTable, RHI::ShaderInputImageIndex imageIndex) const;
@@ -79,7 +100,6 @@ namespace AZ
AZStd::vector<DescriptorHandle> GetCBVsFromBufferViews(const AZStd::array_view<RHI::ConstPtr<RHI::BufferView>>& bufferViews); AZStd::vector<DescriptorHandle> GetCBVsFromBufferViews(const AZStd::array_view<RHI::ConstPtr<RHI::BufferView>>& bufferViews);
AZStd::mutex m_constantAllocatorMutex;
MemoryPoolSubAllocator m_constantAllocator; MemoryPoolSubAllocator m_constantAllocator;
DescriptorContext* m_descriptorContext = nullptr; DescriptorContext* m_descriptorContext = nullptr;
uint32_t m_constantBufferSize = 0; uint32_t m_constantBufferSize = 0;
@@ -21,11 +21,13 @@
"$type": "AZ::DX12::PlatformLimitsDescriptor", "$type": "AZ::DX12::PlatformLimitsDescriptor",
"DescriptorHeapLimits": "DescriptorHeapLimits":
{ {
"DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV": [1000000, 1000000], "DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV": [100000, 1000000],
"DESCRIPTOR_HEAP_TYPE_SAMPLER": [2048, 2048], "DESCRIPTOR_HEAP_TYPE_SAMPLER": [2048, 2048],
"DESCRIPTOR_HEAP_TYPE_RTV": [2048, 0], "DESCRIPTOR_HEAP_TYPE_RTV": [2048, 0],
"DESCRIPTOR_HEAP_TYPE_DSV": [2048, 0] "DESCRIPTOR_HEAP_TYPE_DSV": [2048, 0]
} },
"NumShaderVisibleCbvSrvUavStaticHandles": 2000,
"AllowDescriptorHeapCompaction": false
}, },
"vulkan": "vulkan":
{ {
@@ -10,6 +10,10 @@
#include <RHI/Instance.h> #include <RHI/Instance.h>
#include <RHI/WSISurface.h> #include <RHI/WSISurface.h>
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
#include <AzFramework/XcbConnectionManager.h>
#endif
namespace AZ namespace AZ
{ {
namespace Vulkan namespace Vulkan
@@ -21,7 +25,7 @@ namespace AZ
#if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB #if PAL_TRAIT_LINUX_WINDOW_MANAGER_XCB
xcb_connection_t* xcb_connection = nullptr; xcb_connection_t* xcb_connection = nullptr;
if (auto xcbConnectionManager = AzFramework::LinuxXcbConnectionManagerInterface::Get(); if (auto xcbConnectionManager = AzFramework::XcbConnectionManagerInterface::Get();
xcbConnectionManager != nullptr) xcbConnectionManager != nullptr)
{ {
xcb_connection = xcbConnectionManager->GetXcbConnection(); xcb_connection = xcbConnectionManager->GetXcbConnection();
@@ -40,7 +40,7 @@ namespace AZ
//! by ShaderVariantAssetBuilder this is 1+. //! by ShaderVariantAssetBuilder this is 1+.
static uint32_t MakeAssetProductSubId( static uint32_t MakeAssetProductSubId(
uint32_t rhiApiUniqueIndex, uint32_t supervariantIndex, ShaderVariantStableId variantStableId, uint32_t rhiApiUniqueIndex, uint32_t supervariantIndex, ShaderVariantStableId variantStableId,
uint32_t subProductType = ShaderVariantAssetSubProductType); uint32_t subProductType = 0);
ShaderVariantAsset() = default; ShaderVariantAsset() = default;
~ShaderVariantAsset() = default; ~ShaderVariantAsset() = default;
@@ -51,11 +51,11 @@ set(FILES
Include/Multiplayer/NetworkTime/RewindableObject.inl Include/Multiplayer/NetworkTime/RewindableObject.inl
Include/Multiplayer/Physics/PhysicsUtils.h Include/Multiplayer/Physics/PhysicsUtils.h
Include/Multiplayer/ReplicationWindows/IReplicationWindow.h Include/Multiplayer/ReplicationWindows/IReplicationWindow.h
Source/AutoGen/AutoComponentTypes_Header.jinja Include/Multiplayer/AutoGen/AutoComponentTypes_Header.jinja
Source/AutoGen/AutoComponentTypes_Source.jinja Include/Multiplayer/AutoGen/AutoComponentTypes_Source.jinja
Source/AutoGen/AutoComponent_Common.jinja Include/Multiplayer/AutoGen/AutoComponent_Common.jinja
Source/AutoGen/AutoComponent_Header.jinja Include/Multiplayer/AutoGen/AutoComponent_Header.jinja
Source/AutoGen/AutoComponent_Source.jinja Include/Multiplayer/AutoGen/AutoComponent_Source.jinja
Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.xml
Source/AutoGen/Multiplayer.AutoPackets.xml Source/AutoGen/Multiplayer.AutoPackets.xml
Source/AutoGen/MultiplayerEditor.AutoPackets.xml Source/AutoGen/MultiplayerEditor.AutoPackets.xml
@@ -652,8 +652,13 @@ namespace ScriptCanvas
return {}; return {};
} }
bool Method::GetBehaviorContextClassMethod(const AZStd::string&, const AZ::BehaviorClass*& outClass, const AZ::BehaviorMethod*& outMethod, EventType& outType) const bool Method::GetBehaviorContextClassMethod(const AZ::BehaviorClass*& outClass, const AZ::BehaviorMethod*& outMethod, EventType& outType) const
{ {
if (m_lookupName.empty() && m_className.empty())
{
return false;
}
AZStd::string prettyClassName; AZStd::string prettyClassName;
AZStd::string methodName = m_lookupName; AZStd::string methodName = m_lookupName;
@@ -749,15 +754,14 @@ namespace ScriptCanvas
AZStd::tuple<const AZ::BehaviorMethod*, MethodType, EventType, const AZ::BehaviorClass*> Method::LookupMethod() const AZStd::tuple<const AZ::BehaviorMethod*, MethodType, EventType, const AZ::BehaviorClass*> Method::LookupMethod() const
{ {
using TupleType = AZStd::tuple<const AZ::BehaviorMethod*, MethodType, EventType, const AZ::BehaviorClass*>; using TupleType = AZStd::tuple<const AZ::BehaviorMethod*, MethodType, EventType, const AZ::BehaviorClass*>;
AZStd::string methodName = m_lookupName;
AZStd::string prettyClassName; AZStd::string prettyClassName;
const AZ::BehaviorClass* bcClass{}; const AZ::BehaviorClass* bcClass{};
const AZ::BehaviorMethod* method{}; const AZ::BehaviorMethod* method{};
EventType eventType; EventType eventType;
if (GetBehaviorContextClassMethod(m_lookupName, bcClass, method, eventType)) if (GetBehaviorContextClassMethod(bcClass, method, eventType))
{ {
return TupleType{ method, m_methodType, eventType, bcClass }; return TupleType{ method, m_methodType, eventType, bcClass };
} }
@@ -776,7 +780,7 @@ namespace ScriptCanvas
const AZ::BehaviorMethod* method{}; const AZ::BehaviorMethod* method{};
EventType eventType; EventType eventType;
if (GetBehaviorContextClassMethod(m_lookupName, bcClass, method, eventType)) if (GetBehaviorContextClassMethod(bcClass, method, eventType))
{ {
m_eventType = eventType; m_eventType = eventType;
ConfigureMethod(*method, bcClass); ConfigureMethod(*method, bcClass);
@@ -168,7 +168,7 @@ namespace ScriptCanvas
AZ_INLINE void SetWarnOnMissingFunction(bool enabled) { m_warnOnMissingFunction = enabled; } AZ_INLINE void SetWarnOnMissingFunction(bool enabled) { m_warnOnMissingFunction = enabled; }
bool GetBehaviorContextClassMethod(const AZStd::string& name, const AZ::BehaviorClass*& outClass, const AZ::BehaviorMethod*& outMethod, EventType& outType) const; bool GetBehaviorContextClassMethod(const AZ::BehaviorClass*& outClass, const AZ::BehaviorMethod*& outMethod, EventType& outType) const;
private: private:
friend struct ScriptCanvas::BehaviorContextMethodHelper; friend struct ScriptCanvas::BehaviorContextMethodHelper;
@@ -13,8 +13,6 @@
#include <AzCore/Serialization/EditContext.h> #include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/EditContextConstants.inl> #include <AzCore/Serialization/EditContextConstants.inl>
#include <Atom/RPI.Public/FeatureProcessorFactory.h>
#include <TerrainRenderer/TerrainFeatureProcessor.h>
#include <TerrainSystem/TerrainSystem.h> #include <TerrainSystem/TerrainSystem.h>
namespace Terrain namespace Terrain
@@ -34,8 +32,6 @@ namespace Terrain
->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
; ;
} }
Terrain::TerrainFeatureProcessor::Reflect(context);
} }
} }
@@ -49,9 +45,8 @@ namespace Terrain
incompatible.push_back(AZ_CRC_CE("TerrainService")); incompatible.push_back(AZ_CRC_CE("TerrainService"));
} }
void TerrainSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) void TerrainSystemComponent::GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required)
{ {
required.push_back(AZ_CRC_CE("RPISystem"));
} }
void TerrainSystemComponent::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent) void TerrainSystemComponent::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent)
@@ -68,14 +63,11 @@ namespace Terrain
// every time an entity is added or removed to a level. If this ever changes, the Terrain System ownership could move into // every time an entity is added or removed to a level. If this ever changes, the Terrain System ownership could move into
// the level component. // the level component.
m_terrainSystem = new TerrainSystem(); m_terrainSystem = new TerrainSystem();
AZ::RPI::FeatureProcessorFactory::Get()->RegisterFeatureProcessor<Terrain::TerrainFeatureProcessor>();
} }
void TerrainSystemComponent::Deactivate() void TerrainSystemComponent::Deactivate()
{ {
delete m_terrainSystem; delete m_terrainSystem;
m_terrainSystem = nullptr; m_terrainSystem = nullptr;
AZ::RPI::FeatureProcessorFactory::Get()->UnregisterFeatureProcessor<Terrain::TerrainFeatureProcessor>();
} }
} }
@@ -95,6 +95,8 @@ namespace Terrain
AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(GetEntityId()); AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(GetEntityId());
AzFramework::BoundsRequestBus::Handler::BusConnect(GetEntityId()); AzFramework::BoundsRequestBus::Handler::BusConnect(GetEntityId());
AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusConnect(); AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusConnect();
RefreshCachedWireframeGrid(AZ::Aabb::CreateNull());
} }
void TerrainWorldDebuggerComponent::Deactivate() void TerrainWorldDebuggerComponent::Deactivate()
@@ -0,0 +1,213 @@
/*
* 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 <Components/TerrainWorldRendererComponent.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzFramework/Entity/GameEntityContextBus.h>
#include <SurfaceData/SurfaceDataSystemRequestBus.h>
#include <Atom/RPI.Public/Scene.h>
#include <Atom/RPI.Public/FeatureProcessorFactory.h>
#include <TerrainRenderer/TerrainFeatureProcessor.h>
namespace Terrain
{
void TerrainWorldRendererConfig::Reflect(AZ::ReflectContext* context)
{
Terrain::TerrainFeatureProcessor::Reflect(context);
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
if (serialize)
{
serialize->Class<TerrainWorldRendererConfig, AZ::ComponentConfig>()->Version(1);
AZ::EditContext* edit = serialize->GetEditContext();
if (edit)
{
edit->Class<TerrainWorldRendererConfig>("Terrain World Renderer Component", "Enables terrain rendering")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZStd::vector<AZ::Crc32>({ AZ_CRC_CE("Level") }))
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->Attribute(AZ::Edit::Attributes::AutoExpand, true);
}
}
}
void TerrainWorldRendererComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC_CE("TerrainRendererService"));
}
void TerrainWorldRendererComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC_CE("TerrainRendererService"));
}
void TerrainWorldRendererComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC_CE("TerrainService"));
}
void TerrainWorldRendererComponent::Reflect(AZ::ReflectContext* context)
{
TerrainWorldRendererConfig::Reflect(context);
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
if (serialize)
{
serialize->Class<TerrainWorldRendererComponent, AZ::Component>()->Version(0)->Field(
"Configuration", &TerrainWorldRendererComponent::m_configuration);
}
}
TerrainWorldRendererComponent::TerrainWorldRendererComponent(const TerrainWorldRendererConfig& configuration)
: m_configuration(configuration)
{
}
TerrainWorldRendererComponent::~TerrainWorldRendererComponent()
{
if (m_terrainRendererActive)
{
Deactivate();
}
}
AZ::RPI::Scene* TerrainWorldRendererComponent::GetScene() const
{
// Find the entity context for the entity ID.
AzFramework::EntityContextId entityContextId = AzFramework::EntityContextId::CreateNull();
AzFramework::EntityIdContextQueryBus::EventResult(
entityContextId, GetEntityId(), &AzFramework::EntityIdContextQueryBus::Events::GetOwningContextId);
return AZ::RPI::Scene::GetSceneForEntityContextId(entityContextId);
}
void TerrainWorldRendererComponent::Activate()
{
// On component activation, register the terrain feature processor with Atom and the scene related to this entity context.
AZ::RPI::FeatureProcessorFactory::Get()->RegisterFeatureProcessor<Terrain::TerrainFeatureProcessor>();
if (AZ::RPI::Scene* scene = GetScene(); scene)
{
m_terrainFeatureProcessor = scene->EnableFeatureProcessor<Terrain::TerrainFeatureProcessor>();
}
AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusConnect();
m_terrainRendererActive = true;
}
void TerrainWorldRendererComponent::Deactivate()
{
// On component deactivation, unregister the feature processor and remove it from the default scene.
m_terrainRendererActive = false;
AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusDisconnect();
if (AZ::RPI::Scene* scene = GetScene(); scene)
{
if (scene->GetFeatureProcessor<Terrain::TerrainFeatureProcessor>())
{
scene->DisableFeatureProcessor<Terrain::TerrainFeatureProcessor>();
}
}
m_terrainFeatureProcessor = nullptr;
AZ::RPI::FeatureProcessorFactory::Get()->UnregisterFeatureProcessor<Terrain::TerrainFeatureProcessor>();
}
bool TerrainWorldRendererComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
{
if (auto config = azrtti_cast<const TerrainWorldRendererConfig*>(baseConfig))
{
m_configuration = *config;
return true;
}
return false;
}
bool TerrainWorldRendererComponent::WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const
{
if (auto config = azrtti_cast<TerrainWorldRendererConfig*>(outBaseConfig))
{
*config = m_configuration;
return true;
}
return false;
}
void TerrainWorldRendererComponent::OnTerrainDataDestroyBegin()
{
// If the terrain is being destroyed, remove all existing terrain data from the feature processor.
if (m_terrainFeatureProcessor)
{
m_terrainFeatureProcessor->RemoveTerrainData();
}
}
void TerrainWorldRendererComponent::OnTerrainDataChanged([[maybe_unused]] const AZ::Aabb& dirtyRegion, [[maybe_unused]] TerrainDataChangedMask dataChangedMask)
{
// Block other threads from accessing the surface data bus while we are in GetValue (which may call into the SurfaceData bus).
// We lock our surface data mutex *before* checking / setting "isRequestInProgress" so that we prevent race conditions
// that create false detection of cyclic dependencies when multiple requests occur on different threads simultaneously.
// (One case where this was previously able to occur was in rapid updating of the Preview widget on the
// GradientSurfaceDataComponent in the Editor when moving the threshold sliders back and forth rapidly)
auto& surfaceDataContext = SurfaceData::SurfaceDataSystemRequestBus::GetOrCreateContext(false);
typename SurfaceData::SurfaceDataSystemRequestBus::Context::DispatchLockGuard scopeLock(surfaceDataContext.m_contextMutex);
AZ::Vector2 queryResolution = AZ::Vector2(1.0f);
AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
queryResolution, &AzFramework::Terrain::TerrainDataRequests::GetTerrainHeightQueryResolution);
AZ::Aabb worldBounds = AZ::Aabb::CreateNull();
AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
worldBounds, &AzFramework::Terrain::TerrainDataRequests::GetTerrainAabb);
AZ::Transform transform = AZ::Transform::CreateTranslation(worldBounds.GetCenter());
uint32_t width = aznumeric_cast<uint32_t>(
(float)worldBounds.GetXExtent() / queryResolution.GetX());
uint32_t height = aznumeric_cast<uint32_t>(
(float)worldBounds.GetYExtent() / queryResolution.GetY());
AZStd::vector<float> pixels;
pixels.resize_no_construct(width * height);
const uint32_t pixelDataSize = width * height * sizeof(float);
memset(pixels.data(), 0, pixelDataSize);
for (uint32_t y = 0; y < height; y++)
{
for (uint32_t x = 0; x < width; x++)
{
bool terrainExists = true;
float terrainHeight = 0.0f;
AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
terrainHeight, &AzFramework::Terrain::TerrainDataRequests::GetHeightFromFloats,
(x * queryResolution.GetX()) + worldBounds.GetMin().GetX(),
(y * queryResolution.GetY()) + worldBounds.GetMin().GetY(),
AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT,
&terrainExists);
pixels[(y * width) + x] =
(terrainHeight - worldBounds.GetMin().GetZ()) / worldBounds.GetExtents().GetZ();
}
}
if (m_terrainFeatureProcessor)
{
m_terrainFeatureProcessor->UpdateTerrainData(transform, worldBounds, queryResolution.GetX(), width, height, pixels);
}
}
}
@@ -0,0 +1,75 @@
/*
* 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 <AzCore/Component/Component.h>
#include <AzCore/Math/Vector3.h>
#include <TerrainSystem/TerrainSystem.h>
namespace LmbrCentral
{
template<typename, typename>
class EditorWrappedComponentBase;
}
namespace AZ::RPI
{
class Scene;
}
namespace Terrain
{
class TerrainFeatureProcessor;
class TerrainWorldRendererConfig
: public AZ::ComponentConfig
{
public:
AZ_CLASS_ALLOCATOR(TerrainWorldRendererConfig, AZ::SystemAllocator, 0);
AZ_RTTI(TerrainWorldRendererConfig, "{08C5863C-092D-4A69-8226-4978E4F6E343}", AZ::ComponentConfig);
static void Reflect(AZ::ReflectContext* context);
};
class TerrainWorldRendererComponent
: public AZ::Component
, public AzFramework::Terrain::TerrainDataNotificationBus::Handler
{
public:
template<typename, typename>
friend class LmbrCentral::EditorWrappedComponentBase;
AZ_COMPONENT(TerrainWorldRendererComponent, "{3B0DB71E-5944-437C-8C88-70F8B405BFC7}");
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void Reflect(AZ::ReflectContext* context);
TerrainWorldRendererComponent(const TerrainWorldRendererConfig& configuration);
TerrainWorldRendererComponent() = default;
~TerrainWorldRendererComponent() override;
//////////////////////////////////////////////////////////////////////////
// AZ::Component interface implementation
void Activate() override;
void Deactivate() override;
bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override;
bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override;
protected:
void OnTerrainDataDestroyBegin() override;
void OnTerrainDataChanged(const AZ::Aabb& dirtyRegion, TerrainDataChangedMask dataChangedMask) override;
AZ::RPI::Scene* GetScene() const;
private:
TerrainWorldRendererConfig m_configuration;
bool m_terrainRendererActive{ false };
TerrainFeatureProcessor* m_terrainFeatureProcessor{ nullptr };
};
}
@@ -0,0 +1,56 @@
/*
* 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 <EditorComponents/EditorTerrainWorldRendererComponent.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
namespace Terrain
{
void EditorTerrainWorldRendererComponent::Reflect(AZ::ReflectContext* context)
{
BaseClassType::Reflect(context);
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<EditorTerrainWorldRendererComponent, BaseClassType>()
->Version(0)
;
if (auto editContext = serializeContext->GetEditContext())
{
editContext->Class<EditorTerrainWorldRendererComponent>(
"Terrain World Renderer", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Category, "Terrain")
->Attribute(AZ::Edit::Attributes::Icon, "Editor/Icons/Components/TerrainWorldRenderer.svg")
->Attribute(AZ::Edit::Attributes::ViewportIcon, "Editor/Icons/Components/Viewport/TerrainWorldRenderer.svg")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZStd::vector<AZ::Crc32>({ AZ_CRC_CE("Level") }))
;
}
}
}
void EditorTerrainWorldRendererComponent::Init()
{
BaseClassType::Init();
}
void EditorTerrainWorldRendererComponent::Activate()
{
BaseClassType::Activate();
}
AZ::u32 EditorTerrainWorldRendererComponent::ConfigurationChanged()
{
return BaseClassType::ConfigurationChanged();
}
}
@@ -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 <Components/TerrainWorldRendererComponent.h>
#include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
#include <LmbrCentral/Component/EditorWrappedComponentBase.h>
namespace Terrain
{
class EditorTerrainWorldRendererComponent
: public LmbrCentral::EditorWrappedComponentBase<TerrainWorldRendererComponent, TerrainWorldRendererConfig>
{
public:
using BaseClassType = LmbrCentral::EditorWrappedComponentBase<TerrainWorldRendererComponent, TerrainWorldRendererConfig>;
AZ_EDITOR_COMPONENT(EditorTerrainWorldRendererComponent, "{7BEFF763-89A6-4EDA-B199-B049A8E757AF}", BaseClassType);
static void Reflect(AZ::ReflectContext* context);
//////////////////////////////////////////////////////////////////////////
// AZ::Component interface implementation
void Init() override;
void Activate() override;
AZ::u32 ConfigurationChanged() override;
protected:
using BaseClassType::m_configuration;
using BaseClassType::m_component;
using BaseClassType::m_visible;
private:
};
}

Some files were not shown because too many files have changed in this diff Show More