news2mail.com

HomeMicrosoftPublic › Win32 › Programmer › Directx

microsoft.public.win32.programmer.directx.managed

Microsoft 32-bit development newsgroup.

The room for Managed DirectX — the .NET bindings over the DirectX multimedia and graphics APIs — where game and visualisation developers worked with purpose-written assemblies in the Microsoft.DirectX namespace, whose marshalling to the underlying native implementation was written for the job rather than generated over type libraries.

It sits in the win32.programmer branch alongside the native DirectX rooms; the branch’s other surviving page in this directory is the Win32 WMI group.

Long-form reference · 9,346 words · about a 41-minute read

A room named after a runtime

Read the group's name from the left and it narrows the way a filing system narrows. microsoft is the vendor. public distinguishes the openly propagated groups from the private ones that lived only on Microsoft's own server. win32 is the programming interface of the Windows of that generation, programmer the audience, directx the technology. Then comes the last component, and it does something none of the others do: managed names neither a product nor a subsystem but a manner of execution. It says that the code asking the questions in this room ran on the common language runtime rather than as native machine code linked against a set of headers.

That is unusual enough to be worth pausing over, because the branch above is otherwise a catalogue of things rather than of ways. Its siblings in the active file are kernel, gdi, ole, tapi, mmedia, ui, networks and the rest: pieces of Windows, each with a header file and an export list. The DirectX sub-branch continues in the same spirit — a room per component or per artefact — and then, at the end, adds one room defined entirely by the language you had arrived in. The distinction mattered because the thing on the other side of the door was the same thing in both cases. There was one Direct3D. What differed was the shape of the wrapper you reached it through, and the memory model of the process you reached it from.

The rest of this page is about that wrapper: what it was, why it was interesting, why a garbage collector and a render loop make uncomfortable neighbours, and why the technology this room existed to discuss was withdrawn, replaced, and then had its replacement withdrawn as well. The native-code side of the same branch — the COM mechanics, the interface tables, the reference counting — belongs to the Win32 WMI page, which also does the arithmetic on how many rooms this branch had and what they were called. It is not repeated here.

The paperwork, and how little of it there is

The Internet Systems Consortium's mirrored copy of the Usenet active file — the list from which a news server learns which groups exist and whether they accept posts — still carries this group. The entry says almost nothing. Name, unmoderated flag, and counters that were never advanced — catalogued but never filled. The companion newsgroups file, the descriptive list from which newsreaders build a browsable listing, carries no microsoft.* lines at all, so the standard record preserves not one sentence of self-description for this room or any of its neighbours.

The line shown above this article — Microsoft 32-bit development newsgroup — is therefore not a charter and never was. It is a generic branch-level description inherited from this directory's own listing, applied across the win32.programmer rooms without regard to what any of them was for. It does not mention DirectX, it does not mention managed code, and it would be equally true and equally useless of the TAPI room. The microsoft.* hierarchy never had charters in the Big-8 sense at all; the reasons are set out on the hierarchy's own page.

What the active file does establish is the shape of the neighbourhood. Ten rooms sit beneath microsoft.public.win32.programmer.directx: audio, ddk, graphics, graphics.shaders, input, managed, misc, networking, sdk and video. Nine of the ten are named after a component of the technology or an artefact of using it — a driver kit, a software development kit, a shader language. One is named after a runtime. The parent group itself, microsoft.public.win32.programmer.directx without a suffix, is not in the current active file at all, which leaves the ten children standing without the room they were split out of.

The control archive is more forthcoming, and also more curious. Eight of the ten rooms have surviving newgroup control messages, all issued from [email protected], and eight of them were created in one go. Between 16:28:06 and 16:29:17 Pacific time on Monday 23 April 2001 — seventy-one seconds — the graphics, audio, video, networking, input, SDK, DDK and miscellaneous rooms were all called into existence, one message after another, in that order, in what is plainly a script working through a list. Whoever ran it was subdividing a busy general DirectX room into a component-shaped set of smaller ones, and the timestamps show them doing it in a little over a minute.

The tidiness did not last. The DDK room alone was removed on 1 August 2001, recreated on the 7th, removed again on the 8th and recreated a third time on the 20th, all by the same address; and the parent group's own file ends with a newgroup at 14:09:50 on 28 August 2001 followed by an rmgroup for the same name at 14:10:33 — forty-three seconds later. That last pair is the likeliest reason the parent is absent from the active file today while all ten of its children remain in it.

Two of the ten rooms are missing from that record entirely. There is no control message anywhere in the archive for graphics.shaders, and none for managed — even though the archive kept collecting microsoft.* control traffic until 20 December 2009. Both groups are nevertheless in the active file. The honest conclusion is a negative one: the moment this room was created is not recoverable from the standard record, and this page does not guess at it.

There is one dated trace of the phrase, and it is a small comedy. On Thursday 28 March 2002 the same pssolops address issued a newgroup for microsoft.private.directx.managed at 15:18:03 Pacific time, and an rmgroup for the same name at 15:18:17 — fourteen seconds later. It is the sort of thing that happens when somebody creates a group in the wrong hierarchy and notices immediately. It proves nothing about the public room, but it does date the point at which the words directx and managed first appeared together in Microsoft's own newsgroup namespace: roughly nine months before the technology shipped.

One further oddity in the parent group's file is worth recording because it illustrates how vendor hierarchies actually propagated. The three oldest captured newgroup messages for microsoft.public.win32.programmer.directx did not come from Microsoft. They were emitted by other organisations' news servers, each carrying a Distribution: collabra-internal header and each politely announcing the group to the network on Microsoft's behalf: Cerberus AG in Switzerland on 9 April 1998, Lynden Incorporated in the United States on 13 November 1998, and Concentrex on 27 October 1999. Microsoft's own machines only start appearing in the record on 27 November 2000. Who signs the control messages for this hierarchy today is a separate story, and one the WMI page tells.

