Autor Beitrag
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10181
Erhaltene Danke: 1254

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Fr 20.04.12 16:19 
Wie kann man die aktuelle Einstellung der Hardwarebeschleunigung der Grafikkarte ermitteln bzw. ändern?

Leider gibt es dafür keine direkte API in Windows, offensichtlich macht das Kontrollfeld (in XP: Desktop -> Eigenschaften -> Einstellungen -> Erweitert -> Problembehandlung -> Hardwarebeschleunigung) des Explorers das auch direkt in der Registry (dort wird der Wert abgelegt). :? Insofern muss man bei einer "nachgebauten" Lösung immer mit etwas "Raten" leben. :nixweiss:

Folgende Unit kann die aktuelle Einstellung ermitteln, setzen und eine Änderung auch direkt wirksam machen:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
unit UVHWAccel;

// (C) 2012 by Narses, v1.00 vom 20.04.2012

interface

// Registry-Key des primären Display-Devices holen
// ReturnCode:
// Leerstring: Fehler aufgetreten (primäres Device konnte nicht ermittelt werden)
// sonst: der Schlüssel im Hive HKEY_LOCAL_MACHINE zum primären Display-Device
function GetPrimaryDisplayKey(const ForceUpdate: Boolean = FALSE): AnsiString;

// Hardwarebeschleunigungs-Einstellung des aktuellen Videogerätes ermitteln
// Returncode:
// -1: Fehler aufgetreten
//  0: maximale Beschleunigung
//  1: Cursor und BitBlit deaktiviert
//  2: erweiterte Grafik und Cursor deaktiviert
//  3: alle DD-Funktionen und Cursor deaktiviert
//  4: alles ausser Basisbeschleunigung deaktiviert
//  5: alles deaktiviert
function GetHardwareAccelerationLevel: Integer;

// Hardwarebeschleunigungs-Einstellung des aktuellen Videogerätes setzen
// erlaubte Werte siehe oben
// Returncode:
// TRUE: alles OK, FALSE: Fehler aufgetreten, Wert nicht gesetzt
function SetHardwareAccelerationLevel(const NewLevel: Integer): Boolean;

// Display-Einstellungen aktualisieren
// Returncode:
// TRUE: alles OK, FALSE: Fehler aufgetreten
function ForceUpdateDisplaySettings: Boolean;

implementation

uses
  Windows, Registry, SysUtils;

const
  DISPLAY_DEVICE_PRIMARY_DEVICE = DWORD($00000004);

  REG_PATH_VIDEO = AnsiString('\HARDWARE\DEVICEMAP\VIDEO');
  REG_KEY_VIDEO0 = AnsiString('\Device\Video0');
  REG_PREFIX     = AnsiString('\REGISTRY\MACHINE');
  REG_ACCEL_VAL  = AnsiString('Acceleration.Level');

  ENUM_CURRENT_SETTINGS = DWORD(-1); // aus JwaWinUser.pas

