Condividi tramite


Precisione e ritaglio numerico nei grafici degli effetti

Le applicazioni che eseguono il rendering degli effetti con Direct2D devono prestare attenzione a ottenere il livello desiderato di qualità e prevedibilità rispetto alla precisione numerica. Questo argomento descrive le procedure consigliate e le impostazioni pertinenti in Direct2D, utili se:

  • Il grafico degli effetti si basa su precisione numerica elevata o colori esterni all'intervallo [0, 1] e si vuole assicurarsi che siano sempre disponibili
  • In alternativa, il grafico degli effetti si basa sull'implementazione del rendering per bloccare i colori intermedi all'intervallo [0, 1] e si vuole garantire che questo blocco si verifichi sempre

Direct2D divide spesso un grafico di effetto in sezioni ed esegue il rendering di ogni sezione in un passaggio separato. L'output di alcuni passaggi può essere archiviato in trame Direct3D intermedie che per impostazione predefinita hanno un intervallo numerico e una precisione limitati. Direct2D non garantisce se o dove vengono usate queste trame intermedie. Questo comportamento può variare in base alle funzionalità GPU e alle versioni di Windows.

In Windows 10, Direct2D usa meno trame intermedie grazie al collegamento degli shader. Direct2D può quindi produrre risultati diversi con impostazioni predefinite rispetto alle versioni precedenti di Windows. Ciò influisce principalmente sugli scenari in cui è possibile collegare shader in un grafico degli effetti e contiene anche effetti che producono colori di output estesi dell'intervallo.

Panoramica del rendering degli effetti e degli intermediari

Per eseguire il rendering di un grafico degli effetti, Direct2D trova prima di tutto il grafico sottostante delle "trasformazioni", dove una trasformazione è un nodo del grafo usato all'interno di un effetto. Esistono diversi tipi di trasformazioni, tra cui quelle che forniscono shader Direct3D per Direct2D da usare.

Ad esempio, Direct2D può eseguire il rendering di un grafico degli effetti nel modo seguente:

grafico dell'effetto con trame intermedie

Direct2D cerca opportunità per ridurre il numero di trame intermedie usate per eseguire il rendering del grafico degli effetti; questa logica è opaca per le applicazioni. Ad esempio, il rendering del grafico seguente può essere eseguito da Direct2D usando una chiamata di disegno Direct3D e nessuna trama intermedia:

grafico degli effetti senza trame intermedie

Prima di Windows 10, Direct2D usava sempre trame intermedie se venivano utilizzati shader di pixel multipli all'interno dello stesso grafo degli effetti. La maggior parte degli effetti predefiniti che regolano semplicemente i valori dei colori (ad esempio, Luminosità o Saturazione) lo fanno usando pixel shader.

In Windows 10 Direct2D può ora evitare di usare trame intermedie in tali casi. Questa operazione viene eseguita collegando internamente pixel shader adiacenti. Per esempio:

grafico degli effetti di Windows 10 con più pixel shader e nessuna trama intermedia

Si noti che non tutti gli shader pixel adiacenti in un grafico possono essere collegati insieme e pertanto solo alcuni grafici produrranno output diverso in Windows 10. Per dettagli completi, vedere Effect Shader Linking. Le restrizioni principali sono:

  • Un effetto non verrà collegato agli effetti che ne consumano l'output, se il primo effetto è connesso come input a più effetti.
  • Un effetto non verrà collegato a un effetto impostato come input, se il primo effetto ne esegue il campionamento in una posizione logica diversa rispetto all'output. Ad esempio, un effetto Matrice dei Colori potrebbe essere collegato al relativo input, ma un Effetto di Convoluzione non lo sarà.

Comportamento di effetto predefinito

Molti effetti predefiniti possono produrre colori all'esterno dell'intervallo [0, 1] nello spazio dei colori non premoltiplicato, anche quando i colori di input si trovano all'interno di tale intervallo. In questo caso, tali colori possono essere soggetti a ritagli numerici. Si noti che è importante considerare l'intervallo di colori nello spazio non premoltiplicato, anche se gli effetti predefiniti in genere producono colori nello spazio premoltiplicato. Ciò garantisce che i colori rimangano all'interno dell'intervallo, anche se altri effetti successivamente non li premoltiplicano.

Alcuni degli effetti che possono generare questi colori fuori dalla gamma offrono una proprietà "ClampOutput". Questi includono:

L'impostazione della proprietà ClampOutput su TRUE su questi effetti garantisce che venga ottenuto un risultato coerente indipendentemente da fattori come il collegamento dello shader. Si noti che la limitazione avviene nello spazio non premoltiplicato.

Altri effetti integrati possono anche produrre colori di output oltre l'intervallo [0, 1] nello spazio non premoltiplicato, anche quando i propri pixel di colore (e le proprietà "Colore", se presenti) si trovano all'interno di tale intervallo. Questi includono:

