Предотвращение масштабирования изображения области просмотра Direct3D (SlimDX)

У меня есть сцена Direct3D11, настроенная в SlimDX в окне. Рендеринг выполняется в отдельном потоке.

Есть ли способ удержать средство визуализации от растягивания изображения, когда оно рисует элемент управления с измененным размером? Я пробовал ModeDescription.Scaling = DisplayModeScaling.Centered, и это, похоже, не имеет никакого эффекта. Есть что-то, что мне не хватает?

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

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

Обходной путь 2. Аналогичный обходной путь заключается в проверке флага изменения размера в цикле рендеринга, а не в его прерывании. Средство визуализации должно иметь возможность рисовать напрямую без масштабирования. Это гораздо более приемлемо с точки зрения производительности. Однако для выполнения фактического изменения размера необходимо выполнить блокирующий вызов потока пользовательского интерфейса.

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

В идеале изменение размера должно выполняться непосредственно из потока пользовательского интерфейса (без задержек и повторного входа в поток пользовательского интерфейса из потока рендеринга). Это не ответственность потока рендеринга, и это замедляет его. Точно так же изменение размера буфера должно выполняться в потоке рендеринга для максимальной производительности (никаких хлопот с ожиданием/блокировкой/изменением размера/разблокировкой). Единственная причина, по которой это не работает, заключается в том, что поток рендеринга масштабируется, если изменение размера выполняется до изменения размера буферов.

Итак, мой вопрос остается в силе: есть ли способ рендеринга без масштабирования?


person jnm2    schedule 05.07.2011    source источник


Ответы (2)


Я собираюсь ответить на это с точки зрения задействованных необработанных API-интерфейсов Win32, которые могут потребовать некоторой утонченности для перевода в управляемую среду .NET и SlimDX.

Когда вы перетаскиваете или изменяете размер окна, окна в основном захватывают ваш поток сообщений и создают новый, специально предназначенный для эффективного выполнения логики изменения размера. Эта операция является более или менее модальной, пока не будет завершена. Многие сообщения, которые вы обычно получаете, буквально блокируются до завершения изменения размера или перетаскивания. В условиях приложения вы получаете WM_ENTERSIZEMOVE, когда это поведение начинается, и либо WM_EXITSIZEMOVE, либо WM_CAPTURECHANGED, когда оно заканчивается. Вам нужно проверить оба этих сообщения, так как нажатие клавиши Alt при перетаскивании приведет к отправке WM_CAPTURECHANGED, а не WM_EXITSIZEMOVE!

Все это означает, что когда вы получаете WM_ENTERSIZEMOVE, вы можете установить флаг и знать, что все сообщения WM_SIZE и WM_MOVE, которые появляются впоследствии, относятся к операции перетаскивания. Как правило, изменение размера целей рендеринга, а также отслеживание и освобождение всех ресурсов пула по умолчанию — очень медленная операция, и ее стоит отложить до завершения перетаскивания/изменения размера. Это имеет побочный эффект в виде растягивания окна, что является точно такой же проблемой, которую вы описываете здесь, и вы хотите это исправить.

Должна быть возможность добавить специальные обработчики в WM_SIZE, WM_MOVE или WM_SIZING и WM_MOVING, которые вызывают синхронный рендеринг и перерисовку через SendMessage (в отличие от PostMessage), когда они происходят, но вам нужно убедиться, что вы делаете это только внутри модальный цикл, принадлежащий WM_ENTERSIZEMOVE.

person Zoner    schedule 06.07.2011
comment
Я понимаю низкоуровневые вещи. Мой вопрос действительно заключается в том, как предотвратить его масштабирование, даже если размер буфера и размер окна различаются. На самом деле мне не нужен обходной путь синхронного изменения размера (см. Выше). Это делает интерфейс дерганым. Я просто хочу иметь возможность отображать окно другого размера без масштабирования. - person jnm2; 06.07.2011

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

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

person ssube    schedule 05.07.2011