Merge branch 'development' of https://github.com/o3de/o3de into cgalvan/DraftStreamingImageAssetPixelAPI

This commit is contained in:
Chris Galvan
2022-01-24 11:48:44 -06:00
184 changed files with 2704 additions and 1224 deletions
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7f94f2634eacb4d7bee20dacc45edef96e4d268f1adb7960b8aa8f3b6e2906ed
size 6867609
@@ -69,7 +69,7 @@ def AreaNodes_DependentComponentsAdded():
# Open an existing simple level
helper.init_idle()
helper.open_level("Physics", "Base")
helper.open_level("", "Base")
# Open Landscape Canvas tool and verify
general.open_pane('Landscape Canvas')
@@ -12,6 +12,13 @@ import ly_test_tools.environment.file_system as file_system
import ly_test_tools._internal.pytest_plugin as internal_plugin
from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorParallelTest, EditorTestSuite
@pytest.mark.SUITE_periodic
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
@pytest.mark.parametrize("project", ["AutomatedTesting"])
class TestAutomationWithPrefabSystemEnabled(EditorTestSuite):
class test_LandscapeCanvas_AreaNodes_DependentComponentsAdded(EditorSharedTest):
from .EditorScripts import AreaNodes_DependentComponentsAdded as test_module
@pytest.mark.SUITE_periodic
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
@@ -26,9 +33,6 @@ class TestAutomation(EditorTestSuite):
class test_LandscapeCanvas_GradientMixer_NodeConstruction(EditorSharedTest):
from .EditorScripts import GradientMixer_NodeConstruction as test_module
class test_LandscapeCanvas_AreaNodes_DependentComponentsAdded(EditorSharedTest):
from .EditorScripts import AreaNodes_DependentComponentsAdded as test_module
class test_LandscapeCanvas_AreaNodes_EntityCreatedOnNodeAdd(EditorSharedTest):
from .EditorScripts import AreaNodes_EntityCreatedOnNodeAdd as test_module
@@ -0,0 +1,56 @@
{
"entries": [
{
"base": "AuthorityToAutonomous_PlayerNumber Notify Event",
"context": "AZEventHandler",
"variant": "",
"details": {
"name": "Authority To Autonomous_ Player Number Notify Event"
},
"slots": [
{
"base": "player_number",
"details": {
"name": "player_number"
}
},
{
"base": "AuthorityToAutonomous_PlayerNumber Notify Event",
"details": {
"name": "AuthorityToAutonomous_PlayerNumber Notify Event"
}
},
{
"base": "Connect",
"details": {
"name": "Connect"
}
},
{
"base": "Disconnect",
"details": {
"name": "Disconnect"
}
},
{
"base": "On Connected",
"details": {
"name": "On Connected"
}
},
{
"base": "On Disconnected",
"details": {
"name": "On Disconnected"
}
},
{
"base": "OnEvent",
"details": {
"name": "OnEvent"
}
}
]
}
]
}
@@ -0,0 +1,50 @@
{
"entries": [
{
"base": "AuthorityToClientNoParams_PlayFx Notify Event",
"context": "AZEventHandler",
"variant": "",
"details": {
"name": "Authority To Client No Params_ Play Fx Notify Event"
},
"slots": [
{
"base": "AuthorityToClientNoParams_PlayFx Notify Event",
"details": {
"name": "AuthorityToClientNoParams_PlayFx Notify Event"
}
},
{
"base": "Connect",
"details": {
"name": "Connect"
}
},
{
"base": "Disconnect",
"details": {
"name": "Disconnect"
}
},
{
"base": "On Connected",
"details": {
"name": "On Connected"
}
},
{
"base": "On Disconnected",
"details": {
"name": "On Disconnected"
}
},
{
"base": "OnEvent",
"details": {
"name": "OnEvent"
}
}
]
}
]
}
@@ -0,0 +1,56 @@
{
"entries": [
{
"base": "ServerToAuthority_DealDamage Notify Event",
"context": "AZEventHandler",
"variant": "",
"details": {
"name": "Server To Authority_ Deal Damage Notify Event"
},
"slots": [
{
"base": "damage",
"details": {
"name": "damage"
}
},
{
"base": "ServerToAuthority_DealDamage Notify Event",
"details": {
"name": "ServerToAuthority_DealDamage Notify Event"
}
},
{
"base": "Connect",
"details": {
"name": "Connect"
}
},
{
"base": "Disconnect",
"details": {
"name": "Disconnect"
}
},
{
"base": "On Connected",
"details": {
"name": "On Connected"
}
},
{
"base": "On Disconnected",
"details": {
"name": "On Disconnected"
}
},
{
"base": "OnEvent",
"details": {
"name": "OnEvent"
}
}
]
}
]
}
@@ -8,64 +8,6 @@
"name": "Network Test Player Component"
},
"methods": [
{
"base": "AutonomousToAuthority",
"context": "NetworkTestPlayerComponent",
"entry": {
"name": "In",
"tooltip": "When signaled, this will invoke Autonomous To Authority"
},
"exit": {
"name": "Out",
"tooltip": "Signaled after Autonomous To Authority is invoked"
},
"details": {
"name": "Autonomous To Authority"
},
"params": [
{
"typeid": "{CA5E5C37-98A6-04D2-E15C-1B4BFEE4C7DD}",
"details": {
"name": "Network Test Player Component"
}
},
{
"typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}",
"details": {
"name": "float"
}
}
]
},
{
"base": "ServerToAuthority",
"context": "NetworkTestPlayerComponent",
"entry": {
"name": "In",
"tooltip": "When signaled, this will invoke Server To Authority"
},
"exit": {
"name": "Out",
"tooltip": "Signaled after Server To Authority is invoked"
},
"details": {
"name": "Server To Authority"
},
"params": [
{
"typeid": "{CA5E5C37-98A6-04D2-E15C-1B4BFEE4C7DD}",
"details": {
"name": "Network Test Player Component"
}
},
{
"typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}",
"details": {
"name": "float"
}
}
]
},
{
"base": "AutonomousToAuthorityByEntityId",
"context": "NetworkTestPlayerComponent",
@@ -97,18 +39,72 @@
]
},
{
"base": "ServerToAuthorityByEntityId",
"base": "AuthorityToClientNoParams_PlayFxByEntityId",
"context": "NetworkTestPlayerComponent",
"entry": {
"name": "In",
"tooltip": "When signaled, this will invoke Server To Authority By Entity Id"
"tooltip": "When signaled, this will invoke Authority To Client No Params_ Play Fx By Entity Id"
},
"exit": {
"name": "Out",
"tooltip": "Signaled after Server To Authority By Entity Id is invoked"
"tooltip": "Signaled after Authority To Client No Params_ Play Fx By Entity Id is invoked"
},
"details": {
"name": "Server To Authority By Entity Id"
"name": "Authority To Client No Params_ Play Fx By Entity Id"
},
"params": [
{
"typeid": "{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}",
"details": {
"name": "Source",
"tooltip": "The Source containing the NetworkTestPlayerComponentController"
}
}
]
},
{
"base": "AuthorityToAutonomous_PlayerNumberByEntityId",
"context": "NetworkTestPlayerComponent",
"entry": {
"name": "In",
"tooltip": "When signaled, this will invoke Authority To Autonomous_ Player Number By Entity Id"
},
"exit": {
"name": "Out",
"tooltip": "Signaled after Authority To Autonomous_ Player Number By Entity Id is invoked"
},
"details": {
"name": "Authority To Autonomous_ Player Number By Entity Id"
},
"params": [
{
"typeid": "{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}",
"details": {
"name": "Source",
"tooltip": "The Source containing the NetworkTestPlayerComponentController"
}
},
{
"typeid": "{72039442-EB38-4D42-A1AD-CB68F7E0EEF6}",
"details": {
"name": "player_number"
}
}
]
},
{
"base": "ServerToAuthority_DealDamageByEntityId",
"context": "NetworkTestPlayerComponent",
"entry": {
"name": "In",
"tooltip": "When signaled, this will invoke Server To Authority_ Deal Damage By Entity Id"
},
"exit": {
"name": "Out",
"tooltip": "Signaled after Server To Authority_ Deal Damage By Entity Id is invoked"
},
"details": {
"name": "Server To Authority_ Deal Damage By Entity Id"
},
"params": [
{
@@ -121,47 +117,48 @@
{
"typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}",
"details": {
"name": "some Float"
"name": "damage"
}
}
]
},
{
"base": "AutonomousToAuthorityNoParams",
"base": "AutonomousToAuthorityNoParamsByEntityId",
"context": "NetworkTestPlayerComponent",
"entry": {
"name": "In",
"tooltip": "When signaled, this will invoke Autonomous To Authority No Params"
"tooltip": "When signaled, this will invoke Autonomous To Authority No Params By Entity Id"
},
"exit": {
"name": "Out",
"tooltip": "Signaled after Autonomous To Authority No Params is invoked"
"tooltip": "Signaled after Autonomous To Authority No Params By Entity Id is invoked"
},
"details": {
"name": "Autonomous To Authority No Params"
"name": "Autonomous To Authority No Params By Entity Id"
},
"params": [
{
"typeid": "{CA5E5C37-98A6-04D2-E15C-1B4BFEE4C7DD}",
"typeid": "{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}",
"details": {
"name": "Network Test Player Component"
"name": "Source",
"tooltip": "The Source containing the NetworkTestPlayerComponentController"
}
}
]
},
{
"base": "AuthorityToAutonomous",
"base": "ServerToAuthority_DealDamage",
"context": "NetworkTestPlayerComponent",
"entry": {
"name": "In",
"tooltip": "When signaled, this will invoke Authority To Autonomous"
"tooltip": "When signaled, this will invoke Server To Authority_ Deal Damage"
},
"exit": {
"name": "Out",
"tooltip": "Signaled after Authority To Autonomous is invoked"
"tooltip": "Signaled after Server To Authority_ Deal Damage is invoked"
},
"details": {
"name": "Authority To Autonomous"
"name": "Server To Authority_ Deal Damage"
},
"params": [
{
@@ -179,18 +176,18 @@
]
},
{
"base": "AuthorityToClientNoParams",
"base": "AutonomousToAuthority",
"context": "NetworkTestPlayerComponent",
"entry": {
"name": "In",
"tooltip": "When signaled, this will invoke Authority To Client No Params"
"tooltip": "When signaled, this will invoke Autonomous To Authority"
},
"exit": {
"name": "Out",
"tooltip": "Signaled after Authority To Client No Params is invoked"
"tooltip": "Signaled after Autonomous To Authority is invoked"
},
"details": {
"name": "Authority To Client No Params"
"name": "Autonomous To Authority"
},
"params": [
{
@@ -198,6 +195,41 @@
"details": {
"name": "Network Test Player Component"
}
},
{
"typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}",
"details": {
"name": "float"
}
}
]
},
{
"base": "AuthorityToAutonomous_PlayerNumber",
"context": "NetworkTestPlayerComponent",
"entry": {
"name": "In",
"tooltip": "When signaled, this will invoke Authority To Autonomous_ Player Number"
},
"exit": {
"name": "Out",
"tooltip": "Signaled after Authority To Autonomous_ Player Number is invoked"
},
"details": {
"name": "Authority To Autonomous_ Player Number"
},
"params": [
{
"typeid": "{CA5E5C37-98A6-04D2-E15C-1B4BFEE4C7DD}",
"details": {
"name": "Network Test Player Component"
}
},
{
"typeid": "{72039442-EB38-4D42-A1AD-CB68F7E0EEF6}",
"details": {
"name": "int"
}
}
]
},
@@ -308,79 +340,47 @@
]
},
{
"base": "AuthorityToClientNoParamsByEntityId",
"base": "AutonomousToAuthorityNoParams",
"context": "NetworkTestPlayerComponent",
"entry": {
"name": "In",
"tooltip": "When signaled, this will invoke Authority To Client No Params By Entity Id"
"tooltip": "When signaled, this will invoke Autonomous To Authority No Params"
},
"exit": {
"name": "Out",
"tooltip": "Signaled after Authority To Client No Params By Entity Id is invoked"
"tooltip": "Signaled after Autonomous To Authority No Params is invoked"
},
"details": {
"name": "Authority To Client No Params By Entity Id"
"name": "Autonomous To Authority No Params"
},
"params": [
{
"typeid": "{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}",
"typeid": "{CA5E5C37-98A6-04D2-E15C-1B4BFEE4C7DD}",
"details": {
"name": "Source",
"tooltip": "The Source containing the NetworkTestPlayerComponentController"
"name": "Network Test Player Component"
}
}
]
},
{
"base": "AuthorityToAutonomousByEntityId",
"base": "AuthorityToClientNoParams_PlayFx",
"context": "NetworkTestPlayerComponent",
"entry": {
"name": "In",
"tooltip": "When signaled, this will invoke Authority To Autonomous By Entity Id"
"tooltip": "When signaled, this will invoke Authority To Client No Params_ Play Fx"
},
"exit": {
"name": "Out",
"tooltip": "Signaled after Authority To Autonomous By Entity Id is invoked"
"tooltip": "Signaled after Authority To Client No Params_ Play Fx is invoked"
},
"details": {
"name": "Authority To Autonomous By Entity Id"
"name": "Authority To Client No Params_ Play Fx"
},
"params": [
{
"typeid": "{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}",
"typeid": "{CA5E5C37-98A6-04D2-E15C-1B4BFEE4C7DD}",
"details": {
"name": "Source",
"tooltip": "The Source containing the NetworkTestPlayerComponentController"
}
},
{
"typeid": "{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}",
"details": {
"name": "some Float"
}
}
]
},
{
"base": "AutonomousToAuthorityNoParamsByEntityId",
"context": "NetworkTestPlayerComponent",
"entry": {
"name": "In",
"tooltip": "When signaled, this will invoke Autonomous To Authority No Params By Entity Id"
},
"exit": {
"name": "Out",
"tooltip": "Signaled after Autonomous To Authority No Params By Entity Id is invoked"
},
"details": {
"name": "Autonomous To Authority No Params By Entity Id"
},
"params": [
{
"typeid": "{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}",
"details": {
"name": "Source",
"tooltip": "The Source containing the NetworkTestPlayerComponentController"
"name": "Network Test Player Component"
}
}
]
+4
View File
@@ -93,6 +93,10 @@ endfunction()
# Add the projects first so the Launcher can find them
include(cmake/Projects.cmake)
if(LY_EXTERNAL_SUBDIRS)
set_property(GLOBAL APPEND PROPERTY LY_EXTERNAL_SUBDIRS ${LY_EXTERNAL_SUBDIRS})
endif()
if(NOT INSTALLED_ENGINE)
# Add external subdirectories listed in the engine.json. LY_EXTERNAL_SUBDIRS is a cache variable so the user can add extra
# external subdirectories. This should go before adding the rest of the targets so the targets are availbe to the launcher.
-3
View File
@@ -104,13 +104,11 @@ ly_add_target(
3rdParty::Qt::Concurrent
3rdParty::TIFF
3rdParty::squish-ccr
3rdParty::AWSNativeSDK::STS
Legacy::CryCommon
Legacy::EditorCommon
AZ::AzCore
AZ::AzToolsFramework
Gem::LmbrCentral.Static
AZ::AWSNativeSDKInit
AZ::AtomCore
Gem::Atom_RPI.Edit
Gem::Atom_RPI.Public
@@ -119,7 +117,6 @@ ly_add_target(
Gem::AtomViewportDisplayInfo
${additional_dependencies}
PUBLIC
3rdParty::AWSNativeSDK::Core
3rdParty::Qt::Network
Legacy::EditorCore
RUNTIME_DEPENDENCIES
-12
View File
@@ -36,14 +36,6 @@ AZ_POP_DISABLE_WARNING
#include <QMessageBox>
#include <QDialogButtonBox>
// Aws Native SDK
#include <aws/sts/STSClient.h>
#include <aws/core/auth/AWSCredentialsProvider.h>
#include <aws/sts/model/GetFederationTokenRequest.h>
#include <aws/core/http/HttpClient.h>
#include <aws/core/http/HttpResponse.h>
#include <aws/core/utils/json/JsonSerializer.h>
// AzCore
#include <AzCore/Casting/numeric_cast.h>
#include <AzCore/Component/ComponentApplicationLifecycle.h>
@@ -144,9 +136,7 @@ AZ_POP_DISABLE_WARNING
#include "Plugins/ComponentEntityEditorPlugin/Objects/ComponentEntityObject.h"
// AWSNativeSDK
#include <AzToolsFramework/Undo/UndoSystem.h>
#include <AWSNativeSDKInit/AWSNativeSDKInit.h>
#if defined(AZ_PLATFORM_WINDOWS)
@@ -2125,8 +2115,6 @@ bool CCryEditApp::FixDanglingSharedMemory(const QString& sharedMemName) const
int CCryEditApp::ExitInstance(int exitCode)
{
AZ_TracePrintf("Exit", "Called ExitInstance() with exit code: 0x%x", exitCode);
if (m_pEditor)
{
m_pEditor->OnBeginShutdownSequence();
+1
View File
@@ -18,6 +18,7 @@
// AzCore
#include <AzCore/Component/ComponentApplication.h>
#include <AzCore/IO/IStreamer.h>
#include <AzCore/IO/Streamer/FileRequest.h>
#include <AzCore/std/parallel/binary_semaphore.h>
#include <AzCore/Console/IConsole.h>
-10
View File
@@ -16,12 +16,6 @@
// Qt
#include <QByteArray>
// AWS Native SDK
AZ_PUSH_DISABLE_WARNING(4251 4355 4996, "-Wunknown-warning-option")
#include <aws/core/utils/memory/stl/AWSString.h>
#include <aws/core/platform/FileSystem.h>
AZ_POP_DISABLE_WARNING
// AzCore
#include <AzCore/IO/Path/Path.h>
#include <AzCore/JSON/document.h>
@@ -78,9 +72,6 @@ AZ_POP_DISABLE_WARNING
// EditorCommon
#include <WinWidget/WinWidgetManager.h>
// AWSNativeSDK
#include <AWSNativeSDKInit/AWSNativeSDKInit.h>
#include "Core/QtEditorApplication.h" // for Editor::EditorQtApplication
static CCryEditDoc * theDocument;
@@ -132,7 +123,6 @@ CEditorImpl::CEditorImpl()
, m_pSettingsManager(nullptr)
, m_pLevelIndependentFileMan(nullptr)
, m_pExportManager(nullptr)
, m_awsResourceManager(nullptr)
, m_bMatEditMode(false)
, m_bShowStatusText(true)
, m_bInitialized(false)
-1
View File
@@ -369,7 +369,6 @@ protected:
QString m_selectFileBuffer;
QString m_levelNameBuffer;
IAWSResourceManager* m_awsResourceManager;
std::unique_ptr<WinWidget::WinWidgetManager> m_winWidgetManager;
//! True if the editor is in material edit mode. Fast preview of materials.
@@ -47,12 +47,12 @@ namespace UnitTest
void ViewportMouseCursorRequestImpl::BeginCursorCapture()
{
m_inputChannelMapper->SetCursorCaptureEnabled(true);
m_inputChannelMapper->SetCursorMode(AzToolsFramework::CursorInputMode::CursorModeCaptured);
}
void ViewportMouseCursorRequestImpl::EndCursorCapture()
{
m_inputChannelMapper->SetCursorCaptureEnabled(false);
m_inputChannelMapper->SetCursorMode(AzToolsFramework::CursorInputMode::CursorModeNone);
}
bool ViewportMouseCursorRequestImpl::IsMouseOver() const
-5
View File
@@ -11,11 +11,6 @@
#include <algorithm>
// AWs Native SDK
AZ_PUSH_DISABLE_WARNING(4251 4355 4996, "-Wunknown-warning-option")
#include <aws/core/auth/AWSCredentialsProvider.h>
AZ_POP_DISABLE_WARNING
// Qt
#include <QMenuBar>
#include <QDebug>
@@ -17,6 +17,11 @@
#include <AzCore/Module/Environment.h>
#include <AzCore/std/parallel/shared_mutex.h>
namespace AZStd
{
class any;
}
namespace AZ
{
namespace Data
@@ -19,7 +19,7 @@
#include <AzCore/std/string/string.h>
#include <AzCore/std/string/string_view.h>
#include <AzCore/std/typetraits/is_base_of.h>
#include <AzCore/IO/Streamer/FileRequest.h>
#include <AzCore/IO/IStreamerTypes.h>
namespace AZ
{
@@ -7,11 +7,62 @@
*/
#include <AzCore/Asset/AssetDataStream.h>
#include <AzCore/Memory/Memory.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Debug/Profiler.h>
#include <AzCore/IO/IStreamer.h>
#include <AzCore/IO/Streamer/FileRequest.h>
#include <AzCore/std/parallel/condition_variable.h>
namespace AZ::Data
{
namespace DataStreamInternal
{
struct AssetDataStreamPrivate
{
//! Optional data buffer that's been directly passed in through Open(), instead of reading data from a file.
AZStd::vector<AZ::u8> m_preloadedData;
//! The current active streamer read request - tracked in case we need to cancel it prematurely
AZ::IO::FileRequestPtr m_curReadRequest{ nullptr };
//! Synchronization for the read request, so that it's possible to block until completion.
AZStd::mutex m_readRequestMutex;
AZStd::condition_variable m_readRequestActive;
void SetReadRequest(AZ::IO::FileRequestPtr&& req)
{
AZStd::scoped_lock<AZStd::mutex> lock(m_readRequestMutex);
// The read request finished, so stop tracking it.
m_curReadRequest = AZStd::move(req);
}
void BlockUntilReadComplete()
{
AZStd::unique_lock lock(m_readRequestMutex);
m_readRequestActive.wait(
lock,
[this]
{
return m_curReadRequest == nullptr;
});
lock.unlock();
}
void CancelRequest()
{
AZStd::scoped_lock<AZStd::mutex> lock(m_readRequestMutex);
if (m_curReadRequest)
{
auto streamer = Interface<IO::IStreamer>::Get();
m_curReadRequest = streamer->Cancel(m_curReadRequest);
}
}
};
} // namespace Internal
AssetDataStream::AssetDataStream(AZ::IO::IStreamerTypes::RequestMemoryAllocator* bufferAllocator)
: m_bufferAllocator(bufferAllocator ? bufferAllocator : &m_defaultAllocator)
: m_privateData(AZStd::make_unique<DataStreamInternal::AssetDataStreamPrivate>())
, m_bufferAllocator(bufferAllocator ? bufferAllocator : &m_defaultAllocator)
{
ClearInternalStateData();
}
@@ -53,9 +104,9 @@ namespace AZ::Data
OpenInternal(data.size(), "(mem buffer)");
// Directly take ownership of the provided buffer
m_preloadedData = AZStd::move(data);
m_buffer = m_preloadedData.data();
m_loadedSize = m_preloadedData.size();
m_privateData->m_preloadedData = AZStd::move(data);
m_buffer = m_privateData->m_preloadedData.data();
m_loadedSize = m_privateData->m_preloadedData.size();
}
void AssetDataStream::Open(const AZStd::string& filePath, size_t fileOffset, size_t assetSize,
@@ -65,7 +116,7 @@ namespace AZ::Data
AZ_PROFILE_FUNCTION(AzCore);
AZ_Assert(!m_isOpen, "Attempting to open the stream when it is already open.");
AZ_Assert(!m_curReadRequest, "Queueing an asset stream load while one is still in progress.");
AZ_Assert(!m_privateData->m_curReadRequest, "Queueing an asset stream load while one is still in progress.");
AZ_Assert(!filePath.empty(), "AssetDataStream::Open called without a valid file name.");
// Initialize the state variables and start tracking the overall load timings
@@ -97,11 +148,8 @@ namespace AZ::Data
"Buffer for %s was expected to be %zu bytes, but is %zu bytes.",
m_filePath.c_str(), m_requestedAssetSize, m_loadedSize);
{
AZStd::scoped_lock<AZStd::mutex> lock(m_readRequestMutex);
// The read request finished, so stop tracking it.
m_curReadRequest = nullptr;
}
// The read request finished, so stop tracking it.
m_privateData->SetReadRequest(nullptr);
// Call the load callback to start processing the loaded data.
if (loadCallback)
@@ -115,21 +163,22 @@ namespace AZ::Data
}
// Notify that the load is complete, in case anyone is using BlockUntilLoadComplete to block.
m_readRequestActive.notify_one();
m_privateData->m_readRequestActive.notify_one();
};
// Queue the raw file load with the file streamer.
auto streamer = AZ::Interface<AZ::IO::IStreamer>::Get();
m_curReadRequest = streamer->Read(
m_privateData->m_curReadRequest =
streamer->Read(
m_filePath,
*m_bufferAllocator,
m_requestedAssetSize,
deadline, priority, m_fileOffset);
m_curDeadline = deadline;
m_curPriority = priority;
streamer->SetRequestCompleteCallback(m_curReadRequest, streamerCallback);
streamer->SetRequestCompleteCallback(m_privateData->m_curReadRequest, streamerCallback);
streamer->QueueRequest(m_curReadRequest);
streamer->QueueRequest(m_privateData->m_curReadRequest);
}
else
{
@@ -139,19 +188,19 @@ namespace AZ::Data
loadCallback(AZ::IO::IStreamerTypes::RequestStatus::Completed);
}
m_readRequestActive.notify_one();
m_privateData->m_readRequestActive.notify_one();
}
}
void AssetDataStream::Reschedule(AZStd::chrono::milliseconds newDeadline, AZ::IO::IStreamerTypes::Priority newPriority)
{
if (m_curReadRequest && (newDeadline < m_curDeadline || newPriority > m_curPriority))
if (m_privateData->m_curReadRequest && (newDeadline < m_curDeadline || newPriority > m_curPriority))
{
auto deadline = AZStd::GetMin(m_curDeadline, newDeadline);
auto priority = AZStd::GetMax(m_curPriority, newPriority);
auto streamer = Interface<IO::IStreamer>::Get();
m_curReadRequest = streamer->RescheduleRequest(m_curReadRequest, deadline, priority);
m_privateData->m_curReadRequest = streamer->RescheduleRequest(m_privateData->m_curReadRequest, deadline, priority);
m_curDeadline = deadline;
m_curPriority = priority;
}
@@ -159,15 +208,13 @@ namespace AZ::Data
void AssetDataStream::BlockUntilLoadComplete()
{
AZStd::unique_lock<AZStd::mutex> lock(m_readRequestMutex);
m_readRequestActive.wait(lock, [this] { return m_curReadRequest == nullptr; });
lock.unlock();
m_privateData->BlockUntilReadComplete();
}
void AssetDataStream::ClearInternalStateData()
{
// Clear all our internal state data.
m_preloadedData.resize(0);
m_privateData->m_preloadedData.resize(0);
m_buffer = nullptr;
m_loadedSize = 0;
m_requestedAssetSize = 0;
@@ -204,10 +251,10 @@ namespace AZ::Data
void AssetDataStream::Close()
{
AZ_Assert(m_isOpen, "Attempting to close a stream that hasn't been opened.");
AZ_Assert(m_curReadRequest == nullptr, "Attempting to close a stream with a read request in flight.");
AZ_Assert(m_privateData->m_curReadRequest == nullptr, "Attempting to close a stream with a read request in flight.");
// Destroy the asset buffer and unlock the allocator, so the allocator itself knows that it is no longer needed.
if (m_buffer != m_preloadedData.data())
if (m_buffer != m_privateData->m_preloadedData.data())
{
m_bufferAllocator->Release(m_buffer);
}
@@ -221,12 +268,7 @@ namespace AZ::Data
void AssetDataStream::RequestCancel()
{
AZStd::scoped_lock<AZStd::mutex> lock(m_readRequestMutex);
if (m_curReadRequest)
{
auto streamer = Interface<IO::IStreamer>::Get();
m_curReadRequest = streamer->Cancel(m_curReadRequest);
}
m_privateData->CancelRequest();
}
void AssetDataStream::Seek(AZ::IO::OffsetType bytes, AZ::IO::GenericStream::SeekMode mode)
@@ -9,17 +9,26 @@
#include <AzCore/IO/GenericStreams.h>
#include <AzCore/IO/IStreamerTypes.h>
#include <AzCore/IO/IStreamer.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/parallel/condition_variable.h>
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Debug/Profiler.h>
#include <AzCore/std/functional.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
namespace AZStd
{
template<class T, class Allocator>
class vector;
}
namespace AZ::Data
{
namespace DataStreamInternal
{
struct AssetDataStreamPrivate;
}
class AssetDataStream : public AZ::IO::GenericStream
{
public:
using VectorDataSource = AZStd::vector<AZ::u8, AZStd::allocator>;
// The default Generic Stream APIs in this class will only allow for a single sequential pass
// through the data, no seeking. Reads will block when pages aren't available yet, and
// pages will be marked for recycling once reading has progressed beyond them.
@@ -29,10 +38,10 @@ namespace AZ::Data
~AssetDataStream() override;
// Open the AssetDataStream and make a copy of the provided memory buffer.
void Open(const AZStd::vector<AZ::u8>& data);
void Open(const VectorDataSource& data);
// Open the AssetDataStream and directly take ownership of a pre-populated memory buffer.
void Open(AZStd::vector<AZ::u8>&& data);
void Open(VectorDataSource&& data);
// Open the AssetDataStream and load it via file streaming
using OnCompleteCallback = AZStd::function<void(AZ::IO::IStreamerTypes::RequestStatus)>;
@@ -91,6 +100,8 @@ namespace AZ::Data
void ClearInternalStateData();
AZStd::unique_ptr<DataStreamInternal::AssetDataStreamPrivate> m_privateData;
//! The allocator to use for allocating / deallocating asset buffers
AZ::IO::IStreamerTypes::RequestMemoryAllocator* m_bufferAllocator{ nullptr };
@@ -106,9 +117,6 @@ namespace AZ::Data
//! The amount of data that's expected to be loaded.
size_t m_requestedAssetSize{ 0 };
//! Optional data buffer that's been directly passed in through Open(), instead of reading data from a file.
AZStd::vector<AZ::u8> m_preloadedData;
//! The buffer that will hold the raw data after it's loaded from the file.
void* m_buffer{ nullptr };
@@ -119,19 +127,12 @@ namespace AZ::Data
//! The current offset representing how far we've read into the buffer.
size_t m_curOffset{ 0 };
//! The current active streamer read request - tracked in case we need to cancel it prematurely
AZ::IO::FileRequestPtr m_curReadRequest{ nullptr };
//! The current request deadline. Used to avoid requesting a reschedule to the same (current) deadline.
AZStd::chrono::milliseconds m_curDeadline{ AZ::IO::IStreamerTypes::s_noDeadline };
//! The current request priority. Used to avoid requesting a reschedule to the same (current) priority.
AZ::IO::IStreamerTypes::Priority m_curPriority{ AZ::IO::IStreamerTypes::s_priorityMedium };
//! Synchronization for the read request, so that it's possible to block until completion.
AZStd::mutex m_readRequestMutex;
AZStd::condition_variable m_readRequestActive;
//! Track whether or not the stream is currently open
bool m_isOpen{ false };
@@ -10,6 +10,7 @@
#include <AzCore/Asset/AssetManager_private.h>
#include <AzCore/Asset/AssetDataStream.h>
#include <AzCore/Casting/numeric_cast.h>
#include <AzCore/Debug/Profiler.h>
#include <AzCore/IO/IStreamer.h>
#include <AzCore/Math/Crc.h>
#include <AzCore/Math/MathUtils.h>
@@ -12,7 +12,6 @@
#include <AzCore/Asset/AssetContainer.h>
#include <AzCore/Asset/AssetDataStream.h>
#include <AzCore/Asset/AssetManagerBus.h>
#include <AzCore/IO/Streamer/FileRequest.h>
#include <AzCore/Memory/Memory.h>
#include <AzCore/Memory/SystemAllocator.h> // used as allocator for most components
#include <AzCore/std/parallel/mutex.h>
+5 -1
View File
@@ -15,14 +15,18 @@
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <AzCore/std/string/string.h>
#include <AzCore/std/string/string_view.h>
#include <AzCore/std/any.h>
// These Streamer includes need to be moved to Streamer internals/implementation,
// and pull out only what we need for visibility at IStreamer.h interface declaration.
#include <AzCore/IO/Streamer/Statistics.h>
#include <AzCore/IO/Streamer/FileRequest.h>
namespace AZ::IO
{
class ExternalFileRequest;
class FileRequestHandle;
using FileRequestPtr = AZStd::intrusive_ptr<ExternalFileRequest>;
/**
* Data Streamer Interface
*/
@@ -137,18 +137,18 @@ namespace AZ::IO
AZStd::visit([this, request](auto&& args)
{
using Command = AZStd::decay_t<decltype(args)>;
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadData>)
if constexpr (AZStd::is_same_v<Command, Requests::ReadData>)
{
ReadFile(request, args);
return;
}
else
{
if constexpr (AZStd::is_same_v<Command, FileRequest::FlushData>)
if constexpr (AZStd::is_same_v<Command, Requests::FlushData>)
{
FlushCache(args.m_path);
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::FlushAllData>)
else if constexpr (AZStd::is_same_v<Command, Requests::FlushAllData>)
{
FlushEntireCache();
}
@@ -166,7 +166,7 @@ namespace AZ::IO
{
Section& delayed = m_delayedSections.front();
AZ_Assert(delayed.m_parent, "Delayed section doesn't have a reference to the original request.");
auto data = AZStd::get_if<FileRequest::ReadData>(&delayed.m_parent->GetCommand());
auto data = AZStd::get_if<Requests::ReadData>(&delayed.m_parent->GetCommand());
AZ_Assert(data, "A request in the delayed queue of the BlockCache didn't have a parent with read data.");
// This call can add the same section to the back of the queue if there's not
// enough space. Because of this the entry needs to be removed from the delayed
@@ -233,7 +233,7 @@ namespace AZ::IO
}
}
void BlockCache::ReadFile(FileRequest* request, FileRequest::ReadData& data)
void BlockCache::ReadFile(FileRequest* request, Requests::ReadData& data)
{
if (!m_next)
{
@@ -250,7 +250,7 @@ namespace AZ::IO
m_numMetaDataRetrievalInProgress--;
if (fileSizeRequest.GetStatus() == IStreamerTypes::RequestStatus::Completed)
{
auto& requestInfo = AZStd::get<FileRequest::FileMetaDataRetrievalData>(fileSizeRequest.GetCommand());
auto& requestInfo = AZStd::get<Requests::FileMetaDataRetrievalData>(fileSizeRequest.GetCommand());
if (requestInfo.m_found)
{
ContinueReadFile(request, requestInfo.m_fileSize);
@@ -272,7 +272,7 @@ namespace AZ::IO
Section main;
Section epilog;
auto& data = AZStd::get<FileRequest::ReadData>(request->GetCommand());
auto& data = AZStd::get<Requests::ReadData>(request->GetCommand());
if (!SplitRequest(prolog, main, epilog, data.m_path, fileLength, data.m_offset, data.m_size,
reinterpret_cast<u8*>(data.m_output)))
@@ -21,6 +21,12 @@
namespace AZ::IO
{
class RequestPath;
namespace Requests
{
struct ReadData;
}
struct BlockCacheConfig final :
public IStreamerStackConfig
{
@@ -109,7 +115,7 @@ namespace AZ::IO
using TimePoint = AZStd::chrono::system_clock::time_point;
void ReadFile(FileRequest* request, FileRequest::ReadData& data);
void ReadFile(FileRequest* request, Requests::ReadData& data);
void ContinueReadFile(FileRequest* request, u64 fileLength);
CacheResult ReadFromCache(FileRequest* request, Section& section, const RequestPath& filePath);
CacheResult ReadFromCache(FileRequest* request, Section& section, u32 cacheBlock);
@@ -101,12 +101,12 @@ namespace AZ::IO
AZStd::visit([this, request](auto&& args)
{
using Command = AZStd::decay_t<decltype(args)>;
if constexpr (AZStd::is_same_v<Command, FileRequest::CreateDedicatedCacheData>)
if constexpr (AZStd::is_same_v<Command, Requests::CreateDedicatedCacheData>)
{
args.m_range = FileRange::CreateRangeForEntireFile();
m_context->PushPreparedRequest(request);
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::DestroyDedicatedCacheData>)
else if constexpr (AZStd::is_same_v<Command, Requests::DestroyDedicatedCacheData>)
{
args.m_range = FileRange::CreateRangeForEntireFile();
m_context->PushPreparedRequest(request);
@@ -125,28 +125,28 @@ namespace AZ::IO
AZStd::visit([this, request](auto&& args)
{
using Command = AZStd::decay_t<decltype(args)>;
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadData>)
if constexpr (AZStd::is_same_v<Command, Requests::ReadData>)
{
ReadFile(request, args);
return;
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::CreateDedicatedCacheData>)
else if constexpr (AZStd::is_same_v<Command, Requests::CreateDedicatedCacheData>)
{
CreateDedicatedCache(request, args);
return;
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::DestroyDedicatedCacheData>)
else if constexpr (AZStd::is_same_v<Command, Requests::DestroyDedicatedCacheData>)
{
DestroyDedicatedCache(request, args);
return;
}
else
{
if constexpr (AZStd::is_same_v<Command, FileRequest::FlushData>)
if constexpr (AZStd::is_same_v<Command, Requests::FlushData>)
{
FlushCache(args.m_path);
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::FlushAllData>)
else if constexpr (AZStd::is_same_v<Command, Requests::FlushAllData>)
{
FlushEntireCache();
}
@@ -200,7 +200,7 @@ namespace AZ::IO
}
}
void DedicatedCache::ReadFile(FileRequest* request, FileRequest::ReadData& data)
void DedicatedCache::ReadFile(FileRequest* request, Requests::ReadData& data)
{
size_t index = FindCache(data.m_path, data.m_offset);
if (index == s_fileNotFound)
@@ -255,7 +255,7 @@ namespace AZ::IO
StreamStackEntry::CollectStatistics(statistics);
}
void DedicatedCache::CreateDedicatedCache(FileRequest* request, FileRequest::CreateDedicatedCacheData& data)
void DedicatedCache::CreateDedicatedCache(FileRequest* request, Requests::CreateDedicatedCacheData& data)
{
size_t index = FindCache(data.m_path, data.m_range);
if (index == s_fileNotFound)
@@ -276,7 +276,7 @@ namespace AZ::IO
m_context->MarkRequestAsCompleted(request);
}
void DedicatedCache::DestroyDedicatedCache(FileRequest* request, FileRequest::DestroyDedicatedCacheData& data)
void DedicatedCache::DestroyDedicatedCache(FileRequest* request, Requests::DestroyDedicatedCacheData& data)
{
size_t index = FindCache(data.m_path, data.m_range);
if (index != s_fileNotFound)
@@ -11,15 +11,21 @@
#include <AzCore/IO/Streamer/BlockCache.h>
#include <AzCore/IO/Streamer/FileRange.h>
#include <AzCore/IO/Streamer/Statistics.h>
#include <AzCore/IO/Streamer/StreamerConfiguration.h>
#include <AzCore/IO/Streamer/StreamStackEntry.h>
#include <AzCore/IO/Streamer/StreamerConfiguration.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/std/limits.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/limits.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
namespace AZ::IO
{
namespace Requests
{
struct CreateDedicatedCacheData;
struct DestroyDedicatedCacheData;
} // namespace Requests
struct DedicatedCacheConfig final :
public IStreamerStackConfig
{
@@ -56,16 +62,19 @@ namespace AZ::IO
void UpdateStatus(Status& status) const override;
void UpdateCompletionEstimates(AZStd::chrono::system_clock::time_point now, AZStd::vector<FileRequest*>& internalPending,
StreamerContext::PreparedQueue::iterator pendingBegin, StreamerContext::PreparedQueue::iterator pendingEnd) override;
void UpdateCompletionEstimates(
AZStd::chrono::system_clock::time_point now,
AZStd::vector<FileRequest*>& internalPending,
StreamerContext::PreparedQueue::iterator pendingBegin,
StreamerContext::PreparedQueue::iterator pendingEnd) override;
void CollectStatistics(AZStd::vector<Statistic>& statistics) const override;
private:
void CreateDedicatedCache(FileRequest* request, FileRequest::CreateDedicatedCacheData& data);
void DestroyDedicatedCache(FileRequest* request, FileRequest::DestroyDedicatedCacheData& data);
void CreateDedicatedCache(FileRequest* request, Requests::CreateDedicatedCacheData& data);
void DestroyDedicatedCache(FileRequest* request, Requests::DestroyDedicatedCacheData& data);
void ReadFile(FileRequest* request, FileRequest::ReadData& data);
void ReadFile(FileRequest* request, Requests::ReadData& data);
size_t FindCache(const RequestPath& filename, FileRange range);
size_t FindCache(const RequestPath& filename, u64 offset);
@@ -12,22 +12,30 @@
#include <AzCore/IO/Streamer/FileRequest.h>
#include <AzCore/IO/Streamer/StreamerContext.h>
namespace AZ::IO
//
// Command structures.
//
namespace AZ::IO::Requests
{
//
// Command structures.
//
ReadData::ReadData(void* output, u64 outputSize, const RequestPath& path, u64 offset, u64 size, bool sharedRead)
: m_path(path)
, m_output(output)
, m_outputSize(outputSize)
, m_offset(offset)
, m_size(size)
, m_sharedRead(sharedRead)
{
}
FileRequest::ExternalRequestData::ExternalRequestData(FileRequestPtr&& request)
: m_request(AZStd::move(request))
{}
FileRequest::RequestPathStoreData::RequestPathStoreData(RequestPath path)
: m_path(AZStd::move(path))
{}
FileRequest::ReadRequestData::ReadRequestData(RequestPath path, void* output, u64 outputSize, u64 offset, u64 size,
AZStd::chrono::system_clock::time_point deadline, IStreamerTypes::Priority priority)
ReadRequestData::ReadRequestData(
RequestPath path,
void* output,
u64 outputSize,
u64 offset,
u64 size,
AZStd::chrono::system_clock::time_point deadline,
IStreamerTypes::Priority priority)
: m_path(AZStd::move(path))
, m_allocator(nullptr)
, m_deadline(deadline)
@@ -37,10 +45,16 @@ namespace AZ::IO
, m_size(size)
, m_priority(priority)
, m_memoryType(IStreamerTypes::MemoryType::ReadWrite) // Only generic memory can be assigned externally.
{}
{
}
FileRequest::ReadRequestData::ReadRequestData(RequestPath path, IStreamerTypes::RequestMemoryAllocator* allocator,
u64 offset, u64 size, AZStd::chrono::system_clock::time_point deadline, IStreamerTypes::Priority priority)
ReadRequestData::ReadRequestData(
RequestPath path,
IStreamerTypes::RequestMemoryAllocator* allocator,
u64 offset,
u64 size,
AZStd::chrono::system_clock::time_point deadline,
IStreamerTypes::Priority priority)
: m_path(AZStd::move(path))
, m_allocator(allocator)
, m_deadline(deadline)
@@ -50,9 +64,10 @@ namespace AZ::IO
, m_size(size)
, m_priority(priority)
, m_memoryType(IStreamerTypes::MemoryType::ReadWrite) // Only generic memory can be assigned externally.
{}
{
}
FileRequest::ReadRequestData::~ReadRequestData()
ReadRequestData::~ReadRequestData()
{
if (m_allocator != nullptr)
{
@@ -64,65 +79,80 @@ namespace AZ::IO
}
}
FileRequest::ReadData::ReadData(void* output, u64 outputSize, const RequestPath& path, u64 offset, u64 size, bool sharedRead)
: m_output(output)
, m_outputSize(outputSize)
, m_path(path)
, m_offset(offset)
, m_size(size)
, m_sharedRead(sharedRead)
{}
CreateDedicatedCacheData::CreateDedicatedCacheData(RequestPath path, const FileRange& range)
: m_path(AZStd::move(path))
, m_range(range)
{
}
FileRequest::CompressedReadData::CompressedReadData(CompressionInfo&& compressionInfo, void* output, u64 readOffset, u64 readSize)
DestroyDedicatedCacheData::DestroyDedicatedCacheData(RequestPath path, const FileRange& range)
: m_path(AZStd::move(path))
, m_range(range)
{
}
ExternalRequestData::ExternalRequestData(FileRequestPtr&& request)
: m_request(AZStd::move(request))
{
}
RequestPathStoreData::RequestPathStoreData(RequestPath path)
: m_path(AZStd::move(path))
{
}
CompressedReadData::CompressedReadData(CompressionInfo&& compressionInfo, void* output, u64 readOffset, u64 readSize)
: m_compressionInfo(AZStd::move(compressionInfo))
, m_output(output)
, m_readOffset(readOffset)
, m_readSize(readSize)
{}
{
}
FileRequest::FileExistsCheckData::FileExistsCheckData(const RequestPath& path)
FileExistsCheckData::FileExistsCheckData(const RequestPath& path)
: m_path(path)
{}
{
}
FileRequest::FileMetaDataRetrievalData::FileMetaDataRetrievalData(const RequestPath& path)
FileMetaDataRetrievalData::FileMetaDataRetrievalData(const RequestPath& path)
: m_path(path)
{}
{
}
FileRequest::CancelData::CancelData(FileRequestPtr target)
CancelData::CancelData(FileRequestPtr target)
: m_target(AZStd::move(target))
{}
{
}
FileRequest::FlushData::FlushData(RequestPath path)
FlushData::FlushData(RequestPath path)
: m_path(AZStd::move(path))
{}
{
}
FileRequest::RescheduleData::RescheduleData(FileRequestPtr target, AZStd::chrono::system_clock::time_point newDeadline,
RescheduleData::RescheduleData(
FileRequestPtr target,
AZStd::chrono::system_clock::time_point newDeadline,
IStreamerTypes::Priority newPriority)
: m_target(AZStd::move(target))
, m_newDeadline(newDeadline)
, m_newPriority(newPriority)
{}
{
}
FileRequest::CreateDedicatedCacheData::CreateDedicatedCacheData(RequestPath path, const FileRange& range)
: m_path(AZStd::move(path))
, m_range(range)
{}
FileRequest::DestroyDedicatedCacheData::DestroyDedicatedCacheData(RequestPath path, const FileRange& range)
: m_path(AZStd::move(path))
, m_range(range)
{}
FileRequest::ReportData::ReportData(ReportType reportType)
ReportData::ReportData(ReportType reportType)
: m_reportType(reportType)
{}
{
}
FileRequest::CustomData::CustomData(AZStd::any data, bool failWhenUnhandled)
CustomData::CustomData(AZStd::any data, bool failWhenUnhandled)
: m_data(AZStd::move(data))
, m_failWhenUnhandled(failWhenUnhandled)
{}
{
}
} // namespace AZ::IO::Requests
namespace AZ::IO
{
//
// FileRequest
//
@@ -145,14 +175,14 @@ namespace AZ::IO
m_parent = request->m_request.m_parent;
request->m_request.m_parent = this;
m_dependencies++;
m_command.emplace<ExternalRequestData>(AZStd::move(request));
m_command.emplace<Requests::ExternalRequestData>(AZStd::move(request));
}
void FileRequest::CreateRequestPathStore(FileRequest* parent, RequestPath path)
{
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
"Attempting to set FileRequest to 'CreateRequestPathStore', but another task was already assigned.");
m_command.emplace<RequestPathStoreData>(AZStd::move(path));
m_command.emplace<Requests::RequestPathStoreData>(AZStd::move(path));
SetOptionalParent(parent);
}
@@ -161,7 +191,7 @@ namespace AZ::IO
{
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
"Attempting to set FileRequest to 'ReadRequest', but another task was already assigned.");
m_command.emplace<ReadRequestData>(AZStd::move(path), output, outputSize, offset, size, deadline, priority);
m_command.emplace<Requests::ReadRequestData>(AZStd::move(path), output, outputSize, offset, size, deadline, priority);
}
void FileRequest::CreateReadRequest(RequestPath path, IStreamerTypes::RequestMemoryAllocator* allocator, u64 offset, u64 size,
@@ -169,7 +199,7 @@ namespace AZ::IO
{
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
"Attempting to set FileRequest to 'ReadRequest', but another task was already assigned.");
m_command.emplace<ReadRequestData>(AZStd::move(path), allocator, offset, size, deadline, priority);
m_command.emplace<Requests::ReadRequestData>(AZStd::move(path), allocator, offset, size, deadline, priority);
}
void FileRequest::CreateRead(FileRequest* parent, void* output, u64 outputSize, const RequestPath& path,
@@ -177,7 +207,7 @@ namespace AZ::IO
{
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
"Attempting to set FileRequest to 'Read', but another task was already assigned.");
m_command.emplace<ReadData>(output, outputSize, AZStd::move(path), offset, size, sharedRead);
m_command.emplace<Requests::ReadData>(output, outputSize, AZStd::move(path), offset, size, sharedRead);
SetOptionalParent(parent);
}
@@ -192,7 +222,7 @@ namespace AZ::IO
{
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
"Attempting to set FileRequest to 'CompressedRead', but another task was already assigned.");
m_command.emplace<CompressedReadData>(AZStd::move(compressionInfo), output, readOffset, readSize);
m_command.emplace<Requests::CompressedReadData>(AZStd::move(compressionInfo), output, readOffset, readSize);
SetOptionalParent(parent);
}
@@ -200,7 +230,7 @@ namespace AZ::IO
{
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
"Attempting to set FileRequest to 'Wait', but another task was already assigned.");
m_command.emplace<WaitData>();
m_command.emplace<Requests::WaitData>();
SetOptionalParent(parent);
}
@@ -208,21 +238,21 @@ namespace AZ::IO
{
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
"Attempting to set FileRequest to 'FileExistsCheck', but another task was already assigned.");
m_command.emplace<FileExistsCheckData>(path);
m_command.emplace<Requests::FileExistsCheckData>(path);
}
void FileRequest::CreateFileMetaDataRetrieval(const RequestPath& path)
{
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
"Attempting to set FileRequest to 'FileMetaDataRetrieval', but another task was already assigned.");
m_command.emplace<FileMetaDataRetrievalData>(path);
m_command.emplace<Requests::FileMetaDataRetrievalData>(path);
}
void FileRequest::CreateCancel(FileRequestPtr target)
{
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
"Attempting to set FileRequest to 'Cancel', but another task was already assigned.");
m_command.emplace<CancelData>(AZStd::move(target));
m_command.emplace<Requests::CancelData>(AZStd::move(target));
}
void FileRequest::CreateReschedule(FileRequestPtr target, AZStd::chrono::system_clock::time_point newDeadline,
@@ -230,28 +260,28 @@ namespace AZ::IO
{
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
"Attempting to set FileRequest to 'Reschedule', but another task was already assigned.");
m_command.emplace<RescheduleData>(AZStd::move(target), newDeadline, newPriority);
m_command.emplace<Requests::RescheduleData>(AZStd::move(target), newDeadline, newPriority);
}
void FileRequest::CreateFlush(RequestPath path)
{
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
"Attempting to set FileRequest to 'Flush', but another task was already assigned.");
m_command.emplace<FlushData>(AZStd::move(path));
m_command.emplace<Requests::FlushData>(AZStd::move(path));
}
void FileRequest::CreateFlushAll()
{
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
"Attempting to set FileRequest to 'FlushAll', but another task was already assigned.");
m_command.emplace<FlushAllData>();
m_command.emplace<Requests::FlushAllData>();
}
void FileRequest::CreateDedicatedCacheCreation(RequestPath path, const FileRange& range, FileRequest* parent)
{
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
"Attempting to set FileRequest to 'CreateDedicateCache', but another task was already assigned.");
m_command.emplace<CreateDedicatedCacheData>(AZStd::move(path), range);
m_command.emplace<Requests::CreateDedicatedCacheData>(AZStd::move(path), range);
SetOptionalParent(parent);
}
@@ -259,22 +289,22 @@ namespace AZ::IO
{
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
"Attempting to set FileRequest to 'DestroyDedicateCache', but another task was already assigned.");
m_command.emplace<DestroyDedicatedCacheData>(AZStd::move(path), range);
m_command.emplace<Requests::DestroyDedicatedCacheData>(AZStd::move(path), range);
SetOptionalParent(parent);
}
void FileRequest::CreateReport(ReportData::ReportType reportType)
void FileRequest::CreateReport(Requests::ReportType reportType)
{
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
"Attempting to set FileRequest to 'Report', but another task was already assigned.");
m_command.emplace<ReportData>(reportType);
m_command.emplace<Requests::ReportData>(reportType);
}
void FileRequest::CreateCustom(AZStd::any data, bool failWhenUnhandled, FileRequest* parent)
{
AZ_Assert(AZStd::holds_alternative<AZStd::monostate>(m_command),
"Attempting to set FileRequest to 'Custom', but another task was already assigned.");
m_command.emplace<CustomData>(AZStd::move(data), failWhenUnhandled);
m_command.emplace<Requests::CustomData>(AZStd::move(data), failWhenUnhandled);
SetOptionalParent(parent);
}
@@ -361,7 +391,7 @@ namespace AZ::IO
"Request does not contain a valid command. It may have been reset already or was never assigned a command.");
return true;
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::CustomData>)
else if constexpr (AZStd::is_same_v<Command, Requests::CustomData>)
{
return args.m_failWhenUnhandled;
}
@@ -398,7 +428,7 @@ namespace AZ::IO
const FileRequest* current = this;
while (current)
{
auto* link = AZStd::get_if<ExternalRequestData>(&current->m_command);
auto* link = AZStd::get_if<Requests::ExternalRequestData>(&current->m_command);
if (!link)
{
current = current->m_parent;
@@ -27,7 +27,252 @@ namespace AZ::IO
class ExternalFileRequest;
using FileRequestPtr = AZStd::intrusive_ptr<ExternalFileRequest>;
} // namespace AZ::IO
namespace AZ::IO::Requests
{
//! Request to read data. This is a translated request and holds an absolute path and has been
//! resolved to the archive file if needed.
struct ReadData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium;
inline constexpr static bool s_failWhenUnhandled = true;
ReadData(void* output, u64 outputSize, const RequestPath& path, u64 offset, u64 size, bool sharedRead);
const RequestPath& m_path; //!< The path to the file that contains the requested data.
void* m_output; //!< Target output to write the read data to.
u64 m_outputSize; //!< Size of memory m_output points to. This needs to be at least as big as m_size, but can be bigger.
u64 m_offset; //!< The offset in bytes into the file.
u64 m_size; //!< The number of bytes to read from the file.
bool m_sharedRead; //!< True if other code will be reading from the file or the stack entry can exclusively lock.
};
//! Request to read data. This is an untranslated request and holds a relative path. The Scheduler
//! will translate this to the appropriate ReadData or CompressedReadData.
struct ReadRequestData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium;
inline constexpr static bool s_failWhenUnhandled = true;
ReadRequestData(
RequestPath path,
void* output,
u64 outputSize,
u64 offset,
u64 size,
AZStd::chrono::system_clock::time_point deadline,
IStreamerTypes::Priority priority);
ReadRequestData(
RequestPath path,
IStreamerTypes::RequestMemoryAllocator* allocator,
u64 offset,
u64 size,
AZStd::chrono::system_clock::time_point deadline,
IStreamerTypes::Priority priority);
~ReadRequestData();
RequestPath m_path; //!< Relative path to the target file.
IStreamerTypes::RequestMemoryAllocator* m_allocator; //!< Allocator used to manage the memory for this request.
AZStd::chrono::system_clock::time_point m_deadline; //!< Time by which this request should have been completed.
void* m_output; //!< The memory address assigned (during processing) to store the read data to.
u64 m_outputSize; //!< The memory size of the addressed used to store the read data.
u64 m_offset; //!< The offset in bytes into the file.
u64 m_size; //!< The number of bytes to read from the file.
IStreamerTypes::Priority m_priority; //!< Priority used for ordering requests. This is used when requests have the same deadline.
IStreamerTypes::MemoryType m_memoryType; //!< The type of memory provided by the allocator if used.
};
//! Creates a cache dedicated to a single file. This is best used for files where blocks are read from
//! periodically such as audio banks of video files.
struct CreateDedicatedCacheData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh;
inline constexpr static bool s_failWhenUnhandled = false;
CreateDedicatedCacheData(RequestPath path, const FileRange& range);
RequestPath m_path;
FileRange m_range;
};
//! Destroys a cache dedicated to a single file that was previously created by CreateDedicatedCache
struct DestroyDedicatedCacheData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh;
inline constexpr static bool s_failWhenUnhandled = false;
DestroyDedicatedCacheData(RequestPath path, const FileRange& range);
RequestPath m_path;
FileRange m_range;
};
enum class ReportType : int8_t
{
FileLocks
};
struct ReportData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityLow;
inline constexpr static bool s_failWhenUnhandled = false;
explicit ReportData(ReportType reportType);
ReportType m_reportType;
};
//! Stores a reference to the external request so it stays alive while the request is being processed.
//! This is needed because Streamer supports fire-and-forget requests since completion can be handled by
//! registering a callback.
struct ExternalRequestData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium;
inline constexpr static bool s_failWhenUnhandled = true;
explicit ExternalRequestData(FileRequestPtr&& request);
FileRequestPtr m_request; //!< The request that was send to Streamer.
};
//! Stores an instance of a RequestPath. To reduce copying instances of a RequestPath functions that
//! need a path take them by reference to the original request. In some cases a path originates from
//! within in the stack and temporary storage is needed. This struct allows for that temporary storage
//! so it can be safely referenced later.
struct RequestPathStoreData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium;
inline constexpr static bool s_failWhenUnhandled = true;
explicit RequestPathStoreData(RequestPath path);
RequestPath m_path;
};
//! Request to read and decompress data.
struct CompressedReadData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium;
inline constexpr static bool s_failWhenUnhandled = true;
CompressedReadData(CompressionInfo&& compressionInfo, void* output, u64 readOffset, u64 readSize);
CompressionInfo m_compressionInfo;
void* m_output; //!< Target output to write the read data to.
u64 m_readOffset; //!< The offset into the decompressed to start copying from.
u64 m_readSize; //!< Number of bytes to read from the decompressed file.
};
//! Holds the progress of an operation chain until this request is explicitly completed.
struct WaitData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium;
inline constexpr static bool s_failWhenUnhandled = true;
};
//! Checks to see if any node in the stack can find a file at the provided path.
struct FileExistsCheckData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh;
inline constexpr static bool s_failWhenUnhandled = false;
explicit FileExistsCheckData(const RequestPath& path);
const RequestPath& m_path;
bool m_found{ false };
};
//! Searches for a file in the stack and retrieves the meta data. This may be slower than a file exists
//! check.
struct FileMetaDataRetrievalData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh;
inline constexpr static bool s_failWhenUnhandled = false;
explicit FileMetaDataRetrievalData(const RequestPath& path);
const RequestPath& m_path;
u64 m_fileSize{ 0 };
bool m_found{ false };
};
//! Cancels a request in the stream stack, if possible.
struct CancelData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHighest;
inline constexpr static bool s_failWhenUnhandled = false;
explicit CancelData(FileRequestPtr target);
FileRequestPtr m_target; //!< The request that will be canceled.
};
//! Updates the priority and deadline of a request that has not been queued yet.
struct RescheduleData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh;
inline constexpr static bool s_failWhenUnhandled = false;
RescheduleData(FileRequestPtr target, AZStd::chrono::system_clock::time_point newDeadline, IStreamerTypes::Priority newPriority);
FileRequestPtr m_target; //!< The request that will be rescheduled.
AZStd::chrono::system_clock::time_point m_newDeadline; //!< The new deadline for the request.
IStreamerTypes::Priority m_newPriority; //!< The new priority for the request.
};
//! Flushes all references to the provided file in the streaming stack.
struct FlushData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh;
inline constexpr static bool s_failWhenUnhandled = false;
explicit FlushData(RequestPath path);
RequestPath m_path;
};
//! Flushes all caches in the streaming stack.
struct FlushAllData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh;
inline constexpr static bool s_failWhenUnhandled = false;
};
//! Data for a custom command. This can be used by nodes added extensions that need data that can't be stored
//! in the already provided data.
struct CustomData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium;
CustomData(AZStd::any data, bool failWhenUnhandled);
AZStd::any m_data; //!< The data for the custom request.
bool m_failWhenUnhandled; //!< Whether or not the request is marked as failed or success when no node process it.
};
using CommandVariant = AZStd::variant<
AZStd::monostate,
ExternalRequestData,
RequestPathStoreData,
ReadRequestData,
ReadData,
CompressedReadData,
WaitData,
FileExistsCheckData,
FileMetaDataRetrievalData,
CancelData,
RescheduleData,
FlushData,
FlushAllData,
CreateDedicatedCacheData,
DestroyDedicatedCacheData,
ReportData,
CustomData>;
} // namespace AZ::IO::Requests
namespace AZ::IO
{
class FileRequest final
{
public:
@@ -36,218 +281,7 @@ namespace AZ::IO
friend class StreamerContext;
friend class ExternalFileRequest;
//! Stores a reference to the external request so it stays alive while the request is being processed.
//! This is needed because Streamer supports fire-and-forget requests since completion can be handled by
//! registering a callback.
struct ExternalRequestData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium;
inline constexpr static bool s_failWhenUnhandled = true;
explicit ExternalRequestData(FileRequestPtr&& request);
FileRequestPtr m_request; //!< The request that was send to Streamer.
};
//! Stores an instance of a RequestPath. To reduce copying instances of a RequestPath functions that
//! need a path take them by reference to the original request. In some cases a path originates from
//! within in the stack and temporary storage is needed. This struct allows for that temporary storage
//! so it can be safely referenced later.
struct RequestPathStoreData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium;
inline constexpr static bool s_failWhenUnhandled = true;
explicit RequestPathStoreData(RequestPath path);
RequestPath m_path;
};
//! Request to read data. This is an untranslated request and holds a relative path. The Scheduler
//! will translate this to the appropriate ReadData or CompressedReadData.
struct ReadRequestData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium;
inline constexpr static bool s_failWhenUnhandled = true;
ReadRequestData(RequestPath path, void* output, u64 outputSize, u64 offset, u64 size,
AZStd::chrono::system_clock::time_point deadline, IStreamerTypes::Priority priority);
ReadRequestData(RequestPath path, IStreamerTypes::RequestMemoryAllocator* allocator, u64 offset, u64 size,
AZStd::chrono::system_clock::time_point deadline, IStreamerTypes::Priority priority);
~ReadRequestData();
RequestPath m_path; //!< Relative path to the target file.
IStreamerTypes::RequestMemoryAllocator* m_allocator; //!< Allocator used to manage the memory for this request.
AZStd::chrono::system_clock::time_point m_deadline; //!< Time by which this request should have been completed.
void* m_output; //!< The memory address assigned (during processing) to store the read data to.
u64 m_outputSize; //!< The memory size of the addressed used to store the read data.
u64 m_offset; //!< The offset in bytes into the file.
u64 m_size; //!< The number of bytes to read from the file.
IStreamerTypes::Priority m_priority; //!< Priority used for ordering requests. This is used when requests have the same deadline.
IStreamerTypes::MemoryType m_memoryType; //!< The type of memory provided by the allocator if used.
};
//! Request to read data. This is a translated request and holds an absolute path and has been
//! resolved to the archive file if needed.
struct ReadData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium;
inline constexpr static bool s_failWhenUnhandled = true;
ReadData(void* output, u64 outputSize, const RequestPath& path, u64 offset, u64 size, bool sharedRead);
const RequestPath& m_path; //!< The path to the file that contains the requested data.
void* m_output; //!< Target output to write the read data to.
u64 m_outputSize; //!< Size of memory m_output points to. This needs to be at least as big as m_size, but can be bigger.
u64 m_offset; //!< The offset in bytes into the file.
u64 m_size; //!< The number of bytes to read from the file.
bool m_sharedRead; //!< True if other code will be reading from the file or the stack entry can exclusively lock.
};
//! Request to read and decompress data.
struct CompressedReadData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium;
inline constexpr static bool s_failWhenUnhandled = true;
CompressedReadData(CompressionInfo&& compressionInfo, void* output, u64 readOffset, u64 readSize);
CompressionInfo m_compressionInfo;
void* m_output; //!< Target output to write the read data to.
u64 m_readOffset; //!< The offset into the decompressed to start copying from.
u64 m_readSize; //!< Number of bytes to read from the decompressed file.
};
//! Holds the progress of an operation chain until this request is explicitly completed.
struct WaitData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium;
inline constexpr static bool s_failWhenUnhandled = true;
};
//! Checks to see if any node in the stack can find a file at the provided path.
struct FileExistsCheckData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh;
inline constexpr static bool s_failWhenUnhandled = false;
explicit FileExistsCheckData(const RequestPath& path);
const RequestPath& m_path;
bool m_found{ false };
};
//! Searches for a file in the stack and retrieves the meta data. This may be slower than a file exists
//! check.
struct FileMetaDataRetrievalData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh;
inline constexpr static bool s_failWhenUnhandled = false;
explicit FileMetaDataRetrievalData(const RequestPath& path);
const RequestPath& m_path;
u64 m_fileSize{ 0 };
bool m_found{ false };
};
//! Cancels a request in the stream stack, if possible.
struct CancelData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHighest;
inline constexpr static bool s_failWhenUnhandled = false;
explicit CancelData(FileRequestPtr target);
FileRequestPtr m_target; //!< The request that will be canceled.
};
//! Updates the priority and deadline of a request that has not been queued yet.
struct RescheduleData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh;
inline constexpr static bool s_failWhenUnhandled = false;
RescheduleData(FileRequestPtr target, AZStd::chrono::system_clock::time_point newDeadline, IStreamerTypes::Priority newPriority);
FileRequestPtr m_target; //!< The request that will be rescheduled.
AZStd::chrono::system_clock::time_point m_newDeadline; //!< The new deadline for the request.
IStreamerTypes::Priority m_newPriority; //!< The new priority for the request.
};
//! Flushes all references to the provided file in the streaming stack.
struct FlushData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh;
inline constexpr static bool s_failWhenUnhandled = false;
explicit FlushData(RequestPath path);
RequestPath m_path;
};
//! Flushes all caches in the streaming stack.
struct FlushAllData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh;
inline constexpr static bool s_failWhenUnhandled = false;
};
//! Creates a cache dedicated to a single file. This is best used for files where blocks are read from
//! periodically such as audio banks of video files.
struct CreateDedicatedCacheData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh;
inline constexpr static bool s_failWhenUnhandled = false;
CreateDedicatedCacheData(RequestPath path, const FileRange& range);
RequestPath m_path;
FileRange m_range;
};
//! Destroys a cache dedicated to a single file that was previously created by CreateDedicatedCache
struct DestroyDedicatedCacheData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityHigh;
inline constexpr static bool s_failWhenUnhandled = false;
DestroyDedicatedCacheData(RequestPath path, const FileRange& range);
RequestPath m_path;
FileRange m_range;
};
struct ReportData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityLow;
inline constexpr static bool s_failWhenUnhandled = false;
enum class ReportType
{
FileLocks
};
explicit ReportData(ReportType reportType);
ReportType m_reportType;
};
//! Data for a custom command. This can be used by nodes added extensions that need data that can't be stored
//! in the already provided data.
struct CustomData
{
inline constexpr static IStreamerTypes::Priority s_orderPriority = IStreamerTypes::s_priorityMedium;
CustomData(AZStd::any data, bool failWhenUnhandled);
AZStd::any m_data; //!< The data for the custom request.
bool m_failWhenUnhandled; //!< Whether or not the request is marked as failed or success when no node process it.
};
using CommandVariant = AZStd::variant<AZStd::monostate, ExternalRequestData, RequestPathStoreData, ReadRequestData, ReadData,
CompressedReadData, WaitData, FileExistsCheckData, FileMetaDataRetrievalData, CancelData, RescheduleData, FlushData,
FlushAllData, CreateDedicatedCacheData, DestroyDedicatedCacheData, ReportData, CustomData>;
using CommandVariant = Requests::CommandVariant;
using OnCompletionCallback = AZStd::function<void(FileRequest& request)>;
AZ_CLASS_ALLOCATOR(FileRequest, SystemAllocator, 0);
@@ -278,7 +312,7 @@ namespace AZ::IO
void CreateFlushAll();
void CreateDedicatedCacheCreation(RequestPath path, const FileRange& range = {}, FileRequest* parent = nullptr);
void CreateDedicatedCacheDestruction(RequestPath path, const FileRange& range = {}, FileRequest* parent = nullptr);
void CreateReport(ReportData::ReportType reportType);
void CreateReport(Requests::ReportType reportType);
void CreateCustom(AZStd::any data, bool failWhenUnhandled = true, FileRequest* parent = nullptr);
void SetCompletionCallback(OnCompletionCallback callback);
@@ -325,8 +359,17 @@ namespace AZ::IO
//! Command and parameters for the request.
CommandVariant m_command;
//! Status of the request.
AZStd::atomic<IStreamerTypes::RequestStatus> m_status{ IStreamerTypes::RequestStatus::Pending };
//! Estimated time this request will complete. This is an estimation and depends on many
//! factors which can cause it to change drastically from moment to moment.
AZStd::chrono::system_clock::time_point m_estimatedCompletion;
//! The file request that has a dependency on this one. This can be null if there are no
//! other request depending on this one to complete.
FileRequest* m_parent{ nullptr };
//! Id assigned when the request is added to the pending queue.
size_t m_pendingId{ 0 };
//! Called once the request has completed. This will always be called from the Streamer thread
//! and thread safety is the responsibility of called function. When assigning a lambda avoid
@@ -336,16 +379,8 @@ namespace AZ::IO
//! a longer running task is needed consider using a job to do the work.
OnCompletionCallback m_onCompletion;
//! Estimated time this request will complete. This is an estimation and depends on many
//! factors which can cause it to change drastically from moment to moment.
AZStd::chrono::system_clock::time_point m_estimatedCompletion;
//! The file request that has a dependency on this one. This can be null if there are no
//! other request depending on this one to complete.
FileRequest* m_parent{ nullptr };
//! Id assigned when the request is added to the pending queue.
size_t m_pendingId{ 0 };
//! Status of the request.
AZStd::atomic<IStreamerTypes::RequestStatus> m_status{ IStreamerTypes::RequestStatus::Pending };
//! The number of dependent file request that need to complete before this one is done.
u16 m_dependencies{ 0 };
@@ -91,12 +91,12 @@ namespace AZ::IO
AZStd::visit([this, request](auto&& args)
{
using Command = AZStd::decay_t<decltype(args)>;
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadRequestData>)
if constexpr (AZStd::is_same_v<Command, Requests::ReadRequestData>)
{
PrepareReadRequest(request, args);
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::CreateDedicatedCacheData> ||
AZStd::is_same_v<Command, FileRequest::DestroyDedicatedCacheData>)
else if constexpr (AZStd::is_same_v<Command, Requests::CreateDedicatedCacheData> ||
AZStd::is_same_v<Command, Requests::DestroyDedicatedCacheData>)
{
PrepareDedicatedCache(request, args.m_path);
}
@@ -114,11 +114,11 @@ namespace AZ::IO
AZStd::visit([this, request](auto&& args)
{
using Command = AZStd::decay_t<decltype(args)>;
if constexpr (AZStd::is_same_v<Command, FileRequest::CompressedReadData>)
if constexpr (AZStd::is_same_v<Command, Requests::CompressedReadData>)
{
m_pendingReads.push_back(request);
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::FileExistsCheckData>)
else if constexpr (AZStd::is_same_v<Command, Requests::FileExistsCheckData>)
{
m_pendingFileExistChecks.push_back(request);
}
@@ -203,7 +203,7 @@ namespace AZ::IO
{
FileRequest* compressedRequest = m_processingJobs[i].m_waitRequest->GetParent();
AZ_Assert(compressedRequest, "A wait request attached to FullFileDecompressor was completed but didn't have a parent compressed request.");
auto data = AZStd::get_if<FileRequest::CompressedReadData>(&compressedRequest->GetCommand());
auto data = AZStd::get_if<Requests::CompressedReadData>(&compressedRequest->GetCommand());
AZ_Assert(data, "Compressed request in the decompression queue in FullFileDecompressor didn't contain compression read data.");
size_t bytesToDecompress = data->m_compressionInfo.m_compressedSize;
@@ -255,7 +255,7 @@ namespace AZ::IO
// Calculate the amount of time it will take to decompress the data.
FileRequest* compressedRequest = m_readRequests[i]->GetParent();
auto data = AZStd::get_if<FileRequest::CompressedReadData>(&compressedRequest->GetCommand());
auto data = AZStd::get_if<Requests::CompressedReadData>(&compressedRequest->GetCommand());
size_t bytesToDecompress = data->m_compressionInfo.m_compressedSize;
auto decompressionDuration = AZStd::chrono::microseconds(
@@ -290,7 +290,7 @@ namespace AZ::IO
void FullFileDecompressor::EstimateCompressedReadRequest(FileRequest* request, AZStd::chrono::microseconds& cumulativeDelay,
AZStd::chrono::microseconds decompressionDelay, double totalDecompressionDurationUs, double totalBytesDecompressed) const
{
auto data = AZStd::get_if<FileRequest::CompressedReadData>(&request->GetCommand());
auto data = AZStd::get_if<Requests::CompressedReadData>(&request->GetCommand());
if (data)
{
AZStd::chrono::microseconds processingTime = decompressionDelay;
@@ -343,7 +343,7 @@ namespace AZ::IO
m_numRunningJobs == 0;
}
void FullFileDecompressor::PrepareReadRequest(FileRequest* request, FileRequest::ReadRequestData& data)
void FullFileDecompressor::PrepareReadRequest(FileRequest* request, Requests::ReadRequestData& data)
{
CompressionInfo info;
if (CompressionUtils::FindCompressionInfo(info, data.m_path.GetRelativePath()))
@@ -359,7 +359,7 @@ namespace AZ::IO
{
FileRequest* pathStorageRequest = m_context->GetNewInternalRequest();
pathStorageRequest->CreateRequestPathStore(request, AZStd::move(info.m_archiveFilename));
auto& pathStorage = AZStd::get<FileRequest::RequestPathStoreData>(pathStorageRequest->GetCommand());
auto& pathStorage = AZStd::get<Requests::RequestPathStoreData>(pathStorageRequest->GetCommand());
nextRequest->CreateRead(pathStorageRequest, data.m_output, data.m_outputSize, pathStorage.m_path,
info.m_offset + data.m_offset, data.m_size, info.m_isSharedPak);
@@ -370,13 +370,13 @@ namespace AZ::IO
auto callback = [this, nextRequest](const FileRequest& checkRequest)
{
AZ_PROFILE_FUNCTION(AzCore);
auto check = AZStd::get_if<FileRequest::FileExistsCheckData>(&checkRequest.GetCommand());
auto check = AZStd::get_if<Requests::FileExistsCheckData>(&checkRequest.GetCommand());
AZ_Assert(check,
"Callback in FullFileDecompressor::PrepareReadRequest expected FileExistsCheck but got another command.");
if (check->m_found)
{
FileRequest* originalRequest = m_context->RejectRequest(nextRequest);
if (AZStd::holds_alternative<FileRequest::RequestPathStoreData>(originalRequest->GetCommand()))
if (AZStd::holds_alternative<Requests::RequestPathStoreData>(originalRequest->GetCommand()))
{
originalRequest = m_context->RejectRequest(originalRequest);
}
@@ -412,12 +412,12 @@ namespace AZ::IO
AZStd::visit([request, &info, nextRequest](auto&& args)
{
using Command = AZStd::decay_t<decltype(args)>;
if constexpr (AZStd::is_same_v<Command, FileRequest::CreateDedicatedCacheData>)
if constexpr (AZStd::is_same_v<Command, Requests::CreateDedicatedCacheData>)
{
nextRequest->CreateDedicatedCacheCreation(AZStd::move(info.m_archiveFilename),
FileRange::CreateRange(info.m_offset, info.m_compressedSize), request);
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::DestroyDedicatedCacheData>)
else if constexpr (AZStd::is_same_v<Command, Requests::DestroyDedicatedCacheData>)
{
nextRequest->CreateDedicatedCacheDestruction(AZStd::move(info.m_archiveFilename),
FileRange::CreateRange(info.m_offset, info.m_compressedSize), request);
@@ -429,7 +429,7 @@ namespace AZ::IO
auto callback = [this, nextRequest](const FileRequest& checkRequest)
{
AZ_PROFILE_FUNCTION(AzCore);
auto check = AZStd::get_if<FileRequest::FileExistsCheckData>(&checkRequest.GetCommand());
auto check = AZStd::get_if<Requests::FileExistsCheckData>(&checkRequest.GetCommand());
AZ_Assert(check,
"Callback in FullFileDecompressor::PrepareDedicatedCache expected FileExistsCheck but got another command.");
if (check->m_found)
@@ -461,7 +461,7 @@ namespace AZ::IO
void FullFileDecompressor::FileExistsCheck(FileRequest* checkRequest)
{
auto& fileCheckRequest = AZStd::get<FileRequest::FileExistsCheckData>(checkRequest->GetCommand());
auto& fileCheckRequest = AZStd::get<Requests::FileExistsCheckData>(checkRequest->GetCommand());
CompressionInfo info;
if (CompressionUtils::FindCompressionInfo(info, fileCheckRequest.m_path.GetRelativePath()))
{
@@ -487,7 +487,7 @@ namespace AZ::IO
{
if (m_readBufferStatus[i] == ReadBufferStatus::Unused)
{
auto data = AZStd::get_if<FileRequest::CompressedReadData>(&compressedReadRequest->GetCommand());
auto data = AZStd::get_if<Requests::CompressedReadData>(&compressedReadRequest->GetCommand());
AZ_Assert(data, "Compressed request that's starting a read in FullFileDecompressor didn't contain compression read data.");
AZ_Assert(data->m_compressionInfo.m_decompressor,
"FileRequest for FullFileDecompressor is missing a decompression callback.");
@@ -549,7 +549,7 @@ namespace AZ::IO
}
else
{
auto data = AZStd::get_if<FileRequest::CompressedReadData>(&compressedRequest->GetCommand());
auto data = AZStd::get_if<Requests::CompressedReadData>(&compressedRequest->GetCommand());
AZ_Assert(data, "Compressed request in FullFileDecompressor that finished unsuccessfully didn't contain compression read data.");
CompressionInfo& info = data->m_compressionInfo;
size_t offsetAdjustment = info.m_offset - AZ_SIZE_ALIGN_DOWN(info.m_offset, aznumeric_cast<size_t>(m_alignment));
@@ -591,7 +591,7 @@ namespace AZ::IO
}
FileRequest* waitRequest = m_readRequests[readSlot];
AZ_Assert(AZStd::holds_alternative<FileRequest::WaitData>(waitRequest->GetCommand()),
AZ_Assert(AZStd::holds_alternative<Requests::WaitData>(waitRequest->GetCommand()),
"File request waiting for decompression wasn't marked as being a wait operation.");
FileRequest* compressedRequest = waitRequest->GetParent();
AZ_Assert(compressedRequest, "Read requests started by FullFileDecompressor is missing a parent request.");
@@ -610,7 +610,7 @@ namespace AZ::IO
m_readBuffers[readSlot] = nullptr;
AZ::Job* decompressionJob;
auto data = AZStd::get_if<FileRequest::CompressedReadData>(&compressedRequest->GetCommand());
auto data = AZStd::get_if<Requests::CompressedReadData>(&compressedRequest->GetCommand());
AZ_Assert(data, "Compressed request in FullFileDecompressor that's starting decompression didn't contain compression read data.");
AZ_Assert(data->m_compressionInfo.m_decompressor, "FullFileDecompressor is queuing a decompression job but couldn't find a decompressor.");
@@ -664,7 +664,7 @@ namespace AZ::IO
FileRequest* compressedRequest = jobInfo.m_waitRequest->GetParent();
AZ_Assert(compressedRequest, "A wait request attached to FullFileDecompressor was completed but didn't have a parent compressed request.");
auto data = AZStd::get_if<FileRequest::CompressedReadData>(&compressedRequest->GetCommand());
auto data = AZStd::get_if<Requests::CompressedReadData>(&compressedRequest->GetCommand());
AZ_Assert(data, "Compressed request in FullFileDecompressor that completed decompression didn't contain compression read data.");
CompressionInfo& info = data->m_compressionInfo;
size_t offsetAdjustment = info.m_offset - AZ_SIZE_ALIGN_DOWN(info.m_offset, aznumeric_cast<size_t>(m_alignment));
@@ -694,7 +694,7 @@ namespace AZ::IO
FileRequest* compressedRequest = info.m_waitRequest->GetParent();
AZ_Assert(compressedRequest, "A wait request attached to FullFileDecompressor was completed but didn't have a parent compressed request.");
auto request = AZStd::get_if<FileRequest::CompressedReadData>(&compressedRequest->GetCommand());
auto request = AZStd::get_if<Requests::CompressedReadData>(&compressedRequest->GetCommand());
AZ_Assert(request, "Compressed request in FullFileDecompressor that's running full decompression didn't contain compression read data.");
CompressionInfo& compressionInfo = request->m_compressionInfo;
AZ_Assert(compressionInfo.m_decompressor, "Full decompressor job started, but there's no decompressor callback assigned.");
@@ -719,7 +719,7 @@ namespace AZ::IO
FileRequest* compressedRequest = info.m_waitRequest->GetParent();
AZ_Assert(compressedRequest, "A wait request attached to FullFileDecompressor was completed but didn't have a parent compressed request.");
auto request = AZStd::get_if<FileRequest::CompressedReadData>(&compressedRequest->GetCommand());
auto request = AZStd::get_if<Requests::CompressedReadData>(&compressedRequest->GetCommand());
AZ_Assert(request, "Compressed request in FullFileDecompressor that's running partial decompression didn't contain compression read data.");
CompressionInfo& compressionInfo = request->m_compressionInfo;
AZ_Assert(compressionInfo.m_decompressor, "Partial decompressor job started, but there's no decompressor callback assigned.");
@@ -21,6 +21,11 @@
namespace AZ::IO
{
namespace Requests
{
struct ReadRequestData;
}
struct FullFileDecompressorConfig final :
public IStreamerStackConfig
{
@@ -87,7 +92,7 @@ namespace AZ::IO
bool IsIdle() const;
void PrepareReadRequest(FileRequest* request, FileRequest::ReadRequestData& data);
void PrepareReadRequest(FileRequest* request, Requests::ReadRequestData& data);
void PrepareDedicatedCache(FileRequest* request, const RequestPath& path);
void FileExistsCheck(FileRequest* checkRequest);
@@ -118,7 +118,7 @@ namespace AZ::IO
return;
}
auto data = AZStd::get_if<FileRequest::ReadData>(&request->GetCommand());
auto data = AZStd::get_if<Requests::ReadData>(&request->GetCommand());
if (data == nullptr)
{
StreamStackEntry::QueueRequest(request);
@@ -156,7 +156,7 @@ namespace AZ::IO
void ReadSplitter::QueueAlignedRead(FileRequest* request)
{
auto data = AZStd::get_if<FileRequest::ReadData>(&request->GetCommand());
auto data = AZStd::get_if<Requests::ReadData>(&request->GetCommand());
AZ_Assert(data != nullptr, "Provided request to queue by the Read Splitter did not contain a read command.");
if (data->m_size <= m_maxReadSize)
@@ -187,7 +187,7 @@ namespace AZ::IO
bool ReadSplitter::QueueAlignedRead(PendingRead& pending)
{
auto data = AZStd::get_if<FileRequest::ReadData>(&pending.m_request->GetCommand());
auto data = AZStd::get_if<Requests::ReadData>(&pending.m_request->GetCommand());
AZ_Assert(data != nullptr, "Provided request to queue by the Read Splitter did not contain a read command.");
while (pending.m_readSize > 0)
@@ -237,7 +237,7 @@ namespace AZ::IO
void ReadSplitter::QueueBufferedRead(FileRequest* request)
{
auto data = AZStd::get_if<FileRequest::ReadData>(&request->GetCommand());
auto data = AZStd::get_if<Requests::ReadData>(&request->GetCommand());
AZ_Assert(data != nullptr, "Provided request to queue by the Read Splitter did not contain a read command.");
PendingRead pendingRead;
@@ -262,7 +262,7 @@ namespace AZ::IO
bool ReadSplitter::QueueBufferedRead(PendingRead& pending)
{
auto data = AZStd::get_if<FileRequest::ReadData>(&pending.m_request->GetCommand());
auto data = AZStd::get_if<Requests::ReadData>(&pending.m_request->GetCommand());
AZ_Assert(data != nullptr, "Provided request to queue by the Read Splitter did not contain a read command.");
while (pending.m_readSize > 0)
@@ -6,9 +6,11 @@
*
*/
#include <AzCore/IO/Streamer/Scheduler.h>
#include <AzCore/Casting/numeric_cast.h>
#include <AzCore/Debug/Profiler.h>
#include <AzCore/IO/Streamer/Scheduler.h>
#include <AzCore/IO/Streamer/FileRequest.h>
#include <AzCore/std/containers/deque.h>
#include <AzCore/std/sort.h>
@@ -35,6 +37,8 @@ namespace AZ::IO
m_threadData.m_streamStack = AZStd::move(streamStack);
}
Scheduler::~Scheduler() = default;
void Scheduler::Start(const AZStd::thread_desc& threadDesc)
{
if (!m_isRunning)
@@ -222,10 +226,10 @@ namespace AZ::IO
{
using Command = AZStd::decay_t<decltype(args)>;
if constexpr (
AZStd::is_same_v<Command, FileRequest::ReadData> ||
AZStd::is_same_v<Command, FileRequest::CompressedReadData>)
AZStd::is_same_v<Command, Requests::ReadData> ||
AZStd::is_same_v<Command, Requests::CompressedReadData>)
{
auto parentReadRequest = next->GetCommandFromChain<FileRequest::ReadRequestData>();
auto parentReadRequest = next->GetCommandFromChain<Requests::ReadRequestData>();
AZ_Assert(parentReadRequest != nullptr, "The issued read request can't be found for the (compressed) read command.");
size_t size = parentReadRequest->m_size;
@@ -234,7 +238,7 @@ namespace AZ::IO
AZ_Assert(parentReadRequest->m_allocator,
"The read request was issued without a memory allocator or valid output address.");
u64 recommendedSize = size;
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadData>)
if constexpr (AZStd::is_same_v<Command, Requests::ReadData>)
{
recommendedSize = m_recommendations.CalculateRecommendedMemorySize(size, parentReadRequest->m_offset);
}
@@ -249,12 +253,12 @@ namespace AZ::IO
parentReadRequest->m_output = allocation.m_address;
parentReadRequest->m_outputSize = allocation.m_size;
parentReadRequest->m_memoryType = allocation.m_type;
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadData>)
if constexpr (AZStd::is_same_v<Command, Requests::ReadData>)
{
args.m_output = parentReadRequest->m_output;
args.m_outputSize = allocation.m_size;
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::CompressedReadData>)
else if constexpr (AZStd::is_same_v<Command, Requests::CompressedReadData>)
{
args.m_output = parentReadRequest->m_output;
}
@@ -267,7 +271,7 @@ namespace AZ::IO
}
#endif
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadData>)
if constexpr (AZStd::is_same_v<Command, Requests::ReadData>)
{
m_threadData.m_lastFilePath = args.m_path;
m_threadData.m_lastFileOffset = args.m_offset + args.m_size;
@@ -275,7 +279,7 @@ namespace AZ::IO
m_processingSize += args.m_size;
#endif
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::CompressedReadData>)
else if constexpr (AZStd::is_same_v<Command, Requests::CompressedReadData>)
{
const CompressionInfo& info = args.m_compressionInfo;
m_threadData.m_lastFilePath = info.m_archiveFilename;
@@ -288,15 +292,15 @@ namespace AZ::IO
"Streamer queued %zu: %s", next->GetCommand().index(), parentReadRequest->m_path.GetRelativePath());
m_threadData.m_streamStack->QueueRequest(next);
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::CancelData>)
else if constexpr (AZStd::is_same_v<Command, Requests::CancelData>)
{
return Thread_ProcessCancelRequest(next, args);
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::RescheduleData>)
else if constexpr (AZStd::is_same_v<Command, Requests::RescheduleData>)
{
return Thread_ProcessRescheduleRequest(next, args);
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::FlushData> || AZStd::is_same_v<Command, FileRequest::FlushAllData>)
else if constexpr (AZStd::is_same_v<Command, Requests::FlushData> || AZStd::is_same_v<Command, Requests::FlushAllData>)
{
AZ_PROFILE_INTERVAL_START_COLORED(AzCore, next, ProfilerColor,
"Streamer queued %zu", next->GetCommand().index());
@@ -345,7 +349,7 @@ namespace AZ::IO
#endif
{
using Command = AZStd::decay_t<decltype(args)>;
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadRequestData>)
if constexpr (AZStd::is_same_v<Command, Requests::ReadRequestData>)
{
if (args.m_output == nullptr && args.m_allocator != nullptr)
{
@@ -393,7 +397,7 @@ namespace AZ::IO
}
}
void Scheduler::Thread_ProcessCancelRequest(FileRequest* request, FileRequest::CancelData& data)
void Scheduler::Thread_ProcessCancelRequest(FileRequest* request, Requests::CancelData& data)
{
AZ_PROFILE_INTERVAL_START_COLORED(AzCore, request, ProfilerColor, "Streamer queued cancel");
auto& pending = m_context.GetPreparedRequests();
@@ -415,7 +419,7 @@ namespace AZ::IO
m_threadData.m_streamStack->QueueRequest(request);
}
void Scheduler::Thread_ProcessRescheduleRequest(FileRequest* request, FileRequest::RescheduleData& data)
void Scheduler::Thread_ProcessRescheduleRequest(FileRequest* request, Requests::RescheduleData& data)
{
AZ_PROFILE_INTERVAL_START_COLORED(AzCore, request, ProfilerColor, "Streamer queued reschedule");
auto& pendingRequests = m_context.GetPreparedRequests();
@@ -424,7 +428,7 @@ namespace AZ::IO
if (pending->WorksOn(data.m_target))
{
// Read requests are the only requests that use deadlines and dynamic priorities.
auto readRequest = pending->GetCommandFromChain<FileRequest::ReadRequestData>();
auto readRequest = pending->GetCommandFromChain<Requests::ReadRequestData>();
if (readRequest)
{
readRequest->m_deadline = data.m_newDeadline;
@@ -463,8 +467,8 @@ namespace AZ::IO
// Order is the same for both requests, so prioritize the request that are at risk of missing
// it's deadline.
const FileRequest::ReadRequestData* firstRead = first->GetCommandFromChain<FileRequest::ReadRequestData>();
const FileRequest::ReadRequestData* secondRead = second->GetCommandFromChain<FileRequest::ReadRequestData>();
const Requests::ReadRequestData* firstRead = first->GetCommandFromChain<Requests::ReadRequestData>();
const Requests::ReadRequestData* secondRead = second->GetCommandFromChain<Requests::ReadRequestData>();
if (firstRead == nullptr || secondRead == nullptr)
{
@@ -496,11 +500,11 @@ namespace AZ::IO
auto sameFile = [this](auto&& args)
{
using Command = AZStd::decay_t<decltype(args)>;
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadData>)
if constexpr (AZStd::is_same_v<Command, Requests::ReadData>)
{
return m_threadData.m_lastFilePath == args.m_path;
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::CompressedReadData>)
else if constexpr (AZStd::is_same_v<Command, Requests::CompressedReadData>)
{
return m_threadData.m_lastFilePath == args.m_compressionInfo.m_archiveFilename;
}
@@ -517,11 +521,11 @@ namespace AZ::IO
auto offset = [](auto&& args) -> s64
{
using Command = AZStd::decay_t<decltype(args)>;
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadData>)
if constexpr (AZStd::is_same_v<Command, Requests::ReadData>)
{
return aznumeric_caster(args.m_offset);
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::CompressedReadData>)
else if constexpr (AZStd::is_same_v<Command, Requests::CompressedReadData>)
{
return aznumeric_caster(args.m_compressionInfo.m_offset);
}
@@ -8,6 +8,7 @@
#pragma once
#include <AzCore/IO/Streamer/RequestPath.h>
#include <AzCore/IO/IStreamerTypes.h>
#include <AzCore/IO/Streamer/Statistics.h>
#include <AzCore/IO/Streamer/StreamerConfiguration.h>
@@ -24,11 +25,19 @@ namespace AZ::IO
{
class FileRequest;
namespace Requests
{
struct CancelData;
struct RescheduleData;
} // namespace Requests
class Scheduler final
{
public:
explicit Scheduler(AZStd::shared_ptr<StreamStackEntry> streamStack, u64 memoryAlignment = AZCORE_GLOBAL_NEW_ALIGNMENT,
u64 sizeAlignment = 1, u64 granularity = 1_mib);
~Scheduler();
void Start(const AZStd::thread_desc& threadDesc);
void Stop();
@@ -61,14 +70,14 @@ namespace AZ::IO
bool Thread_ExecuteRequests();
bool Thread_PrepareRequests(AZStd::vector<FileRequestPtr>& outstandingRequests);
void Thread_ProcessTillIdle();
void Thread_ProcessCancelRequest(FileRequest* request, FileRequest::CancelData& data);
void Thread_ProcessRescheduleRequest(FileRequest* request, FileRequest::RescheduleData& data);
void Thread_ProcessCancelRequest(FileRequest* request, Requests::CancelData& data);
void Thread_ProcessRescheduleRequest(FileRequest* request, Requests::RescheduleData& data);
enum class Order
{
FirstRequest, //< The first request is the most important to process next.
SecondRequest, //< The second request is the most important to process next.
Equal //< Both requests are equally important.
FirstRequest, //!< The first request is the most important to process next.
SecondRequest, //!< The second request is the most important to process next.
Equal //!< Both requests are equally important.
};
//! Determine which of the two provided requests is more important to process next.
Order Thread_PrioritizeRequests(const FileRequest* first, const FileRequest* second) const;
@@ -60,13 +60,13 @@ namespace AZ::IO
AZ_PROFILE_FUNCTION(AzCore);
AZ_Assert(request, "PrepareRequest was provided a null request.");
if (AZStd::holds_alternative<FileRequest::ReadRequestData>(request->GetCommand()))
if (AZStd::holds_alternative<Requests::ReadRequestData>(request->GetCommand()))
{
auto& readRequest = AZStd::get<FileRequest::ReadRequestData>(request->GetCommand());
auto& readRequest = AZStd::get<Requests::ReadRequestData>(request->GetCommand());
FileRequest* read = m_context->GetNewInternalRequest();
read->CreateRead(request, readRequest.m_output, readRequest.m_outputSize, readRequest.m_path,
readRequest.m_offset, readRequest.m_size);
read->CreateRead(
request, readRequest.m_output, readRequest.m_outputSize, readRequest.m_path, readRequest.m_offset, readRequest.m_size);
m_context->PushPreparedRequest(read);
return;
}
@@ -79,29 +79,29 @@ namespace AZ::IO
AZStd::visit([this, request](auto&& args)
{
using Command = AZStd::decay_t<decltype(args)>;
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadData> ||
AZStd::is_same_v<Command, FileRequest::FileExistsCheckData> ||
AZStd::is_same_v<Command, FileRequest::FileMetaDataRetrievalData>)
if constexpr (AZStd::is_same_v<Command, Requests::ReadData> ||
AZStd::is_same_v<Command, Requests::FileExistsCheckData> ||
AZStd::is_same_v<Command, Requests::FileMetaDataRetrievalData>)
{
m_pendingRequests.push_back(request);
return;
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::CancelData>)
else if constexpr (AZStd::is_same_v<Command, Requests::CancelData>)
{
CancelRequest(request, args.m_target);
return;
}
else
{
if constexpr (AZStd::is_same_v<Command, FileRequest::FlushData>)
if constexpr (AZStd::is_same_v<Command, Requests::FlushData>)
{
FlushCache(args.m_path);
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::FlushAllData>)
else if constexpr (AZStd::is_same_v<Command, Requests::FlushAllData>)
{
FlushEntireCache();
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::ReportData>)
else if constexpr (AZStd::is_same_v<Command, Requests::ReportData>)
{
Report(args);
}
@@ -118,15 +118,15 @@ namespace AZ::IO
AZStd::visit([this, request](auto&& args)
{
using Command = AZStd::decay_t<decltype(args)>;
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadData>)
if constexpr (AZStd::is_same_v<Command, Requests::ReadData>)
{
ReadFile(request);
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::FileExistsCheckData>)
else if constexpr (AZStd::is_same_v<Command, Requests::FileExistsCheckData>)
{
FileExistsRequest(request);
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::FileMetaDataRetrievalData>)
else if constexpr (AZStd::is_same_v<Command, Requests::FileMetaDataRetrievalData>)
{
FileMetaDataRetrievalRequest(request);
}
@@ -199,25 +199,25 @@ namespace AZ::IO
AZStd::visit([&](auto&& args)
{
using Command = AZStd::decay_t<decltype(args)>;
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadData>)
if constexpr (AZStd::is_same_v<Command, Requests::ReadData>)
{
targetFile = &args.m_path;
readSize = args.m_size;
offset = args.m_offset;
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::CompressedReadData>)
else if constexpr (AZStd::is_same_v<Command, Requests::CompressedReadData>)
{
targetFile = &args.m_compressionInfo.m_archiveFilename;
readSize = args.m_compressionInfo.m_compressedSize;
offset = args.m_compressionInfo.m_offset;
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::FileExistsCheckData>)
else if constexpr (AZStd::is_same_v<Command, Requests::FileExistsCheckData>)
{
readSize = 0;
AZStd::chrono::microseconds averageTime = m_getFileExistsTimeAverage.CalculateAverage();
startTime += averageTime;
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::FileMetaDataRetrievalData>)
else if constexpr (AZStd::is_same_v<Command, Requests::FileMetaDataRetrievalData>)
{
readSize = 0;
AZStd::chrono::microseconds averageTime = m_getFileMetaDataTimeAverage.CalculateAverage();
@@ -254,7 +254,7 @@ namespace AZ::IO
{
AZ_PROFILE_FUNCTION(AzCore);
auto data = AZStd::get_if<FileRequest::ReadData>(&request->GetCommand());
auto data = AZStd::get_if<Requests::ReadData>(&request->GetCommand());
AZ_Assert(data, "FileRequest queued on StorageDrive to be read didn't contain read data.");
SystemFile* file = nullptr;
@@ -342,7 +342,7 @@ namespace AZ::IO
AZ_PROFILE_FUNCTION(AzCore);
TIMED_AVERAGE_WINDOW_SCOPE(m_getFileExistsTimeAverage);
auto& fileExists = AZStd::get<FileRequest::FileExistsCheckData>(request->GetCommand());
auto& fileExists = AZStd::get<Requests::FileExistsCheckData>(request->GetCommand());
size_t cacheIndex = FindFileInCache(fileExists.m_path);
if (cacheIndex != s_fileNotFound)
{
@@ -360,7 +360,7 @@ namespace AZ::IO
AZ_PROFILE_FUNCTION(AzCore);
TIMED_AVERAGE_WINDOW_SCOPE(m_getFileMetaDataTimeAverage);
auto& command = AZStd::get<FileRequest::FileMetaDataRetrievalData>(request->GetCommand());
auto& command = AZStd::get<Requests::FileMetaDataRetrievalData>(request->GetCommand());
// If the file is already open, use the file handle which usually is cheaper than asking for the file by name.
size_t cacheIndex = FindFileInCache(command.m_path);
if (cacheIndex != s_fileNotFound)
@@ -446,11 +446,11 @@ namespace AZ::IO
}
}
void StorageDrive::Report(const FileRequest::ReportData& data) const
void StorageDrive::Report(const Requests::ReportData& data) const
{
switch (data.m_reportType)
{
case FileRequest::ReportData::ReportType::FileLocks:
case Requests::ReportType::FileLocks:
for (u32 i = 0; i < m_fileHandles.size(); ++i)
{
if (m_fileHandles[i] != nullptr)
@@ -8,6 +8,7 @@
#pragma once
#include <AzCore/IO/Streamer/RequestPath.h>
#include <AzCore/IO/Streamer/Statistics.h>
#include <AzCore/IO/Streamer/StreamerConfiguration.h>
#include <AzCore/IO/Streamer/StreamStackEntry.h>
@@ -16,6 +17,11 @@
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/chrono/clocks.h>
namespace AZ::IO::Requests
{
struct ReportData;
}
namespace AZ::IO
{
struct StorageDriveConfig final :
@@ -72,7 +78,7 @@ namespace AZ::IO
void EstimateCompletionTimeForRequest(FileRequest* request, AZStd::chrono::system_clock::time_point& startTime,
const RequestPath*& activeFile, u64& activeOffset) const;
void Report(const FileRequest::ReportData& data) const;
void Report(const Requests::ReportData& data) const;
TimedAverageWindow<s_statisticsWindowSize> m_fileOpenCloseTimeAverage;
TimedAverageWindow<s_statisticsWindowSize> m_getFileExistsTimeAverage;
@@ -9,6 +9,7 @@
#include <AzCore/Casting/numeric_cast.h>
#include <AzCore/Debug/Profiler.h>
#include <AzCore/IO/CompressionBus.h>
#include <AzCore/IO/Streamer/FileRequest.h>
#include <AzCore/IO/Streamer/Streamer.h>
#include <AzCore/IO/Streamer/StreamerConfiguration.h>
#include <AzCore/IO/Streamer/StreamStackEntry.h>
@@ -210,7 +211,7 @@ namespace AZ::IO
IStreamerTypes::ClaimMemory claimMemory) const
{
AZ_Assert(request.m_request, "The request handle provided to Streamer::GetReadRequestResult is invalid.");
auto readRequest = AZStd::get_if<FileRequest::ReadRequestData>(&request.m_request->GetCommand());
auto readRequest = AZStd::get_if<Requests::ReadRequestData>(&request.m_request->GetCommand());
if (readRequest != nullptr)
{
buffer = readRequest->m_output;
@@ -281,14 +282,14 @@ namespace AZ::IO
}
}
FileRequestPtr Streamer::Report(FileRequest::ReportData::ReportType reportType)
FileRequestPtr Streamer::Report(Requests::ReportType reportType)
{
FileRequestPtr result = CreateRequest();
Report(result, reportType);
return result;
}
FileRequestPtr& Streamer::Report(FileRequestPtr& request, FileRequest::ReportData::ReportType reportType)
FileRequestPtr& Streamer::Report(FileRequestPtr& request, Requests::ReportType reportType)
{
request->m_request.CreateReport(reportType);
return request;
@@ -20,6 +20,10 @@ namespace AZStd
struct thread_desc;
}
namespace AZ::IO::Requests
{
enum class ReportType : int8_t;
}
namespace AZ::IO
{
@@ -185,9 +189,9 @@ namespace AZ::IO
void RecordStatistics();
//! Tells AZ::IO::Streamer the report the information for the report to the output.
FileRequestPtr Report(FileRequest::ReportData::ReportType reportType);
FileRequestPtr Report(Requests::ReportType reportType);
//! Tells AZ::IO::Streamer the report the information for the report to the output.
FileRequestPtr& Report(FileRequestPtr& request, FileRequest::ReportData::ReportType reportType);
FileRequestPtr& Report(FileRequestPtr& request, Requests::ReportType reportType);
Streamer(const AZStd::thread_desc& threadDesc, AZStd::unique_ptr<Scheduler> streamStack);
@@ -14,6 +14,7 @@
#include <AzCore/IO/Streamer/BlockCache.h>
#include <AzCore/IO/Streamer/DedicatedCache.h>
#include <AzCore/IO/Streamer/FullFileDecompressor.h>
#include <AzCore/IO/Streamer/FileRequest.h>
#include <AzCore/IO/Streamer/Scheduler.h>
#include <AzCore/IO/Streamer/StreamerComponent.h>
#include <AzCore/IO/Streamer/StreamerConfiguration.h>
@@ -207,7 +208,7 @@ namespace AZ
{
if (m_streamer)
{
m_streamer->QueueRequest(m_streamer->Report(AZ::IO::FileRequest::ReportData::ReportType::FileLocks));
m_streamer->QueueRequest(m_streamer->Report(AZ::IO::Requests::ReportType::FileLocks));
}
}
@@ -22,6 +22,9 @@ namespace AZ
static constexpr char LatePredictionName[] = "Early completions";
static constexpr char MissedDeadlinesName[] = "Missed deadlines";
#endif // AZ_STREAMER_ADD_EXTRA_PROFILING_INFO
StreamerContext::StreamerContext() = default;
StreamerContext::~StreamerContext()
{
for (FileRequest* entry : m_internalRecycleBin)
@@ -204,7 +207,7 @@ namespace AZ
m_latePredictionsPercentageStat.GetMostRecentSample());
}
}
auto readRequest = AZStd::get_if<FileRequest::ReadRequestData>(&top->GetCommand());
auto readRequest = AZStd::get_if<Requests::ReadRequestData>(&top->GetCommand());
if (readRequest != nullptr)
{
m_missedDeadlinePercentageStat.PushSample(now < readRequest->m_deadline ? 0.0 : 1.0);
@@ -224,7 +227,7 @@ namespace AZ
top->m_onCompletion(*top);
AZ_PROFILE_INTERVAL_END(AzCore, top);
}
if (parent)
{
AZ_Assert(parent->m_dependencies > 0,
@@ -8,22 +8,27 @@
#pragma once
#include <AzCore/base.h>
#include <AzCore/IO/Streamer/FileRequest.h>
#include <AzCore/IO/Streamer/Statistics.h>
#include <AzCore/IO/Streamer/StreamerConfiguration.h>
#include <AzCore/IO/Streamer/StreamerContext_Platform.h>
#include <AzCore/std/containers/deque.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/containers/queue.h>
#include <AzCore/Statistics/RunningStatistic.h>
#include <AzCore/std/containers/deque.h>
#include <AzCore/std/containers/queue.h>
#include <AzCore/std/containers/vector.h>
namespace AZ::IO
{
class FileRequest;
class ExternalFileRequest;
using FileRequestPtr = AZStd::intrusive_ptr<ExternalFileRequest>;
class StreamerContext
{
public:
using PreparedQueue = AZStd::deque<FileRequest*>;
StreamerContext();
~StreamerContext();
//! Gets a new file request, either by creating a new instance or
@@ -172,9 +172,9 @@ namespace AZ::IO
AZ_PROFILE_FUNCTION(AzCore);
AZ_Assert(request, "PrepareRequest was provided a null request.");
if (AZStd::holds_alternative<FileRequest::ReadRequestData>(request->GetCommand()))
if (AZStd::holds_alternative<Requests::ReadRequestData>(request->GetCommand()))
{
auto& readRequest = AZStd::get<FileRequest::ReadRequestData>(request->GetCommand());
auto& readRequest = AZStd::get<Requests::ReadRequestData>(request->GetCommand());
if (IsServicedByThisDrive(readRequest.m_path.GetAbsolutePath()))
{
FileRequest* read = m_context->GetNewInternalRequest();
@@ -195,7 +195,7 @@ namespace AZ::IO
AZStd::visit([this, request](auto&& args)
{
using Command = AZStd::decay_t<decltype(args)>;
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadData>)
if constexpr (AZStd::is_same_v<Command, Requests::ReadData>)
{
if (IsServicedByThisDrive(args.m_path.GetAbsolutePath()))
{
@@ -203,8 +203,8 @@ namespace AZ::IO
return;
}
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::FileExistsCheckData> ||
AZStd::is_same_v<Command, FileRequest::FileMetaDataRetrievalData>)
else if constexpr (AZStd::is_same_v<Command, Requests::FileExistsCheckData> ||
AZStd::is_same_v<Command, Requests::FileMetaDataRetrievalData>)
{
if (IsServicedByThisDrive(args.m_path.GetAbsolutePath()))
{
@@ -212,7 +212,7 @@ namespace AZ::IO
return;
}
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::CancelData>)
else if constexpr (AZStd::is_same_v<Command, Requests::CancelData>)
{
if (CancelRequest(request, args.m_target))
{
@@ -221,15 +221,15 @@ namespace AZ::IO
return;
}
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::FlushData>)
else if constexpr (AZStd::is_same_v<Command, Requests::FlushData>)
{
FlushCache(args.m_path);
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::FlushAllData>)
else if constexpr (AZStd::is_same_v<Command, Requests::FlushAllData>)
{
FlushEntireCache();
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::ReportData>)
else if constexpr (AZStd::is_same_v<Command, Requests::ReportData>)
{
Report(args);
}
@@ -254,27 +254,29 @@ namespace AZ::IO
else if (!m_pendingRequests.empty())
{
FileRequest* request = m_pendingRequests.front();
hasWorked = AZStd::visit([this, request](auto&& args)
{
using Command = AZStd::decay_t<decltype(args)>;
if constexpr (AZStd::is_same_v<Command, FileRequest::FileExistsCheckData>)
hasWorked = AZStd::visit(
[this, request](auto&& args)
{
FileExistsRequest(request);
m_pendingRequests.pop_front();
return true;
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::FileMetaDataRetrievalData>)
{
FileMetaDataRetrievalRequest(request);
m_pendingRequests.pop_front();
return true;
}
else
{
AZ_Assert(false, "A request was added to StorageDriveWin's pending queue that isn't supported.");
return false;
}
}, request->GetCommand());
using Command = AZStd::decay_t<decltype(args)>;
if constexpr (AZStd::is_same_v<Command, Requests::FileExistsCheckData>)
{
FileExistsRequest(request);
m_pendingRequests.pop_front();
return true;
}
else if constexpr (AZStd::is_same_v<Command, Requests::FileMetaDataRetrievalData>)
{
FileMetaDataRetrievalRequest(request);
m_pendingRequests.pop_front();
return true;
}
else
{
AZ_Assert(false, "A request was added to StorageDriveWin's pending queue that isn't supported.");
return false;
}
},
request->GetCommand());
}
return StreamStackEntry::ExecuteRequests() || hasFinalizedReads || hasWorked;
@@ -308,7 +310,7 @@ namespace AZ::IO
FileReadInformation& read = m_readSlots_readInfo[i];
u64 totalBytesRead = m_readSizeAverage.GetTotal();
double totalReadTimeUSec = aznumeric_caster(m_readTimeAverage.GetTotal().count());
auto readCommand = AZStd::get_if<FileRequest::ReadData>(&read.m_request->GetCommand());
auto readCommand = AZStd::get_if<Requests::ReadData>(&read.m_request->GetCommand());
AZ_Assert(readCommand, "Request currently reading doesn't contain a read command.");
auto endTime = read.m_startTime + AZStd::chrono::microseconds(aznumeric_cast<u64>((readCommand->m_size * totalReadTimeUSec) / totalBytesRead));
earliestSlot = AZStd::min(earliestSlot, endTime);
@@ -354,25 +356,25 @@ namespace AZ::IO
AZStd::visit([&](auto&& args)
{
using Command = AZStd::decay_t<decltype(args)>;
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadData>)
if constexpr (AZStd::is_same_v<Command, Requests::ReadData>)
{
targetFile = &args.m_path;
readSize = args.m_size;
offset = args.m_offset;
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::CompressedReadData>)
else if constexpr (AZStd::is_same_v<Command, Requests::CompressedReadData>)
{
targetFile = &args.m_compressionInfo.m_archiveFilename;
readSize = args.m_compressionInfo.m_compressedSize;
offset = args.m_compressionInfo.m_offset;
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::FileExistsCheckData>)
else if constexpr (AZStd::is_same_v<Command, Requests::FileExistsCheckData>)
{
readSize = 0;
AZStd::chrono::microseconds getFileExistsTimeAverage = m_getFileExistsTimeAverage.CalculateAverage();
startTime += getFileExistsTimeAverage;
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::FileMetaDataRetrievalData>)
else if constexpr (AZStd::is_same_v<Command, Requests::FileMetaDataRetrievalData>)
{
readSize = 0;
AZStd::chrono::microseconds getFileExistsTimeAverage = m_getFileMetaDataRetrievalTimeAverage.CalculateAverage();
@@ -411,15 +413,15 @@ namespace AZ::IO
AZStd::visit([&, this](auto&& args)
{
using Command = AZStd::decay_t<decltype(args)>;
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadData> ||
AZStd::is_same_v<Command, FileRequest::FileExistsCheckData>)
if constexpr (AZStd::is_same_v<Command, Requests::ReadData> ||
AZStd::is_same_v<Command, Requests::FileExistsCheckData>)
{
if (IsServicedByThisDrive(args.m_path.GetAbsolutePath()))
{
EstimateCompletionTimeForRequest(request, startTime, activeFile, activeOffset);
}
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::CompressedReadData>)
else if constexpr (AZStd::is_same_v<Command, Requests::CompressedReadData>)
{
if (IsServicedByThisDrive(args.m_compressionInfo.m_archiveFilename.GetAbsolutePath()))
{
@@ -435,7 +437,7 @@ namespace AZ::IO
aznumeric_cast<s32>(m_pendingRequests.size()) - m_activeReads_Count;
}
auto StorageDriveWin::OpenFile(HANDLE& fileHandle, size_t& cacheSlot, FileRequest* request, const FileRequest::ReadData& data) -> OpenFileResult
auto StorageDriveWin::OpenFile(HANDLE& fileHandle, size_t& cacheSlot, FileRequest* request, const Requests::ReadData& data) -> OpenFileResult
{
HANDLE file = INVALID_HANDLE_VALUE;
@@ -553,7 +555,7 @@ namespace AZ::IO
return false;
}
auto data = AZStd::get_if<FileRequest::ReadData>(&request->GetCommand());
auto data = AZStd::get_if<Requests::ReadData>(&request->GetCommand());
AZ_Assert(data, "Read request in StorageDriveWin doesn't contain read data.");
HANDLE file = INVALID_HANDLE_VALUE;
@@ -780,7 +782,7 @@ namespace AZ::IO
void StorageDriveWin::FileExistsRequest(FileRequest* request)
{
auto& fileExists = AZStd::get<FileRequest::FileExistsCheckData>(request->GetCommand());
auto& fileExists = AZStd::get<Requests::FileExistsCheckData>(request->GetCommand());
AZ_PROFILE_SCOPE(AzCore, "StorageDriveWin::FileExistsRequest %s : %s",
m_name.c_str(), fileExists.m_path.GetRelativePath());
@@ -836,7 +838,7 @@ namespace AZ::IO
void StorageDriveWin::FileMetaDataRetrievalRequest(FileRequest* request)
{
auto& command = AZStd::get<FileRequest::FileMetaDataRetrievalData>(request->GetCommand());
auto& command = AZStd::get<Requests::FileMetaDataRetrievalData>(request->GetCommand());
AZ_PROFILE_SCOPE(AzCore, "StorageDriveWin::FileMetaDataRetrievalRequest %s : %s",
m_name.c_str(), command.m_path.GetRelativePath());
@@ -1005,7 +1007,7 @@ namespace AZ::IO
FileReadInformation& fileReadInfo = m_readSlots_readInfo[readSlot];
auto readCommand = AZStd::get_if<FileRequest::ReadData>(&fileReadInfo.m_request->GetCommand());
auto readCommand = AZStd::get_if<Requests::ReadData>(&fileReadInfo.m_request->GetCommand());
AZ_Assert(readCommand != nullptr, "Request stored with the overlapped I/O call did not contain a read request.");
if (fileReadInfo.m_sectorAlignedOutput && !encounteredError)
@@ -1147,11 +1149,11 @@ namespace AZ::IO
StreamStackEntry::CollectStatistics(statistics);
}
void StorageDriveWin::Report(const FileRequest::ReportData& data) const
void StorageDriveWin::Report(const Requests::ReportData& data) const
{
switch (data.m_reportType)
{
case FileRequest::ReportData::ReportType::FileLocks:
case Requests::ReportType::FileLocks:
if (m_cachesInitialized)
{
for (u32 i = 0; i < m_maxFileHandles; ++i)
@@ -9,6 +9,7 @@
#pragma once
#include <AzCore/PlatformIncl.h>
#include <AzCore/IO/Streamer/RequestPath.h>
#include <AzCore/IO/Streamer/Statistics.h>
#include <AzCore/IO/Streamer/StreamerConfiguration.h>
#include <AzCore/IO/Streamer/StreamStackEntry.h>
@@ -19,6 +20,12 @@
#include <AzCore/std/string/string_view.h>
#include <AzCore/Statistics/RunningStatistic.h>
namespace AZ::IO::Requests
{
struct ReadData;
struct ReportData;
}
namespace AZ::IO
{
class StorageDriveWin
@@ -111,7 +118,7 @@ namespace AZ::IO
CacheFull
};
OpenFileResult OpenFile(HANDLE& fileHandle, size_t& cacheSlot, FileRequest* request, const FileRequest::ReadData& data);
OpenFileResult OpenFile(HANDLE& fileHandle, size_t& cacheSlot, FileRequest* request, const Requests::ReadData& data);
bool ReadRequest(FileRequest* request);
bool ReadRequest(FileRequest* request, size_t readSlot);
bool CancelRequest(FileRequest* cancelRequest, FileRequestPtr& target);
@@ -137,7 +144,7 @@ namespace AZ::IO
void FinalizeSingleRequest(FileReadStatus& status, size_t readSlot, DWORD numBytesTransferred,
bool isCanceled, bool encounteredError);
void Report(const FileRequest::ReportData& data) const;
void Report(const Requests::ReportData& data) const;
TimedAverageWindow<s_statisticsWindowSize> m_fileOpenCloseTimeAverage;
TimedAverageWindow<s_statisticsWindowSize> m_getFileExistsTimeAverage;
@@ -6,6 +6,7 @@
*
*/
#include <AzCore/Asset/AssetDataStream.h>
#include <AzCore/IO/Streamer/FileRequest.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <AZTestShared/Utils/Utils.h>
#include <Tests/Streamer/IStreamerMock.h>
@@ -406,7 +406,7 @@ namespace AZ::IO
request->CreateFileMetaDataRetrieval(path);
request->SetCompletionCallback([](const FileRequest& request)
{
auto& fileMetaData = AZStd::get<FileRequest::FileMetaDataRetrievalData>(request.GetCommand());
auto& fileMetaData = AZStd::get<Requests::FileMetaDataRetrievalData>(request.GetCommand());
EXPECT_FALSE(fileMetaData.m_found);
EXPECT_EQ(0, fileMetaData.m_fileSize);
});
@@ -424,7 +424,7 @@ namespace AZ::IO
request->SetCompletionCallback([](const FileRequest& request)
{
auto& fileMetaData = AZStd::get<FileRequest::FileMetaDataRetrievalData>(request.GetCommand());
auto& fileMetaData = AZStd::get<Requests::FileMetaDataRetrievalData>(request.GetCommand());
EXPECT_TRUE(fileMetaData.m_found);
EXPECT_EQ(4_kib, fileMetaData.m_fileSize);
});
@@ -442,7 +442,7 @@ namespace AZ::IO
request->CreateFileMetaDataRetrieval(path);
request->SetCompletionCallback([](const FileRequest& request)
{
auto& fileMetaData = AZStd::get<FileRequest::FileMetaDataRetrievalData>(request.GetCommand());
auto& fileMetaData = AZStd::get<Requests::FileMetaDataRetrievalData>(request.GetCommand());
EXPECT_FALSE(fileMetaData.m_found);
EXPECT_EQ(0, fileMetaData.m_fileSize);
});
@@ -460,7 +460,7 @@ namespace AZ::IO
request->SetCompletionCallback([](const FileRequest& request)
{
auto& fileMetaData = AZStd::get<FileRequest::FileMetaDataRetrievalData>(request.GetCommand());
auto& fileMetaData = AZStd::get<Requests::FileMetaDataRetrievalData>(request.GetCommand());
EXPECT_TRUE(fileMetaData.m_found);
EXPECT_EQ(16_kib, fileMetaData.m_fileSize);
});
@@ -484,7 +484,7 @@ namespace AZ::IO
request->SetCompletionCallback([](const FileRequest& request)
{
auto& fileMetaData = AZStd::get<FileRequest::FileMetaDataRetrievalData>(request.GetCommand());
auto& fileMetaData = AZStd::get<Requests::FileMetaDataRetrievalData>(request.GetCommand());
EXPECT_TRUE(fileMetaData.m_found);
EXPECT_EQ(4_kib, fileMetaData.m_fileSize);
});
@@ -502,7 +502,7 @@ namespace AZ::IO
request->CreateFileExistsCheck(invalidPath);
request->SetCompletionCallback([](const FileRequest& request)
{
auto& fileExistsCheck = AZStd::get<FileRequest::FileExistsCheckData>(request.GetCommand());
auto& fileExistsCheck = AZStd::get<Requests::FileExistsCheckData>(request.GetCommand());
EXPECT_EQ(AZ::IO::IStreamerTypes::RequestStatus::Completed, request.GetStatus());
EXPECT_FALSE(fileExistsCheck.m_found);
});
@@ -519,7 +519,7 @@ namespace AZ::IO
request->CreateFileExistsCheck(path);
request->SetCompletionCallback([](const FileRequest& request)
{
auto& fileExistsCheck = AZStd::get<FileRequest::FileExistsCheckData>(request.GetCommand());
auto& fileExistsCheck = AZStd::get<Requests::FileExistsCheckData>(request.GetCommand());
EXPECT_EQ(AZ::IO::IStreamerTypes::RequestStatus::Completed, request.GetStatus());
EXPECT_FALSE(fileExistsCheck.m_found);
});
@@ -535,7 +535,7 @@ namespace AZ::IO
request->CreateFileExistsCheck(m_dummyRequestPath);
request->SetCompletionCallback([](const FileRequest& request)
{
auto& fileExistsCheck = AZStd::get<FileRequest::FileExistsCheckData>(request.GetCommand());
auto& fileExistsCheck = AZStd::get<Requests::FileExistsCheckData>(request.GetCommand());
EXPECT_EQ(AZ::IO::IStreamerTypes::RequestStatus::Completed, request.GetStatus());
EXPECT_TRUE(fileExistsCheck.m_found);
});
@@ -551,7 +551,7 @@ namespace AZ::IO
request->CreateFileExistsCheck(m_dummyRequestPath);
request->SetCompletionCallback([](const FileRequest& request)
{
auto& fileExistsCheck = AZStd::get<FileRequest::FileExistsCheckData>(request.GetCommand());
auto& fileExistsCheck = AZStd::get<Requests::FileExistsCheckData>(request.GetCommand());
EXPECT_EQ(AZ::IO::IStreamerTypes::RequestStatus::Completed, request.GetStatus());
EXPECT_TRUE(fileExistsCheck.m_found);
});
@@ -573,7 +573,7 @@ namespace AZ::IO
request->CreateFileExistsCheck(m_dummyRequestPath);
request->SetCompletionCallback([](const FileRequest& request)
{
auto& fileExistsCheck = AZStd::get<FileRequest::FileExistsCheckData>(request.GetCommand());
auto& fileExistsCheck = AZStd::get<Requests::FileExistsCheckData>(request.GetCommand());
EXPECT_EQ(AZ::IO::IStreamerTypes::RequestStatus::Completed, request.GetStatus());
EXPECT_TRUE(fileExistsCheck.m_found);
});
@@ -603,7 +603,7 @@ namespace AZ::IO
AZ_POP_DISABLE_WARNING
{
EXPECT_EQ(request.GetStatus(), AZ::IO::IStreamerTypes::RequestStatus::Completed);
auto& readRequest = AZStd::get<AZ::IO::FileRequest::ReadData>(request.GetCommand());
auto& readRequest = AZStd::get<AZ::IO::Requests::ReadData>(request.GetCommand());
EXPECT_EQ(readRequest.m_size, fileSize);
EXPECT_STREQ(readRequest.m_path.GetAbsolutePath(), m_dummyFilepath.c_str());
};
@@ -648,7 +648,7 @@ namespace AZ::IO
AZ_POP_DISABLE_WARNING
{
EXPECT_EQ(request.GetStatus(), AZ::IO::IStreamerTypes::RequestStatus::Completed);
auto& readRequest = AZStd::get<AZ::IO::FileRequest::ReadData>(request.GetCommand());
auto& readRequest = AZStd::get<AZ::IO::Requests::ReadData>(request.GetCommand());
EXPECT_EQ(readRequest.m_size, unalignedSize);
EXPECT_EQ(readRequest.m_offset, unalignedOffset);
EXPECT_STREQ(readRequest.m_path.GetAbsolutePath(), m_dummyFilepath.c_str());
@@ -796,7 +796,7 @@ namespace AZ::IO
AZ_POP_DISABLE_WARNING
{
EXPECT_EQ(request.GetStatus(), AZ::IO::IStreamerTypes::RequestStatus::Completed);
auto& readRequest = AZStd::get<AZ::IO::FileRequest::ReadData>(request.GetCommand());
auto& readRequest = AZStd::get<AZ::IO::Requests::ReadData>(request.GetCommand());
EXPECT_EQ(readRequest.m_size, chunkSize);
EXPECT_EQ(readRequest.m_offset, i * chunkSize);
};
@@ -100,7 +100,7 @@ namespace AZ::IO
void QueueReadRequest(FileRequest* request)
{
auto data = AZStd::get_if<FileRequest::ReadData>(&request->GetCommand());
auto data = AZStd::get_if<Requests::ReadData>(&request->GetCommand());
if (data)
{
if (m_fakeFileFound)
@@ -122,15 +122,15 @@ namespace AZ::IO
m_context->MarkRequestAsCompleted(request);
}
else if (
AZStd::holds_alternative<FileRequest::FlushData>(request->GetCommand()) ||
AZStd::holds_alternative<FileRequest::FlushAllData>(request->GetCommand()))
AZStd::holds_alternative<Requests::FlushData>(request->GetCommand()) ||
AZStd::holds_alternative<Requests::FlushAllData>(request->GetCommand()))
{
request->SetStatus(IStreamerTypes::RequestStatus::Completed);
m_context->MarkRequestAsCompleted(request);
}
else if (AZStd::holds_alternative<FileRequest::FileMetaDataRetrievalData>(request->GetCommand()))
else if (AZStd::holds_alternative<Requests::FileMetaDataRetrievalData>(request->GetCommand()))
{
auto& data2 = AZStd::get<FileRequest::FileMetaDataRetrievalData>(request->GetCommand());
auto& data2 = AZStd::get<Requests::FileMetaDataRetrievalData>(request->GetCommand());
data2.m_found = m_fakeFileFound;
data2.m_fileSize = m_fakeFileLength;
request->SetStatus(m_fakeFileFound ? IStreamerTypes::RequestStatus::Completed : IStreamerTypes::RequestStatus::Failed);
@@ -158,16 +158,16 @@ namespace AZ::IO
void QueueCanceledReadRequest(FileRequest* request)
{
auto data = AZStd::get_if<FileRequest::ReadData>(&request->GetCommand());
auto data = AZStd::get_if<Requests::ReadData>(&request->GetCommand());
if (data)
{
ReadFile(data->m_output, data->m_path, data->m_offset, data->m_size);
request->SetStatus(IStreamerTypes::RequestStatus::Canceled);
m_context->MarkRequestAsCompleted(request);
}
else if (AZStd::holds_alternative<FileRequest::FileMetaDataRetrievalData>(request->GetCommand()))
else if (AZStd::holds_alternative<Requests::FileMetaDataRetrievalData>(request->GetCommand()))
{
auto& data2 = AZStd::get<FileRequest::FileMetaDataRetrievalData>(request->GetCommand());
auto& data2 = AZStd::get<Requests::FileMetaDataRetrievalData>(request->GetCommand());
data2.m_found = true;
data2.m_fileSize = m_fakeFileLength;
request->SetStatus(IStreamerTypes::RequestStatus::Completed);
@@ -145,7 +145,7 @@ namespace AZ::IO
void PrepareReadRequest(FileRequest* request)
{
auto data = AZStd::get_if<FileRequest::ReadData>(&request->GetCommand());
auto data = AZStd::get_if<Requests::ReadData>(&request->GetCommand());
ASSERT_NE(nullptr, data);
u64 size = data->m_size >> 2;
@@ -9,6 +9,7 @@
#include <gmock/gmock.h>
#include <AzCore/IO/IStreamer.h>
#include <AzCore/IO/Streamer/FileRequest.h>
using namespace AZ::IO;
@@ -155,7 +155,7 @@ namespace AZ::IO
{
EXPECT_EQ(subRequests[i]->GetParent(), readRequest);
FileRequest::ReadData* data = AZStd::get_if<FileRequest::ReadData>(&subRequests[i]->GetCommand());
Requests::ReadData* data = AZStd::get_if<Requests::ReadData>(&subRequests[i]->GetCommand());
ASSERT_NE(nullptr, data);
EXPECT_EQ(SplitSize, data->m_size);
EXPECT_EQ(SplitSize * i, data->m_offset);
@@ -210,7 +210,7 @@ namespace AZ::IO
{
EXPECT_EQ(subRequests[i]->GetParent(), readRequest);
FileRequest::ReadData* data = AZStd::get_if<FileRequest::ReadData>(&subRequests[i]->GetCommand());
Requests::ReadData* data = AZStd::get_if<Requests::ReadData>(&subRequests[i]->GetCommand());
ASSERT_NE(nullptr, data);
EXPECT_EQ(SplitSize, data->m_size);
EXPECT_EQ(SplitSize * i, data->m_offset);
@@ -230,7 +230,7 @@ namespace AZ::IO
{
EXPECT_EQ(subRequests[i]->GetParent(), readRequest);
FileRequest::ReadData* data = AZStd::get_if<FileRequest::ReadData>(&subRequests[i]->GetCommand());
Requests::ReadData* data = AZStd::get_if<Requests::ReadData>(&subRequests[i]->GetCommand());
ASSERT_NE(nullptr, data);
EXPECT_EQ(SplitSize, data->m_size);
EXPECT_EQ(SplitSize * (batchSize + i), data->m_offset);
@@ -265,7 +265,7 @@ namespace AZ::IO
m_readSplitter->QueueRequest(readRequest);
ASSERT_NE(nullptr, subRequest);
FileRequest::ReadData* data = AZStd::get_if<FileRequest::ReadData>(&subRequest->GetCommand());
Requests::ReadData* data = AZStd::get_if<Requests::ReadData>(&subRequest->GetCommand());
EXPECT_NE(buffer, data->m_output);
EXPECT_EQ(readSize, data->m_size);
EXPECT_EQ(0, data->m_offset);
@@ -311,7 +311,7 @@ namespace AZ::IO
m_readSplitter->QueueRequest(readRequest);
ASSERT_NE(nullptr, subRequest);
FileRequest::ReadData* data = AZStd::get_if<FileRequest::ReadData>(&subRequest->GetCommand());
Requests::ReadData* data = AZStd::get_if<Requests::ReadData>(&subRequest->GetCommand());
EXPECT_NE(buffer, data->m_output);
EXPECT_EQ(readSize + offsetAdjustment, data->m_size);
EXPECT_EQ(0, data->m_offset);
@@ -9,6 +9,7 @@
#include <AzCore/Casting/lossy_cast.h>
#include <AzCore/IO/Streamer/Streamer.h>
#include <AzCore/IO/Streamer/Scheduler.h>
#include <AzCore/IO/Streamer/FileRequest.h>
#include <AzCore/std/parallel/atomic.h>
#include <AzCore/std/parallel/binary_semaphore.h>
#include <AzCore/std/smart_ptr/make_shared.h>
@@ -86,7 +87,7 @@ namespace AZ::IO
.WillOnce([this](FileRequest* request)
{
AZ_Assert(m_streamerContext, "AZ::IO::Streamer is not ready to process requests.");
auto readData = AZStd::get_if<FileRequest::ReadRequestData>(&request->GetCommand());
auto readData = AZStd::get_if<Requests::ReadRequestData>(&request->GetCommand());
AZ_Assert(readData, "Test didn't pass in the correct request.");
FileRequest* read = m_streamerContext->GetNewInternalRequest();
read->CreateRead(request, readData->m_output, readData->m_outputSize, readData->m_path,
@@ -99,7 +100,7 @@ namespace AZ::IO
.WillOnce([this](FileRequest* request)
{
AZ_Assert(m_streamerContext, "AZ::IO::Streamer is not ready to process requests.");
auto readData = AZStd::get_if<FileRequest::ReadData>(&request->GetCommand());
auto readData = AZStd::get_if<Requests::ReadData>(&request->GetCommand());
AZ_Assert(readData, "Test didn't pass in the correct request.");
auto output = reinterpret_cast<uint8_t*>(readData->m_output);
AZ_Assert(output != nullptr, "Output buffer has not been set.");
@@ -304,7 +305,7 @@ namespace AZ::IO
EXPECT_CALL(*m_mock, QueueRequest(_)).Times(1)
.WillOnce(Invoke([this](FileRequest* request)
{
auto* read = request->GetCommandFromChain<FileRequest::ReadRequestData>();
auto* read = request->GetCommandFromChain<Requests::ReadRequestData>();
ASSERT_NE(nullptr, read);
EXPECT_LT(read->m_deadline, FileRequest::s_noDeadlineTime);
EXPECT_EQ(read->m_priority, IStreamerTypes::s_priorityHighest);
@@ -10,6 +10,7 @@
#include <limits>
#include <AzCore/IO/IStreamerTypes.h>
#include <AzCore/IO/Streamer/FileRequest.h>
#include <AzCore/IO/Streamer/StreamerContext.h>
#include <AzCore/IO/Streamer/StreamStackEntry.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
@@ -10,6 +10,7 @@
#include <FileIOBaseTestTypes.h>
#include <AzCore/IO/CompressionBus.h>
#include <AzCore/IO/FileIO.h>
#include <AzCore/IO/Streamer/FileRequest.h>
#include <AzCore/IO/Streamer/Streamer.h>
#include <AzCore/IO/Streamer/StreamerComponent.h>
#include <AzCore/IO/Streamer/StreamerConfiguration.h>
@@ -11,6 +11,7 @@
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/Serialization/Utils.h>
#include <AzCore/IO/FileIO.h>
#include <AzCore/std/parallel/condition_variable.h>
namespace UnitTest
{
@@ -15,6 +15,7 @@
#include <AzCore/Interface/Interface.h>
#include <AzCore/IO/FileIO.h>
#include <AzCore/IO/IStreamer.h>
#include <AzCore/IO/Streamer/FileRequest.h>
#include <AzCore/IO/SystemFile.h>
#include <AzCore/std/chrono/chrono.h>
#include <AzCore/std/string/conversions.h>
@@ -83,9 +83,9 @@ namespace AzFramework
AZ_PROFILE_FUNCTION(AzCore);
AZ_Assert(request, "PrepareRequest was provided a null request.");
if (AZStd::holds_alternative<FileRequest::ReadRequestData>(request->GetCommand()))
if (AZStd::holds_alternative<Requests::ReadRequestData>(request->GetCommand()))
{
auto& readRequest = AZStd::get<FileRequest::ReadRequestData>(request->GetCommand());
auto& readRequest = AZStd::get<Requests::ReadRequestData>(request->GetCommand());
FileRequest* read = m_context->GetNewInternalRequest();
read->CreateRead(request, readRequest.m_output, readRequest.m_outputSize, readRequest.m_path,
@@ -106,14 +106,14 @@ namespace AzFramework
{
using namespace AZ::IO;
using Command = AZStd::decay_t<decltype(args)>;
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadData> ||
AZStd::is_same_v<Command, FileRequest::FileExistsCheckData> ||
AZStd::is_same_v<Command, FileRequest::FileMetaDataRetrievalData>)
if constexpr (AZStd::is_same_v<Command, Requests::ReadData> ||
AZStd::is_same_v<Command, Requests::FileExistsCheckData> ||
AZStd::is_same_v<Command, Requests::FileMetaDataRetrievalData>)
{
m_pendingRequests.push_back(request);
return;
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::CancelData>)
else if constexpr (AZStd::is_same_v<Command, Requests::CancelData>)
{
if (CancelRequest(request, args.m_target))
{
@@ -124,15 +124,15 @@ namespace AzFramework
}
else
{
if constexpr (AZStd::is_same_v<Command, FileRequest::FlushData>)
if constexpr (AZStd::is_same_v<Command, Requests::FlushData>)
{
FlushCache(args.m_path);
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::FlushAllData>)
else if constexpr (AZStd::is_same_v<Command, Requests::FlushAllData>)
{
FlushEntireCache();
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::ReportData>)
else if constexpr (AZStd::is_same_v<Command, Requests::ReportData>)
{
Report(args);
}
@@ -152,15 +152,15 @@ namespace AzFramework
{
using namespace AZ::IO;
using Command = AZStd::decay_t<decltype(args)>;
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadData>)
if constexpr (AZStd::is_same_v<Command, Requests::ReadData>)
{
ReadFile(request);
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::FileExistsCheckData>)
else if constexpr (AZStd::is_same_v<Command, Requests::FileExistsCheckData>)
{
FileExistsRequest(request);
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::FileMetaDataRetrievalData>)
else if constexpr (AZStd::is_same_v<Command, Requests::FileMetaDataRetrievalData>)
{
FileMetaDataRetrievalRequest(request);
}
@@ -232,23 +232,23 @@ namespace AzFramework
{
using namespace AZ::IO;
using Command = AZStd::decay_t<decltype(args)>;
if constexpr (AZStd::is_same_v<Command, FileRequest::ReadData>)
if constexpr (AZStd::is_same_v<Command, Requests::ReadData>)
{
targetFile = &args.m_path;
readSize = args.m_size;
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::CompressedReadData>)
else if constexpr (AZStd::is_same_v<Command, Requests::CompressedReadData>)
{
targetFile = &args.m_compressionInfo.m_archiveFilename;
readSize = args.m_compressionInfo.m_compressedSize;
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::FileExistsCheckData>)
else if constexpr (AZStd::is_same_v<Command, Requests::FileExistsCheckData>)
{
readSize = 0;
AZStd::chrono::microseconds averageTime = m_getFileExistsTimeAverage.CalculateAverage();
startTime += averageTime;
}
else if constexpr (AZStd::is_same_v<Command, FileRequest::FileMetaDataRetrievalData>)
else if constexpr (AZStd::is_same_v<Command, Requests::FileMetaDataRetrievalData>)
{
readSize = 0;
AZStd::chrono::microseconds averageTime = m_getFileMetaDataTimeAverage.CalculateAverage();
@@ -280,7 +280,7 @@ namespace AzFramework
AZ_PROFILE_FUNCTION(AzCore);
auto data = AZStd::get_if<FileRequest::ReadData>(&request->GetCommand());
auto data = AZStd::get_if<Requests::ReadData>(&request->GetCommand());
AZ_Assert(data, "Request doing reading in the RemoteStorageDrive didn't contain read data.");
HandleType file = InvalidHandle;
@@ -397,7 +397,7 @@ namespace AzFramework
TIMED_AVERAGE_WINDOW_SCOPE(m_getFileExistsTimeAverage);
auto& fileExists = AZStd::get<FileRequest::FileExistsCheckData>(request->GetCommand());
auto& fileExists = AZStd::get<Requests::FileExistsCheckData>(request->GetCommand());
size_t cacheIndex = FindFileInCache(fileExists.m_path);
if (cacheIndex != s_fileNotFound)
{
@@ -430,7 +430,7 @@ namespace AzFramework
AZ::u64 fileSize = 0;
bool found = false;
auto& command = AZStd::get<FileRequest::FileMetaDataRetrievalData>(request->GetCommand());
auto& command = AZStd::get<Requests::FileMetaDataRetrievalData>(request->GetCommand());
// If the file is already open, use the file handle which usually is cheaper than asking for the file by name.
size_t cacheIndex = FindFileInCache(command.m_path);
if (cacheIndex != s_fileNotFound)
@@ -526,13 +526,13 @@ namespace AzFramework
StreamStackEntry::CollectStatistics(statistics);
}
void RemoteStorageDrive::Report(const AZ::IO::FileRequest::ReportData& data) const
void RemoteStorageDrive::Report(const AZ::IO::Requests::ReportData& data) const
{
using namespace AZ::IO;
switch (data.m_reportType)
{
case FileRequest::ReportData::ReportType::FileLocks:
case Requests::ReportType::FileLocks:
for (AZ::u32 i = 0; i < m_fileHandles.size(); ++i)
{
if (m_fileHandles[i] != InvalidHandle)
@@ -16,6 +16,15 @@
#include <AzCore/std/chrono/clocks.h>
#include <AzFramework/IO/RemoteFileIO.h>
namespace AZ::IO
{
class RequestPath;
namespace Requests
{
struct ReportData;
}
}
namespace AzFramework
{
struct RemoteStorageDriveConfig final :
@@ -63,7 +72,7 @@ namespace AzFramework
const AZ::IO::RequestPath*& activeFile) const;
void FlushCache(const AZ::IO::RequestPath& filePath);
void FlushEntireCache();
void Report(const AZ::IO::FileRequest::ReportData& data) const;
void Report(const AZ::IO::Requests::ReportData& data) const;
AZ::IO::RemoteFileIO m_fileIO;
AZ::IO::TimedAverageWindow<AZ::IO::s_statisticsWindowSize> m_fileOpenCloseTimeAverage;
@@ -10,6 +10,7 @@
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Interface/Interface.h>
#include <AzFramework/Physics/PhysicsScene.h>
#include <AzFramework/Physics/PhysicsSystem.h>
@@ -8,6 +8,7 @@
#include <AzFramework/Physics/Common/PhysicsSimulatedBodyAutomation.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/Serialization/SerializeContext.h>
@@ -8,6 +8,7 @@
#include <AzFramework/Physics/Common/PhysicsSimulatedBodyEvents.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/std/functional.h>
#include <AzFramework/Physics/PhysicsScene.h>
#include <AzFramework/Physics/PhysicsSystem.h>
@@ -35,16 +35,15 @@ namespace Physics
{
}
virtual ~HeightMaterialPoint() = default;
~HeightMaterialPoint() = default;
static void Reflect(AZ::ReflectContext* context);
AZ_RTTI(HeightMaterialPoint, "{DF167ED4-24E6-4F7B-8AB7-42622F7DBAD3}");
AZ_TYPE_INFO(HeightMaterialPoint, "{DF167ED4-24E6-4F7B-8AB7-42622F7DBAD3}");
float m_height{ 0.0f }; //!< Holds the height of this point in the heightfield relative to the heightfield entity location.
QuadMeshType m_quadMeshType{ QuadMeshType::SubdivideUpperLeftToBottomRight }; //!< By default, create two triangles like this |\|, where this point is in the upper left corner.
uint8_t m_materialIndex{ 0 }; //!< The surface material index for the upper left corner of this quad.
uint16_t m_padding{ 0 }; //!< available for future use.
};
//! An interface to provide heightfield values.
@@ -9,6 +9,7 @@
#include <AzFramework/Physics/PhysicsSystem.h>
#include <AzFramework/Physics/Configuration/SceneConfiguration.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/RTTI/BehaviorContext.h>
@@ -8,6 +8,7 @@
#include <AzFramework/Physics/PhysicsSystem.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/RTTI/BehaviorContext.h>
namespace AzPhysics
@@ -5,25 +5,23 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Component/EntityId.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/Math/Aabb.h>
#include <AzFramework/Entity/EntityContextBus.h>
#include <AzFramework/Render/GeometryIntersectionBus.h>
#include <AzFramework/Render/GeometryIntersectionStructures.h>
#include <AzFramework/Render/IntersectorInterface.h>
#include <AzFramework/Render/GeometryIntersectionBus.h>
namespace AzFramework
{
namespace RenderGeometry
{
//! Implementation of IntersectorBus interface, this class contains a cached AABB list
//! of the connected entities to the intersection bus and calculates performant ray intersections against them
//! Implementation of IntersectorBus interface, this class contains a cached AABB list of the connected
//! entities to the intersection bus and calculates efficient ray intersections against them.
class Intersector final
: public IntersectorBus::Handler
, protected IntersectionNotificationBus::Handler
@@ -34,32 +32,32 @@ namespace AzFramework
Intersector(AzFramework::EntityContextId contextId);
~Intersector();
// IntersectorBus
// IntersectorBus overrides ...
RayResult RayIntersect(const RayRequest& ray) override;
// IntersectionNotifications
// IntersectionNotificationBus overrides ...
void OnEntityConnected(AZ::EntityId entityId) override;
void OnEntityDisconnected(AZ::EntityId entityId) override;
void OnGeometryChanged(AZ::EntityId entityId) override;
private:
struct EntityData
{
EntityData(AZ::EntityId id, AZ::Aabb aabb)
: m_id(id)
, m_aabb(aabb)
, m_ref(1) {}
, m_ref(1)
{
}
AZ::EntityId m_id;
AZ::Aabb m_aabb;
int m_ref;
};
class EntityDataList
{
public:
int AddRef(AZ::EntityId entityId);
int RemoveRef(AZ::EntityId entityId);
void Update(const EntityData& newData);
@@ -88,5 +86,5 @@ namespace AzFramework
AZStd::vector<AZStd::pair<const EntityData*, float>> m_candidatesSortedByDist;
AzFramework::EntityContextId m_contextId;
};
}
}
} // namespace RenderGeometry
} // namespace AzFramework
@@ -17,6 +17,7 @@
#include <AzCore/Asset/AssetSerializer.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/Debug/Profiler.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
@@ -411,18 +411,6 @@ namespace AzQtComponents
}
break;
case CE_HeaderSection:
{
if (qobject_cast<const QHeaderView*>(widget))
{
if (TableView::drawHeaderSection(this, option, painter, widget, m_data->tableViewConfig))
{
return;
}
}
}
break;
case CE_ComboBoxLabel:
{
if (qobject_cast<const QComboBox*>(widget))
@@ -38,7 +38,6 @@ namespace AzQtComponents
ConfigHelpers::read<qreal>(settings, QStringLiteral("FocusBorderWidth"), config.focusBorderWidth);
ConfigHelpers::read<QColor>(settings, QStringLiteral("FocusBorderColor"), config.focusBorderColor);
ConfigHelpers::read<QColor>(settings, QStringLiteral("FocusFillColor"), config.focusFillColor);
ConfigHelpers::read<QColor>(settings, QStringLiteral("HeaderFillColor"), config.headerFillColor);
settings.endGroup();
return config;
@@ -52,7 +51,6 @@ namespace AzQtComponents
config.focusBorderWidth = 1;
config.focusBorderColor = QStringLiteral("#94D2FF");
config.focusFillColor = QStringLiteral("#10ffffff");
config.headerFillColor = QStringLiteral("#2d2d2d");
return config;
}
@@ -177,22 +175,6 @@ namespace AzQtComponents
return true;
}
bool TableView::drawHeaderSection(const Style* style, const QStyleOption* option, QPainter* painter, const QWidget* widget, const Config& config)
{
Q_UNUSED(widget);
Q_UNUSED(style);
const auto headerViewOption = qstyleoption_cast<const QStyleOptionHeader*>(option);
if (!headerViewOption)
{
return false;
}
painter->fillRect(headerViewOption->rect, config.headerFillColor);
return true;
}
bool TableView::drawFrameFocusRect(const Style* style, const QStyleOption* option, QPainter* painter, const Config& config)
{
Q_UNUSED(style);
@@ -62,7 +62,6 @@ namespace AzQtComponents
qreal focusBorderWidth;
QColor focusBorderColor;
QColor focusFillColor;
QColor headerFillColor;
};
/*!
@@ -93,7 +92,6 @@ namespace AzQtComponents
private:
static bool drawHeader(const Style* style, const QStyleOption* option, QPainter* painter, const QWidget* widget, const Config& config);
static bool drawHeaderSection(const Style* style, const QStyleOption* option, QPainter* painter, const QWidget* widget, const Config& config);
static bool drawFrameFocusRect(const Style* style, const QStyleOption* option, QPainter* painter, const Config& config);
static QRect itemViewItemRect(const Style* style, QStyle::SubElement element, const QStyleOptionViewItem* option, const QWidget* widget, const Config& config);
static QSize sizeFromContents(const Style* style, QStyle::ContentsType type, const QStyleOption* option, const QSize& contentsSize, const QWidget* widget, const Config& config);
@@ -66,7 +66,7 @@ QTreeView QHeaderView::section
{
height: 24px;
background: #444444;
background: #2d2d2d;
border: none;
font-size: 12px;
@@ -134,6 +134,9 @@ TableViewPage::TableViewPage(QWidget* parent)
auto logItemDelegate = new AzToolsFramework::Logging::LogTableItemDelegate(ui->logTableView);
ui->logTableView->setItemDelegate(logItemDelegate);
// Example of changing the header section background color
ui->logTableView->setStyleSheet("QHeaderView::section { background: transparent; }");
ui->qTableView->setModel(logModel);
ui->qTableView->setAlternatingRowColors(true);
ui->qTableView->setShowGrid(false);
@@ -63,9 +63,12 @@ namespace AzToolsFramework
/// Registers an existing set of entities with the editor context.
virtual void AddEditorEntities(const EntityList& entities) = 0;
/// Registers an existing set of entities with the editor context.
/// Triggers registered callbacks for an existing set of entities with the editor context.
virtual void HandleEntitiesAdded(const EntityList& entities) = 0;
/// Creates an editor ready entity, and sends out notification for the creation.
virtual void FinalizeEditorEntity(AZ::Entity* entity) = 0;
/// Destroys an entity in the editor context.
/// \return whether or not the entity was destroyed. A false return value signifies the entity did not belong to the game context.
virtual bool DestroyEditorEntity(AZ::EntityId entityId) = 0;
@@ -227,14 +227,8 @@ namespace AzToolsFramework
{
AZ::Entity* entity = CreateEntity(name);
AZ_Assert(entity != nullptr, "Entity with name %s couldn't be created.", name);
if (m_isLegacySliceService)
{
FinalizeEditorEntity(entity);
}
else
{
EditorEntityContextNotificationBus::Broadcast(&EditorEntityContextNotification::OnEditorEntityCreated, entity->GetId());
}
FinalizeEditorEntity(entity);
return entity->GetId();
}
@@ -263,14 +257,7 @@ namespace AzToolsFramework
entity = aznew AZ::Entity(entityId, name);
AZ_Assert(entity != nullptr, "Entity with name %s couldn't be created.", name);
AddEntity(entity);
if (m_isLegacySliceService)
{
FinalizeEditorEntity(entity);
}
else
{
EditorEntityContextNotificationBus::Broadcast(&EditorEntityContextNotification::OnEditorEntityCreated, entity->GetId());
}
FinalizeEditorEntity(entity);
return entity->GetId();
}
@@ -284,10 +271,12 @@ namespace AzToolsFramework
{
return;
}
SetupEditorEntity(entity);
// Store creation undo command.
if (m_isLegacySliceService)
{
SetupEditorEntity(entity);
ScopedUndoBatch undoBatch("Create Entity");
EntityCreateCommand* command = aznew EntityCreateCommand(static_cast<AZ::u64>(entity->GetId()));
@@ -81,6 +81,7 @@ namespace AzToolsFramework
void AddEditorEntity(AZ::Entity* entity) override;
void AddEditorEntities(const EntityList& entities) override;
void HandleEntitiesAdded(const EntityList& entities) override;
void FinalizeEditorEntity(AZ::Entity* entity) override;
bool CloneEditorEntities(const EntityIdList& sourceEntities,
EntityList& resultEntities,
AZ::SliceComponent::EntityIdToEntityIdMap& sourceToCloneEntityIdMap) override;
@@ -142,13 +143,9 @@ namespace AzToolsFramework
}
protected:
void OnContextEntitiesAdded(const EntityList& entities) override;
void OnContextEntityRemoved(const AZ::EntityId& id) override;
// Helper function for creating editor ready entities.
void FinalizeEditorEntity(AZ::Entity* entity);
void SetupEditorEntity(AZ::Entity* entity);
void SetupEditorEntities(const EntityList& entities);
@@ -241,25 +241,34 @@ namespace AzToolsFramework
}
}
void QtEventToAzInputMapper::SetCursorCaptureEnabled(bool enabled)
void QtEventToAzInputMapper::SetCursorMode(AzToolsFramework::CursorInputMode mode)
{
if (m_capturingCursor != enabled)
if (mode != m_cursorMode)
{
m_capturingCursor = enabled;
if (m_capturingCursor)
m_cursorMode = mode;
switch (m_cursorMode)
{
m_mouseDevice->SetSystemCursorState(AzFramework::SystemCursorState::ConstrainedAndHidden);
case CursorInputMode::CursorModeCaptured:
qApp->setOverrideCursor(Qt::BlankCursor);
}
else
{
m_mouseDevice->SetSystemCursorState(AzFramework::SystemCursorState::UnconstrainedAndVisible);
m_mouseDevice->SetSystemCursorState(AzFramework::SystemCursorState::ConstrainedAndHidden);
break;
case CursorInputMode::CursorModeWrapped:
qApp->restoreOverrideCursor();
m_mouseDevice->SetSystemCursorState(AzFramework::SystemCursorState::UnconstrainedAndVisible);
break;
case CursorInputMode::CursorModeNone:
qApp->restoreOverrideCursor();
m_mouseDevice->SetSystemCursorState(AzFramework::SystemCursorState::UnconstrainedAndVisible);
break;
}
}
}
void QtEventToAzInputMapper::SetCursorCaptureEnabled(bool enabled)
{
SetCursorMode(enabled ? CursorInputMode::CursorModeCaptured : CursorInputMode::CursorModeNone);
}
bool QtEventToAzInputMapper::eventFilter(QObject* object, QEvent* event)
{
// Abort if processing isn't enabled.
@@ -436,25 +445,80 @@ namespace AzToolsFramework
return QPoint{ denormalizedX, denormalizedY };
}
void WrapCursorX(const QRect& rect, QPoint& point)
{
if (point.x() < rect.left())
{
point.setX(rect.right() - 1);
}
else if (point.x() > rect.right())
{
point.setX(rect.left() + 1);
}
}
void WrapCursorY(const QRect& rect, QPoint& point)
{
if (point.y() < rect.top())
{
point.setY(rect.bottom() - 1);
}
else if (point.y() > rect.bottom())
{
point.setY(rect.top() + 1);
}
}
void QtEventToAzInputMapper::HandleMouseMoveEvent(const QPoint& globalCursorPosition)
{
const QPoint cursorDelta = globalCursorPosition - m_previousGlobalCursorPosition;
QScreen* screen = m_sourceWidget->screen();
const QRect widgetRect(m_sourceWidget->mapToGlobal(QPoint(0, 0)), m_sourceWidget->size());
m_mouseDevice->m_cursorPositionData2D->m_normalizedPosition =
WidgetPositionToNormalizedPosition(m_sourceWidget->mapFromGlobal(globalCursorPosition));
m_mouseDevice->m_cursorPositionData2D->m_normalizedPositionDelta = WidgetPositionToNormalizedPosition(cursorDelta);
ProcessPendingMouseEvents(cursorDelta);
if (m_capturingCursor)
switch (m_cursorMode)
{
// Reset our cursor position to the previous point
case CursorInputMode::CursorModeCaptured:
AzQtComponents::SetCursorPos(m_previousGlobalCursorPosition);
}
else
{
break;
case CursorInputMode::CursorModeWrappedX:
case CursorInputMode::CursorModeWrappedY:
case CursorInputMode::CursorModeWrapped:
{
QPoint screenPos(globalCursorPosition);
switch (m_cursorMode)
{
case CursorInputMode::CursorModeWrappedX:
WrapCursorX(widgetRect, screenPos);
break;
case CursorInputMode::CursorModeWrappedY:
WrapCursorY(widgetRect, screenPos);
break;
case CursorInputMode::CursorModeWrapped:
WrapCursorX(widgetRect, screenPos);
WrapCursorY(widgetRect, screenPos);
break;
default:
// this should never happen
AZ_Assert(false, "Invalid Curosr Mode: %i.", m_cursorMode);
break;
}
QCursor::setPos(screen, screenPos);
const QPoint screenDelta = globalCursorPosition - screenPos;
m_previousGlobalCursorPosition = globalCursorPosition - screenDelta;
}
break;
case CursorInputMode::CursorModeNone:
m_previousGlobalCursorPosition = globalCursorPosition;
break;
default:
AZ_Assert(false, "Invalid Curosr Mode: %i.", m_cursorMode);
break;
}
ProcessPendingMouseEvents(cursorDelta);
}
void QtEventToAzInputMapper::HandleKeyEvent(QKeyEvent* keyEvent)
@@ -32,6 +32,17 @@ class QWheelEvent;
namespace AzToolsFramework
{
enum class CursorInputMode {
CursorModeNone,
CursorModeCaptured, //!< Sets whether or not the cursor should be constrained to the source widget and invisible.
//!< Internally, this will reset the cursor position after each move event to ensure movement
//!< events don't allow the cursor to escape. This can be used for typical camera controls
//!< like a dolly or rotation, where mouse movement is important but cursor location is not.
CursorModeWrapped, //!< Flags whether the curser is going to wrap around the soruce widget.
CursorModeWrappedX, //!< Flags whether the curser is going to wrap around the soruce widget only on the left and right side.
CursorModeWrappedY //!< Flags whether the curser is going to wrap around the soruce widget only on the top and bottom side.
};
//! Maps events from the Qt input system to synthetic InputChannels in AzFramework
//! that can be used by AzFramework::ViewportControllers.
class QtEventToAzInputMapper final
@@ -56,8 +67,12 @@ namespace AzToolsFramework
//! Internally, this will reset the cursor position after each move event to ensure movement
//! events don't allow the cursor to escape. This can be used for typical camera controls
//! like a dolly or rotation, where mouse movement is important but cursor location is not.
//! @deprecated Use #SetCursorMode()
void SetCursorCaptureEnabled(bool enabled);
//! Set the cursor mode.
void SetCursorMode(AzToolsFramework::CursorInputMode mode);
void SetOverrideCursor(ViewportInteraction::CursorStyleOverride cursorStyleOverride);
void ClearOverrideCursor();
@@ -176,8 +191,8 @@ namespace AzToolsFramework
QWidget* m_sourceWidget;
// Flags whether or not Qt events should currently be processed.
bool m_enabled = true;
// Flags whether or not the cursor is being constrained to the source widget (for invisible mouse movement).
bool m_capturingCursor = false;
// Controls the cursor behavior.
AzToolsFramework::CursorInputMode m_cursorMode = AzToolsFramework::CursorInputMode::CursorModeNone;
// Flags whether the cursor has been overridden.
bool m_overrideCursor = false;
@@ -661,6 +661,7 @@ namespace AzToolsFramework
entityOwningInstance.AddEntity(*entity, entityAlias);
EditorEntityContextRequestBus::Broadcast(&EditorEntityContextRequestBus::Events::HandleEntitiesAdded, EntityList{entity});
EditorEntityContextRequestBus::Broadcast(&EditorEntityContextRequestBus::Events::FinalizeEditorEntity, entity);
AZ::Transform transform = AZ::Transform::CreateIdentity();
transform.SetTranslation(position);
@@ -7,6 +7,7 @@
*/
#pragma once
#include <AzCore/Interface/Interface.h>
#include <AzCore/Asset/AssetManagerBus.h>
#include <AzCore/Component/Component.h>
#include <AzCore/Asset/AssetCommon.h>
@@ -10,12 +10,13 @@
#if !defined(Q_MOC_RUN)
#include <AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#endif
namespace AzToolsFramework
{
using namespace AzToolsFramework::AssetBrowser;
//! Model storing all the files that can be suggested in the Asset Autocompleter for PropertyAssetCtrl
class AssetCompleterModel
: public QAbstractTableModel
@@ -45,7 +46,7 @@ namespace AzToolsFramework
void SetFetchEntryType(AssetBrowserEntry::AssetEntryType entryType);
private:
struct AssetItem
struct AssetItem
{
AZStd::string m_displayName;
AZStd::string m_path;
@@ -44,6 +44,10 @@ namespace UnitTest
QObject::connect(m_inputChannelMapper.get(), &AzToolsFramework::QtEventToAzInputMapper::InputChannelUpdated, m_rootWidget.get(),
[this]([[maybe_unused]] const AzFramework::InputChannel* inputChannel, QEvent* event)
{
if(event == nullptr)
{
return;
}
const QEvent::Type eventType = event->type();
if (eventType == QEvent::Type::MouseButtonPress ||
@@ -96,6 +100,11 @@ namespace UnitTest
m_azChannelEvents.push_back(AzEventInfo(inputChannel));
hasBeenConsumed = m_captureAzEvents;
}
else if (inputChannelId == AzFramework::InputDeviceMouse::SystemCursorPosition)
{
m_azCursorPositions.push_back(*inputChannel.GetCustomData<AzFramework::InputChannel::PositionData2D>());
hasBeenConsumed = m_captureAzEvents;
}
}
else if (AzFramework::InputDeviceKeyboard::IsKeyboardDevice(inputDeviceId))
{
@@ -161,6 +170,7 @@ namespace UnitTest
AZStd::vector<QtEventInfo> m_signalEvents;
AZStd::vector<AzEventInfo> m_azChannelEvents;
AZStd::vector<AZStd::string> m_azTextEvents;
AZStd::vector<AzFramework::InputChannel::PositionData2D> m_azCursorPositions;
bool m_captureAzEvents{ false };
bool m_captureTextEvents{ false };
@@ -512,4 +522,175 @@ namespace UnitTest
return info.param.m_az.GetName();
}
);
struct MouseMoveParam
{
AzToolsFramework::CursorInputMode mode;
int iterations;
QPoint startPos;
QPoint deltaPos;
QPoint expectedPos;
const char* name;
};
class MoveMoveWrapParamQtEventToAzInputMapperFixture
: public QtEventToAzInputMapperFixture
, public ::testing::WithParamInterface<MouseMoveParam>
{
};
TEST_P(MoveMoveWrapParamQtEventToAzInputMapperFixture, DISABLED_MouseMove_NoAzHandlers_VerifyMouseMovementViewport)
{
// setup
const MouseMoveParam mouseMoveParam = GetParam();
AzFramework::InputChannelNotificationBus::Handler::BusConnect();
m_captureAzEvents = true;
m_rootWidget->move(100, 100);
QScreen* screen = m_rootWidget->screen();
MouseMove(m_rootWidget.get(), mouseMoveParam.startPos, QPoint(0, 0));
// given
m_inputChannelMapper->SetCursorMode(mouseMoveParam.mode);
m_azCursorPositions.clear();
for (float i = 0; i < mouseMoveParam.iterations; i++)
{
MouseMove(m_rootWidget.get(), m_rootWidget->mapFromGlobal(QCursor::pos(screen)), (mouseMoveParam.deltaPos / mouseMoveParam.iterations));
}
AZ::Vector2 accumulatedPosition(0.0f,0.0f);
for(const auto& pos: m_azCursorPositions) {
accumulatedPosition += (pos.m_normalizedPositionDelta * AZ::Vector2(aznumeric_cast<float>(WidgetSize.width()), aznumeric_cast<float>(WidgetSize.height())));
}
// validate
const QPoint endPosition = m_rootWidget->mapFromGlobal(QCursor::pos(screen));
EXPECT_NEAR(endPosition.x(), mouseMoveParam.expectedPos.x(), 1.0f);
EXPECT_NEAR(endPosition.y(), mouseMoveParam.expectedPos.y(), 1.0f);
EXPECT_NEAR(accumulatedPosition.GetX(), mouseMoveParam.deltaPos.x(), 1.0f);
EXPECT_NEAR(accumulatedPosition.GetY(), mouseMoveParam.deltaPos.y(), 1.0f);
// cleanup
m_rootWidget->move(0, 0);
m_inputChannelMapper->SetCursorMode(AzToolsFramework::CursorInputMode::CursorModeNone);
AzFramework::InputChannelNotificationBus::Handler::BusDisconnect();
}
INSTANTIATE_TEST_CASE_P(All, MoveMoveWrapParamQtEventToAzInputMapperFixture,
testing::Values(
// verify CursorModeWrappedX wrapping
MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrappedX,
40,
QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() - 20, QtEventToAzInputMapperFixture::WidgetSize.height() / 2),
QPoint(40, 0),
QPoint(20, QtEventToAzInputMapperFixture::WidgetSize.height() / 2),
"CursorModeWrappedX_Test_Right"
},
MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrappedX,
40,
QPoint(20, QtEventToAzInputMapperFixture::WidgetSize.height() / 2),
QPoint(-40, 0),
QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() - 20, QtEventToAzInputMapperFixture::WidgetSize.height()/2),
"CursorModeWrappedX_Test_Left"
},
MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrappedX,
40,
QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, 20),
QPoint(0, -40),
QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, -20),
"CursorModeWrappedX_Test_Top"
},
MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrappedX,
40,
QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, QtEventToAzInputMapperFixture::WidgetSize.height() - 20),
QPoint(0, 40),
QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, QtEventToAzInputMapperFixture::WidgetSize.height() + 20),
"CursorModeWrappedX_Test_Bottom"
},
// verify CursorModeWrappedY wrapping
MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrappedY,
40,
QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() - 20, QtEventToAzInputMapperFixture::WidgetSize.height()/2),
QPoint(40, 0),
QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() + 20, QtEventToAzInputMapperFixture::WidgetSize.height()/2),
"CursorModeWrappedY_Test_Right"
},
MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrappedY,
40,
QPoint(20, QtEventToAzInputMapperFixture::WidgetSize.height() / 2),
QPoint(-40, 0),
QPoint(-20, QtEventToAzInputMapperFixture::WidgetSize.height() / 2),
"CursorModeWrappedY_Test_Left"
},
MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrappedY,
40,
QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, 20),
QPoint(0, -40),
QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, QtEventToAzInputMapperFixture::WidgetSize.height() - 20),
"CursorModeWrappedY_Test_Top"
},
MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrappedY,
40,
QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, QtEventToAzInputMapperFixture::WidgetSize.height() - 20),
QPoint(0, 40),
QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, 20),
"CursorModeWrappedY_Test_Bottom"
},
// verify CursorModeWrapped wrapping
MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrapped,
40,
QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() - 20, QtEventToAzInputMapperFixture::WidgetSize.height()/2),
QPoint(40, 0),
QPoint(20, QtEventToAzInputMapperFixture::WidgetSize.height()/2),
"CursorModeWrapped_Test_Right"
},
MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrapped,
40,
QPoint(20, QtEventToAzInputMapperFixture::WidgetSize.height() / 2),
QPoint(-40, 0),
QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() - 20, QtEventToAzInputMapperFixture::WidgetSize.height()/2),
"CursorModeWrapped_Test_Left"
},
MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrapped,
40,
QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, 20),
QPoint(0, -40),
QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, QtEventToAzInputMapperFixture::WidgetSize.height() - 20),
"CursorModeWrapped_Test_Top"
},
MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeWrapped,
40,
QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, QtEventToAzInputMapperFixture::WidgetSize.height() - 20),
QPoint(0, 40),
QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, 20),
"CursorModeWrapped_Test_Bottom"
},
// verify CursorModeCaptured
MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeCaptured,
40,
QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, QtEventToAzInputMapperFixture::WidgetSize.height() / 2),
QPoint(0, 40),
QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, QtEventToAzInputMapperFixture::WidgetSize.height() / 2),
"CursorModeCaptured"
},
// verify CursorModeNone
MouseMoveParam {AzToolsFramework::CursorInputMode::CursorModeNone,
40,
QPoint(QtEventToAzInputMapperFixture::WidgetSize.width() / 2, QtEventToAzInputMapperFixture::WidgetSize.height() / 2),
QPoint(40, 0),
QPoint((QtEventToAzInputMapperFixture::WidgetSize.width() / 2) + 40, (QtEventToAzInputMapperFixture::WidgetSize.height() / 2)),
"CursorModeNone"
}
),
[](const ::testing::TestParamInfo<MouseMoveParam>& info)
{
return info.param.name;
}
);
} // namespace UnitTest
-1
View File
@@ -614,7 +614,6 @@ struct SSystemGlobalEnvironment
ISystem* pSystem = nullptr;
ILog* pLog;
IMovieSystem* pMovieSystem;
ILyShine* pLyShine;
SharedEnvironmentInstance* pSharedEnvironment;
#if defined(AZ_RESTRICTED_PLATFORM)
@@ -13,6 +13,7 @@
#include <AzCore/Component/ComponentApplication.h>
#include <AzCore/IO/IStreamer.h>
#include <AzCore/IO/Path/Path.h>
#include <AzCore/IO/Streamer/FileRequest.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/Serialization/Utils.h>
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
@@ -18,7 +18,6 @@ ly_add_target(
${pal_source_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
PLATFORM_INCLUDE_FILES
${pal_source_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake
${common_source_dir}/${PAL_TRAIT_COMPILER_ID}/atom_feature_common_${PAL_TRAIT_COMPILER_ID_LOWERCASE}.cmake
INCLUDE_DIRECTORIES
PRIVATE
.
@@ -1,13 +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
#
#
set_source_files_properties(
Source/LuxCore/LuxCoreRenderer.cpp
PROPERTIES
COMPILE_OPTIONS -fexceptions
)
@@ -1,7 +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
#
#
@@ -7,13 +7,16 @@
*/
#pragma once
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/std/parallel/mutex.h>
#include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
#include <Atom/RPI.Reflect/Shader/ShaderVariantAsset.h>
#include <Atom/RPI.Reflect/Shader/ShaderVariantTreeAsset.h>
#include <Atom/RPI.Reflect/Shader/IShaderVariantFinder.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/std/parallel/mutex.h>
#include <AzCore/std/parallel/condition_variable.h>
namespace AZ
{
class ReflectContext;
@@ -10,6 +10,7 @@
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Name/Name.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
namespace AZ
{
@@ -267,7 +267,7 @@ namespace AZ
return m_visScene->GetEntryCount();
}
struct WorklistData
{
CullingDebugContext* m_debugCtx = nullptr;
@@ -296,13 +296,13 @@ namespace AZ
#endif
return worklistData;
}
constexpr size_t WorkListCapacity = 5;
using WorkListType = AZStd::fixed_vector<AzFramework::IVisibilityScene::NodeData, WorkListCapacity>;
#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED
static MaskedOcclusionCulling::CullingResult TestOcclusionCulling(
const AZStd::shared_ptr<WorklistData>& worklistData,
const AZStd::shared_ptr<WorklistData>& worklistData,
AzFramework::VisibilityEntry* visibleEntry);
#endif
@@ -312,7 +312,7 @@ namespace AZ
const View::UsageFlags viewFlags = worklistData->m_view->GetUsageFlags();
const RHI::DrawListMask drawListMask = worklistData->m_view->GetDrawListMask();
uint32_t numDrawPackets = 0;
[[maybe_unused]] uint32_t numDrawPackets = 0;
uint32_t numVisibleCullables = 0;
AZ_Assert(worklist.size() > 0, "Received empty worklist in ProcessWorklist");
@@ -320,8 +320,8 @@ namespace AZ
for (const AzFramework::IVisibilityScene::NodeData& nodeData : worklist)
{
//If a node is entirely contained within the frustum, then we can skip the fine grained culling.
bool nodeIsContainedInFrustum =
!worklistData->m_debugCtx->m_enableFrustumCulling ||
bool nodeIsContainedInFrustum =
!worklistData->m_debugCtx->m_enableFrustumCulling ||
ShapeIntersection::Contains(worklistData->m_frustum, nodeData.m_bounds);
#ifdef AZ_CULL_PROFILE_VERBOSE
@@ -465,7 +465,7 @@ namespace AZ
#if AZ_TRAIT_MASKED_OCCLUSION_CULLING_SUPPORTED
static MaskedOcclusionCulling::CullingResult TestOcclusionCulling(
const AZStd::shared_ptr<WorklistData>& worklistData,
const AZStd::shared_ptr<WorklistData>& worklistData,
AzFramework::VisibilityEntry* visibleEntry)
{
if (!worklistData->m_maskedOcclusionCulling)
@@ -527,9 +527,9 @@ namespace AZ
#endif
void CullingScene::ProcessCullablesCommon(
const Scene& scene [[maybe_unused]],
View& view,
AZ::Frustum& frustum [[maybe_unused]],
const Scene& scene [[maybe_unused]],
View& view,
AZ::Frustum& frustum [[maybe_unused]],
void*& maskedOcclusionCulling [[maybe_unused]])
{
AZ_PROFILE_SCOPE(RPI, "CullingScene::ProcessCullablesCommon() - %s", view.GetName().GetCStr());
@@ -898,7 +898,7 @@ namespace AZ
{
const Matrix4x4& worldToClip = viewPtr->GetWorldToClipMatrix();
Frustum frustum = Frustum::CreateFromMatrixColumnMajor(worldToClip, Frustum::ReverseDepth::True);
m_debugCtx.m_frozenFrustums.insert({ viewPtr.get(), frustum });
m_debugCtx.m_frozenFrustums.insert({ viewPtr.get(), frustum });
}
}
}
@@ -911,7 +911,7 @@ namespace AZ
}
void CullingScene::EndCulling()
{
{
m_cullDataConcurrencyCheck.soft_unlock();
}
@@ -11,13 +11,13 @@
#include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
#include <AzFramework/IO/LocalFileIO.h>
#include <AzCore/Debug/Profiler.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/IO/SystemFile.h>
#include <AzCore/Utils//Utils.h>
#include <AzCore/Serialization/Json/JsonUtils.h>
#include <AzFramework/IO/LocalFileIO.h>
namespace AZ
{
@@ -7,6 +7,8 @@
*/
#include "AssetManagerTestFixture.h"
#include <AzCore/Interface/Interface.h>
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/Memory/PoolAllocator.h>
@@ -332,12 +332,12 @@ namespace AtomToolsFramework
void RenderViewportWidget::BeginCursorCapture()
{
m_inputChannelMapper->SetCursorCaptureEnabled(true);
m_inputChannelMapper->SetCursorMode(AzToolsFramework::CursorInputMode::CursorModeCaptured);
}
void RenderViewportWidget::EndCursorCapture()
{
m_inputChannelMapper->SetCursorCaptureEnabled(false);
m_inputChannelMapper->SetCursorMode(AzToolsFramework::CursorInputMode::CursorModeNone);
}
void RenderViewportWidget::SetOverrideCursor(AzToolsFramework::ViewportInteraction::CursorStyleOverride cursorStyleOverride)
@@ -9,6 +9,7 @@
#include <AzCore/std/containers/unordered_set.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzCore/std/string/string.h>
#include <AzCore/std/parallel/shared_mutex.h>
#include <AzCore/Jobs/JobCompletion.h>
@@ -77,8 +77,7 @@ ly_create_alias(NAME AtomLyIntegration_CommonFeatures.Servers NAMESPACE Gem
if(PAL_TRAIT_BUILD_HOST_TOOLS)
ly_add_target(
NAME AtomLyIntegration_CommonFeatures.Editor GEM_MODULE
NAME AtomLyIntegration_CommonFeatures.Editor.Static STATIC
NAMESPACE Gem
AUTOUIC
AUTOMOC
@@ -98,7 +97,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS)
PRIVATE
ATOMLYINTEGRATION_FEATURE_COMMON_EDITOR
BUILD_DEPENDENCIES
PRIVATE
PUBLIC
Gem::AtomLyIntegration_CommonFeatures.Static
Gem::Atom_RPI.Edit
Gem::AtomToolsFramework.Static
@@ -108,6 +107,24 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS)
Legacy::Editor.Headers
Legacy::EditorCommon
Legacy::CryCommon
)
ly_add_target(
NAME AtomLyIntegration_CommonFeatures.Editor GEM_MODULE
NAMESPACE Gem
FILES_CMAKE
atomlyintegration_commonfeatures_shared_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Source
PUBLIC
Include
COMPILE_DEFINITIONS
PRIVATE
ATOMLYINTEGRATION_FEATURE_COMMON_EDITOR
BUILD_DEPENDENCIES
PRIVATE
Gem::AtomLyIntegration_CommonFeatures.Editor.Static
RUNTIME_DEPENDENCIES
Gem::Atom_RPI.Editor
Gem::Atom_Feature_Common.Editor
@@ -128,6 +145,33 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS)
Gem::AtomLyIntegration_CommonFeatures.Editor
Gem::GradientSignal.Tools
)
################################################################################
# Tests
################################################################################
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
ly_add_target(
NAME AtomLyIntegration_CommonFeatures.Editor.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
NAMESPACE Gem
FILES_CMAKE
atomlyintegration_commonfeatures_editor_test_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Tests
Source
BUILD_DEPENDENCIES
PRIVATE
AZ::AzTest
AZ::AzTestShared
AZ::AzToolsFramework
AZ::AzToolsFrameworkTestCommon
Gem::AtomLyIntegration_CommonFeatures.Static
Gem::AtomLyIntegration_CommonFeatures.Editor.Static
)
ly_add_googletest(
NAME Gem::AtomLyIntegration_CommonFeatures.Editor.Tests
)
endif()
endif()
# AtomLyIntegration_CommonFeatures gem targets are required as part of the Editor and AssetProcessor

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