Shop OBEX P1 Docs P2 Docs Learn Events
Tv and graphics — Parallax Forums

Tv and graphics

JacoJaco Posts: 9
edited 2007-12-23 08:48 in Propeller 1
Hi,

after a long time finally I had the chance to play a little with the propeller chip. I've designed a circuit that takes some measurements from various sensors and I wanted to display the measurements in a tv using the propeller and a serial connection to my device. Currently I use a 320x240 graphic display attached to an ARM7 LPC2368 that does this job very well and instead of writing a library to produce an RGB signal I prefer to use the propeller. The problem though is that I ran out of memory in propeller before I even started. I've made some search in the forum regarding objects, graphics and memory to see if I'm doing something wrong and right now I've only come to the conclusion that the chip has too few memory to use it for video. To me it seems that the graphics_demo is not just a demo but it drives the chip to its limits.

Someone proposed in a thread to disable double buffering and actually this saves a lot of memory but the flickering is way too annoying, therefore double buffering is needed. I've also tried to cut-down the graphics.spin object but I didn't manage to save a lot of memory.

I also understand that assembly may be the solution but in my case it's not an option as my brain stack is near to overflow with a dozen programming and assembly languages I already use in my work and I'm not really willing to put myself in this learning procedure for once again if it's really not necessary for my job.

I just to ask you if there is something that I'm missing and if I can save memory to finish my project. This is my code until now:


CON

  _clkmode = xtal1 + pll16x
  _xinfreq = 5_000_000
  _stack = ($3000 + $3000 + 100) >> 2 'accomodate display memory and stack

  x_tiles = 16
  y_tiles = 12

  paramcount = 14       
  bitmap_base = $2000
  display_base = $5000


  lines = 5
  thickness = 2
  

VAR

  long  tv_status     '0/1/2 = off/visible/invisible           read-only
  long  tv_enable     '0/? = off/on                            write-only
  long  tv_pins       '%ppmmm = pins                           write-only
  long  tv_mode       '%ccinp = chroma,interlace,ntsc/pal,swap write-only
  long  tv_screen     'pointer to screen (words)               write-only
  long  tv_colors     'pointer to colors (longs)               write-only               
  long  tv_hc         'horizontal cells                        write-only
  long  tv_vc         'vertical cells                          write-only
  long  tv_hx         'horizontal cell expansion               write-only
  long  tv_vx         'vertical cell expansion                 write-only
  long  tv_ho         'horizontal offset                       write-only
  long  tv_vo         'vertical offset                         write-only
  long  tv_broadcast  'broadcast frequency (Hz)                write-only
  long  tv_auralcog   'aural fm cog                            write-only

  word  screen[noparse][[/noparse]x_tiles * y_tiles]
  long  colors[noparse][[/noparse]64]

  byte  x[noparse][[/noparse]lines]
  byte  y[noparse][[/noparse]lines]
  byte  xs[noparse][[/noparse]lines]
  byte  ys[noparse][[/noparse]lines]  

OBJ

  tv    : "tv"
  gr    : "graphics"
  serial: "FullDuplexSerial"
  strInt: "Numbers"  

PUB start | i, dx, dy, myColorScheme

  'start tv
  longmove(@tv_status, @tvparams, paramcount)
  tv_screen := @screen
  tv_colors := @colors
  tv.start(@tv_status)

  'init colors
  repeat i from 0 to 63                               
    colors[noparse][[/noparse] i ] := $98072802

  myColorScheme := 0 << 10  ' or 1 or 2 or 63 
  'init tile screen
  repeat dx from 0 to tv_hc - 1
    repeat dy from 0 to tv_vc - 1                                                          
      screen[noparse][[/noparse] dy * tv_hc + dx] := display_base >> 6 + dy + dx * tv_vc + myColorScheme
    

  gr.start
  gr.setup(16, 12, 128, 96, bitmap_base)

  'start serial
  'serial.start(31, 30, 2, 115200)

  'start Numbers
  strInt.Init

  gr.clear
  i := 0
  repeat
    gr.clear
    if i == 100
      i := 0
    else
      i += 1
      DrawBarGraph(100, i, -40, -80)
      'DrawBarGraph(100, i, -80, -55)
      DrawConterLeft(string("S1"), 100, i, -85, 50, 40)
      DrawConterRight(string("S2"), 100, i, 85, 50, 40)
      DrawConterUP(string("S3"), 100, i, 0, 40, 60)
      DrawConterDown(string("S4"), 100, i, 0, 40, 60)
      gr.copy(display_base)