An awkward collision of vocabulary

Anyone searching Microsoft's own period documentation for this group runs almost immediately into a terminological trap, and it is worth defusing before going further. In May 2004 MSDN Magazine ran a Resource File describing the company's newsgroup programme. Microsoft, it said, offered more than 1,900 public and 500 private newsgroups; an individual newsgroup might get up to 15,000 postings per month; the public groups were fed to Usenet and lived on servers outside Microsoft, reachable by pointing a newsreader at msnews.microsoft.com. So far, so descriptive.

Then it introduced the MSDN Managed Community Newsgroups — about 220 of them — and explained that in a managed newsgroup, MSDN subscribers were guaranteed priority service, receiving responses to their technical questions within two business days. A managed newsgroup, in other words, was one with a service-level agreement attached. It had nothing whatever to do with managed code. The same magazine, in the same period, was running feature articles about managed Direct3D.

The article's own examples of managed newsgroups came close enough to be tantalising without settling anything. It named microsoft.public.platformsdk.msi, microsoft.public.dotnet.framework.windowsforms and microsoft.public.win32.programmer.networks — the last of which sits a few doors along the same branch as this room. That establishes that the branch was inside the programme. It does not establish that this room was, and nothing traced for this page does. The coincidence of vocabulary is noted here only so that a reader meeting both usages does not conclude they are the same thing.

DirectX in outline: what the wrapper wrapped

The technology underneath had a well-documented origin. In late 1994 Microsoft was preparing to ship Windows 95 and discovering that games programmers had no intention of leaving MS-DOS, where they could talk to the hardware directly, for an operating system that stood between them and the video card. Three employees — Alex St. John, Craig Eisler and Eric Engstrom — built a set of interfaces to remove the objection, under the codename Manhattan Project and without management's agreement, since management had already written Windows off as a gaming platform. The first release appeared on 30 September 1995 as the Windows Game SDK: DirectX was a name a journalist coined in mockery of the naming scheme, and the team kept it.

The component APIs were named for what they addressed, and the list is short enough to give in full. DirectDraw provided direct low-level access to video memory. DirectSound handled the playing and capturing of digital audio samples, DirectSound3D positional audio. DirectInput covered keyboards, mice, joysticks and force feedback. DirectPlay handled communication between players over a network. Direct3D arrived with DirectX 2 in 1996 and became the part everyone meant when they said DirectX. DirectMusic played soundtracks authored in DirectMusic Producer; DirectShow handled media playback and streaming; the D3DX extension library supplied the vector mathematics, the mesh, animation and texture handling, and the runtime shader assembler that Direct3D itself did not. The word Direct was literal: these routines bypassed the ordinary Windows graphics path and reached the hardware through an abstraction layer thin enough to be worth the trouble.

The versioning is the part that matters for this room, because DirectX moved on its own clock and that clock ran faster than Windows. Version 2 became a built-in component with Windows 95 OSR2 and Windows NT 4.0 in 1996; version 3 followed in September of the same year; version 4 was planned and then shelved for lack of developer interest in what it was to contain, so the numbering jumps to 5.0 in August 1997, 6.0 in August 1998, 7.0 in September 1999. Version 8.0 shipped on 10 November 2000, months before Windows XP; 8.1, dated 24 August 2001, was the version included with Windows XP as released to manufacturing. And DirectX 9.0 — the release that matters here — appeared on 19 December 2002, more than a year after the operating system it ran on, and supported Windows 98, Windows Me, Windows 2000 and Windows XP alike. A developer in 2003 was therefore targeting a graphics API newer than any shipping version of Windows, on machines that might be running an operating system four years old.

A gold-coloured printed circuit board graphics card lying on a pale surface, with a red, orange and yellow 'GeForce FX5900 PixelView' shroud and cooling fan over the processor, a copper heatsink beside it, DVI and VGA connectors on the metal bracket at the left, and an AGP edge connector along the bottom.
A PixelView GeForce FX 5900, an AGP graphics card from the 2003 generation, photographed in 2005. The GeForce FX series was Nvidia's first Direct3D 9 hardware. Managed DirectX shipped with DirectX 9.0 in December 2002 and stayed tied to that generation of the API, and to the D3DX9 library of April 2006, for the rest of its existence. Afrank99 · CC BY-SA 2.5 · via Wikimedia Commons.

That pattern broke exactly once, and the break is the backdrop to everything in the later half of this page. DirectX 9.0b followed in August 2003 and 9.0c in August 2004, bringing Shader Model 3.0 and arriving on Windows XP with Service Pack 2. Then DirectX 10 shipped only with Windows Vista. Windows XP was capped at 9.0c permanently, and the June 2010 redistributable was the last 9.0c release. For the best part of a decade, in other words, the DirectX version everybody actually had was the one Managed DirectX had been built against — which is one reason a deprecated library kept working long after it stopped being maintained.

Two administrative details of the same period are worth noting because they show the SDK itself being dismantled and reassembled around the developer. As of April 2005 DirectShow was removed from DirectX and moved into the Platform SDK, whose own room in this hierarchy is discussed on the Platform SDK security page. And from the Windows 8 Developer Preview onwards the DirectX SDK ceased to exist as a separate download at all, folded into the Windows SDK. The standalone DirectX SDK that this newsgroup's regulars installed, argued about and filed bugs against is an artefact of a specific decade.

One last structural fact, and the one that makes the managed layer interesting: DirectX functionality was provided in the form of COM-style objects and interfaces. You obtained an IDirect3D9, asked it to enumerate adapters, and called its CreateDevice factory method to get an IDirect3DDevice9, which was the workhorse: fourteen explicit factory methods of its own for shaders, buffers, textures and surfaces, a large surface of state-setting calls, and a reference count you were responsible for. As the July 2003 account of the managed layer in MSDN Magazine put it, one view of why unmanaged Direct3D used factory methods at all is simply that COM does not support a new operator.

