Recorte numérico y de precisión en gráficos de efecto

Las aplicaciones que representan efectos mediante Direct2D deben tener cuidado para lograr el nivel deseado de calidad y predictibilidad con respecto a la precisión numérica. En este tema se describen los procedimientos recomendados y la configuración pertinente en Direct2D, que son útiles si:

  • El gráfico de efectos se basa en la alta precisión numérica o los colores fuera del intervalo [0, 1] y desea asegurarse de que siempre estarán disponibles.
  • O bien, el gráfico de efectos se basa en la implementación de representación para restringir los colores intermedios al intervalo [0, 1] y desea asegurarse de que esta fijación siempre se produce.

Direct2D a menudo divide un gráfico de efectos en secciones y representa cada sección en un paso independiente. La salida de algunos pasos se puede almacenar en texturas intermedias de Direct3D que, de forma predeterminada, tienen un intervalo numérico y una precisión limitados. Direct2D no garantiza si se usan estas texturas intermedias o dónde se usan. Este comportamiento puede variar según las funcionalidades de GPU, así como entre las versiones de Windows.

En Windows 10, Direct2D usa menos texturas intermedias debido a su uso de la vinculación del sombreador. Por lo tanto, Direct2D puede producir resultados diferentes con la configuración predeterminada que en versiones anteriores de Windows. Esto afecta principalmente a escenarios en los que la vinculación del sombreador es posible en un gráfico de efectos y ese gráfico también contiene efectos que producen colores de salida de rango extendido.

Información general sobre la representación de efectos e intermedios

Para representar un gráfico de efectos, Direct2D busca primero el gráfico subyacente de "transformaciones", donde una transformación es un nodo de grafo usado dentro de un efecto. Hay diferentes tipos de transformaciones, incluidas las que proporcionan sombreadores Direct3D para que Direct2D las use.

Por ejemplo, Direct2D puede representar un gráfico de efectos de la siguiente manera:

gráfico de efectos con texturas intermedias

Direct2D busca oportunidades para reducir el número de texturas intermedias usadas para representar el gráfico de efectos; esta lógica es opaca para las aplicaciones. Por ejemplo, Direct2D puede representar el gráfico siguiente mediante una llamada de dibujo de Direct3D y sin texturas intermedias:

gráfico de efectos sin texturas intermedias

Antes de Windows 10, Direct2D siempre usaría texturas intermedias si se usaran varios sombreadores de píxeles en el mismo gráfico de efectos. La mayoría de los efectos integrados que simplemente ajustan los valores de color (por ejemplo, Brillo o Saturación) lo hacen mediante sombreadores de píxeles.

En Windows 10, Direct2D ahora puede evitar el uso de texturas intermedias en estos casos. Para ello, vincula internamente sombreadores de píxeles adyacentes. Por ejemplo:

Gráfico de efectos de Windows 10 con varios sombreadores de píxeles y sin texturas intermedias

Tenga en cuenta que no todos los sombreadores de píxeles adyacentes de un grafo se pueden vincular juntos y, por tanto, solo determinados gráficos generarán resultados diferentes en Windows 10. Para obtener información completa, consulte Vinculación de sombreador de efectos. Las restricciones principales son:

  • Un efecto no se vinculará con los efectos que consumen su salida, si el primer efecto está conectado como entrada a varios efectos.
  • Un efecto no se vinculará con un conjunto de efectos como entrada, si el primer efecto muestra su entrada en una posición lógica diferente a su salida. Por ejemplo, un efecto Matriz de colores podría estar vinculado con su entrada, pero no será un efecto convolucional.

Comportamiento de efecto integrado

Muchos efectos integrados pueden producir colores fuera del intervalo [0, 1] en el espacio de colores no premultiplicado, incluso cuando sus colores de entrada están dentro de ese intervalo. Cuando esto sucede, estos colores pueden estar sujetos a recortes numéricos. Tenga en cuenta que es importante tener en cuenta la gama de colores en un espacio no premultiplicado, aunque los efectos integrados suelen producir colores en el espacio premultiplicado. Esto garantiza que los colores permanezcan dentro del intervalo, incluso si otros efectos posteriormente no están disponibles.

Algunos de los efectos que pueden emitir estos colores fuera del rango ofrecen una propiedad "ClampOutput". Entre ellas se incluyen las siguientes:

Establecer la propiedad ClampOutput en TRUE en estos efectos garantiza que se logrará un resultado coherente independientemente de factores como la vinculación del sombreador. Tenga en cuenta que la fijación se produce en un espacio sinmultiplicar.

Otros efectos integrados también pueden producir colores de salida más allá del intervalo [0, 1] en un espacio no premultiplicado, incluso cuando sus píxeles de colores (y propiedades "Color" si existen) están dentro de ese intervalo. Entre ellas se incluyen las siguientes:

Forzar el recorte numérico dentro de un gráfico de efectos

