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:
parent
f8a688d47f
commit
ccac4d1000
|
@ -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.
|
@ -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 }),
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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() { }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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+";
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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)
|
|
@ -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 {
|
||||
|
|
|
@ -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});
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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__
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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 */
|
|
@ -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
|
|
@ -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
|
@ -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
|
|
@ -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
|
@ -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_
|
|
@ -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_
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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_
|
|
@ -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
|
@ -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_
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
Loading…
Reference in New Issue