;****************************************************************************
;*
;*						MegaGraph Graphics Library
;*
;*                  Copyright (C) 1993 Kendall Bennett.
;*							All rights reserved.
;*
;* Filename:	$RCSfile: sv_maxpg.asm $
;* Version:		$Revision: 1.2 $
;*
;* Language:	80386 Assembler
;* Environment:	IBM PC (MS DOS)
;*
;* Description:	Module to compute the maximum number of available video
;*				pages for specific video mode.
;*
;* $Id: sv_maxpg.asm 1.2 1993/03/07 04:04:13 kjb Exp $
;*
;* Revision History:
;* -----------------
;*
;* $Log: sv_maxpg.asm $
;* Revision 1.2  1993/03/07  04:04:13  kjb
;* Bug fixes.
;*
;* Revision 1.1  1993/03/03  10:46:57  kjb
;* Initial revision
;*
;****************************************************************************

; Table of standard video mode information (bytesPerLine,
; vertical resolution and number of colors) used to compute the number of
; pages and page size for the specified video mode. This table can be
; modified at initialisation time for video cards that have non-standard
; bytes per line values (S3 cards and VESA cards).

PageInfo:		dw	grEGA_320x200x16, 		40, 200
				dw	grEGA_640x200x16, 		80, 200
				dw	grEGA_640x350x16, 		80, 350
				dw	grVGA_640x400x16, 		80, 400
				dw	grVGA_640x480x16, 		80, 480
				dw	grSVGA_800x600x16,		100, 600
				dw	grSVGA_1024x768x16,		128, 768
				dw	grSVGA_1280x1024x16,	160, 1024
				dw	grVGA_320x200x256,		320, 200
				dw	grSVGA_640x350x256,		640, 350
				dw	grSVGA_640x400x256,		640, 400
				dw	grSVGA_640x480x256,		640, 480
				dw	grSVGA_800x600x256,		800, 600
				dw	grSVGA_1024x768x256,	1024, 768
				dw	grSVGA_1280x1024x256,	1280, 1024
				dw	grSVGA_320x200x32k,		640, 200
				dw	grSVGA_640x350x32k,		1280, 350
				dw	grSVGA_640x400x32k,		1280, 400
				dw	grSVGA_640x480x32k,		1280, 480
				dw	grSVGA_800x600x32k,		1600, 600
				dw	grSVGA_1024x768x32k,	2048, 768
				dw	grSVGA_1280x1024x32k,	2560, 1024
				dw	grSVGA_320x200x16m,     960, 200
				dw	grSVGA_640x350x16m,		1920, 350
				dw	grSVGA_640x400x16m,		1920, 400
				dw	grSVGA_640x480x16m,		1920, 480
				dw	grSVGA_800x600x16m,		2400, 600
				dw	grSVGA_1024x768x16m,	3072, 768
				dw	grSVGA_1280x1024x16m,	3840, 1024
				dw	-1

;----------------------------------------------------------------------------
; numPages
;----------------------------------------------------------------------------
;
; Computes the number of pages in a specified video mode
;
; Entry:		AX		- Video mode number
;				EBX		- Video memory size
;
; Exit:			AX		- Number of video pages
;				EBX		- Page size for video mode
;				CX		- BytesPerLine value
;
; Registers:	EAX,EBX,ECX,EDX
;
;----------------------------------------------------------------------------
PROC	numPages

		mov		edx,ebx				; EDX := video memory size
		mov		bx,offset PageInfo - 6

@@FindMode:
		add		bx,6
		mov		cx,[WORD cs:bx]
		cmp		cx,-1
		je		@@NotFound
		cmp		cx,ax
		jne		@@FindMode			; Loop till desired mode is found

		push	edx
		xor		eax,eax
		mov		ax,[WORD cs:bx+2]
		mul		[WORD cs:bx+4]		; DX:AX := bytesPerLine * yres
		shl		edx,16
		or		eax,edx				; EAX := bytesPerLine * yre
		pop		edx

		cmp		cx,grSVGA_640x350x256
		jge		@@Colors256
		cmp		cx,grVGA_320x200x256
		je		@@Colors256

; We have a 16 color video mode. We round up the page size depending on
; how large it is, either to 8k, 16k, 32k or 64k boundaries.

@@Colors16:
		shr		edx,2				; EDX := video memory / 4
		add		eax,1FFFh			; Round to next 8k
		and		eax,0FFFFE000h
		cmp		eax,2000h			; Page size = 8k?
		je		@@Done				; Yes, we are done
		add		eax,3FFFh			; Round to next 16k
		and		eax,0FFFFC000h
		cmp		eax,4000h			; Page size = 16k?
		je		@@Done				; Yes, we are done
		add		eax,7FFFh			; Round to next 32k
		and		eax,0FFFF8000h
		cmp		eax,8000h			; Page size = 32k?
		je		@@Done				; Yes, we are done

; We have a 16 color video mode with > 64k per page, or a 256, 32k or
; 16 million color video mode. We thus ensure that the video page size is
; rounded up to the nearest 64k, to ensure pages always begin on bank
; boundaries.

@@Colors256:
		add		eax,0FFFFh			; Round to next 64k
		and		eax,0FFFF0000h

