Précision et découpage numérique dans les graphiques à effet

Les applications qui affichent des effets à l’aide de Direct2D doivent veiller à atteindre le niveau de qualité et de prévisibilité souhaité en ce qui concerne la précision numérique. Cette rubrique décrit les bonnes pratiques et les paramètres pertinents dans Direct2D qui sont utiles si :

  • Votre graphe d’effets s’appuie sur une précision numérique élevée ou des couleurs en dehors de la plage [0, 1], et vous souhaitez vous assurer que celles-ci seront toujours disponibles
  • Ou bien, votre graphe d’effets s’appuie sur l’implémentation de rendu pour fixer les couleurs intermédiaires à la plage [0, 1], et vous souhaitez vous assurer que ce serrage se produit toujours

Direct2D divise souvent un graphique d’effet en sections et restitue chaque section dans une étape distincte. La sortie de certaines étapes peut être stockée dans des textures Direct3D intermédiaires qui, par défaut, ont une plage numérique et une précision limitées. Direct2D ne garantit pas si ou où ces textures intermédiaires sont utilisées. Ce comportement peut varier en fonction des fonctionnalités gpu ainsi qu’entre les versions de Windows.

Dans Windows 10, Direct2D utilise moins de textures intermédiaires en raison de son utilisation de la liaison de nuanceur. Direct2D peut donc produire des résultats différents avec les paramètres par défaut de ceux des versions antérieures de Windows. Cela affecte principalement les scénarios où la liaison de nuanceur est possible dans un graphique d’effet, et ce graphique contient également des effets qui produisent des couleurs de sortie à plage étendue.

Vue d’ensemble du rendu des effets et des intermédiaires

Pour afficher un graphique d’effet, Direct2D recherche d’abord le graphe sous-jacent de « transformations », où une transformation est un nœud de graphe utilisé dans un effet. Il existe différents types de transformations, notamment celles qui fournissent des nuanceurs Direct3D que Direct2D peut utiliser.

Par exemple, Direct2D peut afficher un graphique d’effets comme suit :

Graphe d’effets avec textures intermédiaires

Direct2D recherche des possibilités de réduire le nombre de textures intermédiaires utilisées pour restituer le graphique d’effet ; cette logique est opaque pour les applications. Par exemple, le graphique suivant peut être rendu par Direct2D à l’aide d’un appel de dessin Direct3D et d’aucune texture intermédiaire :

Graphe d’effet sans textures intermédiaires

Avant Windows 10, Direct2D utilisait toujours des textures intermédiaires si plusieurs nuanceurs de pixels étaient utilisés dans le même graphique d’effet. La plupart des effets intégrés qui ajustent simplement les valeurs de couleur (par exemple, Luminosité ou Saturation) le font à l’aide de nuanceurs de pixels.

Dans Windows 10, Direct2D peut désormais éviter d’utiliser des textures intermédiaires dans de tels cas. Pour ce faire, il lie en interne des nuanceurs de pixels adjacents. Exemple :

Graphe d’effet windows 10 avec plusieurs nuanceurs de pixels et aucune texture intermédiaire

Notez que tous les nuanceurs de pixels adjacents d’un graphe peuvent être liés entre eux. Par conséquent, seuls certains graphiques produisent une sortie différente sur Windows 10. Pour plus d’informations, consultez Liaison du nuanceur d’effet. Les principales restrictions sont les suivantes :

  • Un effet n’est pas lié à des effets qui consomment sa sortie, si le premier effet est connecté en tant qu’entrée à plusieurs effets.
  • Un effet n’est pas lié avec un jeu d’effets comme entrée si le premier effet échantillonne son entrée à une autre position logique que sa sortie. Par exemple, un effet Matrice de couleur peut être lié à son entrée, mais un effet Convolution ne le sera pas.

Comportement d’effet intégré

De nombreux effets intégrés peuvent produire des couleurs en dehors de la plage [0, 1] dans l’espace de couleurs non prémultiplié, même lorsque leurs couleurs d’entrée se trouvent dans cette plage. Dans ce cas, ces couleurs peuvent faire l’objet d’un découpage numérique. Notez qu’il est important de prendre en compte la plage de couleurs dans l’espace non prémultiplié, même si les effets intégrés produisent généralement des couleurs dans l’espace prémultiplié. Cela garantit que les couleurs restent à l’intérieur de la plage, même si d’autres effets ne les prédémultipaient par la suite.

Certains des effets qui peuvent émettre ces couleurs hors plage offrent une propriété « ClampOutput ». Il s’agit notamment des paramètres suivants :

Le fait de définir la propriété ClampOutput sur TRUE sur ces effets garantit qu’un résultat cohérent est obtenu, quels que soient les facteurs tels que la liaison de nuanceur. Notez que le serrage se produit dans un espace non prémultiplié.

D’autres effets intégrés peuvent également produire des couleurs de sortie au-delà de la plage [0, 1] dans un espace non prémultiplié, même lorsque leurs pixels de couleurs (et les propriétés « Color » le cas échéant) se trouvent dans cette plage. Il s’agit notamment des paramètres suivants :

