|
@@ -0,0 +1,337 @@
|
|
|
+using System;
|
|
|
+using System.IO;
|
|
|
+using System.IO.MemoryMappedFiles;
|
|
|
+using System.Runtime.InteropServices;
|
|
|
+using System.Threading;
|
|
|
+
|
|
|
+namespace GpuFanControl.MsiAfterburnerWrap
|
|
|
+{
|
|
|
+ using ShareMemoryStructs;
|
|
|
+
|
|
|
+ namespace ShareMemoryStructs
|
|
|
+ {
|
|
|
+ [Serializable]
|
|
|
+ public struct MACM_SHARED_MEMORY_HEADER
|
|
|
+ {
|
|
|
+ public uint signature;
|
|
|
+ public uint version;
|
|
|
+ public uint headerSize;
|
|
|
+ public uint gpuEntryCount;
|
|
|
+ public uint gpuEntrySize;
|
|
|
+ public uint masterGpu;
|
|
|
+ public MACM_SHARED_MEMORY_FLAG flags;
|
|
|
+ public uint time;
|
|
|
+ public MACM_SHARED_MEMORY_COMMAND command;
|
|
|
+ }
|
|
|
+
|
|
|
+ [Flags]
|
|
|
+ public enum MACM_SHARED_MEMORY_FLAG : uint
|
|
|
+ {
|
|
|
+ None = 0,
|
|
|
+ LINK = 1,
|
|
|
+ SYNC = 2,
|
|
|
+ THERMAL = 4,
|
|
|
+ }
|
|
|
+
|
|
|
+ [Flags]
|
|
|
+ public enum MACM_SHARED_MEMORY_COMMAND : uint
|
|
|
+ {
|
|
|
+ None = 0,
|
|
|
+ INIT = 11206656, // 0x00AB0000
|
|
|
+ FLUSH = 11206657, // 0x00AB0001
|
|
|
+ }
|
|
|
+
|
|
|
+ [Serializable]
|
|
|
+ public struct MACM_SHARED_MEMORY_GPU_ENTRY
|
|
|
+ {
|
|
|
+ public MACM_SHARED_MEMORY_GPU_ENTRY_FLAG flags;
|
|
|
+ public uint coreClockCur;
|
|
|
+ public uint coreClockMin;
|
|
|
+ public uint coreClockMax;
|
|
|
+ public uint coreClockDef;
|
|
|
+ public uint shaderClockCur;
|
|
|
+ public uint shaderClockMin;
|
|
|
+ public uint shaderClockMax;
|
|
|
+ public uint shaderClockDef;
|
|
|
+ public uint memoryClockCur;
|
|
|
+ public uint memoryClockMin;
|
|
|
+ public uint memoryClockMax;
|
|
|
+ public uint memoryClockDef;
|
|
|
+ public uint fanSpeedCur;
|
|
|
+ public MACM_SHARED_MEMORY_GPU_ENTRY_FAN_FLAG fanFlagsCur;
|
|
|
+ public uint fanSpeedMin;
|
|
|
+ public uint fanSpeedMax;
|
|
|
+ public uint fanSpeedDef;
|
|
|
+ public MACM_SHARED_MEMORY_GPU_ENTRY_FAN_FLAG fanFlagsDef;
|
|
|
+ public uint coreVoltageCur;
|
|
|
+ public uint coreVoltageMin;
|
|
|
+ public uint coreVoltageMax;
|
|
|
+ public uint coreVoltageDef;
|
|
|
+ public uint memoryVoltageCur;
|
|
|
+ public uint memoryVoltageMin;
|
|
|
+ public uint memoryVoltageMax;
|
|
|
+ public uint memoryVoltageDef;
|
|
|
+ public uint auxVoltageCur;
|
|
|
+ public uint auxVoltageMin;
|
|
|
+ public uint auxVoltageMax;
|
|
|
+ public uint auxVoltageDef;
|
|
|
+ public int coreVoltageBoostCur;
|
|
|
+ public int coreVoltageBoostMin;
|
|
|
+ public int coreVoltageBoostMax;
|
|
|
+ public int coreVoltageBoostDef;
|
|
|
+ public int memoryVoltageBoostCur;
|
|
|
+ public int memoryVoltageBoostMin;
|
|
|
+ public int memoryVoltageBoostMax;
|
|
|
+ public int memoryVoltageBoostDef;
|
|
|
+ public int auxVoltageBoostCur;
|
|
|
+ public int auxVoltageBoostMin;
|
|
|
+ public int auxVoltageBoostMax;
|
|
|
+ public int auxVoltageBoostDef;
|
|
|
+ public int powerLimitCur;
|
|
|
+ public int powerLimitMin;
|
|
|
+ public int powerLimitMax;
|
|
|
+ public int powerLimitDef;
|
|
|
+ public int coreClockBoostCur;
|
|
|
+ public int coreClockBoostMin;
|
|
|
+ public int coreClockBoostMax;
|
|
|
+ public int coreClockBoostDef;
|
|
|
+ public int memoryClockBoostCur;
|
|
|
+ public int memoryClockBoostMin;
|
|
|
+ public int memoryClockBoostMax;
|
|
|
+ public int memoryClockBoostDef;
|
|
|
+ public int thermalLimitCur;
|
|
|
+ public int thermalLimitMin;
|
|
|
+ public int thermalLimitMax;
|
|
|
+ public int thermalLimitDef;
|
|
|
+ public uint thermalPrioritizeCur;
|
|
|
+ public uint thermalPrioritizeDef;
|
|
|
+ }
|
|
|
+
|
|
|
+ [Flags]
|
|
|
+ public enum MACM_SHARED_MEMORY_GPU_ENTRY_FLAG : uint
|
|
|
+ {
|
|
|
+ None = 0,
|
|
|
+ CORE_CLOCK = 1,
|
|
|
+ SHADER_CLOCK = 2,
|
|
|
+ MEMORY_CLOCK = 4,
|
|
|
+ FAN_SPEED = 8,
|
|
|
+ CORE_VOLTAGE = 16, // 0x00000010
|
|
|
+ MEMORY_VOLTAGE = 32, // 0x00000020
|
|
|
+ AUX_VOLTAGE = 64, // 0x00000040
|
|
|
+ CORE_VOLTAGE_BOOST = 128, // 0x00000080
|
|
|
+ MEMORY_VOLTAGE_BOOST = 256, // 0x00000100
|
|
|
+ AUX_VOLTAGE_BOOST = 512, // 0x00000200
|
|
|
+ POWER_LIMIT = 1024, // 0x00000400
|
|
|
+ CORE_CLOCK_BOOST = 2048, // 0x00000800
|
|
|
+ MEMORY_CLOCK_BOOST = 4096, // 0x00001000
|
|
|
+ THERMAL_LIMIT = 8192, // 0x00002000
|
|
|
+ THERMAL_PRIORITIZE = 16384, // 0x00004000
|
|
|
+ SYNCHRONIZED_WITH_MASTER = 2147483648, // 0x80000000
|
|
|
+ }
|
|
|
+
|
|
|
+ [Flags]
|
|
|
+ public enum MACM_SHARED_MEMORY_GPU_ENTRY_FAN_FLAG : uint
|
|
|
+ {
|
|
|
+ None = 0,
|
|
|
+ AUTO = 1,
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ internal class MsiAfterBurnControlWrap
|
|
|
+ {
|
|
|
+ //const
|
|
|
+ private const string ShareMemoryName = "MACMSharedMemory";
|
|
|
+
|
|
|
+ private const string MutexName = "Global\\Access_MACMSharedMemory";
|
|
|
+ private const uint HeaderSignature = ('M' << 24 | ('A' << 16) | ('C' << 8) | ('M'));
|
|
|
+
|
|
|
+ private MemoryMappedFile _hMapFile;
|
|
|
+ private MemoryMappedViewStream _pMapAddr;
|
|
|
+
|
|
|
+ private byte[] _bufSnap;
|
|
|
+
|
|
|
+ public void Connect()
|
|
|
+ {
|
|
|
+ //connect , failure throws FileNotFoundException
|
|
|
+ _hMapFile = MemoryMappedFile.OpenExisting(ShareMemoryName, MemoryMappedFileRights.FullControl);
|
|
|
+ _pMapAddr = _hMapFile.CreateViewStream();
|
|
|
+ //var x_pMapAddr = _hMapFile.CreateViewAccessor();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Disconnect()
|
|
|
+ {
|
|
|
+ _pMapAddr?.Close();
|
|
|
+ _hMapFile?.Dispose();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Refresh()
|
|
|
+ {
|
|
|
+ using (var m = new Mutex(false, MutexName))
|
|
|
+ {
|
|
|
+ m.WaitOne();
|
|
|
+
|
|
|
+ var lenHeader = Marshal.SizeOf(typeof(MACM_SHARED_MEMORY_HEADER));
|
|
|
+ var bufHeader = new byte[lenHeader];
|
|
|
+
|
|
|
+ _pMapAddr.Seek(0, SeekOrigin.Begin);
|
|
|
+ _pMapAddr.Read(bufHeader, 0, lenHeader);
|
|
|
+
|
|
|
+ var stHeader = ByteArrayToStruct<MACM_SHARED_MEMORY_HEADER>(bufHeader);
|
|
|
+ if (stHeader.signature == HeaderSignature)
|
|
|
+ {
|
|
|
+ var lenSnap = stHeader.headerSize + stHeader.gpuEntryCount * stHeader.gpuEntrySize;
|
|
|
+
|
|
|
+ var bufSnap = new byte[lenSnap];
|
|
|
+
|
|
|
+ _pMapAddr.Seek(0, SeekOrigin.Begin);
|
|
|
+ _pMapAddr.Read(bufSnap, 0, (int)lenSnap);
|
|
|
+ _bufSnap = bufSnap;
|
|
|
+ }
|
|
|
+ m.ReleaseMutex();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void Commit()
|
|
|
+ {
|
|
|
+ using (var m = new Mutex(false, MutexName))
|
|
|
+ {
|
|
|
+ m.WaitOne();
|
|
|
+
|
|
|
+ _pMapAddr.Seek(0, SeekOrigin.Begin);
|
|
|
+ _pMapAddr.Write(_bufSnap, 0, _bufSnap.Length);
|
|
|
+ _pMapAddr.Flush();
|
|
|
+
|
|
|
+ _pMapAddr.Seek(0, SeekOrigin.Begin);
|
|
|
+ var header = ByteArrayToStruct<MACM_SHARED_MEMORY_HEADER>(_bufSnap);
|
|
|
+ header.command = MACM_SHARED_MEMORY_COMMAND.FLUSH;
|
|
|
+ StructToByteArray(header, _bufSnap);
|
|
|
+
|
|
|
+ _pMapAddr.Seek(0, SeekOrigin.Begin);
|
|
|
+ _pMapAddr.Write(_bufSnap, 0, _bufSnap.Length);
|
|
|
+ _pMapAddr.Flush();
|
|
|
+
|
|
|
+ m.ReleaseMutex();
|
|
|
+ }
|
|
|
+
|
|
|
+ Refresh();
|
|
|
+ }
|
|
|
+
|
|
|
+ public int GetNumberOfGpu()
|
|
|
+ {
|
|
|
+ var st = ByteArrayToStruct<MACM_SHARED_MEMORY_HEADER>(_bufSnap);
|
|
|
+ return (int)st.gpuEntryCount;
|
|
|
+ }
|
|
|
+
|
|
|
+ public MACM_SHARED_MEMORY_GPU_ENTRY? GetGpuEntry(int index, out string error)
|
|
|
+ {
|
|
|
+ var header = ByteArrayToStruct<MACM_SHARED_MEMORY_HEADER>(_bufSnap);
|
|
|
+ if (index > header.gpuEntryCount || index < 0)
|
|
|
+ {
|
|
|
+ error = "index out of range";
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ var entry = ByteArrayToStruct<MACM_SHARED_MEMORY_GPU_ENTRY>(_bufSnap, (int)header.headerSize + index * (int)header.gpuEntrySize);
|
|
|
+
|
|
|
+ error = null;
|
|
|
+ return entry;
|
|
|
+ }
|
|
|
+
|
|
|
+ public string SetGpuEntry(MACM_SHARED_MEMORY_GPU_ENTRY entry, int index, bool flush = false)
|
|
|
+ {
|
|
|
+ var header = ByteArrayToStruct<MACM_SHARED_MEMORY_HEADER>(_bufSnap);
|
|
|
+ if (index > header.gpuEntryCount || index < 0) return "index out of range";
|
|
|
+
|
|
|
+ StructToByteArray(entry, _bufSnap, (int)(header.headerSize + index * header.gpuEntrySize));
|
|
|
+
|
|
|
+ if (flush) Commit();
|
|
|
+
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private T ByteArrayToStruct<T>(byte[] bytes, int offset = 0)
|
|
|
+ {
|
|
|
+ GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
|
|
|
+ T stuff;
|
|
|
+ try
|
|
|
+ {
|
|
|
+ stuff = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject() + offset, typeof(T));
|
|
|
+ }
|
|
|
+ finally
|
|
|
+ {
|
|
|
+ handle.Free();
|
|
|
+ }
|
|
|
+ return stuff;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void StructToByteArray<T>(T str, byte[] snap, int offset = 0)
|
|
|
+ {
|
|
|
+ var h = default(GCHandle);
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ h = GCHandle.Alloc(snap, GCHandleType.Pinned);
|
|
|
+
|
|
|
+ Marshal.StructureToPtr<T>(str, h.AddrOfPinnedObject() + offset, false);
|
|
|
+ }
|
|
|
+ finally
|
|
|
+ {
|
|
|
+ if (h.IsAllocated)
|
|
|
+ {
|
|
|
+ h.Free();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ internal class TryingSandBox
|
|
|
+ {
|
|
|
+ public static void Go()
|
|
|
+ {
|
|
|
+ var ctl = new MsiAfterBurnControlWrap();
|
|
|
+ ctl.Connect();
|
|
|
+ ctl.Refresh();
|
|
|
+
|
|
|
+ var numberOfGpu = ctl.GetNumberOfGpu();
|
|
|
+
|
|
|
+ for (int i = 0; i < numberOfGpu; i++)
|
|
|
+ {
|
|
|
+ Console.WriteLine($"Get entry of GPU #{i}");
|
|
|
+
|
|
|
+ MACM_SHARED_MEMORY_GPU_ENTRY? g;
|
|
|
+ {
|
|
|
+ g = ctl.GetGpuEntry(i, out string err);
|
|
|
+ if (g.HasValue == false)
|
|
|
+ {
|
|
|
+ Console.WriteLine($"Err:{err}");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ var entry = g.Value;
|
|
|
+ if (entry.flags.HasFlag(MACM_SHARED_MEMORY_GPU_ENTRY_FLAG.FAN_SPEED))
|
|
|
+ {
|
|
|
+ Console.WriteLine($"Updating fan speed of GPU #{i}");
|
|
|
+
|
|
|
+ //entry.fanFlagsCur = MACM_SHARED_MEMORY_GPU_ENTRY_FAN_FLAG.AUTO;
|
|
|
+
|
|
|
+ entry.fanFlagsCur = MACM_SHARED_MEMORY_GPU_ENTRY_FAN_FLAG.None;
|
|
|
+ entry.fanSpeedCur = entry.fanSpeedMax;
|
|
|
+
|
|
|
+
|
|
|
+ var err=ctl.SetGpuEntry(entry, i);
|
|
|
+ if(err!=null) Console.WriteLine($"Err: {err}");
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Console.WriteLine($"Err: No support fan speed");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Console.WriteLine("Commiting...");
|
|
|
+ ctl.Commit();
|
|
|
+ Console.WriteLine("Success");
|
|
|
+
|
|
|
+ ctl.Disconnect();
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|