Latest CocoonJS Releases

New versions of some components of CocoonJS are published. Please, share with us your comments about these releases. Your feedback is important to find bugs and determine next improvements. Enjoy!

Core 2.1.1

iOS

  • iOS ARM64 support
  • Enabled WV+ on 64 bit devices

Services

  • Updated the following third-party services
    • iOS Google Plus SDK
    • Crittercism sdk to version 5.0.5
    • iOS Flurry SDK
    • OpenAL to openal-soft-1.16.0 and enabled OpenSL backend
    • Android-support-v4 updated to 21.0.0 and google-play-services to 6.1.71
    • Parse library to 1.6 in android and 1.4 on iOS (latest ones)
  • Removed Brightroll support.
  • Removed Yume support of iOS.

Canvas+ 2.1.1

  • Fix rare bug where Canvas+ could crash when executing code in onTouchEnd listeners
  • Fixed threading bug which was consuming battery when app was in background
  • Removed support for the GLES1 canvas+ rendering path.

Launcher 2.1.1 for Android

  • Updated to Core and Canvas+ 2.1.1
  • Fixed loading URLs with spaces

Launcher 2.1.1 for iOS

  • Updated to Core and Canvas+ 2.1.1

WebView+ for Android 2.4.0

  • Updated to LudeiChromium_1.0.37.0.2062.94
    • Several bugs fixed for Cordova 3.6 compatibility
    • Added methods needed by Android 5.0
  • Removed unused log and changed exit code.

See repo on github.

Plugins 3.0.5

See repo on github.

Techniques to Optimize Memory Use in CocoonJS Canvas+ Environment

Memory is a critical resource in HTML5/JavaScript game development, especially on mobile devices. In a desktop environment you can load tons of textures but on some low-end mobile devices you can reach the maximum RAM limit quickly. Although JavaScript encourages automatic memory management by using a garbage collection mechanism, you shouldn’t ignore effective memory management techniques. HTML5/JavaScript applications can suffer the same memory related problems as native applications, such as memory leaks, out of memory issues and they must also deal with garbage collection pauses. 

This post will give you some general advice on memory optimization for HTML5 games and some CocoonJS Canvas+ specific tips.

Effective asset loading

Preloading all the assets at the start is the easiest and quickest way to manage the memory but it only works for small games where all the assets fit into the available memory. You shouldn’t preload everything on a heavy game, only the assets that you need each time, and dispose of the unneeded assets as soon as possible. Your game memory usage depends highly on your game engine (some of them do a better job than others). Don’t expect that the browser or the garbage collector will fix all your problems and that you can stop worrying about effective memory management.

Texture packer

Javascript images and canvas objects are backed into OpenGL textures and FBOs, usually using RGBA format, 32 bits per pixel. Think about it, for example a 2048×2048 image eats 16MB of memory!  Some GPUs require POT (Power Of Two) textures for the best performance, so keep in mind that some images could use more memory than their real size and use 2^n size textures whenever you can.

We recommend that you pack all your textures using one of the Sprite Packer tools out there. That way you’ll waste less memory and improve performance (by avoiding the number of context switchings) and loading times. Some HTML5 engines are able to pack all your textures at runtime, others don’t, so please check your engine features first.

Garbage Collection

JavaScript automatically frees objects when it detects that they are not used anymore, this process is called garbage collection. During a collection the execution on your page can be suspended for a moment. If your game creates too many JavaScript objects in each frame it can lead to noticeable pause issues. This is another example that proves that it is a mistake to forget about memory management on JavaScript. You should reuse javascript objects whenever possible.

The dispose method

Image and Canvas objects are disposed when the garbage collector detects that they are not reachable in the JS code. The disposal is not immediate, it may take some seconds depending on the heuristic rules of the JavaScript virtual machine. Using a WebGL context the developer has more precise control over the WebGL texture and buffers disposal but that’s not the case when using a 2d context or when dealing with Image and Canvas objects.

CocoonJS’ Canvas+ environment exposes a method called “dispose” on canvas, image and audio objects. This method immediately frees the associated texture or internal buffer, which is very useful for games with heavy textures or for games that need a greater control over the memory.

Using this CocoonJS Canvas+ exclusive feature is very easy. Imagine we have an image object represented by the “myImage” variable.
[code lang=”javascript”]
myImage.dispose && myImage.dispose(); // The same for canvas and audio objects.
[/code]

The memory warning event

