From 96c8172171d6246e913d6ccd6a2a6e12769b1ee8 Mon Sep 17 00:00:00 2001 From: iwubcode Date: Sat, 9 Dec 2023 16:24:05 -0600 Subject: [PATCH] VideoCommon: update shader asset to provide a variant default value --- .../Core/VideoCommon/Assets/ShaderAsset.cpp | 208 ++++++++++++++---- Source/Core/VideoCommon/Assets/ShaderAsset.h | 68 +++--- 2 files changed, 200 insertions(+), 76 deletions(-) diff --git a/Source/Core/VideoCommon/Assets/ShaderAsset.cpp b/Source/Core/VideoCommon/Assets/ShaderAsset.cpp index e58b9bfbb694..3d9d1f4e2df2 100644 --- a/Source/Core/VideoCommon/Assets/ShaderAsset.cpp +++ b/Source/Core/VideoCommon/Assets/ShaderAsset.cpp @@ -4,16 +4,172 @@ #include "VideoCommon/Assets/ShaderAsset.h" #include -#include -#include #include #include "Common/Logging/Log.h" #include "Common/StringUtil.h" +#include "Common/VariantUtil.h" #include "VideoCommon/Assets/CustomAssetLibrary.h" namespace VideoCommon { +template +bool ParseNumeric(const CustomAssetLibrary::AssetID& asset_id, const picojson::value& json_value, + std::string_view code_name, PropertyType* value) +{ + static_assert(ElementCount <= 4, "Numeric data expected to be four elements or less"); + if constexpr (ElementCount == 1) + { + if (!json_value.is()) + { + ERROR_LOG_FMT(VIDEO, + "Asset id '{}' shader has attribute '{}' where " + "a double was expected but not provided.", + asset_id, code_name); + return false; + } + + *value = static_cast(json_value.get()); + } + else + { + if (!json_value.is()) + { + ERROR_LOG_FMT(VIDEO, + "Asset id '{}' shader has attribute '{}' where " + "an array was expected but not provided.", + asset_id, code_name); + return false; + } + + const auto json_data = json_value.get(); + + if (json_data.size() != ElementCount) + { + ERROR_LOG_FMT(VIDEO, + "Asset id '{}' shader has attribute '{}' with incorrect number " + "of elements, expected {}", + asset_id, code_name, ElementCount); + return false; + } + + if (!std::all_of(json_data.begin(), json_data.end(), + [](const picojson::value& v) { return v.is(); })) + { + ERROR_LOG_FMT(VIDEO, + "Asset id '{}' shader has attribute '{}' where " + "all elements are not of type double.", + asset_id, code_name); + return false; + } + + std::array data; + for (std::size_t i = 0; i < ElementCount; i++) + { + data[i] = static_cast(json_data[i].get()); + } + *value = std::move(data); + } + + return true; +} + +bool ParseShaderValue(const CustomAssetLibrary::AssetID& asset_id, + const picojson::value& json_value, std::string_view code_name, + std::string_view type, ShaderProperty::Value* value) +{ + if (type == "int") + { + return ParseNumeric(asset_id, json_value, code_name, value); + } + else if (type == "int2") + { + return ParseNumeric(asset_id, json_value, code_name, value); + } + else if (type == "int3") + { + return ParseNumeric(asset_id, json_value, code_name, value); + } + else if (type == "int4") + { + return ParseNumeric(asset_id, json_value, code_name, value); + } + else if (type == "float") + { + return ParseNumeric(asset_id, json_value, code_name, value); + } + else if (type == "float2") + { + return ParseNumeric(asset_id, json_value, code_name, value); + } + else if (type == "float3") + { + return ParseNumeric(asset_id, json_value, code_name, value); + } + else if (type == "float4") + { + return ParseNumeric(asset_id, json_value, code_name, value); + } + else if (type == "rgb") + { + ShaderProperty::RGB rgb; + if (!ParseNumeric(asset_id, json_value, code_name, &rgb.value)) + return false; + *value = std::move(rgb); + return true; + } + else if (type == "rgba") + { + ShaderProperty::RGBA rgba; + if (!ParseNumeric(asset_id, json_value, code_name, &rgba.value)) + return false; + *value = std::move(rgba); + return true; + } + else if (type == "bool") + { + if (json_value.is()) + { + *value = json_value.get(); + return true; + } + } + else if (type == "sampler2d") + { + if (json_value.is()) + { + ShaderProperty::Sampler2D sampler2d; + sampler2d.value = json_value.get(); + *value = std::move(sampler2d); + return true; + } + } + else if (type == "sampler2darray") + { + if (json_value.is()) + { + ShaderProperty::Sampler2DArray sampler2darray; + sampler2darray.value = json_value.get(); + *value = std::move(sampler2darray); + return true; + } + } + else if (type == "samplercube") + { + if (json_value.is()) + { + ShaderProperty::SamplerCube samplercube; + samplercube.value = json_value.get(); + *value = std::move(samplercube); + return true; + } + } + + ERROR_LOG_FMT(VIDEO, "Asset '{}' failed to parse the json, value is not valid for type '{}'", + asset_id, type); + return false; +} + bool ParseShaderProperties(const VideoCommon::CustomAssetLibrary::AssetID& asset_id, const picojson::array& properties_data, std::map* shader_properties) @@ -50,41 +206,6 @@ bool ParseShaderProperties(const VideoCommon::CustomAssetLibrary::AssetID& asset std::string type = type_iter->second.to_str(); Common::ToLower(&type); - static constexpr std::array, - static_cast(ShaderProperty::Type::Type_Max)> - pairs = {{ - {"sampler2d", ShaderProperty::Type::Type_Sampler2D}, - {"samplercube", ShaderProperty::Type::Type_SamplerCube}, - {"samplerarrayshared_main", ShaderProperty::Type::Type_SamplerArrayShared_Main}, - {"samplerarrayshared_additional", - ShaderProperty::Type::Type_SamplerArrayShared_Additional}, - {"int", ShaderProperty::Type::Type_Int}, - {"int2", ShaderProperty::Type::Type_Int2}, - {"int3", ShaderProperty::Type::Type_Int3}, - {"int4", ShaderProperty::Type::Type_Int4}, - {"float", ShaderProperty::Type::Type_Float}, - {"float2", ShaderProperty::Type::Type_Float2}, - {"float3", ShaderProperty::Type::Type_Float3}, - {"float4", ShaderProperty::Type::Type_Float4}, - {"rgb", ShaderProperty::Type::Type_RGB}, - {"rgba", ShaderProperty::Type::Type_RGBA}, - {"bool", ShaderProperty::Type::Type_Bool}, - }}; - if (const auto it = std::find_if(pairs.begin(), pairs.end(), - [&](const auto& pair) { return pair.first == type; }); - it != pairs.end()) - { - property.m_type = it->second; - } - else - { - ERROR_LOG_FMT(VIDEO, - "Asset '{}' failed to parse json, property entry type '{}' is " - "an invalid option", - asset_id, type_iter->second.to_str()); - return false; - } - const auto description_iter = property_data_obj.find("description"); if (description_iter == property_data_obj.end()) { @@ -118,7 +239,18 @@ bool ParseShaderProperties(const VideoCommon::CustomAssetLibrary::AssetID& asset asset_id); return false; } - shader_properties->try_emplace(code_name_iter->second.to_str(), std::move(property)); + std::string code_name = code_name_iter->second.to_str(); + + const auto default_iter = property_data_obj.find("default"); + if (default_iter != property_data_obj.end()) + { + if (!ParseShaderValue(asset_id, default_iter->second, code_name, type, &property.m_default)) + { + return false; + } + } + + shader_properties->try_emplace(std::move(code_name), std::move(property)); } return true; diff --git a/Source/Core/VideoCommon/Assets/ShaderAsset.h b/Source/Core/VideoCommon/Assets/ShaderAsset.h index 4030cd96ceb9..0cc4255596ec 100644 --- a/Source/Core/VideoCommon/Assets/ShaderAsset.h +++ b/Source/Core/VideoCommon/Assets/ShaderAsset.h @@ -3,45 +3,49 @@ #pragma once +#include #include #include +#include #include -#include "Common/EnumFormatter.h" #include "VideoCommon/Assets/CustomAsset.h" namespace VideoCommon { struct ShaderProperty { - // "SamplerShared" denotes that the sampler - // already exists outside of the shader source - // (ex: in the Dolphin defined pixel shader) - // "Main" is the first entry in a shared sampler array - // and "Additional" denotes a subsequent entry - // in the array - enum class Type + struct RGB { - Type_Undefined, - Type_SamplerArrayShared_Main, - Type_SamplerArrayShared_Additional, - Type_Sampler2D, - Type_SamplerCube, - Type_Int, - Type_Int2, - Type_Int3, - Type_Int4, - Type_Float, - Type_Float2, - Type_Float3, - Type_Float4, - Type_RGB, - Type_RGBA, - Type_Bool, - Type_Max = Type_Bool + std::array value; }; - Type m_type; + + struct RGBA + { + std::array value; + }; + + struct Sampler2D + { + CustomAssetLibrary::AssetID value; + }; + + struct Sampler2DArray + { + CustomAssetLibrary::AssetID value; + }; + + struct SamplerCube + { + CustomAssetLibrary::AssetID value; + }; + + using Value = std::variant, std::array, std::array, float, + std::array, std::array, std::array, bool, + RGB, RGBA, Sampler2D, Sampler2DArray, SamplerCube>; + + Value m_default; std::string m_description; }; struct PixelShaderData @@ -66,15 +70,3 @@ class PixelShaderAsset final : public CustomLoadableAsset CustomAssetLibrary::LoadInfo LoadImpl(const CustomAssetLibrary::AssetID& asset_id) override; }; } // namespace VideoCommon - -template <> -struct fmt::formatter - : EnumFormatter -{ - constexpr formatter() - : EnumFormatter({"Undefined", "DolphinSamplerArray_Main", "DolphinSamplerArray_Additional", - "2DSampler", "CubeSampler", "Int", "Int2", "Int3", "Int4", "Float", "Float2", - "Float3", "Float4", "RGB", "RGBA", "Bool"}) - { - } -};