Начнем с переписывания подпрограммы DrawPixel . В настоящее время это немного беспорядок!
Нет смысла использовать инструкцию mul
, которая без надобности затирает регистр EDX
. Лучше использовать вариант imul
.
И вместо использования mov eax, 0
lea eax, [si]
для загрузки регистра EAX
, почему бы вам просто не написать mov eax, esi
?
Также следует учитывать ошибку. Поскольку вы работаете на 24-битном истинном цветном экране, запись всего двойного слова (32 бита) изменит часть соседнего пикселя.
;esi = bytes per scan line
;edx = physical address of linear framebuffer memory.
;ebx = x coord * 3
;ecx = y coord
; IN (ebx,ecx,edx,esi) OUT () MOD (eax)
DrawPixel:
mov eax, esi ; BytesPerScanLine
imul eax, ecx ; BytesPerScanLine * Y
add eax, ebx ; BytesPerScanLine * Y + X * 3
mov word [edx+eax], 0x96FA ; Low word of RGB triplet
mov byte [edx+eax+2], 0x32 ; High byte of RGB triplet
ret
Эта новая процедура теперь изменяет только регистр EAX
Часть main имеет собственные проблемы:
mov esi, ModeInfoBlock + 10h
не будет извлекать информацию BytesPerScanLine . Для этого вам понадобится movzx esi, word [ModeInfoBlock + 10h]
l oop использует 2 ветви на каждой итерации. Вполне возможно написать l oop с помощью одной ветки.
Следующая моя версия. Поскольку новая процедура DrawPixel сохраняет все регистры (кроме EAX
), возможны большие упрощения:
xor ebx, ebx ; X = 0 -> EBX = X * 3
xor ecx, ecx ; Y = 0
movzx esi, word [ModeInfoBlock + 10h] ; BytesPerScanLine
mov edx, [ModeInfoBlock + 28h] ; PhysBasePtr
call drawLoop
jmp $
drawLoop:
call DrawPixel ; Modifies EAX
add ebx, 3 ; Like X = X + 1
cmp ebx, 1920*3 ; Length of the line is 1920 pixels
jb drawLoop
ret
Моя версия dr aws эта горизонтальная линия слева направо. Я считаю, что это может быть немного быстрее, чем рисование справа налево.
Вместо использования отдельного счетчика l oop (EDI
) я управляю l oop через тройную координату X. Среди других преимуществ (например, скорость, потому что cmp
и jb
прекрасно сочетаются друг с другом), это снижает нагрузку на использование регистров.
Улучшенные процедуры рисования горизонтальных и вертикальных линий
Специально для рисования горизонтальных и вертикальные линии, не рекомендуется повторно вызывать процедуру DrawPixel . Снова и снова вычислять адрес пикселя - пустая трата времени. Ниже я показываю пару подпрограмм специально для этих задач.
Я добавил несколько дополнительных изменений:
- Вы не должны перегружать основную программу техническими деталями адресации видеопамяти. . Пусть графические процедуры извлекают значения BytesPerScanLine и PhysBasePtr .
- Основная программа должна работать с пикселями на уровне (X, Y). Этот материал « умножить на 3 » снова является технической деталью, относящейся к графическим процедурам.
- Жесткое кодирование цвета в процедурах рисования очень не гибко.
; IN (eax,ebx,ecx,edx) OUT () MOD (eax)
; EAX = X
; EBX = Y
; ECX = Color
; EDX = Line length
HLine:
push edx
push edi
movzx edi, word [ModeInfoBlock + 10h] ; BytesPerScanLine
imul edi, ebx ; BytesPerScanLine * Y
imul eax, 3 ; X * 3
add edi, eax ; BytesPerScanLine * Y + X * 3
add edi, [ModeInfoBlock + 28h] ; ... + PhysBasePtr
mov eax, ecx ; Color 24 bits
shr eax, 8
imul edx, 3 ; Line length * 3
add edx, edi ; Address of the end of line
.a: mov [edi], cx ; Low word of RGB triplet
mov [edi+2], ah ; High byte of RGB triplet
add edi, 3 ; Like (X + 1)
cmp edi, edx
jb .a
pop edi
pop edx
ret
Выше HLine процедура dr aws горизонтальная линия слева направо.
; IN (eax,ebx,ecx,edx) OUT () MOD (eax)
; EAX = X
; EBX = Y
; ECX = Color
; EDX = Line length
VLine:
push edx
push esi
push edi
movzx esi, word [ModeInfoBlock + 10h] ; BytesPerScanLine
mov edi, esi
imul edi, ebx ; BytesPerScanLine * Y
imul eax, 3 ; X * 3
add edi, eax ; BytesPerScanLine * Y + X * 3
add edi, [ModeInfoBlock + 28h] ; ... + PhysBasePtr
mov eax, ecx ; Color 24 bits
shr eax, 8
imul edx, esi ; Line length * BytesPerScanLine
add edx, edi ; Address of the end of line
.a: mov [edi], cx ; Low word of RGB triplet
mov [edi+2], ah ; High byte of RGB triplet
add edi, esi ; Like (Y + 1)
cmp edi, edx
jb .a
pop edi
pop esi
pop edx
ret
Приведенное выше VLine процедура dr aws вертикальная линия сверху вниз.
Вот как вы можете использовать это:
Main:
xor eax, eax ; X = 0
xor ebx, ebx ; Y = 0
mov ecx, 0x003296FA ; Color cyan
mov edx, 1920 ; Line length
call HLine ; -> (EAX)
mov edx, 1080
call VLine ; -> (EAX)
jmp $