What Managed DirectX actually was

Managed DirectX — MDX in the usual abbreviation — first reached the public with DirectX 9.0 in December 2002. Its own documentation could not settle on a name for it: the page introducing it was headed Managed DirectX in the SDK's first published version and DirectX 9.0 for Managed Code by the Summer 2004 update, with the body text changed to match. Under either heading it described the same thing, as enabling access to most of the original unmanaged DirectX functionality from the languages of the .NET Framework. The documented languages were Visual C#, Visual Basic .NET, Visual C++ and JScript .NET. The documented components were Direct3D Graphics, DirectDraw, DirectInput, DirectPlay, DirectSound, and an Audio Video Playback wrapper over DirectShow. The minimum operating system for the managed runtime was Windows 98, although the SDK's samples and tools needed Windows 2000.

Two of those six components were already being overtaken inside DirectX itself. DirectDraw's two-dimensional work had been merged with Direct3D into a single component called DirectX Graphics for version 9, and DirectPlay was deprecated after version 8. A managed wrapper is only as current as the thing it wraps, and part of this one was already historical on the day it shipped.

A correction is due to the folk description of the thing, which this directory repeated for years. Managed DirectX is routinely described as an interop layer between managed code and a COM interface, which is close enough to be misleading. Microsoft's own statement of benefit was the opposite: by eliminating the Component Object Model (COM) interoperability layer, DirectX 9.0 for Managed Code improves performance. What shipped was not a set of runtime-callable wrappers generated over type libraries, with the standard interop machinery underneath. It was a purpose-written set of assemblies, in the Microsoft.DirectX namespace family, that reached the same underlying implementation with marshalling written for the purpose. The interop was real, and it was thin, and it was hand-made. That distinction is the whole design.

Above that, the shape of the API stayed deliberately close to its parent. The MSDN Magazine account of July 2003 put it plainly: for the most part, managed Direct3D provided a one-to-one mapping of the interfaces, structures and enumerations of the unmanaged layer to the classes, structures and enumerations of the managed one. Where it diverged, it diverged towards .NET idiom. Objects were constructed with new rather than obtained from factories, and the managed Device class kept only three factory methods of its own. Render state, sampler state and texture-stage state became properties and indexers, so that setting a cull mode read as device.RenderState.CullMode = Cull.None rather than as a call with an enumeration argument. Colours could be passed as a System.Drawing.Color or as the traditional packed integer, because both overloads existed. And the Device class raised five events — DeviceCreated, DeviceLost, DeviceReset, DeviceResizing and Disposing — so that an application could respond to a lost device the way a Windows Forms application responded to a resize. Hold on to that last one; it comes back.

The library was not, however, a general-purpose object model. The SDK's own tips page stated flatly that DirectX 9.0 for Managed Code did not support class inheritance in applications, that inheriting from its classes was not recommended, and that the resulting behaviour was undefined — adding, with the candour of a document written by people who knew what users would try, that certain inherited classes might be found to work in this version and might not work in a future one. Deployment had its own switch: the redistributable installer had to be invoked as DXSetup.exe /InstallManagedDX to lay down the managed assemblies at all.

The version history is short and easily muddled, so it is worth stating precisely. The library first shipped with DirectX 9.0 in December 2002, only months after the .NET Framework's own 1.0 release at the start of that year. The version that everyone subsequently meant was MDX 1.1, built for the .NET 1.1 runtime that shipped in April 2003; it remained usable under .NET 2.0 and the 3.0 and 3.5 extensions of that runtime. A 2.0 beta existed and never became a product. And that is the entire release history: one shipping generation, one abandoned successor.

Who it was for is answered by its ancestry rather than its documentation. DirectX 7 and DirectX 8 had shipped support for Visual Basic 6.0, not because professional studios wanted it but because, in the account of Chuck Walbourn of the DirectX group, there was intense interest in the hobbyist community in reaching this technology at all. When Visual Basic was folded into the .NET family during DirectX 9's development, the Visual Basic support became the managed libraries, and the emphasis shifted from Visual Basic to C# without the audience changing much. Walbourn, writing years later, credited the whole effort to a great deal of individual passion and effort from Tom Miller and others on the DirectX team — which is a polite way of recording that the managed layer was never a large project.

The frame budget and the collector

This is the engineering problem the room existed around, and it deserves to be stated accurately rather than dramatically, because the dramatic version — managed code is too slow for games — is not what the difficulty actually was.

Managed code is not interpreted. Intermediate language is compiled to native instructions before it runs, and for the arithmetic that dominates a render loop the generated code is ordinary machine code. The problem is not throughput. The problem is that the common language runtime manages memory on the application's behalf, and the moment at which it chooses to do so is not the application's to choose. Microsoft's documentation states the mechanism without euphemism: before a garbage collection starts, all managed threads are suspended except for the thread that triggered the collection. The collector then marks live objects by walking the graph from the roots, relocates references, and compacts the surviving objects so that the heap does not fragment.

None of that is expensive in the abstract. The runtime's collector is generational: new objects go into generation 0, survivors are promoted to generation 1 and then generation 2, and because it is faster to compact part of the heap than all of it, most collections touch only the youngest generation and finish quickly. A generation 2 collection is what the documentation calls a full collection, because it reclaims objects in every generation, and full collections are the ones that hurt. The intrusiveness of collection — its frequency and its duration — is, in the documentation's own words, the result of the volume of allocations and the amount of survived memory on the managed heap.

