some changes to corefeatureanalysis

This commit is contained in:
goyuken 2015-01-16 00:48:40 +00:00
parent 6de080dd9c
commit c5daf82a3b
4 changed files with 218 additions and 188 deletions

View File

@ -33,12 +33,13 @@
this.CoreTree = new System.Windows.Forms.TreeView(); this.CoreTree = new System.Windows.Forms.TreeView();
this.tabControl1 = new System.Windows.Forms.TabControl(); this.tabControl1 = new System.Windows.Forms.TabControl();
this.tabPage1 = new System.Windows.Forms.TabPage(); this.tabPage1 = new System.Windows.Forms.TabPage();
this.CurrentCoreTree = new System.Windows.Forms.TreeView();
this.tabPage2 = new System.Windows.Forms.TabPage(); this.tabPage2 = new System.Windows.Forms.TabPage();
this.ReleasedCoresLabel = new System.Windows.Forms.Label(); this.ReleasedCoresLabel = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label(); this.label2 = new System.Windows.Forms.Label();
this.TotalCoresLabel = new System.Windows.Forms.Label(); this.TotalCoresLabel = new System.Windows.Forms.Label();
this.label1 = new System.Windows.Forms.Label(); this.label1 = new System.Windows.Forms.Label();
this.CurrentCoreTree = new System.Windows.Forms.TreeView(); this.menuStrip1 = new System.Windows.Forms.MenuStrip();
this.tabControl1.SuspendLayout(); this.tabControl1.SuspendLayout();
this.tabPage1.SuspendLayout(); this.tabPage1.SuspendLayout();
this.tabPage2.SuspendLayout(); this.tabPage2.SuspendLayout();
@ -63,7 +64,7 @@
| System.Windows.Forms.AnchorStyles.Right))); | System.Windows.Forms.AnchorStyles.Right)));
this.CoreTree.Location = new System.Drawing.Point(6, 24); this.CoreTree.Location = new System.Drawing.Point(6, 24);
this.CoreTree.Name = "CoreTree"; this.CoreTree.Name = "CoreTree";
this.CoreTree.Size = new System.Drawing.Size(481, 495); this.CoreTree.Size = new System.Drawing.Size(481, 480);
this.CoreTree.TabIndex = 0; this.CoreTree.TabIndex = 0;
// //
// tabControl1 // tabControl1
@ -73,10 +74,10 @@
| System.Windows.Forms.AnchorStyles.Right))); | System.Windows.Forms.AnchorStyles.Right)));
this.tabControl1.Controls.Add(this.tabPage1); this.tabControl1.Controls.Add(this.tabPage1);
this.tabControl1.Controls.Add(this.tabPage2); this.tabControl1.Controls.Add(this.tabPage2);
this.tabControl1.Location = new System.Drawing.Point(15, 12); this.tabControl1.Location = new System.Drawing.Point(15, 27);
this.tabControl1.Name = "tabControl1"; this.tabControl1.Name = "tabControl1";
this.tabControl1.SelectedIndex = 0; this.tabControl1.SelectedIndex = 0;
this.tabControl1.Size = new System.Drawing.Size(501, 551); this.tabControl1.Size = new System.Drawing.Size(501, 536);
this.tabControl1.TabIndex = 6; this.tabControl1.TabIndex = 6;
// //
// tabPage1 // tabPage1
@ -85,11 +86,21 @@
this.tabPage1.Location = new System.Drawing.Point(4, 22); this.tabPage1.Location = new System.Drawing.Point(4, 22);
this.tabPage1.Name = "tabPage1"; this.tabPage1.Name = "tabPage1";
this.tabPage1.Padding = new System.Windows.Forms.Padding(3); this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
this.tabPage1.Size = new System.Drawing.Size(493, 525); this.tabPage1.Size = new System.Drawing.Size(493, 510);
this.tabPage1.TabIndex = 0; this.tabPage1.TabIndex = 0;
this.tabPage1.Text = "Current"; this.tabPage1.Text = "Current";
this.tabPage1.UseVisualStyleBackColor = true; this.tabPage1.UseVisualStyleBackColor = true;
// //
// CurrentCoreTree
//
this.CurrentCoreTree.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.CurrentCoreTree.Location = new System.Drawing.Point(6, 6);
this.CurrentCoreTree.Name = "CurrentCoreTree";
this.CurrentCoreTree.Size = new System.Drawing.Size(481, 498);
this.CurrentCoreTree.TabIndex = 1;
//
// tabPage2 // tabPage2
// //
this.tabPage2.Controls.Add(this.ReleasedCoresLabel); this.tabPage2.Controls.Add(this.ReleasedCoresLabel);
@ -100,7 +111,7 @@
this.tabPage2.Location = new System.Drawing.Point(4, 22); this.tabPage2.Location = new System.Drawing.Point(4, 22);
this.tabPage2.Name = "tabPage2"; this.tabPage2.Name = "tabPage2";
this.tabPage2.Padding = new System.Windows.Forms.Padding(3); this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
this.tabPage2.Size = new System.Drawing.Size(493, 525); this.tabPage2.Size = new System.Drawing.Size(493, 510);
this.tabPage2.TabIndex = 1; this.tabPage2.TabIndex = 1;
this.tabPage2.Text = "All"; this.tabPage2.Text = "All";
this.tabPage2.UseVisualStyleBackColor = true; this.tabPage2.UseVisualStyleBackColor = true;
@ -141,15 +152,13 @@
this.label1.TabIndex = 6; this.label1.TabIndex = 6;
this.label1.Text = "Total:"; this.label1.Text = "Total:";
// //
// CurrentCoreTree // menuStrip1
// //
this.CurrentCoreTree.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) this.menuStrip1.Location = new System.Drawing.Point(0, 0);
| System.Windows.Forms.AnchorStyles.Left) this.menuStrip1.Name = "menuStrip1";
| System.Windows.Forms.AnchorStyles.Right))); this.menuStrip1.Size = new System.Drawing.Size(528, 24);
this.CurrentCoreTree.Location = new System.Drawing.Point(6, 6); this.menuStrip1.TabIndex = 7;
this.CurrentCoreTree.Name = "CurrentCoreTree"; this.menuStrip1.Text = "menuStrip1";
this.CurrentCoreTree.Size = new System.Drawing.Size(481, 513);
this.CurrentCoreTree.TabIndex = 1;
// //
// CoreFeatureAnalysis // CoreFeatureAnalysis
// //
@ -160,16 +169,18 @@
this.ClientSize = new System.Drawing.Size(528, 604); this.ClientSize = new System.Drawing.Size(528, 604);
this.Controls.Add(this.tabControl1); this.Controls.Add(this.tabControl1);
this.Controls.Add(this.OkBtn); this.Controls.Add(this.OkBtn);
this.Controls.Add(this.menuStrip1);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MainMenuStrip = this.menuStrip1;
this.Name = "CoreFeatureAnalysis"; this.Name = "CoreFeatureAnalysis";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Core Features"; this.Text = "Core Features";
this.Load += new System.EventHandler(this.CoreFeatureAnalysis_Load);
this.tabControl1.ResumeLayout(false); this.tabControl1.ResumeLayout(false);
this.tabPage1.ResumeLayout(false); this.tabPage1.ResumeLayout(false);
this.tabPage2.ResumeLayout(false); this.tabPage2.ResumeLayout(false);
this.tabPage2.PerformLayout(); this.tabPage2.PerformLayout();
this.ResumeLayout(false); this.ResumeLayout(false);
this.PerformLayout();
} }
@ -185,5 +196,6 @@
private System.Windows.Forms.Label TotalCoresLabel; private System.Windows.Forms.Label TotalCoresLabel;
private System.Windows.Forms.Label label1; private System.Windows.Forms.Label label1;
private System.Windows.Forms.TreeView CurrentCoreTree; private System.Windows.Forms.TreeView CurrentCoreTree;
private System.Windows.Forms.MenuStrip menuStrip1;
} }
} }

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
using System.Windows.Forms; using System.Windows.Forms;
@ -10,11 +11,105 @@ using BizHawk.Client.Common;
namespace BizHawk.Client.EmuHawk namespace BizHawk.Client.EmuHawk
{ {
public partial class CoreFeatureAnalysis : Form public partial class CoreFeatureAnalysis : Form, IToolFormAutoConfig
{ {
#region ConfigPersist
private class CoreInfo
{
public string CoreName { get; set; }
public string TypeName { get; set; }
public bool Released { get; set; }
public Dictionary<string, ServiceInfo> Services { get; set; }
public CoreInfo() { }
public CoreInfo(IEmulator emu)
{
TypeName = emu.GetType().ToString();
CoreName = emu.Attributes().CoreName;
Released = emu.Attributes().Released;
Services = new Dictionary<string, ServiceInfo>();
var ser = emu.ServiceProvider;
foreach (Type t in ser.AvailableServices)
{
var si = new ServiceInfo(t, ser.GetService(t));
Services.Add(si.TypeName, si);
}
}
}
private class ServiceInfo
{
public string TypeName { get; set; }
public bool Complete { get; set; }
public List<FunctionInfo> Functions { get; set; }
public ServiceInfo() { }
public ServiceInfo(Type servicetype, object service)
{
if (servicetype.IsGenericType)
{
TypeName = servicetype.GetGenericTypeDefinition().ToString();
}
else
{
TypeName = servicetype.ToString();
}
Functions = new List<FunctionInfo>();
IEnumerable<MethodInfo> methods = servicetype.GetMethods(); // .Concat(servicetype.GetProperties().Select(p => p.GetGetMethod()));
if (servicetype.IsInterface)
{
var map = service.GetType().GetInterfaceMap(servicetype);
// project interface methods to actual implementations
methods = methods.Select(
m => map.TargetMethods[Array.IndexOf(map.InterfaceMethods, m)]);
}
foreach (var method in methods)
{
Functions.Add(new FunctionInfo(method, service));
}
Complete = Functions.All(f => f.Complete);
}
}
private class FunctionInfo
{
public string TypeName { get; set; }
public bool Complete { get; set; }
public FunctionInfo() { }
public FunctionInfo(MethodInfo m, object service)
{
TypeName = m.ToString();
try
{
Complete = m.IsImplemented();
}
catch
{
Complete = false; // TODO: fixme
}
}
}
[ConfigPersist]
private Dictionary<string, CoreInfo> KnownCores { get; set; }
[ConfigPersist]
private HashSet<string> KnownServices { get; set; }
#endregion
[RequiredService]
IEmulator emu { get; set; }
public CoreFeatureAnalysis() public CoreFeatureAnalysis()
{ {
InitializeComponent(); InitializeComponent();
KnownCores = new Dictionary<string, CoreInfo>();
KnownServices = new HashSet<string>();
} }
private void OkBtn_Click(object sender, EventArgs e) private void OkBtn_Click(object sender, EventArgs e)
@ -22,208 +117,128 @@ namespace BizHawk.Client.EmuHawk
Close(); Close();
} }
private void CoreFeatureAnalysis_Load(object sender, EventArgs e) private TreeNode CreateCoreTree(CoreInfo ci)
{ {
DoCurrentCoreTree(); var ret = new TreeNode
DoAllCoresTree(); {
Text = ci.CoreName + (ci.Released ? string.Empty : " (UNRELEASED)"),
ForeColor = ci.Released ? Color.Black : Color.DarkGray
};
foreach (var service in ci.Services.Values)
{
string img = service.Complete ? "Good" : "Bad";
var serviceNode = new TreeNode
{
Text = service.TypeName,
ForeColor = service.Complete ? Color.Black : Color.Red,
ImageKey = img,
SelectedImageKey = img,
StateImageKey = img
};
foreach (var function in service.Functions)
{
img = function.Complete ? "Good" : "Bad";
serviceNode.Nodes.Add(new TreeNode
{
Text = function.TypeName,
ForeColor = function.Complete ? Color.Black : Color.Red,
ImageKey = img,
SelectedImageKey = img,
StateImageKey = img
});
}
ret.Nodes.Add(serviceNode);
}
foreach (string servicename in KnownServices.Where(s => !ci.Services.ContainsKey(s)))
{
string img = "Bad";
var serviceNode = new TreeNode
{
Text = servicename,
ForeColor = Color.Red,
ImageKey = img,
SelectedImageKey = img,
StateImageKey = img
};
ret.Nodes.Add(serviceNode);
}
return ret;
} }
private void DoCurrentCoreTree() private void DoCurrentCoreTree(CoreInfo ci)
{ {
CurrentCoreTree.ImageList = new ImageList(); CurrentCoreTree.ImageList = new ImageList();
CurrentCoreTree.ImageList.Images.Add("Good", Properties.Resources.GreenCheck); CurrentCoreTree.ImageList.Images.Add("Good", Properties.Resources.GreenCheck);
CurrentCoreTree.ImageList.Images.Add("Bad", Properties.Resources.ExclamationRed); CurrentCoreTree.ImageList.Images.Add("Bad", Properties.Resources.ExclamationRed);
var core = Global.Emulator;
var services = Assembly
.GetAssembly(typeof(IEmulator))
.GetTypes()
.Where(t => t.IsInterface)
.Where(t => typeof(IEmulatorService).IsAssignableFrom(t))
.Where(t => t != typeof(IEmulatorService))
.ToList();
var additionalRegisteredServices = core.ServiceProvider.AvailableServices
.Where(s => !services.Contains(s))
.Where(s => s != core.GetType()); // We don't care about the core itself
services.AddRange(additionalRegisteredServices);
CurrentCoreTree.Nodes.Clear(); CurrentCoreTree.Nodes.Clear();
CurrentCoreTree.BeginUpdate(); CurrentCoreTree.BeginUpdate();
var coreNode = CreateCoreTree(ci);
var coreNode = new TreeNode
{
Text = core.Attributes().CoreName + (core.Attributes().Released ? string.Empty : " (UNRELEASED)"),
ForeColor = core.Attributes().Released ? Color.Black : Color.DarkGray,
};
coreNode.Expand(); coreNode.Expand();
bool missingImplementation = false;
foreach (var service in services)
{
bool isImplemented = false;
if (core.ServiceProvider.HasService(service))
{
isImplemented = true;
}
else if (service.IsAssignableFrom(typeof(ISettable<,>))) // TODO
{
isImplemented = core.GetType()
.GetInterfaces()
.Where(t => t.IsGenericType &&
t.GetGenericTypeDefinition() == typeof(ISettable<,>))
.FirstOrDefault() != null;
}
var serviceNode = new TreeNode
{
Text = service.Name,
ForeColor = isImplemented ? Color.Black : Color.Red
};
bool fullyImplementedInterface = isImplemented;
if (isImplemented)
{
foreach (var field in service.GetMethods().OrderBy(f => f.Name))
{
try
{
var coreImplementation = core.ServiceProvider.GetService(service).GetType().GetMethod(field.Name);
if (coreImplementation != null)
{
var i = coreImplementation.IsImplemented();
serviceNode.Nodes.Add(new TreeNode
{
Text = field.Name,
ImageKey = i ? "Good" : "Bad",
SelectedImageKey = i ? "Good" : "Bad",
StateImageKey = i ? "Good" : "Bad"
});
if (!i)
{
fullyImplementedInterface = false;
}
}
}
catch (Exception)
{
// TODO: SavestateBinary() and SaveStateBinary(BinaryWriter bw) cause an exception, need to look at signature too
}
}
}
else
{
missingImplementation = true;
}
serviceNode.StateImageKey = serviceNode.SelectedImageKey = serviceNode.ImageKey = fullyImplementedInterface ? "Good" : "Bad";
coreNode.Nodes.Add(serviceNode);
}
coreNode.StateImageKey = coreNode.SelectedImageKey = coreNode.ImageKey = missingImplementation ? "Bad" : "Good";
CurrentCoreTree.Nodes.Add(coreNode); CurrentCoreTree.Nodes.Add(coreNode);
CurrentCoreTree.EndUpdate(); CurrentCoreTree.EndUpdate();
} }
private void DoAllCoresTree() private void DoAllCoresTree(CoreInfo current_ci)
{ {
CoreTree.ImageList = new ImageList(); CoreTree.ImageList = new ImageList();
CoreTree.ImageList.Images.Add("Good", Properties.Resources.GreenCheck); CoreTree.ImageList.Images.Add("Good", Properties.Resources.GreenCheck);
CoreTree.ImageList.Images.Add("Bad", Properties.Resources.ExclamationRed); CoreTree.ImageList.Images.Add("Bad", Properties.Resources.ExclamationRed);
var cores = Assembly TotalCoresLabel.Text = KnownCores.Count.ToString();
.Load("BizHawk.Emulation.Cores") ReleasedCoresLabel.Text = KnownCores.Values.Count(c => c.Released).ToString();
.GetTypes()
.Where(t => typeof(IEmulator).IsAssignableFrom(t))
.Select(core => new
{
CoreType = core,
CoreAttributes = core.GetCustomAttributes(false)
.OfType<CoreAttributes>()
.Single(),
ServicesNotApplicable = core.GetCustomAttributes(false)
.OfType<ServiceNotApplicable>()
.SingleOrDefault() ?? new ServiceNotApplicable()
})
.OrderBy(c => !c.CoreAttributes.Released)
.ThenBy(c => c.CoreAttributes.CoreName)
.ToList();
TotalCoresLabel.Text = cores.Count.ToString();
ReleasedCoresLabel.Text = cores.Count(c => c.CoreAttributes.Released).ToString();
CoreTree.Nodes.Clear(); CoreTree.Nodes.Clear();
CoreTree.BeginUpdate(); CoreTree.BeginUpdate();
foreach (var core in cores) foreach (var ci in KnownCores.Values)
{ {
var coreNode = new TreeNode var coreNode = CreateCoreTree(ci);
{
Text = core.CoreAttributes.CoreName + (core.CoreAttributes.Released ? string.Empty : " (UNRELEASED)"),
ForeColor = core.CoreAttributes.Released ? Color.Black : Color.DarkGray,
};
var service = typeof(IEmulator); if (ci.CoreName == current_ci.CoreName)
bool isImplemented = false;
if (service.IsAssignableFrom(core.CoreType))
{ {
isImplemented = true; coreNode.Expand();
} }
var serviceNode = new TreeNode
{
Text = service.Name,
ForeColor = isImplemented ? Color.Black : Color.Red
};
serviceNode.Expand();
bool fullyImplementedInterface = isImplemented;
if (isImplemented)
{
foreach (var field in service.GetMethods().OrderBy(f => f.Name))
{
var coreImplementation = core.CoreType.GetMethod(field.Name);
if (coreImplementation != null)
{
var i = coreImplementation.IsImplemented();
serviceNode.Nodes.Add(new TreeNode
{
Text = field.Name,
ImageKey = i ? "Good" : "Bad",
SelectedImageKey = i ? "Good" : "Bad",
StateImageKey = i ? "Good" : "Bad"
});
if (!i)
{
fullyImplementedInterface = false;
}
}
}
}
serviceNode.StateImageKey = serviceNode.SelectedImageKey = serviceNode.ImageKey = fullyImplementedInterface ? "Good" : "Bad";
coreNode.Nodes.Add(serviceNode);
coreNode.StateImageKey = coreNode.SelectedImageKey = coreNode.ImageKey = fullyImplementedInterface ? "Good" : "Bad";
CoreTree.Nodes.Add(coreNode); CoreTree.Nodes.Add(coreNode);
} }
CoreTree.EndUpdate(); CoreTree.EndUpdate();
} }
#region IToolForm
public void UpdateValues()
{
}
public void FastUpdate()
{
}
public void Restart()
{
var ci = new CoreInfo(emu);
KnownCores[ci.CoreName] = ci;
// this will keep phantom services around even when no core implements them,
// which might not be desired?
KnownServices.UnionWith(ci.Services.Keys);
DoCurrentCoreTree(ci);
DoAllCoresTree(ci);
}
public bool AskSaveChanges()
{
return true;
}
public bool UpdateBefore
{
get { return false; }
}
#endregion
} }
} }

View File

@ -117,6 +117,9 @@
<resheader name="writer"> <resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> <data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value> <value>

View File

@ -3656,7 +3656,7 @@ namespace BizHawk.Client.EmuHawk
private void FeaturesMenuItem_Click(object sender, EventArgs e) private void FeaturesMenuItem_Click(object sender, EventArgs e)
{ {
new CoreFeatureAnalysis().Show(); GlobalWin.Tools.Load<CoreFeatureAnalysis>();
} }
private void HelpSubMenu_DropDownOpened(object sender, EventArgs e) private void HelpSubMenu_DropDownOpened(object sender, EventArgs e)