Precisie en numerieke knipsels in effectgrafieken

Toepassingen die effecten weergeven met Direct2D, moeten ervoor zorgen dat het gewenste kwaliteitsniveau en voorspelbaarheid met betrekking tot numerieke precisie worden bereikt. In dit onderwerp worden aanbevolen procedures en relevante instellingen in Direct2D beschreven. Dit is handig als:

  • Uw effectgrafiek is afhankelijk van hoge numerieke precisie of kleuren buiten het bereik [0, 1] en u wilt ervoor zorgen dat deze altijd beschikbaar zijn
  • Of je effectgrafiek is afhankelijk van de rendering-implementatie om tussenliggende kleuren te begrenzen binnen het bereik [0, 1], en je wilt ervoor zorgen dat deze begrenzing altijd plaatsvindt

Direct2D verdeelt vaak een effectgrafiek in secties en geeft elke sectie in een afzonderlijke stap weer. De uitvoer van sommige stappen kan worden opgeslagen in tussenliggende Direct3D-patronen die standaard een beperkt numeriek bereik en een beperkte precisie hebben. Direct2D biedt geen garanties over of of deze tussenliggende patronen worden gebruikt. Dit gedrag kan variëren afhankelijk van GPU-mogelijkheden en tussen Windows-versies.

In Windows 10 gebruikt Direct2D minder tussenliggende patronen vanwege het gebruik van shaderkoppelingen. Direct2D kan daarom andere resultaten opleveren met standaardinstellingen dan in eerdere Versies van Windows. Dit is voornamelijk van invloed op scenario's waarbij shaderkoppeling mogelijk is in een effectgrafiek en die grafiek ook effecten bevat die uitvoerkleuren van een uitgebreid bereik produceren.

Overzicht van effectweergave en tussenliggende elementen

Als u een effectgrafiek wilt weergeven, zoekt Direct2D eerst de onderliggende grafiek van 'transformaties', waarbij een transformatie een grafiekknooppunt is dat binnen een effect wordt gebruikt. Er zijn verschillende soorten transformaties, waaronder die welke Direct3D-shaders leveren voor gebruik door Direct2D.

Direct2D kan bijvoorbeeld als volgt een effectgrafiek weergeven:

effectgrafiek met tussenliggende patronen

Direct2D zoekt naar mogelijkheden om het aantal tussenliggende patronen te verminderen dat wordt gebruikt om de effectgrafiek weer te geven; deze logica is ondoorzichtig voor toepassingen. De volgende grafiek kan bijvoorbeeld worden weergegeven door Direct2D met behulp van één Direct3D-tekenoproep en geen tussenliggende patronen:

effectgrafiek zonder tussenliggende patronen

Vóór Windows 10 zou Direct2D altijd tussenliggende texturen gebruiken als er meerdere pixel shaders werden gebruikt in hetzelfde effectdiagram. De meeste ingebouwde effecten die gewoon kleurwaarden aanpassen (bijvoorbeeld helderheid of verzadiging) doen dit met pixel-shaders.

In Windows 10 kan Direct2D nu in dergelijke gevallen het gebruik van tussentijdse texturen vermijden. Dit doet u door aangrenzende pixel-shaders intern te koppelen. Bijvoorbeeld:

windows 10-effectgrafiek met meerdere pixel-shaders en geen tussenliggende patronen

Houd er rekening mee dat niet alle aangrenzende pixel-shaders in een grafiek aan elkaar kunnen worden gekoppeld en daarom alleen bepaalde grafieken verschillende uitvoer produceren in Windows 10. Zie Effect Shader Linkingvoor meer informatie. De primaire beperkingen zijn:

  • Een effect wordt niet gekoppeld aan effecten die de uitvoer verbruiken, als het eerste effect is verbonden als invoer voor meerdere effecten.
  • Een effect wordt niet gekoppeld aan een set van effecten als invoer, als het eerste effect zijn invoer op een andere logische positie bemonstert dan zijn uitvoer. Een kleurmatrixeffect kan bijvoorbeeld worden gekoppeld aan de invoer, maar een convolution-effect is dat niet.

Ingebouwde effectwerking

Veel ingebouwde effecten kunnen kleuren produceren buiten het bereik [0, 1] in de niet-meervoudige kleurruimte, zelfs wanneer hun invoerkleuren binnen dat bereik vallen. Wanneer dit gebeurt, kunnen dergelijke kleuren onderhevig zijn aan numerieke afkapping. Houd er rekening mee dat het belangrijk is om het kleurenbereik in niet-voorgemultipliceerde ruimte te overwegen, ook al produceren ingebouwde effecten meestal kleuren in voorgemultipliceerde ruimte. Dit zorgt ervoor dat kleuren binnen het bereik blijven, zelfs wanneer andere effecten ze daarna gedemultipliceren.

Sommige van de effecten die deze buiten-bereikkleuren kunnen uitzenden bieden een eigenschap genaamd "ClampOutput". Dit zijn onder andere:

Het instellen van de eigenschap ClampOutput op TRUE op deze effecten zorgt ervoor dat een consistent resultaat wordt bereikt, ongeacht factoren zoals shader-koppeling. Houd er rekening mee dat clamping plaatsvindt in ruimte zonder premultiplicatie.

Andere ingebouwde effecten kunnen ook uitvoerkleuren produceren buiten het bereik [0, 1] in niet-voorgemultipliceerde ruimte, zelfs wanneer hun kleurenpixels (en de eigenschappen 'Kleur', indien van toepassing) binnen dat bereik vallen. Dit zijn onder andere:

