<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1197137313991855034</id><updated>2012-01-30T11:06:06.602-06:00</updated><category term='virtual memory'/><category term='opengles2.0'/><category term='FileIO'/><category term='3D'/><category term='Chrome'/><category term='html5'/><category term='debugging'/><category term='blending'/><category term='books'/><category term='performance'/><category term='games'/><category term='memory'/><category term='Native Client'/><category term='alpha blending'/><category term='Chrome Web Store'/><category term='industry'/><category term='google'/><category term='threading'/><title type='text'>The Workbench</title><subtitle type='html'>The ramblings of a graphics programmer, as he keeps himself distracted.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>29</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1197137313991855034.post-1166649236828784537</id><published>2012-01-30T11:06:00.000-06:00</published><updated>2012-01-30T11:06:06.620-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='FileIO'/><category scheme='http://www.blogger.com/atom/ns#' term='Native Client'/><title type='text'>NaCl &amp; best practices for fileIO</title><content type='html'>FileIO continues to be a pain point for most Native Client developers. I've talked about this before, but I think it's time for a refreshing post; Note that this is a huge brain dump, so sit back and get ready to read.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;For hosted applications&lt;/b&gt;&lt;br /&gt;Native Client is a web technology that runs INSIDE of webpage. More specifically, Native Client data is HOSTED on a server, and served to the client when they browse to the website. NaCl modules are defined in a web-page using the EMBED tag that points to the .NEXE files for your architecture. As such, the web browser treats your .nexe files as though they were any other web content (images, videos etc) and saves a copy of your Nexe to the cache when processing the elements of the webpage.&lt;br /&gt;&lt;br /&gt;Note that the EMBED tag, and the corresponding Manifest file ONLY lists the NEXE data, any binary data that you may have uploaded into the same directory as your NEXE on the server is not brought down to the client when the page loads.&lt;br /&gt;&lt;br /&gt;As such, in order to access your files, you must first retrieve them from the server and pull them down manually. This can be done inside of NaCl by issuing an geturl (XHttpRequest) to the specific URI of the content; the asynchronous call will return the result to you as a binary stream of the content once it has been fetched properly. Once you have the data, you can operate on it as you normally would, no problems. On your behalf, Chrome will cache any geturl request results, so that future requests can be re-used. The downside is that the cache can be evicted any time, without your app's consent.&lt;br /&gt;&lt;br /&gt;Pulling down the content manually can be a cumbersome, and bandwidth hogging process if it has to occur every time the user loads your game. To help alleviate this, NaCl provides the Filesystem API, allowing developers to read and write files and folders to a sandboxed area of the user's native filesystem. The files are obfuscated and not easily navigated to by typical users. The API offers a storage location that allows random read &amp; write access to binary data your application stores. The data is persistent between launches of Chrome, and most importantly, the data will not be evicted unless your application deletes it, or the user manually deletes it. When using PERSISTENTT storage, there is no storage cap for the amount of data you can store. &lt;br /&gt;Once assets are fetched from your web server, the Filesystem API can be used to aggressively cache that data locally to disk. With future requests for the same file, first check the local filesystem before issuing the request for the file from the server.&lt;br /&gt;&lt;br /&gt;The intended flow of this, is that when you would like to load a file, first check the FileSystem APIs in NaCl to see if the file exists locally. If it does, load it, and be happy that you've accomplished something. If the file doesn't exist locally, then you issue a geturl request to your content server to grab the file; when the results are ready, immediately open up a FileSystem API call to write that file to disk.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;For packaged applications&lt;/b&gt;&lt;br /&gt;One of the downsides of hosted applications, is that the developer has to pay for hosting cost, and for highly popular content, this can be a large financial burden.&lt;br /&gt;At the time of this writing, Native Client applications can only be distributed from the &lt;a href="https://chrome.google.com/webstore"&gt;Chrome Web Store&lt;/a&gt;. One of the more alluring features of using CWS is that you can create a &lt;i&gt;packaged&lt;/i&gt; application that CWS will host for you and distribute to users free of charge. You can read more about how to properly distribute your NaCl application from the CWS using &lt;a href="https://developers.google.com/native-client/devguide/distributing"&gt;this documentation from gonacl&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;When a user clicks the 'install' button from CWS your Nexe and binary content that has been packaged into a .CRX file will be downloaded to the users' machine in one large blob, and unpacked there on your behalf. These files are downloaded to a directory that’s seperate from the cache and sand boxed filestore; It’s a SEPARATE directory that contains only CWS downloaded and installed apps. &lt;br /&gt;&lt;br /&gt;As such, this means that your NaCl app will still have to use the geturl call to fetch assets. The trick here, however, is that you need to use a &lt;i&gt;relative&lt;/i&gt; path to geturl to properly fetch the files. &lt;br /&gt;&lt;br /&gt;Since these files are already local to the users' machine, you will &lt;b&gt;NOT&lt;/b&gt; need to cache them into the obfuscated filestore unless you need some sort of advanced read/write/seek access to the file that geturl does not offer.&lt;br /&gt;&lt;br /&gt;There's a whole separate discussion to be had about how to modify your existing content API to match the Pepper API. So I'll leave that for another time ;)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1197137313991855034-1166649236828784537?l=mainroach.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/1166649236828784537/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1197137313991855034&amp;postID=1166649236828784537' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/1166649236828784537'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/1166649236828784537'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/2012/01/nacl-best-practices-for-fileio.html' title='NaCl &amp; best practices for fileIO'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1197137313991855034.post-7046809241007741567</id><published>2012-01-24T13:00:00.000-06:00</published><updated>2012-01-24T13:00:27.477-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='google'/><title type='text'>Implementing your own two-step authentication</title><content type='html'>I'm a huge fan of &lt;a href="http://support.google.com/accounts/bin/static.py?hl=en&amp;page=guide.cs&amp;guide=1056283"&gt;two-step authentication&lt;/a&gt; for my Google accounts. It is cumbersome at times (like when I'm trying to pull up a receipt e-mail while standing in line for something) but the security blanket it provides is well worth it.&lt;br /&gt;&lt;br /&gt;Many times I had thought to myself "I wish I could use this for other websites too."&lt;br /&gt;&lt;br /&gt;Imagine my joy when I discovered that implementing two-step authentication on a website isn't that difficult to do; in-fact, &lt;a href="http://code.google.com/p/google-authenticator/"&gt;it's open source&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Using 2 step authentication is very straight forward. The user enters their username / password like normal, and when that authentication is validated, they are presented with a text field, and asked to enter a number.&lt;br /&gt;From there, the user loads &lt;a href="http://support.google.com/accounts/bin/answer.py?hl=en&amp;answer=1066447"&gt;Google Authenticator&lt;/a&gt; on their smartphone, and receives a custom random number to input into the provided text field.&lt;br /&gt;&lt;br /&gt;Once that number is confirmed correct, the user can log in as normal.&lt;br /&gt;&lt;br /&gt;I was going to write my own tutorial on how to get started using all this, but realized that there was a great running &lt;a href="http://blog.tinisles.com/2011/10/google-authenticator-one-time-password-algorithm-in-javascript/"&gt;example&lt;/a&gt; that implements this TOTP process in javascript. So, I'll direct you there instead ;)&lt;br /&gt;&lt;br /&gt;Important bits from the above example, to help you along:&lt;br /&gt;You can create custom QR codes pretty easily; The following QR image was created with this:&lt;br /&gt;&lt;i&gt;https://chart.googleapis.com/chart?chs=150x150&amp;cht=qr&amp;chl=hellomynameismainroach&lt;/i&gt;&lt;br /&gt;&lt;img src="https://chart.googleapis.com/chart?chs=150x150&amp;cht=qr&amp;chl=hellomynameismainroach"/&gt;&lt;br /&gt;&lt;br /&gt;And google provides a great doucment on how to embed the TOTP keys in the QR code &lt;a href="http://code.google.com/p/google-authenticator/wiki/KeyUriFormat"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;So go forth! Add this ability to your service! There's no reason to hold back!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1197137313991855034-7046809241007741567?l=mainroach.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/7046809241007741567/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1197137313991855034&amp;postID=7046809241007741567' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/7046809241007741567'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/7046809241007741567'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/2012/01/implementing-your-own-two-step.html' title='Implementing your own two-step authentication'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1197137313991855034.post-9019101075420507931</id><published>2012-01-18T10:01:00.000-06:00</published><updated>2012-01-18T10:01:48.585-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='FileIO'/><category scheme='http://www.blogger.com/atom/ns#' term='Native Client'/><category scheme='http://www.blogger.com/atom/ns#' term='threading'/><title type='text'>NaCl And Pepper Thread communication.</title><content type='html'>Chrome provides a plugin API called Pepper (PPAPI) that NaCl uses to communicate with the underlying platform. As documented before, all pepper calls must come from the main thread (referred to after this as the ‘pepper’ thread). This includes FileIO, Audio, Rendering, and Input. It's also worth pointing out that these calls are all &lt;i&gt;non-blocking&lt;/i&gt; which means that you call them, and some time in the future, the results are received. More specifically, Pepper APIs and message pumps run on the Pepper thread, along with your webpage script, and V8 / Javascript processing. Which means that blocking the main thread will result in your page processing hanging, causing your tab to stall.&lt;br /&gt;&lt;br /&gt;Audio and Rendering are fire-and-forget style systems, and as such don’t require much modification to your game/app; You can call these on the main thread, and continue on withing having to worry about blocking. Input is poll-based, and can be quiried at any time. The real problem is FileIO, where most developers have expectations that the fileIO is blocking.&lt;br /&gt;&lt;br /&gt;All of the FileSystemAPIs are non-blocking. As you make the call, your pepper thread will not halt and wait for the function to finish. Your results will be available the next frame cycle. POSIX style blocking functions are on the road-map, but their ETA is yet to occur.&lt;br /&gt;&lt;br /&gt;One of the more common solutions to this, is to Spawn a new thread to act as your main thread. This thread will own your update/render loop. You can overload fopen / fread to kick off commands to the pepper thread, and spin-loop to wait for their result. &lt;br /&gt;One of the key results in this is that you need some sort of nifty code that allows you to kick off calls to the main thread from your workers, and block until the results are finished.&lt;br /&gt;&lt;br /&gt;Mad Props to NaCl PM &lt;a href="https://plus.sandbox.google.com/u/1/111857822126789860534/about"&gt;Christian Stefansen&lt;/a&gt; who threw this snippet together.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Christian wrote a generic "do stuff on the main thread and block" class:&lt;br /&gt;&lt;br /&gt;&lt;table width="100%" bgcolor="#222222"&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;&lt;pre&gt;class GenericJob : public MainThreadJob {&lt;br /&gt;     void (*function_)();&lt;br /&gt;     public:&lt;br /&gt;          ~GenericJob() {}&lt;br /&gt;          GenericJob(void (*function)()) : function_(function) {}&lt;br /&gt;          void Run(MainThreadRunner::JobEntry* e) {&lt;br /&gt;               (*function_)();&lt;br /&gt;               MainThreadRunner::ResultCompletion(e, 0);&lt;br /&gt;          }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;To run "func" on the main thread and block, you'd do something like&lt;br /&gt;&lt;br /&gt;&lt;table width="100%" bgcolor="#222222"&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;&lt;br /&gt;GenericJob* job = new GenericJob(func);&lt;br /&gt;runner_-&gt;RunJob(job);&lt;br /&gt;&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;where runner_ is a pointer to a pre-initialized MainThreadRunner object.&lt;br /&gt;&lt;br /&gt;With this, you should be able to overload fread/fwrite when called from worker threads to kick off read calls to the pepper thread to be serviced.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1197137313991855034-9019101075420507931?l=mainroach.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/9019101075420507931/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1197137313991855034&amp;postID=9019101075420507931' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/9019101075420507931'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/9019101075420507931'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/2012/01/nacl-and-pepper-thread-communication.html' title='NaCl And Pepper Thread communication.'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1197137313991855034.post-4483283954032962775</id><published>2011-12-12T12:42:00.000-06:00</published><updated>2011-12-12T12:42:05.135-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Native Client'/><title type='text'>NaCl &amp; CORS pt. 2</title><content type='html'>Since my &lt;a href="http://mainroach.blogspot.com/2011/12/nacl-fetching-content-across-domains.htm"&gt;last post&lt;/a&gt;, I've been getting a slew of "your CORS solution doesn't work for me" e-mails. After some digging, most of these were not related to Native Client, and the fixes did work. &lt;br /&gt;&lt;br /&gt;So, before you flame-on, follow these steps to find the problem :&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Can you access the request when running a javascript function in a page hosted on the domain? (ie www.google.com/corstest.html)&lt;/li&gt;&lt;ol&gt;&lt;li&gt;If YES, Can you access the request running a javascript function on a page NOT on the domain? (ie www.colt.com/corstest.html)&lt;/li&gt;&lt;ol&gt;&lt;li&gt;YES? then please test &lt;a href="http://mainroach.blogspot.com/2011/12/nacl-fetching-content-across-domains.html"&gt;these steps&lt;/a&gt; listed to configure NACL for CORS requests.&lt;/li&gt;&lt;li&gt;if NO,  Have you configured your server to accept CORS requests?&lt;/li&gt; &lt;/ol&gt;&lt;/ol&gt;&lt;li&gt;If NO, please check your syntax and web service accordingly.&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1197137313991855034-4483283954032962775?l=mainroach.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/4483283954032962775/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1197137313991855034&amp;postID=4483283954032962775' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/4483283954032962775'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/4483283954032962775'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/2011/12/nacl-cors-pt-2.html' title='NaCl &amp; CORS pt. 2'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1197137313991855034.post-7989983382392890816</id><published>2011-12-02T09:44:00.001-06:00</published><updated>2011-12-05T08:55:10.116-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Native Client'/><title type='text'>NaCl &amp; fetching content across domains</title><content type='html'>I've been working with a handful of developers lately, that have all been hitting a brick wall with trying to fetch resources from their web-server using GetURL, and having the requests fail.&lt;br /&gt;The problem is that the internet generally doesn't allow you to fetch data across domains for Get/Set requests. Which is great for security, but harsh for NaCl developers who need to fetch binary assets from a cloud service, like Google App Engine.&lt;br /&gt;&lt;br /&gt;Thankfully &lt;a href="https://plus.google.com/107379767907444837458/posts"&gt;Bill Budge&lt;/a&gt; (yes, that &lt;a href="http://en.wikipedia.org/wiki/Bill_Budge"&gt;Bill Budge&lt;/a&gt;), who works on Native Client here @ Google, was on hand to point out how to fix this problem, using CORS.&lt;br /&gt;&lt;br /&gt;HTML5Rocks has a &lt;a href="http://www.html5rocks.com/en/tutorials/cors/"&gt;great article&lt;/a&gt; that discusses this issue, and how to fix it in javascript. This doesn't help you when doing the calls from C++ though, so let's talk about how to attack that.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;u&gt;The setup&lt;/b&gt;&lt;/u&gt;&lt;br /&gt;The Native Client SDK contains a &lt;a href="http://code.google.com/p/nativeclient-sdk/source/browse#svn%2Ftrunk%2Fsrc%2Fexamples%2Fgeturl"&gt;great example&lt;/a&gt; on how to to GET/POST requets to load a page. I've &lt;a href="http://mainroach.blogspot.com/2011/09/nacl-fetching-files.html"&gt;mentioned before&lt;/a&gt; that this is a required process for fetching files off of a server. &lt;br /&gt;&lt;br /&gt;You can compile that app from the SDK, and see how it's used to fetch file data. If you just load the webpage, press the "Get URL" button, and see that it fetches the contents of the desired file. Note, that the HTTPD.py file that's distributed with the SDK creates a webserver to host the NaCl content from. As such, the results of the GetUrlHandler function is actually communicating with a 'webserver' (but it's local).&lt;br /&gt;&lt;br /&gt;Once you try to access a file outside that webserver though, you'll get a denial. For instance, in geturl/geturl.html, change line 60 to read:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;geturlModule.postMessage('getUrl:http://www.sameas.org');&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;When you load the page, you can press the "Get URL" button, and receive this response:&lt;br /&gt;&lt;i&gt;&lt;br /&gt;FULLY QUALIFIED URL: http://www.sameas.org&lt;br /&gt;RESULT: pp::URLLoader::Open() failed&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;This is beacuse you are attempting to fetch data from outside of your apps' origin, and thus are getting denied.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;u&gt;How to fix it&lt;/b&gt;&lt;/u&gt;&lt;br /&gt;In geturl/geturl_handler.cc, add the following code @ line 34:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;url_request_.SetProperty(PP_URLREQUESTPROPERTY_ALLOWCROSSORIGINREQUESTS, pp::Var(true));&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Compile the code, and run the web-page again. When you load the page, and click "Get URL" button you'll receive the stream of HTML data from the sameas.org homepage.&lt;br /&gt;&lt;br /&gt;With this flag, you'll be able to fetch your binary assets across domains properly! &lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;u&gt;One final note&lt;/b&gt;&lt;/u&gt;&lt;br /&gt;For CORS to work on your server, you'll need to make a modification to the server accesses to &lt;i&gt;allow&lt;/i&gt; CORS requests. This differs by server type, so please refer to your server documentation on how to properly enable this.&lt;br /&gt;&lt;br /&gt;~Main&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1197137313991855034-7989983382392890816?l=mainroach.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/7989983382392890816/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1197137313991855034&amp;postID=7989983382392890816' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/7989983382392890816'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/7989983382392890816'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/2011/12/nacl-fetching-content-across-domains.html' title='NaCl &amp; fetching content across domains'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1197137313991855034.post-1921386705557397768</id><published>2011-11-08T08:22:00.001-06:00</published><updated>2011-11-08T08:25:07.829-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Native Client'/><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><category scheme='http://www.blogger.com/atom/ns#' term='Chrome Web Store'/><title type='text'>NaCl &amp; Detecting user setup problems</title><content type='html'>I would apologize about the lack of updates, but it's due to a ton of activity in Native Client land, which I'm sure is just as important as my blog ramblings ;)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;With the recient &lt;a href="http://www.egmnow.com/articles/news/star-legends-becomes-first-native-client-game-for-chrome/"&gt;press&lt;/a&gt; about Native Client, I've started getting flooded with e-mails about developing on NaCl. One of the interesting set that I saw was about common issues with troubleshooting the first line of NaCl restrictions; This includes:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Does the user have the proper version of chrome?&lt;/li&gt;&lt;li&gt;Has the user installed the NaCl app from the Chrome Web Store?&lt;/li&gt;&lt;li&gt;Does the user have the required hardware to run the NaCl module?&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Oddly enough, most of the solutions to these problems have nothing to do with NaCl dev itself, and are more related to Web development. In any case, let me try to address them here.&lt;br /&gt;&lt;br /&gt;Firstly, I'm assuming you've read our &lt;a href="http://www.gonacl.com"&gt;gonacl.com&lt;/a&gt; page on how to &lt;a href="http://www.gonacl.com/dev/ht_packagedhosted.html"&gt;distribute to the Chrome Web Store (CWS)&lt;/a&gt;, and are aware that there's a difference between &lt;i&gt;Hosted&lt;/i&gt; and &lt;i&gt;Packaged&lt;/i&gt; applications.&lt;br /&gt;&lt;br /&gt;&lt;u&gt;&lt;b&gt;Does the user have the proper version of chrome?&lt;/b&gt;&lt;/u&gt;&lt;br /&gt;This one is pretty important. NaCl shipped live in Chrome 14, and shipped 3D support in chrome 15. So if you have a user who hasn't upgraded, this could be an issue. The simplest way to do this is a javascript check for the browser vendor and version. The NaCl SDK has a great example that wraps up how to do a great load of these tests called &lt;a href="http://code.google.com/p/nativeclient-sdk/source/browse#svn%2Ftrunk%2Fsrc%2Fexamples%2Fload_progress"&gt;load_progress&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;To note, Chrome releases every 6 weeks or so, so it's common to get new versions frequently and require the user to update. Detecting the proper version shouldn't be a &lt;a href="http://www.codinghorror.com/blog/2011/05/the-infinite-version.html"&gt; point of stress&lt;/a&gt; however, just make sure you target that the user HAS chrome and has at-least the earliest version with your feature support.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;u&gt;&lt;b&gt;Has the user installed the NaCl app from the Chrome Web Store?&lt;/b&gt;&lt;/u&gt;&lt;br /&gt;Let's be clear about why this is an issue : &lt;b&gt;If you don't have the app installed in CWS, then you won't be able to run the NaCl module&lt;/b&gt;. &lt;br /&gt;&lt;br /&gt;This is a common problem! Let's say that personA installs your &lt;i&gt;Hosted&lt;/i&gt; app from the CWS, so that when they launch it, they get re-directed to your page where your module is running. They bookmark THAT page, and copy the URL to send to a friend. FriendB clicks the link, and the NaCl module doesn't load, generating lots of bug reports for you.&lt;br /&gt;&lt;br /&gt;The proper fix here is using a small snippet of javascript to tell if the user has installed the application from the CWS. &lt;a href="http://code.google.com/chrome/webstore/faq.html#faq-app-24"&gt;This page&lt;/a&gt; has the details. ("How do i detect if my app is running as an installed app...").&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;u&gt;&lt;b&gt;Does the user have the required hardware to run the NaCl module?&lt;/b&gt;&lt;/u&gt;&lt;br /&gt;This is a frequent problem for our NaCl modules with 3D support, specifically that the user installs the app, and doesn't have the required hardware to run the graphics. The exact problem is that Chrome has a list of &lt;a href="http://www.khronos.org/webgl/wiki/BlacklistsAndWhitelists"&gt;Blacklisted Drivers&lt;/a&gt; which are known to cause stability / security issues. &lt;br /&gt;&lt;br /&gt;The detection for this is that you won't get a valid glContext when you attempt to create one for the first time. This needs to be detected inside of NaCl and reported back to the javascript layer to alert the user of the problem.&lt;br /&gt;&lt;br /&gt;For the user, the general fix is to simply upgrade their graphics drivers. To be specific, Chrome blacklists the &lt;i&gt;driver&lt;/i&gt; not the gpu hardware.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;NOTE&lt;/b&gt; the REAL fix here is that we should be able to detect these hardware issues in the CWS and display the issue to the user. FWIW our CWS team is working hard on this feature, until then, please make sure you have proper fallbacks in your application.&lt;br /&gt;&lt;br /&gt;~Main&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1197137313991855034-1921386705557397768?l=mainroach.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/1921386705557397768/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1197137313991855034&amp;postID=1921386705557397768' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/1921386705557397768'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/1921386705557397768'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/2011/11/nacl-detecting-user-setup-problems.html' title='NaCl &amp; Detecting user setup problems'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1197137313991855034.post-4778180230536707190</id><published>2011-10-24T09:21:00.000-05:00</published><updated>2011-10-24T09:21:15.520-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='Native Client'/><title type='text'>NaCl And compiler flag groups</title><content type='html'>The &lt;a href="http://code.google.com/chrome/nativeclient/"&gt;Native Client SDK&lt;/a&gt; provides a modified version of the &lt;a href="http://gcc.gnu.org/"&gt;GCC compiler&lt;/a&gt; that produces safe, portable executable code. &lt;br /&gt;&lt;br /&gt;And for some developers, GCC is dark magic voodoo. (Proved by &lt;a href="http://mainroach.blogspot.com/2011/10/nacl-psa-for-your-current-setup.html"&gt;my previous post&lt;/a&gt; getting a bit of 'wtf? where's my IDE plugin' responses).&lt;br /&gt;&lt;br /&gt;&lt;a href="http://gcc.gnu.org/"&gt;GCC &lt;/a&gt;is a command line compiler that can generate your applications from C/C++ code. The SDK attempts to obfuscate you from the dirty bits of command line generation by using &lt;a href="http://www.scons.org/"&gt;SCONS&lt;/a&gt;, but sadly, this still requires a bit of hand tweaking to get right.&lt;br /&gt;&lt;br /&gt;Getting proper performance is key; and if you've been used to an IDE handling most of the command line options for you, then you've got no idea what flags actually need to be set.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://gcc.gnu.org/onlinedocs/gcc/Option-Summary.html"&gt;Here's &lt;/a&gt;an extensive list of compiler flags, some of the more important ones are listed below, depending on your build configuration.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;DEBUG: -g -O0&lt;/li&gt;&lt;li&gt;PROFILE: [-g] -O{2|3} -msse -mfpmath=sse -ffast-math -fomit-frame-pointer&lt;/li&gt;&lt;li&gt;DEPLOY: -s -O{2|3} -msse -mfpmath=sse -ffast-math -fomit-frame-pointer&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;Note&lt;/b&gt; The -Os flag (to optimize for size without loss of speed) has not been thoroughly tested. I suggest you strip the symbols from your nexe using the &lt;a href="http://code.google.com/chrome/nativeclient/docs/compiling.html"&gt;nacl-strip app&lt;/a&gt; provided in the sdk.&lt;br /&gt;&lt;br /&gt;Also the main difference between -O2 and -O3 is whether optimizations that involve a space-speed tradeoff are performed. It could be the case that these are not desirable due to download size, as such, you'll need to make your own performance measurements to detrmine if this is right for you.&lt;br /&gt;&lt;br /&gt;~Main&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1197137313991855034-4778180230536707190?l=mainroach.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/4778180230536707190/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1197137313991855034&amp;postID=4778180230536707190' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/4778180230536707190'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/4778180230536707190'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/2011/10/nacl-and-compiler-flag-groups.html' title='NaCl And compiler flag groups'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1197137313991855034.post-282263263883437843</id><published>2011-10-24T09:06:00.001-05:00</published><updated>2011-10-28T08:33:13.585-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Native Client'/><category scheme='http://www.blogger.com/atom/ns#' term='Chrome Web Store'/><title type='text'>NaCl And browsing detection</title><content type='html'>Loading NaCl modules can get tricky; Currently, you can only access &lt;a href="www.gonacl.com"&gt;Native Client&lt;/a&gt; apps through the &lt;a href="https://chrome.google.com/webstore/category/home"&gt;Chrome Web Store&lt;/a&gt;; so if someone browses to a &lt;a href="http://www.gonacl.com/dev/ht_packagedhosted.html"&gt;hosted &lt;/a&gt;NaCl app w/o first accessing the CWS, the module will fail, as the proper flags have not been set for access.&lt;br /&gt;&lt;br /&gt;Krasin has a &lt;a href="http://krasin.github.com/naclwtf/"&gt;nice page&lt;/a&gt; which can detect this; Simply browse to it, and it will check your browser version, flags, and even do a sample load of a nacl module to determine if it succeeded. (you can see the important javascript &lt;a href="http://krasin.github.com/naclwtf/naclwtf.js"&gt;here&lt;/a&gt;.)&lt;br /&gt;&lt;br /&gt;EDIT: One of my friends pointed out that the best way to do this is to actually browse the &lt;a href="http://code.google.com/chrome/webstore/faq.html#faq-app-24"&gt;list of installed plugins&lt;/a&gt; in javascript. In my tests, this proved to give the right answer 100% of the time.&lt;br /&gt;&lt;br /&gt;~Main&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1197137313991855034-282263263883437843?l=mainroach.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/282263263883437843/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1197137313991855034&amp;postID=282263263883437843' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/282263263883437843'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/282263263883437843'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/2011/10/nacl-and-browsing-detection.html' title='NaCl And browsing detection'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1197137313991855034.post-8975829028234404005</id><published>2011-10-08T17:31:00.002-05:00</published><updated>2011-10-09T09:14:41.581-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='Native Client'/><category scheme='http://www.blogger.com/atom/ns#' term='Chrome'/><title type='text'>NaCl : PSA for your current setup.</title><content type='html'>This is a Public Service Announcement on how your current build setup should be working when developing on Native Client&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;REMOVE&lt;/b&gt; &lt;i&gt;-fno-builtin&lt;/i&gt; from your compile options. - This flag turns on the slow path for math emulation, which will slow down your game considerably.&lt;/li&gt;&lt;li&gt;ADD the following flags to your compiler options:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;i&gt;-mfpmath=sse&lt;/i&gt;&lt;/LI&gt;&lt;li&gt;&lt;i&gt;-ffast-math&lt;/i&gt;&lt;/LI&gt;&lt;li&gt;&lt;i&gt;-fomit-frame-pointer&lt;/i&gt;&lt;/LI&gt; &lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Make sure you're on the latest &lt;a href="http://code.google.com/chrome/nativeclient/docs/beta-sdk.html"&gt;SDK for chrome 15&lt;/a&gt; &lt;br /&gt;&lt;ul&gt;&lt;li&gt;This moves the 3D APIs out of dev APIs&lt;/li&gt;&lt;li&gt;A number of speed improvements for the rendering RPC buffers&lt;/li&gt;&lt;li&gt;Fixes for ANGLE speeds.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt; Make sure you're running builds of &lt;a href="http://www.chromium.org/getting-involved/dev-channel"&gt;Chrome Canary&lt;/a&gt;, so that you get our fixes as they get pushed out. &lt;b&gt;NOTE, as of right now, Canary is up to date with Chrome 16.&lt;/b&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Also, the memory allocations in Native Client is not as fast as it should be right now. &lt;br /&gt;The &lt;a href="http://en.wikipedia.org/wiki/Newlib"&gt;NewLib &lt;/a&gt;library that Native Client is using for its' C++ runtime is not as performant as it needs to be; the &lt;a href="http://en.wikipedia.org/wiki/GNU_C_Library"&gt;GLIBC &lt;/a&gt;that's available in the &lt;a href="http://code.google.com/chrome/nativeclient/docs/beta-sdk.html"&gt;beta SDK&lt;/a&gt; is better, but the hassle of switching over may not be worth the effort (the process is not automated, you still have to do some manual work).&lt;br /&gt;Until this is fixed, please consider the following :&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Reduce dynamic memory allocations, per-frame, as much as possible (use free-lists, etc)&lt;/li&gt;&lt;li&gt;Use a static heap algorithm with either &lt;a href="http://g.oswego.edu/dl/html/malloc.html"&gt;dlmalloc&lt;/a&gt;, &lt;a href="http://rtportal.upv.es/rtmalloc/"&gt;tlsf&lt;/a&gt;, or &lt;a href="http://goog-perftools.sourceforge.net/doc/tcmalloc.html"&gt;tcMalloc&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1197137313991855034-8975829028234404005?l=mainroach.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/8975829028234404005/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1197137313991855034&amp;postID=8975829028234404005' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/8975829028234404005'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/8975829028234404005'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/2011/10/nacl-psa-for-your-current-setup.html' title='NaCl : PSA for your current setup.'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1197137313991855034.post-4308402793772366872</id><published>2011-10-08T17:21:00.000-05:00</published><updated>2011-10-08T17:21:39.141-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='Chrome'/><title type='text'>FPS Counter in Chrome</title><content type='html'>Little known fact: you can turn on an FPS counter in chrome.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Type &lt;b&gt;about:flags&lt;/b&gt; into your address bar&lt;/li&gt;&lt;li&gt;Turn on the &lt;b&gt;FPS Counter&lt;/b&gt; flag.&lt;/li&gt;&lt;li&gt;Turn on the &lt;b&gt;Focus existing tab on open&lt;/b&gt; flag.&lt;/li&gt;&lt;li&gt;Turn on the &lt;b&gt;GPU compositing on all pages&lt;/b&gt; flag.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Give the browser a restart, just to be sure.&lt;br /&gt;The next time you load up a page with some action, you'll see the FPS graph in the upper corner!&lt;br /&gt;&lt;br /&gt;~Main&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1197137313991855034-4308402793772366872?l=mainroach.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/4308402793772366872/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1197137313991855034&amp;postID=4308402793772366872' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/4308402793772366872'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/4308402793772366872'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/2011/10/fps-counter-in-chrome.html' title='FPS Counter in Chrome'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1197137313991855034.post-656556645745025397</id><published>2011-09-29T08:27:00.000-05:00</published><updated>2011-09-29T08:27:47.312-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='3D'/><category scheme='http://www.blogger.com/atom/ns#' term='opengles2.0'/><category scheme='http://www.blogger.com/atom/ns#' term='Native Client'/><title type='text'>NaCl : Don't call glDisable(GL_TEXTURE_2D)</title><content type='html'>&lt;b&gt;This information is valid as of 9.29.2011, with chrome build 101943&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;OpenGlES 2.0 does not support fixed function rendering. Sadly, for some engines porting over to NaCl that do support fixed function, they will eventaully call glDisable(GL_TEXTUE_2D). Which works for the older 1.1 FF calls, but in 2.0, this isn't supported.&lt;br /&gt;&lt;br /&gt;&lt;b&gt; do not call this function in your shipping product &lt;/b&gt;&lt;br /&gt;&lt;br /&gt;According to the spec, this generates an error. And in NaCl this error gets logged in our about:gpu tab, and grows endlessly.&lt;br /&gt;&lt;br /&gt;So, if you're calling this about 1-3 times a frame, you can expect a memory-filling logging overhead of about 3mb /sec.&lt;br /&gt;&lt;br /&gt;We're working to fix this behavior on our side, but until then, please don't call this function!&lt;br /&gt;&lt;br /&gt;~Main&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1197137313991855034-656556645745025397?l=mainroach.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/656556645745025397/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1197137313991855034&amp;postID=656556645745025397' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/656556645745025397'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/656556645745025397'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/2011/09/nacl-dont-call-gldisablegltexture2d.html' title='NaCl : Don&apos;t call glDisable(GL_TEXTURE_2D)'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1197137313991855034.post-4670703232795958736</id><published>2011-09-26T11:11:00.001-05:00</published><updated>2011-09-26T17:07:26.602-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='FileIO'/><category scheme='http://www.blogger.com/atom/ns#' term='Native Client'/><title type='text'>NaCl : Fetching files</title><content type='html'>In Native Client FileIO doesn’t work the same way as it would in a standard desktop running application. For security reasons, NaCl doesn’t let you just run off into the woods and randomly read / write to things. Instead it provides an obfuscated, restricted area on disk that you can read / write safely to. &lt;br /&gt;&lt;br /&gt;because of this, there's some nuances we need to talk about wrt &lt;b&gt;How to get to your files&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-0Ree29Mylus/ToChmCJtI9I/AAAAAAAAACU/qG_MiD5Ayc0/s1600/ht_fileio_apilist.jpg" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="143" width="200" src="http://4.bp.blogspot.com/-0Ree29Mylus/ToChmCJtI9I/AAAAAAAAACU/qG_MiD5Ayc0/s200/ht_fileio_apilist.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Firstly, your EXE file is being hosted on a WEB PAGE; Which means that the EXE isn’t running directly on a desktop, and doesn’t have access to the file system. So, in order to load files in your session, you need to you can use &lt;a href="http://code.google.com/p/nativeclient-sdk/source/browse/trunk/src/examples/geturl/geturl_handler.cc"&gt;geturl_handler&lt;/a&gt; to directly access files that appear to be 'on the server' where the .nexe file is hosted. The result will fetch the asset and return to you a binary stream that you can do with as you see fit. &lt;br /&gt;Since &lt;a href="http://code.google.com/p/nativeclient-sdk/source/browse/trunk/src/examples/geturl/geturl_handler.cc"&gt;GetURL &lt;/a&gt;is a web-call, Chrome will actively cache your asset for you; which means suibsiquent calls should not have to go out to the internet, but rather, pull it from the local cache.&lt;br /&gt;The upside of this, is that Chrome is doing this on your behalf. The downside, is that you’re victim to the whims of the cache, and have no guarantee of residency. &lt;br /&gt;&lt;br /&gt;A solution to that, is to use the &lt;a href="http://code.google.com/chrome/nativeclient/docs/reference/peppercpp/classpp_1_1_file_system.html"&gt;Pepper FileAPIs&lt;/a&gt;. They will give you access to the local disk to write the data to and manage caching yourself. For writing you’ll get access to a local sandbox data store that you can read/write too freely. More specificly this works well for games that can download their binary assets into the local file manager store, and stream the data from disk into the product so that you can control caching yourself.&lt;br /&gt;&lt;br /&gt;The latest SDK comes with an &lt;a href="http://code.google.com/p/nativeclient-sdk/source/browse/trunk/src/examples/pong/pong.cc"&gt;example&lt;/a&gt; that shows off how to use the File System APIs, and you can see &lt;a href="http://code.google.com/p/nativeclient-sdk/source/browse/trunk/src/examples/pong/pong.cc"&gt;that here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;~Main&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1197137313991855034-4670703232795958736?l=mainroach.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/4670703232795958736/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1197137313991855034&amp;postID=4670703232795958736' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/4670703232795958736'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/4670703232795958736'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/2011/09/nacl-fetching-files.html' title='NaCl : Fetching files'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-0Ree29Mylus/ToChmCJtI9I/AAAAAAAAACU/qG_MiD5Ayc0/s72-c/ht_fileio_apilist.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1197137313991855034.post-1758360766053084840</id><published>2011-09-22T10:37:00.000-05:00</published><updated>2011-09-22T10:37:31.928-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='3D'/><category scheme='http://www.blogger.com/atom/ns#' term='games'/><category scheme='http://www.blogger.com/atom/ns#' term='Native Client'/><title type='text'>NaCl apps in the wild!</title><content type='html'>Turns out NaCl apps have been starting to pop up in the wild!&lt;br /&gt;&lt;br /&gt;First is &lt;a href="https://chrome.google.com/webstore/detail/moehcjggbedbobepfihdamhnlneanioe?hc=search&amp;hcp=main"&gt;SodaSynth&lt;/a&gt; a sound synth tool built in Native Client.&lt;br /&gt;&lt;br /&gt;Next is &lt;a href="https://chrome.google.com/webstore/detail/ocpoapiejnpokdojkgjhglijajghikla?hc=search&amp;hcp=main"&gt;OGRE&lt;/a&gt; which currently only works with Chrome 15 out of the Dev channel.&lt;br /&gt;&lt;br /&gt;More includes &lt;a href="http://sixtysecondshootertest.appspot.com/"&gt;60 second shooter&lt;/a&gt;. (see the &lt;a href="http://sixtysecondshootertest.appspot.com/html/support.html"&gt;HOW TO&lt;/a&gt; in order to get the flags right)&lt;br /&gt;&lt;br /&gt;And &lt;a href="http://www.naclbox.com/"&gt;NaClBox&lt;/a&gt; just got &lt;a href="http://www.naclbox.com/gallery/descent"&gt;Descent &lt;/a&gt;working!&lt;br /&gt;&lt;br /&gt;And don't forget the classics : &lt;a href="http://nacl-quake.appspot.com/"&gt;QUAKE&lt;/a&gt; and &lt;a href="http://doom.pdox.net/"&gt;DOOM&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;~Main&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1197137313991855034-1758360766053084840?l=mainroach.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/1758360766053084840/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1197137313991855034&amp;postID=1758360766053084840' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/1758360766053084840'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/1758360766053084840'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/2011/09/nacl-apps-in-wild.html' title='NaCl apps in the wild!'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1197137313991855034.post-5864776168237006799</id><published>2011-09-13T09:25:00.001-05:00</published><updated>2011-09-13T11:07:53.608-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='3D'/><category scheme='http://www.blogger.com/atom/ns#' term='Native Client'/><title type='text'>NaCl : The super quick start</title><content type='html'>Looking to get up and running with Native Client quickly?&lt;br /&gt;&lt;br /&gt;Firstly, let me point you to the &lt;a href="http://code.google.com/chrome/nativeclient/"&gt;SDK site&lt;/a&gt;; I suggest running through the '&lt;a href="http://code.google.com/chrome/nativeclient/docs/tutorial.html"&gt;getting started&lt;/a&gt;' tutorial first, just to make sure everything is set up.&lt;br /&gt;Secondly, take a look at &lt;a href="http://www.chromium.org/nativeclient/how-tos/guide-to-experimental-3d-support"&gt;How to get experimental 3D up and running&lt;/a&gt;. (If you're into that sort of thing.)&lt;br /&gt;Thirdly, hop over to some details on how to get various forms of &lt;a href="http://www.chromium.org/nativeclient/how-tos/debuggingtips"&gt;debugging working&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Once you've got those set up, there's some known pain-points that we're working on:&lt;br /&gt;&lt;br /&gt;#1 - There's currently no native support for TCP/UDP. You can get around using TCP by sending calls through Pepper to Javascript, and using a websocket from there. (This is primarily a security issue. Imagine if a webpage could sniff your ports and watch your network traffic!)&lt;br /&gt;&lt;br /&gt;#2 - File IO - While Pepper has a full &lt;a href="http://code.google.com/chrome/nativeclient/docs/reference/peppercpp/classpp_1_1_file_system.html"&gt;Filesystem API&lt;/a&gt;; most developers find it easier to request their binary bundles using geturl_handler.cc from the SDK (check out the life example) Once they grab the bundle, they can either cache it locally using FileIO, or just skip through it in memory&lt;br /&gt;&lt;br /&gt;#3 - Sound - If the Pepper &lt;a href="http://code.google.com/chrome/nativeclient/docs/reference/peppercpp/classpp_1_1_audio.html"&gt;sound API&lt;/a&gt; isn't good enough for you; FMOD has &lt;a href="http://www.fmod.org/index.php/download"&gt;support for native client&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;#4 - Build Systems - The SDK comes with &lt;a href="http://www.scons.org/"&gt;SCONS&lt;/a&gt;. Most people find SCONS to be confusing the first few times (especially if you develop on windows primary); SCONS is a 3rd party library with lots of documentation to find, please seek that out first.&lt;br /&gt;&lt;br /&gt;#5 - Help - If the SDK and Chromium pages don't answer your questions, there's two resources available to you:&lt;br /&gt;&lt;b&gt;1. For New Developers, or common issues, &lt;/b&gt; head over to &lt;a href="http://stackoverflow.com/search?q=native+client"&gt;Stack overflow&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2. For NaCl bug reports, SDK Problems, &lt;/b&gt; stop by the &lt;a href="https://groups.google.com/group/native-client-discuss"&gt;Native Client Discussion&lt;/a&gt; group.&lt;br /&gt;&lt;br /&gt;~Main&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1197137313991855034-5864776168237006799?l=mainroach.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/5864776168237006799/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1197137313991855034&amp;postID=5864776168237006799' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/5864776168237006799'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/5864776168237006799'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/2011/09/nacl-super-quick-start.html' title='NaCl : The super quick start'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1197137313991855034.post-2090008396551969998</id><published>2011-09-12T08:48:00.000-05:00</published><updated>2011-09-12T08:48:18.248-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='3D'/><category scheme='http://www.blogger.com/atom/ns#' term='blending'/><category scheme='http://www.blogger.com/atom/ns#' term='Native Client'/><category scheme='http://www.blogger.com/atom/ns#' term='alpha blending'/><title type='text'>NaCl &amp; 3D: Alpha Blending Bug FEATURE!</title><content type='html'>In NaCl, there are two primary ways to do &lt;a href="http://en.wikipedia.org/wiki/Alpha_compositing"&gt;alpha blending&lt;/a&gt;.&lt;br /&gt;1) Drawing a transparent object with alpha blending ENABLED.&lt;br /&gt;2) Drawing a transparent object with alpha blending &lt;b&gt;DISABLED&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;The first way acts as you would expect, blending with the frame buffer as any other API;&lt;br /&gt;The 2nd one though.. that's where the &lt;i&gt;magic&lt;/i&gt; happens.&lt;br /&gt;If you render an object with modified alpha, with alpha blending disabled, then the system assumes that you are taking into account &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2009/11/06/premultiplied-alpha.aspx"&gt;premultiplied alpha&lt;/a&gt;, and rather than blending with the frame buffer, blends with the last modified alpha. Namely being the webpage, not the frame buffer.&lt;br /&gt;&lt;br /&gt;To Be Clear: &lt;b&gt;  If you disable blending, and render an object with a non 1.0 alpha value in the pixel shader, then that object will blend with the background webpage, &lt;i&gt;not&lt;/i&gt; the background frame buffer &lt;/b&gt;&lt;br /&gt;&lt;br /&gt;The unfortuinate part of this, is that it's not the exact result you expect when coming from other rendering APIs. There's a couple ways to fix this.&lt;br /&gt;&lt;br /&gt;&lt;b&gt; #1 : in C++ Force-Clear the backbuffer alpha at the end of the frame&lt;/b&gt;&lt;br /&gt;Add the following at the end of your render loop, before the glPresent():&lt;br /&gt;&lt;br /&gt;&lt;table width="100%" bgcolor="#222222"&gt;&lt;tr&gt;&lt;td&gt;&lt;b&gt;glColorMask(false,false,false,true);&lt;br /&gt;glClearColor(0,0,0,1);&lt;br /&gt;glClear(GL_COLOR_BUFFER_BIT);&lt;br /&gt;glColorMask(true,true,true,true);&lt;br /&gt;&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;b&gt; #2 : in HTML, add a DIV under your EMBED tag.&lt;/b&gt;&lt;br /&gt;This is less fun, but isolates the issue on the HTML side of things, rather than the C++. One thing to note here is that you need to be VERY sensitive to page re-size events to make sure that the NaCl, EMBED, and DIVs all have the same pixel size.&lt;br /&gt;&lt;br /&gt;&lt;b&gt; #3 : When the API gives you lemons, find a cool background image.&lt;/b&gt;&lt;br /&gt;Alternatively, there's some interesting things you can do with blending your game to your page background color. For instance, you could create a custom shape for your rendering window. Or even better, incorporate this into your product, and do some really nifty Pepper / NaCl magic to modify your render window shape over time.&lt;br /&gt;&lt;br /&gt;Or, play a YouTube video of a &lt;a href="http://youtu.be/c5U4Q4A1LWQ"&gt;Boxing Cat&lt;/a&gt; behind your app. It'll drive the internet &lt;i&gt;wild&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;~Main&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1197137313991855034-2090008396551969998?l=mainroach.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/2090008396551969998/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1197137313991855034&amp;postID=2090008396551969998' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/2090008396551969998'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/2090008396551969998'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/2011/09/nacl-3d-alpha-blending-bug-feature.html' title='NaCl &amp; 3D: Alpha Blending &lt;strike&gt;Bug&lt;/strike&gt; FEATURE!'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1197137313991855034.post-4343520144793088807</id><published>2011-09-07T17:37:00.002-05:00</published><updated>2011-09-07T17:41:22.249-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='3D'/><category scheme='http://www.blogger.com/atom/ns#' term='Native Client'/><category scheme='http://www.blogger.com/atom/ns#' term='Chrome'/><title type='text'>NaCl &amp; 3D: Rendering from a sandbox</title><content type='html'>We've had NaCl 3D support in Beta channgel for a bit now. You can go &lt;a href="http://www.chromium.org/nativeclient/how-tos/guide-to-experimental-3d-support"&gt;here &lt;/a&gt;if you're interested in playing with it.&lt;br /&gt;&lt;br /&gt;To understand that, let's take a look at how 3D is implimented in NaCl &amp; Chrome.&lt;br /&gt;&lt;br /&gt;Firstly Chrome is a &lt;a href="http://www.google.com/googlebooks/chrome/index.html"&gt;mutli-process browser&lt;/a&gt;; each tab is a seperate process, that has its' own memory, cycles, and containment. Because processes don't directly share memory spaces, communication between tabs/processes is done through a method called &lt;a href="http://en.wikipedia.org/wiki/Remote_procedure_call"&gt;RPC, or Remote Procedure Calls&lt;/a&gt;. RPC commucation acts like a packatized networking stream, where small blocks of data are batched up in a buffer, and flushed across the RPC pipe to another process at a later time.&lt;br /&gt;&lt;br /&gt;BTW, these RPC flushes come in two flavors:&lt;br /&gt;A flush - simply do an asyncrhounus flush of the buffer&lt;br /&gt;A sync flush - flush the data, and wait until the buffer is consumed.&lt;br /&gt;&lt;br /&gt;For 3D in NaCl, &lt;b&gt; it's the 2nd kind that you need to be worried about.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;For security purposes, all your 3D calls occur in a seperate process. This is not the same process as your current tab, but yet another process that focuses solely on communicating with the graphics API. As such, all your OpenGLES calls occuring inside of your NaCl process do nothing more than push command data into an RPC buffer. &lt;br /&gt;&lt;br /&gt;The upside of this, is that your NaCl process doesn't lose any processing due to graphics API calls. This has been a bane of PC graphics computing for some time now, and its' nice to know that you don't have to split processing between rendering and sim work on your main thread.&lt;br /&gt;&lt;br /&gt;The downside though, is that it's unclear &lt;i&gt;when&lt;/i&gt; an RPC flush call can occur, and weather it is going to be a simple flush or a sync flush. Since each GL call pushes a new command onto the buffer, your flush can occur inside your gl call on your NaCl process. Which means if you're doing processing, it &lt;i&gt;could&lt;/i&gt; look like a random GL call spikes up to 98ms for no reason. This type of debugging data would lead you to believe that there's something wrong with the Native Client GL implimentation, but alas, it's all about the RPC flushing.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So, how do you work around this to keep your 3D performance high in your application?&lt;br /&gt;&lt;br /&gt;Firstly, visit &lt;a href="http://blogs.msdn.com/b/shawnhar/archive/2008/04/07/how-to-tell-if-you-are-cpu-or-gpu-bound.aspx"&gt;this page&lt;/a&gt; and walk through some testing to determine if you're GPU or CPU bound. Note, if you're GPU bound, there's nothing NaCl specific about your problem; NaCl uses the same driver and GPU as your desktop rendering apps. If you're CPU bound, and your seeing spikes in your openGL ES calls then try this:&lt;br /&gt;&lt;br /&gt;First, turn on these environment variables to profile when flushes occur:&lt;br /&gt;&lt;b&gt;Note, the following data is valid as of 9.07.2011&lt;/b&gt;&lt;br /&gt;For more output:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;set PPAPI_BROWSER_DEBUG=1&lt;/li&gt;&lt;li&gt;set NACL_PLUGIN_DEBUG=1&lt;/li&gt;&lt;li&gt;set NACL_PPAPI_PROXY_DEBUG=1&lt;/li&gt;&lt;li&gt;set NACL_SRPC_DEBUG=1 # pick higher number for increased verbosity&lt;/li&gt;&lt;li&gt;set NACLVERBOSITY=2&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Redirect the stdout/stderr (needs --no-sandbox as a command line flag):&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;set NACL_EXE_STDOUT=c:\work\nacl.log&lt;/li&gt;&lt;li&gt;set NACL_EXE_STDERR=c:\work\nacl.log&lt;/li&gt;&lt;/ul&gt;With these turned on, you should be able to see when your flushes occur in nacl.log.&lt;br /&gt;&lt;br /&gt;Secondly, try to force flushes before heavy processing that doesn't have an RPC function call. For instance, right before you kick off your multithreaded particle work, call a flush so that the RPC pipe will be clear by the time you're going to start doing GL calls again.&lt;br /&gt;You can do this directly with two GL function calls :&lt;br /&gt;&lt;br /&gt;glFlush - which will force a flush&lt;br /&gt;glFinish - which will force a flush with a sync.&lt;br /&gt;&lt;br /&gt;I find doing flushes around every 500 or so draws nets me a huge win in NaCl. So make sure your profile your workload and use case, and find an appropriate heuristic in which to issue flush calls.&lt;br /&gt;&lt;br /&gt;~Main&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1197137313991855034-4343520144793088807?l=mainroach.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/4343520144793088807/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1197137313991855034&amp;postID=4343520144793088807' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/4343520144793088807'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/4343520144793088807'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/2011/09/nacl-3d-rendering-from-sandbox.html' title='NaCl &amp; 3D: Rendering from a sandbox'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1197137313991855034.post-5457878484465928674</id><published>2011-09-01T11:49:00.000-05:00</published><updated>2011-09-01T11:49:35.514-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Native Client'/><category scheme='http://www.blogger.com/atom/ns#' term='html5'/><category scheme='http://www.blogger.com/atom/ns#' term='google'/><title type='text'>Back in Black; But highly salted.</title><content type='html'>I'm back! This site had to go down for a while due to unforeseen circumstances. But now that I've gotten all the Tribbles out of the warp nacels, we should be good to go.&lt;br /&gt;&lt;br /&gt;I'm now over at &lt;a href="http://www.google.com"&gt;Google &lt;/a&gt;as a Developer Advocate focusing on gaming for &lt;a href="http://www.chromium.org/nativeclient"&gt;Native Client&lt;/a&gt;. The short of which, is my focus to bring genre-busting gaming experiences to Native Client and the &lt;a href = "https://chrome.google.com/webstore"&gt; Chrome Web Store &lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;For those who haven't heard, Native Client (or &lt;a href="http://en.wikipedia.org/wiki/Sodium_chloride"&gt;NaCl&lt;/a&gt;) is an open source technology that allows you to run native code in web browsers. More specifically, it allows you to run &lt;i&gt;C++ code&lt;/i&gt; in web browsers.&lt;br /&gt;&lt;br /&gt;We're seeing a massive segmentation in the games industry right now. Every platform seeks to create a silo of content, community and developers, and as such, usually has a barrier to entry for developers to move to that platform. This is exceptionally difficult for C++ game developers who ship on consoles/PC to adopt to. Until now, if you wanted to get your XBLA game into the web, you had to re-write everything from C# to &lt;a href="http://www.html5rocks.com"&gt;HTML5&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;And that's a lot of risk for game developers, who are usually doing everything they can to stay in the black. So tossing all their code out the window to move to a new platform isn't an option to them. But what if they could use that same code, and move to the web, so you get digital distribution, AND access to all 6 billion humans on the planet?&lt;br /&gt;&lt;br /&gt;With Native Client, you can &lt;i&gt;do&lt;/i&gt; that.&lt;br /&gt;&lt;br /&gt;Basically, you send your C/C++ code through a modified GCC compiler, and in return, get a 'web safe' application that can be ran inside of a web browser, on &lt;i&gt;any platform&lt;/i&gt;. &lt;br /&gt;&lt;br /&gt;But we'll get into that more later.&lt;br /&gt;&lt;br /&gt;In fact, we're just getting started.&lt;br /&gt;&lt;br /&gt;~Main&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If you're interested in Native Client, hop on over to the &lt;a href="http://code.google.com/chrome/nativeclient/docs/tutorial.html"&gt;SDK and get started&lt;/a&gt;.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1197137313991855034-5457878484465928674?l=mainroach.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/5457878484465928674/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1197137313991855034&amp;postID=5457878484465928674' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/5457878484465928674'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/5457878484465928674'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/2011/09/back-in-black-but-highly-salted.html' title='Back in Black; But highly salted.'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1197137313991855034.post-2126032309695270473</id><published>2008-04-15T13:36:00.001-05:00</published><updated>2011-09-15T13:37:23.250-05:00</updated><title type='text'>Abstracting</title><content type='html'>Abstracting code out to proper, generic, reusable containers is not something that the novice programmer excels at. Most often, code produced is highly specific, very static, and often, not to easy to modify and maintain over time. Early on, I devised a way to fix most of these issues, as I was writing the code. As time went on, I learned to identify the things that could be extracted out into generic containers early on, and avoided having to do multiple passes over my code to generate them.&lt;br /&gt;&lt;br /&gt;"Where is this useful?" I've often found that data managers can, on the whole, be turned into generic functions. For example, a streaming terrain system could be abstracted to several generic containers : Generic Cache, LRU Cache, Streaming Class, Streamed Cache, Streamed Cache populator etc etc. These all could be rolled into one manager for the process, but then if you'd like to duplicate everything for streaming meshes, well, you'd almost have to re-write the entire damn thing!&lt;br /&gt;&lt;br /&gt;In general, here's the process I hold to :&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Write the code as it functions and works in your head. Make sure you're including all the bells and whistles you need. As a general rule here, you want to make the interfaces as slim and generic as possible. Not just because you're planning on genericising it, but because that's just good programming. Note, this also includes allowing massive initialization parameters to be bunched up into classes so that if your function is overridden, the parameters can also be overriden to be expanded by other implementing classes.&lt;/li&gt;&lt;li&gt;Do a quick check to see if any of the operating functionality of your class can be either replaced, or better represented with common generic containers. I'm not saying that your custom, slim, name-value hash paring isn't good, but if it can be replaced by an STL container, or another one that is used elsewhere in the code, you can bet it may be more reliable, and have more general functions. Yea, and as stupid as this sounds, you'd be amazed how many times you'll re-write basic functionality for a system that already exists in a generic form elsewhere. Don't laugh, you're guilty too!&lt;/li&gt;&lt;li&gt;Take a look at your data and how your using it. Could there be any part of your data that could be considered abstracted? Can how you're using it be abstracted? In some cases, can your data be replaced by generic dynamic containers? (Ie can a statically allocated array be replaced by a statically templated array?)&lt;/li&gt;&lt;li&gt;Create new containers that are 'above' your current class. Always approach your current class as the result of inheritance of several container classes; IE it's the leaf of the tree. Start with baby steps in this process. If you get hung up in an area that can't be genericied, then consider it as part of your leaf class, and not part of your generic container. Standard warnings apply about ensuring that your generic classes are memory safe, potentially thread safe, and well documented about it's differences and operations against other containers.&lt;/li&gt;&lt;li&gt;Repeat these steps until you can get at least one generic container out of your data manager. If you can get more, even better.&lt;/li&gt;&lt;/ol&gt;Yea, it's a bit slower than you'd like, but atleast you're getting some good, reusable stuff out of it. And really, when I do code reviews, this is one of the things I look at, just how generic is your code, son?&lt;br /&gt;&lt;br /&gt;~Main&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1197137313991855034-2126032309695270473?l=mainroach.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/2126032309695270473/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1197137313991855034&amp;postID=2126032309695270473' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/2126032309695270473'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/2126032309695270473'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/2008/04/abstracting.html' title='Abstracting'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1197137313991855034.post-1870843271033942584</id><published>2008-02-27T13:34:00.001-06:00</published><updated>2011-09-15T13:35:30.965-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='books'/><title type='text'>BTW, I'm published</title><content type='html'>Game Programming Gems 7 just hit the shelves, and with an unbound amount of luck, my article, "Efficient cache replacement using the Age and Cost metrics" is sitting front and center in the book.&lt;br /&gt;&lt;br /&gt;As already reported on the web, I've got another article coming up in AI Programming Wisdom 4, co-authored with a good friend James Stewert.&lt;br /&gt;&lt;br /&gt;I've got about 4 more articles sitting around, waiting for someone to publish them (well.. waiting for me to have time to finish them first...) so I'm glad I'm not dry on ideas ;)&lt;br /&gt;&lt;br /&gt;To be honest, I like publishing articles and sharing my knowledge. I'm usually bound by the 'Don't talk about anything that's too super cool' due to my job, but in general, there's enough I do in a given day to shake up 1-2 publications every few months. That's one reason I started (and still am) teaching at Guildhall; I'm a self taught games programmer, my undergrad was useless to me for programming purposes (although I did learn the valuable art of the keg stand..) and I recall so many times wishing for information that wasn't available. In some respects publishing and teaching is my way of giving back to others, what I didn't have when I was a struggling programmer.&lt;br /&gt;&lt;br /&gt;See, now I can add "Humanitarian" to my resume...&lt;br /&gt;&lt;br /&gt;~Main&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1197137313991855034-1870843271033942584?l=mainroach.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/1870843271033942584/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1197137313991855034&amp;postID=1870843271033942584' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/1870843271033942584'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/1870843271033942584'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/2008/02/btw-im-published.html' title='BTW, I&apos;m published'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1197137313991855034.post-4789089135660406599</id><published>2008-02-03T13:33:00.002-06:00</published><updated>2011-09-15T13:34:46.566-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='games'/><category scheme='http://www.blogger.com/atom/ns#' term='industry'/><title type='text'>What does it take?</title><content type='html'>The first exposure many of you had to my current project was when this news came out. (Wow.. 2006.. has it been that long?) As we've mentioned before, the project was in development for some time before that date for prototyping. In truth, development on this project has been brewing since as early as 2004 with prototype teams and proof of concept that we could pull off a great RTS on the console. But as many of you know, what's required in this industry are results; Shipping your game. I think our relative release date has been mentioned, although for sake of CYA, I won't mention it here, but rather suggest that you will be able to purchase this product sometime this year. So on the verge of realizing a 4 year vision, I've been looking really hard lately about what it takes to actually get your product out the door.&lt;br /&gt;&lt;br /&gt;I'll be blunt : Video game development is psychotic. And anyone who's involved with it needs to be a tad bit screwed up in the brain to make it through at a professional level.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I've mentioned before that this industry may not be stocked with the most technical people, yet at the core, we're developing a product in a super technical environment. This causes large swings in impact of decisions over the lifetime of the project. Technical and tool chain decisions made at the very beginning of the project often butt heads with fast-and-hard crunch and final push development at the end of the project. So in reality, our job as programmers is almost to act as oracles into the future of the life cycle of the project. In truth, we can't trust our users, ( which is a concept that I naively ignored when starting this project and has come full circle to bite me in the lower parts of my ass.) so we really can't rely on what they are telling us they 'want' out of the future of their development environment.&lt;br /&gt;&lt;br /&gt;I can personally vouch for the fact that too much freedom with content developers is asking for death and confusion in your product. Which, if you listen to them, is the only thing that they dream about at night or when they are alone in the shower. Actions show, however, that more freedom requires more technical understanding of the authoring process, which requires more frontal-lobe-power-per-minute in order to complete their jobs, and that's not always available , or the best idea. I've been impressed before by low-tech solutions to engine systems that have amazing art results and visual, and have come to the conclusion that the reason for visual success in these realms, is not due to feature availability, but LACK of features that force content creators to explore the entire expanse of potential within their constraints.&lt;br /&gt;&lt;br /&gt;So when your final 15-month crunch starts before ship, the ability to finish the project relies on the fact that your tool chain is simple enough that low-frontal-lobe-horsepower people can make art, and not screw things up / break the entire pipeline.&lt;br /&gt;&lt;br /&gt;That being said, I believe there's some confusion at a great deal of companies about what it takes to get that last 100meters out of the game. Recent GDC talks from Blizzard suggest that they have an 'All hands' approach to a shipping title, in that when the cowbell rings, everyone gets behind the shipping cow, and pushes it over the line, as though it were incapable of doing so on it's own like some 50 ton Banana slug. Within 15 mintues of that news hitting, e-mail threads started like wildfire supporting this idea. "Woah" I replied, "If we can't finish the final 10% this product without the entirety of the rest studio helping us, why wait until the final RTM crunch? Why not bring everyone on board NOW so that we release a MUCH more polished product, rather than something with 'less bugs' ?"&lt;br /&gt;&lt;br /&gt;Crickets.&lt;br /&gt;&lt;br /&gt;Which goes to prove my next point: It takes heart to ship a game.&lt;br /&gt;&lt;br /&gt;To elaborate, it takes the attachment to stay focused and productive when you're not crunching for a beta, or a milestone, or RTM. It takes dedication to keep making progress even when the game isn't sexy (yet), and be committed to it long before the it-just-hit-the-fan crunch.&lt;br /&gt;&lt;br /&gt;Game studios that adopt to the 'all hands before ship' approach to things are in my opinion, just patching up problems from the entire dev cycle, and fooling themselves into thinking that adding 200 chefs into the already packed kitchen will really make a massive difference in the short term. More importantly, they are fooling themselves by putting people on the project, during the most crutial time of the project, whom don't have the heart for it. These people are usually working on other projects, their projects, and getting sucked into your project is, at even an unconcous level, pretty annoying.&lt;br /&gt;&lt;br /&gt;If you're going to need the help at the end, just bring them on earlier. Let them get attached to the product, let them take vestment in the decisions. Let them give a damn about what's rolling out the door.&lt;br /&gt;&lt;br /&gt;Because we're all aware, nothing hurts your heart for your project than A never ending crunch.&lt;br /&gt;&lt;br /&gt;Which, unfortunitally, is what most people think is what it REALLY takes to ship a game......&lt;br /&gt;&lt;br /&gt;~Main&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1197137313991855034-4789089135660406599?l=mainroach.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/4789089135660406599/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1197137313991855034&amp;postID=4789089135660406599' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/4789089135660406599'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/4789089135660406599'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/2008/02/what-does-it-take.html' title='What does it take?'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1197137313991855034.post-428392662826726970</id><published>2008-01-07T13:31:00.001-06:00</published><updated>2011-09-15T13:32:40.774-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='threading'/><title type='text'>New year in 'threads'</title><content type='html'>I bit the bullet reciently and upgraded my 4 year old single core PC to a snazzy new Intel Q6600 Quad core machine. The price was pretty good, for around $500 I walked out with the processor, Motherboard, and 2gb of ram. What spurred this, was mainly the interest and research I've been doing lately in the real time ray tracing realm.&lt;br /&gt;&lt;br /&gt;And let's get one thing straight with that. About a year ago, when I told people that software graphics would be the future, I had my fair share of arguments and skeptics. A year later, a software project is already putting out an open source real time ray tracer, which doesn't do any black magic. Really, it does what you'd expect it to, Use multi core, and SIMD. WOW. Amazing! Nothing fancy with RT hardware, or any cutting edge BVH.. just using what is available to us.&lt;br /&gt;&lt;br /&gt;Plus, these other people agree with me. So, it's safe to say I'm not that crazy.&lt;br /&gt;&lt;a href="http://rt07.raytracing.nl/"&gt;Arauna real time ray tracer&lt;/a&gt;&lt;br /&gt;&lt;a href="http://blogs.intel.com/research/2007/10/real_time_raytracing_the_end_o.php"&gt;Intel Blogs&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.beyond3d.com/content/news/511"&gt;Beyond 3D response&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;~Main&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1197137313991855034-428392662826726970?l=mainroach.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/428392662826726970/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1197137313991855034&amp;postID=428392662826726970' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/428392662826726970'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/428392662826726970'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/2008/01/new-year-in-threads.html' title='New year in &apos;threads&apos;'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1197137313991855034.post-6162916664336110494</id><published>2007-09-01T09:50:00.004-05:00</published><updated>2011-09-15T09:52:34.879-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='memory'/><category scheme='http://www.blogger.com/atom/ns#' term='virtual memory'/><title type='text'>Random Access Compressed Containers</title><content type='html'>One situation I've been having to work with a great deal lately is the problem of not having enough memory for data that is highly, repetitively, and randomly accessed in my applications.&lt;br /&gt;&lt;br /&gt;The data is accessed too much to warrant an out-of-core solution, I suppose that I could free up memory from other systems to make room, but instead, I've embarked on a series of containers that are just really cool.&lt;br /&gt;&lt;br /&gt;Standard regular grids (such as textures) save a bit of memory because they don't store spatial locality data. Rather, it's implied that through neighborhood association, your location can be derived. Even with idiotically large data sets, you can still access a regular grid pretty randomly, and almost quite immediately. You never need extra traversals besides a single offset value into the memory stream.&lt;br /&gt;&lt;br /&gt;But, with idiotically large data, you run into the problem that you either don't have enough memory to hold it all. The problem then, is how do you store your large regular grid data set in memory, while still keeping all the properties to allow random access?&lt;br /&gt;&lt;br /&gt;That's where these containers come in. Standard compression algorithms, like JPG2k, vector and wavelets operate on iterative compression systems, such that to get the value of any single data element, we must evaluate a much larger portion of our data.&lt;br /&gt;&lt;br /&gt;For clairity, let's define a Random Access Compressed Container (RACC) as having the following properties:&lt;br /&gt;a) The in-memory, working data set is a compressed representation of a larger dataset.&lt;br /&gt;b) Any element of data within the set can be randomly accessed with minimal decompression of non-relevant data. ( this gets a little 'fuzzy' as 'minimal' changes depending on your platform and target performance.)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Optionally, you can modify the RACC to be a Working RACC (WRACC) by adding another property:&lt;br /&gt;c) As data is added to the compressed representation, non-relivant data is re-compressed based upon its corrolation to the input data.&lt;br /&gt;&lt;br /&gt;What this basicly means, is that a WRACC is a runtime container that data is added to over time. As the data is added, depending on the compression method, other data may need to be re-compressed to take into account the incoming data. For example, if you and a WRACC that implimented an RLE compression scheme, and you added a piece of data to the set that broke one of the RLE runs internally, then that run would be split into two runs, each strattling the newly inserted data.&lt;br /&gt;&lt;br /&gt;Now, each one has their place. I love the ease of use of WRACCs, although you can never get as much compression as you can with a standard RACC.&lt;br /&gt;&lt;br /&gt;Some examples:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;b&gt;RACCs&lt;/b&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Perfect Spatial Hashing&lt;/b&gt;&lt;br /&gt;Hugues Hoppe came up with this one. Basically, he removes sparse data in a set by moving the defined data to a separate data structure which still keeps some implicitly defined regular organization. ( you can read the actual paper for a much better explanation)&lt;br /&gt;&lt;br /&gt;The pro's of this are that you can compress your sparse data set in to it's MINIMAL needed representation, and still have random access to it that doesn't requrie any traversals or extra decompression. (note, this works much like the jagged container, in that we must define what data value is considered 'empty' and only move non-empty values into the extra data sets)&lt;br /&gt;&lt;br /&gt;The cons are that the data must be static. Which kills us for direct editor usage, but it's still nice to take in some of the philosophies.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;center&gt;WRACCs&lt;/center&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Jagged Array&lt;/b&gt;&lt;br /&gt;Andrew Foster came up with a great solution for the Halo Wars editor (and where this all started). Basically, we were struggling with exceptionally sparse data sets, but needed the ability for the sparse data set to a) be compressed, and b) still emulate a regular grid to the outside world.&lt;br /&gt;&lt;br /&gt;The Jagged array container works by creating pointers to the start of each scanline of your 2D data (IE, one per row). When data is placed into the array, we first determine if that row exists. If it doesn't, then we allocate the entire row, and set the pointer appropriately. When we access the container, we usually pass in a 2D coordinate; If the specified row value exists, then we traverse the row to the column coordinate, and return the proper value. If the row has not been allocated however, then we simply return a pre-specified 'empty' value.&lt;br /&gt;&lt;br /&gt;The container works exceptionally well. The row index acts as a pseudo hash key into a table of data (which still maintains regular connectivity). While the x coord is the internal value. We can still keep random access with this process, and we save memory by not allocating 'empty' data.&lt;br /&gt;&lt;br /&gt;This does however, degenerate, as we add progressivly more data, the container itself degenerates back to a regular grid. Also, this conainer allocates a great deal more memory than needed most of the time; for instance, if we enter every element in a single column, the JA would allocate every row, and immediatly degenerate into a 2d grid&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Random Access RLE (or JaggedRLE)&lt;/b&gt;&lt;br /&gt;An extension to this process that I developed is an extra step to help reduce the memory footprint was to RLE any row of data that the jagged array points to. This way, if we have any sort of homogeneous data, we get a mild perf win. This also addresses sparse raster data, such that if there is minimal data elements in a single row, then we do not store the entire row in memory.&lt;br /&gt;&lt;br /&gt;Per row, I label RLE compressed blocks with their start and value, and to safe time, I flag unique blocks with the same process. The row index still acts as a hash key, but now the X value requires some searching to occur. To find our X value, I have to find what block the X Value resides in. This requires walking each block in the stripe and adding the traversed pixels to our running count for the line until we find a block that spans X. If the block is compressed, we simply return the repeated value. If it's not compressed, then we return the element that exists where X should be pointing (derived by subtracting the start of the block from X, and adding that to the start of the block as a local index..)&lt;br /&gt;&lt;br /&gt;Although it's trickier, you can still submit data into the container @ runtime, and allow it to RLE the row as it changes.&lt;br /&gt;&lt;br /&gt;One problem with this however, is that it falls to the standard problems of RLE, in that the more random the data, the less efficient it is to store it as such.&lt;br /&gt;&lt;br /&gt;One side observation though, is that it may be wiser to store pointers to blocks, instead of stripes. Usually images are not really raster in nature, and rather block based, such that RLEing a block may yield better results than a scanline.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Well, those are just a few ideas. You can see that these are powerful notions. The ability to edit data that is compressed on the fly, as well as randomly access it with minimal performance hit, all while expressing a minimal memory footprint!&lt;br /&gt;&lt;br /&gt;That's good shit.&lt;br /&gt;&lt;br /&gt;~Main&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1197137313991855034-6162916664336110494?l=mainroach.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/6162916664336110494/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1197137313991855034&amp;postID=6162916664336110494' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/6162916664336110494'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/6162916664336110494'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/2007/09/random-access-compressed-containers.html' title='Random Access Compressed Containers'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1197137313991855034.post-6726577829123043811</id><published>2007-08-30T09:48:00.006-05:00</published><updated>2011-09-15T09:50:34.265-05:00</updated><title type='text'>Game Dev &amp; Crunch</title><content type='html'>Everyone crunches. If a managers says they don’t, or that ‘it’s not that bad’ they are lying. And you should kick them in the face for that. (I’m kidding… not really..). Crunch is essential to our industry. But, it’s not just us. Every industry has the overtime, and the late hours. We’re no different, we just have a cooler catch prhase to describe why we can’t have a social life for the next month.&lt;br /&gt;&lt;br /&gt;Crunch is a direct result of management. Let me explain.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;If your milestone goals are too large for your team, you crunch.&lt;/li&gt;&lt;li&gt;If personnel hasn’t been allocated correctly, and nothing is done, you crunch.&lt;/li&gt;&lt;li&gt;If you have another demo in a month, you crunch.&lt;/li&gt;&lt;li&gt;If you don’t have enough talent to do the job, you crunch.&lt;/li&gt;&lt;/ul&gt;All of the above reasons are directly controlled, and a result of management. They control the goals for the milestone, personel allocation, demo schedules and focus, and whom is hired, and how.&lt;br /&gt;&lt;br /&gt;Note the lack of “if X happens, MANAGEMENT crunches”&lt;br /&gt;&lt;br /&gt;To be honest, we are talented individuals (well… most of us…) that can get our jobs done, and ensure things work on time. Most of the time though, this isn’t the case, and the management calls CRUNCH!&lt;br /&gt;&lt;br /&gt;Overly long crunches are a sign of a bad company. I would say anything longer than a month is just un-necessary. And in reality, shows that management really doesn’t care much about its’ personnel.&lt;br /&gt;&lt;br /&gt;Tips to survive crunch:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;br /&gt;Showstoppers take top billing. Not all bugs are created equal. If there’s anything that’s keeping any other member of the team from doing there job, then that should be handled first. Trust me, the worst thing to hear is ‘well, I couldn’t work because I was waiting on you.” Also in this category is any fatal bugs that make the game un-playable.&lt;/li&gt;&lt;li&gt;Polish is essential. If you’re in a demo crunch (not just a standard, “no one will see this but us” crunch) then you’ve got to know that there’s about to be people looking at your game, tearing every piece of it apart. Take the attention needed to address polish points before moving on to anything else. Trust me, no one will notice that your exportation code runs 20 seconds faster, but they will notice that slight, 0.5sec jitter between animations on your infantry..&lt;/li&gt;&lt;li&gt;Work the hours everyone else does. If you’re like me, you work the hours you choose, because they fit your schedule and life style. But, this doesn’t fly during crunch. You work what everyone else works, or you can be in a world of hurt. If you leave for the day, and something breaks, everyone WILL notice you’re gone. Even if it’s not your fault! Make sure management sees you pounding away at your work. Stop for food breaks (hopefully provided by the company) and take a point to talk to the producer &amp; manager about how the crunch is going. It’s sometimes tempting to finish your work for the day and head out; be warned, as soon as you do this, something will break, and it’s your fault.&lt;/li&gt;&lt;li&gt;Expect the freakout. It always happens. Some high-strung individual is over-stressed about the milestone, and decides that you’re the person whom is responsible. Try to remember that people in crunch, are not normal people. They are some form of mutant zombie, fueled by caffeine and compiler errors. Try not to get sucked into a trivial yelling argument, or debating stupid items. Keep your eyes on the milestone. After all, at the end of the day, dealing with these problems only detracts you from getting your job done.&lt;/li&gt;&lt;li&gt;New features aren’t that important – If you have a 12 day crunch, and it will take you 4 days to get a new feature done, it’ll take 5 days before anyone else notices or uses it. On top of this, expect a lot of ‘new’ features to show up during crunch. For some reason, people like to brainstorm with your time when they are under the gun. To this extent, find out what is REALLY needed for the milestone, and try to concentrate on the big features. If it’s worth the risk of introducing new bugs, breaking the pipeline, and generally screwing everything up, then go for it. Otherwise, you might want to take a rain check until after the crunch is over.&lt;/li&gt;&lt;li&gt;If you have time, try to do a pre-crunch. The entire development process takes a beating during crunch. So much so, that it will flesh out bugs you never though possible. And trust me, there’s nothing more stressful than having a show stopper that completely makes the game un-playable, or keeps the editor from working. If you can, try to handle some of these high-priority issues the week before crunch begins. Tackling things like memory issues, general performance, and overall stability ahead of time will run miles during the crunch, as it will improve the performance and output of everyone on the team. Not to mention keep your plate a little lighter.&lt;/li&gt;&lt;li&gt;Let your family know you love them. This is for all you married guys out there.. I try to buy my wife flowers before crunch, and after crunch. To be honest, we are willing to work for an unhuman amount of hours because we love what we do. Most spouses don’t agree with that amount of work though. The pressure of crunch is always magnified when you throw home problems into the pot as well. It’s hard to concentrate on the task at hand when you’re mad at your spouse because they didn’t clean out the dish washer last night..&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;~Main&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1197137313991855034-6726577829123043811?l=mainroach.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/6726577829123043811/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1197137313991855034&amp;postID=6726577829123043811' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/6726577829123043811'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/6726577829123043811'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/2007/08/game-dev-crunch.html' title='Game Dev &amp; Crunch'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1197137313991855034.post-5348860252861042793</id><published>2007-08-26T09:47:00.000-05:00</published><updated>2011-09-15T09:47:48.748-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><title type='text'>Algorithmic Dynamic Range</title><content type='html'>Making a game is about compromise, and specalization.&lt;br /&gt;&lt;br /&gt;Let me expand:&lt;br /&gt;&lt;br /&gt;You often can't use the algorithm you'd like to use, because you have some constraint specified by some external force that you have no controll over. (memory, perf, boss, wife....) This is where compromise comes in. How much of the algorithm can you sacrifice in order to make it work within the constraints, and still achieve its goal? This is not an easy question. Often, you have the answer, and end up haveing to change the answer 3 months down the line due to a change in constraints.&lt;br /&gt;Compromise is a good thing however, as it lets you REALLY determine what your algorithm is doing, and what it needs to survive. This sort of system can be developed to expand later on, to add bells and whistles to do other things, when you have the headroom to do so.&lt;br /&gt;&lt;br /&gt;This is where specalization comes in.&lt;br /&gt;&lt;br /&gt;When I say 'dynamic range' i'm not talking about your standard HDR talk. I'm talking about a moving range of algorithms that all accomplish the same thing, but handle specific data sets to accomplish it.&lt;br /&gt;&lt;br /&gt;For example, lets say you have a program that sorts a list of numbers. The numbers can be given to you in any fashion, and continue to be added later on.&lt;br /&gt;What sort algorithm would you use? I think we all know by now that no ONE sort works for everything. But rather different sorts for different tasks.&lt;br /&gt;So, to begin this process, you may write one sort to rule them all, then start specalizing sorts based upon input (ie RADIX sort works great for floats, but it's not as good as quicksort for huge data sets w/ ints) This is what i mean when i say 'dynamic range'&lt;br /&gt;&lt;br /&gt;You'd be suprised how often these special case situations come up in video game development.&lt;br /&gt;Almost always dealing with your data sets, you're constantly fighting the battle of specalization of processing of your data to save memory and increase perf. Why create 3 channels of color when only 1 is used for meshes X,Z,Y,Q? Now, 3 channels are used for ABCD, so you need it there. The rendering of these two differences is important as well, you can create a fast path that renderes the 1 channel texture faster than the 3 channel. So already, you've got a dynamic range system, that, based upon the input will load, sort, operate, and render differently than it's neighbor.&lt;br /&gt;&lt;br /&gt;This is a good thing&lt;br /&gt;&lt;br /&gt;Why?&lt;br /&gt;&lt;br /&gt;Well, because with a large amount of dynamic range, it makes it easy to look at what 'average' is, and makes it even easier to define what 'worse' and 'best' is.&lt;br /&gt;Best case scenario, Every object in the world has 1 channel textures&lt;br /&gt;Worst case, every object has 3 channel textures&lt;br /&gt;Well, we don't have enough memory for everything to have 3 channel, but we can make a compromise that will allow 50% 3 channel, and 50% 1 channel. And shit, while wer'e at it, the artsits are asking for specific 2 channel textures to use on a few special places.&lt;br /&gt;And, if we can find some time in the scedule, we can write a compressor that will make our 3 channel textures take up as much memory as our 1 channel textures, and allow us to have more of them&lt;br /&gt;&lt;br /&gt;Now it's a ballgame folks.&lt;br /&gt;&lt;br /&gt;This idea should be kept in the forefront of your mind while you're programming a system. One algorithm hardly ever works. Instead, break your algorithm down into discrete components that you can understand, and swap between easily. When you do this, you not only give yourself a greater range to drop your perf metrics in, but you also make it easier to enhance perf in any specific branch of the algorithm. (If there's 4 channels, i can make an optomization that it'll run 20% faster than a 3 channel etc..)&lt;br /&gt;&lt;br /&gt;Getting back to it, "Know thine data"&lt;br /&gt;and "understand thine algorithms."&lt;br /&gt;&lt;br /&gt;~Main&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1197137313991855034-5348860252861042793?l=mainroach.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/5348860252861042793/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1197137313991855034&amp;postID=5348860252861042793' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/5348860252861042793'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/5348860252861042793'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/2007/08/algorithmic-dynamic-range.html' title='Algorithmic Dynamic Range'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1197137313991855034.post-757501501984489985</id><published>2007-08-24T09:45:00.002-05:00</published><updated>2011-09-15T09:46:43.226-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><title type='text'>Look under the hood</title><content type='html'>I find sometimes that it's pretty interesting to view the disassembly output from my compiler.&lt;br /&gt;&lt;br /&gt;I usually find this interesting especially when i've found that a particular section of code is taking up 500% of my alloted perf.&lt;br /&gt;&lt;br /&gt;So what do i usually find?&lt;br /&gt;&lt;br /&gt;I did a nice little test today that mirrored a class I had written some time ago to access bits in a stream of __int64s. This class does a great deal of methods. I can set single bits, or spans of bits, as well as any sort of standard list queary that you'd expect (findFirstOfType, findLastOfType, giveTypeRatio, etc etc). My test created the same class, but instead of using__int64s with bitwise operations and logic, i instead, made a bitfield struct, w/ 64 members, all 1 bit long.&lt;br /&gt;&lt;br /&gt;struct int64Bitfield&lt;br /&gt;{&lt;br /&gt;bool _00:1; bool _01:1; ......bool _63:1&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;I then modified the class to do the same operations, but access this class like i would any other structure. There's some things that cause difficulty, like trying to do a bitwise operation on a bitfield (it gets tricky!). What i was testing for, was compiler output. I actually wanted to see what the compiler was generating, to see how far off my custom solution was.&lt;br /&gt;&lt;br /&gt;I was shocked, and appauled. (and a little turned on...)&lt;br /&gt;&lt;br /&gt;What i found, was that simple probing of the bitfield churned out LESS instructions on the whole, vs my powerPC intrinsic heavy-bitwise function using version.&lt;br /&gt;&lt;br /&gt;Dramatically less.&lt;br /&gt;&lt;br /&gt;What did I do? Well, i tabled it for now. I didn't have time to do a full perf analysis on the running functions, and it's always hard to look into how many cycles that chip-specific intrinsics are actually taking up without a profiler.&lt;br /&gt;&lt;br /&gt;What i learned from this though, is an important lesson that i've been hearing from a great deal of PS3 developers : Write your own compiler.&lt;br /&gt;&lt;br /&gt;What???!!! How could you even suggest this? Well, there was a couple reasons that the bitfield specific version of the class produced less number of instructions than my intrinsic version.&lt;br /&gt;&lt;br /&gt;1) Bitfields have built in explicit knowledge of how they need to work. For instance, accessing the 0th bit in a bitfield of 4, the compiler knows that it only needs to do a andi r3, r1, 128. Now, you'd think that by generating the same sort of code in C++ that you'd get the same results. But, you'd be wrong!&lt;br /&gt;&lt;br /&gt;#define cHighBit 128 //0x80 h&lt;br /&gt;bool k = charVal &amp; cHighBit&lt;br /&gt;&lt;br /&gt;You'd think that cHighBit would be constantly loaded in, and replaced everywhere by the value 128. BUT in some instances, this isn't the case! Rather, in some instances, the value 128 has to be loaded into a register, then used from there! This requires a lbz r1, d(rA) before being able to do the andi r4, r2, r3. although this is a really small example, imagine what's occcuring during a great number of temporary variables. Lesson : You may be generating more instructions than you think.&lt;br /&gt;&lt;br /&gt;2) There's a problem with c++. Mainly that it's abstracted from the code that actually runs the goddamn box. You can code away in c++ land, making all these nifty functions and systems, all the while, blissfully ignoring the fact you're killing the cache, and overloading the memory stack.&lt;br /&gt;You don't really know you're doing it until you see perf drop to it's knees as much as your mom did in college. There's no feedback as to HOW bad your code really is, or even WHAT is making it so bad! Now, go down into assembly land, and wow! Look at how much information you're getting! You can visually see that you're thrashing your registers loading in all those temporaries, or that you're causing cache misses all over the place. Basicly, you can see the pulse of the actual system.&lt;br /&gt;&lt;br /&gt;So what i've been hearing going on, is that some developers are either writing all their PS3 code in straight C, or they are writing their own compilers to generate code that's friendly to how the PS3 works. I like the idea of writing your own compiler honestly. Yea, it's a great deal of work, but you can harness so much more from the hardware! Imagine actually being able to define blocks of code that automatically get thrown into a threadpool behind your back, and async. comm back to the main thread w/ the proper information, all in assembly! You, of course, would just have to define start/stop tags for the whole thing, but you get the point.&lt;br /&gt;&lt;br /&gt;Basicly, when you're in perf-critical land, abstraction is your fucking arch-nemisis. This is why platforms like .NET are considered a joke to the video game community. Yea, you can write a graphics engine in C#, and it'll look the same, run at 80% of the regular perf, and you can use all theri nifty frameworks, but you loose two of the MOST important concepts in writing fast code: Know what your memory is doing, and know what your assembly is doing.&lt;br /&gt;&lt;br /&gt;Abstracting your language up multiple levels does great things for the human understanding of programming. But that's not always how the machine thinks. Writing a custom compiler is a great idea, because you can taylor make your output machine code to match what the hardware would expect to do. Along with tons of safety nets that other PC compilers would completly glaze over about. (For instance, how about an automatic pre-cache update when the compiler recognizes that a long block of memory is about to be linearly accessed? That'd help your perf wouldn't it?)&lt;br /&gt;&lt;br /&gt;Am I saying that you should program in fortran? No. And infact, you'd be a fucking idiot if you did. C++ is a great language, that offers you an exceptional amount of power. BUT you have to be willing to explore, and understand, all the innerworkings of what it's doing, in order to truly harness that power to do your bidding. Code highlevel, think lowlevel is a great motto here.&lt;br /&gt;&lt;br /&gt;We should all understand WHAT our assembly is doing, and even more important, what the HARDWARE is doing too. Really, if you think about it, programming on a console without knowing what your code is doing to the hardware is pretty stupid. (Like fucking some random chick without a war-helment.) You can really parallel it to blindly shooting at a target, hoping to understand how to hit the bulls eye. "Well, i can't see, but i THINK i was a little to the left of the target that last shot.."&lt;br /&gt;&lt;br /&gt;When you're blindly wading through code like that, it's time you look under the hood, and come face to face with how you're raping your console.&lt;br /&gt;&lt;br /&gt;~Main&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1197137313991855034-757501501984489985?l=mainroach.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/757501501984489985/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1197137313991855034&amp;postID=757501501984489985' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/757501501984489985'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/757501501984489985'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/2007/08/look-under-hood.html' title='Look under the hood'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1197137313991855034.post-2146138159212460512</id><published>2007-08-22T09:44:00.000-05:00</published><updated>2011-09-15T09:45:21.049-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='books'/><title type='text'>Types of books</title><content type='html'>As far as i'm concerned, there's 2 types of programming books:&lt;br /&gt;&lt;br /&gt;1) The kind that make me crazy&lt;br /&gt;These books are usually great lexicons of useful algorithms and collections of great know-how. These things are the ones that you constantly go back to for info. Why do they make me crazy? Because once you read through one of these books, your brain starts to scour for how you can actually USE all of the information that you've just absorbed. I'm always saying 'well, someone else is going to use it.. i should too.' Most of the time that's just paranoia, other times, it's legit. All in all, these books contain a great deal of information that i can't hold in my brain at one time, and have to keep going back to.&lt;br /&gt;&lt;br /&gt;2) The kind that make me sane&lt;br /&gt;These books are written by the vetrans of the industry. That is, people whom have been around the block a few times wrt programming, and have some generally good insights on how all the information from book type 1 can be, and should be used. These books generally give me the vision of understanding of what the hell i'm really doing on a daily basis. I can see the forest, and the trees.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;There's really 2 other types of books that I classify, but aren't as important.&lt;br /&gt;3) The books that interest me, but i don't get around to reading because they are of a subject matter that i'm not in a place to master just yet.&lt;br /&gt;4) Books that bore the shit out of me, and i generally have no desire to look at. These books are also considered 'copiers' That is, how many 'C++ tricks!' books can you really read before they all start to sound the same? One of these books is nice, but 5? oh come on!&lt;br /&gt;&lt;br /&gt;~Main&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1197137313991855034-2146138159212460512?l=mainroach.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/2146138159212460512/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1197137313991855034&amp;postID=2146138159212460512' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/2146138159212460512'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/2146138159212460512'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/2007/08/types-of-books.html' title='Types of books'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1197137313991855034.post-3289714787041169311</id><published>2007-08-21T09:43:00.001-05:00</published><updated>2011-09-15T09:44:39.668-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><title type='text'>Walking Lists</title><content type='html'>Walking a list is a common practice for every programming task. Even the most boring, trivial tasks requrie you traverse some sort of grouping of data in order to find data.&lt;br /&gt;&lt;br /&gt;Now, contrary to what your CS1 teacher taught you, this is not as simplistic as creating a FOR loop and throwing in some IF statements. Lets take, for example:&lt;br /&gt;&lt;br /&gt;You're creating software for a building with 1 million rooms. Each room has 1 light swtich in it. You need to create software that holds the states of every lightswitch in the building : ON, or OFF.&lt;br /&gt;Lets say that at any time, you ned to traverse the list, and find the first ON swtich. What's the most memory efficent, and performance efficent manner to do this?&lt;br /&gt;&lt;br /&gt;cs 101 : for(i=0;i&lt; 1 million;i++) if(lightSwitches[i]==on) return i;&lt;br /&gt;what works : Uhh, it works...&lt;br /&gt;what doesn't : What if there's no ON element? we'll walk 1mm objects. That sucks.&lt;br /&gt;&lt;br /&gt;Better idea?&lt;br /&gt;cs 102 : Keep a structure of your data that allows you to traverse it in some sort of faster, more efficient manner.&lt;br /&gt;what works : reduces time to find an object greatly (depending on the algorithm)&lt;br /&gt;what doesnt : usually requires more memory to keep all the information for relationships. Also, takes more time to process the data in recursive systems. (this is usually offset by the speedup of faster traversal)&lt;br /&gt;&lt;br /&gt;Better idea?&lt;br /&gt;cs 103 : Keep a 2ndary listing of data that will allow you to immedialy identify the first of a node you're looking for. Think of it as a FIFO structure for your data.&lt;br /&gt;what works : finding the first of a node, REALLY FAST.&lt;br /&gt;what doesnt : more memory again&lt;br /&gt;&lt;br /&gt;We can keep going on like this forever. Read any ALGORITHMS book by Knuth, and you'll see what i mean.&lt;br /&gt;&lt;br /&gt;There are some things though, that programmers need to be aware of before just writing a simplistic walking algorithm.&lt;br /&gt;&lt;br /&gt;1) Cache efficiency&lt;br /&gt;Most PC programmers don't have to be aware of this, but console programmers do. Processing chips come with a temporary area of memory called a 'cache' that data is stored into upon access, and kept there until it's time to free it again. What the cache is for, is to improve seek and read times over long amounts of data access by frontloading all that time at first. Any subsiquent accesses check the cache first, before going back to main memory. When your controller goes to the cache to find a piece of data, and it's in the cache, this is called a 'cache hit' This is a good thing! reading memory from the cache is super fast! When you go to the cache for data, and it's not there, this is called a 'cache miss' THIS BAD! GROG HATE THIS! Why? Wellll, because of the time to access data from main memory is usually pretty slow, and that data has to be loaded into the cache. If your cache is full, you also incur the overhead of determining what cacheline to free, and can overwrite something that another function will need in a few milliseconds, thus incurring a cache hit there. (see my previous post about LRU/MRU efficiency for more on this) Planning for this occurance is actually not too difficult, you just need to be aware of your memory access patterns, and ensure that you're doing prefecting correctly.&lt;br /&gt;&lt;br /&gt;Firstly, ensure that the data you're accessing can fit into a cacheline. On the 360, a cache line is 128 bytes. This means that you can load that data into the cache, and access all of it before incurring a cache miss again. So, if you have a structure that's 64bytes, you can only fit 2 of those in a cacheline before you get a miss. This degenerates REALLY quick when walking structures of these types. Just like the inibitions of your sister when she's out with that guy who has a fast car and 'nice hair.' slut....&lt;br /&gt;&lt;br /&gt;There's some things that make sense about this, that can help.&lt;br /&gt;1) Ensure your structures are aligned properly. Any sort of padding inserted into your structure will add un-needed bytes into the structure class. This takes up precious space in your cache, and can cause a great deal of problems. (I won't go into all the details on how to ensure alignment and padding, you can google that)&lt;br /&gt;2) Try to keep your structures as small as possible. Infact, if needed, break down your structures into smaller data types. Think about 'HOT' and 'COLD' sets. That is, a HOT set is a group of data in your class that's accessed frequently. Say the state, or number of elements it contains. These things are constantly looked up in list walks. the COLD set is things that are only looked at every now and again. If you have a 64byte class, but 40bytes of it can be considered COLD, then it would help you to instead, place all the HOT data into your list, with linkage back to the main data container class. This way, you only have 24bytes per struct of data to queary as you walk the list, and can fit more of these data classes into memory.&lt;br /&gt;3) Try to create 'Structures-of-Arrays' instead of 'Arrays-of-structures' This is just the next stage of (2) above. If your'e not accessing all the data in your HOT set at the same time (ie you'll only ever check the state, OR the number of containments, but rarely both at the same time) it would be smarter to make a list made entirely of STATE, and a seperate list entirely of NUMCONTAINERS. That way, you can fit even MORE information into a cacheline, and you're not wasting cycles moving your memory pointer around for data you don't want.&lt;br /&gt;&lt;br /&gt;Of course these optomizations come with some engineering cost, and maybe a bit of overhead in memory for linkage or explicit defintion of workings of the function, but in general, these are the things that can GREATLY improve your coding speed.&lt;br /&gt;&lt;br /&gt;2) Memory fragmentation.&lt;br /&gt;True, this is more like a memory management issue, but it is important to know, none the less.&lt;br /&gt;By now, everyone should know that dynamic runtime allocations are the DEVIL. Why? Well, every time you call 'new' the memory allocation function trots off into memory, finds a free spot, and gives you memory back that you asked for. Over time, this can cause lots of spaces to be freed, or used, giving the physical apperance of a cratered surface of the moon. What starts to occur, is that when you've got lots of little pieces of memory free everywhere, and you go to allocate a large block, well, the memory has to defragment in order to accomidate your request.&lt;br /&gt;&lt;br /&gt;Not only that, but lets think about jumping around in memory. We already know that when you access spot X in memory, you can get X + 128 in the cache. Well, what if the next data element you're looking for isn't within the next 128 bytes? What if its 2 mb away in memory somewhere? Well, then you have to jump all the way there, cause a cache hit, and load the data. Memory seek times usually aren't that bad, but it can add up the more you start bouncing around. Lets say you've got a linked list, that will dynamically allocate over a number of frames. Well, you've got no insurance that those nodes are conguious in memory. And as you walk that list, you'll find yourself jumping around everywhere, causing cache misses, and incurring perf burden all over the place. This really comes to light in places like file IO, where you have to incurr seek time costs for every read you do off the disk. Especially if you're reading from slow-as-shit optical disks!&lt;br /&gt;&lt;br /&gt;What's better? Known thine data! It is much better to allocate large blocks of memory up front, and manage them yourself over time, rather than constantly rely on dynamic allocations and potentials for memory fragmentation. There's some hueristics that go along with this, namely 'how much do i need to allocate before i run out of room, and how do i handle that?' But those are topics for a different post. What you need to know now, is that handling your own memory by hand is tricky, but can cause massive perf and mental wins over time.&lt;br /&gt;Especially for console development, or large project settings. It gets a great deal easier when you know that your AI system will ONLY ever use memory between addresses 0x61227372 and 0x81227372. So, you know if for some reason your XML system is trying to read memory at location 0x71111111, you've got a problem (unless you're talking to the AI). Not only this, but it maks cleanup a great deal easier. Linked lists are the worst for this, because it takes a great deal longer to free tons of tiny blocks, than it does one big one.&lt;br /&gt;&lt;br /&gt;3) PRECACHE&lt;br /&gt;if you know your memory is conguious, and you know that you're potetially going to have to walk to the next 128byte block, go ahead and issue a precache command on the block to get all the pipes churning so the data will be loaded in there by the time you get there. The reason cache misses hurt so bad, is that the thread your on WAITS until the cache data gets loaded, then returns the data requested. If you precache, then the cache can start loading while your thread is doing it's dirty business. This is good shit.&lt;br /&gt;&lt;br /&gt;4) PRECALCULATE&lt;br /&gt;If, for some ungodly reason, you need to sample a calculated variable while you walk a list (say you need to find the smallest value of a grouping, that requires some math to be done every time its sampled) it's better to NOT do that every time you touch that array element. Instead, precaclulate that stuff as much as you can, even if it's only for this one frame. Remember, list walking is seldom ever a 1 time thing. Most of the time, you'll have to search the same list, a number of times, for different criteria, for different results. Having to caclulate that data every frame, wow, that can suck dick.&lt;br /&gt;&lt;br /&gt;So, all in all, make sure that you keep some of these things in mind when designing youre classes and your list searching structures. Look around your code and you'll be suprised how many violations of these patterns you're doing. And as always, don't be afraid to profile your code. it's always good to know how fast an algorithm is in relation to how fast it could be with the proper attention.&lt;br /&gt;&lt;br /&gt;~Main&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1197137313991855034-3289714787041169311?l=mainroach.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/3289714787041169311/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1197137313991855034&amp;postID=3289714787041169311' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/3289714787041169311'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/3289714787041169311'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/2007/08/walking-lists.html' title='Walking Lists'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1197137313991855034.post-6365473724955669306</id><published>2007-08-18T13:41:00.003-05:00</published><updated>2011-09-15T09:42:32.941-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><title type='text'>The importance of visualizing</title><content type='html'>Debugging is a really crummy process. It's inherit to what we do of programmers. We, as flawed organisim, generate flawed logic and processes that rear their heads into your code, causing us nothing but premature balding, and grief.&lt;br /&gt;&lt;br /&gt;As thinking creatures, we construct mental models in our mind, which we visualize as a series of logical steps and outcomes.&lt;br /&gt;&lt;br /&gt;This is why visualization is so important. Ensuring that you're generating proper information from your systems to actually create a visual representation of what's occcuring can help millions of steps faster than just running the algorithm.&lt;br /&gt;&lt;br /&gt;Infact, imagine NOT having a debugger. Image not having even a visualization of basic steps for your code paths. How hard would it be to debug anything in your code?&lt;br /&gt;&lt;br /&gt;Now, there's not 100% definition about how much visualization you need, or when you should spend time implimenting it. IE you should spend the first 70% of your time, putting an algorithm together, and only until you need to start profiling, or a nasty bug comes up, do you need to visualize everything. BUT the main point here, is that stopping a debugging process to put in tools to help w/ the debugging process, is actually pretty valuable. Mainly because the same tools that you put in for the process can help you to do profiling characteristics.&lt;br /&gt;&lt;br /&gt;So, make sure that next time you find yourself going "what the hell is this thing doing?" answer with " I don't know, let me look."&lt;br /&gt;&lt;br /&gt;~Main&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1197137313991855034-6365473724955669306?l=mainroach.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/6365473724955669306/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1197137313991855034&amp;postID=6365473724955669306' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/6365473724955669306'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/6365473724955669306'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/2007/08/importance-of-visualizing.html' title='The importance of visualizing'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1197137313991855034.post-665432787890399360</id><published>2007-08-18T13:41:00.001-05:00</published><updated>2011-09-15T09:40:50.379-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='virtual memory'/><title type='text'>Virtual Memory Management</title><content type='html'>Like the average programmer gives a hoot. But virtual memory handling is a pretty big deal.&lt;br /&gt;&lt;br /&gt;Especially w/ video games.&lt;br /&gt;&lt;br /&gt;So let's talk about low memory systems. You've got a budget of X texture memory required to render the visible scene. (we're not talking about the full memory required to load that scene into memory, or bus throughput) But, we've only got X/3 space available for this scene. Believe it or not this is actually a really important problem, even on PCs!&lt;br /&gt;&lt;br /&gt;Why is this important?&lt;br /&gt;&lt;br /&gt;Next gen video games will rely heavily on multithreaded systems. For rendering, file IO, network communication, AI.... you name it. It makes sence then, that systems that take full advantage of Asyc communications between these threads will be of more benifit and flexibility than those that do not. Infact, it'll start progressing to the point that if you DON'T enable your systems to be aware of threading and streaming,then you're actually handycapping your entire engine.&lt;br /&gt;&lt;br /&gt;So, that being said, back to our goal here : Working with a cache.&lt;br /&gt;OS programmers have been dealing with this problem for years, and much to my chagrin, know a great deal more about it than I do. They call it 'Virtual Memory Management' and for the sake of confusion, I'll keep to their terminology. How i'll be using it though, is the way that game programmers have been using it for a number of years now : Active texture slots.&lt;br /&gt;Let's say you're working in an pre-vertex shader system. You've got 8 texture slots available to you, and all of your objects on the screen are single textured, referencing some pool of textures on disk. So, in a typical FPS view, lets say you have 20 objects, with about 12 textures used for these objects. In a neive way to render, you would loop through all the objects, set the active texture, render the object, and repeat. This leads to bad perf wrt the API, mainly due to the heavy lifting of all the state changes. A smarter approach would be to sort the objects by texture, so that you minimize the number of state changes that occur over time. This works qutie well for the given example. So, lets try something a bit more challenging.&lt;br /&gt;&lt;br /&gt;Lets say you have 20 objects, and 20 different textures.. Oh shit! Now what? Even with the accelerated view above, you'll cause worst case perf. The answer to this, that many people figured out quite some time ago, was that it's smarter to fill the active texture slots of the GPU with textures that are going to be used, and allow the objects to reference the different slots, instead of just slot 0 all the damn time. This is known as texture cache managment.&lt;br /&gt;So, you would take the first 8 objects. load all 8 textures, then render the 8 objects. Reload 8 textures from 8 new objects, then render those 8 objects. Rinse, recycle, repeat. This of course is worst case scenario, where we have unique textures everywhere, and nothing can be reused. Although, we can save a great deal of perf from this, in the form of preservation. That is, a coherience between frame N and frame N+1. If we can organize our textures in the cache, so that at the end of this frame, we keep around textures that are going to be used next frame, then we decrease the amount of swapping that must occur next frame, and lower the overall perf hit for our system.&lt;br /&gt;&lt;br /&gt;The question is, well, how do we do that? That is, how do we accuratly determine what textures to keep in the cache over time, and what ones we should just dump by the curb? IE how do we pick proper metrics to choose a 'victim' page of memory, when the cache is full. Believe it or not, this is a much harder problem then it sounds. Factor into account the fact that each 'thrash' (replacement of a victim page w/ a new page) has a specific cost associated with it. And there's another cost that the victim texture you choose, might be needed again next frame, which will cause another thrash in the future.&lt;br /&gt;&lt;br /&gt;This is where all those stupid, crazy ass virtual memory algorithms you learned in your OS class in college come in to play. Believe it or not, there's some really good engineering algorithms in there. Let's talk about a few, how they help our texture cache system, and some ideas.&lt;br /&gt;&lt;br /&gt;OPT: this ofcourse, is the best algorithm ever. Your mom boned this algorithm, and created your brother, who now bangs supermodels and gets free money. OPT is theoretical. OPT has the ability to know what texture is going to be used the FARTHEST AWAY in the future, and chooses that texture as the victim when a thrash occurs. This is what we're hoping to move closer too.&lt;br /&gt;&lt;br /&gt;MRU: Most Reciently Used. MRU replaces the page that hasn't been used for the longest amount of time. So when a texture is loaded into a cache page, you set a frame counter to it. When a thrash occurs, you walk the current textures in the cache, and find the one with the oldest frame count. Then you slit the guy's throat and replace him. MRU does some cool things, but is prone to MASSIVE texture thrashing. That is, you'll always have an oldest texture in the cache, which means that unless you're careful, you can actually clear the entire cache every frame. Not exactially good shit.&lt;br /&gt;&lt;br /&gt;LRU: Least Reciently Used. LRU replaces the page that was just replaced. That is, the youngest texture in the frame. LRU has the same problems of MRU (potential to replace the entire cache) but one thing it does have as an advantage, is that it creates a scratch pad. Say for instance you only need to thrash 1 texture spot between 2 textures for the next 10 frames. Well, MRU would thrash every texture in the cache over those 10 frames. (becauase as it inserts, it becomes the youngest) LRU though, would look at the latest replacement, and victimize that. In essencine, this keeps you from thrashing ALL pages, to just thrashing one page. Which, as far as memory cache is concerned, is a good thing.&lt;br /&gt;&lt;br /&gt;There's been some good descriptions about how a MRU/LRU hybrid is a good approach. Basicly, it works in the form that you use MRU most of the time, until you reach the point that your'e needing to thrash every frame (or the youngest texture in your cache, was created last frame) At this point, you switch to LRU to keep from re-creating the entire cache over the next X frames.&lt;br /&gt;&lt;br /&gt;COST : An addition to these algorithms is a cost based metric. That is, you determine how much this texture will COST you to reload it into the cache. So basicly, what this turns into, is that you're more worried about performance cost of a thrash, as opposed to coherience between frames. When a thrash occurs, you find the cheapest texture in the cache, and get rid of it. This has the metric that it COULD create a scratchpad system (if you're constantly bringing in low cost textures) or it could thrash the whole damn thing (if your'e brining in high cost textures.) The good news is that this EVENS OUT over time. That is, that over time, you keep those textures which cost the most to thrash, in memory, and not thrashing. This is a good thing. Now, you can put this on top of LRU/ MRU if you desire. That is, find me the oldest texture, and use that as a multiplier as to the cost of the thrash.&lt;br /&gt;&lt;br /&gt;AGE: One algorithm I really like is a log system. That is, we use the history of this texture to predict the future. When a texture gets placed into the cache, we mark (for a certain number of frames) how many times this texture is used. When we go looking for cost, we evaluate the number of frames it's been used, over the number of frames in our analysis window. This gives us an 'Age percent cost' which allows us to evaluate how imporant this texture is to our scene.&lt;br /&gt;IE if you have a texture that's been visible 70% of the last 100 frames. It's got a high chance that it's going to be visible next frame too. On the other hand, if you have a texture with a 10% APC, then chances are it just became visible, or is on the edge of your view frustum.&lt;br /&gt;&lt;br /&gt;What I like about AGE is that it gives a number of implict benifits, that i don't have to code myself.&lt;br /&gt;1) It biases Old textures. That is, forces textures to PROVE that they are needed for the scene. And once they have, they keep them around. Once an APC gets above 50%, it gets really hard to release it from the cache. This is a good thing!&lt;br /&gt;2) It creates scratchpad. That is, new textures whom haven't proved they are valuble yet, get turned into scratchpads. This is a good thing, as new textures are often results of frustum intersections, and have a high probability to vanish next frame for no goddamn reason at all.&lt;br /&gt;3) It is an NRU scheme. That is, Not Reciently Used. Texutres that might have been visible a high percentage for a short time, could easly shoot up to 50% APC, but then drop out, and slowly work their APC back down over a number of frames. Well, AGE allows you to anaylize this, so that even if the APC &gt; 60%, if the texture hasn't been used in X frames, kill it.&lt;br /&gt;&lt;br /&gt;So, these are just some POV's about this stuff. It's really important to understand this, because more-often-than-not, you're going to run into a sitution when the words 'well, we just don't have enough memory for that' come to play. If you do your homework, your response should be 'well, true, we don't have enough memory to hold it all in memory at the SAME TIME. But if we only have what's NEEDED in memory at one time, then we've got plenty of memory for this!"&lt;br /&gt;&lt;br /&gt;Your boss will love you.&lt;br /&gt;&lt;br /&gt;~Main&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1197137313991855034-665432787890399360?l=mainroach.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mainroach.blogspot.com/feeds/665432787890399360/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1197137313991855034&amp;postID=665432787890399360' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/665432787890399360'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1197137313991855034/posts/default/665432787890399360'/><link rel='alternate' type='text/html' href='http://mainroach.blogspot.com/2007/08/virtual-memory-management.html' title='Virtual Memory Management'/><author><name>~Main</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-hxg0FyL--v4/TrlLRfnvW8I/AAAAAAAAACg/OYS8UwuHEgw/s220/talksmall.jpg'/></author><thr:total>0</thr:total></entry></feed>
