Roku Developer Program

Developers and content creators—a complete solution for growing an audience directly.
cancel
Showing results for 
Search instead for 
Did you mean: 

invalidating bitmaps/sprites

I have a carousel of large images. In order to optimize the amount of available memory I am trying to remove the offscreen sprites from the compositor and then invalidate them. However after i have done so using the r2d2_bitmaps command on port 8080 still shows the bitmaps in the graphics memory. What are the steps for removing a sprite and it's corresponding bitmap from memory?

the relevant functions are below




'avalanche is called from a videoplayer, ads is json from the default getads interface

function avalanche(ads) as boolean
av = setup(ads)
if av.load("http://vmg-us.s3.amazonaws.com/demo/designlab/av-demo-app/source/rokucontent.json")
if av.events()
return true
end if
end if
End function

function setup(ads) as object
this = {
port: CreateObject("roMessagePort")
index: {x: 0, y: [0]}
paused: false
fonts: CreateObject("roFontRegistry") 'global font registry
canvas: CreateObject("roImageCanvas") 'user interface
compositor: CreateObject("roCompositor") 'user interface
clock: CreateObject("roTimespan")
adclock: CreateObject("roTimespan")
player: []
tobedrawn: []
ads: ads
bitmaps : []
introplayed: false
interacted : false
load: load
downloading: {}
videocontrolcanvas: []
videocontroldata: []
initialblack: initialblack
spriteinator: spriteinator
canvinator: canvinator
videocontrols: videocontrols
track: track
events: events
sprites: []
canvasitems: []
imagecachecontrol: imagecachecontrol
canTranslate: canTranslate
translate: translate
bounds: bounds
frames: []
adtimer: adtimer
crumblabel: crumblabel
crumblabeldata: []
adtimerdata: []
close: close
get: get
fade: fade
selector: selector
selected: 0
action: action
play: play
openstore: openstore
writeessay: writeessay
waitforfont: []
drawing: 0
cachefull: false
}


this.canvas.SetMessagePort(this.port)
this.canvas.SetLayer(0, { Color: "#000000" })
loading = []
loading.Push({
Text: "Creating Your Interactive Ad Experience..."
TextAttrs: { font:this.fonts.Get("Syfy Medium", 12, False, False), color: "#ffffff" }
TargetRect: {x: 530, y: 250, w: 300, h:200}
})
this.canvas.SetLayer(1, loading)
this.displaymode = "canvas"
this.canvas.Show()
return this
end function

function spriteinator(file as string, sprite) as object
tempfile = "tmp:/"+ file.tokenize("/")[int(file.tokenize("/").count() - 1)].tostr()

if sprite.meta.delta <> invalid
delta = sprite.meta.delta
x = (sprite.meta.offset.tokenize("|")[0].toint() - (sprite.meta.dimension.tokenize("|")[0].toint() * m.index.x * delta.tokenize("|")[0].tofloat()))
else
x = sprite.meta.offset.tokenize("|")[0].toint()

end if

bitmap = CreateObject("roBitmap", tempfile)
m.bitmaps.push(bitmap)

sprite = m.compositor.newsprite(x, sprite.meta.offset.tokenize("|")[1].toint(), createobject("roregion", bitmap, 0, 0, sprite.meta.dimension.tokenize("|")[0].toint(), sprite.meta.dimension.tokenize("|")[1].toint()), sprite.meta.offset.tokenize("|")[2].toint())
if sprite = invalid
m.cachefull = true
end if
return sprite

end function

function imagecachecontrol()
if m.cacherefresh = m.index or m.cacherefresh = invalid
this = {carousel:0,x:0,y:0,grid:[],filecheck:CreateObject("roFileSystem")}
while m.cachefull <> true
for each sprite in m.sprites
if sprite.meta.imgsrc <> invalid
this.tempfile = "tmp:/"+ sprite.meta.imgsrc.tokenize("/")[int(sprite.meta.imgsrc.tokenize("/").count() - 1)].tostr()
end if
this.carouselwidth = m.canvas.getcanvasrect().w
this.carouselheight = m.canvas.getcanvasrect().h

this.gridx = sprite.meta.offset.tokenize("|")[0].toint() / this.carouselwidth
if sprite.meta.delta <> invalid
if sprite.meta.delta.tokenize("|")[0].toFloat() <> 0
this.gridx = this.gridx / sprite.meta.delta.tokenize("|")[0].toFloat()
end if
end if
this.gridy = sprite.meta.offset.tokenize("|")[1].toint() / this.carouselheight

