Genauigkeit und numerische Abschneidung in Effektgraphen
Anwendungen, die Effekte mit Direct2D rendern, müssen darauf achten, das gewünschte Qualitäts- und Vorhersagbarkeitsniveau hinsichtlich numerischer Genauigkeit zu erreichen. In diesem Thema werden bewährte Methoden und relevante Einstellungen in Direct2D beschrieben, die nützlich sind, wenn:
- Ihr Effektdiagramm basiert auf hoher numerischer Genauigkeit oder Farben außerhalb des [0, 1]-Bereichs, und Sie möchten sicherstellen, dass diese immer verfügbar sind.
- Oder Ihr Effektdiagramm basiert auf der Renderingimplementierung, um Zwischenfarben in den [0, 1] Bereich einzuklemmen, und Sie möchten sicherstellen, dass diese Klemmung immer stattfindet.
Direct2D unterteilt ein Effektdiagramm häufig in Abschnitte und rendert jeden Abschnitt in einem separaten Schritt. Die Ausgabe einiger Schritte kann in Direct3D-Zwischentexturen gespeichert werden, die standardmäßig einen begrenzten numerischen Bereich und eine begrenzte Genauigkeit aufweisen. Direct2D übernimmt keine Garantien darüber, ob oder wo diese Zwischentexturen verwendet werden. Dieses Verhalten kann je nach GPU-Funktionen sowie zwischen Windows-Versionen variieren.
In Windows 10 verwendet Direct2D aufgrund der Verwendung der Shaderverknüpfung weniger Zwischentexturen. Direct2D erzeugt daher möglicherweise andere Ergebnisse mit Standardeinstellungen als in früheren Windows-Releases. Dies wirkt sich in erster Linie auf Szenarien aus, in denen die Shaderverknüpfung in einem Effektdiagramm möglich ist und dieses Diagramm auch Effekte enthält, die Ausgabefarben mit erweitertem Bereich erzeugen.
Übersicht über Effektrendering und Zwischenprodukte
Um ein Effektdiagramm zu rendern, findet Direct2D zuerst das zugrunde liegende Diagramm von "Transformationen", wobei eine Transformation ein Graphknoten ist, der innerhalb eines Effekts verwendet wird. Es gibt verschiedene Arten von Transformationen, einschließlich solcher, die Direct3D-Shader für Direct2D bereitstellen.
Direct2D kann beispielsweise ein Effektdiagramm wie folgt rendern:
Direct2D sucht nach Möglichkeiten, die Anzahl der Zum Rendern des Effektdiagramms verwendeten Zwischentexturen zu reduzieren. Diese Logik ist für Anwendungen undurchsichtig. Beispielsweise kann das folgende Diagramm von Direct2D mit einem Direct3D-Zeichnungsaufruf ohne Zwischentexturen gerendert werden:
Vor Windows 10 verwendet Direct2D immer Zwischentexturen, wenn mehrere Pixel-Shader innerhalb desselben Effektdiagramms verwendet wurden. Die meisten integrierten Effekte, die einfach Farbwerte anpassen (z. B. Helligkeit oder Sättigung), tun dies mithilfe von Pixel-Shadern.
In Windows 10 kann Direct2D in solchen Fällen möglicherweise die Verwendung von Zwischentexturen vermeiden. Dazu werden benachbarte Pixel-Shader intern verknüpft. Beispiel:
Beachten Sie, dass nicht alle benachbarten Pixel-Shader in einem Graphen miteinander verknüpft sein können, sodass nur bestimmte Graphen eine unterschiedliche Ausgabe auf Windows 10 erzeugen. Ausführliche Informationen finden Sie unter Effect Shader Linking. Die wichtigsten Einschränkungen sind:
- Ein Effekt wird nicht mit Effekten verknüpft, die seine Ausgabe verbrauchen, wenn der erste Effekt als Eingabe mit mehreren Effekten verbunden ist.
- Ein Effekt wird nicht mit einem Effektsatz als Eingabe verknüpft, wenn der erste Effekt seine Eingabe an einer anderen logischen Position als seine Ausgabe abgibt. Beispielsweise kann ein Farbmatrixeffekt mit seiner Eingabe verknüpft sein, ein Convolution-Effekt ist es jedoch nicht.
Integriertes Effektverhalten
Viele integrierte Effekte können Farben außerhalb des [0, 1]-Bereichs im nicht vormultiplizierten Farbraum erzeugen, auch wenn sich ihre Eingabefarben innerhalb dieses Bereichs befinden. In diesem Fall können solche Farben numerischen Ausschneidungen unterliegen. Beachten Sie, dass es wichtig ist, den Farbbereich im nicht vormultiplizierten Raum zu berücksichtigen, auch wenn integrierte Effekte normalerweise Farben im vormultiplizierten Raum erzeugen. Dadurch wird sichergestellt, dass Farben in Reichweite bleiben, auch wenn sie von anderen Effekten später nicht vorverbreitet werden.
Einige der Effekte, die diese Außerhalb des Bereichs ausstrahlen können, bieten eine "ClampOutput"-Eigenschaft. Dazu gehören:
Wenn Sie die ClampOutput-Eigenschaft für diese Effekte auf TRUE festlegen, wird unabhängig von Faktoren wie der Shaderverknüpfung ein konsistentes Ergebnis erzielt. Beachten Sie, dass die Klemmung in nicht vormultipliziertem Raum erfolgt.
Andere integrierte Effekte können auch Ausgabefarben außerhalb des [0, 1]-Bereichs im nicht vormultiplizierten Raum erzeugen, auch wenn sich ihre Farben pixel (und "Color"-Eigenschaften (falls vorhanden) innerhalb dieses Bereichs befinden. Dazu gehören:
- Transformierungs- und Skalierungseffekte (Wenn die Interpolationsmodus-Eigenschaft kubisch oder qualitativ hochwertige Kubik ist)
- Lichteffekte
- Edgeerkennung (Wenn die Overlay Edges-Eigenschaft TRUE ist)
- Belichtung
- Zusammengesetzt (Wenn die Mode-Eigenschaft Plus ist)
- Temperatur und Tönung
- Sepia
- Sättigung
Erzwingen des numerischen Clippings innerhalb eines Effektdiagramms
Bei verwendung der oben aufgeführten Effekte, die keine ClampOutput-Eigenschaft aufweisen, sollten Anwendungen erwägen, numerische Klemmungen zu erzwingen. Dies kann durch Einfügen eines zusätzlichen Effekts in das Diagramm erfolgen, der die Pixel einklemmt. Es kann ein Color Matrix-Effekt verwendet werden, dessen Eigenschaft "ClampOutput" auf TRUE festgelegt ist und die "ColorMatrix"-Eigenschaft als Standardwert (Passthrough) bleibt.
Eine zweite Option, um konsistente Ergebnisse zu erzielen, besteht darin, direct2D die Verwendung von Zwischentexturen mit höherer Genauigkeit anzufordern. Dies wird im Folgenden beschrieben.
Steuern der Genauigkeit von Zwischentexturen
Direct2D bietet einige Möglichkeiten, die Genauigkeit eines Diagramms zu steuern. Vor der Verwendung von Hochgenauigkeitsformaten in Direct2D müssen Anwendungen sicherstellen, dass sie von der GPU ausreichend unterstützt werden. Um dies zu überprüfen, verwenden Sie ID2D1DeviceContext::IsBufferPrecisionSupported.
Anwendungen können ein Direct3D-Gerät mithilfe von WARP (Softwareemulation) erstellen, um sicherzustellen, dass alle Puffergenauigkeiten unabhängig von der tatsächlichen GPU-Hardware auf dem Gerät unterstützt werden. Dies wird in Szenarien empfohlen, z. B. beim Anwenden von Effekten auf ein Foto beim Speichern auf dem Datenträger. Auch wenn Direct2D hochgenaue Pufferformate auf der GPU unterstützt, wird in diesem Szenario die Verwendung von WARP auf 9.X-GPUs der Featureebene empfohlen, da die Genauigkeit der Shaderarithmetik und der Sampling auf einigen mobilen GPUs mit geringer Leistung begrenzt ist.
In jedem fall unten ist die angeforderte Genauigkeit tatsächlich die minimale Genauigkeit, die Direct2D verwendet. Höhere Genauigkeit kann verwendet werden, wenn Zwischenprodukte nicht erforderlich sind. Direct2D kann auch Zwischentexturen für verschiedene Teile desselben Graphen oder verschiedene Graphen vollständig gemeinsam nutzen. In diesem Fall verwendet Direct2D die maximale Genauigkeit, die für alle beteiligten Vorgänge angefordert wird.
Präzisionsauswahl aus ID2D1DeviceContext::SetRenderingControls
Die einfachste Möglichkeit, die Genauigkeit der Zwischentexturen von Direct2D zu steuern, besteht darin , ID2D1DeviceContext::SetRenderingControls zu verwenden. Dadurch wird die Genauigkeit aller Zwischentexturen gesteuert, solange eine Genauigkeit nicht auch manuell für Effekte oder Transformationen direkt festgelegt wird.
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);
}
Präzisionsauswahl aus Eingaben und Renderzielen
Anwendungen können sich auch auf die Genauigkeit der Eingaben für ein Effektdiagramm verlassen, um die Genauigkeit von Zwischentexturen zu steuern. Dies gilt, solange eine Puffergenauigkeit nicht mithilfe von ID2D1DeviceContext::SetRenderingControls angegeben und nicht manuell für Effekte festgelegt und direkt transformiert wird.
Die Genauigkeit von Eingaben für Effekte wird über das Diagramm verteilt, um die Genauigkeit der nachgeschalteten Zwischenprodukte auszuwählen. Wenn verschiedene Verzweigungen im Effektdiagramm aufeinandertreffen, wird die höchste Genauigkeit aller Eingaben verwendet.
Die genauigkeit, die basierend auf einer Direct2D-Bitmap ausgewählt wird, wird aus dem Pixelformat bestimmt. Die für eine ID2D1ImageSource ausgewählte Genauigkeit wird aus dem WIC-Pixelformat der zugrunde liegenden IWICBitmapSource bestimmt, die zum Erstellen der ID2D1ImageSource verwendet wird. Beachten Sie, dass Direct2D nicht zulässt, dass Bildquellen mit WIC-Quellen mit Genauigkeiten erstellt werden, die von Direct2D und der GPU nicht unterstützt werden.
Es ist möglich, dass Direct2D einem Effekt keine Genauigkeit basierend auf seinen Eingaben zuweisen kann. Dies geschieht, wenn ein Effekt keine Eingaben aufweist oder wenn eine ID2D1CommandList verwendet wird, die keine bestimmte Genauigkeit aufweist. In diesem Fall wird die Genauigkeit von Zwischentexturen aus der Bitmap bestimmt, die als aktuelles Renderziel des Kontexts festgelegt ist.
Präzisionsauswahl direkt auf den Effekt und die Transformationen
Die Minimale Genauigkeit für Zwischentexturen kann auch an expliziten Stellen innerhalb eines Effektdiagramms festgelegt werden. Dies wird nur für erweiterte Szenarien empfohlen.
Die minimale Genauigkeit kann mithilfe einer -Eigenschaft für einen Effekt wie folgt festgelegt werden:
if (Device->IsBufferPrecisionSupported(D2D1_BUFFER_PRECISION_32BPC_FLOAT))
{
hr = Effect->SetValue(D2D1_PROPERTY_PRECISION, D2D1_BUFFER_PRECISION_32BPC_FLOAT);
}
Innerhalb einer Effektimplementierung kann die minimale Genauigkeit mithilfe von ID2D1RenderInfo::SetOutputPrecision wie folgt festgelegt werden:
if (EffectContext->IsBufferPrecisionSupported(D2D1_BUFFER_PRECISION_32BPC_FLOAT))
{
hr = RenderInfo->SetOutputBuffer(
D2D1_BUFFER_PRECISION_32BPC_FLOAT,
D2D1_CHANNEL_DEPTH_4);
}
Beachten Sie, dass die für einen Effekt festgelegte Genauigkeit an nachgeschaltete Effekte im gleichen Effektdiagramm weitergegeben wird, es sei denn, für diese nachgeschalteten Effekte wird eine andere Genauigkeit festgelegt. Die für eine Transformation innerhalb eines Effekts festgelegte Genauigkeit wirkt sich nicht auf die Genauigkeit für nachgeschaltete Transformationsknoten aus.
Im Folgenden finden Sie die vollständige rekursive Logik, die verwendet wird, um die minimale Genauigkeit für einen Zwischenpuffer zu bestimmen, der die Ausgabe eines bestimmten Transformationsknotens speichert: