Huge Text Drops FPS

Hello. In a program, I have huge text that fills the screen and then quickly fades into nothing. The huge text + the transparency drops the fps from around 60 to around 20 for a few frames. I can’t see a way to fix this besides of course shrinking the text and or ditching the transparency but thats not an option. Does anyone know a way around this?

hm… Just 1 text? I am pushing 300-400 meshes per frames and still getting 20fps. I think sometimes the FPS drops a little at the start as memory is allocated?

@goatboy76 if your text is not moving you can:

  1. sprite it into an image (once),
  2. sprite the image with the fading tint(255,255,255, x ) before.
    that should restore the fps

@goatboy76 are you sure it is the text causing the FPS drop?

@Coder it does really hit the frame rate hard, trying displaying a full screens worth of text with textWrapWidth(WIDTH) every frame.

@Goatboy and @zapaper - I get a similar FPS slowdown with meshes on one of my projects that uses them extensively. It starts at 8 and then progressively gets me back up to 50fps as the project is running. Oddly, this didn’t happen under the previous version of Codea, but only since I’ve upgraded. :-/.

I also suspect its a memory alloc thing - I wonder if there’s a way of preventing this via some Lua memory allocation settings or ‘wait’ until Lua has caught up with its behind the scenes housekeeping…

Any suggestions?

@zapaper Im not quite sure what you meant
@Jmv38 How do you sprite a text? Do you make a actual image or is there another way?
@Coder If I stop drawing the text or reduce the font size by a lot then the lag stops. So I’m quite sure.

@Goatboy76 You can sprite text like this:

textImg = image(WIDTH, HEIGHT) -- Make a new, blank image
setContext(textImg) -- Drawing goes into the image, not onto the screen
text("Text here", WIDTH / 2, HEIGHT / 2) -- Draw the text, once
setContext() -- Return drawing to the screen instead of the image

and then sprite textImg instead of calling text() every frame.

@SkyTheCoder Thanks, I learned something new.

Converting the text into a image still causes the lag. It helps a tiny bitt but not by much.

@Goatboy76 Are you running that code only in setup? It shouldn’t make any lag.

I run this in init

    self.img = image(WIDTH, HEIGHT)
    setContext(self.img)
    font("Arial-BoldMT")
    fontSize(800)
    text(string.format("%1.0f", self.num), WIDTH/2, HEIGHT/2)
    setContext()  

And this in draw

    tint(255, 255, 255, self.alpha)
    sprite(self.img, WIDTH/2, HEIGHT/2)

@Goatboy76 Odd… Maybe it isn’t the text that caused most of the lag. Is there any other code that runs while the text is visible?

@SkyTheCoder The only other thing is the alpha adjustment every frame but I checked that. If I reduce the font by a lot then it works fine so its the text.

@Goatboy76 there seems to be something wrong in your code somewhere.
could you poste the full code so we can check on our side? What ipad are you running?

@Jmv38 iPad 4th gen. Stage manages the StageFades along with the hoopNum remaining.

Stage = class()

function Stage:init(hoopNum, num)
    self.num = num or 1
    self.hoopNum = hoopNum
    self.fadeTable = {}
end

function Stage:draw()
    self:AlphaCheck()
    for i = 1, #self.fadeTable do 
        if self.fadeTable[i] ~= nil then
            self.fadeTable[i]:draw()
        end
    end
end

function Stage:AlphaCheck()
    for i = 1, #self.fadeTable do
        if self.fadeTable[i] ~= nil then
            if self.fadeTable[i]:Fadded() then
                table.remove(self.fadeTable, i)
            end
        end
    end
end