Now set that against a render loop. A game running at sixty frames per second has sixteen milliseconds to complete an update and a draw. Shawn Hargreaves, who worked on the successor framework and wrote the clearest period explanation of the problem, put the arithmetic exactly that way in June 2007: if your game is running at sixty frames per second you only have sixteen milliseconds to complete each update and draw cycle, so spending thirty milliseconds in the garbage collector is going to make you miss a frame. That is the whole tension in one sentence. The collector is not slow; it is merely indifferent to where it lands. A pause that would be invisible in a business application is, in a render loop, a dropped frame — and a dropped frame is not a slowdown but a visible stutter, which players notice far more readily than a uniformly lower frame rate.

The tension is sharpened by what a graphics application does with memory. A frame's work naturally produces short-lived objects: matrices, vectors, colours, strings for the on-screen statistics, the arguments to a call that took a collection. Value types allocate on the stack and cost the collector nothing, but the moment a value type is assigned to an object, stored in a non-generic collection, accessed through an interface or used as a dictionary key, the runtime boxes it — allocates a heap object to hold it — and the frame has produced garbage without a single visible new. Multiply a small mistake by sixty frames a second and the heap grows at a rate that guarantees collections.

On the successor platform the arithmetic was even less forgiving, and it is worth recording because it shows the general problem in a hard case. The Xbox 360 ran a version of the .NET Compact Framework, and Hargreaves stated its rule plainly: on Xbox, the .NET Compact Framework performs a garbage collection after one megabyte has been allocated. What that collection then cost was, by his account, a function not of how many bytes the heap held but of how many objects and references it contained, since the collector must examine every object and follow every reference.

A white Xbox 360 console standing vertically against a plain white background, with a silver-grey hard-drive unit clipped along its upper side, and a white wireless controller with coloured face buttons propped in front of it.
An Xbox 360 in the launch 'Pro' configuration, with its wireless controller; this unit was built in November 2005. The framework Microsoft recommended to Managed DirectX users in October 2006 ran on the Xbox 360 through a native implementation of the .NET Compact Framework, whose collector, in the XNA team's own account, ran after every megabyte allocated — which is why the allocation discipline described above was stated so bluntly. The photograph shows the hardware, not the newsgroup. Evan-Amos · public domain · via Wikimedia Commons.

What the documentation of the period actually advised

The mitigations recorded at the time fall into two families, and the most useful surviving statement of them is Hargreaves's pair of posts of 29 June and 2 July 2007, written for the successor framework but describing the same runtime and the same arithmetic. Total time lost to collection, he observed, is the number of collections multiplied by the latency of each. There are therefore two ways to win, and they are opposites.

  • Reduce the number of collections. Allocate everything the game will ever need while the level loads, and allocate nothing during play. Reuse instances from object pools instead of calling new on reference types. Construct collections with explicit capacity so they never grow. Avoid string formatting, which is hard to do in .NET without allocating. Avoid boxing — assigning value types to object, storing them in the old non-generic collections, reaching them through an interface, using an enumeration as a dictionary key. Be wary of delegates and closures and of generator methods, all of which make the compiler allocate on your behalf. A programmer who follows this path may keep a heap of any size and complexity, because a collector that never runs does not care how tangled the heap is.
  • Reduce the cost of each collection. Keep the heap simple rather than small. The collector must examine every object and follow every reference, so an array of a hundred thousand integers is cheap while a hundred thousand single-integer objects are ruinous. Prefer a few large objects to many small ones, value types to reference types, arrays of value types to graphs, integer handles to object references — store I was created by ship number 23 rather than a pointer to the ship. A programmer who follows this path may allocate freely, because the collections will finish before anyone sees them.

The sting in the tail was that these are not two halves of a strategy. Compromise, in Hargreaves's phrase, will get you nowhere: a medium amount of allocation with a medium-complexity heap produces a game with a medium-sized glitch every medium number of seconds. The advice was to pick one path and follow it to the bitter end.

One further mitigation is worth recording because it inverts the usual rule. Forcing a collection by calling GC.Collect is almost always a mistake — programmers new to garbage collection think it will help and are, in Hargreaves's judgement, almost always wrong, and the current .NET documentation says much the same, that in most cases the collector can determine the best time to collect and should be left to run independently. But on a platform that collects after every megabyte allocated, the amount of garbage left over from loading a level determines how much headroom the gameplay has before the next threshold is crossed. Hargreaves worked the example: a game allocating fifty bytes per frame at sixty frames per second can run five minutes between collections — unless the load happened to end just short of a megabyte boundary, in which case the player gets a glitch forty-two seconds into the level. The remedy was to call GC.Collect deliberately at the very end of the load method, cleaning up the loading garbage and resetting the clock. It is a rare case of the recommended action being the discouraged one, for a reason specific to the platform.

The runtime's own controls for this came later, and belong to a period after this room's subject was already deprecated. The framework eventually exposed GCSettings.LatencyMode, with a low-latency mode that suppresses generation 2 collections and performs only generation 0 and 1 collections, and a sustained low-latency mode that suppresses foreground generation 2 collections while still permitting background ones; later still came a no-GC region, entered through GC.TryStartNoGCRegion, which attempts to disallow collection across a critical path entirely. The documentation's own examples of who these are for — applications that render animations, applications that need quick response times as market data changes during trading hours — describe the shape of the problem precisely. None of them was available to a developer writing Managed DirectX in 2003, whose only instrument was to allocate less.

There was also an obligation that ran the other way, and it caught people. The managed library's stated benefits included freeing you from having to deal with most memory management tasks, such as releasing objects — but the objects that mattered most in a graphics application were exactly the ones wrapping scarce native resources, and those had to be released by hand. The Device class was disposable and raised a Disposing event; textures, vertex buffers and surfaces all had lifetimes the collector could not reason about. Managed code removed the obligation to free memory and left intact the obligation to free everything else, which is a subtler thing to teach than either extreme.