iOS and Android native applications are able to receive a memory warning notification from the system. The default implementation in Canvas+ and WebView+ environments is to perform a garbage collection and free as many internal cached data objects as possible.

From CocoonJS Canvas +2.1, the environment exposes the “memorywarning“ notification as a window listener. It is strongly recommended that you implement this method and free up as much memory as possible by disposing of cached data objects, images on canvases that can be recreated.
[code lang=”javascript”]
Cocoon.on(“memorywarning”, function() {
// dispose of cached images and canvases that can be recreated
});
[/code]

Texture reducer

Texture reducer is a CocoonJS Canvas+ exclusive feature. When your game targets all resolutions you need huge textures for iPad retina like devices and small textures for small mobile devices. A game developer has many ways to handle this:

  1. Create different asset packages, HD and normal. Good solution but bigger app size.
  2. Scale down HD resources. Excessive memory usage and performance impact on small devices.
  3. Create smaller asset packages on runtime rendering to a canvas/texture. Good solution but some JavaScript engines don’t support this.

The CocoonJS Canvas+ texture reducer feature can transparently do the job for you. It uses the third approach and it is highly customizable (for example, you can only apply it to certain resources). Check out the complete API documentation to see how to set it up.

As the texture reduction lowers the quality of the final images to be displayed, an interesting approach that we have recommended to some customers is to apply it only for certain device models, leaving higher resolution for some others (you can use the “navigator.userAgent” property to identify the device model). This, of course, it is not an easy task on Android due to the big number of device types, but on iOS is definitively an interesting option, specially for older devices such as the iPhone4 or the iPad Mini 1st generation.

Max Memory Threshold

This new CocoonJS Canvas+ exclusive feature available from version 2.1 and higher, exposes the “setMaxMemory” utility method. When the max memory threshold is set, CocoonJS checks the total amount of texture sizes (images and canvases). When the runtime memory size reaches the max memory threshold, CocoonJS disposes of the least recently used textures until the memory fits the threshold. It disposes of textures used for JS Image objects (which can be reloaded later if needed or are drawn again). It doesn’t dispose of canvas objects because they cannot be reconstructed if they are used again in a render operation. This extension is designed to be used in 2D contexts, because in WebGL contexts the developer is the one responsible for memory disposal.

Check out the API documentation.

Lazy Loading

Another CocoonJS Canvas+ exclusive feature available on version 2.1 and higher we have added the “cocoonLazyLoad” boolean property to Image objects (we have also added a duplicate called “idtkLoadDisposed” for retro compatibility with Construct2). When the property is set to true, the image is not loaded until it’s used in a render operation. Engines that load all the assets at startup can benefit from this property. But do not forget to purge the textures when they are not needed again, for example, using the dispose mechanism described earlier!

NPOT Textures

Canvas+ uses POT (Power Of Two) textures by default in 2d contexts. This is very useful for performance improvements, especially on mobiles with old GPUs. But it can waste memory on games that don’t use packed or 2^n textures. In CocoonJS Canvas+ version 2.1 you can allow NPOT textures in Canvas2D contexts (they were already supported in WebGL).

Check out the API documentation.

Conclusion

We have covered some basics of memory management in HTML5 games and exposed Canvas+ specific tips and tools.  We are always open to your suggestions. Remember that if you have some problem with memory usage in Canvas+ and you think that the problem is on our side you can send us a testcase and we’ll be glad to help you.

Additional Notes about Ludei’s Canvas+ Environment

CocoonJS’ Canvas+ is not a full browser, but a highly optimized JavaScript Virtual Machine for Canvas 2D and WebGL environments. Comparing it to a full fetched browser is not recommended as browsers include “a lot of magic tricks” (and that is why sometimes they are big and slow). For example, a browser might be able to handle a 5000 by 5000 pixels image but that does not mean that the underlying device is able to do it, just that the browser is handling some things internally for you either lowering the quality of the image (downscaling it) or subdividing it. Very few native technologies (C++ game engines) allow this kind of features as the developers should know how to handle this situations correctly (do not use 5000×5000 textures in the first place). Here at Ludei we never intended to create a new browser, but provide a highly specialized runtime environment so HTML5 developers can be closer to the native side without ever leaving JavaScript and the great HTML5 APIs.

CocoonJS Latest Releases

New versions of some components of CocoonJS are ready. Please, share with us your comments about these releases. Your feedback is important to find bugs and determine next improvements. Enjoy!

Core v2.1

