DirectX newb - Multisampled Texture2D with depth on a Billboard

Here's my requirement: Using DirectX11 (via SlimDX) I have to download a series of verteces and use them to create a Texture2D of a map of county borders. Then I need to do the same thing with state borders, and draw them over the county borders. Then, I need to take that texture and create 2 different textures from it, each containing unique radar data. Then I want to take those textures and display them so that the user can look at, for example, base reflectivity and base velocity side by side. The user should be able to zoom in and out of particular areas of the map.

Here's what I've got working: I'm creating my Texture2D without multisampling or depth on a billboard which is displaying in 2 separate views. But it looks blocky, and if you zoom too far out, some of the borders start to disappear.

Here are my issues:

1) I can't for the life of me get any multisampling quality. I'm using an ATI Radeon HD 5750, so I know it must be able to do it, but no formats I've tried support a quality greater than 0.

2) I'm uncertain whether I need to use a depth stencil since I'm drawing all these textures on top of each other. I hope not because when I try, the ShaderResourceView says, "Puny Human! You cannot use a depth stencil format in a ShaderResourceView! Bwa ha ha!" (I'm embellishing)

I'm willing to bet that a lot of these issues would be solved if I just drew the primitives directly into the world space, but when I do that rendering takes way too long because there are so many lines to render. Is there perhaps a way I can cut down on the time it takes?

And here's the code of my last working version:

using SlimDX; using SlimDX.D3DCompiler; using SlimDX.Direct3D11; using SlimDX.DXGI; using SlimDX.Windows; using System; using System.Windows.Forms; using System.Collections.Generic; using Device = SlimDX.Direct3D11.Device; using Buffer = SlimDX.Direct3D11.Buffer; using Resource = SlimDX.Direct3D11.Resource; using Format = SlimDX.DXGI.Format; using MapFlags = SlimDX.Direct3D11.MapFlags; namespace Radar { abstract public class Renderer { protected static Device mDevice = null; protected SwapChain mSwapChain = null; protected RenderTargetView RenderTarget { get; set; } public static Device Device { get { return mDevice; } protected set { mDevice = value; } } public static DeviceContext Context { get { return Device.ImmediateContext; } } protected SwapChain SwapChain { get { return mSwapChain; } set { mSwapChain = value; } } public Texture2D Texture { get; protected set; } protected int RenderTargetIndex { get; set; } protected VertexShader VertexShader { get; set; } protected PixelShader PixelShader { get; set; } protected Buffer VertexBuffer { get; set; } protected Buffer MatrixBuffer { get; set; } protected InputLayout Layout { get; set; } protected ShaderSignature InputSignature { get; set; } protected SamplerState SamplerState { get; set; } protected Color4 mClearColor = new Color4(0.117f, 0.117f, 0.117f); protected Color4 ClearColor { get { return mClearColor; } } protected void CreateDevice(IntPtr inHandle) { if (Device == null) Device = new Device(DriverType.Hardware, DeviceCreationFlags.Debug); SwapChainDescription chainDescription = new SwapChainDescription() { BufferCount = 2, Usage = Usage.RenderTargetOutput, OutputHandle = inHandle, IsWindowed = true, ModeDescription = new ModeDescription(0, 0, new Rational(60, 1), Format.R8G8B8A8_UNorm), SampleDescription = new SampleDescription(8, 0), Flags = SwapChainFlags.AllowModeSwitch, SwapEffect = SwapEffect.Discard }; SwapChain = new SwapChain(Device.Factory, Device, chainDescription); } protected void SetupViewport(int inWidth, int inHeight) { Viewport viewport = new Viewport(0.0f, 0.0f, inWidth, inHeight); Context.OutputMerger.SetTargets(RenderTarget); Context.Rasterizer.SetViewports(viewport); } public void Clear() { Context.ClearRenderTargetView(RenderTarget, ClearColor); } public void Present() { SwapChain.Present(0, PresentFlags.None); } // I do this to ensure the texture is correct public void Save() { Texture2D.ToFile(Context, Texture, ImageFileFormat.Png, "test.png"); } public virtual void Dispose() { Texture.Dispose(); SamplerState.Dispose(); VertexBuffer.Dispose(); Layout.Dispose(); InputSignature.Dispose(); VertexShader.Dispose(); PixelShader.Dispose(); RenderTarget.Dispose(); SwapChain.Dispose(); Device.Dispose(); } public class RenderTargetParameters { public int Width { get; set; } public int Height { get; set; } public IntPtr Handle { get; set; } public RenderTargetParameters() { Width = 0; Height = 0; Handle = new IntPtr(0); } } public abstract void Render(int inWidth, int inHeight, int inCount = -1); public abstract void Prepare(string inShaderName = null); } public class TextureRenderer : Renderer { public TextureRenderer(RenderTargetParameters inParms) { CreateDevice(inParms.Handle); Texture2DDescription description = new Texture2DDescription() { Width = inParms.Width, Height = inParms.Height, MipLevels = 1, ArraySize = 1, Format = Format.R8G8B8A8_UNorm, SampleDescription = new SampleDescription(8, 0), Usage = ResourceUsage.Default, BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource, CpuAccessFlags = CpuAccessFlags.None, OptionFlags = ResourceOptionFlags.None }; Texture = new Texture2D(Device, description); RenderTarget = new RenderTargetView(Device, Texture); SetupViewport(inParms.Width, inParms.Height); using (ShaderBytecode bytecode = ShaderBytecode.CompileFromFile("ShaderFX.fx", "VShader", "vs_5_0", ShaderFlags.Debug, EffectFlags.None)) { InputSignature = ShaderSignature.GetInputSignature(bytecode); VertexShader = new VertexShader(Device, bytecode); } // load and compile the pixel shader InputElement[] elements = new[] { new InputElement("POSITION", 0, Format.R32G32B32_Float, 0) }; Layout = new InputLayout(Device, InputSignature, elements); Context.InputAssembler.InputLayout = Layout; Context.InputAssembler.PrimitiveTopology = PrimitiveTopology.LineStrip; Context.VertexShader.Set(VertexShader); } public override void Prepare(string inShaderName) { using (ShaderBytecode bytecode = ShaderBytecode.CompileFromFile("ShaderFX.fx", inShaderName, "ps_4_0", ShaderFlags.Debug, EffectFlags.None)) PixelShader = new PixelShader(Device, bytecode); Context.PixelShader.Set(PixelShader); } public void SetVertices(DataStream inShape) { VertexBuffer = new Buffer(Device, inShape, (int)inShape.Length, ResourceUsage.Default, BindFlags.VertexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0); Context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(VertexBuffer, 12, 0)); } public override void Render(int inWidth, int inHeight, int inCount = -1) { Context.Draw(inCount, 0); } } public class RuntimeRenderer : Renderer { private ShaderResourceView ResourceView { get; set; } public RuntimeRenderer(RenderTargetParameters inParms, ref TextureRenderer inTextureRenderer) { CreateDevice(inParms.Handle); Texture = inTextureRenderer.Texture; using (Resource resource = Resource.FromSwapChain<Texture2D>(SwapChain, 0)) RenderTarget = new RenderTargetView(Device, resource); //using (var factory = SwapChain.GetParent<Factory>()) //factory.SetWindowAssociation(inParms.Handle, WindowAssociationFlags.IgnoreAltEnter); } public void Resize() { RenderTarget.Dispose(); SwapChain.ResizeBuffers(2, 0, 0, Format.R8G8B8A8_UNorm, SwapChainFlags.AllowModeSwitch); using (SlimDX.Direct3D11.Resource resource = Resource.FromSwapChain<Texture2D>(SwapChain, 0)) RenderTarget = new RenderTargetView(Device, resource); } public override void Prepare(string inShaderName) { using (ShaderBytecode bytecode = ShaderBytecode.CompileFromFile("ShaderFX.fx", "TextureVertexShader", "vs_4_0", ShaderFlags.EnableStrictness, EffectFlags.None)) { InputSignature = ShaderSignature.GetInputSignature(bytecode); VertexShader = new VertexShader(Device, bytecode); } using (ShaderBytecode bytecode = ShaderBytecode.CompileFromFile("ShaderFX.fx", "TexturePixelShader", "ps_4_0", ShaderFlags.EnableStrictness, EffectFlags.None)) PixelShader = new PixelShader(Device, bytecode); InputElement[] elements = new InputElement[2]; elements[0].SemanticName = "POSITION"; elements[0].SemanticIndex = 0; elements[0].Format = Format.R32G32B32_Float; elements[0].Slot = 0; elements[0].AlignedByteOffset = 0; elements[0].Classification = InputClassification.PerVertexData; elements[0].InstanceDataStepRate = 0; elements[1].SemanticName = "TEXCOORD"; elements[1].SemanticIndex = 0; elements[1].Format = Format.R32G32_Float; elements[1].Slot = 0; elements[1].AlignedByteOffset = InputElement.AppendAligned; elements[1].Classification = InputClassification.PerVertexData; elements[1].InstanceDataStepRate = 0; Layout = new InputLayout(Device, InputSignature, elements); BufferDescription matrixDescription = new BufferDescription() { Usage = ResourceUsage.Dynamic, SizeInBytes = sizeof(float) * 16 * 4, BindFlags = BindFlags.ConstantBuffer, CpuAccessFlags = CpuAccessFlags.Write, OptionFlags = ResourceOptionFlags.None, StructureByteStride = 0 }; MatrixBuffer = new Buffer(Device, matrixDescription); ShaderResourceViewDescription resourceViewDescription = new ShaderResourceViewDescription() { Format = Texture.Description.Format, Dimension = ShaderResourceViewDimension.Texture2DMultisampled, MipLevels = Texture.Description.MipLevels, MostDetailedMip = 0, }; //Texture2D.ToFile(Context, Texture, ImageFileFormat.Png, "test.png"); ResourceView = new ShaderResourceView(Device, Texture, resourceViewDescription); SamplerDescription samplerDescription = new SamplerDescription() { Filter = Filter.MinMagMipLinear, AddressU = TextureAddressMode.Wrap, AddressV = TextureAddressMode.Wrap, AddressW = TextureAddressMode.Wrap, MipLodBias = 0.0f, MaximumAnisotropy = 1, ComparisonFunction = Comparison.Always, BorderColor = ClearColor, MinimumLod = 0, MaximumLod = 99999 }; SamplerState = SamplerState.FromDescription(Device, samplerDescription); } public override void Render(int inWidth, int inHeight, int inCount = -1) { Clear(); Billboard.SetVerteces(Device, Texture.Description.Width, Texture.Description.Height, inWidth, inHeight); SetupViewport(inWidth, inHeight); Context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(Billboard.Verteces, 20, 0)); Context.InputAssembler.SetIndexBuffer(Billboard.Indeces, Format.R32_UInt, 0); Context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleStrip; Context.InputAssembler.InputLayout = Layout; Context.VertexShader.Set(VertexShader); Context.PixelShader.Set(PixelShader); Context.PixelShader.SetSampler(SamplerState, 0); Context.VertexShader.SetConstantBuffer(MatrixBuffer, 0); Context.PixelShader.SetConstantBuffer(MatrixBuffer, 0); Context.PixelShader.SetShaderResource(ResourceView, 0); Context.DrawIndexed(4, 0, 0); Present(); } } }

Image 1 is what it looks like if I save the texture to a file (I scaled this down a LOT so it would fit in my post).

Image 2 is what it looks like in runtime when viewed at about a medium distance (not ideal, but not so bad)

Image 3 is what it looks like zoomed in to a county (Eww! Blocky and fuzzy!)

Image 4 is what it looks like zoomed out (where did all the borders go?)

<img src="https://i.stack.imgur.com/4mh8P.png" alt="enter image description here"> <img src="https://i.stack.imgur.com/yyL1A.png" alt="enter image description here"> <img src="https://i.stack.imgur.com/kph3O.png" alt="enter image description here"> <img src="https://i.stack.imgur.com/PEnp6.png" alt="enter image description here">


About multisampling, generally you can keep quality to 0, quality setting generally are different "subpixels" (aka : samples) patterns. 0 generally does fine.

In case you render to texture with multisampling, you also need to resolve your resource, multi sampled textures are bound as Texture2DMS (instead of Texture2D) in shaders.

To do so, you need to create a second texture (with same format/size), but with only one sample.

Then once you're done rendering your multisampled texture, you need to do the following call:

deviceContext.ResolveSubresource(multisampledtexture, 0, nonmultisampledtexture, 0, format);

You can then use the ShaderView of the non multisampled texture in subsequent passes.

From what I see you should not need to use a depth stencil, just make sure you draw your elements in the correct order.

About formats, this is normal since depth is a bit "special", you need to pass different formats for resource/views. If you want to use D24_UNorm_S8_UInt (most common format i'd say), you need to setup the following:

    <li>In the texture description, format needs to be Format.R24_UNorm_X8_Typeless</li> <li>In the Depth Stencil view description, Format.D24_UNorm_S8_UInt</li> <li>In the shader view description, Format.R24_UNorm_X8_Typeless</li> </ul>

    That will allow you to build a depth stencil that you can read (if you don't need to read your depth buffer, just ignore shader view and use depth format directly).

    Also you can increase quality by using mipmaps (which would help a lot, specially when zooming out).

    To do so, in your texture description, set the following options (make sure that this texture is not multisampled)

    texBufferDesc.OptionFlags |= ResourceOptionFlags.GenerateMipMaps; texBufferDesc.MipLevels = 0; //0 means "all"

    once you're done with your rendering, call:


    using the shader resource view of the texture that just got rendered.

    About drawing the lines directly behind that's definitely possible, and for certain will give you the best quality.

    Not sure how many lines you render, but it doesn't look like something a reasonably modern card would struggle with. And a bit of culling can easily help discard lines that are out of the screen so they don't get drawn.

    You could also do some "hybrid" (use texture when zoomed out, render a subset of the lines when zoomed in), that's not too hard to setup either.


  • Secure Box in JCOP card
  • IntelliJ - debug mode - search text in program memory
  • Get NodeRef of a workflow task Alfresco
  • Unmanaged code calling vb.net callback
  • Only first logging shows unless forcefully disposing
  • jquery validation missing } after property list
  • how to import a dll into a asp.net web application running on webserver
  • Passing Data between VB.NET forms
  • Mongodb exception, “ MongoCursorException' with message '$ operator made object too large”
  • CMake - Accessing configuration parameters of multiple-configuration generators
  • How do you create a simple Automation Extender for Visual Studio with UITypeEditor
  • Excel VBA : How to copy href from HTML by referencing the class name
  • How does CoreLocation locate the device?
  • doubleValue does not convert the object to a double value correctly at all times
  • adb device not listed for Gionee E7 mini
  • Valums Ajax file Upload handle the up. file?
  • Unable to install breakpoint in Eclipse: Absent Line Number Information
  • Flink: How to write DataSet to a variable instead of to a file
  • $this->params returns null in cakephp model
  • Gradle - How to detect --debug flag from command line?
  • CUDA Debugging - VS on windows workstation, GPUs on Linux server?
  • OpenOptionsMenu not working with ActionBarSherlock Custom SubMenu
  • Pointer to a logger class provide for all other classes? [duplicate]
  • Log4j cannot find properties file in a simple application
  • How to make SASS put relative paths in its output
  • Programmatically Update Linked Named Range of excel object in MS Word (2007)
  • How to create virtual printer with iOS Simulator?
  • Spring Integration Bridge with poller not working as expected for JMS
  • runtime error when linking ffmpeg libraries in qt creator
  • Why cout is producing no output on Code Blocks?
  • How to pass solution folder as parameter in command line arguments (for debug)?
  • Is it possible to run clang with llc flags
  • VSCode change debug shell to bash on windows
  • Visual Studio 2010 debugger build correctly - compiler pdb and linker pdb not in synch?
  • Hardware Accelerated Image Scaling in windows using C++
  • Very simple C++ DLL that can be called from .net
  • Can I check if a recipient has an automatic reply before I send an email?
  • Getting last autonumber in access
  • -fvisibility=hidden not passed by compiler for Debug builds
  • How to CLICK on IE download dialog box i.e.(Open, Save, Save As…)