Access vesa modes in freebasic ?

DOS specific questions.
Post Reply
lassar
Posts: 306
Joined: Jan 17, 2006 1:35

Access vesa modes in freebasic ?

Post by lassar »

I am looking to speed up a program.

How does one access 8 bit graphic vesa modes with linear frame buffer in freebasic ?
monochromator
Posts: 42
Joined: Mar 05, 2013 5:37

Re: Access vesa modes in freebasic ?

Post by monochromator »

FreeBASIC graphic library automatically uses VESA for high resolution or high color modes.
For example, If you set screen mode 18 (640x480x8), gfxlib will use VESA interface.

If you want use VESA directly, it is possible with functions "int86" or "int86x" (declared in file "dos\dos.bi") to call VESA interrupt, functions DOSMEMGET/DOSMEMPUT for access to the banked video buffer (declared in "dos\go32.bi") and functions
__dpmi_physical_address_mapping
__dpmi_allocate_ldt_descriptors
__dpmi_set_segment_base_address
__dpmi_set_segment_limit
(declared in "dos\dpmi.bi")
for access to the linear video buffer.
lassar
Posts: 306
Joined: Jan 17, 2006 1:35

Re: Access vesa modes in freebasic ?

Post by lassar »

How do you acess VESA directly using the linear frame buffer?
monochromator
Posts: 42
Joined: Mar 05, 2013 5:37

Re: Access vesa modes in freebasic ?

Post by monochromator »

Then you will not need DOSMEMGET/DOSMEMPUT.

1. Set required video mode through int86.
2. Get physical address and size of frame buffer (int86).
3. Map it to linear address space (__dpmi_physical_address_mapping)
4. Allocate descriptor (__dpmi_allocate_ldt_descriptors)
5. Set it's parameters (base address and limit) to frame buffer (__dpmi_set_segment_base_address
and __dpmi_set_segment_limit)
6 . Seems, that's all.
lassar
Posts: 306
Joined: Jan 17, 2006 1:35

Re: Access vesa modes in freebasic ?

Post by lassar »

Could you post a example that does this?
monochromator
Posts: 42
Joined: Mar 05, 2013 5:37

Re: Access vesa modes in freebasic ?

Post by monochromator »

This is small example of working with VESA in FreeBASIC for DOS.
It contains analogs of ScreenList, ScreenRes, Pset, Cls and Line FreeBASIC subroutines.
During work program enumerates all accessible graphic modes with 8-bit color depth,
sets mode with resolution 640x480x8 and draws some graphical primitives.
Program is very simple and contains some comments, but in case of difficulty, ask questions here.

Code: Select all

'$LANG: "fblite"
'$INCLUDE: 'dos\go32.bi'
'$INCLUDE: 'dos\dpmi.bi'

TYPE RealModePtr FIELD = 1
 ROffs AS USHORT
 RSegm AS USHORT
END TYPE

TYPE VbeInfoBlock FIELD = 1
 VbeSignature AS UINTEGER 'VBE Signature
 VbeVersion AS USHORT 'VBE Version
 OemStringPtr AS RealModePtr 'Pointer to OEM String
 Capabilities AS UINTEGER 'Capabilities of graphics cont.
 VideoModePtr AS RealModePtr 'Pointer to Video Mode List
 TotalMemory AS USHORT 'Number of 64kb memory blocks
 OemSoftwareRev AS USHORT 'VBE implementation Software revision
 OemVendorNamePtr AS RealModePtr 'Pointer to Vendor Name String
 OemProductNamePtr AS RealModePtr 'Pointer to Product Name String
 OemProductRevPtr AS RealModePtr 'Pointer to Product Revision String
 VSReserved (0 TO 221) AS UBYTE 'Reserved for VBE implementation scratch area
 OemData (0 TO 255) AS UBYTE 'Data Area for OEM Strings
END TYPE

TYPE ModeInfoBlock FIELD = 1
 'Mandatory information for all VBE revisions
 ModeAttributes AS USHORT 'mode attributes
 WinAAttributes AS UBYTE 'window A attributes
 WinBAttributes AS UBYTE 'window B attributes
 WinGranularity AS USHORT 'window granularity
 WinSize AS USHORT 'window size
 WinASegment AS USHORT 'window A start segment
 WinBSegment AS USHORT 'window B start segment
 WinFuncPtr AS RealModePtr 'pointer to window function
 BytesPerScanLine AS USHORT 'bytes per scan line
 'Mandatory information for VBE 1.2 and above
 XResolution AS USHORT 'horizontal resolution in pixels or chars
 YResolution AS USHORT 'vertical resolution in pixels or chars
 XCharSize AS UBYTE 'character cell width in pixels
 YCharSize AS UBYTE 'character cell height in pixels
 NumberOfPlanes AS UBYTE 'number of memory planes
 BitsPerPixel AS UBYTE 'bits per pixel
 NumberOfBanks AS UBYTE 'number of banks
 MemoryModel AS UBYTE 'memory model type
 BankSize AS UBYTE 'bank size in KB
 NumberOfImagePages AS UBYTE 'number of images
 MBReserved AS UBYTE 'reserved for page function
 'Direct Color fields (required for direct/6 and YUV/7 memory models)
 RedMaskSize AS UBYTE 'size of direct color red mask in bits
 RedFieldPosition AS UBYTE 'bit position of lsb of red mask
 GreenMaskSize AS UBYTE 'size of direct color green mask in bits
 GreenFieldPosition AS UBYTE 'bit position of lsb of green mask
 BlueMaskSize AS UBYTE 'size of direct color blue mask in bits
 BlueFieldPosition AS UBYTE 'bit position of lsb of blue mask
 RsvdMaskSize AS UBYTE 'size of direct color reserved mask in bits
 RsvdFieldPosition AS UBYTE 'bit position of lsb of reserved mask
 DirectColorModeInfo AS UBYTE 'direct color mode attributes
 'Mandatory information for VBE 2.0 and above
 PhysBasePtr AS UINTEGER 'physical address for flat frame buffer
 OffScreenMemOffset AS UINTEGER 'pointer to start of off screen memory
 OffScreenMemSize AS USHORT 'amount of off screen memory in 1k units
 MB2Reserved (0 TO 205) AS UBYTE 'remainder of ModeInfoBlock
END TYPE

DIM SHARED DOSBlock AS USHORT, DOSBlockAddr AS UINTEGER, regs AS __dpmi_regs, UseSelector%
DIM SHARED VBEI AS VbeInfoBlock, VMDI AS ModeInfoBlock, CurNum%, ModeList(1 TO 256) AS USHORT
DIM SHARED TmpUI AS UINTEGER

FUNCTION AllocDOSMem (BYVAL NeedSize%) AS USHORT
ParSize% = NeedSize% \ 16
IF (NeedSize% MOD 16) <> 0 THEN ParSize% = ParSize% + 1
IF (ParSize% > 65535) OR (ParSize% <= 0) THEN AllocDOSMem = 0: EXIT FUNCTION
regs.x.ax = &H4800: regs.x.bx = ParSize%: __dpmi_int(&H21, @regs)
IF BIT(regs.x.flags, 0) THEN AllocDOSMem = 0: ERR = 255: EXIT FUNCTION
ERR = 0: AllocDOSMem = regs.x.ax 'сегмент выделенного блока
END FUNCTION

FUNCTION FreeDOSMem (BYVAL BlockSegm AS USHORT) AS USHORT
regs.x.ax = &H4900: regs.x.es = BlockSegm: __dpmi_int(&H21, @regs)
FreeDOSMem = BIT(regs.x.flags, 0)
END FUNCTION

FUNCTION VSScreenList (NDepth% = 0) AS UINTEGER
STATIC CurDepth%
VSScreenList = 0
IF NDepth% > 0 THEN 'это первое обращение - получаем список доступных режимов
 CurDepth% = 0: CurNum% = 0: tmp$ = "VBE2"
 DOSMEMPUT STRPTR(tmp$), 4, DOSBlockAddr
 regs.x.ax = &H4F00: regs.x.es = DOSBlock: regs.x.di = 0: __dpmi_int(&H10, @regs)
 IF regs.x.ax <> &H4F THEN ERR = 254: EXIT FUNCTION
 DOSMEMGET DOSBlockAddr, LEN(VBEI), @VBEI
 IF VBEI.VbeSignature <> CVL("VESA") THEN ERR = 253: EXIT FUNCTION 'нет верной сигнатуры
 IF VBEI.VbeVersion < &H200 THEN ERR = 252: EXIT FUNCTION 'версия VESA меньше 2.0 - линейный кадровый буфер не поддерживается
 'Считываем список доступных видеорежимов
 DOSMEMGET (CUINT(VBEI.VideoModePtr.RSegm) SHL 4) + VBEI.VideoModePtr.ROffs, 512, @ModeList(1)
 CurDepth% = NDepth%