All platforms

  • Implemented custom Keyboard handling so users can enter text directly into the app, without popping up a dialog.
  • Cordova support is now always available for all platforms and environments in CocoonJS.

iOS

  • Added the new CocoonJS WebView+ for iOS 8 based on the new WKWebView (Only for 32-bit devices at the moment).
  • Fixed iOS 8 orientation and layout issues.
  • Drop iOS 5 support.
  • Updated the following third-party services
    • FacebookSDK.framework (3.19).
    • Google Play Services (3.0).
  • Fixed bug where reloading with an open websocket made the app crash.
  • Fixed bug where sending a score to GameCenter could cause a crash in poor-quality networks.
  • Fixed bug where after a reload, the system WV was being loaded instead of the WebView+.

Android

  • Added the option to compile Canvas+ projects for Android Wear.
  • Added support for the new ART Java virtual machine.
  • Fixed bug where making a webview call forwarding replaced the HTML body with the returned value in some Android versions.
  • Alert dialogs buttons behavior was not consistent across Android versions. Fixed.
  • Fixed rare case where the webview was being added twice.
  • Fixed negative values as notification ids.
  • Fixed case where webview would remain black after load.

Services

  • Updated the following third-party services
    • Google Play Services (5.0.89)
    • MoPub (3.1.0)
    • AdColony (2.2.4)
    • AdMob (6.12.0)
    • Chartboost (5.0.1)
    • Greystripe (4.3)
    • InMobi (4.5.1)
    • MillenialMedia (5.4.1)
    • Parse (Android: 1.6.0, iOS: 1.4.0)
    • iAd
  • Fixed rare crash when using local notifications.
  • Fixed type cast error showing in the console when sending a push notification.

Canvas+ v2.1

  • Added 8 WebGL extensions:
    • WebGLVertexArrayObjectOES
    • WebGLCompressedTextureS3TC
    • WebGLCompressedTexturePVRTC
    • WebGLTextureFloat
    • WebGLTextureHalfFloat
    • WebGLTextureFloatLinear
    • WebGLTextureHalfFloatLinear
    • WebGLTextureFilterAnisotropic
  • Fixed ambiguity when getting the window.location.port value.
  • Added NPOT texture support for Canvas2D.
  • Added a mechanism to discard seldom-used textures when the app receives a memory warning, to keep Canvas+ working even if the app loads more images than fit in memory.
  • Added a lazy-loading mechanism so images can be loaded on first use instead of when the src attribute is set.
  • Fixed rarely-occurring deadlock when pausing audios.
  • Fixed issue with the audio system not being ended correctly if the audio thread was locked.

WebView+ for Android v2.2.0

  • Updated to Chromium 36.0.1985.143.
  • Fixed unnecessary creation of shell additional instance.
  • Fixed cache mode.

See on github.

Plugins v3.0.4

See on github.

Launcher v2.1

  • New UI for both Android and iOS versions.
  • Added filename/URL search mechanism.
  • Added Favorites panel.
  • The Android Launcher now allows navigation through the whole device file system and loads not only .zip files but entire folders too.
  • Improvements to the debug service usability. Also, new error/warning reporting icons.
  • Restructured settings dialog.
  • More stable architecture. The launcher will keep working even if CocoonJS has a runtime problem.
  • Fixed several problems on Android 2.3.
  • Android launcher now allows canceling the app load process.

CLI v1.0.0-0.5.0

  • CocoonJS serve now has livereload enabled by default.

Known issues:

  • Livereload feature not work in system webviews with no websockets support.

See on github.

CocoonJS and Construct2’s “Great HTML5 Gaming Performance Test: 2014 edition”

Scirra, the company behind Construct2, a great HTML5 game authoring framework, released “The Great HTML5 Gaming Performance Test: 2014 edition” weeks ago. In this test, they used a Construct2 based game demo and executed it in numerous environments. Surprisingly (and we want to think that by mistake), they did not include CocoonJS’ Canvas+ in the comparison, but to help Scirra provide as much information as possible, and to be fair to the Construct2 developer community that has been actively using CocoonJS, we have used the same demo in almost all of the same devices (and some interesting additional one like an iPad1 with iOS 5!). These are the results:

