mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2026-01-15 16:33:15 -03:00
VideoCommon: separate the concept of a 'resource' from an 'asset'. A resource is potentially multiple assets that are chained together but represent one type of data to the rest of the system. An example is a 'material'. A 'material' is a collection of textures, a custom shader, and some metadata that all comes together to form what the concept of the material is. There will be a 'material' resource. For now, start small by introducing the interface and change our texture loading which used assets from the old resource manager, to an actual resource.
This commit is contained in:
@@ -33,12 +33,12 @@
|
||||
#include "IOS/USB/Emulated/Infinity.h"
|
||||
#include "IOS/USB/Emulated/Skylanders/Skylander.h"
|
||||
#include "IOS/USB/USBScanner.h"
|
||||
#include "VideoCommon/Assets/CustomResourceManager.h"
|
||||
#include "VideoCommon/CommandProcessor.h"
|
||||
#include "VideoCommon/Fifo.h"
|
||||
#include "VideoCommon/GeometryShaderManager.h"
|
||||
#include "VideoCommon/PixelEngine.h"
|
||||
#include "VideoCommon/PixelShaderManager.h"
|
||||
#include "VideoCommon/Resources/CustomResourceManager.h"
|
||||
#include "VideoCommon/VertexShaderManager.h"
|
||||
#include "VideoCommon/XFStateManager.h"
|
||||
|
||||
|
||||
@@ -673,10 +673,11 @@
|
||||
<ClInclude Include="VideoCommon\AbstractShader.h" />
|
||||
<ClInclude Include="VideoCommon\AbstractStagingTexture.h" />
|
||||
<ClInclude Include="VideoCommon\AbstractTexture.h" />
|
||||
<ClInclude Include="VideoCommon\Assets\AssetListener.h" />
|
||||
<ClInclude Include="VideoCommon\Assets\CustomAsset.h" />
|
||||
<ClInclude Include="VideoCommon\Assets\CustomAssetCache.h" />
|
||||
<ClInclude Include="VideoCommon\Assets\CustomAssetLibrary.h" />
|
||||
<ClInclude Include="VideoCommon\Assets\CustomAssetLoader.h" />
|
||||
<ClInclude Include="VideoCommon\Assets\CustomResourceManager.h" />
|
||||
<ClInclude Include="VideoCommon\Assets\CustomTextureData.h" />
|
||||
<ClInclude Include="VideoCommon\Assets\DirectFilesystemAssetLibrary.h" />
|
||||
<ClInclude Include="VideoCommon\Assets\MaterialAsset.h" />
|
||||
@@ -752,6 +753,9 @@
|
||||
<ClInclude Include="VideoCommon\PostProcessing.h" />
|
||||
<ClInclude Include="VideoCommon\Present.h" />
|
||||
<ClInclude Include="VideoCommon\RenderState.h" />
|
||||
<ClInclude Include="VideoCommon\Resources\CustomResourceManager.h" />
|
||||
<ClInclude Include="VideoCommon\Resources\Resource.h" />
|
||||
<ClInclude Include="VideoCommon\Resources\TextureDataResource.h" />
|
||||
<ClInclude Include="VideoCommon\ShaderCache.h" />
|
||||
<ClInclude Include="VideoCommon\ShaderCompileUtils.h" />
|
||||
<ClInclude Include="VideoCommon\ShaderGenCommon.h" />
|
||||
@@ -1340,8 +1344,8 @@
|
||||
<ClCompile Include="VideoCommon\AbstractStagingTexture.cpp" />
|
||||
<ClCompile Include="VideoCommon\AbstractTexture.cpp" />
|
||||
<ClCompile Include="VideoCommon\Assets\CustomAsset.cpp" />
|
||||
<ClCompile Include="VideoCommon\Assets\CustomAssetCache.cpp" />
|
||||
<ClCompile Include="VideoCommon\Assets\CustomAssetLoader.cpp" />
|
||||
<ClCompile Include="VideoCommon\Assets\CustomResourceManager.cpp" />
|
||||
<ClCompile Include="VideoCommon\Assets\CustomTextureData.cpp" />
|
||||
<ClCompile Include="VideoCommon\Assets\DirectFilesystemAssetLibrary.cpp" />
|
||||
<ClCompile Include="VideoCommon\Assets\MaterialAsset.cpp" />
|
||||
@@ -1402,6 +1406,9 @@
|
||||
<ClCompile Include="VideoCommon\PostProcessing.cpp" />
|
||||
<ClCompile Include="VideoCommon\Present.cpp" />
|
||||
<ClCompile Include="VideoCommon\RenderState.cpp" />
|
||||
<ClCompile Include="VideoCommon\Resources\CustomResourceManager.cpp" />
|
||||
<ClCompile Include="VideoCommon\Resources\Resource.cpp" />
|
||||
<ClCompile Include="VideoCommon\Resources\TextureDataResource.cpp" />
|
||||
<ClCompile Include="VideoCommon\ShaderCache.cpp" />
|
||||
<ClCompile Include="VideoCommon\ShaderCompileUtils.cpp" />
|
||||
<ClCompile Include="VideoCommon\ShaderGenCommon.cpp" />
|
||||
|
||||
23
Source/Core/VideoCommon/Assets/AssetListener.h
Normal file
23
Source/Core/VideoCommon/Assets/AssetListener.h
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright 2025 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace VideoCommon
|
||||
{
|
||||
class AssetListener
|
||||
{
|
||||
public:
|
||||
AssetListener() = default;
|
||||
virtual ~AssetListener() = default;
|
||||
|
||||
AssetListener(const AssetListener&) = default;
|
||||
AssetListener(AssetListener&&) = default;
|
||||
AssetListener& operator=(const AssetListener&) = default;
|
||||
AssetListener& operator=(AssetListener&&) = default;
|
||||
|
||||
virtual void NotifyAssetLoadSuccess() = 0;
|
||||
virtual void NotifyAssetLoadFailed() = 0;
|
||||
virtual void AssetUnloaded() = 0;
|
||||
};
|
||||
} // namespace VideoCommon
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2025 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "VideoCommon/Assets/CustomResourceManager.h"
|
||||
#include "VideoCommon/Assets/CustomAssetCache.h"
|
||||
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/MemoryUtil.h"
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
namespace VideoCommon
|
||||
{
|
||||
void CustomResourceManager::Initialize()
|
||||
void CustomAssetCache::Initialize()
|
||||
{
|
||||
// Use half of available system memory but leave at least 2GiB unused for system stability.
|
||||
constexpr size_t must_keep_unused = 2 * size_t(1024 * 1024 * 1024);
|
||||
@@ -28,19 +28,16 @@ void CustomResourceManager::Initialize()
|
||||
ERROR_LOG_FMT(VIDEO, "Not enough system memory for custom resources.");
|
||||
|
||||
m_asset_loader.Initialize();
|
||||
|
||||
m_xfb_event =
|
||||
GetVideoEvents().after_frame_event.Register([this](Core::System&) { XFBTriggered(); });
|
||||
}
|
||||
|
||||
void CustomResourceManager::Shutdown()
|
||||
void CustomAssetCache::Shutdown()
|
||||
{
|
||||
Reset();
|
||||
|
||||
m_asset_loader.Shutdown();
|
||||
}
|
||||
|
||||
void CustomResourceManager::Reset()
|
||||
void CustomAssetCache::Reset()
|
||||
{
|
||||
m_asset_loader.Reset(true);
|
||||
|
||||
@@ -48,66 +45,27 @@ void CustomResourceManager::Reset()
|
||||
m_pending_assets = {};
|
||||
m_asset_handle_to_data.clear();
|
||||
m_asset_id_to_handle.clear();
|
||||
m_texture_data_asset_cache.clear();
|
||||
m_dirty_assets.clear();
|
||||
m_ram_used = 0;
|
||||
}
|
||||
|
||||
void CustomResourceManager::MarkAssetDirty(const CustomAssetLibrary::AssetID& asset_id)
|
||||
void CustomAssetCache::MarkAssetDirty(const CustomAssetLibrary::AssetID& asset_id)
|
||||
{
|
||||
std::lock_guard guard(m_dirty_mutex);
|
||||
m_dirty_assets.insert(asset_id);
|
||||
}
|
||||
|
||||
CustomResourceManager::TextureTimePair CustomResourceManager::GetTextureDataFromAsset(
|
||||
const CustomAssetLibrary::AssetID& asset_id,
|
||||
std::shared_ptr<VideoCommon::CustomAssetLibrary> library)
|
||||
void CustomAssetCache::MarkAssetPending(CustomAsset* asset)
|
||||
{
|
||||
auto& resource = m_texture_data_asset_cache[asset_id];
|
||||
if (resource.asset_data != nullptr &&
|
||||
resource.asset_data->load_status == AssetData::LoadStatus::ResourceDataAvailable)
|
||||
{
|
||||
m_active_assets.MakeAssetHighestPriority(resource.asset->GetHandle(), resource.asset);
|
||||
return {resource.texture_data, resource.asset->GetLastLoadedTime()};
|
||||
}
|
||||
|
||||
// If there is an error, don't try and load again until the error is fixed
|
||||
if (resource.asset_data != nullptr && resource.asset_data->has_load_error)
|
||||
return {};
|
||||
|
||||
LoadTextureDataAsset(asset_id, std::move(library), &resource);
|
||||
m_active_assets.MakeAssetHighestPriority(resource.asset->GetHandle(), resource.asset);
|
||||
|
||||
return {};
|
||||
m_pending_assets.MakeAssetHighestPriority(asset->GetHandle(), asset);
|
||||
}
|
||||
|
||||
void CustomResourceManager::LoadTextureDataAsset(
|
||||
const CustomAssetLibrary::AssetID& asset_id,
|
||||
std::shared_ptr<VideoCommon::CustomAssetLibrary> library, InternalTextureDataResource* resource)
|
||||
void CustomAssetCache::MarkAssetActive(CustomAsset* asset)
|
||||
{
|
||||
if (!resource->asset)
|
||||
{
|
||||
resource->asset =
|
||||
CreateAsset<TextureAsset>(asset_id, AssetData::AssetType::TextureData, std::move(library));
|
||||
resource->asset_data = &m_asset_handle_to_data[resource->asset->GetHandle()];
|
||||
}
|
||||
|
||||
auto texture_data = resource->asset->GetData();
|
||||
if (!texture_data || resource->asset_data->load_status == AssetData::LoadStatus::PendingReload)
|
||||
{
|
||||
// Tell the system we are still interested in loading this asset
|
||||
const auto asset_handle = resource->asset->GetHandle();
|
||||
m_pending_assets.MakeAssetHighestPriority(asset_handle,
|
||||
m_asset_handle_to_data[asset_handle].asset.get());
|
||||
}
|
||||
else if (resource->asset_data->load_status == AssetData::LoadStatus::LoadFinished)
|
||||
{
|
||||
resource->texture_data = std::move(texture_data);
|
||||
resource->asset_data->load_status = AssetData::LoadStatus::ResourceDataAvailable;
|
||||
}
|
||||
m_active_assets.MakeAssetHighestPriority(asset->GetHandle(), asset);
|
||||
}
|
||||
|
||||
void CustomResourceManager::XFBTriggered()
|
||||
void CustomAssetCache::Update()
|
||||
{
|
||||
ProcessDirtyAssets();
|
||||
ProcessLoadedAssets();
|
||||
@@ -127,7 +85,7 @@ void CustomResourceManager::XFBTriggered()
|
||||
m_asset_loader.ScheduleAssetsToLoad(m_pending_assets.Elements(), allowed_memory);
|
||||
}
|
||||
|
||||
void CustomResourceManager::ProcessDirtyAssets()
|
||||
void CustomAssetCache::ProcessDirtyAssets()
|
||||
{
|
||||
decltype(m_dirty_assets) dirty_assets;
|
||||
|
||||
@@ -154,7 +112,7 @@ void CustomResourceManager::ProcessDirtyAssets()
|
||||
}
|
||||
}
|
||||
|
||||
void CustomResourceManager::ProcessLoadedAssets()
|
||||
void CustomAssetCache::ProcessLoadedAssets()
|
||||
{
|
||||
const auto load_results = m_asset_loader.TakeLoadResults();
|
||||
|
||||
@@ -189,10 +147,18 @@ void CustomResourceManager::ProcessLoadedAssets()
|
||||
m_active_assets.InsertAsset(handle, asset_data.asset.get());
|
||||
asset_data.load_status = AssetData::LoadStatus::LoadFinished;
|
||||
}
|
||||
|
||||
for (const auto& listener : asset_data.listeners)
|
||||
{
|
||||
if (load_successful)
|
||||
listener->NotifyAssetLoadSuccess();
|
||||
else
|
||||
listener->NotifyAssetLoadFailed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CustomResourceManager::RemoveAssetsUntilBelowMemoryLimit()
|
||||
void CustomAssetCache::RemoveAssetsUntilBelowMemoryLimit()
|
||||
{
|
||||
const u64 threshold_ram = m_max_ram_available * 8 / 10;
|
||||
|
||||
@@ -209,11 +175,11 @@ void CustomResourceManager::RemoveAssetsUntilBelowMemoryLimit()
|
||||
|
||||
AssetData& asset_data = m_asset_handle_to_data[asset->GetHandle()];
|
||||
|
||||
// Remove the resource manager's cached entry with its asset data
|
||||
if (asset_data.type == AssetData::AssetType::TextureData)
|
||||
for (const auto& listener : asset_data.listeners)
|
||||
{
|
||||
m_texture_data_asset_cache.erase(asset->GetAssetId());
|
||||
listener->AssetUnloaded();
|
||||
}
|
||||
|
||||
// Remove the asset's copy
|
||||
const std::size_t bytes_unloaded = asset_data.asset->Unload();
|
||||
m_ram_used -= bytes_unloaded;
|
||||
@@ -10,25 +10,73 @@
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/HookableEvent.h"
|
||||
|
||||
#include "VideoCommon/Assets/AssetListener.h"
|
||||
#include "VideoCommon/Assets/CustomAsset.h"
|
||||
#include "VideoCommon/Assets/CustomAssetLibrary.h"
|
||||
#include "VideoCommon/Assets/CustomAssetLoader.h"
|
||||
#include "VideoCommon/Assets/CustomTextureData.h"
|
||||
|
||||
namespace VideoCommon
|
||||
{
|
||||
class TextureAsset;
|
||||
|
||||
// The resource manager manages custom resources (textures, shaders, meshes)
|
||||
// called assets. These assets are loaded using a priority system,
|
||||
// The asset cache manages custom assets (textures, shaders, meshes).
|
||||
// These assets are loaded using a priority system,
|
||||
// where assets requested more often gets loaded first. This system
|
||||
// also tracks memory usage and if memory usage goes over a calculated limit,
|
||||
// then assets will be purged with older assets being targeted first.
|
||||
class CustomResourceManager
|
||||
class CustomAssetCache
|
||||
{
|
||||
public:
|
||||
// A generic interface to describe an asset
|
||||
// and load state
|
||||
struct AssetData
|
||||
{
|
||||
std::unique_ptr<CustomAsset> asset;
|
||||
|
||||
std::vector<AssetListener*> listeners;
|
||||
|
||||
CustomAsset::TimeType load_request_time = {};
|
||||
bool has_load_error = false;
|
||||
|
||||
enum class LoadStatus
|
||||
{
|
||||
PendingReload,
|
||||
LoadFinished,
|
||||
Unloaded,
|
||||
};
|
||||
LoadStatus load_status = LoadStatus::PendingReload;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
T* CreateAsset(const CustomAssetLibrary::AssetID& asset_id,
|
||||
std::shared_ptr<VideoCommon::CustomAssetLibrary> library, AssetListener* listener)
|
||||
{
|
||||
const auto [it, added] =
|
||||
m_asset_id_to_handle.try_emplace(asset_id, m_asset_handle_to_data.size());
|
||||
if (added)
|
||||
{
|
||||
AssetData asset_data;
|
||||
asset_data.asset = std::make_unique<T>(std::move(library), asset_id, it->second);
|
||||
asset_data.load_request_time = {};
|
||||
asset_data.has_load_error = false;
|
||||
|
||||
m_asset_handle_to_data.insert_or_assign(it->second, std::move(asset_data));
|
||||
}
|
||||
|
||||
auto& asset_data_from_handle = m_asset_handle_to_data[it->second];
|
||||
asset_data_from_handle.listeners.push_back(listener);
|
||||
asset_data_from_handle.load_status = AssetData::LoadStatus::PendingReload;
|
||||
|
||||
return static_cast<T*>(asset_data_from_handle.asset.get());
|
||||
}
|
||||
|
||||
AssetData* GetAssetData(const CustomAssetLibrary::AssetID& asset_id)
|
||||
{
|
||||
const auto it_handle = m_asset_id_to_handle.find(asset_id);
|
||||
if (it_handle == m_asset_id_to_handle.end())
|
||||
return nullptr;
|
||||
return &m_asset_handle_to_data[it_handle->second];
|
||||
}
|
||||
|
||||
void Initialize();
|
||||
void Shutdown();
|
||||
|
||||
@@ -37,81 +85,21 @@ public:
|
||||
// Request that an asset be reloaded
|
||||
void MarkAssetDirty(const CustomAssetLibrary::AssetID& asset_id);
|
||||
|
||||
void XFBTriggered();
|
||||
// Notify the system that we are interested in this asset and
|
||||
// are waiting for it to be loaded
|
||||
void MarkAssetPending(CustomAsset* asset);
|
||||
|
||||
using TextureTimePair = std::pair<std::shared_ptr<CustomTextureData>, CustomAsset::TimeType>;
|
||||
// Notify the system we are interested in this asset and
|
||||
// it has seen activity
|
||||
void MarkAssetActive(CustomAsset* asset);
|
||||
|
||||
// Returns a pair with the custom texture data and the time it was last loaded
|
||||
// Callees are not expected to hold onto the shared_ptr as that will prevent
|
||||
// the resource manager from being able to properly release data
|
||||
TextureTimePair GetTextureDataFromAsset(const CustomAssetLibrary::AssetID& asset_id,
|
||||
std::shared_ptr<VideoCommon::CustomAssetLibrary> library);
|
||||
void Update();
|
||||
|
||||
private:
|
||||
// A generic interface to describe an assets' type
|
||||
// and load state
|
||||
struct AssetData
|
||||
{
|
||||
std::unique_ptr<CustomAsset> asset;
|
||||
CustomAsset::TimeType load_request_time = {};
|
||||
bool has_load_error = false;
|
||||
|
||||
enum class AssetType
|
||||
{
|
||||
TextureData
|
||||
};
|
||||
AssetType type;
|
||||
|
||||
enum class LoadStatus
|
||||
{
|
||||
PendingReload,
|
||||
LoadFinished,
|
||||
ResourceDataAvailable,
|
||||
Unloaded,
|
||||
};
|
||||
LoadStatus load_status = LoadStatus::PendingReload;
|
||||
};
|
||||
|
||||
// A structure to represent some raw texture data
|
||||
// (this data hasn't hit the GPU yet, used for custom textures)
|
||||
struct InternalTextureDataResource
|
||||
{
|
||||
AssetData* asset_data = nullptr;
|
||||
VideoCommon::TextureAsset* asset = nullptr;
|
||||
std::shared_ptr<CustomTextureData> texture_data;
|
||||
};
|
||||
|
||||
void LoadTextureDataAsset(const CustomAssetLibrary::AssetID& asset_id,
|
||||
std::shared_ptr<VideoCommon::CustomAssetLibrary> library,
|
||||
InternalTextureDataResource* resource);
|
||||
|
||||
void ProcessDirtyAssets();
|
||||
void ProcessLoadedAssets();
|
||||
void RemoveAssetsUntilBelowMemoryLimit();
|
||||
|
||||
template <typename T>
|
||||
T* CreateAsset(const CustomAssetLibrary::AssetID& asset_id, AssetData::AssetType asset_type,
|
||||
std::shared_ptr<VideoCommon::CustomAssetLibrary> library)
|
||||
{
|
||||
const auto [it, added] =
|
||||
m_asset_id_to_handle.try_emplace(asset_id, m_asset_handle_to_data.size());
|
||||
|
||||
if (added)
|
||||
{
|
||||
AssetData asset_data;
|
||||
asset_data.asset = std::make_unique<T>(library, asset_id, it->second);
|
||||
asset_data.type = asset_type;
|
||||
asset_data.load_request_time = {};
|
||||
asset_data.has_load_error = false;
|
||||
|
||||
m_asset_handle_to_data.insert_or_assign(it->second, std::move(asset_data));
|
||||
}
|
||||
auto& asset_data_from_handle = m_asset_handle_to_data[it->second];
|
||||
asset_data_from_handle.load_status = AssetData::LoadStatus::PendingReload;
|
||||
|
||||
return static_cast<T*>(asset_data_from_handle.asset.get());
|
||||
}
|
||||
|
||||
// Maintains a priority-sorted list of assets.
|
||||
// Used to figure out which assets to load or unload first.
|
||||
// Most recently used assets get marked with highest priority.
|
||||
@@ -202,14 +190,10 @@ private:
|
||||
// A calculated amount of memory to avoid exceeding.
|
||||
u64 m_max_ram_available = 0;
|
||||
|
||||
std::map<CustomAssetLibrary::AssetID, InternalTextureDataResource> m_texture_data_asset_cache;
|
||||
|
||||
std::mutex m_dirty_mutex;
|
||||
std::set<CustomAssetLibrary::AssetID> m_dirty_assets;
|
||||
|
||||
CustomAssetLoader m_asset_loader;
|
||||
|
||||
Common::EventHook m_xfb_event;
|
||||
};
|
||||
|
||||
} // namespace VideoCommon
|
||||
@@ -14,13 +14,13 @@
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Core/System.h"
|
||||
#include "VideoCommon/Assets/CustomResourceManager.h"
|
||||
#include "VideoCommon/Assets/MaterialAsset.h"
|
||||
#include "VideoCommon/Assets/MeshAsset.h"
|
||||
#include "VideoCommon/Assets/ShaderAsset.h"
|
||||
#include "VideoCommon/Assets/TextureAsset.h"
|
||||
#include "VideoCommon/Assets/TextureAssetUtils.h"
|
||||
#include "VideoCommon/RenderState.h"
|
||||
#include "VideoCommon/Resources/CustomResourceManager.h"
|
||||
|
||||
namespace VideoCommon
|
||||
{
|
||||
|
||||
@@ -8,13 +8,14 @@ add_library(videocommon
|
||||
AbstractStagingTexture.h
|
||||
AbstractTexture.cpp
|
||||
AbstractTexture.h
|
||||
Assets/AssetListener.h
|
||||
Assets/CustomAsset.cpp
|
||||
Assets/CustomAsset.h
|
||||
Assets/CustomAssetCache.cpp
|
||||
Assets/CustomAssetCache.h
|
||||
Assets/CustomAssetLibrary.h
|
||||
Assets/CustomAssetLoader.cpp
|
||||
Assets/CustomAssetLoader.h
|
||||
Assets/CustomResourceManager.cpp
|
||||
Assets/CustomResourceManager.h
|
||||
Assets/CustomTextureData.cpp
|
||||
Assets/CustomTextureData.h
|
||||
Assets/DirectFilesystemAssetLibrary.cpp
|
||||
@@ -145,6 +146,12 @@ add_library(videocommon
|
||||
Present.h
|
||||
RenderState.cpp
|
||||
RenderState.h
|
||||
Resources/CustomResourceManager.cpp
|
||||
Resources/CustomResourceManager.h
|
||||
Resources/Resource.cpp
|
||||
Resources/Resource.h
|
||||
Resources/TextureDataResource.cpp
|
||||
Resources/TextureDataResource.h
|
||||
ShaderCache.cpp
|
||||
ShaderCache.h
|
||||
ShaderCompileUtils.cpp
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "VideoCommon/Assets/CustomAsset.h"
|
||||
#include "VideoCommon/Assets/DirectFilesystemAssetLibrary.h"
|
||||
#include "VideoCommon/OnScreenDisplay.h"
|
||||
#include "VideoCommon/Resources/CustomResourceManager.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
constexpr std::string_view s_format_prefix{"tex1_"};
|
||||
@@ -191,7 +192,7 @@ HiresTexture::HiresTexture(bool has_arbitrary_mipmaps, std::string id)
|
||||
{
|
||||
}
|
||||
|
||||
VideoCommon::CustomResourceManager::TextureTimePair HiresTexture::LoadTexture() const
|
||||
VideoCommon::TextureDataResource* HiresTexture::LoadTexture() const
|
||||
{
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& custom_resource_manager = system.GetCustomResourceManager();
|
||||
|
||||
@@ -8,12 +8,13 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "VideoCommon/Assets/CustomResourceManager.h"
|
||||
#include "VideoCommon/Assets/CustomTextureData.h"
|
||||
#include "VideoCommon/TextureConfig.h"
|
||||
#include "VideoCommon/TextureInfo.h"
|
||||
|
||||
namespace VideoCommon
|
||||
{
|
||||
class TextureDataResource;
|
||||
}
|
||||
|
||||
enum class TextureFormat;
|
||||
|
||||
std::set<std::string> GetTextureDirectoriesWithGameId(const std::string& root_directory,
|
||||
@@ -30,7 +31,7 @@ public:
|
||||
HiresTexture(bool has_arbitrary_mipmaps, std::string id);
|
||||
|
||||
bool HasArbitraryMipmaps() const { return m_has_arbitrary_mipmaps; }
|
||||
VideoCommon::CustomResourceManager::TextureTimePair LoadTexture() const;
|
||||
VideoCommon::TextureDataResource* LoadTexture() const;
|
||||
const std::string& GetId() const { return m_id; }
|
||||
|
||||
private:
|
||||
|
||||
124
Source/Core/VideoCommon/Resources/CustomResourceManager.cpp
Normal file
124
Source/Core/VideoCommon/Resources/CustomResourceManager.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
// Copyright 2025 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "VideoCommon/Resources/CustomResourceManager.h"
|
||||
|
||||
#include "VideoCommon/VideoEvents.h"
|
||||
|
||||
namespace VideoCommon
|
||||
{
|
||||
void CustomResourceManager::Initialize()
|
||||
{
|
||||
m_asset_cache.Initialize();
|
||||
|
||||
m_xfb_event =
|
||||
AfterFrameEvent::Register([this](Core::System&) { XFBTriggered(); }, "CustomResourceManager");
|
||||
}
|
||||
|
||||
void CustomResourceManager::Shutdown()
|
||||
{
|
||||
m_asset_cache.Shutdown();
|
||||
Reset();
|
||||
}
|
||||
|
||||
void CustomResourceManager::Reset()
|
||||
{
|
||||
m_texture_data_resources.clear();
|
||||
|
||||
m_asset_cache.Reset();
|
||||
}
|
||||
|
||||
void CustomResourceManager::MarkAssetDirty(const CustomAssetLibrary::AssetID& asset_id)
|
||||
{
|
||||
m_asset_cache.MarkAssetDirty(asset_id);
|
||||
}
|
||||
|
||||
void CustomResourceManager::XFBTriggered()
|
||||
{
|
||||
m_asset_cache.Update();
|
||||
}
|
||||
|
||||
TextureDataResource* CustomResourceManager::GetTextureDataFromAsset(
|
||||
const CustomAssetLibrary::AssetID& asset_id,
|
||||
std::shared_ptr<VideoCommon::CustomAssetLibrary> library)
|
||||
{
|
||||
const auto [it, added] = m_texture_data_resources.try_emplace(asset_id, nullptr);
|
||||
if (added)
|
||||
{
|
||||
it->second = std::make_unique<TextureDataResource>(CreateResourceContext(asset_id, library));
|
||||
}
|
||||
ProcessResource(it->second.get());
|
||||
return it->second.get();
|
||||
}
|
||||
|
||||
Resource::ResourceContext CustomResourceManager::CreateResourceContext(
|
||||
const CustomAssetLibrary::AssetID& asset_id,
|
||||
const std::shared_ptr<VideoCommon::CustomAssetLibrary>& library)
|
||||
{
|
||||
return Resource::ResourceContext{asset_id, library, &m_asset_cache, this};
|
||||
}
|
||||
|
||||
void CustomResourceManager::ProcessResource(Resource* resource)
|
||||
{
|
||||
resource->MarkAsActive();
|
||||
|
||||
const auto data_processed = resource->IsDataProcessed();
|
||||
if (data_processed == Resource::TaskComplete::Yes ||
|
||||
data_processed == Resource::TaskComplete::Error)
|
||||
{
|
||||
resource->MarkAsActive();
|
||||
if (data_processed == Resource::TaskComplete::Error)
|
||||
return;
|
||||
}
|
||||
|
||||
// Early out if we're already at our end state
|
||||
if (resource->GetState() == Resource::State::DataAvailable)
|
||||
return;
|
||||
|
||||
ProcessResourceState(resource);
|
||||
}
|
||||
|
||||
void CustomResourceManager::ProcessResourceState(Resource* resource)
|
||||
{
|
||||
Resource::State next_state = resource->GetState();
|
||||
Resource::TaskComplete task_complete = Resource::TaskComplete::No;
|
||||
switch (resource->GetState())
|
||||
{
|
||||
case Resource::State::ReloadData:
|
||||
resource->ResetData();
|
||||
task_complete = Resource::TaskComplete::Yes;
|
||||
next_state = Resource::State::CollectingPrimaryData;
|
||||
break;
|
||||
case Resource::State::CollectingPrimaryData:
|
||||
task_complete = resource->CollectPrimaryData();
|
||||
next_state = Resource::State::CollectingDependencyData;
|
||||
if (task_complete == Resource::TaskComplete::No)
|
||||
resource->MarkAsPending();
|
||||
break;
|
||||
case Resource::State::CollectingDependencyData:
|
||||
task_complete = resource->CollectDependencyData();
|
||||
next_state = Resource::State::ProcessingData;
|
||||
break;
|
||||
case Resource::State::ProcessingData:
|
||||
task_complete = resource->ProcessData();
|
||||
next_state = Resource::State::DataAvailable;
|
||||
};
|
||||
|
||||
if (task_complete == Resource::TaskComplete::Yes)
|
||||
{
|
||||
resource->m_state = next_state;
|
||||
if (next_state == Resource::State::DataAvailable)
|
||||
{
|
||||
resource->m_data_processed = task_complete;
|
||||
}
|
||||
else
|
||||
{
|
||||
ProcessResourceState(resource);
|
||||
}
|
||||
}
|
||||
else if (task_complete == Resource::TaskComplete::Error)
|
||||
{
|
||||
resource->m_data_processed = task_complete;
|
||||
}
|
||||
}
|
||||
} // namespace VideoCommon
|
||||
46
Source/Core/VideoCommon/Resources/CustomResourceManager.h
Normal file
46
Source/Core/VideoCommon/Resources/CustomResourceManager.h
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright 2025 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
#include "Common/HookableEvent.h"
|
||||
|
||||
#include "VideoCommon/Assets/CustomAssetCache.h"
|
||||
#include "VideoCommon/Resources/TextureDataResource.h"
|
||||
|
||||
namespace VideoCommon
|
||||
{
|
||||
class CustomResourceManager
|
||||
{
|
||||
public:
|
||||
void Initialize();
|
||||
void Shutdown();
|
||||
|
||||
void Reset();
|
||||
|
||||
// Request that an asset be reloaded
|
||||
void MarkAssetDirty(const CustomAssetLibrary::AssetID& asset_id);
|
||||
|
||||
void XFBTriggered();
|
||||
|
||||
TextureDataResource*
|
||||
GetTextureDataFromAsset(const CustomAssetLibrary::AssetID& asset_id,
|
||||
std::shared_ptr<VideoCommon::CustomAssetLibrary> library);
|
||||
|
||||
private:
|
||||
Resource::ResourceContext
|
||||
CreateResourceContext(const CustomAssetLibrary::AssetID& asset_id,
|
||||
const std::shared_ptr<VideoCommon::CustomAssetLibrary>& library);
|
||||
void ProcessResource(Resource* resource);
|
||||
void ProcessResourceState(Resource* resource);
|
||||
CustomAssetCache m_asset_cache;
|
||||
|
||||
std::map<CustomAssetLibrary::AssetID, std::unique_ptr<TextureDataResource>>
|
||||
m_texture_data_resources;
|
||||
|
||||
Common::EventHook m_xfb_event;
|
||||
};
|
||||
} // namespace VideoCommon
|
||||
81
Source/Core/VideoCommon/Resources/Resource.cpp
Normal file
81
Source/Core/VideoCommon/Resources/Resource.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
// Copyright 2025 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "VideoCommon/Resources/Resource.h"
|
||||
|
||||
namespace VideoCommon
|
||||
{
|
||||
Resource::Resource(ResourceContext resource_context)
|
||||
: m_resource_context(std::move(resource_context))
|
||||
{
|
||||
}
|
||||
|
||||
void Resource::NotifyAssetChanged(bool has_error)
|
||||
{
|
||||
m_data_processed = has_error ? TaskComplete::Error : TaskComplete::No;
|
||||
m_state = State::ReloadData;
|
||||
|
||||
for (Resource* reference : m_references)
|
||||
{
|
||||
reference->NotifyAssetChanged(has_error);
|
||||
}
|
||||
}
|
||||
|
||||
void Resource::NotifyAssetUnloaded()
|
||||
{
|
||||
OnUnloadRequested();
|
||||
|
||||
for (Resource* reference : m_references)
|
||||
{
|
||||
reference->NotifyAssetUnloaded();
|
||||
}
|
||||
}
|
||||
|
||||
void Resource::AddReference(Resource* reference)
|
||||
{
|
||||
m_references.insert(reference);
|
||||
}
|
||||
|
||||
void Resource::RemoveReference(Resource* reference)
|
||||
{
|
||||
m_references.erase(reference);
|
||||
}
|
||||
|
||||
void Resource::NotifyAssetLoadSuccess()
|
||||
{
|
||||
NotifyAssetChanged(false);
|
||||
}
|
||||
|
||||
void Resource::NotifyAssetLoadFailed()
|
||||
{
|
||||
NotifyAssetChanged(true);
|
||||
}
|
||||
|
||||
void Resource::AssetUnloaded()
|
||||
{
|
||||
NotifyAssetUnloaded();
|
||||
}
|
||||
|
||||
void Resource::OnUnloadRequested()
|
||||
{
|
||||
}
|
||||
|
||||
void Resource::ResetData()
|
||||
{
|
||||
}
|
||||
|
||||
Resource::TaskComplete Resource::CollectPrimaryData()
|
||||
{
|
||||
return TaskComplete::Yes;
|
||||
}
|
||||
|
||||
Resource::TaskComplete Resource::CollectDependencyData()
|
||||
{
|
||||
return TaskComplete::Yes;
|
||||
}
|
||||
|
||||
Resource::TaskComplete Resource::ProcessData()
|
||||
{
|
||||
return TaskComplete::Yes;
|
||||
}
|
||||
} // namespace VideoCommon
|
||||
82
Source/Core/VideoCommon/Resources/Resource.h
Normal file
82
Source/Core/VideoCommon/Resources/Resource.h
Normal file
@@ -0,0 +1,82 @@
|
||||
// Copyright 2025 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "VideoCommon/Assets/AssetListener.h"
|
||||
#include "VideoCommon/Assets/CustomAssetLibrary.h"
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_set>
|
||||
|
||||
class AbstractTexture;
|
||||
namespace VideoCommon
|
||||
{
|
||||
class CustomAssetCache;
|
||||
class CustomResourceManager;
|
||||
|
||||
// A resource is an abstract object that maintains
|
||||
// relationships between assets (ex: a material that references a texture),
|
||||
// as well as a standard way of calculating the final data (ex: a material's AbstractPipeline)
|
||||
class Resource : public AssetListener
|
||||
{
|
||||
public:
|
||||
// Everything the resource needs to manage itself
|
||||
struct ResourceContext
|
||||
{
|
||||
CustomAssetLibrary::AssetID primary_asset_id;
|
||||
std::shared_ptr<CustomAssetLibrary> asset_library;
|
||||
CustomAssetCache* asset_cache;
|
||||
CustomResourceManager* resource_manager;
|
||||
};
|
||||
explicit Resource(ResourceContext resource_context);
|
||||
|
||||
enum class TaskComplete
|
||||
{
|
||||
Yes,
|
||||
No,
|
||||
Error,
|
||||
};
|
||||
|
||||
enum class State
|
||||
{
|
||||
ReloadData,
|
||||
CollectingPrimaryData,
|
||||
CollectingDependencyData,
|
||||
ProcessingData,
|
||||
DataAvailable,
|
||||
};
|
||||
|
||||
TaskComplete IsDataProcessed() const { return m_data_processed; }
|
||||
State GetState() const { return m_state; }
|
||||
|
||||
void AddReference(Resource* reference);
|
||||
void RemoveReference(Resource* reference);
|
||||
|
||||
virtual void MarkAsActive() = 0;
|
||||
virtual void MarkAsPending() = 0;
|
||||
|
||||
protected:
|
||||
ResourceContext m_resource_context;
|
||||
|
||||
private:
|
||||
void NotifyAssetChanged(bool has_error);
|
||||
void NotifyAssetUnloaded();
|
||||
|
||||
void NotifyAssetLoadSuccess() final;
|
||||
void NotifyAssetLoadFailed() final;
|
||||
void AssetUnloaded() final;
|
||||
virtual void OnUnloadRequested();
|
||||
|
||||
friend class CustomResourceManager;
|
||||
virtual void ResetData();
|
||||
virtual TaskComplete CollectPrimaryData();
|
||||
virtual TaskComplete CollectDependencyData();
|
||||
virtual TaskComplete ProcessData();
|
||||
|
||||
TaskComplete m_data_processed = TaskComplete::No;
|
||||
State m_state = State::ReloadData;
|
||||
|
||||
std::unordered_set<Resource*> m_references;
|
||||
};
|
||||
} // namespace VideoCommon
|
||||
48
Source/Core/VideoCommon/Resources/TextureDataResource.cpp
Normal file
48
Source/Core/VideoCommon/Resources/TextureDataResource.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright 2025 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "VideoCommon/Resources/TextureDataResource.h"
|
||||
|
||||
#include "VideoCommon/Assets/CustomAssetCache.h"
|
||||
|
||||
namespace VideoCommon
|
||||
{
|
||||
TextureDataResource::TextureDataResource(Resource::ResourceContext resource_context)
|
||||
: Resource(std::move(resource_context))
|
||||
{
|
||||
m_texture_asset = m_resource_context.asset_cache->CreateAsset<TextureAsset>(
|
||||
m_resource_context.primary_asset_id, m_resource_context.asset_library, this);
|
||||
}
|
||||
|
||||
std::shared_ptr<CustomTextureData> TextureDataResource::GetData() const
|
||||
{
|
||||
return m_current_texture_data;
|
||||
}
|
||||
|
||||
CustomAsset::TimeType TextureDataResource::GetLoadTime() const
|
||||
{
|
||||
return m_current_time;
|
||||
}
|
||||
|
||||
Resource::TaskComplete TextureDataResource::CollectPrimaryData()
|
||||
{
|
||||
const auto last_load_time = m_texture_asset->GetLastLoadedTime();
|
||||
const auto asset = m_texture_asset->GetData();
|
||||
if (!asset)
|
||||
return Resource::TaskComplete::No;
|
||||
|
||||
m_current_texture_data = asset;
|
||||
m_current_time = last_load_time;
|
||||
return Resource::TaskComplete::Yes;
|
||||
}
|
||||
|
||||
void TextureDataResource::MarkAsActive()
|
||||
{
|
||||
m_resource_context.asset_cache->MarkAssetActive(m_texture_asset);
|
||||
}
|
||||
|
||||
void TextureDataResource::MarkAsPending()
|
||||
{
|
||||
m_resource_context.asset_cache->MarkAssetPending(m_texture_asset);
|
||||
}
|
||||
} // namespace VideoCommon
|
||||
33
Source/Core/VideoCommon/Resources/TextureDataResource.h
Normal file
33
Source/Core/VideoCommon/Resources/TextureDataResource.h
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright 2025 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "VideoCommon/Resources/Resource.h"
|
||||
|
||||
#include "VideoCommon/Assets/CustomTextureData.h"
|
||||
#include "VideoCommon/Assets/TextureAsset.h"
|
||||
|
||||
namespace VideoCommon
|
||||
{
|
||||
class TextureDataResource final : public Resource
|
||||
{
|
||||
public:
|
||||
explicit TextureDataResource(Resource::ResourceContext resource_context);
|
||||
|
||||
std::shared_ptr<CustomTextureData> GetData() const;
|
||||
CustomAsset::TimeType GetLoadTime() const;
|
||||
|
||||
void MarkAsActive() override;
|
||||
void MarkAsPending() override;
|
||||
|
||||
private:
|
||||
TaskComplete CollectPrimaryData() override;
|
||||
|
||||
// Note: asset cache owns the asset, we access as a reference
|
||||
TextureAsset* m_texture_asset = nullptr;
|
||||
|
||||
std::shared_ptr<CustomTextureData> m_current_texture_data;
|
||||
CustomAsset::TimeType m_current_time = {};
|
||||
};
|
||||
} // namespace VideoCommon
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "VideoCommon/TextureCacheBase.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
@@ -37,7 +38,6 @@
|
||||
#include "VideoCommon/AbstractFramebuffer.h"
|
||||
#include "VideoCommon/AbstractGfx.h"
|
||||
#include "VideoCommon/AbstractStagingTexture.h"
|
||||
#include "VideoCommon/Assets/CustomResourceManager.h"
|
||||
#include "VideoCommon/Assets/CustomTextureData.h"
|
||||
#include "VideoCommon/Assets/TextureAssetUtils.h"
|
||||
#include "VideoCommon/BPMemory.h"
|
||||
@@ -48,6 +48,7 @@
|
||||
#include "VideoCommon/OpcodeDecoding.h"
|
||||
#include "VideoCommon/PixelShaderManager.h"
|
||||
#include "VideoCommon/Present.h"
|
||||
#include "VideoCommon/Resources/CustomResourceManager.h"
|
||||
#include "VideoCommon/ShaderCache.h"
|
||||
#include "VideoCommon/Statistics.h"
|
||||
#include "VideoCommon/TMEM.h"
|
||||
@@ -266,9 +267,9 @@ bool TextureCacheBase::DidLinkedAssetsChange(const TCacheEntry& entry)
|
||||
if (!entry.hires_texture)
|
||||
return false;
|
||||
|
||||
const auto [texture_data, load_time] = entry.hires_texture->LoadTexture();
|
||||
const auto* resource = entry.hires_texture->LoadTexture();
|
||||
|
||||
return load_time > entry.last_load_time;
|
||||
return resource->GetLoadTime() > entry.last_load_time;
|
||||
}
|
||||
|
||||
RcTcacheEntry TextureCacheBase::ApplyPaletteToEntry(RcTcacheEntry& entry, const u8* palette,
|
||||
@@ -1569,7 +1570,9 @@ RcTcacheEntry TextureCacheBase::GetTexture(const int textureCacheSafetyColorSamp
|
||||
if (hires_texture)
|
||||
{
|
||||
has_arbitrary_mipmaps = hires_texture->HasArbitraryMipmaps();
|
||||
std::tie(custom_texture_data, load_time) = hires_texture->LoadTexture();
|
||||
const auto resource = hires_texture->LoadTexture();
|
||||
load_time = resource->GetLoadTime();
|
||||
custom_texture_data = resource->GetData();
|
||||
if (custom_texture_data && !VideoCommon::ValidateTextureData(
|
||||
hires_texture->GetId(), *custom_texture_data,
|
||||
texture_info.GetRawWidth(), texture_info.GetRawHeight()))
|
||||
|
||||
@@ -43,7 +43,6 @@
|
||||
#endif
|
||||
|
||||
#include "VideoCommon/AbstractGfx.h"
|
||||
#include "VideoCommon/Assets/CustomResourceManager.h"
|
||||
#include "VideoCommon/AsyncRequests.h"
|
||||
#include "VideoCommon/BPStructs.h"
|
||||
#include "VideoCommon/BoundingBox.h"
|
||||
@@ -59,6 +58,7 @@
|
||||
#include "VideoCommon/PixelEngine.h"
|
||||
#include "VideoCommon/PixelShaderManager.h"
|
||||
#include "VideoCommon/Present.h"
|
||||
#include "VideoCommon/Resources/CustomResourceManager.h"
|
||||
#include "VideoCommon/TMEM.h"
|
||||
#include "VideoCommon/TextureCacheBase.h"
|
||||
#include "VideoCommon/VertexLoaderManager.h"
|
||||
|
||||
Reference in New Issue
Block a user