English Amiga Board


Go Back   English Amiga Board > Coders > Coders. Asm / Hardware

 
 
Thread Tools
Old 23 November 2021, 14:45   #1
torkildl
Registered User
 
Join Date: May 2021
Location: Norway
Posts: 19
Weird vertical fill issue

Hello!

I am back in the coding game after nearly 30 years. My setup is FS-UAE on A500 OCS, coding a demo again.

In one of the parts, I am using vertical blitter fill (a la Sanity's WOC scroller).
I use triple buffering (1: blitter clear, 2: cpu dot plotting & blitter filling, 3: view) which seems to work perfectly fine when I test it. When drawing is done, I switch pointers around, wait for the blitter to finish and then set the new copperlist.

Two weird things:
1. the blitter fill flickers despite the triple buffering and bltwait routine before setting new copperlist. It's only one bitplane, so even though I use the vertical XOR trick, it should be able to fill one overscan bitplane. I use a lot of CPU on plotting, so I am fine with spending two frames, but despite buffering it still flickers.

Bottom half of screen is filled, while top if not filled. When there is less CPU work to be done, the fill "level" goes up but not far enough.

2. The blitter fill routine seems to go in descending mode (decreasing addresses), while BLTCON0 is set to be ascending.- I've checked the BLTCON bits they seem fine.

I thought my triple buffering should fix these problems, at least when my main loop is waiting for a new VBLANK (testing counter in lvl3 interrupt) before restarting the process.

Do the coding heads on this forum have any idea what I am doing wrong?
torkildl is offline  
Old 23 November 2021, 15:16   #2
deimos
It's coming back!
 
deimos's Avatar
 
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
Quote:
Originally Posted by torkildl View Post
I thought my triple buffering should fix these problems, at least when my main loop is waiting for a new VBLANK (testing counter in lvl3 interrupt) before restarting the process.
I'm not following what you're saying here. At what point during the screen drawing do you update the copper list? If it's after the VBLANK, that's too late. You want to do it at the end of the screen. I do it in a copper interrupt.
deimos is offline  
Old 23 November 2021, 15:23   #3
torkildl
Registered User
 
Join Date: May 2021
Location: Norway
Posts: 19
I have three screenbuffers and three corresponding copperlists: clear, draw, view).
I switch the pointers from clear to draw, draw to view, and view to clear at the end of drawing (and bltwait). Then, I write the _new_ view-address to $dff080.

I think the triple buffering is solid, and that should really do away with any flickering (although movements may be more uneven because sometimes the routine could take 1 frame, and other times 2 frames).

The blitter fill is not "finished" after the bltwait. I use a bltwait I found here that tests a chipregister and should be OK. Had no problems with it otherwise.

As this is the first time I am filling anything with the vertical xor method, I am wondering whether this is a source of the flickering or something else.
torkildl is offline  
Old 23 November 2021, 15:33   #4
deimos
It's coming back!
 
deimos's Avatar
 
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
Quote:
Originally Posted by torkildl View Post
Then, I write the _new_ view-address to $dff080.
And you do this when the beam has finished refreshing the screen?
deimos is offline  
Old 23 November 2021, 15:36   #5
torkildl
Registered User
 
Join Date: May 2021
Location: Norway
Posts: 19
No, no checking. I just write to $dff080 when I am done with all I am supposed to do.
Should I wait until beam is out? I thought $dff080 is read at the vblank, so if the beam is in the middle of the screen when I write to $dff080 it should not be a problem. But my hw knowledge is _veery_ rusty... :-)
torkildl is offline  
Old 23 November 2021, 15:41   #6
deimos
It's coming back!
 
deimos's Avatar
 
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
Quote:
Originally Posted by torkildl View Post
No, no checking. I just write to $dff080 when I am done with all I am supposed to do.
Should I wait until beam is out? I thought $dff080 is read at the vblank, so if the beam is in the middle of the screen when I write to $dff080 it should not be a problem. But my hw knowledge is _veery_ rusty... :-)
Most people would call VBLANK the point at which the VBLANK interrupt is generated, which is actually some time after the screen refresh has started, too late for you.

This is why I use a copper interrupt, at near the end of the screen refresh.

