Merge pull request #12009 from iwubcode/shader_asset
VideoCommon: add a pixel shader asset
This commit is contained in:
commit
0366122306
|
@ -637,6 +637,7 @@
|
||||||
<ClInclude Include="VideoCommon\Assets\CustomAssetLoader.h" />
|
<ClInclude Include="VideoCommon\Assets\CustomAssetLoader.h" />
|
||||||
<ClInclude Include="VideoCommon\Assets\CustomTextureData.h" />
|
<ClInclude Include="VideoCommon\Assets\CustomTextureData.h" />
|
||||||
<ClInclude Include="VideoCommon\Assets\DirectFilesystemAssetLibrary.h" />
|
<ClInclude Include="VideoCommon\Assets\DirectFilesystemAssetLibrary.h" />
|
||||||
|
<ClInclude Include="VideoCommon\Assets\ShaderAsset.h" />
|
||||||
<ClInclude Include="VideoCommon\Assets\TextureAsset.h" />
|
<ClInclude Include="VideoCommon\Assets\TextureAsset.h" />
|
||||||
<ClInclude Include="VideoCommon\AsyncRequests.h" />
|
<ClInclude Include="VideoCommon\AsyncRequests.h" />
|
||||||
<ClInclude Include="VideoCommon\AsyncShaderCompiler.h" />
|
<ClInclude Include="VideoCommon\AsyncShaderCompiler.h" />
|
||||||
|
@ -1252,6 +1253,7 @@
|
||||||
<ClCompile Include="VideoCommon\Assets\CustomAssetLoader.cpp" />
|
<ClCompile Include="VideoCommon\Assets\CustomAssetLoader.cpp" />
|
||||||
<ClCompile Include="VideoCommon\Assets\CustomTextureData.cpp" />
|
<ClCompile Include="VideoCommon\Assets\CustomTextureData.cpp" />
|
||||||
<ClCompile Include="VideoCommon\Assets\DirectFilesystemAssetLibrary.cpp" />
|
<ClCompile Include="VideoCommon\Assets\DirectFilesystemAssetLibrary.cpp" />
|
||||||
|
<ClCompile Include="VideoCommon\Assets\ShaderAsset.cpp" />
|
||||||
<ClCompile Include="VideoCommon\Assets\TextureAsset.cpp" />
|
<ClCompile Include="VideoCommon\Assets\TextureAsset.cpp" />
|
||||||
<ClCompile Include="VideoCommon\AsyncRequests.cpp" />
|
<ClCompile Include="VideoCommon\AsyncRequests.cpp" />
|
||||||
<ClCompile Include="VideoCommon\AsyncShaderCompiler.cpp" />
|
<ClCompile Include="VideoCommon\AsyncShaderCompiler.cpp" />
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
namespace VideoCommon
|
namespace VideoCommon
|
||||||
{
|
{
|
||||||
class CustomTextureData;
|
class CustomTextureData;
|
||||||
|
struct PixelShaderData;
|
||||||
|
|
||||||
// This class provides functionality to load
|
// This class provides functionality to load
|
||||||
// specific data (like textures). Where this data
|
// specific data (like textures). Where this data
|
||||||
|
@ -45,5 +46,8 @@ public:
|
||||||
// Loads a texture as a game texture, providing additional checks like confirming
|
// 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
|
// each mip level size is correct and that the format is consistent across the data
|
||||||
LoadInfo LoadGameTexture(const AssetID& asset_id, CustomTextureData* data);
|
LoadInfo LoadGameTexture(const AssetID& asset_id, CustomTextureData* data);
|
||||||
|
|
||||||
|
// Loads a pixel shader
|
||||||
|
virtual LoadInfo LoadPixelShader(const AssetID& asset_id, PixelShaderData* data) = 0;
|
||||||
};
|
};
|
||||||
} // namespace VideoCommon
|
} // namespace VideoCommon
|
||||||
|
|
|
@ -90,4 +90,11 @@ CustomAssetLoader::LoadGameTexture(const CustomAssetLibrary::AssetID& asset_id,
|
||||||
{
|
{
|
||||||
return LoadOrCreateAsset<GameTextureAsset>(asset_id, m_game_textures, std::move(library));
|
return LoadOrCreateAsset<GameTextureAsset>(asset_id, m_game_textures, std::move(library));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<PixelShaderAsset>
|
||||||
|
CustomAssetLoader::LoadPixelShader(const CustomAssetLibrary::AssetID& asset_id,
|
||||||
|
std::shared_ptr<CustomAssetLibrary> library)
|
||||||
|
{
|
||||||
|
return LoadOrCreateAsset<PixelShaderAsset>(asset_id, m_pixel_shaders, std::move(library));
|
||||||
|
}
|
||||||
} // namespace VideoCommon
|
} // namespace VideoCommon
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "Common/Flag.h"
|
#include "Common/Flag.h"
|
||||||
#include "Common/WorkQueueThread.h"
|
#include "Common/WorkQueueThread.h"
|
||||||
#include "VideoCommon/Assets/CustomAsset.h"
|
#include "VideoCommon/Assets/CustomAsset.h"
|
||||||
|
#include "VideoCommon/Assets/ShaderAsset.h"
|
||||||
#include "VideoCommon/Assets/TextureAsset.h"
|
#include "VideoCommon/Assets/TextureAsset.h"
|
||||||
|
|
||||||
namespace VideoCommon
|
namespace VideoCommon
|
||||||
|
@ -42,6 +43,9 @@ public:
|
||||||
std::shared_ptr<GameTextureAsset> LoadGameTexture(const CustomAssetLibrary::AssetID& asset_id,
|
std::shared_ptr<GameTextureAsset> LoadGameTexture(const CustomAssetLibrary::AssetID& asset_id,
|
||||||
std::shared_ptr<CustomAssetLibrary> library);
|
std::shared_ptr<CustomAssetLibrary> library);
|
||||||
|
|
||||||
|
std::shared_ptr<PixelShaderAsset> LoadPixelShader(const CustomAssetLibrary::AssetID& asset_id,
|
||||||
|
std::shared_ptr<CustomAssetLibrary> library);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// TODO C++20: use a 'derived_from' concept against 'CustomAsset' when available
|
// TODO C++20: use a 'derived_from' concept against 'CustomAsset' when available
|
||||||
template <typename AssetType>
|
template <typename AssetType>
|
||||||
|
@ -74,6 +78,7 @@ private:
|
||||||
|
|
||||||
std::map<CustomAssetLibrary::AssetID, std::weak_ptr<RawTextureAsset>> m_textures;
|
std::map<CustomAssetLibrary::AssetID, std::weak_ptr<RawTextureAsset>> m_textures;
|
||||||
std::map<CustomAssetLibrary::AssetID, std::weak_ptr<GameTextureAsset>> m_game_textures;
|
std::map<CustomAssetLibrary::AssetID, std::weak_ptr<GameTextureAsset>> m_game_textures;
|
||||||
|
std::map<CustomAssetLibrary::AssetID, std::weak_ptr<PixelShaderAsset>> m_pixel_shaders;
|
||||||
std::thread m_asset_monitor_thread;
|
std::thread m_asset_monitor_thread;
|
||||||
Common::Flag m_asset_monitor_thread_shutdown;
|
Common::Flag m_asset_monitor_thread_shutdown;
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
#include "VideoCommon/Assets/CustomTextureData.h"
|
#include "VideoCommon/Assets/CustomTextureData.h"
|
||||||
|
#include "VideoCommon/Assets/ShaderAsset.h"
|
||||||
|
|
||||||
namespace VideoCommon
|
namespace VideoCommon
|
||||||
{
|
{
|
||||||
|
@ -49,6 +50,100 @@ DirectFilesystemAssetLibrary::GetLastAssetWriteTime(const AssetID& asset_id) con
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CustomAssetLibrary::LoadInfo DirectFilesystemAssetLibrary::LoadPixelShader(const AssetID& asset_id,
|
||||||
|
PixelShaderData* data)
|
||||||
|
{
|
||||||
|
const auto asset_map = GetAssetMapForID(asset_id);
|
||||||
|
|
||||||
|
// Asset map for a pixel shader is the shader and some metadata
|
||||||
|
if (asset_map.size() != 2)
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO, "Asset '{}' expected to have two files mapped!", asset_id);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto metadata = asset_map.find("metadata");
|
||||||
|
const auto shader = asset_map.find("shader");
|
||||||
|
if (metadata == asset_map.end())
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO, "Asset '{}' expected to have a metadata entry mapped!", asset_id);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shader == asset_map.end())
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO, "Asset '{}' expected to have a shader entry mapped!", asset_id);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t metadata_size;
|
||||||
|
{
|
||||||
|
std::error_code ec;
|
||||||
|
metadata_size = std::filesystem::file_size(metadata->second, ec);
|
||||||
|
if (ec)
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO,
|
||||||
|
"Asset '{}' error - failed to get shader metadata file size with error '{}'!",
|
||||||
|
asset_id, ec);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::size_t shader_size;
|
||||||
|
{
|
||||||
|
std::error_code ec;
|
||||||
|
shader_size = std::filesystem::file_size(shader->second, ec);
|
||||||
|
if (ec)
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO,
|
||||||
|
"Asset '{}' error - failed to get shader source file size with error '{}'!",
|
||||||
|
asset_id, ec);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const auto approx_mem_size = metadata_size + shader_size;
|
||||||
|
|
||||||
|
if (!File::ReadFileToString(shader->second.string(), data->m_shader_source))
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO, "Asset '{}' error - failed to load the shader file '{}',", asset_id,
|
||||||
|
shader->second.string());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string json_data;
|
||||||
|
if (!File::ReadFileToString(metadata->second.string(), json_data))
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO, "Asset '{}' error - failed to load the json file '{}',", asset_id,
|
||||||
|
metadata->second.string());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
picojson::value root;
|
||||||
|
const auto error = picojson::parse(root, json_data);
|
||||||
|
|
||||||
|
if (!error.empty())
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO,
|
||||||
|
"Asset '{}' error - failed to load the json file '{}', due to parse error: {}",
|
||||||
|
asset_id, metadata->second.string(), error);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (!root.is<picojson::object>())
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(
|
||||||
|
VIDEO,
|
||||||
|
"Asset '{}' error - failed to load the json file '{}', due to root not being an object!",
|
||||||
|
asset_id, metadata->second.string());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& root_obj = root.get<picojson::object>();
|
||||||
|
|
||||||
|
if (!PixelShaderData::FromJson(asset_id, root_obj, data))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return LoadInfo{approx_mem_size, GetLastAssetWriteTime(asset_id)};
|
||||||
|
}
|
||||||
|
|
||||||
CustomAssetLibrary::LoadInfo DirectFilesystemAssetLibrary::LoadTexture(const AssetID& asset_id,
|
CustomAssetLibrary::LoadInfo DirectFilesystemAssetLibrary::LoadTexture(const AssetID& asset_id,
|
||||||
CustomTextureData* data)
|
CustomTextureData* data)
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,6 +22,7 @@ public:
|
||||||
using AssetMap = std::map<std::string, std::filesystem::path>;
|
using AssetMap = std::map<std::string, std::filesystem::path>;
|
||||||
|
|
||||||
LoadInfo LoadTexture(const AssetID& asset_id, CustomTextureData* data) override;
|
LoadInfo LoadTexture(const AssetID& asset_id, CustomTextureData* data) override;
|
||||||
|
LoadInfo LoadPixelShader(const AssetID& asset_id, PixelShaderData* data) override;
|
||||||
|
|
||||||
// Gets the latest time from amongst all the files in the asset map
|
// Gets the latest time from amongst all the files in the asset map
|
||||||
TimeType GetLastAssetWriteTime(const AssetID& asset_id) const override;
|
TimeType GetLastAssetWriteTime(const AssetID& asset_id) const override;
|
||||||
|
|
|
@ -0,0 +1,147 @@
|
||||||
|
// Copyright 2023 Dolphin Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "VideoCommon/Assets/ShaderAsset.h"
|
||||||
|
|
||||||
|
#include "Common/Logging/Log.h"
|
||||||
|
#include "VideoCommon/Assets/CustomAssetLibrary.h"
|
||||||
|
|
||||||
|
namespace VideoCommon
|
||||||
|
{
|
||||||
|
bool ParseShaderProperties(const VideoCommon::CustomAssetLibrary::AssetID& asset_id,
|
||||||
|
const picojson::array& properties_data,
|
||||||
|
std::map<std::string, VideoCommon::ShaderProperty>* shader_properties)
|
||||||
|
{
|
||||||
|
if (!shader_properties) [[unlikely]]
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (const auto& property_data : properties_data)
|
||||||
|
{
|
||||||
|
VideoCommon::ShaderProperty property;
|
||||||
|
if (!property_data.is<picojson::object>())
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse json, property is not the right json type",
|
||||||
|
asset_id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto& property_data_obj = property_data.get<picojson::object>();
|
||||||
|
|
||||||
|
const auto type_iter = property_data_obj.find("type");
|
||||||
|
if (type_iter == property_data_obj.end())
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse json, property entry 'type' not found",
|
||||||
|
asset_id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!type_iter->second.is<std::string>())
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO,
|
||||||
|
"Asset '{}' failed to parse json, property entry 'type' is not "
|
||||||
|
"the right json type",
|
||||||
|
asset_id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::string type = type_iter->second.to_str();
|
||||||
|
std::transform(type.begin(), type.end(), type.begin(),
|
||||||
|
[](unsigned char c) { return std::tolower(c); });
|
||||||
|
|
||||||
|
if (type == "sampler2d")
|
||||||
|
{
|
||||||
|
property.m_type = ShaderProperty::Type::Type_Sampler2D;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO,
|
||||||
|
"Asset '{}' failed to parse json, property entry 'description' is "
|
||||||
|
"an invalid option",
|
||||||
|
asset_id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto description_iter = property_data_obj.find("description");
|
||||||
|
if (description_iter == property_data_obj.end())
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO,
|
||||||
|
"Asset '{}' failed to parse json, property entry 'description' not found",
|
||||||
|
asset_id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!description_iter->second.is<std::string>())
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO,
|
||||||
|
"Asset '{}' failed to parse json, property entry 'description' is not "
|
||||||
|
"the right json type",
|
||||||
|
asset_id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
property.m_description = description_iter->second.to_str();
|
||||||
|
|
||||||
|
const auto code_name_iter = property_data_obj.find("code_name");
|
||||||
|
if (code_name_iter == property_data_obj.end())
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse json, property entry 'code_name' not found",
|
||||||
|
asset_id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!code_name_iter->second.is<std::string>())
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO,
|
||||||
|
"Asset '{}' failed to parse json, property entry 'code_name' is not "
|
||||||
|
"the right json type",
|
||||||
|
asset_id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
shader_properties->try_emplace(code_name_iter->second.to_str(), std::move(property));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PixelShaderData::FromJson(const VideoCommon::CustomAssetLibrary::AssetID& asset_id,
|
||||||
|
const picojson::object& json, PixelShaderData* data)
|
||||||
|
{
|
||||||
|
const auto properties_iter = json.find("properties");
|
||||||
|
if (properties_iter == json.end())
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse json, 'properties' not found", asset_id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!properties_iter->second.is<picojson::array>())
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse json, 'properties' is not the right json type",
|
||||||
|
asset_id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto& properties_array = properties_iter->second.get<picojson::array>();
|
||||||
|
if (!ParseShaderProperties(asset_id, properties_array, &data->m_properties))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (const auto& [name, property] : data->m_properties)
|
||||||
|
{
|
||||||
|
if (data->m_shader_source.find(name) == std::string::npos)
|
||||||
|
{
|
||||||
|
ERROR_LOG_FMT(
|
||||||
|
VIDEO,
|
||||||
|
"Asset '{}' failed to parse json, the code name '{}' defined in the metadata was not "
|
||||||
|
"found in the shader source",
|
||||||
|
asset_id, name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
CustomAssetLibrary::LoadInfo PixelShaderAsset::LoadImpl(const CustomAssetLibrary::AssetID& asset_id)
|
||||||
|
{
|
||||||
|
auto potential_data = std::make_shared<PixelShaderData>();
|
||||||
|
const auto loaded_info = m_owning_library->LoadPixelShader(asset_id, potential_data.get());
|
||||||
|
if (loaded_info.m_bytes_loaded == 0)
|
||||||
|
return {};
|
||||||
|
{
|
||||||
|
std::lock_guard lk(m_data_lock);
|
||||||
|
m_loaded = true;
|
||||||
|
m_data = std::move(potential_data);
|
||||||
|
}
|
||||||
|
return loaded_info;
|
||||||
|
}
|
||||||
|
} // namespace VideoCommon
|
|
@ -0,0 +1,47 @@
|
||||||
|
// Copyright 2023 Dolphin Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <picojson.h>
|
||||||
|
|
||||||
|
#include "VideoCommon/Assets/CustomAsset.h"
|
||||||
|
|
||||||
|
namespace VideoCommon
|
||||||
|
{
|
||||||
|
struct ShaderProperty
|
||||||
|
{
|
||||||
|
enum class Type
|
||||||
|
{
|
||||||
|
Type_Undefined,
|
||||||
|
Type_Sampler2D,
|
||||||
|
Type_Max = Type_Sampler2D
|
||||||
|
};
|
||||||
|
Type m_type;
|
||||||
|
std::string m_description;
|
||||||
|
};
|
||||||
|
struct PixelShaderData
|
||||||
|
{
|
||||||
|
static bool FromJson(const CustomAssetLibrary::AssetID& asset_id, const picojson::object& json,
|
||||||
|
PixelShaderData* data);
|
||||||
|
|
||||||
|
// These shader properties describe the input that the
|
||||||
|
// shader expects to expose. The key is text
|
||||||
|
// expected to be in the shader code and the propery
|
||||||
|
// describes various details about the input
|
||||||
|
std::map<std::string, ShaderProperty> m_properties;
|
||||||
|
std::string m_shader_source;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PixelShaderAsset final : public CustomLoadableAsset<PixelShaderData>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using CustomLoadableAsset::CustomLoadableAsset;
|
||||||
|
|
||||||
|
private:
|
||||||
|
CustomAssetLibrary::LoadInfo LoadImpl(const CustomAssetLibrary::AssetID& asset_id) override;
|
||||||
|
};
|
||||||
|
} // namespace VideoCommon
|
|
@ -18,6 +18,8 @@ add_library(videocommon
|
||||||
Assets/CustomTextureData.h
|
Assets/CustomTextureData.h
|
||||||
Assets/DirectFilesystemAssetLibrary.cpp
|
Assets/DirectFilesystemAssetLibrary.cpp
|
||||||
Assets/DirectFilesystemAssetLibrary.h
|
Assets/DirectFilesystemAssetLibrary.h
|
||||||
|
Assets/ShaderAsset.cpp
|
||||||
|
Assets/ShaderAsset.h
|
||||||
Assets/TextureAsset.cpp
|
Assets/TextureAsset.cpp
|
||||||
Assets/TextureAsset.h
|
Assets/TextureAsset.h
|
||||||
AsyncRequests.cpp
|
AsyncRequests.cpp
|
||||||
|
|
Loading…
Reference in New Issue