<?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:blogger='http://schemas.google.com/blogger/2008' 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-1191561667656967116</id><updated>2026-10-16T23:05:51.694+01:00</updated><category term="Haskell"/><category term="Raytracing"/><category term="C++"/><category term="Optimisation"/><category term="Coding"/><category term="Observations"/><category term="Parallelism"/><category term="Photon Mapping"/><category term="Project Management"/><category term="DX11"/><category term="Development"/><category term="Gen8 Bootcamp"/><category term="Lighting"/><category term="Rendering"/><category term="Sparse Voxel Octree"/><category term="Videogames"/><category term="Brainfart"/><category term="Brooks Law"/><category term="C++11"/><category term="Caching"/><category term="Code re-use"/><category term="Creativity"/><category term="Critical Chain"/><category term="DOD"/><category term="Debugging"/><category term="Design"/><category term="Histogram"/><category term="Marching Cubes"/><category term="OOP"/><category term="Polymorphism"/><category term="Shadows"/><category term="Tone map"/><category term="VPL"/><title type='text'>Tom Hammersley&#39;s Graphics and Games Development Blog</title><subtitle type='html'>Games programming, graphics programming, and general software development</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://tomhammersley.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://tomhammersley.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>41</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1191561667656967116.post-2972085335171823019</id><published>2013-06-05T13:00:00.001+01:00</published><updated>2013-06-05T13:00:05.206+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="DX11"/><category scheme="http://www.blogger.com/atom/ns#" term="Gen8 Bootcamp"/><category scheme="http://www.blogger.com/atom/ns#" term="Lighting"/><title type='text'>Polygonal Area Light Sources on DX11-Class Hardware</title><content type='html'>The surge in interest in Physically-Based Rendering has led to a surge in interest in area light sources. There is, however, something of a dearth of information available for the aspiring implementer.&lt;br /&gt;
&lt;h2&gt;
&lt;br /&gt;&lt;/h2&gt;
&lt;h2&gt;
Introduction&lt;/h2&gt;
The objective of polygonal area light sources is to define an arbitrary polygon in space that may emit light. I&#39;m going to make two simplifications here: firstly, that the polygon emits a constant colour across its surface and secondly, that we are not considering shadowing.&lt;br /&gt;
&lt;br /&gt;
The earliest source I was able to find on this subject is&amp;nbsp;&lt;a href=&quot;http://www.graphics.cornell.edu/pubs/1994/Arv94.pdf&quot;&gt;James Arvo&#39;s 1994 paper on polyhedral light sources&lt;/a&gt;. &amp;nbsp;John Snyder also presents &lt;a href=&quot;http://research.microsoft.com/en-us/um/people/johnsny/papers/arealights.pdf&quot;&gt;another excellent reference&lt;/a&gt;.&amp;nbsp;The approach taken here is to compute a vector field such that at any point in space r, we may obtain the direction of the light. This vector field is a function of the position r, but also the polygon&#39;s vertices. This direction can then be substituted into your brdf equation for a particular surface.&lt;br /&gt;
&lt;br /&gt;
Arvo&#39;s algorithm is simple: for each edge of the polygon he computes a normal named gamma, and a weighting value named theta. The normal is of the triangle formed by the polygon edge and the point r. The weight theta is the angle formed by the pair of vectors from the point r to each edge vertex. He forms a weighted sum of these normals, divides it by 2*PI (to normalise the weights returned by acos) and scales it by the light&#39;s intensity. This is all you need to perform basic area lighting.&lt;br /&gt;
&lt;br /&gt;
There are a couple of twists. Firstly, you typically need to negate the computed vector to get it into a form ready to dot against your normal. Secondly, you must clip the polygon against the plane of the point being shaded. It is possible to have a valid light source that straddles the plane of the point being shaded.&lt;br /&gt;
&lt;h2&gt;
&lt;br /&gt;&lt;/h2&gt;
&lt;h2&gt;
Basic HLSL code&lt;/h2&gt;
&lt;div&gt;
Here is the HLSL code to perform the basic calculation to obtain the light vector for a polygon at a given point. Here, I process quads. This is no algorithm restriction; this is purely to minimise buffer traffic.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;// Derive quad vertices in world-space&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;float3 quadCentre = g_quadLights[lightIndex].pos;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;float3 quadAxisX = g_quadLights[lightIndex].axisX * 0.5f;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;float3 quadAxisY = g_quadLights[lightIndex].axisY * 0.5f;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;float4 quadVertices[4] =&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; float4(quadCentre - quadAxisX - quadAxisY, 1.0f),&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; float4(quadCentre + quadAxisX - quadAxisY, 1.0f),&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; float4(quadCentre + quadAxisX + quadAxisY, 1.0f),&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; float4(quadCentre - quadAxisX + quadAxisY, 1.0f),&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;};&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;float3 lightField = 0.0f;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;uint polyVertex1 = 3;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;for(uint polyVertex0 = 0; polyVertex0 &amp;lt; 4; ++polyVertex0)&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; float3 delta0 = quadVertices[polyVertex0].xyz - worldSpacePos;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; float3 delta1 = clippedPolygon[polyVertex1].xyz - worldSpacePos;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; float3 edge0 = normalize(delta0);&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; float3 edge1 = normalize(delta1);&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; float theta = acos(dot(edge0, edge1));&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; float3 gamma = normalize(cross(delta1, delta0)); // Note you can&#39;t just cross edge0 and edge1 to save the normalize - that gets you the wrong result!&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; lightField += theta * gamma;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; polyVertex1 = polyVertex0;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;// Note that we don&#39;t divide by 2*PI as in the paper. That is just there to account for the sum of the theta values&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;// We don&#39;t need it since we&#39;re doing a normalise - it&#39;s just a uniform scale&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;// Summing normalised vectors doesn&#39;t necessarily give a normalised result. Also flip the vector ready for light calculations&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;lightField = -normalize(lightField);&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;
&lt;br /&gt;&lt;/h2&gt;
&lt;h2&gt;
Clipping&lt;/h2&gt;
&lt;div&gt;
We must now deal with the problem of clipping. This is a particularly awkward operation, especially when it may need to be done per-pixel. Firstly, we must establish whether we actually need to clip. Since the quads are formed using a quad centre and two axes, this may be handled using something very similar to an&amp;nbsp;&lt;a href=&quot;http://www.gamasutra.com/view/feature/3383/simple_intersection_tests_for_games.php&quot;&gt;OBB vs plane test&lt;/a&gt;:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;float criticalDistance = abs(dot(worldSpaceNormal, quadAxisX)) + abs(dot(worldSpaceNormal, quadAxisY));&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;float planeToQuadCentreDistance = dot(worldSpacePlane, float4(quadCentre, 1.0f));&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;if(planeToQuadCentreDistance &amp;lt; -criticalDistance)&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; // Invisible&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;if(planeToQuadCentreDistance &amp;lt; -criticalDistance)&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; // Fully visible - unclipped&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
We then use standard Sutherland-Hodgman clipping to trim the polygon against the plane:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;float4 clippedPolygon[5]; // Clipping against 1 plane can add one extra vertex to the quad&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;uint numClippedVertices = 0;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;// Clip the polygon against the plane of the point being shaded&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;float vertexPlaneSide[4] =&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; sign(dot(quadVertices[0], worldSpacePlane)),&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; sign(dot(quadVertices[1], worldSpacePlane)),&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; sign(dot(quadVertices[2], worldSpacePlane)),&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; sign(dot(quadVertices[3], worldSpacePlane)),&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;};&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;numClippedVertices = 0;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;uint previous = 3;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;for(uint current = 0; current &amp;lt; 4; ++current)&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; float currentSide = vertexPlaneSide[current];&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; if(currentSide &amp;lt; 0.0f)&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if(vertexPlaneSide[previous] &amp;gt; 0.0f)&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; float4 v1 = quadVertices[previous];&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; float4 v2 = quadVertices[current];&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; float3 delta = v2.xyz - v1.xyz;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; float t = dot(worldSpacePlane, v2) / dot(worldSpacePlane.xyz, delta);&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; clippedPolygon[numClippedVertices++] = float4(v2.xyz - delta * t, 1.0f);&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; else&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; float4 v1 = quadVertices[current];&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if(currentSide &amp;gt; 0.0f &amp;amp;&amp;amp; vertexPlaneSide[previous] &amp;lt; 0.0f)&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; float4 v2 = quadVertices[previous];&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; float3 delta = v2.xyz - v1.xyz;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; float t = dot(worldSpacePlane, v2) / dot(worldSpacePlane.xyz, delta);&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; clippedPolygon[numClippedVertices++] = float4(v2.xyz - delta * t, 1.0f);&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; clippedPolygon[numClippedVertices++] = v1;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; previous = current;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The resulting polygon may then be used in the original light field calculation code.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tomhammersley.blogspot.com/feeds/2972085335171823019/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomhammersley.blogspot.com/2013/06/polygonal-area-light-sources-on-dx11.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/2972085335171823019'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/2972085335171823019'/><link rel='alternate' type='text/html' href='http://tomhammersley.blogspot.com/2013/06/polygonal-area-light-sources-on-dx11.html' title='Polygonal Area Light Sources on DX11-Class Hardware'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1191561667656967116.post-4171520195364554057</id><published>2013-05-17T22:07:00.001+01:00</published><updated>2013-05-20T09:57:00.231+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="DX11"/><category scheme="http://www.blogger.com/atom/ns#" term="Gen8 Bootcamp"/><category scheme="http://www.blogger.com/atom/ns#" term="Histogram"/><category scheme="http://www.blogger.com/atom/ns#" term="Tone map"/><title type='text'>Image Histogram Construction In DX11</title><content type='html'>&lt;h2&gt;
Preamble&lt;/h2&gt;
Recently, I have been researching some next-gen rendering techniques. There&#39;s some great presentations out there by the usual suspects - Epic, Crytek, DICE, Guerilla and so on. Many of the vendors also have good sample code to explore. There&#39;s a lot of buzz about certain new techniques... but there&#39;s sometimes a little bit of a gap between the academic literature, the presentations and sample code. Sometimes its a little hard for the time-pressed practioner to google an example and jump straight in.&lt;br /&gt;
&lt;br /&gt;
So, I thought I&#39;d show a little example code to help people get started.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;
Introduction&lt;/h2&gt;
Tone mapping using a histogram is becoming a trend in next-generation graphics. People are starting to experiment with moving away from the DX9/360/PS3 style &quot;compute average luminance, apply exposure, apply film response curve&quot; algorithms towards trying something different.&lt;br /&gt;
&lt;br /&gt;
Histogram based methods aren&#39;t new. An early, commonly cited example is &lt;a href=&quot;http://radsite.lbl.gov/radiance/papers/lbnl39882/tonemap.pdf&quot;&gt;Ward et al &#39;97.&lt;/a&gt; More recent examples are things like &lt;a href=&quot;http://ima.ac.uk/papers/duan2010.pdf&quot;&gt;Duan et al 2010.&lt;/a&gt; The basic idea is that you take an input high dynamic range image, compute a histogram measuring the frequency of different luminances in that scene, and use that to build a response curve. The response curve maps from the scene&#39;s luminance range to your output display lumiance range.&lt;br /&gt;
&lt;br /&gt;
So, in one fell swoop, you can take your HDR image and convert it to an LDR image. No repeated downsampling and cache thrashing, no incorrect half-pixel or half-texel offsets, no frame-by-frame adaptation. A simple algorithm that &quot;just works&quot;.&lt;br /&gt;
&lt;br /&gt;
This algorithm fits very naturally with compute shaders in DX11. However, not everyone out there is a DX11 expert; there are many practictioners busy shipping titles on DX9 class hardware who have not had the opportunity to experiment with DX11 yet. I shall detail the implementation of a very basic histogram based tone mapping operator that may serve as the basis for future expansion.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;
Running a Compute Shader Over an Image&lt;/h2&gt;
&lt;h3&gt;
Compute Shader Introduction&lt;/h3&gt;
Compute shaders off a great deal of general, flexible power on modern DX11 GPUs. They are very flexible and offer immense general computation power. They are not, however, a direct replacement for C++ code; they have a specific programming model that you have to follow. Whilst you can ignore some details of this model, you will not achieve maximum performance. This programming model therefore largely dictates how you must structure your algorithm.&lt;br /&gt;
&lt;br /&gt;
An individual compute shader contains the inner most operation of some loop. However, the compute shader is not executed as some kind of iterative loop. Instead, many separate invocations of the compute shader code are scheduled, dispatched and retired. Each invocation of the compute shader is known as a thread,&amp;nbsp;and each thread receives unique addressing information. And these threads are executed in parallel. Threads are grouped into thread groups. Each thread is therefore separately executing some part of the desired operation. It is very akin to a parallel map operation in a functional language.&lt;br /&gt;
&lt;br /&gt;
A compute shader is therefore unlike a general CPU process or job. It is unlike the jobs or task programming model of the Cell processor. It is &lt;em&gt;very&lt;/em&gt; similar to shading a pixel. In contrast to pixel shading, compute shader threads&amp;nbsp;can communicate with other concurrent threads. A thread may communicate with other threads in the same group using some on-chip fast memory known as group shared memory.&lt;br /&gt;
&lt;br /&gt;
The conclusion of this is that when processing an image with a compute shader, you do not sit in a big x * y loop, fetching pixels and processing them. You do not DMA in parts of an image, process them, and DMA them out again. You write code that processes each pixel independently and dispatch that work to be processed&amp;nbsp;as a whole in parallel. This requires a certain structure to your code, especially if you want to obtain maximum parallelism.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Tiling&lt;/h3&gt;
A common paradigm when executing a compute shader over an image is to break the image up into tiles. Each thread typically corresponds to an input pixel.A thread group maps to a tile. Each thread is executed and aggregates data to the local, on-chip memory known as group shared memory. When all the threads in a group have completed, the results are exported from the transient group shared memory to some persistent off-chip memory.&lt;br /&gt;
&lt;br /&gt;
But what is the reasoning behind this model?&lt;br /&gt;
&lt;br /&gt;
If we liked, we could dispatch a compute shader with a thread group size of 1 x 1 x 1 thread. Inside this one thread of one shader, we would iterate through every single pixel in an image and perform our computation. But, this model offers very little parallelism. We would only enjoy the SIMD instruction level parallelism, and would have no thread-level parallelism. GPUs are built to be very, very wide. We would only be occupying a fraction of the GPU.&lt;br /&gt;
&lt;br /&gt;
Ideally. we want to launch as many threads as possible. This undermines any kind of approach where one thread iterates across many pixels. We want a thread per pixel.&lt;br /&gt;
&lt;br /&gt;
And this is what gives rise to the image tiling model. Here, we break the image into tiles of 16x16, 32x32 or whatever size yields the maximum threads and therefore parallelism possible. We exploit group shared memory rather than work directly in off-chip memory for performance reasons. A modern GPU will not simply sit and churn through every every thread of your compute shader until completion. It will execute wavefronts (groups of threads) from multiple different shaders simultaneously across the GPU. If we can read from off-chip memory but write to on-chip memory, we minimise our bandwidth consumption and play better with other shaders. Ultimately we will need to export the results, but we can do that once in a burst rather than constantly causing memory hazards.&lt;br /&gt;
&lt;br /&gt;
We may need to execute subsequent passes that combine together this intermediate metadata to yield a final result. This arrangement is akin to the common map-reduce parallel programming model.&lt;br /&gt;
&lt;br /&gt;
I will now dive straight into the HLSL compute shader code.&amp;nbsp;For clarity and brevity, I won&#39;t present the detailed DX11 CPU-side code; I shall just detail what it needs to do.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;
Computing the Per-Tile Histogram.&lt;/h2&gt;
Our first task is to compute a histogram for each tile of the image. These will later be combined to form a histogram for the whole image. Each histogram will map the scene&#39;s luminance range across N bins. Each bin holds a uint which represents the number of pixels in that luminance band.&lt;br /&gt;
&lt;br /&gt;
To perform this, we need a few things on the DX11 side:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;A shader resource view that allows us to read the source texture.&lt;/li&gt;
&lt;li&gt;A shader resource view for our constant buffer.&lt;/li&gt;
&lt;li&gt;A large buffer to store all of the per-tile histograms. Its size will be numTiles * numHistogramBins.&lt;/li&gt;
&lt;li&gt;An unordered access view for the per-tile histogram buffer.&lt;/li&gt;
&lt;/ul&gt;
We can then dispatch our compute shader. Note, that we have to round up the image size to be a multiple of our compute size; we must then be careful to only sample the real pixels. Here&#39;s the code:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;#define NUM_HISTOGRAM_BINS (64)&lt;br /&gt;#define HISTOGRAM_TILE_SIZE_X (32)&lt;br /&gt;#define HISTOGRAM_TILE_SIZE_Y (16)&lt;br /&gt;&lt;br /&gt;Texture2DMS&lt;float4&gt;&lt;float4 num_msaa_samples=&quot;&quot;&gt; sourceTextureSRV;&lt;br /&gt;&lt;br /&gt;cbuffer toneMapGammaConstants&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; uint outputWidth;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;uint outputHeight;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; float inputLuminanceMin;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; float inputLuminanceMax;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; uint numPerTileHistograms;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; float outputLuminanceMin;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; float outputLuminanceMax;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;// RGB to luminance&lt;br /&gt;float rgbToLuminance(float3 colour)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Use this equation:&amp;nbsp;&lt;/float4&gt;&lt;/float4&gt;&lt;/span&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Luminance_(relative&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;http://en.wikipedia.org/wiki/Luminance_(relative&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return dot(float3(0.2126f, 0.7152f, 0.0722f), colour);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// RGB to log-luminance&lt;br /&gt;float rgbToLogLuminance(float3 colour)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return log(rgbToLuminance(colour));&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;// Convert a luminance to a histogram bin index&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;uint rgbToHistogramBin(float3 colour)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;{&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Convert to luminance&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; float luminance = rgbToLogLuminance(colour);&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Work out response curve response&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return uint(float(NUM_HISTOGRAM_BINS) * saturate((luminance - inputLuminanceMin) / (inputLuminanceMax - inputLuminanceMin)));&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
// Thread groups correspond to a tile.&lt;br /&gt;// Threads correspond to a pixel&lt;br /&gt;&lt;br /&gt;groupshared uint histogram[NUM_HISTOGRAM_BINS];&lt;br /&gt;&lt;br /&gt;Buffer&lt;uint&gt;&lt;uint&gt; perTileHistogramSRV;&lt;br /&gt;Buffer&lt;uint&gt;&lt;uint&gt; mergedHistogramSRV;&lt;br /&gt;RWBuffer&lt;uint&gt;&lt;uint&gt; perTileHistogramUAV;&lt;br /&gt;RWBuffer&lt;uint&gt;&lt;uint&gt; mergedHistogramUAV;&lt;br /&gt;&lt;br /&gt;[numthreads(HISTOGRAM_TILE_SIZE_X, HISTOGRAM_TILE_SIZE_Y, 1)]&lt;br /&gt;void compute_per_tile_histogram_cs(uint3 globalIdx : SV_DispatchThreadID, uint3 localIdx : SV_GroupThreadID, uint3 groupIdx : SV_GroupID)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; uint localIdxFlattened = localIdx.x + localIdx.y * HISTOGRAM_TILE_SIZE_X; // Which pixel within a tile&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;uint tileIdxFlattened = groupIdx.x + groupIdx.y * GetNumTilesX(); // Which tile from the screen&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;// Initialise the contents of the group shared memory. Only one&amp;nbsp; thread does it to avoid bank conflict overhead&lt;/uint&gt;&lt;/uint&gt;&lt;/uint&gt;&lt;/uint&gt;&lt;/uint&gt;&lt;/uint&gt;&lt;/uint&gt;&lt;/uint&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if(localIdxFlattened == 0)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for(uint index = 0; index &amp;lt; NUM_HISTOGRAM_BINS; ++index)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; histogram[index] = 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GroupMemoryBarrierWithGroupSync();&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // For each thread, update the histogram&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // It is possible that we emit more threads than we have pixels. This is caused due to rounding up an image to a multiple of the tile size&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if(globalIdx.x &amp;lt; outputWidth &amp;amp;&amp;amp; globalIdx.y &amp;lt; outputHeight)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // We just use sample 0 for efficiency reasons. It is unlikely that omitting the extra samples will make a significant difference to the histogram&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; float3 pixelValue = sourceTextureSRV.Load(int2(globalIdx.xy), 0).rgb;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; uint bin = rgbToHistogramBin(pixelValue);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; InterlockedAdd(histogram[bin], 1u);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Thread 0 outputs this thread group&#39;s histogram to the buffer&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GroupMemoryBarrierWithGroupSync();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if(localIdxFlattened == 0)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; // This could write uint4s to the UAV as an optimisation&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; uint outputHistogramIndex = NUM_HISTOGRAM_BINS * tileIdxFlattened;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for(uint index = 0; index &amp;lt; NUM_HISTOGRAM_BINS; ++index)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; uint outputIndex = index + outputHistogramIndex;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; perTileHistogramUAV[outputIndex] = histogram[index];&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
We now need to take this buffer and combine it to form a single histogram for the whole image.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;
Merging the Per-Tile Histograms&lt;/h2&gt;
&lt;div&gt;
This is a relatively simple compute shader. In this case, each thread maps to one of the tiles just computed, and each threadgroup therefore represents a group of tiles. This shader atomically adds each tile&#39;s histogram to the global histogram. In addition to the previous resources, we also now need:&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;A buffer to hold the histogram for the whole image.&lt;/li&gt;
&lt;li&gt;An unordered access view to read said buffer.&lt;/li&gt;
&lt;li&gt;A shader resource view for the per-tile histogram buffer.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;// A thread per tile&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;#define NUM_TILES_PER_THREAD_GROUP 768 // DX10 maximum&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;[numthreads(NUM_TILES_PER_THREAD_GROUP, 1, 1)]&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;void merge_histograms_cs(uint3 globalIdx : SV_DispatchThreadID, uint3 localIdx : SV_GroupThreadID, uint3 groupIdx : SV_GroupID)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;{&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Each thread has the job of adding in the contents of the per-tile histogram to the overall histogram stored in GSM&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // This is an atomic operation, because many, many threads are trying to hit that memory simultaneously&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; uint tileIndex = globalIdx.x;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if(tileIndex &amp;lt; numPerTileHistograms)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for(uint binIndex = 0; binIndex &amp;lt; NUM_HISTOGRAM_BINS; ++binIndex)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; InterlockedAdd(mergedHistogramUAV[binIndex], perTileHistogramSRV[tileIndex * NUM_HISTOGRAM_BINS + binIndex]);&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Note that here we perform atomic operations on the merged histogram. You may do this on both group shared memory and unordered access views; clearly there is extra overhead in the latter. We now have a histogram for the whole image. Our job is now to convert that to a response curve. This is a function that maps from the input HDR image to a new LDR image. Wikipedia offers an&amp;nbsp;&lt;a href=&quot;http://en.wikipedia.org/wiki/Histogram_equalization&quot;&gt;easy explanation.&lt;/a&gt;&lt;/div&gt;
&lt;h2&gt;
&lt;/h2&gt;
&lt;h2&gt;
Computing the Response Curve&lt;/h2&gt;
&lt;div&gt;
Again, more resources are needed:&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;A buffer holding a float for each histogram bin.&lt;/li&gt;
&lt;li&gt;An unordered access view to write to it with.&lt;/li&gt;
&lt;li&gt;A shader resource view for the whole-image histogram.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
There is a small wrinkle in this code. We also include an extra step - the adjustment phase discussed in Page 14 of the Ward &#39;97 paper. This is included only as an example to get you started. I use a 1x1x1 compute shader here as this is such a minimal operation that parallelism would gain little.&lt;/div&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;RWBuffer&lt;float&gt;&lt;/float&gt;&lt;/span&gt;&lt;float style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;responseCurveUAV;&lt;/float&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;groupshared float frequencyPerBin[NUM_HISTOGRAM_BINS];&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;groupshared float initialFrequencyPerBin[NUM_HISTOGRAM_BINS];&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;[numthreads(1, 1, 1)]&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;void compute_histogram_response_curve_cs(uint3 globalIdx : SV_DispatchThreadID, uint3 localIdx : SV_GroupThreadID, uint3 groupIdx : SV_GroupID)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;{&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; // Compute the initial frequency per-bin, and save it&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; float T = 0.0f;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; for(uint bin = 0; bin &amp;lt; NUM_HISTOGRAM_BINS; ++bin)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; float frequency = float(mergedHistogramSRV[bin]);&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; frequencyPerBin[bin] = frequency;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; initialFrequencyPerBin[bin] = frequency;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; T += frequency;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; // Naive histogram adjustment. There are many, many such histogram modification algorithms you may seek to employ - this is&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; // an example implementation that will no doubt later be changed&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; // This is an implementation of page 14 of &quot;A Visibility Matching Tone Reproduction Operator for High Dynamic Range Scenes&quot;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; // There are other, better approaches, like Duan 2010: http://ima.ac.uk/papers/duan2010.pdf&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; float recipDisplayRange = 1.0f / (log(outputLuminanceMax) - log(outputLuminanceMin));&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; // Histogram bin step size - in log(cd/m2)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; float deltaB = (inputLuminanceMax - inputLuminanceMin) / float(NUM_HISTOGRAM_BINS); // Luminance values are already log()d&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; float tolerance = T * 0.025f;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; float trimmings = 0.0f;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; uint loops = 0;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; do&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // Work out the new histogram total&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; T = 0.0f;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; for(uint bin2 = 0; bin2 &amp;lt; NUM_HISTOGRAM_BINS; ++bin2)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; T += frequencyPerBin[bin2];&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if(T &amp;lt; tolerance)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // This convergence is wrong - put it back to the original&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; T = 0.0f;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; for(uint index = 0; index &amp;lt; NUM_HISTOGRAM_BINS; ++index)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; frequencyPerBin[index] = initialFrequencyPerBin[index];&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; T += frequencyPerBin[index];&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; break;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // Compute the ceiling&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; trimmings = 0.0f;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; float ceiling = T * deltaB * recipDisplayRange;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; for(uint bin3 = 0; bin3 &amp;lt; NUM_HISTOGRAM_BINS; ++bin3)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if(frequencyPerBin[bin3] &amp;gt; ceiling)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; trimmings += frequencyPerBin[bin3] - ceiling;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; frequencyPerBin[bin3] = ceiling;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; T -= trimmings;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ++loops;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; while(trimmings &amp;gt; tolerance &amp;amp;&amp;amp; loops &amp;lt; 10);&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; // Compute the cumulative distribution function, per bin&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; float recipT = 1.0f / T;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; float sum = 0.0f;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; for(uint bin5 = 0; bin5 &amp;lt; NUM_HISTOGRAM_BINS; ++bin5) // By now you are wondering about bin1, bin2, bin3 etc. It is a shader compiler thing.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; float probability = frequencyPerBin[bin5] * recipT;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; sum += probability;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; responseCurveUAV[bin5] = sum;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;}&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
And we now have a response curve to apply to our image!&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;
Applying the Response Curve&lt;/h2&gt;
&lt;div&gt;
Again, we need one more new resource: A shader resource view to access the response curve buffer. The code is again quite simple. Here, we&#39;re running a compute shader over tiles of the image. I&#39;ve also included an MSAA resolve and gamma correction step, as these are features you will probably need to implement too in a next-generation linearly correct renderer. Note, that you ideally tone-map before the MSAA resolve. I felt it was simpler to present the code this way around. Secondly, ideally your frame buffer would have separated chrominance from luminance and you would just scale the luminance. Again, I&#39;ve presented it this way for a simple example.&lt;/div&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;#define TONE_MAP_GAMMA_TILE_SIZE (8)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;Buffer&lt;float&gt;&lt;float&gt; responseCurveSRV;&lt;/float&gt;&lt;/float&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;RWTexture2D&lt;float4&gt;&lt;float4&gt;&amp;nbsp;outputUAV;&lt;/float4&gt;&lt;/float4&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;[numthreads(TONE_MAP_GAMMA_TILE_SIZE, TONE_MAP_GAMMA_TILE_SIZE, 1)]&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;void main_cs(uint3 threadID : SV_DispatchThreadID)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;{&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; float3 sourceRGB = 0;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; for(uint sampleIndex = 0; sampleIndex &amp;lt; NUM_MSAA_SAMPLES; ++sampleIndex)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; sourceRGB += sourceTextureSRV.Load(int2(threadID.xy), sampleIndex).rgb;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; sourceRGB /= NUM_MSAA_SAMPLES;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; // Work out response curve response&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; uint bin = rgbToHistogramBin(sourceRGB);&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; float scalar = bin &amp;lt; NUM_HISTOGRAM_BINS ? responseCurveSRV[bin] : 1.0f;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; sourceRGB *= scalar;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; outputUAV[threadID.xy] = float4(saturate(pow(sourceRGB, 1.0f / 2.2f)), 1.0f));&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;}&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;
That&#39;s It&lt;/h2&gt;
&lt;div&gt;
And there we have it. A simple, bare-bones implementation to illustrate how these things may be implemented. Something to get the practitioner up and running.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tomhammersley.blogspot.com/feeds/4171520195364554057/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomhammersley.blogspot.com/2013/05/image-histogram-construction-in-dx11.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/4171520195364554057'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/4171520195364554057'/><link rel='alternate' type='text/html' href='http://tomhammersley.blogspot.com/2013/05/image-histogram-construction-in-dx11.html' title='Image Histogram Construction In DX11'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1191561667656967116.post-1034572964499421226</id><published>2013-04-25T14:51:00.004+01:00</published><updated>2013-04-25T14:51:36.951+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Brainfart"/><category scheme="http://www.blogger.com/atom/ns#" term="Rendering"/><category scheme="http://www.blogger.com/atom/ns#" term="Shadows"/><title type='text'>Distant Shadowing &quot;brainfart&quot;</title><content type='html'>Recently, I&#39;ve been having a little bit of a think about how to handle realtime distant shadowing in games, in order to avoid shadow baking.&lt;br /&gt;
&lt;br /&gt;
Clearly, it&#39;s entirely possible to use some kind of cascaded shadow map extending all the way out. But, this soon ends up getting expensive in terms of textures and rendering. Alternatively, you might consider using something like stencil shadow volumes, and using the extended compute capabilities of modern GPUs to clip down the shadow volume so it doesn&#39;t consume enormous amounts of rasterisation or clipping time.&lt;br /&gt;
&lt;br /&gt;
Alternatively, I&#39;ve been thinking a lot about reprojection. Let&#39;s say you interrogate your cascaded shadow map and use that to build a screen-space mask of the shadow response. You want soft(ish) shadows, so you commit a lot of PCF samples. &lt;br /&gt;
&lt;br /&gt;
How about reprojecting last frame&#39;s shadow mask into this frame&#39;s shadow mask, then filling in the holes with some simple filtering operations? Distant shadows are typically pretty low-frequency things, so you could well get away with some blurring and imperfection in the shadow mask. Then, you need only render the geometry that became newly visible this frame into the shadow map. You could just subtract one frame&#39;s light frustum from the other, yielding a convex polytope, and only render the intersecting objects.&lt;br /&gt;
&lt;br /&gt;
Just a brainfart...&lt;br /&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tomhammersley.blogspot.com/feeds/1034572964499421226/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomhammersley.blogspot.com/2013/04/distant-shadowing-brainfart.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/1034572964499421226'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/1034572964499421226'/><link rel='alternate' type='text/html' href='http://tomhammersley.blogspot.com/2013/04/distant-shadowing-brainfart.html' title='Distant Shadowing &quot;brainfart&quot;'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1191561667656967116.post-4573532738203760056</id><published>2013-03-28T15:47:00.000+00:00</published><updated>2013-04-23T15:42:12.556+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Lighting"/><category scheme="http://www.blogger.com/atom/ns#" term="Rendering"/><category scheme="http://www.blogger.com/atom/ns#" term="VPL"/><title type='text'>Thoughts on VPL Generation Using Cube Maps</title><content type='html'>Recently, I&#39;ve been doing a lot of research and thinking about realtime GI and its related ideas. A common theme in realtime GI is the use of &lt;a href=&quot;http://www.cs.cornell.edu/Courses/cs6630/2012sp/slides/Boyadzhiev-Matzen-InstantRadiosity.pdf&quot;&gt;VPLs&lt;/a&gt;, a way to approximate the radiance bouncing off a surface after interacting with its material. A VPL is only formed where there is a definite light-to-surface interaction. The VPL can therefore be used to simulate light bouncing off geometry.&lt;br /&gt;
&lt;br /&gt;
One technique in use today for generating VPLs is the &lt;a href=&quot;http://dl.acm.org/citation.cfm?id=1053460&quot;&gt;Reflective Shadow Map&lt;/a&gt;&amp;nbsp;algorithm. Here, we render the scene from the light&#39;s point of view, and every pixel in the output image represents a surface receiving primary illumination from the light source. This is obviously a fairly efficient way of finding all the surfaces that receive radiance from a given light source without too much wastage. You can then construct VPLs using that image, reduce the working set and inject them into some lighting algorithm to bounce light around your scene.&lt;br /&gt;
&lt;br /&gt;
The difficulty is, this may not scale well as each new light source would require a new RSM render.&lt;br /&gt;
&lt;br /&gt;
One alternative I considered was the possibility of using a cube map to sample the primary illumination from multiple lights simultaneously. You would put your cube map at your camera position, or some other meaningful point-of-interest. You then render the scene into each cube map face. As you render it, you light it from all of your light sources simultaneously, with shadow maps too if desired. Obviously this would be an expensive render.. but it would only be done once, you can vary the resolution of it and you can always use techniques like tiled lighting to accelerate it if you have many lights.&lt;br /&gt;
&lt;br /&gt;
When complete, this cube map holds the radiance at the first light bounce for many surfaces in the scene near to the point of interest - ie the camera. It contains samples for surfaces all around - both in front of and behind the camera, which is important for GI. You may then use this cube map to generate VPLs for further bounce lighting.&lt;br /&gt;
&lt;br /&gt;
Now, this is as-yet a completely untested idea. I will get round to it, though. I thought I&#39;d throw it out there as an idea for using a commonly-accelerated rendering structure to try to help the scalability of realtime GI solutions.</content><link rel='replies' type='application/atom+xml' href='http://tomhammersley.blogspot.com/feeds/4573532738203760056/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomhammersley.blogspot.com/2013/03/thoughts-on-vpl-generation-using-cube.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/4573532738203760056'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/4573532738203760056'/><link rel='alternate' type='text/html' href='http://tomhammersley.blogspot.com/2013/03/thoughts-on-vpl-generation-using-cube.html' title='Thoughts on VPL Generation Using Cube Maps'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1191561667656967116.post-3853834285993818940</id><published>2013-02-19T12:19:00.002+00:00</published><updated>2013-03-28T15:53:29.932+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="C++"/><category scheme="http://www.blogger.com/atom/ns#" term="C++11"/><category scheme="http://www.blogger.com/atom/ns#" term="Coding"/><title type='text'>C++ 11 Experiences</title><content type='html'>I&#39;ve recently been developing a lot of code in C++ 11. I find it a huge and useful improvement over previous version of C++; here&#39;s some observations on some of the features in it that I&#39;ve found rather valuable.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
emplace&lt;/h3&gt;
This simple, easily-overlooked addition to the STL has to be one of the most practically useful features of C++ 11. In itself, it does very little: it constructs a new object in-place inside a container. This in itself is very useful for optimisation purposes. However, the real advantage lies in semantics, rather than optimisation.&lt;br /&gt;
&lt;br /&gt;
emplace() means that you are no longer forced to include copy semantics into classes that really, really do not want them in order to place (copy) them into a container type. If the container implements some emplace() functionality, you are free to then delete all copy assignment and copy construction operations, only providing move assignment and construction instead.&lt;br /&gt;
&lt;br /&gt;
This is a huge boon for classes such as resource classes, where assignment or copy can sometimes be a very unnatural and dangerous operation. With emplace() and move semantics, you are then free to create resource classes that make extensive use of const and RAII, ensuring that only one class ever binds to a particular resource.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Lambdas for Complex Initialisation&lt;/h3&gt;
How often have you written code such as:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;SomeType blah = unwantedDefaultValue;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;if(x)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;{&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; blah = a; // In reality this would be much more complex&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;else if(y)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;{&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; blah = b;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;else&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;{&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; blah = c;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Which means that &quot;blah&quot; is not const, when it really needs to be, and you have a big chunk of complex code polluting the flow of some code. Typically, you even have the same thing near-duplicated.&lt;br /&gt;
&lt;br /&gt;
You can always factor the big initialisation statement into a function, and assign it to a const variable... but often to do so artificially externalises details you may prefer not to.&lt;br /&gt;
&lt;br /&gt;
With lambdas, you can now factor all that into a lambda expression, capturing nearby variables or passing different values as a parameter:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;const auto initialiser = []()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if(x)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return a;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; else if(y)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return b;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; else&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return c;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;};&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;...&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;const SomeType blah = initialiser();&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;&lt;span style=&quot;font-family: Courier New;&quot;&gt;const SomeType blah2 = initialiser2(x, y);&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New;&quot;&gt;const SomeType blah3 = initialiser3({1, 2, 3, 4});&lt;/span&gt;&lt;br /&gt;
const SomeType blah4 = initialiser3({});&lt;/span&gt;&lt;br /&gt;
And so on. This can make the code a little more focused, more const-safe, less duplicated and easier to step through and debug.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Avoid Ternary Expressions Using Lambdas&lt;/h3&gt;
A simple one. Ternary expressions can be a little difficult to debug, especially when they are nested:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;const int a = d &amp;lt; e ? f :&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; g &amp;lt; h ?: i :&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; j &amp;lt; k&amp;nbsp; ? m : n;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
And so on. Whilst I don&#39;t advocate it, it does occur. Along the lines of the above point, using a lambda creates code you can place breakpoints on and debug easily, at no performance loss.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Reduction of Code Duplication Using Lambdas&lt;/h3&gt;
Lambdas are very useful to reduce internal code duplication within a function. This perhaps seems a little excessive... but it can help because it factors out the details of a particular operation into one place, leaving the rest of the code simpler. Again, this avoids the problem of artifical external functions that reduce encapsulation... though I do not propose that everything be written as giant functions containing lambdas!&lt;br /&gt;
&lt;br /&gt;
What&#39;s more, I&#39;ve found that the compiler is generally smart enough to inline the expansion of these lambas as appropriate. So there is no performance penalty!&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Move Semantics For Resource Assignment&lt;/h3&gt;
A common issue I face with code is in creation code, where one function creates a resource, passes it to another object which is assumed to take responsibility for its lifetime management and destruction. However, often the constructor just takes a pointer to an object - this declaration is less than clear on what it will do with that resource. This doesn&#39;t tell you whether it&#39;ll just hold that reference, or manage it.&lt;br /&gt;
&lt;br /&gt;
I find move semantics can help here, a little. A constructor which has an rvalue reference to some resource declares that it will acquire the resource, hold a reference to it, but also divest the calling code of that object. This perhaps makes it a little clearer that ownership of the resource is being transferred, not simply passed.&lt;br /&gt;
&lt;br /&gt;
Adding the secret sauce of std::unique_ptr&amp;lt;&amp;gt; makes lifetime management even more painless.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Auto&lt;/h3&gt;
Auto&amp;nbsp;seems one of the potentially more divisive additions to C++ 11. At first, I was unsure. I can see how it can avoid&amp;nbsp;template craziness... but would the lack of explicit type names make things harder to debug?&lt;br /&gt;
&lt;br /&gt;
So far, I generally use auto by default as much as I possibly can. I find that if your code is making good use of functions and constructors, they tend to make it fairly clear what types are being constructed. Furthermore, it makes the code much more amenable to change&amp;nbsp;and refactoring, as it reduces the number of times you have to name a particular type. This seems&amp;nbsp;to be a good thing.&lt;br /&gt;
&lt;br /&gt;
The main downsides of it are that you have to be extremely careful to remember to include &amp;amp; to make some types a reference. If you do not, then you end up implicitly copying objects around, which can lead to performance, correctness or compilation issues.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Range-based for&lt;/h3&gt;
This one&#39;s not such a big deal. It can be useful, as it can save on code verbosity... but so often, you need to iterate over multiple containers simultaneously, and that&#39;s where range-based for ceases to be useful.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
constexpr&lt;/h3&gt;
This is a nice simple win. This at least means you don&#39;t have to start making trivial functions into templates to get some compile-time optimisations. It&#39;s unfortunate that it insists on the single-line return statements, as this can mean things such as data tables spill out of the scope of the function.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Class Member Initialisation&lt;/h3&gt;
I find that being able to assign values to class instance members inside the class declaration to be enormously useful. This allows you to vastly simplify your constructors, especially when you have multiple constructors. This removes a lot of duplication, and allows you to instead implement only the specialisations. This seems to be the right way round to me.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Promises, and Futures&lt;/h3&gt;
&lt;div&gt;
By and large, these are quite nice facilities. The big thing they lack though is the ability to poll a future. This seems like quite a major omission, and can make them difficult to use for some algorithms. As such, I tend to find myself rolling my own cut-down variants for many purposes.&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
In summary, it&#39;s very agreeable. No real change is mandated, so you simply opt in or opt out of as many or as few new features you&#39;d like to employ. I&#39;m a convert.</content><link rel='replies' type='application/atom+xml' href='http://tomhammersley.blogspot.com/feeds/3853834285993818940/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomhammersley.blogspot.com/2013/02/c-11-experiences.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/3853834285993818940'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/3853834285993818940'/><link rel='alternate' type='text/html' href='http://tomhammersley.blogspot.com/2013/02/c-11-experiences.html' title='C++ 11 Experiences'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1191561667656967116.post-4793781850690362310</id><published>2012-11-02T21:30:00.005+00:00</published><updated>2012-11-05T10:54:31.444+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="C++"/><category scheme="http://www.blogger.com/atom/ns#" term="Parallelism"/><title type='text'>Job Graphs in C++ 11</title><content type='html'>&lt;h2&gt;
Introduction&lt;/h2&gt;
I&#39;ve recently been experimenting with a lot of the new features in C++ 11, purely for discovery and experimentation. One major new feature are the threading libraries. As using is the best way of learning, I set upon the task of writing a currently-fashionable task/job-graph system using these new features. &lt;br /&gt;
&lt;br /&gt;
I&#39;m not promoting this algorithm as the one true approach for parallelism, as there are many other valuable algorithms that are much more suitable in certain occasions. This one seems a useful, generic solution that fits many cases fairly well. In the process, I found a few interesting quirks during implementation that I thought may be interesting for others.&lt;br /&gt;
&lt;h2&gt;
Job Graphs&lt;/h2&gt;
Job graphs are currently finding wide favour as an approach to the challenge of building a flexible architecture for multithreaded processing. In this scheme, jobs are stored in a graph structure. The edges of the graph are used to represent ordering and data dependencies between jobs. Assuming the graph is structured correctly, this ensures that work is processed in the correct order to ensure the correct and timely flow of data. Nodes that do not share a data dependency may be executed concurrently. The programmer shoulders the responsibility of structuring the graph correctly, and ensuring any conflicts between resources are either resolved via the graph, or using some locking mechanism.&lt;br /&gt;
&lt;br /&gt;
Typically, the jobs are pushed into some kind of queue and distributed to a thread pool. Ideally you would also use work-stealing for maximum efficiency.&lt;br /&gt;
&lt;br /&gt;
The goal is to use this graph structure to allow non-dependent work to execute concurrently, saturating all hardware threads. It is a very simplistic idea, yet at its most it is NP-hard to solve.&lt;br /&gt;
&lt;h2&gt;
C++ 11 Threading Overview&lt;/h2&gt;
&lt;div&gt;
The C++ 11 threading library is really quite a lightweight, spare API. Broadly, it offers the facilities to:&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;Create and manage threads in a cross platform fashion.&lt;/li&gt;
&lt;li&gt;Synchronise activity between these threads using simple primitives such as mutexes, condition variables and promises/futures.&lt;/li&gt;
&lt;li&gt;Package up tasks to be executed on a thread.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2&gt;
Implementation&lt;/h2&gt;
The implementation of a job graph requires relatively few components:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;A job class&lt;/li&gt;
&lt;li&gt;A job graph container&lt;/li&gt;
&lt;li&gt;A job pool&lt;/li&gt;
&lt;li&gt;A thread pool&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
Job Class&lt;/h3&gt;
&lt;div&gt;
The job class is fairly straightforward. It serves two purposes: to package up some functionality to be executed, and have knowledge of precursor jobs and dependent jobs (&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dd492427.aspx#continuations&quot;&gt;this concept is sometimes described as continuations&lt;/a&gt;).&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The major consideration in the design of the job class is the mechanism used to sequence their operation. Ideally, you want to use some kind of OS threading primitive as opposed to some kind of user-space mechanism. The OS is in a far better position to manage threads as it has clear information of the state and dependencies of all of them, and can wake and sleep threads with minimal context switches. User space code often ends up with some kind of inefficient wake-predicate-sleep polling pattern causing a lot of wasted time and context switches.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
I therefore chose to use a C++ 11 thread library primitive: &lt;a href=&quot;http://en.cppreference.com/w/cpp/thread/promise&quot;&gt;std::promise&lt;/a&gt;&amp;nbsp;and &lt;a href=&quot;http://en.cppreference.com/w/cpp/thread/future&quot;&gt;std::future&lt;/a&gt;. A promise provides the ability to calculate some value asynchronously, in a deferred context, in the future. It represents a contract for some piece of code to provide a value based on some inputs. A future is the mechanism used to retrieve that value. The promise is the producer, the future is the client.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The promise and future abstraction provides &amp;nbsp;a good mechanism to couple jobs together. A job can provide a &quot;future&quot; to each of its dependent jobs. The dependent job uses this future to wait for the job&#39;s completion. The future could pass data, or it could solely be used to sequence computation.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
A second feature of C++ 11 that proves useful for the job class is &lt;a href=&quot;http://en.cppreference.com/w/cpp/utility/functional/function&quot;&gt;std::function&lt;/a&gt;&amp;nbsp;and lambda functions. An std::function is simply a wrapper for some callable target. My job class contains one of these to hold the job&#39;s processing kernel. It is initialised in the constructor, which allows me to pass in a lambda function when creating the job. This provides an interesting alternative to using inheritance and virtual functions, and the resultant proliferation of classes. Now, I have just one Job class, and the data handles the variation.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;Job.h:&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;s1&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt; Job;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;//! This monitors the completion of a number of jobs, and sends out a signal when they&#39;re all done&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s1&quot;&gt;class&lt;/span&gt; JobCompletionMonitor&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s1&quot;&gt;public&lt;/span&gt;:&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; JobCompletionMonitor(&lt;span class=&quot;s1&quot;&gt;void&lt;/span&gt;) :&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;m_numJobsPending&lt;/span&gt;(&lt;span class=&quot;s4&quot;&gt;0&lt;/span&gt;)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Forbidden constructors&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; JobCompletionMonitor(&lt;span class=&quot;s3&quot;&gt;JobCompletionMonitor&lt;/span&gt;&amp;amp;) = &lt;span class=&quot;s1&quot;&gt;delete&lt;/span&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p4&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;JobCompletionMonitor&lt;span class=&quot;s2&quot;&gt;&amp;amp; &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;operator&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;=(&lt;/span&gt;JobCompletionMonitor&lt;span class=&quot;s2&quot;&gt;&amp;amp;) = &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Jobs tell the monitor what&#39;s going on&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s1&quot;&gt;void&lt;/span&gt; notifyStart(&lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;* job);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s1&quot;&gt;void&lt;/span&gt; notifyFinish(&lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;* job);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Other people can find out when they&#39;re all done&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s1&quot;&gt;void&lt;/span&gt; waitForCompletion(&lt;span class=&quot;s1&quot;&gt;void&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s1&quot;&gt;bool&lt;/span&gt; allJobsFinished(&lt;span class=&quot;s1&quot;&gt;void&lt;/span&gt;) &lt;span class=&quot;s1&quot;&gt;const&lt;/span&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s1&quot;&gt;private&lt;/span&gt;:&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s5&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s5&quot;&gt;atomic_int&lt;/span&gt; m_numJobsPending;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s5&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s5&quot;&gt;condition_variable&lt;/span&gt; m_allJobsComplete;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s5&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s5&quot;&gt;mutex&lt;/span&gt; m_mutex;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; };&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;//! A self-contained job that is executed somewhere in the frame&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s1&quot;&gt;class&lt;/span&gt; Job : &lt;span class=&quot;s1&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;objects&lt;/span&gt;::&lt;span class=&quot;s3&quot;&gt;CoreObject&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s1&quot;&gt;public&lt;/span&gt;:&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Priority system&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s1&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;int&lt;/span&gt; Priority;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s1&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;Priority&lt;/span&gt; HighPriority = &lt;span class=&quot;s4&quot;&gt;1000&lt;/span&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s1&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;Priority&lt;/span&gt; AboveNormalPriority = &lt;span class=&quot;s4&quot;&gt;5000&lt;/span&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s1&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;Priority&lt;/span&gt; NormalPriority = &lt;span class=&quot;s4&quot;&gt;10000&lt;/span&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s1&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;Priority&lt;/span&gt; BelowNormalPriority = &lt;span class=&quot;s4&quot;&gt;15000&lt;/span&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s1&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;Priority&lt;/span&gt; LowPriority = &lt;span class=&quot;s4&quot;&gt;20000&lt;/span&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Permitted constructors&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Job(&lt;span class=&quot;s1&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;resources&lt;/span&gt;::&lt;span class=&quot;s3&quot;&gt;NameManager&lt;/span&gt;::&lt;span class=&quot;s3&quot;&gt;Name&lt;/span&gt;&amp;amp; name,&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s1&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s5&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s5&quot;&gt;initializer_list&lt;/span&gt;&amp;lt;&lt;span class=&quot;s5&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s5&quot;&gt;shared_ptr&lt;/span&gt;&amp;lt;&lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;&amp;gt;&amp;gt;&amp;amp; precursorJobs = {},&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s5&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s5&quot;&gt;function&lt;/span&gt;&amp;lt;&lt;span class=&quot;s1&quot;&gt;void&lt;/span&gt;(&lt;span class=&quot;s1&quot;&gt;float&lt;/span&gt;)&amp;gt; kernel = [](&lt;span class=&quot;s1&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;float&lt;/span&gt;){},&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s1&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;Priority&lt;/span&gt; priority = &lt;span class=&quot;s3&quot;&gt;NormalPriority&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ~Job();&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Forboidden constructors&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Job(&lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;&amp;amp; job) = &lt;span class=&quot;s1&quot;&gt;delete&lt;/span&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;&amp;amp; &lt;span class=&quot;s1&quot;&gt;operator&lt;/span&gt;=(&lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;&amp;amp; job) = &lt;span class=&quot;s1&quot;&gt;delete&lt;/span&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Management of dependents&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s1&quot;&gt;void&lt;/span&gt; addDependent(&lt;span class=&quot;s1&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s5&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s5&quot;&gt;shared_ptr&lt;/span&gt;&amp;lt;&lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;&amp;gt;&amp;amp; dependent);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s1&quot;&gt;void&lt;/span&gt; removeDependent(&lt;span class=&quot;s1&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s5&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s5&quot;&gt;shared_ptr&lt;/span&gt;&amp;lt;&lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;&amp;gt;&amp;amp; dependent);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Execution API&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s1&quot;&gt;void&lt;/span&gt; prepare(&lt;span class=&quot;s3&quot;&gt;JobCompletionMonitor&lt;/span&gt;* monitor);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s1&quot;&gt;bool&lt;/span&gt; canRun(&lt;span class=&quot;s1&quot;&gt;void&lt;/span&gt;) &lt;span class=&quot;s1&quot;&gt;const&lt;/span&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s1&quot;&gt;void&lt;/span&gt; execute(&lt;span class=&quot;s1&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;float&lt;/span&gt; timeStep);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s1&quot;&gt;void&lt;/span&gt; cleanup(&lt;span class=&quot;s1&quot;&gt;void&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s6&quot;&gt;// Accessors&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s1&quot;&gt;inline&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s5&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s5&quot;&gt;vector&lt;/span&gt;&amp;lt;&lt;span class=&quot;s5&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s5&quot;&gt;shared_ptr&lt;/span&gt;&amp;lt;&lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;&amp;gt;&amp;gt;&amp;amp; getDependents(&lt;span class=&quot;s1&quot;&gt;void&lt;/span&gt;) &lt;span class=&quot;s1&quot;&gt;const&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s1&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;m_dependents&lt;/span&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s1&quot;&gt;inline&lt;/span&gt; &lt;span class=&quot;s5&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s5&quot;&gt;vector&lt;/span&gt;&amp;lt;&lt;span class=&quot;s5&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s5&quot;&gt;shared_ptr&lt;/span&gt;&amp;lt;&lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;&amp;gt;&amp;gt; getPrecursorJobs(&lt;span class=&quot;s1&quot;&gt;void&lt;/span&gt;) &lt;span class=&quot;s1&quot;&gt;const&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s1&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;m_precursors&lt;/span&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p5&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;inline&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;bool&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;operator&lt;span class=&quot;s2&quot;&gt;&amp;lt;(&lt;/span&gt;const&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;amp; other) &lt;/span&gt;const&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s1&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;m_priority&lt;/span&gt; &amp;lt; other.&lt;span class=&quot;s3&quot;&gt;m_priority&lt;/span&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s1&quot;&gt;private&lt;/span&gt;:&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Connection to other jobs&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span class=&quot;s5&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;s5&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s5&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;s5&quot;&gt;shared_ptr&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;gt;&amp;gt; m_precursors; &lt;/span&gt;//!&amp;lt; The job that must complete before we can run. We are a continuation of this job&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span class=&quot;s5&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;s5&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s5&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;s5&quot;&gt;shared_ptr&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;gt;&amp;gt; m_dependents; &lt;/span&gt;//!&amp;lt; A list of all the jobs that continue after us&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Futures to sequence processing&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span class=&quot;s5&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;s5&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s5&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;s5&quot;&gt;future&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;gt;&amp;gt; m_precursorFutures; &lt;/span&gt;//!&amp;lt; The future that is used to tell us when to start - if we have a precursor&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span class=&quot;s5&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;s5&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s5&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;s5&quot;&gt;promise&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;gt;&amp;gt; m_dependentPromises; &lt;/span&gt;//!&amp;lt; The promises we fulfill to trigger other continuations&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Override this function to implement your logic&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span class=&quot;s5&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;s5&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;)&amp;gt; m_kernel; &lt;/span&gt;//!&amp;lt; A simple routine to call to implement the logic for this task&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// What is the execution priority of this job?&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span class=&quot;s3&quot;&gt;Priority&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; m_priority; &lt;/span&gt;//!&amp;lt; Execution priority of this job&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s2&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span class=&quot;s3&quot;&gt;JobCompletionMonitor&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;* m_completionMonitor = &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;nullptr&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;; &lt;/span&gt;//!&amp;lt; This object monitors the job. The job must notify it on completion&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; };&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;Job.cpp:&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;//! Have all of our jobs now finished?&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;JobCompletionMonitor&lt;/span&gt;::allJobsFinished(&lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt;) &lt;span class=&quot;s2&quot;&gt;const&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s4&quot;&gt;m_numJobsPending&lt;/span&gt; == &lt;span class=&quot;s5&quot;&gt;0&lt;/span&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;//! The job tells the monitor when it starts&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;JobCompletionMonitor&lt;/span&gt;::notifyStart(&lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;* job)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s6&quot;&gt;INC_RT_ASSERT&lt;/span&gt;(job != &lt;span class=&quot;s2&quot;&gt;nullptr&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p4&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ++&lt;/span&gt;m_numJobsPending&lt;span class=&quot;s1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;//! The job notifies the monitor that it is complete&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;JobCompletionMonitor&lt;/span&gt;::notifyFinish(&lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;* job)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s6&quot;&gt;INC_RT_ASSERT&lt;/span&gt;(job != &lt;span class=&quot;s2&quot;&gt;nullptr&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p4&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; --&lt;/span&gt;m_numJobsPending&lt;span class=&quot;s1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;if&lt;/span&gt;(&lt;span class=&quot;s4&quot;&gt;m_numJobsPending&lt;/span&gt; == &lt;span class=&quot;s5&quot;&gt;0&lt;/span&gt;)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;m_allJobsComplete&lt;/span&gt;.&lt;span class=&quot;s4&quot;&gt;notify_all&lt;/span&gt;();&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;//! Wait until all the jobs managed by this monitor are complete&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;JobCompletionMonitor&lt;/span&gt;::waitForCompletion(&lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt;)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s7&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s7&quot;&gt;unique_lock&lt;/span&gt;&amp;lt;&lt;span class=&quot;s7&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s7&quot;&gt;mutex&lt;/span&gt;&amp;gt; lock(&lt;span class=&quot;s3&quot;&gt;m_mutex&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;m_allJobsComplete&lt;/span&gt;.&lt;span class=&quot;s4&quot;&gt;wait&lt;/span&gt;(lock);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s6&quot;&gt;INC_RT_ASSERT&lt;/span&gt;(&lt;span class=&quot;s4&quot;&gt;m_numJobsPending&lt;/span&gt; == &lt;span class=&quot;s5&quot;&gt;0&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;//! Construction&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p4&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;Job&lt;span class=&quot;s1&quot;&gt;::Job(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt; &lt;/span&gt;resources&lt;span class=&quot;s1&quot;&gt;::&lt;/span&gt;NameManager&lt;span class=&quot;s1&quot;&gt;::&lt;/span&gt;Name&lt;span class=&quot;s1&quot;&gt;&amp;amp; name,&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s7&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s7&quot;&gt;initializer_list&lt;/span&gt;&amp;lt;&lt;span class=&quot;s7&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s7&quot;&gt;shared_ptr&lt;/span&gt;&amp;lt;&lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;&amp;gt;&amp;gt;&amp;amp; precursorJobs,&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s7&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s7&quot;&gt;function&lt;/span&gt;&amp;lt;&lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt;(&lt;span class=&quot;s2&quot;&gt;float&lt;/span&gt;)&amp;gt; kernel,&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;Priority&lt;/span&gt; priority) :&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; objects::&lt;span class=&quot;s3&quot;&gt;CoreObject&lt;/span&gt;(name),&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;m_precursors&lt;/span&gt;(precursorJobs),&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;m_dependents&lt;/span&gt;(),&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p4&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;m_dependentPromises&lt;span class=&quot;s1&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;m_kernel&lt;/span&gt;(kernel),&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;m_priority&lt;/span&gt;(priority)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;//! Destruction&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;::~Job()&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Add some assertions here to ensure the job has been correctly deleted&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Notify this job of a new dependent that expects to be told when this has finished&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;::addDependent(&lt;span class=&quot;s2&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s7&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s7&quot;&gt;shared_ptr&lt;/span&gt;&amp;lt;&lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;&amp;gt;&amp;amp; dependent)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s6&quot;&gt;INC_RT_ASSERT&lt;/span&gt;(dependent != &lt;span class=&quot;s2&quot;&gt;nullptr&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// If this job isn&#39;t already a dependent, then add it&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;if&lt;/span&gt;(&lt;span class=&quot;s7&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s4&quot;&gt;find&lt;/span&gt;(&lt;span class=&quot;s3&quot;&gt;m_dependents&lt;/span&gt;.&lt;span class=&quot;s4&quot;&gt;begin&lt;/span&gt;(), &lt;span class=&quot;s3&quot;&gt;m_dependents&lt;/span&gt;.&lt;span class=&quot;s4&quot;&gt;end&lt;/span&gt;(), dependent) == &lt;span class=&quot;s3&quot;&gt;m_dependents&lt;/span&gt;.&lt;span class=&quot;s4&quot;&gt;end&lt;/span&gt;())&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;m_dependents&lt;/span&gt;.&lt;span class=&quot;s4&quot;&gt;push_back&lt;/span&gt;(dependent);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Remove a dependency from this job&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;::removeDependent(&lt;span class=&quot;s2&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s7&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s7&quot;&gt;shared_ptr&lt;/span&gt;&amp;lt;&lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;&amp;gt;&amp;amp; dependent)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s6&quot;&gt;INC_RT_ASSERT&lt;/span&gt;(dependent != &lt;span class=&quot;s2&quot;&gt;nullptr&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// If this job isn&#39;t already a dependent, then add it, and re-issue futures&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;auto&lt;/span&gt; it = &lt;span class=&quot;s7&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s4&quot;&gt;find&lt;/span&gt;(&lt;span class=&quot;s3&quot;&gt;m_dependents&lt;/span&gt;.&lt;span class=&quot;s4&quot;&gt;begin&lt;/span&gt;(), &lt;span class=&quot;s3&quot;&gt;m_dependents&lt;/span&gt;.&lt;span class=&quot;s4&quot;&gt;end&lt;/span&gt;(), dependent);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;if&lt;/span&gt;(it != &lt;span class=&quot;s3&quot;&gt;m_dependents&lt;/span&gt;.&lt;span class=&quot;s4&quot;&gt;end&lt;/span&gt;())&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Remove this dependent&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;m_dependents&lt;/span&gt;.&lt;span class=&quot;s4&quot;&gt;erase&lt;/span&gt;(it);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;//! Reset the job ready for graph traversal and execution&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;::prepare(&lt;span class=&quot;s3&quot;&gt;JobCompletionMonitor&lt;/span&gt;* monitor)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s6&quot;&gt;INC_RT_ASSERT&lt;/span&gt;(monitor != &lt;span class=&quot;s2&quot;&gt;nullptr&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;m_completionMonitor&lt;/span&gt; = monitor;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Ask our precursors for a future&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;for&lt;/span&gt;(&lt;span class=&quot;s2&quot;&gt;auto&lt;/span&gt;&amp;amp; precursor : m_precursors)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; precursor-&amp;gt;&lt;span class=&quot;s3&quot;&gt;m_dependentPromises&lt;/span&gt;.&lt;span class=&quot;s4&quot;&gt;push_back&lt;/span&gt;(&lt;span class=&quot;s7&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s7&quot;&gt;promise&lt;/span&gt;&amp;lt;&lt;span class=&quot;s2&quot;&gt;int&lt;/span&gt;&amp;gt;());&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;m_precursorFutures&lt;/span&gt;.&lt;span class=&quot;s4&quot;&gt;push_back&lt;/span&gt;(precursor-&amp;gt;&lt;span class=&quot;s3&quot;&gt;m_dependentPromises&lt;/span&gt;.&lt;span class=&quot;s4&quot;&gt;back&lt;/span&gt;().&lt;span class=&quot;s4&quot;&gt;get_future&lt;/span&gt;());&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;//! Clean up after execution. Remove all the promises and futures&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;::cleanup(&lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt;)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p4&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;m_precursorFutures&lt;span class=&quot;s1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;s4&quot;&gt;clear&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p4&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;m_dependentPromises&lt;span class=&quot;s1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;s4&quot;&gt;clear&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Can this job run? Have all of our futures been satisfied?&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;::canRun(&lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt;) &lt;span class=&quot;s2&quot;&gt;const&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;for&lt;/span&gt;(&lt;span class=&quot;s2&quot;&gt;auto&lt;/span&gt;&amp;amp; it : m_precursorFutures)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;if&lt;/span&gt;(it.&lt;span class=&quot;s4&quot;&gt;valid&lt;/span&gt;() == &lt;span class=&quot;s2&quot;&gt;false&lt;/span&gt;)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;false&lt;/span&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;true&lt;/span&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Actually run this job&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;::execute(&lt;span class=&quot;s2&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;float&lt;/span&gt; timeStep)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Wait to receive the promised values from all precursor jobs&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;for&lt;/span&gt;(&lt;span class=&quot;s2&quot;&gt;auto&lt;/span&gt;&amp;amp; future : m_precursorFutures)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; future.&lt;span class=&quot;s4&quot;&gt;wait&lt;/span&gt;();&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; (&lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt;)future.&lt;span class=&quot;s4&quot;&gt;get&lt;/span&gt;();&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Do our actual work&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;m_kernel&lt;/span&gt;(&lt;span class=&quot;s4&quot;&gt;timeStep&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Fulfill promises to our children&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;for&lt;/span&gt;(&lt;span class=&quot;s2&quot;&gt;auto&lt;/span&gt;&amp;amp; promise : m_dependentPromises)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; promise.&lt;span class=&quot;s4&quot;&gt;set_value&lt;/span&gt;(&lt;span class=&quot;s5&quot;&gt;1&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p4&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;m_completionMonitor&lt;span class=&quot;s1&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;s8&quot;&gt;notifyFinish&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Now that we are done, clear out all of the stale old futures we were waiting for -&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// prepare() will re-issue them next time around&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p4&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;m_precursorFutures&lt;span class=&quot;s1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;s4&quot;&gt;clear&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;
Job Graph&lt;/h3&gt;
&lt;div&gt;
The job graph really has few responsibilities: To contain the jobs, traverse the graph and manage the resources needed for execution.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The job graphs are contained in a simple graph structure. I may later shift to a more capable container such as &lt;a href=&quot;http://www.boost.org/doc/libs/1_51_0/libs/graph/doc/index.html&quot;&gt;boost::graph&lt;/a&gt;.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The main task at hand for the job graph is to traverse the graph, pushing all of the jobs into an ordered pool ready for execution. A thread pool then pulls jobs from this pool when they are ready for execution.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;JobGraph.h:&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;// A graph structure holding all the jobs and conditions&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;class&lt;/span&gt; JobGraph&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;public&lt;/span&gt;:&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; JobGraph(&lt;span class=&quot;s2&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;size_t&lt;/span&gt; numThreads);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ~JobGraph();&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt; add(&lt;span class=&quot;s2&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s3&quot;&gt;shared_ptr&lt;/span&gt;&amp;lt;&lt;span class=&quot;s4&quot;&gt;Job&lt;/span&gt;&amp;gt;&amp;amp; job);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt; remove(&lt;span class=&quot;s2&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s3&quot;&gt;shared_ptr&lt;/span&gt;&amp;lt;&lt;span class=&quot;s4&quot;&gt;Job&lt;/span&gt;&amp;gt;&amp;amp; job);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt; execute(&lt;span class=&quot;s2&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;float&lt;/span&gt; timeStep);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;private&lt;/span&gt;:&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// At the start of the frame, the job graph is traversed and all the jobs to be processed are placed into this pool&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s4&quot;&gt;JobPool&lt;/span&gt; m_jobPool;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// This is a pool of threads which work on executing those jobs&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Threads are free to steal jobs from the overall pool to keep things ticking forwards&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s4&quot;&gt;ThreadPool&lt;/span&gt; m_threadPool;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// This is a special root-level job&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s3&quot;&gt;shared_ptr&lt;/span&gt;&amp;lt;&lt;span class=&quot;s4&quot;&gt;Job&lt;/span&gt;&amp;gt; m_rootJob;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Need to measure when all jobs have completed&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// (not just dispatched - *completed*)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s4&quot;&gt;JobCompletionMonitor&lt;/span&gt; m_jobCompletionMonitor;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Mutually exclude operations like construction, adding jobs and execution&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s3&quot;&gt;mutex&lt;/span&gt; m_mutex;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Does a (parent) job exist within the graph?&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s3&quot;&gt;unordered_map&lt;/span&gt;&amp;lt;&lt;span class=&quot;s4&quot;&gt;Job&lt;/span&gt;*, &lt;span class=&quot;s2&quot;&gt;bool&lt;/span&gt;&amp;gt; m_jobContained;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; };&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;JobGraph.cpp:&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;// A generic minimal visitor pattern&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;class&lt;/span&gt; JobGraphVisitor&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;public&lt;/span&gt;:&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;virtual&lt;/span&gt; ~JobGraphVisitor() {}&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt; traverse(&lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;* job)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s4&quot;&gt;INC_RT_ASSERT&lt;/span&gt;(job != &lt;span class=&quot;s2&quot;&gt;nullptr&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s5&quot;&gt;visit&lt;/span&gt;(job);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;for&lt;/span&gt;(&lt;span class=&quot;s2&quot;&gt;auto&lt;/span&gt; child : job-&amp;gt;getDependents())&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s5&quot;&gt;traverse&lt;/span&gt;(child.&lt;span class=&quot;s6&quot;&gt;get&lt;/span&gt;());&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; };&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;private&lt;/span&gt;:&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt; visit(&lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;* job) {}&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; };&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Visit with a view to pushing a job to the task pool&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;class&lt;/span&gt; PushJobVisitor : &lt;span class=&quot;s2&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;JobGraphVisitor&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;public&lt;/span&gt;:&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;inline&lt;/span&gt; PushJobVisitor(&lt;span class=&quot;s3&quot;&gt;JobPool&lt;/span&gt;&amp;amp; jobPool, &lt;span class=&quot;s2&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;float&lt;/span&gt; timeStep, &lt;span class=&quot;s3&quot;&gt;JobCompletionMonitor&lt;/span&gt;* jobCompletionMonitor) :&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;m_jobPool&lt;/span&gt;(jobPool),&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;m_timeStep&lt;/span&gt;(timeStep),&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;m_jobCompletionMonitor&lt;/span&gt;(jobCompletionMonitor)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;private&lt;/span&gt;:&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;JobPool&lt;/span&gt;&amp;amp; m_jobPool;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;float&lt;/span&gt; m_timeStep;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;JobCompletionMonitor&lt;/span&gt;* &lt;span class=&quot;s2&quot;&gt;const&lt;/span&gt; m_jobCompletionMonitor;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s7&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s7&quot;&gt;unordered_map&lt;/span&gt;&amp;lt;&lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;*, &lt;span class=&quot;s2&quot;&gt;bool&lt;/span&gt;&amp;gt; m_jobPushed;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt; visit(Job* job) override&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;if&lt;/span&gt;(&lt;span class=&quot;s3&quot;&gt;m_jobPushed&lt;/span&gt;[&lt;span class=&quot;s6&quot;&gt;job&lt;/span&gt;] == &lt;span class=&quot;s2&quot;&gt;false&lt;/span&gt;)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;m_jobCompletionMonitor&lt;/span&gt;-&amp;gt;&lt;span class=&quot;s5&quot;&gt;notifyStart&lt;/span&gt;(job);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;m_jobPool&lt;/span&gt;.&lt;span class=&quot;s5&quot;&gt;push&lt;/span&gt;(job);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;m_jobPushed&lt;/span&gt;[&lt;span class=&quot;s6&quot;&gt;job&lt;/span&gt;] = &lt;span class=&quot;s2&quot;&gt;true&lt;/span&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; };&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Reset jobs in preparation&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;class&lt;/span&gt; ResetJobVisitor : &lt;span class=&quot;s2&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;JobGraphVisitor&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;public&lt;/span&gt;:&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;inline&lt;/span&gt; ResetJobVisitor(&lt;span class=&quot;s3&quot;&gt;JobCompletionMonitor&lt;/span&gt;* jobCompletionMonitor) :&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;m_jobCompletionMonitor&lt;/span&gt;(jobCompletionMonitor)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;private&lt;/span&gt;:&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;JobCompletionMonitor&lt;/span&gt;* &lt;span class=&quot;s2&quot;&gt;const&lt;/span&gt; m_jobCompletionMonitor;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt; visit(Job* job) override&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; job-&amp;gt;&lt;span class=&quot;s5&quot;&gt;prepare&lt;/span&gt;(&lt;span class=&quot;s3&quot;&gt;m_jobCompletionMonitor&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; };&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;//! Post-execution by-product clean-up&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;class&lt;/span&gt; CleanUpJobVisitor : &lt;span class=&quot;s2&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;JobGraphVisitor&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;public&lt;/span&gt;:&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;inline&lt;/span&gt; CleanUpJobVisitor(&lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt;)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;private&lt;/span&gt;:&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt; visit(Job* job) override&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; job-&amp;gt;&lt;span class=&quot;s5&quot;&gt;cleanup&lt;/span&gt;();&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; };&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Construction&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;JobGraph&lt;/span&gt;::JobGraph(&lt;span class=&quot;s2&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s7&quot;&gt;size_t&lt;/span&gt; numThreads) :&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;m_jobPool&lt;/span&gt;(),&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;m_threadPool&lt;/span&gt;(numThreads, &lt;span class=&quot;s3&quot;&gt;m_jobPool&lt;/span&gt;),&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;m_rootJob&lt;/span&gt;(&lt;span class=&quot;s2&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;(&lt;span class=&quot;s3&quot;&gt;resources&lt;/span&gt;::&lt;span class=&quot;s5&quot;&gt;getUniqueName&lt;/span&gt;(&lt;span class=&quot;s8&quot;&gt;&quot;Root Job&quot;&lt;/span&gt;)))&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s4&quot;&gt;INC_RT_ASSERT&lt;/span&gt;(numThreads != &lt;span class=&quot;s9&quot;&gt;0&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s7&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s7&quot;&gt;unique_lock&lt;/span&gt;&amp;lt;&lt;span class=&quot;s7&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s7&quot;&gt;mutex&lt;/span&gt;&amp;gt; lock(&lt;span class=&quot;s3&quot;&gt;m_mutex&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Destruction&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;JobGraph&lt;/span&gt;::~JobGraph()&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s4&quot;&gt;INC_RT_ASSERT&lt;/span&gt;(&lt;span class=&quot;s3&quot;&gt;m_jobPool&lt;/span&gt;.&lt;span class=&quot;s5&quot;&gt;jobAvailable&lt;/span&gt;() == &lt;span class=&quot;s2&quot;&gt;false&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;m_jobPool&lt;/span&gt;.&lt;span class=&quot;s5&quot;&gt;shutdown&lt;/span&gt;();&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;m_threadPool&lt;/span&gt;.&lt;span class=&quot;s5&quot;&gt;shutdown&lt;/span&gt;();&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s7&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s7&quot;&gt;this_thread&lt;/span&gt;::&lt;span class=&quot;s6&quot;&gt;yield&lt;/span&gt;();&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Add a job to the graph&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;JobGraph&lt;/span&gt;::add(&lt;span class=&quot;s2&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s7&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s7&quot;&gt;shared_ptr&lt;/span&gt;&amp;lt;&lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;&amp;gt;&amp;amp; job)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s4&quot;&gt;INC_RT_ASSERT&lt;/span&gt;(job != &lt;span class=&quot;s2&quot;&gt;nullptr&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s7&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s7&quot;&gt;unique_lock&lt;/span&gt;&amp;lt;&lt;span class=&quot;s7&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s7&quot;&gt;mutex&lt;/span&gt;&amp;gt; lock(&lt;span class=&quot;s3&quot;&gt;m_mutex&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;if&lt;/span&gt;(job-&amp;gt;&lt;span class=&quot;s5&quot;&gt;getPrecursorJobs&lt;/span&gt;().&lt;span class=&quot;s6&quot;&gt;size&lt;/span&gt;() == &lt;span class=&quot;s9&quot;&gt;0&lt;/span&gt;)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// A null precursor means that it&#39;s a root level task that lives under our&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// special root job&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;m_rootJob&lt;/span&gt;-&amp;gt;&lt;span class=&quot;s5&quot;&gt;addDependent&lt;/span&gt;(job);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;else&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Assert to ensure that the parent job actually exists within the graph!&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;for&lt;/span&gt;(&lt;span class=&quot;s2&quot;&gt;auto&lt;/span&gt;&amp;amp; precursor : job-&amp;gt;getPrecursorJobs())&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s4&quot;&gt;INC_RT_ASSERT&lt;/span&gt;(&lt;span class=&quot;s3&quot;&gt;m_jobContained&lt;/span&gt;[precursor.&lt;span class=&quot;s6&quot;&gt;get&lt;/span&gt;()]);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; precursor-&amp;gt;&lt;span class=&quot;s5&quot;&gt;addDependent&lt;/span&gt;(job);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;m_jobContained&lt;/span&gt;[&lt;span class=&quot;s6&quot;&gt;job&lt;/span&gt;.&lt;span class=&quot;s6&quot;&gt;get&lt;/span&gt;()] = &lt;span class=&quot;s2&quot;&gt;true&lt;/span&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Remove a job from the graph&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;JobGraph&lt;/span&gt;::remove(&lt;span class=&quot;s2&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s7&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s7&quot;&gt;shared_ptr&lt;/span&gt;&amp;lt;&lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;&amp;gt;&amp;amp; job)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s4&quot;&gt;INC_RT_ASSERT&lt;/span&gt;(job != &lt;span class=&quot;s2&quot;&gt;nullptr&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s7&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s7&quot;&gt;unique_lock&lt;/span&gt;&amp;lt;&lt;span class=&quot;s7&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s7&quot;&gt;mutex&lt;/span&gt;&amp;gt; lock(&lt;span class=&quot;s3&quot;&gt;m_mutex&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;if&lt;/span&gt;(job-&amp;gt;&lt;span class=&quot;s5&quot;&gt;getPrecursorJobs&lt;/span&gt;().&lt;span class=&quot;s6&quot;&gt;size&lt;/span&gt;() == &lt;span class=&quot;s9&quot;&gt;0&lt;/span&gt;)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;m_rootJob&lt;/span&gt;-&amp;gt;&lt;span class=&quot;s5&quot;&gt;removeDependent&lt;/span&gt;(job);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;else&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;for&lt;/span&gt;(&lt;span class=&quot;s2&quot;&gt;auto&lt;/span&gt;&amp;amp; precursor : job-&amp;gt;getPrecursorJobs())&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; precursor-&amp;gt;&lt;span class=&quot;s5&quot;&gt;removeDependent&lt;/span&gt;(job);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;m_jobContained&lt;/span&gt;[&lt;span class=&quot;s6&quot;&gt;job&lt;/span&gt;.&lt;span class=&quot;s6&quot;&gt;get&lt;/span&gt;()] = &lt;span class=&quot;s2&quot;&gt;false&lt;/span&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Execute all jobs in the graph&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;JobGraph&lt;/span&gt;::execute(&lt;span class=&quot;s2&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;float&lt;/span&gt; timeStep)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s7&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s7&quot;&gt;unique_lock&lt;/span&gt;&amp;lt;&lt;span class=&quot;s7&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s7&quot;&gt;mutex&lt;/span&gt;&amp;gt; lock(&lt;span class=&quot;s3&quot;&gt;m_mutex&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Make sure the job queue is fully empty from last time&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s4&quot;&gt;INC_RT_ASSERT&lt;/span&gt;(&lt;span class=&quot;s3&quot;&gt;m_jobPool&lt;/span&gt;.&lt;span class=&quot;s5&quot;&gt;jobAvailable&lt;/span&gt;() == &lt;span class=&quot;s2&quot;&gt;false&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Get it all reset ready for execution&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p4&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;ResetJobVisitor&lt;span class=&quot;s1&quot;&gt; resetJobVisitor(&amp;amp;&lt;/span&gt;m_jobCompletionMonitor&lt;span class=&quot;s1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; resetJobVisitor.&lt;span class=&quot;s5&quot;&gt;traverse&lt;/span&gt;(&lt;span class=&quot;s3&quot;&gt;m_rootJob&lt;/span&gt;.&lt;span class=&quot;s6&quot;&gt;get&lt;/span&gt;());&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Traverse the whole job graph, pushing the jobs into the task pool&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;PushJobVisitor&lt;/span&gt; pushJobVisitor(&lt;span class=&quot;s3&quot;&gt;m_jobPool&lt;/span&gt;, timeStep, &amp;amp;&lt;span class=&quot;s3&quot;&gt;m_jobCompletionMonitor&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; pushJobVisitor.&lt;span class=&quot;s5&quot;&gt;traverse&lt;/span&gt;(&lt;span class=&quot;s3&quot;&gt;m_rootJob&lt;/span&gt;.&lt;span class=&quot;s6&quot;&gt;get&lt;/span&gt;());&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// (Note that tasks will be consumed asynchronously as soon as we start to push them)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p4&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;m_jobCompletionMonitor&lt;span class=&quot;s1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;s5&quot;&gt;waitForCompletion&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// We should be all done now. Nothing should be here&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s4&quot;&gt;INC_RT_ASSERT&lt;/span&gt;(&lt;span class=&quot;s3&quot;&gt;m_jobPool&lt;/span&gt;.&lt;span class=&quot;s5&quot;&gt;jobAvailable&lt;/span&gt;() == &lt;span class=&quot;s2&quot;&gt;false&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Get it all cleaned up ready for next time&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;CleanUpJobVisitor&lt;/span&gt; cleanUpVisitor;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; cleanUpVisitor.&lt;span class=&quot;s5&quot;&gt;traverse&lt;/span&gt;(&lt;span class=&quot;s3&quot;&gt;m_rootJob&lt;/span&gt;.&lt;span class=&quot;s6&quot;&gt;get&lt;/span&gt;());&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;
Job Pool&lt;/h3&gt;
&lt;div&gt;
It is initially tempting to simply traverse the graph, push all of the jobs out for execution, and let the OS arbitrate everything. There are a few difficulties here. First of all, unless your target platform&#39;s runtime explicitly models tasks or jobs, this tends to lead to mass thread creation and destruction - a substantial overhead. Secondly, you may wish to cancel the execution of jobs after a precursor has completed. Thirdly, it makes little sense to dispatch many jobs for execution that have no chance of execution. They will just immediately hit a threading hazard and context-switch away. Finally, consider the case where you have N cores and N+1 jobs. Job 0 does some work, and jobs 1..N wait on job 0. Imagine if your target platform has a pooly-implemented runtime, and assigns jobs 1..N to cores instead of job 0. Those jobs may wait, and job 0 may not execute. This case is unlikely in a well-implemented runtime, but it is a risk, and why present code that is inherently at risk?&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The job pool is simply an std::set of jobs, ordered by job priority. Whenever a thread in the thread pool wakes up, it pops the first (highest priority) job from the pool and executes it.&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;JobPool.h:&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;// This represents a pool of tasks that need doing, for all threads to&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// pull from (and therefore work-steal from)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;class&lt;/span&gt; JobPool&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;public&lt;/span&gt;:&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; JobPool(&lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; JobPool(&lt;span class=&quot;s3&quot;&gt;JobPool&lt;/span&gt;&amp;amp;) = &lt;span class=&quot;s2&quot;&gt;delete&lt;/span&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;JobPool&lt;/span&gt;&amp;amp; &lt;span class=&quot;s2&quot;&gt;operator&lt;/span&gt;=(&lt;span class=&quot;s3&quot;&gt;JobPool&lt;/span&gt;&amp;amp;) = &lt;span class=&quot;s2&quot;&gt;delete&lt;/span&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;bool&lt;/span&gt; jobAvailable(&lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt; push(&lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;* job);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;* pop(&lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt; waitForJob(&lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;bool&lt;/span&gt; shouldTerminate(&lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt; shutdown(&lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;private&lt;/span&gt;:&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;//! This gets notified when a task is pushed, to allow the other consuming&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;//! threads to wake up&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s4&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s4&quot;&gt;condition_variable&lt;/span&gt; m_jobPushNotification;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s4&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s4&quot;&gt;condition_variable&lt;/span&gt; m_queueEmptyNotification;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;//! We maintain a set of jobs, so that we can find the first, highest-priority job&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;//! that is in an executable state&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s4&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s4&quot;&gt;set&lt;/span&gt;&amp;lt;&lt;span class=&quot;s3&quot;&gt;Job&lt;/span&gt;*&amp;gt; m_jobs;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;//! This mutex is used to ensure thread safety when pushing a job in or pulling it out&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s4&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s4&quot;&gt;mutex&lt;/span&gt; m_mutex;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;//! Used when it&#39;s time to shut down&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s4&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s4&quot;&gt;atomic&lt;/span&gt;&amp;lt;&lt;span class=&quot;s2&quot;&gt;bool&lt;/span&gt;&amp;gt; m_shouldTerminate;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; };&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;JobPool.cpp:&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;// Construct it&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;JobPool&lt;/span&gt;::JobPool() :&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;m_shouldTerminate&lt;span class=&quot;s1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s3&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p4&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// A consumer calls this function to wait for notification via the condition_variable of a new task&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;JobPool&lt;/span&gt;::waitForJob(&lt;span class=&quot;s3&quot;&gt;void&lt;/span&gt;)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s4&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s4&quot;&gt;unique_lock&lt;/span&gt;&amp;lt;&lt;span class=&quot;s4&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s4&quot;&gt;mutex&lt;/span&gt;&amp;gt; lock(&lt;span class=&quot;s2&quot;&gt;m_mutex&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;m_jobPushNotification&lt;/span&gt;.&lt;span class=&quot;s5&quot;&gt;wait_for&lt;/span&gt;(lock, &lt;span class=&quot;s4&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s4&quot;&gt;chrono&lt;/span&gt;::&lt;span class=&quot;s4&quot;&gt;milliseconds&lt;/span&gt;(&lt;span class=&quot;s6&quot;&gt;100&lt;/span&gt;));&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p4&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// The above timeout means that spurious wakeup is possible&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p4&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Is there a job available in the set?&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;JobPool&lt;/span&gt;::jobAvailable(&lt;span class=&quot;s3&quot;&gt;void&lt;/span&gt;)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s4&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s4&quot;&gt;lock_guard&lt;/span&gt;&amp;lt;&lt;span class=&quot;s4&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s4&quot;&gt;mutex&lt;/span&gt;&amp;gt; lock(&lt;span class=&quot;s2&quot;&gt;m_mutex&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;m_jobs&lt;/span&gt;.&lt;span class=&quot;s5&quot;&gt;empty&lt;/span&gt;() == &lt;span class=&quot;s3&quot;&gt;false&lt;/span&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p4&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Push a new job into the pool&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;JobPool&lt;/span&gt;::push(&lt;span class=&quot;s2&quot;&gt;Job&lt;/span&gt;* job)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s7&quot;&gt;INC_RT_ASSERT&lt;/span&gt;(job != &lt;span class=&quot;s3&quot;&gt;nullptr&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s4&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s4&quot;&gt;lock_guard&lt;/span&gt;&amp;lt;&lt;span class=&quot;s4&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s4&quot;&gt;mutex&lt;/span&gt;&amp;gt; lock(&lt;span class=&quot;s2&quot;&gt;m_mutex&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p4&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s7&quot;&gt;INC_RT_ASSERT&lt;/span&gt;(&lt;span class=&quot;s5&quot;&gt;m_shouldTerminate&lt;/span&gt; == &lt;span class=&quot;s3&quot;&gt;false&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;m_jobs&lt;/span&gt;.&lt;span class=&quot;s5&quot;&gt;insert&lt;/span&gt;(job);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;m_jobPushNotification&lt;span class=&quot;s1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;s5&quot;&gt;notify_one&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p4&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Try to return an executable job from the pool&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;Job&lt;/span&gt;* &lt;span class=&quot;s2&quot;&gt;JobPool&lt;/span&gt;::pop(&lt;span class=&quot;s3&quot;&gt;void&lt;/span&gt;)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s4&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s4&quot;&gt;lock_guard&lt;/span&gt;&amp;lt;&lt;span class=&quot;s4&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s4&quot;&gt;mutex&lt;/span&gt;&amp;gt; lock(&lt;span class=&quot;s2&quot;&gt;m_mutex&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;if&lt;/span&gt;(&lt;span class=&quot;s2&quot;&gt;m_jobs&lt;/span&gt;.&lt;span class=&quot;s5&quot;&gt;empty&lt;/span&gt;())&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Nothing to run!&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;nullptr&lt;/span&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;else&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Find the highest priority job that can run&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;for&lt;/span&gt;(&lt;span class=&quot;s3&quot;&gt;auto&lt;/span&gt; job : m_jobs)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;if&lt;/span&gt;(job-&amp;gt;&lt;span class=&quot;s8&quot;&gt;canRun&lt;/span&gt;())&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;m_jobs&lt;/span&gt;.&lt;span class=&quot;s5&quot;&gt;erase&lt;/span&gt;(job);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;return&lt;/span&gt; job;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p4&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// It is possible that we&#39;re asked for a job but none are able to run... yet&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;nullptr&lt;/span&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p4&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;//! Should we terminate now?&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;JobPool&lt;/span&gt;::shouldTerminate(&lt;span class=&quot;s3&quot;&gt;void&lt;/span&gt;)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p5&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;&lt;span class=&quot;s3&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt; &lt;/span&gt;m_shouldTerminate&lt;span class=&quot;s1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p4&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;//! Send termination message&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;JobPool&lt;/span&gt;::shutdown(&lt;span class=&quot;s3&quot;&gt;void&lt;/span&gt;)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s4&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s4&quot;&gt;lock_guard&lt;/span&gt;&amp;lt;&lt;span class=&quot;s4&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s4&quot;&gt;mutex&lt;/span&gt;&amp;gt; lock(&lt;span class=&quot;s2&quot;&gt;m_mutex&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;m_shouldTerminate&lt;span class=&quot;s1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;s3&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;m_jobs&lt;/span&gt;.&lt;span class=&quot;s5&quot;&gt;clear&lt;/span&gt;();&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;m_jobPushNotification&lt;span class=&quot;s1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;s5&quot;&gt;notify_all&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;
Thread Pool&lt;/h3&gt;
&lt;div&gt;
The purpose of the thread pool is to provide a persistent set of threads capable of executing jobs, saving on the cost of thread creation and destruction. These threads pull jobs from the job pool until they are asked to terminate.&lt;/div&gt;
&lt;h4&gt;
Spurious Wakeup&lt;/h4&gt;
&lt;div&gt;
The threads in the thread pool wait on an std::condition_variable to notify them on the availability of a job. It is important to consider the possibility of&amp;nbsp;&lt;a href=&quot;http://en.wikipedia.org/wiki/Spurious_wakeup&quot;&gt;spurious wakeup&lt;/a&gt;&amp;nbsp;in this system. Therefore, when a thread wakes up, it must ensure a job actually exists in the pool to be executed.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
I actually deliberately allow the std::condition_variable::wait() to time out after 100 ms. The rationale for this is that some operating systems become suspicious of threads that sleep for long periods of time. For stability reasons, I prefer my system to wake up unneccesarily and to service the outer thread loop than wait for infinite amounts of time. This therefore deliberately introduces some degree of spurious wakeup into the system.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;ThreadPool.h:&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;// A pool of threads hungry to execute tasks&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;class&lt;/span&gt; ThreadPool&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;public&lt;/span&gt;:&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ThreadPool(&lt;span class=&quot;s2&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s3&quot;&gt;size_t&lt;/span&gt; numThreads, &lt;span class=&quot;s4&quot;&gt;JobPool&lt;/span&gt;&amp;amp; jobPool);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ~ThreadPool();&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt; shutdown(&lt;span class=&quot;s2&quot;&gt;void&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;private&lt;/span&gt;:&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;//! The set of threads in the thread pool&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s3&quot;&gt;vector&lt;/span&gt;&amp;lt;&lt;span class=&quot;s3&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s3&quot;&gt;thread&lt;/span&gt;&amp;gt; m_threads;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; };&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;ThreadPool.cpp:&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;// Construction / destruction&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;ThreadPool&lt;/span&gt;::ThreadPool(&lt;span class=&quot;s3&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;s4&quot;&gt;size_t&lt;/span&gt; numThreads, &lt;span class=&quot;s2&quot;&gt;JobPool&lt;/span&gt;&amp;amp; jobPool)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;for&lt;/span&gt;(&lt;span class=&quot;s4&quot;&gt;size_t&lt;/span&gt; thread = &lt;span class=&quot;s5&quot;&gt;0&lt;/span&gt;; thread &amp;lt; numThreads; ++thread)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;m_threads&lt;/span&gt;.&lt;span class=&quot;s6&quot;&gt;push_back&lt;/span&gt;(&lt;span class=&quot;s4&quot;&gt;std&lt;/span&gt;::&lt;span class=&quot;s4&quot;&gt;thread&lt;/span&gt;([](&lt;span class=&quot;s2&quot;&gt;JobPool&lt;/span&gt;* jobPool)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;for&lt;/span&gt;(;;)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Sleep, until a job is available&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// (use a condition_variable here)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; jobPool-&amp;gt;&lt;span class=&quot;s7&quot;&gt;waitForJob&lt;/span&gt;();&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Have we been told to shut down?&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;if&lt;/span&gt;(jobPool-&amp;gt;&lt;span class=&quot;s7&quot;&gt;shouldTerminate&lt;/span&gt;())&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;return&lt;/span&gt;;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Pull a job out of the task pool and execute it&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;if&lt;/span&gt;(jobPool-&amp;gt;&lt;span class=&quot;s7&quot;&gt;jobAvailable&lt;/span&gt;())&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Whilst we&#39;d prefer to execute task() here, instead we have to do&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// the pop-and-execute as an atomic-like operation to avoid&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// two threads popping the same task, or one thread popping&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// a task that the other thread expected to receive&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;Job&lt;/span&gt;* job = jobPool-&amp;gt;&lt;span class=&quot;s7&quot;&gt;pop&lt;/span&gt;();&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;if&lt;/span&gt;(job != &lt;span class=&quot;s3&quot;&gt;nullptr&lt;/span&gt;)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Clearly the correct time step should be plumbed here&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; job-&amp;gt;&lt;span class=&quot;s7&quot;&gt;execute&lt;/span&gt;(&lt;span class=&quot;s5&quot;&gt;1.0f&lt;/span&gt; / &lt;span class=&quot;s5&quot;&gt;30.0f&lt;/span&gt;);&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }, &amp;amp;jobPool));&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s2&quot;&gt;ThreadPool&lt;/span&gt;::~ThreadPool()&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p3&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt;// Shutdown the threads. You must have told the JobPool to terminate&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;ThreadPool&lt;/span&gt;::shutdown(&lt;span class=&quot;s3&quot;&gt;void&lt;/span&gt;)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span class=&quot;s3&quot;&gt;for&lt;/span&gt;(&lt;span class=&quot;s3&quot;&gt;auto&lt;/span&gt;&amp;amp; thread : m_threads)&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; thread.&lt;span class=&quot;s6&quot;&gt;join&lt;/span&gt;();&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;p2&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;
Findings&lt;/h2&gt;
&lt;div&gt;
The new C++ 11 libraries largely made this system easy and quick to implement. The libraries are quite clearly defined, unobtrusive, easy to use with few dependencies.&lt;br /&gt;
&lt;br /&gt;
One of the main difficulties encountered in the implementation of this system is simply the life cycles of the C++ 11 std::promises and std::futures. Their life cycles are not clearly documented and they can be difficult to reason about. It was only by reading the STL code that I found these primitives fundamentally hold a &quot;use and discard&quot; policy. This leads to the need for some code to create and destroy these resources each frame. Note that this may possibly vary across platforms, but this seems the best least-common-denominator assumption. This is largely the reason I avoided the use of&amp;nbsp;&lt;a href=&quot;http://en.cppreference.com/w/cpp/thread/packaged_task&quot;&gt;std::packaged_task&lt;/a&gt;. With things like move semantics transferring the object between threads and queues, it becomes very difficult to reason about the life cycle of the object! Furthermore, once you have your own job pool and thread pool, it largely obviates the need for this class. This class only seems useful for &quot;go and load some assets on a thread&quot; type work.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The system itself has thus far proven stable. I have unit tests for a variety of graph configurations, which all pass, and it successfully manages to run my current engine. This engine is in its infancy, and so has not massively load tested this system... but, ultimately, this is meant to be an illustrative, exploratory post!&lt;br /&gt;
&amp;nbsp;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tomhammersley.blogspot.com/feeds/4793781850690362310/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomhammersley.blogspot.com/2012/11/job-graphs-in-c-11.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/4793781850690362310'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/4793781850690362310'/><link rel='alternate' type='text/html' href='http://tomhammersley.blogspot.com/2012/11/job-graphs-in-c-11.html' title='Job Graphs in C++ 11'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1191561667656967116.post-6806130461226514308</id><published>2012-05-17T21:47:00.000+01:00</published><updated>2012-05-17T21:47:04.163+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="C++"/><category scheme="http://www.blogger.com/atom/ns#" term="Debugging"/><category scheme="http://www.blogger.com/atom/ns#" term="Observations"/><title type='text'>The Coder-Trap of Hypotheses</title><content type='html'>As my project is getting towards the end, again, I&#39;m doing a fair bit of debugging. Every so often, a horrible bug crops up that takes a few days, a week, two weeks to fix. Every time I have one, I try to think, on reflection, what could I have done to fix it quicker?&lt;br /&gt;
&lt;br /&gt;
I&#39;ve noticed a pattern emerging.&lt;br /&gt;
&lt;br /&gt;
Briefly, bugs take me longer to fix when I allow myself to be seduced into chasing half-formed hypotheses as to what the bug is. These hypotheses often prove ill-founded, leading to wasted time that doesn&#39;t often add real data or evidence to your bug search. Really, those intermediate hypotheses are little more than speculation or conjecture.&lt;br /&gt;
&lt;br /&gt;
I&#39;m becoming increasingly aware that the more effective strategy is not to consider hypotheses until as late as possible; instead, concentrate on gathering data, evidence and devising test fixtures. This is a very difficult discipline as people naturally love to formulate hypotheses to explain things. They are seductive. They feel like you&#39;ve found a short-cut to the solution, you&#39;ve caught your quarry, the tension of the bug fix is over. You get to announce your triumph.&lt;br /&gt;
&lt;br /&gt;
But it&#39;s rare that you fix the most difficult bugs with a single brilliant moment of insight. More often, it takes hours of analysis and evidence gathering. That&#39;s the most reliable way to reach a well-founded hypothesis that completely fixes the bug, rather than a partial fix, a temporary fix or a heisenbug fix.</content><link rel='replies' type='application/atom+xml' href='http://tomhammersley.blogspot.com/feeds/6806130461226514308/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomhammersley.blogspot.com/2012/05/coder-trap-of-hypotheses.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/6806130461226514308'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/6806130461226514308'/><link rel='alternate' type='text/html' href='http://tomhammersley.blogspot.com/2012/05/coder-trap-of-hypotheses.html' title='The Coder-Trap of Hypotheses'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1191561667656967116.post-319763994987524403</id><published>2012-04-12T13:53:00.001+01:00</published><updated>2012-04-12T13:55:09.254+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Observations"/><title type='text'>Interruption Handling Techniques for Programmers</title><content type='html'>Once more, I find myself in the post-alpha run to the finish line. And once again, I find myself getting busier and busier as the completion date looms.&lt;br /&gt;
&lt;br /&gt;
One of the most challenging issues at this time is managing the stream of traffic to your desk. Other people are very busy too. People have questions. People need answers. And answering those questions takes time away from handling your own workload, allowing it to multiply like bacteria. I find programmers tend to employ several archetypal techniques to handle those interruptions:&lt;br /&gt;
&lt;br /&gt;
1. &lt;strong&gt;Just help them&lt;/strong&gt;. Indulge them. Offer them as much help as you can. Get their problem fixed, as it helps the team move forward. Really, this is the ideal strategy for the whole project. Someone has come to you with a problem, they may be at their wits end, you should help them fix it.&lt;br /&gt;
&lt;br /&gt;
The problem is that it&#39;s a win-win-lose proposition. It&#39;s a win for the individual, it&#39;s a win for the team, but it&#39;s a lose for you. &lt;br /&gt;
&lt;br /&gt;
2. &lt;strong&gt;Say you don&#39;t know&lt;/strong&gt;. Strangely, this is a rare tactic. People often feel it&#39;s preferable to have a stab, and speculate as to the cause or the solution, even without any useful knowledge or data. Email is rife with this kind of thing. This isn&#39;t actually useful. The individual with the problem is likely to have conducted much the same process and reached similar conclusions. It&#39;s nice that you&#39;re trying, but this just consumes time and doesn&#39;t advance a solution. Better to say you don&#39;t know, and refer them to someone else who may be able to help.&lt;br /&gt;
&lt;br /&gt;
3. &lt;strong&gt;Pretend you don&#39;t know&lt;/strong&gt;. You may know the answer, but since fully helping is a time sink for you, you may judge it more profitable to deny all knowledge and continue work.&lt;br /&gt;
&lt;br /&gt;
Until someone rats you out.&lt;br /&gt;
&lt;br /&gt;
Not a great plan. Not professional. Instead, it&#39;s better to admit knowledge where you have it, but if you have a more pressing matter, explain yourself and offer help when you&#39;re done. If it&#39;s urgent, they can find help elsewhere, if not they can wait. Chances are they&#39;ll solve it anyway in the meantime, increasing their own knowledge and learning.&lt;br /&gt;
&lt;br /&gt;
4. &lt;strong&gt;Measured help.&lt;/strong&gt; Give them just enough help to get them moving forward again, but stop short of full disclosure. The advantages to this technique are that you&#39;re offering help, the individual is employing their own initiative and learning and everyone gets to move forward. The downside is that they may return to your desk a further 38 times before the problem is solved.&lt;br /&gt;
&lt;br /&gt;
5. &lt;strong&gt;Be brusque.&lt;/strong&gt; Make people not want to ask. This is a win for you, in the short term, but a lose for the team and a lose for yourself in the long term as people will not offer help in return. It can be difficult to resist this strategy when you&#39;re stressed!&lt;br /&gt;
&lt;br /&gt;
6. &lt;strong&gt;Refer them to a subordinate. &lt;/strong&gt;The joys of seniority! Pass the problem down the line to the next guy. It&#39;s a win for you, but it has mixed results. It may result in a win for the delegate, as they learn something and increase their standing within the team. It may be a win for the individual. It&#39;s a win for you, as it frees your time up. The problem is if the delegate cannot solve that problem. The delegate burns a lot of time, the individual with the problem loses time, and ultimately you end up having to help out anyway. Choose carefully.&lt;br /&gt;
&lt;br /&gt;
7. &lt;strong&gt;Dazzle them with science&lt;/strong&gt;. This is a strange one. When faced with a non-technical user, they blaze them with incredible technical knowledge and prowess. A scintillating analysis, definition and solution to the problem is offered; the individual looks back, blankly. No solution is made. The individual retreats, and contacts your line manager to request that you implement the solution instead. You clearly know what you&#39;re talking about.&lt;br /&gt;
&lt;br /&gt;
8. &lt;strong&gt;Debate them on it.&lt;/strong&gt; One for the orators. Any problem can be negated with a gallant argument, excellent critical analysis and undeniable logic. Your inquirer retreats, defeated. No more problem you think! No. Instead, the inquirer learns to cut you out of the loop, and ratify and implement a solution elsewhere, elsehow.&lt;br /&gt;
&lt;br /&gt;
9. &lt;strong&gt;Blame the build server /&amp;nbsp;Visual Studio&amp;nbsp;/ Perforce / Whatever.&lt;/strong&gt; Clearly the programmer doesn&#39;t honestly believe this is the case. It&#39;s just a play to buy some time, or to momentarily offload the stress.&lt;br /&gt;
&lt;br /&gt;
10. &lt;strong&gt;Counter-problem! &lt;/strong&gt;You come to me with a problem? You&#39;re gonna leave with a bigger one! Thats the Chicago way.</content><link rel='replies' type='application/atom+xml' href='http://tomhammersley.blogspot.com/feeds/319763994987524403/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomhammersley.blogspot.com/2012/04/interruption-handling-techniques-for.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/319763994987524403'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/319763994987524403'/><link rel='alternate' type='text/html' href='http://tomhammersley.blogspot.com/2012/04/interruption-handling-techniques-for.html' title='Interruption Handling Techniques for Programmers'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1191561667656967116.post-2162394010696173819</id><published>2012-02-11T20:53:00.001+00:00</published><updated>2012-02-11T20:53:18.857+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Coding"/><category scheme="http://www.blogger.com/atom/ns#" term="Development"/><category scheme="http://www.blogger.com/atom/ns#" term="Observations"/><title type='text'>R &amp; D - It keeps you honest!</title><content type='html'>I&#39;ve recently been working in an R&amp;amp;D group, developing various features that are quite experimental and wouldn&#39;t normally be scheduled as part of a project. This is intended to be &quot;practical&quot; R&amp;amp;D - we aim to develop features that have a chance of making it into the game, as opposed to features that are blue sky and would never actually be shipped.&lt;br /&gt;
&lt;br /&gt;
This kind of development approach subtly shifts your approach to developing features. Briefly, you become very focused on doing what is necessary to get the feature into the game. You focus on making sure the feature is on-budget. You make sure that you consult with affected parties. You work out the consequences of incorporating the system and seek to mitigate any problems. You suddenly find yourself becoming a salesman, trying to establish a coalition of support for the feature. Your feature really has to prove itself worthwhile so that management will entertain the perceived risk of incorporating it.&lt;br /&gt;
&lt;br /&gt;
Strangely, you don&#39;t always find yourself doing these things during the development of &quot;standard&quot; features. Because they are planned as part of the development effort, their inclusion in the title is automatically assured - pending no major disasters. You don&#39;t have to sell them. These features don&#39;t need to earn their place. Consequently, it can be very easy to find yourself &quot;going down a rabbit hole&quot; with features like this - exploring functionality that is interesting, but not necessarily focused on shipping. Perhaps these features are ultimately more risk-intensive, as they won&#39;t be quite so critically examined as the R&amp;amp;D features.&lt;br /&gt;
&lt;br /&gt;
I tend to find that the whole &quot;posture&quot; you adopt during the development of an R&amp;amp;D feature that is not automatically included in the game is ultimately much better from the perspective of careful software development. It does at least feel more like the kind of process intended by the creators of various software development methodologies. It feels very much along the lines of the approach advocated by Michael Saladino in his &quot;Why Red Lining Your Team Leads to Ineffectiveness&quot;.&lt;br /&gt;
&lt;br /&gt;
Perhaps it&#39;s not for everyone. Perhaps it&#39;s not for every team. Perhaps some may find it quite a pressured, stressful kind of approach. But I really quite like it. It certainly feels a much more considered, deliberate approach. It seems that developing features in branches, that have to prove their worth for integration, sets in motion a slightly changed, more focused set of processes than may be typical.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://tomhammersley.blogspot.com/feeds/2162394010696173819/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomhammersley.blogspot.com/2012/02/r-d-it-keeps-you-honest.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/2162394010696173819'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/2162394010696173819'/><link rel='alternate' type='text/html' href='http://tomhammersley.blogspot.com/2012/02/r-d-it-keeps-you-honest.html' title='R &amp; D - It keeps you honest!'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1191561667656967116.post-1587015635063944350</id><published>2012-02-09T13:56:00.002+00:00</published><updated>2012-02-13T11:05:03.813+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Haskell"/><category scheme="http://www.blogger.com/atom/ns#" term="Raytracing"/><category scheme="http://www.blogger.com/atom/ns#" term="Sparse Voxel Octree"/><title type='text'>Sparse Voxel Octrees in Haskell</title><content type='html'>It&#39;s been a long time coming (daughters birth impedes Haskell coding!), but I&#39;ve finally implemented and uploaded support for Sparse Voxel Octrees in my Haskell Renderer.&lt;br /&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
It&#39;s quite an interesting algorithm to implement in something like Haskell. It&#39;s interesting because it really questions the balance of strict vs lazy evaluation in Haskell. Which is better - strict construction and strict traversal, with the platform optimisations that may bring, or lazy construction-as-you-traverse?&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
In an imperative language, you&#39;d run a complete process to construct the tree, and then traverse the completed tree for each intersection query. You have to pay the total construction cost plus the traversal cost. Since you&#39;d be constructing and storing the whole tree, you need to invest significant effort in data compression. On the other hand, the direct data representation would permit you to make a number of optimisations aimed at evaluation efficiency.&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
With Haskell, the lazy evaluation thunks can do some of that work for you. Instead of trying to crunch the whole tree down to be as small as possible, you may choose instead to rely on the Haskell runtime to just-in-time construct the relevant portions of it. You would only pay the cost of construction for the parts of the tree you traverse. Would this sum be lower than a strict construction and traversal?&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;Alternatively, In Haskell, you can still go for the strict option and implement it much as you would with C.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
What&#39;s interesting is that it introduces this challenging, general question of what offers the most efficiency: A domain-specific, efficiently implemented&amp;nbsp;clever algorithm, or a somewhat more generic algorithm, less specifically optimised but instead relying on lazy evaluation and the higher-order optimisations that may automatically permit?&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;I&#39;m not sure what the answer is to this question right now. I suspect there is a cross over point that is very specific to the data set in question and therefore your particular application.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;strong&gt;&lt;u&gt;Code&lt;/u&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;My current Haskell SVO code is on github, in my Haskell Renderer:&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;a href=&quot;https://github.com/TomHammersley/HaskellRenderer&quot;&gt;https://github.com/TomHammersley/HaskellRenderer&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;I&#39;m going to fix up the various remaining TODOs and then pursue a more optimised, C-like version along the lines of the various SIMD-like SVO implementations that have recently emerged.&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;u&gt;&lt;strong&gt;Implementation Notes&lt;/strong&gt;&lt;/u&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;This was ultimately quite an elegant algorithm to implement in Haskell. Much of the algorithm is built off simple geometric tests. These are quite compact and elegant to represent in a functional language like Haskell. For instance, a ray-box test is simply:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;boundingBoxIntersectRay :: AABB -&amp;gt; Ray -&amp;gt; Maybe (Double, Double)&lt;br /&gt;boundingBoxIntersectRay (bounds0, bounds1) (Ray rayOrg _ invRayDir rayLen)&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | tmax &amp;gt;&amp;nbsp;tmin = Nothing&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | tmin&amp;nbsp;&amp;gt; 0&amp;nbsp;&amp;amp;&amp;amp; tmin&amp;nbsp;&amp;lt; rayLen = Just (tmin, tmax `Prelude.min` rayLen)&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | tmax&amp;nbsp;&amp;gt; 0&amp;nbsp;&amp;amp;&amp;amp; tmax&amp;nbsp;&amp;lt; rayLen = Just (tmax, tmax)&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | otherwise = Nothing&lt;br /&gt;  where&lt;br /&gt;   &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (tmin, tmax) = foldr1 (\(a0, b0) (a1, b1) -&amp;gt; (a0 `Prelude.max` a1, b0 `Prelude.min` b1)) (map intercepts [vecX, vecY, vecZ])&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    intercepts f = let x0 = (f bounds0 - f rayOrg) * f invRayDir&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;x1 = (f bounds1 - f rayOrg) * f invRayDir&lt;br /&gt;                  &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; in (x0 `Prelude.min` x1, x0 `Prelude.max` x1)&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;Here we simply define an operation to calculate the slab intercepts of the box, and then repeat that operation over X, Y and Z, then fold to reduce the results. We&#39;re offering a description of the algorithm to Haskell in high level primitives, permitting optimisation and reduction - as opposed to clumsily trying to indirectly tell a C++ compiler what you&#39;d really like it to do. It&#39;s surprising how often this sort of thing proves faster in Haskell. For example, using the &quot;any&quot; or &quot;all&quot; functions has proven faster than a set of || or &amp;amp;&amp;amp; clauses for me in the past. I could really imagine that a thunk-less version of Haskell, free of the irritation of considering C++ aliasing might produce some very efficient code.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;The traversal code is a simple recursive traversal, with few (as yet) clever tricks. It terminates either at the leaves, at the maximum traversal depth or when the feature becomes too small when projected to screen space (though this calculation needs further elaboration). It therefore gives a simple, automatic LOD control.&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
And so, finally, here it is, our SVO lego-sphere:&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgt2WFqQJyBCbPrUBCHkZj227LaV4i9i82RCzzfsrHno8Pwu2FOnwIz-MBD_yfkWddXnJ149AqQy_1FqLjMqbNRFBp5EwZVOaRYahYL7E5HrbOoVlxwl7uG9pCKDn0dvSLga9DyUBfCURI/s1600/render-output-1.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;180&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgt2WFqQJyBCbPrUBCHkZj227LaV4i9i82RCzzfsrHno8Pwu2FOnwIz-MBD_yfkWddXnJ149AqQy_1FqLjMqbNRFBp5EwZVOaRYahYL7E5HrbOoVlxwl7uG9pCKDn0dvSLga9DyUBfCURI/s320/render-output-1.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tomhammersley.blogspot.com/feeds/1587015635063944350/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomhammersley.blogspot.com/2012/02/sparse-voxel-octrees-in-haskell.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/1587015635063944350'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/1587015635063944350'/><link rel='alternate' type='text/html' href='http://tomhammersley.blogspot.com/2012/02/sparse-voxel-octrees-in-haskell.html' title='Sparse Voxel Octrees in Haskell'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgt2WFqQJyBCbPrUBCHkZj227LaV4i9i82RCzzfsrHno8Pwu2FOnwIz-MBD_yfkWddXnJ149AqQy_1FqLjMqbNRFBp5EwZVOaRYahYL7E5HrbOoVlxwl7uG9pCKDn0dvSLga9DyUBfCURI/s72-c/render-output-1.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1191561667656967116.post-7609961172403877704</id><published>2012-02-02T16:46:00.003+00:00</published><updated>2012-02-02T21:05:12.924+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="C++"/><category scheme="http://www.blogger.com/atom/ns#" term="Coding"/><category scheme="http://www.blogger.com/atom/ns#" term="Observations"/><title type='text'>Peak Abstraction</title><content type='html'>&lt;br /&gt;
An interesting phenomena I&#39;ve observed over my years as a programmer is the occurrence of &quot;Peak Abstraction&quot; within a young programmer - and their subsequent improvement.&lt;br /&gt;
&lt;br /&gt;
There is a common pattern. It typically occurs after 3-4 years of professional practice. A programmer is growing in his confidence. He begins to tackle more complex, challenging problems. And, he reflects those problems with complex, challenging data structures. He has not yet learnt the fine art of simplicity.&lt;br /&gt;
&lt;br /&gt;
Every member of every data structure is a pointer or a reference. There are no simple data types. Everything becomes a &quot;value dictionary&quot;, a &quot;graph-based visitor&quot; or a &quot;multi-dimensional ring buffer&quot;. Disassembly of his code reveals it to be little more than an infinite sequence of lwz, lwz, lwz, lwz and more lwz. Perhaps he/she develops a hobbyist interest in Java. They may develop an editor that connects boxes with lines - such editors are great for filling with lots and lots of abstraction! Often, she/he may favour Boost; perhaps he even becomes your office&#39;s Boost Guy. Even simple plain old data types such as integers are suddenly held within a smart-pointer container and reference counted. And with a pimpl to retrieve their value.&lt;br /&gt;
&lt;br /&gt;
Those around them become increasingly desperate. They can see the code becoming inflated, inefficient, unmaintainable. Spending time reading this individual&#39;s code is like spending time exposed to a radioactive isotope. You can only tolerate a few moments before exhibiting signs of sickness. You attempt to modify their code. 478 pages of template errors dissuade you from considering this foolish course of action again.&lt;br /&gt;
&lt;br /&gt;
And then it happens. The programmer realises the error of their ways. They realise that they are adding neither design value nor computational value. They realise they are adding overhead and maintenance trouble. Perhaps they undergo their first encounter with profiling software. Said software may disclose the full terror of the D$ dirty bomb they have unleashed upon the code. Perhaps they are &quot;introduced&quot; to the profiler by an irate lead in some sort of shotgun-wedding affair. Whatever, the programmer realises that solving complex problems does not require needlessly complex data structures. Such structures impress nobody. People are impressed by simple, elegant solutions. And thus the recovery begins. Data structures become simple, expressive, and maintainable. Data cache misses dip under 20ms/frame for the first time. Co-workers enjoy modifying their code. The compiler begins to emit instructions such as &quot;add&quot; or &quot;mul&quot;. Sadly the compiler may be too fond of outputting &quot;jump&quot; instructions at this stage... The programmer themself becomes wary of others who are pre-Peak Abstraction.&lt;br /&gt;
&lt;br /&gt;
One even wonders if, like it&#39;s namesake &quot;Peak Oil&quot;, there may be a global Peak Abstraction. Perhaps the practising body of programmers may all undergo Peak Abstraction in the next 5-10 years and we will all left never having to refactor some template monstrosity.&lt;br /&gt;
&lt;br /&gt;
But then, where&#39;s the fun in that? Don&#39;t programmers just love to be indignant about others&#39; code?&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tomhammersley.blogspot.com/feeds/7609961172403877704/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomhammersley.blogspot.com/2012/02/peak-abstraction.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/7609961172403877704'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/7609961172403877704'/><link rel='alternate' type='text/html' href='http://tomhammersley.blogspot.com/2012/02/peak-abstraction.html' title='Peak Abstraction'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1191561667656967116.post-366410338220714470</id><published>2011-09-13T21:19:00.000+01:00</published><updated>2011-09-19T09:53:46.374+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Haskell"/><category scheme="http://www.blogger.com/atom/ns#" term="Photon Mapping"/><category scheme="http://www.blogger.com/atom/ns#" term="Raytracing"/><title type='text'>Haskell Photon Mapper Released to Hackage</title><content type='html'>I&#39;ve now uploaded my Haskell photon mapper and raytracer to hackage. It is listed as a package called &quot;crocodile&quot; (named after my son&#39;s current obsession with crocodiles!).&lt;br /&gt;
&lt;br /&gt;
It&#39;s all working on the Cornell box. It&#39;s pretty memory hungry, and has a few self-declared things to fix (eg irradiance gradients), but it&#39;s out there to play with.&lt;br /&gt;
&lt;br /&gt;
Enjoy.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwj7zLB4Tf33vsT4YPYL-Eo8km7PAlbkir0Lmn0rn8cl7j7niowueipw2GOt-psfZXrQvTisjlN7wncJNUuQpUPbGbEh8So87utEbdLk1lQGUf5x_y7V8hccZChOzCqzjYivtxGFCh5Lg/s1600/photon-map-16-9-2011.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;180&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwj7zLB4Tf33vsT4YPYL-Eo8km7PAlbkir0Lmn0rn8cl7j7niowueipw2GOt-psfZXrQvTisjlN7wncJNUuQpUPbGbEh8So87utEbdLk1lQGUf5x_y7V8hccZChOzCqzjYivtxGFCh5Lg/s320/photon-map-16-9-2011.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://tomhammersley.blogspot.com/feeds/366410338220714470/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomhammersley.blogspot.com/2011/09/haskell-photon-mapper-released-to.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/366410338220714470'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/366410338220714470'/><link rel='alternate' type='text/html' href='http://tomhammersley.blogspot.com/2011/09/haskell-photon-mapper-released-to.html' title='Haskell Photon Mapper Released to Hackage'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwj7zLB4Tf33vsT4YPYL-Eo8km7PAlbkir0Lmn0rn8cl7j7niowueipw2GOt-psfZXrQvTisjlN7wncJNUuQpUPbGbEh8So87utEbdLk1lQGUf5x_y7V8hccZChOzCqzjYivtxGFCh5Lg/s72-c/photon-map-16-9-2011.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1191561667656967116.post-8352285143424005605</id><published>2011-08-25T09:42:00.003+01:00</published><updated>2011-08-25T10:19:04.015+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Optimisation"/><title type='text'>This is what happens</title><content type='html'>When universities teach Java!&lt;br /&gt;
&lt;br /&gt;
(some random bit of disassembled code found on my travels)&lt;br /&gt;
&lt;br /&gt;
00A5CA74 EC7E1824 fdivs f3,f30,f3&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 56 PIPE&lt;br /&gt;
00A5CA78 FC406850 fneg f2,f13&lt;br /&gt;
00A5CA7C D0660010 stfs f3,0x10(r6)&lt;br /&gt;
00A5CA80 D0C90010 stfs f6,0x10(r9)&lt;br /&gt;
00A5CA84 D981FF60 stfd f12,-0xA0(r1)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; PIPE&lt;br /&gt;
00A5CA88 E881FF60 ld r4,-0xA0(r1)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 70 (00A5CA84) LHS[01]&lt;br /&gt;
00A5CA8C D961FF60 stfd f11,-0xA0(r1)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; PIPE&lt;br /&gt;
00A5CA90 EBA1FF60 ld r29,-0xA0(r1)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 70 (00A5CA8C) LHS[01]&lt;br /&gt;
00A5CA94 D941FF60 stfd f10,-0xA0(r1)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; PIPE&lt;br /&gt;
00A5CA98 EB81FF60 ld r28,-0xA0(r1)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 70 (00A5CA94) LHS[01]&lt;br /&gt;
00A5CA9C D921FF60 stfd f9,-0xA0(r1)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; PIPE&lt;br /&gt;
00A5CAA0 EB61FF60 ld r27,-0xA0(r1)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 70 (00A5CA9C) LHS[01]&lt;br /&gt;
00A5CAA4 D901FF60 stfd f8,-0xA0(r1)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; PIPE&lt;br /&gt;
00A5CAA8 EB41FF60 ld r26,-0xA0(r1)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 70 (00A5CAA4) LHS[01]&lt;br /&gt;
00A5CAAC D8E1FF60 stfd f7,-0xA0(r1)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; PIPE&lt;br /&gt;
00A5CAB0 EB21FF60 ld r25,-0xA0(r1)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 70 (00A5CAAC) LHS[01]&lt;br /&gt;
00A5CAB4 D1A6000C stfs f13,0xC(r6)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; PIPE&lt;br /&gt;
00A5CAB8 D029000C stfs f1,0xC(r9)&lt;br /&gt;
00A5CABC D801FF60 stfd f0,-0xA0(r1)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; PIPE&lt;br /&gt;
00A5CAC0 E801FF60 ld r0,-0xA0(r1)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 70 (00A5CABC) LHS[01]&lt;br /&gt;
0</content><link rel='replies' type='application/atom+xml' href='http://tomhammersley.blogspot.com/feeds/8352285143424005605/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomhammersley.blogspot.com/2011/08/this-is-what-happens.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/8352285143424005605'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/8352285143424005605'/><link rel='alternate' type='text/html' href='http://tomhammersley.blogspot.com/2011/08/this-is-what-happens.html' title='This is what happens'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1191561667656967116.post-6292848283557360105</id><published>2011-08-24T08:16:00.000+01:00</published><updated>2011-08-24T08:16:23.210+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="C++"/><category scheme="http://www.blogger.com/atom/ns#" term="Haskell"/><category scheme="http://www.blogger.com/atom/ns#" term="Optimisation"/><title type='text'>Pattern matching as an optimisation method, and a means of insight</title><content type='html'>One feature of Haskell that I particularly like is its pattern-matching scheme. To route code down the correct codepath, Haskell uses pattern matching against data types and values, instead of extensive flow-control statements. This makes the code much simpler to read, as your code merely concerns itself with calling the correct functions, with the correct handler cases, and the underlying Haskell compiler deals with the flow-control minutiae.&lt;br /&gt;
&lt;br /&gt;
I&#39;ve increasingly found myself using a similar approach in C++ and HLSL&amp;nbsp;using features such as polymorphic functions. A good example comes from optimisation: frequently, you find cases in the code where someone has written a &quot;kitchen sink&quot; function. This function internally handles many cases, and accordingly takes many parameters. &lt;br /&gt;
&lt;br /&gt;
Frequently, many of these parameters are called with specificliteral values or constants. For example, many parameters may be zero which&amp;nbsp;disable entire codepaths inside the function. For me, this is a bad code smell. But why? Many people would argue that since the code is branched away, what&#39;s the big deal? Especially if it means we can have just one definition of a function. Well, branches are very expensive on modern processors. On contemporary consoles, a floating point branch can yield a 27-cycle penalty. Not to mention all the preamble and branch set-up code.&lt;br /&gt;
&lt;br /&gt;
I&#39;ve therefore found myself increasingly providing multiple specialised versions of these functions, which omit some of the parameters that are permanently called with 0.0f or 1.0f and tailoring the code accordingly. Obviously this saves a lot of needless computation, branching and I$ misses.&lt;br /&gt;
&lt;br /&gt;
What&#39;s interesting about this approach is that once you&#39;ve performed a few of these refactorings, you start to expose patterns in the code and its structure that you previously were unaware of. You may find that your major axis of variation lies not in your chosen object hierarchy composition, but elsewhere. You may have a multitude of objects that add little value at a higher level, but now a large set of lower level functions that process the objects differently. Sometimes it makes more sense to structure and divide your code along the lines of what processing it does, not what you think the object &quot;is&quot;, as that is the greater source of variation.&lt;br /&gt;
</content><link rel='replies' type='application/atom+xml' href='http://tomhammersley.blogspot.com/feeds/6292848283557360105/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomhammersley.blogspot.com/2011/08/pattern-matching-as-optimisation-method.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/6292848283557360105'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/6292848283557360105'/><link rel='alternate' type='text/html' href='http://tomhammersley.blogspot.com/2011/08/pattern-matching-as-optimisation-method.html' title='Pattern matching as an optimisation method, and a means of insight'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1191561667656967116.post-6094123100624037761</id><published>2011-08-23T21:29:00.000+01:00</published><updated>2011-08-23T21:29:52.387+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Caching"/><category scheme="http://www.blogger.com/atom/ns#" term="Optimisation"/><title type='text'>On the limitations of caching</title><content type='html'>I&#39;ve been spending a little time thinking about caching lately. Irradiance caching, optimising some caching in production code, and hardware caches. Here&#39;s a little brain-dump.&lt;br /&gt;
&lt;br /&gt;
I&#39;ve come to the conclusion that if you ever need anything more than a trivially small cache, your algorithm is wrong. This is particularly so for parallel programming, as caches are often a difficult to handle piece of interdependent common state.&lt;br /&gt;
&lt;br /&gt;
My reasoning goes a little something like this. If you are relying on a cache for performance, it is usually to re-use the results of some expensive transformation a -&amp;gt; b. Crucially, there needs to be 1 a to one or more b (otherwise there is no cache reuse!). For an efficient cache, you need:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;To be caching the results of a fairly complex computation,&lt;/li&gt;
&lt;li&gt;To have an efficient means of storing the results of the computation,&lt;/li&gt;
&lt;li&gt;To have a well-behaved cache indexing function.&lt;/li&gt;
&lt;/ul&gt;&lt;div&gt;Now, what often ends up happening is that you iterate over the many objects &#39;b&#39;, and populate the cache on-demand from a common ancestor piece of data, a. And here&#39;s the first problem. You are primarily iterating over the wrong dataset, and filtering and culling parts of the other dataset by proxy. You have an implicit data filtering or reduction operation that could be better handled more explicitly.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Ok, so, we switch our iteration round to iterate over the source objects &#39;a&#39;. We iterate over each &#39;a&#39; object, and produce the resulting 1 or more &#39;b&#39; objects. At this point, do we really have a cache? We&#39;ve turned our cache into a data transformation kernel. All of sudden our cache is no longer some intermediate state used in a computation, but it is now simply a piece of input data. Since we now have a piece of code transforming [a] -&amp;gt; [b], we have a piece of code that is very amenable to data parallelism. Since we&#39;ve decoupled the code from a cache, it&#39;s also much easier to parallelise.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;I think ultimately an extensive caching scheme is evidence that the data domain hasn&#39;t been adequately structured and managed. If you need a cache, you probably need more data conditioning, filtering, and reduction.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;A good counter-example is the vertex stream processing unit of a modern GPU. These units read huge streams of data, transform them, and maintain minimal cached state. Vertex caches are typically miniscule in comparison to the volume of data they process. Yet a post-transform cache can often maintain a very high level of efficiency. The key to this cache&#39;s success is the pre-processing (ie structuring) of the data fed into it. It is not random. It is well conditioned, which yields efficiency at a number of levels, and enables a vertex cache to be used only as a relatively modest addition to the pipeline. The cache is the icing on the cake, not a fundamental component of the algorithm.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;I think this is an important lesson when transitioning from writing single-threaded to parallel code. Don&#39;t dream up increasingly elaborate caching schemes. Instead think up separable, well-structured data-parallel transformations. When you feel the need for a cache, you probably need to carefully re-examine your data flow structure.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tomhammersley.blogspot.com/feeds/6094123100624037761/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomhammersley.blogspot.com/2011/08/on-limitations-of-caching.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/6094123100624037761'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/6094123100624037761'/><link rel='alternate' type='text/html' href='http://tomhammersley.blogspot.com/2011/08/on-limitations-of-caching.html' title='On the limitations of caching'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1191561667656967116.post-143415649178268077</id><published>2011-07-05T09:18:00.000+01:00</published><updated>2011-07-05T09:18:22.615+01:00</updated><title type='text'>Where&#39;d all the Haskell go?</title><content type='html'>It&#39;s not gone. It&#39;ll be back.&lt;br /&gt;
&lt;br /&gt;
I&#39;ve recently moved house, and obviously that consumes a lot of time both before, and after the move. In order to write a Haskell article, I need to develop supporting code. I don&#39;t have much coding time right now.&lt;br /&gt;
&lt;br /&gt;
On the other hand, it&#39;s pretty easy to knock out an article based on the knowledge gained during my Master&#39;s, and through my industry experience, so I&#39;m writing on those subjects for a while.&lt;br /&gt;
&lt;br /&gt;
Haskell will be back!</content><link rel='replies' type='application/atom+xml' href='http://tomhammersley.blogspot.com/feeds/143415649178268077/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomhammersley.blogspot.com/2011/07/whered-all-haskell-go.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/143415649178268077'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/143415649178268077'/><link rel='alternate' type='text/html' href='http://tomhammersley.blogspot.com/2011/07/whered-all-haskell-go.html' title='Where&#39;d all the Haskell go?'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1191561667656967116.post-5794793408922342226</id><published>2011-06-02T22:02:00.000+01:00</published><updated>2011-06-02T22:02:15.442+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Haskell"/><category scheme="http://www.blogger.com/atom/ns#" term="Photon Mapping"/><category scheme="http://www.blogger.com/atom/ns#" term="Raytracing"/><title type='text'>Photon Mapping in Haskell</title><content type='html'>For a while I have been working on extending my Haskell raytracer to include a global illumination model. I chose to implement photon mapping, as it seemed to offer both a number of challenges, and it quite suited a functional programming approach.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;u&gt;Photon Tracing&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
One of the main challenges of implementing an algorithm like photon mapping is that it relies on a small amount of mutable state due to its monte-carlo integration. As each photon is traced through the scene, a random number is required to determine the fate of a photon for a given photon-to-material interaction. A random number generator typically requires state to iterate from one number to the next. Such state is easy to incorporate into imperative code, but it presents a challenge to the Haskell programmer.&lt;br /&gt;
&lt;br /&gt;
There are two main challenges with state: management and propagation of state, and selecting what code should share a given state context. For example, in the photon mapper I could have introduced a single, global state for the random number generator. Or, I could have given each light source its own state. Or each photon. The greater scope that the state has, the greater the coupling in the code and the greater the difficulty in parallelisation.&lt;br /&gt;
&lt;br /&gt;
I chose to give each photon traced its own random number generator state - and each photon had a different initial seed.&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;-- Realistic Image Synthesis Using Photon Mapping p60&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;tracePhoton :: [Photon] -&amp;gt; Photon -&amp;gt; SceneGraph -&amp;gt; StdGen -&amp;gt; (Int, Int) -&amp;gt; [Photon]&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;tracePhoton !currentPhotons (Photon !photonPower !photonPosDir) sceneGraph !rndState !(bounce, maxBounces) =&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; -- See if the photon intersects any surfaces&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; case findNearestIntersection sceneGraph ray of&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; Nothing -&amp;gt; currentPhotons&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; Just (obj, t, subId) -&amp;gt; case photonFate of&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -- Diffuse reflection. Here, we store the photon that got reflected, and trace a new photon - but only if it&#39;s bright enough to be worthwhile&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; DiffuseReflect -&amp;gt; if Colour.magnitude newPhotonPower &amp;gt; brightnessEpsilon &amp;amp;&amp;amp; (bounce + 1) &amp;lt;= maxBounces&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; then tracePhoton (storedPhoton : currentPhotons) reflectedPhoton sceneGraph rndState&#39;&#39; (bounce + 1, maxBounces)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; else storedPhoton : currentPhotons&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; where&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; !reflectedPhoton = Photon newPhotonPower (surfacePos, reflectedDir)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; !(reflectedDir, rndState&#39;&#39;) = diffuseReflectionDirection rndState&#39; tanSpace&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -- Specular reflection. Here, we reflect the photon in the fashion that the surface would reflect towards the viewer and&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -- aim to absorb it somewhere else in the photon map&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; SpecularReflect -&amp;gt; if Colour.magnitude newPhotonPower &amp;gt; brightnessEpsilon &amp;amp;&amp;amp; (bounce + 1) &amp;lt;= maxBounces&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;then tracePhoton currentPhotons reflectedPhoton sceneGraph rndState&#39; (bounce + 1, maxBounces)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;else currentPhotons&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; where&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; !reflectedPhoton = Photon newPhotonPower (surfacePos, reflectedDir)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; !reflectedDir = Vector.negate (snd photonPosDir) `reflect` normal&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -- Absorb. The photon simply gets absorbed into the map&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Absorb -&amp;gt; storedPhoton : currentPhotons&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; where&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; !(photonFate, rndState&#39;) = runState (choosePhotonFate coefficients) rndState&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; !coefficients = russianRouletteCoefficients (material obj)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; !newPhotonPower = computeNewPhotonPower photonFate coefficients photonPower (material obj)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; !tanSpace = primitiveTangentSpace (primitive obj) subId hitPosition obj&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; !normal = thr tanSpace&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; !hitPosition = pointAlongRay ray t&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; !surfacePos = hitPosition + (normal Vector.&amp;lt;*&amp;gt; surfaceEpsilon)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; !brightnessEpsilon = 0.1&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; !storedPhoton = Photon photonPower (surfacePos, snd photonPosDir)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; where&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; !ray = rayWithPosDir photonPosDir 10000&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;u&gt;KD-Tree Construction&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
The resulting list of photons is inserted into a KD tree in order to efficiently locate the set of photons near to a point in space. This is a simple recursive operation:&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;buildKDTree :: [Photon] -&amp;gt; PhotonMapTree&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;buildKDTree photons&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; | length photons == 1 = PhotonMapLeaf (head photons)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; | length photons &amp;gt;= 2 = let (boxMin, boxMax) = photonsBoundingBox photons&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; !axis = largestAxis (boxMax - boxMin)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; !photonsMedian = foldr ((+) . fst . posDir) zeroVector photons Vector. fromIntegral (length photons)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; !value = component photonsMedian axis&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; photonsGT = Prelude.filter (\x -&amp;gt; component ((fst . posDir) x) axis &amp;gt; value) photons&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; photonsLE = Prelude.filter (\x -&amp;gt; component ((fst . posDir) x) axis &amp;lt;= value) photons&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; in if length photonsGT &amp;gt; 0 &amp;amp;&amp;amp; length photonsLE &amp;gt; 0&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;then PhotonMapNode axis value (buildKDTree photonsGT) (buildKDTree photonsLE)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;else let (photons0&#39;, photons1&#39;) = trace &quot;Using degenerate case&quot; $ degenerateSplitList photons in PhotonMapNode axis value (buildKDTree photons0&#39;) (buildKDTree photons1&#39;)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; | otherwise = error (&quot;Invalid case, length of array is &quot; ++ show (length photons) ++ &quot;\n&quot;)&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;u&gt;KD-Tree Query&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
The photon mapping algorithm uses an interesting combination of a kd tree and max-heap to locate only the closest N photons to a point. The max-heap is sorted on the squared distance to a photon. This means the most distant photons are stored towards the top of the max-heap, making them easy to discard.&lt;br /&gt;
&lt;br /&gt;
Traversal of the tree commences with a point of interest and a radius. Any photons found within that radius are added to the max-heap. If the max-heap exceeds its specified size then excess, distant photons are dropped from the top of the heap. Since the max-heap stores the most distant photon at the top of the heap, it is easy to monitor the current-furthest photon and tighten our search radius during traversal.&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;-- Use a max heap to make it easy to eliminate distant photons&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;data GatheredPhoton = GatheredPhoton Float Photon deriving (Show)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;type PhotonHeap = MaxHeap GatheredPhoton&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;instance Ord GatheredPhoton where&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; compare (GatheredPhoton dist1 _) (GatheredPhoton dist2 _)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; | dist1 == dist2 = EQ&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; | dist1 &amp;lt;= dist2 = LT&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; | otherwise = GT&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;instance Eq GatheredPhoton where&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; (GatheredPhoton dist1 _) == (GatheredPhoton dist2 _) = dist1 == dist2&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;minimalSearchRadius !rSq !photonHeap = case viewHead photonHeap of&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Nothing -&amp;gt; rSq&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Just (GatheredPhoton dSq _) -&amp;gt; Prelude.min rSq dSq&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;-- Gather photons for irradiance computations&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;-- Algorithm adapted from Realistic Image Synthesis Using Photon Mapping p73&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;gatherPhotons :: PhotonMapTree -&amp;gt; Position -&amp;gt; Float -&amp;gt; PhotonHeap -&amp;gt; Int -&amp;gt; PhotonHeap&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;gatherPhotons (PhotonMapNode !axis !value gtChild leChild) !pos !rSq !photonHeap !maxPhotons&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; -- In this case, the split plane bisects the search sphere - search both halves of tree&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; | (value - posComponent) ** 2 &amp;lt;= rSq = let heap1 = gatherPhotons gtChild pos rSq&#39; photonHeap maxPhotons&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;rSq&#39;&#39; = minimalSearchRadius rSq&#39; heap1&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;heap2 = gatherPhotons leChild pos rSq&#39;&#39; photonHeap maxPhotons&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;newHeap = union heap1 heap2&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;in Data.Heap.drop (size newHeap - maxPhotons) newHeap&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; -- One side of the tree...&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; | posComponent &amp;gt; value = gatherPhotons gtChild pos rSq&#39; photonHeap maxPhotons&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; -- ... or the other&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; | posComponent &amp;lt;= value = gatherPhotons leChild pos rSq&#39; photonHeap maxPhotons&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; -- Prolapse&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; | otherwise = error &quot;gatherPhotons: unexplained/unexpected case here&quot;&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; where&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; !posComponent = component pos axis&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; !rSq&#39; = minimalSearchRadius rSq photonHeap -- Refine search radius as we go down tree to search no further than closest allowed photon&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;gatherPhotons (PhotonMapLeaf !p) !pos !rSq !photonHeap !maxPhotons&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; | distSq &amp;lt; rSq = let newHeap = insert (GatheredPhoton distSq p) photonHeap&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;in Data.Heap.drop (size newHeap - maxPhotons) newHeap -- Discard any excess photons - we get rid of the furthest ones&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; | otherwise = photonHeap&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp; &amp;nbsp; where !distSq = pos `distanceSq` (fst . posDir) p&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;b&gt;&lt;u&gt;Parallelisation&lt;/u&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;The photon tracing stage is trivially easy to parallelise, provided that you have carefully treated the shared state required by the random number generator. Since I have provided each traced photon with it&#39;s own state, which is uniquely initialised, all photons are data independent and therefore easy to trace in parallel.&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;I have not yet parallelised the photon gathering stage, due to some issues with the current implementation&#39;s efficiency. Two options present themselves for parallelisation. The first is to parallelise the traversal of high-level sub-branches of the KD tree. This naive approach would yield some speedup, but the work of each thread is likely to be highly unbalanced.&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;Speculatively, a work-stealing queue type approach may help here. The high-level nodes to be traversed could be initially inserted into a queue. When a worker thread pulls data, it could compare how many nodes remain to be traversed against the total number of workers. If the ratio of nodes:workers becomes very low, nodes could be repeatedly removed from the queue and replaced with their child nodes, until the ratio becomes favourable. This would populate the queue with a fairly heterogenous mixture of large and small amounts of work to be done, which would help fill up and balance processor time across the threads.&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;b&gt;&lt;u&gt;Results&lt;/u&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;Here is the current output image, with all options cranked up:&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9ZQgL5bbvjTj7bDTBm1I5GVvyPgNSGinPxn_gjdOj8HdhykBAX96A8E1xzZTWXwrDUFbqSdnweMVlroSLWLZn59uXKHeO4PFParTvBree_EGDxydoeGp-u5Jbyiz9yCAalGNTWv_mgyY/s1600/photon-map-wip-1-6-2011.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9ZQgL5bbvjTj7bDTBm1I5GVvyPgNSGinPxn_gjdOj8HdhykBAX96A8E1xzZTWXwrDUFbqSdnweMVlroSLWLZn59uXKHeO4PFParTvBree_EGDxydoeGp-u5Jbyiz9yCAalGNTWv_mgyY/s320/photon-map-wip-1-6-2011.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;The code requires refinement and tuning to eliminate the bias, improve the colour bleeding and fix a few minor artefacts.&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;The photon mapper is currently very slow. It can take hours on my MacBook Pro to trace a scene containing 100,000 photons, and that is a very small number of photons.&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;Most of the time is spent in the gathering phase. The current implementation is very space intensive and requires further serious attention. The photon emission and tracing step, however, is extremely quick, requiring only a few seconds to trace 100,000 photons.&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;b&gt;&lt;u&gt;Code&lt;/u&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;Full source code is available on github:&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;https://github.com/TomHammersley/HaskellRenderer&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;b&gt;&lt;u&gt;Future Work&lt;/u&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;I am now working to improve the efficiency of the gathering phase which will improve efficiency and development speed. I am also implementing an irradiance cache to further optimise execution speed. Clearly various minor bugs also need addressing.&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;b&gt;&lt;u&gt;References&lt;/u&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;Further implementation details can be found primarily in Henrik Wann Jensen&#39;s photon mapping book, supplemented by various SIGGRAPH course materials.&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;iframe align=&quot;left&quot; frameborder=&quot;0&quot; marginheight=&quot;0&quot; marginwidth=&quot;0&quot; scrolling=&quot;no&quot; src=&quot;http://rcm.amazon.com/e/cm?t=tomhamsblog-20&amp;amp;o=1&amp;amp;p=8&amp;amp;l=bpl&amp;amp;asins=1568814623&amp;amp;fc1=000000&amp;amp;IS2=1&amp;amp;lt1=_blank&amp;amp;m=amazon&amp;amp;lc1=0000FF&amp;amp;bc1=000000&amp;amp;bg1=FFFFFF&amp;amp;f=ifr&quot; style=&quot;align: left; height: 245px; padding-right: 10px; padding-top: 5px; width: 131px;&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tomhammersley.blogspot.com/feeds/5794793408922342226/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomhammersley.blogspot.com/2011/06/photon-mapping-in-haskell.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/5794793408922342226'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/5794793408922342226'/><link rel='alternate' type='text/html' href='http://tomhammersley.blogspot.com/2011/06/photon-mapping-in-haskell.html' title='Photon Mapping in Haskell'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9ZQgL5bbvjTj7bDTBm1I5GVvyPgNSGinPxn_gjdOj8HdhykBAX96A8E1xzZTWXwrDUFbqSdnweMVlroSLWLZn59uXKHeO4PFParTvBree_EGDxydoeGp-u5Jbyiz9yCAalGNTWv_mgyY/s72-c/photon-map-wip-1-6-2011.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1191561667656967116.post-5797265524806388591</id><published>2011-05-15T07:16:00.001+01:00</published><updated>2011-05-15T20:02:49.069+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Haskell"/><category scheme="http://www.blogger.com/atom/ns#" term="Photon Mapping"/><category scheme="http://www.blogger.com/atom/ns#" term="Raytracing"/><title type='text'>Haskell Renderer Source Code on Github</title><content type='html'>Just a quick note to let anyone interested that the source code to my work-in-progress Haskell raytracer and photon mapper is now available at:&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://github.com/TomHammersley/HaskellRenderer&quot;&gt;https://github.com/TomHammersley/HaskellRenderer&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
I&#39;m currently mid way through debugging and optimising the photon map solution. It works, though it takes 10 minutes or so on my MacBook Pro.&lt;br /&gt;
&lt;br /&gt;
When run it will output the following image:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSnms72pyyxY4Zb6MFKLswAyNfwyKQT1spq1yGVWHR7pGZRNrADUXc25_WM9KKjPdXf4t4aV-rF69_YCN1r6H9nAWsUI9pVSFl4Bw8911NMJOJysVgUDd31hGFW84kdxKjbUUaVPKFvFU/s1600/photonMap.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSnms72pyyxY4Zb6MFKLswAyNfwyKQT1spq1yGVWHR7pGZRNrADUXc25_WM9KKjPdXf4t4aV-rF69_YCN1r6H9nAWsUI9pVSFl4Bw8911NMJOJysVgUDd31hGFW84kdxKjbUUaVPKFvFU/s320/photonMap.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
To build the program you just need the latest Haskell Platform and the bmp package from cabal.&lt;br /&gt;
&lt;br /&gt;
I&#39;m still a beginner at Haskell so some of the code may not represent the most idiomatic or best practice Haskell. If anyone has any advice, comments or constructive criticism, I&#39;m keen to hear it at &lt;a href=&quot;mailto:tomhammersley@gmail.com&quot;&gt;tomhammersley@gmail.com&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
(I plan to make the package Cabal compatible soon).&lt;br /&gt;
&lt;br /&gt;
Cheers.</content><link rel='replies' type='application/atom+xml' href='http://tomhammersley.blogspot.com/feeds/5797265524806388591/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomhammersley.blogspot.com/2011/05/haskell-renderer-source-code-on-github.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/5797265524806388591'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/5797265524806388591'/><link rel='alternate' type='text/html' href='http://tomhammersley.blogspot.com/2011/05/haskell-renderer-source-code-on-github.html' title='Haskell Renderer Source Code on Github'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSnms72pyyxY4Zb6MFKLswAyNfwyKQT1spq1yGVWHR7pGZRNrADUXc25_WM9KKjPdXf4t4aV-rF69_YCN1r6H9nAWsUI9pVSFl4Bw8911NMJOJysVgUDd31hGFW84kdxKjbUUaVPKFvFU/s72-c/photonMap.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1191561667656967116.post-1214209641787315513</id><published>2011-04-11T21:07:00.002+01:00</published><updated>2011-04-12T09:21:54.462+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="C++"/><category scheme="http://www.blogger.com/atom/ns#" term="Design"/><category scheme="http://www.blogger.com/atom/ns#" term="Haskell"/><category scheme="http://www.blogger.com/atom/ns#" term="Parallelism"/><title type='text'>Designs That Leak State: Using Haskell Notation to Analyse C++ Design</title><content type='html'>I came across an interesting design failure today. In short, a C++ object was internally storing the state specific to a piece of multi-threaded client code. The client code was leaking its state data into the C++ object. In generalised, abstracted terms:&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;class Object&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;{&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;Real member variables&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;...&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; unsigned char m_state1[MaxContexts];&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;float m_state2[MaxContexts];&lt;/span&gt;&lt;/div&gt;&lt;div style=&quot;margin: 0px;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;bool m_state3[MaxContexts];&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;};&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Each of the threads would read from &#39;Object&#39;, process it, and store the results in one of the elements of m_state.&lt;br /&gt;
&lt;br /&gt;
It&#39;s a bad pattern, but I daresay a common pattern.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;u&gt;What is wrong here?&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
The first thing to notice is the series of member variables, all arrays, sized by MaxContexts. A series of variables like this is a dead giveaway that really there is semantically some concept in the system that is not explicitly represented in the code. Given that we are trying to represent an object in a series of &quot;contexts&quot;, with different values for each, it suggests that these variables are not properties of the object, but actually variables of some other,&amp;nbsp;auxiliary&amp;nbsp;state. If there is logically one of something, it&#39;s a member variable of the class in question. If an object embeds a number of them, it&#39;s probably someone else&#39;s variable.&lt;br /&gt;
&lt;br /&gt;
Fundamentally, my problem with this is that we&#39;re embedding some client&#39;s data within the object itself. When the client code operates on the object, it is no longer a pure transformation of one object into another, it is now a conceptually more complex, confusing transformation of one object, to the same object with new state.&lt;br /&gt;
&lt;br /&gt;
This additional state presents serious problems to multi-threading a piece of code. When foreign state is embedded unnecesarily in an object like this it makes it much more difficult to manage the ownership, lifetime and correctness of data. All the other clients of the Object are burdened with helping manage the state of some other system. Appropriate ownership, coupling, and lifetime of data is all-important in parallel programming.&lt;br /&gt;
&lt;br /&gt;
Our problem is that we have inverted the &quot;has-a&quot; relationship. The object does not &quot;have a&quot; state in a number of contexts. In reality, the contexts have the state and they &quot;have&quot;, or refer to the object.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;u&gt;Haskell Function Signature Analysis&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
I increasingly find that Haskell&#39;s function signature notation is a lucid yet lightweight means of analysing data flow. There are many other alternative, successful methods, yet I find the Haskell analysis direct and natural. These days I find myself thinking directly in these terms to understand data transformations.&lt;br /&gt;
&lt;br /&gt;
In Haskell terms, we have:&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;font-family: Times; margin: 0px;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;f :: Object -&amp;gt; Object&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;font-family: Times; margin: 0px;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;Or possible even:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;font-family: Times; margin: 0px;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;f :: Object -&amp;gt; (Object, State)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;
We&#39;re not sure! We would prefer:&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;margin: 0px;&quot;&gt;&lt;span style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;f :: Object -&amp;gt; State&lt;/span&gt;&lt;/div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;b&gt;&lt;u&gt;Usage of State&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
The next question is, how is this state really used? It is not really part of an object&#39;s update function, as the multiple contexts suggest the data is not part of the object. So, what is the client code of the object doing with the state? It doesn&#39;t really matter. Whatever it&#39;s doing, we can infer that:&lt;br /&gt;
a) The state is a &lt;i&gt;product&lt;/i&gt; of the object. If it were not, it would not be in the object.&lt;br /&gt;
b) We have multiple contexts, implying multiple passes over the data.&lt;br /&gt;
&lt;br /&gt;
When a piece of state is the product of an object, it is likely that it is intermediate data. Given that we expect multiple passes over the data, we&#39;re going to be caching a lot of pieces of state data that have nothing to do with the context in question. We could switch the state representation from SoA to AoS, but it&#39;s still data in the wrong place.&lt;br /&gt;
&lt;br /&gt;
Let&#39;s say we have 10 &#39;contexts&#39; and 100 objects. Let&#39;s say the object is 20 bytes, and the &#39;state&#39; is 6 byte. We have a total data volume of 100 * (20 + 6 * 10) bytes, of which 100 * (20 + 6) bytes is used. Out of the total data volume, we&#39;re therefore using only 33% of the total data volume.&lt;br /&gt;
&lt;br /&gt;
So, if we switch from the:&lt;br /&gt;
&lt;br /&gt;
[Object] -&amp;gt; [Object]&lt;br /&gt;
&lt;br /&gt;
implementation to a&lt;br /&gt;
&lt;br /&gt;
[Object] -&amp;gt; [State]&lt;br /&gt;
&lt;br /&gt;
implementation, we now have 100 * 20 + 100 * 6 bytes total data volume and 100% of the data is used.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;u&gt;Where is the data going?&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
The previous transformation is essentially a map operation. We&#39;re applying a function a list of Objects, and returning a list of State objects. A state is not an endpoint of a data processing; it implies that further processing is going to use the data.&lt;br /&gt;
&lt;br /&gt;
Returning to Haskell, let&#39;s say our original state-producing function is f:&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;state = map f objects&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Something else, g, is going to use that data:&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;output = map g (map f objects)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;font-family: Times; margin: 0px;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;Or in terms of function application:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;g . f&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;
Here&#39;s our first big clue. All that data that originally lived inside the object, most likely on the heap, is really just intermediate data polluting the cache. It&#39;s just input to a succeeding function. We can most likely eliminate that &quot;state&quot; data altogether and pass the output directly through to the succeeding function. Or, we can store the state in some piece of intermediate thread-local storage. Either way, we&#39;ve now got a clearer understanding of the real data flow in the program.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;u&gt;Eliminating the containing Object&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
The next question becomes, which bits of the Object really contribute to the new output State?&lt;br /&gt;
&lt;br /&gt;
As the State is the product of an Object, and Object is non-trivial it is unlikely that the State is a product of the entire Object. It is probably some subset of member variables.&lt;br /&gt;
&lt;br /&gt;
To use something of a straw man example, suppose the code in question is a visibility operation. Suppose that Object holds a bounding volume, some geometry, and the State holds various visibility test results, distances, LODs and the likely. Our transformation is therefore more likely to be:&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;BoundingVolume -&amp;gt; LodDescription -&amp;gt; State&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Most of the Object&#39;s data is not used here. We&#39;ve passed a subset of the Object&#39;s data to some function. This is a naive pattern in C++ code. Useful, general, common patterns of code are often hidden behind a facade of encapsulation. Unrelated pieces of data (in a given context) are brought in unnecessarily. When we develop a semi-abstract purely functional description of the operation, we can build a much clearer understanding of the data flow and dependencies.&lt;br /&gt;
&lt;br /&gt;
Now imagine rewriting and structuring this operation in C++ based on this understanding of the data. Arguably an experienced programmer can arrive directly at the same conclusion, but I find the Haskell notation a useful intermediate tool for reasoning about data flows.</content><link rel='replies' type='application/atom+xml' href='http://tomhammersley.blogspot.com/feeds/1214209641787315513/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomhammersley.blogspot.com/2011/04/designs-that-leak-state-using-haskell.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/1214209641787315513'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/1214209641787315513'/><link rel='alternate' type='text/html' href='http://tomhammersley.blogspot.com/2011/04/designs-that-leak-state-using-haskell.html' title='Designs That Leak State: Using Haskell Notation to Analyse C++ Design'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1191561667656967116.post-7717995868353673384</id><published>2011-04-07T08:21:00.000+01:00</published><updated>2011-04-07T08:21:52.437+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Haskell"/><category scheme="http://www.blogger.com/atom/ns#" term="Raytracing"/><title type='text'>Ray-Triangle Intersection in Haskell</title><content type='html'>Recently, I&#39;ve been experimenting with different ray-triangle intersection algorithms. There are many alternatives out there, and many more optimisations and special cases, but I was looking for an version that ran quickly, and &quot;suited&quot; functional programming.&lt;br /&gt;
&lt;br /&gt;
I settled on the half-planes solution. This algorithm defines a plane at each edge of the triangle by crossing the triangle&#39;s normal and the edge direction. To check if a triangle is inside the triangle, you simply check to see if a point (on the plane of the triangle) is on the same side of all of those planes.&lt;br /&gt;
&lt;br /&gt;
This costs a little extra storage space, but it&#39;s a very fast test.&lt;br /&gt;
&lt;br /&gt;
So. How does the code pan out? Well, pointInsideTriangle is simple enough:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;distanceToPlane :: Shape -&amp;gt; Vector -&amp;gt; Float&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;distanceToPlane (Plane !norm !dist) !pos = pos `dot3` norm + dist&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;distanceToPlane _ _ = undefined&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;pointInsideTriangle :: Triangle -&amp;gt; Position -&amp;gt; Bool&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;pointInsideTriangle !tri !point = foldr (&amp;amp;&amp;amp;) True $ map (\pln -&amp;gt; (distanceToPlane pln point) &amp;gt;= 0) (halfPlanes tri)&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;This is best read right-to-left. The map applies a lambda function to each of the half planes. This function simply returns a bool, telling us if a point is on the correct side of a triangle. This yields a list of bools. We need to turn that into a single result; this is done using a fold to reduce many values to a single Bool. I&#39;ve deliberately used a right-fold so that the fold lazily consumes only the necessary parts of the list. It can early-out.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;So there we have it. One line of Haskell (with a couple of helper functions) to do the test.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;The rest of the Haskell code for a ray-triangle intersection is pretty straightforward:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;intersectRayTriangle :: Ray -&amp;gt; Object -&amp;gt; Triangle -&amp;gt; Bool -&amp;gt; Maybe (Float, Triangle)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;intersectRayTriangle !ray !obj !triangle !doubleSided&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;| doubleSided == False &amp;amp;&amp;amp; (direction ray) `dot3` (normal $ plane triangle) &amp;gt; 0 = Nothing&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;| otherwise = case shapeClosestIntersect (plane triangle) ray obj of&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Nothing -&amp;gt; Nothing&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Just (dist&#39;, _) -&amp;gt; if pointInsideTriangle triangle (pointAlongRay ray dist&#39;)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; then Just (dist&#39;, triangle)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; else Nothing&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Here we have a simple guard condition to permit backface culling. If the triangle is not double-sided, we do a backface culling test and possibly reject it. If not, we fall through to the default case and intersect the ray against the plane, and then test that intersection point for containment in the triangle.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Intersecting against a list is an interesting case. A simple version would just map against the list, and then attempt to find the closest intersection out of the resulting list. However, if we use tail recursion, we can add a parameter to hold our current &quot;state&quot; and therefore maintain a current-closest intersection. This eliminates a second search-the-list step, and also permits an early-reject optimisation:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;intersectRayTriangleList :: [Triangle] -&amp;gt; Int -&amp;gt; Maybe (Float, Int) -&amp;gt; Ray -&amp;gt; Object -&amp;gt; Maybe (Float, Int)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;intersectRayTriangleList !(x:xs) !index !currentResult !currentRay !obj = intersectRayTriangleList xs (index + 1) newResult newRay obj&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;where&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;(newRay, newResult) = case intersectRayTriangle currentRay obj x False of&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Nothing -&amp;gt; (currentRay, currentResult)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Just (dist, _) -&amp;gt; (shortenRay currentRay dist, Just (dist, index))&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;intersectRayTriangleList [] _ !currentResult _ _ = currentResult&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;The pattern of &quot;searching a list of x and return the closest&quot; occurs frequently in raytracing. This is a potential candidate to be factored out into a re-usable function, or possibly even a monad.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;The resulting code is also quite efficient. I&#39;m now running at less than a minute for my test scene of the Cornell Box with 8x8 distributed raytracing. This is 30% quicker than my previously &lt;span class=&quot;Apple-style-span&quot; style=&quot;line-height: 19px;&quot;&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: Times, &#39;Times New Roman&#39;, serif;&quot;&gt;Möller-Trumbore&lt;/span&gt;&lt;/span&gt;&amp;nbsp;ray-triangle intersection test.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tomhammersley.blogspot.com/feeds/7717995868353673384/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomhammersley.blogspot.com/2011/04/ray-triangle-intersection-in-haskell.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/7717995868353673384'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/7717995868353673384'/><link rel='alternate' type='text/html' href='http://tomhammersley.blogspot.com/2011/04/ray-triangle-intersection-in-haskell.html' title='Ray-Triangle Intersection in Haskell'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1191561667656967116.post-3648985694927079724</id><published>2011-04-03T22:28:00.003+01:00</published><updated>2011-04-04T22:16:54.354+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Haskell"/><category scheme="http://www.blogger.com/atom/ns#" term="Parallelism"/><category scheme="http://www.blogger.com/atom/ns#" term="Raytracing"/><title type='text'>How to Parallelise A Haskell Raytracer</title><content type='html'>One of the big attractions of functional languages is that they&#39;re theoretically very easily to parallelise as they have no problematic side-effects You only describe how to perform a calculation, and never touch on the details of moving data around the machine. The run-time is then free to process data, given your functional expressions, in parallel.&lt;br /&gt;
&lt;br /&gt;
I&#39;ve been experimenting with Haskell&#39;s basic parallelism primitives, par, and pseq. These primitives trigger (&quot;spark&quot;) evaluation of expressions in parallel - but only if the runtime deems it necessary.&lt;br /&gt;
&lt;br /&gt;
After many failed or mildly successful experiments, I&#39;ve finally managed to get a speedup. In short, I stopped trying to reinvent the wheel myself. I simply used parListChunk:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;rayTraceImage :: Camera -&amp;gt; Int -&amp;gt; Int -&amp;gt; SceneGraph -&amp;gt; [Light] -&amp;gt; [Colour]&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;rayTraceImage camera renderWidth renderHeight sceneGraph lights = map (clamp . tracePixel eyePosition sceneGraph lights) rayDirections `using` parListChunk 256 rseq&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;where !rayDirections = [makeRayDirection renderWidth renderHeight camera (x, y) | y &amp;lt;- [0..(renderHeight - 1)], x &amp;lt;- [0..(renderWidth - 1)]]&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;!eyePosition = Camera.position camera&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Here, we break the list of rays to be traced into data parallel chunks of 256, each free to be evaluated by a different thread. Each of these chunks is processed using map. Map applies the raytracing function to convert a ray direction into a colour, and we clamp the result.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;And that&#39;s it.&lt;br /&gt;
&lt;br /&gt;
Running it on two threads on my dual-core MacBook Pro halves the execution time.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;What&#39;s nice is that the core &#39;map&#39; expression is separated from the details of parallelisation. We&#39;ve separated the concepts of raytracing and its parallel decomposition into two separate concerns. We are therefore free to vary either without intertwining their concerns.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Not a critical section, lock-free queue or atomic operation in sight!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
Clearly, the nature of the functional approach surrenders a lot of low-level implementation details to your platform&#39;s runtime. However, it is more frequently the case that when you require such low-level intervention, you are working around deficiencies in your run-time platform, rather than dealing with fundamental algorithm details. Parallelising many algorithms follows established patterns.&lt;br /&gt;
&lt;br /&gt;
It is also worth noting that the raytracer code is currently pretty straightforward code. I&#39;ve not implemented any particular tricky optimisations, and certainly none of the ideas in work such as Ingo Wald&#39;s parallel raytracing PhD thesis. Not yet, anyway...&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tomhammersley.blogspot.com/feeds/3648985694927079724/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomhammersley.blogspot.com/2011/04/how-to-parallelise-haskell-raytracer.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/3648985694927079724'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/3648985694927079724'/><link rel='alternate' type='text/html' href='http://tomhammersley.blogspot.com/2011/04/how-to-parallelise-haskell-raytracer.html' title='How to Parallelise A Haskell Raytracer'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1191561667656967116.post-6375617835330877980</id><published>2011-03-24T13:38:00.001+00:00</published><updated>2011-03-25T07:12:31.249+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Haskell"/><category scheme="http://www.blogger.com/atom/ns#" term="Optimisation"/><category scheme="http://www.blogger.com/atom/ns#" term="Raytracing"/><title type='text'>Laziness vs Strictness in Haskell</title><content type='html'>I&#39;ve just taken over a minute of execution time off my raytracer.&lt;br /&gt;
&lt;br /&gt;
One of Haskell&#39;s biggest language features is the lazy evaluation system. By default, Haskell evaluates nearly all expressions lazily, as needed. This is one of the features that drew me to Haskell, and indeed it seems a reasonably apt way of writing a raytracer. Raytracing often consists of selectively traversing different parts of large databases for different parts of the scene. Many acceleration schemes involve simple mechanisms to lazily evaluate results.&lt;br /&gt;
&lt;br /&gt;
Laziness, however, does pose an overhead. Haskell introduces a &quot;thunk&quot; for every lazy expression. A thunk describes how to calculate a deferred expression when required. For some expressions, a thunk is a potential time saver: you can defer work until needed, calculate the required value, then re-use it. For other things, such as simple arithmetic operations like vector addition, a thunk is an overhead often comparable to the original operation.&lt;br /&gt;
&lt;br /&gt;
Haskell offers a couple of ways to avoid thunks and therefore lazy evalation. The main two I use are the BangPatterns extension to explicitly mark something as strictly (ie, non-lazily) evaluated, and seq.&lt;br /&gt;
&lt;br /&gt;
The BangPatterns extension allows you to mark expressions that you want to be explicitly evaluated with a !. So, for a Vector, you would write Vector !Float !Float !Float !Float. This way, you force anything you assign to a vector to be strictly evaluated and stored in the vector.&lt;br /&gt;
&lt;br /&gt;
Seq is used to strictly force the evaluation of a function. Seq has the signature of a -&amp;gt; b -&amp;gt; a. It therefore takes two parameters, and returns the second.&lt;br /&gt;
&lt;br /&gt;
An interesting example of where lazy evaluation proven to be an overheard, rather than a win was my light accumulation function. Given a point in space to be shaded, this accumulates the contribution of every light source. Now, the inputs to this function are going to be different every time this function is called as every ray intersection is going to be unique. Thunks will therefore present an additional overhead.&lt;br /&gt;
&lt;br /&gt;
I rewrote my function to use seq. I use seq to strictly evaluate the application of this function, then process the remainder of the list:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;accumulateLight :: [Light] -&amp;gt; Colour -&amp;gt; SceneGraph -&amp;gt; Vector -&amp;gt; Vector -&amp;gt; Material -&amp;gt; Vector -&amp;gt; Colour&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;accumulateLight (x:xs) acc sceneGraph shadePos normal objMaterial viewDirection = let result = acc + (applyLight sceneGraph shadePos normal objMaterial viewDirection x)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;in seq result (accumulateLight xs result sceneGraph shadePos normal objMaterial viewDirection)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;accumulateLight [] acc _ _ _ _ _ = acc&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;This change alone saved over a minute of execution time! Since a raytracer generally consists of many similar kinds of loops, I am now searching for wider application of this technique. It&#39;s a very difficult call to make with a limited data set. Some functions may be faster if strictly evaluated with a small dataset, but may perform better if evaluated lazily with a larger dataset.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Profiling will guide me.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tomhammersley.blogspot.com/feeds/6375617835330877980/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomhammersley.blogspot.com/2011/03/laziness-vs-strictness.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/6375617835330877980'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/6375617835330877980'/><link rel='alternate' type='text/html' href='http://tomhammersley.blogspot.com/2011/03/laziness-vs-strictness.html' title='Laziness vs Strictness in Haskell'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1191561667656967116.post-5883253646635516549</id><published>2011-03-23T09:52:00.002+00:00</published><updated>2011-03-25T07:12:09.698+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="DOD"/><category scheme="http://www.blogger.com/atom/ns#" term="OOP"/><category scheme="http://www.blogger.com/atom/ns#" term="Parallelism"/><title type='text'>Pragmatism vs Idealism (DOD vs OOP)</title><content type='html'>So, it seems no blog these days is complete without a yet another stab at the DOD vs OOP argument.&lt;br /&gt;
&lt;br /&gt;
Here&#39;s my take.&lt;br /&gt;
&lt;br /&gt;
I could have picked any number of &amp;nbsp;dichotomy based titles for this post. Objective vs Subjective. Pragmatism vs Idealism. Design vs Performance. PC vs Console. There is a tendency to view DOD and OOP as somewhat polar extremes that you are either for, or against. Personally, I see merit in both camps. It is something of a false dichotomy. I see value in the ideals of OOP and DOD. Equally, I see shortcomings in both camps. For me, it&#39;s not an either/or, it&#39;s a question of how you blend them together.&lt;br /&gt;
&lt;br /&gt;
For me, the real key issue is choosing what approach to adopt for a given task. This is where the real challenge lies.&lt;br /&gt;
&lt;br /&gt;
The arguments used to support OOP are essentially based on intangible qualities. Design. Re-use. Extensibility. Maintainability. Elegance. Whilst valuable, these are generally somewhat subjective qualities. What constitutes good design is based on widely held best practices, and those practices are based on a consensus of constantly evolving expert opinion. It&#39;s very hard to measure these things explicitly. It&#39;s very hard to say how much &quot;better&quot; a more OOP centric approach can make&amp;nbsp;a piece of code.&lt;br /&gt;
&lt;br /&gt;
The arguments for DOD, by contrast, are based on real-world, objective data: performance. You can directly measure performance, and directly state the improvement that a DOD approach has yielded for a given task. Similarly, you can measure the cost of an OOP based approach in terms of lost performance. Performance has a useful, marginal benefit in a software project. Other qualities have their benefits but are frequently less directly felt.&lt;br /&gt;
&lt;br /&gt;
You therefore end up with a challenging situation. How can the intangible qualities that support OOP argue against the real-world, objective data supporting DOD?&amp;nbsp;How can we support OOP&amp;nbsp;over DOD when it is based on subjective preferences,&amp;nbsp;leading to design decisions that are somewhat arbitrary.&amp;nbsp;&lt;em&gt;Especially when you are trying to a ship a console game!&lt;/em&gt;&lt;br /&gt;
&lt;br /&gt;
As I see it, the performance data that supports DOD should be supporting both arguments. The current generation of consoles in many ways are indicative of what future computing platforms will generally look like. Many cores. Slow memory. Long, simple instruction pipelines.&lt;br /&gt;
&lt;br /&gt;
OOP has its positive qualities, but it is important to view it in context: it largely emerged as a means of improving the structure of large software systems by breaking software into singular, encapsulated objects. Whilst these concerns are significant, there are other, equally valid&amp;nbsp;ways of addressing those concerns than OOP alone. And with the continuing, accelerating&amp;nbsp;trend of parallel hardware, OOP alone cannot be positioned as the primary concern in designing software systems. &lt;br /&gt;
&lt;br /&gt;
For me, my primary concern in software design is parallelism first, DOD second and OOP third.</content><link rel='replies' type='application/atom+xml' href='http://tomhammersley.blogspot.com/feeds/5883253646635516549/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomhammersley.blogspot.com/2011/03/pragmatism-vs-idealism.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/5883253646635516549'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/5883253646635516549'/><link rel='alternate' type='text/html' href='http://tomhammersley.blogspot.com/2011/03/pragmatism-vs-idealism.html' title='Pragmatism vs Idealism (DOD vs OOP)'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1191561667656967116.post-7121738686134190851</id><published>2011-03-22T19:33:00.001+00:00</published><updated>2011-03-23T09:53:22.224+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Haskell"/><category scheme="http://www.blogger.com/atom/ns#" term="Raytracing"/><title type='text'>Sphere Tree Construction and Traversal in Haskell</title><content type='html'>Finally. I&#39;ve finally finished writing and debugging my sphere tree construction code in Haskell.&lt;br /&gt;
&lt;br /&gt;
It should have been so easy. Tree structures are very easily recursively defined which is ideal for functional languages like Haskell. Take your data, split it up, and build the children by recursion. Simple. Only it was anything but...&lt;br /&gt;
&lt;br /&gt;
The logic of the task was simple enough. The main problem was debugging. This is the sort of task that is prone to simple mistakes that cause time-consuming debugging problems. When working in an imperative language, you can easily put down a breakpoint and inspect your data, or if you recur too much the stack blows up, or you can step through your code and see why you&#39;re getting stuck in loops. These strategies don&#39;t map well to Haskell.&lt;br /&gt;
&lt;br /&gt;
What does work in Haskell is to start small, build up gradually and constantly verify your results. You end up with a development cycle that is fundamentally very similar to test driven development. You want to prove your code one little function at a time by feeding it controlled inputs and inspecting the outputs. In Haskell, your primary debugger is your brain - you need to think very carefully through your code and how your express your algorithms. Functional languages reduce the scope of creating simple bugs due to side effects, and Haskell in particular eliminates a lot of plumbing and housekeeping code. What&#39;s left is purely your algorithm - inspect it carefully, that is where your problem lies.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;u&gt;Bounding Volume Hierarchies&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
I considered a few approaches for my bounding volume hierarchy, and for now, I&#39;ve settled on a fairly generic implementation of bounding volume hierarchies that currently is configured as a sphere tree.&lt;br /&gt;
&lt;br /&gt;
Each tree node can optionally (Maybe) hold an object. Each node has a sphere, but that could later be generalised. The children are defined as a list, allowing me to switch using a quadtree, kdtree or octree type approach.&lt;br /&gt;
&lt;br /&gt;
(Note: The code below is best copied and viewed in a real text editor. Also, I am not yet a Haskell expert, and there may be many superior ways to achieve these results. My purpose in writing is to share my experiences as a learner with other learners.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;data SphereTreeNode = SphereTreeNode { object :: Maybe Object, children :: [SphereTreeNode], boundingRadius :: Float, boundingCentre :: Vector } deriving (Show, Read)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;u&gt;Sphere Tree Construction&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
The tree itself is constructed using a fairly simple piece of Haskell:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;-- Build up a sphere tree&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;buildSphereTree :: ([Object] -&amp;gt; [[Object]]) -&amp;gt; [Object] -&amp;gt; SphereTreeNode&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;buildSphereTree _ (obj : []) = SphereTreeNode (Just obj) [] nodeRadius nodeCentre&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;where&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;nodeCentre = calculateMeanPosition (obj:[])&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;nodeRadius = calculateBoundingRadius (obj:[]) nodeCentre&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;buildSphereTree builder (obj:objs)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;| length (obj:objs) == 1 = error &quot;Should have been handled by a different pattern&quot;&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;| length (obj:objs) == 0 = error &quot;Should not have zero objects&quot;&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;| otherwise = SphereTreeNode Nothing nodeChildren nodeRadius nodeCentre&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;where&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;nodeCentre = calculateMeanPosition (obj:objs)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;nodeRadius = calculateBoundingRadius (obj:objs) nodeCentre&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;nodeChildren = map (buildSphereTree builder) (builder (obj:objs))&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;buildSphereTree _ [] = error &quot;Should not hit this pattern for buildSphereTree&quot;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;-- Find the mean of a collection of objects&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;calculateMeanPosition&#39; :: [Object] -&amp;gt; Vector -&amp;gt; Vector&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;calculateMeanPosition&#39; (obj : objects) acc = calculateMeanPosition&#39; objects acc + (getCentre obj)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;calculateMeanPosition&#39; [] acc = acc&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;calculateMeanPosition :: [Object] -&amp;gt; Vector&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;calculateMeanPosition objects = setWTo1 ((calculateMeanPosition&#39; objects zeroVector) fromIntegral (length objects))&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;-- Find the overall bounding radius of a list of objects&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;calculateBoundingRadius :: [Object] -&amp;gt; Vector -&amp;gt; Float&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;calculateBoundingRadius objs centre = foldr Prelude.max 0 (map (\obj -&amp;gt; shapeBoundingRadius (shape obj) (transform obj) centre) objs)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;This object simply recursively builds a tree until it encounters an object list of size 1.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;I&#39;ve deliberately exercised a couple of Haskell idioms here. I&#39;ve used another tail-recursive loop to calculate the mean centre of the objects, and a map/fold pair to calculate the sphere&#39;s bounding radius.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;The most interesting part is the first parameter to buildSphereTree. I pass in a function of type ([Object] -&amp;gt; [[Object]]). This function is responsible for dividing the object list into a number of lists, each of which is the object list used to build a new child node. This trick allows me to abstract out the specific algorithm for building the tree into a user-supplied function.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;In my current code, I&#39;m using a simple KD-type approach:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;-- Generate a plane to split the objects along&lt;/div&gt;&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;makeSplittingPlane :: AABB -&amp;gt; (Vector, Float)&lt;/div&gt;&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;makeSplittingPlane (boxMin, boxMax) = case largestAxis (boxMax - boxMin) of&lt;/div&gt;&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;0 -&amp;gt; (xaxis, -(vecX midPoint))&lt;/div&gt;&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;1 -&amp;gt; (yaxis, -(vecY midPoint))&lt;/div&gt;&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;2 -&amp;gt; (zaxis, -(vecZ midPoint))&lt;/div&gt;&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;_ -&amp;gt; error &quot;Undefined value&quot;&lt;/div&gt;&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;where&lt;/div&gt;&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;midPoint = (boxMin + boxMax) &amp;lt;*&amp;gt; 0.5&lt;/div&gt;&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;-- Make children using a kd tree&lt;/div&gt;&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;generateSceneGraphUsingKDTree :: [Object] -&amp;gt; [[Object]]&lt;/div&gt;&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;generateSceneGraphUsingKDTree objs = leftObjects : rightObjects : []&lt;/div&gt;&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;where&lt;/div&gt;&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;objBox = objectListBoundingBox objs&lt;/div&gt;&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;(planeNormal, planeDist) = makeSplittingPlane objBox&lt;/div&gt;&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;(leftObjects, rightObjects) = partition (\obj -&amp;gt; planeDist + (dot3 planeNormal $ getCentre obj) &amp;gt; 0) objs&lt;/div&gt;&lt;div style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;&quot;&gt;We simply make a splitting plane and split the list of objects according to what side of the plane their centre lies: [[Object], [Object]].&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;&quot;&gt;I could easily replace this function with an alternative strategy. Or even, make a function that returns a function based on the characteristics of the presented list...&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: Times, &amp;quot;Times New Roman&amp;quot;, serif;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;u&gt;Bounding Volume Hierarchy Intersection&lt;/u&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Now this is the real meat of the implementation. The function again takes the form of a tail-recursive loop. The code is essentially similar to implementing a recursive function using a software stack in C. The tail recursion is used to make a simple loop-type recursion rather than a true state-accumulation call-type recursion.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;The code is somewhat complex as several optimisations have been added.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;The code is passed a list of nodes to process. We process the first node in the list, and recur with the remainder of the list - and possibly, some newly added nodes. The code seeks to find and maintain the closest-intersecting object.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;The code constructs a tuple of three values - a result for this object, a list of additional nodes to process and a ray. If an object or bounding volume is hit, this tuples holds new values. If no intersection is found, we simply continue with the existing state passed into the function.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;The code first considers whether the given node has any children; if it has none, it only makes sense to test the object that the node should hold. We report an error if the node has no object (a node without children or objects is useless!).&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;If the node does have children, it holds a subtree we wish to accept or reject. We first test the bounding volume. If this is rejected, we simply retain the current results of the loop with no additional nodes to process. If the bounding volume is intersected, then we will at least recur to the children nodes. If the node contains an object and it is intersected, we update our current intersection results and shorten our ray.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Finally, we pattern match the empty array case to simply return the current results.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Here is the code:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;intersectSphereTree :: [SphereTreeNode] -&amp;gt; Ray -&amp;gt; Maybe (Object, Float, Int) -&amp;gt; Maybe (Object, Float, Int)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;intersectSphereTree (node:nodes) ray currentHit = intersectSphereTree (newNodeList ++ nodes) newRay thisResult&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;where&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;-- Intersect the ray with the bounding volume of this node&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;(thisResult, newNodeList, newRay) = case children node of&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;-- If the node has no children, don&#39;t bother with it&#39;s bounding volume and just check the object (if it has one)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;[] -&amp;gt; case object node of&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Nothing -&amp;gt; error &quot;A node with no children should hold an object&quot;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Just obj -&amp;gt; case shapeIntersect (shape obj) ray (transform obj) of&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -- Didn&#39;t hit the object. Retain the current hit, and continue with remaining nodes on the list&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Nothing -&amp;gt; (currentHit, [], ray)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -- We did hit this object. Update the intersection, and continue with remaining nodes on the list&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Just (objHitDistance, objHitId) -&amp;gt; (Just (obj, objHitDistance, objHitId), [], shortenRay ray objHitDistance)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;-- We have children. In this case it makes sense to test our bounding volume&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;nodeChildren -&amp;gt; case shapeIntersect (Sphere (boundingRadius node)) ray (translationMatrix&#39; (boundingCentre node)) of -- (make a sphere centred at the object&#39;s transform matrix with given radius)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;-- If we do not find an intersection, we do not update the results and we offer no further nodes to be traversed, thus skipping this subtree&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Nothing -&amp;gt; (currentHit, [], ray)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;-- If we do find an intersection against the bounding volume, then we try again against the actual object (if present)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Just (_, _) -&amp;gt; case object node of&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Nothing -&amp;gt; (currentHit, nodeChildren, ray) -- No object; just pass to the children&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Just obj -&amp;gt; case shapeIntersect (shape obj) ray (transform obj) of&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -- Didn&#39;t hit the object. Retain the current hit, but offer up the children of the node as we hit the bounding volume&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Nothing -&amp;gt; (currentHit, nodeChildren, ray)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -- We did hit this object. Update the intersection, and continue with the bounding volume&#39;s children&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Just (objHitDistance, objHitId) -&amp;gt; (Just (obj, objHitDistance, objHitId), nodeChildren, shortenRay ray objHitDistance)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &amp;quot;Courier New&amp;quot;, Courier, monospace;&quot;&gt;intersectSphereTree [] _ currentHit = currentHit&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;The striking thing about this code is that it steadily marches to the right of the screen, with each indentation being a new test of success or failure. Ideally, this code could be rewritten as a monad.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;u&gt;What About Infinite Objects?&lt;/u&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;u&gt;&lt;br /&gt;
&lt;/u&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;They&#39;re simply &quot;filter&quot;ed out at the time of the sphere tree construction, and added to a separate list. It makes little sense to include an infinite object into any bounding volume hierarchy.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;u&gt;Results&lt;/u&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;u&gt;&lt;br /&gt;
&lt;/u&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;The code continues to render my test scene as expected. Disappointingly, it is currently a little slower; however, this is not due to the scene graph code. I have recently rewritten my vector classes to be instances of the Num typeclass, so that I can simply write a + b, rather than coining new operators such as a &amp;lt;+&amp;gt; b. I haven&#39;t yet fully optimised my new code.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;u&gt;Other Observations&lt;/u&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;u&gt;&lt;br /&gt;
&lt;/u&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;As I get further into Haskell, I&#39;m finding myself increasingly thinking in terms of Lambda calculus. I no longer find myself thinking of what iterative steps I need to do to complete an operation, rather I find myself thinking in terms of the transformations of the underlying data and accompanying functions.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;I find this new perspective very helpful when returning to other languages. It gives you a somewhat stream-processing-like perspective and thought process when facing standard C++ code.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;u&gt;What&#39;s Next?&lt;/u&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;u&gt;&lt;br /&gt;
&lt;/u&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;The main focus now is to diagnose, understand and resolve the issues with my new typeclass-based fundamental data types such as Vector and Colour. I want to get it below the ~70 seconds it was previously taking. Following that, it is now time to build a parser and load some standard test scenes that will allow me to develop and optimise the ray tracer further.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tomhammersley.blogspot.com/feeds/7121738686134190851/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomhammersley.blogspot.com/2011/03/sphere-tree-construction-and-traversal.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/7121738686134190851'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/7121738686134190851'/><link rel='alternate' type='text/html' href='http://tomhammersley.blogspot.com/2011/03/sphere-tree-construction-and-traversal.html' title='Sphere Tree Construction and Traversal in Haskell'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1191561667656967116.post-1869481415402334378</id><published>2011-03-03T20:59:00.001+00:00</published><updated>2011-03-03T21:01:01.546+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Haskell"/><category scheme="http://www.blogger.com/atom/ns#" term="Raytracing"/><title type='text'>A worked Haskell example</title><content type='html'>I thought it might be interesting to do a worked example of some work-in-progress Haskell to discuss what I like about it.&lt;br /&gt;
&lt;br /&gt;
The case in question is the code that traverses the scene graph and intersects a ray.&lt;br /&gt;
&lt;br /&gt;
Now, I&#39;m putting the ultimate efficiency and DOD type concerns aside for a moment. I grant you there may be more efficient/better ways of doing this, it&#39;s just for discussion purposes.&lt;br /&gt;
&lt;br /&gt;
Disclaimer: I am not (yet) a Haskell expert. There are probably better ways of doing this or writing it in Haskell. I write for the reasons of discussing what I&#39;ve learnt about trying to write a practical application in Haskell. If there are better ways of doing it, I&#39;d love to know, as I&#39;m still learning.&lt;br /&gt;
&lt;br /&gt;
So, first up, the code:&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;intersectSceneGraph&#39; :: [SceneGraphNode] -&amp;gt; Ray -&amp;gt; Maybe (Object, Position, Int) -&amp;gt; Maybe (Object, Position, Int)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;intersectSceneGraph&#39; (node:nodes) ray currentHit = intersectSceneGraph&#39; (newNodeList ++ nodes) ray thisResult&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;where&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;(thisResult, newNodeList) = case shapeIntersect (Sphere $ boundingRadius node) ray (transform (object node)) of&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Nothing -&amp;gt; (currentHit, [])&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Just (_, _) -&amp;gt; case shapeIntersect nodeObjectShape ray nodeObjectTransform of&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Nothing -&amp;gt; (currentHit, children node)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Just (objHitDistance, objHitId) -&amp;gt; (Just (object node, pointAlongRay ray objHitDistance, objHitId), children node)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; where&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; nodeObjectShape = shape $ object node&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; nodeObjectTransform = transform $ object node&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;intersectSceneGraph&#39; [] _ currentHit = currentHit&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;intersectSceneGraph :: SceneGraphNode -&amp;gt; Ray -&amp;gt; Maybe (Object, Position, Int)&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;intersectSceneGraph node ray = intersectSceneGraph&#39; (node : []) ray Nothing&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;(If the code does not display clearer in your browser, cut and paste to a text editor)&lt;br /&gt;
&lt;br /&gt;
This function is split into two parts. intersectSceneGraph is essentially a front end, a wrapper for intersectSceneGraph&#39;. intersectSceneGraph&#39; traverses a list of scene graph nodes, tests the ray against the bounding volume, and if it intersets it, it then intersects against the contained object and recurs to the children.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;So, how does it traverse a tree?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;The Haskell code is very similar to C code that traverses a tree using a software stack.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;The operation is defined in a tail recursive fashion. I process one element of the list, and then recur to the remainder of the list. If the node in question is a new closest hit, this gets passed through to the next recursion as the new current state. If the bounding volume is intersected, then I add the children of the node to the list. If it is not intersected, I add nothing, an empty list.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;This business of passing through state seems a little odd. Why would one instance of a function pass its internal state to another? This is a Haskell idiom. By passing the state from one call to another, as an &quot;accumulator&quot; parameter, it allows the compiler to eliminate any intermediate state on the stack and implement the recursion as a goto loop.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;And all of this is lazily evaluated.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;In pseudo-C, the code might look something like this:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;closestHit = null;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;while((topOfStack = stack.pop()) != NULL)&lt;br /&gt;
{&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;if(intersect(ray, topOfStack-&amp;gt;bounding volume))&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;{&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;if(intersect(ray, topOfStack-&amp;gt;object))&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;{&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;closestHit = this one&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;push(stack, topOfStack-&amp;gt;children);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;}&lt;/span&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;I think this shows the elegance of Haskell. Think of what is not there. There are no braces to explain scope to the compiler: you just indent it. There are no incidental variables describing the state of loop variables and so on. The compiler automatically pattern matches and dispatches to appropriate special cases instead. No pointer walks. No null checks. No explicit shuffling of data from A to B. You have a closer, more direct description of your algorithm, and the compiler fills in the gubbins.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;Of course, there is a cost to all of this. By sacrificing that lower-level control, you lose out on the ultimate optimisability of the code. Still, the objective here is to find the best way to learn and use Haskell, rather than write the ultimate real-time raytracer in SIMD assembly! :-)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://tomhammersley.blogspot.com/feeds/1869481415402334378/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://tomhammersley.blogspot.com/2011/03/worked-haskell-example.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/1869481415402334378'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1191561667656967116/posts/default/1869481415402334378'/><link rel='alternate' type='text/html' href='http://tomhammersley.blogspot.com/2011/03/worked-haskell-example.html' title='A worked Haskell example'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>