Monday 27 August 2012

Intel Ultimate Coder Challenge - Part Three


The Past

Welcome back to my six part expedition into the development of my feature-packed Ultrabook app called Love Hearts®. 


I hope you had a great week and that you’re ready to go spelunking into the very heart of my code. Last week we took a detailed look at the app design and the development set-up. You may recall my insidious plan (or is that; insane plan), to write my own OpenGL library to replace the one that’s not there on the platform formerly known as Metro.

The Present

This week we’ll be looking at the code, and shedding some light on the challenges you will face when developing for the Ultrabook.  You may recall the project is split into a high level app which we call Love Hearts® and a low level technology we call AGK (www.appgamekit.com). The low level code talks directly to the hardware through an API called WinRT, and for coders who have thousands of lines written for Win32, the journey is far from smooth.

Removing “Windows.h”

The first thing you will notice after creating a blank Visual Studio C++ project for WinRT is that there is no place for “Windows.h” and will actually fail to compile if you try to include it.  Instead you need to pick out the individual C runtime’s you are actually using, and there can be quite a few if your legacy Win32 code base is large. Hours into my conversion, my own header code looked like this:

/// #include “windows.h”
#include “memory.h” // memset
#include “string.h” // strcpy
#include “wtypesbase.h” // DWORD

The list goes on but you get the idea. When you compile under WinRT, your legacy code will have a lot of complains without “Windows.h”.

My first attempt to compile my engine in WinRT

Removing Old APIs

Once you’ve dealt with the basic house-keeping code, you’ll start to stray into more exotic API usage, such as HttpConnect, Threads, Locks, Sound, File and so forth. None of these exist untouched in the new WinRT universe, and new APIs replace each one. With patience, you will be able to find like for like replacement functions for all of them with simple searches on Google. If you are porting your code over however, I highly recommend you use #IFDEF WINRT #ENDIF or platform specific files when you replace legacy code to retain your ability to build standard Win32 applications.

During my engine conversion, I decided to skip porting the ancillary features such as network, sound, sockets and files and jump straight in at the deep end with the OpenGL library.

Amongst the errors, OpenGL code was much highlighted

DirectX and OpenGL are different enough to prevent a like for like conversion, and any developer with sufficient time would have coded an abstraction layer to hide the platform specific differences. My engine code has no such abstraction, just a bunch of files littered with OpenGL calls.

Step one was to re-create the OpenGL header file and create dummy functions for every call. Each function would in turn output that call to a log file so I knew which parts of the library I needed to wrap.

The final step was to empty the engine’s core functions of legacy code by commenting them out, and continuing to do so until the engine compiled successfully.

An Empty WinRT Engine

I used the DirectX 3D application as my template for the new project and left the 3D commands in place for a working reference. I then merged the refactored engine code with the template, and ran as a new Windows 8 app.

Split screen allows two apps to run side by side

Windows 8 has a cool mode which allows me to split the view 75/25 so that I can see the application window running whilst stepping through code. Formerly this would have been a case of using a remote computer, or messing with floating windows, so this was a welcome improvement for developers.  It also gave rise to an important observation that the end users of the Love Hearts® app would also potentially split the view and so this would be an important test case towards the end of the project.

Replacing the template artwork is a breeze

I replaced the stock graphics in the template with my own artwork. There are four assets you can replace and the process is very simple. In the past you had to deal with CUR, ICO and BMP files to form the graphical elements of your executable. With Windows 8 apps, they’re all alpha friendly PNGs with fixed sizes so you just need to hand them over to your artist and get back to coding.

Adding WinRT Meat

It’s no small achievement to have your engine compile and run, but I refused to get to the next blog without mastering the issue of running my potpourri of OpenGL code through DirectX. Getting my engine to render a blank screen without tampering with the original OpenGL code was my next mission.

Deciding to have a little fun, I installed some software on the Ultrabook which would grab a screenshot every 30 seconds whilst I coded the next part. It may give you an interesting perspective on what a typical 12 hour stint looks like when a programmer under the microscope marches into unknown territory.