PUB DrawConterUP(name, total, value, center_x, center_y, radius) | full, angle, free
  gr.textmode(1,1,6,5)
  'Draw numbers
  gr.color(3)

  'Draw arc
  gr.color(3)
  gr.arc(center_x, center_y, radius - 20 , radius - 20, $1FFF * 45 / 360, 1, $1FFF * 135 / 360 - $1FFF * 45 / 360, 3)
  gr.color(0)
  gr.arc(center_x, center_y, radius - 40, radius - 40, $1FFF * 45 / 360, 1, $1FFF * 135 / 360 - $1FFF * 45 / 360, 3)

  'Draw line
  gr.color(2)
  full := ($1FFF * 135 / 360) - ($1FFF * 45 / 360)
  free := full * value / total
  angle := ($1FFF * 45 / 360) + full - free
             
  gr.arc(center_x, center_y, radius - 20, radius - 20, angle, 0, 1, 3)

  gr.textmode(1,1,6,2)
  gr.text(center_x +18, center_y + 25, strInt.ToStr(100*value/total, DEC))

  gr.text(center_x - 40, center_y + 25, name)
  
PUB DrawConterDown(name, total, value, center_x, center_y, radius) | full, angle, free
  gr.textmode(1,1,6,5)
  'Draw numbers
  gr.color(3)

  'Draw arc
  gr.color(3)
  gr.arc(center_x, center_y, radius - 20 , radius - 20, $1FFF * 225 / 360, 1, $1FFF * 315 / 360 - $1FFF * 225 / 360, 3)
  gr.color(0)
  gr.arc(center_x, center_y, radius - 40, radius - 40, $1FFF * 225 / 360, 1, $1FFF * 315 / 360 - $1FFF * 225 / 360, 3)

  'Draw line
  gr.color(2)
  full := ($1FFF * 315 / 360) - ($1FFF * 225 / 360)
  free := full * value / total
  angle := ($1FFF * 225 / 360) + free
             
  gr.arc(center_x, center_y, radius - 20, radius - 20, angle, 0, 1, 3)

  gr.textmode(1,1,6,2)
  gr.text(center_x +18, center_y - 10, strInt.ToStr(100*value/total, DEC))

  gr.text(center_x - 40, center_y - 10, name)

PUB DrawConterLeft(name, total, value, center_x, center_y, radius) | full, angle, free
  gr.textmode(1,1,6,5)
  'Draw numbers
  gr.color(3)
  angle := $1FFF * 180 / 360
  gr.textarc(center_x, center_y, radius, radius, angle, string("0"))
  angle := $1FFF * 155 / 360
  gr.textarc(center_x, center_y, radius, radius, angle, string("20"))
  angle := $1FFF * 130 / 360
  gr.textarc(center_x, center_y, radius, radius, angle, string("40"))
  angle := $1FFF * 105 / 360
  gr.textarc(center_x, center_y, radius, radius, angle, string("60"))
  angle := $1FFF * 80 / 360
  gr.textarc(center_x, center_y, radius, radius, angle, string("80"))
  angle := $1FFF * 55 / 360
  gr.textarc(center_x, center_y, radius, radius, angle, string("100"))

  'Draw arc
  gr.arc(center_x, center_y, radius - 10, radius - 10, angle, 1, $1FFF * 180 / 360 - angle, 2)

  'Draw line
  gr.color(2)
  full := ($1FFF * 180 / 360) - ($1FFF * 55 / 360)
  free := full * value / total
  angle := ($1FFF * 55 / 360) + full - free            
  gr.arc(center_x, center_y, radius - 12, radius - 12, angle, 0, 1, 3)

  gr.textmode(1,1,6,2)
  gr.text(center_x , center_y, strInt.ToStr(100*value/total, DEC))

  gr.text(center_x - 25, center_y - 5, name)