Code:
$ffdf,$fffe, // Wait for vpos >= 255 and hpos >= 222
$2cc1,$fffe, // Wait for vpos >= 44 and hpos >= 192
$009c,$8010, // INTREQ = $8010
$ffff,$fffe  // End of CopperList
And the interrupt code sets custom->cop1lc to the buffer that's ready to be displayed.

But my triple buffering is different to yours (if I'm understanding yours), with back, flip and front buffers. When I finish drawing I swap the back and flip buffers, and the copper interrupt swaps the flip and front buffers before setting cop1lc.

Last edited by deimos; 23 November 2021 at 16:12.
deimos is offline  
Old 23 November 2021, 15:54   #7
a/b
Registered User
 
Join Date: Jun 2016
Location: europe
Posts: 1,043
You have to sync with beam when you are switching.
Let say you finish a frame in the middle of the screen, so you then switch (render->show, show->clear, clear->render) and set the copper list. Half a frame later it's finally activated, and then another half later (about screen middle) you are done with the next frame. Now you switch again and start clearing, but the frame you start clearing is still being shown for another half a frame.
a/b is offline  
Old 23 November 2021, 16:24   #8
a/b
Registered User
 
Join Date: Jun 2016
Location: europe
Posts: 1,043
Quote:
Originally Posted by deimos View Post
This is why I use a copper interrupt, at near the end of the screen refresh.
Similar here, much better control when to trigger, except I prefer int1 so I can still use blitter int3 without interference, and in case I'm using int2 (keyboard, timer) and decide to do some heavier processing in my int1 I don't delay int2 with it.
a/b is offline  
Old 24 November 2021, 11:17   #9
torkildl
Registered User
 
Join Date: May 2021
Location: Norway
Posts: 19
Maybe this is a sync issue, but it is certainly not the case that the clearing eats into the screen being viewed.

The reason I know this is that the dots I plot to be filled with blitter vertical fill, are perfectly visible. I guess I should not call this flickering -- sorry! -- but rather that the fill does not seem to complete.

It also seem weird that the fill is complete in the lower (approx) half of the screen, but not in the upper. When I plot fewer dots (less cycles for cpu), the fill goes higher up.
This vertical fill should use ascending addresses (and I have checked bltcon0).

I have checked the bltwait and it is standard. And avoided having the bltwait just after writing to BLTSIZE.
torkildl is offline  
Old 24 November 2021, 11:38   #10
DanScott
Lemon. / Core Design
 
DanScott's Avatar
 
Join Date: Mar 2016
Location: Tier 5
Posts: 1,212
seems that you are displaying the screen that is being filled, simple as that.
DanScott is offline  
Old 24 November 2021, 12:47   #11
a/b
Registered User
 
Join Date: Jun 2016
Location: europe
Posts: 1,043
You said you wait for the blitter to finish. Well, finish what exactly? Clear? I guess you do a clear+render at the same time, then start a fill and switch, so you end up seeing the screen being filled. Or do you also do a full start to finish wait on fill to finish before switching? I doubt that. And if you don't wait on fill you would need a 4th buffer and start filling mid-drawing, unless you start it at the end and then sync it with the beam (blitter can stay head, and your blit is ascending) but you are not syncing.
It's all hypothetical since we can't see code/exe, but in any case if you don't sync you will see buffers being cleared/filled depending on order of operation and rasterline position. Several scenarios presented so far in this thread.
a/b is offline  
Old 24 November 2021, 16:35   #12
deimos
It's coming back!
 
deimos's Avatar
 
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
Quote:
Originally Posted by torkildl View Post
I have three screenbuffers and three corresponding copperlists: clear, draw, view).
I switch the pointers from clear to draw, draw to view, and view to clear at the end of drawing (and bltwait). Then, I write the _new_ view-address to $dff080.
What might be adding to the confusion is that what you've described isn't what most people would understand to be triple buffering. It's more like double buffering with an extra scratch buffer. Triple buffering would have the switching of the displayed buffer decoupled from the main code (i.e. in an interrupt) and the main code would never need to wait for a vblank or a certain beam position.
deimos is offline  
Old 25 November 2021, 13:18   #13
torkildl
Registered User
 
Join Date: May 2021
Location: Norway
Posts: 19
I found the mistake! Thanks for all very useful and thoughtful responses!

