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

FSA

Community-Fossil

  • »FSA« ist der Autor dieses Themas
  • Private Nachricht senden

1

14.10.2013, 13:40

Probleme mit IUnknown Schnittstelle (DX11)

Hallo
Ich habe heute einen Bug in meinem Projekt gefunden, und weiß nicht so wirklich, wie ich ihn beheben kann. Es geht um Folgendes:
Ich lade zwei mal die selbe Textur, beziehungsweise ich lade sie einmal und erhöhe dann den Referenzzähler von ID3D11ShaderResourceView (erbt von IUnknown) mit AddRef(), wenn ich sie ein zweites mal laden möchte. Wenn ich mein Programm beende, werden automatisch alle Texturen gelöscht. Ich habe alles überprüft und keine Textur hat einen Referenzzähler größer 0 und keine Textur ist noch an die Pipeline gebunden. Komischerweise hängt sich mein Programm an der Stelle auf, wo ich versuche, das ID3D11Device zu löschen (->release()). Wenn ich die Stelle auskommentiere, die die Texturen löscht, oder zwei verschieden Texturen aus verschiedenen Dateien lade, klappt alles einwandfrei. Hat jemand eine Idee dazu?

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// gekürzt
Result TextureManager::DeleteAllTextures()
{
    NXETerminal::DebugWrite("DeleteAllTextures");

    for(int iEntry = 0; iEntry < m_iListSize; iEntry++)
    {
        if(m_pTextureList[iEntry].bExists && m_pTextureList[iEntry].pTextureRV)
        {
            while(m_pTextureList[iEntry].pTextureRV->Release() > 0)
            {
            }

            m_iNumTextures--;
        }
    }

    return NXE_OK;
}


Texturen von der Pipeline "löschen"

C-/C++-Quelltext

1
2
3
4
5
// m_pShaderTexture: ID3DX11EffectShaderResourceVariable*
if(m_pShaderTexture && m_pShaderTexture->IsValid())
    m_pShaderTexture->SetResource(NULL);

m_pShaderTexture = NULL;

Zitat

Der RCCSWU (RandomCamelCaseSomtimesWithUndersquare) Stil bricht auch mal mit den veraltet strukturierten Denkmustern und erlaubt dem Entwickler seine Kreativität zu entfalten.

TrommlBomml

Community-Fossil

Beiträge: 2 117

Wohnort: Berlin

Beruf: Software-Entwickler

  • Private Nachricht senden

2

14.10.2013, 14:07

Man muss soweit ich es weiß, sehr vorsichtig mit AddRef() und Release() umgehen. Bei Direct3D9 war es glaube auch so, dass explizit davon abgeraten wird, das zu tun. Warum wurde aber nicht begründet. Irgendwas ist auch ziemlich komisch, wenn ich mir Zeile 10 anschaue. Wenn du es richtig benutzen möchtest, müsste jedes objekt, welches AddRef() aufgruft, auch Release() aufrufen und nicht mit gieskanne beim Aufräumen. Dann brauchst du das reference counting auch gar nicht. Dann solltest du lieber nur die Pointer rausreichen, keinn AddRef() aufrufen und nur einmal Release aufrufen und dann die pointer nullen. So habe ich das immer gemacht. Dann sollte eigentlich kein Fehler mehr kommen. Ansonsten den code unten verstehe ich nicht, aber auch nur, weil ich kein DX11 kann. Was sagt denn das Control-Panel im Debug-Modus?

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

3

14.10.2013, 14:10

Kann es passieren, dass der Referenzzähler von m_pTextureList[iEntry] bereits vor dem ersten Release() in der Schleife 0 ist? Wenn du mich fragst, ist in deinem Programm aber sowieso gewaltig was faul, wenn du so eine Schleife überhaupt brauchst...

Legend

Alter Hase

Beiträge: 731

Beruf: Softwareentwickler

  • Private Nachricht senden

4

14.10.2013, 15:09

Da empfehlen sich wohl Smartpointer ...
"Wir müssen uns auf unsere Kernkompetenzen konzentrieren!" - "Juhu, wir machen eine Farm auf!"

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

FSA

Community-Fossil

  • »FSA« ist der Autor dieses Themas
  • Private Nachricht senden

5

14.10.2013, 15:33