Along the way I picked up a few tips which might save future explorers into the world of Metro style development a few hours of their lives.

Inside Tip 1: Building WinRT Static Libraries

When building static libraries (LIB) for Metro style apps you need to make a few changes before Visual Studio will let you build the final lib file. Ensure that option /ZW is enabled for your project, but ‘disabled’ for specific files that are ‘C’ only. This option controls whether the compiler handles the new C++/CX extensions such as the new ^ hat operator. You also need to add the following string to your C/C++ command options “/FU Platform.winmd /FU Windows.winmd /AI "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcpackages" /AI "$(WindowsSDK_MetadataPath)"”, and the following to your Librarian command options “/force:allowzwobj”.


Until the final release of VS 2012, you need to hack

Fail to do the above and you will notice your namespace code will not be recognised and the line Windows::UI::Core would highlight the UI element as not known to the compiler.

Insider Tip 2: No run-time shaders


The CSO file is a compressed byte code of the HLSL shader

Metro style apps do support run time compilation of shaders for development but not for deployment, which means if you want your app to consume different shaders at run-time, you can’t.  All shaders need to be pre-compiled and included with your app package which presents something of a problem if your legacy code relies on compiling on the fly.

Insider Tip 3: Don’t put WinRT code in Static Libs

After about four hours of Google research, and putting code all over the place I have come to the conclusion that I will not profit from using a Static Library to place all my WinRT code. Asynchronous operations, which represent every API call in WinRT over 50 milliseconds long, do not perform the same outside of the main application. 


Notice the new syntax .THEN() - parallel here we come!

In fact, they crash in a number of random and completely unfathomable ways. Trying to find posts from fellow coders who have managed to get WinRT code running asynchronously in a static library is amazingly difficult. I am sure it is possible, somehow, but it will take a fresh pair of eyes to solve this one.

A Simpler Approach and Success

After 12 hours it became clear I was not going to win the battle of the static library, and I would have to compile the ‘module’ code directly with the app. This means I cannot distribute a convenient platform LIB for fellow AGK users right away, but it does mean debugging becomes slightly easier.

Just two hours after making this decision I had my first DirectX based OpenGL function. In the code below, I am using a modified version of the VS template CubeRenderer class to contain all my abstracted OpenGL call(s):

void DXRenderer::glClear (GLbitfield mask)
{
          if ( mask & GL_COLOR_BUFFER_BIT )
          {
                   m_d3dContext->ClearRenderTargetView(
                             m_renderTargetView.Get(),
                             tempcolor      );
          }
          if ( mask & GL_DEPTH_BUFFER_BIT )
          {
                   m_d3dContext->ClearDepthStencilView(
                             m_depthStencilView.Get(),
                             D3D11_CLEAR_DEPTH,
                             1.0f,
                             0      );
          }
}

An hour after that I quickly tied the Ultrabook accelerometer to the renderer. After many hours of gorping at crash dialogs, I wanted to treat myself to a little light relief:

void DXRenderer::ReadingChanged(Accelerometer^ sender, AccelerometerReadingChangedEventArgs^ e)
{
    AccelerometerReading^ reading = e->Reading;
          tempcolor[0]=reading->AccelerationX;
          tempcolor[1]=reading->AccelerationY;
          tempcolor[2]=reading->AccelerationZ;
          tempcolor[3]=1.0f;
}

As you might see, the app will now change the colour of the rendered screen when I tilt the Ultrabook right and backwards.


With a single OpenGL command now running under WinRT, the rest should follow quickly. It is fortunate that our Win32 engine is based on shaders, essentially because both DirectX and OpenGL go through pretty much the same process to set-up and then render polygons to the screen. The exciting part about this conversion is that I don’t have to re-factor the original C++ engine code, or create a graphics abstraction layer and carefully align the behaviour with what AGK is doing right now. When I have finished, the WinRT app will be graphically identical to the native OpenGL version, with the small difference that it’s actually DirectX 11.

