From 04ffa824d728d5a26ed73cfd3eb3af661b8f9ae8 Mon Sep 17 00:00:00 2001 From: iwubcode Date: Mon, 17 Nov 2025 18:29:48 -0600 Subject: [PATCH 01/12] VideoCommon: add a 'AfterEFB' action to GraphicsMods that can return a Material, rename previous EFB action as 'BeforeEFB' --- .../GraphicsModSystem/Runtime/Actions/PrintAction.cpp | 2 +- .../GraphicsModSystem/Runtime/Actions/PrintAction.h | 2 +- .../GraphicsModSystem/Runtime/Actions/ScaleAction.cpp | 2 +- .../GraphicsModSystem/Runtime/Actions/ScaleAction.h | 2 +- .../GraphicsModSystem/Runtime/Actions/SkipAction.cpp | 2 +- .../GraphicsModSystem/Runtime/Actions/SkipAction.h | 2 +- .../GraphicsModSystem/Runtime/GraphicsModAction.h | 5 +++-- .../GraphicsModSystem/Runtime/GraphicsModActionData.h | 8 +++++++- .../GraphicsModSystem/Runtime/GraphicsModManager.cpp | 10 ++++++++-- Source/Core/VideoCommon/TextureCacheBase.cpp | 6 +++--- 10 files changed, 27 insertions(+), 14 deletions(-) diff --git a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/PrintAction.cpp b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/PrintAction.cpp index 1bd288512c..ca50a9a430 100644 --- a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/PrintAction.cpp +++ b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/PrintAction.cpp @@ -10,7 +10,7 @@ void PrintAction::OnDrawStarted(GraphicsModActionData::DrawStarted*) INFO_LOG_FMT(VIDEO, "OnDrawStarted Called"); } -void PrintAction::OnEFB(GraphicsModActionData::EFB* efb) +void PrintAction::BeforeEFB(GraphicsModActionData::PreEFB* efb) { if (!efb) [[unlikely]] return; diff --git a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/PrintAction.h b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/PrintAction.h index 82a21c152f..55bd694a6e 100644 --- a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/PrintAction.h +++ b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/PrintAction.h @@ -12,7 +12,7 @@ class PrintAction final : public GraphicsModAction public: static constexpr std::string_view factory_name = "print"; void OnDrawStarted(GraphicsModActionData::DrawStarted*) override; - void OnEFB(GraphicsModActionData::EFB*) override; + void BeforeEFB(GraphicsModActionData::PreEFB*) override; void OnProjection(GraphicsModActionData::Projection*) override; void OnProjectionAndTexture(GraphicsModActionData::Projection*) override; void OnTextureLoad(GraphicsModActionData::TextureLoad*) override; diff --git a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/ScaleAction.cpp b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/ScaleAction.cpp index 305cd8b737..6db08b8351 100644 --- a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/ScaleAction.cpp +++ b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/ScaleAction.cpp @@ -30,7 +30,7 @@ ScaleAction::ScaleAction(Common::Vec3 scale) : m_scale(scale) { } -void ScaleAction::OnEFB(GraphicsModActionData::EFB* efb) +void ScaleAction::BeforeEFB(GraphicsModActionData::PreEFB* efb) { if (!efb) [[unlikely]] return; diff --git a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/ScaleAction.h b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/ScaleAction.h index 4673ed2d18..2ed9d71393 100644 --- a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/ScaleAction.h +++ b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/ScaleAction.h @@ -16,7 +16,7 @@ public: static constexpr std::string_view factory_name = "scale"; static std::unique_ptr Create(const picojson::value& json_data); explicit ScaleAction(Common::Vec3 scale); - void OnEFB(GraphicsModActionData::EFB*) override; + void BeforeEFB(GraphicsModActionData::PreEFB*) override; void OnProjection(GraphicsModActionData::Projection*) override; void OnProjectionAndTexture(GraphicsModActionData::Projection*) override; diff --git a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/SkipAction.cpp b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/SkipAction.cpp index b693fef4f7..3473826fc5 100644 --- a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/SkipAction.cpp +++ b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/SkipAction.cpp @@ -14,7 +14,7 @@ void SkipAction::OnDrawStarted(GraphicsModActionData::DrawStarted* draw_started) *draw_started->skip = true; } -void SkipAction::OnEFB(GraphicsModActionData::EFB* efb) +void SkipAction::BeforeEFB(GraphicsModActionData::PreEFB* efb) { if (!efb) [[unlikely]] return; diff --git a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/SkipAction.h b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/SkipAction.h index 8cda643c5a..df397802ae 100644 --- a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/SkipAction.h +++ b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/SkipAction.h @@ -10,5 +10,5 @@ class SkipAction final : public GraphicsModAction public: static constexpr std::string_view factory_name = "skip"; void OnDrawStarted(GraphicsModActionData::DrawStarted*) override; - void OnEFB(GraphicsModActionData::EFB*) override; + void BeforeEFB(GraphicsModActionData::PreEFB*) override; }; diff --git a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModAction.h b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModAction.h index 04a371a73e..5719d550fe 100644 --- a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModAction.h +++ b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModAction.h @@ -16,8 +16,9 @@ public: GraphicsModAction& operator=(GraphicsModAction&&) = default; virtual void OnDrawStarted(GraphicsModActionData::DrawStarted*) {} - virtual void OnEFB(GraphicsModActionData::EFB*) {} - virtual void OnXFB() {} + virtual void BeforeEFB(GraphicsModActionData::PreEFB*) {} + virtual void AfterEFB(GraphicsModActionData::PostEFB*) {} + virtual void BeforeXFB() {} virtual void OnProjection(GraphicsModActionData::Projection*) {} virtual void OnProjectionAndTexture(GraphicsModActionData::Projection*) {} virtual void OnTextureLoad(GraphicsModActionData::TextureLoad*) {} diff --git a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModActionData.h b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModActionData.h index a4e883ffc2..e82c87e0e4 100644 --- a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModActionData.h +++ b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModActionData.h @@ -12,6 +12,7 @@ #include "Common/Matrix.h" #include "Common/SmallVector.h" #include "VideoCommon/Assets/TextureAsset.h" +#include "VideoCommon/Resources/MaterialResource.h" #include "VideoCommon/ShaderGenCommon.h" namespace GraphicsModActionData @@ -24,7 +25,7 @@ struct DrawStarted std::span* material_uniform_buffer; }; -struct EFB +struct PreEFB { u32 texture_width; u32 texture_height; @@ -33,6 +34,11 @@ struct EFB u32* scaled_height; }; +struct PostEFB +{ + VideoCommon::MaterialResource* material = nullptr; +}; + struct Projection { Common::Matrix44* matrix; diff --git a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModManager.cpp b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModManager.cpp index 79f19fe325..d97fb49d58 100644 --- a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModManager.cpp +++ b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModManager.cpp @@ -36,11 +36,17 @@ public: return; m_action_impl->OnDrawStarted(draw_started); } - void OnEFB(GraphicsModActionData::EFB* efb) override + void BeforeEFB(GraphicsModActionData::PreEFB* efb) override { if (!m_mod.m_enabled) return; - m_action_impl->OnEFB(efb); + m_action_impl->BeforeEFB(efb); + } + void AfterEFB(GraphicsModActionData::PostEFB* efb) override + { + if (!m_mod.m_enabled) + return; + m_action_impl->AfterEFB(efb); } void OnProjection(GraphicsModActionData::Projection* projection) override { diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index 4b048ef2ac..97044c22df 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -2256,16 +2256,16 @@ void TextureCacheBase::CopyRenderTargetToTexture( { for (const auto& action : g_graphics_mod_manager->GetXFBActions(info)) { - action->OnXFB(); + action->BeforeXFB(); } } else { bool skip = false; - GraphicsModActionData::EFB efb{tex_w, tex_h, &skip, &scaled_tex_w, &scaled_tex_h}; + GraphicsModActionData::PreEFB efb{tex_w, tex_h, &skip, &scaled_tex_w, &scaled_tex_h}; for (const auto& action : g_graphics_mod_manager->GetEFBActions(info)) { - action->OnEFB(&efb); + action->BeforeEFB(&efb); } if (skip == true) { From 76e44df132eec545027fca1588b58f40c3ba3d50 Mon Sep 17 00:00:00 2001 From: iwubcode Date: Mon, 17 Nov 2025 18:32:47 -0600 Subject: [PATCH 02/12] VideoCommon: add another another function to 'CustomResourceManager' to get a Material for post processing, this material does not have a UID which is needed for drawing, and handles slightly differently during the processing/compilation step --- .../Resources/CustomResourceManager.cpp | 33 +- .../Resources/CustomResourceManager.h | 19 +- .../Resources/MaterialResource.cpp | 111 ++++-- .../VideoCommon/Resources/MaterialResource.h | 6 +- .../VideoCommon/Resources/ShaderResource.cpp | 318 +++++++++++++++--- .../VideoCommon/Resources/ShaderResource.h | 9 +- 6 files changed, 410 insertions(+), 86 deletions(-) diff --git a/Source/Core/VideoCommon/Resources/CustomResourceManager.cpp b/Source/Core/VideoCommon/Resources/CustomResourceManager.cpp index ffb16b055a..1c571dc2a8 100644 --- a/Source/Core/VideoCommon/Resources/CustomResourceManager.cpp +++ b/Source/Core/VideoCommon/Resources/CustomResourceManager.cpp @@ -43,7 +43,8 @@ void CustomResourceManager::Shutdown() void CustomResourceManager::Reset() { - m_material_resources.clear(); + m_draw_material_resources.clear(); + m_postprocessing_material_resources.clear(); m_shader_resources.clear(); m_texture_data_resources.clear(); m_texture_sampler_resources.clear(); @@ -102,11 +103,11 @@ TextureDataResource* CustomResourceManager::GetTextureDataFromAsset( return resource.get(); } -MaterialResource* CustomResourceManager::GetMaterialFromAsset( +MaterialResource* CustomResourceManager::GetDrawMaterialFromAsset( const CustomAssetLibrary::AssetID& asset_id, const GXPipelineUid& pipeline_uid, std::shared_ptr library) { - auto& resource = m_material_resources[asset_id][PipelineToHash(pipeline_uid)]; + auto& resource = m_draw_material_resources[asset_id][PipelineToHash(pipeline_uid)]; if (resource == nullptr) { resource = std::make_unique( @@ -116,17 +117,31 @@ MaterialResource* CustomResourceManager::GetMaterialFromAsset( return resource.get(); } -ShaderResource* -CustomResourceManager::GetShaderFromAsset(const CustomAssetLibrary::AssetID& asset_id, - std::size_t shader_key, const GXPipelineUid& pipeline_uid, - const std::string& preprocessor_settings, - std::shared_ptr library) +MaterialResource* CustomResourceManager::GetPostProcessingMaterialFromAsset( + const CustomAssetLibrary::AssetID& asset_id, + std::shared_ptr library) +{ + auto& resource = m_postprocessing_material_resources[asset_id]; + if (resource == nullptr) + { + resource = + std::make_unique(CreateResourceContext(asset_id, std::move(library))); + } + resource->Process(); + return resource.get(); +} + +ShaderResource* CustomResourceManager::GetShaderFromAsset( + const CustomAssetLibrary::AssetID& asset_id, std::size_t shader_key, + std::optional pipeline_uid, const std::string& preprocessor_settings, + std::shared_ptr library) { auto& resource = m_shader_resources[asset_id][shader_key]; if (resource == nullptr) { resource = std::make_unique(CreateResourceContext(asset_id, std::move(library)), - pipeline_uid, preprocessor_settings, m_host_config); + std::move(pipeline_uid), preprocessor_settings, + m_host_config); } resource->Process(); return resource.get(); diff --git a/Source/Core/VideoCommon/Resources/CustomResourceManager.h b/Source/Core/VideoCommon/Resources/CustomResourceManager.h index 04eaa46942..fcced2cdc2 100644 --- a/Source/Core/VideoCommon/Resources/CustomResourceManager.h +++ b/Source/Core/VideoCommon/Resources/CustomResourceManager.h @@ -37,14 +37,20 @@ public: TextureDataResource* GetTextureDataFromAsset(const CustomAssetLibrary::AssetID& asset_id, std::shared_ptr library); - MaterialResource* GetMaterialFromAsset(const CustomAssetLibrary::AssetID& asset_id, - const GXPipelineUid& pipeline_uid, - std::shared_ptr library); + MaterialResource* + GetDrawMaterialFromAsset(const CustomAssetLibrary::AssetID& asset_id, + const GXPipelineUid& pipeline_uid, + std::shared_ptr library); + MaterialResource* + GetPostProcessingMaterialFromAsset(const CustomAssetLibrary::AssetID& asset_id, + std::shared_ptr library); ShaderResource* GetShaderFromAsset(const CustomAssetLibrary::AssetID& asset_id, - std::size_t shader_key, const GXPipelineUid& pipeline_uid, + std::size_t shader_key, + std::optional pipeline_uid, const std::string& preprocessor_settings, std::shared_ptr library); + TextureAndSamplerResource* GetTextureAndSamplerFromAsset(const CustomAssetLibrary::AssetID& asset_id, std::shared_ptr library); @@ -59,7 +65,7 @@ private: std::unique_ptr m_async_shader_compiler; using PipelineIdToMaterial = std::map>; - std::map m_material_resources; + std::map m_draw_material_resources; using ShaderKeyToShader = std::map>; std::map m_shader_resources; @@ -70,6 +76,9 @@ private: std::map> m_texture_sampler_resources; + std::map> + m_postprocessing_material_resources; + ShaderHostConfig m_host_config; Common::EventHook m_xfb_event; diff --git a/Source/Core/VideoCommon/Resources/MaterialResource.cpp b/Source/Core/VideoCommon/Resources/MaterialResource.cpp index 38486d7932..d41937d992 100644 --- a/Source/Core/VideoCommon/Resources/MaterialResource.cpp +++ b/Source/Core/VideoCommon/Resources/MaterialResource.cpp @@ -54,6 +54,13 @@ SamplerState CalculateSamplerAnisotropy(const SamplerState& initial_sampler) namespace VideoCommon { +MaterialResource::MaterialResource(Resource::ResourceContext resource_context) + : Resource(std::move(resource_context)) +{ + m_material_asset = m_resource_context.asset_cache->CreateAsset( + m_resource_context.primary_asset_id, m_resource_context.asset_library, this); +} + MaterialResource::MaterialResource(Resource::ResourceContext resource_context, const GXPipelineUid& pipeline_uid) : Resource(std::move(resource_context)), m_uid(pipeline_uid) @@ -61,8 +68,8 @@ MaterialResource::MaterialResource(Resource::ResourceContext resource_context, m_material_asset = m_resource_context.asset_cache->CreateAsset( m_resource_context.primary_asset_id, m_resource_context.asset_library, this); m_uid_vertex_format_copy = - g_gfx->CreateNativeVertexFormat(m_uid.vertex_format->GetVertexDeclaration()); - m_uid.vertex_format = m_uid_vertex_format_copy.get(); + g_gfx->CreateNativeVertexFormat(m_uid->vertex_format->GetVertexDeclaration()); + m_uid->vertex_format = m_uid_vertex_format_copy.get(); } void MaterialResource::ResetData() @@ -98,7 +105,7 @@ Resource::TaskComplete MaterialResource::CollectPrimaryData() } CreateTextureData(m_load_data.get()); - SetShaderKey(m_load_data.get(), &m_uid); + SetShaderKey(m_load_data.get(), m_uid ? &*m_uid : nullptr); return Resource::TaskComplete::Yes; } @@ -140,8 +147,18 @@ Resource::TaskComplete MaterialResource::CollectDependencyData() if (m_load_data->m_material_data->next_material_asset != "") { - m_load_data->m_next_material = m_resource_context.resource_manager->GetMaterialFromAsset( - m_load_data->m_material_data->next_material_asset, m_uid, m_resource_context.asset_library); + if (m_uid) + { + m_load_data->m_next_material = m_resource_context.resource_manager->GetDrawMaterialFromAsset( + m_load_data->m_material_data->next_material_asset, *m_uid, + m_resource_context.asset_library); + } + else + { + m_load_data->m_next_material = + m_resource_context.resource_manager->GetPostProcessingMaterialFromAsset( + m_load_data->m_material_data->next_material_asset, m_resource_context.asset_library); + } m_load_data->m_next_material->AddReference(this); const auto data_processed = m_load_data->m_next_material->IsDataProcessed(); if (data_processed == TaskComplete::Error) @@ -222,33 +239,66 @@ Resource::TaskComplete MaterialResource::ProcessData() config.pixel_shader = m_shader_resource_data->GetPixelShader(); config.geometry_shader = m_shader_resource_data->GetGeometryShader(); - const auto actual_uid = ApplyDriverBugs(*m_uid); - - if (m_material_resource_data->m_material_data->blending_state) - config.blending_state = *m_material_resource_data->m_material_data->blending_state; - else - config.blending_state = actual_uid.blending_state; - - if (m_material_resource_data->m_material_data->depth_state) - config.depth_state = *m_material_resource_data->m_material_data->depth_state; - else - config.depth_state = actual_uid.depth_state; - - config.framebuffer_state = std::move(m_frame_buffer_state); - config.framebuffer_state.additional_color_attachment_count = 0; - - config.rasterization_state = actual_uid.rasterization_state; - if (m_material_resource_data->m_material_data->cull_mode) + if (m_uid) { - config.rasterization_state.cull_mode = - *m_material_resource_data->m_material_data->cull_mode; + // Draw based pipeline + const auto actual_uid = ApplyDriverBugs(*m_uid); + + if (m_material_resource_data->m_material_data->blending_state) + config.blending_state = *m_material_resource_data->m_material_data->blending_state; + else + config.blending_state = actual_uid.blending_state; + + if (m_material_resource_data->m_material_data->depth_state) + config.depth_state = *m_material_resource_data->m_material_data->depth_state; + else + config.depth_state = actual_uid.depth_state; + + config.framebuffer_state = std::move(m_frame_buffer_state); + config.framebuffer_state.additional_color_attachment_count = 0; + + config.rasterization_state = actual_uid.rasterization_state; + if (m_material_resource_data->m_material_data->cull_mode) + { + config.rasterization_state.cull_mode = + *m_material_resource_data->m_material_data->cull_mode; + } + + config.vertex_format = actual_uid.vertex_format; + config.usage = AbstractPipelineUsage::GX; + } + else + { + // Post processing based pipeline + + // Many of these properties don't make sense to replace but we expose them for draw + // based materials, might as well allow them to be used if the user wants + + if (m_material_resource_data->m_material_data->blending_state) + config.blending_state = *m_material_resource_data->m_material_data->blending_state; + else + config.blending_state = RenderState::GetNoBlendingBlendState(); + + if (m_material_resource_data->m_material_data->depth_state) + config.depth_state = *m_material_resource_data->m_material_data->depth_state; + else + config.depth_state = RenderState::GetNoDepthTestingDepthState(); + + config.framebuffer_state = RenderState::GetRGBA8FramebufferState(); + + config.rasterization_state = + RenderState::GetNoCullRasterizationState(PrimitiveType::Triangles); + if (m_material_resource_data->m_material_data->cull_mode) + { + config.rasterization_state.cull_mode = + *m_material_resource_data->m_material_data->cull_mode; + } + + config.vertex_format = nullptr; + config.usage = AbstractPipelineUsage::Utility; } - config.vertex_format = actual_uid.vertex_format; - config.usage = AbstractPipelineUsage::GX; - m_material_resource_data->m_pipeline = g_gfx->CreatePipeline(config); - if (m_material_resource_data->m_pipeline) { WriteUniforms(m_material_resource_data.get()); @@ -268,7 +318,7 @@ Resource::TaskComplete MaterialResource::ProcessData() if (!m_processing_load_data) { auto wi = m_resource_context.shader_compiler->CreateWorkItem( - m_load_data, std::move(shader_data), &m_uid, + m_load_data, std::move(shader_data), m_uid ? &*m_uid : nullptr, g_framebuffer_manager->GetEFBFramebufferState()); // We don't need priority, that is already handled by the resource system @@ -360,7 +410,8 @@ void MaterialResource::SetShaderKey(Data* data, GXPipelineUid* uid) XXH3_INITSTATE(&shader_key_hash); XXH3_64bits_reset_withSeed(&shader_key_hash, static_cast(1)); - UpdateHashWithPipeline(*uid, &shader_key_hash); + if (uid) + UpdateHashWithPipeline(*uid, &shader_key_hash); XXH3_64bits_update(&shader_key_hash, data->m_preprocessor_settings.c_str(), data->m_preprocessor_settings.size()); diff --git a/Source/Core/VideoCommon/Resources/MaterialResource.h b/Source/Core/VideoCommon/Resources/MaterialResource.h index 4842f000ea..6f4835927f 100644 --- a/Source/Core/VideoCommon/Resources/MaterialResource.h +++ b/Source/Core/VideoCommon/Resources/MaterialResource.h @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -27,6 +28,7 @@ namespace VideoCommon class MaterialResource final : public Resource { public: + explicit MaterialResource(Resource::ResourceContext resource_context); MaterialResource(Resource::ResourceContext resource_context, const GXPipelineUid& pipeline_uid); struct TextureLikeReference @@ -93,7 +95,9 @@ private: // Note: asset cache owns the asset, we access as a reference MaterialAsset* m_material_asset = nullptr; - GXPipelineUid m_uid; + // If provided, denotes this material will be used as a custom draw material. + // If not provided, denotes this will be used as an efb post processing material. + std::optional m_uid; std::unique_ptr m_uid_vertex_format_copy; }; } // namespace VideoCommon diff --git a/Source/Core/VideoCommon/Resources/ShaderResource.cpp b/Source/Core/VideoCommon/Resources/ShaderResource.cpp index 47600f2c6a..6b3b4e0a68 100644 --- a/Source/Core/VideoCommon/Resources/ShaderResource.cpp +++ b/Source/Core/VideoCommon/Resources/ShaderResource.cpp @@ -10,6 +10,7 @@ #include "VideoCommon/AbstractGfx.h" #include "VideoCommon/Assets/CustomAssetCache.h" #include "VideoCommon/AsyncShaderCompiler.h" +#include "VideoCommon/FramebufferShaderGen.h" #include "VideoCommon/GeometryShaderGen.h" #include "VideoCommon/PipelineUtils.h" #include "VideoCommon/PixelShaderGen.h" @@ -20,20 +21,223 @@ namespace VideoCommon { namespace { -std::unique_ptr -CompileGeometryShader(const GeometryShaderUid& uid, APIType api_type, ShaderHostConfig host_config) +// TODO: the uniform buffer is combined due to the utility path only having a single +// set of constants, this isn't ideal (both for the end user, where it's more readable +// to see 'custom_uniforms' before variables and from Dolphin because the +// standard uniforms have to be packed with the custom ones +void GeneratePostProcessUniformOutput(ShaderCode& shader_source, std::string_view block_name, + std::string_view uniforms) { - const ShaderCode source_code = - GenerateGeometryShaderCode(api_type, host_config, uid.GetUidData()); - return g_gfx->CreateShaderFromSource(ShaderStage::Geometry, source_code.GetBuffer(), nullptr, - fmt::format("Geometry shader: {}", *uid.GetUidData())); + shader_source.Write("UBO_BINDING(std140, 1) uniform {} {{\n", block_name); + shader_source.Write("\tvec4 source_resolution;\n"); + shader_source.Write("\tvec4 target_resolution;\n"); + shader_source.Write("\tvec4 window_resolution;\n"); + shader_source.Write("\tvec4 source_region;\n"); + shader_source.Write("\tint source_layer;\n"); + shader_source.Write("\tint source_layer_pad1;\n"); + shader_source.Write("\tint source_layer_pad2;\n"); + shader_source.Write("\tint source_layer_pad3;\n"); + shader_source.Write("\tuint time;\n"); + shader_source.Write("\tuint time_pad1;\n"); + shader_source.Write("\tuint time_pad2;\n"); + shader_source.Write("\tuint time_pad3;\n"); + shader_source.Write("\tint graphics_api;\n"); + shader_source.Write("\tint graphics_api_pad1;\n"); + shader_source.Write("\tint graphics_api_pad2;\n"); + shader_source.Write("\tint graphics_api_pad3;\n"); + shader_source.Write("\tuint efb_scale;\n"); + shader_source.Write("\tuint efb_scale_pad1;\n"); + shader_source.Write("\tuint efb_scale_pad2;\n"); + shader_source.Write("\tuint efb_scale_pad3;\n"); + if (!uniforms.empty()) + { + shader_source.Write("{}", uniforms); + } + shader_source.Write("}};\n"); } -std::unique_ptr CompilePixelShader(const PixelShaderUid& uid, - std::string_view preprocessor_settings, - APIType api_type, - const ShaderHostConfig& host_config, - RasterSurfaceShaderData* shader_data) +// TODO: move this to a more standard post processing file +// once post processing has been cleaned up +void GeneratePostProcessingVertexShader(ShaderCode& shader_source, + const CustomVertexContents& custom_contents) +{ + // Note: if blocks are the same, they need to match for the OpenGL backend + GeneratePostProcessUniformOutput(shader_source, "PSBlock", custom_contents.uniforms); + + // Define some defines that are shared with custom draw shaders, + // so that a common shader code could possibly be used in both + shader_source.Write("#define HAS_COLOR_0 0\n"); + shader_source.Write("#define HAS_COLOR_1 0\n"); + shader_source.Write("#define HAS_NORMAL 0\n"); + shader_source.Write("#define HAS_BINORMAL 0\n"); + shader_source.Write("#define HAS_TANGENT 0\n"); + shader_source.Write("#define HAS_TEXTURE_COORD_0 1\n"); + for (u32 i = 1; i < 8; i++) + { + shader_source.Write("#define HAS_TEXTURE_COORD_{} 0\n", i); + } + + // Write the common structs, might want to consider + // moving these to another location? + shader_source.Write("struct DolphinVertexInput\n"); + shader_source.Write("{{\n"); + shader_source.Write("\tvec4 position;\n"); + shader_source.Write("\tvec3 texture_coord_0;\n"); + shader_source.Write("}};\n\n"); + + shader_source.Write("struct DolphinVertexOutput\n"); + shader_source.Write("{{\n"); + shader_source.Write("\tvec4 position;\n"); + shader_source.Write("\tvec3 texture_coord_0;\n"); + shader_source.Write("}};\n\n"); + + constexpr std::string_view emulated_vertex_definition = + "void dolphin_process_emulated_vertex(in DolphinVertexInput vertex_input, out " + "DolphinVertexOutput vertex_output)"; + shader_source.Write("{}\n", emulated_vertex_definition); + shader_source.Write("{{\n"); + shader_source.Write("\tvertex_output.position = vertex_input.position;\n"); + shader_source.Write("\tvertex_output.texture_coord_0 = vertex_input.texture_coord_0;\n"); + shader_source.Write("}}\n"); + + if (custom_contents.shader.empty()) + { + shader_source.Write( + "void process_vertex(in DolphinVertexInput vertex_input, out DolphinVertexOutput " + "vertex_output)\n"); + shader_source.Write("{{\n"); + + shader_source.Write("\tdolphin_process_emulated_vertex(vertex_input, vertex_output);\n"); + + shader_source.Write("}}\n"); + } + else + { + shader_source.Write("{}\n", custom_contents.shader); + } + + if (g_backend_info.bSupportsGeometryShaders) + { + shader_source.Write("VARYING_LOCATION(0) out VertexData {{\n"); + shader_source.Write("\tvec3 v_tex0;\n"); + shader_source.Write("}};\n"); + } + else + { + shader_source.Write("VARYING_LOCATION(0) out vec3 v_tex0;\n"); + } + + shader_source.Write("void main()\n"); + shader_source.Write("{{\n"); + shader_source.Write("\tDolphinVertexInput vertex_input;\n"); + shader_source.Write("\tvec3 vert = vec3(float((gl_VertexID << 1) & 2), " + "float(gl_VertexID & 2), 0.0f);\n"); + shader_source.Write("\tvertex_input.position = vec4(vert.xy * " + "float2(2.0f, -2.0f) + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n"); + shader_source.Write("\tvertex_input.texture_coord_0 = vec3(source_region.xy + " + "(source_region.zw * vert.xy), 0.0f);\n"); + shader_source.Write("\tDolphinVertexOutput vertex_output;\n"); + shader_source.Write("\tprocess_vertex(vertex_input, vertex_output);\n"); + shader_source.Write("\tgl_Position = vertex_output.position;\n"); + shader_source.Write("\tv_tex0 = vertex_output.texture_coord_0;\n"); + + // NDC space is flipped in Vulkan + if (g_backend_info.api_type == APIType::Vulkan) + { + shader_source.Write("\tgl_Position.y = -gl_Position.y;\n"); + } + + shader_source.Write("}}\n"); +} + +void GeneratePostProcessingPixelShader(ShaderCode& shader_source, + const CustomPixelContents& custom_contents) +{ + GeneratePostProcessUniformOutput(shader_source, "PSBlock", custom_contents.uniforms); + + shader_source.Write("SAMPLER_BINDING(0) uniform sampler2DArray samp0;\n"); + + if (g_backend_info.bSupportsGeometryShaders) + { + shader_source.Write("VARYING_LOCATION(0) in VertexData {{\n"); + shader_source.Write("\tvec3 v_tex0;\n"); + shader_source.Write("}};\n"); + } + else + { + shader_source.Write("VARYING_LOCATION(0) in float3 v_tex0;\n"); + } + + shader_source.Write("FRAGMENT_OUTPUT_LOCATION(0) out vec4 ocol0;\n"); + + shader_source.Write("struct DolphinFragmentInput\n"); + shader_source.Write("{{\n"); + for (u32 i = 0; i < 1; i++) + { + shader_source.Write("\tvec3 tex{};\n", i); + } + shader_source.Write("\n"); + + shader_source.Write("}};\n\n"); + + shader_source.Write("struct DolphinFragmentOutput\n"); + shader_source.Write("{{\n"); + shader_source.Write("\tvec4 main;\n"); + shader_source.Write("}};\n\n"); + + constexpr std::string_view emulated_fragment_definition = + "void dolphin_process_emulated_fragment(in DolphinFragmentInput frag_input, out " + "DolphinFragmentOutput frag_output)"; + shader_source.Write("{}\n", emulated_fragment_definition); + shader_source.Write("{{\n"); + shader_source.Write("\tfrag_output.main = texture(samp0, frag_input.tex0);\n"); + shader_source.Write("}}\n"); + + if (custom_contents.shader.empty()) + { + shader_source.Write( + "void process_fragment(in DolphinFragmentInput frag_input, out DolphinFragmentOutput " + "frag_output)\n"); + shader_source.Write("{{\n"); + + shader_source.Write("\tdolphin_process_emulated_fragment(frag_input, frag_output);\n"); + + shader_source.Write("}}\n"); + } + else + { + shader_source.Write("{}\n", custom_contents.shader); + } + + shader_source.Write("void main()\n"); + shader_source.Write("{{\n"); + shader_source.Write("\tDolphinFragmentInput frag_input;\n"); + shader_source.Write("\tfrag_input.tex0 = v_tex0;\n"); + shader_source.Write("\tDolphinFragmentOutput frag_output;\n"); + shader_source.Write("\tprocess_fragment(frag_input, frag_output);\n"); + shader_source.Write("\tocol0 = frag_output.main;\n"); + shader_source.Write("}}\n"); +} + +std::unique_ptr CompileGeometryShader(GeometryShaderUid* uid, APIType api_type, + ShaderHostConfig host_config) +{ + if (!uid) + { + return g_gfx->CreateShaderFromSource( + ShaderStage::Geometry, FramebufferShaderGen::GeneratePassthroughGeometryShader(1, 0), + nullptr, "Custom Post Processing Geometry Shader"); + } + + const ShaderCode source_code = + GenerateGeometryShaderCode(api_type, host_config, uid->GetUidData()); + return g_gfx->CreateShaderFromSource(ShaderStage::Geometry, source_code.GetBuffer(), nullptr, + fmt::format("Geometry shader: {}", *uid->GetUidData())); +} + +std::unique_ptr +CompilePixelShader(PixelShaderUid* uid, std::string_view preprocessor_settings, APIType api_type, + const ShaderHostConfig& host_config, RasterSurfaceShaderData* shader_data) { ShaderCode shader_code; @@ -89,19 +293,25 @@ std::unique_ptr CompilePixelShader(const PixelShaderUid& uid, // Compile the shader CustomPixelContents contents{.shader = shader_code.GetBuffer(), .uniforms = uniform_code.GetBuffer()}; - const ShaderCode source_code = - GeneratePixelShaderCode(api_type, host_config, uid.GetUidData(), contents); + + ShaderCode source_code; + if (uid) + { + source_code = GeneratePixelShaderCode(api_type, host_config, uid->GetUidData(), contents); + } + else + { + GeneratePostProcessingPixelShader(source_code, contents); + } ShaderIncluder* shader_includer = shader_data->shader_includer ? &*shader_data->shader_includer : nullptr; return g_gfx->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer(), shader_includer, "Custom Pixel Shader"); } -std::unique_ptr CompileVertexShader(const VertexShaderUid& uid, - std::string_view preprocessor_settings, - APIType api_type, - const ShaderHostConfig& host_config, - const RasterSurfaceShaderData& shader_data) +std::unique_ptr +CompileVertexShader(VertexShaderUid* uid, std::string_view preprocessor_settings, APIType api_type, + const ShaderHostConfig& host_config, const RasterSurfaceShaderData& shader_data) { ShaderCode shader_code; @@ -157,18 +367,26 @@ std::unique_ptr CompileVertexShader(const VertexShaderUid& uid, // Compile the shader CustomVertexContents contents{.shader = shader_code.GetBuffer(), .uniforms = uniform_code.GetBuffer()}; - const ShaderCode source_code = - GenerateVertexShaderCode(api_type, host_config, uid.GetUidData(), contents); + + ShaderCode source_code; + if (uid) + { + source_code = GenerateVertexShaderCode(api_type, host_config, uid->GetUidData(), contents); + } + else + { + GeneratePostProcessingVertexShader(source_code, contents); + } return g_gfx->CreateShaderFromSource(ShaderStage::Vertex, source_code.GetBuffer(), nullptr, "Custom Vertex Shader"); } } // namespace ShaderResource::ShaderResource(Resource::ResourceContext resource_context, - const GXPipelineUid& pipeline_uid, + std::optional pipeline_uid, const std::string& preprocessor_setting, const ShaderHostConfig& shader_host_config) : Resource(std::move(resource_context)), m_shader_host_config{.bits = shader_host_config.bits}, - m_uid(pipeline_uid), m_preprocessor_settings(preprocessor_setting) + m_uid(std::move(pipeline_uid)), m_preprocessor_settings(preprocessor_setting) { m_shader_asset = m_resource_context.asset_cache->CreateAsset( m_resource_context.primary_asset_id, m_resource_context.asset_library, this); @@ -257,24 +475,46 @@ Resource::TaskComplete ShaderResource::ProcessData() bool Compile() override { const ShaderHostConfig shader_host_config{.bits = m_shader_bits}; - auto actual_uid = ApplyDriverBugs(*m_uid); - - ClearUnusedPixelShaderUidBits(g_backend_info.api_type, shader_host_config, - &actual_uid.ps_uid); - m_resource_data->m_needs_geometry_shader = shader_host_config.backend_geometry_shaders && - !actual_uid.gs_uid.GetUidData()->IsPassthrough(); - - if (m_resource_data->m_needs_geometry_shader) + if (m_uid) { - m_resource_data->m_geometry_shader = - CompileGeometryShader(actual_uid.gs_uid, g_backend_info.api_type, shader_host_config); + // Draw based shader + auto actual_uid = ApplyDriverBugs(*m_uid); + + ClearUnusedPixelShaderUidBits(g_backend_info.api_type, shader_host_config, + &actual_uid.ps_uid); + m_resource_data->m_needs_geometry_shader = shader_host_config.backend_geometry_shaders && + !actual_uid.gs_uid.GetUidData()->IsPassthrough(); + + if (m_resource_data->m_needs_geometry_shader) + { + m_resource_data->m_geometry_shader = CompileGeometryShader( + &actual_uid.gs_uid, g_backend_info.api_type, shader_host_config); + } + m_resource_data->m_pixel_shader = + CompilePixelShader(&actual_uid.ps_uid, m_preprocessor_settings, g_backend_info.api_type, + shader_host_config, m_resource_data->m_shader_data.get()); + m_resource_data->m_vertex_shader = CompileVertexShader( + &actual_uid.vs_uid, m_preprocessor_settings, g_backend_info.api_type, + shader_host_config, *m_resource_data->m_shader_data); + } + else + { + // Post processing based shader + + m_resource_data->m_needs_geometry_shader = + shader_host_config.backend_geometry_shaders && shader_host_config.stereo; + if (m_resource_data->m_needs_geometry_shader) + { + m_resource_data->m_geometry_shader = + CompileGeometryShader(nullptr, g_backend_info.api_type, shader_host_config); + } + m_resource_data->m_pixel_shader = + CompilePixelShader(nullptr, m_preprocessor_settings, g_backend_info.api_type, + shader_host_config, m_resource_data->m_shader_data.get()); + m_resource_data->m_vertex_shader = + CompileVertexShader(nullptr, m_preprocessor_settings, g_backend_info.api_type, + shader_host_config, *m_resource_data->m_shader_data); } - m_resource_data->m_pixel_shader = - CompilePixelShader(actual_uid.ps_uid, m_preprocessor_settings, g_backend_info.api_type, - shader_host_config, m_resource_data->m_shader_data.get()); - m_resource_data->m_vertex_shader = - CompileVertexShader(actual_uid.vs_uid, m_preprocessor_settings, g_backend_info.api_type, - shader_host_config, *m_resource_data->m_shader_data); m_resource_data->m_processing_finished = true; return true; } @@ -291,7 +531,7 @@ Resource::TaskComplete ShaderResource::ProcessData() { std::string_view preprocessor_settings = m_preprocessor_settings; auto wi = m_resource_context.shader_compiler->CreateWorkItem( - m_load_data, &m_uid, m_shader_host_config.bits, preprocessor_settings); + m_load_data, m_uid ? &*m_uid : nullptr, m_shader_host_config.bits, preprocessor_settings); // We don't need priority, that is already handled by the resource system m_resource_context.shader_compiler->QueueWorkItem(std::move(wi), 0); diff --git a/Source/Core/VideoCommon/Resources/ShaderResource.h b/Source/Core/VideoCommon/Resources/ShaderResource.h index 0f91cd3714..5ca2c06bc9 100644 --- a/Source/Core/VideoCommon/Resources/ShaderResource.h +++ b/Source/Core/VideoCommon/Resources/ShaderResource.h @@ -4,6 +4,7 @@ #pragma once #include +#include #include "VideoCommon/Resources/Resource.h" @@ -16,7 +17,8 @@ namespace VideoCommon class ShaderResource final : public Resource { public: - ShaderResource(Resource::ResourceContext resource_context, const GXPipelineUid& pipeline_uid, + ShaderResource(Resource::ResourceContext resource_context, + std::optional pipeline_uid, const std::string& preprocessor_settings, const ShaderHostConfig& shader_host_config); @@ -61,7 +63,10 @@ private: bool m_processing_load_data = false; ShaderHostConfig m_shader_host_config; - GXPipelineUid m_uid; + + // If provided, denotes this shader will be used as a custom draw shader. + // If not provided, denotes this will be used as an efb post processing shader. + std::optional m_uid; std::string m_preprocessor_settings; }; } // namespace VideoCommon From 90c18992ccb40d7111e49b31a146f1bb67ed4eb0 Mon Sep 17 00:00:00 2001 From: iwubcode Date: Mon, 17 Nov 2025 18:35:55 -0600 Subject: [PATCH 03/12] VideoCommon: update CustomPipelineAction to get a Material when an EFB is received --- .../Runtime/Actions/CustomPipelineAction.cpp | 78 +++++++------------ .../Runtime/Actions/CustomPipelineAction.h | 13 +--- 2 files changed, 29 insertions(+), 62 deletions(-) diff --git a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/CustomPipelineAction.cpp b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/CustomPipelineAction.cpp index 4e22d5b3f8..35c8ce0a25 100644 --- a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/CustomPipelineAction.cpp +++ b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/CustomPipelineAction.cpp @@ -3,7 +3,11 @@ #include "VideoCommon/GraphicsModSystem/Runtime/Actions/CustomPipelineAction.h" +#include "Common/JsonUtil.h" #include "Common/Logging/Log.h" +#include "Core/System.h" + +#include "VideoCommon/Resources/CustomResourceManager.h" std::unique_ptr CustomPipelineAction::Create(std::shared_ptr library) @@ -15,58 +19,16 @@ std::unique_ptr CustomPipelineAction::Create(const picojson::value& json_data, std::shared_ptr library) { - std::vector pipeline_passes; + auto material_asset = ReadStringFromJson(json_data.get(), "material_asset"); - const auto& passes_json = json_data.get("passes"); - if (passes_json.is()) + if (!material_asset) { - for (const auto& passes_json_val : passes_json.get()) - { - CustomPipelineAction::PipelinePassPassDescription pipeline_pass; - if (!passes_json_val.is()) - { - ERROR_LOG_FMT(VIDEO, - "Failed to load custom pipeline action, 'passes' has an array value that " - "is not an object!"); - return nullptr; - } - - auto pass = passes_json_val.get(); - if (!pass.contains("pixel_material_asset")) - { - ERROR_LOG_FMT(VIDEO, - "Failed to load custom pipeline action, 'passes' value missing required " - "field 'pixel_material_asset'"); - return nullptr; - } - - auto pixel_material_asset_json = pass["pixel_material_asset"]; - if (!pixel_material_asset_json.is()) - { - ERROR_LOG_FMT(VIDEO, "Failed to load custom pipeline action, 'passes' field " - "'pixel_material_asset' is not a string!"); - return nullptr; - } - pipeline_pass.m_pixel_material_asset = pixel_material_asset_json.to_str(); - pipeline_passes.push_back(std::move(pipeline_pass)); - } - } - - if (pipeline_passes.empty()) - { - ERROR_LOG_FMT(VIDEO, "Failed to load custom pipeline action, must specify at least one pass"); + ERROR_LOG_FMT(VIDEO, + "Failed to load custom pipeline action, 'material_asset' does not have a value"); return nullptr; } - if (pipeline_passes.size() > 1) - { - ERROR_LOG_FMT( - VIDEO, - "Failed to load custom pipeline action, multiple passes are not currently supported"); - return nullptr; - } - - return std::make_unique(std::move(library), std::move(pipeline_passes)); + return std::make_unique(std::move(library), std::move(*material_asset)); } CustomPipelineAction::CustomPipelineAction(std::shared_ptr library) @@ -74,14 +36,26 @@ CustomPipelineAction::CustomPipelineAction(std::shared_ptr library, - std::vector pass_descriptions) - : m_library(std::move(library)), m_passes_config(std::move(pass_descriptions)) +CustomPipelineAction::CustomPipelineAction(std::shared_ptr library, + std::string material_asset) + : m_library(std::move(library)), m_material_asset(std::move(material_asset)) { - m_pipeline_passes.resize(m_passes_config.size()); } void CustomPipelineAction::OnDrawStarted(GraphicsModActionData::DrawStarted*) { + // TODO +} + +void CustomPipelineAction::AfterEFB(GraphicsModActionData::PostEFB* post_efb) +{ + if (!post_efb) [[unlikely]] + return; + + if (m_material_asset.empty()) + return; + + auto& resource_manager = Core::System::GetInstance().GetCustomResourceManager(); + post_efb->material = + resource_manager.GetPostProcessingMaterialFromAsset(m_material_asset, m_library); } diff --git a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/CustomPipelineAction.h b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/CustomPipelineAction.h index 99026b99ce..d03ccd4a6e 100644 --- a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/CustomPipelineAction.h +++ b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/Actions/CustomPipelineAction.h @@ -6,22 +6,15 @@ #include #include #include -#include #include #include "VideoCommon/Assets/CustomAssetLibrary.h" -#include "VideoCommon/GraphicsModSystem/Runtime/CustomPipeline.h" #include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModAction.h" class CustomPipelineAction final : public GraphicsModAction { public: - struct PipelinePassPassDescription - { - std::string m_pixel_material_asset; - }; - static constexpr std::string_view factory_name = "custom_pipeline"; static std::unique_ptr Create(const picojson::value& json_data, @@ -30,11 +23,11 @@ public: Create(std::shared_ptr library); explicit CustomPipelineAction(std::shared_ptr library); CustomPipelineAction(std::shared_ptr library, - std::vector pass_descriptions); + std::string material_asset); void OnDrawStarted(GraphicsModActionData::DrawStarted*) override; + void AfterEFB(GraphicsModActionData::PostEFB*) override; private: std::shared_ptr m_library; - std::vector m_passes_config; - std::vector m_pipeline_passes; + std::string m_material_asset; }; From 8912b77312c50e45346cc8858899409ba6037977 Mon Sep 17 00:00:00 2001 From: iwubcode Date: Mon, 17 Nov 2025 18:40:21 -0600 Subject: [PATCH 04/12] VideoCommon: after an EFB is processed, if there is a graphics mod action that provides a custom material, update the EFB with the material --- Source/Core/VideoCommon/TextureCacheBase.cpp | 124 +++++++++++++++++++ Source/Core/VideoCommon/TextureCacheBase.h | 3 + 2 files changed, 127 insertions(+) diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index 97044c22df..58dfbad64e 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -2327,6 +2327,26 @@ void TextureCacheBase::CopyRenderTargetToTexture( isIntensity, gamma, clamp_top, clamp_bottom, GetVRAMCopyFilterCoefficients(filter_coefficients)); + if (g_ActiveConfig.bGraphicMods) + { + FBInfo info; + info.m_width = tex_w; + info.m_height = tex_h; + info.m_texture_format = baseFormat; + if (!is_xfb_copy) + { + GraphicsModActionData::PostEFB efb; + for (const auto& action : g_graphics_mod_manager->GetEFBActions(info)) + { + action->AfterEFB(&efb); + if (efb.material) + { + ApplyMaterialToCacheEntry(*efb.material, entry.get()); + } + } + } + } + if (is_xfb_copy && (g_ActiveConfig.bDumpXFBTarget || g_ActiveConfig.bGraphicMods)) { const std::string id = fmt::format("{}x{}", tex_w, tex_h); @@ -3033,6 +3053,110 @@ bool TextureCacheBase::DecodeTextureOnGPU(RcTcacheEntry& entry, u32 dst_level, c return true; } +void TextureCacheBase::ApplyMaterialToCacheEntry(const VideoCommon::MaterialResource& material, + TCacheEntry* entry) +{ + const auto material_data = material.GetData(); + if (!material_data) [[unlikely]] + return; + + // Make a copy, we can't write to our texture and use its framebuffer + // at the same time + auto new_entry = AllocateCacheEntry(entry->texture->GetConfig()); + new_entry->SetGeneralParameters(entry->addr, entry->size_in_bytes, entry->format, + entry->should_force_safe_hashing); + new_entry->SetDimensions(entry->native_width, entry->native_height, 1); + new_entry->SetEfbCopy(entry->memory_stride); + new_entry->may_have_overlapping_textures = false; + new_entry->frameCount = FRAMECOUNT_INVALID; + + g_gfx->BeginUtilityDrawing(); + entry->texture->FinishedRendering(); + + const auto custom_uniforms = material_data->GetUniforms(); + + // Set up uniforms. + // TODO: this struct should be shared with post processing + struct Uniforms + { + std::array source_resolution; + std::array target_resolution; + std::array window_resolution; + std::array source_rectangle; + s32 source_layer; + s32 source_layer_pad[3]; + u32 time; + u32 time_pad[3]; + s32 graphics_api; + s32 graphics_api_pad[3]; + u32 efb_scale; + u32 efb_scale_pad[3]; + } uniforms; + + const float rcp_src_width = 1.0f / entry->texture->GetWidth(); + const float rcp_src_height = 1.0f / entry->texture->GetHeight(); + + uniforms.source_resolution = {static_cast(entry->texture->GetWidth()), + static_cast(entry->texture->GetHeight()), rcp_src_width, + rcp_src_height}; + + // The target resolution is the same here, since we're + // injecting into the texture + uniforms.target_resolution = uniforms.source_resolution; + + const auto present_rect = g_presenter->GetTargetRectangle(); + uniforms.window_resolution = {static_cast(present_rect.GetWidth()), + static_cast(present_rect.GetHeight()), + 1.0f / static_cast(present_rect.GetWidth()), + 1.0f / static_cast(present_rect.GetHeight())}; + + uniforms.source_rectangle = {0, 0, 1, 1}; + uniforms.source_layer = 0; + uniforms.time = 0; + uniforms.graphics_api = static_cast(g_backend_info.api_type); + uniforms.efb_scale = g_framebuffer_manager->GetEFBScale(); + + Common::UniqueBuffer uniform_buffer(custom_uniforms.size() + sizeof(uniforms)); + std::memcpy(uniform_buffer.data(), &uniforms, sizeof(uniforms)); + std::memcpy(uniform_buffer.data() + sizeof(uniforms), custom_uniforms.data(), + custom_uniforms.size()); + g_vertex_manager->UploadUtilityUniforms(uniform_buffer.data(), + static_cast(uniform_buffer.size())); + + // Set framebuffer and viewport based on new entry + g_gfx->SetAndDiscardFramebuffer(new_entry->framebuffer.get()); + g_gfx->SetViewportAndScissor(new_entry->framebuffer->GetRect()); + g_gfx->SetPipeline(material_data->GetPipeline()); + + g_gfx->SetTexture(0, entry->texture.get()); + g_gfx->SetSamplerState(0, RenderState::GetPointSamplerState()); + + for (const auto texture : material_data->GetTextures()) + { + g_gfx->SetTexture(texture.sampler_index, texture.texture); + g_gfx->SetSamplerState(texture.sampler_index, texture.sampler); + } + + g_gfx->Draw(0, 3); + g_gfx->EndUtilityDrawing(); + + // Finish rendering new entry + new_entry->texture->FinishedRendering(); + + // Swap new entry and existing entry + std::swap(entry->texture, new_entry->texture); + std::swap(entry->framebuffer, new_entry->framebuffer); + + // Return old entry to pool for use in another pass + // or future functionality + ReleaseToPool(new_entry.get()); + + if (auto* const next_material = material_data->GetNextMaterial(); next_material) + { + ApplyMaterialToCacheEntry(*next_material, entry); + } +} + u32 TCacheEntry::BytesPerRow() const { // RGBA takes two cache lines per block; all others take one diff --git a/Source/Core/VideoCommon/TextureCacheBase.h b/Source/Core/VideoCommon/TextureCacheBase.h index 1aa67dede5..d596f84e5e 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.h +++ b/Source/Core/VideoCommon/TextureCacheBase.h @@ -41,6 +41,7 @@ namespace VideoCommon { class CustomTextureData; class GameTextureAsset; +class MaterialResource; } // namespace VideoCommon constexpr std::string_view EFB_DUMP_PREFIX = "efb1"; @@ -407,6 +408,8 @@ private: void DoSaveState(PointerWrap& p); void DoLoadState(PointerWrap& p); + void ApplyMaterialToCacheEntry(const VideoCommon::MaterialResource& material, TCacheEntry* entry); + // m_textures_by_address is the authoritive version of what's actually "in" the texture cache // but it's possible for invalidated TCache entries to live on elsewhere TexAddrCache m_textures_by_address; From 3b7d5b030c324b858fe68a043478976c66c92a00 Mon Sep 17 00:00:00 2001 From: iwubcode Date: Mon, 17 Nov 2025 18:43:36 -0600 Subject: [PATCH 05/12] VideoCommon: watch the user and system graphics mods directories for modified assets --- .../GraphicsModSystem/Runtime/GraphicsModManager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModManager.cpp b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModManager.cpp index d97fb49d58..5f9cf48d52 100644 --- a/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModManager.cpp +++ b/Source/Core/VideoCommon/GraphicsModSystem/Runtime/GraphicsModManager.cpp @@ -7,6 +7,7 @@ #include #include +#include "Common/FileUtil.h" #include "Common/Logging/Log.h" #include "Common/StringUtil.h" #include "Common/VariantUtil.h" @@ -17,6 +18,7 @@ #include "VideoCommon/GraphicsModSystem/Config/GraphicsMod.h" #include "VideoCommon/GraphicsModSystem/Config/GraphicsModAsset.h" #include "VideoCommon/GraphicsModSystem/Config/GraphicsModGroup.h" +#include "VideoCommon/GraphicsModSystem/Constants.h" #include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModActionFactory.h" #include "VideoCommon/VideoConfig.h" #include "VideoCommon/VideoEvents.h" @@ -197,6 +199,8 @@ void GraphicsModManager::Load(const GraphicsModGroupConfig& config) const auto& mods = config.GetMods(); auto filesystem_library = std::make_shared(); + filesystem_library->Watch(File::GetSysDirectory() + DOLPHIN_SYSTEM_GRAPHICS_MOD_DIR); + filesystem_library->Watch(File::GetUserPath(D_GRAPHICSMOD_IDX)); std::map> group_to_targets; for (const auto& mod : mods) From c75f3f0c881bc2ed29f5768469c82d60929502ba Mon Sep 17 00:00:00 2001 From: iwubcode Date: Sat, 31 Jan 2026 00:57:20 -0600 Subject: [PATCH 06/12] VideoCommon: allow graphics mods to be added to sub folders --- .../Config/GraphicsModGroup.cpp | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/Source/Core/VideoCommon/GraphicsModSystem/Config/GraphicsModGroup.cpp b/Source/Core/VideoCommon/GraphicsModSystem/Config/GraphicsModGroup.cpp index e3cf5b9a10..c0fa1f82ca 100644 --- a/Source/Core/VideoCommon/GraphicsModSystem/Config/GraphicsModGroup.cpp +++ b/Source/Core/VideoCommon/GraphicsModSystem/Config/GraphicsModGroup.cpp @@ -10,6 +10,7 @@ #include #include "Common/CommonPaths.h" +#include "Common/FileSearch.h" #include "Common/FileUtil.h" #include "Common/JsonUtil.h" #include "Common/Logging/Log.h" @@ -84,13 +85,22 @@ void GraphicsModGroupConfig::Load() const auto try_add_mod = [&known_paths, this](const std::string& dir, GraphicsModConfig::Source source) { - auto file = dir + DIR_SEP + "metadata.json"; - UnifyPathSeparators(file); - if (known_paths.contains(file)) - return; + const auto files = Common::DoFileSearch(dir, ".json", true); + for (const auto& file : files) + { + std::string basename; + SplitPath(file, nullptr, &basename, nullptr); + if (basename == "metadata") + { + auto file_copy = file; + UnifyPathSeparators(file_copy); + if (known_paths.contains(file_copy)) + return; - if (auto mod = GraphicsModConfig::Create(file, source)) - m_graphics_mods.push_back(std::move(*mod)); + if (auto mod = GraphicsModConfig::Create(file_copy, source)) + m_graphics_mods.push_back(std::move(*mod)); + } + } }; const std::set graphics_mod_user_directories = From 51f69727e4279687733a2203b90116deee951ca3 Mon Sep 17 00:00:00 2001 From: iwubcode Date: Mon, 17 Nov 2025 18:56:20 -0600 Subject: [PATCH 07/12] Data: add a mod for all games with bloom targets that blurs the bloom based on resolution using a custom material, expose bloom brightness and the amount of spread through parameters (not exposed in the UI yet). Original shader logic by TryTwo, reworked for graphics mods and cleaned up. Consider a guassian function with kernel in the future. Co-authored-by: TryTwo --- .../All Games Blurred Bloom/all.txt | 0 .../All Games Blurred Bloom/blur.ps.glsl | 45 +++++++++++++++++++ .../All Games Blurred Bloom/blur.rastershader | 23 ++++++++++ .../All Games Blurred Bloom/blur.vs.glsl | 4 ++ .../blur_horizontal.rastermaterial | 19 ++++++++ .../blur_vertical.rastermaterial | 19 ++++++++ .../All Games Blurred Bloom/metadata.json | 41 +++++++++++++++++ 7 files changed, 151 insertions(+) create mode 100644 Data/Sys/Load/GraphicMods/All Games Blurred Bloom/all.txt create mode 100644 Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur.ps.glsl create mode 100644 Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur.rastershader create mode 100644 Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur.vs.glsl create mode 100644 Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur_horizontal.rastermaterial create mode 100644 Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur_vertical.rastermaterial create mode 100644 Data/Sys/Load/GraphicMods/All Games Blurred Bloom/metadata.json diff --git a/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/all.txt b/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/all.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur.ps.glsl b/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur.ps.glsl new file mode 100644 index 0000000000..3ad5cb5856 --- /dev/null +++ b/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur.ps.glsl @@ -0,0 +1,45 @@ +void process_fragment(in DolphinFragmentInput frag_input, out DolphinFragmentOutput frag_output) +{ + int layer = int(frag_input.tex0.z); + int r = int(efb_scale) * int(SPREAD_MULTIPLIER); + int coord; + int length; + int2 initial_coords = int2(frag_input.tex0.xy * source_resolution.xy); + vec4 brightness = float4(1.0, 1.0, 1.0, 1.0); + if (HORIZONTAL) + { + length = int(source_resolution.x); + coord = initial_coords.x; + brightness = BRIGHTNESS_MULTIPLIER * brightness; + } + else + { + length = int(source_resolution.y); + coord = initial_coords.y; + } + + int offset; + vec4 count = vec4(0.0,0.0,0.0,0.0); + vec4 col = vec4(0.0,0.0,0.0,0.0); + for (offset = -r; offset <= r; offset++) + { + int pos = coord + offset; + if (pos <= length && pos >= 0) + { + int3 sample_coords; + if (HORIZONTAL) + { + sample_coords = int3(int2(pos, initial_coords.y), layer); + } + else + { + sample_coords = int3(int2(initial_coords.x, pos), layer); + } + + col += texelFetch(samp0, sample_coords, 0); + count += vec4(1.0,1.0,1.0,1.0); + } + } + frag_output.main = col / count * brightness; + +} diff --git a/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur.rastershader b/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur.rastershader new file mode 100644 index 0000000000..6c66f0b81e --- /dev/null +++ b/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur.rastershader @@ -0,0 +1,23 @@ +{ + "properties":[ + { + "code_name": "HORIZONTAL", + "default": true, + "description": "Whether to apply the blur horizontally or vertically", + "type": "bool" + }, + { + "code_name": "SPREAD_MULTIPLIER", + "default": 1.0, + "description": "How much to spread the blur", + "type": "float" + }, + { + "code_name": "BRIGHTNESS_MULTIPLIER", + "default": 1.0, + "description": "How bright the blur is", + "type": "float" + } + ], + "samplers":[] +} diff --git a/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur.vs.glsl b/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur.vs.glsl new file mode 100644 index 0000000000..68d5c36778 --- /dev/null +++ b/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur.vs.glsl @@ -0,0 +1,4 @@ +void process_vertex(in DolphinVertexInput vertex_input, out DolphinVertexOutput vertex_output) +{ + dolphin_process_emulated_vertex(vertex_input, vertex_output); +} diff --git a/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur_horizontal.rastermaterial b/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur_horizontal.rastermaterial new file mode 100644 index 0000000000..a2b869a214 --- /dev/null +++ b/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur_horizontal.rastermaterial @@ -0,0 +1,19 @@ +{ + "next_material_asset":"dolphin_bloom_blur_vertical", + "properties":[ + { + "type": "bool", + "value": true + }, + { + "type": "float", + "value": 1.0 + }, + { + "type": "float", + "value": 1.0 + } + ], + "textures":[], + "shader_asset": "dolphin_bloom_blur" +} diff --git a/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur_vertical.rastermaterial b/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur_vertical.rastermaterial new file mode 100644 index 0000000000..044d0a33f8 --- /dev/null +++ b/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/blur_vertical.rastermaterial @@ -0,0 +1,19 @@ +{ + "next_material_asset":"", + "properties":[ + { + "type": "bool", + "value": false + }, + { + "type": "float", + "value": 1.0 + }, + { + "type": "float", + "value": 1.0 + } + ], + "textures":[], + "shader_asset": "dolphin_bloom_blur" +} diff --git a/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/metadata.json b/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/metadata.json new file mode 100644 index 0000000000..8b79c3e05e --- /dev/null +++ b/Data/Sys/Load/GraphicMods/All Games Blurred Bloom/metadata.json @@ -0,0 +1,41 @@ +{ + "meta": + { + "title": "Bloom Blurred", + "author": "Dolphin Team", + "description": "Modifies bloom effects to blur them to their native resolution. Results in bloom looking much more natural at higher resolutions but the blur may be too intense in some games." + }, + "features": + [ + { + "group": "Bloom", + "action": "custom_pipeline", + "action_data": + { + "material_asset": "dolphin_bloom_blur_horizontal" + } + } + ], + "assets": [ + { + "data": { + "metadata": "blur.rastershader", + "pixel_shader": "blur.ps.glsl", + "vertex_shader": "blur.vs.glsl" + }, + "name": "dolphin_bloom_blur" + }, + { + "data": { + "metadata": "blur_horizontal.rastermaterial" + }, + "name": "dolphin_bloom_blur_horizontal" + }, + { + "data": { + "metadata": "blur_vertical.rastermaterial" + }, + "name": "dolphin_bloom_blur_vertical" + } + ] +} From 72b501231d6d8517a5982703d375fe6088760c52 Mon Sep 17 00:00:00 2001 From: iwubcode Date: Tue, 18 Nov 2025 00:00:26 -0600 Subject: [PATCH 08/12] Data: add more bloom graphics mods --- Data/Sys/Load/GraphicMods/Conduit 2/SC2.txt | 0 .../Load/GraphicMods/Conduit 2/metadata.json | 31 +++++++++++++++++++ Data/Sys/Load/GraphicMods/De Blob 2/SDB.txt | 0 .../Load/GraphicMods/De Blob 2/metadata.json | 31 +++++++++++++++++++ Data/Sys/Load/GraphicMods/De Blob/R6B.txt | 0 .../Load/GraphicMods/De Blob/metadata.json | 31 +++++++++++++++++++ .../Load/GraphicMods/Epic Mickey 2/SER.txt | 0 .../GraphicMods/Epic Mickey 2/metadata.json | 19 ++++++++++++ Data/Sys/Load/GraphicMods/Epic Mickey/SEM.txt | 0 .../GraphicMods/Epic Mickey/metadata.json | 19 ++++++++++++ Data/Sys/Load/GraphicMods/Go Vacation/SGV.txt | 0 .../GraphicMods/Go Vacation/metadata.json | 19 ++++++++++++ Data/Sys/Load/GraphicMods/Lego Batman/RLB.txt | 0 .../GraphicMods/Lego Batman/metadata.json | 19 ++++++++++++ .../Lord of the Rings Aragorns Quest/R8J.txt | 0 .../metadata.json | 19 ++++++++++++ .../WLO.txt | 0 .../metadata.json | 19 ++++++++++++ Data/Sys/Load/GraphicMods/LostWinds/WLW.txt | 0 .../Load/GraphicMods/LostWinds/metadata.json | 19 ++++++++++++ .../Load/GraphicMods/Metroid Other M/R3O.txt | 0 .../GraphicMods/Metroid Other M/metadata.json | 23 ++++++++++++++ .../GraphicMods/Metroid Prime Trilogy/R3M.txt | 0 .../Metroid Prime Trilogy/metadata.json | 23 ++++++++++++++ .../GraphicMods/Overlord Dark Legend/ROA.txt | 0 .../Overlord Dark Legend/metadata.json | 19 ++++++++++++ .../Load/GraphicMods/Sonic Unleashed/RSV.txt | 0 .../GraphicMods/Sonic Unleashed/metadata.json | 23 ++++++++++++++ .../GraphicMods/Spectrobes Origins/RXX.txt | 0 .../Spectrobes Origins/metadata.json | 19 ++++++++++++ Data/Sys/Load/GraphicMods/Spyborgs/RSW.txt | 0 .../Load/GraphicMods/Spyborgs/metadata.json | 23 ++++++++++++++ .../Load/GraphicMods/Takt of Magic/ROS.txt | 0 .../GraphicMods/Takt of Magic/metadata.json | 19 ++++++++++++ .../GraphicMods/Zangeki no Reginleiv/RZN.txt | 0 .../Zangeki no Reginleiv/metadata.json | 19 ++++++++++++ 36 files changed, 394 insertions(+) create mode 100644 Data/Sys/Load/GraphicMods/Conduit 2/SC2.txt create mode 100644 Data/Sys/Load/GraphicMods/Conduit 2/metadata.json create mode 100644 Data/Sys/Load/GraphicMods/De Blob 2/SDB.txt create mode 100644 Data/Sys/Load/GraphicMods/De Blob 2/metadata.json create mode 100644 Data/Sys/Load/GraphicMods/De Blob/R6B.txt create mode 100644 Data/Sys/Load/GraphicMods/De Blob/metadata.json create mode 100644 Data/Sys/Load/GraphicMods/Epic Mickey 2/SER.txt create mode 100644 Data/Sys/Load/GraphicMods/Epic Mickey 2/metadata.json create mode 100644 Data/Sys/Load/GraphicMods/Epic Mickey/SEM.txt create mode 100644 Data/Sys/Load/GraphicMods/Epic Mickey/metadata.json create mode 100644 Data/Sys/Load/GraphicMods/Go Vacation/SGV.txt create mode 100644 Data/Sys/Load/GraphicMods/Go Vacation/metadata.json create mode 100644 Data/Sys/Load/GraphicMods/Lego Batman/RLB.txt create mode 100644 Data/Sys/Load/GraphicMods/Lego Batman/metadata.json create mode 100644 Data/Sys/Load/GraphicMods/Lord of the Rings Aragorns Quest/R8J.txt create mode 100644 Data/Sys/Load/GraphicMods/Lord of the Rings Aragorns Quest/metadata.json create mode 100644 Data/Sys/Load/GraphicMods/LostWinds - Winter of the Melodias/WLO.txt create mode 100644 Data/Sys/Load/GraphicMods/LostWinds - Winter of the Melodias/metadata.json create mode 100644 Data/Sys/Load/GraphicMods/LostWinds/WLW.txt create mode 100644 Data/Sys/Load/GraphicMods/LostWinds/metadata.json create mode 100644 Data/Sys/Load/GraphicMods/Metroid Other M/R3O.txt create mode 100644 Data/Sys/Load/GraphicMods/Metroid Other M/metadata.json create mode 100644 Data/Sys/Load/GraphicMods/Metroid Prime Trilogy/R3M.txt create mode 100644 Data/Sys/Load/GraphicMods/Metroid Prime Trilogy/metadata.json create mode 100644 Data/Sys/Load/GraphicMods/Overlord Dark Legend/ROA.txt create mode 100644 Data/Sys/Load/GraphicMods/Overlord Dark Legend/metadata.json create mode 100644 Data/Sys/Load/GraphicMods/Sonic Unleashed/RSV.txt create mode 100644 Data/Sys/Load/GraphicMods/Sonic Unleashed/metadata.json create mode 100644 Data/Sys/Load/GraphicMods/Spectrobes Origins/RXX.txt create mode 100644 Data/Sys/Load/GraphicMods/Spectrobes Origins/metadata.json create mode 100644 Data/Sys/Load/GraphicMods/Spyborgs/RSW.txt create mode 100644 Data/Sys/Load/GraphicMods/Spyborgs/metadata.json create mode 100644 Data/Sys/Load/GraphicMods/Takt of Magic/ROS.txt create mode 100644 Data/Sys/Load/GraphicMods/Takt of Magic/metadata.json create mode 100644 Data/Sys/Load/GraphicMods/Zangeki no Reginleiv/RZN.txt create mode 100644 Data/Sys/Load/GraphicMods/Zangeki no Reginleiv/metadata.json diff --git a/Data/Sys/Load/GraphicMods/Conduit 2/SC2.txt b/Data/Sys/Load/GraphicMods/Conduit 2/SC2.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Data/Sys/Load/GraphicMods/Conduit 2/metadata.json b/Data/Sys/Load/GraphicMods/Conduit 2/metadata.json new file mode 100644 index 0000000000..06a2e2a24e --- /dev/null +++ b/Data/Sys/Load/GraphicMods/Conduit 2/metadata.json @@ -0,0 +1,31 @@ +{ + "meta": + { + "title": "Bloom Texture Definitions", + "author": "iwubcode" + }, + "groups": + [ + { + "name": "Bloom", + "targets": [ + { + "type": "efb", + "texture_filename": "efb1_n000022_40x28_6" + }, + { + "type": "efb", + "texture_filename": "efb1_n000021_80x56_6" + }, + { + "type": "efb", + "texture_filename": "efb1_n000020_160x112_6" + }, + { + "type": "efb", + "texture_filename": "efb1_n000025_320x224_6" + } + ] + } + ] +} diff --git a/Data/Sys/Load/GraphicMods/De Blob 2/SDB.txt b/Data/Sys/Load/GraphicMods/De Blob 2/SDB.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Data/Sys/Load/GraphicMods/De Blob 2/metadata.json b/Data/Sys/Load/GraphicMods/De Blob 2/metadata.json new file mode 100644 index 0000000000..697d28c730 --- /dev/null +++ b/Data/Sys/Load/GraphicMods/De Blob 2/metadata.json @@ -0,0 +1,31 @@ +{ + "meta": + { + "title": "Bloom Texture Definitions", + "author": "iwubcode" + }, + "groups": + [ + { + "name": "Bloom", + "targets": [ + { + "type": "efb", + "texture_filename": "efb1_n000134_20x14_6" + }, + { + "type": "efb", + "texture_filename": "efb1_n000022_40x28_6" + }, + { + "type": "efb", + "texture_filename": "efb1_n000131_80x56_6" + }, + { + "type": "efb", + "texture_filename": "efb1_n000130_160x112_6" + } + ] + } + ] +} diff --git a/Data/Sys/Load/GraphicMods/De Blob/R6B.txt b/Data/Sys/Load/GraphicMods/De Blob/R6B.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Data/Sys/Load/GraphicMods/De Blob/metadata.json b/Data/Sys/Load/GraphicMods/De Blob/metadata.json new file mode 100644 index 0000000000..697d28c730 --- /dev/null +++ b/Data/Sys/Load/GraphicMods/De Blob/metadata.json @@ -0,0 +1,31 @@ +{ + "meta": + { + "title": "Bloom Texture Definitions", + "author": "iwubcode" + }, + "groups": + [ + { + "name": "Bloom", + "targets": [ + { + "type": "efb", + "texture_filename": "efb1_n000134_20x14_6" + }, + { + "type": "efb", + "texture_filename": "efb1_n000022_40x28_6" + }, + { + "type": "efb", + "texture_filename": "efb1_n000131_80x56_6" + }, + { + "type": "efb", + "texture_filename": "efb1_n000130_160x112_6" + } + ] + } + ] +} diff --git a/Data/Sys/Load/GraphicMods/Epic Mickey 2/SER.txt b/Data/Sys/Load/GraphicMods/Epic Mickey 2/SER.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Data/Sys/Load/GraphicMods/Epic Mickey 2/metadata.json b/Data/Sys/Load/GraphicMods/Epic Mickey 2/metadata.json new file mode 100644 index 0000000000..2859a3638e --- /dev/null +++ b/Data/Sys/Load/GraphicMods/Epic Mickey 2/metadata.json @@ -0,0 +1,19 @@ +{ + "meta": + { + "title": "Bloom Texture Definitions", + "author": "iwubcode" + }, + "groups": + [ + { + "name": "Bloom", + "targets": [ + { + "type": "efb", + "texture_filename": "efb1_n000038_160x120_6" + } + ] + } + ] +} diff --git a/Data/Sys/Load/GraphicMods/Epic Mickey/SEM.txt b/Data/Sys/Load/GraphicMods/Epic Mickey/SEM.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Data/Sys/Load/GraphicMods/Epic Mickey/metadata.json b/Data/Sys/Load/GraphicMods/Epic Mickey/metadata.json new file mode 100644 index 0000000000..2859a3638e --- /dev/null +++ b/Data/Sys/Load/GraphicMods/Epic Mickey/metadata.json @@ -0,0 +1,19 @@ +{ + "meta": + { + "title": "Bloom Texture Definitions", + "author": "iwubcode" + }, + "groups": + [ + { + "name": "Bloom", + "targets": [ + { + "type": "efb", + "texture_filename": "efb1_n000038_160x120_6" + } + ] + } + ] +} diff --git a/Data/Sys/Load/GraphicMods/Go Vacation/SGV.txt b/Data/Sys/Load/GraphicMods/Go Vacation/SGV.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Data/Sys/Load/GraphicMods/Go Vacation/metadata.json b/Data/Sys/Load/GraphicMods/Go Vacation/metadata.json new file mode 100644 index 0000000000..8ff30e05f3 --- /dev/null +++ b/Data/Sys/Load/GraphicMods/Go Vacation/metadata.json @@ -0,0 +1,19 @@ +{ + "meta": + { + "title": "Bloom Texture Definitions", + "author": "iwubcode" + }, + "groups": + [ + { + "name": "Bloom", + "targets": [ + { + "type": "efb", + "texture_filename": "efb1_n000167_80x58_6" + } + ] + } + ] +} diff --git a/Data/Sys/Load/GraphicMods/Lego Batman/RLB.txt b/Data/Sys/Load/GraphicMods/Lego Batman/RLB.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Data/Sys/Load/GraphicMods/Lego Batman/metadata.json b/Data/Sys/Load/GraphicMods/Lego Batman/metadata.json new file mode 100644 index 0000000000..79064099c4 --- /dev/null +++ b/Data/Sys/Load/GraphicMods/Lego Batman/metadata.json @@ -0,0 +1,19 @@ +{ + "meta": + { + "title": "Bloom Texture Definitions", + "author": "iwubcode" + }, + "groups": + [ + { + "name": "Bloom", + "targets": [ + { + "type": "efb", + "texture_filename": "efb1_n000043_80x56_6" + } + ] + } + ] +} diff --git a/Data/Sys/Load/GraphicMods/Lord of the Rings Aragorns Quest/R8J.txt b/Data/Sys/Load/GraphicMods/Lord of the Rings Aragorns Quest/R8J.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Data/Sys/Load/GraphicMods/Lord of the Rings Aragorns Quest/metadata.json b/Data/Sys/Load/GraphicMods/Lord of the Rings Aragorns Quest/metadata.json new file mode 100644 index 0000000000..6209265acb --- /dev/null +++ b/Data/Sys/Load/GraphicMods/Lord of the Rings Aragorns Quest/metadata.json @@ -0,0 +1,19 @@ +{ + "meta": + { + "title": "Bloom Texture Definitions", + "author": "iwubcode" + }, + "groups": + [ + { + "name": "Bloom", + "targets": [ + { + "type": "efb", + "texture_filename": "efb1_n000013_80x60_6" + } + ] + } + ] +} diff --git a/Data/Sys/Load/GraphicMods/LostWinds - Winter of the Melodias/WLO.txt b/Data/Sys/Load/GraphicMods/LostWinds - Winter of the Melodias/WLO.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Data/Sys/Load/GraphicMods/LostWinds - Winter of the Melodias/metadata.json b/Data/Sys/Load/GraphicMods/LostWinds - Winter of the Melodias/metadata.json new file mode 100644 index 0000000000..5aa3459abf --- /dev/null +++ b/Data/Sys/Load/GraphicMods/LostWinds - Winter of the Melodias/metadata.json @@ -0,0 +1,19 @@ +{ + "meta": + { + "title": "Bloom Texture Definitions", + "author": "iwubcode" + }, + "groups": + [ + { + "name": "Bloom", + "targets": [ + { + "type": "efb", + "texture_filename": "efb1_n000015_320x224_6" + } + ] + } + ] +} diff --git a/Data/Sys/Load/GraphicMods/LostWinds/WLW.txt b/Data/Sys/Load/GraphicMods/LostWinds/WLW.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Data/Sys/Load/GraphicMods/LostWinds/metadata.json b/Data/Sys/Load/GraphicMods/LostWinds/metadata.json new file mode 100644 index 0000000000..5aa3459abf --- /dev/null +++ b/Data/Sys/Load/GraphicMods/LostWinds/metadata.json @@ -0,0 +1,19 @@ +{ + "meta": + { + "title": "Bloom Texture Definitions", + "author": "iwubcode" + }, + "groups": + [ + { + "name": "Bloom", + "targets": [ + { + "type": "efb", + "texture_filename": "efb1_n000015_320x224_6" + } + ] + } + ] +} diff --git a/Data/Sys/Load/GraphicMods/Metroid Other M/R3O.txt b/Data/Sys/Load/GraphicMods/Metroid Other M/R3O.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Data/Sys/Load/GraphicMods/Metroid Other M/metadata.json b/Data/Sys/Load/GraphicMods/Metroid Other M/metadata.json new file mode 100644 index 0000000000..7da2cdc7d6 --- /dev/null +++ b/Data/Sys/Load/GraphicMods/Metroid Other M/metadata.json @@ -0,0 +1,23 @@ +{ + "meta": + { + "title": "Bloom Texture Definitions", + "author": "iwubcode" + }, + "groups": + [ + { + "name": "Bloom", + "targets": [ + { + "type": "efb", + "texture_filename": "efb1_n000069_80x60_4" + }, + { + "type": "efb", + "texture_filename": "efb1_n000068_160x120_4" + } + ] + } + ] +} diff --git a/Data/Sys/Load/GraphicMods/Metroid Prime Trilogy/R3M.txt b/Data/Sys/Load/GraphicMods/Metroid Prime Trilogy/R3M.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Data/Sys/Load/GraphicMods/Metroid Prime Trilogy/metadata.json b/Data/Sys/Load/GraphicMods/Metroid Prime Trilogy/metadata.json new file mode 100644 index 0000000000..9b7e4ad47f --- /dev/null +++ b/Data/Sys/Load/GraphicMods/Metroid Prime Trilogy/metadata.json @@ -0,0 +1,23 @@ +{ + "meta": + { + "title": "Bloom Texture Definitions", + "author": "autofire372" + }, + "groups": + [ + { + "name": "Bloom", + "targets": [ + { + "type": "efb", + "texture_filename": "efb1_n000023_320x224_4" + }, + { + "type": "efb", + "texture_filename": "efb1_n000024_320x224_4" + } + ] + } + ] +} diff --git a/Data/Sys/Load/GraphicMods/Overlord Dark Legend/ROA.txt b/Data/Sys/Load/GraphicMods/Overlord Dark Legend/ROA.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Data/Sys/Load/GraphicMods/Overlord Dark Legend/metadata.json b/Data/Sys/Load/GraphicMods/Overlord Dark Legend/metadata.json new file mode 100644 index 0000000000..001bf4dc62 --- /dev/null +++ b/Data/Sys/Load/GraphicMods/Overlord Dark Legend/metadata.json @@ -0,0 +1,19 @@ +{ + "meta": + { + "title": "Bloom Texture Definitions", + "author": "Stalin15" + }, + "groups": + [ + { + "name": "Bloom", + "targets": [ + { + "type": "efb", + "texture_filename": "efb1_n000010_80x60_6" + } + ] + } + ] +} diff --git a/Data/Sys/Load/GraphicMods/Sonic Unleashed/RSV.txt b/Data/Sys/Load/GraphicMods/Sonic Unleashed/RSV.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Data/Sys/Load/GraphicMods/Sonic Unleashed/metadata.json b/Data/Sys/Load/GraphicMods/Sonic Unleashed/metadata.json new file mode 100644 index 0000000000..ebb68825be --- /dev/null +++ b/Data/Sys/Load/GraphicMods/Sonic Unleashed/metadata.json @@ -0,0 +1,23 @@ +{ + "meta": + { + "title": "Bloom Texture Definitions", + "author": "Dr. Azathoth" + }, + "groups": + [ + { + "name": "Bloom", + "targets": [ + { + "type": "efb", + "texture_filename": "efb1_320x240_6" + }, + { + "type": "efb", + "texture_filename": "efb1_640x480_1" + } + ] + } + ] +} diff --git a/Data/Sys/Load/GraphicMods/Spectrobes Origins/RXX.txt b/Data/Sys/Load/GraphicMods/Spectrobes Origins/RXX.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Data/Sys/Load/GraphicMods/Spectrobes Origins/metadata.json b/Data/Sys/Load/GraphicMods/Spectrobes Origins/metadata.json new file mode 100644 index 0000000000..1c0f8449d1 --- /dev/null +++ b/Data/Sys/Load/GraphicMods/Spectrobes Origins/metadata.json @@ -0,0 +1,19 @@ +{ + "meta": + { + "title": "Bloom Texture Definitions", + "author": "iwubcode" + }, + "groups": + [ + { + "name": "Bloom", + "targets": [ + { + "type": "efb", + "texture_filename": "efb1_n000690_80x56_6" + } + ] + } + ] +} diff --git a/Data/Sys/Load/GraphicMods/Spyborgs/RSW.txt b/Data/Sys/Load/GraphicMods/Spyborgs/RSW.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Data/Sys/Load/GraphicMods/Spyborgs/metadata.json b/Data/Sys/Load/GraphicMods/Spyborgs/metadata.json new file mode 100644 index 0000000000..e14989e54a --- /dev/null +++ b/Data/Sys/Load/GraphicMods/Spyborgs/metadata.json @@ -0,0 +1,23 @@ +{ + "meta": + { + "title": "Bloom Texture Definitions", + "author": "iwubcode" + }, + "groups": + [ + { + "name": "Bloom", + "targets": [ + { + "type": "efb", + "texture_filename": "efb1_n000102_80x66_6" + }, + { + "type": "efb", + "texture_filename": "efb1_n000025_320x232_6" + } + ] + } + ] +} diff --git a/Data/Sys/Load/GraphicMods/Takt of Magic/ROS.txt b/Data/Sys/Load/GraphicMods/Takt of Magic/ROS.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Data/Sys/Load/GraphicMods/Takt of Magic/metadata.json b/Data/Sys/Load/GraphicMods/Takt of Magic/metadata.json new file mode 100644 index 0000000000..239960ddb1 --- /dev/null +++ b/Data/Sys/Load/GraphicMods/Takt of Magic/metadata.json @@ -0,0 +1,19 @@ +{ + "meta": + { + "title": "Bloom Texture Definitions", + "author": "iwubcode" + }, + "groups": + [ + { + "name": "Bloom", + "targets": [ + { + "type": "efb", + "texture_filename": "efb1_n000038_80x60_4" + } + ] + } + ] +} diff --git a/Data/Sys/Load/GraphicMods/Zangeki no Reginleiv/RZN.txt b/Data/Sys/Load/GraphicMods/Zangeki no Reginleiv/RZN.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Data/Sys/Load/GraphicMods/Zangeki no Reginleiv/metadata.json b/Data/Sys/Load/GraphicMods/Zangeki no Reginleiv/metadata.json new file mode 100644 index 0000000000..ce0f1d1a8b --- /dev/null +++ b/Data/Sys/Load/GraphicMods/Zangeki no Reginleiv/metadata.json @@ -0,0 +1,19 @@ +{ + "meta": + { + "title": "Bloom Texture Definitions", + "author": "iwubcode" + }, + "groups": + [ + { + "name": "Bloom", + "targets": [ + { + "type": "efb", + "texture_filename": "efb1_n000102_80x66_6" + } + ] + } + ] +} From fece18fd9d6f2aa7f6143ad2baa8faab008a6228 Mon Sep 17 00:00:00 2001 From: iwubcode Date: Tue, 18 Nov 2025 00:21:38 -0600 Subject: [PATCH 09/12] Data: add a blurred DOF feature --- .../GraphicMods/All Games Blurred DOF/all.txt | 0 .../All Games Blurred DOF/blur.ps.glsl | 45 +++++++++++++++++++ .../All Games Blurred DOF/blur.rastershader | 23 ++++++++++ .../All Games Blurred DOF/blur.vs.glsl | 4 ++ .../blur_horizontal.rastermaterial | 19 ++++++++ .../blur_vertical.rastermaterial | 19 ++++++++ .../All Games Blurred DOF/metadata.json | 41 +++++++++++++++++ 7 files changed, 151 insertions(+) create mode 100644 Data/Sys/Load/GraphicMods/All Games Blurred DOF/all.txt create mode 100644 Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur.ps.glsl create mode 100644 Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur.rastershader create mode 100644 Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur.vs.glsl create mode 100644 Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur_horizontal.rastermaterial create mode 100644 Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur_vertical.rastermaterial create mode 100644 Data/Sys/Load/GraphicMods/All Games Blurred DOF/metadata.json diff --git a/Data/Sys/Load/GraphicMods/All Games Blurred DOF/all.txt b/Data/Sys/Load/GraphicMods/All Games Blurred DOF/all.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur.ps.glsl b/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur.ps.glsl new file mode 100644 index 0000000000..3ad5cb5856 --- /dev/null +++ b/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur.ps.glsl @@ -0,0 +1,45 @@ +void process_fragment(in DolphinFragmentInput frag_input, out DolphinFragmentOutput frag_output) +{ + int layer = int(frag_input.tex0.z); + int r = int(efb_scale) * int(SPREAD_MULTIPLIER); + int coord; + int length; + int2 initial_coords = int2(frag_input.tex0.xy * source_resolution.xy); + vec4 brightness = float4(1.0, 1.0, 1.0, 1.0); + if (HORIZONTAL) + { + length = int(source_resolution.x); + coord = initial_coords.x; + brightness = BRIGHTNESS_MULTIPLIER * brightness; + } + else + { + length = int(source_resolution.y); + coord = initial_coords.y; + } + + int offset; + vec4 count = vec4(0.0,0.0,0.0,0.0); + vec4 col = vec4(0.0,0.0,0.0,0.0); + for (offset = -r; offset <= r; offset++) + { + int pos = coord + offset; + if (pos <= length && pos >= 0) + { + int3 sample_coords; + if (HORIZONTAL) + { + sample_coords = int3(int2(pos, initial_coords.y), layer); + } + else + { + sample_coords = int3(int2(initial_coords.x, pos), layer); + } + + col += texelFetch(samp0, sample_coords, 0); + count += vec4(1.0,1.0,1.0,1.0); + } + } + frag_output.main = col / count * brightness; + +} diff --git a/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur.rastershader b/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur.rastershader new file mode 100644 index 0000000000..6c66f0b81e --- /dev/null +++ b/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur.rastershader @@ -0,0 +1,23 @@ +{ + "properties":[ + { + "code_name": "HORIZONTAL", + "default": true, + "description": "Whether to apply the blur horizontally or vertically", + "type": "bool" + }, + { + "code_name": "SPREAD_MULTIPLIER", + "default": 1.0, + "description": "How much to spread the blur", + "type": "float" + }, + { + "code_name": "BRIGHTNESS_MULTIPLIER", + "default": 1.0, + "description": "How bright the blur is", + "type": "float" + } + ], + "samplers":[] +} diff --git a/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur.vs.glsl b/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur.vs.glsl new file mode 100644 index 0000000000..68d5c36778 --- /dev/null +++ b/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur.vs.glsl @@ -0,0 +1,4 @@ +void process_vertex(in DolphinVertexInput vertex_input, out DolphinVertexOutput vertex_output) +{ + dolphin_process_emulated_vertex(vertex_input, vertex_output); +} diff --git a/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur_horizontal.rastermaterial b/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur_horizontal.rastermaterial new file mode 100644 index 0000000000..ca9887f082 --- /dev/null +++ b/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur_horizontal.rastermaterial @@ -0,0 +1,19 @@ +{ + "next_material_asset":"dolphin_dof_blur_vertical", + "properties":[ + { + "type": "bool", + "value": true + }, + { + "type": "float", + "value": 1.0 + }, + { + "type": "float", + "value": 1.0 + } + ], + "textures":[], + "shader_asset": "dolphin_dof_blur" +} diff --git a/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur_vertical.rastermaterial b/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur_vertical.rastermaterial new file mode 100644 index 0000000000..3934d7994f --- /dev/null +++ b/Data/Sys/Load/GraphicMods/All Games Blurred DOF/blur_vertical.rastermaterial @@ -0,0 +1,19 @@ +{ + "next_material_asset":"", + "properties":[ + { + "type": "bool", + "value": false + }, + { + "type": "float", + "value": 1.0 + }, + { + "type": "float", + "value": 1.0 + } + ], + "textures":[], + "shader_asset": "dolphin_dof_blur" +} diff --git a/Data/Sys/Load/GraphicMods/All Games Blurred DOF/metadata.json b/Data/Sys/Load/GraphicMods/All Games Blurred DOF/metadata.json new file mode 100644 index 0000000000..0eb0f4b8b0 --- /dev/null +++ b/Data/Sys/Load/GraphicMods/All Games Blurred DOF/metadata.json @@ -0,0 +1,41 @@ +{ + "meta": + { + "title": "DOF Blurred", + "author": "Dolphin Team", + "description": "Modifies depth of field effects to blur them to their native resolution. Results in depth of field looking much more natural at higher resolutions but the blur may be too intense in some games." + }, + "features": + [ + { + "group": "DOF", + "action": "custom_pipeline", + "action_data": + { + "material_asset": "dolphin_dof_blur_horizontal" + } + } + ], + "assets": [ + { + "data": { + "metadata": "blur.rastershader", + "pixel_shader": "blur.ps.glsl", + "vertex_shader": "blur.vs.glsl" + }, + "name": "dolphin_dof_blur" + }, + { + "data": { + "metadata": "blur_horizontal.rastermaterial" + }, + "name": "dolphin_dof_blur_horizontal" + }, + { + "data": { + "metadata": "blur_vertical.rastermaterial" + }, + "name": "dolphin_dof_blur_vertical" + } + ] +} From 5897d8e0ffac04e4b35701b97c143812cacffc49 Mon Sep 17 00:00:00 2001 From: iwubcode Date: Fri, 30 Jan 2026 21:49:27 -0600 Subject: [PATCH 10/12] Data: update Pandora's Tower Bloom and DOF definitions --- Data/Sys/Load/GraphicMods/Pandora's Tower/metadata.json | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Data/Sys/Load/GraphicMods/Pandora's Tower/metadata.json b/Data/Sys/Load/GraphicMods/Pandora's Tower/metadata.json index dcbdadd49a..a8cfef97bc 100644 --- a/Data/Sys/Load/GraphicMods/Pandora's Tower/metadata.json +++ b/Data/Sys/Load/GraphicMods/Pandora's Tower/metadata.json @@ -2,7 +2,7 @@ "meta": { "title": "Bloom and DOF Texture Definitions", - "author": "linckandrea" + "author": "linckandrea, iwubcode" }, "groups": [ @@ -15,7 +15,7 @@ }, { "type": "efb", - "texture_filename": "efb1_n21_20x15_1" + "texture_filename": "efb1_n21_40x30_1" } ] }, @@ -25,10 +25,6 @@ { "type": "efb", "texture_filename": "efb1_n10_320x240_4" - }, - { - "type": "efb", - "texture_filename": "efb1_n11_320x240_1" } ] } From 8278d16e1a1f414c2165f5ae86c5cb7ebf825b21 Mon Sep 17 00:00:00 2001 From: iwubcode Date: Fri, 30 Jan 2026 21:52:46 -0600 Subject: [PATCH 11/12] Data: update Sonic Colors bloom definitions to remove repeats, thanks FrankyBuster --- .../GraphicMods/Sonic Colors/metadata.json | 22 +------------------ 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/Data/Sys/Load/GraphicMods/Sonic Colors/metadata.json b/Data/Sys/Load/GraphicMods/Sonic Colors/metadata.json index 9be5ac94ea..089ea9d43a 100644 --- a/Data/Sys/Load/GraphicMods/Sonic Colors/metadata.json +++ b/Data/Sys/Load/GraphicMods/Sonic Colors/metadata.json @@ -2,7 +2,7 @@ "meta": { "title": "Bloom Texture Definitions", - "author": "Silent Hell" + "author": "Silent Hell, FrankyBuster" }, "groups": [ @@ -13,37 +13,17 @@ "type": "efb", "texture_filename": "efb1_n000007_160x120_6" }, - { - "type": "efb", - "texture_filename": "efb1_n000008_160x120_6" - }, { "type": "efb", "texture_filename": "efb1_n000009_80x60_6" }, - { - "type": "efb", - "texture_filename": "efb1_n000010_80x60_6" - }, { "type": "efb", "texture_filename": "efb1_n000011_40x30_6" }, - { - "type": "efb", - "texture_filename": "efb1_n000012_40x30_6" - }, { "type": "efb", "texture_filename": "efb1_n000013_20x15_6" - }, - { - "type": "efb", - "texture_filename": "efb1_n000014_20x15_6" - }, - { - "type": "efb", - "texture_filename": "efb1_n000015_160x120_6" } ] } From c1d8a594e3bc3be9caf8c2a488c517f688329818 Mon Sep 17 00:00:00 2001 From: iwubcode Date: Sat, 31 Jan 2026 01:04:43 -0600 Subject: [PATCH 12/12] Data: update De Blob 1 and 2 to use explicit mods for bloom blur and removal, this is because these games do some strange behaviors and can't use the generic solutions. These games have several bloom EFB copies and they draw that on top of an already rendered game. After doing that, they render some other draw calls to "fixup" the bloom that it drew to effectively remove it. This isn't uncommon but there is one special thing these games do...they use a RAM EFB copy for the 'fixup'. This means when playing with high IR, the game will look blurry in specific parts of the screen where the game was attempting to fix the copy! Bloom removal has addressed this by removing all the draw calls related to the bloom, including the fixup draws. The user then needs to turn on 'EFB Copy To Texture Only' for the best visuals (De Blob 2 in particular is broken without this) as the default settings. Bloom blurred will need special attention too but Dolphin doesn't currently have enough functionality to handle it. --- .../De Blob 2/{ => Bloom Blurred}/SDB.txt | 0 .../De Blob 2/Bloom Blurred/metadata.json | 65 +++++++++++++++++++ .../Bloom Removal/SDB.txt} | 0 .../De Blob 2/Bloom Removal/metadata.json | 64 ++++++++++++++++++ .../Load/GraphicMods/De Blob 2/metadata.json | 31 --------- .../GraphicMods/De Blob/Bloom Blurred/R6B.txt | 0 .../De Blob/Bloom Blurred/metadata.json | 65 +++++++++++++++++++ .../GraphicMods/De Blob/Bloom Removal/R6B.txt | 0 .../De Blob/Bloom Removal/metadata.json | 64 ++++++++++++++++++ .../Load/GraphicMods/De Blob/metadata.json | 31 --------- 10 files changed, 258 insertions(+), 62 deletions(-) rename Data/Sys/Load/GraphicMods/De Blob 2/{ => Bloom Blurred}/SDB.txt (100%) create mode 100644 Data/Sys/Load/GraphicMods/De Blob 2/Bloom Blurred/metadata.json rename Data/Sys/Load/GraphicMods/{De Blob/R6B.txt => De Blob 2/Bloom Removal/SDB.txt} (100%) create mode 100644 Data/Sys/Load/GraphicMods/De Blob 2/Bloom Removal/metadata.json delete mode 100644 Data/Sys/Load/GraphicMods/De Blob 2/metadata.json create mode 100644 Data/Sys/Load/GraphicMods/De Blob/Bloom Blurred/R6B.txt create mode 100644 Data/Sys/Load/GraphicMods/De Blob/Bloom Blurred/metadata.json create mode 100644 Data/Sys/Load/GraphicMods/De Blob/Bloom Removal/R6B.txt create mode 100644 Data/Sys/Load/GraphicMods/De Blob/Bloom Removal/metadata.json delete mode 100644 Data/Sys/Load/GraphicMods/De Blob/metadata.json diff --git a/Data/Sys/Load/GraphicMods/De Blob 2/SDB.txt b/Data/Sys/Load/GraphicMods/De Blob 2/Bloom Blurred/SDB.txt similarity index 100% rename from Data/Sys/Load/GraphicMods/De Blob 2/SDB.txt rename to Data/Sys/Load/GraphicMods/De Blob 2/Bloom Blurred/SDB.txt diff --git a/Data/Sys/Load/GraphicMods/De Blob 2/Bloom Blurred/metadata.json b/Data/Sys/Load/GraphicMods/De Blob 2/Bloom Blurred/metadata.json new file mode 100644 index 0000000000..c9f84d4335 --- /dev/null +++ b/Data/Sys/Load/GraphicMods/De Blob 2/Bloom Blurred/metadata.json @@ -0,0 +1,65 @@ +{ + "meta": + { + "title": "Bloom Blurred", + "author": "Dolphin Team", + "description": "Modifies bloom effects to blur them to their native resolution. Results in bloom looking much more natural at higher resolutions but the blur may be too intense in some games." + }, + "groups": + [ + { + "name": "CustomBloom", + "targets": [ + { + "type": "efb", + "texture_filename": "efb1_n000134_20x14_6" + }, + { + "type": "efb", + "texture_filename": "efb1_n000022_40x28_6" + }, + { + "type": "efb", + "texture_filename": "efb1_n000131_80x56_6" + }, + { + "type": "efb", + "texture_filename": "efb1_n000130_160x112_6" + } + ] + } + ], + "features": + [ + { + "group": "CustomBloom", + "action": "custom_pipeline", + "action_data": + { + "material_asset": "dolphin_bloom_blur_horizontal" + } + } + ], + "assets": [ + { + "data": { + "metadata": "../../All Games Blurred Bloom/blur.rastershader", + "pixel_shader": "../../All Games Blurred Bloom/blur.ps.glsl", + "vertex_shader": "../../All Games Blurred Bloom/blur.vs.glsl" + }, + "name": "dolphin_bloom_blur" + }, + { + "data": { + "metadata": "../../All Games Blurred Bloom/blur_horizontal.rastermaterial" + }, + "name": "dolphin_bloom_blur_horizontal" + }, + { + "data": { + "metadata": "../../All Games Blurred Bloom/blur_vertical.rastermaterial" + }, + "name": "dolphin_bloom_blur_vertical" + } + ] +} diff --git a/Data/Sys/Load/GraphicMods/De Blob/R6B.txt b/Data/Sys/Load/GraphicMods/De Blob 2/Bloom Removal/SDB.txt similarity index 100% rename from Data/Sys/Load/GraphicMods/De Blob/R6B.txt rename to Data/Sys/Load/GraphicMods/De Blob 2/Bloom Removal/SDB.txt diff --git a/Data/Sys/Load/GraphicMods/De Blob 2/Bloom Removal/metadata.json b/Data/Sys/Load/GraphicMods/De Blob 2/Bloom Removal/metadata.json new file mode 100644 index 0000000000..bf9255d02e --- /dev/null +++ b/Data/Sys/Load/GraphicMods/De Blob 2/Bloom Removal/metadata.json @@ -0,0 +1,64 @@ +{ + "meta": + { + "title": "Bloom Removal", + "author": "Dolphin Team", + "description": "Skips drawing bloom effects. May be preferable when using a bloom solution from Dolphin's post processing shaders or a third party tool. Requires enabling 'EFB Copy To Texture Only'" + }, + "groups": + [ + { + "name": "CustomBloom", + "targets": [ + { + "type": "draw_started", + "texture_filename": "efb1_n000134_20x14_6" + }, + { + "type": "draw_started", + "texture_filename": "efb1_n000022_40x28_6" + }, + { + "type": "draw_started", + "texture_filename": "efb1_n000131_80x56_6" + }, + { + "type": "draw_started", + "texture_filename": "efb1_n000130_160x112_6" + } + ] + }, + { + "name": "Fixup", + "targets": [ + { + "type": "draw_started", + "texture_filename": "tex1_256x179_802b7563f35b613a_6" + }, + { + "type": "draw_started", + "texture_filename": "efb1_n000182_640x448_5" + }, + { + "type": "draw_started", + "texture_filename": "efb1_n000380_320x224_6" + }, + { + "type": "draw_started", + "texture_filename": "efb1_n000380_240x224_6" + } + ] + } + ], + "features": + [ + { + "group": "CustomBloom", + "action": "skip" + }, + { + "group": "Fixup", + "action": "skip" + } + ] +} diff --git a/Data/Sys/Load/GraphicMods/De Blob 2/metadata.json b/Data/Sys/Load/GraphicMods/De Blob 2/metadata.json deleted file mode 100644 index 697d28c730..0000000000 --- a/Data/Sys/Load/GraphicMods/De Blob 2/metadata.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "meta": - { - "title": "Bloom Texture Definitions", - "author": "iwubcode" - }, - "groups": - [ - { - "name": "Bloom", - "targets": [ - { - "type": "efb", - "texture_filename": "efb1_n000134_20x14_6" - }, - { - "type": "efb", - "texture_filename": "efb1_n000022_40x28_6" - }, - { - "type": "efb", - "texture_filename": "efb1_n000131_80x56_6" - }, - { - "type": "efb", - "texture_filename": "efb1_n000130_160x112_6" - } - ] - } - ] -} diff --git a/Data/Sys/Load/GraphicMods/De Blob/Bloom Blurred/R6B.txt b/Data/Sys/Load/GraphicMods/De Blob/Bloom Blurred/R6B.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Data/Sys/Load/GraphicMods/De Blob/Bloom Blurred/metadata.json b/Data/Sys/Load/GraphicMods/De Blob/Bloom Blurred/metadata.json new file mode 100644 index 0000000000..c9f84d4335 --- /dev/null +++ b/Data/Sys/Load/GraphicMods/De Blob/Bloom Blurred/metadata.json @@ -0,0 +1,65 @@ +{ + "meta": + { + "title": "Bloom Blurred", + "author": "Dolphin Team", + "description": "Modifies bloom effects to blur them to their native resolution. Results in bloom looking much more natural at higher resolutions but the blur may be too intense in some games." + }, + "groups": + [ + { + "name": "CustomBloom", + "targets": [ + { + "type": "efb", + "texture_filename": "efb1_n000134_20x14_6" + }, + { + "type": "efb", + "texture_filename": "efb1_n000022_40x28_6" + }, + { + "type": "efb", + "texture_filename": "efb1_n000131_80x56_6" + }, + { + "type": "efb", + "texture_filename": "efb1_n000130_160x112_6" + } + ] + } + ], + "features": + [ + { + "group": "CustomBloom", + "action": "custom_pipeline", + "action_data": + { + "material_asset": "dolphin_bloom_blur_horizontal" + } + } + ], + "assets": [ + { + "data": { + "metadata": "../../All Games Blurred Bloom/blur.rastershader", + "pixel_shader": "../../All Games Blurred Bloom/blur.ps.glsl", + "vertex_shader": "../../All Games Blurred Bloom/blur.vs.glsl" + }, + "name": "dolphin_bloom_blur" + }, + { + "data": { + "metadata": "../../All Games Blurred Bloom/blur_horizontal.rastermaterial" + }, + "name": "dolphin_bloom_blur_horizontal" + }, + { + "data": { + "metadata": "../../All Games Blurred Bloom/blur_vertical.rastermaterial" + }, + "name": "dolphin_bloom_blur_vertical" + } + ] +} diff --git a/Data/Sys/Load/GraphicMods/De Blob/Bloom Removal/R6B.txt b/Data/Sys/Load/GraphicMods/De Blob/Bloom Removal/R6B.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Data/Sys/Load/GraphicMods/De Blob/Bloom Removal/metadata.json b/Data/Sys/Load/GraphicMods/De Blob/Bloom Removal/metadata.json new file mode 100644 index 0000000000..a2209dfa85 --- /dev/null +++ b/Data/Sys/Load/GraphicMods/De Blob/Bloom Removal/metadata.json @@ -0,0 +1,64 @@ +{ + "meta": + { + "title": "Bloom Removal", + "author": "Dolphin Team", + "description": "Skips drawing bloom effects. May be preferable when using a bloom solution from Dolphin's post processing shaders or a third party tool." + }, + "groups": + [ + { + "name": "CustomBloom", + "targets": [ + { + "type": "draw_started", + "texture_filename": "efb1_n000134_20x14_6" + }, + { + "type": "draw_started", + "texture_filename": "efb1_n000022_40x28_6" + }, + { + "type": "draw_started", + "texture_filename": "efb1_n000131_80x56_6" + }, + { + "type": "draw_started", + "texture_filename": "efb1_n000130_160x112_6" + } + ] + }, + { + "name": "Fixup", + "targets": [ + { + "type": "draw_started", + "texture_filename": "tex1_240x224_05a5e9c230d056cc_6" + }, + { + "type": "draw_started", + "texture_filename": "efb1_n000182_640x448_5" + }, + { + "type": "draw_started", + "texture_filename": "efb1_n000380_320x224_6" + }, + { + "type": "draw_started", + "texture_filename": "efb1_n000380_240x224_6" + } + ] + } + ], + "features": + [ + { + "group": "CustomBloom", + "action": "skip" + }, + { + "group": "Fixup", + "action": "skip" + } + ] +} diff --git a/Data/Sys/Load/GraphicMods/De Blob/metadata.json b/Data/Sys/Load/GraphicMods/De Blob/metadata.json deleted file mode 100644 index 697d28c730..0000000000 --- a/Data/Sys/Load/GraphicMods/De Blob/metadata.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "meta": - { - "title": "Bloom Texture Definitions", - "author": "iwubcode" - }, - "groups": - [ - { - "name": "Bloom", - "targets": [ - { - "type": "efb", - "texture_filename": "efb1_n000134_20x14_6" - }, - { - "type": "efb", - "texture_filename": "efb1_n000022_40x28_6" - }, - { - "type": "efb", - "texture_filename": "efb1_n000131_80x56_6" - }, - { - "type": "efb", - "texture_filename": "efb1_n000130_160x112_6" - } - ] - } - ] -}