@@Done:
		mov		cx,[WORD cs:bx+2]	; Load bytes per line value
		mov		ebx,eax				; EBX := video page size
		mov		eax,edx
		xor		edx,edx				; EDX:EAX := video memory size
		div		ebx					; EAX := number of video pages
		ret

@@NotFound:
		xor		ax,ax
		xor		ebx,ebx
		ret

ENDP	numPages

;----------------------------------------------------------------------------
; setBytesPerLine
;----------------------------------------------------------------------------
;
; Changes the bytesPerLine value for a specified video mode.
;
; Entry:		AX		- Video mode number
;				BX		- New bytes per line value
;
; Exit:			BX		- New bytes per line value
;
; Registers:	AX,BX
;
;----------------------------------------------------------------------------
PROC	setBytesPerLine

		push	cx
		push	dx
		mov		dx,bx				; BX := new bytesPerLine value
		mov		bx,offset PageInfo - 6

@@FindMode:
		add		bx,6
		mov		cx,[WORD cs:bx]
		cmp		cx,-1
		je		@@NotFound
		cmp		cx,ax
		jne		@@FindMode			; Loop till desired mode is found

; Change the bytesPerLine value for the mode.
;
; Some VESA Video BIOS's are screwed and return invalid values for the
; bytes per line (Such as S3 based boards like the STB WIND/X). Generally
; they give us half the expected value, which is naturally less than the
; amount that is _physically_ required for the mode to operate. If this
; is the case we double the specified value :-)

		cmp		dx,[WORD cs:bx+2]
		jge		@@1
		shl		dx,1				; Value is too small, so double it!
@@1:	mov		[WORD cs:bx+2],dx
		mov		bx,dx				; Restore value in BX

@@NotFound:
		pop		dx
		pop		cx
		ret

ENDP	setBytesPerLine

;----------------------------------------------------------------------------
; checkVESAPageFlip
;----------------------------------------------------------------------------
;
; Checks to see if the VESA board supports extended page flipping.
;
; Exit:			carry	- Clear if VESA page flipping is supported
;
; Registers:	AX,BX,CX,DX
;
;----------------------------------------------------------------------------
PROC	checkVESAPageFlip

		mov		ax,4F07h			; Set display start service
		xor		bx,bx				; BH := 0, BL := 0 (set display start)
		xor		cx,cx				; Left most pixel in line
		xor		dx,dx				; First displayed scan line
		int		10h
		cmp		al,4Fh
		jne		@@Invalid			; Function not supported, no page flip
		or		ah,ah
		jnz		@@Invalid			; Function not successful, no page flip

		mov		ax,4F07h			; Get display start service
		mov		bx,1				; BH := 0, BL := 1 (get display start)
		int		10h
		cmp		al,4Fh
		jne		@@Invalid			; Function not supported, no page flip
		or		ah,ah
		jnz		@@Invalid			; Function not successful, no page flip
		or		bh,bh
		jnz		@@Invalid			; BH should be zero if supported also
		or		cx,cx
		jnz		@@Invalid			; CX should be zero (from above call)
		or		dx,dx
		jnz		@@Invalid			; DX should be zero (from above call)

; Horrah! We have page flipping on a VESA board.

		clc
		ret

@@Invalid:
		stc
		ret

ENDP	checkVESAPageFlip

;----------------------------------------------------------------------------
; GetVESABytesPerLine	- Gets the VESA bytes per line value for a mode
;----------------------------------------------------------------------------
;
; Calls a VESA compatible BIOS to get the bytes per line value for a mode,
; and updates the internal tables accordingly.
;
; Entry:		AX		- MGL Mode number
;				CX		- VESA Mode Number
;
; Registers:	None.
;
;----------------------------------------------------------------------------
PROC	GetVESABytesPerLine

		pusha

		push	ax
		push	cs
		pop		es
		mov		di,offset VesaBuf	; ES:DI -> Buffer for VESA info
		mov		ax,4F01h
		int		10h					; Call the video BIOS to get info
		pop		bx
		cmp		ax,004Fh
		jne		@@Exit				; Call failed

		mov		ax,bx
		mov		bx,[WORD VesaBuf+16]
		call	setBytesPerLine

@@Exit:	popa
		ret

ENDP	GetVESABytesPerLine

;----------------------------------------------------------------------------
; ModifyS3BytesPerLine	- Modifies the BytesPerLine for S3 cards.
;----------------------------------------------------------------------------
PROC	ModifyS3BytesPerLine

		mov		ax,grSVGA_800x600x16
		mov		cx,102h
		call	GetVESABytesPerLine
		mov		ax,grSVGA_1024x768x16
		mov		cx,104h
		call	GetVESABytesPerLine
		mov		ax,grSVGA_640x480x256
		mov		cx,101h
		call	GetVESABytesPerLine
		mov		ax,grSVGA_800x600x256
		mov		cx,103h
		call	GetVESABytesPerLine
		mov		ax,grSVGA_1024x768x256
		mov		cx,105h
		call	GetVESABytesPerLine
		mov		ax,grSVGA_640x480x32k
		mov		bx,2048
		call	setBytesPerLine
		ret

ENDP	ModifyS3BytesPerLine
