Live data from Hacker News

CutJS – Fast 2D HTML5 rendering engine for game development

cutjs.org

41–50 of 54 posts

Re: CutJS – Fast 2D HTML5 rendering engine for game development

#41
post #30
post #29

Earlier quoted context omitted.

That's true (thanks), but anyways, it seems to me that a simple animation should take only a fraction of a modern CPU's (or GPU) power. Is the engine calculating more often than what's needed for 60fps or whatever refresh rate our eyes need to be satisfied?

The issue is not with this engine, no other HTML5 game/engine can do better in your browser. CPU is not optimized to do what takes only a fraction of GPU.

This is false. Properly optimized rasterizers (like Adobe Flash's, for example) can deliver vastly superior performance for simple animated scenes like that, and have been doing so for over a decade.

Cut's renderer would be much faster if it were designed in a GPU and CPU-friendly manner instead of the naive graph traversal it does right now (I'll post about this in detail outside this thread)

Re: CutJS – Fast 2D HTML5 rendering engine for game development

#42
'Fast' is a poor descriptive choice for a library that was clearly written without attention paid to CPU performance characteristics, GPU performance characteristics, or the nature of modern Canvas implementations.

EDIT: A quick glance at the sample game 'O!' in the chrome profiler shows that it is triggering a garbage collection roughly every second. Pretty bad for a game with such low scene complexity and rendering complexity, and those pauses may be long on a mobile device.

