Merge branch 'main' into Atom/dmcdiar/ATOM-15517

This commit is contained in:
Doug McDiarmid
2021-06-02 19:09:48 -07:00
94 changed files with 2676 additions and 887 deletions
@@ -29,7 +29,8 @@ ly_add_target(
Legacy::CryCommon
Gem::Atom_RHI.Reflect
Gem::Atom_RPI.Public
Gem::Atom_Bootstrap.Headers
PUBLIC
Gem::Atom_AtomBridge.Static
)
################################################################################
@@ -27,11 +27,14 @@
#include <AzFramework/Scene/SceneSystemInterface.h>
#include <Atom/RPI.Public/DynamicDraw/DynamicDrawContext.h>
#include <AtomBridge/PerViewportDynamicDrawInterface.h>
namespace AZ
{
class FFont;
static constexpr char AtomFontDynamicDrawContextName[] = "AtomFont";
//! AtomFont is the font system manager.
//! AtomFont manages the lifetime of FFont instances, each of which represents an individual font (e.g Courier New Italic)
@@ -90,13 +93,6 @@ namespace AZ
AzFramework::FontDrawInterface* GetFontDrawInterface(AzFramework::FontId fontId) const override;
AzFramework::FontDrawInterface* GetDefaultFontDrawInterface() const override;
void SceneAboutToBeRemoved(AzFramework::Scene& scene);
// Atom DynamicDraw interface management
AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> GetOrCreateDynamicDrawForScene(AZ::RPI::Scene* scene);
public:
void UnregisterFont(const char* fontName);
@@ -108,8 +104,6 @@ namespace AZ
using FontFamilyMap = AZStd::unordered_map<AZStd::string, AZStd::weak_ptr<FontFamily>>;
using FontFamilyReverseLookupMap = AZStd::unordered_map<FontFamily*, FontFamilyMap::iterator>;
using SceneToDynamicDrawMap = AZStd::unordered_map<AZ::RPI::Scene*, AZ::RPI::Ptr<AZ::RPI::DynamicDrawContext>>;
private:
//! Convenience method for loading fonts
IFFont* LoadFont(const char* fontName);
@@ -145,9 +139,6 @@ namespace AZ
int r_persistFontFamilies = 1; //!< Persist fonts for application lifetime to prevent unnecessary work; enabled by default.
AZStd::vector<FontFamilyPtr> m_persistedFontFamilies; //!< Stores persisted fonts (if "persist font families" is enabled)
SceneToDynamicDrawMap m_sceneToDynamicDrawMap;
AZStd::shared_mutex m_sceneToDynamicDrawMutex;
};
}
#endif
@@ -42,11 +42,9 @@
#include <Atom/RPI.Public/Scene.h>
#include <Atom/RPI.Public/DynamicDraw/DynamicDrawInterface.h>
#include <Atom/RPI.Public/ViewportContextBus.h>
#include <Atom/RPI.Public/WindowContext.h>
#include <Atom/RPI.Public/Image/StreamingImage.h>
#include <Atom/Bootstrap/DefaultWindowBus.h>
#include <Atom/Bootstrap/BootstrapNotificationBus.h>
struct ISystem;
namespace AZ
@@ -68,7 +66,6 @@ namespace AZ
: public IFFont
, public AZStd::intrusive_refcount<AZStd::atomic_uint, FontDeleter>
, public AzFramework::FontDrawInterface
, private AZ::Render::Bootstrap::NotificationBus::Handler
{
using ref_count = AZStd::intrusive_refcount<AZStd::atomic_uint, FontDeleter>;
friend FontDeleter;
@@ -168,8 +165,8 @@ namespace AZ
struct FontShaderData
{
AZ::RHI::ShaderInputImageIndex m_imageInputIndex;
AZ::RHI::ShaderInputConstantIndex m_viewProjInputIndex;
AZ::RHI::ShaderInputNameIndex m_imageInputIndex = "m_texture";
AZ::RHI::ShaderInputNameIndex m_viewProjInputIndex = "m_worldToProj";
};
public:
@@ -230,7 +227,6 @@ namespace AZ
private:
virtual ~FFont();
bool InitFont(AZ::RPI::Scene* renderScene);
bool InitTexture();
bool InitCache();
@@ -281,8 +277,6 @@ namespace AZ
void ScaleCoord(const RHI::Viewport& viewport, float& x, float& y) const;
void OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene) override;
RPI::WindowContextSharedPtr GetDefaultWindowContext() const;
RPI::ViewportContextPtr GetDefaultViewportContext() const;
@@ -303,6 +297,8 @@ namespace AZ
string m_name;
string m_curPath;
AZ::Name m_dynamicDrawContextName = AZ::Name(AZ::AtomFontDynamicDrawContextName);
FontTexture* m_fontTexture = nullptr;
size_t m_fontBufferSize = 0;
@@ -315,13 +311,6 @@ namespace AZ
AtomFont* m_atomFont = nullptr;
bool m_fontTexDirty = false;
enum class InitializationState : AZ::u8
{
Uninitialized,
Initializing,
Initialized
};
AZStd::atomic<InitializationState> m_fontInitializationState = InitializationState::Uninitialized;
FontEffects m_effects;
@@ -356,6 +345,7 @@ namespace AZ
if (font && font->m_atomFont)
{
font->m_atomFont->UnregisterFont(font->m_name);
font->m_atomFont = nullptr;
}
delete font;
@@ -354,17 +354,26 @@ AZ::AtomFont::AtomFont(ISystem* system)
#endif
AZ::Interface<AzFramework::FontQueryInterface>::Register(this);
m_sceneEventHandler = AzFramework::ISceneSystem::SceneEvent::Handler(
[this](AzFramework::ISceneSystem::EventType eventType, const AZStd::shared_ptr<AzFramework::Scene>& scene)
// register font per viewport dynamic draw context.
static const char* shaderFilepath = "Shaders/SimpleTextured.azshader";
AZ::AtomBridge::PerViewportDynamicDraw::Get()->RegisterDynamicDrawContext(
AZ::Name(AZ::AtomFontDynamicDrawContextName),
[](RPI::Ptr<RPI::DynamicDrawContext> drawContext)
{
if (eventType == AzFramework::ISceneSystem::EventType::ScenePendingRemoval)
{
SceneAboutToBeRemoved(*scene);
}
Data::Instance<RPI::Shader> shader = AZ::RPI::LoadShader(shaderFilepath);
AZ::RPI::ShaderOptionList shaderOptions;
shaderOptions.push_back(AZ::RPI::ShaderOption(AZ::Name("o_useColorChannels"), AZ::Name("false")));
shaderOptions.push_back(AZ::RPI::ShaderOption(AZ::Name("o_clamp"), AZ::Name("true")));
drawContext->InitShaderWithVariant(shader, &shaderOptions);
drawContext->InitVertexFormat(
{
{"POSITION", RHI::Format::R32G32B32_FLOAT},
{"COLOR", RHI::Format::B8G8R8A8_UNORM},
{"TEXCOORD0", RHI::Format::R32G32_FLOAT}
});
drawContext->EndInit();
});
auto sceneSystem = AzFramework::SceneSystemInterface::Get();
AZ_Assert(sceneSystem, "Font created before the scene system is available.");
sceneSystem->ConnectToEvents(m_sceneEventHandler);
}
AZ::AtomFont::~AtomFont()
@@ -860,52 +869,5 @@ XmlNodeRef AZ::AtomFont::LoadFontFamilyXml(const char* fontFamilyName, string& o
return root;
}
void AZ::AtomFont::SceneAboutToBeRemoved(AzFramework::Scene& scene)
{
AZ::RPI::ScenePtr* rpiScene = scene.FindSubsystem<AZ::RPI::ScenePtr>();
if (rpiScene)
{
AZStd::lock_guard<AZStd::shared_mutex> lock(m_sceneToDynamicDrawMutex);
if (auto it = m_sceneToDynamicDrawMap.find(rpiScene->get()); it != m_sceneToDynamicDrawMap.end())
{
m_sceneToDynamicDrawMap.erase(it);
}
}
}
AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> AZ::AtomFont::GetOrCreateDynamicDrawForScene(AZ::RPI::Scene* scene)
{
static const char* shaderFilepath = "Shaders/SimpleTextured.azshader";
{
// shared lock while reading
AZStd::shared_lock<AZStd::shared_mutex> lock(m_sceneToDynamicDrawMutex);
if (auto it = m_sceneToDynamicDrawMap.find(scene); it != m_sceneToDynamicDrawMap.end())
{
return it->second;
}
}
// Create and initialize DynamicDrawContext for font draw
AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw = RPI::DynamicDrawInterface::Get()->CreateDynamicDrawContext(scene);
Data::Instance<RPI::Shader> shader = AZ::RPI::LoadShader(shaderFilepath);
AZ::RPI::ShaderOptionList shaderOptions;
shaderOptions.push_back(AZ::RPI::ShaderOption(AZ::Name("o_useColorChannels"), AZ::Name("false")));
shaderOptions.push_back(AZ::RPI::ShaderOption(AZ::Name("o_clamp"), AZ::Name("true")));
dynamicDraw->InitShaderWithVariant(shader, &shaderOptions);
dynamicDraw->InitVertexFormat({{"POSITION", RHI::Format::R32G32B32_FLOAT}, {"COLOR", RHI::Format::B8G8R8A8_UNORM}, {"TEXCOORD0", RHI::Format::R32G32_FLOAT}});
dynamicDraw->EndInit();
// exclusive lock while writing
AZStd::lock_guard<AZStd::shared_mutex> lock(m_sceneToDynamicDrawMutex);
m_sceneToDynamicDrawMap.insert(AZStd::make_pair(scene, dynamicDraw));
return dynamicDraw;
}
#endif
@@ -60,14 +60,7 @@ static const size_t MaxVerts = 8 * 1024; // 2048 quads
static const size_t MaxIndices = (MaxVerts * 6) / 4; // 6 indices per quad, 6/4 * MaxVerts
static const char DrawList2DPassName[] = "2dpass";
namespace ShaderInputs
{
static const char TextureIndexName[] = "m_texture";
static const char WorldToProjIndexName[] = "m_worldToProj";
static const char SamplerIndexName[] = "m_sampler";
}
AZ::FFont::FFont(AtomFont* atomFont, const char* fontName)
AZ::FFont::FFont(AZ::AtomFont* atomFont, const char* fontName)
: m_name(fontName)
, m_atomFont(atomFont)
{
@@ -78,9 +71,14 @@ AZ::FFont::FFont(AtomFont* atomFont, const char* fontName)
FontEffect* effect = AddEffect("default");
effect->AddPass();
AddRef();
// Create cpu memory to cache the font draw data before submit
m_vertexBuffer = new SVF_P3F_C4B_T2F[MaxVerts];
m_indexBuffer = new u16[MaxIndices];
AZ::Render::Bootstrap::NotificationBus::Handler::BusConnect();
m_vertexCount = 0;
m_indexCount = 0;
AddRef();
}
AZ::RPI::ViewportContextPtr AZ::FFont::GetDefaultViewportContext() const
@@ -98,55 +96,10 @@ AZ::RPI::WindowContextSharedPtr AZ::FFont::GetDefaultWindowContext() const
return {};
}
bool AZ::FFont::InitFont(AZ::RPI::Scene* renderScene)
{
if (!renderScene)
{
return false;
}
auto initializationState = InitializationState::Uninitialized;
// Do an atomic transition to Initializing if we're in the Uninitialized state.
// Otherwise, check the current state.
// If we're Initialized, there's no more work to be done, return true to indicate we're good to go.
// If we're Initializing (on another thread), return false to let the consumer know it's not safe for us to be used yet.
if (!m_fontInitializationState.compare_exchange_strong(initializationState, InitializationState::Initializing))
{
return initializationState == InitializationState::Initialized;
}
// Create and initialize DynamicDrawContext for font draw
AZ::RPI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw = m_atomFont->GetOrCreateDynamicDrawForScene(renderScene);
// Save draw srg input indices for later use
Data::Instance<RPI::ShaderResourceGroup> drawSrg = dynamicDraw->NewDrawSrg();
const RHI::ShaderResourceGroupLayout* layout = drawSrg->GetAsset()->GetLayout();
m_fontShaderData.m_imageInputIndex = layout->FindShaderInputImageIndex(AZ::Name(ShaderInputs::TextureIndexName));
AZ_Error("AtomFont::FFont", m_fontShaderData.m_imageInputIndex.IsValid(), "Failed to find shader input constant %s.",
ShaderInputs::TextureIndexName);
m_fontShaderData.m_viewProjInputIndex = layout->FindShaderInputConstantIndex(AZ::Name(ShaderInputs::WorldToProjIndexName));
AZ_Error("AtomFont::FFont", m_fontShaderData.m_viewProjInputIndex.IsValid(), "Failed to find shader input constant %s.",
ShaderInputs::WorldToProjIndexName);
// Create cpu memory to cache the font draw data before submit
m_vertexBuffer = new SVF_P3F_C4B_T2F[MaxVerts];
m_indexBuffer = new u16[MaxIndices];
m_vertexCount = 0;
m_indexCount = 0;
m_fontInitializationState = InitializationState::Initialized;
return true;
}
AZ::FFont::~FFont()
{
AZ_Assert(m_atomFont == nullptr, "The font should already be unregistered through a call to AZ::FFont::Release()");
AZ::Render::Bootstrap::NotificationBus::Handler::BusDisconnect();
delete[] m_vertexBuffer;
delete[] m_indexBuffer;
@@ -303,7 +256,8 @@ void AZ::FFont::DrawStringUInternal(
const TextDrawContext& ctx)
{
// Lazily ensure we're initialized before attempting to render.
if (!viewportContext || !InitFont(viewportContext->GetRenderScene().get()))
// Validate that there is a render scene before attempting to init.
if (!viewportContext || !viewportContext->GetRenderScene())
{
return;
}
@@ -323,12 +277,6 @@ void AZ::FFont::DrawStringUInternal(
return;
}
// if the font is about to be deleted then m_atomFont can be nullptr
if (!m_atomFont)
{
return;
}
const bool orthoMode = ctx.m_overrideViewProjMatrices;
const float viewX = viewport.m_minX;
@@ -406,14 +354,17 @@ void AZ::FFont::DrawStringUInternal(
if (numQuads)
{
auto dynamicDraw = m_atomFont->GetOrCreateDynamicDrawForScene(viewportContext->GetRenderScene().get());
//setup per draw srg
auto drawSrg = dynamicDraw->NewDrawSrg();
drawSrg->SetConstant(m_fontShaderData.m_viewProjInputIndex, modelViewProjMat);
drawSrg->SetImageView(m_fontShaderData.m_imageInputIndex, m_fontStreamingImage->GetImageView());
drawSrg->Compile();
AZ::RPI::Ptr<AZ::RPI::DynamicDrawContext> dynamicDraw = AZ::AtomBridge::PerViewportDynamicDraw::Get()->GetDynamicDrawContextForViewport(m_dynamicDrawContextName, viewportContext->GetId());
if (dynamicDraw)
{
//setup per draw srg
auto drawSrg = dynamicDraw->NewDrawSrg();
drawSrg->SetConstant(m_fontShaderData.m_viewProjInputIndex, modelViewProjMat);
drawSrg->SetImageView(m_fontShaderData.m_imageInputIndex, m_fontStreamingImage->GetImageView());
drawSrg->Compile();
dynamicDraw->DrawIndexed(m_vertexBuffer, m_vertexCount, m_indexBuffer, m_indexCount, RHI::IndexFormat::Uint16, drawSrg);
dynamicDraw->DrawIndexed(m_vertexBuffer, m_vertexCount, m_indexBuffer, m_indexCount, RHI::IndexFormat::Uint16, drawSrg);
}
m_indexCount = 0;
m_vertexCount = 0;
}
@@ -694,12 +645,6 @@ uint32_t AZ::FFont::WriteTextQuadsToBuffers(SVF_P2F_C4B_T2F_F4B* verts, uint16_t
return numQuadsWritten;
}
// if the font is about to be deleted then m_atomFont can be nullptr
if (!m_atomFont)
{
return numQuadsWritten;
}
SVF_P2F_C4B_T2F_F4B* vertexData = verts;
uint16_t* indexData = indices;
size_t vertexOffset = 0;
@@ -1523,7 +1468,7 @@ bool AZ::FFont::UpdateTexture()
{
using namespace AZ;
if (m_fontInitializationState != InitializationState::Initialized || !m_fontImage)
if (!m_fontImage)
{
return false;
}
@@ -1591,7 +1536,7 @@ void AZ::FFont::Prepare(const char* str, bool updateTexture, const AtomFont::Gly
const bool rerenderGlyphs = m_sizeBehavior == SizeBehavior::Rerender;
const AtomFont::GlyphSize usedGlyphSize = rerenderGlyphs ? glyphSize : AtomFont::defaultGlyphSize;
bool texUpdateNeeded = m_fontTexture->PreCacheString(str, nullptr, m_sizeRatio, usedGlyphSize, m_fontHintParams) == 1 || m_fontTexDirty;
if (m_fontInitializationState == InitializationState::Initialized && updateTexture && texUpdateNeeded && m_fontImage)
if (updateTexture && texUpdateNeeded && m_fontImage)
{
UpdateTexture();
m_fontTexDirty = false;
@@ -1625,12 +1570,6 @@ void AZ::FFont::ScaleCoord(const RHI::Viewport& viewport, float& x, float& y) co
y *= height / WindowScaleHeight;
}
void AZ::FFont::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapScene)
{
InitFont(bootstrapScene);
}
static void SetCommonContextFlags(AZ::TextDrawContext& ctx, const AzFramework::TextDrawParameters& params)
{
if (params.m_hAlign == AzFramework::TextHorizontalAlignment::Center)
@@ -78,11 +78,9 @@ namespace AZ
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<EditorMaterialComponentSlot>()
->Version(4, &EditorMaterialComponentSlot::ConvertVersion)
->Version(5, &EditorMaterialComponentSlot::ConvertVersion)
->Field("id", &EditorMaterialComponentSlot::m_id)
->Field("materialAsset", &EditorMaterialComponentSlot::m_materialAsset)
->Field("propertyOverrides", &EditorMaterialComponentSlot::m_propertyOverrides)
->Field("matModUvOverrides", &EditorMaterialComponentSlot::m_matModUvOverrides)
;
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
@@ -140,9 +140,16 @@ namespace AZ
AZ::Vector3 nonUniformScale = AZ::Vector3::CreateOne();
AZ::NonUniformScaleRequestBus::EventResult(nonUniformScale, GetEntityId(), &AZ::NonUniformScaleRequests::GetScale);
float t;
AZ::Vector3 ignoreNormal;
constexpr float rayLength = 1000.0f;
if (m_controller.GetModel()->RayIntersection(transform, nonUniformScale, src, dir * rayLength, t, ignoreNormal))
{
distance = rayLength * t;
return true;
}
return m_controller.GetModel()->RayIntersection(transform, nonUniformScale, src, dir, distance, ignoreNormal);
return false;
}
bool EditorMeshComponent::SupportsEditorRayIntersect()
@@ -485,16 +485,12 @@ namespace AZ
m_transformInterface->GetWorldTM(), m_cachedNonUniformScale, ray.m_startWorldPosition,
ray.m_endWorldPosition - ray.m_startWorldPosition, t, normal))
{
// note: this is a temporary workaround to handle cases where model->RayIntersection
// returns negative distances, follow-up ATOM-15673
const auto absT = AZStd::abs(t);
// fill in ray result structure after successful intersection
const auto intersectionLine = (ray.m_endWorldPosition - ray.m_startWorldPosition);
result.m_uv = AZ::Vector2::CreateZero();
result.m_worldPosition = ray.m_startWorldPosition + intersectionLine * absT;
result.m_worldPosition = ray.m_startWorldPosition + intersectionLine * t;
result.m_worldNormal = normal;
result.m_distance = intersectionLine.GetLength() * absT;
result.m_distance = intersectionLine.GetLength() * t;
result.m_entityAndComponent = m_entityComponentIdPair;
}
}