It turned out to be the stupidest of errors: I had switched a move.l with a lea.l, which gave me _a_ screenbuffer, but not _the_ screenbuffer I wanted. I still don't understand why the vertical fill seems to go in descending mode (without that bit set), but I don't care as it works now! :-)

The sync was not a problem in itself. Thanks also for the triple buffering-correction. I do have a counter incremented on VERTB interrupt and wait for that, so I guess that counts as a sync.
torkildl is offline  
Old 08 January 2023, 09:53   #14
torkildl
Registered User
 
Join Date: May 2021
Location: Norway
Posts: 19
Quote:
Originally Posted by deimos View Post
What might be adding to the confusion is that what you've described isn't what most people would understand to be triple buffering. It's more like double buffering with an extra scratch buffer. Triple buffering would have the switching of the displayed buffer decoupled from the main code (i.e. in an interrupt) and the main code would never need to wait for a vblank or a certain beam position.
I have experimented with multiple such systems, but still have problems getting it to shine.
Would you have any examples, in pseudocode or actual assembly?
torkildl is offline  
Old 08 January 2023, 11:42   #15
paraj
Registered User
 
paraj's Avatar
 
Join Date: Feb 2017
Location: Denmark
Posts: 1,145
You have 3 buffers: The one being displayed, one you're currently building and one waiting to be displayed (some of the time).

Display buffer 0
Render buffer 1
Make buffer 1 ready for display
Render buffer 2
In interrupt outside visible area: Display buffer 1
Make buffer 2 ready for display
Render buffer 0
In interrupt outside visible area: Display buffer 2
...

One thing to keep in mind is that if can produce frames faster than they can be displayed (e.g. when running on a faster machine) you need to check if there's already a buffer waiting before making the new one ready for display.
And of course only update the display buffer in the interrupt code if one is actually ready!