END IF
'Процедура не вызывалась ранее с явным указанием NDepth% или при построении списка режимов произошла ошибка
IF CurDepth% <= 0 THEN ERR = 251: EXIT FUNCTION
DO
 CurNum% = CurNum% + 1
 IF (CurNum% < LBOUND(ModeList)) OR (CurNum% > UBOUND(ModeList)) THEN EXIT DO
 IF ModeList(CurNum%) = -1 THEN CurDepth% = 0: EXIT DO 'список доступных видеорежимов закончен
 'получим информацию о текущем видеорежиме
 regs.x.ax = &H4F01: regs.x.cx = ModeList(CurNum%)
 regs.x.es = DOSBlock: regs.x.di = 0: __dpmi_int(&H10, @regs)
 IF regs.x.ax <> &H4F THEN CONTINUE DO
 DOSMEMGET DOSBlockAddr, LEN(VMDI), @VMDI 'получаем блок информации о режиме
 'режим не поддерживается или он неграфический - не подходит
 IF NOT (BIT(VMDI.ModeAttributes, 0) AND BIT(VMDI.ModeAttributes, 0)) THEN CONTINUE DO
 'недоступен режим с линейным кадровым буфером
 IF (NOT BIT(VMDI.ModeAttributes, 7)) OR (VMDI.PhysBasePtr = 0) THEN CONTINUE DO
 'неподходящая модель цветности (поддерживаются только упаук ованные пиксели или "прямой цвет")
 IF (VMDI.MemoryModel <> 4) AND (VMDI.MemoryModel <> 6) THEN CONTINUE DO
 IF (VMDI.NumberOfBanks <> 1) OR (VMDI.NumberOfPlanes <> 1) THEN CONTINUE DO
 'количество разрядов цветности не совпадает с искомым
 IF VMDI.BitsPerPixel <> CurDepth% THEN CONTINUE DO
 VSScreenList = (CUINT(VMDI.XResolution) SHL 16) + VMDI.YResolution: EXIT DO
LOOP
IF (CurNum% < LBOUND(ModeList)) OR (CurNum% > UBOUND(ModeList)) THEN CurDepth% = 0 'список доступных видеорежимов закончен
ERR = 0
END FUNCTION

SUB VSScreenRes (NWidth%, NHeight%, NDepth%)
DIM VModeParam AS UINTEGER, minfo as __dpmi_meminfo, UseSize AS UINTEGER
VModeParam = VSScreenList(NDepth%)
DO UNTIL VModeParam = 0
 IF (HiWord(VModeParam) = NWidth%) AND (LoWord(VModeParam) = NHeight%) THEN EXIT DO
 VModeParam = VSScreenList
LOOP
IF (HiWord(VModeParam) <> NWidth%) OR (LoWord(VModeParam) <> NHeight%) THEN
 ERR = 255: EXIT SUB 'подходящего под требования режима не найдено
END IF
'Требуемый режим найден - его номер ModeList(CurNum%). Блок VMDI также уже заполнен.
UseSelector% = __dpmi_allocate_ldt_descriptors(1)
IF UseSelector% = 0 THEN ERR = 254: EXIT SUB
'Создаем дескриптор для обращения к кадровому буферу
UseSize = VMDI.BytesPerScanLine * VMDI.YResolution
IF (UseSize MOD &H1000) <> 0 THEN UseSize = ((UseSize \ &H1000) + 1) * &H1000 'выравниваем размер по целым страницам
minfo.address = VMDI.PhysBasePtr: minfo.size = UseSize
IF __dpmi_physical_address_mapping (@minfo) <> 0 THEN
 ERR = 253: EXIT SUB 'не удалось картировать видеобуфер в линейное адресное пространство
END IF
IF __dpmi_set_segment_base_address(UseSelector%, minfo.address) <> 0 THEN
 ERR = 252: EXIT SUB 'ошибка установки базового адреса
END IF
IF __dpmi_set_segment_limit(UseSelector%, UseSize - 1) <> 0 THEN
 ERR = 251: EXIT SUB 'ошибка установки предела сегмента
END IF
'Видеобуфер к работе подготовлен, соответствующий ему селектор настроен
'Теперь устанавливаем собственно сам графический режим
regs.x.ax = &H4F02: regs.x.bx = BITSET(ModeList(CurNum%), 14): __dpmi_int(&H10, @regs) 'режим с плоским буфером
IF regs.x.ax <> &H4F THEN ERR = 250: EXIT SUB
ERR = 0
END SUB

SUB VSScreenReset ()
'Освобождаем селектор и устанавливаем стандартный текстовый режим
IF UseSelector% <> 0 THEN
 __dpmi_free_ldt_descriptor(UseSelector%): UseSelector% = 0
END IF
regs.x.ax = 0: __dpmi_int(&H10, @regs) 'режим 0 - стандартный текстовый режим
END SUB

SUB VSDrawPset (XP%, YP%, LColor%)
'Выводит точку с координатами (XP%, YP%) цветом LColor%
DIM OfsCount AS UINTEGER
IF (XP% < 0) OR (XP% >= VMDI.XResolution) THEN EXIT SUB
IF (YP% < 0) OR (YP% >= VMDI.YResolution) THEN EXIT SUB
OfsCount = YP% * VMDI.BytesPerScanLine + XP% * (VMDI.BitsPerPixel SHR 3)
ASM
 push es
 push ebx
 mov ebx, [LColor%]
 mov al, [ebx]
 mov ebx, [OfsCount]
 mov es, word ptr [UseSelector%]
 mov es:[ebx], al
 pop ebx
 pop es
END ASM
END SUB

SUB VSCls
'Процедура очистки экрана. Заполняет весь кадровый буфер нулевым цветом
DIM OfsCount AS UINTEGER
OfsCount = VMDI.YResolution * VMDI.BytesPerScanLine
ASM
 push es
 push ecx
 push edi
 xor al, al
 mov ecx, [OfsCount]
 xor edi, edi
 mov es, word ptr [UseSelector%]
 rep stosb
 pop edi
 pop ecx
 pop es
END ASM
END SUB

SUB VSDrawLine (X1%, Y1%, X2%, Y2%, LColor%)
'Рисует отрезок между точками (X1%, Y1%) и (X2%, Y2%) цветом LColor% с помощью алгоритма Брезенхейма
IF ABS(X2% - X1%) >= ABS(Y2% - Y1%) THEN 'наклон прямой меньше 45 градусов
 Deff% = 2 * ABS(Y2% - Y1%): CritDeff% = ABS(X2% - X1%)
 CurY% = Y1%: AddDeff% = 0
 IF X2% > X1% THEN StppX% = 1 ELSE StppX% = -1
 IF Y2% > Y1% THEN StppY% = 1 ELSE StppY% = -1
 FOR CurX% = X1% TO X2% STEP StppX%
  CALL VSDrawPset(CurX%, CurY%, LColor%) 'рисуем текущую точку
  AddDeff% = AddDeff% + Deff%
  IF AddDeff% >= CritDeff% THEN CurY% = CurY% + StppY%: AddDeff% = AddDeff% - 2 * CritDeff%
 NEXT CurX%
ELSE 'наклон прямой больше 45 градусов
 Deff% = 2 * ABS(X2% - X1%): CritDeff% = ABS(Y2% - Y1%)
 CurX% = X1%: AddDeff% = 0
 IF X2% > X1% THEN StppX% = 1 ELSE StppX% = -1
 IF Y2% > Y1% THEN StppY% = 1 ELSE StppY% = -1
 FOR CurY% = Y1% TO Y2% STEP StppY%
  CALL VSDrawPset(CurX%, CurY%, LColor%) 'рисуем текущую точку
  AddDeff% = AddDeff% + Deff%
  IF AddDeff% >= CritDeff% THEN CurX% = CurX% + StppX%: AddDeff% = AddDeff% - 2 * CritDeff%
 NEXT CurY%
