| 657 | } |
| 658 | |
| 659 | [[nodiscard]] std::optional<std::pair<core::Tensor, core::Tensor>> renderViewAndDepthThreadSafe( |
| 660 | const glm::mat3& rotation, |
| 661 | const glm::vec3& translation, |
| 662 | const int width, |
| 663 | const int height, |
| 664 | const float fov_degrees, |
| 665 | const bool expected_depth) { |
| 666 | auto invoke_render = [&]() { |
| 667 | return renderViewAndDepthOnViewerThread(rotation, translation, width, height, fov_degrees, expected_depth); |
| 668 | }; |
| 669 | |
| 670 | auto* const viewer = get_visualizer(); |
| 671 | if (!viewer || viewer->isOnViewerThread()) { |
| 672 | return invoke_render(); |
| 673 | } |
| 674 | if (!viewer->acceptsPostedWork()) { |
| 675 | return std::nullopt; |
| 676 | } |
| 677 | |
| 678 | auto promise = |
| 679 | std::make_shared<std::promise<std::optional<std::pair<core::Tensor, core::Tensor>>>>(); |
| 680 | auto future = promise->get_future(); |
| 681 | auto completed = std::make_shared<std::atomic_bool>(false); |
| 682 | auto finish = |
| 683 | [promise, completed](std::optional<std::pair<core::Tensor, core::Tensor>> result) mutable { |
| 684 | if (!completed->exchange(true)) { |
| 685 | promise->set_value(std::move(result)); |
| 686 | } |
| 687 | }; |
| 688 | |
| 689 | const bool posted = viewer->postWork(vis::Visualizer::WorkItem{ |
| 690 | .run = |
| 691 | [rotation, translation, width, height, fov_degrees, expected_depth, finish]() mutable { |
| 692 | finish(renderViewAndDepthOnViewerThread(rotation, translation, width, height, fov_degrees, expected_depth)); |
| 693 | }, |
| 694 | .cancel = |
| 695 | [finish]() mutable { |
| 696 | finish(std::nullopt); |
| 697 | }}); |
| 698 | if (!posted) { |
| 699 | return std::nullopt; |
| 700 | } |
| 701 | |
| 702 | nb::gil_scoped_release release; |
| 703 | return future.get(); |
| 704 | } |
| 705 | } // namespace |
| 706 | |
| 707 | void set_render_scene_context(core::Scene* scene) { |
no test coverage detected