Flip-Modell, dirty rectangles, scrolled areas
DXGI 1.2 unterstützt eine neue Auslagerungskette für Flip-Modelle, dirty Rectangles und scrollte Bereiche. Wir erläutern die Vorteile der Verwendung der neuen Tauschkette für Flip-Modelle und der Optimierung der Darstellung durch Angabe von dirty rectangles und scrolled areas.
DXGI- Flip-Model-Präsentation
DXGI 1.2 fügt Unterstützung für das Flip-Präsentationsmodell für Direct3D 10- und höher-APIs hinzu. In Windows 7 hat Direct3D 9EX zuerst eine Flip-Modellpräsentation übernommen, um zu vermeiden, dass der Swap-Chain-Puffer unnötig kopiert wird. Mithilfe des Flip-Modells werden Zurückpuffer zwischen der Laufzeit und Desktopfenster-Manager (DWM) gekippt, sodass DWM immer direkt aus dem Backpuffer erstellt wird, anstatt den Inhalt des Zurückpuffers zu kopieren.
DXGI 1.2-APIs enthalten eine überarbeitete DXGI-Swap-Chain-Schnittstelle, IDXGISwapChain1. Sie können mehrere IDXGIFactory2-Schnittstellenmethoden verwenden, um das entsprechende IDXGISwapChain1-Objekt zu erstellen, das mit einem HWND-Handle, einem CoreWindow-Objekt, DirectCompositionoder dem -Objekt verwendet Windows. BENUTZEROBERFLÄCHE. Xaml-Framework.
Sie wählen das Flip-Präsentationsmodell aus, indem Sie den DXGI _ SWAP EFFECT FLIP _ _ _ SEQUENTIAL-Enumerationswert im SwapEffect-Member der DXGI SWAP CHAIN _ _ _ DESC1-Struktur angeben und das BufferCount-Member von DXGI SWAP CHAIN _ _ _ DESC1 auf mindestens 2 festlegen. Weitere Informationen zur Verwendung des DXGI-Flip-Modells finden Sie unter DXGI-Flip-Modell. Aufgrund der reibungsloseren Darstellung des Flip-Präsentationsmodells und anderer neuer Funktionen wird empfohlen, das Flip-Präsentationsmodell für alle neuen Apps zu verwenden, die Sie mit Direct3D 10- und höher-APIs schreiben.
Verwenden von dirty rectangles und dem Scrollrechteck in der Darstellung der Austauschkette
Durch die Verwendung von dirty rectangles und dem Bildlaufrechteck bei der Darstellung der Swapkette sparen Sie bei der Nutzung der Speicherbandbreite und der damit verbundenen Nutzung der Systemleistung, da die Menge an Pixeldaten, die das Betriebssystem zum Zeichnen des nächsten dargestellten Frames benötigt, reduziert wird, wenn das Betriebssystem nicht den gesamten Frame zeichnen muss. Bei Apps, die häufig über Remotedesktopverbindung und andere Technologien für den Remotezugriff angezeigt werden, sind die Einsparungen besonders in der Anzeigequalität spürbar, da diese Technologien dirty Rechtecke und Bildlaufmetadaten verwenden.
Sie können Scrollen nur mit DXGI-Swapketten verwenden, die im Flip-Präsentationsmodell ausgeführt werden. Sie können dirty rectangles mit DXGI-Swapketten verwenden, die sowohl im Flip-Modell als auch im bitblt-Modell ausgeführt werden (festgelegt mit DXGI _ SWAP EFFECT _ _ SEQUENTIAL).
In diesem Szenario und in dieser Abbildung wird die Funktionalität der Verwendung von dirty rectangles und scroll veranschaulicht. Hier enthält eine scrollbare App Text und animationsvideo. Die App verwendet geänderte Rechtecke, um nur das animierende Video und die neue Zeile für das Fenster zu aktualisieren, anstatt das gesamte Fenster zu aktualisieren. Mit dem Bildlaufrechteck kann das Betriebssystem den zuvor gerenderten Inhalt auf dem neuen Frame kopieren und übersetzen und nur die neue Zeile im neuen Frame rendern.
Die App führt die Präsentation durch Aufrufen der IDXGISwapChain1::P resent1-Methode aus. In diesem Aufruf übergibt die App einen Zeiger auf eine DXGI _ PRESENT _ PARAMETERS-Struktur, die dirty Rectangles und die Anzahl der dirty Rectangles enthält, oder das Bildlaufrechteck und den zugeordneten Bildlaufoffset oder beide dirty Rechtecke und das Bildlaufrechteck. Unsere App übergibt zwei dirty rectangles und das Scrollrechteck. Das Bildlaufrechteck ist der Bereich des vorherigen Frames, den das Betriebssystem in den aktuellen Frame kopieren muss, bevor er den aktuellen Frame rendert. Die App gibt das animierende Video und die neue Linie als dirty rectangles an, und das Betriebssystem rendert sie im aktuellen Frame.

