207 lines
6.5 KiB
HTML
207 lines
6.5 KiB
HTML
; =============================================================================
|
|
; Модуль : VMMDev Display Service (Auto-resize)
|
|
; Назначение : Автоматическое изменение разрешения экрана при resize окна VBox
|
|
; Файл : services/display/display.inc
|
|
;
|
|
; Логика задержки (паттерн heartbeat):
|
|
; Event → запомнить время, поставить флаг pending
|
|
; Tick → если pending и прошло 2 секунды → display_change
|
|
; Каждое новое событие сбрасывает таймер (debounce)
|
|
; =============================================================================
|
|
|
|
svc_display_name db "DISPLAY", 0
|
|
|
|
; --- Display Data ---
|
|
align 4
|
|
vbox_display_enabled dd 0
|
|
kos_display_ptr dd 0
|
|
|
|
; Отложенное обновление (debounce)
|
|
vbox_display_pending dd 0 ; 1 = есть отложенный запрос
|
|
vbox_display_event_time dd 0 ; timer_ticks момента последнего события
|
|
DISPLAY_DELAY_TICKS equ 50 ; 500ms (50 * 10ms)
|
|
|
|
; Статический буфер для запроса GetDisplayChangeRequest2
|
|
align 4
|
|
vmmdev_display_change_s VMMDEV_GET_DISPLAY_CHANGE_REQUEST2 \
|
|
<sizeof.VMMDEV_GET_DISPLAY_CHANGE_REQUEST2, \
|
|
VMMDEV_REQUEST_HEADER_VERSION, \
|
|
VMMDEV_REQ_GET_DISPLAY_CHANGE_2, \
|
|
0, 0, VMMDEV_REQUESTOR_KERNEL>, \
|
|
0, 0, 0, 1, 0 ; x_res, y_res, bpp, event_ack=1, display=0
|
|
|
|
; --- BGA Macros ---
|
|
|
|
macro bga_write index_val, data_val {
|
|
mov eax, index_val
|
|
mov dx, VBE_DISPI_IOPORT_INDEX
|
|
out dx, ax
|
|
mov eax, data_val
|
|
mov dx, VBE_DISPI_IOPORT_DATA
|
|
out dx, ax
|
|
}
|
|
|
|
macro bga_set_mode w, h, bpp {
|
|
bga_write VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED
|
|
bga_write VBE_DISPI_INDEX_XRES, w
|
|
bga_write VBE_DISPI_INDEX_YRES, h
|
|
bga_write VBE_DISPI_INDEX_BPP, bpp
|
|
bga_write VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED or VBE_DISPI_LFB_ENABLED
|
|
}
|
|
|
|
; vmmdev_display_init — Инициализация подсистемы дисплея
|
|
proc vmmdev_display_init
|
|
DEBUGF __DEBUG_DISPLAY__, "[VBoxGuest] [Display] Initializing...\n"
|
|
|
|
; Получить указатель на DISPLAY структуру ядра KolibriOS
|
|
invoke GetDisplay
|
|
mov [kos_display_ptr], eax
|
|
DEBUGF __DEBUG_DISPLAY__, "[VBoxGuest] [Display] KOS display struct: 0x%x\n", eax
|
|
|
|
; Получить физический адрес буфера запроса
|
|
mov eax, vmmdev_display_change_s
|
|
mov [vbox_device.display_virt], eax
|
|
invoke GetPhysAddr
|
|
mov [vbox_device.display_phys], eax
|
|
DEBUGF __DEBUG_DISPLAY__, "[VBoxGuest] [Display] Buffer: virt=0x%x, phys=0x%x\n", \
|
|
vmmdev_display_change_s, eax
|
|
|
|
mov dword [vbox_display_enabled], 1
|
|
|
|
; Сразу обработать текущее разрешение (без задержки)
|
|
call display_change
|
|
|
|
DEBUGF __DEBUG_DISPLAY__, "[VBoxGuest] [Display] Initialized OK\n"
|
|
xor eax, eax
|
|
ret
|
|
endp
|
|
|
|
; display_handle_event — Обработка события (из IRQ)
|
|
proc display_handle_event
|
|
test eax, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST
|
|
jz .done
|
|
cmp dword [vbox_display_enabled], 0
|
|
je .done
|
|
|
|
; Запомнить время события (сбросить таймер при повторных)
|
|
invoke GetTimerTicks
|
|
mov [vbox_display_event_time], eax
|
|
|
|
; Поставить флаг
|
|
mov dword [vbox_display_pending], 1
|
|
|
|
DEBUGF __DEBUG_DISPLAY__, "[VBoxGuest] [Display] Event queued, will apply in 2s\n"
|
|
|
|
.done:
|
|
ret
|
|
endp
|
|
|
|
; display_tick — Вызывается периодически из timer tick
|
|
proc display_tick
|
|
cmp dword [vbox_display_pending], 0
|
|
je .done
|
|
|
|
invoke GetTimerTicks
|
|
sub eax, [vbox_display_event_time]
|
|
cmp eax, DISPLAY_DELAY_TICKS
|
|
jb .done
|
|
|
|
; Сбросить флаг ДО обработки (новое событие во время display_change
|
|
; не потеряется — оно поставит pending заново)
|
|
mov dword [vbox_display_pending], 0
|
|
|
|
DEBUGF __DEBUG_DISPLAY__, "[VBoxGuest] [Display] Delay elapsed, applying...\n"
|
|
call display_change
|
|
|
|
.done:
|
|
ret
|
|
endp
|
|
|
|
; display_change — Запросить и применить новое разрешение
|
|
proc display_change uses ebx ecx edx esi edi
|
|
DEBUGF __DEBUG_DISPLAY__, "[VBoxGuest] [Display] display_change\n"
|
|
|
|
mov ebx, [vbox_device.display_virt]
|
|
test ebx, ebx
|
|
jz .skip
|
|
|
|
mov dword [ebx + VMMDEV_GET_DISPLAY_CHANGE_REQUEST2.header.rc], 0
|
|
mov dword [ebx + VMMDEV_GET_DISPLAY_CHANGE_REQUEST2.event_ack], 1
|
|
mov dword [ebx + VMMDEV_GET_DISPLAY_CHANGE_REQUEST2.display], 0
|
|
|
|
mov eax, [vbox_device.display_phys]
|
|
stdcall vmmdev_send_request, eax
|
|
|
|
mov ebx, [vbox_device.display_virt]
|
|
mov edi, [ebx + VMMDEV_GET_DISPLAY_CHANGE_REQUEST2.x_res]
|
|
mov esi, [ebx + VMMDEV_GET_DISPLAY_CHANGE_REQUEST2.y_res]
|
|
mov ecx, [ebx + VMMDEV_GET_DISPLAY_CHANGE_REQUEST2.bpp]
|
|
|
|
DEBUGF __DEBUG_DISPLAY__, "[VBoxGuest] [Display] Requested: %dx%d %dbpp\n", edi, esi, ecx
|
|
|
|
; Валидация
|
|
cmp edi, DISP_W_MIN
|
|
jb .skip
|
|
cmp esi, DISP_H_MIN
|
|
jb .skip
|
|
cmp edi, DISP_W_MAX
|
|
ja .skip
|
|
cmp esi, DISP_H_MAX
|
|
ja .skip
|
|
|
|
cmp ecx, 32
|
|
je .valid
|
|
cmp ecx, 24
|
|
je .valid
|
|
cmp ecx, 16
|
|
je .valid
|
|
cmp ecx, 8
|
|
jne .skip
|
|
|
|
.valid:
|
|
DEBUGF __DEBUG_DISPLAY__, "[VBoxGuest] [Display] Setting %dx%d %dbpp\n", edi, esi, ecx
|
|
|
|
; BGA под cli (как в v5)
|
|
cli
|
|
bga_set_mode edi, esi, ecx
|
|
sti
|
|
|
|
; Обновить DISPLAY структуру ядра
|
|
mov eax, [kos_display_ptr]
|
|
mov [eax + DISPLAY.width], edi
|
|
mov [eax + DISPLAY.height], esi
|
|
mov [eax + DISPLAY.bits_per_pixel], ecx
|
|
|
|
; pitch = (bpp / 8) * width
|
|
push ebx
|
|
mov ebx, ecx
|
|
shr ecx, 3
|
|
imul ecx, edi
|
|
mov [eax + DISPLAY.pitch], ecx
|
|
pop ebx
|
|
|
|
; SetScreen(width-1, height-1)
|
|
mov eax, edi
|
|
mov edx, esi
|
|
dec eax
|
|
dec edx
|
|
invoke SetScreen
|
|
|
|
DEBUGF __DEBUG_DISPLAY__, "[VBoxGuest] [Display] Resolution set successfully\n"
|
|
|
|
.skip:
|
|
ret
|
|
endp
|
|
|
|
; display_disable — Отключить подсистему дисплея
|
|
proc display_disable
|
|
DEBUGF __DEBUG_DISPLAY__, "[VBoxGuest] [Display] Disabling...\n"
|
|
mov dword [vbox_display_enabled], 0
|
|
mov dword [vbox_display_pending], 0
|
|
xor eax, eax
|
|
ret
|
|
endp
|
|
|
|
REGISTER_SERVICE svc_display_name, DISPLAY_EVENT_MASK, VMMDEV_GUEST_SUPPORTS_GRAPHICS, \
|
|
vmmdev_display_init, 0, display_disable, display_handle_event, display_tick, AUTOSTART_DISPLAY
|