diff --git a/DisplayMagicianShared/AMD/AMDLibrary.cs b/DisplayMagicianShared/AMD/AMDLibrary.cs index 2162ab4..cbefdbb 100644 --- a/DisplayMagicianShared/AMD/AMDLibrary.cs +++ b/DisplayMagicianShared/AMD/AMDLibrary.cs @@ -1,18 +1,12 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Runtime.InteropServices; using ATI.ADL; using Microsoft.Win32.SafeHandles; -using DisplayMagicianShared; -using System.Threading; -using static DisplayMagicianShared.AMD.AMDProfileData; namespace DisplayMagicianShared.AMD { - internal class AMDLibrary : IDisposable + public class AMDLibrary : IDisposable { // Static members are 'eagerly initialized', that is, // immediately when class is loaded for the first time. @@ -26,7 +20,27 @@ namespace DisplayMagicianShared.AMD // Instantiate a SafeHandle instance. private SafeHandle _safeHandle = new SafeFileHandle(IntPtr.Zero, true); - private IntPtr _adlContextHandle = IntPtr.Zero; + private IntPtr _adlContextHandle = IntPtr.Zero; + + // Struct to be used as the AMD Profile + public struct AMDProfile + { + public List Adapters; + } + + // Struct to store the Display + public struct AMDAdapter + { + internal ADLAdapterInfoX2 AdapterInfoX2; + internal List Displays; + } + + // Struct to store the Display + public struct AMDDisplay + { + internal List DisplayModes; + } + static AMDLibrary() { } public AMDLibrary() @@ -1012,7 +1026,7 @@ namespace DisplayMagicianShared.AMD } } - internal AMDProfile GetActiveProfile() + public AMDProfile GetActiveProfile() { SharedLogger.logger.Trace($"AMDLibrary/GetActiveProfile: Getting AMD active adapter count"); @@ -1511,17 +1525,17 @@ namespace DisplayMagicianShared.AMD return profileToCreate; } - internal bool SetActiveProfile(AMDProfile profileToUse) + public bool SetActiveProfile(AMDProfile profileToUse) { return true; } - internal bool IsActiveProfile(AMDProfile profileToTest) + public bool IsActiveProfile(AMDProfile profileToTest) { return true; } - internal bool IsValidProfile(AMDProfile profileToTest) + public bool IsValidProfile(AMDProfile profileToTest) { return true; } diff --git a/DisplayMagicianShared/AMD/AMDProfileData.cs b/DisplayMagicianShared/AMD/AMDProfileData.cs deleted file mode 100644 index ab2473d..0000000 --- a/DisplayMagicianShared/AMD/AMDProfileData.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using ATI.ADL; - -namespace DisplayMagicianShared.AMD -{ - internal class AMDProfileData : VideoLibraryProfileData - { - - // Struct to be used as the AMD Profile - internal struct AMDProfile - { - public List Adapters; - } - - // Struct to store the Display - internal struct AMDAdapter - { - internal ADLAdapterInfoX2 AdapterInfoX2; - internal List Displays; - } - - // Struct to store the Display - internal struct AMDDisplay - { - internal List DisplayModes; - } - - internal AMDProfile ProfileData {get; set;} - - } -} diff --git a/DisplayMagicianShared/AMD/AMDProfileItem.cs b/DisplayMagicianShared/AMD/AMDProfileItem.cs new file mode 100644 index 0000000..039d483 --- /dev/null +++ b/DisplayMagicianShared/AMD/AMDProfileItem.cs @@ -0,0 +1,422 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Windows.Forms; +using DisplayMagicianShared.Resources; +using Newtonsoft.Json; +using System.Drawing; +using System.Drawing.Imaging; +using System.Text.RegularExpressions; +using IWshRuntimeLibrary; +//using WK.Libraries.HotkeyListenerNS; + +namespace DisplayMagicianShared.AMD +{ + public class AMDProfileItem : ProfileItem, IComparable + { + private static List _allSavedProfiles = new List(); + private ProfileIcon _profileIcon; + private Bitmap _profileBitmap, _profileShortcutBitmap; + private List _profileDisplayIdentifiers = new List(); + + private static readonly string uuidV4Regex = @"(?im)^[{(]?[0-9A-F]{8}[-]?(?:[0-9A-F]{4}[-]?){3}[0-9A-F]{12}[)}]?$"; + + private string _uuid = ""; + private bool _isPossible = false; + private Keys _hotkey = Keys.None; + + + public AMDProfileItem() + { + } + + public new static Version Version = new Version(2, 1); + + #region Instance Properties + + [JsonIgnore] + public override bool IsPossible + { + get + { + // Return the cached answer + return _isPossible; + } + set + { + _isPossible = value; + } + } + + [JsonIgnore] + public override bool IsActive + { + get + { + + if (this.Equals(ProfileRepository.CurrentProfile)) + return true; + else + return false; + + } + } + + public override string Driver { get; } = "AMD"; + + public override string Name { get; set; } + + //public Topology.Path[] Paths { get; set; } = new Topology.Path[0]; + + public AMDLibrary.AMDProfile ProfileData { get; set; } = new AMDLibrary.AMDProfile(); + + public override List ProfileDisplayIdentifiers + { + get + { + if (_profileDisplayIdentifiers.Count == 0) + { + _profileDisplayIdentifiers = AMDLibrary.GetLibrary().GenerateProfileDisplayIdentifiers(); + } + return _profileDisplayIdentifiers; + } + set + { + if (value is List) + _profileDisplayIdentifiers = value; + } + } + + [JsonConverter(typeof(CustomBitmapConverter))] + public new Bitmap ProfileBitmap + { + get + { + if (_profileBitmap != null) + return _profileBitmap; + else + { + _profileBitmap = this.ProfileIcon.ToBitmap(256, 256); + return _profileBitmap; + } + } + set + { + _profileBitmap = value; + } + + } + + #endregion + + public override bool IsValid() + { + + if (ProfileIcon is ProfileIcon && + System.IO.File.Exists(SavedProfileIconCacheFilename) && + ProfileBitmap is Bitmap && + ProfileTightestBitmap is Bitmap && + ProfileDisplayIdentifiers.Count > 0) + { + if (ProfileData.Adapters.Count > 0) + return true; + else + return false; + } + else + return false; + } + + + + public bool CopyTo(AMDProfileItem profile, bool overwriteId = true) + { + if (!(profile is AMDProfileItem)) + return false; + + if (overwriteId == true) + profile.UUID = UUID; + + // Copy all our profile data over to the other profile + profile.Name = Name; + profile.ProfileData = ProfileData; + profile.ProfileIcon = ProfileIcon; + profile.SavedProfileIconCacheFilename = SavedProfileIconCacheFilename; + profile.ProfileBitmap = ProfileBitmap; + profile.ProfileTightestBitmap = ProfileTightestBitmap; + profile.ProfileDisplayIdentifiers = ProfileDisplayIdentifiers; + return true; + } + + public override bool PreSave() + { + // Prepare our profile data for saving + if (_profileDisplayIdentifiers.Count == 0) + { + _profileDisplayIdentifiers = AMDLibrary.GetLibrary().GenerateProfileDisplayIdentifiers(); + } + + // Return if it is valid and we should continue + return IsValid(); + } + + + // The public override for the Object.Equals + public override bool Equals(object obj) + { + return this.Equals(obj as AMDProfileItem); + } + + // Profiles are equal if their Viewports are equal + public bool Equals(AMDProfileItem other) + { + + // If parameter is null, return false. + if (other is null) + return false; + + // Optimization for a common success case. + if (Object.ReferenceEquals(this, other)) + return true; + + // If run-time types are not exactly the same, return false. + if (this.GetType() != other.GetType()) + return false; + + if (ProfileData.Adapters.Count != other.ProfileData.Adapters.Count) + return false; + + // Check if the profile identifiers are not the same, then return false + int foundDICount = 0; + foreach (string profileDI in ProfileDisplayIdentifiers) + { + + if (other.ProfileDisplayIdentifiers.Contains(profileDI)) + { + foundDICount++; + continue; + } + + } + + if (foundDICount != other.ProfileDisplayIdentifiers.Count) + return false; + + foundDICount = 0; + foreach (string profileDI in other.ProfileDisplayIdentifiers) + { + + if (ProfileDisplayIdentifiers.Contains(profileDI)) + { + foundDICount++; + continue; + } + + } + + if (foundDICount != ProfileDisplayIdentifiers.Count) + return false; + + // Check whether the profiles' properties are equal + // We need to exclude the name as the name is solely for saving to disk + // and displaying to the user. + // Two profiles are equal only when they have the same viewport data + // The data may be in different orders each run, so we need to compare them one by one + + int foundPathsCount = 0; + int foundOtherPathsCount = 0; + + // TODO: Make this work in AMD land + /*foreach (Topology.Path profilePath in Paths) + { + if (other.Paths.Contains(profilePath)) + { + foundPathsCount++; + continue; + } + + } + foreach (Topology.Path otherPath in other.Paths) + { + if (Paths.Contains(otherPath)) + { + foundOtherPathsCount++; + continue; + } + }*/ + + + if (foundPathsCount == foundOtherPathsCount) + return true; + else + return false; + } + + // If Equals() returns true for this object compared to another + // then GetHashCode() must return the same value for these objects. + /*public override int GetHashCode() + { + + // Get hash code for the Viewports field if it is not null. + int hashPaths = Paths == null ? 0 : Paths.GetHashCode(); + + //Calculate the hash code for the product. + return hashPaths; + + }*/ + public override int GetHashCode() + { + + // Get hash code for the ProfileDisplayIdentifiers field if it is not null. + int hashIds = ProfileDisplayIdentifiers == null ? 0 : ProfileDisplayIdentifiers.GetHashCode(); + + // Get ProfileData too + int hashProfileData = ProfileData.GetHashCode(); + + // Calculate the hash code for the product. + return (hashIds, hashProfileData).GetHashCode(); + + } + + + public override string ToString() + { + return (Name ?? Language.UN_TITLED_PROFILE); + } + + } + + // Custom Equality comparer for the Profile class + // Allows us to use 'Contains' + class AMDProfileComparer : IEqualityComparer + { + // Products are equal if their names and product numbers are equal. + /*public bool Equals(AMDProfileItem x, AMDProfileItem y) + { + + //Check whether the compared objects reference the same data. + if (Object.ReferenceEquals(x, y)) return true; + + //Check whether any of the compared objects is null. + if (x is null || y is null) + return false; + + // Check whether the profiles' properties are equal + // We need to exclude the name as the name is solely for saving to disk + // and displaying to the user. + // Two profiles are equal only when they have the same viewport data + if (x.Paths.SequenceEqual(y.Paths)) + return true; + else + return false; + }*/ + + public bool Equals(AMDProfileItem x, AMDProfileItem y) + { + + //Check whether the compared objects reference the same data. + if (Object.ReferenceEquals(x, y)) return true; + + //Check whether any of the compared objects is null. + if (x is null || y is null) + return false; + + if (x.ProfileData.Adapters.Count != y.ProfileData.Adapters.Count) + return false; + + // Check if the profile identifiers are not the same, then return false + int foundDICount = 0; + foreach (string profileDI in x.ProfileDisplayIdentifiers) + { + if (y.ProfileDisplayIdentifiers.Contains(profileDI)) + { + foundDICount++; + continue; + } + + } + if (foundDICount != x.ProfileDisplayIdentifiers.Count) + return false; + + foundDICount = 0; + foreach (string profileDI in y.ProfileDisplayIdentifiers) + { + if (x.ProfileDisplayIdentifiers.Contains(profileDI)) + { + foundDICount++; + continue; + } + + } + if (foundDICount != y.ProfileDisplayIdentifiers.Count) + return false; + + + // Check whether the profiles' properties are equal + // We need to exclude the name as the name is solely for saving to disk + // and displaying to the user. + // Two profiles are equal only when they have the same viewport data + int foundPathsCount = 0; + int foundOtherPathsCount = 0; + + // TODO: Fix this so it finds compares ProfileData + /*foreach (Topology.Path profilePath in x.Paths) + { + if (y.Paths.Contains(profilePath)) + { + foundPathsCount++; + continue; + } + + } + foreach (Topology.Path otherPath in y.Paths) + { + if (x.Paths.Contains(otherPath)) + { + foundOtherPathsCount++; + continue; + } + }*/ + + + if (foundPathsCount == foundOtherPathsCount) + return true; + else + return false; + } + + // If Equals() returns true for a pair of objects + // then GetHashCode() must return the same value for these objects. + /*public int GetHashCode(AMDProfileItem profile) + { + + // Check whether the object is null + if (profile is null) return 0; + + // Get hash code for the Viewports field if it is not null. + int hashPaths = profile.Paths == null ? 0 : profile.Paths.GetHashCode(); + + //Calculate the hash code for the product. + return hashPaths; + + }*/ + // Modified the GetHashCode to compare the displayidentifier + public int GetHashCode(AMDProfileItem profile) + { + + // Check whether the object is null + if (profile is null) return 0; + + // Get hash code for the ProfileDisplayIdentifiers field if it is not null. + int hashIds = profile.ProfileDisplayIdentifiers == null ? 0 : profile.ProfileDisplayIdentifiers.GetHashCode(); + + // Get hash code for the Paths + int hashProfileData = profile.ProfileData.GetHashCode(); + + //Calculate the hash code for the product. + return (hashIds, hashProfileData).GetHashCode(); + + } + } +} \ No newline at end of file diff --git a/DisplayMagicianShared/DisplayMagicianShared.csproj b/DisplayMagicianShared/DisplayMagicianShared.csproj index 1db0a0c..6f5477d 100644 --- a/DisplayMagicianShared/DisplayMagicianShared.csproj +++ b/DisplayMagicianShared/DisplayMagicianShared.csproj @@ -53,7 +53,9 @@ - + + + True @@ -88,7 +90,6 @@ DisplayView.cs - @@ -155,7 +156,9 @@ True - + + +