Skip to content

Commit 25ba277

Browse files
committed
fix: memory leak in d3d texture interop
1 parent e544757 commit 25ba277

File tree

3 files changed

+66
-29
lines changed

3 files changed

+66
-29
lines changed

src/accelerator/d3d/d3d_texture2d.cpp

Lines changed: 55 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
#include <GL/wglew.h>
77
#include <atlcomcli.h>
88

9+
#include "../ogl/util/device.h"
10+
911
namespace caspar { namespace accelerator { namespace d3d {
12+
1013
d3d_texture2d::d3d_texture2d(ID3D11Texture2D* tex)
11-
: texture_(std::shared_ptr<ID3D11Texture2D>(tex, [](ID3D11Texture2D* p) {
12-
if (p)
13-
p->Release();
14-
}))
14+
: texture_(tex)
1515
{
1616
share_handle_ = nullptr;
1717

@@ -26,46 +26,81 @@ d3d_texture2d::d3d_texture2d(ID3D11Texture2D* tex)
2626
}
2727

2828
{
29-
CComQIPtr<IDXGIResource1> res = texture_.get();
29+
CComQIPtr<IDXGIResource1> res = texture_;
3030
if (res) {
3131
res->CreateSharedHandle(nullptr, DXGI_SHARED_RESOURCE_READ, nullptr, &share_handle_);
3232
}
3333
}
3434

35-
if (share_handle_ == nullptr || !wglDXSetResourceShareHandleNV(texture_.get(), share_handle_)) {
35+
if (share_handle_ == nullptr || !wglDXSetResourceShareHandleNV(texture_, share_handle_)) {
3636
CASPAR_THROW_EXCEPTION(gl::ogl_exception() << msg_info("Failed to setup shared d3d texture."));
3737
}
3838
}
3939

4040
d3d_texture2d::~d3d_texture2d()
4141
{
42-
if (gl_texture_id_ != 0)
43-
glDeleteTextures(1, &gl_texture_id_);
42+
const std::shared_ptr<ogl::device> ogl = ogl_.lock();
43+
if (ogl != nullptr) {
44+
// The cleanup must happen be done on the opengl thread
45+
ogl->dispatch_sync([&] {
46+
const std::shared_ptr<void> interop = ogl->d3d_interop();
47+
if (texture_handle_ != nullptr && interop != nullptr) {
48+
wglDXUnlockObjectsNV(interop.get(), 1, &texture_handle_);
49+
wglDXUnregisterObjectNV(interop.get(), texture_handle_);
50+
texture_handle_ = nullptr;
51+
}
52+
53+
if (gl_texture_id_ != 0) {
54+
GL(glDeleteTextures(1, &gl_texture_id_));
55+
gl_texture_id_ = 0;
56+
}
57+
58+
// TODO: This appears to be leaking something opengl, but it is not clear what that is.
59+
60+
if (share_handle_ != nullptr) {
61+
CloseHandle(share_handle_);
62+
share_handle_ = nullptr;
63+
}
64+
});
65+
}
66+
67+
if (texture_ != nullptr) {
68+
texture_->Release();
69+
texture_ = nullptr;
70+
}
4471
}
4572

46-
void d3d_texture2d::gen_gl_texture(const std::shared_ptr<void>& interop)
73+
void d3d_texture2d::gen_gl_texture(std::shared_ptr<ogl::device> ogl)
4774
{
48-
if (gl_texture_id_ == 0) {
75+
if (gl_texture_id_ != 0 || texture_ == nullptr)
76+
return;
77+
78+
ogl_ = ogl;
79+
80+
const std::shared_ptr<void> interop = ogl->d3d_interop();
81+
if (!interop) {
82+
CASPAR_THROW_EXCEPTION(gl::ogl_exception() << msg_info("d3d interop not setup to bind shared d3d texture."));
83+
}
84+
85+
ogl->dispatch_sync([&] {
4986
GL(glGenTextures(1, &gl_texture_id_));
50-
void* tex_handle = wglDXRegisterObjectNV(
51-
interop.get(), texture_.get(), gl_texture_id_, GL_TEXTURE_2D, WGL_ACCESS_READ_ONLY_NV);
52-
if (!tex_handle) {
87+
88+
texture_handle_ =
89+
wglDXRegisterObjectNV(interop.get(), texture_, gl_texture_id_, GL_TEXTURE_2D, WGL_ACCESS_READ_ONLY_NV);
90+
if (!texture_handle_) {
5391
GL(glDeleteTextures(1, &gl_texture_id_));
5492
gl_texture_id_ = 0;
5593
CASPAR_THROW_EXCEPTION(gl::ogl_exception() << msg_info("Failed to bind shared d3d texture."));
5694
}
5795

58-
texture_handle_ = std::shared_ptr<void>(tex_handle, [=](void* p) {
59-
wglDXUnlockObjectsNV(interop.get(), 1, &p);
60-
wglDXUnregisterObjectNV(interop.get(), p);
61-
});
62-
63-
if (!wglDXLockObjectsNV(interop.get(), 1, &tex_handle)) {
96+
if (!wglDXLockObjectsNV(interop.get(), 1, &texture_handle_)) {
97+
wglDXUnregisterObjectNV(interop.get(), texture_handle_);
98+
texture_handle_ = nullptr;
6499
GL(glDeleteTextures(1, &gl_texture_id_));
65100
gl_texture_id_ = 0;
66101
CASPAR_THROW_EXCEPTION(gl::ogl_exception() << msg_info("Failed to lock shared d3d texture."));
67102
}
68-
}
103+
});
69104
}
70105

71106
}}} // namespace caspar::accelerator::d3d

src/accelerator/d3d/d3d_texture2d.h

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <memory>
99

1010
namespace caspar { namespace accelerator { namespace d3d {
11+
1112
class d3d_texture2d
1213
{
1314
public:
@@ -26,21 +27,22 @@ class d3d_texture2d
2627

2728
void* share_handle() const { return share_handle_; }
2829

29-
ID3D11Texture2D* texture() const { return texture_.get(); }
30+
ID3D11Texture2D* texture() const { return texture_; }
3031

3132
uint32_t gl_texture_id() const { return gl_texture_id_; }
3233

33-
void gen_gl_texture(const std::shared_ptr<void>& interop);
34+
void gen_gl_texture(std::shared_ptr<ogl::device>);
3435

3536
private:
3637
HANDLE share_handle_;
3738

38-
std::shared_ptr<ID3D11Texture2D> const texture_;
39-
uint32_t width_ = 0;
40-
uint32_t height_ = 0;
41-
DXGI_FORMAT format_ = DXGI_FORMAT::DXGI_FORMAT_UNKNOWN;
39+
ID3D11Texture2D* texture_;
40+
uint32_t width_ = 0;
41+
uint32_t height_ = 0;
42+
DXGI_FORMAT format_ = DXGI_FORMAT::DXGI_FORMAT_UNKNOWN;
4243

43-
std::shared_ptr<void> texture_handle_;
44-
uint32_t gl_texture_id_ = 0;
44+
std::weak_ptr<ogl::device> ogl_;
45+
HANDLE texture_handle_ = nullptr;
46+
uint32_t gl_texture_id_ = 0;
4547
};
4648
}}} // namespace caspar::accelerator::d3d

src/accelerator/ogl/image/image_mixer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ struct image_mixer::impl
340340
{
341341
// map directx texture with wgl texture
342342
if (d3d_texture->gl_texture_id() == 0)
343-
ogl_->dispatch_sync([=] { d3d_texture->gen_gl_texture(ogl_->d3d_interop()); });
343+
d3d_texture->gen_gl_texture(ogl_);
344344

345345
// copy directx texture to gl texture
346346
auto gl_texture = ogl_->dispatch_sync([=] {

0 commit comments

Comments
 (0)