Numerieke knipsels afdwingen in een effectgrafiek

Bij het gebruik van de hierboven vermelde effecten die geen ClampOutput-eigenschap hebben, is het aanbevolen dat toepassingen numerieke begrenzing afdwingen. Dit kan worden gedaan door een extra effect in te voegen in de grafiek die de pixels vastlegt. Een kleurmatrixeffect kan worden gebruikt, waarbij de eigenschap 'ClampOutput' is ingesteld op TRUE en de eigenschap ColorMatrix laat staan als de standaardwaarde (passthrough).

Een tweede optie voor het bereiken van consistente resultaten is om aan te vragen dat Direct2D tussenliggende patronen gebruikt die meer precisie hebben. Dit wordt hieronder beschreven.

De precisie van tussenliggende texturen beheren

Direct2D biedt een aantal manieren om de precisie van een grafiek te bepalen. Voordat u hoge precisie-indelingen in Direct2D gebruikt, moeten toepassingen ervoor zorgen dat ze voldoende worden ondersteund door de GPU. Gebruik ID2D1DeviceContext::IsBufferPrecisionSupportedom dit te controleren.

Toepassingen kunnen een Direct3D-apparaat maken met behulp van WARP (software-emulatie) om te garanderen dat alle bufferprecisies worden ondersteund, onafhankelijk van de daadwerkelijke GPU-hardware op het apparaat. Dit wordt aanbevolen in scenario's zoals het toepassen van effecten op een foto tijdens het opslaan op schijf. Zelfs als Direct2D ondersteuning biedt voor bufferindelingen met hoge precisie op de GPU, wordt het gebruik van WARP in dit scenario aanbevolen op gpu's op functieniveau 9.X, vanwege de beperkte precisie van arceringsberekeningen en steekproeven op sommige mobiele GPU's met een laag vermogen.

In elk geval hieronder is de aangevraagde precisie de minimale precisie die Direct2D gebruikt. Er kan een hogere precisie worden gebruikt als tussenliggende gegevens niet vereist zijn. Direct2D kan ook tussenliggende texturen delen voor verschillende gedeeltes van dezelfde grafiek of verschillende grafieken in zijn geheel. In dit geval gebruikt Direct2D de maximale precisie die is aangevraagd voor alle betrokken bewerkingen.

Precisie selectie van ID2D1DeviceContext::SetRenderingControls

De eenvoudigste manier om de precisie van de tussenliggende patronen van Direct2D te bepalen, is door ID2D1DeviceContext::SetRenderingControlste gebruiken. Hiermee bepaalt u de precisie van alle tussenliggende texturen, zolang er niet ook handmatig een precisie is ingesteld op effecten of transformaties rechtstreeks.

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

Precisieselectie van invoer- en renderdoelen

Toepassingen kunnen ook afhankelijk zijn van de precisie van de invoer in een effectgrafiek om de precisie van tussenliggende patronen te bepalen. Dit geldt zolang een bufferprecisie niet is opgegeven met behulp van ID2D1DeviceContext::SetRenderingControlsen niet handmatig op effecten en transformaties direct is ingesteld.

De precisies van invoer naar effecten worden doorgegeven via de graf om de precisie van downstream tussenliggende items te selecteren. Wanneer verschillende vertakkingen in de effectgrafiek elkaar ontmoeten, wordt de grootste precisie van elke invoer gebruikt.

De precisie die is geselecteerd op basis van een Direct2D-bitmap, wordt bepaald op basis van de pixelindeling. De precisie die is geselecteerd voor een ID2D1ImageSource wordt bepaald op basis van de WIC-pixelindeling van de onderliggende IWICBitmapSource die wordt gebruikt om de ID2D1ImageSource-te maken. Direct2D staat niet toe dat afbeeldingsbronnen met WIC-bronnen worden gemaakt met behulp van precisies die niet worden ondersteund door Direct2D en de GPU.

Het is mogelijk dat Direct2D geen precisie kan toewijzen aan een effect op basis van zijn invoer. Dit gebeurt wanneer een effect geen invoer heeft of wanneer een ID2D1CommandList- wordt gebruikt, die geen specifieke precisie heeft. In dit geval wordt de precisie van tussenliggende texturen bepaald door de bitmap die is ingesteld als het huidige rendertarget van de context.

Precieselectie rechtstreeks op effecten en transformaties

De minimale precisie voor tussenliggende patronen kan ook worden ingesteld op expliciete locaties in een effectgrafiek. Dit wordt alleen aanbevolen voor geavanceerde scenario's.

De minimale precisie kan als volgt worden ingesteld met behulp van een eigenschap voor een effect:

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

Binnen een effect-implementatie kan de minimale precisie worden ingesteld met id2D1RenderInfo::SetOutputPrecision als volgt:

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

Houd er rekening mee dat de precisieset voor een effect wordt doorgegeven aan downstreameffecten in dezelfde effectgrafiek, tenzij een andere precisie is ingesteld op deze downstreameffecten. De precisie die is ingesteld op een transformatie binnen een effect, heeft geen invloed op de precisie voor downstreamtransformatieknooppunten.

Hieronder ziet u de volledige recursieve logica die wordt gebruikt om de minimale precisie voor een tussenliggende buffer te bepalen die de uitvoer van een bepaald transformatieknooppunt opslaat:

tussenliggende buffer minimum precisie logica