Frage zu Direct3D11



  • Hallo,

    wenn ich mein Programm im Debug-Modus laufen lasse, bekomme ich von Direct3D11 immer diese Warnungen hier:

    D3D11: WARNING: Live Device: Name="unnamed", Addr=0x004784B0, ExtRef=1 [ STATE_CREATION WARNING #2097297: LIVE_DEVICE ]
    D3D11: WARNING: Live Texture2D: Name="unnamed", Addr=0x0047C594, ExtRef=0, IntRef=1 [ STATE_CREATION WARNING #2097235: LIVE_TEXTURE2D ]
    D3D11: WARNING: Live RenderTargetView: Name="unnamed", Addr=0x0047C27C, ExtRef=1, IntRef=0 [ STATE_CREATION WARNING #2097244: LIVE_RENDERTARGETVIEW ]
    D3D11: WARNING: Live Texture2D: Name="unnamed", Addr=0x0047BFBC, ExtRef=0, IntRef=1 [ STATE_CREATION WARNING #2097235: LIVE_TEXTURE2D ]
    D3D11: WARNING: Live Query: Name="unnamed", Addr=0x02B7B1DC, ExtRef=0, IntRef=1 [ STATE_CREATION WARNING #2097280: LIVE_QUERY ]
    D3D11: WARNING: Live Sampler: Name="unnamed", Addr=0x02B7B02C, ExtRef=0, IntRef=1 [ STATE_CREATION WARNING #2097268: LIVE_SAMPLER ]
    D3D11: WARNING: Live RasterizerState: Name="unnamed", Addr=0x02B7AE9C, ExtRef=0, IntRef=1 [ STATE_CREATION WARNING #2097277: LIVE_RASTERIZERSTATE ]
    D3D11: WARNING: Live DepthStencilState: Name="unnamed", Addr=0x02B7AD6C, ExtRef=0, IntRef=1 [ STATE_CREATION WARNING #2097274: LIVE_DEPTHSTENCILSTATE ]
    D3D11: WARNING: Live BlendState: Name="unnamed", Addr=0x02B7ABDC, ExtRef=0, IntRef=1 [ STATE_CREATION WARNING #2097271: LIVE_BLENDSTATE ]
    D3D11: WARNING: Live Context: Name="unnamed", Addr=0x02B7006C, ExtRef=0, IntRef=1 [ STATE_CREATION WARNING #2097226: LIVE_CONTEXT ]
    D3D11: WARNING: Live Device Child Summary: Device Addr=0x004784B0
    Using ID3D11Debug::ReportLiveDeviceObjects with D3D11_RLDO_DETAIL will help drill into object lifetimes. Objects with ExtRef=0 and IntRef=0 will be eventually destroyed through typical Immediate Context usage. However, if the application requires these objects to be destroyed sooner, ClearState followed by Flush on the Immediate Context will realize their destruction.
    Live              Context:      1
    Live               Buffer:      0
    Live            Texture1D:      0
    Live            Texture2D:      2
    Live            Texture3D:      0
    Live   ShaderResourceView:      0
    Live     RenderTargetView:      1
    Live     DepthStencilView:      0
    Live         VertexShader:      0
    Live       GeometryShader:      0
    Live          PixelShader:      0
    Live          InputLayout:      0
    Live              Sampler:      1
    Live           BlendState:      1
    Live    DepthStencilState:      1
    Live      RasterizerState:      1
    Live                Query:      1
    Live            Predicate:      0
    Live              Counter:      0
    Live          CommandList:      0
    Live           HullShader:      0
    Live         DomainShader:      0
    Live        ClassInstance:      0
    Live         ClassLinkage:      0
    Live        ComputeShader:      0
    Live  UnorderedAccessView:      0
     [ STATE_CREATION WARNING #2097298: LIVE_OBJECT_SUMMARY ]
    

    Soweit ich das verstehen kann, heißt das, dass noch ein paar Objekte nicht zerstört wurden. Dabei release ich alles, wovon ich einen Pointer habe, in diesem Fall nur Context, Device und Swapchain. Wie kann ich nun also auch die Objekte, von denen ich keinen Pointer habe zerstören?
    Und wieso muss man eigentlich alles releasen, wenn man für C++ doch Destruktoren hätte einbauen können?



  • dann kapsel das doch mit z.b. shared_ptr
    der bietet ja auch an eine funktion zum "zerstören" im destruktor aufzurufen



  • Du hast mein Problem nicht verstanden. Die Objekte die da noch Leben, wurden irgendwie intern erzeugt, von denen hab ich gar kein Pointer. Wie krieg ich das interne Zeug dennoch zerstört?



  • Fragerorius schrieb:

    Soweit ich das verstehen kann, heißt das, dass noch ein paar Objekte nicht zerstört wurden.

    exakt.

    Fragerorius schrieb:

    Dabei release ich alles [...]

    Direct3D sieht das offenbar anders.

    Fragerorius schrieb:

    Wie kann ich nun also auch die Objekte, von denen ich keinen Pointer habe zerstören?

    Gar nicht. Wenn dir die Pointer fehlen solltest du rausfinden wo genau du sie verloren hast.

    Ich vermute mal du fragst z.B. die BackBuffer Textur der SwapChain ab und verwendest irgendwelche State-Objekte ohne sie wieder zu releasen.

    Fragerorius schrieb:

    Und wieso muss man eigentlich alles releasen, wenn man für C++ doch Destruktoren hätte einbauen können?

    Direct3D basiert auf COM, das ist unabhängig von C++. Abgesehen davon musst du auch in C++ dafür sorgen dass Objekte die mit new angelegt wurde wieder deleted werden. Außerdem hindert dich ja niemand dran RAII zu benutzen. COM Objekte wie die von Direct3D eignen sich naturgemäß sogar besonders toll dafür...



  • dot schrieb:

    Gar nicht. Wenn dir die Pointer fehlen solltest du rausfinden wo genau du sie verloren hast.

    Live              Sampler:      1
    Live           BlendState:      1
    Live    DepthStencilState:      1
    Live      RasterizerState:      1
    Live                Query:      1
    

    Die fünf Elemente habe ich gar nicht erst angerührt. Das steht exakt gar nichts von meinem Code, der auch nicht viel mehr macht als einen Device zu erzeugen.

    Direct3D basiert auf COM, das ist unabhängig von C++. Abgesehen davon musst du auch in C++ dafür sorgen dass Objekte die mit new angelegt wurde wieder deleted werden. Außerdem hindert dich ja niemand dran RAII zu benutzen. COM Objekte wie die von Direct3D eignen sich naturgemäß sogar besonders toll dafür...

    Nun einen shared_ptr habe ich schon ausprobiert, jedoch gibt es da Konvertierungsprobleme, wenn eine Funktionen einen Pointer darauf nimmt, weswegen er nicht wirklich dafür geeignet ist. Gibts da noch ein paar Tricks, oder muss ich da wirklich meinen eigenen Smartointer schreiben?



  • Fragerorius schrieb:

    Die fünf Elemente habe ich gar nicht erst angerührt.

    Nun gut, aber du hast zwangsweise die BackBuffer-Texture angerührt und ein RenderTargetView dafür erzeugt. Der Rest hängt vielleicht damit zusammen.

    Fragerorius schrieb:

    Gibts da noch ein paar Tricks, oder muss ich da wirklich meinen eigenen Smartointer schreiben?

    http://msdn.microsoft.com/en-us/library/ezzw7k98.aspx
    http://msdn.microsoft.com/en-us/library/417w8b3b.aspx

    #ifndef COMPTR_INCLUDED
    #define COMPTR_INCLUDED
    
    #pragma once
    
    template <class T>
    class com_ptr
    {
    private:
      T* ptr;
    
      static void release(T* ptr)
      {
        if (ptr)
          ptr->Release();
      }
    
      static void acquire(T* ptr)
      {
        if (ptr)
          ptr->AddRef();
      }
    
    public:
      com_ptr(T* ptr = nullptr)
        : ptr(ptr)
      {
      }
    
      com_ptr(const com_ptr& p)
        : ptr(p.ptr)
      {
        acquire(ptr);
      }
    
      com_ptr(com_ptr&& p)
        : ptr(p.ptr)
      {
        p.ptr = nullptr;
      }
    
      ~com_ptr()
      {
        release(ptr);
      }
    
      com_ptr& operator =(const com_ptr& p)
      {
        acquire(p.ptr);
        release(ptr);
        ptr = p.ptr;
        return *this;
      }
    
      com_ptr& operator =(com_ptr&& p)
      {
        std::swap(ptr, p.ptr);
        return *this;
      }
    
      void release()
      {
        release(ptr);
        ptr = nullptr;
      }
    
      T* operator ->() const { return ptr; }
    
      operator T*() const { return ptr; }
    
      T** operator &() { return &ptr; }
    
    };
    
    #endif  // COMPTR_INCLUDED
    


  • Danke für deine Implementierung der Smartpointers, hat mir wirklich sehr geholfen. Jedoch habe ich ein Problem mit der Swapchain, alle com_ptr werden vernünftig released, nur bei der Swapchain bekomme ich eine Zugriffverletzung, beim releasen, der Pointer ist dabei kein nullptr. Wenn ich nur aus der Swapchain wieder einen normalen Pointer mache, funktioniert mein Programm einwandfrei, woran liegt das?



  • Kann es sein dass die SwapChain irgendwie doppelt released wird? Initialisierst du irgendwo zwei com_ptr mit dem selben IDXGISwapChain*? Denn wenn du einmal einen com_ptr auf ein Objekt erstellt hast solltest du alle weiteren com_ptr auf das selbe Objekt erzeugen indem du den ersten com_ptr kopierst und nicht einen weiteren com_ptr mit dem selben IIrgendwas* erzeugen da der entsprechende Konstruktor kein AddRef() aufruft. Dann passiert nämlich genau dass einmal zu oft Release() aufgerufen wird.



  • Ah ja, ich hab irgendwo versteckt, noch vergessen eine Release zu löschen 🙄
    Nun habe ich aber alles mit com_ptr gemacht, jedoch sagt mir der Debugger immer noch, dass viele Sachen nicht released wurden. Die Liste ist sogar unverändert geblieben....



  • Zeig vielleicht mal deinen Code her...



  • Hier die Funktion (auf Direct3D gekürzt) die alles erstellt.
    Mit dem Device der zurückgegeben wird, wird bis auf initialisieren, überhaupt nichts gemacht.

    struct Device {
    	Device(com_ptr<IDXGISwapChain> swapchain_, com_ptr<ID3D11Device> dev_, com_ptr<ID3D11DeviceContext> devcon_) :
    		swapchain(swapchain_), dev(dev_), devcon(devcon_), running(running_) {};
    	com_ptr<IDXGISwapChain> swapchain;
    	com_ptr<ID3D11Device> dev;
    	com_ptr<ID3D11DeviceContext> devcon;
    };
    
    Device CreateDevice {
        com_ptr<IDXGISwapChain> swapchain;
    	com_ptr<ID3D11Device> dev;
    	com_ptr<ID3D11DeviceContext> devcon;
    
    	DXGI_SWAP_CHAIN_DESC sd;
    	std::memset(&sd, 0, sizeof(sd));
    	sd.BufferCount = 1;
    	sd.BufferDesc.Width = width;
    	sd.BufferDesc.Height = height;
    	sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    	sd.BufferDesc.RefreshRate.Numerator = 60;
    	sd.BufferDesc.RefreshRate.Denominator = 1;
    	sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    	sd.OutputWindow = hWnd;
    	sd.SampleDesc.Count = 8;
    	sd.SampleDesc.Quality = 0;
    	sd.Windowed = true;
    
    	D3D_FEATURE_LEVEL featureLevels[] = {
    		D3D_FEATURE_LEVEL_11_0,
    		D3D_FEATURE_LEVEL_10_1,
    		D3D_FEATURE_LEVEL_10_0,
    	};
    	UINT flags = 0;
    #ifdef DEBUG
    	flags |= D3D11_CREATE_DEVICE_DEBUG;
    #endif
    
    	if(FAILED(D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, flags, featureLevels, ARRAYSIZE(featureLevels), D3D11_SDK_VERSION, &sd, &swapchain, &dev, nullptr, &devcon))) {
    		err << "Can't create Direct3D11 device or swapchain" << endl;
    		return failDevice;
    	}
    
    	// Create a render target view
    	com_ptr<ID3D11Texture2D> backBuffer;
    	if(FAILED(swapchain->GetBuffer( 0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&backBuffer)))) {
    		err << "Can't get the BackBuffer" << endl;
    		return failDevice;
    	}
    
    	HRESULT hr = dev->CreateRenderTargetView(backBuffer, nullptr, &targetView );
    	backBuffer->Release();
    	if(FAILED(hr)) {
    		err << "Can't create RenderTargetView" << endl;
    		return failDevice;
    	}
    	devcon->OMSetRenderTargets(1, &targetView, nullptr);
    
    	D3D11_VIEWPORT vp;
    	vp.Width = static_cast<float>(width);
    	vp.Height = static_cast<float>(height);
    	vp.MinDepth = 0.0f;
    	vp.MaxDepth = 1.0f;
    	vp.TopLeftX = 0;
    	vp.TopLeftY = 0;
    	devcon->RSSetViewports(1, &vp);
    
        return Device(swapchain, dev, devcon);
    }
    


  • Warum backBuffer->Release();?
    Ist targetView auch ein com_ptr?



  • Hab jetzt mal mit Suchen und ersetzen alle Release() weggemacht.
    targetView ist zum testen eine globale Variable, aber auch ein com_ptr.



  • Fragerorius schrieb:

    targetView ist zum testen eine globale Variable, aber auch ein com_ptr.

    Naja, dann ist klar. Der Destruktor von targetView wird erst aufgerufen nachdem der Device schon freigegeben wurde. targetView ist ein RenderTargetView und hält daher intern noch eine Referenz auf weitere Dinge, wie z.B. den BackBuffer...


Anmelden zum Antworten