I'm writing a XUL application using HTML Canvas to display Bitmap images.
I'm generating ImageDatas and importing them in a canvas using the putImageData function :
for(var pageIndex=0;pageIndex<100;pageIndex++){
this.img = imageDatas[pageIndex];
/* Create the Canvas element */
let imgCanvasTmp = document.createElementNS("http://www.w3.org/1999/xhtml",'html:canvas');
imgCanvasTmp.setAttribute('width', this.img.width);
imgCanvasTmp.setAttribute('height', this.img.height);
/* Import the image into the Canvas */
imgCanvasTmp.getContext('2d').putImageData(this.img, 0, 0);
/* Use the Canvas into another part of the program (Commented out for testing) */
// this.displayCanvas(imgCanvasTmp,pageIndex);
}
The images are well imported but there seems to be a memory leak due to the putImageData function.
When exiting the "for" loop, I would expect the memory allocated for the Canvas to be freed but, by executing the code without executing putImageData, I noticed that my program at the end uses 100Mb less (my images are quite big).
I came to the conclusion that the putImageData function prevents the garbage collector freeing the allocated memory.
Do you have any idea how I could force the garbage collector to free the memory? Is there any way to empty the Canvas?
I already tried to delete the canvas using the delete operator or to use the clearRect function but it did nothing.
I also tried to reuse the same canvas to display the image at each iteration but the amount of memory used did not changed, as if the image where imported without deleting the existing ones...
You could try clearing the canvas after the loop. Looking at your code, imgCanvasTmp is still reachable, and can't be garbage collected. Note that you might need to let the browser idle for a few minutes before the garbage collector to kick in. Also, maybe you want to clear imageDatas too.
Related
Hi all I want to ask something. I've made a game with Flash CC and createJS. it's a Drag and drop game (3 object for drag, and 3 object for drop) and a lot of vector movieclip object. But when I run it in mobile, the game looks like have a performance issues. I've read some article that talk about caching the object. But I'm really dont know anything about cache and don't know how to use it on an object like movieclip. Do you have any explanation or solution or maybe a tutorial how to use cache function? Thank you very much.
From the docs:
Draws the display object into a new canvas, which is then used for subsequent draws. For complex content that does not change frequently (ex. a Container with many children that do not move, or a complex vector Shape), this can provide for much faster rendering because the content does not need to be re-rendered each tick. The cached display object can be moved, rotated, faded, etc freely, however if its content changes, you must manually update the cache by calling updateCache() or cache() again. You must specify the cache area via the x, y, w, and h parameters. This defines the rectangle that will be rendered and cached using this display object's coordinates.
http://createjs.com/Docs/EaselJS/classes/DisplayObject.html#method_cache
So, you don't want to cache a playing MovieClip (you would have to update the cache every frame, which is slow). However, you could cache elements in the MC that are just being transformed.
For example, an animation of a walking character, with complex vector shapes for the arms, legs, head, and body that are being transformed (scaled, rotated, translated) to create the walk animation. You wouldn't cache the character MC, but you could cache the body parts themselves.
I've got a large, detailed, interactive vector object with dynamic text that will frequently translate horizontally from off the screen onto the screen when the user needs to look at it, then back off the screen when the user is done. If I set myVector.cacheAsBitmap = true before translating it and myVector.cacheAsBitmap = false after translating it, what happens to all of those bitmaps that are generated each time? Do I have to dispose of them myself?
Adobe help about Bitmap caching:
Turning on bitmap caching for an animated object that contains complex
vector graphics (such as text or gradients) improves performance.
However, if bitmap caching is enabled on a display object such as a
movie clip that has its timeline playing, you get the opposite result.
On each frame, the runtime must update the cached bitmap and then
redraw it onscreen, which requires many CPU cycles. The bitmap caching
feature is an advantage only when the cached bitmap can be generated
once and then used without the need to update it.
If you turn on bitmap caching for a Sprite object, the object can be
moved without causing the runtime to regenerate the cached bitmap.
Changing the x and y properties of the object does not cause
regeneration. However, any attempt to rotate it, scale it, or change
its alpha value causes the runtime to regenerate the cached bitmap,
and as a result, hurts performance.
Conclusion
If you make a simple translational movement along the x or y axis, your bitmap is created only one time.
Do I have to dispose of them myself?
It seems that you can't touch the bitmap cache only used internally by Flash player.
I am developing a Windows Store App using XAML / C#. The app also has a Windows Runtime Component, which is used for showing a Chart ouput using DirectX.
I am using SwapChainPanel approach for drawing the lines (x-axis, y-axis and waveform).
I chose this approach from the below MSDN sample (refer scenario 3 - D2DPanel)
http://code.msdn.microsoft.com/windowsapps/XAML-SwapChainPanel-00cb688b
Here is my question,
My waveform contains a huge number of data (ranging from 1,000 to 20,000 set of points). I am calling DrawLine continuously for all these points during each Render function call.
The control also provides panning and zooming but keeps the StrokeWidth constant irrespective of zoom level, hence the visible area (render target) might be much less than the lines I am drawing.
Does calling DrawLine for the area which are going to be off-screen cause performance issues?
I tried PathGeometry & GeometryRealization but I am not able to control the StrokeWidth at various zoom level.
My Render method typically resembles the below snippet. The lineThickness is controlled to be same irrespective of zoom level.
m_d2dContext->SetTransform(m_worldMatrix);
float lineThickness = 2.0f / m_zoom;
for (unsigned int i = 0; i < points->Size; i += 2)
{
double wavex1 = points->GetAt(i);
double wavey1 = points->GetAt(i + 1);
if (i != 0)
{
m_d2dContext->DrawLine(Point2F(prevX, prevY), Point2F(wavex1, wavey1), brush, lineThickness);
}
prevX = wavex1;
prevY = wavey1;
}
I'm kind of new to DirectX, but not to C++. Any thoughts?
Short answer: It probably will. It's good practice to push a clip before drawing. For instance, in your case, you'd do a call to ID2D1DeviceContext::PushAxisAlignedClip with the bounds of your drawing surface. That'll ensure no drawing calls attempt to draw outside the surface's bounds.
Long answer: Really, it depends on a handful of factors, including but not limited to what target the device context is drawing to, the display hardware, and the display driver. For instance, if you're drawing to a CPU-backed ID2D1Bitmap, it's probably fair to assume that there won't be much of a difference.
However, if you're directly drawing to some hardware-backed surface (a GPU bitmap, or a bitmap created from an IDXGISurface), it can get a little hairy. For example, consider this comment from an excellently documented MSDN sample. Here, the where the code is about to Clear an ID2D1Bitmap created from an IDXGISurface:
// The Clear call must follow and not precede the PushAxisAlignedClip call.
// Placing the Clear call before the clip is set violates the contract of the
// virtual surface image source in that the application draws outside the
// designated portion of the surface the image source hands over to it. This
// violation won't actually cause the content to spill outside the designated
// area because the image source will safeguard it. But this extra protection
// has a runtime cost associated with it, and in some drivers this cost can be
// very expensive. So the best performance strategy here is to never create a
// situation where this protection is required. Not drawing outside the appropriate
// clip does that the right way.
I'm working on a small game in Flash (AS3) that generates levels using small tiles.
The location,width,height and other properties of the tile are stored in an array upon generation. Each tile is added to the same container movieclip. When all tiles have been generated, the container movieclip is converted to a bitmap, all tiles are removed from the stage, and the original container is removed from the stage and then deleted. The bitmap is the only remaining "graphic" on the stage, aside from the player.
This yields far better performance than allowing all 60,000+ tiles to be rendered individually during gameplay; however, the framerate still reduces as the number of tiles is increased. This makes no sense, as all the tiles are added to a single bitmap that is always the same size, regardless of the amount of tiles.
With 20,000 tiles during generation, the game runs at the full FPS, but with 60,000 it runs relatively choppy, probably around 4-5 FPS.
I've removed collision detection and any/every script that runs through the tile array to rule out the possibility that some other CPU intensive part of the script is lagging the framerate.
Any idea why, despite the fact that all tiles have been removed from the stage and their container is deleted, the game is still running slow even though the background bitmap contains the same amount of data regardless of the number of tiles generated?
Here is the last part of the level generation algorithm which converts the container movieclip to a bitmap and then removes all the tiles:
var temp_bitmap_data:BitmapData = new BitmapData(this.stage_background_mc.width,this.stage_background_mc.height);
temp_bitmap_data.draw(this.stage_background_mc);
this.stage_background_bitmap = new Bitmap(temp_bitmap_data);
main_class.main.stage.addChild(this.stage_background_bitmap);
for (var block in blocks_array)
{
//every block in blocks_array has a child that is the actual graphic of the tile
blocks_array[block]["block"].removeChild(blocks_array[block]["block"].getChildAt(0));
if (blocks_array[block]["type"] == "bg_block")
{
this.stage_background_mc.removeChild(blocks_array[block]["block"]);
blocks_array[block]["block"] = null;
}
if (blocks_array[block]["type"] == "path_block")
{
//path_blocks have a second child in addition to the first one that's already been removed. the second child is the only other child
blocks_array[block]["block"].removeChild(blocks_array[block]["block"].getChildAt(0));
this.stage_background_mc.removeChild(blocks_array[block]["block"]);
}
}
this.stage_background_mc = null;
[Edit]
Here is a picture of the game to give you a better idea of what's going on:
[Update:]
Even removing the final created bitmap from the stage, ending up with only 1 child on stage, and setting that removed bitmap to null doesn't improve the speed.
A couple of thoughts.
First, you're sorta half taking advantage of AS3's quick work with blitting. You've got the right idea about having only one single Bitmap on the stage, but the steps before (adding DisplayObjects to a MovieClip and the doing draw on that MovieClip) isn't the fastest process. For one thing, BitmapData.draw is slower than BitmapData.copyPixels (here is a post on that). One of the best ways to get speed is to pre-blit all of your graphics, and store them as BitmapData. Then, keep Object references (containing position, etc) for each graphic. In your render loop, run through each object, and use copyPixels to copy the graphic's pixel information to the appropriate positon in your single, on-stage Bitmap. This way, all slow BitmapData.draw commands have happened upfront, and now you are just pushing pixels, which Flash is really fast at.
That process isn't without its downsides, however. For instance, you can't do easy transforms with it. You'd have to pre-blit all frames of a rotation, for instance, in order to rotate the individual graphic (since you can't rotate a BitmapData, and you aren't using draw on a DisplayObject). Still, it is mighty fast if you can live with the limitations.
Here is a post that serves as a tutorial of the process I explained above. It is old, but informative none-the-less.
Finally, 60,000 is a very large number. Flash isn't exactly a "speed demon." No matter how optimized, eventually you'll hit a limit. Just something to keep in mind.
Oh, and this additional post gives some great tips on performance in Flash.
I have a bit trouble with LoaderMax memory occupy, i have a queue, and i am keep loading images depend on user's action. if they click load more and it keep load, but i would like to clean the memory which been occupied by the previous queue (i have remove all the children been added by the loading previously). is there a way i can do it?
the behavior like this.
load
(load the page 1)
load
(load the page 2 and clean the page 1)
queue = new LoaderMax({name:"mainQueue", autoDispose :'true'});
**
A very quick question, everything in the queue (images). Do they all
cache in the browser?
**
{ autoDispose:true } will not unload content, only call the LoaderMax instances dispose method automatically.
You can either call queue.unload() or queue.dispose(true) to remove your loaded content.
Also make sure you have removed any listeners from the children you added to the display to ensure they are garbage collected.
LoaderMax Documentation
To answer your quick question: depends on the browsers settings but probably. LoaderMax has cache-busting options if you are worried about that.