if sprite.meta.delta <> invalid
if sprite.meta.delta.tokenize("|")[1].toFloat() <> 0
this.gridy = int(this.gridy / sprite.meta.delta.tokenize("|")[1].toFloat())
end if
end if
if sprite.meta.position <> invalid
this.gridx = sprite.meta.position.toint()
end if
square = [this.gridx, this.gridy]
if sprite.meta.contentmodel <> "videocontrol"
if (square[0] = m.drawing) or (sprite.meta.contentmodel = "crumb" or sprite.meta.contentmodel = "crumb-behind")
?"drawing sprites for panel" + m.drawing.tostr()
if sprite.meta.scrollabletext<>invalid
if m.fonts.getfont(sprite.meta.scrollabletext.tokenize("|")[5], sprite.meta.scrollabletext.tokenize("|")[6].toint(), False, False) <> invalid
sprite.sprite = m.writeEssay(sprite)
else
m.waitforfont.push(sprite.meta)
end if
end if

if (this.filecheck.exists(this.tempfile) = false) and (sprite.meta.imgsrc <> invalid)
m.get(sprite.meta.imgsrc, sprite.meta)

?"Downloading"
?sprite.meta

else if (sprite.sprite = invalid) and (this.filecheck.exists(this.tempfile) = true) and (sprite.meta.imgsrc <> invalid)
if m.frames.count() = 0
sprite.sprite = m.spriteinator(this.tempfile, sprite)
else
m.tobedrawn.push([this.tempfile, sprite])
end if
end if
end if
end if
end for
if m.events() and m.cachefull <> true
m.drawing = m.drawing + 1
end if
end while

for each sprite in m.sprites

'i decided to remove all the sprites from my parent function to see if anything happened

if sprite.sprite <> invalid
?"REMOVING"
?sprite.meta
stop
sprite.sprite.remove()
sprite.sprite = invalid
global.rungarbagecollector()
end if
end for

end if
end function


0 Kudos
12 Replies
NewManLiving
Level 7

Re: invalidating bitmaps/sprites

While taking only a quick scan of your code you appear to use a compositor with an imagecanvas. Compositors are used with an roScreen. Imagecanvas has its own built in way of displaying images. To release all resources you need to invalidate all created bitmaps as well. It's generally the bitmap that you see in memory. I would reconsider using roScreen for a carousel or use the imagecanvas with correct layers set to the image URL
My Channels: 2D API Framework Presentation: https://owner.roku.com/add/2M9LCVC
Updated: 11-11-2015 - Completed Keyboard interface
The Joel Channel ( Final Beta )
0 Kudos

Re: invalidating bitmaps/sprites

The compositor and the canvas are used for seperate purposes. The carousel is handled entirely by the compositor. There is a video player which uses the image canvas, to display it's controls.

I have trouble invalidating the bitmap once it has been used in a sprite. If i create a bitmap, and then set it to invalid the bitmap is released from memory, however if i define a bitmap, then define a region of that bitmap, then define a sprite of that region, then call .remove() on that sprite, the bitmap remains in memory.

when testing over telnet

bitmap = CreateObject("roBitmap", tempfile)

r2d2_bitmaps returns:

RoGraphics instance 0xafb2c66
address width height bpp size name
0xaccde06 180 18 4 24576
0x603a066 196 24 4 28672
0xae1ef8e 196 128 3 114688 /tmp/plugin/NECAAAdJHbXW/tmp:/crumb4.jpg
Available memory 69832064 used 167936 max 70000000


after bitmap = invalid
r2d2_bitmaps returns as expected:

RoGraphics instance 0xafb2c66
address width height bpp size name
0xaccde06 180 18 4 24576
0x603a066 196 24 4 28672
Available memory 69946752 used 53248 max 70000000

if then over telnet i run

