News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

several video pages

Started by ghjjkl, July 18, 2014, 12:35:14 AM

Previous topic - Next topic

ghjjkl

it's me again. And another thing to be considered. I've tried to implement two components of picture to be drawn on screen. First component must be persitent, "background". Second component should be re-drawn every main cycle's step. First component is drawn first. I decided to use video pages to get this effect, but failed. VGA adapter has 256 kB memory. Problem is that to use video pages i have to enable bit planes. It means that i have to change video pages every pixel, if i draw line by line. If it would be usual addressing, to put pixels to first page i should write to es:0000,es:0004,es:0008,es:000C,...; to put pixels to second page i should write to es:0001,es:0005,es:0009,es:000D,...; to put pixels to third page i should write to es:0002,es:0006,es:000A,es:000E,...; and so on. But i need this memory to be addressed continually. First 64000 bytes must match first video page, next 64000  bytes must match second video page, and so on. Is that possible?

MichaelW

For the VGA you are limited to a 64KB window in the host address space, and basically all of your accesses into the display buffer must be through that window. If what you are trying to do is move a "sprite" over a fixed background, nondestructively, while the VGA probably supports multiple more or less complex methods of doing it, there is a simple method. Basically, the code that draws the sprite needs to save the portion of the background image that the sprite will overlay, and restore the saved background each time the sprite is moved. Implementing this for mode 13h should be fairly simple.
Well Microsoft, here's another nice mess you've gotten us into.

Gunther

Hi ghjjkl,

as Michael mentioned, in Real Mode you're limited to 64 KB. Another approach would be the Protected Mode with the linear frame buffer above 1 MB. So you can use 2 or 3 screens at the same time.

Gunther
You have to know the facts before you can distort them.

ghjjkl