DirtyRectsCount = 2
pDirtyRects[ 0 ] = { 10, 30, 40, 50 } // Video
pDirtyRects[ 1 ] = { 0, 70, 50, 80 } // New line
*pScrollRect = { 0, 0, 50, 70 }
*pScrollOffset = { 0, -10 }
Das gestrichelte Rechteck zeigt das Bildlaufrechteck im aktuellen Rahmen an. Das Bildlaufrechteck wird vom pScrollRect-Member von DXGI _ PRESENT PARAMETERS _ angegeben. Der Pfeil zeigt den Bildlaufoffset an. Der Bildlaufoffset wird vom pScrollOffset-Member von DXGI _ PRESENT PARAMETERS _ angegeben. Gefüllte Rechtecke zeigen geänderte Rechtecke an, die die App mit neuem Inhalt aktualisiert hat. Die ausgefüllten Rechtecke werden von den Membern DirtyRectsCount und pDirtyRects von DXGI PRESENT PARAMETERS _ _ angegeben.
Beispiel für eine 2-Puffer-Flip-Model-Austauschkette mit dirty rectangles und scroll rectangle
Die nächste Abbildung und Sequenz zeigt ein Beispiel für einen DXGI-Flip-Modell-Präsentationsvorgang, bei dem dirty Rechtecke und ein Bildlaufrechteck verwendet werden. In diesem Beispiel verwenden wir die Mindestanzahl von Puffern für die Darstellung des Flipmodells. Dies ist eine Pufferanzahl von zwei, ein Frontpuffer, der den Inhalt der App-Anzeige enthält, und ein Hintergrundpuffer, der den aktuellen Frame enthält, den die App rendern möchte.
- Wie im Frontpuffer am Anfang des Frames gezeigt, zeigt die scrollbare App zunächst einen Frame mit Text und animierendem Video an.
- Um den nächsten Frame zu rendern, rendert die App auf dem Hintergrundpuffer die geänderten Rechtecke, die das animierende Video und die neue Linie für das Fenster aktualisieren.
- Wenn die App IDXGISwapChain1::P resent1 aufruft,gibt sie die dirty rectangles sowie das Bildlaufrechteck und den Offset an. Die Laufzeit kopiert als Nächstes das Bildlaufrechteck aus dem vorherigen Frame abzüglich der aktualisierten geänderten Rechtecke in den aktuellen Hintergrundpuffer.
- Die Runtime tauscht schließlich die Front- und Backpuffer aus.

Nachverfolgen von dirty rectangles und scroll rectangles across multiple frames (Nachverfolgen von dirty rectangles und scroll rectangles über mehrere Frames hinweg)
Wenn Sie in Ihrer App dirty rectangles verwenden, müssen Sie die geänderten Rechtecke nachverfolgen, um inkrementelles Rendering zu unterstützen. Wenn Ihre App IDXGISwapChain1::P resent1 mit dirty rectangles aufruft, müssen Sie sicherstellen, dass jedes Pixel innerhalb der dirty rectangles auf dem neuesten Stand ist. Wenn Sie den gesamten Bereich des veredigten Rechtecks nicht vollständig wieder rendern oder bestimmte Bereiche nicht kennen, müssen Sie einige Daten aus dem vorherigen vollständig einheitlichen Backpuffer in den aktuellen, veralteten Zurückpuffer kopieren, bevor Sie mit dem Rendern beginnen.
Die Runtime kopiert nur die Unterschiede zwischen aktualisierten Bereichen des vorherigen Frames und aktualisierten Bereichen des aktuellen Frames in den aktuellen Hintergrundpuffer. Wenn sich diese Bereiche überschneiden, kopiert die Laufzeit nur den Unterschied zwischen ihnen. Wie Sie im folgenden Diagramm und in der folgenden Sequenz sehen können, müssen Sie die Schnittmenge zwischen dem dirty-Rechteck aus Frame 1 und dem dirty-Rechteck aus Frame 2 in das dirty-Rechteck von Frame 2 kopieren.
- Stellen Sie ein dirty rectangle in Frame 1 vor.
- Kopieren Sie die Schnittmenge zwischen dem dirty-Rechteck aus Frame 1 und dem dirty-Rechteck aus Frame 2 in das dirty-Rechteck von Frame 2.
- Stellen Sie ein dirty rectangle in Frame 2 vor.

