Page 1 of 5

Polling for VSYNC doesn't work (0x3DA port)

Posted: Tue May 16, 2017 6:58 am
by 6502Rulez
Hello. I'm very new to the low level coding of the PC and I really love this forum and the wiki you guys made ! Anyway, let's go to the problem...
I wanted to sync all my code to the VSYNC (I'm not making an OS, but an OS-less game). At first I wanted to do it with an interrupt, but I've read, that most graphics card don't actually support it and I should be polling the 0x3DA port like this :

Code: Select all

.globl VSYNC_WAIT
.type VSYNC_WAIT, @function

VSYNC_WAIT:
	push eax
	push edx
	mov dx, 0x3DA
.l1:
	in al, dx
	test al, 8
	jnz l1
.l2:
	in al, dx
	test al, 8
	jz l2
	
	pop edx
	pop eax
	ret
I've found this exact code (Either in asm or C) on various websites, so I was sure that is the right way to do it, but it doesn't seem to work. My code is still executed way too fast. Just for your information, I am in Protected Mode and I have interrupt enabled and my own handlers. All handlers are generic except for the keyboard and PIT timer.

PS. I print al to the screen after first in and after second in. The first time it's always 0, after the other it's always 9 (4th bit set, isn't that weird ?)

Re: Polling for VSYNC doesn't work (0x3DA port)

Posted: Tue May 16, 2017 7:15 am
by Octocontrabass
6502Rulez wrote:My code is still executed way too fast.
Are you using a virtual machine? Those tend to be inaccurate when it comes to timing.
6502Rulez wrote:The first time it's always 0, after the other it's always 9 (4th bit set, isn't that weird ?)
According to VGADOC, that is the expected behavior.

Re: Polling for VSYNC doesn't work (0x3DA port)

Posted: Tue May 16, 2017 7:18 am
by Geri
first of all, the timing of your game should not rely on vsync.

Re: Polling for VSYNC doesn't work (0x3DA port)

Posted: Tue May 16, 2017 7:31 am
by 6502Rulez
Octocontrabass wrote:
6502Rulez wrote:My code is still executed way too fast.
Are you using a virtual machine? Those tend to be inaccurate when it comes to timing.
6502Rulez wrote:The first time it's always 0, after the other it's always 9 (4th bit set, isn't that weird ?)
According to VGADOC, that is the expected behavior.
Yes i'm using qemu like this :
qemu-system-i386 -fda image.img
Same thing happens on VirtualBox
Geri wrote:first of all, the timing of your game should not rely on vsync.
What's wrong with that ? I can make make my code run outside of the vsync, but I still need it to update the screen without flashing.

Re: Polling for VSYNC doesn't work (0x3DA port)

Posted: Tue May 16, 2017 8:06 am
by ~
You really should get development-only laptops and PCs. You won't get far using only emulators. You should also get peripheral cards that work with those systems, and some newer ones. The "old" cards compatible with Windows 98 and DOS will be key and vital to your OS development success, even if most people around don't like it, because they are specific to the PC platform, relatively modern, and thus they will allow you to get the most of your learning about the PC.

The newest PCI cards with diminished backwards compatibility are probably not even specific to the PC platform. They are probably platform-independent, platform-nonspecific cards for Mac, PC and unknown proprietary non-standard hardware platforms.

The ones I like the most are the ones to which I can install Windows 9x because that also gives me access to DOS.

I also consider that it was an error from my part to switch from Windows 98 to Windows XP in my main machines (actually in all of my machines). The moment I did that is when I lost access to the friendliness of the low-level-oriented Windows 9x and DOS which sustained my main OS development efforts.

Only recently I have reinstalled and reactivated all of my development machines with Windows 9x/98/ME/DOS/FreeDOS, and from there I can boot and test my code in DOS or stand alone.

But you need to start out by getting those machines and fully VGA-compatible video cards, as well as CRT and LCD monitors to really test that the effects of your code are doing something at all.

Re: Polling for VSYNC doesn't work (0x3DA port)

Posted: Tue May 16, 2017 8:14 am
by 6502Rulez
~ wrote:You really should get development-only laptops and PCs. You won't get far using only emulators. You should also get peripheral cards that work with those systems, and some newer ones. The "old" cards compatible with Windows 98 and DOS will be key and vital to your OS development success, even if most people around don't like it, because they are specific to the PC platform, relatively modern, and thus they will allow you to get the most of your learning about the PC.

The newest PCI cards with diminished backwards compatibility are probably not even specific to the PC platform. They are probably platform-independent, platform-nonspecific cards for Mac, PC and unknown proprietary non-standard hardware platforms.

The ones I like the most are the ones to which I can install Windows 9x because that also gives me access to DOS.

I also consider that it was an error from my part to switch from Windows 98 to Windows XP in my main machines (actually in all of my machines). The moment I did that is when I lost access to the friendliness of the low-level-oriented Windows 9x and DOS which sustained my main OS development efforts.

Only recently I have reinstalled and reactivated all of my development machines with Windows 9x/98/ME/DOS/FreeDOS, and from there I can boot and test my code in DOS or stand alone.

But you need to start out by getting those machines and fully VGA-compatible video cards, as well as CRT and LCD monitors to really test that the effects of your code are doing something at all.
I have a Pentium MMX 166 Mhz laptop running win98/DOS, but I can't test it now, it's packed (I'm moving out next week) so that has to wait. But is it really the fault of the emulator ? I googled far and wide and I couldn't find any mention of people having this problem I have (and vsync isn't some exotic thing one would want to do, right ? So I assume that qemu/virtualbox can support it fully)

Re: Polling for VSYNC doesn't work (0x3DA port)

Posted: Tue May 16, 2017 8:21 am
by ~
Currently emulation is always poorer than expected. It's more productive to use real hardware and then see how the rest of things behave, like emulators.

Re: Polling for VSYNC doesn't work (0x3DA port)

Posted: Tue May 16, 2017 9:26 am
by 6502Rulez
I just want to mention that I tested my code few days ago ( I wasn't trying to use VSYNC yet back then) on 2 computers, the 166 Mhz laptop I mentioned and some other Dual Core computer and it did work. Now I tried my code on the laptop I'm writing from currently and it doesn't work ! I only get blinking cursor. So I wrote very simple keyboard loop that just prints what I type on the keyboard for the test. It works in qemu and virtual box, but not on my real laptop. Here's the code :

Code: Select all

.intel_syntax noprefix
.code16
	cli
	ljmp 0, begin
begin:
	xor ax, ax
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	mov bp, ax
	mov ss, ax
	mov sp, bp
start:
	mov ah, 0x00
	int 0x16
	push ax
	mov ah, 0x0E
	int 0x10
	pop ax
	jmp start
Any ideas what is going on ? I'm booting from USB and the laptop is ASUS K52F. I thought it might be because of UEFI, but I just checked, that my linux is not installed in UEFI mode so... This is weird

PS: I just tested my code on yet another laptop, it boots and I see my colors, but they don't change. It seems that my function to change colors in the VGA palette doesn't work. VSYNC doesn't work either.

Re: Polling for VSYNC doesn't work (0x3DA port)

Posted: Tue May 16, 2017 9:58 am
by LtG
Not sure what your issue is, but here's a few notes:
- You don't seem to have ORG anywhere? Maybe it's outside of the code snippet you provided
- Is there a reason you are clearing SP specifically BP? Can't see it affecting your issue though
- Is there a reason you push and pop AX at the bottom of your code? What effect is that supposed to have?
- In your "begin" code you are not initializing BX which I think is used by int 0x10, therefore in VM (Qemu) it might be left at zero while on real hardware it could be anything

Last one being your issue is my guess, or maybe first.. So add to your begin after "xor ax, ax":
mov bx, ax

Re: Polling for VSYNC doesn't work (0x3DA port)

Posted: Tue May 16, 2017 10:04 am
by Octocontrabass
6502Rulez wrote:Yes i'm using qemu like this :
qemu-system-i386 -fda image.img
Same thing happens on VirtualBox
Even if qemu/VirtualBox can get vsync information from the host OS (which they might not be able to do), they aren't necessarily able to provide it to the guest OS. You either need to use an emulator specifically geared towards VGA compatibility, or actual hardware.
6502Rulez wrote:(and vsync isn't some exotic thing one would want to do, right ? So I assume that qemu/virtualbox can support it fully)
Vsync in a virtual machine is a rather unusual requirement. Vsync using a virtual machine's VGA compatibility layer instead of the VM's native graphics device is unheard of.
6502Rulez wrote:Any ideas what is going on ? I'm booting from USB
Booting from USB will behave in unexpected ways if your boot sector doesn't look like a VBR (with a valid BPB) or a MBR (with a valid partition table). Your laptop might do something stupid when it can't find either of those things. It could also be the bug mentioned by LtG.

Re: Polling for VSYNC doesn't work (0x3DA port)

Posted: Tue May 16, 2017 10:20 am
by 6502Rulez
LtG wrote:Not sure what your issue is, but here's a few notes:
- You don't seem to have ORG anywhere? Maybe it's outside of the code snippet you provided
- Is there a reason you are clearing SP specifically BP? Can't see it affecting your issue though
- Is there a reason you push and pop AX at the bottom of your code? What effect is that supposed to have?
- In your "begin" code you are not initializing BX which I think is used by int 0x10, therefore in VM (Qemu) it might be left at zero while on real hardware it could be anything

Last one being your issue is my guess, or maybe first.. So add to your begin after "xor ax, ax":
mov bx, ax
The orgin point is specified in the linker script. I clear the bx now like you said, didn't change anything. I'd like to add that this simple keyboard loop does work on my friend's laptop even before adding mov bx, ax. However, the VSYNC still doesn't work and I can't even change the colors.

Here's what I'm doing.
Enter the 320x200@256 mode
Enter protected Mode
Setup interrupts..
Fill the framebuffer with color lines (0-15, then it repeats)

Now I'm in an infinite loop and in it I call VSYNC_WAIT and CYCLE_COLORS. Cycle colors just changes the first 16 colors to create a moving bars effect. On a virtual machine it works, but way too fast because the VSYNC fails, on real hardware I can't even change the colors.
Vsync in a virtual machine is a rather unusual requirement. Vsync using a virtual machine's VGA compatibility layer instead of the VM's native graphics device is unheard of.
If that's the case, what should I do to get a stable image ? I have to sync with VSYNC, otherwise I will get tears.

Code: Select all

globl CHANGE_VGA_COLOR
.type CHANGE_VGA_COLOR, @function

CHANGE_VGA_COLOR:
	push ebp
	mov ebp, esp
	mov dx, 0x3C8			/* VGA port for color index */
	mov eax, [ebp+8]		/* pop the color index from the stack */
	out dx, ax				/* out it to the port 0x3C8 */
	inc dx					/* now the port is 0x3C9 */
	mov eax, [ebp+12]		/* pop the red */
	out dx, ax		
	mov eax, [ebp+16]		/* pop green */
	out dx, ax
	mov eax, [bp+20]		/* pop blue */
	out dx, ax
	mov esp, ebp
	pop ebp
	ret

.globl CYCLE_COLORS
.type CYCLE_COLORS, @function

CYCLE_COLORS:
    push eax
    push ebx
    push ecx
    push edi
    
    xor eax, eax
    xor ebx, ebx
    xor ecx, ecx
    xor edx, edx

CYCLE_loop:
    cmp ecx, 16
    je CYCLE_end_of_loop

    movzx ebx, byte ptr [colorcounter]
    add ebx, ecx
    and ebx, 15
    
    /*add ebx, colortable			this will add whatever that is at colortable instead of the address of colortable itself*/
    lea edx, colortable
    add ebx, edx
    
    movzx eax, byte ptr [ebx+2]
    push eax
    movzx eax, byte ptr [ebx+1]
    push eax
    movzx eax, byte ptr [ebx]
    push eax
    push ecx
    call CHANGE_VGA_COLOR
    add esp, 16

    inc ecx
    jmp CYCLE_loop

CYCLE_end_of_loop:
    inc byte ptr [colorcounter]
    pop edx
    pop ecx
    pop ebx
    pop eax
    ret


Re: Polling for VSYNC doesn't work (0x3DA port)

Posted: Tue May 16, 2017 10:37 am
by LtG
In case you want to try to fix the "read keyboard, print character" issue, can you provide the code you now use, as well as once compiled and then disassembled.

As for your VSYNC/graphics issue, I'm not as much help.. Though I would expect that any emulator/VM software that is supposed to work with DOS would have to support VSYNC or something similar as presumably some DOS games used it.

Are you sure VSYNC is not working in VM? How fast is "way too fast"? Seems to me that your expectation may or may not be correct, so mentioning how fast would be useful. If it's too fast to visually identify, then slow it down (update graphics only every 10 VSYNC, or 100 VSYNC, etc).

Sorry I can't be of much more help, but running a bit out of time.

Re: Polling for VSYNC doesn't work (0x3DA port)

Posted: Tue May 16, 2017 10:43 am
by 6502Rulez
LtG wrote:In case you want to try to fix the "read keyboard, print character" issue, can you provide the code you now use, as well as once compiled and then disassembled.

As for your VSYNC/graphics issue, I'm not as much help.. Though I would expect that any emulator/VM software that is supposed to work with DOS would have to support VSYNC or something similar as presumably some DOS games used it.

Are you sure VSYNC is not working in VM? How fast is "way too fast"? Seems to me that your expectation may or may not be correct, so mentioning how fast would be useful. If it's too fast to visually identify, then slow it down (update graphics only every 10 VSYNC, or 100 VSYNC, etc).

Sorry I can't be of much more help, but running a bit out of time.
The keyboard loop program works, just not on my own laptop (my guess is that it boots from USB in a weird way) I'm 100% sure that my VSYNC function doesn't work, because it never jumps inside of that function. If I'd call the VSYNC_WAIT twice I should get half of the framerate, right ? It doesn't happen. When I programmed PIT to give me an IRQ at 70HZ I can clearly see the color lines scroll smoothly.

PS : Here's a video, please watch.

Re: Polling for VSYNC doesn't work (0x3DA port)

Posted: Tue May 16, 2017 1:00 pm
by SpyderTL
The VirtualBox source code is online, and if I remember correctly, the V-SYNC bit is simply toggled back and forth between on and off every time you read the register. It definitely does not work as you would expect.

You may be able to get V-SYNC information if you write a custom video card driver for VirtualBox, but that would be quite a bit more work, and it would only work in VirtualBox.

Unfortunately, none of the popular virtual machines focus much attention on running games using the old VGA registers. They have all been designed to work with Windows with custom drivers.

You might try using SimNOW as a test VM. It has some of the best simulated hardware behavior that I've seen.

Also, I found this thread on a setting in VMWare that will enable V-SYNC. It may be worth a shot.

https://arstechnica.com/civis/viewtopic ... &t=1212037

Re: Polling for VSYNC doesn't work (0x3DA port)

Posted: Tue May 16, 2017 1:04 pm
by 6502Rulez
SpyderTL wrote:The VirtualBox source code is online, and if I remember correctly, the V-SYNC bit is simply toggled back and forth between on and off every time you read the register. It definitely does not work as you would expect.

You may be able to get V-SYNC information if you write a custom video card driver for VirtualBox, but that would be quite a bit more work, and it would only work in VirtualBox.

Unfortunately, none of the popular virtual machines focus much attention on running games using the old VGA registers. They have all been designed to work with Windows with custom drivers.

You might try using SimNOW as a test VM. It has some of the best simulated hardware behavior that I've seen.

Also, I found this thread on a setting in VMWare that will enable V-SYNC. It may be worth a shot.

https://arstechnica.com/civis/viewtopic ... &t=1212037
Thanks for the info. But here's the problem. I tested my code on my friend's laptop few hours ago and the vsync doesn't work on it either. I can't even change the colors. The code to change colors is in this thread too. Anyway... If VSYNC is out of question, how else can I update the screen without flickering ?