Forzatura del ritaglio numerico all'interno di un grafico degli effetti

Durante l'uso degli effetti elencati in precedenza che non hanno una proprietà ClampOutput, le applicazioni dovrebbero considerare di forzare il blocco numerico. Questa operazione può essere eseguita inserendo un effetto aggiuntivo nel grafico che blocca i pixel. È possibile utilizzare un effetto Matrice di colori, con la proprietà 'ClampOutput' impostata su TRUE e lasciando la proprietà 'ColorMatrix' come valore predefinito (pass-through).

Una seconda opzione per ottenere risultati coerenti consiste nel richiedere che Direct2D usi trame intermedie con maggiore precisione. Questo è descritto di seguito.

Controllo della precisione delle trame intermedie

Direct2D offre alcuni modi per controllare la precisione di un grafico. Prima di usare formati ad alta precisione in Direct2D, le applicazioni devono assicurarsi che siano supportate sufficientemente dalla GPU. Per verificarlo, usare ID2D1DeviceContext::IsBufferPrecisionSupported.

Le applicazioni possono creare un dispositivo Direct3D usando WARP (emulazione software) per garantire che tutte le precisioni del buffer siano supportate indipendentemente dall'hardware GPU effettivo nel dispositivo. Questa opzione è consigliata in scenari come l'applicazione di effetti a una foto durante il salvataggio su disco. Anche se Direct2D supporta formati buffer ad alta precisione nella GPU, l'uso di WARP è consigliato in questo scenario a livello di funzionalità 9.X GPU, a causa della precisione limitata dell'aritmetica dello shader e del campionamento su alcune GPU per dispositivi mobili a basso consumo.

In ciascun caso seguente, la precisione richiesta è in realtà la precisione minima che verrà usata da Direct2D. È possibile usare una precisione maggiore se non sono necessari intermedi. Direct2D può anche condividere trame intermedie per parti diverse dello stesso grafico o grafici diversi interamente. In questo caso Direct2D usa la precisione massima richiesta per tutte le operazioni coinvolte.

Selezione di precisione da ID2D1DeviceContext::SetRenderingControls

Il modo più semplice per controllare la precisione delle trame intermedie di Direct2D consiste nell'usare ID2D1DeviceContext::SetRenderingControls. Questo controlla la precisione di tutte le trame intermedie, purché una precisione non venga impostata manualmente sugli effetti o sulle trasformazioni direttamente.

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

Selezione di precisione da input e destinazioni di rendering

Le applicazioni possono anche basarsi sulla precisione degli input a un grafico degli effetti per controllare la precisione delle trame intermedie. Questo vale finché non viene specificata una precisione del buffer usando ID2D1DeviceContext::SetRenderingControlse non viene impostata manualmente sugli effetti e sulle trasformazioni dirette.

Le precisioni degli input agli effetti vengono propagate attraverso il grafico per selezionare la precisione degli intermedi downstream. Dove si incontrano rami diversi nel grafico degli effetti, viene usata la massima precisione di qualsiasi input.

La precisione selezionata a partire da una bitmap Direct2D viene determinata dal formato dei pixel. La precisione selezionata per un ID2D1ImageSource viene determinata dal formato di pixel WIC del IWICBitmapSource sottostante usato per creare il ID2D1ImageSource. Si noti che Direct2D non consente la creazione di sorgenti di immagini con WIC utilizzando precisioni non supportate da Direct2D e dalla GPU.

È possibile che Direct2D non possa assegnare un effetto a una precisione in base ai relativi input. Ciò si verifica quando un effetto non ha input o quando viene usato un ID2D1CommandList, che non ha precisione specifica. In questo caso, la precisione delle texture intermedie viene determinata dalla bitmap impostata come destinazione di rendering corrente del contesto.

Selezione di precisione direttamente sugli effetti e sulle trasformazioni

La precisione minima per le trame intermedie può anche essere impostata in posizioni esplicite all'interno di un grafico degli effetti. Questa opzione è consigliata solo per scenari avanzati.

La precisione minima può essere impostata utilizzando una proprietà su un effetto come indicato di seguito:

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

All'interno di un'implementazione dell'effetto, la precisione minima può essere impostata usando ID2D1RenderInfo::SetOutputPrecision come indicato di seguito:

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

Si noti che la precisione stabilita su un effetto si propaga agli effetti a valle nella stessa rete di effetti, a meno che non venga impostata una precisione diversa su quegli effetti a valle. Il livello di precisione impostato su una trasformazione all'interno di un effetto non influisce sulla precisione per i nodi di trasformazione a valle.

Di seguito è riportata la logica ricorsiva completa usata per determinare la precisione minima per un buffer intermedio che archivia l'output di un determinato nodo di trasformazione:

logica di precisione minima del buffer intermedio