If I draw an image to the canvas and the pixels end up being mostly the same as what's already there, will this be faster than if I draw an image where all the pixels end up changing?
Unfortunately no, everything drawn to canvas is drawn using compositing (Porter-Duff) and blending rules regardless of what already is there before it (the same math is applied).
There is some form of dependency though as the existing content may influence the look on the final outcome of these operations, but not in a performance sense. Say various blending modes, global alpha, and of course compositing modes themselves etc.
The cost of checking what to draw and not would most likely outweight the cost of just drawing the content, and it would need to implement a somewhat complex mechanism to consider the various methods that can be used to draw - ie. not so useful for performance.
A browser vendor may chose to optimize for specific cases, but in general and regardless of existing content: everything passes through blending mode, composition and finally alpha blending with the background, at context level - this produces the bitmap used for the next step (or that we can extract as an image). Then something similar at element/DOM level so that the canvas and its content blends in with the rest of the page/DOM content, but where the alpha channel can be considered in a special way:
One exception in regards to performance, also in general, is when the browser need to composite and alpha blend the canvas element itself with the background (ie. everything behind the element). If the alpha channel is disabled for the canvas element, the browser can optimize this step which gives us a little more performance to draw from.
To disable the alpha channel for the 2D context you simply pass in the option:
var ctx = canvas.getContext("2d", {alpha: false});
The two actions will take exactly the same amount of time, because they are both doing the same action. The result of the pixels does not change the speed of how long it will take to execute the code :)
It doesn't matter if the pixels change or not, the pixels refresh either way.
Related
I am working on a game that uses HTML5 canvas 2D context drawing on a Chromecast device (which doesn't have hardware acceleration). I've noticed that drawing two objects in one frame will trigger a repaint of the entire region that contains both of them. As a "worst-case", imagine that I want to only change the color of the top-left and bottom-right pixels of a large canvas element. If I use two one-pixel fillRect calls to do this, it (WebKit/Blink, at least) will mark the entire canvas dirty, triggering a very expensive paint operation. I believe this should link to the code that performs this logic in Chromium:
https://code.google.com/p/chromium/codesearch#chromium/src/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp&l=218
Is there any way to convince the browser to actually perform two small paint operations instead of one (excessively) large one? Or would this always be slower, despite the fact that it's re-drawing significantly less? I have tried putting the elements on different canvas elements layered on top of each other, but the browser still seems to catch it and batch them together (at least as shown by the repaint regions in DevTools).
As far as I know, currently you can't do much better than that; one main drawback is that double buffering is not implemented either, which would have improved the performance. We will be seeing improvements in these areas moving forward.
I want to render concealed objects and achieve a similar effect as the one shown in the link in Stage3D.
Silhouette Effect in Torchlight 2
I already know how to do this theoretically. I have to draw the object twice:
Once with normal settings and
once with a different depth sorting mode where only pixels that are behind rendered geometry are shown. Also, to prevent weird effects later on, these pixels can't be rendered into the depth buffer.
I can set the correct depth sorting mode in Stage3D with Context3DCompareMode.GREATER.
Is it also possible to have Stage3D render pixels into the back buffer, but not the z buffer?
If I can't keep Stage3D from rendering to the depth buffer, the effect will look like this:
Glitchy Silhoutte Effect
Yes, you can turn off depth and stencil buffer. Check context3d.configureBackBuffer method.
If anyone comes across this, there are two things you should be aware of:
1) As Volgogradetzzz make sure you have a stencil/depth buffer as part of your backbuffer using Context3D.configureBackBuffer(...)
2) If you need to turn on or off depth pixel writing at different moments you can use set the depthMask argument in this function:
public function setDepthTest(depthMask:Boolean, passCompareMode:String):void
A little strange to find this feature in a function of this name, as depth write masking affects the results, not the test itself.
I would like to pan on my Html5 canvas without having to rerender, in a smooth transition (not jumpy). Is this possible? Are there code examples?
If possible, can this also be applied for zooming?
I have a performance issue when running on a lower end system (windows tablet), where panning just uses up too much cpu and ends up unusable. The scope is ~2000 graphic objects.
Unfortunately, you can't transform a canvas without redrawing it; however, if it is really just a matter of having too many draw calls, you can render the canvas once, cache the result, then on subsequent draws redraw the cached image. Note, this method won't really take well to scaling beyond maybe 150%, depending on the actual stuff you are drawing.
I made a fiddle that shows what this might look like:
http://jsfiddle.net/mobidevelop/sBvab/
There can be a little bit of jumpiness, but it's generally better than it is without caching the image.
Your mileage may vary.
In short, no. You must redraw the scene if you want panning on the canvas, unless you're doing something bad, like using CSS to limit visible canvas size and your canvas is actually larger. (Don't do this, it isn't a performance gain).
But redrawing your canvas as you pan ought to be fast if you've written it well. If it is "jumpy", then odds are something else is wrong here.
The above is also true for zooming, especially if you want your vector paths/text/etc to scale.
I hope this isn't too open ended.
I'm wondering if there is a better (more battery-friendly) way of doing this --
I have a small HTML 5 game, drawn in a canvas (let's say 500x500). I have some objects whose positions I update every 50ms or so. My current implementation re-draws the entire canvas every 50ms. I can't imagine that being very good for battery life on mobile platforms.
Is there a better way to do this? This must be a common pattern with games.
EDIT:
as requested, here are some more updates:
Right now, the objects are geometric primitives drawn via arcs and lines. I'm not opposed to making these small png/jpg/gif files instead of that'd help out. These are small graphics -- just 15x15 or so.
As the game progresses, more and more of the screen changes at a time. However, at the start, the screen changes relatively slowly (the objects randomly moved a few pixels every 50ms).
Nearly every game with continuous animation like this redraws everything every frame; clever updating algorithms are only applicable when a small part of the screen is changing and there is a nice rule to figure out what is overlapping that part.
Here is some general optimization advice:
Make sure that as much as possible of your graphics are handled by the GPU and not the CPU. (This may be impossible if the user's browser does not use the GPU for 2D canvas rendering, but you can expect upgrades may change that as HTML5 gaming gains popularity.)
This means that you should avoid elaborate clever algorithms in favor of doing as little work as possible in JS code — except that avoiding performing a lot of drawing when it is easy to determine that it will be invisible (e.g. outside the bounds of the screen) is generally worthwhile.
If your target platforms support it (generally not the case for current mobile devices), try using WebGL instead of 2D Canvas. You will have to do more detail work, but WebGL allows you to use operations which are much more likely to be provided efficiently by the GPU hardware.
If your game becomes idle — that is, nothing is actually animating at the moment — stop redrawing. Stop your update loop until the user interacts with the game or a timeout occurs.
It may be helpful for you to add to your question details of what types of graphics you are drawing (e.g. are you using sprites, or geometric primitives? Are you drawing images rotated/scaled? Does most of the screen change or just a few small objects? Are you blending many layers?) and perhaps even a screenshot or two; then we can suggest what sort of optimizations are suitable for your particular game.
Don't draw a background, make it an image and set the CSS background-image of the canvas.
Using requestAnimationFrame should help with battery life.
http://paulirish.com/2011/requestanimationframe-for-smart-animating/
Only do a redraw if something has actually changed. If you haven't already, introduce the concept of invalidations. (ie, the canvas is valid so nothing redraws until something moves. Anything moving within the window of the canvas causes the canvas to become invalid, thus needing a redraw)
If you want to be battery friendly you can use Crafty. This game engine is using modern CSS3 technology so it doesn't need to update a canvas all the time. Look at this example game here.
The way you don't want to redraw entire canvas every frame, it only can be the "Dirty-Check" or "Dirty Matrix" algorithms.
Dirty-check seems more efficient than entire redraw. but I think it depends on your render implementation.
it is not necessary to use it if you are using canvas2D to render. Nearly every game has complex sprites and animation. if you use dirty-check, when a part of sprite or background map need to update, you have to figure out what is overlapping this part. and then clearRect this small area of canvas, and then redraw every sprite or map. etc, what is overlapping.
It means your had to run canvas render api more times than normal render implementation because of the overlapping part. And Canvas2d render performance usually does't sounds efficient.
But if you use WebGL, that maybe quite difference. even though I am not family with WebGL, I do knew that maybe more efficient. Dirty-Check should be a good Choice to match your propose.
I have a large source image and I want to display a small section of it inside a circle, with leaving the part of the canvas outside of the circle transparent.
The Mozilla guide to Compositing with HTML5 covers two topics: globalCompositeOperation and clip. It looks like both of these will let me do what I want, so I'm wondering what the drawbacks are of each, and which I should use.
I could set globalCompositeOperation to source-atop (or source-in, but that seems buggy in WebKit). Then have the destination canvas be transparent with a black circle, and simply draw the source image over that. This will ensure that only the circle part will be filled in.
Or, I could draw a circular path and use clip to define a clipping region, then draw the source image over that, which should also ensure only the circle part will be filled in (in fact, Mozilla's page above even has an example of doing pretty much that with stars).
Will both of these techniques work as I say they will, or am I missing something?
If so, are there any major gotchas with either of these techniques which makes one clearly better than the other?
If not, which one has better performance in general?
I would (purely speculatively) imagine the globalCompositeOperation would have better performance, since it is applying the operation on a per-pixel level, whereas the clip operation needs to do polygon intersection. But that's just a hunch.
As of March, globalCompositeOperation did not work the same on all browsers.
Clip does... except the anti-aliasing, actually, which is sadly different per browser.
In my opinion the appropriate thing to do here is use clip. Using source-atop may work for your very specific situation, but it isn't very extensible as you described it. If you ever want to change any of it, like say have a background behind your circle, you'll run into trouble if you do it the globalComposite way.
And the tests are in: Clip is faster in every browser I tested, and massively faster in Firefox. See the results or try for yourself here