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 assicurarsi che questo blocco si verifichi sempre

Direct2D divide spesso un grafico degli effetti 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 a causa dell'uso del collegamento dello shader. Direct2D può quindi produrre risultati diversi con le impostazioni predefinite rispetto alle versioni precedenti di Windows. Questo influisce principalmente sugli scenari in cui il collegamento dello shader è possibile in un grafico degli effetti e che il grafico contiene anche effetti che producono colori di output di intervallo esteso.

Panoramica del rendering degli effetti e degli intermedi

Per eseguire il rendering di un grafico degli effetti, Direct2D trova innanzitutto 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 da usare per Direct2D.

Ad esempio, Direct2D può eseguire il rendering di un grafico degli effetti come indicato di seguito:

grafico degli effetti 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 usati più pixel shader all'interno dello stesso grafico degli effetti. La maggior parte degli effetti predefiniti che regolano semplicemente i valori di colore (ad esempio, Luminosità o Saturazione) lo fanno usando pixel shader.

In Windows 10 Direct2D potrebbe ora evitare di usare trame intermedie in questi casi. Questa operazione viene eseguita collegando internamente pixel shader adiacenti. Ad esempio:

grafico degli effetti 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 tra loro e pertanto solo alcuni grafici produrranno output diverso su Windows 10. Per informazioni dettagliate, vedere Collegamento degli shader degli effetti. Le restrizioni principali sono:

  • Un effetto non verrà collegato agli effetti che 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 campiona l'input in una posizione logica diversa rispetto all'output. Ad esempio, un effetto Matrice di colori potrebbe essere collegato con il relativo input, ma un effetto Convoluzione non sarà.

Comportamento dell'effetto predefinito

Molti effetti predefiniti possono produrre colori al di fuori 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 producono in genere 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 intervallo offrono una proprietà "ClampOutput". Queste 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 il blocco si verifica nello spazio non premoltiplicato.

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

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

Anche se si usano gli effetti elencati in precedenza che non hanno una proprietà ClampOutput, le applicazioni devono considerare la possibilità 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 relativa 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. Questa procedura è descritta 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 di buffer ad alta precisione nella GPU, l'uso di WARP è consigliato in questo scenario in GPU di livello 9.X, a causa della precisione limitata dell'aritmetica shader e del campionamento su alcune GPU mobili a basso consumo.

In ogni caso di seguito, la precisione richiesta è in realtà la precisione minima direct2D userà. È possibile usare una maggiore precisione 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 della precisione da ID2D1DeviceContext::SetRenderingControls

Il modo più semplice per controllare la precisione delle trame intermedie di Direct2D consiste nell'usare ID2D1DeviceContext::SetRenderingControls. Ciò 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 in un grafico degli effetti per controllare la precisione delle trame intermedie. Ciò vale finché non viene specificata una precisione del buffer usando ID2D1DeviceContext::SetRenderingControls e non viene impostata manualmente sugli effetti e la trasformazione direttamente.

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 in base a una bitmap Direct2D viene determinata dal formato pixel. La precisione selezionata per un OGGETTO ID2D1ImageSource viene determinata dal formato di pixel WIC dell'oggetto IWICBitmapSource sottostante usato per creare ID2D1ImageSource. Si noti che Direct2D non consente la creazione di origini di immagini con origini WIC usando precisioni non supportate da Direct2D e 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 OGGETTO ID2D1CommandList , che non ha precisione specifica. In questo caso, la precisione delle trame intermedie viene determinata dal set di bitmap come destinazione di rendering corrente del contesto.

Selezione della precisione direttamente sull'effetto e sulle trasformazioni

La precisione minima per le trame intermedie può essere impostata anche 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 il set di precisione su un effetto verrà propagato agli effetti downstream nello stesso grafico degli effetti, a meno che non venga impostata una precisione diversa su tali effetti downstream. Il set di precisione in una trasformazione all'interno di un effetto non influisce sulla precisione per i nodi di trasformazione downstream.

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