Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #11876 from iwubcode/directfilesystem_asset_library
VideoCommon: add  an asset library that loads directly from the filesystem
  • Loading branch information
AdmiralCurtiss committed Jun 2, 2023
2 parents 6028c05 + 07307ed commit 4ee2740
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Source/Core/DolphinLib.props
Expand Up @@ -634,6 +634,7 @@
<ClInclude Include="VideoCommon\Assets\CustomAsset.h" />
<ClInclude Include="VideoCommon\Assets\CustomAssetLibrary.h" />
<ClInclude Include="VideoCommon\Assets\CustomTextureData.h" />
<ClInclude Include="VideoCommon\Assets\DirectFilesystemAssetLibrary.h" />
<ClInclude Include="VideoCommon\AsyncRequests.h" />
<ClInclude Include="VideoCommon\AsyncShaderCompiler.h" />
<ClInclude Include="VideoCommon\BoundingBox.h" />
Expand Down Expand Up @@ -1246,6 +1247,7 @@
<ClCompile Include="VideoCommon\Assets\CustomAsset.cpp" />
<ClCompile Include="VideoCommon\Assets\CustomAssetLibrary.cpp" />
<ClCompile Include="VideoCommon\Assets\CustomTextureData.cpp" />
<ClCompile Include="VideoCommon\Assets\DirectFilesystemAssetLibrary.cpp" />
<ClCompile Include="VideoCommon\AsyncRequests.cpp" />
<ClCompile Include="VideoCommon\AsyncShaderCompiler.cpp" />
<ClCompile Include="VideoCommon\BoundingBox.cpp" />
Expand Down
145 changes: 145 additions & 0 deletions Source/Core/VideoCommon/Assets/DirectFilesystemAssetLibrary.cpp
@@ -0,0 +1,145 @@
// Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "VideoCommon/Assets/DirectFilesystemAssetLibrary.h"

#include <algorithm>

#include "Common/FileUtil.h"
#include "Common/Logging/Log.h"
#include "Common/StringUtil.h"
#include "VideoCommon/Assets/CustomTextureData.h"

