Bresenham line routine for the linear framebuffer with 8 bpp
Verfasst: Di 25. Mär 2014, 09:00
Moin.
Ich habe meine Linien-Routine überarbeitet und hier ist das Ergebniss:
Im Anschluss zeige ich wohl besser auch mal wie man die Linen-Routine verwenden kann:
Die Linien-Routine sollte ersatzweise auch für den 32 Bit-Mode verwendet werden könnnen. (Noch nicht getestet.)
In diesem Fall wird der Operationscode der Linien-Routine noch um einige Bytes weniger gross werden, weil die Operandsize- und Adresssize-Prefixe dann nicht benötigt beim Assemblieren vom Assembler weggelassen werden.
Weitere Geschwindigkeits-Optimierung:
Je nachdem ob die Routine für den 16 Bitmode, oder den 32 Bitmode assembliert wird ändern sich innerhalb der Routine auch die Sprungadresse der bedingten Verzweigungsbefehle(conditional jumps). Damit die jeweilige Sprungadresse der dortigen Sprungbefehle bestenfalls auf eine durch 16 teilbare Adresse zielt und um Abhängigkeiten zwischen den Befehlen untereinander zu minimieren, könnte man für eine Geschwindigkeit-Optimierung einige NOP-Befehle zwischen den Befehlen einfügen. Jede Sprungadresse sollte dann dadurch auf eine durch 16 teilbare Adresse ausgerichtet sein.
Um Abhängigkeiten unter den Befehlen zu minimieren ist darauf zu achten das Befehle bei denen beispielsweise zuerst ein Register mit einem Wert beschrieben wurde, das dieses Register danach nicht gleich wieder ausgelesen wird. Weil sonst kommt es zu einer Ausführungsverzögerung der Befehle. Ein Schreibzugriff auf ein Registers nach einem Lesezugriff auf ein Registers macht keine Probleme, sondern nur Lesezugriffe nach dem vorherigen Schreibzugriff auf ein Register.
Beispiele:
Optimierung:
Dirk
Ich habe meine Linien-Routine überarbeitet und hier ist das Ergebniss:
Code: Alles auswählen
;--------------------------------------------------------
; This is a Bresenham line subroutine for videomodes
: with 255 colors using the linear framebuffer(LFB).
;
; This routine need an address table of startaddresses
; of each scanline of the LFB placed in the beginning
; of a data segment at OFFSET 0000.
;
; The first entry of this address table have to be
; the address of the LFB itself. And for all next
; entries we have to add the bytes of the scanline
; of the used resolution, so that every entry in
; this address table represent the startaddress
; of each line on the screen.
;
; The start- and end-coordinates + the color of the
; Line have to be placed in the following registers
; Startpoint:EBX,ESI Endpoint:ECX,EDI Color:AL
;--------------------------------------------------------
LINE: mov edx, edi
sub ecx, ebx
jl T0
add ebx, [esi*4]
sub edx, esi
jl T1
mov esi, DWORD PTR[XMP1]
cmp ecx, edx
jl T2
lea edx, [edx+edx]
mov ebp, edx
sub edx, ecx
mov edi, edx
sub edx, ecx
;-------------------------------------
M00: mov [ebx], al
and edi, edi
jge short M01
lea ebx, [ebx+1]
lea edi, [edi+ebp]
dec ecx
jnz M00
ret
;-------------------------------------
M01: lea ebx, [ebx+esi]
lea edi, [edi+edx]
dec ecx
jnz M00
ret
;-----------------------------------------------------
T0: neg ecx
add ebx, [esi*4]
sub edx, esi
mov esi, DWORD PTR[XMP1]
jl T01
mov esi, DWORD PTR[XMM1]
cmp ecx, edx
jl short T21
lea edx, [edx+edx]
mov ebp, edx
sub edx, ecx
mov edi, edx
sub edx, ecx
;-------------------------------------
M02: mov [ebx], al
and edi, edi
jge short M03
lea ebx, [ebx-1]
lea edi, [edi+ebp]
dec ecx
jnz M02
ret
;-------------------------------------
M03: lea ebx, [ebx+esi]
lea edi, [edi+edx]
dec ecx
jnz M02
ret
;-----------------------------------------------------
T21: lea ecx, [ecx+ecx]
mov ebp, ecx
sub ecx, edx
mov edi, ecx
sub ecx, edx
;-------------------------------------
M04: mov [ebx], al
and edi, edi
jge short M05
add ebx, DWORD PTR[XMAX]
lea edi, [edi+ebp]
dec edx
jnz M04
ret
;-------------------------------------
M05: lea ebx, [ebx+esi]
lea edi, [edi+ecx]
dec edx
jnz M04
ret
;-----------------------------------------------------
T01: neg edx
cmp ecx, edx
jl short T22
lea edx, [edx+edx]
mov ebp, edx
sub edx, ecx
mov edi, edx
sub edx, ecx
;-------------------------------------
M06: mov [ebx], al
and edi, edi
jge short M07
lea ebx, [ebx-1]
lea edi, [edi+ebp]
dec ecx
jnz M06
ret
;-------------------------------------
M07: sub ebx, esi
lea edi, [edi+edx]
dec ecx
jnz M06
ret
;-----------------------------------------------------
T22: lea ecx, [ecx+ecx]
mov ebp, ecx
sub ecx, edx
mov edi, ecx
sub ecx, edx
;-------------------------------------
M08: mov [ebx], al
and edi, edi
jge short M09
sub ebx, DWORD PTR[XMAX]
lea edi, [edi+ebp]
dec edx
jnz M08
ret
;-------------------------------------
M09: sub ebx, esi
lea edi, [edi+ecx]
dec edx
jnz M08
ret
;-----------------------------------------------------
T1: neg edx
mov esi, DWORD PTR[XMM1]
cmp ecx, edx
jl T12
lea edx, [edx+edx]
mov ebp, edx
sub edx, ecx
mov edi, edx
sub edx, ecx
;-------------------------------------
M10: mov [ebx], al
and edi, edi
jge short M11
lea ebx, [ebx+1]
lea edi, [edi+ebp]
dec ecx
jnz M10
ret
;-------------------------------------
M11: sub ebx, esi
lea edi, [edi+edx]
dec ecx
jnz M10
ret
;-----------------------------------------------------
T12: lea ecx, [ecx+ecx]
mov ebp, ecx
sub ecx, edx
mov edi, ecx
sub ecx, edx
;-------------------------------------
M12: mov [ebx], al
and edi, edi
jge short M13
sub ebx, DWORD PTR[XMAX]
lea edi, [edi+ebp]
dec edx
jnz M12
ret
;-------------------------------------
M13: sub ebx, esi
lea edi, [edi+ecx]
dec edx
jnz M12
ret
;-----------------------------------------------------
T2: lea ecx, [ecx+ecx]
mov ebp, ecx
sub ecx, edx
mov edi, ecx
sub ecx, edx
;-------------------------------------
M14: mov [ebx], al
and edi, edi
jge short M15
add ebx, DWORD PTR[XMAX]
lea edi, [edi+ebp]
dec edx
jnz M14
ret
;-------------------------------------
M15: lea ebx, [ebx+esi]
lea edi, [edi+ecx]
dec edx
jnz M14
ret
;-----------------------------------------------------
; Copyfree for all humans on planet earth
;-----------------------------------------------------
Code: Alles auswählen
;----------------------------
; Example for to draw a line using a VBE videomode with a horizontal resolution
; of 1920 and a vertical resolution of 1200 with 255 colors and 8 bit per pixel.
; (Hint: This example shows only wich instruction and data is needed for to use
; the line routine and the code have to be placed inside of a working application.)
;----------------------------
RES_X = 1920 ; horizontal resolution
RES_Y = 1200 ; vertical resolution
Color = 0Eh
;----------------------------
.DATA
;----
; This following table of LFB startaddresses of each line
; have to be placed at offset 0000 in the data segment
;----
PIXTAB DD RES_Y dup (0) ; table of startaddresses (for to draw the line)
XMAX DD 0 ; ScanLine (for to draw the line)
XMP1 DD 0 ; ScanLine + 1 (for to draw the line)
XMM1 DD 0 ; ScanLine - 1 (for to draw the line)
;----
VBEINFO DB 512 dup (0) ; Buffer for VBE 4F00 Vbe Info Block
MODEINFO DB 256 dup (0) ; Buffer for VBE 4F01 Mode Info Block
;----------------------------
.code
mov ax, @DATA ; segment address of the data segment
mov ds, ax
mov es, ax
mov di, OFFSET VBEINFO ; get the Vbe Info Block
mov ax, 4F00h ; es:di 512 byte
int 10h : Function 00h - Return VBE Controller Information
cmp ax, 4Fh
jnz ERROR ; need instructions for output an Error message + terminate program
mov dl, [di+5] ; major version number of VBE
cmp dl, 2 ; version 2?
jb ERROR
; Get the VBE modenumber from the VBE modetable
lfs si, [di+0Eh] ; VbeFarPtr to VideoModeList
GETMode: mov cx, fs:[si] ; get the mode number
lea si, [si+2]
cmp cx, 0FFFFh ; end of modelist ?
jz ERROR
add cx, 4000h ; mode number + linear acess
mov di, OFFSET MODEINFO
mov ax, 4F01h ; get the Mode Info Block
int 10h ; Function 01h - Return VBE Mode Information
cmp ax, 4Fh
jnz ERROR
; Now we have to find the mode number wich operate with our desired resolution
cmp WORD PTR[di+12h], RES_X ; horizontal resolution in pixels
jnz GETMode
cmp WORD PTR[di+14h], RES_Y ; vertical resolution in pixels
jnz GETMode
cmp BYTE PTR[di+19h], 8 ; bits per pixel
jnz GETMode
test WORD PTR[di], 80h ; Linear frame buffer mode
jz GETMode
cmp DWORD PTR[di+28h], 0 ; physical address for flat memory frame buffer
jz GETMode
; Set the VBE mode
mov ax, 4F02h
mov bx, cx ; modenumber
int 10h
cmp ax, 4Fh
jnz ERROR
; create a table of start addresses of each line on the screen
mov si, OFFSET MODEINFO
xor ebx, ebx
mov bx, ds
mov eax, [si+28h] ; Address of the LFB
shl ebx, 4
sub eax, ebx ; LFB = ds:reg32
xor edx, edx
mov dx, [si+32h] ; LinBytesPerScanLine
mov DWORD PTR[XMAX], edx
mov ebx, edx
inc ebx
mov DWORD PTR[XMP1], ebx ; LinBytesPerScanLine + 1
sub ebx, 2
mov DWORD PTR[XMM1], ebx ; LinBytesPerScanLine - 1
xor ecx, ecx
mov cx, [si+14h] ; vertical resolution in pixels
shl ecx, 2 ; vertical resolution in pixels * 4
xor edi, edi ; OFFSET 0000
AGAIN: mov [di], eax ; fill the address table
add edi, 4
add eax, edx ; plus scanline
cmp edi, ecx ; vertical resolution in pixels * 4 ?
jb AGAIN
;-----------
; ---- Switching to the BIG-REALMODE ----
; enhance "DS"-segment up to 4 GB + enable A20 address line
call BIGREALMODE ; this subroutine is not a part of this example
;-----------
; Drawing a line from the upper left corner to the lower right corner
; of the screen using a resolution of 1920 x 1200 with 8 bit color.
; Make sure that the coordinates of the start and end parameter for the
; line routine do not exceed the size of the horizontal and vertical
; resolution minus one. The maximum x/y coordinates have to be one times
; lower as the resolution size. For the resolution of 1920x1200 the highest
; coordinates are X=1919 Y=1199.
mov ebx, 0 ; X1-Position
mov esi, 0 ; Y1-Position
mov ecx, 1919 ; X2-Position
mov edi, 1199 ; Y2-Position
mov al, Color
call LINE
;-----------
In diesem Fall wird der Operationscode der Linien-Routine noch um einige Bytes weniger gross werden, weil die Operandsize- und Adresssize-Prefixe dann nicht benötigt beim Assemblieren vom Assembler weggelassen werden.
Weitere Geschwindigkeits-Optimierung:
Je nachdem ob die Routine für den 16 Bitmode, oder den 32 Bitmode assembliert wird ändern sich innerhalb der Routine auch die Sprungadresse der bedingten Verzweigungsbefehle(conditional jumps). Damit die jeweilige Sprungadresse der dortigen Sprungbefehle bestenfalls auf eine durch 16 teilbare Adresse zielt und um Abhängigkeiten zwischen den Befehlen untereinander zu minimieren, könnte man für eine Geschwindigkeit-Optimierung einige NOP-Befehle zwischen den Befehlen einfügen. Jede Sprungadresse sollte dann dadurch auf eine durch 16 teilbare Adresse ausgerichtet sein.
Um Abhängigkeiten unter den Befehlen zu minimieren ist darauf zu achten das Befehle bei denen beispielsweise zuerst ein Register mit einem Wert beschrieben wurde, das dieses Register danach nicht gleich wieder ausgelesen wird. Weil sonst kommt es zu einer Ausführungsverzögerung der Befehle. Ein Schreibzugriff auf ein Registers nach einem Lesezugriff auf ein Registers macht keine Probleme, sondern nur Lesezugriffe nach dem vorherigen Schreibzugriff auf ein Register.
Beispiele:
Code: Alles auswählen
mov edi, edx ; Zuerst: Lesezugriff auf EDX
sub edx, ecx ; unmittelbar danach: Schreibzugriff auf EDX = keine Verzögerung
Code: Alles auswählen
lea edx, [edx+edx] ; Zuerst: Schreibzugriff auf EDX
mov ebp, edx ; unmittelbar danach: Lesezugriff auf EDX = Verzögerung
Code: Alles auswählen
lea edx, [edx+edx] ; Schreibzugriff auf EDX
nop
mov ebp, edx ; Lesezugriff auf EDX = keine (oder geringere) Verzögerung