END IF
END SUB

UseSelector% = 0: DOSBlock = AllocDOSMem(4096) 'выделяем блок нижней памяти в 4к
DOSBlockAddr = CUINT(DOSBlock) SHL 4 'линейный адрес выделенного блока
PRINT "Список доступных 8-битовых графических режимов"
TmpUI = VSScreenList(8)
IF ERR <> 0 THEN
 PRINT "Ошибка при вызове ScreenList - "; ERR: END 255
END IF
WHILE TmpUI <> 0
 PRINT "Режим"; CurNum%; " разрешение - "; HiWord(TmpUI);"x"; LoWord(TmpUI); " цветность - "; VMDI.BitsPerPixel
 TmpUI = VSScreenList
WEND
SLEEP
WHILE LEN(INKEY$) > 0: WEND
CALL VSScreenRes(640, 480, 8)
IF ERR <> 0 THEN
 PRINT "Ошибка при вызове ScreenRes - "; ERR: END 255
END IF
FOR r% = 0 TO 639: CALL VSDrawPset(r%, 240, r% MOD 256): NEXT r%
CALL VSDrawLine(0, 100, 639, 100, 100)
CALL VSDrawLine(320, 0, 320, 479, 100)
SLEEP: WHILE LEN(INKEY$) > 0: WEND
CALL VSCls
FOR r% = 0 TO 479 STEP 20
 CALL VSDrawLine(0, r%, 639, r% + 50, r% MOD 256)
NEXT r%
SLEEP: WHILE LEN(INKEY$) > 0: WEND
FOR r% = 479 TO 0 STEP -20
 CALL VSDrawLine(0, r%, 639, r% - 50, r% MOD 256)
NEXT r%
SLEEP: WHILE LEN(INKEY$) > 0: WEND
FOR r% = 0 TO 639 STEP 20
 CALL VSDrawLine(r%, 0, r% + 50, 479, r% MOD 256)
NEXT r%
SLEEP: WHILE LEN(INKEY$) > 0: WEND
FOR r% = 639 TO 0 STEP -20
 CALL VSDrawLine(r%, 0, r% - 50, 479, r% MOD 256)
NEXT r%
SLEEP: WHILE LEN(INKEY$) > 0: WEND
CALL VSScreenReset: DOSBlock = FreeDOSMem(DOSBlock)
END

lassar
Posts: 306
Joined: Jan 17, 2006 1:35

Re: Access vesa modes in freebasic ?

Post by lassar »

Tried to get your code to work in dosbox. It crashed. Page seg and that sort of thing.

What about the DS Fat trick?

I think Freebasic uses the DS Fat trick.

http://www.chelograph.8m.com/html/djgpp ... m#Fat%20DS

I have been trying to get the following code to work.

No luck so far.

Code: Select all


#LANG "fblite"


#define _BORLAND_DOS_REGS 1  // djgpp specific switch


#include "dos/pc.bi"
#include "dos/dos.bi"
#include "dos/go32.bi"
#include "dos/dpmi.bi"


Declare Function __djgpp_nearptr_enable cdecl Alias "__djgpp_nearptr_enable" () As Integer   ' Returns 0 if feature not avail
Declare Sub __djgpp_nearptr_disable cdecl Alias "__djgpp_nearptr_disable" ()   ' Enables protection
extern __djgpp_selector_limit Alias "__djgpp_selector_" As Integer   ' Limit on CS and on DS if prot
extern __djgpp_base_address Alias "__djgpp_base_address" As Integer   ' Used in calculation below


Type SVGA_dos_vbe_vgainfo Field = 1
    VESASignature As UINTEGER     ' /* VESA 4-byte signature              */
    VESAVersion As uShort         ' /* VBE version number                 */
    OEMStringPtr As uInteger      ' /* Pointer to OEM string              */
    Capabilities(0 To 3) As uByte ' /* Capabilities of video card         */
    VideoModePtr As uInteger      ' /* Pointer to supported modes         */
    TotalMemory As uShort         ' /* Number of 64kb memory blocks       */
    OEMSoftwareRev As uShort      ' /* VBE software revision              */
    OEMVendorNamePtr As uInteger  ' /* Pointer to vendor name string      */
    OEMProductNamePtr As uInteger ' /* Pointer to product name string     */
    OEMProductRevPtr As uInteger  ' /* Pointer to product revision string */
    Reserved(0 To 221) As Byte    ' /* Reserved as working space          */
    OEMData(0 To 255) As Byte     ' /* Data area for OEM strings          */
End Type

Type SVGA_dos_vbe_modeinfo
    ModeAttributes As Short         '/* Mode attributes                  */
    WinAAttributes As Byte          '/* Window A attributes              */
    WinBAttributes As Byte          '/* Window B attributes              */
    WinGranularity As Short         '/* Window granularity in k          */
    WinSize As Short                '/* Window size in k                 */
    WinASegment As Short            '/* Window A segment                 */
    WinBSegment As Short            '/* Window B segment                 */
    WinFuncPtr As Any ptr           '/* Pointer to window function       */
    BytesPerScanLine As Short       '/* Bytes per scanline               */
    XResolution As Short            '/* Horizontal resolution            */
    YResolution As Short            '/* Vertical resolution              */
    XCharSize As Byte               '/* Character cell width             */
    YCharSize As Byte               '/* Character cell height            */
    NumberOfPlanes As Byte          '/* Number of memory planes          */
    BitsPerPixel As Byte            '/* Bits per pixel                   */
    NumberOfBanks As Byte           '/* Number of CGA style banks        */
    MemoryModel As Byte             '/* Memory model type                */
    BankSize As Byte                '/* Size of CGA style banks          */
    NumberOfImagePages As Byte      '/* Number of images pages           */
    res1 As Byte                    '/* Reserved                         */
    RedMaskSize As Byte             '/* Size of direct color red mask    */
    RedFieldPosition As Byte        '/* Bit posn of lsb of red mask      */
    GreenMaskSize As Byte           '/* Size of direct color green mask  */
    GreenFieldPosition As Byte      '/* Bit posn of lsb of green mask    */
    BlueMaskSize As Byte            '/* Size of direct color blue mask   */
    BlueFieldPosition As Byte       '/* Bit posn of lsb of blue mask     */
    RsvdMaskSize As Byte            '/* Size of direct color res mask    */
    RsvdFieldPosition As Byte       '/* Bit posn of lsb of res mask      */
    DirectColorModeInfo As Byte     '/* Direct color mode attributes     */
    ' VESA 2.0 variables
    PhysBasePtr As UINTEGER         '/* physical address for flat frame buffer */
    OffScreenMemOffset As UINTEGER  '/* pointer to start of off screen memory */
    OffScreenMemSize As UShort      '/* amount of off screen memory in 1k units */
    res2(0 To 205) As Byte          '/* Pad to 256 byte block size       */
End Type

DECLARE Function DetectVBE%(vbeinfo AS SVGA_dos_vbe_vgainfo)
DECLARE Function GetVBEModeInfo%(modeinfo As SVGA_dos_vbe_modeinfo)
DECLARE SUB MapMemory(Vbe AS SVGA_dos_vbe_modeinfo)
DECLARE Sub Screen18()
DECLARE Sub VESA_End()
DECLARE Sub SetColor(cindex As uByte, redval As uByte, greenval As uByte, blueval As uByte)
DECLARE SUB Box(BYVAL X1 AS LONG,BYVAL X2 AS LONG,BYVAL Y1 AS LONG,BYVAL Y2 AS LONG, BYVAL Col3 AS UBYTE)


DIM DosVbe AS SVGA_dos_vbe_vgainfo
DIM VesaInfo AS SVGA_dos_vbe_modeinfo

DIM SHARED BufferPtr AS UBYTE PTR
DIM Shared VideoPtr AS UBYTE PTR

IF DetectVBE%(DosVbe) THEN
    IF GetVBEModeInfo%(VesaInfo) THEN
		MapMemory VesaInfo
		Screen18    
	END IF
END IF

BufferPtr = VideoPtr

Box 200,400,100,300,4

SLEEP
VESA_End
END

