mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-08 21:15:58 +00:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5f0f6e6306 | |||
| d43238b9af | |||
| 2addf1556e | |||
| 883cdead8b | |||
| 104bfa3a8f | |||
| 023c4758e9 | |||
| b9239c4944 | |||
| f229172d3b | |||
| eb18c5b8bd | |||
| 0c7d068112 | |||
| f29a23738a | |||
| 7e5e326842 | |||
| f93e4031ba | |||
| 7e55b4b563 | |||
| ee5049f0d3 | |||
| 15de6e0e08 | |||
| 75519010d2 | |||
| 3e61e6da87 | |||
| 8242e54e42 | |||
| 47b310266e | |||
| 3cfac4abcd | |||
| 92c52342b8 | |||
| db2bdde9b3 | |||
| ce0b15dcf7 | |||
| db922e50e3 | |||
| ca52cf679a |
@@ -1,11 +0,0 @@
|
|||||||
--- a/source/effect_lexer.cpp
|
|
||||||
+++ b/source/effect_lexer.cpp
|
|
||||||
@@ -1181,7 +1181,7 @@
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
-#if 0
|
|
||||||
+#if !defined(__cpp_lib_to_chars)
|
|
||||||
exponent += decimal_location - mantissa_size;
|
|
||||||
|
|
||||||
const bool exponent_negative = exponent < 0;
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
diff --git a/include/vk_mem_alloc.h b/include/vk_mem_alloc.h
|
|
||||||
index 8df0364..4856064 100644
|
|
||||||
--- a/include/vk_mem_alloc.h
|
|
||||||
+++ b/include/vk_mem_alloc.h
|
|
||||||
@@ -3017,7 +3017,7 @@ remove them if not needed.
|
|
||||||
|
|
||||||
#if defined(__ANDROID_API__) && (__ANDROID_API__ < 16)
|
|
||||||
#include <cstdlib>
|
|
||||||
-static void* vma_aligned_alloc(size_t alignment, size_t size)
|
|
||||||
+static inline void* vma_aligned_alloc(size_t alignment, size_t size)
|
|
||||||
{
|
|
||||||
// alignment must be >= sizeof(void*)
|
|
||||||
if(alignment < sizeof(void*))
|
|
||||||
@@ -3860,7 +3860,7 @@ Returned value is the found element, if present in the collection or place where
|
|
||||||
new element with value (key) should be inserted.
|
|
||||||
*/
|
|
||||||
template <typename CmpLess, typename IterT, typename KeyT>
|
|
||||||
-static IterT VmaBinaryFindFirstNotLess(IterT beg, IterT end, const KeyT& key, const CmpLess& cmp)
|
|
||||||
+static inline IterT VmaBinaryFindFirstNotLess(IterT beg, IterT end, const KeyT& key, const CmpLess& cmp)
|
|
||||||
{
|
|
||||||
size_t down = 0;
|
|
||||||
size_t up = size_t(end - beg);
|
|
||||||
@@ -3898,7 +3898,7 @@ Warning! O(n^2) complexity. Use only inside VMA_HEAVY_ASSERT.
|
|
||||||
T must be pointer type, e.g. VmaAllocation, VmaPool.
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
-static bool VmaValidatePointerArray(uint32_t count, const T* arr)
|
|
||||||
+static inline bool VmaValidatePointerArray(uint32_t count, const T* arr)
|
|
||||||
{
|
|
||||||
for (uint32_t i = 0; i < count; ++i)
|
|
||||||
{
|
|
||||||
@@ -4188,13 +4188,13 @@ static void VmaFree(const VkAllocationCallbacks* pAllocationCallbacks, void* ptr
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
-static T* VmaAllocate(const VkAllocationCallbacks* pAllocationCallbacks)
|
|
||||||
+static inline T* VmaAllocate(const VkAllocationCallbacks* pAllocationCallbacks)
|
|
||||||
{
|
|
||||||
return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T), VMA_ALIGN_OF(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
-static T* VmaAllocateArray(const VkAllocationCallbacks* pAllocationCallbacks, size_t count)
|
|
||||||
+static inline T* VmaAllocateArray(const VkAllocationCallbacks* pAllocationCallbacks, size_t count)
|
|
||||||
{
|
|
||||||
return (T*)VmaMalloc(pAllocationCallbacks, sizeof(T) * count, VMA_ALIGN_OF(T));
|
|
||||||
}
|
|
||||||
@@ -4204,14 +4204,14 @@ static T* VmaAllocateArray(const VkAllocationCallbacks* pAllocationCallbacks, si
|
|
||||||
#define vma_new_array(allocator, type, count) new(VmaAllocateArray<type>((allocator), (count)))(type)
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
-static void vma_delete(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr)
|
|
||||||
+static inline void vma_delete(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr)
|
|
||||||
{
|
|
||||||
ptr->~T();
|
|
||||||
VmaFree(pAllocationCallbacks, ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
-static void vma_delete_array(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr, size_t count)
|
|
||||||
+static inline void vma_delete_array(const VkAllocationCallbacks* pAllocationCallbacks, T* ptr, size_t count)
|
|
||||||
{
|
|
||||||
if (ptr != VMA_NULL)
|
|
||||||
{
|
|
||||||
@@ -4658,13 +4658,13 @@ void VmaVector<T, AllocatorT>::remove(size_t index)
|
|
||||||
#endif // _VMA_VECTOR_FUNCTIONS
|
|
||||||
|
|
||||||
template<typename T, typename allocatorT>
|
|
||||||
-static void VmaVectorInsert(VmaVector<T, allocatorT>& vec, size_t index, const T& item)
|
|
||||||
+static inline void VmaVectorInsert(VmaVector<T, allocatorT>& vec, size_t index, const T& item)
|
|
||||||
{
|
|
||||||
vec.insert(index, item);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename allocatorT>
|
|
||||||
-static void VmaVectorRemove(VmaVector<T, allocatorT>& vec, size_t index)
|
|
||||||
+static inline void VmaVectorRemove(VmaVector<T, allocatorT>& vec, size_t index)
|
|
||||||
{
|
|
||||||
vec.remove(index);
|
|
||||||
}
|
|
||||||
@@ -10620,19 +10620,19 @@ static void VmaFree(VmaAllocator hAllocator, void* ptr)
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
-static T* VmaAllocate(VmaAllocator hAllocator)
|
|
||||||
+static inline T* VmaAllocate(VmaAllocator hAllocator)
|
|
||||||
{
|
|
||||||
return (T*)VmaMalloc(hAllocator, sizeof(T), VMA_ALIGN_OF(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
-static T* VmaAllocateArray(VmaAllocator hAllocator, size_t count)
|
|
||||||
+static inline T* VmaAllocateArray(VmaAllocator hAllocator, size_t count)
|
|
||||||
{
|
|
||||||
return (T*)VmaMalloc(hAllocator, sizeof(T) * count, VMA_ALIGN_OF(T));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
-static void vma_delete(VmaAllocator hAllocator, T* ptr)
|
|
||||||
+static inline void vma_delete(VmaAllocator hAllocator, T* ptr)
|
|
||||||
{
|
|
||||||
if(ptr != VMA_NULL)
|
|
||||||
{
|
|
||||||
@@ -10642,7 +10642,7 @@ static void vma_delete(VmaAllocator hAllocator, T* ptr)
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
-static void vma_delete_array(VmaAllocator hAllocator, T* ptr, size_t count)
|
|
||||||
+static inline void vma_delete_array(VmaAllocator hAllocator, T* ptr, size_t count)
|
|
||||||
{
|
|
||||||
if(ptr != VMA_NULL)
|
|
||||||
{
|
|
||||||
+2
-5
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
cmake_minimum_required(VERSION 3.31)
|
cmake_minimum_required(VERSION 3.31)
|
||||||
|
|
||||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "15.0" CACHE STRING "macOS deployment target")
|
|
||||||
project(yuzu)
|
project(yuzu)
|
||||||
|
|
||||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
|
||||||
@@ -85,8 +84,6 @@ option(ENABLE_WERROR "Enable -Werror diagnostics" ON)
|
|||||||
# Lossless Scaling frame generation. Only Android.
|
# Lossless Scaling frame generation. Only Android.
|
||||||
cmake_dependent_option(ENABLE_LSFG "Enable Lossless Scaling frame generation" ON "ANDROID" OFF)
|
cmake_dependent_option(ENABLE_LSFG "Enable Lossless Scaling frame generation" ON "ANDROID" OFF)
|
||||||
|
|
||||||
option(ENABLE_RESHADE "Enable ReShade FX post-processing effects" ON)
|
|
||||||
|
|
||||||
# non-linux bundled qt are static
|
# non-linux bundled qt are static
|
||||||
if (YUZU_USE_BUNDLED_QT AND (APPLE OR NOT UNIX))
|
if (YUZU_USE_BUNDLED_QT AND (APPLE OR NOT UNIX))
|
||||||
set(YUZU_STATIC_BUILD ON)
|
set(YUZU_STATIC_BUILD ON)
|
||||||
@@ -241,7 +238,7 @@ option(YUZU_USE_BUNDLED_SIRIT "Download bundled sirit" ${BUNDLED_SIRIT_DEFAULT})
|
|||||||
# FreeBSD 15+ has libusb, versions below should disable it
|
# FreeBSD 15+ has libusb, versions below should disable it
|
||||||
cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "WIN32 OR LINUX OR FREEBSD OR APPLE" OFF)
|
cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "WIN32 OR LINUX OR FREEBSD OR APPLE" OFF)
|
||||||
|
|
||||||
cmake_dependent_option(ENABLE_OPENGL "Enable OpenGL" ON "NOT (WIN32 AND ARCHITECTURE_arm64) AND NOT APPLE AND NOT ANDROID" OFF)
|
cmake_dependent_option(ENABLE_OPENGL "Enable OpenGL" ON "NOT (WIN32 AND ARCHITECTURE_arm64) AND NOT APPLE" OFF)
|
||||||
mark_as_advanced(FORCE ENABLE_OPENGL)
|
mark_as_advanced(FORCE ENABLE_OPENGL)
|
||||||
|
|
||||||
option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
|
option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
|
||||||
@@ -515,7 +512,7 @@ endfunction()
|
|||||||
# =============================================
|
# =============================================
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
foreach(fw Carbon Metal Cocoa IOKit CoreVideo CoreMedia Security UniformTypeIdentifiers Foundation)
|
foreach(fw Carbon Metal Cocoa IOKit CoreVideo CoreMedia Security UniformTypeIdentifiers)
|
||||||
find_library(${fw}_LIBRARY ${fw} REQUIRED)
|
find_library(${fw}_LIBRARY ${fw} REQUIRED)
|
||||||
list(APPEND PLATFORM_LIBRARIES ${${fw}_LIBRARY})
|
list(APPEND PLATFORM_LIBRARIES ${${fw}_LIBRARY})
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|||||||
+10
-13
@@ -1,4 +1,12 @@
|
|||||||
{
|
{
|
||||||
|
"": {
|
||||||
|
"ci": true,
|
||||||
|
"hash": "9f50d993c39529e022ad456163de91ac5934e16faf8fc348f305355fc0a643c534f87ded707e11bd03bcbc0a1760bd20852b6533a67ac0558a078385181cb184",
|
||||||
|
"name": "SDL3",
|
||||||
|
"package": "SDL3",
|
||||||
|
"repo": "crueter-ci/SDL3",
|
||||||
|
"version": "3.4.14-1788231389-147a8ee32d"
|
||||||
|
},
|
||||||
"biscuit": {
|
"biscuit": {
|
||||||
"hash": "1229f345b014f7ca544dedb4edb3311e41ba736f9aa9a67f88b5f26f3c983288c6bb6cdedcfb0b8a02c63088a37e6a0d7ba97d9c2a4d721b213916327cffe28a",
|
"hash": "1229f345b014f7ca544dedb4edb3311e41ba736f9aa9a67f88b5f26f3c983288c6bb6cdedcfb0b8a02c63088a37e6a0d7ba97d9c2a4d721b213916327cffe28a",
|
||||||
"min_version": "0.9.1",
|
"min_version": "0.9.1",
|
||||||
@@ -60,10 +68,10 @@
|
|||||||
},
|
},
|
||||||
"discord-rpc": {
|
"discord-rpc": {
|
||||||
"find_args": "MODULE",
|
"find_args": "MODULE",
|
||||||
"hash": "8d680b3a16d6f6bf292ad823cf8635595ff986f2a49f758e3009f505b540a9d75194a8cf44cddea75736a8c3e3b5160166e716a0939ce3f18cc463cf648753fe",
|
"hash": "8213c43dcb0f7d479f5861091d111ed12fbdec1e62e6d729d65a4bc181d82f48a35d5fd3cd5c291f2393ac7c9681eabc6b76609755f55376284c8a8d67e148f3",
|
||||||
"package": "DiscordRPC",
|
"package": "DiscordRPC",
|
||||||
"repo": "eden-emulator/discord-rpc",
|
"repo": "eden-emulator/discord-rpc",
|
||||||
"version": "76616d8675"
|
"version": "0d8b2d6a37"
|
||||||
},
|
},
|
||||||
"enet": {
|
"enet": {
|
||||||
"find_args": "MODULE",
|
"find_args": "MODULE",
|
||||||
@@ -238,14 +246,6 @@
|
|||||||
"repo": "stachenov/quazip",
|
"repo": "stachenov/quazip",
|
||||||
"version": "2e95c9001b"
|
"version": "2e95c9001b"
|
||||||
},
|
},
|
||||||
"reshade": {
|
|
||||||
"hash": "6fc9b39821ca6e2d91160f05846b3a42159fec759f5d6fba91d1a57801a1bdaf6047740578c136f0b1a60a9c29ad160d87dbfe0dbfbcdf6ea879a8a078377b8c",
|
|
||||||
"patches": [
|
|
||||||
"0001-from-chars-fallback.patch"
|
|
||||||
],
|
|
||||||
"repo": "crosire/reshade",
|
|
||||||
"version": "v6.8.0"
|
|
||||||
},
|
|
||||||
"sdl3": {
|
"sdl3": {
|
||||||
"hash": "df5a323af7ac366661a3c0e887969c72584d232f3cc211419d59b0487b620b6b2859d4549c9e8df002ee489290062e466fcfddf7edc0872a37b1f2845e81c0f3",
|
"hash": "df5a323af7ac366661a3c0e887969c72584d232f3cc211419d59b0487b620b6b2859d4549c9e8df002ee489290062e466fcfddf7edc0872a37b1f2845e81c0f3",
|
||||||
"min_version": "3.2.10",
|
"min_version": "3.2.10",
|
||||||
@@ -311,9 +311,6 @@
|
|||||||
"find_args": "CONFIG",
|
"find_args": "CONFIG",
|
||||||
"hash": "deb5902ef8db0e329fbd5f3f4385eb0e26bdd9f14f3a2334823fb3fe18f36bc5d235d620d6e5f6fe3551ec3ea7038638899db8778c09f6d5c278f5ff95c3344b",
|
"hash": "deb5902ef8db0e329fbd5f3f4385eb0e26bdd9f14f3a2334823fb3fe18f36bc5d235d620d6e5f6fe3551ec3ea7038638899db8778c09f6d5c278f5ff95c3344b",
|
||||||
"package": "VulkanMemoryAllocator",
|
"package": "VulkanMemoryAllocator",
|
||||||
"patches": [
|
|
||||||
"0001-macos-clang.patch"
|
|
||||||
],
|
|
||||||
"repo": "GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator",
|
"repo": "GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator",
|
||||||
"version": "v3.3.0"
|
"version": "v3.3.0"
|
||||||
},
|
},
|
||||||
|
|||||||
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);
|
|
||||||
for (int x = -3; x <= 3; x += 2)
|
|
||||||
{
|
|
||||||
for (int y = -3; y <= 3; y += 2)
|
|
||||||
{
|
|
||||||
float3 tap = tex2D(BackBuffer, uv + float2(x, y) * spread).rgb;
|
|
||||||
sum += tap * Weight(tap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sum /= 16.0;
|
|
||||||
|
|
||||||
return float4(saturate(color + sum * Amount), 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
technique Bloom <
|
|
||||||
ui_label = "Bloom";
|
|
||||||
ui_tooltip = "Blooms bright areas into a soft glow.";
|
|
||||||
>
|
|
||||||
{
|
|
||||||
pass
|
|
||||||
{
|
|
||||||
VertexShader = VS_PostProcess;
|
|
||||||
PixelShader = PS_Bloom;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
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.";
|
|
||||||
>
|
|
||||||
{
|
|
||||||
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.";
|
|
||||||
>
|
|
||||||
{
|
|
||||||
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.";
|
|
||||||
>
|
|
||||||
{
|
|
||||||
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, like a cheap lens.";
|
|
||||||
>
|
|
||||||
{
|
|
||||||
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 = "Global saturation, brightness, contrast and gamma.";
|
|
||||||
>
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
|
|
||||||
for (int ring = 1; ring <= 2; ++ring)
|
|
||||||
{
|
|
||||||
float angle = base + float(ring) * 2.3999632;
|
|
||||||
float reach = Radius * float(ring) * 0.5;
|
|
||||||
float2 along = float2(cos(angle), sin(angle)) * reach;
|
|
||||||
float2 across = float2(-along.y, along.x);
|
|
||||||
|
|
||||||
float3 s0 = tex2D(BackBuffer, uv + along * texel).rgb;
|
|
||||||
float3 s1 = tex2D(BackBuffer, uv - along * texel).rgb;
|
|
||||||
float3 s2 = tex2D(BackBuffer, uv + across * texel).rgb;
|
|
||||||
float3 s3 = tex2D(BackBuffer, uv - across * texel).rgb;
|
|
||||||
|
|
||||||
total += s0 + s1 + s2 + s3;
|
|
||||||
deviation = max(deviation, max(max(abs(s0 - centre), abs(s1 - centre)),
|
|
||||||
max(abs(s2 - centre), abs(s3 - centre))));
|
|
||||||
}
|
|
||||||
|
|
||||||
float3 average = total * 0.125;
|
|
||||||
float3 flatness = float3(1.0, 1.0, 1.0) -
|
|
||||||
smoothstep(Threshold * 0.5, Threshold, deviation);
|
|
||||||
float3 result = lerp(centre, average, flatness);
|
|
||||||
|
|
||||||
float dither = (Hash(pos.xy + float2(71.3, 41.7)) - 0.5) * Grain;
|
|
||||||
|
|
||||||
return float4(saturate(result + dither), 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
technique Deband <
|
|
||||||
ui_label = "Deband";
|
|
||||||
ui_tooltip = "Smooths the visible steps in gradients such as skies, then dithers whatever survives.";
|
|
||||||
>
|
|
||||||
{
|
|
||||||
pass
|
|
||||||
{
|
|
||||||
VertexShader = VS_PostProcess;
|
|
||||||
PixelShader = PS_Deband;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
|
|
||||||
for (int y = -2; y <= 2; ++y)
|
|
||||||
{
|
|
||||||
for (int x = -2; x <= 2; ++x)
|
|
||||||
{
|
|
||||||
float2 offset = float2(x, y);
|
|
||||||
float3 tap = tex2D(BackBuffer, uv + offset * texel).rgb;
|
|
||||||
float3 weight = IntensityWeight(tap, intensity_sigma, centre) *
|
|
||||||
SpatialWeight(length(offset), spatial_sigma);
|
|
||||||
sum += weight * tap;
|
|
||||||
total += weight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return float4(sum / total, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
technique Denoise <
|
|
||||||
ui_label = "Denoise";
|
|
||||||
ui_tooltip = "Edge preserving blur that clears dithering and compression noise. Ported from Anime4K.";
|
|
||||||
>
|
|
||||||
{
|
|
||||||
pass
|
|
||||||
{
|
|
||||||
VertexShader = VS_PostProcess;
|
|
||||||
PixelShader = PS_Denoise;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
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 = "Warmer and more saturated 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 = "Horizontal scanlines of a CRT display.";
|
|
||||||
>
|
|
||||||
{
|
|
||||||
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.";
|
|
||||||
>
|
|
||||||
{
|
|
||||||
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.";
|
|
||||||
>
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+1
-1
@@ -76,7 +76,7 @@ The following options are desktop only.
|
|||||||
|
|
||||||
- `ENABLE_LIBUSB` (ON) Enable the use of the libusb input backend (HIGHLY RECOMMENDED)
|
- `ENABLE_LIBUSB` (ON) Enable the use of the libusb input backend (HIGHLY RECOMMENDED)
|
||||||
- `ENABLE_OPENGL` (ON) Enable the OpenGL graphics backend
|
- `ENABLE_OPENGL` (ON) Enable the OpenGL graphics backend
|
||||||
- Unavailable on Windows/ARM64 and on Android
|
- Unavailable on Windows/ARM64
|
||||||
- You probably shouldn't turn this off.
|
- You probably shouldn't turn this off.
|
||||||
|
|
||||||
### Qt
|
### Qt
|
||||||
|
|||||||
Vendored
-44
@@ -195,50 +195,6 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# reshadefx
|
|
||||||
if (ENABLE_RESHADE)
|
|
||||||
AddJsonPackage(NAME reshade DOWNLOAD_ONLY)
|
|
||||||
|
|
||||||
set(RESHADEFX_SHIM_DIR ${CMAKE_CURRENT_BINARY_DIR}/reshadefx_shim)
|
|
||||||
file(WRITE ${RESHADEFX_SHIM_DIR}/spirv.hpp "#include <spirv/unified1/spirv.hpp>\n")
|
|
||||||
file(WRITE ${RESHADEFX_SHIM_DIR}/GLSL.std.450.h "#include <spirv/unified1/GLSL.std.450.h>\n")
|
|
||||||
if (APPLE)
|
|
||||||
file(WRITE ${RESHADEFX_SHIM_DIR}/malloc.h "#include <stdlib.h>\n#include <alloca.h>\n")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_library(reshadefx STATIC
|
|
||||||
${reshade_SOURCE_DIR}/source/effect_codegen_spirv.cpp
|
|
||||||
${reshade_SOURCE_DIR}/source/effect_expression.cpp
|
|
||||||
${reshade_SOURCE_DIR}/source/effect_lexer.cpp
|
|
||||||
${reshade_SOURCE_DIR}/source/effect_parser_exp.cpp
|
|
||||||
${reshade_SOURCE_DIR}/source/effect_parser_stmt.cpp
|
|
||||||
${reshade_SOURCE_DIR}/source/effect_preprocessor.cpp
|
|
||||||
${reshade_SOURCE_DIR}/source/effect_symbol_table.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
target_include_directories(reshadefx SYSTEM PUBLIC ${reshade_SOURCE_DIR}/source)
|
|
||||||
target_include_directories(reshadefx PRIVATE ${RESHADEFX_SHIM_DIR})
|
|
||||||
target_link_libraries(reshadefx PUBLIC SPIRV-Headers::SPIRV-Headers)
|
|
||||||
|
|
||||||
if (NOT MSVC)
|
|
||||||
target_compile_options(reshadefx PRIVATE -w -fno-char8_t)
|
|
||||||
else()
|
|
||||||
target_compile_options(reshadefx PRIVATE /w /Zc:char8_t-)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (WIN32)
|
|
||||||
if (NOT MSVC)
|
|
||||||
target_compile_options(reshadefx PRIVATE -include share.h)
|
|
||||||
else()
|
|
||||||
target_compile_options(reshadefx PRIVATE /FIshare.h)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (NOT TARGET reshadefx::reshadefx)
|
|
||||||
add_library(reshadefx::reshadefx ALIAS reshadefx)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Catch2
|
# Catch2
|
||||||
if (YUZU_TESTS OR DYNARMIC_TESTS)
|
if (YUZU_TESTS OR DYNARMIC_TESTS)
|
||||||
AddJsonPackage(catch2)
|
AddJsonPackage(catch2)
|
||||||
|
|||||||
Vendored
-1
@@ -11,7 +11,6 @@
|
|||||||
#include <limits>
|
#include <limits>
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <algorithm>
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
namespace Tz {
|
namespace Tz {
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
|
|||||||
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
|
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
|
||||||
import org.yuzu.yuzu_emu.fragments.EmulationFragment
|
import org.yuzu.yuzu_emu.fragments.EmulationFragment
|
||||||
import org.yuzu.yuzu_emu.utils.NativeConfig
|
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||||
import org.yuzu.yuzu_emu.utils.NativePostProcessing
|
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting
|
import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractShortSetting
|
import org.yuzu.yuzu_emu.features.settings.model.AbstractShortSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting
|
import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting
|
||||||
@@ -233,250 +232,6 @@ class QuickSettings(val emulationFragment: EmulationFragment) {
|
|||||||
container.addView(itemView)
|
container.addView(itemView)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addChoice(
|
|
||||||
title: String,
|
|
||||||
container: ViewGroup,
|
|
||||||
choices: List<String>,
|
|
||||||
selectedIndex: Int,
|
|
||||||
onSelected: (Int) -> Unit
|
|
||||||
) {
|
|
||||||
val inflater = LayoutInflater.from(emulationFragment.requireContext())
|
|
||||||
val itemView = inflater.inflate(R.layout.item_quick_settings_menu, container, false)
|
|
||||||
val headerView = itemView.findViewById<ViewGroup>(R.id.setting_header)
|
|
||||||
val titleView = itemView.findViewById<TextView>(R.id.setting_title)
|
|
||||||
val valueView = itemView.findViewById<TextView>(R.id.setting_value)
|
|
||||||
val expandIcon = itemView.findViewById<android.widget.ImageView>(R.id.expand_icon)
|
|
||||||
val radioGroup = itemView.findViewById<RadioGroup>(R.id.radio_group)
|
|
||||||
|
|
||||||
titleView.text = title
|
|
||||||
|
|
||||||
var current = ""
|
|
||||||
if (selectedIndex in choices.indices) {
|
|
||||||
current = choices[selectedIndex]
|
|
||||||
}
|
|
||||||
valueView.text = current
|
|
||||||
headerView.visibility = View.VISIBLE
|
|
||||||
|
|
||||||
var isExpanded = false
|
|
||||||
choices.forEachIndexed { index, name ->
|
|
||||||
val radioButton = com.google.android.material.radiobutton.MaterialRadioButton(
|
|
||||||
emulationFragment.requireContext()
|
|
||||||
)
|
|
||||||
radioButton.text = name
|
|
||||||
radioButton.id = View.generateViewId()
|
|
||||||
radioButton.isChecked = index == selectedIndex
|
|
||||||
radioButton.setPadding(16, 8, 16, 8)
|
|
||||||
|
|
||||||
radioButton.setOnCheckedChangeListener { _, isChecked ->
|
|
||||||
if (isChecked) {
|
|
||||||
valueView.text = name
|
|
||||||
onSelected(index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
radioGroup.addView(radioButton)
|
|
||||||
}
|
|
||||||
|
|
||||||
headerView.setOnClickListener {
|
|
||||||
isExpanded = !isExpanded
|
|
||||||
if (isExpanded) {
|
|
||||||
radioGroup.visibility = View.VISIBLE
|
|
||||||
expandIcon.animate().rotation(180f).setDuration(200).start()
|
|
||||||
} else {
|
|
||||||
radioGroup.visibility = View.GONE
|
|
||||||
expandIcon.animate().rotation(0f).setDuration(200).start()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
container.addView(itemView)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addStepSlider(
|
|
||||||
title: String,
|
|
||||||
container: ViewGroup,
|
|
||||||
steps: Int,
|
|
||||||
selectedStep: Int,
|
|
||||||
describe: (Int) -> String,
|
|
||||||
onChanged: (Int) -> Unit
|
|
||||||
) {
|
|
||||||
val inflater = LayoutInflater.from(emulationFragment.requireContext())
|
|
||||||
val itemView = inflater.inflate(R.layout.item_quick_settings_menu, container, false)
|
|
||||||
|
|
||||||
val sliderContainer = itemView.findViewById<ViewGroup>(R.id.slider_container)
|
|
||||||
val titleView = itemView.findViewById<TextView>(R.id.slider_title)
|
|
||||||
val valueDisplay = itemView.findViewById<TextView>(R.id.slider_value_display)
|
|
||||||
val slider = itemView.findViewById<com.google.android.material.slider.Slider>(
|
|
||||||
R.id.setting_slider
|
|
||||||
)
|
|
||||||
|
|
||||||
titleView.text = title
|
|
||||||
sliderContainer.visibility = View.VISIBLE
|
|
||||||
|
|
||||||
slider.valueFrom = 0f
|
|
||||||
slider.valueTo = steps.toFloat()
|
|
||||||
slider.stepSize = 1f
|
|
||||||
slider.value = selectedStep.toFloat().coerceIn(0f, steps.toFloat())
|
|
||||||
valueDisplay.text = describe(slider.value.toInt())
|
|
||||||
|
|
||||||
slider.addOnChangeListener { _, value, fromUser ->
|
|
||||||
if (fromUser) {
|
|
||||||
val step = value.toInt()
|
|
||||||
onChanged(step)
|
|
||||||
valueDisplay.text = describe(step)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
slider.setOnTouchListener { _, event ->
|
|
||||||
val drawer = emulationFragment.view?.findViewById<DrawerLayout>(R.id.drawer_layout)
|
|
||||||
when (event.action) {
|
|
||||||
MotionEvent.ACTION_DOWN -> {
|
|
||||||
drawer?.requestDisallowInterceptTouchEvent(true)
|
|
||||||
}
|
|
||||||
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
|
|
||||||
drawer?.requestDisallowInterceptTouchEvent(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
container.addView(itemView)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addPostProcessing(container: ViewGroup, onStructureChanged: () -> Unit) {
|
|
||||||
val usable = NativePostProcessing.catalog().filter { it.valid }
|
|
||||||
if (usable.isEmpty()) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val labels = mutableListOf(
|
|
||||||
YuzuApplication.appContext.getString(R.string.post_processing_none)
|
|
||||||
)
|
|
||||||
val files = mutableListOf("")
|
|
||||||
val techniques = mutableListOf("")
|
|
||||||
|
|
||||||
for (effect in usable) {
|
|
||||||
for (technique in effect.techniques) {
|
|
||||||
var label = effect.label
|
|
||||||
if (effect.techniques.size > 1) {
|
|
||||||
label = effect.label + " \u00b7 " + technique
|
|
||||||
}
|
|
||||||
labels.add(label)
|
|
||||||
files.add(effect.file)
|
|
||||||
techniques.add(technique)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
addDivider(container)
|
|
||||||
|
|
||||||
val chain = NativePostProcessing.chain()
|
|
||||||
for (index in 0..chain.size) {
|
|
||||||
var selected = 0
|
|
||||||
var effect: NativePostProcessing.Effect? = null
|
|
||||||
|
|
||||||
if (index < chain.size) {
|
|
||||||
val entry = chain[index]
|
|
||||||
effect = usable.firstOrNull { it.file == entry.file }
|
|
||||||
for (i in files.indices) {
|
|
||||||
if (files[i] == entry.file && techniques[i] == entry.technique) {
|
|
||||||
selected = i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var title = YuzuApplication.appContext.getString(R.string.post_processing_add)
|
|
||||||
if (index < chain.size) {
|
|
||||||
title = YuzuApplication.appContext.getString(R.string.post_processing_effect)
|
|
||||||
}
|
|
||||||
|
|
||||||
addChoice(title, container, labels, selected) { picked ->
|
|
||||||
applyEffectPick(index, picked, files, techniques, chain.size)
|
|
||||||
onStructureChanged()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (effect != null) {
|
|
||||||
for (uniform in effect.uniforms) {
|
|
||||||
addUniformSliders(container, index, uniform)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun applyEffectPick(
|
|
||||||
index: Int,
|
|
||||||
picked: Int,
|
|
||||||
files: List<String>,
|
|
||||||
techniques: List<String>,
|
|
||||||
chainSize: Int
|
|
||||||
) {
|
|
||||||
if (index >= chainSize) {
|
|
||||||
if (picked > 0) {
|
|
||||||
NativePostProcessing.append(files[picked], techniques[picked])
|
|
||||||
NativePostProcessing.persist()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (picked == 0) {
|
|
||||||
NativePostProcessing.remove(index)
|
|
||||||
NativePostProcessing.persist()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
NativePostProcessing.replace(index, files[picked], techniques[picked])
|
|
||||||
NativePostProcessing.persist()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addUniformSliders(
|
|
||||||
container: ViewGroup,
|
|
||||||
index: Int,
|
|
||||||
uniform: NativePostProcessing.Uniform
|
|
||||||
) {
|
|
||||||
if (uniform.uiType == NativePostProcessing.UI_HIDDEN) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for (component in 0 until uniform.components) {
|
|
||||||
var title = uniform.label
|
|
||||||
if (uniform.components > 1) {
|
|
||||||
title = uniform.label + " [" + component + "]"
|
|
||||||
}
|
|
||||||
|
|
||||||
var value = uniform.defaultAt(component)
|
|
||||||
if (NativePostProcessing.hasValue(index, uniform.name)) {
|
|
||||||
value = NativePostProcessing.getValue(index, uniform.name, component)
|
|
||||||
}
|
|
||||||
|
|
||||||
val steps = uniform.steps
|
|
||||||
val step = Math.round((value - uniform.min) / uniform.step)
|
|
||||||
|
|
||||||
addStepSlider(
|
|
||||||
title,
|
|
||||||
container,
|
|
||||||
steps,
|
|
||||||
step,
|
|
||||||
{ position -> describeUniform(uniform, position) }
|
|
||||||
) { position ->
|
|
||||||
NativePostProcessing.setValue(
|
|
||||||
index,
|
|
||||||
uniform.name,
|
|
||||||
component,
|
|
||||||
uniform.min + position * uniform.step
|
|
||||||
)
|
|
||||||
NativePostProcessing.persist()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun describeUniform(
|
|
||||||
uniform: NativePostProcessing.Uniform,
|
|
||||||
position: Int
|
|
||||||
): String {
|
|
||||||
val value = uniform.min + position * uniform.step
|
|
||||||
if (uniform.kind == NativePostProcessing.KIND_FLOAT) {
|
|
||||||
return String.format("%.3f", value)
|
|
||||||
}
|
|
||||||
return Math.round(value).toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addDivider(container: ViewGroup) {
|
fun addDivider(container: ViewGroup) {
|
||||||
val inflater = LayoutInflater.from(emulationFragment.requireContext())
|
val inflater = LayoutInflater.from(emulationFragment.requireContext())
|
||||||
val dividerView = inflater.inflate(R.layout.item_quick_settings_divider, container, false)
|
val dividerView = inflater.inflate(R.layout.item_quick_settings_divider, container, false)
|
||||||
|
|||||||
-1
@@ -83,7 +83,6 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
|||||||
SHOW_SHADERS_BUILDING("show_shaders_building"),
|
SHOW_SHADERS_BUILDING("show_shaders_building"),
|
||||||
|
|
||||||
DEBUG_FLUSH_BY_LINE("flush_line"),
|
DEBUG_FLUSH_BY_LINE("flush_line"),
|
||||||
EXTENDED_LOGGING("extended_logging"),
|
|
||||||
DONT_SHOW_DRIVER_SHADER_WARNING("dont_show_driver_shader_warning"),
|
DONT_SHOW_DRIVER_SHADER_WARNING("dont_show_driver_shader_warning"),
|
||||||
ENABLE_OVERLAY("enable_overlay"),
|
ENABLE_OVERLAY("enable_overlay"),
|
||||||
|
|
||||||
|
|||||||
-103
@@ -1,103 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.features.settings.model
|
|
||||||
|
|
||||||
import org.yuzu.yuzu_emu.utils.NativePostProcessing
|
|
||||||
import kotlin.math.roundToInt
|
|
||||||
|
|
||||||
abstract class FxUniformSetting(
|
|
||||||
protected val index: Int,
|
|
||||||
protected val uniform: NativePostProcessing.Uniform,
|
|
||||||
protected val component: Int
|
|
||||||
) : AbstractSetting {
|
|
||||||
override val key: String
|
|
||||||
get() = "fx_${index}_${uniform.name}_$component"
|
|
||||||
|
|
||||||
override val isRuntimeModifiable: Boolean
|
|
||||||
get() = true
|
|
||||||
|
|
||||||
override val pairedSettingKey: String
|
|
||||||
get() = ""
|
|
||||||
|
|
||||||
override val isSwitchable: Boolean
|
|
||||||
get() = false
|
|
||||||
|
|
||||||
override val isSaveable: Boolean
|
|
||||||
get() = true
|
|
||||||
|
|
||||||
override var global: Boolean
|
|
||||||
get() = true
|
|
||||||
set(_) {}
|
|
||||||
|
|
||||||
protected fun currentValue(): Float {
|
|
||||||
if (NativePostProcessing.hasValue(index, uniform.name)) {
|
|
||||||
return NativePostProcessing.getValue(index, uniform.name, component)
|
|
||||||
}
|
|
||||||
return uniform.defaultAt(component)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun commit(value: Float) {
|
|
||||||
NativePostProcessing.setValue(index, uniform.name, component, value)
|
|
||||||
NativePostProcessing.persist()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun reset() = commit(uniform.defaultAt(component))
|
|
||||||
}
|
|
||||||
|
|
||||||
class FxUniformSliderSetting(
|
|
||||||
index: Int,
|
|
||||||
uniform: NativePostProcessing.Uniform,
|
|
||||||
component: Int
|
|
||||||
) : FxUniformSetting(index, uniform, component), AbstractIntSetting {
|
|
||||||
override val defaultValue: Any
|
|
||||||
get() = ((uniform.defaultAt(component) - uniform.min) / uniform.step).roundToInt()
|
|
||||||
|
|
||||||
override fun getInt(needsGlobal: Boolean): Int =
|
|
||||||
((currentValue() - uniform.min) / uniform.step).roundToInt()
|
|
||||||
|
|
||||||
override fun setInt(value: Int) = commit(uniform.min + value * uniform.step)
|
|
||||||
|
|
||||||
override fun getValueAsString(needsGlobal: Boolean): String {
|
|
||||||
if (uniform.kind == NativePostProcessing.KIND_FLOAT) {
|
|
||||||
return String.format("%.3f", currentValue())
|
|
||||||
}
|
|
||||||
return currentValue().roundToInt().toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class FxUniformChoiceSetting(
|
|
||||||
index: Int,
|
|
||||||
uniform: NativePostProcessing.Uniform,
|
|
||||||
component: Int
|
|
||||||
) : FxUniformSetting(index, uniform, component), AbstractIntSetting {
|
|
||||||
override val defaultValue: Any
|
|
||||||
get() = uniform.defaultAt(component).roundToInt()
|
|
||||||
|
|
||||||
override fun getInt(needsGlobal: Boolean): Int = currentValue().roundToInt()
|
|
||||||
|
|
||||||
override fun setInt(value: Int) = commit(value.toFloat())
|
|
||||||
|
|
||||||
override fun getValueAsString(needsGlobal: Boolean): String = getInt().toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
class FxUniformBooleanSetting(
|
|
||||||
index: Int,
|
|
||||||
uniform: NativePostProcessing.Uniform,
|
|
||||||
component: Int
|
|
||||||
) : FxUniformSetting(index, uniform, component), AbstractBooleanSetting {
|
|
||||||
override val defaultValue: Any
|
|
||||||
get() = uniform.defaultAt(component) != 0f
|
|
||||||
|
|
||||||
override fun getBoolean(needsGlobal: Boolean): Boolean = currentValue() != 0f
|
|
||||||
|
|
||||||
override fun setBoolean(value: Boolean) {
|
|
||||||
if (value) {
|
|
||||||
commit(1f)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
commit(0f)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getValueAsString(needsGlobal: Boolean): String = getBoolean().toString()
|
|
||||||
}
|
|
||||||
@@ -12,7 +12,6 @@ object Settings {
|
|||||||
SECTION_SYSTEM(R.string.preferences_system),
|
SECTION_SYSTEM(R.string.preferences_system),
|
||||||
SECTION_RENDERER(R.string.preferences_graphics),
|
SECTION_RENDERER(R.string.preferences_graphics),
|
||||||
SECTION_FRAME_GEN(R.string.frame_gen),
|
SECTION_FRAME_GEN(R.string.frame_gen),
|
||||||
SECTION_POST_PROCESSING(R.string.post_processing),
|
|
||||||
SECTION_PERFORMANCE_STATS(R.string.stats_overlay_options),
|
SECTION_PERFORMANCE_STATS(R.string.stats_overlay_options),
|
||||||
SECTION_INPUT_OVERLAY(R.string.input_overlay_options),
|
SECTION_INPUT_OVERLAY(R.string.input_overlay_options),
|
||||||
SECTION_SOC_OVERLAY(R.string.soc_overlay_options),
|
SECTION_SOC_OVERLAY(R.string.soc_overlay_options),
|
||||||
|
|||||||
-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")
|
||||||
|
|||||||
-7
@@ -262,13 +262,6 @@ abstract class SettingsItem(
|
|||||||
descriptionId = R.string.flush_by_line_description
|
descriptionId = R.string.flush_by_line_description
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
put(
|
|
||||||
SwitchSetting(
|
|
||||||
BooleanSetting.EXTENDED_LOGGING,
|
|
||||||
titleId = R.string.extended_logging,
|
|
||||||
descriptionId = R.string.extended_logging_description
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
val dockedModeSetting = object : AbstractBooleanSetting {
|
val dockedModeSetting = object : AbstractBooleanSetting {
|
||||||
override val key = BooleanSetting.USE_DOCKED_MODE.key
|
override val key = BooleanSetting.USE_DOCKED_MODE.key
|
||||||
|
|||||||
-211
@@ -18,9 +18,6 @@ import org.yuzu.yuzu_emu.features.input.model.NpadStyleIndex
|
|||||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractBooleanSetting
|
import org.yuzu.yuzu_emu.features.settings.model.AbstractBooleanSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting
|
import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
|
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.FxUniformBooleanSetting
|
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.FxUniformChoiceSetting
|
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.FxUniformSliderSetting
|
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.ByteSetting
|
import org.yuzu.yuzu_emu.features.settings.model.ByteSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
|
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.LongSetting
|
import org.yuzu.yuzu_emu.features.settings.model.LongSetting
|
||||||
@@ -33,7 +30,6 @@ import org.yuzu.yuzu_emu.features.settings.model.view.*
|
|||||||
import org.yuzu.yuzu_emu.utils.InputHandler
|
import org.yuzu.yuzu_emu.utils.InputHandler
|
||||||
import org.yuzu.yuzu_emu.utils.LosslessScalingHelper
|
import org.yuzu.yuzu_emu.utils.LosslessScalingHelper
|
||||||
import org.yuzu.yuzu_emu.utils.NativeConfig
|
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||||
import org.yuzu.yuzu_emu.utils.NativePostProcessing
|
|
||||||
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
|
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
|
||||||
import org.yuzu.yuzu_emu.utils.FullscreenHelper
|
import org.yuzu.yuzu_emu.utils.FullscreenHelper
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
@@ -167,7 +163,6 @@ class SettingsFragmentPresenter(
|
|||||||
MenuTag.SECTION_SYSTEM -> addSystemSettings(sl)
|
MenuTag.SECTION_SYSTEM -> addSystemSettings(sl)
|
||||||
MenuTag.SECTION_RENDERER -> addGraphicsSettings(sl)
|
MenuTag.SECTION_RENDERER -> addGraphicsSettings(sl)
|
||||||
MenuTag.SECTION_FRAME_GEN -> addFrameGenSettings(sl)
|
MenuTag.SECTION_FRAME_GEN -> addFrameGenSettings(sl)
|
||||||
MenuTag.SECTION_POST_PROCESSING -> addPostProcessingSettings(sl)
|
|
||||||
MenuTag.SECTION_PERFORMANCE_STATS -> addPerformanceOverlaySettings(sl)
|
MenuTag.SECTION_PERFORMANCE_STATS -> addPerformanceOverlaySettings(sl)
|
||||||
MenuTag.SECTION_SOC_OVERLAY -> addSocOverlaySettings(sl)
|
MenuTag.SECTION_SOC_OVERLAY -> addSocOverlaySettings(sl)
|
||||||
MenuTag.SECTION_INPUT_OVERLAY -> addInputOverlaySettings(sl)
|
MenuTag.SECTION_INPUT_OVERLAY -> addInputOverlaySettings(sl)
|
||||||
@@ -195,211 +190,6 @@ class SettingsFragmentPresenter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addPostProcessingSettings(sl: ArrayList<SettingsItem>) {
|
|
||||||
val usable = NativePostProcessing.catalog().filter { it.valid }
|
|
||||||
|
|
||||||
sl.apply {
|
|
||||||
if (usable.isEmpty()) {
|
|
||||||
add(
|
|
||||||
RunnableSetting(
|
|
||||||
titleId = R.string.post_processing_empty,
|
|
||||||
descriptionString = NativePostProcessing.getShaderDirectory(),
|
|
||||||
isRunnable = false
|
|
||||||
) {}
|
|
||||||
)
|
|
||||||
return@apply
|
|
||||||
}
|
|
||||||
|
|
||||||
val labels = mutableListOf<String>()
|
|
||||||
val files = mutableListOf<String>()
|
|
||||||
val techniques = mutableListOf<String>()
|
|
||||||
for (effect in usable) {
|
|
||||||
for (technique in effect.techniques) {
|
|
||||||
if (effect.techniques.size == 1) {
|
|
||||||
labels.add(effect.label)
|
|
||||||
} else {
|
|
||||||
labels.add(effect.label + " \u00b7 " + technique)
|
|
||||||
}
|
|
||||||
files.add(effect.file)
|
|
||||||
techniques.add(technique)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val chain = NativePostProcessing.chain()
|
|
||||||
for (index in chain.indices) {
|
|
||||||
val entry = chain[index]
|
|
||||||
val effect = usable.firstOrNull { it.file == entry.file }
|
|
||||||
|
|
||||||
var header = entry.file
|
|
||||||
var summary = ""
|
|
||||||
if (effect != null) {
|
|
||||||
header = effect.label
|
|
||||||
summary = effect.description
|
|
||||||
}
|
|
||||||
add(HeaderSetting(titleString = header))
|
|
||||||
|
|
||||||
add(
|
|
||||||
IntSingleChoiceSetting(
|
|
||||||
buildSlotSelector(index, entry, files, techniques),
|
|
||||||
titleId = R.string.post_processing_effect,
|
|
||||||
descriptionString = summary,
|
|
||||||
choices = labels.toTypedArray(),
|
|
||||||
values = labels.indices.toList().toTypedArray()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (effect != null) {
|
|
||||||
for (uniform in effect.uniforms) {
|
|
||||||
addUniform(this, index, uniform)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index > 0) {
|
|
||||||
add(
|
|
||||||
RunnableSetting(
|
|
||||||
titleId = R.string.post_processing_move_up,
|
|
||||||
isRunnable = true
|
|
||||||
) {
|
|
||||||
NativePostProcessing.move(index, -1)
|
|
||||||
NativePostProcessing.persist()
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (index < chain.size - 1) {
|
|
||||||
add(
|
|
||||||
RunnableSetting(
|
|
||||||
titleId = R.string.post_processing_move_down,
|
|
||||||
isRunnable = true
|
|
||||||
) {
|
|
||||||
NativePostProcessing.move(index, 1)
|
|
||||||
NativePostProcessing.persist()
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
add(
|
|
||||||
RunnableSetting(
|
|
||||||
titleId = R.string.post_processing_reset,
|
|
||||||
isRunnable = true
|
|
||||||
) {
|
|
||||||
NativePostProcessing.resetValues(index)
|
|
||||||
NativePostProcessing.persist()
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
add(
|
|
||||||
RunnableSetting(
|
|
||||||
titleId = R.string.post_processing_remove,
|
|
||||||
isRunnable = true
|
|
||||||
) {
|
|
||||||
NativePostProcessing.remove(index)
|
|
||||||
NativePostProcessing.persist()
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
add(
|
|
||||||
RunnableSetting(
|
|
||||||
titleId = R.string.post_processing_add,
|
|
||||||
isRunnable = true
|
|
||||||
) {
|
|
||||||
NativePostProcessing.append(files[0], techniques[0])
|
|
||||||
NativePostProcessing.persist()
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun buildSlotSelector(
|
|
||||||
index: Int,
|
|
||||||
entry: NativePostProcessing.ChainEntry,
|
|
||||||
files: List<String>,
|
|
||||||
techniques: List<String>
|
|
||||||
): AbstractIntSetting = object : AbstractIntSetting {
|
|
||||||
override val key = "fx_slot_$index"
|
|
||||||
|
|
||||||
override fun getInt(needsGlobal: Boolean): Int {
|
|
||||||
for (i in files.indices) {
|
|
||||||
if (files[i] == entry.file && techniques[i] == entry.technique) {
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setInt(value: Int) {
|
|
||||||
NativePostProcessing.replace(index, files[value], techniques[value])
|
|
||||||
NativePostProcessing.persist()
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
override val defaultValue = 0
|
|
||||||
override fun getValueAsString(needsGlobal: Boolean): String = getInt().toString()
|
|
||||||
override fun reset() {}
|
|
||||||
override val isRuntimeModifiable = true
|
|
||||||
override val pairedSettingKey = ""
|
|
||||||
override val isSwitchable = false
|
|
||||||
override val isSaveable = true
|
|
||||||
override var global: Boolean
|
|
||||||
get() = true
|
|
||||||
set(_) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addUniform(
|
|
||||||
sl: ArrayList<SettingsItem>,
|
|
||||||
index: Int,
|
|
||||||
uniform: NativePostProcessing.Uniform
|
|
||||||
) {
|
|
||||||
if (uniform.uiType == NativePostProcessing.UI_CHECKBOX ||
|
|
||||||
uniform.kind == NativePostProcessing.KIND_BOOL
|
|
||||||
) {
|
|
||||||
sl.add(
|
|
||||||
SwitchSetting(
|
|
||||||
FxUniformBooleanSetting(index, uniform, 0),
|
|
||||||
titleString = uniform.label,
|
|
||||||
descriptionString = uniform.tooltip
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uniform.items.isNotEmpty() &&
|
|
||||||
(uniform.uiType == NativePostProcessing.UI_COMBO ||
|
|
||||||
uniform.uiType == NativePostProcessing.UI_RADIO)
|
|
||||||
) {
|
|
||||||
sl.add(
|
|
||||||
IntSingleChoiceSetting(
|
|
||||||
FxUniformChoiceSetting(index, uniform, 0),
|
|
||||||
titleString = uniform.label,
|
|
||||||
descriptionString = uniform.tooltip,
|
|
||||||
choices = uniform.items.toTypedArray(),
|
|
||||||
values = uniform.items.indices.toList().toTypedArray()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for (component in 0 until uniform.components) {
|
|
||||||
var title = uniform.label
|
|
||||||
if (uniform.components > 1) {
|
|
||||||
title = uniform.label + " [" + component + "]"
|
|
||||||
}
|
|
||||||
sl.add(
|
|
||||||
SliderSetting(
|
|
||||||
FxUniformSliderSetting(index, uniform, component),
|
|
||||||
titleString = title,
|
|
||||||
descriptionString = uniform.tooltip,
|
|
||||||
min = 0,
|
|
||||||
max = uniform.steps
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun addConfigSettings(sl: ArrayList<SettingsItem>) {
|
private fun addConfigSettings(sl: ArrayList<SettingsItem>) {
|
||||||
sl.apply {
|
sl.apply {
|
||||||
add(
|
add(
|
||||||
@@ -1533,7 +1323,6 @@ class SettingsFragmentPresenter(
|
|||||||
add(HeaderSetting(R.string.log))
|
add(HeaderSetting(R.string.log))
|
||||||
|
|
||||||
add(BooleanSetting.DEBUG_FLUSH_BY_LINE.key)
|
add(BooleanSetting.DEBUG_FLUSH_BY_LINE.key)
|
||||||
add(BooleanSetting.EXTENDED_LOGGING.key)
|
|
||||||
add(StringSetting.LOG_FILTER.key)
|
add(StringSetting.LOG_FILTER.key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1194,10 +1194,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||||||
R.array.rendererAntiAliasingNames,
|
R.array.rendererAntiAliasingNames,
|
||||||
R.array.rendererAntiAliasingValues
|
R.array.rendererAntiAliasingValues
|
||||||
)
|
)
|
||||||
|
|
||||||
quickSettings.addPostProcessing(container) {
|
|
||||||
addQuickSettings()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -383,20 +383,6 @@ class GamePropertiesFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
add(
|
|
||||||
SubmenuProperty(
|
|
||||||
R.string.post_processing,
|
|
||||||
R.string.post_processing_per_game_description,
|
|
||||||
R.drawable.ic_post_processing,
|
|
||||||
action = {
|
|
||||||
val action = HomeNavigationDirections.actionGlobalSettingsActivity(
|
|
||||||
args.game,
|
|
||||||
Settings.MenuTag.SECTION_POST_PROCESSING
|
|
||||||
)
|
|
||||||
binding.root.findNavController().navigate(action)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (GpuDriverHelper.isAdrenoGpu()) {
|
if (GpuDriverHelper.isAdrenoGpu()) {
|
||||||
add(
|
add(
|
||||||
|
|||||||
@@ -171,20 +171,6 @@ class HomeSettingsFragment : Fragment() {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
add(
|
|
||||||
HomeSetting(
|
|
||||||
R.string.post_processing,
|
|
||||||
R.string.post_processing_description,
|
|
||||||
R.drawable.ic_post_processing,
|
|
||||||
{
|
|
||||||
val action = HomeNavigationDirections.actionGlobalSettingsActivity(
|
|
||||||
null,
|
|
||||||
Settings.MenuTag.SECTION_POST_PROCESSING
|
|
||||||
)
|
|
||||||
binding.root.findNavController().navigate(action)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
add(
|
add(
|
||||||
HomeSetting(
|
HomeSetting(
|
||||||
R.string.lossless_scaling,
|
R.string.lossless_scaling,
|
||||||
|
|||||||
@@ -1,183 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.utils
|
|
||||||
|
|
||||||
import org.json.JSONArray
|
|
||||||
import org.json.JSONObject
|
|
||||||
|
|
||||||
object NativePostProcessing {
|
|
||||||
const val KIND_BOOL = 0
|
|
||||||
const val KIND_INT = 1
|
|
||||||
const val KIND_FLOAT = 2
|
|
||||||
|
|
||||||
const val UI_HIDDEN = 0
|
|
||||||
const val UI_SLIDER = 1
|
|
||||||
const val UI_DRAG = 2
|
|
||||||
const val UI_COMBO = 3
|
|
||||||
const val UI_RADIO = 4
|
|
||||||
const val UI_CHECKBOX = 5
|
|
||||||
const val UI_COLOR = 6
|
|
||||||
const val UI_INPUT_BOX = 7
|
|
||||||
|
|
||||||
external fun getCatalogJson(): String
|
|
||||||
|
|
||||||
external fun getChainJson(): String
|
|
||||||
|
|
||||||
external fun append(file: String, technique: String)
|
|
||||||
|
|
||||||
external fun replace(index: Int, file: String, technique: String)
|
|
||||||
|
|
||||||
external fun remove(index: Int)
|
|
||||||
|
|
||||||
external fun move(index: Int, delta: Int)
|
|
||||||
|
|
||||||
external fun resetValues(index: Int)
|
|
||||||
|
|
||||||
external fun getValue(index: Int, uniform: String, component: Int): Float
|
|
||||||
|
|
||||||
external fun hasValue(index: Int, uniform: String): Boolean
|
|
||||||
|
|
||||||
external fun setValue(index: Int, uniform: String, component: Int, value: Float)
|
|
||||||
|
|
||||||
external fun store()
|
|
||||||
|
|
||||||
fun persist() {
|
|
||||||
store()
|
|
||||||
NativeConfig.saveGlobalConfig()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
external fun getShaderDirectory(): String
|
|
||||||
|
|
||||||
data class Uniform(
|
|
||||||
val name: String,
|
|
||||||
val label: String,
|
|
||||||
val tooltip: String,
|
|
||||||
val category: String,
|
|
||||||
val kind: Int,
|
|
||||||
val uiType: Int,
|
|
||||||
val components: Int,
|
|
||||||
val min: Float,
|
|
||||||
val max: Float,
|
|
||||||
val step: Float,
|
|
||||||
val items: List<String>,
|
|
||||||
val defaults: List<Float>
|
|
||||||
) {
|
|
||||||
val steps: Int
|
|
||||||
get() {
|
|
||||||
val span = max - min
|
|
||||||
if (step <= 0f) {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
val count = Math.round(span / step)
|
|
||||||
if (count < 1) {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
return count
|
|
||||||
}
|
|
||||||
|
|
||||||
fun defaultAt(component: Int): Float {
|
|
||||||
if (component < defaults.size) {
|
|
||||||
return defaults[component]
|
|
||||||
}
|
|
||||||
return 0f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class Effect(
|
|
||||||
val file: String,
|
|
||||||
val name: String,
|
|
||||||
val label: String,
|
|
||||||
val description: String,
|
|
||||||
val error: String,
|
|
||||||
val techniques: List<String>,
|
|
||||||
val uniforms: List<Uniform>
|
|
||||||
) {
|
|
||||||
val valid: Boolean
|
|
||||||
get() = error.isEmpty() && techniques.isNotEmpty()
|
|
||||||
}
|
|
||||||
|
|
||||||
data class ChainEntry(val file: String, val technique: String)
|
|
||||||
|
|
||||||
fun catalog(): List<Effect> {
|
|
||||||
val out = mutableListOf<Effect>()
|
|
||||||
val array = JSONArray(getCatalogJson())
|
|
||||||
for (i in 0 until array.length()) {
|
|
||||||
val obj = array.getJSONObject(i)
|
|
||||||
out.add(
|
|
||||||
Effect(
|
|
||||||
file = obj.optString("file"),
|
|
||||||
name = obj.optString("name"),
|
|
||||||
label = obj.optString("label"),
|
|
||||||
description = obj.optString("description"),
|
|
||||||
error = obj.optString("error"),
|
|
||||||
techniques = obj.optJSONArray("techniques").toStringList(),
|
|
||||||
uniforms = obj.optJSONArray("uniforms").toUniformList()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
fun chain(): List<ChainEntry> {
|
|
||||||
val out = mutableListOf<ChainEntry>()
|
|
||||||
val array = JSONArray(getChainJson())
|
|
||||||
for (i in 0 until array.length()) {
|
|
||||||
val obj = array.getJSONObject(i)
|
|
||||||
out.add(ChainEntry(obj.optString("file"), obj.optString("technique")))
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
fun findEffect(file: String): Effect? = catalog().firstOrNull { it.file == file }
|
|
||||||
|
|
||||||
private fun JSONArray?.toStringList(): List<String> {
|
|
||||||
if (this == null) {
|
|
||||||
return emptyList()
|
|
||||||
}
|
|
||||||
val out = mutableListOf<String>()
|
|
||||||
for (i in 0 until length()) {
|
|
||||||
out.add(optString(i))
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun JSONArray?.toFloatList(): List<Float> {
|
|
||||||
if (this == null) {
|
|
||||||
return emptyList()
|
|
||||||
}
|
|
||||||
val out = mutableListOf<Float>()
|
|
||||||
for (i in 0 until length()) {
|
|
||||||
out.add(optDouble(i, 0.0).toFloat())
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun JSONArray?.toUniformList(): List<Uniform> {
|
|
||||||
if (this == null) {
|
|
||||||
return emptyList()
|
|
||||||
}
|
|
||||||
val out = mutableListOf<Uniform>()
|
|
||||||
for (i in 0 until length()) {
|
|
||||||
val obj: JSONObject = optJSONObject(i) ?: continue
|
|
||||||
out.add(
|
|
||||||
Uniform(
|
|
||||||
name = obj.optString("name"),
|
|
||||||
label = obj.optString("label"),
|
|
||||||
tooltip = obj.optString("tooltip"),
|
|
||||||
category = obj.optString("category"),
|
|
||||||
kind = obj.optInt("kind", KIND_FLOAT),
|
|
||||||
uiType = obj.optInt("uiType", UI_HIDDEN),
|
|
||||||
components = obj.optInt("components", 1),
|
|
||||||
min = obj.optDouble("min", 0.0).toFloat(),
|
|
||||||
max = obj.optDouble("max", 1.0).toFloat(),
|
|
||||||
step = obj.optDouble("step", 0.01).toFloat(),
|
|
||||||
items = obj.optJSONArray("items").toStringList(),
|
|
||||||
defaults = obj.optJSONArray("defaults").toFloatList()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -17,7 +17,6 @@ add_library(yuzu-android SHARED
|
|||||||
android_config.cpp
|
android_config.cpp
|
||||||
android_config.h
|
android_config.h
|
||||||
native_input.cpp
|
native_input.cpp
|
||||||
native_post_processing.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR})
|
set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR})
|
||||||
|
|||||||
@@ -1,215 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <jni.h>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
#include "common/android/android_common.h"
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
#include "video_core/post_processing/fx_chain.h"
|
|
||||||
#include "video_core/post_processing/fx_effect.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
nlohmann::json SerializeUniform(const VideoCore::FxUniformDesc& uniform) {
|
|
||||||
nlohmann::json out;
|
|
||||||
out["name"] = uniform.name;
|
|
||||||
out["label"] = uniform.label;
|
|
||||||
out["tooltip"] = uniform.tooltip;
|
|
||||||
out["category"] = uniform.category;
|
|
||||||
out["kind"] = static_cast<int>(uniform.kind);
|
|
||||||
out["uiType"] = static_cast<int>(uniform.ui_type);
|
|
||||||
out["components"] = uniform.components;
|
|
||||||
out["min"] = uniform.ui_min;
|
|
||||||
out["max"] = uniform.ui_max;
|
|
||||||
out["step"] = uniform.ui_step;
|
|
||||||
out["items"] = uniform.items;
|
|
||||||
|
|
||||||
nlohmann::json defaults = nlohmann::json::array();
|
|
||||||
for (u32 i = 0; i < uniform.components; ++i) {
|
|
||||||
defaults.push_back(uniform.default_value[i]);
|
|
||||||
}
|
|
||||||
out["defaults"] = defaults;
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<f32, 4> DefaultValueOf(size_t index, const std::string& uniform) {
|
|
||||||
const auto entries = VideoCore::FxChain::Instance().Entries();
|
|
||||||
if (index >= entries.size()) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
const VideoCore::FxEffectDesc* effect = VideoCore::FindFxEffect(entries[index].file);
|
|
||||||
if (effect == nullptr) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
const VideoCore::FxUniformDesc* desc = VideoCore::FindFxUniform(*effect, uniform);
|
|
||||||
if (desc == nullptr) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
return desc->default_value;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} // Anonymous namespace
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
|
|
||||||
jstring Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_getCatalogJson(JNIEnv* env,
|
|
||||||
jobject obj) {
|
|
||||||
nlohmann::json out = nlohmann::json::array();
|
|
||||||
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
VideoCore::FxChain::Instance().DropUnknownEntries();
|
|
||||||
|
|
||||||
for (const auto& effect : VideoCore::GetFxCatalog()) {
|
|
||||||
nlohmann::json entry;
|
|
||||||
entry["file"] = effect.file;
|
|
||||||
entry["name"] = effect.name;
|
|
||||||
entry["label"] = effect.label;
|
|
||||||
entry["description"] = effect.description;
|
|
||||||
entry["error"] = effect.error;
|
|
||||||
entry["techniques"] = effect.techniques;
|
|
||||||
|
|
||||||
nlohmann::json uniforms = nlohmann::json::array();
|
|
||||||
for (const auto& uniform : effect.uniforms) {
|
|
||||||
uniforms.push_back(SerializeUniform(uniform));
|
|
||||||
}
|
|
||||||
entry["uniforms"] = uniforms;
|
|
||||||
|
|
||||||
out.push_back(entry);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return Common::Android::ToJString(env, out.dump());
|
|
||||||
}
|
|
||||||
|
|
||||||
jstring Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_getChainJson(JNIEnv* env, jobject obj) {
|
|
||||||
nlohmann::json out = nlohmann::json::array();
|
|
||||||
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
for (const auto& entry : VideoCore::FxChain::Instance().Entries()) {
|
|
||||||
nlohmann::json item;
|
|
||||||
item["file"] = entry.file;
|
|
||||||
item["technique"] = entry.technique;
|
|
||||||
|
|
||||||
nlohmann::json values = nlohmann::json::object();
|
|
||||||
for (const auto& [name, value] : entry.values) {
|
|
||||||
values[name] = {value[0], value[1], value[2], value[3]};
|
|
||||||
}
|
|
||||||
item["values"] = values;
|
|
||||||
|
|
||||||
out.push_back(item);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return Common::Android::ToJString(env, out.dump());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_append(JNIEnv* env, jobject obj,
|
|
||||||
jstring jfile, jstring jtechnique) {
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
VideoCore::FxChain::Instance().Append(Common::Android::GetJString(env, jfile),
|
|
||||||
Common::Android::GetJString(env, jtechnique));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_replace(JNIEnv* env, jobject obj,
|
|
||||||
jint index, jstring jfile,
|
|
||||||
jstring jtechnique) {
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
VideoCore::FxChain::Instance().Replace(static_cast<size_t>(index),
|
|
||||||
Common::Android::GetJString(env, jfile),
|
|
||||||
Common::Android::GetJString(env, jtechnique));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_remove(JNIEnv* env, jobject obj,
|
|
||||||
jint index) {
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
VideoCore::FxChain::Instance().Remove(static_cast<size_t>(index));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_move(JNIEnv* env, jobject obj, jint index,
|
|
||||||
jint delta) {
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
VideoCore::FxChain::Instance().Move(static_cast<size_t>(index), delta);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_resetValues(JNIEnv* env, jobject obj,
|
|
||||||
jint index) {
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
VideoCore::FxChain::Instance().ResetValues(static_cast<size_t>(index));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
jfloat Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_getValue(JNIEnv* env, jobject obj,
|
|
||||||
jint index, jstring juniform,
|
|
||||||
jint component) {
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
if (component < 0 || component >= 4) {
|
|
||||||
return 0.0f;
|
|
||||||
}
|
|
||||||
const auto value = VideoCore::FxChain::Instance().GetValue(
|
|
||||||
static_cast<size_t>(index), Common::Android::GetJString(env, juniform));
|
|
||||||
return value[static_cast<size_t>(component)];
|
|
||||||
#else
|
|
||||||
return 0.0f;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
jboolean Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_hasValue(JNIEnv* env, jobject obj,
|
|
||||||
jint index,
|
|
||||||
jstring juniform) {
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
return static_cast<jboolean>(VideoCore::FxChain::Instance().HasValue(
|
|
||||||
static_cast<size_t>(index), Common::Android::GetJString(env, juniform)));
|
|
||||||
#else
|
|
||||||
return static_cast<jboolean>(false);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_setValue(JNIEnv* env, jobject obj,
|
|
||||||
jint index, jstring juniform,
|
|
||||||
jint component, jfloat value) {
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
if (component < 0 || component >= 4) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const std::string uniform = Common::Android::GetJString(env, juniform);
|
|
||||||
auto& chain = VideoCore::FxChain::Instance();
|
|
||||||
const auto slot = static_cast<size_t>(index);
|
|
||||||
|
|
||||||
auto current = chain.GetValue(slot, uniform);
|
|
||||||
if (!chain.HasValue(slot, uniform)) {
|
|
||||||
current = DefaultValueOf(slot, uniform);
|
|
||||||
}
|
|
||||||
|
|
||||||
current[static_cast<size_t>(component)] = value;
|
|
||||||
chain.SetValue(slot, uniform, current);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_store(JNIEnv* env, jobject obj) {
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
VideoCore::FxChain::Instance().StoreToSettings();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
jstring Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_getShaderDirectory(JNIEnv* env,
|
|
||||||
jobject obj) {
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
return Common::Android::ToJString(env, VideoCore::GetFxRootDirectory().string());
|
|
||||||
#else
|
|
||||||
return Common::Android::ToJString(env, "");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
} // extern "C"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="24"
|
|
||||||
android:viewportHeight="24">
|
|
||||||
<path
|
|
||||||
android:fillColor="?attr/colorControlNormal"
|
|
||||||
android:fillType="evenOdd"
|
|
||||||
android:pathData="M8.5,3 L19.4,3 Q21,3 21,4.6 L21,16.5 L19.4,16.5 L19.4,4.6 L8.5,4.6 Z M5,7 L15,7 Q17,7 17,9 L17,19 Q17,21 15,21 L5,21 Q3,21 3,19 L3,9 Q3,7 5,7 Z M5.2,8.6 L14.8,8.6 Q15.4,8.6 15.4,9.2 L15.4,18.8 Q15.4,19.4 14.8,19.4 L5.2,19.4 Q4.6,19.4 4.6,18.8 L4.6,9.2 Q4.6,8.6 5.2,8.6 Z M10,10.9 A3.1,3.1 0 0 1 10,17.1 Z"/>
|
|
||||||
</vector>
|
|
||||||
@@ -298,17 +298,6 @@
|
|||||||
<string name="gpu_driver_fetcher">GPU driver fetcher</string>
|
<string name="gpu_driver_fetcher">GPU driver fetcher</string>
|
||||||
<string name="gpu_driver_manager">GPU driver manager</string>
|
<string name="gpu_driver_manager">GPU driver manager</string>
|
||||||
<string name="install_gpu_driver_description">Install alternative drivers for potentially better performance or accuracy</string>
|
<string name="install_gpu_driver_description">Install alternative drivers for potentially better performance or accuracy</string>
|
||||||
<string name="post_processing">Post-Processing Effects</string>
|
|
||||||
<string name="post_processing_description">ReShade FX effects applied after rendering</string>
|
|
||||||
<string name="post_processing_per_game_description">Configure the effect chain for this game</string>
|
|
||||||
<string name="post_processing_effect">Effect</string>
|
|
||||||
<string name="post_processing_none">None</string>
|
|
||||||
<string name="post_processing_add">Add effect</string>
|
|
||||||
<string name="post_processing_remove">Remove</string>
|
|
||||||
<string name="post_processing_move_up">Move up</string>
|
|
||||||
<string name="post_processing_move_down">Move down</string>
|
|
||||||
<string name="post_processing_reset">Reset to defaults</string>
|
|
||||||
<string name="post_processing_empty">No effects found. Place .fx files in this folder:</string>
|
|
||||||
<string name="frame_gen">Frame generation</string>
|
<string name="frame_gen">Frame generation</string>
|
||||||
<string name="frame_gen_per_game_description">Configure frame generation for this game</string>
|
<string name="frame_gen_per_game_description">Configure frame generation for this game</string>
|
||||||
<string name="frame_gen_description">Insert interpolated frames between rendered ones using Lossless Scaling. Forces FIFO presentation while enabled.</string>
|
<string name="frame_gen_description">Insert interpolated frames between rendered ones using Lossless Scaling. Forces FIFO presentation while enabled.</string>
|
||||||
@@ -647,8 +636,6 @@
|
|||||||
<string name="log">Logging</string>
|
<string name="log">Logging</string>
|
||||||
<string name="flush_by_line">Flush debug logs by line</string>
|
<string name="flush_by_line">Flush debug logs by line</string>
|
||||||
<string name="flush_by_line_description">Flushes debugging logs on each line written, making debugging easier in cases of crashing or freezing.</string>
|
<string name="flush_by_line_description">Flushes debugging logs on each line written, making debugging easier in cases of crashing or freezing.</string>
|
||||||
<string name="extended_logging">Enable extended logging</string>
|
|
||||||
<string name="extended_logging_description">Increases the maximum log file size from 100 MiB to 1 GiB.</string>
|
|
||||||
<string name="log_filter">Log filter</string>
|
<string name="log_filter">Log filter</string>
|
||||||
<string name="log_filter_description">Controls Eden\'s log categories. Example: *:Info Service.LM:Debug</string>
|
<string name="log_filter_description">Controls Eden\'s log categories. Example: *:Info Service.LM:Debug</string>
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <cstdlib>
|
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <llvm/Demangle/Demangle.h>
|
#include <llvm/Demangle/Demangle.h>
|
||||||
|
|||||||
@@ -23,7 +23,6 @@
|
|||||||
#define LOSSLESS_DIR "lossless"
|
#define LOSSLESS_DIR "lossless"
|
||||||
#define NAND_DIR "nand"
|
#define NAND_DIR "nand"
|
||||||
#define PLAY_TIME_DIR "play_time"
|
#define PLAY_TIME_DIR "play_time"
|
||||||
#define POST_SHADER_DIR "post_shaders"
|
|
||||||
#define SCREENSHOTS_DIR "screenshots"
|
#define SCREENSHOTS_DIR "screenshots"
|
||||||
#define SDMC_DIR "sdmc"
|
#define SDMC_DIR "sdmc"
|
||||||
#define SHADER_DIR "shader"
|
#define SHADER_DIR "shader"
|
||||||
|
|||||||
@@ -160,7 +160,6 @@ public:
|
|||||||
GenerateEdenPath(EdenPath::LosslessDir, eden_path / LOSSLESS_DIR);
|
GenerateEdenPath(EdenPath::LosslessDir, eden_path / LOSSLESS_DIR);
|
||||||
GenerateEdenPath(EdenPath::NANDDir, eden_path / NAND_DIR);
|
GenerateEdenPath(EdenPath::NANDDir, eden_path / NAND_DIR);
|
||||||
GenerateEdenPath(EdenPath::PlayTimeDir, eden_path / PLAY_TIME_DIR);
|
GenerateEdenPath(EdenPath::PlayTimeDir, eden_path / PLAY_TIME_DIR);
|
||||||
GenerateEdenPath(EdenPath::PostShaderDir, eden_path / POST_SHADER_DIR);
|
|
||||||
GenerateEdenPath(EdenPath::SaveDir, eden_path / NAND_DIR);
|
GenerateEdenPath(EdenPath::SaveDir, eden_path / NAND_DIR);
|
||||||
GenerateEdenPath(EdenPath::ScreenshotsDir, eden_path / SCREENSHOTS_DIR);
|
GenerateEdenPath(EdenPath::ScreenshotsDir, eden_path / SCREENSHOTS_DIR);
|
||||||
GenerateEdenPath(EdenPath::SDMCDir, eden_path / SDMC_DIR);
|
GenerateEdenPath(EdenPath::SDMCDir, eden_path / SDMC_DIR);
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ enum class EdenPath {
|
|||||||
LosslessDir, // Where the user-supplied Lossless Scaling library is stored.
|
LosslessDir, // Where the user-supplied Lossless Scaling library is stored.
|
||||||
NANDDir, // Where the emulated NAND is stored.
|
NANDDir, // Where the emulated NAND is stored.
|
||||||
PlayTimeDir, // Where play time data is stored.
|
PlayTimeDir, // Where play time data is stored.
|
||||||
PostShaderDir, // Where user post-processing shaders are stored.
|
|
||||||
SaveDir, // Where save data is stored.
|
SaveDir, // Where save data is stored.
|
||||||
ScreenshotsDir, // Where yuzu screenshots are stored.
|
ScreenshotsDir, // Where yuzu screenshots are stored.
|
||||||
SDMCDir, // Where the emulated SDMC is stored.
|
SDMCDir, // Where the emulated SDMC is stored.
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
#include "common/make_unique_for_overwrite.h"
|
#include "common/make_unique_for_overwrite.h"
|
||||||
|
|
||||||
@@ -65,7 +61,7 @@ public:
|
|||||||
void resize(size_type size) {
|
void resize(size_type size) {
|
||||||
if (size > buffer_capacity) {
|
if (size > buffer_capacity) {
|
||||||
auto new_buffer = Common::make_unique_for_overwrite<T[]>(size);
|
auto new_buffer = Common::make_unique_for_overwrite<T[]>(size);
|
||||||
std::memcpy(new_buffer.get(), buffer.get(), buffer_capacity * sizeof(T));
|
std::move(buffer.get(), buffer.get() + buffer_capacity, new_buffer.get());
|
||||||
buffer = std::move(new_buffer);
|
buffer = std::move(new_buffer);
|
||||||
buffer_capacity = size;
|
buffer_capacity = size;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -388,14 +388,6 @@ struct Values {
|
|||||||
true,
|
true,
|
||||||
true};
|
true};
|
||||||
|
|
||||||
Setting<std::string> post_shader_chain{linkage,
|
|
||||||
std::string(),
|
|
||||||
"post_shader_chain",
|
|
||||||
Category::Renderer,
|
|
||||||
Specialization::Default,
|
|
||||||
true,
|
|
||||||
true};
|
|
||||||
|
|
||||||
SwitchableSetting<bool> frame_gen{linkage, false, "frame_gen", Category::Renderer,
|
SwitchableSetting<bool> frame_gen{linkage, false, "frame_gen", Category::Renderer,
|
||||||
Specialization::Default, true, false};
|
Specialization::Default, true, false};
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
|||||||
@@ -6,13 +6,13 @@
|
|||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include <boost/version.hpp>
|
#include <boost/version.hpp>
|
||||||
|
|
||||||
#if BOOST_VERSION > 108400 && (!defined(_WINDOWS) && !defined(__ANDROID__)) || defined(YUZU_BOOST_v1)
|
#if BOOST_VERSION > 108400 && (!defined(_WINDOWS) && !defined(__ANDROID__)) || defined(YUZU_BOOST_v1)
|
||||||
#define USE_BOOST_v1
|
#define USE_BOOST_v1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_BOOST_v1
|
#ifdef USE_BOOST_v1
|
||||||
#include <boost/process/v1/async_pipe.hpp>
|
#include <boost/process/v1/async_pipe.hpp>
|
||||||
#else
|
#else
|
||||||
@@ -358,7 +358,7 @@ private:
|
|||||||
|
|
||||||
ConnectionState(boost::asio::ip::tcp::socket&& client_socket_, async_pipe signal_pipe_, Kernel::KernelCore& kernel)
|
ConnectionState(boost::asio::ip::tcp::socket&& client_socket_, async_pipe signal_pipe_, Kernel::KernelCore& kernel)
|
||||||
: client_socket{std::move(client_socket_)}
|
: client_socket{std::move(client_socket_)}
|
||||||
, signal_pipe{std::move(signal_pipe_)}
|
, signal_pipe{signal_pipe_}
|
||||||
, active_thread{kernel, nullptr}
|
, active_thread{kernel, nullptr}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
@@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <type_traits>
|
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
|
|
||||||
namespace FileSys {
|
namespace FileSys {
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
#include "common/literals.h"
|
#include "common/literals.h"
|
||||||
#include "core/file_sys/fssystem/fs_i_storage.h"
|
#include "core/file_sys/fssystem/fs_i_storage.h"
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <type_traits>
|
|
||||||
#include "core/file_sys/errors.h"
|
#include "core/file_sys/errors.h"
|
||||||
#include "core/file_sys/fssystem/fssystem_bucket_tree.h"
|
#include "core/file_sys/fssystem/fssystem_bucket_tree.h"
|
||||||
#include "core/file_sys/fssystem/fssystem_bucket_tree_utils.h"
|
#include "core/file_sys/fssystem/fssystem_bucket_tree_utils.h"
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
#include "common/alignment.h"
|
#include "common/alignment.h"
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
@@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <type_traits>
|
|
||||||
#include "core/file_sys/errors.h"
|
#include "core/file_sys/errors.h"
|
||||||
#include "core/file_sys/fssystem/fssystem_bucket_tree.h"
|
#include "core/file_sys/fssystem/fssystem_bucket_tree.h"
|
||||||
#include "core/file_sys/fssystem/fssystem_bucket_tree_utils.h"
|
#include "core/file_sys/fssystem/fssystem_bucket_tree_utils.h"
|
||||||
|
|||||||
@@ -6,8 +6,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <type_traits>
|
|
||||||
#include <cstddef>
|
|
||||||
#include "common/literals.h"
|
#include "common/literals.h"
|
||||||
|
|
||||||
#include "core/file_sys/errors.h"
|
#include "core/file_sys/errors.h"
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <type_traits>
|
|
||||||
#include "common/alignment.h"
|
#include "common/alignment.h"
|
||||||
#include "core/file_sys/fssystem/fs_i_storage.h"
|
#include "core/file_sys/fssystem/fs_i_storage.h"
|
||||||
#include "core/file_sys/fssystem/fs_types.h"
|
#include "core/file_sys/fssystem/fs_types.h"
|
||||||
|
|||||||
@@ -6,9 +6,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <type_traits>
|
|
||||||
#include <array>
|
|
||||||
#include <cstddef>
|
|
||||||
#include "core/file_sys/errors.h"
|
#include "core/file_sys/errors.h"
|
||||||
#include "core/file_sys/fssystem/fs_i_storage.h"
|
#include "core/file_sys/fssystem/fs_i_storage.h"
|
||||||
#include "core/file_sys/fssystem/fssystem_bucket_tree.h"
|
#include "core/file_sys/fssystem/fssystem_bucket_tree.h"
|
||||||
|
|||||||
@@ -1,15 +1,9 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <array>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
#include "core/file_sys/fssystem/fs_i_storage.h"
|
#include "core/file_sys/fssystem/fs_i_storage.h"
|
||||||
#include "core/file_sys/fssystem/fs_types.h"
|
#include "core/file_sys/fssystem/fs_types.h"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
@@ -6,8 +6,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <type_traits>
|
|
||||||
#include <cstddef>
|
|
||||||
#include "core/file_sys/fssystem/fssystem_compression_common.h"
|
#include "core/file_sys/fssystem/fssystem_compression_common.h"
|
||||||
#include "core/file_sys/fssystem/fssystem_nca_header.h"
|
#include "core/file_sys/fssystem/fssystem_nca_header.h"
|
||||||
#include "core/file_sys/vfs/vfs.h"
|
#include "core/file_sys/vfs/vfs.h"
|
||||||
|
|||||||
@@ -1,14 +1,8 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <type_traits>
|
|
||||||
#include <array>
|
|
||||||
#include <cstddef>
|
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/literals.h"
|
#include "common/literals.h"
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/page_table.h"
|
#include "common/page_table.h"
|
||||||
|
|||||||
@@ -1021,9 +1021,6 @@ Result KProcess::Run(KernelCore& kernel, s32 priority, size_t stack_size) {
|
|||||||
|
|
||||||
// Suspend for debug, if we should.
|
// Suspend for debug, if we should.
|
||||||
if (kernel.System().DebuggerEnabled()) {
|
if (kernel.System().DebuggerEnabled()) {
|
||||||
LOG_INFO(Debug_GDBStub,
|
|
||||||
"GDB stub enabled; suspending guest process until a debugger continues execution on port {}",
|
|
||||||
Settings::values.gdbstub_port.GetValue());
|
|
||||||
main_thread->RequestSuspend(kernel, SuspendType::Debug);
|
main_thread->RequestSuspend(kernel, SuspendType::Debug);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <type_traits>
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/bit_field.h"
|
#include "common/bit_field.h"
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <type_traits>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
|
|||||||
@@ -175,10 +175,19 @@ Result AlbumManager::LoadAlbumScreenShotImage(LoadAlbumScreenShotImageOutput& ou
|
|||||||
return ResultIsNotMounted;
|
return ResultIsNotMounted;
|
||||||
}
|
}
|
||||||
|
|
||||||
out_image_output = {};
|
out_image_output = {
|
||||||
out_image_output.width = 1280;
|
.width = 1280,
|
||||||
out_image_output.height = 720;
|
.height = 720,
|
||||||
out_image_output.attribute.orientation = AlbumImageOrientation::None;
|
.attribute =
|
||||||
|
{
|
||||||
|
.unknown_0{},
|
||||||
|
.orientation = AlbumImageOrientation::None,
|
||||||
|
.unknown_1{},
|
||||||
|
.unknown_2{},
|
||||||
|
.pad163{},
|
||||||
|
},
|
||||||
|
.pad179{},
|
||||||
|
};
|
||||||
|
|
||||||
std::filesystem::path path;
|
std::filesystem::path path;
|
||||||
const auto result = GetFile(path, file_id);
|
const auto result = GetFile(path, file_id);
|
||||||
@@ -202,10 +211,19 @@ Result AlbumManager::LoadAlbumScreenShotThumbnail(
|
|||||||
return ResultIsNotMounted;
|
return ResultIsNotMounted;
|
||||||
}
|
}
|
||||||
|
|
||||||
out_image_output = {};
|
out_image_output = {
|
||||||
out_image_output.width = 320;
|
.width = 320,
|
||||||
out_image_output.height = 180;
|
.height = 180,
|
||||||
out_image_output.attribute.orientation = AlbumImageOrientation::None;
|
.attribute =
|
||||||
|
{
|
||||||
|
.unknown_0{},
|
||||||
|
.orientation = AlbumImageOrientation::None,
|
||||||
|
.unknown_1{},
|
||||||
|
.unknown_2{},
|
||||||
|
.pad163{},
|
||||||
|
},
|
||||||
|
.pad179{},
|
||||||
|
};
|
||||||
|
|
||||||
std::filesystem::path path;
|
std::filesystem::path path;
|
||||||
const auto result = GetFile(path, file_id);
|
const auto result = GetFile(path, file_id);
|
||||||
|
|||||||
@@ -73,8 +73,13 @@ void IScreenShotApplicationService::CaptureAndSaveScreenshot(AlbumReportOption r
|
|||||||
Layout::FramebufferLayout layout =
|
Layout::FramebufferLayout layout =
|
||||||
Layout::DefaultFrameLayout(screenshot_width, screenshot_height);
|
Layout::DefaultFrameLayout(screenshot_width, screenshot_height);
|
||||||
|
|
||||||
Capture::ScreenShotAttribute attribute{};
|
const Capture::ScreenShotAttribute attribute{
|
||||||
attribute.orientation = Capture::AlbumImageOrientation::None;
|
.unknown_0{},
|
||||||
|
.orientation = Capture::AlbumImageOrientation::None,
|
||||||
|
.unknown_1{},
|
||||||
|
.unknown_2{},
|
||||||
|
.pad163{},
|
||||||
|
};
|
||||||
|
|
||||||
renderer.RequestScreenshot(
|
renderer.RequestScreenshot(
|
||||||
image_data.data(),
|
image_data.data(),
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <type_traits>
|
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||||
@@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <type_traits>
|
|
||||||
#include <fmt/ranges.h>
|
#include <fmt/ranges.h>
|
||||||
|
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <type_traits>
|
|
||||||
#include <fmt/ranges.h>
|
#include <fmt/ranges.h>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <type_traits>
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/hle/service/psc/time/common.h"
|
#include "core/hle/service/psc/time/common.h"
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
#include "common/bit_field.h"
|
#include "common/bit_field.h"
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
|
|||||||
@@ -1,15 +1,8 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <array>
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
#include "common/bit_field.h"
|
#include "common/bit_field.h"
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|||||||
@@ -150,7 +150,6 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent) {
|
|||||||
INSERT(Settings, anti_aliasing, tr("Anti-Aliasing Method:"),
|
INSERT(Settings, anti_aliasing, tr("Anti-Aliasing Method:"),
|
||||||
tr("The anti-aliasing method to use.\nSMAA offers the best quality.\nFXAA "
|
tr("The anti-aliasing method to use.\nSMAA offers the best quality.\nFXAA "
|
||||||
"can produce a more stable picture in lower resolutions."));
|
"can produce a more stable picture in lower resolutions."));
|
||||||
INSERT(Settings, post_shader_chain, QString(), QString());
|
|
||||||
INSERT(Settings, fullscreen_mode, tr("Fullscreen Mode:"),
|
INSERT(Settings, fullscreen_mode, tr("Fullscreen Mode:"),
|
||||||
tr("The method used to render the window in fullscreen.\nBorderless offers the best "
|
tr("The method used to render the window in fullscreen.\nBorderless offers the best "
|
||||||
"compatibility with the on-screen keyboard that some games request for "
|
"compatibility with the on-screen keyboard that some games request for "
|
||||||
|
|||||||
@@ -6,6 +6,55 @@
|
|||||||
|
|
||||||
add_library(shader_recompiler STATIC
|
add_library(shader_recompiler STATIC
|
||||||
backend/bindings.h
|
backend/bindings.h
|
||||||
|
backend/glasm/emit_glasm.cpp
|
||||||
|
backend/glasm/emit_glasm.h
|
||||||
|
backend/glasm/emit_glasm_barriers.cpp
|
||||||
|
backend/glasm/emit_glasm_bitwise_conversion.cpp
|
||||||
|
backend/glasm/emit_glasm_composite.cpp
|
||||||
|
backend/glasm/emit_glasm_context_get_set.cpp
|
||||||
|
backend/glasm/emit_glasm_control_flow.cpp
|
||||||
|
backend/glasm/emit_glasm_convert.cpp
|
||||||
|
backend/glasm/emit_glasm_floating_point.cpp
|
||||||
|
backend/glasm/emit_glasm_image.cpp
|
||||||
|
backend/glasm/emit_glasm_instructions.h
|
||||||
|
backend/glasm/emit_glasm_integer.cpp
|
||||||
|
backend/glasm/emit_glasm_logical.cpp
|
||||||
|
backend/glasm/emit_glasm_memory.cpp
|
||||||
|
backend/glasm/emit_glasm_not_implemented.cpp
|
||||||
|
backend/glasm/emit_glasm_select.cpp
|
||||||
|
backend/glasm/emit_glasm_shared_memory.cpp
|
||||||
|
backend/glasm/emit_glasm_special.cpp
|
||||||
|
backend/glasm/emit_glasm_undefined.cpp
|
||||||
|
backend/glasm/emit_glasm_warp.cpp
|
||||||
|
backend/glasm/glasm_emit_context.cpp
|
||||||
|
backend/glasm/glasm_emit_context.h
|
||||||
|
backend/glasm/reg_alloc.cpp
|
||||||
|
backend/glasm/reg_alloc.h
|
||||||
|
backend/glsl/emit_glsl.cpp
|
||||||
|
backend/glsl/emit_glsl.h
|
||||||
|
backend/glsl/emit_glsl_atomic.cpp
|
||||||
|
backend/glsl/emit_glsl_barriers.cpp
|
||||||
|
backend/glsl/emit_glsl_bitwise_conversion.cpp
|
||||||
|
backend/glsl/emit_glsl_composite.cpp
|
||||||
|
backend/glsl/emit_glsl_context_get_set.cpp
|
||||||
|
backend/glsl/emit_glsl_control_flow.cpp
|
||||||
|
backend/glsl/emit_glsl_convert.cpp
|
||||||
|
backend/glsl/emit_glsl_floating_point.cpp
|
||||||
|
backend/glsl/emit_glsl_image.cpp
|
||||||
|
backend/glsl/emit_glsl_instructions.h
|
||||||
|
backend/glsl/emit_glsl_integer.cpp
|
||||||
|
backend/glsl/emit_glsl_logical.cpp
|
||||||
|
backend/glsl/emit_glsl_memory.cpp
|
||||||
|
backend/glsl/emit_glsl_not_implemented.cpp
|
||||||
|
backend/glsl/emit_glsl_select.cpp
|
||||||
|
backend/glsl/emit_glsl_shared_memory.cpp
|
||||||
|
backend/glsl/emit_glsl_special.cpp
|
||||||
|
backend/glsl/emit_glsl_undefined.cpp
|
||||||
|
backend/glsl/emit_glsl_warp.cpp
|
||||||
|
backend/glsl/glsl_emit_context.cpp
|
||||||
|
backend/glsl/glsl_emit_context.h
|
||||||
|
backend/glsl/var_alloc.cpp
|
||||||
|
backend/glsl/var_alloc.h
|
||||||
backend/spirv/emit_spirv.cpp
|
backend/spirv/emit_spirv.cpp
|
||||||
backend/spirv/emit_spirv.h
|
backend/spirv/emit_spirv.h
|
||||||
backend/spirv/emit_spirv_atomic.cpp
|
backend/spirv/emit_spirv_atomic.cpp
|
||||||
@@ -190,60 +239,9 @@ add_library(shader_recompiler STATIC
|
|||||||
program_header.h
|
program_header.h
|
||||||
runtime_info.h
|
runtime_info.h
|
||||||
shader_info.h
|
shader_info.h
|
||||||
varying_state.h)
|
varying_state.h
|
||||||
|
|
||||||
if (ENABLE_OPENGL)
|
)
|
||||||
target_sources(shader_recompiler PRIVATE
|
|
||||||
backend/glasm/emit_glasm.cpp
|
|
||||||
backend/glasm/emit_glasm.h
|
|
||||||
backend/glasm/emit_glasm_barriers.cpp
|
|
||||||
backend/glasm/emit_glasm_bitwise_conversion.cpp
|
|
||||||
backend/glasm/emit_glasm_composite.cpp
|
|
||||||
backend/glasm/emit_glasm_context_get_set.cpp
|
|
||||||
backend/glasm/emit_glasm_control_flow.cpp
|
|
||||||
backend/glasm/emit_glasm_convert.cpp
|
|
||||||
backend/glasm/emit_glasm_floating_point.cpp
|
|
||||||
backend/glasm/emit_glasm_image.cpp
|
|
||||||
backend/glasm/emit_glasm_instructions.h
|
|
||||||
backend/glasm/emit_glasm_integer.cpp
|
|
||||||
backend/glasm/emit_glasm_logical.cpp
|
|
||||||
backend/glasm/emit_glasm_memory.cpp
|
|
||||||
backend/glasm/emit_glasm_not_implemented.cpp
|
|
||||||
backend/glasm/emit_glasm_select.cpp
|
|
||||||
backend/glasm/emit_glasm_shared_memory.cpp
|
|
||||||
backend/glasm/emit_glasm_special.cpp
|
|
||||||
backend/glasm/emit_glasm_undefined.cpp
|
|
||||||
backend/glasm/emit_glasm_warp.cpp
|
|
||||||
backend/glasm/glasm_emit_context.cpp
|
|
||||||
backend/glasm/glasm_emit_context.h
|
|
||||||
backend/glasm/reg_alloc.cpp
|
|
||||||
backend/glasm/reg_alloc.h
|
|
||||||
backend/glsl/emit_glsl.cpp
|
|
||||||
backend/glsl/emit_glsl.h
|
|
||||||
backend/glsl/emit_glsl_atomic.cpp
|
|
||||||
backend/glsl/emit_glsl_barriers.cpp
|
|
||||||
backend/glsl/emit_glsl_bitwise_conversion.cpp
|
|
||||||
backend/glsl/emit_glsl_composite.cpp
|
|
||||||
backend/glsl/emit_glsl_context_get_set.cpp
|
|
||||||
backend/glsl/emit_glsl_control_flow.cpp
|
|
||||||
backend/glsl/emit_glsl_convert.cpp
|
|
||||||
backend/glsl/emit_glsl_floating_point.cpp
|
|
||||||
backend/glsl/emit_glsl_image.cpp
|
|
||||||
backend/glsl/emit_glsl_instructions.h
|
|
||||||
backend/glsl/emit_glsl_integer.cpp
|
|
||||||
backend/glsl/emit_glsl_logical.cpp
|
|
||||||
backend/glsl/emit_glsl_memory.cpp
|
|
||||||
backend/glsl/emit_glsl_not_implemented.cpp
|
|
||||||
backend/glsl/emit_glsl_select.cpp
|
|
||||||
backend/glsl/emit_glsl_shared_memory.cpp
|
|
||||||
backend/glsl/emit_glsl_special.cpp
|
|
||||||
backend/glsl/emit_glsl_undefined.cpp
|
|
||||||
backend/glsl/emit_glsl_warp.cpp
|
|
||||||
backend/glsl/glsl_emit_context.cpp
|
|
||||||
backend/glsl/glsl_emit_context.h
|
|
||||||
backend/glsl/var_alloc.cpp
|
|
||||||
backend/glsl/var_alloc.h)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_link_libraries(shader_recompiler PUBLIC common fmt::fmt sirit::sirit)
|
target_link_libraries(shader_recompiler PUBLIC common fmt::fmt sirit::sirit)
|
||||||
|
|
||||||
|
|||||||
@@ -553,6 +553,17 @@ void GlobalMemoryToStorageBufferPass(IR::Program& program, const HostTranslateIn
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Descriptors, typename Descriptor, typename Func>
|
||||||
|
static u32 Add(Descriptors& descriptors, const Descriptor& desc, Func&& pred) {
|
||||||
|
// TODO: Handle arrays
|
||||||
|
const auto it{std::ranges::find_if(descriptors, pred)};
|
||||||
|
if (it != descriptors.end()) {
|
||||||
|
return static_cast<u32>(std::distance(descriptors.begin(), it));
|
||||||
|
}
|
||||||
|
descriptors.push_back(desc);
|
||||||
|
return static_cast<u32>(descriptors.size()) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
void JoinStorageInfo(Info& base, Info& source) {
|
void JoinStorageInfo(Info& base, Info& source) {
|
||||||
auto& descriptors = base.storage_buffers_descriptors;
|
auto& descriptors = base.storage_buffers_descriptors;
|
||||||
for (auto& desc : source.storage_buffers_descriptors) {
|
for (auto& desc : source.storage_buffers_descriptors) {
|
||||||
|
|||||||
@@ -299,35 +299,6 @@ if (ENABLE_LSFG)
|
|||||||
target_compile_definitions(video_core PUBLIC HAS_LSFG)
|
target_compile_definitions(video_core PUBLIC HAS_LSFG)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ENABLE_RESHADE)
|
|
||||||
set(BUNDLED_FX_DIR ${CMAKE_SOURCE_DIR}/dist/post_shaders)
|
|
||||||
set(BUNDLED_FX_HEADER ${CMAKE_CURRENT_BINARY_DIR}/bundled_fx_effects.h)
|
|
||||||
file(GLOB BUNDLED_FX_FILES ${BUNDLED_FX_DIR}/*.fx)
|
|
||||||
|
|
||||||
add_custom_command(
|
|
||||||
OUTPUT ${BUNDLED_FX_HEADER}
|
|
||||||
COMMAND ${CMAKE_COMMAND} -P
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/post_processing/GenerateBundledEffects.cmake
|
|
||||||
${BUNDLED_FX_DIR} ${BUNDLED_FX_HEADER}
|
|
||||||
DEPENDS ${BUNDLED_FX_FILES}
|
|
||||||
)
|
|
||||||
|
|
||||||
target_sources(video_core PRIVATE
|
|
||||||
post_processing/fx_chain.cpp
|
|
||||||
post_processing/fx_chain.h
|
|
||||||
post_processing/fx_compile.cpp
|
|
||||||
post_processing/fx_compile.h
|
|
||||||
post_processing/fx_effect.cpp
|
|
||||||
post_processing/fx_effect.h
|
|
||||||
renderer_vulkan/present/post_process.cpp
|
|
||||||
renderer_vulkan/present/post_process.h
|
|
||||||
${BUNDLED_FX_HEADER}
|
|
||||||
)
|
|
||||||
target_include_directories(video_core PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
|
||||||
target_link_libraries(video_core PRIVATE reshadefx::reshadefx)
|
|
||||||
target_compile_definitions(video_core PUBLIC HAS_RESHADE)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (ENABLE_OPENGL)
|
if (ENABLE_OPENGL)
|
||||||
target_sources(video_core PRIVATE
|
target_sources(video_core PRIVATE
|
||||||
renderer_opengl/present/filters.cpp
|
renderer_opengl/present/filters.cpp
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ namespace VideoCommon {
|
|||||||
|
|
||||||
enum class BufferFlagBits {
|
enum class BufferFlagBits {
|
||||||
Picked = 1 << 0,
|
Picked = 1 << 0,
|
||||||
CachedWrites = 1 << 1,
|
|
||||||
PreemtiveDownload = 1 << 2,
|
|
||||||
};
|
};
|
||||||
DECLARE_ENUM_FLAG_OPERATORS(BufferFlagBits)
|
DECLARE_ENUM_FLAG_OPERATORS(BufferFlagBits)
|
||||||
|
|
||||||
@@ -58,15 +56,6 @@ public:
|
|||||||
flags |= BufferFlagBits::Picked;
|
flags |= BufferFlagBits::Picked;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MarkPreemtiveDownload() noexcept {
|
|
||||||
flags |= BufferFlagBits::PreemtiveDownload;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unmark buffer as picked
|
|
||||||
void Unpick() noexcept {
|
|
||||||
flags &= ~BufferFlagBits::Picked;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Increases the likeliness of this being a stream buffer
|
/// Increases the likeliness of this being a stream buffer
|
||||||
void IncreaseStreamScore(int score) noexcept {
|
void IncreaseStreamScore(int score) noexcept {
|
||||||
stream_score += score;
|
stream_score += score;
|
||||||
@@ -87,15 +76,6 @@ public:
|
|||||||
return True(flags & BufferFlagBits::Picked);
|
return True(flags & BufferFlagBits::Picked);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true when the buffer has pending cached writes
|
|
||||||
[[nodiscard]] bool HasCachedWrites() const noexcept {
|
|
||||||
return True(flags & BufferFlagBits::CachedWrites);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsPreemtiveDownload() const noexcept {
|
|
||||||
return True(flags & BufferFlagBits::PreemtiveDownload);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the base CPU address of the buffer
|
/// Returns the base CPU address of the buffer
|
||||||
[[nodiscard]] VAddr CpuAddr() const noexcept {
|
[[nodiscard]] VAddr CpuAddr() const noexcept {
|
||||||
return cpu_addr;
|
return cpu_addr;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <limits>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
|
||||||
@@ -121,25 +122,6 @@ void BufferCache<P>::WriteMemory(DAddr device_addr, u64 size) {
|
|||||||
memory_tracker.MarkRegionAsCpuModified(device_addr, size);
|
memory_tracker.MarkRegionAsCpuModified(device_addr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class P>
|
|
||||||
void BufferCache<P>::CachedWriteMemory(DAddr device_addr, u64 size) {
|
|
||||||
const bool is_dirty = IsRegionRegistered(device_addr, size);
|
|
||||||
if (!is_dirty) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
DAddr aligned_start = Common::AlignDown(device_addr, DEVICE_PAGESIZE);
|
|
||||||
DAddr aligned_end = Common::AlignUp(device_addr + size, DEVICE_PAGESIZE);
|
|
||||||
if (!IsRegionGpuModified(aligned_start, aligned_end - aligned_start)) {
|
|
||||||
WriteMemory(device_addr, size);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp_buffer.resize_destructive(size);
|
|
||||||
device_memory.ReadBlockUnsafe(device_addr, tmp_buffer.data(), size);
|
|
||||||
|
|
||||||
InlineMemoryImplementation(device_addr, size, tmp_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class P>
|
template <class P>
|
||||||
bool BufferCache<P>::OnCPUWrite(DAddr device_addr, u64 size) {
|
bool BufferCache<P>::OnCPUWrite(DAddr device_addr, u64 size) {
|
||||||
const bool is_dirty = IsRegionRegistered(device_addr, size);
|
const bool is_dirty = IsRegionRegistered(device_addr, size);
|
||||||
@@ -422,7 +404,7 @@ void BufferCache<P>::UnbindGraphicsStorageBuffers(size_t stage) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class P>
|
template <class P>
|
||||||
bool BufferCache<P>::BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index, u32 cbuf_index,
|
void BufferCache<P>::BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index, u32 cbuf_index,
|
||||||
u32 cbuf_offset, bool is_written) {
|
u32 cbuf_offset, bool is_written) {
|
||||||
const bool already_enabled =
|
const bool already_enabled =
|
||||||
((channel_state->enabled_storage_buffers[stage] >> ssbo_index) & 1U) != 0;
|
((channel_state->enabled_storage_buffers[stage] >> ssbo_index) & 1U) != 0;
|
||||||
@@ -433,7 +415,7 @@ bool BufferCache<P>::BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index,
|
|||||||
LOG_WARNING(HW_GPU,
|
LOG_WARNING(HW_GPU,
|
||||||
"Skipping graphics storage buffer {} due to driver limit {}",
|
"Skipping graphics storage buffer {} due to driver limit {}",
|
||||||
ssbo_index, max_bindings);
|
ssbo_index, max_bindings);
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -449,7 +431,6 @@ bool BufferCache<P>::BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index,
|
|||||||
const GPUVAddr ssbo_addr = cbufs.const_buffers[cbuf_index].address + cbuf_offset;
|
const GPUVAddr ssbo_addr = cbufs.const_buffers[cbuf_index].address + cbuf_offset;
|
||||||
channel_state->storage_buffers[stage][ssbo_index] =
|
channel_state->storage_buffers[stage][ssbo_index] =
|
||||||
StorageBufferBinding(ssbo_addr, cbuf_index, is_written);
|
StorageBufferBinding(ssbo_addr, cbuf_index, is_written);
|
||||||
return (channel_state->storage_buffers[stage][ssbo_index].buffer_id != NULL_BUFFER_ID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class P>
|
template <class P>
|
||||||
@@ -762,16 +743,6 @@ void BufferCache<P>::BindHostIndexBuffer() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class P>
|
|
||||||
void BufferCache<P>::BindHostVertexBuffer(u32 index, Buffer& buffer, u32 offset, u32 size,
|
|
||||||
u32 stride) {
|
|
||||||
if constexpr (IS_OPENGL) {
|
|
||||||
runtime.BindVertexBuffer(index, buffer, offset, size, stride);
|
|
||||||
} else {
|
|
||||||
runtime.BindVertexBuffer(index, buffer.Handle(), offset, size, stride);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class P>
|
template <class P>
|
||||||
Binding& BufferCache<P>::VertexBufferSlot(u32 index) {
|
Binding& BufferCache<P>::VertexBufferSlot(u32 index) {
|
||||||
ASSERT(index < NUM_VERTEX_BUFFERS);
|
ASSERT(index < NUM_VERTEX_BUFFERS);
|
||||||
@@ -1197,7 +1168,7 @@ void BufferCache<P>::DoUpdateGraphicsBuffers(bool is_indexed) {
|
|||||||
if (is_indexed) {
|
if (is_indexed) {
|
||||||
UpdateIndexBuffer();
|
UpdateIndexBuffer();
|
||||||
}
|
}
|
||||||
UpdateVertexBuffers();
|
UpdateVertexBuffers(is_indexed);
|
||||||
UpdateTransformFeedbackBuffers();
|
UpdateTransformFeedbackBuffers();
|
||||||
for (size_t stage = 0; stage < NUM_STAGES; ++stage) {
|
for (size_t stage = 0; stage < NUM_STAGES; ++stage) {
|
||||||
UpdateUniformBuffers(stage);
|
UpdateUniformBuffers(stage);
|
||||||
@@ -1251,9 +1222,14 @@ void BufferCache<P>::UpdateIndexBuffer() {
|
|||||||
const GPUVAddr gpu_addr_begin = index_buffer_ref.StartAddress();
|
const GPUVAddr gpu_addr_begin = index_buffer_ref.StartAddress();
|
||||||
const GPUVAddr gpu_addr_end = index_buffer_ref.EndAddress();
|
const GPUVAddr gpu_addr_end = index_buffer_ref.EndAddress();
|
||||||
const std::optional<DAddr> device_addr = gpu_memory->GpuToCpuAddress(gpu_addr_begin);
|
const std::optional<DAddr> device_addr = gpu_memory->GpuToCpuAddress(gpu_addr_begin);
|
||||||
const u32 address_size = static_cast<u32>(gpu_addr_end - gpu_addr_begin);
|
u64 address_size = 0;
|
||||||
const u32 draw_size = (index_buffer_ref.count + index_buffer_ref.first) * u32(index_buffer_ref.FormatSizeInBytes());
|
if (gpu_addr_end > gpu_addr_begin) {
|
||||||
const u32 size = (std::min)(address_size, draw_size);
|
address_size = (std::min)(gpu_addr_end - gpu_addr_begin,
|
||||||
|
u64{(std::numeric_limits<u32>::max)()});
|
||||||
|
}
|
||||||
|
const u64 draw_size = (u64{index_buffer_ref.count} + u64{index_buffer_ref.first}) *
|
||||||
|
u64{index_buffer_ref.FormatSizeInBytes()};
|
||||||
|
const u32 size = static_cast<u32>((std::min)(address_size, draw_size));
|
||||||
if (size == 0 || !device_addr) {
|
if (size == 0 || !device_addr) {
|
||||||
channel_state->index_buffer = NULL_BINDING;
|
channel_state->index_buffer = NULL_BINDING;
|
||||||
return;
|
return;
|
||||||
@@ -1266,20 +1242,142 @@ void BufferCache<P>::UpdateIndexBuffer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class P>
|
template <class P>
|
||||||
void BufferCache<P>::UpdateVertexBuffers() {
|
u64 BufferCache<P>::DrawMaxIndex() {
|
||||||
|
if (max_index_scanned) {
|
||||||
|
return cached_max_index;
|
||||||
|
}
|
||||||
|
max_index_scanned = true;
|
||||||
|
cached_max_index = 0;
|
||||||
|
const auto& index_buffer_ref = maxwell3d->draw_manager.draw_state.index_buffer;
|
||||||
|
const u32 count = index_buffer_ref.count;
|
||||||
|
if (count == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
index_scan_buffer.resize_destructive(count);
|
||||||
|
gpu_memory->ReadBlockUnsafe(index_buffer_ref.IndexStart(), index_scan_buffer.data(),
|
||||||
|
size_t{count} * sizeof(u32));
|
||||||
|
u32 restart_index = (std::numeric_limits<u32>::max)();
|
||||||
|
if (maxwell3d->regs.primitive_restart.enabled != 0) {
|
||||||
|
restart_index = maxwell3d->regs.primitive_restart.index;
|
||||||
|
}
|
||||||
|
u32 max_index = 0;
|
||||||
|
for (u32 i = 0; i < count; ++i) {
|
||||||
|
const u32 value = index_scan_buffer[i];
|
||||||
|
if (value == restart_index) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
max_index = (std::max)(max_index, value);
|
||||||
|
}
|
||||||
|
cached_max_index = max_index;
|
||||||
|
return cached_max_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class P>
|
||||||
|
u64 BufferCache<P>::StreamAttributeExtent(u32 index) {
|
||||||
|
using VertexAttribute = typename Maxwell::VertexAttribute;
|
||||||
|
if (stream_extents_valid) {
|
||||||
|
return stream_extents[index];
|
||||||
|
}
|
||||||
|
stream_extents_valid = true;
|
||||||
|
stream_extents.fill(0);
|
||||||
|
for (size_t i = 0; i < Maxwell::NumVertexAttributes; ++i) {
|
||||||
|
const auto& attribute = maxwell3d->regs.vertex_attrib_format[i];
|
||||||
|
if (attribute.constant != 0 || attribute.size == VertexAttribute::Size::Invalid) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const u32 buffer = attribute.buffer.Value();
|
||||||
|
if (buffer >= NUM_VERTEX_BUFFERS) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const u64 end = static_cast<u64>(attribute.offset.Value()) +
|
||||||
|
static_cast<u64>(attribute.SizeInBytes());
|
||||||
|
stream_extents[buffer] = (std::max)(stream_extents[buffer], end);
|
||||||
|
}
|
||||||
|
return stream_extents[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class P>
|
||||||
|
u64 BufferCache<P>::DrawVertexBound(u32 index, bool is_indexed) {
|
||||||
|
const auto& array = maxwell3d->regs.vertex_streams[index];
|
||||||
|
if (array.enable == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const u64 extent = StreamAttributeExtent(index);
|
||||||
|
if (extent == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const u64 stride = static_cast<u64>(array.stride);
|
||||||
|
if (stride == 0) {
|
||||||
|
return extent;
|
||||||
|
}
|
||||||
|
const auto& draw_state = maxwell3d->draw_manager.draw_state;
|
||||||
|
u64 elements = 0;
|
||||||
|
if (maxwell3d->regs.vertex_stream_instances.IsInstancingEnabled(index)) {
|
||||||
|
if (draw_instance_count == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const u64 base_instance = static_cast<u64>(draw_state.base_instance);
|
||||||
|
elements = base_instance + 1;
|
||||||
|
if (array.frequency != 0) {
|
||||||
|
elements = (base_instance + static_cast<u64>(draw_instance_count) - 1) /
|
||||||
|
static_cast<u64>(array.frequency) +
|
||||||
|
1;
|
||||||
|
}
|
||||||
|
} else if (!is_indexed) {
|
||||||
|
elements = static_cast<u64>(draw_state.vertex_buffer.first) +
|
||||||
|
static_cast<u64>(draw_state.vertex_buffer.count);
|
||||||
|
} else {
|
||||||
|
const auto format = draw_state.index_buffer.format;
|
||||||
|
u64 max_index = 0xFF;
|
||||||
|
if (format == Maxwell::IndexFormat::UnsignedShort) {
|
||||||
|
max_index = 0xFFFF;
|
||||||
|
} else if (format != Maxwell::IndexFormat::UnsignedByte) {
|
||||||
|
const auto& limit = maxwell3d->regs.vertex_stream_limits[index];
|
||||||
|
const GPUVAddr gpu_addr_begin = array.Address();
|
||||||
|
const GPUVAddr gpu_addr_end = limit.Address() + 1;
|
||||||
|
if (gpu_addr_end <= gpu_addr_begin) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const bool walks = gpu_addr_end - gpu_addr_begin >= IMPLAUSIBLE_VERTEX_SIZE ||
|
||||||
|
!gpu_memory->IsWithinGPUAddressRange(gpu_addr_end);
|
||||||
|
if (!walks) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
max_index = DrawMaxIndex();
|
||||||
|
}
|
||||||
|
elements = static_cast<u64>(draw_state.base_index) + max_index + 1;
|
||||||
|
}
|
||||||
|
if (elements == 0) {
|
||||||
|
return extent;
|
||||||
|
}
|
||||||
|
return (elements - 1) * stride + extent;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class P>
|
||||||
|
void BufferCache<P>::UpdateVertexBuffers(bool is_indexed) {
|
||||||
auto& flags = maxwell3d->dirty.flags;
|
auto& flags = maxwell3d->dirty.flags;
|
||||||
|
max_index_scanned = false;
|
||||||
|
stream_extents_valid = false;
|
||||||
|
for (u32 index = 0; index < NUM_VERTEX_BUFFERS; ++index) {
|
||||||
|
const u64 bound = DrawVertexBound(index, is_indexed);
|
||||||
|
if (bound <= last_draw_bounds[index]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
flags[Dirty::VertexBuffer0 + index] = true;
|
||||||
|
flags[Dirty::VertexBuffers] = true;
|
||||||
|
}
|
||||||
if (!maxwell3d->dirty.flags[Dirty::VertexBuffers]) {
|
if (!maxwell3d->dirty.flags[Dirty::VertexBuffers]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
flags[Dirty::VertexBuffers] = false;
|
flags[Dirty::VertexBuffers] = false;
|
||||||
|
|
||||||
for (u32 index = 0; index < NUM_VERTEX_BUFFERS; ++index) {
|
for (u32 index = 0; index < NUM_VERTEX_BUFFERS; ++index) {
|
||||||
UpdateVertexBuffer(index);
|
UpdateVertexBuffer(index, is_indexed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class P>
|
template <class P>
|
||||||
void BufferCache<P>::UpdateVertexBuffer(u32 index) {
|
void BufferCache<P>::UpdateVertexBuffer(u32 index, bool is_indexed) {
|
||||||
if (!maxwell3d->dirty.flags[Dirty::VertexBuffer0 + index]) {
|
if (!maxwell3d->dirty.flags[Dirty::VertexBuffer0 + index]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1288,15 +1386,31 @@ void BufferCache<P>::UpdateVertexBuffer(u32 index) {
|
|||||||
const GPUVAddr gpu_addr_begin = array.Address();
|
const GPUVAddr gpu_addr_begin = array.Address();
|
||||||
const GPUVAddr gpu_addr_end = limit.Address() + 1;
|
const GPUVAddr gpu_addr_end = limit.Address() + 1;
|
||||||
const std::optional<DAddr> device_addr = gpu_memory->GpuToCpuAddress(gpu_addr_begin);
|
const std::optional<DAddr> device_addr = gpu_memory->GpuToCpuAddress(gpu_addr_begin);
|
||||||
const u32 address_size = static_cast<u32>(gpu_addr_end - gpu_addr_begin);
|
if (array.enable == 0 || !device_addr || gpu_addr_end <= gpu_addr_begin) {
|
||||||
u32 size = address_size; // TODO: Analyze stride and number of vertices
|
|
||||||
if (array.enable == 0 || size == 0 || !device_addr) {
|
|
||||||
channel_state->vertex_buffers[index] = NULL_BINDING;
|
channel_state->vertex_buffers[index] = NULL_BINDING;
|
||||||
UpdateVertexBufferSlot(index, NULL_BINDING);
|
UpdateVertexBufferSlot(index, NULL_BINDING);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!gpu_memory->IsWithinGPUAddressRange(gpu_addr_end) || size >= 64_MiB) {
|
// TODO: Analyze stride and number of vertices
|
||||||
size = static_cast<u32>(gpu_memory->MaxContinuousRange(gpu_addr_begin, size));
|
constexpr u64 implausible_size = IMPLAUSIBLE_VERTEX_SIZE;
|
||||||
|
u64 address_size = gpu_addr_end - gpu_addr_begin;
|
||||||
|
if (address_size > u64{(std::numeric_limits<u32>::max)()}) {
|
||||||
|
address_size = implausible_size;
|
||||||
|
}
|
||||||
|
const u64 draw_bound = DrawVertexBound(index, is_indexed);
|
||||||
|
last_draw_bounds[index] = (std::numeric_limits<u64>::max)();
|
||||||
|
if (draw_bound != 0) {
|
||||||
|
last_draw_bounds[index] = draw_bound;
|
||||||
|
address_size = (std::min)(address_size, draw_bound);
|
||||||
|
}
|
||||||
|
if (!gpu_memory->IsWithinGPUAddressRange(gpu_addr_end) || address_size >= implausible_size) {
|
||||||
|
address_size = gpu_memory->MaxContinuousRange(gpu_addr_begin, address_size);
|
||||||
|
}
|
||||||
|
const u32 size = static_cast<u32>(address_size);
|
||||||
|
if (size == 0) {
|
||||||
|
channel_state->vertex_buffers[index] = NULL_BINDING;
|
||||||
|
UpdateVertexBufferSlot(index, NULL_BINDING);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
const BufferId buffer_id = FindBuffer(*device_addr, size);
|
const BufferId buffer_id = FindBuffer(*device_addr, size);
|
||||||
const Binding binding{
|
const Binding binding{
|
||||||
@@ -1578,9 +1692,10 @@ template <class P>
|
|||||||
BufferId BufferCache<P>::CreateBuffer(DAddr device_addr, u32 wanted_size) {
|
BufferId BufferCache<P>::CreateBuffer(DAddr device_addr, u32 wanted_size) {
|
||||||
DAddr device_addr_end = Common::AlignUp(device_addr + wanted_size, CACHING_PAGESIZE);
|
DAddr device_addr_end = Common::AlignUp(device_addr + wanted_size, CACHING_PAGESIZE);
|
||||||
device_addr = Common::AlignDown(device_addr, CACHING_PAGESIZE);
|
device_addr = Common::AlignDown(device_addr, CACHING_PAGESIZE);
|
||||||
wanted_size = static_cast<u32>(device_addr_end - device_addr);
|
constexpr u64 max_buffer_size = u64{(std::numeric_limits<u32>::max)()};
|
||||||
|
wanted_size = static_cast<u32>((std::min)(device_addr_end - device_addr, max_buffer_size));
|
||||||
const OverlapResult overlap = ResolveOverlaps(device_addr, wanted_size);
|
const OverlapResult overlap = ResolveOverlaps(device_addr, wanted_size);
|
||||||
const u32 size = static_cast<u32>(overlap.end - overlap.begin);
|
const u32 size = static_cast<u32>((std::min)(overlap.end - overlap.begin, max_buffer_size));
|
||||||
const BufferId new_buffer_id = slot_buffers.insert(runtime, overlap.begin, size);
|
const BufferId new_buffer_id = slot_buffers.insert(runtime, overlap.begin, size);
|
||||||
auto& new_buffer = slot_buffers[new_buffer_id];
|
auto& new_buffer = slot_buffers[new_buffer_id];
|
||||||
const size_t size_bytes = new_buffer.SizeBytes();
|
const size_t size_bytes = new_buffer.SizeBytes();
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ constexpr u32 NUM_VERTEX_BUFFERS = 16;
|
|||||||
#else
|
#else
|
||||||
constexpr u32 NUM_VERTEX_BUFFERS = 32;
|
constexpr u32 NUM_VERTEX_BUFFERS = 32;
|
||||||
#endif
|
#endif
|
||||||
|
constexpr u64 IMPLAUSIBLE_VERTEX_SIZE = 64_MiB;
|
||||||
constexpr u32 NUM_TRANSFORM_FEEDBACK_BUFFERS = 4;
|
constexpr u32 NUM_TRANSFORM_FEEDBACK_BUFFERS = 4;
|
||||||
constexpr u32 NUM_GRAPHICS_UNIFORM_BUFFERS = 18;
|
constexpr u32 NUM_GRAPHICS_UNIFORM_BUFFERS = 18;
|
||||||
constexpr u32 NUM_COMPUTE_UNIFORM_BUFFERS = 8;
|
constexpr u32 NUM_COMPUTE_UNIFORM_BUFFERS = 8;
|
||||||
@@ -217,8 +218,6 @@ public:
|
|||||||
|
|
||||||
void WriteMemory(DAddr device_addr, u64 size);
|
void WriteMemory(DAddr device_addr, u64 size);
|
||||||
|
|
||||||
void CachedWriteMemory(DAddr device_addr, u64 size);
|
|
||||||
|
|
||||||
bool OnCPUWrite(DAddr device_addr, u64 size);
|
bool OnCPUWrite(DAddr device_addr, u64 size);
|
||||||
|
|
||||||
void DownloadMemory(DAddr device_addr, u64 size);
|
void DownloadMemory(DAddr device_addr, u64 size);
|
||||||
@@ -248,7 +247,7 @@ public:
|
|||||||
|
|
||||||
void UnbindGraphicsStorageBuffers(size_t stage);
|
void UnbindGraphicsStorageBuffers(size_t stage);
|
||||||
|
|
||||||
bool BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index, u32 cbuf_index, u32 cbuf_offset,
|
void BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index, u32 cbuf_index, u32 cbuf_offset,
|
||||||
bool is_written);
|
bool is_written);
|
||||||
|
|
||||||
void UnbindGraphicsTextureBuffers(size_t stage);
|
void UnbindGraphicsTextureBuffers(size_t stage);
|
||||||
@@ -309,6 +308,10 @@ public:
|
|||||||
current_draw_indirect = current_draw_indirect_;
|
current_draw_indirect = current_draw_indirect_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetDrawInstanceCount(u32 draw_instance_count_) {
|
||||||
|
draw_instance_count = draw_instance_count_;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::pair<Buffer*, u32> GetDrawIndirectCount();
|
[[nodiscard]] std::pair<Buffer*, u32> GetDrawIndirectCount();
|
||||||
|
|
||||||
[[nodiscard]] std::pair<Buffer*, u32> GetDrawIndirectBuffer();
|
[[nodiscard]] std::pair<Buffer*, u32> GetDrawIndirectBuffer();
|
||||||
@@ -376,8 +379,6 @@ private:
|
|||||||
|
|
||||||
void BindHostTransformFeedbackBuffers();
|
void BindHostTransformFeedbackBuffers();
|
||||||
|
|
||||||
void BindHostVertexBuffer(u32 index, Buffer& buffer, u32 offset, u32 size, u32 stride);
|
|
||||||
|
|
||||||
void BindHostComputeUniformBuffers();
|
void BindHostComputeUniformBuffers();
|
||||||
|
|
||||||
void BindHostComputeStorageBuffers();
|
void BindHostComputeStorageBuffers();
|
||||||
@@ -390,9 +391,15 @@ private:
|
|||||||
|
|
||||||
void UpdateIndexBuffer();
|
void UpdateIndexBuffer();
|
||||||
|
|
||||||
void UpdateVertexBuffers();
|
void UpdateVertexBuffers(bool is_indexed);
|
||||||
|
|
||||||
void UpdateVertexBuffer(u32 index);
|
void UpdateVertexBuffer(u32 index, bool is_indexed);
|
||||||
|
|
||||||
|
[[nodiscard]] u64 DrawVertexBound(u32 index, bool is_indexed);
|
||||||
|
|
||||||
|
[[nodiscard]] u64 DrawMaxIndex();
|
||||||
|
|
||||||
|
[[nodiscard]] u64 StreamAttributeExtent(u32 index);
|
||||||
|
|
||||||
void UpdateDrawIndirect();
|
void UpdateDrawIndirect();
|
||||||
|
|
||||||
@@ -484,6 +491,14 @@ private:
|
|||||||
|
|
||||||
const Tegra::Engines::Maxwell3D::DrawManager::IndirectParams* current_draw_indirect{};
|
const Tegra::Engines::Maxwell3D::DrawManager::IndirectParams* current_draw_indirect{};
|
||||||
|
|
||||||
|
u32 draw_instance_count = 0;
|
||||||
|
std::array<u64, NUM_VERTEX_BUFFERS> last_draw_bounds{};
|
||||||
|
Common::ScratchBuffer<u32> index_scan_buffer;
|
||||||
|
u64 cached_max_index = 0;
|
||||||
|
bool max_index_scanned = false;
|
||||||
|
std::array<u64, NUM_VERTEX_BUFFERS> stream_extents{};
|
||||||
|
bool stream_extents_valid = false;
|
||||||
|
|
||||||
u32 last_index_count = 0;
|
u32 last_index_count = 0;
|
||||||
|
|
||||||
u32 enabled_vertex_buffers_mask = 0;
|
u32 enabled_vertex_buffers_mask = 0;
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
#include "common/bit_field.h"
|
#include "common/bit_field.h"
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
|
|||||||
@@ -1,15 +1,8 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
#include "common/bit_field.h"
|
#include "common/bit_field.h"
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/scratch_buffer.h"
|
#include "common/scratch_buffer.h"
|
||||||
|
|||||||
@@ -206,6 +206,40 @@ foreach(VARIANT IN ITEMS ${SHADER_TYPE_VARIANTS})
|
|||||||
set(SHADER_HEADERS ${SHADER_HEADERS} ${VARIANT_HEADER_FILE})
|
set(SHADER_HEADERS ${SHADER_HEADERS} ${VARIANT_HEADER_FILE})
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
set(SHADER_DEFINE_VARIANTS
|
||||||
|
"block_linear_unswizzle_2d.comp|nonarrow|HAS_EXTENDED_TYPES=0"
|
||||||
|
"pitch_unswizzle.comp|nonarrow|HAS_EXTENDED_TYPES=0"
|
||||||
|
"block_linear_unswizzle_3d.comp|nonarrow|HAS_EXTENDED_TYPES=0"
|
||||||
|
)
|
||||||
|
|
||||||
|
foreach(VARIANT IN ITEMS ${SHADER_DEFINE_VARIANTS})
|
||||||
|
string(REPLACE "|" ";" VARIANT_PARTS ${VARIANT})
|
||||||
|
list(GET VARIANT_PARTS 0 VARIANT_FILENAME)
|
||||||
|
list(GET VARIANT_PARTS 1 VARIANT_SUFFIX)
|
||||||
|
list(GET VARIANT_PARTS 2 VARIANT_DEFINE)
|
||||||
|
|
||||||
|
set(VARIANT_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/${VARIANT_FILENAME})
|
||||||
|
get_filename_component(VARIANT_STEM ${VARIANT_FILENAME} NAME_WE)
|
||||||
|
get_filename_component(VARIANT_EXT ${VARIANT_FILENAME} EXT)
|
||||||
|
string(REPLACE "." "" VARIANT_EXT ${VARIANT_EXT})
|
||||||
|
set(VARIANT_NAME ${VARIANT_STEM}_${VARIANT_SUFFIX}_${VARIANT_EXT})
|
||||||
|
|
||||||
|
string(TOUPPER ${VARIANT_NAME}_SPV VARIANT_VARIABLE_NAME)
|
||||||
|
set(VARIANT_HEADER_FILE ${SHADER_DIR}/${VARIANT_NAME}_spv.h)
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT
|
||||||
|
${VARIANT_HEADER_FILE}
|
||||||
|
COMMAND
|
||||||
|
${GLSLANGVALIDATOR} -V ${QUIET_FLAG} -I"${FIDELITYFX_INCLUDE_DIR}" ${GLSL_FLAGS}
|
||||||
|
-D${VARIANT_DEFINE}
|
||||||
|
--variable-name ${VARIANT_VARIABLE_NAME} -o ${VARIANT_HEADER_FILE} ${VARIANT_SOURCE}
|
||||||
|
--target-env ${SPIR_V_VERSION}
|
||||||
|
MAIN_DEPENDENCY
|
||||||
|
${VARIANT_SOURCE}
|
||||||
|
)
|
||||||
|
set(SHADER_HEADERS ${SHADER_HEADERS} ${VARIANT_HEADER_FILE})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
foreach(FILEPATH IN ITEMS ${FIDELITYFX_FILES})
|
foreach(FILEPATH IN ITEMS ${FIDELITYFX_FILES})
|
||||||
get_filename_component(FILENAME ${FILEPATH} NAME)
|
get_filename_component(FILENAME ${FILEPATH} NAME)
|
||||||
string(REPLACE "." "_" HEADER_NAME ${FILENAME})
|
string(REPLACE "." "_" HEADER_NAME ${FILENAME})
|
||||||
|
|||||||
@@ -5,9 +5,13 @@
|
|||||||
|
|
||||||
#ifdef VULKAN
|
#ifdef VULKAN
|
||||||
|
|
||||||
|
#ifndef HAS_EXTENDED_TYPES
|
||||||
|
#define HAS_EXTENDED_TYPES 1
|
||||||
|
#endif
|
||||||
|
#if HAS_EXTENDED_TYPES
|
||||||
#extension GL_EXT_shader_16bit_storage : require
|
#extension GL_EXT_shader_16bit_storage : require
|
||||||
#extension GL_EXT_shader_8bit_storage : require
|
#extension GL_EXT_shader_8bit_storage : require
|
||||||
#define HAS_EXTENDED_TYPES 1
|
#endif
|
||||||
#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
|
#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
|
||||||
#define END_PUSH_CONSTANTS };
|
#define END_PUSH_CONSTANTS };
|
||||||
#define UNIFORM(n)
|
#define UNIFORM(n)
|
||||||
|
|||||||
@@ -5,9 +5,13 @@
|
|||||||
|
|
||||||
#ifdef VULKAN
|
#ifdef VULKAN
|
||||||
|
|
||||||
|
#ifndef HAS_EXTENDED_TYPES
|
||||||
|
#define HAS_EXTENDED_TYPES 1
|
||||||
|
#endif
|
||||||
|
#if HAS_EXTENDED_TYPES
|
||||||
#extension GL_EXT_shader_16bit_storage : require
|
#extension GL_EXT_shader_16bit_storage : require
|
||||||
#extension GL_EXT_shader_8bit_storage : require
|
#extension GL_EXT_shader_8bit_storage : require
|
||||||
#define HAS_EXTENDED_TYPES 1
|
#endif
|
||||||
#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
|
#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
|
||||||
#define END_PUSH_CONSTANTS };
|
#define END_PUSH_CONSTANTS };
|
||||||
#define UNIFORM(n)
|
#define UNIFORM(n)
|
||||||
|
|||||||
@@ -5,9 +5,13 @@
|
|||||||
|
|
||||||
#ifdef VULKAN
|
#ifdef VULKAN
|
||||||
|
|
||||||
|
#ifndef HAS_EXTENDED_TYPES
|
||||||
|
#define HAS_EXTENDED_TYPES 1
|
||||||
|
#endif
|
||||||
|
#if HAS_EXTENDED_TYPES
|
||||||
#extension GL_EXT_shader_16bit_storage : require
|
#extension GL_EXT_shader_16bit_storage : require
|
||||||
#extension GL_EXT_shader_8bit_storage : require
|
#extension GL_EXT_shader_8bit_storage : require
|
||||||
#define HAS_EXTENDED_TYPES 1
|
#endif
|
||||||
#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
|
#define BEGIN_PUSH_CONSTANTS layout(push_constant) uniform PushConstants {
|
||||||
#define END_PUSH_CONSTANTS };
|
#define END_PUSH_CONSTANTS };
|
||||||
#define UNIFORM(n)
|
#define UNIFORM(n)
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
set(EFFECT_DIR ${CMAKE_ARGV3})
|
|
||||||
set(HEADER_FILE ${CMAKE_ARGV4})
|
|
||||||
|
|
||||||
file(GLOB EFFECT_FILES ${EFFECT_DIR}/*.fx)
|
|
||||||
list(SORT EFFECT_FILES)
|
|
||||||
|
|
||||||
set(ENTRIES "")
|
|
||||||
foreach(EFFECT_FILE IN LISTS EFFECT_FILES)
|
|
||||||
get_filename_component(EFFECT_NAME ${EFFECT_FILE} NAME)
|
|
||||||
file(READ ${EFFECT_FILE} EFFECT_BODY)
|
|
||||||
|
|
||||||
string(REGEX REPLACE ";" "{{SEMICOLON}}" EFFECT_BODY "${EFFECT_BODY}")
|
|
||||||
string(REGEX REPLACE "\n" ";" EFFECT_BODY "${EFFECT_BODY}")
|
|
||||||
|
|
||||||
set(EFFECT_TEXT "")
|
|
||||||
foreach(LINE IN LISTS EFFECT_BODY)
|
|
||||||
string(CONCAT EFFECT_TEXT "${EFFECT_TEXT}" " R\"(${LINE}\n)\"\n")
|
|
||||||
endforeach()
|
|
||||||
string(REGEX REPLACE "{{SEMICOLON}}" ";" EFFECT_TEXT "${EFFECT_TEXT}")
|
|
||||||
|
|
||||||
string(CONCAT ENTRIES "${ENTRIES}"
|
|
||||||
" {\n \"${EFFECT_NAME}\",\n${EFFECT_TEXT} },\n")
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
get_filename_component(OUTPUT_DIR ${HEADER_FILE} DIRECTORY)
|
|
||||||
make_directory(${OUTPUT_DIR})
|
|
||||||
|
|
||||||
file(WRITE ${HEADER_FILE}
|
|
||||||
"// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string_view>
|
|
||||||
|
|
||||||
namespace VideoCore {
|
|
||||||
|
|
||||||
struct BundledFxEffect {
|
|
||||||
std::string_view name;
|
|
||||||
std::string_view source;
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr BundledFxEffect BUNDLED_FX_EFFECTS[]{
|
|
||||||
${ENTRIES}};
|
|
||||||
|
|
||||||
} // namespace VideoCore
|
|
||||||
")
|
|
||||||
@@ -1,301 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
#include <fmt/format.h>
|
|
||||||
|
|
||||||
#include "common/settings.h"
|
|
||||||
#include "video_core/post_processing/fx_chain.h"
|
|
||||||
#include "video_core/post_processing/fx_effect.h"
|
|
||||||
|
|
||||||
namespace VideoCore {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
std::vector<std::string_view> Split(std::string_view value, char separator) {
|
|
||||||
std::vector<std::string_view> out;
|
|
||||||
size_t start = 0;
|
|
||||||
while (start <= value.size()) {
|
|
||||||
size_t end = value.find(separator, start);
|
|
||||||
if (end == std::string_view::npos) {
|
|
||||||
end = value.size();
|
|
||||||
}
|
|
||||||
out.push_back(value.substr(start, end - start));
|
|
||||||
start = end + 1;
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsSerializableName(std::string_view value) {
|
|
||||||
return value.find_first_of(";|,=") == std::string_view::npos;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // Anonymous namespace
|
|
||||||
|
|
||||||
std::vector<FxChainEntry> ParseFxChain(std::string_view value) {
|
|
||||||
std::vector<FxChainEntry> parsed;
|
|
||||||
|
|
||||||
for (const std::string_view record : Split(value, ';')) {
|
|
||||||
if (record.empty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto fields = Split(record, '|');
|
|
||||||
if (fields.size() < 2 || fields[0].empty() || fields[1].empty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
FxChainEntry entry;
|
|
||||||
entry.file = std::string(fields[0]);
|
|
||||||
entry.technique = std::string(fields[1]);
|
|
||||||
|
|
||||||
if (fields.size() >= 3) {
|
|
||||||
for (const std::string_view assignment : Split(fields[2], ',')) {
|
|
||||||
const size_t equals = assignment.find('=');
|
|
||||||
if (equals == std::string_view::npos) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const std::string name(assignment.substr(0, equals));
|
|
||||||
if (name.empty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<f32, 4> components{};
|
|
||||||
size_t index = 0;
|
|
||||||
for (const std::string_view piece : Split(assignment.substr(equals + 1), '/')) {
|
|
||||||
if (index >= components.size()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
const std::string text(piece);
|
|
||||||
if (!text.empty()) {
|
|
||||||
components[index] = std::strtof(text.c_str(), nullptr);
|
|
||||||
}
|
|
||||||
++index;
|
|
||||||
}
|
|
||||||
entry.values.emplace(name, components);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
parsed.push_back(std::move(entry));
|
|
||||||
}
|
|
||||||
|
|
||||||
return parsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string SerializeFxChain(std::span<const FxChainEntry> entries) {
|
|
||||||
std::string out;
|
|
||||||
|
|
||||||
for (const auto& entry : entries) {
|
|
||||||
if (!IsSerializableName(entry.file) || !IsSerializableName(entry.technique)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!out.empty()) {
|
|
||||||
out += ';';
|
|
||||||
}
|
|
||||||
out += fmt::format("{}|{}|", entry.file, entry.technique);
|
|
||||||
|
|
||||||
bool first = true;
|
|
||||||
for (const auto& [name, value] : entry.values) {
|
|
||||||
if (!IsSerializableName(name)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!first) {
|
|
||||||
out += ',';
|
|
||||||
}
|
|
||||||
first = false;
|
|
||||||
out += name;
|
|
||||||
out += '=';
|
|
||||||
for (size_t i = 0; i < value.size(); ++i) {
|
|
||||||
if (i > 0) {
|
|
||||||
out += '/';
|
|
||||||
}
|
|
||||||
out += fmt::format("{}", value[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
FxChain& FxChain::Instance() {
|
|
||||||
static FxChain instance;
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
FxChainSnapshot FxChain::Snapshot() const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
return FxChainSnapshot{
|
|
||||||
.entries = entries,
|
|
||||||
.generation = generation.load(std::memory_order_relaxed),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<FxChainEntry> FxChain::Entries() const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
return entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t FxChain::Size() const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
return entries.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void FxChain::Append(std::string_view file, std::string_view technique) {
|
|
||||||
{
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
FxChainEntry entry;
|
|
||||||
entry.file = std::string(file);
|
|
||||||
entry.technique = std::string(technique);
|
|
||||||
entries.push_back(std::move(entry));
|
|
||||||
}
|
|
||||||
generation.fetch_add(1, std::memory_order_relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FxChain::Replace(size_t index, std::string_view file, std::string_view technique) {
|
|
||||||
{
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
if (index >= entries.size()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (entries[index].file == file && entries[index].technique == technique) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
FxChainEntry entry;
|
|
||||||
entry.file = std::string(file);
|
|
||||||
entry.technique = std::string(technique);
|
|
||||||
entries[index] = std::move(entry);
|
|
||||||
}
|
|
||||||
generation.fetch_add(1, std::memory_order_relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FxChain::Remove(size_t index) {
|
|
||||||
{
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
if (index >= entries.size()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
entries.erase(entries.begin() + static_cast<std::ptrdiff_t>(index));
|
|
||||||
}
|
|
||||||
generation.fetch_add(1, std::memory_order_relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FxChain::Move(size_t index, int delta) {
|
|
||||||
{
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
if (index >= entries.size()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const std::ptrdiff_t target = static_cast<std::ptrdiff_t>(index) + delta;
|
|
||||||
if (target < 0 || target >= static_cast<std::ptrdiff_t>(entries.size())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::swap(entries[index], entries[static_cast<size_t>(target)]);
|
|
||||||
}
|
|
||||||
generation.fetch_add(1, std::memory_order_relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FxChain::Clear() {
|
|
||||||
{
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
entries.clear();
|
|
||||||
}
|
|
||||||
generation.fetch_add(1, std::memory_order_relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FxChain::SetValue(size_t index, std::string_view uniform, const std::array<f32, 4>& value) {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
if (index >= entries.size()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
entries[index].values[std::string(uniform)] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<f32, 4> FxChain::GetValue(size_t index, std::string_view uniform) const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
if (index >= entries.size()) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
const auto it = entries[index].values.find(std::string(uniform));
|
|
||||||
if (it == entries[index].values.end()) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<std::string, std::array<f32, 4>> FxChain::EntryValues(size_t index) const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
if (index >= entries.size()) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
return entries[index].values;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FxChain::HasValue(size_t index, std::string_view uniform) const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
if (index >= entries.size()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return entries[index].values.contains(std::string(uniform));
|
|
||||||
}
|
|
||||||
|
|
||||||
void FxChain::ResetValues(size_t index) {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
if (index >= entries.size()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
entries[index].values.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void FxChain::LoadFromSettings() {
|
|
||||||
auto parsed = ParseFxChain(Settings::values.post_shader_chain.GetValue());
|
|
||||||
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
entries = std::move(parsed);
|
|
||||||
loaded = true;
|
|
||||||
generation.fetch_add(1, std::memory_order_relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FxChain::EnsureLoadedFromSettings() {
|
|
||||||
{
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
if (loaded) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LoadFromSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
void FxChain::StoreToSettings() const {
|
|
||||||
std::string serialized;
|
|
||||||
{
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
serialized = SerializeFxChain(entries);
|
|
||||||
}
|
|
||||||
Settings::values.post_shader_chain.SetValue(serialized);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FxChain::DropUnknownEntries() {
|
|
||||||
bool changed = false;
|
|
||||||
{
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
const auto removed = std::remove_if(entries.begin(), entries.end(), [](const FxChainEntry& entry) {
|
|
||||||
const FxEffectDesc* effect = FindFxEffect(entry.file);
|
|
||||||
if (effect == nullptr || !effect->Valid()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return std::find(effect->techniques.begin(), effect->techniques.end(),
|
|
||||||
entry.technique) == effect->techniques.end();
|
|
||||||
});
|
|
||||||
if (removed != entries.end()) {
|
|
||||||
entries.erase(removed, entries.end());
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (changed) {
|
|
||||||
generation.fetch_add(1, std::memory_order_relaxed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace VideoCore
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <atomic>
|
|
||||||
#include <map>
|
|
||||||
#include <mutex>
|
|
||||||
#include <span>
|
|
||||||
#include <string>
|
|
||||||
#include <string_view>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
|
|
||||||
namespace VideoCore {
|
|
||||||
|
|
||||||
struct FxChainEntry {
|
|
||||||
std::string file;
|
|
||||||
std::string technique;
|
|
||||||
std::map<std::string, std::array<f32, 4>> values;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FxChainSnapshot {
|
|
||||||
std::vector<FxChainEntry> entries;
|
|
||||||
u64 generation{};
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<FxChainEntry> ParseFxChain(std::string_view value);
|
|
||||||
|
|
||||||
std::string SerializeFxChain(std::span<const FxChainEntry> entries);
|
|
||||||
|
|
||||||
class FxChain {
|
|
||||||
public:
|
|
||||||
static FxChain& Instance();
|
|
||||||
|
|
||||||
FxChainSnapshot Snapshot() const;
|
|
||||||
|
|
||||||
std::vector<FxChainEntry> Entries() const;
|
|
||||||
|
|
||||||
size_t Size() const;
|
|
||||||
|
|
||||||
void Append(std::string_view file, std::string_view technique);
|
|
||||||
|
|
||||||
void Replace(size_t index, std::string_view file, std::string_view technique);
|
|
||||||
|
|
||||||
void Remove(size_t index);
|
|
||||||
|
|
||||||
void Move(size_t index, int delta);
|
|
||||||
|
|
||||||
void Clear();
|
|
||||||
|
|
||||||
void SetValue(size_t index, std::string_view uniform, const std::array<f32, 4>& value);
|
|
||||||
|
|
||||||
std::array<f32, 4> GetValue(size_t index, std::string_view uniform) const;
|
|
||||||
|
|
||||||
std::map<std::string, std::array<f32, 4>> EntryValues(size_t index) const;
|
|
||||||
|
|
||||||
bool HasValue(size_t index, std::string_view uniform) const;
|
|
||||||
|
|
||||||
void ResetValues(size_t index);
|
|
||||||
|
|
||||||
void LoadFromSettings();
|
|
||||||
|
|
||||||
void EnsureLoadedFromSettings();
|
|
||||||
|
|
||||||
void StoreToSettings() const;
|
|
||||||
|
|
||||||
void DropUnknownEntries();
|
|
||||||
|
|
||||||
private:
|
|
||||||
FxChain() = default;
|
|
||||||
|
|
||||||
mutable std::mutex mutex;
|
|
||||||
std::vector<FxChainEntry> entries;
|
|
||||||
bool loaded{};
|
|
||||||
std::atomic<u64> generation{1};
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace VideoCore
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include <memory>
|
|
||||||
#include <set>
|
|
||||||
|
|
||||||
#include "effect_codegen.hpp"
|
|
||||||
#include "effect_parser.hpp"
|
|
||||||
#include "effect_preprocessor.hpp"
|
|
||||||
|
|
||||||
#include "common/fs/fs.h"
|
|
||||||
#include "common/fs/fs_util.h"
|
|
||||||
#include "video_core/post_processing/fx_compile.h"
|
|
||||||
#include "video_core/post_processing/fx_effect.h"
|
|
||||||
|
|
||||||
namespace VideoCore {
|
|
||||||
|
|
||||||
FxCompileResult CompileFxEffect(const std::filesystem::path& path, u32 width, u32 height,
|
|
||||||
u32 color_bit_depth) {
|
|
||||||
FxCompileResult result;
|
|
||||||
|
|
||||||
if (!Common::FS::Exists(path)) {
|
|
||||||
result.error = "Effect file not found: " + Common::FS::PathToUTF8String(path);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
reshadefx::preprocessor preprocessor;
|
|
||||||
preprocessor.add_macro_definition("__RESHADE__", "60800");
|
|
||||||
preprocessor.add_macro_definition("__RESHADE_PERFORMANCE_MODE__", "1");
|
|
||||||
preprocessor.add_macro_definition("__RENDERER__", "0x20000");
|
|
||||||
preprocessor.add_macro_definition("__VENDOR__", "0");
|
|
||||||
preprocessor.add_macro_definition("__DEVICE__", "0");
|
|
||||||
preprocessor.add_macro_definition("__APPLICATION__", "0");
|
|
||||||
preprocessor.add_macro_definition("BUFFER_WIDTH", std::to_string(width));
|
|
||||||
preprocessor.add_macro_definition("BUFFER_HEIGHT", std::to_string(height));
|
|
||||||
preprocessor.add_macro_definition("BUFFER_RCP_WIDTH", "(1.0 / BUFFER_WIDTH)");
|
|
||||||
preprocessor.add_macro_definition("BUFFER_RCP_HEIGHT", "(1.0 / BUFFER_HEIGHT)");
|
|
||||||
preprocessor.add_macro_definition("BUFFER_COLOR_DEPTH", std::to_string(color_bit_depth));
|
|
||||||
preprocessor.add_macro_definition("BUFFER_COLOR_BIT_DEPTH", std::to_string(color_bit_depth));
|
|
||||||
|
|
||||||
for (const auto& include : GetFxIncludePaths(path)) {
|
|
||||||
preprocessor.add_include_path(include);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!preprocessor.append_file(path)) {
|
|
||||||
result.error = preprocessor.errors();
|
|
||||||
if (result.error.empty()) {
|
|
||||||
result.error = "Failed to preprocess " + Common::FS::PathToUTF8String(path);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<reshadefx::codegen> backend(
|
|
||||||
reshadefx::create_codegen_spirv(true, false, false, false, true));
|
|
||||||
|
|
||||||
reshadefx::parser parser;
|
|
||||||
if (!parser.parse(preprocessor.output(), backend.get())) {
|
|
||||||
result.error = parser.errors();
|
|
||||||
if (result.error.empty()) {
|
|
||||||
result.error = "Failed to parse " + Common::FS::PathToUTF8String(path);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
result.module = backend->module();
|
|
||||||
|
|
||||||
std::set<std::string> wanted;
|
|
||||||
for (const auto& technique : result.module.techniques) {
|
|
||||||
for (const auto& pass : technique.passes) {
|
|
||||||
if (!pass.vs_entry_point.empty()) {
|
|
||||||
wanted.insert(pass.vs_entry_point);
|
|
||||||
}
|
|
||||||
if (!pass.ps_entry_point.empty()) {
|
|
||||||
wanted.insert(pass.ps_entry_point);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& name : wanted) {
|
|
||||||
std::string binary;
|
|
||||||
std::string assembly;
|
|
||||||
std::string errors;
|
|
||||||
if (!backend->assemble_code_for_entry_point(name, binary, assembly, errors)) {
|
|
||||||
result.error = "Failed to assemble entry point '" + name + "': " + errors;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
if (binary.size() % sizeof(u32) != 0) {
|
|
||||||
result.error = "Entry point '" + name + "' produced a malformed SPIR-V module";
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<u32> words(binary.size() / sizeof(u32));
|
|
||||||
std::memcpy(words.data(), binary.data(), binary.size());
|
|
||||||
result.entry_points.emplace(name, std::move(words));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.entry_points.empty()) {
|
|
||||||
result.error = "Effect declares no usable entry points";
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace VideoCore
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <filesystem>
|
|
||||||
#include <map>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "effect_module.hpp"
|
|
||||||
|
|
||||||
namespace VideoCore {
|
|
||||||
|
|
||||||
struct FxCompileResult {
|
|
||||||
reshadefx::effect_module module;
|
|
||||||
std::map<std::string, std::vector<u32>> entry_points;
|
|
||||||
std::string error;
|
|
||||||
|
|
||||||
bool Succeeded() const {
|
|
||||||
return error.empty() && !entry_points.empty();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
FxCompileResult CompileFxEffect(const std::filesystem::path& path, u32 width, u32 height,
|
|
||||||
u32 color_bit_depth);
|
|
||||||
|
|
||||||
} // namespace VideoCore
|
|
||||||
@@ -1,307 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include "bundled_fx_effects.h"
|
|
||||||
#include "common/fs/file.h"
|
|
||||||
#include "common/fs/fs.h"
|
|
||||||
#include "common/fs/fs_util.h"
|
|
||||||
#include "common/fs/path_util.h"
|
|
||||||
#include "common/logging.h"
|
|
||||||
#include "video_core/post_processing/fx_compile.h"
|
|
||||||
#include "video_core/post_processing/fx_effect.h"
|
|
||||||
|
|
||||||
namespace VideoCore {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
constexpr u32 CATALOG_PROBE_WIDTH = 1280;
|
|
||||||
constexpr u32 CATALOG_PROBE_HEIGHT = 720;
|
|
||||||
constexpr u32 CATALOG_PROBE_DEPTH = 8;
|
|
||||||
|
|
||||||
std::vector<FxEffectDesc> catalog;
|
|
||||||
bool catalog_scanned = false;
|
|
||||||
|
|
||||||
const reshadefx::annotation* FindAnnotation(const std::vector<reshadefx::annotation>& annotations,
|
|
||||||
std::string_view name) {
|
|
||||||
const auto it = std::find_if(annotations.begin(), annotations.end(),
|
|
||||||
[&](const reshadefx::annotation& a) { return a.name == name; });
|
|
||||||
if (it == annotations.end()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return &*it;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string AnnotationString(const std::vector<reshadefx::annotation>& annotations,
|
|
||||||
std::string_view name) {
|
|
||||||
const reshadefx::annotation* a = FindAnnotation(annotations, name);
|
|
||||||
if (a == nullptr) {
|
|
||||||
return std::string();
|
|
||||||
}
|
|
||||||
return a->value.string_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AnnotationFloat(const std::vector<reshadefx::annotation>& annotations, std::string_view name,
|
|
||||||
f32& out) {
|
|
||||||
const reshadefx::annotation* a = FindAnnotation(annotations, name);
|
|
||||||
if (a == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (a->type.is_floating_point()) {
|
|
||||||
out = a->value.as_float[0];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (a->type.is_integral()) {
|
|
||||||
out = static_cast<f32>(a->value.as_int[0]);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
FxUiType ParseUiType(std::string_view value) {
|
|
||||||
if (value == "slider") {
|
|
||||||
return FxUiType::Slider;
|
|
||||||
}
|
|
||||||
if (value == "drag") {
|
|
||||||
return FxUiType::Drag;
|
|
||||||
}
|
|
||||||
if (value == "combo") {
|
|
||||||
return FxUiType::Combo;
|
|
||||||
}
|
|
||||||
if (value == "radio") {
|
|
||||||
return FxUiType::Radio;
|
|
||||||
}
|
|
||||||
if (value == "check" || value == "checkbox") {
|
|
||||||
return FxUiType::CheckBox;
|
|
||||||
}
|
|
||||||
if (value == "color") {
|
|
||||||
return FxUiType::Color;
|
|
||||||
}
|
|
||||||
if (value == "input") {
|
|
||||||
return FxUiType::InputBox;
|
|
||||||
}
|
|
||||||
return FxUiType::Hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> SplitItems(const std::string& items) {
|
|
||||||
std::vector<std::string> out;
|
|
||||||
std::string current;
|
|
||||||
for (const char c : items) {
|
|
||||||
if (c == '\0') {
|
|
||||||
out.push_back(current);
|
|
||||||
current.clear();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
current += c;
|
|
||||||
}
|
|
||||||
if (!current.empty()) {
|
|
||||||
out.push_back(current);
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
FxUniformDesc DescribeUniform(const reshadefx::uniform& info) {
|
|
||||||
FxUniformDesc desc;
|
|
||||||
desc.name = info.name;
|
|
||||||
desc.components = std::min<u32>(info.type.components(), 4);
|
|
||||||
|
|
||||||
if (info.type.is_boolean()) {
|
|
||||||
desc.kind = FxUniformKind::Boolean;
|
|
||||||
} else if (info.type.is_integral()) {
|
|
||||||
desc.kind = FxUniformKind::Integer;
|
|
||||||
} else {
|
|
||||||
desc.kind = FxUniformKind::Floating;
|
|
||||||
}
|
|
||||||
|
|
||||||
desc.label = AnnotationString(info.annotations, "ui_label");
|
|
||||||
if (desc.label.empty()) {
|
|
||||||
desc.label = info.name;
|
|
||||||
}
|
|
||||||
desc.tooltip = AnnotationString(info.annotations, "ui_tooltip");
|
|
||||||
desc.category = AnnotationString(info.annotations, "ui_category");
|
|
||||||
desc.ui_type = ParseUiType(AnnotationString(info.annotations, "ui_type"));
|
|
||||||
desc.items = SplitItems(AnnotationString(info.annotations, "ui_items"));
|
|
||||||
|
|
||||||
if (desc.kind == FxUniformKind::Boolean) {
|
|
||||||
desc.ui_min = 0.0f;
|
|
||||||
desc.ui_max = 1.0f;
|
|
||||||
desc.ui_step = 1.0f;
|
|
||||||
} else if (desc.kind == FxUniformKind::Integer) {
|
|
||||||
desc.ui_min = 0.0f;
|
|
||||||
desc.ui_max = 100.0f;
|
|
||||||
desc.ui_step = 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void(AnnotationFloat(info.annotations, "ui_min", desc.ui_min));
|
|
||||||
void(AnnotationFloat(info.annotations, "ui_max", desc.ui_max));
|
|
||||||
void(AnnotationFloat(info.annotations, "ui_step", desc.ui_step));
|
|
||||||
|
|
||||||
if (desc.ui_step <= 0.0f) {
|
|
||||||
desc.ui_step = 0.01f;
|
|
||||||
if (desc.kind != FxUniformKind::Floating) {
|
|
||||||
desc.ui_step = 1.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (desc.ui_max < desc.ui_min) {
|
|
||||||
std::swap(desc.ui_min, desc.ui_max);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info.has_initializer_value) {
|
|
||||||
for (u32 i = 0; i < desc.components; ++i) {
|
|
||||||
if (desc.kind == FxUniformKind::Floating) {
|
|
||||||
desc.default_value[i] = info.initializer_value.as_float[i];
|
|
||||||
} else {
|
|
||||||
desc.default_value[i] = static_cast<f32>(info.initializer_value.as_int[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return desc;
|
|
||||||
}
|
|
||||||
|
|
||||||
FxEffectDesc DescribeEffect(const std::filesystem::path& path, const std::filesystem::path& root) {
|
|
||||||
FxEffectDesc desc;
|
|
||||||
desc.file = Common::FS::PathToUTF8String(std::filesystem::relative(path, root));
|
|
||||||
desc.name = Common::FS::PathToUTF8String(path.stem());
|
|
||||||
|
|
||||||
const auto compiled =
|
|
||||||
CompileFxEffect(path, CATALOG_PROBE_WIDTH, CATALOG_PROBE_HEIGHT, CATALOG_PROBE_DEPTH);
|
|
||||||
if (!compiled.Succeeded()) {
|
|
||||||
desc.error = compiled.error;
|
|
||||||
return desc;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& technique : compiled.module.techniques) {
|
|
||||||
desc.techniques.push_back(technique.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!compiled.module.techniques.empty()) {
|
|
||||||
const auto& annotations = compiled.module.techniques.front().annotations;
|
|
||||||
desc.label = AnnotationString(annotations, "ui_label");
|
|
||||||
desc.description = AnnotationString(annotations, "ui_tooltip");
|
|
||||||
}
|
|
||||||
if (desc.label.empty()) {
|
|
||||||
desc.label = desc.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& uniform : compiled.module.uniforms) {
|
|
||||||
FxUniformDesc uniform_desc = DescribeUniform(uniform);
|
|
||||||
if (uniform_desc.ui_type == FxUiType::Hidden) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
desc.uniforms.push_back(std::move(uniform_desc));
|
|
||||||
}
|
|
||||||
|
|
||||||
return desc;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // Anonymous namespace
|
|
||||||
|
|
||||||
std::filesystem::path GetFxRootDirectory() {
|
|
||||||
return Common::FS::GetEdenPath(Common::FS::EdenPath::PostShaderDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::filesystem::path> GetFxIncludePaths(const std::filesystem::path& effect_path) {
|
|
||||||
const auto root = GetFxRootDirectory();
|
|
||||||
std::vector<std::filesystem::path> paths;
|
|
||||||
paths.push_back(effect_path.parent_path());
|
|
||||||
paths.push_back(root);
|
|
||||||
paths.push_back(root / "Shaders");
|
|
||||||
|
|
||||||
const auto last = std::unique(paths.begin(), paths.end());
|
|
||||||
paths.erase(last, paths.end());
|
|
||||||
return paths;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::filesystem::path ResolveFxTexturePath(const std::filesystem::path& effect_path,
|
|
||||||
std::string_view source) {
|
|
||||||
const auto root = GetFxRootDirectory();
|
|
||||||
const std::filesystem::path name{source};
|
|
||||||
|
|
||||||
const std::array candidates{
|
|
||||||
effect_path.parent_path() / name,
|
|
||||||
root / "Textures" / name,
|
|
||||||
root / name,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (const auto& candidate : candidates) {
|
|
||||||
if (Common::FS::Exists(candidate)) {
|
|
||||||
return candidate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::filesystem::path();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReloadFxCatalog() {
|
|
||||||
catalog.clear();
|
|
||||||
catalog_scanned = true;
|
|
||||||
|
|
||||||
const auto root = GetFxRootDirectory();
|
|
||||||
if (!Common::FS::Exists(root) && !Common::FS::CreateDirs(root)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& bundled : BUNDLED_FX_EFFECTS) {
|
|
||||||
const auto path = root / bundled.name;
|
|
||||||
if (Common::FS::Exists(path)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
void(Common::FS::WriteStringToFile(path, Common::FS::FileType::TextFile, bundled.source));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::filesystem::path> effect_files;
|
|
||||||
Common::FS::IterateDirEntriesRecursively(
|
|
||||||
root,
|
|
||||||
[&](const std::filesystem::directory_entry& entry) {
|
|
||||||
if (entry.path().extension() == ".fx") {
|
|
||||||
effect_files.push_back(entry.path());
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
Common::FS::DirEntryFilter::File);
|
|
||||||
|
|
||||||
std::sort(effect_files.begin(), effect_files.end());
|
|
||||||
|
|
||||||
for (const auto& file : effect_files) {
|
|
||||||
FxEffectDesc desc = DescribeEffect(file, root);
|
|
||||||
if (!desc.error.empty()) {
|
|
||||||
LOG_WARNING(Render, "Post-processing effect '{}' failed to compile:\n{}", desc.file,
|
|
||||||
desc.error);
|
|
||||||
}
|
|
||||||
catalog.push_back(std::move(desc));
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t usable = std::count_if(catalog.begin(), catalog.end(),
|
|
||||||
[](const FxEffectDesc& d) { return d.Valid(); });
|
|
||||||
LOG_INFO(Render, "Loaded {} post-processing effects ({} usable)", catalog.size(), usable);
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<FxEffectDesc>& GetFxCatalog() {
|
|
||||||
if (!catalog_scanned) {
|
|
||||||
ReloadFxCatalog();
|
|
||||||
}
|
|
||||||
return catalog;
|
|
||||||
}
|
|
||||||
|
|
||||||
const FxEffectDesc* FindFxEffect(std::string_view file) {
|
|
||||||
const auto& effects = GetFxCatalog();
|
|
||||||
const auto it = std::find_if(effects.begin(), effects.end(),
|
|
||||||
[&](const FxEffectDesc& d) { return d.file == file; });
|
|
||||||
if (it == effects.end()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return &*it;
|
|
||||||
}
|
|
||||||
|
|
||||||
const FxUniformDesc* FindFxUniform(const FxEffectDesc& effect, std::string_view name) {
|
|
||||||
const auto it = std::find_if(effect.uniforms.begin(), effect.uniforms.end(),
|
|
||||||
[&](const FxUniformDesc& u) { return u.name == name; });
|
|
||||||
if (it == effect.uniforms.end()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return &*it;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace VideoCore
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <filesystem>
|
|
||||||
#include <string>
|
|
||||||
#include <string_view>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
|
|
||||||
namespace VideoCore {
|
|
||||||
|
|
||||||
enum class FxUniformKind {
|
|
||||||
Boolean,
|
|
||||||
Integer,
|
|
||||||
Floating,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class FxUiType {
|
|
||||||
Hidden,
|
|
||||||
Slider,
|
|
||||||
Drag,
|
|
||||||
Combo,
|
|
||||||
Radio,
|
|
||||||
CheckBox,
|
|
||||||
Color,
|
|
||||||
InputBox,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FxUniformDesc {
|
|
||||||
std::string name;
|
|
||||||
std::string label;
|
|
||||||
std::string tooltip;
|
|
||||||
std::string category;
|
|
||||||
FxUniformKind kind{FxUniformKind::Floating};
|
|
||||||
u32 components{1};
|
|
||||||
FxUiType ui_type{FxUiType::Hidden};
|
|
||||||
f32 ui_min{0.0f};
|
|
||||||
f32 ui_max{1.0f};
|
|
||||||
f32 ui_step{0.01f};
|
|
||||||
std::vector<std::string> items;
|
|
||||||
std::array<f32, 4> default_value{};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FxEffectDesc {
|
|
||||||
std::string file;
|
|
||||||
std::string name;
|
|
||||||
std::string label;
|
|
||||||
std::string description;
|
|
||||||
std::vector<std::string> techniques;
|
|
||||||
std::vector<FxUniformDesc> uniforms;
|
|
||||||
std::string error;
|
|
||||||
|
|
||||||
bool Valid() const {
|
|
||||||
return error.empty() && !techniques.empty();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::filesystem::path GetFxRootDirectory();
|
|
||||||
|
|
||||||
std::vector<std::filesystem::path> GetFxIncludePaths(const std::filesystem::path& effect_path);
|
|
||||||
|
|
||||||
std::filesystem::path ResolveFxTexturePath(const std::filesystem::path& effect_path,
|
|
||||||
std::string_view source);
|
|
||||||
|
|
||||||
void ReloadFxCatalog();
|
|
||||||
|
|
||||||
const std::vector<FxEffectDesc>& GetFxCatalog();
|
|
||||||
|
|
||||||
const FxEffectDesc* FindFxEffect(std::string_view file);
|
|
||||||
|
|
||||||
const FxUniformDesc* FindFxUniform(const FxEffectDesc& effect, std::string_view name);
|
|
||||||
|
|
||||||
} // namespace VideoCore
|
|
||||||
@@ -226,22 +226,6 @@ void BufferCacheRuntime::BindIndexBuffer(Buffer& buffer, u32 offset, u32 size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BufferCacheRuntime::BindVertexBuffer(u32 index, Buffer& buffer, u32 offset, u32 size,
|
|
||||||
u32 stride) {
|
|
||||||
if (index >= max_attributes) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (has_unified_vertex_buffers) {
|
|
||||||
buffer.MakeResident(GL_READ_ONLY);
|
|
||||||
glBindVertexBuffer(index, 0, 0, static_cast<GLsizei>(stride));
|
|
||||||
glBufferAddressRangeNV(GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV, index,
|
|
||||||
buffer.HostGpuAddr() + offset, static_cast<GLsizeiptr>(size));
|
|
||||||
} else {
|
|
||||||
glBindVertexBuffer(index, buffer.Handle(), static_cast<GLintptr>(offset),
|
|
||||||
static_cast<GLsizei>(stride));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings) {
|
void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings) {
|
||||||
// TODO: Should HostBindings provide the correct runtime types to avoid these transforms?
|
// TODO: Should HostBindings provide the correct runtime types to avoid these transforms?
|
||||||
std::array<GLuint, 32> buffer_handles;
|
std::array<GLuint, 32> buffer_handles;
|
||||||
|
|||||||
@@ -99,8 +99,6 @@ public:
|
|||||||
|
|
||||||
void BindIndexBuffer(Buffer& buffer, u32 offset, u32 size);
|
void BindIndexBuffer(Buffer& buffer, u32 offset, u32 size);
|
||||||
|
|
||||||
void BindVertexBuffer(u32 index, Buffer& buffer, u32 offset, u32 size, u32 stride);
|
|
||||||
|
|
||||||
void BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings);
|
void BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings);
|
||||||
|
|
||||||
void BindUniformBuffer(size_t stage, u32 binding_index, Buffer& buffer, u32 offset, u32 size);
|
void BindUniformBuffer(size_t stage, u32 binding_index, Buffer& buffer, u32 offset, u32 size);
|
||||||
|
|||||||
@@ -259,6 +259,7 @@ void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::Draw(bool is_indexed, u32 instance_count) {
|
void RasterizerOpenGL::Draw(bool is_indexed, u32 instance_count) {
|
||||||
|
buffer_cache.SetDrawInstanceCount(instance_count);
|
||||||
PrepareDraw(is_indexed, [this, is_indexed, instance_count](GLenum primitive_mode) {
|
PrepareDraw(is_indexed, [this, is_indexed, instance_count](GLenum primitive_mode) {
|
||||||
const auto& draw_state = maxwell3d->draw_manager.draw_state;
|
const auto& draw_state = maxwell3d->draw_manager.draw_state;
|
||||||
const GLuint base_instance = GLuint(draw_state.base_instance);
|
const GLuint base_instance = GLuint(draw_state.base_instance);
|
||||||
@@ -304,6 +305,7 @@ void RasterizerOpenGL::Draw(bool is_indexed, u32 instance_count) {
|
|||||||
void RasterizerOpenGL::DrawIndirect() {
|
void RasterizerOpenGL::DrawIndirect() {
|
||||||
const auto& params = maxwell3d->draw_manager.indirect_state;
|
const auto& params = maxwell3d->draw_manager.indirect_state;
|
||||||
buffer_cache.SetDrawIndirect(¶ms);
|
buffer_cache.SetDrawIndirect(¶ms);
|
||||||
|
buffer_cache.SetDrawInstanceCount(0);
|
||||||
PrepareDraw(params.is_indexed, [this, ¶ms](GLenum primitive_mode) {
|
PrepareDraw(params.is_indexed, [this, ¶ms](GLenum primitive_mode) {
|
||||||
if (params.is_byte_count) {
|
if (params.is_byte_count) {
|
||||||
const GPUVAddr tfb_object_base_addr = params.indirect_start_address - 4U;
|
const GPUVAddr tfb_object_base_addr = params.indirect_start_address - 4U;
|
||||||
|
|||||||
@@ -18,10 +18,6 @@
|
|||||||
#include "video_core/renderer_vulkan/present/sgsr.h"
|
#include "video_core/renderer_vulkan/present/sgsr.h"
|
||||||
#include "video_core/renderer_vulkan/present/fxaa.h"
|
#include "video_core/renderer_vulkan/present/fxaa.h"
|
||||||
#include "video_core/renderer_vulkan/present/layer.h"
|
#include "video_core/renderer_vulkan/present/layer.h"
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
#include "video_core/post_processing/fx_chain.h"
|
|
||||||
#include "video_core/renderer_vulkan/present/post_process.h"
|
|
||||||
#endif
|
|
||||||
#include "video_core/renderer_vulkan/present/present_push_constants.h"
|
#include "video_core/renderer_vulkan/present/present_push_constants.h"
|
||||||
#include "video_core/renderer_vulkan/present/smaa.h"
|
#include "video_core/renderer_vulkan/present/smaa.h"
|
||||||
#include "video_core/renderer_vulkan/present/util.h"
|
#include "video_core/renderer_vulkan/present/util.h"
|
||||||
@@ -97,9 +93,6 @@ void Layer::ConfigureDraw(const Device& device, PresentPushConstants* out_push_c
|
|||||||
|
|
||||||
RefreshResources(device, framebuffer);
|
RefreshResources(device, framebuffer);
|
||||||
SetAntiAliasPass(device);
|
SetAntiAliasPass(device);
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
SetPostProcessPass(device);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Finish any pending renderpass
|
// Finish any pending renderpass
|
||||||
scheduler.RequestOutsideRenderPassOperationContext();
|
scheduler.RequestOutsideRenderPassOperationContext();
|
||||||
@@ -122,12 +115,6 @@ void Layer::ConfigureDraw(const Device& device, PresentPushConstants* out_push_c
|
|||||||
smaa->Draw(device, scheduler, image_index, &source_image, &source_image_view);
|
smaa->Draw(device, scheduler, image_index, &source_image, &source_image_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
if (post_process.has_value()) {
|
|
||||||
post_process->Draw(device, scheduler, image_index, &source_image, &source_image_view);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
auto crop_rect = Tegra::NormalizeCrop(framebuffer, texture_width, texture_height);
|
auto crop_rect = Tegra::NormalizeCrop(framebuffer, texture_width, texture_height);
|
||||||
const VkExtent2D render_extent{
|
const VkExtent2D render_extent{
|
||||||
.width = scaled_width,
|
.width = scaled_width,
|
||||||
@@ -227,40 +214,6 @@ void Layer::SetAntiAliasPass(const Device& device) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
void Layer::SetPostProcessPass(const Device& device) {
|
|
||||||
const VkExtent2D render_area{
|
|
||||||
.width = Settings::values.resolution_info.ScaleUp(raw_width),
|
|
||||||
.height = Settings::values.resolution_info.ScaleUp(raw_height),
|
|
||||||
};
|
|
||||||
|
|
||||||
const u64 generation = VideoCore::FxChain::Instance().Snapshot().generation;
|
|
||||||
|
|
||||||
if (post_process_generation == generation && post_process_extent.width == render_area.width &&
|
|
||||||
post_process_extent.height == render_area.height) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const u64 tick : resource_ticks) {
|
|
||||||
scheduler.Wait(tick);
|
|
||||||
}
|
|
||||||
|
|
||||||
post_process_generation = generation;
|
|
||||||
post_process_extent = render_area;
|
|
||||||
post_process.reset();
|
|
||||||
|
|
||||||
if (VideoCore::FxChain::Instance().Size() == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
post_process.emplace(device, memory_allocator, scheduler, image_count, render_area);
|
|
||||||
|
|
||||||
if (post_process->Empty()) {
|
|
||||||
post_process.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void Layer::ReleaseRawImages() {
|
void Layer::ReleaseRawImages() {
|
||||||
for (const u64 tick : resource_ticks) {
|
for (const u64 tick : resource_ticks) {
|
||||||
scheduler.Wait(tick);
|
scheduler.Wait(tick);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user