Anatomy of a documented performance bug

The best surviving evidence of what this argument sounded like at the time is a short column Tom Miller — a developer in Microsoft's DirectX group and, by the magazine's own description of him, the designer and developer of the Managed DirectX libraries — wrote for the August 2005 MSDN Magazine. It is worth summarising at length because it is a first-party account of a real defect, written by the person responsible, and because the shape of the defect is unexpected.

Miller opened by reporting the volume of the complaint. It seemed that at least twice a week he was asked about poor performance in Managed DirectX, he wrote, which was a big improvement over the five to ten times a week of a few years earlier when the technology first came out. Many of the people asking began from the assumption that managed code is slow and therefore that Managed DirectX must be slow — a misconception held, he noted, by many different types of developer, from the hardcore game developer to programmers within his own DirectX team.

The case he then described had begun as a colleague's proof-of-concept prototype that ran so badly Miller first thought it had been written that way intentionally. The first problems were ordinary: the application used no resource buffers at all, passing the entire data set to the card on every draw whether or not it had changed, and it issued essentially one draw call per object. Both are mistakes a native-code programmer could make just as easily, and fixing the first resolved a large part of the problem.

What profiling revealed afterwards is the interesting part. There was an extraordinary number of garbage collections, including generation 1 and generation 2 collections — something, Miller wrote, you never want to see in a high-performance 3D application. The cause was a code pattern repeated virtually everywhere: rather than caching an object, the developer had reached it through a property on a child, writing VertexBuffer.Device where a stored reference would have done. That property returned an entirely new object every time it was accessed, and the library's event mechanism created three further miscellaneous objects each time an event was raised. The pattern was causing a minimum of two thousand extra objects to be created every frame.

And the vast majority of those objects were never collected at all, despite the collections. The culprit was the event hooking: every resource a device created hooked events on the device itself — at the very least the disposing event — and each hook was a hard link back to the child, keeping it alive regardless of whether it had gone out of scope, until the device itself was disposed. The library's most .NET-idiomatic feature, the one the 2003 magazine account had paused over as an interesting use of the .NET delegate-based event pattern, was quietly pinning the heap.

The fixes were architectural rather than exhortative, which is the part that argues against the simple reading of the story. Properties that returned other objects had their values cached internally, so the application no longer had to maintain the list; and the event-hooking mechanism was changed so that applications wanting more control over their objects' lifetimes could disable it. Miller reported that the application then performed well above expectations, and that the number of times he was asked about performance was steadily diminishing.

Two things follow. The first is that the difficulty was real and was not, in this instance, a property of garbage collection as such: it was a design defect in a wrapper, of a kind that a reference-counted native library would have expressed as a leak instead of as a collection storm. The second is that the fix arrived in the version of the library that was about to be abandoned. Miller ended his column looking forward to the Visual Studio 2005 version, which he expected would convince more people. The Visual Studio 2005 version of Managed DirectX was the 2.0 beta, and it was withdrawn fourteen months after that issue went to press.

Managed DirectX 2.0, and the reorganisation

With the release of .NET 2.0 in October 2005 there was an effort to update Managed DirectX to use the new constructs of the runtime — generics above all, which would have removed a great deal of the boxing the library's users had been warned about. A Managed DirectX 2.0 beta was included in the DirectX SDK during 2005. It differed from 1.1 in a number of places; people ported to it; and then, in Walbourn's account, a major reorganisation took place at Microsoft, and when the dust settled the relatively small team that had been working on the technology suddenly found itself the seed of an entirely new effort around .NET games development. The Managed DirectX 2.0 project was shelved, and the effort went into a more comprehensive end-to-end solution for independent game developers targeting Windows, the Xbox 360, the Zune and eventually Windows Phone 7.

Developers learned about it from a release note. The October 2006 DirectX SDK carried the following, quoted here at length because it is the closest thing to a formal notice of withdrawal that this technology ever received:

Managed DirectX 2.0 Beta Removed. In the October 2006 SDK, the Managed DirectX 2.0 Beta has been removed and is no longer supported. There are two distinct paths for developers migrating from Managed DirectX 2.0.
If you are currently using Managed DirectX 2.0 for tool, editors, or other applications that require specific Direct3D, Direct3DX, DirectSound, or DirectInput functionality, you should migrate to the Managed DirectX 1.1 runtime. Managed DirectX 1.1 is completely compatible with the .NET Framework 2.0 and will not require you to change the version of the CLR.
If you are planning to release a game using the .NET Framework, it is recommended that you adopt XNA Game Studio Express, currently in beta. XNA Game Studio Express uses the XNA Framework which is very similar to Manged DirectX in many respects. XNA Game Studio Express is scheduled for release before the end of 2006. This first release is targeted at hobbyists developers and students.

The typographical slips are in the original, in both paragraphs. So is the shape of the offer: anyone who had ported forward was invited either to port back to the version they had left, or to adopt a product that did not yet exist in finished form, aimed explicitly at hobbyists and students. For a developer maintaining a tool or an editor rather than a game, the second option was not an option at all — which the note acknowledged by steering that audience to 1.1. The note is preserved because a Microsoft employee quoted it verbatim on his own blog on 12 December 2006, in a post recording his dismay at having dutifully ported his code to the 2.0 beta.

Deprecation in slow motion

What happened to Managed DirectX 1.1 after 2006 is best described as neglect with backward compatibility. The last update to the library was in April 2006, to match that version of the D3DX9 extension library; its documentation had last been updated in August 2005; and the August 2006 DirectX SDK was the last to include its samples and documentation at all. The assemblies themselves, however, continued to be shipped for years — in the SDK's developer runtime, in the DirectSetup redistributable folder, in the DirectX end-user runtime package and in the web installer — specifically, in Walbourn's words, to simplify legacy deployment and support existing applications that relied on it.

The consequence was a library you could still install long after you could no longer sensibly build against it, and the list of reasons is worth setting out because it is a compact history of everything that changed underneath it:

  • The assemblies were 32-bit only. An application could not run as anycpu on a 64-bit system; it had to be built for x86 and stay within the two-gigabyte memory space of a 32-bit process.
  • They supported only the legacy DirectX API set. There was no support for Direct3D 9Ex, none for Direct3D 10.x, 11 or later, and none for Direct2D, DirectWrite, DXGI, XAudio2, XACT or XInput — the whole apparatus that arrived with Windows Vista and after.
  • Because MDX 2.0 was never released in production form, the shipping assemblies continued to reflect .NET 1.1 design principles and made no use of .NET 2.0 constructs.
  • They were compatible with .NET 2.0 and its 3.0 and 3.5 extensions but not with .NET 4.0. Since Visual Studio 2010's toolset supported only .NET 4.0 development, the practical effect was that the current version of Microsoft's own development environment could not build a Managed DirectX application without multi-targeting back to older toolsets.
  • The last version of D3DX9 it supported was April 2006, which meant a shader compiler several years out of date by the time anyone noticed.

By December 2010 Walbourn was writing that Managed DirectX 1.1 was deprecated and really beginning to show its age, and that the legacy deployment support was likely to be removed in a future SDK update. The question he was answering had been asked, over and over, by people installing the June 2010 DirectX SDK, opening Visual Studio 2010 and finding no Microsoft.DirectX to add to their project. Eight years after it shipped, the library was still generating support traffic — from developers who had no idea it had ever stopped.

The successor, and the successor's own ending

XNA was announced at the Game Developers Conference in San Jose on 24 March 2004, well before Managed DirectX 2.0 was shelved, and the name was a recursive joke: XNA's not acronymed. What it eventually became was a managed runtime plus a toolset plus a content pipeline: on Windows it ran on the .NET Framework 2.0, and on the Xbox 360 on a native implementation of the .NET Compact Framework 2.0, in both cases on a version of the common language runtime described as optimised for gaming. Games could technically be written in any .NET-compliant language; in practice they were written in C#, with Visual Basic support added in 2011.

The release history is quick to give and is the story of a product that was actively developed for five years. A first beta of XNA Game Studio Express appeared in late August 2006, a second on 1 November, and the finished release on 11 December 2006. Version 2.0 followed on 13 December 2007, adding Xbox Live networking and support for every edition of Visual Studio 2005. Version 3.0 arrived on 30 October 2008 with the Zune as a target and with a trial mode for games; 3.1 on 11 June 2009 with video playback and Xbox 360 Avatars; 4.0 on 16 September 2010, adding Windows Phone with hardware 3D acceleration; and a Refresh on 6 October 2011 that added Windows Phone 7.5 and Visual Basic. Xbox 360 distribution ran through a premium membership costing about ninety-nine US dollars a year and a peer-review process by other creators, after which a game that passed was listed on Xbox Live Marketplace.

A silver-and-white portable media player lying face up on beige carpet, with a rectangular screen above a round control pad flanked by two small buttons, a black earphone lead running away to one side and a coiled black sync cable beside it.
A first-generation Microsoft Zune with earphones and sync cable, photographed by its owner in 2007. XNA Game Studio 3.0 added the Zune as a target in October 2008; by 2013 both the player and the framework that targeted it had been discontinued. KyleRog at English Wikipedia · public domain · via Wikimedia Commons.

It ended for a structural reason before it ended for an announced one. XNA was not compatible with the Windows Runtime, the API for the new class of applications introduced with Windows 8, which meant that a framework built to reach hobbyists on Microsoft's platforms could not reach the platform Microsoft was steering everyone towards. At the end of January 2013 an internal message to Microsoft's MVPs made the position explicit, and on 1 February 2013 Gamasutra ran the story under the headline It's official: XNA is dead, quoting the company:

XNA Game Studio remains a supported toolset for developing games for Xbox 360, Windows and Windows Phone. However, there are no plans for future versions of the XNA product.

Support for the toolset ended in April 2014. Counting from the October 2006 release note that pointed Managed DirectX users at it, the recommended successor lasted a little over six years as a developed product and rather over seven as a supported one. Counting from the same note, a developer who had followed Microsoft's advice at each step had by 2013 been moved off two frameworks in succession and had nowhere official left to go: the managed game-programming story on Windows had, unusually, no vendor-supported chapter at all.

What developers were left with

Everything in this section postdates the mail-to-news gateway whose snapshot produced this directory, and most of it postdates the newsgroup's useful life; it is included because a reader arriving at this page from a search for Managed DirectX is entitled to know how the story ends. The most authoritative period inventory is Walbourn's, written in December 2010 for exactly the developer who had turned up with a Managed DirectX question and no library to answer it with. His list, and what became of each item:

  • XNA Game Studio — the recommended route for anyone writing a game, with the limitations already described and, by his account, numerous tools and a vibrant developer community. Discontinued 2013.
  • The Windows API Code Pack — managed assemblies for Direct3D 10.1 and 11, Direct2D, DirectWrite, DXGI and the Windows Imaging Component, aimed at Windows Presentation Foundation developers who needed the newer graphics APIs; it supported .NET 4.0 and 64-bit anycpu, though the HLSL compiler still had to come from the DirectX SDK.
  • SlimDX — an open-source library explicitly designed to mimic Managed DirectX 1.1 for developers who wanted the same shape of API without the limitations: anycpu, DirectX 11, .NET 4.0. Its licence is the MIT licence and its copyright notice reads Copyright (c) 2007-2012 SlimDX Group; it was not maintained after about 2012.
  • SharpDX — created by Alexandre Mutel around 2010 and for some years the preferred managed route on the newer Microsoft platforms, including the Windows Store and Windows Phone 8. Its author retired it on 29 March 2019, writing that the project had been around for almost nine years and citing a lack of strong technical leadership and community involvement; the repository is read-only, the binaries remain available, and the MIT licence permits anyone to fork it.
  • directshow.net — for media developers who needed more than the simple Audio Video Playback wrapper, though already, by his own note, not updated since about 2010.
  • Writing your own — standard native interop, or a C++/CLI component doing the DirectX work natively and handed to Windows Presentation Foundation through D3DImage.

