Shop OBEX P1 Docs P2 Docs Learn Events
Buffered Video Output? — Parallax Forums

Buffered Video Output?

PhilldapillPhilldapill Posts: 1,283
edited 2008-12-14 00:07 in Propeller 1
I've done a few projects where the RCA TV connection is how I figure out what's going on. My beef with this whole thing is the constant flicker when the screen updates. What I do, is I clear the screen by doing TV.out(0), then write my stuff to it, then when I update, I repeat the process. I'm guessing the flicker comes in when I clear the screen so 1 frame is blank, then I write my data and then there is text on the screen.

What I have in mind, is modifying the TV_Text object, so that you can write to a buffer and get everything laid out, THEN tell it when to flip it, instead of clearing the whole thing each time. This way, I think it reduce flicker drastically.

Has this been done???

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2008-12-10 20:24
    It's been done for graphics, not for any of the text displays. One simpler way to avoid flicker is to leave the various titles and other labels on the screen, not clear it, but modify the decimal formatting routine to always put out enough blanks after the number to clear the field. The hex and binary formatter already use a fixed field length. If you're updating text strings, you could have an alternate string output routine that similarly clears any existing fixed length field by outputting enough spaces after the last digit.

    Generally, if you're modifying large areas of the screen (changing the layout effectively), you're better off clearing the screen and repainting it from scratch.

    Post Edited (Mike Green) : 12/10/2008 8:58:07 PM GMT
  • Erik FriesenErik Friesen Posts: 1,071
    edited 2008-12-10 20:36
    Here is what I have done for menus and misc.



    Text.str(string(1,"Hello everyone ") 'with spaces here because the post self edits them out

    Then to update the same line,

    Text.str(string(1,"Hello everyone is here ")

    Presto no flicker.

    While you can do it with a buffer, it will greatly increase your memory needs.

    Post Edited (Erik Friesen) : 12/10/2008 8:43:07 PM GMT
  • mcstarmcstar Posts: 144
    edited 2008-12-10 21:01
    Erik, I think Phil's point is that there is already a double buffer in the TV driver. The problem is that the writes to text.str and other calls are not synchronized with the buffer flips. The flips happen automatically and very quickly (much faster than you can do all your text outs.) Therefore the flicker is the result of fact that you actually see the frames that are being cleared and drawn on. This was a big problem with winforms application before people learned how to double buffering correctly.

    I agree with you phil, you should be able to prevent the tv driver from flipping buffers while you're doing your update, then allow it to continue when you're done. This drives me nuts too. What we need is a tv.SuspendFlip method and a subsequent tv.ResumeFlip. Then we could pause the flipping (it would continue to update from the forward buffer while we do our writes to the back buffer.

    This needs to be done in the TV.spin file, but my asm is nowhere near what it needs to be to make it happen.
  • PhilldapillPhilldapill Posts: 1,283
    edited 2008-12-10 21:22
    That's exactly what I'm talking about, mcstar. I, as well, don't have the ASM skills to do it. I'm just worried I might fall over and have a seizure someday because of this crazy TV flickering... I'm not epiliptic, but jeez... It just bugs me, and I'm sure it would bug my customers once I start selling my projects.

    I've heard of a method of writing something, and when you need to change it, backing up to a particular position, blanking the predefined area out with spaces, then re-writing to that same position. This still creates flicker because of the frame that gets flipped with the blank spaces, then back with text. Memory isn't an issue in this project... I'm running some ADC's, and PWM, and not much more besides the TV object.
  • Mike GreenMike Green Posts: 23,101
    edited 2008-12-10 21:26
    There is only a single display buffer in the TV text driver. You may be confusing the graphics driver (which does provide two buffers normally) with the text driver. TV.spin is used for both and, as far as it is concerned, it has a single array of pointers to tiles. In the case of the graphics driver, the tile pointers are swapped out so they point to the alternate graphics buffer. In the case of the text driver, the tiles are in the font table in ROM and the tile pointers are changed as the display characters change.
  • mcstarmcstar Posts: 144
    edited 2008-12-10 21:30
    OK, I found this in Andre LaMothe's Hydra book....
    Somebody said...

    16.3.2.1 Video Memory Mapping and Organization
    The actual organization of the Tile Bitmap Memory and the Tile Pointer Map are a bit
    tricky, so we are going to discuss that in a moment, but first let’s talk about animation and
    double buffering. The TV driver supports a “double buffered” architecture, that is you
    draw on an “off-screen” buffer and the TV driver renders an “on-screen” buffer.
    Therefore, on start-up you tell the TV driver the address of the on-screen buffer only
    (actually you do this indirectly through the Tile Pointer Map), the off-screen buffer is
    manipulated by the Graphics driver and it’s the job of the Graphics driver to “copy” the
    contents of the off-screen buffer to the on-screen buffer. Therefore, there is no coupling
    between the TV and Graphics drivers other than if you want to see something then you need
    to copy it into the on-screen buffer since this is the only thing the TV driver renders.

    It's not clear to me whether he means that the graphics driver does the buffering or the tv.spin driver itself. There is mention of a "field" and a "superfield" in tv.spin, though I'm not sure if those are the buffers or not.

    Here's a spin only idea...
    In Tv_text.spin, add a new buffer (word screen2[noparse][[/noparse]screensize]) and new method called printBufferd(c)
    -have it write to screen2

    pri print(c)
    screen2[noparse][[/noparse]row * cols + col] := (color << 1 + c & 1) << 10 + $200 + c & $FE
    if ++col == cols
    newline

    and then use a longmove to replace screen with screen2.

    [noparse][[/noparse]EDIT]
    Thanks for the clarification Mike. Do you think the screen2 buffer idea would work?
  • Mike GreenMike Green Posts: 23,101
    edited 2008-12-10 21:46
    TV.spin knows nothing about a second screen buffer. That's handled completely outside it. You can certainly write a double buffered version of TV_text.spin if you want. You'll need another 1K bytes or so for another 40 x 13 text buffer, a modest increase. I'm sure there are some applications where users would prefer a double buffered text display over a single buffer. Rather than a separate call, I'd suggest using another control character to copy the buffer, perhaps synchronizing it with the vertical sync so it's less visible.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2008-12-10 22:43
    Attached is a "double-buffered" version of tv_wtext.spin, called "tv_wtext_db.spin", along with a short demo program. This is not double-buffered in the traditional sense that one buffer is being written as the other is displayed, followed by the two buffers getting swapped. Rather, the written buffer gets copied to the display buffer upon command. This has the advantage of maintaining the screen (window) contents from the previous display, in case you want to update only part of it.

    No attempt is made to synchonize the copy operation to the vertical sync, either. This has the disadvantage that a dynamic frame capture could show partly old contents and partly new contents. It has the advantage that throughput is enhanced for rapidly-changing content.

    Note that no changes appear on the screen until either the character SHOSCR is sent or the public method showscreen is called.

    -Phil

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    'Just a few PropSTICK Kit bare PCBs left!

    Post Edited (Phil Pilgrim (PhiPi)) : 12/10/2008 10:51:27 PM GMT
  • mcstarmcstar Posts: 144
    edited 2008-12-10 23:04
    That's very nice! Windows, scrolling etc. I cannot wait to try it tonight!
    Thanks
  • Oldbitcollector (Jeff)Oldbitcollector (Jeff) Posts: 8,091
    edited 2008-12-10 23:12
    AiGeneric is also available. 40x24, no flicker!

    OBC

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    New to the Propeller?

    Getting started with a Propeller Protoboard?
    Check out: Introduction to the Proboard & Propeller Cookbook 1.4
    Updates to the Cookbook are now posted to: Propeller.warrantyvoid.us
    Got an SD card connected? - PropDOS
  • PhilldapillPhilldapill Posts: 1,283
    edited 2008-12-10 23:17
    May God bless you and all your descendants, Phil. Bless you throughout the ages.

    This is exactly what I was thinking of. I can't believe it's been in my library for so long and I forgot about it. Perfect.
  • HarleyHarley Posts: 997
    edited 2008-12-11 00:24
    I've been using TV_text, first with a 5" b/w monitor, and after that died with a 8" LCD DVD player with a Video IN jack. I don't know about flicker as most values displayed change only one at a time; most events are a result of pressing a keypad. I have all the 'titles' written initially by one routine, and all the variables updated by another routine. So, this has been more than adequate for my use.

    The attachment is a bit overexposed; haven't yet gotten exposures proper for this LCD display; backlight greys the background too much. Is nice to 'see' the headings in color now. yeah.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Harley Shanko
    640 x 480 - 51K
  • PhilldapillPhilldapill Posts: 1,283
    edited 2008-12-11 01:09
    Phil,
    Again, I can't thank you enough. I've replaced this as the TV object in my project and wow.... I love seeing numbers change on my screen with no flicker. I'm starting to get a little bleary-eyed from joy.


    Thank you.
  • PhilldapillPhilldapill Posts: 1,283
    edited 2008-12-11 02:37
    Phil, again, thank you... But is there a way to output a number, like 1630 as 1.630? I have an ADC reading but I like to use integers, so I'm just storing it as mV. I'd like to just take the mV reading, and pass it to a function and specify the decimal places, and get back a string like above, OR pass in the number, and number of decimal places, and have a function print it to the screen.

    I could do this myself, but if it's already been done, I should save time. Any thoughts?
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2008-12-11 02:52
    Phil,

    Yes, this is easy to do. If the "digits" argument to decn is negative, the output is padded with leading zeroes instead of blanks. So to print a value x as dd.ddd, do this:

    pr.decn(x / 1000, 2)
    pr.out(".")
    pr.decn(||x // 1000, -3)
    
    
    


    The absolute value operator in the second decn permits this to work with negative as well as positive numbers.

    -Phil

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    'Just a few PropSTICK Kit bare PCBs left!
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2008-12-11 03:02
    I just noticed that decn doesn't behave itself when the value and digits arguments are both negative. Here's a corrected version, along with a demo program that illustrates my previous point.

    -Phil

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    'Just a few PropSTICK Kit bare PCBs left!
  • PhilldapillPhilldapill Posts: 1,283
    edited 2008-12-11 03:56
    You are amazing Phil. Here is a simple function that does all that in one package. I think something like this is used often and would be nice to have as a function for formatting.

    PUB decnd(value, digits, decimals) | exp
    '' Print a decimal number, right-justified in a field width given by digits PLUS decimals
      exp := 1
      repeat decimals
        exp := exp*10
      decn(value/exp, digits)
      out(".")
      decn(||value//exp,-decimals)
    
  • mcstarmcstar Posts: 144
    edited 2008-12-11 14:50
    I must echo Phill's thoughts on this! Great job on the windowed driver. I'm converting over to it's use now. It greatly outperforms the base tv driver in so many ways. It works so well, it almost feels like cheating!
  • Ken PetersonKen Peterson Posts: 806
    edited 2008-12-11 18:18
    I had a flicker problem with the original TV_Text, so I just added a function called waitblank() to the TV_Text object that would wait until the vertical blanking interval (tv_status == 1). Then whenever I wanted to write to the screen, I would call waitblank() and then write the info. It only works if your screen update fits within a blanking interval, but for what I was doing it was adequate.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    ·"I have always wished that my computer would be as easy to use as my telephone.· My wish has come true.· I no longer know how to use my telephone."

    - Bjarne Stroustrup
  • mcstarmcstar Posts: 144
    edited 2008-12-13 23:28
    I found a "bug" where i couldn't get a window to show up on the first line.
    Basically, I created a window with the following string...
    text.str(string(DEFWIN,1,1,1,40,1,USEWIN,1,CHGCLR,3)) ' top title bar

    but this created a window one line down from the top of the screen. I tried
    text.str(string(DEFWIN,1,0,1,40,1,USEWIN,1,CHGCLR,3)) ' top title bar

    but the "0" is not allowed in a string!

    Well, after a little several tries, here's how I fixed it...

    text.str(string(DEFWIN,1,1))
    text.out(0)
    text.str(string(40,1,USEWIN,1,CHGCLR,2)) ' top title bar
  • Mike GreenMike Green Posts: 23,101
    edited 2008-12-13 23:39
    It's not a bug, it's a feature.

    Strings in Spin use the C convention of ending strings with a zero byte. This has the effect of terminating a string early if you try to embed a zero byte in the middle. The compiler is supposed to catch it. Your "solution" is the only way to include a zero value in an output stream.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2008-12-14 00:07
    Since a zero byte is not allowed in strings, tv_wtext and tv_wtext_db have a "substitute zero" for use in command arguments, having the value $ff. This is defined for you in the demo programs under the name ZERO. You can use it in your program this way:

    text.str(string(DEFWIN,1,ZERO,1,40,1,USEWIN,1,CHGCLR,3)) ' top title bar
    
    
    


    There's also an alternate to CLS which can be used in strings: CLRW, which has the value $1e.

    In retrospect, having two such "zero" substitutes is a bit kludgy, and I really should try to come up with something better. Also, I need to update these objects to include the constant definitions, rather than relying on the demo programs to define them.

    -Phil

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    'Just a few PropSTICK Kit bare PCBs left!
Sign In or Register to comment.