Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

23.05.2015, 19:04

DirectX 11 Offscreen Rendering in Memory

Hallo,

ich habe von Render to Texture gelesen bei dem man mit einem zweiten Buffer, eine Texture als Renderziel nimmt.
Für diese Texture habe ich aber keine Verwendung, das gerenderte Bild soll auf dem Computer nie angezeigt werden.

Mein derzeitiger Aufbau ist: D3D11CreateDeviceAndSwapChain -> CreateRenderTargetView -> OMSetRenderTargets -> RSSetViewports -> Present

In Zukunft möchte ich ohne SwapChain arbeiten, nur mit D3D11CreateDevice und D3D11CreateDevice::Flip.


Im Grunde möchte ich das gerenderte Bild aus dem Videospeicher in den Arbeitsspeicher kopieren und von dort aus asynchron auslesen, das Ganze so schnell wie möglich.



Habt ihr Ideen oder Vorschläge wie ich das Ganze angehen sollte, an welcher Stelle ich z.b. das Bild "abgreifen" sollte ?


MFG

Legend

Alter Hase

Beiträge: 731

Beruf: Softwareentwickler

  • Private Nachricht senden

2

23.05.2015, 21:12

Ich bin etwas verwirrt. Was willst du erreichen? Was renderst du denn für Daten in die Textur die du abgreifen willst?
"Wir müssen uns auf unsere Kernkompetenzen konzentrieren!" - "Juhu, wir machen eine Farm auf!"

Netzwerkbibliothek von mir, C#, LGPL: https://sourceforge.net/projects/statetransmitt/

TrommlBomml

Community-Fossil

Beiträge: 2 117

Wohnort: Berlin

Beruf: Software-Entwickler

  • Private Nachricht senden

3

23.05.2015, 21:37

Du kannst das Bild natürlich nach dem Rendern ganz normal aus dem Output Merger nehmen und dir einfach nach jedem Bildaufbau die Daten in den RAM kopieren. Dazu musst du aber ein RenderTarget erzeugen, was du auch auf der CPU lesen kannst, musst also ein eigenes Erzeugen. Dann kannst du das ganze wieder von der Grafikkarte lesen, klar.

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

4

23.05.2015, 22:21

Im Grund funktioniert das wie jeder CPU-readback. Du erzeugst eine Textur (D3D11_USAGE_DEFAULT, D3D11_BIND_RENDER_TARGET) und setzt diese als Rendertarget. Außerdem brauchst du eine passende Stagingtextur fürs zurücklesen (D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_READ). Dann kannst du mit CopyResource/CopySubresourceRegion den Inhalt zurück in den Systemspeicher kopieren. Die Stagingtextur kannst du mappen und auslesen.

Um die CPU nicht zu 'stallen' solltest du einen Ring von Stagingtexturen verwenden (z.B. 3 oder 4) und jeden Frame eine neue Textur als Ziel angeben. Beim zurücklesen kannst du entsprechend D3D11_MAP_FLAG_DO_NOT_WAIT angeben um zu testen ob die Textur schon zum auslesen bereit ist. Hier etwas Pseudocode um das Ganze zu verdeutlichen: (alles ungetestet ohne Gewähr auf Fehlerfreiheit! ;))

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// create readback ring
ID3D11Texture2D* m_ReadBackRing[MAX_READBACK_BUFFERS];

for (uint32 i = 0; i < MAX_READBACK_BUFFERS; ++i)
  m_ReadBackRing[i] = CreateStagingTexture(width, height, bpp, ...);

// copy frame to texture
if (RingBufferIsFull()) // wenn der ringpuffer voll ist, also writeindex = readindex
{
  context->Map(m_ReadBackRing[m_CurrentReadIndex], ..., 0, &mappedResource); // CPU stallen bis nächster slot frei wird
  resultReady = true;
}
else
{
  device->CopyResource(frameBuffer, m_ReadBackRing[m_CurrentWriteIndex]); // kopie vom framebuffer anstoßen

  m_CurrentWriteIndex = (m_CurrentWriteIndex + 1) % MAX_READBACK_BUFFERS;

  // readback
  resultReady = context->Map(m_ReadBackRing[m_CurrentReadIndex], ..., D3D11_MAP_FLAG_DO_NOT_WAIT, &mappedResource) != DXGI_ERROR_WAS_STILL_DRAWING;
}

if (resultReady)
{
  memcpy(dest, mappedResource.pData, size);

  m_CurrentReadIndex = (m_CurrentReadIndex + 1) % MAX_READBACK_BUFFERS;
}


Links:
Copying and Accessing Resource Data
@D13_Dreinig

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »David_pb« (23.05.2015, 22:35)


5

23.05.2015, 22:50

Ja das meinte ich mit dem Render to Texture, ich hatte das bereits ausprobiert und mit D3DX11SaveTextureToFile probeweise mal auf die HDD geschrieben.

Da war der Aufbau:
D3D11CreateDeviceAndSwapChain -> BackBuffer Texture erstellen -> CreateRenderTargetView basierend auf der BackBuffer Texture -> CaptureTexture erstellen -> mappen -> RSSetViewports -> Present

Meine Frage ist, ist das der schnellste Weg ? - So wie ich das verstehe wird zuerst in die BackBufferTexture gerendet und dann in die CaptureTexture kopiert und von dort in den Arbeitsspeicher kopiert.

Julién

Alter Hase

Beiträge: 717

Wohnort: Bayreuth

Beruf: Student | Hilfswissenschaftler in der Robotik

  • Private Nachricht senden

6

24.05.2015, 00:23

Gab es nicht einen alternativen Weg über das SwapChain? (P.S. unsicher)
I write my own game engines because if I'm going to live in buggy crappy filth, I want it to me my own - Ron Gilbert

Legend

Alter Hase

Beiträge: 731

Beruf: Softwareentwickler

  • Private Nachricht senden

7

24.05.2015, 09:57

Also um auf Daten aus einem Buffer (ganz egal welcher Art, also auch Texturen) auf die CPU zu kopieren muss man den Buffer mit CPUAccessFlags = D3D11_CPU_ACCESS_READ erstellen. Meiner Erfahrung nach schließt das praktisch jede andere Verwendung dieses Buffers aus! Daher wirst du um zwei Texturen, eine zum rendern, die anderen für den Zugriff durch die CPU nicht herum kommen.
"Wir müssen uns auf unsere Kernkompetenzen konzentrieren!" - "Juhu, wir machen eine Farm auf!"

Netzwerkbibliothek von mir, C#, LGPL: https://sourceforge.net/projects/statetransmitt/

8

24.05.2015, 16:03

Ich zeichne ein Rechteck, welches seine Farbe bei jedem Rendern ändert und erhalte folgende FPS Werte:


Start: ~13.000 FPS
+ "CopyResource": ~1.500 FPS
+ "D3DX11SaveTextureToFile": ~26 FPS

Letzteres kann ignoriert werden, da auf die HDD geschrieben wird.

Wie man sieht ist der FPS-Verlust von 13.000 auf 1.500 enorm.
Wenn ich das Programm ohne CopyResource ausführe und mit Open Broadcaster Software aufnehme ist der FPS-Verlust minimal.


Ich bin davon ausgegangen dass wenn ich das "Bild" so früh wie möglich abgreife, dass das die schnellste Methode wäre.
Vielleicht ist es besser das Bild am Ende abzugreifen, mit DirectShow oder so.

Sylence

Community-Fossil

Beiträge: 1 663

Beruf: Softwareentwickler

  • Private Nachricht senden

9

24.05.2015, 17:42

Wie man sieht ist der FPS-Verlust von 13.000 auf 1.500 enorm.


Und kann auch direkt ignoriert werden. Gerade bei so hohen Werten sind die FPS eine völlig ungeeignete Größe um irgendwas zu bestimmen ;)

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

10

24.05.2015, 20:04

Wenn ich das Programm ohne CopyResource ausführe und mit Open Broadcaster Software aufnehme ist der FPS-Verlust minimal.

Wie minimal denn? ;)

Werbeanzeige