Making Your Ultrabook Go Ping

One of the features I hinted at last week was the Always On Notification component which could bleep the user’s closed Ultrabook and present them with the app when they open it up. I have no clue what API it belonged to or where to start looking. As an antidote to spending too much time on DirectX, I switched tracks to do some research into this key area.



During my development, I have found the WinRT API reference site hosted by Microsoft to be of great help. The portal (http://msdn.microsoft.com/en-US/library/windows/apps/br211377) gives you an overview of EVERY feature category, and was the starting point of my search. It did not take long to find it, and drill into the page to learn all about it:


Further digging revealed a great article (http://msdn.microsoft.com/en-US/library/windows/apps/hh913756) which explains the process in detail, and provides a good starting point for adding this exciting feature. One thing that needs more research is whether the Smart Connect technology is entirely low-level with no API to call? I’m also finding very little information about the ability to get the device to ‘ping’, ‘bleep’ or ‘scream’ during the device’s momentary dip into consciousness. I do wonder whether I actually dreamed this feature up during one of my fevered imaginings. If there is a way though, I’ll find it!


What I suspected was a speaker (or exhaust port)

The good news is that push notifications are definitely supported in the Metro style, and the code within the client is actually quite simple. The tricky icky part is setting up the cloud service to manage the notifications, and connecting with the Windows Store server to authenticate everything and bring the Ultrabook Start Page to life.

One Final Feature

Not content with writing OpenGL in DirectX, or getting the Ultrabook to sound a claxon while sleeping, I also wanted to tap into the raw processing power hiding amongst the silicon. The 3D graphics used by my app will push the GPU but we needed something to push the multi-core processor too.

The majority of the app logic is pretty sequential and would not benefit from a touch of parallel code, but the built-in games are another story. To this end, we have modified Box2D to run on multiple cores so any time AGK has to process a lot of 2D physics, it will split the solver across all available processors.


AGK Box2D Physics commands - simplicity itself!


This task only took a few days, and the performance benefit on the multi-core Ultrabook was immediate. We have created a small video showing the technology demo we used to test the performance of the optimisation:



When the time comes, I will be able to drop the latest n-core Box2D code directly into our WinRT engine without further modification, thanks largely to the fact that we're writing it in C.

Incidentally, another benefit of writing for WinRT is that the API is largely asynchronous, which means the app does not wait for sections of slow code such as loading, processing and buffer allocation. It will run those sections in parallel and dive straight into the main loop as quickly as possible. This is partly due to the new C++\CX technology which gently prods you to use a parallel paradigm, and in some cases preventing programmers from choosing a synchronous alternative.

The Future

Steve is back this week, which means the next blog will have lots of cool new app content to share. I would have liked to show you the new artwork Peter has produced, but as usual, he’s hoarding the files. I’ll probably get an email this week with a salvo of two hundred new files to climb through. Fortunately, Steve is adept at climbing mountains of art.

With the engine (one command of it) now rendering under DirectX, the rest of the functions should quickly follow. Rather than completely convert the engine, I can select those parts needed by the Love Hearts® app to save some time. Time I can use to add new touch, sensor and notification commands to the app and start testing what I hope becomes the ultimate Ultrabook app. Join me next time when you will see the app actually running under WinRT and tapping into the technology we've developed so far.

More Information

For more information about the Ultimate Challenge, check out the official website at:http://software.intel.com/sites/campaigns/ultimatecoder/

Blog Timelapse

For everyone who likes time lapses, I have prepared a small video showing the entire 14 hour coding session which starts with an OpenGL engine and finishes with a "1 command" DirectX engine. 


2 comments:

  1. I'm really impressed with your writing skills and also with the layout on your weblog. Either way keep up the excellent quality writing, it is rare to see a great blog like this one these days..
    www.coderstech.com
    www.codersiq.com

    ReplyDelete
  2. Thanks for the comments! I will be blogging all the way through 2013 where I am sure to change your mind :)

    ReplyDelete