What is the fastest way to use the mouse in direct vesa mode. (No freebasic fbgfx graphic commands)
Do using interrupts, going from protected mode to real mode and back, slow things down?
Direct vesa:Fastest way to use the mouse?
Re: Direct vesa:Fastest way to use the mouse?
For real-mode DOS and QuickBASIC one method that worked well for me was to set up a mouse driver interrupt sub that stored the mouse status in a QuickBASIC global structure, eliminating the need to periodically call the mouse driver. Once installed, the mouse driver called the interrupt sub for any of the defined conditions (events), the interrupt sub updated the QuickBASIC global structure, and the QuickBASIC app could simply read the mouse status from the structure members. Here are the relavant parts of the assembly module source:
The missing file test.asm is not necessary for your purposes, but by way of explaining what it was here is the start of the header:
I have had only a few minutes to consider this, but I think you should be able to adapt this method to work with FreeBASIC DOS. Specifically, I think you could use the Allocate Real Mode Call-Back Address function to handle the interrupt sub call in protected mode. I have no idea how to translate the mouse driver virtual screen coordinates to screen coordinates for non-VGA modes.
Code: Select all
;===================================================
; This is the MASM 6+ source code for a QuickBASIC
; Mouse procedure library. Beyond providing wrappers
; for a few of the most common mouse functions, it
; includes a MouseInit procedure that initializes
; the mouse driver and installs a mouse driver
; interrupt subroutine that maintains the current
; mouse status in a QuickBASIC global variable.
;
; The QuickBASIC global variable must be of type
; MouseType, and the segment and offset addresses
; of the variable must be passed in the first call
; to the MouseInit procedure. The button states
; are TRUE (-1) if the button is pressed, or FALSE
; (0) if the button is not pressed. The event mask
; indicates what type of mouse event triggered the
; most recent interrupt. The possible events are a
; position change or a press or release of the
; left or right button.
;
; TYPE MouseType
; x AS INTEGER ' Cursor X coordinate
; y AS INTEGER ' Cursor Y coordinate
; left AS INTEGER ' Left button state
; right AS INTEGER ' Right button state
; event AS INTEGER ' Event mask
; END TYPE
; DIM SHARED mouse AS MouseType
;
; These constants are used to interpret the event
; mask. The assigned values are the value of the
; corresponding bit in the event mask, so an
; event can be detected by ANDing the appropriate
; constant with the event mask.
; CONST POSITION = 1
; CONST LPRESS = 2
; CONST LRELEASE = 4
; CONST RPRESS = 8
; CONST RRELEASE = 16
;
; For the range of video modes that are supported
; by QuickBASIC, the interrupt subroutine and the
; MouseSetPosition procedure automatically
; translate between mouse driver virtual screen
; coordinates and physical screen coordinates,
; so as viewed from the QuickBASIC module all
; coordinates are physical screen coordinates.
; For the text modes, the x coordinate will be
; the base 1 column position and the y coordinate
; will be the base 1 row position.
;
; For uniformity, all of the procedures that take
; arguments expect the arguments to be passed by
; reference. "Pass by reference" is the QB default
; and it means that the value passed is the address
; of the argument in the QB default data segment.
; Within the procedures, the arguments, which as
; viewed from the procedure are properly termed
; "parameters", are accessed by first loading the
; address of the parameter into a base or index
; register and then by using a register indirect
; form of the instruction that accesses the
; parameter. For example, to load the value of a
; parameter named varPtr into AX:
;
; mov bx,varPtr
; mov ax,[bx]
;
; QB procedures are always called with a far call
; and the procedures must preserve the direction
; flag and the BP, DI, SI, DS, and SS registers.
; The BASIC calling conventions require that the
; arguments be pushed onto the stack in left to
; right order as they appear in the procedure
; definition, and that the called procedure remove
; the arguments from the stack. One significant
; advantage of using MASM for mixed language
; programming is that you can specify a language
; type in the .MODEL directive and MASM will
; automatically generate the code that is required
; to properly implement the calling conventions.
; For example, for the RET instruction in the
; procedures MASM knows to encode a far return,
; and for the procedures that take arguments, MASM
; knows to add an operand to the RET instruction
; that will cause the processor to add an
; appropriate value to SP after the procedure has
; returned to the caller.
;===================================================
; Declare a structure to use as a template when
; accessing the mouse status variable.
MouseType struct
x WORD ?
y WORD ?
left WORD ?
right WORD ?
event WORD ?
MouseType ends
; This prototype establishes the call interface for
; the B_OnExit procedure (so MASM will know how to
; call it) and effectively generates an external
; declaration in this module (so MASM will know that
; the procedure is defined in another module).
B_OnExit proto far basic :far ptr
; This is the normal model specification for QB.
.model medium,basic
; Enable assembly of the 186 instruction set (the
; minimum processor that will support an immediate
; (constant) operand for a push instruction).
.186
; Start a near data segment. The linker will combine
; this segment with the QB default data segment.
.data
; Allocate a flag variable to lock out multiple
; calls to MouseInit. The name avoids the MASM
; reserved word "finit".
f_init dw 0
; Define screen and cursor masks for a crosshair
; cursor. The cursor defintion is within this
; module rather than being passed as a parameter
; simply because defining the cursor with binary
; numbers is much easier than defining it with
; hex numbers.
;
; Note that this cursor will not work correctly
; for SCREEN 1, and that the aspect ratio will
; be significantly off for the 640x200 modes.
;
; For the QB graphics modes other than SCREEN 1,
; the mouse driver will AND the screen mask bits
; with the corresponding screen pixel bits and
; XOR the result with the cursor mask. In truth
; table form:
;
; screen mask cursor mask resulting screen bit
; 0 0 0
; 0 1 1
; 1 0 unchanged
; 1 1 inverted
;
; Note that the masks bits are expanded as
; necessary for the current graphics mode.
; For example, for mode 13h (SCREEN 13) each
; mask bit is expanded to 8 bits and these
; bits are then combined with the 8 attribute
; bits for the corresponding screen pixel.
;0123456701234567
cross dw 1111111111111111b ;0
dw 1111111111111111b ;1
dw 1111111011111111b ;2
dw 1111111011111111b ;3
dw 1111111011111111b ;4
dw 1111111011111111b ;5
dw 1111111111111111b ;6
dw 0000001110000001b ;7
dw 1111111111111111b ;0
dw 1111111011111111b ;1
dw 1111111011111111b ;2
dw 1111111011111111b ;3
dw 1111111011111111b ;4
dw 1111111111111111b ;5
dw 1111111111111111b ;6
dw 1111111111111111b ;7
dw 0000000000000000b ;0
dw 0000000000000000b ;1
dw 0000000100000000b ;2
dw 0000000100000000b ;3
dw 0000000100000000b ;4
dw 0000000100000000b ;5
dw 0000000000000000b ;6
dw 1111110001111110b ;7
dw 0000000000000000b ;0
dw 0000000100000000b ;1
dw 0000000100000000b ;2
dw 0000000100000000b ;3
dw 0000000100000000b ;4
dw 0000000000000000b ;5
dw 0000000000000000b ;6
dw 0000000000000000b ;7
; Start a (far) code segment.
.code
; This include directive includes TEST.ASM in this
; file, effectively making it part of this file.
include test.asm
;===================================================
; Allocate a variable to store the far address of
; the mouse status variable, and a lookup table of
; shift and base adjust values indexed by BIOS video
; mode, that will be used to translate between mouse
; driver virtual screen coordinates and physical
; screen coordinates. These variables need to be in
; the code segment because they must be accessed
; from the interrupt subroutine, and when the mouse
; driver calls the subroutine the only segment
; register with a known value is CS.
statusVarPtr dd 0
; To allow the table to be indexed by the BIOS video
; mode the table must include all mode numbers from
; 0 to 13h, even though several of the included
; modes have no corresponding QB SCREEN mode and
; others are not supported on the typical PC. Each
; element consists of an x shift word, a y shift
; word, a base adjust word, and a pad word that is
; included to simplify table indexing. The base
; adjust value is 1 for the text modes and 0 for
; the graphic modes. Aligning the table on a word
; boundary minimizes the time required to access
; the table.
align 2
luTable dw 4,3,1,0 ; 0
dw 4,3,1,0 ; 1 (SCREEN 0, 40 column)
dw 3,3,1,0 ; 2
dw 3,3,1,0 ; 3 (SCREEN 0, 80 column)
dw 1,0,0,0 ; 4 (SCREEN 1)
dw 1,0,0,0 ; 5
dw 0,0,0,0 ; 6 (SCREEN 2)
dw 3,3,1,0 ; 7 (SCREEN 0, monochrome only)
dw 2,0,0,0 ; 8 PCjr only
dw 0,0,0,0 ; 9 PCjr only
dw 0,0,0,0 ; A PCjr only
dw 0,0,0,0 ; B EGA BIOS internal only
dw 0,0,0,0 ; C EGA BIOS internal only
dw 1,0,0,0 ; D (SCREEN 7)
dw 0,0,0,0 ; E (SCREEN 8)
dw 0,0,0,0 ; F (SCREEN 10)
dw 0,0,0,0 ; 10 (SCREEN 9)
dw 0,0,0,0 ; 11 (SCREEN 11)
dw 0,0,0,0 ; 12 (SCREEN 12)
dw 1,0,0,0 ; 13 (SCREEN 13)
;===================================================
; The following procedure declarations use the
; distance (far) and langtype (basic) from the
; .MODEL directive, and default to PUBLIC
; visibility.
;===================================================
; This proc calls the mouse driver Mouse Reset and
; Status function to reset the mouse driver to clear
; the interrupt subroutine call mask, which causes
; the mouse driver to cease calling the interrupt
; subroutine.
; This declaration must be placed before the
; reference to it in the MouseInit procedure.
;===================================================
TermProc proc
xor ax,ax
int 33h
ret
TermProc endp
;===================================================
; This proc checks for a mouse driver, resets it,
; saves the segment and offset addresses of the
; global status variable, installs the interrupt
; subroutine, and calls the B_OnExit routine to log
; a termination procedure that will automatically
; disable the interrupt subroutine when the program
; terminates. It returns non-zero for success, or
; zero for failure. The first call sets a flag that
; locks out subsequent calls.
;===================================================
MouseInit proc varSeg:WORD,varPtr:WORD
; Lock out subseqent calls.
.IF f_init != 0
xor ax,ax
ret
.ENDIF
mov f_init,-1
; Check for a mouse driver.
; Use the DOS Get Interrupt Vector function
; to get the interrupt 33h vector. If the
; segment address is zero, then the mouse
; driver is not installed.
mov ax,3533h
int 21h
mov ax,es
.IF ax == 0
ret
.ENDIF
; Attempt to reset the mouse driver. If the
; reset fails then the mouse driver is not
; installed.
xor ax,ax
int 33h
.IF ax == 0
ret
.ENDIF
; Save the address of the mouse status variable.
mov bx,varPtr
mov ax,[bx]
mov word ptr cs:statusVarPtr,ax
mov bx,varSeg
mov ax,[bx]
mov word ptr cs:statusVarPtr+2,ax
; Install the interrupt subroutine.
mov ax,12
; This condition mask specifies that an
; interrupt be generated for any of the
; defined conditions.
mov cx,11111b
push cs
pop es
mov dx,OFFSET InterruptSub
int 33h
; Register the termination routine.
; The arguments must be pushed onto the stack
; as per the basic calling convention before
; calling the routine.
push cs
push OFFSET TermProc
call B_OnExit
; Return whatever B_OnExit returned.
ret
MouseInit endp
;===================================================
; This proc is the interrupt subroutine. The mouse
; driver will call it for each mouse interrupt.
;
; The local variables allow temporary values to be
; stored on the stack in named locations.
;===================================================
align 2
InterruptSub proc
LOCAL xShift:WORD,yShift:WORD,baseAdjust:WORD
; Preserve DS before changing it because the
; mouse driver probably will not expect it to
; change.
push ds
; Preserve BX before changing it because it
; contains the button status.
push bx
; Get the video mode from the BIOS data area.
mov bx,40h
mov ds,bx
mov bx,49h
mov bx,[bx]
; Because the mode is actually stored as a
; byte and we are reading a word, and because
; bit 7 of the byte may or may not be set
; depending on whether or not the display
; memory was erased during the most recent
; mode set, we need to discard the upper 9
; bits of BX.
and bx,1111111b
; Get the corresponding x and y shift and
; base adjust values and store them in
; local variables. BX must first be scaled by
; the size of the table elements (BX=BX*8).
shl bx,3
; For instructions that take two operands,
; only one can be a memory operand. The push-
; pop sequences are used to perform a memory
; to memory move without involving a scratch
; register. Local variables can be accessed
; without a segment override because they are
; allocated from the stack, so the POP
; instructions reference BP (for example,
; "pop xShift" is encoded as "pop [bp-2]"),
; so the processor automatically uses SS.
push cs:[luTable+bx]
pop xShift
push cs:[luTable+bx+2]
pop yShift
push cs:[luTable+bx+4]
pop baseAdjust
; Load the status variable address into DS:BX.
mov bx,word ptr cs:[statusVarPtr]
mov ds,word ptr cs:[statusVarPtr+2]
; This assume informs MASM that BX contains
; a pointer to a variable of MouseType, so
; it will know what the following references
; to [bx].elementname mean:
ASSUME bx:ptr MouseType
; Store the event mask in the status variable.
mov [bx].event,ax
; We are Finished with the value in AX so pop
; the preserved button status into it.
pop ax
; Store the button status in the status
; variable. Bit0 of the button status will
; be set if the left mouse button is pressed
; and bit1 if the right mouse button is
; pressed. In the MASM 6+ High Level syntax
; "&" is the bit test operator, which returns
; true if the bit with the specified "place"
; value is set.
.IF ax & 1
mov [bx].left,-1
.ELSE
mov [bx].left,0
.ENDIF
.IF ax & 2
mov [bx].right,-1
.ELSE
mov [bx].right,0
.ENDIF
; Convert the virtual screen coordinates
; of the mouse cursor to physical screen
; coordinates and store the results in
; the status variable.
mov ax,cx
mov cx,xShift
shr ax,cl
add ax,baseAdjust
mov [bx].x,ax
mov ax,dx
mov cx,yShift
shr ax,cl
add ax,baseAdjust
mov [bx].y,ax
; Remove the assumption for BX.
ASSUME bx:NOTHING
; Recover DS.
pop ds
ret
InterruptSub endp
Snip…
Code: Select all
; This file contains a procedure that performs a
; measurement of the number of clock cycles the
; interrupt subroutine takes to execute. To use the
; procedure, include this file in MOUSELIB.ASM
;
; The purpose of the measurement was to ensure that,
; in the worst case, the interrupt subroutine would
; not consume an unreasonable amount of processor
; time.
Re: Direct vesa:Fastest way to use the mouse?
How do you use the Allocate Real Mode Call-Back Address function to call a protected mode subroutine?
Re: Direct vesa:Fastest way to use the mouse?
Yes, there is a surprising amount of overhead involved.Do using interrupts, going from protected mode to real mode and back, slow things down?
This is a FB-DOS version of the newer cycle count macros (counter.bas):
Code: Select all
''=============================================================================
dim shared as longint counter_cycles
dim shared as integer _counter_loopcount_, _counter_loopcounter_
#macro COUNTER_BEGIN( loop_count )
_counter_loopcount_ = loop_count
_counter_loopcounter_ = _counter_loopcount_
asm
xor eax, eax
cpuid '' serialize
rdtsc '' get reference loop start count
push edx '' preserve msd (most significant dword)
push eax '' preserve lsd
xor eax, eax
cpuid '' serialize
.balign 16
0: '' start of reference loop
sub DWORD PTR _counter_loopcounter_, 1
jnz 0b '' end of reference loop
xor eax, eax
cpuid '' serialize
rdtsc '' get reference loop end count
pop ecx '' recover lsd of start count
sub eax, ecx '' calc lsd of reference loop count
pop ecx '' recover msd of start count
sbb edx, ecx '' calc msd of reference loop count
push edx '' preserve msd of reference loop count
push eax '' preserve lsd of reference loop count
xor eax, eax
cpuid '' serialize
rdtsc '' get test loop start count
push edx '' preserve msd
push eax '' preserve lsd
end asm
_counter_loopcounter_ = _counter_loopcount_
asm
xor eax, eax
cpuid '' serialize
.balign 16
1: '' start of test loop
end asm
#endmacro
''=============================================================================
#macro COUNTER_END()
asm
sub DWORD PTR _counter_loopcounter_, 1
jnz 1b '' end of test loop
xor eax, eax
cpuid '' serialize
rdtsc
pop ecx '' recover lsd of start count
sub eax, ecx '' calc lsd of test loop count
pop ecx '' recover msd of start count
sbb edx, ecx '' calc msd of test loop count
pop ecx '' recover lsd of reference loop count
sub eax, ecx '' calc lsd of corrected loop count
pop ecx '' recover msd of reference loop count
sbb edx, ecx '' calc msd of corrected loop count
mov DWORD PTR [counter_cycles], eax
mov DWORD PTR [counter_cycles+4], edx
end asm
counter_cycles /= _counter_loopcount_
#endmacro
''=============================================================================
Code: Select all
jmp handler
...
handler:
push ds
mov ds, cs:[xxxx]
mov ax, ds:[0010]
pop ds
iret
Code: Select all
#include "counter.bas"
sleep 5000
''-----------------------------------------------------------
'' Disable the maskable interrupts so the system timer tick,
'' keyboard interrupt, etc will not interfere with the cycle
'' count code.
''-----------------------------------------------------------
asm cli
for i as integer = 1 to 6
COUNTER_BEGIN( 100 )
COUNTER_END()
print counter_cycles
COUNTER_BEGIN( 100 )
asm int 0x11
COUNTER_END()
print counter_cycles
next
asm sti
sleep
Code: Select all
HDPMI:
0
2112
0
2110
0
2109
0
2110
0
2110
0
2110
CWSDPMI:
0
4665
0
4653
0
4667
0
4673
0
4672
0
4651
Results with the Windows XP NTVDM:
Code: Select all
-1
12768
0
12653
0
12688
0
12738
0
12645
0
12678
I have not tried yet, but I expect that it will not be difficult. Which VESA modes do you expect to be using?How do you use the Allocate Real Mode Call-Back Address function to call a protected mode subroutine?
Re: Direct vesa:Fastest way to use the mouse?
Vesa LBF mode 101h, 640x480 8 bit color.