В течение многих недель я искал и тестировал различные виды библиотек для С# дней. До сих пор я не нашел ни одной библиотеки, которая хорошо работает в многооконных настройках рендеринга. Требование состоит в том, чтобы иметь возможность запускать программу на 12+ мониторах (финансовый график) без задержек на быстром компьютере. Каждое окно необходимо обновлять несколько раз в секунду. В то время как этому процессору необходимо выполнять множество интенсивных и критически важных задач, некоторые из них должны быть перенесены на графические процессоры. То, что происходит с аппаратным рендерингом, другими словами, DirectX или OpenGL.
Я попробовал GDI + с формами окон и понял, что это слишком медленно для моих нужд. Я пробовал OpenGL через OpenTK (на панели управления окнами), который казался довольно быстрым (у меня все еще есть некоторые тесты для запуска на нем), но с трудом трудно нормально работать (трудно найти/использовать программы для хорошего воспроизведения текста). Недавно я попробовал DirectX9, DirectX10 и Direct2D с формами Windows через SharpDX. Я попробовал отдельное устройство для каждого окна, и к нему подошло одно устройство/несколько подкатегорий. Все это привело к очень низкой производительности в нескольких окнах. Например, если я устанавливаю целевой FPS на 20 и открываю 4 полноэкранных окна на разных мониторах, вся операционная система начинает сильно отставать. Рендеринг - это просто очистка экрана от черного, без примитивов. Использование ЦП в этом тесте было около 0%, а использование GPU около 10%, я не понимаю, что здесь является узким местом? Мой компьютер разработки очень быстрый, i7 2700k, AMD HD7900, 16GB, поэтому тесты должны определенно работать на этом.
В сравнении я делал некоторые тесты DirectX9 на С++/Win32 API одно устройство/несколько цепочек подкачки, и я мог открыть 100 окон, распространяющихся по всему рабочему пространству с 4 мониторами (с вращающимся на них трехмерным чайником) и по-прежнему имел совершенно ответственную операционную систему (fps, конечно же, резко снижалось в окнах рендеринга примерно до 5, что, как я ожидал, будет выполнять 100 одновременных рендерингов).
Кто-нибудь знает какие-либо хорошие способы сделать многооконный рендеринг на С#, или я вынужден перезаписать мою программу на С++, чтобы получить эту производительность (большая боль)? Наверное, я даю OpenGL еще один выстрел, прежде чем перейти на С++-маршрут. Я расскажу о любых результатах здесь.
Методы тестирования для справки:
Для теста С# DirectX с одним устройством с несколькими swapchain я использовал метод из этого превосходного ответа: Отображать разные изображения на монитор directX 10
Версия Direct3D10:
Я создал d3d10device и DXGIFactory следующим образом:
D3DDev = new SharpDX.Direct3D10.Device(SharpDX.Direct3D10.DriverType.Hardware,
SharpDX.Direct3D10.DeviceCreationFlags.None);
DXGIFac = new SharpDX.DXGI.Factory();
Затем инициализируются окна рендеринга следующим образом:
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);
Команда рисования, выполняемая на каждой итерации рендеринга, проста:
Parent.D3DDev.ClearRenderTargetView(_rt, new Color4(0, 0, 0, 0));
SC.Present(0, SharpDX.DXGI.PresentFlags.None);
Версия DirectX9 очень похожа:
Инициализация устройства:
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);
Инициализация окна рендеринга:
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);
}
Код для цикла рисования:
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();
Тест С++ DirectX9/Win32 API с несколькими swapchains и одним кодом устройства:
[С++] DirectX9 Multi-window test - Pastebin.com
Это измененная версия кода с хорошим примером кода Кевина Харриса.
Edit:
Только для того, чтобы это было ясно, моя главная проблема заключается не в низких значениях fps здесь при выполнении рендеринга нескольких окон, это общая латентность, вызванная всеми функциями операционной системы (анимация окна, перетаскивание и отбрасывание прокрутки и т.д.).