Compare commits

..

18 Commits

Author SHA1 Message Date
CamilleLaVey ffc431848c Refine quick settings fx shader + add presets + polish UI bugs :'v 2026-09-08 22:03:50 -04:00
CamilleLaVey 5b51a960d5 OH MY GOD THIS UI TORTURE 2026-09-08 18:20:17 -04:00
CamilleLaVey a986cc8565 Fix Android builds 2026-09-08 04:38:08 -04:00
CamilleLaVey 5cebeabe03 More math adjustments to shaders + new shader 2026-09-08 04:18:37 -04:00
CamilleLaVey 690c1e9e12 Bump ReShade dependency 2026-09-08 03:29:26 -04:00
CamilleLaVey ecc981bd20 Math reviewed on shaders 2026-09-08 03:18:27 -04:00
CamilleLaVey 7eda109134 Adjustment on the design of UI + new shaders 2026-09-07 17:58:46 -04:00
CamilleLaVey fcaea7d502 Messing around with chromatic aberration fx 2026-09-07 06:20:31 -04:00
CamilleLaVey 80f0239a68 New shaders 2026-09-07 04:55:10 -04:00
CamilleLaVey fa8c5291df Windows final boss 2026-09-07 04:55:10 -04:00
CamilleLaVey 28af06a351 A funny shader. 2026-09-07 04:55:10 -04:00
CamilleLaVey cddcd580e8 Bundle extra shaders ported from PPSSPP 2026-09-07 04:55:10 -04:00
CamilleLaVey 45371b6a3a Fix settings Android 2026-09-07 04:55:10 -04:00
CamilleLaVey 1b5c489ebb Fix settings value 2026-09-07 04:55:10 -04:00
CamilleLaVey 1fdc31de6b some adjustments to the chain enable 2026-09-07 04:55:10 -04:00
CamilleLaVey 6c12de4930 Fix build 2026-09-07 04:55:10 -04:00
CamilleLaVey 151de110b5 add reshade toggle 2026-09-07 04:55:10 -04:00
CamilleLaVey f40461d0ad [vulkan] Initial implementation of post-processing shaders 2026-09-07 04:55:10 -04:00
131 changed files with 15252 additions and 8862 deletions
@@ -0,0 +1,11 @@
--- 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;
+2
View File
@@ -85,6 +85,8 @@ option(ENABLE_WERROR "Enable -Werror diagnostics" ON)
# Lossless Scaling frame generation. Only Android.
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
if (YUZU_USE_BUNDLED_QT AND (APPLE OR NOT UNIX))
set(YUZU_STATIC_BUILD ON)
+8
View File
@@ -238,6 +238,14 @@
"repo": "stachenov/quazip",
"version": "2e95c9001b"
},
"reshade": {
"hash": "6fc9b39821ca6e2d91160f05846b3a42159fec759f5d6fba91d1a57801a1bdaf6047740578c136f0b1a60a9c29ad160d87dbfe0dbfbcdf6ea879a8a078377b8c",
"patches": [
"0001-from-chars-fallback.patch"
],
"repo": "crosire/reshade",
"version": "v6.8.0"
},
"sdl3": {
"hash": "df5a323af7ac366661a3c0e887969c72584d232f3cc211419d59b0487b620b6b2859d4549c9e8df002ee489290062e466fcfddf7edc0872a37b1f2845e81c0f3",
"min_version": "3.2.10",
+328 -320
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+369 -371
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+323 -315
View File
File diff suppressed because it is too large Load Diff
+322 -314
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+335 -327
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+381 -387
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+317 -309
View File
File diff suppressed because it is too large Load Diff
+3
View File
@@ -0,0 +1,3 @@
name=Anime
description=Cel shaded look: the picture is cleaned first, then the lighting is collapsed into flat bands with inked edges, finished with a small glow.
chain=Denoise.fx|Denoise|Strength=0.18,Radius=1.2;CelShading.fx|CelShading|Bands=5,BandContrast=0.35,BandEdge=0.2,Detail=0.7,OutlineStrength=0.7,OutlineThreshold=0.2,Saturation=1.3;Bloom.fx|Bloom|Radius=1.2,Amount=0.25
+3
View File
@@ -0,0 +1,3 @@
name=Cinematic
description=Film look: soft glow on the highlights, a filmic contrast curve, cool shadows against warm highlights, fine grain and a gentle vignette.
chain=Bloom.fx|Bloom|Radius=1.6,Amount=0.35;FilmicCurve.fx|FilmicCurve|Toe=1.35,Shoulder=1.3,Amount=0.85;SplitToning.fx|SplitToning|ShadowHue=210,ShadowStrength=0.25,HighlightHue=38,HighlightStrength=0.3;FilmGrain.fx|FilmGrain|Intensity=0.022;Vignette.fx|Vignette|Strength=0.5
+3
View File
@@ -0,0 +1,3 @@
name=Clean
description=Cleans up a low internal resolution: removes dithering and compression noise, smooths banded skies and brings edge detail back. The safe starting point if you are not sure what you want.
chain=Denoise.fx|Denoise|Strength=0.14,Curve=1.2;Deband.fx|Deband|;Sharpen.fx|Sharpen|Amount=0.75
+3
View File
@@ -0,0 +1,3 @@
name=Dreamy
description=Soft focus: the centre of the screen stays sharp while everything around it blurs, with a wide glow over the highlights. Good for slower games and cutscenes.
chain=Blur.fx|Blur|Radius=6,Strength=0.85,FocusSize=0.28,FocusSoftness=0.5;Bloom.fx|Bloom|Radius=2.0,Amount=0.55
+3
View File
@@ -0,0 +1,3 @@
name=Retro
description=Old television look: colour fringing at the edges of the screen, curved scanlines with a phosphor mask, and darkened corners. The scanline roll is switched off so it does not crawl.
chain=ChromaticAberration.fx|ChromaticAberration|Strength=1.0;CRT.fx|CRT|RollSpeed=0,Bleed=1.2;Vignette.fx|Vignette|Strength=0.7
+3
View File
@@ -0,0 +1,3 @@
name=Vivid
description=Punchier colour without stylising the image: warmer and more saturated, blacks and whites pushed to the ends of the range, and a light sharpen.
chain=NaturalColors.fx|NaturalColors|Luma=1.15,Chroma=1.35;Levels.fx|Levels|InputBlack=0.02,InputWhite=0.98;Sharpen.fx|Sharpen|Amount=0.5
+70
View File
@@ -0,0 +1,70 @@
// 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 = "Bleeds light out of the brightest areas into a soft halo, the way a camera does when pointed at something too bright.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Bloom;
}
}
+87
View File
@@ -0,0 +1,87 @@
// 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
@@ -0,0 +1,74 @@
// 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, for games that were drawn with that kind of screen in mind.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_CRT;
}
}
+79
View File
@@ -0,0 +1,79 @@
// 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, so try Cartoon Soft or Cel Shading if the blacks smear.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Cartoon;
}
}
+100
View File
@@ -0,0 +1,100 @@
// 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 so dark scenes do not turn into black blobs.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_CartoonSoft;
}
}
+120
View File
@@ -0,0 +1,120 @@
// 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
@@ -0,0 +1,53 @@
// 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, the way a cheap lens fails to focus every colour on the same spot.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_ChromaticAberration;
}
}
+64
View File
@@ -0,0 +1,64 @@
// 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 = "The four basic colour controls in one pass: saturation, brightness, contrast and gamma. Reach for this before anything more specialised.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_ColorGrade;
}
}
+91
View File
@@ -0,0 +1,91 @@
// 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. Worth adding whenever large flat areas show rings.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Deband;
}
}
+83
View File
@@ -0,0 +1,83 @@
// 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 while leaving outlines sharp. Ported from Anime4K.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Denoise;
}
}
+65
View File
@@ -0,0 +1,65 @@
// 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
@@ -0,0 +1,60 @@
// 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
@@ -0,0 +1,53 @@
// 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
@@ -0,0 +1,66 @@
// 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
@@ -0,0 +1,88 @@
// 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
@@ -0,0 +1,60 @@
// 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 = "Warms the picture and lifts saturation for a less washed out look. Ported from the PPSSPP shader.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Natural;
}
}
+90
View File
@@ -0,0 +1,90 @@
// 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
@@ -0,0 +1,66 @@
// 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 = "Darkens alternating rows of pixels to imitate the horizontal scanlines of a CRT. Cheaper than the full CRT effect when you only want the lines.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Scanlines;
}
}
+43
View File
@@ -0,0 +1,43 @@
// 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. Most useful after upscaling a low internal resolution.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Sharpen;
}
}
+75
View File
@@ -0,0 +1,75 @@
// 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
@@ -0,0 +1,52 @@
// 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 to pull the eye towards the middle, the way a camera lens falls off at its edges.";
>
{
pass
{
VertexShader = VS_PostProcess;
PixelShader = PS_Vignette;
}
}
+76
View File
@@ -0,0 +1,76 @@
// 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;
}
}
+44
View File
@@ -195,6 +195,50 @@ else()
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
if (YUZU_TESTS OR DYNARMIC_TESTS)
AddJsonPackage(catch2)
@@ -3,6 +3,8 @@
package org.yuzu.yuzu_emu.dialogs
import android.content.res.ColorStateList
import android.graphics.Rect
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
@@ -18,6 +20,7 @@ import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
import org.yuzu.yuzu_emu.fragments.EmulationFragment
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.AbstractShortSetting
import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting
@@ -232,6 +235,395 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
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 addShaderCard(
title: String,
summary: String,
container: ViewGroup,
onRemove: () -> Unit
): ViewGroup {
val inflater = LayoutInflater.from(emulationFragment.requireContext())
val itemView = inflater.inflate(R.layout.item_quick_settings_shader, container, false)
val headerView = itemView.findViewById<ViewGroup>(R.id.shader_header)
val titleView = itemView.findViewById<TextView>(R.id.shader_title)
val summaryView = itemView.findViewById<TextView>(R.id.shader_summary)
val removeView = itemView.findViewById<android.widget.ImageView>(R.id.shader_remove)
val expandIcon = itemView.findViewById<android.widget.ImageView>(R.id.shader_expand)
val bodyView = itemView.findViewById<ViewGroup>(R.id.shader_body)
titleView.text = title
if (summary.isEmpty()) {
summaryView.visibility = View.GONE
} else {
summaryView.text = summary
}
var isExpanded = false
headerView.setOnClickListener {
isExpanded = !isExpanded
if (isExpanded) {
bodyView.visibility = View.VISIBLE
expandIcon.animate().rotation(180f).setDuration(200).start()
} else {
bodyView.visibility = View.GONE
expandIcon.animate().rotation(0f).setDuration(200).start()
}
}
removeView.setOnClickListener {
onRemove()
}
container.addView(itemView)
return bodyView
}
fun addEffectPicker(
container: ViewGroup,
choices: List<String>,
onPicked: (Int) -> Unit
) {
val context = emulationFragment.requireContext()
val inflater = LayoutInflater.from(context)
val itemView = inflater.inflate(R.layout.item_quick_settings_add, container, false)
val button = itemView.findViewById<com.google.android.material.button.MaterialButton>(
R.id.add_button
)
val choiceGroup = itemView.findViewById<RadioGroup>(R.id.add_choices)
choices.forEachIndexed { index, name ->
val radioButton = com.google.android.material.radiobutton.MaterialRadioButton(context)
radioButton.text = name
radioButton.id = View.generateViewId()
radioButton.setPadding(16, 8, 16, 8)
radioButton.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
onPicked(index)
}
}
choiceGroup.addView(radioButton)
}
val closedBackground = MaterialColors.getColor(
button,
com.google.android.material.R.attr.colorSecondaryContainer
)
val closedForeground = MaterialColors.getColor(
button,
com.google.android.material.R.attr.colorOnSecondaryContainer
)
val openBackground = MaterialColors.getColor(
button,
com.google.android.material.R.attr.colorErrorContainer
)
val openForeground = MaterialColors.getColor(
button,
com.google.android.material.R.attr.colorOnErrorContainer
)
val slide = context.resources.displayMetrics.density * 24.0f
var isOpen = false
button.setOnClickListener {
isOpen = !isOpen
if (isOpen) {
choiceGroup.alpha = 0.0f
choiceGroup.translationY = slide
choiceGroup.visibility = View.VISIBLE
choiceGroup.animate()
.alpha(1.0f)
.translationY(0.0f)
.setDuration(220)
.withEndAction {
choiceGroup.requestRectangleOnScreen(
Rect(0, 0, choiceGroup.width, choiceGroup.height),
false
)
}
.start()
button.text = context.getString(R.string.post_processing_hide_effects)
button.setIconResource(R.drawable.ic_clear)
button.backgroundTintList = ColorStateList.valueOf(openBackground)
button.setTextColor(openForeground)
button.iconTint = ColorStateList.valueOf(openForeground)
} else {
choiceGroup.animate()
.alpha(0.0f)
.translationY(slide)
.setDuration(160)
.withEndAction {
choiceGroup.visibility = View.GONE
}
.start()
button.text = context.getString(R.string.post_processing_add)
button.setIconResource(R.drawable.ic_add)
button.backgroundTintList = ColorStateList.valueOf(closedBackground)
button.setTextColor(closedForeground)
button.iconTint = ColorStateList.valueOf(closedForeground)
}
}
container.addView(itemView)
}
fun addPresetBand(container: ViewGroup, name: String, summary: String) {
val inflater = LayoutInflater.from(emulationFragment.requireContext())
val itemView = inflater.inflate(R.layout.item_quick_settings_preset, container, false)
val titleView = itemView.findViewById<TextView>(R.id.preset_title)
val summaryView = itemView.findViewById<TextView>(R.id.preset_summary)
val switchView = itemView.findViewById<MaterialSwitch>(R.id.preset_switch)
titleView.text = name
if (summary.isEmpty()) {
summaryView.visibility = View.GONE
} else {
summaryView.text = summary
}
switchView.isChecked = NativePostProcessing.isEnabled()
switchView.setOnCheckedChangeListener { _, checked ->
NativePostProcessing.setEnabled(checked)
saveSettings()
}
container.addView(itemView)
}
fun addPostProcessing(container: ViewGroup, onStructureChanged: () -> Unit) {
val usable = NativePostProcessing.catalog().filter { it.valid }
if (usable.isEmpty()) {
return
}
val preset = NativePostProcessing.getActivePreset()
if (preset.isNotEmpty()) {
addDivider(container)
var summary =
YuzuApplication.appContext.getString(R.string.post_processing_preset_locked)
if (NativePostProcessing.isPresetModified()) {
summary =
YuzuApplication.appContext.getString(R.string.post_processing_preset_modified)
}
addPresetBand(container, preset, summary)
return
}
val labels = mutableListOf<String>()
val files = mutableListOf<String>()
val techniques = mutableListOf<String>()
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()
chain.forEachIndexed { index, entry ->
val effect = usable.firstOrNull { it.file == entry.file }
var title = entry.file
var summary = ""
if (effect != null) {
title = effect.label
if (effect.techniques.size > 1) {
title = effect.label + " \u00b7 " + entry.technique
}
summary = effect.description
}
val body = addShaderCard(title, summary, container) {
NativePostProcessing.remove(index)
NativePostProcessing.persistFor(emulationFragment.shouldUseCustom)
onStructureChanged()
}
if (effect != null) {
for (uniform in effect.uniforms) {
addUniformSliders(body, index, uniform)
}
}
}
addEffectPicker(container, labels) { picked ->
NativePostProcessing.append(files[picked], techniques[picked])
NativePostProcessing.persistFor(emulationFragment.shouldUseCustom)
onStructureChanged()
}
}
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.persistFor(emulationFragment.shouldUseCustom)
}
}
}
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) {
val inflater = LayoutInflater.from(emulationFragment.requireContext())
val dividerView = inflater.inflate(R.layout.item_quick_settings_divider, container, false)
@@ -0,0 +1,103 @@
// 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,6 +12,7 @@ object Settings {
SECTION_SYSTEM(R.string.preferences_system),
SECTION_RENDERER(R.string.preferences_graphics),
SECTION_FRAME_GEN(R.string.frame_gen),
SECTION_POST_PROCESSING(R.string.post_processing),
SECTION_PERFORMANCE_STATS(R.string.stats_overlay_options),
SECTION_INPUT_OVERLAY(R.string.input_overlay_options),
SECTION_SOC_OVERLAY(R.string.soc_overlay_options),
@@ -13,6 +13,7 @@ enum class StringSetting(override val key: String) : AbstractStringSetting {
DEVICE_NAME("device_name"),
LOG_FILTER("log_filter"),
PROGRAM_ARGS("program_args"),
POST_SHADER_CHAIN("post_shader_chain"),
WEB_TOKEN("eden_token"),
WEB_USERNAME("eden_username")
@@ -0,0 +1,17 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.features.settings.model.view
import androidx.annotation.StringRes
class CardSetting(
@StringRes titleId: Int = 0,
titleString: String = "",
@StringRes descriptionId: Int = 0,
descriptionString: String = "",
val expanded: Boolean,
val runnable: () -> Unit
) : SettingsItem(emptySetting, titleId, titleString, descriptionId, descriptionString) {
override val type = TYPE_CARD
}
@@ -144,6 +144,7 @@ abstract class SettingsItem(
const val TYPE_LAUNCHABLE = 13
const val TYPE_PATH = 14
const val TYPE_GPU_UNSWIZZLE = 15
const val TYPE_CARD = 16
const val FASTMEM_COMBINED = "fastmem_combined"
const val GPU_UNSWIZZLE_COMBINED = "gpu_unswizzle_combined"
@@ -23,6 +23,7 @@ import com.google.android.material.timepicker.TimeFormat
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.SettingsNavigationDirections
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.databinding.ListItemSettingCardBinding
import org.yuzu.yuzu_emu.databinding.ListItemSettingInputBinding
import org.yuzu.yuzu_emu.databinding.ListItemSettingSwitchBinding
import org.yuzu.yuzu_emu.databinding.ListItemSettingsHeaderBinding
@@ -106,6 +107,10 @@ class SettingsAdapter(
GpuUnswizzleViewHolder(ListItemSettingBinding.inflate(inflater), this)
}
SettingsItem.TYPE_CARD -> {
CardViewHolder(ListItemSettingCardBinding.inflate(inflater), this)
}
else -> {
HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this)
}
@@ -18,6 +18,9 @@ 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.AbstractIntSetting
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.IntSetting
import org.yuzu.yuzu_emu.features.settings.model.LongSetting
@@ -30,6 +33,7 @@ import org.yuzu.yuzu_emu.features.settings.model.view.*
import org.yuzu.yuzu_emu.utils.InputHandler
import org.yuzu.yuzu_emu.utils.LosslessScalingHelper
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.FullscreenHelper
import androidx.core.content.edit
@@ -44,6 +48,12 @@ class SettingsFragmentPresenter(
) {
private var settingsList = ArrayList<SettingsItem>()
private val expandedShaderSlots = mutableSetOf<Int>()
private var shaderPickerOpen = false
private var presetPickerOpen = false
private val context get() = YuzuApplication.appContext
// Extension for altering settings list based on each setting's properties
@@ -163,6 +173,7 @@ class SettingsFragmentPresenter(
MenuTag.SECTION_SYSTEM -> addSystemSettings(sl)
MenuTag.SECTION_RENDERER -> addGraphicsSettings(sl)
MenuTag.SECTION_FRAME_GEN -> addFrameGenSettings(sl)
MenuTag.SECTION_POST_PROCESSING -> addPostProcessingSettings(sl)
MenuTag.SECTION_PERFORMANCE_STATS -> addPerformanceOverlaySettings(sl)
MenuTag.SECTION_SOC_OVERLAY -> addSocOverlaySettings(sl)
MenuTag.SECTION_INPUT_OVERLAY -> addInputOverlaySettings(sl)
@@ -190,6 +201,272 @@ 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 active = NativePostProcessing.getActivePreset()
var presetSummary = context.getString(R.string.post_processing_preset_none)
if (active.isNotEmpty()) {
presetSummary = active
if (NativePostProcessing.isPresetModified()) {
presetSummary = context.getString(R.string.post_processing_preset_modified)
}
}
add(
CardSetting(
titleId = R.string.post_processing_preset,
descriptionString = presetSummary,
expanded = presetPickerOpen
) {
presetPickerOpen = !presetPickerOpen
settingsViewModel.setReloadListAndNotifyDataset(true)
}
)
if (presetPickerOpen) {
add(
RunnableSetting(
titleId = R.string.post_processing_preset_none,
isRunnable = true
) {
NativePostProcessing.clearPreset()
presetPickerOpen = false
settingsViewModel.setReloadListAndNotifyDataset(true)
}
)
for (preset in NativePostProcessing.presets()) {
add(
RunnableSetting(
titleString = preset.name,
descriptionString = preset.description,
isRunnable = true
) {
NativePostProcessing.applyPreset(preset.name)
NativePostProcessing.store()
presetPickerOpen = false
expandedShaderSlots.clear()
settingsViewModel.setReloadListAndNotifyDataset(true)
}
)
}
}
if (active.isNotEmpty()) {
add(
RunnableSetting(
titleId = R.string.post_processing_preset_reset,
isRunnable = true
) {
NativePostProcessing.applyPreset(active)
NativePostProcessing.store()
expandedShaderSlots.clear()
settingsViewModel.setReloadListAndNotifyDataset(true)
}
)
}
val labels = mutableListOf<String>()
val summaries = 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)
}
summaries.add(effect.description)
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
if (effect.techniques.size > 1) {
header = effect.label + " \u00b7 " + entry.technique
}
summary = effect.description
}
val isOpen = expandedShaderSlots.contains(index)
add(
CardSetting(
titleString = header,
descriptionString = summary,
expanded = isOpen
) {
if (isOpen) {
expandedShaderSlots.remove(index)
} else {
expandedShaderSlots.add(index)
}
settingsViewModel.setReloadListAndNotifyDataset(true)
}
)
if (!isOpen) {
continue
}
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.store()
expandedShaderSlots.clear()
settingsViewModel.setReloadListAndNotifyDataset(true)
}
)
}
if (index < chain.size - 1) {
add(
RunnableSetting(
titleId = R.string.post_processing_move_down,
isRunnable = true
) {
NativePostProcessing.move(index, 1)
NativePostProcessing.store()
expandedShaderSlots.clear()
settingsViewModel.setReloadListAndNotifyDataset(true)
}
)
}
add(
RunnableSetting(
titleId = R.string.post_processing_reset,
isRunnable = true
) {
NativePostProcessing.resetValues(index)
NativePostProcessing.store()
settingsViewModel.setReloadListAndNotifyDataset(true)
}
)
add(
RunnableSetting(
titleId = R.string.post_processing_remove,
isRunnable = true
) {
NativePostProcessing.remove(index)
NativePostProcessing.store()
expandedShaderSlots.clear()
settingsViewModel.setReloadListAndNotifyDataset(true)
}
)
}
add(
CardSetting(
titleId = R.string.post_processing_add,
expanded = shaderPickerOpen
) {
shaderPickerOpen = !shaderPickerOpen
settingsViewModel.setReloadListAndNotifyDataset(true)
}
)
if (shaderPickerOpen) {
for (choice in labels.indices) {
add(
RunnableSetting(
titleString = labels[choice],
descriptionString = summaries[choice],
isRunnable = true
) {
NativePostProcessing.append(files[choice], techniques[choice])
NativePostProcessing.store()
shaderPickerOpen = false
settingsViewModel.setReloadListAndNotifyDataset(true)
}
)
}
}
}
}
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>) {
sl.apply {
add(
@@ -0,0 +1,42 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.features.settings.ui.viewholder
import android.view.View
import org.yuzu.yuzu_emu.databinding.ListItemSettingCardBinding
import org.yuzu.yuzu_emu.features.settings.model.view.CardSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class CardViewHolder(val binding: ListItemSettingCardBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) {
private lateinit var setting: CardSetting
override fun bind(item: SettingsItem) {
setting = item as CardSetting
binding.textCardName.text = item.title
binding.textCardDescription.text = item.description
binding.textCardDescription.setVisible(item.description.isNotEmpty())
var rotation = 0f
if (setting.expanded) {
rotation = 180f
}
binding.cardExpand.rotation = rotation
}
override fun onClick(clicked: View) {
val target = binding.cardExpand
var rotation = 180f
if (setting.expanded) {
rotation = 0f
}
target.animate().rotation(rotation).setDuration(200).start()
setting.runnable.invoke()
}
override fun onLongClick(clicked: View): Boolean = true
}
@@ -1194,6 +1194,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
R.array.rendererAntiAliasingNames,
R.array.rendererAntiAliasingValues
)
quickSettings.addPostProcessing(container) {
addQuickSettings()
}
}
}
@@ -383,6 +383,20 @@ 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()) {
add(
@@ -171,6 +171,20 @@ 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(
HomeSetting(
R.string.lossless_scaling,
@@ -0,0 +1,234 @@
// 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()
external fun getPresetsJson(): String
external fun getActivePreset(): String
external fun isPresetModified(): Boolean
external fun applyPreset(name: String): Boolean
external fun savePreset(name: String, description: String): Boolean
external fun deletePreset(name: String): Boolean
external fun clearPreset()
external fun isEnabled(): Boolean
external fun setEnabled(enabled: Boolean)
external fun getPresetDirectory(): String
fun persist() {
store()
NativeConfig.saveGlobalConfig()
}
fun persistFor(perGame: Boolean) {
store()
if (perGame) {
NativeConfig.savePerGameConfig()
} else {
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)
data class Preset(
val name: String,
val description: String,
val bundled: Boolean
)
fun presets(): List<Preset> {
val out = mutableListOf<Preset>()
val array = JSONArray(getPresetsJson())
for (i in 0 until array.length()) {
val obj = array.getJSONObject(i)
out.add(
Preset(
name = obj.optString("name"),
description = obj.optString("description"),
bundled = obj.optBoolean("bundled")
)
)
}
return out
}
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,6 +17,7 @@ add_library(yuzu-android SHARED
android_config.cpp
android_config.h
native_input.cpp
native_post_processing.cpp
)
set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR})
@@ -0,0 +1,314 @@
// 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 "common/settings.h"
#include "video_core/post_processing/fx_effect.h"
#include "video_core/post_processing/fx_preset.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
}
jstring Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_getPresetsJson(JNIEnv* env,
jobject obj) {
nlohmann::json out = nlohmann::json::array();
#ifdef HAS_RESHADE
VideoCore::ReloadFxPresetCatalog();
for (const auto& preset : VideoCore::GetFxPresetCatalog()) {
nlohmann::json entry;
entry["name"] = preset.name;
entry["description"] = preset.description;
entry["bundled"] = preset.bundled;
out.push_back(entry);
}
#endif
return Common::Android::ToJString(env, out.dump());
}
jstring Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_getActivePreset(JNIEnv* env,
jobject obj) {
#ifdef HAS_RESHADE
return Common::Android::ToJString(env, VideoCore::GetActiveFxPreset());
#else
return Common::Android::ToJString(env, "");
#endif
}
jboolean Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_isPresetModified(JNIEnv* env,
jobject obj) {
#ifdef HAS_RESHADE
return static_cast<jboolean>(VideoCore::IsActiveFxPresetModified());
#else
return static_cast<jboolean>(false);
#endif
}
jboolean Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_applyPreset(JNIEnv* env, jobject obj,
jstring jname) {
#ifdef HAS_RESHADE
return static_cast<jboolean>(
VideoCore::ApplyFxPreset(Common::Android::GetJString(env, jname)));
#else
return static_cast<jboolean>(false);
#endif
}
jboolean Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_savePreset(JNIEnv* env, jobject obj,
jstring jname,
jstring jdescription) {
#ifdef HAS_RESHADE
return static_cast<jboolean>(
VideoCore::SaveFxPreset(Common::Android::GetJString(env, jname),
Common::Android::GetJString(env, jdescription)));
#else
return static_cast<jboolean>(false);
#endif
}
jboolean Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_deletePreset(JNIEnv* env, jobject obj,
jstring jname) {
#ifdef HAS_RESHADE
return static_cast<jboolean>(
VideoCore::DeleteFxPreset(Common::Android::GetJString(env, jname)));
#else
return static_cast<jboolean>(false);
#endif
}
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_clearPreset(JNIEnv* env, jobject obj) {
#ifdef HAS_RESHADE
VideoCore::SetActiveFxPreset(std::string_view());
#endif
}
jboolean Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_isEnabled(JNIEnv* env, jobject obj) {
#ifdef HAS_RESHADE
return static_cast<jboolean>(Settings::values.post_shader_enabled.GetValue());
#else
return static_cast<jboolean>(false);
#endif
}
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_setEnabled(JNIEnv* env, jobject obj,
jboolean enabled) {
#ifdef HAS_RESHADE
Settings::values.post_shader_enabled.SetValue(enabled != JNI_FALSE);
#endif
}
jstring Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_getPresetDirectory(JNIEnv* env,
jobject obj) {
#ifdef HAS_RESHADE
return Common::Android::ToJString(env, VideoCore::GetFxPresetDirectory().string());
#else
return Common::Android::ToJString(env, "");
#endif
}
} // extern "C"
@@ -0,0 +1,10 @@
<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>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="?attr/colorSurfaceVariant" />
<corners android:radius="16dp" />
<stroke
android:width="1dp"
android:color="?attr/colorOutline" />
</shape>
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.google.android.material.button.MaterialButton
android:id="@+id/add_button"
style="@style/Widget.Material3.Button.TonalButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="4dp"
android:text="@string/post_processing_add"
app:icon="@drawable/ic_add" />
<RadioGroup
android:id="@+id/add_choices"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="24dp"
android:paddingEnd="24dp"
android:paddingTop="4dp"
android:paddingBottom="8dp"
android:visibility="gone" />
</LinearLayout>
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
android:background="@drawable/shader_card_background"
android:orientation="horizontal"
android:paddingStart="20dp"
android:paddingEnd="16dp"
android:paddingTop="16dp"
android:paddingBottom="16dp">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:orientation="vertical">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/preset_title"
style="@style/TextAppearance.Material3.TitleMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/preset_summary"
style="@style/TextAppearance.Material3.BodySmall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textColor="?attr/colorOnSurfaceVariant" />
</LinearLayout>
<com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/preset_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="16dp"
android:minHeight="48dp" />
</LinearLayout>
@@ -0,0 +1,82 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
android:background="@drawable/shader_card_background"
android:orientation="vertical">
<LinearLayout
android:id="@+id/shader_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="16dp"
android:paddingEnd="8dp"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:orientation="vertical">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/shader_title"
style="@style/TextAppearance.Material3.TitleSmall"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/shader_summary"
style="@style/TextAppearance.Material3.BodySmall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:textColor="?attr/colorOnSurfaceVariant" />
</LinearLayout>
<ImageView
android:id="@+id/shader_remove"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center_vertical"
android:padding="8dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true"
android:focusable="true"
android:src="@drawable/ic_delete"
android:contentDescription="@string/post_processing_remove"
app:tint="?attr/colorOnSurfaceVariant" />
<ImageView
android:id="@+id/shader_expand"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:layout_marginStart="4dp"
android:src="@drawable/ic_dropdown_arrow"
android:contentDescription=""
app:tint="?attr/colorPrimary" />
</LinearLayout>
<LinearLayout
android:id="@+id/shader_body"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="8dp"
android:visibility="gone" />
</LinearLayout>
@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
android:background="@drawable/shader_card_background"
android:clickable="true"
android:focusable="true"
android:orientation="horizontal"
android:paddingStart="20dp"
android:paddingEnd="16dp"
android:paddingTop="16dp"
android:paddingBottom="16dp">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:orientation="vertical">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/text_card_name"
style="@style/TextAppearance.Material3.TitleMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/text_card_description"
style="@style/TextAppearance.Material3.BodySmall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textColor="?attr/colorOnSurfaceVariant" />
</LinearLayout>
<ImageView
android:id="@+id/card_expand"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:layout_marginStart="16dp"
android:contentDescription=""
android:src="@drawable/ic_dropdown_arrow"
app:tint="?attr/colorPrimary" />
</LinearLayout>
@@ -106,7 +106,7 @@
<!-- NVDEC Emulation -->
<string name="nvdec_emulation">محاكاة NVDEC</string>
<string name="nvdec_emulation_description">قم بتغيير المعالج المركزي في حالة حدوث عطل أثناء المشاهد السينمائية.</string>
<string name="nvdec_emulation_description">حدد كيفية التعامل مع فك تشفير الفيديو (NVDEC) خلال المشاهد التمهيدية والمقدمة.</string>
<string name="nvdec_emulation_none">لا شيء</string>
<!-- Optimize SPIRV output -->
@@ -292,7 +292,7 @@
<string name="gpu_driver_manager">إدارة برامج تشغيل وحدة معالجة الرسومات</string>
<string name="install_gpu_driver_description">تثبيت برامج تشغيل بديلة لأداء أو دقة أفضل</string>
<string name="frame_gen">توليد الإطار</string>
<string name="frame_gen_per_game_description">ضبط إعدادات إنشاء الإطارات لهذه اللعبة</string>
<string name="frame_gen_per_game_description">تكوين إعدادات إنشاء الإطارات لهذه اللعبة</string>
<string name="frame_gen_description">قم بإدراج الإطارات المُستكملة بين الإطارات المُعالجة باستخدام تقنية التحجيم بدون فقدان الجودة. يُفرض هذا الخيار عرض الإطارات وفقًا لترتيب FIFO عند تفعيله.</string>
<string name="frame_gen_multiplier">مضاعف الإطارات</string>
<string name="frame_gen_multiplier_description">عدد الإطارات المطلوب عرضها لكل إطار مُعالَج. تتطلب القيم الأعلى وقت معالجة رسوميات أكبر. طلب عدد إطارات يفوق قدرة الشاشة على عرضه سيؤدي إلى إبطاء المحاكاة.</string>
@@ -300,7 +300,6 @@
<string name="frame_gen_multiplier_3x">3x</string>
<string name="frame_gen_multiplier_4x">4x</string>
<string name="frame_gen_target_rate">معدل الإطارات المستهدف</string>
<string name="frame_gen_target_rate_description">اختر المعدل الذي يمكن لشاشتك عرضه فعليًّا. عندئذٍ يرتفع المضاعف أو ينخفض تلقائيًّا للحفاظ على هذا المعدل، ويقوم بالتراجع عن أي خطوة تؤدي إلى إبطاء سير اللعبة نفسها.</string>
<string name="frame_gen_target_rate_off">استخدم مضاعفًا ثابتًا</string>
<string name="frame_gen_target_rate_60">60 إطارًا في الثانية</string>
<string name="frame_gen_target_rate_90">90 إطارًا في الثانية</string>
@@ -308,50 +307,6 @@
<string name="frame_gen_target_rate_144">144 إطارًا في الثانية</string>
<string name="frame_gen_target_rate_165">165 إطارًا في الثانية</string>
<string name="frame_gen_queue_target">هدف قائمة انتظار الإطارات</string>
<string name="frame_gen_queue_target_description">كم عدد الإطارات المكتملة التي قد تنتظر قبل عرضها؟ تعمل قوائم الانتظار الأكبر حجمًا على امتصاص الارتفاعات المفاجئة في حمل وحدة معالجة الرسومات على حساب زمن انتقال الإدخال.</string>
<string name="frame_gen_queue_target_0">أقل زمن انتقال (بدون تخزين مؤقت)</string>
<string name="frame_gen_queue_target_1">متوازن (1 إطار)</string>
<string name="frame_gen_queue_target_2">الأكثر سلاسة (2 إطارات)</string>
<string name="frame_gen_flow_scale_auto">تكييف تقدير الحركة مع اللعبة</string>
<string name="frame_gen_flow_scale_auto_description">قم بتقدير الحركة بناءً على الدقة التي تعرضها اللعبة فعليًّا، بدلاً من الإخراج الذي تم رفع دقته. ولا يؤثر ذلك على الدقة بأي شكل، لأن رفع الدقة لا يضيف أي تفاصيل تتعلق بالحركة.</string>
<string name="frame_gen_flow_scale">دقة تقدير الحركة</string>
<string name="frame_gen_flow_scale_description">دقة مسار التدفق البصري، كجزء من الناتج. ويُعد خفض هذه القيمة أرخص طريقة لاستعادة الأداء.</string>
<string name="frame_gen_fp16">مُظلِّلات نصف الدقة</string>
<string name="frame_gen_fp16_description">استخدم نسخة التظليل 16 بت. يتم التراجع تلقائيًا إلى الخيار البديل في حالة عدم توفرها في برنامج التشغيل أو الملف.</string>
<string name="frame_gen_dump_flow">إفراغ الإطار الذي تم إنشاؤه</string>
<string name="frame_gen_dump_flow_description">قم بكتابة مستويات MIP للتدفق البصري والإطار المُستكمل إلى مجلد lossless/debug مرة واحدة، لغرض استكشاف الأخطاء وإصلاحها</string>
<string name="frame_gen_unsupported">توليد الإطار غير متاح</string>
<string name="frame_gen_unsupported_description">لا يدعم برنامج تشغيل وحدة معالجة الرسومات هذا نموذج ذاكرة Vulkan، الذي تتطلبه برامج التظليل الخاصة بـ«Lossless Scaling».</string>
<string name="lossless_scaling_setup_description">اختياري. قم بتوفير ملف Lossless.dll الخاص بك لتمكين إنشاء الإطارات لاحقًا</string>
<string name="lossless_scaling_install">تثبيت ملف Lossless.dll</string>
<string name="lossless_scaling_install_description">يتطلب إنشاء الإطارات أن تكون لديك نسخة قانونية خاصة بك من ملف Lossless.dll المأخوذ من برنامج Lossless Scaling</string>
<string name="lossless_scaling_replace_description">اختر نسخة أخرى من ملف Lossless.dll</string>
<string name="frame_generation_support">توليد الإطارات</string>
<string name="frame_generation_supported">مدعوم</string>
<string name="frame_generation_unsupported">غير مدعوم (لا يتوفر نموذج ذاكرة Vulkan)</string>
<string name="lossless_scaling">Lossless Scaling</string>
<string name="lossless_scaling_description">قم بتوفير نسختك الخاصة من ملف Lossless.dll لتمكين توليد الإطارات</string>
<string name="lossless_scaling_installed">مثبت</string>
<string name="lossless_scaling_not_installed">غير مثبت</string>
<string name="lossless_scaling_replace">استبدل</string>
<string name="lossless_scaling_remove">إزالة</string>
<string name="lossless_scaling_remove_description">احذف ملف Lossless.dll المثبت ووحدات التظليل المعدة له</string>
<string name="lossless_scaling_remove_confirmation">سيتوقف توليد الإطارات عن العمل إلى أن تقوم بتثبيت ملف Lossless.dll مرة أخرى. ولن يتأثر ملفك الأصلي بذلك.</string>
<string name="lossless_scaling_missing">ملف Lossless.dll غير مثبت</string>
<string name="lossless_scaling_missing_description">قم بتثبيته من الإعدادات › Lossless Scaling لاستخدام ميزة توليد الإطارات.</string>
<string name="lossless_scaling_locked">أغلق اللعبة أولاً</string>
<string name="lossless_scaling_locked_description">لا يمكن تعديل ملف Lossless.dll أثناء تشغيل اللعبة.</string>
<string name="lossless_scaling_remove_unavailable">لا يوجد شيء يجب إزالته</string>
<string name="lossless_scaling_remove_unavailable_description">لم يتم تثبيت ملف Lossless.dll بعد.</string>
<string name="lossless_scaling_installing">جاري التحضير لإنشاء مظلّلات الإطارات…</string>
<string name="lossless_scaling_install_success">تم تثبيت ملف Lossless.dll بنجاح</string>
<string name="lossless_scaling_install_failed">تعذر تثبيت ملف Lossless.dll</string>
<string name="error_lossless_copy_failed">تعذر نسخ الملف المحدد.</string>
<string name="error_lossless_unreadable">تعذر قراءة الملف المحدد.</string>
<string name="error_lossless_not_pe">الملف المحدد ليس مكتبة Windows. حدد ملف Lossless.dll من تثبيت برنامج Lossless Scaling.</string>
<string name="error_lossless_missing_shaders">لا تحتوي هذه النسخة من ملف Lossless.dll على برامج التظليل الخاصة بتوليد الإطارات. قم بتحديث ميزة «Lossless Scaling» وحاول مرة أخرى.</string>
<string name="error_lossless_translation_failed">تعذر ترجمة برامج التظليل الخاصة بتوليد الإطارات. هذا الإصدار من «Lossless Scaling» غير مدعوم حتى الآن.</string>
<string name="error_lossless_cache_failed">تعذر كتابة برامج التظليل المترجمة إلى وحدة التخزين. تأكد من توفر مساحة خالية.</string>
<string name="advanced_settings">الإعدادات المتقدمة</string>
<string name="settings_description">ضبط إعدادات المحاكي</string>
<string name="search_recently_played">تم تشغيلها مؤخرًا</string>
@@ -630,10 +585,6 @@
<string name="log">السجلات</string>
<string name="flush_by_line">تفريغ سجلات التصحيح حسب السطر</string>
<string name="flush_by_line_description">يفرغ سجلات التصحيح عند كتابة كل سطر، مما يجعل التصحيح أسهل في حالات التوقف أو التجميد.</string>
<string name="extended_logging">تفعيل التسجيل الموسع</string>
<string name="extended_logging_description">يزيد الحد الأقصى لحجم ملف السجل من 100 ميجابايت إلى 1 جيجابايت.</string>
<string name="log_filter">مرشح السجلات</string>
<string name="log_filter_description">يتحكم في فئات سجلات Eden. مثال: *:Info Service.LM:Debug</string>
<!-- GPU Logging strings -->
<string name="gpu_logging_header">تسجيل وحدة معالجة الرسومات</string>
@@ -710,10 +661,10 @@
<string name="gamecube_controller">ذراع تحكم GameCube</string>
<string name="invert_axis">عكس المحور</string>
<string name="invert_button">عكس الزر</string>
<string name="toggle_button">زر تفعيل/تعطيل</string>
<string name="toggle_button">زر تشغيل/إيقاف</string>
<string name="turbo_button">زر التوربو</string>
<string name="set_threshold">تعيين الحد الفاصل</string>
<string name="toggle_axis">تفعيل/تعطيل المحور</string>
<string name="toggle_axis">تشغيل/إيقاف المحور</string>
<string name="connected">متصل</string>
<string name="use_system_vibrator">استخدم هزاز النظام</string>
<string name="input_overlay">طبقة الإدخال</string>
@@ -852,7 +803,7 @@
<string name="version">الإصدار</string>
<string name="copy_details">نسخ التفاصيل</string>
<string name="add_ons">الإضافات</string>
<string name="add_ons_description">تفعيل/تعطيل التعديلات، التحديثات، المحتوى القابل للتنزيل</string>
<string name="add_ons_description">التعديلات، التحديثات، المحتوى القابل للتنزيل</string>
<string name="playtime">زمن اللعب:</string>
<string name="reset_playtime">مسح زمن اللعب</string>
<string name="reset_playtime_description">إعادة تعيين زمن اللعب للعبة الحالية إلى 0 ثانية</string>
@@ -957,13 +908,13 @@
<!-- Emulation Menu -->
<string name="emulation_exit">خروج من المحاكاة</string>
<string name="emulation_done">إنهاء</string>
<string name="emulation_toggle_controls">تفعيل/تعطيل أزرار التحكم</string>
<string name="emulation_toggle_controls">تشغيل/إيقاف أزرار التحكم</string>
<string name="emulation_rel_stick_center">مركز العصا النسبي</string>
<string name="emulation_dpad_slide">انزلاق الأسهم</string>
<string name="emulation_haptics">الاهتزازات الديناميكية</string>
<string name="emulation_show_overlay">عرض ذراع التحكم</string>
<string name="emulation_hide_overlay">إخفاء ذراع التحكم</string>
<string name="emulation_toggle_all">تفعيل/تعطيل الكل</string>
<string name="emulation_toggle_all">تشغيل/إيقاف الكل</string>
<string name="emulation_control_adjust">ضبط الطبقة</string>
<string name="emulation_control_scale">الحجم</string>
<string name="emulation_control_opacity">الشفافية</string>
@@ -1128,7 +1079,7 @@
<string name="freedreno_info_title">حول إعدادات Freedreno</string>
<string name="freedreno_info_description">قم بإعداد خيارات برنامج تشغيل Freedreno/Turnip لوحدة معالجة الرسومات لأغراض التصحيح، والتحليل، وتحسين الأداء. يتم حفظ التغييرات تلقائيًا. راجع https://docs.mesa3d.org/drivers/freedreno.html للحصول على الوثائق التفصيلية.</string>
<string name="freedreno_per_game_title">إعدادات Freedreno</string>
<string name="freedreno_per_game_description">ضبط إعدادات برنامج تشغيل وحدة معالجة الرسومات لهذه اللعبة</string>
<string name="freedreno_per_game_description">قم بضبط إعدادات برنامج تشغيل وحدة معالجة الرسومات لهذه اللعبة</string>
<string name="freedreno_per_game_saved">تم حفظ إعدادات Freedreno</string>
<!-- Gamepad Buttons -->
@@ -1156,6 +1107,7 @@
<string name="theme_mode_light">فاتح</string>
<string name="theme_mode_dark">داكن</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">خلفيات سوداء</string>
<string name="use_black_backgrounds_description">عند استخدام السمة الداكنة، قم بتطبيق خلفيات سوداء.</string>
@@ -62,6 +62,7 @@
<string name="cpuopt_unsafe_host_mmu_description">ئەم باشکردنە خێرایی دەستکەوتنی بیرگە لەلایەن پرۆگرامی میوانەکە زیاد دەکات. چالاککردنی وای لێدەکات کە خوێندنەوە/نووسینەکانی بیرگەی میوانەکە ڕاستەوخۆ لە بیرگە ئەنجام بدرێت و میمیکردنی MMU میواندە بەکاربهێنێت. ناچالاککردنی ئەمە هەموو دەستکەوتنەکانی بیرگە ڕەت دەکاتەوە لە بەکارهێنانی میمیکردنی MMU نەرمەکاڵا.</string>
<!-- NVDEC Emulation -->
<string name="nvdec_emulation">ئیمولەیشنی NVDEC</string>
<string name="nvdec_emulation_description">هەڵبژاردنی ڕێگای دیکۆدکردنی ڤیدیۆ</string>
<string name="nvdec_emulation_none">هیچ</string>
<!-- Optimize SPIRV output -->
@@ -378,6 +379,7 @@
<string name="log">تۆمارکردن</string>
<string name="flush_by_line">خاوکردنەوەی تۆمارەکانی دیباگ بە هێڵ</string>
<string name="flush_by_line_description">تۆمارەکانی دیباگ لە هەر هێڵێکدا دەنوسرێت خاو دەکاتەوە، ئەمە وا دەکات دیباگکردن ئاسانتر بێت لە کاتی کرشکردن یان پێکەنین.</string>
<!-- Audio settings strings -->
<string name="audio_output_engine">بزوێنری دەرچوونی دەنگ</string>
<string name="audio_volume">دەنگ</string>
@@ -97,6 +97,7 @@
<!-- NVDEC Emulation -->
<string name="nvdec_emulation">Emulace NVDEC</string>
<string name="nvdec_emulation_description">Určuje, jakým způsobem se zpracovává dekódování videa (NVDEC).</string>
<string name="nvdec_emulation_none">Žádné</string>
<!-- Optimize SPIRV output -->
@@ -495,6 +496,7 @@
<string name="log">Protokolování</string>
<string name="flush_by_line">Vypisovat ladicí záznamy po řádcích</string>
<string name="flush_by_line_description">Vypisuje ladicí záznamy po každém napsaném řádku, což usnadňuje ladění v případě pádu nebo zamrznutí.</string>
<!-- Audio settings strings -->
<string name="audio_output_engine">Výstupní engine</string>
<string name="audio_volume">Hlasitost</string>
@@ -64,8 +64,8 @@
<string name="bat_temperature_unit">Batterietemperatur-Einheiten</string>
<string name="show_power_info">Batterieinfo anzeigen</string>
<string name="show_power_info_description">Aktuellen Stromverbrauch und verbleibende Kapazität der Batterie anzeigen</string>
<string name="show_shaders_building">Shader-Erstellung anzeigen</string>
<string name="show_shaders_building_description">Aktuelle Anzahl der erstellten Shader anzeigen</string>
<string name="show_shaders_building">Schattierer-Erstellung anzeigen</string>
<string name="show_shaders_building_description">Aktuelle Anzahl der erstellten Schattierer anzeigen</string>
<string name="pipeline_worker_cores_description">Lege die Anzahl der Kerne fest, die für die Erstellung von Vulkan-Rohrleitungen verwendet werden sollen. Ein höherer Wert verbessert die Kompilierungsleistung der Rohrleitung, führt jedoch auch zu einem Anstieg der Temperaturen.</string>
<string name="overlay_position">Überlagerungs-Position</string>
<string name="overlay_position_description">Wähle aus, wo die Überlagerung auf dem Bildschirm angezeigt wird</string>
@@ -105,7 +105,7 @@
<!-- NVDEC Emulation -->
<string name="nvdec_emulation">NVDEC-Emulation</string>
<string name="nvdec_emulation_description">Wechsle auf CPU, falls ein Absturz bei einem Cinematic auftritt.</string>
<string name="nvdec_emulation_description">Wähle aus, wie die Videodekodierung (NVDEC) während Zwischensequenzen und Intros gehandhabt wird.</string>
<string name="nvdec_emulation_none">Keine</string>
<!-- Optimize SPIRV output -->
@@ -290,38 +290,6 @@
<string name="gpu_driver_fetcher">GPU-Treiber-Hersteller</string>
<string name="gpu_driver_manager">GPU-Treiber Verwaltung</string>
<string name="install_gpu_driver_description">Alternative Treiber für eventuell bessere Leistung oder Genauigkeit installieren</string>
<string name="frame_gen">Frame-Generation</string>
<string name="frame_gen_per_game_description">Konfiguriere Frame-Generation für dieses Spiel</string>
<string name="frame_gen_description">Füge zwischen den gerenderten Bildern interpolierte Bilder mithilfe von Lossless Scaling ein. </string>
<string name="frame_gen_multiplier">Frame-Multiplikator</string>
<string name="frame_gen_multiplier_description">Wie viele Bilder für jedes gerenderte angezeigt werden soll. Höhere Werte kosten proportional mehr GPU-Zeit. Nach mehr zu fragen, als dein Bildschirm darstellen kann, wird die Emulation verlangsamen.</string>
<string name="frame_gen_multiplier_2x">2x</string>
<string name="frame_gen_multiplier_3x">3x</string>
<string name="frame_gen_multiplier_4x">4x</string>
<string name="frame_gen_target_rate">Ziel-Bildrate</string>
<string name="frame_gen_target_rate_description">Wähle die Rate aus die dein Bildschirm tatsächlich darstellen kann. Der Multiplikator steigt oder fällt dann alleine um sie zu halten, und rollt jeden Schritt zurück, der das Spiel selber langsamer macht.</string>
<string name="frame_gen_target_rate_off">Nutze einen fixierten Multiplikator</string>
<string name="frame_gen_target_rate_60">60 FPS</string>
<string name="frame_gen_target_rate_90">90 FPS</string>
<string name="frame_gen_target_rate_120">120 FPS</string>
<string name="frame_gen_target_rate_144">144 FPS</string>
<string name="frame_gen_target_rate_165">165 FPS</string>
<string name="frame_gen_queue_target_1">Ausbalanciert (1 Bild)</string>
<string name="frame_gen_queue_target_2">Flüssigste (2 Bilder)</string>
<string name="frame_gen_unsupported">Frame-Generation nicht verfügbar</string>
<string name="frame_gen_unsupported_description">Dieser GPU-Treiber unterstützt das Vulkan-Memory-Model nicht, welches Lossless Scaling-Shader benötigen.</string>
<string name="lossless_scaling_setup_description">Optional. Stelle deine eigene Lossless.dll zur Verfügung, um Frame-Generation später zu aktivieren.</string>
<string name="lossless_scaling_install">Installiere Lossless.dll</string>
<string name="lossless_scaling_replace_description">Wähle eine andere Kopie von Lossless.dll</string>
<string name="frame_generation_supported">Unterstützt</string>
<string name="frame_generation_unsupported">Nicht unterstützt (kein Vulkan-Memory-Model)</string>
<string name="lossless_scaling">Lossless Scaling</string>
<string name="lossless_scaling_installed">Installiert</string>
<string name="lossless_scaling_not_installed">Nicht installiert</string>
<string name="lossless_scaling_replace">Ersetzen</string>
<string name="lossless_scaling_remove">Entfernen</string>
<string name="lossless_scaling_locked">Schließe zuerst das Spiel</string>
<string name="lossless_scaling_remove_unavailable">Nichts zum Entfernen</string>
<string name="advanced_settings">Erweiterte Einstellungen</string>
<string name="settings_description">Emulatoreinstellungen konfigurieren</string>
<string name="search_recently_played">Kürzlich gespielt</string>
@@ -426,7 +394,6 @@ Wirklich fortfahren?</string>
<string name="copied_to_clipboard">In die Zwischenablage kopiert</string>
<string name="about_app_description">Ein quelloffener Switch-Emulator</string>
<string name="contributors">Beitragende</string>
<string name="contributors_description">Personen, die Eden für Android möglich gemacht haben</string>
<string name="licenses_description">Projekte, die Eden für Android möglich machen </string>
<string name="build">Build</string>
<string name="user_data">Nutzerdaten</string>
@@ -462,8 +429,6 @@ Wird der Handheld-Modus verwendet, verringert es die Auflösung und erhöht die
<string name="use_custom_rtc_description">Ermöglicht Ihnen, eine benutzerdefinierte Echtzeituhr unabhängig von Ihrer aktuellen Systemzeit einzustellen.</string>
<string name="set_custom_rtc">Legen Sie eine benutzerdefinierte Echtzeituhr fest</string>
<!-- CPU -->
<string name="fast_cpu_time">CPU-Takte</string>
<string name="custom_cpu_ticks">Benutzerdefinierte CPU-Ticks</string>
<string name="custom_cpu_ticks_description">Legen Sie einen benutzerdefinierten Wert für CPU-Ticks fest. Höhere Werte können die Leistung steigern, aber auch zum Einfrieren des Spiels führen. Ein Bereich von 7721000 wird empfohlen.</string>
<string name="cpu_ticks">Ticks</string>
@@ -508,14 +473,10 @@ Wird der Handheld-Modus verwendet, verringert es die Auflösung und erhöht die
<string name="renderer_reactive_flushing_description">Verbessert die Genauigkeit in einigen Spielen.</string>
<string name="hacks">Hacks</string>
<string name="fast_gpu_time">GPU-Takte</string>
<string name="skip_cpu_inner_invalidation">CPU-interne Invalidierung überspringen</string>
<string name="skip_cpu_inner_invalidation_description">Überspringt bestimmte Cache-Invalidierungen auf CPU-Seite während Speicherupdates, reduziert die CPU-Auslastung und verbessert die Leistung. Kann in einigen Spielen zu Fehlern oder Abstürzen führen.</string>
<string name="renderer_asynchronous_shaders">Asynchrone Shader</string>
<string name="renderer_asynchronous_shaders_description">Kompiliert Shader asynchron. Dies kann Ruckler reduzieren, aber auch Grafikfehler verursachen.</string>
<string name="gpu_unswizzle_default_button">Standard</string>
<string name="extensions">Erweiterungen</string>
<string name="dyna_state">Erweiterter dynamischer Status</string>
@@ -537,7 +498,6 @@ Wird der Handheld-Modus verwendet, verringert es die Auflösung und erhöht die
<!-- Debug settings strings -->
<string name="cpu">CPU</string>
<string name="clocks">Takte</string>
<string name="use_auto_stub">Auto-Stub verwenden</string>
<string name="use_auto_stub_description">Ergänzt automatisch fehlende Dienste und Funktionen. Kann die Kompatibilität verbessern, aber auch zu Abstürzen und Stabilitätsproblemen führen.</string>
@@ -552,6 +512,7 @@ Wird der Handheld-Modus verwendet, verringert es die Auflösung und erhöht die
<string name="log">Protokollierung</string>
<string name="flush_by_line">Debug-Protokolle zeilenweise leeren</string>
<string name="flush_by_line_description">Leert Debug-Protokolle bei jeder geschriebenen Zeile, was das Debuggen bei Abstürzen oder Einfrieren erleichtert.</string>
<string name="general">Allgemein</string>
<!-- Audio settings strings -->
@@ -792,7 +753,6 @@ Wirklich fortfahren?</string>
<string name="confirm_uninstall">Bestätigen Sie die Deinstallation</string>
<string name="confirm_uninstall_description">Möchten Sie dieses Add-on wirklich deinstallieren\?</string>
<string name="verify_integrity">Integrität prüfen</string>
<string name="verifying">Verifiziere...</string>
<string name="verify_success">Integritätsüberprüfung erfolgreich!</string>
<string name="verify_failure">Integritätsüberprüfung fehlgeschlagen!</string>
<string name="verify_failure_description">Der Dateiinhalt ist möglicherweise beschädigt</string>
@@ -914,16 +874,6 @@ Wirklich fortfahren?</string>
<string name="memory_6gb">6 GB (Unsicher)</string>
<string name="memory_8gb">8 GB (Unsicher)</string>
<!-- CPU clock levels -->
<string name="clock_normal">Normal</string>
<string name="clock_boost">Beschleunigung</string>
<string name="clock_fast">Übertaktung</string>
<!-- GPU clock levels -->
<string name="fast_gpu_normal">Normal</string>
<string name="fast_gpu_medium">Beschleunigung</string>
<string name="fast_gpu_high">Übertaktung</string>
<!-- GPU swizzle texture size -->
<string name="gpu_texturesizeswizzle_verysmall">Sehr klein (16 MB)</string>
<string name="gpu_texturesizeswizzle_small">Klein (32 MB)</string>
@@ -969,13 +919,6 @@ Wirklich fortfahren?</string>
<string name="dma_accuracy_unsafe">Unsicher</string>
<string name="dma_accuracy_safe">Sicher</string>
<!-- GPU Fence Behavior -->
<string name="gpu_fence_behavior_default">Standard</string>
<string name="gpu_fence_behavior_immediate">Direkt</string>
<string name="gpu_fence_behavior_balanced">Ausgewogen</string>
<string name="gpu_fence_behavior_accurate">Genau</string>
<string name="gpu_fence_behavior_strict">Strikt</string>
<string name="vram_usage_conservative">Konservativ</string>
<string name="vram_usage_aggressive">Aggressiv</string>
@@ -1042,32 +985,27 @@ Wirklich fortfahren?</string>
<string name="theme_material_you">Material You</string>
<string name="app_settings">App-Einstellungen</string>
<string name="theme_and_color">Theme und Farben</string>
<string name="fullscreen_mode">Vollbild-Modus</string>
<!-- Theme Modes -->
<string name="change_theme_mode">Design</string>
<string name="theme_mode_follow_system">System folgen</string>
<string name="theme_mode_light">Hell</string>
<string name="theme_mode_dark">Dunkel</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Schwarze Hintergründe</string>
<string name="use_black_backgrounds_description">Bei Verwendung des dunklen Designs, schwarze Hintergründe verwenden.</string>
<!-- Buttons -->
<string name="enable_folder_button">Ordner</string>
<string name="enable_qlaunch_button">QLaunch</string>
<!-- App Language -->
<string name="app_language">App-Sprache</string>
<string name="app_language_description">Sprache der App-Oberfläche ändern</string>
<string name="app_language_system">System folgen</string>
<!-- Static Themes -->
<string name="static_theme_color">Designfarbe</string>
<string name="eden_theme">Eden</string>
<string name="violet">Violett </string>
<string name="blue">Blau</string>
<string name="cyan">Cyan</string>
<string name="red">Rot</string>
<string name="green">Grün</string>
<string name="yellow">Gelb</string>
<string name="orange">Orange</string>
<string name="pink">Rosa</string>
@@ -1099,10 +1037,6 @@ Wirklich fortfahren?</string>
<string name="enable_overlay">Applet-Overlay aktivieren</string>
<string name="enable_overlay_description">Aktiviert Horizons eingebautes Overlay-Applet. Halte die Home-Taste eine Sekunde lang gedrückt, um es anzuzeigen.</string>
<!-- Profile Management -->
<string name="profile_manager">Nutzerverwaltung</string>
<string name="error">Fehler</string>
<!-- Licenses screen strings -->
<string name="licenses">Lizenzen</string>
<string name="license_fidelityfx_fsr_description">Hochwertiges Upscaling von AMD</string>
@@ -106,6 +106,7 @@
<!-- NVDEC Emulation -->
<string name="nvdec_emulation">Emulación NVDEC</string>
<string name="nvdec_emulation_description">Seleccione cómo se maneja la decodificación de vídeo (NVDEC) durante las escenas y las introducciones.</string>
<string name="nvdec_emulation_none">Ninguno</string>
<!-- Optimize SPIRV output -->
@@ -291,41 +292,22 @@
<string name="gpu_driver_manager">Gestor de controladores de la GPU</string>
<string name="install_gpu_driver_description">Instale los controladores alternativos para obtener un posible mejor rendimiento o precisión</string>
<string name="frame_gen">Generación de fotograma</string>
<string name="frame_gen_per_game_description">Configurar la generación de fotogramas para este juego</string>
<string name="frame_gen_multiplier">Multiplicador de fotograma</string>
<string name="frame_gen_multiplier_2x">2x</string>
<string name="frame_gen_multiplier_3x">3x</string>
<string name="frame_gen_multiplier_4x">4x</string>
<string name="frame_gen_target_rate">Objetivo de tasa de fotogramas</string>
<string name="frame_gen_target_rate_off">Usar un multiplicador fijo</string>
<string name="frame_gen_target_rate_60">60 FPS</string>
<string name="frame_gen_target_rate_90">90 FPS</string>
<string name="frame_gen_target_rate_120">120 FPS</string>
<string name="frame_gen_target_rate_144">144 FPS</string>
<string name="frame_gen_target_rate_165">165 FPS</string>
<string name="frame_gen_queue_target_0">Latencia más baja (Sin búfer)</string>
<string name="frame_gen_queue_target_1">Equilibrado (1 fotograma)</string>
<string name="frame_gen_queue_target_2">Más suave (2 fotogramas)</string>
<string name="frame_gen_fp16">Sombreadores de media precisión</string>
<string name="frame_gen_unsupported">Generación de fotogramas no disponbile</string>
<string name="lossless_scaling_install">Instalar Lossless.dll</string>
<string name="lossless_scaling_replace_description">Seleccionar una copia diferente de Lossless.dll</string>
<string name="frame_generation_support">Generación de fotograma</string>
<string name="frame_generation_supported">Soportado</string>
<string name="frame_generation_unsupported">No soportado (sin modelo de memoria de Vulkan)</string>
<string name="lossless_scaling">Escalado sin pérdidas</string>
<string name="lossless_scaling_installed">Instalado</string>
<string name="lossless_scaling_not_installed">No instalado</string>
<string name="lossless_scaling_replace">Reemplazar</string>
<string name="lossless_scaling_remove">Borrar</string>
<string name="lossless_scaling_remove_description">Borrar Lossless.dll instalado y sus sombreadores preparados</string>
<string name="lossless_scaling_missing">Lossless.dll no instalado</string>
<string name="lossless_scaling_locked">Primero cierra el juego</string>
<string name="lossless_scaling_remove_unavailable">Nada que borrar</string>
<string name="lossless_scaling_install_success">Lossless.dll instalado correctamente</string>
<string name="lossless_scaling_install_failed">No se pudo instalar Lossless.dll</string>
<string name="error_lossless_copy_failed">No se pudo copiar el archivo seleccionado.</string>
<string name="error_lossless_unreadable">No se pudo leer el archivo seleccionado.</string>
<string name="advanced_settings">Ajustes avanzados</string>
<string name="settings_description">Configurar los ajustes del emulador</string>
<string name="search_recently_played">Jugado recientemente</string>
@@ -472,8 +454,6 @@
<string name="use_custom_rtc_description">Le permite tener un reloj personalizado en tiempo real diferente de la hora de su sistema.</string>
<string name="set_custom_rtc">Configurar RTC personalizado</string>
<!-- CPU -->
<string name="fast_cpu_time">Relojes de la CPU</string>
<string name="custom_cpu_ticks">Ticks de CPU personalizados</string>
<string name="custom_cpu_ticks_description">Establezca un valor personalizado de los ciclos de la CPU. Los valores más altos pueden aumentar el rendimiento, pero también pueden hacer que el juego se congele. Se recomienda un rango de 7721000.</string>
<string name="cpu_ticks">Ciclos</string>
@@ -532,7 +512,6 @@
<string name="hacks">Hacks</string>
<string name="fast_gpu_time">Relojes de la GPU</string>
<string name="skip_cpu_inner_invalidation">Omitir invalidación interna de la CPU</string>
<string name="skip_cpu_inner_invalidation_description">Omite ciertas invalidaciones de caché de la CPU durante las actualizaciones de memoria, lo que reduce el uso de la CPU y mejora su rendimiento. Esto puede causar fallos o bloqueos en algunos juegos.</string>
<string name="fix_bloom_effects">Arreglar los efectos de resplandor</string>
@@ -579,7 +558,6 @@
<!-- Debug settings strings -->
<string name="cpu">CPU</string>
<string name="clocks">Relojes</string>
<string name="use_auto_stub">Usar Auto Stub</string>
<string name="use_auto_stub_description">Rellena automáticamente servicios y funciones ausentes. Puede mejorar la compatibilidad pero puede causar cierres inesperados.</string>
@@ -594,8 +572,6 @@
<string name="log">Registro</string>
<string name="flush_by_line">Vaciar los registros de depuración por línea</string>
<string name="flush_by_line_description">Vacía los registros de depuración en cada línea escrita, facilitando la depuración en casos de bloqueos o congelamientos.</string>
<string name="log_filter">Filtro de registros</string>
<string name="log_filter_description">Controla las categorias de registros de Eden. Por ejemplo: *:Info Service.LM:Debug</string>
<!-- GPU Logging strings -->
<string name="gpu_logging_header">Registros de la GPU</string>
@@ -983,12 +959,10 @@
<!-- CPU clock levels -->
<string name="clock_normal">Normal</string>
<string name="clock_boost">Impulso</string>
<string name="clock_fast">Overclock</string>
<!-- GPU clock levels -->
<string name="fast_gpu_normal">Normal</string>
<string name="fast_gpu_medium">Impulso</string>
<string name="fast_gpu_high">Overclock</string>
<!-- GPU swizzle texture size -->
@@ -1118,6 +1092,7 @@
<string name="theme_mode_light">Claro</string>
<string name="theme_mode_dark">Oscuro</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Fondos oscuros</string>
<string name="use_black_backgrounds_description">Cuando se usa el modo oscuro, aplicar fondos de pantalla negros.</string>
@@ -104,6 +104,7 @@
<!-- NVDEC Emulation -->
<string name="nvdec_emulation">Émulation NVDEC</string>
<string name="nvdec_emulation_description">Sélectionnez la manière dont le décodage vidéo (NVDEC) est géré pendant les cinématiques et les intros.</string>
<string name="nvdec_emulation_none">Aucun</string>
<!-- Optimize SPIRV output -->
@@ -517,6 +518,7 @@
<string name="log">Journalisation</string>
<string name="flush_by_line">Vider les journaux de débogage ligne par ligne</string>
<string name="flush_by_line_description">Vide les journaux de débogage à chaque ligne écrite, facilitant le débogage en cas de plantage ou de gel.</string>
<!-- GPU Logging strings -->
<string name="gpu_logging_header">Journalisation GPU</string>
<string name="gpu_log_level">Niveau de journalisation</string>
@@ -1002,6 +1004,7 @@
<string name="theme_mode_light">Lumineux</string>
<string name="theme_mode_dark">Sombre</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Arrière-plan noir</string>
<string name="use_black_backgrounds_description">Lorsque vous utilisez le thème sombre, appliquer un arrière-plan noir.</string>
@@ -67,6 +67,7 @@
<string name="debug_knobs_description">לשימוש בפיתוח בלבד.</string>
<!-- NVDEC Emulation -->
<string name="nvdec_emulation">אמולציית NVDEC</string>
<string name="nvdec_emulation_description">בחר כיצד לטפל בפענוח וידאו</string>
<string name="nvdec_emulation_none">ללא</string>
<!-- Optimize SPIRV output -->
@@ -407,6 +408,7 @@
<string name="log">רישום</string>
<string name="flush_by_line">רוקן יומני ניפוי שגיאות לפי שורה</string>
<string name="flush_by_line_description">מרוקן יומני ניפוי שגיאות בכל שורה שנכתבת, מה שמקל על ניפוי שגיאות במקרים של קריסה או קיפאון.</string>
<!-- Audio settings strings -->
<string name="audio_output_engine">מנוע פלט</string>
<string name="audio_volume">עוצמת שמע</string>
@@ -62,6 +62,7 @@
<string name="cpuopt_unsafe_host_mmu_description">Ez az optimalizáció gyorsítja a vendégprogram memória-hozzáférését. Engedélyezése esetén a vendég memóriaolvasási/írási műveletei közvetlenül a memóriában történnek, és kihasználják a gazda MMU-ját. Letiltás esetén minden memória-hozzáférés a szoftveres MMU emulációt használja.</string>
<!-- NVDEC Emulation -->
<string name="nvdec_emulation">NVDEC emuláció</string>
<string name="nvdec_emulation_description">Videódekódolás kezelése</string>
<string name="nvdec_emulation_none">Nincs</string>
<!-- Optimize SPIRV output -->
@@ -395,6 +396,7 @@
<string name="log">Naplózás</string>
<string name="flush_by_line">Hibakeresési naplók soronkénti kiürítése</string>
<string name="flush_by_line_description">Kiüríti a hibakeresési naplókat minden írt sor után, megkönnyítve a hibakeresést összeomlás vagy fagyás esetén.</string>
<!-- Audio settings strings -->
<string name="audio_output_engine">Kimeneti motor</string>
<string name="audio_volume">Hangerő</string>
@@ -81,6 +81,7 @@
<string name="cpuopt_unsafe_host_mmu_description">Optimasi ini mempercepat akses memori oleh program tamu. Mengaktifkannya menyebabkan pembacaan/penulisan memori tamu dilakukan langsung ke memori dan memanfaatkan MMU Host. Menonaktifkan ini memaksa semua akses memori menggunakan Emulasi MMU Perangkat Lunak.</string>
<!-- NVDEC Emulation -->
<string name="nvdec_emulation">Emulasi NVDEC</string>
<string name="nvdec_emulation_description">Pilih cara decoding video (NVDEC) ditangani selama cutscene dan intro.</string>
<string name="nvdec_emulation_none">Tidak Ada</string>
<!-- Optimize SPIRV output -->
@@ -429,6 +430,7 @@
<string name="log">Pencatatan</string>
<string name="flush_by_line">Buang log debug per baris</string>
<string name="flush_by_line_description">Membuang log debug pada setiap baris yang ditulis, memudahkan debugging dalam kasus crash atau freeze.</string>
<!-- Audio settings strings -->
<string name="audio_output_engine">Output audio</string>
<string name="audio_volume">Volume</string>
@@ -79,6 +79,7 @@
<string name="cpuopt_unsafe_host_mmu_description">Questa ottimizzazione accelera gli accessi alla memoria da parte del programma guest. Abilitandola, le letture/scritture della memoria guest vengono eseguite direttamente in memoria e sfruttano la MMU host. Disabilitandola, tutti gli accessi alla memoria sono costretti a utilizzare l\'emulazione software della MMU.</string>
<!-- NVDEC Emulation -->
<string name="nvdec_emulation">Emulazione NVDEC</string>
<string name="nvdec_emulation_description">Scegli come gestire la decodifica video</string>
<string name="nvdec_emulation_none">Nessuna</string>
<!-- Optimize SPIRV output -->
@@ -436,6 +437,7 @@
<string name="log">Registrazione</string>
<string name="flush_by_line">Svuota i log di debug per riga</string>
<string name="flush_by_line_description">Svuota i log di debug su ogni riga scritta, facilitando il debug in caso di crash o blocco.</string>
<!-- Audio settings strings -->
<string name="audio_output_engine">Motore di Output</string>
<string name="audio_volume">Volume</string>
@@ -62,6 +62,7 @@
<string name="cpuopt_unsafe_host_mmu_description">この最適化により、ゲストプログラムによるメモリアクセスが高速化されます。有効にすると、ゲストのメモリ読み書きが直接メモリ内で実行され、ホストのMMUを利用します。無効にすると、すべてのメモリアクセスでソフトウェアMMUエミュレーションが使用されます。</string>
<!-- NVDEC Emulation -->
<string name="nvdec_emulation">NVDECエミュレーション</string>
<string name="nvdec_emulation_description">ビデオデコード方法</string>
<string name="nvdec_emulation_none">無効</string>
<!-- Optimize SPIRV output -->
@@ -397,6 +398,7 @@
<string name="log">ロギング</string>
<string name="flush_by_line">デバッグログを行ごとにフラッシュ</string>
<string name="flush_by_line_description">デバッグログを行ごとにフラッシュし、クラッシュやフリーズ時のデバッグを容易にします。</string>
<!-- Audio settings strings -->
<string name="audio_output_engine">出力エンジン</string>
<string name="audio_volume">音量</string>
@@ -62,6 +62,7 @@
<string name="cpuopt_unsafe_host_mmu_description">이 최적화는 게스트 프로그램의 메모리 접근 속도를 높입니다. 활성화하면 게스트의 메모리 읽기/쓰기가 메모리에서 직접 수행되고 호스트의 MMU를 활용합니다. 비활성화하면 모든 메모리 접근에 소프트웨어 MMU 에뮬레이션을 사용하게 됩니다.</string>
<!-- NVDEC Emulation -->
<string name="nvdec_emulation">NVDEC 에뮬레이션</string>
<string name="nvdec_emulation_description">비디오 디코딩 처리 방식 선택</string>
<string name="nvdec_emulation_none">없음</string>
<!-- Optimize SPIRV output -->
@@ -397,6 +398,7 @@
<string name="log">로깅</string>
<string name="flush_by_line">디버그 로그를 줄별로 플러시</string>
<string name="flush_by_line_description">디버그 로그를 각 줄마다 플러시하여 충돌 또는 정지 시 디버깅을 용이하게 합니다.</string>
<!-- Audio settings strings -->
<string name="audio_output_engine">출력 엔진</string>
<string name="audio_volume">볼륨</string>
@@ -62,6 +62,7 @@
<string name="cpuopt_unsafe_host_mmu_description">Denne optimaliseringen fremskynder minnetilgang av gjesteprogrammet. Hvis aktivert, utføres gjestens minnelesing/skriving direkte i minnet og bruker vertens MMU. Deaktivering tvinger alle minnetilganger til å bruke programvarebasert MMU-emulering.</string>
<!-- NVDEC Emulation -->
<string name="nvdec_emulation">NVDEC-emulering</string>
<string name="nvdec_emulation_description">Velg hvordan videodekoding håndteres</string>
<string name="nvdec_emulation_none">Ingen</string>
<!-- Optimize SPIRV output -->
@@ -378,6 +379,7 @@
<string name="log">Logging</string>
<string name="flush_by_line">Tøm feilsøkingslogger per linje</string>
<string name="flush_by_line_description">Tømmer feilsøkingslogger for hver linje som skrives, noe som gjør feilsøking enklere ved krasj eller frysing.</string>
<!-- Audio settings strings -->
<string name="audio_output_engine">Lydmotor</string>
<string name="audio_volume">Volum</string>
@@ -97,6 +97,7 @@
<!-- NVDEC Emulation -->
<string name="nvdec_emulation">Emulacja NVDEC</string>
<string name="nvdec_emulation_description">Wybierz metodę dekodowania wideo (NVDEC).</string>
<string name="nvdec_emulation_none">Brak</string>
<!-- Optimize SPIRV output -->
@@ -499,6 +500,7 @@
<string name="log">Rejestrowanie</string>
<string name="flush_by_line">Opróżniaj dzienniki debugowania linia po linii</string>
<string name="flush_by_line_description">Opróżnia dzienniki debugowania po każdej napisanej linii, ułatwiając debugowanie w przypadku awarii lub zawieszenia.</string>
<string name="general">Ogólne</string>
<!-- Audio settings strings -->
@@ -933,6 +935,7 @@
<string name="theme_mode_light">Jasny</string>
<string name="theme_mode_dark">Ciemny</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Czarne tła</string>
<string name="use_black_backgrounds_description">Kiedy używany ciemny motyw, tła zostają zastąpione czernią.</string>
@@ -91,6 +91,7 @@
<!-- NVDEC Emulation -->
<string name="nvdec_emulation">Decodificação de Vídeo (NVDEC)</string>
<string name="nvdec_emulation_description">Selecione como a decodificação de vídeo é realizada durante cutscenes e intros.</string>
<string name="nvdec_emulation_none">Nenhum</string>
<!-- Optimize SPIRV output -->
@@ -482,6 +483,7 @@
<string name="log">Registro</string>
<string name="flush_by_line">Liberar logs de depuração por linha</string>
<string name="flush_by_line_description">Libera logs de depuração em cada linha escrita, facilitando a depuração em casos de travamento ou congelamento.</string>
<string name="general">Geral</string>
<!-- Audio settings strings -->
@@ -889,6 +891,7 @@
<string name="theme_mode_light">Claro</string>
<string name="theme_mode_dark">Escuro</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Planos de fundo pretos</string>
<string name="use_black_backgrounds_description">Quando usar o tema escuro, aplicar fundos pretos</string>
@@ -62,6 +62,7 @@
<string name="cpuopt_unsafe_host_mmu_description">Esta otimização acelera os acessos à memória pelo programa convidado. Ativar faz com que as leituras/escritas de memória do convidado sejam efetuadas diretamente na memória e utilizem a MMU do Anfitrião. Desativar força todos os acessos à memória a usar a Emulação de MMU por Software.</string>
<!-- NVDEC Emulation -->
<string name="nvdec_emulation">Emulação NVDEC</string>
<string name="nvdec_emulation_description">Método de decodificação de vídeo.</string>
<string name="nvdec_emulation_none">Nenhum</string>
<!-- Optimize SPIRV output -->
@@ -401,6 +402,7 @@
<string name="log">Registo</string>
<string name="flush_by_line">Libertar registos de depuração por linha</string>
<string name="flush_by_line_description">Liberta registos de depuração em cada linha escrita, facilitando a depuração em casos de falha ou congelamento.</string>
<!-- Audio settings strings -->
<string name="audio_output_engine">Motor de saída</string>
<string name="audio_volume">Volume</string>
@@ -106,7 +106,7 @@
<!-- NVDEC Emulation -->
<string name="nvdec_emulation">Эмуляция NVDEC</string>
<string name="nvdec_emulation_description">Переключите на CPU, если происходит вылет на кат-сценах.</string>
<string name="nvdec_emulation_description">Обработка видео (ролики, интро)</string>
<string name="nvdec_emulation_none">Отключено</string>
<!-- Optimize SPIRV output -->
@@ -291,58 +291,6 @@
<string name="gpu_driver_fetcher">Получение драйверов ГПУ</string>
<string name="gpu_driver_manager">Менеджер драйверов ГПУ</string>
<string name="install_gpu_driver_description">Установите альтернативные драйверы для потенциально лучшей производительности и/или точности</string>
<string name="frame_gen">Генерация кадров</string>
<string name="frame_gen_per_game_description">Настройка генерации кадров для данной игры</string>
<string name="frame_gen_description">Вставляет промежуточные кадры между отрендеренными с помощью Lossless Scaling. При включении принудительно устанавливает режим вывода FIFO.</string>
<string name="frame_gen_multiplier">Множитель кадров</string>
<string name="frame_gen_multiplier_description">Количество кадров, отображаемых на каждый отрисованный кадр. Повышение значения пропорционально увеличивает затраты ресурсов ГПУ. Если запрашивать больше, чем может отобразить ваш экран, эмуляция будет замедляться.</string>
<string name="frame_gen_target_rate">Целевая частота кадров</string>
<string name="frame_gen_target_rate_description">Выберите значение под ваш дисплей. Множитель подстроится сам, чтобы его держать, и откатит изменения, если игра начнёт тормозить.</string>
<string name="frame_gen_target_rate_off">Использовать фиксированный множитель</string>
<string name="frame_gen_queue_target">Целевой размер очереди кадров</string>
<string name="frame_gen_queue_target_description">Сколько готовых кадров может ожидать перед выводом на экран. Более длинные очереди сглаживают скачки ГПУ ценой задержки ввода.</string>
<string name="frame_gen_queue_target_0">Минимальная задержка (Без буферизации)</string>
<string name="frame_gen_queue_target_1">Сбалансированный (1 кадр)</string>
<string name="frame_gen_queue_target_2">Наиболее плавный (2 кадра)</string>
<string name="frame_gen_flow_scale_auto">Подстроить оценку движения под игру</string>
<string name="frame_gen_flow_scale_auto_description">Оценивать движение в разрешении, которое игра действительно рендерит, вместо масштабированного вывода. Ничего не стоит в точности, так как масштабирование не добавляет деталей движения.</string>
<string name="frame_gen_flow_scale">Разрешение оценки движения</string>
<string name="frame_gen_flow_scale_description">Разрешение прохода оптического потока в долях от выходного разрешения. Его понижение — самый дешёвый способ вернуть производительность.</string>
<string name="frame_gen_fp16">Шейдеры половинной точности</string>
<string name="frame_gen_fp16_description">Использовать 16-битную версию шейдеров. Автоматически переключается на обычную, если драйвер или файл не поддерживают её.</string>
<string name="frame_gen_dump_flow">Сохранить сгенерированный кадр</string>
<string name="frame_gen_dump_flow_description">Однократно записать уровни мип-карт оптического потока и интерполированный кадр в папку lossless/debug для диагностики.</string>
<string name="frame_gen_unsupported">Генерация кадров недоступна</string>
<string name="frame_gen_unsupported_description">Драйвер ГПУ не поддерживает модель памяти Vulkan, требуемую шейдерами Lossless Scaling.</string>
<string name="lossless_scaling_setup_description">Опционально. Укажите свой Lossless.dll для включения генерации кадров позже.</string>
<string name="lossless_scaling_install">Установить Lossless.dll</string>
<string name="lossless_scaling_install_description">Для генерации кадров требуется ваша собственная легальная копия Lossless.dll из Lossless Scaling</string>
<string name="lossless_scaling_replace_description">Выбрать другой файл Lossless.dll</string>
<string name="frame_generation_support">Генерация кадров</string>
<string name="frame_generation_supported">Поддерживается</string>
<string name="frame_generation_unsupported">Не поддерживается (нет модели памяти Vulkan)</string>
<string name="lossless_scaling_description">Предоставьте свою копию Lossless.dll для включения генерации кадров</string>
<string name="lossless_scaling_installed">Установлена</string>
<string name="lossless_scaling_not_installed">Не установлена</string>
<string name="lossless_scaling_replace">Заменить</string>
<string name="lossless_scaling_remove">Удалить</string>
<string name="lossless_scaling_remove_description">Удалить установленный Lossless.dll и его подготовленные шейдеры</string>
<string name="lossless_scaling_remove_confirmation">Генерация кадров перестанет работать, пока вы снова не установите Lossless.dll. Ваш исходный файл не пострадает.</string>
<string name="lossless_scaling_missing">Lossless.dll не установлен</string>
<string name="lossless_scaling_missing_description">Установите его через Настройки › Lossless Scaling для использования генерации кадров.</string>
<string name="lossless_scaling_locked">Сначала закройте игру</string>
<string name="lossless_scaling_locked_description">Lossless.dll нельзя изменить, пока запущена игра.</string>
<string name="lossless_scaling_remove_unavailable">Нечего удалять.</string>
<string name="lossless_scaling_remove_unavailable_description">Lossless.dll ещё не установлен.</string>
<string name="lossless_scaling_installing">Подготовка шейдеров генерации кадров…</string>
<string name="lossless_scaling_install_success">Lossless.dll успешно установлен</string>
<string name="lossless_scaling_install_failed">Не удалось установить Lossless.dll</string>
<string name="error_lossless_copy_failed">Не удалось скопировать выбранный файл.</string>
<string name="error_lossless_unreadable">Не удалось прочитать выбранный файл.</string>
<string name="error_lossless_not_pe">Выбранный файл не является библиотекой Windows. Выберите Lossless.dll из установки Lossless Scaling.</string>
<string name="error_lossless_missing_shaders">Эта копия Lossless.dll не содержит шейдеров генерации кадров. Обновите Lossless Scaling и попробуйте снова.</string>
<string name="error_lossless_translation_failed">Не удалось транслировать шейдеры генерации кадров. Эта версия Lossless Scaling пока не поддерживается.</string>
<string name="error_lossless_cache_failed">Не удалось записать транслированные шейдеры в хранилище. Проверьте, есть ли свободное место.</string>
<string name="advanced_settings">Расширенные настройки</string>
<string name="settings_description">Настройка параметров эмулятора</string>
<string name="search_recently_played">Недавно сыгранные</string>
@@ -491,9 +439,6 @@
<string name="use_custom_rtc_description">Позволяет установить пользовательские часы реального времени отдельно от текущего системного времени.</string>
<string name="set_custom_rtc">Установить пользовательский RTC</string>
<!-- CPU -->
<string name="fast_cpu_time">Тактовая частота ЦП</string>
<string name="fast_cpu_time_description">Повышает тактовую частоту, которую сообщает эмулируемый процессор, что убирает некоторые ограничители FPS. На более слабых процессорах производительность может снизиться, а в некоторых играх возможно некорректное поведение.</string>
<string name="custom_cpu_ticks">Пользовательские такты ЦП</string>
<string name="custom_cpu_ticks_description">Установите пользовательское значение тактов ЦП. Более высокие значения могут увеличить производительность, но также могут вызвать зависание игры. Рекомендуется диапазон 77–21000.</string>
<string name="cpu_ticks">Такты</string>
@@ -554,8 +499,6 @@
<string name="hacks">Хаки</string>
<string name="fast_gpu_time">Тактовая частота ГПУ</string>
<string name="fast_gpu_time_description">Заставляет игру думать, что работа ГПУ завершается быстрее, чем на самом деле, поэтому она перестаёт снижать разрешение и дистанцию прорисовки, чтобы подстраиваться под тактовые частоты Switch.</string>
<string name="skip_cpu_inner_invalidation">Пропустить внутреннюю инвалидацию ЦП</string>
<string name="skip_cpu_inner_invalidation_description">Пропускает некоторые инвалидации кэша на стороне ЦП при обновлениях памяти, уменьшая нагрузку на процессор и повышая производительность. Может вызывать сбои в некоторых играх.</string>
<string name="fix_bloom_effects">Исправить эффекты размытия</string>
@@ -602,7 +545,6 @@
<!-- Debug settings strings -->
<string name="cpu">ЦП</string>
<string name="clocks">Тактовая частота</string>
<string name="use_auto_stub">Использовать Auto Stub</string>
<string name="use_auto_stub_description">Автоматически заглушает отсутствующие сервисы и функции. Может улучшить совместимость, но вызывать сбои и проблемы стабильности.</string>
@@ -617,6 +559,7 @@
<string name="log">Логирование</string>
<string name="flush_by_line">Сбрасывать логи отладки построчно</string>
<string name="flush_by_line_description">Сбрасывает логи отладки после каждой написанной строки, упрощая отладку в случае сбоев или зависаний.</string>
<!-- GPU Logging strings -->
<string name="gpu_logging_header">Ведение журнала ГПУ</string>
<string name="gpu_log_level">Уровень журналирования</string>
@@ -1001,16 +944,6 @@
<string name="memory_6gb">6 ГБ (Небезопасно)</string>
<string name="memory_8gb">8 ГБ (Небезопасно)</string>
<!-- CPU clock levels -->
<string name="clock_normal">Обычная</string>
<string name="clock_boost">Турбо</string>
<string name="clock_fast">Разгон</string>
<!-- GPU clock levels -->
<string name="fast_gpu_normal">Обычная</string>
<string name="fast_gpu_medium">Турбо</string>
<string name="fast_gpu_high">Разгон</string>
<!-- GPU swizzle texture size -->
<string name="gpu_texturesizeswizzle_verysmall">Очень малый (16 МБ)</string>
<string name="gpu_texturesizeswizzle_small">Малый (32 МБ)</string>
@@ -1138,6 +1071,7 @@
<string name="theme_mode_light">Светлая</string>
<string name="theme_mode_dark">Темная</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Чёрный фон</string>
<string name="use_black_backgrounds_description">При использовании темной темы применяйте черный фон.</string>
@@ -60,6 +60,7 @@
<string name="cpuopt_unsafe_host_mmu_description">Ова оптимизација убрзава приступ меморији од стране гостујућег програма. Укључивање изазива да се читања/уписа меморије госта обављају директно у меморији и користе MMU домаћина. Искључивање присиљава све приступе меморији да користе софтверску емулацију MMU.</string>
<!-- NVDEC Emulation -->
<string name="nvdec_emulation">НВДЕЦ Емулација</string>
<string name="nvdec_emulation_description">Изаберите како се видео декодирање (НВДЕЦ) обрађује током секс и увозних интросија.</string>
<string name="nvdec_emulation_none">Ниједан</string>
<!-- Optimize SPIRV output -->
@@ -400,6 +401,7 @@
<string name="log">Сечеља</string>
<string name="flush_by_line">Записници за уклањање погрешака по линији</string>
<string name="flush_by_line_description">Испушта ознаке за уклањање погрешака на сваком писменом линијском линији, олакшавање уклањања погрешака у случајевима пада или замрзавања.</string>
<!-- Audio settings strings -->
<string name="audio_output_engine">Излазни мотор</string>
<string name="audio_volume">Запремина</string>
@@ -106,6 +106,7 @@
<!-- NVDEC Emulation -->
<string name="nvdec_emulation">Емуляція NVDEC</string>
<string name="nvdec_emulation_description">Обробка відео під час катсцен</string>
<string name="nvdec_emulation_none">Вимкнено</string>
<!-- Optimize SPIRV output -->
@@ -553,6 +554,7 @@
<string name="log">Журналювання</string>
<string name="flush_by_line">Скидати логи налагодження по рядках</string>
<string name="flush_by_line_description">Скидає логи налагодження після кожного написаного рядка, полегшуючи налагодження у випадках збоїв або зависань.</string>
<!-- GPU Logging strings -->
<string name="gpu_logging_header">Журналювання ГП</string>
<string name="gpu_log_level">Рівень журналювання</string>
@@ -1051,6 +1053,7 @@
<string name="theme_mode_light">Світла</string>
<string name="theme_mode_dark">Темна</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Чорний фон</string>
<string name="use_black_backgrounds_description">Використовувати чорний фон у темній темі.</string>
@@ -62,6 +62,7 @@
<string name="cpuopt_unsafe_host_mmu_description">Tối ưu hóa này tăng tốc độ truy cập bộ nhớ của chương trình khách. Bật nó lên khiến các thao tác đọc/ghi bộ nhớ khách được thực hiện trực tiếp vào bộ nhớ và sử dụng MMU của Máy chủ. Tắt tính năng này buộc tất cả quyền truy cập bộ nhớ phải sử dụng Giả lập MMU Phần mềm.</string>
<!-- NVDEC Emulation -->
<string name="nvdec_emulation">Giả lập NVDEC</string>
<string name="nvdec_emulation_description">Chọn cách xử lý giải mã video</string>
<string name="nvdec_emulation_none">Tắt</string>
<!-- Optimize SPIRV output -->
@@ -372,6 +373,7 @@
<string name="log">Ghi nhật ký</string>
<string name="flush_by_line">Xả nhật ký gỡ lỗi theo dòng</string>
<string name="flush_by_line_description">Xả nhật ký gỡ lỗi trên mỗi dòng được viết, giúp gỡ lỗi dễ dàng hơn trong trường hợp bị treo hoặc sập.</string>
<!-- Audio settings strings -->
<string name="audio_output_engine">Công cụ xuất âm thanh</string>
<string name="audio_volume">Âm lượng</string>

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