Forcer le découpage numérique dans un graphique d’effets

Lors de l’utilisation des effets répertoriés ci-dessus qui n’ont pas de propriété ClampOutput, les applications doivent envisager de forcer le serrage numérique. Pour ce faire, insérez un effet supplémentaire dans le graphique qui serre ses pixels. Un effet Color Matrix peut être utilisé, avec sa propriété « ClampOutput » définie sur TRUE et la propriété « ColorMatrix » comme valeur par défaut (pass-through).

Une deuxième option pour obtenir des résultats cohérents consiste à demander à Direct2D d’utiliser des textures intermédiaires qui ont une plus grande précision. Ceci est décrit ci-dessous.

Contrôle de la précision des textures intermédiaires

Direct2D fournit plusieurs façons de contrôler la précision d’un graphique. Avant d’utiliser des formats de haute précision dans Direct2D, les applications doivent s’assurer qu’ils sont suffisamment pris en charge par le GPU. Pour case activée cela, utilisez ID2D1DeviceContext::IsBufferPrecisionSupported.

Les applications peuvent créer un appareil Direct3D à l’aide de WARP (émulation logicielle) pour garantir que toutes les précisions de mémoire tampon sont prises en charge indépendamment du matériel GPU réel sur l’appareil. Cela est recommandé dans des scénarios tels que l’application d’effets à une photo lors de l’enregistrement sur disque. Même si Direct2D prend en charge les formats de mémoire tampon de haute précision sur le GPU, l’utilisation de WARP est recommandée dans ce scénario sur les GPU 9.X de niveau de fonctionnalité, en raison de la précision limitée de l’arithmétique du nuanceur et de l’échantillonnage sur certains GPU mobiles de faible puissance.

Dans chaque cas ci-dessous, la précision demandée est en fait la précision minimale utilisée par Direct2D. Une précision plus élevée peut être utilisée si les intermédiaires ne sont pas nécessaires. Direct2D peut également partager des textures intermédiaires pour différentes parties du même graphique ou des graphiques différents entièrement. Dans ce cas, Direct2D utilise la précision maximale demandée pour toutes les opérations impliquées.

Sélection de précision dans ID2D1DeviceContext::SetRenderingControls

Le moyen le plus simple de contrôler la précision des textures intermédiaires de Direct2D consiste à utiliser ID2D1DeviceContext::SetRenderingControls. Cela contrôle la précision de toutes les textures intermédiaires, tant qu’une précision n’est pas également définie manuellement sur les effets ou les transformations directement.

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

Sélection de précision à partir des entrées et des cibles de rendu

Les applications peuvent également s’appuyer sur la précision des entrées d’un graphique d’effet pour contrôler la précision des textures intermédiaires. Cela est vrai tant qu’une précision de mémoire tampon n’est pas spécifiée à l’aide de ID2D1DeviceContext::SetRenderingControls, et qu’elle n’est pas définie manuellement sur les effets et la transformation directement.

Les précisions des entrées aux effets sont propagées dans le graphique pour sélectionner la précision des intermédiaires en aval. Lorsque les différentes branches du graphique d’effet se rencontrent, la plus grande précision de toute entrée est utilisée.

La précision sélectionnée en fonction d’un bitmap Direct2D est déterminée à partir de son format de pixels. La précision sélectionnée pour un ID2D1ImageSource est déterminée à partir du format de pixel WIC de la source IWICBitmapSource sous-jacente utilisée pour créer l’ID2D1ImageSource. Notez que Direct2D n’autorise pas la création de sources d’images avec des sources WIC à l’aide de précisions non prises en charge par Direct2D et le GPU.

Il est possible que Direct2D ne puisse pas affecter une précision à un effet en fonction de ses entrées. Cela se produit lorsqu’un effet n’a pas d’entrées ou lorsqu’un ID2D1CommandList est utilisé, qui n’a pas de précision spécifique. Dans ce cas, la précision des textures intermédiaires est déterminée à partir du jeu bitmap en tant que cible de rendu actuelle du contexte.

Sélection de précision directement sur l’effet et les transformations

La précision minimale pour les textures intermédiaires peut également être définie à des emplacements explicites dans un graphique d’effet. Ceci est recommandé uniquement pour les scénarios avancés.

La précision minimale peut être définie à l’aide d’une propriété sur un effet comme suit :

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

Dans une implémentation d’effet, la précision minimale peut être définie à l’aide de ID2D1RenderInfo::SetOutputPrecision comme suit :

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

Notez que le jeu de précision sur un effet se propage aux effets en aval dans le même graphique d’effets, sauf si une autre précision est définie sur ces effets en aval. Le jeu de précision sur une transformation au sein d’un effet n’affecte pas la précision des nœuds de transformation en aval.

Voici la logique récursive complète utilisée pour déterminer la précision minimale d’une mémoire tampon intermédiaire stockant la sortie d’un nœud de transformation donné :

Logique de précision minimale de la mémoire tampon intermédiaire