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.
To be clear, I don’t want to clear the screen at all
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
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.
Clear initial 4 frames. (i dont know why 4 frames)
Update positions every 3 frames.
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 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
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 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.
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.