Based on a casual review of the source code (which I'll note is quite readable - good job!), here are some obvious problems that probably need to be addressed, both in terms of actual performance and code quality.

Don't render the scene in graph traversal order; doing so ensures that the number of graphics state changes (shader, transform, texture, etc) is as high as possible. Most game engines render using a more sophisticated algorithm where your drawing operations are ordered (as possible - obviously layering has to be preserved) by graphics state in order to minimize overhead.

For some documentation on this approach, see articles like http://realtimecollisiondetection.net/blog/?p=86 I've been using this approach in my games for years and it produces a huge measurable performance improvement on virtually all modern architectures (even canvas, though it's less significant there)

The tickBefore/tick/tickAfter architecture is particularly suspicious, as is its use of poorly-scaling algorithms/primitives like Array.splice. Usually this sort of thing is more clearly and efficiently handled by having an ordered set of operations (typically represented by a linked list, a heapqueue, or an array of priority-value tuples that you sort once per frame).

I see frequent references to Cut.Pin.prototype.absoluteMatrix and .matrix. I will note that these don't appear to create garbage - which is great! - but they silently mutate a shared Matrix instance which means that it is very easy for a library consumer to end up with their state corrupted - if you store the result of absoluteMatrix, then modify the state of a Pin, that matrix will suddenly become corrupted. Sadly the code appears to make no effort to warn users about this.

You're not using any type hinting (i.e. | 0, +) which means that JS JITs will have to work harder to figure out whether given values are integers, floats, or something else. This results in JIT recompilations, less efficient in-memory representation, and in some cases results in floating point/integer values being boxed instead of stored efficiently on the stack/heap.

You mix different types in some of your slots (for one example, Anim._time is both 'object' and 'integer') which prevents optimization in most modern JS runtimes. This can have a catastrophic impact on performance in some scenarios, so you should avoid it if possible. A good way to replace a null/integer pattern is to have an integer that's always an integer, along with a hasValue boolean - this is how nullable primitives work in C#, for example.

Some of your non-initialization code uses temporary object literals - this.pin({ ... }), this._next = { ... }, etc - which is a recipe for bad performance and GC pauses if you're doing it during updates or rendering operations. It's not immediately obvious to me whether you could optimize this out easily, but you should make sure these temporary literals are not being created in large quantities.

You have many functions containing throw statements and a few containing catch statements. In most JS runtimes these both prevent optimization of the function body. You can solve this by hoisting the throw into a utility function (In JSIL I have a 'JSIL.RuntimeError' function that just does 'throw') - this allows the function to be optimized even if the throw-function is not optimized or inlined. When you have a single throw statement in a complex high-traffic function this can matter a lot.

You appear to not be validating or properly type-casting the inputs you pass to canvas.drawImage, which will impair performance and result in runtime errors. I can tell you've already run into problems with this since your drawImage call has a try/catch wrapped around it (YUCK) - the right solution here is to read the spec (that more or less clearly specifies the expected types and constraints for drawImage), and then make sure your code satisfies those constraints. It will be much faster and more reliable if you do so.

It appears that you may have many scenarios where you call drawImage with a source rectangle. This tends to be poorly-performing in canvas implementations (due to deficiencies in the spec), so if you want that to be fast for source rectangles that don't change, you should cache the source rectangle in a unique canvas so you can draw without source parameters. Typically source-rect blits can't be batched at all (i.e. one hardware draw call per blit) so this makes a big difference.

I'm sure there's more, this is just the result of a quick skim of the code. Feel free to contact me if you have more questions. You can identify many of these performance problems by reading specs and using things like Chrome's profiler and Firefox's SPS and JIT Inspector profiling tools.

I'm a huge fan of people sharing their libraries and engines with the world, but if you're going to spout superlatives you need to be prepared to back them up. Otherwise, people who don't know better will be misled by your dishonesty and end up having their efforts at using your tech go to waste when they have to port to something better.

Re: CutJS – Fast 2D HTML5 rendering engine for game development

#43
post #30

Earlier quoted context omitted.

The issue is not with this engine, no other HTML5 game/engine can do better in your browser. CPU is not optimized to do what takes only a fraction of GPU.

This is false. Properly optimized rasterizers (like Adobe Flash's, for example) can deliver vastly superior performance for simple animated scenes like that, and have been doing so for over a decade. Cut's renderer would be much faster if it were designed in a GPU and CPU-friendly manner instead of the naive graph traversal it does right now (I'll post about this in detail outside this thread)

CutJS is already GPU and CPU-friendly, the problem is that his browser is not GPU-enabled and uses CPU for GPU tasks. It is not about CutJS, Canvas or Flash. When you use CutJS with a GPU enabled browser only a very small portion of CPU is used which shows that is CPU-friendly.

Re: CutJS – Fast 2D HTML5 rendering engine for game development

#44
post #19

Why not WebGL-based?

Most likely because they also want to target mobile and system browsers don't allow for it.

Note that most canvas implementations on mobile are not hardware accelerated, so you're not getting all that much for your trouble. ;/ WebGL on mobile performs much better than Canvas on mobile for configurations that support both, just like on desktops.

Re: CutJS – Fast 2D HTML5 rendering engine for game development

#45

'Fast' is a poor descriptive choice for a library that was clearly written without attention paid to CPU performance characteristics, GPU performance characteristics, or the nature of modern Canvas implementations. EDIT: A quick glance at the sample game 'O!' in the chrome profiler shows that it is triggering a garbage collection roughly every second. Pretty bad for a game with such low scene complexity and rendering…

Thanks a lot for code review, I'm reading, but you have made many unjustified claims and based on results I would say your conclusion is not valid.

You have also made personal attack ("your dishonesty"), probably because of your own competing library (jsil.org).

Re: CutJS – Fast 2D HTML5 rendering engine for game development

#46
post #43

Earlier quoted context omitted.

This is false. Properly optimized rasterizers (like Adobe Flash's, for example) can deliver vastly superior performance for simple animated scenes like that, and have been doing so for over a decade. Cut's renderer would be much faster if it were designed in a GPU and CPU-friendly manner instead of the naive graph traversal it does right now (I'll post about this in detail outside this thread)

CutJS is already GPU and CPU-friendly, the problem is that his browser is not GPU-enabled and uses CPU for GPU tasks. It is not about CutJS, Canvas or Flash. When you use CutJS with a GPU enabled browser only a very small portion of CPU is used which shows that is CPU-friendly.

As I mention in my top level post, this is false. The most obvious example is that you do all your rendering and updates in graph traversal order, even though this is one of the worst traversal orders to use because it minimizes the effectiveness of the processor's caches and produces the maximum number of GPU state changes. GPU state changes increase both CPU and GPU overhead, and in a software rasterizer they also prohibit efficient caching (for example, in Cairo).

You can say it's efficient as much as you like, but you clearly haven't done much research if you think it's fast just because the CPU usage is low in your trivial demos - demos that cause GC pauses on a regular basis, I should note. If you want to claim that it's fast and GPU/CPU friendly, you should be profiling it in a GPU profiler like PIX to ensure that it produces few GPU draw calls and state changes, and profiling it in a CPU profiler to ensure that virtually all the time spent is spent inside of the Canvas implementation - which, sadly, is not true for your example game 'O!' in the Chrome Profiler.

Re: CutJS – Fast 2D HTML5 rendering engine for game development

#47
post #45

'Fast' is a poor descriptive choice for a library that was clearly written without attention paid to CPU performance characteristics, GPU performance characteristics, or the nature of modern Canvas implementations. EDIT: A quick glance at the sample game 'O!' in the chrome profiler shows that it is triggering a garbage collection roughly every second. Pretty bad for a game with such low scene complexity and rendering…

Thanks a lot for code review, I'm reading, but you have made many unjustified claims and based on results I would say your conclusion is not valid. You have also made personal attack ("your dishonesty"), probably because of your own competing library (jsil.org).

Feel free to ignore the unsolicited advice on how to improve your software from someone who's been working on games and game engines for 10 years.

I ran your sample under a profiler and saw obvious problems with CPU and memory performance, and there are obvious problems with GPU efficiency based on your rendering model. This is not subjective; profiling is objective.

P.S. JSIL doesn't compete with your library, it's a cross-compiler. Are you angry because I gave a specific example of how I used one of the optimizations I suggested, or just because I'm pointing out that your website is dishonest?

EDIT: I shouldn't have to point this out either, but saying 'this text you wrote is dishonest' is not a personal attack. It's an objective criticism of your writing. Saying 'it's dishonest to call this library fast because x' is also not a personal attack, it is an objective criticism of your code.

If I called you a liar or a dishonest person, that would be a personal attack. I have not done that. I could certainly make that claim based on your argumentative style in this thread, but I shall not.

Re: CutJS – Fast 2D HTML5 rendering engine for game development

#48
post #45

Earlier quoted context omitted.

Thanks a lot for code review, I'm reading, but you have made many unjustified claims and based on results I would say your conclusion is not valid. You have also made personal attack ("your dishonesty"), probably because of your own competing library (jsil.org).

Feel free to ignore the unsolicited advice on how to improve your software from someone who's been working on games and game engines for 10 years. I ran your sample under a profiler and saw obvious problems with CPU and memory performance, and there are obvious problems with GPU efficiency based on your rendering model. This is not subjective; profiling is objective. P.S. JSIL doesn't compete with your library, it's…

Actually I love your feedbacks, but putting your quick conclusion on top and putting personal attack on bottom is strange.

Your exact phrase is "your dishonestly", you could have described it as "inaccurate description" instead.

Re: CutJS – Fast 2D HTML5 rendering engine for game development

#49
post #48

Earlier quoted context omitted.

Feel free to ignore the unsolicited advice on how to improve your software from someone who's been working on games and game engines for 10 years. I ran your sample under a profiler and saw obvious problems with CPU and memory performance, and there are obvious problems with GPU efficiency based on your rendering model. This is not subjective; profiling is objective. P.S. JSIL doesn't compete with your library, it's…

Actually I love your feedbacks, but putting your quick conclusion on top and putting personal attack on bottom is strange. Your exact phrase is "your dishonestly", you could have described it as "inaccurate description" instead.

'dishonesty' describes a dishonest or deceitful act, and I was referring to the act of writing 'fast' on your website. I don't believe this was an inappropriate use of the term.

I apologize if for whatever reason you believed that to be a personal attack - I did not intend to hurt you and if I did, I am sorry. But I will not retract what I wrote, because I believe it is accurate.

Re: CutJS – Fast 2D HTML5 rendering engine for game development

#50
post #48

Earlier quoted context omitted.

Actually I love your feedbacks, but putting your quick conclusion on top and putting personal attack on bottom is strange. Your exact phrase is "your dishonestly", you could have described it as "inaccurate description" instead.

'dishonesty' describes a dishonest or deceitful act, and I was referring to the act of writing 'fast' on your website. I don't believe this was an inappropriate use of the term. I apologize if for whatever reason you believed that to be a personal attack - I did not intend to hurt you and if I did, I am sorry. But I will not retract what I wrote, because I believe it is accurate.

No worries. Peace! I'm almost done answering your first comment.
Post reply on HN