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...