Skip to content

Commit 1f848a4

Browse files
committed
[Feature] Use librashader for .slangp (RetroArch) shader support
1 parent fdec9a3 commit 1f848a4

7 files changed

Lines changed: 532 additions & 27 deletions

File tree

Assets/dll/librashader.dll

8.05 MB
Binary file not shown.

src/BizHawk.Client.Common/DisplayManager/DisplayManagerBase.cs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// TODO
1+
// TODO
22
// we could flag textures as 'actually' render targets (keep a reference to the render target?) which could allow us to convert between them more quickly in some cases
33

44
using System.Collections.Generic;
@@ -112,6 +112,7 @@ protected DisplayManagerBase(
112112
// `_apiHawkIDTo2DRenderer` is a new empty dict, members are lazily-initialised
113113

114114
RefreshUserShader();
115+
RefreshLibrashader();
115116
}
116117

117118
public void UpdateGlobals(Config config, IEmulator emulator)
@@ -158,6 +159,8 @@ public void Dispose()
158159
s?.Dispose();
159160
}
160161

162+
_librashaderFilter?.Dispose();
163+
161164
_theOneFont?.Dispose();
162165
_renderer.Dispose();
163166
}
@@ -222,6 +225,8 @@ private StringRenderer Font
222225

223226
private RetroShaderChain _shaderChainUser;
224227

228+
private LibrashaderFilter _librashaderFilter;
229+
225230
public abstract void ActivateOpenGLContext();
226231

227232
protected abstract void ActivateGraphicsControlContext();
@@ -231,6 +236,7 @@ private StringRenderer Font
231236
public void RefreshUserShader()
232237
{
233238
_shaderChainUser?.Dispose();
239+
_shaderChainUser = null;
234240
if (File.Exists(GlobalConfig.DispUserFilterPath))
235241
{
236242
var fi = new FileInfo(GlobalConfig.DispUserFilterPath);
@@ -239,6 +245,25 @@ public void RefreshUserShader()
239245
}
240246
}
241247

