1. Faster pixel() in SVGA

The following code demonstrates how to write to SVGA video memory.  It
does not perform any clipping at screen edges.  The procedure svga_info
must be called with the graphic mode number before calling pixel or
display_image.  Performance is optimized when pixel writes are done in
small vertical increments.

---- code begins ----
include machine.e

sequence regs, dummy
integer bank_start, bytes_per_line, bank_granularity
bank_start = 0

regs = repeat(0, 10)
regs[REG_AX] = #4F05
regs[REG_BX] = #0000

global procedure pixel(object data, sequence p)
    integer offset, len
    if atom(data) then
        len = 1
    else
        len = length(data)
    end if
    offset = p[2] * bytes_per_line + p[1]
    if offset < bank_start or offset + len > bank_start + 65536 then
        regs[REG_DX] = floor(offset / bank_granularity)
        dummy = dos_interrupt(#10, regs)
        bank_start = regs[REG_DX] * bank_granularity
    end if
    poke(#A0000 + offset - bank_start, data)
end procedure

global procedure display_image(sequence p, sequence data)
    for y = 1 to length(data) do
        pixel(data[y], p)
        p[2] = p[2] + 1
    end for
end procedure

global procedure svga_setup(integer mode)
    atom data
    sequence regs
    data = allocate_low(256)
    regs = repeat(0,10)
    regs[REG_AX] = #4F01
    regs[REG_CX] = mode
    regs[REG_ES] = floor(data / 16)
    regs[REG_DI] = and_bits(data, 15)
    regs = dos_interrupt(#10, regs)
    bank_granularity = (peek(data + 4) + 256 * peek(data + 5)) * 1024
    bytes_per_line = peek(data + #10) + 256 * peek(data + #11)
    free_low(data)
end procedure

-- demo stuff
include graphics.e
atom junk
junk = graphics_mode(257)
svga_setup(257)

for a = 0 to 479 do
    pixel(repeat(a, 160), {a,a})
end for

---- code ends ----

Pete Eberlein <xseal at harborside.com>

new topic     » topic index » view message » categorize

2. Re: Faster pixel() in SVGA

Hi all!

I timed Pete's faster SVGA routine (display_image()) with my 486-66 machine.

1) displaying 320*200 image (257 mode):
Euphoria: 30 f.p.s
Pete's:   40 f.p.s
Pete's routine is 33% faster than Euphoria's built-in.

2) displaying 640*480 image (257 mode):
Euphoria: 4.5 f.p.s
Pete's:   5.0 f.p.s
Pete's routine is 11% faster.

Pete's is faster, however, Euphoria's built-in do perform screen edge
clipping, whereas the Pete's does'nt...
and one more, when Pete's routine is used in my computer, a few(2 or 3)
pixel-image lines were blackened in the middle of the runs of pixels.

Bye! from Lee woo seob

new topic     » goto parent     » topic index » view message » categorize

3. Re: Faster pixel() in SVGA

Lee woo seob wrote:
> I timed Pete's faster SVGA routine (display_image()) with my 486-66 machine.

Thanks, I hadn't got around to doing that.  Notice that random pixels
are not a whole lot faster than in Euphoria, but pixels that are drawn
closely in descending order are much faster.

> Pete's is faster, however, Euphoria's built-in do perform screen edge
> clipping, whereas the Pete's does'nt...
> and one more, when Pete's routine is used in my computer, a few(2 or 3)
> pixel-image lines were blackened in the middle of the runs of pixels.

That blackening is unusual.  Send me any test programs you write.

> Bye! from Lee woo seob

BABOR, JIRI wrote:
> Pete, every time I try to run your demo on my 486-66 in win95 dos window, it c
raps out
> with: A fatal exception 0D has occurred at 5453:00004406. Any ideas? Jiri

I had this happen to me once.  Has anyone else encountered this error?
I'm not sure if it's a problem with calling the vesa interrupt or
writing directly to video memory.  There is absolutely no bounds
checking or error handling, so bad data results in very bad output or
worse.  There is also a way to call the set_window_func directly,
instead of calling an interrupt, but I haven't messed around with that
yet.  It might be a little faster but I doubt it's worth the effort in
machine coding.

I also discovered that my display_image is practically the same as the
one in image.e, so my display_image procedure is unneccessary.  If I had
taken the time to look, I would have realized that display_image calls
the new pixel procedure as long as it's redefined before including
image.e.  Display_image is already optimized for the new pixel procedure
because it draws the image in a top-down fashion.

I've also noticed that using some other graphics functions in
conjunction with the modified pixel exhibits some peculiar behavior.
Text written to the screen and lines often appear in the wrong position
as well as some other undesired effects.  Apparently the graphics
library Euphoria uses expects the bank to always be reset to 0 after
each graphics procedure.  This is exactly what I was trying to avoid, so
that the bank would not have to be selected through an interrupt quite
as often.

Other enhancements might be a routine that works like Michael Bolins
extended mem copy as Ralf suggested.  I've added a complimentary
get_pixel function and a svga_mode function that should be used in place
of graphics_mode so that I still can get the necessary info on the mode.

---- code begins ----
-- svga.e
-- faster routines for SVGA pixel manipulation in Euphoria
-- by Pete Eberlein <xseal at harborside.com>

include machine.e
include graphics.e

sequence regs, dummy
integer bank_start, bytes_per_line, bank_granularity
atom win_func_ptr
bank_start = 0
regs = repeat(0, 10)
regs[REG_AX] = #4F05
regs[REG_BX] = #0000

global procedure pixel(object data, sequence p)
    integer offset, len
    if atom(data) then
        len = 1
    else
        len = length(data)
    end if
    offset = p[2] * bytes_per_line + p[1]
    if offset < bank_start or offset + len > bank_start + 65536 then
        regs[REG_DX] = floor(offset / bank_granularity)
        dummy = dos_interrupt(#10, regs)
        bank_start = regs[REG_DX] * bank_granularity
    end if
    poke(#A0000 + offset - bank_start, data)
end procedure

global function get_pixel(sequence p)
    integer offset
    offset = p[2] * bytes_per_line + p[1]
    if length(p) = 2 then
        if offset < bank_start or offset > bank_start + 65535 then
            regs[REG_DX] = floor(offset / bank_granularity)
            dummy = dos_interrupt(#10, regs)
            bank_start = regs[REG_DX] * bank_granularity
        end if
        return peek(#A0000 + offset - bank_start)
    elsif length(p) = 3 then
        if offset < bank_start or offset + p[3] > bank_start + 65536
then
            regs[REG_DX] = floor(offset / bank_granularity)
            dummy = dos_interrupt(#10, regs)
            bank_start = regs[REG_DX] * bank_granularity
        end if
        return peek({#A0000 + offset - bank_start, p[3]})
    end if
end function

global function svga_mode(integer mode)
    atom data
    sequence regs
    regs = repeat(0,10)
    data = allocate_low(256)
    if data then
        regs[REG_AX] = #4F01
        regs[REG_CX] = mode
        regs[REG_ES] = floor(data / 16)
        regs[REG_DI] = and_bits(data, 15)
        regs = dos_interrupt(#10, regs)
        bank_granularity = (peek(data + 4) + 256 * peek(data + 5)) *
1024
        bytes_per_line = peek(data + #10) + 256 * peek(data + #11)
        win_func_ptr = bytes_to_int(peek({data+12, 4}))
        free_low(data)
    end if
    return graphics_mode(mode) or (data = 0) or (regs[REG_AX] != #4F)
end function
---- code ends ----

Pete Eberlein <xseal at harborside.com>

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu