Подтвердить что ты не робот

Быстрая многооконная рендеринг

В течение многих недель я искал и тестировал различные виды библиотек для С# дней. До сих пор я не нашел ни одной библиотеки, которая хорошо работает в многооконных настройках рендеринга. Требование состоит в том, чтобы иметь возможность запускать программу на 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 здесь при выполнении рендеринга нескольких окон, это общая латентность, вызванная всеми функциями операционной системы (анимация окна, перетаскивание и отбрасывание прокрутки и т.д.).

4b9b3361

Ответ 1

Говоря о DirectX только здесь, но я помню, что у нас был такой же вопрос один раз (5 видеокарт и 9 экранов для одного ПК).

Похоже, что многократный полноэкранный коммутатор хочет включить вертикальную синхронизацию на мониторах, и поскольку Present не может быть потоковым, чем больше экранов с вертикальной синхронизацией, тем выше будет ваше падение (так как вы будете ждать от 0 до 16 миллисекунд ) для каждого текущего вызова.

Решение, которое у нас было в нашем случае, заключалось в том, чтобы создать окно как максимально развернутое и удалить границы, оно не идеально, а оказалось от 10 к/с, отведя прямоугольник обратно к стандартной скорости (60).

Если вы хотите, чтобы образец кода дал мне знать, я подготовлю его.

Также для тестирования у меня было создание 30 окон на моем движке с помощью С#/slimdx/dx11, рендеринг сферы с основным затенением, еще более 40 кадров в секунду.

Ответ 2

У нас есть аналогичная проблема (нужно визуализировать 3D-виды на 9+ мониторах, используя 3 + видеокарты). Мы решили использовать raw DirectX11 после того, как обнаружили, что сторонние библиотеки-получатели очень бедны в нескольких окнах на нескольких мониторах, не говоря уже о нескольких адаптерах. (Кажется, большинство движков рассчитано на полноэкранную игру и, как правило, сосать в окнах). Вместо того, чтобы использовать сторонний уровень, такой как SlimDX или SharpDX, в конце концов мы решили написать основной рендеринг непосредственно на С++ и просто предоставить простой API, который требуется нашему приложению через С++/CLI - это должно максимизировать производительность и минимизировать проблемы обслуживания (полагаясь на стороннем поставщике исправлений ошибок и т.д.).

Однако, как и вы, мы обнаружили, что если мы отобрали 9 представлений из одного процесса (каждый из которых был создан в собственном потоке), мы получили ужасную производительность (очень низкие частоты кадров). Однако, если мы выполнили 9 отдельных процессов (по одному на просмотр/монитор), производительность была как ожидалось (отлично).

Таким образом, потратив несколько дней на то, чтобы тратить сеть на лучшее решение, мы решили просто запустить наши рендереры в отдельных процессах. Не совсем плохое решение для нас, так как наши рендереры должны поддерживать распространение на нескольких ПК в любом случае, так что это просто означает, что мы будем использовать этот объект постоянно, а не только тогда, когда это требуется.

(Я не знаю, поможет ли это вам в качестве ответа, но мы также очень хотели бы знать, есть ли там какие-либо другие решения, которые работают на нескольких видеокартах, если мы не будем лучший трюк)

Ответ 3

У меня никогда не было возможности запускать подобные сценарии, но я уверен, что с управляемой оболочкой абсолютно не нужно беспокоиться, у вас будет такая же проблема с кодом на С++.

Кроме того, в вашем описании довольно неясно, сколько графических карт вы установили в своей системе. Также вам следует внимательно изучить "" DirectX Graphics Infrastructure (DXGI): лучшие практики ", поскольку они описывают множество проблем, которые могут возникнуть. Работа с другой графической картой в полноэкранном режиме с правильной настройкой swapchain для полноэкранного режима должна быть в порядке (используя" flip "вместо" blit", см. Msdn doc об этом), но если вы запускаете приложение в окне с максимизацией, я не думаю что производительность будет хорошей, так как blit будет мешать и производить некоторые задержки.

Вы можете отлично иметь одно многопоточное приложение, использующее несколько устройств, одно устройство на поток, и они должны иметь возможность правильно планировать... но опять же, поскольку у меня нет опыта в подобных сценариях, может быть какой-то вид задачи планирования графического процессора в этом конкретном случае.

Если проблема сохраняется даже после тщательной настройки DXGI, я бы предложил вам отладить все это с помощью GPUView, чтобы проверить более тщательно эти проблемы. Он предназначен именно для такого рода сценариев, но вам потребуется некоторое время, чтобы понять, как сделать диагностику с помощью такого инструмента. Был также один разговор о GPUView наконец GDC 2012: использование GPUView для понимания вашей игры DirectX 11 (Jon Story), которое, вероятно, стоит прочитать.

Ответ 4

Убедитесь, что вы отключили проверки безопасности для вызовов на собственный код (через SuppressUnmanagedCodeSecurityAttribute).

Связанная стековая ходьба - это убийца производительности.