<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>luminance &#187; 360</title>
	<atom:link href="http://www.luminance.org/tag/360/feed" rel="self" type="application/rss+xml" />
	<link>http://www.luminance.org/blog</link>
	<description>Programming and Game Development - Kevin Gadd&#039;s Blog</description>
	<lastBuildDate>Sun, 02 Oct 2011 00:15:58 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Updating Onscreen Objects / Profiling</title>
		<link>http://www.luminance.org/blog/gruedorf/2009/08/20/updating-onscreen-objects-profiling</link>
		<comments>http://www.luminance.org/blog/gruedorf/2009/08/20/updating-onscreen-objects-profiling#comments</comments>
		<pubDate>Fri, 21 Aug 2009 04:24:39 +0000</pubDate>
		<dc:creator>Kael</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Gruedorf]]></category>
		<category><![CDATA[360]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[profiler]]></category>
		<category><![CDATA[xna]]></category>

		<guid isPermaLink="false">http://www.luminance.org/?p=742</guid>
		<description><![CDATA[One of the problems I started to run into while polishing things up for my contest entry builds was that as my levels grew larger, the game&#8217;s CPU utilization on the 360 steadily grew with them. While PC builds of my game ran smooth on basically all the machines I had access to, on the [...]]]></description>
			<content:encoded><![CDATA[<p>One of the problems I started to run into while polishing things up for my contest entry builds was that as my levels grew larger, the game&#8217;s CPU utilization on the 360 steadily grew with them. While PC builds of my game ran smooth on basically all the machines I had access to, on the 360 the cost of updating all the level&#8217;s objects and entities became quite significant &#8211; most likely due to the 360&#8242;s feeble floating-point performance and lack of out-of-order execution.</p>
<p>The solution to this was, at least to me, relatively obvious: My levels were much larger than the camera, so it didn&#8217;t really make sense to update the entire level every frame.</p>
<p>The first thing I tried to verify this theory was simply hacking it in: Do a check before updating each object to see if it was onscreen. Interestingly, this didn&#8217;t make the game any faster on the 360. Depending on your point of view, this either confirmed or denied my hypothesis: If the problem was simply the cost of all the floating point operations, the cost of doing the onscreen check for each object (since the camera and object bounds were both expressed in floating-point) could have been making the problem worse. Clearly, I didn&#8217;t have enough data to be sure about the right choice to make.</p>
<p>So, I spent a day or so rigging up the necessary infrastructure to be able to profile my game on the 360. Since you can&#8217;t use tools like CLR Profiler or NProf on the 360, I ended up building a very simple frame timing system, and adding an overlay to the game that would show timing data. This let me get a good idea of how much time each subsystem in the game was using, and then I could compare the costs of individual subsystems, and try making changes and seeing how the profile data changed.</p>
<p>Once I had the profiler up and running on the 360, a clear pattern emerged.</p>
<p><a href="http://www.luminance.org/wp-content/uploads/2009/08/01.png"><img class="aligncenter size-full wp-image-745" title="01" src="http://www.luminance.org/wp-content/uploads/2009/08/01.png" alt="01" width="500" height="550" /></a></p>
<p>Updates were consuming a huge amount of CPU time on the 360. While on my desktop, updates basically accounted for no more than 1% of CPU time, on the 360 they actually accounted for more CPU time than rendering &#8211; this was actually a bit of a surprise to me since rendering was definitely the bottleneck at one point on the 360. It seems that at some point along the way, I solved my rendering performance issues on the 360, but didn&#8217;t notice because I had made updates so much more expensive &#8211; one mistake I plan not to repeat was that I went a week or two without testing the game on the 360, since my 360 was not hooked up at the time. During that span of time I made a lot of changes that drastically altered the game&#8217;s performance characteristics, so it was hard to tell what had caused things to degrade.</p>
<p><span id="more-742"></span></p>
<p>Now that I knew updates were expensive, I decided to try and narrow down which object types were the problem. I added profiling markers around specific types of objects, to try and figure out which ones cost the most CPU time to update. After doing that and deploying a few builds to the 360, I found one of my culprits: Water.</p>
<p><a href="http://www.luminance.org/wp-content/uploads/2009/08/04.png"></a><a href="http://www.luminance.org/wp-content/uploads/2009/08/05.png"><img class="aligncenter size-full wp-image-749" title="05" src="http://www.luminance.org/wp-content/uploads/2009/08/05.png" alt="05" width="500" height="550" /></a></p>
<p>While I had suspected that water might be a problem, I was still somewhat surprised by the results; A similar piece of in-game geometry, zones, used similar update code but turned out to have virtually zero update cost at runtime, while water cost a tremendous amount of CPU for very little gameplay impact. The problem turned out to be a subtle difference in how they were implemented.</p>
<p>Zones were inefficient in that every frame, each zone did an obstruction test to see if any entities were inside &#8211; in most cases a zone would be empty, so this was wasted effort. This would have been better implemented by having every entity check for nearby zones, since there are typically far less entities than there are zones. However, in practice this didn&#8217;t turn out to be the problem. The problem was that water built on this logic, and then used it to perform additional work: It did an obstruction test to determine how far the water should fall, and then did another obstruction test to locate any entities inside the water and apply &#8216;flow force&#8217; to them so that the flowing water would push them in a given direction. These two obstruction tests each ended up accounting for a significant portion of the time spent updating the level.</p>
<p>To solve this, I took two steps. First, I reworked zones and water so that they both operated the way I described &#8211; each entity does a check to locate all the zones it&#8217;s within, in a single obstruction test. This reduced the number of obstruction tests I was running every frame by a large amount, and helped reduce CPU usage for water. However, that still wasn&#8217;t enough.</p>
<p>The biggest improvement came from reworking things so that only onscreen objects get updated every frame. Instead of performing a test against every object to see if it&#8217;s onscreen, I decided to build on the partitioning scheme I use for rendering to get a list of onscreen objects, and use that as my list of objects to update. Once I had that working, my performance improved drastically and the game easily ran at 60fps in every part of my levels with CPU to spare.</p>
<p>Of course, doing this introduced bugs. One of the biggest issues is that often you will have important objects just outside the edge of the screen that need to keep updating, like moving platforms or enemies. To solve this, I added two mechanisms:</p>
<p>First, I added a margin around the screen within which objects still continued to update. This meant that an object just barely offscreen would keep updating, and solved the problem of a moving platform or enemy getting left behind as soon as he dropped offscreen.</p>
<p>Second, I built a simple &#8216;update manager&#8217; that maintains a list of all the objects that are currently onscreen. When an object leaves the screen, instead of removing it immediately, the update manager instead sets a timeout, which causes the object to become &#8216;asleep&#8217; within a certain number of frames. As a result, once an object leaves the screen it has a second or two to return to the screen before it falls asleep, which helps with things like moving platforms that are going to move on and off the screen regularly &#8211; since they don&#8217;t spend very long offscreen, they never have a chance to fall asleep.</p>
<p>The update manager also gives me the ability to exclude some objects from updates entirely, by flagging them as &#8216;unable to wake&#8217;, so the update manager knows to never remove them from sleep status. Likewise, it gives me the option to flag objects as &#8216;unable to sleep&#8217; so that they always stay active &#8211; for example, I do this to the player character and his companion to avoid any unintentional bugs that might result from the player remaining offscreen too long (say, during a cinematic).</p>
<p>The update manager has some other benefits, too. Here&#8217;s what it looks like:</p>
<pre>    public class UpdateManager&lt;T&gt;
        where T : class, IUpdateable, IHasBounds {

        public struct Entry {
            public readonly T Object;
            public int WakeCounter;

            public Entry (T obj, int wakeCounter) {
                Object = obj;
                WakeCounter = wakeCounter;
            }
        }

        protected Dictionary&lt;T, bool&gt; _VisibleObjects = new Dictionary&lt;T, bool&gt;(new ReferenceComparer&lt;T&gt;());
        protected UnorderedList&lt;Entry&gt; _Entries = new UnorderedList&lt;Entry&gt;();

        public int SleepTimeout = 30;
        public readonly SpatialCollection&lt;T&gt; Collection;

        public UpdateManager (SpatialCollection&lt;T&gt; collection) {
            Collection = collection;
        }

        public void Update (Bounds liveRegion) {
            using (var e = Collection.GetItemsFromBounds(liveRegion, true))
            while (e.MoveNext()) {
                _VisibleObjects[e.Current.Item] = false;
            }

            Entry currentItem;

            using (var e = _Entries.GetEnumerator())
            while (e.GetNext(out currentItem)) {
                if (!_VisibleObjects.Remove(currentItem.Object)) {
                    // Object not visible

                    if (!currentItem.Object.AllowSleep) {
                        // Object cannot fall asleep
                    } else if (--currentItem.WakeCounter == 0) {
                        // Object fell asleep
                        e.RemoveCurrent();
                        continue;
                    } else {
                        // Object still awake
                        e.SetCurrent(ref currentItem);
                    }
                } else {
                    // Object visible

                    currentItem.WakeCounter = SleepTimeout;
                    e.SetCurrent(ref currentItem);
                }

                currentItem.Object.Update();
            }

            foreach (var newObject in _VisibleObjects.Keys) {
                if (newObject.AllowWake) {
                    _Entries.Add(new Entry(newObject, SleepTimeout));

                    newObject.Update();
                }
            }

            _VisibleObjects.Clear();
        }
    }</pre>
<p>One of the nice things it does in addition to improving performance is that it simplifies my game code &#8211; previously, I had hand-written logic to step through the various object lists (geometry, entities, etc) and update them every frame, and that code differed in subtle ways. The update manager unifies all that, so it kills a lot of duplicated code. Also, by maintaining a unique &#8216;awake objects&#8217; list, it allows me to remove objects from the geometry/entity lists while performing an update, instead of having to wait until the end of the frame, which simplifies some of my entity code as well.</p>
<p>And despite the amount of problems it solves, it ends up actually being quite simple and easy to use. All I have to do to rig up an update manager is point it at a collection of objects and hand it the current camera boundaries every frame.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.luminance.org/blog/gruedorf/2009/08/20/updating-onscreen-objects-profiling/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>One down</title>
		<link>http://www.luminance.org/blog/gruedorf/2009/08/06/one-down</link>
		<comments>http://www.luminance.org/blog/gruedorf/2009/08/06/one-down#comments</comments>
		<pubDate>Fri, 07 Aug 2009 06:44:41 +0000</pubDate>
		<dc:creator>Kael</dc:creator>
				<category><![CDATA[Gruedorf]]></category>
		<category><![CDATA[360]]></category>
		<category><![CDATA[dbp2009]]></category>
		<category><![CDATA[lame]]></category>
		<category><![CDATA[xna]]></category>

		<guid isPermaLink="false">http://www.luminance.org/?p=679</guid>
		<description><![CDATA[One to go. Thanks to some especially hard work by Troupe and Ian, we got a relatively decent build of the game in for the Dream-Build-Play 2009 deadline. Next is the Intel Level Up 2009 competion, only a few days from now. I&#8217;m too lazy to write a large blog post this time, since I&#8217;ve [...]]]></description>
			<content:encoded><![CDATA[<p>One to go.</p>
<p>Thanks to some especially hard work by Troupe and Ian, we got a relatively decent build of the game in for the Dream-Build-Play 2009 deadline. Next is the Intel Level Up 2009 competion, only a few days from now.</p>
<p>I&#8217;m too lazy to write a large blog post this time, since I&#8217;ve been up for about 48 hours. Instead, enjoy this <a href="http://www.luminance.org/inferusgame">conveniently placed link</a> that allows you to download a build of the game and try it out. Feel free to mess around with the level editor, too.</p>
<p>Biggest things of note from the SVN logs this week:</p>
<ul>
<li>Added a boss fight!</li>
<li>Overhauled my physics system to address some floating point accuracy issues.</li>
<li>Overhauled the combat system to try and make it more fun. Only slightly successful.</li>
<li>Finally implemented the player character&#8217;s companion, and added support for talking to her.</li>
<li>Significantly reduced garbage generation, which means less stuttering on the 360. Hooray!</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.luminance.org/blog/gruedorf/2009/08/06/one-down/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Cutting and tuning</title>
		<link>http://www.luminance.org/blog/gruedorf/2009/06/12/cutting-and-tuning</link>
		<comments>http://www.luminance.org/blog/gruedorf/2009/06/12/cutting-and-tuning#comments</comments>
		<pubDate>Sat, 13 Jun 2009 04:53:28 +0000</pubDate>
		<dc:creator>Kael</dc:creator>
				<category><![CDATA[Gruedorf]]></category>
		<category><![CDATA[360]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[cuts]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[xna]]></category>

		<guid isPermaLink="false">http://www.luminance.org/?p=446</guid>
		<description><![CDATA[As far as gameplay goes, the only major addition since last week&#8217;s post was a relatively complete implementation of player death, along with the &#8216;reunion&#8217; teleport that goes with it. Fairly simple at present, with some bugs to work out (including one related to the teleport location that you&#8217;ll see in the video below). Definitely [...]]]></description>
			<content:encoded><![CDATA[<p>As far as gameplay goes, the only major addition since last week&#8217;s post was a relatively complete implementation of player death, along with the &#8216;reunion&#8217; teleport that goes with it. Fairly simple at present, with some bugs to work out (including one related to the teleport location that you&#8217;ll see in the video below). Definitely helps get a better feeling for whether a given puzzle is too hard or too easy.</p>
<p><object width="640" height="385" data="http://www.youtube-nocookie.com/v/FXb9E23WxpQ&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" type="application/x-shockwave-flash"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube-nocookie.com/v/FXb9E23WxpQ&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" /><param name="allowfullscreen" value="true" /></object></p>
<p>Other than that, the only thing of note code-wise is the time I spent doing some performance tuning. My framerate had crept down over the past month or so, to the point that I wasn&#8217;t able to maintain a stable 60fps on the 360 anymore and my CPU utilization was approaching 30% on my desktop PC. Some of the optimizations were relatively obvious &#8211; for example, I was calling SpriteBatch.Begin/SpriteBatch.End for every on-screen object, for the sake of simplicity, which resulted in a lot of unnecessary draw calls.</p>
<p>Some simple changes to automatically begin/end batches when changing rendering settings reduced the number of draw calls per frame in most cases to around 30, which is perfectly acceptable, and reduced my CPU utilization by around 50%. After that, the rest of the optimization was pretty trivial &#8211; finding other hotspots in my profiler data and reducing the cost.</p>
<p>Well, it was trivial until I ran the game on the 360 again and noticed that the framerate hadn&#8217;t improved very much. Huh? I doubled my framerate on the PC, but on the 360, it barely moved an inch. What&#8217;s the deal?</p>
<p>Turns out, the 360&#8242;s pitiful floating-point performance was kneecapping me. Believe it or not, the primary culprit was the geometric shapes in the game&#8217;s HUD, for the circular health displays you may have seen in previous screenshots/videos. I knew the 360&#8242;s FPU was weak, but not THAT bad. Unfortunately, the only way to detect this is by manually measuring the performance cost of your code on the 360, by commenting out/toggling individual sections of your game code.</p>
<p>Tedious, at best. For now, I ended up just reducing the complexity of the geometry for the HUD elements and reducing the number of shapes I was drawing, which brought the 360 framerate much closer to what it used to be. As it happens, some design changes later in the week helped here too&#8230;</p>
<hr />The majority of my work ended up focusing on the game&#8217;s design: My schedule for this project is extremely aggressive (insanely so, really) and as such, I need to have a relatively complete playable demo within mere months for submission to a couple major game competitions. Being able to hit that deadline in my free time requires me to aggressively control the scope of the project, avoid feature creep, and do as little work as possible to get game mechanics implemented and content built.&nbsp;<br />
&nbsp;<br />
Towards this end, after getting one of my main mechanics prototyped and testing it out in content I&#8217;d built, I made the hard decision to cut the mechanic. The second controllable character you&#8217;ve seen in some of my previous videos is effectively gone, though I&#8217;m going to attempt to make use of the design and code effort for the revised design.&nbsp;<br />
&nbsp;<br />
Making a choice like this is always painful, especially when you don&#8217;t have an unchangeable deadline or overbearing boss pushing you towards it. But ultimately, I think I&#8217;ll benefit from making these cuts sooner rather than later. I wish I had started thinking hard about it a few weeks earlier, when my first prototypes were working, instead of waiting until the issues were obvious, but I&#8217;m still relatively happy with the turnaround. I was able to prototype a relatively unusual game mechanic in a matter of a couple dozen hours of programming time, and decide that it wasn&#8217;t worth pursuing, and cut it. Definitely an improvement over traditional Waterfall with long cycles, but not quite true Agile yet. <img src='http://www.luminance.org/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> &nbsp;<br />
&nbsp;<br />
For me, this underscores the importance of aggressive, early prototyping of almost every possible game mechanic and design, instead of focusing on a single section of game content or gameplay until it&#8217;s done. Previously I was used to having a rigid focus on a section of a game or application, working on it day in and day out until it was done and ready to hand off &#8211; but in many cases, this meant that I could sink days or weeks of my time into something that ultimately had to be thrown out.&nbsp;<br />
&nbsp;<br />
Just like a lot of Agile proponents will tell you, it turns out that failing fast means wasting less time. The chaotic feeling and loss of productivity to context switches can be painful, and I think being successful requires setting things up to avoid having to pay those costs too many times a week, but ultimately, it&#8217;s a great decision.&nbsp;<br />
&nbsp;<br />
<object width="640" height="385"><param name="movie" value="http://www.youtube-nocookie.com/v/AujBCa_R4tM&#038;hl=en&#038;fs=1&#038;rel=0&#038;color1=0x2b405b&#038;color2=0x6b8ab6&#038;hd=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube-nocookie.com/v/AujBCa_R4tM&#038;hl=en&#038;fs=1&#038;rel=0&#038;color1=0x2b405b&#038;color2=0x6b8ab6&#038;hd=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="385"></embed></object></p>
]]></content:encoded>
			<wfw:commentRss>http://www.luminance.org/blog/gruedorf/2009/06/12/cutting-and-tuning/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

