diff --git a/applications/gui/src/camera.cpp b/applications/gui/src/camera.cpp
index 9141c862feac76b12d16bea5fc9380da8ca5fc99..0407bd45c56417199195ab104bcbd45e8d407b29 100644
--- a/applications/gui/src/camera.cpp
+++ b/applications/gui/src/camera.cpp
@@ -121,6 +121,13 @@ static Eigen::Vector3f cudaToEigen(const float3 &v) {
 	return e;
 }
 
+void ftl::gui::Camera::drawUpdated(std::vector<ftl::rgbd::FrameSet*> &fss) {
+	// Only draw if frameset updated.
+	if (!stale_frame_.test_and_set()) {
+		draw(fss);
+	}
+}
+
 void ftl::gui::Camera::draw(std::vector<ftl::rgbd::FrameSet*> &fss) {
 	if (fid_ != 255) return;
 	//if (fsid_ >= fss.size()) return;
@@ -294,7 +301,9 @@ void ftl::gui::Camera::_draw(std::vector<ftl::rgbd::FrameSet*> &fss) {
 		} catch(std::exception &e) {
 			LOG(ERROR) << "Exception in render: " << e.what();
 		}
+
 		for (auto *fs : fss) {
+			if (!usesFrameset(fs->id)) continue;
 			fs->mtx.unlock();
 		}
 	}
@@ -366,8 +375,6 @@ void ftl::gui::Camera::_downloadFrames(ftl::cuda::TextureObject<uchar4> &a, ftl:
 	if (im2_.cols != im1_.cols || im2_.rows != im1_.rows) {
 		throw FTL_Error("Left and right images are different sizes");
 	}
-
-	new_frame_.clear();
 }
 
 void ftl::gui::Camera::_downloadFrame(ftl::cuda::TextureObject<uchar4> &a) {
@@ -381,8 +388,6 @@ void ftl::gui::Camera::_downloadFrame(ftl::cuda::TextureObject<uchar4> &a) {
 	height_ = im1_.rows;
 
 	im2_ = cv::Mat();
-
-	new_frame_.clear();
 }
 
 void ftl::gui::Camera::update(int fsid, const ftl::codecs::Channels<0> &c) {
@@ -398,6 +403,7 @@ void ftl::gui::Camera::update(std::vector<ftl::rgbd::FrameSet*> &fss) {
 	UNIQUE_LOCK(mutex_, lk);
 
 	framesets_ = &fss;
+	stale_frame_.clear();
 
 	//if (fss.size() <= fsid_) return;
 	if (fid_ == 255) {
@@ -405,7 +411,7 @@ void ftl::gui::Camera::update(std::vector<ftl::rgbd::FrameSet*> &fss) {
 		// Do a draw if not active. If active the draw function will be called
 		// directly.
 		if (screen_->activeCamera() != this) {
-			_draw(fss);
+			//_draw(fss);
 		}
 	} else {
 		for (auto *fs : fss) {
@@ -707,7 +713,7 @@ const void ftl::gui::Camera::captureFrame() {
 		if (framesets_) draw(*framesets_);
 
 		{
-			//UNIQUE_LOCK(mutex_, lk);
+			UNIQUE_LOCK(mutex_, lk);
 			if (im1_.rows != 0) {
 				texture1_.update(im1_);
 			}
diff --git a/applications/gui/src/camera.hpp b/applications/gui/src/camera.hpp
index d044151da12113c7eff28978c527b557d355bcc6..9e034c83a9509aa7663648d3f12ecc8390b39bd0 100644
--- a/applications/gui/src/camera.hpp
+++ b/applications/gui/src/camera.hpp
@@ -67,6 +67,12 @@ class Camera {
 	 */
 	void update(int fsid, const ftl::codecs::Channels<0> &c);
 
+	/**
+	 * Draw virtual camera only if the frameset has been updated since last
+	 * draw.
+	 */
+	void drawUpdated(std::vector<ftl::rgbd::FrameSet*> &fss);
+
 	void draw(std::vector<ftl::rgbd::FrameSet*> &fss);
 
 	inline int64_t getFrameTimeMS() const { return int64_t(delta_ * 1000.0f); }
@@ -131,7 +137,7 @@ class Camera {
 	cv::Mat im1_; // first channel (left)
 	cv::Mat im2_; // second channel ("right")
 	bool stereo_;
-	std::atomic_flag new_frame_;
+	std::atomic_flag stale_frame_;
 	int rx_;
 	int ry_;
 	std::vector<ftl::rgbd::FrameSet*> *framesets_;
diff --git a/applications/gui/src/screen.cpp b/applications/gui/src/screen.cpp
index e2f8a7f161c961a5f50753da736b263a91f6afda..efd853eaf9fdc7596871284bc84a9c0b8624171e 100644
--- a/applications/gui/src/screen.cpp
+++ b/applications/gui/src/screen.cpp
@@ -551,6 +551,12 @@ void ftl::gui::Screen::draw(NVGcontext *ctx) {
 			mShader.drawIndexed(GL_TRIANGLES, 0, 2);
 			//glDisable(GL_SCISSOR_TEST);
 		}
+	} else {
+		// Must periodically render the cameras here to update any thumbnails.
+		auto cams = swindow_->getCameras();
+		for (auto *c : cams) {
+			c->drawUpdated(swindow_->getFramesets());
+		}
 	}
 
 	nvgTextAlign(ctx, NVG_ALIGN_RIGHT);
diff --git a/applications/gui/src/src_window.cpp b/applications/gui/src/src_window.cpp
index 5b6b84174cf8271ee2348988a0e6a9f6417ee427..5620e1928632dae4a9f34390fee702f5827bb526 100644
--- a/applications/gui/src/src_window.cpp
+++ b/applications/gui/src/src_window.cpp
@@ -74,6 +74,12 @@ SourceWindow::SourceWindow(ftl::gui::Screen *screen)
 	
 	new Label(this, "Select Camera","sans-bold",20);
 
+	// FIXME: Reallocating the vector may currently causes thread issues since
+	// it might be in use elsewhere. A safer mechanism is needed for sharing
+	// framesets. Temporary solution: preallocate enough slots.
+	pre_pipelines_.reserve(5);
+	framesets_.reserve(5);
+
 	auto vscroll = new VScrollPanel(this);
 	ipanel_ = new Widget(vscroll);
 	ipanel_->setLayout(new GridLayout(nanogui::Orientation::Horizontal, 2,
@@ -179,11 +185,6 @@ bool SourceWindow::_processFrameset(ftl::rgbd::FrameSet &fs, bool fromstream) {
 		interceptor_->select(fs.id, cs);
 	}
 
-	/*if (fs.id > 0) {
-		LOG(INFO) << "Got frameset: " << fs.id;
-		return true;
-	}*/
-
 	// Make sure there are enough framesets allocated
 	_checkFrameSets(fs.id);
 
@@ -375,6 +376,7 @@ void SourceWindow::draw(NVGcontext *ctx) {
 			cv::Mat t;
 			auto *cam = camera.second.camera;
 			if (cam) {
+				//cam->draw(framesets_);
 				if (cam->thumbnail(t)) {
 					thumbs_[i].update(t);
 				}