function Stage:CreateFade()
    self.fadeTable[#self.fadeTable + 1] = StageFade(self.hoopNum)
    self.hoopNum = self.hoopNum - 1
    self:HoopNumCheck()
end

StageFade = class()

function StageFade:init(num)

    self.num = num
    self.alpha = 75
    self.subAlphaNum = 2
    self.img = image(WIDTH, HEIGHT)
    popStyle()
    setContext(self.img)
    font("Arial-BoldMT")
    fontSize(200)
    text(string.format("%1.0f", self.num), WIDTH/2, HEIGHT/2)
    setContext()  
    pushStyle()      

end

function StageFade:draw()

    self.alpha = self.alpha - self.subAlphaNum
    if self.alpha <= 0 then
        self.alpha = 0
    end

    -- print(self.alpha)
    pushStyle()
    tint(255, 255, 255, self.alpha)
    sprite(self.img, WIDTH/2, HEIGHT/2)
    popStyle()
    --[[
    textImg = image(WIDTH, HEIGHT) -- Make a new, blank image
    setContext(textImg) -- Drawing goes into the image, not onto the screen
    text("Text here", WIDTH / 2, HEIGHT / 2) -- Draw the text, once
    setContext() -- Return drawing to the screen instead of the image
    ]]
end

function StageFade:Fadded()
    retVal = false
    if self.alpha == 0 then
        retVal = true
    end
    return retVal
end

not 100% sure, but the loop for i ... self.fadetable[i]:draw() looks very suspicious to me. Are yousure you are not drawing fadeTable many many times here instead of only once?

@Jmv +1 I got no lag at all when using only a single StageFade class. That loop looked potentiously laggy.

@Goatboy76 Are you sure you’re only adding a new fade once?

@Jmv38 That does look suspicious. I haven’t been able to find anything in my tests that would point to it drawing several times. Also, if it drawed enough times to cause that big of a lag drop, then the text wouldn’t be transparent.

@SkyTheCoder When I print the #self.fadeTable the number makes sense as its usually 1 or 2 and whenever I make one the number it displays is one less than the last so think it would be quite apparent if that was the case.

I have a confession to make. There was an error with this code before and I slapped on a very nasty bandaid. Occashionly when there was multiple fades it would error out saying that it was attemping to index a fade that wasent there in the table. So what did I do? I just threw in a if statment seeing if self.fadeTable[i] was nil. I still don’t know why that bug is there and I think thats part of the puzzle.

This program shows what I’m talking about. Just tap the screen to make a fade. Paste the whole thing in to main.

-- Stage Fade test

-- Use this function to perform your initial setup
function setup()
    fadeTable = {}
    num = 10
end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(40, 40, 50)
    
    local fps = 1/DeltaTime
    fill(255,255,255)
    fontSize(30)
    textMode(CENTER)
    text(string.format("%1.0f",fps), WIDTH - 40, 10)
    pushStyle()
    
    FaddedCheck()
    DrawFades()

end

function touched(touch)
    if touch.state == BEGAN then
        CreateFade()
    end
end

function CreateFade()
    num = num - 1
    fadeTable[#fadeTable + 1] = StageFade(num)
end


function DrawFades()
    for i = 1, #fadeTable do
        fadeTable[i]:draw()
    end
end

function FaddedCheck()
    for i = 1, #fadeTable do
        if fadeTable[i]:Fadded() then
            RemoveFade(i)
        end
    end
end

function RemoveFade(i)
    table.remove(fadeTable,i)
end

StageFade = class()

function StageFade:init(num)

    self.num = num
    self.alpha = 75
    self.subAlphaNum = .5
    self.img = image(WIDTH, HEIGHT)
    popStyle()
    setContext(self.img)
    font("Arial-BoldMT")
    fontSize(200)
    text(string.format("%1.0f", self.num), WIDTH/2, HEIGHT/2)
    setContext()  
    pushStyle()      

end

function StageFade:draw()

    self.alpha = self.alpha - self.subAlphaNum
    if self.alpha <= 0 then
        self.alpha = 0
    end

    -- print(self.alpha)
    pushStyle()
    tint(255, 255, 255, self.alpha)
    sprite(self.img, WIDTH/2, HEIGHT/2)
    popStyle()
    --[[
    textImg = image(WIDTH, HEIGHT) -- Make a new, blank image
    setContext(textImg) -- Drawing goes into the image, not onto the screen
    text("Text here", WIDTH / 2, HEIGHT / 2) -- Draw the text, once
    setContext() -- Return drawing to the screen instead of the image
    ]]
end

function StageFade:Fadded()
    retVal = false
    if self.alpha == 0 then
        retVal = true
    end
    return retVal
end