From ac5d51bb12a65f257bc7033d2e4bef090d6e2626 Mon Sep 17 00:00:00 2001 From: Terry MacDonald Date: Tue, 22 Jun 2021 21:05:24 +1200 Subject: [PATCH] [WIP] Initial ProfileItem split into libraries This is part of the new strategy to split the ProfileItems into different derived clases with one per Video card technology. The purpose is to allow each video card driver to produce a slightly different profiledata section which is customised to the needs of that video card. This will allieviate the need for us to extend the Path object to support AMD, as we'll be doing the differentiation at each ProfileItem. Time will tell if this is a better strategy or not. This is all to do with my even longer term strategy of devloping video card driver library files inhouse. This strategy was directly created just so that I can make changes in my own code if I need to support some additional features such as HDR support within the profiles. It is very difficult to do this if I'm using another video card library. Much more simple to update my own code! --- DisplayMagicianShared/AMD/AMDLibrary.cs | 38 +- DisplayMagicianShared/AMD/AMDProfileData.cs | 35 - DisplayMagicianShared/AMD/AMDProfileItem.cs | 422 +++++ .../DisplayMagicianShared.csproj | 9 +- DisplayMagicianShared/NVIDIA/NVIDIALibrary.cs | 1543 +++++++++++++++++ .../NVIDIA/NVIDIAProfileItem.cs | 426 +++++ DisplayMagicianShared/ProfileItem.cs | 55 +- DisplayMagicianShared/ProfileRepository.cs | 26 +- .../VideoLibraryProfileData.cs | 14 - 9 files changed, 2466 insertions(+), 102 deletions(-) delete mode 100644 DisplayMagicianShared/AMD/AMDProfileData.cs create mode 100644 DisplayMagicianShared/AMD/AMDProfileItem.cs create mode 100644 DisplayMagicianShared/NVIDIA/NVIDIALibrary.cs create mode 100644 DisplayMagicianShared/NVIDIA/NVIDIAProfileItem.cs delete mode 100644 DisplayMagicianShared/VideoLibraryProfileData.cs 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 - + + +