Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Rgb mittels Asm darstellen (https://www.delphipraxis.net/133524-rgb-mittels-asm-darstellen.html)

thomasku 4. Mai 2009 00:42


Rgb mittels Asm darstellen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,

Ich möchte gern die rgb Funktion mittels assemblercode darstellen.
Delphi-Quellcode:
function farbverlauf1(rot,gruen:integer):TColor;
begin
  if rot < gruen then
    result:=rgb(rot-gruen,0,0)
  else
    result:=rgb(0,gruen-rot,0);
{$R *.dfm}
end;
function farbverlauf2(rot,gruen:integer):TColor;
begin
  ASM
    Mov Eax,rot;     //init
    Mov Edx,gruen;
    CMP Eax,edx;
    jns @kalt;       //rot<gruen
    sub edx,eax;
    Mov result,Eax;
    jmp @weiter;
    @kalt:
      sub edx,eax;
      shl eax,8;
      Mov result,Eax;
    @weiter:
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
Var x,y:integer;
begin
  For x:=0 to 255 do
    For y:=0 to 255 do
      Image1.Canvas.Pixels[x,y]:=farbverlauf2(x,y);
      Image1.Update;
end;
MIt dieser bekomme ich zwar ein ähnliches Ergebnis, allerdings dunkler(wobei beides integer, a 8 Bit sind).
Siehe dazu Bild.
Folgende Funktion hatte ich ursprünglich, hier erhalte ich aber nur einen teil.
Delphi-Quellcode:
function farbverlauf2(rot,gruen:integer):TColor;
begin
  ASM
    Mov Eax,rot;     //init
    Mov Edx,gruen;
    CMP Eax,edx;
    jns @kalt;       //rot<gruen
    sub eax,edx;
    Mov result,Eax;
    jmp @weiter;
    @kalt:
      sub edx,eax;
      shl eax,8;
      Mov result,Eax;
    @weiter:
  end;
end;
Mfg thomas

Medium 4. Mai 2009 04:11

Re: Rgb mittels Asm darstellen
 
Ohne jetzt explizit auf das Problem einzugehen: Wenn es dir hierbei um einen Geschwindigkeitsvorteil geht (und 8 Bit/Kanal ausreichen), sollte es sich für dich lohnen wenn du dir den MMX Befehlssatz mal anschaust.
Mir ist ausserdem gerade schleierhaft inwiefern deine Farbverlaufsmethode sinnvoll eingesetzt werden könnte - darf man fragen wozu du sie brauchst? (Reines Interesse, keine subtile Kritik.)

thomasku 4. Mai 2009 04:23

Re: Rgb mittels Asm darstellen
 
Hallo Medium und vielen Dank,

Nein um Geschwindigkeit oder irgendeinen anderen multimedialen Einsatz geht es mir nicht.
Die Aufgabe habe ich in dieser Art gestellt bekommen. Der Sinn ist die Einbindung von Assemblerbefehlen in Delphi.
Dienen soll es der Darstellung von Temperaturen, rot=warm...

Mfg thomas

Medium 4. Mai 2009 04:27

Re: Rgb mittels Asm darstellen
 
Ahhhh okay, danke :)
Was das Problem an sich angeht... da hätte ich wohl die Nacht besser nicht durchgemacht *hust* :stupid: Ich seh nur noch Matsche aufm Bildschirm, au ha.

jaenicke 4. Mai 2009 05:38

Re: Rgb mittels Asm darstellen
 
Was mir auffällt ist erst einmal: Wozu legst du die Parameter in eax und edx? Da sind die doch eh schon drin...
Mach lieber eine komplette Assemblerroutine draus, dann sparst du dir das.

Zum Fehler:
Delphi-Quellcode:
sub edx,eax;
    Mov result,Eax;
Du subtrahierst von edx (gruen) den Inhalt von eax (rot), also gruen - rot, und das ist dann in edx. Danach packst du den Inhalt von eax (rot) in Result... ;-)
Du hast die Parameter für sub vertauscht. Vor allem machst du ja die selbe Subtraktion für beide Fälle und benutzt danach immer das (unveränderte) eax.

thomasku 4. Mai 2009 06:57

Re: Rgb mittels Asm darstellen
 
Morgen jaenicke und vielen Dank,

Hatte schon im ersten Post sowie in meinem Programm einen Fehler.
rot < gruen => rot>gruen