Something like this (assuming I didn't make any silly mistakes):

Code:
        include exec/execbase.i
        include hardware/custom.i
        include hardware/intbits.i
        include hardware/dmabits.i
        include hardware/cia.i

screenw=320
screenh=256
xstart=$81+(320-screenw)/2
ystart=$2c+(256-screenh)/2

bplbytes=(screenw/8)*screenh

custom=$dff000

        SECTION code,code

start:
        lea     custom,a6
        move.w  #$7fff,d0
        move.w  d0,intena(a6)
        move.w  d0,dmacon(a6)


        move.w  #$000,color(a6)
        move.w  #$ccc,color+2(a6)
        move.w  #$1200,bplcon0(a6)
        move.w  #0,bplcon1(a6)
        move.w  #$0024,bplcon2(a6)
        move.w  #0,bpl1mod(a6)
        move.w  #0,bpl2mod(a6)
        move.w  #(ystart<<8)!xstart,diwstrt(a6)
        move.w  #(((ystart+screenh)<<8)&$ff00)!((xstart+screenw)&$ff),diwstop(a6)
        move.w  #xstart/2-8,ddfstrt(a6)
        move.w  #xstart/2-8+8*((screenw+15)/16-1),ddfstop(a6)
        move.l  #copperlist,cop1lc(a6)

        move.l  #buf0,d0 ; Start out displaying buffer 0
        bsr     updatebplptr
        move.w  #1,workbufidx ; And render to buffer 1

        move.l  #lev1handler,$64.w

        move.w  #INTF_VERTB!INTF_SOFTINT,intreq(a6)
.w:
        btst.b  #INTB_VERTB,intreqr+1(a6)
        beq.b   .w
        move.w  #DMAF_SETCLR!DMAF_MASTER!DMAF_COPPER!DMAF_RASTER,dmacon(a6)
        move.w  #INTF_SETCLR!INTF_INTEN!INTF_SOFTINT,intena(a6)

        moveq   #0,d7
.main:
        ; Get current work buffer to a5
        move.w  workbufidx,d0
        lsl.w   #2,d0
        lea     bufptrs(pc),a0
        move.l  (a0,d0.w),a5

        ; Render something
        move.l  a5,a0
        move.l  d7,d0
        move.w  #screenh-1,d1
.y:
        moveq   #0,d2
        btst    #3,d0
        beq.b   .n
        moveq   #-1,d2
.n:
        rept    screenw/32
        move.l  d2,(a0)+
        endr
        addq.w  #1,d0
        dbf     d1,.y
        addq.w   #1,d7

        ; Waste some time randomly to simulate unstable frame rate
        moveq   #0,d0
        add.b   $bfe801,d0
        add.b   $bfd800,d0
        add.w   #$50,d0
.waste: move.b  vhposr(a6),d1
.wl:    cmp.b   vhposr(a6),d1
        beq.b   .wl
        dbf     d0,.waste

        ; Make "workbuf" ready for display
        ; If we're going very fast the last buffer may not be displayed yet
        lea     nextbuf(pc),a0
.wait:  tst.l   (a0)
        bne.b   .wait
        move.l  a5,(a0)

        ; And move to the next buffer
        lea     workbufidx(pc),a0
        move.w  (a0),d0
        addq.w  #1,d0
        cmp.w   #3,d0
        bne.b   .nowrap
        moveq   #0,d0
.nowrap:
        move.w  d0,(a0)

        bra     .main

updatebplptr:
        lea     copperlist,a0
        move.w  d0,6(a0)
        swap    d0
        move.w  d0,2(a0)
        rts

lev1handler:
        movem.l a0/d0,-(sp)
        ; Ack interrupt
        lea     custom+intreq,a0
        moveq   #INTF_SOFTINT,d0
        move.w  d0,(a0)
        move.w  d0,(a0)
        ; Check if there's a new buffer ready
        lea     nextbuf(pc),a0
        move.l  (a0),d0
        beq.b   .no
        clr.l   (a0)
        bsr     updatebplptr
.no:
        movem.l (sp)+,a0/d0
        rte

nextbuf:
        dc.l    0
workbufidx:
        dc.w    0

bufptrs:
        dc.l    buf0
        dc.l    buf1
        dc.l    buf2

        SECTION bss_c,bss_c
buf0:   ds.w bplbytes/2
buf1:   ds.w bplbytes/2
buf2:   ds.w bplbytes/2

        SECTION data_c,data_c
copperlist:
        dc.w bplpt+0,$0000
        dc.w bplpt+2,$0000
        ; Wait for end of screen
        if (ystart+screenh-1)>$ff
        dc.w $ffdf,-2 ; Handle wraparound
        endc
        dc.w ((ystart+screenh-1)&$ff)<<8!$df,-2
        dc.w intreq,INTF_SETCLR!INTF_SOFTINT  ; Trigger soft int
        dc.l -2
paraj is offline  
Old 08 January 2023, 20:25   #16
torkildl
Registered User
 
Join Date: May 2021
Location: Norway
Posts: 19
Quote:
Originally Posted by paraj View Post
You have 3 buffers: The one being displayed, one you're currently building and one waiting to be displayed (some of the time).

Display buffer 0
Render buffer 1
Make buffer 1 ready for display
Render buffer 2
In interrupt outside visible area: Display buffer 1
Make buffer 2 ready for display
Render buffer 0
In interrupt outside visible area: Display buffer 2
Thanks! This looks very useful. I understand the system. I note that you set one buffer to be displayed by poking bplptrs in the copperlist.

I do have three separate readymade copperlists. Switching buffers is to switch copperlists. How would you implement that within this system? Just poke the address of ready buffer to dff080?
torkildl is offline  
Old 08 January 2023, 20:53   #17
paraj
Registered User
 
paraj's Avatar
 
Join Date: Feb 2017
Location: Denmark
Posts: 1,145
Yes, just poke the new copperlist to cop1lc in lev1handler. You can make "nextbuf" point to that instead of the bitplane data. Make sure the copperlist you're "publishing" corresponds to the "workbufidx" you just updated (maybe keep a parallel array of pointers to copperlists) and that all of them trigger SOFTINT at the right spot.
paraj is offline  
 


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools

Similar Threads
Thread Thread Starter Forum Replies Last Post
A500 Tank Mouse vertical movement issue 005AGIMA support.Hardware 25 23 June 2020 23:15
Weird A500 issue stevew support.Hardware 7 25 April 2020 22:28
Blitter Vertical Fill 71M Coders. Asm / Hardware 34 16 November 2017 22:31
Weird vertical lines (c64) daznic support.Hardware 12 16 December 2011 09:42
Weird MaxTransfer issue Retroplay support.Hardware 2 11 May 2011 22:38

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 06:24.

Top

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.
Page generated in 0.08966 seconds with 15 queries