Read in retrospect the list is not encouraging, and it was not written to be. One item was already stale when he recommended it; one was the advice to build the thing yourself; two of the open-source options have since stopped; and the item at the top of the list, the one he recommended most warmly, was withdrawn by his own employer within three years.

What actually survived came from the community, and it came by reimplementation rather than by binding. MonoGame began in December 2009, before XNA's discontinuation and for an unrelated reason: Microsoft had never extended XNA to the iPhone or to Android, so José Antonio Leal de Farias combined code from Bill Reiss's SilverSprite with the community Mono.XNA project to produce XNA Touch, a port aimed at the iPhone. It was renamed MonoGame and moved to GitHub in 2011, gained Android, Mac, Linux and OpenGL-on-Windows support, and in February 2013 — the month Microsoft confirmed there would be no further XNA — found itself the continuation of a framework whose author had stopped. It is distributed under the Microsoft Public License, has been owned since September 2023 by a non-profit MonoGame Foundation, and now runs on the current consoles as well as the desktops. FNA, forked by Ethan Lee around 2013, exists because MonoGame was willing to extend and reinterpret the XNA API where FNA wanted strict accuracy to it.

The games are the part of this that is checkable rather than arguable. XNA was used for Bastion and Terraria; games built with MonoGame include Bastion, Celeste, Barotrauma, Fez and Stardew Valley. A framework Microsoft withdrew in 2013 was still, a decade later, the substrate of games that most players would name if asked for examples of the independent boom.

The binding-layer tradition did not die either, though it moved outside Microsoft. Silk.NET, which describes itself as an official project under the .NET Foundation umbrella, provides bindings to DirectX alongside Vulkan, OpenGL, OpenCL, OpenAL, OpenXR, WebGPU, SDL and a good deal else — the plural where Managed DirectX was singular. And Microsoft's own later managed graphics work went to narrower places: Win2D, a Windows Runtime projection of Direct2D and DirectWrite, is a wrapper over the drawing APIs rather than a route to Direct3D.

The argument the room was having

The question underneath this newsgroup — whether managed code was viable for real-time work — was a genuine dispute with participants on both sides, and the surviving first-party documents show the positions clearly enough that they can be reported without anyone having to be quoted from an archive.

The sceptical position was the default one, and Miller's own column is the evidence for how widely it was held: many of the people who came to him began from the assumption that managed code is slow, and they included both hardcore game developers and programmers within his own team at Microsoft. In its strong form the objection was not about throughput at all but about determinism — that a system which decides for itself when to suspend every thread in the process cannot be trusted with a sixteen-millisecond budget, and that no amount of care by the programmer changes who is making the decision.

The answering position was that the decision is in fact the programmer's, indirectly and completely: the collector runs as a function of allocation, and its cost is a function of heap shape, both of which the programmer controls. This is the position the period documentation took, and it is why the advice of the era reads as a discipline rather than as a tuning exercise — allocate nothing during play, or keep the heap flat, and pick one. Its strong form is the claim that a well-written managed game has no collection glitch because it has no collections during gameplay, which is a stronger claim than fast enough.

A third position, less argued and more widely acted on, was that the trade was worth it for the work that was not a shipping AAA title. Microsoft's own framing leaned on it: managed code can reduce the volume of code and increase productivity, the interface is more intuitive, and — in the 2003 magazine account's closing summary — managed Direct3D is nearly as efficient as its unmanaged counterpart while providing a great future for high-performance rapid game development. Tools, level editors, visualisation applications, prototypes, student projects and small games do not have the same worst-case requirements as a console shooter, and for those the argument was over before it started.

The answer changed over time, and it changed in a way that vindicated nobody's framing. C# did become a mainstream language for making games — but almost never against a Microsoft binding to DirectX. It reached that position through Unity, whose primary scripting API is C# running on Mono, and through MonoGame and FNA. The garbage collector did not stop being a consideration; the discipline described above simply became part of what a competent game programmer in a managed language knows, in the way that cache behaviour became part of what a competent C++ programmer knows. What did not survive was the specific thing this room was named after: a vendor-supplied managed wrapper over the vendor's own graphics API. This page reports the argument; it does not adjudicate it.

Who was in the room

No roster survives, the active file records the group as unmoderated so no moderator was ever appointed, and this page names nobody. What can be said about the population is what can be inferred from the documented design of the thing they were discussing, and that is more than nothing.

The library's ancestry was the hobbyist one. DirectX had carried Visual Basic 6.0 support through versions 7 and 8 precisely because of interest from people who were not professional games programmers, and the managed libraries inherited that constituency along with the code. The October 2006 release note that ended Managed DirectX 2.0 described its replacement's first release as targeted at hobbyists developers and students, in those words. Students in particular were a deliberate audience: a free year of premium App Hub membership was distributed to educational establishments through Microsoft's DreamSpark programme and the MSDN Academic Alliance, and the Dream Build Play contest existed to give the resulting work somewhere to go.

Alongside them were professionals doing the evaluation described in the previous section — often not for a game at all, but for a tool, an editor, a simulation or a visualisation front end, the applications for which the October 2006 note specifically advised staying on Managed DirectX 1.1 rather than moving to a games framework. These are the users who kept the library's support traffic alive into the 2010s, because a line-of-business application with a Direct3D viewport does not get rewritten because a redistributable stopped being updated.