248+
public void RefreshLibrashader()
249+
{
250+
Console.WriteLine($"[librashader] RefreshLibrashader called, path: {GlobalConfig.DispUserFilterPath}");
251+
_librashaderFilter?.Dispose();
252+
_librashaderFilter = null;
253+
if (_gl is IGL_OpenGL && File.Exists(GlobalConfig.DispUserFilterPath))
254+
{
255+
Console.WriteLine("[librashader] Creating LibrashaderFilter");
256+
_librashaderFilter = new LibrashaderFilter(GlobalConfig.DispUserFilterPath);
257+
}
258+
else
259+
{
260+
if (!(_gl is IGL_OpenGL))
261+
Console.WriteLine("[librashader] GL is not IGL_OpenGL, skipping librashader");
262+
else if (!File.Exists(GlobalConfig.DispUserFilterPath))
263+
Console.WriteLine("[librashader] Shader preset file not found");
264+
}
265+
}
266+
242267
private (int Left, int Top, int Right, int Bottom) CalculateCompleteContentPadding(bool user, bool source)
243268
{
244269
var padding = (Left: 0, Top: 0, Right: 0, Bottom: 0);
@@ -282,6 +307,7 @@ private FilterProgram BuildDefaultChain(Size chainInSize, Size chainOutSize, boo
282307
// select user special FX shader chain
283308
KeyValuePair<string, float>[] selectedChainProperties = null;
284309
RetroShaderChain selectedChain = null;
310+
bool useLibrashader = false;
285311
switch (GlobalConfig.TargetDisplayFilter)
286312
{
287313
case 1 when _shaderChainHq2X is { Available: true }:
@@ -294,11 +320,15 @@ private FilterProgram BuildDefaultChain(Size chainInSize, Size chainOutSize, boo
294320
case 3 when _shaderChainUser is { Available: true }:
295321
selectedChain = _shaderChainUser;
296322
break;
323+
case 4 when _librashaderFilter != null:
324+
useLibrashader = true;
325+
break;
297326
}
298327

299328
if (!includeUserFilters)
300329
{
301330
selectedChain = null;
331+
useLibrashader = false;
302332
}
303333

304334
var fCoreScreenControl = CreateCoreScreenControl();
@@ -362,6 +392,12 @@ private FilterProgram BuildDefaultChain(Size chainInSize, Size chainOutSize, boo
362392
AppendRetroShaderChain(chain, "retroShader", selectedChain, selectedChainProperties);
363393
}
364394

395+
// add librashader filter
396+
if (useLibrashader)
397+
{
398+
chain.AddFilter(_librashaderFilter, "librashader");
399+
}
400+
365401
// AutoPrescale makes no sense for a None final filter
366402
if (GlobalConfig.DispAutoPrescale && GlobalConfig.DispFinalFilter != (int)FinalPresentation.eFilterOption.None)
367403
{
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
using System.Text;
4+
5+
using BizHawk.Common;
6+
7+
namespace BizHawk.Client.Common.Filters
8+
{
9+
public static unsafe class Librashader
10+
{
11+
private const string DllName = "librashader.dll";
12+
private static IntPtr _handle = IntPtr.Zero;
13+
private static bool _loaded = false;
14+
15+
public static bool IsLoaded => _loaded;
16+
17+
public static bool Load()
18+
{
19+
if (_loaded) return true;
20+
21+
Util.DebugWriteLine("[librashader] Attempting to load dll\\librashader.dll...");
22+
_handle = LoadLibrary("dll\\librashader.dll");
23+
if (_handle == IntPtr.Zero)
24+
{
25+
Util.DebugWriteLine("[librashader] Failed to load librashader.dll");
26+
return false;
27+
}
28+
29+
Util.DebugWriteLine("[librashader] Successfully loaded librashader.dll");
30+
_loaded = true;
31+
LoadFunctions();
32+
return true;
33+
}
34+
35+
[DllImport("kernel32.dll", SetLastError = true)]
36+
private static extern IntPtr LoadLibrary(string lpFileName);
37+
38+
[DllImport("kernel32.dll", SetLastError = true)]
39+
private static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
40+
41+
private static T GetDelegate<T>(string name) where T : Delegate
42+
{
43+
IntPtr addr = GetProcAddress(_handle, name);
44+
return addr != IntPtr.Zero ? Marshal.GetDelegateForFunctionPointer<T>(addr) : null;
45+
}
46+
47+
public delegate IntPtr PFN_libra_instance_abi_version();
48+
public delegate IntPtr PFN_libra_instance_api_version();
49+
public delegate IntPtr PFN_libra_preset_create(byte* filename, out IntPtr preset);
50+
public delegate int PFN_libra_preset_free(ref IntPtr preset);
51+
public delegate int PFN_libra_error_free(ref IntPtr error);
52+
public delegate int PFN_libra_error_print(IntPtr error);
53+
public delegate int PFN_libra_error_errno(IntPtr error);
54+
55+
public delegate IntPtr PFN_libra_gl_loader_t(byte* name);
56+
57+
public delegate IntPtr PFN_libra_gl_filter_chain_create(
58+
ref IntPtr preset,
59+
IntPtr loader,
60+
[In] ref filter_chain_gl_opt_t options,
61+
out IntPtr chain);
62+
63+
public delegate int PFN_libra_gl_filter_chain_frame(
64+
ref IntPtr chain,
65+
UIntPtr frame_count,
66+
libra_image_gl_t image,
67+
libra_image_gl_t output,
68+
IntPtr viewport,
69+
IntPtr mvp,
70+
IntPtr options);
71+
72+
public delegate int PFN_libra_gl_filter_chain_free(ref IntPtr chain);
73+
74+
public static PFN_libra_instance_abi_version instance_abi_version;
75+
public static PFN_libra_instance_api_version instance_api_version;
76+
public static PFN_libra_preset_create preset_create;
77+
public static PFN_libra_preset_free preset_free;
78+
public static PFN_libra_error_free error_free;
79+
public static PFN_libra_error_print error_print;
80+
public static PFN_libra_error_errno error_errno;
81+
public static PFN_libra_gl_filter_chain_create gl_filter_chain_create;
82+
public static PFN_libra_gl_filter_chain_frame gl_filter_chain_frame;
83+
public static PFN_libra_gl_filter_chain_free gl_filter_chain_free;
84+
85+
private static void LoadFunctions()
86+
{
87+
instance_abi_version = GetDelegate<PFN_libra_instance_abi_version>("libra_instance_abi_version");
88+
instance_api_version = GetDelegate<PFN_libra_instance_api_version>("libra_instance_api_version");
89+
preset_create = GetDelegate<PFN_libra_preset_create>("libra_preset_create");
90+
preset_free = GetDelegate<PFN_libra_preset_free>("libra_preset_free");
91+
error_free = GetDelegate<PFN_libra_error_free>("libra_error_free");
92+
error_print = GetDelegate<PFN_libra_error_print>("libra_error_print");
93+
error_errno = GetDelegate<PFN_libra_error_errno>("libra_error_errno");
94+
gl_filter_chain_create = GetDelegate<PFN_libra_gl_filter_chain_create>("libra_gl_filter_chain_create");
95+
gl_filter_chain_frame = GetDelegate<PFN_libra_gl_filter_chain_frame>("libra_gl_filter_chain_frame");
96+
gl_filter_chain_free = GetDelegate<PFN_libra_gl_filter_chain_free>("libra_gl_filter_chain_free");
97+
}
98+
99+
public static IntPtr PresetCreate(string filename, out IntPtr preset)
100+
{
101+
byte[] bytes = Encoding.UTF8.GetBytes(filename + "\0");
102+
fixed (byte* ptr = bytes)
103+
{
104+
return preset_create(ptr, out preset);
105+
}
106+
}
107+
108+
[StructLayout(LayoutKind.Sequential)]
109+
public struct filter_chain_gl_opt_t
110+
{
111+
public UIntPtr version;
112+
public ushort glsl_version;
113+
[MarshalAs(UnmanagedType.U1)]
114+
public bool use_dsa;
115+
[MarshalAs(UnmanagedType.U1)]
116+
public bool force_no_mipmaps;
117+
[MarshalAs(UnmanagedType.U1)]
118+
public bool disable_cache;
119+
}
120+
121+
[StructLayout(LayoutKind.Sequential)]
122+
public struct libra_image_gl_t
123+
{
124+
public uint handle;
125+
public uint format;
126+
public uint width;
127+
public uint height;
128+
}
129+
130+
[StructLayout(LayoutKind.Sequential)]
131+
public struct libra_viewport_t
132+
{
133+
public float x;
134+
public float y;
135+
public uint width;
136+
public uint height;
137+
}
138+
139+
public static filter_chain_gl_opt_t CreateDefaultOptions()
140+
{
141+
return new filter_chain_gl_opt_t
142+
{
143+
version = new UIntPtr(1),
144+
glsl_version = 330,
145+
use_dsa = false,
146+
force_no_mipmaps = false,
147+
disable_cache = false
148+
};
149+
}
150+
}
151+
}

0 commit comments

Comments
 (0)