VideoCommon: add custom asset implementation and asset library that can load an asset
This commit is contained in:
parent
6302cea22c
commit
b2c5a5485a
|
@ -631,6 +631,8 @@
|
||||||
<ClInclude Include="VideoCommon\AbstractShader.h" />
|
<ClInclude Include="VideoCommon\AbstractShader.h" />
|
||||||
<ClInclude Include="VideoCommon\AbstractStagingTexture.h" />
|
<ClInclude Include="VideoCommon\AbstractStagingTexture.h" />
|
||||||
<ClInclude Include="VideoCommon\AbstractTexture.h" />
|
<ClInclude Include="VideoCommon\AbstractTexture.h" />
|
||||||
|
<ClInclude Include="VideoCommon\Assets\CustomAsset.h" />
|
||||||
|
<ClInclude Include="VideoCommon\Assets\CustomAssetLibrary.h" />
|
||||||
<ClInclude Include="VideoCommon\AsyncRequests.h" />
|
<ClInclude Include="VideoCommon\AsyncRequests.h" />
|
||||||
<ClInclude Include="VideoCommon\AsyncShaderCompiler.h" />
|
<ClInclude Include="VideoCommon\AsyncShaderCompiler.h" />
|
||||||
<ClInclude Include="VideoCommon\BoundingBox.h" />
|
<ClInclude Include="VideoCommon\BoundingBox.h" />
|
||||||
|
@ -1241,6 +1243,8 @@
|
||||||
<ClCompile Include="VideoCommon\AbstractGfx.cpp" />
|
<ClCompile Include="VideoCommon\AbstractGfx.cpp" />
|
||||||
<ClCompile Include="VideoCommon\AbstractStagingTexture.cpp" />
|
<ClCompile Include="VideoCommon\AbstractStagingTexture.cpp" />
|
||||||
<ClCompile Include="VideoCommon\AbstractTexture.cpp" />
|
<ClCompile Include="VideoCommon\AbstractTexture.cpp" />
|
||||||
|
<ClCompile Include="VideoCommon\Assets\CustomAsset.cpp" />
|
||||||
|
<ClCompile Include="VideoCommon\Assets\CustomAssetLibrary.cpp" />
|
||||||
<ClCompile Include="VideoCommon\AsyncRequests.cpp" />
|
<ClCompile Include="VideoCommon\AsyncRequests.cpp" />
|
||||||
<ClCompile Include="VideoCommon\AsyncShaderCompiler.cpp" />
|
<ClCompile Include="VideoCommon\AsyncShaderCompiler.cpp" />
|
||||||
<ClCompile Include="VideoCommon\BoundingBox.cpp" />
|
<ClCompile Include="VideoCommon\BoundingBox.cpp" />
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
// Copyright 2023 Dolphin Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "VideoCommon/Assets/CustomAsset.h"
|
||||||
|
|
||||||
|
namespace VideoCommon
|
||||||
|
{
|
||||||
|
CustomAsset::CustomAsset(std::shared_ptr<CustomAssetLibrary> library,
|
||||||
|
const CustomAssetLibrary::AssetID& asset_id)
|
||||||
|
: m_owning_library(std::move(library)), m_asset_id(asset_id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CustomAsset::Load()
|
||||||
|
{
|
||||||
|
const auto load_information = LoadImpl(m_asset_id);
|
||||||
|
if (load_information.m_bytes_loaded > 0)
|
||||||
|
{
|
||||||
|
m_bytes_loaded = load_information.m_bytes_loaded;
|
||||||
|
m_last_loaded_time = load_information.m_load_time;
|
||||||
|
}
|
||||||
|
return load_information.m_bytes_loaded != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomAssetLibrary::TimeType CustomAsset::GetLastWriteTime() const
|
||||||
|
{
|
||||||
|
return m_owning_library->GetLastAssetWriteTime(m_asset_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const CustomAssetLibrary::TimeType& CustomAsset::GetLastLoadedTime() const
|
||||||
|
{
|
||||||
|
return m_last_loaded_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CustomAssetLibrary::AssetID& CustomAsset::GetAssetId() const
|
||||||
|
{
|
||||||
|
return m_asset_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t CustomAsset::GetByteSizeInMemory() const
|
||||||
|
{
|
||||||
|
return m_bytes_loaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace VideoCommon
|
|
@ -0,0 +1,81 @@
|
||||||
|
// Copyright 2023 Dolphin Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "VideoCommon/Assets/CustomAssetLibrary.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
namespace VideoCommon
|
||||||
|
{
|
||||||
|
// An abstract class that provides operations for loading
|
||||||
|
// data from a 'CustomAssetLibrary'
|
||||||
|
class CustomAsset
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CustomAsset(std::shared_ptr<CustomAssetLibrary> library,
|
||||||
|
const CustomAssetLibrary::AssetID& asset_id);
|
||||||
|
virtual ~CustomAsset() = default;
|
||||||
|
CustomAsset(const CustomAsset&) = default;
|
||||||
|
CustomAsset(CustomAsset&&) = default;
|
||||||
|
CustomAsset& operator=(const CustomAsset&) = default;
|
||||||
|
CustomAsset& operator=(CustomAsset&&) = default;
|
||||||
|
|
||||||
|
// Loads the asset from the library returning a pass/fail result
|
||||||
|
bool Load();
|
||||||
|
|
||||||
|
// Queries the last time the asset was modified or standard epoch time
|
||||||
|
// if the asset hasn't been modified yet
|
||||||
|
CustomAssetLibrary::TimeType GetLastWriteTime() const;
|
||||||
|
|
||||||
|
// Returns the time that the data was last loaded
|
||||||
|
const CustomAssetLibrary::TimeType& GetLastLoadedTime() const;
|
||||||
|
|
||||||
|
// Returns an id that uniquely identifies this asset
|
||||||
|
const CustomAssetLibrary::AssetID& GetAssetId() const;
|
||||||
|
|
||||||
|
// A rough estimate of how much space this asset
|
||||||
|
// will take in memroy
|
||||||
|
std::size_t GetByteSizeInMemory() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const std::shared_ptr<CustomAssetLibrary> m_owning_library;
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual CustomAssetLibrary::LoadInfo LoadImpl(const CustomAssetLibrary::AssetID& asset_id) = 0;
|
||||||
|
CustomAssetLibrary::AssetID m_asset_id;
|
||||||
|
std::size_t m_bytes_loaded = 0;
|
||||||
|
CustomAssetLibrary::TimeType m_last_loaded_time;
|
||||||
|
};
|
||||||
|
|
||||||
|
// An abstract class that is expected to
|
||||||
|
// be the base class for all assets
|
||||||
|
// It provides a simple interface for
|
||||||
|
// verifying that an asset data of type
|
||||||
|
// 'UnderlyingType' is loaded by
|
||||||
|
// checking against 'GetData()'
|
||||||
|
template <typename UnderlyingType>
|
||||||
|
class CustomLoadableAsset : public CustomAsset
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using CustomAsset::CustomAsset;
|
||||||
|
|
||||||
|
const UnderlyingType* GetData() const
|
||||||
|
{
|
||||||
|
std::lock_guard lk(m_lock);
|
||||||
|
if (m_loaded)
|
||||||
|
return &m_data;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool m_loaded = false;
|
||||||
|
mutable std::mutex m_lock;
|
||||||
|
UnderlyingType m_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace VideoCommon
|
|
@ -0,0 +1,82 @@
|
||||||
|
// Copyright 2023 Dolphin Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "VideoCommon/Assets/CustomAssetLibrary.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "Common/Logging/Log.h"
|
||||||
|
#include "VideoCommon/GraphicsModSystem/Runtime/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::LoadInfo CustomAssetLibrary::LoadGameTexture(const AssetID& asset_id,
|
||||||
|
CustomTextureData* data)
|
||||||
|
{
|
||||||
|
const auto load_info = LoadTexture(asset_id, data);
|
||||||
|
if (load_info.m_bytes_loaded == 0)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
// Note: 'LoadTexture()' ensures we have a level loaded
|
||||||
|
const auto& first_mip = data->m_levels[0];
|
||||||
|
|
||||||
|
// Verify that each mip level is the correct size (divide by 2 each time).
|
||||||
|
u32 current_mip_width = first_mip.width;
|
||||||
|
u32 current_mip_height = first_mip.height;
|
||||||
|
for (u32 mip_level = 1; mip_level < static_cast<u32>(data->m_levels.size()); mip_level++)
|
||||||
|
{
|
||||||
|
if (current_mip_width != 1 || current_mip_height != 1)
|
||||||
|
{
|
||||||
|
current_mip_width = std::max(current_mip_width / 2, 1u);
|
||||||
|
current_mip_height = std::max(current_mip_height / 2, 1u);
|
||||||
|
|
||||||
|
const VideoCommon::CustomTextureData::Level& level = data->m_levels[mip_level];
|
||||||
|
if (current_mip_width == level.width && current_mip_height == level.height)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ERROR_LOG_FMT(VIDEO,
|
||||||
|
"Invalid custom game texture size {}x{} for texture asset {}. Mipmap level {} "
|
||||||
|
"must be {}x{}.",
|
||||||
|
level.width, level.height, asset_id, mip_level, current_mip_width,
|
||||||
|
current_mip_height);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// It is invalid to have more than a single 1x1 mipmap.
|
||||||
|
ERROR_LOG_FMT(VIDEO,
|
||||||
|
"Custom game texture {} has too many 1x1 mipmaps. Skipping extra levels.",
|
||||||
|
asset_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drop this mip level and any others after it.
|
||||||
|
while (data->m_levels.size() > mip_level)
|
||||||
|
data->m_levels.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
// All levels have to have the same format.
|
||||||
|
if (std::any_of(data->m_levels.begin(), data->m_levels.end(),
|
||||||
|
[&first_mip](const VideoCommon::CustomTextureData::Level& l) {
|
||||||
|
return l.format != first_mip.format;
|
||||||
|
}))
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO, "Custom game texture {} has inconsistent formats across mip levels.",
|
||||||
|
asset_id);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return load_info;
|
||||||
|
}
|
||||||
|
} // namespace VideoCommon
|
|
@ -0,0 +1,49 @@
|
||||||
|
// Copyright 2023 Dolphin Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace VideoCommon
|
||||||
|
{
|
||||||
|
class CustomTextureData;
|
||||||
|
|
||||||
|
// This class provides functionality to load
|
||||||
|
// specific data (like textures). Where this data
|
||||||
|
// is loaded from is implementation defined
|
||||||
|
class CustomAssetLibrary
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// TODO: this should be std::chrono::system_clock::time_point to
|
||||||
|
// support any type of loader where the time isn't from the filesystem
|
||||||
|
// but there's no way to convert filesystem times to system times
|
||||||
|
// without 'clock_cast', once our builders catch up
|
||||||
|
// to support 'clock_cast' we should update this
|
||||||
|
// For now, it's fine as a filesystem library is all that is
|
||||||
|
// available
|
||||||
|
using TimeType = std::filesystem::file_time_type;
|
||||||
|
|
||||||
|
// The AssetID is a unique identifier for a particular asset
|
||||||
|
using AssetID = std::string;
|
||||||
|
|
||||||
|
struct LoadInfo
|
||||||
|
{
|
||||||
|
std::size_t m_bytes_loaded;
|
||||||
|
CustomAssetLibrary::TimeType m_load_time;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Loads a texture, if there are no levels, bytes loaded will be empty
|
||||||
|
virtual LoadInfo LoadTexture(const AssetID& asset_id, CustomTextureData* data) = 0;
|
||||||
|
|
||||||
|
// Gets the last write time for a given asset id
|
||||||
|
virtual TimeType GetLastAssetWriteTime(const AssetID& asset_id) const = 0;
|
||||||
|
|
||||||
|
// Loads a texture as a game texture, providing additional checks like confirming
|
||||||
|
// each mip level size is correct and that the format is consistent across the data
|
||||||
|
LoadInfo LoadGameTexture(const AssetID& asset_id, CustomTextureData* data);
|
||||||
|
};
|
||||||
|
} // namespace VideoCommon
|
|
@ -8,6 +8,10 @@ add_library(videocommon
|
||||||
AbstractStagingTexture.h
|
AbstractStagingTexture.h
|
||||||
AbstractTexture.cpp
|
AbstractTexture.cpp
|
||||||
AbstractTexture.h
|
AbstractTexture.h
|
||||||
|
Assets/CustomAsset.cpp
|
||||||
|
Assets/CustomAsset.h
|
||||||
|
Assets/CustomAssetLibrary.cpp
|
||||||
|
Assets/CustomAssetLibrary.h
|
||||||
AsyncRequests.cpp
|
AsyncRequests.cpp
|
||||||
AsyncRequests.h
|
AsyncRequests.h
|
||||||
AsyncShaderCompiler.cpp
|
AsyncShaderCompiler.cpp
|
||||||
|
|
Loading…
Reference in New Issue