bitmap = CreateObject("roBitmap", tempfile)
sprite = m.compositor.newsprite(x, y, createobject("roregion", bitmap, 0, 0, bitmap.getwidth(), bitmap.getheight())

and then i run

sprite.remove()
bitmap = invalid

r2d2_bitmaps still returns

RoGraphics instance 0xafb2c66
address width height bpp size name
0xaccde06 180 18 4 24576
0x603a066 196 24 4 28672
0xae1ef8e 196 128 3 114688 /tmp/plugin/NECAAAdJHbXW/tmp:/crumb4.jpg
Available memory 69832064 used 167936 max 70000000

Is there some additional step needed to remove that bitmap once defined in a sprite?
0 Kudos
NewManLiving
Level 7

Re: invalidating bitmaps/sprites

Generally your AA keeps a handle to your region (optional) the bitmap and the Sprite. When the Sprite is removed then both the bitmap and the Sprite inI the AA are invalidated to release memory. Memory is recovered with the next call to swapbuffers using the roScreen. I have no experience using the compositor apart from roScreen nor do I completely understand the reason for its use apart from roScreen. Sprites are positioned on an roScreen and used for collision, layering etc. exactly what to you intend to do with the Sprite
My Channels: 2D API Framework Presentation: https://owner.roku.com/add/2M9LCVC
Updated: 11-11-2015 - Completed Keyboard interface
The Joel Channel ( Final Beta )
0 Kudos

Re: invalidating bitmaps/sprites

Well, to be honest when i set this up I had no idea what i was doing.

I am using the sprites to contain bitmaps, so that I can layer them, and more easily move them across the screen, and in particular create a neat parrallaxing effect ( each layer translates at a slightly different rate to create a false sense of depth) when the carousel advances.

rather than establishing a region the size of the screen for a much larger bitmap and then changing it's offset within the region to scroll, I have several sprites, where each sprite is it's own layer, and then I use the sprite's moveto utility in order to scroll.

In the netflix app when you scroll down from their initial hero image, it parallaxes slightly as it fades out. I am trying to replicate something similar for each panel of the carousel, altho without the fadeout.

the carousel has a series of panels, where each covers the whole screen.
0 Kudos
NewManLiving
Level 7

Re: invalidating bitmaps/sprites

That's a very appropriate way to use sprites. However that will only work with roScreen ( which perhaps you are using? ) not imagecanvas. Furthermore you cannot use an imagecanvas and an roScreen at the same time. They have incompatible window stacks. Notice that compositor.setdrawto takes an roScreen or bitmap handle. Either way they can only be drawn on an roScreen not an inagecanvas. Imagecanvas is also inappropriate for a carousel and it is much too slow
My Channels: 2D API Framework Presentation: https://owner.roku.com/add/2M9LCVC
Updated: 11-11-2015 - Completed Keyboard interface
The Joel Channel ( Final Beta )
0 Kudos
NewManLiving
Level 7

Re: invalidating bitmaps/sprites

If you want to pull off what you describe and have a large number of bitmaps that need to be memory managed your best bet is the roScreen and the rotexturemanager
My Channels: 2D API Framework Presentation: https://owner.roku.com/add/2M9LCVC
Updated: 11-11-2015 - Completed Keyboard interface
The Joel Channel ( Final Beta )
0 Kudos
NewManLiving
Level 7

Re: invalidating bitmaps/sprites

After reading further about your Netflix effects. A combination of direct screen draw and region offsetting is faster than redrawing or moving each Sprite esp in roku 1. You can create entire or partial regions within any bitmap or combination of bitmaps such as the top row of a grid bitmap and animate them drawing the region directly to the screen and offsetting the regions that you only wish to scroll normally such as rows below the top row. To pull this off you basically define your region to be animated ( this is usually a composite ), set the z order of those sprites you are animating via their regions to < 0 to hide the Sprite, call compositor.drawall to draw all sprites not in the animation, then use the roScreen drawing functions to perform your animation and then call swapbuffers. When done you simply offset the hidden sprites to their final destination, change the z order back to visible and redraw. I use this approach all the time to create complex interface. The only drawback (and not so much) is that your direct screen draw will overwrite any visible Sprite. If you need to perform layered animation then you simply get those regions and later your direct drawing as you would if you did not use compositor
My Channels: 2D API Framework Presentation: https://owner.roku.com/add/2M9LCVC
Updated: 11-11-2015 - Completed Keyboard interface
The Joel Channel ( Final Beta )
0 Kudos

Re: invalidating bitmaps/sprites

Yeah, it occurred to me that this is probably the case. i will look into that.

This is in response to your previous post:

I did not post the full code, a roscreen is defined, but not until after the first round of bitmaps is downloaded. I am using rourlttansfer to manage my bitmaps, mainly because i didn't want to have a separate get function for bitmaps and my other http get requests. Is there a benefit to using the texturemanager over an asynchronous urltransfer and then creating a bitmap from the filesystem?

There are two seperate screen stacks. I am not sure if this is the intent, but whichever screen stack is defined last ends up showing on top. So if i define a roscreen and then define a roimagecanvas it works similar to the regular screen stack. Altho both cover the whole screen.

I need a videoplayer on the screen on user initiation, however i dont want to deconstruct my roscreen / all my sprites yet. If you display the rovideoplayer on roscreen it always shows on the bottom layer below the screen and is covered by other image data. i decided to solve this by defining a new image canvas and then targeting my videoplayer and it's ui to that. Then to return to the screen i just close the image canvas.

I have a working version that displays the carousel and video and animations as intended.

The problem l am specifically having is this: over the course of navigating through the carousel of images, images are downloaded from a server before they come into view, and then a sprite is generated to add to the carousel. Other images are deleted in order to give those space. This works fine but i have to preset the number of frames it loads in each direction.

What i want to do is this: load and create bitmaps until a bitmap returns invalid when defined. Then delete the frame of images that weren't completely loaded. This will reduce the number of times i have to load.

Right now this fails during the main loading sequence. The bitmaps are loaded, one returns invalid, the sprites for the extra frame are removed, but the bitmaps for those sprites remain in memory. When a new bitmap is created to fadeout the load screen the memory is already full.

I think i may need to call screen.swapbuffers, maybe the bitmaps are not released until the buffer has cleared.

I cant test until tomorrow.
0 Kudos

Re: invalidating bitmaps/sprites

Looking at it this morning, it seems that i need to call screen.clear> compositor.drawall> screen.swapbuffers before invalidating my sprites, regions, and bitmaps. After doing it in this order the memory for the bitmaps used in sprites is cleared.
0 Kudos