From bf29bd99121325bd0f95d82f700a858211905115 Mon Sep 17 00:00:00 2001 From: Nicolas Pope <nwpope@utu.fi> Date: Tue, 17 Sep 2019 20:03:11 +0300 Subject: [PATCH] Add frame swapping and channel iterator --- applications/reconstruct/src/main.cpp | 88 +++++-------------- .../include/ftl/rgbd/channels.hpp | 27 ++++++ .../rgbd-sources/include/ftl/rgbd/frame.hpp | 7 ++ .../include/ftl/rgbd/frameset.hpp | 4 + components/rgbd-sources/src/frame.cpp | 22 +++++ components/rgbd-sources/src/frameset.cpp | 39 ++++++++ components/rgbd-sources/test/frame_unit.cpp | 14 +++ 7 files changed, 133 insertions(+), 68 deletions(-) create mode 100644 components/rgbd-sources/src/frameset.cpp diff --git a/applications/reconstruct/src/main.cpp b/applications/reconstruct/src/main.cpp index 6e9ad3685..36d4862a0 100644 --- a/applications/reconstruct/src/main.cpp +++ b/applications/reconstruct/src/main.cpp @@ -92,23 +92,25 @@ static void run(ftl::Configurable *root) { } } + ftl::rgbd::FrameSet scene_A; // Output of align process + ftl::rgbd::FrameSet scene_B; // Input of render process + //ftl::voxhash::SceneRep *scene = ftl::create<ftl::voxhash::SceneRep>(root, "voxelhash"); ftl::rgbd::Streamer *stream = ftl::create<ftl::rgbd::Streamer>(root, "stream", net); - ftl::rgbd::Source *virt = ftl::create<ftl::rgbd::Source>(root, "virtual", net); - ftl::render::Splatter *splat = new ftl::render::Splatter(); + ftl::rgbd::VirtualSource *virt = ftl::create<ftl::rgbd::VirtualSource>(root, "virtual", net); + ftl::render::Splatter *splat = ftl::create<ftl::render::Splatter>(root, "renderer", scene); ftl::rgbd::Group group; ftl::ILW align; - //auto virtimpl = new ftl::rgbd::VirtualSource(virt); - //virt->customImplementation(virtimpl); - //virtimpl->setScene(scene); + // Generate virtual camera render when requested by streamer + virt->onRender([splat,&scene_B](ftl::rgbd::Frame &out) { + splat->render(scene_B, out); + }); stream->add(virt); for (size_t i=0; i<sources.size(); i++) { Source *in = sources[i]; in->setChannel(Channel::Depth); - //stream->add(in); - //scene->addSource(in); group.addSource(in); } @@ -116,87 +118,37 @@ static void run(ftl::Configurable *root) { bool busy = false; - ftl::rgbd::FrameSet scene; - group.setName("ReconGroup"); group.sync([splat,virt,&busy,&slave](ftl::rgbd::FrameSet &fs) -> bool { //cudaSetDevice(scene->getCUDADevice()); + + if (slave.isPaused()) return true; if (busy) { LOG(INFO) << "Group frameset dropped: " << fs.timestamp; return true; } busy = true; - //scene->nextFrame(); - - // Send all frames to GPU, block until done? - // TODO: Allow non-block and keep frameset locked until later - if (!slave.isPaused()) { - //scene->upload(fs); - for (auto &f : fs.frames) { - f.upload(Channel::Colour + Channel::Depth); // TODO: (Nick) Add scene stream - } - } - //int64_t ts = fs.timestamp; + // Swap the entire frameset to allow rapid return + fs.swapTo(scene_A); - ftl::pool.push([splat,virt,&busy,&fs,&slave](int id) { + ftl::pool.push([&scene_B,&scene_A,&busy,&slave](int id) { //cudaSetDevice(scene->getCUDADevice()); // TODO: Release frameset here... //cudaSafeCall(cudaStreamSynchronize(scene->getIntegrationStream())); - if (!slave.isPaused()) { - //scene->integrate(); - //scene->garbage(); - align.process(fs, scene); - } + // Send all frames to GPU, block until done? + scene_A.upload(Channel::Colour + Channel::Depth); // TODO: (Nick) Add scene stream. + align.process(scene_A); - // Don't render here... but update timestamp. - splat->render(scene, virt); //, scene->getIntegrationStream()); + // TODO: To use second GPU, could do a download, swap, device change, + // then upload to other device. Or some direct device-2-device copy. + scene_A.swapTo(scene_B); busy = false; }); return true; }); - - - /*int active = sources.size(); - while (ftl::running) { - if (active == 0) { - LOG(INFO) << "Waiting for sources..."; - sleep_for(milliseconds(1000)); - } - - active = 0; - - if (!slave.isPaused()) { - // Mark voxels as cleared - scene->nextFrame(); - - // Grab, upload frames and allocate voxel blocks - active = scene->upload(); - - // Make sure previous virtual camera frame has finished rendering - //stream->wait(); - cudaSafeCall(cudaStreamSynchronize(scene->getIntegrationStream())); - - - // Merge new frames into the voxel structure - scene->integrate(); - - //LOG(INFO) << "Allocated: " << scene->getOccupiedCount(); - - // Remove any redundant voxels - scene->garbage(); - - } else { - active = 1; - } - - splat->render(virt, scene->getIntegrationStream()); - - // Start virtual camera rendering and previous frame compression - stream->poll(); - }*/ } int main(int argc, char **argv) { diff --git a/components/rgbd-sources/include/ftl/rgbd/channels.hpp b/components/rgbd-sources/include/ftl/rgbd/channels.hpp index 9c7f24b03..7c014e682 100644 --- a/components/rgbd-sources/include/ftl/rgbd/channels.hpp +++ b/components/rgbd-sources/include/ftl/rgbd/channels.hpp @@ -28,6 +28,21 @@ enum struct Channel : int { class Channels { public: + + class iterator { + public: + iterator(const Channels &c, unsigned int ix) : channels_(c), ix_(ix) { } + iterator operator++(); + iterator operator++(int junk); + inline ftl::rgbd::Channel operator*() { return static_cast<Channel>(static_cast<int>(ix_)); } + //ftl::rgbd::Channel operator->() { return ptr_; } + inline bool operator==(const iterator& rhs) { return ix_ == rhs.ix_; } + inline bool operator!=(const iterator& rhs) { return ix_ != rhs.ix_; } + private: + const Channels &channels_; + unsigned int ix_; + }; + inline Channels() { mask = 0; } inline explicit Channels(unsigned int m) { mask = m; } inline explicit Channels(Channel c) { mask = (c == Channel::None) ? 0 : 0x1 << static_cast<unsigned int>(c); } @@ -48,6 +63,9 @@ class Channels { return mask & (0x1 << c); } + inline iterator begin() { return iterator(*this, 0); } + inline iterator end() { return iterator(*this, 32); } + inline operator unsigned int() { return mask; } inline operator bool() { return mask > 0; } inline operator Channel() { @@ -63,10 +81,19 @@ class Channels { static const size_t kMax = 32; + static Channels All(); + private: unsigned int mask; }; +inline Channels::iterator Channels::iterator::operator++() { Channels::iterator i = *this; while (++ix_ < 32 && !channels_.has(ix_)); return i; } +inline Channels::iterator Channels::iterator::operator++(int junk) { while (++ix_ < 32 && !channels_.has(ix_)); return *this; } + +inline Channels Channels::All() { + return Channels(0xFFFFFFFFu); +} + static const Channels kNoChannels; static const Channels kAllChannels(0xFFFFFFFFu); diff --git a/components/rgbd-sources/include/ftl/rgbd/frame.hpp b/components/rgbd-sources/include/ftl/rgbd/frame.hpp index 6574de3bf..fff355035 100644 --- a/components/rgbd-sources/include/ftl/rgbd/frame.hpp +++ b/components/rgbd-sources/include/ftl/rgbd/frame.hpp @@ -40,6 +40,13 @@ public: void download(ftl::rgbd::Channels c, cv::cuda::Stream& stream=cv::cuda::Stream::Null()); void upload(ftl::rgbd::Channels c, cv::cuda::Stream& stream=cv::cuda::Stream::Null()); + /** + * Perform a buffer swap of the selected channels. This is intended to be + * a copy from `this` to the passed frame object but by buffer swap + * instead of memory copy, meaning `this` may become invalid afterwards. + */ + void swapTo(ftl::rgbd::Channels, Frame &); + /** * Create a channel with a given format. This will discard any existing * data associated with the channel and ensure all data structures and diff --git a/components/rgbd-sources/include/ftl/rgbd/frameset.hpp b/components/rgbd-sources/include/ftl/rgbd/frameset.hpp index 93839efda..4831d1cb8 100644 --- a/components/rgbd-sources/include/ftl/rgbd/frameset.hpp +++ b/components/rgbd-sources/include/ftl/rgbd/frameset.hpp @@ -24,6 +24,10 @@ struct FrameSet { std::atomic<unsigned int> mask; // Mask of all sources that contributed bool stale; // True if buffers have been invalidated SHARED_MUTEX mtx; + + void upload(ftl::rgbd::Channels, cudaStream_t stream=0); + void download(ftl::rgbd::Channels, cudaStream_t stream=0); + void swapTo(ftl::rgbd::FrameSet &); }; } diff --git a/components/rgbd-sources/src/frame.cpp b/components/rgbd-sources/src/frame.cpp index 4886ff3cb..f8a4b348a 100644 --- a/components/rgbd-sources/src/frame.cpp +++ b/components/rgbd-sources/src/frame.cpp @@ -39,6 +39,28 @@ void Frame::upload(Channels c, cv::cuda::Stream& stream) { } } +void Frame::swapTo(ftl::rgbd::Channels channels, Frame &f) { + // For all channels in this frame object + for (auto c : channels_) { + // Should we swap this channel? + if (channels.has(c)) { + // Does 'f' have this channel? + if (!f.hasChannel(c)) { + // No, so create it first + // FIXME: Allocate the memory as well? + if (isCPU(c)) f.create<cv::Mat>(c); + else f.create<cv::cuda::GpuMat>(c); + } + + auto &m1 = _get(c); + auto &m2 = f._get(c); + + cv::swap(m1.host, m2.host); + cv::cuda::swap(m1.gpu, m2.gpu); + } + } +} + template<> cv::Mat& Frame::get(ftl::rgbd::Channel channel) { if (channel == Channel::None) { DLOG(WARNING) << "Cannot get the None channel from a Frame"; diff --git a/components/rgbd-sources/src/frameset.cpp b/components/rgbd-sources/src/frameset.cpp new file mode 100644 index 000000000..4b830cf7c --- /dev/null +++ b/components/rgbd-sources/src/frameset.cpp @@ -0,0 +1,39 @@ +#include <ftl/rgbd/frameset.hpp> + +using ftl::rgbd::FrameSet; +using ftl::rgbd::Channels; +using ftl::rgbd::Channel; + +void FrameSet::upload(ftl::rgbd::Channels c, cudaStream_t stream) { + for (auto &f : frames) { + f.upload(c, stream); + } +} + +void FrameSet::download(ftl::rgbd::Channels c, cudaStream_t stream) { + for (auto &f : frames) { + f.download(c, stream); + } +} + +void FrameSet::swapTo(ftl::rgbd::FrameSet &fs) { + UNIQUE_LOCK(fs.mtx, lk); + + if (fs.frames.size() != frames.size()) { + // Assume "this" is correct and "fs" is not. + fs.sources.clear(); + for (auto s : sources) fs.sources.push_back(s); + fs.frames.resize(frames.size()); + } + + fs.timestamp = timestamp; + fs.count = count; + fs.stale = stale; + fs.mask = mask; + + for (size_t i=0; i<frames.size(); ++i) { + frames[i].swap(Channels::All(), fs.frames[i]); + } + + stale = true; +} diff --git a/components/rgbd-sources/test/frame_unit.cpp b/components/rgbd-sources/test/frame_unit.cpp index 1d1648b21..6ad528a28 100644 --- a/components/rgbd-sources/test/frame_unit.cpp +++ b/components/rgbd-sources/test/frame_unit.cpp @@ -3,6 +3,7 @@ using ftl::rgbd::Frame; using ftl::rgbd::Channel; +using ftl::rgbd::Channels; using ftl::rgbd::Format; TEST_CASE("Frame::create() cpu mat", "") { @@ -267,3 +268,16 @@ TEST_CASE("Frame::getTexture()", "") { REQUIRE( !hadexception ); } } + +TEST_CASE("Frame::swapTo()", "") { + SECTION("Single host channel to empty frame") { + Frame f1; + Frame f2; + + f1.create<cv::Mat>(Channel::Colour, Format<uchar3>(100,100)); + f1.swapTo(Channels::All(), f2); + + REQUIRE( f2.hasChannel(Channel::Colour) ); + REQUIRE( (f2.get<cv::Mat>(Channel::Colour).cols == 100) ); + } +} -- GitLab