Function DetectVBE%(vbeinfo AS SVGA_dos_vbe_vgainfo)
    Dim regs As __dpmi_regs

    regs.x.ax = &H4F00
    regs.x.di = __tb AND &H0F
    regs.x.es = (__tb shr 4) AND &HFFFF
    
    dosmemput(@vbeinfo, sizeof(SVGA_dos_vbe_vgainfo), __tb)
    __dpmi_int(&H10, @regs)
    dosmemget(__tb, sizeof(SVGA_dos_vbe_vgainfo), @vbeinfo)    
    
    Result% = regs.h.ah
    IF Result% = 0 THEN Return 1
End Function

Function GetVBEModeInfo%(modeinfo As SVGA_dos_vbe_modeinfo)
    Dim Mode AS USHORT

	Mode = BitSet(&H101, 14)

    Dim regs As __dpmi_regs
    
    regs.x.ax = &H4F01
    regs.x.cx = mode
    regs.x.di= __tb AND &H0F
    regs.x.es = (__tb shr 4) AND &HFFFF
    __dpmi_int(&H10, @regs)
    dosmemget(__tb, sizeof(SVGA_dos_vbe_modeinfo), @modeinfo)
    Result% = regs.h.ah
    IF Result% = 0 THEN Return 1
End Function

SUB MapMemory(Vbe AS SVGA_dos_vbe_modeinfo)
    DIM mapping as __dpmi_meminfo

	'selector% = __dpmi_allocate_ldt_descriptors(1)

    __djgpp_nearptr_enable
    
    
    ' map into linear memory 
    mapping.address = Vbe.PhysBasePtr


	mapping.size = 307200
    IF __dpmi_physical_address_mapping(@mapping) <> 0 THEN
        EXIT SUB
    END IF	
    
    VideoPtr = mapping.address + __djgpp_conventional_base
   '__dpmi_free_physical_address_mapping @mapping
END SUB

Sub Screen18()
    DIM Mode AS USHORT
	Mode = BitSet(&H101, 14)
    'Mode = &H101 'OR &B0100000000000000
    Dim regs As REGS
    regs.x.eax = &H4f02
    regs.x.ebx = Mode
    int86(&H10,@regs,@regs)
End Sub

Sub VESA_End()
    DIM mapping as __dpmi_meminfo
    Dim regs As __dpmi_regs
    regs.x.ax = 3
    __dpmi_int(&H10, @regs)
    __dpmi_free_physical_address_mapping(@mapping)
    __djgpp_nearptr_disable()
End Sub

Sub SetColor(cindex As uByte, redval As uByte, greenval As uByte, blueval As uByte)
    outp(&H03c6, &HFF)
    outp(&H03c8, cindex)
    outp(&H03c9, redval)
    outp(&H03c9, greenval)
    outp(&H03c9, blueval)
End Sub


SUB Box(BYVAL X1 AS LONG,BYVAL X2 AS LONG,BYVAL Y1 AS LONG,BYVAL Y2 AS LONG, BYVAL Col3 AS UBYTE)
    DIM DwordCounter AS UINTEGER
    DIM ByteCounter AS UINTEGER
    
    ASM
        
        MOV        EDI,[BufferPtr]
        MOV        EDX,[X1]
        MOV        ECX,[X2]
        CMP        EDX,ECX
        JL         NoSwap1
        MOV        [X1],ECX
        MOV        [X2],EDX
        NoSwap1:
        MOV        ECX,[X2]
        SUB        ECX,[X1]
        INC        ECX
        MOV        EAX,ECX
        SHR        EAX,2
        MOV        [DwordCounter],EAX
        ADD        EDI,[X1]
        
        MOV        EBX,[Y1]       'figure out Video[EDI] starting position
        SHL        EBX,6
        MOV        EDX, EBX
        SHL        EBX,2
        ADD        EDX, EBX
        SHL        EDX,1
        ADD        EDI,EDX
        
        MOV        EBX,[Y2]
        SUB        EBX,[Y1]
        INC        EBX
        MOV        EAX,ECX
        AND        EAX,3
        MOV        [ByteCounter],EAX
        MOV        EDX, 640
        'ADD        EDX,EAX
        SUB        EDX, ECX       'EDX will have Y add value
        MOV        AL, [Col3]
        MOV        AH,AL
        BSWAP      EAX
        MOV        AL, [Col3]
        MOV        AH,AL
        
        DoAgain:
        CLD
        MOV        ECX, [DwordCounter]
        REP        STOSD
        MOV        ECX, [ByteCounter]
        REP        STOSB        
        DEC        EBX
        CMP        EBX,0
        JE         EndBox
        ADD        EDI, EDX
        JMP        DoAgain
        EndBox:
    END ASM
END SUB


monochromator
Posts: 42
Joined: Mar 05, 2013 5:37

Re: Access vesa modes in freebasic ?

Post by monochromator »

Computer is very obscure thing and filled by paradoxes.

The cause of exception, which is observed in program in DOSBOX, is statement SLEEP.

FreeBASIC "SLEEP" in current condition is incompatible with DOSBOX.
Yes, it's hard to believe, but this is a fact.

Try this small example and you receive GPF.

Code: Select all


SLEEP
WHILE LEN(INKEY$) > 0: WEND

This is version of the program without SLEEP, and it works much better.

Code: Select all


'$LANG: "fblite"
'$INCLUDE: 'dos\go32.bi'
'$INCLUDE: 'dos\dpmi.bi'

TYPE RealModePtr FIELD = 1
 ROffs AS USHORT
 RSegm AS USHORT
END TYPE

TYPE VbeInfoBlock FIELD = 1
 VbeSignature AS UINTEGER 'VBE Signature
 VbeVersion AS USHORT 'VBE Version
 OemStringPtr AS RealModePtr 'Pointer to OEM String
 Capabilities AS UINTEGER 'Capabilities of graphics cont.
 VideoModePtr AS RealModePtr 'Pointer to Video Mode List
 TotalMemory AS USHORT 'Number of 64kb memory blocks
 OemSoftwareRev AS USHORT 'VBE implementation Software revision
 OemVendorNamePtr AS RealModePtr 'Pointer to Vendor Name String
 OemProductNamePtr AS RealModePtr 'Pointer to Product Name String
 OemProductRevPtr AS RealModePtr 'Pointer to Product Revision String
 VSReserved (0 TO 221) AS UBYTE 'Reserved for VBE implementation scratch area
 OemData (0 TO 255) AS UBYTE 'Data Area for OEM Strings
END TYPE

TYPE ModeInfoBlock FIELD = 1
 'Mandatory information for all VBE revisions
 ModeAttributes AS USHORT 'mode attributes
 WinAAttributes AS UBYTE 'window A attributes
 WinBAttributes AS UBYTE 'window B attributes
 WinGranularity AS USHORT 'window granularity
 WinSize AS USHORT 'window size
 WinASegment AS USHORT 'window A start segment
 WinBSegment AS USHORT 'window B start segment
 WinFuncPtr AS RealModePtr 'pointer to window function
 BytesPerScanLine AS USHORT 'bytes per scan line
 'Mandatory information for VBE 1.2 and above
 XResolution AS USHORT 'horizontal resolution in pixels or chars
 YResolution AS USHORT 'vertical resolution in pixels or chars
 XCharSize AS UBYTE 'character cell width in pixels
 YCharSize AS UBYTE 'character cell height in pixels
 NumberOfPlanes AS UBYTE 'number of memory planes
 BitsPerPixel AS UBYTE 'bits per pixel
 NumberOfBanks AS UBYTE 'number of banks
 MemoryModel AS UBYTE 'memory model type
 BankSize AS UBYTE 'bank size in KB
 NumberOfImagePages AS UBYTE 'number of images
 MBReserved AS UBYTE 'reserved for page function
 'Direct Color fields (required for direct/6 and YUV/7 memory models)
 RedMaskSize AS UBYTE 'size of direct color red mask in bits
 RedFieldPosition AS UBYTE 'bit position of lsb of red mask
 GreenMaskSize AS UBYTE 'size of direct color green mask in bits
 GreenFieldPosition AS UBYTE 'bit position of lsb of green mask
 BlueMaskSize AS UBYTE 'size of direct color blue mask in bits
 BlueFieldPosition AS UBYTE 'bit position of lsb of blue mask
 RsvdMaskSize AS UBYTE 'size of direct color reserved mask in bits
 RsvdFieldPosition AS UBYTE 'bit position of lsb of reserved mask
 DirectColorModeInfo AS UBYTE 'direct color mode attributes
 'Mandatory information for VBE 2.0 and above
 PhysBasePtr AS UINTEGER 'physical address for flat frame buffer
 OffScreenMemOffset AS UINTEGER 'pointer to start of off screen memory
 OffScreenMemSize AS USHORT 'amount of off screen memory in 1k units
 MB2Reserved (0 TO 205) AS UBYTE 'remainder of ModeInfoBlock