type
  // http://msdn.microsoft.com/en-us/library/dd183569(v=vs.85).aspx
  TDisplayDevice = packed record
    cb: DWORD;
    DeviceName: array[0..31of AnsiChar;
    DeviceString: array[0..127of AnsiChar;
    StateFlags: DWORD;
    DeviceID: array[0..127of AnsiChar;
    DeviceKey: array[0..127of AnsiChar;
  end;

var
  PrimaryDisplayKeyCached: AnsiString;

// Import der API-Funktion  
function EnumDisplayDevices(Unused: Pointer; iDevNum: DWORD;
  var lpDisplayDevice: TDisplayDevice; dwFlags: DWORD): BOOL;
  stdcallexternal user32 name 'EnumDisplayDevicesA';

function GetPrimaryDisplayKey(const ForceUpdate: Boolean = FALSE): AnsiString;
  var
    DisplayDevice: TDisplayDevice;
    iDevNum: DWORD;
    Reg: TRegistry;
begin
  if ForceUpdate then
    PrimaryDisplayKeyCached := '';
  if (PrimaryDisplayKeyCached = ''then begin
    // Standard: Registrierungs-Schlüssel per API ermitteln
    DisplayDevice.cb := SizeOf(DisplayDevice);
    iDevNum:= 0;
    // http://msdn.microsoft.com/en-us/library/dd162609(v=vs.85).aspx
    while (PrimaryDisplayKeyCached = ''and EnumDisplayDevices(NIL, iDevNum, DisplayDevice, 0do begin
      if (DisplayDevice.StateFlags and DISPLAY_DEVICE_PRIMARY_DEVICE) <> 0 then
        PrimaryDisplayKeyCached := DisplayDevice.DeviceKey;
        // DisplayDevice.DeviceString -> da steht der Klartextname drin
      Inc(iDevNum);
    end;
    // Backup: Schlüssel aus Device \Video0 nehmen, wenn vorhanden
    if (PrimaryDisplayKeyCached = ''then begin
      Reg := TRegistry.Create(KEY_READ);
      try
        try
          Reg.RootKey := HKEY_LOCAL_MACHINE;
          if Reg.OpenKey(REG_PATH_VIDEO, FALSE) then
            PrimaryDisplayKeyCached := Reg.ReadString(REG_KEY_VIDEO0);
        finally
          Reg.Free;
        end;
      except
        PrimaryDisplayKeyCached := '';
      end;
    end;
    // Nacharbeiten: das Dummy-Prefix am Anfang entfernen
    if (UpperCase(Copy(PrimaryDisplayKeyCached, 1, Length(REG_PREFIX))) = REG_PREFIX) then
      Delete(PrimaryDisplayKeyCached, 1, Length(REG_PREFIX));
  end;
  Result := PrimaryDisplayKeyCached;
end;

function GetHardwareAccelerationLevel: Integer;
  var
    Reg: TRegistry;
begin
  Result := -1// ERROR
  if (PrimaryDisplayKeyCached = ''then
    GetPrimaryDisplayKey;
  if (PrimaryDisplayKeyCached <> ''then begin
    Reg := TRegistry.Create(KEY_READ);
    try
      Reg.RootKey := HKEY_LOCAL_MACHINE;
      if Reg.OpenKey(PrimaryDisplayKeyCached, FALSE) then begin
        if Reg.ValueExists(REG_ACCEL_VAL) then
          Result := Reg.ReadInteger(REG_ACCEL_VAL)
        else
          Result := 0// Default, wenn Wert fehlt
      end
    finally
      Reg.Free;
    end;
  end;
end;

function SetHardwareAccelerationLevel(const NewLevel: Integer): Boolean;
  var
    Reg: TRegistry;
begin
  Result := FALSE; // ERROR
  if (PrimaryDisplayKeyCached = ''then
    GetPrimaryDisplayKey;
  if (PrimaryDisplayKeyCached <> ''then begin
    Reg := TRegistry.Create;
    try
      Reg.RootKey := HKEY_LOCAL_MACHINE;
      if Reg.OpenKey(PrimaryDisplayKeyCached, FALSE) then begin
        if (NewLevel = 0then begin
          Reg.DeleteValue(REG_ACCEL_VAL);
          Result := TRUE;
        end
        else if (NewLevel in [1..5]) then begin
          Reg.WriteInteger(REG_ACCEL_VAL, NewLevel);
          Result := TRUE;
        end;
      end
    finally
      Reg.Free;
    end;
  end;
end;

function ForceUpdateDisplaySettings: Boolean;
  var
    DevMode: TDevMode;
begin
  // http://msdn.microsoft.com/en-us/library/dd162611(v=vs.85).aspx
  Result := EnumDisplaySettings(NIL, ENUM_CURRENT_SETTINGS, DevMode);
  if Result then
    // http://msdn.microsoft.com/en-us/library/dd183411(v=vs.85).aspx
    ChangeDisplaySettings(DevMode, CDS_RESET);
end;

initialization
  PrimaryDisplayKeyCached := '';

end.
Anmerkungen:
  • Die Identifikation des primären Display-Devices erfolgt im Wesentlichen über die Funktion EnumDisplayDevices, die mittlerweile auch den Registrierungsschlüssel des entsprechenden Gerätes liefert (seit wann, weiß ich leider nicht). Wenn das primäre Device nicht auf diesem Wege ermittelt werden kann, wird manuell unter \\HKLM\HARDWARE\DEVICEMAP\VIDEO\Device\Video0 in der Registrierung gesucht, was aber leider nicht immer funktioniert, da es von dem Treiber abhängt, wie das Device dort eingetragen wird. Es ist also prinzipiell möglich, dass die Funktionen der Unit nicht genutzt werden können, weil der Registrierungs-Schlüssel des primären Devices nicht gefunden wurde.
  • Bisher getestet unter Win XP prof sp3, weitere Testergebnisse sind willkommen

Benutzung:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
uses
  ..., UVHWAccel;

  var
    i: Integer;
begin
  i := GetHardwareAccelerationLevel;
  if (i >= 0then
    ShowMessage(IntToStr(i))
  else
    ShowMessage('Fehler!');
end;

begin
  if SetHardwareAccelerationLevel(0then // max. Beschleunigung
    ForceUpdateDisplaySettings // Änderung aktivieren
  else
    ShowMessage('Fehler!');

Im Anhang befindet sich eine Demo-Anwendung mit Quelltext.

Als kleine Spezial-Zugabe hängt auch noch ein Kommandozeilenutility (mit Quelltext) dran, so dass man die Funktionalität direkt fertig gekapselt nutzen kann. ;)

Warum braucht man das überhaupt? :gruebel:
Leider kommt es unter bestimmten Umständen zu einer Fehlersituation bei Fernwartungs-Programmen (z.B. NetOp, VNC, etc.) und Java-Anwendungen: der Inhalt eines Java-Fensters wird in der Fernwartung nicht angezeigt (leer oder schwarz), da die Java-Laufzeitumgebung irgendwelche Probleme mit dem Grafiktreiber hat (die Details führen hier wirklich zu weit, da schieben sich auch die Beteiligten gegenseitig den Schwarzen Peter zu, die (vor allem Onboard-)Treiber-Hersteller sagen, dass Java-Framework ist "kaputt", die Java-Leute sagen, der Treiber ist "kaputt", *seufz*). Wenn man dann die Hardwarebeschleunigung runterdreht, so dass die DD-Funktionen von Java nicht mehr verwendet werden, ist der Inhalt der Java-Fenster wieder in der Fernwartung sichtbar. :idea:


HWAccel.zip  (3.31 KB) Download (Rev 0)
 (751x, 751x gesamt)
Beschreibung: Demo-Projekt mit Quelltext (D7pro)
vhwautil.zip  (50.94 KB) Download (Rev 0)
 (1451x, 1451x gesamt)
Beschreibung: Kommandozeilen-Utility mit Quelltext und Binary
_________________
There are 10 types of people - those who understand binary and those who don´t.