PUB DrawConterRight(name, total, value, center_x, center_y, radius) | full, angle, free
  gr.textmode(1,1,6,5)
  'Draw numbers
  gr.color(3)
  angle := 0
  gr.textarc(center_x, center_y, radius, radius, angle, string("0"))
  angle := $1FFF * 25 / 360
  gr.textarc(center_x, center_y, radius, radius, angle, string("20"))
  angle := $1FFF * 50 / 360
  gr.textarc(center_x, center_y, radius, radius, angle, string("40"))
  angle := $1FFF * 75 / 360
  gr.textarc(center_x, center_y, radius, radius, angle, string("60"))
  angle := $1FFF * 100 / 360
  gr.textarc(center_x, center_y, radius, radius, angle, string("80"))
  angle := $1FFF * 125 / 360
  gr.textarc(center_x, center_y, radius, radius, angle, string("100"))

  'Draw arc
  gr.arc(center_x, center_y, radius - 10, radius - 10, 0, 1, angle, 2)

  'Draw line
  gr.color(2)
  full := $1FFF * 125 / 360
  free := full * value / total
  angle := free            
  gr.arc(center_x, center_y, radius - 12, radius - 12, angle, 0, 1, 3)

  gr.textmode(1,1,6,2)
  gr.text(center_x , center_y, strInt.ToStr(100*value/total, DEC))
  
  gr.text(center_x - 25, center_y - 5, name)
    
PUB DrawPie(name, total, free, center_x, center_y, radius) | full
  full := $1FFF
  free := full*free/total
  gr.textmode(1,1,6,5)
  gr.color(2)
  gr.text(center_x, center_y +28, name)
  gr.color(7)
  gr.arc(center_x, center_y, radius, radius, 0, 1, free, 3)
  gr.color(2)
  gr.arc(center_x, center_y, radius, radius, free, 1, full - free, 3)
  gr.text(center_x - 30, center_y - 30, strInt.ToStr(free, DEC ))

PUB DrawBarGraph(total, value, position_x, position_y) | width, high, value1
  width := 80
  high := 20
  gr.color(2)
  value1 := width * value / total
  gr.text(position_x + width, position_y + 18, strInt.ToStr(value1 * 100 / width, DEC))
  gr.text(position_x + width + 20, position_y + 18, string("%"))
  if value < 5
    value := 5
    
  value := width * value / total
  
  gr.quad(position_x, position_y, position_x, position_y + high, position_x + width, position_y + high, position_x + width, position_y)
  gr.color(3)
  gr.quad(position_x + 1, position_y + 1, position_x + 1, position_y + high - 1, position_x + value - 1, position_y + high - 1, position_x + value - 1, position_y + 1)

DAT

tvparams                long    0               'status
                        long    1               'enable
                        long    %001_0101       'pins
                        long    %0000           'mode
                        long    0               'screen
                        long    0               'colors
                        long    x_tiles         'hc
                        long    y_tiles         'vc
                        long    10              'hx
                        long    1               'vx
                        long    0               'ho
                        long    0               'vo
                        long    0               'broadcast
                        long    0               'auralcog


CON
DEC      =  %000_000_000_0_0_000000_01010  




This code right now doesn't compile but if for a test you change

long  colors[noparse][[/noparse]64]



to

long  colors[noparse][[/noparse] 4 ] 


eyes.gif

then it compiles.

My purpose is to display several counters and info but I think that this will not be possible.

Display speed isn't critical while the sensors updates are every few seconds or minutes.

Thank you.

Edit:
There seems to be a bug in the forum's code section that doesn't ignore the symbols "[noparse][[/noparse]" and "]"

Post Edited (Jaco) : 12/22/2007 5:34:30 PM GMT

