Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added Assets/dll/librashader.dll
Binary file not shown.
38 changes: 37 additions & 1 deletion src/BizHawk.Client.Common/DisplayManager/DisplayManagerBase.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// TODO
// TODO
// 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

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

RefreshUserShader();
RefreshLibrashader();
}

public void UpdateGlobals(Config config, IEmulator emulator)
Expand Down Expand Up @@ -158,6 +159,8 @@ public void Dispose()
s?.Dispose();
}

_librashaderFilter?.Dispose();

_theOneFont?.Dispose();
_renderer.Dispose();
}
Expand Down Expand Up @@ -222,6 +225,8 @@ private StringRenderer Font

private RetroShaderChain _shaderChainUser;

private LibrashaderFilter _librashaderFilter;

public abstract void ActivateOpenGLContext();

protected abstract void ActivateGraphicsControlContext();
Expand All @@ -231,6 +236,7 @@ private StringRenderer Font
public void RefreshUserShader()
{
_shaderChainUser?.Dispose();
_shaderChainUser = null;
if (File.Exists(GlobalConfig.DispUserFilterPath))
{
var fi = new FileInfo(GlobalConfig.DispUserFilterPath);
Expand All @@ -239,6 +245,25 @@ public void RefreshUserShader()
}
}

public void RefreshLibrashader()
{
Console.WriteLine($"[librashader] RefreshLibrashader called, path: {GlobalConfig.DispUserFilterPath}");
_librashaderFilter?.Dispose();
_librashaderFilter = null;
if (_gl is IGL_OpenGL && File.Exists(GlobalConfig.DispUserFilterPath))
{
Console.WriteLine("[librashader] Creating LibrashaderFilter");
_librashaderFilter = new LibrashaderFilter(GlobalConfig.DispUserFilterPath);
}
else
{
if (_gl is not IGL_OpenGL)
Console.WriteLine("[librashader] GL is not IGL_OpenGL, skipping librashader");
else if (!File.Exists(GlobalConfig.DispUserFilterPath))
Console.WriteLine("[librashader] Shader preset file not found");
}
}