Die Funktion DeleteAllTextures habe ich hier gepostet, da ich testweise alle manuellen Release-Aufrufe aus dem Quellcode herausgenommen habe. Wenn man alles richtig macht, löscht DeleteAllTextures nichts mehr.
@TrommlBomml: Ich führe eine interne Liste mit allen Texturen. Wenn eine Textur bekannt ist, wird sie nicht mehr geladen sonder nur noch ein Zeiger zurückgegeben und AddRef() aufgerufen. Wenn die Textur noch nicht bekannt ist, wird sie geladen und ebenfalls ein Zeiger auf sie zurückgegeben. Die Ausgabe sagt leider nichts.

Hier die Funktion, die eine einzelne Textur löscht:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Result TextureManager::ReleaseTexture(ShaderResourceView* pTextureRV)
{
    NXETerminal::DebugWrite("Release Texture");

    int iIndex;

    iIndex = GetTextureIndex(pTextureRV);
    if(iIndex == -1)
    {
        LOG_WARNING("Could not find texture");
        return NXE_NOT_FOUND;
    }

    if(m_pTextureList[iIndex].pTextureRV->Release() == 0)
    {
        ZeroMemory(&m_pTextureList[iIndex], sizeof(TextureListEntry));
        m_iNumTextures--;
    }

    return NXE_OK;
}


Zitat von »dot«


Kann es passieren, dass der Referenzzähler von m_pTextureList[iEntry] bereits vor dem ersten Release() in der Schleife 0 ist?

Nein.

Ich glaube ihr sucht an einem falschen Ort. Es geht lediglich darum, dass ich mein ID3D11Device nicht mehr löschen kann, wenn ich den selben Pointer auf eine Textur (bzw. ID3DX11EffectShaderResourceVariable) an zwei verschiedenen Orten auf die Pipeline binde. Vielleicht ist das auch schon der Fehler. Unter DirectX9 klappte es jedenfalls.

Zitat

Der RCCSWU (RandomCamelCaseSomtimesWithUndersquare) Stil bricht auch mal mit den veraltet strukturierten Denkmustern und erlaubt dem Entwickler seine Kreativität zu entfalten.

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

6

14.10.2013, 15:45

Wenn man alles richtig macht, löscht DeleteAllTextures nichts mehr.

Meinst du damit, dass m_pTextureList dann leer ist? Mit anderen Worten: Wenn m_pTextureList in DeleteAllTextures() nicht leer ist, ist irgendwo was schiefgelaufen!? In dem Fall würde ich empfehlen, statt der Schleife ein assert(m_pTextureList.empty()); zu installieren... ;)

Ich glaube ihr sucht an einem falschen Ort. Es geht lediglich darum, dass ich mein ID3D11Device nicht mehr löschen kann, wenn ich den selben Pointer auf eine Textur (bzw. ID3DX11EffectShaderResourceVariable) an zwei verschiedenen Orten auf die Pipeline binde.

Wieso bindest du die Variable an zwei verschiedene Orte und was genau für eine Ressource bindest du an genau welche Orte?

FSA

Community-Fossil

  • »FSA« ist der Autor dieses Themas
  • Private Nachricht senden

7

14.10.2013, 17:52

Zitat von »dot«

Meinst du damit, dass m_pTextureList dann leer ist? Mit anderen Worten: Wenn m_pTextureList in DeleteAllTextures() nicht leer ist, ist irgendwo was schiefgelaufen!? In dem Fall würde ich empfehlen, statt der Schleife ein assert(m_pTextureList.empty()); zu installieren... ;)

Ich habe oben als Kommentar geschrieben, dass der Code gekürzt ist. Die Schleife ist eine Sicherheit, dass auch wirklich alles weg kommt. Es ist natürlich ein Hinweis vorhanden.

Ich brauche die selbe Textur zweimal in unterschiedlichen Klassen und lade sie dadurch einmal und kopiere den Zeiger. Dann binde ich die Textur einmal in Klasse 1 und rendere und einmal in Klasse 2 und rendere. Es wäre sinnfrei dieselbe Textur zwei mal zu laden, wenn ich zwei Pointer auf sie haben kann.

Zitat

Der RCCSWU (RandomCamelCaseSomtimesWithUndersquare) Stil bricht auch mal mit den veraltet strukturierten Denkmustern und erlaubt dem Entwickler seine Kreativität zu entfalten.

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

8

14.10.2013, 18:25

Zitat von »dot«

