Точность и усечение чисел в графиках эффектов
Приложения, отрисовывающие эффекты с помощью Direct2D, должны обеспечить требуемый уровень качества и прогнозируемости в отношении числовой точности. В этом разделе описаны рекомендации и соответствующие параметры в Direct2D, которые полезны, если:
- Граф эффектов использует высокую числовую точность или цвета за пределами диапазона [0, 1], и вы хотите убедиться, что они всегда будут доступны.
- Или ваш график эффектов полагается на реализацию отрисовки, которая ограничивает промежуточные цвета в диапазоне [0, 1], и вы хотите убедиться, что это ограничение всегда выполняется.
Direct2D часто делит граф эффектов на разделы и отрисовывает каждый раздел в отдельном шаге. Выходные данные некоторых шагов могут храниться в промежуточных текстурах Direct3D, которые по умолчанию имеют ограниченный числовый диапазон и точность. Direct2D не гарантирует, используется ли эти промежуточные текстуры. Это поведение может отличаться в зависимости от возможностей GPU, а также между версиями Windows.
В Windows 10 Direct2D использует меньше промежуточных текстур из-за использования связывания шейдеров. Direct2D может создавать разные результаты с параметрами по умолчанию, чем в предыдущих выпусках Windows. Это в первую очередь влияет на сценарии, когда связывание шейдеров возможно в графе эффектов, и этот граф также содержит эффекты, которые создают цвета выходных данных расширенного диапазона.
Общие сведения о отрисовке эффектов и промежуточных элементах
Чтобы отобразить граф эффектов, Direct2D сначала находит базовый граф "преобразования", где преобразование является узлом графа, используемого в эффекте. Существуют различные типы преобразований, включая те, которые предоставляют шейдеры Direct3D для использования в Direct2D.
Например, Direct2D может отобразить граф эффектов следующим образом:
граф эффектов
Direct2D ищет возможности уменьшения числа промежуточных текстур, используемых для отрисовки графа эффектов; эта логика непрозрачна для приложений. Например, следующий граф можно отобразить с помощью Direct2D с помощью одного вызова рисования Direct3D и без промежуточных текстур:
граф эффектов
До Windows 10 Direct2D всегда будет использовать промежуточные текстуры, если в одном графе эффектов использовались несколько шейдеров пикселей. Большинство встроенных эффектов, которые просто настраивают значения цвета (например, яркость или насыщенность) делают это с помощью шейдеров пикселей.
В Windows 10 Direct2D теперь может избежать использования промежуточных текстур в таких случаях. Это достигается посредством внутреннего связывания соседних шейдеров пикселей. Например:
Обратите внимание, что не все смежные шейдеры пикселей в графе могут быть связаны друг с другом, и поэтому только определенные графы будут производить разные выходные данные в Windows 10. Полные сведения см. в разделе Связывание шейдеров эффектов. Основными ограничениями являются:
- Эффект не будет связан с эффектами, потребляющими его выходные данные, если первый эффект подключен в качестве входных данных к нескольким эффектам.
- Эффект не будет связан с набором эффектов в качестве входных данных, если первый эффект обрабатывает вход в другой логической позиции, чем выход. Например, эффект "Цветная матрица" может быть связан с входными данными, но эффект свертки не будет.
Встроенное поведение эффекта
Многие встроенные эффекты могут создавать цвета за пределами диапазона [0, 1] в непреднаставленном цветовом пространстве, даже если их входные цвета находятся в этом диапазоне. В этом случае такие цвета могут быть подвержены числовым вырезкам. Обратите внимание, что важно учитывать диапазон цветов в неумноженном пространстве, даже если встроенные эффекты обычно создают цвета в умноженном пространстве. Это гарантирует, что цвета остаются в заданном диапазоне, даже если другие эффекты впоследствии демультиплицируют их.
Некоторые эффекты, которые могут излучать несоответствующие диапазону цвета, имеют свойство ClampOutput. К ним относятся:
При задании свойства ClampOutput значение TRUE для этих эффектов гарантируется, что согласованный результат будет достигнут независимо от факторов, таких как связывание шейдеров. Обратите внимание, что ограничение происходит в непредварительно умноженном пространстве.
Другие встроенные эффекты также могут создавать выходные цвета за пределами диапазона [0, 1] в непрезумированном пространстве, даже если их цвета пикселей (и свойства 'Цвет', если таковые имеются) находятся в этом диапазоне. К ним относятся:
- Эффекты трансформации и масштабирования (если свойство режима интерполяции задано как кубическая или высококачественная кубическая интерполяция).
- эффекты освещения
- обнаружение границ (если свойство Overlay Edges установлено в значение истина)
- Экспозиция
- компонент (если свойство "Mode" имеет значение Plus)
- температура и оттенок
- Сепия
- насыщенность
Принудительное ограничение числовых значений в графе эффектов
При использовании эффектов, перечисленных выше, которые не имеют свойства ClampOutput, приложениям следует принудительно ограничивать значения. Это можно сделать, добавив в граф дополнительный эффект, который ограничивает его пиксели. Можно использовать эффект Color Matrix с установленным для свойства ClampOutput значением TRUE, оставив свойство ColorMatrix со значением по умолчанию (сквозной).
Второй вариант достижения согласованных результатов — запросить, чтобы Direct2D использовал промежуточные текстуры, которые имеют большую точность. Это описано ниже.
Управление точностью промежуточных текстур
Direct2D предоставляет несколько способов управления точностью графа. Прежде чем использовать форматы высокой точности в Direct2D, приложения должны убедиться, что они достаточно поддерживаются GPU. Чтобы проверить это, используйте ID2D1DeviceContext::IsBufferPrecisionSupported.
Приложения могут создавать устройство Direct3D с помощью WARP (программной эмуляции), чтобы гарантировать поддержку всех точностей буфера независимо от фактической аппаратуры GPU на устройстве. Это рекомендуется в таких сценариях, как применение эффектов к фотографии при сохранении на диске. Даже если Direct2D поддерживает форматы буферов высокой точности на GPU, использование WARP рекомендуется в этом сценарии на уровне функций 9.X GPU, из-за ограниченной точности арифметики и выборки шейдера на некоторых низкопроизводительных графических процессорах.
В каждом из приведённых ниже случаев запрошенная точность фактически является минимальной точностью, которую будет использовать Direct2D. Более высокая точность может использоваться, если промежуточные значения не требуются. Direct2D также может совместно использовать промежуточные текстуры для различных частей одного графа или полностью различных графов. В этом случае Direct2D использует максимальную точность, запрошенную для всех участвующих операций.
Выбор точности из ID2D1DeviceContext::SetRenderingControls
Самый простой способ управления точностью промежуточных текстур Direct2D — использовать ID2D1DeviceContext::SetRenderingControls. Это управляет точностью всех промежуточных текстур, пока точность не устанавливается вручную для эффектов или преобразований напрямую.
if (Device->IsBufferPrecisionSupported(D2D1_BUFFER_PRECISION_32BPC_FLOAT))
{
// Get the current rendering controls
D2D1_RENDERING_CONTROLS renderingControls = {};
Context->GetRenderingControls(&renderingControls);
// Switch the precision within the rendering controls and set it
renderingControls.bufferPrecision = D2D1_BUFFER_PRECISION_32BPC_FLOAT;
Context->SetRenderingControls(&renderingControls);
}
Точный выбор из входных данных и целей отрисовки
Приложения также могут полагаться на точность входных данных в граф эффектов для управления точностью промежуточных текстур. Это верно, если точность буфера не задана с помощью ID2D1DeviceContext::SetRenderingControlsи не настраивается вручную на эффекты и преобразования напрямую.
Точность входных данных для эффектов распространяется по графу, чтобы выбрать точность подчиненных промежуточных. Где сходятся различные ветви в графе эффектов, используется наивысшая точность среди всех входных данных.
Точность, выбранная на основе растрового изображения Direct2D, определяется по его формату пикселя. Точность, выбранная для ID2D1ImageSource, определяется из формата пикселей WIC базового IWICBitmapSource, используемого для создания ID2D1ImageSource. Обратите внимание, что Direct2D не позволяет создавать источники изображений из источников WIC, если их точность не поддерживается Direct2D и GPU.
Возможно, Direct2D не может присвоить эффекту уровень точности на основе его входных данных. Это происходит, если эффект не имеет входных данных или когда используется ID2D1CommandList, которая не имеет определенной точности. В этом случае точность промежуточных текстур определяется из набора битмапов в качестве текущего объекта вывода контекста.
Выбор высокой точности непосредственно для эффектов и преобразований
Минимальная точность промежуточных текстур также может быть задана в явных расположениях в графе эффектов. Это рекомендуется только для расширенных сценариев.
Минимальная точность может быть задана с помощью свойства для эффекта следующим образом:
if (Device->IsBufferPrecisionSupported(D2D1_BUFFER_PRECISION_32BPC_FLOAT))
{
hr = Effect->SetValue(D2D1_PROPERTY_PRECISION, D2D1_BUFFER_PRECISION_32BPC_FLOAT);
}
В реализации эффекта минимальная точность может быть задана с помощью ID2D1RenderInfo::SetOutputPrecision следующим образом:
if (EffectContext->IsBufferPrecisionSupported(D2D1_BUFFER_PRECISION_32BPC_FLOAT))
{
hr = RenderInfo->SetOutputBuffer(
D2D1_BUFFER_PRECISION_32BPC_FLOAT,
D2D1_CHANNEL_DEPTH_4);
}
Обратите внимание, что набор точности для эффекта будет распространяться на подчиненные эффекты в том же графе эффектов, если для этих подчиненных эффектов не задана другая точность. Установка точности преобразования в эффекте не влияет на точность для нижестоящих узлов преобразования.
Ниже приведена полная рекурсивная логика, используемая для определения минимальной точности промежуточного буфера, в котором хранятся выходные данные заданного узла преобразования: