Strange rendering "flicker" (example code)

Here’s the code I’m running that has a really odd flickering effect (even when clearing background on the first call of draw).

I thought maybe the issue was the decimal numbers being send to rect so I tried rounding them to integers, no luck.

I added a crappy psuedo-sleep function to slow things down and can see the pixels “wiggling” well after they are drawn.

I’m using iOS 5.0 (9A334) on an MC916LL ipad2



-- Use this function to perform your initial setup
function setup()
	theta = 0

	offsetX = WIDTH / 2
	offsetY = HEIGHT / 2

	first = true
end

-- This function gets called once every frame
function draw()
	r = theta

	x = r * math.cos(theta) + offsetX
	y = r * math.sin(theta) + offsetY

	if (first) then
		background(0, 0, 0, 255)
		first = false
	end

	x=round(x)
	y=round(y)

	fill(0, 255, 38, 255)
	rect(x,y,20,20)

	print(x,y)

	theta = theta + 1.25

	sleep()
end

function sleep()
	for i=1,999999 do
	end
end

function round(num,idp)
	local mult=10^(idp or 0)
	return math.floor(num * mult + 0.5) / mult
end

I’m pretty sure this is an issue with double buffering on the graphics. Each frame you draw, you are drawing to one of two buffers which swap between showing on the screen, and being drawn to. If you don’t clear them every frame (or draw on the whole screen), then you will see it swapping the buffers (you are effectively seeing where objects where at even and odd frames).

One way to fix this may be to not draw anything on odd frames. We could put a call in that makes it only call draw every second frame also.

Try doing something like:


drawFrame = true

function draw()
  if drawFrame
    --do your drawing
  drawFrame = not drawFrame
end



Hi,
I think you’ll find that the flickering will go away if you actually clear the background on every draw frame (as opposed to just the first). It’s basically the same as a clearcreen command. I currently draw over a thousand random lines with random colours and widths, with no flickering at all. Just have a background command at the very start of the draw method. :slight_smile: :slight_smile:

I’m putting a background() call inside draw() in the new default project template when Codea is updated.

Hopefully this will solve the confusion. It doesn’t clear by default in case people want to draw trails, as in the Handling Touches example.

To be clear, I don’t want to clear the screen at all :slight_smile:

Dylan’s fix (mostly) works. Drawing every other frame only writes to one of apparently 2 buffers mostly giving me the expected result (there is a different flicker as the blank buffer flips in every other frame of course).

Now that he pointed it out I can see it clearly. Half the pixels are being shown in one frame with the other half shown in the next which results in something rather psychedelic, but unexpected.

The expectation of cod(ify | ea) seems to be that I’m doing some kind of animation. In this case however I just want to cumulatively add pixels to the image without any clearing.

If I don’t clear the screen with the background function, I would expect the current screen buffer to be copied to the next so, when I add my new pixels, the existing ones are already there :slight_smile:

jguice: we’re surprised by this behaviour too. The iPad device seems to be triple-buffered with rendering occurring over the frame-before-last, creating a flickering effect. Running the same code on Mac OS X doesn’t exhibit this behaviour.

This bug won’t be fixed in the next update, unfortunately. We’ll keep looking for a way to solve it, though.

Temporary solution

  1. Clear initial 4 frames. (i dont know why 4 frames)
  2. Update positions every 3 frames.
  3. Draw every frame.

Code:


-- Use this function to perform your initial setup
function setup()
    theta = 0
    offsetX = WIDTH / 2
    offsetY = HEIGHT / 2

    --elapsed = 0
    --watch("elapsed")

    f = 0
    iparameter("updateRate", 2, 15, 3)
    clearFirstXFrames = 4
end

-- This function gets called once every frame 
function draw()
    -- Clear initial frames
    if clearFirstXFrames > 0 then
        background(255, 0, 0, 255)
        clearFirstXFrames = clearFirstXFrames - 1
        return
    end

   -- Update positions every x frames
   if math.fmod(f, updateRate) == 0 then 
    --if elapsed == 0 or elapsed >= 0.05  then 
       -- print("updating...") 
       doUpdate()
      -- elapsed = 0
    --end
    --elapsed = elapsed + DeltaTime    
   end

   -- draw every frame
   doDraw()
   f = f + 1
 end

function doUpdate()
    r = theta

    x = r * math.cos(theta) + offsetX
    y = r * math.sin(theta) + offsetY

    x=round(x)
    y=round(y)
    
    theta = theta + 1.25
end

function doDraw()
    fill(0, 255, 38, 255)
    rect(x,y,20,20)
end

function round(num,idp)
    local mult=10^(idp or 0)
    return math.floor(num * mult + 0.5) / mult
end

I like this bug, please leave it :smiley: If you move a sprite around the screen without clearing the double/triple buffering gives the impression that old sprites are still animated (the old unlimited bobs effect, if anyone else remembers old demos :slight_smile:

@GabrielMoreira Thanks! Nice workaround :slight_smile:

I have a sprite library that tracks dirty regions across the triple-buffer and ends up drawing much faster than I could if I cleared the BG and redrew every cycle. It’s nice to have the option to be fast!

I have added the ability to optionally turn off the triple buffering in a future update.

I just tried some sample code to see exactly what happens and found that it varied quite a bit. There’s an initial stage which is quite chaotic, after which it settles down. But if I had a print statement in the draw function then I got two buffers and if I didn’t then I got three. The settling down period was roughly ten full cycles (so 20 with the print and 30 without).

Also, the time-per-frame took some time to settle into a rhythm.

This stuff is all controlled by iOS’s opengl compositor, so who knows what crazy optimisations they have setup. Our code just uses their default opengl view setup, so I cant really shed any light on what its actually doing.

There is a parameter you can give the OS which tells it to stop the shenanigans and just do straight retained mode backing, which simulates single buffering. This means its not as optimised though, and causes rendering to slow down substantially on iPad 1.

How slow is it in comparison to having to draw the same thing three times to ensure that it appears on every frame?

I was looking at it today with Dylan, it’s not too slow on iPad 1. It seems to cause a small framerate hit on iPad 1 (~5 fps). The benefits might outweigh the cost for some applications.

Yeah drawing the same thing for three frames would basically cut your framerate to a third, so its nowhere near that bad.
5 fps is noticeable on an iPad 1 if you are already running around 20fps or so because you are drawing a lot, but I guess apps that use this would be more about drawing images or painting than they would be about high framerates.

So when you say ~5fps do you mean that if my app runs at x fps without the parameter set then it goes to x - 5 fps with this on?

From your side, I would guess that the best strategy is to make it user-configurable. This would also be the best from our side so long as we have good information to help us decide which strategy to use and when.

Yeah, x - 5fps on iPad 1 with retained backing mode enabled. It will be off by default, as it’s really only useful in specialised cases.