END TYPE

DIM SHARED DOSBlock AS USHORT, DOSBlockAddr AS UINTEGER, regs AS __dpmi_regs, UseSelector%
DIM SHARED VBEI AS VbeInfoBlock, VMDI AS ModeInfoBlock, CurNum%, ModeList(1 TO 256) AS USHORT
DIM SHARED TmpUI AS UINTEGER

FUNCTION AllocDOSMem (BYVAL NeedSize%) AS USHORT
ParSize% = NeedSize% \ 16
IF (NeedSize% MOD 16) <> 0 THEN ParSize% = ParSize% + 1
IF (ParSize% > 65535) OR (ParSize% <= 0) THEN AllocDOSMem = 0: EXIT FUNCTION
regs.x.ax = &H4800: regs.x.bx = ParSize%: __dpmi_int(&H21, @regs)
IF BIT(regs.x.flags, 0) THEN AllocDOSMem = 0: ERR = 255: EXIT FUNCTION
ERR = 0: AllocDOSMem = regs.x.ax 'сегмент выделенного блока
END FUNCTION

FUNCTION FreeDOSMem (BYVAL BlockSegm AS USHORT) AS USHORT
regs.x.ax = &H4900: regs.x.es = BlockSegm: __dpmi_int(&H21, @regs)
FreeDOSMem = BIT(regs.x.flags, 0)
END FUNCTION

FUNCTION VSScreenList (NDepth% = 0) AS UINTEGER
STATIC CurDepth%
VSScreenList = 0
IF NDepth% > 0 THEN 'это первое обращение - получаем список доступных режимов
 CurDepth% = 0: CurNum% = 0: tmp$ = "VBE2"
 DOSMEMPUT STRPTR(tmp$), 4, DOSBlockAddr
 regs.x.ax = &H4F00: regs.x.es = DOSBlock: regs.x.di = 0: __dpmi_int(&H10, @regs)
 IF regs.x.ax <> &H4F THEN ERR = 254: EXIT FUNCTION
 DOSMEMGET DOSBlockAddr, LEN(VBEI), @VBEI
 IF VBEI.VbeSignature <> CVL("VESA") THEN ERR = 253: EXIT FUNCTION 'нет верной сигнатуры
 IF VBEI.VbeVersion < &H200 THEN ERR = 252: EXIT FUNCTION 'версия VESA меньше 2.0 - линейный кадровый буфер не поддерживается
 'Считываем список доступных видеорежимов
 DOSMEMGET (CUINT(VBEI.VideoModePtr.RSegm) SHL 4) + VBEI.VideoModePtr.ROffs, 512, @ModeList(1)
 CurDepth% = NDepth%
END IF
'Процедура не вызывалась ранее с явным указанием NDepth% или при построении списка режимов произошла ошибка
IF CurDepth% <= 0 THEN ERR = 251: EXIT FUNCTION
DO
 CurNum% = CurNum% + 1
 IF (CurNum% < LBOUND(ModeList)) OR (CurNum% > UBOUND(ModeList)) THEN EXIT DO
 IF ModeList(CurNum%) = -1 THEN CurDepth% = 0: EXIT DO 'список доступных видеорежимов закончен
 'получим информацию о текущем видеорежиме
 regs.x.ax = &H4F01: regs.x.cx = ModeList(CurNum%)
 regs.x.es = DOSBlock: regs.x.di = 0: __dpmi_int(&H10, @regs)
 IF regs.x.ax <> &H4F THEN CONTINUE DO
 DOSMEMGET DOSBlockAddr, LEN(VMDI), @VMDI 'получаем блок информации о режиме
 'режим не поддерживается или он неграфический - не подходит
 IF NOT (BIT(VMDI.ModeAttributes, 0) AND BIT(VMDI.ModeAttributes, 0)) THEN CONTINUE DO
 'недоступен режим с линейным кадровым буфером
 IF (NOT BIT(VMDI.ModeAttributes, 7)) OR (VMDI.PhysBasePtr = 0) THEN CONTINUE DO
 'неподходящая модель цветности (поддерживаются только упаук ованные пиксели или "прямой цвет")
 IF (VMDI.MemoryModel <> 4) AND (VMDI.MemoryModel <> 6) THEN CONTINUE DO
 IF (VMDI.NumberOfBanks <> 1) OR (VMDI.NumberOfPlanes <> 1) THEN CONTINUE DO
 'количество разрядов цветности не совпадает с искомым
 IF VMDI.BitsPerPixel <> CurDepth% THEN CONTINUE DO
 VSScreenList = (CUINT(VMDI.XResolution) SHL 16) + VMDI.YResolution: EXIT DO
LOOP
IF (CurNum% < LBOUND(ModeList)) OR (CurNum% > UBOUND(ModeList)) THEN CurDepth% = 0 'список доступных видеорежимов закончен
ERR = 0
END FUNCTION

SUB VSScreenRes (NWidth%, NHeight%, NDepth%)
DIM VModeParam AS UINTEGER, minfo as __dpmi_meminfo, UseSize AS UINTEGER
VModeParam = VSScreenList(NDepth%)
DO UNTIL VModeParam = 0
 IF (HiWord(VModeParam) = NWidth%) AND (LoWord(VModeParam) = NHeight%) THEN EXIT DO
 VModeParam = VSScreenList
LOOP
IF (HiWord(VModeParam) <> NWidth%) OR (LoWord(VModeParam) <> NHeight%) THEN
 ERR = 255: EXIT SUB 'подходящего под требования режима не найдено
END IF
'Требуемый режим найден - его номер ModeList(CurNum%). Блок VMDI также уже заполнен.
UseSelector% = __dpmi_allocate_ldt_descriptors(1)
IF UseSelector% = 0 THEN ERR = 254: EXIT SUB
'Создаем дескриптор для обращения к кадровому буферу
UseSize = VMDI.BytesPerScanLine * VMDI.YResolution
IF (UseSize MOD &H1000) <> 0 THEN UseSize = ((UseSize \ &H1000) + 1) * &H1000 'выравниваем размер по целым страницам
minfo.address = VMDI.PhysBasePtr: minfo.size = UseSize
IF __dpmi_physical_address_mapping (@minfo) <> 0 THEN
 ERR = 253: EXIT SUB 'не удалось картировать видеобуфер в линейное адресное пространство
END IF
IF __dpmi_set_segment_base_address(UseSelector%, minfo.address) <> 0 THEN
 ERR = 252: EXIT SUB 'ошибка установки базового адреса
END IF
IF __dpmi_set_segment_limit(UseSelector%, UseSize - 1) <> 0 THEN
 ERR = 251: EXIT SUB 'ошибка установки предела сегмента
END IF
'Видеобуфер к работе подготовлен, соответствующий ему селектор настроен
'Теперь устанавливаем собственно сам графический режим
regs.x.ax = &H4F02: regs.x.bx = BITSET(ModeList(CurNum%), 14): __dpmi_int(&H10, @regs) 'режим с плоским буфером
IF regs.x.ax <> &H4F THEN ERR = 250: EXIT SUB
ERR = 0
END SUB

SUB VSScreenReset ()
'Освобождаем селектор и устанавливаем стандартный текстовый режим
IF UseSelector% <> 0 THEN
 __dpmi_free_ldt_descriptor(UseSelector%): UseSelector% = 0
END IF
regs.x.ax = 0: __dpmi_int(&H10, @regs) 'режим 0 - стандартный текстовый режим
END SUB