but why couldn't they organize memory as i wrote?I wonder, why are these "bit planes"? Why didn't they do continuous space? In that case i could simply change video page and stored data to A000h:XXXX as usual  :(

Gunther

Hi ghjjkl,

Quote from: ghjjkl on July 18, 2014, 09:33:59 PM
but why couldn't they organize memory as i wrote?I wonder, why are these "bit planes"?

it's a question of simple arithmetics. You have a 64 KB memory window starting at A000h for your graphics data. The standard VGA with 640x480 and 16 colors needs 640 * 480 * 4 = 1228800 bit = 153600 byte = 150 KB. That doesn't fit into the 64 KB window and must be organized in 4 bit planes.

If you would like to experiment with VGA graphics programming, you should read first the standard book by Michael Abrash. That's my advice.

Gunther
You have to know the facts before you can distort them.

MichaelW

Quote from: ghjjkl on July 18, 2014, 09:33:59 PM
Why didn't they do continuous space?

They did do a continuous space, but unless someone has developed a "trick" for doing so, it's not accessible from Real Mode. See Gunther's post in reply #2, specifically "Protected Mode with the linear frame buffer". In Real Mode, for some of the display modes the handling of the bit planes is automatic, for example mode 13h, but for others you must effectively program the VGA hardware to do it (or use the VGA BIOS functions) . This code uses one of several possible methods to write the color for a single pixel to all four bit planes in mode 12h:

;==============================================================================
.model small,c
.386
.stack
;==============================================================================

SetPixel_12   PROTO x:WORD,y:WORD,color:WORD
WaitKey       PROTO

;==============================================================================

;--------------------------------------------------------------------
; Host I/O ports for Graphics Controller Address and Data Registers:
;--------------------------------------------------------------------

GraphicsAddressRegister   equ 3ceh
GraphicsDataRegister      equ 3cfh

;---------------------------------------------------------
; Index value for Graphics Controller Set/Reset Register:
;---------------------------------------------------------

SetResetIndex             equ 0

;----------------------------------------------------------------
; Index value for Graphics Controller Enable Set/Reset Register:
;----------------------------------------------------------------

EnableSetResetIndex       equ 1

;--------------------------------------------------------
; Index value for Graphics Controller Bit Mask Register:
;--------------------------------------------------------

BitMaskIndex              equ 8

;-------------------------------------------------------------------
; Macro to wite a value to an 8-bit I/O port in a single statement.
;-------------------------------------------------------------------

outp MACRO port, val
  mov   dx, port
  mov   ax, val
  out   dx, al
ENDM

;==============================================================================
.data
.code
.startup
;==============================================================================

    mov   ax, 0a000h
    mov   es, ax

    mov   ax, 12h
    int   10h

    invoke SetPixel_12, 320, 240, 15

    call waitkey

.exit

;----------------------------------------------------------
; This proc assumes that the VGA is operating in mode 12h,
; and that ES has been loaded with the segment address of
; the graphics display buffer.
;
; This proc uses the Set/Reset function to write the color
; value for a single pixel to all four bit planes. This
; entails enabling all four bit planes in the Set/Reset
; register, loading the color value into the Set/Reset
; register, and setting the Bit Mask register so the
; write operation will affect only the target pixel.
;----------------------------------------------------------

SetPixel_12 proc uses ax bx cx dx x:WORD,y:WORD,color:WORD

    outp GraphicsAddressRegister,EnableSetResetIndex
    outp GraphicsDataRegister,0fh
    outp GraphicsAddressRegister,SetResetIndex
    outp GraphicsDataRegister, color
    outp GraphicsAddressRegister,BitMaskIndex

    mov   cx, x         ; bit mask = 80h>>(x&7)
    and   cx, 7
    mov   ax, 80h
    shr   ax, cl
    outp GraphicsDataRegister,ax

    mov   ax, y         ; pixel byte address = y*80+(x>>3)
    mov   cx, 80
    mul   cx
    mov   bx, ax
    mov   cx, x
    shr   cx, 3
    add   bx, cx

    ;--------------------------------------------------
    ; Perform a dummy write to the addressed byte.
    ; The color value for the addressed pixel will be
    ; supplied by the Set/Reset register.
    ;--------------------------------------------------

    mov   BYTE PTR es:[bx], 0

    ;------------------------------------------------------
    ; Restore the Bit Mask and Enable Set/Reset registers
    ; to their default values.
    ;------------------------------------------------------

    outp GraphicsAddressRegister,BitMaskIndex
    outp GraphicsDataRegister,0ffh
    outp GraphicsAddressRegister,EnableSetResetIndex
    outp GraphicsDataRegister,0

    ret

SetPixel_12 endp

; ---------------------------------------------------------
; This proc calls the BIOS Read Keyboard Status and Read
; Keyboard Input functions to flush the keyboard buffer,
; wait for a key press, and then flush the buffer again,
; leaving it empty. The BIOS scan code for the key pressed
; is returned in AH and the character code in AL.
; ---------------------------------------------------------

WaitKey proc
  @@:
    mov   ah, 1
    int   16h                   ; Check for key press
    jz    @F                    ; Jump if buffer empty
    mov   ah, 0
    int   16h                   ; Get key
    jmp   @B                    ; Repeat
  @@:
    mov   ah, 1
    int   16h                   ; Check for key press
    jz    @B                    ; Repeat
    mov   ah, 0
    int   16h                   ; Get key
    push  ax                   ; Preserve it
  @@:
    mov   ah, 1
    int   16h                   ; Check for key press
    jz    @F                    ; Jump if buffer empty
    mov   ah, 0
    int   16h                   ; Get key
    jmp   @B                    ; Repeat
  @@:
    pop   ax                    ; Recover key
    ret
WaitKey endp

end

Well Microsoft, here's another nice mess you've gotten us into.

ghjjkl

MichaelW, thanks for that code! I've tried something like that, but i used mode 0dh. But there's too many actions for single pixel still   :(
Where could i read about ports like 3ceh,3dfh,3c4h and so on?

ghjjkl

#7
Quote from: ghjjkl on July 19, 2014, 04:30:37 PM
I've tried something like that, but i used mode 0dh.
Here:


mov dx,3c4h
mov ax,0102h ;ah - color as i suppose, al - index for port 3c5h (02 means map mask register)
out dx,ax
mov di,0
xor bx,bx
mov byte ptr es:[bx],10000000b ;to put blue point to upper left corner


but it's too complicated, if i want to draw several images. For every pixel i must access port 3c4h. For mode 13h i could simply read data from buffer and store that color i want, without any "extra" actions, like this


buffer db 0,1,2,3,4,5,6,7,8,9
(...)
mov ax,offset buffer
mov ds, ax
mov ax,0a000h
mov es,ax
xor si,si
xor di,di
mov cx,10
rep movsb

MichaelW

Quote from: ghjjkl on July 19, 2014, 04:30:37 PM
Where could i read about ports like 3ceh,3dfh,3c4h and so on?

The reference I use is available, among other places, here.

Quote
I've tried something like that, but i used mode 0dh. But there's too many actions for single pixel still

I think at least in the general case there is no need to access the map mask register for each pixel. In one of the code examples from Richard Ferraro's book, he sets the map mask register once per bit plane, and then writes an entire plane of data.

Doing VGA graphics there is no way to avoid executing a large number of instructions, but because I/O port accesses are relatively slow you should avoid doing them unnecessarily.

Quote from: ghjjkl on July 19, 2014, 06:30:11 PM
Here:


mov dx,3c4h
mov ax,0102h ;ah - color as i suppose, al - index for port 3c5h (02 means map mask register)
out dx,ax
mov di,0
xor bx,bx
mov byte ptr es:[bx],10000000b ;to put blue point to upper left corner


but it's to complicated, if i want to draw several images. For every pixel i must access port 3c4h.

Your code is not accessing the map mask register correctly. For the VGA, to avoid using an excessive number of I/O port addresses, the Sequencer, CRT Controller, Graphics Controller, and Attribute Controller (*) registers are accessed indirectly, using an address port and a data port. To access a register you output the register index to the address port and then do the access through the data port. My mode 12h code above shows how to do this.

* all but one group

It would be a lot easier for us to answer your questions if you would provide a detailed description of what you are trying to do.
Well Microsoft, here's another nice mess you've gotten us into.

ghjjkl

Quote from: MichaelW on July 21, 2014, 04:35:09 PM
It would be a lot easier for us to answer your questions if you would provide a detailed description of what you are trying to do.
well, then i tell you about some problems i've met.

Lets imagine that we need to draw some image:



img BYTE 0,0,0,1,0,0,0,0   
      BYTE 0,1,0,0,4,1,0,0
      BYTE 0,0,1,1,0,0,1,0
      BYTE 0,2,0,1,1,0,0,0
      BYTE 1,0,0,0,1,3,0,0
      BYTE 0,0,0,1,0,0,0,0
      BYTE 0,1,0,3,0,0,1,0
      BYTE 0,0,1,0,0,1,0,3



so its width is 8, height is 8 too.

if i need it to be drawn, i could use this:



screenWidth equ 320

draw_ proc near c  uses cx pos:WORD,_off:WORD,_width:WORD,height:WORD
mov di,pos
mov si,_off
        mov ax,height
.while ax>0
mov cx,_width
rep movsb
sub di,slice
add di,screenWidth
dec ax
.endw
ret
draw_ endp


but there are several problems:

- if i dont want image's zero bytes to cover other images, i have to skip these bytes so all images are drawn more slowly 
- 256 colors are too many for my needings. 16 would be nice, but in that case i have to pack two colors into one byte, and this means i have to perform many extra actions to draw such images, it's bad for performance too

to meet my demands i decided to use another video mode instead 13h.
But problem is that there are no modes that have memory space which could be whether addressed or accessed as easy as 13h and would demand significantly less memory than 13h.

Gunther

Quote from: ghjjkl on July 21, 2014, 06:43:29 PM
to meet my demands i decided to use another video mode instead 13h.
But problem is that there are no modes that have memory space which could be whether addressed or accessed as easy as 13h and would demand significantly less memory than 13h.

There are only 2 ways to go:

  • Use a SVGA mode with a VESA driver.
  • Try ModX

Gunther
You have to know the facts before you can distort them.

FORTRANS

Quote from: ghjjkl on July 21, 2014, 06:43:29 PM
but there are several problems:

- if i dont want image's zero bytes to cover other images, i have to skip these bytes so all images are drawn more slowly 
- 256 colors are too many for my needings. 16 would be nice, but in that case i have to pack two colors into one byte, and this means i have to perform many extra actions to draw such images, it's bad for performance too

Hi,

   If you do not need more than 16 colors, you can use multiple
palettes in mode 13H.  You can assign the background to the first
sixteen entries (low nybble of color byte).  Then assign colors for
the foreground objects to the high four bits (with redundant entries
in the low bits).  XORing the foreground object with the background
will leave the background unchanged with zero bytes in the foreground
object.  Of course, after doing this, some of the high bits will be set,
so you will have to work around that before the next round of XORing.

Steve

FORTRANS

Hi,

QuoteIf you do not need more than 16 colors, you can use multiple
palettes in mode 13H.  You can assign the background to the first
sixteen entries (low nybble of color byte).  Then assign colors for
the foreground objects to the high four bits (with redundant entries
in the low bits).  XORing the foreground object with the background
will leave the background unchanged with zero bytes in the foreground
object.

   Well, I implemented a variation on this idea.  Just to see how it
works out.  The background is a 16 color TGA picture.  The sprite
uses a simple palette and shows transparency.  Clumsy, and not
too practical, but it is what it is.

Cheers,

Steve

MichaelW

If I recall correctly in mode 13h, and assuming the default palette and color register values, the first 16 colors (0-15) by design match the colors for the 16-color modes.
Well Microsoft, here's another nice mess you've gotten us into.

dedndave

if i remember correctly, the DAC values are 6-bits only
so, 0 is for no luminance in that color, and 3Fh is full luminance
i don't remember the order for colors, but guessing R, G, B
;
; set video mode 13h
;
        MOV     AX,13h
        INT     10h
;
; set DAC registers
;
        XOR     BX,BX
        MOV     CX,COLORS       ;number of colors
        MOV     DX,OFS PAL13A   ;address of pallette
        MOV     AX,1012h
        INT     10h
;
; set overscan register
;
        MOV     BH,0
        MOV     AX,1001h
        INT     10h