mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-25 10:53:03 +00:00
Compare commits
49 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e52e920b14 | |||
| d58ab98794 | |||
| b84e63f06b | |||
| 2db4c35c54 | |||
| d3d26797c1 | |||
| 99a65383f1 | |||
| 5f47a7f064 | |||
| 9c0d41b55f | |||
| 2cc7a94053 | |||
| b30e68a599 | |||
| 4e1f277432 | |||
| 9b0008008a | |||
| e47aee1215 | |||
| 61fd747cbd | |||
| bfcdcdc145 | |||
| 7a80ce616b | |||
| ed8d2d9ded | |||
| 4e5f0cd4e1 | |||
| f8685e0c92 | |||
| 2b952b79d7 | |||
| c040f73794 | |||
| 08c284fcb8 | |||
| 16b103aa6c | |||
| 36bd1c262a | |||
| 39ee32a311 | |||
| 51224713b7 | |||
| 08e5861af9 | |||
| a3ecd2b6cb | |||
| 70b4070709 | |||
| 72bc40c50b | |||
| 76b1180d02 | |||
| 23e11d2a58 | |||
| ff4ae20a88 | |||
| 37d4c6e636 | |||
| a06a5377ad | |||
| 684188d375 | |||
| 6e69740ab7 | |||
| f6d6e3c195 | |||
| 695a40872a | |||
| 897f9d5029 | |||
| e79ece6518 | |||
| 3d6974607e | |||
| d85d576b0d | |||
| e4c55e1aff | |||
| 8c3404960a | |||
| 0325b44d8e | |||
| a86e24731d | |||
| aafbcd6ce1 | |||
| 2c57681ca1 |
@@ -19,6 +19,7 @@ log.txt
|
|||||||
# Generated source files
|
# Generated source files
|
||||||
src/common/scm_rev.cpp
|
src/common/scm_rev.cpp
|
||||||
dist/english_plurals/generated_en.ts
|
dist/english_plurals/generated_en.ts
|
||||||
|
*-toolchain.cmake
|
||||||
|
|
||||||
# Project/editor files
|
# Project/editor files
|
||||||
*.swp
|
*.swp
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
--- a/source/effect_lexer.cpp
|
|
||||||
+++ b/source/effect_lexer.cpp
|
|
||||||
@@ -1181,7 +1181,7 @@
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
-#if 0
|
|
||||||
+#if !defined(__cpp_lib_to_chars)
|
|
||||||
exponent += decimal_location - mantissa_size;
|
|
||||||
|
|
||||||
const bool exponent_negative = exponent < 0;
|
|
||||||
+7
-2
@@ -53,6 +53,7 @@ if (YUZU_STATIC_ROOM)
|
|||||||
# disable e v e r y t h i n g
|
# disable e v e r y t h i n g
|
||||||
set(ENABLE_QT OFF)
|
set(ENABLE_QT OFF)
|
||||||
set(YUZU_CMD OFF)
|
set(YUZU_CMD OFF)
|
||||||
|
set(ENABLE_CUBEB OFF)
|
||||||
set(ENABLE_UPDATE_CHECKER OFF)
|
set(ENABLE_UPDATE_CHECKER OFF)
|
||||||
set(USE_DISCORD_PRESENCE OFF)
|
set(USE_DISCORD_PRESENCE OFF)
|
||||||
set(BUILD_TESTING OFF)
|
set(BUILD_TESTING OFF)
|
||||||
@@ -84,8 +85,6 @@ option(ENABLE_WERROR "Enable -Werror diagnostics" ON)
|
|||||||
# Lossless Scaling frame generation. Only Android.
|
# Lossless Scaling frame generation. Only Android.
|
||||||
cmake_dependent_option(ENABLE_LSFG "Enable Lossless Scaling frame generation" ON "ANDROID" OFF)
|
cmake_dependent_option(ENABLE_LSFG "Enable Lossless Scaling frame generation" ON "ANDROID" OFF)
|
||||||
|
|
||||||
option(ENABLE_RESHADE "Enable ReShade FX post-processing effects" ON)
|
|
||||||
|
|
||||||
# non-linux bundled qt are static
|
# non-linux bundled qt are static
|
||||||
if (YUZU_USE_BUNDLED_QT AND (APPLE OR NOT UNIX))
|
if (YUZU_USE_BUNDLED_QT AND (APPLE OR NOT UNIX))
|
||||||
set(YUZU_STATIC_BUILD ON)
|
set(YUZU_STATIC_BUILD ON)
|
||||||
@@ -216,6 +215,8 @@ if(MSVC)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
# TODO(crueter): Cleanup, each dep that has a bundled option should allow to choose between bundled, external, system
|
# TODO(crueter): Cleanup, each dep that has a bundled option should allow to choose between bundled, external, system
|
||||||
|
option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
|
||||||
|
|
||||||
set(EXT_DEFAULT OFF)
|
set(EXT_DEFAULT OFF)
|
||||||
if (MSVC OR ANDROID)
|
if (MSVC OR ANDROID)
|
||||||
set(EXT_DEFAULT ON)
|
set(EXT_DEFAULT ON)
|
||||||
@@ -574,6 +575,10 @@ if (NOT YUZU_STATIC_ROOM)
|
|||||||
find_package(DiscordRPC)
|
find_package(DiscordRPC)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (ENABLE_CUBEB)
|
||||||
|
find_package(cubeb)
|
||||||
|
endif()
|
||||||
|
|
||||||
if (YUZU_TESTS OR DYNARMIC_TESTS)
|
if (YUZU_TESTS OR DYNARMIC_TESTS)
|
||||||
find_package(Catch2)
|
find_package(Catch2)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
set(CROSS_TARGET "powerpc64le" CACHE STRING "Cross-compilation target (aarch64, powerpc64le, riscv64, etc)")
|
||||||
|
|
||||||
|
set(CMAKE_SYSROOT /usr/${CROSS_TARGET}-unknown-linux-gnu)
|
||||||
|
|
||||||
|
set(CMAKE_C_COMPILER ${CROSS_TARGET}-unknown-linux-gnu-gcc)
|
||||||
|
set(CMAKE_CXX_COMPILER ${CROSS_TARGET}-unknown-linux-gnu-g++)
|
||||||
|
|
||||||
|
# search programs in the host environment
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||||
|
|
||||||
|
# search headers and libraries in the target environment
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||||
|
|
||||||
|
set(CMAKE_FIND_ROOT_PATH /usr/${CROSS_TARGET}-unknown-linux-gnu)
|
||||||
+12
-8
@@ -46,6 +46,18 @@
|
|||||||
"repo": "arun11299/cpp-jwt",
|
"repo": "arun11299/cpp-jwt",
|
||||||
"version": "7f24eb4c32"
|
"version": "7f24eb4c32"
|
||||||
},
|
},
|
||||||
|
"cubeb": {
|
||||||
|
"find_args": "CONFIG",
|
||||||
|
"hash": "8a4bcb2f83ba590f52c66626e895304a73eb61928dbc57777e1822e55378e3568366f17f9da4b80036cc2ef4ea9723c32abf6e7d9bbe00fb03654f0991596ab0",
|
||||||
|
"options": [
|
||||||
|
"USE_SANITIZERS OFF",
|
||||||
|
"BUILD_TESTS OFF",
|
||||||
|
"BUILD_TOOLS OFF",
|
||||||
|
"BUNDLE_SPEEX ON"
|
||||||
|
],
|
||||||
|
"repo": "mozilla/cubeb",
|
||||||
|
"version": "fa02160712"
|
||||||
|
},
|
||||||
"discord-rpc": {
|
"discord-rpc": {
|
||||||
"find_args": "MODULE",
|
"find_args": "MODULE",
|
||||||
"hash": "8d680b3a16d6f6bf292ad823cf8635595ff986f2a49f758e3009f505b540a9d75194a8cf44cddea75736a8c3e3b5160166e716a0939ce3f18cc463cf648753fe",
|
"hash": "8d680b3a16d6f6bf292ad823cf8635595ff986f2a49f758e3009f505b540a9d75194a8cf44cddea75736a8c3e3b5160166e716a0939ce3f18cc463cf648753fe",
|
||||||
@@ -226,14 +238,6 @@
|
|||||||
"repo": "stachenov/quazip",
|
"repo": "stachenov/quazip",
|
||||||
"version": "2e95c9001b"
|
"version": "2e95c9001b"
|
||||||
},
|
},
|
||||||
"reshade": {
|
|
||||||
"hash": "6fc9b39821ca6e2d91160f05846b3a42159fec759f5d6fba91d1a57801a1bdaf6047740578c136f0b1a60a9c29ad160d87dbfe0dbfbcdf6ea879a8a078377b8c",
|
|
||||||
"patches": [
|
|
||||||
"0001-from-chars-fallback.patch"
|
|
||||||
],
|
|
||||||
"repo": "crosire/reshade",
|
|
||||||
"version": "v6.8.0"
|
|
||||||
},
|
|
||||||
"sdl3": {
|
"sdl3": {
|
||||||
"hash": "df5a323af7ac366661a3c0e887969c72584d232f3cc211419d59b0487b620b6b2859d4549c9e8df002ee489290062e466fcfddf7edc0872a37b1f2845e81c0f3",
|
"hash": "df5a323af7ac366661a3c0e887969c72584d232f3cc211419d59b0487b620b6b2859d4549c9e8df002ee489290062e466fcfddf7edc0872a37b1f2845e81c0f3",
|
||||||
"min_version": "3.2.10",
|
"min_version": "3.2.10",
|
||||||
|
|||||||
Vendored
-3
@@ -1,3 +0,0 @@
|
|||||||
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
|
|
||||||
Vendored
-3
@@ -1,3 +0,0 @@
|
|||||||
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
|
|
||||||
Vendored
-3
@@ -1,3 +0,0 @@
|
|||||||
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
|
|
||||||
Vendored
-3
@@ -1,3 +0,0 @@
|
|||||||
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
|
|
||||||
Vendored
-3
@@ -1,3 +0,0 @@
|
|||||||
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
|
|
||||||
Vendored
-3
@@ -1,3 +0,0 @@
|
|||||||
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
|
|
||||||
Vendored
-70
@@ -1,70 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2012 PPSSPP Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
// Ported from bloomnoblur.fsh in PPSSPP.
|
|
||||||
|
|
||||||
texture BackBufferTex : COLOR;
|
|
||||||
sampler BackBuffer { Texture = BackBufferTex; };
|
|
||||||
|
|
||||||
uniform float Radius <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Radius";
|
|
||||||
ui_tooltip = "How far the glow spreads from bright areas.";
|
|
||||||
ui_min = 0.0; ui_max = 4.0; ui_step = 0.05;
|
|
||||||
> = 1.0;
|
|
||||||
|
|
||||||
uniform float Amount <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Amount";
|
|
||||||
ui_tooltip = "Strength of the glow added on top of the image.";
|
|
||||||
ui_min = 0.0; ui_max = 2.0; ui_step = 0.05;
|
|
||||||
> = 0.6;
|
|
||||||
|
|
||||||
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
|
|
||||||
{
|
|
||||||
uv = float2(float(id & 2), float((id & 1) << 1));
|
|
||||||
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float Weight(float3 color)
|
|
||||||
{
|
|
||||||
float gray = (color.r + color.g + color.b) / 3.0;
|
|
||||||
float saturation = (abs(color.r - gray) + abs(color.g - gray) + abs(color.b - gray)) / 3.0;
|
|
||||||
return gray * gray / max(saturation, 0.25);
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PS_Bloom(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
|
|
||||||
{
|
|
||||||
float3 color = tex2D(BackBuffer, uv).rgb;
|
|
||||||
|
|
||||||
float gray = (color.r + color.g + color.b) / 3.0;
|
|
||||||
float saturation = (abs(color.r - gray) + abs(color.g - gray) + abs(color.b - gray)) / 3.0;
|
|
||||||
float spread = 0.002 * gray / max(saturation, 0.25) * Radius;
|
|
||||||
|
|
||||||
float3 sum = float3(0.0, 0.0, 0.0);
|
|
||||||
[unroll] for (int x = -3; x <= 3; x += 2)
|
|
||||||
{
|
|
||||||
[unroll] 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
-87
@@ -1,87 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
texture BackBufferTex : COLOR;
|
|
||||||
sampler BackBuffer { Texture = BackBufferTex; };
|
|
||||||
|
|
||||||
uniform float Radius <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Radius";
|
|
||||||
ui_tooltip = "How far the blur reaches, in pixels.";
|
|
||||||
ui_min = 1.0; ui_max = 12.0; ui_step = 0.5;
|
|
||||||
> = 4.0;
|
|
||||||
|
|
||||||
uniform float Strength <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Strength";
|
|
||||||
ui_tooltip = "Blend between the original image and the blurred one.";
|
|
||||||
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
|
|
||||||
> = 1.0;
|
|
||||||
|
|
||||||
uniform float FocusSize <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Sharp Centre";
|
|
||||||
ui_tooltip = "Size of the region left in focus at the centre of the screen. At zero the whole image is blurred evenly.";
|
|
||||||
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
|
|
||||||
> = 0.0;
|
|
||||||
|
|
||||||
uniform float FocusSoftness <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Focus Falloff";
|
|
||||||
ui_tooltip = "How gradually the sharp centre gives way to the blur.";
|
|
||||||
ui_min = 0.05; ui_max = 1.0; ui_step = 0.05;
|
|
||||||
> = 0.4;
|
|
||||||
|
|
||||||
static const int TAPS = 17;
|
|
||||||
|
|
||||||
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
|
|
||||||
{
|
|
||||||
uv = float2(float(id & 2), float((id & 1) << 1));
|
|
||||||
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PS_Blur(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
|
|
||||||
{
|
|
||||||
float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT);
|
|
||||||
float3 original = tex2D(BackBuffer, uv).rgb;
|
|
||||||
|
|
||||||
float2 centred = (uv - 0.5) * float2(BUFFER_WIDTH * BUFFER_RCP_HEIGHT, 1.0) * 2.0;
|
|
||||||
float distance_from_centre = length(centred);
|
|
||||||
float no_focus = 1.0 - step(0.001, FocusSize);
|
|
||||||
float focus = max(smoothstep(FocusSize, FocusSize + FocusSoftness, distance_from_centre), no_focus);
|
|
||||||
float amount = Strength * focus;
|
|
||||||
|
|
||||||
float angle = frac(sin(dot(pos.xy, float2(12.9898, 78.233))) * 43758.5453) * 6.2831853;
|
|
||||||
float2 spoke = float2(cos(angle), sin(angle));
|
|
||||||
|
|
||||||
const float2 turn = float2(cos(2.39996323), sin(2.39996323));
|
|
||||||
const float decay = exp(-2.0 / float(TAPS));
|
|
||||||
float weight = exp(-1.0 / float(TAPS));
|
|
||||||
|
|
||||||
float3 sum = float3(0.0, 0.0, 0.0);
|
|
||||||
float total = 0.0;
|
|
||||||
[unroll] 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
-74
@@ -1,74 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2012 PPSSPP Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
// Ported from crt.fsh in PPSSPP, by KillaMaaki.
|
|
||||||
|
|
||||||
|
|
||||||
texture BackBufferTex : COLOR;
|
|
||||||
sampler BackBuffer { Texture = BackBufferTex; };
|
|
||||||
|
|
||||||
uniform float Timer < source = "timer"; > = 0.0;
|
|
||||||
|
|
||||||
uniform float Density <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Line Density";
|
|
||||||
ui_min = 60.0; ui_max = 720.0; ui_step = 10.0;
|
|
||||||
> = 272.0;
|
|
||||||
|
|
||||||
uniform float RollSpeed <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Roll Speed";
|
|
||||||
ui_tooltip = "Speed of the rolling bar. Zero disables it.";
|
|
||||||
ui_min = 0.0; ui_max = 2.0; ui_step = 0.05;
|
|
||||||
> = 1.0;
|
|
||||||
|
|
||||||
uniform float Bleed <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Colour Bleed";
|
|
||||||
ui_tooltip = "Horizontal separation of the red and green channels.";
|
|
||||||
ui_min = 0.0; ui_max = 4.0; ui_step = 0.1;
|
|
||||||
> = 1.0;
|
|
||||||
|
|
||||||
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
|
|
||||||
{
|
|
||||||
uv = float2(float(id & 2), float((id & 1) << 1));
|
|
||||||
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PS_CRT(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
|
|
||||||
{
|
|
||||||
float seconds = Timer * 0.001;
|
|
||||||
float scan = floor((uv.y + seconds * RollSpeed * 0.5) * Density);
|
|
||||||
float line_intensity = frac(scan * 0.5) * 2.0;
|
|
||||||
|
|
||||||
float2 shift = float2(line_intensity * 0.0005, 0.0);
|
|
||||||
float2 bleed = float2(BUFFER_RCP_WIDTH * Bleed, 0.0);
|
|
||||||
|
|
||||||
float r = tex2D(BackBuffer, uv + bleed + shift).r;
|
|
||||||
float g = tex2D(BackBuffer, uv - bleed + shift).g;
|
|
||||||
float b = tex2D(BackBuffer, uv).b;
|
|
||||||
|
|
||||||
float3 color = float3(r, g * 0.99, b) * clamp(line_intensity, 0.85, 1.0);
|
|
||||||
|
|
||||||
if (RollSpeed > 0.0)
|
|
||||||
{
|
|
||||||
float rollbar = sin((uv.y + seconds * RollSpeed) * 4.0);
|
|
||||||
color += rollbar * 0.02;
|
|
||||||
}
|
|
||||||
|
|
||||||
return float4(saturate(color), 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
technique CRT <
|
|
||||||
ui_label = "CRT";
|
|
||||||
ui_tooltip = "Curved scanlines and the phosphor mask of a CRT television, for games that were drawn with that kind of screen in mind.";
|
|
||||||
>
|
|
||||||
{
|
|
||||||
pass
|
|
||||||
{
|
|
||||||
VertexShader = VS_PostProcess;
|
|
||||||
PixelShader = PS_CRT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
-79
@@ -1,79 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2012 PPSSPP Project
|
|
||||||
// SPDX-FileCopyrightText: guest(r)
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
// Ported from cartoon.fsh in PPSSPP, Advanced Cartoon shader I by guest(r).
|
|
||||||
|
|
||||||
texture BackBufferTex : COLOR;
|
|
||||||
sampler BackBuffer { Texture = BackBufferTex; };
|
|
||||||
|
|
||||||
uniform float EdgeStrength <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Edge Strength";
|
|
||||||
ui_tooltip = "Darkness of the ink outline drawn around detected edges.";
|
|
||||||
ui_min = 0.0; ui_max = 2.0; ui_step = 0.05;
|
|
||||||
> = 0.5;
|
|
||||||
|
|
||||||
uniform float Levels <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Colour Levels";
|
|
||||||
ui_tooltip = "How many bands the colours are quantised into.";
|
|
||||||
ui_min = 2.0; ui_max = 16.0; ui_step = 1.0;
|
|
||||||
> = 4.0;
|
|
||||||
|
|
||||||
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
|
|
||||||
{
|
|
||||||
uv = float2(float(id & 2), float((id & 1) << 1));
|
|
||||||
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PS_Cartoon(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
|
|
||||||
{
|
|
||||||
float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT);
|
|
||||||
|
|
||||||
float3 c00 = tex2D(BackBuffer, uv + texel * float2(-1.0, -1.0)).rgb;
|
|
||||||
float3 c10 = tex2D(BackBuffer, uv + texel * float2( 0.0, -1.0)).rgb;
|
|
||||||
float3 c20 = tex2D(BackBuffer, uv + texel * float2( 1.0, -1.0)).rgb;
|
|
||||||
float3 c01 = tex2D(BackBuffer, uv + texel * float2(-1.0, 0.0)).rgb;
|
|
||||||
float3 c11 = tex2D(BackBuffer, uv).rgb;
|
|
||||||
float3 c21 = tex2D(BackBuffer, uv + texel * float2( 1.0, 0.0)).rgb;
|
|
||||||
float3 c02 = tex2D(BackBuffer, uv + texel * float2(-1.0, 1.0)).rgb;
|
|
||||||
float3 c12 = tex2D(BackBuffer, uv + texel * float2( 0.0, 1.0)).rgb;
|
|
||||||
float3 c22 = tex2D(BackBuffer, uv + texel * float2( 1.0, 1.0)).rgb;
|
|
||||||
|
|
||||||
const float3 dt = float3(1.0, 1.0, 1.0);
|
|
||||||
|
|
||||||
float d1 = dot(abs(c00 - c22), dt);
|
|
||||||
float d2 = dot(abs(c20 - c02), dt);
|
|
||||||
float hl = dot(abs(c01 - c21), dt);
|
|
||||||
float vl = dot(abs(c10 - c12), dt);
|
|
||||||
float edge = EdgeStrength * (d1 + d2 + hl + vl) / (dot(c11, dt) + 0.15);
|
|
||||||
|
|
||||||
float lc = Levels * length(c11);
|
|
||||||
float f = frac(lc);
|
|
||||||
f *= f;
|
|
||||||
lc = (floor(lc) + f * f) / Levels + 0.05;
|
|
||||||
|
|
||||||
float3 unit = normalize(max(c11, 0.0001));
|
|
||||||
float3 quant = Levels * unit;
|
|
||||||
float3 frct = frac(quant);
|
|
||||||
frct *= frct;
|
|
||||||
quant = floor(quant) + 0.05 * dt + frct * frct;
|
|
||||||
|
|
||||||
float3 color = lc * (1.1 - edge * sqrt(edge)) * quant / Levels;
|
|
||||||
return float4(saturate(color), 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
technique Cartoon <
|
|
||||||
ui_label = "Cartoon";
|
|
||||||
ui_tooltip = "Ink outlines and flat colour bands. Faithful port of the PPSSPP shader; the outline gets heavy in dark scenes, so try Cartoon Soft or Cel Shading if the blacks smear.";
|
|
||||||
>
|
|
||||||
{
|
|
||||||
pass
|
|
||||||
{
|
|
||||||
VertexShader = VS_PostProcess;
|
|
||||||
PixelShader = PS_Cartoon;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
-100
@@ -1,100 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2012 PPSSPP Project
|
|
||||||
// SPDX-FileCopyrightText: guest(r)
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
texture BackBufferTex : COLOR;
|
|
||||||
sampler BackBuffer { Texture = BackBufferTex; };
|
|
||||||
|
|
||||||
uniform float EdgeStrength <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Edge Strength";
|
|
||||||
ui_tooltip = "Darkness of the ink outline drawn around detected edges.";
|
|
||||||
ui_min = 0.0; ui_max = 2.0; ui_step = 0.05;
|
|
||||||
> = 0.45;
|
|
||||||
|
|
||||||
uniform float ShadowGuard <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Shadow Guard";
|
|
||||||
ui_tooltip = "Holds the outline back in dark areas. Raise it if shadows turn into black blobs.";
|
|
||||||
ui_min = 0.1; ui_max = 2.0; ui_step = 0.05;
|
|
||||||
> = 0.8;
|
|
||||||
|
|
||||||
uniform float Levels <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Colour Levels";
|
|
||||||
ui_tooltip = "How many bands the colours are quantised into.";
|
|
||||||
ui_min = 2.0; ui_max = 16.0; ui_step = 1.0;
|
|
||||||
> = 6.0;
|
|
||||||
|
|
||||||
uniform float Smoothing <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Banding";
|
|
||||||
ui_tooltip = "How far the picture is pushed towards flat bands.";
|
|
||||||
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
|
|
||||||
> = 0.75;
|
|
||||||
|
|
||||||
uniform float Saturation <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Saturation";
|
|
||||||
ui_min = 0.0; ui_max = 2.0; ui_step = 0.05;
|
|
||||||
> = 1.15;
|
|
||||||
|
|
||||||
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
|
|
||||||
{
|
|
||||||
uv = float2(float(id & 2), float((id & 1) << 1));
|
|
||||||
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PS_CartoonSoft(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
|
|
||||||
{
|
|
||||||
float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT);
|
|
||||||
|
|
||||||
float3 c00 = tex2D(BackBuffer, uv + texel * float2(-1.0, -1.0)).rgb;
|
|
||||||
float3 c10 = tex2D(BackBuffer, uv + texel * float2( 0.0, -1.0)).rgb;
|
|
||||||
float3 c20 = tex2D(BackBuffer, uv + texel * float2( 1.0, -1.0)).rgb;
|
|
||||||
float3 c01 = tex2D(BackBuffer, uv + texel * float2(-1.0, 0.0)).rgb;
|
|
||||||
float3 c11 = tex2D(BackBuffer, uv).rgb;
|
|
||||||
float3 c21 = tex2D(BackBuffer, uv + texel * float2( 1.0, 0.0)).rgb;
|
|
||||||
float3 c02 = tex2D(BackBuffer, uv + texel * float2(-1.0, 1.0)).rgb;
|
|
||||||
float3 c12 = tex2D(BackBuffer, uv + texel * float2( 0.0, 1.0)).rgb;
|
|
||||||
float3 c22 = tex2D(BackBuffer, uv + texel * float2( 1.0, 1.0)).rgb;
|
|
||||||
|
|
||||||
const float3 dt = float3(1.0, 1.0, 1.0);
|
|
||||||
const float3 luma_weights = float3(0.299, 0.587, 0.114);
|
|
||||||
|
|
||||||
float d1 = dot(abs(c00 - c22), dt);
|
|
||||||
float d2 = dot(abs(c20 - c02), dt);
|
|
||||||
float hl = dot(abs(c01 - c21), dt);
|
|
||||||
float vl = dot(abs(c10 - c12), dt);
|
|
||||||
|
|
||||||
float luma = dot(c11, luma_weights);
|
|
||||||
float response = (d1 + d2 + hl + vl) / (luma * 2.0 + ShadowGuard);
|
|
||||||
float ink = 1.0 - saturate(response * EdgeStrength);
|
|
||||||
|
|
||||||
float scaled = luma * Levels;
|
|
||||||
float step_position = frac(scaled);
|
|
||||||
float eased = step_position * step_position * (3.0 - 2.0 * step_position);
|
|
||||||
float banded = (floor(scaled) + eased) / Levels;
|
|
||||||
float target = lerp(luma, banded, Smoothing);
|
|
||||||
|
|
||||||
float3 tinted = c11 * (target / max(luma, 0.001));
|
|
||||||
float3 grey = dot(tinted, luma_weights);
|
|
||||||
float3 color = lerp(grey, tinted, Saturation) * ink;
|
|
||||||
|
|
||||||
return float4(saturate(color), 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
technique CartoonSoft <
|
|
||||||
ui_label = "Cartoon Soft";
|
|
||||||
ui_tooltip = "Ink outlines and flat colour bands, with the outline held back in the shadows so dark scenes do not turn into black blobs.";
|
|
||||||
>
|
|
||||||
{
|
|
||||||
pass
|
|
||||||
{
|
|
||||||
VertexShader = VS_PostProcess;
|
|
||||||
PixelShader = PS_CartoonSoft;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
-120
@@ -1,120 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
texture BackBufferTex : COLOR;
|
|
||||||
sampler BackBuffer { Texture = BackBufferTex; };
|
|
||||||
|
|
||||||
uniform float Bands <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Shading Bands";
|
|
||||||
ui_tooltip = "How many flat steps the lighting is collapsed into. Three or four gives the classic look.";
|
|
||||||
ui_min = 2.0; ui_max = 8.0; ui_step = 1.0;
|
|
||||||
> = 4.0;
|
|
||||||
|
|
||||||
uniform float BandContrast <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Band Contrast";
|
|
||||||
ui_tooltip = "Spreads the bands towards pure black and white. Lower it if the shadows crush.";
|
|
||||||
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
|
|
||||||
> = 0.5;
|
|
||||||
|
|
||||||
uniform float BandEdge <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Band Edge";
|
|
||||||
ui_tooltip = "Width of the transition between bands. Low values give hard cel steps.";
|
|
||||||
ui_min = 0.02; ui_max = 1.0; ui_step = 0.02;
|
|
||||||
> = 0.15;
|
|
||||||
|
|
||||||
uniform float Detail <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Texture Detail";
|
|
||||||
ui_tooltip = "How much surface texture survives the flattening. At zero the bands are completely flat.";
|
|
||||||
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
|
|
||||||
> = 0.6;
|
|
||||||
|
|
||||||
uniform float OutlineStrength <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Outline Strength";
|
|
||||||
ui_tooltip = "Opacity of the ink line drawn along detected edges.";
|
|
||||||
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
|
|
||||||
> = 0.8;
|
|
||||||
|
|
||||||
uniform float OutlineThreshold <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Outline Threshold";
|
|
||||||
ui_tooltip = "How strong an edge has to be before it is inked. Raise it to keep ink off textures and specular highlights.";
|
|
||||||
ui_min = 0.01; ui_max = 0.4; ui_step = 0.01;
|
|
||||||
> = 0.18;
|
|
||||||
|
|
||||||
uniform float Saturation <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Saturation";
|
|
||||||
ui_tooltip = "Colour intensity of the flat regions.";
|
|
||||||
ui_min = 0.0; ui_max = 2.0; ui_step = 0.05;
|
|
||||||
> = 1.25;
|
|
||||||
|
|
||||||
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
|
|
||||||
{
|
|
||||||
uv = float2(float(id & 2), float((id & 1) << 1));
|
|
||||||
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PS_CelShading(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
|
|
||||||
{
|
|
||||||
const float3 luma_weights = float3(0.2126, 0.7152, 0.0722);
|
|
||||||
float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT);
|
|
||||||
|
|
||||||
float3 centre = tex2D(BackBuffer, uv).rgb;
|
|
||||||
float luma = dot(centre, luma_weights);
|
|
||||||
|
|
||||||
float2 near = texel * 1.5;
|
|
||||||
float2 far = texel * 3.5;
|
|
||||||
|
|
||||||
float a00 = dot(tex2D(BackBuffer, uv + near * float2(-1.0, -1.0)).rgb, luma_weights);
|
|
||||||
float a20 = dot(tex2D(BackBuffer, uv + near * float2( 1.0, -1.0)).rgb, luma_weights);
|
|
||||||
float a02 = dot(tex2D(BackBuffer, uv + near * float2(-1.0, 1.0)).rgb, luma_weights);
|
|
||||||
float a22 = dot(tex2D(BackBuffer, uv + near * float2( 1.0, 1.0)).rgb, luma_weights);
|
|
||||||
|
|
||||||
float b00 = dot(tex2D(BackBuffer, uv + far * float2(-1.0, -1.0)).rgb, luma_weights);
|
|
||||||
float b20 = dot(tex2D(BackBuffer, uv + far * float2( 1.0, -1.0)).rgb, luma_weights);
|
|
||||||
float b02 = dot(tex2D(BackBuffer, uv + far * float2(-1.0, 1.0)).rgb, luma_weights);
|
|
||||||
float b22 = dot(tex2D(BackBuffer, uv + far * float2( 1.0, 1.0)).rgb, luma_weights);
|
|
||||||
|
|
||||||
float gx = (a00 + a02) - (a20 + a22);
|
|
||||||
float gy = (a00 + a20) - (a02 + a22);
|
|
||||||
float gradient = sqrt(gx * gx + gy * gy);
|
|
||||||
float ink = smoothstep(OutlineThreshold, OutlineThreshold + 0.04, gradient);
|
|
||||||
|
|
||||||
float lighting = (a00 + a20 + a02 + a22 + b00 + b20 + b02 + b22) * 0.125;
|
|
||||||
float detail = luma - lighting;
|
|
||||||
|
|
||||||
float softness = max(BandEdge, 0.001);
|
|
||||||
float coord = lighting * Bands - softness * 0.5;
|
|
||||||
float index = floor(coord) + smoothstep(1.0 - softness, 1.0, frac(coord));
|
|
||||||
|
|
||||||
float centred = (index + 0.5) / Bands;
|
|
||||||
float stretched = index / max(Bands - 1.0, 1.0);
|
|
||||||
float banded = saturate(lerp(centred, stretched, BandContrast));
|
|
||||||
|
|
||||||
float target = saturate(banded + detail * Detail);
|
|
||||||
|
|
||||||
float gain = min(target / max(luma, 0.001), 4.0);
|
|
||||||
float3 shaded = centre * gain;
|
|
||||||
float3 grey = dot(shaded, luma_weights);
|
|
||||||
float3 color = lerp(grey, shaded, Saturation);
|
|
||||||
color *= 1.0 - ink * OutlineStrength;
|
|
||||||
|
|
||||||
return float4(saturate(color), 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
technique CelShading <
|
|
||||||
ui_label = "Cel Shading";
|
|
||||||
ui_tooltip = "Collapses the lighting into a few hard steps and inks the edges, keeping texture detail and hue intact.";
|
|
||||||
>
|
|
||||||
{
|
|
||||||
pass
|
|
||||||
{
|
|
||||||
VertexShader = VS_PostProcess;
|
|
||||||
PixelShader = PS_CelShading;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-53
@@ -1,53 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
texture BackBufferTex : COLOR;
|
|
||||||
sampler BackBuffer { Texture = BackBufferTex; };
|
|
||||||
|
|
||||||
uniform float Strength <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Strength";
|
|
||||||
ui_tooltip = "Channel separation in pixels, measured at the edge of the screen.";
|
|
||||||
ui_min = 0.0; ui_max = 8.0; ui_step = 0.1;
|
|
||||||
> = 1.5;
|
|
||||||
|
|
||||||
uniform float Falloff <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Falloff";
|
|
||||||
ui_tooltip = "How fast the separation grows away from the centre. Higher keeps the middle clean.";
|
|
||||||
ui_min = 1.0; ui_max = 4.0; ui_step = 0.1;
|
|
||||||
> = 2.0;
|
|
||||||
|
|
||||||
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
|
|
||||||
{
|
|
||||||
uv = float2(float(id & 2), float((id & 1) << 1));
|
|
||||||
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PS_ChromaticAberration(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
|
|
||||||
{
|
|
||||||
float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT);
|
|
||||||
|
|
||||||
float2 direction = uv - float2(0.5, 0.5);
|
|
||||||
float radius = length(direction);
|
|
||||||
float2 unit = direction / max(radius, 0.0001);
|
|
||||||
float2 offset = unit * Strength * pow(radius * 2.0, Falloff) * texel;
|
|
||||||
|
|
||||||
float red = tex2D(BackBuffer, uv + offset).r;
|
|
||||||
float green = tex2D(BackBuffer, uv).g;
|
|
||||||
float blue = tex2D(BackBuffer, uv - offset).b;
|
|
||||||
|
|
||||||
return float4(red, green, blue, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
technique ChromaticAberration <
|
|
||||||
ui_label = "Chromatic Aberration";
|
|
||||||
ui_tooltip = "Splits the colour channels apart towards the edges of the screen, the way a cheap lens fails to focus every colour on the same spot.";
|
|
||||||
>
|
|
||||||
{
|
|
||||||
pass
|
|
||||||
{
|
|
||||||
VertexShader = VS_PostProcess;
|
|
||||||
PixelShader = PS_ChromaticAberration;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
-64
@@ -1,64 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2012 PPSSPP Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
// Based on colorcorrection.fsh in PPSSPP.
|
|
||||||
|
|
||||||
texture BackBufferTex : COLOR;
|
|
||||||
sampler BackBuffer { Texture = BackBufferTex; };
|
|
||||||
|
|
||||||
uniform float Saturation <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Saturation";
|
|
||||||
ui_min = 0.0; ui_max = 2.0; ui_step = 0.01;
|
|
||||||
> = 1.0;
|
|
||||||
|
|
||||||
uniform float Brightness <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Brightness";
|
|
||||||
ui_min = 0.0; ui_max = 2.0; ui_step = 0.01;
|
|
||||||
> = 1.0;
|
|
||||||
|
|
||||||
uniform float Contrast <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Contrast";
|
|
||||||
ui_min = 0.0; ui_max = 2.0; ui_step = 0.01;
|
|
||||||
> = 1.0;
|
|
||||||
|
|
||||||
uniform float Gamma <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Gamma";
|
|
||||||
ui_min = 0.5; ui_max = 2.0; ui_step = 0.01;
|
|
||||||
> = 1.0;
|
|
||||||
|
|
||||||
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
|
|
||||||
{
|
|
||||||
uv = float2(float(id & 2), float((id & 1) << 1));
|
|
||||||
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PS_ColorGrade(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
|
|
||||||
{
|
|
||||||
float3 rgb = tex2D(BackBuffer, uv).rgb;
|
|
||||||
|
|
||||||
float luma = dot(rgb, float3(0.2126, 0.7152, 0.0722));
|
|
||||||
rgb = lerp(float3(luma, luma, luma), rgb, Saturation);
|
|
||||||
rgb *= Brightness;
|
|
||||||
rgb = (rgb - 0.5) * Contrast + 0.5;
|
|
||||||
rgb = pow(max(rgb, 0.0), 1.0 / max(Gamma, 0.0001));
|
|
||||||
|
|
||||||
return float4(saturate(rgb), 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
technique ColorGrade <
|
|
||||||
ui_label = "Colour Grade";
|
|
||||||
ui_tooltip = "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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
-91
@@ -1,91 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2015 Niklas Haas
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
texture BackBufferTex : COLOR;
|
|
||||||
sampler BackBuffer { Texture = BackBufferTex; };
|
|
||||||
|
|
||||||
uniform float Threshold <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Threshold";
|
|
||||||
ui_tooltip = "How flat a neighbourhood must be before it gets smoothed. Raise it to catch wider bands, lower it to keep more detail.";
|
|
||||||
ui_min = 0.002; ui_max = 0.05; ui_step = 0.001;
|
|
||||||
> = 0.012;
|
|
||||||
|
|
||||||
uniform float Radius <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Radius";
|
|
||||||
ui_tooltip = "How far the sampling reaches, in pixels. Wider gradients need a larger radius.";
|
|
||||||
ui_min = 1.0; ui_max = 32.0; ui_step = 1.0;
|
|
||||||
> = 8.0;
|
|
||||||
|
|
||||||
uniform float Grain <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Dither";
|
|
||||||
ui_tooltip = "Noise added to break up whatever banding survives the smoothing.";
|
|
||||||
ui_min = 0.0; ui_max = 0.02; ui_step = 0.001;
|
|
||||||
> = 0.004;
|
|
||||||
|
|
||||||
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
|
|
||||||
{
|
|
||||||
uv = float2(float(id & 2), float((id & 1) << 1));
|
|
||||||
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float Hash(float2 p)
|
|
||||||
{
|
|
||||||
float3 scattered = frac(float3(p.x, p.y, p.x) * 0.1031);
|
|
||||||
scattered += dot(scattered, scattered.yzx + 33.33);
|
|
||||||
return frac((scattered.x + scattered.y) * scattered.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PS_Deband(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
|
|
||||||
{
|
|
||||||
float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT);
|
|
||||||
|
|
||||||
float3 centre = tex2D(BackBuffer, uv).rgb;
|
|
||||||
float base = Hash(pos.xy) * 6.2831853;
|
|
||||||
|
|
||||||
float3 total = float3(0.0, 0.0, 0.0);
|
|
||||||
float3 deviation = float3(0.0, 0.0, 0.0);
|
|
||||||
|
|
||||||
[unroll] 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
-83
@@ -1,83 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2019-2021 bloc97
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
texture BackBufferTex : COLOR;
|
|
||||||
sampler BackBuffer { Texture = BackBufferTex; };
|
|
||||||
|
|
||||||
uniform float Strength <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Strength";
|
|
||||||
ui_min = 0.01; ui_max = 0.5; ui_step = 0.01;
|
|
||||||
> = 0.1;
|
|
||||||
|
|
||||||
uniform float Radius <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Radius";
|
|
||||||
ui_min = 0.3; ui_max = 2.0; ui_step = 0.05;
|
|
||||||
> = 1.0;
|
|
||||||
|
|
||||||
uniform float Curve <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Shadow Bias";
|
|
||||||
ui_min = 0.0; ui_max = 2.0; ui_step = 0.05;
|
|
||||||
> = 1.0;
|
|
||||||
|
|
||||||
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
|
|
||||||
{
|
|
||||||
uv = float2(float(id & 2), float((id & 1) << 1));
|
|
||||||
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float3 IntensityWeight(float3 value, float3 sigma, float3 centre)
|
|
||||||
{
|
|
||||||
float3 scaled = (value - centre) / sigma;
|
|
||||||
return exp(-0.5 * scaled * scaled);
|
|
||||||
}
|
|
||||||
|
|
||||||
float SpatialWeight(float distance, float sigma)
|
|
||||||
{
|
|
||||||
float scaled = distance / sigma;
|
|
||||||
return exp(-0.5 * scaled * scaled);
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PS_Denoise(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
|
|
||||||
{
|
|
||||||
float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT);
|
|
||||||
|
|
||||||
float3 centre = tex2D(BackBuffer, uv).rgb;
|
|
||||||
float3 intensity_sigma = max(pow(centre + 0.0001, Curve) * Strength, 0.0001);
|
|
||||||
float spatial_sigma = max(Radius, 0.05);
|
|
||||||
|
|
||||||
float3 sum = float3(0.0, 0.0, 0.0);
|
|
||||||
float3 total = float3(0.0, 0.0, 0.0);
|
|
||||||
|
|
||||||
[unroll] for (int y = -2; y <= 2; ++y)
|
|
||||||
{
|
|
||||||
[unroll] 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
-65
@@ -1,65 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
texture BackBufferTex : COLOR;
|
|
||||||
sampler BackBuffer { Texture = BackBufferTex; };
|
|
||||||
|
|
||||||
uniform float Intensity <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Intensity";
|
|
||||||
ui_min = 0.0; ui_max = 0.2; ui_step = 0.005;
|
|
||||||
> = 0.03;
|
|
||||||
|
|
||||||
uniform float Size <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Size";
|
|
||||||
ui_tooltip = "Grain cell size in pixels.";
|
|
||||||
ui_min = 1.0; ui_max = 4.0; ui_step = 1.0;
|
|
||||||
> = 1.0;
|
|
||||||
|
|
||||||
uniform float Colored <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Colour";
|
|
||||||
ui_tooltip = "Zero gives monochrome grain, one gives independent noise per channel.";
|
|
||||||
ui_min = 0.0; ui_max = 1.0; ui_step = 0.01;
|
|
||||||
> = 0.0;
|
|
||||||
|
|
||||||
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
|
|
||||||
{
|
|
||||||
uv = float2(float(id & 2), float((id & 1) << 1));
|
|
||||||
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float Hash(float2 p)
|
|
||||||
{
|
|
||||||
float3 scattered = frac(float3(p.x, p.y, p.x) * 0.1031);
|
|
||||||
scattered += dot(scattered, scattered.yzx + 33.33);
|
|
||||||
return frac((scattered.x + scattered.y) * scattered.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PS_FilmGrain(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
|
|
||||||
{
|
|
||||||
float3 rgb = tex2D(BackBuffer, uv).rgb;
|
|
||||||
|
|
||||||
float2 cell = floor(pos.xy / max(Size, 1.0));
|
|
||||||
float mono = Hash(cell) - 0.5;
|
|
||||||
float3 chroma = float3(Hash(cell + 11.7), Hash(cell + 23.1), Hash(cell + 37.5)) - 0.5;
|
|
||||||
float3 noise = lerp(float3(mono, mono, mono), chroma, Colored);
|
|
||||||
|
|
||||||
float luma = dot(rgb, float3(0.2126, 0.7152, 0.0722));
|
|
||||||
float response = 1.0 - abs(luma * 2.0 - 1.0);
|
|
||||||
|
|
||||||
return float4(saturate(rgb + noise * Intensity * response), 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
technique FilmGrain <
|
|
||||||
ui_label = "Film Grain";
|
|
||||||
ui_tooltip = "Adds photographic grain, strongest in the midtones and fading out in blacks and whites.";
|
|
||||||
>
|
|
||||||
{
|
|
||||||
pass
|
|
||||||
{
|
|
||||||
VertexShader = VS_PostProcess;
|
|
||||||
PixelShader = PS_FilmGrain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
-60
@@ -1,60 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
texture BackBufferTex : COLOR;
|
|
||||||
sampler BackBuffer { Texture = BackBufferTex; };
|
|
||||||
|
|
||||||
uniform float Exposure <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Exposure";
|
|
||||||
ui_min = 0.5; ui_max = 2.0; ui_step = 0.01;
|
|
||||||
> = 1.0;
|
|
||||||
|
|
||||||
uniform float Toe <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Toe";
|
|
||||||
ui_tooltip = "Above 1.0 deepens the shadows, below 1.0 lifts them.";
|
|
||||||
ui_min = 0.5; ui_max = 2.0; ui_step = 0.01;
|
|
||||||
> = 1.2;
|
|
||||||
|
|
||||||
uniform float Shoulder <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Shoulder";
|
|
||||||
ui_tooltip = "Above 1.0 opens up the highlights, below 1.0 compresses them.";
|
|
||||||
ui_min = 0.5; ui_max = 2.0; ui_step = 0.01;
|
|
||||||
> = 1.2;
|
|
||||||
|
|
||||||
uniform float Amount <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Amount";
|
|
||||||
ui_min = 0.0; ui_max = 1.0; ui_step = 0.01;
|
|
||||||
> = 0.7;
|
|
||||||
|
|
||||||
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
|
|
||||||
{
|
|
||||||
uv = float2(float(id & 2), float((id & 1) << 1));
|
|
||||||
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PS_FilmicCurve(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
|
|
||||||
{
|
|
||||||
float3 rgb = tex2D(BackBuffer, uv).rgb;
|
|
||||||
|
|
||||||
float3 curved = saturate(rgb * Exposure);
|
|
||||||
curved = pow(max(curved, 0.0), Toe);
|
|
||||||
curved = 1.0 - pow(max(1.0 - curved, 0.0), Shoulder);
|
|
||||||
|
|
||||||
return float4(saturate(lerp(rgb, curved, Amount)), 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
technique FilmicCurve <
|
|
||||||
ui_label = "Filmic Curve";
|
|
||||||
ui_tooltip = "Filmic contrast curve. Deepens the shadows and opens the highlights without clipping either end.";
|
|
||||||
>
|
|
||||||
{
|
|
||||||
pass
|
|
||||||
{
|
|
||||||
VertexShader = VS_PostProcess;
|
|
||||||
PixelShader = PS_FilmicCurve;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
-53
@@ -1,53 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
texture BackBufferTex : COLOR;
|
|
||||||
sampler BackBuffer { Texture = BackBufferTex; };
|
|
||||||
|
|
||||||
uniform float Distortion <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Distortion";
|
|
||||||
ui_tooltip = "Positive bulges the picture outwards, negative pinches it inwards.";
|
|
||||||
ui_min = -0.5; ui_max = 0.5; ui_step = 0.01;
|
|
||||||
> = 0.1;
|
|
||||||
|
|
||||||
uniform float Zoom <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Zoom";
|
|
||||||
ui_tooltip = "Scales the picture to hide the edges the warp pulls in.";
|
|
||||||
ui_min = 0.5; ui_max = 1.5; ui_step = 0.01;
|
|
||||||
> = 1.0;
|
|
||||||
|
|
||||||
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
|
|
||||||
{
|
|
||||||
uv = float2(float(id & 2), float((id & 1) << 1));
|
|
||||||
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PS_LensDistortion(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
|
|
||||||
{
|
|
||||||
float aspect = BUFFER_WIDTH * BUFFER_RCP_HEIGHT;
|
|
||||||
float2 half_size = float2(aspect, 1.0);
|
|
||||||
float2 unit = half_size / length(half_size);
|
|
||||||
|
|
||||||
float2 centred = (uv - 0.5) * 2.0 * unit;
|
|
||||||
float r2 = dot(centred, centred);
|
|
||||||
centred *= 1.0 + Distortion * r2;
|
|
||||||
centred /= max(Zoom, 0.001);
|
|
||||||
|
|
||||||
float2 source = centred / (2.0 * unit) + 0.5;
|
|
||||||
|
|
||||||
return float4(tex2D(BackBuffer, source).rgb, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
technique LensDistortion <
|
|
||||||
ui_label = "Lens Distortion";
|
|
||||||
ui_tooltip = "Barrel or pincushion warp, like looking through a wide angle lens.";
|
|
||||||
>
|
|
||||||
{
|
|
||||||
pass
|
|
||||||
{
|
|
||||||
VertexShader = VS_PostProcess;
|
|
||||||
PixelShader = PS_LensDistortion;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
-66
@@ -1,66 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
texture BackBufferTex : COLOR;
|
|
||||||
sampler BackBuffer { Texture = BackBufferTex; };
|
|
||||||
|
|
||||||
uniform float InputBlack <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Input Black";
|
|
||||||
ui_tooltip = "Input level mapped to black. Raise it to deepen washed out shadows.";
|
|
||||||
ui_min = 0.0; ui_max = 0.5; ui_step = 0.005;
|
|
||||||
> = 0.0;
|
|
||||||
|
|
||||||
uniform float InputWhite <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Input White";
|
|
||||||
ui_min = 0.5; ui_max = 1.0; ui_step = 0.005;
|
|
||||||
> = 1.0;
|
|
||||||
|
|
||||||
uniform float Gamma <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Gamma";
|
|
||||||
ui_min = 0.2; ui_max = 3.0; ui_step = 0.01;
|
|
||||||
> = 1.0;
|
|
||||||
|
|
||||||
uniform float OutputBlack <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Output Black";
|
|
||||||
ui_tooltip = "Lifts crushed shadows so detail stops collapsing into one flat black.";
|
|
||||||
ui_min = 0.0; ui_max = 0.5; ui_step = 0.005;
|
|
||||||
> = 0.0;
|
|
||||||
|
|
||||||
uniform float OutputWhite <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Output White";
|
|
||||||
ui_min = 0.5; ui_max = 1.0; ui_step = 0.005;
|
|
||||||
> = 1.0;
|
|
||||||
|
|
||||||
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
|
|
||||||
{
|
|
||||||
uv = float2(float(id & 2), float((id & 1) << 1));
|
|
||||||
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PS_Levels(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
|
|
||||||
{
|
|
||||||
float3 rgb = tex2D(BackBuffer, uv).rgb;
|
|
||||||
|
|
||||||
rgb = saturate((rgb - InputBlack) / max(InputWhite - InputBlack, 0.001));
|
|
||||||
rgb = pow(max(rgb, 0.0), 1.0 / max(Gamma, 0.001));
|
|
||||||
rgb = lerp(OutputBlack, OutputWhite, rgb);
|
|
||||||
|
|
||||||
return float4(saturate(rgb), 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
technique Levels <
|
|
||||||
ui_label = "Levels";
|
|
||||||
ui_tooltip = "Black point, white point, gamma and output range. Use it to fix crushed or washed out shadows.";
|
|
||||||
>
|
|
||||||
{
|
|
||||||
pass
|
|
||||||
{
|
|
||||||
VertexShader = VS_PostProcess;
|
|
||||||
PixelShader = PS_Levels;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
-88
@@ -1,88 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
texture BackBufferTex : COLOR;
|
|
||||||
sampler BackBuffer { Texture = BackBufferTex; };
|
|
||||||
|
|
||||||
uniform float Length <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Length";
|
|
||||||
ui_tooltip = "How far the streaks reach, as a percentage of screen height.";
|
|
||||||
ui_min = 0.0; ui_max = 20.0; ui_step = 0.5;
|
|
||||||
> = 5.0;
|
|
||||||
|
|
||||||
uniform float Zoom <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Zoom";
|
|
||||||
ui_tooltip = "Streaks running out from the centre of the screen, as if rushing forward. The centre stays sharp.";
|
|
||||||
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
|
|
||||||
> = 1.0;
|
|
||||||
|
|
||||||
uniform float Pan <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Pan";
|
|
||||||
ui_tooltip = "Streaks running in one fixed direction, as if the camera were sweeping across.";
|
|
||||||
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
|
|
||||||
> = 0.0;
|
|
||||||
|
|
||||||
uniform float Angle <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Pan Angle";
|
|
||||||
ui_tooltip = "Direction of the sweep, in degrees.";
|
|
||||||
ui_min = 0.0; ui_max = 360.0; ui_step = 5.0;
|
|
||||||
> = 0.0;
|
|
||||||
|
|
||||||
uniform float Spin <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Spin";
|
|
||||||
ui_tooltip = "Streaks curling around the centre, as if the camera were rolling. Negative turns the other way.";
|
|
||||||
ui_min = -1.0; ui_max = 1.0; ui_step = 0.05;
|
|
||||||
> = 0.0;
|
|
||||||
|
|
||||||
static const int TAPS = 24;
|
|
||||||
|
|
||||||
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
|
|
||||||
{
|
|
||||||
uv = float2(float(id & 2), float((id & 1) << 1));
|
|
||||||
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PS_MotionBlur(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
|
|
||||||
{
|
|
||||||
float aspect = BUFFER_WIDTH * BUFFER_RCP_HEIGHT;
|
|
||||||
float2 to_screen = float2(aspect, 1.0);
|
|
||||||
|
|
||||||
float2 centred = (uv - 0.5) * to_screen * 2.0;
|
|
||||||
float2 outward = centred;
|
|
||||||
float2 around = float2(-centred.y, centred.x);
|
|
||||||
|
|
||||||
float radians_angle = Angle * 0.01745329;
|
|
||||||
float2 sweep = float2(cos(radians_angle), sin(radians_angle));
|
|
||||||
|
|
||||||
float2 velocity = sweep * Pan + outward * Zoom + around * Spin;
|
|
||||||
velocity *= Length * 0.01;
|
|
||||||
velocity /= to_screen;
|
|
||||||
|
|
||||||
float jitter = frac(sin(dot(pos.xy, float2(12.9898, 78.233))) * 43758.5453);
|
|
||||||
|
|
||||||
float3 sum = float3(0.0, 0.0, 0.0);
|
|
||||||
[unroll] 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
-60
@@ -1,60 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2012 PPSSPP Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
// Ported from naturalA.fsh in PPSSPP, by ShadX, modified by SimoneT.
|
|
||||||
|
|
||||||
texture BackBufferTex : COLOR;
|
|
||||||
sampler BackBuffer { Texture = BackBufferTex; };
|
|
||||||
|
|
||||||
uniform float Luma <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Luma Curve";
|
|
||||||
ui_tooltip = "Gamma applied to the luminance channel in YIQ space.";
|
|
||||||
ui_min = 0.5; ui_max = 2.0; ui_step = 0.01;
|
|
||||||
> = 1.2;
|
|
||||||
|
|
||||||
uniform float Chroma <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Chroma Gain";
|
|
||||||
ui_tooltip = "Boost applied to the two colour difference channels.";
|
|
||||||
ui_min = 0.0; ui_max = 2.0; ui_step = 0.01;
|
|
||||||
> = 1.2;
|
|
||||||
|
|
||||||
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
|
|
||||||
{
|
|
||||||
uv = float2(float(id & 2), float((id & 1) << 1));
|
|
||||||
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PS_Natural(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
|
|
||||||
{
|
|
||||||
const float3x3 RGBtoYIQ = float3x3(0.299, 0.587, 0.114,
|
|
||||||
0.596, -0.275, -0.321,
|
|
||||||
0.212, -0.523, 0.311);
|
|
||||||
|
|
||||||
const float3x3 YIQtoRGB = float3x3(1.0, 0.95568806, 0.61985809,
|
|
||||||
1.0, -0.27158180, -0.64687382,
|
|
||||||
1.0, -1.10817733, 1.70506456);
|
|
||||||
|
|
||||||
float3 rgb = tex2D(BackBuffer, uv).rgb;
|
|
||||||
float3 yiq = mul(RGBtoYIQ, rgb);
|
|
||||||
|
|
||||||
yiq.x = pow(max(yiq.x, 0.0), Luma);
|
|
||||||
yiq.yz *= Chroma;
|
|
||||||
|
|
||||||
return float4(saturate(mul(YIQtoRGB, yiq)), 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
technique NaturalColors <
|
|
||||||
ui_label = "Natural Colours";
|
|
||||||
ui_tooltip = "Warms the picture and lifts saturation for a less washed out look. Ported from the PPSSPP shader.";
|
|
||||||
>
|
|
||||||
{
|
|
||||||
pass
|
|
||||||
{
|
|
||||||
VertexShader = VS_PostProcess;
|
|
||||||
PixelShader = PS_Natural;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
-90
@@ -1,90 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
texture BackBufferTex : COLOR;
|
|
||||||
sampler BackBuffer { Texture = BackBufferTex; };
|
|
||||||
|
|
||||||
uniform float Timer < source = "timer"; > = 0.0;
|
|
||||||
|
|
||||||
uniform float Horizon <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Reflection Line";
|
|
||||||
ui_tooltip = "Height on screen where the reflective floor begins. Everything above it is left untouched.";
|
|
||||||
ui_min = 0.0; ui_max = 1.0; ui_step = 0.01;
|
|
||||||
> = 0.55;
|
|
||||||
|
|
||||||
uniform float Amount <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Amount";
|
|
||||||
ui_tooltip = "How strongly the reflection shows through the floor.";
|
|
||||||
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
|
|
||||||
> = 0.35;
|
|
||||||
|
|
||||||
uniform float Falloff <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Falloff";
|
|
||||||
ui_tooltip = "How quickly the reflection fades as the floor comes towards the viewer. At zero it stays even.";
|
|
||||||
ui_min = 0.0; ui_max = 4.0; ui_step = 0.1;
|
|
||||||
> = 1.2;
|
|
||||||
|
|
||||||
uniform float Perspective <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Perspective";
|
|
||||||
ui_tooltip = "Stretches or squashes the mirrored image. One is a true mirror, higher values pull it towards the line.";
|
|
||||||
ui_min = 0.2; ui_max = 2.0; ui_step = 0.05;
|
|
||||||
> = 1.0;
|
|
||||||
|
|
||||||
uniform float Ripple <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Ripple";
|
|
||||||
ui_tooltip = "Amplitude of the waves disturbing the reflection. At zero the mirror is perfectly still.";
|
|
||||||
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
|
|
||||||
> = 0.0;
|
|
||||||
|
|
||||||
uniform float RippleSpeed <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Ripple Speed";
|
|
||||||
ui_tooltip = "How fast the waves travel.";
|
|
||||||
ui_min = 0.0; ui_max = 4.0; ui_step = 0.1;
|
|
||||||
> = 1.0;
|
|
||||||
|
|
||||||
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
|
|
||||||
{
|
|
||||||
uv = float2(float(id & 2), float((id & 1) << 1));
|
|
||||||
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PS_Reflections(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
|
|
||||||
{
|
|
||||||
float3 color = tex2D(BackBuffer, uv).rgb;
|
|
||||||
|
|
||||||
float depth = uv.y - Horizon;
|
|
||||||
float on_floor = step(0.0, depth);
|
|
||||||
float span = max(1.0 - Horizon, 0.001);
|
|
||||||
float distance_down = saturate(depth / span);
|
|
||||||
|
|
||||||
float seconds = Timer * 0.001;
|
|
||||||
float wave = sin(uv.x * 38.0 + seconds * RippleSpeed * 2.0) *
|
|
||||||
sin(uv.y * 21.0 - seconds * RippleSpeed * 1.3);
|
|
||||||
float2 disturbance = float2(wave * 0.004, wave * 0.002) * Ripple * distance_down;
|
|
||||||
|
|
||||||
float2 mirrored = float2(uv.x, Horizon - depth * Perspective) + disturbance;
|
|
||||||
float3 reflection = tex2D(BackBuffer, saturate(mirrored)).rgb;
|
|
||||||
|
|
||||||
float fade = pow(max(1.0 - distance_down, 0.0001), Falloff);
|
|
||||||
float strength = Amount * fade * on_floor;
|
|
||||||
|
|
||||||
return float4(lerp(color, reflection, strength), 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
technique Reflections <
|
|
||||||
ui_label = "Reflections";
|
|
||||||
ui_tooltip = "Mirrors the picture into a reflective floor below a line you choose, with optional water ripples.";
|
|
||||||
>
|
|
||||||
{
|
|
||||||
pass
|
|
||||||
{
|
|
||||||
VertexShader = VS_PostProcess;
|
|
||||||
PixelShader = PS_Reflections;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
-66
@@ -1,66 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2012 PPSSPP Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
// Ported from scanlines.fsh in PPSSPP.
|
|
||||||
|
|
||||||
|
|
||||||
texture BackBufferTex : COLOR;
|
|
||||||
sampler BackBuffer { Texture = BackBufferTex; };
|
|
||||||
|
|
||||||
uniform float Density <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Line Density";
|
|
||||||
ui_tooltip = "Number of scanline pairs across the screen.";
|
|
||||||
ui_min = 60.0; ui_max = 720.0; ui_step = 10.0;
|
|
||||||
> = 340.0;
|
|
||||||
|
|
||||||
uniform float Intensity <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Intensity";
|
|
||||||
ui_tooltip = "How dark the gaps between lines become.";
|
|
||||||
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
|
|
||||||
> = 0.5;
|
|
||||||
|
|
||||||
uniform float Tint <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Phosphor Tint";
|
|
||||||
ui_tooltip = "Strength of the green-warm phosphor cast.";
|
|
||||||
ui_min = 0.0; ui_max = 1.0; ui_step = 0.05;
|
|
||||||
> = 1.0;
|
|
||||||
|
|
||||||
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
|
|
||||||
{
|
|
||||||
uv = float2(float(id & 2), float((id & 1) << 1));
|
|
||||||
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PS_Scanlines(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
|
|
||||||
{
|
|
||||||
float line_pos = uv.y * Density * 0.5;
|
|
||||||
float gate = cos((frac(line_pos) - 0.5) * 3.1415926 * Intensity) * 1.5;
|
|
||||||
|
|
||||||
float3 rgb = tex2D(BackBuffer, uv).rgb;
|
|
||||||
float3 color = rgb * 0.5 + 0.5 * rgb * rgb * 1.2;
|
|
||||||
|
|
||||||
float3 phosphor = lerp(float3(1.0, 1.0, 1.0), float3(0.9, 1.0, 0.7), Tint);
|
|
||||||
color *= phosphor;
|
|
||||||
|
|
||||||
float2 diff = uv - 0.5;
|
|
||||||
color *= 1.1 - 0.6 * (dot(diff, diff) * 2.0);
|
|
||||||
|
|
||||||
return float4(saturate(color * saturate(gate)), 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
technique Scanlines <
|
|
||||||
ui_label = "Scanlines";
|
|
||||||
ui_tooltip = "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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
-43
@@ -1,43 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
texture BackBufferTex : COLOR;
|
|
||||||
sampler BackBuffer { Texture = BackBufferTex; };
|
|
||||||
|
|
||||||
uniform float Amount <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Amount";
|
|
||||||
ui_min = 0.0; ui_max = 3.0; ui_step = 0.01;
|
|
||||||
> = 0.6;
|
|
||||||
|
|
||||||
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
|
|
||||||
{
|
|
||||||
uv = float2(float(id & 2), float((id & 1) << 1));
|
|
||||||
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PS_Sharpen(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
|
|
||||||
{
|
|
||||||
float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT);
|
|
||||||
|
|
||||||
float3 centre = tex2D(BackBuffer, uv).rgb;
|
|
||||||
float3 blur = tex2D(BackBuffer, uv + float2(-texel.x, 0.0)).rgb;
|
|
||||||
blur += tex2D(BackBuffer, uv + float2(texel.x, 0.0)).rgb;
|
|
||||||
blur += tex2D(BackBuffer, uv + float2(0.0, -texel.y)).rgb;
|
|
||||||
blur += tex2D(BackBuffer, uv + float2(0.0, texel.y)).rgb;
|
|
||||||
blur *= 0.25;
|
|
||||||
|
|
||||||
return float4(centre + (centre - blur) * Amount, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
technique Sharpen <
|
|
||||||
ui_label = "Sharpen";
|
|
||||||
ui_tooltip = "Unsharp mask that brings back edge detail lost to scaling. Most useful after upscaling a low internal resolution.";
|
|
||||||
>
|
|
||||||
{
|
|
||||||
pass
|
|
||||||
{
|
|
||||||
VertexShader = VS_PostProcess;
|
|
||||||
PixelShader = PS_Sharpen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
-75
@@ -1,75 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
texture BackBufferTex : COLOR;
|
|
||||||
sampler BackBuffer { Texture = BackBufferTex; };
|
|
||||||
|
|
||||||
uniform float ShadowHue <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Shadow Hue";
|
|
||||||
ui_min = 0.0; ui_max = 360.0; ui_step = 1.0;
|
|
||||||
> = 210.0;
|
|
||||||
|
|
||||||
uniform float ShadowStrength <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Shadow Strength";
|
|
||||||
ui_min = 0.0; ui_max = 1.0; ui_step = 0.01;
|
|
||||||
> = 0.0;
|
|
||||||
|
|
||||||
uniform float HighlightHue <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Highlight Hue";
|
|
||||||
ui_min = 0.0; ui_max = 360.0; ui_step = 1.0;
|
|
||||||
> = 45.0;
|
|
||||||
|
|
||||||
uniform float HighlightStrength <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Highlight Strength";
|
|
||||||
ui_min = 0.0; ui_max = 1.0; ui_step = 0.01;
|
|
||||||
> = 0.0;
|
|
||||||
|
|
||||||
uniform float Balance <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Balance";
|
|
||||||
ui_tooltip = "Moves the split between what counts as shadow and what counts as highlight.";
|
|
||||||
ui_min = -0.5; ui_max = 0.5; ui_step = 0.01;
|
|
||||||
> = 0.0;
|
|
||||||
|
|
||||||
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
|
|
||||||
{
|
|
||||||
uv = float2(float(id & 2), float((id & 1) << 1));
|
|
||||||
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float3 HueToRGB(float hue)
|
|
||||||
{
|
|
||||||
float h = frac(hue / 360.0) * 6.0;
|
|
||||||
return saturate(float3(abs(h - 3.0) - 1.0, 2.0 - abs(h - 2.0), 2.0 - abs(h - 4.0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PS_SplitToning(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
|
|
||||||
{
|
|
||||||
float3 rgb = tex2D(BackBuffer, uv).rgb;
|
|
||||||
|
|
||||||
float luma = saturate(dot(rgb, float3(0.2126, 0.7152, 0.0722)) + Balance);
|
|
||||||
|
|
||||||
float3 shadow_tint = HueToRGB(ShadowHue) - 0.5;
|
|
||||||
float3 highlight_tint = HueToRGB(HighlightHue) - 0.5;
|
|
||||||
|
|
||||||
rgb += shadow_tint * ShadowStrength * 0.25 * (1.0 - luma);
|
|
||||||
rgb += highlight_tint * HighlightStrength * 0.25 * luma;
|
|
||||||
|
|
||||||
return float4(saturate(rgb), 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
technique SplitToning <
|
|
||||||
ui_label = "Split Toning";
|
|
||||||
ui_tooltip = "Tints the shadows and the highlights towards two different hues.";
|
|
||||||
>
|
|
||||||
{
|
|
||||||
pass
|
|
||||||
{
|
|
||||||
VertexShader = VS_PostProcess;
|
|
||||||
PixelShader = PS_SplitToning;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
-52
@@ -1,52 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2012 PPSSPP Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
// Ported from vignette.fsh in PPSSPP, by Henrik Rydgard.
|
|
||||||
|
|
||||||
texture BackBufferTex : COLOR;
|
|
||||||
sampler BackBuffer { Texture = BackBufferTex; };
|
|
||||||
|
|
||||||
uniform float Strength <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Strength";
|
|
||||||
ui_tooltip = "How dark the corners become.";
|
|
||||||
ui_min = 0.0; ui_max = 2.0; ui_step = 0.01;
|
|
||||||
> = 0.6;
|
|
||||||
|
|
||||||
uniform float Aspect <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Aspect";
|
|
||||||
ui_min = 0.5; ui_max = 2.0; ui_step = 0.01;
|
|
||||||
> = 1.0;
|
|
||||||
|
|
||||||
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
|
|
||||||
{
|
|
||||||
uv = float2(float(id & 2), float((id & 1) << 1));
|
|
||||||
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PS_Vignette(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
|
|
||||||
{
|
|
||||||
float2 diff = uv - 0.5;
|
|
||||||
diff.x *= Aspect;
|
|
||||||
diff.y /= max(Aspect, 0.0001);
|
|
||||||
|
|
||||||
float falloff = 1.0 - min(1.0, Strength * dot(diff, diff) * 2.0);
|
|
||||||
float3 rgb = tex2D(BackBuffer, uv).rgb;
|
|
||||||
|
|
||||||
return float4(rgb * falloff, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
technique Vignette <
|
|
||||||
ui_label = "Vignette";
|
|
||||||
ui_tooltip = "Darkens the corners of the screen to pull the eye towards the middle, the way a camera lens falls off at its edges.";
|
|
||||||
>
|
|
||||||
{
|
|
||||||
pass
|
|
||||||
{
|
|
||||||
VertexShader = VS_PostProcess;
|
|
||||||
PixelShader = PS_Vignette;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
-76
@@ -1,76 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
texture BackBufferTex : COLOR;
|
|
||||||
sampler BackBuffer { Texture = BackBufferTex; };
|
|
||||||
|
|
||||||
uniform float Temperature <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Temperature";
|
|
||||||
ui_tooltip = "Negative cools the picture towards blue, positive warms it towards orange.";
|
|
||||||
ui_min = -100.0; ui_max = 100.0; ui_step = 1.0;
|
|
||||||
> = 0.0;
|
|
||||||
|
|
||||||
uniform float Tint <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Tint";
|
|
||||||
ui_tooltip = "Negative shifts towards green, positive towards magenta.";
|
|
||||||
ui_min = -100.0; ui_max = 100.0; ui_step = 1.0;
|
|
||||||
> = 0.0;
|
|
||||||
|
|
||||||
void VS_PostProcess(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
|
|
||||||
{
|
|
||||||
uv = float2(float(id & 2), float((id & 1) << 1));
|
|
||||||
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float3 WhitePointLMS(float t1, float t2)
|
|
||||||
{
|
|
||||||
float shift = 0.05;
|
|
||||||
if (t1 < 0.0)
|
|
||||||
{
|
|
||||||
shift = 0.10;
|
|
||||||
}
|
|
||||||
float x = 0.31271 - t1 * shift;
|
|
||||||
float y = 2.87 * x - 3.0 * x * x - 0.27509507 + t2 * 0.05;
|
|
||||||
|
|
||||||
float big_y = 1.0;
|
|
||||||
float big_x = big_y * x / y;
|
|
||||||
float big_z = big_y * (1.0 - x - y) / y;
|
|
||||||
|
|
||||||
return float3( 0.7328 * big_x + 0.4296 * big_y - 0.1624 * big_z,
|
|
||||||
-0.7036 * big_x + 1.6975 * big_y + 0.0061 * big_z,
|
|
||||||
0.0030 * big_x + 0.0136 * big_y + 0.9834 * big_z);
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PS_WhiteBalance(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
|
|
||||||
{
|
|
||||||
float3 rgb = pow(max(tex2D(BackBuffer, uv).rgb, 0.0), 2.2);
|
|
||||||
|
|
||||||
float3 balance = float3(0.949237, 1.03542, 1.08728) /
|
|
||||||
WhitePointLMS(Temperature / 65.0, Tint / 65.0);
|
|
||||||
|
|
||||||
const float3x3 rgb_to_lms = float3x3(0.390405, 0.549941, 0.008926,
|
|
||||||
0.070841, 0.963172, 0.001358,
|
|
||||||
0.023108, 0.128021, 0.936245);
|
|
||||||
const float3x3 lms_to_rgb = float3x3( 2.858470, -1.628790, -0.024891,
|
|
||||||
-0.210182, 1.158200, 0.000324,
|
|
||||||
-0.041812, -0.118169, 1.068670);
|
|
||||||
|
|
||||||
float3 lms = mul(rgb_to_lms, rgb) * balance;
|
|
||||||
rgb = mul(lms_to_rgb, lms);
|
|
||||||
|
|
||||||
return float4(saturate(pow(max(rgb, 0.0), 1.0 / 2.2)), 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
technique WhiteBalance <
|
|
||||||
ui_label = "White Balance";
|
|
||||||
ui_tooltip = "Corrects a picture that looks too cool, too warm or tinted.";
|
|
||||||
>
|
|
||||||
{
|
|
||||||
pass
|
|
||||||
{
|
|
||||||
VertexShader = VS_PostProcess;
|
|
||||||
PixelShader = PS_WhiteBalance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -100,6 +100,8 @@ For reasons unberknownst to any human being, `glslangValidator` will crash upon
|
|||||||
|
|
||||||
For this reason this patch is NOT applied to default on all platforms (for obvious reasons) - instead this is a HaikuOS specific patch, apply with `git apply <absolute path to patch>` after cloning SPIRV-Tools then `make -C build` and add the resulting binary (in `build/StandAlone/glslang`) into PATH.
|
For this reason this patch is NOT applied to default on all platforms (for obvious reasons) - instead this is a HaikuOS specific patch, apply with `git apply <absolute path to patch>` after cloning SPIRV-Tools then `make -C build` and add the resulting binary (in `build/StandAlone/glslang`) into PATH.
|
||||||
|
|
||||||
|
`cubeb_devel` will also not work, either disable cubeb or uninstall it.
|
||||||
|
|
||||||
Still will not run flawlessly until `mesa-24` is available. Modify CMakeCache.txt with the `.so` of libGL and libGLESv2 by doing the incredibly difficult task of copy pasting them (`cp /boot/system/lib/libGL.so .`)
|
Still will not run flawlessly until `mesa-24` is available. Modify CMakeCache.txt with the `.so` of libGL and libGLESv2 by doing the incredibly difficult task of copy pasting them (`cp /boot/system/lib/libGL.so .`)
|
||||||
|
|
||||||
If you have `quazip1_qt6_devel`, uninstall it. It may call `Core5Compat` on CMake which is wrongly packaged.
|
If you have `quazip1_qt6_devel`, uninstall it. It may call `Core5Compat` on CMake which is wrongly packaged.
|
||||||
|
|||||||
+137
-1
@@ -2,7 +2,122 @@
|
|||||||
|
|
||||||
General guide for cross compiling.
|
General guide for cross compiling.
|
||||||
|
|
||||||
## Debian ARM64
|
## Gentoo
|
||||||
|
|
||||||
|
Gentoo's cross-compilation setup is relatively easy, provided you're already familiar with portage.
|
||||||
|
|
||||||
|
### Crossdev
|
||||||
|
|
||||||
|
First, emerge crossdev via `sudo emerge -a sys-devel/crossdev`.
|
||||||
|
|
||||||
|
Now, set up the environment depending on the target architecture; e.g.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo crossdev powerpc64le
|
||||||
|
sudo crossdev aarch64
|
||||||
|
```
|
||||||
|
|
||||||
|
### QEMU
|
||||||
|
|
||||||
|
Installing a qemu user setup is recommended for testing. To do so, you will need the relevant USE flags:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
app-emulation/qemu static-user qemu_user_targets_ppc64le qemu_user_targets_aarch64
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that to use cross-emerged libraries, you will need to tell qemu where the sysroot is. You can do this with an alias:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
alias qemu-ppc64le="qemu-ppc64le -L /usr/powerpc64le-unknown-linux-gnu"
|
||||||
|
alias qemu-aarch64="qemu-aarch64 -L /usr/aarch64-unknown-linux-gnu"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
Some packages have broken USE flags on other architectures; you'll also need to set up python targets. In `/usr/<target>-unknown-linux-gnu/etc/portage/package.use`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
>=net-misc/curl-8.16.0-r1 ssl
|
||||||
|
|
||||||
|
*/* PYTHON_TARGETS: python3_13 PYTHON_SINGLE_TARGET: python3_13
|
||||||
|
*/* pam
|
||||||
|
|
||||||
|
sys-apps/util-linux pam su
|
||||||
|
app-shells/bash -readline
|
||||||
|
>=dev-libs/libpcre2-10.47 unicode
|
||||||
|
>=x11-libs/libxkbcommon-1.12.3 X
|
||||||
|
>=sys-libs/zlib-1.3.1-r1 minizip
|
||||||
|
>=app-alternatives/gpg-1-r3 ssl
|
||||||
|
>=app-crypt/gnupg-2.5.13-r2 ssl
|
||||||
|
|
||||||
|
dev-libs/* -introspection
|
||||||
|
media-libs/harfbuzz -introspection
|
||||||
|
dev-libs/quazip -qt5 qt6
|
||||||
|
```
|
||||||
|
|
||||||
|
Dependencies should be about the same [as normal Gentoo](./Deps.md), but removing gamemode and renderdoc is recommended. Keep in mind that when emerging, you want to use `emerge-<target>-unknown-linux-gnu`, e.g. `emerge-powerpc64le-unknown-linux-gnu`.
|
||||||
|
|
||||||
|
Enable GURU in the cross environment (as root):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mkdir -p /usr/powerpc64le-unknown-linux-gnu/etc/portage/repos.conf
|
||||||
|
cat << EOF > /usr/powerpc64le-unknown-linux-gnu/etc/portage/repos.conf/guru.conf
|
||||||
|
[guru]
|
||||||
|
location = /var/db/repos/guru
|
||||||
|
auto-sync = no
|
||||||
|
priority = 1
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
Now emerge your dependencies:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo emerge-powerpc64le-unknown-linux-gnu -aU app-arch/lz4 app-arch/zstd app-arch/unzip \
|
||||||
|
dev-libs/libfmt dev-libs/libusb dev-libs/mcl dev-libs/sirit dev-libs/oaknut \
|
||||||
|
dev-libs/unordered_dense dev-libs/boost dev-libs/openssl dev-libs/discord-rpc \
|
||||||
|
dev-util/spirv-tools dev-util/spirv-headers dev-util/vulkan-headers \
|
||||||
|
dev-util/vulkan-utility-libraries dev-util/glslang \
|
||||||
|
media-libs/libva media-libs/opus media-video/ffmpeg \
|
||||||
|
media-libs/VulkanMemoryAllocator media-libs/libsdl2 media-libs/cubeb \
|
||||||
|
net-libs/enet net-libs/mbedtls \
|
||||||
|
sys-libs/zlib \
|
||||||
|
dev-cpp/nlohmann_json dev-cpp/simpleini dev-cpp/cpp-httplib dev-cpp/cpp-jwt dev-cpp/catch \
|
||||||
|
net-wireless/wireless-tools \
|
||||||
|
dev-qt/qtbase:6 dev-libs/quazip \
|
||||||
|
virtual/pkgconfig
|
||||||
|
```
|
||||||
|
|
||||||
|
### Building
|
||||||
|
|
||||||
|
A toolchain is provided in `CMakeModules/GentooCross.cmake`. To use it:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cmake -S . -B build/ppc64 -DCMAKE_TOOLCHAIN_FILE=CMakeModules/GentooCross.cmake -G Ninja -DCROSS_TARGET=powerpc64le -DENABLE_OPENGL=OFF
|
||||||
|
```
|
||||||
|
|
||||||
|
Now build as normal:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cmake --build build/ppc64 -j$(nproc)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Alternatively
|
||||||
|
|
||||||
|
Only emerge the absolute necessities:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo emerge-powerpc64le-unknown-linux-gnu -aU media-video/ffmpeg media-libs/libsdl2 dev-qt/qtbase:6
|
||||||
|
```
|
||||||
|
|
||||||
|
Then set `YUZU_USE_CPM=ON`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cmake -S . -B build/ppc64 -DCMAKE_TOOLCHAIN_FILE=CMakeModules/GentooCross.cmake -G Ninja -DCROSS_TARGET=powerpc64le -DENABLE_OPENGL=OFF -DYUZU_USE_CPM=ON
|
||||||
|
```
|
||||||
|
|
||||||
|
## ARM64
|
||||||
|
|
||||||
|
### Debian ARM64
|
||||||
|
|
||||||
A painless guide for cross compilation (or to test NCE) from a x86_64 system without polluting your main.
|
A painless guide for cross compilation (or to test NCE) from a x86_64 system without polluting your main.
|
||||||
|
|
||||||
@@ -88,3 +203,24 @@ And finally, run the compiled executable with QEMU!
|
|||||||
```sh
|
```sh
|
||||||
qemu-aarch64 build/aarch64/bin/eden
|
qemu-aarch64 build/aarch64/bin/eden
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## PowerPC
|
||||||
|
|
||||||
|
This is a guide for FreeBSD users mainly.
|
||||||
|
|
||||||
|
Now you got a PowerPC sysroot - quickly decompress it somewhere, say `/home/user/opt/powerpc64le`. Create a toolchain file, for example `powerpc64le-toolchain.cmake`; always [consult the manual](https://man.freebsd.org/cgi/man.cgi?query=cmake-toolchains&sektion=7&manpath=FreeBSD+13.2-RELEASE+and+Ports).
|
||||||
|
|
||||||
|
There is a script to automatically do all of this under `./tools/setup-cross-sysroot.sh`.
|
||||||
|
|
||||||
|
Remember to add `-mabi=elfv1` to `CFLAGS`/`CXXFLAGS` otherwise the program will crash.
|
||||||
|
|
||||||
|
Specify:
|
||||||
|
|
||||||
|
- `YUZU_USE_CPM`: Set this to `ON` so packages can be found and built if your sysroot doesn't have them.
|
||||||
|
- `YUZU_USE_EXTERNAL_FFMPEG`: Set this to `ON` as well.
|
||||||
|
|
||||||
|
Then run using a program such as QEMU to emulate userland syscalls:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cmake --build build-ppc64-pc-freebsd -t dynarmic_tests -- -j8 && qemu-ppc64-static -L $HOME/opt/ppc64-freebsd/sysroot ./build-ppc64-pc-freebsd/bin/dynarmic_tests
|
||||||
|
```
|
||||||
|
|||||||
+3
-2
@@ -73,6 +73,7 @@ Certain other dependencies will be fetched by CPM regardless. System packages *c
|
|||||||
|
|
||||||
* [SimpleIni](https://github.com/brofield/simpleini)
|
* [SimpleIni](https://github.com/brofield/simpleini)
|
||||||
* [DiscordRPC](https://github.com/eden-emulator/discord-rpc)
|
* [DiscordRPC](https://github.com/eden-emulator/discord-rpc)
|
||||||
|
* [cubeb](https://github.com/mozilla/cubeb)
|
||||||
* [libusb](https://github.com/libusb/libusb)
|
* [libusb](https://github.com/libusb/libusb)
|
||||||
* [VulkanMemoryAllocator](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator)
|
* [VulkanMemoryAllocator](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator)
|
||||||
* [sirit](https://github.com/eden-emulator/sirit)
|
* [sirit](https://github.com/eden-emulator/sirit)
|
||||||
@@ -121,7 +122,7 @@ sudo emerge -a \
|
|||||||
dev-util/spirv-tools dev-util/spirv-headers dev-util/vulkan-headers \
|
dev-util/spirv-tools dev-util/spirv-headers dev-util/vulkan-headers \
|
||||||
dev-util/vulkan-utility-libraries dev-util/glslang \
|
dev-util/vulkan-utility-libraries dev-util/glslang \
|
||||||
media-gfx/renderdoc media-libs/libva media-libs/opus media-video/ffmpeg \
|
media-gfx/renderdoc media-libs/libva media-libs/opus media-video/ffmpeg \
|
||||||
media-libs/VulkanMemoryAllocator media-libs/libsdl3 \
|
media-libs/VulkanMemoryAllocator media-libs/libsdl3 media-libs/cubeb \
|
||||||
net-libs/enet \
|
net-libs/enet \
|
||||||
sys-libs/zlib \
|
sys-libs/zlib \
|
||||||
dev-cpp/nlohmann_json dev-cpp/simpleini dev-cpp/cpp-httplib dev-cpp/cpp-jwt \
|
dev-cpp/nlohmann_json dev-cpp/simpleini dev-cpp/cpp-httplib dev-cpp/cpp-jwt \
|
||||||
@@ -355,7 +356,7 @@ pacman -Syuu --needed --noconfirm $packages
|
|||||||
<summary>HaikuOS</summary>
|
<summary>HaikuOS</summary>
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
pkgman install git cmake patch libfmt_devel nlohmann_json lz4_devel opus_devel boost1.90_devel vulkan_devel qt6_base_devel qt6_declarative_devel libsdl3_devel ffmpeg7_devel libx11_devel enet_devel catch2_devel quazip1_qt5_devel qt6_5compat_devel glslang qt6_devel qt6_charts_devel simpleini quazip_qt6_devel
|
pkgman install git cmake patch libfmt_devel nlohmann_json lz4_devel opus_devel boost1.90_devel vulkan_devel qt6_base_devel qt6_declarative_devel libsdl3_devel ffmpeg7_devel libx11_devel enet_devel catch2_devel quazip1_qt5_devel qt6_5compat_devel glslang qt6_devel qt6_charts_devel cubeb_devel simpleini quazip_qt6_devel
|
||||||
```
|
```
|
||||||
|
|
||||||
[Caveats](./Caveats.md#haikuos).
|
[Caveats](./Caveats.md#haikuos).
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Modern game consoles require heavy power to be emulated appropriately. This is w
|
|||||||
|
|
||||||
For example, take a disk write, instead of emulating a proper SD card we instead use the C++ standard library for I/O. Additionally we use the abstractions provided by the `fs` service to "lie" to programs about certain SD card properties. Notably this includes making up sizes for the fake SD card, giving "realistic" values or expected outputs for a given card, and so on. And instead of writing to an actual SD card, the emulator simply writes to a file.
|
For example, take a disk write, instead of emulating a proper SD card we instead use the C++ standard library for I/O. Additionally we use the abstractions provided by the `fs` service to "lie" to programs about certain SD card properties. Notably this includes making up sizes for the fake SD card, giving "realistic" values or expected outputs for a given card, and so on. And instead of writing to an actual SD card, the emulator simply writes to a file.
|
||||||
|
|
||||||
This also means grand part of the emulator consists of just re-implementing firmware but using HLE primitives; for example audio doesn't go to an emulated audio device, but rather gets processed on the fly by a dedicated service and then passed to SDL3 or null backend.
|
This also means grand part of the emulator consists of just re-implementing firmware but using HLE primitives; for example audio doesn't go to an emulated audio device, but rather gets processed on the fly by a dedicated service and then passed to SDL3/cubeb/etc.
|
||||||
|
|
||||||
As such, many of the systems implemented are not 100% accurate to the original software, but they're "good enough" to pass as being so. While we do strive to maintain high compatibility (especially with homebrew), there are realistic limitations to these approaches.
|
As such, many of the systems implemented are not 100% accurate to the original software, but they're "good enough" to pass as being so. While we do strive to maintain high compatibility (especially with homebrew), there are realistic limitations to these approaches.
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ These options control dependencies.
|
|||||||
|
|
||||||
- `ENABLE_WEB_SERVICE` (ON) Enable multiplayer service
|
- `ENABLE_WEB_SERVICE` (ON) Enable multiplayer service
|
||||||
- `ENABLE_WIFI_SCAN` (OFF) Enable WiFi scanning (requires iw on Linux) - experimental
|
- `ENABLE_WIFI_SCAN` (OFF) Enable WiFi scanning (requires iw on Linux) - experimental
|
||||||
|
- `ENABLE_CUBEB` (ON) Enables the cubeb audio backend
|
||||||
|
- This option is subject for removal.
|
||||||
- `YUZU_TESTS` (ON) Compile tests - requires Catch2
|
- `YUZU_TESTS` (ON) Compile tests - requires Catch2
|
||||||
- `ENABLE_LTO` (OFF) Enable link-time optimization
|
- `ENABLE_LTO` (OFF) Enable link-time optimization
|
||||||
- Not recommended on Windows
|
- Not recommended on Windows
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# PowerPC 64 backend
|
||||||
|
|
||||||
|
The ppc64 backend currently only supports the little endian variant, with big endian support being experimental for the time being. Additionally only A32 is supported (for now).
|
||||||
|
|
||||||
|
- Flag handling: Flags are emulated via software, while there may be some funny tricks with the CTR, I'd rather not bother - plus it's widely known that those instructions are not nice on real metal - so I would rather take the i-cache cost.
|
||||||
|
- 128-bit atomics: No 128-bit atomic support is provided, this may cause wrong or erroneous execution in some contexts.
|
||||||
|
|
||||||
|
To handle endianess differences all 16/32/64-bit loads and stores to the "emulated memory" are byteswapped beforehand.
|
||||||
@@ -7,11 +7,12 @@ A dynamic recompiler for ARM.
|
|||||||
|
|
||||||
Cortex-A57 (32 and 64 bit) is the emulated guest target. See [ArchVersion](../../src/dynarmic/src/dynarmic/interface/A32/arch_version.h).
|
Cortex-A57 (32 and 64 bit) is the emulated guest target. See [ArchVersion](../../src/dynarmic/src/dynarmic/interface/A32/arch_version.h).
|
||||||
|
|
||||||
The only supported host architectures are x86-64, and AArch64. There are no plans to support any 32-bit architectures.
|
The only supported host architectures are x86-64, PowerPC 64, and AArch64. There are no plans to support any 32-bit architectures.
|
||||||
|
|
||||||
See [an example usage](../../src/dynarmic/tests/print_info.cpp).
|
See [an example usage](../../src/dynarmic/tests/print_info.cpp).
|
||||||
|
|
||||||
Design documentation can be found at [./Design.md](./Design.md).
|
Design documentation can be found at [./Design.md](./Design.md).
|
||||||
|
PowerPC design documentation can be found at [./PowerPC](./PowerPC.md).
|
||||||
|
|
||||||
Alternatives to Dynarmic
|
Alternatives to Dynarmic
|
||||||
------------------------
|
------------------------
|
||||||
|
|||||||
Vendored
+35
-44
@@ -106,6 +106,36 @@ endif()
|
|||||||
# SimpleIni
|
# SimpleIni
|
||||||
AddJsonPackage(simpleini)
|
AddJsonPackage(simpleini)
|
||||||
|
|
||||||
|
# Most linux distros don't package cubeb, so enable regardless of cpm settings
|
||||||
|
if(ENABLE_CUBEB)
|
||||||
|
AddJsonPackage(cubeb)
|
||||||
|
|
||||||
|
if (cubeb_ADDED)
|
||||||
|
if (NOT MSVC)
|
||||||
|
if (TARGET speex)
|
||||||
|
target_compile_options(speex PRIVATE $<$<COMPILE_LANGUAGE:C,CXX>:-Wno-sign-compare>)
|
||||||
|
endif()
|
||||||
|
set_target_properties(cubeb PROPERTIES COMPILE_OPTIONS "")
|
||||||
|
target_compile_options(cubeb INTERFACE
|
||||||
|
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-implicit-const-int-float-conversion>
|
||||||
|
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-shadow>
|
||||||
|
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-missing-declarations>
|
||||||
|
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-return-type>
|
||||||
|
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-uninitialized>
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
target_compile_options(cubeb PRIVATE
|
||||||
|
/wd4456
|
||||||
|
/wd4458
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT TARGET cubeb::cubeb)
|
||||||
|
add_library(cubeb::cubeb ALIAS cubeb)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
if (NOT YUZU_USE_BUNDLED_SDL3)
|
if (NOT YUZU_USE_BUNDLED_SDL3)
|
||||||
if (NOT WIN32)
|
if (NOT WIN32)
|
||||||
# Yuzu itself needs: Atomic Audio Events Joystick Haptic Sensor Threads Timers
|
# Yuzu itself needs: Atomic Audio Events Joystick Haptic Sensor Threads Timers
|
||||||
@@ -165,50 +195,6 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# reshadefx
|
|
||||||
if (ENABLE_RESHADE)
|
|
||||||
AddJsonPackage(NAME reshade DOWNLOAD_ONLY)
|
|
||||||
|
|
||||||
set(RESHADEFX_SHIM_DIR ${CMAKE_CURRENT_BINARY_DIR}/reshadefx_shim)
|
|
||||||
file(WRITE ${RESHADEFX_SHIM_DIR}/spirv.hpp "#include <spirv/unified1/spirv.hpp>\n")
|
|
||||||
file(WRITE ${RESHADEFX_SHIM_DIR}/GLSL.std.450.h "#include <spirv/unified1/GLSL.std.450.h>\n")
|
|
||||||
if (APPLE)
|
|
||||||
file(WRITE ${RESHADEFX_SHIM_DIR}/malloc.h "#include <stdlib.h>\n#include <alloca.h>\n")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_library(reshadefx STATIC
|
|
||||||
${reshade_SOURCE_DIR}/source/effect_codegen_spirv.cpp
|
|
||||||
${reshade_SOURCE_DIR}/source/effect_expression.cpp
|
|
||||||
${reshade_SOURCE_DIR}/source/effect_lexer.cpp
|
|
||||||
${reshade_SOURCE_DIR}/source/effect_parser_exp.cpp
|
|
||||||
${reshade_SOURCE_DIR}/source/effect_parser_stmt.cpp
|
|
||||||
${reshade_SOURCE_DIR}/source/effect_preprocessor.cpp
|
|
||||||
${reshade_SOURCE_DIR}/source/effect_symbol_table.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
target_include_directories(reshadefx SYSTEM PUBLIC ${reshade_SOURCE_DIR}/source)
|
|
||||||
target_include_directories(reshadefx PRIVATE ${RESHADEFX_SHIM_DIR})
|
|
||||||
target_link_libraries(reshadefx PUBLIC SPIRV-Headers::SPIRV-Headers)
|
|
||||||
|
|
||||||
if (NOT MSVC)
|
|
||||||
target_compile_options(reshadefx PRIVATE -w -fno-char8_t)
|
|
||||||
else()
|
|
||||||
target_compile_options(reshadefx PRIVATE /w /Zc:char8_t-)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (WIN32)
|
|
||||||
if (NOT MSVC)
|
|
||||||
target_compile_options(reshadefx PRIVATE -include share.h)
|
|
||||||
else()
|
|
||||||
target_compile_options(reshadefx PRIVATE /FIshare.h)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (NOT TARGET reshadefx::reshadefx)
|
|
||||||
add_library(reshadefx::reshadefx ALIAS reshadefx)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Catch2
|
# Catch2
|
||||||
if (YUZU_TESTS OR DYNARMIC_TESTS)
|
if (YUZU_TESTS OR DYNARMIC_TESTS)
|
||||||
AddJsonPackage(catch2)
|
AddJsonPackage(catch2)
|
||||||
@@ -263,6 +249,11 @@ endif()
|
|||||||
# TZDB (Time Zone Database)
|
# TZDB (Time Zone Database)
|
||||||
add_subdirectory(nx_tzdb)
|
add_subdirectory(nx_tzdb)
|
||||||
|
|
||||||
|
# PowerPC emitter
|
||||||
|
if (ARCHITECTURE_powerpc64)
|
||||||
|
add_subdirectory(powah)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_library(tz tz/tz/tz.cpp)
|
add_library(tz tz/tz/tz.cpp)
|
||||||
target_include_directories(tz PUBLIC ./tz)
|
target_include_directories(tz PUBLIC ./tz)
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -166,7 +166,7 @@ detect_architecture_symbols(
|
|||||||
"_M_MRX000")
|
"_M_MRX000")
|
||||||
|
|
||||||
detect_architecture_symbols(
|
detect_architecture_symbols(
|
||||||
ARCH ppc64
|
ARCH powerpc64
|
||||||
SYMBOLS
|
SYMBOLS
|
||||||
"__ppc64__"
|
"__ppc64__"
|
||||||
"__powerpc64__"
|
"__powerpc64__"
|
||||||
@@ -174,7 +174,7 @@ detect_architecture_symbols(
|
|||||||
"_M_PPC64")
|
"_M_PPC64")
|
||||||
|
|
||||||
detect_architecture_symbols(
|
detect_architecture_symbols(
|
||||||
ARCH ppc
|
ARCH powerpc
|
||||||
SYMBOLS
|
SYMBOLS
|
||||||
"__ppc__"
|
"__ppc__"
|
||||||
"__ppc"
|
"__ppc"
|
||||||
|
|||||||
Vendored
+10
@@ -0,0 +1,10 @@
|
|||||||
|
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
add_library(powah INTERFACE)
|
||||||
|
target_include_directories(powah INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
target_compile_options(powah INTERFACE -Wno-unused-parameter)
|
||||||
|
|
||||||
|
add_executable(powah_tests tests.cpp)
|
||||||
|
create_target_directory_groups(powah_tests)
|
||||||
|
target_link_libraries(powah_tests PRIVATE Catch2::Catch2WithMain)
|
||||||
Vendored
+145
@@ -0,0 +1,145 @@
|
|||||||
|
vabsdub,VX,04,1027
|
||||||
|
vabsduh,VX,04,1091
|
||||||
|
vabsduw,VX,04,1155
|
||||||
|
vaddcuw,VX,04,384
|
||||||
|
vaddfp,VX,04,10
|
||||||
|
vaddsbs,VX,04,768
|
||||||
|
vaddshs,VX,04,832
|
||||||
|
vaddsws,VX,04,896
|
||||||
|
vaddubm,VX,04,0
|
||||||
|
vaddubs,VX,04,512
|
||||||
|
vadduhm,VX,04,64
|
||||||
|
vadduhs,VX,04,576
|
||||||
|
vadduwm,VX,04,128
|
||||||
|
vadduws,VX,04,640
|
||||||
|
vand,VX,04,1028
|
||||||
|
vandc,VX,04,1092
|
||||||
|
vavgsb,VX,04,1282
|
||||||
|
vavgsh,VX,04,1346
|
||||||
|
vavgsw,VX,04,1410
|
||||||
|
vavgub,VX,04,1026
|
||||||
|
vavguh,VX,04,1090
|
||||||
|
vavguw,VX,04,1154
|
||||||
|
vcfsx,VDU,04842
|
||||||
|
vcfux,VDU,04778
|
||||||
|
vcmpbfp,VXR,04,966
|
||||||
|
vcmpeqfp,VXR,04,198
|
||||||
|
vcmpequb,VXR,04,6
|
||||||
|
vcmpequh,VXR,04,70
|
||||||
|
vcmpequw,VXR,04,134
|
||||||
|
vcmpgefp,VXR,04,454
|
||||||
|
vcmpgtfp,VXR,04,710
|
||||||
|
vcmpgtsb,VXR,04,774
|
||||||
|
vcmpgtsh,VXR,04,838
|
||||||
|
vcmpgtsw,VXR,04,902
|
||||||
|
vcmpgtub,VXR,04,518
|
||||||
|
vcmpgtuh,VXR,04,582
|
||||||
|
vcmpgtuw,VXR,04,646
|
||||||
|
vctsxs,VDU,04970
|
||||||
|
vctuxs,VDU,04906
|
||||||
|
vexptefp,VY,04,394
|
||||||
|
vlogefp,VY,04,458
|
||||||
|
vmaddfp,VXC,46
|
||||||
|
vmaxfp,VX,04,1034
|
||||||
|
vmaxsb,VX,04,258
|
||||||
|
vmaxsh,VX,04,322
|
||||||
|
vmaxsw,VX,04,386
|
||||||
|
vmaxub,VX,04,2
|
||||||
|
vmaxuh,VX,04,66
|
||||||
|
vmaxuw,VX,04,130
|
||||||
|
vmhaddshs,VXC,32
|
||||||
|
vmhraddshs,VXC,33
|
||||||
|
vminfp,VX,04,1098
|
||||||
|
vminsb,VX,04,770
|
||||||
|
vminsh,VX,04,834
|
||||||
|
vminsw,VX,04,898
|
||||||
|
vminub,VX,04,514
|
||||||
|
vminuh,VX,04,578
|
||||||
|
vminuw,VX,04,642
|
||||||
|
vmladduhm,VXC,34
|
||||||
|
vmrghb,VX,04,12
|
||||||
|
vmrghh,VX,04,76
|
||||||
|
vmrghw,VX,04,140
|
||||||
|
vmrglb,VX,04,268
|
||||||
|
vmrglh,VX,04,332
|
||||||
|
vmrglw,VX,04,396
|
||||||
|
vmsummbm,VXC,37
|
||||||
|
vmsumshm,VXC,40
|
||||||
|
vmsumshs,VXC,41
|
||||||
|
vmsumubm,VXC,36
|
||||||
|
vmsumuhm,VXC,38
|
||||||
|
vmsumuhs,VXC,39
|
||||||
|
vmulesb,VX,04,776
|
||||||
|
vmulesh,VX,04,840
|
||||||
|
vmuleub,VX,04,520
|
||||||
|
vmuleuh,VX,04,584
|
||||||
|
vmulosb,VX,04,264
|
||||||
|
vmulosh,VX,04,328
|
||||||
|
vmuloub,VX,04,8
|
||||||
|
vmulouh,VX,04,72
|
||||||
|
vnmsubfp,VXC,47
|
||||||
|
vnor,VX,04,1284
|
||||||
|
vor,VX,04,1156
|
||||||
|
vperm,VXC,43
|
||||||
|
vpkpx,VX,04,782
|
||||||
|
vpkshss,VX,04,398
|
||||||
|
vpkshus,VX,04,270
|
||||||
|
vpkswss,VX,04,462
|
||||||
|
vpkswus,VX,04,334
|
||||||
|
vpkuhum,VX,04,14
|
||||||
|
vpkuhus,VX,04,142
|
||||||
|
vpkuwum,VX,04,78
|
||||||
|
vpkuwus,VX,04,206
|
||||||
|
vrefp,VY,04,266
|
||||||
|
vrfim,VY,04,714
|
||||||
|
vrfin,VY,04,522
|
||||||
|
vrfip,VY,04,650
|
||||||
|
vrfiz,VY,04,586
|
||||||
|
vrlb,VX,04,4
|
||||||
|
vrlh,VX,04,68
|
||||||
|
vrlw,VX,04,132
|
||||||
|
vrsqrtefp,VY,04,330
|
||||||
|
vsel,VXC,42
|
||||||
|
vsl,VX,04,452
|
||||||
|
vslb,VX,04,260
|
||||||
|
vsldoi,VX,04,/ SH 44
|
||||||
|
vslh,VX,04,324
|
||||||
|
vslo,VX,04,1036
|
||||||
|
vslw,VX,04,388
|
||||||
|
vspltb,VU,04,524
|
||||||
|
vsplth,VU,04,588
|
||||||
|
vspltisb,VS,04,780
|
||||||
|
vspltish,VS,04,844
|
||||||
|
vspltisw,VS,04,908
|
||||||
|
vspltw,VSU,04,652
|
||||||
|
vsr,VX,04,708
|
||||||
|
vsrab,VX,04,772
|
||||||
|
vsrah,VX,04,836
|
||||||
|
vsraw,VX,04,900
|
||||||
|
vsrb,VX,04,516
|
||||||
|
vsrh,VX,04,580
|
||||||
|
vsro,VX,04,1100
|
||||||
|
vsrw,VX,04,644
|
||||||
|
vsubcuw,VX,04,1408
|
||||||
|
vsubfp,VX,04,74
|
||||||
|
vsubsbs,VX,04,1792
|
||||||
|
vsubshs,VX,04,1856
|
||||||
|
vsubsws,VX,04,1920
|
||||||
|
vsububm,VX,04,1024
|
||||||
|
vsububs,VX,04,1536
|
||||||
|
vsubuhm,VX,04,1088
|
||||||
|
vsubuhs,VX,04,1600
|
||||||
|
vsubuwm,VX,04,1152
|
||||||
|
vsubuws,VX,04,1664
|
||||||
|
vsumsws,VX,04,1928
|
||||||
|
vsum2sws,VX,04,1672
|
||||||
|
vsum4sbs,VX,04,1800
|
||||||
|
vsum4shs,VX,04,1608
|
||||||
|
vsum4ubs,VX,04,1544
|
||||||
|
vupkhpx,VY,04,846
|
||||||
|
vupkhsb,VY,04,526
|
||||||
|
vupkhsh,VY,04,590
|
||||||
|
vupklpx,VY,04,974
|
||||||
|
vupklsb,VY,04,654
|
||||||
|
vupklsh,VY,04,718
|
||||||
|
vxor,VX,04,122
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
$CC data2code.c -o data2code && ./data2code data.txt >powah_gen_base.hpp
|
||||||
|
$CC --target=powerpc64le test.S -c -o test && objdump -SC test
|
||||||
Vendored
+222
@@ -0,0 +1,222 @@
|
|||||||
|
add[o][.],Add,XO,31,266
|
||||||
|
addc[o][.],Add Carrying,XO,31,10
|
||||||
|
adde[o][.],Add Extended,XO,31,138
|
||||||
|
addi,Add Immediate,D,14,
|
||||||
|
addic,Add Immediate Carrying,D,12,
|
||||||
|
addic.,Add Immediate Carrying and Record,D,13,
|
||||||
|
addis,Add Immediate Shifted,D,15,
|
||||||
|
addme[o][.],Add to Minus One Extended,XO,31,234
|
||||||
|
addze[o][.],Add to Zero Extended,XO,31,202
|
||||||
|
and[.],AND,X,31,28
|
||||||
|
andc[.],AND with Complement,X,31,60
|
||||||
|
andi.,AND Immediate,D,28,
|
||||||
|
andis.,AND Immediate Shifted,D,29,
|
||||||
|
b[l][a],Branch,I,18,
|
||||||
|
bc[l][a],Branch Conditional,B,16,
|
||||||
|
bcctr[l],Branch Conditional to Count Register,XL,19,528
|
||||||
|
bclr[l],Branch Conditional Link Register,XL,19,16
|
||||||
|
cmp,Compare,X,31,0
|
||||||
|
cmpi,Compare Immediate,D,11,
|
||||||
|
cmpl,Compare Logical,X,31,32
|
||||||
|
cmpli,Compare Logical Immediate,D,10,
|
||||||
|
cntlzd,Count Leading Zeros Doubleword,X,31,58
|
||||||
|
cntlzw[.],Count Leading Zeros Word,X,31,26
|
||||||
|
crand,Condition Register AND,XL,19,257
|
||||||
|
crandc,Condition Register AND with Complement,XL,19,129
|
||||||
|
creqv,Condition Register Equivalent,XL,19,289
|
||||||
|
crnand,Condition Register NAND,XL,19,225
|
||||||
|
crnor,Condition Register NOR,XL,19,33
|
||||||
|
cror,Condition Register OR,XL,19,449
|
||||||
|
crorc,Condition Register OR with Complement,XL,19,417
|
||||||
|
crxor,Condition Register XOR,XL,19,193
|
||||||
|
dcbf,Data Cache Block Flush,X,31,86
|
||||||
|
dcbi,Data Cache Block Invalidate,X,31,470
|
||||||
|
dcbst,Data Cache Block Store,X,31,54
|
||||||
|
dcbt,Data Cache Block Touch,X,31,278
|
||||||
|
dcbtst,Data Cache Block Touch for Store,X,31,246
|
||||||
|
dcbz,Data Cache Block Set to Zero,X,31,1014
|
||||||
|
divd,Divide Doubleword,XO,31,489
|
||||||
|
divdu,Divide Doubleword Unsigned,XO,31,457
|
||||||
|
divw[o][.],Divide Word,XO,31,491
|
||||||
|
divwu[o][.],Divide Word Unsigned,XO,31,459
|
||||||
|
eciwx,External Control in Word Indexed (opt.),X,31,310
|
||||||
|
ecowx,External Control out Word Indexed (opt.),X,31,438
|
||||||
|
eieio,Enforce In-order Execution of I/O,X,31,854
|
||||||
|
eqv[.],Equivalent,X,31,284
|
||||||
|
extsb[.],Extend Sign Byte,X,31,954
|
||||||
|
extsh[.],Extend Sign Halfword,XO,31,922
|
||||||
|
extsw,Extend Sign Word,X,31,986
|
||||||
|
fabs[.],Floating Absolute Value,X,63,264
|
||||||
|
fadd[.],Floating Add,A,63,21
|
||||||
|
fadds[.],Floating Add Single,A,59,21
|
||||||
|
fcfid,Floating Convert from Integer Doubleword,X,63,846
|
||||||
|
fcmpo,Floating Compare Ordered,X,63,32
|
||||||
|
fcmpu,Floating Compare Unordered,XL,63,0
|
||||||
|
fctid,Floating Convert to Integer Doubleword,X,63,814
|
||||||
|
fctidz,Floating Convert to Integer Doubleword with Round Toward Zero,X,63,815
|
||||||
|
fctiw[.],Floating Convert to Integer Word,X,63,14
|
||||||
|
fctiwz[.],Floating Convert to Integer Word with Round to Zero,XL,63,15
|
||||||
|
fdiv[.],Floating Divide,A,63,18
|
||||||
|
fdivs[.],Floating Divide Single,A,59,18
|
||||||
|
fmadd[.],Floating Multiply-Add,A,63,29
|
||||||
|
fmadds[.],Floating Multiply-Add Single,A,59,29
|
||||||
|
fmr[.],Floating Move Register,X,63,72
|
||||||
|
fmsub[.],Floating Multiply-Subtract,A,63,28
|
||||||
|
fmsubs[.],Floating Multiply-Subtract Single,A,59,28
|
||||||
|
fmul[.],Floating Multiply,A,63,25
|
||||||
|
fmuls[.],Floating Multiply Single,A,59,25
|
||||||
|
fnabs[.],Floating Negative Absolute Value,X,63,136
|
||||||
|
fneg[.],Floating Negate,X,63,40
|
||||||
|
fnmadd[.],Floating Negative Multiply-Add,A,63,31
|
||||||
|
fnmadds[.],Floating Negative Multiply-Add Single,A,59,31
|
||||||
|
fnmsub[.],Floating Negative Multiply-Subtract,A,63,30
|
||||||
|
fnmsubs[.],Floating Negative Multiply-Subtract Single,A,59,30
|
||||||
|
fres[.],Floating Reciprocal Estimate Single (optional),A,59,24
|
||||||
|
frsp[.],Floating Round to Single Precision,X,63,12
|
||||||
|
frsqrte[.],Floating Reciprocal Square Root Estimate (optional),A,63,26
|
||||||
|
fsel[.],Floating-Point Select (optional),A,63,23
|
||||||
|
fsub[.],Floating Subtract,A,63,20
|
||||||
|
fsubs[.],Floating Subtract Single,A,59,20
|
||||||
|
icbi,Instruction Cache Block Invalidate,X,31,982
|
||||||
|
isync,Instruction Synchronize,X,19,150
|
||||||
|
lbz,Load Byte and Zero,D,34,
|
||||||
|
lbzu,Load Byte and Zero with Update,D,35,
|
||||||
|
lbzux,Load Byte and Zero with Update Indexed,X,31,119
|
||||||
|
lbzx,Load Byte and Zero Indexed,X,31,87
|
||||||
|
ld,Load Doubleword,DS,58,0
|
||||||
|
ldarx,Load Doubleword and Reserve Indexed,X,31,84
|
||||||
|
ldu,Load Doubleword with Update,DS,58,1
|
||||||
|
ldux,Load Doubleword with Update Indexed,X,31,53
|
||||||
|
ldx,Load Doubleword Indexed,X,31,21
|
||||||
|
lfd,Load Floating-Point Double,D,50,
|
||||||
|
lfdu,Load Floating-Point Double with Update,D,51,
|
||||||
|
lfdux,Load Floating-Point Double with Update Indexed,X,31,631
|
||||||
|
lfdx,Load Floating-Point Double Indexed,X,31,599
|
||||||
|
lfs,Load Floating-Point Single,D,48,
|
||||||
|
lfsu,Load Floating-Point Single with Update,D,49,
|
||||||
|
lfsux,Load Floating-Point Single with Update Indexed,X,31,567
|
||||||
|
lfsx,Load Floating-Point Single Indexed,X,31,535
|
||||||
|
lha,Load Half Algebraic,D,42,
|
||||||
|
lhau,Load Half Algebraic with Update,D,43,
|
||||||
|
lhaux,Load Half Algebraic with Update Indexed,X,31,375
|
||||||
|
lhax,Load Half Algebraic Indexed,X,31,343
|
||||||
|
lhbrx,Load Half Byte-Reversed Indexed,X,31,790
|
||||||
|
lhz,Load Half and Zero,D,40,
|
||||||
|
lhzu,Load Half and Zero with Update,D,41,
|
||||||
|
lhzux,Load Half and Zero with Update Indexed,X,31,331
|
||||||
|
lhzx,Load Half and Zero Indexed,X,31,279
|
||||||
|
lmw,Load Multiple Word,D,46,
|
||||||
|
lswi,Load String Word Immediate,X,31,597
|
||||||
|
lswx,Load String Word Indexed,X,31,533
|
||||||
|
lwa,Load Word Algebraic,DS,58,2
|
||||||
|
lwarx,Load Word and Reserve Indexed,X,31,20
|
||||||
|
lwaux,Load Word Algebraic with Update Indexed,X,31,373
|
||||||
|
lwax,Load Word Algebraic Indexed,X,31,341
|
||||||
|
lwbrx,Load Word Byte-Reversed Indexed,X,31,534
|
||||||
|
lwz,Load Word and Zero,D,32,
|
||||||
|
lwzu,Load Word with Zero Update,D,33,
|
||||||
|
lwzux,Load Word and Zero with Update Indexed,X,31,55
|
||||||
|
lwzx,Load Word and Zero Indexed,X,31,23
|
||||||
|
mcrf,Move Condition Register Field,XL,19,0
|
||||||
|
mcrfs,Move to Condition Register from FPSCR,X,63,64
|
||||||
|
mcrxr,Move to Condition Register from XER,X,31,512
|
||||||
|
mfcr,Move from Condition Register,X,31,19
|
||||||
|
mffs[.],Move from FPSCR,X,63,583
|
||||||
|
mfmsr,Move from Machine State Register,X,31,83
|
||||||
|
mfspr,Move from Special-Purpose Register,X,31,339
|
||||||
|
mfsr,Move from Segment Register,X,31,595
|
||||||
|
mfsrin,Move from Segment Register Indirect,X,31,659
|
||||||
|
mtcrf,Move to Condition Register Fields,XFX,31,144
|
||||||
|
mtfsb0[.],Move to FPSCR Bit 0,X,63,70
|
||||||
|
mtfsb1[.],Move to FPSCR Bit 1,X,63,38
|
||||||
|
mtfsf[.],Move to FPSCR Fields,XFL,63,711
|
||||||
|
mtfsfi[.],Move to FPSCR Field Immediate,X,63,134
|
||||||
|
mtmsr,Move to Machine State Register,X,31,146
|
||||||
|
mtspr,Move to Special-Purpose Register,X,31,467
|
||||||
|
mtsr,Move to Segment Register,X,31,210
|
||||||
|
mtsrin,Move to Segment Register Indirect,X,31,242
|
||||||
|
mulhd,Multiply High Doubleword,XO,31,73
|
||||||
|
mulhdu,Multiply High Doubleword Unsigned,XO,31,9
|
||||||
|
mulhw[.],Multiply High Word,XO,31,75
|
||||||
|
mulhwu[.],Multiply High Word Unsigned,XO,31,11
|
||||||
|
mulld,Multiply Low Doubleword,XO,31,233
|
||||||
|
mulli,Multiply Low Immediate,D,07,
|
||||||
|
mullw[o][.],Multiply Low Word,XO,31,235
|
||||||
|
nand[.],NAND,X,31,476
|
||||||
|
neg[o][.],Negate,XO,31,104
|
||||||
|
nor[.],NOR,X,31,124
|
||||||
|
or[.],OR,X,31,444
|
||||||
|
orc[.],OR with Complement,X,31,412
|
||||||
|
ori,OR Immediate,D,24,
|
||||||
|
oris,OR Immediate Shifted,D,25,
|
||||||
|
rfi,Return from Interrupt,X,19,50
|
||||||
|
rldcl,Rotate Left Doubleword then Clear Left,MDS,30,8
|
||||||
|
rldcr,Rotate Left Doubleword then Clear Right,MDS,30,9
|
||||||
|
rldic,Rotate Left Doubleword Immediate then Clear,MD,30,2
|
||||||
|
rldicl,Rotate Left Doubleword Immediate then Clear Left,MD,30,0
|
||||||
|
rldicr,Rotate Left Doubleword Immediate then Clear Right,MD,30,1
|
||||||
|
rldimi,Rotate Left Doubleword Immediate then Mask Insert,MD,30,3
|
||||||
|
rlwimi[.],Rotate Left Word Immediate then Mask Insert,M,20,
|
||||||
|
rlwinm[.],Rotate Left Word Immediate then AND with Mask,M,21,
|
||||||
|
rlwnm[.],Rotate Left Word then AND with Mask,M,23,
|
||||||
|
sc,System Call,SC,17,
|
||||||
|
si,Subtract Immediate,D,12,
|
||||||
|
si.,Subtract Immediate and Record,D,13,
|
||||||
|
slbia,SLB Invalidate All,X,31,498
|
||||||
|
slbie,SLB Invalidate Entry,X,31,434
|
||||||
|
sld,Shift Left Doubleword,X,31,27
|
||||||
|
slw[.],Shift Left Word,X,31,24
|
||||||
|
srad,Shift Right Algebraic Doubleword,X,31,794
|
||||||
|
sradi,Shift Right Algebraic Doubleword Immediate,XS,31,413
|
||||||
|
srd,Shift Right Doubleword,X,31,539
|
||||||
|
sraw[.],Shift Right Algebraic Word,X,31,792
|
||||||
|
srawi[.],Shift Right Algebraic Word Immediate,X,31,824
|
||||||
|
srw[.],Shift Right Word,X,31,536
|
||||||
|
stb,Store Byte,D,38,
|
||||||
|
stbu,Store Byte with Update,D,39,
|
||||||
|
stbux,Store Byte with Update Indexed,X,31,247
|
||||||
|
stbx,Store Byte Indexed,X,31,215
|
||||||
|
std,Store Doubleword,DS,62,0
|
||||||
|
stdcx,Store Doubleword Conditional Indexed,X,31,214
|
||||||
|
stdu,Store Doubleword with Update,DS,62,1
|
||||||
|
stdux,Store Doubleword with Update Indexed,X,31,181
|
||||||
|
stdx,Store Doubleword Indexed,X,31,149
|
||||||
|
stfd,Store Floating-Point Double,D,54,
|
||||||
|
stfdu,Store Floating-Point Double with Update,D,55,
|
||||||
|
stfdux,Store Floating-Point Double with Update Indexed,X,31,759
|
||||||
|
stfdx,Store Floating-Point Double Indexed,X,31,727
|
||||||
|
stfiwx,Store Floating-Point as Integer Word Indexed (optional),X,31,983
|
||||||
|
stfs,Store Floating-Point Single,D,52,
|
||||||
|
stfsu,Store Floating-Point Single with Update,D,53,
|
||||||
|
stfsux,Store Floating-Point Single with Update Indexed,X,31,695
|
||||||
|
stfsx,Store Floating-Point Single Indexed,X,31,663
|
||||||
|
sth,Store Half,D,44,
|
||||||
|
sthbrx,Store Half Byte-Reverse Indexed,X,31,918
|
||||||
|
sthu,Store Half with Update,D,45,
|
||||||
|
sthux,Store Half with Update Indexed,X,31,439
|
||||||
|
sthx,Store Half Indexed,X,31,407
|
||||||
|
stmw,Store Multiple Word,D,47,
|
||||||
|
stswi,Store String Word Immediate,X,31,725
|
||||||
|
stswx,Store String Word Indexed,X,31,661
|
||||||
|
stw,Store,D,36,
|
||||||
|
stwbrx,Store Word Byte-Reversed Indexed,X,31,662
|
||||||
|
stwcx.,Store Word Conditional Indexed,X,31,150
|
||||||
|
stwu,Store Word with Update,D,37,
|
||||||
|
stwux,Store Word with Update Indexed,X,31,183
|
||||||
|
stwx,Store Word Indexed,X,31,151
|
||||||
|
subf[o][.],Subtract from,XO,31,40
|
||||||
|
subfc[o][.],Subtract from Carrying,XO,31,08
|
||||||
|
subfe[o][.],Subtract from Extended,XO,31,136
|
||||||
|
subfic,Subtract from Immediate Carrying,D,08,
|
||||||
|
subfme[o][.],Subtract from Minus One Extended,XO,31,232
|
||||||
|
subfze[o][.],Subtract from Zero Extended,XO,31,200
|
||||||
|
sync,Synchronize,X,31,598
|
||||||
|
td,Trap Doubleword,X,31,68
|
||||||
|
tdi,Trap Doubleword Immediate,D,2,
|
||||||
|
tlbie,Translation Look-aside Buffer Invalidate Entry (optional),X,31,306
|
||||||
|
tlbsync,Translation Look-aside Buffer Synchronize (optional),X,31,566
|
||||||
|
tw,Trap Word,X,31,04
|
||||||
|
twi,Trap Word Immediate,D,03,
|
||||||
|
xor[.],XOR,X,31,316
|
||||||
|
xori,XOR Immediate,D,26,
|
||||||
|
xoris,XOR Immediate Shift,D,27,
|
||||||
Vendored
+343
@@ -0,0 +1,343 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
printf(
|
||||||
|
"// this file is autogenerated DO NOT MODIFY\n"
|
||||||
|
"#pragma once\n"
|
||||||
|
);
|
||||||
|
FILE* fp = fopen(argv[1], "rt");
|
||||||
|
if (fp) {
|
||||||
|
char line[80];
|
||||||
|
while (fgets(line, sizeof line, fp) != NULL) {
|
||||||
|
bool with_o = strstr(line, "[o]"), with_d = strstr(line, "[.]");
|
||||||
|
char* p = strchr(line, '\n'), *name = strchr(line, ','), *mem = line;
|
||||||
|
if (p) *p = '\0';
|
||||||
|
if (name) {
|
||||||
|
*name++ = '\0';
|
||||||
|
char *form = strchr(name, ',');
|
||||||
|
if (form) {
|
||||||
|
*form++ = '\0';
|
||||||
|
char *opc = strchr(form, ',');
|
||||||
|
if (opc) {
|
||||||
|
*opc++ = '\0';
|
||||||
|
char *sec = strchr(opc, ',');
|
||||||
|
if (sec) {
|
||||||
|
struct b_info { const char *s; int o; int p; } infos[] = {
|
||||||
|
{"",1,0},
|
||||||
|
{"LT",1,12},
|
||||||
|
{"LE",2,4},
|
||||||
|
{"NG",2,4},
|
||||||
|
{"EQ",3,12},
|
||||||
|
{"GE",1,4},
|
||||||
|
{"NL",1,4},
|
||||||
|
{"GT",2,12},
|
||||||
|
{"NE",3,4},
|
||||||
|
{"SO",4,12},
|
||||||
|
{"UN",4,12},
|
||||||
|
{"NS",4,4},
|
||||||
|
{"NU",4,4},
|
||||||
|
};
|
||||||
|
#define OP_EXT ((i_opcode << 26) | (i_extopc << 1))
|
||||||
|
if (strchr(mem, '[') != NULL) *strchr(mem, '[') = '\0';
|
||||||
|
if (strchr(mem, '.') != NULL) *strchr(mem, '.') = '_';
|
||||||
|
*sec++ = '\0';
|
||||||
|
for (int i = 0; i < strlen(mem); ++i)
|
||||||
|
mem[i] = toupper(mem[i]);
|
||||||
|
int i_opcode = atoi(opc);
|
||||||
|
int i_extopc = atoi(sec);
|
||||||
|
//printf("// %s\n", mem);
|
||||||
|
if (!strcmp(form, "XO")) {
|
||||||
|
if (!strcmp(mem, "EXTSH")) {
|
||||||
|
printf(
|
||||||
|
"void %s(GPR const rt, GPR const ra) {"
|
||||||
|
" emit_%s(0x%08x, rt, ra, R0, false, false); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
printf(
|
||||||
|
"void %sC(GPR const rt, GPR const ra) {"
|
||||||
|
" emit_%s(0x%08x, rt, ra, R0, true, false); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
printf(
|
||||||
|
"void %s_(GPR const rt, GPR const ra) {"
|
||||||
|
" emit_%s(0x%08x, rt, ra, R0, false, true); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
printf(
|
||||||
|
"void %sC_(GPR const rt, GPR const ra) {"
|
||||||
|
" emit_%s(0x%08x, rt, ra, R0, true, true); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
} else {
|
||||||
|
printf(
|
||||||
|
"void %s(GPR const rt, GPR const ra, GPR const rb) {"
|
||||||
|
" emit_%s(0x%08x, rt, ra, rb, false, false); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
printf(
|
||||||
|
"void %sO(GPR const rt, GPR const ra, GPR const rb) {"
|
||||||
|
" emit_%s(0x%08x, rt, ra, rb, true, false); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
printf(
|
||||||
|
"void %s_(GPR const rt, GPR const ra, GPR const rb) {"
|
||||||
|
" emit_%s(0x%08x, rt, ra, rb, false, true); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
printf(
|
||||||
|
"void %sO_(GPR const rt, GPR const ra, GPR const rb) {"
|
||||||
|
" emit_%s(0x%08x, rt, ra, rb, true, true); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
}
|
||||||
|
} else if (!strcmp(form, "X")) {
|
||||||
|
if (!strcmp(mem, "CMPL") || !strcmp(mem, "CMP")) {
|
||||||
|
printf(
|
||||||
|
"void %s(uint32_t bf, uint32_t l, GPR const ra, GPR const rb) {"
|
||||||
|
" emit_%s(0x%08x, GPR{(bf << 2) | l}, ra, rb, false); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
} else if (!strcmp(mem, "CNTLZD") || !strcmp(mem, "CNTLZW") || !strcmp(mem, "EXTSB") || !strcmp(mem, "EXTSH") || !strcmp(mem, "EXTSW")) {
|
||||||
|
printf(
|
||||||
|
"void %s(GPR const rt, GPR const ra) {"
|
||||||
|
" emit_%s(0x%08x, ra, rt, R0, false); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
printf(
|
||||||
|
"void %s_(GPR const rt, GPR const ra) {"
|
||||||
|
" emit_%s(0x%08x, ra, rt, R0, true); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
} else {
|
||||||
|
printf(
|
||||||
|
"void %s(GPR const rt, GPR const ra, GPR const rb) {"
|
||||||
|
" emit_%s(0x%08x, ra, rt, rb, false); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
printf(
|
||||||
|
"void %s_(GPR const rt, GPR const ra, GPR const rb) {"
|
||||||
|
" emit_%s(0x%08x, ra, rt, rb, true); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
}
|
||||||
|
} else if (!strcmp(form, "I")) {
|
||||||
|
printf(
|
||||||
|
"void %s(Label const& i) {"
|
||||||
|
" emit_reloc_%s(0x%08x, i, false); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, i_opcode << 26);
|
||||||
|
printf(
|
||||||
|
"void %sL(Label const& i) {"
|
||||||
|
" emit_reloc_%s(0x%08x, i, true); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, i_opcode << 26);
|
||||||
|
} else if (!strcmp(form, "B")) {
|
||||||
|
for (int i = 0; i < 12; ++i) {
|
||||||
|
printf(
|
||||||
|
"void %s%s(CPR const cr, Label const& i) {"
|
||||||
|
" emit_reloc_%s(0x%08x, %i, cr.index + %i, i, false); "
|
||||||
|
"}\n"
|
||||||
|
, mem, infos[i].s, form, i_opcode << 26, infos[i].p, infos[i].o - 1);
|
||||||
|
printf(
|
||||||
|
"void %s%sL(CPR const cr, Label const& i) {"
|
||||||
|
" emit_reloc_%s(0x%08x, %i, cr.index + %i, i, true); "
|
||||||
|
"}\n"
|
||||||
|
, mem, infos[i].s, form, i_opcode << 26, infos[i].p, infos[i].o - 1);
|
||||||
|
if (!strcmp(mem, "BC")) mem[1] = '\0';
|
||||||
|
}
|
||||||
|
} else if (!strcmp(form, "D")) {
|
||||||
|
if (!strcmp(mem, "CMPLI") || !strcmp(mem, "CMPI")) {
|
||||||
|
printf(
|
||||||
|
"void %s(uint32_t bf, uint32_t l, GPR const ra, uint32_t d) {"
|
||||||
|
" emit_%s(0x%08x, GPR{(bf << 2) | l}, ra, d); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, i_opcode << 26);
|
||||||
|
} else if (!strcmp(mem, "ANDIS_") || !strcmp(mem, "ANDI_")
|
||||||
|
|| !strcmp(mem, "ORI") || !strcmp(mem, "ORIS")
|
||||||
|
|| !strcmp(mem, "XORI") || !strcmp(mem, "XORIS")) {
|
||||||
|
printf(
|
||||||
|
"void %s(GPR const rt, GPR const ra, uint32_t d) {"
|
||||||
|
" emit_%s(0x%08x, ra, rt, d); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, i_opcode << 26);
|
||||||
|
} else {
|
||||||
|
printf(
|
||||||
|
"void %s(GPR const rt, GPR const ra, uint32_t d) {"
|
||||||
|
" emit_%s(0x%08x, rt, ra, d); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, i_opcode << 26);
|
||||||
|
}
|
||||||
|
} else if (!strcmp(form, "SC")) {
|
||||||
|
printf(
|
||||||
|
"void %s(uint32_t lev) {"
|
||||||
|
" emit_%s(0x%08x, lev); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, i_opcode << 26);
|
||||||
|
} else if (!strcmp(form, "DS")) {
|
||||||
|
#define OP_EXT_DS ((i_opcode << 26) | (i_extopc << 0))
|
||||||
|
printf(
|
||||||
|
"void %s(GPR const rt, GPR const ra, uint32_t d) {"
|
||||||
|
" emit_%s(0x%08x, rt, ra, d >> 2); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT_DS);
|
||||||
|
#undef OP_EXT_DS
|
||||||
|
} else if (!strcmp(form, "XS")) {
|
||||||
|
#define OP_EXT_XS ((i_opcode << 26) | (i_extopc << 2))
|
||||||
|
/* HUGE DIFFERENCE DO NOT REMOVE */
|
||||||
|
printf(
|
||||||
|
"void %s(GPR const rt, GPR const ra, uint32_t sh) {"
|
||||||
|
" emit_%s(0x%08x, rt, ra, sh, false); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT_XS);
|
||||||
|
printf(
|
||||||
|
"void %s_(GPR const rt, GPR const ra, uint32_t sh) {"
|
||||||
|
" emit_%s(0x%08x, rt, ra, sh, true); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT_XS);
|
||||||
|
#undef OP_EXT_XS
|
||||||
|
} else if (!strcmp(form, "XL")) {
|
||||||
|
if (!strcmp(mem, "BCLR")) {
|
||||||
|
printf(
|
||||||
|
"void %s(GPR const bt, CPR const ba, GPR const bb) {"
|
||||||
|
" emit_%s(0x%08x, bt.index, ba.index, bb.index, false); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
printf(
|
||||||
|
"void %sL(GPR const bt, CPR const ba, GPR const bb) {"
|
||||||
|
" emit_%s(0x%08x, bt.index, ba.index, bb.index, true); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
if (!strcmp(mem, "BCLR")) mem[1] = '\0';
|
||||||
|
for (int i = 1; i < 12; ++i) {
|
||||||
|
printf(
|
||||||
|
"void %s%sLR(CPR const cr) {"
|
||||||
|
" emit_%s(0x%08x, %i, cr.index + %i, 0, false); "
|
||||||
|
"}\n"
|
||||||
|
, mem, infos[i].s, form, OP_EXT, infos[i].p, infos[i].o - 1);
|
||||||
|
printf(
|
||||||
|
"void %s%sLRL(CPR const cr) {"
|
||||||
|
" emit_%s(0x%08x, %i, cr.index + %i, 0, true); "
|
||||||
|
"}\n"
|
||||||
|
, mem, infos[i].s, form, OP_EXT, infos[i].p, infos[i].o - 1);
|
||||||
|
}
|
||||||
|
} else if (mem[0] == 'B') {
|
||||||
|
printf(
|
||||||
|
"void %s(GPR const bt, CPR const ba, GPR const bb) {"
|
||||||
|
" emit_%s(0x%08x, bt.index, ba.index, bb.index, false); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
printf(
|
||||||
|
"void %sL(GPR const bt, CPR const ba, GPR const bb) {"
|
||||||
|
" emit_%s(0x%08x, bt.index, ba.index, bb.index, true); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
printf(
|
||||||
|
"void %s(GPR const bt, Cond const ba, GPR const bb) {"
|
||||||
|
" emit_%s(0x%08x, bt.index, cond2offset(ba), bb.index, false); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
printf(
|
||||||
|
"void %sL(GPR const bt, Cond const ba, GPR const bb) {"
|
||||||
|
" emit_%s(0x%08x, bt.index, cond2offset(ba), bb.index, true); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
} else {
|
||||||
|
printf(
|
||||||
|
"void %s(CPR const bt, CPR const ba, CPR const bb) {"
|
||||||
|
" emit_%s(0x%08x, bt.index, ba.index, bb.index, false); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
printf(
|
||||||
|
"void %sL(CPR const bt, CPR const ba, CPR const bb) {"
|
||||||
|
" emit_%s(0x%08x, bt.index, ba.index, bb.index, true); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
}
|
||||||
|
} else if (!strcmp(form, "M")) {
|
||||||
|
if (!strcmp(mem, "RLWNM")) {
|
||||||
|
printf(
|
||||||
|
"void %s(GPR const rs, GPR const ra, GPR const rb, uint32_t mb, uint32_t me = 0) {"
|
||||||
|
" emit_%s(0x%08x, ra, rs, rb.index, mb, me, false); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
printf(
|
||||||
|
"void %s_(GPR const rs, GPR const ra, GPR const rb, uint32_t mb, uint32_t me = 0) {"
|
||||||
|
" emit_%s(0x%08x, ra, rs, rb.index, mb, me, true); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
} else {
|
||||||
|
printf(
|
||||||
|
"void %s(GPR const rs, GPR const ra, uint32_t sh, uint32_t mb, uint32_t me = 0) {"
|
||||||
|
" emit_%s(0x%08x, ra, rs, sh, mb, me, false); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
printf(
|
||||||
|
"void %s_(GPR const rs, GPR const ra, uint32_t sh, uint32_t mb, uint32_t me = 0) {"
|
||||||
|
" emit_%s(0x%08x, ra, rs, sh, mb, me, true); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
}
|
||||||
|
} else if (!strcmp(form, "MD")) {
|
||||||
|
printf(
|
||||||
|
"void %s(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) {"
|
||||||
|
" emit_%s(0x%08x, ra, rs, mb, sh, false); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, (i_opcode << 26) | (i_extopc << 2));
|
||||||
|
printf(
|
||||||
|
"void %s_(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) {"
|
||||||
|
" emit_%s(0x%08x, ra, rs, mb, sh, true); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, (i_opcode << 26) | (i_extopc << 2));
|
||||||
|
} else if (!strcmp(form, "MDS")) {
|
||||||
|
printf(
|
||||||
|
"void %s(GPR const rs, GPR const ra, GPR const rb, uint32_t mb) {"
|
||||||
|
" emit_%s(0x%08x, ra, rs, rb, mb, false); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
printf(
|
||||||
|
"void %s_(GPR const rs, GPR const ra, GPR const rb, uint32_t mb) {"
|
||||||
|
" emit_%s(0x%08x, ra, rs, rb, mb, true); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
} else if (!strcmp(form, "A")) {
|
||||||
|
printf(
|
||||||
|
"void %s(FPR const frt, FPR const fra, FPR const frb, FPR const frc) {"
|
||||||
|
" emit_%s(0x%08x, frt, fra, frb, frc, false); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
printf(
|
||||||
|
"void %s_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) {"
|
||||||
|
" emit_%s(0x%08x, frt, fra, frb, frc, true); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
} else if (!strcmp(form, "XFX")) {
|
||||||
|
printf(
|
||||||
|
"void %s(GPR const rt, uint32_t spr) {"
|
||||||
|
" emit_%s(0x%08x, rt, spr); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
} else {
|
||||||
|
printf(
|
||||||
|
"void %s() {"
|
||||||
|
" emit_%s(0x%08x); "
|
||||||
|
"}\n"
|
||||||
|
, mem, form, OP_EXT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//printf("%s\n", line);
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
Vendored
+401
@@ -0,0 +1,401 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#undef NDEBUG
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cassert>
|
||||||
|
#include <vector>
|
||||||
|
#include <utility>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
//#ifndef __cpp_lib_unreachable
|
||||||
|
namespace std {
|
||||||
|
[[noreturn]] inline void unreachable() {
|
||||||
|
#if defined(_MSC_VER) && !defined(__clang__) // MSVC
|
||||||
|
__assume(false);
|
||||||
|
#else // GCC, Clang
|
||||||
|
__builtin_unreachable();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
namespace powah {
|
||||||
|
|
||||||
|
// Symbolic conditions
|
||||||
|
enum class Cond : uint8_t {
|
||||||
|
LT, LE, NG, EQ, GE, NL, GT, NE, SO, UN, NS, NU
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GPR { uint32_t index; };
|
||||||
|
struct FPR { uint32_t index; };
|
||||||
|
struct VPR { uint32_t index; };
|
||||||
|
struct CPR { uint32_t index; };
|
||||||
|
struct Label { uint32_t index; };
|
||||||
|
|
||||||
|
constexpr inline GPR R0{0};
|
||||||
|
constexpr inline GPR R1{1};
|
||||||
|
constexpr inline GPR R2{2};
|
||||||
|
constexpr inline GPR R3{3};
|
||||||
|
constexpr inline GPR R4{4};
|
||||||
|
constexpr inline GPR R5{5};
|
||||||
|
constexpr inline GPR R6{6};
|
||||||
|
constexpr inline GPR R7{7};
|
||||||
|
constexpr inline GPR R8{8};
|
||||||
|
constexpr inline GPR R9{9};
|
||||||
|
constexpr inline GPR R10{10};
|
||||||
|
constexpr inline GPR R11{11};
|
||||||
|
constexpr inline GPR R12{12};
|
||||||
|
constexpr inline GPR R13{13};
|
||||||
|
constexpr inline GPR R14{14};
|
||||||
|
constexpr inline GPR R15{15};
|
||||||
|
constexpr inline GPR R16{16};
|
||||||
|
constexpr inline GPR R17{17};
|
||||||
|
constexpr inline GPR R18{18};
|
||||||
|
constexpr inline GPR R19{19};
|
||||||
|
constexpr inline GPR R20{20};
|
||||||
|
constexpr inline GPR R21{21};
|
||||||
|
constexpr inline GPR R22{22};
|
||||||
|
constexpr inline GPR R23{23};
|
||||||
|
constexpr inline GPR R24{24};
|
||||||
|
constexpr inline GPR R25{25};
|
||||||
|
constexpr inline GPR R26{26};
|
||||||
|
constexpr inline GPR R27{27};
|
||||||
|
constexpr inline GPR R28{28};
|
||||||
|
constexpr inline GPR R29{29};
|
||||||
|
constexpr inline GPR R30{30};
|
||||||
|
constexpr inline GPR R31{31};
|
||||||
|
|
||||||
|
constexpr inline FPR FR0{0};
|
||||||
|
constexpr inline FPR FR1{1};
|
||||||
|
constexpr inline FPR FR2{2};
|
||||||
|
constexpr inline FPR FR3{3};
|
||||||
|
constexpr inline FPR FR4{4};
|
||||||
|
constexpr inline FPR FR5{5};
|
||||||
|
constexpr inline FPR FR6{6};
|
||||||
|
constexpr inline FPR FR7{7};
|
||||||
|
constexpr inline FPR FR8{8};
|
||||||
|
constexpr inline FPR FR9{9};
|
||||||
|
constexpr inline FPR FR10{10};
|
||||||
|
constexpr inline FPR FR11{11};
|
||||||
|
constexpr inline FPR FR12{12};
|
||||||
|
constexpr inline FPR FR13{13};
|
||||||
|
constexpr inline FPR FR14{14};
|
||||||
|
constexpr inline FPR FR15{15};
|
||||||
|
constexpr inline FPR FR16{16};
|
||||||
|
constexpr inline FPR FR17{17};
|
||||||
|
constexpr inline FPR FR18{18};
|
||||||
|
constexpr inline FPR FR19{19};
|
||||||
|
constexpr inline FPR FR20{20};
|
||||||
|
constexpr inline FPR FR21{21};
|
||||||
|
constexpr inline FPR FR22{22};
|
||||||
|
constexpr inline FPR FR23{23};
|
||||||
|
constexpr inline FPR FR24{24};
|
||||||
|
constexpr inline FPR FR25{25};
|
||||||
|
constexpr inline FPR FR26{26};
|
||||||
|
constexpr inline FPR FR27{27};
|
||||||
|
constexpr inline FPR FR28{28};
|
||||||
|
constexpr inline FPR FR29{29};
|
||||||
|
constexpr inline FPR FR30{30};
|
||||||
|
constexpr inline FPR FR31{31};
|
||||||
|
|
||||||
|
// They call it CPR because when programmers see this code they-
|
||||||
|
constexpr inline CPR CR0{0};
|
||||||
|
constexpr inline CPR CR1{4};
|
||||||
|
constexpr inline CPR CR2{8};
|
||||||
|
constexpr inline CPR CR3{12};
|
||||||
|
constexpr inline CPR CR4{16};
|
||||||
|
constexpr inline CPR CR5{20};
|
||||||
|
constexpr inline CPR CR6{24};
|
||||||
|
constexpr inline CPR CR7{28};
|
||||||
|
|
||||||
|
constexpr uint32_t XER_SO = 32;
|
||||||
|
constexpr uint32_t XER_OV = 33;
|
||||||
|
constexpr uint32_t XER_CA = 34;
|
||||||
|
|
||||||
|
enum class RelocKind : uint8_t {
|
||||||
|
FormB,
|
||||||
|
FormI,
|
||||||
|
};
|
||||||
|
struct RelocInfo {
|
||||||
|
uint32_t offset;
|
||||||
|
RelocKind kind;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Context {
|
||||||
|
Context() = default;
|
||||||
|
Context(void* ptr, size_t size)
|
||||||
|
: base{reinterpret_cast<uint32_t*>(ptr)}
|
||||||
|
, offset{0}
|
||||||
|
, size{uint32_t(size)} {
|
||||||
|
|
||||||
|
}
|
||||||
|
~Context() = default;
|
||||||
|
|
||||||
|
std::vector<uint32_t> labels;
|
||||||
|
std::vector<std::pair<uint32_t, RelocInfo>> relocs;
|
||||||
|
|
||||||
|
Label DefineLabel() {
|
||||||
|
labels.push_back(0);
|
||||||
|
return Label{ uint32_t(labels.size() - 1) };
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApplyRelocs() {
|
||||||
|
for (auto const &[index, info] : relocs) {
|
||||||
|
//assert(labels[index] != 0); //label must have an addr
|
||||||
|
int32_t rel = (int32_t)labels[index] - (int32_t)info.offset;
|
||||||
|
switch (info.kind) {
|
||||||
|
case RelocKind::FormB:
|
||||||
|
base[info.offset] |= bitExt(rel, 16, 14);
|
||||||
|
break;
|
||||||
|
case RelocKind::FormI:
|
||||||
|
base[info.offset] |= bitExt(rel, 6, 24);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
relocs.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LABEL(Label l) {
|
||||||
|
assert(labels[l.index] == 0);
|
||||||
|
labels[l.index] = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint32_t cond2offset(Cond c) noexcept {
|
||||||
|
switch (c) {
|
||||||
|
case Cond::LT: return 1;
|
||||||
|
case Cond::LE: return 2;
|
||||||
|
case Cond::NG: return 2;
|
||||||
|
case Cond::EQ: return 3;
|
||||||
|
case Cond::GE: return 1;
|
||||||
|
case Cond::NL: return 1;
|
||||||
|
case Cond::GT: return 2;
|
||||||
|
case Cond::NE: return 3;
|
||||||
|
case Cond::SO: return 4;
|
||||||
|
case Cond::UN: return 4;
|
||||||
|
case Cond::NS: return 4;
|
||||||
|
case Cond::NU: return 4;
|
||||||
|
default: return 0; //hopefully icc isn't stupid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t bitExt(uint32_t value, uint32_t offs, uint32_t n) {
|
||||||
|
uint32_t mask = (1UL << n) - 1;
|
||||||
|
return (value & mask) << (32 - (n + offs));
|
||||||
|
}
|
||||||
|
void emit_XO(uint32_t op, GPR const rt, GPR const ra, GPR const rb, bool oe, bool rc) {
|
||||||
|
base[offset++] = (op |
|
||||||
|
bitExt(rt.index, 6, 5)
|
||||||
|
| bitExt(ra.index, 11, 5)
|
||||||
|
| bitExt(rb.index, 16, 5)
|
||||||
|
| bitExt(oe, 21, 1)
|
||||||
|
| bitExt(rc, 31, 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
void emit_D(uint32_t op, GPR const rt, GPR const ra, uint32_t d) {
|
||||||
|
base[offset++] = (op |
|
||||||
|
bitExt(rt.index, 6, 5)
|
||||||
|
| bitExt(ra.index, 11, 5)
|
||||||
|
| (d & 0xffff)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
void emit_X(uint32_t op, GPR const rt, GPR const ra, GPR const rb, bool rc) {
|
||||||
|
base[offset++] = (op |
|
||||||
|
bitExt(rt.index, 6, 5)
|
||||||
|
| bitExt(ra.index, 11, 5)
|
||||||
|
| bitExt(rb.index, 16, 5)
|
||||||
|
| bitExt(rc, 31, 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
void emit_XS(uint32_t op, GPR const rt, GPR const ra, uint32_t sh, bool rc) {
|
||||||
|
base[offset++] = (op |
|
||||||
|
((rt.index & 0x1f) << 16)
|
||||||
|
| ((ra.index & 0x1f) << 21)
|
||||||
|
| ((sh & 0x1f) << 11)
|
||||||
|
| ((sh >> 4) & 0x02)
|
||||||
|
| bitExt(rc, 31, 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
void emit_reloc_I(uint32_t op, Label const& l, bool lk) {
|
||||||
|
relocs.emplace_back(l.index, RelocInfo{ offset, RelocKind::FormI });
|
||||||
|
base[offset++] = (op |
|
||||||
|
bitExt(lk, 31, 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
void emit_reloc_B(uint32_t op, uint32_t bo, uint32_t cri, Label const& l, bool lk) {
|
||||||
|
relocs.emplace_back(l.index, RelocInfo{ offset, RelocKind::FormB });
|
||||||
|
base[offset++] = (op |
|
||||||
|
bitExt(bo, 6, 5)
|
||||||
|
| bitExt(cri, 11, 5)
|
||||||
|
| bitExt(lk, 31, 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
void emit_XL(uint32_t op, uint32_t bt, uint32_t ba, uint32_t bb, bool lk) {
|
||||||
|
base[offset++] = (op |
|
||||||
|
bitExt(bt, 6, 5)
|
||||||
|
| bitExt(ba, 11, 5)
|
||||||
|
| bitExt(bb, 16, 5)
|
||||||
|
| bitExt(lk, 31, 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
void emit_A(uint32_t op, FPR const frt, FPR const fra, FPR const frb, FPR const frc, bool rc) {
|
||||||
|
base[offset++] = (op |
|
||||||
|
bitExt(frt.index, 6, 5)
|
||||||
|
| bitExt(fra.index, 11, 5)
|
||||||
|
| bitExt(frb.index, 16, 5)
|
||||||
|
| bitExt(frc.index, 21, 5)
|
||||||
|
| bitExt(rc, 31, 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
void emit_DS(uint32_t op, GPR const rt, GPR const ra, uint32_t d) {
|
||||||
|
//assert(d & 0x03 == 0);
|
||||||
|
base[offset++] = (op |
|
||||||
|
bitExt(rt.index, 6, 5)
|
||||||
|
| bitExt(ra.index, 11, 5)
|
||||||
|
| bitExt(d, 16, 14)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
void emit_M(uint32_t op, GPR const rs, GPR const ra, uint32_t sh, uint32_t mb, uint32_t me, bool rc) {
|
||||||
|
assert(sh <= 0x3f && mb <= 0x3f);
|
||||||
|
base[offset++] = (op |
|
||||||
|
bitExt(rs.index, 6, 5)
|
||||||
|
| bitExt(ra.index, 11, 5)
|
||||||
|
| ((sh & 0x1f) << 11)
|
||||||
|
| ((mb & 0x1f) << 6)
|
||||||
|
| ((me & 0x1f) << 1)
|
||||||
|
| bitExt(rc, 31, 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
void emit_MD(uint32_t op, GPR const rs, GPR const ra, GPR const rb, uint32_t mb, bool rc) {
|
||||||
|
assert(mb <= 0x3f);
|
||||||
|
base[offset++] = (op |
|
||||||
|
bitExt(rs.index, 6, 5)
|
||||||
|
| bitExt(ra.index, 11, 5)
|
||||||
|
| bitExt(rb.index, 16, 5)
|
||||||
|
| ((mb & 0x1f) << 6) | (mb & 0x20)
|
||||||
|
| bitExt(rc, 31, 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
void emit_MD(uint32_t op, GPR const rs, GPR const ra, uint32_t sh, uint32_t mb, bool rc) {
|
||||||
|
assert(sh <= 0x3f && mb <= 0x3f);
|
||||||
|
base[offset++] = (op |
|
||||||
|
bitExt(rs.index, 6, 5)
|
||||||
|
| bitExt(ra.index, 11, 5)
|
||||||
|
| ((mb & 0x1f) << 6) | (mb & 0x20)
|
||||||
|
| ((sh & 0x1f) << 11) | ((sh >> 4) & 0x02)
|
||||||
|
| bitExt(rc, 31, 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
void emit_MDS(uint32_t op, GPR const rs, GPR const ra, GPR const rb, uint32_t mb, bool rc) {
|
||||||
|
base[offset++] = (op |
|
||||||
|
bitExt(rs.index, 6, 5)
|
||||||
|
| bitExt(ra.index, 11, 5)
|
||||||
|
| bitExt(rb.index, 16, 5)
|
||||||
|
| ((mb & 0x1f) << 6) | (mb & 0x20)
|
||||||
|
| bitExt(rc, 31, 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
void emit_XFL(uint32_t op) {
|
||||||
|
(void)op;
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
void emit_XFX(uint32_t op, GPR const rt, uint32_t spr) {
|
||||||
|
base[offset++] = (op |
|
||||||
|
(rt.index & 0x1f) << 21
|
||||||
|
| ((spr & 0xff) << 12)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
void emit_SC(uint32_t op, uint32_t lev) {
|
||||||
|
(void)op;
|
||||||
|
(void)lev;
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extended Memmonics, hand coded :)
|
||||||
|
void MR(GPR const ra, GPR const rs) { OR(ra, rs, rs); }
|
||||||
|
void NOP() { ORI(R0, R0, 0); }
|
||||||
|
void NOT(GPR const ra, GPR const rs) { NOR(ra, rs, rs); }
|
||||||
|
|
||||||
|
void ROTLDI(GPR const ra, GPR const rs, uint32_t n) { RLDICL(ra, rs, n, 0); }
|
||||||
|
void ROTRDI(GPR const ra, GPR const rs, uint32_t n) { RLDICL(ra, rs, 64 - n, 0); }
|
||||||
|
|
||||||
|
void ROTLWI(GPR const ra, GPR const rs, uint32_t n) { RLWINM(ra, rs, n, 0, 31); }
|
||||||
|
void ROTRWI(GPR const ra, GPR const rs, uint32_t n) { RLWINM(ra, rs, 32 - n, 0, 31); }
|
||||||
|
|
||||||
|
void ROTLW(GPR const ra, GPR const rs, GPR const rb) { RLWNM(ra, rs, rb, 0, 31); }
|
||||||
|
void ROTLD(GPR const ra, GPR const rs, GPR const rb) { RLDCL(ra, rs, rb, 0); }
|
||||||
|
|
||||||
|
void EXTLDI(GPR const ra, GPR const rs, uint32_t n, uint32_t b) { RLDICR(ra, rs, b, n - 1); }
|
||||||
|
void SLDI(GPR const ra, GPR const rs, uint32_t n) { RLDICR(ra, rs, n, 63 - n); }
|
||||||
|
void CLRLDI(GPR const ra, GPR const rs, uint32_t n) { RLDICL(ra, rs, 0, n); }
|
||||||
|
|
||||||
|
void EXTRDI(GPR const ra, GPR const rs, uint32_t n, uint32_t b) { RLDICL(ra, rs, b + n, 64 - n); }
|
||||||
|
void SRDI(GPR const ra, GPR const rs, uint32_t n) { RLDICL(ra, rs, 64 - n, n); }
|
||||||
|
void CLLDI(GPR const ra, GPR const rs, uint32_t n) { RLDICR(ra, rs, 0, n); }
|
||||||
|
void CLRSLDI(GPR const ra, GPR const rs, uint32_t n, uint32_t b) { RLDICR(ra, rs, n, b - n); }
|
||||||
|
|
||||||
|
void EXTLWI(GPR const ra, GPR const rs, uint32_t n, uint32_t b) { RLWINM(ra, rs, b, 0, n - 1); }
|
||||||
|
void SRWI(GPR const ra, GPR const rs, uint32_t n) { RLWINM(ra, rs, 32 - n, n, 31); }
|
||||||
|
void CLRRWI(GPR const ra, GPR const rs, uint32_t n) { RLWINM(ra, rs, 0, 0, 31 - n); }
|
||||||
|
|
||||||
|
void CRSET(CPR const bx) { CREQV(bx, bx, bx); }
|
||||||
|
void CRCLR(CPR const bx) { CRXOR(bx, bx, bx); }
|
||||||
|
void CRMOVE(CPR const bx, CPR const by) { CROR(bx, by, by); }
|
||||||
|
void CRNOT(CPR const bx, CPR const by) { CRNOR(bx, by, by); }
|
||||||
|
|
||||||
|
void CMPLDI(CPR const cr, GPR const rx, uint32_t v) { CMPLI(cr.index, 1, rx, v); }
|
||||||
|
void CMPLWI(CPR const cr, GPR const rx, uint32_t v) { CMPLI(cr.index, 0, rx, v); }
|
||||||
|
void CMPLD(CPR const cr, GPR const rx, GPR const ry) { CMPL(cr.index, 1, rx, ry); }
|
||||||
|
void CMPLW(CPR const cr, GPR const rx, GPR const ry) { CMPL(cr.index, 0, rx, ry); }
|
||||||
|
void CMPLDI(GPR const rx, uint32_t v) { CMPLI(0, 1, rx, v); }
|
||||||
|
void CMPLWI(GPR const rx, uint32_t v) { CMPLI(0, 0, rx, v); }
|
||||||
|
void CMPLD(GPR const rx, GPR const ry) { CMPL(0, 1, rx, ry); }
|
||||||
|
void CMPLW(GPR const rx, GPR const ry) { CMPL(0, 0, rx, ry); }
|
||||||
|
|
||||||
|
void CMPWI(CPR const cr, GPR const rx, uint32_t si) { CMPI(cr.index, 0, rx, si); }
|
||||||
|
void CMPW(CPR const cr, GPR const rx, GPR const ry) { CMP(cr.index, 0, rx, ry); }
|
||||||
|
void CMPDI(CPR const cr, GPR const rx, uint32_t si) { CMPI(cr.index, 1, rx, si); }
|
||||||
|
void CMPD(CPR const cr, GPR const rx, GPR const ry) { CMP(cr.index, 1, rx, ry); }
|
||||||
|
void CMPWI(GPR const rx, uint32_t si) { CMPI(0, 0, rx, si); }
|
||||||
|
void CMPW(GPR const rx, GPR const ry) { CMP(0, 0, rx, ry); }
|
||||||
|
void CMPDI(GPR const rx, uint32_t si) { CMPI(0, 1, rx, si); }
|
||||||
|
void CMPD(GPR const rx, GPR const ry) { CMP(0, 1, rx, ry); }
|
||||||
|
|
||||||
|
void LI(GPR const rx, uint32_t value) { ADDI(rx, R0, value); }
|
||||||
|
void LIS(GPR const rx, uint32_t value) { ADDIS(rx, R0, value); }
|
||||||
|
|
||||||
|
void MFLR(GPR const rt) { MFSPR(powah::GPR{8}, rt, powah::GPR{0}); }
|
||||||
|
void MTLR(GPR const rt) { MTSPR(powah::GPR{8}, rt, powah::GPR{0}); }
|
||||||
|
void BLR() { base[offset++] = 0x4e800020; } //BCLR(R0, CR0, R0);
|
||||||
|
|
||||||
|
void MFCTR(GPR const rt) { MFSPR(powah::GPR{9}, rt, powah::GPR{0}); }
|
||||||
|
void MTCTR(GPR const rt) { MTSPR(powah::GPR{9}, rt, powah::GPR{0}); }
|
||||||
|
void BCTRL() { base[offset++] = 0x4e800421; } //BCCTRL(R0, CR0, R0);
|
||||||
|
void BCTR() { base[offset++] = 0x4e800420; } //BCCTR(R0, CR0, R0);
|
||||||
|
|
||||||
|
// TODO: PowerPC 11 stuff
|
||||||
|
void ISEL(GPR const rd, GPR const ra, GPR const rb, uint32_t d) {
|
||||||
|
(void)rd;
|
||||||
|
(void)ra;
|
||||||
|
(void)rb;
|
||||||
|
(void)d;
|
||||||
|
std::unreachable();
|
||||||
|
}
|
||||||
|
void ISELLT(GPR const rd, GPR const ra, GPR const rb) { ISEL(rd, ra, rb, 0); }
|
||||||
|
void ISELGT(GPR const rd, GPR const ra, GPR const rb) { ISEL(rd, ra, rb, 1); }
|
||||||
|
void ISELEQ(GPR const rd, GPR const ra, GPR const rb) { ISEL(rd, ra, rb, 2); }
|
||||||
|
|
||||||
|
// Rawly pasted because fuck you
|
||||||
|
#include "powah_gen_base.hpp"
|
||||||
|
|
||||||
|
uint32_t* base = nullptr;
|
||||||
|
uint32_t offset = 0;
|
||||||
|
uint32_t size = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
Vendored
+487
@@ -0,0 +1,487 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
// this file is autogenerated DO NOT MODIFY
|
||||||
|
#pragma once
|
||||||
|
void ADD(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000214, rt, ra, rb, false, false); }
|
||||||
|
void ADDO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000214, rt, ra, rb, true, false); }
|
||||||
|
void ADD_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000214, rt, ra, rb, false, true); }
|
||||||
|
void ADDO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000214, rt, ra, rb, true, true); }
|
||||||
|
void ADDC(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000014, rt, ra, rb, false, false); }
|
||||||
|
void ADDCO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000014, rt, ra, rb, true, false); }
|
||||||
|
void ADDC_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000014, rt, ra, rb, false, true); }
|
||||||
|
void ADDCO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000014, rt, ra, rb, true, true); }
|
||||||
|
void ADDE(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000114, rt, ra, rb, false, false); }
|
||||||
|
void ADDEO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000114, rt, ra, rb, true, false); }
|
||||||
|
void ADDE_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000114, rt, ra, rb, false, true); }
|
||||||
|
void ADDEO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000114, rt, ra, rb, true, true); }
|
||||||
|
void ADDI(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x38000000, rt, ra, d); }
|
||||||
|
void ADDIC(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x30000000, rt, ra, d); }
|
||||||
|
void ADDIC_(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x34000000, rt, ra, d); }
|
||||||
|
void ADDIS(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x3c000000, rt, ra, d); }
|
||||||
|
void ADDME(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d4, rt, ra, rb, false, false); }
|
||||||
|
void ADDMEO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d4, rt, ra, rb, true, false); }
|
||||||
|
void ADDME_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d4, rt, ra, rb, false, true); }
|
||||||
|
void ADDMEO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d4, rt, ra, rb, true, true); }
|
||||||
|
void ADDZE(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000194, rt, ra, rb, false, false); }
|
||||||
|
void ADDZEO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000194, rt, ra, rb, true, false); }
|
||||||
|
void ADDZE_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000194, rt, ra, rb, false, true); }
|
||||||
|
void ADDZEO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000194, rt, ra, rb, true, true); }
|
||||||
|
void AND(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000038, ra, rt, rb, false); }
|
||||||
|
void AND_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000038, ra, rt, rb, true); }
|
||||||
|
void ANDC(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000078, ra, rt, rb, false); }
|
||||||
|
void ANDC_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000078, ra, rt, rb, true); }
|
||||||
|
void ANDI_(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x70000000, ra, rt, d); }
|
||||||
|
void ANDIS_(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x74000000, ra, rt, d); }
|
||||||
|
void B(Label const& i) { emit_reloc_I(0x48000000, i, false); }
|
||||||
|
void BL(Label const& i) { emit_reloc_I(0x48000000, i, true); }
|
||||||
|
void BC(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 0, cr.index + 0, i, false); }
|
||||||
|
void BCL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 0, cr.index + 0, i, true); }
|
||||||
|
void BLT(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 0, i, false); }
|
||||||
|
void BLTL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 0, i, true); }
|
||||||
|
void BLE(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 1, i, false); }
|
||||||
|
void BLEL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 1, i, true); }
|
||||||
|
void BNG(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 1, i, false); }
|
||||||
|
void BNGL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 1, i, true); }
|
||||||
|
void BEQ(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 2, i, false); }
|
||||||
|
void BEQL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 2, i, true); }
|
||||||
|
void BGE(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 0, i, false); }
|
||||||
|
void BGEL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 0, i, true); }
|
||||||
|
void BNL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 0, i, false); }
|
||||||
|
void BNLL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 0, i, true); }
|
||||||
|
void BGT(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 1, i, false); }
|
||||||
|
void BGTL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 1, i, true); }
|
||||||
|
void BNE(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 2, i, false); }
|
||||||
|
void BNEL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 2, i, true); }
|
||||||
|
void BSO(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 3, i, false); }
|
||||||
|
void BSOL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 3, i, true); }
|
||||||
|
void BUN(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 3, i, false); }
|
||||||
|
void BUNL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 12, cr.index + 3, i, true); }
|
||||||
|
void BNS(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 3, i, false); }
|
||||||
|
void BNSL(CPR const cr, Label const& i) { emit_reloc_B(0x40000000, 4, cr.index + 3, i, true); }
|
||||||
|
void BCCTR(GPR const bt, CPR const ba, GPR const bb) { emit_XL(0x4c000420, bt.index, ba.index, bb.index, false); }
|
||||||
|
void BCCTRL(GPR const bt, CPR const ba, GPR const bb) { emit_XL(0x4c000420, bt.index, ba.index, bb.index, true); }
|
||||||
|
void BCCTR(GPR const bt, Cond const ba, GPR const bb) { emit_XL(0x4c000420, bt.index, cond2offset(ba), bb.index, false); }
|
||||||
|
void BCCTRL(GPR const bt, Cond const ba, GPR const bb) { emit_XL(0x4c000420, bt.index, cond2offset(ba), bb.index, true); }
|
||||||
|
void BCLR(GPR const bt, CPR const ba, GPR const bb) { emit_XL(0x4c000020, bt.index, ba.index, bb.index, false); }
|
||||||
|
void BCLRL(GPR const bt, CPR const ba, GPR const bb) { emit_XL(0x4c000020, bt.index, ba.index, bb.index, true); }
|
||||||
|
void BLTLR(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 0, 0, false); }
|
||||||
|
void BLTLRL(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 0, 0, true); }
|
||||||
|
void BLELR(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 1, 0, false); }
|
||||||
|
void BLELRL(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 1, 0, true); }
|
||||||
|
void BNGLR(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 1, 0, false); }
|
||||||
|
void BNGLRL(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 1, 0, true); }
|
||||||
|
void BEQLR(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 2, 0, false); }
|
||||||
|
void BEQLRL(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 2, 0, true); }
|
||||||
|
void BGELR(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 0, 0, false); }
|
||||||
|
void BGELRL(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 0, 0, true); }
|
||||||
|
void BNLLR(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 0, 0, false); }
|
||||||
|
void BNLLRL(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 0, 0, true); }
|
||||||
|
void BGTLR(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 1, 0, false); }
|
||||||
|
void BGTLRL(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 1, 0, true); }
|
||||||
|
void BNELR(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 2, 0, false); }
|
||||||
|
void BNELRL(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 2, 0, true); }
|
||||||
|
void BSOLR(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 3, 0, false); }
|
||||||
|
void BSOLRL(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 3, 0, true); }
|
||||||
|
void BUNLR(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 3, 0, false); }
|
||||||
|
void BUNLRL(CPR const cr) { emit_XL(0x4c000020, 12, cr.index + 3, 0, true); }
|
||||||
|
void BNSLR(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 3, 0, false); }
|
||||||
|
void BNSLRL(CPR const cr) { emit_XL(0x4c000020, 4, cr.index + 3, 0, true); }
|
||||||
|
void CMP(uint32_t bf, uint32_t l, GPR const ra, GPR const rb) { emit_X(0x7c000000, GPR{(bf << 2) | l}, ra, rb, false); }
|
||||||
|
void CMPI(uint32_t bf, uint32_t l, GPR const ra, uint32_t d) { emit_D(0x2c000000, GPR{(bf << 2) | l}, ra, d); }
|
||||||
|
void CMPL(uint32_t bf, uint32_t l, GPR const ra, GPR const rb) { emit_X(0x7c000040, GPR{(bf << 2) | l}, ra, rb, false); }
|
||||||
|
void CMPLI(uint32_t bf, uint32_t l, GPR const ra, uint32_t d) { emit_D(0x28000000, GPR{(bf << 2) | l}, ra, d); }
|
||||||
|
void CNTLZD(GPR const rt, GPR const ra) { emit_X(0x7c000074, ra, rt, R0, false); }
|
||||||
|
void CNTLZD_(GPR const rt, GPR const ra) { emit_X(0x7c000074, ra, rt, R0, true); }
|
||||||
|
void CNTLZW(GPR const rt, GPR const ra) { emit_X(0x7c000034, ra, rt, R0, false); }
|
||||||
|
void CNTLZW_(GPR const rt, GPR const ra) { emit_X(0x7c000034, ra, rt, R0, true); }
|
||||||
|
void CRAND(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000202, bt.index, ba.index, bb.index, false); }
|
||||||
|
void CRANDL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000202, bt.index, ba.index, bb.index, true); }
|
||||||
|
void CRANDC(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000102, bt.index, ba.index, bb.index, false); }
|
||||||
|
void CRANDCL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000102, bt.index, ba.index, bb.index, true); }
|
||||||
|
void CREQV(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000242, bt.index, ba.index, bb.index, false); }
|
||||||
|
void CREQVL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000242, bt.index, ba.index, bb.index, true); }
|
||||||
|
void CRNAND(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c0001c2, bt.index, ba.index, bb.index, false); }
|
||||||
|
void CRNANDL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c0001c2, bt.index, ba.index, bb.index, true); }
|
||||||
|
void CRNOR(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000042, bt.index, ba.index, bb.index, false); }
|
||||||
|
void CRNORL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000042, bt.index, ba.index, bb.index, true); }
|
||||||
|
void CROR(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000382, bt.index, ba.index, bb.index, false); }
|
||||||
|
void CRORL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000382, bt.index, ba.index, bb.index, true); }
|
||||||
|
void CRORC(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000342, bt.index, ba.index, bb.index, false); }
|
||||||
|
void CRORCL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000342, bt.index, ba.index, bb.index, true); }
|
||||||
|
void CRXOR(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000182, bt.index, ba.index, bb.index, false); }
|
||||||
|
void CRXORL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000182, bt.index, ba.index, bb.index, true); }
|
||||||
|
void DCBF(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000ac, ra, rt, rb, false); }
|
||||||
|
void DCBF_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000ac, ra, rt, rb, true); }
|
||||||
|
void DCBI(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0003ac, ra, rt, rb, false); }
|
||||||
|
void DCBI_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0003ac, ra, rt, rb, true); }
|
||||||
|
void DCBST(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00006c, ra, rt, rb, false); }
|
||||||
|
void DCBST_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00006c, ra, rt, rb, true); }
|
||||||
|
void DCBT(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00022c, ra, rt, rb, false); }
|
||||||
|
void DCBT_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00022c, ra, rt, rb, true); }
|
||||||
|
void DCBTST(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001ec, ra, rt, rb, false); }
|
||||||
|
void DCBTST_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001ec, ra, rt, rb, true); }
|
||||||
|
void DCBZ(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0007ec, ra, rt, rb, false); }
|
||||||
|
void DCBZ_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0007ec, ra, rt, rb, true); }
|
||||||
|
void DIVD(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0003d2, rt, ra, rb, false, false); }
|
||||||
|
void DIVDO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0003d2, rt, ra, rb, true, false); }
|
||||||
|
void DIVD_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0003d2, rt, ra, rb, false, true); }
|
||||||
|
void DIVDO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0003d2, rt, ra, rb, true, true); }
|
||||||
|
void DIVDU(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000392, rt, ra, rb, false, false); }
|
||||||
|
void DIVDUO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000392, rt, ra, rb, true, false); }
|
||||||
|
void DIVDU_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000392, rt, ra, rb, false, true); }
|
||||||
|
void DIVDUO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000392, rt, ra, rb, true, true); }
|
||||||
|
void DIVW(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0003d6, rt, ra, rb, false, false); }
|
||||||
|
void DIVWO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0003d6, rt, ra, rb, true, false); }
|
||||||
|
void DIVW_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0003d6, rt, ra, rb, false, true); }
|
||||||
|
void DIVWO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0003d6, rt, ra, rb, true, true); }
|
||||||
|
void DIVWU(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000396, rt, ra, rb, false, false); }
|
||||||
|
void DIVWUO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000396, rt, ra, rb, true, false); }
|
||||||
|
void DIVWU_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000396, rt, ra, rb, false, true); }
|
||||||
|
void DIVWUO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000396, rt, ra, rb, true, true); }
|
||||||
|
void ECIWX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00026c, ra, rt, rb, false); }
|
||||||
|
void ECIWX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00026c, ra, rt, rb, true); }
|
||||||
|
void ECOWX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00036c, ra, rt, rb, false); }
|
||||||
|
void ECOWX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00036c, ra, rt, rb, true); }
|
||||||
|
void EIEIO(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0006ac, ra, rt, rb, false); }
|
||||||
|
void EIEIO_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0006ac, ra, rt, rb, true); }
|
||||||
|
void EQV(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000238, ra, rt, rb, false); }
|
||||||
|
void EQV_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000238, ra, rt, rb, true); }
|
||||||
|
void EXTSB(GPR const rt, GPR const ra) { emit_X(0x7c000774, ra, rt, R0, false); }
|
||||||
|
void EXTSB_(GPR const rt, GPR const ra) { emit_X(0x7c000774, ra, rt, R0, true); }
|
||||||
|
void EXTSH(GPR const rt, GPR const ra) { emit_XO(0x7c000734, rt, ra, R0, false, false); }
|
||||||
|
void EXTSHC(GPR const rt, GPR const ra) { emit_XO(0x7c000734, rt, ra, R0, true, false); }
|
||||||
|
void EXTSH_(GPR const rt, GPR const ra) { emit_XO(0x7c000734, rt, ra, R0, false, true); }
|
||||||
|
void EXTSHC_(GPR const rt, GPR const ra) { emit_XO(0x7c000734, rt, ra, R0, true, true); }
|
||||||
|
void EXTSW(GPR const rt, GPR const ra) { emit_X(0x7c0007b4, ra, rt, R0, false); }
|
||||||
|
void EXTSW_(GPR const rt, GPR const ra) { emit_X(0x7c0007b4, ra, rt, R0, true); }
|
||||||
|
void FABS(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000210, ra, rt, rb, false); }
|
||||||
|
void FABS_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000210, ra, rt, rb, true); }
|
||||||
|
void FADD(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00002a, frt, fra, frb, frc, false); }
|
||||||
|
void FADD_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00002a, frt, fra, frb, frc, true); }
|
||||||
|
void FADDS(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec00002a, frt, fra, frb, frc, false); }
|
||||||
|
void FADDS_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec00002a, frt, fra, frb, frc, true); }
|
||||||
|
void FCFID(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00069c, ra, rt, rb, false); }
|
||||||
|
void FCFID_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00069c, ra, rt, rb, true); }
|
||||||
|
void FCMPO(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000040, ra, rt, rb, false); }
|
||||||
|
void FCMPO_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000040, ra, rt, rb, true); }
|
||||||
|
void FCMPU(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0xfc000000, bt.index, ba.index, bb.index, false); }
|
||||||
|
void FCMPUL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0xfc000000, bt.index, ba.index, bb.index, true); }
|
||||||
|
void FCTID(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00065c, ra, rt, rb, false); }
|
||||||
|
void FCTID_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00065c, ra, rt, rb, true); }
|
||||||
|
void FCTIDZ(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00065e, ra, rt, rb, false); }
|
||||||
|
void FCTIDZ_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00065e, ra, rt, rb, true); }
|
||||||
|
void FCTIW(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00001c, ra, rt, rb, false); }
|
||||||
|
void FCTIW_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00001c, ra, rt, rb, true); }
|
||||||
|
void FCTIWZ(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0xfc00001e, bt.index, ba.index, bb.index, false); }
|
||||||
|
void FCTIWZL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0xfc00001e, bt.index, ba.index, bb.index, true); }
|
||||||
|
void FDIV(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000024, frt, fra, frb, frc, false); }
|
||||||
|
void FDIV_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000024, frt, fra, frb, frc, true); }
|
||||||
|
void FDIVS(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000024, frt, fra, frb, frc, false); }
|
||||||
|
void FDIVS_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000024, frt, fra, frb, frc, true); }
|
||||||
|
void FMADD(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00003a, frt, fra, frb, frc, false); }
|
||||||
|
void FMADD_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00003a, frt, fra, frb, frc, true); }
|
||||||
|
void FMADDS(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec00003a, frt, fra, frb, frc, false); }
|
||||||
|
void FMADDS_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec00003a, frt, fra, frb, frc, true); }
|
||||||
|
void FMR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000090, ra, rt, rb, false); }
|
||||||
|
void FMR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000090, ra, rt, rb, true); }
|
||||||
|
void FMSUB(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000038, frt, fra, frb, frc, false); }
|
||||||
|
void FMSUB_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000038, frt, fra, frb, frc, true); }
|
||||||
|
void FMSUBS(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000038, frt, fra, frb, frc, false); }
|
||||||
|
void FMSUBS_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000038, frt, fra, frb, frc, true); }
|
||||||
|
void FMUL(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000032, frt, fra, frb, frc, false); }
|
||||||
|
void FMUL_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000032, frt, fra, frb, frc, true); }
|
||||||
|
void FMULS(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000032, frt, fra, frb, frc, false); }
|
||||||
|
void FMULS_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000032, frt, fra, frb, frc, true); }
|
||||||
|
void FNABS(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000110, ra, rt, rb, false); }
|
||||||
|
void FNABS_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000110, ra, rt, rb, true); }
|
||||||
|
void FNEG(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000050, ra, rt, rb, false); }
|
||||||
|
void FNEG_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000050, ra, rt, rb, true); }
|
||||||
|
void FNMADD(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00003e, frt, fra, frb, frc, false); }
|
||||||
|
void FNMADD_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00003e, frt, fra, frb, frc, true); }
|
||||||
|
void FNMADDS(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec00003e, frt, fra, frb, frc, false); }
|
||||||
|
void FNMADDS_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec00003e, frt, fra, frb, frc, true); }
|
||||||
|
void FNMSUB(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00003c, frt, fra, frb, frc, false); }
|
||||||
|
void FNMSUB_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00003c, frt, fra, frb, frc, true); }
|
||||||
|
void FNMSUBS(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec00003c, frt, fra, frb, frc, false); }
|
||||||
|
void FNMSUBS_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec00003c, frt, fra, frb, frc, true); }
|
||||||
|
void FRES(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000030, frt, fra, frb, frc, false); }
|
||||||
|
void FRES_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000030, frt, fra, frb, frc, true); }
|
||||||
|
void FRSP(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000018, ra, rt, rb, false); }
|
||||||
|
void FRSP_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000018, ra, rt, rb, true); }
|
||||||
|
void FRSQRTE(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000034, frt, fra, frb, frc, false); }
|
||||||
|
void FRSQRTE_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000034, frt, fra, frb, frc, true); }
|
||||||
|
void FSEL(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00002e, frt, fra, frb, frc, false); }
|
||||||
|
void FSEL_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc00002e, frt, fra, frb, frc, true); }
|
||||||
|
void FSUB(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000028, frt, fra, frb, frc, false); }
|
||||||
|
void FSUB_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xfc000028, frt, fra, frb, frc, true); }
|
||||||
|
void FSUBS(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000028, frt, fra, frb, frc, false); }
|
||||||
|
void FSUBS_(FPR const frt, FPR const fra, FPR const frb, FPR const frc) { emit_A(0xec000028, frt, fra, frb, frc, true); }
|
||||||
|
void ICBI(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0007ac, ra, rt, rb, false); }
|
||||||
|
void ICBI_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0007ac, ra, rt, rb, true); }
|
||||||
|
void ISYNC(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x4c00012c, ra, rt, rb, false); }
|
||||||
|
void ISYNC_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x4c00012c, ra, rt, rb, true); }
|
||||||
|
void LBZ(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x88000000, rt, ra, d); }
|
||||||
|
void LBZU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x8c000000, rt, ra, d); }
|
||||||
|
void LBZUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000ee, ra, rt, rb, false); }
|
||||||
|
void LBZUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000ee, ra, rt, rb, true); }
|
||||||
|
void LBZX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000ae, ra, rt, rb, false); }
|
||||||
|
void LBZX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000ae, ra, rt, rb, true); }
|
||||||
|
void LD(GPR const rt, GPR const ra, uint32_t d) { emit_DS(0xe8000000, rt, ra, d >> 2); }
|
||||||
|
void LDARX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000a8, ra, rt, rb, false); }
|
||||||
|
void LDARX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000a8, ra, rt, rb, true); }
|
||||||
|
void LDU(GPR const rt, GPR const ra, uint32_t d) { emit_DS(0xe8000001, rt, ra, d >> 2); }
|
||||||
|
void LDUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00006a, ra, rt, rb, false); }
|
||||||
|
void LDUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00006a, ra, rt, rb, true); }
|
||||||
|
void LDX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00002a, ra, rt, rb, false); }
|
||||||
|
void LDX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00002a, ra, rt, rb, true); }
|
||||||
|
void LFD(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xc8000000, rt, ra, d); }
|
||||||
|
void LFDU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xcc000000, rt, ra, d); }
|
||||||
|
void LFDUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004ee, ra, rt, rb, false); }
|
||||||
|
void LFDUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004ee, ra, rt, rb, true); }
|
||||||
|
void LFDX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004ae, ra, rt, rb, false); }
|
||||||
|
void LFDX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004ae, ra, rt, rb, true); }
|
||||||
|
void LFS(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xc0000000, rt, ra, d); }
|
||||||
|
void LFSU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xc4000000, rt, ra, d); }
|
||||||
|
void LFSUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00046e, ra, rt, rb, false); }
|
||||||
|
void LFSUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00046e, ra, rt, rb, true); }
|
||||||
|
void LFSX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00042e, ra, rt, rb, false); }
|
||||||
|
void LFSX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00042e, ra, rt, rb, true); }
|
||||||
|
void LHA(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xa8000000, rt, ra, d); }
|
||||||
|
void LHAU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xac000000, rt, ra, d); }
|
||||||
|
void LHAUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002ee, ra, rt, rb, false); }
|
||||||
|
void LHAUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002ee, ra, rt, rb, true); }
|
||||||
|
void LHAX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002ae, ra, rt, rb, false); }
|
||||||
|
void LHAX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002ae, ra, rt, rb, true); }
|
||||||
|
void LHBRX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00062c, ra, rt, rb, false); }
|
||||||
|
void LHBRX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00062c, ra, rt, rb, true); }
|
||||||
|
void LHZ(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xa0000000, rt, ra, d); }
|
||||||
|
void LHZU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xa4000000, rt, ra, d); }
|
||||||
|
void LHZUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000296, ra, rt, rb, false); }
|
||||||
|
void LHZUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000296, ra, rt, rb, true); }
|
||||||
|
void LHZX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00022e, ra, rt, rb, false); }
|
||||||
|
void LHZX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00022e, ra, rt, rb, true); }
|
||||||
|
void LMW(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xb8000000, rt, ra, d); }
|
||||||
|
void LSWI(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004aa, ra, rt, rb, false); }
|
||||||
|
void LSWI_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004aa, ra, rt, rb, true); }
|
||||||
|
void LSWX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00042a, ra, rt, rb, false); }
|
||||||
|
void LSWX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00042a, ra, rt, rb, true); }
|
||||||
|
void LWA(GPR const rt, GPR const ra, uint32_t d) { emit_DS(0xe8000002, rt, ra, d >> 2); }
|
||||||
|
void LWARX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000028, ra, rt, rb, false); }
|
||||||
|
void LWARX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000028, ra, rt, rb, true); }
|
||||||
|
void LWAUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002ea, ra, rt, rb, false); }
|
||||||
|
void LWAUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002ea, ra, rt, rb, true); }
|
||||||
|
void LWAX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002aa, ra, rt, rb, false); }
|
||||||
|
void LWAX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002aa, ra, rt, rb, true); }
|
||||||
|
void LWBRX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00042c, ra, rt, rb, false); }
|
||||||
|
void LWBRX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00042c, ra, rt, rb, true); }
|
||||||
|
void LWZ(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x80000000, rt, ra, d); }
|
||||||
|
void LWZU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x84000000, rt, ra, d); }
|
||||||
|
void LWZUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00006e, ra, rt, rb, false); }
|
||||||
|
void LWZUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00006e, ra, rt, rb, true); }
|
||||||
|
void LWZX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00002e, ra, rt, rb, false); }
|
||||||
|
void LWZX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00002e, ra, rt, rb, true); }
|
||||||
|
void MCRF(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000000, bt.index, ba.index, bb.index, false); }
|
||||||
|
void MCRFL(CPR const bt, CPR const ba, CPR const bb) { emit_XL(0x4c000000, bt.index, ba.index, bb.index, true); }
|
||||||
|
void MCRFS(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000080, ra, rt, rb, false); }
|
||||||
|
void MCRFS_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc000080, ra, rt, rb, true); }
|
||||||
|
void MCRXR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000400, ra, rt, rb, false); }
|
||||||
|
void MCRXR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000400, ra, rt, rb, true); }
|
||||||
|
void MFCR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000026, ra, rt, rb, false); }
|
||||||
|
void MFCR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000026, ra, rt, rb, true); }
|
||||||
|
void MFFS(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00048e, ra, rt, rb, false); }
|
||||||
|
void MFFS_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00048e, ra, rt, rb, true); }
|
||||||
|
void MFMSR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000a6, ra, rt, rb, false); }
|
||||||
|
void MFMSR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000a6, ra, rt, rb, true); }
|
||||||
|
void MFSPR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002a6, ra, rt, rb, false); }
|
||||||
|
void MFSPR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0002a6, ra, rt, rb, true); }
|
||||||
|
void MFSR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004a6, ra, rt, rb, false); }
|
||||||
|
void MFSR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004a6, ra, rt, rb, true); }
|
||||||
|
void MFSRIN(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000526, ra, rt, rb, false); }
|
||||||
|
void MFSRIN_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000526, ra, rt, rb, true); }
|
||||||
|
void MTCRF(GPR const rt, uint32_t spr) { emit_XFX(0x7c000120, rt, spr); }
|
||||||
|
void MTFSB0(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00008c, ra, rt, rb, false); }
|
||||||
|
void MTFSB0_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00008c, ra, rt, rb, true); }
|
||||||
|
void MTFSB1(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00004c, ra, rt, rb, false); }
|
||||||
|
void MTFSB1_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00004c, ra, rt, rb, true); }
|
||||||
|
void MTFSF() { emit_XFL(0xfc00058e); }
|
||||||
|
void MTFSFI(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00010c, ra, rt, rb, false); }
|
||||||
|
void MTFSFI_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0xfc00010c, ra, rt, rb, true); }
|
||||||
|
void MTMSR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000124, ra, rt, rb, false); }
|
||||||
|
void MTMSR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000124, ra, rt, rb, true); }
|
||||||
|
void MTSPR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0003a6, ra, rt, rb, false); }
|
||||||
|
void MTSPR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0003a6, ra, rt, rb, true); }
|
||||||
|
void MTSR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001a4, ra, rt, rb, false); }
|
||||||
|
void MTSR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001a4, ra, rt, rb, true); }
|
||||||
|
void MTSRIN(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001e4, ra, rt, rb, false); }
|
||||||
|
void MTSRIN_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001e4, ra, rt, rb, true); }
|
||||||
|
void MULHD(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000092, rt, ra, rb, false, false); }
|
||||||
|
void MULHDO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000092, rt, ra, rb, true, false); }
|
||||||
|
void MULHD_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000092, rt, ra, rb, false, true); }
|
||||||
|
void MULHDO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000092, rt, ra, rb, true, true); }
|
||||||
|
void MULHDU(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000012, rt, ra, rb, false, false); }
|
||||||
|
void MULHDUO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000012, rt, ra, rb, true, false); }
|
||||||
|
void MULHDU_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000012, rt, ra, rb, false, true); }
|
||||||
|
void MULHDUO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000012, rt, ra, rb, true, true); }
|
||||||
|
void MULHW(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000096, rt, ra, rb, false, false); }
|
||||||
|
void MULHWO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000096, rt, ra, rb, true, false); }
|
||||||
|
void MULHW_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000096, rt, ra, rb, false, true); }
|
||||||
|
void MULHWO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000096, rt, ra, rb, true, true); }
|
||||||
|
void MULHWU(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000016, rt, ra, rb, false, false); }
|
||||||
|
void MULHWUO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000016, rt, ra, rb, true, false); }
|
||||||
|
void MULHWU_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000016, rt, ra, rb, false, true); }
|
||||||
|
void MULHWUO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000016, rt, ra, rb, true, true); }
|
||||||
|
void MULLD(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d2, rt, ra, rb, false, false); }
|
||||||
|
void MULLDO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d2, rt, ra, rb, true, false); }
|
||||||
|
void MULLD_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d2, rt, ra, rb, false, true); }
|
||||||
|
void MULLDO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d2, rt, ra, rb, true, true); }
|
||||||
|
void MULLI(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x1c000000, rt, ra, d); }
|
||||||
|
void MULLW(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d6, rt, ra, rb, false, false); }
|
||||||
|
void MULLWO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d6, rt, ra, rb, true, false); }
|
||||||
|
void MULLW_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d6, rt, ra, rb, false, true); }
|
||||||
|
void MULLWO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d6, rt, ra, rb, true, true); }
|
||||||
|
void NAND(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0003b8, ra, rt, rb, false); }
|
||||||
|
void NAND_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0003b8, ra, rt, rb, true); }
|
||||||
|
void NEG(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0000d0, rt, ra, rb, false, false); }
|
||||||
|
void NEGO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0000d0, rt, ra, rb, true, false); }
|
||||||
|
void NEG_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0000d0, rt, ra, rb, false, true); }
|
||||||
|
void NEGO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0000d0, rt, ra, rb, true, true); }
|
||||||
|
void NOR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000f8, ra, rt, rb, false); }
|
||||||
|
void NOR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0000f8, ra, rt, rb, true); }
|
||||||
|
void OR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000378, ra, rt, rb, false); }
|
||||||
|
void OR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000378, ra, rt, rb, true); }
|
||||||
|
void ORC(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000338, ra, rt, rb, false); }
|
||||||
|
void ORC_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000338, ra, rt, rb, true); }
|
||||||
|
void ORI(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x60000000, ra, rt, d); }
|
||||||
|
void ORIS(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x64000000, ra, rt, d); }
|
||||||
|
void RFI(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x4c000064, ra, rt, rb, false); }
|
||||||
|
void RFI_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x4c000064, ra, rt, rb, true); }
|
||||||
|
void RLDCL(GPR const rs, GPR const ra, GPR const rb, uint32_t mb) { emit_MDS(0x78000010, ra, rs, rb, mb, false); }
|
||||||
|
void RLDCL_(GPR const rs, GPR const ra, GPR const rb, uint32_t mb) { emit_MDS(0x78000010, ra, rs, rb, mb, true); }
|
||||||
|
void RLDCR(GPR const rs, GPR const ra, GPR const rb, uint32_t mb) { emit_MDS(0x78000012, ra, rs, rb, mb, false); }
|
||||||
|
void RLDCR_(GPR const rs, GPR const ra, GPR const rb, uint32_t mb) { emit_MDS(0x78000012, ra, rs, rb, mb, true); }
|
||||||
|
void RLDIC(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) { emit_MD(0x78000008, ra, rs, mb, sh, false); }
|
||||||
|
void RLDIC_(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) { emit_MD(0x78000008, ra, rs, mb, sh, true); }
|
||||||
|
void RLDICL(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) { emit_MD(0x78000000, ra, rs, mb, sh, false); }
|
||||||
|
void RLDICL_(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) { emit_MD(0x78000000, ra, rs, mb, sh, true); }
|
||||||
|
void RLDICR(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) { emit_MD(0x78000004, ra, rs, mb, sh, false); }
|
||||||
|
void RLDICR_(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) { emit_MD(0x78000004, ra, rs, mb, sh, true); }
|
||||||
|
void RLDIMI(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) { emit_MD(0x7800000c, ra, rs, mb, sh, false); }
|
||||||
|
void RLDIMI_(GPR const rs, GPR const ra, uint32_t mb, uint32_t sh) { emit_MD(0x7800000c, ra, rs, mb, sh, true); }
|
||||||
|
void RLWIMI(GPR const rs, GPR const ra, uint32_t sh, uint32_t mb, uint32_t me = 0) { emit_M(0x50000000, ra, rs, sh, mb, me, false); }
|
||||||
|
void RLWIMI_(GPR const rs, GPR const ra, uint32_t sh, uint32_t mb, uint32_t me = 0) { emit_M(0x50000000, ra, rs, sh, mb, me, true); }
|
||||||
|
void RLWINM(GPR const rs, GPR const ra, uint32_t sh, uint32_t mb, uint32_t me = 0) { emit_M(0x54000000, ra, rs, sh, mb, me, false); }
|
||||||
|
void RLWINM_(GPR const rs, GPR const ra, uint32_t sh, uint32_t mb, uint32_t me = 0) { emit_M(0x54000000, ra, rs, sh, mb, me, true); }
|
||||||
|
void RLWNM(GPR const rs, GPR const ra, GPR const rb, uint32_t mb, uint32_t me = 0) { emit_M(0x5c000000, ra, rs, rb.index, mb, me, false); }
|
||||||
|
void RLWNM_(GPR const rs, GPR const ra, GPR const rb, uint32_t mb, uint32_t me = 0) { emit_M(0x5c000000, ra, rs, rb.index, mb, me, true); }
|
||||||
|
void SC(uint32_t lev) { emit_SC(0x44000000, lev); }
|
||||||
|
void SI(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x30000000, rt, ra, d); }
|
||||||
|
void SI_(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x34000000, rt, ra, d); }
|
||||||
|
void SLBIA(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0003e4, ra, rt, rb, false); }
|
||||||
|
void SLBIA_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0003e4, ra, rt, rb, true); }
|
||||||
|
void SLBIE(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000364, ra, rt, rb, false); }
|
||||||
|
void SLBIE_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000364, ra, rt, rb, true); }
|
||||||
|
void SLD(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000036, ra, rt, rb, false); }
|
||||||
|
void SLD_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000036, ra, rt, rb, true); }
|
||||||
|
void SLW(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000030, ra, rt, rb, false); }
|
||||||
|
void SLW_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000030, ra, rt, rb, true); }
|
||||||
|
void SRAD(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000634, ra, rt, rb, false); }
|
||||||
|
void SRAD_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000634, ra, rt, rb, true); }
|
||||||
|
void SRADI(GPR const rt, GPR const ra, uint32_t sh) { emit_XS(0x7c000674, rt, ra, sh, false); }
|
||||||
|
void SRADI_(GPR const rt, GPR const ra, uint32_t sh) { emit_XS(0x7c000674, rt, ra, sh, true); }
|
||||||
|
void SRD(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000436, ra, rt, rb, false); }
|
||||||
|
void SRD_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000436, ra, rt, rb, true); }
|
||||||
|
void SRAW(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000630, ra, rt, rb, false); }
|
||||||
|
void SRAW_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000630, ra, rt, rb, true); }
|
||||||
|
void SRAWI(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000670, ra, rt, rb, false); }
|
||||||
|
void SRAWI_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000670, ra, rt, rb, true); }
|
||||||
|
void SRW(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000430, ra, rt, rb, false); }
|
||||||
|
void SRW_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000430, ra, rt, rb, true); }
|
||||||
|
void STB(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x98000000, rt, ra, d); }
|
||||||
|
void STBU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x9c000000, rt, ra, d); }
|
||||||
|
void STBUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001ee, ra, rt, rb, false); }
|
||||||
|
void STBUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001ee, ra, rt, rb, true); }
|
||||||
|
void STBX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001ae, ra, rt, rb, false); }
|
||||||
|
void STBX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001ae, ra, rt, rb, true); }
|
||||||
|
void STD(GPR const rt, GPR const ra, uint32_t d) { emit_DS(0xf8000000, rt, ra, d >> 2); }
|
||||||
|
void STDCX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001ac, ra, rt, rb, false); }
|
||||||
|
void STDCX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0001ac, ra, rt, rb, true); }
|
||||||
|
void STDU(GPR const rt, GPR const ra, uint32_t d) { emit_DS(0xf8000001, rt, ra, d >> 2); }
|
||||||
|
void STDUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00016a, ra, rt, rb, false); }
|
||||||
|
void STDUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00016a, ra, rt, rb, true); }
|
||||||
|
void STDX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00012a, ra, rt, rb, false); }
|
||||||
|
void STDX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00012a, ra, rt, rb, true); }
|
||||||
|
void STFD(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xd8000000, rt, ra, d); }
|
||||||
|
void STFDU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xdc000000, rt, ra, d); }
|
||||||
|
void STFDUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0005ee, ra, rt, rb, false); }
|
||||||
|
void STFDUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0005ee, ra, rt, rb, true); }
|
||||||
|
void STFDX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0005ae, ra, rt, rb, false); }
|
||||||
|
void STFDX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0005ae, ra, rt, rb, true); }
|
||||||
|
void STFIWX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0007ae, ra, rt, rb, false); }
|
||||||
|
void STFIWX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0007ae, ra, rt, rb, true); }
|
||||||
|
void STFS(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xd0000000, rt, ra, d); }
|
||||||
|
void STFSU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xd4000000, rt, ra, d); }
|
||||||
|
void STFSUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00056e, ra, rt, rb, false); }
|
||||||
|
void STFSUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00056e, ra, rt, rb, true); }
|
||||||
|
void STFSX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00052e, ra, rt, rb, false); }
|
||||||
|
void STFSX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00052e, ra, rt, rb, true); }
|
||||||
|
void STH(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xb0000000, rt, ra, d); }
|
||||||
|
void STHBRX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00072c, ra, rt, rb, false); }
|
||||||
|
void STHBRX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00072c, ra, rt, rb, true); }
|
||||||
|
void STHU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xb4000000, rt, ra, d); }
|
||||||
|
void STHUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00036e, ra, rt, rb, false); }
|
||||||
|
void STHUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00036e, ra, rt, rb, true); }
|
||||||
|
void STHX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00032e, ra, rt, rb, false); }
|
||||||
|
void STHX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00032e, ra, rt, rb, true); }
|
||||||
|
void STMW(GPR const rt, GPR const ra, uint32_t d) { emit_D(0xbc000000, rt, ra, d); }
|
||||||
|
void STSWI(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0005aa, ra, rt, rb, false); }
|
||||||
|
void STSWI_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0005aa, ra, rt, rb, true); }
|
||||||
|
void STSWX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00052a, ra, rt, rb, false); }
|
||||||
|
void STSWX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00052a, ra, rt, rb, true); }
|
||||||
|
void STW(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x90000000, rt, ra, d); }
|
||||||
|
void STWBRX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00052c, ra, rt, rb, false); }
|
||||||
|
void STWBRX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00052c, ra, rt, rb, true); }
|
||||||
|
void STWCX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00012c, ra, rt, rb, false); }
|
||||||
|
void STWCX__(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00012c, ra, rt, rb, true); }
|
||||||
|
void STWU(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x94000000, rt, ra, d); }
|
||||||
|
void STWUX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00016e, ra, rt, rb, false); }
|
||||||
|
void STWUX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00016e, ra, rt, rb, true); }
|
||||||
|
void STWX(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00012e, ra, rt, rb, false); }
|
||||||
|
void STWX_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00012e, ra, rt, rb, true); }
|
||||||
|
void SUBF(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000050, rt, ra, rb, false, false); }
|
||||||
|
void SUBFO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000050, rt, ra, rb, true, false); }
|
||||||
|
void SUBF_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000050, rt, ra, rb, false, true); }
|
||||||
|
void SUBFO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000050, rt, ra, rb, true, true); }
|
||||||
|
void SUBFC(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000010, rt, ra, rb, false, false); }
|
||||||
|
void SUBFCO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000010, rt, ra, rb, true, false); }
|
||||||
|
void SUBFC_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000010, rt, ra, rb, false, true); }
|
||||||
|
void SUBFCO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000010, rt, ra, rb, true, true); }
|
||||||
|
void SUBFE(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000110, rt, ra, rb, false, false); }
|
||||||
|
void SUBFEO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000110, rt, ra, rb, true, false); }
|
||||||
|
void SUBFE_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000110, rt, ra, rb, false, true); }
|
||||||
|
void SUBFEO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000110, rt, ra, rb, true, true); }
|
||||||
|
void SUBFIC(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x20000000, rt, ra, d); }
|
||||||
|
void SUBFME(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d0, rt, ra, rb, false, false); }
|
||||||
|
void SUBFMEO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d0, rt, ra, rb, true, false); }
|
||||||
|
void SUBFME_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d0, rt, ra, rb, false, true); }
|
||||||
|
void SUBFMEO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c0001d0, rt, ra, rb, true, true); }
|
||||||
|
void SUBFZE(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000190, rt, ra, rb, false, false); }
|
||||||
|
void SUBFZEO(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000190, rt, ra, rb, true, false); }
|
||||||
|
void SUBFZE_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000190, rt, ra, rb, false, true); }
|
||||||
|
void SUBFZEO_(GPR const rt, GPR const ra, GPR const rb) { emit_XO(0x7c000190, rt, ra, rb, true, true); }
|
||||||
|
void SYNC(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004ac, ra, rt, rb, false); }
|
||||||
|
void SYNC_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c0004ac, ra, rt, rb, true); }
|
||||||
|
void TD(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000088, ra, rt, rb, false); }
|
||||||
|
void TD_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000088, ra, rt, rb, true); }
|
||||||
|
void TDI(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x08000000, rt, ra, d); }
|
||||||
|
void TLBIE(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000264, ra, rt, rb, false); }
|
||||||
|
void TLBIE_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000264, ra, rt, rb, true); }
|
||||||
|
void TLBSYNC(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00046c, ra, rt, rb, false); }
|
||||||
|
void TLBSYNC_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c00046c, ra, rt, rb, true); }
|
||||||
|
void TW(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000008, ra, rt, rb, false); }
|
||||||
|
void TW_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000008, ra, rt, rb, true); }
|
||||||
|
void TWI(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x0c000000, rt, ra, d); }
|
||||||
|
void XOR(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000278, ra, rt, rb, false); }
|
||||||
|
void XOR_(GPR const rt, GPR const ra, GPR const rb) { emit_X(0x7c000278, ra, rt, rb, true); }
|
||||||
|
void XORI(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x68000000, ra, rt, d); }
|
||||||
|
void XORIS(GPR const rt, GPR const ra, uint32_t d) { emit_D(0x6c000000, ra, rt, d); }
|
||||||
Vendored
+340
@@ -0,0 +1,340 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include "powah_emit.hpp"
|
||||||
|
|
||||||
|
#define EB32(X) __bswap32(X)
|
||||||
|
|
||||||
|
TEST_CASE("ppc64: addi", "[ppc64]") {
|
||||||
|
std::vector<uint32_t> data(64);
|
||||||
|
powah::Context ctx(data.data(), data.size());
|
||||||
|
|
||||||
|
ctx.ADDI(powah::R2, powah::R2, 0);
|
||||||
|
ctx.ADDIS(powah::R2, powah::R12, 0);
|
||||||
|
REQUIRE(data[0] == EB32(0x00004238));
|
||||||
|
REQUIRE(data[1] == EB32(0x00004c3c));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("ppc64: std/mr", "[ppc64]") {
|
||||||
|
std::vector<uint32_t> data(64);
|
||||||
|
powah::Context ctx(data.data(), data.size());
|
||||||
|
|
||||||
|
ctx.STD(powah::R26, powah::R1, 144);
|
||||||
|
ctx.MR(powah::R26, powah::R4);
|
||||||
|
ctx.STD(powah::R30, powah::R1, 176);
|
||||||
|
ctx.MR(powah::R30, powah::R3);
|
||||||
|
ctx.RLDICR(powah::R4, powah::R5, 25, 6);
|
||||||
|
ctx.STD(powah::R28, powah::R1, 160);
|
||||||
|
REQUIRE(data[0] == EB32(0x900041fb));
|
||||||
|
REQUIRE(data[1] == EB32(0x78239a7c));
|
||||||
|
REQUIRE(data[2] == EB32(0xb000c1fb));
|
||||||
|
REQUIRE(data[3] == EB32(0x781b7e7c));
|
||||||
|
REQUIRE(data[4] == EB32(0x84c9a478));
|
||||||
|
REQUIRE(data[5] == EB32(0xa00081fb));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("ppc64: sldi", "[ppc64]") {
|
||||||
|
std::vector<uint32_t> data(64);
|
||||||
|
powah::Context ctx(data.data(), data.size());
|
||||||
|
|
||||||
|
ctx.SLDI(powah::R3, powah::R5, 37);
|
||||||
|
REQUIRE(data[0] == EB32(0x862ea378));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("ppc64: rldicr", "[ppc64]") {
|
||||||
|
std::vector<uint32_t> data(64);
|
||||||
|
powah::Context ctx(data.data(), data.size());
|
||||||
|
ctx.RLDICR(powah::R1, powah::R1, 0, 0);
|
||||||
|
ctx.RLDICR(powah::R1, powah::R1, 1, 0);
|
||||||
|
ctx.RLDICR(powah::R1, powah::R1, 0, 1);
|
||||||
|
ctx.RLDICR(powah::R1, powah::R1, 1, 1);
|
||||||
|
ctx.RLDICR(powah::R1, powah::R1, 31, 31);
|
||||||
|
REQUIRE(data[0] == EB32(0x04002178));
|
||||||
|
REQUIRE(data[1] == EB32(0x04082178));
|
||||||
|
REQUIRE(data[2] == EB32(0x44002178));
|
||||||
|
REQUIRE(data[3] == EB32(0x44082178));
|
||||||
|
REQUIRE(data[4] == EB32(0xc4ff2178));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("ppc64: mr/or/std", "[ppc64]") {
|
||||||
|
std::vector<uint32_t> data(64);
|
||||||
|
powah::Context ctx(data.data(), data.size());
|
||||||
|
ctx.MR(powah::R27, powah::R7);
|
||||||
|
ctx.MR(powah::R29, powah::R6);
|
||||||
|
ctx.OR(powah::R3, powah::R3, powah::R4);
|
||||||
|
ctx.MR(powah::R4, powah::R28);
|
||||||
|
ctx.CRMOVE(powah::CPR{8}, powah::CPR{1});
|
||||||
|
ctx.MR(powah::R25, powah::R5);
|
||||||
|
ctx.OR(powah::R3, powah::R3, powah::R26);
|
||||||
|
ctx.STD(powah::R3, powah::R1, 56);
|
||||||
|
ctx.MR(powah::R3, powah::R30);
|
||||||
|
REQUIRE(data[0] == EB32(0x783bfb7c));
|
||||||
|
REQUIRE(data[1] == EB32(0x7833dd7c));
|
||||||
|
REQUIRE(data[2] == EB32(0x7823637c));
|
||||||
|
REQUIRE(data[3] == EB32(0x78e3847f));
|
||||||
|
REQUIRE(data[4] == EB32(0x820b014d));
|
||||||
|
REQUIRE(data[5] == EB32(0x782bb97c));
|
||||||
|
REQUIRE(data[6] == EB32(0x78d3637c));
|
||||||
|
REQUIRE(data[7] == EB32(0x380061f8));
|
||||||
|
REQUIRE(data[8] == EB32(0x78f3c37f));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("ppc64: ld/crand+addi", "[ppc64]") {
|
||||||
|
std::vector<uint32_t> data(64);
|
||||||
|
powah::Context ctx(data.data(), data.size());
|
||||||
|
ctx.LD(powah::R4, powah::R1, 72);
|
||||||
|
ctx.LWZ(powah::R5, powah::R1, 80);
|
||||||
|
ctx.CRAND(powah::CPR{20}, powah::CPR{10}, powah::CPR{9});
|
||||||
|
ctx.ADDI(powah::R6, powah::R4, 4);
|
||||||
|
ctx.ANDIS_(powah::R4, powah::R5, 1992);
|
||||||
|
ctx.LD(powah::R5, powah::R30, 1984);
|
||||||
|
ctx.LBZ(powah::R3, powah::R1, 84);
|
||||||
|
ctx.CLRLDI(powah::R26, powah::R6, 8);
|
||||||
|
ctx.STW(powah::R4, powah::R1, 80);
|
||||||
|
ctx.ADDI(powah::R5, powah::R5, 1);
|
||||||
|
ctx.STD(powah::R26, powah::R1, 72);
|
||||||
|
ctx.STD(powah::R5, powah::R30, 1984);
|
||||||
|
REQUIRE(data[0] == EB32(0x480081e8));
|
||||||
|
REQUIRE(data[1] == EB32(0x5000a180));
|
||||||
|
REQUIRE(data[2] == EB32(0x024a8a4e));
|
||||||
|
REQUIRE(data[3] == EB32(0x0400c438));
|
||||||
|
REQUIRE(data[4] == EB32(0xc807a474));
|
||||||
|
REQUIRE(data[5] == EB32(0xc007bee8));
|
||||||
|
REQUIRE(data[6] == EB32(0x54006188));
|
||||||
|
REQUIRE(data[7] == EB32(0x0002da78));
|
||||||
|
REQUIRE(data[8] == EB32(0x50008190));
|
||||||
|
REQUIRE(data[9] == EB32(0x0100a538));
|
||||||
|
REQUIRE(data[10] == EB32(0x480041fb));
|
||||||
|
REQUIRE(data[11] == EB32(0xc007bef8));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("ppc64: rotldi", "[ppc64]") {
|
||||||
|
std::vector<uint32_t> data(64);
|
||||||
|
powah::Context ctx(data.data(), data.size());
|
||||||
|
ctx.ROTLDI(powah::R5, powah::R3, 16);
|
||||||
|
ctx.ROTLDI(powah::R4, powah::R3, 8);
|
||||||
|
ctx.RLDIMI(powah::R4, powah::R5, 8, 48);
|
||||||
|
ctx.ROTLDI(powah::R5, powah::R3, 24);
|
||||||
|
ctx.RLDIMI(powah::R4, powah::R5, 16, 40);
|
||||||
|
ctx.ROTLDI(powah::R5, powah::R3, 32);
|
||||||
|
ctx.RLDIMI(powah::R4, powah::R5, 24, 32);
|
||||||
|
ctx.ROTLDI(powah::R5, powah::R3, 48);
|
||||||
|
ctx.RLDIMI(powah::R4, powah::R5, 40, 16);
|
||||||
|
ctx.ROTLDI(powah::R5, powah::R3, 56);
|
||||||
|
ctx.RLDIMI(powah::R4, powah::R5, 48, 8);
|
||||||
|
ctx.RLDIMI(powah::R4, powah::R3, 56, 0);
|
||||||
|
ctx.MR(powah::R3, powah::R4);
|
||||||
|
REQUIRE(data[0] == EB32(0x00806578));
|
||||||
|
REQUIRE(data[1] == EB32(0x00406478));
|
||||||
|
REQUIRE(data[2] == EB32(0x2c44a478));
|
||||||
|
REQUIRE(data[3] == EB32(0x00c06578));
|
||||||
|
REQUIRE(data[4] == EB32(0x2c82a478));
|
||||||
|
REQUIRE(data[5] == EB32(0x02006578));
|
||||||
|
REQUIRE(data[6] == EB32(0x2cc0a478));
|
||||||
|
REQUIRE(data[7] == EB32(0x02806578));
|
||||||
|
REQUIRE(data[8] == EB32(0x0e44a478));
|
||||||
|
REQUIRE(data[9] == EB32(0x02c06578));
|
||||||
|
REQUIRE(data[10] == EB32(0x0e82a478));
|
||||||
|
REQUIRE(data[11] == EB32(0x0ec06478));
|
||||||
|
REQUIRE(data[12] == EB32(0x7823837c));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("ppc64: branch-backwards", "[ppc64]") {
|
||||||
|
std::vector<uint32_t> data(64);
|
||||||
|
powah::Context ctx(data.data(), data.size());
|
||||||
|
powah::Label l_3 = ctx.DefineLabel();
|
||||||
|
ctx.LABEL(l_3);
|
||||||
|
ctx.ADD(powah::R1, powah::R2, powah::R3);
|
||||||
|
ctx.B(l_3);
|
||||||
|
ctx.ApplyRelocs();
|
||||||
|
REQUIRE(data[0] == EB32(0x141a227c));
|
||||||
|
REQUIRE(data[1] == EB32(0xfcffff4b));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("ppc64: rlwimi madness", "[ppc64]") {
|
||||||
|
std::vector<uint32_t> data(64);
|
||||||
|
powah::Context ctx(data.data(), data.size());
|
||||||
|
ctx.ROTLWI(powah::R10, powah::R3, 24);
|
||||||
|
ctx.SRDI(powah::R9, powah::R3, 32);
|
||||||
|
ctx.RLWIMI(powah::R10, powah::R3, 8, 8, 15);
|
||||||
|
ctx.RLWIMI(powah::R10, powah::R3, 8, 24, 31);
|
||||||
|
ctx.ROTLWI(powah::R3, powah::R9, 24);
|
||||||
|
ctx.RLWIMI(powah::R3, powah::R9, 8, 8, 15);
|
||||||
|
ctx.RLWIMI(powah::R3, powah::R9, 8, 24, 31);
|
||||||
|
ctx.RLDIMI(powah::R3, powah::R10, 32, 0);
|
||||||
|
REQUIRE(data[0] == EB32(0x3ec06a54));
|
||||||
|
REQUIRE(data[1] == EB32(0x22006978));
|
||||||
|
REQUIRE(data[2] == EB32(0x1e426a50));
|
||||||
|
REQUIRE(data[3] == EB32(0x3e466a50));
|
||||||
|
REQUIRE(data[4] == EB32(0x3ec02355));
|
||||||
|
REQUIRE(data[5] == EB32(0x1e422351));
|
||||||
|
REQUIRE(data[6] == EB32(0x3e462351));
|
||||||
|
REQUIRE(data[7] == EB32(0x0e004379));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
0: 78 1b 68 7c mr 8, 3
|
||||||
|
4: 38 28 83 7c and 3, 4, 5
|
||||||
|
8: 74 00 6a 7c cntlzd 10, 3
|
||||||
|
c: 76 06 69 7c sradi 9, 3, 32
|
||||||
|
10: 82 d1 4a 79 rldicl 10, 10, 58, 6
|
||||||
|
14: 00 00 29 55 rlwinm 9, 9, 0, 0, 0
|
||||||
|
18: 64 f0 4a 79 sldi 10, 10, 30
|
||||||
|
1c: 78 53 29 7d or 9, 9, 10
|
||||||
|
20: 00 00 28 f9 std 9, 0(8)
|
||||||
|
24: 20 00 80 4e blr
|
||||||
|
*/
|
||||||
|
TEST_CASE("ppc64: functor-2", "[ppc64]") {
|
||||||
|
std::vector<uint32_t> data(64);
|
||||||
|
powah::Context ctx(data.data(), data.size());
|
||||||
|
ctx.MR(powah::R8, powah::R3);
|
||||||
|
ctx.AND(powah::R3, powah::R4, powah::R5);
|
||||||
|
ctx.CNTLZD(powah::R10, powah::R3);
|
||||||
|
ctx.SRADI(powah::R9, powah::R3, 32);
|
||||||
|
ctx.RLDICL(powah::R10, powah::R10, 58, 6);
|
||||||
|
ctx.RLWINM(powah::R9, powah::R9, 0, 0, 0);
|
||||||
|
ctx.SLDI(powah::R10, powah::R10, 30);
|
||||||
|
ctx.OR(powah::R9, powah::R9, powah::R10);
|
||||||
|
ctx.STD(powah::R9, powah::R8, 0);
|
||||||
|
ctx.BLR();
|
||||||
|
REQUIRE(data[0] == EB32(0x781b687c));
|
||||||
|
REQUIRE(data[1] == EB32(0x3828837c));
|
||||||
|
REQUIRE(data[2] == EB32(0x74006a7c));
|
||||||
|
REQUIRE(data[3] == EB32(0x7606697c));
|
||||||
|
REQUIRE(data[4] == EB32(0x82d14a79));
|
||||||
|
REQUIRE(data[5] == EB32(0x00002955));
|
||||||
|
REQUIRE(data[6] == EB32(0x64f04a79));
|
||||||
|
REQUIRE(data[7] == EB32(0x7853297d));
|
||||||
|
REQUIRE(data[8] == EB32(0x000028f9));
|
||||||
|
REQUIRE(data[9] == EB32(0x2000804e));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("ppc64: functor-1", "[ppc64]") {
|
||||||
|
std::vector<uint32_t> data(64);
|
||||||
|
powah::Context ctx(data.data(), data.size());
|
||||||
|
powah::Label l_4 = ctx.DefineLabel();
|
||||||
|
powah::Label l_7 = ctx.DefineLabel();
|
||||||
|
ctx.CMPLD(powah::CR0, powah::R3, powah::R4);
|
||||||
|
ctx.MR(powah::R9, powah::R3);
|
||||||
|
ctx.BGT(powah::CR0, l_7);
|
||||||
|
ctx.CMPLDI(powah::CR0, powah::R3, 3781);
|
||||||
|
ctx.LI(powah::R3, 1);
|
||||||
|
ctx.BGTLR(powah::CR0);
|
||||||
|
ctx.CMPLD(powah::CR0, powah::R9, powah::R5);
|
||||||
|
ctx.BLE(powah::CR0, l_4);
|
||||||
|
ctx.SUBF(powah::R5, powah::R9, powah::R5);
|
||||||
|
ctx.XOR(powah::R3, powah::R5, powah::R4);
|
||||||
|
ctx.BLR();
|
||||||
|
ctx.LABEL(l_4);
|
||||||
|
ctx.ADD(powah::R5, powah::R4, powah::R5);
|
||||||
|
ctx.ADD(powah::R3, powah::R5, powah::R9);
|
||||||
|
ctx.BLR();
|
||||||
|
ctx.LABEL(l_7);
|
||||||
|
ctx.ADD(powah::R3, powah::R4, powah::R5);
|
||||||
|
ctx.BLR();
|
||||||
|
ctx.ApplyRelocs();
|
||||||
|
REQUIRE(data[0] == EB32(0x4020237c));
|
||||||
|
REQUIRE(data[1] == EB32(0x781b697c));
|
||||||
|
REQUIRE(data[2] == EB32(0x30008141));
|
||||||
|
REQUIRE(data[3] == EB32(0xc50e2328));
|
||||||
|
REQUIRE(data[4] == EB32(0x01006038));
|
||||||
|
REQUIRE(data[5] == EB32(0x2000814d));
|
||||||
|
REQUIRE(data[6] == EB32(0x4028297c));
|
||||||
|
REQUIRE(data[7] == EB32(0x10008140));
|
||||||
|
REQUIRE(data[8] == EB32(0x5028a97c));
|
||||||
|
REQUIRE(data[9] == EB32(0x7822a37c));
|
||||||
|
REQUIRE(data[10] == EB32(0x2000804e));
|
||||||
|
REQUIRE(data[11] == EB32(0x142aa47c));
|
||||||
|
REQUIRE(data[12] == EB32(0x144a657c));
|
||||||
|
REQUIRE(data[13] == EB32(0x2000804e));
|
||||||
|
REQUIRE(data[14] == EB32(0x142a647c));
|
||||||
|
REQUIRE(data[15] == EB32(0x2000804e));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(ARCHITECTURE_powerpc64)
|
||||||
|
/*
|
||||||
|
0: d619637c mullw 3, 3, 3
|
||||||
|
4: 20006378 clrldi 3, 3, 32
|
||||||
|
8: 2000804e blr
|
||||||
|
*/
|
||||||
|
TEST_CASE("ppc64: live-exec square", "[ppc64]") {
|
||||||
|
uint32_t* data = (uint32_t*)mmap(nullptr, 4096, PROT_WRITE | PROT_READ | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||||
|
REQUIRE(data != nullptr);
|
||||||
|
|
||||||
|
powah::Context ctx((void*)data, 4096);
|
||||||
|
ctx.MULLW(powah::R3, powah::R3, powah::R3);
|
||||||
|
ctx.CLRLDI(powah::R3, powah::R3, 32);
|
||||||
|
ctx.BLR();
|
||||||
|
REQUIRE(data[0] == EB32(0xd619637c));
|
||||||
|
REQUIRE(data[1] == EB32(0x20006378));
|
||||||
|
REQUIRE(data[2] == EB32(0x2000804e));
|
||||||
|
|
||||||
|
auto* fn = (int (*)(int))data;
|
||||||
|
REQUIRE(fn(4) == 4 * 4);
|
||||||
|
REQUIRE(fn(8) == 8 * 8);
|
||||||
|
|
||||||
|
munmap((void*)data, 4096);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
int f(int a, int b, int c) {
|
||||||
|
a += (a > b) ? b - 0xffff : c + 402, b += 2, c &= b*c;
|
||||||
|
return a * a + b ^ c & b;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
TEST_CASE("ppc64: live-exec xoralu", "[ppc64]") {
|
||||||
|
uint32_t* data = (uint32_t*)mmap(nullptr, 4096, PROT_WRITE | PROT_READ | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||||
|
REQUIRE(data != nullptr);
|
||||||
|
|
||||||
|
powah::Context ctx((void*)data, 4096);
|
||||||
|
powah::Label l_2 = ctx.DefineLabel();
|
||||||
|
powah::Label l_3 = ctx.DefineLabel();
|
||||||
|
ctx.CMPW(powah::R3, powah::R4);
|
||||||
|
ctx.BGT(powah::CR0, l_2);
|
||||||
|
ctx.ADDI(powah::R6, powah::R5, 402);
|
||||||
|
ctx.B(l_3);
|
||||||
|
ctx.LABEL(l_2);
|
||||||
|
ctx.ADDI(powah::R6, powah::R4, 1);
|
||||||
|
ctx.ADDIS(powah::R6, powah::R6, -1);
|
||||||
|
ctx.LABEL(l_3);
|
||||||
|
ctx.ADDI(powah::R4, powah::R4, 2);
|
||||||
|
ctx.ADD(powah::R3, powah::R6, powah::R3);
|
||||||
|
ctx.MULLW(powah::R6, powah::R4, powah::R5);
|
||||||
|
ctx.MULLW(powah::R3, powah::R3, powah::R3);
|
||||||
|
ctx.AND(powah::R5, powah::R5, powah::R6);
|
||||||
|
ctx.ADD(powah::R3, powah::R3, powah::R4);
|
||||||
|
ctx.AND(powah::R4, powah::R5, powah::R4);
|
||||||
|
ctx.XOR(powah::R3, powah::R3, powah::R4);
|
||||||
|
ctx.EXTSW(powah::R3, powah::R3);
|
||||||
|
ctx.BLR();
|
||||||
|
ctx.ApplyRelocs();
|
||||||
|
REQUIRE(data[0] == EB32(0x0020037c));
|
||||||
|
REQUIRE(data[1] == EB32(0x0c008141));
|
||||||
|
REQUIRE(data[2] == EB32(0x9201c538));
|
||||||
|
REQUIRE(data[3] == EB32(0x0c000048));
|
||||||
|
REQUIRE(data[4] == EB32(0x0100c438));
|
||||||
|
REQUIRE(data[5] == EB32(0xffffc63c));
|
||||||
|
REQUIRE(data[6] == EB32(0x02008438));
|
||||||
|
REQUIRE(data[7] == EB32(0x141a667c));
|
||||||
|
REQUIRE(data[8] == EB32(0xd629c47c));
|
||||||
|
REQUIRE(data[9] == EB32(0xd619637c));
|
||||||
|
REQUIRE(data[10] == EB32(0x3830a57c));
|
||||||
|
REQUIRE(data[11] == EB32(0x1422637c));
|
||||||
|
REQUIRE(data[12] == EB32(0x3820a47c));
|
||||||
|
REQUIRE(data[13] == EB32(0x7822637c));
|
||||||
|
REQUIRE(data[14] == EB32(0xb407637c));
|
||||||
|
REQUIRE(data[15] == EB32(0x2000804e));
|
||||||
|
|
||||||
|
auto const orig = [](int a, int b, int c) {
|
||||||
|
a += (a > b) ? b - 0xffff : c + 402, b += 2, c &= b*c;
|
||||||
|
return a * a + b ^ c & b;
|
||||||
|
};
|
||||||
|
auto* fn = (int (*)(int, int, int))data;
|
||||||
|
REQUIRE(fn(0, 1, 2) == orig(0, 1, 2));
|
||||||
|
REQUIRE(fn(6456, 4564, 4564561) == orig(6456, 4564, 4564561));
|
||||||
|
|
||||||
|
munmap((void*)data, 4096);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -15,7 +15,7 @@ pkgs.mkShellNoCC {
|
|||||||
enet libopus vulkan-headers vulkan-utility-libraries
|
enet libopus vulkan-headers vulkan-utility-libraries
|
||||||
spirv-tools spirv-headers vulkan-loader unzip
|
spirv-tools spirv-headers vulkan-loader unzip
|
||||||
glslang python3 httplib cpp-jwt ffmpeg-headless
|
glslang python3 httplib cpp-jwt ffmpeg-headless
|
||||||
libusb1
|
libusb1 cubeb
|
||||||
# eden
|
# eden
|
||||||
qt6.qtbase qt6.qtmultimedia qt6.qtwayland qt6.qttools
|
qt6.qtbase qt6.qtmultimedia qt6.qtwayland qt6.qttools
|
||||||
qt6.qtwebengine qt6.qt5compat
|
qt6.qtwebengine qt6.qt5compat
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@
|
|||||||
include_directories(.)
|
include_directories(.)
|
||||||
|
|
||||||
# Dynarmic
|
# Dynarmic
|
||||||
if ((ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64 OR ARCHITECTURE_riscv64 OR ARCHITECTURE_loongarch64) AND NOT YUZU_STATIC_ROOM)
|
if ((ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64 OR ARCHITECTURE_riscv64 OR ARCHITECTURE_loongarch64 OR ARCHITECTURE_powerpc64) AND NOT YUZU_STATIC_ROOM)
|
||||||
add_subdirectory(dynarmic)
|
add_subdirectory(dynarmic)
|
||||||
add_library(dynarmic::dynarmic ALIAS dynarmic)
|
add_library(dynarmic::dynarmic ALIAS dynarmic)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -3,8 +3,6 @@
|
|||||||
|
|
||||||
package org.yuzu.yuzu_emu.dialogs
|
package org.yuzu.yuzu_emu.dialogs
|
||||||
|
|
||||||
import android.content.res.ColorStateList
|
|
||||||
import android.graphics.Rect
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@@ -20,28 +18,11 @@ import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
|
|||||||
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
|
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
|
||||||
import org.yuzu.yuzu_emu.fragments.EmulationFragment
|
import org.yuzu.yuzu_emu.fragments.EmulationFragment
|
||||||
import org.yuzu.yuzu_emu.utils.NativeConfig
|
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||||
import org.yuzu.yuzu_emu.utils.NativePostProcessing
|
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting
|
import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractShortSetting
|
import org.yuzu.yuzu_emu.features.settings.model.AbstractShortSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting
|
import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting
|
||||||
|
|
||||||
class QuickSettings(val emulationFragment: EmulationFragment) {
|
class QuickSettings(val emulationFragment: EmulationFragment) {
|
||||||
private val expandedShaders = mutableSetOf<Int>()
|
|
||||||
|
|
||||||
private fun forgetShaderSlot(index: Int) {
|
|
||||||
val shifted = mutableSetOf<Int>()
|
|
||||||
for (slot in expandedShaders) {
|
|
||||||
if (slot < index) {
|
|
||||||
shifted.add(slot)
|
|
||||||
}
|
|
||||||
if (slot > index) {
|
|
||||||
shifted.add(slot - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expandedShaders.clear()
|
|
||||||
expandedShaders.addAll(shifted)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun saveSettings() {
|
private fun saveSettings() {
|
||||||
if (emulationFragment.shouldUseCustom) {
|
if (emulationFragment.shouldUseCustom) {
|
||||||
NativeConfig.savePerGameConfig()
|
NativeConfig.savePerGameConfig()
|
||||||
@@ -251,428 +232,6 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
|||||||
container.addView(itemView)
|
container.addView(itemView)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addChoice(
|
|
||||||
title: String,
|
|
||||||
container: ViewGroup,
|
|
||||||
choices: List<String>,
|
|
||||||
selectedIndex: Int,
|
|
||||||
onSelected: (Int) -> Unit
|
|
||||||
) {
|
|
||||||
val inflater = LayoutInflater.from(emulationFragment.requireContext())
|
|
||||||
val itemView = inflater.inflate(R.layout.item_quick_settings_menu, container, false)
|
|
||||||
val headerView = itemView.findViewById<ViewGroup>(R.id.setting_header)
|
|
||||||
val titleView = itemView.findViewById<TextView>(R.id.setting_title)
|
|
||||||
val valueView = itemView.findViewById<TextView>(R.id.setting_value)
|
|
||||||
val expandIcon = itemView.findViewById<android.widget.ImageView>(R.id.expand_icon)
|
|
||||||
val radioGroup = itemView.findViewById<RadioGroup>(R.id.radio_group)
|
|
||||||
|
|
||||||
titleView.text = title
|
|
||||||
|
|
||||||
var current = ""
|
|
||||||
if (selectedIndex in choices.indices) {
|
|
||||||
current = choices[selectedIndex]
|
|
||||||
}
|
|
||||||
valueView.text = current
|
|
||||||
headerView.visibility = View.VISIBLE
|
|
||||||
|
|
||||||
var isExpanded = false
|
|
||||||
choices.forEachIndexed { index, name ->
|
|
||||||
val radioButton = com.google.android.material.radiobutton.MaterialRadioButton(
|
|
||||||
emulationFragment.requireContext()
|
|
||||||
)
|
|
||||||
radioButton.text = name
|
|
||||||
radioButton.id = View.generateViewId()
|
|
||||||
radioButton.isChecked = index == selectedIndex
|
|
||||||
radioButton.setPadding(16, 8, 16, 8)
|
|
||||||
|
|
||||||
radioButton.setOnCheckedChangeListener { _, isChecked ->
|
|
||||||
if (isChecked) {
|
|
||||||
valueView.text = name
|
|
||||||
onSelected(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
radioGroup.addView(radioButton)
|
|
||||||
}
|
|
||||||
|
|
||||||
headerView.setOnClickListener {
|
|
||||||
isExpanded = !isExpanded
|
|
||||||
if (isExpanded) {
|
|
||||||
radioGroup.visibility = View.VISIBLE
|
|
||||||
expandIcon.animate().rotation(180f).setDuration(200).start()
|
|
||||||
} else {
|
|
||||||
radioGroup.visibility = View.GONE
|
|
||||||
expandIcon.animate().rotation(0f).setDuration(200).start()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
container.addView(itemView)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addStepSlider(
|
|
||||||
title: String,
|
|
||||||
container: ViewGroup,
|
|
||||||
steps: Int,
|
|
||||||
selectedStep: Int,
|
|
||||||
describe: (Int) -> String,
|
|
||||||
onCommitted: (Int) -> Unit,
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var pressedValue = slider.value
|
|
||||||
|
|
||||||
slider.setOnTouchListener { _, event ->
|
|
||||||
val drawer = emulationFragment.view?.findViewById<DrawerLayout>(R.id.drawer_layout)
|
|
||||||
when (event.action) {
|
|
||||||
MotionEvent.ACTION_DOWN -> {
|
|
||||||
drawer?.requestDisallowInterceptTouchEvent(true)
|
|
||||||
pressedValue = slider.value
|
|
||||||
}
|
|
||||||
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
|
|
||||||
drawer?.requestDisallowInterceptTouchEvent(false)
|
|
||||||
if (slider.value != pressedValue) {
|
|
||||||
onCommitted(slider.value.toInt())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
container.addView(itemView)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addShaderCard(
|
|
||||||
index: Int,
|
|
||||||
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 = expandedShaders.contains(index)
|
|
||||||
if (isExpanded) {
|
|
||||||
bodyView.visibility = View.VISIBLE
|
|
||||||
expandIcon.rotation = 180f
|
|
||||||
}
|
|
||||||
|
|
||||||
headerView.setOnClickListener {
|
|
||||||
isExpanded = !isExpanded
|
|
||||||
if (isExpanded) {
|
|
||||||
expandedShaders.add(index)
|
|
||||||
bodyView.visibility = View.VISIBLE
|
|
||||||
expandIcon.animate().rotation(180f).setDuration(200).start()
|
|
||||||
} else {
|
|
||||||
expandedShaders.remove(index)
|
|
||||||
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>,
|
|
||||||
hasEffects: Boolean,
|
|
||||||
onRemoveAll: () -> Unit,
|
|
||||||
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 removeButton =
|
|
||||||
itemView.findViewById<com.google.android.material.button.MaterialButton>(
|
|
||||||
R.id.remove_all_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)
|
|
||||||
}
|
|
||||||
|
|
||||||
var closedLabel = R.string.post_processing_add
|
|
||||||
if (hasEffects) {
|
|
||||||
closedLabel = R.string.post_processing_open_list
|
|
||||||
removeButton.visibility = View.VISIBLE
|
|
||||||
}
|
|
||||||
button.setText(closedLabel)
|
|
||||||
|
|
||||||
val removeBackground = MaterialColors.getColor(
|
|
||||||
removeButton,
|
|
||||||
com.google.android.material.R.attr.colorErrorContainer
|
|
||||||
)
|
|
||||||
val removeForeground = MaterialColors.getColor(
|
|
||||||
removeButton,
|
|
||||||
com.google.android.material.R.attr.colorOnErrorContainer
|
|
||||||
)
|
|
||||||
removeButton.backgroundTintList = ColorStateList.valueOf(removeBackground)
|
|
||||||
removeButton.setTextColor(removeForeground)
|
|
||||||
removeButton.iconTint = ColorStateList.valueOf(removeForeground)
|
|
||||||
removeButton.setOnClickListener {
|
|
||||||
onRemoveAll()
|
|
||||||
}
|
|
||||||
|
|
||||||
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.setText(R.string.post_processing_close_list)
|
|
||||||
button.setIconResource(R.drawable.ic_clear)
|
|
||||||
} else {
|
|
||||||
choiceGroup.animate()
|
|
||||||
.alpha(0.0f)
|
|
||||||
.translationY(slide)
|
|
||||||
.setDuration(160)
|
|
||||||
.withEndAction {
|
|
||||||
choiceGroup.visibility = View.GONE
|
|
||||||
}
|
|
||||||
.start()
|
|
||||||
|
|
||||||
button.setText(closedLabel)
|
|
||||||
button.setIconResource(R.drawable.ic_add)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 ->
|
|
||||||
emulationFragment.editPostProcessing {
|
|
||||||
NativePostProcessing.setEnabled(checked)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 = ""
|
|
||||||
val described = NativePostProcessing.presets().firstOrNull { it.name == preset }
|
|
||||||
if (described != null) {
|
|
||||||
summary = described.description
|
|
||||||
}
|
|
||||||
if (summary.isEmpty()) {
|
|
||||||
summary =
|
|
||||||
YuzuApplication.appContext.getString(R.string.post_processing_preset_locked)
|
|
||||||
}
|
|
||||||
if (NativePostProcessing.isPresetModified()) {
|
|
||||||
summary = summary + "\n" +
|
|
||||||
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(index, title, summary, container) {
|
|
||||||
emulationFragment.editPostProcessing {
|
|
||||||
NativePostProcessing.remove(index)
|
|
||||||
}
|
|
||||||
forgetShaderSlot(index)
|
|
||||||
onStructureChanged()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (effect != null) {
|
|
||||||
for (uniform in effect.uniforms) {
|
|
||||||
addUniformSliders(body, index, uniform)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
addEffectPicker(
|
|
||||||
container,
|
|
||||||
labels,
|
|
||||||
chain.isNotEmpty(),
|
|
||||||
{
|
|
||||||
emulationFragment.editPostProcessing {
|
|
||||||
NativePostProcessing.clearChain()
|
|
||||||
}
|
|
||||||
expandedShaders.clear()
|
|
||||||
onStructureChanged()
|
|
||||||
}
|
|
||||||
) { picked ->
|
|
||||||
emulationFragment.editPostProcessing {
|
|
||||||
NativePostProcessing.append(files[picked], techniques[picked])
|
|
||||||
}
|
|
||||||
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 -> uniform.describe(position) },
|
|
||||||
{ emulationFragment.persistPostProcessing() }
|
|
||||||
) { position ->
|
|
||||||
NativePostProcessing.setValue(
|
|
||||||
index,
|
|
||||||
uniform.name,
|
|
||||||
component,
|
|
||||||
uniform.min + position * uniform.step
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addDivider(container: ViewGroup) {
|
fun addDivider(container: ViewGroup) {
|
||||||
val inflater = LayoutInflater.from(emulationFragment.requireContext())
|
val inflater = LayoutInflater.from(emulationFragment.requireContext())
|
||||||
val dividerView = inflater.inflate(R.layout.item_quick_settings_divider, container, false)
|
val dividerView = inflater.inflate(R.layout.item_quick_settings_divider, container, false)
|
||||||
|
|||||||
-36
@@ -1,36 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.features.settings.model
|
|
||||||
|
|
||||||
class FxPresetNameSetting(private val onNamed: (String) -> Unit) : AbstractStringSetting {
|
|
||||||
override val key: String
|
|
||||||
get() = "fx_preset_name"
|
|
||||||
|
|
||||||
override val defaultValue: Any
|
|
||||||
get() = ""
|
|
||||||
|
|
||||||
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(_) {}
|
|
||||||
|
|
||||||
override fun getString(needsGlobal: Boolean): String = ""
|
|
||||||
|
|
||||||
override fun setString(value: String) = onNamed(value)
|
|
||||||
|
|
||||||
override fun getValueAsString(needsGlobal: Boolean): String = ""
|
|
||||||
|
|
||||||
override fun reset() {}
|
|
||||||
}
|
|
||||||
-67
@@ -1,67 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.features.settings.model
|
|
||||||
|
|
||||||
import org.yuzu.yuzu_emu.utils.NativePostProcessing
|
|
||||||
import kotlin.math.roundToInt
|
|
||||||
|
|
||||||
abstract class FxUniformSetting(
|
|
||||||
protected val index: Int,
|
|
||||||
protected val uniform: NativePostProcessing.Uniform,
|
|
||||||
protected val component: Int
|
|
||||||
) : AbstractSetting {
|
|
||||||
override val key: String
|
|
||||||
get() = "fx_${index}_${uniform.name}_$component"
|
|
||||||
|
|
||||||
override val isRuntimeModifiable: Boolean
|
|
||||||
get() = true
|
|
||||||
|
|
||||||
override val pairedSettingKey: String
|
|
||||||
get() = ""
|
|
||||||
|
|
||||||
override val isSwitchable: Boolean
|
|
||||||
get() = false
|
|
||||||
|
|
||||||
override val isSaveable: Boolean
|
|
||||||
get() = true
|
|
||||||
|
|
||||||
override var global: Boolean
|
|
||||||
get() = true
|
|
||||||
set(_) {}
|
|
||||||
|
|
||||||
protected fun currentValue(): Float {
|
|
||||||
if (NativePostProcessing.hasValue(index, uniform.name)) {
|
|
||||||
return NativePostProcessing.getValue(index, uniform.name, component)
|
|
||||||
}
|
|
||||||
return uniform.defaultAt(component)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun commit(value: Float) {
|
|
||||||
NativePostProcessing.setValue(index, uniform.name, component, value)
|
|
||||||
NativePostProcessing.store()
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -12,7 +12,6 @@ object Settings {
|
|||||||
SECTION_SYSTEM(R.string.preferences_system),
|
SECTION_SYSTEM(R.string.preferences_system),
|
||||||
SECTION_RENDERER(R.string.preferences_graphics),
|
SECTION_RENDERER(R.string.preferences_graphics),
|
||||||
SECTION_FRAME_GEN(R.string.frame_gen),
|
SECTION_FRAME_GEN(R.string.frame_gen),
|
||||||
SECTION_POST_PROCESSING(R.string.post_processing),
|
|
||||||
SECTION_PERFORMANCE_STATS(R.string.stats_overlay_options),
|
SECTION_PERFORMANCE_STATS(R.string.stats_overlay_options),
|
||||||
SECTION_INPUT_OVERLAY(R.string.input_overlay_options),
|
SECTION_INPUT_OVERLAY(R.string.input_overlay_options),
|
||||||
SECTION_SOC_OVERLAY(R.string.soc_overlay_options),
|
SECTION_SOC_OVERLAY(R.string.soc_overlay_options),
|
||||||
|
|||||||
-1
@@ -13,7 +13,6 @@ enum class StringSetting(override val key: String) : AbstractStringSetting {
|
|||||||
DEVICE_NAME("device_name"),
|
DEVICE_NAME("device_name"),
|
||||||
LOG_FILTER("log_filter"),
|
LOG_FILTER("log_filter"),
|
||||||
PROGRAM_ARGS("program_args"),
|
PROGRAM_ARGS("program_args"),
|
||||||
POST_SHADER_CHAIN("post_shader_chain"),
|
|
||||||
|
|
||||||
WEB_TOKEN("eden_token"),
|
WEB_TOKEN("eden_token"),
|
||||||
WEB_USERNAME("eden_username")
|
WEB_USERNAME("eden_username")
|
||||||
|
|||||||
-13
@@ -1,13 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.features.settings.model.view
|
|
||||||
|
|
||||||
import androidx.annotation.StringRes
|
|
||||||
|
|
||||||
class FxButtonSetting(
|
|
||||||
@StringRes titleId: Int,
|
|
||||||
val onClick: () -> Unit
|
|
||||||
) : SettingsItem(emptySetting, titleId, "", 0, "") {
|
|
||||||
override val type = TYPE_FX_BUTTON
|
|
||||||
}
|
|
||||||
-14
@@ -1,14 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.features.settings.model.view
|
|
||||||
|
|
||||||
class FxPresetSetting(
|
|
||||||
titleString: String,
|
|
||||||
descriptionString: String = "",
|
|
||||||
val deletable: Boolean = false,
|
|
||||||
val onApply: () -> Unit,
|
|
||||||
val onDelete: () -> Unit = {}
|
|
||||||
) : SettingsItem(emptySetting, 0, titleString, 0, descriptionString) {
|
|
||||||
override val type = TYPE_FX_PRESET
|
|
||||||
}
|
|
||||||
-19
@@ -1,19 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.features.settings.model.view
|
|
||||||
|
|
||||||
import org.yuzu.yuzu_emu.utils.NativePostProcessing
|
|
||||||
|
|
||||||
class FxShaderCardSetting(
|
|
||||||
titleString: String,
|
|
||||||
descriptionString: String,
|
|
||||||
val index: Int,
|
|
||||||
val expanded: Boolean,
|
|
||||||
val uniforms: List<NativePostProcessing.Uniform>,
|
|
||||||
val onToggle: () -> Unit,
|
|
||||||
val onRemove: () -> Unit,
|
|
||||||
val onReset: () -> Unit
|
|
||||||
) : SettingsItem(emptySetting, 0, titleString, 0, descriptionString) {
|
|
||||||
override val type = TYPE_FX_SHADER
|
|
||||||
}
|
|
||||||
-19
@@ -1,19 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.features.settings.model.view
|
|
||||||
|
|
||||||
import androidx.annotation.StringRes
|
|
||||||
|
|
||||||
class FxToolbarSetting(
|
|
||||||
@StringRes val addLabelId: Int,
|
|
||||||
val listOpen: Boolean,
|
|
||||||
val presetLabel: String,
|
|
||||||
val hasEffects: Boolean,
|
|
||||||
val createPreset: StringInputSetting,
|
|
||||||
val onAdd: () -> Unit,
|
|
||||||
val onPresets: () -> Unit,
|
|
||||||
val onRemoveAll: () -> Unit
|
|
||||||
) : SettingsItem(emptySetting, 0, "", 0, "") {
|
|
||||||
override val type = TYPE_FX_TOOLBAR
|
|
||||||
}
|
|
||||||
-4
@@ -144,10 +144,6 @@ abstract class SettingsItem(
|
|||||||
const val TYPE_LAUNCHABLE = 13
|
const val TYPE_LAUNCHABLE = 13
|
||||||
const val TYPE_PATH = 14
|
const val TYPE_PATH = 14
|
||||||
const val TYPE_GPU_UNSWIZZLE = 15
|
const val TYPE_GPU_UNSWIZZLE = 15
|
||||||
const val TYPE_FX_TOOLBAR = 16
|
|
||||||
const val TYPE_FX_PRESET = 17
|
|
||||||
const val TYPE_FX_SHADER = 18
|
|
||||||
const val TYPE_FX_BUTTON = 19
|
|
||||||
|
|
||||||
const val FASTMEM_COMBINED = "fastmem_combined"
|
const val FASTMEM_COMBINED = "fastmem_combined"
|
||||||
const val GPU_UNSWIZZLE_COMBINED = "gpu_unswizzle_combined"
|
const val GPU_UNSWIZZLE_COMBINED = "gpu_unswizzle_combined"
|
||||||
|
|||||||
-32
@@ -23,10 +23,6 @@ import com.google.android.material.timepicker.TimeFormat
|
|||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
import org.yuzu.yuzu_emu.SettingsNavigationDirections
|
import org.yuzu.yuzu_emu.SettingsNavigationDirections
|
||||||
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
|
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
|
||||||
import org.yuzu.yuzu_emu.databinding.ListItemSettingFxButtonBinding
|
|
||||||
import org.yuzu.yuzu_emu.databinding.ListItemSettingFxPresetBinding
|
|
||||||
import org.yuzu.yuzu_emu.databinding.ListItemSettingFxShaderBinding
|
|
||||||
import org.yuzu.yuzu_emu.databinding.ListItemSettingFxToolbarBinding
|
|
||||||
import org.yuzu.yuzu_emu.databinding.ListItemSettingInputBinding
|
import org.yuzu.yuzu_emu.databinding.ListItemSettingInputBinding
|
||||||
import org.yuzu.yuzu_emu.databinding.ListItemSettingSwitchBinding
|
import org.yuzu.yuzu_emu.databinding.ListItemSettingSwitchBinding
|
||||||
import org.yuzu.yuzu_emu.databinding.ListItemSettingsHeaderBinding
|
import org.yuzu.yuzu_emu.databinding.ListItemSettingsHeaderBinding
|
||||||
@@ -110,34 +106,6 @@ class SettingsAdapter(
|
|||||||
GpuUnswizzleViewHolder(ListItemSettingBinding.inflate(inflater), this)
|
GpuUnswizzleViewHolder(ListItemSettingBinding.inflate(inflater), this)
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsItem.TYPE_FX_TOOLBAR -> {
|
|
||||||
FxToolbarViewHolder(
|
|
||||||
ListItemSettingFxToolbarBinding.inflate(inflater, parent, false),
|
|
||||||
this
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsItem.TYPE_FX_PRESET -> {
|
|
||||||
FxPresetViewHolder(
|
|
||||||
ListItemSettingFxPresetBinding.inflate(inflater, parent, false),
|
|
||||||
this
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsItem.TYPE_FX_SHADER -> {
|
|
||||||
FxShaderCardViewHolder(
|
|
||||||
ListItemSettingFxShaderBinding.inflate(inflater, parent, false),
|
|
||||||
this
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsItem.TYPE_FX_BUTTON -> {
|
|
||||||
FxButtonViewHolder(
|
|
||||||
ListItemSettingFxButtonBinding.inflate(inflater, parent, false),
|
|
||||||
this
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this)
|
HeaderViewHolder(ListItemSettingsHeaderBinding.inflate(inflater), this)
|
||||||
}
|
}
|
||||||
|
|||||||
-214
@@ -18,7 +18,6 @@ import org.yuzu.yuzu_emu.features.input.model.NpadStyleIndex
|
|||||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractBooleanSetting
|
import org.yuzu.yuzu_emu.features.settings.model.AbstractBooleanSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting
|
import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
|
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.FxPresetNameSetting
|
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.ByteSetting
|
import org.yuzu.yuzu_emu.features.settings.model.ByteSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
|
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.LongSetting
|
import org.yuzu.yuzu_emu.features.settings.model.LongSetting
|
||||||
@@ -31,7 +30,6 @@ import org.yuzu.yuzu_emu.features.settings.model.view.*
|
|||||||
import org.yuzu.yuzu_emu.utils.InputHandler
|
import org.yuzu.yuzu_emu.utils.InputHandler
|
||||||
import org.yuzu.yuzu_emu.utils.LosslessScalingHelper
|
import org.yuzu.yuzu_emu.utils.LosslessScalingHelper
|
||||||
import org.yuzu.yuzu_emu.utils.NativeConfig
|
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||||
import org.yuzu.yuzu_emu.utils.NativePostProcessing
|
|
||||||
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
|
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
|
||||||
import org.yuzu.yuzu_emu.utils.FullscreenHelper
|
import org.yuzu.yuzu_emu.utils.FullscreenHelper
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
@@ -46,14 +44,6 @@ class SettingsFragmentPresenter(
|
|||||||
) {
|
) {
|
||||||
private var settingsList = ArrayList<SettingsItem>()
|
private var settingsList = ArrayList<SettingsItem>()
|
||||||
|
|
||||||
private val expandedShaderSlots = mutableSetOf<Int>()
|
|
||||||
|
|
||||||
private var shaderPickerOpen = false
|
|
||||||
|
|
||||||
private var presetPickerOpen = false
|
|
||||||
|
|
||||||
private var postProcessingSynced = false
|
|
||||||
|
|
||||||
private val context get() = YuzuApplication.appContext
|
private val context get() = YuzuApplication.appContext
|
||||||
|
|
||||||
// Extension for altering settings list based on each setting's properties
|
// Extension for altering settings list based on each setting's properties
|
||||||
@@ -173,7 +163,6 @@ class SettingsFragmentPresenter(
|
|||||||
MenuTag.SECTION_SYSTEM -> addSystemSettings(sl)
|
MenuTag.SECTION_SYSTEM -> addSystemSettings(sl)
|
||||||
MenuTag.SECTION_RENDERER -> addGraphicsSettings(sl)
|
MenuTag.SECTION_RENDERER -> addGraphicsSettings(sl)
|
||||||
MenuTag.SECTION_FRAME_GEN -> addFrameGenSettings(sl)
|
MenuTag.SECTION_FRAME_GEN -> addFrameGenSettings(sl)
|
||||||
MenuTag.SECTION_POST_PROCESSING -> addPostProcessingSettings(sl)
|
|
||||||
MenuTag.SECTION_PERFORMANCE_STATS -> addPerformanceOverlaySettings(sl)
|
MenuTag.SECTION_PERFORMANCE_STATS -> addPerformanceOverlaySettings(sl)
|
||||||
MenuTag.SECTION_SOC_OVERLAY -> addSocOverlaySettings(sl)
|
MenuTag.SECTION_SOC_OVERLAY -> addSocOverlaySettings(sl)
|
||||||
MenuTag.SECTION_INPUT_OVERLAY -> addInputOverlaySettings(sl)
|
MenuTag.SECTION_INPUT_OVERLAY -> addInputOverlaySettings(sl)
|
||||||
@@ -201,209 +190,6 @@ class SettingsFragmentPresenter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addPostProcessingSettings(sl: ArrayList<SettingsItem>) {
|
|
||||||
if (!postProcessingSynced) {
|
|
||||||
postProcessingSynced = true
|
|
||||||
NativePostProcessing.reload()
|
|
||||||
}
|
|
||||||
|
|
||||||
val usable = NativePostProcessing.catalog().filter { it.valid }
|
|
||||||
|
|
||||||
sl.apply {
|
|
||||||
if (usable.isEmpty()) {
|
|
||||||
add(
|
|
||||||
RunnableSetting(
|
|
||||||
titleId = R.string.post_processing_empty,
|
|
||||||
descriptionString = NativePostProcessing.getShaderDirectory(),
|
|
||||||
isRunnable = false
|
|
||||||
) {}
|
|
||||||
)
|
|
||||||
return@apply
|
|
||||||
}
|
|
||||||
|
|
||||||
val labels = mutableListOf<String>()
|
|
||||||
val 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()
|
|
||||||
val active = NativePostProcessing.getActivePreset()
|
|
||||||
|
|
||||||
var addLabel = R.string.post_processing_add
|
|
||||||
if (chain.isNotEmpty()) {
|
|
||||||
addLabel = R.string.post_processing_open_list
|
|
||||||
}
|
|
||||||
if (shaderPickerOpen) {
|
|
||||||
addLabel = R.string.post_processing_close_list
|
|
||||||
}
|
|
||||||
|
|
||||||
var presetLabel = context.getString(R.string.post_processing_presets)
|
|
||||||
if (active.isNotEmpty()) {
|
|
||||||
presetLabel = active
|
|
||||||
}
|
|
||||||
|
|
||||||
val createPreset = StringInputSetting(
|
|
||||||
setting = FxPresetNameSetting { name ->
|
|
||||||
NativePostProcessing.savePreset(name, "")
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
},
|
|
||||||
titleId = R.string.post_processing_preset_new,
|
|
||||||
descriptionId = R.string.post_processing_preset_new_description,
|
|
||||||
validator = { it != null && it.isNotBlank() && !it.contains('=') },
|
|
||||||
errorId = R.string.post_processing_preset_name_invalid
|
|
||||||
)
|
|
||||||
|
|
||||||
add(
|
|
||||||
FxToolbarSetting(
|
|
||||||
addLabelId = addLabel,
|
|
||||||
listOpen = shaderPickerOpen,
|
|
||||||
presetLabel = presetLabel,
|
|
||||||
hasEffects = chain.isNotEmpty(),
|
|
||||||
createPreset = createPreset,
|
|
||||||
onAdd = {
|
|
||||||
shaderPickerOpen = !shaderPickerOpen
|
|
||||||
presetPickerOpen = false
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
},
|
|
||||||
onPresets = {
|
|
||||||
presetPickerOpen = !presetPickerOpen
|
|
||||||
shaderPickerOpen = false
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
},
|
|
||||||
onRemoveAll = {
|
|
||||||
NativePostProcessing.clearChain()
|
|
||||||
NativePostProcessing.clearPreset()
|
|
||||||
NativePostProcessing.store()
|
|
||||||
expandedShaderSlots.clear()
|
|
||||||
shaderPickerOpen = false
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (presetPickerOpen) {
|
|
||||||
add(
|
|
||||||
FxPresetSetting(
|
|
||||||
titleString = context.getString(R.string.post_processing_preset_none),
|
|
||||||
onApply = {
|
|
||||||
NativePostProcessing.clearPreset()
|
|
||||||
presetPickerOpen = false
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
for (preset in NativePostProcessing.presets()) {
|
|
||||||
add(
|
|
||||||
FxPresetSetting(
|
|
||||||
titleString = preset.name,
|
|
||||||
descriptionString = preset.description,
|
|
||||||
deletable = !preset.bundled,
|
|
||||||
onApply = {
|
|
||||||
NativePostProcessing.applyPreset(preset.name)
|
|
||||||
NativePostProcessing.store()
|
|
||||||
presetPickerOpen = false
|
|
||||||
expandedShaderSlots.clear()
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
},
|
|
||||||
onDelete = {
|
|
||||||
NativePostProcessing.deletePreset(preset.name)
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (active.isNotEmpty()) {
|
|
||||||
add(
|
|
||||||
FxButtonSetting(titleId = R.string.post_processing_preset_reset) {
|
|
||||||
NativePostProcessing.applyPreset(active)
|
|
||||||
NativePostProcessing.store()
|
|
||||||
expandedShaderSlots.clear()
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
for (index in chain.indices) {
|
|
||||||
val entry = chain[index]
|
|
||||||
val effect = usable.firstOrNull { it.file == entry.file }
|
|
||||||
|
|
||||||
var header = entry.file
|
|
||||||
var summary = ""
|
|
||||||
var uniforms = emptyList<NativePostProcessing.Uniform>()
|
|
||||||
if (effect != null) {
|
|
||||||
header = effect.label
|
|
||||||
if (effect.techniques.size > 1) {
|
|
||||||
header = effect.label + " \u00b7 " + entry.technique
|
|
||||||
}
|
|
||||||
summary = effect.description
|
|
||||||
uniforms = effect.uniforms
|
|
||||||
}
|
|
||||||
|
|
||||||
val isOpen = expandedShaderSlots.contains(index)
|
|
||||||
|
|
||||||
add(
|
|
||||||
FxShaderCardSetting(
|
|
||||||
titleString = header,
|
|
||||||
descriptionString = summary,
|
|
||||||
index = index,
|
|
||||||
expanded = isOpen,
|
|
||||||
uniforms = uniforms,
|
|
||||||
onToggle = {
|
|
||||||
if (isOpen) {
|
|
||||||
expandedShaderSlots.remove(index)
|
|
||||||
} else {
|
|
||||||
expandedShaderSlots.add(index)
|
|
||||||
}
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
},
|
|
||||||
onRemove = {
|
|
||||||
NativePostProcessing.remove(index)
|
|
||||||
NativePostProcessing.store()
|
|
||||||
expandedShaderSlots.clear()
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
},
|
|
||||||
onReset = {
|
|
||||||
NativePostProcessing.resetValues(index)
|
|
||||||
NativePostProcessing.store()
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addConfigSettings(sl: ArrayList<SettingsItem>) {
|
private fun addConfigSettings(sl: ArrayList<SettingsItem>) {
|
||||||
sl.apply {
|
sl.apply {
|
||||||
add(
|
add(
|
||||||
|
|||||||
-28
@@ -1,28 +0,0 @@
|
|||||||
// 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.ListItemSettingFxButtonBinding
|
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.view.FxButtonSetting
|
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
|
|
||||||
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
|
|
||||||
|
|
||||||
class FxButtonViewHolder(
|
|
||||||
val binding: ListItemSettingFxButtonBinding,
|
|
||||||
adapter: SettingsAdapter
|
|
||||||
) : SettingViewHolder(binding.root, adapter) {
|
|
||||||
private lateinit var setting: FxButtonSetting
|
|
||||||
|
|
||||||
override fun bind(item: SettingsItem) {
|
|
||||||
setting = item as FxButtonSetting
|
|
||||||
|
|
||||||
binding.fxButton.text = item.title
|
|
||||||
binding.fxButton.setOnClickListener { setting.onClick.invoke() }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onClick(clicked: View) {}
|
|
||||||
|
|
||||||
override fun onLongClick(clicked: View): Boolean = true
|
|
||||||
}
|
|
||||||
-35
@@ -1,35 +0,0 @@
|
|||||||
// 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.ListItemSettingFxPresetBinding
|
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.view.FxPresetSetting
|
|
||||||
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 FxPresetViewHolder(
|
|
||||||
val binding: ListItemSettingFxPresetBinding,
|
|
||||||
adapter: SettingsAdapter
|
|
||||||
) : SettingViewHolder(binding.root, adapter) {
|
|
||||||
private lateinit var setting: FxPresetSetting
|
|
||||||
|
|
||||||
override fun bind(item: SettingsItem) {
|
|
||||||
setting = item as FxPresetSetting
|
|
||||||
|
|
||||||
binding.presetName.text = item.title
|
|
||||||
binding.presetDescription.text = item.description
|
|
||||||
binding.presetDescription.setVisible(item.description.isNotEmpty())
|
|
||||||
|
|
||||||
binding.presetRow.setOnClickListener { setting.onApply.invoke() }
|
|
||||||
|
|
||||||
binding.presetDelete.setVisible(setting.deletable)
|
|
||||||
binding.presetDelete.setOnClickListener { setting.onDelete.invoke() }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onClick(clicked: View) {}
|
|
||||||
|
|
||||||
override fun onLongClick(clicked: View): Boolean = true
|
|
||||||
}
|
|
||||||
-100
@@ -1,100 +0,0 @@
|
|||||||
// 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.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import org.yuzu.yuzu_emu.databinding.ItemSettingFxActionsBinding
|
|
||||||
import org.yuzu.yuzu_emu.databinding.ItemSettingFxSliderBinding
|
|
||||||
import org.yuzu.yuzu_emu.databinding.ListItemSettingFxShaderBinding
|
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.FxUniformSliderSetting
|
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.view.FxShaderCardSetting
|
|
||||||
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.NativePostProcessing
|
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
|
||||||
|
|
||||||
class FxShaderCardViewHolder(
|
|
||||||
val binding: ListItemSettingFxShaderBinding,
|
|
||||||
adapter: SettingsAdapter
|
|
||||||
) : SettingViewHolder(binding.root, adapter) {
|
|
||||||
private lateinit var setting: FxShaderCardSetting
|
|
||||||
|
|
||||||
override fun bind(item: SettingsItem) {
|
|
||||||
setting = item as FxShaderCardSetting
|
|
||||||
|
|
||||||
binding.shaderTitle.text = item.title
|
|
||||||
binding.shaderSummary.text = item.description
|
|
||||||
binding.shaderSummary.setVisible(item.description.isNotEmpty())
|
|
||||||
|
|
||||||
var rotation = 0f
|
|
||||||
if (setting.expanded) {
|
|
||||||
rotation = 180f
|
|
||||||
}
|
|
||||||
binding.shaderExpand.rotation = rotation
|
|
||||||
|
|
||||||
binding.shaderHeader.setOnClickListener { setting.onToggle.invoke() }
|
|
||||||
binding.shaderRemove.setOnClickListener { setting.onRemove.invoke() }
|
|
||||||
|
|
||||||
binding.shaderBody.removeAllViews()
|
|
||||||
binding.shaderBody.setVisible(setting.expanded)
|
|
||||||
if (!setting.expanded) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val inflater = LayoutInflater.from(binding.root.context)
|
|
||||||
for (uniform in setting.uniforms) {
|
|
||||||
if (uniform.uiType == NativePostProcessing.UI_HIDDEN) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for (component in 0 until uniform.components) {
|
|
||||||
addSlider(inflater, uniform, component)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
addActions(inflater)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addSlider(
|
|
||||||
inflater: LayoutInflater,
|
|
||||||
uniform: NativePostProcessing.Uniform,
|
|
||||||
component: Int
|
|
||||||
) {
|
|
||||||
val row = ItemSettingFxSliderBinding.inflate(inflater, binding.shaderBody, false)
|
|
||||||
val value = FxUniformSliderSetting(setting.index, uniform, component)
|
|
||||||
|
|
||||||
var title = uniform.label
|
|
||||||
if (uniform.components > 1) {
|
|
||||||
title = uniform.label + " [" + component + "]"
|
|
||||||
}
|
|
||||||
row.fxSliderTitle.text = title
|
|
||||||
|
|
||||||
val steps = uniform.steps.toFloat()
|
|
||||||
row.fxSlider.valueFrom = 0f
|
|
||||||
row.fxSlider.valueTo = steps
|
|
||||||
row.fxSlider.stepSize = 1f
|
|
||||||
row.fxSlider.value = value.getInt(false).toFloat().coerceIn(0f, steps)
|
|
||||||
row.fxSliderValue.text = uniform.describe(row.fxSlider.value.toInt())
|
|
||||||
|
|
||||||
row.fxSlider.addOnChangeListener { _, position, fromUser ->
|
|
||||||
if (fromUser) {
|
|
||||||
value.setInt(position.toInt())
|
|
||||||
row.fxSliderValue.text = uniform.describe(position.toInt())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.shaderBody.addView(row.root)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addActions(inflater: LayoutInflater) {
|
|
||||||
val row = ItemSettingFxActionsBinding.inflate(inflater, binding.shaderBody, false)
|
|
||||||
|
|
||||||
row.fxReset.setOnClickListener { setting.onReset.invoke() }
|
|
||||||
|
|
||||||
binding.shaderBody.addView(row.root)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onClick(clicked: View) {}
|
|
||||||
|
|
||||||
override fun onLongClick(clicked: View): Boolean = true
|
|
||||||
}
|
|
||||||
-57
@@ -1,57 +0,0 @@
|
|||||||
// 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.content.res.ColorStateList
|
|
||||||
import android.view.View
|
|
||||||
import com.google.android.material.color.MaterialColors
|
|
||||||
import org.yuzu.yuzu_emu.R
|
|
||||||
import org.yuzu.yuzu_emu.databinding.ListItemSettingFxToolbarBinding
|
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.view.FxToolbarSetting
|
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
|
|
||||||
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
|
|
||||||
|
|
||||||
class FxToolbarViewHolder(
|
|
||||||
val binding: ListItemSettingFxToolbarBinding,
|
|
||||||
adapter: SettingsAdapter
|
|
||||||
) : SettingViewHolder(binding.root, adapter) {
|
|
||||||
private lateinit var setting: FxToolbarSetting
|
|
||||||
|
|
||||||
override fun bind(item: SettingsItem) {
|
|
||||||
setting = item as FxToolbarSetting
|
|
||||||
|
|
||||||
binding.fxAdd.setText(setting.addLabelId)
|
|
||||||
var addIcon = R.drawable.ic_add
|
|
||||||
if (setting.listOpen) {
|
|
||||||
addIcon = R.drawable.ic_clear
|
|
||||||
}
|
|
||||||
binding.fxAdd.setIconResource(addIcon)
|
|
||||||
binding.fxAdd.setOnClickListener { setting.onAdd.invoke() }
|
|
||||||
|
|
||||||
binding.fxPresets.text = setting.presetLabel
|
|
||||||
binding.fxPresets.setOnClickListener { setting.onPresets.invoke() }
|
|
||||||
|
|
||||||
binding.fxCreatePreset.isEnabled = setting.hasEffects
|
|
||||||
binding.fxCreatePreset.setOnClickListener {
|
|
||||||
adapter.onStringInputClick(setting.createPreset, bindingAdapterPosition)
|
|
||||||
}
|
|
||||||
|
|
||||||
val removeBackground = MaterialColors.getColor(
|
|
||||||
binding.fxRemoveAll,
|
|
||||||
com.google.android.material.R.attr.colorErrorContainer
|
|
||||||
)
|
|
||||||
val removeForeground = MaterialColors.getColor(
|
|
||||||
binding.fxRemoveAll,
|
|
||||||
com.google.android.material.R.attr.colorOnErrorContainer
|
|
||||||
)
|
|
||||||
binding.fxRemoveAll.backgroundTintList = ColorStateList.valueOf(removeBackground)
|
|
||||||
binding.fxRemoveAll.iconTint = ColorStateList.valueOf(removeForeground)
|
|
||||||
binding.fxRemoveAll.isEnabled = setting.hasEffects
|
|
||||||
binding.fxRemoveAll.setOnClickListener { setting.onRemoveAll.invoke() }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onClick(clicked: View) {}
|
|
||||||
|
|
||||||
override fun onLongClick(clicked: View): Boolean = true
|
|
||||||
}
|
|
||||||
@@ -94,7 +94,6 @@ import org.yuzu.yuzu_emu.utils.InputHandler
|
|||||||
import org.yuzu.yuzu_emu.utils.Log
|
import org.yuzu.yuzu_emu.utils.Log
|
||||||
import org.yuzu.yuzu_emu.utils.NativeConfig
|
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||||
import org.yuzu.yuzu_emu.utils.NativeFreedrenoConfig
|
import org.yuzu.yuzu_emu.utils.NativeFreedrenoConfig
|
||||||
import org.yuzu.yuzu_emu.utils.NativePostProcessing
|
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils
|
import org.yuzu.yuzu_emu.utils.ViewUtils
|
||||||
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
|
||||||
import org.yuzu.yuzu_emu.utils.collect
|
import org.yuzu.yuzu_emu.utils.collect
|
||||||
@@ -884,8 +883,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
if (shouldUseCustom) {
|
if (shouldUseCustom) {
|
||||||
SettingsFile.loadCustomConfig(game!!)
|
SettingsFile.loadCustomConfig(game!!)
|
||||||
}
|
}
|
||||||
refreshPostProcessing()
|
|
||||||
addQuickSettings()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1090,34 +1087,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun withPerGameConfig(create: Boolean, action: () -> Unit) {
|
|
||||||
val target = game
|
|
||||||
var owned = false
|
|
||||||
if (target != null && !NativeConfig.isPerGameConfigLoaded()) {
|
|
||||||
if (create || SettingsFile.getCustomSettingsFile(target).exists()) {
|
|
||||||
SettingsFile.loadCustomConfig(target)
|
|
||||||
owned = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
action()
|
|
||||||
if (owned) {
|
|
||||||
NativeConfig.unloadPerGameConfig()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun refreshPostProcessing() = withPerGameConfig(false) {
|
|
||||||
NativePostProcessing.reload()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun persistPostProcessing() = withPerGameConfig(true) {
|
|
||||||
NativePostProcessing.persist()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun editPostProcessing(action: () -> Unit) = withPerGameConfig(true) {
|
|
||||||
action()
|
|
||||||
NativePostProcessing.persist()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addQuickSettings() {
|
private fun addQuickSettings() {
|
||||||
binding.quickSettingsSheet.apply {
|
binding.quickSettingsSheet.apply {
|
||||||
val container = binding.quickSettingsSheet.findViewById<ViewGroup>(R.id.quick_settings_container)
|
val container = binding.quickSettingsSheet.findViewById<ViewGroup>(R.id.quick_settings_container)
|
||||||
@@ -1225,10 +1194,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
R.array.rendererAntiAliasingNames,
|
R.array.rendererAntiAliasingNames,
|
||||||
R.array.rendererAntiAliasingValues
|
R.array.rendererAntiAliasingValues
|
||||||
)
|
)
|
||||||
|
|
||||||
quickSettings.addPostProcessing(container) {
|
|
||||||
addQuickSettings()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -383,20 +383,6 @@ class GamePropertiesFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
add(
|
|
||||||
SubmenuProperty(
|
|
||||||
R.string.post_processing,
|
|
||||||
R.string.post_processing_per_game_description,
|
|
||||||
R.drawable.ic_post_processing,
|
|
||||||
action = {
|
|
||||||
val action = HomeNavigationDirections.actionGlobalSettingsActivity(
|
|
||||||
args.game,
|
|
||||||
Settings.MenuTag.SECTION_POST_PROCESSING
|
|
||||||
)
|
|
||||||
binding.root.findNavController().navigate(action)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (GpuDriverHelper.isAdrenoGpu()) {
|
if (GpuDriverHelper.isAdrenoGpu()) {
|
||||||
add(
|
add(
|
||||||
|
|||||||
@@ -171,20 +171,6 @@ class HomeSettingsFragment : Fragment() {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
add(
|
|
||||||
HomeSetting(
|
|
||||||
R.string.post_processing,
|
|
||||||
R.string.post_processing_description,
|
|
||||||
R.drawable.ic_post_processing,
|
|
||||||
{
|
|
||||||
val action = HomeNavigationDirections.actionGlobalSettingsActivity(
|
|
||||||
null,
|
|
||||||
Settings.MenuTag.SECTION_POST_PROCESSING
|
|
||||||
)
|
|
||||||
binding.root.findNavController().navigate(action)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
add(
|
add(
|
||||||
HomeSetting(
|
HomeSetting(
|
||||||
R.string.lossless_scaling,
|
R.string.lossless_scaling,
|
||||||
|
|||||||
@@ -58,6 +58,13 @@ class LicensesFragment : Fragment() {
|
|||||||
R.string.license_fidelityfx_fsr_copyright,
|
R.string.license_fidelityfx_fsr_copyright,
|
||||||
R.string.license_fidelityfx_fsr_text
|
R.string.license_fidelityfx_fsr_text
|
||||||
),
|
),
|
||||||
|
License(
|
||||||
|
R.string.license_cubeb,
|
||||||
|
R.string.license_cubeb_description,
|
||||||
|
R.string.license_cubeb_link,
|
||||||
|
R.string.license_cubeb_copyright,
|
||||||
|
R.string.license_cubeb_text
|
||||||
|
),
|
||||||
License(
|
License(
|
||||||
R.string.license_dynarmic,
|
R.string.license_dynarmic,
|
||||||
R.string.license_dynarmic_description,
|
R.string.license_dynarmic_description,
|
||||||
|
|||||||
@@ -1,242 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.utils
|
|
||||||
|
|
||||||
import org.json.JSONArray
|
|
||||||
import org.json.JSONObject
|
|
||||||
|
|
||||||
object NativePostProcessing {
|
|
||||||
const val KIND_BOOL = 0
|
|
||||||
const val KIND_INT = 1
|
|
||||||
const val KIND_FLOAT = 2
|
|
||||||
|
|
||||||
const val UI_HIDDEN = 0
|
|
||||||
const val UI_SLIDER = 1
|
|
||||||
const val UI_DRAG = 2
|
|
||||||
const val UI_COMBO = 3
|
|
||||||
const val UI_RADIO = 4
|
|
||||||
const val UI_CHECKBOX = 5
|
|
||||||
const val UI_COLOR = 6
|
|
||||||
const val UI_INPUT_BOX = 7
|
|
||||||
|
|
||||||
external fun getCatalogJson(): String
|
|
||||||
|
|
||||||
external fun getChainJson(): String
|
|
||||||
|
|
||||||
external fun append(file: String, technique: String)
|
|
||||||
|
|
||||||
external fun replace(index: Int, file: String, technique: String)
|
|
||||||
|
|
||||||
external fun remove(index: Int)
|
|
||||||
|
|
||||||
external fun move(index: Int, delta: Int)
|
|
||||||
|
|
||||||
external fun resetValues(index: Int)
|
|
||||||
|
|
||||||
external fun getValue(index: Int, uniform: String, component: Int): Float
|
|
||||||
|
|
||||||
external fun hasValue(index: Int, uniform: String): Boolean
|
|
||||||
|
|
||||||
external fun setValue(index: Int, uniform: String, component: Int, value: Float)
|
|
||||||
|
|
||||||
external fun store()
|
|
||||||
|
|
||||||
external fun reload()
|
|
||||||
|
|
||||||
external fun clearChain()
|
|
||||||
|
|
||||||
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() {
|
|
||||||
val perGame = NativeConfig.isPerGameConfigLoaded()
|
|
||||||
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 describe(position: Int): String {
|
|
||||||
val value = min + position * step
|
|
||||||
if (kind == NativePostProcessing.KIND_FLOAT) {
|
|
||||||
return String.format("%.3f", value)
|
|
||||||
}
|
|
||||||
return Math.round(value).toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
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,7 +17,6 @@ add_library(yuzu-android SHARED
|
|||||||
android_config.cpp
|
android_config.cpp
|
||||||
android_config.h
|
android_config.h
|
||||||
native_input.cpp
|
native_input.cpp
|
||||||
native_post_processing.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR})
|
set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR})
|
||||||
|
|||||||
@@ -15,22 +15,10 @@
|
|||||||
#include "frontend_common/config.h"
|
#include "frontend_common/config.h"
|
||||||
#include "frontend_common/settings_generator.h"
|
#include "frontend_common/settings_generator.h"
|
||||||
#include "native.h"
|
#include "native.h"
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
#include "video_core/post_processing/fx_chain.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::unique_ptr<AndroidConfig> global_config;
|
std::unique_ptr<AndroidConfig> global_config;
|
||||||
std::unique_ptr<AndroidConfig> per_game_config;
|
std::unique_ptr<AndroidConfig> per_game_config;
|
||||||
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
static void ResetFxChainToGlobal() {
|
|
||||||
VideoCore::UseGlobalFxSettings();
|
|
||||||
VideoCore::FxChain::Instance().LoadFromSettings();
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static void ResetFxChainToGlobal() {}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Settings::Setting<T>* getSetting(JNIEnv* env, jstring jkey) {
|
Settings::Setting<T>* getSetting(JNIEnv* env, jstring jkey) {
|
||||||
auto key = Common::Android::GetJString(env, jkey);
|
auto key = Common::Android::GetJString(env, jkey);
|
||||||
@@ -51,7 +39,6 @@ extern "C" {
|
|||||||
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_initializeGlobalConfig(JNIEnv* env, jobject obj) {
|
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_initializeGlobalConfig(JNIEnv* env, jobject obj) {
|
||||||
global_config = std::make_unique<AndroidConfig>();
|
global_config = std::make_unique<AndroidConfig>();
|
||||||
FrontendCommon::GenerateSettings();
|
FrontendCommon::GenerateSettings();
|
||||||
ResetFxChainToGlobal();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_unloadGlobalConfig(JNIEnv* env, jobject obj) {
|
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_unloadGlobalConfig(JNIEnv* env, jobject obj) {
|
||||||
@@ -60,7 +47,6 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_unloadGlobalConfig(JNIEnv* env,
|
|||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_reloadGlobalConfig(JNIEnv* env, jobject obj) {
|
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_reloadGlobalConfig(JNIEnv* env, jobject obj) {
|
||||||
global_config->AndroidConfig::ReloadAllValues();
|
global_config->AndroidConfig::ReloadAllValues();
|
||||||
ResetFxChainToGlobal();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_saveGlobalConfig(JNIEnv* env, jobject obj) {
|
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_saveGlobalConfig(JNIEnv* env, jobject obj) {
|
||||||
|
|||||||
@@ -1,350 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <jni.h>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
#include "common/android/android_common.h"
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
#include "android_config.h"
|
|
||||||
#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"
|
|
||||||
|
|
||||||
extern std::unique_ptr<AndroidConfig> per_game_config;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
bool EditingPerGame() {
|
|
||||||
return per_game_config != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BeginFxEdit() {
|
|
||||||
if (!EditingPerGame()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
VideoCore::UsePerGameFxSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
BeginFxEdit();
|
|
||||||
VideoCore::FxChain::Instance().StoreToSettings();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_reload(JNIEnv* env, jobject obj) {
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
if (!EditingPerGame()) {
|
|
||||||
VideoCore::UseGlobalFxSettings();
|
|
||||||
}
|
|
||||||
VideoCore::FxChain::Instance().LoadFromSettings();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_clearChain(JNIEnv* env, jobject obj) {
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
VideoCore::FxChain::Instance().Clear();
|
|
||||||
#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
|
|
||||||
BeginFxEdit();
|
|
||||||
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
|
|
||||||
BeginFxEdit();
|
|
||||||
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
|
|
||||||
BeginFxEdit();
|
|
||||||
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
|
|
||||||
BeginFxEdit();
|
|
||||||
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
|
|
||||||
BeginFxEdit();
|
|
||||||
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"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="24"
|
|
||||||
android:viewportHeight="24">
|
|
||||||
<path
|
|
||||||
android:fillColor="?attr/colorControlNormal"
|
|
||||||
android:fillType="evenOdd"
|
|
||||||
android:pathData="M8.5,3 L19.4,3 Q21,3 21,4.6 L21,16.5 L19.4,16.5 L19.4,4.6 L8.5,4.6 Z M5,7 L15,7 Q17,7 17,9 L17,19 Q17,21 15,21 L5,21 Q3,21 3,19 L3,9 Q3,7 5,7 Z M5.2,8.6 L14.8,8.6 Q15.4,8.6 15.4,9.2 L15.4,18.8 Q15.4,19.4 14.8,19.4 L5.2,19.4 Q4.6,19.4 4.6,18.8 L4.6,9.2 Q4.6,8.6 5.2,8.6 Z M10,10.9 A3.1,3.1 0 0 1 10,17.1 Z"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<?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>
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
<?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">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:layout_marginTop="4dp"
|
|
||||||
android:baselineAligned="false"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/add_button"
|
|
||||||
style="@style/Widget.Material3.Button.TonalButton"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:minHeight="48dp"
|
|
||||||
android:paddingStart="12dp"
|
|
||||||
android:paddingEnd="12dp"
|
|
||||||
android:text="@string/post_processing_add"
|
|
||||||
app:icon="@drawable/ic_add"
|
|
||||||
app:iconPadding="6dp" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/remove_all_button"
|
|
||||||
style="@style/Widget.Material3.Button.TonalButton"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:minHeight="48dp"
|
|
||||||
android:paddingStart="12dp"
|
|
||||||
android:paddingEnd="12dp"
|
|
||||||
android:text="@string/post_processing_remove_all"
|
|
||||||
android:visibility="gone"
|
|
||||||
app:icon="@drawable/ic_delete"
|
|
||||||
app:iconPadding="6dp" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
<?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>
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
<?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>
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
<?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:orientation="horizontal"
|
|
||||||
android:paddingStart="20dp"
|
|
||||||
android:paddingEnd="20dp"
|
|
||||||
android:paddingTop="8dp"
|
|
||||||
android:paddingBottom="8dp">
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/fx_reset"
|
|
||||||
style="@style/Widget.Material3.Button.TonalButton"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:text="@string/post_processing_reset" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
<?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:orientation="vertical"
|
|
||||||
android:paddingStart="20dp"
|
|
||||||
android:paddingEnd="20dp"
|
|
||||||
android:paddingTop="8dp"
|
|
||||||
android:paddingBottom="4dp">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
|
||||||
android:id="@+id/fx_slider_title"
|
|
||||||
style="@style/TextAppearance.Material3.TitleSmall"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
|
||||||
android:id="@+id/fx_slider_value"
|
|
||||||
style="@style/TextAppearance.Material3.BodySmall"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:textColor="?attr/colorOnSurfaceVariant" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<com.google.android.material.slider.Slider
|
|
||||||
android:id="@+id/fx_slider"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:stepSize="1"
|
|
||||||
android:valueFrom="0"
|
|
||||||
android:valueTo="100" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
<?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:orientation="horizontal">
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/fx_button"
|
|
||||||
style="@style/Widget.Material3.Button.TonalButton"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:maxLines="1" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
<?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/preset_row"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:paddingStart="16dp"
|
|
||||||
android:paddingEnd="8dp"
|
|
||||||
android:paddingTop="12dp"
|
|
||||||
android:paddingBottom="12dp">
|
|
||||||
|
|
||||||
<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_name"
|
|
||||||
style="@style/TextAppearance.Material3.TitleSmall"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
|
||||||
android:id="@+id/preset_description"
|
|
||||||
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/preset_delete"
|
|
||||||
android:layout_width="40dp"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:layout_gravity="center_vertical"
|
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
|
||||||
android:clickable="true"
|
|
||||||
android:contentDescription="@string/post_processing_preset_delete"
|
|
||||||
android:focusable="true"
|
|
||||||
android:padding="8dp"
|
|
||||||
android:src="@drawable/ic_delete"
|
|
||||||
android:visibility="gone"
|
|
||||||
app:tint="?attr/colorOnSurfaceVariant" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
<?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:background="?attr/selectableItemBackground"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:paddingStart="20dp"
|
|
||||||
android:paddingEnd="8dp"
|
|
||||||
android:paddingTop="14dp"
|
|
||||||
android:paddingBottom="14dp">
|
|
||||||
|
|
||||||
<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.TitleMedium"
|
|
||||||
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="4dp"
|
|
||||||
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:background="?attr/selectableItemBackgroundBorderless"
|
|
||||||
android:clickable="true"
|
|
||||||
android:contentDescription="@string/post_processing_remove"
|
|
||||||
android:focusable="true"
|
|
||||||
android:padding="8dp"
|
|
||||||
android:src="@drawable/ic_delete"
|
|
||||||
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:contentDescription=""
|
|
||||||
android:src="@drawable/ic_dropdown_arrow"
|
|
||||||
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>
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
<?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:baselineAligned="false"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/fx_add"
|
|
||||||
style="@style/Widget.Material3.Button.TonalButton"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:minHeight="48dp"
|
|
||||||
android:paddingStart="12dp"
|
|
||||||
android:paddingEnd="12dp"
|
|
||||||
android:text="@string/post_processing_add"
|
|
||||||
app:icon="@drawable/ic_add"
|
|
||||||
app:iconPadding="6dp" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/fx_presets"
|
|
||||||
style="@style/Widget.Material3.Button.TonalButton"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_weight="1.4"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:minHeight="48dp"
|
|
||||||
android:paddingStart="12dp"
|
|
||||||
android:paddingEnd="12dp"
|
|
||||||
android:text="@string/post_processing_presets"
|
|
||||||
app:icon="@drawable/ic_dropdown_arrow"
|
|
||||||
app:iconGravity="textEnd"
|
|
||||||
app:iconPadding="6dp" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/fx_create_preset"
|
|
||||||
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
|
|
||||||
android:layout_width="48dp"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:contentDescription="@string/post_processing_preset_new"
|
|
||||||
app:icon="@drawable/ic_add" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/fx_remove_all"
|
|
||||||
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
|
|
||||||
android:layout_width="48dp"
|
|
||||||
android:layout_height="48dp"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:contentDescription="@string/post_processing_remove_all"
|
|
||||||
app:icon="@drawable/ic_delete" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
@@ -799,6 +799,9 @@
|
|||||||
<string name="theme_mode_light">روشن</string>
|
<string name="theme_mode_light">روشن</string>
|
||||||
<string name="theme_mode_dark">تاریک</string>
|
<string name="theme_mode_dark">تاریک</string>
|
||||||
|
|
||||||
|
<!-- Audio output engines -->
|
||||||
|
<string name="cubeb">cubeb</string>
|
||||||
|
|
||||||
<!-- Anisotropic filtering options -->
|
<!-- Anisotropic filtering options -->
|
||||||
<string name="multiplier_x2">x2</string>
|
<string name="multiplier_x2">x2</string>
|
||||||
<string name="multiplier_x4">x4</string>
|
<string name="multiplier_x4">x4</string>
|
||||||
|
|||||||
@@ -466,11 +466,13 @@
|
|||||||
<string-array name="outputEngineEntries">
|
<string-array name="outputEngineEntries">
|
||||||
<item>@string/auto</item>
|
<item>@string/auto</item>
|
||||||
<item>@string/sdl3</item>
|
<item>@string/sdl3</item>
|
||||||
|
<item>@string/cubeb</item>
|
||||||
<item>@string/string_null</item>
|
<item>@string/string_null</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<integer-array name="outputEngineValues">
|
<integer-array name="outputEngineValues">
|
||||||
<item>0</item>
|
<item>0</item>
|
||||||
<item>2</item>
|
<item>2</item>
|
||||||
|
<item>1</item>
|
||||||
<item>3</item>
|
<item>3</item>
|
||||||
</integer-array>
|
</integer-array>
|
||||||
|
|
||||||
|
|||||||
@@ -298,25 +298,6 @@
|
|||||||
<string name="gpu_driver_fetcher">GPU driver fetcher</string>
|
<string name="gpu_driver_fetcher">GPU driver fetcher</string>
|
||||||
<string name="gpu_driver_manager">GPU driver manager</string>
|
<string name="gpu_driver_manager">GPU driver manager</string>
|
||||||
<string name="install_gpu_driver_description">Install alternative drivers for potentially better performance or accuracy</string>
|
<string name="install_gpu_driver_description">Install alternative drivers for potentially better performance or accuracy</string>
|
||||||
<string name="post_processing">Post-Processing Effects</string>
|
|
||||||
<string name="post_processing_description">ReShade FX effects applied after rendering</string>
|
|
||||||
<string name="post_processing_per_game_description">Configure the effect chain for this game</string>
|
|
||||||
<string name="post_processing_add">Add effect</string>
|
|
||||||
<string name="post_processing_remove">Remove</string>
|
|
||||||
<string name="post_processing_open_list">Open list</string>
|
|
||||||
<string name="post_processing_close_list">Close list</string>
|
|
||||||
<string name="post_processing_remove_all">Remove effects</string>
|
|
||||||
<string name="post_processing_preset_locked">Preset active. Edit it in Post-Processing Effects before starting a game.</string>
|
|
||||||
<string name="post_processing_preset_modified">Values changed from the original preset.</string>
|
|
||||||
<string name="post_processing_presets">Presets</string>
|
|
||||||
<string name="post_processing_preset_new">New preset</string>
|
|
||||||
<string name="post_processing_preset_new_description">Saves the effects you have loaded, with their current values, as a preset you can pick later.</string>
|
|
||||||
<string name="post_processing_preset_name_invalid">Give the preset a name without an equals sign.</string>
|
|
||||||
<string name="post_processing_preset_none">No preset</string>
|
|
||||||
<string name="post_processing_preset_delete">Delete preset</string>
|
|
||||||
<string name="post_processing_preset_reset">Reset preset values</string>
|
|
||||||
<string name="post_processing_reset">Reset to default</string>
|
|
||||||
<string name="post_processing_empty">No effects found. Place .fx files in this folder:</string>
|
|
||||||
<string name="frame_gen">Frame generation</string>
|
<string name="frame_gen">Frame generation</string>
|
||||||
<string name="frame_gen_per_game_description">Configure frame generation for this game</string>
|
<string name="frame_gen_per_game_description">Configure frame generation for this game</string>
|
||||||
<string name="frame_gen_description">Insert interpolated frames between rendered ones using Lossless Scaling. Forces FIFO presentation while enabled.</string>
|
<string name="frame_gen_description">Insert interpolated frames between rendered ones using Lossless Scaling. Forces FIFO presentation while enabled.</string>
|
||||||
@@ -1262,6 +1243,7 @@
|
|||||||
|
|
||||||
<!-- Audio output engines -->
|
<!-- Audio output engines -->
|
||||||
<string name="sdl3" translatable="false">SDL3</string>
|
<string name="sdl3" translatable="false">SDL3</string>
|
||||||
|
<string name="cubeb" translatable="false">cubeb</string>
|
||||||
|
|
||||||
<!-- Anisotropic filtering options -->
|
<!-- Anisotropic filtering options -->
|
||||||
<string name="multiplier_x2" translatable="false">x2</string>
|
<string name="multiplier_x2" translatable="false">x2</string>
|
||||||
@@ -1401,6 +1383,23 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
|
</string>
|
||||||
|
<string name="license_cubeb" translatable="false">cubeb</string>
|
||||||
|
<string name="license_cubeb_description" translatable="false">Cross platform audio library</string>
|
||||||
|
<string name="license_cubeb_link" translatable="false">https://github.com/mozilla/cubeb</string>
|
||||||
|
<string name="license_cubeb_copyright" translatable="false">Copyright © 2011 Mozilla Foundation</string>
|
||||||
|
<string name="license_cubeb_text" translatable="false">
|
||||||
|
Permission to use, copy, modify, and distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.\n\n
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
</string>
|
</string>
|
||||||
<string name="license_dynarmic" translatable="false">Dynarmic</string>
|
<string name="license_dynarmic" translatable="false">Dynarmic</string>
|
||||||
<string name="license_dynarmic_description" translatable="false">An ARM dynamic recompiler</string>
|
<string name="license_dynarmic_description" translatable="false">An ARM dynamic recompiler</string>
|
||||||
|
|||||||
@@ -229,6 +229,15 @@ endif()
|
|||||||
target_include_directories(audio_core PRIVATE ${OPUS_INCLUDE_DIRS})
|
target_include_directories(audio_core PRIVATE ${OPUS_INCLUDE_DIRS})
|
||||||
target_link_libraries(audio_core PUBLIC common core Opus::opus)
|
target_link_libraries(audio_core PUBLIC common core Opus::opus)
|
||||||
|
|
||||||
|
if (ENABLE_CUBEB)
|
||||||
|
target_sources(audio_core PRIVATE
|
||||||
|
sink/cubeb_sink.cpp
|
||||||
|
sink/cubeb_sink.h)
|
||||||
|
|
||||||
|
target_link_libraries(audio_core PRIVATE cubeb::cubeb)
|
||||||
|
target_compile_definitions(audio_core PRIVATE HAVE_CUBEB=1)
|
||||||
|
endif()
|
||||||
|
|
||||||
target_sources(audio_core PRIVATE
|
target_sources(audio_core PRIVATE
|
||||||
sink/sdl3_sink.cpp
|
sink/sdl3_sink.cpp
|
||||||
sink/sdl3_sink.h)
|
sink/sdl3_sink.h)
|
||||||
@@ -236,8 +245,4 @@ target_sources(audio_core PRIVATE
|
|||||||
target_link_libraries(audio_core PRIVATE SDL3::SDL3)
|
target_link_libraries(audio_core PRIVATE SDL3::SDL3)
|
||||||
target_compile_definitions(audio_core PRIVATE HAVE_SDL3)
|
target_compile_definitions(audio_core PRIVATE HAVE_SDL3)
|
||||||
|
|
||||||
if (ANDROID)
|
|
||||||
target_link_libraries(audio_core PRIVATE OpenSLES)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
create_target_directory_groups(audio_core)
|
create_target_directory_groups(audio_core)
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -12,9 +9,7 @@
|
|||||||
namespace AudioCore::Renderer {
|
namespace AudioCore::Renderer {
|
||||||
|
|
||||||
Manager::Manager(Core::System& system_)
|
Manager::Manager(Core::System& system_)
|
||||||
: system{system_}
|
: system{system_}, system_manager{std::make_unique<SystemManager>(system)} {
|
||||||
, system_manager{std::make_unique<SystemManager>(system)}
|
|
||||||
{
|
|
||||||
std::iota(session_ids.begin(), session_ids.end(), 0);
|
std::iota(session_ids.begin(), session_ids.end(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,12 +38,14 @@ Result Manager::GetWorkBufferSize(const AudioRendererParameterInternal& params,
|
|||||||
|
|
||||||
s32 Manager::GetSessionId() {
|
s32 Manager::GetSessionId() {
|
||||||
std::scoped_lock l{session_lock};
|
std::scoped_lock l{session_lock};
|
||||||
ASSERT(session_count <= session_ids.size());
|
auto session_id{session_ids[session_count]};
|
||||||
auto const session_id = session_ids[session_count];
|
|
||||||
if (session_id >= 0) {
|
if (session_id == -1) {
|
||||||
session_ids[session_count] = -1;
|
return -1;
|
||||||
session_count++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
session_ids[session_count] = -1;
|
||||||
|
session_count++;
|
||||||
return session_id;
|
return session_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
#include "audio_core/opus/hardware_opus.h"
|
#include "audio_core/opus/hardware_opus.h"
|
||||||
#include "audio_core/opus/parameters.h"
|
#include "audio_core/opus/parameters.h"
|
||||||
#include "common/alignment.h"
|
#include "common/alignment.h"
|
||||||
#include "common/scope_exit.h"
|
|
||||||
#include "common/swap.h"
|
#include "common/swap.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
|
||||||
@@ -29,18 +28,10 @@ OpusDecoder::OpusDecoder(Core::System& system_, HardwareOpus& hardware_opus_)
|
|||||||
OpusDecoder::~OpusDecoder() {
|
OpusDecoder::~OpusDecoder() {
|
||||||
if (decode_object_initialized) {
|
if (decode_object_initialized) {
|
||||||
hardware_opus.ShutdownDecodeObject(shared_buffer.data(), shared_buffer.size());
|
hardware_opus.ShutdownDecodeObject(shared_buffer.data(), shared_buffer.size());
|
||||||
hardware_opus.UnregisterDecoder(this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result OpusDecoder::Initialize(const OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) {
|
Result OpusDecoder::Initialize(const OpusParametersEx& params, Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) {
|
||||||
R_TRY(hardware_opus.RegisterDecoder(this));
|
|
||||||
SCOPE_EXIT {
|
|
||||||
if (!decode_object_initialized) {
|
|
||||||
hardware_opus.UnregisterDecoder(this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
auto frame_size{params.use_large_frame_size ? 5760 : 1920};
|
auto frame_size{params.use_large_frame_size ? 5760 : 1920};
|
||||||
shared_buffer.resize(transfer_memory_size);
|
shared_buffer.resize(transfer_memory_size);
|
||||||
shared_memory_mapped = true;
|
shared_memory_mapped = true;
|
||||||
@@ -70,13 +61,6 @@ Result OpusDecoder::Initialize(const OpusParametersEx& params, Kernel::KTransfer
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result OpusDecoder::Initialize(const OpusMultiStreamParametersEx& params, Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) {
|
Result OpusDecoder::Initialize(const OpusMultiStreamParametersEx& params, Kernel::KTransferMemory* transfer_memory, u64 transfer_memory_size) {
|
||||||
R_TRY(hardware_opus.RegisterDecoder(this));
|
|
||||||
SCOPE_EXIT {
|
|
||||||
if (!decode_object_initialized) {
|
|
||||||
hardware_opus.UnregisterDecoder(this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
auto frame_size{params.use_large_frame_size ? 5760 : 1920};
|
auto frame_size{params.use_large_frame_size ? 5760 : 1920};
|
||||||
shared_buffer.resize(transfer_memory_size, 0);
|
shared_buffer.resize(transfer_memory_size, 0);
|
||||||
shared_memory_mapped = true;
|
shared_memory_mapped = true;
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
#include "audio_core/audio_core.h"
|
#include "audio_core/audio_core.h"
|
||||||
@@ -46,25 +45,6 @@ HardwareOpus::HardwareOpus(Core::System& system_)
|
|||||||
opus_decoder.SetSharedMemory(shared_memory);
|
opus_decoder.SetSharedMemory(shared_memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result HardwareOpus::RegisterDecoder(OpusDecoder* decoder) {
|
|
||||||
std::scoped_lock l{mutex};
|
|
||||||
const auto slot = std::ranges::find(decoders, nullptr);
|
|
||||||
if (slot == decoders.end()) {
|
|
||||||
R_THROW(ResultOutOfOpusDecoders);
|
|
||||||
}
|
|
||||||
*slot = decoder;
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
void HardwareOpus::UnregisterDecoder(OpusDecoder* decoder) {
|
|
||||||
std::scoped_lock l{mutex};
|
|
||||||
const auto slot = std::ranges::find(decoders, decoder);
|
|
||||||
if (slot == decoders.end()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
*slot = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 HardwareOpus::GetWorkBufferSize(u32 channel) {
|
u32 HardwareOpus::GetWorkBufferSize(u32 channel) {
|
||||||
if (!opus_decoder.IsRunning()) {
|
if (!opus_decoder.IsRunning()) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <opus.h>
|
#include <opus.h>
|
||||||
|
|
||||||
@@ -16,12 +12,9 @@
|
|||||||
#include "core/hle/service/audio/errors.h"
|
#include "core/hle/service/audio/errors.h"
|
||||||
|
|
||||||
namespace AudioCore::OpusDecoder {
|
namespace AudioCore::OpusDecoder {
|
||||||
class OpusDecoder;
|
|
||||||
class HardwareOpus {
|
class HardwareOpus {
|
||||||
public:
|
public:
|
||||||
HardwareOpus(Core::System& system);
|
HardwareOpus(Core::System& system);
|
||||||
Result RegisterDecoder(OpusDecoder* decoder);
|
|
||||||
void UnregisterDecoder(OpusDecoder* decoder);
|
|
||||||
|
|
||||||
u32 GetWorkBufferSize(u32 channel);
|
u32 GetWorkBufferSize(u32 channel);
|
||||||
u32 GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count);
|
u32 GetWorkBufferSizeForMultiStream(u32 total_stream_count, u32 stereo_stream_count);
|
||||||
@@ -46,7 +39,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
std::mutex mutex;
|
std::mutex mutex;
|
||||||
std::array<OpusDecoder*, 24> decoders{};
|
|
||||||
ADSP::OpusDecoder::OpusDecoder& opus_decoder;
|
ADSP::OpusDecoder::OpusDecoder& opus_decoder;
|
||||||
ADSP::OpusDecoder::SharedMemory shared_memory;
|
ADSP::OpusDecoder::SharedMemory shared_memory;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,450 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <span>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "audio_core/common/common.h"
|
||||||
|
#include "audio_core/sink/cubeb_sink.h"
|
||||||
|
#include "audio_core/sink/sink_stream.h"
|
||||||
|
#include "common/logging.h"
|
||||||
|
#include "common/scope_exit.h"
|
||||||
|
#include "core/core.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <objbase.h>
|
||||||
|
#undef CreateEvent
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace AudioCore::Sink {
|
||||||
|
/**
|
||||||
|
* Cubeb sink stream, responsible for sinking samples to hardware.
|
||||||
|
*/
|
||||||
|
class CubebSinkStream final : public SinkStream {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Create a new sink stream.
|
||||||
|
*
|
||||||
|
* @param ctx_ - Cubeb context to create this stream with.
|
||||||
|
* @param device_channels_ - Number of channels supported by the hardware.
|
||||||
|
* @param system_channels_ - Number of channels the audio systems expect.
|
||||||
|
* @param output_device - Cubeb output device id.
|
||||||
|
* @param input_device - Cubeb input device id.
|
||||||
|
* @param name_ - Name of this stream.
|
||||||
|
* @param type_ - Type of this stream.
|
||||||
|
* @param system_ - Core system.
|
||||||
|
* @param event - Event used only for audio renderer, signalled on buffer consume.
|
||||||
|
*/
|
||||||
|
CubebSinkStream(cubeb* ctx_, u32 device_channels_, u32 system_channels_,
|
||||||
|
cubeb_devid output_device, cubeb_devid input_device, const std::string& name_,
|
||||||
|
StreamType type_, Core::System& system_)
|
||||||
|
: SinkStream(system_, type_), ctx{ctx_} {
|
||||||
|
#ifdef _WIN32
|
||||||
|
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
||||||
|
#endif
|
||||||
|
name = name_;
|
||||||
|
device_channels = device_channels_;
|
||||||
|
system_channels = system_channels_;
|
||||||
|
|
||||||
|
cubeb_stream_params params{};
|
||||||
|
params.rate = TargetSampleRate;
|
||||||
|
params.channels = device_channels;
|
||||||
|
params.format = CUBEB_SAMPLE_S16LE;
|
||||||
|
params.prefs = CUBEB_STREAM_PREF_NONE;
|
||||||
|
switch (params.channels) {
|
||||||
|
case 1:
|
||||||
|
params.layout = CUBEB_LAYOUT_MONO;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
params.layout = CUBEB_LAYOUT_STEREO;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
params.layout = CUBEB_LAYOUT_3F2_LFE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 minimum_latency{0};
|
||||||
|
const auto latency_error = cubeb_get_min_latency(ctx, ¶ms, &minimum_latency);
|
||||||
|
if (latency_error != CUBEB_OK) {
|
||||||
|
LOG_CRITICAL(Audio_Sink, "Error getting minimum latency, error: {}", latency_error);
|
||||||
|
minimum_latency = TargetSampleCount * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
minimum_latency = (std::max)(minimum_latency, TargetSampleCount * 2);
|
||||||
|
|
||||||
|
LOG_INFO(Service_Audio,
|
||||||
|
"Opening cubeb stream {} type {} with: rate {} channels {} (system channels {}) "
|
||||||
|
"latency {}",
|
||||||
|
name, type, params.rate, params.channels, system_channels, minimum_latency);
|
||||||
|
|
||||||
|
auto init_error{0};
|
||||||
|
if (type == StreamType::In) {
|
||||||
|
init_error = cubeb_stream_init(ctx, &stream_backend, name.c_str(), input_device,
|
||||||
|
¶ms, output_device, nullptr, minimum_latency,
|
||||||
|
&CubebSinkStream::DataCallback,
|
||||||
|
&CubebSinkStream::StateCallback, this);
|
||||||
|
} else {
|
||||||
|
init_error = cubeb_stream_init(ctx, &stream_backend, name.c_str(), input_device,
|
||||||
|
nullptr, output_device, ¶ms, minimum_latency,
|
||||||
|
&CubebSinkStream::DataCallback,
|
||||||
|
&CubebSinkStream::StateCallback, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (init_error != CUBEB_OK) {
|
||||||
|
LOG_CRITICAL(Audio_Sink, "Error initializing cubeb stream, error: {}", init_error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy the sink stream.
|
||||||
|
*/
|
||||||
|
~CubebSinkStream() override {
|
||||||
|
LOG_DEBUG(Service_Audio, "Destructing cubeb stream {}", name);
|
||||||
|
|
||||||
|
if (!ctx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Finalize();
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
CoUninitialize();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finalize the sink stream.
|
||||||
|
*/
|
||||||
|
void Finalize() override {
|
||||||
|
Stop();
|
||||||
|
cubeb_stream_destroy(stream_backend);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the sink stream.
|
||||||
|
*
|
||||||
|
* @param resume - Set to true if this is resuming the stream a previously-active stream.
|
||||||
|
* Default false.
|
||||||
|
*/
|
||||||
|
void Start(bool resume = false) override {
|
||||||
|
if (!ctx || !paused) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
paused = false;
|
||||||
|
if (cubeb_stream_start(stream_backend) != CUBEB_OK) {
|
||||||
|
LOG_CRITICAL(Audio_Sink, "Error starting cubeb stream");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop the sink stream.
|
||||||
|
*/
|
||||||
|
void Stop() override {
|
||||||
|
if (!ctx || paused) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SignalPause();
|
||||||
|
if (cubeb_stream_stop(stream_backend) != CUBEB_OK) {
|
||||||
|
LOG_CRITICAL(Audio_Sink, "Error stopping cubeb stream");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Main callback from Cubeb. Either expects samples from us (audio render/audio out), or will
|
||||||
|
* provide samples to be copied (audio in).
|
||||||
|
*
|
||||||
|
* @param stream - Cubeb-specific data about the stream.
|
||||||
|
* @param user_data - Custom data pointer passed along, points to a CubebSinkStream.
|
||||||
|
* @param in_buff - Input buffer to be used if the stream is an input type.
|
||||||
|
* @param out_buff - Output buffer to be used if the stream is an output type.
|
||||||
|
* @param num_frames_ - Number of frames of audio in the buffers. Note: Not number of samples.
|
||||||
|
*/
|
||||||
|
static long DataCallback([[maybe_unused]] cubeb_stream* stream, void* user_data,
|
||||||
|
[[maybe_unused]] const void* in_buff, void* out_buff,
|
||||||
|
long num_frames_) {
|
||||||
|
auto* impl = static_cast<CubebSinkStream*>(user_data);
|
||||||
|
if (!impl) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t num_channels = impl->GetDeviceChannels();
|
||||||
|
const std::size_t frame_size = num_channels;
|
||||||
|
const std::size_t num_frames{static_cast<size_t>(num_frames_)};
|
||||||
|
|
||||||
|
if (impl->type == StreamType::In) {
|
||||||
|
std::span<const s16> input_buffer{reinterpret_cast<const s16*>(in_buff),
|
||||||
|
num_frames * frame_size};
|
||||||
|
impl->ProcessAudioIn(input_buffer, num_frames);
|
||||||
|
} else {
|
||||||
|
std::span<s16> output_buffer{reinterpret_cast<s16*>(out_buff), num_frames * frame_size};
|
||||||
|
impl->ProcessAudioOutAndRender(output_buffer, num_frames);
|
||||||
|
}
|
||||||
|
|
||||||
|
return num_frames_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cubeb callback for if a device state changes. Unused currently.
|
||||||
|
*
|
||||||
|
* @param stream - Cubeb-specific data about the stream.
|
||||||
|
* @param user_data - Custom data pointer passed along, points to a CubebSinkStream.
|
||||||
|
* @param state - New state of the device.
|
||||||
|
*/
|
||||||
|
static void StateCallback(cubeb_stream*, void*, cubeb_state) {}
|
||||||
|
|
||||||
|
/// Main Cubeb context
|
||||||
|
cubeb* ctx{};
|
||||||
|
/// Cubeb stream backend
|
||||||
|
cubeb_stream* stream_backend{};
|
||||||
|
};
|
||||||
|
|
||||||
|
CubebSink::CubebSink(std::string_view target_device_name) {
|
||||||
|
// Cubeb requires COM to be initialized on the thread calling cubeb_init on Windows
|
||||||
|
#ifdef _WIN32
|
||||||
|
com_init_result = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (cubeb_init(&ctx, "Eden", nullptr) != CUBEB_OK) {
|
||||||
|
LOG_CRITICAL(Audio_Sink, "cubeb_init failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target_device_name != auto_device_name && !target_device_name.empty()) {
|
||||||
|
cubeb_device_collection collection;
|
||||||
|
if (cubeb_enumerate_devices(ctx, CUBEB_DEVICE_TYPE_OUTPUT, &collection) != CUBEB_OK) {
|
||||||
|
LOG_WARNING(Audio_Sink, "Audio output device enumeration not supported");
|
||||||
|
} else {
|
||||||
|
const auto collection_end{collection.device + collection.count};
|
||||||
|
const auto device{
|
||||||
|
std::find_if(collection.device, collection_end, [&](const cubeb_device_info& info) {
|
||||||
|
return info.friendly_name != nullptr &&
|
||||||
|
target_device_name == std::string(info.friendly_name);
|
||||||
|
})};
|
||||||
|
if (device != collection_end) {
|
||||||
|
output_device = device->devid;
|
||||||
|
}
|
||||||
|
cubeb_device_collection_destroy(ctx, &collection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cubeb_get_max_channel_count(ctx, &device_channels);
|
||||||
|
device_channels = device_channels >= 6U ? 6U : 2U;
|
||||||
|
}
|
||||||
|
|
||||||
|
CubebSink::~CubebSink() {
|
||||||
|
if (!ctx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& sink_stream : sink_streams) {
|
||||||
|
sink_stream.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
cubeb_destroy(ctx);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (SUCCEEDED(com_init_result)) {
|
||||||
|
CoUninitialize();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
SinkStream* CubebSink::AcquireSinkStream(Core::System& system, u32 system_channels_,
|
||||||
|
const std::string& name, StreamType type) {
|
||||||
|
system_channels = system_channels_;
|
||||||
|
SinkStreamPtr& stream = sink_streams.emplace_back(std::make_unique<CubebSinkStream>(
|
||||||
|
ctx, device_channels, system_channels, output_device, input_device, name, type, system));
|
||||||
|
|
||||||
|
return stream.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CubebSink::CloseStream(SinkStream* stream) {
|
||||||
|
for (size_t i = 0; i < sink_streams.size(); i++) {
|
||||||
|
if (sink_streams[i].get() == stream) {
|
||||||
|
sink_streams[i].reset();
|
||||||
|
sink_streams.erase(sink_streams.begin() + i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CubebSink::CloseStreams() {
|
||||||
|
sink_streams.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
f32 CubebSink::GetDeviceVolume() const {
|
||||||
|
if (sink_streams.empty()) {
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sink_streams[0]->GetDeviceVolume();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CubebSink::SetDeviceVolume(f32 volume) {
|
||||||
|
for (auto& stream : sink_streams) {
|
||||||
|
stream->SetDeviceVolume(volume);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CubebSink::SetSystemVolume(f32 volume) {
|
||||||
|
for (auto& stream : sink_streams) {
|
||||||
|
stream->SetSystemVolume(volume);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> ListCubebSinkDevices(bool capture) {
|
||||||
|
std::vector<std::string> device_list;
|
||||||
|
cubeb* ctx;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
auto com_init_result = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (cubeb_init(&ctx, "Eden Device Enumerator", nullptr) != CUBEB_OK) {
|
||||||
|
LOG_CRITICAL(Audio_Sink, "cubeb_init failed");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (SUCCEEDED(com_init_result)) {
|
||||||
|
CoUninitialize();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
auto type{capture ? CUBEB_DEVICE_TYPE_INPUT : CUBEB_DEVICE_TYPE_OUTPUT};
|
||||||
|
cubeb_device_collection collection;
|
||||||
|
if (cubeb_enumerate_devices(ctx, type, &collection) != CUBEB_OK) {
|
||||||
|
LOG_WARNING(Audio_Sink, "Audio output device enumeration not supported");
|
||||||
|
} else {
|
||||||
|
for (std::size_t i = 0; i < collection.count; i++) {
|
||||||
|
const cubeb_device_info& device = collection.device[i];
|
||||||
|
if (device.friendly_name && device.friendly_name[0] != '\0' &&
|
||||||
|
device.state == CUBEB_DEVICE_STATE_ENABLED) {
|
||||||
|
device_list.emplace_back(device.friendly_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cubeb_device_collection_destroy(ctx, &collection);
|
||||||
|
}
|
||||||
|
|
||||||
|
cubeb_destroy(ctx);
|
||||||
|
return device_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* REVERSION TO 3833 - function GetCubebLatency REINTRODUCED FROM 3833 - DIABLO 3 FIX */
|
||||||
|
u32 GetCubebLatency() {
|
||||||
|
cubeb* ctx;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
auto com_init_result = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Init cubeb
|
||||||
|
if (cubeb_init(&ctx, "yuzu Latency Getter", nullptr) != CUBEB_OK) {
|
||||||
|
LOG_CRITICAL(Audio_Sink, "cubeb_init failed");
|
||||||
|
// Return a large latency so we choose SDL instead.
|
||||||
|
return 10000u;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (SUCCEEDED(com_init_result)) {
|
||||||
|
CoUninitialize();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Get min latency
|
||||||
|
cubeb_stream_params params{};
|
||||||
|
params.rate = TargetSampleRate;
|
||||||
|
params.channels = 2;
|
||||||
|
params.format = CUBEB_SAMPLE_S16LE;
|
||||||
|
params.prefs = CUBEB_STREAM_PREF_NONE;
|
||||||
|
params.layout = CUBEB_LAYOUT_STEREO;
|
||||||
|
|
||||||
|
u32 latency{0};
|
||||||
|
const auto latency_error = cubeb_get_min_latency(ctx, ¶ms, &latency);
|
||||||
|
if (latency_error != CUBEB_OK) {
|
||||||
|
LOG_CRITICAL(Audio_Sink, "Error getting minimum latency, error: {}", latency_error);
|
||||||
|
latency = TargetSampleCount * 2;
|
||||||
|
}
|
||||||
|
latency = (std::max)(latency, TargetSampleCount * 2);
|
||||||
|
cubeb_destroy(ctx);
|
||||||
|
return latency;
|
||||||
|
}
|
||||||
|
|
||||||
|
// REVERTED back to 3833 - Below namespace section and function IsCubebSuitable() removed, reverting to GetCubebLatency() above. - DIABLO 3 FIX
|
||||||
|
/*
|
||||||
|
namespace {
|
||||||
|
static long TmpDataCallback(cubeb_stream*, void*, const void*, void*, long) {
|
||||||
|
return TargetSampleCount;
|
||||||
|
}
|
||||||
|
static void TmpStateCallback(cubeb_stream*, void*, cubeb_state) {}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
bool IsCubebSuitable() {
|
||||||
|
#if !defined(HAVE_CUBEB)
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
cubeb* ctx{nullptr};
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
auto com_init_result = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Init cubeb
|
||||||
|
if (cubeb_init(&ctx, "Eden Latency Getter", nullptr) != CUBEB_OK) {
|
||||||
|
LOG_ERROR(Audio_Sink, "Cubeb failed to init, it is not suitable.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SCOPE_EXIT {
|
||||||
|
cubeb_destroy(ctx);
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (SUCCEEDED(com_init_result)) {
|
||||||
|
CoUninitialize();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Get min latency
|
||||||
|
cubeb_stream_params params{};
|
||||||
|
params.rate = TargetSampleRate;
|
||||||
|
params.channels = 2;
|
||||||
|
params.format = CUBEB_SAMPLE_S16LE;
|
||||||
|
params.prefs = CUBEB_STREAM_PREF_NONE;
|
||||||
|
params.layout = CUBEB_LAYOUT_STEREO;
|
||||||
|
|
||||||
|
u32 latency{0};
|
||||||
|
const auto latency_error = cubeb_get_min_latency(ctx, ¶ms, &latency);
|
||||||
|
if (latency_error != CUBEB_OK) {
|
||||||
|
LOG_ERROR(Audio_Sink, "Cubeb could not get min latency, it is not suitable.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
latency = (std::max)(latency, TargetSampleCount * 2);
|
||||||
|
|
||||||
|
// Test opening a device with standard parameters
|
||||||
|
cubeb_devid output_device{0};
|
||||||
|
cubeb_devid input_device{0};
|
||||||
|
std::string name{"Eden test"};
|
||||||
|
cubeb_stream* stream{nullptr};
|
||||||
|
|
||||||
|
if (cubeb_stream_init(ctx, &stream, name.c_str(), input_device, nullptr, output_device, ¶ms,
|
||||||
|
latency, &TmpDataCallback, &TmpStateCallback, nullptr) != CUBEB_OK) {
|
||||||
|
LOG_CRITICAL(Audio_Sink, "Cubeb could not open a device, it is not suitable.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cubeb_stream_stop(stream);
|
||||||
|
cubeb_stream_destroy(stream);
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
} // namespace AudioCore::Sink
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <cubeb/cubeb.h>
|
||||||
|
|
||||||
|
#include "audio_core/sink/sink.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace AudioCore::Sink {
|
||||||
|
class SinkStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cubeb backend sink, holds multiple output streams and is responsible for sinking samples to
|
||||||
|
* hardware. Used by Audio Render, Audio In and Audio Out.
|
||||||
|
*/
|
||||||
|
class CubebSink final : public Sink {
|
||||||
|
public:
|
||||||
|
explicit CubebSink(std::string_view device_id);
|
||||||
|
~CubebSink() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new sink stream.
|
||||||
|
*
|
||||||
|
* @param system - Core system.
|
||||||
|
* @param system_channels - Number of channels the audio system expects.
|
||||||
|
* May differ from the device's channel count.
|
||||||
|
* @param name - Name of this stream.
|
||||||
|
* @param type - Type of this stream, render/in/out.
|
||||||
|
*
|
||||||
|
* @return A pointer to the created SinkStream
|
||||||
|
*/
|
||||||
|
SinkStream* AcquireSinkStream(Core::System& system, u32 system_channels,
|
||||||
|
const std::string& name, StreamType type) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close a given stream.
|
||||||
|
*
|
||||||
|
* @param stream - The stream to close.
|
||||||
|
*/
|
||||||
|
void CloseStream(SinkStream* stream) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close all streams.
|
||||||
|
*/
|
||||||
|
void CloseStreams() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the device volume. Set from calls to the IAudioDevice service.
|
||||||
|
*
|
||||||
|
* @return Volume of the device.
|
||||||
|
*/
|
||||||
|
f32 GetDeviceVolume() const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the device volume. Set from calls to the IAudioDevice service.
|
||||||
|
*
|
||||||
|
* @param volume - New volume of the device.
|
||||||
|
*/
|
||||||
|
void SetDeviceVolume(f32 volume) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the system volume. Comes from the audio system using this stream.
|
||||||
|
*
|
||||||
|
* @param volume - New volume of the system.
|
||||||
|
*/
|
||||||
|
void SetSystemVolume(f32 volume) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// Backend Cubeb context
|
||||||
|
cubeb* ctx{};
|
||||||
|
/// Cubeb id of the actual hardware output device
|
||||||
|
cubeb_devid output_device{};
|
||||||
|
/// Cubeb id of the actual hardware input device
|
||||||
|
cubeb_devid input_device{};
|
||||||
|
/// Vector of streams managed by this sink
|
||||||
|
std::vector<SinkStreamPtr> sink_streams{};
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
/// Cubeb required COM to be initialized multi-threaded on Windows
|
||||||
|
u32 com_init_result = 0;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of connected devices from Cubeb.
|
||||||
|
*
|
||||||
|
* @param capture - Return input (capture) devices if true, otherwise output devices.
|
||||||
|
*/
|
||||||
|
std::vector<std::string> ListCubebSinkDevices(bool capture);
|
||||||
|
|
||||||
|
// REVERSION - function GetCubebLatency() reintroduced from EA-3833 - DIABLO 3 FIX
|
||||||
|
/**
|
||||||
|
* Get the reported latency for this sink.
|
||||||
|
*
|
||||||
|
* @return Minimum latency for this sink.
|
||||||
|
*/
|
||||||
|
u32 GetCubebLatency();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this backend is suitable for use.
|
||||||
|
* Checks if enabled, its latency, whether it opens successfully, etc.
|
||||||
|
*
|
||||||
|
* @return True is this backend is suitable, false otherwise.
|
||||||
|
*/
|
||||||
|
// bool IsCubebSuitable(); // REVERTED BACK TO GetCubebLatency() FROM 3833
|
||||||
|
|
||||||
|
} // namespace AudioCore::Sink
|
||||||
@@ -25,22 +25,13 @@ namespace {
|
|||||||
// See https://github.com/PCSX2/pcsx2/pull/12312
|
// See https://github.com/PCSX2/pcsx2/pull/12312
|
||||||
// "SDL and cubeb backends previously resulted in different names for the output which
|
// "SDL and cubeb backends previously resulted in different names for the output which
|
||||||
// caused them be identified as different applications by the OS."
|
// caused them be identified as different applications by the OS."
|
||||||
|
//
|
||||||
|
// Keep in sync with cubeb_sink.cpp name.
|
||||||
SDL_SetHint("SDL_AUDIO_DEVICE_APP_NAME", "yuzu Latency Getter");
|
SDL_SetHint("SDL_AUDIO_DEVICE_APP_NAME", "yuzu Latency Getter");
|
||||||
SDL_SetHint("SDL_HINT_AUDIO_DEVICE_STREAM_ROLE", "Game");
|
|
||||||
// We do our own processing, so just have SDL copy our audio
|
|
||||||
SDL_SetHint("SDL_HINT_AUDIO_DEVICE_RAW_STREAM", "1");
|
|
||||||
#ifdef __ANDROID__
|
|
||||||
SDL_SetHintWithPriority(SDL_HINT_AUDIO_DRIVER, "openslES", SDL_HINT_OVERRIDE);
|
|
||||||
if (!SDL_InitSubSystem(SDL_INIT_AUDIO)) {
|
if (!SDL_InitSubSystem(SDL_INIT_AUDIO)) {
|
||||||
LOG_WARNING(Audio_Sink, "OpenSL ES audio initialization failed: {}; retrying default drivers", SDL_GetError());
|
|
||||||
SDL_ResetHint(SDL_HINT_AUDIO_DRIVER);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (!SDL_WasInit(SDL_INIT_AUDIO) && !SDL_InitSubSystem(SDL_INIT_AUDIO)) {
|
|
||||||
LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem audio failed: {}", SDL_GetError());
|
LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem audio failed: {}", SDL_GetError());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
LOG_INFO(Audio_Sink, "SDL audio driver: {}", SDL_GetCurrentAudioDriver());
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -91,18 +82,23 @@ public:
|
|||||||
|
|
||||||
SDL_AudioSpec spec{};
|
SDL_AudioSpec spec{};
|
||||||
spec.freq = TargetSampleRate;
|
spec.freq = TargetSampleRate;
|
||||||
spec.channels = u8(device_channels);
|
spec.channels = static_cast<u8>(device_channels);
|
||||||
spec.format = SDL_AUDIO_S16LE;
|
spec.format = SDL_AUDIO_S16;
|
||||||
|
|
||||||
auto const is_capture = (type == StreamType::In);
|
std::string device_name{output_device};
|
||||||
std::string device_name = is_capture ? input_device : output_device;
|
bool capture{false};
|
||||||
const SDL_AudioDeviceID audio_device = device_name.empty()
|
if (type == StreamType::In) {
|
||||||
? (is_capture
|
device_name = input_device;
|
||||||
? SDL_AUDIO_DEVICE_DEFAULT_RECORDING
|
capture = true;
|
||||||
: SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK)
|
}
|
||||||
: FindAudioDeviceByName(device_name, is_capture);
|
|
||||||
|
|
||||||
stream = SDL_OpenAudioDeviceStream(audio_device, &spec, &SDLSinkStream::DataCallback, this);
|
const SDL_AudioDeviceID audio_device =
|
||||||
|
device_name.empty() ? (capture ? SDL_AUDIO_DEVICE_DEFAULT_RECORDING
|
||||||
|
: SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK)
|
||||||
|
: FindAudioDeviceByName(device_name, capture);
|
||||||
|
|
||||||
|
stream = SDL_OpenAudioDeviceStream(audio_device, &spec, &SDLSinkStream::DataCallback,
|
||||||
|
this);
|
||||||
|
|
||||||
if (stream == nullptr) {
|
if (stream == nullptr) {
|
||||||
LOG_CRITICAL(Audio_Sink, "Error opening SDL audio device: {}", SDL_GetError());
|
LOG_CRITICAL(Audio_Sink, "Error opening SDL audio device: {}", SDL_GetError());
|
||||||
@@ -111,12 +107,13 @@ public:
|
|||||||
|
|
||||||
SDL_AudioSpec stream_in{};
|
SDL_AudioSpec stream_in{};
|
||||||
SDL_AudioSpec stream_out{};
|
SDL_AudioSpec stream_out{};
|
||||||
void(SDL_GetAudioStreamFormat(stream, &stream_in, &stream_out));
|
static_cast<void>(SDL_GetAudioStreamFormat(stream, &stream_in, &stream_out));
|
||||||
|
|
||||||
LOG_INFO(Service_Audio,
|
LOG_INFO(Service_Audio,
|
||||||
"Opening SDL stream {} with: rate {} channels {} (system channels {}) "
|
"Opening SDL stream {} with: rate {} channels {} (system channels {}) "
|
||||||
" format {}",
|
" format {}",
|
||||||
static_cast<const void*>(stream), stream_out.freq, stream_out.channels,
|
static_cast<const void*>(stream), stream_out.freq, stream_out.channels,
|
||||||
system_channels, int(stream_out.format));
|
system_channels, static_cast<int>(stream_out.format));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -131,12 +128,14 @@ public:
|
|||||||
* Finalize the sink stream.
|
* Finalize the sink stream.
|
||||||
*/
|
*/
|
||||||
void Finalize() override {
|
void Finalize() override {
|
||||||
if (stream != nullptr) {
|
if (stream == nullptr) {
|
||||||
Stop();
|
return;
|
||||||
SDL_ClearAudioStream(stream);
|
|
||||||
SDL_DestroyAudioStream(stream);
|
|
||||||
stream = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Stop();
|
||||||
|
SDL_ClearAudioStream(stream);
|
||||||
|
SDL_DestroyAudioStream(stream);
|
||||||
|
stream = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -149,8 +148,9 @@ public:
|
|||||||
if (stream == nullptr || !paused) {
|
if (stream == nullptr || !paused) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
paused = false;
|
paused = false;
|
||||||
void(SDL_ResumeAudioStreamDevice(stream));
|
static_cast<void>(SDL_ResumeAudioStreamDevice(stream));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -161,7 +161,7 @@ public:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SignalPause();
|
SignalPause();
|
||||||
void(SDL_PauseAudioStreamDevice(stream));
|
static_cast<void>(SDL_PauseAudioStreamDevice(stream));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -173,34 +173,51 @@ private:
|
|||||||
* @param stream - Buffer of samples to be filled or read.
|
* @param stream - Buffer of samples to be filled or read.
|
||||||
* @param len - Length of the stream in bytes.
|
* @param len - Length of the stream in bytes.
|
||||||
*/
|
*/
|
||||||
static void DataCallback(void* userdata, SDL_AudioStream* stream, int additional_amount, int total_amount) {
|
static void DataCallback(void* userdata, SDL_AudioStream* stream, int additional_amount,
|
||||||
if (auto* impl = static_cast<SDLSinkStream*>(userdata); impl) {
|
int total_amount) {
|
||||||
auto const num_channels = impl->GetDeviceChannels();
|
auto* impl = static_cast<SDLSinkStream*>(userdata);
|
||||||
auto const frame_size = num_channels;
|
|
||||||
if (impl->type == StreamType::In) {
|
if (!impl) {
|
||||||
auto const bytes_available = SDL_GetAudioStreamAvailable(stream);
|
return;
|
||||||
if (bytes_available > 0) {
|
}
|
||||||
std::vector<s16> input(bytes_available / int(sizeof(s16)));
|
|
||||||
auto const bytes_read = SDL_GetAudioStreamData(stream, input.data(), bytes_available);
|
const std::size_t num_channels = impl->GetDeviceChannels();
|
||||||
if (bytes_read > 0) {
|
const std::size_t frame_size = num_channels;
|
||||||
auto const num_frames = std::size_t(bytes_read) / sizeof(s16) / frame_size;
|
|
||||||
std::span<const s16> input_buffer{input.data(), std::size_t(bytes_read) / sizeof(s16)};
|
if (impl->type == StreamType::In) {
|
||||||
impl->ProcessAudioIn(input_buffer, num_frames);
|
const int bytes_available = SDL_GetAudioStreamAvailable(stream);
|
||||||
}
|
if (bytes_available <= 0) {
|
||||||
}
|
return;
|
||||||
} else if (additional_amount > 0 || total_amount > 0) {
|
|
||||||
auto const bytes_requested = additional_amount > 0 ? additional_amount : total_amount;
|
|
||||||
std::vector<s16> output(bytes_requested / int(sizeof(s16)));
|
|
||||||
auto const num_frames = std::size_t(bytes_requested) / sizeof(s16) / frame_size;
|
|
||||||
std::span<s16> output_buffer{output.data(), output.size()};
|
|
||||||
impl->ProcessAudioOutAndRender(output_buffer, num_frames);
|
|
||||||
void(SDL_PutAudioStreamData(stream, output.data(), bytes_requested));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<s16> input(bytes_available / static_cast<int>(sizeof(s16)));
|
||||||
|
const int bytes_read = SDL_GetAudioStreamData(stream, input.data(), bytes_available);
|
||||||
|
if (bytes_read <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::size_t num_frames =
|
||||||
|
static_cast<std::size_t>(bytes_read) / sizeof(s16) / frame_size;
|
||||||
|
std::span<const s16> input_buffer{input.data(),
|
||||||
|
static_cast<std::size_t>(bytes_read) / sizeof(s16)};
|
||||||
|
impl->ProcessAudioIn(input_buffer, num_frames);
|
||||||
|
} else {
|
||||||
|
if (additional_amount <= 0 && total_amount <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int bytes_requested = additional_amount > 0 ? additional_amount : total_amount;
|
||||||
|
std::vector<s16> output(bytes_requested / static_cast<int>(sizeof(s16)));
|
||||||
|
const std::size_t num_frames =
|
||||||
|
static_cast<std::size_t>(bytes_requested) / sizeof(s16) / frame_size;
|
||||||
|
std::span<s16> output_buffer{output.data(), output.size()};
|
||||||
|
impl->ProcessAudioOutAndRender(output_buffer, num_frames);
|
||||||
|
static_cast<void>(SDL_PutAudioStreamData(stream, output.data(), bytes_requested));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SDL stream attached to an opened input/output device
|
/// SDL stream attached to an opened input/output device
|
||||||
SDL_AudioStream* stream = nullptr;
|
SDL_AudioStream* stream{};
|
||||||
};
|
};
|
||||||
|
|
||||||
SDLSink::SDLSink(std::string_view target_device_name) {
|
SDLSink::SDLSink(std::string_view target_device_name) {
|
||||||
@@ -216,9 +233,11 @@ SDLSink::SDLSink(std::string_view target_device_name) {
|
|||||||
|
|
||||||
SDLSink::~SDLSink() = default;
|
SDLSink::~SDLSink() = default;
|
||||||
|
|
||||||
SinkStream* SDLSink::AcquireSinkStream(Core::System& system, u32 system_channels_, const std::string&, StreamType type) {
|
SinkStream* SDLSink::AcquireSinkStream(Core::System& system, u32 system_channels_,
|
||||||
|
const std::string&, StreamType type) {
|
||||||
system_channels = system_channels_;
|
system_channels = system_channels_;
|
||||||
SinkStreamPtr& stream = sink_streams.emplace_back(std::make_unique<SDLSinkStream>(device_channels, system_channels, output_device, input_device, type, system));
|
SinkStreamPtr& stream = sink_streams.emplace_back(std::make_unique<SDLSinkStream>(
|
||||||
|
device_channels, system_channels, output_device, input_device, type, system));
|
||||||
return stream.get();
|
return stream.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,7 +256,11 @@ void SDLSink::CloseStreams() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
f32 SDLSink::GetDeviceVolume() const {
|
f32 SDLSink::GetDeviceVolume() const {
|
||||||
return sink_streams.empty() ? 1.0f : sink_streams[0]->GetDeviceVolume();
|
if (sink_streams.empty()) {
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sink_streams[0]->GetDeviceVolume();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDLSink::SetDeviceVolume(f32 volume) {
|
void SDLSink::SetDeviceVolume(f32 volume) {
|
||||||
@@ -252,21 +275,68 @@ void SDLSink::SetSystemVolume(f32 volume) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> ListSDLSinkDevices(bool is_capture) {
|
std::vector<std::string> ListSDLSinkDevices(bool capture) {
|
||||||
std::vector<std::string> device_list{};
|
if (!InitializeAudio())
|
||||||
if (InitializeAudio()) {
|
return {}; //no devices
|
||||||
int device_count = 0;
|
|
||||||
SDL_AudioDeviceID* devices = is_capture ? SDL_GetAudioRecordingDevices(&device_count) : SDL_GetAudioPlaybackDevices(&device_count);
|
std::vector<std::string> device_list;
|
||||||
if (devices != nullptr) {
|
int device_count = 0;
|
||||||
for (int i = 0; i < device_count; ++i) {
|
SDL_AudioDeviceID* devices =
|
||||||
if (const char* name = SDL_GetAudioDeviceName(devices[i]); name) {
|
capture ? SDL_GetAudioRecordingDevices(&device_count)
|
||||||
device_list.emplace_back(name);
|
: SDL_GetAudioPlaybackDevices(&device_count);
|
||||||
}
|
if (devices == nullptr) {
|
||||||
}
|
return device_list;
|
||||||
SDL_free(devices);
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < device_count; ++i) {
|
||||||
|
if (const char* name = SDL_GetAudioDeviceName(devices[i])) {
|
||||||
|
device_list.emplace_back(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
SDL_free(devices);
|
||||||
|
|
||||||
return device_list;
|
return device_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* REVERSION to 3833 - function GetSDLLatency() REINTRODUCED FROM 3833 - DIABLO 3 FIX */
|
||||||
|
u32 GetSDLLatency() {
|
||||||
|
return TargetSampleCount * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// REVERTED back to 3833 - Below function IsSDLSuitable() removed, reverting to GetSDLLatency() above. - DIABLO 3 FIX
|
||||||
|
/*
|
||||||
|
bool IsSDLSuitable() {
|
||||||
|
#if !defined(HAVE_SDL3)
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
// Check SDL can init
|
||||||
|
if (!InitializeAudio()!
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// We can set any latency frequency we want with SDL, so no need to check that.
|
||||||
|
|
||||||
|
// Check we can open a device with standard parameters
|
||||||
|
SDL_AudioSpec spec;
|
||||||
|
spec.freq = TargetSampleRate;
|
||||||
|
spec.channels = 2u;
|
||||||
|
spec.format = AUDIO_S16SYS;
|
||||||
|
spec.samples = TargetSampleCount * 2;
|
||||||
|
spec.callback = nullptr;
|
||||||
|
spec.userdata = nullptr;
|
||||||
|
|
||||||
|
SDL_AudioSpec obtained;
|
||||||
|
auto device = SDL_OpenAudioDevice(nullptr, false, &spec, &obtained, false);
|
||||||
|
|
||||||
|
if (device == 0) {
|
||||||
|
LOG_ERROR(Audio_Sink, "SDL failed to open a device, it is not suitable. Error: {}",
|
||||||
|
SDL_GetError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_CloseAudioDevice(device);
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
} // namespace AudioCore::Sink
|
} // namespace AudioCore::Sink
|
||||||
|
|||||||
@@ -90,4 +90,20 @@ private:
|
|||||||
*/
|
*/
|
||||||
std::vector<std::string> ListSDLSinkDevices(bool capture);
|
std::vector<std::string> ListSDLSinkDevices(bool capture);
|
||||||
|
|
||||||
|
// REVERSION - function GetSDLLatency() reintroduced from EA-3833 - DIABLO 3 FIX
|
||||||
|
/**
|
||||||
|
* Get the reported latency for this sink.
|
||||||
|
*
|
||||||
|
* @return Minimum latency for this sink.
|
||||||
|
*/
|
||||||
|
u32 GetSDLLatency();
|
||||||
|
|
||||||
|
/** REVERTED back to 3833 - Below function IsSDLSuitable() removed, reverting to GetSDLLatency() above. - DIABLO 3 FIX
|
||||||
|
* Check if this backend is suitable for use.
|
||||||
|
* Checks if enabled, its latency, whether it opens successfully, etc.
|
||||||
|
*
|
||||||
|
* @return True is this backend is suitable, false otherwise.
|
||||||
|
*/
|
||||||
|
//bool IsSDLSuitable(); // REVERTED for GetSDLLatency() from EA-3833
|
||||||
|
|
||||||
} // namespace AudioCore::Sink
|
} // namespace AudioCore::Sink
|
||||||
|
|||||||
@@ -10,6 +10,9 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "audio_core/sink/sink_details.h"
|
#include "audio_core/sink/sink_details.h"
|
||||||
|
#ifdef HAVE_CUBEB
|
||||||
|
#include "audio_core/sink/cubeb_sink.h"
|
||||||
|
#endif
|
||||||
#ifdef HAVE_SDL3
|
#ifdef HAVE_SDL3
|
||||||
#include "audio_core/sink/sdl3_sink.h"
|
#include "audio_core/sink/sdl3_sink.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -31,10 +34,24 @@ struct SinkDetails {
|
|||||||
FactoryFn factory;
|
FactoryFn factory;
|
||||||
/// A method to call to list available devices.
|
/// A method to call to list available devices.
|
||||||
ListDevicesFn list_devices;
|
ListDevicesFn list_devices;
|
||||||
|
/// Method to get the latency of this backend - REINTRODUCED FROM 3833 - DIABLO 3 FIX
|
||||||
|
LatencyFn latency;
|
||||||
|
/// Check whether this backend is suitable to be used.
|
||||||
|
/// SuitableFn is_suitable; // REVERTED FOR LatencyFn latency ABOVE - DIABLO 3 FIX
|
||||||
};
|
};
|
||||||
|
|
||||||
// sink_details is ordered in terms of desirability, with the best choice at the top.
|
// sink_details is ordered in terms of desirability, with the best choice at the top.
|
||||||
static constexpr SinkDetails sink_details[] = {
|
constexpr SinkDetails sink_details[] = {
|
||||||
|
#ifdef HAVE_CUBEB
|
||||||
|
SinkDetails{
|
||||||
|
Settings::AudioEngine::Cubeb,
|
||||||
|
[](std::string_view device_id) -> std::unique_ptr<Sink> {
|
||||||
|
return std::make_unique<CubebSink>(device_id);
|
||||||
|
},
|
||||||
|
&ListCubebSinkDevices,
|
||||||
|
&GetCubebLatency,
|
||||||
|
},
|
||||||
|
#endif
|
||||||
#ifdef HAVE_SDL3
|
#ifdef HAVE_SDL3
|
||||||
SinkDetails{
|
SinkDetails{
|
||||||
Settings::AudioEngine::Sdl3,
|
Settings::AudioEngine::Sdl3,
|
||||||
@@ -42,6 +59,7 @@ static constexpr SinkDetails sink_details[] = {
|
|||||||
return std::make_unique<SDLSink>(device_id);
|
return std::make_unique<SDLSink>(device_id);
|
||||||
},
|
},
|
||||||
&ListSDLSinkDevices,
|
&ListSDLSinkDevices,
|
||||||
|
&GetSDLLatency,
|
||||||
},
|
},
|
||||||
#endif
|
#endif
|
||||||
SinkDetails{
|
SinkDetails{
|
||||||
@@ -50,32 +68,69 @@ static constexpr SinkDetails sink_details[] = {
|
|||||||
return std::make_unique<NullSink>(device_id);
|
return std::make_unique<NullSink>(device_id);
|
||||||
},
|
},
|
||||||
[](bool capture) { return std::vector<std::string>{"null"}; },
|
[](bool capture) { return std::vector<std::string>{"null"}; },
|
||||||
|
[]() { return 0u; },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const SinkDetails& GetOutputSinkDetails(Settings::AudioEngine sink_id) {
|
const SinkDetails& GetOutputSinkDetails(Settings::AudioEngine sink_id) {
|
||||||
const auto find_backend{[](Settings::AudioEngine id) {
|
const auto find_backend{[](Settings::AudioEngine id) {
|
||||||
return std::ranges::find_if(std::begin(sink_details), std::end(sink_details), [&id](const auto& e) {
|
return std::find_if(std::begin(sink_details), std::end(sink_details),
|
||||||
return e.id == id;
|
[&id](const auto& sink_detail) { return sink_detail.id == id; });
|
||||||
});
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
auto iter = find_backend(sink_id);
|
auto iter = find_backend(sink_id);
|
||||||
if (sink_id == Settings::AudioEngine::Cubeb || sink_id == Settings::AudioEngine::Auto) {
|
|
||||||
|
if (sink_id == Settings::AudioEngine::Auto) {
|
||||||
|
// REVERTED TO 3833 BELOW - DIABLO 3 FIX
|
||||||
|
/*
|
||||||
|
// Auto-select a backend. Use the sink details ordering, preferring cubeb first, checking
|
||||||
|
// that the backend is available and suitable to use.
|
||||||
|
for (auto& details : sink_details) {
|
||||||
|
if (details.is_suitable()) {
|
||||||
|
iter = &details;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/ // END REVERTED CODE - DIABLO 3 FIX
|
||||||
|
|
||||||
|
// BEGIN REINTRODUCED FROM 3833 - REPLACED CODE BLOCK ABOVE - DIABLO 3 FIX
|
||||||
|
// Auto-select a backend. Prefer CubeB, but it may report a large minimum latency which
|
||||||
|
// causes audio issues, in that case go with SDL.
|
||||||
|
#if defined(HAVE_CUBEB) && defined(HAVE_SDL3)
|
||||||
|
iter = find_backend(Settings::AudioEngine::Cubeb);
|
||||||
|
if (iter->latency() > TargetSampleCount * 3) {
|
||||||
iter = find_backend(Settings::AudioEngine::Sdl3);
|
iter = find_backend(Settings::AudioEngine::Sdl3);
|
||||||
LOG_INFO(Service_Audio, "Auto-selecting the {} backend", Settings::CanonicalizeEnum(iter->id));
|
}
|
||||||
|
#else
|
||||||
|
iter = std::begin(sink_details);
|
||||||
|
#endif
|
||||||
|
// END REINTRODUCED SECTION FROM 3833 - DIABLO 3 FIX
|
||||||
|
LOG_INFO(Service_Audio, "Auto-selecting the {} backend",
|
||||||
|
Settings::CanonicalizeEnum(iter->id));
|
||||||
|
/* BEGIN REMOVED - REVERTING BACK TO 3833, this didn't exist at all. - DIABLO 3 FIX
|
||||||
|
} else {
|
||||||
|
if (iter != std::end(sink_details) && !iter->is_suitable()) {
|
||||||
|
LOG_ERROR(Service_Audio, "Selected backend {} is not suitable, falling back to null",
|
||||||
|
Settings::CanonicalizeEnum(iter->id));
|
||||||
|
iter = find_backend(Settings::AudioEngine::Null);
|
||||||
|
} */ // END REMOVED REVERT - DIABLO 3 FIX
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iter == std::end(sink_details)) {
|
if (iter == std::end(sink_details)) {
|
||||||
LOG_ERROR(Audio, "Invalid sink_id {}", Settings::CanonicalizeEnum(sink_id));
|
LOG_ERROR(Audio, "Invalid sink_id {}", Settings::CanonicalizeEnum(sink_id));
|
||||||
iter = find_backend(Settings::AudioEngine::Null);
|
iter = find_backend(Settings::AudioEngine::Null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return *iter;
|
return *iter;
|
||||||
}
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
std::vector<Settings::AudioEngine> GetSinkIDs() {
|
std::vector<Settings::AudioEngine> GetSinkIDs() {
|
||||||
std::vector<Settings::AudioEngine> sink_ids(std::size(sink_details));
|
std::vector<Settings::AudioEngine> sink_ids(std::size(sink_details));
|
||||||
std::transform(std::begin(sink_details), std::end(sink_details), std::begin(sink_ids), [](const auto& sink) { return sink.id; });
|
|
||||||
|
std::transform(std::begin(sink_details), std::end(sink_details), std::begin(sink_ids),
|
||||||
|
[](const auto& sink) { return sink.id; });
|
||||||
|
|
||||||
return sink_ids;
|
return sink_ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user