Für eine Swapkette mit N Puffern ist der Bereich, den die Laufzeit vom letzten Frame in den aktuellen Frame auf dem aktuellen Frame kopiert, um zu generalisieren:

Wobei buffer den Pufferindex in einer Swapkette angibt, beginnend mit dem aktuellen Pufferindex bei 0 (null).
Sie können alle Schnittpunkte zwischen dem vorherigen Frame und den dirty Rectangles des aktuellen Frames nachverfolgen, indem Sie eine Kopie der dirty Rectangles des vorherigen Rahmens behalten oder die dirty Rectangles des neuen Frames mit dem entsprechenden Inhalt aus dem vorherigen Frame erneut rendern.
Ebenso müssen Sie in Fällen, in denen die Swapkette mehr als 2 Hintergrundpuffer enthält, sicherstellen, dass überlappende Bereiche zwischen den dirty-Rechtecke des aktuellen Puffers und den dirty-Rechtecke aller vorherigen Rahmen kopiert oder erneut gerendert werden.
Nachverfolgen einer einzelnen Schnittmenge zwischen zwei dirty rectangles
Im einfachsten Fall können sich die geänderten Rechtecke über zwei Frames überschneiden, wenn Sie ein einzelnes geändertes Rechteck pro Frame aktualisieren. Um herauszufinden, ob sich das dirty-Rechteck des vorherigen Frames und das dirty-Rechteck des aktuellen Rahmens überlappen, müssen Sie überprüfen, ob sich das dirty-Rechteck des vorherigen Frames mit dem dirty-Rechteck des aktuellen Rahmens überschneidet. Sie können die GDI IntersectRect-Funktion aufrufen, um zu bestimmen, ob sich zwei RECT-Strukturen überschneiden, die die beiden dirty rectangles darstellen.
In diesem Codeausschnitt gibt ein Aufruf von IntersectRect die Schnittmenge von zwei dirty rectangles in einem anderen RECT namens dirtyRectCopy zurück. Nachdem der Codeausschnitt ermittelt hat, dass sich die beiden dirty rectangles überschneiden, ruft er die ID3D11DeviceContext1::CopySubresourceRegion1-Methode auf, um den Schnittpunktbereich in den aktuellen Frame zu kopieren.
RECT dirtyRectPrev, dirtyRectCurrent, dirtyRectCopy;
if (IntersectRect( &dirtyRectCopy, &dirtyRectPrev, &dirtyRectCurrent ))
{
D3D11_BOX intersectBox;
intersectBox.left = dirtyRectCopy.left;
intersectBox.top = dirtyRectCopy.top;
intersectBox.front = 0;
intersectBox.right = dirtyRectCopy.right;
intersectBox.bottom = dirtyRectCopy.bottom;
intersectBox.back = 1;
d3dContext->CopySubresourceRegion1(pBackbuffer,
0,
0,
0,
0,
pPrevBackbuffer,
0,
&intersectBox,
0
);
}
// Render additional content to the current pBackbuffer and call Present1.
Wenn Sie diesen Codeausschnitt in Ihrer Anwendung verwenden, kann die App IDXGISwapChain1::P resent1 aufrufen, um den aktuellen Frame mit dem aktuellen geänderten Rechteck zu aktualisieren.
Nachverfolgen von Schnittmengen zwischen N dirty rectangles
Wenn Sie mehrere dirty rectangles angeben, die ein dirty rectangle für die neu angezeigte Bildlauflinie pro Frame enthalten können, müssen Sie alle Überlappungen überprüfen und nachverfolgen, die zwischen allen dirty Rectangles des vorherigen Rahmens und allen dirty Rectangles des aktuellen Rahmens auftreten können. Um die Schnittmengen zwischen den dirty rectangles des vorherigen Rahmens und den dirty rectangles des aktuellen Rahmens zu berechnen, können Sie die dirty rectangles in Bereiche gruppiert werden.
In diesem Codeausschnitt rufen wir die GDI-Funktion SetRectRgn auf, um jedes dirty Rechteck in einen rechteckigen Bereich zu konvertieren, und rufen dann die GDI CombineRgn-Funktion auf, um alle dirty rechteckigen Bereiche in einer Gruppe zu kombinieren.
HRGN hDirtyRgnPrev, hDirtyRgnCurrent, hRectRgn; // Handles to regions
// Save all the dirty rectangles from the previous frame.
RECT dirtyRect[N]; // N is the number of dirty rectangles in current frame, which includes newly scrolled area.
int iReturn;
SetRectRgn(hDirtyRgnCurrent,
dirtyRect[0].left,
dirtyRect[0].top,
dirtyRect[0].right,
dirtyRect[0].bottom
);
for (int i = 1; i<N; i++)
{
SetRectRgn(hRectRgn,
dirtyRect[0].left,
dirtyRect[0].top,
dirtyRect[0].right,
dirtyRect[0].bottom
);
iReturn = CombineRgn(hDirtyRgnCurrent,
hDirtyRgnCurrent,
hRectRgn,
RGN_OR
);
// Handle the error that CombineRgn returns for iReturn.
}
Sie können jetzt die GDI CombineRgn-Funktion verwenden, um die Schnittmenge zwischen dem dirty-Bereich des vorherigen Frames und dem dirty-Bereich des aktuellen Frames zu bestimmen. Nachdem Sie den überschneidenden Bereich erhalten haben, rufen Sie die GDI-Funktion GetRegionData auf, um jedes einzelne Rechteck aus dem sich überschneidenden Bereich zu erhalten, und rufen Sie dann die ID3D11DeviceContext1::CopySubresourceRegion1-Methode auf, um jedes sich überschneidende Rechteck in den aktuellen Hintergrundpuffer zu kopieren. Der nächste Codeausschnitt zeigt, wie diese GDI- und Direct3D-Funktionen verwendet werden.
HRGN hIntersectRgn;
bool bRegionsIntersect;
iReturn = CombineRgn(hIntersectRgn, hDirtyRgnCurrent, hDirtyRgnPrev, RGN_AND);
if (iReturn == ERROR)
{
// Handle error.
}
else if(iReturn == NULLREGION)
{
bRegionsIntersect = false;
}
else
{
bRegionsIntersect = true;
}
if (bRegionsIntersect)
{
int rgnDataSize = GetRegionData(hIntersectRgn, 0, NULL);
if (rgnDataSize)
{
char pMem[] = new char[size];
RGNDATA* pRgnData = reinterpret_cast<RGNDATA*>(pMem);
iReturn = GetRegionData(hIntersectRgn, rgnDataSize, pRgnData);
// Handle iReturn failure.
for (int rectcount = 0; rectcount < pRgnData->rdh.nCount; ++r)
{
const RECT* pIntersectRect = reinterpret_cast<RECT*>(pRgnData->Buffer) +
rectcount;
D3D11_BOX intersectBox;
intersectBox.left = pIntersectRect->left;
intersectBox.top = pIntersectRect->top;
intersectBox.front = 0;
intersectBox.right = pIntersectRect->right;
intersectBox.bottom = pIntersectRect->bottom;
intersectBox.back = 1;
d3dContext->CopySubresourceRegion1(pBackbuffer,
0,
0,
0,
0,
pPrevBackbuffer,
0,
&intersectBox,
0
);
}
delete [] pMem;
}
}
Bitblt-Modell-Austauschkette mit dirty rectangles
Sie können dirty rectangles mit DXGI-Swapketten verwenden, die im bitblt-Modell ausgeführt werden (festgelegt mit DXGI _ SWAP EFFECT _ _ SEQUENTIAL). Bitblt-Modelltauschketten, die mehr als einen Puffer verwenden, müssen auch überlappende dirty Rechtecke über Frames hinweg auf die gleiche Weise nachverfolgen, wie unter Nachverfolgen von dirty rectangles und scroll rectangles across multiple frames for flip model swap chains (Nachverfolgen von dirty rectangles und scroll rectangles across multiple frames for flip model swap chains) beschrieben. Bitblt-Modelltauschketten mit nur einem Puffer müssen keine überlappenden dirty rectangles nachverfolgen, da der gesamte Puffer in jedem Frame neu gezeichnet wird.