Comments

  • deSilvadeSilva Posts: 2,967
    edited 2007-12-22 14:26
    Jaco,
    I see that you understand the situation perfectly.
    The propeller needs CREATIVE solutions for nearly every new graphics application.
    12kB video buffer and 12kB swap buffer leaves too little head room.

    There are generally 5 ways forward:
    (1) Optimize code - this generally adds up to peanuts
    (2) Reclaim the HUB area where GRAPHICS and TV have been allocated - this is somewhat tricky but more awarding (yields 3 kB)
    (3) Use two-color mode - this will half the memory requirements (giving you back 12 KB!), but needs detailed changes in GRAPHICS
    (4) Try a tile-scheme - using blocks of 16x16 self defined "characters" can give you a lot of possibilities (though this will need double buffering as well)
    (5) Try a small graphics window within a character (=tile) screen

    When the screen can be updated very fast there is the chance to do it all during the non-drawing timeslot (around 4ms).
    This will need changes in GRAPHICS as well. Note that GRAPHICS is highly optimized and there is no space left for evan a single instruction.
    In fact GRAPHICS is a truly astonishing piece of code...

    I can type this list so easily as it had been my design for an advanced course for my microcontroller students,
    but I realized only a part of it upto now. I shall look for my (5) approach, but don't push me, please smile.gif

    However there are some experimental solutions for all of this distributed through this forum... I am sure the programmers will call here shortly smile.gif

    Post Edited (deSilva) : 12/22/2007 2:35:24 PM GMT
  • PerryPerry Posts: 253
    edited 2007-12-22 14:38
    try this:

    comment out all of the lowercase characters in the graphics code

    from
    '        word    fline + xa1 + ya9 + xb3 + yb7                   '`
    



    down to

    '        word    farc + xa2 + ya8 + a0 + ax1 + ay1               'bullet
    
    CON     fx = 0 ' 3  'number of custom characters
    



    never use these characters in your application

    Perry
  • RaymanRayman Posts: 14,162
    edited 2007-12-22 15:35
    Jaco: You're right about the Graphics demo being a bit misleading in the sense that it is really about the best it can do... You get the feeling that there are more degrees of freedom than there actually are...

    deSilva summed up you possiblilities.

    Personally, I would not use Graphics at all. Instead, I would use the basic VGA or TV tile drivers and use the internal font and perhaps custom characters to display the information. Unless, you really need a pixel level graph... In that case maybe use Graphics, but not for the whole screen, but from small areas (as deSilva mentioned).
  • JacoJaco Posts: 9
    edited 2007-12-22 17:22
    Thank you guys for all your answers.

    To be honest I didn't expect a solution but as they say hope dies last.

    @deSilva
    As you say: "In fact GRAPHICS is a truly astonishing piece of code...", therefore there aren't many things to change or optimize there except cut-off features like colors, functions not needed, character memory map. I did the last two because it was no-time for first reading the code. I don't know if I'm willing to do in-depth optimizations because it seems that propeller isn't the propriate for this current task. Although I understand that propeller is not targeting graphics where video ram must be in tons, I can't find the reason why the ram is so limited.

    @perry
    All characters and symbols except capitals and number was the first victim. Although I've gained some ram, if you think that before even start programming the ram was again almost full then there weren't much room to go.

    @Rayman
    You're right about not using the graphics.spin in the sense that it will free the ram but on the other hand I lose the power of what a descriptive language can offer because everything then would be static (graphics with predefined fonts) and I cannot create graphics with maths and code. Only with the idea I feel very limited like in cell.

    Seems that I'll stick to ARM7 for that, I was just hoping to do something with this chip as I've bought the dev kit almost a year ago and never had the time to play with or to include it to any product. I don't want to put it again in the pile of dev kits so I'll have to find something else to do with it during Christmass.

    Seeing some things now clearly I would like to ask a question that I hope it would not sound heretic as it isn't. Is there any massive production device in the market that uses the propeller chip? Do you have any links?

    Thank you.

    Post Edited (Jaco) : 12/22/2007 5:28:41 PM GMT
  • deSilvadeSilva Posts: 2,967
    edited 2007-12-22 17:34
    Jaco, the situation is much better than you think... It is just that there are no ready-to-go solutions,
    and you would have to dig really deep. I recognized this problem and the need for an easy to use family of video drivers
    a long time ago, but this was not the only issue smile.gif
    Jaco said...
    I would like to ask a question that I hope it would not sound heretic as it isn't. Is there any massive production device in the market that uses the propeller chip? Do you have any links?

    I would be interested in such information as well!
    I like to describe the Propeller as a "generalist", able to perform anything, but for each task you will find a "specialist" that can do it faster and for less money.
    And it is great for prototyping and feasibilty studies!
    Within its limitations...
  • RaymanRayman Posts: 14,162
    edited 2007-12-22 17:48
    Well, you can create your own fonts and custom tiles...· (This is how I would do what I think you have in mind...).· Look at a few of my things here:

    http://www.rayslogic.com/propeller/Programming/RaysStuff/RaysStuff.htm

    I have info and tools to create your own graphics and tiles here:
    http://www.rayslogic.com/propeller/Programming/Programming.htm
  • JacoJaco Posts: 9
    edited 2007-12-22 17:54
    daSilva, I understand the exact meaning of your words and I agree in the general meaning of them. I'm sure that parallax didn't just throw out an other silicon chip, this is a serious tool and really powerfull regarding calculations (although a bit expensive nono.gif ). On the other hand the ready-to-go solutions are part of our life now in electronics and I think that we all know that. It's not good or bad, white or black, it's grey actually but sometimes in my case finds me guilty for not to have the time to optimize something to get the 120% out of it.
    Sometimes this doesn't always mean lack of knowledge it's just time efficient, for example I'm always thinking that although I hate .NET Framework and I find it the worst piece of code the MS did since 1998 I'm really lucky I don't have to program web services with the alternative ways...

    Anyway, thank you for your response.
  • JacoJaco Posts: 9
    edited 2007-12-22 18:01
    Rayman, I've seen your site. Nice stuff you have there. I understood what you meant this is why I said I feel limited because I will have to store static images and I can't draw within the code with maths. Maybe I will try though, I don't know...

    Thank you for your response.
  • RaymanRayman Posts: 14,162
    edited 2007-12-22 18:12
    You might look at the Hydra stuff... They seem capable of using the prop for decent graphics... Also, I think Baggers is making a custom Prop-based graphics board...
  • JacoJaco Posts: 9
    edited 2007-12-22 18:21
    Rayman said...
    You might look at the Hydra stuff... They seem capable of using the prop for decent graphics... Also, I think Baggers is making a custom Prop-based graphics board...

    Thanks Rayman, I'll take a look also in the Hydra section.
  • potatoheadpotatohead Posts: 10,260
    edited 2007-12-22 18:26
    In your main graphics loop, you are drawing everything more or less as quickly as it can be drawn, with a clear operation between each drawn screen. In a single buffered screen, that's a worse case scenario for flicker, as most of the time, one is viewing an incomplete graphics screen.

    Consider changing the draw scheme to something that leaves most of the screen intact, for most of the time. This boils down to just spreading out the draw operations over time, and eliminating the full screen clear.

    You've likely got some static elements on the screen, so draw those, then leave them there, meaning you just don't ever clear the entire screen, or maybe clear it all once in a while, just in case. Use longfill to clear specific areas of the screen, where variable elements are present. Alternate the drawing of variable elements such that only one of them, say the pie or line graph, is being drawn at a time. This will leave most of the screen static most of the time, thus sharply diminishing the perception of flicker. Align your screen elements to the tile addressing so that a few longfill instructions will clear the area of the screen required for the graph, without having to supply too many address blocks.

    Your single buffered loop then looks something like this:

    {clear graphics screen}

    {draw all static elements]

    repeat
    {clear area of screen related to variable element 1}
    {draw variable element 1}
    {pause}
    {clear area of screen related to variable element 2}
    {draw variable element 2}
    {pause}

    {or, maybe draw them all, then pause some reasonable amount of time, say, 1/3 sec to 1/2 sec}

    The idea being to never clear the entire screen, and limit the drawing to those areas where and when it needs to occur. It takes some time for the data to accumulate right? Use the pause to allow that to happen, or just limit the number of changes per second to a lower level. IMHO, this graphics could be significantly improved, without having to deal with assembly, or double buffering. The only real cost is a lower number of total screen updates per second. If each variable element were displayed every few frames, you could get 2 - 3 complete screen updates per second, with flicker that's below the level of annoyance.

    An alternative would be to draw the graphics more slowly.

    So, incorporate a delay into the procedures that draw the graphics. Eliminate the delays in the main loop, but keep the localized clear operation. At any time, one graph is building, leaving the others static on the screen for some length of time. Arrange the delays so that an entire screen is drawn every 1/2 to 1/3 second or so. In that scenario, you are really just drawing changes and the single buffered display will have little overall impact on the perception of flicker.

    Set the display up for 4 colors, single buffered display, if you've the RAM to do that.

    Edit: Just saw that display speed is not critical. This will work nicely, and you can spread your variable drawing operations over a second or so. I would draw one graph, pause, draw the next graph, and the next, with each one in a one second cycle, resulting in a screen that fully updates every 3 -5 seconds. Do your localized clear operation, for a given variable screen element, then draw that element right after that, then pause to consume some time and let the viewer see that display for a time, before drawing the next graph.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!

    Post Edited (potatohead) : 12/22/2007 6:40:05 PM GMT
  • JacoJaco Posts: 9
    edited 2007-12-22 18:52
    Hi potatohead,

    you're right about not changing the whole image and change parts of it instead. This is also a very well used image compression method but in my case it will be a "RAM compression" method. Of course the complexity is much higher and I have to write a very efficient piece of code that will act as a mechanism that detects only the changes in the current buffer (whatever that is) and apply them on the buffer without further procession. This ain't easy at all but it's sure the most effective and actually the most programatically correct method but it's really time consuming and I think it will be again a problem if various pixels change simultaneously (not in my case though). Therefore, the problem seems to be my free time and not the prop at least for now that I can't view the result of it to decide if this method will be acceptable for a viewer.

    Maybe this method could be included in a future graphics object.

    Thank you for your response.
  • potatoheadpotatohead Posts: 10,260
    edited 2007-12-22 19:32
    I'm not sure you understood where I was going with that.

    No compression is needed.

    It's also not a whole lot of time. Try this before bailing on this whole thing:

    Simply insert a delay into your main repeat loop, maybe 2 seconds. Set your display back to single buffer, leave everything else as is. Place it right after the last graphic element is drawn. You will see your graphics build, then remain static for most of the time. Little flicker, high display utility. That one change would mean the code you have right now crosses the border from annoying to useful. If that's enough, you are done!

    What I meant by localized screen clear operations was far more coarse than I think you understood. For each graphic, there is an area of the screen it occupies. To make things really easy, just draw a black filled rectangle over that area to clear it, prior to it drawing.

    To employ fully, what I was trying to convey, one only needs two new code elements:

    one being a few clear operations that only clear where a graph is drawn. Could be just the filled rectangle command, one line then, per graph.

    the other being a delay in the main repeat loop so that things are not being drawn so rapidly. (that's the core problem, and it's just not needed, given your slow rate of change on the sensors)

    Move the full screen clear out of the main repeat loop, and it's all done.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!
  • JacoJaco Posts: 9
    edited 2007-12-22 20:05
    hmm... yes now I see where you point at it's the same thing in a larger scale. By the way, I wasn't meant compression in the real sense just the method they use in compression (my english sometimes have more bugs than my codes), which in that case it's kind of the same method you propose but with the difference that a mechanism scans only for changes in pixel level inside the buffer and changes only the pixels that have to be changed. That would be the best and programatically right solution but its time-cost and difficult to do it right.
    I'll try tommorow the method you propose which is to black only small areas and redraw only on that areas, that's far easier. Of course I expect flickering but I'll try to find a "window frame" that in given processor speed is redrawn faster than 15-20fps.

    Again, thank you.
  • deSilvadeSilva Posts: 2,967
    edited 2007-12-22 20:08
    Potatohead, what you describe is very clear and applicable in many cases,
    however not when you have a complex graphic, containing overlapping elements.

    However I think the idea to update a (rectangular) part of the screen is fine as long as it is self contained.
    Combining it with clearing and drawing within the 4 ms retrace gap - "peu-a-peu" - will be worth persuing further.

    We shall need a "patchwork" driver for it smile.gif this is the fourth kind of drivers:
    - tile drivers
    - bitmap drivers
    - sprite drivers
    - and now: a "patchwork driver"
    smile.gif

    Post Edited (deSilva) : 12/22/2007 8:16:20 PM GMT
  • potatoheadpotatohead Posts: 10,260
    edited 2007-12-22 20:11
    I don't think you need 15-20fps.

    Your data rate is on the order of seconds, therefore you only need unique graphics screens on the order of seconds.

    If you spread your graphics draws over some time, there will be moments of flicker, when an area is cleared and the new graphic is drawn, but they will be seen as program activity, not overall graphics flicker.

    Flicker will be seen and annoying at 15-20fps. Screen contrast is too high for that number to yield the perception of a steady display. Leave it static for as high percentage of time as is possible. What will happen is the eye will be drawn to the new graph, right after it is made current. This is actually useful!

    Best!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!
  • deSilvadeSilva Posts: 2,967
    edited 2007-12-22 20:16
    Flicker will be noticed when it takes too long a time between erasing (a part of) the screen and rebuilding it.
    This is quite independent of the size of the area.
  • potatoheadpotatohead Posts: 10,260
    edited 2007-12-22 20:22
    @ De-Silva, agreed.

    That is not the case on this problem though. So, we've an easy solution. Keep the display static as much of the time as is possible and spread graph redraws over some time. I would personally just draw one new one every second, alternating between all of them, such that a new, complete display happens every few seconds. That's only a few new clear commands, and a light sprinkling of delays throughout the main graphics loop --and the omission of the full screen clear, but for every hundred cycles or so. At any given time, the user has a very high percentage chance of seeing a static display. Should the user see one redraw, it's actually then a feature, indicating new data is present!

    The idea here being the flicker is managed and kept below the threshold where it's annoying. Think of how many older medical display systems worked. They employ various delay draw systems to manage flicker such that it's actually useful. For the code above, a clear, followed by a draw of the graph will be seen as activity, not annoying display quality.

    On your point of overlapping elements, really a display list is needed. If they are drawn in a specific order, then clear / XOR operations can be managed, keeping overall display change within the VBLANK period. Another option is to draw into a sub-buffer, smaller than the overall single buffered screen. Of course, the elements will need clipping, but I think the existing graphics library does that. If that's the case, then the list of display elements can be processed into the smaller buffer, clipped, then copied to the main screen in less time than a VBLANK would take. The result is more computationally heavy than other means, but one does get most of the benefit of the double buffer without actually having to have a complete double buffer. On the propeller, we usually have compute time. What we don't always have is memory.

    If those redraw, clip, copy operations were done checkerboard fashion, one per frame, the end result would be pretty decent, IMHO. Given the number of elements to be handled is not too high, screen updates, on the order of 10fps would be totally viewable and solid looking.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!

    Post Edited (potatohead) : 12/22/2007 8:28:17 PM GMT
  • deSilvadeSilva Posts: 2,967
    edited 2007-12-22 20:32
    This come close to the standard behaviour of window systems. Having a display list will also decouple the "display management" from the user.
    It will take another COG, but will improve the useability.

    I think this is exactly what I was looking for, for some time now... We had great difficulties in the classes starting with TV and GRAPHICS, as both are NOT user friendly.
    We see the same requests here in the forum....

    ----
    Edit: No, it still needs reconsideration. There are too many "show stoppers"...
    (a) You cannot have any decent animation
    (b) you cannot build complex structures, e.g. a shooting target. The flat-fill is the slowest part of GRAPHICS..

    I still prefer the "patch-work" solution, something like static sprites... GRAPHICS can easily be modified to work on many canvases...

    Post Edited (deSilva) : 12/22/2007 8:55:12 PM GMT
  • potatoheadpotatohead Posts: 10,260
    edited 2007-12-22 21:33
    There are always tradeoffs, meaning single buffered displays are almost always some combination of things being discussed.

    (hope this is ok, on this thread)

    The perception of animation begins somewhere at 8fps, looks smooth at 12-15 or so. Decent animation then is not outside the realm of possibilities for many of these options.

    If one decouples the graphics draw, from a game engine, then lower frame rates do permit things like moving targets. Also, one can use XOR to draw small elements that lie beneath the VBLANK time to generate, thus eliminating the need for a buffer at all. The moving target, and other things could happen in this fashion. If too much draw time is needed, skip frames, cull objects, etc...

    The down side for this kind of thing is that one needs to build an engine for their particular display. That's been going on for the games we are seeing so far. Lots of great examples there. Takes time, if one is not well versed and practicing that art regularly.

    If it were me, I would significantly restructure the graphics demo program for teaching.

    It's default mode is to generate the entire screen, then bulk copy it from one HUB memory region to another. In the double buffered configuration, this works, but is not optimal at all. One change, that would free significant compute time, would be to toggle the draw pointer and display pointer once drawing is complete. It would be ideal to time that toggle to the VBLANK as well, to eliminate tearing. There is no need for the bulk memory move. Higher overall frame rates are possible, as well as displays locked to the screen refresh are possible as well. Edit: Well, only if a quick screen clear is quicker than the copy.

    In the single buffer mode, putting the screen to be displayed in a single bulk repeat is highly likely to result in significant flicker for a majority of displays.

    For the single buffer then, a number of options become viable:

    -sub-buffer drawing (draw to this buffer, when complete, copy into screen memory, ideally during VBLANK)

    -slow drawing (basically, let the screen get built over some time, turning flicker into activity instead)

    -tiles (one can build up static display elements, then point the screen addresses to those areas of memory that contain the image to be displayed this one can do nice animation, BTW. The Parallax screen memory layout is very flexible, but somewhat complex. A procedure to simplify this might help students. If the same image is to appear multiple places, this can be a big savings, particularly when combined with sub-buffer drawing.)

    -XOR (draw, then re-draw, then draw again, during VBLANK times good for smaller moving things that have no overlaps if there are overlaps, then masking must happen too)

    -compression / pixel difference engines. (takes a lot of compute & highly likely to not deliver more than the other methods applied well.)

    IMHO, small examples of each would then convey the options to the students, where they then build their own display engine to solve whatever problem they have at hand.

    @deSilva Thought of another option. If graphics.spin were keyed to the vertical blank, as in only draw while VBLANK = 1, then anything written with it would then have it's drawing keyed to the display. Changes would only occur during non-display times, and I'm assuming a clear can get done in one VBLANK time. The higher level program then just sees slower graphics draws in general and has to do nothing else.

    Given that, a whole lot of graphics cases would draw largely flicker free. Some of them might appear over the course of a few frames, but that's not gonna be as detracting as the flat out flicker is, when just drawing all of it, clearing, not synced is.





    With that modification, people can plan some of their graphics, without having to deal with so many of the lower level issues.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!

    Post Edited (potatohead) : 12/22/2007 11:04:22 PM GMT
  • deSilvadeSilva Posts: 2,967
    edited 2007-12-23 00:24
    Interesting ideas!
    Your idea of using VBLANK can easily be checked without any change in GRAPHICS!
    Just WAIT until VBLANK starts before calling CLEAR
    Filling 3k longs will take 600 µs only
  • JacoJaco Posts: 9
    edited 2007-12-23 07:08
    There is still a need of a large buffer that will contain the changes before applies them and that buffer in case the whole image is changed it should be the same size with the display buffer. The problem is that the display system now looses its continuity and that's really bad because it's not deterministic as you never know what changes and when so you can't create only a small predefined buffer. Therefore, if the buffer is not of the same size with the display buffer, then it must be a dynamic buffer with an algorithm to hold the puzzle pieces' position in the real buffer and that's an extra complexity with the danger in some occasions to retrieve a bigger size buffer than the real output. In general, I think that in any occasion the RAM will still be a limit and there is no room for writing code.

    Post Edited (Jaco) : 12/23/2007 7:18:34 AM GMT
  • deSilvadeSilva Posts: 2,967
    edited 2007-12-23 08:24
    Yes, Jaco, you are right - in principle... We tend to forget that this is $10 MICRO-Controller, not a $100 "Linux-on-a-chip". And one COG (20MIPS) is not really fast...
    But -also in principle - there are many possibilities for "clever short cuts". The Video Drivers need not rely on a fixed video bitmap, but can to things "on the fly" (which is the sprite concept). Display lists COULD work similar, but we are far away from the needed processor speed...
    It already becomes awkward with sprites when you are not on byte boundary. TV timing gives you some headroom, but VGA will not..
  • JacoJaco Posts: 9
    edited 2007-12-23 08:48
    After seeing the work that some people you're doing here (that takes a simple search in the forum) with the prop and the comprehensive thinking you have it won't be a suprise for me if you overcome some of these problems and apply the "clever short cuts" in a new object. It's just me that I will not have the pleasure and time to contribute to this direction cry.gif
    I hope I see in the future an improved graphic object.

    Thank you all for your replies and keep up the good work!
Sign In or Register to comment.