Skip to content

Commit

Permalink
fix: improve lock handling of d3d interop
Browse files Browse the repository at this point in the history
  • Loading branch information
Julusian committed Nov 16, 2023
1 parent 794dbd7 commit 666066c
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 7 deletions.
5 changes: 0 additions & 5 deletions src/accelerator/d3d/d3d_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,6 @@
namespace caspar { namespace accelerator { namespace d3d {
struct d3d_device::impl : public std::enable_shared_from_this<impl>
{
using texture_queue_t = tbb::concurrent_bounded_queue<std::shared_ptr<d3d_texture2d>>;

mutable std::mutex device_pools_mutex_;
tbb::concurrent_unordered_map<size_t, texture_queue_t> device_pools_;

std::wstring adaptor_name_ = L"N/A";
std::shared_ptr<ID3D11Device> device_;
std::shared_ptr<d3d_device_context> ctx_;
Expand Down
62 changes: 61 additions & 1 deletion src/accelerator/d3d/d3d_texture2d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,11 @@ d3d_texture2d::~d3d_texture2d()
ogl->dispatch_sync([&] {
const std::shared_ptr<void> interop = ogl->d3d_interop();
if (texture_handle_ != nullptr && interop != nullptr) {
wglDXUnlockObjectsNV(interop.get(), 1, &texture_handle_);
if (is_locked_) {
wglDXUnlockObjectsNV(interop.get(), 1, &texture_handle_);
is_locked_ = false;
}

wglDXUnregisterObjectNV(interop.get(), texture_handle_);
texture_handle_ = nullptr;
}
Expand Down Expand Up @@ -100,7 +104,63 @@ void d3d_texture2d::gen_gl_texture(std::shared_ptr<ogl::device> ogl)
gl_texture_id_ = 0;
CASPAR_THROW_EXCEPTION(gl::ogl_exception() << msg_info("Failed to lock shared d3d texture."));
}

is_locked_ = true;
});
}

void d3d_texture2d::lock_gl()
{
if (is_locked_)
return;

if (!texture_handle_ || gl_texture_id_ == 0) {
CASPAR_THROW_EXCEPTION(gl::ogl_exception() << msg_info("texture is not ready to be locked."));
}

const std::shared_ptr<ogl::device> ogl = ogl_.lock();
if (ogl == nullptr) {
CASPAR_THROW_EXCEPTION(gl::ogl_exception() << msg_info("failed to lock opengl device."));
}

const std::shared_ptr<void> interop = ogl->d3d_interop();
if (!interop) {
CASPAR_THROW_EXCEPTION(gl::ogl_exception() << msg_info("d3d interop not setup to lock shared d3d texture."));
}

bool res = ogl->dispatch_sync([&] { return wglDXLockObjectsNV(interop.get(), 1, &texture_handle_); });
if (!res) {
CASPAR_THROW_EXCEPTION(gl::ogl_exception() << msg_info("Failed to lock shared d3d texture."));
}

is_locked_ = true;
}

void d3d_texture2d::unlock_gl()
{
if (!is_locked_)
return;

if (!texture_handle_ || gl_texture_id_ == 0) {
CASPAR_THROW_EXCEPTION(gl::ogl_exception() << msg_info("texture is not ready to be locked."));
}

const std::shared_ptr<ogl::device> ogl = ogl_.lock();
if (ogl == nullptr) {
CASPAR_THROW_EXCEPTION(gl::ogl_exception() << msg_info("failed to lock opengl device."));
}

const std::shared_ptr<void> interop = ogl->d3d_interop();
if (!interop) {
CASPAR_THROW_EXCEPTION(gl::ogl_exception() << msg_info("d3d interop not setup to unlock shared d3d texture."));
}

bool res = ogl->dispatch_sync([&] { return wglDXUnlockObjectsNV(interop.get(), 1, &texture_handle_); });
if (!res) {
CASPAR_THROW_EXCEPTION(gl::ogl_exception() << msg_info("Failed to unlock shared d3d texture."));
}

is_locked_ = false;
}

}}} // namespace caspar::accelerator::d3d
5 changes: 5 additions & 0 deletions src/accelerator/d3d/d3d_texture2d.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ class d3d_texture2d

void gen_gl_texture(std::shared_ptr<ogl::device>);

void lock_gl();

void unlock_gl();

private:
HANDLE share_handle_;

Expand All @@ -44,5 +48,6 @@ class d3d_texture2d
std::weak_ptr<ogl::device> ogl_;
HANDLE texture_handle_ = nullptr;
uint32_t gl_texture_id_ = 0;
bool is_locked_ = false;
};
}}} // namespace caspar::accelerator::d3d
8 changes: 7 additions & 1 deletion src/accelerator/ogl/image/image_mixer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,15 +341,21 @@ struct image_mixer::impl
// map directx texture with wgl texture
if (d3d_texture->gl_texture_id() == 0)
d3d_texture->gen_gl_texture(ogl_);
else
// signal d3d to flush/sync the texture
d3d_texture->lock_gl();

// copy directx texture to gl texture
// copy d3d texture to gl texture
auto gl_texture = ogl_->dispatch_sync([=] {
return ogl_->copy_async(d3d_texture->gl_texture_id(), d3d_texture->width(), d3d_texture->height(), 4);
});

// make gl texture to draw
std::vector<future_texture> textures{make_ready_future(gl_texture.get())};

// signal d3d is free to take ownership
d3d_texture->unlock_gl();

std::weak_ptr<image_mixer::impl> weak_self = shared_from_this();
core::pixel_format_desc desc(core::pixel_format::bgra);
desc.planes.push_back(core::pixel_format_desc::plane(d3d_texture->width(), d3d_texture->height(), 4));
Expand Down

0 comments on commit 666066c

Please sign in to comment.