Aunque se usan efectos enumerados anteriormente que no tienen una propiedad ClampOutput, las aplicaciones deben considerar la posibilidad de forzar la fijación numérica. Esto se puede hacer insertando un efecto adicional en el gráfico que fija sus píxeles. Se puede usar un efecto Matriz de colores, con su propiedad "ClampOutput" establecida en TRUE y dejando la propiedad "ColorMatrix" como valor predeterminado (paso a través).

Una segunda opción para lograr resultados coherentes es solicitar que Direct2D use texturas intermedias que tengan mayor precisión. Este procedimiento se describe a continuación.

Controlar la precisión de las texturas intermedias

Direct2D proporciona varias maneras de controlar la precisión de un grafo. Antes de usar formatos de alta precisión en Direct2D, las aplicaciones deben asegurarse de que son compatibles con la GPU. Para comprobarlo, use ID2D1DeviceContext::IsBufferPrecisionSupported.

Las aplicaciones pueden crear un dispositivo Direct3D mediante WARP (emulación de software) para garantizar que todas las precisiónes del búfer sean compatibles independientemente del hardware real de GPU en el dispositivo. Esto se recomienda en escenarios como la aplicación de efectos a una foto mientras se guarda en el disco. Incluso si Direct2D admite formatos de búfer de alta precisión en la GPU, se recomienda usar WARP en este escenario en gpu de nivel de característica 9.X, debido a la precisión limitada de aritmética y muestreo del sombreador en algunas GPU móviles de bajo consumo.

En cada caso siguiente, la precisión solicitada es realmente la precisión mínima que usará Direct2D. Se puede usar una precisión mayor si no se requieren intermedios. Direct2D también puede compartir texturas intermedias para diferentes partes del mismo grafo o gráficos diferentes por completo. En este caso Direct2D usa la precisión máxima solicitada para todas las operaciones implicadas.

Selección de precisión de ID2D1DeviceContext::SetRenderingControls

La manera más sencilla de controlar la precisión de las texturas intermedias de Direct2D es usar ID2D1DeviceContext::SetRenderingControls. Esto controla la precisión de todas las texturas intermedias, siempre y cuando una precisión no también se establezca manualmente en efectos o transformaciones directamente.

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);
}
              

Selección de precisión de entradas y destinos de representación

Las aplicaciones también pueden depender de la precisión de las entradas en un gráfico de efectos para controlar la precisión de las texturas intermedias. Esto es true siempre y cuando no se especifique una precisión del búfer mediante ID2D1DeviceContext::SetRenderingControls y no se establezca manualmente en los efectos y la transformación directamente.

Las precisiónes de las entradas a los efectos se propagan a través del gráfico para seleccionar la precisión de los intermedios de bajada. Cuando se cumplen diferentes ramas del gráfico de efectos, se usa la mayor precisión de cualquier entrada.

La precisión seleccionada en función de un mapa de bits de Direct2D se determina a partir de su formato de píxel. La precisión seleccionada para un ID2D1ImageSource se determina a partir del formato de píxel WIC del IWICBitmapSource subyacente que se usa para crear id2D1ImageSource. Tenga en cuenta que Direct2D no permite que los orígenes de imágenes se creen con orígenes WIC mediante precisiones no admitidas por Direct2D y la GPU.

Es posible que Direct2D no pueda asignar un efecto una precisión en función de sus entradas. Esto sucede cuando un efecto no tiene entradas o cuando se usa id2D1CommandList , que no tiene ninguna precisión específica. En este caso, la precisión de las texturas intermedias se determina a partir del mapa de bits establecido como destino de representación actual del contexto.

Selección de precisión directamente en el efecto y las transformaciones

La precisión mínima para las texturas intermedias también se puede establecer en ubicaciones explícitas dentro de un gráfico de efectos. Esto solo se recomienda para escenarios avanzados.

La precisión mínima se puede establecer mediante una propiedad en un efecto como se indica a continuación:

if (Device->IsBufferPrecisionSupported(D2D1_BUFFER_PRECISION_32BPC_FLOAT))
{
  hr = Effect->SetValue(D2D1_PROPERTY_PRECISION, D2D1_BUFFER_PRECISION_32BPC_FLOAT);
}
              

Dentro de una implementación de efecto, la precisión mínima se puede establecer mediante ID2D1RenderInfo::SetOutputPrecision de la siguiente manera:

if (EffectContext->IsBufferPrecisionSupported(D2D1_BUFFER_PRECISION_32BPC_FLOAT))
{
  hr = RenderInfo->SetOutputBuffer(
  D2D1_BUFFER_PRECISION_32BPC_FLOAT,
  D2D1_CHANNEL_DEPTH_4);
}
              

Tenga en cuenta que la precisión establecida en un efecto se propagará a los efectos descendentes en el mismo gráfico de efectos, a menos que se establezca una precisión diferente en esos efectos descendentes. La precisión establecida en una transformación dentro de un efecto no afecta a la precisión de los nodos de transformación de bajada.

A continuación se muestra la lógica recursiva completa que se usa para determinar la precisión mínima de un búfer intermedio que almacena la salida de un nodo de transformación determinado:

Lógica de precisión mínima del búfer intermedio