und mit deinen Tipps, habe ich nun auch das selbige raus.
vollstaendigkeits- halber der Code:
Delphi-Quellcode:
function farbverlauf1(rot,gruen:integer):TColor;
begin
  if rot > gruen then
    result:=rgb(rot-gruen,0,0)
  else
    result:=rgb(0,gruen-rot,0);
{$R *.dfm}
end;
function farbverlauf2(rot,gruen:integer):TColor;
begin
  ASM
    Mov Eax,rot;     //init
    Mov Edx,gruen;
    CMP Eax,edx;
    js @kalt;       //rot<gruen
    sub eax,edx;
    Mov result,Eax;
    jmp @weiter;
    @kalt:
      sub edx,eax;
      shl edx,8;
      Mov result,Edx;
    @weiter:
  end;
end;
Momentan sehe ich zwar noch nicht warum ich nicht die selbe Grafik erhalte, wenn ich wie oben, in farbverlauf1 das Relationszeichen drehe und in farbverlauf2 aus js =>jns mache, allerdings bin ich erstmal sehr froh das es klappt. :lol:

Ich habe keine eigene Routine gemacht, weil ich noch nicht weiß wie dies geht. Ich mache derzeit meine ersten Gehversuche mit der Assemblereinbindung.

Mfg thomas

jaenicke 4. Mai 2009 07:04

Re: Rgb mittels Asm darstellen
 
Schreib das einfach so:
Delphi-Quellcode:
function farbverlauf2(rot, gruen: integer): TColor;
asm
  cmp eax, edx;
  js @kalt;       //rot<gruen
  sub eax, edx;
  jmp @weiter;
  @kalt:
    sub edx, eax;
    shl edx, 8;
    mov eax, edx;
  @weiter:
end;
Die Parameter liegen der Reihe nach in EAX, EDX und ECX, danach auf dem Stack. Das Ergebnis gehört in EAX.

(Ausnahme wäre ein String als Rückgabewert. Dabei wird der String für das Ergebnis wie ein weiterer Parameter übergeben.)

thomasku 4. Mai 2009 07:17

Re: Rgb mittels Asm darstellen
 
Danke nochmal,

Achso dann muss ich wohl leider zugeben, dass ich doch schon einmal etwas davon gehört habe.
(Mit Stackframe bzw ohne, dachte immer mit ist die sichere Variante)
Ich werde mich nochmal intensiver damit beschäftigen.

Mfg thomas

himitsu 4. Mai 2009 08:28

Re: Rgb mittels Asm darstellen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Delphi-Quellcode:
function farbverlauf2(rot,gruen:integer):TColor;
begin
  ASM
    @kalt:
      sub edx,eax;
erstmal das Begin-End ... darum wird doch bestimmt ein "unnötiger" Stackframe erstellt
und durch die nutzung von Result (mittendrin) ebenfalls ... dort wird Result<>EAX bestimmt sein, da zwischendurch eine Temp-Variable für Result eingerichtet und diese erst am Ende nach EAX kopiert wird.

außerdem wozu rechnest du da mit EDX, wo du EDX danach eh nichtmehr verwendest?
bei kalt also überall statt eax ein edx verwenden :zwinker:

und wenn das ASM richtig genutzt würde (ohne delphis Stackframe), dann wäre Mov result,Eax; eh "nutzlos", da Result=EAX.

also ich würde mal stark vermuten, daß 'ne compileroptimierte Variante am Ende sogar schneller/optimaler arbeitet, als dieser ASM-Code.
[add] *ins Bild guck* ... stümmt [/add]

PS: jns @kalt;
im High-Byte ist ein Steurbyte (bei der GDI für die verwendete Farboalette) und keine der Farben Rot oder Grün, also hat dieser Vergleich nichts mit Rot-Grün zu tun.

oben im Bild:
Delphi-Quellcode:
function farbverlauf2(rot, gruen: Integer): TColor;
begin
  if rot < gruen then result := rot - gruen
  else result := (gruen - rot) shl 8;
