Compare commits

..

26 Commits

Author SHA1 Message Date
CamilleLaVey 5f0f6e6306 Experimenting with scissors offsets 2026-09-01 21:53:15 -04:00
CamilleLaVey d43238b9af Another change 2026-09-02 02:57:14 +02:00
CamilleLaVey 2addf1556e Another check 2026-09-02 02:57:14 +02:00
CamilleLaVey 883cdead8b Some sanity on the vertex stream 2026-09-02 02:57:14 +02:00
CamilleLaVey 104bfa3a8f Another take for indexing guards 2026-09-02 02:57:14 +02:00
CamilleLaVey 023c4758e9 Unify vertex entries from the indexed and non-indexed resolves into a single path 2026-09-02 02:57:14 +02:00
CamilleLaVey b9239c4944 Add instance draw counts to vertex buffers 2026-09-02 02:57:14 +02:00
CamilleLaVey f229172d3b Some cleanups on the vertex buffer path 2026-09-02 02:57:14 +02:00
CamilleLaVey eb18c5b8bd Removing redundant stagging per downloaded and swizzled image 2026-09-02 02:57:14 +02:00
CamilleLaVey 0c7d068112 Blit corrections within the image initialization 2026-09-02 02:57:14 +02:00
CamilleLaVey f29a23738a A quick change on the e3D pass 2026-09-02 02:57:14 +02:00
CamilleLaVey 7e5e326842 Another meow 2026-09-02 02:57:14 +02:00
CamilleLaVey f93e4031ba tie gpu modified regions to rescalable textures 2026-09-02 02:57:14 +02:00
CamilleLaVey 7e55b4b563 Dale a tu cuerpo alegría macarena 2026-09-02 02:57:14 +02:00
CamilleLaVey ee5049f0d3 Mercy please 2026-09-02 02:57:14 +02:00
CamilleLaVey 15de6e0e08 AAAAAAH 2026-09-02 02:57:14 +02:00
CamilleLaVey 75519010d2 Refining fix 2026-09-02 02:57:14 +02:00
CamilleLaVey 3e61e6da87 AQUI LLEGO TU LOBITO, MI LOBA. 2026-09-02 02:57:14 +02:00
CamilleLaVey 8242e54e42 This is so fucking tiring 2026-09-02 02:57:14 +02:00
CamilleLaVey 47b310266e Another try to fix QCOM driver, dear god. 2026-09-02 02:57:14 +02:00
CamilleLaVey 3cfac4abcd Just a small touch on the 3d swizzle params 2026-09-02 02:57:14 +02:00
CamilleLaVey 92c52342b8 Another try on the 3D pass 2026-09-02 02:57:14 +02:00
CamilleLaVey db2bdde9b3 Revert "Just another change"
This reverts commit 2ea449f71a.
2026-09-02 02:57:14 +02:00
CamilleLaVey ce0b15dcf7 Just another change 2026-09-02 02:57:14 +02:00
CamilleLaVey db922e50e3 Another check on feedback loop 2026-09-02 02:57:14 +02:00
CamilleLaVey ca52cf679a Another try on unswizzling 2026-09-02 02:57:14 +02:00
127 changed files with 1265 additions and 5987 deletions
@@ -1,11 +0,0 @@
--- a/source/effect_lexer.cpp
+++ b/source/effect_lexer.cpp
@@ -1181,7 +1181,7 @@
}
else
{
-#if 0
+#if !defined(__cpp_lib_to_chars)
exponent += decimal_location - mantissa_size;
const bool exponent_negative = exponent < 0;
@@ -1,112 +0,0 @@
diff --git a/include/vk_mem_alloc.h b/include/vk_mem_alloc.h
index 8df0364..4856064 100644
--- a/include/vk_mem_alloc.h
+++ b/include/vk_mem_alloc.h
@@ -3017,7 +3017,7 @@ remove them if not needed.
#if defined(__ANDROID_API__) && (__ANDROID_API__ < 16)
#include <cstdlib>
-static void* vma_aligned_alloc(size_t alignment, size_t size)
+static inline void* vma_aligned_alloc(size_t alignment, size_t size)
{
// alignment must be >= sizeof(void*)
if(alignment < sizeof(void*))
@@ -3860,7 +3860,7 @@ Returned value is the found element, if present in the collection or place where
new element with value (key) should be inserted.
*/
template <typename CmpLess, typename IterT, typename KeyT>
-static IterT VmaBinaryFindFirstNotLess(IterT beg, IterT end, const KeyT& key, const CmpLess& cmp)
+static inline IterT VmaBinaryFindFirstNotLess(IterT beg, IterT end, const KeyT& key, const CmpLess& cmp)
{
size_t down = 0;
size_t up = size_t(end - beg);
@@ -3898,7 +3898,7 @@ Warning! O(n^2) complexity. Use only inside VMA_HEAVY_ASSERT.
T must be pointer type, e.g. VmaAllocation, VmaPool.
*/
template<typename T>
-static bool VmaValidatePointerArray(uint32_t count, const T* arr)
+static inline bool VmaValidatePointerArray(uint32_t count, const T* arr)
{
for (uint32_t i = 0; i < count; ++i)
{
@@ -4188,13 +4188,13 @@ static void VmaFree(const VkAllocationCallbacks* pAllocationCallbacks, void* ptr
}
template<typename T>
-static T* VmaAllocate(const VkAllocationCallbacks* pAllocationCallbacks)
+static inline T* VmaAllocate(const VkAllocationCallbacks* pAllocationCallbacks)
{
return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T), VMA_ALIGN_OF(T));
}
template<typename T>
-static T* VmaAllocateArray(const VkAllocationCallbacks* pAllocationCallbacks, size_t count)
+static inline T* VmaAllocateArray(const VkAllocationCallbacks* pAllocationCallbacks, size_t count)
{
return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T) * count, VMA_ALIGN_OF(T));
}
@@ -4204,14 +4204,14 @@ static T* VmaAllocateArray(const VkAllocationCallbacks* pAllocationCallbacks, si
#define vma_new_array(allocator, type, count) new(VmaAllocateArray<type>((allocator), (count)))(type)
template<typename T>
-static void vma_delete(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr)
+static inline void vma_delete(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr)
{
ptr->~T();
VmaFree(pAllocationCallbacks, ptr);
}
template<typename T>
-static void vma_delete_array(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr, size_t count)
+static inline void vma_delete_array(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr, size_t count)
{
if (ptr != VMA_NULL)
{
@@ -4658,13 +4658,13 @@ void VmaVector<T, AllocatorT>::remove(size_t index)
#endif // _VMA_VECTOR_FUNCTIONS
template<typename T, typename allocatorT>
-static void VmaVectorInsert(VmaVector<T, allocatorT>& vec, size_t index, const T& item)
+static inline void VmaVectorInsert(VmaVector<T, allocatorT>& vec, size_t index, const T& item)
{
vec.insert(index, item);
}
template<typename T, typename allocatorT>
-static void VmaVectorRemove(VmaVector<T, allocatorT>& vec, size_t index)
+static inline void VmaVectorRemove(VmaVector<T, allocatorT>& vec, size_t index)
{
vec.remove(index);
}
@@ -10620,19 +10620,19 @@ static void VmaFree(VmaAllocator hAllocator, void* ptr)
}
template<typename T>
-static T* VmaAllocate(VmaAllocator hAllocator)
+static inline T* VmaAllocate(VmaAllocator hAllocator)
{
return (T*)VmaMalloc(hAllocator, sizeof(T), VMA_ALIGN_OF(T));
}
template<typename T>
-static T* VmaAllocateArray(VmaAllocator hAllocator, size_t count)
+static inline T* VmaAllocateArray(VmaAllocator hAllocator, size_t count)
{
return (T*)VmaMalloc(hAllocator, sizeof(T) * count, VMA_ALIGN_OF(T));
}
template<typename T>
-static void vma_delete(VmaAllocator hAllocator, T* ptr)
+static inline void vma_delete(VmaAllocator hAllocator, T* ptr)
{
if(ptr != VMA_NULL)
{
@@ -10642,7 +10642,7 @@ static void vma_delete(VmaAllocator hAllocator, T* ptr)
}
template<typename T>
-static void vma_delete_array(VmaAllocator hAllocator, T* ptr, size_t count)
+static inline void vma_delete_array(VmaAllocator hAllocator, T* ptr, size_t count)
{
if(ptr != VMA_NULL)
{
+2 -5
View File
@@ -3,7 +3,6 @@
cmake_minimum_required(VERSION 3.31) cmake_minimum_required(VERSION 3.31)
set(CMAKE_OSX_DEPLOYMENT_TARGET "15.0" CACHE STRING "macOS deployment target")
project(yuzu) project(yuzu)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
@@ -85,8 +84,6 @@ option(ENABLE_WERROR "Enable -Werror diagnostics" ON)
# Lossless Scaling frame generation. Only Android. # Lossless Scaling frame generation. Only Android.
cmake_dependent_option(ENABLE_LSFG "Enable Lossless Scaling frame generation" ON "ANDROID" OFF) cmake_dependent_option(ENABLE_LSFG "Enable Lossless Scaling frame generation" ON "ANDROID" OFF)
option(ENABLE_RESHADE "Enable ReShade FX post-processing effects" ON)
# non-linux bundled qt are static # non-linux bundled qt are static
if (YUZU_USE_BUNDLED_QT AND (APPLE OR NOT UNIX)) if (YUZU_USE_BUNDLED_QT AND (APPLE OR NOT UNIX))
set(YUZU_STATIC_BUILD ON) set(YUZU_STATIC_BUILD ON)
@@ -241,7 +238,7 @@ option(YUZU_USE_BUNDLED_SIRIT "Download bundled sirit" ${BUNDLED_SIRIT_DEFAULT})
# FreeBSD 15+ has libusb, versions below should disable it # FreeBSD 15+ has libusb, versions below should disable it
cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "WIN32 OR LINUX OR FREEBSD OR APPLE" OFF) cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "WIN32 OR LINUX OR FREEBSD OR APPLE" OFF)
cmake_dependent_option(ENABLE_OPENGL "Enable OpenGL" ON "NOT (WIN32 AND ARCHITECTURE_arm64) AND NOT APPLE AND NOT ANDROID" OFF) cmake_dependent_option(ENABLE_OPENGL "Enable OpenGL" ON "NOT (WIN32 AND ARCHITECTURE_arm64) AND NOT APPLE" OFF)
mark_as_advanced(FORCE ENABLE_OPENGL) mark_as_advanced(FORCE ENABLE_OPENGL)
option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON) option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
@@ -515,7 +512,7 @@ endfunction()
# ============================================= # =============================================
if (APPLE) if (APPLE)
foreach(fw Carbon Metal Cocoa IOKit CoreVideo CoreMedia Security UniformTypeIdentifiers Foundation) foreach(fw Carbon Metal Cocoa IOKit CoreVideo CoreMedia Security UniformTypeIdentifiers)
find_library(${fw}_LIBRARY ${fw} REQUIRED) find_library(${fw}_LIBRARY ${fw} REQUIRED)
list(APPEND PLATFORM_LIBRARIES ${${fw}_LIBRARY}) list(APPEND PLATFORM_LIBRARIES ${${fw}_LIBRARY})
endforeach() endforeach()
+10 -13
View File
@@ -1,4 +1,12 @@
{ {
"": {
"ci": true,
"hash": "9f50d993c39529e022ad456163de91ac5934e16faf8fc348f305355fc0a643c534f87ded707e11bd03bcbc0a1760bd20852b6533a67ac0558a078385181cb184",
"name": "SDL3",
"package": "SDL3",
"repo": "crueter-ci/SDL3",
"version": "3.4.14-1788231389-147a8ee32d"
},
"biscuit": { "biscuit": {
"hash": "1229f345b014f7ca544dedb4edb3311e41ba736f9aa9a67f88b5f26f3c983288c6bb6cdedcfb0b8a02c63088a37e6a0d7ba97d9c2a4d721b213916327cffe28a", "hash": "1229f345b014f7ca544dedb4edb3311e41ba736f9aa9a67f88b5f26f3c983288c6bb6cdedcfb0b8a02c63088a37e6a0d7ba97d9c2a4d721b213916327cffe28a",
"min_version": "0.9.1", "min_version": "0.9.1",
@@ -60,10 +68,10 @@
}, },
"discord-rpc": { "discord-rpc": {
"find_args": "MODULE", "find_args": "MODULE",
"hash": "8d680b3a16d6f6bf292ad823cf8635595ff986f2a49f758e3009f505b540a9d75194a8cf44cddea75736a8c3e3b5160166e716a0939ce3f18cc463cf648753fe", "hash": "8213c43dcb0f7d479f5861091d111ed12fbdec1e62e6d729d65a4bc181d82f48a35d5fd3cd5c291f2393ac7c9681eabc6b76609755f55376284c8a8d67e148f3",
"package": "DiscordRPC", "package": "DiscordRPC",
"repo": "eden-emulator/discord-rpc", "repo": "eden-emulator/discord-rpc",
"version": "76616d8675" "version": "0d8b2d6a37"
}, },
"enet": { "enet": {
"find_args": "MODULE", "find_args": "MODULE",
@@ -238,14 +246,6 @@
"repo": "stachenov/quazip", "repo": "stachenov/quazip",
"version": "2e95c9001b" "version": "2e95c9001b"
}, },
"reshade": {
"hash": "6fc9b39821ca6e2d91160f05846b3a42159fec759f5d6fba91d1a57801a1bdaf6047740578c136f0b1a60a9c29ad160d87dbfe0dbfbcdf6ea879a8a078377b8c",
"patches": [
"0001-from-chars-fallback.patch"
],
"repo": "crosire/reshade",
"version": "v6.8.0"
},
"sdl3": { "sdl3": {
"hash": "df5a323af7ac366661a3c0e887969c72584d232f3cc211419d59b0487b620b6b2859d4549c9e8df002ee489290062e466fcfddf7edc0872a37b1f2845e81c0f3", "hash": "df5a323af7ac366661a3c0e887969c72584d232f3cc211419d59b0487b620b6b2859d4549c9e8df002ee489290062e466fcfddf7edc0872a37b1f2845e81c0f3",
"min_version": "3.2.10", "min_version": "3.2.10",
@@ -311,9 +311,6 @@
"find_args": "CONFIG", "find_args": "CONFIG",
"hash": "deb5902ef8db0e329fbd5f3f4385eb0e26bdd9f14f3a2334823fb3fe18f36bc5d235d620d6e5f6fe3551ec3ea7038638899db8778c09f6d5c278f5ff95c3344b", "hash": "deb5902ef8db0e329fbd5f3f4385eb0e26bdd9f14f3a2334823fb3fe18f36bc5d235d620d6e5f6fe3551ec3ea7038638899db8778c09f6d5c278f5ff95c3344b",
"package": "VulkanMemoryAllocator", "package": "VulkanMemoryAllocator",
"patches": [
"0001-macos-clang.patch"
],
"repo": "GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator", "repo": "GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator",
"version": "v3.3.0" "version": "v3.3.0"
}, },
-70
View File
@@ -1,70 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2012 PPSSPP Project
// SPDX-License-Identifier: GPL-2.0-or-later
// Ported from bloomnoblur.fsh in PPSSPP.
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Radius <
ui_type = "slider";
ui_label = "Radius";
ui_tooltip = "How far the glow spreads from bright areas.";
ui_min = 0.0; ui_max = 4.0; ui_step = 0.05;
> = 1.0;
uniform float Amount <
ui_type = "slider";
ui_label = "Amount";
ui_tooltip = "Strength of the glow added on top of the image.";
ui_min = 0.0; ui_max = 2.0; ui_step = 0.05;
> = 0.6;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float Weight(float3 color)
{
float gray = (color.r + color.g + color.b) / 3.0;
float saturation = (abs(color.r - gray) + abs(color.g - gray) + abs(color.b - gray)) / 3.0;
return gray * gray / max(saturation, 0.25);
}
float4 PS_Bloom(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float3 color = tex2D(BackBuffer, uv).rgb;
float gray = (color.r + color.g + color.b) / 3.0;
float saturation = (abs(color.r - gray) + abs(color.g - gray) + abs(color.b - gray)) / 3.0;
float spread = 0.002 * gray / max(saturation, 0.25) * Radius;
float3 sum = float3(0.0, 0.0, 0.0);
for (int x = -3; x <= 3; x += 2)
{
for (int y = -3; y <= 3; y += 2)
{
float3 tap = tex2D(BackBuffer, uv + float2(x, y) * spread).rgb;
sum += tap * Weight(tap);
}
}
sum /= 16.0;
return float4(saturate(color + sum * Amount), 1.0);
}
technique Bloom <
ui_label = "Bloom";
ui_tooltip = "Blooms bright areas into a soft glow.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Bloom;
}
}
-87
View File
@@ -1,87 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Radius <
ui_type = "slider";
ui_label = "Radius";
ui_tooltip = "How far the blur reaches, in pixels.";
ui_min = 1.0; ui_max = 12.0; ui_step = 0.5;
> = 4.0;
uniform float Strength <
ui_type = "slider";
ui_label = "Strength";
ui_tooltip = "Blend between the original image and the blurred one.";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
> = 1.0;
uniform float FocusSize <
ui_type = "slider";
ui_label = "Sharp Centre";
ui_tooltip = "Size of the region left in focus at the centre of the screen. At zero the whole image is blurred evenly.";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
> = 0.0;
uniform float FocusSoftness <
ui_type = "slider";
ui_label = "Focus Falloff";
ui_tooltip = "How gradually the sharp centre gives way to the blur.";
ui_min = 0.05; ui_max = 1.0; ui_step = 0.05;
> = 0.4;
static const int TAPS = 17;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_Blur(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT);
float3 original = tex2D(BackBuffer, uv).rgb;
float2 centred = (uv - 0.5) * float2(BUFFER_WIDTH * BUFFER_RCP_HEIGHT, 1.0) * 2.0;
float distance_from_centre = length(centred);
float no_focus = 1.0 - step(0.001, FocusSize);
float focus = max(smoothstep(FocusSize, FocusSize + FocusSoftness, distance_from_centre), no_focus);
float amount = Strength * focus;
float angle = frac(sin(dot(pos.xy, float2(12.9898, 78.233))) * 43758.5453) * 6.2831853;
float2 spoke = float2(cos(angle), sin(angle));
const float2 turn = float2(cos(2.39996323), sin(2.39996323));
const float decay = exp(-2.0 / float(TAPS));
float weight = exp(-1.0 / float(TAPS));
float3 sum = float3(0.0, 0.0, 0.0);
float total = 0.0;
for (int i = 0; i < TAPS; ++i)
{
float reach = sqrt((float(i) + 0.5) / float(TAPS));
sum += tex2D(BackBuffer, uv + spoke * reach * texel * Radius).rgb * weight;
total += weight;
weight *= decay;
spoke = float2(spoke.x * turn.x - spoke.y * turn.y,
spoke.x * turn.y + spoke.y * turn.x);
}
float3 blurred = sum / total;
return float4(lerp(original, blurred, amount), 1.0);
}
technique Blur <
ui_label = "Blur";
ui_tooltip = "Gaussian blur with an optional sharp centre, for softening the picture or faking depth of field.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Blur;
}
}
-74
View File
@@ -1,74 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2012 PPSSPP Project
// SPDX-License-Identifier: GPL-2.0-or-later
// Ported from crt.fsh in PPSSPP, by KillaMaaki.
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Timer < source = "timer"; > = 0.0;
uniform float Density <
ui_type = "slider";
ui_label = "Line Density";
ui_min = 60.0; ui_max = 720.0; ui_step = 10.0;
> = 272.0;
uniform float RollSpeed <
ui_type = "slider";
ui_label = "Roll Speed";
ui_tooltip = "Speed of the rolling bar. Zero disables it.";
ui_min = 0.0; ui_max = 2.0; ui_step = 0.05;
> = 1.0;
uniform float Bleed <
ui_type = "slider";
ui_label = "Colour Bleed";
ui_tooltip = "Horizontal separation of the red and green channels.";
ui_min = 0.0; ui_max = 4.0; ui_step = 0.1;
> = 1.0;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_CRT(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float seconds = Timer * 0.001;
float scan = floor((uv.y + seconds * RollSpeed * 0.5) * Density);
float line_intensity = frac(scan * 0.5) * 2.0;
float2 shift = float2(line_intensity * 0.0005, 0.0);
float2 bleed = float2(BUFFER_RCP_WIDTH * Bleed, 0.0);
float r = tex2D(BackBuffer, uv + bleed + shift).r;
float g = tex2D(BackBuffer, uv - bleed + shift).g;
float b = tex2D(BackBuffer, uv).b;
float3 color = float3(r, g * 0.99, b) * clamp(line_intensity, 0.85, 1.0);
if (RollSpeed > 0.0)
{
float rollbar = sin((uv.y + seconds * RollSpeed) * 4.0);
color += rollbar * 0.02;
}
return float4(saturate(color), 1.0);
}
technique CRT <
ui_label = "CRT";
ui_tooltip = "Curved scanlines and the phosphor mask of a CRT television.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_CRT;
}
}
-79
View File
@@ -1,79 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2012 PPSSPP Project
// SPDX-FileCopyrightText: guest(r)
// SPDX-License-Identifier: GPL-2.0-or-later
// Ported from cartoon.fsh in PPSSPP, Advanced Cartoon shader I by guest(r).
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float EdgeStrength <
ui_type = "slider";
ui_label = "Edge Strength";
ui_tooltip = "Darkness of the ink outline drawn around detected edges.";
ui_min = 0.0; ui_max = 2.0; ui_step = 0.05;
> = 0.5;
uniform float Levels <
ui_type = "slider";
ui_label = "Colour Levels";
ui_tooltip = "How many bands the colours are quantised into.";
ui_min = 2.0; ui_max = 16.0; ui_step = 1.0;
> = 4.0;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_Cartoon(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT);
float3 c00 = tex2D(BackBuffer, uv + texel * float2(-1.0, -1.0)).rgb;
float3 c10 = tex2D(BackBuffer, uv + texel * float2( 0.0, -1.0)).rgb;
float3 c20 = tex2D(BackBuffer, uv + texel * float2( 1.0, -1.0)).rgb;
float3 c01 = tex2D(BackBuffer, uv + texel * float2(-1.0, 0.0)).rgb;
float3 c11 = tex2D(BackBuffer, uv).rgb;
float3 c21 = tex2D(BackBuffer, uv + texel * float2( 1.0, 0.0)).rgb;
float3 c02 = tex2D(BackBuffer, uv + texel * float2(-1.0, 1.0)).rgb;
float3 c12 = tex2D(BackBuffer, uv + texel * float2( 0.0, 1.0)).rgb;
float3 c22 = tex2D(BackBuffer, uv + texel * float2( 1.0, 1.0)).rgb;
const float3 dt = float3(1.0, 1.0, 1.0);
float d1 = dot(abs(c00 - c22), dt);
float d2 = dot(abs(c20 - c02), dt);
float hl = dot(abs(c01 - c21), dt);
float vl = dot(abs(c10 - c12), dt);
float edge = EdgeStrength * (d1 + d2 + hl + vl) / (dot(c11, dt) + 0.15);
float lc = Levels * length(c11);
float f = frac(lc);
f *= f;
lc = (floor(lc) + f * f) / Levels + 0.05;
float3 unit = normalize(max(c11, 0.0001));
float3 quant = Levels * unit;
float3 frct = frac(quant);
frct *= frct;
quant = floor(quant) + 0.05 * dt + frct * frct;
float3 color = lc * (1.1 - edge * sqrt(edge)) * quant / Levels;
return float4(saturate(color), 1.0);
}
technique Cartoon <
ui_label = "Cartoon";
ui_tooltip = "Ink outlines and flat colour bands. Faithful port of the PPSSPP shader; the outline gets heavy in dark scenes.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Cartoon;
}
}
-100
View File
@@ -1,100 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2012 PPSSPP Project
// SPDX-FileCopyrightText: guest(r)
// SPDX-License-Identifier: GPL-2.0-or-later
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float EdgeStrength <
ui_type = "slider";
ui_label = "Edge Strength";
ui_tooltip = "Darkness of the ink outline drawn around detected edges.";
ui_min = 0.0; ui_max = 2.0; ui_step = 0.05;
> = 0.45;
uniform float ShadowGuard <
ui_type = "slider";
ui_label = "Shadow Guard";
ui_tooltip = "Holds the outline back in dark areas. Raise it if shadows turn into black blobs.";
ui_min = 0.1; ui_max = 2.0; ui_step = 0.05;
> = 0.8;
uniform float Levels <
ui_type = "slider";
ui_label = "Colour Levels";
ui_tooltip = "How many bands the colours are quantised into.";
ui_min = 2.0; ui_max = 16.0; ui_step = 1.0;
> = 6.0;
uniform float Smoothing <
ui_type = "slider";
ui_label = "Banding";
ui_tooltip = "How far the picture is pushed towards flat bands.";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
> = 0.75;
uniform float Saturation <
ui_type = "slider";
ui_label = "Saturation";
ui_min = 0.0; ui_max = 2.0; ui_step = 0.05;
> = 1.15;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_CartoonSoft(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT);
float3 c00 = tex2D(BackBuffer, uv + texel * float2(-1.0, -1.0)).rgb;
float3 c10 = tex2D(BackBuffer, uv + texel * float2( 0.0, -1.0)).rgb;
float3 c20 = tex2D(BackBuffer, uv + texel * float2( 1.0, -1.0)).rgb;
float3 c01 = tex2D(BackBuffer, uv + texel * float2(-1.0, 0.0)).rgb;
float3 c11 = tex2D(BackBuffer, uv).rgb;
float3 c21 = tex2D(BackBuffer, uv + texel * float2( 1.0, 0.0)).rgb;
float3 c02 = tex2D(BackBuffer, uv + texel * float2(-1.0, 1.0)).rgb;
float3 c12 = tex2D(BackBuffer, uv + texel * float2( 0.0, 1.0)).rgb;
float3 c22 = tex2D(BackBuffer, uv + texel * float2( 1.0, 1.0)).rgb;
const float3 dt = float3(1.0, 1.0, 1.0);
const float3 luma_weights = float3(0.299, 0.587, 0.114);
float d1 = dot(abs(c00 - c22), dt);
float d2 = dot(abs(c20 - c02), dt);
float hl = dot(abs(c01 - c21), dt);
float vl = dot(abs(c10 - c12), dt);
float luma = dot(c11, luma_weights);
float response = (d1 + d2 + hl + vl) / (luma * 2.0 + ShadowGuard);
float ink = 1.0 - saturate(response * EdgeStrength);
float scaled = luma * Levels;
float step_position = frac(scaled);
float eased = step_position * step_position * (3.0 - 2.0 * step_position);
float banded = (floor(scaled) + eased) / Levels;
float target = lerp(luma, banded, Smoothing);
float3 tinted = c11 * (target / max(luma, 0.001));
float3 grey = dot(tinted, luma_weights);
float3 color = lerp(grey, tinted, Saturation) * ink;
return float4(saturate(color), 1.0);
}
technique CartoonSoft <
ui_label = "Cartoon Soft";
ui_tooltip = "Ink outlines and flat colour bands, with the outline held back in the shadows.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_CartoonSoft;
}
}
-120
View File
@@ -1,120 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Bands <
ui_type = "slider";
ui_label = "Shading Bands";
ui_tooltip = "How many flat steps the lighting is collapsed into. Three or four gives the classic look.";
ui_min = 2.0; ui_max = 8.0; ui_step = 1.0;
> = 4.0;
uniform float BandContrast <
ui_type = "slider";
ui_label = "Band Contrast";
ui_tooltip = "Spreads the bands towards pure black and white. Lower it if the shadows crush.";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
> = 0.5;
uniform float BandEdge <
ui_type = "slider";
ui_label = "Band Edge";
ui_tooltip = "Width of the transition between bands. Low values give hard cel steps.";
ui_min = 0.02; ui_max = 1.0; ui_step = 0.02;
> = 0.15;
uniform float Detail <
ui_type = "slider";
ui_label = "Texture Detail";
ui_tooltip = "How much surface texture survives the flattening. At zero the bands are completely flat.";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
> = 0.6;
uniform float OutlineStrength <
ui_type = "slider";
ui_label = "Outline Strength";
ui_tooltip = "Opacity of the ink line drawn along detected edges.";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
> = 0.8;
uniform float OutlineThreshold <
ui_type = "slider";
ui_label = "Outline Threshold";
ui_tooltip = "How strong an edge has to be before it is inked. Raise it to keep ink off textures and specular highlights.";
ui_min = 0.01; ui_max = 0.4; ui_step = 0.01;
> = 0.18;
uniform float Saturation <
ui_type = "slider";
ui_label = "Saturation";
ui_tooltip = "Colour intensity of the flat regions.";
ui_min = 0.0; ui_max = 2.0; ui_step = 0.05;
> = 1.25;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_CelShading(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
const float3 luma_weights = float3(0.2126, 0.7152, 0.0722);
float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT);
float3 centre = tex2D(BackBuffer, uv).rgb;
float luma = dot(centre, luma_weights);
float2 near = texel * 1.5;
float2 far = texel * 3.5;
float a00 = dot(tex2D(BackBuffer, uv + near * float2(-1.0, -1.0)).rgb, luma_weights);
float a20 = dot(tex2D(BackBuffer, uv + near * float2( 1.0, -1.0)).rgb, luma_weights);
float a02 = dot(tex2D(BackBuffer, uv + near * float2(-1.0, 1.0)).rgb, luma_weights);
float a22 = dot(tex2D(BackBuffer, uv + near * float2( 1.0, 1.0)).rgb, luma_weights);
float b00 = dot(tex2D(BackBuffer, uv + far * float2(-1.0, -1.0)).rgb, luma_weights);
float b20 = dot(tex2D(BackBuffer, uv + far * float2( 1.0, -1.0)).rgb, luma_weights);
float b02 = dot(tex2D(BackBuffer, uv + far * float2(-1.0, 1.0)).rgb, luma_weights);
float b22 = dot(tex2D(BackBuffer, uv + far * float2( 1.0, 1.0)).rgb, luma_weights);
float gx = (a00 + a02) - (a20 + a22);
float gy = (a00 + a20) - (a02 + a22);
float gradient = sqrt(gx * gx + gy * gy);
float ink = smoothstep(OutlineThreshold, OutlineThreshold + 0.04, gradient);
float lighting = (a00 + a20 + a02 + a22 + b00 + b20 + b02 + b22) * 0.125;
float detail = luma - lighting;
float softness = max(BandEdge, 0.001);
float coord = lighting * Bands - softness * 0.5;
float index = floor(coord) + smoothstep(1.0 - softness, 1.0, frac(coord));
float centred = (index + 0.5) / Bands;
float stretched = index / max(Bands - 1.0, 1.0);
float banded = saturate(lerp(centred, stretched, BandContrast));
float target = saturate(banded + detail * Detail);
float gain = min(target / max(luma, 0.001), 4.0);
float3 shaded = centre * gain;
float3 grey = dot(shaded, luma_weights);
float3 color = lerp(grey, shaded, Saturation);
color *= 1.0 - ink * OutlineStrength;
return float4(saturate(color), 1.0);
}
technique CelShading <
ui_label = "Cel Shading";
ui_tooltip = "Collapses the lighting into a few hard steps and inks the edges, keeping texture detail and hue intact.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_CelShading;
}
}
-53
View File
@@ -1,53 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Strength <
ui_type = "slider";
ui_label = "Strength";
ui_tooltip = "Channel separation in pixels, measured at the edge of the screen.";
ui_min = 0.0; ui_max = 8.0; ui_step = 0.1;
> = 1.5;
uniform float Falloff <
ui_type = "slider";
ui_label = "Falloff";
ui_tooltip = "How fast the separation grows away from the centre. Higher keeps the middle clean.";
ui_min = 1.0; ui_max = 4.0; ui_step = 0.1;
> = 2.0;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_ChromaticAberration(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT);
float2 direction = uv - float2(0.5, 0.5);
float radius = length(direction);
float2 unit = direction / max(radius, 0.0001);
float2 offset = unit * Strength * pow(radius * 2.0, Falloff) * texel;
float red = tex2D(BackBuffer, uv + offset).r;
float green = tex2D(BackBuffer, uv).g;
float blue = tex2D(BackBuffer, uv - offset).b;
return float4(red, green, blue, 1.0);
}
technique ChromaticAberration <
ui_label = "Chromatic Aberration";
ui_tooltip = "Splits the colour channels apart towards the edges of the screen, like a cheap lens.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_ChromaticAberration;
}
}
-64
View File
@@ -1,64 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2012 PPSSPP Project
// SPDX-License-Identifier: GPL-2.0-or-later
// Based on colorcorrection.fsh in PPSSPP.
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Saturation <
ui_type = "slider";
ui_label = "Saturation";
ui_min = 0.0; ui_max = 2.0; ui_step = 0.01;
> = 1.0;
uniform float Brightness <
ui_type = "slider";
ui_label = "Brightness";
ui_min = 0.0; ui_max = 2.0; ui_step = 0.01;
> = 1.0;
uniform float Contrast <
ui_type = "slider";
ui_label = "Contrast";
ui_min = 0.0; ui_max = 2.0; ui_step = 0.01;
> = 1.0;
uniform float Gamma <
ui_type = "slider";
ui_label = "Gamma";
ui_min = 0.5; ui_max = 2.0; ui_step = 0.01;
> = 1.0;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_ColorGrade(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float3 rgb = tex2D(BackBuffer, uv).rgb;
float luma = dot(rgb, float3(0.2126, 0.7152, 0.0722));
rgb = lerp(float3(luma, luma, luma), rgb, Saturation);
rgb *= Brightness;
rgb = (rgb - 0.5) * Contrast + 0.5;
rgb = pow(max(rgb, 0.0), 1.0 / max(Gamma, 0.0001));
return float4(saturate(rgb), 1.0);
}
technique ColorGrade <
ui_label = "Colour Grade";
ui_tooltip = "Global saturation, brightness, contrast and gamma.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_ColorGrade;
}
}
-91
View File
@@ -1,91 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2015 Niklas Haas
// SPDX-License-Identifier: MIT
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Threshold <
ui_type = "slider";
ui_label = "Threshold";
ui_tooltip = "How flat a neighbourhood must be before it gets smoothed. Raise it to catch wider bands, lower it to keep more detail.";
ui_min = 0.002; ui_max = 0.05; ui_step = 0.001;
> = 0.012;
uniform float Radius <
ui_type = "slider";
ui_label = "Radius";
ui_tooltip = "How far the sampling reaches, in pixels. Wider gradients need a larger radius.";
ui_min = 1.0; ui_max = 32.0; ui_step = 1.0;
> = 8.0;
uniform float Grain <
ui_type = "slider";
ui_label = "Dither";
ui_tooltip = "Noise added to break up whatever banding survives the smoothing.";
ui_min = 0.0; ui_max = 0.02; ui_step = 0.001;
> = 0.004;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float Hash(float2 p)
{
float3 scattered = frac(float3(p.x, p.y, p.x) * 0.1031);
scattered += dot(scattered, scattered.yzx + 33.33);
return frac((scattered.x + scattered.y) * scattered.z);
}
float4 PS_Deband(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT);
float3 centre = tex2D(BackBuffer, uv).rgb;
float base = Hash(pos.xy) * 6.2831853;
float3 total = float3(0.0, 0.0, 0.0);
float3 deviation = float3(0.0, 0.0, 0.0);
for (int ring = 1; ring <= 2; ++ring)
{
float angle = base + float(ring) * 2.3999632;
float reach = Radius * float(ring) * 0.5;
float2 along = float2(cos(angle), sin(angle)) * reach;
float2 across = float2(-along.y, along.x);
float3 s0 = tex2D(BackBuffer, uv + along * texel).rgb;
float3 s1 = tex2D(BackBuffer, uv - along * texel).rgb;
float3 s2 = tex2D(BackBuffer, uv + across * texel).rgb;
float3 s3 = tex2D(BackBuffer, uv - across * texel).rgb;
total += s0 + s1 + s2 + s3;
deviation = max(deviation, max(max(abs(s0 - centre), abs(s1 - centre)),
max(abs(s2 - centre), abs(s3 - centre))));
}
float3 average = total * 0.125;
float3 flatness = float3(1.0, 1.0, 1.0) -
smoothstep(Threshold * 0.5, Threshold, deviation);
float3 result = lerp(centre, average, flatness);
float dither = (Hash(pos.xy + float2(71.3, 41.7)) - 0.5) * Grain;
return float4(saturate(result + dither), 1.0);
}
technique Deband <
ui_label = "Deband";
ui_tooltip = "Smooths the visible steps in gradients such as skies, then dithers whatever survives.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Deband;
}
}
-83
View File
@@ -1,83 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2019-2021 bloc97
// SPDX-License-Identifier: MIT
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Strength <
ui_type = "slider";
ui_label = "Strength";
ui_min = 0.01; ui_max = 0.5; ui_step = 0.01;
> = 0.1;
uniform float Radius <
ui_type = "slider";
ui_label = "Radius";
ui_min = 0.3; ui_max = 2.0; ui_step = 0.05;
> = 1.0;
uniform float Curve <
ui_type = "slider";
ui_label = "Shadow Bias";
ui_min = 0.0; ui_max = 2.0; ui_step = 0.05;
> = 1.0;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float3 IntensityWeight(float3 value, float3 sigma, float3 centre)
{
float3 scaled = (value - centre) / sigma;
return exp(-0.5 * scaled * scaled);
}
float SpatialWeight(float distance, float sigma)
{
float scaled = distance / sigma;
return exp(-0.5 * scaled * scaled);
}
float4 PS_Denoise(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT);
float3 centre = tex2D(BackBuffer, uv).rgb;
float3 intensity_sigma = max(pow(centre + 0.0001, Curve) * Strength, 0.0001);
float spatial_sigma = max(Radius, 0.05);
float3 sum = float3(0.0, 0.0, 0.0);
float3 total = float3(0.0, 0.0, 0.0);
for (int y = -2; y <= 2; ++y)
{
for (int x = -2; x <= 2; ++x)
{
float2 offset = float2(x, y);
float3 tap = tex2D(BackBuffer, uv + offset * texel).rgb;
float3 weight = IntensityWeight(tap, intensity_sigma, centre) *
SpatialWeight(length(offset), spatial_sigma);
sum += weight * tap;
total += weight;
}
}
return float4(sum / total, 1.0);
}
technique Denoise <
ui_label = "Denoise";
ui_tooltip = "Edge preserving blur that clears dithering and compression noise. Ported from Anime4K.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Denoise;
}
}
-65
View File
@@ -1,65 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Intensity <
ui_type = "slider";
ui_label = "Intensity";
ui_min = 0.0; ui_max = 0.2; ui_step = 0.005;
> = 0.03;
uniform float Size <
ui_type = "slider";
ui_label = "Size";
ui_tooltip = "Grain cell size in pixels.";
ui_min = 1.0; ui_max = 4.0; ui_step = 1.0;
> = 1.0;
uniform float Colored <
ui_type = "slider";
ui_label = "Colour";
ui_tooltip = "Zero gives monochrome grain, one gives independent noise per channel.";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.01;
> = 0.0;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float Hash(float2 p)
{
float3 scattered = frac(float3(p.x, p.y, p.x) * 0.1031);
scattered += dot(scattered, scattered.yzx + 33.33);
return frac((scattered.x + scattered.y) * scattered.z);
}
float4 PS_FilmGrain(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float3 rgb = tex2D(BackBuffer, uv).rgb;
float2 cell = floor(pos.xy / max(Size, 1.0));
float mono = Hash(cell) - 0.5;
float3 chroma = float3(Hash(cell + 11.7), Hash(cell + 23.1), Hash(cell + 37.5)) - 0.5;
float3 noise = lerp(float3(mono, mono, mono), chroma, Colored);
float luma = dot(rgb, float3(0.2126, 0.7152, 0.0722));
float response = 1.0 - abs(luma * 2.0 - 1.0);
return float4(saturate(rgb + noise * Intensity * response), 1.0);
}
technique FilmGrain <
ui_label = "Film Grain";
ui_tooltip = "Adds photographic grain, strongest in the midtones and fading out in blacks and whites.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_FilmGrain;
}
}
-60
View File
@@ -1,60 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Exposure <
ui_type = "slider";
ui_label = "Exposure";
ui_min = 0.5; ui_max = 2.0; ui_step = 0.01;
> = 1.0;
uniform float Toe <
ui_type = "slider";
ui_label = "Toe";
ui_tooltip = "Above 1.0 deepens the shadows, below 1.0 lifts them.";
ui_min = 0.5; ui_max = 2.0; ui_step = 0.01;
> = 1.2;
uniform float Shoulder <
ui_type = "slider";
ui_label = "Shoulder";
ui_tooltip = "Above 1.0 opens up the highlights, below 1.0 compresses them.";
ui_min = 0.5; ui_max = 2.0; ui_step = 0.01;
> = 1.2;
uniform float Amount <
ui_type = "slider";
ui_label = "Amount";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.01;
> = 0.7;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_FilmicCurve(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float3 rgb = tex2D(BackBuffer, uv).rgb;
float3 curved = saturate(rgb * Exposure);
curved = pow(max(curved, 0.0), Toe);
curved = 1.0 - pow(max(1.0 - curved, 0.0), Shoulder);
return float4(saturate(lerp(rgb, curved, Amount)), 1.0);
}
technique FilmicCurve <
ui_label = "Filmic Curve";
ui_tooltip = "Filmic contrast curve. Deepens the shadows and opens the highlights without clipping either end.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_FilmicCurve;
}
}
-53
View File
@@ -1,53 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Distortion <
ui_type = "slider";
ui_label = "Distortion";
ui_tooltip = "Positive bulges the picture outwards, negative pinches it inwards.";
ui_min = -0.5; ui_max = 0.5; ui_step = 0.01;
> = 0.1;
uniform float Zoom <
ui_type = "slider";
ui_label = "Zoom";
ui_tooltip = "Scales the picture to hide the edges the warp pulls in.";
ui_min = 0.5; ui_max = 1.5; ui_step = 0.01;
> = 1.0;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_LensDistortion(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float aspect = BUFFER_WIDTH * BUFFER_RCP_HEIGHT;
float2 half_size = float2(aspect, 1.0);
float2 unit = half_size / length(half_size);
float2 centred = (uv - 0.5) * 2.0 * unit;
float r2 = dot(centred, centred);
centred *= 1.0 + Distortion * r2;
centred /= max(Zoom, 0.001);
float2 source = centred / (2.0 * unit) + 0.5;
return float4(tex2D(BackBuffer, source).rgb, 1.0);
}
technique LensDistortion <
ui_label = "Lens Distortion";
ui_tooltip = "Barrel or pincushion warp, like looking through a wide angle lens.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_LensDistortion;
}
}
-66
View File
@@ -1,66 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float InputBlack <
ui_type = "slider";
ui_label = "Input Black";
ui_tooltip = "Input level mapped to black. Raise it to deepen washed out shadows.";
ui_min = 0.0; ui_max = 0.5; ui_step = 0.005;
> = 0.0;
uniform float InputWhite <
ui_type = "slider";
ui_label = "Input White";
ui_min = 0.5; ui_max = 1.0; ui_step = 0.005;
> = 1.0;
uniform float Gamma <
ui_type = "slider";
ui_label = "Gamma";
ui_min = 0.2; ui_max = 3.0; ui_step = 0.01;
> = 1.0;
uniform float OutputBlack <
ui_type = "slider";
ui_label = "Output Black";
ui_tooltip = "Lifts crushed shadows so detail stops collapsing into one flat black.";
ui_min = 0.0; ui_max = 0.5; ui_step = 0.005;
> = 0.0;
uniform float OutputWhite <
ui_type = "slider";
ui_label = "Output White";
ui_min = 0.5; ui_max = 1.0; ui_step = 0.005;
> = 1.0;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_Levels(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float3 rgb = tex2D(BackBuffer, uv).rgb;
rgb = saturate((rgb - InputBlack) / max(InputWhite - InputBlack, 0.001));
rgb = pow(max(rgb, 0.0), 1.0 / max(Gamma, 0.001));
rgb = lerp(OutputBlack, OutputWhite, rgb);
return float4(saturate(rgb), 1.0);
}
technique Levels <
ui_label = "Levels";
ui_tooltip = "Black point, white point, gamma and output range. Use it to fix crushed or washed out shadows.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Levels;
}
}
-88
View File
@@ -1,88 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Length <
ui_type = "slider";
ui_label = "Length";
ui_tooltip = "How far the streaks reach, as a percentage of screen height.";
ui_min = 0.0; ui_max = 20.0; ui_step = 0.5;
> = 5.0;
uniform float Zoom <
ui_type = "slider";
ui_label = "Zoom";
ui_tooltip = "Streaks running out from the centre of the screen, as if rushing forward. The centre stays sharp.";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
> = 1.0;
uniform float Pan <
ui_type = "slider";
ui_label = "Pan";
ui_tooltip = "Streaks running in one fixed direction, as if the camera were sweeping across.";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
> = 0.0;
uniform float Angle <
ui_type = "slider";
ui_label = "Pan Angle";
ui_tooltip = "Direction of the sweep, in degrees.";
ui_min = 0.0; ui_max = 360.0; ui_step = 5.0;
> = 0.0;
uniform float Spin <
ui_type = "slider";
ui_label = "Spin";
ui_tooltip = "Streaks curling around the centre, as if the camera were rolling. Negative turns the other way.";
ui_min = -1.0; ui_max = 1.0; ui_step = 0.05;
> = 0.0;
static const int TAPS = 24;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_MotionBlur(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float aspect = BUFFER_WIDTH * BUFFER_RCP_HEIGHT;
float2 to_screen = float2(aspect, 1.0);
float2 centred = (uv - 0.5) * to_screen * 2.0;
float2 outward = centred;
float2 around = float2(-centred.y, centred.x);
float radians_angle = Angle * 0.01745329;
float2 sweep = float2(cos(radians_angle), sin(radians_angle));
float2 velocity = sweep * Pan + outward * Zoom + around * Spin;
velocity *= Length * 0.01;
velocity /= to_screen;
float jitter = frac(sin(dot(pos.xy, float2(12.9898, 78.233))) * 43758.5453);
float3 sum = float3(0.0, 0.0, 0.0);
for (int i = 0; i < TAPS; ++i)
{
float t = (float(i) + jitter) / float(TAPS) - 0.5;
sum += tex2D(BackBuffer, uv + velocity * t).rgb;
}
return float4(sum / float(TAPS), 1.0);
}
technique MotionBlur <
ui_label = "Motion Blur";
ui_tooltip = "Camera style motion blur: streaks the picture outwards, sideways or around, without touching still detail at the centre.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_MotionBlur;
}
}
-60
View File
@@ -1,60 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2012 PPSSPP Project
// SPDX-License-Identifier: GPL-2.0-or-later
// Ported from naturalA.fsh in PPSSPP, by ShadX, modified by SimoneT.
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Luma <
ui_type = "slider";
ui_label = "Luma Curve";
ui_tooltip = "Gamma applied to the luminance channel in YIQ space.";
ui_min = 0.5; ui_max = 2.0; ui_step = 0.01;
> = 1.2;
uniform float Chroma <
ui_type = "slider";
ui_label = "Chroma Gain";
ui_tooltip = "Boost applied to the two colour difference channels.";
ui_min = 0.0; ui_max = 2.0; ui_step = 0.01;
> = 1.2;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_Natural(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
const float3x3 RGBtoYIQ = float3x3(0.299, 0.587, 0.114,
0.596, -0.275, -0.321,
0.212, -0.523, 0.311);
const float3x3 YIQtoRGB = float3x3(1.0, 0.95568806, 0.61985809,
1.0, -0.27158180, -0.64687382,
1.0, -1.10817733, 1.70506456);
float3 rgb = tex2D(BackBuffer, uv).rgb;
float3 yiq = mul(RGBtoYIQ, rgb);
yiq.x = pow(max(yiq.x, 0.0), Luma);
yiq.yz *= Chroma;
return float4(saturate(mul(YIQtoRGB, yiq)), 1.0);
}
technique NaturalColors <
ui_label = "Natural Colours";
ui_tooltip = "Warmer and more saturated look. Ported from the PPSSPP shader.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Natural;
}
}
-90
View File
@@ -1,90 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Timer < source = "timer"; > = 0.0;
uniform float Horizon <
ui_type = "slider";
ui_label = "Reflection Line";
ui_tooltip = "Height on screen where the reflective floor begins. Everything above it is left untouched.";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.01;
> = 0.55;
uniform float Amount <
ui_type = "slider";
ui_label = "Amount";
ui_tooltip = "How strongly the reflection shows through the floor.";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
> = 0.35;
uniform float Falloff <
ui_type = "slider";
ui_label = "Falloff";
ui_tooltip = "How quickly the reflection fades as the floor comes towards the viewer. At zero it stays even.";
ui_min = 0.0; ui_max = 4.0; ui_step = 0.1;
> = 1.2;
uniform float Perspective <
ui_type = "slider";
ui_label = "Perspective";
ui_tooltip = "Stretches or squashes the mirrored image. One is a true mirror, higher values pull it towards the line.";
ui_min = 0.2; ui_max = 2.0; ui_step = 0.05;
> = 1.0;
uniform float Ripple <
ui_type = "slider";
ui_label = "Ripple";
ui_tooltip = "Amplitude of the waves disturbing the reflection. At zero the mirror is perfectly still.";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
> = 0.0;
uniform float RippleSpeed <
ui_type = "slider";
ui_label = "Ripple Speed";
ui_tooltip = "How fast the waves travel.";
ui_min = 0.0; ui_max = 4.0; ui_step = 0.1;
> = 1.0;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_Reflections(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float3 color = tex2D(BackBuffer, uv).rgb;
float depth = uv.y - Horizon;
float on_floor = step(0.0, depth);
float span = max(1.0 - Horizon, 0.001);
float distance_down = saturate(depth / span);
float seconds = Timer * 0.001;
float wave = sin(uv.x * 38.0 + seconds * RippleSpeed * 2.0) *
sin(uv.y * 21.0 - seconds * RippleSpeed * 1.3);
float2 disturbance = float2(wave * 0.004, wave * 0.002) * Ripple * distance_down;
float2 mirrored = float2(uv.x, Horizon - depth * Perspective) + disturbance;
float3 reflection = tex2D(BackBuffer, saturate(mirrored)).rgb;
float fade = pow(max(1.0 - distance_down, 0.0001), Falloff);
float strength = Amount * fade * on_floor;
return float4(lerp(color, reflection, strength), 1.0);
}
technique Reflections <
ui_label = "Reflections";
ui_tooltip = "Mirrors the picture into a reflective floor below a line you choose, with optional water ripples.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Reflections;
}
}
-66
View File
@@ -1,66 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2012 PPSSPP Project
// SPDX-License-Identifier: GPL-2.0-or-later
// Ported from scanlines.fsh in PPSSPP.
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Density <
ui_type = "slider";
ui_label = "Line Density";
ui_tooltip = "Number of scanline pairs across the screen.";
ui_min = 60.0; ui_max = 720.0; ui_step = 10.0;
> = 340.0;
uniform float Intensity <
ui_type = "slider";
ui_label = "Intensity";
ui_tooltip = "How dark the gaps between lines become.";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
> = 0.5;
uniform float Tint <
ui_type = "slider";
ui_label = "Phosphor Tint";
ui_tooltip = "Strength of the green-warm phosphor cast.";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
> = 1.0;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_Scanlines(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float line_pos = uv.y * Density * 0.5;
float gate = cos((frac(line_pos) - 0.5) * 3.1415926 * Intensity) * 1.5;
float3 rgb = tex2D(BackBuffer, uv).rgb;
float3 color = rgb * 0.5 + 0.5 * rgb * rgb * 1.2;
float3 phosphor = lerp(float3(1.0, 1.0, 1.0), float3(0.9, 1.0, 0.7), Tint);
color *= phosphor;
float2 diff = uv - 0.5;
color *= 1.1 - 0.6 * (dot(diff, diff) * 2.0);
return float4(saturate(color * saturate(gate)), 1.0);
}
technique Scanlines <
ui_label = "Scanlines";
ui_tooltip = "Horizontal scanlines of a CRT display.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Scanlines;
}
}
-43
View File
@@ -1,43 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Amount <
ui_type = "slider";
ui_label = "Amount";
ui_min = 0.0; ui_max = 3.0; ui_step = 0.01;
> = 0.6;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_Sharpen(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT);
float3 centre = tex2D(BackBuffer, uv).rgb;
float3 blur = tex2D(BackBuffer, uv + float2(-texel.x, 0.0)).rgb;
blur += tex2D(BackBuffer, uv + float2(texel.x, 0.0)).rgb;
blur += tex2D(BackBuffer, uv + float2(0.0, -texel.y)).rgb;
blur += tex2D(BackBuffer, uv + float2(0.0, texel.y)).rgb;
blur *= 0.25;
return float4(centre + (centre - blur) * Amount, 1.0);
}
technique Sharpen <
ui_label = "Sharpen";
ui_tooltip = "Unsharp mask that brings back edge detail lost to scaling.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Sharpen;
}
}
-75
View File
@@ -1,75 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float ShadowHue <
ui_type = "slider";
ui_label = "Shadow Hue";
ui_min = 0.0; ui_max = 360.0; ui_step = 1.0;
> = 210.0;
uniform float ShadowStrength <
ui_type = "slider";
ui_label = "Shadow Strength";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.01;
> = 0.0;
uniform float HighlightHue <
ui_type = "slider";
ui_label = "Highlight Hue";
ui_min = 0.0; ui_max = 360.0; ui_step = 1.0;
> = 45.0;
uniform float HighlightStrength <
ui_type = "slider";
ui_label = "Highlight Strength";
ui_min = 0.0; ui_max = 1.0; ui_step = 0.01;
> = 0.0;
uniform float Balance <
ui_type = "slider";
ui_label = "Balance";
ui_tooltip = "Moves the split between what counts as shadow and what counts as highlight.";
ui_min = -0.5; ui_max = 0.5; ui_step = 0.01;
> = 0.0;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float3 HueToRGB(float hue)
{
float h = frac(hue / 360.0) * 6.0;
return saturate(float3(abs(h - 3.0) - 1.0, 2.0 - abs(h - 2.0), 2.0 - abs(h - 4.0)));
}
float4 PS_SplitToning(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float3 rgb = tex2D(BackBuffer, uv).rgb;
float luma = saturate(dot(rgb, float3(0.2126, 0.7152, 0.0722)) + Balance);
float3 shadow_tint = HueToRGB(ShadowHue) - 0.5;
float3 highlight_tint = HueToRGB(HighlightHue) - 0.5;
rgb += shadow_tint * ShadowStrength * 0.25 * (1.0 - luma);
rgb += highlight_tint * HighlightStrength * 0.25 * luma;
return float4(saturate(rgb), 1.0);
}
technique SplitToning <
ui_label = "Split Toning";
ui_tooltip = "Tints the shadows and the highlights towards two different hues.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_SplitToning;
}
}
-52
View File
@@ -1,52 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2012 PPSSPP Project
// SPDX-License-Identifier: GPL-2.0-or-later
// Ported from vignette.fsh in PPSSPP, by Henrik Rydgard.
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Strength <
ui_type = "slider";
ui_label = "Strength";
ui_tooltip = "How dark the corners become.";
ui_min = 0.0; ui_max = 2.0; ui_step = 0.01;
> = 0.6;
uniform float Aspect <
ui_type = "slider";
ui_label = "Aspect";
ui_min = 0.5; ui_max = 2.0; ui_step = 0.01;
> = 1.0;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float4 PS_Vignette(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float2 diff = uv - 0.5;
diff.x *= Aspect;
diff.y /= max(Aspect, 0.0001);
float falloff = 1.0 - min(1.0, Strength * dot(diff, diff) * 2.0);
float3 rgb = tex2D(BackBuffer, uv).rgb;
return float4(rgb * falloff, 1.0);
}
technique Vignette <
ui_label = "Vignette";
ui_tooltip = "Darkens the corners of the screen.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Vignette;
}
}
-76
View File
@@ -1,76 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
texture BackBufferTex : COLOR;
sampler BackBuffer { Texture = BackBufferTex; };
uniform float Temperature <
ui_type = "slider";
ui_label = "Temperature";
ui_tooltip = "Negative cools the picture towards blue, positive warms it towards orange.";
ui_min = -100.0; ui_max = 100.0; ui_step = 1.0;
> = 0.0;
uniform float Tint <
ui_type = "slider";
ui_label = "Tint";
ui_tooltip = "Negative shifts towards green, positive towards magenta.";
ui_min = -100.0; ui_max = 100.0; ui_step = 1.0;
> = 0.0;
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
{
uv = float2(float(id & 2), float((id & 1) << 1));
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
}
float3 WhitePointLMS(float t1, float t2)
{
float shift = 0.05;
if (t1 < 0.0)
{
shift = 0.10;
}
float x = 0.31271 - t1 * shift;
float y = 2.87 * x - 3.0 * x * x - 0.27509507 + t2 * 0.05;
float big_y = 1.0;
float big_x = big_y * x / y;
float big_z = big_y * (1.0 - x - y) / y;
return float3( 0.7328 * big_x + 0.4296 * big_y - 0.1624 * big_z,
-0.7036 * big_x + 1.6975 * big_y + 0.0061 * big_z,
0.0030 * big_x + 0.0136 * big_y + 0.9834 * big_z);
}
float4 PS_WhiteBalance(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
{
float3 rgb = pow(max(tex2D(BackBuffer, uv).rgb, 0.0), 2.2);
float3 balance = float3(0.949237, 1.03542, 1.08728) /
WhitePointLMS(Temperature / 65.0, Tint / 65.0);
const float3x3 rgb_to_lms = float3x3(0.390405, 0.549941, 0.008926,
0.070841, 0.963172, 0.001358,
0.023108, 0.128021, 0.936245);
const float3x3 lms_to_rgb = float3x3( 2.858470, -1.628790, -0.024891,
-0.210182, 1.158200, 0.000324,
-0.041812, -0.118169, 1.068670);
float3 lms = mul(rgb_to_lms, rgb) * balance;
rgb = mul(lms_to_rgb, lms);
return float4(saturate(pow(max(rgb, 0.0), 1.0 / 2.2)), 1.0);
}
technique WhiteBalance <
ui_label = "White Balance";
ui_tooltip = "Corrects a picture that looks too cool, too warm or tinted.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_WhiteBalance;
}
}
+1 -1
View File
@@ -76,7 +76,7 @@ The following options are desktop only.
- `ENABLE_LIBUSB` (ON) Enable the use of the libusb input backend (HIGHLY RECOMMENDED) - `ENABLE_LIBUSB` (ON) Enable the use of the libusb input backend (HIGHLY RECOMMENDED)
- `ENABLE_OPENGL` (ON) Enable the OpenGL graphics backend - `ENABLE_OPENGL` (ON) Enable the OpenGL graphics backend
- Unavailable on Windows/ARM64 and on Android - Unavailable on Windows/ARM64
- You probably shouldn't turn this off. - You probably shouldn't turn this off.
### Qt ### Qt
-44
View File
@@ -195,50 +195,6 @@ else()
endif() endif()
endif() endif()
# reshadefx
if (ENABLE_RESHADE)
AddJsonPackage(NAME reshade DOWNLOAD_ONLY)
set(RESHADEFX_SHIM_DIR ${CMAKE_CURRENT_BINARY_DIR}/reshadefx_shim)
file(WRITE ${RESHADEFX_SHIM_DIR}/spirv.hpp "#include <spirv/unified1/spirv.hpp>\n")
file(WRITE ${RESHADEFX_SHIM_DIR}/GLSL.std.450.h "#include <spirv/unified1/GLSL.std.450.h>\n")
if (APPLE)
file(WRITE ${RESHADEFX_SHIM_DIR}/malloc.h "#include <stdlib.h>\n#include <alloca.h>\n")
endif()
add_library(reshadefx STATIC
${reshade_SOURCE_DIR}/source/effect_codegen_spirv.cpp
${reshade_SOURCE_DIR}/source/effect_expression.cpp
${reshade_SOURCE_DIR}/source/effect_lexer.cpp
${reshade_SOURCE_DIR}/source/effect_parser_exp.cpp
${reshade_SOURCE_DIR}/source/effect_parser_stmt.cpp
${reshade_SOURCE_DIR}/source/effect_preprocessor.cpp
${reshade_SOURCE_DIR}/source/effect_symbol_table.cpp
)
target_include_directories(reshadefx SYSTEM PUBLIC ${reshade_SOURCE_DIR}/source)
target_include_directories(reshadefx PRIVATE ${RESHADEFX_SHIM_DIR})
target_link_libraries(reshadefx PUBLIC SPIRV-Headers::SPIRV-Headers)
if (NOT MSVC)
target_compile_options(reshadefx PRIVATE -w -fno-char8_t)
else()
target_compile_options(reshadefx PRIVATE /w /Zc:char8_t-)
endif()
if (WIN32)
if (NOT MSVC)
target_compile_options(reshadefx PRIVATE -include share.h)
else()
target_compile_options(reshadefx PRIVATE /FIshare.h)
endif()
endif()
if (NOT TARGET reshadefx::reshadefx)
add_library(reshadefx::reshadefx ALIAS reshadefx)
endif()
endif()
# Catch2 # Catch2
if (YUZU_TESTS OR DYNARMIC_TESTS) if (YUZU_TESTS OR DYNARMIC_TESTS)
AddJsonPackage(catch2) AddJsonPackage(catch2)
-1
View File
@@ -11,7 +11,6 @@
#include <limits> #include <limits>
#include <span> #include <span>
#include <array> #include <array>
#include <algorithm>
#include <time.h> #include <time.h>
namespace Tz { namespace Tz {
@@ -18,7 +18,6 @@ import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
import org.yuzu.yuzu_emu.features.settings.model.IntSetting import org.yuzu.yuzu_emu.features.settings.model.IntSetting
import org.yuzu.yuzu_emu.fragments.EmulationFragment import org.yuzu.yuzu_emu.fragments.EmulationFragment
import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.NativePostProcessing
import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting
import org.yuzu.yuzu_emu.features.settings.model.AbstractShortSetting import org.yuzu.yuzu_emu.features.settings.model.AbstractShortSetting
import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting
@@ -233,250 +232,6 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
container.addView(itemView) container.addView(itemView)
} }
fun addChoice(
title: String,
container: ViewGroup,
choices: List<String>,
selectedIndex: Int,
onSelected: (Int) -> Unit
) {
val inflater = LayoutInflater.from(emulationFragment.requireContext())
val itemView = inflater.inflate(R.layout.item_quick_settings_menu, container, false)
val headerView = itemView.findViewById<ViewGroup>(R.id.setting_header)
val titleView = itemView.findViewById<TextView>(R.id.setting_title)
val valueView = itemView.findViewById<TextView>(R.id.setting_value)
val expandIcon = itemView.findViewById<android.widget.ImageView>(R.id.expand_icon)
val radioGroup = itemView.findViewById<RadioGroup>(R.id.radio_group)
titleView.text = title
var current = ""
if (selectedIndex in choices.indices) {
current = choices[selectedIndex]
}
valueView.text = current
headerView.visibility = View.VISIBLE
var isExpanded = false
choices.forEachIndexed { index, name ->
val radioButton = com.google.android.material.radiobutton.MaterialRadioButton(
emulationFragment.requireContext()
)
radioButton.text = name
radioButton.id = View.generateViewId()
radioButton.isChecked = index == selectedIndex
radioButton.setPadding(16, 8, 16, 8)
radioButton.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
valueView.text = name
onSelected(index)
}
}
radioGroup.addView(radioButton)
}
headerView.setOnClickListener {
isExpanded = !isExpanded
if (isExpanded) {
radioGroup.visibility = View.VISIBLE
expandIcon.animate().rotation(180f).setDuration(200).start()
} else {
radioGroup.visibility = View.GONE
expandIcon.animate().rotation(0f).setDuration(200).start()
}
}
container.addView(itemView)
}
fun addStepSlider(
title: String,
container: ViewGroup,
steps: Int,
selectedStep: Int,
describe: (Int) -> String,
onChanged: (Int) -> Unit
) {
val inflater = LayoutInflater.from(emulationFragment.requireContext())
val itemView = inflater.inflate(R.layout.item_quick_settings_menu, container, false)
val sliderContainer = itemView.findViewById<ViewGroup>(R.id.slider_container)
val titleView = itemView.findViewById<TextView>(R.id.slider_title)
val valueDisplay = itemView.findViewById<TextView>(R.id.slider_value_display)
val slider = itemView.findViewById<com.google.android.material.slider.Slider>(
R.id.setting_slider
)
titleView.text = title
sliderContainer.visibility = View.VISIBLE
slider.valueFrom = 0f
slider.valueTo = steps.toFloat()
slider.stepSize = 1f
slider.value = selectedStep.toFloat().coerceIn(0f, steps.toFloat())
valueDisplay.text = describe(slider.value.toInt())
slider.addOnChangeListener { _, value, fromUser ->
if (fromUser) {
val step = value.toInt()
onChanged(step)
valueDisplay.text = describe(step)
}
}
slider.setOnTouchListener { _, event ->
val drawer = emulationFragment.view?.findViewById<DrawerLayout>(R.id.drawer_layout)
when (event.action) {
MotionEvent.ACTION_DOWN -> {
drawer?.requestDisallowInterceptTouchEvent(true)
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
drawer?.requestDisallowInterceptTouchEvent(false)
}
}
false
}
container.addView(itemView)
}
fun addPostProcessing(container: ViewGroup, onStructureChanged: () -> Unit) {
val usable = NativePostProcessing.catalog().filter { it.valid }
if (usable.isEmpty()) {
return
}
val labels = mutableListOf(
YuzuApplication.appContext.getString(R.string.post_processing_none)
)
val files = mutableListOf("")
val techniques = mutableListOf("")
for (effect in usable) {
for (technique in effect.techniques) {
var label = effect.label
if (effect.techniques.size > 1) {
label = effect.label + " \u00b7 " + technique
}
labels.add(label)
files.add(effect.file)
techniques.add(technique)
}
}
addDivider(container)
val chain = NativePostProcessing.chain()
for (index in 0..chain.size) {
var selected = 0
var effect: NativePostProcessing.Effect? = null
if (index < chain.size) {
val entry = chain[index]
effect = usable.firstOrNull { it.file == entry.file }
for (i in files.indices) {
if (files[i] == entry.file && techniques[i] == entry.technique) {
selected = i
}
}
}
var title = YuzuApplication.appContext.getString(R.string.post_processing_add)
if (index < chain.size) {
title = YuzuApplication.appContext.getString(R.string.post_processing_effect)
}
addChoice(title, container, labels, selected) { picked ->
applyEffectPick(index, picked, files, techniques, chain.size)
onStructureChanged()
}
if (effect != null) {
for (uniform in effect.uniforms) {
addUniformSliders(container, index, uniform)
}
}
}
}
private fun applyEffectPick(
index: Int,
picked: Int,
files: List<String>,
techniques: List<String>,
chainSize: Int
) {
if (index >= chainSize) {
if (picked > 0) {
NativePostProcessing.append(files[picked], techniques[picked])
NativePostProcessing.persist()
}
return
}
if (picked == 0) {
NativePostProcessing.remove(index)
NativePostProcessing.persist()
return
}
NativePostProcessing.replace(index, files[picked], techniques[picked])
NativePostProcessing.persist()
}
private fun addUniformSliders(
container: ViewGroup,
index: Int,
uniform: NativePostProcessing.Uniform
) {
if (uniform.uiType == NativePostProcessing.UI_HIDDEN) {
return
}
for (component in 0 until uniform.components) {
var title = uniform.label
if (uniform.components > 1) {
title = uniform.label + " [" + component + "]"
}
var value = uniform.defaultAt(component)
if (NativePostProcessing.hasValue(index, uniform.name)) {
value = NativePostProcessing.getValue(index, uniform.name, component)
}
val steps = uniform.steps
val step = Math.round((value - uniform.min) / uniform.step)
addStepSlider(
title,
container,
steps,
step,
{ position -> describeUniform(uniform, position) }
) { position ->
NativePostProcessing.setValue(
index,
uniform.name,
component,
uniform.min + position * uniform.step
)
NativePostProcessing.persist()
}
}
}
private fun describeUniform(
uniform: NativePostProcessing.Uniform,
position: Int
): String {
val value = uniform.min + position * uniform.step
if (uniform.kind == NativePostProcessing.KIND_FLOAT) {
return String.format("%.3f", value)
}
return Math.round(value).toString()
}
fun addDivider(container: ViewGroup) { fun addDivider(container: ViewGroup) {
val inflater = LayoutInflater.from(emulationFragment.requireContext()) val inflater = LayoutInflater.from(emulationFragment.requireContext())
val dividerView = inflater.inflate(R.layout.item_quick_settings_divider, container, false) val dividerView = inflater.inflate(R.layout.item_quick_settings_divider, container, false)
@@ -83,7 +83,6 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
SHOW_SHADERS_BUILDING("show_shaders_building"), SHOW_SHADERS_BUILDING("show_shaders_building"),
DEBUG_FLUSH_BY_LINE("flush_line"), DEBUG_FLUSH_BY_LINE("flush_line"),
EXTENDED_LOGGING("extended_logging"),
DONT_SHOW_DRIVER_SHADER_WARNING("dont_show_driver_shader_warning"), DONT_SHOW_DRIVER_SHADER_WARNING("dont_show_driver_shader_warning"),
ENABLE_OVERLAY("enable_overlay"), ENABLE_OVERLAY("enable_overlay"),
@@ -1,103 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.features.settings.model
import org.yuzu.yuzu_emu.utils.NativePostProcessing
import kotlin.math.roundToInt
abstract class FxUniformSetting(
protected val index: Int,
protected val uniform: NativePostProcessing.Uniform,
protected val component: Int
) : AbstractSetting {
override val key: String
get() = "fx_${index}_${uniform.name}_$component"
override val isRuntimeModifiable: Boolean
get() = true
override val pairedSettingKey: String
get() = ""
override val isSwitchable: Boolean
get() = false
override val isSaveable: Boolean
get() = true
override var global: Boolean
get() = true
set(_) {}
protected fun currentValue(): Float {
if (NativePostProcessing.hasValue(index, uniform.name)) {
return NativePostProcessing.getValue(index, uniform.name, component)
}
return uniform.defaultAt(component)
}
protected fun commit(value: Float) {
NativePostProcessing.setValue(index, uniform.name, component, value)
NativePostProcessing.persist()
}
override fun reset() = commit(uniform.defaultAt(component))
}
class FxUniformSliderSetting(
index: Int,
uniform: NativePostProcessing.Uniform,
component: Int
) : FxUniformSetting(index, uniform, component), AbstractIntSetting {
override val defaultValue: Any
get() = ((uniform.defaultAt(component) - uniform.min) / uniform.step).roundToInt()
override fun getInt(needsGlobal: Boolean): Int =
((currentValue() - uniform.min) / uniform.step).roundToInt()
override fun setInt(value: Int) = commit(uniform.min + value * uniform.step)
override fun getValueAsString(needsGlobal: Boolean): String {
if (uniform.kind == NativePostProcessing.KIND_FLOAT) {
return String.format("%.3f", currentValue())
}
return currentValue().roundToInt().toString()
}
}
class FxUniformChoiceSetting(
index: Int,
uniform: NativePostProcessing.Uniform,
component: Int
) : FxUniformSetting(index, uniform, component), AbstractIntSetting {
override val defaultValue: Any
get() = uniform.defaultAt(component).roundToInt()
override fun getInt(needsGlobal: Boolean): Int = currentValue().roundToInt()
override fun setInt(value: Int) = commit(value.toFloat())
override fun getValueAsString(needsGlobal: Boolean): String = getInt().toString()
}
class FxUniformBooleanSetting(
index: Int,
uniform: NativePostProcessing.Uniform,
component: Int
) : FxUniformSetting(index, uniform, component), AbstractBooleanSetting {
override val defaultValue: Any
get() = uniform.defaultAt(component) != 0f
override fun getBoolean(needsGlobal: Boolean): Boolean = currentValue() != 0f
override fun setBoolean(value: Boolean) {
if (value) {
commit(1f)
return
}
commit(0f)
}
override fun getValueAsString(needsGlobal: Boolean): String = getBoolean().toString()
}
@@ -12,7 +12,6 @@ object Settings {
SECTION_SYSTEM(R.string.preferences_system), SECTION_SYSTEM(R.string.preferences_system),
SECTION_RENDERER(R.string.preferences_graphics), SECTION_RENDERER(R.string.preferences_graphics),
SECTION_FRAME_GEN(R.string.frame_gen), SECTION_FRAME_GEN(R.string.frame_gen),
SECTION_POST_PROCESSING(R.string.post_processing),
SECTION_PERFORMANCE_STATS(R.string.stats_overlay_options), SECTION_PERFORMANCE_STATS(R.string.stats_overlay_options),
SECTION_INPUT_OVERLAY(R.string.input_overlay_options), SECTION_INPUT_OVERLAY(R.string.input_overlay_options),
SECTION_SOC_OVERLAY(R.string.soc_overlay_options), SECTION_SOC_OVERLAY(R.string.soc_overlay_options),
@@ -13,7 +13,6 @@ enum class StringSetting(override val key: String) : AbstractStringSetting {
DEVICE_NAME("device_name"), DEVICE_NAME("device_name"),
LOG_FILTER("log_filter"), LOG_FILTER("log_filter"),
PROGRAM_ARGS("program_args"), PROGRAM_ARGS("program_args"),
POST_SHADER_CHAIN("post_shader_chain"),
WEB_TOKEN("eden_token"), WEB_TOKEN("eden_token"),
WEB_USERNAME("eden_username") WEB_USERNAME("eden_username")
@@ -262,13 +262,6 @@ abstract class SettingsItem(
descriptionId = R.string.flush_by_line_description descriptionId = R.string.flush_by_line_description
) )
) )
put(
SwitchSetting(
BooleanSetting.EXTENDED_LOGGING,
titleId = R.string.extended_logging,
descriptionId = R.string.extended_logging_description
)
)
val dockedModeSetting = object : AbstractBooleanSetting { val dockedModeSetting = object : AbstractBooleanSetting {
override val key = BooleanSetting.USE_DOCKED_MODE.key override val key = BooleanSetting.USE_DOCKED_MODE.key
@@ -18,9 +18,6 @@ import org.yuzu.yuzu_emu.features.input.model.NpadStyleIndex
import org.yuzu.yuzu_emu.features.settings.model.AbstractBooleanSetting import org.yuzu.yuzu_emu.features.settings.model.AbstractBooleanSetting
import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
import org.yuzu.yuzu_emu.features.settings.model.FxUniformBooleanSetting
import org.yuzu.yuzu_emu.features.settings.model.FxUniformChoiceSetting
import org.yuzu.yuzu_emu.features.settings.model.FxUniformSliderSetting
import org.yuzu.yuzu_emu.features.settings.model.ByteSetting import org.yuzu.yuzu_emu.features.settings.model.ByteSetting
import org.yuzu.yuzu_emu.features.settings.model.IntSetting import org.yuzu.yuzu_emu.features.settings.model.IntSetting
import org.yuzu.yuzu_emu.features.settings.model.LongSetting import org.yuzu.yuzu_emu.features.settings.model.LongSetting
@@ -33,7 +30,6 @@ import org.yuzu.yuzu_emu.features.settings.model.view.*
import org.yuzu.yuzu_emu.utils.InputHandler import org.yuzu.yuzu_emu.utils.InputHandler
import org.yuzu.yuzu_emu.utils.LosslessScalingHelper import org.yuzu.yuzu_emu.utils.LosslessScalingHelper
import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.NativePostProcessing
import org.yuzu.yuzu_emu.utils.DirectoryInitialization import org.yuzu.yuzu_emu.utils.DirectoryInitialization
import org.yuzu.yuzu_emu.utils.FullscreenHelper import org.yuzu.yuzu_emu.utils.FullscreenHelper
import androidx.core.content.edit import androidx.core.content.edit
@@ -167,7 +163,6 @@ class SettingsFragmentPresenter(
MenuTag.SECTION_SYSTEM -> addSystemSettings(sl) MenuTag.SECTION_SYSTEM -> addSystemSettings(sl)
MenuTag.SECTION_RENDERER -> addGraphicsSettings(sl) MenuTag.SECTION_RENDERER -> addGraphicsSettings(sl)
MenuTag.SECTION_FRAME_GEN -> addFrameGenSettings(sl) MenuTag.SECTION_FRAME_GEN -> addFrameGenSettings(sl)
MenuTag.SECTION_POST_PROCESSING -> addPostProcessingSettings(sl)
MenuTag.SECTION_PERFORMANCE_STATS -> addPerformanceOverlaySettings(sl) MenuTag.SECTION_PERFORMANCE_STATS -> addPerformanceOverlaySettings(sl)
MenuTag.SECTION_SOC_OVERLAY -> addSocOverlaySettings(sl) MenuTag.SECTION_SOC_OVERLAY -> addSocOverlaySettings(sl)
MenuTag.SECTION_INPUT_OVERLAY -> addInputOverlaySettings(sl) MenuTag.SECTION_INPUT_OVERLAY -> addInputOverlaySettings(sl)
@@ -195,211 +190,6 @@ class SettingsFragmentPresenter(
} }
} }
private fun addPostProcessingSettings(sl: ArrayList<SettingsItem>) {
val usable = NativePostProcessing.catalog().filter { it.valid }
sl.apply {
if (usable.isEmpty()) {
add(
RunnableSetting(
titleId = R.string.post_processing_empty,
descriptionString = NativePostProcessing.getShaderDirectory(),
isRunnable = false
) {}
)
return@apply
}
val labels = mutableListOf<String>()
val files = mutableListOf<String>()
val techniques = mutableListOf<String>()
for (effect in usable) {
for (technique in effect.techniques) {
if (effect.techniques.size == 1) {
labels.add(effect.label)
} else {
labels.add(effect.label + " \u00b7 " + technique)
}
files.add(effect.file)
techniques.add(technique)
}
}
val chain = NativePostProcessing.chain()
for (index in chain.indices) {
val entry = chain[index]
val effect = usable.firstOrNull { it.file == entry.file }
var header = entry.file
var summary = ""
if (effect != null) {
header = effect.label
summary = effect.description
}
add(HeaderSetting(titleString = header))
add(
IntSingleChoiceSetting(
buildSlotSelector(index, entry, files, techniques),
titleId = R.string.post_processing_effect,
descriptionString = summary,
choices = labels.toTypedArray(),
values = labels.indices.toList().toTypedArray()
)
)
if (effect != null) {
for (uniform in effect.uniforms) {
addUniform(this, index, uniform)
}
}
if (index > 0) {
add(
RunnableSetting(
titleId = R.string.post_processing_move_up,
isRunnable = true
) {
NativePostProcessing.move(index, -1)
NativePostProcessing.persist()
settingsViewModel.setReloadListAndNotifyDataset(true)
}
)
}
if (index < chain.size - 1) {
add(
RunnableSetting(
titleId = R.string.post_processing_move_down,
isRunnable = true
) {
NativePostProcessing.move(index, 1)
NativePostProcessing.persist()
settingsViewModel.setReloadListAndNotifyDataset(true)
}
)
}
add(
RunnableSetting(
titleId = R.string.post_processing_reset,
isRunnable = true
) {
NativePostProcessing.resetValues(index)
NativePostProcessing.persist()
settingsViewModel.setReloadListAndNotifyDataset(true)
}
)
add(
RunnableSetting(
titleId = R.string.post_processing_remove,
isRunnable = true
) {
NativePostProcessing.remove(index)
NativePostProcessing.persist()
settingsViewModel.setReloadListAndNotifyDataset(true)
}
)
}
add(
RunnableSetting(
titleId = R.string.post_processing_add,
isRunnable = true
) {
NativePostProcessing.append(files[0], techniques[0])
NativePostProcessing.persist()
settingsViewModel.setReloadListAndNotifyDataset(true)
}
)
}
}
private fun buildSlotSelector(
index: Int,
entry: NativePostProcessing.ChainEntry,
files: List<String>,
techniques: List<String>
): AbstractIntSetting = object : AbstractIntSetting {
override val key = "fx_slot_$index"
override fun getInt(needsGlobal: Boolean): Int {
for (i in files.indices) {
if (files[i] == entry.file && techniques[i] == entry.technique) {
return i
}
}
return -1
}
override fun setInt(value: Int) {
NativePostProcessing.replace(index, files[value], techniques[value])
NativePostProcessing.persist()
settingsViewModel.setReloadListAndNotifyDataset(true)
}
override val defaultValue = 0
override fun getValueAsString(needsGlobal: Boolean): String = getInt().toString()
override fun reset() {}
override val isRuntimeModifiable = true
override val pairedSettingKey = ""
override val isSwitchable = false
override val isSaveable = true
override var global: Boolean
get() = true
set(_) {}
}
private fun addUniform(
sl: ArrayList<SettingsItem>,
index: Int,
uniform: NativePostProcessing.Uniform
) {
if (uniform.uiType == NativePostProcessing.UI_CHECKBOX ||
uniform.kind == NativePostProcessing.KIND_BOOL
) {
sl.add(
SwitchSetting(
FxUniformBooleanSetting(index, uniform, 0),
titleString = uniform.label,
descriptionString = uniform.tooltip
)
)
return
}
if (uniform.items.isNotEmpty() &&
(uniform.uiType == NativePostProcessing.UI_COMBO ||
uniform.uiType == NativePostProcessing.UI_RADIO)
) {
sl.add(
IntSingleChoiceSetting(
FxUniformChoiceSetting(index, uniform, 0),
titleString = uniform.label,
descriptionString = uniform.tooltip,
choices = uniform.items.toTypedArray(),
values = uniform.items.indices.toList().toTypedArray()
)
)
return
}
for (component in 0 until uniform.components) {
var title = uniform.label
if (uniform.components > 1) {
title = uniform.label + " [" + component + "]"
}
sl.add(
SliderSetting(
FxUniformSliderSetting(index, uniform, component),
titleString = title,
descriptionString = uniform.tooltip,
min = 0,
max = uniform.steps
)
)
}
}
private fun addConfigSettings(sl: ArrayList<SettingsItem>) { private fun addConfigSettings(sl: ArrayList<SettingsItem>) {
sl.apply { sl.apply {
add( add(
@@ -1533,7 +1323,6 @@ class SettingsFragmentPresenter(
add(HeaderSetting(R.string.log)) add(HeaderSetting(R.string.log))
add(BooleanSetting.DEBUG_FLUSH_BY_LINE.key) add(BooleanSetting.DEBUG_FLUSH_BY_LINE.key)
add(BooleanSetting.EXTENDED_LOGGING.key)
add(StringSetting.LOG_FILTER.key) add(StringSetting.LOG_FILTER.key)
} }
@@ -1194,10 +1194,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
R.array.rendererAntiAliasingNames, R.array.rendererAntiAliasingNames,
R.array.rendererAntiAliasingValues R.array.rendererAntiAliasingValues
) )
quickSettings.addPostProcessing(container) {
addQuickSettings()
}
} }
} }
@@ -383,20 +383,6 @@ class GamePropertiesFragment : Fragment() {
} }
) )
) )
add(
SubmenuProperty(
R.string.post_processing,
R.string.post_processing_per_game_description,
R.drawable.ic_post_processing,
action = {
val action = HomeNavigationDirections.actionGlobalSettingsActivity(
args.game,
Settings.MenuTag.SECTION_POST_PROCESSING
)
binding.root.findNavController().navigate(action)
}
)
)
if (GpuDriverHelper.isAdrenoGpu()) { if (GpuDriverHelper.isAdrenoGpu()) {
add( add(
@@ -171,20 +171,6 @@ class HomeSettingsFragment : Fragment() {
) )
) )
} }
add(
HomeSetting(
R.string.post_processing,
R.string.post_processing_description,
R.drawable.ic_post_processing,
{
val action = HomeNavigationDirections.actionGlobalSettingsActivity(
null,
Settings.MenuTag.SECTION_POST_PROCESSING
)
binding.root.findNavController().navigate(action)
}
)
)
add( add(
HomeSetting( HomeSetting(
R.string.lossless_scaling, R.string.lossless_scaling,
@@ -1,183 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.utils
import org.json.JSONArray
import org.json.JSONObject
object NativePostProcessing {
const val KIND_BOOL = 0
const val KIND_INT = 1
const val KIND_FLOAT = 2
const val UI_HIDDEN = 0
const val UI_SLIDER = 1
const val UI_DRAG = 2
const val UI_COMBO = 3
const val UI_RADIO = 4
const val UI_CHECKBOX = 5
const val UI_COLOR = 6
const val UI_INPUT_BOX = 7
external fun getCatalogJson(): String
external fun getChainJson(): String
external fun append(file: String, technique: String)
external fun replace(index: Int, file: String, technique: String)
external fun remove(index: Int)
external fun move(index: Int, delta: Int)
external fun resetValues(index: Int)
external fun getValue(index: Int, uniform: String, component: Int): Float
external fun hasValue(index: Int, uniform: String): Boolean
external fun setValue(index: Int, uniform: String, component: Int, value: Float)
external fun store()
fun persist() {
store()
NativeConfig.saveGlobalConfig()
}
external fun getShaderDirectory(): String
data class Uniform(
val name: String,
val label: String,
val tooltip: String,
val category: String,
val kind: Int,
val uiType: Int,
val components: Int,
val min: Float,
val max: Float,
val step: Float,
val items: List<String>,
val defaults: List<Float>
) {
val steps: Int
get() {
val span = max - min
if (step <= 0f) {
return 1
}
val count = Math.round(span / step)
if (count < 1) {
return 1
}
return count
}
fun defaultAt(component: Int): Float {
if (component < defaults.size) {
return defaults[component]
}
return 0f
}
}
data class Effect(
val file: String,
val name: String,
val label: String,
val description: String,
val error: String,
val techniques: List<String>,
val uniforms: List<Uniform>
) {
val valid: Boolean
get() = error.isEmpty() && techniques.isNotEmpty()
}
data class ChainEntry(val file: String, val technique: String)
fun catalog(): List<Effect> {
val out = mutableListOf<Effect>()
val array = JSONArray(getCatalogJson())
for (i in 0 until array.length()) {
val obj = array.getJSONObject(i)
out.add(
Effect(
file = obj.optString("file"),
name = obj.optString("name"),
label = obj.optString("label"),
description = obj.optString("description"),
error = obj.optString("error"),
techniques = obj.optJSONArray("techniques").toStringList(),
uniforms = obj.optJSONArray("uniforms").toUniformList()
)
)
}
return out
}
fun chain(): List<ChainEntry> {
val out = mutableListOf<ChainEntry>()
val array = JSONArray(getChainJson())
for (i in 0 until array.length()) {
val obj = array.getJSONObject(i)
out.add(ChainEntry(obj.optString("file"), obj.optString("technique")))
}
return out
}
fun findEffect(file: String): Effect? = catalog().firstOrNull { it.file == file }
private fun JSONArray?.toStringList(): List<String> {
if (this == null) {
return emptyList()
}
val out = mutableListOf<String>()
for (i in 0 until length()) {
out.add(optString(i))
}
return out
}
private fun JSONArray?.toFloatList(): List<Float> {
if (this == null) {
return emptyList()
}
val out = mutableListOf<Float>()
for (i in 0 until length()) {
out.add(optDouble(i, 0.0).toFloat())
}
return out
}
private fun JSONArray?.toUniformList(): List<Uniform> {
if (this == null) {
return emptyList()
}
val out = mutableListOf<Uniform>()
for (i in 0 until length()) {
val obj: JSONObject = optJSONObject(i) ?: continue
out.add(
Uniform(
name = obj.optString("name"),
label = obj.optString("label"),
tooltip = obj.optString("tooltip"),
category = obj.optString("category"),
kind = obj.optInt("kind", KIND_FLOAT),
uiType = obj.optInt("uiType", UI_HIDDEN),
components = obj.optInt("components", 1),
min = obj.optDouble("min", 0.0).toFloat(),
max = obj.optDouble("max", 1.0).toFloat(),
step = obj.optDouble("step", 0.01).toFloat(),
items = obj.optJSONArray("items").toStringList(),
defaults = obj.optJSONArray("defaults").toFloatList()
)
)
}
return out
}
}
@@ -17,7 +17,6 @@ add_library(yuzu-android SHARED
android_config.cpp android_config.cpp
android_config.h android_config.h
native_input.cpp native_input.cpp
native_post_processing.cpp
) )
set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR}) set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR})
@@ -1,215 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <array>
#include <string>
#include <jni.h>
#include <nlohmann/json.hpp>
#include "common/android/android_common.h"
#ifdef HAS_RESHADE
#include "video_core/post_processing/fx_chain.h"
#include "video_core/post_processing/fx_effect.h"
#endif
namespace {
#ifdef HAS_RESHADE
nlohmann::json SerializeUniform(const VideoCore::FxUniformDesc& uniform) {
nlohmann::json out;
out["name"] = uniform.name;
out["label"] = uniform.label;
out["tooltip"] = uniform.tooltip;
out["category"] = uniform.category;
out["kind"] = static_cast<int>(uniform.kind);
out["uiType"] = static_cast<int>(uniform.ui_type);
out["components"] = uniform.components;
out["min"] = uniform.ui_min;
out["max"] = uniform.ui_max;
out["step"] = uniform.ui_step;
out["items"] = uniform.items;
nlohmann::json defaults = nlohmann::json::array();
for (u32 i = 0; i < uniform.components; ++i) {
defaults.push_back(uniform.default_value[i]);
}
out["defaults"] = defaults;
return out;
}
std::array<f32, 4> DefaultValueOf(size_t index, const std::string& uniform) {
const auto entries = VideoCore::FxChain::Instance().Entries();
if (index >= entries.size()) {
return {};
}
const VideoCore::FxEffectDesc* effect = VideoCore::FindFxEffect(entries[index].file);
if (effect == nullptr) {
return {};
}
const VideoCore::FxUniformDesc* desc = VideoCore::FindFxUniform(*effect, uniform);
if (desc == nullptr) {
return {};
}
return desc->default_value;
}
#endif
} // Anonymous namespace
extern "C" {
jstring Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_getCatalogJson(JNIEnv* env,
jobject obj) {
nlohmann::json out = nlohmann::json::array();
#ifdef HAS_RESHADE
VideoCore::FxChain::Instance().DropUnknownEntries();
for (const auto& effect : VideoCore::GetFxCatalog()) {
nlohmann::json entry;
entry["file"] = effect.file;
entry["name"] = effect.name;
entry["label"] = effect.label;
entry["description"] = effect.description;
entry["error"] = effect.error;
entry["techniques"] = effect.techniques;
nlohmann::json uniforms = nlohmann::json::array();
for (const auto& uniform : effect.uniforms) {
uniforms.push_back(SerializeUniform(uniform));
}
entry["uniforms"] = uniforms;
out.push_back(entry);
}
#endif
return Common::Android::ToJString(env, out.dump());
}
jstring Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_getChainJson(JNIEnv* env, jobject obj) {
nlohmann::json out = nlohmann::json::array();
#ifdef HAS_RESHADE
for (const auto& entry : VideoCore::FxChain::Instance().Entries()) {
nlohmann::json item;
item["file"] = entry.file;
item["technique"] = entry.technique;
nlohmann::json values = nlohmann::json::object();
for (const auto& [name, value] : entry.values) {
values[name] = {value[0], value[1], value[2], value[3]};
}
item["values"] = values;
out.push_back(item);
}
#endif
return Common::Android::ToJString(env, out.dump());
}
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_append(JNIEnv* env, jobject obj,
jstring jfile, jstring jtechnique) {
#ifdef HAS_RESHADE
VideoCore::FxChain::Instance().Append(Common::Android::GetJString(env, jfile),
Common::Android::GetJString(env, jtechnique));
#endif
}
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_replace(JNIEnv* env, jobject obj,
jint index, jstring jfile,
jstring jtechnique) {
#ifdef HAS_RESHADE
VideoCore::FxChain::Instance().Replace(static_cast<size_t>(index),
Common::Android::GetJString(env, jfile),
Common::Android::GetJString(env, jtechnique));
#endif
}
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_remove(JNIEnv* env, jobject obj,
jint index) {
#ifdef HAS_RESHADE
VideoCore::FxChain::Instance().Remove(static_cast<size_t>(index));
#endif
}
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_move(JNIEnv* env, jobject obj, jint index,
jint delta) {
#ifdef HAS_RESHADE
VideoCore::FxChain::Instance().Move(static_cast<size_t>(index), delta);
#endif
}
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_resetValues(JNIEnv* env, jobject obj,
jint index) {
#ifdef HAS_RESHADE
VideoCore::FxChain::Instance().ResetValues(static_cast<size_t>(index));
#endif
}
jfloat Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_getValue(JNIEnv* env, jobject obj,
jint index, jstring juniform,
jint component) {
#ifdef HAS_RESHADE
if (component < 0 || component >= 4) {
return 0.0f;
}
const auto value = VideoCore::FxChain::Instance().GetValue(
static_cast<size_t>(index), Common::Android::GetJString(env, juniform));
return value[static_cast<size_t>(component)];
#else
return 0.0f;
#endif
}
jboolean Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_hasValue(JNIEnv* env, jobject obj,
jint index,
jstring juniform) {
#ifdef HAS_RESHADE
return static_cast<jboolean>(VideoCore::FxChain::Instance().HasValue(
static_cast<size_t>(index), Common::Android::GetJString(env, juniform)));
#else
return static_cast<jboolean>(false);
#endif
}
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_setValue(JNIEnv* env, jobject obj,
jint index, jstring juniform,
jint component, jfloat value) {
#ifdef HAS_RESHADE
if (component < 0 || component >= 4) {
return;
}
const std::string uniform = Common::Android::GetJString(env, juniform);
auto& chain = VideoCore::FxChain::Instance();
const auto slot = static_cast<size_t>(index);
auto current = chain.GetValue(slot, uniform);
if (!chain.HasValue(slot, uniform)) {
current = DefaultValueOf(slot, uniform);
}
current[static_cast<size_t>(component)] = value;
chain.SetValue(slot, uniform, current);
#endif
}
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_store(JNIEnv* env, jobject obj) {
#ifdef HAS_RESHADE
VideoCore::FxChain::Instance().StoreToSettings();
#endif
}
jstring Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_getShaderDirectory(JNIEnv* env,
jobject obj) {
#ifdef HAS_RESHADE
return Common::Android::ToJString(env, VideoCore::GetFxRootDirectory().string());
#else
return Common::Android::ToJString(env, "");
#endif
}
} // extern "C"
@@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/colorControlNormal"
android:fillType="evenOdd"
android:pathData="M8.5,3 L19.4,3 Q21,3 21,4.6 L21,16.5 L19.4,16.5 L19.4,4.6 L8.5,4.6 Z M5,7 L15,7 Q17,7 17,9 L17,19 Q17,21 15,21 L5,21 Q3,21 3,19 L3,9 Q3,7 5,7 Z M5.2,8.6 L14.8,8.6 Q15.4,8.6 15.4,9.2 L15.4,18.8 Q15.4,19.4 14.8,19.4 L5.2,19.4 Q4.6,19.4 4.6,18.8 L4.6,9.2 Q4.6,8.6 5.2,8.6 Z M10,10.9 A3.1,3.1 0 0 1 10,17.1 Z"/>
</vector>
@@ -298,17 +298,6 @@
<string name="gpu_driver_fetcher">GPU driver fetcher</string> <string name="gpu_driver_fetcher">GPU driver fetcher</string>
<string name="gpu_driver_manager">GPU driver manager</string> <string name="gpu_driver_manager">GPU driver manager</string>
<string name="install_gpu_driver_description">Install alternative drivers for potentially better performance or accuracy</string> <string name="install_gpu_driver_description">Install alternative drivers for potentially better performance or accuracy</string>
<string name="post_processing">Post-Processing Effects</string>
<string name="post_processing_description">ReShade FX effects applied after rendering</string>
<string name="post_processing_per_game_description">Configure the effect chain for this game</string>
<string name="post_processing_effect">Effect</string>
<string name="post_processing_none">None</string>
<string name="post_processing_add">Add effect</string>
<string name="post_processing_remove">Remove</string>
<string name="post_processing_move_up">Move up</string>
<string name="post_processing_move_down">Move down</string>
<string name="post_processing_reset">Reset to defaults</string>
<string name="post_processing_empty">No effects found. Place .fx files in this folder:</string>
<string name="frame_gen">Frame generation</string> <string name="frame_gen">Frame generation</string>
<string name="frame_gen_per_game_description">Configure frame generation for this game</string> <string name="frame_gen_per_game_description">Configure frame generation for this game</string>
<string name="frame_gen_description">Insert interpolated frames between rendered ones using Lossless Scaling. Forces FIFO presentation while enabled.</string> <string name="frame_gen_description">Insert interpolated frames between rendered ones using Lossless Scaling. Forces FIFO presentation while enabled.</string>
@@ -647,8 +636,6 @@
<string name="log">Logging</string> <string name="log">Logging</string>
<string name="flush_by_line">Flush debug logs by line</string> <string name="flush_by_line">Flush debug logs by line</string>
<string name="flush_by_line_description">Flushes debugging logs on each line written, making debugging easier in cases of crashing or freezing.</string> <string name="flush_by_line_description">Flushes debugging logs on each line written, making debugging easier in cases of crashing or freezing.</string>
<string name="extended_logging">Enable extended logging</string>
<string name="extended_logging_description">Increases the maximum log file size from 100 MiB to 1 GiB.</string>
<string name="log_filter">Log filter</string> <string name="log_filter">Log filter</string>
<string name="log_filter_description">Controls Eden\'s log categories. Example: *:Info Service.LM:Debug</string> <string name="log_filter_description">Controls Eden\'s log categories. Example: *:Info Service.LM:Debug</string>
-1
View File
@@ -5,7 +5,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <string> #include <string>
#include <cstdlib>
#include <string_view> #include <string_view>
#ifdef _WIN32 #ifdef _WIN32
#include <llvm/Demangle/Demangle.h> #include <llvm/Demangle/Demangle.h>
-1
View File
@@ -23,7 +23,6 @@
#define LOSSLESS_DIR "lossless" #define LOSSLESS_DIR "lossless"
#define NAND_DIR "nand" #define NAND_DIR "nand"
#define PLAY_TIME_DIR "play_time" #define PLAY_TIME_DIR "play_time"
#define POST_SHADER_DIR "post_shaders"
#define SCREENSHOTS_DIR "screenshots" #define SCREENSHOTS_DIR "screenshots"
#define SDMC_DIR "sdmc" #define SDMC_DIR "sdmc"
#define SHADER_DIR "shader" #define SHADER_DIR "shader"
-1
View File
@@ -160,7 +160,6 @@ public:
GenerateEdenPath(EdenPath::LosslessDir, eden_path / LOSSLESS_DIR); GenerateEdenPath(EdenPath::LosslessDir, eden_path / LOSSLESS_DIR);
GenerateEdenPath(EdenPath::NANDDir, eden_path / NAND_DIR); GenerateEdenPath(EdenPath::NANDDir, eden_path / NAND_DIR);
GenerateEdenPath(EdenPath::PlayTimeDir, eden_path / PLAY_TIME_DIR); GenerateEdenPath(EdenPath::PlayTimeDir, eden_path / PLAY_TIME_DIR);
GenerateEdenPath(EdenPath::PostShaderDir, eden_path / POST_SHADER_DIR);
GenerateEdenPath(EdenPath::SaveDir, eden_path / NAND_DIR); GenerateEdenPath(EdenPath::SaveDir, eden_path / NAND_DIR);
GenerateEdenPath(EdenPath::ScreenshotsDir, eden_path / SCREENSHOTS_DIR); GenerateEdenPath(EdenPath::ScreenshotsDir, eden_path / SCREENSHOTS_DIR);
GenerateEdenPath(EdenPath::SDMCDir, eden_path / SDMC_DIR); GenerateEdenPath(EdenPath::SDMCDir, eden_path / SDMC_DIR);
-1
View File
@@ -26,7 +26,6 @@ enum class EdenPath {
LosslessDir, // Where the user-supplied Lossless Scaling library is stored. LosslessDir, // Where the user-supplied Lossless Scaling library is stored.
NANDDir, // Where the emulated NAND is stored. NANDDir, // Where the emulated NAND is stored.
PlayTimeDir, // Where play time data is stored. PlayTimeDir, // Where play time data is stored.
PostShaderDir, // Where user post-processing shaders are stored.
SaveDir, // Where save data is stored. SaveDir, // Where save data is stored.
ScreenshotsDir, // Where yuzu screenshots are stored. ScreenshotsDir, // Where yuzu screenshots are stored.
SDMCDir, // Where the emulated SDMC is stored. SDMCDir, // Where the emulated SDMC is stored.
+1 -5
View File
@@ -1,13 +1,9 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <iterator> #include <iterator>
#include <cstring>
#include "common/make_unique_for_overwrite.h" #include "common/make_unique_for_overwrite.h"
@@ -65,7 +61,7 @@ public:
void resize(size_type size) { void resize(size_type size) {
if (size > buffer_capacity) { if (size > buffer_capacity) {
auto new_buffer = Common::make_unique_for_overwrite<T[]>(size); auto new_buffer = Common::make_unique_for_overwrite<T[]>(size);
std::memcpy(new_buffer.get(), buffer.get(), buffer_capacity * sizeof(T)); std::move(buffer.get(), buffer.get() + buffer_capacity, new_buffer.get());
buffer = std::move(new_buffer); buffer = std::move(new_buffer);
buffer_capacity = size; buffer_capacity = size;
} }
-8
View File
@@ -388,14 +388,6 @@ struct Values {
true, true,
true}; true};
Setting<std::string> post_shader_chain{linkage,
std::string(),
"post_shader_chain",
Category::Renderer,
Specialization::Default,
true,
true};
SwitchableSetting<bool> frame_gen{linkage, false, "frame_gen", Category::Renderer, SwitchableSetting<bool> frame_gen{linkage, false, "frame_gen", Category::Renderer,
Specialization::Default, true, false}; Specialization::Default, true, false};
-1
View File
@@ -10,7 +10,6 @@
#include <functional> #include <functional>
#include <span> #include <span>
#include <string> #include <string>
#include <type_traits>
#include "common/common_types.h" #include "common/common_types.h"
+3 -3
View File
@@ -6,13 +6,13 @@
#include <mutex> #include <mutex>
#include <utility> #include <utility>
#include <type_traits>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/version.hpp> #include <boost/version.hpp>
#if BOOST_VERSION > 108400 && (!defined(_WINDOWS) && !defined(__ANDROID__)) || defined(YUZU_BOOST_v1) #if BOOST_VERSION > 108400 && (!defined(_WINDOWS) && !defined(__ANDROID__)) || defined(YUZU_BOOST_v1)
#define USE_BOOST_v1 #define USE_BOOST_v1
#endif #endif
#ifdef USE_BOOST_v1 #ifdef USE_BOOST_v1
#include <boost/process/v1/async_pipe.hpp> #include <boost/process/v1/async_pipe.hpp>
#else #else
@@ -358,7 +358,7 @@ private:
ConnectionState(boost::asio::ip::tcp::socket&& client_socket_, async_pipe signal_pipe_, Kernel::KernelCore& kernel) ConnectionState(boost::asio::ip::tcp::socket&& client_socket_, async_pipe signal_pipe_, Kernel::KernelCore& kernel)
: client_socket{std::move(client_socket_)} : client_socket{std::move(client_socket_)}
, signal_pipe{std::move(signal_pipe_)} , signal_pipe{signal_pipe_}
, active_thread{kernel, nullptr} , active_thread{kernel, nullptr}
{} {}
+1 -2
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
@@ -6,7 +6,6 @@
#pragma once #pragma once
#include <type_traits>
#include "common/common_funcs.h" #include "common/common_funcs.h"
namespace FileSys { namespace FileSys {
@@ -7,7 +7,6 @@
#pragma once #pragma once
#include <optional> #include <optional>
#include <type_traits>
#include "common/literals.h" #include "common/literals.h"
#include "core/file_sys/fssystem/fs_i_storage.h" #include "core/file_sys/fssystem/fs_i_storage.h"
@@ -4,7 +4,6 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <type_traits>
#include "core/file_sys/errors.h" #include "core/file_sys/errors.h"
#include "core/file_sys/fssystem/fssystem_bucket_tree.h" #include "core/file_sys/fssystem/fssystem_bucket_tree.h"
#include "core/file_sys/fssystem/fssystem_bucket_tree_utils.h" #include "core/file_sys/fssystem/fssystem_bucket_tree_utils.h"
@@ -1,13 +1,9 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <mutex> #include <mutex>
#include <type_traits>
#include "common/alignment.h" #include "common/alignment.h"
#include "common/common_funcs.h" #include "common/common_funcs.h"
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
@@ -6,7 +6,6 @@
#pragma once #pragma once
#include <type_traits>
#include "core/file_sys/errors.h" #include "core/file_sys/errors.h"
#include "core/file_sys/fssystem/fssystem_bucket_tree.h" #include "core/file_sys/fssystem/fssystem_bucket_tree.h"
#include "core/file_sys/fssystem/fssystem_bucket_tree_utils.h" #include "core/file_sys/fssystem/fssystem_bucket_tree_utils.h"
@@ -6,8 +6,6 @@
#pragma once #pragma once
#include <type_traits>
#include <cstddef>
#include "common/literals.h" #include "common/literals.h"
#include "core/file_sys/errors.h" #include "core/file_sys/errors.h"
@@ -1,12 +1,8 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <type_traits>
#include "common/alignment.h" #include "common/alignment.h"
#include "core/file_sys/fssystem/fs_i_storage.h" #include "core/file_sys/fssystem/fs_i_storage.h"
#include "core/file_sys/fssystem/fs_types.h" #include "core/file_sys/fssystem/fs_types.h"
@@ -6,9 +6,6 @@
#pragma once #pragma once
#include <type_traits>
#include <array>
#include <cstddef>
#include "core/file_sys/errors.h" #include "core/file_sys/errors.h"
#include "core/file_sys/fssystem/fs_i_storage.h" #include "core/file_sys/fssystem/fs_i_storage.h"
#include "core/file_sys/fssystem/fssystem_bucket_tree.h" #include "core/file_sys/fssystem/fssystem_bucket_tree.h"
@@ -1,15 +1,9 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <optional> #include <optional>
#include <array>
#include <cstddef>
#include <type_traits>
#include "core/file_sys/fssystem/fs_i_storage.h" #include "core/file_sys/fssystem/fs_i_storage.h"
#include "core/file_sys/fssystem/fs_types.h" #include "core/file_sys/fssystem/fs_types.h"
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
@@ -6,8 +6,6 @@
#pragma once #pragma once
#include <type_traits>
#include <cstddef>
#include "core/file_sys/fssystem/fssystem_compression_common.h" #include "core/file_sys/fssystem/fssystem_compression_common.h"
#include "core/file_sys/fssystem/fssystem_nca_header.h" #include "core/file_sys/fssystem/fssystem_nca_header.h"
#include "core/file_sys/vfs/vfs.h" #include "core/file_sys/vfs/vfs.h"
@@ -1,14 +1,8 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <type_traits>
#include <array>
#include <cstddef>
#include "common/common_funcs.h" #include "common/common_funcs.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/literals.h" #include "common/literals.h"
-1
View File
@@ -7,7 +7,6 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include <type_traits>
#include "common/common_funcs.h" #include "common/common_funcs.h"
#include "common/page_table.h" #include "common/page_table.h"
-3
View File
@@ -1021,9 +1021,6 @@ Result KProcess::Run(KernelCore& kernel, s32 priority, size_t stack_size) {
// Suspend for debug, if we should. // Suspend for debug, if we should.
if (kernel.System().DebuggerEnabled()) { if (kernel.System().DebuggerEnabled()) {
LOG_INFO(Debug_GDBStub,
"GDB stub enabled; suspending guest process until a debugger continues execution on port {}",
Settings::values.gdbstub_port.GetValue());
main_thread->RequestSuspend(kernel, SuspendType::Debug); main_thread->RequestSuspend(kernel, SuspendType::Debug);
} }
-1
View File
@@ -6,7 +6,6 @@
#pragma once #pragma once
#include <type_traits>
#include "common/assert.h" #include "common/assert.h"
#include "common/bit_field.h" #include "common/bit_field.h"
#include "common/common_funcs.h" #include "common/common_funcs.h"
-4
View File
@@ -1,13 +1,9 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
#pragma once #pragma once
#include <array> #include <array>
#include <type_traits>
#include <functional> #include <functional>
#include "common/common_funcs.h" #include "common/common_funcs.h"
+26 -8
View File
@@ -175,10 +175,19 @@ Result AlbumManager::LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& ou
return ResultIsNotMounted; return ResultIsNotMounted;
} }
out_image_output = {}; out_image_output = {
out_image_output.width = 1280; .width = 1280,
out_image_output.height = 720; .height = 720,
out_image_output.attribute.orientation = AlbumImageOrientation::None; .attribute =
{
.unknown_0{},
.orientation = AlbumImageOrientation::None,
.unknown_1{},
.unknown_2{},
.pad163{},
},
.pad179{},
};
std::filesystem::path path; std::filesystem::path path;
const auto result = GetFile(path, file_id); const auto result = GetFile(path, file_id);
@@ -202,10 +211,19 @@ Result AlbumManager::LoadAlbumScreenShotThumbnail(
return ResultIsNotMounted; return ResultIsNotMounted;
} }
out_image_output = {}; out_image_output = {
out_image_output.width = 320; .width = 320,
out_image_output.height = 180; .height = 180,
out_image_output.attribute.orientation = AlbumImageOrientation::None; .attribute =
{
.unknown_0{},
.orientation = AlbumImageOrientation::None,
.unknown_1{},
.unknown_2{},
.pad163{},
},
.pad179{},
};
std::filesystem::path path; std::filesystem::path path;
const auto result = GetFile(path, file_id); const auto result = GetFile(path, file_id);
+7 -2
View File
@@ -73,8 +73,13 @@ void IScreenShotApplicationService::CaptureAndSaveScreenshot(AlbumReportOption r
Layout::FramebufferLayout layout = Layout::FramebufferLayout layout =
Layout::DefaultFrameLayout(screenshot_width, screenshot_height); Layout::DefaultFrameLayout(screenshot_width, screenshot_height);
Capture::ScreenShotAttribute attribute{}; const Capture::ScreenShotAttribute attribute{
attribute.orientation = Capture::AlbumImageOrientation::None; .unknown_0{},
.orientation = Capture::AlbumImageOrientation::None,
.unknown_1{},
.unknown_2{},
.pad163{},
};
renderer.RequestScreenshot( renderer.RequestScreenshot(
image_data.data(), image_data.data(),
-4
View File
@@ -1,12 +1,8 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <type_traits>
#include "common/common_funcs.h" #include "common/common_funcs.h"
#include "common/common_types.h" #include "common/common_types.h"
+1 -2
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
@@ -6,7 +6,6 @@
#pragma once #pragma once
#include <type_traits>
#include <fmt/ranges.h> #include <fmt/ranges.h>
#include "common/common_funcs.h" #include "common/common_funcs.h"
-1
View File
@@ -8,7 +8,6 @@
#include <array> #include <array>
#include <chrono> #include <chrono>
#include <type_traits>
#include <fmt/ranges.h> #include <fmt/ranges.h>
#include "common/common_types.h" #include "common/common_types.h"
@@ -1,13 +1,10 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <array> #include <array>
#include <type_traits>
#include "common/common_types.h" #include "common/common_types.h"
#include "core/hle/service/psc/time/common.h" #include "core/hle/service/psc/time/common.h"
@@ -7,7 +7,6 @@
#pragma once #pragma once
#include <array> #include <array>
#include <type_traits>
#include "common/bit_field.h" #include "common/bit_field.h"
#include "common/common_funcs.h" #include "common/common_funcs.h"
-7
View File
@@ -1,15 +1,8 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <cstddef>
#include <array>
#include <type_traits>
#include "common/bit_field.h" #include "common/bit_field.h"
#include "common/common_funcs.h" #include "common/common_funcs.h"
#include "common/common_types.h" #include "common/common_types.h"
@@ -150,7 +150,6 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent) {
INSERT(Settings, anti_aliasing, tr("Anti-Aliasing Method:"), INSERT(Settings, anti_aliasing, tr("Anti-Aliasing Method:"),
tr("The anti-aliasing method to use.\nSMAA offers the best quality.\nFXAA " tr("The anti-aliasing method to use.\nSMAA offers the best quality.\nFXAA "
"can produce a more stable picture in lower resolutions.")); "can produce a more stable picture in lower resolutions."));
INSERT(Settings, post_shader_chain, QString(), QString());
INSERT(Settings, fullscreen_mode, tr("Fullscreen Mode:"), INSERT(Settings, fullscreen_mode, tr("Fullscreen Mode:"),
tr("The method used to render the window in fullscreen.\nBorderless offers the best " tr("The method used to render the window in fullscreen.\nBorderless offers the best "
"compatibility with the on-screen keyboard that some games request for " "compatibility with the on-screen keyboard that some games request for "
+51 -53
View File
@@ -6,6 +6,55 @@
add_library(shader_recompiler STATIC add_library(shader_recompiler STATIC
backend/bindings.h backend/bindings.h
backend/glasm/emit_glasm.cpp
backend/glasm/emit_glasm.h
backend/glasm/emit_glasm_barriers.cpp
backend/glasm/emit_glasm_bitwise_conversion.cpp
backend/glasm/emit_glasm_composite.cpp
backend/glasm/emit_glasm_context_get_set.cpp
backend/glasm/emit_glasm_control_flow.cpp
backend/glasm/emit_glasm_convert.cpp
backend/glasm/emit_glasm_floating_point.cpp
backend/glasm/emit_glasm_image.cpp
backend/glasm/emit_glasm_instructions.h
backend/glasm/emit_glasm_integer.cpp
backend/glasm/emit_glasm_logical.cpp
backend/glasm/emit_glasm_memory.cpp
backend/glasm/emit_glasm_not_implemented.cpp
backend/glasm/emit_glasm_select.cpp
backend/glasm/emit_glasm_shared_memory.cpp
backend/glasm/emit_glasm_special.cpp
backend/glasm/emit_glasm_undefined.cpp
backend/glasm/emit_glasm_warp.cpp
backend/glasm/glasm_emit_context.cpp
backend/glasm/glasm_emit_context.h
backend/glasm/reg_alloc.cpp
backend/glasm/reg_alloc.h
backend/glsl/emit_glsl.cpp
backend/glsl/emit_glsl.h
backend/glsl/emit_glsl_atomic.cpp
backend/glsl/emit_glsl_barriers.cpp
backend/glsl/emit_glsl_bitwise_conversion.cpp
backend/glsl/emit_glsl_composite.cpp
backend/glsl/emit_glsl_context_get_set.cpp
backend/glsl/emit_glsl_control_flow.cpp
backend/glsl/emit_glsl_convert.cpp
backend/glsl/emit_glsl_floating_point.cpp
backend/glsl/emit_glsl_image.cpp
backend/glsl/emit_glsl_instructions.h
backend/glsl/emit_glsl_integer.cpp
backend/glsl/emit_glsl_logical.cpp
backend/glsl/emit_glsl_memory.cpp
backend/glsl/emit_glsl_not_implemented.cpp
backend/glsl/emit_glsl_select.cpp
backend/glsl/emit_glsl_shared_memory.cpp
backend/glsl/emit_glsl_special.cpp
backend/glsl/emit_glsl_undefined.cpp
backend/glsl/emit_glsl_warp.cpp
backend/glsl/glsl_emit_context.cpp
backend/glsl/glsl_emit_context.h
backend/glsl/var_alloc.cpp
backend/glsl/var_alloc.h
backend/spirv/emit_spirv.cpp backend/spirv/emit_spirv.cpp
backend/spirv/emit_spirv.h backend/spirv/emit_spirv.h
backend/spirv/emit_spirv_atomic.cpp backend/spirv/emit_spirv_atomic.cpp
@@ -190,60 +239,9 @@ add_library(shader_recompiler STATIC
program_header.h program_header.h
runtime_info.h runtime_info.h
shader_info.h shader_info.h
varying_state.h) varying_state.h
if (ENABLE_OPENGL) )
target_sources(shader_recompiler PRIVATE
backend/glasm/emit_glasm.cpp
backend/glasm/emit_glasm.h
backend/glasm/emit_glasm_barriers.cpp
backend/glasm/emit_glasm_bitwise_conversion.cpp
backend/glasm/emit_glasm_composite.cpp
backend/glasm/emit_glasm_context_get_set.cpp
backend/glasm/emit_glasm_control_flow.cpp
backend/glasm/emit_glasm_convert.cpp
backend/glasm/emit_glasm_floating_point.cpp
backend/glasm/emit_glasm_image.cpp
backend/glasm/emit_glasm_instructions.h
backend/glasm/emit_glasm_integer.cpp
backend/glasm/emit_glasm_logical.cpp
backend/glasm/emit_glasm_memory.cpp
backend/glasm/emit_glasm_not_implemented.cpp
backend/glasm/emit_glasm_select.cpp
backend/glasm/emit_glasm_shared_memory.cpp
backend/glasm/emit_glasm_special.cpp
backend/glasm/emit_glasm_undefined.cpp
backend/glasm/emit_glasm_warp.cpp
backend/glasm/glasm_emit_context.cpp
backend/glasm/glasm_emit_context.h
backend/glasm/reg_alloc.cpp
backend/glasm/reg_alloc.h
backend/glsl/emit_glsl.cpp
backend/glsl/emit_glsl.h
backend/glsl/emit_glsl_atomic.cpp
backend/glsl/emit_glsl_barriers.cpp
backend/glsl/emit_glsl_bitwise_conversion.cpp
backend/glsl/emit_glsl_composite.cpp
backend/glsl/emit_glsl_context_get_set.cpp
backend/glsl/emit_glsl_control_flow.cpp
backend/glsl/emit_glsl_convert.cpp
backend/glsl/emit_glsl_floating_point.cpp
backend/glsl/emit_glsl_image.cpp
backend/glsl/emit_glsl_instructions.h
backend/glsl/emit_glsl_integer.cpp
backend/glsl/emit_glsl_logical.cpp
backend/glsl/emit_glsl_memory.cpp
backend/glsl/emit_glsl_not_implemented.cpp
backend/glsl/emit_glsl_select.cpp
backend/glsl/emit_glsl_shared_memory.cpp
backend/glsl/emit_glsl_special.cpp
backend/glsl/emit_glsl_undefined.cpp
backend/glsl/emit_glsl_warp.cpp
backend/glsl/glsl_emit_context.cpp
backend/glsl/glsl_emit_context.h
backend/glsl/var_alloc.cpp
backend/glsl/var_alloc.h)
endif()
target_link_libraries(shader_recompiler PUBLIC common fmt::fmt sirit::sirit) target_link_libraries(shader_recompiler PUBLIC common fmt::fmt sirit::sirit)
@@ -553,6 +553,17 @@ void GlobalMemoryToStorageBufferPass(IR::Program& program, const HostTranslateIn
} }
} }
template <typename Descriptors, typename Descriptor, typename Func>
static u32 Add(Descriptors& descriptors, const Descriptor& desc, Func&& pred) {
// TODO: Handle arrays
const auto it{std::ranges::find_if(descriptors, pred)};
if (it != descriptors.end()) {
return static_cast<u32>(std::distance(descriptors.begin(), it));
}
descriptors.push_back(desc);
return static_cast<u32>(descriptors.size()) - 1;
}
void JoinStorageInfo(Info& base, Info& source) { void JoinStorageInfo(Info& base, Info& source) {
auto& descriptors = base.storage_buffers_descriptors; auto& descriptors = base.storage_buffers_descriptors;
for (auto& desc : source.storage_buffers_descriptors) { for (auto& desc : source.storage_buffers_descriptors) {
-29
View File
@@ -299,35 +299,6 @@ if (ENABLE_LSFG)
target_compile_definitions(video_core PUBLIC HAS_LSFG) target_compile_definitions(video_core PUBLIC HAS_LSFG)
endif() endif()
if (ENABLE_RESHADE)
set(BUNDLED_FX_DIR ${CMAKE_SOURCE_DIR}/dist/post_shaders)
set(BUNDLED_FX_HEADER ${CMAKE_CURRENT_BINARY_DIR}/bundled_fx_effects.h)
file(GLOB BUNDLED_FX_FILES ${BUNDLED_FX_DIR}/*.fx)
add_custom_command(
OUTPUT ${BUNDLED_FX_HEADER}
COMMAND ${CMAKE_COMMAND} -P
${CMAKE_CURRENT_SOURCE_DIR}/post_processing/GenerateBundledEffects.cmake
${BUNDLED_FX_DIR} ${BUNDLED_FX_HEADER}
DEPENDS ${BUNDLED_FX_FILES}
)
target_sources(video_core PRIVATE
post_processing/fx_chain.cpp
post_processing/fx_chain.h
post_processing/fx_compile.cpp
post_processing/fx_compile.h
post_processing/fx_effect.cpp
post_processing/fx_effect.h
renderer_vulkan/present/post_process.cpp
renderer_vulkan/present/post_process.h
${BUNDLED_FX_HEADER}
)
target_include_directories(video_core PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
target_link_libraries(video_core PRIVATE reshadefx::reshadefx)
target_compile_definitions(video_core PUBLIC HAS_RESHADE)
endif()
if (ENABLE_OPENGL) if (ENABLE_OPENGL)
target_sources(video_core PRIVATE target_sources(video_core PRIVATE
renderer_opengl/present/filters.cpp renderer_opengl/present/filters.cpp
-20
View File
@@ -20,8 +20,6 @@ namespace VideoCommon {
enum class BufferFlagBits { enum class BufferFlagBits {
Picked = 1 << 0, Picked = 1 << 0,
CachedWrites = 1 << 1,
PreemtiveDownload = 1 << 2,
}; };
DECLARE_ENUM_FLAG_OPERATORS(BufferFlagBits) DECLARE_ENUM_FLAG_OPERATORS(BufferFlagBits)
@@ -58,15 +56,6 @@ public:
flags |= BufferFlagBits::Picked; flags |= BufferFlagBits::Picked;
} }
void MarkPreemtiveDownload() noexcept {
flags |= BufferFlagBits::PreemtiveDownload;
}
/// Unmark buffer as picked
void Unpick() noexcept {
flags &= ~BufferFlagBits::Picked;
}
/// Increases the likeliness of this being a stream buffer /// Increases the likeliness of this being a stream buffer
void IncreaseStreamScore(int score) noexcept { void IncreaseStreamScore(int score) noexcept {
stream_score += score; stream_score += score;
@@ -87,15 +76,6 @@ public:
return True(flags & BufferFlagBits::Picked); return True(flags & BufferFlagBits::Picked);
} }
/// Returns true when the buffer has pending cached writes
[[nodiscard]] bool HasCachedWrites() const noexcept {
return True(flags & BufferFlagBits::CachedWrites);
}
bool IsPreemtiveDownload() const noexcept {
return True(flags & BufferFlagBits::PreemtiveDownload);
}
/// Returns the base CPU address of the buffer /// Returns the base CPU address of the buffer
[[nodiscard]] VAddr CpuAddr() const noexcept { [[nodiscard]] VAddr CpuAddr() const noexcept {
return cpu_addr; return cpu_addr;
+161 -46
View File
@@ -7,6 +7,7 @@
#pragma once #pragma once
#include <algorithm> #include <algorithm>
#include <limits>
#include <memory> #include <memory>
#include <numeric> #include <numeric>
@@ -121,25 +122,6 @@ void BufferCache<P>::WriteMemory(DAddr device_addr, u64 size) {
memory_tracker.MarkRegionAsCpuModified(device_addr, size); memory_tracker.MarkRegionAsCpuModified(device_addr, size);
} }
template <class P>
void BufferCache<P>::CachedWriteMemory(DAddr device_addr, u64 size) {
const bool is_dirty = IsRegionRegistered(device_addr, size);
if (!is_dirty) {
return;
}
DAddr aligned_start = Common::AlignDown(device_addr, DEVICE_PAGESIZE);
DAddr aligned_end = Common::AlignUp(device_addr + size, DEVICE_PAGESIZE);
if (!IsRegionGpuModified(aligned_start, aligned_end - aligned_start)) {
WriteMemory(device_addr, size);
return;
}
tmp_buffer.resize_destructive(size);
device_memory.ReadBlockUnsafe(device_addr, tmp_buffer.data(), size);
InlineMemoryImplementation(device_addr, size, tmp_buffer);
}
template <class P> template <class P>
bool BufferCache<P>::OnCPUWrite(DAddr device_addr, u64 size) { bool BufferCache<P>::OnCPUWrite(DAddr device_addr, u64 size) {
const bool is_dirty = IsRegionRegistered(device_addr, size); const bool is_dirty = IsRegionRegistered(device_addr, size);
@@ -422,7 +404,7 @@ void BufferCache<P>::UnbindGraphicsStorageBuffers(size_t stage) {
} }
template <class P> template <class P>
bool BufferCache<P>::BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index, u32 cbuf_index, void BufferCache<P>::BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index, u32 cbuf_index,
u32 cbuf_offset, bool is_written) { u32 cbuf_offset, bool is_written) {
const bool already_enabled = const bool already_enabled =
((channel_state->enabled_storage_buffers[stage] >> ssbo_index) & 1U) != 0; ((channel_state->enabled_storage_buffers[stage] >> ssbo_index) & 1U) != 0;
@@ -433,7 +415,7 @@ bool BufferCache<P>::BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index,
LOG_WARNING(HW_GPU, LOG_WARNING(HW_GPU,
"Skipping graphics storage buffer {} due to driver limit {}", "Skipping graphics storage buffer {} due to driver limit {}",
ssbo_index, max_bindings); ssbo_index, max_bindings);
return false; return;
} }
} }
} }
@@ -449,7 +431,6 @@ bool BufferCache<P>::BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index,
const GPUVAddr ssbo_addr = cbufs.const_buffers[cbuf_index].address + cbuf_offset; const GPUVAddr ssbo_addr = cbufs.const_buffers[cbuf_index].address + cbuf_offset;
channel_state->storage_buffers[stage][ssbo_index] = channel_state->storage_buffers[stage][ssbo_index] =
StorageBufferBinding(ssbo_addr, cbuf_index, is_written); StorageBufferBinding(ssbo_addr, cbuf_index, is_written);
return (channel_state->storage_buffers[stage][ssbo_index].buffer_id != NULL_BUFFER_ID);
} }
template <class P> template <class P>
@@ -762,16 +743,6 @@ void BufferCache<P>::BindHostIndexBuffer() {
} }
} }
template <class P>
void BufferCache<P>::BindHostVertexBuffer(u32 index, Buffer& buffer, u32 offset, u32 size,
u32 stride) {
if constexpr (IS_OPENGL) {
runtime.BindVertexBuffer(index, buffer, offset, size, stride);
} else {
runtime.BindVertexBuffer(index, buffer.Handle(), offset, size, stride);
}
}
template <class P> template <class P>
Binding& BufferCache<P>::VertexBufferSlot(u32 index) { Binding& BufferCache<P>::VertexBufferSlot(u32 index) {
ASSERT(index < NUM_VERTEX_BUFFERS); ASSERT(index < NUM_VERTEX_BUFFERS);
@@ -1197,7 +1168,7 @@ void BufferCache<P>::DoUpdateGraphicsBuffers(bool is_indexed) {
if (is_indexed) { if (is_indexed) {
UpdateIndexBuffer(); UpdateIndexBuffer();
} }
UpdateVertexBuffers(); UpdateVertexBuffers(is_indexed);
UpdateTransformFeedbackBuffers(); UpdateTransformFeedbackBuffers();
for (size_t stage = 0; stage < NUM_STAGES; ++stage) { for (size_t stage = 0; stage < NUM_STAGES; ++stage) {
UpdateUniformBuffers(stage); UpdateUniformBuffers(stage);
@@ -1251,9 +1222,14 @@ void BufferCache<P>::UpdateIndexBuffer() {
const GPUVAddr gpu_addr_begin = index_buffer_ref.StartAddress(); const GPUVAddr gpu_addr_begin = index_buffer_ref.StartAddress();
const GPUVAddr gpu_addr_end = index_buffer_ref.EndAddress(); const GPUVAddr gpu_addr_end = index_buffer_ref.EndAddress();
const std::optional<DAddr> device_addr = gpu_memory->GpuToCpuAddress(gpu_addr_begin); const std::optional<DAddr> device_addr = gpu_memory->GpuToCpuAddress(gpu_addr_begin);
const u32 address_size = static_cast<u32>(gpu_addr_end - gpu_addr_begin); u64 address_size = 0;
const u32 draw_size = (index_buffer_ref.count + index_buffer_ref.first) * u32(index_buffer_ref.FormatSizeInBytes()); if (gpu_addr_end > gpu_addr_begin) {
const u32 size = (std::min)(address_size, draw_size); address_size = (std::min)(gpu_addr_end - gpu_addr_begin,
u64{(std::numeric_limits<u32>::max)()});
}
const u64 draw_size = (u64{index_buffer_ref.count} + u64{index_buffer_ref.first}) *
u64{index_buffer_ref.FormatSizeInBytes()};
const u32 size = static_cast<u32>((std::min)(address_size, draw_size));
if (size == 0 || !device_addr) { if (size == 0 || !device_addr) {
channel_state->index_buffer = NULL_BINDING; channel_state->index_buffer = NULL_BINDING;
return; return;
@@ -1266,20 +1242,142 @@ void BufferCache<P>::UpdateIndexBuffer() {
} }
template <class P> template <class P>
void BufferCache<P>::UpdateVertexBuffers() { u64 BufferCache<P>::DrawMaxIndex() {
if (max_index_scanned) {
return cached_max_index;
}
max_index_scanned = true;
cached_max_index = 0;
const auto& index_buffer_ref = maxwell3d->draw_manager.draw_state.index_buffer;
const u32 count = index_buffer_ref.count;
if (count == 0) {
return 0;
}
index_scan_buffer.resize_destructive(count);
gpu_memory->ReadBlockUnsafe(index_buffer_ref.IndexStart(), index_scan_buffer.data(),
size_t{count} * sizeof(u32));
u32 restart_index = (std::numeric_limits<u32>::max)();
if (maxwell3d->regs.primitive_restart.enabled != 0) {
restart_index = maxwell3d->regs.primitive_restart.index;
}
u32 max_index = 0;
for (u32 i = 0; i < count; ++i) {
const u32 value = index_scan_buffer[i];
if (value == restart_index) {
continue;
}
max_index = (std::max)(max_index, value);
}
cached_max_index = max_index;
return cached_max_index;
}
template <class P>
u64 BufferCache<P>::StreamAttributeExtent(u32 index) {
using VertexAttribute = typename Maxwell::VertexAttribute;
if (stream_extents_valid) {
return stream_extents[index];
}
stream_extents_valid = true;
stream_extents.fill(0);
for (size_t i = 0; i < Maxwell::NumVertexAttributes; ++i) {
const auto& attribute = maxwell3d->regs.vertex_attrib_format[i];
if (attribute.constant != 0 || attribute.size == VertexAttribute::Size::Invalid) {
continue;
}
const u32 buffer = attribute.buffer.Value();
if (buffer >= NUM_VERTEX_BUFFERS) {
continue;
}
const u64 end = static_cast<u64>(attribute.offset.Value()) +
static_cast<u64>(attribute.SizeInBytes());
stream_extents[buffer] = (std::max)(stream_extents[buffer], end);
}
return stream_extents[index];
}
template <class P>
u64 BufferCache<P>::DrawVertexBound(u32 index, bool is_indexed) {
const auto& array = maxwell3d->regs.vertex_streams[index];
if (array.enable == 0) {
return 0;
}
const u64 extent = StreamAttributeExtent(index);
if (extent == 0) {
return 0;
}
const u64 stride = static_cast<u64>(array.stride);
if (stride == 0) {
return extent;
}
const auto& draw_state = maxwell3d->draw_manager.draw_state;
u64 elements = 0;
if (maxwell3d->regs.vertex_stream_instances.IsInstancingEnabled(index)) {
if (draw_instance_count == 0) {
return 0;
}
const u64 base_instance = static_cast<u64>(draw_state.base_instance);
elements = base_instance + 1;
if (array.frequency != 0) {
elements = (base_instance + static_cast<u64>(draw_instance_count) - 1) /
static_cast<u64>(array.frequency) +
1;
}
} else if (!is_indexed) {
elements = static_cast<u64>(draw_state.vertex_buffer.first) +
static_cast<u64>(draw_state.vertex_buffer.count);
} else {
const auto format = draw_state.index_buffer.format;
u64 max_index = 0xFF;
if (format == Maxwell::IndexFormat::UnsignedShort) {
max_index = 0xFFFF;
} else if (format != Maxwell::IndexFormat::UnsignedByte) {
const auto& limit = maxwell3d->regs.vertex_stream_limits[index];
const GPUVAddr gpu_addr_begin = array.Address();
const GPUVAddr gpu_addr_end = limit.Address() + 1;
if (gpu_addr_end <= gpu_addr_begin) {
return 0;
}
const bool walks = gpu_addr_end - gpu_addr_begin >= IMPLAUSIBLE_VERTEX_SIZE ||
!gpu_memory->IsWithinGPUAddressRange(gpu_addr_end);
if (!walks) {
return 0;
}
max_index = DrawMaxIndex();
}
elements = static_cast<u64>(draw_state.base_index) + max_index + 1;
}
if (elements == 0) {
return extent;
}
return (elements - 1) * stride + extent;
}
template <class P>
void BufferCache<P>::UpdateVertexBuffers(bool is_indexed) {
auto& flags = maxwell3d->dirty.flags; auto& flags = maxwell3d->dirty.flags;
max_index_scanned = false;
stream_extents_valid = false;
for (u32 index = 0; index < NUM_VERTEX_BUFFERS; ++index) {
const u64 bound = DrawVertexBound(index, is_indexed);
if (bound <= last_draw_bounds[index]) {
continue;
}
flags[Dirty::VertexBuffer0 + index] = true;
flags[Dirty::VertexBuffers] = true;
}
if (!maxwell3d->dirty.flags[Dirty::VertexBuffers]) { if (!maxwell3d->dirty.flags[Dirty::VertexBuffers]) {
return; return;
} }
flags[Dirty::VertexBuffers] = false; flags[Dirty::VertexBuffers] = false;
for (u32 index = 0; index < NUM_VERTEX_BUFFERS; ++index) { for (u32 index = 0; index < NUM_VERTEX_BUFFERS; ++index) {
UpdateVertexBuffer(index); UpdateVertexBuffer(index, is_indexed);
} }
} }
template <class P> template <class P>
void BufferCache<P>::UpdateVertexBuffer(u32 index) { void BufferCache<P>::UpdateVertexBuffer(u32 index, bool is_indexed) {
if (!maxwell3d->dirty.flags[Dirty::VertexBuffer0 + index]) { if (!maxwell3d->dirty.flags[Dirty::VertexBuffer0 + index]) {
return; return;
} }
@@ -1288,15 +1386,31 @@ void BufferCache<P>::UpdateVertexBuffer(u32 index) {
const GPUVAddr gpu_addr_begin = array.Address(); const GPUVAddr gpu_addr_begin = array.Address();
const GPUVAddr gpu_addr_end = limit.Address() + 1; const GPUVAddr gpu_addr_end = limit.Address() + 1;
const std::optional<DAddr> device_addr = gpu_memory->GpuToCpuAddress(gpu_addr_begin); const std::optional<DAddr> device_addr = gpu_memory->GpuToCpuAddress(gpu_addr_begin);
const u32 address_size = static_cast<u32>(gpu_addr_end - gpu_addr_begin); if (array.enable == 0 || !device_addr || gpu_addr_end <= gpu_addr_begin) {
u32 size = address_size; // TODO: Analyze stride and number of vertices
if (array.enable == 0 || size == 0 || !device_addr) {
channel_state->vertex_buffers[index] = NULL_BINDING; channel_state->vertex_buffers[index] = NULL_BINDING;
UpdateVertexBufferSlot(index, NULL_BINDING); UpdateVertexBufferSlot(index, NULL_BINDING);
return; return;
} }
if (!gpu_memory->IsWithinGPUAddressRange(gpu_addr_end) || size >= 64_MiB) { // TODO: Analyze stride and number of vertices
size = static_cast<u32>(gpu_memory->MaxContinuousRange(gpu_addr_begin, size)); constexpr u64 implausible_size = IMPLAUSIBLE_VERTEX_SIZE;
u64 address_size = gpu_addr_end - gpu_addr_begin;
if (address_size > u64{(std::numeric_limits<u32>::max)()}) {
address_size = implausible_size;
}
const u64 draw_bound = DrawVertexBound(index, is_indexed);
last_draw_bounds[index] = (std::numeric_limits<u64>::max)();
if (draw_bound != 0) {
last_draw_bounds[index] = draw_bound;
address_size = (std::min)(address_size, draw_bound);
}
if (!gpu_memory->IsWithinGPUAddressRange(gpu_addr_end) || address_size >= implausible_size) {
address_size = gpu_memory->MaxContinuousRange(gpu_addr_begin, address_size);
}
const u32 size = static_cast<u32>(address_size);
if (size == 0) {
channel_state->vertex_buffers[index] = NULL_BINDING;
UpdateVertexBufferSlot(index, NULL_BINDING);
return;
} }
const BufferId buffer_id = FindBuffer(*device_addr, size); const BufferId buffer_id = FindBuffer(*device_addr, size);
const Binding binding{ const Binding binding{
@@ -1578,9 +1692,10 @@ template <class P>
BufferId BufferCache<P>::CreateBuffer(DAddr device_addr, u32 wanted_size) { BufferId BufferCache<P>::CreateBuffer(DAddr device_addr, u32 wanted_size) {
DAddr device_addr_end = Common::AlignUp(device_addr + wanted_size, CACHING_PAGESIZE); DAddr device_addr_end = Common::AlignUp(device_addr + wanted_size, CACHING_PAGESIZE);
device_addr = Common::AlignDown(device_addr, CACHING_PAGESIZE); device_addr = Common::AlignDown(device_addr, CACHING_PAGESIZE);
wanted_size = static_cast<u32>(device_addr_end - device_addr); constexpr u64 max_buffer_size = u64{(std::numeric_limits<u32>::max)()};
wanted_size = static_cast<u32>((std::min)(device_addr_end - device_addr, max_buffer_size));
const OverlapResult overlap = ResolveOverlaps(device_addr, wanted_size); const OverlapResult overlap = ResolveOverlaps(device_addr, wanted_size);
const u32 size = static_cast<u32>(overlap.end - overlap.begin); const u32 size = static_cast<u32>((std::min)(overlap.end - overlap.begin, max_buffer_size));
const BufferId new_buffer_id = slot_buffers.insert(runtime, overlap.begin, size); const BufferId new_buffer_id = slot_buffers.insert(runtime, overlap.begin, size);
auto& new_buffer = slot_buffers[new_buffer_id]; auto& new_buffer = slot_buffers[new_buffer_id];
const size_t size_bytes = new_buffer.SizeBytes(); const size_t size_bytes = new_buffer.SizeBytes();
@@ -51,6 +51,7 @@ constexpr u32 NUM_VERTEX_BUFFERS = 16;
#else #else
constexpr u32 NUM_VERTEX_BUFFERS = 32; constexpr u32 NUM_VERTEX_BUFFERS = 32;
#endif #endif
constexpr u64 IMPLAUSIBLE_VERTEX_SIZE = 64_MiB;
constexpr u32 NUM_TRANSFORM_FEEDBACK_BUFFERS = 4; constexpr u32 NUM_TRANSFORM_FEEDBACK_BUFFERS = 4;
constexpr u32 NUM_GRAPHICS_UNIFORM_BUFFERS = 18; constexpr u32 NUM_GRAPHICS_UNIFORM_BUFFERS = 18;
constexpr u32 NUM_COMPUTE_UNIFORM_BUFFERS = 8; constexpr u32 NUM_COMPUTE_UNIFORM_BUFFERS = 8;
@@ -217,8 +218,6 @@ public:
void WriteMemory(DAddr device_addr, u64 size); void WriteMemory(DAddr device_addr, u64 size);
void CachedWriteMemory(DAddr device_addr, u64 size);
bool OnCPUWrite(DAddr device_addr, u64 size); bool OnCPUWrite(DAddr device_addr, u64 size);
void DownloadMemory(DAddr device_addr, u64 size); void DownloadMemory(DAddr device_addr, u64 size);
@@ -248,7 +247,7 @@ public:
void UnbindGraphicsStorageBuffers(size_t stage); void UnbindGraphicsStorageBuffers(size_t stage);
bool BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index, u32 cbuf_index, u32 cbuf_offset, void BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index, u32 cbuf_index, u32 cbuf_offset,
bool is_written); bool is_written);
void UnbindGraphicsTextureBuffers(size_t stage); void UnbindGraphicsTextureBuffers(size_t stage);
@@ -309,6 +308,10 @@ public:
current_draw_indirect = current_draw_indirect_; current_draw_indirect = current_draw_indirect_;
} }
void SetDrawInstanceCount(u32 draw_instance_count_) {
draw_instance_count = draw_instance_count_;
}
[[nodiscard]] std::pair<Buffer*, u32> GetDrawIndirectCount(); [[nodiscard]] std::pair<Buffer*, u32> GetDrawIndirectCount();
[[nodiscard]] std::pair<Buffer*, u32> GetDrawIndirectBuffer(); [[nodiscard]] std::pair<Buffer*, u32> GetDrawIndirectBuffer();
@@ -376,8 +379,6 @@ private:
void BindHostTransformFeedbackBuffers(); void BindHostTransformFeedbackBuffers();
void BindHostVertexBuffer(u32 index, Buffer& buffer, u32 offset, u32 size, u32 stride);
void BindHostComputeUniformBuffers(); void BindHostComputeUniformBuffers();
void BindHostComputeStorageBuffers(); void BindHostComputeStorageBuffers();
@@ -390,9 +391,15 @@ private:
void UpdateIndexBuffer(); void UpdateIndexBuffer();
void UpdateVertexBuffers(); void UpdateVertexBuffers(bool is_indexed);
void UpdateVertexBuffer(u32 index); void UpdateVertexBuffer(u32 index, bool is_indexed);
[[nodiscard]] u64 DrawVertexBound(u32 index, bool is_indexed);
[[nodiscard]] u64 DrawMaxIndex();
[[nodiscard]] u64 StreamAttributeExtent(u32 index);
void UpdateDrawIndirect(); void UpdateDrawIndirect();
@@ -484,6 +491,14 @@ private:
const Tegra::Engines::Maxwell3D::DrawManager::IndirectParams* current_draw_indirect{}; const Tegra::Engines::Maxwell3D::DrawManager::IndirectParams* current_draw_indirect{};
u32 draw_instance_count = 0;
std::array<u64, NUM_VERTEX_BUFFERS> last_draw_bounds{};
Common::ScratchBuffer<u32> index_scan_buffer;
u64 cached_max_index = 0;
bool max_index_scanned = false;
std::array<u64, NUM_VERTEX_BUFFERS> stream_extents{};
bool stream_extents_valid = false;
u32 last_index_count = 0; u32 last_index_count = 0;
u32 enabled_vertex_buffers_mask = 0; u32 enabled_vertex_buffers_mask = 0;
-1
View File
@@ -8,7 +8,6 @@
#include <array> #include <array>
#include <vector> #include <vector>
#include <type_traits>
#include "common/bit_field.h" #include "common/bit_field.h"
#include "common/common_funcs.h" #include "common/common_funcs.h"
-7
View File
@@ -1,15 +1,8 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
#include <array>
#include <cstddef>
#include <type_traits>
#include "common/bit_field.h" #include "common/bit_field.h"
#include "common/common_funcs.h" #include "common/common_funcs.h"
#include "common/common_types.h" #include "common/common_types.h"
-1
View File
@@ -7,7 +7,6 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include <type_traits>
#include "common/common_types.h" #include "common/common_types.h"
#include "common/scratch_buffer.h" #include "common/scratch_buffer.h"
@@ -206,6 +206,40 @@ foreach(VARIANT IN ITEMS ${SHADER_TYPE_VARIANTS})
set(SHADER_HEADERS ${SHADER_HEADERS} ${VARIANT_HEADER_FILE}) set(SHADER_HEADERS ${SHADER_HEADERS} ${VARIANT_HEADER_FILE})
endforeach() endforeach()
set(SHADER_DEFINE_VARIANTS
"block_linear_unswizzle_2d.comp|nonarrow|HAS_EXTENDED_TYPES=0"
"pitch_unswizzle.comp|nonarrow|HAS_EXTENDED_TYPES=0"
"block_linear_unswizzle_3d.comp|nonarrow|HAS_EXTENDED_TYPES=0"
)
foreach(VARIANT IN ITEMS ${SHADER_DEFINE_VARIANTS})
string(REPLACE "|" ";" VARIANT_PARTS ${VARIANT})
list(GET VARIANT_PARTS 0 VARIANT_FILENAME)
list(GET VARIANT_PARTS 1 VARIANT_SUFFIX)
list(GET VARIANT_PARTS 2 VARIANT_DEFINE)
set(VARIANT_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/${VARIANT_FILENAME})
get_filename_component(VARIANT_STEM ${VARIANT_FILENAME} NAME_WE)
get_filename_component(VARIANT_EXT ${VARIANT_FILENAME} EXT)
string(REPLACE "." "" VARIANT_EXT ${VARIANT_EXT})
set(VARIANT_NAME ${VARIANT_STEM}_${VARIANT_SUFFIX}_${VARIANT_EXT})
string(TOUPPER ${VARIANT_NAME}_SPV VARIANT_VARIABLE_NAME)
set(VARIANT_HEADER_FILE ${SHADER_DIR}/${VARIANT_NAME}_spv.h)
add_custom_command(
OUTPUT
${VARIANT_HEADER_FILE}
COMMAND
${GLSLANGVALIDATOR} -V ${QUIET_FLAG} -I"${FIDELITYFX_INCLUDE_DIR}" ${GLSL_FLAGS}
-D${VARIANT_DEFINE}
--variable-name ${VARIANT_VARIABLE_NAME} -o ${VARIANT_HEADER_FILE} ${VARIANT_SOURCE}
--target-env ${SPIR_V_VERSION}
MAIN_DEPENDENCY
${VARIANT_SOURCE}
)
set(SHADER_HEADERS ${SHADER_HEADERS} ${VARIANT_HEADER_FILE})
endforeach()
foreach(FILEPATH IN ITEMS ${FIDELITYFX_FILES}) foreach(FILEPATH IN ITEMS ${FIDELITYFX_FILES})
get_filename_component(FILENAME ${FILEPATH} NAME) get_filename_component(FILENAME ${FILEPATH} NAME)
string(REPLACE "." "_" HEADER_NAME ${FILENAME}) string(REPLACE "." "_" HEADER_NAME ${FILENAME})
@@ -5,9 +5,13 @@
#ifdef VULKAN #ifdef VULKAN
#ifndef HAS_EXTENDED_TYPES
#define HAS_EXTENDED_TYPES 1
#endif
#if HAS_EXTENDED_TYPES
#extension GL_EXT_shader_16bit_storage : require #extension GL_EXT_shader_16bit_storage : require
#extension GL_EXT_shader_8bit_storage : require #extension GL_EXT_shader_8bit_storage : require
#define HAS_EXTENDED_TYPES 1 #endif
#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants { #define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
#define END_PUSH_CONSTANTS }; #define END_PUSH_CONSTANTS };
#define UNIFORM(n) #define UNIFORM(n)
@@ -5,9 +5,13 @@
#ifdef VULKAN #ifdef VULKAN
#ifndef HAS_EXTENDED_TYPES
#define HAS_EXTENDED_TYPES 1
#endif
#if HAS_EXTENDED_TYPES
#extension GL_EXT_shader_16bit_storage : require #extension GL_EXT_shader_16bit_storage : require
#extension GL_EXT_shader_8bit_storage : require #extension GL_EXT_shader_8bit_storage : require
#define HAS_EXTENDED_TYPES 1 #endif
#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants { #define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
#define END_PUSH_CONSTANTS }; #define END_PUSH_CONSTANTS };
#define UNIFORM(n) #define UNIFORM(n)
@@ -5,9 +5,13 @@
#ifdef VULKAN #ifdef VULKAN
#ifndef HAS_EXTENDED_TYPES
#define HAS_EXTENDED_TYPES 1
#endif
#if HAS_EXTENDED_TYPES
#extension GL_EXT_shader_16bit_storage : require #extension GL_EXT_shader_16bit_storage : require
#extension GL_EXT_shader_8bit_storage : require #extension GL_EXT_shader_8bit_storage : require
#define HAS_EXTENDED_TYPES 1 #endif
#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants { #define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
#define END_PUSH_CONSTANTS }; #define END_PUSH_CONSTANTS };
#define UNIFORM(n) #define UNIFORM(n)
@@ -1,50 +0,0 @@
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
set(EFFECT_DIR ${CMAKE_ARGV3})
set(HEADER_FILE ${CMAKE_ARGV4})
file(GLOB EFFECT_FILES ${EFFECT_DIR}/*.fx)
list(SORT EFFECT_FILES)
set(ENTRIES "")
foreach(EFFECT_FILE IN LISTS EFFECT_FILES)
get_filename_component(EFFECT_NAME ${EFFECT_FILE} NAME)
file(READ ${EFFECT_FILE} EFFECT_BODY)
string(REGEX REPLACE ";" "{{SEMICOLON}}" EFFECT_BODY "${EFFECT_BODY}")
string(REGEX REPLACE "\n" ";" EFFECT_BODY "${EFFECT_BODY}")
set(EFFECT_TEXT "")
foreach(LINE IN LISTS EFFECT_BODY)
string(CONCAT EFFECT_TEXT "${EFFECT_TEXT}" " R\"(${LINE}\n)\"\n")
endforeach()
string(REGEX REPLACE "{{SEMICOLON}}" ";" EFFECT_TEXT "${EFFECT_TEXT}")
string(CONCAT ENTRIES "${ENTRIES}"
" {\n \"${EFFECT_NAME}\",\n${EFFECT_TEXT} },\n")
endforeach()
get_filename_component(OUTPUT_DIR ${HEADER_FILE} DIRECTORY)
make_directory(${OUTPUT_DIR})
file(WRITE ${HEADER_FILE}
"// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <string_view>
namespace VideoCore {
struct BundledFxEffect {
std::string_view name;
std::string_view source;
};
constexpr BundledFxEffect BUNDLED_FX_EFFECTS[]{
${ENTRIES}};
} // namespace VideoCore
")
-301
View File
@@ -1,301 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <algorithm>
#include <cstdlib>
#include <fmt/format.h>
#include "common/settings.h"
#include "video_core/post_processing/fx_chain.h"
#include "video_core/post_processing/fx_effect.h"
namespace VideoCore {
namespace {
std::vector<std::string_view> Split(std::string_view value, char separator) {
std::vector<std::string_view> out;
size_t start = 0;
while (start <= value.size()) {
size_t end = value.find(separator, start);
if (end == std::string_view::npos) {
end = value.size();
}
out.push_back(value.substr(start, end - start));
start = end + 1;
}
return out;
}
bool IsSerializableName(std::string_view value) {
return value.find_first_of(";|,=") == std::string_view::npos;
}
} // Anonymous namespace
std::vector<FxChainEntry> ParseFxChain(std::string_view value) {
std::vector<FxChainEntry> parsed;
for (const std::string_view record : Split(value, ';')) {
if (record.empty()) {
continue;
}
const auto fields = Split(record, '|');
if (fields.size() < 2 || fields[0].empty() || fields[1].empty()) {
continue;
}
FxChainEntry entry;
entry.file = std::string(fields[0]);
entry.technique = std::string(fields[1]);
if (fields.size() >= 3) {
for (const std::string_view assignment : Split(fields[2], ',')) {
const size_t equals = assignment.find('=');
if (equals == std::string_view::npos) {
continue;
}
const std::string name(assignment.substr(0, equals));
if (name.empty()) {
continue;
}
std::array<f32, 4> components{};
size_t index = 0;
for (const std::string_view piece : Split(assignment.substr(equals + 1), '/')) {
if (index >= components.size()) {
break;
}
const std::string text(piece);
if (!text.empty()) {
components[index] = std::strtof(text.c_str(), nullptr);
}
++index;
}
entry.values.emplace(name, components);
}
}
parsed.push_back(std::move(entry));
}
return parsed;
}
std::string SerializeFxChain(std::span<const FxChainEntry> entries) {
std::string out;
for (const auto& entry : entries) {
if (!IsSerializableName(entry.file) || !IsSerializableName(entry.technique)) {
continue;
}
if (!out.empty()) {
out += ';';
}
out += fmt::format("{}|{}|", entry.file, entry.technique);
bool first = true;
for (const auto& [name, value] : entry.values) {
if (!IsSerializableName(name)) {
continue;
}
if (!first) {
out += ',';
}
first = false;
out += name;
out += '=';
for (size_t i = 0; i < value.size(); ++i) {
if (i > 0) {
out += '/';
}
out += fmt::format("{}", value[i]);
}
}
}
return out;
}
FxChain& FxChain::Instance() {
static FxChain instance;
return instance;
}
FxChainSnapshot FxChain::Snapshot() const {
std::scoped_lock lock{mutex};
return FxChainSnapshot{
.entries = entries,
.generation = generation.load(std::memory_order_relaxed),
};
}
std::vector<FxChainEntry> FxChain::Entries() const {
std::scoped_lock lock{mutex};
return entries;
}
size_t FxChain::Size() const {
std::scoped_lock lock{mutex};
return entries.size();
}
void FxChain::Append(std::string_view file, std::string_view technique) {
{
std::scoped_lock lock{mutex};
FxChainEntry entry;
entry.file = std::string(file);
entry.technique = std::string(technique);
entries.push_back(std::move(entry));
}
generation.fetch_add(1, std::memory_order_relaxed);
}
void FxChain::Replace(size_t index, std::string_view file, std::string_view technique) {
{
std::scoped_lock lock{mutex};
if (index >= entries.size()) {
return;
}
if (entries[index].file == file && entries[index].technique == technique) {
return;
}
FxChainEntry entry;
entry.file = std::string(file);
entry.technique = std::string(technique);
entries[index] = std::move(entry);
}
generation.fetch_add(1, std::memory_order_relaxed);
}
void FxChain::Remove(size_t index) {
{
std::scoped_lock lock{mutex};
if (index >= entries.size()) {
return;
}
entries.erase(entries.begin() + static_cast<std::ptrdiff_t>(index));
}
generation.fetch_add(1, std::memory_order_relaxed);
}
void FxChain::Move(size_t index, int delta) {
{
std::scoped_lock lock{mutex};
if (index >= entries.size()) {
return;
}
const std::ptrdiff_t target = static_cast<std::ptrdiff_t>(index) + delta;
if (target < 0 || target >= static_cast<std::ptrdiff_t>(entries.size())) {
return;
}
std::swap(entries[index], entries[static_cast<size_t>(target)]);
}
generation.fetch_add(1, std::memory_order_relaxed);
}
void FxChain::Clear() {
{
std::scoped_lock lock{mutex};
entries.clear();
}
generation.fetch_add(1, std::memory_order_relaxed);
}
void FxChain::SetValue(size_t index, std::string_view uniform, const std::array<f32, 4>& value) {
std::scoped_lock lock{mutex};
if (index >= entries.size()) {
return;
}
entries[index].values[std::string(uniform)] = value;
}
std::array<f32, 4> FxChain::GetValue(size_t index, std::string_view uniform) const {
std::scoped_lock lock{mutex};
if (index >= entries.size()) {
return {};
}
const auto it = entries[index].values.find(std::string(uniform));
if (it == entries[index].values.end()) {
return {};
}
return it->second;
}
std::map<std::string, std::array<f32, 4>> FxChain::EntryValues(size_t index) const {
std::scoped_lock lock{mutex};
if (index >= entries.size()) {
return {};
}
return entries[index].values;
}
bool FxChain::HasValue(size_t index, std::string_view uniform) const {
std::scoped_lock lock{mutex};
if (index >= entries.size()) {
return false;
}
return entries[index].values.contains(std::string(uniform));
}
void FxChain::ResetValues(size_t index) {
std::scoped_lock lock{mutex};
if (index >= entries.size()) {
return;
}
entries[index].values.clear();
}
void FxChain::LoadFromSettings() {
auto parsed = ParseFxChain(Settings::values.post_shader_chain.GetValue());
std::scoped_lock lock{mutex};
entries = std::move(parsed);
loaded = true;
generation.fetch_add(1, std::memory_order_relaxed);
}
void FxChain::EnsureLoadedFromSettings() {
{
std::scoped_lock lock{mutex};
if (loaded) {
return;
}
}
LoadFromSettings();
}
void FxChain::StoreToSettings() const {
std::string serialized;
{
std::scoped_lock lock{mutex};
serialized = SerializeFxChain(entries);
}
Settings::values.post_shader_chain.SetValue(serialized);
}
void FxChain::DropUnknownEntries() {
bool changed = false;
{
std::scoped_lock lock{mutex};
const auto removed = std::remove_if(entries.begin(), entries.end(), [](const FxChainEntry& entry) {
const FxEffectDesc* effect = FindFxEffect(entry.file);
if (effect == nullptr || !effect->Valid()) {
return true;
}
return std::find(effect->techniques.begin(), effect->techniques.end(),
entry.technique) == effect->techniques.end();
});
if (removed != entries.end()) {
entries.erase(removed, entries.end());
changed = true;
}
}
if (changed) {
generation.fetch_add(1, std::memory_order_relaxed);
}
}
} // namespace VideoCore
-81
View File
@@ -1,81 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <array>
#include <atomic>
#include <map>
#include <mutex>
#include <span>
#include <string>
#include <string_view>
#include <vector>
#include "common/common_types.h"
namespace VideoCore {
struct FxChainEntry {
std::string file;
std::string technique;
std::map<std::string, std::array<f32, 4>> values;
};
struct FxChainSnapshot {
std::vector<FxChainEntry> entries;
u64 generation{};
};
std::vector<FxChainEntry> ParseFxChain(std::string_view value);
std::string SerializeFxChain(std::span<const FxChainEntry> entries);
class FxChain {
public:
static FxChain& Instance();
FxChainSnapshot Snapshot() const;
std::vector<FxChainEntry> Entries() const;
size_t Size() const;
void Append(std::string_view file, std::string_view technique);
void Replace(size_t index, std::string_view file, std::string_view technique);
void Remove(size_t index);
void Move(size_t index, int delta);
void Clear();
void SetValue(size_t index, std::string_view uniform, const std::array<f32, 4>& value);
std::array<f32, 4> GetValue(size_t index, std::string_view uniform) const;
std::map<std::string, std::array<f32, 4>> EntryValues(size_t index) const;
bool HasValue(size_t index, std::string_view uniform) const;
void ResetValues(size_t index);
void LoadFromSettings();
void EnsureLoadedFromSettings();
void StoreToSettings() const;
void DropUnknownEntries();
private:
FxChain() = default;
mutable std::mutex mutex;
std::vector<FxChainEntry> entries;
bool loaded{};
std::atomic<u64> generation{1};
};
} // namespace VideoCore
@@ -1,105 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <cstring>
#include <memory>
#include <set>
#include "effect_codegen.hpp"
#include "effect_parser.hpp"
#include "effect_preprocessor.hpp"
#include "common/fs/fs.h"
#include "common/fs/fs_util.h"
#include "video_core/post_processing/fx_compile.h"
#include "video_core/post_processing/fx_effect.h"
namespace VideoCore {
FxCompileResult CompileFxEffect(const std::filesystem::path& path, u32 width, u32 height,
u32 color_bit_depth) {
FxCompileResult result;
if (!Common::FS::Exists(path)) {
result.error = "Effect file not found: " + Common::FS::PathToUTF8String(path);
return result;
}
reshadefx::preprocessor preprocessor;
preprocessor.add_macro_definition("__RESHADE__", "60800");
preprocessor.add_macro_definition("__RESHADE_PERFORMANCE_MODE__", "1");
preprocessor.add_macro_definition("__RENDERER__", "0x20000");
preprocessor.add_macro_definition("__VENDOR__", "0");
preprocessor.add_macro_definition("__DEVICE__", "0");
preprocessor.add_macro_definition("__APPLICATION__", "0");
preprocessor.add_macro_definition("BUFFER_WIDTH", std::to_string(width));
preprocessor.add_macro_definition("BUFFER_HEIGHT", std::to_string(height));
preprocessor.add_macro_definition("BUFFER_RCP_WIDTH", "(1.0 / BUFFER_WIDTH)");
preprocessor.add_macro_definition("BUFFER_RCP_HEIGHT", "(1.0 / BUFFER_HEIGHT)");
preprocessor.add_macro_definition("BUFFER_COLOR_DEPTH", std::to_string(color_bit_depth));
preprocessor.add_macro_definition("BUFFER_COLOR_BIT_DEPTH", std::to_string(color_bit_depth));
for (const auto& include : GetFxIncludePaths(path)) {
preprocessor.add_include_path(include);
}
if (!preprocessor.append_file(path)) {
result.error = preprocessor.errors();
if (result.error.empty()) {
result.error = "Failed to preprocess " + Common::FS::PathToUTF8String(path);
}
return result;
}
std::unique_ptr<reshadefx::codegen> backend(
reshadefx::create_codegen_spirv(true, false, false, false, true));
reshadefx::parser parser;
if (!parser.parse(preprocessor.output(), backend.get())) {
result.error = parser.errors();
if (result.error.empty()) {
result.error = "Failed to parse " + Common::FS::PathToUTF8String(path);
}
return result;
}
result.module = backend->module();
std::set<std::string> wanted;
for (const auto& technique : result.module.techniques) {
for (const auto& pass : technique.passes) {
if (!pass.vs_entry_point.empty()) {
wanted.insert(pass.vs_entry_point);
}
if (!pass.ps_entry_point.empty()) {
wanted.insert(pass.ps_entry_point);
}
}
}
for (const auto& name : wanted) {
std::string binary;
std::string assembly;
std::string errors;
if (!backend->assemble_code_for_entry_point(name, binary, assembly, errors)) {
result.error = "Failed to assemble entry point '" + name + "': " + errors;
return result;
}
if (binary.size() % sizeof(u32) != 0) {
result.error = "Entry point '" + name + "' produced a malformed SPIR-V module";
return result;
}
std::vector<u32> words(binary.size() / sizeof(u32));
std::memcpy(words.data(), binary.data(), binary.size());
result.entry_points.emplace(name, std::move(words));
}
if (result.entry_points.empty()) {
result.error = "Effect declares no usable entry points";
}
return result;
}
} // namespace VideoCore
@@ -1,29 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <filesystem>
#include <map>
#include <string>
#include <vector>
#include "common/common_types.h"
#include "effect_module.hpp"
namespace VideoCore {
struct FxCompileResult {
reshadefx::effect_module module;
std::map<std::string, std::vector<u32>> entry_points;
std::string error;
bool Succeeded() const {
return error.empty() && !entry_points.empty();
}
};
FxCompileResult CompileFxEffect(const std::filesystem::path& path, u32 width, u32 height,
u32 color_bit_depth);
} // namespace VideoCore
@@ -1,307 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <algorithm>
#include "bundled_fx_effects.h"
#include "common/fs/file.h"
#include "common/fs/fs.h"
#include "common/fs/fs_util.h"
#include "common/fs/path_util.h"
#include "common/logging.h"
#include "video_core/post_processing/fx_compile.h"
#include "video_core/post_processing/fx_effect.h"
namespace VideoCore {
namespace {
constexpr u32 CATALOG_PROBE_WIDTH = 1280;
constexpr u32 CATALOG_PROBE_HEIGHT = 720;
constexpr u32 CATALOG_PROBE_DEPTH = 8;
std::vector<FxEffectDesc> catalog;
bool catalog_scanned = false;
const reshadefx::annotation* FindAnnotation(const std::vector<reshadefx::annotation>& annotations,
std::string_view name) {
const auto it = std::find_if(annotations.begin(), annotations.end(),
[&](const reshadefx::annotation& a) { return a.name == name; });
if (it == annotations.end()) {
return nullptr;
}
return &*it;
}
std::string AnnotationString(const std::vector<reshadefx::annotation>& annotations,
std::string_view name) {
const reshadefx::annotation* a = FindAnnotation(annotations, name);
if (a == nullptr) {
return std::string();
}
return a->value.string_data;
}
bool AnnotationFloat(const std::vector<reshadefx::annotation>& annotations, std::string_view name,
f32& out) {
const reshadefx::annotation* a = FindAnnotation(annotations, name);
if (a == nullptr) {
return false;
}
if (a->type.is_floating_point()) {
out = a->value.as_float[0];
return true;
}
if (a->type.is_integral()) {
out = static_cast<f32>(a->value.as_int[0]);
return true;
}
return false;
}
FxUiType ParseUiType(std::string_view value) {
if (value == "slider") {
return FxUiType::Slider;
}
if (value == "drag") {
return FxUiType::Drag;
}
if (value == "combo") {
return FxUiType::Combo;
}
if (value == "radio") {
return FxUiType::Radio;
}
if (value == "check" || value == "checkbox") {
return FxUiType::CheckBox;
}
if (value == "color") {
return FxUiType::Color;
}
if (value == "input") {
return FxUiType::InputBox;
}
return FxUiType::Hidden;
}
std::vector<std::string> SplitItems(const std::string& items) {
std::vector<std::string> out;
std::string current;
for (const char c : items) {
if (c == '\0') {
out.push_back(current);
current.clear();
continue;
}
current += c;
}
if (!current.empty()) {
out.push_back(current);
}
return out;
}
FxUniformDesc DescribeUniform(const reshadefx::uniform& info) {
FxUniformDesc desc;
desc.name = info.name;
desc.components = std::min<u32>(info.type.components(), 4);
if (info.type.is_boolean()) {
desc.kind = FxUniformKind::Boolean;
} else if (info.type.is_integral()) {
desc.kind = FxUniformKind::Integer;
} else {
desc.kind = FxUniformKind::Floating;
}
desc.label = AnnotationString(info.annotations, "ui_label");
if (desc.label.empty()) {
desc.label = info.name;
}
desc.tooltip = AnnotationString(info.annotations, "ui_tooltip");
desc.category = AnnotationString(info.annotations, "ui_category");
desc.ui_type = ParseUiType(AnnotationString(info.annotations, "ui_type"));
desc.items = SplitItems(AnnotationString(info.annotations, "ui_items"));
if (desc.kind == FxUniformKind::Boolean) {
desc.ui_min = 0.0f;
desc.ui_max = 1.0f;
desc.ui_step = 1.0f;
} else if (desc.kind == FxUniformKind::Integer) {
desc.ui_min = 0.0f;
desc.ui_max = 100.0f;
desc.ui_step = 1.0f;
}
void(AnnotationFloat(info.annotations, "ui_min", desc.ui_min));
void(AnnotationFloat(info.annotations, "ui_max", desc.ui_max));
void(AnnotationFloat(info.annotations, "ui_step", desc.ui_step));
if (desc.ui_step <= 0.0f) {
desc.ui_step = 0.01f;
if (desc.kind != FxUniformKind::Floating) {
desc.ui_step = 1.0f;
}
}
if (desc.ui_max < desc.ui_min) {
std::swap(desc.ui_min, desc.ui_max);
}
if (info.has_initializer_value) {
for (u32 i = 0; i < desc.components; ++i) {
if (desc.kind == FxUniformKind::Floating) {
desc.default_value[i] = info.initializer_value.as_float[i];
} else {
desc.default_value[i] = static_cast<f32>(info.initializer_value.as_int[i]);
}
}
}
return desc;
}
FxEffectDesc DescribeEffect(const std::filesystem::path& path, const std::filesystem::path& root) {
FxEffectDesc desc;
desc.file = Common::FS::PathToUTF8String(std::filesystem::relative(path, root));
desc.name = Common::FS::PathToUTF8String(path.stem());
const auto compiled =
CompileFxEffect(path, CATALOG_PROBE_WIDTH, CATALOG_PROBE_HEIGHT, CATALOG_PROBE_DEPTH);
if (!compiled.Succeeded()) {
desc.error = compiled.error;
return desc;
}
for (const auto& technique : compiled.module.techniques) {
desc.techniques.push_back(technique.name);
}
if (!compiled.module.techniques.empty()) {
const auto& annotations = compiled.module.techniques.front().annotations;
desc.label = AnnotationString(annotations, "ui_label");
desc.description = AnnotationString(annotations, "ui_tooltip");
}
if (desc.label.empty()) {
desc.label = desc.name;
}
for (const auto& uniform : compiled.module.uniforms) {
FxUniformDesc uniform_desc = DescribeUniform(uniform);
if (uniform_desc.ui_type == FxUiType::Hidden) {
continue;
}
desc.uniforms.push_back(std::move(uniform_desc));
}
return desc;
}
} // Anonymous namespace
std::filesystem::path GetFxRootDirectory() {
return Common::FS::GetEdenPath(Common::FS::EdenPath::PostShaderDir);
}
std::vector<std::filesystem::path> GetFxIncludePaths(const std::filesystem::path& effect_path) {
const auto root = GetFxRootDirectory();
std::vector<std::filesystem::path> paths;
paths.push_back(effect_path.parent_path());
paths.push_back(root);
paths.push_back(root / "Shaders");
const auto last = std::unique(paths.begin(), paths.end());
paths.erase(last, paths.end());
return paths;
}
std::filesystem::path ResolveFxTexturePath(const std::filesystem::path& effect_path,
std::string_view source) {
const auto root = GetFxRootDirectory();
const std::filesystem::path name{source};
const std::array candidates{
effect_path.parent_path() / name,
root / "Textures" / name,
root / name,
};
for (const auto& candidate : candidates) {
if (Common::FS::Exists(candidate)) {
return candidate;
}
}
return std::filesystem::path();
}
void ReloadFxCatalog() {
catalog.clear();
catalog_scanned = true;
const auto root = GetFxRootDirectory();
if (!Common::FS::Exists(root) && !Common::FS::CreateDirs(root)) {
return;
}
for (const auto& bundled : BUNDLED_FX_EFFECTS) {
const auto path = root / bundled.name;
if (Common::FS::Exists(path)) {
continue;
}
void(Common::FS::WriteStringToFile(path, Common::FS::FileType::TextFile, bundled.source));
}
std::vector<std::filesystem::path> effect_files;
Common::FS::IterateDirEntriesRecursively(
root,
[&](const std::filesystem::directory_entry& entry) {
if (entry.path().extension() == ".fx") {
effect_files.push_back(entry.path());
}
return true;
},
Common::FS::DirEntryFilter::File);
std::sort(effect_files.begin(), effect_files.end());
for (const auto& file : effect_files) {
FxEffectDesc desc = DescribeEffect(file, root);
if (!desc.error.empty()) {
LOG_WARNING(Render, "Post-processing effect '{}' failed to compile:\n{}", desc.file,
desc.error);
}
catalog.push_back(std::move(desc));
}
const size_t usable = std::count_if(catalog.begin(), catalog.end(),
[](const FxEffectDesc& d) { return d.Valid(); });
LOG_INFO(Render, "Loaded {} post-processing effects ({} usable)", catalog.size(), usable);
}
const std::vector<FxEffectDesc>& GetFxCatalog() {
if (!catalog_scanned) {
ReloadFxCatalog();
}
return catalog;
}
const FxEffectDesc* FindFxEffect(std::string_view file) {
const auto& effects = GetFxCatalog();
const auto it = std::find_if(effects.begin(), effects.end(),
[&](const FxEffectDesc& d) { return d.file == file; });
if (it == effects.end()) {
return nullptr;
}
return &*it;
}
const FxUniformDesc* FindFxUniform(const FxEffectDesc& effect, std::string_view name) {
const auto it = std::find_if(effect.uniforms.begin(), effect.uniforms.end(),
[&](const FxUniformDesc& u) { return u.name == name; });
if (it == effect.uniforms.end()) {
return nullptr;
}
return &*it;
}
} // namespace VideoCore
@@ -1,77 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <array>
#include <filesystem>
#include <string>
#include <string_view>
#include <vector>
#include "common/common_types.h"
namespace VideoCore {
enum class FxUniformKind {
Boolean,
Integer,
Floating,
};
enum class FxUiType {
Hidden,
Slider,
Drag,
Combo,
Radio,
CheckBox,
Color,
InputBox,
};
struct FxUniformDesc {
std::string name;
std::string label;
std::string tooltip;
std::string category;
FxUniformKind kind{FxUniformKind::Floating};
u32 components{1};
FxUiType ui_type{FxUiType::Hidden};
f32 ui_min{0.0f};
f32 ui_max{1.0f};
f32 ui_step{0.01f};
std::vector<std::string> items;
std::array<f32, 4> default_value{};
};
struct FxEffectDesc {
std::string file;
std::string name;
std::string label;
std::string description;
std::vector<std::string> techniques;
std::vector<FxUniformDesc> uniforms;
std::string error;
bool Valid() const {
return error.empty() && !techniques.empty();
}
};
std::filesystem::path GetFxRootDirectory();
std::vector<std::filesystem::path> GetFxIncludePaths(const std::filesystem::path& effect_path);
std::filesystem::path ResolveFxTexturePath(const std::filesystem::path& effect_path,
std::string_view source);
void ReloadFxCatalog();
const std::vector<FxEffectDesc>& GetFxCatalog();
const FxEffectDesc* FindFxEffect(std::string_view file);
const FxUniformDesc* FindFxUniform(const FxEffectDesc& effect, std::string_view name);
} // namespace VideoCore
@@ -226,22 +226,6 @@ void BufferCacheRuntime::BindIndexBuffer(Buffer& buffer, u32 offset, u32 size) {
} }
} }
void BufferCacheRuntime::BindVertexBuffer(u32 index, Buffer& buffer, u32 offset, u32 size,
u32 stride) {
if (index >= max_attributes) {
return;
}
if (has_unified_vertex_buffers) {
buffer.MakeResident(GL_READ_ONLY);
glBindVertexBuffer(index, 0, 0, static_cast<GLsizei>(stride));
glBufferAddressRangeNV(GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV, index,
buffer.HostGpuAddr() + offset, static_cast<GLsizeiptr>(size));
} else {
glBindVertexBuffer(index, buffer.Handle(), static_cast<GLintptr>(offset),
static_cast<GLsizei>(stride));
}
}
void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings) { void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings) {
// TODO: Should HostBindings provide the correct runtime types to avoid these transforms? // TODO: Should HostBindings provide the correct runtime types to avoid these transforms?
std::array<GLuint, 32> buffer_handles; std::array<GLuint, 32> buffer_handles;
@@ -99,8 +99,6 @@ public:
void BindIndexBuffer(Buffer& buffer, u32 offset, u32 size); void BindIndexBuffer(Buffer& buffer, u32 offset, u32 size);
void BindVertexBuffer(u32 index, Buffer& buffer, u32 offset, u32 size, u32 stride);
void BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings); void BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings);
void BindUniformBuffer(size_t stage, u32 binding_index, Buffer& buffer, u32 offset, u32 size); void BindUniformBuffer(size_t stage, u32 binding_index, Buffer& buffer, u32 offset, u32 size);
@@ -259,6 +259,7 @@ void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) {
} }
void RasterizerOpenGL::Draw(bool is_indexed, u32 instance_count) { void RasterizerOpenGL::Draw(bool is_indexed, u32 instance_count) {
buffer_cache.SetDrawInstanceCount(instance_count);
PrepareDraw(is_indexed, [this, is_indexed, instance_count](GLenum primitive_mode) { PrepareDraw(is_indexed, [this, is_indexed, instance_count](GLenum primitive_mode) {
const auto& draw_state = maxwell3d->draw_manager.draw_state; const auto& draw_state = maxwell3d->draw_manager.draw_state;
const GLuint base_instance = GLuint(draw_state.base_instance); const GLuint base_instance = GLuint(draw_state.base_instance);
@@ -304,6 +305,7 @@ void RasterizerOpenGL::Draw(bool is_indexed, u32 instance_count) {
void RasterizerOpenGL::DrawIndirect() { void RasterizerOpenGL::DrawIndirect() {
const auto& params = maxwell3d->draw_manager.indirect_state; const auto& params = maxwell3d->draw_manager.indirect_state;
buffer_cache.SetDrawIndirect(&params); buffer_cache.SetDrawIndirect(&params);
buffer_cache.SetDrawInstanceCount(0);
PrepareDraw(params.is_indexed, [this, &params](GLenum primitive_mode) { PrepareDraw(params.is_indexed, [this, &params](GLenum primitive_mode) {
if (params.is_byte_count) { if (params.is_byte_count) {
const GPUVAddr tfb_object_base_addr = params.indirect_start_address - 4U; const GPUVAddr tfb_object_base_addr = params.indirect_start_address - 4U;
@@ -18,10 +18,6 @@
#include "video_core/renderer_vulkan/present/sgsr.h" #include "video_core/renderer_vulkan/present/sgsr.h"
#include "video_core/renderer_vulkan/present/fxaa.h" #include "video_core/renderer_vulkan/present/fxaa.h"
#include "video_core/renderer_vulkan/present/layer.h" #include "video_core/renderer_vulkan/present/layer.h"
#ifdef HAS_RESHADE
#include "video_core/post_processing/fx_chain.h"
#include "video_core/renderer_vulkan/present/post_process.h"
#endif
#include "video_core/renderer_vulkan/present/present_push_constants.h" #include "video_core/renderer_vulkan/present/present_push_constants.h"
#include "video_core/renderer_vulkan/present/smaa.h" #include "video_core/renderer_vulkan/present/smaa.h"
#include "video_core/renderer_vulkan/present/util.h" #include "video_core/renderer_vulkan/present/util.h"
@@ -97,9 +93,6 @@ void Layer::ConfigureDraw(const Device& device, PresentPushConstants* out_push_c
RefreshResources(device, framebuffer); RefreshResources(device, framebuffer);
SetAntiAliasPass(device); SetAntiAliasPass(device);
#ifdef HAS_RESHADE
SetPostProcessPass(device);
#endif
// Finish any pending renderpass // Finish any pending renderpass
scheduler.RequestOutsideRenderPassOperationContext(); scheduler.RequestOutsideRenderPassOperationContext();
@@ -122,12 +115,6 @@ void Layer::ConfigureDraw(const Device& device, PresentPushConstants* out_push_c
smaa->Draw(device, scheduler, image_index, &source_image, &source_image_view); smaa->Draw(device, scheduler, image_index, &source_image, &source_image_view);
} }
#ifdef HAS_RESHADE
if (post_process.has_value()) {
post_process->Draw(device, scheduler, image_index, &source_image, &source_image_view);
}
#endif
auto crop_rect = Tegra::NormalizeCrop(framebuffer, texture_width, texture_height); auto crop_rect = Tegra::NormalizeCrop(framebuffer, texture_width, texture_height);
const VkExtent2D render_extent{ const VkExtent2D render_extent{
.width = scaled_width, .width = scaled_width,
@@ -227,40 +214,6 @@ void Layer::SetAntiAliasPass(const Device& device) {
} }
} }
#ifdef HAS_RESHADE
void Layer::SetPostProcessPass(const Device& device) {
const VkExtent2D render_area{
.width = Settings::values.resolution_info.ScaleUp(raw_width),
.height = Settings::values.resolution_info.ScaleUp(raw_height),
};
const u64 generation = VideoCore::FxChain::Instance().Snapshot().generation;
if (post_process_generation == generation && post_process_extent.width == render_area.width &&
post_process_extent.height == render_area.height) {
return;
}
for (const u64 tick : resource_ticks) {
scheduler.Wait(tick);
}
post_process_generation = generation;
post_process_extent = render_area;
post_process.reset();
if (VideoCore::FxChain::Instance().Size() == 0) {
return;
}
post_process.emplace(device, memory_allocator, scheduler, image_count, render_area);
if (post_process->Empty()) {
post_process.reset();
}
}
#endif
void Layer::ReleaseRawImages() { void Layer::ReleaseRawImages() {
for (const u64 tick : resource_ticks) { for (const u64 tick : resource_ticks) {
scheduler.Wait(tick); scheduler.Wait(tick);

Some files were not shown because too many files have changed in this diff Show More