SUB VSDrawPset (XP%, YP%, LColor%)
'Выводит точку с координатами (XP%, YP%) цветом LColor%
DIM OfsCount AS UINTEGER
IF (XP% < 0) OR (XP% >= VMDI.XResolution) THEN EXIT SUB
IF (YP% < 0) OR (YP% >= VMDI.YResolution) THEN EXIT SUB
OfsCount = YP% * VMDI.BytesPerScanLine + XP% * (VMDI.BitsPerPixel SHR 3)
ASM
 push es
 push ebx
 mov ebx, [LColor%]
 mov al, [ebx]
 mov ebx, [OfsCount]
 mov es, word ptr [UseSelector%]
 mov es:[ebx], al
 pop ebx
 pop es
END ASM
END SUB

SUB VSCls
'Процедура очистки экрана. Заполняет весь кадровый буфер нулевым цветом
DIM OfsCount AS UINTEGER
OfsCount = VMDI.YResolution * VMDI.BytesPerScanLine
ASM
 push es
 push ecx
 push edi
 xor al, al
 mov ecx, [OfsCount]
 xor edi, edi
 mov es, word ptr [UseSelector%]
 rep stosb
 pop edi
 pop ecx
 pop es
END ASM
END SUB

SUB VSDrawLine (X1%, Y1%, X2%, Y2%, LColor%)
'Рисует отрезок между точками (X1%, Y1%) и (X2%, Y2%) цветом LColor% с помощью алгоритма Брезенхейма
IF ABS(X2% - X1%) >= ABS(Y2% - Y1%) THEN 'наклон прямой меньше 45 градусов
 Deff% = 2 * ABS(Y2% - Y1%): CritDeff% = ABS(X2% - X1%)
 CurY% = Y1%: AddDeff% = 0
 IF X2% > X1% THEN StppX% = 1 ELSE StppX% = -1
 IF Y2% > Y1% THEN StppY% = 1 ELSE StppY% = -1
 FOR CurX% = X1% TO X2% STEP StppX%
  CALL VSDrawPset(CurX%, CurY%, LColor%) 'рисуем текущую точку
  AddDeff% = AddDeff% + Deff%
  IF AddDeff% >= CritDeff% THEN CurY% = CurY% + StppY%: AddDeff% = AddDeff% - 2 * CritDeff%
 NEXT CurX%
ELSE 'наклон прямой больше 45 градусов
 Deff% = 2 * ABS(X2% - X1%): CritDeff% = ABS(Y2% - Y1%)
 CurX% = X1%: AddDeff% = 0
 IF X2% > X1% THEN StppX% = 1 ELSE StppX% = -1
 IF Y2% > Y1% THEN StppY% = 1 ELSE StppY% = -1
 FOR CurY% = Y1% TO Y2% STEP StppY%
  CALL VSDrawPset(CurX%, CurY%, LColor%) 'рисуем текущую точку
  AddDeff% = AddDeff% + Deff%
  IF AddDeff% >= CritDeff% THEN CurX% = CurX% + StppX%: AddDeff% = AddDeff% - 2 * CritDeff%
 NEXT CurY%
END IF
END SUB

UseSelector% = 0: DOSBlock = AllocDOSMem(4096) 'выделяем блок нижней памяти в 4к
DOSBlockAddr = CUINT(DOSBlock) SHL 4 'линейный адрес выделенного блока
PRINT "Список доступных 8-битовых графических режимов"
TmpUI = VSScreenList(8)
IF ERR <> 0 THEN
 r% = ERR: PRINT "Ошибка при вызове ScreenList - "; r%: END 255
END IF
WHILE TmpUI <> 0
 PRINT "Режим"; CurNum%; " разрешение - "; HiWord(TmpUI);"x"; LoWord(TmpUI); " цветность - "; VMDI.BitsPerPixel
 TmpUI = VSScreenList
WEND
WHILE LEN(INKEY$) = 0: WEND
CALL VSScreenRes(640, 480, 8)
IF ERR <> 0 THEN
 r% = ERR: PRINT "Ошибка при вызове ScreenRes - "; r%: END 255
END IF
FOR r% = 0 TO 639: CALL VSDrawPset(r%, 240, r% MOD 256): NEXT r%
CALL VSDrawLine(0, 100, 639, 100, 100)
CALL VSDrawLine(320, 0, 320, 479, 100)
WHILE LEN(INKEY$) = 0: WEND
CALL VSCls
FOR r% = 0 TO 479 STEP 20
 CALL VSDrawLine(0, r%, 639, r% + 50, r% MOD 256)
NEXT r%
WHILE LEN(INKEY$) = 0: WEND
FOR r% = 479 TO 0 STEP -20
 CALL VSDrawLine(0, r%, 639, r% - 50, r% MOD 256)
NEXT r%
WHILE LEN(INKEY$) = 0: WEND
FOR r% = 0 TO 639 STEP 20
 CALL VSDrawLine(r%, 0, r% + 50, 479, r% MOD 256)
NEXT r%
WHILE LEN(INKEY$) = 0: WEND
FOR r% = 639 TO 0 STEP -20
 CALL VSDrawLine(r%, 0, r% - 50, 479, r% MOD 256)
NEXT r%
WHILE LEN(INKEY$) = 0: WEND
CALL VSScreenReset: DOSBlock = FreeDOSMem(DOSBlock)
END

"Fat DS".

This is version of the program, which uses "Fat DS".

Code: Select all

'Вариант использования VESA с использованием техники ЖИРНОГО DS
'(раздувания селектора DS на все адресное пространство)

'$LANG: "fblite"
'$INCLUDE: 'dos\go32.bi'
'$INCLUDE: 'dos\dpmi.bi'

TYPE RealModePtr FIELD = 1
 ROffs AS USHORT
 RSegm AS USHORT
END TYPE

TYPE VbeInfoBlock FIELD = 1
 VbeSignature AS UINTEGER 'VBE Signature
 VbeVersion AS USHORT 'VBE Version
 OemStringPtr AS RealModePtr 'Pointer to OEM String
 Capabilities AS UINTEGER 'Capabilities of graphics cont.
 VideoModePtr AS RealModePtr 'Pointer to Video Mode List
 TotalMemory AS USHORT 'Number of 64kb memory blocks
 OemSoftwareRev AS USHORT 'VBE implementation Software revision
 OemVendorNamePtr AS RealModePtr 'Pointer to Vendor Name String
 OemProductNamePtr AS RealModePtr 'Pointer to Product Name String
 OemProductRevPtr AS RealModePtr 'Pointer to Product Revision String
 VSReserved (0 TO 221) AS UBYTE 'Reserved for VBE implementation scratch area
 OemData (0 TO 255) AS UBYTE 'Data Area for OEM Strings
END TYPE

TYPE ModeInfoBlock FIELD = 1
 'Mandatory information for all VBE revisions
 ModeAttributes AS USHORT 'mode attributes
 WinAAttributes AS UBYTE 'window A attributes
 WinBAttributes AS UBYTE 'window B attributes
 WinGranularity AS USHORT 'window granularity
 WinSize AS USHORT 'window size
 WinASegment AS USHORT 'window A start segment
 WinBSegment AS USHORT 'window B start segment
 WinFuncPtr AS RealModePtr 'pointer to window function
 BytesPerScanLine AS USHORT 'bytes per scan line
 'Mandatory information for VBE 1.2 and above
 XResolution AS USHORT 'horizontal resolution in pixels or chars
 YResolution AS USHORT 'vertical resolution in pixels or chars
 XCharSize AS UBYTE 'character cell width in pixels
 YCharSize AS UBYTE 'character cell height in pixels
 NumberOfPlanes AS UBYTE 'number of memory planes
 BitsPerPixel AS UBYTE 'bits per pixel
 NumberOfBanks AS UBYTE 'number of banks
 MemoryModel AS UBYTE 'memory model type
 BankSize AS UBYTE 'bank size in KB
 NumberOfImagePages AS UBYTE 'number of images
 MBReserved AS UBYTE 'reserved for page function
 'Direct Color fields (required for direct/6 and YUV/7 memory models)
 RedMaskSize AS UBYTE 'size of direct color red mask in bits
 RedFieldPosition AS UBYTE 'bit position of lsb of red mask
 GreenMaskSize AS UBYTE 'size of direct color green mask in bits
 GreenFieldPosition AS UBYTE 'bit position of lsb of green mask
 BlueMaskSize AS UBYTE 'size of direct color blue mask in bits
 BlueFieldPosition AS UBYTE 'bit position of lsb of blue mask
 RsvdMaskSize AS UBYTE 'size of direct color reserved mask in bits
 RsvdFieldPosition AS UBYTE 'bit position of lsb of reserved mask
 DirectColorModeInfo AS UBYTE 'direct color mode attributes
 'Mandatory information for VBE 2.0 and above
 PhysBasePtr AS UINTEGER 'physical address for flat frame buffer
 OffScreenMemOffset AS UINTEGER 'pointer to start of off screen memory
 OffScreenMemSize AS USHORT 'amount of off screen memory in 1k units
 MB2Reserved (0 TO 205) AS UBYTE 'remainder of ModeInfoBlock
