Jump to content
  • Advertisement


  • Content Count

  • Joined

  • Last visited

Community Reputation

255 Neutral

About Syncaidius

  • Rank
  1. Syncaidius

    Writing a quick reference guide

    What you're making is very useful and easy to read. I'd just like to say thank you for putting the time into it.   I haven't had the time to mess with DX12 yet (still working with DX11) so there isn't much else I can say besides, keep up the good work!
  2. A bit late but, I thought I'd throw in my two cents, since I've been building my own engine on SharpDX for the past year.   Making your own engine will take a lot (and I mean, a huge amount) of time under a graphical API/wrapper like SharpDX or OpenTK.   Before you can start rendering anything, you need to build at least some kind of basic device, shader, texture and buffer management framework.   Then comes the sound, input, file IO, etc.   Out of everything I've done in my own engine so far, the hardest part was dealing with loading the common texture and model formats. I wrote my own DDS loader/saver to avoid using WIC (Windows imaging component). That alone took me almost 2 weeks due to how many variants of the DDS format there are, and it's such a small thing in terms of a basic engine. MonoGame does all of that for you.   Now, back to MonoGame. If you're developing for PC, there are two things to consider. The first is that, MonoGame uses SharpDX under the hood for Win-desktop, WinPhone and universal apps. MonoGame is also open source, so if you run into something a bit lacking you can pop the hood open and start adding or tweaking stuff yourself.   At the end of it all though, I understand the desire to build something you own in its entirety, with no worry about licenses. I also think it's an invaluable learning experience. Even if you never finish your engine and jump ship, you'll have learned a fair amount from the endeavor.   My reason for rolling with SharpDX was mostly for the same reason you stated. I wanted an engine that I owned, forever. My other reason was because I didn't like Monogame's or Unity's content system. I wanted to be able to stream content in and avoid loading screens entirely. I've succeeded on that front, but in doing so, I've forgone things like cross-platform support. Adding it will take a lot of work, but its doable.   Lastly, if you need any inspiration/motivation to stick with your decision, check out Space Engineers on steam. It's built on a DX11 engine made with SharpDX. The original iteration of the engine was made by 1 guy (Marek Rosa), who started out with XNA, then later rebuilt it under DX9 SharpDX for another game called Miner Wars. So it's definitely achievable. ;)
  3. Syncaidius

    [SharpDX] DirectX 12 problems

    Ah thank you! That is good to know.   Obviously my desktop (main work computer) has a DX12 compatible graphics card (GCN gpu), but I'm not risking Windows 10 on it for now.   It shouldn't be too long before SharpDX updates considering how fast they've stayed on top of DX12 so far.     I'm actually glad they've decided to cut all of the old baggage.
  4. Hi. I've been looking in to DirectX like many of you around here. However, I've been attempting to get it working via the SharpDX DX12 preview release.   I'm wondering if anyone else has been able to get the DX12 sample to work? https://github.com/sharpdx/SharpDX-Samples/tree/master/Desktop/Direct3D12/HelloWorld   I can't get a DX12 device to initialize after trying it on both an Intel HD 3000 (DX10.1) and Nividia Geforce 525M (DX11.0).   I had Windows 10 installed, and the Windows SDK. I've also tried every single available feature level to no avail.   Here is the sample code: using System; using System.Diagnostics; using System.Threading; using System.Windows.Forms; using SharpDX; using SharpDX.Direct3D; using SharpDX.DXGI; using System.Collections.Generic; namespace HelloWorld { using SharpDX.Direct3D12; /// <summary> /// HelloWorldD3D12 sample demonstrating clearing the screen. with D3D12 API. /// </summary> public class HelloWorld : IDisposable { private const int SwapBufferCount = 2; private int width; private int height; private Device device; private CommandAllocator commandListAllocator; private CommandQueue commandQueue; private SwapChain swapChain; private DescriptorHeap descriptorHeap; private GraphicsCommandList commandList; private Resource renderTarget; private Rectangle scissorRectangle; private ViewportF viewPort; private AutoResetEvent eventHandle; private Fence fence; private long currentFence; private int indexLastSwapBuf; private readonly Stopwatch clock; /// <summary> /// Constructor. /// </summary> public HelloWorld() { clock = Stopwatch.StartNew(); } /// <summary> /// Initializes this instance. /// </summary> /// <param name="form">The form.</param> public void Initialize(Form form) { width = form.ClientSize.Width; height = form.ClientSize.Height; LoadPipeline(form); LoadAssets(); } /// <summary> /// Updates this instance. /// </summary> public void Update() { } /// <summary> /// Render scene /// </summary> public void Render() { // record all the commands we need to render the scene into the command list PopulateCommandLists(); // execute the command list commandQueue.ExecuteCommandList(commandList); // swap the back and front buffers swapChain.Present(1, 0); indexLastSwapBuf = (indexLastSwapBuf + 1) % SwapBufferCount; Utilities.Dispose(ref renderTarget); renderTarget = swapChain.GetBackBuffer<Resource>(indexLastSwapBuf); device.CreateRenderTargetView(renderTarget, null, descriptorHeap.CPUDescriptorHandleForHeapStart); // wait and reset EVERYTHING WaitForPrevFrame(); } /// <summary> /// Cleanup allocations /// </summary> public void Dispose() { // wait for the GPU to be done with all resources WaitForPrevFrame(); swapChain.SetFullscreenState(false, null); eventHandle.Close(); // asset objects Utilities.Dispose(ref commandList); // pipeline objects Utilities.Dispose(ref descriptorHeap); Utilities.Dispose(ref renderTarget); Utilities.Dispose(ref commandListAllocator); Utilities.Dispose(ref commandQueue); Utilities.Dispose(ref device); Utilities.Dispose(ref swapChain); } /// <summary> /// Creates the rendering pipeline. /// </summary> /// <param name="form">The form.</param> private void LoadPipeline(Form form) { // create the device device = CreateDeviceWithSwapChain(form.Handle, DriverType.Hardware, DeviceCreationFlags.Debug, FeatureLevel.Level_11_0, out swapChain, out commandQueue); // create command queue and allocator objects commandListAllocator = device.CreateCommandAllocator(CommandListType.Direct); } /// <summary> /// Setup resources for rendering /// </summary> private void LoadAssets() { // Create the descriptor heap for the render target view descriptorHeap = device.CreateDescriptorHeap(new DescriptorHeapDescription() { Type = DescriptorHeapType.RenderTargetView, DescriptorCount = 1 }); // Create the main command list commandList = device.CreateCommandList(CommandListType.Direct, commandListAllocator, null); // Get the backbuffer and creates the render target view renderTarget = swapChain.GetBackBuffer<Resource>(0); device.CreateRenderTargetView(renderTarget, null, descriptorHeap.CPUDescriptorHandleForHeapStart); // Create the viewport viewPort = new ViewportF(0, 0, width, height); // Create the scissor scissorRectangle = new Rectangle(0, 0, width, height); // Create a fence to wait for next frame fence = device.CreateFence(0, FenceMiscFlags.None); currentFence = 1; // Close command list commandList.Close(); // Create an event handle use for VTBL eventHandle = new AutoResetEvent(false); // Wait the command list to complete WaitForPrevFrame(); } /// <summary> /// Fill the command list with commands /// </summary> private void PopulateCommandLists() { commandListAllocator.Reset(); commandList.Reset(commandListAllocator, null); // setup viewport and scissors commandList.SetViewport(viewPort); commandList.SetScissorRectangles(scissorRectangle); // Use barrier to notify that we are using the RenderTarget to clear it commandList.ResourceBarrierTransition(renderTarget, ResourceUsage.Present, ResourceUsage.RenderTarget); // Clear the RenderTarget var time = clock.Elapsed.TotalSeconds; commandList.ClearRenderTargetView(descriptorHeap.CPUDescriptorHandleForHeapStart, new Color4((float)Math.Sin(time) * 0.25f + 0.5f, (float)Math.Sin(time * 0.5f) * 0.4f + 0.6f, 0.4f, 1.0f), null, 0); // Use barrier to notify that we are going to present the RenderTarget commandList.ResourceBarrierTransition(renderTarget, ResourceUsage.RenderTarget, ResourceUsage.Present); // Execute the command commandList.Close(); } /// <summary> /// Wait the previous command list to finish executing. /// </summary> private void WaitForPrevFrame() { // WAITING FOR THE FRAME TO COMPLETE BEFORE CONTINUING IS NOT BEST PRACTICE. // This is code implemented as such for simplicity. long localFence = currentFence; commandQueue.Signal(fence, localFence); currentFence++; if (fence.CompletedValue < localFence) { fence.SetEventOnCompletion(localFence, eventHandle.SafeWaitHandle.DangerousGetHandle()); eventHandle.WaitOne(); } } private static Device CreateDeviceWithSwapChain(IntPtr formHandle, DriverType driverType, DeviceCreationFlags flags, FeatureLevel level, out SwapChain swapChain, out CommandQueue queue) { // create swap chain descriptor SwapChainDescription swapChainDescription = new SwapChainDescription() { BufferCount = SwapBufferCount, ModeDescription = new ModeDescription(Format.R8G8B8A8_UNorm), Usage = Usage.RenderTargetOutput, OutputHandle = formHandle, SwapEffect = SwapEffect.FlipSequential, SampleDescription = new SampleDescription(1, 0), IsWindowed = true, }; // NOTE: Messy hack for letting me switch adapter on my laptop Factory1 factory = new Factory1(); List<Adapter> adapters = new List<Adapter>(); Adapter[] detected = factory.Adapters; for (int i = 0; i < detected.Length; i++) { int outputCount = detected[i].GetOutputCount(); if (outputCount > 0) { adapters.Add(detected[i]); } } // NOTE: This always fails regardless of which device controls they display. var device = new Device(adapters[0], flags, level); queue = device.CreateCommandQueue(new CommandQueueDescription(CommandListType.Direct)); swapChain = new SwapChain(factory, queue, swapChainDescription); return device; } } } The parts I've edited are commented with "NOTE". On a side note, everything works in DX11, so I assume DX12 should work at feature level 10_1 and 11_0 too.   Any help would be much appreciated.
  5. Syncaidius

    Stream Leaks in SharpDX

    I'm unsure if you're using DX9 or DX11 so I'll just assume its DX11. I've been using DX11 + SharpDX for a few months now. There are a few ways to update a buffer. One way is via Context.UpdateSubResource(data, buffer). I have no idea if this works on non-writable buffers though. So far I've used map/unmap without any problems on various buffers types (vertex/index/structured/stream, staging/dynamic, etc). For dynamic buffers I use: // Map DataStream mappedData; Context.MapSubresource(buffer, MapMode.WriteDiscard, MapFlags.None, out mappedData); // Write data mappedData.WriteRange(dataArray, offset, count); // Cleanup + unmap mappedData.Dispose(); Context.UnmapSubresource(buffer, 0); For this to work, your (vertex) buffer needs to be setup with the following description:     BufferDescription desc = new BufferDescription()     {         BindFlags =  BindFlags.VertexBuffer,         Usage = ResourceUsage.Dynamic,         OptionFlags = ResourceOptionFlags.None,         SizeInBytes = _stride * elementCapacity,         CpuAccessFlags = CpuAccessFlags.Write, //Dynamic buffers will only accept write flags     };     Keep in mind dynamic buffers can only ever be written to by the CPU, and only read by the GPU. Adding CpuAccessFlags.Read to the description will cause an exception (usually "the parameters are incorrect"). The other way of updating a buffer is via a staging buffer. These are better if you'll be updating buffer data less than once per frame. Staging buffers can be both written and read to by the CPU, but have a massive tradeoff. They cannot be used by the GPU for anything except resource transfer (staging).   Usually they're paired with a "default" buffer which the staging buffer will transfer to (or from): BufferDescription desc = new BufferDescription() {     BindFlags =  BindFlags.VertexBuffer,     Usage = ResourceUsage.Default, //NOTE: Default usage     OptionFlags = ResourceOptionFlags.None,     SizeInBytes = _stride * elementCapacity,     CpuAccessFlags = CpuAccessFlags.None, //NOTE: no cpu access }; For me, the FPS gain from rendering with a default buffer has been significant. But the frame rate tends to die pretty fast if you constantly update the buffer via staging buffers once per frame or more (which is where dynamic buffers are better).   Map/unmap can be used to fill a staging buffer as such: // Map - Note the "Write" map mode. DataStream mappedData; Context.MapSubresource(stagingBuffer, MapMode.Write, MapFlags.None, out mappedData); //MapMode.Read if you want to read from it. // Write data mappedData.WriteRange(dataArray, offset, count); // Cleanup + unmap mappedData.Dispose(); Context.UnmapSubresource(stagingBuffer, 0); Since staging buffers arn't bound to the pipeline for use, it is safe to use a Write or Read map mode. I'm unsure if WriteDiscard works on a staging buffer, but i'd expect it to wipe all of the data in the buffer.   The description for a staging buffer is generally the same for every staging buffer, since they are a bindless resource: BufferDescription desc = new BufferDescription() {     BindFlags =  BindFlags.None,     Usage = ResourceUsage.Staging,     OptionFlags = ResourceOptionFlags.None,     SizeInBytes = _stride * elementCapacity,     CpuAccessFlags = CpuAccessFlags.Write, //You can add read flags here if you're going to be reading. }; Before the data is usable by the GPU, it must be copied to the buffer you're going to be rendering/using via Context.CopyResource. Context.CopyResource(stagingBuffer, vertexBuffer); You can also use them in reverse for copying data from a buffer on the GPU, to a staging buffer. But this is more use for things like structured or stream-out buffers than vertex or index buffers.   If you really wanted to pull data out of a dynamic buffer, you should be able to do: Context.CopyResource(dynamicVertexBuffer, stagingBuffer); Then use map/unmap on the staging buffer with MapMode.Read.   Keep in mind that dynamic buffers can only be read by the GPU, so I'm not sure copying from a staging buffer to a dynamic buffer will work, since that would involve the GPU writing to it.   All of this will work the same for index buffers too (and most of the other buffer types).   Hopefully this helps, and apologies if I derped. Its my first post here. If you have any other questions, drop them here and I'll try my best to help if I'm around.
  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!