diff options
Diffstat (limited to 'Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/CustomPipelineAction.cpp')
| -rw-r--r-- | Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/CustomPipelineAction.cpp | 413 |
1 files changed, 17 insertions, 396 deletions
diff --git a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/CustomPipelineAction.cpp b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/CustomPipelineAction.cpp index f457300847..92c048860f 100644 --- a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/CustomPipelineAction.cpp +++ b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/CustomPipelineAction.cpp @@ -5,6 +5,7 @@ #include <algorithm> #include <array> +#include <optional> #include <fmt/format.h> @@ -20,164 +21,12 @@ #include "VideoCommon/ShaderGenCommon.h" #include "VideoCommon/TextureCacheBase.h" -namespace -{ -bool IsQualifier(std::string_view value) -{ - static std::array<std::string_view, 7> qualifiers = {"attribute", "const", "highp", "lowp", - "mediump", "uniform", "varying"}; - return std::find(qualifiers.begin(), qualifiers.end(), value) != qualifiers.end(); -} - -bool IsBuiltInMacro(std::string_view value) +std::unique_ptr<CustomPipelineAction> +CustomPipelineAction::Create(std::shared_ptr<VideoCommon::CustomAssetLibrary> library) { - static std::array<std::string_view, 5> built_in = {"__LINE__", "__FILE__", "__VERSION__", - "GL_core_profile", "GL_compatibility_profile"}; - return std::find(built_in.begin(), built_in.end(), value) != built_in.end(); + return std::make_unique<CustomPipelineAction>(std::move(library)); } -std::vector<std::string> GlobalConflicts(std::string_view source) -{ - std::string_view last_identifier = ""; - std::vector<std::string> global_result; - u32 scope = 0; - for (u32 i = 0; i < source.size(); i++) - { - // If we're out of global scope, we don't care - // about any of the details - if (scope > 0) - { - if (source[i] == '{') - { - scope++; - } - else if (source[i] == '}') - { - scope--; - } - continue; - } - - const auto parse_identifier = [&]() { - const u32 start = i; - for (; i < source.size(); i++) - { - if (!Common::IsAlpha(source[i]) && source[i] != '_' && !std::isdigit(source[i])) - break; - } - u32 end = i; - i--; // unwind - return source.substr(start, end - start); - }; - - if (Common::IsAlpha(source[i]) || source[i] == '_') - { - const std::string_view identifier = parse_identifier(); - if (IsQualifier(identifier)) - continue; - if (IsBuiltInMacro(identifier)) - continue; - last_identifier = identifier; - } - else if (source[i] == '#') - { - const auto parse_until_end_of_preprocessor = [&]() { - bool continue_until_next_newline = false; - for (; i < source.size(); i++) - { - if (source[i] == '\n') - { - if (continue_until_next_newline) - continue_until_next_newline = false; - else - break; - } - else if (source[i] == '\\') - { - continue_until_next_newline = true; - } - } - }; - i++; - const std::string_view identifier = parse_identifier(); - if (identifier == "define") - { - i++; - // skip whitespace - while (source[i] == ' ') - { - i++; - } - global_result.push_back(std::string{parse_identifier()}); - parse_until_end_of_preprocessor(); - } - else - { - parse_until_end_of_preprocessor(); - } - } - else if (source[i] == '{') - { - scope++; - } - else if (source[i] == '(') - { - // Unlikely the user will be using layouts but... - if (last_identifier == "layout") - continue; - - // Since we handle equality, we can assume the identifier - // before '(' is a function definition - global_result.push_back(std::string{last_identifier}); - } - else if (source[i] == '=') - { - global_result.push_back(std::string{last_identifier}); - i++; - for (; i < source.size(); i++) - { - if (source[i] == ';') - break; - } - } - else if (source[i] == '/') - { - if ((i + 1) >= source.size()) - continue; - - if (source[i + 1] == '/') - { - // Go to end of line... - for (; i < source.size(); i++) - { - if (source[i] == '\n') - break; - } - } - else if (source[i + 1] == '*') - { - // Multiline, look for first '*/' - for (; i < source.size(); i++) - { - if (source[i] == '/' && source[i - 1] == '*') - break; - } - } - } - } - - // Sort the conflicts from largest to smallest string - // this way we can ensure smaller strings that are a substring - // of the larger string are able to be replaced appropriately - std::sort(global_result.begin(), global_result.end(), - [](const std::string& first, const std::string& second) { - return first.size() > second.size(); - }); - return global_result; -} - -} // namespace - std::unique_ptr<CustomPipelineAction> CustomPipelineAction::Create(const picojson::value& json_data, std::shared_ptr<VideoCommon::CustomAssetLibrary> library) @@ -236,16 +85,19 @@ CustomPipelineAction::Create(const picojson::value& json_data, return std::make_unique<CustomPipelineAction>(std::move(library), std::move(pipeline_passes)); } +CustomPipelineAction::CustomPipelineAction(std::shared_ptr<VideoCommon::CustomAssetLibrary> library) + : m_library(std::move(library)) +{ +} + CustomPipelineAction::CustomPipelineAction( std::shared_ptr<VideoCommon::CustomAssetLibrary> library, std::vector<PipelinePassPassDescription> pass_descriptions) : m_library(std::move(library)), m_passes_config(std::move(pass_descriptions)) { - m_passes.resize(m_passes_config.size()); + m_pipeline_passes.resize(m_passes_config.size()); } -CustomPipelineAction::~CustomPipelineAction() = default; - void CustomPipelineAction::OnDrawStarted(GraphicsModActionData::DrawStarted* draw_started) { if (!draw_started) [[unlikely]] @@ -254,251 +106,20 @@ void CustomPipelineAction::OnDrawStarted(GraphicsModActionData::DrawStarted* dra if (!draw_started->custom_pixel_shader) [[unlikely]] return; - if (!draw_started->material_uniform_buffer) [[unlikely]] - return; - - if (m_passes.empty()) [[unlikely]] + if (m_pipeline_passes.empty()) [[unlikely]] return; auto& loader = Core::System::GetInstance().GetCustomAssetLoader(); // For now assume a single pass const auto& pass_config = m_passes_config[0]; - auto& pass = m_passes[0]; - - if (!pass.m_pixel_material.m_asset || - pass_config.m_pixel_material_asset != pass.m_pixel_material.m_asset->GetAssetId()) - { - pass.m_pixel_material.m_asset = - loader.LoadMaterial(pass_config.m_pixel_material_asset, m_library); - } + auto& pass = m_pipeline_passes[0]; - const auto material_data = pass.m_pixel_material.m_asset->GetData(); - if (!material_data) - { - return; - } - - std::size_t max_material_data_size = 0; - if (pass.m_pixel_material.m_asset->GetLastLoadedTime() > - pass.m_pixel_material.m_cached_write_time) - { - m_last_generated_material_code = ShaderCode{}; - pass.m_pixel_material.m_cached_write_time = pass.m_pixel_material.m_asset->GetLastLoadedTime(); - std::size_t texture_count = 0; - for (const auto& property : material_data->properties) - { - max_material_data_size += VideoCommon::MaterialProperty::GetMemorySize(property); - VideoCommon::MaterialProperty::WriteAsShaderCode(m_last_generated_material_code, property); - if (auto* texture_asset_id = - std::get_if<VideoCommon::CustomAssetLibrary::AssetID>(&property.m_value)) - { - texture_count++; - } - } - m_material_data.resize(max_material_data_size); - pass.m_game_textures.resize(texture_count); - } - - if (!pass.m_pixel_shader.m_asset || - pass.m_pixel_shader.m_asset->GetLastLoadedTime() > pass.m_pixel_shader.m_cached_write_time || - material_data->shader_asset != pass.m_pixel_shader.m_asset->GetAssetId()) - { - pass.m_pixel_shader.m_asset = loader.LoadPixelShader(material_data->shader_asset, m_library); - pass.m_pixel_shader.m_cached_write_time = pass.m_pixel_shader.m_asset->GetLastLoadedTime(); - - m_last_generated_shader_code = ShaderCode{}; - } - - const auto shader_data = pass.m_pixel_shader.m_asset->GetData(); - if (!shader_data) - { - return; - } - - if (shader_data->m_properties.size() != material_data->properties.size()) - { - return; - } - - u8* material_buffer = m_material_data.data(); - u32 sampler_index = 8; - for (std::size_t index = 0; index < material_data->properties.size(); index++) - { - auto& property = material_data->properties[index]; - const auto shader_it = shader_data->m_properties.find(property.m_code_name); - if (shader_it == shader_data->m_properties.end()) - { - ERROR_LOG_FMT(VIDEO, - "Custom pipeline, has material asset '{}' that uses a " - "code name of '{}' but that can't be found on shader asset '{}'!", - pass.m_pixel_material.m_asset->GetAssetId(), property.m_code_name, - pass.m_pixel_shader.m_asset->GetAssetId()); - return; - } - - if (auto* texture_asset_id = - std::get_if<VideoCommon::CustomAssetLibrary::AssetID>(&property.m_value)) - { - if (*texture_asset_id != "") - { - auto asset = loader.LoadGameTexture(*texture_asset_id, m_library); - if (!asset) - { - return; - } - - auto& texture_asset = pass.m_game_textures[index]; - if (!texture_asset || - texture_asset->m_cached_asset.m_asset->GetLastLoadedTime() > - texture_asset->m_cached_asset.m_cached_write_time || - *texture_asset_id != texture_asset->m_cached_asset.m_asset->GetAssetId()) - { - if (!texture_asset) - { - texture_asset = PipelinePass::CachedTextureAsset{}; - } - const auto loaded_time = asset->GetLastLoadedTime(); - texture_asset->m_cached_asset = VideoCommon::CachedAsset<VideoCommon::GameTextureAsset>{ - std::move(asset), loaded_time}; - texture_asset->m_texture.reset(); - - if (std::holds_alternative<VideoCommon::ShaderProperty::Sampler2D>( - shader_it->second.m_default)) - { - texture_asset->m_sampler_code = - fmt::format("SAMPLER_BINDING({}) uniform sampler2D samp_{};\n", sampler_index, - property.m_code_name); - texture_asset->m_define_code = fmt::format("#define HAS_{} 1\n", property.m_code_name); - } - else if (std::holds_alternative<VideoCommon::ShaderProperty::Sampler2DArray>( - shader_it->second.m_default)) - { - texture_asset->m_sampler_code = - fmt::format("SAMPLER_BINDING({}) uniform sampler2DArray samp_{};\n", sampler_index, - property.m_code_name); - texture_asset->m_define_code = fmt::format("#define HAS_{} 1\n", property.m_code_name); - } - else if (std::holds_alternative<VideoCommon::ShaderProperty::SamplerCube>( - shader_it->second.m_default)) - { - texture_asset->m_sampler_code = - fmt::format("SAMPLER_BINDING({}) uniform samplerCube samp_{};\n", sampler_index, - property.m_code_name); - texture_asset->m_define_code = fmt::format("#define HAS_{} 1\n", property.m_code_name); - } - } - - const auto texture_data = texture_asset->m_cached_asset.m_asset->GetData(); - if (!texture_data) - { - return; - } - - if (texture_asset->m_texture) - { - g_gfx->SetTexture(sampler_index, texture_asset->m_texture.get()); - g_gfx->SetSamplerState(sampler_index, texture_data->m_sampler); - } - else - { - AbstractTextureType texture_usage = AbstractTextureType::Texture_2DArray; - if (std::holds_alternative<VideoCommon::ShaderProperty::SamplerCube>( - shader_it->second.m_default)) - { - texture_usage = AbstractTextureType::Texture_CubeMap; - } - else if (std::holds_alternative<VideoCommon::ShaderProperty::Sampler2D>( - shader_it->second.m_default)) - { - texture_usage = AbstractTextureType::Texture_2D; - } - - if (texture_data->m_texture.m_slices.empty() || - texture_data->m_texture.m_slices[0].m_levels.empty()) - { - return; - } - - auto& first_slice = texture_data->m_texture.m_slices[0]; - const TextureConfig texture_config( - first_slice.m_levels[0].width, first_slice.m_levels[0].height, - static_cast<u32>(first_slice.m_levels.size()), - static_cast<u32>(texture_data->m_texture.m_slices.size()), 1, - first_slice.m_levels[0].format, 0, texture_usage); - texture_asset->m_texture = g_gfx->CreateTexture( - texture_config, fmt::format("Custom shader texture '{}'", property.m_code_name)); - for (std::size_t slice_index = 0; slice_index < texture_data->m_texture.m_slices.size(); - slice_index++) - { - auto& slice = texture_data->m_texture.m_slices[slice_index]; - for (u32 level_index = 0; level_index < static_cast<u32>(slice.m_levels.size()); - ++level_index) - { - auto& level = slice.m_levels[level_index]; - texture_asset->m_texture->Load(level_index, level.width, level.height, - level.row_length, level.data.data(), level.data.size(), - static_cast<u32>(slice_index)); - } - } - } - - sampler_index++; - } - } - else - { - VideoCommon::MaterialProperty::WriteToMemory(material_buffer, property); - } - } - - if (m_last_generated_shader_code.GetBuffer().empty()) - { - // Calculate shader details - std::string color_shader_data = - ReplaceAll(shader_data->m_shader_source, "custom_main", CUSTOM_PIXELSHADER_COLOR_FUNC); - const auto global_conflicts = GlobalConflicts(color_shader_data); - color_shader_data = ReplaceAll(color_shader_data, "\r\n", "\n"); - color_shader_data = ReplaceAll(color_shader_data, "{", "{{"); - color_shader_data = ReplaceAll(color_shader_data, "}", "}}"); - // First replace global conflicts with dummy strings - // This avoids the problem where a shorter word - // is in a longer word, ex two functions: 'execute' and 'execute_fast' - for (std::size_t i = 0; i < global_conflicts.size(); i++) - { - const std::string& identifier = global_conflicts[i]; - color_shader_data = - ReplaceAll(color_shader_data, identifier, fmt::format("_{0}_DOLPHIN_TEMP_{0}_", i)); - } - // Now replace the temporaries with the actual value - for (std::size_t i = 0; i < global_conflicts.size(); i++) - { - const std::string& identifier = global_conflicts[i]; - color_shader_data = ReplaceAll(color_shader_data, fmt::format("_{0}_DOLPHIN_TEMP_{0}_", i), - fmt::format("{}_{{0}}", identifier)); - } - - for (const auto& game_texture : pass.m_game_textures) - { - if (!game_texture) - continue; - - m_last_generated_shader_code.Write("{}", game_texture->m_sampler_code); - m_last_generated_shader_code.Write("{}", game_texture->m_define_code); - } - - for (std::size_t i = 0; i < draw_started->texture_units.size(); i++) - { - const auto& texture_unit = draw_started->texture_units[i]; - m_last_generated_shader_code.Write( - "#define TEX_COORD{} data.texcoord[data.texmap_to_texcoord_index[{}]].xy\n", i, - texture_unit); - } - m_last_generated_shader_code.Write("{}", color_shader_data); - } + pass.UpdatePixelData(loader, m_library, draw_started->texture_units, + pass_config.m_pixel_material_asset); CustomPixelShader custom_pixel_shader; - custom_pixel_shader.custom_shader = m_last_generated_shader_code.GetBuffer(); - custom_pixel_shader.material_uniform_block = m_last_generated_material_code.GetBuffer(); + custom_pixel_shader.custom_shader = pass.m_last_generated_shader_code.GetBuffer(); + custom_pixel_shader.material_uniform_block = pass.m_last_generated_material_code.GetBuffer(); *draw_started->custom_pixel_shader = custom_pixel_shader; - *draw_started->material_uniform_buffer = m_material_data; + *draw_started->material_uniform_buffer = pass.m_material_data; } |