namespace VideoCommon
{
namespace
{
std::size_t GetAssetSize(const CustomTextureData& data)
{
std::size_t total = 0;
for (const auto& level : data.m_levels)
{
total += level.data.size();
}
return total;
}
} // namespace
CustomAssetLibrary::TimeType
DirectFilesystemAssetLibrary::GetLastAssetWriteTime(const AssetID& asset_id) const
{
if (auto iter = m_assetid_to_asset_map_path.find(asset_id);
iter != m_assetid_to_asset_map_path.end())
{
const auto& asset_map_path = iter->second;
CustomAssetLibrary::TimeType max_entry;
for (const auto& [key, value] : asset_map_path)
{
const auto tp = std::filesystem::last_write_time(value);
if (tp > max_entry)
max_entry = tp;
}
return max_entry;
}

return {};
}

CustomAssetLibrary::LoadInfo DirectFilesystemAssetLibrary::LoadTexture(const AssetID& asset_id,
CustomTextureData* data)
{
if (auto iter = m_assetid_to_asset_map_path.find(asset_id);
iter != m_assetid_to_asset_map_path.end())
{
const auto& asset_map_path = iter->second;

// Raw texture is expected to have one asset mapped
if (asset_map_path.empty() || asset_map_path.size() > 1)
return {};
const auto& asset_path = asset_map_path.begin()->second;

const auto last_loaded_time = std::filesystem::last_write_time(asset_path);
auto ext = asset_path.extension().string();
Common::ToLower(&ext);
if (ext == ".dds")
{
LoadDDSTexture(data, asset_path.string());
if (data->m_levels.empty()) [[unlikely]]
return {};
if (!LoadMips(asset_path, data))
return {};

return LoadInfo{GetAssetSize(*data), last_loaded_time};
}
else if (ext == ".png")
{
LoadPNGTexture(data, asset_path.string());
if (data->m_levels.empty()) [[unlikely]]
return {};
if (!LoadMips(asset_path, data))
return {};

return LoadInfo{GetAssetSize(*data), last_loaded_time};
}
}

return {};
}

void DirectFilesystemAssetLibrary::SetAssetIDMapData(
const AssetID& asset_id, std::map<std::string, std::filesystem::path> asset_path_map)
{
m_assetid_to_asset_map_path[asset_id] = std::move(asset_path_map);
}

bool DirectFilesystemAssetLibrary::LoadMips(const std::filesystem::path& asset_path,
CustomTextureData* data)
{
if (!data) [[unlikely]]
return false;

std::string path;
std::string filename;
std::string extension;
SplitPath(asset_path.string(), &path, &filename, &extension);

std::string extension_lower = extension;
Common::ToLower(&extension_lower);

// Load additional mip levels
for (u32 mip_level = static_cast<u32>(data->m_levels.size());; mip_level++)
{
const auto mip_level_filename = filename + fmt::format("_mip{}", mip_level);

const auto full_path = path + mip_level_filename + extension;
if (!File::Exists(full_path))
return true;

VideoCommon::CustomTextureData::Level level;
if (extension_lower == ".dds")
{
if (!LoadDDSTexture(&level, full_path, mip_level))
{
ERROR_LOG_FMT(VIDEO, "Custom mipmap '{}' failed to load", mip_level_filename);
return false;
}
}
else if (extension_lower == ".png")
{
if (!LoadPNGTexture(&level, full_path))
{
ERROR_LOG_FMT(VIDEO, "Custom mipmap '{}' failed to load", mip_level_filename);
return false;
}
}
else
{
ERROR_LOG_FMT(VIDEO, "Custom mipmap '{}' has unsupported extension", mip_level_filename);
return false;
}

data->m_levels.push_back(std::move(level));
}

return true;
}
} // namespace VideoCommon
37 changes: 37 additions & 0 deletions Source/Core/VideoCommon/Assets/DirectFilesystemAssetLibrary.h
@@ -0,0 +1,37 @@
// Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once
#include <chrono>
#include <filesystem>
#include <map>
#include <string>

#include "VideoCommon/Assets/CustomAssetLibrary.h"

namespace VideoCommon
{
class CustomTextureData;

// This class implements 'CustomAssetLibrary' and loads any assets
// directly from the filesystem
class DirectFilesystemAssetLibrary final : public CustomAssetLibrary
{
public:
LoadInfo LoadTexture(const AssetID& asset_id, CustomTextureData* data) override;

// Gets the latest time from amongst all the files in the asset map
TimeType GetLastAssetWriteTime(const AssetID& asset_id) const override;

// Assigns the asset id to a map of files, how this map is read is dependent on the data
// For instance, a raw texture would expect the map to have a single entry and load that
// file as the asset. But a model file data might have its data spread across multiple files
void SetAssetIDMapData(const AssetID& asset_id,
std::map<std::string, std::filesystem::path> asset_path_map);

private:
// Loads additional mip levels into the texture structure until _mip<N> texture is not found
bool LoadMips(const std::filesystem::path& asset_path, CustomTextureData* data);
std::map<AssetID, std::map<std::string, std::filesystem::path>> m_assetid_to_asset_map_path;
};
} // namespace VideoCommon
2 changes: 2 additions & 0 deletions Source/Core/VideoCommon/CMakeLists.txt
Expand Up @@ -14,6 +14,8 @@ add_library(videocommon
Assets/CustomAssetLibrary.h
Assets/CustomTextureData.cpp
Assets/CustomTextureData.h
Assets/DirectFilesystemAssetLibrary.cpp
Assets/DirectFilesystemAssetLibrary.h
AsyncRequests.cpp
AsyncRequests.h
AsyncShaderCompiler.cpp
Expand Down

0 comments on commit 4ee2740

Please sign in to comment.