end;
unten im Bild:
Code:
[b]function[/b] farbverlauf2(rot,gruen:integer):TColor;
[b]begin[/b]
  [b]ASM[/b]
    Mov Eax,rot     //init
    Mov Edx,gruen
    CMP Eax,edx
    jns @kalt      //rot<gruen
    sub eax,edx
    Mov result,Eax
    jmp @weiter
    @kalt:
      sub edx,eax
      shl [color=#ff0000]edx[/color], 8
      Mov result, [color=#ff000]Edx[/color]
    @weiter:
  [b]end;[/b]
[b]end;[/b]
und in einem "neueren" Delphi, wo Inline-Funktionen unterstütz werden, wäre dieses das optimalste, da dort nichtmal erst 'ne Funktion angelegt, sondern der Code direkt an der aufrufenden Stelle eingefügt würde. :angel:
Delphi-Quellcode:
function farbverlauf2(rot, gruen: Integer): TColor; Inline;
begin
  if rot < gruen then result := rot - gruen
  else result := (gruen - rot) shl 8;
end;
[edit]
ups, Bild vergessen :oops:

[add]
und wenn ich mir den Code von jaenicke anseh ... bis auf jmp @weiter;, welches in 'ner kleinem RET kürzer wär ... ist's schonmal ein sehr großer Fortschritt, gegenüber dem "Original" :angel2:


[add2]
was du eigentlich meintest war:
(sobald du für rot und gruen mal 'nen Wert außerhalb von 0..255 übergibst, wirst du den Unterschied erkennen :wink: )
Delphi-Quellcode:
function farbverlauf1(rot, gruen: Byte): TColor;
begin
  if rot < gruen then
    result := rgb(rot - gruen, 0, 0)
  else
    result := rgb(0, gruen - rot, 0);
end;

function farbverlauf2(rot, gruen: Byte): TColor;
ASM
  cmp al, dl
  jns @kalt
  sub al, dl
  and eax, $0000ff
  ret
  @kalt:
  sub eax, edx
  xor eax, eax // statt   and eax, $00ff00
  mov ah, dl
  //and eax, $00ff00
end;

thomasku 7. Mai 2009 09:22

Re: Rgb mittels Asm darstellen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo himitsu und vielen Dank,

ich habe mir ebenfalls mal die Cpu-Fenster meiner Funktion farbverlauf2 (aus Beitrag6)anzeigen lassen. (Vgl Tasm.jpg)
Das sind einmal die Funktion mit Begin und End und das andere mal ohne.
Meiner Meinung nach legen aber beide Funktionen einen Stackframe an.
Delphi-Quellcode:
Mov ebp,esp //lade Stack pointer in Base pointer
Result erzeugt glaube ebenfalls einen;
Delphi-Quellcode:
Add esp, $0c
jedoch sehe ich nicht die Notwendigkeit
(rechte Seite des Bildes) von:
Delphi-Quellcode:
push ecx //ablegen von ecx auf dem stack
Der Result- STackframe dient doch dann der Sicherung, ist er wirklich unnötig?
Zu mind. solange man noch nicht weiß ob der Code funktioniert.
(Ich habe es nicht nur einmal geschafft Delphi zum abstürzen zu bringen :mrgreen: )


Zur Schnelligkeit, es ist wie gesagt nur ein Bsp an den wir den Umgang mit Asm üben sollen.
Woran erkennt man denn, welches Programm schneller arbeitet, ohne explizit zu testen?
Am Umfang der elementar Operationen?

Habe mir auch schon das Tutorial hierzu durchgelesen:
http://www.delphipraxis.net/internal...ct.php?t=94005

An den negativen Werten arbeite ich noch.

Mfg Thomas

himitsu 7. Mai 2009 10:09

Re: Rgb mittels Asm darstellen
 
Das PUSH ECX gehört zum Standardverhallten des Compilers.

Der automatisch erzeugte Eintritts- und Austrittscode:
Delphi-Quellcode:
PUSH   EBP            // Vorhanden wenn Locals <> 0 oder Params <> 0
MOV    EBP, ESP       // Vorhanden wenn Locals <> 0 oder Params <> 0
SUB    ESP, Locals    // Vorhanden wenn Locals <> 0
PUSH   ECX            // -
...
MOV    EAX, [EBP-4]   // Vorhanden wenn nachdem &Result etwas zugewiesen wurde auch noch EAX etwas zugewiesen
                        //   wird, in diesem Fall wird für &Result [EBP-4] statt EAX verwendet - wenn Result <= Integer
POP    ECX            // -
MOV    ESP, EBP       // Vorhanden wenn Locals <> 0
POP    EBP            // Vorhanden wenn Locals <> 0 oder Params <> 0
RET    Params         // Immer vorhanden
Standardmäßig sind, laut Intel-Sepzifikation, EAX, EDX und ECX, sowie die Statusregister frei verfügbar
und alle anderen Register müssen nach der Prozedur/Funktion wieder hergestellt werden.

Allerdings verwendet Delphi das ECX intern für eigene Dinge, weßhalb es dieses sicherheitshalber selber nochmal sichert, da der Programmierer es (laut Spec) ja nicht selber machen muß.

shmia 7. Mai 2009 10:25

Re: Rgb mittels Asm darstellen
 
Mal was Grundsätzliches zum Farbverlauf.
Ein "g'scheite" Funktion zum Berechnen eines Farbverlaufs braucht 3 Parameter:
* Anfangsfarbe
* Endfarbe
* Überblendungsfaktor
Der Überblendungsfaktor könnte ein Double im Bereich 0.0 bis 1.0 oder auch 0% bis 100% sein.
Wenn man Integerarithmetik einsetzen möchte (gerade auch weil man die Funktion in Assembler implementieren will)
dann kann man den Überblendungsfaktor auch von 0 bis 255 (Datentyp Integer) festlegen.

Ich verweise hier mal auf Farbverlauf berechnen.
Du kannst versuchen die Funktion ColorBetween() in Assembler umzusetzen.
Den Aufruf von ColorToRGB() kann man sich schenken, wenn man sicherstellt, dass keine Systemfarben wie z.B. clWindow übergeben werden.
Den Aufruf von GetRValue(), GetGValue() und GetBValue() braucht man auch nicht, wenn man die Farbkomponenten rot, grün und blau direkt aus TColor rausholt.

thomasku 7. Mai 2009 15:35

Re: Rgb mittels Asm darstellen
 
Hallo himitsu und vielen Dank!

Hallo shmia,

habe mich mal daran probiert, scheint aber noch zu schwierig!
Danke aber dafür, ist recht interessant.
Warum darf man keine Systemfarben übergeben bzw warum stören die 2 Nullen?
00XXXXXXX

mal mein bisheriges Ergebnis :oops:
(immerhin werden es schon 2 unterschiedlich gefärbte Vierecke :mrgreen: )
Delphi-Quellcode:
function ColorBetween2(a,b:TColor;c:integer):TColor;
ASM
 // Shl eax,24; //cmp al,$00;
 // cmp ah,$00;
 // je @weiter;

  Sub dl,al;
  Xchg al,dl;
  Mul dl;
  add al,dl;

  Sub dx,ax;
  Xchg ax,dx;
  Mul dx;
  add ax,cx;
  shl ax,8;

  Sub edx,eax;
  Xchg eax,edx;
  Mul edx;
  add eax,ecx;
  shl eax,16;
  Ret;
  //@weiter:;
END;
Mfg Thomas

//Edit also 2 unterschiedliche Vierecke wenn man die Kommentarklammeren entfernt

himitsu 7. Mai 2009 16:08

Re: Rgb mittels Asm darstellen
 
die zwei 00 stören nicht, aber Farben aus gewissen paletten

Delphi-Quellcode:
// Quelle siehe Anhang

Const COLOR_SCROLLBAR = TColorIndex(0);
  COLOR_BACKGROUND   = TColorIndex(1);
  COLOR_ACTIVECAPTION = TColorIndex(2);

  cpSystemPalette    = $00;
  cpActingPalette    = $01;
  cpLogicalPalette   = $02;
  cpNoColor          = $1F;
  cpDefaultColor     = $20;
  cpSystemColor      = $FF;

  clScrollBar        = TColor(cpSystemColor shl 24 or COLOR_SCROLLBAR);
  clBackground       = TColor(cpSystemColor shl 24 or COLOR_BACKGROUND);
  clActiveCaption    = TColor(cpSystemColor shl 24 or COLOR_ACTIVECAPTION);


Function ColorToRGB(Color: TColor): TColor;
  Var _Color: TColorRec Absolute Color;

  Begin
    If _Color.Palette = cpSystemColor Then Result := GetSysColor(Color and $FF) and $FFFFFF
    Else If _Color.Palette in [cpSystemPalette..cpLogicalPalette] Then Result := Color and $FFFFFF
    Else Result := $000000;
  End;
so hat z.B. clBackground den Wert $FF000001 (auch so zu finden in der Unit Graphics von Delphi)

Speziell die Systemfarben sind über ihren Index kodiert und müssen erst entschlüsselt werden.


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:59 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz