Fast multi-window rendering - c#

I've been searching and testing different kinds of rendering libraries for C# days for many weeks now. So far I haven't found a single library that works well on multi-windowed rendering setups. The requirement is to be able to run the program on 12+ monitor setups (financial charting) without latencies on a fast computer. Each window needs to update multiple times every second. While doing this CPU needs to do lots of intensive and time critical tasks so some of the burden has to be shifted to GPUs. That's where hardware rendering steps in, in another words DirectX or OpenGL.
I have tried GDI+ with windows forms and figured it's way too slow for my needs. I have tried OpenGL via OpenTK (on windows forms control) which seemed decently quick (I still have some tests to run on it) but painfully difficult to get working properly (hard to find/program good text rendering libraries). Recently I tried DirectX9, DirectX10 and Direct2D with Windows forms via SharpDX. I tried a separate device for each window and a single device/multiple swap chains approaches. All of these resulted in very poor performance on multiple windows. For example if I set target FPS to 20 and open 4 full screen windows on different monitors the whole operating system starts lagging very badly. Rendering is simply clearing the screen to black, no primitives rendered. CPU usage on this test was about 0% and GPU usage about 10%, I don't understand what is the bottleneck here? My development computer is very fast, i7 2700k, AMD HD7900, 16GB ram so the tests should definitely run on this one.
In comparison I did some DirectX9 tests on C++/Win32 API one device/multiple swap chains and I could open 100 windows spread all over the 4-monitor workspace (with 3D teapot rotating on them) and still had perfectly responsible operating system (fps was dropping of course on the rendering windows quite badly to around 5 which is what I would expect running 100 simultaneous renderings).
Does anyone know any good ways to do multi-windowed rendering on C# or am I forced to re-write my program in C++ to get that performance (major pain)? I guess I'm giving OpenGL another shot before I go the C++ route. I'll report any findings here.
Test methods for reference:
For C# DirectX one-device multiple swapchain test I used the method from this excellent answer:
Display Different images per monitor directX 10
Direct3D10 version:
I created the d3d10device and DXGIFactory like this:
D3DDev = new SharpDX.Direct3D10.Device(SharpDX.Direct3D10.DriverType.Hardware,
SharpDX.Direct3D10.DeviceCreationFlags.None);
DXGIFac = new SharpDX.DXGI.Factory();
Then initialized the rendering windows like this:
var scd = new SwapChainDescription();
scd.BufferCount = 1;
scd.ModeDescription = new ModeDescription(control.Width, control.Height,
new Rational(60, 1), Format.R8G8B8A8_UNorm);
scd.IsWindowed = true;
scd.OutputHandle = control.Handle;
scd.SampleDescription = new SampleDescription(1, 0);
scd.SwapEffect = SwapEffect.Discard;
scd.Usage = Usage.RenderTargetOutput;
SC = new SwapChain(Parent.DXGIFac, Parent.D3DDev, scd);
var backBuffer = Texture2D.FromSwapChain<Texture2D>(SC, 0);
_rt = new RenderTargetView(Parent.D3DDev, backBuffer);
Drawing command executed on each rendering iteration is simply:
Parent.D3DDev.ClearRenderTargetView(_rt, new Color4(0, 0, 0, 0));
SC.Present(0, SharpDX.DXGI.PresentFlags.None);
DirectX9 version is very similar:
Device initialization:
PresentParameters par = new PresentParameters();
par.PresentationInterval = PresentInterval.Immediate;
par.Windowed = true;
par.SwapEffect = SharpDX.Direct3D9.SwapEffect.Discard;
par.PresentationInterval = PresentInterval.Immediate;
par.AutoDepthStencilFormat = SharpDX.Direct3D9.Format.D16;
par.EnableAutoDepthStencil = true;
par.BackBufferFormat = SharpDX.Direct3D9.Format.X8R8G8B8;
// firsthandle is the handle of first rendering window
D3DDev = new SharpDX.Direct3D9.Device(new Direct3D(), 0, DeviceType.Hardware, firsthandle,
CreateFlags.SoftwareVertexProcessing, par);
Rendering window initialization:
if (parent.D3DDev.SwapChainCount == 0)
{
SC = parent.D3DDev.GetSwapChain(0);
}
else
{
PresentParameters pp = new PresentParameters();
pp.Windowed = true;
pp.SwapEffect = SharpDX.Direct3D9.SwapEffect.Discard;
pp.BackBufferFormat = SharpDX.Direct3D9.Format.X8R8G8B8;
pp.EnableAutoDepthStencil = true;
pp.AutoDepthStencilFormat = SharpDX.Direct3D9.Format.D16;
pp.PresentationInterval = PresentInterval.Immediate;
SC = new SharpDX.Direct3D9.SwapChain(parent.D3DDev, pp);
}
Code for drawing loop:
SharpDX.Direct3D9.Surface bb = SC.GetBackBuffer(0);
Parent.D3DDev.SetRenderTarget(0, bb);
Parent.D3DDev.Clear(ClearFlags.Target, Color.Black, 1f, 0);
SC.Present(Present.None, new SharpDX.Rectangle(), new SharpDX.Rectangle(), HWND);
bb.Dispose();
C++ DirectX9/Win32 API test with multiple swapchains and one device code is here:
[C++] DirectX9 Multi-window test - Pastebin.com
It's a modified version from Kevin Harris's nice example code.
Edit:
Just to make it clear, my main problem is not low fps here when doing multi-window rendering, it's the general latency caused to all operating system functions (window animations, dragging&dropping scrolling etc).

Speaking of DirectX only here, but I remember we had the same kind of issue once (5 graphics card and 9 screens for a single PC).
Lot of times full screen switch seems to want to enable vertical sync on monitors, and since Present can't be threaded, the more screens with vertical sync the higher drop you will have (since you will wait between 0 and 16 milliseconds) for each present call.
Solution we had in our case was to create window as maximised and remove borders, it's not ideal but turned from 10 fps drawing a rectangle back to standard speed (60).
If you want code sample let me know I'll prepare one.
Also just for testing I had a go creating 30 windows on my engine using c#/slimdx/dx11, rendering a sphere with basic shading, still well over 40 fps.

We have a similar problem (need to render 3D views on 9+ monitors using 3+ graphics cards). We opted to use raw DirectX11 after finding that 3rd party rendering libraries are all very poor at multiple windows across multiple monitors, let alone with multiple adapters too. (It seems most engines are designed for a fullscreen game, and tend to suck at windowed views). Rather than using a 3rd party layer like SlimDX or SharpDX, we decided in the end to write the core renderer directly in C++ and just expose the simple API that our application needs via C++/CLI - this should maximise performance and minimise maintainability issues (relying on 3rd party vendor for bug fixes etc).
However, just like you, we found in testing that if we rendered 9 views from a single process (each rendered on its own thread), we got terrible performance (very low frame rates). However, if we ran 9 separate processes (one per view/monitor), the performance was as expected (excellent).
So having spent days trawling the net fruitlessly for a better solution, we opted for simply running our renderers in separate processes. Not entirely a bad solution for us as our renderers need to support distribution over multiple PCs anyway, so it just means we'll use this facility permanently instead of only when required.
(I don't know if this is helpful to you as an answer, but we'd also be very keen to know if there are any other solutions out there that work across multiple graphics cards, in case we're missing a better trick)

Never had the opportunity to run this kind of scenarios, but the only thing I'm pretty sure is that there is absolutely no concern using a managed wrapper, you would have exactly the same problem with C++ code.
Also, in your description, It is pretty unclear how many graphics card do you have installed on your system. Also you should follow more closely the "DirectX Graphics Infrastructure (DXGI): Best Practices" as they are describing lots of problem that you could have. Running with different graphics card in fullscreen with correctly swapchain setup for fullscreen should be ok (using "flip" instead of "blit", see msdn doc about this ), but if you are running your app in maximized window, I don't think that performance will be good, as the blit will interfere and produce some lags.
You can perfectly have a single multithreaded application using multiple device, one device per thread and they should be able to schedule things correctly... but again, as I have no experience in this kind of scenarios, there could be some kind of GPU scheduling problem in this specific case.
If the problem persist even after following carefully DXGI setup, I would suggest you to debug the whole thing with GPUView in order to check more carefully these problems. It is intended exactly for this kind of scenarios, but you will have to take some time to understand how to make a diagnostic with this kind of tool. There was also one talk about GPUView at last GDC 2012: Using GPUView to Understand your DirectX 11 Game (Jon Story) that is probably worth reading.

Make sure you've disabled security checks for calls to native code (via SuppressUnmanagedCodeSecurityAttribute).
The associated stack walking is a performance killer.

Its always a good idea to use doublebuffering because that can prevent flickering - atleast it does with windows forms.

Related

Force windows to use the best graphic card available

I have a WPF application which has a small 3D Engine on some specific pages (integrated via WindowsFormsHost).
I've seen that on many laptops with several graphic cards (dedicated and integrated) Windows would by default use the integrated one which in many cases will not be good enough to run my 3D Engine.
For example all my games are automatically executed with the dedicated GPU. Is there a way to show windows this WPF application needs the best GPU available ?
I understand that you can change that choice in your graphic card's settings but it's a complicated manipulation for most of the final users.
These two threads might be helpful:
- https://gamedev.stackexchange.com/questions/58546/how-can-i-set-my-application-to-run-on-the-high-performance-gpu-by-default
- https://stackoverflow.com/questions/16823372/forcing-machine-to-use-dedicated-graphics-card Christopher Oezbek's answer may be of interest
- https://stackoverflow.com/questions/29504891/laptop-dual-video-cards-how-to-programatically-detect-and-or-choose-which-one
The solution posted by axon seems promising

Drawing geographic map tiles with C#

I am creating a privately consumed custom map overlay.
I cannot use an open source server like MapServer, because of the sheer volumes of data and the format that it is in.
Originally it was going to be a client-side solution that pushed an ArrayBuffer to the client and render the data on a map using WebGL, however we later found out that our users' PCs would be minus a GPU, so they cannot smoothly run the WebGL rendering.
So I took the concepts and applied them to OpenTK - I created an IIS server handler that creates an OpenTK instance, and renders a requested tile.
For prototype's sake, it works - however I feel this is not the best solution.
What is the most efficient way to render out tiles?
I would love to pre-render the tiles, but there are just too many datasets (adding 1000 more per day!) to be able to efficiently do this.
Is OpenTK a good route to go down (because of the hardware acceleration it can take advantage of?), or is there too much overhead in setting up an instance?
Or are the C# Graphics libraries a better route to learn and use?
Or even - is it worth ditching IIS and C# all together and using a different language/framework for serving the images?
Your server only has a single GPU, so launching multiple instances of OpenTK will be significantly slower than launching a single instance and queuing tiles for rendering. Context switching inside the GPU drivers hurts. The latest version of OpenTK starts up in milliseconds so that should not be a problem (but you will have to measure.)

Capture visual output of a DirectX application - even in background?

I need to capture the visual output (like a screenshot) of a DirectX window.
Currently, I use this approach.
But, when the window is in background, it captures whatever is in front of it.
I see that DirectX windows render even when minimized or in background, so this should be possible.
But, how? (It also needs to be fast, and it needs to work on Windows XP too, unfortunately...)
Edit: I am very busy these days... Don't worry, I'll put the bounty back if it expires.
To capture Direct3D windows that are in the background (or moved off screen), I believe you have the following options:
Inject and hook Direct3D within the target application via the link you have already posted or this more up-to-date example (EasyHook can be difficult to get setup but it does work really well) - you can always ask for help about getting it working. I have used that technique for capturing in a number of games without issues (most recently for an ambilight-clone project). The problem with this approach is your concern about game protection causing bans, however FRAPs also uses hooking to achieve this, so perhaps your concerns are exaggerated? I guess gamers being banned for a screen shot is an expensive way of finding out.
For windowed applications on Vista/Win 7 - you could inject and hook the DWM and make your capture requests through its shared surface. I have had this working on Vista, but have not finished getting it working on Windows 7, here is an example of it working for Windows 7 http://www.youtube.com/watch?v=G75WKeXqXkc. The main problem with this approach is the use of undocumented API's which could mean your application breaks without any warning upon a windows patch release - also you would have to redo the technique for each new major Windows flavour. This also does not address your need to capture in Windows XP.
Also within the DWM, there is a thumbnail API. This has limitations depending on what your trying to do. There is some information on this API along with other DWM API's here http://blogs.msdn.com/b/greg_schechter/archive/2006/09/14/753605.aspx
There are other techniques for intercepting the Direct3D calls without using EasyHook, such as substituting the various DLL's with wrappers. You will find various other game hooking/interception techniques here: http://www.gamedeception.net/
Simply bring the Direct3D application to the foreground (which I guess is undesirable in your situation) - this wouldn't work for off-screen windows unless you also move the window.
Unfortunately the only solution for Windows XP that I can think of is intercepting the Direct3D API in some form.
Just a clarification on Direct3D rendering while minimised. During my fairly limited testing on this matter I have found this to be application dependant; it is generally not recommended that rendering take place while the application is minimized (also this reference), it does continue to render while in the background however.
UPDATED: provided additional link to more up-to-date injection example for point 1.
A quick google and i found this Code Project which relates to Windows XP. I dont know if you can apply this knowledge to Windows Vista and 7??
http://www.codeproject.com/Articles/5051/Various-methods-for-capturing-the-screen
EDIT:
I found this article as well:
http://www.codeproject.com/Articles/20651/Capturing-Minimized-Window-A-Kid-s-Trick
This links off from Justins blog post here from the comments. It seems he was working on this with someone (i see thats your link about).
http://spazzarama.com/2009/02/07/screencapture-with-direct3d/
The code that you linked to (from spazzarama), which you said you were using in your project, captures the front buffer of your DirectX device. Have you tried capturing the back buffer instead? Going from the code on your linked site, you would change line 90 from
device.GetFrontBufferData(0, surface);
to
Surface backbuffer = device.GetBackBuffer(0, 0, BackBufferType.Mono);
SurfaceLoader.Save("Screenshot.bmp", ImageFileFormat.Bmp, backbuffer);
This would also involve removing lines 96-98 in your linked example. The backbuffer might be generated without the obstructing window.
EDIT
Nevermind all of that. I just realized that your linked sample code is using the window handle to define a region of the screen, and not actually doing anything with the DirectX window. Your sample code won't work around the obstruction because your region is already drawn with the other window in front of it by the time you access it.
Your best bet to salvage the application is probably to bring the DirectX window to the top of the screen before running the code to capture the image. You can use the Wind32API BringWindowToTop function to do that (http://msdn.microsoft.com/en-us/library/ms632673%28VS.85%29.aspx).

multiple realtime graphics forms in own threads, global 60fps limit?

I'm using XNA and creating a bunch of forms that roll their own 'game loop' to handle drawing and such. Each new form is opened on its own thread, with a subsequent Application.Run(form) to make the thread handle the messages for that form.
When I started I noticed that despite me not implementing any kind of frame limiting timing, the window drew at 60 fps. This was the number I was aiming for anyway so I left it at that.
However now I discovered that when I open multiple windows, the original 60 fps gets divided evenly between them: 2 windows 30 each, 3 20 each, etc.
I also tried a loop with Application.DoEvents instead of Application.Run, but with the same results.
Anyone know where this 60fps limit coming from, how to overcome it?
Go to your graphic driver settings window. Turn off VSYNC.
I'm not an XNA expert, but it sounds that you're being limited by vsync, did you check that?
You say "forms" which leads me to believe you are running in windows on the desktop and not using a dedicated full screen display?
I believe that with Vista and Windows 7, the desktop compositor ("dwm") handles all of the actual drawing. It probably runs at 60 fps (or less when on battery). I am not sure why it divides the FPS between the two windows, but it could be some interaction of locking between graphics calls.
You can't benefit from multi threading drawing calls to the GPU. The GPU, although very good at parallel processing in it's own right, interacts with the CPU one thing at a time only and everything is blocked until it finishes the task at hand. Two draw calls on one thread will take just as long as two Draw calls on separate threads. Actually slower because of threading overhead.

Is it reasonable to use OpenGL for desktop applications?

I've been writing a small desktop gadget-type application that displays scrolling text along the bottom of the screen (Similar to the old CNN news ticker), however the performance of GDI is just unsatisfactory (As high as 8-12% on a quad core and 20% on a single core) even after I've attempted to clean out bottlenecks.
I was considering using OpenGL instead to render everything, but I don't know if that is a reasonable option to require users to have hardware acceleration for a tiny app like this.
Does anybody have any input on this?
If you're comfortable with using OpenGL and your intended users are happy with the additional dependencies that OpenGL brings then I say go for it. :)
In terms of staying with GDI, I'd make sure you're rendering the text a few times as possible (through such techniques as rendering to bitmap and just scrolling that instead).
If neither one of those two options sounds appealing then there's always DirectX.
You could write the app in WPF and let WPF handle the acceleration for you (it's backed by DirectX).
I wouldn't want to install open gl for a program like that. You say that you "attempted" to eliminate the bottlenecks, but it does not sound like you succeeded. Like lzcd mentioned, there are other ways to scroll text than to repaint it constantly. Why not just draw to a bitmap and scroll that?

Categories

Resources