2014-12-08 2 views
4

Я использую проект SharpDX.WPF для возможностей WPF, кажется, что это легко понять низкоуровневую библиотеку по сравнению с Toolkit, который поставляется с SharpDX (который имеет такую ​​же проблему!)D3DImage и SharpDX мерцают на медленных аппаратных средствах

Во-первых: я установил проект SharpDX.WPF для последних SharpDX используя следующее: https://stackoverflow.com/a/19791534/442833

Тогда я сделал следующее Hacky корректировку DXElement.cs, решение, которое было также сделано here:

private Query queryForCompletion; 
    public void Render() 
    { 
     if (Renderer == null || IsInDesignMode) 
      return; 

     var test = Renderer as D3D11; 
     if (queryForCompletion == null) 
     { 

      queryForCompletion = new Query(test.Device, 
       new QueryDescription {Type = QueryType.Event, Flags = QueryFlags.None}); 
     } 

     Renderer.Render(GetDrawEventArgs()); 

     Surface.Lock(); 
     test.Device.ImmediateContext.End(queryForCompletion); 
     // wait until drawing completes 
     Bool completed; 
     var counter = 0; 
     while (!(test.Device.ImmediateContext.GetData(queryForCompletion, out completed) 
       && completed)) 
     { 
      Console.WriteLine("Yielding..." + ++counter); 
      Thread.Yield(); 
     } 
     //Surface.Invalidate(); 
     Surface.AddDirtyRect(new Int32Rect(0, 0, Surface.PixelWidth, Surface.PixelHeight)); 
     Surface.Unlock(); 
    } 

Тогда я сделать 8000 кубов в шаблон куба ...

Уступая ...

получает распечатанные на консоль довольно часто, но мерцающий все еще там. Я предполагаю, что WPF достаточно хорош, чтобы показать изображение, используя другой поток, прежде чем сделать рендеринг, но не уверен, хотя ... Эта же проблема также возникает, когда я использую вариант Toolkit поддержки WPF с помощью SharpDX.

Изображения на вопрос продемонстрировать режим:

Примечание: Это случайно переключается между этими старыми изображениями, случайным образом. Я также использую очень старое оборудование, которое делает мерцающий гораздо больше appearant (GeForce Quadro FX 1700)

выполненного репо, который содержит тот же исходный код, я использую, чтобы получить этот вопрос: https://github.com/ManIkWeet/FlickeringIssue/

+0

Проблема заключается D3DImage синхронизации DirectX, вы не только один с этой проблемой. См. Этот conv с создателем SharpDX: https://twitter.com/xoofx/status/544974189430448128 Я ищу решение самостоятельно ... :( –

ответ

0

Я думаю, что вы не запираетесь должным образом. Насколько я понимаю, MSDN documentation вы должны зафиксировать в течение всего рендеринга не только в конце этого:

Пока D3DImage заблокирован, приложение может также оказать на поверхность Direct3D присвоенной задний буфер ,

Информация, которую вы найдете в интернете о D3DImage/SharpDX несколько сбивает с толку, потому что ребята SharpDX не очень нравится то, как реализуется D3DImage (не может обвинить их), так что есть высказывания по этому поводу быть «ошибка» на стороне Microsoft, когда это фактически просто неправильное использование API.

Да, блокировка во время рендеринга имеет проблемы с производительностью, но, вероятно, невозможно исправить их, не перенося WPF в DirectX11 и реализуя что-то вроде SwapChainPanel, которое доступно в приложениях UWP. (Сам WPF по-прежнему работает на DirectX9)

Если блокировка является проблемой производительности для вас, одна из идей, которые у меня были (но не проверены), заключается в том, что вы можете визуализировать на внеочередной поверхности и сократить продолжительность блокировки до копирования этой поверхности поверх к D3DImage. Не знаю, поможет ли это производительности, но ее попробовать.

+0

С тех пор я перешел на использование DirectX11, он реализован намного лучше Я отмечу ваш ответ как решение, хотя я его еще не пробовал. – ManIkWeet

+0

@ Зарат Вау, я действительно не видел вашего ответа, прежде чем предоставлять свой собственный http://stackoverflow.com/questions/13368940/performance-issues -with-sharpdx-and-d3dimage/39580537, и похоже, что мы оба обходимся вокруг той же идеи .. –

3

, связанные с D3DImage замком, обратите внимание, что D3DImage.TryLock API имеет весьма нетрадиционную семантику, которые большинство разработчиков не были бы ожидать:

Осторожно!
Вы должны вызвать Unlock даже в том случае, когда TryLock указывает на неисправность (т.е. возвращает ложь)

Хотя, возможно, больше из выбора тревожными дизайн чем ошибка по себе, непонимание этого поведения будет тривиально приводить к тупикам D3DImage и зависанию, и, таким образом, они могут нести ответственность за большую часть разочарования, которое испытывают люди, пытаясь правильно работать D3DImage.

Следующий кодом является правильным WPF D3D визуализации, без мерцания в моем приложении:

void WPF_D3D_render(IntPtr pSurface) 
{ 
    if (TryLock(new Duration(default(TimeSpan)))) 
    { 
     SetBackBuffer(D3DResourceType.IDirect3DSurface9, pSurface); 
     AddDirtyRect(new Int32Rect(0, 0, PixelWidth, PixelHeight)); 
    } 
    Unlock(); // <--- ! 
} 

Да, это неинтуитивный код на самом деле правильно; это то, что D3DImage.TryLock(0)течет один внутренний буфер D3D-буфера каждый раз, когда он возвращает сбой. Вы не должны принимать мои слова для него, вот код CLR из PresentationCore.dll v4.0.30319:

private bool LockImpl(Duration timeout) 
{ 
    bool flag = false; 

    if (_lockCount == uint.MaxValue) 
     throw new InvalidOperationException(); 

    if (_lockCount == 0) 
    { 
     if (timeout == Duration.Forever) 
      flag = _canWriteEvent.WaitOne(); 
     else 
      flag = _canWriteEvent.WaitOne(timeout.TimeSpan, false); 

     UnsubscribeFromCommittingBatch(); 
    } 
    _lockCount++; 
    return flag; 
} 

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

Необычное поведение, по-видимому, не упоминается в MSDN, но, если быть справедливым, то в документации не отмечается, что вы должны позвонить Unlock(), если звонок будет успешным.

enter image description here

1

Проблема не запирающего механизма. Обычно вы используете Present, чтобы нарисовать, чтобы представить изображение. Present будет ждать, пока все чертежи будут готовы. С D3DImage вы не используете метод Present(). Вместо представления вы блокируете, добавляете DirtyRect и разблокируете D3DImage.

Отрисовка выполняется asynchrone, поэтому, когда вы разблокируете, действия ничьей могут быть не готовы. Это вызывает эффект мерцания. Иногда вы видите элементы наполовину вытянутые. Плохое решение (я тестировал с) добавляет небольшую задержку перед разблокировкой. Это немного помогло, но это было не простое решение. Это было ужасно!

Решение:

продолжал я с чем-то еще; Я устал от MSAA (сглаживание) и первой проблемой, с которой я столкнулся; MSAA не может быть выполнена на общей текстуре dx11/dx9, поэтому я решил отобразить новую текстуру (dx11) и создать копию общей текстуры dx9. Я хлопнул головой по табуляции, потому что теперь он был сглажен и бесстрастным! Не забудьте позвонить Flush() перед добавлением грязного прямоугольника.

Таким образом, создавая копию текстуры: DXDevice11.Device.ImmediateContext.ResolveSubresource(_dx11RenderTexture, 0, _dx11BackpageTexture, 0, ColorFormat);(_dx11BackpageTexture разделяют текстуры) будет ждать, пока рендеринг не готов и будет создавать копию.

Это, как я избавилась от мерцающих ....

Смежные вопросы