And there were Microsoft's own people. The company's newsgroup programme was staffed: the community was made up, by its own description, of expert Microsoft developers, Microsoft support professionals, MSDN subscribers, Most Valuable Professionals, IT professionals and other developers exchanging ideas; and the designer of the library in question was a public figure with a blog on blogs.msdn.com who fielded the performance question twice a week by his own count. How much of that presence landed in this particular room, as opposed to the graphics room next door or the product's own web forums, is a question about traffic, and traffic is precisely what has not survived.

The room's neighbours mattered to what it was for. Shader questions had graphics.shaders; installation and version questions had sdk; audio, input and networking each had their own. The .NET side of the hierarchy had its own rooms elsewhere — see, for a neighbouring example of a technology filed under both its native and its managed door, the .NET Framework WMI group — and the scripting rooms, such as the VBScript group, served the far end of the same spectrum, where the language did everything for you and nobody was counting milliseconds. This room sat at the join: .NET conveniences, real-time obligations.

What postdates the gateway

A boundary is worth drawing explicitly, because this page has ranged well past it. The mail-to-news gateway whose group list produced this directory operated between 2000 and 2004. Everything in the second half of this article — the 2.0 beta, the reorganisation, the October 2006 release note, XNA in all five of its versions, the deprecation, the 2013 announcement, SlimDX, SharpDX, MonoGame, Silk.NET — happened after the gateway had closed and is included as history rather than as anything the gateway's users saw.

What falls inside the window is a narrow and rather interesting slice: the DirectX rooms being created in a seventy-one-second burst in April 2001; the parent room being created and removed again forty-three seconds apart in August 2001; a private group with managed in its name appearing and vanishing in March 2002; DirectX 9.0 and the first Managed DirectX shipping in December 2002; the .NET 1.1 runtime and MDX 1.1 arriving in the spring of 2003; the first substantial magazine coverage in July 2003; and DirectX 9.0c in August 2004. That is the whole of the technology's confident period, and it is roughly the whole of the gateway's operating life. The room outlived both by six years, until Microsoft announced that it would discontinue support for its public newsgroups from 1 June 2010 and closed the server; that shutdown, with the company's own reasoning, is described on the hierarchy page and is not this page's story to tell.

What the record does not show

The list below is not an apology for thin research; it is the substance of what a preserved vendor newsgroup honestly leaves behind. Each item was looked for during the writing of this page and not found.

  • When the group was created. No control message for it survives in the ISC archive, although the archive holds messages for eight of its nine siblings and continued collecting until December 2009. Nothing here was voted, so none of the paperwork a Big-8 group leaves behind was ever generated.
  • How busy it was. No posting counts, subscriber estimates or traffic curves are published for individual microsoft.public.* groups. The May 2004 MSDN Magazine figure of up to 15,000 postings a month applies to an individual newsgroup at the top of the range, not to this one, and is quoted above only to show the scale the programme operated at.
  • Whether it was a serviced group. Microsoft ran about 220 newsgroups under a response-time commitment, and the article listing them named a group from this branch but not this one. Nothing traced for this page establishes whether this room was among them.
  • Who answered. There was no moderator, no roster and no register of recognised contributors. The people who did the answering are identifiable only from their own postings, and this page names none of them.
  • How questions divided. A managed-code question about a shader could reasonably have gone to this room or to graphics.shaders; a managed question about installing the SDK could have gone here or to sdk; and from 2006 the same questions increasingly went to the successor's own web forums instead. Nothing in the surviving record settles how the traffic actually distributed.
  • Whether the March 2002 private group is connected. A group named microsoft.private.directx.managed was created and removed within fourteen seconds. Whether it was an error, a rehearsal, or the visible edge of an internal beta programme is not established by the control message, which says nothing but its own name.
  • The group's last day. It falls somewhere inside the 2010 shutdown window and is recoverable, if at all, only from the tail of the archive.

Scope and limits of this page

Everything asserted here about the group itself comes from two sources and nothing has been inferred from either beyond what they literally contain: the ISC's mirrored active file, which records the group's existence, its posting flag and its empty article range; and the ISC's microsoft control archive, which records the newgroup and rmgroup messages described above with their senders and their timestamps. Where this page says the record is silent, it means those files are silent.

Everything asserted about the technology is verified against Microsoft's own archived documentation — the DirectX 9.0 for Managed Code introduction and tips pages, the MSDN Magazine articles of July 2003, May 2004 and August 2005, the October 2006 SDK release note as quoted verbatim in a Microsoft employee's blog at the time, and the DirectX team's later posts by Chuck Walbourn and Shawn Hargreaves — together with the current .NET documentation for the garbage collector and standard encyclopaedic sources for release dates. Where a date is given it is the document's date. None of it is a claim about what any particular poster in this room was told, or when, or by whom.

Two things this page deliberately does not do. It does not reproduce or paraphrase any posting from the group, because no posting has been read for it and inventing one would be worse than saying nothing. And it does not decide the argument described above. Managed code for real-time rendering was a live technical dispute with informed people on both sides and a documented history of surprises in both directions; the surviving record supports reporting the positions accurately, and that is what has been attempted.

One caution about the technical material, finally. The interfaces, namespaces, switches and constraints described here belonged to a library that has not been updated since April 2006 and whose documentation has not been updated since August 2005. Unlike the native APIs discussed on this branch's other page, nothing here is still current. An answer written in this room in 2004 about a Device object and a lost device would have been correct then, is of historical interest now, and will not build against a modern toolchain — which is, in the end, the point of the article above.

Reading microsoft.public.win32.programmer.directx.managed today