Squashed commit of the following:

commit 15611308c2c6ed5e4f46bd840ade8700e3768527
Author: CasualPokePlayer <50538166+CasualPokePlayer@users.noreply.github.com>
Date:   Fri Mar 11 19:29:57 2022 -0800

    derp

commit 3c0546cdd8f08004c1ad82bdb72910498dddac91
Author: CasualPokePlayer <50538166+CasualPokePlayer@users.noreply.github.com>
Date:   Fri Mar 11 19:28:06 2022 -0800

    bob

commit 8e24ef7adc9ccee5405f8618bb8ddb165ff9cf8f
Author: CasualPokePlayer <50538166+CasualPokePlayer@users.noreply.github.com>
Date:   Fri Mar 11 19:10:45 2022 -0800

    removing perf core here now

commit 66225df3b175544d28d91c6ede53861c74e71239
Author: CasualPokePlayer <50538166+CasualPokePlayer@users.noreply.github.com>
Date:   Fri Mar 11 18:51:14 2022 -0800

    delete perf core, cleanups, get submodule pushed

commit 06b627bd949f15aac4749a33762ec5cb47e5aea9
Author: CasualPokePlayer <50538166+CasualPokePlayer@users.noreply.github.com>
Date:   Fri Mar 11 17:46:36 2022 -0800

    oh fucking please don't tell me this was it

commit 0bd0625d172a74a82e30b89e2f10702394e74491
Author: CasualPokePlayer <50538166+CasualPokePlayer@users.noreply.github.com>
Date:   Fri Mar 11 17:21:22 2022 -0800

    bleh

commit 20c1497fd1fb25eb6ac6c44fe2490b71009fc9e0
Author: CasualPokePlayer <50538166+CasualPokePlayer@users.noreply.github.com>
Date:   Fri Mar 11 16:36:02 2022 -0800

    bleh

commit 4ccd7982d97f8c4c85c5b18801bb9784df9772e8
Author: CasualPokePlayer <50538166+CasualPokePlayer@users.noreply.github.com>
Date:   Fri Mar 11 15:55:43 2022 -0800

    testing

commit ab9e14bc7bb3e533f903a003b80f8e6a006cd819
Author: CasualPokePlayer <50538166+CasualPokePlayer@users.noreply.github.com>
Date:   Fri Mar 11 15:44:24 2022 -0800

    bleh

commit 6d2de266825ac23df25466fdd6154e60ec6132de
Author: CasualPokePlayer <50538166+CasualPokePlayer@users.noreply.github.com>
Date:   Fri Mar 11 00:08:45 2022 -0800

    bleh

commit f55c3e3277b979a8535667312fdb988a1f70bc01
Author: CasualPokePlayer <50538166+CasualPokePlayer@users.noreply.github.com>
Date:   Thu Mar 10 23:54:49 2022 -0800

    oh derp

commit 16e3c87d7ab06947da208feb88b3f3fd96874621
Author: CasualPokePlayer <50538166+CasualPokePlayer@users.noreply.github.com>
Date:   Thu Mar 10 23:43:27 2022 -0800

    bleh

commit 1630845d46af7dc048b8c5dcfc7b0359d7f3133a
Author: CasualPokePlayer <50538166+CasualPokePlayer@users.noreply.github.com>
Date:   Thu Mar 10 23:36:14 2022 -0800

    gross hack

commit ff1ef0ac6da559e0ce0e7cad10583b70a63c3551
Author: CasualPokePlayer <50538166+CasualPokePlayer@users.noreply.github.com>
Date:   Thu Mar 10 23:10:54 2022 -0800

    angrylion integration into ares.
This commit is contained in:
CasualPokePlayer 2022-03-11 19:36:56 -08:00
parent f8a688d47f
commit ccac4d1000
71 changed files with 112 additions and 25277 deletions

3
.gitmodules vendored
View File

@ -46,3 +46,6 @@
[submodule "submodules/sameboy/libsameboy"]
path = submodules/sameboy/libsameboy
url = https://github.com/LIJI32/SameBoy.git
[submodule "waterbox/ares64/ares/thirdparty/angrylion-rdp"]
path = waterbox/ares64/ares/thirdparty/angrylion-rdp
url = https://github.com/TASEmulators/angrylion-rdp

Binary file not shown.

View File

@ -27,7 +27,7 @@ namespace BizHawk.Client.Common
(new[] { VSystemID.Raw.SNES },
new[] { CoreNames.Faust, CoreNames.Snes9X, CoreNames.Bsnes, CoreNames.Bsnes115 }),
(new[] { VSystemID.Raw.N64 },
new[] { CoreNames.Mupen64Plus, CoreNames.Ares64Performance, CoreNames.Ares64Accuracy }),
new[] { CoreNames.Mupen64Plus, CoreNames.Ares64 }),
(new[] { VSystemID.Raw.SGB },
new[] { CoreNames.Gambatte, CoreNames.Bsnes, CoreNames.Bsnes115}),
(new[] { VSystemID.Raw.GB, VSystemID.Raw.GBC },
@ -37,7 +37,7 @@ namespace BizHawk.Client.Common
(new[] { VSystemID.Raw.PCE, VSystemID.Raw.PCECD, VSystemID.Raw.SGX },
new[] { CoreNames.TurboNyma, CoreNames.HyperNyma, CoreNames.PceHawk }),
(new[] { VSystemID.Raw.PSX },
new[] { CoreNames.Octoshock, CoreNames.Nymashock}),
new[] { CoreNames.Octoshock, CoreNames.Nymashock }),
(new[] { VSystemID.Raw.TI83 },
new[] { CoreNames.TI83Hawk, CoreNames.Emu83 }),
};

View File

@ -1,59 +0,0 @@
using System.ComponentModel;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Ares64.Accuracy
{
public partial class Ares64 : ISettable<object, Ares64.Ares64SyncSettings>
{
private Ares64SyncSettings _syncSettings;
public object GetSettings() => null;
public Ares64SyncSettings GetSyncSettings() => _syncSettings.Clone();
public PutSettingsDirtyBits PutSettings(object o) => PutSettingsDirtyBits.None;
public PutSettingsDirtyBits PutSyncSettings(Ares64SyncSettings o)
{
var ret = Ares64SyncSettings.NeedsReboot(_syncSettings, o);
_syncSettings = o;
return ret ? PutSettingsDirtyBits.RebootCore : PutSettingsDirtyBits.None;
}
public class Ares64SyncSettings
{
[DisplayName("Player 1 Controller")]
[Description("")]
[DefaultValue(LibAres64.ControllerType.Mempak)]
public LibAres64.ControllerType P1Controller { get; set; }
[DisplayName("Player 2 Controller")]
[Description("")]
[DefaultValue(LibAres64.ControllerType.Unplugged)]
public LibAres64.ControllerType P2Controller { get; set; }
[DisplayName("Player 3 Controller")]
[Description("")]
[DefaultValue(LibAres64.ControllerType.Unplugged)]
public LibAres64.ControllerType P3Controller { get; set; }
[DisplayName("Player 4 Controller")]
[Description("")]
[DefaultValue(LibAres64.ControllerType.Unplugged)]
public LibAres64.ControllerType P4Controller { get; set; }
[DisplayName("Restrict Analog Range")]
[Description("Restricts analog range to account for physical limitations.")]
[DefaultValue(false)]
public bool RestrictAnalogRange { get; set; }
public Ares64SyncSettings() => SettingsUtil.SetDefaultValues(this);
public Ares64SyncSettings Clone() => MemberwiseClone() as Ares64SyncSettings;
public static bool NeedsReboot(Ares64SyncSettings x, Ares64SyncSettings y) => !DeepEquality.DeepEquals(x, y);
}
}
}

View File

@ -1,22 +1,25 @@
using System;
using System.ComponentModel;
using Newtonsoft.Json;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Ares64.Performance
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Ares64
{
public partial class Ares64 : ISettable<object, Ares64.Ares64SyncSettings>
public partial class Ares64 : ISettable<Ares64.Ares64Settings, Ares64.Ares64SyncSettings>
{
private Ares64Settings _settings;
private Ares64SyncSettings _syncSettings;
public object GetSettings() => null;
public Ares64Settings GetSettings() => _settings.Clone();
public Ares64SyncSettings GetSyncSettings() => _syncSettings.Clone();
public PutSettingsDirtyBits PutSettings(object o) => PutSettingsDirtyBits.None;
public PutSettingsDirtyBits PutSettings(Ares64Settings o)
{
var ret = Ares64Settings.NeedsReboot(_settings, o);
_settings = o;
return ret ? PutSettingsDirtyBits.RebootCore : PutSettingsDirtyBits.None;
}
public PutSettingsDirtyBits PutSyncSettings(Ares64SyncSettings o)
{
@ -25,6 +28,21 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Ares64.Performance
return ret ? PutSettingsDirtyBits.RebootCore : PutSettingsDirtyBits.None;
}
public class Ares64Settings
{
[DisplayName("Deinterlacer")]
[Description("Weave looks good for still images, but creates artifacts for moving images.\n" +
"Bob looks good for moving images, but makes the image bob up and down.")]
[DefaultValue(LibAres64.DeinterlacerType.Weave)]
public LibAres64.DeinterlacerType Deinterlacer { get; set; }
public Ares64Settings() => SettingsUtil.SetDefaultValues(this);
public Ares64Settings Clone() => MemberwiseClone() as Ares64Settings;
public static bool NeedsReboot(Ares64Settings x, Ares64Settings y) => !DeepEquality.DeepEquals(x, y);
}
public class Ares64SyncSettings
{
[DisplayName("Player 1 Controller")]
@ -52,21 +70,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Ares64.Performance
[DefaultValue(false)]
public bool RestrictAnalogRange { get; set; }
[DisplayName("Enable Vulkan")]
[Description("Enables Vulkan RDP. May fallback to software RDP if your GPU does not support Vulkan.")]
[DefaultValue(true)]
public bool EnableVulkan { get; set; }
[DisplayName("Supersampling")]
[Description("Scales HD and UHD resolutions back down to SD")]
[DefaultValue(false)]
public bool SuperSample { get; set; }
[DisplayName("Vulkan Upscale")]
[Description("")]
[DefaultValue(LibAres64.VulkanUpscaleOpts.SD)]
public LibAres64.VulkanUpscaleOpts VulkanUpscale { get; set; }
public Ares64SyncSettings() => SettingsUtil.SetDefaultValues(this);
public Ares64SyncSettings Clone() => MemberwiseClone() as Ares64SyncSettings;

View File

@ -1,469 +0,0 @@
using System;
using System.IO;
using System.Linq;
using BizHawk.BizInvoke;
using BizHawk.Common;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Properties;
using BizHawk.Emulation.Cores.Waterbox;
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Ares64.Performance
{
[PortedCore(CoreNames.Ares64Performance, "ares team, Near", "v126", "https://ares-emulator.github.io/", singleInstance: true, isReleased: false)]
[ServiceNotApplicable(new[] { typeof(IDriveLight), })]
public partial class Ares64 : IEmulator, IVideoProvider, ISoundProvider, IStatable, IInputPollable, ISaveRam, IRegionable
{
private static readonly LibAres64Performance _core;
static Ares64()
{
var resolver = new DynamicLibraryImportResolver(
OSTailoredCode.IsUnixHost ? "libares64.so" : "libares64.dll", hasLimitedLifetime: false);
_core = BizInvoker.GetInvoker<LibAres64Performance>(resolver, CallingConventionAdapters.Native);
}
private readonly BasicServiceProvider _serviceProvider;
public IEmulatorServiceProvider ServiceProvider => _serviceProvider;
public int Frame { get; private set; }
public int LagCount { get; set; }
public bool IsLagFrame { get; set; }
[FeatureNotImplemented]
public IInputCallbackSystem InputCallbacks => throw new NotImplementedException();
public string SystemId => VSystemID.Raw.N64;
public bool DeterministicEmulation => false;
public void ResetCounters()
{
Frame = 0;
LagCount = 0;
IsLagFrame = false;
}
public void Dispose() => _core.Deinit();
[CoreConstructor(VSystemID.Raw.N64)]
public Ares64(CoreLoadParameters<object, Ares64SyncSettings> lp)
{
if (lp.DeterministicEmulationRequested)
{
lp.Comm.ShowMessage("This core is not deterministic, switch over to the Ares (Accuracy) core for deterministic movie recordings. You have been warned!");
}
_serviceProvider = new(this);
_syncSettings = lp.SyncSettings ?? new();
int upscale = _syncSettings.EnableVulkan ? (int)_syncSettings.VulkanUpscale : 1;
_videoBuffer = new int[640 * upscale * 576 * upscale];
ControllerSettings = new[]
{
_syncSettings.P1Controller,
_syncSettings.P2Controller,
_syncSettings.P3Controller,
_syncSettings.P4Controller,
};
N64Controller = CreateControllerDefinition(ControllerSettings);
var rom = lp.Roms[0].RomData;
Region = rom[0x3E] switch
{
0x44 or 0x46 or 0x49 or 0x50 or 0x53 or 0x55 or 0x58 or 0x59 => DisplayType.PAL,
_ => DisplayType.NTSC,
};
var pal = Region == DisplayType.PAL;
VsyncNumerator = pal ? 50 : 60000;
VsyncDenominator = pal ? 1 : 1001;
LibAres64.LoadFlags loadFlags = 0;
if (_syncSettings.RestrictAnalogRange)
loadFlags |= LibAres64.LoadFlags.RestrictAnalogRange;
if (pal)
loadFlags |= LibAres64.LoadFlags.Pal;
if (_syncSettings.EnableVulkan)
loadFlags |= LibAres64.LoadFlags.UseVulkan;
if (_syncSettings.SuperSample)
loadFlags |= LibAres64.LoadFlags.SuperSample;
var pif = Util.DecompressGzipFile(new MemoryStream(pal ? Resources.PIF_PAL_ROM.Value : Resources.PIF_NTSC_ROM.Value));
unsafe
{
fixed (byte* pifPtr = pif, romPtr = rom)
{
var loadData = new LibAres64.LoadData()
{
PifData = (IntPtr)pifPtr,
PifLen = pif.Length,
RomData = (IntPtr)romPtr,
RomLen = rom.Length,
VulkanUpscale = upscale,
};
if (!_core.Init(loadData, ControllerSettings, loadFlags))
{
throw new InvalidOperationException("Init returned false!");
}
}
}
ResetCounters();
var areas = new LibWaterboxCore.MemoryArea[256];
_core.GetMemoryAreas(areas);
_memoryAreas = areas.Where(a => a.Data != IntPtr.Zero && a.Size != 0 && !a.Flags.HasFlag(LibWaterboxCore.MemoryDomainFlags.FunctionHook))
.ToArray();
var memoryDomains = _memoryAreas.Select(a => new WaterboxMemoryDomainPointer(a, _monitor)).ToList();
var primaryDomain = memoryDomains
.Where(md => md.Definition.Flags.HasFlag(LibWaterboxCore.MemoryDomainFlags.Primary))
.Single();
var mdl = new MemoryDomainList(
memoryDomains.Cast<MemoryDomain>().ToList()
)
{
MainMemory = primaryDomain
};
_serviceProvider.Register<IMemoryDomains>(mdl);
_saveramAreas = memoryDomains
.Where(md => md.Definition.Flags.HasFlag(LibWaterboxCore.MemoryDomainFlags.Saverammable))
.ToArray();
_saveramSize = (int)_saveramAreas.Sum(a => a.Size);
}
public DisplayType Region { get; }
public ControllerDefinition ControllerDefinition => N64Controller;
private ControllerDefinition N64Controller { get; }
public LibAres64.ControllerType[] ControllerSettings { get; }
private static ControllerDefinition CreateControllerDefinition(LibAres64.ControllerType[] controllerSettings)
{
var ret = new ControllerDefinition("Nintendo 64 Controller");
for (int i = 0; i < 4; i++)
{
if (controllerSettings[i] != LibAres64.ControllerType.Unplugged)
{
ret.BoolButtons.Add($"P{i + 1} DPad U");
ret.BoolButtons.Add($"P{i + 1} DPad D");
ret.BoolButtons.Add($"P{i + 1} DPad L");
ret.BoolButtons.Add($"P{i + 1} DPad R");
ret.BoolButtons.Add($"P{i + 1} Start");
ret.BoolButtons.Add($"P{i + 1} Z");
ret.BoolButtons.Add($"P{i + 1} B");
ret.BoolButtons.Add($"P{i + 1} A");
ret.BoolButtons.Add($"P{i + 1} C Up");
ret.BoolButtons.Add($"P{i + 1} C Down");
ret.BoolButtons.Add($"P{i + 1} C Left");
ret.BoolButtons.Add($"P{i + 1} C Right");
ret.BoolButtons.Add($"P{i + 1} L");
ret.BoolButtons.Add($"P{i + 1} R");
ret.AddXYPair($"P{i + 1} {{0}} Axis", AxisPairOrientation.RightAndUp, (-128).RangeTo(127), 0);
if (controllerSettings[i] == LibAres64.ControllerType.Rumblepak)
{
ret.HapticsChannels.Add($"P{i + 1} Rumble Pak");
}
}
}
ret.BoolButtons.Add("Reset");
ret.BoolButtons.Add("Power");
return ret.MakeImmutable();
}
private static LibAres64.Buttons GetButtons(IController controller, int num)
{
LibAres64.Buttons ret = 0;
if (controller.IsPressed($"P{num} DPad U"))
ret |= LibAres64.Buttons.UP;
if (controller.IsPressed($"P{num} DPad D"))
ret |= LibAres64.Buttons.DOWN;
if (controller.IsPressed($"P{num} DPad L"))
ret |= LibAres64.Buttons.LEFT;
if (controller.IsPressed($"P{num} DPad R"))
ret |= LibAres64.Buttons.RIGHT;
if (controller.IsPressed($"P{num} B"))
ret |= LibAres64.Buttons.B;
if (controller.IsPressed($"P{num} A"))
ret |= LibAres64.Buttons.A;
if (controller.IsPressed($"P{num} C Up"))
ret |= LibAres64.Buttons.C_UP;
if (controller.IsPressed($"P{num} C Down"))
ret |= LibAres64.Buttons.C_DOWN;
if (controller.IsPressed($"P{num} C Left"))
ret |= LibAres64.Buttons.C_LEFT;
if (controller.IsPressed($"P{num} C Right"))
ret |= LibAres64.Buttons.C_RIGHT;
if (controller.IsPressed($"P{num} L"))
ret |= LibAres64.Buttons.L;
if (controller.IsPressed($"P{num} R"))
ret |= LibAres64.Buttons.R;
if (controller.IsPressed($"P{num} Z"))
ret |= LibAres64.Buttons.Z;
if (controller.IsPressed($"P{num} Start"))
ret |= LibAres64.Buttons.START;
return ret;
}
private LibWaterboxCore.FrameInfo FrameAdvancePrep(IController controller, bool render, bool rendersound)
{
for (int i = 0; i < 4; i++)
{
if (ControllerSettings[i] == LibAres64.ControllerType.Rumblepak)
{
controller.SetHapticChannelStrength($"P{i + 1} Rumble Pak", _core.GetRumbleStatus(i) ? int.MaxValue : 0);
}
}
return new LibAres64.FrameInfo
{
P1Buttons = GetButtons(controller, 1),
P1XAxis = (short)controller.AxisValue("P1 X Axis"),
P1YAxis = (short)controller.AxisValue("P1 Y Axis"),
P2Buttons = GetButtons(controller, 2),
P2XAxis = (short)controller.AxisValue("P2 X Axis"),
P2YAxis = (short)controller.AxisValue("P2 Y Axis"),
P3Buttons = GetButtons(controller, 3),
P3XAxis = (short)controller.AxisValue("P3 X Axis"),
P3YAxis = (short)controller.AxisValue("P3 Y Axis"),
P4Buttons = GetButtons(controller, 4),
P4XAxis = (short)controller.AxisValue("P4 X Axis"),
P4YAxis = (short)controller.AxisValue("P4 Y Axis"),
Reset = controller.IsPressed("Reset"),
Power = controller.IsPressed("Power"),
};
}
public unsafe bool FrameAdvance(IController controller, bool render, bool rendersound = true)
{
_core.SetInputCallback(null);
fixed (int* vp = _videoBuffer)
fixed (short* sp = _soundBuffer)
{
var frame = FrameAdvancePrep(controller, render, rendersound);
frame.VideoBuffer = (IntPtr)vp;
frame.SoundBuffer = (IntPtr)sp;
_core.FrameAdvance(frame);
Frame++;
if (IsLagFrame = frame.Lagged != 0)
LagCount++;
if (render)
{
BufferWidth = frame.Width;
BufferHeight = frame.Height;
}
if (rendersound)
{
_numSamples = frame.Samples;
}
else
{
_numSamples = 0;
}
FrameAdvancePost();
}
return true;
}
private void FrameAdvancePost()
{
if (BufferWidth == 1 && BufferHeight == 1)
{
BufferWidth = 640;
BufferHeight = 480;
_blankFrame = true;
}
else
{
_blankFrame = false;
}
}
public int[] GetVideoBuffer() => _blankFrame ? _blankBuffer : _videoBuffer;
private bool _blankFrame;
private readonly int[] _blankBuffer = new int[640 * 480];
private readonly int[] _videoBuffer;
public int VirtualWidth => 640;
public int VirtualHeight => 480;
public int BufferWidth { get; private set; }
public int BufferHeight { get; private set; }
public int VsyncNumerator { get; }
public int VsyncDenominator { get; }
public int BackgroundColor => unchecked((int)0xff000000);
public void SetSyncMode(SyncSoundMode mode)
{
if (mode == SyncSoundMode.Async)
{
throw new NotSupportedException("Async mode is not supported.");
}
}
public void GetSamplesSync(out short[] samples, out int nsamp)
{
samples = _soundBuffer;
nsamp = _numSamples;
}
public void GetSamplesAsync(short[] samples) => throw new InvalidOperationException("Async mode is not supported.");
public void DiscardSamples() {}
private readonly short[] _soundBuffer = new short[2048 * 2];
private int _numSamples;
public bool CanProvideAsync => false;
public SyncSoundMode SyncMode => SyncSoundMode.Sync;
private byte[] _stateBuffer = new byte[0];
public void SaveStateBinary(BinaryWriter writer)
{
var len = _core.SerializeSize();
if (len != _stateBuffer.Length)
{
_stateBuffer = new byte[len];
}
_core.Serialize(_stateBuffer);
writer.Write(_stateBuffer.Length);
writer.Write(_stateBuffer);
// other variables
writer.Write(Frame);
writer.Write(LagCount);
writer.Write(IsLagFrame);
}
public void LoadStateBinary(BinaryReader reader)
{
var len = reader.ReadInt32();
if (len != _core.SerializeSize())
{
throw new InvalidOperationException("Savestate size mismatch!");
}
if (len != _stateBuffer.Length)
{
_stateBuffer = new byte[len];
}
reader.Read(_stateBuffer, 0, len);
if (!_core.Unserialize(_stateBuffer, len))
{
throw new Exception($"{nameof(_core.Unserialize)}() returned false!");
}
// other variables
Frame = reader.ReadInt32();
LagCount = reader.ReadInt32();
IsLagFrame = reader.ReadBoolean();
}
private readonly LibWaterboxCore.MemoryArea[] _memoryAreas;
private readonly WaterboxMemoryDomain[] _saveramAreas;
private readonly int _saveramSize;
public unsafe bool SaveRamModified
{
get
{
if (_saveramSize == 0)
return false;
var buff = new byte[4096];
fixed (byte* bp = buff)
{
foreach (var area in _saveramAreas)
{
var stream = new MemoryDomainStream(area);
int cmp = (area.Definition.Flags & LibWaterboxCore.MemoryDomainFlags.OneFilled) != 0 ? -1 : 0;
while (true)
{
int nread = stream.Read(buff, 0, 4096);
if (nread == 0)
break;
int* p = (int*)bp;
int* pend = p + nread / sizeof(int);
while (p < pend)
{
if (*p++ != cmp)
return true;
}
}
}
}
return false;
}
}
public byte[] CloneSaveRam()
{
if (_saveramSize == 0)
return null;
var ret = new byte[_saveramSize];
var dest = new MemoryStream(ret, true);
foreach (var area in _saveramAreas)
{
new MemoryDomainStream(area).CopyTo(dest);
}
return ret;
}
public void StoreSaveRam(byte[] data)
{
if (data.Length != _saveramSize)
throw new InvalidOperationException("Saveram size mismatch");
var source = new MemoryStream(data, false);
foreach (var area in _saveramAreas)
{
WaterboxUtils.CopySome(source, new MemoryDomainStream(area), area.Size);
}
}
private readonly DummyMonitor _monitor = new();
private class DummyMonitor : IMonitor
{
public void Enter() { }
public void Exit() { }
}
}
}

View File

@ -6,16 +6,16 @@ using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Properties;
using BizHawk.Emulation.Cores.Waterbox;
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Ares64.Accuracy
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Ares64
{
[PortedCore(CoreNames.Ares64Accuracy, "ares team, Near", "v126", "https://ares-emulator.github.io/", isReleased: false)]
[PortedCore(CoreNames.Ares64, "ares team, Near", "v127", "https://ares-emulator.github.io/", isReleased: false)]
[ServiceNotApplicable(new[] { typeof(IDriveLight), })]
public partial class Ares64 : WaterboxCore, IRegionable
{
private readonly LibAres64Accuracy _core;
private readonly LibAres64 _core;
[CoreConstructor(VSystemID.Raw.N64)]
public Ares64(CoreLoadParameters<object, Ares64SyncSettings> lp)
public Ares64(CoreLoadParameters<Ares64Settings, Ares64SyncSettings> lp)
: base(lp.Comm, new Configuration
{
DefaultWidth = 640,
@ -23,11 +23,12 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Ares64.Accuracy
MaxWidth = 640,
MaxHeight = 576,
MaxSamples = 2048,
DefaultFpsNumerator = 60000,
DefaultFpsDenominator = 1001,
DefaultFpsNumerator = 60,
DefaultFpsDenominator = 1,
SystemId = VSystemID.Raw.N64,
})
{
_settings = lp.Settings ?? new();
_syncSettings = lp.SyncSettings ?? new();
ControllerSettings = new[]
@ -40,7 +41,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Ares64.Accuracy
N64Controller = CreateControllerDefinition(ControllerSettings);
_core = PreInit<LibAres64Accuracy>(new WaterboxOptions
_core = PreInit<LibAres64>(new WaterboxOptions
{
Filename = "ares64.wbx",
SbrkHeapSizeKB = 2 * 1024,
@ -73,6 +74,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Ares64.Accuracy
loadFlags |= LibAres64.LoadFlags.RestrictAnalogRange;
if (pal)
loadFlags |= LibAres64.LoadFlags.Pal;
if (_settings.Deinterlacer == LibAres64.DeinterlacerType.Bob)
loadFlags |= LibAres64.LoadFlags.BobDeinterlace;
var pif = Util.DecompressGzipFile(new MemoryStream(pal ? Resources.PIF_PAL_ROM.Value : Resources.PIF_NTSC_ROM.Value));
@ -87,7 +90,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Ares64.Accuracy
RomData = (IntPtr)romPtr,
RomLen = rom.Length,
};
if (!_core.Init(loadData, ControllerSettings, loadFlags))
if (!_core.Init(ref loadData, ControllerSettings, loadFlags))
{
throw new InvalidOperationException("Init returned false!");
}
@ -207,17 +210,5 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Ares64.Accuracy
Power = controller.IsPressed("Power"),
};
}
protected override void FrameAdvancePost()
{
if (BufferWidth == 0)
{
BufferWidth = BufferHeight == 239 ? 320 : 640;
}
}
public override int VirtualWidth => 640;
public override int VirtualHeight => 480;
}
}

View File

@ -35,6 +35,12 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Ares64
Rumblepak,
}
public enum DeinterlacerType : uint
{
Weave,
Bob,
}
[StructLayout(LayoutKind.Sequential)]
public new class FrameInfo : LibWaterboxCore.FrameInfo
{
@ -64,52 +70,22 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Ares64
{
RestrictAnalogRange = 1 << 0,
Pal = 1 << 1,
// performance only flags
UseVulkan = 1 << 2,
SuperSample = 1 << 3,
}
public enum VulkanUpscaleOpts : uint
{
SD = 1,
HD = 2,
UHD = 4,
BobDeinterlace = 1 << 2, // weave otherwise
}
[StructLayout(LayoutKind.Sequential)]
public class LoadData
public struct LoadData
{
public IntPtr PifData;
public int PifLen;
public IntPtr RomData;
public int RomLen;
// performance only data
public int VulkanUpscale;
}
[BizImport(CC)]
public abstract bool Init(LoadData loadData, ControllerType[] controllerSettings, LoadFlags loadFlags);
public abstract bool Init(ref LoadData loadData, ControllerType[] controllerSettings, LoadFlags loadFlags);
[BizImport(CC)]
public abstract bool GetRumbleStatus(int num);
}
public abstract class LibAres64Accuracy : LibAres64
{
}
public abstract class LibAres64Performance : LibAres64
{
[BizImport(CC)]
public abstract void Deinit();
[BizImport(CC)]
public abstract int SerializeSize();
[BizImport(CC)]
public abstract void Serialize(byte[] buf);
[BizImport(CC)]
public abstract bool Unserialize(byte[] buf, int sz);
}
}

View File

@ -10,8 +10,7 @@ namespace BizHawk.Emulation.Cores
public static class CoreNames
{
public const string A7800Hawk = "A7800Hawk";
public const string Ares64Accuracy = "Ares64 (Accuracy)";
public const string Ares64Performance = "Ares64 (Performance)";
public const string Ares64 = "Ares64";
public const string Atari2600Hawk = "Atari2600Hawk";
public const string Bsnes = "BSNES";
public const string Bsnes115 = "BSNESv115+";

View File

@ -26,21 +26,11 @@ namespace BizHawk.Emulation.Cores
}
}
}
else if (core is Consoles.Nintendo.Ares64.Accuracy.Ares64 ares64Acc)
else if (core is Ares64 ares64)
{
for (var i = 0; i < 4; i++)
{
if (ares64Acc.ControllerSettings[i] != LibAres64.ControllerType.Unplugged)
{
yield return StandardController(i + 1);
}
}
}
else if (core is Consoles.Nintendo.Ares64.Performance.Ares64 ares64Perf)
{
for (var i = 0; i < 4; i++)
{
if (ares64Perf.ControllerSettings[i] != LibAres64.ControllerType.Unplugged)
if (ares64.ControllerSettings[i] != LibAres64.ControllerType.Unplugged)
{
yield return StandardController(i + 1);
}

View File

@ -1,17 +1,10 @@
#include <n64/n64.hpp>
#if WATERBOXED
#include <emulibc.h>
#include <waterboxcore.h>
#endif
#include <vector>
#ifndef WATERBOXED
#define ECL_EXPORT __attribute__((visibility("default")))
#include "../emulibc/waterboxcore.h"
#endif
#define EXPORT extern "C" ECL_EXPORT
typedef enum
@ -321,9 +314,7 @@ static inline SaveType DetectSaveType(u8* rom)
return ret;
}
namespace ares::Nintendo64 { extern bool RestrictAnalogRange; }
bool Inited = false;
namespace ares::Nintendo64 { extern bool RestrictAnalogRange; extern bool BobDeinterlace; }
typedef struct
{
@ -331,27 +322,17 @@ typedef struct
u32 PifLen;
u8* RomData;
u32 RomLen;
#ifndef WATERBOXED
u32 VulkanUpscale;
#endif
} LoadData;
typedef enum
{
RESTRICT_ANALOG_RANGE = 1 << 0,
IS_PAL = 1 << 1,
#ifndef WATERBOXED
USE_VULKAN = 1 << 2,
SUPER_SAMPLE = 1 << 3,
#endif
BOB_DEINTERLACE = 1 << 2, // weave otherwise (todo: implement this)
} LoadFlags;
EXPORT void Deinit();
EXPORT bool Init(LoadData* loadData, ControllerType* controllers, LoadFlags loadFlags)
{
if (Inited) Deinit();
platform = new BizPlatform;
platform->bizpak = new vfs::directory;
@ -397,7 +378,7 @@ EXPORT bool Init(LoadData* loadData, ControllerType* controllers, LoadFlags load
case SRAM32KB: len = 32 * 1024; name = "save.ram"; break;
case SRAM96KB: len = 96 * 1024; name = "save.ram"; break;
case FLASH128KB: len = 128 * 1024; name = "save.flash"; break;
default: Deinit(); return false;
default: return false;
}
data = new u8[len];
memset(data, 0xFF, len);
@ -407,15 +388,8 @@ EXPORT bool Init(LoadData* loadData, ControllerType* controllers, LoadFlags load
ares::platform = platform;
#ifndef WATERBOXED
ares::Nintendo64::option("Enable Vulkan", !!(loadFlags & USE_VULKAN));
ares::Nintendo64::option("Quality", loadData->VulkanUpscale == 1 ? "SD" : (loadData->VulkanUpscale == 2 ? "HD" : "UHD"));
ares::Nintendo64::option("Supersampling", !!(loadFlags & SUPER_SAMPLE));
#endif
if (!ares::Nintendo64::load(root, {"[Nintendo] Nintendo 64 (", region, ")"}))
{
Deinit();
return false;
}
@ -426,7 +400,6 @@ EXPORT bool Init(LoadData* loadData, ControllerType* controllers, LoadFlags load
}
else
{
Deinit();
return false;
}
@ -453,51 +426,23 @@ EXPORT bool Init(LoadData* loadData, ControllerType* controllers, LoadFlags load
}
else
{
Deinit();
return false;
}
}
else
{
Deinit();
return false;
}
}
ares::Nintendo64::RestrictAnalogRange = loadFlags & RESTRICT_ANALOG_RANGE;
ares::Nintendo64::BobDeinterlace = loadFlags & BOB_DEINTERLACE;
root->power(false);
HackeryDoo();
Inited = true;
return true;
}
EXPORT void Deinit()
{
if (root) root->unload();
if (platform)
{
if (platform->bizpak) platform->bizpak.reset();
delete platform;
}
if (pifData)
{
delete[] (u8*)pifData->data();
delete pifData;
}
if (romData)
{
delete[] (u8*)romData->data();
delete romData;
}
if (saveData)
{
delete[] (u8*)saveData->data();
delete saveData;
}
Inited = false;
}
EXPORT bool GetRumbleStatus(u32 num)
{
ares::Nintendo64::Gamepad* c = nullptr;
@ -511,23 +456,6 @@ EXPORT bool GetRumbleStatus(u32 num)
return c ? c->motor->enable() : false;
}
EXPORT u32 SerializeSize()
{
return root->serialize(false).size();
}
EXPORT void Serialize(u8* buf)
{
auto s = root->serialize(false);
memcpy(buf, s.data(), s.size());
}
EXPORT bool Unserialize(u8* buf, u32 sz)
{
serializer s(buf, sz);
return root->unserialize(s);
}
#define ADD_MEMORY_DOMAIN(mem, name, flags) do { \
m[i].Data = ares::Nintendo64::mem.data; \
m[i].Name = name; \
@ -565,7 +493,6 @@ EXPORT void GetMemoryAreas(MemoryArea *m)
ADD_MEMPAK_DOMAIN(4);
}
// fixme: this mismatches the c# side due to some re-ordering c# is doing for some reason
struct MyFrameInfo : public FrameInfo
{
Buttons_t P1Buttons;
@ -664,4 +591,4 @@ EXPORT void FrameAdvance(MyFrameInfo* f)
EXPORT void SetInputCallback(void (*callback)())
{
platform->inputcb = callback;
}
}

View File

@ -1,18 +1,15 @@
NEED_LIBCO := 1
ARES_PATH = $(ROOT_DIR)/ares/ares
MAME_PATH = $(ROOT_DIR)/ares/thirdparty/mame
ANGRYLION_PATH = $(ROOT_DIR)/ares/thirdparty/angrylion-rdp/mylittle-nocomment
CXXFLAGS := -std=c++17 -msse4.2 \
-I../libco -I.$(ROOT_DIR)/ares/ -I.$(ROOT_DIR)/ares/thirdparty/ -I.$(ARES_PATH) \
-Werror=int-to-pointer-cast -Wno-unused-but-set-variable -Wno-delete-non-virtual-dtor \
-Wno-parentheses -Wno-reorder -Wno-unused-variable \
-Werror=int-to-pointer-cast -Wno-unused-but-set-variable -Wno-format-security \
-Wno-parentheses -Wno-reorder -Wno-unused-variable -Wno-delete-non-virtual-dtor \
-Wno-sign-compare -Wno-switch -Wno-unused-local-typedefs \
-fno-strict-aliasing -fwrapv -fno-operator-names \
-I.$(MAME_PATH)/devices -I.$(MAME_PATH)/emu \
-I.$(MAME_PATH)/lib/util -I.$(MAME_PATH)/mame \
-I.$(MAME_PATH)/osd -DMAME_RDP -DLSB_FIRST -DPTR64 -DSDLMAME_EMSCRIPTEN \
-DWATERBOXED
-I.$(ANGRYLION_PATH) -DANGRYLION_RDP
TARGET = ares64.wbx
@ -42,17 +39,10 @@ SRCS_N64 = \
$(ARES_PATH)/n64/rdp/rdp.cpp \
$(ARES_PATH)/n64/rsp/rsp.cpp
SRCS_MAME = \
$(MAME_PATH)/emu/emucore.cpp \
$(MAME_PATH)/lib/util/delegate.cpp \
$(MAME_PATH)/lib/util/strformat.cpp \
$(MAME_PATH)/mame/video/n64.cpp \
$(MAME_PATH)/mame/video/pin64.cpp \
$(MAME_PATH)/mame/video/rdpblend.cpp \
$(MAME_PATH)/mame/video/rdptpipe.cpp \
$(MAME_PATH)/osd/osdcore.cpp \
$(MAME_PATH)/osd/osdsync.cpp
SRCS_ANGRYLION = \
$(ANGRYLION_PATH)/main.cpp \
$(ANGRYLION_PATH)/n64video.cpp
SRCS = $(SRCS_PROCESSORS) $(SRCS_ARES) $(SRCS_N64) $(SRCS_MAME) BizInterface.cpp
SRCS = $(SRCS_PROCESSORS) $(SRCS_ARES) $(SRCS_N64) $(SRCS_ANGRYLION) BizInterface.cpp
include ../common.mak

View File

@ -1,160 +0,0 @@
ARES_PATH = $(ROOT_DIR)/ares/ares
MAME_PATH = $(ROOT_DIR)/ares/thirdparty/mame
SLJIT_PATH = $(ROOT_DIR)/ares/thirdparty/sljit
CCFLAGS := -std=c99 -Wall -Wno-format -Wno-parentheses
CXXFLAGS := -std=c++17 -msse4.2 -O3 -flto -fvisibility=internal \
-I../libco -I.$(ROOT_DIR)/ares/ -I.$(ROOT_DIR)/ares/thirdparty/ -I.$(ARES_PATH) \
-Werror=int-to-pointer-cast -Wno-unused-but-set-variable \
-Wno-parentheses -Wno-reorder -Wno-unused-variable \
-Wno-sign-compare -Wno-switch -Wno-unused-local-typedefs \
-fno-strict-aliasing -fwrapv -fno-operator-names \
-I.$(MAME_PATH)/devices -I.$(MAME_PATH)/emu \
-I.$(MAME_PATH)/lib/util -I.$(MAME_PATH)/mame \
-I.$(MAME_PATH)/osd -DMAME_RDP -DLSB_FIRST -DPTR64 -DSLJIT_HAVE_CONFIG_PRE=1 -DSLJIT_HAVE_CONFIG_POST=1 -fPIC
LDFLAGS := -shared
ifeq ($(OS),Windows_NT)
CCFLAGS += -DVK_USE_PLATFORM_WIN32_KHR
CXXFLAGS += -DVK_USE_PLATFORM_WIN32_KHR -DOSD_WINDOWS=1
TARGET = libares64.dll
else
CXXFLAGS += -DSDLMAME_LINUX
TARGET = libares64.so
endif
SRCS_LIBCO = \
$(ROOT_DIR)/ares/libco/libco.c
SRCS_PROCESSORS = \
$(ARES_PATH)/component/processor/sm5k/sm5k.cpp
SRCS_ARES = \
$(ARES_PATH)/ares/ares.cpp \
$(ARES_PATH)/ares/memory/fixed-allocator.cpp
SRCS_N64 = \
$(ARES_PATH)/n64/memory/memory.cpp \
$(ARES_PATH)/n64/system/system.cpp \
$(ARES_PATH)/n64/cartridge/cartridge.cpp \
$(ARES_PATH)/n64/controller/controller.cpp \
$(ARES_PATH)/n64/dd/dd.cpp \
$(ARES_PATH)/n64/sp/sp.cpp \
$(ARES_PATH)/n64/dp/dp.cpp \
$(ARES_PATH)/n64/mi/mi.cpp \
$(ARES_PATH)/n64/vi/vi.cpp \
$(ARES_PATH)/n64/ai/ai.cpp \
$(ARES_PATH)/n64/pi/pi.cpp \
$(ARES_PATH)/n64/ri/ri.cpp \
$(ARES_PATH)/n64/si/si.cpp \
$(ARES_PATH)/n64/rdram/rdram.cpp \
$(ARES_PATH)/n64/cpu/cpu.cpp \
$(ARES_PATH)/n64/rdp/rdp.cpp \
$(ARES_PATH)/n64/rsp/rsp.cpp \
$(ARES_PATH)/n64/vulkan/vulkan.cpp
PARALLEL_RDP_IMPLEMENTATION = $(ARES_PATH)/n64/vulkan/parallel-rdp
SRCS_PARALLEL_RDP = \
$(wildcard $(PARALLEL_RDP_IMPLEMENTATION)/parallel-rdp/*.cpp) \
$(PARALLEL_RDP_IMPLEMENTATION)/vulkan/buffer.cpp \
$(PARALLEL_RDP_IMPLEMENTATION)/vulkan/buffer_pool.cpp \
$(PARALLEL_RDP_IMPLEMENTATION)/vulkan/command_buffer.cpp \
$(PARALLEL_RDP_IMPLEMENTATION)/vulkan/command_pool.cpp \
$(PARALLEL_RDP_IMPLEMENTATION)/vulkan/context.cpp \
$(PARALLEL_RDP_IMPLEMENTATION)/vulkan/cookie.cpp \
$(PARALLEL_RDP_IMPLEMENTATION)/vulkan/descriptor_set.cpp \
$(PARALLEL_RDP_IMPLEMENTATION)/vulkan/device.cpp \
$(PARALLEL_RDP_IMPLEMENTATION)/vulkan/event_manager.cpp \
$(PARALLEL_RDP_IMPLEMENTATION)/vulkan/fence.cpp \
$(PARALLEL_RDP_IMPLEMENTATION)/vulkan/fence_manager.cpp \
$(PARALLEL_RDP_IMPLEMENTATION)/vulkan/image.cpp \
$(PARALLEL_RDP_IMPLEMENTATION)/vulkan/memory_allocator.cpp \
$(PARALLEL_RDP_IMPLEMENTATION)/vulkan/pipeline_event.cpp \
$(PARALLEL_RDP_IMPLEMENTATION)/vulkan/query_pool.cpp \
$(PARALLEL_RDP_IMPLEMENTATION)/vulkan/render_pass.cpp \
$(PARALLEL_RDP_IMPLEMENTATION)/vulkan/sampler.cpp \
$(PARALLEL_RDP_IMPLEMENTATION)/vulkan/semaphore.cpp \
$(PARALLEL_RDP_IMPLEMENTATION)/vulkan/semaphore_manager.cpp \
$(PARALLEL_RDP_IMPLEMENTATION)/vulkan/shader.cpp \
$(PARALLEL_RDP_IMPLEMENTATION)/vulkan/texture_format.cpp \
$(PARALLEL_RDP_IMPLEMENTATION)/util/logging.cpp \
$(PARALLEL_RDP_IMPLEMENTATION)/util/thread_id.cpp \
$(PARALLEL_RDP_IMPLEMENTATION)/util/aligned_alloc.cpp \
$(PARALLEL_RDP_IMPLEMENTATION)/util/timer.cpp \
$(PARALLEL_RDP_IMPLEMENTATION)/util/timeline_trace_file.cpp \
$(PARALLEL_RDP_IMPLEMENTATION)/util/thread_name.cpp \
$(PARALLEL_RDP_IMPLEMENTATION)/volk/volk.c
PARALLEL_RDP_INCLUDE_DIRS = \
-I.$(PARALLEL_RDP_IMPLEMENTATION)/parallel-rdp \
-I.$(PARALLEL_RDP_IMPLEMENTATION)/volk \
-I.$(PARALLEL_RDP_IMPLEMENTATION)/vulkan \
-I.$(PARALLEL_RDP_IMPLEMENTATION)/vulkan-headers/include \
-I.$(PARALLEL_RDP_IMPLEMENTATION)/util
CXXFLAGS += $(PARALLEL_RDP_INCLUDE_DIRS) -DVULKAN -DGRANITE_VULKAN_MT
CCFLAGS += $(PARALLEL_RDP_INCLUDE_DIRS)
SRCS_MAME = \
$(MAME_PATH)/emu/emucore.cpp \
$(MAME_PATH)/lib/util/delegate.cpp \
$(MAME_PATH)/lib/util/strformat.cpp \
$(MAME_PATH)/mame/video/n64.cpp \
$(MAME_PATH)/mame/video/pin64.cpp \
$(MAME_PATH)/mame/video/rdpblend.cpp \
$(MAME_PATH)/mame/video/rdptpipe.cpp \
$(MAME_PATH)/osd/osdcore.cpp \
$(MAME_PATH)/osd/osdsync.cpp
SRCS_SLJIT = \
$(SLJIT_PATH)/../sljitAllocator.cpp \
$(SLJIT_PATH)/sljit_src/sljitLir.c
SRCS = $(SRCS_LIBCO) $(SRCS_PROCESSORS) $(SRCS_ARES) $(SRCS_N64) $(SRCS_PARALLEL_RDP) $(SRCS_MAME) $(SRCS_SLJIT) BizInterface.cpp
ROOT_DIR := $(shell dirname $(realpath Performance.mak))
OUTPUTDLL_DIR := $(realpath $(ROOT_DIR)/../../Assets/dll)
OUTPUTDLLCOPY_DIR := $(realpath $(ROOT_DIR)/../../output/dll)
OUT_DIR := $(ROOT_DIR)/obj
OBJ_DIR := $(OUT_DIR)/release_performance
CC := gcc
CXX := g++
_OBJS := $(addsuffix .o,$(realpath $(SRCS)))
OBJS := $(patsubst $(ROOT_DIR)%,$(OBJ_DIR)%,$(_OBJS))
$(OBJ_DIR)/%.c.o: %.c
@echo cc $<
@mkdir -p $(@D)
@$(CC) -c -o $@ $< $(CCFLAGS) $(PER_FILE_FLAGS_$<)
$(OBJ_DIR)/%.cpp.o: %.cpp
@echo cxx $<
@mkdir -p $(@D)
@$(CXX) -c -o $@ $< $(CXXFLAGS) $(PER_FILE_FLAGS_$<)
.DEFAULT_GOAL := install
.PHONY: release install
TARGET_RELEASE := $(OBJ_DIR)/$(TARGET)
release: $(TARGET_RELEASE)
$(TARGET_RELEASE): $(OBJS)
@echo ld $@
@$(CXX) -o $@ $(LDFLAGS) $(CCFLAGS) $(CXXFLAGS) $(OBJS)
install: $(TARGET_RELEASE)
@cp -f $(TARGET_RELEASE) $(OUTPUTDLL_DIR)/$(TARGET)
@cp -f $(TARGET_RELEASE) $(OUTPUTDLLCOPY_DIR)/$(TARGET)
@echo Release build of $(TARGET) installed.
.PHONY: clean
clean:
rm -rf $(OUT_DIR)
-include $(OBJS:%o=%d)

View File

@ -1,11 +1,7 @@
#pragma once
#ifdef WATERBOXED
#include <emulibc.h>
#include <libco.h>
#else
#include <libco/libco.h>
#endif
#include <sljit.h>
@ -61,11 +57,7 @@ namespace ares {
}
namespace Video {
#ifdef WATERBOXED
static constexpr bool Threaded = false;
#else
static constexpr bool Threaded = true;
#endif
}
namespace Constants {

View File

@ -3,17 +3,10 @@ Screen::Screen(string name, u32 width, u32 height) : Video(name) {
_canvasHeight = height;
if(width && height) {
#ifdef WATERBOXED
_inputA = alloc_invisible<u32>(width * height);
_inputB = alloc_invisible<u32>(width * height);
_output = alloc_invisible<u32>(width * height);
_rotate = alloc_invisible<u32>(width * height);
#else
_inputA = new u32[width * height]();
_inputB = new u32[width * height]();
_output = new u32[width * height]();
_rotate = new u32[width * height]();
#endif
if constexpr(ares::Video::Threaded) {
_thread = nall::thread::create({&Screen::main, this});

View File

@ -1,10 +1,6 @@
struct Accuracy {
//enable all accuracy flags
#ifdef WATERBOXED
static constexpr bool Reference = 1;
#else
static constexpr bool Reference = 0;
#endif
struct CPU {
static constexpr bool Interpreter = 0 | Reference;

View File

@ -15,10 +15,6 @@ using v128 = __m128i;
#include <n64/vulkan/vulkan.hpp>
#endif
#if defined(MAME_RDP)
class n64_state;
#endif
namespace ares::Nintendo64 {
auto enumerate() -> vector<string>;
auto load(Node::System& node, string name) -> bool;

View File

@ -1,19 +1,7 @@
#include <n64/n64.hpp>
#if defined(MAME_RDP)
#include "emu.h"
#include "includes/n64.h"
struct n64_periphs_impl : public n64_periphs {
auto dp_full_sync() -> void override {
ares::Nintendo64::rdp.syncFull();
}
static auto instance() -> n64_periphs_impl* {
static n64_periphs_impl* inst = new n64_periphs_impl();
return inst;
}
};
#if defined(ANGRYLION_RDP)
#include "Gfx #1.3.h"
#endif
namespace ares::Nintendo64 {
@ -28,10 +16,9 @@ auto RDP::load(Node::Object parent) -> void {
node = parent->append<Node::Object>("RDP");
debugger.load(node);
#if defined(MAME_RDP)
state = new n64_state((u32*)rdram.ram.data, (u32*)rsp.dmem.data, n64_periphs_impl::instance());
#if defined(ANGRYLION_RDP)
puts("starting RDP video");
state->video_start();
angrylion::RomOpen();
#endif
}
@ -39,8 +26,8 @@ auto RDP::unload() -> void {
debugger = {};
node.reset();
#if defined(MAME_RDP)
state.reset();
#if defined(ANGRYLION_RDP)
angrylion::RomClosed();
#endif
}

View File

@ -347,10 +347,6 @@ struct RDP : Thread, Memory::IO<RDP> {
n32 data;
} test;
} io{*this};
#if defined(MAME_RDP)
unique_pointer<n64_state> state;
#endif
};
extern RDP rdp;

View File

@ -49,15 +49,13 @@ auto RDP::render() -> void {
if(vulkan.enable && vulkan.render()) return;
#endif
#if defined(MAME_RDP)
auto rdp = state->rdp();
rdp->set_current(command.current);
rdp->set_end(command.end);
rdp->set_status(command.source ? DP_STATUS_XBUS_DMA : 0);
rdp->process_command_list();
command.current = rdp->get_current();
#if defined(ANGRYLION_RDP)
if (angrylion::ProcessRDPList()) {
command.start = command.current = command.end;
}
return;
#else
#endif
auto& memory = !command.source ? rdram.ram : rsp.dmem;
auto fetch = [&]() -> u64 {
@ -553,7 +551,6 @@ auto RDP::render() -> void {
}
}
#endif
}
//0x00

View File

@ -1,5 +1,9 @@
#include <n64/n64.hpp>
#if defined(ANGRYLION_RDP)
#include "Gfx #1.3.h"
#endif
namespace ares::Nintendo64 {
VI vi;
@ -78,6 +82,16 @@ auto VI::main() -> void {
}
#endif
#if defined(ANGRYLION_RDP)
#if defined(VULKAN)
if (!vulkan.enable) {
#endif
angrylion::UpdateScreen();
#if defined(VULKAN)
}
#endif
#endif
refreshed = true;
screen->frame();
}
@ -91,6 +105,8 @@ auto VI::step(u32 clocks) -> void {
Thread::clock += clocks;
}
bool BobDeinterlace = 0;
auto VI::refresh() -> void {
#if defined(VULKAN)
if(vulkan.enable && gpuOutputValid) {
@ -116,6 +132,22 @@ auto VI::refresh() -> void {
}
#endif
#if defined(ANGRYLION_RDP)
#if defined(VULKAN)
if(!vulkan.enable) {
#else
{
#endif
u32 width = 640;
u32 height = Region::PAL() ? 576 : 480;
screen->setViewport(0, 0, width, height);
u32* src = angrylion::FinalizeFrame(BobDeinterlace);
u32* dst = screen->pixels(1).data();
memcpy(dst, src, width * height * sizeof(u32));
return;
}
#endif
u32 pitch = vi.io.width;
u32 width = vi.io.width; //vi.io.xscale <= 0x300 ? 320 : 640;
u32 height = vi.io.yscale <= 0x400 ? 239 : 478;

@ -0,0 +1 @@
Subproject commit 53dfbd3e6c385bf1898de53d7ff176de6c4cffa1

File diff suppressed because it is too large Load Diff

View File

@ -1,115 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************
emu.h
Core header file to be included by most files.
NOTE: The contents of this file are designed to meet the needs of
drivers and devices. In addition to this file, you will also need
to include the headers of any CPUs or other devices that are required.
If you find yourself needing something outside of this file in a
driver or device, think carefully about what you are doing.
***************************************************************************/
#ifndef __EMU_H__
#define __EMU_H__
#include <list>
#include <forward_list>
#include <vector>
#include <memory>
#include <map>
#include <unordered_map>
#include <unordered_set>
// core emulator headers -- must be first (profiler needs attotime, attotime needs xtal)
#include "emucore.h"
#include "osdcore.h"
#include "eminline.h"
#if !defined(MAME_RDP)
#include "xtal.h"
#include "attotime.h"
#include "profiler.h"
// http interface helpers
#include "http.h"
#endif
// commonly-referenced utilities imported from lib/util
#include "corealloc.h"
#if !defined(MAME_RDP)
#include "palette.h"
#endif
// emulator-specific utilities
#include "hash.h"
#if !defined(MAME_RDP)
#include "fileio.h"
#endif
#include "delegate.h"
#if !defined(MAME_RDP)
#include "devdelegate.h"
// memory and address spaces
#include "emumem.h"
// machine-wide utilities
#include "romentry.h"
#include "save.h"
// I/O
#include "input.h"
#include "ioport.h"
#include "output.h"
// devices and callbacks
#include "device.h"
#include "devfind.h"
#include "addrmap.h" // Needs optional_device<> and required_device<>
#include "distate.h"
#include "dimemory.h"
#include "dipalette.h"
#include "digfx.h"
#include "diimage.h"
#include "dislot.h"
#include "disound.h"
#include "divideo.h"
#include "dinvram.h"
#include "schedule.h"
#include "dinetwork.h"
// machine and driver configuration
#include "mconfig.h"
#include "gamedrv.h"
#include "parameters.h"
// the running machine
#include "main.h"
#include "machine.h"
#include "driver.h"
// common device interfaces
#include "diexec.h"
#include "devcpu.h"
// video-related
#include "drawgfx.h"
#include "video.h"
// sound-related
#include "sound.h"
// generic helpers
#include "devcb.h"
#include "bookkeeping.h"
#include "video/generic.h"
// member templates that don't like incomplete types
#include "device.ipp"
#endif
#endif // __EMU_H__

View File

@ -1,43 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Nicola Salmoria, Aaron Giles
/***************************************************************************
emucore.cpp
Simple core functions that are defined in emucore.h and which may
need to be accessed by other MAME-related tools.
****************************************************************************/
#include "emu.h"
#include "emucore.h"
#include "osdcore.h"
emu_fatalerror::emu_fatalerror(util::format_argument_pack<std::ostream> const &args)
: emu_fatalerror(0, args)
{
#if !defined(MAME_RDP)
osd_break_into_debugger(m_text.c_str());
#endif
}
emu_fatalerror::emu_fatalerror(int _exitcode, util::format_argument_pack<std::ostream> const &args)
: m_text(util::string_format(args))
, m_code(_exitcode)
{
}
#if !defined(MAME_RDP)
void report_bad_cast(const std::type_info &src_type, const std::type_info &dst_type)
{
throw emu_fatalerror("Error: bad downcast<> or device<>. Tried to convert a %s to a %s, which are incompatible.\n",
src_type.name(), dst_type.name());
}
void report_bad_device_cast(const device_t *dev, const std::type_info &src_type, const std::type_info &dst_type)
{
throw emu_fatalerror("Error: bad downcast<> or device<>. Tried to convert the device %s (%s) of type %s to a %s, which are incompatible.\n",
dev->tag(), dev->name(), src_type.name(), dst_type.name());
}
#endif

View File

@ -1,424 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Nicola Salmoria, Aaron Giles
/***************************************************************************
emucore.h
General core utilities and macros used throughout the emulator.
***************************************************************************/
#ifndef MAME_EMU_EMUCORE_H
#define MAME_EMU_EMUCORE_H
#pragma once
// standard C includes
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cstdarg>
// some cleanups for Solaris for things defined in stdlib.h
#if defined(__sun__) && defined(__svr4__)
#undef si_status
#undef WWORD
#endif
// standard C++ includes
#include <exception>
#include <string>
#include <type_traits>
#include <typeinfo>
// core system includes
#include "osdcomm.h"
#include "coretmpl.h"
#include "bitmap.h"
#include "endianness.h"
#include "strformat.h"
#include "vecstream.h"
#include "emufwd.h"
//**************************************************************************
// COMPILER-SPECIFIC NASTINESS
//**************************************************************************
// Suppress warnings about redefining the macro 'PPC' on LinuxPPC.
#undef PPC
// Suppress warnings about redefining the macro 'ARM' on ARM.
#undef ARM
//**************************************************************************
// FUNDAMENTAL TYPES
//**************************************************************************
// explicitly sized integers
using osd::u8;
using osd::u16;
using osd::u32;
using osd::u64;
using osd::s8;
using osd::s16;
using osd::s32;
using osd::s64;
// useful utility functions
using util::underlying_value;
using util::enum_value;
using util::make_bitmask;
using util::BIT;
using util::bitswap;
using util::iabs;
using util::string_format;
using endianness_t = util::endianness;
using util::BYTE_XOR_BE;
using util::BYTE_XOR_LE;
using util::BYTE4_XOR_BE;
using util::BYTE4_XOR_LE;
using util::WORD_XOR_BE;
using util::WORD_XOR_LE;
using util::BYTE8_XOR_BE;
using util::BYTE8_XOR_LE;
using util::WORD2_XOR_BE;
using util::WORD2_XOR_LE;
using util::DWORD_XOR_BE;
using util::DWORD_XOR_LE;
// pen_t is used to represent pixel values in bitmaps
typedef u32 pen_t;
//**************************************************************************
// USEFUL COMPOSITE TYPES
//**************************************************************************
// PAIR is an endian-safe union useful for representing 32-bit CPU registers
union PAIR
{
#ifdef LSB_FIRST
struct { u8 l,h,h2,h3; } b;
struct { u16 l,h; } w;
struct { s8 l,h,h2,h3; } sb;
struct { s16 l,h; } sw;
#else
struct { u8 h3,h2,h,l; } b;
struct { s8 h3,h2,h,l; } sb;
struct { u16 h,l; } w;
struct { s16 h,l; } sw;
#endif
u32 d;
s32 sd;
};
// PAIR16 is a 16-bit extension of a PAIR
union PAIR16
{
#ifdef LSB_FIRST
struct { u8 l,h; } b;
struct { s8 l,h; } sb;
#else
struct { u8 h,l; } b;
struct { s8 h,l; } sb;
#endif
u16 w;
s16 sw;
};
// PAIR64 is a 64-bit extension of a PAIR
union PAIR64
{
#ifdef LSB_FIRST
struct { u8 l,h,h2,h3,h4,h5,h6,h7; } b;
struct { u16 l,h,h2,h3; } w;
struct { u32 l,h; } d;
struct { s8 l,h,h2,h3,h4,h5,h6,h7; } sb;
struct { s16 l,h,h2,h3; } sw;
struct { s32 l,h; } sd;
#else
struct { u8 h7,h6,h5,h4,h3,h2,h,l; } b;
struct { u16 h3,h2,h,l; } w;
struct { u32 h,l; } d;
struct { s8 h7,h6,h5,h4,h3,h2,h,l; } sb;
struct { s16 h3,h2,h,l; } sw;
struct { s32 h,l; } sd;
#endif
u64 q;
s64 sq;
};
//**************************************************************************
// COMMON CONSTANTS
//**************************************************************************
constexpr endianness_t ENDIANNESS_LITTLE = util::endianness::little;
constexpr endianness_t ENDIANNESS_BIG = util::endianness::big;
constexpr endianness_t ENDIANNESS_NATIVE = util::endianness::native;
// M_PI is not part of the C/C++ standards and is not present on
// strict ANSI compilers or when compiling under GCC with -ansi
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
/// \name Image orientation flags
/// \{
constexpr int ORIENTATION_FLIP_X = 0x0001; ///< Mirror horizontally (in the X direction)
constexpr int ORIENTATION_FLIP_Y = 0x0002; ///< Mirror vertically (in the Y direction)
constexpr int ORIENTATION_SWAP_XY = 0x0004; ///< Mirror along the top-left/bottom-right diagonal
constexpr int ROT0 = 0;
constexpr int ROT90 = ORIENTATION_SWAP_XY | ORIENTATION_FLIP_X; ///< Rotate 90 degrees clockwise
constexpr int ROT180 = ORIENTATION_FLIP_X | ORIENTATION_FLIP_Y; ///< Rotate 180 degrees
constexpr int ROT270 = ORIENTATION_SWAP_XY | ORIENTATION_FLIP_Y; ///< Rotate 90 degrees anti-clockwise (270 degrees clockwise)
/// \}
// these are UTF-8 encoded strings for common characters
#define UTF8_NBSP "\xc2\xa0" /* non-breaking space */
#define UTF8_MULTIPLY "\xc3\x97" /* multiplication sign */
#define UTF8_DIVIDE "\xc3\xb7" /* division sign */
#define UTF8_SQUAREROOT "\xe2\x88\x9a" /* square root symbol */
#define UTF8_PLUSMINUS "\xc2\xb1" /* plusminus symbol */
#define UTF8_POW_2 "\xc2\xb2" /* superscript 2 */
#define UTF8_POW_X "\xcb\xa3" /* superscript x */
#define UTF8_POW_Y "\xca\xb8" /* superscript y */
#define UTF8_PRIME "\xca\xb9" /* prime symbol */
#define UTF8_DEGREES "\xc2\xb0" /* degrees symbol */
#define UTF8_SMALL_PI "\xcf\x80" /* Greek small letter pi */
#define UTF8_CAPITAL_SIGMA "\xce\xa3" /* Greek capital letter sigma */
#define UTF8_CAPITAL_DELTA "\xce\x94" /* Greek capital letter delta */
#define UTF8_MACRON "\xc2\xaf" /* macron symbol */
#define UTF8_NONSPACE_MACRON "\xcc\x84" /* nonspace macron, use after another char */
#define a_RING "\xc3\xa5" /* small a with a ring */
#define a_UMLAUT "\xc3\xa4" /* small a with an umlaut */
#define o_UMLAUT "\xc3\xb6" /* small o with an umlaut */
#define u_UMLAUT "\xc3\xbc" /* small u with an umlaut */
#define e_ACUTE "\xc3\xa9" /* small e with an acute */
#define n_TILDE "\xc3\xb1" /* small n with a tilde */
#define A_RING "\xc3\x85" /* capital A with a ring */
#define A_UMLAUT "\xc3\x84" /* capital A with an umlaut */
#define O_UMLAUT "\xc3\x96" /* capital O with an umlaut */
#define U_UMLAUT "\xc3\x9c" /* capital U with an umlaut */
#define E_ACUTE "\xc3\x89" /* capital E with an acute */
#define N_TILDE "\xc3\x91" /* capital N with a tilde */
#define UTF8_LEFT "\xe2\x86\x90" /* cursor left */
#define UTF8_RIGHT "\xe2\x86\x92" /* cursor right */
#define UTF8_UP "\xe2\x86\x91" /* cursor up */
#define UTF8_DOWN "\xe2\x86\x93" /* cursor down */
//**************************************************************************
// COMMON MACROS
//**************************************************************************
// macro for defining a copy constructor and assignment operator to prevent copying
#define DISABLE_COPYING(TYPE) \
TYPE(const TYPE &) = delete; \
TYPE &operator=(const TYPE &) = delete
// macro for declaring enumeration operators that increment/decrement like plain old C
#define DECLARE_ENUM_INCDEC_OPERATORS(TYPE) \
inline TYPE &operator++(TYPE &value) { return value = TYPE(std::underlying_type_t<TYPE>(value) + 1); } \
inline TYPE &operator--(TYPE &value) { return value = TYPE(std::underlying_type_t<TYPE>(value) - 1); } \
inline TYPE operator++(TYPE &value, int) { TYPE const old(value); ++value; return old; } \
inline TYPE operator--(TYPE &value, int) { TYPE const old(value); --value; return old; }
// macro for declaring bitwise operators for an enumerated type
#define DECLARE_ENUM_BITWISE_OPERATORS(TYPE) \
constexpr TYPE operator~(TYPE value) { return TYPE(~std::underlying_type_t<TYPE>(value)); } \
constexpr TYPE operator&(TYPE a, TYPE b) { return TYPE(std::underlying_type_t<TYPE>(a) & std::underlying_type_t<TYPE>(b)); } \
constexpr TYPE operator|(TYPE a, TYPE b) { return TYPE(std::underlying_type_t<TYPE>(a) | std::underlying_type_t<TYPE>(b)); } \
inline TYPE &operator&=(TYPE &a, TYPE b) { return a = a & b; } \
inline TYPE &operator|=(TYPE &a, TYPE b) { return a = a | b; }
// this macro passes an item followed by a string version of itself as two consecutive parameters
#define NAME(x) x, #x
// this macro wraps a function 'x' and can be used to pass a function followed by its name
#define FUNC(x) &x, #x
// macros to convert radians to degrees and degrees to radians
template <typename T> constexpr auto RADIAN_TO_DEGREE(T const &x) { return (180.0 / M_PI) * x; }
template <typename T> constexpr auto DEGREE_TO_RADIAN(T const &x) { return (M_PI / 180.0) * x; }
//**************************************************************************
// EXCEPTION CLASSES
//**************************************************************************
// emu_exception is the base class for all emu-related exceptions
class emu_exception : public std::exception { };
// emu_fatalerror is a generic fatal exception that provides an error string
class emu_fatalerror : public emu_exception
{
public:
emu_fatalerror(util::format_argument_pack<std::ostream> const &args);
emu_fatalerror(int _exitcode, util::format_argument_pack<std::ostream> const &args);
template <typename Format, typename... Params>
emu_fatalerror(Format const &fmt, Params &&... args)
: emu_fatalerror(static_cast<util::format_argument_pack<std::ostream> const &>(util::make_format_argument_pack(fmt, std::forward<Params>(args)...)))
{
}
template <typename Format, typename... Params>
emu_fatalerror(int _exitcode, Format const &fmt, Params &&... args)
: emu_fatalerror(_exitcode, static_cast<util::format_argument_pack<std::ostream> const &>(util::make_format_argument_pack(fmt, std::forward<Params>(args)...)))
{
}
virtual char const *what() const noexcept override { return m_text.c_str(); }
int exitcode() const noexcept { return m_code; }
private:
std::string m_text;
int m_code;
};
class tag_add_exception
{
public:
tag_add_exception(const char *tag) : m_tag(tag) { }
const char *tag() const { return m_tag.c_str(); }
private:
std::string m_tag;
};
//**************************************************************************
// CASTING TEMPLATES
//**************************************************************************
[[noreturn]] void report_bad_cast(const std::type_info &src_type, const std::type_info &dst_type);
[[noreturn]] void report_bad_device_cast(const device_t *dev, const std::type_info &src_type, const std::type_info &dst_type);
template <typename Dest, typename Source>
inline void report_bad_cast(Source *src)
{
if constexpr (std::is_base_of_v<device_t, Source>)
{
if (src) report_bad_device_cast(src, typeid(Source), typeid(Dest));
else report_bad_cast(typeid(Source), typeid(Dest));
}
else
{
device_t const *dev(dynamic_cast<device_t const *>(src));
if (dev) report_bad_device_cast(dev, typeid(Source), typeid(Dest));
else report_bad_cast(typeid(Source), typeid(Dest));
}
}
// template function for casting from a base class to a derived class that is checked
// in debug builds and fast in release builds
template <typename Dest, typename Source>
inline Dest downcast(Source *src)
{
#if defined(MAME_DEBUG)
Dest const chk(dynamic_cast<Dest>(src));
if (chk != src) report_bad_cast<std::remove_pointer_t<Dest>, Source>(src);
#endif
return static_cast<Dest>(src);
}
template<class Dest, class Source>
inline Dest downcast(Source &src)
{
#if defined(MAME_DEBUG)
std::remove_reference_t<Dest> *const chk(dynamic_cast<std::remove_reference_t<Dest> *>(&src));
if (chk != &src) report_bad_cast<std::remove_reference_t<Dest>, Source>(&src);
#endif
return static_cast<Dest>(src);
}
//**************************************************************************
// INLINE FUNCTIONS
//**************************************************************************
template <typename... T>
[[noreturn]] inline void fatalerror(T &&... args)
{
throw emu_fatalerror(std::forward<T>(args)...);
}
// convert a series of 32 bits into a float
inline float u2f(u32 v)
{
union {
float ff;
u32 vv;
} u;
u.vv = v;
return u.ff;
}
// convert a float into a series of 32 bits
inline u32 f2u(float f)
{
union {
float ff;
u32 vv;
} u;
u.ff = f;
return u.vv;
}
// convert a series of 64 bits into a double
inline double u2d(u64 v)
{
union {
double dd;
u64 vv;
} u;
u.vv = v;
return u.dd;
}
// convert a double into a series of 64 bits
inline u64 d2u(double d)
{
union {
double dd;
u64 vv;
} u;
u.dd = d;
return u.vv;
}
#endif // MAME_EMU_EMUCORE_H

View File

@ -1,255 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/**********************************************************************
* emufwd.h
*
* Forward declarations for MAME famework.
*
* Please place forward declarations here rather than littering them
* throughout headers in src/emu. It makes it much easier to update
* them and remove obsolete ones.
**********************************************************************/
#ifndef MAME_EMU_EMUFWD_H
#define MAME_EMU_EMUFWD_H
#pragma once
#include <type_traits>
//----------------------------------
// 3rdparty
//----------------------------------
// declared in expat.h
struct XML_ParserStruct;
//----------------------------------
// osd
//----------------------------------
// declared in modules/output/output_module.h
class output_module;
// declared in osdepend.h
class osd_font;
class osd_interface;
//----------------------------------
// lib/util
//----------------------------------
// declared in aviio.h
class avi_file;
// declared in chd.h
class chd_file;
// declared in unzip.h
namespace util { class archive_file; }
// declared in xmlfile.h
namespace util::xml { class data_node; class file; }
//----------------------------------
// emu
//----------------------------------
// declared in addrmap.h
class address_map;
class address_map_entry;
// declared in bookkeeping.h
class bookkeeping_manager;
// declared in config.h
enum class config_type : int;
enum class config_level : int;
class configuration_manager;
// declared in crsshair.h
class crosshair_manager;
// declared in debug/debugcmd.h
class debugger_commands;
// declared in debug/debugcon.h
class debugger_console;
// declared in debug/debugcpu.h
class debugger_cpu;
class device_debug;
// declared in debug/debugvw.h
class debug_view;
class debug_view_manager;
// declared in debug/express.h
class parsed_expression;
class symbol_table;
// declared in debug/points.h
class debug_breakpoint;
class debug_watchpoint;
class debug_registerpoint;
// declared in debugger.h
class debugger_manager;
// declared in devcb.h
class devcb_base;
template <typename Input, std::make_unsigned_t<Input> DefaultMask> class devcb_write;
// declared in devfind.h
class finder_base;
template <class DeviceClass, bool Required> class device_finder;
// declared in device.h
class device_interface;
class device_t;
// declared in didisasm.h
class device_disasm_interface;
// declared in diexec.h
class device_execute_interface;
// declared in digfx.h
struct gfx_decode_entry;
// declared in diimage.h
class device_image_interface;
// declared in dimemory.h
class device_memory_interface;
// declared in dipalette.h
class device_palette_interface;
// declared in distate.h
class device_state_interface;
// declared in drawgfx.h
class gfx_element;
// declared in driver.h
class driver_device;
// declared in emumem.h
class address_space;
class memory_bank;
class memory_manager;
class memory_region;
class memory_share;
class memory_view;
// declared in emuopts.h
class emu_options;
// declared in gamedrv.h
class game_driver;
// declared in input.h
class input_manager;
// declared in inputdev.h
class input_class;
class input_device;
class input_device_item;
// declared in image.h
class image_manager;
// declared in ioport.h
class analog_field;
struct input_device_default;
class ioport_field;
struct ioport_field_live;
class ioport_list;
class ioport_manager;
class ioport_port;
struct ioport_port_live;
// declared in machine.h
class running_machine;
// declared in mconfig.h
namespace emu::detail { class machine_config_replace; }
class machine_config;
// declared in natkeyboard.h
class natural_keyboard;
// declared in network.h
class network_manager;
// declared in output.h
class output_manager;
// declared in render.h
class render_container;
class render_manager;
class render_target;
class render_texture;
// declared in rendfont.h
class render_font;
// declared in rendlay.h
class layout_element;
class layout_view_item;
class layout_view;
class layout_file;
// declared in romentry.h
class rom_entry;
// declared in romload.h
class rom_load_manager;
// declared in schedule.h
class device_scheduler;
class emu_timer;
// declared in screen.h
class screen_device;
// declared in softlist.h
class software_info;
class software_part;
// declared in softlist_dev.h
class software_list_device;
class software_list_loader;
// declared in sound.h
class sound_manager;
class sound_stream;
// declared in speaker.h
class speaker_device;
// declared in tilemap.h
class tilemap_device;
class tilemap_manager;
class tilemap_t;
// declared in ui/uimain.h
class ui_manager;
// declared in uiinput.h
class ui_input_manager;
// declared in validity.h
class validity_checker;
// declared in video.h
class video_manager;
#endif // MAME_EMU_EMUFWD_H

View File

@ -1,445 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb, Ryan Holtz
/***************************************************************************
rgbgen.h
General RGB utilities.
***************************************************************************/
#ifndef MAME_EMU_VIDEO_RGBGEN_H
#define MAME_EMU_VIDEO_RGBGEN_H
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
class rgbaint_t
{
public:
rgbaint_t(): m_a(0), m_r(0), m_g(0), m_b(0) { }
explicit rgbaint_t(u32 rgba) { set(rgba); }
rgbaint_t(s32 a, s32 r, s32 g, s32 b) { set(a, r, g, b); }
explicit rgbaint_t(const rgb_t& rgba) { set(rgba); }
rgbaint_t(const rgbaint_t& other) = default;
rgbaint_t &operator=(const rgbaint_t& other) = default;
void set(const rgbaint_t& other) { set(other.m_a, other.m_r, other.m_g, other.m_b); }
void set(u32 rgba) { set((rgba >> 24) & 0xff, (rgba >> 16) & 0xff, (rgba >> 8) & 0xff, rgba & 0xff); }
void set(s32 a, s32 r, s32 g, s32 b)
{
m_a = a;
m_r = r;
m_g = g;
m_b = b;
}
void set(const rgb_t& rgba) { set(rgba.a(), rgba.r(), rgba.g(), rgba.b()); }
// This function sets all elements to the same val
void set_all(const s32& val) { set(val, val, val, val); }
// This function zeros all elements
void zero() { set_all(0); }
// This function zeros only the alpha element
void zero_alpha() { m_a = 0; }
rgb_t to_rgba() const { return rgb_t(get_a(), get_r(), get_g(), get_b()); }
rgb_t to_rgba_clamp() const
{
const u8 a = (m_a < 0) ? 0 : (m_a > 255) ? 255 : m_a;
const u8 r = (m_r < 0) ? 0 : (m_r > 255) ? 255 : m_r;
const u8 g = (m_g < 0) ? 0 : (m_g > 255) ? 255 : m_g;
const u8 b = (m_b < 0) ? 0 : (m_b > 255) ? 255 : m_b;
return rgb_t(a, r, g, b);
}
void set_a16(const s32 value) { m_a = value; }
void set_a(const s32 value) { m_a = value; }
void set_r(const s32 value) { m_r = value; }
void set_g(const s32 value) { m_g = value; }
void set_b(const s32 value) { m_b = value; }
u8 get_a() const { return u8(u32(m_a)); }
u8 get_r() const { return u8(u32(m_r)); }
u8 get_g() const { return u8(u32(m_g)); }
u8 get_b() const { return u8(u32(m_b)); }
s32 get_a32() const { return m_a; }
s32 get_r32() const { return m_r; }
s32 get_g32() const { return m_g; }
s32 get_b32() const { return m_b; }
// These selects return an rgbaint_t with all fields set to the element choosen (a, r, g, or b)
rgbaint_t select_alpha32() const { return rgbaint_t(get_a32(), get_a32(), get_a32(), get_a32()); }
rgbaint_t select_red32() const { return rgbaint_t(get_r32(), get_r32(), get_r32(), get_r32()); }
rgbaint_t select_green32() const { return rgbaint_t(get_g32(), get_g32(), get_g32(), get_g32()); }
rgbaint_t select_blue32() const { return rgbaint_t(get_b32(), get_b32(), get_b32(), get_b32()); }
inline void add(const rgbaint_t& color)
{
add_imm_rgba(color.m_a, color.m_r, color.m_g, color.m_b);
}
inline void add_imm(const s32 imm)
{
add_imm_rgba(imm, imm, imm, imm);
}
inline void add_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
{
m_a += a;
m_r += r;
m_g += g;
m_b += b;
}
inline void sub(const rgbaint_t& color)
{
sub_imm_rgba(color.m_a, color.m_r, color.m_g, color.m_b);
}
inline void sub_imm(const s32 imm)
{
sub_imm_rgba(imm, imm, imm, imm);
}
inline void sub_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
{
m_a -= a;
m_r -= r;
m_g -= g;
m_b -= b;
}
inline void subr(const rgbaint_t& color)
{
subr_imm_rgba(color.m_a, color.m_r, color.m_g, color.m_b);
}
inline void subr_imm(const s32 imm)
{
subr_imm_rgba(imm, imm, imm, imm);
}
inline void subr_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
{
m_a = a - m_a;
m_r = r - m_r;
m_g = g - m_g;
m_b = b - m_b;
}
inline void mul(const rgbaint_t& color)
{
mul_imm_rgba(color.m_a, color.m_r, color.m_g, color.m_b);
}
inline void mul_imm(const s32 imm)
{
mul_imm_rgba(imm, imm, imm, imm);
}
inline void mul_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
{
m_a *= a;
m_r *= r;
m_g *= g;
m_b *= b;
}
inline void shl(const rgbaint_t& shift)
{
m_a <<= shift.m_a;
m_r <<= shift.m_r;
m_g <<= shift.m_g;
m_b <<= shift.m_b;
}
inline void shl_imm(const u8 shift)
{
if (shift == 0)
return;
m_a <<= shift;
m_r <<= shift;
m_g <<= shift;
m_b <<= shift;
}
inline void shr(const rgbaint_t& shift)
{
m_a = s32(u32(m_a) >> shift.m_a);
m_r = s32(u32(m_r) >> shift.m_r);
m_g = s32(u32(m_g) >> shift.m_g);
m_b = s32(u32(m_b) >> shift.m_b);
}
inline void shr_imm(const u8 shift)
{
if (shift == 0)
return;
m_a = s32(u32(m_a) >> shift);
m_r = s32(u32(m_r) >> shift);
m_g = s32(u32(m_g) >> shift);
m_b = s32(u32(m_b) >> shift);
}
inline void sra(const rgbaint_t& shift)
{
m_a >>= shift.m_a;
if (m_a & (1 << (31 - shift.m_a)))
m_a |= ~0 << (32 - shift.m_a);
m_r >>= shift.m_r;
if (m_r & (1 << (31 - shift.m_r)))
m_r |= ~0 << (32 - shift.m_r);
m_g >>= shift.m_g;
if (m_g & (1 << (31 - shift.m_g)))
m_g |= ~0 << (32 - shift.m_g);
m_b >>= shift.m_b;
if (m_b & (1 << (31 - shift.m_b)))
m_b |= ~0 << (32 - shift.m_b);
}
inline void sra_imm(const u8 shift)
{
const u32 high_bit = 1 << (31 - shift);
const u32 high_mask = ~0 << (32 - shift);
m_a >>= shift;
if (m_a & high_bit)
m_a |= high_mask;
m_r >>= shift;
if (m_r & high_bit)
m_r |= high_mask;
m_g >>= shift;
if (m_g & high_bit)
m_g |= high_mask;
m_b >>= shift;
if (m_b & high_bit)
m_b |= high_mask;
}
void or_reg(const rgbaint_t& color) { or_imm_rgba(color.m_a, color.m_r, color.m_g, color.m_b); }
void and_reg(const rgbaint_t& color) { and_imm_rgba(color.m_a, color.m_r, color.m_g, color.m_b); }
void xor_reg(const rgbaint_t& color) { xor_imm_rgba(color.m_a, color.m_r, color.m_g, color.m_b); }
void andnot_reg(const rgbaint_t& color) { and_imm_rgba(~color.m_a, ~color.m_r, ~color.m_g, ~color.m_b); }
void or_imm(s32 imm) { or_imm_rgba(imm, imm, imm, imm); }
void and_imm(s32 imm) { and_imm_rgba(imm, imm, imm, imm); }
void xor_imm(s32 imm) { xor_imm_rgba(imm, imm, imm, imm); }
inline void or_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
{
m_a |= a;
m_r |= r;
m_g |= g;
m_b |= b;
}
inline void and_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
{
m_a &= a;
m_r &= r;
m_g &= g;
m_b &= b;
}
inline void xor_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
{
m_a ^= a;
m_r ^= r;
m_g ^= g;
m_b ^= b;
}
inline void clamp_and_clear(const u32 sign)
{
if (m_a & sign) m_a = 0;
if (m_r & sign) m_r = 0;
if (m_g & sign) m_g = 0;
if (m_b & sign) m_b = 0;
clamp_to_uint8();
}
inline void clamp_to_uint8()
{
m_a = (m_a < 0) ? 0 : (m_a > 255) ? 255 : m_a;
m_r = (m_r < 0) ? 0 : (m_r > 255) ? 255 : m_r;
m_g = (m_g < 0) ? 0 : (m_g > 255) ? 255 : m_g;
m_b = (m_b < 0) ? 0 : (m_b > 255) ? 255 : m_b;
}
inline void sign_extend(const u32 compare, const u32 sign)
{
if ((m_a & compare) == compare)
m_a |= sign;
if ((m_r & compare) == compare)
m_r |= sign;
if ((m_g & compare) == compare)
m_g |= sign;
if ((m_b & compare) == compare)
m_b |= sign;
}
inline void min(const s32 value)
{
m_a = (m_a > value) ? value : m_a;
m_r = (m_r > value) ? value : m_r;
m_g = (m_g > value) ? value : m_g;
m_b = (m_b > value) ? value : m_b;
}
inline void max(const s32 value)
{
m_a = (m_a < value) ? value : m_a;
m_r = (m_r < value) ? value : m_r;
m_g = (m_g < value) ? value : m_g;
m_b = (m_b < value) ? value : m_b;
}
void blend(const rgbaint_t& other, u8 factor);
void scale_and_clamp(const rgbaint_t& scale);
void scale_imm_and_clamp(const s32 scale);
void scale2_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other, const rgbaint_t& scale2);
void scale_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other);
void cmpeq(const rgbaint_t& value) { cmpeq_imm_rgba(value.m_a, value.m_r, value.m_g, value.m_b); }
void cmpgt(const rgbaint_t& value) { cmpgt_imm_rgba(value.m_a, value.m_r, value.m_g, value.m_b); }
void cmplt(const rgbaint_t& value) { cmplt_imm_rgba(value.m_a, value.m_r, value.m_g, value.m_b); }
void cmpeq_imm(s32 value) { cmpeq_imm_rgba(value, value, value, value); }
void cmpgt_imm(s32 value) { cmpgt_imm_rgba(value, value, value, value); }
void cmplt_imm(s32 value) { cmplt_imm_rgba(value, value, value, value); }
void cmpeq_imm_rgba(s32 a, s32 r, s32 g, s32 b)
{
m_a = (m_a == a) ? 0xffffffff : 0;
m_r = (m_r == r) ? 0xffffffff : 0;
m_g = (m_g == g) ? 0xffffffff : 0;
m_b = (m_b == b) ? 0xffffffff : 0;
}
void cmpgt_imm_rgba(s32 a, s32 r, s32 g, s32 b)
{
m_a = (m_a > a) ? 0xffffffff : 0;
m_r = (m_r > r) ? 0xffffffff : 0;
m_g = (m_g > g) ? 0xffffffff : 0;
m_b = (m_b > b) ? 0xffffffff : 0;
}
void cmplt_imm_rgba(s32 a, s32 r, s32 g, s32 b)
{
m_a = (m_a < a) ? 0xffffffff : 0;
m_r = (m_r < r) ? 0xffffffff : 0;
m_g = (m_g < g) ? 0xffffffff : 0;
m_b = (m_b < b) ? 0xffffffff : 0;
}
void merge_alpha16(const rgbaint_t& alpha)
{
m_a = alpha.m_a;
}
void merge_alpha(const rgbaint_t& alpha)
{
m_a = alpha.m_a;
}
rgbaint_t& operator+=(const rgbaint_t& other)
{
add_imm_rgba(other.m_a, other.m_r, other.m_g, other.m_b);
return *this;
}
rgbaint_t& operator+=(const s32 other)
{
add_imm_rgba(other, other, other, other);
return *this;
}
rgbaint_t &operator-=(const rgbaint_t& other)
{
sub_imm_rgba(other.m_a, other.m_r, other.m_g, other.m_b);
return *this;
}
rgbaint_t& operator*=(const rgbaint_t& other)
{
mul_imm_rgba(other.m_a, other.m_r, other.m_g, other.m_b);
return *this;
}
rgbaint_t& operator*=(const s32 other)
{
mul_imm_rgba(other, other, other, other);
return *this;
}
rgbaint_t& operator>>=(const s32 shift)
{
sra_imm(shift);
return *this;
}
static u32 bilinear_filter(u32 rgb00, u32 rgb01, u32 rgb10, u32 rgb11, u8 u, u8 v)
{
u32 rb0 = (rgb00 & 0x00ff00ff) + ((((rgb01 & 0x00ff00ff) - (rgb00 & 0x00ff00ff)) * u) >> 8);
u32 rb1 = (rgb10 & 0x00ff00ff) + ((((rgb11 & 0x00ff00ff) - (rgb10 & 0x00ff00ff)) * u) >> 8);
rgb00 >>= 8;
rgb01 >>= 8;
rgb10 >>= 8;
rgb11 >>= 8;
u32 ag0 = (rgb00 & 0x00ff00ff) + ((((rgb01 & 0x00ff00ff) - (rgb00 & 0x00ff00ff)) * u) >> 8);
u32 ag1 = (rgb10 & 0x00ff00ff) + ((((rgb11 & 0x00ff00ff) - (rgb10 & 0x00ff00ff)) * u) >> 8);
rb0 = (rb0 & 0x00ff00ff) + ((((rb1 & 0x00ff00ff) - (rb0 & 0x00ff00ff)) * v) >> 8);
ag0 = (ag0 & 0x00ff00ff) + ((((ag1 & 0x00ff00ff) - (ag0 & 0x00ff00ff)) * v) >> 8);
return ((ag0 << 8) & 0xff00ff00) | (rb0 & 0x00ff00ff);
}
void bilinear_filter_rgbaint(u32 rgb00, u32 rgb01, u32 rgb10, u32 rgb11, u8 u, u8 v)
{
u32 rb0 = (rgb00 & 0x00ff00ff) + ((((rgb01 & 0x00ff00ff) - (rgb00 & 0x00ff00ff)) * u) >> 8);
u32 rb1 = (rgb10 & 0x00ff00ff) + ((((rgb11 & 0x00ff00ff) - (rgb10 & 0x00ff00ff)) * u) >> 8);
rgb00 >>= 8;
rgb01 >>= 8;
rgb10 >>= 8;
rgb11 >>= 8;
u32 ag0 = (rgb00 & 0x00ff00ff) + ((((rgb01 & 0x00ff00ff) - (rgb00 & 0x00ff00ff)) * u) >> 8);
u32 ag1 = (rgb10 & 0x00ff00ff) + ((((rgb11 & 0x00ff00ff) - (rgb10 & 0x00ff00ff)) * u) >> 8);
rb0 = (rb0 & 0x00ff00ff) + ((((rb1 & 0x00ff00ff) - (rb0 & 0x00ff00ff)) * v) >> 8);
ag0 = (ag0 & 0x00ff00ff) + ((((ag1 & 0x00ff00ff) - (ag0 & 0x00ff00ff)) * v) >> 8);
u32 result = ((ag0 << 8) & 0xff00ff00) | (rb0 & 0x00ff00ff);
this->set(result);
}
protected:
s32 m_a;
s32 m_r;
s32 m_g;
s32 m_b;
};
#endif // MAME_EMU_VIDEO_RGBGEN_H

View File

@ -1,502 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb, Ryan Holtz
/***************************************************************************
rgbsse.h
SSE optimized RGB utilities.
WARNING: This code assumes SSE2 or greater capability.
***************************************************************************/
#ifndef MAME_EMU_VIDEO_RGBSSE_H
#define MAME_EMU_VIDEO_RGBSSE_H
#pragma once
#include <emmintrin.h>
#ifdef __SSE4_1__
#include <smmintrin.h>
#endif
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
class rgbaint_t
{
public:
rgbaint_t() { }
explicit rgbaint_t(u32 rgba) { set(rgba); }
rgbaint_t(s32 a, s32 r, s32 g, s32 b) { set(a, r, g, b); }
explicit rgbaint_t(const rgb_t& rgb) { set(rgb); }
explicit rgbaint_t(__m128i rgba) { m_value = rgba; }
rgbaint_t(const rgbaint_t& other) = default;
rgbaint_t &operator=(const rgbaint_t& other) = default;
void set(const rgbaint_t& other) { m_value = other.m_value; }
void set(const u32& rgba) { m_value = _mm_unpacklo_epi16(_mm_unpacklo_epi8(_mm_cvtsi32_si128(rgba), _mm_setzero_si128()), _mm_setzero_si128()); }
void set(s32 a, s32 r, s32 g, s32 b) { m_value = _mm_set_epi32(a, r, g, b); }
void set(const rgb_t& rgb) { set((const u32&) rgb); }
// This function sets all elements to the same val
void set_all(const s32& val) { m_value = _mm_set1_epi32(val); }
// This function zeros all elements
void zero() { m_value = _mm_xor_si128(m_value, m_value); }
// This function zeros only the alpha element
void zero_alpha() { m_value = _mm_and_si128(m_value, alpha_mask()); }
inline rgb_t to_rgba() const
{
return _mm_cvtsi128_si32(_mm_packus_epi16(_mm_packs_epi32(m_value, _mm_setzero_si128()), _mm_setzero_si128()));
}
inline rgb_t to_rgba_clamp() const
{
return _mm_cvtsi128_si32(_mm_packus_epi16(_mm_packs_epi32(m_value, _mm_setzero_si128()), _mm_setzero_si128()));
}
void set_a16(const s32 value) { m_value = _mm_insert_epi16(m_value, value, 6); }
#ifdef __SSE4_1__
void set_a(const s32 value) { m_value = _mm_insert_epi32(m_value, value, 3); }
void set_r(const s32 value) { m_value = _mm_insert_epi32(m_value, value, 2); }
void set_g(const s32 value) { m_value = _mm_insert_epi32(m_value, value, 1); }
void set_b(const s32 value) { m_value = _mm_insert_epi32(m_value, value, 0); }
#else
void set_a(const s32 value) { m_value = _mm_or_si128(_mm_and_si128(m_value, alpha_mask()), _mm_set_epi32(value, 0, 0, 0)); }
void set_r(const s32 value) { m_value = _mm_or_si128(_mm_and_si128(m_value, red_mask()), _mm_set_epi32(0, value, 0, 0)); }
void set_g(const s32 value) { m_value = _mm_or_si128(_mm_and_si128(m_value, green_mask()), _mm_set_epi32(0, 0, value, 0)); }
void set_b(const s32 value) { m_value = _mm_or_si128(_mm_and_si128(m_value, blue_mask()), _mm_set_epi32(0, 0, 0, value)); }
#endif
u8 get_a() const { return u8(unsigned(_mm_extract_epi16(m_value, 6))); }
u8 get_r() const { return u8(unsigned(_mm_extract_epi16(m_value, 4))); }
u8 get_g() const { return u8(unsigned(_mm_extract_epi16(m_value, 2))); }
u8 get_b() const { return u8(unsigned(_mm_cvtsi128_si32(m_value))); }
#ifdef __SSE4_1__
s32 get_a32() const { return _mm_extract_epi32(m_value, 3); }
s32 get_r32() const { return _mm_extract_epi32(m_value, 2); }
s32 get_g32() const { return _mm_extract_epi32(m_value, 1); }
s32 get_b32() const { return _mm_extract_epi32(m_value, 0); }
#else
s32 get_a32() const { return (_mm_cvtsi128_si32(_mm_shuffle_epi32(m_value, _MM_SHUFFLE(0, 0, 0, 3)))); }
s32 get_r32() const { return (_mm_cvtsi128_si32(_mm_shuffle_epi32(m_value, _MM_SHUFFLE(0, 0, 0, 2)))); }
s32 get_g32() const { return (_mm_cvtsi128_si32(_mm_shuffle_epi32(m_value, _MM_SHUFFLE(0, 0, 0, 1)))); }
s32 get_b32() const { return (_mm_cvtsi128_si32(m_value)); }
#endif
// These selects return an rgbaint_t with all fields set to the element choosen (a, r, g, or b)
rgbaint_t select_alpha32() const { return (rgbaint_t)_mm_shuffle_epi32(m_value, _MM_SHUFFLE(3, 3, 3, 3)); }
rgbaint_t select_red32() const { return (rgbaint_t)_mm_shuffle_epi32(m_value, _MM_SHUFFLE(2, 2, 2, 2)); }
rgbaint_t select_green32() const { return (rgbaint_t)_mm_shuffle_epi32(m_value, _MM_SHUFFLE(1, 1, 1, 1)); }
rgbaint_t select_blue32() const { return (rgbaint_t)_mm_shuffle_epi32(m_value, _MM_SHUFFLE(0, 0, 0, 0)); }
inline void add(const rgbaint_t& color2)
{
m_value = _mm_add_epi32(m_value, color2.m_value);
}
inline void add_imm(const s32 imm)
{
m_value = _mm_add_epi32(m_value, _mm_set1_epi32(imm));
}
inline void add_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
{
m_value = _mm_add_epi32(m_value, _mm_set_epi32(a, r, g, b));
}
inline void sub(const rgbaint_t& color2)
{
m_value = _mm_sub_epi32(m_value, color2.m_value);
}
inline void sub_imm(const s32 imm)
{
m_value = _mm_sub_epi32(m_value, _mm_set1_epi32(imm));
}
inline void sub_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
{
m_value = _mm_sub_epi32(m_value, _mm_set_epi32(a, r, g, b));
}
inline void subr(const rgbaint_t& color2)
{
m_value = _mm_sub_epi32(color2.m_value, m_value);
}
inline void subr_imm(const s32 imm)
{
m_value = _mm_sub_epi32(_mm_set1_epi32(imm), m_value);
}
inline void subr_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
{
m_value = _mm_sub_epi32(_mm_set_epi32(a, r, g, b), m_value);
}
inline void mul(const rgbaint_t& color)
{
__m128i tmp1 = _mm_mul_epu32(m_value, color.m_value);
__m128i tmp2 = _mm_mul_epu32(_mm_srli_si128(m_value, 4), _mm_srli_si128(color.m_value, 4));
m_value = _mm_unpacklo_epi32(_mm_shuffle_epi32(tmp1, _MM_SHUFFLE(0, 0, 2, 0)), _mm_shuffle_epi32(tmp2, _MM_SHUFFLE(0, 0, 2, 0)));
}
inline void mul_imm(const s32 imm)
{
__m128i immv = _mm_set1_epi32(imm);
__m128i tmp1 = _mm_mul_epu32(m_value, immv);
__m128i tmp2 = _mm_mul_epu32(_mm_srli_si128(m_value, 4), _mm_srli_si128(immv, 4));
m_value = _mm_unpacklo_epi32(_mm_shuffle_epi32(tmp1, _MM_SHUFFLE(0, 0, 2, 0)), _mm_shuffle_epi32(tmp2, _MM_SHUFFLE(0, 0, 2, 0)));
}
inline void mul_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
{
__m128i immv = _mm_set_epi32(a, r, g, b);
__m128i tmp1 = _mm_mul_epu32(m_value, immv);
__m128i tmp2 = _mm_mul_epu32(_mm_srli_si128(m_value, 4), _mm_srli_si128(immv, 4));
m_value = _mm_unpacklo_epi32(_mm_shuffle_epi32(tmp1, _MM_SHUFFLE(0, 0, 2, 0)), _mm_shuffle_epi32(tmp2, _MM_SHUFFLE(0, 0, 2, 0)));
}
inline void shl(const rgbaint_t& shift)
{
rgbaint_t areg(*this);
rgbaint_t rreg(*this);
rgbaint_t greg(*this);
rgbaint_t breg(*this);
rgbaint_t ashift(0, 0, 0, shift.get_a32());
rgbaint_t rshift(0, 0, 0, shift.get_r32());
rgbaint_t gshift(0, 0, 0, shift.get_g32());
rgbaint_t bshift(0, 0, 0, shift.get_b32());
areg.m_value = _mm_sll_epi32(areg.m_value, ashift.m_value);
rreg.m_value = _mm_sll_epi32(rreg.m_value, rshift.m_value);
greg.m_value = _mm_sll_epi32(greg.m_value, gshift.m_value);
breg.m_value = _mm_sll_epi32(breg.m_value, bshift.m_value);
set(areg.get_a32(), rreg.get_r32(), greg.get_g32(), breg.get_b32());
}
inline void shl_imm(const u8 shift)
{
m_value = _mm_slli_epi32(m_value, shift);
}
inline void shr(const rgbaint_t& shift)
{
rgbaint_t areg(*this);
rgbaint_t rreg(*this);
rgbaint_t greg(*this);
rgbaint_t breg(*this);
rgbaint_t ashift(0, 0, 0, shift.get_a32());
rgbaint_t rshift(0, 0, 0, shift.get_r32());
rgbaint_t gshift(0, 0, 0, shift.get_g32());
rgbaint_t bshift(0, 0, 0, shift.get_b32());
areg.m_value = _mm_srl_epi32(areg.m_value, ashift.m_value);
rreg.m_value = _mm_srl_epi32(rreg.m_value, rshift.m_value);
greg.m_value = _mm_srl_epi32(greg.m_value, gshift.m_value);
breg.m_value = _mm_srl_epi32(breg.m_value, bshift.m_value);
set(areg.get_a32(), rreg.get_r32(), greg.get_g32(), breg.get_b32());
}
inline void shr_imm(const u8 shift)
{
m_value = _mm_srli_epi32(m_value, shift);
}
inline void sra(const rgbaint_t& shift)
{
rgbaint_t areg(*this);
rgbaint_t rreg(*this);
rgbaint_t greg(*this);
rgbaint_t breg(*this);
rgbaint_t ashift(0, 0, 0, shift.get_a32());
rgbaint_t rshift(0, 0, 0, shift.get_r32());
rgbaint_t gshift(0, 0, 0, shift.get_g32());
rgbaint_t bshift(0, 0, 0, shift.get_b32());
areg.m_value = _mm_sra_epi32(areg.m_value, ashift.m_value);
rreg.m_value = _mm_sra_epi32(rreg.m_value, rshift.m_value);
greg.m_value = _mm_sra_epi32(greg.m_value, gshift.m_value);
breg.m_value = _mm_sra_epi32(breg.m_value, bshift.m_value);
set(areg.get_a32(), rreg.get_r32(), greg.get_g32(), breg.get_b32());
}
inline void sra_imm(const u8 shift)
{
m_value = _mm_srai_epi32(m_value, shift);
}
void or_reg(const rgbaint_t& color2) { m_value = _mm_or_si128(m_value, color2.m_value); }
void and_reg(const rgbaint_t& color2) { m_value = _mm_and_si128(m_value, color2.m_value); }
void xor_reg(const rgbaint_t& color2) { m_value = _mm_xor_si128(m_value, color2.m_value); }
void andnot_reg(const rgbaint_t& color2) { m_value = _mm_andnot_si128(color2.m_value, m_value); }
void or_imm(s32 value) { m_value = _mm_or_si128(m_value, _mm_set1_epi32(value)); }
void and_imm(s32 value) { m_value = _mm_and_si128(m_value, _mm_set1_epi32(value)); }
void xor_imm(s32 value) { m_value = _mm_xor_si128(m_value, _mm_set1_epi32(value)); }
void or_imm_rgba(s32 a, s32 r, s32 g, s32 b) { m_value = _mm_or_si128(m_value, _mm_set_epi32(a, r, g, b)); }
void and_imm_rgba(s32 a, s32 r, s32 g, s32 b) { m_value = _mm_and_si128(m_value, _mm_set_epi32(a, r, g, b)); }
void xor_imm_rgba(s32 a, s32 r, s32 g, s32 b) { m_value = _mm_xor_si128(m_value, _mm_set_epi32(a, r, g, b)); }
inline void clamp_and_clear(const u32 sign)
{
__m128i vsign = _mm_set1_epi32(sign);
m_value = _mm_and_si128(m_value, _mm_cmpeq_epi32(_mm_and_si128(m_value, vsign), _mm_setzero_si128()));
vsign = _mm_srai_epi32(vsign, 1);
vsign = _mm_xor_si128(vsign, _mm_set1_epi32(0xffffffff));
__m128i mask = _mm_cmpgt_epi32(m_value, vsign);
m_value = _mm_or_si128(_mm_and_si128(vsign, mask), _mm_and_si128(m_value, _mm_xor_si128(mask, _mm_set1_epi32(0xffffffff))));
}
inline void clamp_to_uint8()
{
m_value = _mm_packs_epi32(m_value, _mm_setzero_si128());
m_value = _mm_packus_epi16(m_value, _mm_setzero_si128());
m_value = _mm_unpacklo_epi8(m_value, _mm_setzero_si128());
m_value = _mm_unpacklo_epi16(m_value, _mm_setzero_si128());
}
inline void sign_extend(const u32 compare, const u32 sign)
{
__m128i compare_vec = _mm_set1_epi32(compare);
__m128i compare_mask = _mm_cmpeq_epi32(_mm_and_si128(m_value, compare_vec), compare_vec);
__m128i compared = _mm_and_si128(_mm_set1_epi32(sign), compare_mask);
m_value = _mm_or_si128(m_value, compared);
}
inline void min(const s32 value)
{
__m128i val = _mm_set1_epi32(value);
#ifdef __SSE4_1__
m_value = _mm_min_epi32(m_value, val);
#else
__m128i is_greater_than = _mm_cmpgt_epi32(m_value, val);
__m128i val_to_set = _mm_and_si128(val, is_greater_than);
__m128i keep_mask = _mm_xor_si128(is_greater_than, _mm_set1_epi32(0xffffffff));
m_value = _mm_and_si128(m_value, keep_mask);
m_value = _mm_or_si128(val_to_set, m_value);
#endif
}
inline void max(const s32 value)
{
__m128i val = _mm_set1_epi32(value);
#ifdef __SSE4_1__
m_value = _mm_max_epi32(m_value, val);
#else
__m128i is_less_than = _mm_cmplt_epi32(m_value, val);
__m128i val_to_set = _mm_and_si128(val, is_less_than);
__m128i keep_mask = _mm_xor_si128(is_less_than, _mm_set1_epi32(0xffffffff));
m_value = _mm_and_si128(m_value, keep_mask);
m_value = _mm_or_si128(val_to_set, m_value);
#endif
}
void blend(const rgbaint_t& other, u8 factor);
void scale_and_clamp(const rgbaint_t& scale);
// Leave this here in case Model3 blows up...
//inline void scale_imm_and_clamp(const s32 scale)
//{
// mul_imm(scale);
// sra_imm(8);
// clamp_to_uint8();
//}
// This version needs absolute value of value and scale to be 11 bits or less
inline void scale_imm_and_clamp(const s16 scale)
{
// Set mult a 16 bit inputs to scale
__m128i immv = _mm_set1_epi16(scale);
// Shift up by 4
immv = _mm_slli_epi16(immv, 4);
// Pack color into mult b 16 bit inputs
m_value = _mm_packs_epi32(m_value, _mm_setzero_si128());
// Shift up by 4
m_value = _mm_slli_epi16(m_value, 4);
// Do the 16 bit multiply, bottom 64 bits will contain 16 bit truncated results
m_value = _mm_mulhi_epi16(m_value, immv);
// Clamp to u8
m_value = _mm_packus_epi16(m_value, _mm_setzero_si128());
// Unpack up to s32
m_value = _mm_unpacklo_epi8(m_value, _mm_setzero_si128());
m_value = _mm_unpacklo_epi16(m_value, _mm_setzero_si128());
}
// This function needs absolute value of color and scale to be 15 bits or less
inline void scale_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other)
{
#ifdef __SSE4_1__
m_value = _mm_mullo_epi32(m_value, scale.m_value);
#else
// Mask off the top 16 bits of each 32-bit value
m_value = _mm_and_si128(m_value, _mm_set1_epi32(0x0000ffff));
// Do 16x16 multiplies and sum into 32-bit pairs; the AND above ensures upper pair is always 0
m_value = _mm_madd_epi16(m_value, scale.m_value);
#endif
// Arithmetic shift down the result by 8 bits
sra_imm(8);
add(other);
clamp_to_uint8();
}
// This function needs absolute value of color and scale to be 15 bits or less
inline void scale2_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other, const rgbaint_t& scale2)
{
// Pack 32-bit values to 16-bit values in low half, and scales in top half
__m128i tmp1 = _mm_packs_epi32(m_value, scale.m_value);
// Same for other and scale2
__m128i tmp2 = _mm_packs_epi32(other.m_value, scale2.m_value);
// Interleave the low halves (m_value, other)
__m128i tmp3 = _mm_unpacklo_epi16(tmp1, tmp2);
// Interleave the top halves (scale, scale2)
__m128i tmp4 = _mm_unpackhi_epi16(tmp1, tmp2);
// Multiply values by scales and add adjacent pairs
m_value = _mm_madd_epi16(tmp3, tmp4);
// Final shift by 8
sra_imm(8);
clamp_to_uint8();
}
void cmpeq(const rgbaint_t& value) { m_value = _mm_cmpeq_epi32(m_value, value.m_value); }
void cmpgt(const rgbaint_t& value) { m_value = _mm_cmpgt_epi32(m_value, value.m_value); }
void cmplt(const rgbaint_t& value) { m_value = _mm_cmplt_epi32(m_value, value.m_value); }
void cmpeq_imm(s32 value) { m_value = _mm_cmpeq_epi32(m_value, _mm_set1_epi32(value)); }
void cmpgt_imm(s32 value) { m_value = _mm_cmpgt_epi32(m_value, _mm_set1_epi32(value)); }
void cmplt_imm(s32 value) { m_value = _mm_cmplt_epi32(m_value, _mm_set1_epi32(value)); }
void cmpeq_imm_rgba(s32 a, s32 r, s32 g, s32 b) { m_value = _mm_cmpeq_epi32(m_value, _mm_set_epi32(a, r, g, b)); }
void cmpgt_imm_rgba(s32 a, s32 r, s32 g, s32 b) { m_value = _mm_cmpgt_epi32(m_value, _mm_set_epi32(a, r, g, b)); }
void cmplt_imm_rgba(s32 a, s32 r, s32 g, s32 b) { m_value = _mm_cmplt_epi32(m_value, _mm_set_epi32(a, r, g, b)); }
inline rgbaint_t& operator+=(const rgbaint_t& other)
{
m_value = _mm_add_epi32(m_value, other.m_value);
return *this;
}
inline rgbaint_t& operator+=(const s32 other)
{
m_value = _mm_add_epi32(m_value, _mm_set1_epi32(other));
return *this;
}
inline rgbaint_t& operator-=(const rgbaint_t& other)
{
m_value = _mm_sub_epi32(m_value, other.m_value);
return *this;
}
inline rgbaint_t& operator*=(const rgbaint_t& other)
{
m_value = _mm_unpacklo_epi32(_mm_shuffle_epi32(_mm_mul_epu32(m_value, other.m_value), _MM_SHUFFLE(0, 0, 2, 0)), _mm_shuffle_epi32(_mm_mul_epu32(_mm_srli_si128(m_value, 4), _mm_srli_si128(other.m_value, 4)), _MM_SHUFFLE(0, 0, 2, 0)));
return *this;
}
inline rgbaint_t& operator*=(const s32 other)
{
const __m128i immv = _mm_set1_epi32(other);
m_value = _mm_unpacklo_epi32(_mm_shuffle_epi32(_mm_mul_epu32(m_value, immv), _MM_SHUFFLE(0, 0, 2, 0)), _mm_shuffle_epi32(_mm_mul_epu32(_mm_srli_si128(m_value, 4), _mm_srli_si128(immv, 4)), _MM_SHUFFLE(0, 0, 2, 0)));
return *this;
}
inline rgbaint_t& operator>>=(const s32 shift)
{
m_value = _mm_srai_epi32(m_value, shift);
return *this;
}
inline void merge_alpha16(const rgbaint_t& alpha)
{
m_value = _mm_insert_epi16(m_value, _mm_extract_epi16(alpha.m_value, 6), 6);
}
inline void merge_alpha(const rgbaint_t& alpha)
{
#ifdef __SSE4_1__
m_value = _mm_insert_epi32(m_value, _mm_extract_epi32(alpha.m_value, 3), 3);
#else
m_value = _mm_insert_epi16(m_value, _mm_extract_epi16(alpha.m_value, 7), 7);
m_value = _mm_insert_epi16(m_value, _mm_extract_epi16(alpha.m_value, 6), 6);
#endif
}
static u32 bilinear_filter(u32 rgb00, u32 rgb01, u32 rgb10, u32 rgb11, u8 u, u8 v)
{
__m128i color00 = _mm_cvtsi32_si128(rgb00);
__m128i color01 = _mm_cvtsi32_si128(rgb01);
__m128i color10 = _mm_cvtsi32_si128(rgb10);
__m128i color11 = _mm_cvtsi32_si128(rgb11);
/* interleave color01 and color00 at the byte level */
color01 = _mm_unpacklo_epi8(color01, color00);
color11 = _mm_unpacklo_epi8(color11, color10);
color01 = _mm_unpacklo_epi8(color01, _mm_setzero_si128());
color11 = _mm_unpacklo_epi8(color11, _mm_setzero_si128());
color01 = _mm_madd_epi16(color01, scale_factor(u));
color11 = _mm_madd_epi16(color11, scale_factor(u));
color01 = _mm_slli_epi32(color01, 15);
color11 = _mm_srli_epi32(color11, 1);
color01 = _mm_max_epi16(color01, color11);
color01 = _mm_madd_epi16(color01, scale_factor(v));
color01 = _mm_srli_epi32(color01, 15);
color01 = _mm_packs_epi32(color01, _mm_setzero_si128());
color01 = _mm_packus_epi16(color01, _mm_setzero_si128());
return _mm_cvtsi128_si32(color01);
}
void bilinear_filter_rgbaint(u32 rgb00, u32 rgb01, u32 rgb10, u32 rgb11, u8 u, u8 v)
{
__m128i color00 = _mm_cvtsi32_si128(rgb00);
__m128i color01 = _mm_cvtsi32_si128(rgb01);
__m128i color10 = _mm_cvtsi32_si128(rgb10);
__m128i color11 = _mm_cvtsi32_si128(rgb11);
/* interleave color01 and color00 at the byte level */
color01 = _mm_unpacklo_epi8(color01, color00);
color11 = _mm_unpacklo_epi8(color11, color10);
color01 = _mm_unpacklo_epi8(color01, _mm_setzero_si128());
color11 = _mm_unpacklo_epi8(color11, _mm_setzero_si128());
color01 = _mm_madd_epi16(color01, scale_factor(u));
color11 = _mm_madd_epi16(color11, scale_factor(u));
color01 = _mm_slli_epi32(color01, 15);
color11 = _mm_srli_epi32(color11, 1);
color01 = _mm_max_epi16(color01, color11);
color01 = _mm_madd_epi16(color01, scale_factor(v));
m_value = _mm_srli_epi32(color01, 15);
}
protected:
struct _statics
{
__m128 dummy_for_alignment;
u16 alpha_mask[8];
u16 red_mask[8];
u16 green_mask[8];
u16 blue_mask[8];
s16 scale_table[256][8];
};
static __m128i alpha_mask() { return *(__m128i *)&statics.alpha_mask[0]; }
static __m128i red_mask() { return *(__m128i *)&statics.red_mask[0]; }
static __m128i green_mask() { return *(__m128i *)&statics.green_mask[0]; }
static __m128i blue_mask() { return *(__m128i *)&statics.blue_mask[0]; }
static __m128i scale_factor(u8 index) { return *(__m128i *)&statics.scale_table[index][0]; }
__m128i m_value;
static const _statics statics;
};
#endif /* MAME_EMU_VIDEO_RGBSSE_H */

View File

@ -1,32 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************
rgbutil.h
Utility definitions for RGB manipulation. Allows RGB handling to be
performed in an abstracted fashion and optimized with SIMD.
***************************************************************************/
#ifndef MAME_EMU_VIDEO_RGBUTIL_H
#define MAME_EMU_VIDEO_RGBUTIL_H
// use SSE on 64-bit implementations, where it can be assumed
#if (!defined(MAME_DEBUG) || defined(__OPTIMIZE__)) && (defined(__SSE2__) || defined(_M_X64) || (defined(_M_IX86_FP) && (_M_IX86_FP >= 2)))
#define MAME_RGB_HIGH_PRECISION
#include "rgbsse.h"
#elif defined(__ALTIVEC__)
#define MAME_RGB_HIGH_PRECISION
#include "rgbvmx.h"
#else
#include "rgbgen.h"
#endif
#endif // MAME_EMU_VIDEO_RGBUTIL_H

View File

@ -1,728 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb, Ryan Holtz
/***************************************************************************
rgbvmx.h
VMX/Altivec optimised RGB utilities.
***************************************************************************/
#ifndef MAME_EMU_VIDEO_RGBVMX_H
#define MAME_EMU_VIDEO_RGBVMX_H
#pragma once
#include <altivec.h>
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
class rgbaint_t
{
protected:
typedef __vector signed char VECS8;
typedef __vector unsigned char VECU8;
typedef __vector signed short VECS16;
typedef __vector unsigned short VECU16;
typedef __vector signed int VECS32;
typedef __vector unsigned int VECU32;
public:
rgbaint_t() { set(0, 0, 0, 0); }
explicit rgbaint_t(u32 rgba) { set(rgba); }
rgbaint_t(s32 a, s32 r, s32 g, s32 b) { set(a, r, g, b); }
explicit rgbaint_t(const rgb_t& rgb) { set(rgb); }
explicit rgbaint_t(VECS32 rgba) : m_value(rgba) { }
rgbaint_t(const rgbaint_t& other) = default;
rgbaint_t &operator=(const rgbaint_t& other) = default;
void set(const rgbaint_t& other) { m_value = other.m_value; }
void set(u32 rgba)
{
const VECU32 zero = { 0, 0, 0, 0 };
#ifdef __LITTLE_ENDIAN__
const VECS8 temp = *reinterpret_cast<const VECS8 *>(&rgba);
m_value = VECS32(vec_mergeh(VECS16(vec_mergeh(temp, VECS8(zero))), VECS16(zero)));
#else
const VECS8 temp = VECS8(vec_perm(vec_lde(0, &rgba), zero, vec_lvsl(0, &rgba)));
m_value = VECS32(vec_mergeh(VECS16(zero), VECS16(vec_mergeh(VECS8(zero), temp))));
#endif
}
void set(s32 a, s32 r, s32 g, s32 b)
{
#ifdef __LITTLE_ENDIAN__
const VECS32 result = { b, g, r, a };
#else
const VECS32 result = { a, r, g, b };
#endif
m_value = result;
}
void set(const rgb_t& rgb)
{
const VECU32 zero = { 0, 0, 0, 0 };
#ifdef __LITTLE_ENDIAN__
const VECS8 temp = *reinterpret_cast<const VECS8 *>(rgb.ptr());
m_value = VECS32(vec_mergeh(VECS16(vec_mergeh(temp, VECS8(zero))), VECS16(zero)));
#else
const VECS8 temp = VECS8(vec_perm(vec_lde(0, rgb.ptr()), zero, vec_lvsl(0, rgb.ptr())));
m_value = VECS32(vec_mergeh(VECS16(zero), VECS16(vec_mergeh(VECS8(zero), temp))));
#endif
}
// This function sets all elements to the same val
void set_all(const s32& val) { set(val, val, val, val); }
// This function zeros all elements
void zero() { set_all(0); }
// This function zeros only the alpha element
void zero_alpha() { set_a(0); }
inline rgb_t to_rgba() const
{
VECU32 temp = VECU32(vec_packs(m_value, m_value));
temp = VECU32(vec_packsu(VECS16(temp), VECS16(temp)));
u32 result;
vec_ste(temp, 0, &result);
return result;
}
inline rgb_t to_rgba_clamp() const
{
VECU32 temp = VECU32(vec_packs(m_value, m_value));
temp = VECU32(vec_packsu(VECS16(temp), VECS16(temp)));
u32 result;
vec_ste(temp, 0, &result);
return result;
}
void set_a16(const s32 value)
{
const VECS32 temp = { value, value, value, value };
m_value = vec_perm(m_value, temp, alpha_perm);
}
void set_a(const s32 value)
{
const VECS32 temp = { value, value, value, value };
m_value = vec_perm(m_value, temp, alpha_perm);
}
void set_r(const s32 value)
{
const VECS32 temp = { value, value, value, value };
m_value = vec_perm(m_value, temp, red_perm);
}
void set_g(const s32 value)
{
const VECS32 temp = { value, value, value, value };
m_value = vec_perm(m_value, temp, green_perm);
}
void set_b(const s32 value)
{
const VECS32 temp = { value, value, value, value };
m_value = vec_perm(m_value, temp, blue_perm);
}
u8 get_a() const
{
u8 result;
#ifdef __LITTLE_ENDIAN__
vec_ste(vec_splat(VECU8(m_value), 12), 0, &result);
#else
vec_ste(vec_splat(VECU8(m_value), 3), 0, &result);
#endif
return result;
}
u8 get_r() const
{
u8 result;
#ifdef __LITTLE_ENDIAN__
vec_ste(vec_splat(VECU8(m_value), 8), 0, &result);
#else
vec_ste(vec_splat(VECU8(m_value), 7), 0, &result);
#endif
return result;
}
u8 get_g() const
{
u8 result;
#ifdef __LITTLE_ENDIAN__
vec_ste(vec_splat(VECU8(m_value), 4), 0, &result);
#else
vec_ste(vec_splat(VECU8(m_value), 11), 0, &result);
#endif
return result;
}
u8 get_b() const
{
u8 result;
#ifdef __LITTLE_ENDIAN__
vec_ste(vec_splat(VECU8(m_value), 0), 0, &result);
#else
vec_ste(vec_splat(VECU8(m_value), 15), 0, &result);
#endif
return result;
}
s32 get_a32() const
{
s32 result;
#ifdef __LITTLE_ENDIAN__
vec_ste(vec_splat(m_value, 3), 0, &result);
#else
vec_ste(vec_splat(m_value, 0), 0, &result);
#endif
return result;
}
s32 get_r32() const
{
s32 result;
#ifdef __LITTLE_ENDIAN__
vec_ste(vec_splat(m_value, 2), 0, &result);
#else
vec_ste(vec_splat(m_value, 1), 0, &result);
#endif
return result;
}
s32 get_g32() const
{
s32 result;
#ifdef __LITTLE_ENDIAN__
vec_ste(vec_splat(m_value, 1), 0, &result);
#else
vec_ste(vec_splat(m_value, 2), 0, &result);
#endif
return result;
}
s32 get_b32() const
{
s32 result;
#ifdef __LITTLE_ENDIAN__
vec_ste(vec_splat(m_value, 0), 0, &result);
#else
vec_ste(vec_splat(m_value, 3), 0, &result);
#endif
return result;
}
// These selects return an rgbaint_t with all fields set to the element choosen (a, r, g, or b)
rgbaint_t select_alpha32() const { return rgbaint_t(get_a32(), get_a32(), get_a32(), get_a32()); }
rgbaint_t select_red32() const { return rgbaint_t(get_r32(), get_r32(), get_r32(), get_r32()); }
rgbaint_t select_green32() const { return rgbaint_t(get_g32(), get_g32(), get_g32(), get_g32()); }
rgbaint_t select_blue32() const { return rgbaint_t(get_b32(), get_b32(), get_b32(), get_b32()); }
inline void add(const rgbaint_t& color2)
{
m_value = vec_add(m_value, color2.m_value);
}
inline void add_imm(const s32 imm)
{
const VECS32 temp = { imm, imm, imm, imm };
m_value = vec_add(m_value, temp);
}
inline void add_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
{
#ifdef __LITTLE_ENDIAN__
const VECS32 temp = { b, g, r, a };
#else
const VECS32 temp = { a, r, g, b };
#endif
m_value = vec_add(m_value, temp);
}
inline void sub(const rgbaint_t& color2)
{
m_value = vec_sub(m_value, color2.m_value);
}
inline void sub_imm(const s32 imm)
{
const VECS32 temp = { imm, imm, imm, imm };
m_value = vec_sub(m_value, temp);
}
inline void sub_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
{
#ifdef __LITTLE_ENDIAN__
const VECS32 temp = { b, g, r, a };
#else
const VECS32 temp = { a, r, g, b };
#endif
m_value = vec_sub(m_value, temp);
}
inline void subr(const rgbaint_t& color2)
{
m_value = vec_sub(color2.m_value, m_value);
}
inline void subr_imm(const s32 imm)
{
const VECS32 temp = { imm, imm, imm, imm };
m_value = vec_sub(temp, m_value);
}
inline void subr_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
{
#ifdef __LITTLE_ENDIAN__
const VECS32 temp = { b, g, r, a };
#else
const VECS32 temp = { a, r, g, b };
#endif
m_value = vec_sub(temp, m_value);
}
inline void mul(const rgbaint_t& color)
{
const VECU32 shift = vec_splat_u32(-16);
const VECU32 temp = vec_msum(VECU16(m_value), VECU16(vec_rl(color.m_value, shift)), vec_splat_u32(0));
#ifdef __LITTLE_ENDIAN__
m_value = VECS32(vec_add(vec_sl(temp, shift), vec_mule(VECU16(m_value), VECU16(color.m_value))));
#else
m_value = VECS32(vec_add(vec_sl(temp, shift), vec_mulo(VECU16(m_value), VECU16(color.m_value))));
#endif
}
inline void mul_imm(const s32 imm)
{
const VECU32 value = { u32(imm), u32(imm), u32(imm), u32(imm) };
const VECU32 shift = vec_splat_u32(-16);
const VECU32 temp = vec_msum(VECU16(m_value), VECU16(vec_rl(value, shift)), vec_splat_u32(0));
#ifdef __LITTLE_ENDIAN__
m_value = VECS32(vec_add(vec_sl(temp, shift), vec_mule(VECU16(m_value), VECU16(value))));
#else
m_value = VECS32(vec_add(vec_sl(temp, shift), vec_mulo(VECU16(m_value), VECU16(value))));
#endif
}
inline void mul_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
{
#ifdef __LITTLE_ENDIAN__
const VECU32 value = { u32(b), u32(g), u32(r), u32(a) };
#else
const VECU32 value = { u32(a), u32(r), u32(g), u32(b) };
#endif
const VECU32 shift = vec_splat_u32(-16);
const VECU32 temp = vec_msum(VECU16(m_value), VECU16(vec_rl(value, shift)), vec_splat_u32(0));
#ifdef __LITTLE_ENDIAN__
m_value = VECS32(vec_add(vec_sl(temp, shift), vec_mule(VECU16(m_value), VECU16(value))));
#else
m_value = VECS32(vec_add(vec_sl(temp, shift), vec_mulo(VECU16(m_value), VECU16(value))));
#endif
}
inline void shl(const rgbaint_t& shift)
{
const VECU32 limit = { 32, 32, 32, 32 };
m_value = vec_and(vec_sl(m_value, VECU32(shift.m_value)), vec_cmpgt(limit, VECU32(shift.m_value)));
}
inline void shl_imm(const u8 shift)
{
const VECU32 temp = { shift, shift, shift, shift };
m_value = vec_sl(m_value, temp);
}
inline void shr(const rgbaint_t& shift)
{
const VECU32 limit = { 32, 32, 32, 32 };
m_value = vec_and(vec_sr(m_value, VECU32(shift.m_value)), vec_cmpgt(limit, VECU32(shift.m_value)));
}
inline void shr_imm(const u8 shift)
{
const VECU32 temp = { shift, shift, shift, shift };
m_value = vec_sr(m_value, temp);
}
inline void sra(const rgbaint_t& shift)
{
const VECU32 limit = { 31, 31, 31, 31 };
m_value = vec_sra(m_value, vec_min(VECU32(shift.m_value), limit));
}
inline void sra_imm(const u8 shift)
{
const VECU32 temp = { shift, shift, shift, shift };
m_value = vec_sra(m_value, temp);
}
inline void or_reg(const rgbaint_t& color2)
{
m_value = vec_or(m_value, color2.m_value);
}
inline void or_imm(const s32 value)
{
const VECS32 temp = { value, value, value, value };
m_value = vec_or(m_value, temp);
}
inline void or_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
{
#ifdef __LITTLE_ENDIAN__
const VECS32 temp = { b, g, r, a };
#else
const VECS32 temp = { a, r, g, b };
#endif
m_value = vec_or(m_value, temp);
}
inline void and_reg(const rgbaint_t& color)
{
m_value = vec_and(m_value, color.m_value);
}
inline void andnot_reg(const rgbaint_t& color)
{
m_value = vec_andc(m_value, color.m_value);
}
inline void and_imm(const s32 value)
{
const VECS32 temp = { value, value, value, value };
m_value = vec_and(m_value, temp);
}
inline void and_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
{
#ifdef __LITTLE_ENDIAN__
const VECS32 temp = { b, g, r, a };
#else
const VECS32 temp = { a, r, g, b };
#endif
m_value = vec_and(m_value, temp);
}
inline void xor_reg(const rgbaint_t& color2)
{
m_value = vec_xor(m_value, color2.m_value);
}
inline void xor_imm(const s32 value)
{
const VECS32 temp = { value, value, value, value };
m_value = vec_xor(m_value, temp);
}
inline void xor_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
{
#ifdef __LITTLE_ENDIAN__
const VECS32 temp = { b, g, r, a };
#else
const VECS32 temp = { a, r, g, b };
#endif
m_value = vec_xor(m_value, temp);
}
inline void clamp_and_clear(const u32 sign)
{
const VECS32 vzero = { 0, 0, 0, 0 };
VECS32 vsign = { s32(sign), s32(sign), s32(sign), s32(sign) };
m_value = vec_and(m_value, vec_cmpeq(vec_and(m_value, vsign), vzero));
vsign = vec_nor(vec_sra(vsign, vec_splat_u32(1)), vzero);
const VECS32 mask = VECS32(vec_cmpgt(m_value, vsign));
m_value = vec_or(vec_and(vsign, mask), vec_and(m_value, vec_nor(mask, vzero)));
}
inline void clamp_to_uint8()
{
const VECU32 zero = { 0, 0, 0, 0 };
m_value = VECS32(vec_packs(m_value, m_value));
m_value = VECS32(vec_packsu(VECS16(m_value), VECS16(m_value)));
#ifdef __LITTLE_ENDIAN__
m_value = VECS32(vec_mergeh(VECU8(m_value), VECU8(zero)));
m_value = VECS32(vec_mergeh(VECS16(m_value), VECS16(zero)));
#else
m_value = VECS32(vec_mergeh(VECU8(zero), VECU8(m_value)));
m_value = VECS32(vec_mergeh(VECS16(zero), VECS16(m_value)));
#endif
}
inline void sign_extend(const u32 compare, const u32 sign)
{
const VECS32 compare_vec = { s32(compare), s32(compare), s32(compare), s32(compare) };
const VECS32 compare_mask = VECS32(vec_cmpeq(vec_and(m_value, compare_vec), compare_vec));
const VECS32 sign_vec = { s32(sign), s32(sign), s32(sign), s32(sign) };
m_value = vec_or(m_value, vec_and(sign_vec, compare_mask));
}
inline void min(const s32 value)
{
const VECS32 temp = { value, value, value, value };
m_value = vec_min(m_value, temp);
}
inline void max(const s32 value)
{
const VECS32 temp = { value, value, value, value };
m_value = vec_max(m_value, temp);
}
void blend(const rgbaint_t& other, u8 factor);
void scale_and_clamp(const rgbaint_t& scale);
void scale_imm_and_clamp(const s32 scale);
void scale_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other)
{
mul(scale);
sra_imm(8);
add(other);
clamp_to_uint8();
}
void scale2_add_and_clamp(const rgbaint_t& scale, const rgbaint_t& other, const rgbaint_t& scale2)
{
rgbaint_t color2(other);
color2.mul(scale2);
mul(scale);
add(color2);
sra_imm(8);
clamp_to_uint8();
}
inline void cmpeq(const rgbaint_t& value)
{
m_value = VECS32(vec_cmpeq(m_value, value.m_value));
}
inline void cmpeq_imm(const s32 value)
{
const VECS32 temp = { value, value, value, value };
m_value = VECS32(vec_cmpeq(m_value, temp));
}
inline void cmpeq_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
{
#ifdef __LITTLE_ENDIAN__
const VECS32 temp = { b, g, r, a };
#else
const VECS32 temp = { a, r, g, b };
#endif
m_value = VECS32(vec_cmpeq(m_value, temp));
}
inline void cmpgt(const rgbaint_t& value)
{
m_value = VECS32(vec_cmpgt(m_value, value.m_value));
}
inline void cmpgt_imm(const s32 value)
{
const VECS32 temp = { value, value, value, value };
m_value = VECS32(vec_cmpgt(m_value, temp));
}
inline void cmpgt_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
{
#ifdef __LITTLE_ENDIAN__
const VECS32 temp = { b, g, r, a };
#else
const VECS32 temp = { a, r, g, b };
#endif
m_value = VECS32(vec_cmpgt(m_value, temp));
}
inline void cmplt(const rgbaint_t& value)
{
m_value = VECS32(vec_cmplt(m_value, value.m_value));
}
inline void cmplt_imm(const s32 value)
{
const VECS32 temp = { value, value, value, value };
m_value = VECS32(vec_cmplt(m_value, temp));
}
inline void cmplt_imm_rgba(const s32 a, const s32 r, const s32 g, const s32 b)
{
#ifdef __LITTLE_ENDIAN__
const VECS32 temp = { b, g, r, a };
#else
const VECS32 temp = { a, r, g, b };
#endif
m_value = VECS32(vec_cmplt(m_value, temp));
}
inline rgbaint_t& operator+=(const rgbaint_t& other)
{
m_value = vec_add(m_value, other.m_value);
return *this;
}
inline rgbaint_t& operator+=(const s32 other)
{
const VECS32 temp = { other, other, other, other };
m_value = vec_add(m_value, temp);
return *this;
}
inline rgbaint_t& operator-=(const rgbaint_t& other)
{
m_value = vec_sub(m_value, other.m_value);
return *this;
}
inline rgbaint_t& operator*=(const rgbaint_t& other)
{
const VECU32 shift = vec_splat_u32(-16);
const VECU32 temp = vec_msum(VECU16(m_value), VECU16(vec_rl(other.m_value, shift)), vec_splat_u32(0));
#ifdef __LITTLE_ENDIAN__
m_value = VECS32(vec_add(vec_sl(temp, shift), vec_mule(VECU16(m_value), VECU16(other.m_value))));
#else
m_value = VECS32(vec_add(vec_sl(temp, shift), vec_mulo(VECU16(m_value), VECU16(other.m_value))));
#endif
return *this;
}
inline rgbaint_t& operator*=(const s32 other)
{
const VECS32 value = { other, other, other, other };
const VECU32 shift = vec_splat_u32(-16);
const VECU32 temp = vec_msum(VECU16(m_value), VECU16(vec_rl(value, shift)), vec_splat_u32(0));
#ifdef __LITTLE_ENDIAN__
m_value = VECS32(vec_add(vec_sl(temp, shift), vec_mule(VECU16(m_value), VECU16(value))));
#else
m_value = VECS32(vec_add(vec_sl(temp, shift), vec_mulo(VECU16(m_value), VECU16(value))));
#endif
return *this;
}
inline rgbaint_t& operator>>=(const s32 shift)
{
const VECU32 temp = { u32(shift), u32(shift), u32(shift), u32(shift) };
m_value = vec_sra(m_value, temp);
return *this;
}
inline void merge_alpha16(const rgbaint_t& alpha)
{
m_value = vec_perm(m_value, alpha.m_value, alpha_perm);
}
inline void merge_alpha(const rgbaint_t& alpha)
{
m_value = vec_perm(m_value, alpha.m_value, alpha_perm);
}
static u32 bilinear_filter(const u32 &rgb00, const u32 &rgb01, const u32 &rgb10, const u32 &rgb11, u8 u, u8 v)
{
const VECS32 zero = vec_splat_s32(0);
// put each packed value into first element of a vector register
#ifdef __LITTLE_ENDIAN__
VECS32 color00 = *reinterpret_cast<const VECS32 *>(&rgb00);
VECS32 color01 = *reinterpret_cast<const VECS32 *>(&rgb01);
VECS32 color10 = *reinterpret_cast<const VECS32 *>(&rgb10);
VECS32 color11 = *reinterpret_cast<const VECS32 *>(&rgb11);
#else
VECS32 color00 = vec_perm(VECS32(vec_lde(0, &rgb00)), zero, vec_lvsl(0, &rgb00));
VECS32 color01 = vec_perm(VECS32(vec_lde(0, &rgb01)), zero, vec_lvsl(0, &rgb01));
VECS32 color10 = vec_perm(VECS32(vec_lde(0, &rgb10)), zero, vec_lvsl(0, &rgb10));
VECS32 color11 = vec_perm(VECS32(vec_lde(0, &rgb11)), zero, vec_lvsl(0, &rgb11));
#endif
// interleave color01/color00 and color10/color11 at the byte level then zero-extend
color01 = VECS32(vec_mergeh(VECU8(color01), VECU8(color00)));
color11 = VECS32(vec_mergeh(VECU8(color11), VECU8(color10)));
#ifdef __LITTLE_ENDIAN__
color01 = VECS32(vec_mergeh(VECU8(color01), VECU8(zero)));
color11 = VECS32(vec_mergeh(VECU8(color11), VECU8(zero)));
#else
color01 = VECS32(vec_mergeh(VECU8(zero), VECU8(color01)));
color11 = VECS32(vec_mergeh(VECU8(zero), VECU8(color11)));
#endif
color01 = vec_msum(VECS16(color01), scale_table[u], zero);
color11 = vec_msum(VECS16(color11), scale_table[u], zero);
color01 = vec_sl(color01, vec_splat_u32(15));
color11 = vec_sr(color11, vec_splat_u32(1));
color01 = VECS32(vec_max(VECS16(color01), VECS16(color11)));
color01 = vec_msum(VECS16(color01), scale_table[v], zero);
color01 = vec_sr(color01, vec_splat_u32(15));
color01 = VECS32(vec_packs(color01, color01));
color01 = VECS32(vec_packsu(VECS16(color01), VECS16(color01)));
u32 result;
vec_ste(VECU32(color01), 0, &result);
return result;
}
void bilinear_filter_rgbaint(const u32 &rgb00, const u32 &rgb01, const u32 &rgb10, const u32 &rgb11, u8 u, u8 v)
{
const VECS32 zero = vec_splat_s32(0);
// put each packed value into first element of a vector register
#ifdef __LITTLE_ENDIAN__
VECS32 color00 = *reinterpret_cast<const VECS32 *>(&rgb00);
VECS32 color01 = *reinterpret_cast<const VECS32 *>(&rgb01);
VECS32 color10 = *reinterpret_cast<const VECS32 *>(&rgb10);
VECS32 color11 = *reinterpret_cast<const VECS32 *>(&rgb11);
#else
VECS32 color00 = vec_perm(VECS32(vec_lde(0, &rgb00)), zero, vec_lvsl(0, &rgb00));
VECS32 color01 = vec_perm(VECS32(vec_lde(0, &rgb01)), zero, vec_lvsl(0, &rgb01));
VECS32 color10 = vec_perm(VECS32(vec_lde(0, &rgb10)), zero, vec_lvsl(0, &rgb10));
VECS32 color11 = vec_perm(VECS32(vec_lde(0, &rgb11)), zero, vec_lvsl(0, &rgb11));
#endif
// interleave color01/color00 and color10/color11 at the byte level then zero-extend
color01 = VECS32(vec_mergeh(VECU8(color01), VECU8(color00)));
color11 = VECS32(vec_mergeh(VECU8(color11), VECU8(color10)));
#ifdef __LITTLE_ENDIAN__
color01 = VECS32(vec_mergeh(VECU8(color01), VECU8(zero)));
color11 = VECS32(vec_mergeh(VECU8(color11), VECU8(zero)));
#else
color01 = VECS32(vec_mergeh(VECU8(zero), VECU8(color01)));
color11 = VECS32(vec_mergeh(VECU8(zero), VECU8(color11)));
#endif
color01 = vec_msum(VECS16(color01), scale_table[u], zero);
color11 = vec_msum(VECS16(color11), scale_table[u], zero);
color01 = vec_sl(color01, vec_splat_u32(15));
color11 = vec_sr(color11, vec_splat_u32(1));
color01 = VECS32(vec_max(VECS16(color01), VECS16(color11)));
color01 = vec_msum(VECS16(color01), scale_table[v], zero);
m_value = vec_sr(color01, vec_splat_u32(15));
}
protected:
VECS32 m_value;
static const VECU8 alpha_perm;
static const VECU8 red_perm;
static const VECU8 green_perm;
static const VECU8 blue_perm;
static const VECS16 scale_table[256];
};
// altivec.h somehow redefines "bool" in a bad way. really.
#ifdef vector
#undef vector
#endif
#ifdef bool
#undef bool
#endif
#ifdef pixel
#undef pixel
#endif
#endif // MAME_EMU_VIDEO_RGBVMX_H

View File

@ -1,117 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/// \file
/// \brief ABI feature macros
///
/// Macros that are useful for writing ABI-dependent code.
#ifndef MAME_LIB_UTIL_ABI_H
#define MAME_LIB_UTIL_ABI_H
#pragma once
/// \brief Itanium C++ ABI
///
/// Value of #MAME_ABI_CXX_TYPE when compiled with a variant of the
/// Itanium C++ ABI.
/// \sa MAME_ABI_CXX_TYPE MAME_ABI_CXX_MSVC
#define MAME_ABI_CXX_ITANIUM 0
/// \brief Microsoft Visual C++ ABI
///
/// Value of #MAME_ABI_CXX_TYPE when compiled with a variant of the
/// Microsoft Visual C++ ABI.
/// \sa MAME_ABI_CXX_TYPE MAME_ABI_CXX_ITANIUM
#define MAME_ABI_CXX_MSVC 1
/// \brief Standard Itanium C++ ABI member function pointers
///
/// Value of #MAME_ABI_CXX_ITANIUM_MFP_TYPE when compiled with a variant
/// of the Itanium C++ ABI using the standard representation of
/// pointers to non-static member functions.
/// \sa MAME_ABI_CXX_ITANIUM_MFP_TYPE MAME_ABI_CXX_ITANIUM_MFP_ARM
#define MAME_ABI_CXX_ITANIUM_MFP_STANDARD 0
/// \brief ARM Itanium C++ ABI member function pointers
///
/// Value of #MAME_ABI_CXX_ITANIUM_MFP_TYPE when compiled with a variant
/// of the Itanium C++ ABI using the 32-bit ARM representation of
/// pointers to non-static member functions.
/// \sa MAME_ABI_CXX_ITANIUM_MFP_TYPE MAME_ABI_CXX_ITANIUM_MFP_STANDARD
#define MAME_ABI_CXX_ITANIUM_MFP_ARM 1
/// \def MAME_ABI_FNDESC_SIZE
/// \brief Size of function descriptors
///
/// Size of function descriptors as a multiple of the size of a pointer,
/// or zero if function pointers point to the function entry point
/// directly.
#if (defined(__ppc64__) || defined(__PPC64__)) && !defined(__APPLE__) && !defined(__LITTLE_ENDIAN__)
#define MAME_ABI_FNDESC_SIZE 3 // entry point (PC), TOC (R2), environment (R11)
#elif defined(__ia64__)
#define MAME_ABI_FNDESC_SIZE 2 // GP, entry point
#else
#define MAME_ABI_FNDESC_SIZE 0 // function pointers point to entry point directly
#endif
/// \def MAME_ABI_CXX_TYPE
/// \brief C++ ABI type
///
/// A constant representing the C++ ABI.
/// \sa MAME_ABI_CXX_ITANIUM MAME_ABI_CXX_MSVC
#if defined(_MSC_VER)
#define MAME_ABI_CXX_TYPE MAME_ABI_CXX_MSVC
#else
#define MAME_ABI_CXX_TYPE MAME_ABI_CXX_ITANIUM
#endif
/// \def MAME_ABI_CXX_MEMBER_CALL
/// \brief Member function calling convention qualifier
///
/// A qualifier for functions and function pointers that may be used to
/// specify that the calling convention for non-static member functions
/// should be used.
#if defined(__GNUC__) && defined(__MINGW32__) && !defined(__x86_64__) && defined(__i386__)
#define MAME_ABI_CXX_MEMBER_CALL __thiscall
#else
#define MAME_ABI_CXX_MEMBER_CALL
#endif
/// \def MAME_ABI_CXX_VTABLE_FNDESC
/// \brief Whether function descriptors are stored in virtual tables
///
/// Non-zero if function descriptors are stored in virtual tables
/// directly, or zero if function entries in virtual tables are
/// conventional function pointers.
/// \sa MAME_ABI_FNDESC_SIZE
#if defined(__ia64__)
#define MAME_ABI_CXX_VTABLE_FNDESC 1 // function descriptors stored directly in vtable
#else
#define MAME_ABI_CXX_VTABLE_FNDESC 0 // conventional function pointers in vtable
#endif
/// \def MAME_ABI_CXX_ITANIUM_MFP_TYPE
/// Itanium C++ member function representation
///
/// A constant representing the representation of pointers to non-static
/// member functions in use with the Itanium C++ ABI. Only valid if
/// compiled with a variant of the Itanium C++ ABI.
/// \sa MAME_ABI_CXX_ITANIUM_MFP_STANDARD MAME_ABI_CXX_ITANIUM_MFP_ARM
/// MAME_ABI_CXX_TYPE
#if defined(__arm__) || defined(__ARMEL__) || defined(__aarch64__)
#define MAME_ABI_CXX_ITANIUM_MFP_TYPE MAME_ABI_CXX_ITANIUM_MFP_ARM
#elif defined(__MIPSEL__) || defined(__mips_isa_rev) || defined(__mips64)
#define MAME_ABI_CXX_ITANIUM_MFP_TYPE MAME_ABI_CXX_ITANIUM_MFP_ARM
#elif defined(__EMSCRIPTEN__)
#define MAME_ABI_CXX_ITANIUM_MFP_TYPE MAME_ABI_CXX_ITANIUM_MFP_ARM
#else
#define MAME_ABI_CXX_ITANIUM_MFP_TYPE MAME_ABI_CXX_ITANIUM_MFP_STANDARD
#endif
#endif // MAME_LIB_UTIL_ABI_H

View File

@ -1,415 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************
bitmap.h
Core bitmap routines.
***************************************************************************/
#ifndef MAME_UTIL_BITMAP_H
#define MAME_UTIL_BITMAP_H
#pragma once
#include "palette.h"
#include <algorithm>
#include <memory>
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// bitmap_format describes the various bitmap formats we use
enum bitmap_format
{
BITMAP_FORMAT_INVALID = 0, // invalid forma
BITMAP_FORMAT_IND8, // 8bpp indexed
BITMAP_FORMAT_IND16, // 16bpp indexed
BITMAP_FORMAT_IND32, // 32bpp indexed
BITMAP_FORMAT_IND64, // 64bpp indexed
BITMAP_FORMAT_RGB32, // 32bpp 8-8-8 RGB
BITMAP_FORMAT_ARGB32, // 32bpp 8-8-8-8 ARGB
BITMAP_FORMAT_YUY16 // 16bpp 8-8 Y/Cb, Y/Cr in sequence
};
// ======================> rectangle
// rectangles describe a bitmap portion
class rectangle
{
public:
// construction/destruction
constexpr rectangle() { }
constexpr rectangle(int32_t minx, int32_t maxx, int32_t miny, int32_t maxy)
: min_x(minx), max_x(maxx), min_y(miny), max_y(maxy)
{ }
// getters
constexpr int32_t left() const { return min_x; }
constexpr int32_t right() const { return max_x; }
constexpr int32_t top() const { return min_y; }
constexpr int32_t bottom() const { return max_y; }
// compute intersection with another rect
rectangle &operator&=(const rectangle &src)
{
if (src.min_x > min_x) min_x = src.min_x;
if (src.max_x < max_x) max_x = src.max_x;
if (src.min_y > min_y) min_y = src.min_y;
if (src.max_y < max_y) max_y = src.max_y;
return *this;
}
// compute union with another rect
rectangle &operator|=(const rectangle &src)
{
if (src.min_x < min_x) min_x = src.min_x;
if (src.max_x > max_x) max_x = src.max_x;
if (src.min_y < min_y) min_y = src.min_y;
if (src.max_y > max_y) max_y = src.max_y;
return *this;
}
rectangle operator&(const rectangle &b)
{
rectangle a(*this);
a &= b;
return a;
}
rectangle operator|(const rectangle &b)
{
rectangle a(*this);
a |= b;
return a;
}
// comparisons
constexpr bool operator==(const rectangle &rhs) const { return min_x == rhs.min_x && max_x == rhs.max_x && min_y == rhs.min_y && max_y == rhs.max_y; }
constexpr bool operator!=(const rectangle &rhs) const { return min_x != rhs.min_x || max_x != rhs.max_x || min_y != rhs.min_y || max_y != rhs.max_y; }
constexpr bool operator>(const rectangle &rhs) const { return min_x < rhs.min_x && min_y < rhs.min_y && max_x > rhs.max_x && max_y > rhs.max_y; }
constexpr bool operator>=(const rectangle &rhs) const { return min_x <= rhs.min_x && min_y <= rhs.min_y && max_x >= rhs.max_x && max_y >= rhs.max_y; }
constexpr bool operator<(const rectangle &rhs) const { return min_x >= rhs.min_x || min_y >= rhs.min_y || max_x <= rhs.max_x || max_y <= rhs.max_y; }
constexpr bool operator<=(const rectangle &rhs) const { return min_x > rhs.min_x || min_y > rhs.min_y || max_x < rhs.max_x || max_y < rhs.max_y; }
// other helpers
constexpr bool empty() const { return (min_x > max_x) || (min_y > max_y); }
constexpr bool contains(int32_t x, int32_t y) const { return (x >= min_x) && (x <= max_x) && (y >= min_y) && (y <= max_y); }
constexpr bool contains(const rectangle &rect) const { return (min_x <= rect.min_x) && (max_x >= rect.max_x) && (min_y <= rect.min_y) && (max_y >= rect.max_y); }
constexpr int32_t width() const { return max_x + 1 - min_x; }
constexpr int32_t height() const { return max_y + 1 - min_y; }
constexpr int32_t xcenter() const { return (min_x + max_x + 1) / 2; }
constexpr int32_t ycenter() const { return (min_y + max_y + 1) / 2; }
// setters
void set(int32_t minx, int32_t maxx, int32_t miny, int32_t maxy) { min_x = minx; max_x = maxx; min_y = miny; max_y = maxy; }
void setx(int32_t minx, int32_t maxx) { min_x = minx; max_x = maxx; }
void sety(int32_t miny, int32_t maxy) { min_y = miny; max_y = maxy; }
void set_width(int32_t width) { max_x = min_x + width - 1; }
void set_height(int32_t height) { max_y = min_y + height - 1; }
void set_origin(int32_t x, int32_t y) { max_x += x - min_x; max_y += y - min_y; min_x = x; min_y = y; }
void set_size(int32_t width, int32_t height) { set_width(width); set_height(height); }
// offset helpers
void offset(int32_t xdelta, int32_t ydelta) { min_x += xdelta; max_x += xdelta; min_y += ydelta; max_y += ydelta; }
void offsetx(int32_t delta) { min_x += delta; max_x += delta; }
void offsety(int32_t delta) { min_y += delta; max_y += delta; }
// internal state
int32_t min_x = 0; // minimum X, or left coordinate
int32_t max_x = 0; // maximum X, or right coordinate (inclusive)
int32_t min_y = 0; // minimum Y, or top coordinate
int32_t max_y = 0; // maximum Y, or bottom coordinate (inclusive)
};
// ======================> bitmap_t
// bitmaps describe a rectangular array of pixels
class bitmap_t
{
protected:
// construction/destruction -- subclasses only to ensure type correctness
bitmap_t(const bitmap_t &) = delete;
bitmap_t(bitmap_t &&that);
bitmap_t(bitmap_format format, uint8_t bpp, int width = 0, int height = 0, int xslop = 0, int yslop = 0);
bitmap_t(bitmap_format format, uint8_t bpp, void *base, int width, int height, int rowpixels);
bitmap_t(bitmap_format format, uint8_t bpp, bitmap_t &source, const rectangle &subrect);
virtual ~bitmap_t();
// prevent implicit copying
bitmap_t &operator=(const bitmap_t &) = delete;
bitmap_t &operator=(bitmap_t &&that);
public:
// allocation/deallocation
void reset();
// getters
int32_t width() const { return m_width; }
int32_t height() const { return m_height; }
int32_t rowpixels() const { return m_rowpixels; }
int32_t rowbytes() const { return m_rowpixels * m_bpp / 8; }
uint8_t bpp() const { return m_bpp; }
bitmap_format format() const { return m_format; }
bool valid() const { return (m_base != nullptr); }
palette_t *palette() const { return m_palette; }
const rectangle &cliprect() const { return m_cliprect; }
// allocation/sizing
void allocate(int width, int height, int xslop = 0, int yslop = 0);
void resize(int width, int height, int xslop = 0, int yslop = 0);
// operations
void set_palette(palette_t *palette);
void fill(uint64_t color) { fill(color, m_cliprect); }
void fill(uint64_t color, const rectangle &bounds);
void plot_box(int32_t x, int32_t y, int32_t width, int32_t height, uint64_t color)
{
fill(color, rectangle(x, x + width - 1, y, y + height - 1));
}
// pixel access
void *raw_pixptr(int32_t y, int32_t x = 0) { return reinterpret_cast<uint8_t *>(m_base) + (y * m_rowpixels + x) * m_bpp / 8; }
void const *raw_pixptr(int32_t y, int32_t x = 0) const { return reinterpret_cast<uint8_t *>(m_base) + (y * m_rowpixels + x) * m_bpp / 8; }
protected:
// for use by subclasses only to ensure type correctness
template <typename PixelType> PixelType &pixt(int32_t y, int32_t x = 0) { return *(reinterpret_cast<PixelType *>(m_base) + y * m_rowpixels + x); }
template <typename PixelType> PixelType const &pixt(int32_t y, int32_t x = 0) const { return *(reinterpret_cast<PixelType *>(m_base) + y * m_rowpixels + x); }
void wrap(void *base, int width, int height, int rowpixels);
void wrap(bitmap_t &source, const rectangle &subrect);
private:
// internal helpers
int32_t compute_rowpixels(int width, int xslop);
void compute_base(int xslop, int yslop);
bool valid_format() const;
// internal state
std::unique_ptr<uint8_t []> m_alloc; // pointer to allocated pixel memory
uint32_t m_allocbytes; // size of our allocation
void * m_base; // pointer to pixel (0,0) (adjusted for padding)
int32_t m_rowpixels; // pixels per row (including padding)
int32_t m_width; // width of the bitmap
int32_t m_height; // height of the bitmap
bitmap_format m_format; // format of the bitmap
uint8_t m_bpp; // bits per pixel
palette_t * m_palette; // optional palette
rectangle m_cliprect; // a clipping rectangle covering the full bitmap
};
// ======================> bitmap_specific, bitmap8_t, bitmap16_t, bitmap32_t, bitmap64_t
template <typename PixelType>
class bitmap_specific : public bitmap_t
{
static constexpr int PIXEL_BITS = 8 * sizeof(PixelType);
protected:
// construction/destruction -- subclasses only
bitmap_specific(bitmap_specific<PixelType> &&) = default;
bitmap_specific(bitmap_format format, int width = 0, int height = 0, int xslop = 0, int yslop = 0) : bitmap_t(format, PIXEL_BITS, width, height, xslop, yslop) { }
bitmap_specific(bitmap_format format, PixelType *base, int width, int height, int rowpixels) : bitmap_t(format, PIXEL_BITS, base, width, height, rowpixels) { }
bitmap_specific(bitmap_format format, bitmap_specific<PixelType> &source, const rectangle &subrect) : bitmap_t(format, PIXEL_BITS, source, subrect) { }
bitmap_specific<PixelType> &operator=(bitmap_specific<PixelType> &&) = default;
public:
using pixel_t = PixelType;
// getters
uint8_t bpp() const { return PIXEL_BITS; }
// pixel accessors
PixelType &pix(int32_t y, int32_t x = 0) { return pixt<PixelType>(y, x); }
PixelType const &pix(int32_t y, int32_t x = 0) const { return pixt<PixelType>(y, x); }
// operations
void fill(PixelType color) { fill(color, cliprect()); }
void fill(PixelType color, const rectangle &bounds)
{
// if we have a cliprect, intersect with that
rectangle fill(bounds);
fill &= cliprect();
if (!fill.empty())
{
for (int32_t y = fill.top(); y <= fill.bottom(); y++)
std::fill_n(&pix(y, fill.left()), fill.width(), color);
}
}
void plot_box(int32_t x, int32_t y, int32_t width, int32_t height, PixelType color)
{
fill(color, rectangle(x, x + width - 1, y, y + height - 1));
}
};
// 8bpp bitmaps
using bitmap8_t = bitmap_specific<uint8_t>;
extern template class bitmap_specific<uint8_t>;
// 16bpp bitmaps
using bitmap16_t = bitmap_specific<uint16_t>;
extern template class bitmap_specific<uint16_t>;
// 32bpp bitmaps
using bitmap32_t = bitmap_specific<uint32_t>;
extern template class bitmap_specific<uint32_t>;
// 64bpp bitmaps
using bitmap64_t = bitmap_specific<uint64_t>;
extern template class bitmap_specific<uint64_t>;
// ======================> bitmap_ind8, bitmap_ind16, bitmap_ind32, bitmap_ind64
// BITMAP_FORMAT_IND8 bitmaps
class bitmap_ind8 : public bitmap8_t
{
static const bitmap_format k_bitmap_format = BITMAP_FORMAT_IND8;
public:
// construction/destruction
bitmap_ind8(bitmap_ind8 &&) = default;
bitmap_ind8(int width = 0, int height = 0, int xslop = 0, int yslop = 0) : bitmap8_t(k_bitmap_format, width, height, xslop, yslop) { }
bitmap_ind8(uint8_t *base, int width, int height, int rowpixels) : bitmap8_t(k_bitmap_format, base, width, height, rowpixels) { }
bitmap_ind8(bitmap_ind8 &source, const rectangle &subrect) : bitmap8_t(k_bitmap_format, source, subrect) { }
void wrap(uint8_t *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); }
void wrap(bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); }
// getters
bitmap_format format() const { return k_bitmap_format; }
bitmap_ind8 &operator=(bitmap_ind8 &&) = default;
};
// BITMAP_FORMAT_IND16 bitmaps
class bitmap_ind16 : public bitmap16_t
{
static const bitmap_format k_bitmap_format = BITMAP_FORMAT_IND16;
public:
// construction/destruction
bitmap_ind16(bitmap_ind16 &&) = default;
bitmap_ind16(int width = 0, int height = 0, int xslop = 0, int yslop = 0) : bitmap16_t(k_bitmap_format, width, height, xslop, yslop) { }
bitmap_ind16(uint16_t *base, int width, int height, int rowpixels) : bitmap16_t(k_bitmap_format, base, width, height, rowpixels) { }
bitmap_ind16(bitmap_ind16 &source, const rectangle &subrect) : bitmap16_t(k_bitmap_format, source, subrect) { }
void wrap(uint16_t *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); }
void wrap(bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); }
// getters
bitmap_format format() const { return k_bitmap_format; }
bitmap_ind16 &operator=(bitmap_ind16 &&) = default;
};
// BITMAP_FORMAT_IND32 bitmaps
class bitmap_ind32 : public bitmap32_t
{
static const bitmap_format k_bitmap_format = BITMAP_FORMAT_IND32;
public:
// construction/destruction
bitmap_ind32(bitmap_ind32 &&) = default;
bitmap_ind32(int width = 0, int height = 0, int xslop = 0, int yslop = 0) : bitmap32_t(k_bitmap_format, width, height, xslop, yslop) { }
bitmap_ind32(uint32_t *base, int width, int height, int rowpixels) : bitmap32_t(k_bitmap_format, base, width, height, rowpixels) { }
bitmap_ind32(bitmap_ind32 &source, const rectangle &subrect) : bitmap32_t(k_bitmap_format, source, subrect) { }
void wrap(uint32_t *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); }
void wrap(bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); }
// getters
bitmap_format format() const { return k_bitmap_format; }
bitmap_ind32 &operator=(bitmap_ind32 &&) = default;
};
// BITMAP_FORMAT_IND64 bitmaps
class bitmap_ind64 : public bitmap64_t
{
static const bitmap_format k_bitmap_format = BITMAP_FORMAT_IND64;
public:
// construction/destruction
bitmap_ind64(bitmap_ind64 &&) = default;
bitmap_ind64(int width = 0, int height = 0, int xslop = 0, int yslop = 0) : bitmap64_t(k_bitmap_format, width, height, xslop, yslop) { }
bitmap_ind64(uint64_t *base, int width, int height, int rowpixels) : bitmap64_t(k_bitmap_format, base, width, height, rowpixels) { }
bitmap_ind64(bitmap_ind64 &source, const rectangle &subrect) : bitmap64_t(k_bitmap_format, source, subrect) { }
void wrap(uint64_t *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); }
void wrap(bitmap_ind8 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); }
// getters
bitmap_format format() const { return k_bitmap_format; }
bitmap_ind64 &operator=(bitmap_ind64 &&) = default;
};
// ======================> bitmap_yuy16, bitmap_rgb32, bitmap_argb32
// BITMAP_FORMAT_YUY16 bitmaps
class bitmap_yuy16 : public bitmap16_t
{
static const bitmap_format k_bitmap_format = BITMAP_FORMAT_YUY16;
public:
// construction/destruction
bitmap_yuy16(bitmap_yuy16 &&) = default;
bitmap_yuy16(int width = 0, int height = 0, int xslop = 0, int yslop = 0) : bitmap16_t(k_bitmap_format, width, height, xslop, yslop) { }
bitmap_yuy16(uint16_t *base, int width, int height, int rowpixels) : bitmap16_t(k_bitmap_format, base, width, height, rowpixels) { }
bitmap_yuy16(bitmap_yuy16 &source, const rectangle &subrect) : bitmap16_t(k_bitmap_format, source, subrect) { }
void wrap(uint16_t *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); }
void wrap(bitmap_yuy16 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); }
// getters
bitmap_format format() const { return k_bitmap_format; }
bitmap_yuy16 &operator=(bitmap_yuy16 &&) = default;
};
// BITMAP_FORMAT_RGB32 bitmaps
class bitmap_rgb32 : public bitmap32_t
{
static const bitmap_format k_bitmap_format = BITMAP_FORMAT_RGB32;
public:
// construction/destruction
bitmap_rgb32(bitmap_rgb32 &&) = default;
bitmap_rgb32(int width = 0, int height = 0, int xslop = 0, int yslop = 0) : bitmap32_t(k_bitmap_format, width, height, xslop, yslop) { }
bitmap_rgb32(uint32_t *base, int width, int height, int rowpixels) : bitmap32_t(k_bitmap_format, base, width, height, rowpixels) { }
bitmap_rgb32(bitmap_rgb32 &source, const rectangle &subrect) : bitmap32_t(k_bitmap_format, source, subrect) { }
void wrap(uint32_t *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); }
void wrap(bitmap_rgb32 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); }
// getters
bitmap_format format() const { return k_bitmap_format; }
bitmap_rgb32 &operator=(bitmap_rgb32 &&) = default;
};
// BITMAP_FORMAT_ARGB32 bitmaps
class bitmap_argb32 : public bitmap32_t
{
static const bitmap_format k_bitmap_format = BITMAP_FORMAT_ARGB32;
public:
// construction/destruction
bitmap_argb32(bitmap_argb32 &&) = default;
bitmap_argb32(int width = 0, int height = 0, int xslop = 0, int yslop = 0) : bitmap32_t(k_bitmap_format, width, height, xslop, yslop) { }
bitmap_argb32(uint32_t *base, int width, int height, int rowpixels) : bitmap32_t(k_bitmap_format, base, width, height, rowpixels) { }
bitmap_argb32(bitmap_argb32 &source, const rectangle &subrect) : bitmap32_t(k_bitmap_format, source, subrect) { }
void wrap(uint32_t *base, int width, int height, int rowpixels) { bitmap_t::wrap(base, width, height, rowpixels); }
void wrap(bitmap_argb32 &source, const rectangle &subrect) { bitmap_t::wrap(static_cast<bitmap_t &>(source), subrect); }
// getters
bitmap_format format() const { return k_bitmap_format; }
bitmap_argb32 &operator=(bitmap_argb32 &&) = default;
};
#endif // MAME_UTIL_BITMAP_H

View File

@ -1,66 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************
corealloc.h
Memory allocation helpers for the helper library.
***************************************************************************/
#ifndef MAME_LIB_UTIL_COREALLOC_H
#define MAME_LIB_UTIL_COREALLOC_H
#pragma once
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <memory>
#include <new>
#include <type_traits>
#include <utility>
// global allocation helpers
template<typename Tp> struct MakeUniqClearT { typedef std::unique_ptr<Tp> single_object; };
template<typename Tp> struct MakeUniqClearT<Tp[]> { typedef std::unique_ptr<Tp[]> array; };
template<typename Tp, size_t Bound> struct MakeUniqClearT<Tp[Bound]> { struct invalid_type { }; };
/// make_unique_clear for single objects
template<typename Tp, typename... Params>
inline typename MakeUniqClearT<Tp>::single_object make_unique_clear(Params&&... args)
{
void *const ptr = ::operator new(sizeof(Tp)); // allocate memory
std::memset(ptr, 0, sizeof(Tp));
return std::unique_ptr<Tp>(new(ptr) Tp(std::forward<Params>(args)...));
}
/// make_unique_clear for arrays of unknown bound
template<typename Tp>
inline typename MakeUniqClearT<Tp>::array make_unique_clear(size_t num)
{
auto size = sizeof(std::remove_extent_t<Tp>) * num;
unsigned char* ptr = new unsigned char[size]; // allocate memory
std::memset(ptr, 0, size);
return std::unique_ptr<Tp>(new(ptr) std::remove_extent_t<Tp>[num]());
}
template<typename Tp, unsigned char F>
inline typename MakeUniqClearT<Tp>::array make_unique_clear(size_t num)
{
auto size = sizeof(std::remove_extent_t<Tp>) * num;
unsigned char* ptr = new unsigned char[size]; // allocate memory
std::memset(ptr, F, size);
return std::unique_ptr<Tp>(new(ptr) std::remove_extent_t<Tp>[num]());
}
/// Disable make_unique_clear for arrays of known bound
template<typename Tp, typename... Params>
inline typename MakeUniqClearT<Tp>::invalid_type make_unique_clear(Params&&...) = delete;
#endif // MAME_LIB_UTIL_COREALLOC_H

View File

@ -1,689 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles, Vas Crabb
/***************************************************************************
coretmpl.h
Core templates for basic non-string types.
***************************************************************************/
#ifndef MAME_UTIL_CORETMPL_H
#define MAME_UTIL_CORETMPL_H
#pragma once
#include "osdcomm.h"
#include "vecstream.h"
#include <array>
#include <cstddef>
#include <iterator>
#include <numeric>
#include <stdexcept>
#include <string_view>
#include <type_traits>
#include <utility>
// ======================> simple_list
// a simple_list is a singly-linked list whose 'next' pointer is owned
// by the object
template<class ElementType>
class simple_list final
{
public:
class auto_iterator
{
public:
typedef int difference_type;
typedef ElementType value_type;
typedef ElementType *pointer;
typedef ElementType &reference;
typedef std::forward_iterator_tag iterator_category;
// construction/destruction
auto_iterator() noexcept : m_current(nullptr) { }
auto_iterator(ElementType *ptr) noexcept : m_current(ptr) { }
// required operator overloads
bool operator==(const auto_iterator &iter) const noexcept { return m_current == iter.m_current; }
bool operator!=(const auto_iterator &iter) const noexcept { return m_current != iter.m_current; }
ElementType &operator*() const noexcept { return *m_current; }
ElementType *operator->() const noexcept { return m_current; }
// note that ElementType::next() must not return a const ptr
auto_iterator &operator++() noexcept { m_current = m_current->next(); return *this; }
auto_iterator operator++(int) noexcept { auto_iterator result(*this); m_current = m_current->next(); return result; }
private:
// private state
ElementType *m_current;
};
// construction/destruction
simple_list() noexcept { }
~simple_list() noexcept { reset(); }
// we don't support deep copying
simple_list(const simple_list &) = delete;
simple_list &operator=(const simple_list &) = delete;
// but we do support cheap swap/move
simple_list(simple_list &&list) noexcept { operator=(std::move(list)); }
simple_list &operator=(simple_list &&list)
{
using std::swap;
swap(m_head, list.m_head);
swap(m_tail, list.m_tail);
swap(m_count, list.m_count);
return *this;
}
// simple getters
ElementType *first() const noexcept { return m_head; }
ElementType *last() const noexcept { return m_tail; }
int count() const noexcept { return m_count; }
bool empty() const noexcept { return m_count == 0; }
// range iterators
auto_iterator begin() const noexcept { return auto_iterator(m_head); }
auto_iterator end() const noexcept { return auto_iterator(nullptr); }
// remove (free) all objects in the list, leaving an empty list
void reset() noexcept
{
while (m_head != nullptr)
remove(*m_head);
}
// add the given object to the head of the list
ElementType &prepend(ElementType &object) noexcept
{
object.m_next = m_head;
m_head = &object;
if (m_tail == nullptr)
m_tail = m_head;
m_count++;
return object;
}
// add the given list to the head of the list
void prepend_list(simple_list<ElementType> &list) noexcept
{
int count = list.count();
if (count == 0)
return;
ElementType *tail = list.last();
ElementType *head = list.detach_all();
tail->m_next = m_head;
m_head = head;
if (m_tail == nullptr)
m_tail = tail;
m_count += count;
}
// add the given object to the tail of the list
ElementType &append(ElementType &object) noexcept
{
object.m_next = nullptr;
if (m_tail != nullptr)
m_tail = m_tail->m_next = &object;
else
m_tail = m_head = &object;
m_count++;
return object;
}
// add the given list to the tail of the list
void append_list(simple_list<ElementType> &list) noexcept
{
int count = list.count();
if (count == 0)
return;
ElementType *tail = list.last();
ElementType *head = list.detach_all();
if (m_tail != nullptr)
m_tail->m_next = head;
else
m_head = head;
m_tail = tail;
m_count += count;
}
// insert the given object after a particular object (nullptr means prepend)
ElementType &insert_after(ElementType &object, ElementType *insert_after) noexcept
{
if (insert_after == nullptr)
return prepend(object);
object.m_next = insert_after->m_next;
insert_after->m_next = &object;
if (m_tail == insert_after)
m_tail = &object;
m_count++;
return object;
}
// insert the given object before a particular object (nullptr means append)
ElementType &insert_before(ElementType &object, ElementType *insert_before) noexcept
{
if (insert_before == nullptr)
return append(object);
for (ElementType **curptr = &m_head; *curptr != nullptr; curptr = &(*curptr)->m_next)
if (*curptr == insert_before)
{
object.m_next = insert_before;
*curptr = &object;
if (m_head == insert_before)
m_head = &object;
m_count++;
return object;
}
return object;
}
// replace an item in the list at the same location, and remove it
ElementType &replace_and_remove(ElementType &object, ElementType &toreplace) noexcept
{
ElementType *prev = nullptr;
for (ElementType *cur = m_head; cur != nullptr; prev = cur, cur = cur->m_next)
if (cur == &toreplace)
{
if (prev != nullptr)
prev->m_next = &object;
else
m_head = &object;
if (m_tail == &toreplace)
m_tail = &object;
object.m_next = toreplace.m_next;
delete &toreplace;
return object;
}
return append(object);
}
// detach the head item from the list, but don't free its memory
ElementType *detach_head() noexcept
{
ElementType *result = m_head;
if (result != nullptr)
{
m_head = result->m_next;
m_count--;
if (m_head == nullptr)
m_tail = nullptr;
}
return result;
}
// detach the given item from the list, but don't free its memory
ElementType &detach(ElementType &object) noexcept
{
ElementType *prev = nullptr;
for (ElementType *cur = m_head; cur != nullptr; prev = cur, cur = cur->m_next)
if (cur == &object)
{
if (prev != nullptr)
prev->m_next = object.m_next;
else
m_head = object.m_next;
if (m_tail == &object)
m_tail = prev;
m_count--;
return object;
}
return object;
}
// detach the entire list, returning the head, but don't free memory
ElementType *detach_all() noexcept
{
ElementType *result = m_head;
m_head = m_tail = nullptr;
m_count = 0;
return result;
}
// remove the given object and free its memory
void remove(ElementType &object) noexcept
{
delete &detach(object);
}
// find an object by index in the list
ElementType *find(int index) const noexcept
{
for (ElementType *cur = m_head; cur != nullptr; cur = cur->m_next)
if (index-- == 0)
return cur;
return nullptr;
}
// return the index of the given object in the list
int indexof(const ElementType &object) const noexcept
{
int index = 0;
for (ElementType *cur = m_head; cur != nullptr; cur = cur->m_next)
{
if (cur == &object)
return index;
index++;
}
return -1;
}
private:
// internal state
ElementType * m_head = nullptr; // head of the singly-linked list
ElementType * m_tail = nullptr; // tail of the singly-linked list
int m_count = 0; // number of objects in the list
};
// ======================> fixed_allocator
// a fixed_allocator is a simple class that maintains a free pool of objects
template<class ItemType>
class fixed_allocator
{
// we don't support deep copying
fixed_allocator(const fixed_allocator &);
fixed_allocator &operator=(const fixed_allocator &);
public:
// construction/destruction
fixed_allocator() { }
// allocate a new item, either by recycling an old one, or by allocating a new one
ItemType *alloc()
{
ItemType *result = m_freelist.detach_head();
if (result == nullptr)
result = new ItemType;
return result;
}
// reclaim an item by adding it to the free list
void reclaim(ItemType *item) { if (item != nullptr) m_freelist.append(*item); }
void reclaim(ItemType &item) { m_freelist.append(item); }
// reclaim all items from a list
void reclaim_all(simple_list<ItemType> &_list) { m_freelist.append_list(_list); }
private:
// internal state
simple_list<ItemType> m_freelist; // list of free objects
};
// ======================> contiguous_sequence_wrapper
namespace util {
using osd::u8;
using osd::u16;
using osd::u32;
using osd::u64;
using osd::s8;
using osd::s16;
using osd::s32;
using osd::s64;
// wraps an existing sequence of values
template<typename T>
class contiguous_sequence_wrapper
{
public:
typedef std::ptrdiff_t difference_type;
typedef std::size_t size_type;
typedef T value_type;
typedef T &reference;
typedef const T &const_reference;
typedef T *pointer;
typedef T *iterator;
typedef const T *const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
contiguous_sequence_wrapper(T *ptr, std::size_t size)
: m_begin(ptr)
, m_end(ptr + size)
{
}
contiguous_sequence_wrapper(const contiguous_sequence_wrapper &that) = default;
// iteration
iterator begin() { return m_begin; }
const_iterator begin() const { return m_begin; }
const_iterator cbegin() const { return m_begin; }
iterator end() { return m_end; }
const_iterator end() const { return m_end; }
const_iterator cend() const { return m_end; }
// reverse iteration
reverse_iterator rbegin() { return std::reverse_iterator<iterator>(end()); }
const_reverse_iterator rbegin() const { return std::reverse_iterator<const_iterator>(end()); }
const_reverse_iterator crbegin() const { return std::reverse_iterator<const_iterator>(cend()); }
reverse_iterator rend() { return std::reverse_iterator<iterator>(begin()); }
const_reverse_iterator rend() const { return std::reverse_iterator<iterator>(begin()); }
const_reverse_iterator crend() const { return std::reverse_iterator<iterator>(begin()); }
// capacity
size_type size() const { return m_end - m_begin; }
size_type max_size() const { return size(); }
bool empty() const { return size() == 0; }
// element access
reference front() { return operator[](0); }
const_reference front() const { return operator[](0); }
reference back() { return operator[](size() - 1); }
const_reference back() const { return operator[](size() - 1); }
reference operator[] (size_type n) { return m_begin[n]; }
const_reference operator[] (size_type n) const { return m_begin[n]; }
reference at(size_type n) { check_in_bounds(n); return operator[](n); }
const_reference at(size_type n) const { check_in_bounds(n); return operator[](n); }
private:
iterator m_begin;
iterator m_end;
void check_in_bounds(size_type n)
{
if (n < 0 || n >= size())
throw std::out_of_range("invalid contiguous_sequence_wrapper<T> subscript");
}
};
template <typename T, std::size_t N, bool WriteWrap = false, bool ReadWrap = WriteWrap>
class fifo : protected std::array<T, N>
{
public:
fifo()
: std::array<T, N>()
, m_head(this->begin())
, m_tail(this->begin())
, m_empty(true)
{
static_assert(0U < N, "FIFO must have at least one element");
}
fifo(fifo<T, N, WriteWrap, ReadWrap> const &) = delete;
fifo(fifo<T, N, WriteWrap, ReadWrap> &&) = delete;
fifo<T, N, WriteWrap, ReadWrap> &operator=(fifo<T, N, WriteWrap, ReadWrap> const &) = delete;
fifo<T, N, WriteWrap, ReadWrap> &operator=(fifo<T, N, WriteWrap, ReadWrap> &&) = delete;
template <bool W, bool R>
fifo(fifo<T, N, W, R> const &that)
: std::array<T, N>(that)
, m_head(std::advance(this->begin(), std::distance(that.begin(), that.m_head)))
, m_tail(std::advance(this->begin(), std::distance(that.begin(), that.m_tail)))
, m_empty(that.m_empty)
{
}
template <bool W, bool R>
fifo(fifo<T, N, W, R> &&that)
: std::array<T, N>(std::move(that))
, m_head(std::advance(this->begin(), std::distance(that.begin(), that.m_head)))
, m_tail(std::advance(this->begin(), std::distance(that.begin(), that.m_tail)))
, m_empty(that.m_empty)
{
}
template <bool W, bool R>
fifo<T, N, WriteWrap, ReadWrap> &operator=(fifo<T, N, W, R> const &that)
{
std::array<T, N>::operator=(that);
m_head = std::advance(this->begin(), std::distance(that.begin(), that.m_head));
m_tail = std::advance(this->begin(), std::distance(that.begin(), that.m_tail));
m_empty = that.m_empty;
return *this;
}
template <bool W, bool R>
fifo<T, N, WriteWrap, ReadWrap> &operator=(fifo<T, N, WriteWrap, ReadWrap> &&that)
{
std::array<T, N>::operator=(std::move(that));
m_head = std::advance(this->begin(), std::distance(that.begin(), that.m_head));
m_tail = std::advance(this->begin(), std::distance(that.begin(), that.m_tail));
m_empty = that.m_empty;
return *this;
}
bool full() const { return !m_empty && (m_head == m_tail); }
bool empty() const { return m_empty; }
// number of currently enqueued elements
std::size_t queue_length() const
{
if (m_empty)
return 0;
auto const distance = std::distance(m_head, m_tail);
return (distance > 0) ? distance : (N + distance);
}
void enqueue(T const &v)
{
if (WriteWrap || m_empty || (m_head != m_tail))
{
*m_tail = v;
if (this->end() == ++m_tail)
m_tail = this->begin();
m_empty = false;
}
}
void enqueue(T &&v)
{
if (WriteWrap || m_empty || (m_head != m_tail))
{
*m_tail = std::move(v);
if (this->end() == ++m_tail)
m_tail = this->begin();
m_empty = false;
}
}
T const &dequeue()
{
T const &result(*m_head);
if (ReadWrap || !m_empty)
{
if (this->end() == ++m_head)
m_head = this->begin();
m_empty = (m_head == m_tail);
}
return result;
}
void poke(T &v)
{
*m_tail = v;
}
void poke(T &&v)
{
*m_tail = std::move(v);
}
T const &peek() const
{
return *m_head;
}
void clear()
{
m_head = m_tail = this->begin();
m_empty = true;
}
private:
typename fifo::iterator m_head, m_tail;
bool m_empty;
};
// extract a string_view from an ovectorstream buffer
template <typename CharT, typename Traits, typename Allocator>
std::basic_string_view<CharT, Traits> buf_to_string_view(basic_ovectorstream<CharT, Traits, Allocator> &stream)
{
// this works on the assumption that the value tellp returns is the same both before and after vec is called
return std::basic_string_view<CharT, Traits>(&stream.vec()[0], stream.tellp());
}
// For declaring an array of the same dimensions as another array (including multi-dimensional arrays)
template <typename T, typename U> struct equivalent_array_or_type { typedef T type; };
template <typename T, typename U, std::size_t N> struct equivalent_array_or_type<T, U[N]> { typedef typename equivalent_array_or_type<T, U>::type type[N]; };
template <typename T, typename U> using equivalent_array_or_type_t = typename equivalent_array_or_type<T, U>::type;
template <typename T, typename U> struct equivalent_array { };
template <typename T, typename U, std::size_t N> struct equivalent_array<T, U[N]> { typedef equivalent_array_or_type_t<T, U> type[N]; };
template <typename T, typename U> using equivalent_array_t = typename equivalent_array<T, U>::type;
#define EQUIVALENT_ARRAY(a, T) util::equivalent_array_t<T, std::remove_reference_t<decltype(a)> >
template <typename E>
using enable_enum_t = typename std::enable_if_t<std::is_enum<E>::value, typename std::underlying_type_t<E> >;
// template function which takes a strongly typed enumerator and returns its value as a compile-time constant
template <typename E>
constexpr enable_enum_t<E> underlying_value(E e) noexcept
{
return static_cast<typename std::underlying_type_t<E> >(e);
}
// template function which takes an integral value and returns its representation as enumerator (even strongly typed)
template <typename E , typename T>
constexpr typename std::enable_if_t<std::is_enum<E>::value && std::is_integral<T>::value, E> enum_value(T value) noexcept
{
return static_cast<E>(value);
}
/// \defgroup bitutils Useful functions for bit shuffling
/// \{
/// \brief Generate a right-aligned bit mask
///
/// Generates a right aligned mask of the specified width. Works with
/// signed and unsigned integer types.
/// \tparam T Desired output type.
/// \tparam U Type of the input (generally resolved by the compiler).
/// \param [in] n Width of the mask to generate in bits.
/// \return Right-aligned mask of the specified width.
template <typename T, typename U> constexpr T make_bitmask(U n)
{
return T((n < (8 * sizeof(T)) ? (std::make_unsigned_t<T>(1) << n) : std::make_unsigned_t<T>(0)) - 1);
}
/// \brief Extract a single bit from an integer
///
/// Extracts a single bit from an integer into the least significant bit
/// position.
///
/// \param [in] x The integer to extract the bit from.
/// \param [in] n The bit to extract, where zero is the least
/// significant bit of the input.
/// \return Zero if the specified bit is unset, or one if it is set.
/// \sa bitswap
template <typename T, typename U> constexpr T BIT(T x, U n) noexcept { return (x >> n) & T(1); }
/// \brief Extract a bit field from an integer
///
/// Extracts and right-aligns a bit field from an integer.
///
/// \param [in] x The integer to extract the bit field from.
/// \param [in] n The least significant bit position of the field to
/// extract, where zero is the least significant bit of the input.
/// \param [in] w The width of the field to extract in bits.
/// \return The field [n..(n+w-1)] from the input.
/// \sa bitswap
template <typename T, typename U, typename V> constexpr T BIT(T x, U n, V w)
{
return (x >> n) & make_bitmask<T>(w);
}
/// \brief Extract bits in arbitrary order
///
/// Extracts bits from an integer. Specify the bits in the order they
/// should be arranged in the output, from most significant to least
/// significant. The extracted bits will be packed into a right-aligned
/// field in the output.
///
/// \param [in] val The integer to extract bits from.
/// \param [in] b The first bit to extract from the input
/// extract, where zero is the least significant bit of the input.
/// This bit will appear in the most significant position of the
/// right-aligned output field.
/// \param [in] c The remaining bits to extract, where zero is the
/// least significant bit of the input.
/// \return The extracted bits packed into a right-aligned field.
template <typename T, typename U, typename... V> constexpr T bitswap(T val, U b, V... c) noexcept
{
if constexpr (sizeof...(c) > 0U)
return (BIT(val, b) << sizeof...(c)) | bitswap(val, c...);
else
return BIT(val, b);
}
/// \brief Extract bits in arbitrary order with explicit count
///
/// Extracts bits from an integer. Specify the bits in the order they
/// should be arranged in the output, from most significant to least
/// significant. The extracted bits will be packed into a right-aligned
/// field in the output. The number of bits to extract must be supplied
/// as a template argument.
///
/// A compile error will be generated if the number of bit positions
/// supplied does not match the specified number of bits to extract, or
/// if the output type is too small to hold the extracted bits. This
/// guards against some simple errors.
///
/// \tparam B The number of bits to extract. Must match the number of
/// bit positions supplied.
/// \param [in] val The integer to extract bits from.
/// \param [in] b Bits to extract, where zero is the least significant
/// bit of the input. Specify bits in the order they should appear in
/// the output field, from most significant to least significant.
/// \return The extracted bits packed into a right-aligned field.
template <unsigned B, typename T, typename... U> T bitswap(T val, U... b) noexcept
{
static_assert(sizeof...(b) == B, "wrong number of bits");
static_assert((sizeof(std::remove_reference_t<T>) * 8) >= B, "return type too small for result");
return bitswap(val, b...);
}
/// \}
// constexpr absolute value of an integer
template <typename T>
constexpr std::enable_if_t<std::is_signed<T>::value, T> iabs(T v) noexcept
{
return (v < T(0)) ? -v : v;
}
// reduce a fraction
template <typename M, typename N>
inline void reduce_fraction(M &num, N &den)
{
auto const div(std::gcd(num, den));
if (div)
{
num /= div;
den /= div;
}
}
} // namespace util
#endif // MAME_UTIL_CORETMPL_H

View File

@ -1,287 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles,Vas Crabb
/***************************************************************************
delegate.cpp
Templates and classes to enable delegates for callbacks.
***************************************************************************/
#include "delegate.h"
#include <cstdio>
#include <sstream>
//**************************************************************************
// MACROS
//**************************************************************************
#if defined(MAME_DELEGATE_LOG_ADJ)
#define LOG(...) printf(__VA_ARGS__)
#else
#define LOG(...) do { if (false) printf(__VA_ARGS__); } while (false)
#endif
//**************************************************************************
// LATE BINDING EXCEPTION
//**************************************************************************
binding_type_exception::binding_type_exception(std::type_info const &target_type, std::type_info const &actual_type)
: m_target_type(&target_type)
, m_actual_type(&actual_type)
{
std::ostringstream os;
os << "Error performing late bind of function expecting type " << target_type.name() << " to instance of type " << actual_type.name();
m_what = os.str();
}
char const *binding_type_exception::what() const noexcept
{
return m_what.c_str();
}
namespace util::detail {
//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
const delegate_mfp_compatible::raw_mfp_data delegate_mfp_compatible::s_null_mfp = { { 0 } };
//**************************************************************************
// INTERNAL DELEGATE HELPERS
//**************************************************************************
//-------------------------------------------------
// delegate_mfp_itanium::convert_to_generic -
// given an object pointer and member function
// pointer, apply the displacement and get the
// actual function pointer
//-------------------------------------------------
delegate_generic_function delegate_mfp_itanium::convert_to_generic(delegate_generic_class *&object) const
{
// apply the "this" delta to the object first - the value is shifted to the left one bit position for the ARM-like variant
LOG("Input this=%p ptr=%p adj=%ld ", reinterpret_cast<void const *>(object), reinterpret_cast<void const *>(m_function), long(m_this_delta));
object = reinterpret_cast<delegate_generic_class *>(
reinterpret_cast<std::uint8_t *>(object) + (m_this_delta >> ((MAME_ABI_CXX_ITANIUM_MFP_TYPE == MAME_ABI_CXX_ITANIUM_MFP_ARM) ? 1 : 0)));
LOG("Calculated this=%p ", reinterpret_cast<void const *>(object));
// test the virtual member function flag - it's the low bit of either the ptr or adj field, depending on the variant
if ((MAME_ABI_CXX_ITANIUM_MFP_TYPE == MAME_ABI_CXX_ITANIUM_MFP_ARM) ? !(m_this_delta & 1) : !(m_function & 1))
{
// conventional function pointer
LOG("ptr=%p\n", reinterpret_cast<void const *>(m_function));
return reinterpret_cast<delegate_generic_function>(m_function);
}
else
{
// byte index into the vtable to the function
std::uint8_t const *const vtable_ptr = *reinterpret_cast<std::uint8_t const *const *>(object) + m_function - ((MAME_ABI_CXX_ITANIUM_MFP_TYPE == MAME_ABI_CXX_ITANIUM_MFP_ARM) ? 0 : 1);
delegate_generic_function result;
if (MAME_ABI_CXX_VTABLE_FNDESC)
result = reinterpret_cast<delegate_generic_function>(uintptr_t(vtable_ptr));
else
result = *reinterpret_cast<delegate_generic_function const *>(vtable_ptr);
LOG("ptr=%p (vtable)\n", reinterpret_cast<void const *>(result));
return result;
}
}
//-------------------------------------------------
// delegate_mfp_msvc::adjust_this_pointer - given
// an object pointer and member function pointer,
// apply the displacement, and walk past
// recognisable thunks
//-------------------------------------------------
delegate_generic_function delegate_mfp_msvc::adjust_this_pointer(delegate_generic_class *&object) const
{
LOG("Input this=%p ", reinterpret_cast<void const *>(object));
if (sizeof(single_base_equiv) < m_size)
LOG("thisdelta=%d ", m_this_delta);
if (sizeof(unknown_base_equiv) == m_size)
LOG("vptrdelta=%d vindex=%d ", m_vptr_offs, m_vt_index);
std::uint8_t *byteptr = reinterpret_cast<std::uint8_t *>(object);
// test for pointer to member function cast across virtual inheritance relationship
if ((sizeof(unknown_base_equiv) == m_size) && m_vt_index)
{
// add offset from "this" pointer to location of vptr, and add offset to virtual base from vtable
byteptr += m_vptr_offs;
std::uint8_t const *const vptr = *reinterpret_cast<std::uint8_t const *const *>(byteptr);
byteptr += *reinterpret_cast<int const *>(vptr + m_vt_index);
}
// add "this" pointer displacement if present in the pointer to member function
if (sizeof(single_base_equiv) < m_size)
byteptr += m_this_delta;
LOG("Calculated this=%p\n", reinterpret_cast<void const *>(byteptr));
object = reinterpret_cast<delegate_generic_class *>(byteptr);
// walk past recognisable thunks
#if defined(__x86_64__) || defined(_M_X64)
std::uint8_t const *func = reinterpret_cast<std::uint8_t const *>(m_function);
while (true)
{
// Assumes Windows calling convention, and doesn't consider that
// the "this" pointer could be in RDX if RCX is a pointer to
// space for an oversize scalar result. Since the result area
// is uninitialised on entry, you won't see something that looks
// like a vtable dispatch through RCX in this case - it won't
// behave badly, it just won't bypass virtual call thunks in the
// rare situations where the return type is an oversize scalar.
if (0xe9 == func[0])
{
// relative jump with 32-bit displacement (typically a resolved PLT entry)
LOG("Found relative jump at %p ", func);
func += std::ptrdiff_t(5) + *reinterpret_cast<std::int32_t const *>(func + 1);
LOG("redirecting to %p\n", func);
continue;
}
else if ((0x48 == func[0]) && (0x8b == func[1]) && (0x01 == func[2]))
{
if ((0xff == func[3]) && ((0x20 == func[4]) || (0x60 == func[4]) || (0xa0 == func[4])))
{
// MSVC virtual function call thunk - mov rax,QWORD PTR [rcx] ; jmp QWORD PTR [rax+...]
LOG("Found virtual member function thunk at %p ", func);
std::uint8_t const *const vptr = *reinterpret_cast<std::uint8_t const *const *>(object);
if (0x20 == func[4]) // no displacement
func = *reinterpret_cast<std::uint8_t const *const *>(vptr);
else if (0x60 == func[4]) // 8-bit displacement
func = *reinterpret_cast<std::uint8_t const *const *>(vptr + *reinterpret_cast<std::int8_t const *>(func + 5));
else // 32-bit displacement
func = *reinterpret_cast<std::uint8_t const *const *>(vptr + *reinterpret_cast<std::int32_t const *>(func + 5));
LOG("redirecting to %p\n", func);
continue;
}
else if ((0x48 == func[3]) && (0x8b == func[4]))
{
// clang virtual function call thunk - mov rax,QWORD PTR [rcx] ; mov rax,QWORD PTR [rax+...] ; jmp rax
if ((0x00 == func[5]) && (0x48 == func[6]) && (0xff == func[7]) && (0xe0 == func[8]))
{
// no displacement
LOG("Found virtual member function thunk at %p ", func);
std::uint8_t const *const vptr = *reinterpret_cast<std::uint8_t const *const *>(object);
func = *reinterpret_cast<std::uint8_t const *const *>(vptr);
LOG("redirecting to %p\n", func);
continue;
}
else if ((0x40 == func[5]) && (0x48 == func[7]) && (0xff == func[8]) && (0xe0 == func[9]))
{
// 8-bit displacement
LOG("Found virtual member function thunk at %p ", func);
std::uint8_t const *const vptr = *reinterpret_cast<std::uint8_t const *const *>(object);
func = *reinterpret_cast<std::uint8_t const *const *>(vptr + *reinterpret_cast<std::int8_t const *>(func + 6));
LOG("redirecting to %p\n", func);
continue;
}
else if ((0x80 == func[5]) && (0x48 == func[10]) && (0xff == func[11]) && (0xe0 == func[12]))
{
// 32-bit displacement
LOG("Found virtual member function thunk at %p ", func);
std::uint8_t const *const vptr = *reinterpret_cast<std::uint8_t const *const *>(object);
func = *reinterpret_cast<std::uint8_t const *const *>(vptr + *reinterpret_cast<std::int32_t const *>(func + 6));
LOG("redirecting to %p\n", func);
continue;
}
}
}
// clang uses unoptimised thunks if optimisation is disabled
// Without optimisation, clang produces thunks like:
// 50 push rax
// 48 89 0c 24 mov QWORD PTR [rsp],rcx
// 48 8b 0c 24 mov rcx,QWORD PTR [rsp]
// 48 8b 01 mov rax,QWORD PTR [rcx]
// 48 8b 80 xx xx xx xx mov rax,QWORD PTR [rax+...]
// 41 5a pop r10
// 48 ff e0 jmp rax
// Trying to decode these thunks likely isn't worth the effort.
// Chasing performance in unoptimised builds isn't very useful,
// and the format of these thunks may be fragile.
// not something we can easily bypass
break;
}
return reinterpret_cast<delegate_generic_function>(std::uintptr_t(func));
#elif defined(__aarch64__) || defined(_M_ARM64)
std::uint32_t const *func = reinterpret_cast<std::uint32_t const *>(m_function);
while (true)
{
// Assumes little Endian mode. Instructions are always stored
// in little Endian format on AArch64, so if big Endian mode is
// to be supported, the values need to be swapped.
if ((0x90000010 == (func[0] & 0x9f00001f)) && (0x91000210 == (func[1] & 0xffc003ff)) && (0xd61f0200 == func[2]))
{
// page-relative jump with +/-4GB reach - adrp xip0,... ; add xip0,xip0,#... ; br xip0
LOG("Found page-relative jump at %p ", func);
std::int64_t const page =
(std::uint64_t(func[0] & 0x60000000) >> 17) |
(std::uint64_t(func[0] & 0x00ffffe0) << 9) |
((func[0] & 0x00800000) ? (~std::uint64_t(0) << 33) : 0);
std::uint32_t const offset = (func[1] & 0x003ffc00) >> 10;
func = reinterpret_cast<std::uint32_t const *>(((std::uintptr_t(func) + page) & (~std::uintptr_t(0) << 12)) + offset);
LOG("redirecting to %p\n", func);
}
else if ((0xf9400010 == func[0]) && (0xf9400210 == (func[1] & 0xffc003ff)) && (0xd61f0200 == func[2]))
{
// virtual function call thunk - ldr xip0,[x0] ; ldr xip0,[x0,#...] ; br xip0
LOG("Found virtual member function thunk at %p ", func);
std::uint32_t const *const *const vptr = *reinterpret_cast<std::uint32_t const *const *const *>(object);
func = vptr[(func[1] & 0x003ffc00) >> 10];
LOG("redirecting to %p\n", func);
}
else
{
// not something we can easily bypass
break;
}
// clang uses horribly sub-optimal thunks for AArch64
// Without optimisation, clang produces thunks like:
// d10143ff sub sp,sp,#80
// f90027e7 str x7,[sp,#72]
// f90023e6 str x6,[sp,#64]
// f9001fe5 str x5,[sp,#56]
// f9001be4 str x4,[sp,#48]
// f90017e3 str x3,[sp,#40]
// f90013e2 str x2,[sp,#32]
// f9000fe1 str x1,[sp,#24]
// f90007e0 str x0,[sp,#8]
// f94007e0 ldr x0,[sp,#8]
// f9400009 ldr x9,[x0]
// f9400129 ldr x9,[x9,#...]
// 910143ff add sp,sp,#80
// d61f0120 br x9
// With optimisation, clang produces thunks like:
// d10103ff sub sp,sp,#64
// a9008be1 stp x1,x2,[sp,#8]
// a90193e3 stp x3,x4,[sp,#24]
// a9029be5 stp x5,x6,[sp,#40]
// f9001fe7 str x7,[sp,#56]
// f9400009 ldr x9,[x0]
// f9400129 ldr x9,[x9,#...]
// 910103ff add sp,sp,#64
// d61f0120 br x9
// It's more effort than it's worth to try decoding these
// thunks.
}
return reinterpret_cast<delegate_generic_function>(std::uintptr_t(func));
#else
return reinterpret_cast<delegate_generic_function>(m_function);
#endif
}
} // namespace util::detail

View File

@ -1,972 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles,Couriersud,Miodrag Milanovic,Vas Crabb
/***************************************************************************
delegate.h
Templates and classes to enable delegates for callbacks.
****************************************************************************
There are many implementations of delegate-like functionality for
C++ code, but none of them is a perfect drop-in fit for use in MAME.
In order to be useful in MAME, we need the following properties:
* No significant overhead; we want to use these for memory
accessors, and memory accessor overhead is already the dominant
performance aspect for most drivers.
* Existing static functions need to be bound with an additional
pointer parameter as the first argument. All existing
implementations that allow static function binding assume the
same signature as the member functions.
* We must be able to bind the function separately from the
object. This is to allow configurations to bind functions
before the objects are created.
Thus, the implementations below are based on existing works but are
really a new implementation that is specific to MAME.
--------------------------------------------------------------------
The "compatible" version of delegates is based on an implementation
from Sergey Ryazanov, found here:
https://www.codeproject.com/Articles/11015/The-Impossibly-Fast-C-Delegates
These delegates essentially generate a templated static stub function
for each target function. The static function takes the first
parameter, uses it as the object pointer, and calls through the
member function. For static functions, the stub is compatible with
the signature of a static function, so we just set the stub directly.
Pros:
* should work with any modern compiler
* static bindings are just as fast as direct calls
Cons:
* lots of little stub functions generated
* double-hops on member function calls means more overhead
* calling through stub functions repackages parameters
--------------------------------------------------------------------
The "Itanium" version of delegates makes use of the internal
structure of member function pointers in order to convert them at
binding time into simple static function pointers. This only works
on platforms where object->func(p1, p2) is equivalent in calling
convention to func(object, p1, p2).
Pros:
* as fast as a standard function call in static and member cases
* no stub functions or double-hops needed
Cons:
* requires internal knowledge of the member function pointer
* only works for two popular variants of the Itanium C++ ABI
--------------------------------------------------------------------
The "MSVC" version of delegates makes use of the internal structure
of member function pointers in order to convert them at binding time
into simple static function pointers. This only works on platforms
where object->func(p1, p2) is equivalent in calling convention to
func(object, p1, p2).
Pros:
* as fast as a standard function call in static and non-virtual
member cases
* no stub functions needed
Cons:
* requires internal knowledge of the member function pointer
* only works works with MSVC ABI, and not on 32-bit x86
* does not work for classes with virtual bases
* structure return does not work with member function pointers
* virtual member function lookup cannot be done in advance
--------------------------------------------------------------------
Further reading:
* http://itanium-cxx-abi.github.io/cxx-abi/abi.html#member-pointers
Formal specification for the most common member function pointer
implementations.
* https://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible
Discusses many member function pointer implementations. Based
on reverse-engineering, so not entirely accurate. In particular,
various fields are incorrectly assumed to be int-sized which is
not true in the general case.
* https://devblogs.microsoft.com/oldnewthing/20040209-00/?p=40713
Describes the MSVC implementation of pointers to member
functions for classes with single or multiple inheritance. Does
not mention the additional variants for virtual or unknown
inheritance. Incorrectly states that the "this" pointer
displacement is a size_t when in reality it is an int (important
for 64-bit architectures).
***************************************************************************/
#ifndef MAME_LIB_UTIL_DELEGATE_H
#define MAME_LIB_UTIL_DELEGATE_H
#pragma once
#include "abi.h"
#include <any>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <functional>
#include <string>
#include <type_traits>
#include <typeinfo>
#include <utility>
//**************************************************************************
// MACROS
//**************************************************************************
// types of delegates supported
#define MAME_DELEGATE_TYPE_COMPATIBLE 0
#define MAME_DELEGATE_TYPE_ITANIUM 1
#define MAME_DELEGATE_TYPE_MSVC 2
// select which one we will be using
#if defined(MAME_DELEGATE_FORCE_COMPATIBLE)
#define MAME_DELEGATE_USE_TYPE MAME_DELEGATE_TYPE_COMPATIBLE
#elif defined(__GNUC__)
// 32bit MINGW asks for different convention
#if defined(__MINGW32__) && !defined(__x86_64__) && defined(__i386__)
#define MAME_DELEGATE_USE_TYPE MAME_DELEGATE_TYPE_COMPATIBLE
//#define MAME_DELEGATE_USE_TYPE MAME_DELEGATE_TYPE_ITANIUM
//#define MAME_DELEGATE_DIFFERENT_MEMBER_ABI 1
#elif defined(__clang__) && defined(__i386__) && defined(_WIN32)
#define MAME_DELEGATE_USE_TYPE MAME_DELEGATE_TYPE_COMPATIBLE
#else
#define MAME_DELEGATE_USE_TYPE MAME_DELEGATE_TYPE_ITANIUM
#define MAME_DELEGATE_DIFFERENT_MEMBER_ABI 0
#endif
#elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64))
#define MAME_DELEGATE_DIFFERENT_MEMBER_ABI 0
#define MAME_DELEGATE_USE_TYPE MAME_DELEGATE_TYPE_MSVC
#else
#define MAME_DELEGATE_USE_TYPE MAME_DELEGATE_TYPE_COMPATIBLE
#endif
#if MAME_DELEGATE_USE_TYPE == MAME_DELEGATE_TYPE_COMPATIBLE
#define MAME_DELEGATE_DIFFERENT_MEMBER_ABI 0
#endif
/// \brief Base for objects used with late binding
///
/// Default polymorphic class used as base for objects that can be bound
/// to after the target function has already been set.
class delegate_late_bind
{
public:
virtual ~delegate_late_bind() = default;
};
/// \brief Inappropriate late bind object error
///
/// Thrown as an exception if the object supplied for late binding
/// cannot be cast to the target type for the delegate's function.
class binding_type_exception : public std::bad_cast
{
public:
binding_type_exception(std::type_info const &target_type, std::type_info const &actual_type);
virtual char const *what() const noexcept override;
std::type_info const &target_type() const noexcept { return *m_target_type; }
std::type_info const &actual_type() const noexcept { return *m_actual_type; }
private:
std::string m_what;
std::type_info const *m_target_type;
std::type_info const *m_actual_type;
};
namespace util::detail {
//**************************************************************************
// HELPER CLASSES
//**************************************************************************
// generic function type
using delegate_generic_function = void(*)();
// ======================> generic_class
// define a dummy generic class that is just straight single-inheritance
#ifdef _MSC_VER
class delegate_generic_class { };
#else
class delegate_generic_class;
#endif
// ======================> delegate_traits
// delegate_traits is a meta-template that is used to provide a static function pointer
// and member function pointer of the appropriate type and number of parameters
template <typename ClassType, typename ReturnType, typename... Params>
struct delegate_traits
{
using static_func_type = ReturnType (*)(ClassType *, Params...);
using static_ref_func_type = ReturnType (*)(ClassType &, Params...);
using member_func_type = ReturnType (ClassType::*)(Params...);
using const_member_func_type = ReturnType (ClassType::*)(Params...) const;
};
/// \brief Maximally compatible member function pointer wrapper
///
/// Instantiates a static member function template on construction as
/// an adaptor thunk to call the supplied member function with the
/// supplied object. Adds one layer of indirection to calls.
///
/// This implementation requires the representation of a null member
/// function pointer to be all zeroes.
class delegate_mfp_compatible
{
public:
// default constructor
delegate_mfp_compatible()
: m_rawdata(s_null_mfp)
, m_realobject(nullptr)
, m_stubfunction(nullptr)
{ }
// copy constructor
delegate_mfp_compatible(const delegate_mfp_compatible &src) = default;
// construct from any member function pointer
template <typename MemberFunctionType, class MemberFunctionClass, typename ReturnType, typename StaticFunctionType>
delegate_mfp_compatible(MemberFunctionType mfp, MemberFunctionClass *, ReturnType *, StaticFunctionType)
: m_rawdata(s_null_mfp)
, m_realobject(nullptr)
, m_stubfunction(make_generic<StaticFunctionType>(&delegate_mfp_compatible::method_stub<MemberFunctionClass, ReturnType>))
{
static_assert(sizeof(mfp) <= sizeof(m_rawdata), "Unsupported member function pointer size");
*reinterpret_cast<MemberFunctionType *>(&m_rawdata) = mfp;
}
// comparison helpers
bool operator==(const delegate_mfp_compatible &rhs) const { return m_rawdata == rhs.m_rawdata; }
bool isnull() const { return m_rawdata == s_null_mfp; }
// getters
delegate_generic_class *real_object(delegate_generic_class *original) const
{
return m_realobject;
}
// binding helpers
template <typename FunctionType>
void update_after_bind(FunctionType &funcptr, delegate_generic_class *&object);
template <typename FunctionType>
void update_after_copy(FunctionType &funcptr, delegate_generic_class *&object);
private:
// helper stubs for calling encased member function pointers
template <class FunctionClass, typename ReturnType, typename... Params>
static ReturnType method_stub(delegate_generic_class *object, Params ... args);
// helper to convert a function of a given type to a generic function, forcing template
// instantiation to match the source type
template <typename SourceType>
static delegate_generic_function make_generic(SourceType funcptr)
{
return reinterpret_cast<delegate_generic_function>(funcptr);
}
// FIXME: not properly aligned for storing pointers
struct raw_mfp_data
{
#if defined(__INTEL_COMPILER) && defined(_M_X64) // needed for "Intel(R) C++ Intel(R) 64 Compiler XE for applications running on Intel(R) 64, Version 14.0.2.176 Build 20140130" at least
int data[((sizeof(void *) + 4 * sizeof(int)) + (sizeof(int) - 1)) / sizeof(int)];
#else // all other cases - for MSVC maximum size is one pointer, plus 3 ints; all other implementations seem to be smaller
int data[((sizeof(void *) + 3 * sizeof(int)) + (sizeof(int) - 1)) / sizeof(int)];
#endif
bool operator==(const raw_mfp_data &rhs) const { return !std::memcmp(data, rhs.data, sizeof(data)); }
};
// internal state
raw_mfp_data m_rawdata; // raw buffer to hold the copy of the function pointer
delegate_generic_class * m_realobject; // pointer to the object used for calling
delegate_generic_function m_stubfunction; // pointer to our matching stub function
static const raw_mfp_data s_null_mfp; // nullptr mfp
};
template <typename FunctionType>
void delegate_mfp_compatible::update_after_bind(FunctionType &funcptr, delegate_generic_class *&object)
{
m_realobject = object;
object = reinterpret_cast<delegate_generic_class *>(this);
funcptr = reinterpret_cast<FunctionType>(m_stubfunction);
}
template <typename FunctionType>
void delegate_mfp_compatible::update_after_copy(FunctionType &funcptr, delegate_generic_class *&object)
{
assert(reinterpret_cast<FunctionType>(m_stubfunction) == funcptr);
object = reinterpret_cast<delegate_generic_class *>(this);
}
template <class FunctionClass, typename ReturnType, typename... Params>
ReturnType delegate_mfp_compatible::method_stub(delegate_generic_class *object, Params ... args)
{
using mfptype = ReturnType(FunctionClass::*)(Params...);
delegate_mfp_compatible &_this = *reinterpret_cast<delegate_mfp_compatible *>(object);
mfptype &mfp = *reinterpret_cast<mfptype *>(&_this.m_rawdata);
return (reinterpret_cast<FunctionClass *>(_this.m_realobject)->*mfp)(std::forward<Params>(args)...);
}
/// \brief Itanium C++ ABI member function pointer wrapper
///
/// Supports the two most popular pointer to member function
/// implementations described in the Itanium C++ ABI. Both of these
/// consist of a pointer followed by a ptrdiff_t.
///
/// The first variant is used when member the least significant bit of a
/// member function pointer need never be set and vtable entry offsets
/// are guaranteed to be even numbers of bytes. If the pointer is even,
/// it is a conventional function pointer to the member function. If
/// the pointer is odd, it is a byte offset into the vtable plus one.
/// The ptrdiff_t is a byte offset to add to the this pointer. A null
/// member function pointer is represented by setting the pointer to a
/// null pointer.
///
/// The second variant is used when the least significant bit of a
/// pointer to a member function may need to be set or it may not be
/// possible to distinguish between a vtable offset and a null pointer.
/// (This is the case for ARM where the least significant bit of a
/// pointer to a function is set if the function starts in Thumb mode.)
/// If the least significant bit of the ptrdiff_t is clear, the pointer
/// is a conventional function pointer to the member function. If the
/// least significant bit of the ptrdiff_t is set, the pointer is a byte
/// offset into the vtable. The ptrdiff_t must be shifted right one bit
/// position to make a byte offset to add to the this pointer. A null
/// member function pointer is represented by setting the pointer to a
/// null pointer and clearing the least significant bit of the
/// ptrdiff_t.
class delegate_mfp_itanium
{
public:
// default constructor
delegate_mfp_itanium() = default;
// copy constructor
delegate_mfp_itanium(const delegate_mfp_itanium &src) = default;
// construct from any member function pointer
template <typename MemberFunctionType, class MemberFunctionClass, typename ReturnType, typename StaticFunctionType>
delegate_mfp_itanium(MemberFunctionType mfp, MemberFunctionClass *, ReturnType *, StaticFunctionType)
{
static_assert(sizeof(mfp) == sizeof(*this), "Unsupported member function pointer size");
*reinterpret_cast<MemberFunctionType *>(this) = mfp;
}
// comparison helpers
bool operator==(const delegate_mfp_itanium &rhs) const
{
return (isnull() && rhs.isnull()) || ((m_function == rhs.m_function) && (m_this_delta == rhs.m_this_delta));
}
bool isnull() const
{
if (MAME_ABI_CXX_ITANIUM_MFP_TYPE == MAME_ABI_CXX_ITANIUM_MFP_ARM)
return !reinterpret_cast<void (*)()>(m_function) && !(m_this_delta & 1);
else
return !reinterpret_cast<void (*)()>(m_function);
}
// getters
static delegate_generic_class *real_object(delegate_generic_class *original)
{
return original;
}
// binding helpers
template <typename FunctionType>
void update_after_bind(FunctionType &funcptr, delegate_generic_class *&object)
{
funcptr = reinterpret_cast<FunctionType>(convert_to_generic(object));
}
template <typename FunctionType>
void update_after_copy(FunctionType &funcptr, delegate_generic_class *&object)
{
}
private:
// extract the generic function and adjust the object pointer
delegate_generic_function convert_to_generic(delegate_generic_class *&object) const;
// actual state
uintptr_t m_function = reinterpret_cast<uintptr_t>(static_cast<void (*)()>(nullptr)); // function pointer or vtable offset
ptrdiff_t m_this_delta = 0; // delta to apply to the 'this' pointer
};
/// \brief MSVC member function pointer wrapper
///
/// MSVC uses space optimisation. A member function pointer is a
/// conventional function pointer followed by zero to three int values,
/// depending on whether the class has single, multiple, virtual or
/// unknown inheritance of base classes. The function pointer is always
/// a conventional function pointer (a thunk is used to call virtual
/// member functions through the vtable).
///
/// If present, the first int value is a byte offset to add to the this
/// pointer before calling the function.
///
/// For the virtual inheritance case, the offset to the vtable pointer
/// from the location the this pointer points to must be known by the
/// compiler when the member function pointer is called. The second int
/// value is a byte offset into the vtable to an int value containing an
/// additional byte offset to add to the this pointer.
///
/// For the unknown inheritance case, the second int value is a byte
/// offset add to the this pointer to obtain a pointer to the vtable
/// pointer, or undefined if not required. If the third int value is
/// not zero, it is a byte offset into the vtable to an int value
/// containing an additional byte offset to add to the this pointer.
///
/// It is not possible to support the virtual inheritance case without
/// some way of obtaining the offset to the vtable pointer.
class delegate_mfp_msvc
{
struct single_base_equiv { delegate_generic_function fptr; };
struct multi_base_equiv { delegate_generic_function fptr; int thisdisp; };
struct unknown_base_equiv { delegate_generic_function fptr; int thisdisp, vptrdisp, vtdisp; };
public:
// default constructor
delegate_mfp_msvc() = default;
// copy constructor
delegate_mfp_msvc(const delegate_mfp_msvc &src) = default;
// construct from any member function pointer
template <typename MemberFunctionType, class MemberFunctionClass, typename ReturnType, typename StaticFunctionType>
delegate_mfp_msvc(MemberFunctionType mfp, MemberFunctionClass *, ReturnType *, StaticFunctionType)
{
// FIXME: this doesn't actually catch the unsupported virtual inheritance case on 64-bit targets
// alignment of the pointer means sizeof gives the same value for multiple inheritance and virtual inheritance cases
static_assert(
(sizeof(mfp) == sizeof(single_base_equiv)) || (sizeof(mfp) == sizeof(multi_base_equiv)) || (sizeof(mfp) == sizeof(unknown_base_equiv)),
"Unsupported member function pointer size");
static_assert(sizeof(mfp) <= sizeof(*this), "Member function pointer is too large to support");
*reinterpret_cast<MemberFunctionType *>(this) = mfp;
m_size = sizeof(mfp);
}
// comparison helpers
bool operator==(const delegate_mfp_msvc &rhs) const
{
if (m_function != rhs.m_function)
{
return false;
}
else if (sizeof(single_base_equiv) == m_size)
{
return (sizeof(single_base_equiv) == rhs.m_size) || (!rhs.m_this_delta && ((sizeof(multi_base_equiv) == rhs.m_size) || !rhs.m_vt_index));
}
else if (sizeof(multi_base_equiv) == m_size)
{
if (sizeof(unknown_base_equiv) == rhs.m_size)
return (m_this_delta == rhs.m_this_delta) && !rhs.m_vt_index;
else
return (sizeof(single_base_equiv) == rhs.m_size) ? !m_this_delta : (m_this_delta == rhs.m_this_delta);
}
else if (sizeof(unknown_base_equiv) == rhs.m_size)
{
return (m_this_delta == rhs.m_this_delta) && (m_vt_index == rhs.m_vt_index) && (!m_vt_index || (m_vptr_offs == rhs.m_vptr_offs));
}
else
{
return !m_vt_index && ((sizeof(multi_base_equiv) == rhs.m_size) ? (m_this_delta == rhs.m_this_delta) : !m_this_delta);
}
}
bool isnull() const
{
return !reinterpret_cast<void (*)()>(m_function);
}
// getters
static delegate_generic_class *real_object(delegate_generic_class *original) { return original; }
// binding helpers
template <typename FunctionType>
void update_after_bind(FunctionType &funcptr, delegate_generic_class *&object)
{
funcptr = reinterpret_cast<FunctionType>(adjust_this_pointer(object));
}
template <typename FunctionType>
void update_after_copy(FunctionType &funcptr, delegate_generic_class *&object)
{
}
private:
// adjust the object pointer and bypass thunks
delegate_generic_function adjust_this_pointer(delegate_generic_class *&object) const;
// actual state
uintptr_t m_function = 0; // pointer to function or non-virtual thunk for virtual function call
int m_this_delta = 0; // delta to apply to the 'this' pointer for multiple inheritance
int m_vptr_offs = 0; // offset to apply to this pointer to obtain pointer to vptr
int m_vt_index = 0; // offset into vtable to additional delta to apply to the 'this' pointer
unsigned m_size = 0; // overall size of the pointer to member function representation
};
#if MAME_DELEGATE_USE_TYPE == MAME_DELEGATE_TYPE_COMPATIBLE
template <typename ReturnType>
struct delegate_mfp { using type = delegate_mfp_compatible; };
#elif MAME_DELEGATE_USE_TYPE == MAME_DELEGATE_TYPE_ITANIUM
template <typename ReturnType>
struct delegate_mfp { using type = delegate_mfp_itanium; };
#elif MAME_DELEGATE_USE_TYPE == MAME_DELEGATE_TYPE_MSVC
/// \brief Determine whether a type is returned conventionally
///
/// Under the MSVC C++ ABI with the Microsoft calling convention for
/// x86-64 or AArch64, the calling convention for member functions is
/// not quite the same as a free function with the "this" pointer as the
/// first parameter.
///
/// Conventionally, structure and union values can be returned in
/// registers if they are small enough and are aggregates (trivially
/// constructible, destructible, copyable and assignable). On x86-64,
/// if the value cannot be returned in registers, the pointer to the
/// area for the return value is conventionally passed in RCX and
/// explicit parameters are shifted by one position. On AArch64, if the
/// value cannot be returned in registers, the pointer to the area for
/// the return value is passed in X8 (explicit parameters do not need to
/// be shifted).
///
/// For member functions, structure and union types are never returned
/// in registers, and the pointer to the area for the return value is
/// passed differently for structures and unions. When a structure or
/// union is to be returned, a pointer to the area for the return value
/// is effectively passed as a second implicit parameter. On x86-64,
/// the "this" pointer is passed in RCX and the pointer to the area for
/// the return value is passed in RDX; on AArch64, the "this" pointer is
/// passed in X0 and the pointer to the area for the return value is
/// passed in X1. Explicit parameters are shifted an additional
/// position to allow for the second implicit parameter.
///
/// Note that pointer types are returned conventionally from member
/// functions even when they're too large to return in registers (e.g. a
/// pointer to a function member of a class with unknown inheritance).
///
/// Because of this, we may need to use the #delegate_mfp_compatible
/// class to generate adaptor thunks depending on the return type. This
/// trait doesn't need to reliably be true for types that are returned
/// conventionally from member functions; it only needs to reliably be
/// false for types that aren't. Incorrectly yielding true will result
/// in incorrect behaviour while incorrectly yielding false will just
/// cause increased overhead (both compile-time and run-time).
template <typename ReturnType>
using delegate_mfp_conventional_return = std::bool_constant<
std::is_void_v<ReturnType> ||
std::is_scalar_v<ReturnType> ||
std::is_reference_v<ReturnType> >;
template <typename ReturnType, typename Enable = void>
struct delegate_mfp;
template <typename ReturnType>
struct delegate_mfp<ReturnType, std::enable_if_t<delegate_mfp_conventional_return<ReturnType>::value> > { using type = delegate_mfp_msvc; };
template <typename ReturnType>
struct delegate_mfp<ReturnType, std::enable_if_t<!delegate_mfp_conventional_return<ReturnType>::value> > { using type = delegate_mfp_compatible; };
#endif
template <typename ReturnType> using delegate_mfp_t = typename delegate_mfp<ReturnType>::type;
/// \brief Helper class for generating late bind functions
///
/// Members of this class don't depend on the delegate's signature.
/// Keeping them here reduces the number of template instantiations as
/// you'll only need one late bind helper for each class used for late
/// binding, not for each class for each delegate signature.
template <class LateBindBase>
class delegate_late_bind_helper
{
public:
// make it default constructible and copyable
delegate_late_bind_helper() = default;
delegate_late_bind_helper(delegate_late_bind_helper const &) = default;
delegate_late_bind_helper(delegate_late_bind_helper &&) = default;
delegate_late_bind_helper &operator=(delegate_late_bind_helper const &) = default;
delegate_late_bind_helper &operator=(delegate_late_bind_helper &&) = default;
template <class FunctionClass>
delegate_late_bind_helper(FunctionClass *)
: m_latebinder(&delegate_late_bind_helper::late_bind_helper<FunctionClass>)
{
}
delegate_generic_class *operator()(LateBindBase &object) { return m_latebinder(object); }
explicit operator bool() const noexcept { return bool(m_latebinder); }
private:
using late_bind_func = delegate_generic_class*(*)(LateBindBase &object);
template <class FunctionClass> static delegate_generic_class *late_bind_helper(LateBindBase &object);
late_bind_func m_latebinder = nullptr;
};
template <class LateBindBase>
template <class FunctionClass>
delegate_generic_class *delegate_late_bind_helper<LateBindBase>::late_bind_helper(LateBindBase &object)
{
FunctionClass *result = dynamic_cast<FunctionClass *>(&object);
if (result)
return reinterpret_cast<delegate_generic_class *>(result);
throw binding_type_exception(typeid(FunctionClass), typeid(object));
}
//**************************************************************************
// COMMON DELEGATE BASE CLASS
//**************************************************************************
template <class LateBindBase, typename ReturnType, typename... Params>
class delegate_base
{
public:
// define our traits
template <class FunctionClass> using traits = delegate_traits<FunctionClass, ReturnType, Params...>;
using generic_static_func = typename traits<delegate_generic_class>::static_func_type;
typedef MAME_ABI_CXX_MEMBER_CALL generic_static_func generic_member_func;
// generic constructor
delegate_base() = default;
// copy constructor
delegate_base(const delegate_base &src)
: m_function(src.m_function)
, m_object(src.m_object)
, m_latebinder(src.m_latebinder)
, m_raw_function(src.m_raw_function)
, m_raw_mfp(src.m_raw_mfp)
{
if (src.object() && is_mfp())
m_raw_mfp.update_after_copy(m_function, m_object);
}
// copy constructor with late bind
delegate_base(const delegate_base &src, LateBindBase &object)
: m_function(src.m_function)
, m_latebinder(src.m_latebinder)
, m_raw_function(src.m_raw_function)
, m_raw_mfp(src.m_raw_mfp)
{
late_bind(object);
}
// construct from member function with object pointer
template <class FunctionClass>
delegate_base(typename traits<FunctionClass>::member_func_type funcptr, FunctionClass *object)
: m_latebinder(object)
, m_raw_mfp(funcptr, object, static_cast<ReturnType *>(nullptr), static_cast<generic_static_func>(nullptr))
{
bind(object);
}
// construct from const member function with object pointer
template <class FunctionClass>
delegate_base(typename traits<FunctionClass>::const_member_func_type funcptr, FunctionClass *object)
: m_latebinder(object)
, m_raw_mfp(funcptr, object, static_cast<ReturnType *>(nullptr), static_cast<generic_static_func>(nullptr))
{
bind(object);
}
// construct from static reference function with object reference
template <class FunctionClass>
delegate_base(typename traits<FunctionClass>::static_ref_func_type funcptr, FunctionClass *object)
: m_function(reinterpret_cast<generic_static_func>(funcptr))
, m_latebinder(object)
, m_raw_function(reinterpret_cast<generic_static_func>(funcptr))
{
bind(object);
}
// copy operator
delegate_base &operator=(const delegate_base &src)
{
if (this != &src)
{
m_function = src.m_function;
m_object = src.m_object;
m_latebinder = src.m_latebinder;
m_raw_function = src.m_raw_function;
m_raw_mfp = src.m_raw_mfp;
if (src.object() && is_mfp())
m_raw_mfp.update_after_copy(m_function, m_object);
}
return *this;
}
// comparison helper
bool operator==(const delegate_base &rhs) const
{
return (m_raw_function == rhs.m_raw_function) && (object() == rhs.object()) && (m_raw_mfp == rhs.m_raw_mfp);
}
// call the function
ReturnType operator()(Params... args) const
{
if ((MAME_DELEGATE_DIFFERENT_MEMBER_ABI) && is_mfp())
return (*reinterpret_cast<generic_member_func>(m_function))(m_object, std::forward<Params>(args)...);
else
return (*m_function)(m_object, std::forward<Params>(args)...);
}
// getters
bool has_object() const { return object() != nullptr; }
bool isnull() const { return !m_raw_function && m_raw_mfp.isnull(); }
bool is_mfp() const { return !m_raw_mfp.isnull(); }
// late binding
void late_bind(LateBindBase &object)
{
if (m_latebinder)
bind(m_latebinder(object));
}
protected:
// return the actual object (not the one we use for calling)
delegate_generic_class *object() const { return is_mfp() ? m_raw_mfp.real_object(m_object) : m_object; }
// bind the actual object
template <typename FunctionClass>
void bind(FunctionClass *object)
{
m_object = reinterpret_cast<delegate_generic_class *>(object);
// if we're wrapping a member function pointer, handle special stuff
if (m_object && is_mfp())
m_raw_mfp.update_after_bind(m_function, m_object);
}
// internal state
generic_static_func m_function = nullptr; // resolved static function pointer
delegate_generic_class * m_object = nullptr; // resolved object to the post-cast object
delegate_late_bind_helper<LateBindBase> m_latebinder; // late binding helper
generic_static_func m_raw_function = nullptr; // raw static function pointer
delegate_mfp_t<ReturnType> m_raw_mfp; // raw member function pointer
};
} // namespace util::detail
//**************************************************************************
// NATURAL SYNTAX
//**************************************************************************
// declare the base template
template <typename Signature, class LateBindBase = delegate_late_bind> class delegate;
template <class LateBindBase, typename ReturnType, typename... Params>
class delegate<ReturnType (Params...), LateBindBase> : public util::detail::delegate_base<LateBindBase, ReturnType, Params...>
{
private:
using basetype = util::detail::delegate_base<LateBindBase, ReturnType, Params...>;
using functoid_setter = void (*)(delegate &);
template <typename T> struct functoid_type_unwrap { using type = std::remove_reference_t<T>; };
template <typename T> struct functoid_type_unwrap<std::reference_wrapper<T> > { using type = typename functoid_type_unwrap<T>::type; };
template <typename T> using unwrapped_functoid_t = typename functoid_type_unwrap<std::remove_cv_t<std::remove_reference_t<T> > >::type;
template <typename T> static constexpr bool matching_non_const_call(T &&) { return false; }
template <typename T> static constexpr bool matching_non_const_call(ReturnType (T::*)(Params...)) { return true; }
template <typename T> static constexpr bool matching_const_call(T &&) { return false; }
template <typename T> static constexpr bool matching_const_call(ReturnType (T::*)(Params...) const) { return true; }
template <typename T> static T *unwrap_functoid(T *functoid) { return functoid; }
template <typename T> static T *unwrap_functoid(std::reference_wrapper<T> *functoid) { return &functoid->get(); }
template <typename T>
unwrapped_functoid_t<T> *unwrap_functoid() noexcept
{
return unwrap_functoid(std::any_cast<std::remove_cv_t<std::remove_reference_t<T> > >(&m_functoid));
}
template <typename T>
static functoid_setter make_functoid_setter()
{
if constexpr (matching_non_const_call(&unwrapped_functoid_t<T>::operator()))
{
return
[] (delegate &obj)
{
obj.basetype::operator=(
basetype(
static_cast<ReturnType (unwrapped_functoid_t<T>::*)(Params...)>(&unwrapped_functoid_t<T>::operator()),
obj.unwrap_functoid<T>()));
};
}
else if constexpr (matching_const_call(&unwrapped_functoid_t<T>::operator()))
{
return
[] (delegate &obj)
{
obj.basetype::operator=(
basetype(
static_cast<ReturnType (unwrapped_functoid_t<T>::*)(Params...) const>(&unwrapped_functoid_t<T>::operator()),
obj.unwrap_functoid<T>()));
};
}
else
{
return
[] (delegate &obj)
{
obj.basetype::operator=(
basetype(
[] (unwrapped_functoid_t<T> &f, Params... args) { return ReturnType(f(std::forward<Params>(args)...)); },
obj.unwrap_functoid<T>()));
};
}
}
std::any m_functoid;
functoid_setter m_set_functoid = nullptr;
protected:
template <class FunctionClass> using traits = typename basetype::template traits<FunctionClass>;
template <class FunctionClass> using member_func_type = typename traits<FunctionClass>::member_func_type;
template <class FunctionClass> using const_member_func_type = typename traits<FunctionClass>::const_member_func_type;
template <class FunctionClass> using static_ref_func_type = typename traits<FunctionClass>::static_ref_func_type;
template <typename T> using suitable_functoid = std::is_invocable_r<ReturnType, T, Params...>;
public:
delegate() : basetype() { }
delegate(delegate const &src)
: basetype(src.m_functoid.has_value() ? static_cast<const basetype &>(basetype()) : src)
, m_functoid(src.m_functoid)
, m_set_functoid(src.m_set_functoid)
{
if (m_functoid.has_value())
m_set_functoid(*this);
}
delegate(delegate &src)
: delegate(const_cast<delegate const &>(src))
{
}
delegate(delegate &&src)
: basetype(src.m_functoid.has_value() ? basetype() : std::move(src))
, m_functoid(std::move(src.m_functoid))
, m_set_functoid(std::move(src.m_set_functoid))
{
if (m_functoid.has_value())
m_set_functoid(*this);
}
delegate(delegate const &src, LateBindBase &object)
: basetype(src.m_functoid.has_value() ? basetype() : basetype(src, object))
, m_functoid(src.m_functoid)
, m_set_functoid(src.m_set_functoid)
{
if (m_functoid.has_value())
m_set_functoid(*this);
}
template <class FunctionClass> delegate(member_func_type<FunctionClass> funcptr, FunctionClass *object) : basetype(funcptr, object) { }
template <class FunctionClass> delegate(const_member_func_type<FunctionClass> funcptr, FunctionClass *object) : basetype(funcptr, object) { }
template <class FunctionClass> delegate(static_ref_func_type<FunctionClass> funcptr, FunctionClass *object) : basetype(funcptr, object) { }
template <typename T>
explicit delegate(T &&functoid, std::enable_if_t<suitable_functoid<T>::value, int> = 0)
: basetype()
, m_functoid(std::forward<T>(functoid))
, m_set_functoid(make_functoid_setter<T>())
{
m_set_functoid(*this);
}
delegate &operator=(std::nullptr_t) noexcept
{
reset();
return *this;
}
delegate &operator=(delegate const &src)
{
m_functoid = src.m_functoid;
m_set_functoid = src.m_set_functoid;
if (m_functoid.has_value())
m_set_functoid(*this);
else
basetype::operator=(src);
return *this;
}
delegate &operator=(delegate &&src)
{
m_functoid = std::move(src.m_functoid);
m_set_functoid = std::move(src.m_set_functoid);
if (m_functoid.has_value())
m_set_functoid(*this);
else
basetype::operator=(std::move(src));
return *this;
}
void reset() noexcept
{
basetype::operator=(basetype());
m_functoid.reset();
m_set_functoid = nullptr;
}
};
#endif // MAME_LIB_UTIL_DELEGATE_H

View File

@ -1,76 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************
endianness.h
Endianness types and utility functions.
***************************************************************************/
#ifndef MAME_LIB_UTIL_ENDIANNESS_H
#define MAME_LIB_UTIL_ENDIANNESS_H
#pragma once
#include <string_view>
namespace util {
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// constants for expression endianness
enum class endianness
{
little,
big,
#ifdef LSB_FIRST
native = little
#else
native = big
#endif
};
//**************************************************************************
// MACROS AND INLINE FUNCTIONS
//**************************************************************************
constexpr std::string_view endian_to_string_view(endianness e) { using namespace std::literals; return e == endianness::little ? "little"sv : "big"sv; }
// endian-based value: first value is if native endianness is little-endian, second is if native is big-endian
#define NATIVE_ENDIAN_VALUE_LE_BE(leval,beval) ((util::endianness::native == util::endianness::little) ? (leval) : (beval))
// inline functions for accessing bytes and words within larger chunks
// read/write a byte to a 16-bit space
template <typename T> constexpr T BYTE_XOR_BE(T a) { return a ^ NATIVE_ENDIAN_VALUE_LE_BE(1,0); }
template <typename T> constexpr T BYTE_XOR_LE(T a) { return a ^ NATIVE_ENDIAN_VALUE_LE_BE(0,1); }
// read/write a byte to a 32-bit space
template <typename T> constexpr T BYTE4_XOR_BE(T a) { return a ^ NATIVE_ENDIAN_VALUE_LE_BE(3,0); }
template <typename T> constexpr T BYTE4_XOR_LE(T a) { return a ^ NATIVE_ENDIAN_VALUE_LE_BE(0,3); }
// read/write a word to a 32-bit space
template <typename T> constexpr T WORD_XOR_BE(T a) { return a ^ NATIVE_ENDIAN_VALUE_LE_BE(2,0); }
template <typename T> constexpr T WORD_XOR_LE(T a) { return a ^ NATIVE_ENDIAN_VALUE_LE_BE(0,2); }
// read/write a byte to a 64-bit space
template <typename T> constexpr T BYTE8_XOR_BE(T a) { return a ^ NATIVE_ENDIAN_VALUE_LE_BE(7,0); }
template <typename T> constexpr T BYTE8_XOR_LE(T a) { return a ^ NATIVE_ENDIAN_VALUE_LE_BE(0,7); }
// read/write a word to a 64-bit space
template <typename T> constexpr T WORD2_XOR_BE(T a) { return a ^ NATIVE_ENDIAN_VALUE_LE_BE(6,0); }
template <typename T> constexpr T WORD2_XOR_LE(T a) { return a ^ NATIVE_ENDIAN_VALUE_LE_BE(0,6); }
// read/write a dword to a 64-bit space
template <typename T> constexpr T DWORD_XOR_BE(T a) { return a ^ NATIVE_ENDIAN_VALUE_LE_BE(4,0); }
template <typename T> constexpr T DWORD_XOR_LE(T a) { return a ^ NATIVE_ENDIAN_VALUE_LE_BE(0,4); }
} // namespace util
#endif // MAME_LIB_UTIL_ENDIANNESS_H

View File

@ -1,122 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************
hash.h
Function to handle hash functions (checksums)
Based on original idea by Farfetch'd
***************************************************************************/
#ifndef MAME_UTIL_HASH_H
#define MAME_UTIL_HASH_H
#pragma once
#include "hashing.h"
//**************************************************************************
// MACROS
//**************************************************************************
// use these to define compile-time internal-format hash strings
#define CRC(x) "R" #x
#define SHA1(x) "S" #x
#define NO_DUMP "!"
#define BAD_DUMP "^"
namespace util {
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> hash_collection
// a collection of the various supported hashes and flags
class hash_collection
{
public:
// hash types are identified by non-hex alpha values (G-Z)
static constexpr char HASH_CRC = 'R';
static constexpr char HASH_SHA1 = 'S';
// common combinations for requests
static char const *const HASH_TYPES_CRC;
static char const *const HASH_TYPES_CRC_SHA1;
static char const *const HASH_TYPES_ALL;
// flags are identified by punctuation marks
static constexpr char FLAG_NO_DUMP = '!';
static constexpr char FLAG_BAD_DUMP = '^';
// construction/destruction
hash_collection();
hash_collection(std::string_view string);
hash_collection(const hash_collection &src);
~hash_collection();
// operators
hash_collection &operator=(const hash_collection &src);
bool operator==(const hash_collection &rhs) const;
bool operator!=(const hash_collection &rhs) const { return !(*this == rhs); }
// getters
bool flag(char flag) const { return (m_flags.find_first_of(flag) != std::string::npos); }
std::string hash_types() const;
// hash manipulators
void reset();
bool add_from_string(char type, std::string_view string);
bool remove(char type);
// CRC-specific helpers
bool crc(uint32_t &result) const { result = m_crc32; return m_has_crc32; }
void add_crc(uint32_t crc) { m_crc32 = crc; m_has_crc32 = true; }
// SHA1-specific helpers
bool sha1(sha1_t &result) const { result = m_sha1; return m_has_sha1; }
void add_sha1(sha1_t sha1) { m_has_sha1 = true; m_sha1 = sha1; }
// string conversion
std::string internal_string() const;
std::string macro_string() const;
std::string attribute_string() const;
bool from_internal_string(std::string_view string);
// creation
void begin(const char *types = nullptr);
void buffer(const uint8_t *data, uint32_t length);
void end();
void compute(const uint8_t *data, uint32_t length, const char *types = nullptr) { begin(types); buffer(data, length); end(); }
private:
// internal helpers
void copyfrom(const hash_collection &src);
// internal state
std::string m_flags;
bool m_has_crc32;
crc32_t m_crc32;
bool m_has_sha1;
sha1_t m_sha1;
// creators
struct hash_creator
{
bool m_doing_crc32;
crc32_creator m_crc32_creator;
bool m_doing_sha1;
sha1_creator m_sha1_creator;
};
hash_creator * m_creator;
};
} // namespace util
#endif // MAME_UTIL_HASH_H

View File

@ -1,314 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles, Vas Crabb
/***************************************************************************
hashing.h
Hashing helper classes.
***************************************************************************/
#ifndef MAME_UTIL_HASHING_H
#define MAME_UTIL_HASHING_H
#pragma once
#include "md5.h"
#include <array>
#include <cstdint>
#include <cstring>
#include <functional>
#include <string>
#include <string_view>
namespace util {
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> SHA-1
// final digest
struct sha1_t
{
bool operator==(const sha1_t &rhs) const { return memcmp(m_raw, rhs.m_raw, sizeof(m_raw)) == 0; }
bool operator!=(const sha1_t &rhs) const { return memcmp(m_raw, rhs.m_raw, sizeof(m_raw)) != 0; }
operator uint8_t *() { return m_raw; }
bool from_string(std::string_view string);
std::string as_string() const;
uint8_t m_raw[20];
static const sha1_t null;
};
// creation helper
class sha1_creator
{
public:
// construction/destruction
sha1_creator() { reset(); }
// reset
void reset();
// append data
void append(const void *data, uint32_t length);
// finalize and compute the final digest
sha1_t finish();
// static wrapper to just get the digest from a block
static sha1_t simple(const void *data, uint32_t length)
{
sha1_creator creator;
creator.append(data, length);
return creator.finish();
}
protected:
uint64_t m_cnt;
std::array<uint32_t, 5> m_st;
uint32_t m_buf[16];
};
// ======================> MD5
// final digest
struct md5_t
{
bool operator==(const md5_t &rhs) const { return memcmp(m_raw, rhs.m_raw, sizeof(m_raw)) == 0; }
bool operator!=(const md5_t &rhs) const { return memcmp(m_raw, rhs.m_raw, sizeof(m_raw)) != 0; }
operator uint8_t *() { return m_raw; }
bool from_string(std::string_view string);
std::string as_string() const;
uint8_t m_raw[16];
static const md5_t null;
};
// creation helper
class md5_creator
{
public:
// construction/destruction
md5_creator() { reset(); }
// reset
void reset() { MD5Init(&m_context); }
// append data
void append(const void *data, uint32_t length) { MD5Update(&m_context, reinterpret_cast<const unsigned char *>(data), length); }
// finalize and compute the final digest
md5_t finish()
{
md5_t result;
MD5Final(result.m_raw, &m_context);
return result;
}
// static wrapper to just get the digest from a block
static md5_t simple(const void *data, uint32_t length)
{
md5_creator creator;
creator.append(data, length);
return creator.finish();
}
protected:
// internal state
struct MD5Context m_context; // internal context
};
// ======================> CRC-32
// final digest
struct crc32_t
{
crc32_t() { }
constexpr crc32_t(const crc32_t &rhs) = default;
constexpr crc32_t(const uint32_t crc) : m_raw(crc) { }
constexpr bool operator==(const crc32_t &rhs) const { return m_raw == rhs.m_raw; }
constexpr bool operator!=(const crc32_t &rhs) const { return m_raw != rhs.m_raw; }
crc32_t &operator=(const crc32_t &rhs) = default;
crc32_t &operator=(const uint32_t crc) { m_raw = crc; return *this; }
constexpr operator uint32_t() const { return m_raw; }
bool from_string(std::string_view string);
std::string as_string() const;
uint32_t m_raw;
static const crc32_t null;
};
// creation helper
class crc32_creator
{
public:
// construction/destruction
crc32_creator() { reset(); }
// reset
void reset() { m_accum.m_raw = 0; }
// append data
void append(const void *data, uint32_t length);
// finalize and compute the final digest
crc32_t finish() { return m_accum; }
// static wrapper to just get the digest from a block
static crc32_t simple(const void *data, uint32_t length)
{
crc32_creator creator;
creator.append(data, length);
return creator.finish();
}
protected:
// internal state
crc32_t m_accum; // internal accumulator
};
// ======================> CRC-16
// final digest
struct crc16_t
{
crc16_t() { }
constexpr crc16_t(const crc16_t &rhs) = default;
constexpr crc16_t(const uint16_t crc) : m_raw(crc) { }
constexpr bool operator==(const crc16_t &rhs) const { return m_raw == rhs.m_raw; }
constexpr bool operator!=(const crc16_t &rhs) const { return m_raw != rhs.m_raw; }
crc16_t &operator=(const crc16_t &rhs) = default;
crc16_t &operator=(const uint16_t crc) { m_raw = crc; return *this; }
constexpr operator uint16_t() const { return m_raw; }
bool from_string(std::string_view string);
std::string as_string() const;
uint16_t m_raw;
static const crc16_t null;
};
// creation helper
class crc16_creator
{
public:
// construction/destruction
crc16_creator() { reset(); }
// reset
void reset() { m_accum.m_raw = 0xffff; }
// append data
void append(const void *data, uint32_t length);
// finalize and compute the final digest
crc16_t finish() { return m_accum; }
// static wrapper to just get the digest from a block
static crc16_t simple(const void *data, uint32_t length)
{
crc16_creator creator;
creator.append(data, length);
return creator.finish();
}
protected:
// internal state
crc16_t m_accum; // internal accumulator
};
// ======================> SUM-16
// final digest
struct sum16_t
{
sum16_t() { }
constexpr sum16_t(const sum16_t &rhs) = default;
constexpr sum16_t(const uint16_t sum) : m_raw(sum) { }
constexpr bool operator==(const sum16_t &rhs) const { return m_raw == rhs.m_raw; }
constexpr bool operator!=(const sum16_t &rhs) const { return m_raw != rhs.m_raw; }
sum16_t &operator=(const sum16_t &rhs) = default;
sum16_t &operator=(const uint16_t sum) { m_raw = sum; return *this; }
constexpr operator uint16_t() const { return m_raw; }
bool from_string(std::string_view string);
std::string as_string() const;
uint16_t m_raw;
static const sum16_t null;
};
// creation helper
class sum16_creator
{
public:
// construction/destruction
sum16_creator() { reset(); }
// reset
void reset() { m_accum.m_raw = 0; }
// append data
void append(const void *data, uint32_t length);
// finalize and compute the final digest
sum16_t finish() { return m_accum; }
// static wrapper to just get the digest from a block
static sum16_t simple(const void *data, uint32_t length)
{
sum16_creator creator;
creator.append(data, length);
return creator.finish();
}
protected:
// internal state
sum16_t m_accum; // internal accumulator
};
} // namespace util
namespace std {
template <> struct hash<::util::crc32_t>
{
typedef ::util::crc32_t argument_type;
typedef std::size_t result_type;
result_type operator()(argument_type const & s) const { return std::hash<std::uint32_t>()(s); }
};
template <> struct hash<::util::crc16_t>
{
typedef ::util::crc16_t argument_type;
typedef std::size_t result_type;
result_type operator()(argument_type const & s) const { return std::hash<std::uint16_t>()(s); }
};
} // namespace std
#endif // MAME_UTIL_HASHING_H

View File

@ -1,43 +0,0 @@
// license:Public Domain
// copyright-holders:Colin Plumb
/*
* This is the header file for the MD5 message-digest algorithm.
* The algorithm is due to Ron Rivest. This code was
* written by Colin Plumb in 1993, no copyright is claimed.
* This code is in the public domain; do with it what you wish.
*
* Equivalent code is available from RSA Data Security, Inc.
* This code has been tested against that, and is equivalent,
* except that you don't need to include two pages of legalese
* with every copy.
*
* To compute the message digest of a chunk of bytes, declare an
* MD5Context structure, pass it to MD5Init, call MD5Update as
* needed on buffers full of bytes, and then call MD5Final, which
* will fill a supplied 16-byte array with the digest.
*
* Changed so as no longer to depend on Colin Plumb's `usual.h'
* header definitions; now uses stuff from dpkg's config.h
* - Ian Jackson <ijackson@nyx.cs.du.edu>.
* Still in the public domain.
*/
#ifndef MD5_H
#define MD5_H
typedef unsigned int UWORD32;
#define md5byte unsigned char
struct MD5Context {
UWORD32 buf[4];
UWORD32 bytes[2];
UWORD32 in[16];
};
void MD5Init(struct MD5Context *context);
void MD5Update(struct MD5Context *context, md5byte const *buf, unsigned len);
void MD5Final(unsigned char digest[16], struct MD5Context *context);
void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]);
#endif /* !MD5_H */

View File

@ -1,287 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/******************************************************************************
palette.h
Core palette routines.
***************************************************************************/
#ifndef MAME_UTIL_PALETTE_H
#define MAME_UTIL_PALETTE_H
#pragma once
#include <cstdint>
#include <vector>
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// forward definitions
class palette_t;
// an rgb15_t is a single combined 15-bit R,G,B value
typedef uint16_t rgb15_t;
// ======================> rgb_t
// an rgb_t is a single combined R,G,B (and optionally alpha) value
class rgb_t
{
public:
// construction/destruction
constexpr rgb_t() : m_data(0) { }
constexpr rgb_t(uint32_t data) : m_data(data) { }
constexpr rgb_t(uint8_t r, uint8_t g, uint8_t b) : m_data((255 << 24) | (r << 16) | (g << 8) | b) { }
constexpr rgb_t(uint8_t a, uint8_t r, uint8_t g, uint8_t b) : m_data((a << 24) | (r << 16) | (g << 8) | b) { }
// getters
constexpr uint8_t a() const { return m_data >> 24; }
constexpr uint8_t r() const { return m_data >> 16; }
constexpr uint8_t g() const { return m_data >> 8; }
constexpr uint8_t b() const { return m_data >> 0; }
constexpr rgb15_t as_rgb15() const { return ((r() >> 3) << 10) | ((g() >> 3) << 5) | ((b() >> 3) << 0); }
constexpr uint8_t brightness() const { return (r() * 222 + g() * 707 + b() * 71) / 1000; }
constexpr uint32_t const *ptr() const { return &m_data; }
void expand_rgb(uint8_t &r, uint8_t &g, uint8_t &b) const { r = m_data >> 16; g = m_data >> 8; b = m_data >> 0; }
void expand_rgb(int &r, int &g, int &b) const { r = (m_data >> 16) & 0xff; g = (m_data >> 8) & 0xff; b = (m_data >> 0) & 0xff; }
// setters
rgb_t &set_a(uint8_t a) { m_data &= ~0xff000000; m_data |= a << 24; return *this; }
rgb_t &set_r(uint8_t r) { m_data &= ~0x00ff0000; m_data |= r << 16; return *this; }
rgb_t &set_g(uint8_t g) { m_data &= ~0x0000ff00; m_data |= g << 8; return *this; }
rgb_t &set_b(uint8_t b) { m_data &= ~0x000000ff; m_data |= b << 0; return *this; }
// implicit conversion operators
constexpr operator uint32_t() const { return m_data; }
// operations
rgb_t &scale8(uint8_t scale) { m_data = rgb_t(clamphi((a() * scale) >> 8), clamphi((r() * scale) >> 8), clamphi((g() * scale) >> 8), clamphi((b() * scale) >> 8)); return *this; }
// assignment operators
rgb_t &operator=(uint32_t rhs) { m_data = rhs; return *this; }
rgb_t &operator+=(const rgb_t &rhs) { m_data = uint32_t(*this + rhs); return *this; }
rgb_t &operator-=(const rgb_t &rhs) { m_data = uint32_t(*this - rhs); return *this; }
// arithmetic operators
constexpr rgb_t operator+(const rgb_t &rhs) const { return rgb_t(clamphi(a() + rhs.a()), clamphi(r() + rhs.r()), clamphi(g() + rhs.g()), clamphi(b() + rhs.b())); }
constexpr rgb_t operator-(const rgb_t &rhs) const { return rgb_t(clamplo(a() - rhs.a()), clamplo(r() - rhs.r()), clamplo(g() - rhs.g()), clamplo(b() - rhs.b())); }
// static helpers
static constexpr uint8_t clamp(int32_t value) { return (value < 0) ? 0 : (value > 255) ? 255 : value; }
static constexpr uint8_t clamphi(int32_t value) { return (value > 255) ? 255 : value; }
static constexpr uint8_t clamplo(int32_t value) { return (value < 0) ? 0 : value; }
// constant factories
static constexpr rgb_t black() { return rgb_t(0, 0, 0); }
static constexpr rgb_t white() { return rgb_t(255, 255, 255); }
static constexpr rgb_t green() { return rgb_t(0, 255, 0); }
static constexpr rgb_t amber() { return rgb_t(247, 170, 0); }
static constexpr rgb_t transparent() { return rgb_t(0, 0, 0, 0); }
private:
uint32_t m_data;
};
// ======================> palette_client
// a single palette client
class palette_client
{
public:
// construction/destruction
palette_client(palette_t &palette);
~palette_client();
// getters
palette_client *next() const { return m_next; }
palette_t &palette() const { return m_palette; }
const uint32_t *dirty_list(uint32_t &mindirty, uint32_t &maxdirty);
// dirty marking
void mark_dirty(uint32_t index) { m_live->mark_dirty(index); }
private:
// internal object to track dirty states
class dirty_state
{
public:
// construction
dirty_state();
// operations
const uint32_t *dirty_list(uint32_t &mindirty, uint32_t &maxdirty);
void resize(uint32_t colors);
void mark_dirty(uint32_t index);
void reset();
private:
// internal state
std::vector<uint32_t> m_dirty; // bitmap of dirty entries
uint32_t m_mindirty; // minimum dirty entry
uint32_t m_maxdirty; // minimum dirty entry
};
// internal state
palette_t & m_palette; // reference to the palette
palette_client *m_next; // pointer to next client
dirty_state * m_live; // live dirty state
dirty_state * m_previous; // previous dirty state
dirty_state m_dirty[2]; // two dirty states
};
// ======================> palette_t
// a palette object
class palette_t
{
friend class palette_client;
public:
// static constructor: used to ensure same new/delete is used
static palette_t *alloc(uint32_t numcolors, uint32_t numgroups = 1);
// reference counting
void ref() { m_refcount++; }
void deref();
// getters
int num_colors() const { return m_numcolors; }
int num_groups() const { return m_numgroups; }
int max_index() const { return m_numcolors * m_numgroups + 2; }
uint32_t black_entry() const { return m_numcolors * m_numgroups + 0; }
uint32_t white_entry() const { return m_numcolors * m_numgroups + 1; }
// overall adjustments
void set_brightness(float brightness);
void set_contrast(float contrast);
void set_gamma(float gamma);
// entry getters
rgb_t entry_color(uint32_t index) const { return (index < m_numcolors) ? m_entry_color[index] : rgb_t::black(); }
rgb_t entry_adjusted_color(uint32_t index) const { return (index < m_numcolors * m_numgroups) ? m_adjusted_color[index] : rgb_t::black(); }
float entry_contrast(uint32_t index) const { return (index < m_numcolors) ? m_entry_contrast[index] : 1.0f; }
// entry setters
void entry_set_color(uint32_t index, rgb_t rgb);
void entry_set_red_level(uint32_t index, uint8_t level);
void entry_set_green_level(uint32_t index, uint8_t level);
void entry_set_blue_level(uint32_t index, uint8_t level);
void entry_set_contrast(uint32_t index, float contrast);
// entry list getters
const rgb_t *entry_list_raw() const { return &m_entry_color[0]; }
const rgb_t *entry_list_adjusted() const { return &m_adjusted_color[0]; }
const rgb_t *entry_list_adjusted_rgb15() const { return &m_adjusted_rgb15[0]; }
// group adjustments
void group_set_brightness(uint32_t group, float brightness);
void group_set_contrast(uint32_t group, float contrast);
// utilities
void normalize_range(uint32_t start, uint32_t end, int lum_min = 0, int lum_max = 255);
private:
// construction/destruction
palette_t(uint32_t numcolors, uint32_t numgroups = 1);
~palette_t();
// internal helpers
rgb_t adjust_palette_entry(rgb_t entry, float brightness, float contrast, const uint8_t *gamma_map);
void update_adjusted_color(uint32_t group, uint32_t index);
// internal state
uint32_t m_refcount; // reference count on the palette
uint32_t m_numcolors; // number of colors in the palette
uint32_t m_numgroups; // number of groups in the palette
float m_brightness; // overall brightness value
float m_contrast; // overall contrast value
float m_gamma; // overall gamma value
uint8_t m_gamma_map[256]; // gamma map
std::vector<rgb_t> m_entry_color; // array of raw colors
std::vector<float> m_entry_contrast; // contrast value for each entry
std::vector<rgb_t> m_adjusted_color; // array of adjusted colors
std::vector<rgb_t> m_adjusted_rgb15; // array of adjusted colors as RGB15
std::vector<float> m_group_bright; // brightness value for each group
std::vector<float> m_group_contrast; // contrast value for each group
palette_client *m_client_list; // list of clients for this palette
};
//**************************************************************************
// INLINE FUNCTIONS
//**************************************************************************
//-------------------------------------------------
// palexpand - expand a palette value to 8 bits
//-------------------------------------------------
template<int _NumBits>
constexpr uint8_t palexpand(uint8_t bits)
{
if (_NumBits == 1) { return (bits & 1) ? 0xff : 0x00; }
if (_NumBits == 2) { bits &= 3; return (bits << 6) | (bits << 4) | (bits << 2) | bits; }
if (_NumBits == 3) { bits &= 7; return (bits << 5) | (bits << 2) | (bits >> 1); }
if (_NumBits == 4) { bits &= 0xf; return (bits << 4) | bits; }
if (_NumBits == 5) { bits &= 0x1f; return (bits << 3) | (bits >> 2); }
if (_NumBits == 6) { bits &= 0x3f; return (bits << 2) | (bits >> 4); }
if (_NumBits == 7) { bits &= 0x7f; return (bits << 1) | (bits >> 6); }
return bits;
}
//-------------------------------------------------
// palxbit - convert an x-bit value to 8 bits
//-------------------------------------------------
constexpr uint8_t pal1bit(uint8_t bits) { return palexpand<1>(bits); }
constexpr uint8_t pal2bit(uint8_t bits) { return palexpand<2>(bits); }
constexpr uint8_t pal3bit(uint8_t bits) { return palexpand<3>(bits); }
constexpr uint8_t pal4bit(uint8_t bits) { return palexpand<4>(bits); }
constexpr uint8_t pal5bit(uint8_t bits) { return palexpand<5>(bits); }
constexpr uint8_t pal6bit(uint8_t bits) { return palexpand<6>(bits); }
constexpr uint8_t pal7bit(uint8_t bits) { return palexpand<7>(bits); }
//-------------------------------------------------
// rgbexpand - expand a 32-bit raw data to 8-bit
// RGB
//-------------------------------------------------
template<int _RBits, int _GBits, int _BBits>
constexpr rgb_t rgbexpand(uint32_t data, uint8_t rshift, uint8_t gshift, uint8_t bshift)
{
return rgb_t(palexpand<_RBits>(data >> rshift), palexpand<_GBits>(data >> gshift), palexpand<_BBits>(data >> bshift));
}
template<int _ABits, int _RBits, int _GBits, int _BBits>
constexpr rgb_t argbexpand(uint32_t data, uint8_t ashift, uint8_t rshift, uint8_t gshift, uint8_t bshift)
{
return rgb_t(palexpand<_ABits>(data >> ashift), palexpand<_RBits>(data >> rshift), palexpand<_GBits>(data >> gshift), palexpand<_BBits>(data >> bshift));
}
//-------------------------------------------------
// palxxx - create an x-x-x color by extracting
// bits from a uint32_t
//-------------------------------------------------
constexpr rgb_t pal332(uint32_t data, uint8_t rshift, uint8_t gshift, uint8_t bshift) { return rgbexpand<3,3,2>(data, rshift, gshift, bshift); }
constexpr rgb_t pal444(uint32_t data, uint8_t rshift, uint8_t gshift, uint8_t bshift) { return rgbexpand<4,4,4>(data, rshift, gshift, bshift); }
constexpr rgb_t pal555(uint32_t data, uint8_t rshift, uint8_t gshift, uint8_t bshift) { return rgbexpand<5,5,5>(data, rshift, gshift, bshift); }
constexpr rgb_t pal565(uint32_t data, uint8_t rshift, uint8_t gshift, uint8_t bshift) { return rgbexpand<5,6,5>(data, rshift, gshift, bshift); }
constexpr rgb_t pal888(uint32_t data, uint8_t rshift, uint8_t gshift, uint8_t bshift) { return rgbexpand<8,8,8>(data, rshift, gshift, bshift); }
#endif // MAME_UTIL_PALETTE_H

View File

@ -1,661 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/***************************************************************************
strformat.h
type-safe printf substitutes
***************************************************************************/
#include "strformat.h"
#include <iostream>
#include <sstream>
namespace util {
namespace detail {
template class format_chars<char>;
template class format_chars<wchar_t>;
template void format_flags::apply(std::ostream &) const;
template void format_flags::apply(std::wostream &) const;
template void format_flags::apply(std::iostream &) const;
template void format_flags::apply(std::wiostream &) const;
template void format_flags::apply(std::ostringstream &) const;
template void format_flags::apply(std::wostringstream &) const;
template void format_flags::apply(std::stringstream &) const;
template void format_flags::apply(std::wstringstream &) const;
template void format_flags::apply(ovectorstream &) const;
template void format_flags::apply(wovectorstream &) const;
template void format_flags::apply(vectorstream &) const;
template void format_flags::apply(wvectorstream &) const;
template class format_argument<std::ostream>;
template void format_argument<std::ostream>::static_output<char>(std::ostream &, format_flags const &, void const *);
template void format_argument<std::ostream>::static_output<signed char>(std::ostream &, format_flags const &, void const *);
template void format_argument<std::ostream>::static_output<unsigned char>(std::ostream &, format_flags const &, void const *);
template void format_argument<std::ostream>::static_output<short>(std::ostream &, format_flags const &, void const *);
template void format_argument<std::ostream>::static_output<unsigned short>(std::ostream &, format_flags const &, void const *);
template void format_argument<std::ostream>::static_output<int>(std::ostream &, format_flags const &, void const *);
template void format_argument<std::ostream>::static_output<unsigned int>(std::ostream &, format_flags const &, void const *);
template void format_argument<std::ostream>::static_output<long>(std::ostream &, format_flags const &, void const *);
template void format_argument<std::ostream>::static_output<unsigned long>(std::ostream &, format_flags const &, void const *);
template void format_argument<std::ostream>::static_output<long long>(std::ostream &, format_flags const &, void const *);
template void format_argument<std::ostream>::static_output<unsigned long long>(std::ostream &, format_flags const &, void const *);
template void format_argument<std::ostream>::static_output<char *>(std::ostream &, format_flags const &, void const *);
template void format_argument<std::ostream>::static_output<char const *>(std::ostream &, format_flags const &, void const *);
template void format_argument<std::ostream>::static_output<std::string>(std::ostream &, format_flags const &, void const *);
template void format_argument<std::ostream>::static_output<std::string_view>(std::ostream &, format_flags const &, void const *);
template bool format_argument<std::ostream>::static_make_integer<char>(void const *, int &);
template bool format_argument<std::ostream>::static_make_integer<signed char>(void const *, int &);
template bool format_argument<std::ostream>::static_make_integer<unsigned char>(void const *, int &);
template bool format_argument<std::ostream>::static_make_integer<short>(void const *, int &);
template bool format_argument<std::ostream>::static_make_integer<unsigned short>(void const *, int &);
template bool format_argument<std::ostream>::static_make_integer<int>(void const *, int &);
template bool format_argument<std::ostream>::static_make_integer<unsigned int>(void const *, int &);
template bool format_argument<std::ostream>::static_make_integer<long>(void const *, int &);
template bool format_argument<std::ostream>::static_make_integer<unsigned long>(void const *, int &);
template bool format_argument<std::ostream>::static_make_integer<long long>(void const *, int &);
template bool format_argument<std::ostream>::static_make_integer<unsigned long long>(void const *, int &);
template bool format_argument<std::ostream>::static_make_integer<char *>(void const *, int &);
template bool format_argument<std::ostream>::static_make_integer<char const *>(void const *, int &);
template bool format_argument<std::ostream>::static_make_integer<std::string>(void const *, int &);
template bool format_argument<std::ostream>::static_make_integer<std::string_view>(void const *, int &);
template void format_argument<std::ostream>::static_store_integer<char>(void const *, std::streamoff);
template void format_argument<std::ostream>::static_store_integer<signed char>(void const *, std::streamoff);
template void format_argument<std::ostream>::static_store_integer<unsigned char>(void const *, std::streamoff);
template void format_argument<std::ostream>::static_store_integer<short>(void const *, std::streamoff);
template void format_argument<std::ostream>::static_store_integer<unsigned short>(void const *, std::streamoff);
template void format_argument<std::ostream>::static_store_integer<int>(void const *, std::streamoff);
template void format_argument<std::ostream>::static_store_integer<unsigned int>(void const *, std::streamoff);
template void format_argument<std::ostream>::static_store_integer<long>(void const *, std::streamoff);
template void format_argument<std::ostream>::static_store_integer<unsigned long>(void const *, std::streamoff);
template void format_argument<std::ostream>::static_store_integer<long long>(void const *, std::streamoff);
template void format_argument<std::ostream>::static_store_integer<unsigned long long>(void const *, std::streamoff);
template void format_argument<std::ostream>::static_store_integer<char *>(void const *, std::streamoff);
template void format_argument<std::ostream>::static_store_integer<char const *>(void const *, std::streamoff);
template void format_argument<std::ostream>::static_store_integer<std::string>(void const *, std::streamoff);
template void format_argument<std::ostream>::static_store_integer<std::string_view>(void const *, std::streamoff);
template class format_argument<std::wostream>;
template void format_argument<std::wostream>::static_output<char>(std::wostream &, format_flags const &, void const *);
template void format_argument<std::wostream>::static_output<signed char>(std::wostream &, format_flags const &, void const *);
template void format_argument<std::wostream>::static_output<unsigned char>(std::wostream &, format_flags const &, void const *);
template void format_argument<std::wostream>::static_output<wchar_t>(std::wostream &, format_flags const &, void const *);
template void format_argument<std::wostream>::static_output<short>(std::wostream &, format_flags const &, void const *);
template void format_argument<std::wostream>::static_output<unsigned short>(std::wostream &, format_flags const &, void const *);
template void format_argument<std::wostream>::static_output<int>(std::wostream &, format_flags const &, void const *);
template void format_argument<std::wostream>::static_output<unsigned int>(std::wostream &, format_flags const &, void const *);
template void format_argument<std::wostream>::static_output<long>(std::wostream &, format_flags const &, void const *);
template void format_argument<std::wostream>::static_output<unsigned long>(std::wostream &, format_flags const &, void const *);
template void format_argument<std::wostream>::static_output<long long>(std::wostream &, format_flags const &, void const *);
template void format_argument<std::wostream>::static_output<unsigned long long>(std::wostream &, format_flags const &, void const *);
template void format_argument<std::wostream>::static_output<wchar_t *>(std::wostream &, format_flags const &, void const *);
template void format_argument<std::wostream>::static_output<wchar_t const *>(std::wostream &, format_flags const &, void const *);
template void format_argument<std::wostream>::static_output<std::wstring>(std::wostream &, format_flags const &, void const *);
template void format_argument<std::wostream>::static_output<std::wstring_view>(std::wostream &, format_flags const &, void const *);
template bool format_argument<std::wostream>::static_make_integer<char>(void const *, int &);
template bool format_argument<std::wostream>::static_make_integer<signed char>(void const *, int &);
template bool format_argument<std::wostream>::static_make_integer<unsigned char>(void const *, int &);
template bool format_argument<std::wostream>::static_make_integer<wchar_t>(void const *, int &);
template bool format_argument<std::wostream>::static_make_integer<short>(void const *, int &);
template bool format_argument<std::wostream>::static_make_integer<unsigned short>(void const *, int &);
template bool format_argument<std::wostream>::static_make_integer<int>(void const *, int &);
template bool format_argument<std::wostream>::static_make_integer<unsigned int>(void const *, int &);
template bool format_argument<std::wostream>::static_make_integer<long>(void const *, int &);
template bool format_argument<std::wostream>::static_make_integer<unsigned long>(void const *, int &);
template bool format_argument<std::wostream>::static_make_integer<long long>(void const *, int &);
template bool format_argument<std::wostream>::static_make_integer<unsigned long long>(void const *, int &);
template bool format_argument<std::wostream>::static_make_integer<wchar_t *>(void const *, int &);
template bool format_argument<std::wostream>::static_make_integer<wchar_t const *>(void const *, int &);
template bool format_argument<std::wostream>::static_make_integer<std::wstring>(void const *, int &);
template bool format_argument<std::wostream>::static_make_integer<std::wstring_view>(void const *, int &);
template void format_argument<std::wostream>::static_store_integer<char>(void const *, std::streamoff);
template void format_argument<std::wostream>::static_store_integer<signed char>(void const *, std::streamoff);
template void format_argument<std::wostream>::static_store_integer<unsigned char>(void const *, std::streamoff);
template void format_argument<std::wostream>::static_store_integer<wchar_t>(void const *, std::streamoff);
template void format_argument<std::wostream>::static_store_integer<short>(void const *, std::streamoff);
template void format_argument<std::wostream>::static_store_integer<unsigned short>(void const *, std::streamoff);
template void format_argument<std::wostream>::static_store_integer<int>(void const *, std::streamoff);
template void format_argument<std::wostream>::static_store_integer<unsigned int>(void const *, std::streamoff);
template void format_argument<std::wostream>::static_store_integer<long>(void const *, std::streamoff);
template void format_argument<std::wostream>::static_store_integer<unsigned long>(void const *, std::streamoff);
template void format_argument<std::wostream>::static_store_integer<long long>(void const *, std::streamoff);
template void format_argument<std::wostream>::static_store_integer<unsigned long long>(void const *, std::streamoff);
template void format_argument<std::wostream>::static_store_integer<wchar_t *>(void const *, std::streamoff);
template void format_argument<std::wostream>::static_store_integer<wchar_t const *>(void const *, std::streamoff);
template void format_argument<std::wostream>::static_store_integer<std::wstring>(void const *, std::streamoff);
template void format_argument<std::wostream>::static_store_integer<std::wstring_view>(void const *, std::streamoff);
template class format_argument<std::iostream>;
template void format_argument<std::iostream>::static_output<char>(std::iostream &, format_flags const &, void const *);
template void format_argument<std::iostream>::static_output<signed char>(std::iostream &, format_flags const &, void const *);
template void format_argument<std::iostream>::static_output<unsigned char>(std::iostream &, format_flags const &, void const *);
template void format_argument<std::iostream>::static_output<short>(std::iostream &, format_flags const &, void const *);
template void format_argument<std::iostream>::static_output<unsigned short>(std::iostream &, format_flags const &, void const *);
template void format_argument<std::iostream>::static_output<int>(std::iostream &, format_flags const &, void const *);
template void format_argument<std::iostream>::static_output<unsigned int>(std::iostream &, format_flags const &, void const *);
template void format_argument<std::iostream>::static_output<long>(std::iostream &, format_flags const &, void const *);
template void format_argument<std::iostream>::static_output<unsigned long>(std::iostream &, format_flags const &, void const *);
template void format_argument<std::iostream>::static_output<long long>(std::iostream &, format_flags const &, void const *);
template void format_argument<std::iostream>::static_output<unsigned long long>(std::iostream &, format_flags const &, void const *);
template void format_argument<std::iostream>::static_output<char *>(std::iostream &, format_flags const &, void const *);
template void format_argument<std::iostream>::static_output<char const *>(std::iostream &, format_flags const &, void const *);
template void format_argument<std::iostream>::static_output<std::string>(std::iostream &, format_flags const &, void const *);
template void format_argument<std::iostream>::static_output<std::string_view>(std::iostream &, format_flags const &, void const *);
template bool format_argument<std::iostream>::static_make_integer<char>(void const *, int &);
template bool format_argument<std::iostream>::static_make_integer<signed char>(void const *, int &);
template bool format_argument<std::iostream>::static_make_integer<unsigned char>(void const *, int &);
template bool format_argument<std::iostream>::static_make_integer<short>(void const *, int &);
template bool format_argument<std::iostream>::static_make_integer<unsigned short>(void const *, int &);
template bool format_argument<std::iostream>::static_make_integer<int>(void const *, int &);
template bool format_argument<std::iostream>::static_make_integer<unsigned int>(void const *, int &);
template bool format_argument<std::iostream>::static_make_integer<long>(void const *, int &);
template bool format_argument<std::iostream>::static_make_integer<unsigned long>(void const *, int &);
template bool format_argument<std::iostream>::static_make_integer<long long>(void const *, int &);
template bool format_argument<std::iostream>::static_make_integer<unsigned long long>(void const *, int &);
template bool format_argument<std::iostream>::static_make_integer<char *>(void const *, int &);
template bool format_argument<std::iostream>::static_make_integer<char const *>(void const *, int &);
template bool format_argument<std::iostream>::static_make_integer<std::string>(void const *, int &);
template bool format_argument<std::iostream>::static_make_integer<std::string_view>(void const *, int &);
template void format_argument<std::iostream>::static_store_integer<char>(void const *, std::streamoff);
template void format_argument<std::iostream>::static_store_integer<signed char>(void const *, std::streamoff);
template void format_argument<std::iostream>::static_store_integer<unsigned char>(void const *, std::streamoff);
template void format_argument<std::iostream>::static_store_integer<short>(void const *, std::streamoff);
template void format_argument<std::iostream>::static_store_integer<unsigned short>(void const *, std::streamoff);
template void format_argument<std::iostream>::static_store_integer<int>(void const *, std::streamoff);
template void format_argument<std::iostream>::static_store_integer<unsigned int>(void const *, std::streamoff);
template void format_argument<std::iostream>::static_store_integer<long>(void const *, std::streamoff);
template void format_argument<std::iostream>::static_store_integer<unsigned long>(void const *, std::streamoff);
template void format_argument<std::iostream>::static_store_integer<long long>(void const *, std::streamoff);
template void format_argument<std::iostream>::static_store_integer<unsigned long long>(void const *, std::streamoff);
template void format_argument<std::iostream>::static_store_integer<char *>(void const *, std::streamoff);
template void format_argument<std::iostream>::static_store_integer<char const *>(void const *, std::streamoff);
template void format_argument<std::iostream>::static_store_integer<std::string>(void const *, std::streamoff);
template void format_argument<std::iostream>::static_store_integer<std::string_view>(void const *, std::streamoff);
template class format_argument<std::wiostream>;
template void format_argument<std::wiostream>::static_output<char>(std::wiostream &, format_flags const &, void const *);
template void format_argument<std::wiostream>::static_output<signed char>(std::wiostream &, format_flags const &, void const *);
template void format_argument<std::wiostream>::static_output<unsigned char>(std::wiostream &, format_flags const &, void const *);
template void format_argument<std::wiostream>::static_output<wchar_t>(std::wiostream &, format_flags const &, void const *);
template void format_argument<std::wiostream>::static_output<short>(std::wiostream &, format_flags const &, void const *);
template void format_argument<std::wiostream>::static_output<unsigned short>(std::wiostream &, format_flags const &, void const *);
template void format_argument<std::wiostream>::static_output<int>(std::wiostream &, format_flags const &, void const *);
template void format_argument<std::wiostream>::static_output<unsigned int>(std::wiostream &, format_flags const &, void const *);
template void format_argument<std::wiostream>::static_output<long>(std::wiostream &, format_flags const &, void const *);
template void format_argument<std::wiostream>::static_output<unsigned long>(std::wiostream &, format_flags const &, void const *);
template void format_argument<std::wiostream>::static_output<long long>(std::wiostream &, format_flags const &, void const *);
template void format_argument<std::wiostream>::static_output<unsigned long long>(std::wiostream &, format_flags const &, void const *);
template void format_argument<std::wiostream>::static_output<wchar_t *>(std::wiostream &, format_flags const &, void const *);
template void format_argument<std::wiostream>::static_output<wchar_t const *>(std::wiostream &, format_flags const &, void const *);
template void format_argument<std::wiostream>::static_output<std::wstring>(std::wiostream &, format_flags const &, void const *);
template void format_argument<std::wiostream>::static_output<std::wstring_view>(std::wiostream &, format_flags const &, void const *);
template bool format_argument<std::wiostream>::static_make_integer<char>(void const *, int &);
template bool format_argument<std::wiostream>::static_make_integer<signed char>(void const *, int &);
template bool format_argument<std::wiostream>::static_make_integer<unsigned char>(void const *, int &);
template bool format_argument<std::wiostream>::static_make_integer<wchar_t>(void const *, int &);
template bool format_argument<std::wiostream>::static_make_integer<short>(void const *, int &);
template bool format_argument<std::wiostream>::static_make_integer<unsigned short>(void const *, int &);
template bool format_argument<std::wiostream>::static_make_integer<int>(void const *, int &);
template bool format_argument<std::wiostream>::static_make_integer<unsigned int>(void const *, int &);
template bool format_argument<std::wiostream>::static_make_integer<long>(void const *, int &);
template bool format_argument<std::wiostream>::static_make_integer<unsigned long>(void const *, int &);
template bool format_argument<std::wiostream>::static_make_integer<long long>(void const *, int &);
template bool format_argument<std::wiostream>::static_make_integer<unsigned long long>(void const *, int &);
template bool format_argument<std::wiostream>::static_make_integer<wchar_t *>(void const *, int &);
template bool format_argument<std::wiostream>::static_make_integer<wchar_t const *>(void const *, int &);
template bool format_argument<std::wiostream>::static_make_integer<std::wstring>(void const *, int &);
template bool format_argument<std::wiostream>::static_make_integer<std::wstring_view>(void const *, int &);
template void format_argument<std::wiostream>::static_store_integer<char>(void const *, std::streamoff);
template void format_argument<std::wiostream>::static_store_integer<signed char>(void const *, std::streamoff);
template void format_argument<std::wiostream>::static_store_integer<unsigned char>(void const *, std::streamoff);
template void format_argument<std::wiostream>::static_store_integer<wchar_t>(void const *, std::streamoff);
template void format_argument<std::wiostream>::static_store_integer<short>(void const *, std::streamoff);
template void format_argument<std::wiostream>::static_store_integer<unsigned short>(void const *, std::streamoff);
template void format_argument<std::wiostream>::static_store_integer<int>(void const *, std::streamoff);
template void format_argument<std::wiostream>::static_store_integer<unsigned int>(void const *, std::streamoff);
template void format_argument<std::wiostream>::static_store_integer<long>(void const *, std::streamoff);
template void format_argument<std::wiostream>::static_store_integer<unsigned long>(void const *, std::streamoff);
template void format_argument<std::wiostream>::static_store_integer<long long>(void const *, std::streamoff);
template void format_argument<std::wiostream>::static_store_integer<unsigned long long>(void const *, std::streamoff);
template void format_argument<std::wiostream>::static_store_integer<wchar_t *>(void const *, std::streamoff);
template void format_argument<std::wiostream>::static_store_integer<wchar_t const *>(void const *, std::streamoff);
template void format_argument<std::wiostream>::static_store_integer<std::wstring>(void const *, std::streamoff);
template void format_argument<std::wiostream>::static_store_integer<std::wstring_view>(void const *, std::streamoff);
template class format_argument<std::ostringstream>;
template void format_argument<std::ostringstream>::static_output<char>(std::ostringstream &, format_flags const &, void const *);
template void format_argument<std::ostringstream>::static_output<signed char>(std::ostringstream &, format_flags const &, void const *);
template void format_argument<std::ostringstream>::static_output<unsigned char>(std::ostringstream &, format_flags const &, void const *);
template void format_argument<std::ostringstream>::static_output<short>(std::ostringstream &, format_flags const &, void const *);
template void format_argument<std::ostringstream>::static_output<unsigned short>(std::ostringstream &, format_flags const &, void const *);
template void format_argument<std::ostringstream>::static_output<int>(std::ostringstream &, format_flags const &, void const *);
template void format_argument<std::ostringstream>::static_output<unsigned int>(std::ostringstream &, format_flags const &, void const *);
template void format_argument<std::ostringstream>::static_output<long>(std::ostringstream &, format_flags const &, void const *);
template void format_argument<std::ostringstream>::static_output<unsigned long>(std::ostringstream &, format_flags const &, void const *);
template void format_argument<std::ostringstream>::static_output<long long>(std::ostringstream &, format_flags const &, void const *);
template void format_argument<std::ostringstream>::static_output<unsigned long long>(std::ostringstream &, format_flags const &, void const *);
template void format_argument<std::ostringstream>::static_output<char *>(std::ostringstream &, format_flags const &, void const *);
template void format_argument<std::ostringstream>::static_output<char const *>(std::ostringstream &, format_flags const &, void const *);
template void format_argument<std::ostringstream>::static_output<std::string>(std::ostringstream &, format_flags const &, void const *);
template void format_argument<std::ostringstream>::static_output<std::string_view>(std::ostringstream &, format_flags const &, void const *);
template bool format_argument<std::ostringstream>::static_make_integer<char>(void const *, int &);
template bool format_argument<std::ostringstream>::static_make_integer<signed char>(void const *, int &);
template bool format_argument<std::ostringstream>::static_make_integer<unsigned char>(void const *, int &);
template bool format_argument<std::ostringstream>::static_make_integer<short>(void const *, int &);
template bool format_argument<std::ostringstream>::static_make_integer<unsigned short>(void const *, int &);
template bool format_argument<std::ostringstream>::static_make_integer<int>(void const *, int &);
template bool format_argument<std::ostringstream>::static_make_integer<unsigned int>(void const *, int &);
template bool format_argument<std::ostringstream>::static_make_integer<long>(void const *, int &);
template bool format_argument<std::ostringstream>::static_make_integer<unsigned long>(void const *, int &);
template bool format_argument<std::ostringstream>::static_make_integer<long long>(void const *, int &);
template bool format_argument<std::ostringstream>::static_make_integer<unsigned long long>(void const *, int &);
template bool format_argument<std::ostringstream>::static_make_integer<char *>(void const *, int &);
template bool format_argument<std::ostringstream>::static_make_integer<char const *>(void const *, int &);
template bool format_argument<std::ostringstream>::static_make_integer<std::string>(void const *, int &);
template bool format_argument<std::ostringstream>::static_make_integer<std::string_view>(void const *, int &);
template void format_argument<std::ostringstream>::static_store_integer<char>(void const *, std::streamoff);
template void format_argument<std::ostringstream>::static_store_integer<signed char>(void const *, std::streamoff);
template void format_argument<std::ostringstream>::static_store_integer<unsigned char>(void const *, std::streamoff);
template void format_argument<std::ostringstream>::static_store_integer<short>(void const *, std::streamoff);
template void format_argument<std::ostringstream>::static_store_integer<unsigned short>(void const *, std::streamoff);
template void format_argument<std::ostringstream>::static_store_integer<int>(void const *, std::streamoff);
template void format_argument<std::ostringstream>::static_store_integer<unsigned int>(void const *, std::streamoff);
template void format_argument<std::ostringstream>::static_store_integer<long>(void const *, std::streamoff);
template void format_argument<std::ostringstream>::static_store_integer<unsigned long>(void const *, std::streamoff);
template void format_argument<std::ostringstream>::static_store_integer<long long>(void const *, std::streamoff);
template void format_argument<std::ostringstream>::static_store_integer<unsigned long long>(void const *, std::streamoff);
template void format_argument<std::ostringstream>::static_store_integer<char *>(void const *, std::streamoff);
template void format_argument<std::ostringstream>::static_store_integer<char const *>(void const *, std::streamoff);
template void format_argument<std::ostringstream>::static_store_integer<std::string>(void const *, std::streamoff);
template void format_argument<std::ostringstream>::static_store_integer<std::string_view>(void const *, std::streamoff);
template class format_argument<std::wostringstream>;
template void format_argument<std::wostringstream>::static_output<char>(std::wostringstream &, format_flags const &, void const *);
template void format_argument<std::wostringstream>::static_output<signed char>(std::wostringstream &, format_flags const &, void const *);
template void format_argument<std::wostringstream>::static_output<unsigned char>(std::wostringstream &, format_flags const &, void const *);
template void format_argument<std::wostringstream>::static_output<wchar_t>(std::wostringstream &, format_flags const &, void const *);
template void format_argument<std::wostringstream>::static_output<short>(std::wostringstream &, format_flags const &, void const *);
template void format_argument<std::wostringstream>::static_output<unsigned short>(std::wostringstream &, format_flags const &, void const *);
template void format_argument<std::wostringstream>::static_output<int>(std::wostringstream &, format_flags const &, void const *);
template void format_argument<std::wostringstream>::static_output<unsigned int>(std::wostringstream &, format_flags const &, void const *);
template void format_argument<std::wostringstream>::static_output<long>(std::wostringstream &, format_flags const &, void const *);
template void format_argument<std::wostringstream>::static_output<unsigned long>(std::wostringstream &, format_flags const &, void const *);
template void format_argument<std::wostringstream>::static_output<long long>(std::wostringstream &, format_flags const &, void const *);
template void format_argument<std::wostringstream>::static_output<unsigned long long>(std::wostringstream &, format_flags const &, void const *);
template void format_argument<std::wostringstream>::static_output<wchar_t *>(std::wostringstream &, format_flags const &, void const *);
template void format_argument<std::wostringstream>::static_output<wchar_t const *>(std::wostringstream &, format_flags const &, void const *);
template void format_argument<std::wostringstream>::static_output<std::wstring>(std::wostringstream &, format_flags const &, void const *);
template void format_argument<std::wostringstream>::static_output<std::wstring_view>(std::wostringstream &, format_flags const &, void const *);
template bool format_argument<std::wostringstream>::static_make_integer<char>(void const *, int &);
template bool format_argument<std::wostringstream>::static_make_integer<signed char>(void const *, int &);
template bool format_argument<std::wostringstream>::static_make_integer<unsigned char>(void const *, int &);
template bool format_argument<std::wostringstream>::static_make_integer<wchar_t>(void const *, int &);
template bool format_argument<std::wostringstream>::static_make_integer<short>(void const *, int &);
template bool format_argument<std::wostringstream>::static_make_integer<unsigned short>(void const *, int &);
template bool format_argument<std::wostringstream>::static_make_integer<int>(void const *, int &);
template bool format_argument<std::wostringstream>::static_make_integer<unsigned int>(void const *, int &);
template bool format_argument<std::wostringstream>::static_make_integer<long>(void const *, int &);
template bool format_argument<std::wostringstream>::static_make_integer<unsigned long>(void const *, int &);
template bool format_argument<std::wostringstream>::static_make_integer<long long>(void const *, int &);
template bool format_argument<std::wostringstream>::static_make_integer<unsigned long long>(void const *, int &);
template bool format_argument<std::wostringstream>::static_make_integer<wchar_t *>(void const *, int &);
template bool format_argument<std::wostringstream>::static_make_integer<wchar_t const *>(void const *, int &);
template bool format_argument<std::wostringstream>::static_make_integer<std::wstring>(void const *, int &);
template bool format_argument<std::wostringstream>::static_make_integer<std::wstring_view>(void const *, int &);
template void format_argument<std::wostringstream>::static_store_integer<char>(void const *, std::streamoff);
template void format_argument<std::wostringstream>::static_store_integer<signed char>(void const *, std::streamoff);
template void format_argument<std::wostringstream>::static_store_integer<unsigned char>(void const *, std::streamoff);
template void format_argument<std::wostringstream>::static_store_integer<wchar_t>(void const *, std::streamoff);
template void format_argument<std::wostringstream>::static_store_integer<short>(void const *, std::streamoff);
template void format_argument<std::wostringstream>::static_store_integer<unsigned short>(void const *, std::streamoff);
template void format_argument<std::wostringstream>::static_store_integer<int>(void const *, std::streamoff);
template void format_argument<std::wostringstream>::static_store_integer<unsigned int>(void const *, std::streamoff);
template void format_argument<std::wostringstream>::static_store_integer<long>(void const *, std::streamoff);
template void format_argument<std::wostringstream>::static_store_integer<unsigned long>(void const *, std::streamoff);
template void format_argument<std::wostringstream>::static_store_integer<long long>(void const *, std::streamoff);
template void format_argument<std::wostringstream>::static_store_integer<unsigned long long>(void const *, std::streamoff);
template void format_argument<std::wostringstream>::static_store_integer<wchar_t *>(void const *, std::streamoff);
template void format_argument<std::wostringstream>::static_store_integer<wchar_t const *>(void const *, std::streamoff);
template void format_argument<std::wostringstream>::static_store_integer<std::wstring>(void const *, std::streamoff);
template void format_argument<std::wostringstream>::static_store_integer<std::wstring_view>(void const *, std::streamoff);
template class format_argument<std::stringstream>;
template void format_argument<std::stringstream>::static_output<char>(std::stringstream &, format_flags const &, void const *);
template void format_argument<std::stringstream>::static_output<signed char>(std::stringstream &, format_flags const &, void const *);
template void format_argument<std::stringstream>::static_output<unsigned char>(std::stringstream &, format_flags const &, void const *);
template void format_argument<std::stringstream>::static_output<short>(std::stringstream &, format_flags const &, void const *);
template void format_argument<std::stringstream>::static_output<unsigned short>(std::stringstream &, format_flags const &, void const *);
template void format_argument<std::stringstream>::static_output<int>(std::stringstream &, format_flags const &, void const *);
template void format_argument<std::stringstream>::static_output<unsigned int>(std::stringstream &, format_flags const &, void const *);
template void format_argument<std::stringstream>::static_output<long>(std::stringstream &, format_flags const &, void const *);
template void format_argument<std::stringstream>::static_output<unsigned long>(std::stringstream &, format_flags const &, void const *);
template void format_argument<std::stringstream>::static_output<long long>(std::stringstream &, format_flags const &, void const *);
template void format_argument<std::stringstream>::static_output<unsigned long long>(std::stringstream &, format_flags const &, void const *);
template void format_argument<std::stringstream>::static_output<char *>(std::stringstream &, format_flags const &, void const *);
template void format_argument<std::stringstream>::static_output<char const *>(std::stringstream &, format_flags const &, void const *);
template void format_argument<std::stringstream>::static_output<std::string>(std::stringstream &, format_flags const &, void const *);
template void format_argument<std::stringstream>::static_output<std::string_view>(std::stringstream &, format_flags const &, void const *);
template bool format_argument<std::stringstream>::static_make_integer<char>(void const *, int &);
template bool format_argument<std::stringstream>::static_make_integer<signed char>(void const *, int &);
template bool format_argument<std::stringstream>::static_make_integer<unsigned char>(void const *, int &);
template bool format_argument<std::stringstream>::static_make_integer<short>(void const *, int &);
template bool format_argument<std::stringstream>::static_make_integer<unsigned short>(void const *, int &);
template bool format_argument<std::stringstream>::static_make_integer<int>(void const *, int &);
template bool format_argument<std::stringstream>::static_make_integer<unsigned int>(void const *, int &);
template bool format_argument<std::stringstream>::static_make_integer<long>(void const *, int &);
template bool format_argument<std::stringstream>::static_make_integer<unsigned long>(void const *, int &);
template bool format_argument<std::stringstream>::static_make_integer<long long>(void const *, int &);
template bool format_argument<std::stringstream>::static_make_integer<unsigned long long>(void const *, int &);
template bool format_argument<std::stringstream>::static_make_integer<char *>(void const *, int &);
template bool format_argument<std::stringstream>::static_make_integer<char const *>(void const *, int &);
template bool format_argument<std::stringstream>::static_make_integer<std::string>(void const *, int &);
template bool format_argument<std::stringstream>::static_make_integer<std::string_view>(void const *, int &);
template void format_argument<std::stringstream>::static_store_integer<char>(void const *, std::streamoff);
template void format_argument<std::stringstream>::static_store_integer<signed char>(void const *, std::streamoff);
template void format_argument<std::stringstream>::static_store_integer<unsigned char>(void const *, std::streamoff);
template void format_argument<std::stringstream>::static_store_integer<short>(void const *, std::streamoff);
template void format_argument<std::stringstream>::static_store_integer<unsigned short>(void const *, std::streamoff);
template void format_argument<std::stringstream>::static_store_integer<int>(void const *, std::streamoff);
template void format_argument<std::stringstream>::static_store_integer<unsigned int>(void const *, std::streamoff);
template void format_argument<std::stringstream>::static_store_integer<long>(void const *, std::streamoff);
template void format_argument<std::stringstream>::static_store_integer<unsigned long>(void const *, std::streamoff);
template void format_argument<std::stringstream>::static_store_integer<long long>(void const *, std::streamoff);
template void format_argument<std::stringstream>::static_store_integer<unsigned long long>(void const *, std::streamoff);
template void format_argument<std::stringstream>::static_store_integer<char *>(void const *, std::streamoff);
template void format_argument<std::stringstream>::static_store_integer<char const *>(void const *, std::streamoff);
template void format_argument<std::stringstream>::static_store_integer<std::string>(void const *, std::streamoff);
template void format_argument<std::stringstream>::static_store_integer<std::string_view>(void const *, std::streamoff);
template class format_argument<std::wstringstream>;
template void format_argument<std::wstringstream>::static_output<char>(std::wstringstream &, format_flags const &, void const *);
template void format_argument<std::wstringstream>::static_output<signed char>(std::wstringstream &, format_flags const &, void const *);
template void format_argument<std::wstringstream>::static_output<unsigned char>(std::wstringstream &, format_flags const &, void const *);
template void format_argument<std::wstringstream>::static_output<wchar_t>(std::wstringstream &, format_flags const &, void const *);
template void format_argument<std::wstringstream>::static_output<short>(std::wstringstream &, format_flags const &, void const *);
template void format_argument<std::wstringstream>::static_output<unsigned short>(std::wstringstream &, format_flags const &, void const *);
template void format_argument<std::wstringstream>::static_output<int>(std::wstringstream &, format_flags const &, void const *);
template void format_argument<std::wstringstream>::static_output<unsigned int>(std::wstringstream &, format_flags const &, void const *);
template void format_argument<std::wstringstream>::static_output<long>(std::wstringstream &, format_flags const &, void const *);
template void format_argument<std::wstringstream>::static_output<unsigned long>(std::wstringstream &, format_flags const &, void const *);
template void format_argument<std::wstringstream>::static_output<long long>(std::wstringstream &, format_flags const &, void const *);
template void format_argument<std::wstringstream>::static_output<unsigned long long>(std::wstringstream &, format_flags const &, void const *);
template void format_argument<std::wstringstream>::static_output<wchar_t *>(std::wstringstream &, format_flags const &, void const *);
template void format_argument<std::wstringstream>::static_output<wchar_t const *>(std::wstringstream &, format_flags const &, void const *);
template void format_argument<std::wstringstream>::static_output<std::wstring>(std::wstringstream &, format_flags const &, void const *);
template void format_argument<std::wstringstream>::static_output<std::wstring_view>(std::wstringstream &, format_flags const &, void const *);
template bool format_argument<std::wstringstream>::static_make_integer<char>(void const *, int &);
template bool format_argument<std::wstringstream>::static_make_integer<signed char>(void const *, int &);
template bool format_argument<std::wstringstream>::static_make_integer<unsigned char>(void const *, int &);
template bool format_argument<std::wstringstream>::static_make_integer<wchar_t>(void const *, int &);
template bool format_argument<std::wstringstream>::static_make_integer<short>(void const *, int &);
template bool format_argument<std::wstringstream>::static_make_integer<unsigned short>(void const *, int &);
template bool format_argument<std::wstringstream>::static_make_integer<int>(void const *, int &);
template bool format_argument<std::wstringstream>::static_make_integer<unsigned int>(void const *, int &);
template bool format_argument<std::wstringstream>::static_make_integer<long>(void const *, int &);
template bool format_argument<std::wstringstream>::static_make_integer<unsigned long>(void const *, int &);
template bool format_argument<std::wstringstream>::static_make_integer<long long>(void const *, int &);
template bool format_argument<std::wstringstream>::static_make_integer<unsigned long long>(void const *, int &);
template bool format_argument<std::wstringstream>::static_make_integer<wchar_t *>(void const *, int &);
template bool format_argument<std::wstringstream>::static_make_integer<wchar_t const *>(void const *, int &);
template bool format_argument<std::wstringstream>::static_make_integer<std::wstring>(void const *, int &);
template bool format_argument<std::wstringstream>::static_make_integer<std::wstring_view>(void const *, int &);
template void format_argument<std::wstringstream>::static_store_integer<char>(void const *, std::streamoff);
template void format_argument<std::wstringstream>::static_store_integer<signed char>(void const *, std::streamoff);
template void format_argument<std::wstringstream>::static_store_integer<unsigned char>(void const *, std::streamoff);
template void format_argument<std::wstringstream>::static_store_integer<wchar_t>(void const *, std::streamoff);
template void format_argument<std::wstringstream>::static_store_integer<short>(void const *, std::streamoff);
template void format_argument<std::wstringstream>::static_store_integer<unsigned short>(void const *, std::streamoff);
template void format_argument<std::wstringstream>::static_store_integer<int>(void const *, std::streamoff);
template void format_argument<std::wstringstream>::static_store_integer<unsigned int>(void const *, std::streamoff);
template void format_argument<std::wstringstream>::static_store_integer<long>(void const *, std::streamoff);
template void format_argument<std::wstringstream>::static_store_integer<unsigned long>(void const *, std::streamoff);
template void format_argument<std::wstringstream>::static_store_integer<long long>(void const *, std::streamoff);
template void format_argument<std::wstringstream>::static_store_integer<unsigned long long>(void const *, std::streamoff);
template void format_argument<std::wstringstream>::static_store_integer<wchar_t *>(void const *, std::streamoff);
template void format_argument<std::wstringstream>::static_store_integer<wchar_t const *>(void const *, std::streamoff);
template void format_argument<std::wstringstream>::static_store_integer<std::wstring>(void const *, std::streamoff);
template void format_argument<std::wstringstream>::static_store_integer<std::wstring_view>(void const *, std::streamoff);
template class format_argument<ovectorstream>;
template void format_argument<ovectorstream>::static_output<char>(ovectorstream &, format_flags const &, void const *);
template void format_argument<ovectorstream>::static_output<signed char>(ovectorstream &, format_flags const &, void const *);
template void format_argument<ovectorstream>::static_output<unsigned char>(ovectorstream &, format_flags const &, void const *);
template void format_argument<ovectorstream>::static_output<short>(ovectorstream &, format_flags const &, void const *);
template void format_argument<ovectorstream>::static_output<unsigned short>(ovectorstream &, format_flags const &, void const *);
template void format_argument<ovectorstream>::static_output<int>(ovectorstream &, format_flags const &, void const *);
template void format_argument<ovectorstream>::static_output<unsigned int>(ovectorstream &, format_flags const &, void const *);
template void format_argument<ovectorstream>::static_output<long>(ovectorstream &, format_flags const &, void const *);
template void format_argument<ovectorstream>::static_output<unsigned long>(ovectorstream &, format_flags const &, void const *);
template void format_argument<ovectorstream>::static_output<long long>(ovectorstream &, format_flags const &, void const *);
template void format_argument<ovectorstream>::static_output<unsigned long long>(ovectorstream &, format_flags const &, void const *);
template void format_argument<ovectorstream>::static_output<char *>(ovectorstream &, format_flags const &, void const *);
template void format_argument<ovectorstream>::static_output<char const *>(ovectorstream &, format_flags const &, void const *);
template void format_argument<ovectorstream>::static_output<std::string>(ovectorstream &, format_flags const &, void const *);
template void format_argument<ovectorstream>::static_output<std::string_view>(ovectorstream &, format_flags const &, void const *);
template bool format_argument<ovectorstream>::static_make_integer<char>(void const *, int &);
template bool format_argument<ovectorstream>::static_make_integer<signed char>(void const *, int &);
template bool format_argument<ovectorstream>::static_make_integer<unsigned char>(void const *, int &);
template bool format_argument<ovectorstream>::static_make_integer<short>(void const *, int &);
template bool format_argument<ovectorstream>::static_make_integer<unsigned short>(void const *, int &);
template bool format_argument<ovectorstream>::static_make_integer<int>(void const *, int &);
template bool format_argument<ovectorstream>::static_make_integer<unsigned int>(void const *, int &);
template bool format_argument<ovectorstream>::static_make_integer<long>(void const *, int &);
template bool format_argument<ovectorstream>::static_make_integer<unsigned long>(void const *, int &);
template bool format_argument<ovectorstream>::static_make_integer<long long>(void const *, int &);
template bool format_argument<ovectorstream>::static_make_integer<unsigned long long>(void const *, int &);
template bool format_argument<ovectorstream>::static_make_integer<char *>(void const *, int &);
template bool format_argument<ovectorstream>::static_make_integer<char const *>(void const *, int &);
template bool format_argument<ovectorstream>::static_make_integer<std::string>(void const *, int &);
template bool format_argument<ovectorstream>::static_make_integer<std::string_view>(void const *, int &);
template void format_argument<ovectorstream>::static_store_integer<char>(void const *, std::streamoff);
template void format_argument<ovectorstream>::static_store_integer<signed char>(void const *, std::streamoff);
template void format_argument<ovectorstream>::static_store_integer<unsigned char>(void const *, std::streamoff);
template void format_argument<ovectorstream>::static_store_integer<short>(void const *, std::streamoff);
template void format_argument<ovectorstream>::static_store_integer<unsigned short>(void const *, std::streamoff);
template void format_argument<ovectorstream>::static_store_integer<int>(void const *, std::streamoff);
template void format_argument<ovectorstream>::static_store_integer<unsigned int>(void const *, std::streamoff);
template void format_argument<ovectorstream>::static_store_integer<long>(void const *, std::streamoff);
template void format_argument<ovectorstream>::static_store_integer<unsigned long>(void const *, std::streamoff);
template void format_argument<ovectorstream>::static_store_integer<long long>(void const *, std::streamoff);
template void format_argument<ovectorstream>::static_store_integer<unsigned long long>(void const *, std::streamoff);
template void format_argument<ovectorstream>::static_store_integer<char *>(void const *, std::streamoff);
template void format_argument<ovectorstream>::static_store_integer<char const *>(void const *, std::streamoff);
template void format_argument<ovectorstream>::static_store_integer<std::string>(void const *, std::streamoff);
template void format_argument<ovectorstream>::static_store_integer<std::string_view>(void const *, std::streamoff);
template class format_argument<wovectorstream>;
template void format_argument<wovectorstream>::static_output<char>(wovectorstream &, format_flags const &, void const *);
template void format_argument<wovectorstream>::static_output<signed char>(wovectorstream &, format_flags const &, void const *);
template void format_argument<wovectorstream>::static_output<unsigned char>(wovectorstream &, format_flags const &, void const *);
template void format_argument<wovectorstream>::static_output<wchar_t>(wovectorstream &, format_flags const &, void const *);
template void format_argument<wovectorstream>::static_output<short>(wovectorstream &, format_flags const &, void const *);
template void format_argument<wovectorstream>::static_output<unsigned short>(wovectorstream &, format_flags const &, void const *);
template void format_argument<wovectorstream>::static_output<int>(wovectorstream &, format_flags const &, void const *);
template void format_argument<wovectorstream>::static_output<unsigned int>(wovectorstream &, format_flags const &, void const *);
template void format_argument<wovectorstream>::static_output<long>(wovectorstream &, format_flags const &, void const *);
template void format_argument<wovectorstream>::static_output<unsigned long>(wovectorstream &, format_flags const &, void const *);
template void format_argument<wovectorstream>::static_output<long long>(wovectorstream &, format_flags const &, void const *);
template void format_argument<wovectorstream>::static_output<unsigned long long>(wovectorstream &, format_flags const &, void const *);
template void format_argument<wovectorstream>::static_output<wchar_t *>(wovectorstream &, format_flags const &, void const *);
template void format_argument<wovectorstream>::static_output<wchar_t const *>(wovectorstream &, format_flags const &, void const *);
template void format_argument<wovectorstream>::static_output<std::wstring>(wovectorstream &, format_flags const &, void const *);
template void format_argument<wovectorstream>::static_output<std::wstring_view>(wovectorstream &, format_flags const &, void const *);
template bool format_argument<wovectorstream>::static_make_integer<char>(void const *, int &);
template bool format_argument<wovectorstream>::static_make_integer<signed char>(void const *, int &);
template bool format_argument<wovectorstream>::static_make_integer<unsigned char>(void const *, int &);
template bool format_argument<wovectorstream>::static_make_integer<wchar_t>(void const *, int &);
template bool format_argument<wovectorstream>::static_make_integer<short>(void const *, int &);
template bool format_argument<wovectorstream>::static_make_integer<unsigned short>(void const *, int &);
template bool format_argument<wovectorstream>::static_make_integer<int>(void const *, int &);
template bool format_argument<wovectorstream>::static_make_integer<unsigned int>(void const *, int &);
template bool format_argument<wovectorstream>::static_make_integer<long>(void const *, int &);
template bool format_argument<wovectorstream>::static_make_integer<unsigned long>(void const *, int &);
template bool format_argument<wovectorstream>::static_make_integer<long long>(void const *, int &);
template bool format_argument<wovectorstream>::static_make_integer<unsigned long long>(void const *, int &);
template bool format_argument<wovectorstream>::static_make_integer<wchar_t *>(void const *, int &);
template bool format_argument<wovectorstream>::static_make_integer<wchar_t const *>(void const *, int &);
template bool format_argument<wovectorstream>::static_make_integer<std::wstring>(void const *, int &);
template bool format_argument<wovectorstream>::static_make_integer<std::wstring_view>(void const *, int &);
template void format_argument<wovectorstream>::static_store_integer<char>(void const *, std::streamoff);
template void format_argument<wovectorstream>::static_store_integer<signed char>(void const *, std::streamoff);
template void format_argument<wovectorstream>::static_store_integer<unsigned char>(void const *, std::streamoff);
template void format_argument<wovectorstream>::static_store_integer<wchar_t>(void const *, std::streamoff);
template void format_argument<wovectorstream>::static_store_integer<short>(void const *, std::streamoff);
template void format_argument<wovectorstream>::static_store_integer<unsigned short>(void const *, std::streamoff);
template void format_argument<wovectorstream>::static_store_integer<int>(void const *, std::streamoff);
template void format_argument<wovectorstream>::static_store_integer<unsigned int>(void const *, std::streamoff);
template void format_argument<wovectorstream>::static_store_integer<long>(void const *, std::streamoff);
template void format_argument<wovectorstream>::static_store_integer<unsigned long>(void const *, std::streamoff);
template void format_argument<wovectorstream>::static_store_integer<long long>(void const *, std::streamoff);
template void format_argument<wovectorstream>::static_store_integer<unsigned long long>(void const *, std::streamoff);
template void format_argument<wovectorstream>::static_store_integer<wchar_t *>(void const *, std::streamoff);
template void format_argument<wovectorstream>::static_store_integer<wchar_t const *>(void const *, std::streamoff);
template void format_argument<wovectorstream>::static_store_integer<std::wstring>(void const *, std::streamoff);
template void format_argument<wovectorstream>::static_store_integer<std::wstring_view>(void const *, std::streamoff);
template class format_argument<vectorstream>;
template void format_argument<vectorstream>::static_output<char>(vectorstream &, format_flags const &, void const *);
template void format_argument<vectorstream>::static_output<signed char>(vectorstream &, format_flags const &, void const *);
template void format_argument<vectorstream>::static_output<unsigned char>(vectorstream &, format_flags const &, void const *);
template void format_argument<vectorstream>::static_output<short>(vectorstream &, format_flags const &, void const *);
template void format_argument<vectorstream>::static_output<unsigned short>(vectorstream &, format_flags const &, void const *);
template void format_argument<vectorstream>::static_output<int>(vectorstream &, format_flags const &, void const *);
template void format_argument<vectorstream>::static_output<unsigned int>(vectorstream &, format_flags const &, void const *);
template void format_argument<vectorstream>::static_output<long>(vectorstream &, format_flags const &, void const *);
template void format_argument<vectorstream>::static_output<unsigned long>(vectorstream &, format_flags const &, void const *);
template void format_argument<vectorstream>::static_output<long long>(vectorstream &, format_flags const &, void const *);
template void format_argument<vectorstream>::static_output<unsigned long long>(vectorstream &, format_flags const &, void const *);
template void format_argument<vectorstream>::static_output<char *>(vectorstream &, format_flags const &, void const *);
template void format_argument<vectorstream>::static_output<char const *>(vectorstream &, format_flags const &, void const *);
template void format_argument<vectorstream>::static_output<std::string>(vectorstream &, format_flags const &, void const *);
template void format_argument<vectorstream>::static_output<std::string_view>(vectorstream &, format_flags const &, void const *);
template bool format_argument<vectorstream>::static_make_integer<char>(void const *, int &);
template bool format_argument<vectorstream>::static_make_integer<signed char>(void const *, int &);
template bool format_argument<vectorstream>::static_make_integer<unsigned char>(void const *, int &);
template bool format_argument<vectorstream>::static_make_integer<short>(void const *, int &);
template bool format_argument<vectorstream>::static_make_integer<unsigned short>(void const *, int &);
template bool format_argument<vectorstream>::static_make_integer<int>(void const *, int &);
template bool format_argument<vectorstream>::static_make_integer<unsigned int>(void const *, int &);
template bool format_argument<vectorstream>::static_make_integer<long>(void const *, int &);
template bool format_argument<vectorstream>::static_make_integer<unsigned long>(void const *, int &);
template bool format_argument<vectorstream>::static_make_integer<long long>(void const *, int &);
template bool format_argument<vectorstream>::static_make_integer<unsigned long long>(void const *, int &);
template bool format_argument<vectorstream>::static_make_integer<char *>(void const *, int &);
template bool format_argument<vectorstream>::static_make_integer<char const *>(void const *, int &);
template bool format_argument<vectorstream>::static_make_integer<std::string>(void const *, int &);
template bool format_argument<vectorstream>::static_make_integer<std::string_view>(void const *, int &);
template void format_argument<vectorstream>::static_store_integer<char>(void const *, std::streamoff);
template void format_argument<vectorstream>::static_store_integer<signed char>(void const *, std::streamoff);
template void format_argument<vectorstream>::static_store_integer<unsigned char>(void const *, std::streamoff);
template void format_argument<vectorstream>::static_store_integer<short>(void const *, std::streamoff);
template void format_argument<vectorstream>::static_store_integer<unsigned short>(void const *, std::streamoff);
template void format_argument<vectorstream>::static_store_integer<int>(void const *, std::streamoff);
template void format_argument<vectorstream>::static_store_integer<unsigned int>(void const *, std::streamoff);
template void format_argument<vectorstream>::static_store_integer<long>(void const *, std::streamoff);
template void format_argument<vectorstream>::static_store_integer<unsigned long>(void const *, std::streamoff);
template void format_argument<vectorstream>::static_store_integer<long long>(void const *, std::streamoff);
template void format_argument<vectorstream>::static_store_integer<unsigned long long>(void const *, std::streamoff);
template void format_argument<vectorstream>::static_store_integer<char *>(void const *, std::streamoff);
template void format_argument<vectorstream>::static_store_integer<char const *>(void const *, std::streamoff);
template void format_argument<vectorstream>::static_store_integer<std::string>(void const *, std::streamoff);
template void format_argument<vectorstream>::static_store_integer<std::string_view>(void const *, std::streamoff);
template class format_argument<wvectorstream>;
template void format_argument<wvectorstream>::static_output<char>(wvectorstream &, format_flags const &, void const *);
template void format_argument<wvectorstream>::static_output<signed char>(wvectorstream &, format_flags const &, void const *);
template void format_argument<wvectorstream>::static_output<unsigned char>(wvectorstream &, format_flags const &, void const *);
template void format_argument<wvectorstream>::static_output<wchar_t>(wvectorstream &, format_flags const &, void const *);
template void format_argument<wvectorstream>::static_output<short>(wvectorstream &, format_flags const &, void const *);
template void format_argument<wvectorstream>::static_output<unsigned short>(wvectorstream &, format_flags const &, void const *);
template void format_argument<wvectorstream>::static_output<int>(wvectorstream &, format_flags const &, void const *);
template void format_argument<wvectorstream>::static_output<unsigned int>(wvectorstream &, format_flags const &, void const *);
template void format_argument<wvectorstream>::static_output<long>(wvectorstream &, format_flags const &, void const *);
template void format_argument<wvectorstream>::static_output<unsigned long>(wvectorstream &, format_flags const &, void const *);
template void format_argument<wvectorstream>::static_output<long long>(wvectorstream &, format_flags const &, void const *);
template void format_argument<wvectorstream>::static_output<unsigned long long>(wvectorstream &, format_flags const &, void const *);
template void format_argument<wvectorstream>::static_output<wchar_t *>(wvectorstream &, format_flags const &, void const *);
template void format_argument<wvectorstream>::static_output<wchar_t const *>(wvectorstream &, format_flags const &, void const *);
template void format_argument<wvectorstream>::static_output<std::wstring>(wvectorstream &, format_flags const &, void const *);
template void format_argument<wvectorstream>::static_output<std::wstring_view>(wvectorstream &, format_flags const &, void const *);
template bool format_argument<wvectorstream>::static_make_integer<char>(void const *, int &);
template bool format_argument<wvectorstream>::static_make_integer<signed char>(void const *, int &);
template bool format_argument<wvectorstream>::static_make_integer<unsigned char>(void const *, int &);
template bool format_argument<wvectorstream>::static_make_integer<wchar_t>(void const *, int &);
template bool format_argument<wvectorstream>::static_make_integer<short>(void const *, int &);
template bool format_argument<wvectorstream>::static_make_integer<unsigned short>(void const *, int &);
template bool format_argument<wvectorstream>::static_make_integer<int>(void const *, int &);
template bool format_argument<wvectorstream>::static_make_integer<unsigned int>(void const *, int &);
template bool format_argument<wvectorstream>::static_make_integer<long>(void const *, int &);
template bool format_argument<wvectorstream>::static_make_integer<unsigned long>(void const *, int &);
template bool format_argument<wvectorstream>::static_make_integer<long long>(void const *, int &);
template bool format_argument<wvectorstream>::static_make_integer<unsigned long long>(void const *, int &);
template bool format_argument<wvectorstream>::static_make_integer<wchar_t *>(void const *, int &);
template bool format_argument<wvectorstream>::static_make_integer<wchar_t const *>(void const *, int &);
template bool format_argument<wvectorstream>::static_make_integer<std::wstring>(void const *, int &);
template bool format_argument<wvectorstream>::static_make_integer<std::wstring_view>(void const *, int &);
template void format_argument<wvectorstream>::static_store_integer<char>(void const *, std::streamoff);
template void format_argument<wvectorstream>::static_store_integer<signed char>(void const *, std::streamoff);
template void format_argument<wvectorstream>::static_store_integer<unsigned char>(void const *, std::streamoff);
template void format_argument<wvectorstream>::static_store_integer<wchar_t>(void const *, std::streamoff);
template void format_argument<wvectorstream>::static_store_integer<short>(void const *, std::streamoff);
template void format_argument<wvectorstream>::static_store_integer<unsigned short>(void const *, std::streamoff);
template void format_argument<wvectorstream>::static_store_integer<int>(void const *, std::streamoff);
template void format_argument<wvectorstream>::static_store_integer<unsigned int>(void const *, std::streamoff);
template void format_argument<wvectorstream>::static_store_integer<long>(void const *, std::streamoff);
template void format_argument<wvectorstream>::static_store_integer<unsigned long>(void const *, std::streamoff);
template void format_argument<wvectorstream>::static_store_integer<long long>(void const *, std::streamoff);
template void format_argument<wvectorstream>::static_store_integer<unsigned long long>(void const *, std::streamoff);
template void format_argument<wvectorstream>::static_store_integer<wchar_t *>(void const *, std::streamoff);
template void format_argument<wvectorstream>::static_store_integer<wchar_t const *>(void const *, std::streamoff);
template void format_argument<wvectorstream>::static_store_integer<std::wstring>(void const *, std::streamoff);
template void format_argument<wvectorstream>::static_store_integer<std::wstring_view>(void const *, std::streamoff);
template class format_argument_pack<std::ostream>;
template class format_argument_pack<std::wostream>;
template class format_argument_pack<std::iostream>;
template class format_argument_pack<std::wiostream>;
template class format_argument_pack<std::ostringstream>;
template class format_argument_pack<std::wostringstream>;
template class format_argument_pack<std::stringstream>;
template class format_argument_pack<std::wstringstream>;
template class format_argument_pack<ovectorstream>;
template class format_argument_pack<wovectorstream>;
template class format_argument_pack<vectorstream>;
template class format_argument_pack<wvectorstream>;
template std::ostream::off_type stream_format(std::ostream &, format_argument_pack<std::ostream> const &);
template std::wostream::off_type stream_format(std::wostream &, format_argument_pack<std::wostream> const &);
template std::iostream::off_type stream_format(std::iostream &, format_argument_pack<std::ostream> const &);
template std::iostream::off_type stream_format(std::iostream &, format_argument_pack<std::iostream> const &);
template std::wiostream::off_type stream_format(std::wiostream &, format_argument_pack<std::wostream> const &);
template std::wiostream::off_type stream_format(std::wiostream &, format_argument_pack<std::wiostream> const &);
template std::ostringstream::off_type stream_format(std::ostringstream &, format_argument_pack<std::ostream> const &);
template std::ostringstream::off_type stream_format(std::ostringstream &, format_argument_pack<std::ostringstream> const &);
template std::wostringstream::off_type stream_format(std::wostringstream &, format_argument_pack<std::wostream> const &);
template std::wostringstream::off_type stream_format(std::wostringstream &, format_argument_pack<std::wostringstream> const &);
template std::stringstream::off_type stream_format(std::stringstream &, format_argument_pack<std::ostream> const &);
template std::stringstream::off_type stream_format(std::stringstream &, format_argument_pack<std::iostream> const &);
template std::stringstream::off_type stream_format(std::stringstream &, format_argument_pack<std::stringstream> const &);
template std::wstringstream::off_type stream_format(std::wstringstream &, format_argument_pack<std::wostream> const &);
template std::wstringstream::off_type stream_format(std::wstringstream &, format_argument_pack<std::wiostream> const &);
template std::wstringstream::off_type stream_format(std::wstringstream &, format_argument_pack<std::wstringstream> const &);
template ovectorstream::off_type stream_format(ovectorstream &, format_argument_pack<std::ostream> const &);
template ovectorstream::off_type stream_format(ovectorstream &, format_argument_pack<ovectorstream> const &);
template wovectorstream::off_type stream_format(wovectorstream &, format_argument_pack<std::wostream> const &);
template wovectorstream::off_type stream_format(wovectorstream &, format_argument_pack<wovectorstream> const &);
template vectorstream::off_type stream_format(vectorstream &, format_argument_pack<std::ostream> const &);
template vectorstream::off_type stream_format(vectorstream &, format_argument_pack<std::iostream> const &);
template vectorstream::off_type stream_format(vectorstream &, format_argument_pack<vectorstream> const &);
template wvectorstream::off_type stream_format(wvectorstream &, format_argument_pack<std::wostream> const &);
template wvectorstream::off_type stream_format(wvectorstream &, format_argument_pack<std::wiostream> const &);
template wvectorstream::off_type stream_format(wvectorstream &, format_argument_pack<wvectorstream> const &);
} // namespace detail
} // namespace util

File diff suppressed because it is too large Load Diff

View File

@ -1,408 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/***************************************************************************
vecstream.h
streams with vector storage
These types are useful if you want a persistent buffer for formatted
text and you need to use it like a character array or character
pointer, as you get read-only access to it without copying. The
storage is always guaranteed to be contiguous. Writing to the
stream may invalidate pointers to storage.
***************************************************************************/
#ifndef MAME_UTIL_VECSTREAM_H
#define MAME_UTIL_VECSTREAM_H
#pragma once
#include <algorithm>
#include <cassert>
#include <ios>
#include <istream>
#include <ostream>
#include <memory>
#include <ostream>
#include <streambuf>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
namespace util {
template <typename CharT, typename Traits = std::char_traits<CharT>, typename Allocator = std::allocator<CharT> >
class basic_vectorbuf : public std::basic_streambuf<CharT, Traits>
{
public:
typedef typename std::basic_streambuf<CharT, Traits>::char_type char_type;
typedef typename std::basic_streambuf<CharT, Traits>::int_type int_type;
typedef typename std::basic_streambuf<CharT, Traits>::pos_type pos_type;
typedef typename std::basic_streambuf<CharT, Traits>::off_type off_type;
typedef Allocator allocator_type;
typedef std::vector<char_type, Allocator> vector_type;
basic_vectorbuf(std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) : std::basic_streambuf<CharT, Traits>(), m_mode(mode), m_storage(), m_threshold(nullptr)
{
setup();
}
basic_vectorbuf(vector_type const &content, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) : std::basic_streambuf<CharT, Traits>(), m_mode(mode), m_storage(content), m_threshold(nullptr)
{
setup();
}
basic_vectorbuf(vector_type &&content, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) : std::basic_streambuf<CharT, Traits>(), m_mode(mode), m_storage(std::move(content)), m_threshold(nullptr)
{
setup();
}
basic_vectorbuf(basic_vectorbuf const &that) : std::basic_streambuf<CharT, Traits>(that), m_mode(that.m_mode), m_storage(that.m_storage), m_threshold(nullptr)
{
adjust();
}
basic_vectorbuf(basic_vectorbuf &&that) : std::basic_streambuf<CharT, Traits>(that), m_mode(that.m_mode), m_storage(std::move(that.m_storage)), m_threshold(that.m_threshold)
{
that.clear();
}
vector_type const &vec() const
{
if (m_mode & std::ios_base::out)
{
if (this->pptr() > m_threshold) m_threshold = this->pptr();
auto const base(this->pbase());
auto const end(m_threshold - base);
if (m_storage.size() > std::make_unsigned_t<decltype(end)>(end))
{
m_storage.resize(std::make_unsigned_t<decltype(end)>(end));
assert(&m_storage[0] == base);
auto const put_offset(this->pptr() - base);
const_cast<basic_vectorbuf *>(this)->setp(base, base + put_offset);
const_cast<basic_vectorbuf *>(this)->pbump(put_offset);
}
}
return m_storage;
}
void vec(const vector_type &content)
{
m_storage = content;
setup();
}
void vec(vector_type &&content)
{
m_storage = std::move(content);
setup();
}
void clear()
{
m_storage.clear();
setup();
}
void swap(basic_vectorbuf &that)
{
using std::swap;
std::basic_streambuf<CharT, Traits>::swap(that);
swap(m_mode, that.m_mode);
swap(m_storage, that.m_storage);
swap(m_threshold, that.m_threshold);
}
void reserve(typename vector_type::size_type size)
{
if ((m_mode & std::ios_base::out) && (m_storage.capacity() < size))
{
m_storage.reserve(size);
adjust();
}
}
basic_vectorbuf &operator=(basic_vectorbuf const &that)
{
std::basic_streambuf<CharT, Traits>::operator=(that);
m_mode = that.m_mode;
m_storage = that.m_storage;
m_threshold = that.m_threshold;
adjust();
return *this;
}
basic_vectorbuf &operator=(basic_vectorbuf &&that)
{
std::basic_streambuf<CharT, Traits>::operator=(that);
m_mode = that.m_mode;
m_storage = std::move(that.m_storage);
m_threshold = that.m_threshold;
that.clear();
return *this;
}
protected:
virtual pos_type seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode which = std::ios_base::in | std::ios_base::out) override
{
bool const in(which & std::ios_base::in);
bool const out(which & std::ios_base::out);
if ((!in && !out) ||
(in && out && (std::ios_base::cur == dir)) ||
(in && !(m_mode & std::ios_base::in)) ||
(out && !(m_mode & std::ios_base::out)))
{
return pos_type(off_type(-1));
}
maximise_egptr();
off_type const end((m_mode & std::ios_base::out) ? off_type(m_threshold - this->pbase()) : off_type(m_storage.size()));
switch (dir)
{
case std::ios_base::beg:
break;
case std::ios_base::end:
off += end;
break;
case std::ios_base::cur:
off += off_type(in ? (this->gptr() - this->eback()) : (this->pptr() - this->pbase()));
break;
default:
return pos_type(off_type(-1));
}
if ((off_type(0) > off) || ((m_mode & std::ios_base::app) && out && (end != off))) return pos_type(off_type(-1));
if ((out ? off_type(this->epptr() - this->pbase()) : end) < off) return pos_type(off_type(-1));
if (out)
{
this->setp(this->pbase(), this->epptr());
this->pbump(off);
if (m_threshold < this->pptr()) m_threshold = this->pptr();
if (m_mode & std::ios_base::in)
{
if (in) this->setg(this->eback(), this->eback() + off, m_threshold);
else if (this->egptr() < m_threshold) this->setg(this->eback(), this->gptr(), m_threshold);
}
}
else if (in)
{
this->setg(this->eback(), this->eback() + off, this->egptr());
}
return pos_type(off);
}
virtual pos_type seekpos(pos_type pos, std::ios_base::openmode which = std::ios_base::in |std:: ios_base::out) override
{
return seekoff(off_type(pos), std::ios_base::beg, which);
}
virtual int_type underflow() override
{
if (!this->gptr()) return Traits::eof();
maximise_egptr();
return (this->gptr() < this->egptr()) ? Traits::to_int_type(*this->gptr()) : Traits::eof();
}
virtual int_type overflow(int_type ch = Traits::eof()) override
{
if (!(m_mode & std::ios_base::out)) return Traits::eof();
if (Traits::eq_int_type(ch, Traits::eof())) return Traits::not_eof(ch);
auto const put_offset(this->pptr() - this->pbase() + 1);
auto const threshold_offset((std::max)(m_threshold - this->pbase(), put_offset));
m_storage.push_back(Traits::to_char_type(ch));
m_storage.resize(m_storage.capacity());
auto const base(&m_storage[0]);
this->setp(base, base + m_storage.size());
m_threshold = base + threshold_offset;
if (m_mode & std::ios_base::in) this->setg(base, base + (this->gptr() - this->eback()), m_threshold);
this->pbump(int(put_offset));
return ch;
}
virtual int_type pbackfail(int_type ch = Traits::eof()) override
{
if (this->gptr() != this->eback())
{
if (Traits::eq_int_type(ch, Traits::eof()))
{
this->gbump(-1);
return Traits::not_eof(ch);
}
else if (Traits::eq(Traits::to_char_type(ch), this->gptr()[-1]))
{
this->gbump(-1);
return ch;
}
else if (m_mode & std::ios_base::out)
{
this->gbump(-1);
*this->gptr() = Traits::to_char_type(ch);
return ch;
}
}
return Traits::eof();
}
private:
void setup()
{
if (m_mode & std::ios_base::out)
{
auto const end(m_storage.size());
m_storage.resize(m_storage.capacity());
if (m_storage.empty())
{
m_threshold = nullptr;
this->setg(nullptr, nullptr, nullptr);
this->setp(nullptr, nullptr);
}
else
{
auto const base(&m_storage[0]);
m_threshold = base + end;
this->setp(base, base + m_storage.size());
if (m_mode & std::ios_base::in) this->setg(base, base, m_threshold);
}
if (m_mode & (std::ios_base::app | std::ios_base::ate)) this->pbump(int(unsigned(end)));
}
else if (m_storage.empty())
{
this->setg(nullptr, nullptr, nullptr);
}
else if (m_mode & std::ios_base::in)
{
auto const base(&m_storage[0]);
this->setg(base, base, base + m_storage.size());
}
}
void adjust()
{
auto const put_offset(this->pptr() - this->pbase());
auto const get_offset(this->gptr() - this->eback());
setup();
if (m_mode & std::ios_base::out)
{
this->pbump(int(put_offset));
m_threshold = this->pptr();
if (m_mode & std::ios_base::in)
{
auto const base(&m_storage[0]);
this->setg(base, base + get_offset, m_threshold);
}
}
else if (m_mode & std::ios_base::in)
{
this->gbump(int(get_offset));
}
}
void maximise_egptr()
{
if (m_mode & std::ios_base::out)
{
if (m_threshold < this->pptr()) m_threshold = this->pptr();
if ((m_mode & std::ios_base::in) && (this->egptr() < m_threshold)) this->setg(this->eback(), this->gptr(), m_threshold);
}
}
std::ios_base::openmode m_mode;
mutable vector_type m_storage;
mutable CharT *m_threshold;
};
template <typename CharT, typename Traits = std::char_traits<CharT>, typename Allocator = std::allocator<CharT> >
class basic_ivectorstream : public std::basic_istream<CharT, Traits>
{
public:
typedef typename basic_vectorbuf<CharT, Traits, Allocator>::vector_type vector_type;
basic_ivectorstream(std::ios_base::openmode mode = std::ios_base::in) : std::basic_istream<CharT, Traits>(&m_rdbuf), m_rdbuf(mode) { }
basic_ivectorstream(vector_type const &content, std::ios_base::openmode mode = std::ios_base::in) : std::basic_istream<CharT, Traits>(&m_rdbuf), m_rdbuf(content, mode) { }
basic_ivectorstream(vector_type &&content, std::ios_base::openmode mode = std::ios_base::in) : std::basic_istream<CharT, Traits>(&m_rdbuf), m_rdbuf(std::move(content), mode) { }
basic_vectorbuf<CharT, Traits, Allocator> *rdbuf() const { return static_cast<basic_vectorbuf<CharT, Traits, Allocator> *>(std::basic_istream<CharT, Traits>::rdbuf()); }
vector_type const &vec() const { return rdbuf()->vec(); }
void vec(const vector_type &content) { rdbuf()->vec(content); }
void vec(vector_type &&content) { rdbuf()->vec(std::move(content)); }
void swap(basic_ivectorstream &that) { std::basic_istream<CharT, Traits>::swap(that); rdbuf()->swap(*that.rdbuf()); }
private:
basic_vectorbuf<CharT, Traits, Allocator> m_rdbuf;
};
template <typename CharT, typename Traits = std::char_traits<CharT>, typename Allocator = std::allocator<CharT> >
class basic_ovectorstream : public std::basic_ostream<CharT, Traits>
{
public:
typedef typename basic_vectorbuf<CharT, Traits, Allocator>::vector_type vector_type;
basic_ovectorstream(std::ios_base::openmode mode = std::ios_base::out) : std::basic_ostream<CharT, Traits>(&m_rdbuf), m_rdbuf(mode) { }
basic_ovectorstream(vector_type const &content, std::ios_base::openmode mode = std::ios_base::out) : std::basic_ostream<CharT, Traits>(&m_rdbuf), m_rdbuf(content, mode) { }
basic_ovectorstream(vector_type &&content, std::ios_base::openmode mode = std::ios_base::out) : std::basic_ostream<CharT, Traits>(&m_rdbuf), m_rdbuf(std::move(content), mode) { }
basic_vectorbuf<CharT, Traits, Allocator> *rdbuf() const { return static_cast<basic_vectorbuf<CharT, Traits, Allocator> *>(std::basic_ostream<CharT, Traits>::rdbuf()); }
vector_type const &vec() const { return rdbuf()->vec(); }
void vec(const vector_type &content) { rdbuf()->vec(content); }
void vec(vector_type &&content) { rdbuf()->vec(std::move(content)); }
basic_ovectorstream &reserve(typename vector_type::size_type size) { rdbuf()->reserve(size); return *this; }
void swap(basic_ovectorstream &that) { std::basic_ostream<CharT, Traits>::swap(that); rdbuf()->swap(*that.rdbuf()); }
private:
basic_vectorbuf<CharT, Traits, Allocator> m_rdbuf;
};
template <typename CharT, typename Traits = std::char_traits<CharT>, typename Allocator = std::allocator<CharT> >
class basic_vectorstream : public std::basic_iostream<CharT, Traits>
{
public:
typedef typename basic_vectorbuf<CharT, Traits, Allocator>::vector_type vector_type;
basic_vectorstream(std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) : std::basic_iostream<CharT, Traits>(&m_rdbuf), m_rdbuf(mode) { }
basic_vectorstream(vector_type const &content, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) : std::basic_iostream<CharT, Traits>(&m_rdbuf), m_rdbuf(content, mode) { }
basic_vectorstream(vector_type &&content, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) : std::basic_iostream<CharT, Traits>(&m_rdbuf), m_rdbuf(std::move(content), mode) { }
basic_vectorbuf<CharT, Traits, Allocator> *rdbuf() const { return static_cast<basic_vectorbuf<CharT, Traits, Allocator> *>(std::basic_iostream<CharT, Traits>::rdbuf()); }
vector_type const &vec() const { return rdbuf()->vec(); }
void vec(const vector_type &content) { rdbuf()->vec(content); }
void vec(vector_type &&content) { rdbuf()->vec(std::move(content)); }
basic_vectorstream &reserve(typename vector_type::size_type size) { rdbuf()->reserve(size); return *this; }
void swap(basic_vectorstream &that) { std::basic_iostream<CharT, Traits>::swap(that); rdbuf()->swap(*that.rdbuf()); }
private:
basic_vectorbuf<CharT, Traits, Allocator> m_rdbuf;
};
typedef basic_ivectorstream<char> ivectorstream;
typedef basic_ivectorstream<wchar_t> wivectorstream;
typedef basic_ovectorstream<char> ovectorstream;
typedef basic_ovectorstream<wchar_t> wovectorstream;
typedef basic_vectorstream<char> vectorstream;
typedef basic_vectorstream<wchar_t> wvectorstream;
template <typename CharT, typename Traits, typename Allocator>
void swap(basic_vectorbuf<CharT, Traits, Allocator> &a, basic_vectorbuf<CharT, Traits, Allocator> &b) { a.swap(b); }
template <typename CharT, typename Traits, typename Allocator>
void swap(basic_ivectorstream<CharT, Traits, Allocator> &a, basic_ivectorstream<CharT, Traits, Allocator> &b) { a.swap(b); }
template <typename CharT, typename Traits, typename Allocator>
void swap(basic_ovectorstream<CharT, Traits, Allocator> &a, basic_ovectorstream<CharT, Traits, Allocator> &b) { a.swap(b); }
template <typename CharT, typename Traits, typename Allocator>
void swap(basic_vectorstream<CharT, Traits, Allocator> &a, basic_vectorstream<CharT, Traits, Allocator> &b) { a.swap(b); }
extern template class basic_ivectorstream<char>;
extern template class basic_ivectorstream<wchar_t>;
extern template class basic_ovectorstream<char>;
extern template class basic_ovectorstream<wchar_t>;
extern template class basic_vectorstream<char>;
extern template class basic_vectorstream<wchar_t>;
} // namespace util
#endif // MAME_UTIL_VECSTREAM_H

View File

@ -1,470 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
#ifndef MAME_INCLUDES_N64_H
#define MAME_INCLUDES_N64_H
#pragma once
#if defined(MAME_RDP)
#include "video/n64.h"
class running_machine
{
public:
running_machine(n64_state* state)
: m_state(state), m_rand_seed(0x9d14abd7)
{ }
template <class DriverClass> DriverClass *driver_data() const;
u32 rand()
{
m_rand_seed = 1664525 * m_rand_seed + 1013904223;
// return rotated by 16 bits; the low bits have a short period
// and are frequently used
return (m_rand_seed >> 16) | (m_rand_seed << 16);
}
private:
n64_state* m_state;
u32 m_rand_seed; // current random number seed
};
template <> inline n64_state *running_machine::driver_data() const { return m_state; }
class n64_state
{
public:
n64_state(uint32_t* rdram, uint32_t* rsp_dmem, n64_periphs* rcp_periphs)
: m_machine(this), m_rdram(rdram), m_rsp_dmem(rsp_dmem), m_rcp_periphs(rcp_periphs)
{ }
void video_start();
// Getters
n64_rdp* rdp() { return m_rdp.get(); }
running_machine& machine() { return m_machine; }
protected:
running_machine m_machine;
uint32_t* m_rdram;
uint32_t* m_rsp_dmem;
n64_periphs* m_rcp_periphs;
/* video-related */
std::unique_ptr<n64_rdp> m_rdp;
};
class n64_periphs
{
public:
virtual void dp_full_sync() = 0;
};
#else
#include "cpu/rsp/rsp.h"
#include "cpu/mips/mips3.h"
#include "sound/dmadac.h"
#include "video/n64.h"
/*----------- driver state -----------*/
class n64_rdp;
class n64_periphs;
class n64_state : public driver_device
{
public:
n64_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag)
, m_vr4300(*this, "maincpu")
, m_rsp(*this, "rsp")
, m_sram(*this, "sram")
, m_rdram(*this, "rdram")
, m_rsp_imem(*this, "rsp_imem")
, m_rsp_dmem(*this, "rsp_dmem")
, m_rcp_periphs(*this, "rcp")
{
}
virtual void machine_start() override;
virtual void machine_reset() override;
virtual void video_start() override;
void n64_machine_stop();
uint32_t screen_update_n64(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
DECLARE_WRITE_LINE_MEMBER(screen_vblank_n64);
// Getters
n64_rdp* rdp() { return m_rdp.get(); }
uint32_t* rdram() { return m_rdram; }
uint32_t* sram() { return m_sram; }
protected:
required_device<mips3_device> m_vr4300;
required_device<rsp_device> m_rsp;
optional_shared_ptr<uint32_t> m_sram;
required_shared_ptr<uint32_t> m_rdram;
required_shared_ptr<uint32_t> m_rsp_imem;
required_shared_ptr<uint32_t> m_rsp_dmem;
required_device<n64_periphs> m_rcp_periphs;
/* video-related */
std::unique_ptr<n64_rdp> m_rdp;
};
/*----------- devices -----------*/
#define AUDIO_DMA_DEPTH 2
struct n64_savable_data_t
{
uint8_t sram[0x20000];
uint8_t eeprom[2048];
uint8_t mempak[2][0x8000];
};
class n64_periphs : public device_t,
public device_video_interface
{
private:
struct AUDIO_DMA
{
uint32_t address;
uint32_t length;
};
public:
// construction/destruction
n64_periphs(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
uint32_t is64_r(offs_t offset);
void is64_w(offs_t offset, uint32_t data);
uint32_t open_r(offs_t offset);
void open_w(uint32_t data);
uint32_t rdram_reg_r(offs_t offset, uint32_t mem_mask = ~0);
void rdram_reg_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
uint32_t mi_reg_r(offs_t offset, uint32_t mem_mask = ~0);
void mi_reg_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
uint32_t vi_reg_r(offs_t offset, uint32_t mem_mask = ~0);
void vi_reg_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
uint32_t ai_reg_r(offs_t offset, uint32_t mem_mask = ~0);
void ai_reg_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
uint32_t pi_reg_r(offs_t offset, uint32_t mem_mask = ~0);
void pi_reg_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
uint32_t ri_reg_r(offs_t offset, uint32_t mem_mask = ~0);
void ri_reg_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
uint32_t si_reg_r(offs_t offset);
void si_reg_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
uint32_t dd_reg_r(offs_t offset);
void dd_reg_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
uint32_t pif_ram_r(offs_t offset, uint32_t mem_mask = ~0);
void pif_ram_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
TIMER_CALLBACK_MEMBER(reset_timer_callback);
TIMER_CALLBACK_MEMBER(vi_scanline_callback);
TIMER_CALLBACK_MEMBER(dp_delay_callback);
TIMER_CALLBACK_MEMBER(ai_timer_callback);
TIMER_CALLBACK_MEMBER(pi_dma_callback);
TIMER_CALLBACK_MEMBER(si_dma_callback);
uint32_t dp_reg_r(offs_t offset, uint32_t mem_mask = ~0);
void dp_reg_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
uint32_t sp_reg_r(offs_t offset);
void sp_reg_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
void sp_set_status(uint32_t data);
void signal_rcp_interrupt(int interrupt);
void check_interrupts();
void dp_full_sync();
void ai_timer_tick();
void pi_dma_tick();
void si_dma_tick();
void reset_tick();
void video_update(bitmap_rgb32 &bitmap);
// Video Interface (VI) registers
uint32_t vi_width;
uint32_t vi_origin;
uint32_t vi_control;
uint32_t vi_blank;
uint32_t vi_hstart;
uint32_t vi_vstart;
uint32_t vi_xscale;
uint32_t vi_yscale;
uint32_t vi_burst;
uint32_t vi_vsync;
uint32_t vi_hsync;
uint32_t vi_leap;
uint32_t vi_intr;
uint32_t vi_vburst;
uint8_t field;
// nvram-specific for the console
device_t *m_nvram_image;
n64_savable_data_t m_save_data;
uint32_t cart_length;
bool dd_present;
bool disk_present;
bool cart_present;
// Mouse X2/Y2 for delta position
int mouse_x2[4];
int mouse_y2[4];
void poll_reset_button(bool button);
uint32_t dp_clock;
protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
private:
n64_state* m_n64;
address_space *m_mem_map;
required_device<mips3_device> m_vr4300;
required_device<rsp_device> m_rsp;
required_shared_ptr<uint32_t> m_rsp_imem;
required_shared_ptr<uint32_t> m_rsp_dmem;
uint32_t *m_rdram;
uint32_t *m_sram;
void clear_rcp_interrupt(int interrupt);
bool reset_held;
emu_timer *reset_timer;
emu_timer *dp_delay_timer;
uint8_t is64_buffer[0x10000];
// Video interface (VI) registers and functions
emu_timer *vi_scanline_timer;
// Audio Interface (AI) registers and functions
void ai_dma();
AUDIO_DMA *ai_fifo_get_top();
void ai_fifo_push(uint32_t address, uint32_t length);
void ai_fifo_pop();
bool ai_delayed_carry;
required_device_array<dmadac_sound_device, 2> ai_dac;
uint32_t ai_dram_addr;
uint32_t ai_len;
uint32_t ai_control;
int ai_dacrate;
int ai_bitrate;
uint32_t ai_status;
emu_timer *ai_timer;
AUDIO_DMA ai_fifo[AUDIO_DMA_DEPTH];
int ai_fifo_wpos;
int ai_fifo_rpos;
int ai_fifo_num;
// Memory Interface (MI) registers
uint32_t mi_version;
uint32_t mi_interrupt;
uint32_t mi_intr_mask;
uint32_t mi_mode;
// RDRAM Interface (RI) registers
uint32_t rdram_regs[10];
uint32_t ri_regs[8];
// RSP Interface (SP) registers
void sp_dma(int direction);
uint32_t sp_mem_addr;
uint32_t sp_dram_addr;
uint32_t sp_mem_addr_start;
uint32_t sp_dram_addr_start;
int sp_dma_length;
int sp_dma_count;
int sp_dma_skip;
uint32_t sp_semaphore;
// Disk Drive (DD) registers and functions
void dd_set_zone_and_track_offset();
void dd_update_bm();
void dd_write_sector();
void dd_read_sector();
void dd_read_C2();
uint32_t dd_buffer[256];
uint32_t dd_sector_data[64];
uint32_t dd_ram_seq_data[16];
uint32_t dd_data_reg;
uint32_t dd_status_reg;
uint32_t dd_track_reg;
uint32_t dd_buf_status_reg;
uint32_t dd_sector_err_reg;
uint32_t dd_seq_status_reg;
uint32_t dd_seq_ctrl_reg;
uint32_t dd_sector_reg;
uint32_t dd_reset_reg;
uint32_t dd_current_reg;
bool dd_bm_reset_held;
bool dd_write;
uint8_t dd_int;
uint8_t dd_start_block;
uint8_t dd_start_sector;
uint8_t dd_sectors_per_block;
uint8_t dd_sector_size;
uint8_t dd_zone;
uint32_t dd_track_offset;
// Peripheral Interface (PI) registers and functions
emu_timer *pi_dma_timer;
uint32_t pi_dram_addr;
uint32_t pi_cart_addr;
uint32_t pi_rd_len;
uint32_t pi_wr_len;
uint32_t pi_status;
uint32_t pi_bsd_dom1_lat;
uint32_t pi_bsd_dom1_pwd;
uint32_t pi_bsd_dom1_pgs;
uint32_t pi_bsd_dom1_rls;
uint32_t pi_bsd_dom2_lat;
uint32_t pi_bsd_dom2_pwd;
uint32_t pi_bsd_dom2_pgs;
uint32_t pi_bsd_dom2_rls;
uint32_t pi_dma_dir;
// Serial Interface (SI) registers and functions
emu_timer *si_dma_timer;
void pif_dma(int direction);
void handle_pif();
int pif_channel_handle_command(int channel, int slength, uint8_t *sdata, int rlength, uint8_t *rdata);
uint8_t calc_mempak_crc(uint8_t *buffer, int length);
uint8_t pif_ram[0x40];
uint8_t pif_cmd[0x40];
uint32_t si_dram_addr;
uint32_t si_pif_addr;
uint32_t si_pif_addr_rd64b;
uint32_t si_pif_addr_wr64b;
uint32_t si_status_val;
uint32_t si_dma_dir;
uint32_t cic_status;
int cic_type;
n64_savable_data_t savable_data;
// Video Interface (VI) functions
void vi_recalculate_resolution();
void video_update16(bitmap_rgb32 &bitmap);
void video_update32(bitmap_rgb32 &bitmap);
uint8_t random_seed; // %HACK%, adds 19 each time it's read and is more or less random
uint8_t get_random() { return random_seed += 0x13; }
int32_t m_gamma_table[256];
int32_t m_gamma_dither_table[0x4000];
};
// device type definition
DECLARE_DEVICE_TYPE(N64PERIPH, n64_periphs)
#endif
/*----------- defined in video/n64.c -----------*/
#define DACRATE_NTSC (48681812)
#define DACRATE_PAL (49656530)
#define DACRATE_MPAL (48628316)
/*----------- defined in machine/n64.c -----------*/
#define SP_INTERRUPT 0x1
#define SI_INTERRUPT 0x2
#define AI_INTERRUPT 0x4
#define VI_INTERRUPT 0x8
#define PI_INTERRUPT 0x10
#define DP_INTERRUPT 0x20
#define SP_STATUS_HALT 0x0001
#define SP_STATUS_BROKE 0x0002
#define SP_STATUS_DMABUSY 0x0004
#define SP_STATUS_DMAFULL 0x0008
#define SP_STATUS_IOFULL 0x0010
#define SP_STATUS_SSTEP 0x0020
#define SP_STATUS_INTR_BREAK 0x0040
#define SP_STATUS_SIGNAL0 0x0080
#define SP_STATUS_SIGNAL1 0x0100
#define SP_STATUS_SIGNAL2 0x0200
#define SP_STATUS_SIGNAL3 0x0400
#define SP_STATUS_SIGNAL4 0x0800
#define SP_STATUS_SIGNAL5 0x1000
#define SP_STATUS_SIGNAL6 0x2000
#define SP_STATUS_SIGNAL7 0x4000
#define DP_STATUS_XBUS_DMA 0x01
#define DP_STATUS_FREEZE 0x02
#define DP_STATUS_FLUSH 0x04
#define DP_STATUS_START_VALID 0x400
#define DD_ASIC_STATUS_DISK_CHANGE 0x00010000
#define DD_ASIC_STATUS_MECHA_ERR 0x00020000
#define DD_ASIC_STATUS_WRPROTECT_ERR 0x00040000
#define DD_ASIC_STATUS_HEAD_RETRACT 0x00080000
#define DD_ASIC_STATUS_MOTOR_OFF 0x00100000
#define DD_ASIC_STATUS_RESET 0x00400000
#define DD_ASIC_STATUS_BUSY 0x00800000
#define DD_ASIC_STATUS_DISK 0x01000000
#define DD_ASIC_STATUS_MECHA_INT 0x02000000
#define DD_ASIC_STATUS_BM_INT 0x04000000
#define DD_ASIC_STATUS_BM_ERROR 0x08000000
#define DD_ASIC_STATUS_C2_XFER 0x10000000
#define DD_ASIC_STATUS_DREQ 0x40000000
#define DD_TRACK_INDEX_LOCK 0x60000000
#define DD_BM_MECHA_INT_RESET 0x01000000
#define DD_BM_XFERBLOCKS 0x02000000
#define DD_BM_DISABLE_C1 0x04000000
#define DD_BM_DISABLE_OR_CHK 0x08000000
#define DD_BM_RESET 0x10000000
#define DD_BM_INT_MASK 0x20000000
#define DD_BM_MODE 0x40000000
#define DD_BM_START 0x80000000
#define DD_BMST_RUNNING 0x80000000
#define DD_BMST_ERROR 0x04000000
#define DD_BMST_MICRO_STATUS 0x02000000
#define DD_BMST_BLOCKS 0x01000000
#define DD_BMST_C1_CORRECT 0x00800000
#define DD_BMST_C1_DOUBLE 0x00400000
#define DD_BMST_C1_SINGLE 0x00200000
#define DD_BMST_C1_ERROR 0x00010000
#define DD_ASIC_ERR_AM_FAIL 0x80000000
#define DD_ASIC_ERR_MICRO_FAIL 0x40000000
#define DD_ASIC_ERR_SPINDLE_FAIL 0x20000000
#define DD_ASIC_ERR_OVER_RUN 0x10000000
#define DD_ASIC_ERR_OFFTRACK 0x08000000
#define DD_ASIC_ERR_NO_DISK 0x04000000
#define DD_ASIC_ERR_CLOCK_UNLOCK 0x02000000
#define DD_ASIC_ERR_SELF_STOP 0x01000000
#define DD_SEQ_MICRO_INT_MASK 0x80000000
#define DD_SEQ_MICRO_PC_ENABLE 0x40000000
#define SECTORS_PER_BLOCK 85
#define BLOCKS_PER_TRACK 2
const unsigned int ddZoneSecSize[16] = {232,216,208,192,176,160,144,128,
216,208,192,176,160,144,128,112};
const unsigned int ddZoneTrackSize[16] = {158,158,149,149,149,149,149,114,
158,158,149,149,149,149,149,114};
const unsigned int ddStartOffset[16] =
{0x0,0x5F15E0,0xB79D00,0x10801A0,0x1523720,0x1963D80,0x1D414C0,0x20BBCE0,
0x23196E0,0x28A1E00,0x2DF5DC0,0x3299340,0x36D99A0,0x3AB70E0,0x3E31900,0x4149200};
#endif // MAME_INCLUDES_N64_H

File diff suppressed because it is too large Load Diff

View File

@ -1,426 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
#ifndef _VIDEO_N64_H_
#define _VIDEO_N64_H_
#include "video/poly.h"
#include "pin64.h"
/*****************************************************************************/
#define PIXEL_SIZE_4BIT 0
#define PIXEL_SIZE_8BIT 1
#define PIXEL_SIZE_16BIT 2
#define PIXEL_SIZE_32BIT 3
#define CYCLE_TYPE_1 0
#define CYCLE_TYPE_2 1
#define CYCLE_TYPE_COPY 2
#define CYCLE_TYPE_FILL 3
#define SAMPLE_TYPE_1x1 0
#define SAMPLE_TYPE_2x2 1
#define BYTE_ADDR_XOR BYTE4_XOR_BE(0)
#define WORD_ADDR_XOR (WORD_XOR_BE(0) >> 1)
#define XOR_SWAP_BYTE_SHIFT 2
#define XOR_SWAP_WORD_SHIFT 1
#define XOR_SWAP_DWORD_SHIFT 0
#define XOR_SWAP_BYTE 4
#define XOR_SWAP_WORD 2
#define XOR_SWAP_DWORD 1
#define FORMAT_RGBA 0
#define FORMAT_YUV 1
#define FORMAT_CI 2
#define FORMAT_IA 3
#define FORMAT_I 4
#ifdef LSB_FIRST
#define BYTE_XOR_DWORD_SWAP 7
#define WORD_XOR_DWORD_SWAP 3
#else
#define BYTE_XOR_DWORD_SWAP 4
#define WORD_XOR_DWORD_SWAP 2
#endif
#define DWORD_XOR_DWORD_SWAP 1
#define GET_LOW_RGBA16_TMEM(x) (m_rdp->m_replicated_rgba[((x) >> 1) & 0x1f])
#define GET_MED_RGBA16_TMEM(x) (m_rdp->m_replicated_rgba[((x) >> 6) & 0x1f])
#define GET_HI_RGBA16_TMEM(x) (m_rdp->m_replicated_rgba[((x) >> 11) & 0x1f])
#define MEM8_LIMIT 0x7fffff
#define MEM16_LIMIT 0x3fffff
#define MEM32_LIMIT 0x1fffff
#define RDP_RANGE_CHECK (0)
#if RDP_RANGE_CHECK
#define CHECK8(in) if(rdp_range_check((in))) { printf("Check8: Address %08x out of range!\n", (in)); fflush(stdout); fatalerror("Address %08x out of range!\n", (in)); }
#define CHECK16(in) if(rdp_range_check((in) << 1)) { printf("Check16: Address %08x out of range!\n", (in) << 1); fflush(stdout); fatalerror("Address %08x out of range!\n", (in) << 1); }
#define CHECK32(in) if(rdp_range_check((in) << 2)) { printf("Check32: Address %08x out of range!\n", (in) << 2); fflush(stdout); fatalerror("Address %08x out of range!\n", (in) << 2); }
#else
#define CHECK8(in) { }
#define CHECK16(in) { }
#define CHECK32(in) { }
#endif
#if RDP_RANGE_CHECK
#define RREADADDR8(in) ((rdp_range_check((in))) ? 0 : (((uint8_t*)m_rdram)[(in) ^ BYTE_ADDR_XOR]))
#define RREADIDX16(in) ((rdp_range_check((in) << 1)) ? 0 : (((uint16_t*)m_rdram)[(in) ^ WORD_ADDR_XOR]))
#define RREADIDX32(in) ((rdp_range_check((in) << 2)) ? 0 : m_rdram[(in)])
#define RWRITEADDR8(in, val) if(rdp_range_check((in))) { printf("Write8: Address %08x out of range!\n", (in)); fflush(stdout); fatalerror("Address %08x out of range!\n", (in)); } else { ((uint8_t*)m_rdram)[(in) ^ BYTE_ADDR_XOR] = val;}
#define RWRITEIDX16(in, val) if(rdp_range_check((in) << 1)) { printf("Write16: Address %08x out of range!\n", ((object.m_misc_state.m_fb_address >> 1) + curpixel) << 1); fflush(stdout); fatalerror("Address out of range\n"); } else { ((uint16_t*)m_rdram)[(in) ^ WORD_ADDR_XOR] = val;}
#define RWRITEIDX32(in, val) if(rdp_range_check((in) << 2)) { printf("Write32: Address %08x out of range!\n", (in) << 2); fflush(stdout); fatalerror("Address %08x out of range!\n", (in) << 2); } else { m_rdram[(in)] = val;}
#else
#define RREADADDR8(in) (((uint8_t*)m_rdram)[(in) ^ BYTE_ADDR_XOR])
#define RREADIDX16(in) (((uint16_t*)m_rdram)[(in) ^ WORD_ADDR_XOR])
#define RREADIDX32(in) (m_rdram[(in)])
#define RWRITEADDR8(in, val) ((uint8_t*)m_rdram)[(in) ^ BYTE_ADDR_XOR] = val;
#define RWRITEIDX16(in, val) ((uint16_t*)m_rdram)[(in) ^ WORD_ADDR_XOR] = val;
#define RWRITEIDX32(in, val) m_rdram[(in)] = val
#endif
#define U_RREADADDR8(in) (((uint8_t*)m_rdram)[(in) ^ BYTE_ADDR_XOR])
#define U_RREADIDX16(in) (((uint16_t*)m_rdram)[(in) ^ WORD_ADDR_XOR])
#define U_RREADIDX32(in) (m_rdram[(in)])
#define GETLOWCOL(x) (((x) & 0x3e) << 2)
#define GETMEDCOL(x) (((x) & 0x7c0) >> 3)
#define GETHICOL(x) (((x) & 0xf800) >> 8)
#define HREADADDR8(in) /*(((in) <= MEM8_LIMIT) ? */(m_hidden_bits[(in) ^ BYTE_ADDR_XOR])/* : 0)*/
#define HWRITEADDR8(in, val) /*{if ((in) <= MEM8_LIMIT) */m_hidden_bits[(in) ^ BYTE_ADDR_XOR] = val;/*}*/
//sign-extension macros
#define SIGN22(x) (((x & 0x00200000) * 0x7ff) | (x & 0x1fffff))
#define SIGN17(x) (((x & 0x00010000) * 0xffff) | (x & 0xffff))
#define SIGN16(x) (((x & 0x00008000) * 0x1ffff) | (x & 0x7fff))
#define SIGN13(x) (((x & 0x00001000) * 0xfffff) | (x & 0xfff))
#define SIGN11(x) (((x & 0x00000400) * 0x3fffff) | (x & 0x3ff))
#define SIGN9(x) (((x & 0x00000100) * 0xffffff) | (x & 0xff))
#define SIGN8(x) (((x & 0x00000080) * 0x1ffffff) | (x & 0x7f))
#define KURT_AKELEY_SIGN9(x) ((((x) & 0x180) == 0x180) ? ((x) | ~0x1ff) : ((x) & 0x1ff))
#define SPAN_R (0)
#define SPAN_G (1)
#define SPAN_B (2)
#define SPAN_A (3)
#define SPAN_S (4)
#define SPAN_T (5)
#define SPAN_W (6)
#define SPAN_Z (7)
#define EXTENT_AUX_COUNT (sizeof(rdp_span_aux)*(480*192)) // Screen coverage *192, more or less
/*****************************************************************************/
class n64_periphs;
class n64_rdp;
#include "video/n64types.h"
#include "video/rdpblend.h"
#include "video/rdptpipe.h"
class n64_state;
class n64_rdp : public poly_manager<uint32_t, rdp_poly_state, 8>
{
public:
n64_rdp(n64_state &state, uint32_t* rdram, uint32_t* dmem);
running_machine &machine() const { assert(m_machine != nullptr); return *m_machine; }
void init_internal_state()
{
m_tmem = std::make_unique<uint8_t[]>(0x1000);
memset(m_tmem.get(), 0, 0x1000);
#if !defined(MAME_RDP)
uint8_t* normpoint = machine().root_device().memregion("normpoint")->base();
uint8_t* normslope = machine().root_device().memregion("normslope")->base();
for(int32_t i = 0; i < 64; i++)
{
m_norm_point_rom[i] = (normpoint[(i << 1) + 1] << 8) | normpoint[i << 1];
m_norm_slope_rom[i] = (normslope[(i << 1) + 1] << 8) | normslope[i << 1];
}
#endif
memset(m_tiles, 0, 8 * sizeof(n64_tile_t));
memset(m_cmd_data, 0, sizeof(m_cmd_data));
for (int32_t i = 0; i < 8; i++)
{
m_tiles[i].num = i;
m_tiles[i].invmm = rgbaint_t(~0, ~0, ~0, ~0);
m_tiles[i].invmask = rgbaint_t(~0, ~0, ~0, ~0);
}
}
void process_command_list();
uint64_t read_data(uint32_t address);
void disassemble(uint64_t *cmd_buf, char* buffer);
void set_machine(running_machine& machine) { m_machine = &machine; }
void set_n64_periphs(n64_periphs* periphs) { m_n64_periphs = periphs; }
// CPU-visible registers
void set_start(uint32_t val) { m_start = val; }
uint32_t get_start() const { return m_start; }
void set_end(uint32_t val) { m_end = val; }
uint32_t get_end() const { return m_end; }
void set_current(uint32_t val) { m_current = val; }
uint32_t get_current() const { return m_current; }
void set_status(uint32_t val) { m_status = val; }
uint32_t get_status() const { return m_status; }
// Color Combiner
int32_t color_combiner_equation(int32_t a, int32_t b, int32_t c, int32_t d);
int32_t alpha_combiner_equation(int32_t a, int32_t b, int32_t c, int32_t d);
void set_suba_input_rgb(color_t** input, int32_t code, rdp_span_aux* userdata);
void set_subb_input_rgb(color_t** input, int32_t code, rdp_span_aux* userdata);
void set_mul_input_rgb(color_t** input, int32_t code, rdp_span_aux* userdata);
void set_add_input_rgb(color_t** input, int32_t code, rdp_span_aux* userdata);
void set_sub_input_alpha(color_t** input, int32_t code, rdp_span_aux* userdata);
void set_mul_input_alpha(color_t** input, int32_t code, rdp_span_aux* userdata);
// Texture memory
uint8_t* get_tmem8() { return m_tmem.get(); }
uint16_t* get_tmem16() { return (uint16_t*)m_tmem.get(); }
// YUV Factors
void set_yuv_factors(color_t k02, color_t k13, color_t k4, color_t k5) { m_k02 = k02; m_k13 = k13; m_k4 = k4; m_k5 = k5; }
color_t& get_k02() { return m_k02; }
color_t& get_k13() { return m_k13; }
// Blender-related (move into RDP::Blender)
void set_blender_input(int32_t cycle, int32_t which, color_t** input_rgb, color_t** input_a, int32_t a, int32_t b, rdp_span_aux* userdata);
// Span rasterization
void span_draw_1cycle(int32_t scanline, const extent_t &extent, const rdp_poly_state &object, int32_t threadid);
void span_draw_2cycle(int32_t scanline, const extent_t &extent, const rdp_poly_state &object, int32_t threadid);
void span_draw_copy(int32_t scanline, const extent_t &extent, const rdp_poly_state &object, int32_t threadid);
void span_draw_fill(int32_t scanline, const extent_t &extent, const rdp_poly_state &object, int32_t threadid);
// Render-related (move into eventual drawing-related classes?)
void tc_div(int32_t ss, int32_t st, int32_t sw, int32_t* sss, int32_t* sst);
void tc_div_no_perspective(int32_t ss, int32_t st, int32_t sw, int32_t* sss, int32_t* sst);
uint32_t get_log2(uint32_t lod_clamp);
void render_spans(int32_t start, int32_t end, int32_t tilenum, bool flip, extent_t* spans, bool rect, rdp_poly_state* object);
int32_t get_alpha_cvg(int32_t comb_alpha, rdp_span_aux* userdata, const rdp_poly_state &object);
void z_store(const rdp_poly_state &object, uint32_t zcurpixel, uint32_t dzcurpixel, uint32_t z, uint32_t enc);
uint32_t z_decompress(uint32_t zcurpixel);
uint32_t dz_decompress(uint32_t zcurpixel, uint32_t dzcurpixel);
uint32_t dz_compress(uint32_t value);
int32_t normalize_dzpix(int32_t sum);
bool z_compare(uint32_t zcurpixel, uint32_t dzcurpixel, uint32_t sz, uint16_t dzpix, rdp_span_aux* userdata, const rdp_poly_state &object);
// Commands
void cmd_noop(uint64_t *cmd_buf);
void cmd_tex_rect(uint64_t *cmd_buf);
void cmd_tex_rect_flip(uint64_t *cmd_buf);
void cmd_sync_load(uint64_t *cmd_buf);
void cmd_sync_pipe(uint64_t *cmd_buf);
void cmd_sync_tile(uint64_t *cmd_buf);
void cmd_sync_full(uint64_t *cmd_buf);
void cmd_set_key_gb(uint64_t *cmd_buf);
void cmd_set_key_r(uint64_t *cmd_buf);
void cmd_set_fill_color32(uint64_t *cmd_buf);
void cmd_set_convert(uint64_t *cmd_buf);
void cmd_set_scissor(uint64_t *cmd_buf);
void cmd_set_prim_depth(uint64_t *cmd_buf);
void cmd_set_other_modes(uint64_t *cmd_buf);
void cmd_load_tlut(uint64_t *cmd_buf);
void cmd_set_tile_size(uint64_t *cmd_buf);
void cmd_load_block(uint64_t *cmd_buf);
void cmd_load_tile(uint64_t *cmd_buf);
void cmd_fill_rect(uint64_t *cmd_buf);
void cmd_set_tile(uint64_t *cmd_buf);
void cmd_set_fog_color(uint64_t *cmd_buf);
void cmd_set_blend_color(uint64_t *cmd_buf);
void cmd_set_prim_color(uint64_t *cmd_buf);
void cmd_set_env_color(uint64_t *cmd_buf);
void cmd_set_combine(uint64_t *cmd_buf);
void cmd_set_texture_image(uint64_t *cmd_buf);
void cmd_set_mask_image(uint64_t *cmd_buf);
void cmd_set_color_image(uint64_t *cmd_buf);
void rgbaz_clip(int32_t sr, int32_t sg, int32_t sb, int32_t sa, int32_t* sz, rdp_span_aux* userdata);
void rgbaz_correct_triangle(int32_t offx, int32_t offy, int32_t* r, int32_t* g, int32_t* b, int32_t* a, int32_t* z, rdp_span_aux* userdata, const rdp_poly_state &object);
void triangle(uint64_t *cmd_buf, bool shade, bool texture, bool zbuffer);
void get_dither_values(int32_t x, int32_t y, int32_t* cdith, int32_t* adith, const rdp_poly_state &object);
uint16_t decompress_cvmask_frombyte(uint8_t x);
void lookup_cvmask_derivatives(uint32_t mask, uint8_t* offx, uint8_t* offy, rdp_span_aux* userdata);
void mark_frame() { m_capture.mark_frame(*m_machine); }
misc_state_t m_misc_state;
// Color constants
color_t m_blend_color; /* constant blend color */
color_t m_prim_color; /* flat primitive color */
color_t m_prim_alpha; /* flat primitive alpha */
color_t m_env_color; /* generic color constant ('environment') */
color_t m_env_alpha; /* generic alpha constant ('environment') */
color_t m_fog_color; /* generic color constant ('fog') */
color_t m_key_scale; /* color-keying constant */
color_t m_lod_fraction; /* Z-based LOD fraction for this poly */
color_t m_prim_lod_fraction; /* fixed LOD fraction for this poly */
color_t m_one;
color_t m_zero;
uint32_t m_fill_color;
other_modes_t m_other_modes;
n64_blender_t m_blender;
n64_texture_pipe_t m_tex_pipe;
uint8_t m_hidden_bits[0x800000];
uint8_t m_replicated_rgba[32];
uint16_t m_dzpix_normalize[0x10000];
rectangle_t m_scissor;
span_base_t m_span_base;
void draw_triangle(uint64_t *cmd_buf, bool shade, bool texture, bool zbuffer, bool rect);
std::unique_ptr<uint8_t[]> m_aux_buf;
uint32_t m_aux_buf_ptr;
uint32_t m_aux_buf_index;
bool rdp_range_check(uint32_t addr);
n64_tile_t m_tiles[8];
private:
void compute_cvg_noflip(extent_t* spans, int32_t* majorx, int32_t* minorx, int32_t* majorxint, int32_t* minorxint, int32_t scanline, int32_t yh, int32_t yl, int32_t base);
void compute_cvg_flip(extent_t* spans, int32_t* majorx, int32_t* minorx, int32_t* majorxint, int32_t* minorxint, int32_t scanline, int32_t yh, int32_t yl, int32_t base);
void write_pixel4(uint32_t curpixel, color_t& color, rdp_span_aux* userdata, const rdp_poly_state &object);
void write_pixel8(uint32_t curpixel, color_t& color, rdp_span_aux* userdata, const rdp_poly_state &object);
void write_pixel16(uint32_t curpixel, color_t& color, rdp_span_aux* userdata, const rdp_poly_state &object);
void write_pixel32(uint32_t curpixel, color_t& color, rdp_span_aux* userdata, const rdp_poly_state &object);
void read_pixel4(uint32_t curpixel, rdp_span_aux* userdata, const rdp_poly_state &object);
void read_pixel8(uint32_t curpixel, rdp_span_aux* userdata, const rdp_poly_state &object);
void read_pixel16(uint32_t curpixel, rdp_span_aux* userdata, const rdp_poly_state &object);
void read_pixel32(uint32_t curpixel, rdp_span_aux* userdata, const rdp_poly_state &object);
void copy_pixel4(uint32_t curpixel, color_t& color, const rdp_poly_state &object);
void copy_pixel8(uint32_t curpixel, color_t& color, const rdp_poly_state &object);
void copy_pixel16(uint32_t curpixel, color_t& color, const rdp_poly_state &object);
void copy_pixel32(uint32_t curpixel, color_t& color, const rdp_poly_state &object);
void fill_pixel4(uint32_t curpixel, const rdp_poly_state &object);
void fill_pixel8(uint32_t curpixel, const rdp_poly_state &object);
void fill_pixel16(uint32_t curpixel, const rdp_poly_state &object);
void fill_pixel32(uint32_t curpixel, const rdp_poly_state &object);
void precalc_cvmask_derivatives(void);
void z_build_com_table(void);
typedef void (n64_rdp::*compute_cvg_t) (extent_t* spans, int32_t* majorx, int32_t* minorx, int32_t* majorxint, int32_t* minorxint, int32_t scanline, int32_t yh, int32_t yl, int32_t base);
compute_cvg_t m_compute_cvg[2];
typedef void (n64_rdp::*write_pixel_t) (uint32_t curpixel, color_t& color, rdp_span_aux* userdata, const rdp_poly_state &object);
typedef void (n64_rdp::*read_pixel_t) (uint32_t curpixel, rdp_span_aux* userdata, const rdp_poly_state &object);
typedef void (n64_rdp::*copy_pixel_t) (uint32_t curpixel, color_t& color, const rdp_poly_state &object);
typedef void (n64_rdp::*fill_pixel_t) (uint32_t curpixel, const rdp_poly_state &object);
write_pixel_t m_write_pixel[4];
read_pixel_t m_read_pixel[4];
copy_pixel_t m_copy_pixel[4];
fill_pixel_t m_fill_pixel[4];
running_machine* m_machine;
uint32_t* m_rdram;
uint32_t* m_dmem;
n64_periphs* m_n64_periphs;
combine_modes_t m_combine;
bool m_pending_mode_block;
bool m_pipe_clean;
cv_mask_derivative_t cvarray[(1 << 8)];
uint16_t m_z_com_table[0x40000]; //precalced table of compressed z values, 18b: 512 KB array!
uint32_t m_z_complete_dec_table[0x4000]; //the same for decompressed z values, 14b
uint8_t m_compressed_cvmasks[0x10000]; //16bit cvmask -> to byte
uint64_t m_cmd_data[0x800];
uint64_t m_temp_rect_data[0x800];
uint32_t m_start;
uint32_t m_end;
uint32_t m_current;
uint32_t m_status;
std::unique_ptr<uint8_t[]> m_tmem;
// YUV factors
color_t m_k02;
color_t m_k13;
color_t m_k4;
color_t m_k5;
// Texture perspective division
#if !defined(MAME_RDP)
int32_t m_norm_point_rom[64];
int32_t m_norm_slope_rom[64];
#else
int32_t m_norm_point_rom[64] =
{
0x4000, 0x3f04, 0x3e10, 0x3d22, 0x3c3c, 0x3b5d, 0x3a83, 0x39b1,
0x38e4, 0x381c, 0x375a, 0x369d, 0x35e5, 0x3532, 0x3483, 0x33d9,
0x3333, 0x3291, 0x31f4, 0x3159, 0x30c3, 0x3030, 0x2fa1, 0x2f15,
0x2e8c, 0x2e06, 0x2d83, 0x2d03, 0x2c86, 0x2c0b, 0x2b93, 0x2b1e,
0x2aab, 0x2a3a, 0x29cc, 0x2960, 0x28f6, 0x288e, 0x2828, 0x27c4,
0x2762, 0x2702, 0x26a4, 0x2648, 0x25ed, 0x2594, 0x253d, 0x24e7,
0x2492, 0x243f, 0x23ee, 0x239e, 0x234f, 0x2302, 0x22b6, 0x226c,
0x2222, 0x21da, 0x2193, 0x214d, 0x2108, 0x20c5, 0x2082, 0x2041,
};
int32_t m_norm_slope_rom[64] =
{
0xfc, 0xf4, 0xee, 0xe6, 0xdf, 0xda, 0xd2, 0xcd,
0xc8, 0xc2, 0xbd, 0xb8, 0xb3, 0xaf, 0xaa, 0xa6,
0xa2, 0x9d, 0x9b, 0x96, 0x93, 0x8f, 0x8c, 0x89,
0x86, 0x83, 0x80, 0x7d, 0x7b, 0x78, 0x75, 0x73,
0x71, 0x6e, 0x6c, 0x6a, 0x68, 0x66, 0x64, 0x62,
0x60, 0x5e, 0x5c, 0x5b, 0x59, 0x57, 0x56, 0x55,
0x53, 0x51, 0x50, 0x4f, 0x4d, 0x4c, 0x4a, 0x4a,
0x48, 0x47, 0x46, 0x45, 0x43, 0x43, 0x41, 0x41,
};
#endif
pin64_t m_capture;
static uint32_t s_special_9bit_clamptable[512];
static z_decompress_entry_t const m_z_dec_table[8];
static uint8_t const s_bayer_matrix[16];
static uint8_t const s_magic_matrix[16];
static int32_t const s_rdp_command_length[];
static char const *const s_image_format[];
static char const *const s_image_size[];
public:
bool ignore;
bool dolog;
};
#endif // _VIDEO_N64_H_

View File

@ -1,340 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
#ifndef _VIDEO_N64TYPES_H_
#define _VIDEO_N64TYPES_H_
#include "video/rgbutil.h"
struct misc_state_t
{
misc_state_t()
{
m_max_level = 0;
m_min_level = 0;
}
int32_t m_fb_format; // Framebuffer pixel format index (0 - I, 1 - IA, 2 - CI, 3 - RGBA)
int32_t m_fb_size; // Framebuffer pixel size index (0 - 4bpp, 1 - 8bpp, 2 - 16bpp, 3 - 32bpp)
int32_t m_fb_width; // Framebuffer width, in pixels
int32_t m_fb_height; // Framebuffer height, in pixels
uint32_t m_fb_address; // Framebuffer source address offset (in bytes) from start of RDRAM
uint32_t m_zb_address; // Z-buffer source address offset (in bytes) from start of RDRAM
int32_t m_ti_format; // Format for Texture Interface (TI) transfers
int32_t m_ti_size; // Size (in bytes) of TI transfers
int32_t m_ti_width; // Width (in pixels) of TI transfers
uint32_t m_ti_address; // Destination address for TI transfers
uint32_t m_max_level; // Maximum LOD level for texture filtering
uint32_t m_min_level; // Minimum LOD level for texture filtering
uint16_t m_primitive_z; // Forced Z value for current primitive, if applicable
uint16_t m_primitive_dz; // Forced Delta-Z value for current primitive, if applicable
};
#if 0
class color_t
{
public:
color_t()
{
c = 0;
}
color_t(uint32_t color)
{
set(color);
}
color_t(uint8_t a, uint8_t r, uint8_t g, uint8_t b)
{
set(a, r, g, b);
}
inline void set(color_t& other)
{
c = other.c;
}
inline void set(uint32_t color)
{
i.a = (color >> 24) & 0xff;
i.r = (color >> 16) & 0xff;
i.g = (color >> 8) & 0xff;
i.b = color & 0xff;
}
void set(uint8_t a, uint8_t r, uint8_t g, uint8_t b)
{
i.a = a;
i.r = r;
i.g = g;
i.b = b;
}
inline void set_direct(uint32_t color)
{
c = color;
}
uint32_t get()
{
return i.a << 24 | i.r << 16 | i.g << 8 | i.b;
}
union
{
uint32_t c;
#ifdef LSB_FIRST
struct { uint8_t a, b, g, r; } i;
#else
struct { uint8_t r, g, b, a; } i;
#endif
};
};
#else
#define color_t rgbaint_t
#endif
enum
{
BIT_DEPTH_32 = 0,
BIT_DEPTH_16,
BIT_DEPTH_COUNT
};
struct n64_tile_t
{
int32_t format; // Image data format: RGBA, YUV, CI, IA, I
int32_t size; // Size of texel element: 4b, 8b, 16b, 32b
int32_t line; // Size of tile line in bytes
int32_t tmem; // Starting tmem address for this tile in bytes
int32_t palette; // Palette number for 4b CI texels
int32_t ct, mt, cs, ms; // Clamp / mirror enable bits for S / T direction
int32_t mask_t, shift_t, mask_s, shift_s; // Mask values / LOD shifts
int32_t lshift_s, rshift_s, lshift_t, rshift_t;
int32_t wrapped_mask_s, wrapped_mask_t;
bool clamp_s, clamp_t;
rgbaint_t mm, invmm;
rgbaint_t wrapped_mask;
rgbaint_t mask;
rgbaint_t invmask;
rgbaint_t lshift;
rgbaint_t rshift;
rgbaint_t sth;
rgbaint_t stl;
rgbaint_t clamp_st;
uint16_t sl, tl, sh, th; // 10.2 fixed-point, starting and ending texel row / column
int32_t num;
};
struct span_base_t
{
int32_t m_span_dr;
int32_t m_span_dg;
int32_t m_span_db;
int32_t m_span_da;
int32_t m_span_ds;
int32_t m_span_dt;
int32_t m_span_dw;
int32_t m_span_dz;
int32_t m_span_dymax;
int32_t m_span_dzpix;
int32_t m_span_drdy;
int32_t m_span_dgdy;
int32_t m_span_dbdy;
int32_t m_span_dady;
int32_t m_span_dzdy;
};
struct combine_modes_t
{
int32_t sub_a_rgb0;
int32_t sub_b_rgb0;
int32_t mul_rgb0;
int32_t add_rgb0;
int32_t sub_a_a0;
int32_t sub_b_a0;
int32_t mul_a0;
int32_t add_a0;
int32_t sub_a_rgb1;
int32_t sub_b_rgb1;
int32_t mul_rgb1;
int32_t add_rgb1;
int32_t sub_a_a1;
int32_t sub_b_a1;
int32_t mul_a1;
int32_t add_a1;
};
struct color_inputs_t
{
// combiner inputs
color_t* combiner_rgbsub_a[2];
color_t* combiner_rgbsub_b[2];
color_t* combiner_rgbmul[2];
color_t* combiner_rgbadd[2];
color_t* combiner_alphasub_a[2];
color_t* combiner_alphasub_b[2];
color_t* combiner_alphamul[2];
color_t* combiner_alphaadd[2];
// blender input
color_t* blender1a_rgb[2];
color_t* blender1b_a[2];
color_t* blender2a_rgb[2];
color_t* blender2b_a[2];
};
struct other_modes_t
{
int32_t cycle_type;
bool persp_tex_en;
bool detail_tex_en;
bool sharpen_tex_en;
bool tex_lod_en;
bool en_tlut;
bool tlut_type;
bool sample_type;
bool mid_texel;
bool bi_lerp0;
bool bi_lerp1;
bool convert_one;
bool key_en;
int32_t rgb_dither_sel;
int32_t alpha_dither_sel;
int32_t blend_m1a_0;
int32_t blend_m1a_1;
int32_t blend_m1b_0;
int32_t blend_m1b_1;
int32_t blend_m2a_0;
int32_t blend_m2a_1;
int32_t blend_m2b_0;
int32_t blend_m2b_1;
int32_t tex_edge;
int32_t force_blend;
int32_t blend_shift;
bool alpha_cvg_select;
bool cvg_times_alpha;
int32_t z_mode;
int32_t cvg_dest;
bool color_on_cvg;
uint8_t image_read_en;
bool z_update_en;
bool z_compare_en;
bool antialias_en;
bool z_source_sel;
int32_t dither_alpha_en;
int32_t alpha_compare_en;
int32_t alpha_dither_mode;
};
struct rectangle_t
{
uint16_t m_xl; // 10.2 fixed-point
uint16_t m_yl; // 10.2 fixed-point
uint16_t m_xh; // 10.2 fixed-point
uint16_t m_yh; // 10.2 fixed-point
};
struct rdp_poly_state
{
n64_rdp* m_rdp; /* pointer back to the RDP state */
misc_state_t m_misc_state; /* miscellaneous rasterizer bits */
other_modes_t m_other_modes; /* miscellaneous rasterizer bits (2) */
span_base_t m_span_base; /* span initial values for triangle rasterization */
rectangle_t m_scissor; /* screen-space scissor bounds */
uint32_t m_fill_color; /* poly fill color */
n64_tile_t m_tiles[8]; /* texture tile state */
uint8_t m_tmem[0x1000]; /* texture cache */
int32_t tilenum; /* texture tile index */
bool flip; /* left-major / right-major flip */
bool rect; /* primitive is rectangle (vs. triangle) */
};
#define RDP_CVG_SPAN_MAX (1024)
// This is enormous and horrible
struct rdp_span_aux
{
uint32_t m_unscissored_rx;
uint16_t m_cvg[RDP_CVG_SPAN_MAX];
color_t m_memory_color;
color_t m_pixel_color;
color_t m_inv_pixel_color;
color_t m_blended_pixel_color;
color_t m_combined_color;
color_t m_combined_alpha;
color_t m_texel0_color;
color_t m_texel0_alpha;
color_t m_texel1_color;
color_t m_texel1_alpha;
color_t m_next_texel_color;
color_t m_next_texel_alpha;
color_t m_blend_color; /* constant blend color */
color_t m_prim_color; /* flat primitive color */
color_t m_prim_alpha; /* flat primitive alpha */
color_t m_env_color; /* generic color constant ('environment') */
color_t m_env_alpha; /* generic alpha constant ('environment') */
color_t m_fog_color; /* generic color constant ('fog') */
color_t m_shade_color; /* gouraud-shaded color */
color_t m_shade_alpha; /* gouraud-shaded alpha */
color_t m_key_scale; /* color-keying constant */
color_t m_noise_color; /* noise */
color_t m_lod_fraction; /* Z-based LOD fraction for this poly */
color_t m_prim_lod_fraction; /* fixed LOD fraction for this poly */
color_t m_k4;
color_t m_k5;
color_inputs_t m_color_inputs;
uint32_t m_current_pix_cvg;
uint32_t m_current_mem_cvg;
uint32_t m_current_cvg_bit;
int32_t m_shift_a;
int32_t m_shift_b;
int32_t m_precomp_s;
int32_t m_precomp_t;
int32_t m_blend_enable;
bool m_pre_wrap;
int32_t m_dzpix_enc;
uint8_t* m_tmem; /* pointer to texture cache for this polygon */
bool m_start_span;
rgbaint_t m_clamp_diff[8];
combine_modes_t m_combine;
};
struct z_decompress_entry_t
{
uint32_t shift;
uint32_t add;
};
struct cv_mask_derivative_t
{
uint8_t cvg;
uint8_t cvbit;
uint8_t xoff;
uint8_t yoff;
};
class span_param_t
{
public:
union
{
uint32_t w;
#ifdef LSB_FIRST
struct { uint16_t l; int16_t h; } h;
#else
struct { int16_t h; uint16_t l; } h;
#endif
};
};
#endif // _VIDEO_N64TYPES_H_

View File

@ -1,511 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
#include "emu.h"
#include "pin64.h"
#define CAP_NAME "pin64_%d.cap"
// pin64_fileutil_t members
void pin64_fileutil_t::write(FILE* file, uint32_t data) {
if (!file)
return;
uint8_t temp(data >> 24);
fwrite(&temp, 1, 1, file);
temp = (uint8_t)(data >> 16);
fwrite(&temp, 1, 1, file);
temp = (uint8_t)(data >> 8);
fwrite(&temp, 1, 1, file);
temp = (uint8_t)data;
fwrite(&temp, 1, 1, file);
}
void pin64_fileutil_t::write(FILE* file, const uint8_t* data, uint32_t size) {
if (!file)
return;
fwrite(data, 1, size, file);
}
// pin64_data_t members
void pin64_data_t::put8(uint8_t data) {
m_data.push_back(data);
m_offset++;
}
void pin64_data_t::put16(uint16_t data) {
put8((uint8_t)(data >> 8));
put8((uint8_t)data);
}
void pin64_data_t::put32(uint32_t data) {
put16((uint16_t)(data >> 16));
put16((uint16_t)data);
}
void pin64_data_t::put64(uint64_t data) {
put32((uint32_t)(data >> 32));
put32((uint32_t)data);
}
uint8_t pin64_data_t::get8() {
if (m_offset >= m_data.size())
fatalerror("PIN64: Call to pin64_data_t::get8() at end of block (requested offset %x, size %x)\n", m_offset, (uint32_t)m_data.size());
uint8_t ret = m_data[m_offset];
m_offset++;
return ret;
}
uint16_t pin64_data_t::get16() {
uint16_t ret = (uint16_t)get8() << 8;
return ret | get8();
}
uint32_t pin64_data_t::get32() {
uint32_t ret = (uint32_t)get16() << 16;
return ret | get16();
}
uint64_t pin64_data_t::get64() {
uint64_t ret = (uint64_t)get32() << 32;
return ret | get32();
}
uint8_t pin64_data_t::get8(uint32_t offset, bool temp_access) {
update_offset(offset, temp_access);
uint8_t ret = get8();
m_offset = m_old_offset;
return ret;
}
uint16_t pin64_data_t::get16(uint32_t offset, bool temp_access) {
update_offset(offset, temp_access);
uint16_t ret = get16();
m_offset = m_old_offset;
return ret;
}
uint32_t pin64_data_t::get32(uint32_t offset, bool temp_access) {
update_offset(offset, temp_access);
uint32_t ret = get32();
m_offset = m_old_offset;
return ret;
}
uint64_t pin64_data_t::get64(uint32_t offset, bool temp_access) {
update_offset(offset, temp_access);
uint32_t ret = get64();
m_offset = m_old_offset;
return ret;
}
void pin64_data_t::reset() {
m_old_offset = 0;
m_offset = 0;
}
void pin64_data_t::clear() {
reset();
m_data.clear();
}
void pin64_data_t::update_offset(uint32_t offset, bool update_current) {
m_old_offset = (update_current ? offset : m_offset);
m_offset = offset;
}
// pin64_printer_t members
void pin64_printer_t::print_data(pin64_block_t* block) {
pin64_data_t* data = block->data();
printf(" CRC32: %08x\n", (uint32_t)block->crc32()); fflush(stdout);
printf(" Data Size: %08x\n", (uint32_t)data->size()); fflush(stdout);
printf(" Data: "); fflush(stdout);
const uint32_t data_size = data->size();
const uint32_t row_count = (data_size + 31) / 32;
const uint8_t* bytes = data->bytes();
for (uint32_t row = 0; row < row_count; row++) {
const uint32_t row_index = row * 32;
const uint32_t data_remaining = data_size - row_index;
const uint32_t col_count = (data_remaining > 32 ? 32 : data_remaining);
for (uint32_t col = 0; col < col_count; col++) {
printf("%02x ", bytes[row_index + col]); fflush(stdout);
}
if (row == (row_count - 1)) {
printf("\n"); fflush(stdout);
} else {
printf("\n "); fflush(stdout);
}
}
printf("\n"); fflush(stdout);
}
void pin64_printer_t::print_command(int cmd_start, int cmd, std::unordered_map<util::crc32_t, pin64_block_t*>& blocks, std::vector<util::crc32_t>& commands) {
pin64_block_t* block = blocks[commands[cmd]];
pin64_data_t* data = block->data();
printf(" Command %d:\n", cmd - cmd_start); fflush(stdout);
const uint32_t cmd_size(data->get32());
printf(" CRC32: %08x\n", (uint32_t)commands[cmd]); fflush(stdout);
printf(" Packet Data Size: %d words\n", cmd_size); fflush(stdout);
printf(" Packet Data: "); fflush(stdout);
bool load_command = false;
for (int i = 0; i < cmd_size; i++) {
const uint64_t cmd_entry(data->get64());
if (i == 0) {
const uint8_t top_byte = uint8_t(cmd_entry >> 56) & 0x3f;
if (top_byte == 0x30 || top_byte == 0x33 || top_byte == 0x34)
load_command = true;
}
printf("%08x%08x\n", uint32_t(cmd_entry >> 32), (uint32_t)cmd_entry); fflush(stdout);
if (i < (cmd_size - 1)) {
printf(" "); fflush(stdout);
}
}
printf(" Data Block Present: %s\n", load_command ? "Yes" : "No"); fflush(stdout);
if (load_command) {
printf(" Data Block CRC32: %08x\n", data->get32()); fflush(stdout);
}
data->reset();
};
// pin64_block_t members
void pin64_block_t::finalize() {
#if !defined(MAME_RDP)
if (m_data.size() > 0)
m_crc32 = util::crc32_creator::simple(m_data.bytes(), m_data.size());
else
#endif
m_crc32 = ~0;
m_data.reset();
}
void pin64_block_t::clear() {
m_crc32 = 0;
m_data.clear();
}
void pin64_block_t::write(FILE* file) {
pin64_fileutil_t::write(file, m_crc32);
pin64_fileutil_t::write(file, m_data.size());
if (m_data.size() > 0)
pin64_fileutil_t::write(file, m_data.bytes(), m_data.size());
}
uint32_t pin64_block_t::size() {
return sizeof(uint32_t) // data CRC32
+ sizeof(uint32_t) // data size
+ m_data.size(); // data
}
// pin64_t members
const uint8_t pin64_t::CAP_ID[8] = { 'P', 'I', 'N', '6', '4', 'C', 'A', 'P' };
pin64_t::~pin64_t() {
if (m_capture_file)
finish();
clear();
}
void pin64_t::start(int frames)
{
if (m_capture_index == ~0)
init_capture_index();
if (m_capture_file)
fatalerror("PIN64: Call to start() while already capturing\n");
char name_buf[256];
sprintf(name_buf, CAP_NAME, m_capture_index);
m_capture_index++;
m_capture_file = fopen(name_buf, "wb");
m_capture_frames = frames;
m_frames.push_back(0);
}
void pin64_t::finish() {
if (!m_capture_file)
return;
finalize();
print();
write(m_capture_file);
fclose(m_capture_file);
m_capture_file = nullptr;
clear();
}
void pin64_t::finalize() {
finish_command();
data_end();
}
void pin64_t::play(int index) {
}
void pin64_t::mark_frame(running_machine& machine) {
if (m_capture_file) {
if (m_frames.size() == m_capture_frames && m_capture_frames > 0) {
printf("\n");
finish();
#if !defined(MAME_RDP)
machine.popmessage("Done recording.");
#endif
} else {
printf("%d ", (uint32_t)m_commands.size());
m_frames.push_back((uint32_t)m_commands.size());
}
}
#if PIN64_ENABLE_CAPTURE
if (machine.input().code_pressed_once(KEYCODE_N) && !m_capture_file) {
start(1);
machine.popmessage("Capturing PIN64 snapshot to pin64_%d.cap", m_capture_index - 1);
} else if (machine.input().code_pressed_once(KEYCODE_M)) {
if (m_capture_file) {
finish();
machine.popmessage("Done recording.");
} else {
start();
machine.popmessage("Recording PIN64 movie to pin64_%d.cap", m_capture_index - 1);
}
}
#endif
}
void pin64_t::command(uint64_t* cmd_data, uint32_t size) {
if (!capturing())
return;
finish_command();
m_current_command = new pin64_block_t();
m_current_command->data()->put32(size);
for (uint32_t i = 0 ; i < size; i++)
m_current_command->data()->put64(cmd_data[i]);
}
void pin64_t::finish_command() {
if (!m_current_command)
return;
m_current_command->finalize();
if (m_blocks.find(m_current_command->crc32()) == m_blocks.end())
m_blocks[m_current_command->crc32()] = m_current_command;
m_commands.push_back(m_current_command->crc32());
}
void pin64_t::data_begin() {
if (!capturing())
return;
if (m_current_data)
data_end();
m_current_data = new pin64_block_t();
}
pin64_data_t* pin64_t::data_block() {
if (!capturing() || !m_current_data)
return &m_dummy_data;
return m_current_data->data();
}
void pin64_t::data_end() {
if (!capturing() || !m_current_data)
return;
m_current_data->finalize();
m_current_command->data()->put32(m_current_data->crc32());
finish_command();
if (m_blocks.find(m_current_data->crc32()) == m_blocks.end())
m_blocks[m_current_data->crc32()] = m_current_data;
m_current_data = nullptr;
}
size_t pin64_t::size() {
return header_size() + block_directory_size() + cmdlist_directory_size() + cmdlist_size();
}
size_t pin64_t::header_size() {
return sizeof(uint8_t) * 8 // "PIN64CAP"
+ sizeof(uint32_t) // total file size
+ sizeof(uint32_t) // start of block directory data
+ sizeof(uint32_t) // start of command-list directory data
+ sizeof(uint32_t) // start of blocks
+ sizeof(uint32_t); // start of commands
}
size_t pin64_t::block_directory_size() {
return (m_blocks.size() + 1) * sizeof(uint32_t);
}
size_t pin64_t::cmdlist_directory_size() {
return (m_frames.size() + 1) * sizeof(uint16_t);
}
size_t pin64_t::blocks_size() {
size_t block_size = 0;
for (std::pair<util::crc32_t, pin64_block_t*> block_pair : m_blocks)
block_size += (block_pair.second)->size();
return block_size;
}
size_t pin64_t::cmdlist_size() {
return (m_commands.size() + 1) * sizeof(uint32_t);
}
void pin64_t::print()
{
printf("Total Size: %9x bytes\n", (uint32_t)size()); fflush(stdout);
printf("Header Size: %9x bytes\n", (uint32_t)header_size()); fflush(stdout);
printf("Block Dir Size: %9x bytes\n", (uint32_t)block_directory_size()); fflush(stdout);
printf("Cmdlist Dir Size: %9x bytes\n", (uint32_t)cmdlist_directory_size()); fflush(stdout);
printf("Blocks Size: %9x bytes\n", (uint32_t)blocks_size()); fflush(stdout);
printf("Cmdlist Size: %9x bytes\n", (uint32_t)cmdlist_size()); fflush(stdout);
printf("Command-List Count: %d\n", (uint32_t)m_frames.size()); fflush(stdout);
for (int i = 0; i < m_frames.size(); i++) {
printf(" List %d:\n", i); fflush(stdout);
const int next_start = ((i == (m_frames.size() - 1)) ? m_commands.size() : m_frames[i+1]);
for (int cmd = m_frames[i]; cmd < next_start; cmd++) {
pin64_printer_t::print_command(m_frames[i], cmd, m_blocks, m_commands);
}
if (i == (m_frames.size() - 1)) {
printf("\n"); fflush(stdout);
}
}
printf("\nData Block Count: %d\n", (uint32_t)m_blocks.size()); fflush(stdout);
int i = 0;
for (std::pair<util::crc32_t, pin64_block_t*> block_pair : m_blocks) {
printf(" Block %d:\n", i); fflush(stdout);
pin64_printer_t::print_data((block_pair.second));
if (i == (m_blocks.size() - 1)) {
printf("\n"); fflush(stdout);
}
i++;
}
}
void pin64_t::write(FILE* file) {
const uint32_t size_total = size();
const uint32_t size_header = header_size();
const uint32_t size_block_dir = block_directory_size();
const uint32_t size_cmdlist_dir = cmdlist_directory_size();
const uint32_t size_blocks_dir = blocks_size();
pin64_fileutil_t::write(file, CAP_ID, 8);
pin64_fileutil_t::write(file, size_total);
pin64_fileutil_t::write(file, size_header);
pin64_fileutil_t::write(file, size_header + size_block_dir);
pin64_fileutil_t::write(file, size_header + size_block_dir + size_cmdlist_dir);
pin64_fileutil_t::write(file, size_header + size_block_dir + size_cmdlist_dir + size_blocks_dir);
write_data_directory(file);
write_cmdlist_directory(file);
for (std::pair<util::crc32_t, pin64_block_t*> block_pair : m_blocks)
(block_pair.second)->write(file);
pin64_fileutil_t::write(file, m_commands.size());
for (util::crc32_t crc : m_commands)
pin64_fileutil_t::write(file, crc);
}
void pin64_t::write_data_directory(FILE* file) {
pin64_fileutil_t::write(file, m_blocks.size());
size_t offset(header_size());
for (std::pair<util::crc32_t, pin64_block_t*> block_pair : m_blocks) {
pin64_fileutil_t::write(file, offset);
offset += (block_pair.second)->size();
}
}
void pin64_t::write_cmdlist_directory(FILE* file) {
pin64_fileutil_t::write(file, m_frames.size());
for (uint32_t frame : m_frames)
pin64_fileutil_t::write(file, frame);
}
void pin64_t::clear() {
if (m_capture_file != nullptr) {
fclose(m_capture_file);
m_capture_file = nullptr;
}
for (std::pair<util::crc32_t, pin64_block_t*> block_pair : m_blocks)
delete block_pair.second;
m_blocks.clear();
m_commands.clear();
m_frames.clear();
m_current_data = nullptr;
m_current_command = nullptr;
}
void pin64_t::init_capture_index()
{
char name_buf[256];
bool found = true;
m_capture_index = 0;
do {
sprintf(name_buf, CAP_NAME, m_capture_index);
FILE* temp = fopen(name_buf, "rb");
if (temp == nullptr) {
break;
} else {
fclose(temp);
m_capture_index++;
}
} while(found);
}

View File

@ -1,180 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
#ifndef MAME_VIDEO_PIN64_H
#define MAME_VIDEO_PIN64_H
#pragma once
#include <cstdio>
#include <map>
#include <vector>
#define PIN64_ENABLE_CAPTURE (0)
class pin64_fileutil_t {
public:
static void write(FILE* file, uint32_t data);
static void write(FILE* file, const uint8_t* data, uint32_t size);
};
class pin64_command_t {
public:
std::vector<uint8_t> data;
};
class pin64_data_t {
public:
pin64_data_t()
: m_offset(0)
, m_old_offset(0) { }
void reset();
void clear();
// setters
virtual void put8(uint8_t data);
virtual void put16(uint16_t data);
virtual void put32(uint32_t data);
virtual void put64(uint64_t data);
// getters
virtual uint8_t get8();
virtual uint8_t get8(uint32_t offset, bool temp_access = false);
virtual uint16_t get16();
virtual uint16_t get16(uint32_t offset, bool temp_access = false);
virtual uint32_t get32();
virtual uint32_t get32(uint32_t offset, bool temp_access = false);
virtual uint64_t get64();
virtual uint64_t get64(uint32_t offset, bool temp_access = false);
virtual uint32_t offset() { return m_offset; }
uint8_t* bytes() { return (m_data.size() > 0) ? &m_data[0] : nullptr; }
uint32_t size() { return m_data.size(); }
private:
void update_offset(uint32_t offset, bool temp_access = false);
protected:
std::vector<uint8_t> m_data;
uint32_t m_offset;
uint32_t m_old_offset;
};
class pin64_dummy_data_t : public pin64_data_t {
public:
void put8(uint8_t data) override { }
void put16(uint16_t data) override { }
void put32(uint32_t data) override { }
void put64(uint64_t data) override { }
uint8_t get8() override { return 0; }
uint8_t get8(uint32_t offset, bool update_current = true) override { return 0; }
uint16_t get16() override { return 0; }
uint16_t get16(uint32_t offset, bool update_current = true) override { return 0; }
uint32_t get32() override { return 0; }
uint32_t get32(uint32_t offset, bool update_current = true) override { return 0; }
uint64_t get64() override { return 0; }
uint64_t get64(uint32_t offset, bool update_current = true) override { return 0; }
uint32_t offset() override { return 0; }
};
class pin64_block_t {
public:
pin64_block_t()
: m_crc32{0} { }
virtual ~pin64_block_t() { }
void finalize();
void clear();
void write(FILE* file);
// getters
uint32_t size();
pin64_data_t* data() { return &m_data; }
util::crc32_t crc32() const { return m_crc32; }
protected:
util::crc32_t m_crc32;
pin64_data_t m_data;
};
class pin64_printer_t {
public:
static void print_data(pin64_block_t* block);
static void print_command(int cmd_start, int cmd, std::unordered_map<util::crc32_t, pin64_block_t*>& blocks, std::vector<util::crc32_t>& commands);
};
class pin64_t
{
public:
pin64_t()
: m_capture_file(nullptr)
, m_capture_index(~0)
, m_capture_frames(0)
, m_current_data(nullptr)
, m_current_command(nullptr)
, m_playing(false)
{ }
~pin64_t();
void start(int frames = 0);
void finish();
void clear();
void print();
void mark_frame(running_machine& machine);
void play(int index);
void command(uint64_t* cmd_data, uint32_t size);
void data_begin();
pin64_data_t* data_block();
pin64_block_t& block() { return *m_current_data; }
void data_end();
bool capturing() const { return m_capture_file != nullptr; }
bool playing() const { return m_playing; }
size_t size();
private:
void start_command_block();
void write(FILE* file);
size_t header_size();
size_t block_directory_size();
size_t cmdlist_directory_size();
size_t blocks_size();
size_t cmdlist_size();
void finish_command();
void write_data_directory(FILE* file);
void write_cmdlist_directory(FILE* file);
void init_capture_index();
void finalize();
FILE *m_capture_file;
int32_t m_capture_index;
int m_capture_frames;
pin64_block_t* m_current_data;
pin64_block_t* m_current_command;
std::unordered_map<util::crc32_t, pin64_block_t*> m_blocks;
std::vector<util::crc32_t> m_commands;
std::vector<uint32_t> m_frames;
bool m_playing;
pin64_dummy_data_t m_dummy_data;
static const uint8_t CAP_ID[8];
};
#endif // MAME_VIDEO_PIN64_H

View File

@ -1,461 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
/******************************************************************************
SGI/Nintendo Reality Display Processor Blend Unit (BL)
-------------------
by Ryan Holtz
based on initial C code by Ville Linde
contains additional improvements from angrylion, Ziggy, Gonetz and Orkin
******************************************************************************/
#include "emu.h"
#include "includes/n64.h"
#include "video/n64.h"
n64_blender_t::n64_blender_t()
{
blend1[0] = &n64_blender_t::cycle1_noblend_noacvg_nodither;
blend1[1] = &n64_blender_t::cycle1_noblend_noacvg_dither;
blend1[2] = &n64_blender_t::cycle1_noblend_acvg_nodither;
blend1[3] = &n64_blender_t::cycle1_noblend_acvg_dither;
blend1[4] = &n64_blender_t::cycle1_blend_noacvg_nodither;
blend1[5] = &n64_blender_t::cycle1_blend_noacvg_dither;
blend1[6] = &n64_blender_t::cycle1_blend_acvg_nodither;
blend1[7] = &n64_blender_t::cycle1_blend_acvg_dither;
blend2[0] = &n64_blender_t::cycle2_noblend_noacvg_nodither;
blend2[1] = &n64_blender_t::cycle2_noblend_noacvg_dither;
blend2[2] = &n64_blender_t::cycle2_noblend_acvg_nodither;
blend2[3] = &n64_blender_t::cycle2_noblend_acvg_dither;
blend2[4] = &n64_blender_t::cycle2_blend_noacvg_nodither;
blend2[5] = &n64_blender_t::cycle2_blend_noacvg_dither;
blend2[6] = &n64_blender_t::cycle2_blend_acvg_nodither;
blend2[7] = &n64_blender_t::cycle2_blend_acvg_dither;
for (int value = 0; value < 256; value++)
{
for (int dither = 0; dither < 8; dither++)
{
m_color_dither[(value << 3) | dither] = (uint8_t)dither_color(value, dither);
m_alpha_dither[(value << 3) | dither] = (uint8_t)dither_alpha(value, dither);
}
}
}
int32_t n64_blender_t::dither_alpha(int32_t alpha, int32_t dither)
{
return min(alpha + dither, 0xff);
}
int32_t n64_blender_t::dither_color(int32_t color, int32_t dither)
{
if ((color & 7) > dither)
{
color = (color & 0xf8) + 8;
if (color > 247)
{
color = 255;
}
}
return color;
}
bool n64_blender_t::test_for_reject(rdp_span_aux* userdata, const rdp_poly_state& object)
{
if (alpha_reject(userdata, object))
{
return true;
}
if (object.m_other_modes.antialias_en ? !userdata->m_current_pix_cvg : !userdata->m_current_cvg_bit)
{
return true;
}
return false;
}
bool n64_blender_t::alpha_reject(rdp_span_aux* userdata, const rdp_poly_state& object)
{
switch (object.m_other_modes.alpha_dither_mode)
{
case 0:
case 1:
return false;
case 2:
return userdata->m_pixel_color.get_a() < userdata->m_blend_color.get_a();
case 3:
return userdata->m_pixel_color.get_a() < (machine().rand() & 0xff);
default:
return false;
}
}
bool n64_blender_t::cycle1_noblend_noacvg_nodither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, rdp_span_aux* userdata, const rdp_poly_state& object)
{
userdata->m_pixel_color.set_a(m_alpha_dither[((uint8_t)userdata->m_pixel_color.get_a() << 3) | adseed]);
userdata->m_shade_color.set_a(m_alpha_dither[((uint8_t)userdata->m_shade_color.get_a() << 3) | adseed]);
if (test_for_reject(userdata, object))
{
return false;
}
blended_pixel.set(*userdata->m_color_inputs.blender1a_rgb[0]);
return true;
}
bool n64_blender_t::cycle1_noblend_noacvg_dither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, rdp_span_aux* userdata, const rdp_poly_state& object)
{
userdata->m_pixel_color.set_a(m_alpha_dither[((uint8_t)userdata->m_pixel_color.get_a() << 3) | adseed]);
userdata->m_shade_color.set_a(m_alpha_dither[((uint8_t)userdata->m_shade_color.get_a() << 3) | adseed]);
if (test_for_reject(userdata, object))
{
return false;
}
rgbaint_t index(*userdata->m_color_inputs.blender1a_rgb[0]);
index.shl_imm(3);
index.or_imm(dith);
index.and_imm(0x7ff);
blended_pixel.set(0, m_color_dither[index.get_r32()], m_color_dither[index.get_g32()], m_color_dither[index.get_b32()]);
return true;
}
bool n64_blender_t::cycle1_noblend_acvg_nodither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, rdp_span_aux* userdata, const rdp_poly_state& object)
{
userdata->m_shade_color.set_a(m_alpha_dither[((uint8_t)userdata->m_shade_color.get_a() << 3) | adseed]);
if (test_for_reject(userdata, object))
{
return false;
}
blended_pixel.set(*userdata->m_color_inputs.blender1a_rgb[0]);
return true;
}
bool n64_blender_t::cycle1_noblend_acvg_dither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, rdp_span_aux* userdata, const rdp_poly_state& object)
{
userdata->m_shade_color.set_a(m_alpha_dither[((uint8_t)userdata->m_shade_color.get_a() << 3) | adseed]);
if (test_for_reject(userdata, object))
{
return false;
}
rgbaint_t index(*userdata->m_color_inputs.blender1a_rgb[0]);
index.shl_imm(3);
index.or_imm(dith);
index.and_imm(0x7ff);
blended_pixel.set(0, m_color_dither[index.get_r32()], m_color_dither[index.get_g32()], m_color_dither[index.get_b32()]);
return true;
}
bool n64_blender_t::cycle1_blend_noacvg_nodither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, rdp_span_aux* userdata, const rdp_poly_state& object)
{
userdata->m_pixel_color.set_a(m_alpha_dither[((uint8_t)userdata->m_pixel_color.get_a() << 3) | adseed]);
userdata->m_shade_color.set_a(m_alpha_dither[((uint8_t)userdata->m_shade_color.get_a() << 3) | adseed]);
if (test_for_reject(userdata, object))
{
return false;
}
blend_with_partial_reject(blended_pixel, 0, partialreject, sel0, userdata, object);
return true;
}
bool n64_blender_t::cycle1_blend_noacvg_dither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, rdp_span_aux* userdata, const rdp_poly_state& object)
{
userdata->m_pixel_color.set_a(m_alpha_dither[((uint8_t)userdata->m_pixel_color.get_a() << 3) | adseed]);
userdata->m_shade_color.set_a(m_alpha_dither[((uint8_t)userdata->m_shade_color.get_a() << 3) | adseed]);
if (test_for_reject(userdata, object))
{
return false;
}
color_t rgb;
blend_with_partial_reject(rgb, 0, partialreject, sel0, userdata, object);
rgb.shl_imm(3);
rgb.or_imm(dith);
rgb.and_imm(0x7ff);
blended_pixel.set(0, m_color_dither[rgb.get_r32()], m_color_dither[rgb.get_g32()], m_color_dither[rgb.get_b32()]);
return true;
}
bool n64_blender_t::cycle1_blend_acvg_nodither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, rdp_span_aux* userdata, const rdp_poly_state& object)
{
userdata->m_shade_color.set_a(m_alpha_dither[((uint8_t)userdata->m_shade_color.get_a() << 3) | adseed]);
if (test_for_reject(userdata, object))
{
return false;
}
blend_with_partial_reject(blended_pixel, 0, partialreject, sel0, userdata, object);
return true;
}
bool n64_blender_t::cycle1_blend_acvg_dither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, rdp_span_aux* userdata, const rdp_poly_state& object)
{
userdata->m_shade_color.set_a(m_alpha_dither[((uint8_t)userdata->m_shade_color.get_a() << 3) | adseed]);
if (test_for_reject(userdata, object))
{
return false;
}
color_t rgb;
blend_with_partial_reject(rgb, 0, partialreject, sel0, userdata, object);
rgb.shl_imm(3);
rgb.or_imm(dith);
rgb.and_imm(0x7ff);
blended_pixel.set(0, m_color_dither[rgb.get_r32()], m_color_dither[rgb.get_g32()], m_color_dither[rgb.get_b32()]);
return true;
}
bool n64_blender_t::cycle2_noblend_noacvg_nodither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, int sel1, rdp_span_aux* userdata, const rdp_poly_state& object)
{
userdata->m_pixel_color.set_a(m_alpha_dither[((uint8_t)userdata->m_pixel_color.get_a() << 3) | adseed]);
userdata->m_shade_color.set_a(m_alpha_dither[((uint8_t)userdata->m_shade_color.get_a() << 3) | adseed]);
if (test_for_reject(userdata, object))
{
return false;
}
userdata->m_inv_pixel_color.set_a(0xff - userdata->m_color_inputs.blender1b_a[0]->get_a());
blend_pipe(0, sel0, userdata->m_blended_pixel_color, userdata, object);
userdata->m_blended_pixel_color.set_a(userdata->m_pixel_color.get_a());
blended_pixel.set(*userdata->m_color_inputs.blender1a_rgb[1]);
return true;
}
bool n64_blender_t::cycle2_noblend_noacvg_dither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, int sel1, rdp_span_aux* userdata, const rdp_poly_state& object)
{
userdata->m_pixel_color.set_a(m_alpha_dither[((uint8_t)userdata->m_pixel_color.get_a() << 3) | adseed]);
userdata->m_shade_color.set_a(m_alpha_dither[((uint8_t)userdata->m_shade_color.get_a() << 3) | adseed]);
if (test_for_reject(userdata, object))
{
return false;
}
userdata->m_inv_pixel_color.set_a(0xff - (uint8_t)userdata->m_color_inputs.blender1b_a[0]->get_a());
blend_pipe(0, sel0, userdata->m_blended_pixel_color, userdata, object);
userdata->m_blended_pixel_color.set_a(userdata->m_pixel_color.get_a());
rgbaint_t index(*userdata->m_color_inputs.blender1a_rgb[1]);
index.shl_imm(3);
index.or_imm(dith);
index.and_imm(0x7ff);
blended_pixel.set(0, m_color_dither[index.get_r32()], m_color_dither[index.get_g32()], m_color_dither[index.get_b32()]);
return true;
}
bool n64_blender_t::cycle2_noblend_acvg_nodither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, int sel1, rdp_span_aux* userdata, const rdp_poly_state& object)
{
userdata->m_shade_color.set_a(m_alpha_dither[((uint8_t)userdata->m_shade_color.get_a() << 3) | adseed]);
if (test_for_reject(userdata, object))
{
return false;
}
userdata->m_inv_pixel_color.set_a(0xff - userdata->m_color_inputs.blender1b_a[0]->get_a());
blend_pipe(0, sel0, userdata->m_blended_pixel_color, userdata, object);
userdata->m_blended_pixel_color.set_a(userdata->m_pixel_color.get_a());
blended_pixel.set(*userdata->m_color_inputs.blender1a_rgb[1]);
return true;
}
bool n64_blender_t::cycle2_noblend_acvg_dither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, int sel1, rdp_span_aux* userdata, const rdp_poly_state& object)
{
userdata->m_shade_color.set_a(m_alpha_dither[((uint8_t)userdata->m_shade_color.get_a() << 3) | adseed]);
if (test_for_reject(userdata, object))
{
return false;
}
userdata->m_inv_pixel_color.set_a(0xff - userdata->m_color_inputs.blender1b_a[0]->get_a());
blend_pipe(0, sel0, userdata->m_blended_pixel_color, userdata, object);
userdata->m_blended_pixel_color.set_a(userdata->m_pixel_color.get_a());
rgbaint_t index(*userdata->m_color_inputs.blender1a_rgb[1]);
index.shl_imm(3);
index.or_imm(dith);
index.and_imm(0x7ff);
blended_pixel.set(0, m_color_dither[index.get_r32()], m_color_dither[index.get_g32()], m_color_dither[index.get_b32()]);
return true;
}
bool n64_blender_t::cycle2_blend_noacvg_nodither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, int sel1, rdp_span_aux* userdata, const rdp_poly_state& object)
{
userdata->m_pixel_color.set_a(m_alpha_dither[((uint8_t)userdata->m_pixel_color.get_a() << 3) | adseed]);
userdata->m_shade_color.set_a(m_alpha_dither[((uint8_t)userdata->m_shade_color.get_a() << 3) | adseed]);
if (test_for_reject(userdata, object))
{
return false;
}
userdata->m_inv_pixel_color.set_a(0xff - userdata->m_color_inputs.blender1b_a[0]->get_a());
blend_pipe(0, sel0, userdata->m_blended_pixel_color, userdata, object);
userdata->m_blended_pixel_color.set_a(userdata->m_pixel_color.get_a());
blend_with_partial_reject(blended_pixel, 1, partialreject, sel1, userdata, object);
return true;
}
bool n64_blender_t::cycle2_blend_noacvg_dither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, int sel1, rdp_span_aux* userdata, const rdp_poly_state& object)
{
userdata->m_pixel_color.set_a(m_alpha_dither[(userdata->m_pixel_color.get_a() << 3) | adseed]);
userdata->m_shade_color.set_a(m_alpha_dither[(userdata->m_shade_color.get_a() << 3) | adseed]);
if (test_for_reject(userdata, object))
{
return false;
}
userdata->m_inv_pixel_color.set_a(0xff - userdata->m_color_inputs.blender1b_a[0]->get_a());
blend_pipe(0, sel0, userdata->m_blended_pixel_color, userdata, object);
userdata->m_blended_pixel_color.set_a(userdata->m_pixel_color.get_a());
color_t rgb;
blend_with_partial_reject(rgb, 1, partialreject, sel1, userdata, object);
rgb.shl_imm(3);
rgb.or_imm(dith);
rgb.and_imm(0x7ff);
blended_pixel.set(0, m_color_dither[rgb.get_r32()], m_color_dither[rgb.get_g32()], m_color_dither[rgb.get_b32()]);
return true;
}
bool n64_blender_t::cycle2_blend_acvg_nodither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, int sel1, rdp_span_aux* userdata, const rdp_poly_state& object)
{
userdata->m_shade_color.set_a(m_alpha_dither[(userdata->m_shade_color.get_a() << 3) | adseed]);
if (test_for_reject(userdata, object))
{
return false;
}
userdata->m_inv_pixel_color.set_a(0xff - userdata->m_color_inputs.blender1b_a[0]->get_a());
blend_pipe(0, sel0, userdata->m_blended_pixel_color, userdata, object);
userdata->m_blended_pixel_color.set_a(userdata->m_pixel_color.get_a());
blend_with_partial_reject(blended_pixel, 1, partialreject, sel1, userdata, object);
return true;
}
bool n64_blender_t::cycle2_blend_acvg_dither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, int sel1, rdp_span_aux* userdata, const rdp_poly_state& object)
{
userdata->m_shade_color.set_a(m_alpha_dither[(userdata->m_shade_color.get_a() << 3) | adseed]);
if (test_for_reject(userdata, object))
{
return false;
}
userdata->m_inv_pixel_color.set_a(0xff - userdata->m_color_inputs.blender1b_a[0]->get_a());
blend_pipe(0, sel0, userdata->m_blended_pixel_color, userdata, object);
userdata->m_blended_pixel_color.set_a(userdata->m_pixel_color.get_a());
color_t rgb;
blend_with_partial_reject(rgb, 1, partialreject, sel1, userdata, object);
rgb.shl_imm(3);
rgb.or_imm(dith);
rgb.and_imm(0x7ff);
blended_pixel.set(0, m_color_dither[rgb.get_r32()], m_color_dither[rgb.get_g32()], m_color_dither[rgb.get_b32()]);
return true;
}
void n64_blender_t::blend_with_partial_reject(color_t& out, int32_t cycle, int32_t partialreject, int32_t select, rdp_span_aux* userdata, const rdp_poly_state& object)
{
if (partialreject && userdata->m_pixel_color.get_a() >= 0xff)
{
out.set(*userdata->m_color_inputs.blender1a_rgb[cycle]);
}
else
{
userdata->m_inv_pixel_color.set_a(0xff - userdata->m_color_inputs.blender1b_a[cycle]->get_a());
blend_pipe(cycle, select, out, userdata, object);
}
}
void n64_blender_t::blend_pipe(const int cycle, const int special, color_t& out, rdp_span_aux* userdata, const rdp_poly_state& object)
{
const int32_t mask = 0xff &~ (0x73 * special);
const int32_t shift_a = 3 + userdata->m_shift_a * special;
const int32_t shift_b = 3 + userdata->m_shift_b * special;
const int32_t blend1a = (userdata->m_color_inputs.blender1b_a[cycle]->get_a() >> shift_a) & mask;
const int32_t blend2a = (userdata->m_color_inputs.blender2b_a[cycle]->get_a() >> shift_b) & mask;
const int32_t special_shift = special << 1;
rgbaint_t temp(*userdata->m_color_inputs.blender1a_rgb[cycle]);
temp.mul_imm(blend1a);
rgbaint_t secondary(*userdata->m_color_inputs.blender2a_rgb[cycle]);
rgbaint_t other(*userdata->m_color_inputs.blender2a_rgb[cycle]);
other.mul_imm(blend2a);
temp.add(other);
secondary.shl_imm(special_shift);
temp.add(secondary);
temp.shr_imm(object.m_other_modes.blend_shift);
int32_t factor_sum = 0;
if (!object.m_other_modes.force_blend)
{
factor_sum = ((blend1a >> 2) + (blend2a >> 2) + 1) & 0xf;
if (factor_sum)
{
temp.set_r(temp.get_r32() / factor_sum);
temp.set_g(temp.get_g32() / factor_sum);
temp.set_b(temp.get_b32() / factor_sum);
}
else
{
temp.set(0, 0xff, 0xff, 0xff);
}
}
temp.min(255);
out.set(temp);
}
inline int32_t n64_blender_t::min(const int32_t x, const int32_t min)
{
if (x < min)
{
return x;
}
return min;
}

View File

@ -1,72 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
/******************************************************************************
SGI/Nintendo Reality Display Processor Blend Unit (BL)
-------------------
by Ryan Holtz
based on initial C code by Ville Linde
contains additional improvements from angrylion, Ziggy, Gonetz and Orkin
******************************************************************************/
#ifndef _VIDEO_RDPBLEND_H_
#define _VIDEO_RDPBLEND_H_
#include "video/n64.h"
class n64_blender_t
{
public:
typedef bool (n64_blender_t::*blender1)(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, rdp_span_aux* userdata, const rdp_poly_state& object);
typedef bool (n64_blender_t::*blender2)(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, int sel1, rdp_span_aux* userdata, const rdp_poly_state& object);
n64_blender_t();
blender1 blend1[8];
blender2 blend2[8];
void set_machine(running_machine& machine) { m_machine = &machine; }
void set_processor(n64_rdp* rdp) { m_rdp = rdp; }
running_machine &machine() const { assert(m_machine != nullptr); return *m_machine; }
private:
running_machine* m_machine;
n64_rdp* m_rdp;
int32_t min(const int32_t x, const int32_t min);
bool alpha_reject(rdp_span_aux* userdata, const rdp_poly_state& object);
bool test_for_reject(rdp_span_aux* userdata, const rdp_poly_state& object);
void blend_pipe(const int cycle, const int special, color_t& out, rdp_span_aux* userdata, const rdp_poly_state& object);
void blend_with_partial_reject(color_t& out, int32_t cycle, int32_t partialreject, int32_t select, rdp_span_aux* userdata, const rdp_poly_state& object);
bool cycle1_noblend_noacvg_nodither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, rdp_span_aux* userdata, const rdp_poly_state& object);
bool cycle1_noblend_noacvg_dither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, rdp_span_aux* userdata, const rdp_poly_state& object);
bool cycle1_noblend_acvg_nodither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, rdp_span_aux* userdata, const rdp_poly_state& object);
bool cycle1_noblend_acvg_dither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, rdp_span_aux* userdata, const rdp_poly_state& object);
bool cycle1_blend_noacvg_nodither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, rdp_span_aux* userdata, const rdp_poly_state& object);
bool cycle1_blend_noacvg_dither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, rdp_span_aux* userdata, const rdp_poly_state& object);
bool cycle1_blend_acvg_nodither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, rdp_span_aux* userdata, const rdp_poly_state& object);
bool cycle1_blend_acvg_dither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, rdp_span_aux* userdata, const rdp_poly_state& object);
bool cycle2_noblend_noacvg_nodither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, int sel1, rdp_span_aux* userdata, const rdp_poly_state& object);
bool cycle2_noblend_noacvg_dither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, int sel1, rdp_span_aux* userdata, const rdp_poly_state& object);
bool cycle2_noblend_acvg_nodither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, int sel1, rdp_span_aux* userdata, const rdp_poly_state& object);
bool cycle2_noblend_acvg_dither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, int sel1, rdp_span_aux* userdata, const rdp_poly_state& object);
bool cycle2_blend_noacvg_nodither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, int sel1, rdp_span_aux* userdata, const rdp_poly_state& object);
bool cycle2_blend_noacvg_dither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, int sel1, rdp_span_aux* userdata, const rdp_poly_state& object);
bool cycle2_blend_acvg_nodither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, int sel1, rdp_span_aux* userdata, const rdp_poly_state& object);
bool cycle2_blend_acvg_dither(color_t& blended_pixel, int dith, int adseed, int partialreject, int sel0, int sel1, rdp_span_aux* userdata, const rdp_poly_state& object);
int32_t dither_alpha(int32_t alpha, int32_t dither);
int32_t dither_color(int32_t color, int32_t dither);
uint8_t m_color_dither[256 * 8];
uint8_t m_alpha_dither[256 * 8];
};
#endif // _VIDEO_RDPBLEND_H_

View File

@ -1,617 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
#if 0
static inline void video_filter16(int *out_r, int *out_g, int *out_b, uint16_t* vbuff, uint8_t* hbuff, const uint32_t hres);
static inline void divot_filter16(uint8_t* r, uint8_t* g, uint8_t* b, uint16_t* fbuff, uint32_t fbuff_index);
static inline void restore_filter16(int32_t* r, int32_t* g, int32_t* b, uint16_t* fbuff, uint32_t fbuff_index, uint32_t hres);
static inline void divot_filter16_buffer(int32_t* r, int32_t* g, int32_t* b, color_t* vibuffer);
static inline void restore_filter16_buffer(int32_t* r, int32_t* g, int32_t* b, color_t* vibuff, uint32_t hres);
static inline void restore_two(color_t* filtered, color_t* neighbour);
static inline void video_max(uint32_t* Pixels, uint8_t* max, uint32_t* enb);
static inline uint32_t ge_two(uint32_t enb);
static inline void video_filter16(int *out_r, int *out_g, int *out_b, uint16_t* vbuff, uint8_t* hbuff, const uint32_t hres)
{
color_t penumax, penumin, max, min;
uint16_t pix = *vbuff;
const uint8_t centercvg = (*hbuff & 3) + ((pix & 1) << 2) + 1;
uint32_t numoffull = 1;
uint32_t cvg;
uint32_t backr[7], backg[7], backb[7];
uint32_t invr[7], invg[7], invb[7];
int32_t coeff;
int32_t leftup = -hres - 2;
int32_t leftdown = hres - 2;
int32_t toleft = -2;
uint32_t colr, colg, colb;
uint32_t enb;
uint32_t r = ((pix >> 8) & 0xf8) | (pix >> 13);
uint32_t g = ((pix >> 3) & 0xf8) | ((pix >> 8) & 0x07);
uint32_t b = ((pix << 2) & 0xf8) | ((pix >> 3) & 0x07);
*out_r = *out_g = *out_b = 0;
backr[0] = r;
backg[0] = g;
backb[0] = b;
invr[0] = ~r;
invg[0] = ~g;
invb[0] = ~b;
if (centercvg == 8)
{
*out_r = r;
*out_g = g;
*out_b = b;
return;
}
for(int i = 0; i < 5; i++)
{
pix = vbuff[leftup ^ WORD_ADDR_XOR];
cvg = hbuff[leftup ^ BYTE_ADDR_XOR] & 3;
if(i & 1)
{
if (cvg == 3 && (pix & 1))
{
backr[numoffull] = ((pix >> 8) & 0xf8) | (pix >> 13);
backg[numoffull] = ((pix >> 3) & 0xf8) | ((pix >> 8) & 0x07);
backb[numoffull] = ((pix << 2) & 0xf8) | ((pix >> 3) & 0x07);
invr[numoffull] = ~backr[numoffull];
invg[numoffull] = ~backg[numoffull];
invb[numoffull] = ~backb[numoffull];
}
else
{
backr[numoffull] = invr[numoffull] = 0;
backg[numoffull] = invg[numoffull] = 0;
backb[numoffull] = invb[numoffull] = 0;
}
numoffull++;
}
leftup++;
}
for(int i = 0; i < 5; i++)
{
pix = vbuff[leftdown ^ WORD_ADDR_XOR];
cvg = hbuff[leftdown ^ BYTE_ADDR_XOR] & 3;
if (i&1)
{
if (cvg == 3 && (pix & 1))
{
backr[numoffull] = ((pix >> 8) & 0xf8) | (pix >> 13);
backg[numoffull] = ((pix >> 3) & 0xf8) | ((pix >> 8) & 0x07);
backb[numoffull] = ((pix << 2) & 0xf8) | ((pix >> 3) & 0x07);
invr[numoffull] = ~backr[numoffull];
invg[numoffull] = ~backg[numoffull];
invb[numoffull] = ~backb[numoffull];
}
else
{
backr[numoffull] = invr[numoffull] = 0;
backg[numoffull] = invg[numoffull] = 0;
backb[numoffull] = invb[numoffull] = 0;
}
numoffull++;
}
leftdown++;
}
for(int i = 0; i < 5; i++)
{
pix = vbuff[toleft ^ WORD_ADDR_XOR];
cvg = hbuff[toleft ^ BYTE_ADDR_XOR] & 3;
if (!(i&3))
{
if (cvg == 3 && (pix & 1))
{
backr[numoffull] = ((pix >> 8) & 0xf8) | (pix >> 13);
backg[numoffull] = ((pix >> 3) & 0xf8) | ((pix >> 8) & 0x07);
backb[numoffull] = ((pix << 2) & 0xf8) | ((pix >> 3) & 0x07);
invr[numoffull] = ~backr[numoffull];
invg[numoffull] = ~backg[numoffull];
invb[numoffull] = ~backb[numoffull];
}
else
{
backr[numoffull] = invr[numoffull] = 0;
backg[numoffull] = invg[numoffull] = 0;
backb[numoffull] = invb[numoffull] = 0;
}
numoffull++;
}
toleft++;
}
video_max(&backr[0], &max.i.r, &enb);
for(int i = 1; i < 7; i++)
{
if (!((enb >> i) & 1))
{
backr[i] = 0;
}
}
video_max(&backg[0], &max.i.g, &enb);
for (int i = 1; i < 7; i++)
{
if (!((enb >> i) & 1))
{
backg[i] = 0;
}
}
video_max(&backb[0], &max.i.b, &enb);
for (int i = 1; i < 7; i++)
{
if (!((enb >> i) & 1))
{
backb[i] = 0;
}
}
video_max(&invr[0], &min.i.r, &enb);
for (int i = 1; i < 7; i++)
{
if (!((enb >> i) & 1))
{
backr[i] = 0;
}
}
video_max(&invg[0], &min.i.g, &enb);
for (int i = 1; i < 7; i++)
{
if (!((enb >> i) & 1))
{
backg[i] = 0;
}
}
video_max(&invb[0], &min.i.b, &enb);
for (int i = 1; i < 7; i++)
{
if (!((enb >> i) & 1))
{
backb[i] = 0;
}
}
video_max(&backr[0], &penumax.i.r, &enb);
penumax.i.r = ge_two(enb) ? max.i.r : penumax.i.r;
video_max(&backg[0], &penumax.i.g, &enb);
penumax.i.g = ge_two(enb) ? max.i.g : penumax.i.g;
video_max(&backb[0], &penumax.i.b, &enb);
penumax.i.b = ge_two(enb) ? max.i.b : penumax.i.b;
video_max(&invr[0], &penumin.i.r, &enb);
penumin.i.r = ge_two(enb) ? min.i.r : penumin.i.r;
video_max(&invg[0], &penumin.i.g, &enb);
penumin.i.g = ge_two(enb) ? min.i.g : penumin.i.g;
video_max(&invb[0], &penumin.i.b, &enb);
penumin.i.b = ge_two(enb) ? min.i.b : penumin.i.b;
penumin.i.r = ~penumin.i.r;
penumin.i.g = ~penumin.i.g;
penumin.i.b = ~penumin.i.b;
colr = (uint32_t)penumin.i.r + (uint32_t)penumax.i.r - (r << 1);
colg = (uint32_t)penumin.i.g + (uint32_t)penumax.i.g - (g << 1);
colb = (uint32_t)penumin.i.b + (uint32_t)penumax.i.b - (b << 1);
coeff = 8 - centercvg;
colr = (((colr * coeff) + 4) >> 3) + r;
colg = (((colg * coeff) + 4) >> 3) + g;
colb = (((colb * coeff) + 4) >> 3) + b;
*out_r = colr & 0xff;
*out_g = colg & 0xff;
*out_b = colb & 0xff;
return;
}
// This needs to be fixed for endianness.
static inline void divot_filter16(uint8_t* r, uint8_t* g, uint8_t* b, uint16_t* fbuff, uint32_t fbuff_index)
{
uint8_t leftr, leftg, leftb, rightr, rightg, rightb;
uint16_t leftpix, rightpix;
uint16_t* next, *prev;
uint32_t Lsw = fbuff_index & 1;
next = (Lsw) ? (uint16_t*)(fbuff - 1) : (uint16_t*)(fbuff + 3);
prev = (Lsw) ? (uint16_t*)(fbuff - 3) : (uint16_t*)(fbuff + 1);
leftpix = *prev;
rightpix = *next;
//leftpix = *(fbuff - 1); //for BE targets
//rightpix = *(fbuff + 1);
leftr = ((leftpix >> 8) & 0xf8) | (leftpix >> 13);
leftg = ((leftpix >> 3) & 0xf8) | ((leftpix >> 8) & 0x07);
leftb = ((leftpix << 2) & 0xf8) | ((leftpix >> 3) & 0x07);
rightr = ((rightpix >> 8) & 0xf8) | (rightpix >> 13);
rightg = ((rightpix >> 3) & 0xf8) | ((rightpix >> 8) & 0x07);
rightb = ((rightpix << 2) & 0xf8) | ((rightpix >> 3) & 0x07);
if ((leftr >= *r && rightr >= leftr) || (leftr >= rightr && *r >= leftr))
{
*r = leftr; //left = median value
}
if ((rightr >= *r && leftr >= rightr) || (rightr >= leftr && *r >= rightr))
{
*r = rightr; //right = median, else *r itself is median
}
if ((leftg >= *g && rightg >= leftg) || (leftg >= rightg && *g >= leftg))
{
*g = leftg;
}
if ((rightg >= *g && leftg >= rightg) || (rightg >= leftg && *g >= rightg))
{
*g = rightg;
}
if ((leftb >= *b && rightb >= leftb) || (leftb >= rightb && *b >= leftb))
{
*b = leftb;
}
if ((rightb >= *b && leftb >= rightb) || (rightb >= leftb && *b >= rightb))
{
*b = rightb;
}
}
static inline void divot_filter16_buffer(int* r, int* g, int* b, color_t* vibuffer)
{
color_t leftpix = vibuffer[-1];
color_t rightpix = vibuffer[1];
color_t filtered = *vibuffer;
*r = filtered.i.r;
*g = filtered.i.g;
*b = filtered.i.b;
uint32_t leftr = leftpix.i.r;
uint32_t leftg = leftpix.i.g;
uint32_t leftb = leftpix.i.b;
uint32_t rightr = rightpix.i.r;
uint32_t rightg = rightpix.i.g;
uint32_t rightb = rightpix.i.b;
if ((leftr >= *r && rightr >= leftr) || (leftr >= rightr && *r >= leftr))
{
*r = leftr; //left = median value
}
if ((rightr >= *r && leftr >= rightr) || (rightr >= leftr && *r >= rightr))
{
*r = rightr; //right = median, else *r itself is median
}
if ((leftg >= *g && rightg >= leftg) || (leftg >= rightg && *g >= leftg))
{
*g = leftg;
}
if ((rightg >= *g && leftg >= rightg) || (rightg >= leftg && *g >= rightg))
{
*g = rightg;
}
if ((leftb >= *b && rightb >= leftb) || (leftb >= rightb && *b >= leftb))
{
*b = leftb;
}
if ((rightb >= *b && leftb >= rightb) || (rightb >= leftb && *b >= rightb))
{
*b = rightb;
}
filtered.i.r = *r;
filtered.i.g = *g;
filtered.i.b = *b;
}
// Fix me.
static inline void restore_filter16(int* r, int* g, int* b, uint16_t* fbuff, uint32_t fbuff_index, uint32_t hres)
{
int32_t leftuppix = -hres - 1;
int32_t leftdownpix = hres - 1;
int32_t toleftpix = -1;
uint8_t tempr, tempg, tempb;
uint16_t pix;
int i;
uint8_t r5 = *r;
uint8_t g5 = *g;
uint8_t b5 = *b;
r5 &= ~7;
g5 &= ~7;
b5 &= ~7;
for (i = 0; i < 3; i++)
{
pix = fbuff[leftuppix ^ 1];
tempr = ((pix >> 8) & 0xf8) | (pix >> 13);
tempg = ((pix >> 3) & 0xf8) | ((pix >> 8) & 0x07);
tempb = ((pix << 2) & 0xf8) | ((pix >> 3) & 0x07);
tempr &= ~7;
tempg &= ~7;
tempb &= ~7;
if (tempr > r5)
{
*r += 1;
}
if (tempr < r5)
{
*r -= 1;
}
if (tempg > g5)
{
*g += 1;
}
if (tempg < g5)
{
*g -= 1;
}
if (tempb > b5)
{
*b += 1;
}
if (tempb < b5)
{
*b -= 1;
}
leftuppix++;
}
for (i = 0; i < 3; i++)
{
pix = fbuff[leftdownpix ^ 1];
tempr = ((pix >> 8) & 0xf8) | (pix >> 13);
tempg = ((pix >> 3) & 0xf8) | ((pix >> 8) & 0x07);
tempb = ((pix << 2) & 0xf8) | ((pix >> 3) & 0x07);
tempr &= ~7;
tempg &= ~7;
tempb &= ~7;
if (tempr > r5)
{
*r += 1;
}
if (tempr < r5)
{
*r -= 1;
}
if (tempg > g5)
{
*g += 1;
}
if (tempg < g5)
{
*g -= 1;
}
if (tempb > b5)
{
*b += 1;
}
if (tempb < b5)
{
*b -= 1;
}
leftdownpix++;
}
for(i = 0; i < 3; i++)
{
if (!(i & 1))
{
pix = fbuff[toleftpix ^ 1];
tempr = ((pix >> 8) & 0xf8) | (pix >> 13);
tempg = ((pix >> 3) & 0xf8) | ((pix >> 8) & 0x07);
tempb = ((pix << 2) & 0xf8) | ((pix >> 3) & 0x07);
tempr &= ~7;
tempg &= ~7;
tempb &= ~7;
if (tempr > r5)
{
*r += 1;
}
if (tempr < r5)
{
*r -= 1;
}
if (tempg > g5)
{
*g += 1;
}
if (tempg < g5)
{
*g -= 1;
}
if (tempb > b5)
{
*b += 1;
}
if (tempb < b5)
{
*b -= 1;
}
}
toleftpix++;
}
}
static inline void restore_filter16_buffer(int32_t* r, int32_t* g, int32_t* b, color_t* vibuff, uint32_t hres)
{
color_t filtered;
color_t leftuppix, leftdownpix, leftpix;
color_t rightuppix, rightdownpix, rightpix;
color_t uppix, downpix;
int32_t ihres = (int32_t)hres; //can't apply unary minus to unsigned
leftuppix = vibuff[-ihres - 1];
leftdownpix = vibuff[ihres - 1];
leftpix = vibuff[-1];
rightuppix = vibuff[-ihres + 1];
rightdownpix = vibuff[ihres + 1];
rightpix = vibuff[1];
uppix = vibuff[-ihres];
downpix = vibuff[ihres];
filtered = *vibuff;
restore_two(&filtered, &leftuppix);
restore_two(&filtered, &uppix);
restore_two(&filtered, &rightuppix);
restore_two(&filtered, &leftpix);
restore_two(&filtered, &rightpix);
restore_two(&filtered, &leftdownpix);
restore_two(&filtered, &downpix);
restore_two(&filtered, &rightdownpix);
*r = filtered.i.r;
*g = filtered.i.g;
*b = filtered.i.b;
if(*r < 0) *r = 0;
else if(*r > 255) *r = 255;
if(*g < 0) *g = 0;
else if(*g > 255) *g = 255;
if(*b < 0) *b = 0;
else if(*b > 255) *b = 255;
}
// This is wrong, only the 5 upper bits are compared.
static inline void restore_two(color_t* filtered, color_t* neighbour)
{
if (neighbour->i.r > filtered->i.r)
{
filtered->i.r += 1;
}
if (neighbour->i.r < filtered->i.r)
{
filtered->i.r -= 1;
}
if (neighbour->i.g > filtered->i.g)
{
filtered->i.g += 1;
}
if (neighbour->i.g < filtered->i.g)
{
filtered->i.g -= 1;
}
if (neighbour->i.b > filtered->i.b)
{
filtered->i.b += 1;
}
if (neighbour->i.b < filtered->i.b)
{
filtered->i.b -= 1;
}
}
static inline void video_max(uint32_t* Pixels, uint8_t* max, uint32_t* enb)
{
int i;
int pos = 0;
*enb = 0;
for(i = 0; i < 7; i++)
{
if (Pixels[i] > Pixels[pos])
{
*enb += (1 << i);
pos = i;
}
else if (Pixels[i] < Pixels[pos])
{
*enb += (1 << i);
}
else
{
pos = i;
}
}
*max = Pixels[pos];
}
static inline uint32_t ge_two(uint32_t enb)
{
if(enb & 1)
{
if(enb & 2)
return 1;
if(enb & 4)
return 1;
if(enb & 8)
return 1;
if(enb & 16)
return 1;
if(enb & 32)
return 1;
if(enb & 64)
return 1;
if(enb & 128)
return 1;
return 0;
}
else if(enb & 2)
{
if(enb & 4)
return 1;
if(enb & 8)
return 1;
if(enb & 16)
return 1;
if(enb & 32)
return 1;
if(enb & 64)
return 1;
if(enb & 128)
return 1;
return 0;
}
else if(enb & 4)
{
if(enb & 8)
return 1;
if(enb & 16)
return 1;
if(enb & 32)
return 1;
if(enb & 64)
return 1;
if(enb & 128)
return 1;
return 0;
}
else if(enb & 8)
{
if(enb & 16)
return 1;
if(enb & 32)
return 1;
if(enb & 64)
return 1;
if(enb & 128)
return 1;
return 0;
}
else if(enb & 16)
{
if(enb & 32)
return 1;
if(enb & 64)
return 1;
if(enb & 128)
return 1;
return 0;
}
else if(enb & 32)
{
if(enb & 64)
return 1;
if(enb & 128)
return 1;
return 0;
}
else if(enb & 64)
{
if(enb & 128)
return 1;
return 0;
}
return 0;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,165 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
/******************************************************************************
SGI/Nintendo Reality Display Texture Fetch Unit (TF)
-------------------
by Ryan Holtz
based on initial C code by Ville Linde
contains additional improvements from angrylion, Ziggy, Gonetz and Orkin
******************************************************************************/
#ifndef _VIDEO_RDPTEXPIPE_H_
#define _VIDEO_RDPTEXPIPE_H_
#include "video/n64types.h"
class n64_texture_pipe_t
{
public:
typedef void (n64_texture_pipe_t::*texel_fetcher_t) (rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
typedef void (n64_texture_pipe_t::*texel_cycler_t) (color_t* TEX, color_t* prev, int32_t SSS, int32_t SST, uint32_t tilenum, uint32_t cycle, rdp_span_aux* userdata, const rdp_poly_state& object);
n64_texture_pipe_t()
{
m_maskbits_table[0] = 0xffff;
for(int i = 1; i < 16; i++)
{
m_maskbits_table[i] = ((uint16_t)(0xffff) >> (16 - i)) & 0x3ff;
}
m_start_span = false;
for (auto & elem : m_texel_fetch)
{
elem = &n64_texture_pipe_t::fetch_nop;
}
m_texel_fetch[ 8] = &n64_texture_pipe_t::fetch_rgba16_raw;
m_texel_fetch[ 9] = &n64_texture_pipe_t::fetch_rgba16_raw;
m_texel_fetch[10] = &n64_texture_pipe_t::fetch_rgba16_tlut0;
m_texel_fetch[11] = &n64_texture_pipe_t::fetch_rgba16_tlut1;
m_texel_fetch[12] = &n64_texture_pipe_t::fetch_rgba32_raw;
m_texel_fetch[13] = &n64_texture_pipe_t::fetch_rgba32_raw;
m_texel_fetch[14] = &n64_texture_pipe_t::fetch_rgba32_tlut0;
m_texel_fetch[15] = &n64_texture_pipe_t::fetch_rgba32_tlut1;
m_texel_fetch[24] = &n64_texture_pipe_t::fetch_yuv;
m_texel_fetch[25] = &n64_texture_pipe_t::fetch_yuv;
m_texel_fetch[26] = &n64_texture_pipe_t::fetch_yuv;
m_texel_fetch[27] = &n64_texture_pipe_t::fetch_yuv;
m_texel_fetch[32] = &n64_texture_pipe_t::fetch_ci4_raw;
m_texel_fetch[33] = &n64_texture_pipe_t::fetch_ci4_raw;
m_texel_fetch[34] = &n64_texture_pipe_t::fetch_ci4_tlut0;
m_texel_fetch[35] = &n64_texture_pipe_t::fetch_ci4_tlut1;
m_texel_fetch[36] = &n64_texture_pipe_t::fetch_ci8_raw;
m_texel_fetch[37] = &n64_texture_pipe_t::fetch_ci8_raw;
m_texel_fetch[38] = &n64_texture_pipe_t::fetch_ci8_tlut0;
m_texel_fetch[39] = &n64_texture_pipe_t::fetch_ci8_tlut1;
m_texel_fetch[48] = &n64_texture_pipe_t::fetch_ia4_raw;
m_texel_fetch[49] = &n64_texture_pipe_t::fetch_ia4_raw;
m_texel_fetch[50] = &n64_texture_pipe_t::fetch_ia4_tlut0;
m_texel_fetch[51] = &n64_texture_pipe_t::fetch_ia4_tlut1;
m_texel_fetch[52] = &n64_texture_pipe_t::fetch_ia8_raw;
m_texel_fetch[53] = &n64_texture_pipe_t::fetch_ia8_raw;
m_texel_fetch[54] = &n64_texture_pipe_t::fetch_ia8_tlut0;
m_texel_fetch[55] = &n64_texture_pipe_t::fetch_ia8_tlut1;
m_texel_fetch[56] = &n64_texture_pipe_t::fetch_ia16_raw;
m_texel_fetch[57] = &n64_texture_pipe_t::fetch_ia16_raw;
m_texel_fetch[58] = &n64_texture_pipe_t::fetch_ia16_tlut0;
m_texel_fetch[59] = &n64_texture_pipe_t::fetch_ia16_tlut1;
m_texel_fetch[64] = &n64_texture_pipe_t::fetch_i4_raw;
m_texel_fetch[65] = &n64_texture_pipe_t::fetch_i4_raw;
m_texel_fetch[66] = &n64_texture_pipe_t::fetch_i4_tlut0;
m_texel_fetch[67] = &n64_texture_pipe_t::fetch_i4_tlut1;
m_texel_fetch[68] = &n64_texture_pipe_t::fetch_i8_raw;
m_texel_fetch[69] = &n64_texture_pipe_t::fetch_i8_raw;
m_texel_fetch[70] = &n64_texture_pipe_t::fetch_i8_tlut0;
m_texel_fetch[71] = &n64_texture_pipe_t::fetch_i8_tlut1;
m_cycle[0] = &n64_texture_pipe_t::cycle_nearest;
m_cycle[1] = &n64_texture_pipe_t::cycle_nearest_lerp;
m_cycle[2] = &n64_texture_pipe_t::cycle_linear;
m_cycle[3] = &n64_texture_pipe_t::cycle_linear_lerp;
}
void cycle_nearest(color_t* TEX, color_t* prev, int32_t SSS, int32_t SST, uint32_t tilenum, uint32_t cycle, rdp_span_aux* userdata, const rdp_poly_state& object);
void cycle_nearest_lerp(color_t* TEX, color_t* prev, int32_t SSS, int32_t SST, uint32_t tilenum, uint32_t cycle, rdp_span_aux* userdata, const rdp_poly_state& object);
void cycle_linear(color_t* TEX, color_t* prev, int32_t SSS, int32_t SST, uint32_t tilenum, uint32_t cycle, rdp_span_aux* userdata, const rdp_poly_state& object);
void cycle_linear_lerp(color_t* TEX, color_t* prev, int32_t SSS, int32_t SST, uint32_t tilenum, uint32_t cycle, rdp_span_aux* userdata, const rdp_poly_state& object);
texel_cycler_t m_cycle[4];
void copy(color_t* TEX, int32_t SSS, int32_t SST, uint32_t tilenum, const rdp_poly_state& object, rdp_span_aux* userdata);
void calculate_clamp_diffs(uint32_t prim_tile, rdp_span_aux* userdata, const rdp_poly_state& object);
void lod_1cycle(int32_t* sss, int32_t* sst, const int32_t s, const int32_t t, const int32_t w, const int32_t dsinc, const int32_t dtinc, const int32_t dwinc, rdp_span_aux* userdata, const rdp_poly_state& object);
void lod_2cycle(int32_t* sss, int32_t* sst, const int32_t s, const int32_t t, const int32_t w, const int32_t dsinc, const int32_t dtinc, const int32_t dwinc, const int32_t prim_tile, int32_t* t1, int32_t* t2, rdp_span_aux* userdata, const rdp_poly_state& object);
void lod_2cycle_limited(int32_t* sss, int32_t* sst, const int32_t s, const int32_t t, int32_t w, const int32_t dsinc, const int32_t dtinc, const int32_t dwinc, const int32_t prim_tile, int32_t* t1, const rdp_poly_state& object);
void set_machine(running_machine& machine);
bool m_start_span;
private:
void mask(rgbaint_t& sstt, const n64_tile_t& tile);
rgbaint_t shift_cycle(rgbaint_t& st, const n64_tile_t& tile);
void shift_copy(rgbaint_t& st, const n64_tile_t& tile);
void clamp_cycle(rgbaint_t& st, rgbaint_t& stfrac, rgbaint_t& maxst, const int32_t tilenum, const n64_tile_t& tile, rdp_span_aux* userdata);
void clamp_cycle_light(rgbaint_t& st, rgbaint_t& maxst, const int32_t tilenum, const n64_tile_t& tile, rdp_span_aux* userdata);
void fetch_nop(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
void fetch_rgba16_tlut0(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
void fetch_rgba16_tlut1(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
void fetch_rgba16_raw(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
void fetch_rgba32_tlut0(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
void fetch_rgba32_tlut1(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
void fetch_rgba32_raw(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
void fetch_yuv(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
void fetch_ci4_tlut0(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
void fetch_ci4_tlut1(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
void fetch_ci4_raw(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
void fetch_ci8_tlut0(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
void fetch_ci8_tlut1(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
void fetch_ci8_raw(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
void fetch_ia4_tlut0(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
void fetch_ia4_tlut1(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
void fetch_ia4_raw(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
void fetch_ia8_tlut0(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
void fetch_ia8_tlut1(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
void fetch_ia8_raw(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
void fetch_ia16_tlut0(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
void fetch_ia16_tlut1(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
void fetch_ia16_raw(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
void fetch_i4_tlut0(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
void fetch_i4_tlut1(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
void fetch_i4_raw(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
void fetch_i8_tlut0(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
void fetch_i8_tlut1(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
void fetch_i8_raw(rgbaint_t& out, int32_t s, int32_t t, int32_t tbase, int32_t tpal, rdp_span_aux* userdata);
texel_fetcher_t m_texel_fetch[16*5];
n64_rdp* m_rdp;
int32_t m_maskbits_table[16];
color_t m_expand_16to32_table[0x10000];
uint16_t m_lod_lookup[0x80000];
rgbaint_t m_st2_add;
rgbaint_t m_v1;
};
#endif // _VIDEO_RDPTEXPIPE_H_

View File

@ -1,148 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/***************************************************************************
eigccppc.h
Inline implementations for GCC compilers. This code is automatically
included if appropriate by eminline.h.
***************************************************************************/
#ifndef MAME_OSD_EIGCC_H
#define MAME_OSD_EIGCC_H
#include <cassert>
/***************************************************************************
INLINE MATH FUNCTIONS
***************************************************************************/
/*-------------------------------------------------
addu_32x32_co - perform an unsigned 32 bit + 32
bit addition and return the result with carry
out
-------------------------------------------------*/
#ifndef addu_32x32_co
#define addu_32x32_co _addu_32x32_co
inline bool _addu_32x32_co(uint32_t a, uint32_t b, uint32_t &sum)
{
return __builtin_add_overflow(a, b, &sum);
}
#endif
/*-------------------------------------------------
addu_64x64_co - perform an unsigned 64 bit + 64
bit addition and return the result with carry
out
-------------------------------------------------*/
#ifndef addu_64x64_co
#define addu_64x64_co _addu_64x64_co
inline bool _addu_64x64_co(uint64_t a, uint64_t b, uint64_t &sum)
{
return __builtin_add_overflow(a, b, &sum);
}
#endif
/***************************************************************************
INLINE BIT MANIPULATION FUNCTIONS
***************************************************************************/
/*-------------------------------------------------
count_leading_zeros_32 - return the number of
leading zero bits in a 32-bit value
-------------------------------------------------*/
#ifndef count_leading_zeros_32
#define count_leading_zeros_32 _count_leading_zeros_32
inline uint8_t _count_leading_zeros_32(uint32_t val)
{
// uses CPU feature if available, otherwise falls back to runtime library call
static_assert(sizeof(val) == sizeof(unsigned), "expected 32-bit unsigned int");
return uint8_t(unsigned(val ? __builtin_clz(val) : 32));
}
#endif
/*-------------------------------------------------
count_leading_ones_32 - return the number of
leading one bits in a 32-bit value
-------------------------------------------------*/
#ifndef count_leading_ones_32
#define count_leading_ones_32 _count_leading_ones_32
inline uint8_t _count_leading_ones_32(uint32_t val)
{
return count_leading_zeros_32(~val);
}
#endif
/*-------------------------------------------------
count_leading_zeros_64 - return the number of
leading zero bits in a 64-bit value
-------------------------------------------------*/
#ifndef count_leading_zeros_64
#define count_leading_zeros_64 _count_leading_zeros_64
inline uint8_t _count_leading_zeros_64(uint64_t val)
{
// uses CPU feature if available, otherwise falls back to runtime library call
static_assert(sizeof(val) == sizeof(unsigned long long), "expected 64-bit unsigned long long int");
return uint8_t(unsigned(val ? __builtin_clzll(val) : 64));
}
#endif
/*-------------------------------------------------
count_leading_ones_64 - return the number of
leading one bits in a 64-bit value
-------------------------------------------------*/
#ifndef count_leading_ones_64
#define count_leading_ones_64 _count_leading_ones_64
inline uint8_t _count_leading_ones_64(uint64_t val)
{
return count_leading_zeros_64(~val);
}
#endif
/*-------------------------------------------------
population_count_32 - return the number of
one bits in a 32-bit value
-------------------------------------------------*/
#ifndef population_count_32
#define population_count_32 _population_count_32
inline unsigned _population_count_32(uint32_t val)
{
// uses CPU feature if available, otherwise falls back to implementation similar to eminline.h
static_assert(sizeof(val) == sizeof(unsigned), "expected 32-bit unsigned int");
return unsigned(__builtin_popcount(static_cast<unsigned>(val)));
}
#endif
/*-------------------------------------------------
population_count_64 - return the number of
one bits in a 64-bit value
-------------------------------------------------*/
#ifndef population_count_64
#define population_count_64 _population_count_64
inline unsigned _population_count_64(uint64_t val)
{
// uses CPU feature if available, otherwise falls back to implementation similar to eminline.h
static_assert(sizeof(val) == sizeof(unsigned long long), "expected 64-bit unsigned long long int");
return unsigned(__builtin_popcountll(static_cast<unsigned long long>(val)));
}
#endif
#endif // MAME_OSD_EIGCC_H

View File

@ -1,332 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/***************************************************************************
eigccarm.h
ARM/AArch64 inline implementations for GCC compilers. This code is
automatically included if appropriate by eminline.h.
***************************************************************************/
#ifndef MAME_OSD_EIGCCARM_H
#define MAME_OSD_EIGCCARM_H
/***************************************************************************
INLINE MATH FUNCTIONS
***************************************************************************/
/*-------------------------------------------------
mul_32x32 - perform a signed 32 bit x 32 bit
multiply and return the full 64 bit result
-------------------------------------------------*/
// GCC can do a good job of this.
/*-------------------------------------------------
mulu_32x32 - perform an unsigned 32 bit x
32 bit multiply and return the full 64 bit
result
-------------------------------------------------*/
// GCC can do a good job of this
/*-------------------------------------------------
mul_32x32_hi - perform a signed 32 bit x 32 bit
multiply and return the upper 32 bits of the
result
-------------------------------------------------*/
// GCC can do a good job of this
/*-------------------------------------------------
mulu_32x32_hi - perform an unsigned 32 bit x
32 bit multiply and return the upper 32 bits
of the result
-------------------------------------------------*/
// GCC can do a good job of this
/*-------------------------------------------------
mul_32x32_shift - perform a signed 32 bit x
32 bit multiply and shift the result by the
given number of bits before truncating the
result to 32 bits
-------------------------------------------------*/
#if !defined(__aarch64__)
#define mul_32x32_shift _mul_32x32_shift
inline int32_t ATTR_CONST ATTR_FORCE_INLINE
_mul_32x32_shift(int32_t val1, int32_t val2, uint8_t shift)
{
uint32_t l, h;
__asm__ (
" smull %[l], %[h], %[val1], %[val2] \n"
: [l] "=r" (l)
, [h] "=r" (h)
: [val1] "%r" (val1)
, [val2] "r" (val2)
);
// Valid for (0 <= shift <= 31)
return int32_t((l >> shift) | (h << (32 - shift)));
}
#endif
/*-------------------------------------------------
mulu_32x32_shift - perform an unsigned 32 bit x
32 bit multiply and shift the result by the
given number of bits before truncating the
result to 32 bits
-------------------------------------------------*/
#if !defined(__aarch64__)
#define mulu_32x32_shift _mulu_32x32_shift
inline uint32_t ATTR_CONST ATTR_FORCE_INLINE
_mulu_32x32_shift(uint32_t val1, uint32_t val2, uint8_t shift)
{
uint32_t l, h;
__asm__ (
" umull %[l], %[h], %[val1], %[val2] \n"
: [l] "=r" (l)
, [h] "=r" (h)
: [val1] "%r" (val1)
, [val2] "r" (val2)
);
// Valid for (0 <= shift <= 31)
return (l >> shift) | (h << (32 - shift));
}
#endif
/*-------------------------------------------------
div_64x32 - perform a signed 64 bit x 32 bit
divide and return the 32 bit quotient
-------------------------------------------------*/
// TBD
/*-------------------------------------------------
divu_64x32 - perform an unsigned 64 bit x 32 bit
divide and return the 32 bit quotient
-------------------------------------------------*/
// TBD
/*-------------------------------------------------
div_64x32_rem - perform a signed 64 bit x 32
bit divide and return the 32 bit quotient and
32 bit remainder
-------------------------------------------------*/
// TBD
/*-------------------------------------------------
divu_64x32_rem - perform an unsigned 64 bit x
32 bit divide and return the 32 bit quotient
and 32 bit remainder
-------------------------------------------------*/
// TBD
/*-------------------------------------------------
div_32x32_shift - perform a signed divide of
two 32 bit values, shifting the first before
division, and returning the 32 bit quotient
-------------------------------------------------*/
// TBD
/*-------------------------------------------------
divu_32x32_shift - perform an unsigned divide of
two 32 bit values, shifting the first before
division, and returning the 32 bit quotient
-------------------------------------------------*/
// TBD
/*-------------------------------------------------
mod_64x32 - perform a signed 64 bit x 32 bit
divide and return the 32 bit remainder
-------------------------------------------------*/
// TBD
/*-------------------------------------------------
modu_64x32 - perform an unsigned 64 bit x 32 bit
divide and return the 32 bit remainder
-------------------------------------------------*/
// TBD
/*-------------------------------------------------
recip_approx - compute an approximate floating
point reciprocal
-------------------------------------------------*/
#if defined(__aarch64__)
#define recip_approx _recip_approx
inline float ATTR_CONST ATTR_FORCE_INLINE
_recip_approx(float value)
{
float result;
__asm__ (
" frecpe %s[result], %s[value] \n"
: [result] "=w" (result)
: [value] "w" (value)
);
return result;
}
#endif
/*-------------------------------------------------
mul_64x64 - perform a signed 64 bit x 64 bit
multiply and return the full 128 bit result
-------------------------------------------------*/
#if defined(__aarch64__)
#define mul_64x64 _mul_64x64
inline int64_t ATTR_FORCE_INLINE
_mul_64x64(int64_t a, int64_t b, int64_t &hi)
{
__int128 const r(__int128(a) * b);
hi = int64_t(uint64_t((unsigned __int128)r >> 64));
return int64_t(uint64_t((unsigned __int128)r));
}
#endif
/*-------------------------------------------------
mulu_64x64 - perform an unsigned 64 bit x 64
bit multiply and return the full 128 bit result
-------------------------------------------------*/
#if defined(__aarch64__)
#define mulu_64x64 _mulu_64x64
inline uint64_t ATTR_FORCE_INLINE
_mulu_64x64(uint64_t a, uint64_t b, uint64_t &hi)
{
unsigned __int128 const r((unsigned __int128)a * b);
hi = uint64_t(r >> 64);
return uint64_t(r);
}
#endif
/***************************************************************************
INLINE BIT MANIPULATION FUNCTIONS
***************************************************************************/
/*-------------------------------------------------
count_leading_zeros_32 - return the number of
leading zero bits in a 32-bit value
-------------------------------------------------*/
#if defined(__aarch64__)
#define count_leading_zeros_32 _count_leading_zeros_32
inline uint8_t ATTR_CONST ATTR_FORCE_INLINE
_count_leading_zeros_32(uint32_t value)
{
uint32_t result;
__asm__ (
" clz %w[result], %w[value] \n"
: [result] "=r" (result)
: [value] "r" (value)
);
return uint8_t(result);
}
#endif
/*-------------------------------------------------
count_leading_ones_32 - return the number of
leading one bits in a 32-bit value
-------------------------------------------------*/
#if defined(__aarch64__)
#define count_leading_ones_32 _count_leading_ones_32
inline uint8_t ATTR_CONST ATTR_FORCE_INLINE
_count_leading_ones_32(uint32_t value)
{
uint32_t result;
__asm__ (
" clz %w[result], %w[value] \n"
: [result] "=r" (result)
: [value] "r" (~value)
);
return uint8_t(result);
}
#endif
/*-------------------------------------------------
count_leading_zeros_64 - return the number of
leading zero bits in a 64-bit value
-------------------------------------------------*/
#if defined(__aarch64__)
#define count_leading_zeros_64 _count_leading_zeros_64
inline uint8_t ATTR_CONST ATTR_FORCE_INLINE
_count_leading_zeros_64(uint64_t value)
{
uint64_t result;
__asm__ (
" clz %[result], %[value] \n"
: [result] "=r" (result)
: [value] "r" (value)
);
return uint8_t(result);
}
#endif
/*-------------------------------------------------
count_leading_ones_64 - return the number of
leading one bits in a 64-bit value
-------------------------------------------------*/
#if defined(__aarch64__)
#define count_leading_ones_64 _count_leading_ones_64
inline uint8_t ATTR_CONST ATTR_FORCE_INLINE
_count_leading_ones_64(uint64_t value)
{
uint64_t result;
__asm__ (
" clz %[result], %[value] \n"
: [result] "=r" (result)
: [value] "r" (~value)
);
return uint8_t(result);
}
#endif
#endif // MAME_OSD_EIGCCARM_H

View File

@ -1,328 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/***************************************************************************
eigccppc.h
PowerPC (32 and 64-bit) inline implementations for GCC compilers. This
code is automatically included if appropriate by eminline.h.
***************************************************************************/
#ifndef MAME_OSD_EIGCCPPC_H
#define MAME_OSD_EIGCCPPC_H
/***************************************************************************
INLINE MATH FUNCTIONS
***************************************************************************/
/*-------------------------------------------------
mul_32x32 - perform a signed 32 bit x 32 bit
multiply and return the full 64 bit result
-------------------------------------------------*/
// GCC can do a good job of this.
/*-------------------------------------------------
mulu_32x32 - perform an unsigned 32 bit x
32 bit multiply and return the full 64 bit
result
-------------------------------------------------*/
// GCC can do a good job of this
/*-------------------------------------------------
mul_32x32_hi - perform a signed 32 bit x 32 bit
multiply and return the upper 32 bits of the
result
-------------------------------------------------*/
// GCC can do a good job of this
/*-------------------------------------------------
mulu_32x32_hi - perform an unsigned 32 bit x
32 bit multiply and return the upper 32 bits
of the result
-------------------------------------------------*/
// GCC can do a good job of this
/*-------------------------------------------------
mul_32x32_shift - perform a signed 32 bit x
32 bit multiply and shift the result by the
given number of bits before truncating the
result to 32 bits
-------------------------------------------------*/
#if !defined(__ppc64__) && !defined(__PPC64__) && !defined(_ARCH_PPC64)
#define mul_32x32_shift _mul_32x32_shift
inline int32_t ATTR_CONST ATTR_FORCE_INLINE
_mul_32x32_shift(int32_t val1, int32_t val2, uint8_t shift)
{
uint32_t l, h;
__asm__ (
" mullw %[l], %[val1], %[val2] \n"
" mulhw %[h], %[val1], %[val2] \n"
: [l] "=&r" (l)
, [h] "=r" (h)
: [val1] "%r" (val1)
, [val2] "r" (val2)
);
// Valid for (0 <= shift <= 31)
return int32_t((l >> shift) | (h << (32 - shift)));
}
#endif
/*-------------------------------------------------
mulu_32x32_shift - perform an unsigned 32 bit x
32 bit multiply and shift the result by the
given number of bits before truncating the
result to 32 bits
-------------------------------------------------*/
#if !defined(__ppc64__) && !defined(__PPC64__) && !defined(_ARCH_PPC64)
#define mulu_32x32_shift _mulu_32x32_shift
inline uint32_t ATTR_CONST ATTR_FORCE_INLINE
_mulu_32x32_shift(uint32_t val1, uint32_t val2, uint8_t shift)
{
uint32_t l, h;
__asm__ (
" mullw %[l], %[val1], %[val2] \n"
" mulhwu %[h], %[val1], %[val2] \n"
: [l] "=&r" (l)
, [h] "=r" (h)
: [val1] "%r" (val1)
, [val2] "r" (val2)
);
// Valid for (0 <= shift <= 31)
return (l >> shift) | (h << (32 - shift));
}
#endif
/*-------------------------------------------------
div_64x32 - perform a signed 64 bit x 32 bit
divide and return the 32 bit quotient
-------------------------------------------------*/
// TBD
/*-------------------------------------------------
divu_64x32 - perform an unsigned 64 bit x 32 bit
divide and return the 32 bit quotient
-------------------------------------------------*/
// TBD
/*-------------------------------------------------
div_64x32_rem - perform a signed 64 bit x 32
bit divide and return the 32 bit quotient and
32 bit remainder
-------------------------------------------------*/
// TBD
/*-------------------------------------------------
divu_64x32_rem - perform an unsigned 64 bit x
32 bit divide and return the 32 bit quotient
and 32 bit remainder
-------------------------------------------------*/
// TBD
/*-------------------------------------------------
div_32x32_shift - perform a signed divide of
two 32 bit values, shifting the first before
division, and returning the 32 bit quotient
-------------------------------------------------*/
// TBD
/*-------------------------------------------------
divu_32x32_shift - perform an unsigned divide of
two 32 bit values, shifting the first before
division, and returning the 32 bit quotient
-------------------------------------------------*/
// TBD
/*-------------------------------------------------
mod_64x32 - perform a signed 64 bit x 32 bit
divide and return the 32 bit remainder
-------------------------------------------------*/
// TBD
/*-------------------------------------------------
modu_64x32 - perform an unsigned 64 bit x 32 bit
divide and return the 32 bit remainder
-------------------------------------------------*/
// TBD
/*-------------------------------------------------
recip_approx - compute an approximate floating
point reciprocal
-------------------------------------------------*/
#define recip_approx _recip_approx
inline float ATTR_CONST ATTR_FORCE_INLINE
_recip_approx(float value)
{
float result;
__asm__ (
" fres %[result], %[value] \n"
: [result] "=f" (result)
: [value] "f" (value)
);
return result;
}
/*-------------------------------------------------
mul_64x64 - perform a signed 64 bit x 64 bit
multiply and return the full 128 bit result
-------------------------------------------------*/
#if defined(__ppc64__) || defined(__PPC64___) || defined(_ARCH_PPC64)
#define mul_64x64 _mul_64x64
inline int64_t ATTR_FORCE_INLINE
_mul_64x64(int64_t a, int64_t b, int64_t &hi)
{
__int128 const r(__int128(a) * b);
hi = int64_t(uint64_t((unsigned __int128)r >> 64));
return int64_t(uint64_t((unsigned __int128)r));
}
#endif
/*-------------------------------------------------
mulu_64x64 - perform an unsigned 64 bit x 64
bit multiply and return the full 128 bit result
-------------------------------------------------*/
#if defined(__ppc64__) || defined(__PPC64___) || defined(_ARCH_PPC64)
#define mulu_64x64 _mulu_64x64
inline uint64_t ATTR_FORCE_INLINE
_mulu_64x64(uint64_t a, uint64_t b, uint64_t &hi)
{
unsigned __int128 const r((unsigned __int128)a * b);
hi = uint64_t(r >> 64);
return uint64_t(r);
}
#endif
/***************************************************************************
INLINE BIT MANIPULATION FUNCTIONS
***************************************************************************/
/*-------------------------------------------------
count_leading_zeros_32 - return the number of
leading zero bits in a 32-bit value
-------------------------------------------------*/
#define count_leading_zeros_32 _count_leading_zeros_32
inline uint8_t ATTR_CONST ATTR_FORCE_INLINE
_count_leading_zeros_32(uint32_t value)
{
uint32_t result;
__asm__ (
" cntlzw %[result], %[value] \n"
: [result] "=r" (result)
: [value] "r" (value)
);
return uint8_t(result);
}
/*-------------------------------------------------
count_leading_ones_32 - return the number of
leading one bits in a 32-bit value
-------------------------------------------------*/
#define count_leading_ones_32 _count_leading_ones_32
inline uint8_t ATTR_CONST ATTR_FORCE_INLINE
_count_leading_ones_32(uint32_t value)
{
uint32_t result;
__asm__ (
" cntlzw %[result], %[value] \n"
: [result] "=r" (result)
: [value] "r" (~value)
);
return uint8_t(result);
}
/*-------------------------------------------------
count_leading_zeros_64 - return the number of
leading zero bits in a 64-bit value
-------------------------------------------------*/
#if defined(__ppc64__) || defined(__PPC64___) || defined(_ARCH_PPC64)
#define count_leading_zeros_64 _count_leading_zeros_64
inline uint8_t ATTR_CONST ATTR_FORCE_INLINE
_count_leading_zeros_64(uint64_t value)
{
uint64_t result;
__asm__ (
" cntlzd %[result], %[value] \n"
: [result] "=r" (result)
: [value] "r" (value)
);
return uint8_t(result);
}
#endif
/*-------------------------------------------------
count_leading_ones_64 - return the number of
leading one bits in a 64-bit value
-------------------------------------------------*/
#if defined(__ppc64__) || defined(__PPC64___) || defined(_ARCH_PPC64)
#define count_leading_ones_64 _count_leading_ones_64
inline uint8_t ATTR_CONST ATTR_FORCE_INLINE
_count_leading_ones_64(uint64_t value)
{
uint64_t result;
__asm__ (
" cntlzd %[result], %[value] \n"
: [result] "=r" (result)
: [value] "r" (~value)
);
return uint8_t(result);
}
#endif
#endif // MAME_OSD_EIGCCPPC_H

View File

@ -1,526 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/***************************************************************************
eigccx86.h
x86 (32 and 64-bit) inline implementations for GCC compilers. This
code is automatically included if appropriate by eminline.h.
***************************************************************************/
#ifndef MAME_OSD_EIGCCX86_H
#define MAME_OSD_EIGCCX86_H
// Include MMX/SSE intrinsics headers
#ifdef __SSE2__
#include <cstdlib>
#include <mmintrin.h> // MMX
#include <xmmintrin.h> // SSE
#include <emmintrin.h> // SSE2
#endif
/***************************************************************************
INLINE MATH FUNCTIONS
***************************************************************************/
/*-------------------------------------------------
mul_32x32 - perform a signed 32 bit x 32 bit
multiply and return the full 64 bit result
-------------------------------------------------*/
// GCC can do a good job of this.
/*-------------------------------------------------
mulu_32x32 - perform an unsigned 32 bit x
32 bit multiply and return the full 64 bit
result
-------------------------------------------------*/
// GCC can do a good job of this.
/*-------------------------------------------------
mul_32x32_hi - perform a signed 32 bit x 32 bit
multiply and return the upper 32 bits of the
result
-------------------------------------------------*/
// GCC can do a good job of this.
/*-------------------------------------------------
mulu_32x32_hi - perform an unsigned 32 bit x
32 bit multiply and return the upper 32 bits
of the result
-------------------------------------------------*/
// GCC can do a good job of this.
/*-------------------------------------------------
mul_32x32_shift - perform a signed 32 bit x
32 bit multiply and shift the result by the
given number of bits before truncating the
result to 32 bits
-------------------------------------------------*/
#ifndef __x86_64__
#define mul_32x32_shift _mul_32x32_shift
inline int32_t ATTR_CONST ATTR_FORCE_INLINE
_mul_32x32_shift(int32_t a, int32_t b, uint8_t shift)
{
int32_t result;
// Valid for (0 <= shift <= 31)
__asm__ (
" imull %[b] ;"
" shrdl %[shift], %%edx, %[result] ;"
: [result] "=a" (result) // result ends up in eax
: [a] "%0" (a) // 'a' should also be in eax on entry
, [b] "rm" (b) // 'b' can be memory or register
, [shift] "Ic" (shift) // 'shift' must be constant in 0-31 range or in cl
: "%edx", "cc" // clobbers edx and condition codes
);
return result;
}
#endif
/*-------------------------------------------------
mulu_32x32_shift - perform an unsigned 32 bit x
32 bit multiply and shift the result by the
given number of bits before truncating the
result to 32 bits
-------------------------------------------------*/
#ifndef __x86_64__
#define mulu_32x32_shift _mulu_32x32_shift
inline uint32_t ATTR_CONST ATTR_FORCE_INLINE
_mulu_32x32_shift(uint32_t a, uint32_t b, uint8_t shift)
{
uint32_t result;
// Valid for (0 <= shift <= 31)
__asm__ (
" mull %[b] ;"
" shrdl %[shift], %%edx, %[result] ;"
: [result] "=a" (result) // result ends up in eax
: [a] "%0" (a) // 'a' should also be in eax on entry
, [b] "rm" (b) // 'b' can be memory or register
, [shift] "Ic" (shift) // 'shift' must be constant in 0-31 range or in cl
: "%edx", "cc" // clobbers edx and condition codes
);
return result;
}
#endif
/*-------------------------------------------------
div_64x32 - perform a signed 64 bit x 32 bit
divide and return the 32 bit quotient
-------------------------------------------------*/
#ifndef __x86_64__
#define div_64x32 _div_64x32
inline int32_t ATTR_CONST ATTR_FORCE_INLINE
_div_64x32(int64_t a, int32_t b)
{
int32_t result, temp;
// Throws arithmetic exception if result doesn't fit in 32 bits
__asm__ (
" idivl %[b] ;"
: [result] "=a" (result) // result ends up in eax
, [temp] "=d" (temp) // this is effectively a clobber
: [a] "A" (a) // 'a' in edx:eax
, [b] "rm" (b) // 'b' in register or memory
: "cc" // clobbers condition codes
);
return result;
}
#endif
/*-------------------------------------------------
divu_64x32 - perform an unsigned 64 bit x 32 bit
divide and return the 32 bit quotient
-------------------------------------------------*/
#ifndef __x86_64__
#define divu_64x32 _divu_64x32
inline uint32_t ATTR_CONST ATTR_FORCE_INLINE
_divu_64x32(uint64_t a, uint32_t b)
{
uint32_t result, temp;
// Throws arithmetic exception if result doesn't fit in 32 bits
__asm__ (
" divl %[b] ;"
: [result] "=a" (result) // result ends up in eax
, [temp] "=d" (temp) // this is effectively a clobber
: [a] "A" (a) // 'a' in edx:eax
, [b] "rm" (b) // 'b' in register or memory
: "cc" // clobbers condition codes
);
return result;
}
#endif
/*-------------------------------------------------
div_64x32_rem - perform a signed 64 bit x 32
bit divide and return the 32 bit quotient and
32 bit remainder
-------------------------------------------------*/
#define div_64x32_rem _div_64x32_rem
inline int32_t ATTR_FORCE_INLINE
_div_64x32_rem(int64_t dividend, int32_t divisor, int32_t &remainder)
{
int32_t quotient;
#ifndef __x86_64__
// Throws arithmetic exception if result doesn't fit in 32 bits
__asm__ (
" idivl %[divisor] ;"
: [result] "=a" (quotient) // quotient ends up in eax
, [remainder] "=d" (remainder) // remainder ends up in edx
: [dividend] "A" (dividend) // 'dividend' in edx:eax
, [divisor] "rm" (divisor) // 'divisor' in register or memory
: "cc" // clobbers condition codes
);
#else
int32_t const divh{ int32_t(uint32_t(uint64_t(dividend) >> 32)) };
int32_t const divl{ int32_t(uint32_t(uint64_t(dividend))) };
// Throws arithmetic exception if result doesn't fit in 32 bits
__asm__ (
" idivl %[divisor] ;"
: [result] "=a" (quotient) // quotient ends up in eax
, [remainder] "=d" (remainder) // remainder ends up in edx
: [divl] "a" (divl) // 'dividend' in edx:eax
, [divh] "d" (divh)
, [divisor] "rm" (divisor) // 'divisor' in register or memory
: "cc" // clobbers condition codes
);
#endif
return quotient;
}
/*-------------------------------------------------
divu_64x32_rem - perform an unsigned 64 bit x
32 bit divide and return the 32 bit quotient
and 32 bit remainder
-------------------------------------------------*/
#define divu_64x32_rem _divu_64x32_rem
inline uint32_t ATTR_FORCE_INLINE
_divu_64x32_rem(uint64_t dividend, uint32_t divisor, uint32_t &remainder)
{
uint32_t quotient;
#ifndef __x86_64__
// Throws arithmetic exception if result doesn't fit in 32 bits
__asm__ (
" divl %[divisor] ;"
: [result] "=a" (quotient) // quotient ends up in eax
, [remainder] "=d" (remainder) // remainder ends up in edx
: [dividend] "A" (dividend) // 'dividend' in edx:eax
, [divisor] "rm" (divisor) // 'divisor' in register or memory
: "cc" // clobbers condition codes
);
#else
uint32_t const divh{ uint32_t(dividend >> 32) };
uint32_t const divl{ uint32_t(dividend) };
// Throws arithmetic exception if result doesn't fit in 32 bits
__asm__ (
" divl %[divisor] ;"
: [result] "=a" (quotient) // quotient ends up in eax
, [remainder] "=d" (remainder) // remainder ends up in edx
: [divl] "a" (divl) // 'dividend' in edx:eax
, [divh] "d" (divh)
, [divisor] "rm" (divisor) // 'divisor' in register or memory
: "cc" // clobbers condition codes
);
#endif
return quotient;
}
/*-------------------------------------------------
div_32x32_shift - perform a signed divide of
two 32 bit values, shifting the first before
division, and returning the 32 bit quotient
-------------------------------------------------*/
#ifndef __x86_64__
#define div_32x32_shift _div_32x32_shift
inline int32_t ATTR_CONST ATTR_FORCE_INLINE
_div_32x32_shift(int32_t a, int32_t b, uint8_t shift)
{
int32_t result;
// Valid for (0 <= shift <= 31)
// Throws arithmetic exception if result doesn't fit in 32 bits
__asm__ (
" cdq ;"
" shldl %[shift], %[a], %%edx ;"
" shll %[shift], %[a] ;"
" idivl %[b] ;"
: [result] "=&a" (result) // result ends up in eax
: [a] "0" (a) // 'a' should also be in eax on entry
, [b] "rm" (b) // 'b' can be memory or register
, [shift] "Ic" (shift) // 'shift' must be constant in 0-31 range or in cl
: "%edx", "cc" // clobbers edx and condition codes
);
return result;
}
#endif
/*-------------------------------------------------
divu_32x32_shift - perform an unsigned divide of
two 32 bit values, shifting the first before
division, and returning the 32 bit quotient
-------------------------------------------------*/
#ifndef __x86_64__
#define divu_32x32_shift _divu_32x32_shift
inline uint32_t ATTR_CONST ATTR_FORCE_INLINE
_divu_32x32_shift(uint32_t a, uint32_t b, uint8_t shift)
{
int32_t result;
// Valid for (0 <= shift <= 31)
// Throws arithmetic exception if result doesn't fit in 32 bits
__asm__ (
" clr %%edx ;"
" shldl %[shift], %[a], %%edx ;"
" shll %[shift], %[a] ;"
" divl %[b] ;"
: [result] "=&a" (result) // result ends up in eax
: [a] "0" (a) // 'a' should also be in eax on entry
, [b] "rm" (b) // 'b' can be memory or register
, [shift] "Ic" (shift) // 'shift' must be constant in 0-31 range or in cl
: "%edx", "cc" // clobbers edx and condition codes
);
return result;
}
#endif
/*-------------------------------------------------
mod_64x32 - perform a signed 64 bit x 32 bit
divide and return the 32 bit remainder
-------------------------------------------------*/
#ifndef __x86_64__
#define mod_64x32 _mod_64x32
inline int32_t ATTR_CONST ATTR_FORCE_INLINE
_mod_64x32(int64_t a, int32_t b)
{
int32_t result, temp;
// Throws arithmetic exception if quotient doesn't fit in 32 bits
__asm__ (
" idivl %[b] ;"
: [result] "=d" (result) // Result ends up in edx
, [temp] "=a" (temp) // This is effectively a clobber
: [a] "A" (a) // 'a' in edx:eax
, [b] "rm" (b) // 'b' in register or memory
: "cc" // Clobbers condition codes
);
return result;
}
#endif
/*-------------------------------------------------
modu_64x32 - perform an unsigned 64 bit x 32 bit
divide and return the 32 bit remainder
-------------------------------------------------*/
#ifndef __x86_64__
#define modu_64x32 _modu_64x32
inline uint32_t ATTR_CONST ATTR_FORCE_INLINE
_modu_64x32(uint64_t a, uint32_t b)
{
uint32_t result, temp;
// Throws arithmetic exception if quotient doesn't fit in 32 bits
__asm__ (
" divl %[b] ;"
: [result] "=d" (result) // Result ends up in edx
, [temp] "=a" (temp) // This is effectively a clobber
: [a] "A" (a) // 'a' in edx:eax
, [b] "rm" (b) // 'b' in register or memory
: "cc" // Clobbers condition codes
);
return result;
}
#endif
/*-------------------------------------------------
recip_approx - compute an approximate floating
point reciprocal
-------------------------------------------------*/
#ifdef __SSE2__
#define recip_approx _recip_approx
inline float ATTR_CONST ATTR_FORCE_INLINE
_recip_approx(float value)
{
__m128 const value_xmm(_mm_set_ss(value));
__m128 const result_xmm(_mm_rcp_ss(value_xmm));
float result;
_mm_store_ss(&result, result_xmm);
return result;
}
#endif
/*-------------------------------------------------
mul_64x64 - perform a signed 64 bit x 64 bit
multiply and return the full 128 bit result
-------------------------------------------------*/
#ifdef __x86_64__
#define mul_64x64 _mul_64x64
inline int64_t ATTR_FORCE_INLINE
_mul_64x64(int64_t a, int64_t b, int64_t &hi)
{
__int128 const r(__int128(a) * b);
hi = int64_t(uint64_t((unsigned __int128)r >> 64));
return int64_t(uint64_t((unsigned __int128)r));
}
#endif
/*-------------------------------------------------
mulu_64x64 - perform an unsigned 64 bit x 64
bit multiply and return the full 128 bit result
-------------------------------------------------*/
#ifdef __x86_64__
#define mulu_64x64 _mulu_64x64
inline uint64_t ATTR_FORCE_INLINE
_mulu_64x64(uint64_t a, uint64_t b, uint64_t &hi)
{
unsigned __int128 const r((unsigned __int128)a * b);
hi = uint64_t(r >> 64);
return uint64_t(r);
}
#endif
/***************************************************************************
INLINE BIT MANIPULATION FUNCTIONS
***************************************************************************/
/*-------------------------------------------------
count_leading_zeros_32 - return the number of
leading zero bits in a 32-bit value
-------------------------------------------------*/
#define count_leading_zeros_32 _count_leading_zeros_32
inline uint8_t ATTR_CONST ATTR_FORCE_INLINE
_count_leading_zeros_32(uint32_t value)
{
uint32_t result;
__asm__ (
" bsrl %[value], %[result] ;"
" cmovzl %[bias], %[result] ;"
: [result] "=&r" (result) // result can be in any register
: [value] "rm" (value) // 'value' can be register or memory
, [bias] "rm" (~uint32_t(0)) // 'bias' can be register or memory
: "cc" // clobbers condition codes
);
return uint8_t(31U - result);
}
/*-------------------------------------------------
count_leading_ones_32 - return the number of
leading one bits in a 32-bit value
-------------------------------------------------*/
#define count_leading_ones_32 _count_leading_ones_32
inline uint8_t ATTR_CONST ATTR_FORCE_INLINE
_count_leading_ones_32(uint32_t value)
{
uint32_t result;
__asm__ (
" bsrl %[value], %[result] ;"
" cmovzl %[bias], %[result] ;"
: [result] "=&r" (result) // result can be in any register
: [value] "rm" (~value) // 'value' can be register or memory
, [bias] "rm" (~uint32_t(0)) // 'bias' can be register or memory
: "cc" // clobbers condition codes
);
return uint8_t(31U - result);
}
/*-------------------------------------------------
count_leading_zeros_64 - return the number of
leading zero bits in a 64-bit value
-------------------------------------------------*/
#ifdef __x86_64__
#define count_leading_zeros_64 _count_leading_zeros_64
inline uint8_t ATTR_CONST ATTR_FORCE_INLINE
_count_leading_zeros_64(uint64_t value)
{
uint64_t result;
__asm__ (
" bsrq %[value], %[result] ;"
" cmovzq %[bias], %[result] ;"
: [result] "=&r" (result) // result can be in any register
: [value] "rm" (value) // 'value' can be register or memory
, [bias] "rm" (~uint64_t(0)) // 'bias' can be register or memory
: "cc" // clobbers condition codes
);
return uint8_t(63U - result);
}
#endif
/*-------------------------------------------------
count_leading_ones_64 - return the number of
leading one bits in a 64-bit value
-------------------------------------------------*/
#ifdef __x86_64__
#define count_leading_ones_64 _count_leading_ones_64
inline uint8_t ATTR_CONST ATTR_FORCE_INLINE
_count_leading_ones_64(uint64_t value)
{
uint64_t result;
__asm__ (
" bsrq %[value], %[result] ;"
" cmovzq %[bias], %[result] ;"
: [result] "=&r" (result) // result can be in any register
: [value] "rm" (~value) // 'value' can be register or memory
, [bias] "rm" (~uint64_t(0)) // 'bias' can be register or memory
: "cc" // clobbers condition codes
);
return uint8_t(63U - result);
}
#endif
#endif // MAME_OSD_EIGCCX86_H

View File

@ -1,94 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
//============================================================
//
// eivc.h
//
// Inline implementations for MSVC compiler.
//
//============================================================
#ifndef MAME_OSD_EIVC_H
#define MAME_OSD_EIVC_H
#pragma once
#include <intrin.h>
#pragma intrinsic(_BitScanReverse)
#ifdef PTR64
#pragma intrinsic(_BitScanReverse64)
#endif
/***************************************************************************
INLINE BIT MANIPULATION FUNCTIONS
***************************************************************************/
/*-------------------------------------------------
count_leading_zeros_32 - return the number of
leading zero bits in a 32-bit value
-------------------------------------------------*/
#ifndef count_leading_zeros_32
#define count_leading_zeros_32 _count_leading_zeros_32
__forceinline uint8_t _count_leading_zeros_32(uint32_t value)
{
unsigned long index;
return _BitScanReverse(&index, value) ? (31U - index) : 32U;
}
#endif
/*-------------------------------------------------
count_leading_ones_32 - return the number of
leading one bits in a 32-bit value
-------------------------------------------------*/
#ifndef count_leading_ones_32
#define count_leading_ones_32 _count_leading_ones_32
__forceinline uint8_t _count_leading_ones_32(uint32_t value)
{
unsigned long index;
return _BitScanReverse(&index, ~value) ? (31U - index) : 32U;
}
#endif
/*-------------------------------------------------
count_leading_zeros_64 - return the number of
leading zero bits in a 64-bit value
-------------------------------------------------*/
#ifndef count_leading_zeros_64
#define count_leading_zeros_64 _count_leading_zeros_64
__forceinline uint8_t _count_leading_zeros_64(uint64_t value)
{
unsigned long index;
#ifdef PTR64
return _BitScanReverse64(&index, value) ? (63U - index) : 64U;
#else
return _BitScanReverse(&index, uint32_t(value >> 32)) ? (31U - index) : _BitScanReverse(&index, uint32_t(value)) ? (63U - index) : 64U;
#endif
}
#endif
/*-------------------------------------------------
count_leading_ones_64 - return the number of
leading one bits in a 64-bit value
-------------------------------------------------*/
#ifndef count_leading_ones_64
#define count_leading_ones_64 _count_leading_ones_64
__forceinline uint8_t _count_leading_ones_64(uint64_t value)
{
unsigned long index;
#ifdef PTR64
return _BitScanReverse64(&index, ~value) ? (63U - index) : 64U;
#else
return _BitScanReverse(&index, ~uint32_t(value >> 32)) ? (31U - index) : _BitScanReverse(&index, ~uint32_t(value)) ? (63U - index) : 64U;
#endif
}
#endif
#endif // MAME_OSD_EIVC_H

View File

@ -1,75 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
//============================================================
//
// eivcarm.h
//
// ARM/AArch64 inline implementations for MSVC compiler.
//
//============================================================
#ifndef MAME_OSD_EIVCARM_H
#define MAME_OSD_EIVCARM_H
#pragma once
#include <intrin.h>
#pragma intrinsic(_CountLeadingZeros)
#pragma intrinsic(_CountLeadingZeros64)
#pragma intrinsic(_CountLeadingOnes)
#pragma intrinsic(_CountLeadingOnes64)
/***************************************************************************
INLINE BIT MANIPULATION FUNCTIONS
***************************************************************************/
/*-------------------------------------------------
count_leading_zeros_32 - return the number of
leading zero bits in a 32-bit value
-------------------------------------------------*/
#define count_leading_zeros_32 _count_leading_zeros_32
__forceinline uint8_t _count_leading_zeros_32(uint32_t value)
{
return uint8_t(_CountLeadingZeros(value));
}
/*-------------------------------------------------
count_leading_ones_32 - return the number of
leading one bits in a 32-bit value
-------------------------------------------------*/
#define count_leading_ones_32 _count_leading_ones_32
__forceinline uint8_t _count_leading_ones_32(uint32_t value)
{
return uint8_t(_CountLeadingOnes(value));
}
/*-------------------------------------------------
count_leading_zeros_64 - return the number of
leading zero bits in a 64-bit value
-------------------------------------------------*/
#define count_leading_zeros_64 _count_leading_zeros_64
__forceinline uint8_t _count_leading_zeros_64(uint64_t value)
{
return uint8_t(_CountLeadingZeros64(value));
}
/*-------------------------------------------------
count_leading_ones_64 - return the number of
leading one bits in a 64-bit value
-------------------------------------------------*/
#define count_leading_ones_64 _count_leading_ones_64
__forceinline uint8_t _count_leading_ones_64(uint64_t value)
{
return uint8_t(_CountLeadingOnes64(value));
}
#endif // MAME_OSD_EIVCARM_H

View File

@ -1,468 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
//============================================================
//
// eivcx86.h
//
// x86 inline implementations for MSVC compiler.
//
//============================================================
#ifndef MAME_OSD_EIVCX86_H
#define MAME_OSD_EIVCX86_H
#pragma once
#ifdef PTR64
#include <emmintrin.h>
#endif
#include <intrin.h>
/***************************************************************************
INLINE MATH FUNCTIONS
***************************************************************************/
/*-------------------------------------------------
mul_32x32 - perform a signed 32 bit x 32 bit
multiply and return the full 64 bit result
-------------------------------------------------*/
#ifndef PTR64
#define mul_32x32 _mul_32x32
inline int64_t _mul_32x32(int32_t a, int32_t b)
{
// in theory this should work, but it is untested
__asm
{
mov eax,a
imul b
// leave results in edx:eax
}
}
#endif
/*-------------------------------------------------
mulu_32x32 - perform an unsigned 32 bit x
32 bit multiply and return the full 64 bit
result
-------------------------------------------------*/
#ifndef PTR64
#define mulu_32x32 _mulu_32x32
inline uint64_t _mulu_32x32(uint32_t a, uint32_t b)
{
// in theory this should work, but it is untested
__asm
{
mov eax,a
mul b
// leave results in edx:eax
}
}
#endif
/*-------------------------------------------------
mul_32x32_hi - perform a signed 32 bit x 32 bit
multiply and return the upper 32 bits of the
result
-------------------------------------------------*/
#ifndef PTR64
#define mul_32x32_hi _mul_32x32_hi
inline int32_t _mul_32x32_hi(int32_t a, int32_t b)
{
int32_t result;
__asm
{
mov eax,a
imul b
mov result,edx
}
return result;
}
#endif
/*-------------------------------------------------
mulu_32x32_hi - perform an unsigned 32 bit x
32 bit multiply and return the upper 32 bits
of the result
-------------------------------------------------*/
#ifndef PTR64
#define mulu_32x32_hi _mulu_32x32_hi
inline uint32_t _mulu_32x32_hi(uint32_t a, uint32_t b)
{
int32_t result;
__asm
{
mov eax,a
mul b
mov result,edx
}
return result;
}
#endif
/*-------------------------------------------------
mul_32x32_shift - perform a signed 32 bit x
32 bit multiply and shift the result by the
given number of bits before truncating the
result to 32 bits
-------------------------------------------------*/
#ifndef PTR64
#define mul_32x32_shift _mul_32x32_shift
static inline int32_t _mul_32x32_shift(int32_t a, int32_t b, uint8_t shift)
{
int32_t result;
__asm
{
mov eax,a
imul b
mov cl,shift
shrd eax,edx,cl
mov result,eax
}
return result;
}
#endif
/*-------------------------------------------------
mulu_32x32_shift - perform an unsigned 32 bit x
32 bit multiply and shift the result by the
given number of bits before truncating the
result to 32 bits
-------------------------------------------------*/
#ifndef PTR64
#define mulu_32x32_shift _mulu_32x32_shift
inline uint32_t _mulu_32x32_shift(uint32_t a, uint32_t b, uint8_t shift)
{
int32_t result;
__asm
{
mov eax,a
mul b
mov cl,shift
shrd eax,edx,cl
mov result,eax
}
return result;
}
#endif
/*-------------------------------------------------
div_64x32 - perform a signed 64 bit x 32 bit
divide and return the 32 bit quotient
-------------------------------------------------*/
#ifndef PTR64
#define div_64x32 _div_64x32
inline int32_t _div_64x32(int64_t a, int32_t b)
{
int32_t result;
int32_t alow = a;
int32_t ahigh = a >> 32;
__asm
{
mov eax,alow
mov edx,ahigh
idiv b
mov result,eax
}
return result;
}
#endif
/*-------------------------------------------------
divu_64x32 - perform an unsigned 64 bit x 32 bit
divide and return the 32 bit quotient
-------------------------------------------------*/
#ifndef PTR64
#define divu_64x32 _divu_64x32
inline uint32_t _divu_64x32(uint64_t a, uint32_t b)
{
uint32_t result;
uint32_t alow = a;
uint32_t ahigh = a >> 32;
__asm
{
mov eax,alow
mov edx,ahigh
div b
mov result,eax
}
return result;
}
#endif
/*-------------------------------------------------
div_64x32_rem - perform a signed 64 bit x 32
bit divide and return the 32 bit quotient and
32 bit remainder
-------------------------------------------------*/
#ifndef PTR64
#define div_64x32_rem _div_64x32_rem
inline int32_t _div_64x32_rem(int64_t a, int32_t b, int32_t &remainder)
{
int32_t result;
int32_t alow = a;
int32_t ahigh = a >> 32;
int32_t rem;
__asm
{
mov eax,alow
mov edx,ahigh
idiv b
mov result,eax
mov rem,edx
}
remainder = rem;
return result;
}
#endif
/*-------------------------------------------------
divu_64x32_rem - perform an unsigned 64 bit x
32 bit divide and return the 32 bit quotient
and 32 bit remainder
-------------------------------------------------*/
#ifndef PTR64
#define divu_64x32_rem _divu_64x32_rem
inline uint32_t _divu_64x32_rem(uint64_t a, uint32_t b, uint32_t &remainder)
{
uint32_t result;
uint32_t alow = a;
uint32_t ahigh = a >> 32;
uint32_t rem;
__asm
{
mov eax,alow
mov edx,ahigh
div b
mov result,eax
mov rem,edx
}
remainder = rem;
return result;
}
#endif
/*-------------------------------------------------
div_32x32_shift - perform a signed divide of
two 32 bit values, shifting the first before
division, and returning the 32 bit quotient
-------------------------------------------------*/
#ifndef PTR64
#define div_32x32_shift _div_32x32_shift
inline int32_t _div_32x32_shift(int32_t a, int32_t b, uint8_t shift)
{
int32_t result;
__asm
{
mov eax,a
cdq
mov cl,shift
shld edx,eax,cl
shl eax,cl
idiv b
mov result,eax
}
return result;
}
#endif
/*-------------------------------------------------
divu_32x32_shift - perform an unsigned divide of
two 32 bit values, shifting the first before
division, and returning the 32 bit quotient
-------------------------------------------------*/
#ifndef PTR64
#define divu_32x32_shift _divu_32x32_shift
inline uint32_t _divu_32x32_shift(uint32_t a, uint32_t b, uint8_t shift)
{
uint32_t result;
__asm
{
mov eax,a
xor edx,edx
mov cl,shift
shld edx,eax,cl
shl eax,cl
div b
mov result,eax
}
return result;
}
#endif
/*-------------------------------------------------
mod_64x32 - perform a signed 64 bit x 32 bit
divide and return the 32 bit remainder
-------------------------------------------------*/
#ifndef PTR64
#define mod_64x32 _mod_64x32
static inline int32_t _mod_64x32(int64_t a, int32_t b)
{
int32_t result;
int32_t alow = a;
int32_t ahigh = a >> 32;
__asm
{
mov eax,alow
mov edx,ahigh
idiv b
mov result,edx
}
return result;
}
#endif
/*-------------------------------------------------
modu_64x32 - perform an unsigned 64 bit x 32 bit
divide and return the 32 bit remainder
-------------------------------------------------*/
#ifndef PTR64
#define modu_64x32 _modu_64x32
inline uint32_t _modu_64x32(uint64_t a, uint32_t b)
{
uint32_t result;
uint32_t alow = a;
uint32_t ahigh = a >> 32;
__asm
{
mov eax,alow
mov edx,ahigh
div b
mov result,edx
}
return result;
}
#endif
/*-------------------------------------------------
recip_approx - compute an approximate floating
point reciprocal
-------------------------------------------------*/
#ifdef PTR64
#define recip_approx _recip_approx
inline float _recip_approx(float z)
{
__m128 const mz = _mm_set_ss(z);
__m128 const mooz = _mm_rcp_ss(mz);
float ooz;
_mm_store_ss(&ooz, mooz);
return ooz;
}
#endif
/*-------------------------------------------------
mul_64x64 - perform a signed 64 bit x 64 bit
multiply and return the full 128 bit result
-------------------------------------------------*/
#ifdef PTR64
#define mul_64x64 _mul_64x64
__forceinline int64_t _mul_64x64(int64_t a, int64_t b, int64_t &hi)
{
return _mul128(a, b, &hi);
}
#endif
/*-------------------------------------------------
mulu_64x64 - perform an unsigned 64 bit x 64
bit multiply and return the full 128 bit result
-------------------------------------------------*/
#ifdef PTR64
#define mulu_64x64 _mulu_64x64
__forceinline int64_t _mulu_64x64(uint64_t a, uint64_t b, uint64_t &hi)
{
return _umul128(a, b, &hi);
}
#endif
/*-------------------------------------------------
addu_32x32_co - perform an unsigned 32 bit + 32
bit addition and return the result with carry
out
-------------------------------------------------*/
#define addu_32x32_co _addu_32x32_co
__forceinline bool _addu_32x32_co(uint32_t a, uint32_t b, uint32_t &sum)
{
return _addcarry_u32(0, a, b, &sum);
}
/*-------------------------------------------------
addu_64x64_co - perform an unsigned 64 bit + 64
bit addition and return the result with carry
out
-------------------------------------------------*/
#define addu_64x64_co _addu_64x64_co
__forceinline bool _addu_64x64_co(uint64_t a, uint64_t b, uint64_t &sum)
{
#ifdef PTR64
return _addcarry_u64(0, a, b, &sum);
#else
uint32_t l, h;
bool const result = _addcarry_u32(_addcarry_u32(0, uint32_t(a), uint32_t(b), &l), uint32_t(a >> 32), uint32_t(b >> 32), &h);
sum = (uint64_t(h) << 32) | l;
return result;
#endif
}
#endif // MAME_OSD_EIVCX86_H

View File

@ -1,495 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************
eminline.h
Definitions for inline functions that can be overridden by OSD-
specific code.
***************************************************************************/
#ifndef MAME_OSD_EMINLINE_H
#define MAME_OSD_EMINLINE_H
#pragma once
#include "osdcomm.h"
#include "osdcore.h"
#if !defined(MAME_NOASM)
#if defined(__GNUC__)
#if defined(__i386__) || defined(__x86_64__)
#include "eigccx86.h"
#elif defined(__ppc__) || defined (__PPC__) || defined(__ppc64__) || defined(__PPC64__)
#include "eigccppc.h"
#elif defined(__arm__) || defined(__aarch64__)
#include "eigccarm.h"
#endif
#include "eigcc.h"
#elif defined(_MSC_VER)
#if defined(_M_IX86) || defined(_M_X64)
#include "eivcx86.h"
#elif defined(_M_ARM) || defined(_M_ARM64)
#include "eivcarm.h"
#endif
#include "eivc.h"
#endif
#endif // !defined(MAME_NOASM)
/***************************************************************************
INLINE MATH FUNCTIONS
***************************************************************************/
/*-------------------------------------------------
mul_32x32 - perform a signed 32 bit x 32 bit
multiply and return the full 64 bit result
-------------------------------------------------*/
#ifndef mul_32x32
constexpr int64_t mul_32x32(int32_t a, int32_t b)
{
return int64_t(a) * int64_t(b);
}
#endif
/*-------------------------------------------------
mulu_32x32 - perform an unsigned 32 bit x
32 bit multiply and return the full 64 bit
result
-------------------------------------------------*/
#ifndef mulu_32x32
constexpr uint64_t mulu_32x32(uint32_t a, uint32_t b)
{
return uint64_t(a) * uint64_t(b);
}
#endif
/*-------------------------------------------------
mul_32x32_hi - perform a signed 32 bit x 32 bit
multiply and return the upper 32 bits of the
result
-------------------------------------------------*/
#ifndef mul_32x32_hi
constexpr int32_t mul_32x32_hi(int32_t a, int32_t b)
{
return uint32_t((int64_t(a) * int64_t(b)) >> 32);
}
#endif
/*-------------------------------------------------
mulu_32x32_hi - perform an unsigned 32 bit x
32 bit multiply and return the upper 32 bits
of the result
-------------------------------------------------*/
#ifndef mulu_32x32_hi
constexpr uint32_t mulu_32x32_hi(uint32_t a, uint32_t b)
{
return uint32_t((uint64_t(a) * uint64_t(b)) >> 32);
}
#endif
/*-------------------------------------------------
mul_32x32_shift - perform a signed 32 bit x
32 bit multiply and shift the result by the
given number of bits before truncating the
result to 32 bits
-------------------------------------------------*/
#ifndef mul_32x32_shift
constexpr int32_t mul_32x32_shift(int32_t a, int32_t b, uint8_t shift)
{
return int32_t((int64_t(a) * int64_t(b)) >> shift);
}
#endif
/*-------------------------------------------------
mulu_32x32_shift - perform an unsigned 32 bit x
32 bit multiply and shift the result by the
given number of bits before truncating the
result to 32 bits
-------------------------------------------------*/
#ifndef mulu_32x32_shift
constexpr uint32_t mulu_32x32_shift(uint32_t a, uint32_t b, uint8_t shift)
{
return uint32_t((uint64_t(a) * uint64_t(b)) >> shift);
}
#endif
/*-------------------------------------------------
div_64x32 - perform a signed 64 bit x 32 bit
divide and return the 32 bit quotient
-------------------------------------------------*/
#ifndef div_64x32
constexpr int32_t div_64x32(int64_t a, int32_t b)
{
return a / int64_t(b);
}
#endif
/*-------------------------------------------------
divu_64x32 - perform an unsigned 64 bit x 32 bit
divide and return the 32 bit quotient
-------------------------------------------------*/
#ifndef divu_64x32
constexpr uint32_t divu_64x32(uint64_t a, uint32_t b)
{
return a / uint64_t(b);
}
#endif
/*-------------------------------------------------
div_64x32_rem - perform a signed 64 bit x 32
bit divide and return the 32 bit quotient and
32 bit remainder
-------------------------------------------------*/
#ifndef div_64x32_rem
inline int32_t div_64x32_rem(int64_t a, int32_t b, int32_t &remainder)
{
int32_t const res(div_64x32(a, b));
remainder = a - (int64_t(b) * res);
return res;
}
#endif
/*-------------------------------------------------
divu_64x32_rem - perform an unsigned 64 bit x
32 bit divide and return the 32 bit quotient
and 32 bit remainder
-------------------------------------------------*/
#ifndef divu_64x32_rem
inline uint32_t divu_64x32_rem(uint64_t a, uint32_t b, uint32_t &remainder)
{
uint32_t const res(divu_64x32(a, b));
remainder = a - (uint64_t(b) * res);
return res;
}
#endif
/*-------------------------------------------------
div_32x32_shift - perform a signed divide of
two 32 bit values, shifting the first before
division, and returning the 32 bit quotient
-------------------------------------------------*/
#ifndef div_32x32_shift
constexpr int32_t div_32x32_shift(int32_t a, int32_t b, uint8_t shift)
{
return (int64_t(a) << shift) / int64_t(b);
}
#endif
/*-------------------------------------------------
divu_32x32_shift - perform an unsigned divide of
two 32 bit values, shifting the first before
division, and returning the 32 bit quotient
-------------------------------------------------*/
#ifndef divu_32x32_shift
constexpr uint32_t divu_32x32_shift(uint32_t a, uint32_t b, uint8_t shift)
{
return (uint64_t(a) << shift) / uint64_t(b);
}
#endif
/*-------------------------------------------------
mod_64x32 - perform a signed 64 bit x 32 bit
divide and return the 32 bit remainder
-------------------------------------------------*/
#ifndef mod_64x32
constexpr int32_t mod_64x32(int64_t a, int32_t b)
{
return a - (b * div_64x32(a, b));
}
#endif
/*-------------------------------------------------
modu_64x32 - perform an unsigned 64 bit x 32 bit
divide and return the 32 bit remainder
-------------------------------------------------*/
#ifndef modu_64x32
constexpr uint32_t modu_64x32(uint64_t a, uint32_t b)
{
return a - (b * divu_64x32(a, b));
}
#endif
/*-------------------------------------------------
recip_approx - compute an approximate floating
point reciprocal
-------------------------------------------------*/
#ifndef recip_approx
constexpr float recip_approx(float value)
{
return 1.0f / value;
}
#endif
/*-------------------------------------------------
mul_64x64 - perform a signed 64 bit x 64 bit
multiply and return the full 128 bit result
-------------------------------------------------*/
#ifndef mul_64x64
inline int64_t mul_64x64(int64_t a, int64_t b, int64_t &hi)
{
uint64_t const a_hi = uint64_t(a) >> 32;
uint64_t const b_hi = uint64_t(b) >> 32;
uint64_t const a_lo = uint32_t(uint64_t(a));
uint64_t const b_lo = uint32_t(uint64_t(b));
uint64_t const ab_lo = a_lo * b_lo;
uint64_t const ab_m1 = a_hi * b_lo;
uint64_t const ab_m2 = a_lo * b_hi;
uint64_t const ab_hi = a_hi * b_hi;
uint64_t const carry = ((ab_lo >> 32) + uint32_t(ab_m1) + uint32_t(ab_m2)) >> 32;
hi = ab_hi + (ab_m1 >> 32) + (ab_m2 >> 32) + carry;
// adjust for sign
if (a < 0)
hi -= b;
if (b < 0)
hi -= a;
return ab_lo + (ab_m1 << 32) + (ab_m2 << 32);
}
#endif
/*-------------------------------------------------
mulu_64x64 - perform an unsigned 64 bit x 64
bit multiply and return the full 128 bit result
-------------------------------------------------*/
#ifndef mulu_64x64
inline uint64_t mulu_64x64(uint64_t a, uint64_t b, uint64_t &hi)
{
uint64_t const a_hi = uint32_t(a >> 32);
uint64_t const b_hi = uint32_t(b >> 32);
uint64_t const a_lo = uint32_t(a);
uint64_t const b_lo = uint32_t(b);
uint64_t const ab_lo = a_lo * b_lo;
uint64_t const ab_m1 = a_hi * b_lo;
uint64_t const ab_m2 = a_lo * b_hi;
uint64_t const ab_hi = a_hi * b_hi;
uint64_t const carry = ((ab_lo >> 32) + uint32_t(ab_m1) + uint32_t(ab_m2)) >> 32;
hi = ab_hi + (ab_m1 >> 32) + (ab_m2 >> 32) + carry;
return ab_lo + (ab_m1 << 32) + (ab_m2 << 32);
}
#endif
/*-------------------------------------------------
addu_32x32_co - perform an unsigned 32 bit + 32
bit addition and return the result with carry
out
-------------------------------------------------*/
#ifndef addu_32x32_co
inline bool addu_32x32_co(uint32_t a, uint32_t b, uint32_t &sum)
{
sum = a + b;
return (a > sum) || (b > sum);
}
#endif
/*-------------------------------------------------
addu_64x64_co - perform an unsigned 64 bit + 64
bit addition and return the result with carry
out
-------------------------------------------------*/
#ifndef addu_64x64_co
inline bool addu_64x64_co(uint64_t a, uint64_t b, uint64_t &sum)
{
sum = a + b;
return (a > sum) || (b > sum);
}
#endif
/***************************************************************************
INLINE BIT MANIPULATION FUNCTIONS
***************************************************************************/
/*-------------------------------------------------
count_leading_zeros_32 - return the number of
leading zero bits in a 32-bit value
-------------------------------------------------*/
#ifndef count_leading_zeros_32
inline uint8_t count_leading_zeros_32(uint32_t val)
{
if (!val) return 32U;
uint8_t count;
for (count = 0; int32_t(val) >= 0; count++) val <<= 1;
return count;
}
#endif
/*-------------------------------------------------
count_leading_ones_32 - return the number of
leading one bits in a 32-bit value
-------------------------------------------------*/
#ifndef count_leading_ones_32
inline uint8_t count_leading_ones_32(uint32_t val)
{
uint8_t count;
for (count = 0; int32_t(val) < 0; count++) val <<= 1;
return count;
}
#endif
/*-------------------------------------------------
count_leading_zeros_64 - return the number of
leading zero bits in a 64-bit value
-------------------------------------------------*/
#ifndef count_leading_zeros_64
inline uint8_t count_leading_zeros_64(uint64_t val)
{
if (!val) return 64U;
uint8_t count;
for (count = 0; int64_t(val) >= 0; count++) val <<= 1;
return count;
}
#endif
/*-------------------------------------------------
count_leading_ones_64 - return the number of
leading one bits in a 64-bit value
-------------------------------------------------*/
#ifndef count_leading_ones_64
inline uint8_t count_leading_ones_64(uint64_t val)
{
uint8_t count;
for (count = 0; int64_t(val) < 0; count++) val <<= 1;
return count;
}
#endif
/*-------------------------------------------------
population_count_32 - return the number of
one bits in a 32-bit value
-------------------------------------------------*/
#ifndef population_count_32
inline unsigned population_count_32(uint32_t val)
{
#if defined(__NetBSD__)
return popcount32(val);
#else
// optimal Hamming weight assuming fast 32*32->32
constexpr uint32_t m1(0x55555555);
constexpr uint32_t m2(0x33333333);
constexpr uint32_t m4(0x0f0f0f0f);
constexpr uint32_t h01(0x01010101);
val -= (val >> 1) & m1;
val = (val & m2) + ((val >> 2) & m2);
val = (val + (val >> 4)) & m4;
return unsigned((val * h01) >> 24);
#endif
}
#endif
/*-------------------------------------------------
population_count_64 - return the number of
one bits in a 64-bit value
-------------------------------------------------*/
#ifndef population_count_64
inline unsigned population_count_64(uint64_t val)
{
#if defined(__NetBSD__)
return popcount64(val);
#else
// guess that architectures with 64-bit pointers have 64-bit multiplier
if (sizeof(void *) >= sizeof(uint64_t))
{
// optimal Hamming weight assuming fast 64*64->64
constexpr uint64_t m1(0x5555555555555555);
constexpr uint64_t m2(0x3333333333333333);
constexpr uint64_t m4(0x0f0f0f0f0f0f0f0f);
constexpr uint64_t h01(0x0101010101010101);
val -= (val >> 1) & m1;
val = (val & m2) + ((val >> 2) & m2);
val = (val + (val >> 4)) & m4;
return unsigned((val * h01) >> 56);
}
else
{
// fall back to two 32-bit operations to avoid slow multiply
return population_count_32(uint32_t(val)) + population_count_32(uint32_t(val >> 32));
}
#endif
}
#endif
/***************************************************************************
INLINE TIMING FUNCTIONS
***************************************************************************/
/*-------------------------------------------------
get_profile_ticks - return a tick counter
from the processor that can be used for
profiling. It does not need to run at any
particular rate.
-------------------------------------------------*/
#ifndef get_profile_ticks
inline int64_t get_profile_ticks()
{
return osd_ticks();
}
#endif
#endif // MAME_OSD_EMINLINE_H

View File

@ -1,119 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************
osdcomm.h
Common definitions shared by the OSD layer. This includes the most
fundamental integral types as well as compiler-specific tweaks.
***************************************************************************/
#ifndef MAME_OSD_OSDCOMM_H
#define MAME_OSD_OSDCOMM_H
#pragma once
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <type_traits>
/***************************************************************************
COMPILER-SPECIFIC NASTINESS
***************************************************************************/
// The Win32 port requires this constant for variable arg routines.
#ifndef CLIB_DECL
#define CLIB_DECL
#endif
// Some optimizations/warnings cleanups for GCC
#if defined(__GNUC__)
#define ATTR_PRINTF(x,y) __attribute__((format(printf, x, y)))
#define ATTR_CONST __attribute__((const))
#define ATTR_FORCE_INLINE __attribute__((always_inline))
#define ATTR_HOT __attribute__((hot))
#define ATTR_COLD __attribute__((cold))
#define UNEXPECTED(exp) __builtin_expect(!!(exp), 0)
#define EXPECTED(exp) __builtin_expect(!!(exp), 1)
#define RESTRICT __restrict__
#else
#define ATTR_PRINTF(x,y)
#define ATTR_CONST
#define ATTR_FORCE_INLINE __forceinline
#define ATTR_HOT
#define ATTR_COLD
#define UNEXPECTED(exp) (exp)
#define EXPECTED(exp) (exp)
#define RESTRICT
#endif
/***************************************************************************
FUNDAMENTAL TYPES
***************************************************************************/
namespace osd {
using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;
using s8 = std::int8_t;
using s16 = std::int16_t;
using s32 = std::int32_t;
using s64 = std::int64_t;
} // namespace OSD
/***************************************************************************
FUNDAMENTAL MACROS
***************************************************************************/
// Concatenate/extract 32-bit halves of 64-bit values
constexpr uint64_t concat_64(uint32_t hi, uint32_t lo) { return (uint64_t(hi) << 32) | uint32_t(lo); }
constexpr uint32_t extract_64hi(uint64_t val) { return uint32_t(val >> 32); }
constexpr uint32_t extract_64lo(uint64_t val) { return uint32_t(val); }
// Macros for normalizing data into big or little endian formats
constexpr uint16_t swapendian_int16(uint16_t val) { return (val << 8) | (val >> 8); }
constexpr uint32_t swapendian_int32_partial16(uint32_t val) { return ((val << 8) & 0xFF00FF00U) | ((val >> 8) & 0x00FF00FFU); }
constexpr uint32_t swapendian_int32(uint32_t val) { return (swapendian_int32_partial16(val) << 16) | (swapendian_int32_partial16(val) >> 16); }
constexpr uint64_t swapendian_int64_partial16(uint64_t val) { return ((val << 8) & 0xFF00FF00FF00FF00U) | ((val >> 8) & 0x00FF00FF00FF00FFU); }
constexpr uint64_t swapendian_int64_partial32(uint64_t val) { return ((swapendian_int64_partial16(val) << 16) & 0xFFFF0000FFFF0000U) | ((swapendian_int64_partial16(val) >> 16) & 0x0000FFFF0000FFFFU); }
constexpr uint64_t swapendian_int64(uint64_t val) { return (swapendian_int64_partial32(val) << 32) | (swapendian_int64_partial32(val) >> 32); }
#ifdef LSB_FIRST
constexpr uint16_t big_endianize_int16(uint16_t x) { return swapendian_int16(x); }
constexpr uint32_t big_endianize_int32(uint32_t x) { return swapendian_int32(x); }
constexpr uint64_t big_endianize_int64(uint64_t x) { return swapendian_int64(x); }
constexpr uint16_t little_endianize_int16(uint16_t x) { return x; }
constexpr uint32_t little_endianize_int32(uint32_t x) { return x; }
constexpr uint64_t little_endianize_int64(uint64_t x) { return x; }
#else
constexpr uint16_t big_endianize_int16(uint16_t x) { return x; }
constexpr uint32_t big_endianize_int32(uint32_t x) { return x; }
constexpr uint64_t big_endianize_int64(uint64_t x) { return x; }
constexpr uint16_t little_endianize_int16(uint16_t x) { return swapendian_int16(x); }
constexpr uint32_t little_endianize_int32(uint32_t x) { return swapendian_int32(x); }
constexpr uint64_t little_endianize_int64(uint64_t x) { return swapendian_int64(x); }
#endif // LSB_FIRST
#ifdef _MSC_VER
using ssize_t = std::make_signed_t<size_t>;
#endif
#ifdef __GNUC__
#ifndef alloca
#define alloca(size) __builtin_alloca(size)
#endif
#endif
#endif // MAME_OSD_OSDCOMM_H

View File

@ -1,223 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
#include "osdcore.h"
#include <thread>
#include <chrono>
#if defined(SDLMAME_ANDROID)
#include <android/log.h>
#endif
#ifdef _WIN32
#include <windows.h>
#include <cstdio>
#include <shellapi.h>
#if !defined(MAME_RDP)
#include "strconv.h"
#endif
#endif
static const int MAXSTACK = 10;
static osd_output *m_stack[MAXSTACK];
static int m_ptr = -1;
/*-------------------------------------------------
osd_output
-------------------------------------------------*/
void osd_output::push(osd_output *delegate)
{
if (m_ptr < MAXSTACK - 1)
{
delegate->m_chain = (m_ptr >= 0 ? m_stack[m_ptr] : nullptr);
m_ptr++;
m_stack[m_ptr] = delegate;
}
}
void osd_output::pop(osd_output *delegate)
{
int f = -1;
for (int i = 0; i <= m_ptr; i++)
if (m_stack[i] == delegate)
{
f = i;
break;
}
if (f >= 0)
{
if (f < m_ptr)
m_stack[f+1]->m_chain = m_stack[f]->m_chain;
m_ptr--;
for (int i = f; i <= m_ptr; i++)
m_stack[i] = m_stack[i+1];
}
}
/***************************************************************************
OUTPUT MANAGEMENT
***************************************************************************/
/*-------------------------------------------------
osd_vprintf_error - output an error to the
appropriate callback
-------------------------------------------------*/
void osd_vprintf_error(util::format_argument_pack<std::ostream> const &args)
{
#if defined(SDLMAME_ANDROID)
__android_log_write(ANDROID_LOG_ERROR, "%s", util::string_format(args).c_str());
#else
if (m_ptr >= 0) m_stack[m_ptr]->output_callback(OSD_OUTPUT_CHANNEL_ERROR, args);
#endif
}
/*-------------------------------------------------
osd_vprintf_warning - output a warning to the
appropriate callback
-------------------------------------------------*/
void osd_vprintf_warning(util::format_argument_pack<std::ostream> const &args)
{
#if defined(SDLMAME_ANDROID)
__android_log_write(ANDROID_LOG_WARN, "%s", util::string_format(args).c_str());
#else
if (m_ptr >= 0) m_stack[m_ptr]->output_callback(OSD_OUTPUT_CHANNEL_WARNING, args);
#endif
}
/*-------------------------------------------------
osd_vprintf_info - output info text to the
appropriate callback
-------------------------------------------------*/
void osd_vprintf_info(util::format_argument_pack<std::ostream> const &args)
{
#if defined(SDLMAME_ANDROID)
__android_log_write(ANDROID_LOG_INFO, "%s", util::string_format(args).c_str());
#else
if (m_ptr >= 0) m_stack[m_ptr]->output_callback(OSD_OUTPUT_CHANNEL_INFO, args);
#endif
}
/*-------------------------------------------------
osd_vprintf_verbose - output verbose text to
the appropriate callback
-------------------------------------------------*/
void osd_vprintf_verbose(util::format_argument_pack<std::ostream> const &args)
{
#if defined(SDLMAME_ANDROID)
__android_log_write( ANDROID_LOG_VERBOSE, "%s", util::string_format(args).c_str());
#else
if (m_ptr >= 0) m_stack[m_ptr]->output_callback(OSD_OUTPUT_CHANNEL_VERBOSE, args);
#endif
}
/*-------------------------------------------------
osd_vprintf_debug - output debug text to the
appropriate callback
-------------------------------------------------*/
void osd_vprintf_debug(util::format_argument_pack<std::ostream> const &args)
{
#if defined(SDLMAME_ANDROID)
__android_log_write(ANDROID_LOG_DEBUG, "%s", util::string_format(args).c_str());
#else
if (m_ptr >= 0) m_stack[m_ptr]->output_callback(OSD_OUTPUT_CHANNEL_DEBUG, args);
#endif
}
//============================================================
// osd_ticks
//============================================================
osd_ticks_t osd_ticks()
{
#ifdef _WIN32
LARGE_INTEGER val;
QueryPerformanceCounter(&val);
return val.QuadPart;
#else
return std::chrono::high_resolution_clock::now().time_since_epoch().count();
#endif
}
//============================================================
// osd_ticks_per_second
//============================================================
osd_ticks_t osd_ticks_per_second()
{
#ifdef _WIN32
LARGE_INTEGER val;
QueryPerformanceFrequency(&val);
return val.QuadPart;
#else
return std::chrono::high_resolution_clock::period::den / std::chrono::high_resolution_clock::period::num;
#endif
}
//============================================================
// osd_sleep
//============================================================
void osd_sleep(osd_ticks_t duration)
{
#ifdef _WIN32
// sleep_for appears to oversleep on Windows with gcc 8
Sleep(duration / (osd_ticks_per_second() / 1000));
#else
std::this_thread::sleep_for(std::chrono::high_resolution_clock::duration(duration));
#endif
}
#if !defined(MAME_RDP)
//============================================================
// osd_get_command_line - returns command line arguments
// in an std::vector<std::string> in UTF-8
//
// The real purpose of this call is to hide details necessary
// on Windows (provided that one wants to avoid using wmain)
//============================================================
std::vector<std::string> osd_get_command_line(int argc, char *argv[])
{
std::vector<std::string> results;
#ifdef _WIN32
{
// Get the command line from Windows
int count;
LPWSTR *wide_args = CommandLineToArgvW(GetCommandLineW(), &count);
// Convert the returned command line arguments to UTF8 std::vector<std::string>
results.reserve(count);
for (int i = 0; i < count; i++)
{
std::string arg = osd::text::from_wstring(wide_args[i]);
results.push_back(std::move(arg));
}
LocalFree(wide_args);
}
#else // !_WIN32
{
// for non Windows platforms, we are assuming that arguments are
// already UTF-8; we just need to convert to std::vector<std::string>
results.reserve(argc);
for (int i = 0; i < argc; i++)
results.emplace_back(argv[i]);
}
#endif // _WIN32
return results;
}
#endif

View File

@ -1,676 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/// \file
/// \brief Core OS-dependent code interface
///
/// The prototypes in this file describe the interfaces that the MAME
/// core and various tools rely on to interact with the outside world.
/// They are broken out into several categories.
#ifndef MAME_OSD_OSDCORE_H
#define MAME_OSD_OSDCORE_H
#pragma once
#include "osdcomm.h"
#include "strformat.h"
#include <cstdarg>
#include <cstdint>
#include <iosfwd>
#include <string>
#include <utility>
#include <vector>
/// \brief Get environment variable value
///
/// \param [in] name Name of the environment variable as a
/// NUL-terminated string.
/// \return Pointer to environment variable value as a NUL-terminated
/// string if found, or nullptr if not found.
const char *osd_getenv(const char *name);
/// \brief Get current process ID
///
/// \return The process ID of the current process.
int osd_getpid();
/*-----------------------------------------------------------------------------
osd_uchar_from_osdchar: convert the given character or sequence of
characters from the OS-default encoding to a Unicode character
Parameters:
uchar - pointer to a uint32_t to receive the resulting unicode
character
osdchar - pointer to one or more chars that are in the OS-default
encoding
count - number of characters provided in the OS-default encoding
Return value:
The number of characters required to form a Unicode character.
-----------------------------------------------------------------------------*/
int osd_uchar_from_osdchar(char32_t *uchar, const char *osdchar, size_t count);
/***************************************************************************
TIMING INTERFACES
***************************************************************************/
/* a osd_ticks_t is a 64-bit unsigned integer that is used as a core type in timing interfaces */
typedef uint64_t osd_ticks_t;
/*-----------------------------------------------------------------------------
osd_ticks: return the current running tick counter
Parameters:
None
Return value:
an osd_ticks_t value which represents the current tick counter
Notes:
The resolution of this counter should be 1ms or better for accurate
performance. It is also important that the source of this timer be
accurate. It is ok if this call is not ultra-fast, since it is
primarily used for once/frame synchronization.
-----------------------------------------------------------------------------*/
osd_ticks_t osd_ticks();
/*-----------------------------------------------------------------------------
osd_ticks_per_second: return the number of ticks per second
Parameters:
None
Return value:
an osd_ticks_t value which represents the number of ticks per
second
-----------------------------------------------------------------------------*/
osd_ticks_t osd_ticks_per_second();
/*-----------------------------------------------------------------------------
osd_sleep: sleep for the specified time interval
Parameters:
duration - an osd_ticks_t value that specifies how long we should
sleep
Return value:
None
Notes:
The OSD layer should try to sleep for as close to the specified
duration as possible, or less. This is used as a mechanism to
"give back" unneeded time to other programs running in the system.
On a simple, non multitasking system, this routine can be a no-op.
If there is significant volatility in the amount of time that the
sleep occurs for, the OSD layer should strive to sleep for less time
than specified rather than sleeping too long.
-----------------------------------------------------------------------------*/
void osd_sleep(osd_ticks_t duration);
/***************************************************************************
WORK ITEM INTERFACES
***************************************************************************/
/* this is the maximum number of supported threads for a single work queue */
/* threadid values are expected to range from 0..WORK_MAX_THREADS-1 */
#define WORK_MAX_THREADS 16
/* these flags can be set when creating a queue to give hints to the code about
how to configure the queue */
#define WORK_QUEUE_FLAG_IO 0x0001
#define WORK_QUEUE_FLAG_MULTI 0x0002
#define WORK_QUEUE_FLAG_HIGH_FREQ 0x0004
/* these flags can be set when queueing a work item to indicate how to handle
its deconstruction */
#define WORK_ITEM_FLAG_AUTO_RELEASE 0x0001
/* osd_work_queue is an opaque type which represents a queue of work items */
struct osd_work_queue;
/* osd_work_item is an opaque type which represents a single work item */
struct osd_work_item;
/* osd_work_callback is a callback function that does work */
typedef void *(*osd_work_callback)(void *param, int threadid);
/*-----------------------------------------------------------------------------
osd_work_queue_alloc: create a new work queue
Parameters:
flags - one or more of the WORK_QUEUE_FLAG_* values ORed together:
WORK_QUEUE_FLAG_IO - indicates that the work queue will do some
I/O; this may be a useful hint so that threads are created
even on single-processor systems since I/O can often be
overlapped with other work
WORK_QUEUE_FLAG_MULTI - indicates that the work queue should
take advantage of as many processors as it can; items queued
here are assumed to be fully independent or shared
WORK_QUEUE_FLAG_HIGH_FREQ - indicates that items are expected
to be queued at high frequency and acted upon quickly; in
general, this implies doing some spin-waiting internally
before falling back to OS-specific synchronization
Return value:
A pointer to an allocated osd_work_queue object.
Notes:
A work queue abstracts the notion of how potentially threaded work
can be performed. If no threading support is available, it is a
simple matter to execute the work items as they are queued.
-----------------------------------------------------------------------------*/
osd_work_queue *osd_work_queue_alloc(int flags);
/*-----------------------------------------------------------------------------
osd_work_queue_items: return the number of pending items in the queue
Parameters:
queue - pointer to an osd_work_queue that was previously created via
osd_work_queue_alloc
Return value:
The number of incomplete items remaining in the queue.
-----------------------------------------------------------------------------*/
int osd_work_queue_items(osd_work_queue *queue);
/*-----------------------------------------------------------------------------
osd_work_queue_wait: wait for the queue to be empty
Parameters:
queue - pointer to an osd_work_queue that was previously created via
osd_work_queue_alloc
timeout - a timeout value in osd_ticks_per_second()
Return value:
true if the queue is empty; false if the wait timed out before the
queue was emptied.
-----------------------------------------------------------------------------*/
bool osd_work_queue_wait(osd_work_queue *queue, osd_ticks_t timeout);
/*-----------------------------------------------------------------------------
osd_work_queue_free: free a work queue, waiting for all items to complete
Parameters:
queue - pointer to an osd_work_queue that was previously created via
osd_work_queue_alloc
Return value:
None.
-----------------------------------------------------------------------------*/
void osd_work_queue_free(osd_work_queue *queue);
/*-----------------------------------------------------------------------------
osd_work_item_queue_multiple: queue a set of work items
Parameters:
queue - pointer to an osd_work_queue that was previously created via
osd_work_queue_alloc
callback - pointer to a function that will do the work
numitems - number of work items to queue
param - a void * parameter that can be used to pass data to the
function
paramstep - the number of bytes to increment param by for each item
queued; for example, if you have an array of work_unit objects,
you can point param to the base of the array and set paramstep to
sizeof(work_unit)
flags - one or more of the WORK_ITEM_FLAG_* values ORed together:
WORK_ITEM_FLAG_AUTO_RELEASE - indicates that the work item
should be automatically freed when it is complete
Return value:
A pointer to the final allocated osd_work_item in the list.
Notes:
On single-threaded systems, this function may actually execute the
work item immediately before returning.
-----------------------------------------------------------------------------*/
osd_work_item *osd_work_item_queue_multiple(osd_work_queue *queue, osd_work_callback callback, int32_t numitems, void *parambase, int32_t paramstep, uint32_t flags);
/* inline helper to queue a single work item using the same interface */
static inline osd_work_item *osd_work_item_queue(osd_work_queue *queue, osd_work_callback callback, void *param, uint32_t flags)
{
return osd_work_item_queue_multiple(queue, callback, 1, param, 0, flags);
}
/*-----------------------------------------------------------------------------
osd_work_item_wait: wait for a work item to complete
Parameters:
item - pointer to an osd_work_item that was previously returned from
osd_work_item_queue
timeout - a timeout value in osd_ticks_per_second()
Return value:
true if the item completed; false if the wait timed out before the
item completed.
-----------------------------------------------------------------------------*/
bool osd_work_item_wait(osd_work_item *item, osd_ticks_t timeout);
/*-----------------------------------------------------------------------------
osd_work_item_result: get the result of a work item
Parameters:
item - pointer to an osd_work_item that was previously returned from
osd_work_item_queue
Return value:
A void * that represents the work item's result.
-----------------------------------------------------------------------------*/
void *osd_work_item_result(osd_work_item *item);
/*-----------------------------------------------------------------------------
osd_work_item_release: release the memory allocated to a work item
Parameters:
item - pointer to an osd_work_item that was previously returned from
osd_work_item_queue
Return value:
None.
Notes:
The osd_work_item exists until explicitly released, even if it has
long since completed. It is the queuer's responsibility to release
any work items it has queued.
-----------------------------------------------------------------------------*/
void osd_work_item_release(osd_work_item *item);
/***************************************************************************
MISCELLANEOUS INTERFACES
***************************************************************************/
/// \brief Break into host debugger if attached
///
/// This function is called when a fatal error occurs. If a debugger is
/// attached, it should break and display the specified message.
/// \param [in] message Message to output to the debugger as a
/// NUL-terminated string.
void osd_break_into_debugger(const char *message);
/// \brief Get clipboard text
///
/// Gets current clipboard content as UTF-8 text. Returns an empty
/// string if the clipboard contents cannot be converted to plain text.
/// \return Clipboard contents or an empty string.
std::string osd_get_clipboard_text();
/***************************************************************************
MIDI I/O INTERFACES
***************************************************************************/
class osd_midi_device
{
public:
virtual ~osd_midi_device() { }
// free result with osd_close_midi_channel()
virtual bool open_input(const char *devname) = 0;
// free result with osd_close_midi_channel()
virtual bool open_output(const char *devname) = 0;
virtual void close() = 0;
virtual bool poll() = 0;
virtual int read(uint8_t *pOut) = 0;
virtual void write(uint8_t data) = 0;
};
//FIXME: really needed here?
void osd_list_network_adapters();
/***************************************************************************
UNCATEGORIZED INTERFACES
***************************************************************************/
/*-----------------------------------------------------------------------------
osd_subst_env: substitute environment variables with values
Parameters:
dst - result pointer
src - source string
-----------------------------------------------------------------------------*/
void osd_subst_env(std::string &dst, std::string const &src);
class osd_gpu
{
public:
osd_gpu() { }
virtual ~osd_gpu() { }
typedef uint64_t handle_t;
class vertex_decl
{
public:
enum attr_type : uint32_t
{
FLOAT32,
FLOAT16,
UINT32,
UINT16,
UINT8,
MAX_TYPES
};
static constexpr size_t TYPE_SIZES[MAX_TYPES] = { 4, 2, 4, 2, 1 };
static constexpr uint32_t MAX_COLORS = 2;
static constexpr uint32_t MAX_TEXCOORDS = 8;
enum attr_usage : uint32_t
{
POSITION,
COLOR,
TEXCOORD = COLOR + MAX_COLORS,
NORMAL = TEXCOORD + MAX_TEXCOORDS,
BINORMAL,
TANGENT,
MAX_ATTRS
};
class attr_entry
{
public:
attr_entry() : m_usage(POSITION), m_type(FLOAT32), m_count(3), m_size(12) { }
attr_entry(attr_usage usage, attr_type type, size_t count) : m_usage(usage), m_type(type), m_count(count), m_size(TYPE_SIZES[type] * count) { }
attr_usage usage() const { return m_usage; }
attr_type type() const { return m_type; }
size_t count() const { return m_count; }
size_t size() const { return m_size; }
private:
attr_usage m_usage;
attr_type m_type;
size_t m_count;
size_t m_size;
};
vertex_decl()
: m_entry_count(0)
, m_size(0)
{
}
vertex_decl & add_attr(attr_usage usage, attr_type type, size_t count)
{
m_entries[m_entry_count] = attr_entry(usage, type, count);
m_size += m_entries[m_entry_count].size();
m_entry_count++;
return *this;
}
size_t entry_count() const { return m_entry_count; }
size_t size() const { return m_size; }
const attr_entry &entry(const uint32_t index) const { return m_entries[index]; }
protected:
attr_entry m_entries[MAX_ATTRS];
size_t m_entry_count;
size_t m_size;
};
class vertex_buffer_interface
{
public:
vertex_buffer_interface(vertex_decl &decl, uint32_t flags)
: m_decl(decl)
, m_flags(flags)
{
}
virtual ~vertex_buffer_interface() {}
const vertex_decl &decl() const { return m_decl; }
uint32_t flags() const { return m_flags; }
handle_t handle() { return m_handle; }
virtual size_t count() const = 0;
virtual size_t size() const = 0;
virtual void upload() = 0;
protected:
const vertex_decl &m_decl;
const uint32_t m_flags;
handle_t m_handle;
};
class static_vertex_buffer_interface : public vertex_buffer_interface
{
public:
enum vertex_buffer_flags : uint32_t
{
RETAIN_ON_CPU = 0x00000001
};
static_vertex_buffer_interface(vertex_decl &decl, size_t count, uint32_t flags)
: vertex_buffer_interface(decl, flags)
, m_count(count)
, m_size(decl.size() * count)
{
}
virtual ~static_vertex_buffer_interface()
{
if (m_data)
delete [] m_data;
}
size_t count() const override { return m_count; }
size_t size() const override { return m_size; }
void set_data(void *data)
{
allocate_if_needed();
memcpy(m_data, data, m_size);
}
protected:
void allocate_if_needed()
{
if ((m_flags & RETAIN_ON_CPU) != 0 && m_data == nullptr)
m_data = new uint8_t[m_size];
}
const size_t m_count;
const size_t m_size;
uint8_t *m_data;
};
virtual void bind_buffer(vertex_buffer_interface *vb) = 0;
virtual void unbind_buffer(vertex_buffer_interface *vb) = 0;
};
/// \defgroup osd_printf Diagnostic output functions
/// \{
// output channels
enum osd_output_channel
{
OSD_OUTPUT_CHANNEL_ERROR,
OSD_OUTPUT_CHANNEL_WARNING,
OSD_OUTPUT_CHANNEL_INFO,
OSD_OUTPUT_CHANNEL_DEBUG,
OSD_OUTPUT_CHANNEL_VERBOSE,
OSD_OUTPUT_CHANNEL_LOG,
OSD_OUTPUT_CHANNEL_COUNT
};
class osd_output
{
public:
osd_output() { }
virtual ~osd_output() { }
virtual void output_callback(osd_output_channel channel, util::format_argument_pack<std::ostream> const &args) = 0;
static void push(osd_output *delegate);
static void pop(osd_output *delegate);
protected:
void chain_output(osd_output_channel channel, util::format_argument_pack<std::ostream> const &args) const
{
if (m_chain)
m_chain->output_callback(channel, args);
}
private:
osd_output *m_chain = nullptr;
};
void osd_vprintf_error(util::format_argument_pack<std::ostream> const &args);
void osd_vprintf_warning(util::format_argument_pack<std::ostream> const &args);
void osd_vprintf_info(util::format_argument_pack<std::ostream> const &args);
void osd_vprintf_verbose(util::format_argument_pack<std::ostream> const &args);
void osd_vprintf_debug(util::format_argument_pack<std::ostream> const &args);
/// \brief Print error message
///
/// By default, error messages are sent to standard error. The relaxed
/// format rules used by util::string_format apply.
/// \param [in] fmt Message format string.
/// \param [in] args Optional message format arguments.
/// \sa util::string_format
template <typename Format, typename... Params> void osd_printf_error(Format &&fmt, Params &&...args)
{
return osd_vprintf_error(util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...));
}
/// \brief Print warning message
///
/// By default, warning messages are sent to standard error. The
/// relaxed format rules used by util::string_format apply.
/// \param [in] fmt Message format string.
/// \param [in] args Optional message format arguments.
/// \sa util::string_format
template <typename Format, typename... Params> void osd_printf_warning(Format &&fmt, Params &&...args)
{
return osd_vprintf_warning(util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...));
}
/// \brief Print informational message
///
/// By default, informational messages are sent to standard output.
/// The relaxed format rules used by util::string_format apply.
/// \param [in] fmt Message format string.
/// \param [in] args Optional message format arguments.
/// \sa util::string_format
template <typename Format, typename... Params> void osd_printf_info(Format &&fmt, Params &&...args)
{
return osd_vprintf_info(util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...));
}
/// \brief Print verbose diagnostic message
///
/// Verbose diagnostic messages are disabled by default. If enabled,
/// they are sent to standard output by default. The relaxed format
/// rules used by util::string_format apply. Note that the format
/// string and arguments will always be evaluated, even if verbose
/// diagnostic messages are disabled.
/// \param [in] fmt Message format string.
/// \param [in] args Optional message format arguments.
/// \sa util::string_format
template <typename Format, typename... Params> void osd_printf_verbose(Format &&fmt, Params &&...args)
{
return osd_vprintf_verbose(util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...));
}
/// \brief Print debug message
///
/// By default, debug messages are sent to standard output for debug
/// builds only. The relaxed format rules used by util::string_format
/// apply. Note that the format string and arguments will always be
/// evaluated, even if debug messages are disabled.
/// \param [in] fmt Message format string.
/// \param [in] args Optional message format arguments.
/// \sa util::string_format
template <typename Format, typename... Params> void osd_printf_debug(Format &&fmt, Params &&...args)
{
return osd_vprintf_debug(util::make_format_argument_pack(std::forward<Format>(fmt), std::forward<Params>(args)...));
}
/// \}
// returns command line arguments as an std::vector<std::string> in UTF-8
std::vector<std::string> osd_get_command_line(int argc, char *argv[]);
/* discourage the use of printf directly */
/* sadly, can't do this because of the ATTR_PRINTF under GCC */
/*
#undef printf
#define printf !MUST_USE_osd_printf_*_CALLS_WITHIN_THE_CORE!
*/
// specifies "aggressive focus" - should MAME capture input for any windows co-habiting a MAME window?
void osd_set_aggressive_input_focus(bool aggressive_focus);
#endif // MAME_OSD_OSDCORE_H

View File

@ -1,287 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/// \file
/// \brief Core OS-dependent file interface
///
/// The prototypes in this file describe the interfaces that the MAME
/// core and various tools rely on to interact with the outside world.
/// They are broken out into several categories.
#ifndef MAME_OSD_OSDFILE_H
#define MAME_OSD_OSDFILE_H
#pragma once
#include <chrono>
#include <cstdint>
#include <memory>
#include <string>
#include <system_error>
#include <vector>
/***************************************************************************
FILE I/O INTERFACES
***************************************************************************/
/* Make sure we have a path separator (default to /) */
#ifndef PATH_SEPARATOR
#if defined(_WIN32)
#define PATH_SEPARATOR "\\"
#else
#define PATH_SEPARATOR "/"
#endif
#endif
/// \defgroup openflags File open flags
/// \{
/// Open file for reading.
constexpr uint32_t OPEN_FLAG_READ = 0x0001;
/// Open file for writing.
constexpr uint32_t OPEN_FLAG_WRITE = 0x0002;
/// Create the file, or truncate it if it exists.
constexpr uint32_t OPEN_FLAG_CREATE = 0x0004;
/// Create non-existent directories in the path.
constexpr uint32_t OPEN_FLAG_CREATE_PATHS = 0x0008;
/// Do not decompress into memory on open.
constexpr uint32_t OPEN_FLAG_NO_PRELOAD = 0x0010;
/// \}
/// \brief Interface to file-like resources
///
/// This interface is used to access file-like and stream-like
/// resources. Examples include plain files, TCP socket, named pipes,
/// pseudo-terminals, and compressed archive members.
class osd_file
{
public:
/// \brief Smart pointer to a file handle
typedef std::unique_ptr<osd_file> ptr;
/// \brief Open a new file handle
///
/// This function is called by core_fopen and several other places
/// in the core to access files. These functions will construct
/// paths by concatenating various search paths held in the
/// options.c options database with partial paths specified by the
/// core. The core assumes that the path separator is the first
/// character of the string PATH_SEPARATOR, but does not interpret
/// any path separators in the search paths, so if you use a
/// different path separator in a search path, you may get a mixture
/// of PATH_SEPARATORs (from the core) and alternate path separators
/// (specified by users and placed into the options database).
/// \param [in] path Path to the file to open.
/// \param [in] openflags Combination of #OPEN_FLAG_READ,
/// #OPEN_FLAG_WRITE, #OPEN_FLAG_CREATE and
/// #OPEN_FLAG_CREATE_PATHS specifying the requested access mode
/// and open behaviour.
/// \param [out] file Receives the file handle if the operation
/// succeeds. Not valid if the operation fails.
/// \param [out] filesize Receives the size of the opened file if
/// the operation succeeded. Not valid if the operation failed.
/// Will be zero for stream-like objects (e.g. TCP sockets or
/// named pipes).
/// \return Result of the operation.
static std::error_condition open(std::string const &path, std::uint32_t openflags, ptr &file, std::uint64_t &filesize) noexcept;
/// \brief Create a new pseudo-terminal (PTY) pair
///
/// \param [out] file Receives the handle of the master side of the
/// pseudo-terminal if the operation succeeds. Not valid if the
/// operation fails.
/// \param [out] name Receives the name of the slave side of the
/// pseudo-terminal if the operation succeeds. Not valid if the
/// operation fails.
/// \return Result of the operation.
static std::error_condition openpty(ptr &file, std::string &name) noexcept;
/// \brief Close an open file
virtual ~osd_file() { }
/// \brief Read from an open file
///
/// Read data from an open file at specified offset. Note that the
/// seek and read are not guaranteed to be atomic, which may cause
/// issues in multi-threaded applications.
/// \param [out] buffer Pointer to memory that will receive the data
/// read.
/// \param [in] offset Byte offset within the file to read at,
/// relative to the start of the file. Ignored for stream-like
/// objects (e.g. TCP sockets or named pipes).
/// \param [in] length Number of bytes to read. Fewer bytes may be
/// read if the end of file is reached, or if no data is
/// available.
/// \param [out] actual Receives the number of bytes read if the
/// operation succeeds. Not valid if the operation fails.
/// \return Result of the operation.
virtual std::error_condition read(void *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) noexcept = 0;
/// \brief Write to an open file
///
/// Write data to an open file at specified offset. Note that the
/// seek and write are not guaranteed to be atomic, which may cause
/// issues in multi-threaded applications.
/// \param [in] buffer Pointer to memory containing data to write.
/// \param [in] offset Byte offset within the file to write at,
/// relative to the start of the file. Ignored for stream-like
/// objects (e.g. TCP sockets or named pipes).
/// \param [in] length Number of bytes to write.
/// \param [out] actual Receives the number of bytes written if the
/// operation succeeds. Not valid if the operation fails.
/// \return Result of the operation.
virtual std::error_condition write(void const *buffer, std::uint64_t offset, std::uint32_t length, std::uint32_t &actual) noexcept = 0;
/// \brief Change the size of an open file
///
/// \param [in] offset Desired size of the file.
/// \return Result of the operation.
virtual std::error_condition truncate(std::uint64_t offset) noexcept = 0;
/// \brief Flush file buffers
///
/// This flushes any data cached by the application, but does not
/// guarantee that all prior writes have reached persistent storage.
/// \return Result of the operation.
virtual std::error_condition flush() noexcept = 0;
/// \brief Delete a file
///
/// \param [in] filename Path to the file to delete.
/// \return Result of the operation.
static std::error_condition remove(std::string const &filename) noexcept;
};
/// \brief Describe geometry of physical drive
///
/// If the given path points to a physical drive, return the geometry of
/// that drive.
///
/// \param [in] filename Pointer to a path which might describe a
/// physical drive.
/// \param [out] cylinders Pointer to a uint32_t to receive the number of
/// cylinders of the physical drive.
/// \param [out] heads Pointer to a uint32_t to receive the number of
/// heads per cylinder of the physical drive.
/// \param [out] sectors Pointer to a uint32_t to receive the number of
/// sectors per cylinder of the physical drive.
/// \param [out] bps Pointer to a uint32_t to receive the number of
/// bytes per sector of the physical drive.
/// \return true if the filename points to a physical drive and if the
/// values pointed to by cylinders, heads, sectors, and bps are valid;
/// false in any other case
bool osd_get_physical_drive_geometry(const char *filename, uint32_t *cylinders, uint32_t *heads, uint32_t *sectors, uint32_t *bps) noexcept;
/// \brief Is the given character legal for filenames?
///
/// \param [in] uchar The character to check.
/// \return Whether this character is legal in a filename.
bool osd_is_valid_filename_char(char32_t uchar) noexcept;
/// \brief Is the given character legal for paths?
///
/// \param [in] uchar The character to check.
/// \return Whether this character is legal in a file path.
bool osd_is_valid_filepath_char(char32_t uchar) noexcept;
/***************************************************************************
DIRECTORY INTERFACES
***************************************************************************/
namespace osd
{
// directory is an opaque type which represents an open directory
class directory
{
public:
typedef std::unique_ptr<directory> ptr;
// osd::directory::entry contains basic information about a file when iterating through
// a directory
class entry
{
public:
enum class entry_type
{
NONE,
FILE,
DIR,
OTHER
};
const char * name; // name of the entry
entry_type type; // type of the entry
std::uint64_t size; // size of the entry
std::chrono::system_clock::time_point last_modified; // last modified time
};
/// \brief Open a directory for iteration.
///
/// \param [in] dirname Path to the directory in question.
/// \return Upon success, a directory pointer which contains opaque
/// data necessary to traverse the directory; on failure, nullptr.
static ptr open(std::string const &dirname);
/// \brief Close an open directory.
virtual ~directory() { }
/// \brief Return information about the next entry in the directory.
///
/// \return A constant pointer to an entry representing the current
/// item in the directory, or nullptr, indicating that no more
/// entries are present.
virtual const entry *read() = 0;
};
};
/// \brief Return a directory entry for a path.
///
/// \param [in] path The path in question.
/// \return An allocated pointer to an osd::directory::entry representing
/// info on the path; even if the file does not exist.
std::unique_ptr<osd::directory::entry> osd_stat(std::string const &path);
/***************************************************************************
PATH INTERFACES
***************************************************************************/
/// \brief Returns whether the specified path is absolute.
///
/// \param [in] path The path in question.
/// \return true if the path is absolute, false otherwise.
bool osd_is_absolute_path(const std::string &path) noexcept;
/// \brief Retrieves the full path.
/// \param [in] path The path in question.
/// \param [out] dst Reference to receive new path.
/// \return File error.
std::error_condition osd_get_full_path(std::string &dst, std::string const &path) noexcept;
/// \brief Retrieves the volume name.
///
/// \param [in] idx Index number of volume.
/// \return Volume name or empty string of out of range.
std::string osd_get_volume_name(int idx);
/// \brief Retrieves volume names.
///
/// \return Names of all mounted volumes.
std::vector<std::string> osd_get_volume_names();
#endif // MAME_OSD_OSDFILE_H

View File

@ -1,823 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
//============================================================
//
// osdsync.c - OSD core work item functions
//
//============================================================
#if defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
// standard windows headers
#include <windows.h>
#include <process.h>
#include <tchar.h>
#include <cstdlib>
#ifdef __GNUC__
#include <cstdint>
#endif
#endif
#include <mutex>
#include <atomic>
#include <thread>
#include <vector>
#include <algorithm>
// MAME headers
#include "osdcore.h"
#include "osdsync.h"
#include "eminline.h"
#if defined(SDLMAME_LINUX) || defined(SDLMAME_BSD) || defined(SDLMAME_HAIKU) || defined(SDLMAME_EMSCRIPTEN) || defined(SDLMAME_MACOSX)
#include <pthread.h>
#endif
#if defined(MAME_RDP)
#define osd_getenv getenv
#endif
//============================================================
// DEBUGGING
//============================================================
#define KEEP_STATISTICS (0)
//============================================================
// PARAMETERS
//============================================================
#define ENV_PROCESSORS "OSDPROCESSORS"
#define ENV_WORKQUEUEMAXTHREADS "OSDWORKQUEUEMAXTHREADS"
#define SPIN_LOOP_TIME (osd_ticks_per_second() / 10000)
//============================================================
// MACROS
//============================================================
#if KEEP_STATISTICS
#define add_to_stat(v,x) do { (v) += (x); } while (0)
#define begin_timing(v) do { (v) -= get_profile_ticks(); } while (0)
#define end_timing(v) do { (v) += get_profile_ticks(); } while (0)
#else
#define add_to_stat(v,x) do { } while (0)
#define begin_timing(v) do { } while (0)
#define end_timing(v) do { } while (0)
#endif
template<typename _AtomType, typename _MainType>
static void spin_while(const volatile _AtomType * volatile atom, const _MainType val, const osd_ticks_t timeout, const int invert = 0)
{
osd_ticks_t stopspin = osd_ticks() + timeout;
do {
int spin = 10000;
while (--spin)
{
if ((*atom != val) ^ invert)
return;
}
} while (((*atom == val) ^ invert) && osd_ticks() < stopspin);
}
template<typename _AtomType, typename _MainType>
static void spin_while_not(const volatile _AtomType * volatile atom, const _MainType val, const osd_ticks_t timeout)
{
spin_while<_AtomType, _MainType>(atom, val, timeout, 1);
}
//============================================================
// osd_num_processors
//============================================================
int osd_get_num_processors()
{
#if defined(SDLMAME_EMSCRIPTEN)
// multithreading is not supported at this time
return 1;
#else
// max out at 4 for now since scaling above that seems to do poorly
return std::min(std::thread::hardware_concurrency(), 4U);
#endif
}
//============================================================
// TYPE DEFINITIONS
//============================================================
struct work_thread_info
{
work_thread_info(uint32_t aid, osd_work_queue &aqueue)
: queue(aqueue)
, handle(nullptr)
, wakeevent(false, false) // auto-reset, not signalled
, active(0)
, id(aid)
#if KEEP_STATISTICS
, itemsdone(0)
, actruntime(0)
, runtime(0)
, spintime(0)
, waittime(0)
#endif
{
}
osd_work_queue & queue; // pointer back to the queue
std::thread * handle; // handle to the thread
osd_event wakeevent; // wake event for the thread
std::atomic<int32_t> active; // are we actively processing work?
uint32_t id;
#if KEEP_STATISTICS
int32_t itemsdone;
osd_ticks_t actruntime;
osd_ticks_t runtime;
osd_ticks_t spintime;
osd_ticks_t waittime;
#endif
};
struct osd_work_queue
{
osd_work_queue()
: list(nullptr)
, tailptr(nullptr)
, free(nullptr)
, items(0)
, livethreads(0)
, waiting(0)
, exiting(0)
, threads(0)
, flags(0)
, doneevent(true, true) // manual reset, signalled
#if KEEP_STATISTICS
, itemsqueued(0)
, setevents(0)
, extraitems(0)
, spinloops(0)
#endif
{
}
std::mutex lock; // lock for protecting the queue
std::atomic<osd_work_item *> list; // list of items in the queue
osd_work_item ** volatile tailptr; // pointer to the tail pointer of work items in the queue
std::atomic<osd_work_item *> free; // free list of work items
std::atomic<int32_t> items; // items in the queue
std::atomic<int32_t> livethreads; // number of live threads
std::atomic<int32_t> waiting; // is someone waiting on the queue to complete?
std::atomic<int32_t> exiting; // should the threads exit on their next opportunity?
uint32_t threads; // number of threads in this queue
uint32_t flags; // creation flags
std::vector<work_thread_info *> thread; // array of thread information
osd_event doneevent; // event signalled when work is complete
#if KEEP_STATISTICS
std::atomic<int32_t> itemsqueued; // total items queued
std::atomic<int32_t> setevents; // number of times we called SetEvent
std::atomic<int32_t> extraitems; // how many extra items we got after the first in the queue loop
std::atomic<int32_t> spinloops; // how many times spinning bought us more items
#endif
};
struct osd_work_item
{
osd_work_item(osd_work_queue &aqueue)
: next(nullptr)
, queue(aqueue)
, callback(nullptr)
, param(nullptr)
, result(nullptr)
, event(nullptr) // manual reset, not signalled
, flags(0)
, done(false)
{
}
osd_work_item * next; // pointer to next item
osd_work_queue & queue; // pointer back to the owning queue
osd_work_callback callback; // callback function
void * param; // callback parameter
void * result; // callback result
osd_event * event; // event signalled when complete
uint32_t flags; // creation flags
std::atomic<int32_t> done; // is the item done?
};
//============================================================
// GLOBAL VARIABLES
//============================================================
int osd_num_processors = 0;
//============================================================
// FUNCTION PROTOTYPES
//============================================================
static int effective_num_processors();
static void * worker_thread_entry(void *param);
static void worker_thread_process(osd_work_queue *queue, work_thread_info *thread);
static bool queue_has_list_items(osd_work_queue *queue);
//============================================================
// osd_thread_adjust_priority
//============================================================
int thread_adjust_priority(std::thread *thread, int adjust)
{
#if defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
if (adjust)
SetThreadPriority((HANDLE)thread->native_handle(), THREAD_PRIORITY_ABOVE_NORMAL);
else
SetThreadPriority((HANDLE)thread->native_handle(), GetThreadPriority(GetCurrentThread()));
#endif
#if defined(SDLMAME_LINUX) || defined(SDLMAME_BSD) || defined(SDLMAME_HAIKU) || defined(SDLMAME_DARWIN)
struct sched_param sched;
int policy;
if (pthread_getschedparam(thread->native_handle(), &policy, &sched) == 0)
{
sched.sched_priority += adjust;
if (pthread_setschedparam(thread->native_handle(), policy, &sched) == 0)
return true;
else
return false;
}
#endif
return true;
}
//============================================================
// osd_work_queue_alloc
//============================================================
osd_work_queue *osd_work_queue_alloc(int flags)
{
int threadnum;
int numprocs = effective_num_processors();
osd_work_queue *queue;
int osdthreadnum = 0;
int allocthreadnum;
const char *osdworkqueuemaxthreads = osd_getenv(ENV_WORKQUEUEMAXTHREADS);
// allocate a new queue
queue = new osd_work_queue();
// initialize basic queue members
queue->tailptr = (osd_work_item **)&queue->list;
queue->flags = flags;
// determine how many threads to create...
// on a single-CPU system, create 1 thread for I/O queues, and 0 threads for everything else
if (numprocs == 1)
threadnum = (flags & WORK_QUEUE_FLAG_IO) ? 1 : 0;
// on an n-CPU system, create n-1 threads for multi queues, and 1 thread for everything else
else
threadnum = (flags & WORK_QUEUE_FLAG_MULTI) ? (numprocs - 1) : 1;
if (osdworkqueuemaxthreads != nullptr && sscanf(osdworkqueuemaxthreads, "%d", &osdthreadnum) == 1 && threadnum > osdthreadnum)
threadnum = osdthreadnum;
#if defined(SDLMAME_EMSCRIPTEN)
// threads are not supported at all
threadnum = 0;
#endif
// clamp to the maximum
queue->threads = std::min(threadnum, WORK_MAX_THREADS);
// allocate memory for thread array (+1 to count the calling thread if WORK_QUEUE_FLAG_MULTI)
if (flags & WORK_QUEUE_FLAG_MULTI)
allocthreadnum = queue->threads + 1;
else
allocthreadnum = queue->threads;
#if KEEP_STATISTICS
printf("osdprocs: %d effecprocs: %d threads: %d allocthreads: %d osdthreads: %d maxthreads: %d queuethreads: %d\n", osd_num_processors, numprocs, threadnum, allocthreadnum, osdthreadnum, WORK_MAX_THREADS, queue->threads);
#endif
for (threadnum = 0; threadnum < allocthreadnum; threadnum++)
queue->thread.push_back(new work_thread_info(threadnum, *queue));
// iterate over threads
for (threadnum = 0; threadnum < queue->threads; threadnum++)
{
work_thread_info *thread = queue->thread[threadnum];
// create the thread
thread->handle = new std::thread(worker_thread_entry, thread);
if (thread->handle == nullptr)
goto error;
// set its priority: I/O threads get high priority because they are assumed to be
// blocked most of the time; other threads just match the creator's priority
if (flags & WORK_QUEUE_FLAG_IO)
thread_adjust_priority(thread->handle, 1);
else
thread_adjust_priority(thread->handle, 0);
}
// start a timer going for "waittime" on the main thread
if (flags & WORK_QUEUE_FLAG_MULTI)
{
begin_timing(queue->thread[queue->threads]->waittime);
}
return queue;
error:
osd_work_queue_free(queue);
return nullptr;
}
//============================================================
// osd_work_queue_items
//============================================================
int osd_work_queue_items(osd_work_queue *queue)
{
// return the number of items currently in the queue
return queue->items;
}
//============================================================
// osd_work_queue_wait
//============================================================
bool osd_work_queue_wait(osd_work_queue *queue, osd_ticks_t timeout)
{
// if no threads, no waiting
if (queue->threads == 0)
return true;
// if no items, we're done
if (queue->items == 0)
return true;
// if this is a multi queue, help out rather than doing nothing
if (queue->flags & WORK_QUEUE_FLAG_MULTI)
{
work_thread_info *thread = queue->thread[queue->threads];
end_timing(thread->waittime);
// process what we can as a worker thread
worker_thread_process(queue, thread);
// if we're a high frequency queue, spin until done
if (queue->flags & WORK_QUEUE_FLAG_HIGH_FREQ && queue->items != 0)
{
// spin until we're done
begin_timing(thread->spintime);
spin_while_not<std::atomic<int>,int>(&queue->items, 0, timeout);
end_timing(thread->spintime);
begin_timing(thread->waittime);
return (queue->items == 0);
}
begin_timing(thread->waittime);
}
// reset our done event and double-check the items before waiting
queue->doneevent.reset();
queue->waiting = true;
if (queue->items != 0)
queue->doneevent.wait(timeout);
queue->waiting = false;
// return true if we actually hit 0
return (queue->items == 0);
}
//============================================================
// osd_work_queue_free
//============================================================
void osd_work_queue_free(osd_work_queue *queue)
{
// stop the timer for "waittime" on the main thread
if (queue->flags & WORK_QUEUE_FLAG_MULTI)
{
end_timing(queue->thread[queue->threads]->waittime);
}
// signal all the threads to exit
queue->exiting = true;
for (int threadnum = 0; threadnum < queue->threads; threadnum++)
{
work_thread_info *thread = queue->thread[threadnum];
thread->wakeevent.set();
}
// wait for all the threads to go away
for (int threadnum = 0; threadnum < queue->threads; threadnum++)
{
work_thread_info *thread = queue->thread[threadnum];
// block on the thread going away, then close the handle
if (thread->handle != nullptr)
{
thread->handle->join();
delete thread->handle;
}
}
#if KEEP_STATISTICS
// output per-thread statistics
for (work_thread_info *thread : queue->thread)
{
osd_ticks_t total = thread->runtime + thread->waittime + thread->spintime;
printf("Thread %d: items=%9d run=%5.2f%% (%5.2f%%) spin=%5.2f%% wait/other=%5.2f%% total=%9d\n",
thread->id, thread->itemsdone,
(double)thread->runtime * 100.0 / (double)total,
(double)thread->actruntime * 100.0 / (double)total,
(double)thread->spintime * 100.0 / (double)total,
(double)thread->waittime * 100.0 / (double)total,
(uint32_t) total);
}
#endif
// free the list
for (auto & th : queue->thread)
delete th;
queue->thread.clear();
// free all items in the free list
while (queue->free.load() != nullptr)
{
auto *item = (osd_work_item *)queue->free;
queue->free = item->next;
delete item->event;
delete item;
}
// free all items in the active list
while (queue->list.load() != nullptr)
{
auto *item = (osd_work_item *)queue->list;
queue->list = item->next;
delete item->event;
delete item;
}
#if KEEP_STATISTICS
printf("Items queued = %9d\n", queue->itemsqueued.load());
printf("SetEvent calls = %9d\n", queue->setevents.load());
printf("Extra items = %9d\n", queue->extraitems.load());
printf("Spin loops = %9d\n", queue->spinloops.load());
#endif
// free the queue itself
delete queue;
}
//============================================================
// osd_work_item_queue_multiple
//============================================================
osd_work_item *osd_work_item_queue_multiple(osd_work_queue *queue, osd_work_callback callback, int32_t numitems, void *parambase, int32_t paramstep, uint32_t flags)
{
osd_work_item *itemlist = nullptr, *lastitem = nullptr;
osd_work_item **item_tailptr = &itemlist;
int itemnum;
// loop over items, building up a local list of work
for (itemnum = 0; itemnum < numitems; itemnum++)
{
osd_work_item *item;
// first allocate a new work item; try the free list first
{
std::lock_guard<std::mutex> lock(queue->lock);
do
{
item = (osd_work_item *)queue->free;
} while (item != nullptr && !queue->free.compare_exchange_weak(item, item->next, std::memory_order_release, std::memory_order_relaxed));
}
// if nothing, allocate something new
if (item == nullptr)
{
// allocate the item
item = new osd_work_item(*queue);
if (item == nullptr)
return nullptr;
}
else
{
item->done = false; // needs to be set this way to prevent data race/usage of uninitialized memory on Linux
}
// fill in the basics
item->next = nullptr;
item->callback = callback;
item->param = parambase;
item->result = nullptr;
item->flags = flags;
// advance to the next
lastitem = item;
*item_tailptr = item;
item_tailptr = &item->next;
parambase = (uint8_t *)parambase + paramstep;
}
// enqueue the whole thing within the critical section
{
std::lock_guard<std::mutex> lock(queue->lock);
*queue->tailptr = itemlist;
queue->tailptr = item_tailptr;
}
// increment the number of items in the queue
queue->items += numitems;
add_to_stat(queue->itemsqueued, numitems);
// look for free threads to do the work
if (queue->livethreads < queue->threads)
{
int threadnum;
// iterate over all the threads
for (threadnum = 0; threadnum < queue->threads; threadnum++)
{
work_thread_info *thread = queue->thread[threadnum];
// if this thread is not active, wake him up
if (!thread->active)
{
thread->wakeevent.set();
add_to_stat(queue->setevents, 1);
// for non-shared, the first one we find is good enough
if (--numitems == 0)
break;
}
}
}
// if no threads, run the queue now on this thread
if (queue->threads == 0)
{
end_timing(queue->thread[0]->waittime);
worker_thread_process(queue, queue->thread[0]);
begin_timing(queue->thread[0]->waittime);
}
// only return the item if it won't get released automatically
return (flags & WORK_ITEM_FLAG_AUTO_RELEASE) ? nullptr : lastitem;
}
//============================================================
// osd_work_item_wait
//============================================================
bool osd_work_item_wait(osd_work_item *item, osd_ticks_t timeout)
{
// if we're done already, just return
if (item->done)
return true;
// if we don't have an event, create one
if (item->event == nullptr)
{
std::lock_guard<std::mutex> lock(item->queue.lock);
item->event = new osd_event(true, false); // manual reset, not signalled
}
else
item->event->reset();
// if we don't have an event, we need to spin (shouldn't ever really happen)
if (item->event == nullptr)
{
// TODO: do we need to measure the spin time here as well? and how can we do it?
spin_while<std::atomic<int>,int>(&item->done, 0, timeout);
}
// otherwise, block on the event until done
else if (!item->done)
item->event->wait(timeout);
// return true if the refcount actually hit 0
return item->done;
}
//============================================================
// osd_work_item_result
//============================================================
void *osd_work_item_result(osd_work_item *item)
{
return item->result;
}
//============================================================
// osd_work_item_release
//============================================================
void osd_work_item_release(osd_work_item *item)
{
osd_work_item *next;
// make sure we're done first
osd_work_item_wait(item, 100 * osd_ticks_per_second());
// add us to the free list on our queue
std::lock_guard<std::mutex> lock(item->queue.lock);
do
{
next = (osd_work_item *) item->queue.free;
item->next = next;
} while (!item->queue.free.compare_exchange_weak(next, item, std::memory_order_release, std::memory_order_relaxed));
}
//============================================================
// effective_num_processors
//============================================================
static int effective_num_processors()
{
int physprocs = osd_get_num_processors();
// osd_num_processors == 0 for 'auto'
if (osd_num_processors > 0)
{
return std::min(4 * physprocs, osd_num_processors);
}
else
{
int numprocs = 0;
// if the OSDPROCESSORS environment variable is set, use that value if valid
// note that we permit more than the real number of processors for testing
const char *procsoverride = osd_getenv(ENV_PROCESSORS);
if (procsoverride != nullptr && sscanf(procsoverride, "%d", &numprocs) == 1 && numprocs > 0)
return std::min(4 * physprocs, numprocs);
// otherwise, return the info from the system
return physprocs;
}
}
//============================================================
// worker_thread_entry
//============================================================
static void *worker_thread_entry(void *param)
{
auto *thread = (work_thread_info *)param;
osd_work_queue &queue = thread->queue;
// loop until we exit
for ( ;; )
{
// block waiting for work or exit
// bail on exit, and only wait if there are no pending items in queue
if (queue.exiting)
break;
if (!queue_has_list_items(&queue))
{
begin_timing(thread->waittime);
thread->wakeevent.wait( OSD_EVENT_WAIT_INFINITE);
end_timing(thread->waittime);
}
if (queue.exiting)
break;
// indicate that we are live
thread->active = true;
++queue.livethreads;
// process work items
for ( ;; )
{
// process as much as we can
worker_thread_process(&queue, thread);
// if we're a high frequency queue, spin for a while before giving up
if (queue.flags & WORK_QUEUE_FLAG_HIGH_FREQ && queue.list.load() == nullptr)
{
// spin for a while looking for more work
begin_timing(thread->spintime);
spin_while<std::atomic<osd_work_item *>, osd_work_item *>(&queue.list, (osd_work_item *)nullptr, SPIN_LOOP_TIME);
end_timing(thread->spintime);
}
// if nothing more, release the processor
if (!queue_has_list_items(&queue))
break;
add_to_stat(queue.spinloops, 1);
}
// decrement the live thread count
thread->active = false;
--queue.livethreads;
}
return nullptr;
}
//============================================================
// worker_thread_process
//============================================================
static void worker_thread_process(osd_work_queue *queue, work_thread_info *thread)
{
int threadid = thread->id;
begin_timing(thread->runtime);
// loop until everything is processed
while (true)
{
osd_work_item *item = nullptr;
bool end_loop = false;
// use a critical section to synchronize the removal of items
{
std::lock_guard<std::mutex> lock(queue->lock);
if (queue->list.load() == nullptr)
{
end_loop = true;
}
else
{
// pull the item from the queue
item = (osd_work_item *)queue->list;
if (item != nullptr)
{
queue->list = item->next;
if (queue->list.load() == nullptr)
queue->tailptr = (osd_work_item **)&queue->list;
}
}
}
if (end_loop)
break;
// process non-NULL items
if (item != nullptr)
{
// call the callback and stash the result
begin_timing(thread->actruntime);
item->result = (*item->callback)(item->param, threadid);
end_timing(thread->actruntime);
// decrement the item count after we are done
--queue->items;
item->done = true;
add_to_stat(thread->itemsdone, 1);
// if it's an auto-release item, release it
if (item->flags & WORK_ITEM_FLAG_AUTO_RELEASE)
osd_work_item_release(item);
// set the result and signal the event
else
{
std::lock_guard<std::mutex> lock(queue->lock);
if (item->event != nullptr)
{
item->event->set();
add_to_stat(item->queue.setevents, 1);
}
}
// if we removed an item and there's still work to do, bump the stats
if (queue_has_list_items(queue))
add_to_stat(queue->extraitems, 1);
}
}
// we don't need to set the doneevent for multi queues because they spin
if (queue->waiting)
{
queue->doneevent.set();
add_to_stat(queue->setevents, 1);
}
end_timing(thread->runtime);
}
bool queue_has_list_items(osd_work_queue *queue)
{
std::lock_guard<std::mutex> lock(queue->lock);
bool has_list_items = (queue->list.load() != nullptr);
return has_list_items;
}

View File

@ -1,167 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert, R. Belmont
//============================================================
//
// osdsync.h - Core synchronization functions
//
//============================================================
#ifndef MAME_OSD_OSDSYNC_H
#define MAME_OSD_OSDSYNC_H
#pragma once
// C++ headers
#include <mutex>
#include <atomic>
#include <condition_variable>
#include "osdcomm.h"
/***************************************************************************
SYNCHRONIZATION INTERFACES - Events
***************************************************************************/
#define OSD_EVENT_WAIT_INFINITE (~(osd_ticks_t)0)
/* osd_event is an opaque type which represents a setable/resettable event */
class osd_event
{
public:
/*-----------------------------------------------------------------------------
constructor: allocate a new event
Parameters:
manualreset - boolean. If true, the event will be automatically set
to non-signalled after a thread successfully waited for
it.
initialstate - boolean. If true, the event is signalled initially.
Return value:
A pointer to the allocated event.
-----------------------------------------------------------------------------*/
osd_event(int manualreset, int initialstate)
{
m_signalled = initialstate;
m_autoreset = !manualreset;
}
~osd_event()
{
}
/*-----------------------------------------------------------------------------
wait: wait for an event to be signalled
If the event is in signalled state, the
function returns immediately. If not it will wait for the event
to become signalled.
Parameters:
timeout - timeout in osd_ticks
Return value:
true: The event was signalled
false: A timeout occurred
-----------------------------------------------------------------------------*/
bool wait(osd_ticks_t timeout)
{
if (timeout == OSD_EVENT_WAIT_INFINITE)
timeout = osd_ticks_per_second() * (osd_ticks_t)10000;
std::unique_lock<std::mutex> lock(m_mutex);
if (!timeout)
{
if (!m_signalled)
{
return false;
}
}
else
{
if (!m_signalled)
{
uint64_t msec = timeout * 1000 / osd_ticks_per_second();
do {
if (m_cond.wait_for(lock, std::chrono::milliseconds(msec)) == std::cv_status::timeout)
{
if (!m_signalled)
{
return false;
}
else
break;
} else
break;
} while (true);
}
}
if (m_autoreset)
m_signalled = 0;
return true;
}
/*-----------------------------------------------------------------------------
osd_event_reset: reset an event to non-signalled state
Parameters:
None
Return value:
None
-----------------------------------------------------------------------------*/
void reset()
{
m_mutex.lock();
m_signalled = false;
m_mutex.unlock();
}
/*-----------------------------------------------------------------------------
osd_event_set: set an event to signalled state
Parameters:
None
Return value:
None
Notes:
All threads waiting for the event will be signalled.
-----------------------------------------------------------------------------*/
void set()
{
m_mutex.lock();
if (m_signalled == false)
{
m_signalled = true;
if (m_autoreset)
m_cond.notify_one();
else
m_cond.notify_all();
}
m_mutex.unlock();
}
private:
std::mutex m_mutex;
std::condition_variable m_cond;
std::atomic<int32_t> m_autoreset;
std::atomic<int32_t> m_signalled;
};
#endif // MAME_OSD_OSDSYNC_H

@ -1 +1 @@
Subproject commit 7e45e3582be653db468293189d63349c2632c3cb
Subproject commit 70e45e69f466fb6750abc786200cf027ade11867