private (int Left, int Top, int Right, int Bottom) CalculateCompleteContentPadding(bool user, bool source)
{
var padding = (Left: 0, Top: 0, Right: 0, Bottom: 0);
Expand Down Expand Up @@ -282,6 +307,7 @@ private FilterProgram BuildDefaultChain(Size chainInSize, Size chainOutSize, boo
// select user special FX shader chain
KeyValuePair<string, float>[] selectedChainProperties = null;
RetroShaderChain selectedChain = null;
bool useLibrashader = false;
switch (GlobalConfig.TargetDisplayFilter)
{
case 1 when _shaderChainHq2X is { Available: true }:
Expand All @@ -294,11 +320,15 @@ private FilterProgram BuildDefaultChain(Size chainInSize, Size chainOutSize, boo
case 3 when _shaderChainUser is { Available: true }:
selectedChain = _shaderChainUser;
break;
case 4 when _librashaderFilter != null:
useLibrashader = true;
break;
}

if (!includeUserFilters)
{
selectedChain = null;
useLibrashader = false;
}

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

// add librashader filter
if (useLibrashader)
{
chain.AddFilter(_librashaderFilter, "librashader");
}

// AutoPrescale makes no sense for a None final filter
if (GlobalConfig.DispAutoPrescale && GlobalConfig.DispFinalFilter != (int)FinalPresentation.eFilterOption.None)
{
Expand Down
157 changes: 157 additions & 0 deletions src/BizHawk.Client.Common/DisplayManager/Filters/Librashader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
using System.Runtime.InteropServices;
using System.Text;

using BizHawk.Common;

namespace BizHawk.Client.Common.Filters
{
public static unsafe class Librashader
{
private const string DllName = "librashader.dll";
private static IntPtr _handle = IntPtr.Zero;
private static bool _loaded = false;

public static bool IsLoaded => _loaded;

public static bool Load()
{
if (_loaded) return true;

Util.DebugWriteLine("[librashader] Attempting to load dll\\librashader.dll...");
_handle = LoadLibrary("dll\\librashader.dll");
if (_handle == IntPtr.Zero)
{
Util.DebugWriteLine("[librashader] Failed to load librashader.dll");
return false;
}

Util.DebugWriteLine("[librashader] Successfully loaded librashader.dll");
_loaded = true;
LoadFunctions();
return true;
}

[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr LoadLibrary(string lpFileName);
Comment thread
YoshiRulz marked this conversation as resolved.
Outdated

[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);

private static T GetDelegate<T>(string name) where T : Delegate
{
IntPtr addr = GetProcAddress(_handle, name);
return addr != IntPtr.Zero ? Marshal.GetDelegateForFunctionPointer<T>(addr) : null;
}

public delegate IntPtr PFN_libra_instance_abi_version();
public delegate IntPtr PFN_libra_instance_api_version();
public delegate IntPtr PFN_libra_preset_create(byte* filename, out IntPtr preset);
public delegate int PFN_libra_preset_free(ref IntPtr preset);
public delegate int PFN_libra_error_free(ref IntPtr error);
public delegate int PFN_libra_error_print(IntPtr error);
public delegate int PFN_libra_error_errno(IntPtr error);

public delegate IntPtr PFN_libra_gl_loader_t(byte* name);

public delegate IntPtr PFN_libra_gl_filter_chain_create(
ref IntPtr preset,
IntPtr loader,
[In] ref filter_chain_gl_opt_t options,
out IntPtr chain);

public delegate int PFN_libra_gl_filter_chain_frame(
ref IntPtr chain,
UIntPtr frame_count,
libra_image_gl_t image,
libra_image_gl_t output,
IntPtr viewport,
IntPtr mvp,
IntPtr options);

public delegate int PFN_libra_gl_filter_chain_free(ref IntPtr chain);

private static PFN_libra_instance_abi_version _instance_abi_version;
private static PFN_libra_instance_api_version _instance_api_version;
private static PFN_libra_preset_create _preset_create;
private static PFN_libra_preset_free _preset_free;
private static PFN_libra_error_free _error_free;
private static PFN_libra_error_print _error_print;
private static PFN_libra_error_errno _error_errno;
private static PFN_libra_gl_filter_chain_create _gl_filter_chain_create;
private static PFN_libra_gl_filter_chain_frame _gl_filter_chain_frame;
private static PFN_libra_gl_filter_chain_free _gl_filter_chain_free;

internal static PFN_libra_preset_create preset_create => _preset_create;
internal static PFN_libra_preset_free preset_free => _preset_free;
internal static PFN_libra_error_print error_print => _error_print;
internal static PFN_libra_gl_filter_chain_create gl_filter_chain_create => _gl_filter_chain_create;
internal static PFN_libra_gl_filter_chain_frame gl_filter_chain_frame => _gl_filter_chain_frame;
internal static PFN_libra_gl_filter_chain_free gl_filter_chain_free => _gl_filter_chain_free;

private static void LoadFunctions()
{
_instance_abi_version = GetDelegate<PFN_libra_instance_abi_version>("libra_instance_abi_version");
_instance_api_version = GetDelegate<PFN_libra_instance_api_version>("libra_instance_api_version");
_preset_create = GetDelegate<PFN_libra_preset_create>("libra_preset_create");
_preset_free = GetDelegate<PFN_libra_preset_free>("libra_preset_free");
_error_free = GetDelegate<PFN_libra_error_free>("libra_error_free");
_error_print = GetDelegate<PFN_libra_error_print>("libra_error_print");
_error_errno = GetDelegate<PFN_libra_error_errno>("libra_error_errno");
_gl_filter_chain_create = GetDelegate<PFN_libra_gl_filter_chain_create>("libra_gl_filter_chain_create");
_gl_filter_chain_frame = GetDelegate<PFN_libra_gl_filter_chain_frame>("libra_gl_filter_chain_frame");
_gl_filter_chain_free = GetDelegate<PFN_libra_gl_filter_chain_free>("libra_gl_filter_chain_free");
}

public static IntPtr PresetCreate(string filename, out IntPtr preset)
{
byte[] bytes = Encoding.UTF8.GetBytes(filename + "\0");
fixed (byte* ptr = bytes)
{
return _preset_create(ptr, out preset);
}
}

[StructLayout(LayoutKind.Sequential)]
public struct filter_chain_gl_opt_t
{
public UIntPtr version;
public ushort glsl_version;
[MarshalAs(UnmanagedType.U1)]
public bool use_dsa;
[MarshalAs(UnmanagedType.U1)]
public bool force_no_mipmaps;
[MarshalAs(UnmanagedType.U1)]
public bool disable_cache;
}

[StructLayout(LayoutKind.Sequential)]
public struct libra_image_gl_t
{
public uint handle;
public uint format;
public uint width;
public uint height;
}

[StructLayout(LayoutKind.Sequential)]
public struct libra_viewport_t
{
public float x;
public float y;
public uint width;
public uint height;
}

public static filter_chain_gl_opt_t CreateDefaultOptions()
{
return new filter_chain_gl_opt_t
{
version = new UIntPtr(1),
glsl_version = 330,
use_dsa = false,
force_no_mipmaps = false,
disable_cache = false,
};
}
}
}
Loading