END TYPE

DIM SHARED DOSBlock AS USHORT, DOSBlockAddr AS UINTEGER, regs AS __dpmi_regs, FrameBuffer AS UBYTE PTR
DIM SHARED VBEI AS VbeInfoBlock, VMDI AS ModeInfoBlock, CurNum%, ModeList(1 TO 256) AS USHORT
DIM SHARED TmpUI AS UINTEGER

FUNCTION AllocDOSMem (BYVAL NeedSize%) AS USHORT
ParSize% = NeedSize% \ 16
IF (NeedSize% MOD 16) <> 0 THEN ParSize% = ParSize% + 1
IF (ParSize% > 65535) OR (ParSize% <= 0) THEN AllocDOSMem = 0: EXIT FUNCTION
regs.x.ax = &H4800: regs.x.bx = ParSize%: __dpmi_int(&H21, @regs)
IF BIT(regs.x.flags, 0) THEN AllocDOSMem = 0: ERR = 255: EXIT FUNCTION
ERR = 0: AllocDOSMem = regs.x.ax 'сегмент выделенного блока
END FUNCTION

FUNCTION FreeDOSMem (BYVAL BlockSegm AS USHORT) AS USHORT
regs.x.ax = &H4900: regs.x.es = BlockSegm: __dpmi_int(&H21, @regs)
FreeDOSMem = BIT(regs.x.flags, 0)
END FUNCTION

FUNCTION VSScreenList (NDepth% = 0) AS UINTEGER
STATIC CurDepth%
VSScreenList = 0
IF NDepth% > 0 THEN 'это первое обращение - получаем список доступных режимов
 CurDepth% = 0: CurNum% = 0: tmp$ = "VBE2"
 DOSMEMPUT STRPTR(tmp$), 4, DOSBlockAddr
 regs.x.ax = &H4F00: regs.x.es = DOSBlock: regs.x.di = 0: __dpmi_int(&H10, @regs)
 IF regs.x.ax <> &H4F THEN ERR = 254: EXIT FUNCTION
 DOSMEMGET DOSBlockAddr, LEN(VBEI), @VBEI
 IF VBEI.VbeSignature <> CVL("VESA") THEN ERR = 253: EXIT FUNCTION 'нет верной сигнатуры
 IF VBEI.VbeVersion < &H200 THEN ERR = 252: EXIT FUNCTION 'версия VESA меньше 2.0 - линейный кадровый буфер не поддерживается
 'Считываем список доступных видеорежимов
 DOSMEMGET (CUINT(VBEI.VideoModePtr.RSegm) SHL 4) + VBEI.VideoModePtr.ROffs, 512, @ModeList(1)
 CurDepth% = NDepth%
END IF
'Процедура не вызывалась ранее с явным указанием NDepth% или при построении списка режимов произошла ошибка
IF CurDepth% <= 0 THEN ERR = 251: EXIT FUNCTION
DO
 CurNum% = CurNum% + 1
 IF (CurNum% < LBOUND(ModeList)) OR (CurNum% > UBOUND(ModeList)) THEN EXIT DO
 IF ModeList(CurNum%) = -1 THEN CurDepth% = 0: EXIT DO 'список доступных видеорежимов закончен
 'получим информацию о текущем видеорежиме
 regs.x.ax = &H4F01: regs.x.cx = ModeList(CurNum%)
 regs.x.es = DOSBlock: regs.x.di = 0: __dpmi_int(&H10, @regs)
 IF regs.x.ax <> &H4F THEN CONTINUE DO
 DOSMEMGET DOSBlockAddr, LEN(VMDI), @VMDI 'получаем блок информации о режиме
 'режим не поддерживается или он неграфический - не подходит
 IF NOT (BIT(VMDI.ModeAttributes, 0) AND BIT(VMDI.ModeAttributes, 0)) THEN CONTINUE DO
 'недоступен режим с линейным кадровым буфером
 IF (NOT BIT(VMDI.ModeAttributes, 7)) OR (VMDI.PhysBasePtr = 0) THEN CONTINUE DO
 'неподходящая модель цветности (поддерживаются только упаук ованные пиксели или "прямой цвет")
 IF (VMDI.MemoryModel <> 4) AND (VMDI.MemoryModel <> 6) THEN CONTINUE DO
 IF (VMDI.NumberOfBanks <> 1) OR (VMDI.NumberOfPlanes <> 1) THEN CONTINUE DO
 'количество разрядов цветности не совпадает с искомым
 IF VMDI.BitsPerPixel <> CurDepth% THEN CONTINUE DO
 VSScreenList = (CUINT(VMDI.XResolution) SHL 16) + VMDI.YResolution: EXIT DO
LOOP
IF (CurNum% < LBOUND(ModeList)) OR (CurNum% > UBOUND(ModeList)) THEN CurDepth% = 0 'список доступных видеорежимов закончен
ERR = 0
END FUNCTION

SUB VSScreenRes (NWidth%, NHeight%, NDepth%)
DIM VModeParam AS UINTEGER, minfo as __dpmi_meminfo, UseSize AS UINTEGER, DSAddr AS UINTEGER
VModeParam = VSScreenList(NDepth%)
DO UNTIL VModeParam = 0
 IF (HiWord(VModeParam) = NWidth%) AND (LoWord(VModeParam) = NHeight%) THEN EXIT DO
 VModeParam = VSScreenList
LOOP
IF (HiWord(VModeParam) <> NWidth%) OR (LoWord(VModeParam) <> NHeight%) THEN
 ERR = 255: EXIT SUB 'подходящего под требования режима не найдено
END IF
'Требуемый режим найден - его номер ModeList(CurNum%). Блок VMDI также уже заполнен.
'Картируем видеобуфер в пространство линейных адресов
UseSize = VMDI.BytesPerScanLine * VMDI.YResolution
IF (UseSize MOD &H1000) <> 0 THEN UseSize = ((UseSize \ &H1000) + 1) * &H1000 'выравниваем размер по целым страницам
minfo.address = VMDI.PhysBasePtr: minfo.size = UseSize
IF __dpmi_physical_address_mapping (@minfo) <> 0 THEN
 ERR = 254: EXIT SUB 'не удалось картировать видеобуфер в линейное адресное пространство
END IF
DSSelector% = 0
ASM mov word ptr [DSSelector], ds
IF __dpmi_set_segment_limit(DSSelector%, &HFFFFFFFF) <> 0 THEN
 ERR = 253: EXIT SUB 'ошибка установки предела сегмента
END IF
IF __dpmi_get_segment_base_address(DSSelector%, @DSAddr) <> 0 THEN
 ERR = 252: EXIT SUB 'ошибка получения базового адреса сегмента
END IF
IF minfo.address < DSAddr THEN 'сегмент начинается за видеобуфером - исправляем
 IF __dpmi_set_segment_base_address(DSSelector%, minfo.address - 2) <> 0 THEN
  ERR = 251: EXIT SUB 'ошибка установки базового адреса
 END IF
 DSAddr = minfo.address - 2
END IF
FrameBuffer = CAST(UBYTE PTR, minfo.address - DSAddr)
'Видеобуфер к работе подготовлен, соответствующий ему указатель настроен
'Теперь устанавливаем собственно сам графический режим
regs.x.ax = &H4F02: regs.x.bx = BITSET(ModeList(CurNum%), 14): __dpmi_int(&H10, @regs) 'режим с плоским буфером
IF regs.x.ax <> &H4F THEN ERR = 250: EXIT SUB
ERR = 0
END SUB

SUB VSScreenReset ()
'Освобождаем селектор и устанавливаем стандартный текстовый режим
regs.x.ax = 0: __dpmi_int(&H10, @regs) 'режим 0 - стандартный текстовый режим
END SUB