Device Canvas+ canvas2d Canvas+ webgl Chrome34 webgl Firefox webgl Safari 7 canvas2d Ejecta webgl
Nexus 4 58 60  59 58 N/A N/A
Nexus 7 52 60 59 51 N/A N/A
SGS3 58 59 58 58 N/A N/A
iPad 2 53 55 N/A N/A 46 55
iPad 1 20 35 N/A N/A N/A N/A
iPhone 4S 32 51  N/A N/A 40 51
iPhone 5 60 60 N/A N/A 60 N/A
Kindle 44 58  N/A N/A N/A N/A

As you can see Canvas+ is really efficient for both 2d and webgl contexts in all of the devices that were tested (even on an iPad1!!!).

It is also important to remember that Chrome, Firefox and Safari are not technologies to create native apps for iOS or Android. If someone wants to run a game on a mobile browser, this list gives a good glimps of what to expect, but not all of the final users/players have these browsers and their latest versions installed (specially on Android) and most of these technologies won’t be an option to create native apps for existing mobile markets. Moreover, Safari has Nitro JIT so the comparison is also biased. Bottom line is that CocoonJS is still the only technology that allows webgl native app deployment for both iOS and Android using the same execution environment, with no fragmentation and with an easy one click final deployment.

The good news is that the new CocoonJS release 2.0.1 is soon to be out and with it anyone will be able test these results on his/her own easily by installing the CocoonJS Launcher App for iOS and/or Android. This new version of CocoonJS will execute any Construct2 project exported for the web out of the box, so this perf test will also work just by pointing to the following URL (either typing it or using the provided QRCode for your convenience):

http://www.scirra.com/demos/c2/sbperftest/

ScirraPerfTestURL

Happy perf-testing! 😉

Mobile GPU setbacks

We received a question in the forum that prompted us to write a detailed explanation of what things you should have in mind when developing games for mobile hardware.

Here’s the question by xero in our forum:

In earlier posts you mentioned to keep the number of canvases tight. However, it is a common technique in browsers to use multiple layered canvases to gain performance boost, since only some part of the content gets redrawn. What are you’re suggestions about that? Are CocoonJS canvases more expensive than browser ones? Will I benefit from having to redraw less stuff or will the overhead (memory, CPU?) of managing additional canvases by CocoonJS overweight all possible performance gains?

The first thing you must understand to develop for mobile platforms is those devices have very low performance compared to what you can expect in a modern PC. On the other hand, while most mobile browsers draw everything using the CPU, CocoonJS uses the GPU to draw shapes and images really fast, so the picture is more complex than it would initially appear. Mobile devices are slower, but we’re squeezing every last bit of performance out of them.

In this case, the performance optimization mentioned by xero is generally useful in run-off-the-mill browsers because blending several images in a canvas is pretty slow there. In CocoonJS however, image blending is done by the GPU, so it’s a lot cheaper.

The optimization does usually work, however, if you intend to draw lots of static images into a canvas, and then reuse that canvas during lots of frames. In effect, you’ll be creating a “cache” with that image to reuse it later. This can be very useful if you want to display, say, 500 objects which won’t change for a long time.

The thing is, drawing from that “cached” canvas to the final screen isn’t free either, so you must make sure the original draws are actually slower than drawing the “cache” canvas will be. For example, using a canvas to cache a simple static background probably won’t get you any performance improvement compared to just drawing the background itself.

More to the point, drawing full-screen canvases can easily exhaust what in GPU jargon is called “fill-rate”. Fill-rate, usually expressed in MPixels/s, is the speed at which a GPU can paint pixels. A mid-range GPU nowadays has about 500 MPixels/s of fill-rate. If you intend to run at 60fps, that means you get ~8.3 MPixels/frame. If your screen has a resolution of 1280 by 720 (pretty standard nowadays), each fullscreen canvas you draw takes 0.92 Mpixels of fill-rate. That means if you have 5 canvases you’re already exhausting more than half the fill-rate your GPU is capable of delivering.

Some devices have such a small fill-rate/screen-size ratio that you can only get about 2-3 fullscreen draws before you hit the GPU’s max drawing capacity. This is unfortunately a hardware limitation you’ll have to think about in your games if you want to deploy to low-power mobile devices.

So, to sum everything up, if you want to optimize your game you’re gonna have to know a bit about the hardware, test your assumptions and measure results. CocoonJS provides you with a powerful time profiling mechanism you can use to track how much CPU each part of your game is using.

In the case of the optimization mentioned by xero, how well it works will depend on how many canvases are used, how much work is saved by drawing to a canvas, how powerful is the hardware, and if fill-rate is actually the bottleneck for you! The only way to be sure is trying the technique in your game and measuring performance. Always measure!