Meinst du damit, dass m_pTextureList dann leer ist? Mit anderen Worten: Wenn m_pTextureList in DeleteAllTextures() nicht leer ist, ist irgendwo was schiefgelaufen!? In dem Fall würde ich empfehlen, statt der Schleife ein assert(m_pTextureList.empty()); zu installieren... ;)

Ich habe oben als Kommentar geschrieben, dass der Code gekürzt ist. Die Schleife ist eine Sicherheit, dass auch wirklich alles weg kommt.

Die Schleife ist also dazu da, Fehler im Programm auszugleichen. Der imo bessere Ansatz wäre, die Fehler im Ressourcenmanagement zu beheben, anstatt sie mit so einem Ansatz zu vertuschen. Denn das einzige, was deine momentane Lösung macht, ist, dafür zu sorgen, dass du möglichst nicht merkst, wenn wo was schiefläuft... ;)

Ich brauche die selbe Textur zweimal in unterschiedlichen Klassen und lade sie dadurch einmal und kopiere den Zeiger. Dann binde ich die Textur einmal in Klasse 1 und rendere und einmal in Klasse 2 und rendere. Es wäre sinnfrei dieselbe Textur zwei mal zu laden, wenn ich zwei Pointer auf sie haben kann.

Du hast also zwei unterschiedliche Klassen, die die gleiche Texture verwenden. Die Frage ist nun: Müssen wirklich beide Klassen die Textur auch besitzen? Und falls ja: Wie ist dafür gesorgt, dass die Textur auch freigegeben wird? Ich nehme an, diese beiden Klassen versuchen, diese Textur an unterschiedliche Punkte zu binden!? Gleichzeitig? Was genau sind das für Punkte? Was genau ist das für eine Textur? Was genau wird damit gemacht?

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »dot« (14.10.2013, 18:33)


TrommlBomml

Community-Fossil

Beiträge: 2 117

Wohnort: Berlin

Beruf: Software-Entwickler

  • Private Nachricht senden

9

14.10.2013, 18:27

Das meine ich auch mit meinem initialem Post. In deinem Ressourcenmanagement ist einiges schräg. Das kann schon die ursache für solche Seiteneffekte sein.

FSA

Community-Fossil

  • »FSA« ist der Autor dieses Themas
  • Private Nachricht senden

10

14.10.2013, 19:06

@dot: Ich schreibe Allokationen und Laden von Texturen immer mit. Wenn vergessen wird etwas zu löschen, wird eine Warnung ausgegeben, in welcher die Zeile und Datei der Erstellung angezeigt wird.
@TB: Nein das kann nicht die Ursache sein, da das manuelle Löschen ebenfalls nicht funktioniert. Mein Ressourcenmanagement ist nicht mit diesen beiden Funktionen zu verallgemeinern.

Zitat von »dot«


Müssen wirklich beide Klassen die Textur auch besitzen?

Ja.

Zitat von »dot«


Wie ist dafür gesorgt, dass die Textur auch freigegeben wird?

Wann genau? Beim Beenden des Programms durch meinen Quellcode bzw. mein Aufruf von ReleaseTexture();

Zitat von »dot«


Ich nehme an, diese beiden Klassen versuchen, diese Textur an unterschiedliche Punkte zu binden!?

Ja.

Zitat von »dot«


Gleichzeitig? [...] Was genau wird damit gemacht?

Nein. Vgl mein vorherigen Post:

Zitat von »FSA«


Dann binde ich die Textur einmal in Klasse 1 und rendere und einmal in Klasse 2 und rendere.


Zitat von »dot«


Was genau sind das für Punkte?

Du meinst, wann ich was binde? In der Render funktion der jeweiligen Klasse vor dem Draw aufruf mit m_pShaderTexture->SetResource(m_pTexture); wobei m_pShaderTexture vom Typ ID3DX11EffectShaderResourceVariable* und m_pTexture der Zeiger auf die Textur ist (ID3D11ShaderResourceView*)

Zitat von »dot«


Was genau ist das für eine Textur?

Eine Textur, die aus mehreren Bildern zusammengesetzt ist. Typ png 24 Bit pro Kanal.

Zitat

Der RCCSWU (RandomCamelCaseSomtimesWithUndersquare) Stil bricht auch mal mit den veraltet strukturierten Denkmustern und erlaubt dem Entwickler seine Kreativität zu entfalten.

Werbeanzeige