SUB VSDrawPset (XP%, YP%, LColor%)
'Выводит точку с координатами (XP%, YP%) цветом LColor%
DIM OfsCount AS UINTEGER
IF (XP% < 0) OR (XP% >= VMDI.XResolution) THEN EXIT SUB
IF (YP% < 0) OR (YP% >= VMDI.YResolution) THEN EXIT SUB
OfsCount = YP% * VMDI.BytesPerScanLine + XP% * (VMDI.BitsPerPixel SHR 3)
*(FrameBuffer + OfsCount) = LColor%
END SUB

SUB VSCls
'Процедура очистки экрана. Заполняет весь кадровый буфер нулевым цветом
CALL CLEAR (*FrameBuffer, 0, VMDI.YResolution * VMDI.BytesPerScanLine)
END SUB

SUB VSDrawLine (X1%, Y1%, X2%, Y2%, LColor%)
'Рисует отрезок между точками (X1%, Y1%) и (X2%, Y2%) цветом LColor% с помощью алгоритма Брезенхейма
IF ABS(X2% - X1%) >= ABS(Y2% - Y1%) THEN 'наклон прямой меньше 45 градусов
 Deff% = 2 * ABS(Y2% - Y1%): CritDeff% = ABS(X2% - X1%)
 CurY% = Y1%: AddDeff% = 0
 IF X2% > X1% THEN StppX% = 1 ELSE StppX% = -1
 IF Y2% > Y1% THEN StppY% = 1 ELSE StppY% = -1
 FOR CurX% = X1% TO X2% STEP StppX%
  CALL VSDrawPset(CurX%, CurY%, LColor%) 'рисуем текущую точку
  AddDeff% = AddDeff% + Deff%
  IF AddDeff% >= CritDeff% THEN CurY% = CurY% + StppY%: AddDeff% = AddDeff% - 2 * CritDeff%
 NEXT CurX%
ELSE 'наклон прямой больше 45 градусов
 Deff% = 2 * ABS(X2% - X1%): CritDeff% = ABS(Y2% - Y1%)
 CurX% = X1%: AddDeff% = 0
 IF X2% > X1% THEN StppX% = 1 ELSE StppX% = -1
 IF Y2% > Y1% THEN StppY% = 1 ELSE StppY% = -1
 FOR CurY% = Y1% TO Y2% STEP StppY%
  CALL VSDrawPset(CurX%, CurY%, LColor%) 'рисуем текущую точку
  AddDeff% = AddDeff% + Deff%
  IF AddDeff% >= CritDeff% THEN CurX% = CurX% + StppX%: AddDeff% = AddDeff% - 2 * CritDeff%
 NEXT CurY%
END IF
END SUB

DOSBlock = AllocDOSMem(4096) 'выделяем блок нижней памяти в 4к
DOSBlockAddr = CUINT(DOSBlock) SHL 4 'линейный адрес выделенного блока
PRINT "Список доступных 8-битовых графических режимов"
TmpUI = VSScreenList(8)
IF ERR <> 0 THEN
 r% = ERR: PRINT "Ошибка при вызове ScreenList - "; r%: END 255
END IF
WHILE TmpUI <> 0
 PRINT "Режим"; CurNum%; " разрешение - "; HiWord(TmpUI);"x"; LoWord(TmpUI); " цветность - "; VMDI.BitsPerPixel
 TmpUI = VSScreenList
WEND
WHILE LEN(INKEY$) = 0: WEND
CALL VSScreenRes(640, 480, 8)
IF ERR <> 0 THEN
 r% = ERR: PRINT "Ошибка при вызове ScreenRes - "; r%: END 255
END IF
FOR r% = 0 TO 639: CALL VSDrawPset(r%, 240, r% MOD 256): NEXT r%
CALL VSDrawLine(0, 100, 639, 100, 100)
CALL VSDrawLine(320, 0, 320, 479, 100)
WHILE LEN(INKEY$) = 0: WEND
CALL VSCls
FOR r% = 0 TO 479 STEP 20
 CALL VSDrawLine(0, r%, 639, r% + 50, r% MOD 256)
NEXT r%
WHILE LEN(INKEY$) = 0: WEND
FOR r% = 479 TO 0 STEP -20
 CALL VSDrawLine(0, r%, 639, r% - 50, r% MOD 256)
NEXT r%
WHILE LEN(INKEY$) = 0: WEND
FOR r% = 0 TO 639 STEP 20
 CALL VSDrawLine(r%, 0, r% + 50, 479, r% MOD 256)
NEXT r%
WHILE LEN(INKEY$) = 0: WEND
FOR r% = 639 TO 0 STEP -20
 CALL VSDrawLine(r%, 0, r% - 50, 479, r% MOD 256)
NEXT r%
WHILE LEN(INKEY$) = 0: WEND
CALL VSScreenReset: DOSBlock = FreeDOSMem(DOSBlock)
END

Results of testing:
Both programs work excellently in pure DOS (FreeDOS 1.1, MS-DOS 7.1) and in Win98 DOS session.
Also both programs work reasonably good in DOSBOX 0.74 ("Fat DS" version periodically
crashes DOSBOX, the cause is still unclear).

NTVDM DPMI server in Windows XP don't support mapping of physical memory regions
(0800h function). Seems, applying of flat frame buffer is impossible there at all.
At least, I do not know how to do it.
lassar
Posts: 306
Joined: Jan 17, 2006 1:35

Re: Access vesa modes in freebasic ?

Post by lassar »

It is still page faulting in dosbox and virtual pc.

I am using CWSDPMI for the DPMI server.

What dpmi server are you using?
monochromator
Posts: 42
Joined: Mar 05, 2013 5:37

Re: Access vesa modes in freebasic ?

Post by monochromator »

For DOS I use CWSDPMI r7.

May you use earlier version of CWSDPMI?

As far as I remember, version 3 is really less stable.

PS. Additionally i tested both programs in FreeDOS 1.1 under VirtualBox. All work excellently.
lassar
Posts: 306
Joined: Jan 17, 2006 1:35

Re: Access vesa modes in freebasic ?

Post by lassar »

Okay I am still having trouble with page faults. What version of freebasic are you using.
monochromator
Posts: 42
Joined: Mar 05, 2013 5:37

Re: Access vesa modes in freebasic ?

Post by monochromator »

I use FreeBASIC 0.25, which was downloaded from github in form of source code
approximately three months before.
At this link (http://tempfile.ru/file/2888375) there are executable files of the both programs. Try
execute it directly without compilation.
lassar
Posts: 306
Joined: Jan 17, 2006 1:35

Re: Access vesa modes in freebasic ?

Post by lassar »

I got my version of it to work!

I managed to cut and paste you fat ds part.

What I like about the fat ds is, that I don't have to change my assembly code.

I can now get RadioTelephone Tutor to run speedy in dosbox at 500 cycles!

Freebasic updating the framebuffer was really making the keyboard interface sluggish at 500 cycles.

The interface is definitely not sluggish now.
Last edited by lassar on Jul 05, 2013 21:22, edited 1 time in total.
rugxulo
Posts: 219
Joined: Jun 30, 2006 5:31
Location: Usono (aka, USA)
Contact:

Re: Access vesa modes in freebasic ?

Post by rugxulo »

monochromator wrote:NTVDM DPMI server in Windows XP don't support mapping of physical memory regions
(0800h function). Seems, applying of flat frame buffer is impossible there at all.
At least, I do not know how to do it.
VESA graphics under XP's NTVDM are probably a lost cause (though way better than Vista/7/8). I think there are some third-party hacks to get it working there, but I don't remember the details (and never tried and don't have XP anymore to test, sadly). The person to ask would probably be RayeR from BTTR Forum as he seemed fairly knowledgeable about such things.

Otherwise, it's probably best to use DOSEMU or VirtualBox or even native FreeDOS (e.g. atop bootable USB from RUFUS).
lassar
Posts: 306
Joined: Jan 17, 2006 1:35

Re: Access vesa modes in freebasic ?

Post by lassar »

Thank you monochromator for reply to my post and helping me out with my code.

I managed to get GFX_NULL vesa mouse routines working.

Here is the link to it in tricks and tips.

Again I say thank you.
Post Reply