23 November 2021, 14:45 | #1 |
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? |
23 November 2021, 15:16 | #2 |
It's coming back!
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
|
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.
|
23 November 2021, 15:23 | #3 |
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. |
23 November 2021, 15:33 | #4 |
It's coming back!
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
|
|
23 November 2021, 15:36 | #5 |
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... :-) |
23 November 2021, 15:41 | #6 | |
It's coming back!
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
|
Quote:
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 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. |
|
23 November 2021, 15:54 | #7 |
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. |
23 November 2021, 16:24 | #8 |
Registered User
Join Date: Jun 2016
Location: europe
Posts: 1,043
|
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.
|
24 November 2021, 11:17 | #9 |
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. |
24 November 2021, 11:38 | #10 |
Lemon. / Core Design
Join Date: Mar 2016
Location: Tier 5
Posts: 1,212
|
seems that you are displaying the screen that is being filled, simple as that.
|
24 November 2021, 12:47 | #11 |
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. |
24 November 2021, 16:35 | #12 |
It's coming back!
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
|
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.
|
25 November 2021, 13:18 | #13 |
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. |
08 January 2023, 09:53 | #14 | |
Registered User
Join Date: May 2021
Location: Norway
Posts: 19
|
Quote:
Would you have any examples, in pseudocode or actual assembly? |
|
08 January 2023, 11:42 | #15 |
Registered User
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 |
08 January 2023, 20:25 | #16 | |
Registered User
Join Date: May 2021
Location: Norway
Posts: 19
|
Quote:
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? |
|
08 January 2023, 20:53 | #17 |
Registered User
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.
|
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 |
|
|